diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/alpha/kernel/process.c linux.20pre10-ac2/arch/alpha/kernel/process.c
--- linux.20pre10/arch/alpha/kernel/process.c	2002-10-09 21:36:57.000000000 +0100
+++ linux.20pre10-ac2/arch/alpha/kernel/process.c	2002-08-06 15:42:19.000000000 +0100
@@ -30,6 +30,7 @@
 #include <linux/reboot.h>
 #include <linux/tty.h>
 #include <linux/console.h>
+#include <linux/sched_runqueue.h>
 
 #include <asm/reg.h>
 #include <asm/uaccess.h>
@@ -74,9 +75,6 @@
 cpu_idle(void)
 {
 	/* An endless idle loop with no priority at all.  */
-	current->nice = 20;
-	current->counter = -100;
-
 	while (1) {
 		/* FIXME -- EV6 and LCA45 know how to power down
 		   the CPU.  */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/alpha/kernel/smp.c linux.20pre10-ac2/arch/alpha/kernel/smp.c
--- linux.20pre10/arch/alpha/kernel/smp.c	2002-10-09 21:36:57.000000000 +0100
+++ linux.20pre10-ac2/arch/alpha/kernel/smp.c	2002-08-06 15:42:19.000000000 +0100
@@ -82,6 +82,7 @@
 int smp_num_cpus = 1;		/* Number that came online.  */
 int smp_threads_ready;		/* True once the per process idle is forked. */
 cycles_t cacheflush_time;
+unsigned long cache_decay_ticks;
 
 int __cpu_number_map[NR_CPUS];
 int __cpu_logical_map[NR_CPUS];
@@ -156,11 +157,6 @@
 {
 	int cpuid = hard_smp_processor_id();
 
-	if (current != init_tasks[cpu_number_map(cpuid)]) {
-		printk("BUG: smp_calling: cpu %d current %p init_tasks[cpu_number_map(cpuid)] %p\n",
-		       cpuid, current, init_tasks[cpu_number_map(cpuid)]);
-	}
-
 	DBGS(("CALLIN %d state 0x%lx\n", cpuid, current->state));
 
 	/* Turn on machine checks.  */
@@ -215,9 +211,6 @@
 	DBGS(("smp_callin: commencing CPU %d current %p\n",
 	      cpuid, current));
 
-	/* Setup the scheduler for this processor.  */
-	init_idle();
-
 	/* ??? This should be in init_idle.  */
 	atomic_inc(&init_mm.mm_count);
 	current->active_mm = &init_mm;
@@ -236,8 +229,9 @@
 smp_tune_scheduling (int cpuid)
 {
 	struct percpu_struct *cpu;
-	unsigned long on_chip_cache;
-	unsigned long freq;
+	unsigned long on_chip_cache;	/* kB */
+	unsigned long freq;		/* Hz */
+	unsigned long bandwidth = 350;	/* MB/s */
 
 	cpu = (struct percpu_struct*)((char*)hwrpb + hwrpb->processor_offset
 				      + cpuid * hwrpb->processor_size);
@@ -258,29 +252,21 @@
 
 	case EV6_CPU:
 	case EV67_CPU:
-		on_chip_cache = 64 + 64;
-		break;
-
 	default:
-		on_chip_cache = 8 + 8;
+		on_chip_cache = 64 + 64;
 		break;
 	}
 
 	freq = hwrpb->cycle_freq ? : est_cycle_freq;
 
-#if 0
-	/* Magic estimation stolen from x86 port.  */
-	cacheflush_time = freq / 1024L * on_chip_cache / 5000L;
-
-        printk("Using heuristic of %d cycles.\n",
-               cacheflush_time);
-#else
-	/* Magic value to force potential preemption of other CPUs.  */
-	cacheflush_time = INT_MAX;
+	cacheflush_time = (freq / 1000000) * (on_chip_cache << 10) / bandwidth;
+	cache_decay_ticks = cacheflush_time / (freq / 1000) * HZ / 1000;
 
-        printk("Using heuristic of %d cycles.\n",
-               cacheflush_time);
-#endif
+	printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n",
+	       cacheflush_time/(freq/1000000),
+	       (cacheflush_time*100/(freq/1000000)) % 100);
+	printk("task migration cache decay timeout: %ld msecs.\n",
+	       (cache_decay_ticks + 1) * 1000 / HZ);
 }
 
 /*
@@ -505,14 +491,11 @@
 	if (idle == &init_task)
 		panic("idle process is init_task for CPU %d", cpuid);
 
-	idle->processor = cpuid;
-	idle->cpus_runnable = 1 << cpuid; /* we schedule the first task manually */
+	init_idle(idle, cpuid);
+	unhash_process(idle);
+
 	__cpu_logical_map[cpunum] = cpuid;
 	__cpu_number_map[cpuid] = cpunum;
- 
-	del_from_runqueue(idle);
-	unhash_process(idle);
-	init_tasks[cpunum] = idle;
 
 	DBGS(("smp_boot_one_cpu: CPU %d state 0x%lx flags 0x%lx\n",
 	      cpuid, idle->state, idle->flags));
@@ -619,14 +602,11 @@
 
 	__cpu_number_map[boot_cpuid] = 0;
 	__cpu_logical_map[0] = boot_cpuid;
-	current->processor = boot_cpuid;
 
 	smp_store_cpu_info(boot_cpuid);
 	smp_tune_scheduling(boot_cpuid);
 	smp_setup_percpu_timer(boot_cpuid);
 
-	init_idle();
-
 	/* ??? This should be in init_idle.  */
 	atomic_inc(&init_mm.mm_count);
 	current->active_mm = &init_mm;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/alpha/mm/fault.c linux.20pre10-ac2/arch/alpha/mm/fault.c
--- linux.20pre10/arch/alpha/mm/fault.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/alpha/mm/fault.c	2002-08-29 19:00:49.000000000 +0100
@@ -122,8 +122,6 @@
 		goto bad_area;
 	if (vma->vm_start <= address)
 		goto good_area;
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		goto bad_area;
 	if (expand_stack(vma, address))
 		goto bad_area;
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/arm/config.in linux.20pre10-ac2/arch/arm/config.in
--- linux.20pre10/arch/arm/config.in	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/arm/config.in	2002-09-27 13:54:57.000000000 +0100
@@ -646,6 +646,7 @@
 bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
 dep_bool '  Debug memory allocations' CONFIG_DEBUG_SLAB $CONFIG_DEBUG_KERNEL
 dep_bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ $CONFIG_DEBUG_KERNEL
+dep_bool '  Morse code panics' CONFIG_PANIC_MORSE $CONFIG_DEBUG_KERNEL $CONFIG_PC_KEYB
 dep_bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK $CONFIG_DEBUG_KERNEL
 dep_bool '  Wait queue debugging' CONFIG_DEBUG_WAITQ $CONFIG_DEBUG_KERNEL
 dep_bool '  Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE $CONFIG_DEBUG_KERNEL
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/arm/mm/fault-common.c linux.20pre10-ac2/arch/arm/mm/fault-common.c
--- linux.20pre10/arch/arm/mm/fault-common.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/arm/mm/fault-common.c	2002-08-06 15:42:21.000000000 +0100
@@ -229,7 +229,7 @@
 	goto survive;
 
 check_stack:
-	if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr))
+	if (!expand_stack(vma, addr))
 		goto good_area;
 out:
 	return fault;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/cris/drivers/ide.c linux.20pre10-ac2/arch/cris/drivers/ide.c
--- linux.20pre10/arch/cris/drivers/ide.c	2002-10-09 21:37:04.000000000 +0100
+++ linux.20pre10-ac2/arch/cris/drivers/ide.c	2002-08-06 15:42:22.000000000 +0100
@@ -816,13 +816,13 @@
 			rq = HWGROUP(drive)->rq;
 			for (i = rq->nr_sectors; i > 0;) {
 				i -= rq->current_nr_sectors;
-				ide_end_request(1, HWGROUP(drive));
+				DRIVER(drive)->end_request(drive, 1);
 			}
 			return ide_stopped;
 		}
 		printk("%s: bad DMA status\n", drive->name);
 	}
-	return ide_error(drive, "dma_intr", stat);
+	return DRIVER(drive)->error(drive, "dma_intr", stat);
 }
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/config.in linux.20pre10-ac2/arch/i386/config.in
--- linux.20pre10/arch/i386/config.in	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/config.in	2002-10-10 23:56:47.000000000 +0100
@@ -82,7 +82,7 @@
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
-   define_bool CONFIG_X86_HAS_TSC y
+   define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_PPRO_FENCE y
    define_bool CONFIG_X86_F00F_WORKS_OK n
 fi
@@ -90,23 +90,23 @@
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_USE_STRING_486 y
    define_bool CONFIG_X86_ALIGNMENT_16 y
-   define_bool CONFIG_X86_HAS_TSC y
+   define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_PPRO_FENCE y
    define_bool CONFIG_X86_F00F_WORKS_OK n
 fi
 if [ "$CONFIG_M686" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
-   define_bool CONFIG_X86_HAS_TSC y
+   define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
-   define_bool CONFIG_X86_PGE y
+   bool 'PGE extensions (not for Cyrix/Transmeta)' CONFIG_X86_PGE
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
    define_bool CONFIG_X86_PPRO_FENCE y
    define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MPENTIUMIII" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
-   define_bool CONFIG_X86_HAS_TSC y
+   define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_PGE y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
@@ -114,7 +114,7 @@
 fi
 if [ "$CONFIG_MPENTIUM4" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 7
-   define_bool CONFIG_X86_HAS_TSC y
+   define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_PGE y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
@@ -123,12 +123,12 @@
 if [ "$CONFIG_MK6" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_ALIGNMENT_16 y
-   define_bool CONFIG_X86_HAS_TSC y
+   define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
 fi
 if [ "$CONFIG_MK7" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 6
-   define_bool CONFIG_X86_HAS_TSC y
+   define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_GOOD_APIC y
    define_bool CONFIG_X86_USE_3DNOW y
    define_bool CONFIG_X86_PGE y
@@ -143,14 +143,14 @@
 fi
 if [ "$CONFIG_MCYRIXIII" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
-   define_bool CONFIG_X86_HAS_TSC y
+   define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_ALIGNMENT_16 y
    define_bool CONFIG_X86_USE_3DNOW y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
 fi
 if [ "$CONFIG_MCRUSOE" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
-   define_bool CONFIG_X86_HAS_TSC y
+   define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_F00F_WORKS_OK y
 fi
 if [ "$CONFIG_MWINCHIPC6" = "y" ]; then
@@ -163,7 +163,7 @@
 if [ "$CONFIG_MWINCHIP2" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_ALIGNMENT_16 y
-   define_bool CONFIG_X86_HAS_TSC y
+   define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
    define_bool CONFIG_X86_OOSTORE y
    define_bool CONFIG_X86_F00F_WORKS_OK y
@@ -171,7 +171,7 @@
 if [ "$CONFIG_MWINCHIP3D" = "y" ]; then
    define_int  CONFIG_X86_L1_CACHE_SHIFT 5
    define_bool CONFIG_X86_ALIGNMENT_16 y
-   define_bool CONFIG_X86_HAS_TSC y
+   define_bool CONFIG_X86_TSC y
    define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
    define_bool CONFIG_X86_OOSTORE y
    define_bool CONFIG_X86_F00F_WORKS_OK y
@@ -179,6 +179,22 @@
 
 bool 'Machine Check Exception' CONFIG_X86_MCE
 
+dep_bool 'CPU Frequency scaling (EXPERIMENTAL)' CONFIG_CPU_FREQ $CONFIG_EXPERIMENTAL
+if [ "$CONFIG_CPU_FREQ" = "y" ]; then
+   bool ' /proc/sys/cpu/ interface (2.4. / OLD)' CONFIG_CPU_FREQ_24_API
+   tristate ' AMD Mobile K6-2/K6-3 PowerNow!' CONFIG_X86_POWERNOW_K6
+   if [ "$CONFIG_MELAN" = "y" ]; then
+       tristate ' AMD Elan' CONFIG_ELAN_CPUFREQ
+   fi
+   tristate ' VIA Cyrix III Longhaul' CONFIG_X86_LONGHAUL
+   tristate ' Intel Speedstep' CONFIG_X86_SPEEDSTEP
+   tristate ' Intel Pentium 4 clock modulation' CONFIG_X86_P4_CLOCKMOD
+   if [ "$CONFIG_CPU_FREQ_24_API" = "n" ]; then
+       tristate ' Transmeta LongRun' CONFIG_X86_LONGRUN
+   fi
+fi
+
+ 
 tristate 'Toshiba Laptop support' CONFIG_TOSHIBA
 tristate 'Dell laptop support' CONFIG_I8K
 
@@ -217,11 +233,7 @@
    fi
 else
    bool 'Multiquad NUMA system' CONFIG_MULTIQUAD
-fi
-
-bool 'Unsynced TSC support' CONFIG_X86_TSC_DISABLE
-if [ "$CONFIG_X86_TSC_DISABLE" != "y" -a "$CONFIG_X86_HAS_TSC" = "y" ]; then
-   define_bool CONFIG_X86_TSC y
+   dep_bool 'Summit Architecture support' CONFIG_SUMMIT $CONFIG_MULTIQUAD
 fi
 
 if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then
@@ -263,6 +275,8 @@
    bool 'ISA bus support' CONFIG_ISA
 fi
 
+tristate 'NatSemi SCx200 support' CONFIG_SCx200
+
 source drivers/pci/Config.in
 
 bool 'EISA support' CONFIG_EISA
@@ -295,6 +309,8 @@
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 
+bool 'Kernel .config support' CONFIG_IKCONFIG
+
 bool 'Power Management support' CONFIG_PM
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
@@ -445,12 +461,13 @@
 bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
 if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
    bool '  Check for stack overflows' CONFIG_DEBUG_STACKOVERFLOW
+   bool '  Compile the kernel with frame pointers' CONFIG_FRAME_POINTER
    bool '  Debug high memory support' CONFIG_DEBUG_HIGHMEM
    bool '  Debug memory allocations' CONFIG_DEBUG_SLAB
    bool '  Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT
    bool '  Magic SysRq key' CONFIG_MAGIC_SYSRQ
+	bool '  Morse code panics' CONFIG_PANIC_MORSE
    bool '  Spinlock debugging' CONFIG_DEBUG_SPINLOCK
-   bool '  Compile the kernel with frame pointers' CONFIG_FRAME_POINTER
 fi
 
 endmenu
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/defconfig linux.20pre10-ac2/arch/i386/defconfig
--- linux.20pre10/arch/i386/defconfig	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/defconfig	2002-10-07 18:33:24.000000000 +0100
@@ -2,7 +2,6 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_X86=y
-CONFIG_ISA=y
 # CONFIG_SBUS is not set
 CONFIG_UID16=y
 
@@ -50,7 +49,9 @@
 CONFIG_X86_GOOD_APIC=y
 CONFIG_X86_PGE=y
 CONFIG_X86_USE_PPRO_CHECKSUM=y
+CONFIG_X86_F00F_WORKS_OK=y
 CONFIG_X86_MCE=y
+# CONFIG_CPU_FREQ is not set
 # CONFIG_TOSHIBA is not set
 # CONFIG_I8K is not set
 # CONFIG_MICROCODE is not set
@@ -59,10 +60,12 @@
 CONFIG_NOHIGHMEM=y
 # CONFIG_HIGHMEM4G is not set
 # CONFIG_HIGHMEM64G is not set
+# CONFIG_HIGHMEM is not set
 # CONFIG_MATH_EMULATION is not set
 # CONFIG_MTRR is not set
 CONFIG_SMP=y
 # CONFIG_MULTIQUAD is not set
+# CONFIG_SUMMIT is not set
 CONFIG_HAVE_DEC_LOCK=y
 
 #
@@ -77,6 +80,7 @@
 CONFIG_PCI_GOANY=y
 CONFIG_PCI_BIOS=y
 CONFIG_PCI_DIRECT=y
+CONFIG_ISA=y
 CONFIG_PCI_NAMES=y
 # CONFIG_EISA is not set
 # CONFIG_MCA is not set
@@ -95,10 +99,11 @@
 # PCI Hotplug Support
 #
 # CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HOTPLUG_PCI_ACPI is not set
 # CONFIG_HOTPLUG_PCI_COMPAQ is not set
 # CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
 # CONFIG_HOTPLUG_PCI_IBM is not set
-# CONFIG_HOTPLUG_PCI_ACPI is not set
+# CONFIG_HOTPLUG_PCI_H2999 is not set
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
@@ -107,6 +112,7 @@
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=y
+# CONFIG_IKCONFIG is not set
 CONFIG_PM=y
 # CONFIG_APM is not set
 
@@ -141,6 +147,7 @@
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -233,10 +240,12 @@
 # CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDECD_BAILOUT is not set
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
 
 #
 # IDE chipset support/bugfixes
@@ -244,8 +253,8 @@
 CONFIG_BLK_DEV_CMD640=y
 # CONFIG_BLK_DEV_CMD640_ENHANCED is not set
 # CONFIG_BLK_DEV_ISAPNP is not set
-CONFIG_BLK_DEV_RZ1000=y
 CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_GENERIC is not set
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -254,30 +263,30 @@
 # CONFIG_IDEDMA_ONLYDISK is not set
 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 is not set
 # CONFIG_WDC_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
 # CONFIG_AMD74XX_OVERRIDE is not set
 # CONFIG_BLK_DEV_CMD64X is not set
-# 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_PIIX=y
-CONFIG_PIIX_TUNING=y
+# CONFIG_BLK_DEV_NFORCE is not set
 # CONFIG_BLK_DEV_NS87415 is not set
 # CONFIG_BLK_DEV_OPTI621 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=y
 # 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
@@ -433,11 +442,11 @@
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_TULIP is not set
-# CONFIG_TC35815 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
 # CONFIG_DM9102 is not set
 CONFIG_EEPRO100=y
+# CONFIG_E100 is not set
 # CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
@@ -449,11 +458,12 @@
 # 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
 # CONFIG_TLAN is not set
+# CONFIG_TC35815 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_WINBOND_840 is not set
@@ -464,6 +474,7 @@
 #
 # CONFIG_ACENIC is not set
 # CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
 # CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
@@ -589,6 +600,7 @@
 # CONFIG_WATCHDOG is not set
 # CONFIG_AMD_RNG is not set
 # CONFIG_INTEL_RNG is not set
+# CONFIG_AMD_PM768 is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
 # CONFIG_DTLK is not set
@@ -617,8 +629,8 @@
 CONFIG_DRM_TDFX=y
 # CONFIG_DRM_R128 is not set
 CONFIG_DRM_RADEON=y
-CONFIG_DRM_I810=y
-CONFIG_DRM_I810_XFREE_41=y
+# CONFIG_DRM_I810 is not set
+# CONFIG_DRM_I830 is not set
 # CONFIG_DRM_MGA is not set
 # CONFIG_DRM_SIS is not set
 
@@ -626,6 +638,7 @@
 # PCMCIA character devices
 #
 # CONFIG_PCMCIA_SERIAL_CS is not set
+# CONFIG_SYNCLINK_CS is not set
 # CONFIG_MWAVE is not set
 
 #
@@ -637,6 +650,9 @@
 # File systems
 #
 # CONFIG_QUOTA is not set
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+# CONFIG_QIFACE_COMPAT is not set
 # CONFIG_AUTOFS_FS is not set
 CONFIG_AUTOFS4_FS=y
 # CONFIG_REISERFS_FS is not set
@@ -646,6 +662,8 @@
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EXT3_FS is not set
 # CONFIG_JBD is not set
@@ -663,6 +681,9 @@
 CONFIG_ISO9660_FS=y
 # 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 is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
@@ -693,6 +714,7 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 # CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
@@ -706,7 +728,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
@@ -721,11 +742,13 @@
 #
 CONFIG_VGA_CONSOLE=y
 # CONFIG_VIDEO_SELECT is not set
+# CONFIG_SPEAKUP is not set
 
 #
 # Sound
 #
 CONFIG_SOUND=y
+# CONFIG_SOUND_ALI5455 is not set
 # CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_EMU10K1 is not set
@@ -737,6 +760,7 @@
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
 # CONFIG_SOUND_ICH is not set
 # CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
@@ -774,6 +798,7 @@
 # CONFIG_USB_AUDIO is not set
 # CONFIG_USB_EMI26 is not set
 # CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_MIDI is not set
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_DATAFAB is not set
@@ -782,6 +807,7 @@
 # CONFIG_USB_STORAGE_DPCM is not set
 # CONFIG_USB_STORAGE_HP8200e is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
 # CONFIG_USB_STORAGE_JUMPSHOT is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
@@ -798,6 +824,7 @@
 # CONFIG_USB_HIDDEV is not set
 # CONFIG_USB_KBD is not set
 # CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
 
 #
@@ -836,38 +863,13 @@
 # USB Serial Converter support
 #
 # CONFIG_USB_SERIAL is not set
-# CONFIG_USB_SERIAL_GENERIC is not set
-# CONFIG_USB_SERIAL_BELKIN is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
-# CONFIG_USB_SERIAL_EMPEG is not set
-# CONFIG_USB_SERIAL_FTDI_SIO is not set
-# CONFIG_USB_SERIAL_VISOR is not set
-# CONFIG_USB_SERIAL_IPAQ is not set
-# CONFIG_USB_SERIAL_IR is not set
-# CONFIG_USB_SERIAL_EDGEPORT is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_CYBERJACK is not set
-# CONFIG_USB_SERIAL_XIRCOM is not set
-# CONFIG_USB_SERIAL_OMNINET is not set
 
 #
 # USB Miscellaneous drivers
 #
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_TIGL is not set
 # CONFIG_USB_BRLVGER is not set
 
 #
@@ -879,3 +881,9 @@
 # Kernel hacking
 #
 # CONFIG_DEBUG_KERNEL is not set
+
+#
+# Library routines
+#
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/apic.c linux.20pre10-ac2/arch/i386/kernel/apic.c
--- linux.20pre10/arch/i386/kernel/apic.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/apic.c	2002-08-13 14:02:53.000000000 +0100
@@ -29,6 +29,7 @@
 #include <asm/mtrr.h>
 #include <asm/mpspec.h>
 #include <asm/pgalloc.h>
+#include <asm/smpboot.h>
 
 /* Using APIC to generate smp_local_timer_interrupt? */
 int using_apic_timer = 0;
@@ -260,6 +261,16 @@
 	apic_write_around(APIC_LVT1, value);
 }
 
+static unsigned long apic_ldr_value(unsigned long value)
+{
+	if (clustered_apic_logical)
+		return (value);
+	if (clustered_apic_physical)
+		return (((value) & ~APIC_LDR_MASK) |
+			SET_APIC_LOGICAL_ID(physical_to_logical_apicid(hard_smp_processor_id())));
+	return (((value) & ~APIC_LDR_MASK) | SET_APIC_LOGICAL_ID(1UL << smp_processor_id()));
+}
+
 void __init setup_local_APIC (void)
 {
 	unsigned long value, ver, maxlvt;
@@ -292,21 +303,23 @@
 	 * document number 292116).  So here it goes...
 	 */
 
-	if (!clustered_apic_mode) {
+	if (!clustered_apic_logical) {
 		/*
-		 * In clustered apic mode, the firmware does this for us 
-		 * Put the APIC into flat delivery mode.
-		 * Must be "all ones" explicitly for 82489DX.
+		 * For NUMA-Q (clustered apic logical), the firmware does this
+		 * for us. Otherwise put the APIC into clustered or flat
+		 * delivery mode. Must be "all ones" explicitly for 82489DX.
 		 */
-		apic_write_around(APIC_DFR, 0xffffffff);
+
+		if(clustered_apic_mode)
+			apic_write_around(APIC_DFR, APIC_DFR_CLUSTER);
+		else
+			apic_write_around(APIC_DFR, APIC_DFR_FLAT);
 
 		/*
 		 * Set up the logical destination ID.
 		 */
 		value = apic_read(APIC_LDR);
-		value &= ~APIC_LDR_MASK;
-		value |= (1<<(smp_processor_id()+24));
-		apic_write_around(APIC_LDR, value);
+		apic_write_around(APIC_LDR, apic_ldr_value(value));
 	}
 
 	/*
@@ -1050,12 +1063,11 @@
 /*
  * Local APIC timer interrupt. This is the most natural way for doing
  * local interrupts, but local timer interrupts can be emulated by
- * broadcast interrupts too. [in case the hw doesn't support APIC timers]
+ * broadcast interrupts too. [in case the hw doesnt support APIC timers]
  *
  * [ if a single-CPU system runs an SMP kernel then we call the local
  *   interrupt as well. Thus we cannot inline the local irq ... ]
  */
-unsigned int apic_timer_irqs [NR_CPUS];
 
 void smp_apic_timer_interrupt(struct pt_regs * regs)
 {
@@ -1064,7 +1076,7 @@
 	/*
 	 * the NMI deadlock-detector uses this.
 	 */
-	apic_timer_irqs[cpu]++;
+	irq_stat[cpu].apic_timer_irqs++;
 
 	/*
 	 * NOTE! We'd better ACK the irq immediately,
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/apm.c linux.20pre10-ac2/arch/i386/kernel/apm.c
--- linux.20pre10/arch/i386/kernel/apm.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/apm.c	2002-08-26 14:19:32.000000000 +0100
@@ -247,6 +247,7 @@
  *	    					powering off
  *	    [no-]debug			log some debugging messages
  *	    [no-]power[-_]off		power off on shutdown
+ *	    [no-]smp			Use apm even on an SMP box
  *	    bounce[-_]interval=<n>	number of ticks to ignore suspend
  *	    				bounces
  *          idle[-_]threshold=<n>       System idle percentage above which to
@@ -393,6 +394,7 @@
 static int			got_clock_diff;
 #endif
 static int			debug;
+static int			smp = 0;
 static int			apm_disabled = -1;
 #ifdef CONFIG_SMP
 static int			power_off;
@@ -494,6 +496,40 @@
 }
 
 /*
+ * Lock APM functionality to physical CPU 0
+ */
+ 
+#ifdef CONFIG_SMP
+
+static unsigned long apm_save_cpus(void)
+{
+	unsigned long x = current->cpus_allowed;
+	/* Some bioses don't like being called from CPU != 0 */
+	if (cpu_number_map(smp_processor_id()) != 0) {
+		set_cpus_allowed(current, 1 << cpu_logical_map(0));
+		if (unlikely(cpu_number_map(smp_processor_id()) != 0))
+			BUG();
+	}
+	return x;
+}
+
+static inline void apm_restore_cpus(unsigned long mask)
+{
+	set_cpus_allowed(current, mask);
+}
+
+#else
+
+/*
+ *	No CPU lockdown needed on a uniprocessor
+ */
+ 
+#define apm_save_cpus()	0
+#define apm_restore_cpus(x)	(void)(x)
+
+#endif
+
+/*
  * These are the actual BIOS calls.  Depending on APM_ZERO_SEGS and
  * apm_info.allow_ints, we are being really paranoid here!  Not only
  * are interrupts disabled, but all the segment registers (except SS)
@@ -566,7 +602,8 @@
 {
 	APM_DECL_SEGS
 	unsigned long	flags;
-
+	unsigned long cpus = apm_save_cpus();
+	
 	__save_flags(flags);
 	APM_DO_CLI;
 	APM_DO_SAVE_SEGS;
@@ -588,6 +625,9 @@
 		: "memory", "cc");
 	APM_DO_RESTORE_SEGS;
 	__restore_flags(flags);
+	
+	apm_restore_cpus(cpus);
+	
 	return *eax & 0xff;
 }
 
@@ -611,6 +651,8 @@
 	APM_DECL_SEGS
 	unsigned long	flags;
 
+	unsigned long cpus = apm_save_cpus();
+	
 	__save_flags(flags);
 	APM_DO_CLI;
 	APM_DO_SAVE_SEGS;
@@ -636,6 +678,9 @@
 	}
 	APM_DO_RESTORE_SEGS;
 	__restore_flags(flags);
+
+	apm_restore_cpus(cpus);
+	
 	return error;
 }
 
@@ -751,10 +796,12 @@
 	if (apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &eax)) {
 		static unsigned long t;
 
-		if (time_after(jiffies, t + 10 * HZ)) {
+		/* This always fails on some SMP boards running UP kernels.
+		 * Only report the failure the first 5 times.
+		 */
+		if (++t < 5) {
 			printk(KERN_DEBUG "apm_do_idle failed (%d)\n",
 					(eax >> 8) & 0xff);
-			t = jiffies;
 		}
 		return -1;
 	}
@@ -888,17 +935,12 @@
 	/*
 	 * This may be called on an SMP machine.
 	 */
-#ifdef CONFIG_SMP
-	/* Some bioses don't like being called from CPU != 0 */
-	if (cpu_number_map(smp_processor_id()) != 0) {
-		current->cpus_allowed = 1;
-		schedule();
-		if (unlikely(cpu_number_map(smp_processor_id()) != 0))
-			BUG();
-	}
-#endif
 	if (apm_info.realmode_power_off)
+	{
+		(void)apm_save_cpus();
 		machine_real_restart(po_bios_call, sizeof(po_bios_call));
+		/* Never returns */
+	}
 	else
 		(void) set_system_power_state(APM_STATE_OFF);
 }
@@ -1074,6 +1116,19 @@
 	}
 	if ((error == APM_SUCCESS) || (error == APM_NO_ERROR))
 		return 1;
+	if (error == APM_NOT_ENGAGED) {
+		static int tried;
+		int eng_error;
+		if (tried++ == 0) {
+			eng_error = apm_engage_power_management(APM_DEVICE_ALL, 1);
+			if (eng_error) {
+				apm_error("set display", error);
+				apm_error("engage interface", eng_error);
+				return 0;
+			} else
+				return apm_console_blank(blank);
+		}
+	}
 	apm_error("set display", error);
 	return 0;
 }
@@ -1397,7 +1452,7 @@
 	as = fp->private_data;
 	if (check_apm_user(as, "read"))
 		return -EIO;
-	if (count < sizeof(apm_event_t))
+	if ((int)count < sizeof(apm_event_t))
 		return -EINVAL;
 	if ((queue_empty(as)) && (fp->f_flags & O_NONBLOCK))
 		return -EAGAIN;
@@ -1571,7 +1626,7 @@
 
 	p = buf;
 
-	if ((smp_num_cpus == 1) &&
+	if ((smp_num_cpus == 1 || smp) &&
 	    !(error = apm_get_power_status(&bx, &cx, &dx))) {
 		ac_line_status = (bx >> 8) & 0xff;
 		battery_status = bx & 0xff;
@@ -1716,7 +1771,7 @@
 		}
 	}
 
-	if (debug) {
+	if (debug && (smp_num_cpus == 1 || smp )) {
 		error = apm_get_power_status(&bx, &cx, &dx);
 		if (error)
 			printk(KERN_INFO "apm: power status not available\n");
@@ -1760,7 +1815,7 @@
 		pm_power_off = apm_power_off;
 	register_sysrq_key('o', &sysrq_poweroff_op);
 
-	if (smp_num_cpus == 1) {
+	if (smp_num_cpus == 1 || smp) {
 #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
 		console_blank_hook = apm_console_blank;
 #endif
@@ -1799,6 +1854,11 @@
 			str += 3;
 		if (strncmp(str, "debug", 5) == 0)
 			debug = !invert;
+		if (strncmp(str, "smp", 3) == 0)
+		{
+			smp = !invert;
+			idle_threshold = 100;
+		}
 		if ((strncmp(str, "power-off", 9) == 0) ||
 		    (strncmp(str, "power_off", 9) == 0))
 			power_off = !invert;
@@ -1903,7 +1963,7 @@
 		printk(KERN_NOTICE "apm: disabled on user request.\n");
 		return -ENODEV;
 	}
-	if ((smp_num_cpus > 1) && !power_off) {
+	if ((smp_num_cpus > 1) && !power_off && !smp) {
 		printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n");
 		return -ENODEV;
 	}
@@ -1957,7 +2017,7 @@
 
 	kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
 
-	if (smp_num_cpus > 1) {
+	if (smp_num_cpus > 1 && !smp) {
 		printk(KERN_NOTICE
 		   "apm: disabled - APM is not SMP safe (power off active).\n");
 		return 0;
@@ -2025,5 +2085,8 @@
 MODULE_PARM(idle_period, "i");
 MODULE_PARM_DESC(idle_period,
 	"Period (in sec/100) over which to caculate the idle percentage");
+MODULE_PARM(smp, "i");
+MODULE_PARM_DESC(smp,
+	"Set this to enable APM use on an SMP platform. Use with caution on older systems");
 
 EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/dmi_scan.c linux.20pre10-ac2/arch/i386/kernel/dmi_scan.c
--- linux.20pre10/arch/i386/kernel/dmi_scan.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/dmi_scan.c	2002-10-11 00:12:50.000000000 +0100
@@ -31,7 +31,7 @@
 	if(!s)
 		return "";
 	s--;
-	while(s>0)
+	while(s>0 && *bp)
 	{
 		bp+=strlen(bp);
 		bp++;
@@ -50,7 +50,7 @@
 	u8 *buf;
 	struct dmi_header *dm;
 	u8 *data;
-	int i=1;
+	int i=0;
 		
 	buf = bt_ioremap(base, len);
 	if(buf==NULL)
@@ -59,28 +59,23 @@
 	data = buf;
 
 	/*
- 	 *	Stop when we see al the items the table claimed to have
+ 	 *	Stop when we see all the items the table claimed to have
  	 *	OR we run off the end of the table (also happens)
  	 */
  
-	while(i<num && (data - buf) < len)
+	while(i<num && data-buf+sizeof(struct dmi_header)<=len)
 	{
 		dm=(struct dmi_header *)data;
-	
 		/*
-		 *	Avoid misparsing crud if the length of the last
-	 	 *	record is crap 
+		 *  We want to know the total length (formated area and strings)
+		 *  before decoding to make sure we won't run off the table in
+		 *  dmi_decode or dmi_string
 		 */
-		if((data-buf+dm->length) >= len)
-			break;
-		decode(dm);		
 		data+=dm->length;
-		/*
-		 *	Don't go off the end of the data if there is
-	 	 *	stuff looking like string fill past the end
-	 	 */
-		while((data-buf) < len && (*data || data[1]))
+		while(data-buf<len-1 && (data[0] || data[1]))
 			data++;
+		if(data-buf<len-1)
+			decode(dm);
 		data+=2;
 		i++;
 	}
@@ -89,11 +84,20 @@
 }
 
 
+inline static int __init dmi_checksum(u8 *buf)
+{
+	u8 sum=0;
+	int a;
+	
+	for(a=0; a<15; a++)
+		sum+=buf[a];
+	return (sum==0);
+}
+
 static int __init dmi_iterate(void (*decode)(struct dmi_header *))
 {
-	unsigned char buf[20];
-	long fp=0xE0000L;
-	fp -= 16;
+	u8 buf[15];
+	u32 fp=0xF0000;
 
 #ifdef CONFIG_SIMNOW
 	/*
@@ -105,24 +109,30 @@
  	
 	while( fp < 0xFFFFF)
 	{
-		fp+=16;
-		isa_memcpy_fromio(buf, fp, 20);
-		if(memcmp(buf, "_DMI_", 5)==0)
+		isa_memcpy_fromio(buf, fp, 15);
+		if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf))
 		{
 			u16 num=buf[13]<<8|buf[12];
 			u16 len=buf[7]<<8|buf[6];
 			u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
 
-			dmi_printk((KERN_INFO "DMI %d.%d present.\n",
-				buf[14]>>4, buf[14]&0x0F));
+			/*
+			 * DMI version 0.0 means that the real version is taken from
+			 * the SMBIOS version, which we don't know at this point.
+			 */
+			if(buf[14]!=0)
+				dmi_printk((KERN_INFO "DMI %d.%d present.\n",
+					buf[14]>>4, buf[14]&0x0F));
+			else
+				dmi_printk((KERN_INFO "DMI present.\n"));
 			dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n",
-				buf[13]<<8|buf[12],
-				buf[7]<<8|buf[6]));
+				num, len));
 			dmi_printk((KERN_INFO "DMI table at 0x%08X.\n",
-				buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]));
+				base));
 			if(dmi_table(base,len, num, decode)==0)
 				return 0;
 		}
+		fp+=16;
 	}
 	return -1;
 }
@@ -475,6 +485,22 @@
 	return 0;
 }
 
+/*
+ * Work around broken HP Pavilion Notebooks which assign USB to
+ * IRQ 9 even though it is actually wired to IRQ 11
+ */
+static __init int fix_broken_hp_bios_irq9(struct dmi_blacklist *d)
+{
+#ifdef CONFIG_PCI
+	extern int broken_hp_bios_irq9;
+	if (broken_hp_bios_irq9 == 0)
+	{
+		broken_hp_bios_irq9 = 1;
+		printk(KERN_INFO "%s detected - fixing broken IRQ routing\n", d->ident);
+	}
+#endif
+	return 0;
+}
 
 /*
  *	Simple "print if true" callback
@@ -755,7 +781,14 @@
 			NO_MATCH, NO_MATCH
 			} },
 	 
-			
+	{ fix_broken_hp_bios_irq9, "HP Pavilion N5400 Series Laptop", {
+			MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+			MATCH(DMI_BIOS_VERSION, "GE.M1.03"),
+			MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook Model GE"),
+			MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736")
+			} },
+ 
+
 	/*
 	 *	Generic per vendor APM settings
 	 */
@@ -810,59 +843,43 @@
 static void __init dmi_decode(struct dmi_header *dm)
 {
 	u8 *data = (u8 *)dm;
-	char *p;
 	
 	switch(dm->type)
 	{
 		case  0:
-			p=dmi_string(dm,data[4]);
-			if(*p)
-			{
-				dmi_printk(("BIOS Vendor: %s\n", p));
-				dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
-				dmi_printk(("BIOS Version: %s\n", 
-					dmi_string(dm, data[5])));
-				dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
-				dmi_printk(("BIOS Release: %s\n",
-					dmi_string(dm, data[8])));
-				dmi_save_ident(dm, DMI_BIOS_DATE, 8);
-			}
+			dmi_printk(("BIOS Vendor: %s\n",
+				dmi_string(dm, data[4])));
+			dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
+			dmi_printk(("BIOS Version: %s\n", 
+				dmi_string(dm, data[5])));
+			dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
+			dmi_printk(("BIOS Release: %s\n",
+				dmi_string(dm, data[8])));
+			dmi_save_ident(dm, DMI_BIOS_DATE, 8);
 			break;
-			
 		case 1:
-			p=dmi_string(dm,data[4]);
-			if(*p)
-			{
-				dmi_printk(("System Vendor: %s.\n",p));
-				dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
-				dmi_printk(("Product Name: %s.\n",
-					dmi_string(dm, data[5])));
-				dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
-				dmi_printk(("Version %s.\n",
-					dmi_string(dm, data[6])));
-				dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
-				dmi_printk(("Serial Number %s.\n",
-					dmi_string(dm, data[7])));
-			}
+			dmi_printk(("System Vendor: %s\n",
+				dmi_string(dm, data[4])));
+			dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
+			dmi_printk(("Product Name: %s\n",
+				dmi_string(dm, data[5])));
+			dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
+			dmi_printk(("Version: %s\n",
+				dmi_string(dm, data[6])));
+			dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
+			dmi_printk(("Serial Number: %s\n",
+				dmi_string(dm, data[7])));
 			break;
 		case 2:
-			p=dmi_string(dm,data[4]);
-			if(*p)
-			{
-				dmi_printk(("Board Vendor: %s.\n",p));
-				dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
-				dmi_printk(("Board Name: %s.\n",
-					dmi_string(dm, data[5])));
-				dmi_save_ident(dm, DMI_BOARD_NAME, 5);
-				dmi_printk(("Board Version: %s.\n",
-					dmi_string(dm, data[6])));
-				dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
-			}
-			break;
-		case 3:
-			p=dmi_string(dm,data[8]);
-			if(*p && *p!=' ')
-				dmi_printk(("Asset Tag: %s.\n", p));
+			dmi_printk(("Board Vendor: %s\n",
+				dmi_string(dm, data[4])));
+			dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
+			dmi_printk(("Board Name: %s\n",
+				dmi_string(dm, data[5])));
+			dmi_save_ident(dm, DMI_BOARD_NAME, 5);
+			dmi_printk(("Board Version: %s\n",
+				dmi_string(dm, data[6])));
+			dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
 			break;
 	}
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/elanfreq.c linux.20pre10-ac2/arch/i386/kernel/elanfreq.c
--- linux.20pre10/arch/i386/kernel/elanfreq.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/elanfreq.c	2002-09-30 17:24:56.000000000 +0100
@@ -0,0 +1,336 @@
+/*
+ * 	elanfreq: 	cpufreq driver for the AMD ELAN family
+ *
+ *	(c) Copyright 2002 Robert Schwebel <r.schwebel@pengutronix.de>
+ *
+ *	Parts of this code are (c) Sven Geggus <sven@geggus.net> 
+ *
+ *      All Rights Reserved. 
+ *
+ *	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. 
+ *
+ *	2002-02-13: - initial revision for 2.4.18-pre9 by Robert Schwebel
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/cpufreq.h>
+
+#include <asm/msr.h>
+#include <asm/timex.h>
+#include <asm/io.h>
+
+#define REG_CSCIR 0x22 		/* Chip Setup and Control Index Register    */
+#define REG_CSCDR 0x23		/* Chip Setup and Control Data  Register    */
+
+#define SAFE_FREQ 33000		/* every Elan CPU can run at 33 MHz         */
+
+static struct cpufreq_driver *elanfreq_driver;
+
+/* Module parameter */
+static int max_freq;
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Robert Schwebel <r.schwebel@pengutronix.de>, Sven Geggus <sven@geggus.net>");
+MODULE_DESCRIPTION("cpufreq driver for AMD's Elan CPUs");
+
+struct s_elan_multiplier {
+	int clock;		/* frequency in kHz                         */
+	int val40h;		/* PMU Force Mode register                  */
+	int val80h;		/* CPU Clock Speed Register                 */
+};
+
+/*
+ * It is important that the frequencies 
+ * are listed in ascending order here!
+ */
+struct s_elan_multiplier elan_multiplier[] = {
+	{1000,	0x02,	0x18},
+	{2000,	0x02,	0x10},
+	{4000,	0x02,	0x08},
+	{8000,	0x00,	0x00},
+	{16000,	0x00,	0x02},
+	{33000,	0x00,	0x04},
+	{66000,	0x01,	0x04},
+	{99000,	0x01,	0x05}
+};
+
+
+/**
+ *	elanfreq_get_cpu_frequency: determine current cpu speed
+ *
+ *	Finds out at which frequency the CPU of the Elan SOC runs
+ *	at the moment. Frequencies from 1 to 33 MHz are generated 
+ *	the normal way, 66 and 99 MHz are called "Hyperspeed Mode"
+ *	and have the rest of the chip running with 33 MHz. 
+ */
+
+static unsigned int elanfreq_get_cpu_frequency(void)
+{
+        u8 clockspeed_reg;    /* Clock Speed Register */
+	
+	local_irq_disable();
+        outb_p(0x80,REG_CSCIR);
+        clockspeed_reg = inb_p(REG_CSCDR);
+	local_irq_enable();
+
+        if ((clockspeed_reg & 0xE0) == 0xE0) { return 0; }
+
+        /* Are we in CPU clock multiplied mode (66/99 MHz)? */
+        if ((clockspeed_reg & 0xE0) == 0xC0) {
+                if ((clockspeed_reg & 0x01) == 0) {
+			return 66000;
+		} else {
+			return 99000;             
+		}
+        }
+
+	/* 33 MHz is not 32 MHz... */
+	if ((clockspeed_reg & 0xE0)==0xA0)
+		return 33000;
+
+        return ((1<<((clockspeed_reg & 0xE0) >> 5)) * 1000);
+}
+
+
+/**
+ *      elanfreq_set_cpu_frequency: Change the CPU core frequency
+ * 	@cpu: cpu number
+ *	@freq: frequency in kHz
+ *
+ *      This function takes a frequency value and changes the CPU frequency 
+ *	according to this. Note that the frequency has to be checked by
+ *	elanfreq_validatespeed() for correctness!
+ *	
+ *	There is no return value. 
+ */
+
+static void elanfreq_set_cpu_state (unsigned int state) {
+
+	struct cpufreq_freqs    freqs;
+
+	if (!elanfreq_driver) {
+		printk(KERN_ERR "cpufreq: initialization problem or invalid target frequency\n");
+		return;
+	}
+
+	freqs.old = elanfreq_get_cpu_frequency();
+	freqs.new = elan_multiplier[state].clock;
+	freqs.cpu = CPUFREQ_ALL_CPUS; /* elanfreq.c is UP only driver */
+	
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	printk(KERN_INFO "elanfreq: attempting to set frequency to %i kHz\n",elan_multiplier[state].clock);
+
+
+	/* 
+	 * Access to the Elan's internal registers is indexed via    
+	 * 0x22: Chip Setup & Control Register Index Register (CSCI) 
+	 * 0x23: Chip Setup & Control Register Data  Register (CSCD) 
+	 *
+	 */
+
+	/* 
+	 * 0x40 is the Power Management Unit's Force Mode Register. 
+	 * Bit 6 enables Hyperspeed Mode (66/100 MHz core frequency)
+	 */
+
+	local_irq_disable();
+	outb_p(0x40,REG_CSCIR); 	/* Disable hyperspeed mode          */
+	outb_p(0x00,REG_CSCDR);
+	local_irq_enable();		/* wait till internal pipelines and */
+	udelay(1000);			/* buffers have cleaned up          */
+
+	local_irq_disable();
+
+	/* now, set the CPU clock speed register (0x80) */
+	outb_p(0x80,REG_CSCIR);
+	outb_p(elan_multiplier[state].val80h,REG_CSCDR);
+
+	/* now, the hyperspeed bit in PMU Force Mode Register (0x40) */
+	outb_p(0x40,REG_CSCIR);
+	outb_p(elan_multiplier[state].val40h,REG_CSCDR);
+	udelay(10000);
+	local_irq_enable();
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+};
+
+
+/**
+ *	elanfreq_validatespeed: test if frequency range is valid 
+ *
+ *	This function checks if a given frequency range in kHz is valid 
+ *      for the hardware supported by the driver. 
+ */
+
+static void elanfreq_verify (struct cpufreq_policy *policy)
+{
+	unsigned int    number_states = 0;
+	unsigned int    i;
+
+	if (!policy || !max_freq)
+		return;
+
+	policy->cpu = 0;
+
+	cpufreq_verify_within_limits(policy, 1000, max_freq);
+
+	for (i=(sizeof(elan_multiplier)/sizeof(struct s_elan_multiplier) - 1); i>=0; i--)
+		if ((elan_multiplier[i].clock >= policy->min) &&
+		    (elan_multiplier[i].clock <= policy->max))
+			number_states++;
+
+	if (number_states)
+		return;
+
+	for (i=(sizeof(elan_multiplier)/sizeof(struct s_elan_multiplier) - 1); i>=0; i--)
+		if (elan_multiplier[i].clock < policy->max)
+			break;
+
+	policy->max = elan_multiplier[i+1].clock;
+
+	return;
+}
+
+static void elanfreq_setpolicy (struct cpufreq_policy *policy)
+{
+	unsigned int    number_states = 0;
+	unsigned int    i, j=4;
+
+	if (!elanfreq_driver)
+		return;
+
+	for (i=(sizeof(elan_multiplier)/sizeof(struct s_elan_multiplier) - 1); i>=0; i--)
+		if ((elan_multiplier[i].clock >= policy->min) &&
+		    (elan_multiplier[i].clock <= policy->max))
+		{
+			number_states++;
+			j = i;
+		}
+
+	if (number_states == 1) {
+		elanfreq_set_cpu_state(j);
+		return;
+	}
+
+	switch (policy->policy) {
+	case CPUFREQ_POLICY_POWERSAVE:
+		for (i=(sizeof(elan_multiplier)/sizeof(struct s_elan_multiplier) - 1); i>=0; i--)
+			if ((elan_multiplier[i].clock >= policy->min) &&
+			    (elan_multiplier[i].clock <= policy->max))
+				j = i;
+		break;
+	case CPUFREQ_POLICY_PERFORMANCE:
+		for (i=0; i<(sizeof(elan_multiplier)/sizeof(struct s_elan_multiplier) - 1); i++)
+			if ((elan_multiplier[i].clock >= policy->min) &&
+			    (elan_multiplier[i].clock <= policy->max))
+				j = i;
+		break;
+	default:
+		return;
+	}
+
+	if (elan_multiplier[j].clock > max_freq)
+		BUG();
+
+	elanfreq_set_cpu_state(j);
+	return;
+}
+
+
+/*
+ *	Module init and exit code
+ */
+
+#ifndef MODULE
+/**
+ * elanfreq_setup - elanfreq command line parameter parsing
+ *
+ * elanfreq command line parameter.  Use:
+ *  elanfreq=66000
+ * to set the maximum CPU frequency to 66 MHz. Note that in
+ * case you do not give this boot parameter, the maximum
+ * frequency will fall back to _current_ CPU frequency which
+ * might be lower. If you build this as a module, use the
+ * max_freq module parameter instead.
+ */
+static int __init elanfreq_setup(char *str)
+{
+	max_freq = simple_strtoul(str, &str, 0);
+	return 1;
+}
+__setup("elanfreq=", elanfreq_setup);
+#endif
+
+static int __init elanfreq_init(void) 
+{	
+	struct cpuinfo_x86 *c = cpu_data;
+	struct cpufreq_driver *driver;
+	int ret;
+
+	/* Test if we have the right hardware */
+	if ((c->x86_vendor != X86_VENDOR_AMD) ||
+		(c->x86 != 4) || (c->x86_model!=10))
+	{
+		printk(KERN_INFO "elanfreq: error: no Elan processor found!\n");
+                return -ENODEV;
+	}
+	
+	driver = kmalloc(sizeof(struct cpufreq_driver) +
+			 NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
+	if (!driver)
+		return -ENOMEM;
+
+	driver->policy = (struct cpufreq_policy *) (driver + 1);
+
+	if (!max_freq)
+		max_freq = elanfreq_get_cpu_frequency();
+
+#ifdef CONFIG_CPU_FREQ_24_API
+	driver->cpu_min_freq    = 1000;
+	driver->cpu_cur_freq[0] = elanfreq_get_cpu_frequency();
+#endif
+
+	driver->verify        = &elanfreq_verify;
+	driver->setpolicy     = &elanfreq_setpolicy;
+
+	driver->policy[0].cpu    = 0;
+	driver->policy[0].min    = 1000;
+	driver->policy[0].max    = max_freq;
+	driver->policy[0].policy = CPUFREQ_POLICY_PERFORMANCE;
+	driver->policy[0].max_cpu_freq  = max_freq;
+
+	ret = cpufreq_register(driver);
+	if (ret) {
+		kfree(driver);
+		return ret;
+	}
+
+	elanfreq_driver = driver;
+
+	return 0;
+}
+
+
+static void __exit elanfreq_exit(void) 
+{
+	if (elanfreq_driver) {
+		cpufreq_unregister();
+		kfree(elanfreq_driver);
+	}
+}
+
+module_init(elanfreq_init);
+module_exit(elanfreq_exit);
+
+MODULE_PARM (max_freq, "i");
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/entry.S linux.20pre10-ac2/arch/i386/kernel/entry.S
--- linux.20pre10/arch/i386/kernel/entry.S	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/entry.S	2002-09-15 18:17:09.000000000 +0100
@@ -77,7 +77,7 @@
 exec_domain	= 16
 need_resched	= 20
 tsk_ptrace	= 24
-processor	= 52
+cpu		= 32
 
 ENOSYS = 38
 
@@ -176,9 +176,11 @@
 
 
 ENTRY(ret_from_fork)
+#if CONFIG_SMP
 	pushl %ebx
 	call SYMBOL_NAME(schedule_tail)
 	addl $4, %esp
+#endif
 	GET_CURRENT(%ebx)
 	testb $0x02,tsk_ptrace(%ebx)	# PT_TRACESYS
 	jne tracesys_exit
@@ -637,8 +639,8 @@
  	.long SYMBOL_NAME(sys_tkill)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sendfile64 */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* 240 reserved for futex */
-	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sched_setaffinity */
-	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for sched_getaffinity */
+	.long SYMBOL_NAME(sys_sched_setaffinity)
+	.long SYMBOL_NAME(sys_sched_getaffinity)
 	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_set_thread_area */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* sys_get_thread_area */
 	.long SYMBOL_NAME(sys_ni_syscall)	/* 245 sys_io_setup */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/head.S linux.20pre10-ac2/arch/i386/kernel/head.S
--- linux.20pre10/arch/i386/kernel/head.S	2002-10-09 21:36:57.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/head.S	2002-08-06 15:42:19.000000000 +0100
@@ -445,4 +445,15 @@
 	.quad 0x00409a0000000000	/* 0x48 APM CS    code */
 	.quad 0x00009a0000000000	/* 0x50 APM CS 16 code (16 bit) */
 	.quad 0x0040920000000000	/* 0x58 APM DS    data */
+ 	/* Segments used for calling PnP BIOS */
+	.quad 0x00c09a0000000000	/* 0x60 32-bit code */
+	.quad 0x00809a0000000000	/* 0x68 16-bit code */
+	.quad 0x0080920000000000	/* 0x70 16-bit data */
+	.quad 0x0080920000000000	/* 0x78 16-bit data */
+	.quad 0x0080920000000000	/* 0x80 16-bit data */
+	.quad 0x0000000000000000	/* 0x88 not used */
+	.quad 0x0000000000000000	/* 0x90 not used */
+	.quad 0x0000000000000000	/* 0x98 not used */
+	/* Per CPU segments */
 	.fill NR_CPUS*4,8,0		/* space for TSS's and LDT's */
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/i386_ksyms.c linux.20pre10-ac2/arch/i386/kernel/i386_ksyms.c
--- linux.20pre10/arch/i386/kernel/i386_ksyms.c	2002-10-09 21:36:57.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/i386_ksyms.c	2002-09-27 13:56:32.000000000 +0100
@@ -49,6 +49,7 @@
 EXPORT_SYMBOL(drive_info);
 #endif
 
+extern unsigned long cpu_khz;
 extern unsigned long get_cmos_time(void);
 
 /* platform dependent support */
@@ -71,6 +72,7 @@
 EXPORT_SYMBOL(pm_idle);
 EXPORT_SYMBOL(pm_power_off);
 EXPORT_SYMBOL(get_cmos_time);
+EXPORT_SYMBOL(cpu_khz);
 EXPORT_SYMBOL(apm_info);
 EXPORT_SYMBOL(gdt);
 EXPORT_SYMBOL(empty_zero_page);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/io_apic.c linux.20pre10-ac2/arch/i386/kernel/io_apic.c
--- linux.20pre10/arch/i386/kernel/io_apic.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/io_apic.c	2002-08-13 14:05:00.000000000 +0100
@@ -28,10 +28,12 @@
 #include <linux/config.h>
 #include <linux/smp_lock.h>
 #include <linux/mc146818rtc.h>
+#include <linux/compiler.h>
 
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/desc.h>
+#include <asm/smpboot.h>
 
 #undef APIC_LOCKUP_DEBUG
 
@@ -183,6 +185,86 @@
 			clear_IO_APIC_pin(apic, pin);
 }
 
+static void set_ioapic_affinity (unsigned int irq, unsigned long mask)
+{
+	unsigned long flags;
+
+	/*
+	 * Only the first 8 bits are valid.
+	 */
+	mask = mask << 24;
+	spin_lock_irqsave(&ioapic_lock, flags);
+	__DO_ACTION(1, = mask, )
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
+#if CONFIG_SMP
+
+typedef struct {
+	unsigned int cpu;
+	unsigned long timestamp;
+} ____cacheline_aligned irq_balance_t;
+
+static irq_balance_t irq_balance[NR_IRQS] __cacheline_aligned
+			= { [ 0 ... NR_IRQS-1 ] = { 0, 0 } };
+
+extern unsigned long irq_affinity [NR_IRQS];
+
+#endif
+
+#define IDLE_ENOUGH(cpu,now) \
+		(idle_cpu(cpu) && ((now) - irq_stat[(cpu)].idle_timestamp > 1))
+
+#define IRQ_ALLOWED(cpu,allowed_mask) \
+		((1 << cpu) & (allowed_mask))
+
+static unsigned long move(int curr_cpu, unsigned long allowed_mask, unsigned long now, int direction)
+{
+	int search_idle = 1;
+	int cpu = curr_cpu;
+
+	goto inside;
+
+	do {
+		if (unlikely(cpu == curr_cpu))
+			search_idle = 0;
+inside:
+		if (direction == 1) {
+			cpu++;
+			if (cpu >= smp_num_cpus)
+				cpu = 0;
+		} else {
+			cpu--;
+			if (cpu == -1)
+				cpu = smp_num_cpus-1;
+		}
+	} while (!IRQ_ALLOWED(cpu,allowed_mask) ||
+			(search_idle && !IDLE_ENOUGH(cpu,now)));
+
+	return cpu;
+}
+
+static inline void balance_irq(int irq)
+{
+#if CONFIG_SMP
+	irq_balance_t *entry = irq_balance + irq;
+	unsigned long now = jiffies;
+
+	if (unlikely(entry->timestamp != now)) {
+		unsigned long allowed_mask;
+		int random_number;
+
+		rdtscl(random_number);
+		random_number &= 1;
+
+		allowed_mask = cpu_online_map & irq_affinity[irq];
+		entry->timestamp = now;
+		entry->cpu = move(entry->cpu, allowed_mask, now, random_number);
+		set_ioapic_affinity(irq, cpu_present_to_apicid(entry->cpu));
+	}
+#endif
+}
+
 /*
  * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to
  * specific CPU-side IRQs.
@@ -287,7 +369,7 @@
 
 	Dprintk("querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n",
 		bus, slot, pin);
-	if (mp_bus_id_to_pci_bus[bus] == -1) {
+	if ((mp_bus_id_to_pci_bus==NULL) || (mp_bus_id_to_pci_bus[bus] == -1)) {
 		printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus);
 		return -1;
 	}
@@ -605,6 +687,40 @@
 	return current_vector;
 }
 
+#ifdef CONFIG_MULTIQUAD
+
+/*
+ * round_robin_cpu_apic_id -- Since Linux doesn't use either the APIC TPRs or
+ * XTPRs to set task/interrupt priority, xAPICs and SAPICs tend to hit one CPU
+ * with all interrupts for each quad.  Distribute the interrupts using a simple
+ * round robin scheme.
+ */
+static inline int round_robin_cpu_apic_id(void)
+{
+	int		val;
+	static unsigned	next_cpu = 0;
+
+	for (;; ++next_cpu) {
+		if (next_cpu >= smp_num_cpus)
+			next_cpu = 0;
+		if (!(logical_cpu_present_map & (1UL << next_cpu)))
+			continue;
+		val = cpu_present_to_apicid(next_cpu);
+		++next_cpu;
+		return (val);
+	}
+}
+
+static inline int __target_cpus(void)
+{
+	if (clustered_apic_logical)
+		return APIC_BROADCAST_ID_APIC;	/* broadcast to local quad */
+	if (clustered_apic_physical)
+		return round_robin_cpu_apic_id();
+	return cpu_online_map;
+}
+#endif
+
 extern void (*interrupt[NR_IRQS])(void);
 static struct hw_interrupt_type ioapic_level_irq_type;
 static struct hw_interrupt_type ioapic_edge_irq_type;
@@ -625,8 +741,8 @@
 		 */
 		memset(&entry,0,sizeof(entry));
 
-		entry.delivery_mode = dest_LowestPrio;
-		entry.dest_mode = INT_DELIVERY_MODE;
+		entry.delivery_mode = INT_DELIVERY_MODE;
+		entry.dest_mode = (INT_DEST_ADDR_MODE != 0);
 		entry.mask = 0;				/* enable IRQ */
 		entry.dest.logical.logical_dest = TARGET_CPUS;
 
@@ -646,7 +762,6 @@
 		if (irq_trigger(idx)) {
 			entry.trigger = 1;
 			entry.mask = 1;
-			entry.dest.logical.logical_dest = TARGET_CPUS;
 		}
 
 		irq = pin_2_irq(idx, apic, pin);
@@ -654,7 +769,7 @@
 		 * skip adding the timer int on secondary nodes, which causes
 		 * a small but painful rift in the time-space continuum
 		 */
-		if (clustered_apic_mode && (apic != 0) && (irq == 0))
+		if (clustered_apic_logical && (apic != 0) && (irq == 0))
 			continue;
 		else
 			add_pin_to_irq(irq, apic, pin);
@@ -688,8 +803,7 @@
 }
 
 /*
- * Set up the 8259A-master output pin as broadcast to all
- * CPUs.
+ * Set up the 8259A-master output pin:
  */
 void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector)
 {
@@ -707,10 +821,10 @@
 	 * We use logical delivery to get the timer IRQ
 	 * to the first CPU.
 	 */
-	entry.dest_mode = INT_DELIVERY_MODE;
+	entry.dest_mode = (INT_DEST_ADDR_MODE != 0);
 	entry.mask = 0;					/* unmask IRQ now */
 	entry.dest.logical.logical_dest = TARGET_CPUS;
-	entry.delivery_mode = dest_LowestPrio;
+	entry.delivery_mode = INT_DELIVERY_MODE;
 	entry.polarity = 0;
 	entry.trigger = 0;
 	entry.vector = vector;
@@ -734,8 +848,9 @@
 
 void __init UNEXPECTED_IO_APIC(void)
 {
-	printk(KERN_WARNING " WARNING: unexpected IO-APIC, please mail\n");
-	printk(KERN_WARNING "          to linux-smp@vger.kernel.org\n");
+	printk(KERN_WARNING 
+		"An unexpected IO-APIC was found. If this kernel release is less than\n"
+		"three months old please report this to linux-smp@vger.kernel.org\n");
 }
 
 void __init print_IO_APIC(void)
@@ -788,6 +903,7 @@
 	printk(KERN_DEBUG ".......     : PRQ implemented: %X\n", reg_01.PRQ);
 	printk(KERN_DEBUG ".......     : IO APIC version: %04X\n", reg_01.version);
 	if (	(reg_01.version != 0x01) && /* 82489DX IO-APICs */
+		(reg_01.version != 0x02) && /* VIA */
 		(reg_01.version != 0x10) && /* oldest IO-APICs */
 		(reg_01.version != 0x11) && /* Pentium/Pro IO-APICs */
 		(reg_01.version != 0x13) && /* Xeon IO-APICs */
@@ -1062,7 +1178,7 @@
 		
 		old_id = mp_ioapics[apic].mpc_apicid;
 
-		if (mp_ioapics[apic].mpc_apicid >= 0xf) {
+		if (mp_ioapics[apic].mpc_apicid >= apic_broadcast_id) {
 			printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
 				apic, mp_ioapics[apic].mpc_apicid);
 			printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
@@ -1074,14 +1190,16 @@
 		 * Sanity check, is the ID really free? Every APIC in a
 		 * system must have a unique ID or we get lots of nice
 		 * 'stuck on smp_invalidate_needed IPI wait' messages.
+		 * I/O APIC IDs no longer have any meaning for xAPICs and SAPICs.
 		 */
-		if (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid)) {
+		if (!clustered_apic_physical &&
+		    (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid))) {
 			printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",
 				apic, mp_ioapics[apic].mpc_apicid);
 			for (i = 0; i < 0xf; i++)
 				if (!(phys_id_present_map & (1 << i)))
 					break;
-			if (i >= 0xf)
+			if (i >= apic_broadcast_id)
 				panic("Max APIC ID exceeded!\n");
 			printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
 				i);
@@ -1209,6 +1327,7 @@
  */
 static void ack_edge_ioapic_irq(unsigned int irq)
 {
+	balance_irq(irq);
 	if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
 					== (IRQ_PENDING | IRQ_DISABLED))
 		mask_IO_APIC_irq(irq);
@@ -1248,6 +1367,7 @@
 	unsigned long v;
 	int i;
 
+	balance_irq(irq);
 /*
  * It appears there is an erratum which affects at least version 0x11
  * of I/O APIC (that's the 82093AA and cores integrated into various
@@ -1304,19 +1424,6 @@
 
 static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ }
 
-static void set_ioapic_affinity (unsigned int irq, unsigned long mask)
-{
-	unsigned long flags;
-	/*
-	 * Only the first 8 bits are valid.
-	 */
-	mask = mask << 24;
-
-	spin_lock_irqsave(&ioapic_lock, flags);
-	__DO_ACTION(1, = mask, )
-	spin_unlock_irqrestore(&ioapic_lock, flags);
-}
-
 /*
  * Level and edge triggered IO-APIC interrupts need different handling,
  * so we use two separate IRQ descriptors. Edge triggered IRQs can be
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/irq.c linux.20pre10-ac2/arch/i386/kernel/irq.c
--- linux.20pre10/arch/i386/kernel/irq.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/irq.c	2002-08-13 14:05:06.000000000 +0100
@@ -170,7 +170,7 @@
 	p += sprintf(p, "LOC: ");
 	for (j = 0; j < smp_num_cpus; j++)
 		p += sprintf(p, "%10u ",
-			apic_timer_irqs[cpu_logical_map(j)]);
+			irq_stat[cpu_logical_map(j)].apic_timer_irqs);
 	p += sprintf(p, "\n");
 #endif
 	p += sprintf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
@@ -1090,7 +1090,7 @@
 
 static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
 
-static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
+unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
 static int irq_affinity_read_proc (char *page, char **start, off_t off,
 			int count, int *eof, void *data)
 {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/ldt.c linux.20pre10-ac2/arch/i386/kernel/ldt.c
--- linux.20pre10/arch/i386/kernel/ldt.c	2002-10-09 21:36:57.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/ldt.c	2002-08-26 14:24:47.000000000 +0100
@@ -12,37 +12,139 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/vmalloc.h>
+#include <linux/slab.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/ldt.h>
 #include <asm/desc.h>
 
+#ifdef CONFIG_SMP /* avoids "defined but not used" warnig */
+static void flush_ldt(void *mm)
+{
+	if (current->active_mm)
+		load_LDT(&current->active_mm->context);
+}
+#endif
+
+static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
+{
+	void *oldldt;
+	void *newldt;
+	int oldsize;
+
+	if (mincount <= pc->size)
+		return 0;
+	oldsize = pc->size;
+	mincount = (mincount+511)&(~511);
+	if (mincount*LDT_ENTRY_SIZE > PAGE_SIZE)
+		newldt = vmalloc(mincount*LDT_ENTRY_SIZE);
+	else
+		newldt = kmalloc(mincount*LDT_ENTRY_SIZE, GFP_KERNEL);
+
+	if (!newldt)
+		return -ENOMEM;
+
+	if (oldsize)
+		memcpy(newldt, pc->ldt, oldsize*LDT_ENTRY_SIZE);
+
+	oldldt = pc->ldt;
+	memset(newldt+oldsize*LDT_ENTRY_SIZE, 0, (mincount-oldsize)*LDT_ENTRY_SIZE);
+	wmb();
+	pc->ldt = newldt;
+	pc->size = mincount;
+	if (reload) {
+		load_LDT(pc);
+#ifdef CONFIG_SMP
+		if (current->mm->cpu_vm_mask != (1<<smp_processor_id()))
+			smp_call_function(flush_ldt, 0, 1, 1);
+#endif
+	}
+	wmb();
+	if (oldsize) {
+		if (oldsize*LDT_ENTRY_SIZE > PAGE_SIZE)
+			vfree(oldldt);
+		else
+			kfree(oldldt);
+	}
+	return 0;
+}
+
+static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
+{
+	int err = alloc_ldt(new, old->size, 0);
+	if (err < 0) {
+		printk(KERN_WARNING "ldt allocation failed\n");
+		new->size = 0;
+		return err;
+	}
+	memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE);
+	return 0;
+}
+
+/*
+ * we do not have to muck with descriptors here, that is
+ * done in switch_mm() as needed.
+ */
+int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+	struct mm_struct * old_mm;
+	int retval = 0;
+
+	init_MUTEX(&mm->context.sem);
+	mm->context.size = 0;
+	old_mm = current->mm;
+	if (old_mm && old_mm->context.size > 0) {
+		down(&old_mm->context.sem);
+		retval = copy_ldt(&mm->context, &old_mm->context);
+		up(&old_mm->context.sem);
+	}
+	return retval;
+}
+
 /*
- * read_ldt() is not really atomic - this is not a problem since
- * synchronization of reads and writes done to the LDT has to be
- * assured by user-space anyway. Writes are atomic, to protect
- * the security checks done on new descriptors.
+ * No need to lock the MM as we are the last user
+ * Do not touch the ldt register, we are already
+ * in the next thread.
  */
+void destroy_context(struct mm_struct *mm)
+{
+	if (mm->context.size) {
+		if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE)
+			vfree(mm->context.ldt);
+		else
+			kfree(mm->context.ldt);
+		mm->context.size = 0;
+	}
+}
+
 static int read_ldt(void * ptr, unsigned long bytecount)
 {
 	int err;
 	unsigned long size;
 	struct mm_struct * mm = current->mm;
 
-	err = 0;
-	if (!mm->context.segments)
-		goto out;
+	if (!mm->context.size)
+		return 0;
+	if (bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES)
+		bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES;
 
-	size = LDT_ENTRIES*LDT_ENTRY_SIZE;
+	down(&mm->context.sem);
+	size = mm->context.size*LDT_ENTRY_SIZE;
 	if (size > bytecount)
 		size = bytecount;
 
-	err = size;
-	if (copy_to_user(ptr, mm->context.segments, size))
+	err = 0;
+	if (copy_to_user(ptr, mm->context.ldt, size))
 		err = -EFAULT;
-out:
-	return err;
+	up(&mm->context.sem);
+	if (err < 0)
+		return err;
+	if (size != bytecount) {
+		/* zero-fill the rest */
+		clear_user(ptr+size, bytecount-size);
+	}
+	return bytecount;
 }
 
 static int read_default_ldt(void * ptr, unsigned long bytecount)
@@ -53,7 +155,7 @@
 
 	err = 0;
 	address = &default_ldt[0];
-	size = sizeof(struct desc_struct);
+	size = 5*sizeof(struct desc_struct);
 	if (size > bytecount)
 		size = bytecount;
 
@@ -88,24 +190,14 @@
 			goto out;
 	}
 
-	/*
-	 * the GDT index of the LDT is allocated dynamically, and is
-	 * limited by MAX_LDT_DESCRIPTORS.
-	 */
-	down_write(&mm->mmap_sem);
-	if (!mm->context.segments) {
-		void * segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
-		error = -ENOMEM;
-		if (!segments)
+	down(&mm->context.sem);
+	if (ldt_info.entry_number >= mm->context.size) {
+		error = alloc_ldt(&current->mm->context, ldt_info.entry_number+1, 1);
+		if (error < 0)
 			goto out_unlock;
-		memset(segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
-		wmb();
-		mm->context.segments = segments;
-		mm->context.cpuvalid = 1UL << smp_processor_id();
-		load_LDT(mm);
 	}
 
-	lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.segments);
+	lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->context.ldt);
 
    	/* Allow LDTs to be cleared by the user. */
    	if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
@@ -143,7 +235,7 @@
 	error = 0;
 
 out_unlock:
-	up_write(&mm->mmap_sem);
+	up(&mm->context.sem);
 out:
 	return error;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/longhaul.c linux.20pre10-ac2/arch/i386/kernel/longhaul.c
--- linux.20pre10/arch/i386/kernel/longhaul.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/longhaul.c	2002-10-10 23:54:36.000000000 +0100
@@ -0,0 +1,821 @@
+/*
+ *  $Id: longhaul.c,v 1.73 2002/10/08 07:59:14 db Exp $
+ *
+ *  (C) 2001  Dave Jones. <davej@suse.de>
+ *  (C) 2002  Padraig Brady. <padraig@antefacto.com>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *  Based upon datasheets & sample CPUs kindly provided by VIA.
+ *
+ *  VIA have currently 3 different versions of Longhaul.
+ *
+ *  +---------------------+----------+---------------------------------+
+ *  | Marketing name      | Codename | longhaul version / features.    |
+ *  +---------------------+----------+---------------------------------+
+ *  |  Samuel/CyrixIII    |   C5A    | v1 : multipliers only           |
+ *  |  Samuel2/C3         | C3E/C5B  | v1 : multiplier only            |
+ *  |  Ezra               |   C5C    | v2 : multipliers & voltage      |
+ *  |  Ezra-T             | C5M/C5N  | v3 : multipliers, voltage & FSB |
+ *  +---------------------+----------+---------------------------------+
+ *
+ *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h> 
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <asm/msr.h>
+#include <asm/timex.h>
+#include <asm/io.h>
+
+#define DEBUG
+
+#ifdef DEBUG
+#define dprintk(msg...) printk(msg)
+#else
+#define dprintk(msg...) do { } while(0);
+#endif
+
+static int numscales=16, numvscales;
+static int minvid, maxvid;
+static int can_scale_voltage;
+static int can_scale_fsb;
+static int vrmrev;
+
+
+/* Module parameters */
+static int dont_scale_voltage;
+static int dont_scale_fsb;
+static int current_fsb;
+
+#define __hlt()     __asm__ __volatile__("hlt": : :"memory")
+
+/*
+ * Clock ratio tables.
+ * The eblcr ones specify the ratio read from the CPU.
+ * The clock_ratio ones specify what to write to the CPU.
+ */
+
+/* VIA C3 Samuel 1  & Samuel 2 (stepping 0)*/
+static int __initdata longhaul1_clock_ratio[16] = {
+	-1, /* 0000 -> RESERVED */
+	30, /* 0001 ->  3.0x */
+	40, /* 0010 ->  4.0x */
+	-1, /* 0011 -> RESERVED */
+	-1, /* 0100 -> RESERVED */
+	35, /* 0101 ->  3.5x */
+	45, /* 0110 ->  4.5x */
+	55, /* 0111 ->  5.5x */
+	60, /* 1000 ->  6.0x */
+	70, /* 1001 ->  7.0x */
+	80, /* 1010 ->  8.0x */
+	50, /* 1011 ->  5.0x */
+	65, /* 1100 ->  6.5x */
+	75, /* 1101 ->  7.5x */
+	-1, /* 1110 -> RESERVED */
+	-1, /* 1111 -> RESERVED */
+};
+
+static int __initdata samuel1_eblcr[16] = {
+	50, /* 0000 -> RESERVED */
+	30, /* 0001 ->  3.0x */
+	40, /* 0010 ->  4.0x */
+	-1, /* 0011 -> RESERVED */
+	55, /* 0100 ->  5.5x */
+	35, /* 0101 ->  3.5x */
+	45, /* 0110 ->  4.5x */
+	-1, /* 0111 -> RESERVED */
+	-1, /* 1000 -> RESERVED */
+	70, /* 1001 ->  7.0x */
+	80, /* 1010 ->  8.0x */
+	60, /* 1011 ->  6.0x */
+	-1, /* 1100 -> RESERVED */
+	75, /* 1101 ->  7.5x */
+	-1, /* 1110 -> RESERVED */
+	65, /* 1111 ->  6.5x */
+};
+
+/* VIA C3 Samuel2 Stepping 1->15 & VIA C3 Ezra */
+static int __initdata longhaul2_clock_ratio[16] = {
+	100, /* 0000 -> 10.0x */
+	30,  /* 0001 ->  3.0x */
+	40,  /* 0010 ->  4.0x */
+	90,  /* 0011 ->  9.0x */
+	95,  /* 0100 ->  9.5x */
+	35,  /* 0101 ->  3.5x */
+	45,  /* 0110 ->  4.5x */
+	55,  /* 0111 ->  5.5x */
+	60,  /* 1000 ->  6.0x */
+	70,  /* 1001 ->  7.0x */
+	80,  /* 1010 ->  8.0x */
+	50,  /* 1011 ->  5.0x */
+	65,  /* 1100 ->  6.5x */
+	75,  /* 1101 ->  7.5x */
+	85,  /* 1110 ->  8.5x */
+	120, /* 1111 -> 12.0x */
+};
+
+static int __initdata samuel2_eblcr[16] = {
+	50,  /* 0000 ->  5.0x */
+	30,  /* 0001 ->  3.0x */
+	40,  /* 0010 ->  4.0x */
+	100, /* 0011 -> 10.0x */
+	55,  /* 0100 ->  5.5x */
+	35,  /* 0101 ->  3.5x */
+	45,  /* 0110 ->  4.5x */
+	110, /* 0111 -> 11.0x */
+	90,  /* 1000 ->  9.0x */
+	70,  /* 1001 ->  7.0x */
+	80,  /* 1010 ->  8.0x */
+	60,  /* 1011 ->  6.0x */
+	120, /* 1100 -> 12.0x */
+	75,  /* 1101 ->  7.5x */
+	130, /* 1110 -> 13.0x */
+	65,  /* 1111 ->  6.5x */
+};
+
+static int __initdata ezra_eblcr[16] = {
+	50,  /* 0000 ->  5.0x */
+	30,  /* 0001 ->  3.0x */
+	40,  /* 0010 ->  4.0x */
+	100, /* 0011 -> 10.0x */
+	55,  /* 0100 ->  5.5x */
+	35,  /* 0101 ->  3.5x */
+	45,  /* 0110 ->  4.5x */
+	95,  /* 0111 ->  9.5x */
+	90,  /* 1000 ->  9.0x */
+	70,  /* 1001 ->  7.0x */
+	80,  /* 1010 ->  8.0x */
+	60,  /* 1011 ->  6.0x */
+	120, /* 1100 -> 12.0x */
+	75,  /* 1101 ->  7.5x */
+	85,  /* 1110 ->  8.5x */
+	65,  /* 1111 ->  6.5x */
+};
+
+/* VIA C5M. */
+static int __initdata longhaul3_clock_ratio[32] = {
+	100, /* 0000 -> 10.0x */
+	30,  /* 0001 ->  3.0x */
+	40,  /* 0010 ->  4.0x */
+	90,  /* 0011 ->  9.0x */
+	95,  /* 0100 ->  9.5x */
+	35,  /* 0101 ->  3.5x */
+	45,  /* 0110 ->  4.5x */
+	55,  /* 0111 ->  5.5x */
+	60,  /* 1000 ->  6.0x */
+	70,  /* 1001 ->  7.0x */
+	80,  /* 1010 ->  8.0x */
+	50,  /* 1011 ->  5.0x */
+	65,  /* 1100 ->  6.5x */
+	75,  /* 1101 ->  7.5x */
+	85,  /* 1110 ->  8.5x */
+	120, /* 1111 ->  12.0x */
+
+	-1,  /* 0000 -> RESERVED (10.0x) */
+	110, /* 0001 -> 11.0x */
+	120, /* 0010 -> 12.0x */
+	-1,  /* 0011 -> RESERVED (9.0x)*/
+	105, /* 0100 -> 10.5x */
+	115, /* 0101 -> 11.5x */
+	125, /* 0110 -> 12.5x */
+	135, /* 0111 -> 13.5x */
+	140, /* 1000 -> 14.0x */
+	150, /* 1001 -> 15.0x */
+	160, /* 1010 -> 16.0x */
+	130, /* 1011 -> 13.0x */
+	145, /* 1100 -> 14.5x */
+	155, /* 1101 -> 15.5x */
+	-1,  /* 1110 -> RESERVED (13.0x) */
+	-1,  /* 1111 -> RESERVED (12.0x) */
+};
+
+static int __initdata c5m_eblcr[32] = {
+	50,  /* 0000 ->  5.0x */
+	30,  /* 0001 ->  3.0x */
+	40,  /* 0010 ->  4.0x */
+	100, /* 0011 -> 10.0x */
+	55,  /* 0100 ->  5.5x */
+	35,  /* 0101 ->  3.5x */
+	45,  /* 0110 ->  4.5x */
+	95,  /* 0111 ->  9.5x */
+	90,  /* 1000 ->  9.0x */
+	70,  /* 1001 ->  7.0x */
+	80,  /* 1010 ->  8.0x */
+	60,  /* 1011 ->  6.0x */
+	120, /* 1100 -> 12.0x */
+	75,  /* 1101 ->  7.5x */
+	85,  /* 1110 ->  8.5x */
+	65,  /* 1111 ->  6.5x */
+
+	-1,  /* 0000 -> RESERVED (9.0x) */
+	110, /* 0001 -> 11.0x */
+	120, /* 0010 -> 12.0x */
+	-1,  /* 0011 -> RESERVED (10.0x)*/
+	135, /* 0100 -> 13.5x */
+	115, /* 0101 -> 11.5x */
+	125, /* 0110 -> 12.5x */
+	105, /* 0111 -> 10.5x */
+	130, /* 1000 -> 13.0x */
+	150, /* 1001 -> 15.0x */
+	160, /* 1010 -> 16.0x */
+	140, /* 1011 -> 14.0x */
+	-1,  /* 1100 -> RESERVED (12.0x) */
+	155, /* 1101 -> 15.5x */
+	-1,  /* 1110 -> RESERVED (13.0x) */
+	145, /* 1111 -> 14.5x */
+};
+
+/* fsb values as defined in CPU */
+static unsigned int eblcr_fsb_table[] = { 66, 133, 100, -1 };
+/* fsb values to favour low fsb speed (lower power) */
+static unsigned int power_fsb_table[] = { 66, 100, 133, -1 };
+/* fsb values to favour high fsb speed (for e.g. if lowering CPU 
+   freq because of heat, but want to maintain highest performance possible) */
+static unsigned int perf_fsb_table[] = { 133, 100, 66, -1 };
+static unsigned int *fsb_search_table;
+
+/* Voltage scales. Div by 1000 to get actual voltage. */
+static int __initdata vrm85scales[32] = {
+	1250, 1200, 1150, 1100, 1050, 1800, 1750, 1700,
+	1650, 1600, 1550, 1500, 1450, 1400, 1350, 1300,
+	1275, 1225, 1175, 1125, 1075, 1825, 1775, 1725,
+	1675, 1625, 1575, 1525, 1475, 1425, 1375, 1325,
+};
+
+static int __initdata mobilevrmscales[32] = {
+	2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650,
+	1600, 1550, 1500, 1450, 1500, 1350, 1300, -1,
+	1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100,
+	1075, 1050, 1025, 1000, 975, 950, 925, -1,
+};
+
+/* Clock ratios multiplied by 10 */
+static int clock_ratio[32];
+static int eblcr_table[32];
+static int voltage_table[32];
+static int highest_speed, lowest_speed; /* kHz */
+static int longhaul; /* version. */
+static struct cpufreq_driver *longhaul_driver;
+
+
+static int longhaul_get_cpu_fsb (void)
+{
+	unsigned long invalue=0,lo, hi;
+
+	if (current_fsb == 0) {
+		rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi);
+		invalue = (lo & (1<<18|1<<19)) >>18;
+		return eblcr_fsb_table[invalue];
+	} else {
+		return current_fsb;
+	}
+}
+
+
+static int longhaul_get_cpu_mult (void)
+{
+	unsigned long invalue=0,lo, hi;
+
+	rdmsr (MSR_IA32_EBL_CR_POWERON, lo, hi);
+	invalue = (lo & (1<<22|1<<23|1<<24|1<<25)) >>22;
+	if (longhaul==3) {
+		if (lo & (1<<27))
+			invalue+=16;
+	}
+	return eblcr_table[invalue];
+}
+
+
+/**
+ * longhaul_set_cpu_frequency()
+ * @clock_ratio_index : index of clock_ratio[] for new frequency
+ * @newfsb: the new FSB
+ *
+ * Sets a new clock ratio, and -if applicable- a new Front Side Bus
+ */
+
+static void longhaul_setstate (unsigned int clock_ratio_index, unsigned int newfsb)
+{
+	unsigned long lo, hi;
+	unsigned int bits;
+	int revkey;
+	int vidindex, i;
+	struct cpufreq_freqs freqs;
+	
+	if (!newfsb || (clock_ratio[clock_ratio_index] == -1))
+		return;
+
+	if ((!can_scale_fsb) && (newfsb != current_fsb))
+		return;
+
+	freqs.old = longhaul_get_cpu_mult() * longhaul_get_cpu_fsb() * 100;
+	freqs.new = clock_ratio[clock_ratio_index] * newfsb * 100;
+	freqs.cpu = CPUFREQ_ALL_CPUS; /* longhaul.c is UP only driver */
+	
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	dprintk (KERN_INFO "longhaul: New FSB:%d Mult(x10):%d\n",
+				newfsb, clock_ratio[clock_ratio_index]);
+
+	bits = clock_ratio_index;
+	/* "bits" contains the bitpattern of the new multiplier.
+	   we now need to transform it to the desired format. */
+
+	switch (longhaul) {
+	case 1:
+		rdmsr (MSR_VIA_BCR2, lo, hi);
+		revkey = (lo & 0xf)<<4; /* Rev key. */
+		lo &= ~(1<<23|1<<24|1<<25|1<<26);
+		lo |= (1<<19);		/* Enable software clock multiplier */
+		lo |= (bits<<23);	/* desired multiplier */
+		lo |= revkey;
+		wrmsr (MSR_VIA_BCR2, lo, hi);
+
+		__hlt();
+
+		/* Disable software clock multiplier */
+		rdmsr (MSR_VIA_BCR2, lo, hi);
+		lo &= ~(1<<19);
+		lo |= revkey;
+		wrmsr (MSR_VIA_BCR2, lo, hi);
+		break;
+
+	case 2:
+		rdmsr (MSR_VIA_LONGHAUL, lo, hi);
+		revkey = (lo & 0xf)<<4;	/* Rev key. */
+		lo &= 0xfff0bf0f;	/* reset [19:16,14](bus ratio) and [7:4](rev key) to 0 */
+		lo |= (bits<<16);
+		lo |= (1<<8);	/* EnableSoftBusRatio */
+		lo |= revkey;
+
+		if (can_scale_voltage) {
+			if (can_scale_fsb==1) {
+				dprintk (KERN_INFO "longhaul: Voltage scaling + FSB scaling not done yet.\n");
+				goto bad_voltage;
+			} else {
+				/* PB: TODO fix this up */
+				vidindex = (((highest_speed-lowest_speed) / (newfsb/2)) -
+						((highest_speed-((clock_ratio[clock_ratio_index] * newfsb * 100)/1000)) / (newfsb/2)));
+			}
+			for (i=0;i<32;i++) {
+				dprintk (KERN_INFO "VID hunting. Looking for %d, found %d\n",
+						minvid+(vidindex*25), voltage_table[i]);
+				if (voltage_table[i]==(minvid + (vidindex * 25)))
+					break;
+			}
+			if (i==32)
+				goto bad_voltage;
+
+			dprintk (KERN_INFO "longhaul: Desired vid index=%d\n", i);
+#if 0
+			lo &= 0xfe0fffff;/* reset [24:20](voltage) to 0 */
+			lo |= (i<<20);   /* set voltage */
+			lo |= (1<<9);    /* EnableSoftVID */
+#endif
+		}
+
+bad_voltage:
+		wrmsr (MSR_VIA_LONGHAUL, lo, hi);
+		__hlt();
+
+		rdmsr (MSR_VIA_LONGHAUL, lo, hi);
+		lo &= ~(1<<8);
+		if (can_scale_voltage)
+			lo &= ~(1<<9);
+		lo |= revkey;
+		wrmsr (MSR_VIA_LONGHAUL, lo, hi);
+		break;
+
+	case 3:
+		rdmsr (MSR_VIA_LONGHAUL, lo, hi);
+		revkey = (lo & 0xf)<<4;	/* Rev key. */
+		lo &= 0xfff0bf0f;	/* reset longhaul[19:16,14] to 0 */
+		lo |= (bits<<16);
+		lo |= (1<<8);	/* EnableSoftBusRatio */
+		lo |= revkey;
+
+		/* Set FSB */
+		if (can_scale_fsb==1) {
+			lo &= ~(1<<28|1<<29);
+			switch (newfsb) {
+				case 66:	lo |= (1<<28|1<<29); /* 11 */
+							break;
+				case 100:	lo |= 1<<28;	/* 01 */
+							break;
+				case 133:	break;	/* 00*/
+			}
+		}
+		wrmsr (MSR_VIA_LONGHAUL, lo, hi);
+		__hlt();
+
+		rdmsr (MSR_VIA_LONGHAUL, lo, hi);
+		lo &= ~(1<<8);
+		lo |= revkey;
+		wrmsr (MSR_VIA_LONGHAUL, lo, hi);
+		break;
+	}
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+}
+
+
+static void __init longhaul_get_ranges (void)
+{
+	unsigned long lo, hi, invalue;
+	unsigned int minmult=0, maxmult=0, minfsb=0, maxfsb=0;
+	unsigned int multipliers[32]= {
+		50,30,40,100,55,35,45,95,90,70,80,60,120,75,85,65,
+		-1,110,120,-1,135,115,125,105,130,150,160,140,-1,155,-1,145 };
+	unsigned int fsb_table[4] = { 133, 100, -1, 66 };
+
+	switch (longhaul) {
+	case 1:
+		/* Ugh, Longhaul v1 didn't have the min/max MSRs.
+		   Assume max = whatever we booted at. */
+		maxmult = longhaul_get_cpu_mult();
+		break;
+
+	case 2 ... 3:
+		rdmsr (MSR_VIA_LONGHAUL, lo, hi);
+
+		invalue = (hi & (1<<0|1<<1|1<<2|1<<3));
+		if (hi & (1<<11))
+			invalue += 16;
+		maxmult=multipliers[invalue];
+
+#if 0	/* This is MaxMhz @ Min Voltage. Ignore for now */
+		invalue = (hi & (1<<16|1<<17|1<<18|1<<19)) >> 16;
+		if (hi & (1<<27))
+		invalue += 16;
+		minmult = multipliers[invalue];
+#else
+		minmult = 30; /* as per spec */
+#endif
+
+		if (can_scale_fsb==1) {
+			invalue = (hi & (1<<9|1<<10)) >> 9;
+			maxfsb = fsb_table[invalue];
+
+			invalue = (hi & (1<<25|1<<26)) >> 25;
+			minfsb = fsb_table[invalue];
+
+			dprintk (KERN_INFO "longhaul: Min FSB=%d Max FSB=%d\n",
+				minfsb, maxfsb);
+		} else {
+			minfsb = maxfsb = current_fsb;
+		}
+		break;
+	}
+
+	highest_speed = maxmult * maxfsb * 100;
+	lowest_speed = minmult * minfsb * 100;
+
+	dprintk (KERN_INFO "longhaul: MinMult(x10)=%d MaxMult(x10)=%d\n",
+		minmult, maxmult);
+	dprintk (KERN_INFO "longhaul: Lowestspeed=%d Highestspeed=%d\n",
+		lowest_speed, highest_speed);
+}
+
+
+static void __init longhaul_setup_voltagescaling (unsigned long lo, unsigned long hi)
+{
+	int revkey;
+
+	can_scale_voltage = 1;
+
+	minvid = (hi & (1<<20|1<<21|1<<22|1<<23|1<<24)) >> 20; /* 56:52 */
+	maxvid = (hi & (1<<4|1<<5|1<<6|1<<7|1<<8)) >> 4;       /* 40:36 */
+	vrmrev = (lo & (1<<15))>>15;
+
+	if (vrmrev==0) {
+		dprintk (KERN_INFO "longhaul: VRM 8.5 : ");
+		memcpy (voltage_table, vrm85scales, sizeof(voltage_table));
+		numvscales = (voltage_table[maxvid]-voltage_table[minvid])/25;
+	} else {
+		dprintk (KERN_INFO "longhaul: Mobile VRM : ");
+		memcpy (voltage_table, mobilevrmscales, sizeof(voltage_table));
+		numvscales = (voltage_table[maxvid]-voltage_table[minvid])/5;
+	}
+
+	/* Current voltage isn't readable at first, so we need to
+	   set it to a known value. The spec says to use maxvid */
+	revkey = (lo & 0xf)<<4;	/* Rev key. */
+	lo &= 0xfe0fff0f;	/* Mask unneeded bits */
+	lo |= (1<<9);		/* EnableSoftVID */
+	lo |= revkey;		/* Reinsert key */
+	lo |= maxvid << 20;
+	wrmsr (MSR_VIA_LONGHAUL, lo, hi);
+	minvid = voltage_table[minvid];
+	maxvid = voltage_table[maxvid];
+	dprintk ("Min VID=%d.%03d Max VID=%d.%03d, %d possible voltage scales\n",
+		maxvid/1000, maxvid%1000, minvid/1000, minvid%1000, numvscales);
+}
+
+
+static inline unsigned int longhaul_statecount_fsb(struct cpufreq_policy *policy, unsigned int fsb) {
+	unsigned int i, count = 0;
+
+	for(i=0; i<numscales; i++) {
+		if ((clock_ratio[i] != -1) &&
+		    ((clock_ratio[i] * fsb * 100) <= policy->max) &&
+		    ((clock_ratio[i] * fsb * 100) >= policy->min))
+			count++;
+	}
+
+	return count;
+}
+
+
+static void longhaul_verify(struct cpufreq_policy *policy)
+{
+	unsigned int    number_states = 0;
+	unsigned int    i;
+	unsigned int    fsb_index = 0;
+	unsigned int    tmpfreq = 0;
+	unsigned int    newmax = -1;
+
+	if (!policy || !longhaul_driver)
+		return;
+
+	policy->cpu = 0;
+	cpufreq_verify_within_limits(policy, lowest_speed, highest_speed);
+
+	if (can_scale_fsb==1) {
+		for (fsb_index=0; fsb_search_table[fsb_index]!=-1; fsb_index++)
+			number_states += longhaul_statecount_fsb(policy, fsb_search_table[fsb_index]);
+	} else
+		number_states = longhaul_statecount_fsb(policy, current_fsb);
+
+	if (number_states)
+		return;
+
+	/* get frequency closest above current policy->max */
+	if (can_scale_fsb==1) {
+		for (fsb_index=0; fsb_search_table[fsb_index] != -1; fsb_index++)
+			for(i=0; i<numscales; i++) {
+				if (clock_ratio[i] == -1)
+					continue;
+
+				tmpfreq = clock_ratio[i] * fsb_search_table[fsb_index];
+				if ((tmpfreq > policy->max) &&
+				    (tmpfreq < newmax))
+					newmax = tmpfreq;
+			}
+	} else {
+		for(i=0; i<numscales; i++) {
+			if (clock_ratio[i] == -1)
+				continue;
+
+			tmpfreq = clock_ratio[i] * current_fsb;
+			if ((tmpfreq > policy->max) &&
+			    (tmpfreq < newmax))
+				newmax = tmpfreq;
+			}
+	}
+
+	policy->max = newmax;
+}
+
+
+static void longhaul_setpolicy (struct cpufreq_policy *policy)
+{
+	unsigned int    number_states = 0;
+	unsigned int    i;
+	unsigned int    fsb_index = 0;
+	unsigned int    new_fsb = 0;
+	unsigned int    new_clock_ratio = 0;
+	unsigned int    best_freq = -1;
+
+	if (!longhaul_driver)
+		return;
+
+	if (policy->policy==CPUFREQ_POLICY_PERFORMANCE)
+		fsb_search_table = perf_fsb_table;
+	else
+		fsb_search_table = power_fsb_table;
+
+	if (can_scale_fsb==1) {
+		for (fsb_index=0; fsb_search_table[fsb_index]!=-1; fsb_index++) 
+		{
+			unsigned int tmpcount = longhaul_statecount_fsb(policy, fsb_search_table[fsb_index]);
+			if (tmpcount == 1)
+				new_fsb = fsb_search_table[fsb_index];
+			number_states += tmpcount;
+		}
+	} else {
+		number_states = longhaul_statecount_fsb(policy, current_fsb);
+		new_fsb = current_fsb;
+	}
+
+	if (!number_states)
+		return;
+	else if (number_states == 1) {
+		for(i=0; i<numscales; i++) {
+			if ((clock_ratio[i] != -1) &&
+			    ((clock_ratio[i] * new_fsb * 100) <= policy->max) &&
+			    ((clock_ratio[i] * new_fsb * 100) >= policy->min))
+				new_clock_ratio = i;
+		}
+		longhaul_setstate(new_clock_ratio, new_fsb);
+	}
+
+	switch (policy->policy) {
+	case CPUFREQ_POLICY_POWERSAVE:
+		best_freq = -1;
+		if (can_scale_fsb==1) {
+			for (fsb_index=0; fsb_search_table[fsb_index]!=-1; fsb_index++) 
+			{
+				for(i=0; i<numscales; i++) {
+					unsigned int tmpfreq = fsb_search_table[fsb_index] * clock_ratio[i] * 100;
+					if (clock_ratio[i] == -1)
+						continue;
+
+					if ((tmpfreq >= policy->min) &&
+					    (tmpfreq <= policy->max) &&
+					    (tmpfreq < best_freq)) {
+						new_clock_ratio = i;
+						new_fsb = fsb_search_table[fsb_index];
+					}
+				}
+			}
+		} else {
+			for(i=0; i<numscales; i++) {
+				unsigned int tmpfreq = current_fsb * clock_ratio[i] * 100;
+					if (clock_ratio[i] == -1)
+						continue;
+
+					if ((tmpfreq >= policy->min) &&
+					    (tmpfreq <= policy->max) &&
+					    (tmpfreq < best_freq)) {
+						new_clock_ratio = i;
+						new_fsb = current_fsb;
+					}
+				}
+		}
+		break;
+	case CPUFREQ_POLICY_PERFORMANCE:
+		best_freq = 0;
+		if (can_scale_fsb==1) {
+			for (fsb_index=0; fsb_search_table[fsb_index]!=-1; fsb_index++) 
+			{
+				for(i=0; i<numscales; i++) {
+					unsigned int tmpfreq = fsb_search_table[fsb_index] * clock_ratio[i] * 100;
+					if (clock_ratio[i] == -1)
+						continue;
+
+					if ((tmpfreq >= policy->min) &&
+					    (tmpfreq <= policy->max) &&
+					    (tmpfreq > best_freq)) {
+						new_clock_ratio = i;
+						new_fsb = fsb_search_table[fsb_index];
+					}
+				}
+			}
+		} else {
+			for(i=0; i<numscales; i++) {
+				unsigned int tmpfreq = current_fsb * clock_ratio[i] * 100;
+					if (clock_ratio[i] == -1)
+						continue;
+
+					if ((tmpfreq >= policy->min) &&
+					    (tmpfreq <= policy->max) &&
+					    (tmpfreq > best_freq)) {
+						new_clock_ratio = i;
+						new_fsb = current_fsb;
+					}
+				}
+		}
+		break;
+	default:
+		return;
+	}
+
+	longhaul_setstate(new_clock_ratio, new_fsb);
+	return;
+}
+
+
+static int __init longhaul_init (void)
+{
+	struct cpuinfo_x86 *c = cpu_data;
+	unsigned int currentspeed;
+	static int currentmult;
+	unsigned long lo, hi;
+	int ret;
+	struct cpufreq_driver *driver;
+
+	if ((c->x86_vendor != X86_VENDOR_CENTAUR) || (c->x86 !=6) )
+		return -ENODEV;
+
+	switch (c->x86_model) {
+	case 6:		/* VIA C3 Samuel C5A */
+		longhaul=1;
+		memcpy (clock_ratio, longhaul1_clock_ratio, sizeof(longhaul1_clock_ratio));
+		memcpy (eblcr_table, samuel1_eblcr, sizeof(samuel1_eblcr));
+		break;
+
+	case 7:		/* C5B / C5C */
+		switch (c->x86_mask) {
+		case 0:
+			longhaul=1;
+			memcpy (clock_ratio, longhaul1_clock_ratio, sizeof(longhaul1_clock_ratio));
+			memcpy (eblcr_table, samuel2_eblcr, sizeof(samuel2_eblcr));
+			break;
+		case 1 ... 15:
+			longhaul=2;
+			memcpy (clock_ratio, longhaul2_clock_ratio, sizeof(longhaul2_clock_ratio));
+			memcpy (eblcr_table, ezra_eblcr, sizeof(ezra_eblcr));
+			break;
+		}
+		break;
+
+	case 8:		/* C5M/C5N */
+		return -ENODEV; // Waiting on updated docs from VIA before this is usable
+		longhaul=3;
+		numscales=32;
+		memcpy (clock_ratio, longhaul3_clock_ratio, sizeof(longhaul3_clock_ratio));
+		memcpy (eblcr_table, c5m_eblcr, sizeof(c5m_eblcr));
+		break;
+
+	default:
+		printk (KERN_INFO "longhaul: Unknown VIA CPU. Contact davej@suse.de\n");
+		return -ENODEV;
+	}
+
+	printk (KERN_INFO "longhaul: VIA CPU detected. Longhaul version %d supported\n", longhaul);
+
+	current_fsb = longhaul_get_cpu_fsb();
+	currentmult = longhaul_get_cpu_mult();
+	currentspeed = currentmult * current_fsb * 100;
+
+	dprintk (KERN_INFO "longhaul: CPU currently at %dMHz (%d x %d.%d)\n",
+		(currentspeed/1000), current_fsb, currentmult/10, currentmult%10);
+
+	if (longhaul==2 || longhaul==3) {
+		rdmsr (MSR_VIA_LONGHAUL, lo, hi);
+		if ((lo & (1<<0)) && (dont_scale_voltage==0))
+			longhaul_setup_voltagescaling (lo, hi);
+
+		if ((lo & (1<<1)) && (dont_scale_fsb==0) && (current_fsb==0))
+			can_scale_fsb = 1;
+	}
+
+	longhaul_get_ranges();
+
+	driver = kmalloc(sizeof(struct cpufreq_driver) + 
+			 NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
+	if (!driver)
+		return -ENOMEM;
+
+	driver->policy = (struct cpufreq_policy *) (driver + 1);
+
+#ifdef CONFIG_CPU_FREQ_24_API
+	driver->cpu_min_freq    = (unsigned int) lowest_speed;
+	driver->cpu_cur_freq[0] = currentspeed;
+#endif
+
+	driver->verify    = &longhaul_verify;
+	driver->setpolicy = &longhaul_setpolicy;
+
+	driver->policy[0].cpu = 0;
+	driver->policy[0].min = (unsigned int) lowest_speed;
+	driver->policy[0].max = (unsigned int) highest_speed;
+	driver->policy[0].policy = CPUFREQ_POLICY_PERFORMANCE;
+	driver->policy[0].max_cpu_freq = (unsigned int) highest_speed;
+
+	ret = cpufreq_register(driver);
+
+	if (ret) {
+		kfree(driver);
+		return ret;
+	}
+
+	longhaul_driver = driver;
+	return 0;
+}
+
+
+static void __exit longhaul_exit (void)
+{
+	if (longhaul_driver) {
+		cpufreq_unregister();
+		kfree(longhaul_driver);
+	}
+}
+
+MODULE_PARM (dont_scale_fsb, "i");
+MODULE_PARM (dont_scale_voltage, "i");
+MODULE_PARM (current_fsb, "i");
+
+MODULE_AUTHOR ("Dave Jones <davej@suse.de>");
+MODULE_DESCRIPTION ("Longhaul driver for VIA Cyrix processors.");
+MODULE_LICENSE ("GPL");
+
+module_init(longhaul_init);
+module_exit(longhaul_exit);
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/longrun.c linux.20pre10-ac2/arch/i386/kernel/longrun.c
--- linux.20pre10/arch/i386/kernel/longrun.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/longrun.c	2002-09-30 17:24:56.000000000 +0100
@@ -0,0 +1,283 @@
+/*
+ *  $Id: longrun.c,v 1.12 2002/09/29 23:43:10 db Exp $
+ *
+ * (C) 2002  Dominik Brodowski <linux@brodo.de>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h> 
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
+
+#include <asm/msr.h>
+#include <asm/processor.h>
+#include <asm/timex.h>
+
+static struct cpufreq_driver	*longrun_driver;
+
+/**
+ * longrun_{low,high}_freq is needed for the conversion of cpufreq kHz 
+ * values into per cent values. In TMTA microcode, the following is valid:
+ * performance_pctg = (current_freq - low_freq)/(high_freq - low_freq)
+ */
+static unsigned int longrun_low_freq, longrun_high_freq;
+
+
+/**
+ * longrun_get_policy - get the current LongRun policy
+ * @policy: struct cpufreq_policy where current policy is written into
+ *
+ * Reads the current LongRun policy by access to MSR_TMTA_LONGRUN_FLAGS
+ * and MSR_TMTA_LONGRUN_CTRL
+ */
+static void longrun_get_policy(struct cpufreq_policy *policy)
+{
+	u32 msr_lo, msr_hi;
+
+	if (!longrun_driver)
+		return;
+
+	rdmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi);
+	if (msr_lo & 0x01)
+		policy->policy = CPUFREQ_POLICY_PERFORMANCE;
+	else
+		policy->policy = CPUFREQ_POLICY_POWERSAVE;
+	
+	rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
+	msr_lo &= 0x0000007F;
+	msr_hi &= 0x0000007F;
+
+	policy->min = longrun_low_freq + msr_lo * 
+		((longrun_high_freq - longrun_low_freq) / 100);
+	policy->min = longrun_low_freq + msr_hi * 
+		((longrun_high_freq - longrun_low_freq) / 100);
+	policy->cpu = 0;
+}
+
+
+/**
+ * longrun_set_policy - sets a new CPUFreq policy
+ * @policy - new policy
+ *
+ * Sets a new CPUFreq policy on LongRun-capable processors. This function
+ * has to be called with cpufreq_driver locked.
+ */
+static void longrun_set_policy(struct cpufreq_policy *policy)
+{
+	u32 msr_lo, msr_hi;
+	u32 pctg_lo, pctg_hi;
+
+	if (!longrun_driver || !policy)
+		return;
+
+	pctg_lo = (policy->min - longrun_low_freq) / 
+		((longrun_high_freq - longrun_low_freq) / 100);
+	pctg_hi = (policy->max - longrun_low_freq) / 
+		((longrun_high_freq - longrun_low_freq) / 100);
+
+	if (pctg_hi > 100)
+		pctg_hi = 100;
+	if (pctg_lo > pctg_hi)
+		pctg_lo = pctg_hi;
+
+	/* performance or economy mode */
+	rdmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi);
+	msr_lo &= 0xFFFFFFFE;
+	switch (policy->policy) {
+	case CPUFREQ_POLICY_PERFORMANCE:
+		msr_lo |= 0x00000001;
+		break;
+	case CPUFREQ_POLICY_POWERSAVE:
+		break;
+	}
+	wrmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi);
+
+	/* lower and upper boundary */
+	rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
+	msr_lo &= 0xFFFFFF80;
+	msr_hi &= 0xFFFFFF80;
+	msr_lo |= pctg_lo;
+	msr_hi |= pctg_hi;
+	wrmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
+
+	return;
+}
+
+
+/**
+ * longrun_verify_poliy - verifies a new CPUFreq policy
+ *
+ * Validates a new CPUFreq policy. This function has to be called with 
+ * cpufreq_driver locked.
+ */
+static void longrun_verify_policy(struct cpufreq_policy *policy)
+{
+	if (!policy || !longrun_driver)
+		return;
+
+	policy->cpu = 0;
+	cpufreq_verify_within_limits(policy, 0, 
+		longrun_driver->policy[0].max_cpu_freq);
+
+	return;
+}
+
+
+/**
+ * longrun_determine_freqs - determines the lowest and highest possible core frequency
+ *
+ * Determines the lowest and highest possible core frequencies on this CPU.
+ * This is neccessary to calculate the performance percentage according to
+ * TMTA rules:
+ * performance_pctg = (target_freq - low_freq)/(high_freq - low_freq)
+ */
+static unsigned int __init longrun_determine_freqs(unsigned int *low_freq, 
+						   unsigned int *high_freq)
+{
+	u32 msr_lo, msr_hi;
+	u32 save_lo, save_hi;
+	u32 eax, ebx, ecx, edx;
+	struct cpuinfo_x86 *c = cpu_data;
+
+	if (!low_freq || !high_freq)
+		return -EINVAL;
+
+	if (test_bit(X86_FEATURE_LRTI, c->x86_capability)) {
+		/* if the LongRun Table Interface is present, the
+		 * detection is a bit easier: 
+		 * For minimum frequency, read out the maximum
+		 * level (msr_hi), write that into "currently 
+		 * selected level", and read out the frequency.
+		 * For maximum frequency, read out level zero.
+		 */
+		/* minimum */
+		rdmsr(MSR_TMTA_LRTI_READOUT, msr_lo, msr_hi);
+		wrmsr(MSR_TMTA_LRTI_READOUT, msr_hi, msr_hi);
+		rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi);
+		*low_freq = msr_lo * 1000; /* to kHz */
+
+		/* maximum */
+		wrmsr(MSR_TMTA_LRTI_READOUT, 0, msr_hi);
+		rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi);
+		*high_freq = msr_lo * 1000; /* to kHz */
+
+		if (*low_freq > *high_freq)
+			*low_freq = *high_freq;
+		return 0;
+	}
+
+	/* set the upper border to the value determined during TSC init */
+	*high_freq = (cpu_khz / 1000);
+	*high_freq = *high_freq * 1000;
+
+	/* get current borders */
+	rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
+	save_lo = msr_lo & 0x0000007F;
+	save_hi = msr_hi & 0x0000007F;
+
+	/* if current perf_pctg is larger than 90%, we need to decrease the
+	 * upper limit to make the calculation more accurate.
+	 */
+	cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
+	if (ecx > 90) {
+		/* set to 0 to 80 perf_pctg */
+		msr_lo &= 0xFFFFFF80;
+		msr_hi &= 0xFFFFFF80;
+		msr_lo |= 0;
+		msr_hi |= 80;
+		wrmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
+
+		/* read out current core MHz and current perf_pctg */
+		cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
+
+		/* restore values */
+		wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi);	
+	}
+
+	/* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq)
+	 * eqals
+	 * low_freq * ( 1 - perf_pctg) = (cur_freq - high_freq * perf_pctg)
+	 *
+	 * high_freq * perf_pctg is stored tempoarily into "ebx".
+	 */
+	ebx = (((cpu_khz / 1000) * ecx) / 100); /* to MHz */
+
+	if ((ecx > 95) || (ecx == 0) || (eax < ebx))
+		return -EIO;
+
+	edx = (eax - ebx) / (100 - ecx); 
+	*low_freq = edx * 1000; /* back to kHz */
+
+	if (*low_freq > *high_freq)
+		*low_freq = *high_freq;
+
+	return 0;
+}
+
+
+/**
+ * longrun_init - initializes the Transmeta Crusoe LongRun CPUFreq driver
+ *
+ * Initializes the LongRun support.
+ */
+static int __init longrun_init(void)
+{
+	int                     result;
+	struct cpufreq_driver   *driver;
+	struct cpuinfo_x86 *c = cpu_data;
+
+	if (c->x86_vendor != X86_VENDOR_TRANSMETA || 
+	    !test_bit(X86_FEATURE_LONGRUN, c->x86_capability))
+		return 0;
+
+	/* initialization of main "cpufreq" code*/
+	driver = kmalloc(sizeof(struct cpufreq_driver) + 
+			 NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
+	if (!driver)
+		return -ENOMEM;
+
+	driver->policy = (struct cpufreq_policy *) (driver + 1);
+
+	if (longrun_determine_freqs(&longrun_low_freq, &longrun_high_freq)) {
+		kfree(driver);
+		return -EIO;
+	}
+	driver->policy[0].max_cpu_freq  = longrun_high_freq;
+
+	longrun_get_policy(&driver->policy[0]);
+
+	driver->verify         = &longrun_verify_policy;
+	driver->setpolicy      = &longrun_set_policy;
+	result = cpufreq_register(driver);
+	if (result) {
+		kfree(driver);
+		return result;
+	}
+	longrun_driver = driver;
+
+	return 0;
+}
+
+
+/**
+ * longrun_exit - unregisters LongRun support
+ */
+static void __exit longrun_exit(void)
+{
+	if (longrun_driver) {
+		cpufreq_unregister();
+		kfree(longrun_driver);
+	}
+}
+
+
+MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
+MODULE_DESCRIPTION ("LongRun driver for Transmeta Crusoe processors.");
+MODULE_LICENSE ("GPL");
+module_init(longrun_init);
+module_exit(longrun_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/Makefile linux.20pre10-ac2/arch/i386/kernel/Makefile
--- linux.20pre10/arch/i386/kernel/Makefile	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/Makefile	2002-10-10 23:56:47.000000000 +0100
@@ -40,5 +40,15 @@
 obj-$(CONFIG_X86_LOCAL_APIC)	+= mpparse.o apic.o nmi.o
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o acpitable.o
 obj-$(CONFIG_X86_VISWS_APIC)	+= visws_apic.o
+obj-$(CONFIG_X86_POWERNOW_K6)	+= powernow-k6.o
+obj-$(CONFIG_X86_LONGHAUL)	+= longhaul.o
+obj-$(CONFIG_X86_SPEEDSTEP)	+= speedstep.o
+obj-$(CONFIG_X86_P4_CLOCKMOD)	+= p4-clockmod.o
+obj-$(CONFIG_X86_LONGRUN)	+= longrun.o
+obj-$(CONFIG_ELAN_CPUFREQ)	+= elanfreq.o
+
+
+export-objs += scx200.o
+obj-$(CONFIG_SCx200)		+= scx200.o
 
 include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/mpparse.c linux.20pre10-ac2/arch/i386/kernel/mpparse.c
--- linux.20pre10/arch/i386/kernel/mpparse.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/mpparse.c	2002-09-06 00:46:28.000000000 +0100
@@ -12,6 +12,7 @@
  *	Maciej W. Rozycki	:	Bits for default MP configurations
  */
 
+#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/irq.h>
 #include <linux/init.h>
@@ -26,6 +27,7 @@
 #include <asm/mtrr.h>
 #include <asm/mpspec.h>
 #include <asm/pgalloc.h>
+#include <asm/smpboot.h>
 
 /* Have we found an MP table */
 int smp_found_config;
@@ -35,18 +37,20 @@
  * MP-table.
  */
 int apic_version [MAX_APICS];
-int mp_bus_id_to_type [MAX_MP_BUSSES];
-int mp_bus_id_to_node [MAX_MP_BUSSES];
-int mp_bus_id_to_local [MAX_MP_BUSSES];
 int quad_local_to_mp_bus_id [NR_CPUS/4][4];
-int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
 int mp_current_pci_id;
+int *mp_bus_id_to_type;
+int *mp_bus_id_to_node;
+int *mp_bus_id_to_local;
+int *mp_bus_id_to_pci_bus;
+int max_mp_busses;
+int max_irq_sources;
 
 /* I/O APIC entries */
 struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
 
 /* # of MP IRQ source entries */
-struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
+struct mpc_config_intsrc *mp_irqs;
 
 /* MP IRQ source entries */
 int mp_irq_entries;
@@ -64,6 +68,16 @@
 
 /* Bitmask of physically existing CPUs */
 unsigned long phys_cpu_present_map;
+unsigned long logical_cpu_present_map;
+
+unsigned int apic_broadcast_id = APIC_BROADCAST_ID_APIC;
+unsigned int int_dest_addr_mode = APIC_DEST_LOGICAL;
+unsigned char int_delivery_mode = dest_LowestPrio;
+unsigned char clustered_apic_mode = 0;
+unsigned char esr_disable = 0;
+
+unsigned char raw_phys_apicid[NR_CPUS] = { 0 };
+
 
 /*
  * Intel MP BIOS table parsing routines:
@@ -146,8 +160,8 @@
 	if (!(m->mpc_cpuflag & CPU_ENABLED))
 		return;
 
-	logical_apicid = m->mpc_apicid;
-	if (clustered_apic_mode) {
+	logical_apicid = 0x01;
+	if (clustered_apic_logical) {
 		quad = translation_table[mpc_record]->trans_quad;
 		logical_apicid = (quad << 4) + 
 			(m->mpc_apicid ? m->mpc_apicid << 1 : 1);
@@ -223,15 +237,14 @@
 	if (m->mpc_apicid > MAX_APICS) {
 		printk("Processor #%d INVALID. (Max ID: %d).\n",
 			m->mpc_apicid, MAX_APICS);
+		--num_processors;
 		return;
 	}
 	ver = m->mpc_apicver;
 
-	if (clustered_apic_mode) {
-		phys_cpu_present_map |= (logical_apicid&0xf) << (4*quad);
-	} else {
-		phys_cpu_present_map |= 1 << m->mpc_apicid;
-	}
+	logical_cpu_present_map |= 1 << (num_processors-1);
+	phys_cpu_present_map |= apicid_to_phys_cpu_present(m->mpc_apicid);
+
 	/*
 	 * Validate version
 	 */
@@ -240,6 +253,7 @@
 		ver = 0x10;
 	}
 	apic_version[m->mpc_apicid] = ver;
+	raw_phys_apicid[num_processors - 1] = m->mpc_apicid;
 }
 
 static void __init MP_bus_info (struct mpc_config_bus *m)
@@ -250,7 +264,7 @@
 	memcpy(str, m->mpc_bustype, 6);
 	str[6] = 0;
 	
-	if (clustered_apic_mode) {
+	if (clustered_apic_logical) {
 		quad = translation_table[mpc_record]->trans_quad;
 		mp_bus_id_to_node[m->mpc_busid] = quad;
 		mp_bus_id_to_local[m->mpc_busid] = translation_table[mpc_record]->trans_local;
@@ -304,7 +318,7 @@
 			m->mpc_irqtype, m->mpc_irqflag & 3,
 			(m->mpc_irqflag >> 2) & 3, m->mpc_srcbus,
 			m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq);
-	if (++mp_irq_entries == MAX_IRQ_SOURCES)
+	if (++mp_irq_entries == max_irq_sources)
 		panic("Max # of irq sources exceeded!!\n");
 }
 
@@ -388,15 +402,25 @@
        }
 }
 
+extern void disable_tsc(void);
+
 /*
  * Read/parse the MPC
  */
 
 static int __init smp_read_mpc(struct mp_config_table *mpc)
 {
-	char str[16];
+	char oem[16], prod[14];
 	int count=sizeof(*mpc);
 	unsigned char *mpt=((unsigned char *)mpc)+count;
+	int num_bus = 0;
+	int num_irq = 0;
+	unsigned char *bus_data;
+	int xapic = 0;
+	int numaq = 0;
+	static const char *mode_names[] = {
+		"Flat", "Clustered Logical", "Clustered Physical", "???"
+	};
 
 	if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) {
 		panic("SMP mptable: bad signature [%c%c%c%c]!\n",
@@ -419,13 +443,21 @@
 		printk(KERN_ERR "SMP mptable: null local APIC address!\n");
 		return 0;
 	}
-	memcpy(str,mpc->mpc_oem,8);
-	str[8]=0;
-	printk("OEM ID: %s ",str);
-
-	memcpy(str,mpc->mpc_productid,12);
-	str[12]=0;
-	printk("Product ID: %s ",str);
+	memcpy(oem,mpc->mpc_oem,8);
+	oem[8]=0;
+	printk("OEM ID: %s ",oem);
+
+	memcpy(prod,mpc->mpc_productid,12);
+	prod[12]=0;
+	printk("Product ID: %s ",prod);
+
+	/*
+	 * Can't recognize Summit xAPICs at present, so use the OEM ID.
+	 */
+	if (!strncmp(oem, "IBM ENSW", 8) && (!strncmp(prod, "NF 6000R", 8) || !strncmp(prod, "VIGIL SMP", 9)))
+		xapic = 2;
+	else if (!strncmp(oem, "IBM NUMA", 8))
+		numaq = 1;
 
 	printk("APIC at: 0x%lX\n",mpc->mpc_lapic);
 
@@ -435,16 +467,77 @@
 	if (!have_acpi_tables)
 		mp_lapic_addr = mpc->mpc_lapic;
 
-	if (clustered_apic_mode && mpc->mpc_oemptr) {
+	if (clustered_apic_logical && mpc->mpc_oemptr) {
 		/* We need to process the oem mpc tables to tell us which quad things are in ... */
 		mpc_record = 0;
 		smp_read_mpc_oem((struct mp_config_oemtable *) mpc->mpc_oemptr, mpc->mpc_oemsize);
 		mpc_record = 0;
 	}
 
+	/* Pre-scan to determine the number of bus and 
+	 * interrupts records we have
+	 */
+	while (count < mpc->mpc_length) {
+		switch (*mpt) {
+			case MP_PROCESSOR:
+				mpt += sizeof(struct mpc_config_processor);
+				count += sizeof(struct mpc_config_processor);
+				break;
+			case MP_BUS:
+				++num_bus;
+				mpt += sizeof(struct mpc_config_bus);
+				count += sizeof(struct mpc_config_bus);
+				break;
+			case MP_INTSRC:
+				++num_irq;
+				mpt += sizeof(struct mpc_config_intsrc);
+				count += sizeof(struct mpc_config_intsrc);
+				break;
+			case MP_IOAPIC:
+				mpt += sizeof(struct mpc_config_ioapic);
+				count += sizeof(struct mpc_config_ioapic);
+				break;
+			case MP_LINTSRC:
+				mpt += sizeof(struct mpc_config_lintsrc);
+				count += sizeof(struct mpc_config_lintsrc);
+				break;
+			default:
+				count = mpc->mpc_length;
+				break;
+		}
+	}
+	/* 
+	 * Paranoia: Allocate one extra of both the number of busses and number
+	 * of irqs, and make sure that we have at least 4 interrupts per PCI
+	 * slot.  But some machines do not report very many busses, so we need
+	 * to fall back on the older defaults.
+	 */
+	++num_bus;
+	max_mp_busses = max(num_bus, MAX_MP_BUSSES);
+	if (num_irq < (4 * max_mp_busses))
+		num_irq = 4 * num_bus;	/* 4 intr/PCI slot */
+	++num_irq;
+	max_irq_sources = max(num_irq, MAX_IRQ_SOURCES);
+	
+	count = (max_mp_busses * sizeof(int)) * 4;
+	count += (max_irq_sources * sizeof(struct mpc_config_intsrc));
+	bus_data = alloc_bootmem(count);
+	if (!bus_data) {
+		printk(KERN_ERR "SMP mptable: out of memory!\n");
+		return 0;
+	}
+	mp_bus_id_to_type = (int *)&bus_data[0];
+	mp_bus_id_to_node = (int *)&bus_data[(max_mp_busses * sizeof(int))];
+	mp_bus_id_to_local = (int *)&bus_data[(max_mp_busses * sizeof(int)) * 2];
+	mp_bus_id_to_pci_bus = (int *)&bus_data[(max_mp_busses * sizeof(int)) * 3];
+	mp_irqs = (struct mpc_config_intsrc *)&bus_data[(max_mp_busses * sizeof(int)) * 4];
+	memset(mp_bus_id_to_pci_bus, -1, max_mp_busses);
+
 	/*
 	 *	Now process the configuration blocks.
 	 */
+	count = sizeof(*mpc);
+	mpt = ((unsigned char *)mpc)+count;
 	while (count < mpc->mpc_length) {
 		switch(*mpt) {
 			case MP_PROCESSOR:
@@ -504,6 +597,20 @@
 		}
 		++mpc_record;
 	}
+	if (xapic || numaq) {
+		if (numaq)
+			xapic = 0;	/* NUMA-Q boxes never had xAPICs */
+		clustered_apic_mode = (u8)(xapic | numaq);
+		esr_disable = 1;
+		apic_broadcast_id = (xapic ? APIC_BROADCAST_ID_XAPIC : APIC_BROADCAST_ID_APIC);
+		int_dest_addr_mode = (xapic ? APIC_DEST_PHYSICAL : APIC_DEST_LOGICAL);
+		int_delivery_mode = (xapic ? dest_Fixed : dest_LowestPrio);
+		phys_cpu_present_map = logical_cpu_present_map;
+		/* There isnt a single clock source on these boxen */
+		disable_tsc();
+	}
+	printk("Enabling APIC mode:  %s.  Using %d I/O APICs\n",
+		mode_names[clustered_apic_mode], nr_ioapics);
 	if (!num_processors)
 		printk(KERN_ERR "SMP mptable: no processors registered!\n");
 	return num_processors;
@@ -799,18 +906,16 @@
 	 * there is a real-mode segmented pointer pointing to the
 	 * 4K EBDA area at 0x40E, calculate and scan it here.
 	 *
-	 * NOTE! There are Linux loaders that will corrupt the EBDA
+	 * NOTE! There were Linux loaders that will corrupt the EBDA
 	 * area, and as such this kind of SMP config may be less
 	 * trustworthy, simply because the SMP table may have been
-	 * stomped on during early boot. These loaders are buggy and
-	 * should be fixed.
+	 * stomped on during early boot.  Thankfully the bootloaders
+	 * now honour the EBDA.
 	 */
 
 	address = *(unsigned short *)phys_to_virt(0x40E);
 	address <<= 4;
 	smp_scan_config(address, 0x1000);
-	if (smp_found_config)
-		printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.kernel.org if you experience SMP problems!\n");
 }
 
 #else
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/nmi.c linux.20pre10-ac2/arch/i386/kernel/nmi.c
--- linux.20pre10/arch/i386/kernel/nmi.c	2002-10-09 21:36:57.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/nmi.c	2002-08-06 15:42:19.000000000 +0100
@@ -343,7 +343,7 @@
 	 */
 	int sum, cpu = smp_processor_id();
 
-	sum = apic_timer_irqs[cpu];
+	sum = irq_stat[cpu].apic_timer_irqs;
 
 	if (last_irq_sums[cpu] == sum) {
 		/*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/p4-clockmod.c linux.20pre10-ac2/arch/i386/kernel/p4-clockmod.c
--- linux.20pre10/arch/i386/kernel/p4-clockmod.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/p4-clockmod.c	2002-10-10 23:54:36.000000000 +0100
@@ -0,0 +1,310 @@
+/*
+ *	Pentium 4/Xeon CPU on demand clock modulation/speed scaling
+ *	(C) 2002 Zwane Mwaikambo <zwane@commfireservices.com>
+ *	(C) 2002 Arjan van de Ven <arjanv@redhat.com>
+ *	(C) 2002 Tora T. Engstad
+ *	All Rights Reserved
+ *
+ *	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.
+ *
+ *      The author(s) of this software shall not be held liable for damages
+ *      of any nature resulting due to the use of this software. This
+ *      software is provided AS-IS with no warranties.
+ *	
+ *	Date		Errata			Description
+ *	20020525	N44, O17	12.5% or 25% DC causes lockup
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h> 
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/cpufreq.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+#include <asm/processor.h> 
+#include <asm/msr.h>
+#include <asm/timex.h>
+
+#define PFX	"cpufreq: "
+
+/*
+ * Duty Cycle (3bits), note DC_DISABLE is not specified in
+ * intel docs i just use it to mean disable
+ */
+enum {
+	DC_RESV, DC_DFLT, DC_25PT, DC_38PT, DC_50PT,
+	DC_64PT, DC_75PT, DC_88PT, DC_DISABLE
+};
+
+#define DC_ENTRIES	8
+
+
+static int has_N44_O17_errata;
+static int stock_freq;
+MODULE_PARM(stock_freq, "i");
+
+static struct cpufreq_driver *cpufreq_p4_driver;
+
+
+static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
+{
+	u32 l, h;
+	unsigned long cpus_allowed;
+	struct cpufreq_freqs    freqs;
+	int hyperthreading;
+
+
+	if (!cpu_online(cpu) || (newstate > DC_DISABLE) || 
+		(newstate == DC_RESV))
+		return -EINVAL;
+
+	/* switch to physical CPU where state is to be changed*/
+	cpus_allowed = current->cpus_allowed;
+
+	/* hyperthreading? */
+#ifdef CONFIG_SMP
+	hyperthreading = ((cpu_has_ht) && (smp_num_siblings == 2));
+#else
+	hyperthreading = 0;
+#endif
+	if (hyperthreading) {
+		unsigned int phys_cpu = cpu / 2;
+		set_cpus_allowed(current, 3 << (phys_cpu));
+		BUG_ON((cpu & ~1) != (smp_processor_id() & ~1));
+		cpu = phys_cpu * 2;
+	} else {
+		set_cpus_allowed(current, 1 <<  cpu);
+		BUG_ON(cpu != smp_processor_id());
+	}
+	/* get current state */
+	rdmsr(MSR_IA32_THERM_CONTROL, l, h);
+	l = l >> 1;
+	l &= 0x7;
+
+	if (l == newstate) {
+		set_cpus_allowed(current, cpus_allowed);
+		return 0;
+	}
+
+	/* notifiers */
+	freqs.old = stock_freq * l / 8;
+	freqs.new = stock_freq * newstate / 8;
+	freqs.cpu = cpu;
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	if (hyperthreading) {
+		freqs.cpu++;
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	}
+
+	rdmsr(MSR_IA32_THERM_STATUS, l, h);
+	if (l & 0x01)
+		printk(KERN_DEBUG PFX "CPU#%d currently thermal throttled\n", cpu);
+
+	if (has_N44_O17_errata && (newstate == DC_25PT || newstate == DC_DFLT))
+		newstate = DC_38PT;
+
+	rdmsr(MSR_IA32_THERM_CONTROL, l, h);
+	if (newstate == DC_DISABLE) {
+		printk(KERN_INFO PFX "CPU#%d disabling modulation\n", cpu);
+		wrmsr(MSR_IA32_THERM_CONTROL, l & ~(1<<4), h);
+	} else {
+		printk(KERN_INFO PFX "CPU#%d setting duty cycle to %d%%\n", cpu, ((125 * newstate) / 10));
+		/* bits 63 - 5	: reserved 
+		 * bit  4	: enable/disable
+		 * bits 3-1	: duty cycle
+		 * bit  0	: reserved
+		 */
+		l = (l & ~14);
+		l = l | (1<<4) | ((newstate & 0x7)<<1);
+		wrmsr(MSR_IA32_THERM_CONTROL, l, h);
+	}
+
+	set_cpus_allowed(current, cpus_allowed);
+
+	/* notifiers */
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	if (hyperthreading) {
+		freqs.cpu--;
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	}
+
+	return 0;
+}
+
+
+static void cpufreq_p4_setpolicy(struct cpufreq_policy *policy)
+{
+	unsigned int    i;
+	unsigned int    newstate = 0;
+	unsigned int    number_states = 0;
+
+	if (!cpufreq_p4_driver || !stock_freq || !policy)
+		return;
+
+	if (policy->policy == CPUFREQ_POLICY_POWERSAVE)
+	{
+		for (i=8; i>0; i++)
+			if ((policy->min <= ((stock_freq / 8) * i)) &&
+			    (policy->max >= ((stock_freq / 8) * i))) 
+			{
+				newstate = i;
+				number_states++;
+			}
+	} else {
+		for (i=0; i<=8; i--)
+			if ((policy->min <= ((stock_freq / 8) * i)) &&
+			    (policy->max >= ((stock_freq / 8) * i))) 
+			{
+				newstate = i;
+				number_states++;
+			}
+	}
+
+	/* if (number_states == 1) */
+	{
+		if (policy->cpu == CPUFREQ_ALL_CPUS) {
+			for (i=0; i<NR_CPUS; i++)
+				if (cpu_online(i))
+					cpufreq_p4_setdc(i, newstate);
+		} else {
+			cpufreq_p4_setdc(policy->cpu, newstate);
+		}
+	}
+	/* else {
+		if (policy->policy == CPUFREQ_POLICY_POWERSAVE) {
+			min_state = newstate;
+			max_state = newstate + (number_states - 1);
+		} else {
+			max_state = newstate;
+			min_state = newstate - (number_states - 1);
+		}
+	} */
+}
+
+
+static void cpufreq_p4_verify(struct cpufreq_policy *policy)
+{
+	unsigned int    number_states = 0;
+	unsigned int    i;
+
+	if (!cpufreq_p4_driver || !stock_freq || !policy)
+		return;
+
+	if (!cpu_online(policy->cpu))
+		policy->cpu = CPUFREQ_ALL_CPUS;
+	cpufreq_verify_within_limits(policy, (stock_freq / 8), stock_freq);
+
+	/* is there at least one state within limit? */
+	for (i=1; i<=8; i++)
+		if ((policy->min <= ((stock_freq / 8) * i)) &&
+		    (policy->max >= ((stock_freq / 8) * i)))
+			number_states++;
+
+	if (number_states)
+		return;
+
+	policy->max = (stock_freq / 8) * (((unsigned int) ((policy->max * 8) / stock_freq)) + 1);
+	return;
+}
+
+
+int __init cpufreq_p4_init(void)
+{	
+	struct cpuinfo_x86 *c = cpu_data;
+	int cpuid;
+	int ret;
+	struct cpufreq_driver *driver;
+	unsigned int i;
+
+	/*
+	 * THERM_CONTROL is architectural for IA32 now, so 
+	 * we can rely on the capability checks
+	 */
+	if (c->x86_vendor != X86_VENDOR_INTEL)
+		return -ENODEV;
+
+	if (!test_bit(X86_FEATURE_ACPI, c->x86_capability) ||
+		!test_bit(X86_FEATURE_ACC, c->x86_capability))
+		return -ENODEV;
+
+	/* Errata workarounds */
+	cpuid = (c->x86 << 8) | (c->x86_model << 4) | c->x86_mask;
+	switch (cpuid) {
+		case 0x0f07:
+		case 0x0f0a:
+		case 0x0f11:
+		case 0x0f12:
+			has_N44_O17_errata = 1;
+		default:
+			break;
+	}
+
+	printk(KERN_INFO PFX "P4/Xeon(TM) CPU On-Demand Clock Modulation available\n");
+	driver = kmalloc(sizeof(struct cpufreq_driver) +
+			 NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
+	if (!driver)
+		return -ENOMEM;
+
+	driver->policy = (struct cpufreq_policy *) (driver + 1);
+
+	if (!stock_freq)
+		stock_freq = cpu_khz;
+
+#ifdef CONFIG_CPU_FREQ_24_API
+	driver->cpu_min_freq    = stock_freq / 8;
+	for (i=0;i<NR_CPUS;i++)
+		driver->cpu_cur_freq[i] = stock_freq;
+#endif
+
+	driver->verify        = &cpufreq_p4_verify;
+	driver->setpolicy     = &cpufreq_p4_setpolicy;
+
+	for (i=0;i<NR_CPUS;i++) {
+		if (has_N44_O17_errata)
+			driver->policy[i].min    = (stock_freq * 3) / 8;
+		else
+			driver->policy[i].min    = stock_freq / 8;
+		driver->policy[i].max    = stock_freq;
+		driver->policy[i].policy = CPUFREQ_POLICY_PERFORMANCE;
+		driver->policy[i].max_cpu_freq  = stock_freq;
+		driver->policy[i].cpu    = i;
+	}
+
+	ret = cpufreq_register(driver);
+	if (ret) {
+		kfree(driver);
+		return ret;
+	}
+
+	cpufreq_p4_driver = driver;
+	
+	return 0;
+}
+
+
+void __exit cpufreq_p4_exit(void)
+{
+	u32 l, h;
+
+	if (cpufreq_p4_driver) {
+		cpufreq_unregister();
+		/* return back to a non modulated state */
+		rdmsr(MSR_IA32_THERM_CONTROL, l, h);
+		wrmsr(MSR_IA32_THERM_CONTROL, l & ~(1<<4), h);
+		kfree(cpufreq_p4_driver);
+	}
+}
+
+MODULE_AUTHOR ("Zwane Mwaikambo <zwane@commfireservices.com>");
+MODULE_DESCRIPTION ("cpufreq driver for Pentium(TM) 4/Xeon(TM)");
+MODULE_LICENSE ("GPL");
+
+module_init(cpufreq_p4_init);
+module_exit(cpufreq_p4_exit);
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/pci-dma.c linux.20pre10-ac2/arch/i386/kernel/pci-dma.c
--- linux.20pre10/arch/i386/kernel/pci-dma.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/pci-dma.c	2002-08-15 13:16:11.000000000 +0100
@@ -19,7 +19,7 @@
 	void *ret;
 	int gfp = GFP_ATOMIC;
 
-	if (hwdev == NULL || ((u32)hwdev->dma_mask != 0xffffffff))
+	if (hwdev == NULL || hwdev->dma_mask < 0xffffffff)
 		gfp |= GFP_DMA;
 	ret = (void *)__get_free_pages(gfp, get_order(size));
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/pci-irq.c linux.20pre10-ac2/arch/i386/kernel/pci-irq.c
--- linux.20pre10/arch/i386/kernel/pci-irq.c	2002-10-09 21:36:57.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/pci-irq.c	2002-08-06 15:42:19.000000000 +0100
@@ -22,6 +22,8 @@
 #define PIRQ_SIGNATURE	(('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
 #define PIRQ_VERSION 0x0100
 
+int broken_hp_bios_irq9;
+
 static struct irq_routing_table *pirq_table;
 
 /*
@@ -596,6 +598,15 @@
 	DBG(" -> PIRQ %02x, mask %04x, excl %04x", pirq, mask, pirq_table->exclusive_irqs);
 	mask &= pcibios_irq_mask;
 
+	/* Work around broken HP Pavilion Notebooks which assign USB to
+	   IRQ 9 even though it is actually wired to IRQ 11 */
+
+	if (broken_hp_bios_irq9 && pirq == 0x59 && dev->irq == 9) {
+		dev->irq = 11;
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
+		r->set(pirq_router_dev, dev, pirq, 11);
+	}
+
 	/*
 	 * Find the best IRQ to assign: use the one
 	 * reported by the device if possible.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/powernow-k6.c linux.20pre10-ac2/arch/i386/kernel/powernow-k6.c
--- linux.20pre10/arch/i386/kernel/powernow-k6.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/powernow-k6.c	2002-10-10 23:54:36.000000000 +0100
@@ -0,0 +1,294 @@
+/*
+ *  $Id: powernow-k6.c,v 1.34 2002/09/30 20:25:01 db Exp $
+ *  This file was part of Powertweak Linux (http://powertweak.sf.net)
+ *  and is shared with the Linux Kernel module.
+ *
+ *  (C) 2000-2002  Dave Jones, Arjan van de Ven, Janne Pnkl, Dominik Brodowski.
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *
+ *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h> 
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+
+#include <asm/msr.h>
+#include <asm/timex.h>
+#include <asm/io.h>
+
+
+#define POWERNOW_IOPORT 0xfff0         /* it doesn't matter where, as long
+					  as it is unused */
+
+static struct cpufreq_driver		*powernow_driver;
+static unsigned int                     busfreq;   /* FSB, in 10 kHz */
+static unsigned int                     max_multiplier;
+
+
+/* Clock ratio multiplied by 10 - see table 27 in AMD#23446 */
+static int clock_ratio[8] = {
+	45,  /* 000 -> 4.5x */
+	50,  /* 001 -> 5.0x */
+	40,  /* 010 -> 4.0x */
+	55,  /* 011 -> 5.5x */
+	20,  /* 100 -> 2.0x */
+	30,  /* 101 -> 3.0x */
+	60,  /* 110 -> 6.0x */
+	35   /* 111 -> 3.5x */
+};
+
+
+/**
+ * powernow_k6_get_cpu_multiplier - returns the current FSB multiplier
+ *
+ *   Returns the current setting of the frequency multiplier. Core clock
+ * speed is frequency of the Front-Side Bus multiplied with this value.
+ */
+static int powernow_k6_get_cpu_multiplier(void)
+{
+	u64             invalue = 0;
+	u32             msrval;
+	
+	msrval = POWERNOW_IOPORT + 0x1;
+	wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
+	invalue=inl(POWERNOW_IOPORT + 0x8);
+	msrval = POWERNOW_IOPORT + 0x0;
+	wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
+
+	return clock_ratio[(invalue >> 5)&7];
+}
+
+
+/**
+ * powernow_k6_set_state - set the PowerNow! multiplier
+ * @best_i: clock_ratio[best_i] is the target multiplier
+ *
+ *   Tries to change the PowerNow! multiplier
+ */
+static void powernow_k6_set_state (unsigned int best_i)
+{
+	unsigned long           outvalue=0, invalue=0;
+	unsigned long           msrval;
+	struct cpufreq_freqs    freqs;
+
+	if (!powernow_driver) {
+		printk(KERN_ERR "cpufreq: initialization problem or invalid target frequency\n");
+		return;
+	}
+
+	freqs.old = busfreq * powernow_k6_get_cpu_multiplier();
+	freqs.new = busfreq * clock_ratio[best_i];
+	freqs.cpu = CPUFREQ_ALL_CPUS; /* powernow-k6.c is UP only driver */
+	
+	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	/* we now need to transform best_i to the BVC format, see AMD#23446 */
+
+	outvalue = (1<<12) | (1<<10) | (1<<9) | (best_i<<5);
+
+	msrval = POWERNOW_IOPORT + 0x1;
+	wrmsr(MSR_K6_EPMR, msrval, 0); /* enable the PowerNow port */
+	invalue=inl(POWERNOW_IOPORT + 0x8);
+	invalue = invalue & 0xf;
+	outvalue = outvalue | invalue;
+	outl(outvalue ,(POWERNOW_IOPORT + 0x8));
+	msrval = POWERNOW_IOPORT + 0x0;
+	wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
+
+	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	return;
+}
+
+
+/**
+ * powernow_k6_verify - verifies a new CPUfreq policy
+ * @policy: new policy
+ *
+ * Policy must be within lowest and highest possible CPU Frequency,
+ * and at least one possible state must be within min and max.
+ */
+static void powernow_k6_verify(struct cpufreq_policy *policy)
+{
+	unsigned int    number_states = 0;
+	unsigned int    i, j;
+
+	if (!policy || !busfreq)
+		return;
+
+	policy->cpu = 0;
+	cpufreq_verify_within_limits(policy, (20 * busfreq),
+				     (max_multiplier * busfreq));
+
+	for (i=0; i<8; i++)
+		if ((policy->min <= (busfreq * clock_ratio[i])) &&
+		    (policy->max >= (busfreq * clock_ratio[i])))
+			number_states++;
+
+	if (number_states)
+		return;
+
+	/* no state is available within range -- find next larger state */
+
+	j = 6;
+
+	for (i=0; i<8; i++)
+		if (((clock_ratio[i] * busfreq) >= policy->min) &&
+		    (clock_ratio[i] < clock_ratio[j]))
+			j = i;
+
+	policy->max = clock_ratio[j] * busfreq;
+
+	return;
+}
+
+
+/**
+ * powernow_k6_setpolicy - sets a new CPUFreq policy
+ * @policy - new policy
+ *
+ * sets a new CPUFreq policy
+ */
+static void powernow_k6_setpolicy (struct cpufreq_policy *policy)
+{
+	unsigned int    number_states = 0;
+	unsigned int    i, j=4;
+
+	if (!powernow_driver)
+		return;
+
+	for (i=0; i<8; i++)
+		if ((policy->min <= (busfreq * clock_ratio[i])) &&
+		    (policy->max >= (busfreq * clock_ratio[i])))
+		{
+			number_states++;
+			j = i;
+		}
+
+	if (number_states == 1) {
+		/* if only one state is within the limit borders, it
+		   is easily detected and set */
+		powernow_k6_set_state(j);
+		return;
+	}
+
+	/* more than one state within limit */
+	switch (policy->policy) {
+	case CPUFREQ_POLICY_POWERSAVE:
+		j = 6;
+		for (i=0; i<8; i++)
+		if ((policy->min <= (busfreq * clock_ratio[i])) &&
+		    (policy->max >= (busfreq * clock_ratio[i])) &&
+			    (clock_ratio[i] < clock_ratio[j]))
+				j = i;
+		break;
+	case CPUFREQ_POLICY_PERFORMANCE:
+		j = 4;
+		for (i=0; i<8; i++)
+		if ((policy->min <= (busfreq * clock_ratio[i])) &&
+		    (policy->max >= (busfreq * clock_ratio[i])) &&
+			    (clock_ratio[i] > clock_ratio[j]))
+				j = i;
+		break;
+	default:
+		return;
+	}
+
+	if (clock_ratio[i] > max_multiplier)
+		BUG();
+
+	powernow_k6_set_state(j);
+	return;
+}
+
+
+/**
+ * powernow_k6_init - initializes the k6 PowerNow! CPUFreq driver
+ *
+ *   Initializes the K6 PowerNow! support. Returns -ENODEV on unsupported
+ * devices, -EINVAL or -ENOMEM on problems during initiatization, and zero
+ * on success.
+ */
+static int __init powernow_k6_init(void)
+{	
+	struct cpuinfo_x86      *c = cpu_data;
+	struct cpufreq_driver   *driver;
+	unsigned int            result;
+
+	if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 != 5) ||
+		((c->x86_model != 12) && (c->x86_model != 13)))
+		return -ENODEV;
+
+	max_multiplier = powernow_k6_get_cpu_multiplier();
+	busfreq = cpu_khz / max_multiplier;
+
+	if (!request_region(POWERNOW_IOPORT, 16, "PowerNow!")) {
+		printk("cpufreq: PowerNow IOPORT region already used.\n");
+		return -EIO;
+	}
+
+	/* initialization of main "cpufreq" code*/
+	driver = kmalloc(sizeof(struct cpufreq_driver) +
+			 NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
+	if (!driver) {
+		release_region (POWERNOW_IOPORT, 16);
+		return -ENOMEM;
+	}
+	driver->policy = (struct cpufreq_policy *) (driver + 1);
+
+#ifdef CONFIG_CPU_FREQ_24_API
+	driver->cpu_min_freq     = busfreq * 20;
+	driver->cpu_cur_freq[0]  = busfreq * max_multiplier;
+#endif
+
+	driver->verify        = &powernow_k6_verify;
+	driver->setpolicy     = &powernow_k6_setpolicy;
+
+	driver->policy[0].cpu    = 0;
+	driver->policy[0].min    = busfreq * 20;
+	driver->policy[0].max    = busfreq * max_multiplier;
+	driver->policy[0].policy = CPUFREQ_POLICY_PERFORMANCE;
+	driver->policy[0].max_cpu_freq  = busfreq * max_multiplier;
+
+
+	result = cpufreq_register(driver);
+	if (result) {
+		release_region (POWERNOW_IOPORT, 16);
+		kfree(driver);
+		return result;
+	}
+	powernow_driver = driver;
+
+	return 0;
+}
+
+
+/**
+ * powernow_k6_exit - unregisters AMD K6-2+/3+ PowerNow! support
+ *
+ *   Unregisters AMD K6-2+ / K6-3+ PowerNow! support.
+ */
+static void __exit powernow_k6_exit(void)
+{
+	unsigned int i;
+
+	if (powernow_driver) {
+		for (i=0;i<8;i++)
+			if (clock_ratio[i] == max_multiplier)
+				powernow_k6_set_state(i);		
+		cpufreq_unregister();
+		kfree(powernow_driver);
+	}
+}
+
+
+MODULE_AUTHOR ("Arjan van de Ven <arjanv@redhat.com>, Dave Jones <davej@suse.de>, Dominik Brodowski <linux@brodo.de>");
+MODULE_DESCRIPTION ("PowerNow! driver for AMD K6-2+ / K6-3+ processors.");
+MODULE_LICENSE ("GPL");
+module_init(powernow_k6_init);
+module_exit(powernow_k6_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/process.c linux.20pre10-ac2/arch/i386/kernel/process.c
--- linux.20pre10/arch/i386/kernel/process.c	2002-10-09 21:36:57.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/process.c	2002-08-26 14:24:47.000000000 +0100
@@ -124,15 +124,12 @@
 void cpu_idle (void)
 {
 	/* endless idle loop with no priority at all */
-	init_idle();
-	current->nice = 20;
-	current->counter = -100;
 
 	while (1) {
 		void (*idle)(void) = pm_idle;
 		if (!idle)
 			idle = default_idle;
-		while (!current->need_resched)
+		if (!current->need_resched)
 			idle();
 		schedule();
 		check_pgt_cache();
@@ -187,7 +184,7 @@
 			}
 				/* we will leave sorting out the final value 
 				when we are ready to reboot, since we might not
- 				have set up boot_cpu_id or smp_num_cpu */
+ 				have set up boot_cpu_physical_apicid or smp_num_cpu */
 			break;
 #endif
 		}
@@ -253,7 +250,7 @@
 	0x66, 0x0f, 0x20, 0xc3,			/*    movl  %cr0,%ebx        */
 	0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60,	/*    andl  $0x60000000,%ebx */
 	0x74, 0x02,				/*    jz    f                */
-	0x0f, 0x08,				/*    invd                   */
+	0x0f, 0x09,				/*    wbinvd                 */
 	0x24, 0x10,				/* f: andb  $0x10,al         */
 	0x66, 0x0f, 0x22, 0xc0			/*    movl  %eax,%cr0        */
 };
@@ -466,23 +463,6 @@
 }
 
 /*
- * No need to lock the MM as we are the last user
- */
-void release_segments(struct mm_struct *mm)
-{
-	void * ldt = mm->context.segments;
-
-	/*
-	 * free the LDT
-	 */
-	if (ldt) {
-		mm->context.segments = NULL;
-		clear_LDT();
-		vfree(ldt);
-	}
-}
-
-/*
  * Create a kernel thread
  */
 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
@@ -534,45 +514,19 @@
 void release_thread(struct task_struct *dead_task)
 {
 	if (dead_task->mm) {
-		void * ldt = dead_task->mm->context.segments;
-
 		// temporary debugging check
-		if (ldt) {
-			printk("WARNING: dead process %8s still has LDT? <%p>\n",
-					dead_task->comm, ldt);
+		if (dead_task->mm->context.size) {
+			printk("WARNING: dead process %8s still has LDT? <%p/%d>\n",
+					dead_task->comm,
+					dead_task->mm->context.ldt,
+					dead_task->mm->context.size);
 			BUG();
 		}
 	}
-
 	release_x86_irqs(dead_task);
 }
 
 /*
- * we do not have to muck with descriptors here, that is
- * done in switch_mm() as needed.
- */
-void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
-{
-	struct mm_struct * old_mm;
-	void *old_ldt, *ldt;
-
-	ldt = NULL;
-	old_mm = current->mm;
-	if (old_mm && (old_ldt = old_mm->context.segments) != NULL) {
-		/*
-		 * Completely new LDT, we initialize it from the parent:
-		 */
-		ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
-		if (!ldt)
-			printk(KERN_WARNING "ldt allocation failed\n");
-		else
-			memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
-	}
-	new_mm->context.segments = ldt;
-	new_mm->context.cpuvalid = ~0UL;	/* valid on all CPU's - they can't have stale data */
-}
-
-/*
  * Save a segment.
  */
 #define savesegment(seg,value) \
@@ -697,15 +651,17 @@
 	asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs));
 
 	/*
-	 * Restore %fs and %gs.
+	 * Restore %fs and %gs if needed.
 	 */
-	loadsegment(fs, next->fs);
-	loadsegment(gs, next->gs);
+	if (unlikely(prev->fs | prev->gs | next->fs | next->gs)) {
+		loadsegment(fs, next->fs);
+		loadsegment(gs, next->gs);
+	}
 
 	/*
 	 * Now maybe reload the debug registers
 	 */
-	if (next->debugreg[7]){
+	if (unlikely(next->debugreg[7])) {
 		loaddebug(next, 0);
 		loaddebug(next, 1);
 		loaddebug(next, 2);
@@ -715,7 +671,7 @@
 		loaddebug(next, 7);
 	}
 
-	if (prev->ioperm || next->ioperm) {
+	if (unlikely(prev->ioperm || next->ioperm)) {
 		if (next->ioperm) {
 			/*
 			 * 4 cachelines copy ... not good, but not that
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/scx200.c linux.20pre10-ac2/arch/i386/kernel/scx200.c
--- linux.20pre10/arch/i386/kernel/scx200.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/scx200.c	2002-10-10 23:56:47.000000000 +0100
@@ -0,0 +1,128 @@
+/* linux/arch/i386/kernel/scx200.c 
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   National Semiconductor SCx200 support. */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <linux/scx200.h>
+#include <linux/scx200.h>
+
+#define NAME "scx200"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 Driver");
+MODULE_LICENSE("GPL");
+
+unsigned scx200_gpio_base = 0;
+long scx200_gpio_shadow[2];
+
+spinlock_t scx200_gpio_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t scx200_gpio_config_lock = SPIN_LOCK_UNLOCKED;
+
+u32 scx200_gpio_configure(int index, u32 mask, u32 bits)
+{
+	u32 config, new_config;
+	unsigned long flags;
+
+	spin_lock_irqsave(&scx200_gpio_config_lock, flags);
+
+	outl(index, scx200_gpio_base + 0x20);
+	config = inl(scx200_gpio_base + 0x24);
+
+	new_config = (config & mask) | bits;
+	outl(new_config, scx200_gpio_base + 0x24);
+
+	spin_unlock_irqrestore(&scx200_gpio_config_lock, flags);
+
+	return config;
+}
+
+void scx200_gpio_dump(unsigned index)
+{
+	u32 config = scx200_gpio_configure(index, ~0, 0);
+	printk(KERN_DEBUG "GPIO%02u: 0x%08lx", index, (unsigned long)config);
+	
+	if (config & 1) 
+		printk(" OE"); /* output enabled */
+	else
+		printk(" TS"); /* tristate */
+	if (config & 2) 
+		printk(" PP"); /* push pull */
+	else
+		printk(" OD"); /* open drain */
+	if (config & 4) 
+		printk(" PUE"); /* pull up enabled */
+	else
+		printk(" PUD"); /* pull up disabled */
+	if (config & 8) 
+		printk(" LOCKED"); /* locked */
+	if (config & 16) 
+		printk(" LEVEL"); /* level input */
+	else
+		printk(" EDGE"); /* edge input */
+	if (config & 32) 
+		printk(" HI"); /* trigger on rising edge */
+	else
+		printk(" LO"); /* trigger on falling edge */
+	if (config & 64) 
+		printk(" DEBOUNCE"); /* debounce */
+	printk("\n");
+}
+
+int __init scx200_init(void)
+{
+	struct pci_dev *bridge;
+	int bank;
+	unsigned base;
+
+	printk(KERN_INFO NAME ": NatSemi SCx200 Driver\n");
+
+	if ((bridge = pci_find_device(PCI_VENDOR_ID_NS, 
+				      PCI_DEVICE_ID_NS_SCx200_BRIDGE,
+				      NULL)) == NULL)
+		return -ENODEV;
+
+	base = pci_resource_start(bridge, 0);
+	printk(KERN_INFO NAME ": GPIO base 0x%x\n", base);
+
+	if (request_region(base, SCx200_GPIO_SIZE, "NatSemi SCx200 GPIO") == 0) {
+		printk(KERN_ERR NAME ": can't allocate I/O for GPIOs\n");
+		return -EBUSY;
+	}
+
+	scx200_gpio_base = base;
+
+	/* read the current values driven on the GPIO signals */
+	for (bank = 0; bank < 2; ++bank)
+		scx200_gpio_shadow[bank] = inl(scx200_gpio_base + 0x10 * bank);
+
+	return 0;
+}
+
+void __exit scx200_cleanup(void)
+{
+	release_region(scx200_gpio_base, SCx200_GPIO_SIZE);
+}
+
+module_init(scx200_init);
+module_exit(scx200_cleanup);
+
+EXPORT_SYMBOL(scx200_gpio_base);
+EXPORT_SYMBOL(scx200_gpio_shadow);
+EXPORT_SYMBOL(scx200_gpio_lock);
+EXPORT_SYMBOL(scx200_gpio_configure);
+EXPORT_SYMBOL(scx200_gpio_dump);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../../.. SUBDIRS=arch/i386/kernel modules"
+        c-basic-offset: 8
+    End:
+*/
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/setup.c linux.20pre10-ac2/arch/i386/kernel/setup.c
--- linux.20pre10/arch/i386/kernel/setup.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/setup.c	2002-10-07 21:36:29.000000000 +0100
@@ -1175,23 +1175,49 @@
 }
 __setup("cachesize=", cachesize_setup);
 
-
 #ifndef CONFIG_X86_TSC
+
 static int tsc_disable __initdata = 0;
 
+void disable_tsc(void)
+{
+	if(tsc_disable == 0)
+	{
+		printk(KERN_INFO "Disabling use of TSC for time counting.\n");
+		tsc_disable = 1;
+	}
+}
+
+/* Disable TSC on processor and also for get time of day */
+
 static int __init notsc_setup(char *str)
 {
+	tsc_disable = 2;
+	return 1;
+}
+
+__setup("notsc", notsc_setup);
+
+/* Allow TSC use but don't use it for gettimeofday  */
+
+static int __init badtsc_setup(char *str)
+{
 	tsc_disable = 1;
 	return 1;
 }
+
+__setup("badtsc", badtsc_setup);
+
 #else
-static int __init notsc_setup(char *str)
+
+#define tsc_disable	0
+
+void disable_tsc(void)
 {
-	printk("notsc: Kernel compiled with CONFIG_X86_TSC, cannot disable TSC.\n");
-	return 1;
+	panic("Time stamp counter required by this kernel, but not supported by the hardware.\n");
 }
+
 #endif
-__setup("notsc", notsc_setup);
 
 static int __init highio_setup(char *str)
 {
@@ -1478,11 +1504,9 @@
 }
 
 /*
- * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in
- * order to identify the Cyrix CPU model after we're out of setup.c
- *
- * Actually since bugs.h doesn't even reference this perhaps someone should
- * fix the documentation ???
+ * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in
+ * order to identify the Cyrix CPU model after we're out of the
+ * initial setup.
  */
 static unsigned char Cx86_dir0_msb __initdata = 0;
 
@@ -2291,6 +2315,20 @@
 				}
 			}
 		}
+
+		/* Intel PIII Tualatin. This comes in two flavours.
+		 * One has 256kb of cache, the other 512. We have no way
+		 * to determine which, so we use a boottime override
+		 * for the 512kb model, and assume 256 otherwise.
+		 */
+		if ((c->x86_vendor == X86_VENDOR_INTEL) && (c->x86 == 6) &&
+			(c->x86_model == 11) && (l2 == 0))
+			l2 = 256;
+
+		/* Allow user to override all this if necessary. */
+		if (cachesize_override != -1)
+			l2 = cachesize_override;
+
 		if ( l1i || l1d )
 			printk(KERN_INFO "CPU: L1 I cache: %dK, L1 D cache: %dK\n",
 			       l1i, l1d);
@@ -2774,10 +2812,8 @@
 	 */
 
 	/* TSC disabled? */
-#ifndef CONFIG_X86_TSC
-	if ( tsc_disable )
+	if ( tsc_disable > 1 )
 		clear_bit(X86_FEATURE_TSC, &c->x86_capability);
-#endif
 
 	/* check for caps that have been disabled earlier */ 
 	for (i = 0; i < NCAPINTS; i++) { 
@@ -2828,17 +2864,31 @@
 	       boot_cpu_data.x86_capability[2],
 	       boot_cpu_data.x86_capability[3]);
 }
+
+
 /*
  *	Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c
  */
  
-void __init dodgy_tsc(void)
+int __init select_tsc(void)
 {
 	get_cpu_vendor(&boot_cpu_data);
 
 	if ( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ||
 	     boot_cpu_data.x86_vendor == X86_VENDOR_NSC )
 		init_cyrix(&boot_cpu_data);
+
+	/* Cyclone needs to be added */
+		
+	/* Is it disabled ? */
+	if(tsc_disable)
+		return TSC_NONE;
+		
+	/* Does it exist ? */
+	if(!cpu_has_tsc)
+		return TSC_NONE;
+
+	return TSC_CPU;
 }
 
 
@@ -2885,6 +2935,7 @@
 	 * applications want to get the raw CPUID data, they should access
 	 * /dev/cpu/<cpu_nr>/cpuid instead.
 	 */
+	extern	int phys_proc_id[NR_CPUS];
 	static char *x86_cap_flags[] = {
 		/* Intel-defined */
 	        "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
@@ -2942,6 +2993,11 @@
 	/* Cache size */
 	if (c->x86_cache_size >= 0)
 		seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
+
+#ifdef CONFIG_SMP
+	seq_printf(m, "physical id\t: %d\n",phys_proc_id[n]);
+	seq_printf(m, "siblings\t: %d\n",smp_num_siblings);
+#endif
 	
 	/* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */
 	fpu_exception = c->hard_math && (ignore_irq13 || cpu_has_fpu);
@@ -3014,14 +3070,12 @@
 
 	if (cpu_has_vme || cpu_has_tsc || cpu_has_de)
 		clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
-#ifndef CONFIG_X86_TSC
-	if (tsc_disable && cpu_has_tsc) {
+	if (tsc_disable > 1 && cpu_has_tsc) {
 		printk(KERN_NOTICE "Disabling TSC...\n");
 		/**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/
 		clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability);
 		set_in_cr4(X86_CR4_TSD);
 	}
-#endif
 
 	__asm__ __volatile__("lgdt %0": "=m" (gdt_descr));
 	__asm__ __volatile__("lidt %0": "=m" (idt_descr));
@@ -3044,11 +3098,12 @@
 	set_tss_desc(nr,t);
 	gdt_table[__TSS(nr)].b &= 0xfffffdff;
 	load_TR(nr);
-	load_LDT(&init_mm);
+	load_LDT(&init_mm.context);
 
-	/*
-	 * Clear all 6 debug registers:
-	 */
+	/* Clear %fs and %gs. */
+	asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs");
+
+	/* Clear all 6 debug registers: */
 
 #define CD(register) __asm__("movl %0,%%db" #register ::"r"(0) );
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/smpboot.c linux.20pre10-ac2/arch/i386/kernel/smpboot.c
--- linux.20pre10/arch/i386/kernel/smpboot.c	2002-10-09 21:36:57.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/smpboot.c	2002-08-18 11:11:18.000000000 +0100
@@ -58,7 +58,7 @@
 
 /* Number of siblings per CPU package */
 int smp_num_siblings = 1;
-int __initdata phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */
+int phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */
 
 /* Bitmask of currently online CPUs */
 unsigned long cpu_online_map;
@@ -365,7 +365,7 @@
 	 * (This works even if the APIC is not enabled.)
 	 */
 	phys_id = GET_APIC_ID(apic_read(APIC_ID));
-	cpuid = current->processor;
+	cpuid = cpu();
 	if (test_and_set_bit(cpuid, &cpu_online_map)) {
 		printk("huh, phys CPU#%d, CPU#%d already present??\n",
 					phys_id, cpuid);
@@ -435,6 +435,7 @@
 	 */
  	smp_store_cpu_info(cpuid);
 
+	disable_APIC_timer();
 	/*
 	 * Allow the master to continue.
 	 */
@@ -443,7 +444,7 @@
 	/*
 	 *      Synchronize the TSC with the BP
 	 */
-	if (cpu_has_tsc)
+	if (cpu_has_tsc > 1)
 		synchronize_tsc_ap();
 }
 
@@ -465,6 +466,7 @@
 	smp_callin();
 	while (!atomic_read(&smp_commenced))
 		rep_nop();
+	enable_APIC_timer();
 	/*
 	 * low-memory mappings have been cleared, flush them from
 	 * the local TLBs too.
@@ -509,59 +511,28 @@
 	return do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0);
 }
 
-/* which physical APIC ID maps to which logical CPU number */
-volatile int physical_apicid_2_cpu[MAX_APICID];
 /* which logical CPU number maps to which physical APIC ID */
-volatile int cpu_2_physical_apicid[NR_CPUS];
+volatile u8 cpu_2_physical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
 
-/* which logical APIC ID maps to which logical CPU number */
-volatile int logical_apicid_2_cpu[MAX_APICID];
 /* which logical CPU number maps to which logical APIC ID */
-volatile int cpu_2_logical_apicid[NR_CPUS];
+volatile u8 cpu_2_logical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
 
-static inline void init_cpu_to_apicid(void)
-/* Initialize all maps between cpu number and apicids */
-{
-	int apicid, cpu;
-
-	for (apicid = 0; apicid < MAX_APICID; apicid++) {
-		physical_apicid_2_cpu[apicid] = -1;
-		logical_apicid_2_cpu[apicid] = -1;
-	}
-	for (cpu = 0; cpu < NR_CPUS; cpu++) {
-		cpu_2_physical_apicid[cpu] = -1;
-		cpu_2_logical_apicid[cpu] = -1;
-	}
-}
-
-static inline void map_cpu_to_boot_apicid(int cpu, int apicid)
+static inline void map_cpu_to_boot_apicid(int cpu, int phys_apicid, int log_apicid)
 /* 
- * set up a mapping between cpu and apicid. Uses logical apicids for multiquad,
- * else physical apic ids
+ * set up a mapping between cpu and apicids.
  */
 {
-	if (clustered_apic_mode) {
-		logical_apicid_2_cpu[apicid] = cpu;	
-		cpu_2_logical_apicid[cpu] = apicid;
-	} else {
-		physical_apicid_2_cpu[apicid] = cpu;	
-		cpu_2_physical_apicid[cpu] = apicid;
-	}
+	cpu_2_logical_apicid[cpu] = (u8) log_apicid;
+	cpu_2_physical_apicid[cpu] = (u8) phys_apicid;
 }
 
-static inline void unmap_cpu_to_boot_apicid(int cpu, int apicid)
+static inline void unmap_cpu_to_boot_apicid(int cpu)
 /* 
- * undo a mapping between cpu and apicid. Uses logical apicids for multiquad,
- * else physical apic ids
+ * undo a mapping between cpu and apicids.
  */
 {
-	if (clustered_apic_mode) {
-		logical_apicid_2_cpu[apicid] = -1;	
-		cpu_2_logical_apicid[cpu] = -1;
-	} else {
-		physical_apicid_2_cpu[apicid] = -1;	
-		cpu_2_physical_apicid[cpu] = -1;
-	}
+	cpu_2_logical_apicid[cpu] = BAD_APICID;
+	cpu_2_physical_apicid[cpu] = BAD_APICID;
 }
 
 #if APIC_DEBUG
@@ -775,17 +746,13 @@
 
 extern unsigned long cpu_initialized;
 
-static void __init do_boot_cpu (int apicid) 
-/*
- * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
- * (ie clustered apic addressing mode), this is a LOGICAL apic ID.
- */
+static void __init do_boot_cpu (int phys_apicid, int log_apicid)
 {
 	struct task_struct *idle;
 	unsigned long boot_error = 0;
 	int timeout, cpu;
 	unsigned long start_eip;
-	unsigned short nmi_high, nmi_low;
+	unsigned short nmi_high = 0, nmi_low = 0;
 
 	cpu = ++cpucount;
 	/*
@@ -803,22 +770,19 @@
 	if (!idle)
 		panic("No idle process for CPU %d", cpu);
 
-	idle->processor = cpu;
-	idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */
+	init_idle(idle, cpu);
 
-	map_cpu_to_boot_apicid(cpu, apicid);
+	map_cpu_to_boot_apicid(cpu, phys_apicid, log_apicid);
 
 	idle->thread.eip = (unsigned long) start_secondary;
 
-	del_from_runqueue(idle);
 	unhash_process(idle);
-	init_tasks[cpu] = idle;
 
 	/* start_eip had better be page-aligned! */
 	start_eip = setup_trampoline();
 
 	/* So we see what's up   */
-	printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip);
+	printk("Booting processor %d/%d eip %lx\n", cpu, log_apicid, start_eip);
 	stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle);
 
 	/*
@@ -830,7 +794,7 @@
 
 	Dprintk("Setting warm reset code and vector.\n");
 
-	if (clustered_apic_mode) {
+	if (clustered_apic_logical) {
 		/* stash the current NMI vector, so we can put things back */
 		nmi_high = *((volatile unsigned short *) TRAMPOLINE_HIGH);
 		nmi_low = *((volatile unsigned short *) TRAMPOLINE_LOW);
@@ -847,7 +811,7 @@
 	/*
 	 * Be paranoid about clearing APIC errors.
 	 */
-	if (!clustered_apic_mode && APIC_INTEGRATED(apic_version[apicid])) {
+	if (!clustered_apic_mode && APIC_INTEGRATED(apic_version[phys_apicid])) {
 		apic_read_around(APIC_SPIV);
 		apic_write(APIC_ESR, 0);
 		apic_read(APIC_ESR);
@@ -862,10 +826,10 @@
 	 * Starting actual IPI sequence...
 	 */
 
-	if (clustered_apic_mode)
-		boot_error = wakeup_secondary_via_NMI(apicid);
+	if (clustered_apic_logical)
+		boot_error = wakeup_secondary_via_NMI(log_apicid);
 	else 
-		boot_error = wakeup_secondary_via_INIT(apicid, start_eip);
+		boot_error = wakeup_secondary_via_INIT(phys_apicid, start_eip);
 
 	if (!boot_error) {
 		/*
@@ -901,13 +865,13 @@
 				printk("Not responding.\n");
 #if APIC_DEBUG
 			if (!clustered_apic_mode)
-				inquire_remote_apic(apicid);
+				inquire_remote_apic(phys_apicid);
 #endif
 		}
 	}
 	if (boot_error) {
 		/* Try to put things back the way they were before ... */
-		unmap_cpu_to_boot_apicid(cpu, apicid);
+		unmap_cpu_to_boot_apicid(cpu);
 		clear_bit(cpu, &cpu_callout_map); /* was set here (do_boot_cpu()) */
 		clear_bit(cpu, &cpu_initialized); /* was set by cpu_init() */
 		clear_bit(cpu, &cpu_online_map);  /* was set in smp_callin() */
@@ -917,7 +881,7 @@
 	/* mark "stuck" area as not stuck */
 	*((volatile unsigned long *)phys_to_virt(8192)) = 0;
 
-	if(clustered_apic_mode) {
+	if (clustered_apic_logical) {
 		printk("Restoring NMI vector\n");
 		*((volatile unsigned short *) TRAMPOLINE_HIGH) = nmi_high;
 		*((volatile unsigned short *) TRAMPOLINE_LOW) = nmi_low;
@@ -925,6 +889,7 @@
 }
 
 cycles_t cacheflush_time;
+unsigned long cache_decay_ticks;
 
 static void smp_tune_scheduling (void)
 {
@@ -958,9 +923,13 @@
 		cacheflush_time = (cpu_khz>>10) * (cachesize<<10) / bandwidth;
 	}
 
+	cache_decay_ticks = (long)cacheflush_time/cpu_khz * HZ / 1000;
+
 	printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n",
 		(long)cacheflush_time/(cpu_khz/1000),
 		((long)cacheflush_time*100/(cpu_khz/1000)) % 100);
+	printk("task migration cache decay timeout: %ld msecs.\n",
+		(cache_decay_ticks + 1) * 1000 / HZ);
 }
 
 /*
@@ -971,17 +940,19 @@
 extern int prof_old_multiplier[NR_CPUS];
 extern int prof_counter[NR_CPUS];
 
-static int boot_cpu_logical_apicid;
+#ifdef CONFIG_MULTIQUAD
 /* Where the IO area was mapped on multiquad, always 0 otherwise */
 void *xquad_portio;
+#endif
 
 int cpu_sibling_map[NR_CPUS] __cacheline_aligned;
 
 void __init smp_boot_cpus(void)
 {
-	int apicid, cpu, bit;
+	int phys_apicid, log_apicid, cpu, bit;
 
-        if (clustered_apic_mode && (numnodes > 1)) {
+#ifdef CONFIG_MULTIQUAD
+        if (clustered_apic_logical && (numnodes > 1)) {
                 printk("Remapping cross-quad port I/O for %d quads\n",
 			numnodes);
                 printk("xquad_portio vaddr 0x%08lx, len %08lx\n",
@@ -990,6 +961,7 @@
                 xquad_portio = ioremap (XQUAD_PORTIO_BASE, 
 			numnodes * XQUAD_PORTIO_LEN);
         }
+#endif
 
 #ifdef CONFIG_MTRR
 	/*  Must be done before other processors booted  */
@@ -1006,8 +978,6 @@
 		prof_multiplier[cpu] = 1;
 	}
 
-	init_cpu_to_apicid();
-
 	/*
 	 * Setup boot CPU information
 	 */
@@ -1019,12 +989,16 @@
 	 * We have the boot CPU online for sure.
 	 */
 	set_bit(0, &cpu_online_map);
-	boot_cpu_logical_apicid = logical_smp_processor_id();
-	map_cpu_to_boot_apicid(0, boot_cpu_apicid);
+	if (clustered_apic_physical)
+		boot_cpu_logical_apicid = physical_to_logical_apicid(boot_cpu_physical_apicid);
+	else if (clustered_apic_logical)
+		boot_cpu_logical_apicid = logical_smp_processor_id();
+	else
+		boot_cpu_logical_apicid = 0x01;
+	map_cpu_to_boot_apicid(0, boot_cpu_physical_apicid, boot_cpu_logical_apicid);
 
 	global_irq_holder = 0;
-	current->processor = 0;
-	init_idle();
+	current->cpu = 0;
 	smp_tune_scheduling();
 
 	/*
@@ -1103,28 +1077,36 @@
 	 */
 	Dprintk("CPU present map: %lx\n", phys_cpu_present_map);
 
+	cpu = 1;
 	for (bit = 0; bit < NR_CPUS; bit++) {
-		apicid = cpu_present_to_apicid(bit);
+		if (!(phys_cpu_present_map & (1UL << bit)))
+			continue;
+		if ((max_cpus >= 0) && (max_cpus <= cpucount+1))
+			continue;
+		phys_apicid = raw_phys_apicid[bit];
 		/*
 		 * Don't even attempt to start the boot CPU!
 		 */
-		if (apicid == boot_cpu_apicid)
-			continue;
-
-		if (!(phys_cpu_present_map & (1 << bit)))
-			continue;
-		if ((max_cpus >= 0) && (max_cpus <= cpucount+1))
+		if (phys_apicid == boot_cpu_physical_apicid)
 			continue;
+		if (clustered_apic_physical)
+			log_apicid = physical_to_logical_apicid(phys_apicid);
+		else if (clustered_apic_logical)
+			log_apicid = ((bit >> 2) << 4) | (1 << (bit & 0x3));
+		else
+			log_apicid = 1u << cpu;
 
-		do_boot_cpu(apicid);
+		do_boot_cpu(phys_apicid, log_apicid);
 
 		/*
 		 * Make sure we unmap all failed CPUs
 		 */
-		if ((boot_apicid_to_cpu(apicid) == -1) &&
-				(phys_cpu_present_map & (1 << bit)))
+		if ((cpu_to_physical_apicid(bit) == BAD_APICID) &&
+				(phys_cpu_present_map & (1ul << bit)))
 			printk("CPU #%d not responding - cannot use it.\n",
-								apicid);
+								bit);
+		else
+			++cpu;
 	}
 
 	/*
@@ -1216,7 +1198,7 @@
 	/*
 	 * Synchronize the TSC with the AP
 	 */
-	if (cpu_has_tsc && cpucount)
+	if (cpu_has_tsc > 1 && cpucount)
 		synchronize_tsc_bp();
 
 smp_done:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/smp.c linux.20pre10-ac2/arch/i386/kernel/smp.c
--- linux.20pre10/arch/i386/kernel/smp.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/smp.c	2002-08-13 14:05:23.000000000 +0100
@@ -115,7 +115,7 @@
 
 static inline int __prepare_ICR (unsigned int shortcut, int vector)
 {
-	return APIC_DM_FIXED | shortcut | vector | APIC_DEST_LOGICAL;
+	return APIC_DM_FIXED | shortcut | vector | INT_DEST_ADDR_MODE;
 }
 
 static inline int __prepare_ICR2 (unsigned int mask)
@@ -214,7 +214,9 @@
 			/*
 			 * prepare target chip field
 			 */
-			cfg = __prepare_ICR2(cpu_to_logical_apicid(query_cpu));
+			cfg = __prepare_ICR2(clustered_apic_physical ?
+					cpu_to_physical_apicid(query_cpu) :
+					cpu_to_logical_apicid(query_cpu));
 			apic_write_around(APIC_ICR2, cfg);
 		
 			/*
@@ -493,13 +495,23 @@
  * it goes straight through and wastes no time serializing
  * anything. Worst case is that we lose a reschedule ...
  */
-
 void smp_send_reschedule(int cpu)
 {
 	send_IPI_mask(1 << cpu, RESCHEDULE_VECTOR);
 }
 
 /*
+ * this function sends a reschedule IPI to all (other) CPUs.
+ * This should only be used if some 'global' task became runnable,
+ * such as a RT task, that must be handled now. The first CPU
+ * that manages to grab the task will run it.
+ */
+void smp_send_reschedule_all(void)
+{
+	send_IPI_allbutself(RESCHEDULE_VECTOR);
+}
+
+/*
  * Structure and data for smp_call_function(). This is designed to minimise
  * static memory requirements. It also looks cleaner.
  */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/speedstep.c linux.20pre10-ac2/arch/i386/kernel/speedstep.c
--- linux.20pre10/arch/i386/kernel/speedstep.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/speedstep.c	2002-09-30 17:24:56.000000000 +0100
@@ -0,0 +1,728 @@
+/*
+ *  $Id: speedstep.c,v 1.53 2002/09/29 23:43:11 db Exp $
+ *
+ * (C) 2001  Dave Jones, Arjan van de ven.
+ * (C) 2002  Dominik Brodowski <linux@brodo.de>
+ *
+ *  Licensed under the terms of the GNU GPL License version 2.
+ *  Based upon reverse engineered information, and on Intel documentation
+ *  for chipsets ICH2-M and ICH3-M.
+ *
+ *  Many thanks to Ducrot Bruno for finding and fixing the last
+ *  "missing link" for ICH2-M/ICH3-M support, and to Thomas Winkler 
+ *  for extensive testing.
+ *
+ *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*
+ */
+
+
+/*********************************************************************
+ *                        SPEEDSTEP - DEFINITIONS                    *
+ *********************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h> 
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <asm/msr.h>
+
+
+static struct cpufreq_driver		*speedstep_driver;
+
+/* speedstep_chipset:
+ *   It is necessary to know which chipset is used. As accesses to 
+ * this device occur at various places in this module, we need a 
+ * static struct pci_dev * pointing to that device.
+ */
+static unsigned int                     speedstep_chipset;
+static struct pci_dev                   *speedstep_chipset_dev;
+
+#define SPEEDSTEP_CHIPSET_ICH2M         0x00000002
+#define SPEEDSTEP_CHIPSET_ICH3M         0x00000003
+
+
+/* speedstep_processor
+ */
+static unsigned int                     speedstep_processor;
+
+#define SPEEDSTEP_PROCESSOR_PIII_C      0x00000001  /* Coppermine core */
+#define SPEEDSTEP_PROCESSOR_PIII_T      0x00000002  /* Tualatin core */
+#define SPEEDSTEP_PROCESSOR_P4M         0x00000003  /* P4-M with 100 MHz FSB */
+
+
+/* speedstep_[low,high]_freq
+ *   There are only two frequency states for each processor. Values
+ * are in kHz for the time being.
+ */
+static unsigned int                     speedstep_low_freq;
+static unsigned int                     speedstep_high_freq;
+
+#define SPEEDSTEP_HIGH                  0x00000000
+#define SPEEDSTEP_LOW                   0x00000001
+
+
+/* DEBUG
+ *   Define it if you want verbose debug output, e.g. for bug reporting
+ */
+//#define SPEEDSTEP_DEBUG
+
+#ifdef SPEEDSTEP_DEBUG
+#define dprintk(msg...) printk(msg)
+#else
+#define dprintk(msg...) do { } while(0);
+#endif
+
+
+
+/*********************************************************************
+ *                    LOW LEVEL CHIPSET INTERFACE                    *
+ *********************************************************************/
+
+/**
+ * speedstep_get_state - read the current SpeedStep state
+ * @state: Speedstep state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
+ *
+ *   Tries to read the SpeedStep state. Returns -EIO when there has been
+ * trouble to read the status or write to the control register, -EINVAL
+ * on an unsupported chipset, and zero on success.
+ */
+static int speedstep_get_state (unsigned int *state)
+{
+	unsigned long   flags;
+	u32             pmbase;
+	u8              value;
+
+	if (!speedstep_chipset_dev || !state)
+		return -EINVAL;
+
+	switch (speedstep_chipset) {
+	case SPEEDSTEP_CHIPSET_ICH2M:
+	case SPEEDSTEP_CHIPSET_ICH3M:
+		/* get PMBASE */
+		pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase);
+		if (!(pmbase & 0x01))
+			return -EIO;
+
+		pmbase &= 0xFFFFFFFE;
+		if (!pmbase) 
+			return -EIO;
+
+		/* read state */
+		local_irq_save(flags);
+		value = inb(pmbase + 0x50);
+		local_irq_restore(flags);
+
+		dprintk(KERN_DEBUG "cpufreq: read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
+
+		*state = value & 0x01;
+		return 0;
+
+	}
+
+	printk (KERN_ERR "cpufreq: setting CPU frequency on this chipset unsupported.\n");
+	return -EINVAL;
+}
+
+
+/**
+ * speedstep_set_state - set the SpeedStep state
+ * @state: new processor frequency state (SPEEDSTEP_LOW or SPEEDSTEP_HIGH)
+ *
+ *   Tries to change the SpeedStep state. 
+ */
+static void speedstep_set_state (unsigned int state, int notify)
+{
+	u32                     pmbase;
+	u8	                pm2_blk;
+	u8                      value;
+	unsigned long           flags;
+	unsigned int            oldstate;
+	struct cpufreq_freqs    freqs;
+
+	if (!speedstep_chipset_dev || (state > 0x1))
+		return;
+
+	if (speedstep_get_state(&oldstate))
+		return;
+
+	if (oldstate == state)
+		return;
+
+	freqs.old = (oldstate == SPEEDSTEP_HIGH) ? speedstep_high_freq : speedstep_low_freq;
+	freqs.new = (state == SPEEDSTEP_HIGH) ? speedstep_high_freq : speedstep_low_freq;
+	freqs.cpu = CPUFREQ_ALL_CPUS; /* speedstep.c is UP only driver */
+	
+	if (notify)
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+	switch (speedstep_chipset) {
+	case SPEEDSTEP_CHIPSET_ICH2M:
+	case SPEEDSTEP_CHIPSET_ICH3M:
+		/* get PMBASE */
+		pci_read_config_dword(speedstep_chipset_dev, 0x40, &pmbase);
+		if (!(pmbase & 0x01))
+		{
+			printk(KERN_ERR "cpufreq: could not find speedstep register\n");
+			return;
+		}
+
+		pmbase &= 0xFFFFFFFE;
+		if (!pmbase) {
+			printk(KERN_ERR "cpufreq: could not find speedstep register\n");
+			return;
+		}
+
+		/* Disable IRQs */
+		local_irq_save(flags);
+
+		/* read state */
+		value = inb(pmbase + 0x50);
+
+		dprintk(KERN_DEBUG "cpufreq: read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
+
+		/* write new state */
+		value &= 0xFE;
+		value |= state;
+
+		dprintk(KERN_DEBUG "cpufreq: writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase);
+
+		/* Disable bus master arbitration */
+		pm2_blk = inb(pmbase + 0x20);
+		pm2_blk |= 0x01;
+		outb(pm2_blk, (pmbase + 0x20));
+
+		/* Actual transition */
+		outb(value, (pmbase + 0x50));
+
+		/* Restore bus master arbitration */
+		pm2_blk &= 0xfe;
+		outb(pm2_blk, (pmbase + 0x20));
+
+		/* check if transition was sucessful */
+		value = inb(pmbase + 0x50);
+
+		/* Enable IRQs */
+		local_irq_restore(flags);
+
+		dprintk(KERN_DEBUG "cpufreq: read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
+
+		if (state == (value & 0x1)) {
+			dprintk (KERN_INFO "cpufreq: change to %u MHz succeded\n", (freqs.new / 1000));
+		} else {
+			printk (KERN_ERR "cpufreq: change failed - I/O error\n");
+		}
+		break;
+	default:
+		printk (KERN_ERR "cpufreq: setting CPU frequency on this chipset unsupported.\n");
+	}
+
+	if (notify)
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+	return;
+}
+
+
+/**
+ * speedstep_activate - activate SpeedStep control in the chipset
+ *
+ *   Tries to activate the SpeedStep status and control registers.
+ * Returns -EINVAL on an unsupported chipset, and zero on success.
+ */
+static int speedstep_activate (void)
+{
+	if (!speedstep_chipset_dev)
+		return -EINVAL;
+
+	switch (speedstep_chipset) {
+	case SPEEDSTEP_CHIPSET_ICH2M:
+	case SPEEDSTEP_CHIPSET_ICH3M:
+	{
+		u16             value = 0;
+
+		pci_read_config_word(speedstep_chipset_dev, 
+				     0x00A0, &value);
+		if (!(value & 0x08)) {
+			value |= 0x08;
+			dprintk(KERN_DEBUG "cpufreq: activating SpeedStep (TM) registers\n");
+			pci_write_config_word(speedstep_chipset_dev, 
+					      0x00A0, value);
+		}
+
+		return 0;
+	}
+	}
+	
+	printk (KERN_ERR "cpufreq: SpeedStep (TM) on this chipset unsupported.\n");
+	return -EINVAL;
+}
+
+
+/**
+ * speedstep_detect_chipset - detect the Southbridge which contains SpeedStep logic
+ *
+ *   Detects PIIX4, ICH2-M and ICH3-M so far. The pci_dev points to 
+ * the LPC bridge / PM module which contains all power-management 
+ * functions. Returns the SPEEDSTEP_CHIPSET_-number for the detected
+ * chipset, or zero on failure.
+ */
+static unsigned int speedstep_detect_chipset (void)
+{
+	speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL,
+			      PCI_DEVICE_ID_INTEL_82801CA_12, 
+			      PCI_ANY_ID,
+			      PCI_ANY_ID,
+			      NULL);
+	if (speedstep_chipset_dev)
+		return SPEEDSTEP_CHIPSET_ICH3M;
+
+
+	speedstep_chipset_dev = pci_find_subsys(PCI_VENDOR_ID_INTEL,
+			      PCI_DEVICE_ID_INTEL_82801BA_10,
+			      PCI_ANY_ID,
+			      PCI_ANY_ID,
+			      NULL);
+	if (speedstep_chipset_dev) {
+		/* speedstep.c causes lockups on Dell Inspirons 8000 and
+		 * 8100 which use a pretty old revision of the 82815 
+		 * host brige. Abort on these systems.
+		 */
+		static struct pci_dev   *hostbridge;
+		u8			rev = 0;
+
+		hostbridge  = pci_find_subsys(PCI_VENDOR_ID_INTEL,
+			      PCI_DEVICE_ID_INTEL_82815_MC,
+			      PCI_ANY_ID,
+			      PCI_ANY_ID,
+			      NULL);
+
+		if (!hostbridge)
+			return SPEEDSTEP_CHIPSET_ICH2M;
+			
+		pci_read_config_byte(hostbridge, PCI_REVISION_ID, &rev);
+		if (rev < 5) {
+			dprintk(KERN_INFO "cpufreq: hostbrige does not support speedstep\n");
+			speedstep_chipset_dev = NULL;
+			return 0;
+		}
+
+		return SPEEDSTEP_CHIPSET_ICH2M;
+	}
+
+	return 0;
+}
+
+
+
+/*********************************************************************
+ *                   LOW LEVEL PROCESSOR INTERFACE                   *
+ *********************************************************************/
+
+
+/**
+ * pentium3_get_frequency - get the core frequencies for PIIIs
+ *
+ *   Returns the core frequency of a Pentium III processor (in kHz)
+ */
+static unsigned int pentium3_get_frequency (void)
+{
+        /* See table 14 of p3_ds.pdf and table 22 of 29834003.pdf */
+	struct {
+		unsigned int ratio;	/* Frequency Multiplier (x10) */
+		u8 bitmap;	        /* power on configuration bits
+					   [27, 25:22] (in MSR 0x2a) */
+	} msr_decode_mult [] = {
+		{ 30, 0x01 },
+		{ 35, 0x05 },
+		{ 40, 0x02 },
+		{ 45, 0x06 },
+		{ 50, 0x00 },
+		{ 55, 0x04 },
+		{ 60, 0x0b },
+		{ 65, 0x0f },
+		{ 70, 0x09 },
+		{ 75, 0x0d },
+		{ 80, 0x0a },
+		{ 85, 0x26 },
+		{ 90, 0x20 },
+		{ 100, 0x2b },
+		{ 0, 0xff }     /* error or unknown value */
+	};
+	/* PIII(-M) FSB settings: see table b1-b of 24547206.pdf */
+	struct {
+		unsigned int value;     /* Front Side Bus speed in MHz */
+		u8 bitmap;              /* power on configuration bits [18: 19]
+					   (in MSR 0x2a) */
+	} msr_decode_fsb [] = {
+		{  66, 0x0 },
+		{ 100, 0x2 },
+		{ 133, 0x1 },
+		{   0, 0xff}
+	};
+	u32     msr_lo, msr_tmp;
+	int     i = 0, j = 0;
+	struct  cpuinfo_x86 *c = cpu_data;
+
+	/* read MSR 0x2a - we only need the low 32 bits */
+	rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
+	dprintk(KERN_DEBUG "cpufreq: P3 - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
+	msr_tmp = msr_lo;
+
+	/* decode the FSB */
+	msr_tmp &= 0x00c0000;
+	msr_tmp >>= 18;
+	while (msr_tmp != msr_decode_fsb[i].bitmap) {
+		if (msr_decode_fsb[i].bitmap == 0xff)
+			return -EINVAL;
+		i++;
+	}
+
+	/* decode the multiplier */
+	if ((c->x86_model == 0x08) && (c->x86_mask == 0x01)) 
+                /* different on early Coppermine PIII */
+		msr_lo &= 0x03c00000;
+	else
+		msr_lo &= 0x0bc00000;
+	msr_lo >>= 22;
+	while (msr_lo != msr_decode_mult[j].bitmap) {
+		if (msr_decode_mult[j].bitmap == 0xff)
+			return -EINVAL;
+		j++;
+	}
+
+	return (msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100);
+}
+
+
+/**
+ * pentium4_get_frequency - get the core frequency for P4-Ms
+ *
+ *   Should return the core frequency (in kHz) for P4-Ms. 
+ */
+static unsigned int pentium4_get_frequency(void)
+{
+	u32 msr_lo, msr_hi;
+
+	rdmsr(0x2c, msr_lo, msr_hi);
+
+	dprintk(KERN_DEBUG "cpufreq: P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi);
+
+	/* First 12 bits seem to change a lot (0x511, 0x410 and 0x30f seen 
+	 * yet). Next 12 bits always seem to be 0x300. If this is not true 
+	 * on this CPU, complain. Last 8 bits are frequency (in 100MHz).
+	 */
+	if (msr_hi || ((msr_lo & 0x00FFF000) != 0x300000)) {
+		printk(KERN_DEBUG "cpufreq: P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi);
+		printk(KERN_INFO "cpufreq: problem in initialization. Please contact Dominik Brodowski\n");
+		printk(KERN_INFO "cpufreq: <linux@brodo.de> and attach this dmesg. Thanks in advance\n");
+		return 0;
+	}
+
+	msr_lo >>= 24;
+	return (msr_lo * 100000);
+}
+
+
+/** 
+ * speedstep_detect_processor - detect Intel SpeedStep-capable processors.
+ *
+ *   Returns the SPEEDSTEP_PROCESSOR_-number for the detected chipset, 
+ * or zero on failure.
+ */
+static unsigned int speedstep_detect_processor (void)
+{
+	struct cpuinfo_x86 *c = cpu_data;
+	u32                     ebx;
+
+	if ((c->x86_vendor != X86_VENDOR_INTEL) || 
+	    ((c->x86 != 6) && (c->x86 != 0xF)))
+		return 0;
+
+	if (c->x86 == 0xF) {
+		/* Intel Pentium 4 Mobile P4-M */
+		if (c->x86_model != 2)
+			return 0;
+
+		if (c->x86_mask != 4)
+			return 0;
+
+		ebx = cpuid_ebx(0x00000001);
+		ebx &= 0x000000FF;
+		if ((ebx != 0x0e) && (ebx != 0x0f))
+			return 0;
+
+		return SPEEDSTEP_PROCESSOR_P4M;
+	}
+
+	switch (c->x86_model) {
+	case 0x0B: /* Intel PIII [Tualatin] */
+		/* cpuid_ebx(1) is 0x04 for desktop PIII, 
+		                   0x06 for mobile PIII-M */
+		ebx = cpuid_ebx(0x00000001);
+
+		ebx &= 0x000000FF;
+		if (ebx != 0x06)
+			return 0;
+
+		/* So far all PIII-M processors support SpeedStep. See
+		 * Intel's 24540633.pdf of August 2002 
+		 */
+
+		return SPEEDSTEP_PROCESSOR_PIII_T;
+
+	case 0x08: /* Intel PIII [Coppermine] */
+		/* based on reverse-engineering information and
+		 * some guessing. HANDLE WITH CARE! */
+ 	        {
+			u32     msr_lo, msr_hi;
+
+			/* all mobile PIII Coppermines have FSB 100 MHz
+			 * ==> sort out a few desktop PIIIs. */
+			rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi);
+			dprintk(KERN_DEBUG "cpufreq: Coppermine: MSR_IA32_EBL_Cr_POWERON is 0x%x, 0x%x\n", msr_lo, msr_hi);
+			msr_lo &= 0x00c0000;
+			if (msr_lo != 0x0080000)
+				return 0;
+
+			/* platform ID seems to be 0x00140000 */
+			rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi);
+			dprintk(KERN_DEBUG "cpufreq: Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", msr_lo, msr_hi);
+			msr_hi = msr_lo & 0x001c0000;
+			if (msr_hi != 0x00140000)
+				return 0;
+
+			/* and these bits seem to be either 00_b, 01_b or
+			 * 10_b but never 11_b */
+			msr_lo &= 0x00030000;
+			if (msr_lo == 0x0030000)
+				return 0;
+
+			/* let's hope this is correct... */
+			return SPEEDSTEP_PROCESSOR_PIII_C;
+		}
+
+	default:
+		return 0;
+	}
+}
+
+
+
+/*********************************************************************
+ *                        HIGH LEVEL FUNCTIONS                       *
+ *********************************************************************/
+
+/**
+ * speedstep_detect_speeds - detects low and high CPU frequencies.
+ *
+ *   Detects the low and high CPU frequencies in kHz. Returns 0 on
+ * success or -EINVAL / -EIO on problems. 
+ */
+static int speedstep_detect_speeds (void)
+{
+	unsigned long   flags;
+	unsigned int    state;
+	int             i, result;
+
+	/* Disable irqs for entire detection process */
+	local_irq_save(flags);
+
+	for (i=0; i<2; i++) {
+		/* read the current state */
+		result = speedstep_get_state(&state);
+		if (result)
+			return result;
+
+		/* save the correct value, and switch to other */
+		if (state == SPEEDSTEP_LOW) {
+			switch (speedstep_processor) {
+			case SPEEDSTEP_PROCESSOR_PIII_C:
+			case SPEEDSTEP_PROCESSOR_PIII_T:
+				speedstep_low_freq = pentium3_get_frequency();
+				break;
+			case SPEEDSTEP_PROCESSOR_P4M:
+				speedstep_low_freq = pentium4_get_frequency();
+			}
+			speedstep_set_state(SPEEDSTEP_HIGH, 0);
+		} else {
+			switch (speedstep_processor) {
+			case SPEEDSTEP_PROCESSOR_PIII_C:
+			case SPEEDSTEP_PROCESSOR_PIII_T:
+				speedstep_high_freq = pentium3_get_frequency();
+				break;
+			case SPEEDSTEP_PROCESSOR_P4M:
+				speedstep_high_freq = pentium4_get_frequency();
+			}
+			speedstep_set_state(SPEEDSTEP_LOW, 0);
+		}
+	}
+
+	local_irq_restore(flags);
+
+	if (!speedstep_low_freq || !speedstep_high_freq || 
+	    (speedstep_low_freq == speedstep_high_freq))
+		return -EIO;
+
+	return 0;
+}
+
+
+/**
+ * speedstep_setpolicy - set a new CPUFreq policy
+ * @policy: new policy
+ *
+ * Sets a new CPUFreq policy.
+ */
+static void speedstep_setpolicy (struct cpufreq_policy *policy)
+{
+	if (!speedstep_driver || !policy)
+		return;
+
+	if (policy->min > speedstep_low_freq) 
+		speedstep_set_state(SPEEDSTEP_HIGH, 1);
+	else {
+		if (policy->max < speedstep_high_freq)
+			speedstep_set_state(SPEEDSTEP_LOW, 1);
+		else {
+			/* both frequency states are allowed */
+			if (policy->policy == CPUFREQ_POLICY_POWERSAVE)
+				speedstep_set_state(SPEEDSTEP_LOW, 1);
+			else
+				speedstep_set_state(SPEEDSTEP_HIGH, 1);
+		}
+	}
+}
+
+
+/**
+ * speedstep_verify - verifies a new CPUFreq policy
+ * @freq: new policy
+ *
+ * Limit must be within speedstep_low_freq and speedstep_high_freq, with
+ * at least one border included.
+ */
+static void speedstep_verify (struct cpufreq_policy *policy)
+{
+	if (!policy || !speedstep_driver || 
+	    !speedstep_low_freq || !speedstep_high_freq)
+		return;
+
+	policy->cpu = 0; /* UP only */
+
+	cpufreq_verify_within_limits(policy, speedstep_low_freq, speedstep_high_freq);
+
+	if ((policy->min > speedstep_low_freq) && 
+	    (policy->max < speedstep_high_freq))
+		policy->max = speedstep_high_freq;
+	
+	return;
+}
+
+
+/**
+ * speedstep_init - initializes the SpeedStep CPUFreq driver
+ *
+ *   Initializes the SpeedStep support. Returns -ENODEV on unsupported
+ * devices, -EINVAL on problems during initiatization, and zero on
+ * success.
+ */
+static int __init speedstep_init(void)
+{
+	int                     result;
+	unsigned int            speed;
+	struct cpufreq_driver   *driver;
+
+
+	/* detect chipset */
+	speedstep_chipset = speedstep_detect_chipset();
+
+	/* detect chipset */
+	if (speedstep_chipset)
+		speedstep_processor = speedstep_detect_processor();
+
+	if ((!speedstep_chipset) || (!speedstep_processor)) {
+		dprintk(KERN_INFO "cpufreq: Intel(R) SpeedStep(TM) for this %s not (yet) available.\n", speedstep_processor ? "chipset" : "processor");
+		return -ENODEV;
+	}
+
+	dprintk(KERN_INFO "cpufreq: Intel(R) SpeedStep(TM) support $Revision: 1.53 $\n");
+	dprintk(KERN_DEBUG "cpufreq: chipset 0x%x - processor 0x%x\n", 
+	       speedstep_chipset, speedstep_processor);
+
+	/* activate speedstep support */
+	result = speedstep_activate();
+	if (result)
+		return result;
+
+	/* detect low and high frequency */
+	result = speedstep_detect_speeds();
+	if (result)
+		return result;
+
+	/* get current speed setting */
+	result = speedstep_get_state(&speed);
+	if (result)
+		return result;
+
+	speed = (speed == SPEEDSTEP_LOW) ? speedstep_low_freq : speedstep_high_freq;
+
+	dprintk(KERN_INFO "cpufreq: currently at %s speed setting - %i MHz\n", 
+	       (speed == speedstep_low_freq) ? "low" : "high",
+	       (speed / 1000));
+
+	/* initialization of main "cpufreq" code*/
+	driver = kmalloc(sizeof(struct cpufreq_driver) + 
+			 NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL);
+	if (!driver)
+		return -ENOMEM;
+
+	driver->policy = (struct cpufreq_policy *) (driver + 1);
+
+#ifdef CONFIG_CPU_FREQ_24_API
+	driver->cpu_min_freq    = speedstep_low_freq;
+	driver->cpu_cur_freq[0] = speed;
+#endif
+
+	driver->verify      = &speedstep_verify;
+	driver->setpolicy   = &speedstep_setpolicy;
+
+	driver->policy[0].cpu    = 0;
+	driver->policy[0].min    = speedstep_low_freq;
+	driver->policy[0].max    = speedstep_high_freq;
+	driver->policy[0].max_cpu_freq = speedstep_high_freq;
+	driver->policy[0].policy = (speed == speedstep_low_freq) ? 
+	    CPUFREQ_POLICY_POWERSAVE : CPUFREQ_POLICY_PERFORMANCE;
+
+	result = cpufreq_register(driver);
+	if (result) {
+		kfree(driver);
+		return result;
+	}
+	speedstep_driver = driver;
+
+	return 0;
+}
+
+
+/**
+ * speedstep_exit - unregisters SpeedStep support
+ *
+ *   Unregisters SpeedStep support.
+ */
+static void __exit speedstep_exit(void)
+{
+	if (speedstep_driver) {
+		cpufreq_unregister();
+		kfree(speedstep_driver);
+	}
+}
+
+
+MODULE_AUTHOR ("Dave Jones <davej@suse.de>, Dominik Brodowski <linux@brodo.de>");
+MODULE_DESCRIPTION ("Speedstep driver for Intel mobile processors.");
+MODULE_LICENSE ("GPL");
+module_init(speedstep_init);
+module_exit(speedstep_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/time.c linux.20pre10-ac2/arch/i386/kernel/time.c
--- linux.20pre10/arch/i386/kernel/time.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/time.c	2002-09-30 17:24:56.000000000 +0100
@@ -42,6 +42,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/smp.h>
+#include <linux/cpufreq.h>
 
 #include <asm/io.h>
 #include <asm/smp.h>
@@ -637,6 +638,51 @@
 	return 0;
 }
 
+#ifdef CONFIG_CPU_FREQ
+
+static int
+time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
+		       void *data)
+{
+	struct cpufreq_freqs *freq = data;
+	unsigned int i;
+
+	if (!cpu_has_tsc)
+		return 0;
+
+	switch (val) {
+	case CPUFREQ_PRECHANGE:
+		if ((freq->old < freq->new) &&
+		((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == 0)))  {
+			cpu_khz = cpufreq_scale(cpu_khz, freq->old, freq->new);
+		        fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_quotient, freq->new, freq->old);
+		}
+		for (i=0; i<NR_CPUS; i++)
+			if ((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == i))
+				cpu_data[i].loops_per_jiffy = cpufreq_scale(cpu_data[i].loops_per_jiffy, freq->old, freq->new);
+		break;
+
+	case CPUFREQ_POSTCHANGE:
+		if ((freq->new < freq->old) &&
+		((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == 0)))  {
+			cpu_khz = cpufreq_scale(cpu_khz, freq->old, freq->new);
+		        fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_quotient, freq->new, freq->old);
+		}
+		for (i=0; i<NR_CPUS; i++)
+			if ((freq->cpu == CPUFREQ_ALL_CPUS) || (freq->cpu == i))
+				cpu_data[i].loops_per_jiffy = cpufreq_scale(cpu_data[i].loops_per_jiffy, freq->old, freq->new);
+		break;
+	}
+
+	return 0;
+}
+
+static struct notifier_block time_cpufreq_notifier_block = {
+	notifier_call:	time_cpufreq_notifier
+};
+#endif
+
+
 void __init time_init(void)
 {
 	extern int x86_udelay_tsc;
@@ -669,51 +715,64 @@
  	 *	moaned if you have the only one in the world - you fix it!
  	 */
  
- 	dodgy_tsc();
- 	
-	if (cpu_has_tsc) {
-		unsigned long tsc_quotient = calibrate_tsc();
-		if (tsc_quotient) {
-			fast_gettimeoffset_quotient = tsc_quotient;
-			use_tsc = 1;
-			/*
-			 *	We could be more selective here I suspect
-			 *	and just enable this for the next intel chips ?
-			 */
-			x86_udelay_tsc = 1;
+	switch (select_tsc()) 
+	{
+		case TSC_NONE:
+			setup_irq(0, &irq0);
+			break;
+		case TSC_CPU:
+		{
+			unsigned long tsc_quotient = calibrate_tsc();
+			if (tsc_quotient) {
+				fast_gettimeoffset_quotient = tsc_quotient;
+				use_tsc = 1;
+				/*
+				 *	We could be more selective here I suspect
+				 *	and just enable this for the next intel chips ?
+				 */
+				x86_udelay_tsc = 1;
 #ifndef do_gettimeoffset
-			do_gettimeoffset = do_fast_gettimeoffset;
+				do_gettimeoffset = do_fast_gettimeoffset;
 #endif
 
-			/* report CPU clock rate in Hz.
-			 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
-			 * clock/second. Our precision is about 100 ppm.
-			 */
-			{	unsigned long eax=0, edx=1000;
-				__asm__("divl %2"
-		       		:"=a" (cpu_khz), "=d" (edx)
-        	       		:"r" (tsc_quotient),
-	                	"0" (eax), "1" (edx));
-				printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000);
+				/* report CPU clock rate in Hz.
+				 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
+				 * clock/second. Our precision is about 100 ppm.
+				 */
+				{	unsigned long eax=0, edx=1000;
+					__asm__("divl %2"
+			       		:"=a" (cpu_khz), "=d" (edx)
+	        	       		:"r" (tsc_quotient),
+		                	"0" (eax), "1" (edx));
+					printk("Detected %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000);
+				}
+#ifdef CONFIG_CPU_FREQ
+			cpufreq_register_notifier(&time_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
+#endif
 			}
+			setup_irq(0, &irq0);
+			break;
 		}
-	}
-
+		case TSC_CYCLONE:
+			/* To be added */
+			setup_irq(0, &irq0);
+			break;
 #ifdef CONFIG_VISWS
-	printk("Starting Cobalt Timer system clock\n");
+		case TSC_VISWS:
+			printk("Starting Cobalt Timer system clock\n");
 
-	/* Set the countdown value */
-	co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ);
+			/* Set the countdown value */
+			co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ);
 
-	/* Start the timer */
-	co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN);
+			/* Start the timer */
+			co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN);
 
-	/* Enable (unmask) the timer interrupt */
-	co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK);
+			/* Enable (unmask) the timer interrupt */
+			co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK);
 
-	/* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */
-	setup_irq(CO_IRQ_TIMER, &irq0);
-#else
-	setup_irq(0, &irq0);
+			/* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */
+			setup_irq(CO_IRQ_TIMER, &irq0);
+			break;
 #endif
+	}
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/kernel/traps.c linux.20pre10-ac2/arch/i386/kernel/traps.c
--- linux.20pre10/arch/i386/kernel/traps.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/kernel/traps.c	2002-08-13 14:05:33.000000000 +0100
@@ -284,6 +284,20 @@
 
 void die(const char * str, struct pt_regs * regs, long err)
 {
+#ifdef CONFIG_PNPBIOS		
+	if (regs->xcs == 0x60 || regs->xcs == 0x68)
+	{
+		extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp;
+		extern u32 pnp_bios_is_utter_crap;
+		pnp_bios_is_utter_crap = 1;
+		printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n");
+		__asm__ volatile(
+			"movl %0, %%esp\n\t"
+			"jmp %1\n\t"
+			: "=a" (pnp_bios_fault_esp), "=b" (pnp_bios_fault_eip));
+		panic("do_trap: can't hit this");
+	}
+#endif	
 	console_verbose();
 	spin_lock_irq(&die_lock);
 	bust_spinlocks(1);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/Makefile linux.20pre10-ac2/arch/i386/Makefile
--- linux.20pre10/arch/i386/Makefile	2002-10-09 21:36:57.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/Makefile	2002-09-30 17:45:01.000000000 +0100
@@ -83,7 +83,7 @@
 endif
 
 ifdef CONFIG_MCYRIXIII
-CFLAGS += -march=i586
+CFLAGS += -march=i486 -malign-functions=0 -malign-jumps=0 -malign-loops=0
 endif
 
 HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/math-emu/fpu_system.h linux.20pre10-ac2/arch/i386/math-emu/fpu_system.h
--- linux.20pre10/arch/i386/math-emu/fpu_system.h	2002-10-09 21:36:57.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/math-emu/fpu_system.h	2002-09-02 14:57:05.000000000 +0100
@@ -20,7 +20,7 @@
    of the stack frame of math_emulate() */
 #define SETUP_DATA_AREA(arg)	FPU_info = (struct info *) &arg
 
-#define LDT_DESCRIPTOR(s)	(((struct desc_struct *)current->mm->context.segments)[(s) >> 3])
+#define LDT_DESCRIPTOR(s)	(((struct desc_struct *)current->mm->context.ldt)[(s) >> 3])
 #define SEG_D_SIZE(x)		((x).b & (3 << 21))
 #define SEG_G_BIT(x)		((x).b & (1 << 23))
 #define SEG_GRANULARITY(x)	(((x).b & (1 << 23)) ? 4096 : 1)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/i386/mm/fault.c linux.20pre10-ac2/arch/i386/mm/fault.c
--- linux.20pre10/arch/i386/mm/fault.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/i386/mm/fault.c	2002-08-29 19:00:49.000000000 +0100
@@ -76,9 +76,7 @@
 	return 1;
 
 check_stack:
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		goto bad_area;
-	if (expand_stack(vma, start) == 0)
+	if (!expand_stack(vma, start))
 		goto good_area;
 
 bad_area:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/ia64/ia32/sys_ia32.c linux.20pre10-ac2/arch/ia64/ia32/sys_ia32.c
--- linux.20pre10/arch/ia64/ia32/sys_ia32.c	2002-10-09 21:37:03.000000000 +0100
+++ linux.20pre10-ac2/arch/ia64/ia32/sys_ia32.c	2002-08-06 15:42:21.000000000 +0100
@@ -3693,7 +3693,11 @@
 	return result;
 }
 
-struct dqblk32 {
+extern asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
+
+#ifdef CONFIG_QIFACE_COMPAT
+#ifdef CONFIG_QIFACE_V1
+struct user_dqblk32 {
 	__u32 dqb_bhardlimit;
 	__u32 dqb_bsoftlimit;
 	__u32 dqb_curblocks;
@@ -3703,49 +3707,82 @@
 	__kernel_time_t32 dqb_btime;
 	__kernel_time_t32 dqb_itime;
 };
+typedef struct v1c_mem_dqblk comp_dqblk_t;
 
-asmlinkage long
-sys32_quotactl (int cmd, unsigned int special, int id, struct dqblk32 *addr)
+#define Q_COMP_GETQUOTA Q_V1_GETQUOTA
+#define Q_COMP_SETQUOTA Q_V1_SETQUOTA
+#define Q_COMP_SETQLIM Q_V1_SETQLIM
+#define Q_COMP_SETUSE Q_V1_SETUSE
+#else
+struct user_dqblk32 {
+	__u32 dqb_ihardlimit;
+	__u32 dqb_isoftlimit;
+	__u32 dqb_curinodes;
+	__u32 dqb_bhardlimit;
+	__u32 dqb_bsoftlimit;
+	__u64 dqb_curspace;
+	__kernel_time_t32 dqb_btime;
+	__kernel_time_t32 dqb_itime;
+};
+typedef struct v2c_mem_dqblk comp_dqblk_t;
+
+#define Q_COMP_GETQUOTA Q_V2_GETQUOTA
+#define Q_COMP_SETQUOTA Q_V2_SETQUOTA
+#define Q_COMP_SETQLIM Q_V2_SETQLIM
+#define Q_COMP_SETUSE Q_V2_SETUSE
+#endif
+
+asmlinkage long sys32_quotactl(int cmd, const char *special, int id, caddr_t addr)
 {
-	extern asmlinkage long sys_quotactl (int, const char *, int, caddr_t);
 	int cmds = cmd >> SUBCMDSHIFT;
+	long err;
+	comp_dqblk_t d;
 	mm_segment_t old_fs;
-	struct dqblk d;
 	char *spec;
-	long err;
-
+	
 	switch (cmds) {
-	      case Q_GETQUOTA:
-		break;
-	      case Q_SETQUOTA:
-	      case Q_SETUSE:
-	      case Q_SETQLIM:
-		if (copy_from_user (&d, addr, sizeof(struct dqblk32)))
-			return -EFAULT;
-		d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
-		d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
-		break;
-	      default:
-		return sys_quotactl(cmd, (void *) A(special), id, (caddr_t) addr);
+		case Q_COMP_GETQUOTA:
+			break;
+		case Q_COMP_SETQUOTA:
+		case Q_COMP_SETUSE:
+		case Q_COMP_SETQLIM:
+			if (copy_from_user(&d, (struct user_dqblk32 *)addr,
+					    sizeof (struct user_dqblk32)))
+				return -EFAULT;
+			d.dqb_itime = ((struct user_dqblk32 *)&d)->dqb_itime;
+			d.dqb_btime = ((struct user_dqblk32 *)&d)->dqb_btime;
+			break;
+	default:
+		return sys_quotactl(cmd, special, id, (__kernel_caddr_t)addr);
 	}
-	spec = getname32((void *) A(special));
+	spec = getname (special);
 	err = PTR_ERR(spec);
-	if (IS_ERR(spec))
+	if (IS_ERR(spec)) return err;
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_quotactl(cmd, (const char *)spec, id, (__kernel_caddr_t)&d);
+	set_fs (old_fs);
+	putname (spec);
+	if (err)
 		return err;
-	old_fs = get_fs ();
-	set_fs(KERNEL_DS);
-	err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d);
-	set_fs(old_fs);
-	putname(spec);
-	if (cmds == Q_GETQUOTA) {
+	if (cmds == Q_COMP_GETQUOTA) {
 		__kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
-		((struct dqblk32 *)&d)->dqb_itime = i;
-		((struct dqblk32 *)&d)->dqb_btime = b;
-		if (copy_to_user(addr, &d, sizeof(struct dqblk32)))
+		((struct user_dqblk32 *)&d)->dqb_itime = i;
+		((struct user_dqblk32 *)&d)->dqb_btime = b;
+		if (copy_to_user ((struct user_dqblk32 *)addr, &d,
+				  sizeof (struct user_dqblk32)))
 			return -EFAULT;
 	}
-	return err;
+	return 0;
+}
+
+#else
+/* No conversion needed for new interface */
+asmlinkage long sys32_quotactl(int cmd, const char *special, int id, caddr_t addr)
+{
+	return sys_quotactl(cmd, special, id, addr);
 }
+#endif
 
 asmlinkage long
 sys32_sched_rr_get_interval (pid_t pid, struct timespec32 *interval)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/ia64/kernel/irq.c linux.20pre10-ac2/arch/ia64/kernel/irq.c
--- linux.20pre10/arch/ia64/kernel/irq.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/ia64/kernel/irq.c	2002-09-14 22:05:38.000000000 +0100
@@ -193,7 +193,7 @@
 	p += sprintf(p, "LOC: ");
 	for (j = 0; j < smp_num_cpus; j++)
 		p += sprintf(p, "%10u ",
-			apic_timer_irqs[cpu_logical_map(j)]);
+			irq_stat[cpu_logical_map(j)].apic_timer_irqs);
 	p += sprintf(p, "\n");
 #endif
 	p += sprintf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/ia64/mm/fault.c linux.20pre10-ac2/arch/ia64/mm/fault.c
--- linux.20pre10/arch/ia64/mm/fault.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/ia64/mm/fault.c	2002-09-14 22:06:47.000000000 +0100
@@ -129,8 +129,6 @@
 
   check_expansion:
 	if (!(prev_vma && (prev_vma->vm_flags & VM_GROWSUP) && (address == prev_vma->vm_end))) {
-		if (!(vma->vm_flags & VM_GROWSDOWN))
-			goto bad_area;
 		if (rgn_index(address) != rgn_index(vma->vm_start)
 		    || rgn_offset(address) >= RGN_MAP_LIMIT)
 			goto bad_area;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/mips/mm/fault.c linux.20pre10-ac2/arch/mips/mm/fault.c
--- linux.20pre10/arch/mips/mm/fault.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/mips/mm/fault.c	2002-08-29 19:00:49.000000000 +0100
@@ -111,8 +111,6 @@
 		goto bad_area;
 	if (vma->vm_start <= address)
 		goto good_area;
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		goto bad_area;
 	if (expand_stack(vma, address))
 		goto bad_area;
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/mips64/mm/fault.c linux.20pre10-ac2/arch/mips64/mm/fault.c
--- linux.20pre10/arch/mips64/mm/fault.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/mips64/mm/fault.c	2002-09-14 22:10:21.000000000 +0100
@@ -135,8 +135,6 @@
 		goto bad_area;
 	if (vma->vm_start <= address)
 		goto good_area;
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		goto bad_area;
 	if (expand_stack(vma, address))
 		goto bad_area;
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/parisc/kernel/entry.S linux.20pre10-ac2/arch/parisc/kernel/entry.S
--- linux.20pre10/arch/parisc/kernel/entry.S	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/parisc/kernel/entry.S	2002-09-18 12:28:20.000000000 +0100
@@ -498,7 +498,6 @@
 	.import		handle_real_interruption,code
 	.import		do_cpu_irq_mask,code
 	.import		parisc_stopkernel,code
-	.import		cpu_irq_region,data
 
 	/*
 	 * r26 = function to be called
@@ -815,7 +814,7 @@
 	 */
 
 intr_extint:
-	CMPIB=,n 0,%r16,1f
+	CMPIB=,n 0,%r16,1f	/* on User or kernel stack? */
 	get_stack_use_cr30
 	b,n 3f
 
@@ -846,29 +845,17 @@
 	
 	loadgp
 
-	copy	%r29, %r25	/* arg1 is pt_regs */
+	copy	%r29, %r26	/* arg0 is pt_regs */
 	copy	%r29, %r16	/* save pt_regs */
-#ifdef CONFIG_KWDB
-	copy	%r29, %r3	/* KWDB - update frame pointer (gr3) */
-#endif
-
+	ldil	L%intr_return, %r2
 #ifdef __LP64__
 	ldo	-16(%r30),%r29	/* Reference param save area */
-#else
-	nop
 #endif
-	
-	/*
-	 * We need to either load the CPU's ID or IRQ region.
-	 * Until we have "per CPU" IRQ regions, this is easy.
-	 */
-	ldil	L%cpu_irq_region, %r26
-	ldil	L%intr_return, %r2
-	ldo	R%cpu_irq_region(%r26), %r26
-	
 	b	do_cpu_irq_mask
 	ldo	R%intr_return(%r2), %r2	/* return to intr_return, not here */
 
+
+
 	/* Generic interruptions (illegal insn, unaligned, page fault, etc) */
 
 	.export         intr_save, code /* for os_hpmc */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/parisc/kernel/irq.c linux.20pre10-ac2/arch/parisc/kernel/irq.c
--- linux.20pre10/arch/parisc/kernel/irq.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/parisc/kernel/irq.c	2002-09-18 12:28:20.000000000 +0100
@@ -104,24 +104,35 @@
 	set_eiem(cpu_eiem);
 }
 
-static struct irqaction cpu_irq_actions[IRQ_PER_REGION] = {
+/*
+ * XXX cpu_irq_actions[] will become 2 dimensional for per CPU EIR support.
+ * correspond changes needed in:
+ * 	processor_probe()	initialize additional action arrays
+ * 	request_irq()		handle CPU IRQ region specially
+ * 	do_cpu_irq_mask()	index into the matching irq_action array.
+ */
+struct irqaction cpu_irq_actions[IRQ_PER_REGION] = {
 	[IRQ_OFFSET(TIMER_IRQ)] { handler: timer_interrupt, name: "timer", },
 #ifdef CONFIG_SMP
 	[IRQ_OFFSET(IPI_IRQ)]	{ handler: ipi_interrupt,   name: "IPI", },
 #endif
 };
 
-struct irq_region cpu_irq_region = {
+struct irq_region_ops cpu_irq_ops = {
+	disable_cpu_irq, enable_cpu_irq, unmask_cpu_irq, unmask_cpu_irq
+};
+
+struct irq_region cpu0_irq_region = {
 	ops:	{ disable_cpu_irq, enable_cpu_irq, unmask_cpu_irq, unmask_cpu_irq },
 	data:	{ dev: &cpu_data[0],
-		  name: "PA-CPU-00",
+		  name: "PARISC-CPU",
 		  irqbase: IRQ_FROM_REGION(CPU_IRQ_REGION), },
 	action:	cpu_irq_actions,
 };
 
 struct irq_region *irq_region[NR_IRQ_REGS] = {
 	[ 0 ]              NULL, /* reserved for EISA, else causes data page fault (aka code 15) */
-	[ CPU_IRQ_REGION ] &cpu_irq_region,
+	[ CPU_IRQ_REGION ] &cpu0_irq_region,
 };
 
 
@@ -190,13 +201,14 @@
 {
 #ifdef CONFIG_PROC_FS
 	char *p = buf;
-	unsigned int regnr = 0;
+	unsigned int regnr;
 
 	p += sprintf(p, "     ");
 #ifdef CONFIG_SMP
-	for (; regnr < smp_num_cpus; regnr++)
+	for (regnr = 0; regnr < smp_num_cpus; regnr++)
 #endif
-		p += sprintf(p, "      CPU%d ", regnr);
+		p += sprintf(p, "     CPU%02d ", regnr);
+
 
 #ifdef PARISC_IRQ_CR16_COUNTS
 	p += sprintf(p, "[min/avg/max] (CPU cycle counts)");
@@ -210,6 +222,9 @@
 	for (regnr = 0; regnr < NR_IRQ_REGS; regnr++) {
 	    unsigned int i;
 	    struct irq_region *region = irq_region[regnr];
+#ifdef CONFIG_SMP
+	    unsigned int j;
+#endif
 
             if (!region || !region->action)
 		continue;
@@ -217,9 +232,6 @@
 	    for (i = 0; i <= MAX_CPU_IRQ; i++) {
 		struct irqaction *action = &region->action[i];
 		unsigned int irq_no = IRQ_FROM_REGION(regnr) + i;
-#ifdef CONFIG_SMP
-		unsigned int j;
-#endif
 
 		if (!action->handler)
 			continue;
@@ -229,11 +241,12 @@
 		p += sprintf(p, "%10u ", kstat_irqs(irq_no));
 #else
 		for (j = 0; j < smp_num_cpus; j++)
-		    p += sprintf(p, "%10u ",
-			    kstat.irqs[cpu_logical_map(j)][irq_no]);
+			p += sprintf(p, "%10u ",
+				kstat.irqs[j][regnr][i]);
 #endif
 		p += sprintf(p, " %14s",
 			    region->data.name ? region->data.name : "N/A");
+
 #ifndef PARISC_IRQ_CR16_COUNTS
 		p += sprintf(p, "  %s", action->name);
 
@@ -295,7 +308,7 @@
 
 	/* never return irq 0 cause that's the interval timer */
 	for (irq = 1; irq <= MAX_CPU_IRQ; irq++) {
-		if (cpu_irq_region.action[irq].handler == NULL) {
+		if (cpu_irq_actions[irq].handler == NULL) {
 			return (IRQ_FROM_REGION(CPU_IRQ_REGION) + irq);
 		}
 	}
@@ -317,14 +330,18 @@
 unsigned long
 txn_alloc_addr(int virt_irq)
 {
-	struct cpuinfo_parisc *dev = (struct cpuinfo_parisc *) (irq_region[IRQ_REGION(virt_irq)]->data.dev);
+	static int next_cpu = -1;
 
-	if (!dev) {
-		printk(KERN_ERR "txn_alloc_addr(0x%x): CPU IRQ region? dev %p\n",
-			virt_irq,dev);
-		return 0;
-	}
-	return (dev->txn_addr);
+	next_cpu++; /* assign to "next" CPU we want this bugger on */
+
+	/* validate entry */
+	while ((next_cpu < NR_CPUS) && !cpu_data[next_cpu].txn_addr)
+		next_cpu++;
+
+	if (next_cpu >= NR_CPUS) 
+		next_cpu = 0;	/* nothing else, assign monarch */
+
+	return cpu_data[next_cpu].txn_addr;
 }
 
 
@@ -368,7 +385,7 @@
 	int cpu = smp_processor_id();
 
 	irq_enter(cpu, irq);
-	++kstat.irqs[IRQ_REGION(irq)][IRQ_OFFSET(irq)];
+	++kstat.irqs[cpu][IRQ_REGION(irq)][IRQ_OFFSET(irq)];
 
 	DBG_IRQ(irq, ("do_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq)));
 
@@ -410,7 +427,7 @@
 
 
 /* ONLY called from entry.S:intr_extint() */
-void do_cpu_irq_mask(struct irq_region *region, struct pt_regs *regs)
+void do_cpu_irq_mask(struct pt_regs *regs)
 {
 	unsigned long eirr_val;
 	unsigned int i=3;	/* limit time in interrupt context */
@@ -434,7 +451,7 @@
 	 */
 	while ((eirr_val = (mfctl(23) & cpu_eiem)) && --i) {
 		unsigned long bit = (1UL<<MAX_CPU_IRQ);
-		unsigned int irq = 0;
+		unsigned int irq;
 
 		mtctl(eirr_val, 23); /* reset bits we are going to process */
 
@@ -443,17 +460,15 @@
 			printk(KERN_DEBUG "do_cpu_irq_mask  %x\n", eirr_val);
 #endif
 
-		for (; eirr_val && bit; bit>>=1, irq++)
+		for (irq = 0; eirr_val && bit; bit>>=1, irq++)
 		{
-			unsigned int irq_num;
 			if (!(bit&eirr_val))
 				continue;
 
 			/* clear bit in mask - can exit loop sooner */
 			eirr_val &= ~bit;
 
-			irq_num = region->data.irqbase + irq;
-			do_irq(&region->action[irq], irq_num, regs);
+			do_irq(&cpu_irq_actions[irq], TIMER_IRQ+irq, regs);
 		}
 	}
 	set_eiem(cpu_eiem);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/parisc/kernel/lasimap.map linux.20pre10-ac2/arch/parisc/kernel/lasimap.map
--- linux.20pre10/arch/parisc/kernel/lasimap.map	2002-10-09 21:37:03.000000000 +0100
+++ linux.20pre10-ac2/arch/parisc/kernel/lasimap.map	1970-01-01 01:00:00.000000000 +0100
@@ -1,322 +0,0 @@
-# HP 712 kernel keymap. This uses 7 modifier combinations.
-
-keymaps 0-2,4-5,8,12
-# ie, plain,  Shift,  AltGr,  Control, Control+Shift, Alt and Control+Alt
-
-
-# Change the above line into
-#	keymaps 0-2,4-6,8,12
-# in case you want the entries
-#	altgr   control keycode  83 = Boot            
-#	altgr   control keycode 111 = Boot            
-# below.
-#
-# In fact AltGr is used very little, and one more keymap can
-# be saved by mapping AltGr to Alt (and adapting a few entries):
-# keycode 100 = Alt
-#
-keycode   1 = F9	F19	Console_21
-	control	keycode	1 = F9
-	alt	keycode	1 = Console_9
-	control	alt	keycode	1 = Console_9
-keycode   2 =
-keycode   3 = F5	F15	Console_17
-	control	keycode	3 = F5
-	alt	keycode	3 = Console_5
-	control	alt	keycode	3 = Console_5
-keycode   4 = F3	F13	Console_15
-	control	keycode	4 = F3
-	alt	keycode	4 = Console_3
-	control	alt	keycode	4 = Console_3
-keycode   5 = F1	F11	Console_13
-	control	keycode	5 = F1
-	alt	keycode	5 = Console_1
-	control	alt	keycode	5 = Console_1
-keycode   6 = F2	F12	Console_14
-	control	keycode	6 = F2
-	alt	keycode	6 = Console_2
-	control	alt	keycode	6 = Console_2
-keycode   7 = F12	F12	Console_24
-	control	keycode	7 = F12
-	alt	keycode	7 = Console_12
-	control	alt	keycode	7 = Console_12
-keycode   8 = 
-keycode   9 = F10	F20	Console_22
-	control	keycode	9 = F10
-	alt	keycode	9 = Console_10
-	control	alt	keycode	9 = Console_10
-keycode  10 = F8	F18	Console_20
-	control	keycode	10 = F8
-	alt	keycode	10 = Console_8
-	control	alt	keycode	10 = Console_8
-keycode  11 = F6	F16	Console_18
-	control	keycode	11 = F6
-	alt	keycode	11 = Console_6
-	control	alt	keycode	11 = Console_6
-keycode  12 = F4	F14	Console_16
-	control	keycode	12 = F4
-	alt	keycode	12 = Console_4
-	control	alt	keycode 12 = Console_4
-keycode  13 = Tab	Tab
-	alt	keycode	13 = Meta_Tab
-keycode  14 = grave	asciitilde
-	control	keycode	14 = nul
-	alt	keycode	14 = Meta_grave
-keycode  15 = 
-keycode  16 =
-keycode  17 = Alt
-keycode  18 = Shift
-keycode  19 =
-keycode  20 = Control
-keycode  21 = q
-keycode  22 = one	exclam	exclam
-keycode  23 =
-keycode  24 =
-keycode  25 =
-keycode  26 = z
-keycode  27 = s
-keycode  28 = a
-	altgr	keycode	28 = Hex_A
-keycode  29 = w
-keycode  30 = two	at	at
-keycode  31 =
-keycode  32 =
-keycode  33 = c
-	altgr	keycode	46 = Hex_C
-keycode  34 = x
-keycode  35 = d
-	altgr	keycode 35 = Hex_D
-keycode  36 = e
-	altgr	keycode	36 = Hex_E
-keycode  37 = four	dollar
-keycode  38 = three	numbersign
-keycode  39 =
-keycode  40 =
-keycode  41 =
-keycode  42 = v
-keycode  43 = f
-	 altgr	keycode 43 = Hex_F
-keycode  44 = t
-keycode  45 = r
-keycode  46 = five	percent
-keycode  47 =
-keycode  48 =
-keycode  49 = n
-keycode  50 = b
-	altgr	keycode	50 = Hex_B
-keycode  51 = h
-keycode  52 = g
-keycode  53 = y
-keycode  54 = six	asciicircum
-keycode  55 =
-keycode  56 =
-keycode  57 =
-keycode  58 = m
-keycode  59 = j
-keycode  60 = u
-keycode  61 = seven	ampersand
-keycode  62 = eight	asterisk	asterisk
-keycode  63 =
-keycode  64 =        
-keycode  65 = comma	less
-	alt	keycode	65 = Meta_comma
-keycode  66 = k
-keycode  67 = i
-keycode  68 = o
-keycode  69 = zero	parenright	bracketright
-keycode  70 = nine	parenleft	bracketleft
-keycode  71 = 
-keycode  72 =
-keycode  73 = period	greater
-	control	keycode	73 = Compose
-	alt	keycode	73 = Meta_period
-keycode  74 = slash	question
-	control	keycode 74 = Delete
-	alt	keycode 53 = Meta_slash
-keycode  75 = l
-keycode  76 = semicolon	colon
-	alt	keycode	39 = Meta_semicolon
-keycode  77 = p
-keycode  78 = minus	underscore
-keycode  79 =
-keycode  80 =
-keycode  81 =
-keycode  82 = apostrophe	quotedbl
-	control	keycode	82 = Control_g
-	alt	keycode	40 = Meta_apostrophe
-keycode  83 =
-keycode  84 = bracketleft	braceleft
-	control	keycode	84 = Escape
-	alt	keycode	26 = Meta_bracketleft
-keycode  85 = equal	plus
-keycode  86 = 
-keycode  87 = 
-keycode  88 = Caps_Lock
-keycode  88 =
-keycode  89 =
-keycode  89 =
-keycode  89 =
-keycode  90 = Return
-	 alt  keycode	90 = Meta_Control_m
-keycode  91 = bracketright	braceright	asciitilde
-	control	keycode	91 = Control_bracketright
-	alt	keycode	91 = Meta_bracketright
-keycode  92 =
-keycode  93 = backslash		bar
-	control	keycode	43 = Control_backslash
-	alt	keycode	43 = Meta_backslash
-keycode  94 =
-keycode  95 =
-keycode  96 =
-keycode  97 =
-keycode  98 =
-keycode  99 =
-keycode 100 =
-keycode 101 =
-keycode 102 = BackSpace
-keycode 103 =
-keycode 104 =
-keycode 105 = KP_1
-	alt	keycode	105 = Ascii_1
-	altgr	keycode	105 = Hex_1
-keycode 106 =
-keycode 107 = KP_4
-	alt	keycode	107 = Ascii_4
-	altgr	keycode	107 = Hex_4
-keycode 108 = KP_7
-	alt	keycode	108 = Ascii_7
-	altgr	keycode	108 = Hex_7
-keycode 109 =
-keycode 110 =
-keycode 111 =
-keycode 112 = KP_0
-	alt	keycode	82 = Ascii_0
-	altgr	keycode	82 = Hex_0
-keycode 113 = KP_Period
-keycode 114 = KP_2
-	alt	keycode	114 = Ascii_2
-	altgr	keycode	114 = Hex_2
-keycode 115 = KP_5
-	alt	keycode	115 = Ascii_5
-	altgr	keycode	115 = Hex_5
-keycode 116 = KP_6
-	alt	keycode	116 = Ascii_6
-	altgr	keycode	116 = Hex_6
-keycode 117 = KP_8
-	alt	keycode	117 = Ascii_8
-	altgr	keycode	117 = Hex_8
-keycode 118 = Escape
-keycode 119 =
-keycode 120 = F11
-keycode 121 = KP_Add
-keycode 122 = KP_3
-	alt	keycode	122 = Ascii_3
-	altgr	keycode	122 = Hex_3
-keycode 123 = KP_Subtract
-keycode 124 = KP_Multiply
-keycode 125 = KP_9
-	alt	keycode	125 = Ascii_9
-	altgr	keycode	125 = Hex_9
-keycode 126 =
-# 131!!
-keycode 127 = F7	F17	Console_19
-	control	keycode	127 = F7
-	alt	keycode	127 = Console_7
-	control	alt	keycode	127 = Console_7
-
-string F1 = "\033[[A"
-string F2 = "\033[[B"
-string F3 = "\033[[C"
-string F4 = "\033[[D"
-string F5 = "\033[[E"
-string F6 = "\033[17~"
-string F7 = "\033[18~"
-string F8 = "\033[19~"
-string F9 = "\033[20~"
-string F10 = "\033[21~"
-string F11 = "\033[23~"
-string F12 = "\033[24~"
-string F13 = "\033[25~"
-string F14 = "\033[26~"
-string F15 = "\033[28~"
-string F16 = "\033[29~"
-string F17 = "\033[31~"
-string F18 = "\033[32~"
-string F19 = "\033[33~"
-string F20 = "\033[34~"
-string Find = "\033[1~"
-string Insert = "\033[2~"
-string Remove = "\033[3~"
-string Select = "\033[4~"
-string Prior = "\033[5~"
-string Next = "\033[6~"
-string Macro = "\033[M"
-string Pause = "\033[P"
-compose '`' 'A' to ''
-compose '`' 'a' to ''
-compose '\'' 'A' to ''
-compose '\'' 'a' to ''
-compose '^' 'A' to ''
-compose '^' 'a' to ''
-compose '~' 'A' to ''
-compose '~' 'a' to ''
-compose '"' 'A' to ''
-compose '"' 'a' to ''
-compose 'O' 'A' to ''
-compose 'o' 'a' to ''
-compose '0' 'A' to ''
-compose '0' 'a' to ''
-compose 'A' 'A' to ''
-compose 'a' 'a' to ''
-compose 'A' 'E' to ''
-compose 'a' 'e' to ''
-compose ',' 'C' to ''
-compose ',' 'c' to ''
-compose '`' 'E' to ''
-compose '`' 'e' to ''
-compose '\'' 'E' to ''
-compose '\'' 'e' to ''
-compose '^' 'E' to ''
-compose '^' 'e' to ''
-compose '"' 'E' to ''
-compose '"' 'e' to ''
-compose '`' 'I' to ''
-compose '`' 'i' to ''
-compose '\'' 'I' to ''
-compose '\'' 'i' to ''
-compose '^' 'I' to ''
-compose '^' 'i' to ''
-compose '"' 'I' to ''
-compose '"' 'i' to ''
-compose '-' 'D' to ''
-compose '-' 'd' to ''
-compose '~' 'N' to ''
-compose '~' 'n' to ''
-compose '`' 'O' to ''
-compose '`' 'o' to ''
-compose '\'' 'O' to ''
-compose '\'' 'o' to ''
-compose '^' 'O' to ''
-compose '^' 'o' to ''
-compose '~' 'O' to ''
-compose '~' 'o' to ''
-compose '"' 'O' to ''
-compose '"' 'o' to ''
-compose '/' 'O' to ''
-compose '/' 'o' to ''
-compose '`' 'U' to ''
-compose '`' 'u' to ''
-compose '\'' 'U' to ''
-compose '\'' 'u' to ''
-compose '^' 'U' to ''
-compose '^' 'u' to ''
-compose '"' 'U' to ''
-compose '"' 'u' to ''
-compose '\'' 'Y' to ''
-compose '\'' 'y' to ''
-compose 'T' 'H' to ''
-compose 't' 'h' to ''
-compose 's' 's' to ''
-compose '"' 'y' to ''
-compose 's' 'z' to ''
-compose 'i' 'j' to ''
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/parisc/kernel/processor.c linux.20pre10-ac2/arch/parisc/kernel/processor.c
--- linux.20pre10/arch/parisc/kernel/processor.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/parisc/kernel/processor.c	2002-09-18 12:28:20.000000000 +0100
@@ -77,6 +77,8 @@
 	unsigned long txn_addr;
 	unsigned long cpuid;
 	struct cpuinfo_parisc *p;
+	extern struct irq_region_ops cpu_irq_ops; /* arch/parisc...irq.c */
+	extern struct irqaction cpu_irq_actions[]; /* arch/parisc...irq.c */
 
 #ifndef CONFIG_SMP
 	if (boot_cpu_data.cpu_count > 0) {
@@ -167,12 +169,24 @@
 	**	p->state = STATE_RENDEZVOUS;
 	*/
 
-	/*
-	** itimer and ipi IRQ handlers are statically initialized in
-	** arch/parisc/kernel/irq.c. ie Don't need to register them.
-	*/
-	p->region = irq_region[IRQ_FROM_REGION(CPU_IRQ_REGION)];
+#if 0
+	/* CPU 0 IRQ table is statically allocated/initialized */
+	if (cpuid) {
+		struct irqaction actions[];
+
+		/*
+		** itimer and ipi IRQ handlers are statically initialized in
+		** arch/parisc/kernel/irq.c. ie Don't need to register them.
+		*/
+		actions = kmalloc(sizeof(struct irqaction)*MAX_CPU_IRQ, GFP_ATOMIC);
+		if (!actions) {
+			/* not getting it's own table, share with monarch */
+			actions = cpu_irq_actions[0];
+		}
 
+		cpu_irq_actions[cpuid] = actions;
+	}
+#endif
 	return 0;
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/ppc/kernel/entry.S linux.20pre10-ac2/arch/ppc/kernel/entry.S
--- linux.20pre10/arch/ppc/kernel/entry.S	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/ppc/kernel/entry.S	2002-08-26 14:23:02.000000000 +0100
@@ -264,7 +264,9 @@
 
 	.globl	ret_from_fork
 ret_from_fork:
+#ifdef CONFIG_SMP
 	bl	schedule_tail
+#endif	
 	lwz	r0,TASK_PTRACE(r2)
 	andi.	r0,r0,PT_TRACESYS
 	bnel-	syscall_trace
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/ppc/kernel/idle.c linux.20pre10-ac2/arch/ppc/kernel/idle.c
--- linux.20pre10/arch/ppc/kernel/idle.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/ppc/kernel/idle.c	2002-10-09 21:48:03.000000000 +0100
@@ -51,9 +51,6 @@
 		do_power_save = 1;
 
 	/* endless loop with no priority at all */
-	current->nice = 20;
-	current->counter = -100;
-	init_idle();
 	for (;;) {
 #ifdef CONFIG_SMP
 		if (!do_power_save) {
@@ -73,11 +70,8 @@
 		if (do_power_save && !current->need_resched)
 			power_save_6xx();
 #endif /* CONFIG_6xx */			
-
-		if (current->need_resched) {
-			schedule();
-			check_pgt_cache();
-		}
+		schedule();
+		check_pgt_cache();
 	}
 	return 0;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/ppc/kernel/mk_defs.c linux.20pre10-ac2/arch/ppc/kernel/mk_defs.c
--- linux.20pre10/arch/ppc/kernel/mk_defs.c	2002-10-09 21:36:58.000000000 +0100
+++ linux.20pre10-ac2/arch/ppc/kernel/mk_defs.c	2002-08-29 23:15:28.000000000 +0100
@@ -37,8 +37,7 @@
 	/*DEFINE(KERNELBASE, KERNELBASE);*/
 	DEFINE(STATE, offsetof(struct task_struct, state));
 	DEFINE(NEXT_TASK, offsetof(struct task_struct, next_task));
-	DEFINE(COUNTER, offsetof(struct task_struct, counter));
-	DEFINE(PROCESSOR, offsetof(struct task_struct, processor));
+	DEFINE(PROCESSOR, offsetof(struct task_struct, cpu));
 	DEFINE(SIGPENDING, offsetof(struct task_struct, sigpending));
 	DEFINE(THREAD, offsetof(struct task_struct, thread));
 	DEFINE(MM, offsetof(struct task_struct, mm));
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/ppc/kernel/ppc_defs.h linux.20pre10-ac2/arch/ppc/kernel/ppc_defs.h
--- linux.20pre10/arch/ppc/kernel/ppc_defs.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/arch/ppc/kernel/ppc_defs.h	2002-08-26 14:23:02.000000000 +0100
@@ -0,0 +1,81 @@
+/*
+ * WARNING! This file is automatically generated - DO NOT EDIT!
+ */
+#define	STATE	0
+#define	NEXT_TASK	76
+#define	PROCESSOR	32
+#define	SIGPENDING	8
+#define	THREAD	608
+#define	MM	84
+#define	ACTIVE_MM	88
+#define	TASK_STRUCT_SIZE	1520
+#define	KSP	0
+#define	PGDIR	16
+#define	LAST_SYSCALL	20
+#define	PT_REGS	8
+#define	PT_TRACESYS	2
+#define	TASK_FLAGS	4
+#define	TASK_PTRACE	24
+#define	NEED_RESCHED	20
+#define	THREAD_FPR0	24
+#define	THREAD_FPSCR	284
+#define	THREAD_VR0	288
+#define	THREAD_VRSAVE	816
+#define	THREAD_VSCR	800
+#define	TASK_UNION_SIZE	8192
+#define	STACK_FRAME_OVERHEAD	16
+#define	INT_FRAME_SIZE	192
+#define	GPR0	16
+#define	GPR1	20
+#define	GPR2	24
+#define	GPR3	28
+#define	GPR4	32
+#define	GPR5	36
+#define	GPR6	40
+#define	GPR7	44
+#define	GPR8	48
+#define	GPR9	52
+#define	GPR10	56
+#define	GPR11	60
+#define	GPR12	64
+#define	GPR13	68
+#define	GPR14	72
+#define	GPR15	76
+#define	GPR16	80
+#define	GPR17	84
+#define	GPR18	88
+#define	GPR19	92
+#define	GPR20	96
+#define	GPR21	100
+#define	GPR22	104
+#define	GPR23	108
+#define	GPR24	112
+#define	GPR25	116
+#define	GPR26	120
+#define	GPR27	124
+#define	GPR28	128
+#define	GPR29	132
+#define	GPR30	136
+#define	GPR31	140
+#define	_NIP	144
+#define	_MSR	148
+#define	_CTR	156
+#define	_LINK	160
+#define	_CCR	168
+#define	_MQ	172
+#define	_XER	164
+#define	_DAR	180
+#define	_DSISR	184
+#define	_DEAR	180
+#define	_ESR	184
+#define	ORIG_GPR3	152
+#define	RESULT	188
+#define	TRAP	176
+#define	CLONE_VM	256
+#define	MM_PGD	12
+#define	CPU_SPEC_ENTRY_SIZE	32
+#define	CPU_SPEC_PVR_MASK	0
+#define	CPU_SPEC_PVR_VALUE	4
+#define	CPU_SPEC_FEATURES	12
+#define	CPU_SPEC_SETUP	28
+#define	NUM_USER_SEGMENTS	8
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/ppc/kernel/setup.c linux.20pre10-ac2/arch/ppc/kernel/setup.c
--- linux.20pre10/arch/ppc/kernel/setup.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/ppc/kernel/setup.c	2002-09-14 21:45:44.000000000 +0100
@@ -669,14 +669,16 @@
 	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->trseuc         = __le16_to_cpu(id->trseuc);
+	id->trsEuc         = __le16_to_cpu(id->trsEuc);
 	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->word92         = __le16_to_cpu(id->word92);
+	id->mprc           = __le16_to_cpu(id->mprc);
 	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->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]);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/ppc/kernel/smp.c linux.20pre10-ac2/arch/ppc/kernel/smp.c
--- linux.20pre10/arch/ppc/kernel/smp.c	2002-10-09 21:36:59.000000000 +0100
+++ linux.20pre10-ac2/arch/ppc/kernel/smp.c	2002-08-26 14:23:02.000000000 +0100
@@ -294,8 +294,6 @@
 	cpu_callin_map[0] = 1;
 	current->processor = 0;
 
-	init_idle();
-
 	for (i = 0; i < NR_CPUS; i++) {
 		prof_counter[i] = 1;
 		prof_multiplier[i] = 1;
@@ -348,7 +346,8 @@
 		p = init_task.prev_task;
 		if (!p)
 			panic("No idle task for CPU %d", i);
-		del_from_runqueue(p);
+		init_idle(p, i);
+
 		unhash_process(p);
 		init_tasks[i] = p;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/ppc/mm/fault.c linux.20pre10-ac2/arch/ppc/mm/fault.c
--- linux.20pre10/arch/ppc/mm/fault.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/ppc/mm/fault.c	2002-08-29 18:44:13.000000000 +0100
@@ -109,8 +109,6 @@
 		goto bad_area;
 	if (vma->vm_start <= address)
 		goto good_area;
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		goto bad_area;
 	if (expand_stack(vma, address))
 		goto bad_area;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/ppc/platforms/chrp_setup.c linux.20pre10-ac2/arch/ppc/platforms/chrp_setup.c
--- linux.20pre10/arch/ppc/platforms/chrp_setup.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/ppc/platforms/chrp_setup.c	2002-10-09 21:47:26.000000000 +0100
@@ -533,31 +533,6 @@
 }
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/*
- * IDE stuff.
- */
-
-static int __chrp
-chrp_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-        return check_region(from, extent);
-}
-
-static void __chrp
-chrp_ide_request_region(ide_ioreg_t from,
-			unsigned int extent,
-			const char *name)
-{
-        request_region(from, extent, name);
-}
-
-static void __chrp
-chrp_ide_release_region(ide_ioreg_t from,
-			unsigned int extent)
-{
-        release_region(from, extent);
-}
-
 static void __chrp
 chrp_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
@@ -657,9 +632,6 @@
 #endif /* CONFIG_SMP */
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.ide_check_region = chrp_ide_check_region;
-        ppc_ide_md.ide_request_region = chrp_ide_request_region;
-        ppc_ide_md.ide_release_region = chrp_ide_release_region;
         ppc_ide_md.ide_init_hwif = chrp_ide_init_hwif_ports;
 #endif
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/ppc/platforms/pmac_setup.c linux.20pre10-ac2/arch/ppc/platforms/pmac_setup.c
--- linux.20pre10/arch/ppc/platforms/pmac_setup.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/ppc/platforms/pmac_setup.c	2002-09-14 21:45:44.000000000 +0100
@@ -708,44 +708,7 @@
    pmac_power_off();
 }
 
-
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/*
- * IDE stuff.
- */
-static int __pmac
-pmac_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	if (pmac_ide_check_base(from) >= 0)
-		return 0;
-#endif
-	return check_region(from, extent);
-}
-
-static void __pmac
-pmac_ide_request_region(ide_ioreg_t from,
-			unsigned int extent,
-			const char *name)
-{
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	if (pmac_ide_check_base(from) >= 0)
-		return;
-#endif
-	request_region(from, extent, name);
-}
-
-static void __pmac
-pmac_ide_release_region(ide_ioreg_t from,
-			unsigned int extent)
-{
-#ifdef CONFIG_BLK_DEV_IDE_PMAC
-	if (pmac_ide_check_base(from) >= 0)
-		return;
-#endif
-	release_region(from, extent);
-}
-
 #ifndef CONFIG_BLK_DEV_IDE_PMAC
 /*
  * This is only used if we have a PCI IDE controller, not
@@ -926,9 +889,6 @@
 	select_adb_keyboard();
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.ide_check_region	= pmac_ide_check_region;
-        ppc_ide_md.ide_request_region	= pmac_ide_request_region;
-        ppc_ide_md.ide_release_region	= pmac_ide_release_region;
 #ifdef CONFIG_BLK_DEV_IDE_PMAC
         ppc_ide_md.ide_init_hwif	= pmac_ide_init_hwif_ports;
         ppc_ide_md.default_io_base	= pmac_ide_get_base;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/ppc/platforms/prep_setup.c linux.20pre10-ac2/arch/ppc/platforms/prep_setup.c
--- linux.20pre10/arch/ppc/platforms/prep_setup.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/ppc/platforms/prep_setup.c	2002-09-14 21:45:44.000000000 +0100
@@ -660,27 +660,6 @@
 	}
 }
 
-static int __prep
-prep_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-	return check_region(from, extent);
-}
-
-static void __prep
-prep_ide_request_region(ide_ioreg_t from,
-			unsigned int extent,
-			const char *name)
-{
-	request_region(from, extent, name);
-}
-
-static void __prep
-prep_ide_release_region(ide_ioreg_t from,
-			unsigned int extent)
-{
-	release_region(from, extent);
-}
-
 static void __init
 prep_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
@@ -865,9 +844,6 @@
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 	ppc_ide_md.default_irq = prep_ide_default_irq;
 	ppc_ide_md.default_io_base = prep_ide_default_io_base;
-	ppc_ide_md.ide_check_region = prep_ide_check_region;
-	ppc_ide_md.ide_request_region = prep_ide_request_region;
-	ppc_ide_md.ide_release_region = prep_ide_release_region;
 	ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports;
 #endif
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/ppc64/kernel/setup.c linux.20pre10-ac2/arch/ppc64/kernel/setup.c
--- linux.20pre10/arch/ppc64/kernel/setup.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/ppc64/kernel/setup.c	2002-08-29 18:44:39.000000000 +0100
@@ -585,17 +585,19 @@
 	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->trseuc         = __le16_to_cpu(id->trseuc);
+	id->trsEuc         = __le16_to_cpu(id->trsEuc);
 	id->CurAPMvalues   = __le16_to_cpu(id->CurAPMvalues);
-	id->word92         = __le16_to_cpu(id->word92);
+	id->mprc           = __le16_to_cpu(id->mprc);
 	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->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 < 21; i++)
-		id->words104_125[i]  = __le16_to_cpu(id->words104_125[i]);
+	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);
@@ -605,14 +607,14 @@
 	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 < 15; 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 < 29; 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);
+	id->integrity_word  = __le16_to_cpu(id->integrity_word);
 }
 #endif
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/s390/kernel/entry.S linux.20pre10-ac2/arch/s390/kernel/entry.S
--- linux.20pre10/arch/s390/kernel/entry.S	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/s390/kernel/entry.S	2002-08-13 14:09:16.000000000 +0100
@@ -254,13 +254,14 @@
 ret_from_fork:  
         basr    %r13,0
         l       %r13,.Lentry_base-.(%r13)  # setup base pointer to &entry_base
+	# not saving R14 here because we go to sysc_return ultimately
+	l	%r1,BASED(.Lschedtail)
+	basr	%r14,%r1          # call schedule_tail (unlock stuff)
         GET_CURRENT               # load pointer to task_struct to R9
         stosm   24(%r15),0x03     # reenable interrupts
         sr      %r0,%r0           # child returns 0
         st      %r0,SP_R2(%r15)   # store return value (change R2 on stack)
-        l       %r1,BASED(.Lschedtail)
-	la      %r14,BASED(sysc_return)
-        br      %r1               # call schedule_tail, return to sysc_return
+	b	BASED(sysc_return)
 
 #
 # clone, fork, vfork, exec and sigreturn need glue,
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/s390x/kernel/entry.S linux.20pre10-ac2/arch/s390x/kernel/entry.S
--- linux.20pre10/arch/s390x/kernel/entry.S	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/s390x/kernel/entry.S	2002-08-13 14:09:33.000000000 +0100
@@ -240,11 +240,11 @@
 #
         .globl  ret_from_fork
 ret_from_fork:  
+	brasl	%r14,schedule_tail
         GET_CURRENT               # load pointer to task_struct to R9
         stosm   48(%r15),0x03     # reenable interrupts
 	xc      SP_R2(8,%r15),SP_R2(%r15) # child returns 0
-	larl    %r14,sysc_return
-        jg      schedule_tail     # return to sysc_return
+	j	sysc_return
 
 #
 # clone, fork, vfork, exec and sigreturn need glue,
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/s390x/kernel/linux32.c linux.20pre10-ac2/arch/s390x/kernel/linux32.c
--- linux.20pre10/arch/s390x/kernel/linux32.c	2002-10-09 21:37:04.000000000 +0100
+++ linux.20pre10-ac2/arch/s390x/kernel/linux32.c	2002-08-06 15:42:22.000000000 +0100
@@ -912,64 +912,97 @@
 	return sys32_fcntl(fd, cmd, arg);
 }
 
-struct dqblk32 {
-    __u32 dqb_bhardlimit;
-    __u32 dqb_bsoftlimit;
-    __u32 dqb_curblocks;
-    __u32 dqb_ihardlimit;
-    __u32 dqb_isoftlimit;
-    __u32 dqb_curinodes;
-    __kernel_time_t32 dqb_btime;
-    __kernel_time_t32 dqb_itime;
-};
-                                
 extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
 
-asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr)
+#ifdef CONFIG_QIFACE_COMPAT
+#ifdef CONFIG_QIFACE_V1
+struct user_dqblk32 {
+	__u32 dqb_bhardlimit;
+	__u32 dqb_bsoftlimit;
+	__u32 dqb_curblocks;
+	__u32 dqb_ihardlimit;
+	__u32 dqb_isoftlimit;
+	__u32 dqb_curinodes;
+	__kernel_time_t32 dqb_btime;
+	__kernel_time_t32 dqb_itime;
+};
+typedef struct v1c_mem_dqblk comp_dqblk_t;
+
+#define Q_COMP_GETQUOTA Q_V1_GETQUOTA
+#define Q_COMP_SETQUOTA Q_V1_SETQUOTA
+#define Q_COMP_SETQLIM Q_V1_SETQLIM
+#define Q_COMP_SETUSE Q_V1_SETUSE
+#else
+struct user_dqblk32 {
+	__u32 dqb_ihardlimit;
+	__u32 dqb_isoftlimit;
+	__u32 dqb_curinodes;
+	__u32 dqb_bhardlimit;
+	__u32 dqb_bsoftlimit;
+	__u64 dqb_curspace;
+	__kernel_time_t32 dqb_btime;
+	__kernel_time_t32 dqb_itime;
+};
+typedef struct v2c_mem_dqblk comp_dqblk_t;
+
+#define Q_COMP_GETQUOTA Q_V2_GETQUOTA
+#define Q_COMP_SETQUOTA Q_V2_SETQUOTA
+#define Q_COMP_SETQLIM Q_V2_SETQLIM
+#define Q_COMP_SETUSE Q_V2_SETUSE
+#endif
+
+asmlinkage int sys32_quotactl(int cmd, const char *special, int id, caddr_t addr)
 {
 	int cmds = cmd >> SUBCMDSHIFT;
 	int err;
-	struct dqblk d;
+	comp_dqblk_t d;
 	mm_segment_t old_fs;
 	char *spec;
 	
 	switch (cmds) {
-	case Q_GETQUOTA:
-		break;
-	case Q_SETQUOTA:
-	case Q_SETUSE:
-	case Q_SETQLIM:
-		if (copy_from_user (&d, (struct dqblk32 *)addr,
-				    sizeof (struct dqblk32)))
-			return -EFAULT;
-		d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
-		d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
-		break;
+		case Q_COMP_GETQUOTA:
+			break;
+		case Q_COMP_SETQUOTA:
+		case Q_COMP_SETUSE:
+		case Q_COMP_SETQLIM:
+			if (copy_from_user(&d, (struct user_dqblk32 *)addr,
+					    sizeof (struct user_dqblk32)))
+				return -EFAULT;
+			d.dqb_itime = ((struct user_dqblk32 *)&d)->dqb_itime;
+			d.dqb_btime = ((struct user_dqblk32 *)&d)->dqb_btime;
+			break;
 	default:
-		return sys_quotactl(cmd, special,
-				    id, (caddr_t)addr);
+		return sys_quotactl(cmd, special, id, (__kernel_caddr_t)addr);
 	}
 	spec = getname (special);
 	err = PTR_ERR(spec);
 	if (IS_ERR(spec)) return err;
-	old_fs = get_fs ();
+	old_fs = get_fs();
 	set_fs (KERNEL_DS);
-	err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d);
+	err = sys_quotactl(cmd, (const char *)spec, id, (__kernel_caddr_t)&d);
 	set_fs (old_fs);
 	putname (spec);
 	if (err)
 		return err;
-	if (cmds == Q_GETQUOTA) {
+	if (cmds == Q_COMP_GETQUOTA) {
 		__kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
-		((struct dqblk32 *)&d)->dqb_itime = i;
-		((struct dqblk32 *)&d)->dqb_btime = b;
-		if (copy_to_user ((struct dqblk32 *)addr, &d,
-				  sizeof (struct dqblk32)))
+		((struct user_dqblk32 *)&d)->dqb_itime = i;
+		((struct user_dqblk32 *)&d)->dqb_btime = b;
+		if (copy_to_user ((struct user_dqblk32 *)addr, &d,
+				  sizeof (struct user_dqblk32)))
 			return -EFAULT;
 	}
 	return 0;
 }
 
+#else
+/* No conversion needed for new interface */
+asmlinkage int sys32_quotactl(int cmd, const char *special, int id, caddr_t addr)
+{
+	return sys_quotactl(cmd, special, id, addr);
+}
+#endif
+
 static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
 {
 	int err;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/sh/mm/fault.c linux.20pre10-ac2/arch/sh/mm/fault.c
--- linux.20pre10/arch/sh/mm/fault.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/sh/mm/fault.c	2002-08-29 19:00:49.000000000 +0100
@@ -72,8 +72,6 @@
 	return 1;
 
 check_stack:
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		goto bad_area;
 	if (expand_stack(vma, start) == 0)
 		goto good_area;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/sparc/kernel/sunos_ioctl.c linux.20pre10-ac2/arch/sparc/kernel/sunos_ioctl.c
--- linux.20pre10/arch/sparc/kernel/sunos_ioctl.c	2002-10-09 21:36:57.000000000 +0100
+++ linux.20pre10-ac2/arch/sparc/kernel/sunos_ioctl.c	2002-08-06 15:42:19.000000000 +0100
@@ -39,8 +39,12 @@
 {
 	int ret = -EBADF;
 
-	if (fd >= SUNOS_NR_OPEN || !fcheck(fd))
+	read_lock(&current->files->file_lock);
+	if (fd >= SUNOS_NR_OPEN || !fcheck(fd)) {
+		read_unlock(&current->files->file_lock);
 		goto out;
+	}
+	read_unlock(&current->files->file_lock);
 
 	/* First handle an easy compat. case for tty ldisc. */
 	if(cmd == TIOCSETD) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/sparc/mm/fault.c linux.20pre10-ac2/arch/sparc/mm/fault.c
--- linux.20pre10/arch/sparc/mm/fault.c	2002-10-09 21:36:57.000000000 +0100
+++ linux.20pre10-ac2/arch/sparc/mm/fault.c	2002-08-06 15:42:19.000000000 +0100
@@ -249,8 +249,6 @@
 		goto bad_area;
 	if(vma->vm_start <= address)
 		goto good_area;
-	if(!(vma->vm_flags & VM_GROWSDOWN))
-		goto bad_area;
 	if(expand_stack(vma, address))
 		goto bad_area;
 	/*
@@ -496,8 +494,6 @@
 		goto bad_area;
 	if(vma->vm_start <= address)
 		goto good_area;
-	if(!(vma->vm_flags & VM_GROWSDOWN))
-		goto bad_area;
 	if(expand_stack(vma, address))
 		goto bad_area;
 good_area:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/sparc64/kernel/sunos_ioctl32.c linux.20pre10-ac2/arch/sparc64/kernel/sunos_ioctl32.c
--- linux.20pre10/arch/sparc64/kernel/sunos_ioctl32.c	2002-10-09 21:37:00.000000000 +0100
+++ linux.20pre10-ac2/arch/sparc64/kernel/sunos_ioctl32.c	2002-08-06 15:42:21.000000000 +0100
@@ -100,8 +100,12 @@
 
 	if(fd >= SUNOS_NR_OPEN)
 		goto out;
-	if(!fcheck(fd))
+	read_lock(&current->files->file_lock);
+	if(!fcheck(fd)) {
+		read_unlock(&current->files->file_lock);
 		goto out;
+	}
+	read_unlock(&current->files->file_lock);
 
 	if(cmd == TIOCSETD) {
 		mm_segment_t old_fs = get_fs();
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/sparc64/kernel/sys_sparc32.c linux.20pre10-ac2/arch/sparc64/kernel/sys_sparc32.c
--- linux.20pre10/arch/sparc64/kernel/sys_sparc32.c	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/arch/sparc64/kernel/sys_sparc32.c	2002-10-07 18:33:41.000000000 +0100
@@ -888,62 +888,97 @@
 	return sys32_fcntl(fd, cmd, arg);
 }
 
-struct dqblk32 {
-    __u32 dqb_bhardlimit;
-    __u32 dqb_bsoftlimit;
-    __u32 dqb_curblocks;
-    __u32 dqb_ihardlimit;
-    __u32 dqb_isoftlimit;
-    __u32 dqb_curinodes;
-    __kernel_time_t32 dqb_btime;
-    __kernel_time_t32 dqb_itime;
-};
-                                
 extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
 
-asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr)
+#ifdef CONFIG_QIFACE_COMPAT
+#ifdef CONFIG_QIFACE_V1
+struct user_dqblk32 {
+	__u32 dqb_bhardlimit;
+	__u32 dqb_bsoftlimit;
+	__u32 dqb_curblocks;
+	__u32 dqb_ihardlimit;
+	__u32 dqb_isoftlimit;
+	__u32 dqb_curinodes;
+	__kernel_time_t32 dqb_btime;
+	__kernel_time_t32 dqb_itime;
+};
+typedef struct v1c_mem_dqblk comp_dqblk_t;
+
+#define Q_COMP_GETQUOTA Q_V1_GETQUOTA
+#define Q_COMP_SETQUOTA Q_V1_SETQUOTA
+#define Q_COMP_SETQLIM Q_V1_SETQLIM
+#define Q_COMP_SETUSE Q_V1_SETUSE
+#else
+struct user_dqblk32 {
+	__u32 dqb_ihardlimit;
+	__u32 dqb_isoftlimit;
+	__u32 dqb_curinodes;
+	__u32 dqb_bhardlimit;
+	__u32 dqb_bsoftlimit;
+	__u64 dqb_curspace;
+	__kernel_time_t32 dqb_btime;
+	__kernel_time_t32 dqb_itime;
+};
+typedef struct v2c_mem_dqblk comp_dqblk_t;
+
+#define Q_COMP_GETQUOTA Q_V2_GETQUOTA
+#define Q_COMP_SETQUOTA Q_V2_SETQUOTA
+#define Q_COMP_SETQLIM Q_V2_SETQLIM
+#define Q_COMP_SETUSE Q_V2_SETUSE
+#endif
+
+asmlinkage int sys32_quotactl(int cmd, const char *special, int id, caddr_t addr)
 {
 	int cmds = cmd >> SUBCMDSHIFT;
 	int err;
-	struct dqblk d;
+	comp_dqblk_t d;
 	mm_segment_t old_fs;
 	char *spec;
 	
 	switch (cmds) {
-	case Q_GETQUOTA:
-		break;
-	case Q_SETQUOTA:
-	case Q_SETUSE:
-	case Q_SETQLIM:
-		if (copy_from_user (&d, (struct dqblk32 *)addr,
-				    sizeof (struct dqblk32)))
-			return -EFAULT;
-		d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
-		d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
-		break;
+		case Q_COMP_GETQUOTA:
+			break;
+		case Q_COMP_SETQUOTA:
+		case Q_COMP_SETUSE:
+		case Q_COMP_SETQLIM:
+			if (copy_from_user(&d, (struct user_dqblk32 *)addr,
+					    sizeof (struct user_dqblk32)))
+				return -EFAULT;
+			d.dqb_itime = ((struct user_dqblk32 *)&d)->dqb_itime;
+			d.dqb_btime = ((struct user_dqblk32 *)&d)->dqb_btime;
+			break;
 	default:
-		return sys_quotactl(cmd, special,
-				    id, (caddr_t)addr);
+		return sys_quotactl(cmd, special, id, (__kernel_caddr_t)addr);
 	}
 	spec = getname (special);
 	err = PTR_ERR(spec);
 	if (IS_ERR(spec)) return err;
-	old_fs = get_fs ();
+	old_fs = get_fs();
 	set_fs (KERNEL_DS);
-	err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d);
+	err = sys_quotactl(cmd, (const char *)spec, id, (__kernel_caddr_t)&d);
 	set_fs (old_fs);
 	putname (spec);
-	if (cmds == Q_GETQUOTA) {
+	if (err)
+		return err;
+	if (cmds == Q_COMP_GETQUOTA) {
 		__kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
-		((struct dqblk32 *)&d)->dqb_itime = i;
-		((struct dqblk32 *)&d)->dqb_btime = b;
-		if (copy_to_user ((struct dqblk32 *)addr, &d,
-				  sizeof (struct dqblk32)))
+		((struct user_dqblk32 *)&d)->dqb_itime = i;
+		((struct user_dqblk32 *)&d)->dqb_btime = b;
+		if (copy_to_user ((struct user_dqblk32 *)addr, &d,
+				  sizeof (struct user_dqblk32)))
 			return -EFAULT;
 	}
-	return err;
+	return 0;
 }
 
+#else
+/* No conversion needed for new interface */
+asmlinkage int sys32_quotactl(int cmd, const char *special, int id, caddr_t addr)
+{
+	return sys_quotactl(cmd, special, id, addr);
+}
+#endif
+
 static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
 {
 	int err;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/sparc64/mm/fault.c linux.20pre10-ac2/arch/sparc64/mm/fault.c
--- linux.20pre10/arch/sparc64/mm/fault.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/arch/sparc64/mm/fault.c	2002-09-26 21:48:14.000000000 +0100
@@ -373,8 +373,6 @@
 
 	if (vma->vm_start <= address)
 		goto good_area;
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		goto bad_area;
 	if (!(fault_code & FAULT_CODE_WRITE)) {
 		/* Non-faulting loads shouldn't expand stack. */
 		insn = get_fault_insn(regs, insn);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/arch/sparc64/solaris/timod.c linux.20pre10-ac2/arch/sparc64/solaris/timod.c
--- linux.20pre10/arch/sparc64/solaris/timod.c	2002-10-09 21:37:02.000000000 +0100
+++ linux.20pre10-ac2/arch/sparc64/solaris/timod.c	2002-08-06 15:42:21.000000000 +0100
@@ -149,7 +149,9 @@
 	struct socket *sock;
 
 	SOLD("wakeing socket");
+	read_lock(&current->files->file_lock);
 	sock = &current->files->fd[fd]->f_dentry->d_inode->u.socket_i;
+	read_unlock(&current->files->file_lock);
 	wake_up_interruptible(&sock->wait);
 	read_lock(&sock->sk->callback_lock);
 	if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
@@ -163,7 +165,9 @@
 	struct sol_socket_struct *sock;
 
 	SOLD("queuing primsg");
+	read_lock(&current->files->file_lock);
 	sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data;
+	read_unlock(&current->files->file_lock);
 	it->next = sock->pfirst;
 	sock->pfirst = it;
 	if (!sock->plast)
@@ -177,7 +181,9 @@
 	struct sol_socket_struct *sock;
 
 	SOLD("queuing primsg at end");
+	read_lock(&current->files->file_lock);
 	sock = (struct sol_socket_struct *)current->files->fd[fd]->private_data;
+	read_unlock(&current->files->file_lock);
 	it->next = NULL;
 	if (sock->plast)
 		sock->plast->next = it;
@@ -355,7 +361,11 @@
 		(int (*)(int, unsigned long *))SYS(socketcall);
 	int (*sys_sendto)(int, void *, size_t, unsigned, struct sockaddr *, int) =
 		(int (*)(int, void *, size_t, unsigned, struct sockaddr *, int))SYS(sendto);
-	filp = current->files->fd[fd];
+	read_lock(&current->files->file_lock);
+	filp = fcheck(fd);
+	read_unlock(&current->files->file_lock);
+	if (!filp)
+		return -EBADF;
 	ino = filp->f_dentry->d_inode;
 	sock = (struct sol_socket_struct *)filp->private_data;
 	SOLD("entry");
@@ -636,7 +646,11 @@
 	
 	SOLD("entry");
 	SOLDD(("%u %p %d %p %p %d %p %d\n", fd, ctl_buf, ctl_maxlen, ctl_len, data_buf, data_maxlen, data_len, *flags_p));
-	filp = current->files->fd[fd];
+	read_lock(&current->files->file_lock);
+	filp = fcheck(fd);
+	read_unlock(&current->files->file_lock);
+	if (!filp)
+		return -EBADF;
 	ino = filp->f_dentry->d_inode;
 	sock = (struct sol_socket_struct *)filp->private_data;
 	SOLDD(("%p %p\n", sock->pfirst, sock->pfirst ? sock->pfirst->next : NULL));
@@ -847,7 +861,9 @@
 	lock_kernel();
 	if(fd >= NR_OPEN) goto out;
 
-	filp = current->files->fd[fd];
+	read_lock(&current->files->file_lock);
+	filp = fcheck(fd);
+	read_unlock(&current->files->file_lock);
 	if(!filp) goto out;
 
 	ino = filp->f_dentry->d_inode;
@@ -914,7 +930,9 @@
 	lock_kernel();
 	if(fd >= NR_OPEN) goto out;
 
-	filp = current->files->fd[fd];
+	read_lock(&current->files->file_lock);
+	filp = fcheck(fd);
+	read_unlock(&current->files->file_lock);
 	if(!filp) goto out;
 
 	ino = filp->f_dentry->d_inode;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/Changelog.rmap linux.20pre10-ac2/Changelog.rmap
--- linux.20pre10/Changelog.rmap	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/Changelog.rmap	2002-09-29 20:03:17.000000000 +0100
@@ -0,0 +1,187 @@
+The second maintenance release of the 14th version of the reverse
+mapping based VM is now available.
+This is an attempt at making a more robust and flexible VM
+subsystem, while cleaning up a lot of code at the same time.
+The patch is available from:
+
+           http://surriel.com/patches/2.4/2.4.19-rmap14b
+and        http://linuxvm.bkbits.net/
+
+
+My big TODO items for a next release are:
+  - backport speedups from 2.5
+  - pte-highmem
+
+rmap 14b:
+  - don't unmap pages not in pagecache (ext3 & reiser)    (Andrew Morton, me)
+  - clean up mark_page_accessed a bit                     (me)
+  - Alpha NUMA fix for Ingo's per-cpu pages               (Flvio Leitner, me)
+  - remove explicit low latency schedule zap_page_range   (Robert Love)
+  - fix OOM stuff for good, hopefully                     (me)
+rmap 14a:
+  - Ingo Molnar's per-cpu pages (SMP speedup)             (Christoph Hellwig)
+  - fix SMP bug in page_launder_zone (rmap14 only)        (Arjan van de Ven) 
+  - semicolon day, fix typo in rmap.c w/ DEBUG_RMAP       (Craig Kulesa)
+  - remove unneeded pte_chain_unlock/lock pair vmscan.c   (Craig Kulesa)
+  - low latency zap_page_range also without preempt       (Arjan van de Ven)
+  - do some throughput tuning for kswapd/page_launder     (me)
+  - don't allocate swap space for pages we're not writing (me)
+rmap 14:
+  - get rid of stalls during swapping, hopefully          (me)
+  - low latency zap_page_range                            (Robert Love)
+rmap 13c:
+  - add wmb() to wakeup_memwaiters                        (Arjan van de Ven)
+  - remap_pmd_range now calls pte_alloc with full address (Paul Mackerras)
+  - #ifdef out pte_chain_lock/unlock on UP machines       (Andrew Morton)
+  - un-BUG() truncate_complete_page, the race is expected (Andrew Morton, me)
+  - remove NUMA changes from rmap13a                      (Christoph Hellwig)
+rmap 13b:
+  - prevent PF_MEMALLOC recursion for higher order allocs (Arjan van de Ven, me)
+  - fix small SMP race, PG_lru                            (Hugh Dickins)
+rmap 13a:
+  - NUMA changes for page_address                         (Samuel Ortiz)
+  - replace vm.freepages with simpler kswapd_minfree      (Christoph Hellwig)
+rmap 13:
+  - rename touch_page to mark_page_accessed and uninline  (Christoph Hellwig)
+  - NUMA bugfix for __alloc_pages                         (William Irwin)
+  - kill __find_page                                      (Christoph Hellwig)
+  - make pte_chain_freelist per zone                      (William Irwin)
+  - protect pte_chains by per-page lock bit               (William Irwin)
+  - minor code cleanups                                   (me)
+rmap 12i:
+  - slab cleanup                                          (Christoph Hellwig)
+  - remove references to compiler.h from mm/*             (me)
+  - move rmap to marcelo's bk tree                        (me)
+  - minor cleanups                                        (me)
+rmap 12h:
+  - hopefully fix OOM detection algorithm                 (me)
+  - drop pte quicklist in anticipation of pte-highmem     (me)
+  - replace andrea's highmem emulation by ingo's one      (me)
+  - improve rss limit checking                            (Nick Piggin)
+rmap 12g:
+  - port to armv architecture                             (David Woodhouse)
+  - NUMA fix to zone_table initialisation                 (Samuel Ortiz)
+  - remove init_page_count                                (David Miller)
+rmap 12f:
+  - for_each_pgdat macro                                  (William Lee Irwin)
+  - put back EXPORT(__find_get_page) for modular rd       (me)
+  - make bdflush and kswapd actually start queued disk IO (me)
+rmap 12e
+  - RSS limit fix, the limit can be 0 for some reason     (me)
+  - clean up for_each_zone define to not need pgdata_t    (William Lee Irwin)
+  - fix i810_dma bug introduced with page->wait removal   (William Lee Irwin)
+rmap 12d:
+  - fix compiler warning in rmap.c                        (Roger Larsson)
+  - read latency improvement   (read-latency2)            (Andrew Morton)
+rmap 12c:
+  - fix small balancing bug in page_launder_zone          (Nick Piggin)
+  - wakeup_kswapd / wakeup_memwaiters code fix            (Arjan van de Ven)
+  - improve RSS limit enforcement                         (me)
+rmap 12b:
+  - highmem emulation (for debugging purposes)            (Andrea Arcangeli)
+  - ulimit RSS enforcement when memory gets tight         (me)
+  - sparc64 page->virtual quickfix                        (Greg Procunier)
+rmap 12a:
+  - fix the compile warning in buffer.c                   (me)
+  - fix divide-by-zero on highmem initialisation  DOH!    (me)
+  - remove the pgd quicklist (suspicious ...)             (DaveM, me)
+rmap 12:
+  - keep some extra free memory on large machines         (Arjan van de Ven, me)
+  - higher-order allocation bugfix                        (Adrian Drzewiecki)
+  - nr_free_buffer_pages() returns inactive + free mem    (me)
+  - pages from unused objects directly to inactive_clean  (me)
+  - use fast pte quicklists on non-pae machines           (Andrea Arcangeli)
+  - remove sleep_on from wakeup_kswapd                    (Arjan van de Ven)
+  - page waitqueue cleanup                                (Christoph Hellwig)
+rmap 11c:
+  - oom_kill race locking fix                             (Andres Salomon)
+  - elevator improvement                                  (Andrew Morton)
+  - dirty buffer writeout speedup (hopefully ;))          (me)
+  - small documentation updates                           (me)
+  - page_launder() never does synchronous IO, kswapd
+    and the processes calling it sleep on higher level    (me)
+  - deadlock fix in touch_page()                          (me)
+rmap 11b:
+  - added low latency reschedule points in vmscan.c       (me)
+  - make i810_dma.c include mm_inline.h too               (William Lee Irwin)
+  - wake up kswapd sleeper tasks on OOM kill so the
+    killed task can continue on its way out               (me)
+  - tune page allocation sleep point a little             (me)
+rmap 11a:
+  - don't let refill_inactive() progress count for OOM    (me)
+  - after an OOM kill, wait 5 seconds for the next kill   (me)
+  - agpgart_be fix for hashed waitqueues                  (William Lee Irwin)
+rmap 11:
+  - fix stupid logic inversion bug in wakeup_kswapd()     (Andrew Morton)
+  - fix it again in the morning                           (me)
+  - add #ifdef BROKEN_PPC_PTE_ALLOC_ONE to rmap.h, it
+    seems PPC calls pte_alloc() before mem_map[] init     (me)
+  - disable the debugging code in rmap.c ... the code
+    is working and people are running benchmarks          (me)
+  - let the slab cache shrink functions return a value
+    to help prevent early OOM killing                     (Ed Tomlinson)
+  - also, don't call the OOM code if we have enough
+    free pages                                            (me)
+  - move the call to lru_cache_del into __free_pages_ok   (Ben LaHaise)
+  - replace the per-page waitqueue with a hashed
+    waitqueue, reduces size of struct page from 64
+    bytes to 52 bytes (48 bytes on non-highmem machines)  (William Lee Irwin)
+rmap 10:
+  - fix the livelock for real (yeah right), turned out
+    to be a stupid bug in page_launder_zone()             (me)
+  - to make sure the VM subsystem doesn't monopolise
+    the CPU, let kswapd and some apps sleep a bit under
+    heavy stress situations                               (me)
+  - let __GFP_HIGH allocations dig a little bit deeper
+    into the free page pool, the SCSI layer seems fragile (me)
+rmap 9:
+  - improve comments all over the place                   (Michael Cohen)
+  - don't panic if page_remove_rmap() cannot find the
+    rmap in question, it's possible that the memory was
+    PG_reserved and belonging to a driver, but the driver
+    exited and cleared the PG_reserved bit                (me)
+  - fix the VM livelock by replacing > by >= in a few
+    critical places in the pageout code                   (me)
+  - treat the reclaiming of an inactive_clean page like
+    allocating a new page, calling try_to_free_pages()
+    and/or fixup_freespace() if required                  (me)
+  - when low on memory, don't make things worse by
+    doing swapin_readahead                                (me)
+rmap 8:
+  - add ANY_ZONE to the balancing functions to improve
+    kswapd's balancing a bit                              (me)
+  - regularize some of the maximum loop bounds in
+    vmscan.c for cosmetic purposes                        (William Lee Irwin)
+  - move page_address() to architecture-independent
+    code, now the removal of page->virtual is portable    (William Lee Irwin)
+  - speed up free_area_init_core() by doing a single
+    pass over the pages and not using atomic ops          (William Lee Irwin)
+  - documented the buddy allocator in page_alloc.c        (William Lee Irwin)
+rmap 7:
+  - clean up and document vmscan.c                        (me)
+  - reduce size of page struct, part one                  (William Lee Irwin)
+  - add rmap.h for other archs (untested, not for ARM)    (me)
+rmap 6:
+  - make the active and inactive_dirty list per zone,
+    this is finally possible because we can free pages
+    based on their physical address                       (William Lee Irwin)
+  - cleaned up William's code a bit                       (me)
+  - turn some defines into inlines and move those to
+    mm_inline.h (the includes are a mess ...)             (me)
+  - improve the VM balancing a bit                        (me)
+  - add back inactive_target to /proc/meminfo             (me)
+rmap 5:
+  - fixed recursive buglet, introduced by directly
+    editing the patch for making rmap 4 ;)))              (me)
+rmap 4:
+  - look at the referenced bits in page tables            (me)
+rmap 3:
+  - forgot one FASTCALL definition                        (me)
+rmap 2:
+  - teach try_to_unmap_one() about mremap()               (me)
+  - don't assign swap space to pages with buffers         (me)
+  - make the rmap.c functions FASTCALL / inline           (me)
+rmap 1:
+  - fix the swap leak in rmap 0                           (Dave McCracken)
+rmap 0:
+  - port of reverse mapping VM to 2.4.16                  (me)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/CREDITS linux.20pre10-ac2/CREDITS
--- linux.20pre10/CREDITS	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/CREDITS	2002-10-10 23:53:35.000000000 +0100
@@ -1065,6 +1065,11 @@
 D: Transformed old user space bdflush into 1st kernel thread - kflushd.
 D: Many other patches, documentation files, mini kernels, utilities, ...
 
+N: Masanori GOTO
+E: gotom@debian.or.jp
+D: Workbit NinjaSCSI-32Bi/UDE driver
+S: Japan
+
 N: John E. Gotts
 E: jgotts@linuxsavvy.com
 D: kernel hacker
@@ -1888,7 +1893,8 @@
 E: pavel@ucw.cz
 E: pavel@suse.cz
 D: Softcursor for vga, hypertech cdrom support, vcsa bugfix, nbd
-D: sun4/330 port, capabilities for elf, speedup for rm on ext2, USB
+D: sun4/330 port, capabilities for elf, speedup for rm on ext2, USB,
+D: x86-64 port, software suspend
 S: Volkova 1131
 S: 198 00 Praha 9
 S: Czech Republic
@@ -2541,6 +2547,12 @@
 S: 7000 Stuttgart 50
 S: Germany
 
+N: Andrew Rodland
+E: arodland@linuxguru.net
+D: That crazy morse code thing.
+P: D2B1 5215 B1B9 18E0 B6AD  6ADD 4373 165F 1770 BD5C
+S: Pennsylvania, USA
+
 N: Christoph Rohland
 E: hans-christoph.rohland@sap.com
 E: ch.rohland@gmx.net
@@ -3282,6 +3294,12 @@
 S: Socorro NM, 87801
 S: USA
 
+N: Hiroshi YOKOTA
+E: yokota@netlab.is.tsukuba.ac.jp
+D: Workbit NinjaSCSI-3/32Bi PCMCIA driver
+D: Workbit NinjaSCSI-32Bi/UDE driver
+S: Japan
+
 N: Eric Youngdale
 E: eric@andante.org
 W: http://www.andante.org
@@ -3322,14 +3340,10 @@
 S: Germany
 
 N: Leonard N. Zubkoff
-E: lnz@dandelion.com
 W: http://www.dandelion.com/Linux/
 D: BusLogic SCSI driver
 D: Mylex DAC960 PCI RAID driver
 D: Miscellaneous kernel fixes
-S: 3078 Sulphur Spring Court
-S: San Jose, California 95148
-S: USA
 
 N: Alessandro Zummo
 E: azummo@ita.flashnet.it
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/Documentation/Configure.help linux.20pre10-ac2/Documentation/Configure.help
--- linux.20pre10/Documentation/Configure.help	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/Documentation/Configure.help	2002-10-11 00:22:21.000000000 +0100
@@ -230,22 +230,6 @@
   network and embedded applications.  For more information see the
   Axis Communication site, <http://developer.axis.com/>.
 
-Unsynced TSC support
-CONFIG_X86_TSC_DISABLE
-  This option is used for getting Linux to run on a NUMA multi-node 
-  boxes, laptops and other systems suffering from unsynced TSCs or 
-  TSC drift, which can cause gettimeofday to return non-monotonic values. 
-  Choosing this option will disable the CONFIG_X86_TSC optimization,
-  and allows you to then specify "notsc" as a boot option regardless of 
-  which processor you have compiled for. 
-  
-  NOTE: If your system hangs when init should run, you are probably
-  using a i686 compiled glibc which reads the TSC without checking for 
-  availability. Boot without "notsc" and install a i386 compiled glibc 
-  to solve the problem.
-
-  If unsure, say N.
-
 Multiquad support for NUMA systems
 CONFIG_MULTIQUAD
   This option is used for getting Linux to run on a (IBM/Sequent) NUMA 
@@ -456,8 +440,14 @@
   The initial RAM disk is a RAM disk that is loaded by the boot loader
   (loadlin or lilo) and that is mounted as root before the normal boot
   procedure. It is typically used to load modules needed to mount the
-  "real" root file system, etc. See <file:Documentation/initrd.txt>
-  for details.
+  "real" root file system, etc.
+
+  Due to a problem elsewhere in the kernel, initial RAM disks _must_
+  have the file system on them created with a 1024 byte block size.
+  If any other value is used, the kernel will be unable to mount the
+  RAM disk at boot time, causing a kernel panic.
+
+  See <file:Documentation/initrd.txt> for details.
 
 Loopback device support
 CONFIG_BLK_DEV_LOOP
@@ -1114,10 +1104,10 @@
   This effect can be also invoked by calling "idex=ata66"
   If unsure, say N.
 
-CMD64X and CMD680 chipset support
+CMD64X/CMD680 chipset support
 CONFIG_BLK_DEV_CMD64X
   Say Y here if you have an IDE controller which uses any of these
-  chipsets: CMD643, CMD646, CMD648, CMD649 or CMD680.
+  chipsets: CMD643, CMD646, CMD648 or CMD680.
 
 CY82C693 chipset support
 CONFIG_BLK_DEV_CY82C693
@@ -1822,6 +1812,20 @@
   want), say M here and read <file:Documentation/modules.txt>.  The
   module will be called lvm-mod.o.
 
+Device-mapper support
+CONFIG_BLK_DEV_DM
+  Device-mapper is a low level volume manager.  It works by allowing
+  people to specify mappings for ranges of logical sectors.  Various
+  mapping types are available, in addition people may write their own
+  modules containing custom mappings if they wish.
+
+  Higher level volume managers such as LVM2 use this driver.
+
+  If you want to compile this as a module, say M here and read 
+  <file:Documentation/modules.txt>.  The module will be called dm-mod.o.
+
+  If unsure, say N.
+
 Multiple devices driver support (RAID and LVM)
 CONFIG_MD
   Support multiple physical spindles through a single logical device.
@@ -4563,14 +4567,11 @@
   BIOS routines contained in a ROM chip in HP PA-RISC based machines.
   Enabling this option will implement the linux framebuffer device and
   an fbcon color text console using calls to the STI BIOS routines.
-  The HP framebuffer device is usually planar, uses a strange memory
+  The HP framebuffer device is sometimes planar, using a strange memory
   layout, and changing the plane mask to create colored pixels
-  requires a call to the STI routines, so do not expect /dev/fb to
-  actually be useful.  However, it is the best we have as far as
-  graphics on the HP chipsets due to lack of hardware level
-  documentation for the various on-board HP chipsets used in these
-  systems.  It is sufficient for basic text console functions,
-  including fonts.
+  can require a call to the STI routines, so /dev/fb may not actually 
+  be useful.  However, on some systems packed pixel formats are supported.  
+  It is sufficient for basic text console functions, including fonts.
 
   You should probably enable this option, unless you are having
   trouble getting video when booting the kernel (make sure it isn't
@@ -4708,12 +4709,11 @@
   messages. Most people will want to say N here. If unsure, you will
   also want to say N.
 
-Matrox unified accelerated driver
 CONFIG_FB_MATROX
-  Say Y here if you have a Matrox Millennium, Millennium II, Mystique,
-  Mystique 220, Productiva G100, Mystique G200, Millennium G200,
-  Matrox G400, G450 or G550 card in your box. At this time, support for 
-  the G-series digital output is almost non-existant.
+  Say Y here if you have a Matrox Millennium, Matrox Millennium II,
+  Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox
+  Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video,
+  Matrox G400, G450 or G550 card in your box.
 
   This driver is also available as a module ( = code which can be
   inserted and removed from the running kernel whenever you want).
@@ -4724,7 +4724,6 @@
   module load time. The parameters look like "video=matrox:XXX", and
   are described in <file:Documentation/fb/matroxfb.txt>.
 
-Matrox Millennium I/II support
 CONFIG_FB_MATROX_MILLENIUM
   Say Y here if you have a Matrox Millennium or Matrox Millennium II
   video card. If you select "Advanced lowlevel driver options" below,
@@ -4732,7 +4731,6 @@
   packed pixel, 24 bpp packed pixel and 32 bpp packed pixel. You can
   also use font widths different from 8.
 
-Matrox Mystique support
 CONFIG_FB_MATROX_MYSTIQUE
   Say Y here if you have a Matrox Mystique or Matrox Mystique 220
   video card. If you select "Advanced lowlevel driver options" below,
@@ -4740,27 +4738,46 @@
   packed pixel and 32 bpp packed pixel. You can also use font widths
   different from 8.
 
-Matrox G100/G200/G400/G450/G550 support
-CONFIG_FB_MATROX_G100
-  Say Y here if you have a Matrox G100, G200, G400, G450, or G550
-  based video card. If you select "Advanced lowlevel driver options",
-  you should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp
-  packed pixel and 32 bpp packed pixel. You can also use font widths
+CONFIG_FB_MATROX_G450
+  Say Y here if you have a Matrox G100, G200, G400, G450 or G550 based
+  video card. If you select "Advanced lowlevel driver options", you
+  should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed
+  pixel and 32 bpp packed pixel. You can also use font widths
   different from 8.
 
   If you need support for G400 secondary head, you must first say Y to
   "I2C support" and "I2C bit-banging support" in the character devices
   section, and then to "Matrox I2C support" and "G400 second head
-  support" here in the framebuffer section.
+  support" here in the framebuffer section. G450/G550 secondary head
+  and digital output are supported without additional modules.
+  
+  The driver starts in monitor mode. You must use the matroxset tool 
+  (available at <ftp://platan.vc.cvut.cz/pub/linux/matrox-latest/>) to 
+  swap primary and secondary head outputs, or to change output mode.  
+  Secondary head driver always start in 640x480 resolution and you 
+  must use fbset to change it.
+
+  Do not forget that second head supports only 16 and 32 bpp
+  packed pixels, so it is a good idea to compile them into the kernel
+  too. You can use only some font widths, as the driver uses generic
+  painting procedures (the secondary head does not use acceleration
+  engine).
   
-  If you have G550, you must also compile support for G450/G550 secondary
-  head into kernel, otherwise picture will be shown only on the output you
-  are probably not using...
+  G450/G550 hardware can display TV picture only from secondary CRTC,
+  and it performs no scaling, so picture must have 525 or 625 lines.
+
+CONFIG_FB_MATROX_G100A
+  Say Y here if you have a Matrox G100, G200 or G400 based
+  video card. If you select "Advanced lowlevel driver options", you
+  should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed
+  pixel and 32 bpp packed pixel. You can also use font widths
+  different from 8.
 
-  If you need support for G450 or G550 secondary head, say Y to
-  "Matrox G450/G550 second head support" below.
+  If you need support for G400 secondary head, you must first say Y to
+  "I2C support" and "I2C bit-banging support" in the character devices
+  section, and then to "Matrox I2C support" and "G400 second head
+  support" here in the framebuffer section.
 
-Matrox I2C support
 CONFIG_FB_MATROX_I2C
   This drivers creates I2C buses which are needed for accessing the
   DDC (I2C) bus present on all Matroxes, an I2C bus which
@@ -4774,7 +4791,6 @@
   If you compile it as module, it will create a module named
   i2c-matroxfb.o.
 
-Matrox G400 second head support
 CONFIG_FB_MATROX_MAVEN
   WARNING !!! This support does not work with G450 !!!
 
@@ -4803,32 +4819,14 @@
   painting procedures (the secondary head does not use acceleration
   engine).
 
-Matrox G450 second head support
-CONFIG_FB_MATROX_G450
-  Say Y or M here if you want to use a secondary head (meaning two
-  monitors in parallel) on G450, or if you are using analog output
-  of G550.
-
-  If you compile it as module, two modules are created,
-  matroxfb_crtc2.o and matroxfb_g450.o. Both modules are needed if you
-  want two independent display devices.
-
-  The driver starts in monitor mode and currently does not support
-  output in TV modes.  You must use the matroxset tool (available
-  at <ftp://platan.vc.cvut.cz/pub/linux/matrox-latest/>) to swap
-  primary and secondary head outputs.  Secondary head driver always
-  start in 640x480 resolution and you must use fbset to change it.
-
-  Note on most G550 cards the analog output is the secondary head,
-  so you will need to say Y here to use it.
-
-  Also do not forget that second head supports only 16 and 32 bpp
-  packed pixels, so it is a good idea to compile them into the kernel
-  too. You can use only some font widths, as the driver uses generic
-  painting procedures (the secondary head does not use acceleration
-  engine).
-
-Matrox unified driver multihead support
+CONFIG_FB_MATROX_PROC
+  Say Y or M here if you want to access some informations about driver
+  state through /proc interface.
+  
+  You should download matrox_pins tool (available at
+  <ftp://platan.vc.cvut.cz/pub/linux/matrox-latest/>) to get human
+  readable output.
+  
 CONFIG_FB_MATROX_MULTIHEAD
   Say Y here if you have more than one (supported) Matrox device in
   your computer and you want to use all of them for different monitors
@@ -5274,6 +5272,19 @@
   replacement for kerneld.) Say Y here and read about configuring it
   in <file:Documentation/kmod.txt>.
 
+Kernel .config file saved in kernel image
+CONFIG_IKCONFIG
+  This option enables the complete Linux kernel ".config" file contents
+  to be saved in the kernel (zipped) image file.  It provides
+  documentation of which kernel options are used in a running kernel or
+  in an on-disk kernel.  It can be extracted from the kernel image file
+  with a script and used as input to rebuild the current kernel or to
+  build another kernel.  Since the kernel image is zipped, using this
+  option adds approximately 8 KB to a kernel image file.
+  This option is not available as a module.  If you want a separate
+  file to save the kernel's .config contents, use 'installkernel' or 'cp'
+  or a similar tool, or just save it in '/lib/modules/<kernel-version>'.
+
 ARP daemon support
 CONFIG_ARPD
   Normally, the kernel maintains an internal cache which maps IP
@@ -6305,6 +6316,12 @@
   This is a Logical Link Layer protocol used for X.25 connections over
   Ethernet, using ordinary Ethernet cards.
 
+ANSI/IEEE 802.2 Data link layer User Interface SAPs (EXPERIMENTAL)
+CONFIG_LLC_UI
+  LLC User Interface SAPs is a Linux socket interface into the LLC datalink
+  layer. This allows a user to create entire user space network layers tied
+  to a real SAP.
+
 Frame Diverter
 CONFIG_NET_DIVERT
   The Frame Diverter allows you to divert packets from the
@@ -7907,6 +7924,17 @@
 
   The common answer here is N, but answering Y is safe.
 
+Workbit NinjaSCSI-32Bi/UDE support
+CONFIG_SCSI_NSP32
+  This is support for the Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus
+  SCSI host adapter. Please read the SCSI-HOWTO, available from
+  <http://www.linuxdoc.org/docs.html#howto>.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>.  The module
+  will be called nsp32.o.
+
 IBMMCA SCSI support
 CONFIG_SCSI_IBMMCA
   This is support for the IBM SCSI adapter found in many of the PS/2
@@ -9086,13 +9114,13 @@
 Aironet 4500/4800 I365 broken support
 CONFIG_AIRONET4500_I365
   If you have a PCMCIA Aironet 4500/4800 card which you want to use
-  without the standard PCMCIA cardservices provided by the pcmcia-cs
+  without the standard PCMCIA card provided by the pcmcia-cs
   package, say Y here. This is not recommended, so say N.
 
 Aironet 4500/4800 PCMCIA support
 CONFIG_AIRONET4500_CS
   Say Y here if you have a PCMCIA Aironet 4500/4800 card which you
-  want to use with the standard PCMCIA cardservices provided by the
+  want to use with the standard PCMCIA card provided by the
   pcmcia-cs package.
 
   This driver is also available as a module ( = code which can be
@@ -12642,12 +12670,44 @@
 Quota support
 CONFIG_QUOTA
   If you say Y here, you will be able to set per user limits for disk
-  usage (also called disk quotas). Currently, it works only for the
-  ext2 file system. You need additional software in order to use quota
-  support; for details, read the Quota mini-HOWTO, available from
+  usage (also called disk quotas). Currently, it works for the
+  ext2, ext3, and reiserfs file system. You need additional software
+  in order to use quota support (you can download sources from
+  <http://www.sf.net/projects/linuxquota/>). For further details, read
+  the Quota mini-HOWTO, available from
   <http://www.tldp.org/docs.html#howto>. Probably the quota
   support is only useful for multi user systems. If unsure, say N.
 
+Old quota format support
+CONFIG_QFMT_V1
+  This quota format was (is) used by kernels earlier than 2.4.??. If
+  you have quota working and you don't want to convert to new quota
+  format say Y here.
+
+VFS v0 quota format support
+CONFIG_QFMT_V2
+  This quota format allows using quotas with 32-bit UIDs/GIDs. If you
+  need this functionality say Y here. Note that you will need latest
+  quota utilities for new quota format with this kernel.
+
+Compatible quota interfaces
+CONFIG_QIFACE_COMPAT
+  This option will enable old quota interface in kernel.
+  If you have old quota tools (version <= 3.04) and you don't want to
+  upgrade them say Y here.
+
+Original quota interface
+CONFIG_QIFACE_V1
+  This is the oldest quota interface. It was used for old quota format.
+  If you have old quota tools and you use old quota format choose this
+  interface (if unsure, this interface is the best one to choose).
+
+VFS v0 quota interface
+CONFIG_QIFACE_V2
+  This quota interface was used by VFS v0 quota format. If you need
+  support for VFS v0 quota format (eg. you're using quota on ReiserFS)
+  and you don't want to upgrade quota tools, choose this interface.
+
 Memory Technology Device (MTD) support
 CONFIG_MTD
   Memory Technology Devices are flash, RAM and similar chips, often
@@ -15162,6 +15222,35 @@
   debugging output from the driver. This is unlike previous versions
   of the driver, where enabling this option would turn on debugging
   output automatically.
+  
+  Example:
+  mount -t befs /dev/hda2 /mnt -o debug
+
+BeOS filesystem support (BeFS) (read only)
+CONFIG_BEFS_FS
+  The BeOS File System (BeFS) is the native file system of Be, Inc's
+  BeOS. Notable features include support for arbitrary attributes
+  on files and directories, and database-like indices on selected
+  attributes. (Also note that this driver doesn't make those features
+  available at this time). It is a 64 bit filesystem, so it supports
+  extremely large volumes and files.
+
+  If you use this filesystem, you should also say Y to at least one
+  of the NLS (native language support) options below.
+
+  If you don't know what this is about, say N.
+
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called befs.o.
+
+Debug BeFS
+CONFIG_BEFS_DEBUG
+  If you say Y here, you can use the 'debug' mount option to enable
+  debugging output from the driver. This is unlike previous versions
+  of the driver, where enabling this option would turn on debugging
+  output automatically.
 
   Example:
   mount -t befs /dev/hda2 /mnt -o debug
@@ -15565,6 +15654,30 @@
 
   If unsure, say N.
 
+Allow direct I/O on files in NFS
+CONFIG_NFS_DIRECTIO
+  There are important applications whose performance or correctness
+  depends on uncached access to file data.  Database clusters (multiple
+  copies of the same instance running on separate hosts) implement their
+  own cache coherency protocol that subsumes the NFS cache protocols.
+  Applications that process datasets considerably larger than the client's
+  memory do not always benefit from a local cache.  A streaming video
+  server, for instance, has no need to cache the contents of a file.
+
+  This option enables applications to perform direct I/O on files in NFS
+  file systems using the O_DIRECT open() flag.  When O_DIRECT is set for
+  files, their data is not cached in the system's page cache.  Direct
+  read and write operations are aligned to block boundaries.  Data is
+  moved to and from user-level application buffers directly.
+
+  Unless your program is designed to use O_DIRECT properly, you are much
+  better off allowing the NFS client to manage caching for you.  Misusing
+  O_DIRECT can cause poor server performance or network storms.  This
+  kernel build option defaults OFF to avoid exposing system administrators
+  unwittingly to a potentially hazardous feature.
+
+  If unsure, say N.
+
 Root file system on NFS
 CONFIG_ROOT_NFS
   If you want your Linux box to mount its whole root file system (the
@@ -15961,7 +16074,7 @@
   Say Y here if you would like to use hard disks under Linux which
   were partitioned on a Macintosh.
 
-Windows Logical Disk Manager (Dynamic Disk) support (EXPERIMENTAL)
+Windows Logical Disk Manager (Dynamic Disk) support
 CONFIG_LDM_PARTITION
   Say Y here if you would like to use hard disks under Linux which
   were partitioned using Windows 2000's or XP's Logical Disk Manager.
@@ -15976,8 +16089,7 @@
   Normal partitions are now called Basic Disks under Windows 2000 and
   XP.
 
-  Technical documentation to accompany this driver is available from:
-  <http://linux-ntfs.sf.net/ldm/>.
+  For a fuller description read <file:Documentation/ldm.txt>.
 
   If unsure, say N.
 
@@ -16050,8 +16162,9 @@
 Intel EFI GUID partition support
 CONFIG_EFI_PARTITION
   Say Y here if you would like to use hard disks under Linux which
-  were partitioned using EFI GPT.  Presently only useful on the
-  IA-64 platform.
+  were partitioned using EFI GPT.  This is the default partition
+  scheme on IA64, and can be used on other platforms when
+  large block device (64-bit block address) support is desired.
 
 Ultrix partition table support
 CONFIG_ULTRIX_PARTITION
@@ -16893,17 +17006,36 @@
 HIL keyboard support
 CONFIG_HIL
   The "Human Interface Loop" is a older, 8-channel USB-like controller
-  used in Hewlett Packard PA-RISC based machines.  There are a few
-  cases where it is seen on PC/MAC architectures as well, usually also
-  manufactured by HP.  This driver is based off MACH and BSD drivers,
-  and implements support for a keyboard attached to the HIL port.
+  used in several Hewlett Packard models.  This driver is based off 
+  MACH and BSD drivers, and implements support for a keyboard attached 
+  to the HIL port, but not for any other types of HIL input devices 
+  like mice or tablets.  However, it has been thoroughly tested and is 
+  stable.
+ 
   Full support for the USB-like functions and non-keyboard channels of
-  the HIL is not provided for in this driver.  There are vestiges of
-  mouse support in the driver, but it is probably not working.  The
-  necessary hardware documentation to fully support the HIL controller
-  and interface it to the linux-input API is lacking.
+  the HIL is currently being added to the PA-RISC port and will
+  be backported to work on the m68k port as well.
 
-  Enable this option if you intend to use a HIL keyboard.
+  Enable this option if you intend to use a HIL keyboard as your
+  primary keyboard and/or do not wish to test the new HIL driver.
+
+HP System Device Controller support
+CONFIG_HP_SDC
+  This option enables supports for the the "System Device Controller",
+  an i8042 carrying microcode to manage a few miscellanous devices
+  on some Hewlett Packard systems.  The SDC itself contains a 10ms
+  resolution timer/clock capable of delivering interrupts on periodic 
+  and one-shot basis.  The SDC may also be connected to a battery-backed
+  real-time clock, a basic audio waveform generator, and an HP-HIL
+  Master Link Controller serving up to seven input devices.
+
+  By itself this option is rather useless, but enabling it will
+  enable selection of drivers for the abovementioned devices.
+  It is, however, incompatible with the old, reliable HIL keyboard
+  driver, and the new HIL driver is experimental, so if you plan to
+  use a HIL keyboard as your primary keyboard, you may wish to
+  keep using that driver until the new HIL drivers have had more 
+  testing.
 
 Include IOP (IIfx/Quadra 9x0) ADB driver
 CONFIG_ADB_IOP
@@ -17213,6 +17345,19 @@
   read <file:Documentation/modules.txt>. The module will be called
   istallion.o.
 
+PDC software console support
+CONFIG_PDC_CONSOLE
+  Saying Y here will enable the software based PDC console to be 
+  used as the system console.  This is useful for machines in 
+  which the hardware based console has not been written yet.  The
+  following steps must be competed to use the PDC console:
+
+    1. create the device entry (mknod /dev/ttyB0 c 60 0)
+    2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0
+    3. Add device ttyB0 to /etc/securetty (if you want to log on as
+         root on this console.)
+    4. Change the kernel command console parameter to: console=ttyB0
+
 Microgate SyncLink adapter support
 CONFIG_SYNCLINK
   Provides support for the SyncLink ISA and PCI multiprotocol serial
@@ -17362,6 +17507,10 @@
   doing that; to actually get it to happen you need to pass the
   option "console=lp0" to the kernel at boot time.
 
+  Note that kernel messages can get lost if the printer is out of
+  paper (or off, or unplugged, or too busy..), but this behaviour
+  can be changed. See drivers/char/lp.c (do this at your own risk).
+
   If the printer is out of paper (or off, or unplugged, or too
   busy..) the kernel will stall until the printer is ready again.
   By defining CONSOLE_LP_STRICT to 0 (at your own risk) you
@@ -18249,7 +18398,7 @@
   determined automatically, so you need to specify it here ONLY if
   running a DEC Alpha, otherwise this setting has no effect.
 
-Double Talk PC internal speech card support
+Double Talk PC internal speech card support 
 CONFIG_DTLK
   This driver is for the DoubleTalk PC, a speech synthesizer
   manufactured by RC Systems (<http://www.rcsys.com/>).  It is also
@@ -18791,6 +18940,12 @@
   <file:Documentation/modules.txt>. The module will be called
   toshiba.o
 
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>. The module will be called
+  toshiba.o
+
   Say Y if you intend to run this kernel on a Toshiba portable.
   Say N otherwise.
 
@@ -19026,10 +19181,11 @@
   The module will be called cs461x.o.  If you want to compile it as a
   module, say M here and read <file:Documentation/modules.txt>.
 
-Aureal Vortex and Trident 4DWave gameports
+Aureal Vortex, Trident 4DWave, and ALi 5451 gameports
 CONFIG_INPUT_PCIGAME
   Say Y here if you have a Trident 4DWave DX/NX or Aureal Vortex 1/2
-  card. For more information on how to use the driver please read
+  card or an ALi 5451 chip on your motherboard. For more information
+  on how to use the driver please read
   <file:Documentation/input/joystick.txt>.
 
   This driver is also available as a module ( = code which can be
@@ -25405,16 +25561,6 @@
   for the zx1 IOMMU and makes root bus bridges appear in PCI config space
   (required for zx1 agpgart support).
 
-CONFIG_IA64_SGI_SN_SIM
-  Build a kernel that runs on both the SGI simulator AND on hardware.
-  There is a very slight performance penalty on hardware for including this
-  option.
-
-CONFIG_IA64_SGI_SN_DEBUG
-  This enables addition debug code that helps isolate
-  platform/kernel bugs. There is a small but measurable performance
-  degradation when this option is enabled.
-
 # Choice: pagesize
 Kernel page size
 CONFIG_IA64_PAGE_SIZE_4KB
@@ -25606,6 +25752,14 @@
   of the BUG call as well as the EIP and oops trace.  This aids
   debugging but costs about 70-100K of memory.
 
+Morse code panics
+CONFIG_PANIC_MORSE
+  Say Y here to receive panic messages in morse code on your keyboard LEDs, and
+  optionally the PC speaker, if available.
+  The kernel param "panicblink" controls this feature, set it to 0 to disable,
+  1 for LEDs only, 2 for pc speaker, or 3 for both. If you disable this option,
+  then you will receive a steady blink on the LEDs instead.
+
 Include kgdb kernel debugger
 CONFIG_KGDB
   Include in-kernel hooks for kgdb, the Linux kernel source level
@@ -25639,9 +25793,11 @@
 
 U2/Uturn I/O MMU
 CONFIG_IOMMU_CCIO
-  Say Y here to enable DMA management routines for the first
-  generation of PA-RISC cache-coherent machines.  Programs the
-  U2/Uturn chip in "Virtual Mode" and use the I/O MMU.
+  The U2/UTurn is a bus converter with io mmu present in the Cxxx, D,
+  J, K, and R class machines.  Compiling this driver into the kernel will
+  not hurt anything, removing it will reduce your kernel by about 14k.
+
+  If unsure, say Y.
 
 LBA/Elroy PCI support
 CONFIG_PCI_LBA
@@ -26014,6 +26170,77 @@
   written) to implement the policy. If you don't understand what this
   is all about, it's safe to say 'N'.
 
+  For more information, take a look at linux/Documentation/cpufreq or
+  at <http://www.brodo.de/cpufreq/>
+
+  If in doubt, say N.
+
+CONFIG_CPU_FREQ_24_API
+  This enables the /proc/sys/cpu/ sysctl interface for controlling
+  CPUFreq, as known from the 2.4.-kernel patches for CPUFreq. 2.5
+  uses /proc/cpufreq instead. Please note that some drivers do not 
+  work with the 2.4. /proc/sys/cpu sysctl interface, so if in doubt,
+  say N here.
+
+  For details, take a look at linux/Documentation/cpufreq. 
+
+  If in doubt, say N.
+
+CONFIG_X86_POWERNOW_K6
+  This adds the CPUFreq driver for mobile AMD K6-2+ and mobile
+  AMD K6-3+ processors.
+
+  For details, take a look at linux/Documentation/cpufreq. 
+
+  If in doubt, say N.
+
+CONFIG_X86_P4_CLOCKMOD
+  This adds the CPUFreq driver for Intel Pentium 4 / XEON
+  processors.
+
+  For details, take a look at linux/Documentation/cpufreq. 
+
+  If in doubt, say N.
+
+CONFIG_ELAN_CPUFREQ
+  This adds the CPUFreq driver for AMD Elan SC400 and SC410
+  processors.
+
+  You need to specify the processor maximum speed as a boot
+  parameter (or as module parameter): 
+  elanfreq=maxspeed
+  with the argument "maxspeed" given in kHz. 
+
+  For details, take a look at linux/Documentation/cpufreq. 
+
+  If in doubt, say N.
+
+CONFIG_X86_LONGHAUL
+  This adds the CPUFreq driver for VIA Samuel/CyrixIII, 
+  VIA Cyrix Samuel/C3, VIA Cyrix Ezra and VIA Cyrix Ezra-T 
+  processors.
+
+  For details, take a look at linux/Documentation/cpufreq. 
+
+  If in doubt, say N.
+
+CONFIG_X86_SPEEDSTEP
+  This adds the CPUFreq driver for certain mobile Intel Pentium III
+  (Coppermine), all mobile Intel Pentium III-M (Tulatin) and all
+  mobile Intel Pentium 4 P4-Ms.
+
+  For details, take a look at linux/Documentation/cpufreq. 
+
+  If in doubt, say N.
+
+CONFIG_X86_LONGRUN
+  This adds the CPUFreq driver for Transmeta Crusoe processors which
+  support LongRun.
+
+  For details, take a look at linux/Documentation/cpufreq. 
+
+  If in doubt, say N.
+
 SiS
 CONFIG_DRM_SIS
   Choose this option if you have a SIS graphics card. AGP support is
@@ -26027,7 +26254,7 @@
 
 Slave has its own LEDs
 CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS
-  Enable if the slave has it's own LEDs.
+  Enable if the slave has its own LEDs.
 
 ATA/IDE support
 CONFIG_ETRAX_IDE
@@ -26197,6 +26424,58 @@
 
   If unsure, say N.
 
+NatSemi SCx200 support
+CONFIG_SCx200
+  This provides basic support for the National Semiconductor SCx200
+  processor.  Right now this is just a driver for the GPIO pins.
+
+  If you don't know what to do here, say N.
+
+  This support is also available as a module.  If compiled as a
+  module, it will be called scx200.o.
+
+NatSemi SCx200 Watchdog
+CONFIG_SCx200_WDT
+  Enable the built-in watchdog timer support on the National 
+  Semiconductor SCx200 processors.
+
+  If compiled as a module, it will be called scx200_watchdog.o.
+
+Flash device mapped with DOCCS on NatSemi SCx200
+CONFIG_MTD_SCx200_DOCFLASH
+  Enable support for a flash chip mapped using the DOCCS signal on a
+  National Semiconductor SCx200 processor.
+
+  If you don't know what to do here, say N.
+
+  If compiled as a module, it will be called scx200_docflash.o.
+
+NatSemi SCx200 I2C using GPIO pins
+CONFIG_SCx200_I2C
+  Enable the use of two GPIO pins of a SCx200 processor as an I2C bus.
+
+  If you don't know what to do here, say N.
+
+  If compiled as a module, it will be called scx200_i2c.o.
+
+GPIO pin used for SCL
+CONFIG_SCx200_I2C_SCL
+  Enter the GPIO pin number used for the SCL signal.  This value can
+  also be specified with a module parameter.
+
+GPIO pin used for SDA
+CONFIG_SCx200_I2C_SDA
+  Enter the GPIO pin number used for the SSA signal.  This value can
+  also be specified with a module parameter.
+
+NatSemi SCx200 ACCESS.bus
+CONFIG_SCx200_ACB
+  Enable the use of the ACCESS.bus controllers of a SCx200 processor.
+
+  If you don't know what to do here, say N.
+
+  If compiled as a module, it will be called scx200_acb.o.
+
 #
 # A couple of things I keep forgetting:
 #   capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet,
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/Documentation/cpufreq linux.20pre10-ac2/Documentation/cpufreq
--- linux.20pre10/Documentation/cpufreq	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/Documentation/cpufreq	2002-09-30 17:24:56.000000000 +0100
@@ -0,0 +1,361 @@
+     CPU frequency and voltage scaling code in the Linux(TM) kernel
+
+
+		         L i n u x    C P U F r e q
+
+
+
+
+		    Dominik Brodowski  <linux@brodo.de>
+		     David Kimdon <dwhedon@debian.org>
+
+
+
+   Clock scaling allows you to change the clock speed of the CPUs on the
+    fly. This is a nice method to save battery power, because the lower
+            the clock speed, the less power the CPU consumes.
+
+
+
+Contents:
+---------
+1.  Supported architectures
+2.  User interface
+2.1   /proc/cpufreq interface  [2.6]
+2.2.  /proc/sys/cpu/ interface [2.4]
+3.  CPUFreq core and interfaces
+3.1   General information
+3.2   CPUFreq notifiers
+3.3   CPUFreq architecture drivers
+4.  Mailing list and Links
+
+
+
+1. Supported architectures
+==========================
+
+ARM:
+    ARM Integrator, SA 1100, SA1110
+--------------------------------
+    This driver will be ported to new CPUFreq core soon, so
+    far it will not work.
+
+
+AMD Elan:
+    SC400, SC410
+--------------------------------
+    You need to specify the highest allowed CPU frequency as 
+    a module parameter ("max_freq") or as boot parameter 
+    ("elanfreq="). Else the available speed range will be 
+    limited to the speed at which the CPU runs while this
+    module is loaded.
+
+
+VIA Cyrix Longhaul:
+    VIA Samuel/CyrixIII, VIA Cyrix Samuel/C3, 
+    VIA Cyrix Ezra, VIA Cyrix Ezra-T
+--------------------------------
+    If you do not want to scale the Front Side Bus or voltage,
+    pass the module parameter "dont_scale_fsb 1" or
+    "dont_scale_voltage 1". Additionally, it is advised that
+    you pass the current Front Side Bus speed (in MHz) to 
+    this module as module parameter "current_fsb", e.g. 
+    "current_fsb 133" for a Front Side Bus speed of 133 MHz.
+
+
+Intel SpeedStep:
+    certain mobile Intel Pentium III (Coppermine), and all mobile
+    Intel Pentium III-M (Tualatin) and mobile Intel Pentium 4 P4-Ms.
+--------------------------------
+    Unfortunately only modern Intel ICH2-M and ICH3-M chipsets are 
+    supported.
+
+
+P4 CPU Clock Modulation:
+    Intel Pentium 4 Xeon processors
+---------------------------------
+    Note that you can only switch the speed of two logical CPUs at
+    once - but each phyiscal CPU may have different throttling levels.
+
+
+PowerNow! K6:
+    mobile AMD K6-2+ / mobile K6-3+:
+--------------------------------
+    No known issues.
+
+
+Transmeta Crusoe Longrun:
+    Transmeta Crusoe processors:
+--------------------------------
+    Does not work with the 2.4. /proc/sys/cpu/ interface.
+
+
+
+2. User Interface
+=================
+
+2.1   /proc/cpufreq interface [2.6]
+***********************************
+
+Starting in the patches for kernel 2.5.33, CPUFreq uses a "policy"
+interface /proc/cpufreq.
+
+When you "cat" this file, you'll find something like:
+
+--
+          minimum CPU frequency  -  maximum CPU frequency  -  policy
+CPU  0       1200000 ( 75%)      -     1600000 (100%)      -  performance
+--
+
+This means the current policy allows this CPU to be run anywhere
+between 1.2 GHz (the value is in kHz) and 1.6 GHz with an eye towards
+performance.
+
+To change the policy, "echo" the desired new policy into
+/proc/cpufreq. Use one of the following formats:
+
+cpu_nr:min_freq:max_freq:policy
+cpu_nr%min_freq%max_freq%policy
+min_freq:max_freq:policy
+min_freq%max_freq%policy
+
+with cpu_nr being the CPU which shall be affected, min_freq and
+max_freq the lower and upper limit of the CPU core frequency in kHz,
+and policy either "performance" or "powersave".
+A few examples:
+
+root@notebook:#echo -n "0:0:0:powersave" > /proc/cpufreq
+     sets the CPU #0 to the lowest supported frequency.
+
+root@notebook:#echo -n "1%100%100%performance" > /proc/cpufreq
+     sets the CPU #1 to the highest supported frequency.
+
+root@notebook:#echo -n "1000000:2000000:performance" > /proc/cpufreq
+     to set the frequency of all CPUs between 1 GHz and 2 GHz and to
+     the policy "performance".
+
+Please note that the values you "echo" into /proc/cpufreq are
+validated first, and may be limited by hardware or thermal
+considerations. Because of this, a read from /proc/cpufreq might 
+differ from what was written into it.
+
+
+When you read /proc/cpufreq for the first time after a CPUFreq driver
+has been initialized, you'll see the "default policy" for this
+driver. If this does not suit your needs, you can pass a boot
+parameter to the cpufreq core. Use the following syntax for this:
+   "cpufreq=min_freq:max_freq:policy", i.e. you may not chose a
+specific CPU and you need to specify the limits in kHz and not in
+per cent.
+
+
+2.2   /proc/cpufreq interface [2.4]
+***********************************
+
+Previsiously (and still available as a config option), CPUFreq used 
+a "sysctl" interface which is located in 
+	/proc/sys/cpu/0/
+	/proc/sys/cpu/1/ ...	(SMP only)
+
+In these directories, you will find three files of importance for
+CPUFreq: speed-max, speed-min and speed: 
+
+speed		    shows the current CPU frequency in kHz, 
+speed-min	    the minimum supported CPU frequency, and
+speed-max	    the maximum supported CPU frequency.
+
+
+To change the CPU frequency, "echo" the desired CPU frequency (in kHz)
+to speed. For example, to set the CPU speed to the lowest/highest
+allowed frequency do:
+
+root@notebook:# cat /proc/sys/cpu/0/speed-min > /proc/sys/cpu/0/speed
+root@notebook:# cat /proc/sys/cpu/0/speed-max > /proc/sys/cpu/0/speed
+
+
+
+3.  CPUFreq core and interfaces
+===============================
+
+3.1   General information
+*************************
+
+The CPUFreq core code is located in linux/kernel/cpufreq.c. This
+cpufreq code offers a standardized interface for the CPUFreq
+architecture drivers (those pieces of code that do actual
+frequency transitions), as well as to "notifiers". These are device
+drivers or other part of the kernel that need to be informed of
+policy changes (like thermal modules like ACPI) or of all
+frequency changes (like timing code) or even need to force certain
+speed limits (like LCD drivers on ARM architecture). Additionally, the
+kernel "constant" loops_per_jiffy is updated on frequency changes
+here.
+
+
+3.2   CPUFreq notifiers
+***********************
+
+CPUFreq notifiers conform to the standard kernel notifier interface.
+See linux/include/linux/notifier.h for details on notifiers.
+
+There are two different CPUFreq notifiers - policy notifiers and
+transition notifiers.
+
+
+3.2.1 CPUFreq policy notifiers
+******************************
+
+These are notified when a new policy is intended to be set. Each
+CPUFreq policy notifier is called three times for a policy transition:
+
+1.) During CPUFREQ_ADJUST all CPUFreq notifiers may change the limit if
+    they see a need for this - may it be thermal considerations or
+    hardware limitations.
+
+2.) During CPUFREQ_INCOMPATIBLE only changes may be done in order to avoid
+    hardware failure.
+
+3.) And during CPUFREQ_NOTIFY all notifiers are informed of the new policy
+   - if two hardware drivers failed to agree on a new policy before this
+   stage, the incompatible hardware shall be shut down, and the user
+   informed of this.
+
+The phase is specified in the second argument to the notifier.
+
+The third argument, a void *pointer, points to a struct cpufreq_policy
+consisting of five values: cpu, min, max, policy and max_cpu_freq. Min 
+and max are the lower and upper frequencies (in kHz) of the new
+policy, policy the new policy, cpu the number of the affected CPU or
+CPUFREQ_ALL_CPUS for all CPUs; and max_cpu_freq the maximum supported
+CPU frequency. This value is given for informational purposes only.
+
+
+3.2.2 CPUFreq transition notifiers
+**********************************
+
+These are notified twice when the CPUfreq driver switches the CPU core
+frequency and this change has any external implications.
+
+The second argument specifies the phase - CPUFREQ_PRECHANGE or
+CPUFREQ_POSTCHANGE.
+
+The third argument is a struct cpufreq_freqs with the following
+values:
+cpu	- number of the affected CPU or CPUFREQ_ALL_CPUS
+old	- old frequency
+new	- new frequency
+
+
+3.3   CPUFreq architecture drivers
+**********************************
+
+CPUFreq architecture drivers are the pieces of kernel code that
+actually perform CPU frequency transitions. These need to be
+initialized separately (separate initcalls), and may be
+modularized. They interact with the CPUFreq core in the following way:
+
+cpufreq_register()
+------------------
+cpufreq_register registers an arch driver to the CPUFreq core. Please
+note that only one arch driver may be registered at any time. -EBUSY
+is returned when an arch driver is already registered. The argument to
+cpufreq_register, struct cpufreq_driver *driver, is described later.
+
+cpufreq_unregister()
+--------------------
+cpufreq_unregister unregisters an arch driver, e.g. on module
+unloading. Please note that there is no check done that this is called
+from the driver which actually registered itself to the core, so
+please only call this function when you are sure the arch driver got
+registered correctly before.
+
+cpufreq_notify_transition()
+---------------------------
+On "dumb" hardware where only fixed frequency can be set, the driver
+must call cpufreq_notify_transition() once before, and once after the
+actual transition.
+
+struct cpufreq_driver
+---------------------
+On initialization, the arch driver is supposed to pass a pointer
+to a struct cpufreq_driver *cpufreq_driver consisting of the following
+entries:
+
+cpufreq_verify_t verify: This is a pointer to a function with the
+	following definition:
+	void verify_function (struct cpufreq_policy *policy).
+	This function must verify the new policy is within the limits
+	supported by the CPU, and at least one supported CPU is within
+	this range. It may be useful to use cpufreq.h /
+	cpufreq_verify_within_limits for this.
+
+cpufreq_setpolicy_t setpolicy: This is a pointer to a function with
+	the following definition:
+	void setpolicy_function (struct cpufreq_policy *policy).
+	This function must set the CPU to the new policy. If it is a
+	"dumb" CPU which only allows fixed frequencies to be set, it
+	shall set it to the lowest within the limit for
+	CPUFREQ_POLICY_POWERSAVE, and to the highest for
+	CPUFREQ_POLICY_PERFORMANCE. Once CONFIG_CPU_FREQ_DYNAMIC is
+	implemented, it can use a dynamic method to adjust the speed
+	between the lower and upper limit.
+
+struct cpufreq_policy   *policy: This is an array of NR_CPUS struct
+	cpufreq_policies, containing the current policies set for these
+	CPUs. Note that policy[0].max_cpu_freq must contain the
+	absolute maximum CPU frequency supported by _all_ CPUs.
+
+In case the driver is expected to run with the 2.4.-style API
+(/proc/sys/cpu/.../), two more values must be passed
+#ifdef CONFIG_CPU_FREQ_24_API
+	unsigned int            cpu_min_freq;
+	unsigned int            cpu_cur_freq[NR_CPUS];
+#endif
+	with cpu_min_freq being the minimum CPU frequency supported by
+	the CPUs; and the entries in cpu_cur_freq reflecting the
+	current speed of the appropriate CPU.
+
+Some Requirements to CPUFreq architecture drivers
+-------------------------------------------------
+* Only call cpufreq_register() when the ability to switch CPU
+  frequencies is _verified_ or can't be missing
+* cpufreq_unregister() may only be called if cpufreq_register() has
+  been successfully(!) called before.
+* kfree() the struct cpufreq_driver only after the call to 
+  cpufreq_unregister(), unless cpufreq_register() failed.
+* Be aware that there is currently no error management in the
+  setpolicy() code in the CPUFreq core. So only call yourself a
+  cpufreq_driver if you are really a working cpufreq_driver!
+
+
+
+4. Mailing list and Links
+*************************
+
+
+Mailing List
+------------
+There is a CPU frequency changing CVS commit and general list where
+you can report bugs, problems or submit patches. To post a message,
+send an email to cpufreq@www.linux.org.uk, to subscribe go to
+http://www.linux.org.uk/mailman/listinfo/cpufreq. Previous post to the
+mailing list are available to subscribers at
+http://www.linux.org.uk/mailman/private/cpufreq/.
+
+
+Links
+-----
+the FTP archives:
+* ftp://ftp.linux.org.uk/pub/linux/cpufreq/
+
+how to access the CVS repository:
+* http://cvs.arm.linux.org.uk/
+
+the CPUFreq Mailing list:
+* http://www.linux.org.uk/mailman/listinfo/cpufreq
+
+Clock and voltage scaling for the SA-1100:
+* http://www.lart.tudelft.nl/projects/scaling
+
+CPUFreq project homepage
+* http://www.brodo.de/cpufreq/
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/Documentation/filesystems/ramfs.txt linux.20pre10-ac2/Documentation/filesystems/ramfs.txt
--- linux.20pre10/Documentation/filesystems/ramfs.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/Documentation/filesystems/ramfs.txt	2002-08-06 15:42:23.000000000 +0100
@@ -0,0 +1,47 @@
+	ramfs - An automatically resizing memory based filesystem
+
+
+  Ramfs is a file system which keeps all files in RAM. It allows read
+  and write access. In contrast to RAM disks, which get allocated a
+  fixed amount of RAM, ramfs grows and shrinks to accommodate the
+  files it contains.
+
+  You can mount the ramfs with:
+      mount -t ramfs none /mnt/wherever
+
+  Then just create and use files. When the filesystem is unmounted, all
+  its contents are lost.
+
+  NOTE! This filesystem is probably most useful not as a real
+  filesystem, but as an example of how virtual filesystems can be
+  written.
+
+Resource limits:
+
+By default a ramfs will be limited to using half of (physical) memory
+for storing file contents, a bit over that when the metadata is
+included. The resource usage limits of ramfs can be controlled with
+the following mount options:
+
+	maxsize=NNN
+		Sets the maximum allowed memory usage of the
+filesystem to NNN kilobytes. This will be rounded down to a multiple
+of the page size. The default is half of physical memory. NB.  unlike
+most of the other limits, setting this to zero does *not* mean no
+limit, but will actually limit the size of the filesystem data to zero
+pages. There might be a use for this in some perverse situation.
+	
+	maxfilesize=NNN
+		Sets the maximum size of a single file on the
+filesystem to NNN kilobytes. This will be rounded down to a multiple
+of the page size. If NNN=0 there is no limit. The default is no limit.
+
+       maxdentries=NNN
+		Sets the maximum number of directory entries (hard
+links) on the filesystem to NNN. If NNN=0 there is no limit. By
+default this is set to maxsize/4.
+
+	maxinodes=NNN
+		Sets the maximum number of inodes (i.e. distinct
+files) on the filesystem to NNN. If NNN=0 there is no limit. The
+default is no limit (but there can never be more inodes than dentries).
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/Documentation/kernel-parameters.txt linux.20pre10-ac2/Documentation/kernel-parameters.txt
--- linux.20pre10/Documentation/kernel-parameters.txt	2002-10-09 21:37:05.000000000 +0100
+++ linux.20pre10-ac2/Documentation/kernel-parameters.txt	2002-09-29 20:04:19.000000000 +0100
@@ -23,6 +23,7 @@
 	HW	Appropriate hardware is enabled.
 	IA-32	IA-32 aka i386 architecture is enabled.
 	IA-64	IA-64 architecture is enabled.
+	IP_PNP	IP DCHP, BOOTP, or RARP is enabled.
 	ISAPNP  ISA PnP code is enabled.
 	ISDN	Appropriate ISDN support is enabled.
 	JOY 	Appropriate joystick support is enabled.
@@ -251,7 +252,7 @@
 
 	initrd=		[BOOT] Specify the location of the initial ramdisk. 
 
-	ip=		[PNP]
+	ip=		[IP_PNP]
 
 	isapnp=		[ISAPNP] Specify RDP, reset, pci_scan and verbosity.
 
@@ -273,10 +274,14 @@
  
 	kbd-reset	[VT]
 
-	keep_initrd	[HW, ARM]
+	keepinitrd	[HW, ARM]
 
 	load_ramdisk=	[RAM] List of ramdisks to load from floppy.
 
+	lockd.udpport=	[NFS]
+
+	lockd.tcpport=	[NFS]
+
 	logi_busmouse=	[HW, MOUSE]
 
 	lp=0		[LP]	Specify parallel ports to use, e.g,
@@ -313,7 +318,7 @@
 
 	max_scsi_luns=	[SCSI]
 
-	mca-pentium	[BUGS=ix86]
+	mca-pentium	[BUGS=IA-32]
 
 	mcd=		[HW,CD]
 
@@ -327,6 +332,11 @@
 
 	megaraid=	[HW,SCSI]
  
+	mem=exactmap	[KNL,BOOT,IA-32] enable setting of an exact
+			e820 memory map, as specified by the user.
+			Such mem=exactmap lines can be constructed
+			based on BIOS output or other requirements.
+
 	mem=nn[KMG]	[KNL,BOOT] force use of a specific amount of
 			memory; to be used when the kernel is not able
 			to see the whole system memory or for test.
@@ -359,9 +369,9 @@
 
 	nfsroot=	[NFS] nfs root filesystem for disk-less boxes.
 
-	nmi_watchdog=	[KNL,BUGS=ix86] debugging features for SMP kernels.
+	nmi_watchdog=	[KNL,BUGS=IA-32] debugging features for SMP kernels.
 
-	no387		[BUGS=ix86] Tells the kernel to use the 387 maths
+	no387		[BUGS=IA-32] Tells the kernel to use the 387 maths
 			emulation library even if a 387 maths coprocessor
 			is present.
 
@@ -379,7 +389,9 @@
 
 	nohlt		[BUGS=ARM]
  
-	no-hlt		[BUGS=ix86]
+	no-hlt		[BUGS=IA-32] Tells the kernel that the hlt
+			instruction doesn't work correctly and not to
+			use it.
 
 	noht		[SMP,IA-32] Disables P4 Xeon(tm) HyperThreading.
 
@@ -396,7 +408,7 @@
 
 	nosync		[HW, M68K] Disables sync negotiation for all devices.
 
-	notsc           [BUGS=ix86] Disable Time Stamp Counter
+	notsc           [BUGS=IA-32] Disable Time Stamp Counter
 
 	nowb		[ARM]
  
@@ -504,7 +516,7 @@
 	ramdisk_start=	[RAM] Starting block of RAM disk image (so you can
 			place it after the kernel image on a boot floppy).
 
-	reboot=		[BUGS=ix86]
+	reboot=		[BUGS=IA-32]
 
 	reserve=	[KNL,BUGS] force the kernel to ignore some iomem area.
 
@@ -514,6 +526,10 @@
 
 	root=		[KNL] root filesystem.
 
+	rootflags=	[KNL] set root filesystem mount option string
+
+	rootfstype=	[KNL] set root filesystem type
+
 	rw		[KNL] Mount root device read-write on boot.
 
 	S		[KNL] run init in single mode.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/Documentation/sched-coding.txt linux.20pre10-ac2/Documentation/sched-coding.txt
--- linux.20pre10/Documentation/sched-coding.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/Documentation/sched-coding.txt	2002-09-12 13:52:19.000000000 +0100
@@ -0,0 +1,129 @@
+     Reference for various scheduler-related methods in the O(1) scheduler
+		Robert Love <rml@tech9.net>, MontaVista Software
+
+
+Note most of these methods are local to kernel/sched.c - this is by design.
+The scheduler is meant to be self-contained and abstracted away.  This document
+is primarily for understanding the scheduler, not interfacing to it.  Some of
+the discussed interfaces, however, are general process/scheduling methods.
+They are typically defined in include/linux/sched.h.
+
+
+Main Scheduling Methods
+-----------------------
+
+void load_balance(runqueue_t *this_rq, int idle)
+	Attempts to pull tasks from one cpu to another to balance cpu usage,
+	if needed.  This method is called explicitly if the runqueues are
+	inbalanced or periodically by the timer tick.  Prior to calling,
+	the current runqueue must be locked and interrupts disabled.
+
+void schedule()
+	The main scheduling function.  Upon return, the highest priority
+	process will be active.
+
+
+Locking
+-------
+
+Each runqueue has its own lock, rq->lock.  When multiple runqueues need
+to be locked, lock acquires must be ordered by ascending &runqueue value.
+
+A specific runqueue is locked via
+
+	task_rq_lock(task_t pid, unsigned long *flags)
+
+which disables preemption, disables interrupts, and locks the runqueue pid is
+running on.  Likewise,
+
+	task_rq_unlock(task_t pid, unsigned long *flags)
+
+unlocks the runqueue pid is running on, restores interrupts to their previous
+state, and reenables preemption.
+
+The routines
+
+	double_rq_lock(runqueue_t *rq1, runqueue_t *rq2)
+
+and
+
+	double_rq_unlock(runqueue_t *rq1, runqueue_t rq2)
+
+safely lock and unlock, respectively, the two specified runqueues.  They do
+not, however, disable and restore interrupts.  Users are required to do so
+manually before and after calls.
+
+
+Values
+------
+
+MAX_PRIO
+	The maximum priority of the system, stored in the task as task->prio.
+	Lower priorities are higher.  Normal (non-RT) priorities range from
+	MAX_RT_PRIO to (MAX_PRIO - 1).
+MAX_RT_PRIO
+	The maximum real-time priority of the system.  Valid RT priorities
+	range from 0 to (MAX_RT_PRIO - 1).
+MAX_USER_RT_PRIO
+	The maximum real-time priority that is exported to user-space.  Should
+	always be equal to or less than MAX_RT_PRIO.  Setting it less allows
+	kernel threads to have higher priorities than any user-space task.
+MIN_TIMESLICE
+MAX_TIMESLICE
+	Respectively, the minimum and maximum timeslices (quanta) of a process.
+
+Data
+----
+
+struct runqueue
+	The main per-CPU runqueue data structure.
+struct task_struct
+	The main per-process data structure.
+
+
+General Methods
+---------------
+
+cpu_rq(cpu)
+	Returns the runqueue of the specified cpu.
+this_rq()
+	Returns the runqueue of the current cpu.
+task_rq(task)
+	Returns the runqueue which holds the specified task.
+cpu_curr(cpu)
+	Returns the task currently running on the given cpu.
+rt_task(task)
+	Returns true if task is real-time, false if not.
+task_cpu(task)
+
+
+Process Control Methods
+-----------------------
+
+void set_user_nice(task_t *p, long nice)
+	Sets the "nice" value of task p to the given value.
+int setscheduler(pid_t pid, int policy, struct sched_param *param)
+	Sets the scheduling policy and parameters for the given pid.
+void set_cpus_allowed(task_t *p, unsigned long new_mask)
+	Sets a given task's CPU affinity and migrates it to a proper cpu.
+	Callers must have a valid reference to the task and assure the
+	task not exit prematurely.  No locks can be held during the call.
+set_task_state(tsk, state_value)
+	Sets the given task's state to the given value.
+set_current_state(state_value)
+	Sets the current task's state to the given value.
+void set_tsk_need_resched(struct task_struct *tsk)
+	Sets need_resched in the given task.
+void clear_tsk_need_resched(struct task_struct *tsk)
+	Clears need_resched in the given task.
+void set_need_resched()
+	Sets need_resched in the current task.
+void set_task_cpu(task, cpu)
+	Sets task->cpu to cpu on SMP.  Noop on UP.
+void clear_need_resched()
+	Clears need_resched in the current task.
+int need_resched()
+	Returns true if need_resched is set in the current task, false
+	otherwise.
+yield()
+	Place the current process at the end of the runqueue and call schedule.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/Documentation/sched-design.txt linux.20pre10-ac2/Documentation/sched-design.txt
--- linux.20pre10/Documentation/sched-design.txt	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/Documentation/sched-design.txt	2002-08-06 15:42:28.000000000 +0100
@@ -0,0 +1,165 @@
+		   Goals, Design and Implementation of the
+		      new ultra-scalable O(1) scheduler
+
+
+  This is an edited version of an email Ingo Molnar sent to
+  lkml on 4 Jan 2002.  It describes the goals, design, and
+  implementation of Ingo's new ultra-scalable O(1) scheduler.
+  Last Updated: 18 April 2002.
+
+
+Goal
+====
+
+The main goal of the new scheduler is to keep all the good things we know
+and love about the current Linux scheduler:
+
+ - good interactive performance even during high load: if the user
+   types or clicks then the system must react instantly and must execute
+   the user tasks smoothly, even during considerable background load.
+
+ - good scheduling/wakeup performance with 1-2 runnable processes.
+
+ - fairness: no process should stay without any timeslice for any
+   unreasonable amount of time. No process should get an unjustly high
+   amount of CPU time.
+
+ - priorities: less important tasks can be started with lower priority,
+   more important tasks with higher priority.
+
+ - SMP efficiency: no CPU should stay idle if there is work to do.
+
+ - SMP affinity: processes which run on one CPU should stay affine to
+   that CPU. Processes should not bounce between CPUs too frequently.
+
+ - plus additional scheduler features: RT scheduling, CPU binding.
+
+and the goal is also to add a few new things:
+
+ - fully O(1) scheduling. Are you tired of the recalculation loop
+   blowing the L1 cache away every now and then? Do you think the goodness
+   loop is taking a bit too long to finish if there are lots of runnable
+   processes? This new scheduler takes no prisoners: wakeup(), schedule(),
+   the timer interrupt are all O(1) algorithms. There is no recalculation
+   loop. There is no goodness loop either.
+
+ - 'perfect' SMP scalability. With the new scheduler there is no 'big'
+   runqueue_lock anymore - it's all per-CPU runqueues and locks - two
+   tasks on two separate CPUs can wake up, schedule and context-switch
+   completely in parallel, without any interlocking. All
+   scheduling-relevant data is structured for maximum scalability.
+
+ - better SMP affinity. The old scheduler has a particular weakness that
+   causes the random bouncing of tasks between CPUs if/when higher
+   priority/interactive tasks, this was observed and reported by many
+   people. The reason is that the timeslice recalculation loop first needs
+   every currently running task to consume its timeslice. But when this
+   happens on eg. an 8-way system, then this property starves an
+   increasing number of CPUs from executing any process. Once the last
+   task that has a timeslice left has finished using up that timeslice,
+   the recalculation loop is triggered and other CPUs can start executing
+   tasks again - after having idled around for a number of timer ticks.
+   The more CPUs, the worse this effect.
+
+   Furthermore, this same effect causes the bouncing effect as well:
+   whenever there is such a 'timeslice squeeze' of the global runqueue,
+   idle processors start executing tasks which are not affine to that CPU.
+   (because the affine tasks have finished off their timeslices already.)
+
+   The new scheduler solves this problem by distributing timeslices on a
+   per-CPU basis, without having any global synchronization or
+   recalculation.
+
+ - batch scheduling. A significant proportion of computing-intensive tasks
+   benefit from batch-scheduling, where timeslices are long and processes
+   are roundrobin scheduled. The new scheduler does such batch-scheduling
+   of the lowest priority tasks - so nice +19 jobs will get
+   'batch-scheduled' automatically. With this scheduler, nice +19 jobs are
+   in essence SCHED_IDLE, from an interactiveness point of view.
+
+ - handle extreme loads more smoothly, without breakdown and scheduling
+   storms.
+
+ - O(1) RT scheduling. For those RT folks who are paranoid about the
+   O(nr_running) property of the goodness loop and the recalculation loop.
+
+ - run fork()ed children before the parent. Andrea has pointed out the
+   advantages of this a few months ago, but patches for this feature
+   do not work with the old scheduler as well as they should,
+   because idle processes often steal the new child before the fork()ing
+   CPU gets to execute it.
+
+
+Design
+======
+
+the core of the new scheduler are the following mechanizms:
+
+ - *two*, priority-ordered 'priority arrays' per CPU. There is an 'active'
+   array and an 'expired' array. The active array contains all tasks that
+   are affine to this CPU and have timeslices left. The expired array
+   contains all tasks which have used up their timeslices - but this array
+   is kept sorted as well. The active and expired array is not accessed
+   directly, it's accessed through two pointers in the per-CPU runqueue
+   structure. If all active tasks are used up then we 'switch' the two
+   pointers and from now on the ready-to-go (former-) expired array is the
+   active array - and the empty active array serves as the new collector
+   for expired tasks.
+
+ - there is a 64-bit bitmap cache for array indices. Finding the highest
+   priority task is thus a matter of two x86 BSFL bit-search instructions.
+
+the split-array solution enables us to have an arbitrary number of active
+and expired tasks, and the recalculation of timeslices can be done
+immediately when the timeslice expires. Because the arrays are always
+access through the pointers in the runqueue, switching the two arrays can
+be done very quickly.
+
+this is a hybride priority-list approach coupled with roundrobin
+scheduling and the array-switch method of distributing timeslices.
+
+ - there is a per-task 'load estimator'.
+
+one of the toughest things to get right is good interactive feel during
+heavy system load. While playing with various scheduler variants i found
+that the best interactive feel is achieved not by 'boosting' interactive
+tasks, but by 'punishing' tasks that want to use more CPU time than there
+is available. This method is also much easier to do in an O(1) fashion.
+
+to establish the actual 'load' the task contributes to the system, a
+complex-looking but pretty accurate method is used: there is a 4-entry
+'history' ringbuffer of the task's activities during the last 4 seconds.
+This ringbuffer is operated without much overhead. The entries tell the
+scheduler a pretty accurate load-history of the task: has it used up more
+CPU time or less during the past N seconds. [the size '4' and the interval
+of 4x 1 seconds was found by lots of experimentation - this part is
+flexible and can be changed in both directions.]
+
+the penalty a task gets for generating more load than the CPU can handle
+is a priority decrease - there is a maximum amount to this penalty
+relative to their static priority, so even fully CPU-bound tasks will
+observe each other's priorities, and will share the CPU accordingly.
+
+the SMP load-balancer can be extended/switched with additional parallel
+computing and cache hierarchy concepts: NUMA scheduling, multi-core CPUs
+can be supported easily by changing the load-balancer. Right now it's
+tuned for my SMP systems.
+
+i skipped the prev->mm == next->mm advantage - no workload i know of shows
+any sensitivity to this. It can be added back by sacrificing O(1)
+schedule() [the current and one-lower priority list can be searched for a
+that->mm == current->mm condition], but costs a fair number of cycles
+during a number of important workloads, so i wanted to avoid this as much
+as possible.
+
+- the SMP idle-task startup code was still racy and the new scheduler
+triggered this. So i streamlined the idle-setup code a bit. We do not call
+into schedule() before all processors have started up fully and all idle
+threads are in place.
+
+- the patch also cleans up a number of aspects of sched.c - moves code
+into other areas of the kernel where it's appropriate, and simplifies
+certain code paths and data constructs. As a result, the new scheduler's
+code is smaller than the old one.
+
+	Ingo
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/Documentation/SubmittingDrivers linux.20pre10-ac2/Documentation/SubmittingDrivers
--- linux.20pre10/Documentation/SubmittingDrivers	2002-10-09 21:37:07.000000000 +0100
+++ linux.20pre10-ac2/Documentation/SubmittingDrivers	2002-09-30 19:00:22.000000000 +0100
@@ -2,9 +2,8 @@
 ---------------------------------------
 
 This document is intended to explain how to submit device drivers to the
-Linux 2.2 and 2.4 kernel trees. Note that if you are interested in video
-card drivers you should probably talk to XFree86 (http://www.xfree86.org) 
-instead.
+various kernel trees. Note that if you are interested in video card drivers
+you should probably talk to XFree86 (http://www.xfree86.org) instead.
 
 Also read the Documentation/SubmittingPatches document.
 
@@ -35,21 +34,23 @@
 	maintainer then please contact Alan Cox <alan@lxorguk.ukuu.org.uk>
 
 Linux 2.4:
-	This kernel tree is under active development. The same rules apply
-	as 2.2 but you may wish to submit your driver via linux-kernel (see
-	resources) and follow that list to track changes in API's. These
-	should no longer be occuring as we are now in a code freeze.
-	The final contact point for Linux 2.4 submissions is 	
-	<torvalds@transmeta.com>.
+	The same rules apply as 2.2 but this kernel tree is under active
+	development. The final contact point for Linux 2.4 submissions is
+	Marcelo Tosatti <marcelo@conectiva.com.br>.
+
+Linux 2.5:
+	The same rules apply as 2.4 except that you should follow linux-kernel
+	to track changes in API's. The final contact point for Linux 2.5
+	submissions is Linus Torvalds <torvalds@transmeta.com>.
 
 What Criteria Determine Acceptance
 ----------------------------------
 
-Licensing:	The code must be released to us under the GNU General Public License. 
-		We don't insist on any kind of exclusively GPL licensing,
-		and if you wish the driver to be useful to other communities
-		such as BSD you may well wish to release under multiple
-		licenses.
+Licensing:	The code must be released to us under the
+		GNU General Public License. We don't insist on any kind
+		of exclusively GPL licensing, and if you wish the driver
+		to be useful to other communities such as BSD you may well
+		wish to release under multiple licenses.
 
 Interfaces:	If your driver uses existing interfaces and behaves like
 		other drivers in the same class it will be much more likely
@@ -64,12 +65,13 @@
 		maintain them just once seperate them out nicely and note
 		this fact.
 
-Portability:	Pointers are not always 32bits, people do not all have
-		floating point and you shouldn't use inline x86 assembler in 
-		your driver without careful thought. Pure x86 drivers
-		generally are not popular. If you only have x86 hardware it 
-		is hard to test portability but it is easy to make sure the
-		code can easily be made portable.
+Portability:	Pointers are not always 32bits, not all computers are little
+		endian, people do not all have floating point and you
+		shouldn't use inline x86 assembler in your driver without
+		careful thought. Pure x86 drivers generally are not popular.
+		If you only have x86 hardware it is hard to test portability
+		but it is easy to make sure the code can easily be made
+		portable.
 
 Clarity:	It helps if anyone can see how to fix the driver. It helps
 		you because you get patches not bug reports. If you submit a
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/Documentation/video4linux/README.cpia linux.20pre10-ac2/Documentation/video4linux/README.cpia
--- linux.20pre10/Documentation/video4linux/README.cpia	2002-10-09 21:37:04.000000000 +0100
+++ linux.20pre10-ac2/Documentation/video4linux/README.cpia	2002-08-06 15:42:28.000000000 +0100
@@ -1,8 +1,18 @@
-This is a driver for the CPiA PPC2 driven parallel connected
-Camera. For example the Creative WebcamII is CPiA driven.
+This is a driver for the CPiA PPC2 driven parallel connected or USB
+Camera. For example the Creative WebcamII is CPiA driven.  Also
+various USB cameras, and the Intel Play QX3 microscope.
 
    ) [1]Peter Pregler, Linz 2000, published under the [2]GNU GPL
 
+
+NOTE ADDED (2002/05/23):
+An improved version of the driver (cpia.c, cpia.h, cpia_usb.c, cpia_pp.c)
+with extra features not yet integrated into the Official Linux Kernel versions
+is available from http://sourceforge.net/projects/webcam as
+cpia-2.2.1.tgz.  This is a drop-in replacement for the driver in the kernel
+sources, at least up to 2.4.18 kernels.   The driver at sourceforge has been 
+stable for over a year, and is currently in low maintenance mode
+(tracking kernel changes only).
 ---------------------------------------------------------------------------
 
 USAGE:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/Documentation/vm/overcommit-accounting linux.20pre10-ac2/Documentation/vm/overcommit-accounting
--- linux.20pre10/Documentation/vm/overcommit-accounting	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/Documentation/vm/overcommit-accounting	2002-09-18 12:58:44.000000000 +0100
@@ -0,0 +1,70 @@
+* This describes the overcommit management facility in the latest kernel
+  tree (FIXME: actually it also describes the stuff that isnt yet done)
+
+The Linux kernel supports four overcommit handling modes
+
+0	-	Heuristic overcommit handling. Obvious overcommits of
+		address space are refused. Used for a typical system. It
+		ensures a seriously wild allocation fails while allowing
+		overcommit to reduce swap usage
+
+1	-	No overcommit handling. Appropriate for some scientific
+		applications
+
+2	-	(NEW) strict overcommit. The total address space commit
+		for the system is not permitted to exceed swap + half ram.
+		In almost all situations this means a process will not be
+		killed while accessing pages but only by malloc failures
+		that are reported back by the kernel mmap/brk code.
+
+3	-	(NEW) paranoid overcommit The total address space commit
+		for the system is not permitted to exceed swap. The machine
+		will never kill a process accessing pages it has mapped
+		except due to a bug (ie report it!)
+
+Gotchas
+-------
+
+The C language stack growth does an implicit mremap. If you want absolute
+guarantees and run close to the edge you MUST mmap your stack for the 
+largest size you think you will need. For typical stack usage is does
+not matter much but its a corner case if you really really care
+
+In modes 2 and 3 the MAP_NORESERVE flag is ignored. 
+
+
+How It Works
+------------
+
+The overcommit is based on the following rules
+
+For a file backed map
+	SHARED or READ-only	-	0 cost (the file is the map not swap)
+	PRIVATE WRITABLE	-	size of mapping per instance
+
+For an anonymous or /dev/zero map
+	SHARED			-	size of mapping
+	PRIVATE READ-only	-	0 cost (but of little use)
+	PRIVATE WRITABLE	-	size of mapping per instance
+
+Additional accounting
+	Pages made writable copies by mmap
+	shmfs memory drawn from the same pool
+
+Status
+------
+
+o	We account mmap memory mappings
+o	We account mprotect changes in commit
+o	We account mremap changes in size
+o	We account brk
+o	We account munmap
+o	We report the commit status in /proc
+o	Account and check on fork
+o	Review stack handling/building on exec
+o	SHMfs accounting
+o	Implement actual limit enforcement
+
+To Do
+-----
+o	Account ptrace pages (this is hard)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/atm/iphase.c linux.20pre10-ac2/drivers/atm/iphase.c
--- linux.20pre10/drivers/atm/iphase.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/atm/iphase.c	2002-10-11 00:15:48.000000000 +0100
@@ -124,7 +124,7 @@
 }
 
 static int ia_enque_rtn_q (IARTN_Q *que, struct desc_tbl_t data) {
-   IARTN_Q *entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+   IARTN_Q *entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
    if (!entry) return -1;
    entry->data = data;
    entry->next = NULL;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/block/elevator.c linux.20pre10-ac2/drivers/block/elevator.c
--- linux.20pre10/drivers/block/elevator.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/block/elevator.c	2002-09-26 21:50:34.000000000 +0100
@@ -218,3 +218,5 @@
 	*elevator = type;
 	elevator->queue_ID = queue_ID++;
 }
+
+EXPORT_SYMBOL(elevator_init);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/block/ll_rw_blk.c linux.20pre10-ac2/drivers/block/ll_rw_blk.c
--- linux.20pre10/drivers/block/ll_rw_blk.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/block/ll_rw_blk.c	2002-10-07 21:31:14.000000000 +0100
@@ -118,6 +118,13 @@
  */
 int * max_sectors[MAX_BLKDEV];
 
+/*
+ * blkdev_varyio indicates if variable size IO can be done on a device.
+ *
+ * Currently used for doing variable size IO on RAW devices.
+ */
+char * blkdev_varyio[MAX_BLKDEV];
+
 unsigned long blk_max_low_pfn, blk_max_pfn;
 int blk_nohighio = 0;
 
@@ -1210,6 +1217,38 @@
 	}
 }
 
+/*
+ * submit_bh_blknr() - same as submit_bh() except that b_rsector is
+ * set to b_blocknr. Used for RAW VARY.
+ */
+void submit_bh_blknr(int rw, struct buffer_head * bh)
+{
+	int count = bh->b_size >> 9;
+
+	if (!test_bit(BH_Lock, &bh->b_state))
+		BUG();
+
+	set_bit(BH_Req, &bh->b_state);
+
+	/*
+	 * First step, 'identity mapping' - RAID or LVM might
+	 * further remap this.
+	 */
+	bh->b_rdev = bh->b_dev;
+	bh->b_rsector = bh->b_blocknr;
+
+	generic_make_request(rw, bh);
+
+	switch (rw) {
+		case WRITE:
+			kstat.pgpgout += count;
+			break;
+		default:
+			kstat.pgpgin += count;
+			break;
+	}
+}
+
 /**
  * ll_rw_block: low-level access to block devices
  * @rw: whether to %READ or %WRITE or maybe %READA (readahead)
@@ -1413,12 +1452,6 @@
 #ifdef CONFIG_ISP16_CDI
 	isp16_init();
 #endif
-#if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_IDE)
-	ide_init();		/* this MUST precede hd_init */
-#endif
-#if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_HD)
-	hd_init();
-#endif
 #ifdef CONFIG_BLK_DEV_PS2
 	ps2esdi_init();
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/block/loop.c linux.20pre10-ac2/drivers/block/loop.c
--- linux.20pre10/drivers/block/loop.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/block/loop.c	2002-09-18 12:33:40.000000000 +0100
@@ -199,9 +199,9 @@
 		page = grab_cache_page(mapping, index);
 		if (!page)
 			goto fail;
+		kaddr = kmap(page);
 		if (aops->prepare_write(file, page, offset, offset+size))
 			goto unlock;
-		kaddr = page_address(page);
 		flush_dcache_page(page);
 		transfer_result = lo_do_transfer(lo, WRITE, kaddr + offset, data, size, IV);
 		if (transfer_result) {
@@ -216,6 +216,7 @@
 			goto unlock;
 		if (transfer_result)
 			goto unlock;
+		kunmap(page);
 		data += size;
 		len -= size;
 		offset = 0;
@@ -228,6 +229,7 @@
 	return 0;
 
 unlock:
+	kunmap(page);
 	UnlockPage(page);
 	page_cache_release(page);
 fail:
@@ -418,6 +420,7 @@
 			break;
 
 		run_task_queue(&tq_disk);
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(HZ);
 	} while (1);
 	memset(bh, 0, sizeof(*bh));
@@ -437,6 +440,7 @@
 			break;
 
 		run_task_queue(&tq_disk);
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(HZ);
 	} while (1);
 
@@ -563,6 +567,7 @@
 
 	daemonize();
 	exit_files(current);
+	reparent_to_init();
 
 	sprintf(current->comm, "loop%d", lo->lo_number);
 
@@ -571,9 +576,6 @@
 	flush_signals(current);
 	spin_unlock_irq(&current->sigmask_lock);
 
-	current->policy = SCHED_OTHER;
-	current->nice = -20;
-
 	spin_lock_irq(&lo->lo_lock);
 	lo->lo_state = Lo_bound;
 	atomic_inc(&lo->lo_pending);
@@ -645,7 +647,7 @@
 		lo_device = inode->i_rdev;
 		if (lo_device == dev) {
 			error = -EBUSY;
-			goto out;
+			goto out_putf;
 		}
 	} else if (S_ISREG(inode->i_mode)) {
 		struct address_space_operations *aops = inode->i_mapping->a_ops;
@@ -1014,11 +1016,6 @@
 		return -EIO;
 	}
 
-	devfs_handle = devfs_mk_dir(NULL, "loop", NULL);
-	devfs_register_series(devfs_handle, "%u", max_loop, DEVFS_FL_DEFAULT,
-			      MAJOR_NR, 0,
-			      S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
-			      &lo_fops, NULL);
 
 	loop_dev = kmalloc(max_loop * sizeof(struct loop_device), GFP_KERNEL);
 	if (!loop_dev)
@@ -1051,13 +1048,21 @@
 	for (i = 0; i < max_loop; i++)
 		register_disk(NULL, MKDEV(MAJOR_NR, i), 1, &lo_fops, 0);
 
+	devfs_handle = devfs_mk_dir(NULL, "loop", NULL);
+	devfs_register_series(devfs_handle, "%u", max_loop, DEVFS_FL_DEFAULT,
+			      MAJOR_NR, 0,
+			      S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
+			      &lo_fops, NULL);
+
 	printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop);
 	return 0;
 
-out_sizes:
-	kfree(loop_dev);
 out_blksizes:
 	kfree(loop_sizes);
+out_sizes:
+	kfree(loop_dev);
+	if (devfs_unregister_blkdev(MAJOR_NR, "loop"))
+		printk(KERN_WARNING "loop: cannot unregister blkdev\n");
 	printk(KERN_ERR "loop: ran out of memory\n");
 	return -ENOMEM;
 }
@@ -1067,7 +1072,6 @@
 	devfs_unregister(devfs_handle);
 	if (devfs_unregister_blkdev(MAJOR_NR, "loop"))
 		printk(KERN_WARNING "loop: cannot unregister blkdev\n");
-
 	kfree(loop_dev);
 	kfree(loop_sizes);
 	kfree(loop_blksizes);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/block/Makefile linux.20pre10-ac2/drivers/block/Makefile
--- linux.20pre10/drivers/block/Makefile	2002-10-09 21:36:46.000000000 +0100
+++ linux.20pre10-ac2/drivers/block/Makefile	2002-08-25 16:23:25.000000000 +0100
@@ -10,7 +10,7 @@
 
 O_TARGET := block.o
 
-export-objs	:= ll_rw_blk.o blkpg.o loop.o DAC960.o genhd.o
+export-objs	:= ll_rw_blk.o blkpg.o elevator.o loop.o DAC960.o genhd.o
 
 obj-y	:= ll_rw_blk.o blkpg.o genhd.o elevator.o
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/acquirewdt.c linux.20pre10-ac2/drivers/char/acquirewdt.c
--- linux.20pre10/drivers/char/acquirewdt.c	2002-10-09 21:36:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/acquirewdt.c	2002-09-29 20:29:59.000000000 +0100
@@ -17,6 +17,9 @@
  *
  *	(c) Copyright 1995    Alan Cox <alan@redhat.com>
  *
+ *      14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ *          Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ *          Can't add timeout - driver doesn't allow changing value
  */
 
 #include <linux/config.h>
@@ -42,6 +45,7 @@
 
 static int acq_is_open;
 static spinlock_t acq_lock;
+static int expect_close = 0;
 
 /*
  *	You must set these - there is no sane way to probe for this board.
@@ -50,8 +54,14 @@
 #define WDT_STOP 0x43
 #define WDT_START 0x443
 
-#define WD_TIMO (100*60)		/* 1 minute */
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
 
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
 /*
  *	Kernel methods.
@@ -72,6 +82,21 @@
 
 	if(count)
 	{
+		if (!nowayout)
+		{
+			size_t i;
+
+			expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 1;
+			}
+		}
+
 		acq_ping();
 		return 1;
 	}
@@ -90,7 +115,7 @@
 {
 	static struct watchdog_info ident=
 	{
-		WDIOF_KEEPALIVEPING, 1, "Acquire WDT"
+		WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 1, "Acquire WDT"
 	};
 	
 	switch(cmd)
@@ -126,10 +151,12 @@
 				spin_unlock(&acq_lock);
 				return -EBUSY;
 			}
+			if (nowayout) {
+				MOD_INC_USE_COUNT;
+			}
 			/*
 			 *	Activate 
 			 */
-	 
 			acq_is_open=1;
 			inb_p(WDT_START);      
 			spin_unlock(&acq_lock);
@@ -145,9 +172,14 @@
 	if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
 	{
 		spin_lock(&acq_lock);
-#ifndef CONFIG_WATCHDOG_NOWAYOUT	
-		inb_p(WDT_STOP);
-#endif		
+		if (expect_close)
+		{
+			inb_p(WDT_STOP);
+		}
+		else
+		{
+			printk(KERN_CRIT "WDT closed unexpectedly.  WDT will not stop!\n");
+		}
 		acq_is_open=0;
 		spin_unlock(&acq_lock);
 	}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/advantechwdt.c linux.20pre10-ac2/drivers/char/advantechwdt.c
--- linux.20pre10/drivers/char/advantechwdt.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/advantechwdt.c	2002-09-29 20:29:59.000000000 +0100
@@ -20,6 +20,8 @@
  *
  *	(c) Copyright 1995    Alan Cox <alan@redhat.com>
  *
+ *	14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ *	    Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
  */
 
 #include <linux/config.h>
@@ -57,6 +59,15 @@
 
 static int wd_margin = 60; /* 60 sec default timeout */
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 /*
  *	Kernel methods.
  */
@@ -108,20 +119,20 @@
 		return -ESPIPE;
 
 	if (count) {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-		size_t i;
+		if (!nowayout) {
+			size_t i;
 
-		adv_expect_close = 0;
-
-		for (i = 0; i != count; i++) {
-			char c;
-			if(get_user(c, buf+i))
-				return -EFAULT;
-			if (c == 'V')
-				adv_expect_close = 42;
+			adv_expect_close = 0;
+	
+			for (i = 0; i != count; i++) {
+				char c;
+				if(get_user(c, buf+i))
+					return -EFAULT;
+				if (c == 'V')
+					adv_expect_close = 42;
+			}
 		}
-#endif
-		advwdt_ping();
+			advwdt_ping();
 	}
 	return count;
 }
@@ -132,7 +143,7 @@
 {
 	int new_margin;
 	static struct watchdog_info ident = {
-		options:		WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
+		options:		WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
 		firmware_version:	0,
 		identity:		"Advantech WDT"
 	};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/agp/agpgart_be.c linux.20pre10-ac2/drivers/char/agp/agpgart_be.c
--- linux.20pre10/drivers/char/agp/agpgart_be.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/agp/agpgart_be.c	2002-10-07 21:31:25.000000000 +0100
@@ -4609,6 +4609,12 @@
 		"SiS",
 		"645",
 		sis_generic_setup },
+	{ PCI_DEVICE_ID_SI_646,
+		PCI_VENDOR_ID_SI,
+		SIS_GENERIC,
+		"SiS",
+		"646",
+		sis_generic_setup },
 	{ PCI_DEVICE_ID_SI_735,
 		PCI_VENDOR_ID_SI,
 		SIS_GENERIC,
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/alim1535d_wdt.c linux.20pre10-ac2/drivers/char/alim1535d_wdt.c
--- linux.20pre10/drivers/char/alim1535d_wdt.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/alim1535d_wdt.c	2002-08-12 14:58:07.000000000 +0100
@@ -0,0 +1,356 @@
+/*
+ *	Watchdog for the 7101 PMU version found in the ALi1535 chipsets
+ *
+ *	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/module.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/init.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+static spinlock_t ali_lock;	/* Guards the hardware */
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+static unsigned long timer_alive;
+static char ali_expect_close;
+static u32 ali_timeout = 60;			/* 60 seconds */
+static u32 ali_timeout_bits = 1 | (1<<7);	/* 1 count in minutes */
+
+static struct pci_dev *ali_pci;
+
+/**
+ *	ali_timer_start		-	start watchdog countdown
+ *	@dev: PCI device of the PMU
+ *
+ *	Starts the timer running providing the timer has a counter
+ *	configuration set.
+ */
+ 
+static void ali_timer_start(struct pci_dev *pdev)
+{
+	u32 val;
+
+	spin_lock(&ali_lock);
+	
+	pci_read_config_dword(pdev, 0xCC, &val);
+	val &= ~0x3F;	/* Mask count */
+	val |= (1<<25) | ali_timeout_bits;
+	pci_write_config_dword(pdev, 0xCC, val);
+	spin_unlock(&ali_lock);
+}
+
+/**
+ *	ali_timer_stop	-	stop the timer countdown
+ *	@pdev: PCI device of the PMU
+ *
+ *	Stop the ALi watchdog countdown
+ */
+ 
+static void ali_timer_stop (struct pci_dev *pdev)
+{
+	u32 val;
+
+	spin_lock(&ali_lock);
+	pci_read_config_dword(pdev, 0xCC, &val);
+	val &= ~0x3F;	/* Mask count to zero (disabled) */
+	val &= ~(1<<25);/* and for safety mask the reset enable */
+	pci_write_config_dword(pdev, 0xCC, val);
+	spin_unlock(&ali_lock);
+}
+
+/**
+ *	ali_timer_settimer	-	compute the timer reload value
+ *	@pdev: PCI device of the PMU
+ *	@t: time in seconds
+ *
+ *	Computes the timeout values needed and then restarts the timer
+ *	running with the new timeout values
+ */
+
+static int ali_timer_settimer(struct pci_dev *pdev, unsigned long t)
+{
+	if(t < 60)
+		ali_timeout_bits = t|(1<<6);
+	else if(t < 3600)
+		ali_timeout_bits = (t/60)|(1<<7);
+	else if(t < 18000)
+		ali_timeout_bits = (t/300)|(1<<6)|(1<<7);
+	else return -EINVAL;
+	
+	ali_timeout = t;
+	ali_timer_start(pdev);
+	return 0;
+}
+
+/**
+ *	ali_open	-	handle open of ali watchdog
+ *	@inode: inode from VFS
+ *	@file: file from VFS
+ *
+ *	Open the ALi watchdog device. Ensure only one person opens it
+ *	at a time. Also start the watchdog running.
+ */
+
+static int ali_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(0, &timer_alive))
+		return -EBUSY;
+	ali_timer_start (ali_pci);
+	return 0;
+}
+
+/**
+ *	ali_release	-	close an ALi watchdog
+ *	@inode: inode from VFS
+ *	@file: file from VFS
+ *
+ *	Close the ALi watchdog device. Actual shutdown of the timer
+ *	only occurs if the magic sequence has been set or nowayout is 
+ *	disabled
+ */
+ 
+static int ali_release (struct inode *inode, struct file *file)
+{
+	/*
+	 *      Shut off the timer.
+	 */
+	if (ali_expect_close == 42 && !nowayout) {
+		ali_timer_stop(ali_pci);
+	} else {
+		ali_timer_start(ali_pci);
+		printk(KERN_CRIT  "ali1535_wdt: Unexpected close, not stopping watchdog!\n");
+	}
+	clear_bit(0, &timer_alive);
+	ali_expect_close = 0;
+	return 0;
+}
+
+/**
+ *	ali_write	-	writes to ALi watchdog
+ *	@file: file from VFS
+ *	@data: user address of data
+ *	@len: length of data
+ *	@ppos: pointer to the file offset
+ *
+ *	Handle a write to the ALi watchdog. Writing to the file pings
+ *	the watchdog and resets it. Writing the magic 'V' sequence allows
+ *	the next close to turn off the watchdog.
+ */
+ 
+static ssize_t ali_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;
+
+	/* See if we got the magic character 'V' and reload the timer */
+	if (len) {
+		size_t i;
+
+		ali_expect_close = 0;
+
+		/* scan to see wether or not we got the magic character */
+		for (i = 0; i != len; i++) {
+			u8 c;
+			if(get_user(c, data+i))
+				return -EFAULT;
+			if (c == 'V')
+				ali_expect_close = 42;
+		}
+
+		/* someone wrote to us, we should reload the timer */
+		ali_timer_start(ali_pci);
+		return 1;
+	}
+	return 0;
+}
+
+/**
+ *	ali_ioctl	-	handle watchdog ioctls
+ *	@inode: VFS inode
+ *	@file: VFS file pointer
+ *	@cmd: ioctl number
+ *	@arg: arguments to the ioctl
+ *
+ *	Handle the watchdog ioctls supported by the ALi driver. Really
+ *	we want an extension to enable irq ack monitoring and the like
+ */
+
+static int ali_ioctl (struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg)
+{
+	int options, retval = -EINVAL;
+	u32 t;
+	static struct watchdog_info ident = {
+		options:		WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+		firmware_version:	0,
+		identity:		"ALi 1535D+ TCO timer",
+	};
+	switch (cmd) {
+		default:
+			return -ENOTTY;
+		case WDIOC_GETSUPPORT:
+			if (copy_to_user((struct watchdog_info *) arg, &ident, sizeof (ident)))
+				return -EFAULT;
+			return 0;
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, (int *) arg);
+		case WDIOC_SETOPTIONS:
+			if (get_user (options, (int *) arg))
+				return -EFAULT;
+			if (options & WDIOS_DISABLECARD) {
+				ali_timer_stop(ali_pci);
+				retval = 0;
+			}
+			if (options & WDIOS_ENABLECARD) {
+				ali_timer_start(ali_pci);
+				retval = 0;
+			}
+			return retval;
+		case WDIOC_KEEPALIVE:
+			ali_timer_start(ali_pci);
+			return 0;
+		case WDIOC_SETTIMEOUT:
+			if (get_user(t, (int *) arg))
+				return -EFAULT;
+			if (ali_timer_settimer(ali_pci, t))
+			    return -EINVAL;
+			ali_timer_start(ali_pci);
+			/* Fall */
+		case WDIOC_GETTIMEOUT:
+			return put_user(ali_timeout, (int *)arg);
+	}
+}
+
+/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
+ * register a pci_driver, because someone else might one day
+ * want to register another driver on the same PCI id.
+ */
+ 
+static struct pci_device_id ali_pci_tbl[] __initdata = {
+	{ PCI_VENDOR_ID_AL, 1535, PCI_ANY_ID, PCI_ANY_ID,},
+	{ 0, },
+};
+MODULE_DEVICE_TABLE (pci, ali_pci_tbl);
+
+
+/**
+ *	ali_find_watchdog	-	find a 1535 and 7101
+ *	
+ *	Scans the PCI hardware for a 1535 series bridge and matching 7101
+ *	watchdog device. This may be overtight but it is better to be safe
+ */	
+
+static int __init ali_find_watchdog(void)
+{
+	struct pci_dev *pdev;
+	u32 wdog;
+	
+	/* Check for a 1535 series bridge */
+	pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x1535, NULL);
+	if(pdev == NULL)
+		return -ENODEV;
+
+	/* Check for the a 7101 PMU */
+	pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x7101, NULL);
+	if(pdev == NULL)
+		return -ENODEV;
+
+	if(pci_enable_device(pdev))
+		return -EIO;
+		
+	ali_pci = pdev;
+	
+	/*
+	 *	Initialize the timer bits
+	 */
+	 
+	pci_read_config_dword(pdev, 0xCC, &wdog);
+	
+	wdog &= ~0x3F;		/* Timer bits */
+	wdog &= ~((1<<27)|(1<<26)|(1<<25)|(1<<24));	/* Issued events */
+	wdog &= ~((1<<16)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9));	/* No monitor bits */
+
+	pci_write_config_dword(pdev, 0xCC, wdog);
+	return 0;
+}
+
+static struct file_operations ali_fops = {
+	owner:		THIS_MODULE,
+	write:		ali_write,
+	ioctl:		ali_ioctl,
+	open:		ali_open,
+	release:	ali_release,
+};
+
+static struct miscdevice ali_miscdev = {
+	minor:		WATCHDOG_MINOR,
+	name:		"watchdog",
+	fops:		&ali_fops,
+};
+
+/**
+ *	watchdog_init	-	module initialiser
+ *	
+ *	Scan for a suitable watchdog and if so initialize it. Return an error
+ *	if we cannot, the error causes the module to unload
+ */
+ 
+static int __init watchdog_init (void)
+{
+	spin_lock_init(&ali_lock);
+	if (!ali_find_watchdog())
+		return -ENODEV;
+	if (misc_register (&ali_miscdev) != 0) {
+		printk (KERN_ERR "alim1535d: cannot register watchdog device node.\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+/**
+ *	watchdog_cleanup	-	unload watchdog
+ *
+ *	Called on the unload of a successfully installed watchdog module.
+ */
+ 
+static void __exit watchdog_cleanup (void)
+{
+	ali_timer_stop(ali_pci);
+	misc_deregister (&ali_miscdev);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_cleanup);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("Watchdog driver for the ALi 1535+ PMU");
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/alim7101_wdt.c linux.20pre10-ac2/drivers/char/alim7101_wdt.c
--- linux.20pre10/drivers/char/alim7101_wdt.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/alim7101_wdt.c	2002-09-29 20:29:59.000000000 +0100
@@ -79,6 +79,15 @@
 static int wdt_expect_close;
 static struct pci_dev *alim7101_pmu;
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 /*
  *	Whack the dog
  */
@@ -157,21 +166,24 @@
 	/* See if we got the magic character */
 	if(count) 
 	{
-		size_t ofs;
-
-		/* note: just in case someone wrote the magic character
-		 * five months ago... */
-		wdt_expect_close = 0;
-
-		/* now scan */
-		for(ofs = 0; ofs != count; ofs++)
-		{
-			char c;
-			if(get_user(c, buf+ofs))
-				return -EFAULT;
-			if(c == 'V')
-				wdt_expect_close = 1;
+		if (!nowayout) {
+			size_t ofs;
+	
+			/* note: just in case someone wrote the magic character
+			 * five months ago... */
+			wdt_expect_close = 0;
+	
+			/* now scan */
+			for(ofs = 0; ofs != count; ofs++)
+			{
+				char c;
+				if(get_user(c, buf+ofs))
+					return -EFAULT;
+				if(c == 'V')
+					wdt_expect_close = 1;
+			}
 		}
+
 		/* someone wrote to us, we should restart timer */
 		next_heartbeat = jiffies + WDT_HEARTBEAT;
 		return 1;
@@ -197,15 +209,11 @@
 
 static int fop_close(struct inode * inode, struct file * file)
 {
-#ifdef CONFIG_WDT_NOWAYOUT
 	if(wdt_expect_close)
 		wdt_turnoff();
 	else {
 		printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n");
 	}
-#else
-	wdt_turnoff();
-#endif
 	clear_bit(0, &wdt_is_open);
 	return 0;
 }
@@ -214,7 +222,7 @@
 {
 	static struct watchdog_info ident=
 	{
-		0,
+		WDIOF_MAGICCLOSE,
 		1,
 		"ALiM7101"
 	};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/amd76x_pm.c linux.20pre10-ac2/drivers/char/amd76x_pm.c
--- linux.20pre10/drivers/char/amd76x_pm.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/amd76x_pm.c	2002-08-06 15:42:07.000000000 +0100
@@ -0,0 +1,688 @@
+/*
+ * ACPI sytle PM for SMP AMD-760MP(X) based systems.
+ * For use until the ACPI project catches up. :-)
+ *
+ * Copyright (C) 2002 Johnathan Hicks <thetech@folkwolf.net>
+ *
+ * History:
+ * 
+ *   20020702 - amd-smp-idle: Tony Lindgren <tony@atomide.com>
+ *	Influenced by Vcool, and LVCool. Rewrote everything from scratch to
+ *	use the PCI features in Linux, and to support SMP systems. Provides
+ *	C2 idling on SMP AMD-760MP systems.
+ *	
+ *   20020722: JH
+ *   	I adapted Tony's code for the AMD-765/766 southbridge and adapted it
+ *   	according to the AMD-768 data sheet to provide the same capability for
+ *   	SMP AMD-760MPX systems. Posted to acpi-devel list.
+ *   	
+ *   20020722: Alan Cox
+ *   	Replaces non-functional amd76x_pm code in -ac tree.
+ *   	
+ *   20020730: JH
+ *   	Added ability to do normal throttling (the non-thermal kind), C3 idling
+ *   	and Power On Suspend (S1 sleep). It would be very easy to tie swsusp
+ *   	into activate_amd76x_SLP(). C3 idling doesn't happen yet; see my note
+ *   	in amd76x_smp_idle(). I've noticed that when NTH and idling are both
+ *   	enabled, my hardware locks and requires a hard reset, so I have
+ *   	#ifndefed around the idle loop setting to prevent this. POS locks it up
+ *   	too, both ought to be fixable. I've also noticed that idling and NTH
+ *   	make some interference that is picked up by the onboard sound chip on
+ *   	my ASUS A7M266-D motherboard.
+ *
+ *
+ * TODO: Thermal throttling (TTH).
+ * 	 /proc interface for normal throttling level.
+ * 	 /proc interface for POS.
+ *
+ *
+ *    <Notes from 20020722-ac revision>
+ *
+ * Processor idle mode module for AMD SMP 760MP(X) based systems
+ *
+ * Copyright (C) 2002 Tony Lindgren <tony@atomide.com>
+ *                    Johnathan Hicks (768 support)
+ *
+ * Using this module saves about 70 - 90W of energy in the idle mode compared
+ * to the default idle mode. Waking up from the idle mode is fast to keep the
+ * system response time good. Currently no CPU load calculation is done, the
+ * system exits the idle mode if the idle function runs twice on the same
+ * processor in a row. This only works on SMP systems, but maybe the idle mode
+ * enabling can be integrated to ACPI to provide C2 mode at some point.
+ *
+ * NOTE: Currently there's a bug somewhere where the reading the
+ *       P_LVL2 for the first time causes the system to sleep instead of 
+ *       idling. This means that you need to hit the power button once to
+ *       wake the system after loading the module for the first time after
+ *       reboot. After that the system idles as supposed.
+ *
+ *
+ * Influenced by Vcool, and LVCool. Rewrote everything from scratch to
+ * use the PCI features in Linux, and to support SMP systems.
+ * 
+ * Currently only tested on a TYAN S2460 (760MP) system (Tony) and an
+ * ASUS A7M266-D (760MPX) system (Johnathan). Adding support for other Athlon
+ * SMP or single processor systems should be easy if desired.
+ *
+ * This software is licensed under GNU General Public License Version 2 
+ * as specified in file COPYING in the Linux kernel source tree main 
+ * directory.
+ * 
+ *   </Notes from 20020722-ac revision>
+ */
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+
+#include "amd76x_pm.h"
+
+#define VERSION	"20020730"
+
+// #define AMD76X_C3  1
+// #define AMD76X_NTH 1
+// #define AMD76X_POS 1
+
+
+extern void default_idle(void);
+static void amd76x_smp_idle(void);
+static int amd76x_pm_main(void);
+static int __devinit amd_nb_init(struct pci_dev *pdev,
+				 const struct pci_device_id *ent);
+static void amd_nb_remove(struct pci_dev *pdev);
+static int __devinit amd_sb_init(struct pci_dev *pdev,
+				 const struct pci_device_id *ent);
+static void amd_sb_remove(struct pci_dev *pdev);
+
+
+static struct pci_dev *pdev_nb;
+static struct pci_dev *pdev_sb;
+
+struct PM_cfg {
+	unsigned int status_reg;
+	unsigned int C2_reg;
+	unsigned int C3_reg;
+	unsigned int NTH_reg;
+	unsigned int slp_reg;
+	unsigned int resume_reg;
+	void (*orig_idle) (void);
+	void (*curr_idle) (void);
+	unsigned long C2_cnt, C3_cnt;
+	int last_pr;
+};
+static struct PM_cfg amd76x_pm_cfg;
+
+struct cpu_idle_state {
+	int idle;
+	int count;
+};
+static struct cpu_idle_state prs[2];
+
+static struct pci_device_id amd_nb_tbl[] __devinitdata = {
+	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, PCI_ANY_ID, PCI_ANY_ID,},
+	{0,}
+};
+
+static struct pci_device_id amd_sb_tbl[] __devinitdata = {
+	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413, PCI_ANY_ID, PCI_ANY_ID,},
+	{PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7443, PCI_ANY_ID, PCI_ANY_ID,},
+	{0,}
+};
+
+static struct pci_driver amd_nb_driver = {
+	name:"amd76x_pm-nb",
+	id_table:amd_nb_tbl,
+	probe:amd_nb_init,
+	remove:__devexit_p(amd_nb_remove),
+};
+
+static struct pci_driver amd_sb_driver = {
+	name:"amd76x_pm-sb",
+	id_table:amd_sb_tbl,
+	probe:amd_sb_init,
+	remove:__devexit_p(amd_sb_remove),
+};
+
+
+static int __devinit
+amd_nb_init(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	pdev_nb = pdev;
+	printk(KERN_INFO "amd76x_pm: Initializing northbridge %s\n",
+	       pdev_nb->name);
+
+	return 0;
+}
+
+
+static void __devexit
+amd_nb_remove(struct pci_dev *pdev)
+{
+}
+
+
+static int __devinit
+amd_sb_init(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	pdev_sb = pdev;
+	printk(KERN_INFO "amd76x_pm: Initializing southbridge %s\n",
+	       pdev_sb->name);
+
+	return 0;
+}
+
+
+static void __devexit
+amd_sb_remove(struct pci_dev *pdev)
+{
+}
+
+
+/*
+ * Configures the AMD-762 northbridge to support PM calls
+ */
+static int
+config_amd762(int enable)
+{
+	unsigned int regdword;
+
+	/* Enable STPGNT in BIU Status/Control for cpu0 */
+	pci_read_config_dword(pdev_nb, 0x60, &regdword);
+	regdword |= (1 << 17);
+	pci_write_config_dword(pdev_nb, 0x60, regdword);
+
+	/* Enable STPGNT in BIU Status/Control for cpu1 */
+	pci_read_config_dword(pdev_nb, 0x68, &regdword);
+	regdword |= (1 << 17);
+	pci_write_config_dword(pdev_nb, 0x68, regdword);
+
+	/* DRAM refresh enable */
+	pci_read_config_dword(pdev_nb, 0x58, &regdword);
+	regdword &= ~(1 << 19);
+	pci_write_config_dword(pdev_nb, 0x58, regdword);
+
+	/* Self refresh enable */
+	pci_read_config_dword(pdev_nb, 0x70, &regdword);
+	regdword |= (1 << 18);
+	pci_write_config_dword(pdev_nb, 0x70, regdword);
+
+	return 0;
+}
+
+
+/*
+ * Get the base PMIO address and set the pm registers in amd76x_pm_cfg.
+ */
+static void
+amd76x_get_PM(void)
+{
+	unsigned int regdword;
+
+	/* Get the address for pm status, P_LVL2, etc */
+	pci_read_config_dword(pdev_sb, 0x58, &regdword);
+	regdword &= 0xff80;
+	amd76x_pm_cfg.status_reg = (regdword + 0x00);
+	amd76x_pm_cfg.slp_reg =    (regdword + 0x04);
+	amd76x_pm_cfg.NTH_reg =    (regdword + 0x10);
+	amd76x_pm_cfg.C2_reg =     (regdword + 0x14);
+	amd76x_pm_cfg.C3_reg =     (regdword + 0x15);
+	amd76x_pm_cfg.resume_reg = (regdword + 0x16); /* N/A for 768 */
+}
+
+
+/*
+ * En/Disable PMIO and configure W4SG & STPGNT.
+ */
+static int
+config_PMIO_amd76x(int is_766, int enable)
+{
+	unsigned char regbyte;
+
+	/* Clear W4SG, and set PMIOEN, if using a 765/766 set STPGNT as well.
+	 * AMD-766: C3A41; page 59 in AMD-766 doc
+	 * AMD-768: DevB:3x41C; page 94 in AMD-768 doc */
+	pci_read_config_byte(pdev_sb, 0x41, &regbyte);
+	if(enable) {
+		regbyte |= ((0 << 0) | (is_766?1:0 << 1) | (1 << 7));
+	}
+	else {
+		regbyte |= (0 << 7);
+	}
+	pci_write_config_byte(pdev_sb, 0x41, regbyte);
+
+	return 0;
+}
+
+/*
+ * C2 idle support for AMD-766.
+ */
+static void
+config_amd766_C2(int enable)
+{
+	unsigned int regdword;
+
+	/* Set C2 options in C3A50, page 63 in AMD-766 doc */
+	pci_read_config_dword(pdev_sb, 0x50, &regdword);
+	if(enable) {
+		regdword &= ~((DCSTOP_EN | CPUSTP_EN | PCISTP_EN | SUSPND_EN |
+					CPURST_EN) << C2_REGS);
+		regdword |= (STPCLK_EN	/* ~ 20 Watt savings max */
+			 |  CPUSLP_EN)	/* Additional ~ 70 Watts max! */
+			 << C2_REGS;
+	}
+	else
+		regdword &= ~((STPCLK_EN | CPUSLP_EN) << C2_REGS);
+	pci_write_config_dword(pdev_sb, 0x50, regdword);
+}
+
+
+#ifdef AMD76X_C3
+/*
+ * Untested C3 idle support for AMD-766.
+ */
+static void
+config_amd766_C3(int enable)
+{
+	unsigned int regdword;
+
+	/* Set C3 options in C3A50, page 63 in AMD-766 doc */
+	pci_read_config_dword(pdev_sb, 0x50, &regdword);
+	if(enable) {
+		regdword &= ~((DCSTOP_EN | PCISTP_EN | SUSPND_EN | CPURST_EN)
+				<< C3_REGS);
+		regdword |= (STPCLK_EN	/* ~ 20 Watt savings max */
+			 |  CPUSLP_EN	/* Additional ~ 70 Watts max! */
+			 |  CPUSTP_EN)	/* yet more savings! */
+			 << C3_REGS;
+	}
+	else
+		regdword &= ~((STPCLK_EN | CPUSLP_EN | CPUSTP_EN) << C3_REGS);
+	pci_write_config_dword(pdev_sb, 0x50, regdword);
+}
+#endif
+
+
+#ifdef AMD76X_POS
+static void
+config_amd766_POS(int enable)
+{
+	unsigned int regdword;
+
+	/* Set C3 options in C3A50, page 63 in AMD-766 doc */
+	pci_read_config_dword(pdev_sb, 0x50, &regdword);
+	if(enable) {
+		regdword &= ~((ZZ_CACHE_EN | CPURST_EN) << POS_REGS);
+		regdword |= ((DCSTOP_EN | STPCLK_EN | CPUSTP_EN | PCISTP_EN |
+					CPUSLP_EN | SUSPND_EN) << POS_REGS);
+	}
+	else
+		regdword ^= (0xff << POS_REGS);
+	pci_write_config_dword(pdev_sb, 0x50, regdword);
+}
+#endif
+
+
+/*
+ * Configures the 765 & 766 southbridges.
+ */
+static int
+config_amd766(int enable)
+{
+	amd76x_get_PM();
+	config_PMIO_amd76x(1, 1);
+
+	config_amd766_C2(enable);
+#ifdef AMD76X_C3
+	config_amd766_C3(enable);
+#endif
+#ifdef AMD76X_POS
+	config_amd766_POS(enable);
+#endif
+
+	return 0;
+}
+
+
+/*
+ * C2 idling support for AMD-768.
+ */
+static void
+config_amd768_C2(int enable)
+{
+	unsigned char regbyte;
+	
+	/* Set C2 options in DevB:3x4F, page 100 in AMD-768 doc */
+	pci_read_config_byte(pdev_sb, 0x4F, &regbyte);
+	if(enable)
+		regbyte |= C2EN;
+	else
+		regbyte ^= C2EN;
+	pci_write_config_byte(pdev_sb, 0x4F, regbyte);
+}
+
+
+#ifdef AMD76X_C3
+/*
+ * C3 idle support for AMD-768. The idle loop would need some extra
+ * handling for C3, but it would make more sense for ACPI to handle CX level
+ * transitions like it is supposed to. Unfortunately ACPI doesn't do CX
+ * levels on SMP systems yet.
+ */
+static void
+config_amd768_C3(int enable)
+{
+	unsigned char regbyte;
+	
+	/* Set C3 options in DevB:3x4F, page 100 in AMD-768 doc */
+	pci_read_config_byte(pdev_sb, 0x4F, &regbyte);
+	if(enable)
+		regbyte |= (C3EN /* | ZZ_C3EN | CSLP_C3EN | CSTP_C3EN */);
+	else
+		regbyte ^= C3EN;
+	pci_write_config_byte(pdev_sb, 0x4F, regbyte);
+}
+#endif
+
+
+#ifdef AMD76X_POS
+/*
+ * Untested Power On Suspend support for AMD-768. This should also be handled
+ * by ACPI.
+ */
+static void
+config_amd768_POS(int enable)
+{
+	unsigned int regdword;
+
+	/* Set POS options in DevB:3x50, page 101 in AMD-768 doc */
+	pci_read_config_dword(pdev_sb, 0x50, &regdword);
+	if(enable) 
+		regdword |= (POSEN | CSTP | PSTP | ASTP | DCSTP | CSLP | SUSP);
+	else
+		regdword ^= POSEN;
+	pci_write_config_dword(pdev_sb, 0x50, regdword);
+}
+#endif
+
+
+#ifdef AMD76X_NTH
+/*
+ * Normal Throttling support for AMD-768. There are several settings
+ * that can be set depending on how long you want some of the delays to be.
+ * I'm not sure if this is even neccessary at all as the 766 doesn't need this.
+ */
+static void
+config_amd768_NTH(int enable, int ntper, int thminen)
+{
+	unsigned char regbyte;
+
+	/* DevB:3x40, pg 93 of 768 doc */
+	pci_read_config_byte(pdev_sb, 0x40, &regbyte);
+	/* Is it neccessary to use THMINEN at ANY time? */
+	regbyte |= (NTPER(ntper) | THMINEN(thminen));
+	pci_write_config_byte(pdev_sb, 0x40, regbyte);
+}
+#endif
+
+
+/*
+ * Configures the 768 southbridge to support idle calls, and gets
+ * the processor idle call register location.
+ */
+static int
+config_amd768(int enable)
+{
+	amd76x_get_PM();
+	config_PMIO_amd76x(0, 1);
+
+	config_amd768_C2(enable);
+#ifdef AMD76X_C3
+	config_amd768_C3(enable);
+#endif
+#ifdef AMD76X_POS
+	config_amd768_POS(enable);
+#endif
+#ifdef AMD76X_NTH
+	config_amd768_NTH(enable, 1, 2);
+#endif
+
+	return 0;
+}
+
+
+#ifdef AMD76X_NTH
+/*
+ * Activate normal throttling via its ACPI register (P_CNT).
+ */
+static void
+activate_amd76x_NTH(int enable, int ratio)
+{
+	unsigned int regdword;
+
+	/* PM10, pg 110 of 768 doc, pg 70 of 766 doc */
+	regdword=inl(amd76x_pm_cfg.NTH_reg);
+	if(enable)
+		regdword |= (NTH_EN | NTH_RATIO(ratio));
+	else
+		regdword ^= NTH_EN;
+	outl(regdword, amd76x_pm_cfg.NTH_reg);
+}
+#endif
+
+
+/*
+ * Activate sleep state via its ACPI register (PM1_CNT).
+ */
+static void
+activate_amd76x_SLP(int type)
+{
+	unsigned short regshort;
+
+	/* PM04, pg 109 of 768 doc, pg 69 of 766 doc */
+	regshort=inw(amd76x_pm_cfg.slp_reg);
+	regshort |= (SLP_EN | SLP_TYP(type)) ;
+	outw(regshort, amd76x_pm_cfg.slp_reg);
+}
+
+
+#ifdef AMD76X_POS
+/*
+ * Wrapper function to activate POS sleep state.
+ */
+static void
+activate_amd76x_POS(void)
+{
+	activate_amd76x_SLP(1);
+}
+#endif
+
+
+#if 0
+/*
+ * Idle loop for single processor systems
+ */
+void
+amd76x_up_idle(void)
+{
+	// FIXME: Optionally add non-smp idle loop here
+}
+#endif
+
+
+/*
+ * Idle loop for SMP systems, supports currently only 2 processors.
+ *
+ * Note; for 2.5 folks - not pre-empt safe
+ */
+static void
+amd76x_smp_idle(void)
+{
+
+	/*
+	 * Exit idle mode immediately if the CPU does not change.
+	 * Usually that means that we have some load on another CPU.
+	 */
+	if (prs[0].idle && prs[1].idle && amd76x_pm_cfg.last_pr == smp_processor_id()) {
+		prs[0].idle = 0;
+		prs[1].idle = 0;
+		/* This looks redundent as it was just checked in the if() */
+		/* amd76x_pm_cfg.last_pr = smp_processor_id(); */
+		return;
+	}
+
+	prs[smp_processor_id()].count++;
+
+	/* Don't start the idle mode immediately */
+	if (prs[smp_processor_id()].count >= LAZY_IDLE_DELAY) {
+
+		/* Put the current processor into idle mode */
+		prs[smp_processor_id()].idle =
+			(prs[smp_processor_id()].idle ? 2 : 1);
+
+		/* Only idle if both processors are idle */
+		if ((prs[0].idle==1) && (prs[1].idle==1)) {
+			amd76x_pm_cfg.C2_cnt++;
+			inb(amd76x_pm_cfg.C2_reg);
+		}
+	#ifdef AMD76X_C3
+		/*
+		 * JH: I've not been able to get into here. Could this have
+		 * something to do with the way the kernel handles the idle
+		 * loop, or and error that I've made?
+		 */
+		else if ((prs[0].idle==2) && (prs[1].idle==2)) {
+			amd76x_pm_cfg.C3_cnt++;
+			inb(amd76x_pm_cfg.C3_reg);
+		}
+	#endif
+
+		prs[smp_processor_id()].count = 0;
+
+	}
+	amd76x_pm_cfg.last_pr = smp_processor_id();
+}
+
+
+/*
+ * Finds and initializes the bridges, and then sets the idle function
+ */
+static int
+amd76x_pm_main(void)
+{
+	int found;
+
+	/* Find northbridge */
+	found = pci_module_init(&amd_nb_driver);
+	if (found < 0) {
+		printk(KERN_ERR "amd76x_pm: Could not find northbridge\n");
+		return 1;
+	}
+
+	/* Find southbridge */
+	found = pci_module_init(&amd_sb_driver);
+	if (found < 0) {
+		printk(KERN_ERR "amd76x_pm: Could not find southbridge\n");
+		pci_unregister_driver(&amd_nb_driver);
+		return 1;
+	}
+
+	/* Init southbridge */
+	switch (pdev_sb->device) {
+	case PCI_DEVICE_ID_AMD_VIPER_7413:	/* AMD-765 or 766 */
+		config_amd766(1);
+		break;
+	case PCI_DEVICE_ID_AMD_VIPER_7443:	/* AMD-768 */
+		config_amd768(1);
+		break;
+	default:
+		printk(KERN_ERR "amd76x_pm: No southbridge to initialize\n");
+		break;
+	}
+
+	/* Init northbridge and queue the new idle function */
+	switch (pdev_nb->device) {
+	case PCI_DEVICE_ID_AMD_FE_GATE_700C:	/* AMD-762 */
+		config_amd762(1);
+#ifndef AMD76X_NTH
+		amd76x_pm_cfg.curr_idle = amd76x_smp_idle;
+#endif
+		break;
+	default:
+		printk(KERN_ERR "amd76x_pm: No northbridge to initialize\n");
+		break;
+	}
+
+#ifndef AMD76X_NTH
+	if (!amd76x_pm_cfg.curr_idle) {
+		printk(KERN_ERR "amd76x_pm: Idle function not changed\n");
+		return 1;
+	}
+
+	amd76x_pm_cfg.orig_idle = pm_idle;
+	pm_idle = amd76x_pm_cfg.curr_idle;
+#endif
+
+#ifdef AMD76X_NTH
+	/* Turn NTH on with maxium throttling for testing. */
+	activate_amd76x_NTH(1, 1);
+#endif
+
+#ifdef AMD76X_POS
+	/* Testing here only. */
+	activate_amd76x_POS();
+#endif
+
+	return 0;
+}
+
+
+static int __init
+amd76x_pm_init(void)
+{
+	printk(KERN_INFO "amd76x_pm: Version %s\n", VERSION);
+	return amd76x_pm_main();
+}
+
+
+static void __exit
+amd76x_pm_cleanup(void)
+{
+#ifndef AMD76X_NTH
+	pm_idle = amd76x_pm_cfg.orig_idle;
+
+	/* This isn't really needed. */
+	printk(KERN_INFO "amd76x_pm: %lu C2 calls\n", amd76x_pm_cfg.C2_cnt);
+#ifdef AMD76X_C3
+	printk(KERN_INFO "amd76x_pm: %lu C3 calls\n", amd76x_pm_cfg.C3_cnt);
+#endif
+
+	/* 
+	 * FIXME: We want to wait until all CPUs have set the new
+	 * idle function, otherwise we will oops. This may not be
+	 * the right way to do it, but seems to work.
+	 *
+	 * - Best answer is going to be to ban unload, but when its debugged
+	 *   --- Alan
+	 */
+	schedule();
+	mdelay(1000);
+#endif
+
+#ifdef AMD76X_NTH
+	/* Turn NTH off*/
+	activate_amd76x_NTH(0, 0);
+#endif
+
+	pci_unregister_driver(&amd_nb_driver);
+	pci_unregister_driver(&amd_sb_driver);
+
+}
+
+
+MODULE_LICENSE("GPL");
+module_init(amd76x_pm_init);
+module_exit(amd76x_pm_cleanup);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/amd76x_pm.h linux.20pre10-ac2/drivers/char/amd76x_pm.h
--- linux.20pre10/drivers/char/amd76x_pm.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/amd76x_pm.h	2002-08-06 15:42:07.000000000 +0100
@@ -0,0 +1,59 @@
+/* 
+ * Begin 765/766
+ */
+/* C2/C3/POS options in C3A50, page 63 in AMD-766 doc */
+#define ZZ_CACHE_EN	1
+#define DCSTOP_EN	(1 << 1)
+#define STPCLK_EN	(1 << 2)
+#define CPUSTP_EN	(1 << 3)
+#define PCISTP_EN	(1 << 4)
+#define CPUSLP_EN	(1 << 5)
+#define SUSPND_EN	(1 << 6)
+#define CPURST_EN	(1 << 7)
+
+#define C2_REGS		0
+#define C3_REGS		8
+#define POS_REGS	16	
+/*
+ * End 765/766
+ */
+
+
+/*
+ * Begin 768
+ */
+/* C2/C3 options in DevB:3x4F, page 100 in AMD-768 doc */
+#define C2EN		1
+#define C3EN		(1 << 1)
+#define ZZ_C3EN		(1 << 2)
+#define CSLP_C3EN	(1 << 3)
+#define CSTP_C3EN	(1 << 4)
+
+/* POS options in DevB:3x50, page 101 in AMD-768 doc */
+#define POSEN	1
+#define CSTP	(1 << 2)
+#define PSTP	(1 << 3)
+#define ASTP	(1 << 4)
+#define DCSTP	(1 << 5)
+#define CSLP	(1 << 6)
+#define SUSP	(1 << 8)
+#define MSRSM	(1 << 14)
+#define PITRSM	(1 << 15)
+
+/* NTH options DevB:3x40, pg 93 of 768 doc */
+#define NTPER(x) (x << 3)
+#define THMINEN(x) (x << 4)
+
+/*
+ * End 768
+ */
+
+/* NTH activate. PM10, pg 110 of 768 doc, pg 70 of 766 doc */
+#define NTH_RATIO(x) (x << 1)
+#define NTH_EN (1 << 4)
+
+/* Sleep state. PM04, pg 109 of 768 doc, pg 69 of 766 doc */
+#define SLP_EN (1 << 13)
+#define SLP_TYP(x) (x << 10)
+
+#define LAZY_IDLE_DELAY	800	/* 0: Best savings,  3000: More responsive */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/Config.in linux.20pre10-ac2/drivers/char/Config.in
--- linux.20pre10/drivers/char/Config.in	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/Config.in	2002-10-10 23:56:47.000000000 +0100
@@ -193,6 +193,7 @@
    bool '  Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
    tristate '  Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
    tristate '  Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT
+   tristate '  ALi M7101 PMU on ALi 1535D+ Watchdog Timer' CONFIG_ALIM1535_WDT
    tristate '  ALi M7101 PMU Watchdog Timer' CONFIG_ALIM7101_WDT
    tristate '  AMD "Elan" SC520 Watchdog Timer' CONFIG_SC520_WDT
    tristate '  Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
@@ -212,6 +213,7 @@
    tristate '  Mixcom Watchdog' CONFIG_MIXCOMWD 
    tristate '  SBC-60XX Watchdog Timer' CONFIG_60XX_WDT
    dep_tristate '  SC1200 Watchdog Timer (EXPERIMENTAL)' CONFIG_SC1200_WDT $CONFIG_EXPERIMENTAL
+   tristate '  NatSemi SCx200 Watchdog' CONFIG_SCx200_WDT
    tristate '  Software Watchdog' CONFIG_SOFT_WATCHDOG
    tristate '  W83877F (EMACS) Watchdog Timer' CONFIG_W83877F_WDT
    tristate '  WDT Watchdog timer' CONFIG_WDT
@@ -235,6 +237,7 @@
    fi
    tristate 'NetWinder flash support' CONFIG_NWFLASH
 fi
+dep_tristate 'NatSemi SCx200 GPIO Support' CONFIG_SCx200_GPIO $CONFIG_SCx200
 
 if [ "$CONFIG_X86" = "y" -o "$CONFIG_X86_64" = "y" ]; then
    dep_tristate 'AMD 768 Random Number Generator support' CONFIG_AMD_RNG $CONFIG_PCI
@@ -242,6 +245,7 @@
 if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then
    dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI
 fi
+dep_tristate 'AMD 76x native power management (Experimental)' CONFIG_AMD_PM768 $CONFIG_PCI
 tristate '/dev/nvram support' CONFIG_NVRAM
 tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
 if [ "$CONFIG_IA64" = "y" ]; then
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/console.c linux.20pre10-ac2/drivers/char/console.c
--- linux.20pre10/drivers/char/console.c	2002-10-09 21:36:46.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/console.c	2002-09-27 14:01:00.000000000 +0100
@@ -1421,7 +1421,10 @@
 	kbd_table[currcons].slockstate = 0;
 	kbd_table[currcons].ledmode = LED_SHOW_FLAGS;
 	kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
-	set_leds();
+	
+	/* Only schedule the keyboard_tasklet if it is enabled. */
+	if(!atomic_read(&keyboard_tasklet.count))
+		set_leds();
 
 	cursor_type = CUR_DEFAULT;
 	complement_mask = s_complement_mask;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/drm/i810_dma.c linux.20pre10-ac2/drivers/char/drm/i810_dma.c
--- linux.20pre10/drivers/char/drm/i810_dma.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/drm/i810_dma.c	2002-10-07 21:31:25.000000000 +0100
@@ -219,7 +219,7 @@
 		down_write( &current->mm->mmap_sem );
         	retcode = do_munmap(current->mm,
 				    (unsigned long)buf_priv->virtual,
-				    (size_t) buf->total);
+				    (size_t) buf->total, 1);
 		up_write( &current->mm->mmap_sem );
 	}
    	buf_priv->currently_mapped = I810_BUF_UNMAPPED;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/drm/i830_dma.c linux.20pre10-ac2/drivers/char/drm/i830_dma.c
--- linux.20pre10/drivers/char/drm/i830_dma.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/drm/i830_dma.c	2002-09-26 22:20:23.000000000 +0100
@@ -233,7 +233,7 @@
 		down_write( &current->mm->mmap_sem );
         	retcode = do_munmap(current->mm, 
 				    (unsigned long)buf_priv->virtual, 
-				    (size_t) buf->total);
+				    (size_t) buf->total, 1);
    		up_write( &current->mm->mmap_sem );
 	}
    	buf_priv->currently_mapped = I830_BUF_UNMAPPED;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/drm/sis_ds.c linux.20pre10-ac2/drivers/char/drm/sis_ds.c
--- linux.20pre10/drivers/char/drm/sis_ds.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/drm/sis_ds.c	2002-09-01 17:44:07.000000000 +0100
@@ -49,15 +49,16 @@
   set_t *set;
 
   set = (set_t *)MALLOC(sizeof(set_t));
-  for(i = 0; i < SET_SIZE; i++){
-    set->list[i].free_next = i+1;    
-    set->list[i].alloc_next = -1;
-  }    
-  set->list[SET_SIZE-1].free_next = -1;
-  set->free = 0;
-  set->alloc = -1;
-  set->trace = -1;
-  
+  if (set) {
+    for(i = 0; i < SET_SIZE; i++){
+      set->list[i].free_next = i+1;    
+      set->list[i].alloc_next = -1;
+    }    
+    set->list[SET_SIZE-1].free_next = -1;
+    set->free = 0;
+    set->alloc = -1;
+    set->trace = -1;
+  }
   return set;
 }
 
@@ -171,7 +172,8 @@
 {
   void *addr;
   addr = kmalloc(nmemb*size, GFP_KERNEL);
-  memset(addr, 0, nmemb*size);
+  if (addr)
+    memset(addr, 0, nmemb*size);
   return addr;
 }
 #define free(n) kfree(n)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/drm-4.0/i810_dma.c linux.20pre10-ac2/drivers/char/drm-4.0/i810_dma.c
--- linux.20pre10/drivers/char/drm-4.0/i810_dma.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/drm-4.0/i810_dma.c	2002-08-06 15:42:07.000000000 +0100
@@ -231,7 +231,7 @@
 #else
         	retcode = do_munmap(current->mm, 
 				    (unsigned long)buf_priv->virtual, 
-				    (size_t) buf->total);
+				    (size_t) buf->total, 1);
 #endif
    		up_write(&current->mm->mmap_sem);
 	}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/drm-4.0/tdfx_drv.c linux.20pre10-ac2/drivers/char/drm-4.0/tdfx_drv.c
--- linux.20pre10/drivers/char/drm-4.0/tdfx_drv.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/drm-4.0/tdfx_drv.c	2002-08-21 22:26:53.000000000 +0100
@@ -554,7 +554,6 @@
 					lock.context, current->pid, j,
 					dev->lock.lock_time, jiffies);
                                 current->state = TASK_INTERRUPTIBLE;
-				current->policy |= SCHED_YIELD;
                                 schedule_timeout(DRM_LOCK_SLICE-j);
 				DRM_DEBUG("jiffies=%d\n", jiffies);
                         }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/eurotechwdt.c linux.20pre10-ac2/drivers/char/eurotechwdt.c
--- linux.20pre10/drivers/char/eurotechwdt.c	2002-10-09 21:36:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/eurotechwdt.c	2002-09-29 20:29:59.000000000 +0100
@@ -35,6 +35,9 @@
  *
  * 2001 - Rodolfo Giometti
  *	Initial release
+ *
+ * 2002.05.30 - Joel Becker <joel.becker@oracle.com>
+ * 	Added Matt Domsch's nowayout module option.
  */
 
 #include <linux/config.h>
@@ -68,6 +71,14 @@
  
 #define WDT_TIMEOUT		60                /* 1 minute */
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
 /*
  * Some symbolic names 
@@ -127,48 +138,48 @@
 
 static inline void eurwdt_write_reg(u8 index, u8 data)
 {
-   outb(index, io);
-   outb(data, io+1);
+	outb(index, io);
+	outb(data, io+1);
 }
 
 static inline void eurwdt_lock_chip(void)
 {
-   outb(0xaa, io);
+	outb(0xaa, io);
 }
 
 static inline void eurwdt_unlock_chip(void)
 {
-   outb(0x55, io);
-   eurwdt_write_reg(0x07, 0x08);   /* set the logical device */
+	outb(0x55, io);
+	eurwdt_write_reg(0x07, 0x08);   /* set the logical device */
 }
 
 static inline void eurwdt_set_timeout(int timeout)
 {
-   eurwdt_write_reg(WDT_TIMEOUT_VAL, (u8) timeout);
+	eurwdt_write_reg(WDT_TIMEOUT_VAL, (u8) timeout);
 }
 
 static inline void eurwdt_disable_timer(void)
 {
-   eurwdt_set_timeout(0);
+	eurwdt_set_timeout(0);
 }
  
 static void eurwdt_activate_timer(void)
 {
-   eurwdt_disable_timer();
-   eurwdt_write_reg(WDT_CTRL_REG, 0x01);      /* activate the WDT */
-   eurwdt_write_reg(WDT_OUTPIN_CFG, !strcmp("int", ev) ?
+	eurwdt_disable_timer();
+	eurwdt_write_reg(WDT_CTRL_REG, 0x01);      /* activate the WDT */
+	eurwdt_write_reg(WDT_OUTPIN_CFG, !strcmp("int", ev) ?
                                     WDT_EVENT_INT : WDT_EVENT_REBOOT);
-   /* Setting interrupt line */
-   if (irq == 2 || irq > 15 || irq < 0) {
-      printk(KERN_ERR ": invalid irq number\n");
-      irq = 0;   /* if invalid we disable interrupt */
-   }
-   if (irq == 0)
-      printk(KERN_INFO ": interrupt disabled\n");
-   eurwdt_write_reg(WDT_TIMER_CFG, irq<<4);
+	/* Setting interrupt line */
+	if (irq == 2 || irq > 15 || irq < 0) {
+		printk(KERN_ERR ": invalid irq number\n");
+		irq = 0;   /* if invalid we disable interrupt */
+	}
+	if (irq == 0)
+		printk(KERN_INFO ": interrupt disabled\n");
+	eurwdt_write_reg(WDT_TIMER_CFG, irq<<4);
 
-   eurwdt_write_reg(WDT_UNIT_SEL, WDT_UNIT_SECS);   /* we use seconds */
-   eurwdt_set_timeout(0);                           /* the default timeout */ 
+	eurwdt_write_reg(WDT_UNIT_SEL, WDT_UNIT_SECS);   /* we use seconds */
+	eurwdt_set_timeout(0);                           /* the default timeout */ 
 }
 
 
@@ -178,13 +189,13 @@
  
 void eurwdt_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-   printk(KERN_CRIT "timeout WDT timeout\n");
+	printk(KERN_CRIT "timeout WDT timeout\n");
  
 #ifdef ONLY_TESTING
-   printk(KERN_CRIT "Would Reboot.\n");
+	printk(KERN_CRIT "Would Reboot.\n");
 #else
-   printk(KERN_CRIT "Initiating system reboot.\n");
-   machine_restart(NULL);
+	printk(KERN_CRIT "Initiating system reboot.\n");
+	machine_restart(NULL);
 #endif
 }
 
@@ -197,8 +208,8 @@
  
 static void eurwdt_ping(void)
 {
-   /* Write the watchdog default value */
-   eurwdt_set_timeout(eurwdt_timeout);
+	/* Write the watchdog default value */
+	eurwdt_set_timeout(eurwdt_timeout);
 }
  
 /**
@@ -212,28 +223,29 @@
  *      write of data will do, as we we don't define content meaning.
  */
  
-static ssize_t eurwdt_write(struct file *file, const char *buf, size_t count,
-loff_t *ppos)
+static ssize_t eurwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
-   /*  Can't seek (pwrite) on this device  */
-   if (ppos != &file->f_pos)
-      return -ESPIPE;
- 
-   if (count) {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-      size_t i;
-
-      eur_expect_close = 0;
-
-      for (i = 0; i != count; i++) {
-         if (buf[i] == 'V')
-            eur_expect_close = 42;
-      }
-#endif
-      eurwdt_ping();   /* the default timeout */
-   }
-
-   return count;
+	/*  Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+ 
+	if (count) {
+		if (!nowayout) {
+			size_t i;
+
+			eur_expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if(get_user(c, buf+i))
+					return -EFAULT;
+				if (c == 'V')
+					eur_expect_close = 42;
+			}
+		}
+		eurwdt_ping();   /* the default timeout */
+	}
+	return count;
 }
 
 /**
@@ -250,66 +262,54 @@
 static int eurwdt_ioctl(struct inode *inode, struct file *file,
         unsigned int cmd, unsigned long arg)
 {
-   static struct watchdog_info ident = {
-      options		: WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
-      firmware_version	: 0,
-      identity		: "WDT Eurotech CPU-1220/1410"
-   };
-
-   int time;
- 
-   switch(cmd) {
-      default:
-         return -ENOTTY;
-
-      case WDIOC_GETSUPPORT:
-         return copy_to_user((struct watchdog_info *)arg, &ident,
-               sizeof(ident)) ? -EFAULT : 0;
- 
-      case WDIOC_GETSTATUS:
-      case WDIOC_GETBOOTSTATUS:
-         return put_user(0, (int *) arg);
-
-      case WDIOC_KEEPALIVE:
-         eurwdt_ping();
-         return 0;
-
-      case WDIOC_SETTIMEOUT:
-         if (copy_from_user(&time, (int *) arg, sizeof(int)))
-            return -EFAULT;
-
-         /* Sanity check */
-         if (time < 0 || time > 255)
-            return -EINVAL;
-
-         eurwdt_timeout = time; 
-         eurwdt_set_timeout(time); 
-	 /* Fall */
-
-      case WDIOC_GETTIMEOUT:
-	 return put_user(eurwdt_timeout, (int *)arg);
-
-      case WDIOC_SETOPTIONS:
-      {
-	 int options, retval = -EINVAL;
-
-	 if (get_user(options, (int *)arg))
-	    return -EFAULT;
-
-	 if (options & WDIOS_DISABLECARD) {
-	    eurwdt_disable_timer();
-	    retval = 0;
-	 }
-
-	 if (options & WDIOS_ENABLECARD) {
-	    eurwdt_activate_timer();
-	    eurwdt_ping();
-	    retval = 0;
-	 }
-
-	 return retval;
-      }
-   }
+	static struct watchdog_info ident = {
+		options		: WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
+		firmware_version	: 0,
+		identity		: "WDT Eurotech CPU-1220/1410"
+	};
+	int time;
+ 
+	switch(cmd) {
+		default:
+			return -ENOTTY;
+		case WDIOC_GETSUPPORT:
+			return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)) ? -EFAULT : 0;
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, (int *) arg);
+		case WDIOC_KEEPALIVE:
+			eurwdt_ping();
+			return 0;
+		case WDIOC_SETTIMEOUT:
+			if (copy_from_user(&time, (int *) arg, sizeof(int)))
+				return -EFAULT;
+			/* Sanity check */
+			if (time < 0 || time > 255)
+				return -EINVAL;
+			eurwdt_timeout = time; 
+			eurwdt_set_timeout(time); 
+			/* Fall */
+		case WDIOC_GETTIMEOUT:
+			return put_user(eurwdt_timeout, (int *)arg);
+		case WDIOC_SETOPTIONS:
+		{
+			int options, retval = -EINVAL;
+
+			if (get_user(options, (int *)arg))
+				return -EFAULT;
+			if (options & WDIOS_DISABLECARD) {
+				eurwdt_disable_timer();
+				retval = 0;
+			}
+
+			if (options & WDIOS_ENABLECARD) {
+				eurwdt_activate_timer();
+				eurwdt_ping();
+				retval = 0;
+			}
+			return retval;
+		}
+	}
 }
 
 /**
@@ -323,15 +323,15 @@
  
 static int eurwdt_open(struct inode *inode, struct file *file)
 {
-   if (test_and_set_bit(0, &eurwdt_is_open))
-      return -EBUSY;
+	if (test_and_set_bit(0, &eurwdt_is_open))
+		return -EBUSY;
 
-   eurwdt_timeout = WDT_TIMEOUT;   /* initial timeout */
+	eurwdt_timeout = WDT_TIMEOUT;   /* initial timeout */
 
-   /* Activate the WDT */
-   eurwdt_activate_timer(); 
+	/* Activate the WDT */
+	eurwdt_activate_timer(); 
 
-   return 0;
+	return 0;
 }
  
 /**
@@ -348,16 +348,15 @@
  
 static int eurwdt_release(struct inode *inode, struct file *file)
 {
-   if (eur_expect_close == 42) {
-      eurwdt_disable_timer();
-   } else {
-      printk(KERN_CRIT "eurwdt: Unexpected close, not stopping watchdog!\n");
-      eurwdt_ping();
-   }
-   clear_bit(0, &eurwdt_is_open);
-   eur_expect_close = 0;
-
-   return 0;
+	if (eur_expect_close == 42) {
+		eurwdt_disable_timer();
+	} else {
+		printk(KERN_CRIT "eurwdt: Unexpected close, not stopping watchdog!\n");
+		eurwdt_ping();
+	}
+	clear_bit(0, &eurwdt_is_open);
+	eur_expect_close = 0;
+	return 0;
 }
  
 /**
@@ -375,12 +374,11 @@
 static int eurwdt_notify_sys(struct notifier_block *this, unsigned long code,
         void *unused)
 {
-   if (code == SYS_DOWN || code == SYS_HALT) {
-      /* Turn the card off */
-      eurwdt_disable_timer();
-   }
-
-   return NOTIFY_DONE;
+	if (code == SYS_DOWN || code == SYS_HALT) {
+		/* Turn the card off */
+		eurwdt_disable_timer();
+	}
+	return NOTIFY_DONE;
 }
  
 /*
@@ -428,13 +426,11 @@
  
 static void __exit eurwdt_exit(void)
 {
-   eurwdt_lock_chip();
-
-   misc_deregister(&eurwdt_miscdev);
-
-   unregister_reboot_notifier(&eurwdt_notifier);
-   release_region(io, 2);
-   free_irq(irq, NULL);
+	eurwdt_lock_chip();
+	misc_deregister(&eurwdt_miscdev);
+	unregister_reboot_notifier(&eurwdt_notifier);
+	release_region(io, 2);
+	free_irq(irq, NULL);
 }
  
 /**
@@ -447,52 +443,44 @@
  
 static int __init eurwdt_init(void)
 {
-   int ret;
- 
-   ret = misc_register(&eurwdt_miscdev);
-   if (ret) {
-      printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n",
-            WATCHDOG_MINOR);
-      goto out;
-   }
-
-   ret = request_irq(irq, eurwdt_interrupt, SA_INTERRUPT, "eurwdt", NULL);
-   if(ret) {
-      printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq);
-      goto outmisc;
-   }
-
-   if (!request_region(io, 2, "eurwdt")) {
-       printk(KERN_ERR "eurwdt: IO %X is not free.\n", io);
-       ret = -EBUSY;
-       goto outirq;
-   }
-
-   ret = register_reboot_notifier(&eurwdt_notifier);
-   if (ret) {
-      printk(KERN_ERR "eurwdt: can't register reboot notifier (err=%d)\n", ret);
-      goto outreg;
-   }
-
-   eurwdt_unlock_chip();
+	int ret;
  
-   ret = 0;
-   printk(KERN_INFO "Eurotech WDT driver 0.01 at %X (Interrupt %d)"
-                    " - timeout event: %s\n", 
-         io, irq, (!strcmp("int", ev) ? "int" : "reboot"));
-
-   out:
-      return ret;
- 
-   outreg:
-      release_region(io, 2);
-
-   outirq:
-      free_irq(irq, NULL);
-
-   outmisc:
-      misc_deregister(&eurwdt_miscdev);
-      goto out;
+	ret = misc_register(&eurwdt_miscdev);
+	if (ret) {
+		printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n", WATCHDOG_MINOR);
+		goto out;
+	}
+	ret = request_irq(irq, eurwdt_interrupt, SA_INTERRUPT, "eurwdt", NULL);
+	if(ret) {
+		printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq);
+		goto outmisc;
+	}
+
+	if (!request_region(io, 2, "eurwdt")) {
+		printk(KERN_ERR "eurwdt: IO %X is not free.\n", io);
+		ret = -EBUSY;
+		goto outirq;
+	}
+
+	ret = register_reboot_notifier(&eurwdt_notifier);
+	if (ret) {
+		printk(KERN_ERR "eurwdt: can't register reboot notifier (err=%d)\n", ret);
+		goto outreg;
+	}
+	eurwdt_unlock_chip();
+ 
+	ret = 0;
+	printk(KERN_INFO "Eurotech WDT driver 0.01 at %X (Interrupt %d)"
+                    " - timeout event: %s\n",  io, irq, (!strcmp("int", ev) ? "int" : "reboot"));
+	return ret;
+outreg:
+	release_region(io, 2);
+outirq:
+	free_irq(irq, NULL);
+outmisc:
+	misc_deregister(&eurwdt_miscdev);
+out:
+	return ret;
 }
  
 module_init(eurwdt_init);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/i810-tco.c linux.20pre10-ac2/drivers/char/i810-tco.c
--- linux.20pre10/drivers/char/i810-tco.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/i810-tco.c	2002-09-29 20:29:59.000000000 +0100
@@ -244,7 +244,9 @@
 	int options, retval = -EINVAL;
 
 	static struct watchdog_info ident = {
-		options:		WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+		options:		WDIOF_SETTIMEOUT |
+					WDIOF_KEEPALIVEPING |
+					WDIOF_MAGICCLOSE,
 		firmware_version:	0,
 		identity:		"i810 TCO timer",
 	};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/ib700wdt.c linux.20pre10-ac2/drivers/char/ib700wdt.c
--- linux.20pre10/drivers/char/ib700wdt.c	2002-10-09 21:36:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/ib700wdt.c	2002-09-29 20:29:59.000000000 +0100
@@ -50,6 +50,7 @@
 
 static int ibwdt_is_open;
 static spinlock_t ibwdt_lock;
+static int expect_close = 0;
 
 /*
  *
@@ -114,6 +115,15 @@
 
 static int wd_margin = WD_TIMO;
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 
 /*
  *	Kernel methods.
@@ -134,6 +144,20 @@
 		return -ESPIPE;
 
 	if (count) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 1;
+			}
+		}
 		ibwdt_ping();
 		return 1;
 	}
@@ -153,7 +177,10 @@
 	int i, new_margin;
 
 	static struct watchdog_info ident = {
-		WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, 1, "IB700 WDT"
+		WDIOF_KEEPALIVEPING |
+		WDIOF_SETTIMEOUT |
+		WDIOF_MAGICCLOSE,
+		1, "IB700 WDT"
 	};
 
 	switch (cmd) {
@@ -222,9 +249,11 @@
 	lock_kernel();
 	if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
 		spin_lock(&ibwdt_lock);
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-		outb_p(wd_times[wd_margin], WDT_STOP);
-#endif
+		if (expect_close) {
+			outb_p(wd_times[wd_margin], WDT_STOP);
+		} else {
+			printk(KERN_CRIT "WDT device closed unexpectedly.  WDT will not stop!\n");
+		}
 		ibwdt_is_open = 0;
 		spin_unlock(&ibwdt_lock);
 	}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/indydog.c linux.20pre10-ac2/drivers/char/indydog.c
--- linux.20pre10/drivers/char/indydog.c	2002-10-09 21:36:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/indydog.c	2002-09-29 20:29:59.000000000 +0100
@@ -26,6 +26,16 @@
 
 static unsigned long indydog_alive;
 static struct sgimc_misc_ctrl *mcmisc_regs; 
+static int expect_close = 0;
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
 static void indydog_ping()
 {
@@ -43,9 +53,9 @@
 	
 	if( test_and_set_bit(0,&indydog_alive) )
 		return -EBUSY;
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
-	MOD_INC_USE_COUNT;
-#endif
+	if (nowayout) {
+		MOD_INC_USE_COUNT;
+	}
 	/*
 	 *	Activate timer
 	 */
@@ -63,16 +73,19 @@
 {
 	/*
 	 *	Shut off the timer.
-	 * 	Lock it in if it's a module and we defined ...NOWAYOUT
+	 * 	Lock it in if it's a module and we set nowayout.
 	 */
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
+	if (expect_close)
 	{
-	u32 mc_ctrl0 = mcmisc_regs->cpuctrl0; 
-	mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
-	mcmisc_regs->cpuctrl0 = mc_ctrl0;
-	printk("Stopped watchdog timer.\n");
+		u32 mc_ctrl0 = mcmisc_regs->cpuctrl0; 
+		mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
+		mcmisc_regs->cpuctrl0 = mc_ctrl0;
+		printk("Stopped watchdog timer.\n");
+	}
+	else
+	{
+		printk(KERN_CRIT "WDT device closed unexpectedly.  WDT will not stop!\n");
 	}
-#endif
 	clear_bit(0,&indydog_alive);
 	return 0;
 }
@@ -87,6 +100,20 @@
 	 *	Refresh the timer.
 	 */
 	if(len) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != len; i++) {
+				char c;
+				if (get_user(c, data + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 1;
+			}
+		}
 		indydog_ping();
 		return 1;
 	}
@@ -97,6 +124,7 @@
 	unsigned int cmd, unsigned long arg)
 {
 	static struct watchdog_info ident = {
+		options: WDIOF_MAGICCLOSE,
 		identity: "Hardware Watchdog for SGI IP22",
 	};
 	switch (cmd) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/joystick/Config.in linux.20pre10-ac2/drivers/char/joystick/Config.in
--- linux.20pre10/drivers/char/joystick/Config.in	2002-10-09 21:36:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/joystick/Config.in	2002-09-12 13:55:03.000000000 +0100
@@ -9,7 +9,7 @@
    dep_tristate 'Game port support' CONFIG_INPUT_GAMEPORT $CONFIG_INPUT
       dep_tristate '  Classic ISA/PnP gameports' CONFIG_INPUT_NS558 $CONFIG_INPUT_GAMEPORT
       dep_tristate '  PDPI Lightning 4 gamecard' CONFIG_INPUT_LIGHTNING $CONFIG_INPUT_GAMEPORT
-      dep_tristate '  Aureal Vortex and Trident 4DWave gameports' CONFIG_INPUT_PCIGAME $CONFIG_INPUT_GAMEPORT
+      dep_tristate '  Aureal Vortex, Trident 4DWave, and ALi 5451 gameports' CONFIG_INPUT_PCIGAME $CONFIG_INPUT_GAMEPORT
       dep_tristate '  Crystal SoundFusion gameports' CONFIG_INPUT_CS461X  $CONFIG_INPUT_GAMEPORT
       dep_tristate '  SoundBlaster Live! gameports' CONFIG_INPUT_EMU10K1 $CONFIG_INPUT_GAMEPORT
    tristate 'Serial port device support' CONFIG_INPUT_SERIO
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/machzwd.c linux.20pre10-ac2/drivers/char/machzwd.c
--- linux.20pre10/drivers/char/machzwd.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/machzwd.c	2002-09-29 20:29:59.000000000 +0100
@@ -24,6 +24,8 @@
  *  a system RESET and it starts wd#2 that unconditionaly will RESET 
  *  the system when the counter reaches zero.
  *
+ *  14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ * 	Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
  */
 
 #include <linux/config.h>
@@ -103,10 +105,19 @@
 MODULE_PARM(action, "i");
 MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*)  1 = SMI  2 = NMI  3 = SCI");
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 #define PFX "machzwd"
 
 static struct watchdog_info zf_info = {
-	options:		WDIOF_KEEPALIVEPING, 
+	options:		WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 
 	firmware_version:	1, 
 	identity:		"ZF-Logic watchdog"
 };
@@ -307,26 +318,26 @@
 		 * no need to check for close confirmation
 		 * no way to disable watchdog ;)
 		 */
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-		size_t ofs;
-
-		/* 
-		 * note: just in case someone wrote the magic character
-		 * five months ago...
-		 */
-		zf_expect_close = 0;
+		if (!nowayout) {
+			size_t ofs;
 
-		/* now scan */
-		for(ofs = 0; ofs != count; ofs++){
-			char c;
-			if(get_user(c, buf+ofs))
-				return -EFAULT;
-			if(c == 'V'){
-				zf_expect_close = 1;
-				dprintk("zf_expect_close 1\n");
+			/* 
+			 * note: just in case someone wrote the
+			 * magic character five months ago...
+			 */
+			zf_expect_close = 0;
+
+			/* now scan */
+			for(ofs = 0; ofs != count; ofs++){
+				char c;
+				if(get_user(c, buf+ofs))
+					return -EFAULT;
+				if(c == 'V'){
+					zf_expect_close = 1;
+					dprintk("zf_expect_close 1\n");
+				}
 			}
 		}
-#endif
 		/*
 		 * Well, anyhow someone wrote to us,
 		 * we should return that favour
@@ -384,9 +395,9 @@
 				return -EBUSY;
 			}
 
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
-			MOD_INC_USE_COUNT;
-#endif
+			if (nowayout) {
+				MOD_INC_USE_COUNT;
+			}
 			zf_is_open = 1;
 
 			spin_unlock(&zf_lock);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/Makefile linux.20pre10-ac2/drivers/char/Makefile
--- linux.20pre10/drivers/char/Makefile	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/Makefile	2002-10-10 23:56:47.000000000 +0100
@@ -230,6 +230,7 @@
 obj-$(CONFIG_DS1620) += ds1620.o
 obj-$(CONFIG_INTEL_RNG) += i810_rng.o
 obj-$(CONFIG_AMD_RNG) += amd768_rng.o
+obj-$(CONFIG_AMD_PM768) += amd76x_pm.o
 
 obj-$(CONFIG_ITE_GPIO) += ite_gpio.o
 obj-$(CONFIG_AU1000_GPIO) += au1000_gpio.o
@@ -252,6 +253,7 @@
 obj-$(CONFIG_DZ) += dz.o
 obj-$(CONFIG_NWBUTTON) += nwbutton.o
 obj-$(CONFIG_NWFLASH) += nwflash.o
+obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o
 
 # Only one watchdog can succeed. We probe the hardware watchdog
 # drivers first, then the softdog driver.  This means if your hardware
@@ -275,9 +277,10 @@
 obj-$(CONFIG_SH_WDT) += shwdt.o
 obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
 obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
-#obj-$(CONFIG_ALIM1535_WDT) += alim1535d_wdt.o
+obj-$(CONFIG_ALIM1535_WDT) += alim1535d_wdt.o
 obj-$(CONFIG_INDYDOG) += indydog.o
 obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
+obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
 obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
 obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
 obj-$(CONFIG_AMD7XX_TCO) += amd7xx_tco.o
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/mixcomwd.c linux.20pre10-ac2/drivers/char/mixcomwd.c
--- linux.20pre10/drivers/char/mixcomwd.c	2002-10-09 21:36:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/mixcomwd.c	2002-09-29 20:29:59.000000000 +0100
@@ -27,10 +27,13 @@
  *
  * Version 0.4 (99/11/15):
  *		- support for one more type board
+ *
+ * Version 0.5 (2001/12/14) Matt Domsch <Matt_Domsch@dell.com>
+ * 		- added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
  *	
  */
 
-#define VERSION "0.4" 
+#define VERSION "0.5" 
   
 #include <linux/module.h>
 #include <linux/config.h>
@@ -58,25 +61,31 @@
 
 static int watchdog_port;
 
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
 static int mixcomwd_timer_alive;
 static struct timer_list mixcomwd_timer;
+static int expect_close = 0;
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
 #endif
 
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 static void mixcomwd_ping(void)
 {
 	outb_p(55,watchdog_port);
 	return;
 }
 
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
 static void mixcomwd_timerfun(unsigned long d)
 {
 	mixcomwd_ping();
 	
 	mod_timer(&mixcomwd_timer,jiffies+ 5*HZ);
 }
-#endif
 
 /*
  *	Allow only one person to hold it open
@@ -89,12 +98,13 @@
 	}
 	mixcomwd_ping();
 	
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
+	if (nowayout) {
+		MOD_INC_USE_COUNT;
+	}
 	if(mixcomwd_timer_alive) {
 		del_timer(&mixcomwd_timer);
 		mixcomwd_timer_alive=0;
 	} 
-#endif
 	return 0;
 }
 
@@ -102,19 +112,21 @@
 {
 
 	lock_kernel();
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-	if(mixcomwd_timer_alive) {
-		printk(KERN_ERR "mixcomwd: release called while internal timer alive");
-		unlock_kernel();
-		return -EBUSY;
+	if (expect_close) {
+		if(mixcomwd_timer_alive) {
+			printk(KERN_ERR "mixcomwd: release called while internal timer alive");
+			unlock_kernel();
+			return -EBUSY;
+		}
+		init_timer(&mixcomwd_timer);
+		mixcomwd_timer.expires=jiffies + 5 * HZ;
+		mixcomwd_timer.function=mixcomwd_timerfun;
+		mixcomwd_timer.data=0;
+		mixcomwd_timer_alive=1;
+		add_timer(&mixcomwd_timer);
+	} else {
+		printk(KERN_CRIT "mixcomwd: WDT device closed unexpectedly.  WDT will not stop!\n");
 	}
-	init_timer(&mixcomwd_timer);
-	mixcomwd_timer.expires=jiffies + 5 * HZ;
-	mixcomwd_timer.function=mixcomwd_timerfun;
-	mixcomwd_timer.data=0;
-	mixcomwd_timer_alive=1;
-	add_timer(&mixcomwd_timer);
-#endif
 
 	clear_bit(0,&mixcomwd_opened);
 	unlock_kernel();
@@ -130,6 +142,20 @@
 
 	if(len)
 	{
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != len; i++) {
+				char c;
+				if (get_user(c, data + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 1;
+			}
+		}
 		mixcomwd_ping();
 		return 1;
 	}
@@ -141,16 +167,17 @@
 {
 	int status;
         static struct watchdog_info ident = {
-		WDIOF_KEEPALIVEPING, 1, "MixCOM watchdog"
+		WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+		1, "MixCOM watchdog"
 	};
                                         
 	switch(cmd)
 	{
 		case WDIOC_GETSTATUS:
 			status=mixcomwd_opened;
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-			status|=mixcomwd_timer_alive;
-#endif
+			if (!nowayout) {
+				status|=mixcomwd_timer_alive;
+			}
 			if (copy_to_user((int *)arg, &status, sizeof(int))) {
 				return -EFAULT;
 			}
@@ -255,14 +282,14 @@
 
 static void __exit mixcomwd_exit(void)
 {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-	if(mixcomwd_timer_alive) {
-		printk(KERN_WARNING "mixcomwd: I quit now, hardware will"
-			" probably reboot!\n");
-		del_timer(&mixcomwd_timer);
-		mixcomwd_timer_alive=0;
+	if (!nowayout) {
+		if(mixcomwd_timer_alive) {
+			printk(KERN_WARNING "mixcomwd: I quit now, hardware will"
+				" probably reboot!\n");
+			del_timer(&mixcomwd_timer);
+			mixcomwd_timer_alive=0;
+		}
 	}
-#endif
 	release_region(watchdog_port,1);
 	misc_deregister(&mixcomwd_miscdev);
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/mwave/mwavedd.c linux.20pre10-ac2/drivers/char/mwave/mwavedd.c
--- linux.20pre10/drivers/char/mwave/mwavedd.c	2002-10-09 21:36:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/mwave/mwavedd.c	2002-08-06 15:42:07.000000000 +0100
@@ -279,7 +279,6 @@
 			pDrvData->IPCs[ipcnum].bIsHere = FALSE;
 			pDrvData->IPCs[ipcnum].bIsEnabled = TRUE;
 	#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-			current->nice = -20;	/* boost to provide priority timing */
 	#else
 			current->priority = 0x28;	/* boost to provide priority timing */
 	#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/n_r3964.c linux.20pre10-ac2/drivers/char/n_r3964.c
--- linux.20pre10/drivers/char/n_r3964.c	2002-10-09 21:36:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/n_r3964.c	2002-08-06 15:42:07.000000000 +0100
@@ -1364,7 +1364,7 @@
       pHeader->owner = pClient;
    }
 
-   copy_from_user (pHeader->data, data, count); /* We already verified this */
+   __copy_from_user(pHeader->data, data, count); /* We already verified this */
 
    if(pInfo->flags & R3964_DEBUG)
    {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/nwflash.c linux.20pre10-ac2/drivers/char/nwflash.c
--- linux.20pre10/drivers/char/nwflash.c	2002-10-09 21:36:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/nwflash.c	2002-08-06 15:42:07.000000000 +0100
@@ -154,12 +154,11 @@
 		if (down_interruptible(&nwflash_sem))
 			return -ERESTARTSYS;
 
-		ret = copy_to_user(buf, (void *)(FLASH_BASE + p), count);
-		if (ret == 0) {
-			ret = count;
-			*ppos += count;
-		}
+		ret = count - copy_to_user(buf, (void *)(FLASH_BASE + p), count);
+		*ppos += ret;
 		up(&nwflash_sem);
+		if (ret == 0)
+			ret = -EFAULT;
 	}
 	return ret;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/pc_keyb.c linux.20pre10-ac2/drivers/char/pc_keyb.c
--- linux.20pre10/drivers/char/pc_keyb.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/pc_keyb.c	2002-10-07 21:31:35.000000000 +0100
@@ -64,7 +64,6 @@
 static void kbd_write_command_w(int data);
 static void kbd_write_output_w(int data);
 #ifdef CONFIG_PSMOUSE
-static void aux_write_ack(int val);
 static void __aux_write_ack(int val);
 static int aux_reconnect = 0;
 #endif
@@ -1009,6 +1008,7 @@
 	kb_wait();
 }
 
+#ifdef INITIALIZE_MOUSE
 static void aux_write_ack(int val)
 {
 	unsigned long flags;
@@ -1017,6 +1017,7 @@
 	__aux_write_ack(val);
 	spin_unlock_irqrestore(&kbd_controller_lock, flags);
 }
+#endif
 
 static unsigned char get_from_queue(void)
 {
@@ -1074,6 +1075,9 @@
 
 static int open_aux(struct inode * inode, struct file * file)
 {
+	unsigned long flags;
+	int cnt, status;
+
 	if (aux_count++) {
 		return 0;
 	}
@@ -1085,7 +1089,30 @@
 	kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE);	/* Enable the
 							   auxiliary port on
 							   controller. */
-	aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */
+
+	spin_lock_irqsave(&kbd_controller_lock, flags);
+	__aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */
+	for(cnt = 50; cnt > 0; --cnt) {
+		status = handle_kbd_event();
+		if (mouse_reply_expected == 0 ||
+		    (status & (KBD_STAT_GTO | KBD_STAT_PERR)))
+			break;
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		spin_unlock_irqrestore(&kbd_controller_lock, flags);
+		schedule_timeout(2);
+		spin_lock_irqsave(&kbd_controller_lock, flags);
+		set_current_state(TASK_RUNNING);
+	}
+	if (cnt == 0 || (status & (KBD_STAT_GTO | KBD_STAT_PERR))) {
+		--aux_count;
+		spin_unlock_irqrestore(&kbd_controller_lock, flags);
+		kbd_write_cmd(AUX_INTS_OFF);
+		kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE);
+		aux_free_irq(AUX_DEV);
+		return -ENXIO;
+	}
+	spin_unlock_irqrestore(&kbd_controller_lock, flags);
+
 	kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */
 	
 	mdelay(2);			/* Ensure we follow the kbc access delay rules.. */
@@ -1225,41 +1252,13 @@
 #endif /* CONFIG_PSMOUSE */
 
 
-static int blink_frequency = HZ/2;
+void pckbd_blink (char led) {
+		led = led ? (0x01 | 0x04) : 0x00;
 
-/* Tell the user who may be running in X and not see the console that we have 
-   panic'ed. This is to distingush panics from "real" lockups. 
-   Could in theory send the panic message as morse, but that is left as an
-   exercise for the reader.  */ 
-void panic_blink(void)
-{ 
-	static unsigned long last_jiffie;
-	static char led;
-	/* Roughly 1/2s frequency. KDB uses about 1s. Make sure it is 
-	   different. */
-	if (!blink_frequency) 
-		return;
-	if (jiffies - last_jiffie > blink_frequency) {
-		led ^= 0x01 | 0x04;
 		while (kbd_read_status() & KBD_STAT_IBF) mdelay(1); 
 		kbd_write_output(KBD_CMD_SET_LEDS);
 		mdelay(1); 
 		while (kbd_read_status() & KBD_STAT_IBF) mdelay(1); 
 		mdelay(1); 
 		kbd_write_output(led);
-		last_jiffie = jiffies;
-	}
-}  
-
-static int __init panicblink_setup(char *str)
-{
-    int par;
-    if (get_option(&str,&par)) 
-	    blink_frequency = par*(1000/HZ);
-    return 1;
 }
-
-/* panicblink=0 disables the blinking as it caused problems with some console
-   switches. otherwise argument is ms of a blink period. */
-__setup("panicblink=", panicblink_setup);
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/pcwd.c linux.20pre10-ac2/drivers/char/pcwd.c
--- linux.20pre10/drivers/char/pcwd.c	2002-10-09 21:36:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/pcwd.c	2002-09-29 20:29:59.000000000 +0100
@@ -88,6 +88,7 @@
 
 static int timeout_val;
 static int timeout = 2;
+static int expect_close = 0;
 
 MODULE_PARM (timeout, "i");
 MODULE_PARM_DESC (timeout, "Watchdog timeout in seconds (default=2)");
@@ -213,7 +214,7 @@
 	spin_unlock (&io_lock);
 
 	/* Transform the card register to the ioctl bits we use internally */
-	retval = 0;
+	retval = WDIOF_MAGICCLOSE;
 	if (status & WD_WDRST)
 		retval |= WDIOF_CARDRESET;
 	if (status & WD_T110)
@@ -385,6 +386,20 @@
 		return -ESPIPE;
 
 	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != len; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 1;
+			}
+		}
 		pcwd_info.card_info->wd_tickle ();
 		return 1;
 	}
@@ -450,7 +465,7 @@
 {
 	switch (MINOR (ino->i_rdev)) {
 	case WATCHDOG_MINOR:
-		if (!nowayout)
+		if (expect_close)
 			pcwd_info.card_info->enable_card (0);
 
 		atomic_inc (&pcwd_info.open_allowed);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/raw.c linux.20pre10-ac2/drivers/char/raw.c
--- linux.20pre10/drivers/char/raw.c	2002-10-09 21:36:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/raw.c	2002-08-06 15:42:07.000000000 +0100
@@ -23,6 +23,7 @@
 	struct block_device *binding;
 	int inuse, sector_size, sector_bits;
 	struct semaphore mutex;
+	int can_do_vary;
 } raw_device_data_t;
 
 static raw_device_data_t raw_devices[256];
@@ -119,6 +120,8 @@
 	if (raw_devices[minor].inuse++)
 		goto out;
 
+	raw_devices[minor].can_do_vary = 
+			get_blkdev_varyio(MAJOR(rdev), MINOR(rdev));
 	/* 
 	 * Don't interfere with mounted devices: we cannot safely set
 	 * the blocksize on a device which is already mounted.  
@@ -128,6 +131,7 @@
 	if (is_mounted(rdev)) {
 		if (blksize_size[MAJOR(rdev)])
 			sector_size = blksize_size[MAJOR(rdev)][MINOR(rdev)];
+		 raw_devices[minor].can_do_vary = 0;
 	} else {
 		if (hardsect_size[MAJOR(rdev)])
 			sector_size = hardsect_size[MAJOR(rdev)][MINOR(rdev)];
@@ -135,6 +139,7 @@
 
 	set_blocksize(rdev, sector_size);
 	raw_devices[minor].sector_size = sector_size;
+	filp->f_iobuf->dovary = raw_devices[minor].can_do_vary;
 
 	for (sector_bits = 0; !(sector_size & 1); )
 		sector_size>>=1, sector_bits++;
@@ -201,9 +206,10 @@
 
 		/* First, find out which raw minor we want */
 
-		err = copy_from_user(&rq, (void *) arg, sizeof(rq));
-		if (err)
+		if (copy_from_user(&rq, (void *) arg, sizeof(rq))) {
+			err = -EFAULT;
 			break;
+		}
 		
 		minor = rq.raw_minor;
 		if (minor <= 0 || minor > MINORMASK) {
@@ -260,6 +266,8 @@
 				rq.block_major = rq.block_minor = 0;
 			}
 			err = copy_to_user((void *) arg, &rq, sizeof(rq));
+			if (err)
+				err = -EFAULT;
 		}
 		break;
 		
@@ -322,6 +330,7 @@
 		if (err)
 			goto out;
 		new_iobuf = 1;
+		iobuf->dovary = raw_devices[minor].can_do_vary;
 	}
 
 	dev = to_kdev_t(raw_devices[minor].binding->bd_dev);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/sbc60xxwdt.c linux.20pre10-ac2/drivers/char/sbc60xxwdt.c
--- linux.20pre10/drivers/char/sbc60xxwdt.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/sbc60xxwdt.c	2002-09-29 20:29:59.000000000 +0100
@@ -234,7 +234,7 @@
 {
 	static struct watchdog_info ident=
 	{
-		0,
+		WDIOF_MAGICCLOSE,
 		1,
 		"SB60xx"
 	};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/sc1200wdt.c linux.20pre10-ac2/drivers/char/sc1200wdt.c
--- linux.20pre10/drivers/char/sc1200wdt.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/sc1200wdt.c	2002-09-29 20:29:59.000000000 +0100
@@ -22,6 +22,8 @@
  *		 <rob@osinvestor.com>	Return proper status instead of temperature warning
  *					Add WDIOC_GETBOOTSTATUS and WDIOC_SETOPTIONS ioctls
  *					Fix CONFIG_WATCHDOG_NOWAYOUT
+ *	20020530 Joel Becker		Add Matt Domsch's nowayout
+ *					module option
  */
 
 #include <linux/config.h>
@@ -86,6 +88,14 @@
 MODULE_PARM(timeout, "i");
 MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1");
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
 
 /* Read from Data Register */
@@ -161,7 +171,7 @@
 {
 	int new_timeout;
 	static struct watchdog_info ident = {
-		options:		WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
+		options:		WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
 		firmware_version:	0,
 		identity:		"PC87307/PC97307"
 	};
@@ -246,20 +256,20 @@
 		return -ESPIPE;
 	
 	if (len) {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-		size_t i;
+		if (!nowayout) {
+			size_t i;
 
-		expect_close = 0;
+			expect_close = 0;
 
-		for (i = 0; i != len; i++)
-		{
-			char c;
-			if(get_user(c, data+i))
-				return -EFAULT;
-			if (c == 'V')
-				expect_close = 42;
+			for (i = 0; i != len; i++)
+			{
+				char c;
+				if(get_user(c, data+i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 42;
+			}
 		}
-#endif
 		sc1200wdt_write_data(WDTO, timeout);
 		return len;
 	}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/sc520_wdt.c linux.20pre10-ac2/drivers/char/sc520_wdt.c
--- linux.20pre10/drivers/char/sc520_wdt.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/sc520_wdt.c	2002-09-29 20:29:59.000000000 +0100
@@ -110,6 +110,15 @@
 static unsigned long wdt_is_open;
 static int wdt_expect_close;
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 static spinlock_t wdt_spinlock;
 /*
  *	Whack the dog
@@ -172,12 +181,12 @@
 
 static void wdt_turnoff(void)
 {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-	/* Stop the timer */
-	del_timer(&timer);
-	wdt_config(0);
-	printk(OUR_NAME ": Watchdog timer is now disabled...\n");
-#endif
+	if (!nowayout) {
+		/* Stop the timer */
+		del_timer(&timer);
+		wdt_config(0);
+		printk(OUR_NAME ": Watchdog timer is now disabled...\n");
+	}
 }
 
 
@@ -226,9 +235,9 @@
 				return -EBUSY;
 			/* Good, fire up the show */
 			wdt_startup();
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
-			MOD_INC_USE_COUNT;
-#endif	
+			if (nowayout) {
+				MOD_INC_USE_COUNT;
+			}
 			return 0;
 		default:
 			return -ENODEV;
@@ -260,7 +269,7 @@
 {
 	static struct watchdog_info ident=
 	{
-		0,
+		WDIOF_MAGICCLOSE,
 		1,
 		"SC520"
 	};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/scx200_gpio.c linux.20pre10-ac2/drivers/char/scx200_gpio.c
--- linux.20pre10/drivers/char/scx200_gpio.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/scx200_gpio.c	2002-10-10 23:56:47.000000000 +0100
@@ -0,0 +1,154 @@
+/* linux/drivers/char/scx200_gpio.c 
+
+   National Semiconductor SCx200 GPIO driver.  Allows a user space
+   process to play with the GPIO pins.
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include <linux/scx200_gpio.h>
+
+#define NAME "scx200_gpio"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 GPIO Pin Driver");
+MODULE_LICENSE("GPL");
+
+static int major = 0;		/* default to dynamic major */
+MODULE_PARM(major, "i");
+MODULE_PARM_DESC(major, "Major device number");
+
+static ssize_t scx200_gpio_write(struct file *file, const char *data, 
+				 size_t len, loff_t *ppos)
+{
+	unsigned m = minor(file->f_dentry->d_inode->i_rdev);
+	size_t i;
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	for (i = 0; i < len; ++i) {
+		char c;
+		if (get_user(c, data+i))
+			return -EFAULT;
+		switch (c)
+		{
+		case '0': 
+			scx200_gpio_set(m, 0); 
+			break;
+		case '1': 
+			scx200_gpio_set(m, 1); 
+			break;
+		case 'O':
+			printk(KERN_INFO NAME ": GPIO%d output enabled\n", m);
+			scx200_gpio_configure(m, ~1, 1);
+			break;
+		case 'o':
+			printk(KERN_INFO NAME ": GPIO%d output disabled\n", m);
+			scx200_gpio_configure(m, ~1, 0);
+			break;
+		case 'T':
+			printk(KERN_INFO NAME ": GPIO%d output is push pull\n", m);
+			scx200_gpio_configure(m, ~2, 2);
+			break;
+		case 't':
+			printk(KERN_INFO NAME ": GPIO%d output is open drain\n", m);
+			scx200_gpio_configure(m, ~2, 0);
+			break;
+		case 'P':
+			printk(KERN_INFO NAME ": GPIO%d pull up enabled\n", m);
+			scx200_gpio_configure(m, ~4, 4);
+			break;
+		case 'p':
+			printk(KERN_INFO NAME ": GPIO%d pull up disabled\n", m);
+			scx200_gpio_configure(m, ~4, 0);
+			break;
+		}
+	}
+
+	return len;
+}
+
+static ssize_t scx200_gpio_read(struct file *file, char *buf,
+				size_t len, loff_t *ppos)
+{
+	unsigned m = minor(file->f_dentry->d_inode->i_rdev);
+	int value;
+
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	value = scx200_gpio_get(m);
+	if (put_user(value ? '1' : '0', buf))
+		return -EFAULT;
+	
+	return 1;
+}
+
+static int scx200_gpio_open(struct inode *inode, struct file *file)
+{
+	unsigned m = minor(inode->i_rdev);
+	if (m > 63)
+		return -EINVAL;
+	return 0;
+}
+
+static int scx200_gpio_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+
+static struct file_operations scx200_gpio_fops = {
+	.owner   = THIS_MODULE,
+	.write   = scx200_gpio_write,
+	.read    = scx200_gpio_read,
+	.open    = scx200_gpio_open,
+	.release = scx200_gpio_release,
+};
+
+static int __init scx200_gpio_init(void)
+{
+	int r;
+
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 GPIO Driver\n");
+
+	if (!scx200_gpio_present()) {
+		printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
+		return -ENODEV;
+	}
+
+	r = register_chrdev(major, NAME, &scx200_gpio_fops);
+	if (r < 0) {
+		printk(KERN_ERR NAME ": unable to register character device\n");
+		return r;
+	}
+	if (!major) {
+		major = r;
+		printk(KERN_DEBUG NAME ": got dynamic major %d\n", major);
+	}
+
+	return 0;
+}
+
+static void __exit scx200_gpio_cleanup(void)
+{
+	unregister_chrdev(major, NAME);
+}
+
+module_init(scx200_gpio_init);
+module_exit(scx200_gpio_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules"
+        c-basic-offset: 8
+    End:
+*/
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/scx200_wdt.c linux.20pre10-ac2/drivers/char/scx200_wdt.c
--- linux.20pre10/drivers/char/scx200_wdt.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/scx200_wdt.c	2002-10-10 23:56:47.000000000 +0100
@@ -0,0 +1,277 @@
+/* linux/drivers/char/scx200_wdt.c 
+
+   National Semiconductor SCx200 Watchdog support
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   Som code taken from:
+   National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver
+   (c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.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.
+
+   The author(s) of this software shall not be held liable for damages
+   of any nature resulting due to the use of this software. This
+   software is provided AS-IS with no warranties. */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include <linux/scx200.h>
+
+#define NAME "scx200_wdt"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 Watchdog Driver");
+MODULE_LICENSE("GPL");
+
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+#define CONFIG_WATCHDOG_NOWAYOUT 0
+#endif
+
+static int margin = 60;		/* in seconds */
+MODULE_PARM(margin, "i");
+MODULE_PARM_DESC(margin, "Watchdog margin in seconds");
+
+static int nowayout = CONFIG_WATCHDOG_NOWAYOUT;
+MODULE_PARM(nowayout, "i");
+MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
+
+static u16 wdto_restart;
+static struct semaphore open_semaphore;
+static unsigned expect_close;
+
+/* Bits of the WDCNFG register */
+#define W_ENABLE 0x00fa		/* Enable watchdog */
+#define W_DISABLE 0x0000	/* Disable watchdog */
+
+/* The scaling factor for the timer, this depends on the value of W_ENABLE */
+#define W_SCALE (32768/1024)
+
+static void scx200_wdt_ping(void)
+{
+	outw(wdto_restart, SCx200_CB_BASE + SCx200_WDT_WDTO);
+}
+
+static void scx200_wdt_update_margin(void)
+{
+	printk(KERN_INFO NAME ": timer margin %d seconds\n", margin);
+	wdto_restart = margin * W_SCALE;
+}
+
+static void scx200_wdt_enable(void)
+{
+	printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n", 
+	       wdto_restart);
+
+	outw(0, SCx200_CB_BASE + SCx200_WDT_WDTO);
+	outb(SCx200_WDT_WDSTS_WDOVF, SCx200_CB_BASE + SCx200_WDT_WDSTS);
+	outw(W_ENABLE, SCx200_CB_BASE + SCx200_WDT_WDCNFG);
+
+	scx200_wdt_ping();
+}
+
+static void scx200_wdt_disable(void)
+{
+	printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
+		
+	outw(0, SCx200_CB_BASE + SCx200_WDT_WDTO);
+	outb(SCx200_WDT_WDSTS_WDOVF, SCx200_CB_BASE + SCx200_WDT_WDSTS);
+	outw(W_DISABLE, SCx200_CB_BASE + SCx200_WDT_WDCNFG);
+}
+
+static int scx200_wdt_open(struct inode *inode, struct file *file)
+{
+        /* only allow one at a time */
+        if (down_trylock(&open_semaphore))
+                return -EBUSY;
+	scx200_wdt_enable();
+	expect_close = 0;
+
+	return 0;
+}
+
+static int scx200_wdt_release(struct inode *inode, struct file *file)
+{
+	if (!expect_close) {
+		printk(KERN_WARNING NAME ": watchdog device closed unexpectedly, will not disable the watchdog timer\n");
+	} else if (!nowayout) {
+		scx200_wdt_disable();
+	}
+        up(&open_semaphore);
+
+	return 0;
+}
+
+static int scx200_wdt_notify_sys(struct notifier_block *this, 
+				      unsigned long code, void *unused)
+{
+        if (code == SYS_HALT || code == SYS_POWER_OFF)
+		if (!nowayout)
+			scx200_wdt_disable();
+
+        return NOTIFY_DONE;
+}
+
+static struct notifier_block scx200_wdt_notifier =
+{
+        notifier_call: scx200_wdt_notify_sys
+};
+
+static ssize_t scx200_wdt_write(struct file *file, const char *data, 
+				     size_t len, loff_t *ppos)
+{
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	/* check for a magic close character */
+	if (len) 
+	{
+		size_t i;
+
+		scx200_wdt_ping();
+
+		expect_close = 0;
+		for (i = 0; i < len; ++i) {
+			char c;
+			if (get_user(c, data+i))
+				return -EFAULT;
+			if (c == 'V')
+				expect_close = 1;
+		}
+
+		return len;
+	}
+
+	return 0;
+}
+
+static int scx200_wdt_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	static struct watchdog_info ident = {
+		.identity = "NatSemi SCx200 Watchdog",
+		.firmware_version = 1, 
+		.options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING),
+	};
+	int new_margin;
+	
+	switch (cmd) {
+	default:
+		return -ENOTTY;
+	case WDIOC_GETSUPPORT:
+		if(copy_to_user((struct watchdog_info *)arg, &ident, 
+				sizeof(ident)))
+			return -EFAULT;
+		return 0;
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		if (put_user(0, (int *)arg))
+			return -EFAULT;
+		return 0;
+	case WDIOC_KEEPALIVE:
+		scx200_wdt_ping();
+		return 0;
+	case WDIOC_SETTIMEOUT:
+		if (get_user(new_margin, (int *)arg))
+			return -EFAULT;
+		if (new_margin < 1)
+			return -EINVAL;
+		margin = new_margin;
+		scx200_wdt_update_margin();
+		scx200_wdt_ping();
+	case WDIOC_GETTIMEOUT:
+		if (put_user(margin, (int *)arg))
+			return -EFAULT;
+		return 0;
+	}
+}
+
+static struct file_operations scx200_wdt_fops = {
+	.owner	 = THIS_MODULE,
+	.write   = scx200_wdt_write,
+	.ioctl   = scx200_wdt_ioctl,
+	.open    = scx200_wdt_open,
+	.release = scx200_wdt_release,
+};
+
+static struct miscdevice scx200_wdt_miscdev = {
+	.minor = WATCHDOG_MINOR,
+	.name  = NAME,
+	.fops  = &scx200_wdt_fops,
+};
+
+static int __init scx200_wdt_init(void)
+{
+	int r;
+
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 Watchdog Driver\n");
+
+	/* First check that this really is a NatSemi SCx200 CPU */
+	if ((pci_find_device(PCI_VENDOR_ID_NS, 
+			     PCI_DEVICE_ID_NS_SCx200_BRIDGE,
+			     NULL)) == NULL)
+		return -ENODEV;
+
+	/* More sanity checks, verify that the configuration block is there */
+	if (!scx200_cb_probe(SCx200_CB_BASE)) {
+		printk(KERN_WARNING NAME ": no configuration block found\n");
+		return -ENODEV;
+	}
+
+	if (!request_region(SCx200_CB_BASE + SCx200_WDT_OFFSET, 
+			    SCx200_WDT_SIZE, 
+			    "NatSemi SCx200 Watchdog")) {
+		printk(KERN_WARNING NAME ": watchdog I/O region busy\n");
+		return -EBUSY;
+	}
+
+	scx200_wdt_update_margin();
+	scx200_wdt_disable();
+
+	sema_init(&open_semaphore, 1);
+
+	r = misc_register(&scx200_wdt_miscdev);
+	if (r)
+		return r;
+
+	r = register_reboot_notifier(&scx200_wdt_notifier);
+        if (r) {
+                printk(KERN_ERR NAME ": unable to register reboot notifier");
+		misc_deregister(&scx200_wdt_miscdev);
+                return r;
+        }
+
+	return 0;
+}
+
+static void __exit scx200_wdt_cleanup(void)
+{
+        unregister_reboot_notifier(&scx200_wdt_notifier);
+	misc_deregister(&scx200_wdt_miscdev);
+	release_region(SCx200_CB_BASE + SCx200_WDT_OFFSET,
+		       SCx200_WDT_SIZE);
+}
+
+module_init(scx200_wdt_init);
+module_exit(scx200_wdt_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules"
+        c-basic-offset: 8
+    End:
+*/
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/serial.c linux.20pre10-ac2/drivers/char/serial.c
--- linux.20pre10/drivers/char/serial.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/serial.c	2002-09-12 13:55:41.000000000 +0100
@@ -62,6 +62,10 @@
  *        Robert Schwebel <robert@schwebel.de>,
  *        Juergen Beisert <jbeisert@eurodsn.de>,
  *        Theodore Ts'o <tytso@mit.edu>
+ *  4/02: added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUTS
+ *        to waiting processes
+ *        Sapan Bhatia <sapan@corewars.org>
+ *
  */
 
 static char *serial_version = "5.05c";
@@ -203,6 +207,7 @@
 #include <linux/ioport.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/spinlock.h>
 #if (LINUX_VERSION_CODE >= 131343)
 #include <linux/init.h>
 #endif
@@ -1213,7 +1218,7 @@
 	if (!page)
 		return -ENOMEM;
 
-	save_flags(flags); cli();
+	spin_lock_irqsave( &info->irq_spinlock, flags);
 
 	if (info->flags & ASYNC_INITIALIZED) {
 		free_page(page);
@@ -1451,11 +1456,11 @@
 	change_speed(info, 0);
 
 	info->flags |= ASYNC_INITIALIZED;
-	restore_flags(flags);
+	spin_unlock_irqrestore( &info->irq_spinlock, flags);
 	return 0;
 	
 errout:
-	restore_flags(flags);
+	spin_unlock_irqrestore( &info->irq_spinlock, flags);
 	return retval;
 }
 
@@ -1479,7 +1484,7 @@
 	       state->irq);
 #endif
 	
-	save_flags(flags); cli(); /* Disable interrupts */
+	spin_lock_irqsave( &info->irq_spinlock, flags);
 
 	/*
 	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
@@ -1487,41 +1492,6 @@
 	 */
 	wake_up_interruptible(&info->delta_msr_wait);
 	
-	/*
-	 * First unlink the serial port from the IRQ chain...
-	 */
-	if (info->next_port)
-		info->next_port->prev_port = info->prev_port;
-	if (info->prev_port)
-		info->prev_port->next_port = info->next_port;
-	else
-		IRQ_ports[state->irq] = info->next_port;
-	figure_IRQ_timeout(state->irq);
-	
-	/*
-	 * Free the IRQ, if necessary
-	 */
-	if (state->irq && (!IRQ_ports[state->irq] ||
-			  !IRQ_ports[state->irq]->next_port)) {
-		if (IRQ_ports[state->irq]) {
-			free_irq(state->irq, &IRQ_ports[state->irq]);
-			retval = request_irq(state->irq, rs_interrupt_single,
-					     SA_SHIRQ, "serial",
-					     &IRQ_ports[state->irq]);
-			
-			if (retval)
-				printk("serial shutdown: request_irq: error %d"
-				       "  Couldn't reacquire IRQ.\n", retval);
-		} else
-			free_irq(state->irq, &IRQ_ports[state->irq]);
-	}
-
-	if (info->xmit.buf) {
-		unsigned long pg = (unsigned long) info->xmit.buf;
-		info->xmit.buf = 0;
-		free_page(pg);
-	}
-
 	info->IER = 0;
 	serial_outp(info, UART_IER, 0x00);	/* disable all intrs */
 #ifdef CONFIG_SERIAL_MANY_PORTS
@@ -1578,7 +1548,43 @@
 		serial_outp(info, UART_IER, UART_IERX_SLEEP);
 	}
 	info->flags &= ~ASYNC_INITIALIZED;
-	restore_flags(flags);
+
+	/*
+	 * First unlink the serial port from the IRQ chain...
+	 */
+	if (info->next_port)
+		info->next_port->prev_port = info->prev_port;
+	if (info->prev_port)
+		info->prev_port->next_port = info->next_port;
+	else
+		IRQ_ports[state->irq] = info->next_port;
+	figure_IRQ_timeout(state->irq);
+	
+	/*
+	 * Free the IRQ, if necessary
+	 */
+	if (state->irq && (!IRQ_ports[state->irq] ||
+			  !IRQ_ports[state->irq]->next_port)) {
+		if (IRQ_ports[state->irq]) {
+			free_irq(state->irq, &IRQ_ports[state->irq]);
+			retval = request_irq(state->irq, rs_interrupt_single,
+					     SA_SHIRQ, "serial",
+					     &IRQ_ports[state->irq]);
+			
+			if (retval)
+				printk("serial shutdown: request_irq: error %d"
+				       "  Couldn't reacquire IRQ.\n", retval);
+		} else
+			free_irq(state->irq, &IRQ_ports[state->irq]);
+	}
+
+	if (info->xmit.buf) {
+		unsigned long pg = (unsigned long) info->xmit.buf;
+		info->xmit.buf = 0;
+		free_page(pg);
+	}
+
+	spin_unlock_irqrestore( &info->irq_spinlock, flags);
 }
 
 #if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
@@ -3123,6 +3129,7 @@
 	info->tqueue.routine = do_softint;
 	info->tqueue.data = info;
 	info->state = sstate;
+	spin_lock_init(&info->irq_spinlock);
 	if (sstate->info) {
 		kfree(info);
 		*ret_info = sstate->info;
@@ -3237,6 +3244,7 @@
 #ifdef SERIAL_DEBUG_OPEN
 	printk("rs_open ttys%d successful...", info->line);
 #endif
+	set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 	return 0;
 }
 
@@ -3650,6 +3658,7 @@
 	info->io_type = state->io_type;
 	info->iomem_base = state->iomem_base;
 	info->iomem_reg_shift = state->iomem_reg_shift;
+	info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED;
 
 	save_flags(flags); cli();
 	
@@ -3902,7 +3911,14 @@
 			case 6: /* BAR 4*/
 			case 7: base_idx=idx-2; /* BAR 5*/
 		}
-
+ 
+	/* AFAVLAB uses a different mixture of BARs and offsets */
+	/* Not that ugly ;) -- HW */ 
+	if (dev->vendor == PCI_VENDOR_ID_AFAVLAB && idx >= 4) {
+		base_idx = 4;
+		offset = (idx - 4) * 8;
+	}
+ 
 	/* Some Titan cards are also a little weird */
 	if (dev->vendor == PCI_VENDOR_ID_TITAN &&
 	    (dev->device == PCI_DEVICE_ID_TITAN_400L ||
@@ -4306,9 +4322,11 @@
 
 	pbn_b0_bt_1_115200,
 	pbn_b0_bt_2_115200,
+	pbn_b0_bt_8_115200,
 	pbn_b0_bt_1_460800,
 	pbn_b0_bt_2_460800,
 	pbn_b0_bt_2_921600,
+	pbn_b0_bt_4_460800,
 
 	pbn_b1_1_115200,
 	pbn_b1_2_115200,
@@ -4387,9 +4405,11 @@
 
 	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b0_bt_1_115200 */
 	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */
+	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 8, 115200 }, /* pbn_b0_bt_8_115200 */
 	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */
 	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */
 	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b0_bt_2_921600 */
+	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 460800 }, /* pbn_b0_bt_4_460800 */
 
 	{ SPCI_FL_BASE1, 1, 115200 },		/* pbn_b1_1_115200 */
 	{ SPCI_FL_BASE1, 2, 115200 },		/* pbn_b1_2_115200 */
@@ -4854,6 +4874,12 @@
 	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 		pbn_b0_bt_2_460800 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_A,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_4_460800 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_OCTO_B,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_4_460800 },
 	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 		pbn_b0_bt_1_115200 },
@@ -4866,6 +4892,11 @@
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 		pbn_b2_bt_2_115200 },
 
+	/* AFAVLAB serial card, from Harald Welte <laforge@gnumonks.org> */
+	{	PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_b0_bt_8_115200 },
+		
 	/* EKF addition for i960 Boards form EKF with serial port */
 	{	PCI_VENDOR_ID_INTEL, 0x1960,
 		0xE4BF, PCI_ANY_ID, 0, 0,
@@ -4885,6 +4916,7 @@
 		0x1048, 0x1500, 0, 0,
 		pbn_b1_1_115200 },
 
+	/* SGI IOC3 board */
 	{	PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
 		0xFF00, 0, 0, 0,
 		pbn_sgi_ioc3 },
@@ -5537,12 +5569,22 @@
 		tty_register_devfs(&callout_driver, 0,
 				   callout_driver.minor_start + state->line);
 	}
+#ifdef CONFIG_SERIAL_GSC
+	probe_serial_gsc();
+#endif
+#ifdef CONFIG_SUPERIO
+	superio_serial_init();
+#endif
 #ifdef ENABLE_SERIAL_PCI
 	probe_serial_pci();
 #endif
 #ifdef ENABLE_SERIAL_PNP
        probe_serial_pnp();
 #endif
+	// FIXME: Clean this one up
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_PARISC)
+	serial_console_init();
+#endif
 	return 0;
 }
 
@@ -5652,6 +5694,7 @@
 		info->io_type = req->io_type;
 		info->iomem_base = req->iomem_base;
 		info->iomem_reg_shift = req->iomem_reg_shift;
+		info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED;
 	}
 	autoconfig(state);
 	if (state->type == PORT_UNKNOWN) {
@@ -5959,6 +6002,7 @@
 	info->io_type = state->io_type;
 	info->iomem_base = state->iomem_base;
 	info->iomem_reg_shift = state->iomem_reg_shift;
+	info->irq_spinlock= (spinlock_t) SPIN_LOCK_UNLOCKED;
 	quot = state->baud_base / baud;
 	cval = cflag & (CSIZE | CSTOPB);
 #if defined(__powerpc__) || defined(__alpha__)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/shwdt.c linux.20pre10-ac2/drivers/char/shwdt.c
--- linux.20pre10/drivers/char/shwdt.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/shwdt.c	2002-09-29 20:29:59.000000000 +0100
@@ -347,7 +347,7 @@
 };
 
 static struct watchdog_info sh_wdt_info = {
-	options:		WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
+	options:		WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
 	firmware_version:	0,
 	identity:		"SH WDT",
 };
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/softdog.c linux.20pre10-ac2/drivers/char/softdog.c
--- linux.20pre10/drivers/char/softdog.c	2002-10-09 21:36:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/softdog.c	2002-09-29 20:29:59.000000000 +0100
@@ -31,6 +31,9 @@
  *	Added soft_noboot; Allows testing the softdog trigger without 
  *	requiring a recompile.
  *	Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT.
+ *
+ *  20020530 Joel Becker <joel.becker@oracle.com>
+ *  	Added Matt Domsch's nowayout module option.
  */
  
 #include <linux/module.h>
@@ -48,6 +51,7 @@
 
 #define TIMER_MARGIN	60		/* (secs) Default is 1 minute */
 
+static int expect_close = 0;
 static int soft_margin = TIMER_MARGIN;	/* in seconds */
 #ifdef ONLY_TESTING
 static int soft_noboot = 1;
@@ -59,6 +63,15 @@
 MODULE_PARM(soft_noboot,"i");
 MODULE_LICENSE("GPL");
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 /*
  *	Our timer
  */
@@ -95,9 +108,9 @@
 {
 	if(test_and_set_bit(0, &timer_alive))
 		return -EBUSY;
-#ifdef CONFIG_WATCHDOG_NOWAYOUT	 
-	MOD_INC_USE_COUNT;
-#endif	
+	if (nowayout) {
+		MOD_INC_USE_COUNT;
+	}
 	/*
 	 *	Activate timer
 	 */
@@ -109,11 +122,13 @@
 {
 	/*
 	 *	Shut off the timer.
-	 * 	Lock it in if it's a module and we defined ...NOWAYOUT
+	 * 	Lock it in if it's a module and we set nowayout
 	 */
-#ifndef CONFIG_WATCHDOG_NOWAYOUT	 
-	del_timer(&watchdog_ticktock);
-#endif	
+	if (expect_close) {
+		del_timer(&watchdog_ticktock);
+	} else {
+		printk(KERN_CRIT "SOFTDOG: WDT device closed unexpectedly.  WDT will not stop!\n");
+	}
 	clear_bit(0, &timer_alive);
 	return 0;
 }
@@ -128,6 +143,20 @@
 	 *	Refresh the timer.
 	 */
 	if(len) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != len; i++) {
+				char c;
+				if (get_user(c, data + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 1;
+			}
+		}
 		mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
 		return 1;
 	}
@@ -139,7 +168,7 @@
 {
 	int new_margin;
 	static struct watchdog_info ident = {
-		WDIOF_SETTIMEOUT,
+		WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
 		0,
 		"Software Watchdog"
 	};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/w83877f_wdt.c linux.20pre10-ac2/drivers/char/w83877f_wdt.c
--- linux.20pre10/drivers/char/w83877f_wdt.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/w83877f_wdt.c	2002-09-29 20:29:59.000000000 +0100
@@ -251,7 +251,7 @@
 {
 	static struct watchdog_info ident=
 	{
-		0,
+		WDIOF_MAGICCLOSE,
 		1,
 		"W83877F"
 	};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/wafer5823wdt.c linux.20pre10-ac2/drivers/char/wafer5823wdt.c
--- linux.20pre10/drivers/char/wafer5823wdt.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/wafer5823wdt.c	2002-09-29 20:29:59.000000000 +0100
@@ -40,6 +40,7 @@
 
 static unsigned long wafwdt_is_open;
 static spinlock_t wafwdt_lock;
+static int expect_close = 0;
 
 /*
  *	You must set these - there is no sane way to probe for this board.
@@ -56,6 +57,15 @@
 #define WD_TIMO 60		/* 1 minute */
 static int wd_margin = WD_TIMO;
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 static void wafwdt_ping(void)
 {
 	/* pat watchdog */
@@ -86,6 +96,20 @@
 		return -ESPIPE;
 
 	if (count) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 1;
+			}
+		}
 		wafwdt_ping();
 		return 1;
 	}
@@ -97,7 +121,9 @@
 {
 	int new_margin;
 	static struct watchdog_info ident = {
-		WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
+		WDIOF_KEEPALIVEPING |
+		WDIOF_SETTIMEOUT |
+		WDIOF_MAGICCLOSE,
 		1, "Wafer 5823 WDT"
 	};
 	int one=1;
@@ -148,9 +174,11 @@
 wafwdt_close(struct inode *inode, struct file *file)
 {
 	clear_bit(0, &wafwdt_is_open);
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-        wafwdt_stop();
-#endif
+	if (expect_close) {
+        	wafwdt_stop();
+	} else {
+		printk(KERN_CRIT "WDT device closed unexpectedly.  WDT will not stop!\n");
+	}
 	return 0;
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/wdt977.c linux.20pre10-ac2/drivers/char/wdt977.c
--- linux.20pre10/drivers/char/wdt977.c	2002-10-09 21:36:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/wdt977.c	2002-09-29 20:29:59.000000000 +0100
@@ -1,5 +1,5 @@
 /*
- *	Wdt977	0.01:	A Watchdog Device for Netwinder W83977AF chip
+ *	Wdt977	0.02:	A Watchdog Device for Netwinder W83977AF chip
  *
  *	(c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>)
  *
@@ -11,6 +11,8 @@
  *	2 of the License, or (at your option) any later version.
  *
  *			-----------------------
+ *      14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
+ *           Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
  */
  
 #include <linux/module.h>
@@ -31,6 +33,17 @@
 static	int timeout = 3;
 static	int timer_alive;
 static	int testmode;
+static	int expect_close = 0;
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 
 /*
  *	Allow only one person to hold it open
@@ -40,9 +53,9 @@
 {
 	if(timer_alive)
 		return -EBUSY;
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
-	MOD_INC_USE_COUNT;
-#endif
+	if (nowayout) {
+		MOD_INC_USE_COUNT;
+	}
 	timer_alive++;
 
 	//max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog.
@@ -89,50 +102,66 @@
 {
 	/*
 	 *	Shut off the timer.
-	 * 	Lock it in if it's a module and we defined ...NOWAYOUT
+	 * 	Lock it in if it's a module and we set nowayout
 	 */
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
 	lock_kernel();
+	if (expect_close) {
 
-	// unlock the SuperIO chip
-	outb(0x87,0x370); 
-	outb(0x87,0x370); 
-	
-	//select device Aux2 (device=8) and set watchdog regs F2,F3 and F4
-	//F3 is reset to its default state
-	//F4 can clear the TIMEOUT'ed state (bit 0) - back to default
-	//We can not use GP17 as a PowerLed, as we use its usage as a RedLed
+		// unlock the SuperIO chip
+		outb(0x87,0x370); 
+		outb(0x87,0x370); 
+	
+		//select device Aux2 (device=8) and set watchdog regs F2,F3 and F4
+		//F3 is reset to its default state
+		//F4 can clear the TIMEOUT'ed state (bit 0) - back to default
+		//We can not use GP17 as a PowerLed, as we use its usage as a RedLed
 	
-	outb(0x07,0x370);
-	outb(0x08,0x371);
-	outb(0xF2,0x370);
-	outb(0xFF,0x371);
-	outb(0xF3,0x370);
-	outb(0x00,0x371);
-	outb(0xF4,0x370);
-	outb(0x00,0x371);
-	outb(0xF2,0x370);
-	outb(0x00,0x371);
+		outb(0x07,0x370);
+		outb(0x08,0x371);
+		outb(0xF2,0x370);
+		outb(0xFF,0x371);
+		outb(0xF3,0x370);
+		outb(0x00,0x371);
+		outb(0xF4,0x370);
+		outb(0x00,0x371);
+		outb(0xF2,0x370);
+		outb(0x00,0x371);
 	
-	//at last select device Aux1 (dev=7) and set GP16 as a watchdog output
-	outb(0x07,0x370);
-	outb(0x07,0x371);
-	outb(0xE6,0x370);
-	outb(0x08,0x371);
+		//at last select device Aux1 (dev=7) and set GP16 as a watchdog output
+		outb(0x07,0x370);
+		outb(0x07,0x371);
+		outb(0xE6,0x370);
+		outb(0x08,0x371);
 	
-	// lock the SuperIO chip
-	outb(0xAA,0x370);
+		// lock the SuperIO chip
+		outb(0xAA,0x370);
+		printk(KERN_INFO "Watchdog: shutdown.\n");
+	} else {
+		printk(KERN_CRIT "WDT device closed unexpectedly.  WDT will not stop!\n");
+	}
 
 	timer_alive=0;
 	unlock_kernel();
 
-	printk(KERN_INFO "Watchdog: shutdown.\n");
-#endif
 	return 0;
 }
 
 static ssize_t wdt977_write(struct file *file, const char *data, size_t len, loff_t *ppos)
 {
+	if (!nowayout) {
+		size_t i;
+
+		/* In case it was set long ago */
+		expect_close = 0;
+
+		for (i = 0; i != len; i++) {
+			char c;
+			if (get_user(c, data + i))
+				return -EFAULT;
+			if (c == 'V')
+				expect_close = 1;
+		}
+	}
 
 	//max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog.
 	if (timeout>255)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/wdt.c linux.20pre10-ac2/drivers/char/wdt.c
--- linux.20pre10/drivers/char/wdt.c	2002-10-09 21:36:46.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/wdt.c	2002-09-29 20:29:59.000000000 +0100
@@ -28,6 +28,7 @@
  *					Parameterized timeout
  *		Tigran Aivazian	:	Restructured wdt_init() to handle failures
  *		Joel Becker	:	Added WDIOC_GET/SETTIMEOUT
+ *		Matt Domsch	:	Added nowayout module option
  */
 
 #include <linux/config.h>
@@ -52,6 +53,7 @@
 #include <linux/init.h>
 
 static unsigned long wdt_is_open;
+static int expect_close;
 
 /*
  *	You must set these - there is no sane way to probe for this board.
@@ -66,6 +68,15 @@
 
 static int wd_margin = WD_TIMO;
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 #ifndef MODULE
 
 /**
@@ -243,6 +254,20 @@
 
 	if(count)
 	{
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 1;
+			}
+		}
 		wdt_ping();
 		return 1;
 	}
@@ -304,7 +329,7 @@
 	{
 		WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER
 			|WDIOF_EXTERN1|WDIOF_EXTERN2|WDIOF_FANFAULT
-			|WDIOF_SETTIMEOUT,
+			|WDIOF_SETTIMEOUT|WDIOF_MAGICCLOSE,
 		1,
 		"WDT500/501"
 	};
@@ -394,10 +419,12 @@
 {
 	if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
 	{
-#ifndef CONFIG_WATCHDOG_NOWAYOUT	
-		inb_p(WDT_DC);		/* Disable counters */
-		wdt_ctr_load(2,0);	/* 0 length reset pulses now */
-#endif		
+		if (expect_close) {
+			inb_p(WDT_DC);		/* Disable counters */
+			wdt_ctr_load(2,0);	/* 0 length reset pulses now */
+		} else {
+			printk(KERN_CRIT "wdt: WDT device closed unexpectedly.  WDT will not stop!\n");
+		}
 		clear_bit(0, &wdt_is_open);
 	}
 	return 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/char/wdt_pci.c linux.20pre10-ac2/drivers/char/wdt_pci.c
--- linux.20pre10/drivers/char/wdt_pci.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/char/wdt_pci.c	2002-09-29 20:29:59.000000000 +0100
@@ -32,6 +32,7 @@
  *		Tigran Aivazian	:	Restructured wdtpci_init_one() to handle failures
  *		Joel Becker	:	Added WDIOC_GET/SETTIMEOUT
  *		Zwane Mwaikambo :	Magic char closing, locking changes, cleanups
+ *		Matt Domsch	:	nowayout module option
  */
 
 #include <linux/config.h>
@@ -87,6 +88,15 @@
 
 static int wd_margin = WD_TIMO;
 
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+MODULE_PARM(nowayout,"i");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
 /*
  *	Programming support
  */
@@ -231,19 +241,19 @@
 		return -ESPIPE;
 
 	if (count) {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-		size_t i;
+		if (!nowayout) {
+			size_t i;
 
-		expect_close = 0;
+			expect_close = 0;
 
-		for (i = 0; i != count; i++) {
-			char c;
-			if(get_user(c, buf+i))
-				return -EFAULT;
-			if (c == 'V')
-				expect_close = 1;
+			for (i = 0; i != count; i++) {
+				char c;
+				if(get_user(c, buf+i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 1;
+			}
 		}
-#endif
 		wdtpci_ping();
 	}
 
@@ -304,7 +314,7 @@
 	{
 		WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER
 			|WDIOF_EXTERN1|WDIOF_EXTERN2|WDIOF_FANFAULT
-			|WDIOF_SETTIMEOUT,
+			|WDIOF_SETTIMEOUT|WDIOF_MAGICCLOSE,
 		1,
 		"WDT500/501PCI"
 	};
@@ -358,12 +368,12 @@
 	switch(MINOR(inode->i_rdev))
 	{
 		case WATCHDOG_MINOR:
-			 if (down_trylock(&open_sem))
-                        	return -EBUSY;
+			if (down_trylock(&open_sem))
+				return -EBUSY;
 
-#ifdef CONFIG_WATCHDOG_NOWAYOUT	
-			MOD_INC_USE_COUNT;
-#endif
+			if (nowayout) {
+				MOD_INC_USE_COUNT;
+			}
 			/*
 			 *	Activate 
 			 */
@@ -418,7 +428,6 @@
 {
 
 	if (MINOR(inode->i_rdev)==WATCHDOG_MINOR) {
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
 		unsigned long flags;
 		if (expect_close) {
 			spin_lock_irqsave(&wdtpci_lock, flags);
@@ -429,7 +438,6 @@
 			printk(KERN_CRIT PFX "Unexpected close, not stopping timer!");
 			wdtpci_ping();
 		}
-#endif		
 		up(&open_sem);
 	}
 	return 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/hotplug/Config.in linux.20pre10-ac2/drivers/hotplug/Config.in
--- linux.20pre10/drivers/hotplug/Config.in	2002-10-09 21:36:57.000000000 +0100
+++ linux.20pre10-ac2/drivers/hotplug/Config.in	2002-08-18 23:30:48.000000000 +0100
@@ -6,11 +6,11 @@
 
 dep_tristate 'Support for PCI Hotplug (EXPERIMENTAL)' CONFIG_HOTPLUG_PCI $CONFIG_EXPERIMENTAL $CONFIG_PCI
 
+dep_tristate '  ACPI PCI Hotplug driver' CONFIG_HOTPLUG_PCI_ACPI $CONFIG_ACPI $CONFIG_HOTPLUG_PCI
 dep_tristate '  Compaq PCI Hotplug driver' CONFIG_HOTPLUG_PCI_COMPAQ $CONFIG_HOTPLUG_PCI $CONFIG_X86
 dep_mbool '    Save configuration into NVRAM on Compaq servers' CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM $CONFIG_HOTPLUG_PCI_COMPAQ
 if [ "$CONFIG_X86_IO_APIC" = "y" ]; then
    dep_tristate '  IBM PCI Hotplug driver' CONFIG_HOTPLUG_PCI_IBM $CONFIG_HOTPLUG_PCI $CONFIG_X86_IO_APIC $CONFIG_X86
 fi
-dep_tristate '  ACPI PCI Hotplug driver' CONFIG_HOTPLUG_PCI_ACPI $CONFIG_ACPI $CONFIG_HOTPLUG_PCI
-
+dep_tristate '  IBM Thinkpad (20H2999) Docking driver (VERY EXPERIMENTAL) ' CONFIG_HOTPLUG_PCI_H2999 $CONFIG_HOTPLUG_PCI $CONFIG_X86
 endmenu
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/hotplug/Makefile linux.20pre10-ac2/drivers/hotplug/Makefile
--- linux.20pre10/drivers/hotplug/Makefile	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/hotplug/Makefile	2002-08-18 15:41:12.000000000 +0100
@@ -12,6 +12,7 @@
 obj-$(CONFIG_HOTPLUG_PCI_COMPAQ)	+= cpqphp.o
 obj-$(CONFIG_HOTPLUG_PCI_IBM)		+= ibmphp.o
 obj-$(CONFIG_HOTPLUG_PCI_ACPI)		+= acpiphp.o
+obj-$(CONFIG_HOTPLUG_PCI_H2999)		+= tp600.o
 
 pci_hotplug-objs	:=	pci_hotplug_core.o	\
 				pci_hotplug_util.o
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/hotplug/pci_hotplug_core.c linux.20pre10-ac2/drivers/hotplug/pci_hotplug_core.c
--- linux.20pre10/drivers/hotplug/pci_hotplug_core.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/hotplug/pci_hotplug_core.c	2002-09-29 19:55:11.000000000 +0100
@@ -581,7 +581,7 @@
 
 	if (*offset < 0)
 		return -EINVAL;
-	if (count <= 0)
+	if (count == 0 || count > 16384)
 		return 0;
 	if (*offset != 0)
 		return 0;
@@ -692,7 +692,7 @@
 
 	if (*offset < 0)
 		return -EINVAL;
-	if (count <= 0)
+	if (count == 0 || count > 16384)
 		return 0;
 	if (*offset != 0)
 		return 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/hotplug/tp600.c linux.20pre10-ac2/drivers/hotplug/tp600.c
--- linux.20pre10/drivers/hotplug/tp600.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/hotplug/tp600.c	2002-09-13 00:45:51.000000000 +0100
@@ -0,0 +1,500 @@
+/*
+ *	Drivers for the IBM 20H2999 found in the IBM thinkpad series
+ *	machines. 
+ *
+ *	This driver was done without documentation from IBM 
+ *
+ *              _
+ *             { }
+ *	       | |		All reverse engineering done 
+ *	       | |		in accordance with 92/250/EEC
+ *	    .-.! !.-.		and Copyright (Computer Programs)
+ *	  .-!  ! !  !.-.	Regulations 1992 (S.I. 1992 No. 3233)
+ *	  ! !       !  ;
+ *         \	      ;	
+ *	   \	     ;	
+ *	    !       :
+ *	    !       |
+ *	    |       |
+ *
+ *
+ *	Various other IBM's tried to obtain docs but failed. For that
+ *	reason we only support warm not hot undocking at the moment.
+ *
+ *	Known bugs:
+ *		Sometimes we hang with an IRQ storm. I don't know what
+ *			deals with the IRQ disables yet. (Hot dock)
+ *		Sometimes busmastering (and maybe IRQs) don't come back
+ *		(Seems to be a buffering issue for hot dock)
+ *
+ *	Yet to do:
+ *		ISA is not yet handled (oh god help us)
+ *		Instead of saving/restoring pci devices we should
+ *			re-enumerate that subtree so you can change devices
+ *			(That also deals with stale save problems)
+ *		We need to do a proper warm save/restore interface
+ *		Bridged cards don't yet work
+ *
+ *	Usage:
+ *		Load module
+ *		Pray
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/smp_lock.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+
+#include "pci_hotplug.h"
+#include "tp600.h"
+
+static struct h2999_dev *testdev;
+
+/**
+ *	pci_save_slot	-	save slot PCI data
+ *	@slot: slot to save
+ *
+ *	Save the slot data from a PCI device
+ */
+ 
+static void pci_save_slot(struct h2999_slot *s)
+{
+	int i, n;
+	
+	for(i=0;i<8;i++)
+	{
+		struct pci_dev *p = pci_find_slot(s->dev->hotplug_bus, PCI_DEVFN(s->slotid, i));
+		s->pci[i] = p;
+		if(p)
+		{
+			for(n = 0; n < 64; n++)
+				pci_read_config_dword(p, n * 4, &s->save[i][n]);
+//			printk("Saved %02X:%02X.%X\n",
+//				s->dev->hotplug_bus, s->slotid, i);
+		}
+	}
+}
+
+static void pci_restore_slot(struct h2999_slot *s)
+{
+	int i,n;
+
+	for(i = 0 ; i < 8; i++)
+	{
+		if(s->pci[i])
+		{
+			pci_set_power_state(s->pci[i], 0);
+
+			for(n = 0; n < 54; n++)
+				if(n!=1)
+					pci_write_config_dword(s->pci[i], n * 4, s->save[i][n]);
+			pci_write_config_dword(s->pci[i], 4, s->save[i][1]);
+//			printk("Restored %02X:%02X.%X\n",
+//				s->dev->hotplug_bus, s->slotid, i);
+		}
+	}
+}
+		
+/**
+ *	slot_enable	-	enable H2999 slot
+ *	@slot: slot to enable
+ *
+ *	Enable a slot. Its not actually clear what this means with
+ *	a hot dock. We can certainly 'discover' the PCI device in the
+ *	slot when asked.
+ */
+ 
+static int slot_enable(struct hotplug_slot *slot)
+{
+	struct h2999_slot *s = slot->private;
+	int i;
+	pci_restore_slot(s);
+	for(i=0; i < 8; i++)
+	{
+		if(s->pci[i] && (s->drivermap&(1<<i)))
+			pci_announce_device_to_drivers(s->pci[i]);
+	}
+	return 0;
+}
+
+/**
+ *	slot_disable	-	disable H2999 slot
+ *	@slot: slot to disable
+ *
+ *	Disable a slot. Its not actually clear what to do here. We could
+ *	report the device as having been removed when we are told to do
+ *	this.
+ */
+ 
+static int slot_disable(struct hotplug_slot *slot)
+{
+	struct h2999_slot *s = slot->private;
+	struct pci_dev *pdev;
+	int i;
+
+	for(i = 0; i < 8; i++)
+	{
+		pdev = s->pci[i];
+		/* Hack for now */
+		if (pdev && pdev->driver) {
+			if (!pdev->driver->remove)
+				return -EBUSY;
+		}
+	}
+	
+	s->drivermap = 0;
+		
+	for(i = 0; i < 8; i++)
+	{
+		pdev = s->pci[i];
+		if(pdev)
+		{
+			if(pdev->driver)
+			{
+				s->drivermap|=(1<<i);
+				pdev->driver->remove(pdev);
+				pdev->driver = NULL;
+			}
+		}
+	}
+	return 0;
+}
+
+/**
+ *	set_attention_status	-	set attention callback
+ *	@slot: slot to set
+ *	@value: on/off
+ *
+ *	Called when the hotplug layer wants to set the attention status of
+ *	the hotplug slot. The H2999 doesn't have an attention control (at
+ *	least not that we know of). So we ignore this.
+ */
+ 
+static int set_attention_status(struct hotplug_slot *slot, u8 value)
+{
+	return 0;
+}
+
+/**
+ *	hardware_test		-	test hardware callback
+ *	@slot: slot to test
+ *	value: test to run
+ *
+ *	The H2999 does not support any hardware tests that we know of. 
+ */
+ 
+static int hardware_test(struct hotplug_slot *slot, u32 value)
+{
+	return 0;
+}
+
+/**
+ *	get_power_status	-	power query callback
+ *	@slot; slot to query
+ *	@value: returned state
+ *
+ *	Called when the hotplug layer wants to ask us if the slot is
+ *	powered. We work on the basis that all slots are powered when
+ *	the unit is docked. This seems to be correct but I've not actually
+ *	rammed a voltmeter into the slots to see if they are cleverer than
+ *	that.
+ */
+ 
+static int get_power_status(struct hotplug_slot *slot, u8 *value)
+{
+	struct h2999_slot *s = slot->private;
+
+	/* Slots are all powered when docked */
+	if(s->dev->docked > 0)
+		*value = 1;
+	else
+		*value = 0;
+	return 0;
+}
+
+/**
+ *	get_adapter_status	-	card presence query
+ *	@slot: slot to query
+ *	@value: returned state
+ *
+ *	If we are not docked, we know the "slot" is empty. If we are
+ *	docked its a bit more complicated.
+ */
+ 
+static int get_adapter_status(struct hotplug_slot *slot, u8 *value)
+{
+	struct h2999_slot *s = slot->private;
+	
+	*value = 0;
+
+	if(s->dev->docked)
+		*value = 1;
+	return 0;
+}
+
+static struct hotplug_slot_ops h2999_ops = {
+	THIS_MODULE,
+	slot_enable,
+	slot_disable,
+	set_attention_status,
+	hardware_test,
+	get_power_status,
+	NULL,
+	NULL,
+	get_adapter_status
+};
+
+/**
+ *	h2999_is_docked		-	check if docked
+ *	@dev: h2999 device
+ *
+ *	Check if we are currently docked. The method we use at the moment
+ *	relies on poking around behind the bridge. There is no doubt a
+ *	correct way to do this. Maybe one day IBM will be decide to 
+ *	actually provide documentation
+ */
+ 
+static int h2999_is_docked(struct h2999_dev *dev)
+{
+	struct pci_dev *pdev = pci_find_slot(dev->hotplug_bus, PCI_DEVFN(0,0));
+	u32 status;
+	
+	if(pdev == NULL)
+		return 0;	/* Shouldnt happen - must be undocked */
+	
+	if(pci_read_config_dword(pdev, PCI_VENDOR_ID, &status))
+		return 0;	/* Config read failed - its missing */
+	
+	if(status == 0xFFFFFFFFUL)	/* Failed */
+		return 0;
+
+	/* Must be docked */		
+	return 1;
+}
+/**
+ *	h2999_reconfigure_dock	-	redock event handler
+ *	@dev: h2999 device
+ *
+ *	A redocking event has occurred. There may also have been an undock
+ *	before hand. If so then the unconfigure routine is called first.
+ */
+ 
+static void h2999_reconfigure_dock(struct h2999_dev *dev)
+{
+	int docked, i;
+	
+	docked = h2999_is_docked(dev);
+			
+	if(docked ^ dev->docked)
+	{
+		printk("h2999: Now %sdocked.\n",
+			docked?"":"un");
+		if(docked)
+		{
+			/* We should do the re-enumeration of the bus here
+			   The current save/restore is a test hack */
+			for(i=0; i < H2999_SLOTS; i++)
+			{
+				if(dev->slots[i].hotplug_slot.private != &dev->slots[i])
+					BUG();
+				slot_enable(&dev->slots[i].hotplug_slot);
+			}
+		}
+		else
+		{
+			for(i=0; i < H2999_SLOTS; i++)
+			{
+				if(slot_disable(&dev->slots[i].hotplug_slot))
+					printk(KERN_ERR "h2999: someone undocked while devices were in use, how rude!\n");
+			}
+		}
+		dev->docked = docked;
+	}
+	/* Clear bits */
+	pci_write_config_byte(dev->pdev, 0x1f, 0xf0);
+}
+
+/*
+ *	h2999_attach	-	attach an H2999 bridge
+ *	@pdev: PCI device
+ *	@unused: unused 
+ *
+ *	Called when the PCI layer discovers an H2999 docking bridge is
+ *	present in the system. We scan the bridge to obtain its current
+ *	status and register it with the hot plug layer
+ */
+ 
+static int __devinit h2999_attach(struct pci_dev *pdev, const struct pci_device_id *unused)
+{
+	/* PCI core found a new H2999 */
+	struct h2999_dev *dev;
+	u8 bus;
+	int i;
+	
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if(dev == NULL)
+		goto nomem;
+		
+	memset(dev, 0, sizeof(*dev));
+
+	dev->pdev = pdev;
+
+	pci_read_config_byte(pdev, PCI_SECONDARY_BUS, &bus);	
+	dev->hotplug_bus = bus;
+
+	/* Requires hotplug_bus and pdev are set */
+	
+	dev->docked = h2999_is_docked(dev);
+	
+	printk(KERN_INFO "Found IBM 20H2999. Status is %sdocked, docking bus is %d.\n",
+		dev->docked?"":"un", dev->hotplug_bus);
+
+	/*
+	 *	Allow for 8 devices. On the TP600 at least we have
+	 *	0-3 as the onboard devices, and 4-7 as the slots.
+	 *	To add more fun there is an ISA bridge which we
+	 *	don't really handle yet.
+	 */
+	 
+	for(i = 0; i < H2999_SLOTS; i++)
+	{
+		struct h2999_slot *s = &dev->slots[i];
+		int ret;
+		
+		s->hotplug_slot.info = &s->hotplug_info;
+		s->hotplug_slot.private = s;
+		s->slotid = i;
+		s->dev = dev;
+		s->live = 1;
+		s->hotplug_slot.ops = &h2999_ops;
+		s->hotplug_slot.name = s->name;
+		s->hotplug_info.power_status = dev->docked;
+		/* FIXME - should probe here 
+		   In truth the hp_register ought to call thse as needed! */
+		s->hotplug_info.adapter_status = 0;
+		s->pdev = pci_find_slot(dev->hotplug_bus, PCI_DEVFN(i, 0));
+		snprintf(s->name, SLOT_NAME_SIZE, "Dock%d.%d", dev->hotplug_bus, i);
+		pci_save_slot(s);	
+		ret = pci_hp_register(&s->hotplug_slot);
+		if(ret)
+		{
+			printk(KERN_ERR "pci_hp_register failed for slot %d with error %d\n", i, ret);
+			s->live = 0;
+		}
+	}
+	pci_set_drvdata(pdev, dev);
+	
+	testdev = dev;
+	return 0;
+nomem:
+	printk(KERN_ERR "h2999_attach: out of memory.\n");
+	return -ENOMEM;
+}
+
+/**
+ *	h2999_cleanup	-	free H2999 memory resources
+ *	@dev: h2999 device
+ *
+ *	Unregister and free up all of our slots
+ */
+
+static int __devinit h2999_cleanup(struct h2999_dev *dev)
+{
+	struct h2999_slot *s;
+	int slot;
+	
+	for(slot = 0; slot < H2999_SLOTS; slot++)
+	{
+		s = &dev->slots[slot];
+		if(s->live)
+			pci_hp_deregister(&s->hotplug_slot);
+	}
+	kfree(dev);
+}
+
+/**
+ *	h2999_detach	-	an H2999 controller vanished
+ *	@dev: device that vanished
+ *
+ *	Called when the PCI layer sees the bridge unplugged. At the moment
+ *	this doesn't happen and since its currently unclear what to do
+ *	in the hot plug layer if it does this may be a good thing 8)
+ */
+ 
+static void __devinit h2999_detach(struct pci_dev *pdev)
+{
+	struct h2999_dev *dev = pci_get_drvdata(pdev);
+	h2999_cleanup(dev);
+}
+
+
+static struct pci_device_id h2999_id_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_IBM, 0x0095, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, h2999_id_tbl);
+
+static struct pci_driver h2999_driver = {
+	name:		"h2999",
+	id_table:	h2999_id_tbl,
+	probe:		h2999_attach,
+	remove:		__devexit_p(h2999_detach)
+	/* FIXME - PM functions */
+};
+
+/*
+ *	Test harness
+ */
+ 
+static struct completion thread_done;
+
+static int h2999_thread(void *unused)
+{
+	lock_kernel();
+	while(testdev != NULL)
+	{
+		set_current_state(TASK_INTERRUPTIBLE);
+		if(signal_pending(current))
+			break;
+		schedule_timeout(HZ);
+		h2999_reconfigure_dock(testdev);
+	}
+	unlock_kernel();
+	complete_and_exit(&thread_done, 0);
+}
+
+static int __init h2999_init_module(void)
+{
+	int rc;
+	printk(KERN_INFO "IBM 20H2999 PCI docking bridge driver v0.01\n");
+	
+	init_completion(&thread_done);
+	
+	rc = pci_module_init(&h2999_driver);
+	if (rc == 0)
+	{
+		if( kernel_thread(h2999_thread, NULL, CLONE_SIGHAND) >= 0)
+			return 0;
+	}	
+	complete(&thread_done);
+	return rc;
+}
+
+static void __exit h2999_cleanup_module(void)
+{
+	pci_unregister_driver(&h2999_driver);
+	wait_for_completion(&thread_done);
+}
+
+module_init(h2999_init_module);
+module_exit(h2999_cleanup_module);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("IBM 20H2999 Docking Bridge Driver");
+MODULE_LICENSE("GPL");
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/hotplug/tp600.h linux.20pre10-ac2/drivers/hotplug/tp600.h
--- linux.20pre10/drivers/hotplug/tp600.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/hotplug/tp600.h	2002-08-19 01:34:17.000000000 +0100
@@ -0,0 +1,29 @@
+#define SLOT_NAME_SIZE 12
+
+struct h2999_slot
+{
+	int slotid;
+
+	struct hotplug_slot hotplug_slot;
+	struct hotplug_slot_info hotplug_info;
+	char name[SLOT_NAME_SIZE];
+
+	struct h2999_dev *dev;
+	struct pci_dev *pdev;
+	int live;
+
+	struct pci_dev *pci[8];
+	u32 save[8][64];
+	u8 drivermap;
+};
+
+#define H2999_SLOTS	8
+
+struct h2999_dev
+{
+	int docked;
+	int hotplug_bus;
+	struct pci_dev *pdev;
+
+	struct h2999_slot slots[H2999_SLOTS];
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/i2c/Config.in linux.20pre10-ac2/drivers/i2c/Config.in
--- linux.20pre10/drivers/i2c/Config.in	2002-10-09 21:36:54.000000000 +0100
+++ linux.20pre10-ac2/drivers/i2c/Config.in	2002-10-10 23:56:47.000000000 +0100
@@ -13,6 +13,12 @@
       dep_tristate '  Philips style parallel port adapter' CONFIG_I2C_PHILIPSPAR $CONFIG_I2C_ALGOBIT $CONFIG_PARPORT
       dep_tristate '  ELV adapter' CONFIG_I2C_ELV $CONFIG_I2C_ALGOBIT
       dep_tristate '  Velleman K9000 adapter' CONFIG_I2C_VELLEMAN $CONFIG_I2C_ALGOBIT
+      dep_tristate '  NatSemi SCx200 I2C using GPIO pins' CONFIG_SCx200_I2C $CONFIG_SCx200 $CONFIG_I2C_ALGOBIT
+      if [ "$CONFIG_SCx200_I2C" != "n" ]; then
+         int  '    GPIO pin used for SCL' CONFIG_SCx200_I2C_SCL 12
+         int  '    GPIO pin used for SDA' CONFIG_SCx200_I2C_SDA 13
+      fi
+      dep_tristate '  NatSemi SCx200 ACCESS.bus' CONFIG_SCx200_ACB $CONFIG_I2C
    fi
 
    dep_tristate 'I2C PCF 8584 interfaces' CONFIG_I2C_ALGOPCF $CONFIG_I2C
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/i2c/Makefile linux.20pre10-ac2/drivers/i2c/Makefile
--- linux.20pre10/drivers/i2c/Makefile	2002-10-09 21:36:54.000000000 +0100
+++ linux.20pre10-ac2/drivers/i2c/Makefile	2002-10-10 23:56:47.000000000 +0100
@@ -18,6 +18,8 @@
 obj-$(CONFIG_ITE_I2C_ALGO)	+= i2c-algo-ite.o
 obj-$(CONFIG_ITE_I2C_ADAP)	+= i2c-adap-ite.o
 obj-$(CONFIG_I2C_PROC)		+= i2c-proc.o
+obj-$(CONFIG_SCx200_I2C)	+= scx200_i2c.o
+obj-$(CONFIG_SCx200_ACB)	+= scx200_acb.o
 obj-$(CONFIG_I2C_KEYWEST)	+= i2c-keywest.o
 
 # This is needed for automatic patch generation: sensors code starts here
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/i2c/scx200_acb.c linux.20pre10-ac2/drivers/i2c/scx200_acb.c
--- linux.20pre10/drivers/i2c/scx200_acb.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/i2c/scx200_acb.c	2002-10-11 00:44:15.000000000 +0100
@@ -0,0 +1,579 @@
+/*  linux/drivers/i2c/scx200_acb.c 
+
+    Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+    National Semiconductor SCx200 ACCESS.bus support
+    
+    Based on i2c-keywest.c which is:
+        Copyright (c) 2001 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+        Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.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 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/smp_lock.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include <linux/scx200.h>
+
+#define NAME "scx200_acb"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 ACCESS.bus Driver");
+MODULE_LICENSE("GPL");
+
+#define MAX_DEVICES 4
+static int base[MAX_DEVICES] = { 0x840 };
+MODULE_PARM(base, "1-4i");
+MODULE_PARM_DESC(base, "Base addresses for the ACCESS.bus controllers");
+
+#define DEBUG 0
+
+#if DEBUG
+#define DBG(x...) printk(KERN_DEBUG NAME ": " x)
+#else
+#define DBG(x...)
+#endif
+
+/* The hardware supports interrupt driven mode too, but I haven't
+   implemented that. */
+#define POLLED_MODE 1
+#define POLL_TIMEOUT (HZ)
+
+enum scx200_acb_state {
+	state_idle,
+	state_address,
+	state_command,
+	state_repeat_start,
+	state_quick,
+	state_read,
+	state_write,
+};
+
+static const char *scx200_acb_state_name[] = {
+	"idle",
+	"address",
+	"command",
+	"repeat_start",
+	"quick",
+	"read",
+	"write",
+};
+
+/* Physical interface */
+struct scx200_acb_iface
+{
+	struct scx200_acb_iface *next;
+	struct i2c_adapter adapter;
+	unsigned base;
+	struct semaphore sem;
+
+	/* State machine data */
+	enum scx200_acb_state state;
+	int result;
+	u8 address_byte;
+	u8 command;
+	u8 *ptr;
+	char needs_reset;
+	unsigned len;
+};
+
+/* Register Definitions */
+#define ACBSDA		(iface->base + 0)
+#define ACBST		(iface->base + 1)
+#define    ACBST_SDAST		0x40 /* SDA Status */
+#define    ACBST_BER		0x20 
+#define    ACBST_NEGACK		0x10 /* Negative Acknowledge */
+#define    ACBST_STASTR		0x08 /* Stall After Start */
+#define    ACBST_MASTER		0x02
+#define ACBCST		(iface->base + 2)
+#define    ACBCST_BB		0x02
+#define ACBCTL1		(iface->base + 3)
+#define    ACBCTL1_STASTRE	0x80
+#define    ACBCTL1_NMINTE	0x40
+#define	   ACBCTL1_ACK		0x10
+#define	   ACBCTL1_STOP		0x02
+#define	   ACBCTL1_START	0x01
+#define ACBADDR		(iface->base + 4)
+#define ACBCTL2		(iface->base + 5)
+#define    ACBCTL2_ENABLE	0x01
+
+/************************************************************************/
+
+static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
+{
+	const char *errmsg;
+
+	DBG("state %s, status = 0x%02x\n", 
+	    scx200_acb_state_name[iface->state], status);
+
+	if (status & ACBST_BER) {
+		errmsg = "bus error";
+		goto error;
+	}
+	if (!(status & ACBST_MASTER)) {
+		errmsg = "not master";
+		goto error;
+	}
+	if (status & ACBST_NEGACK)
+		goto negack;
+
+	switch (iface->state) {
+	case state_idle:
+		printk(KERN_WARNING NAME ": %s, interrupt in idle state\n", 
+		       iface->adapter.name);
+		break;
+
+	case state_address:
+		/* Do a pointer write first */
+		outb(iface->address_byte & ~1, ACBSDA);
+
+		iface->state = state_command;
+		break;
+
+	case state_command:
+		outb(iface->command, ACBSDA);
+
+		if (iface->address_byte & 1)
+			iface->state = state_repeat_start;
+		else
+			iface->state = state_write;
+		break;
+
+	case state_repeat_start:
+		outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+		/* fallthrough */
+		
+	case state_quick:
+		if (iface->address_byte & 1) {
+			if (iface->len == 1) 
+				outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+			else
+				outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+			outb(iface->address_byte, ACBSDA);
+
+			iface->state = state_read;
+		} else {
+			outb(iface->address_byte, ACBSDA);
+
+			iface->state = state_write;
+		}
+		break;
+
+	case state_read:
+		/* Set ACK if receiving the last byte */
+		if (iface->len == 1)
+			outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
+		else
+			outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
+
+		*iface->ptr++ = inb(ACBSDA);
+		--iface->len;
+
+		if (iface->len == 0) {
+			iface->result = 0;
+			iface->state = state_idle;
+			outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+		}
+
+		break;
+
+	case state_write:
+		if (iface->len == 0) {
+			iface->result = 0;
+			iface->state = state_idle;
+			outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+			break;
+		}
+		
+		outb(*iface->ptr++, ACBSDA);
+		--iface->len;
+		
+		break;
+	}
+
+	return;
+
+ negack:
+	DBG("negative acknowledge in state %s\n", 
+	    scx200_acb_state_name[iface->state]);
+
+	iface->state = state_idle;
+	iface->result = -ENXIO;
+
+	outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+	outb(ACBST_STASTR | ACBST_NEGACK, ACBST);
+	return;
+
+ error:
+	printk(KERN_ERR NAME ": %s, %s in state %s\n", iface->adapter.name, 
+	       errmsg, scx200_acb_state_name[iface->state]);
+
+	iface->state = state_idle;
+	iface->result = -EIO;
+	iface->needs_reset = 1;
+}
+
+static void scx200_acb_timeout(struct scx200_acb_iface *iface) 
+{
+	printk(KERN_ERR NAME ": %s, timeout in state %s\n", 
+	       iface->adapter.name, scx200_acb_state_name[iface->state]);
+
+	iface->state = state_idle;
+	iface->result = -EIO;
+	iface->needs_reset = 1;
+}
+
+#ifdef POLLED_MODE
+static void scx200_acb_poll(struct scx200_acb_iface *iface)
+{
+	u8 status = 0;
+	unsigned long timeout;
+
+	timeout = jiffies + POLL_TIMEOUT;
+	while (time_before(jiffies, timeout)) {
+		status = inb(ACBST);
+		if ((status & (ACBST_SDAST|ACBST_BER|ACBST_NEGACK)) != 0) {
+			scx200_acb_machine(iface, status);
+			return;
+		}
+		yield();
+	}
+
+	scx200_acb_timeout(iface);
+}
+#endif /* POLLED_MODE */
+
+static void scx200_acb_reset(struct scx200_acb_iface *iface)
+{
+	/* Disable the ACCESS.bus device and Configure the SCL
+           frequency: 16 clock cycles */
+	outb(0x70, ACBCTL2);
+	/* Polling mode */
+	outb(0, ACBCTL1);
+	/* Disable slave address */
+	outb(0, ACBADDR);
+	/* Enable the ACCESS.bus device */
+	outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+	/* Free STALL after START */
+	outb(inb(ACBCTL1) & ~(ACBCTL1_STASTRE | ACBCTL1_NMINTE), ACBCTL1);
+	/* Send a STOP */
+	outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
+	/* Clear BER, NEGACK and STASTR bits */
+	outb(ACBST_BER | ACBST_NEGACK | ACBST_STASTR, ACBST);
+	/* Clear BB bit */
+	outb(inb(ACBCST) | ACBCST_BB, ACBCST);
+}
+
+static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter,
+				u16 address, unsigned short flags,	
+				char rw, u8 command, int size, 
+				union i2c_smbus_data *data)
+{
+	struct scx200_acb_iface *iface = adapter->data;
+	int len;
+	u8 *buffer;
+	u16 cur_word;
+	int rc;
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+	    	len = 0;
+	    	buffer = NULL;
+	    	break;
+	case I2C_SMBUS_BYTE:
+		if (rw == I2C_SMBUS_READ) {
+			len = 1;
+			buffer = &data->byte;
+		} else {
+			len = 1;
+			buffer = &command;
+		}
+	    	break;
+	case I2C_SMBUS_BYTE_DATA:
+	    	len = 1;
+	    	buffer = &data->byte;
+	    	break;
+	case I2C_SMBUS_WORD_DATA:
+		len = 2;
+	    	cur_word = cpu_to_le16(data->word);
+	    	buffer = (u8 *)&cur_word;
+		break;
+	case I2C_SMBUS_BLOCK_DATA:
+	    	len = data->block[0];
+	    	buffer = &data->block[1];
+		break;
+	default:
+	    	return -EINVAL;
+	}
+
+	DBG("size=%d, address=0x%x, command=0x%x, len=%d, read=%d\n",
+	    size, address, command, len, rw == I2C_SMBUS_READ);
+
+	if (!len && rw == I2C_SMBUS_READ) {
+		printk(KERN_WARNING NAME ": %s, zero length read\n", 
+		       adapter->name);
+		return -EINVAL;
+	}
+
+	if (len && !buffer) {
+		printk(KERN_WARNING NAME ": %s, nonzero length but no buffer\n", adapter->name);
+		return -EFAULT;
+	}
+
+	down(&iface->sem);
+
+	iface->address_byte = address<<1;
+	if (rw == I2C_SMBUS_READ)
+		iface->address_byte |= 1;
+	iface->command = command;
+	iface->ptr = buffer;
+	iface->len = len;
+	iface->result = -EINVAL;
+	iface->needs_reset = 0;
+
+	outb(inb(ACBCTL1) | ACBCTL1_START, ACBCTL1);
+
+	if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE)
+		iface->state = state_quick;
+	else
+		iface->state = state_address;
+
+#ifdef POLLED_MODE
+	while (iface->state != state_idle)
+		scx200_acb_poll(iface);
+#else /* POLLED_MODE */
+#error Interrupt driven mode not implemented
+#endif /* POLLED_MODE */	
+
+	if (iface->needs_reset)
+		scx200_acb_reset(iface);
+
+	rc = iface->result;
+
+	up(&iface->sem);
+
+	if (rc == 0 && size == I2C_SMBUS_WORD_DATA && rw == I2C_SMBUS_READ)
+	    	data->word = le16_to_cpu(cur_word);
+
+#if DEBUG
+	printk(KERN_DEBUG NAME ": transfer done, result: %d", rc);
+	if (buffer) {
+		int i;
+		printk(" data:");
+		for (i = 0; i < len; ++i)
+			printk(" %02x", buffer[i]);
+	}
+	printk("\n");
+#endif
+
+	return rc;
+}
+
+static u32 scx200_acb_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	       I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static int scx200_acb_reg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static int scx200_acb_unreg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static void scx200_acb_inc_use(struct i2c_adapter *adapter)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void scx200_acb_dec_use(struct i2c_adapter *adapter)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+/* For now, we only handle combined mode (smbus) */
+static struct i2c_algorithm scx200_acb_algorithm = {
+	name:		"NatSemi SCx200 ACCESS.bus",
+	id:		I2C_ALGO_SMBUS,
+	smbus_xfer:	scx200_acb_smbus_xfer,
+	functionality:	scx200_acb_func,
+};
+
+struct scx200_acb_iface *scx200_acb_list;
+
+int scx200_acb_probe(struct scx200_acb_iface *iface)
+{
+	u8 val;
+
+	/* Disable the ACCESS.bus device and Configure the SCL
+           frequency: 16 clock cycles */
+	outb(0x70, ACBCTL2);
+
+	if (inb(ACBCTL2) != 0x70) {
+		DBG("ACBCTL2 readback failed\n");
+		return -ENXIO;
+	}
+
+	outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+	val = inb(ACBCTL1);
+	if (val) {
+		DBG("disabled, but ACBCTL1=0x%02x\n", val);
+		return -ENXIO;
+	}
+
+	outb(inb(ACBCTL2) | ACBCTL2_ENABLE, ACBCTL2);
+
+	outb(inb(ACBCTL1) | ACBCTL1_NMINTE, ACBCTL1);
+
+	val = inb(ACBCTL1);
+	if ((val & ACBCTL1_NMINTE) != ACBCTL1_NMINTE) {
+		DBG("enabled, but NMINTE won't be set, ACBCTL1=0x%02x\n", val);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static int  __init scx200_acb_create(int base, int index)
+{
+	struct scx200_acb_iface *iface;
+	struct i2c_adapter *adapter;
+	int rc = 0;
+	char description[64];
+
+	iface = kmalloc(sizeof(*iface), GFP_KERNEL);
+	if (!iface) {
+		printk(KERN_ERR NAME ": can't allocate memory\n");
+		rc = -ENOMEM;
+		goto errout;
+	}
+
+	memset(iface, 0, sizeof(*iface));
+	adapter = &iface->adapter;
+	adapter->data = iface;
+	sprintf(adapter->name, "SCx200 ACB%d", index);
+	adapter->id = I2C_ALGO_SMBUS;
+	adapter->algo = &scx200_acb_algorithm;
+	adapter->inc_use = scx200_acb_inc_use;
+	adapter->dec_use = scx200_acb_dec_use;
+	adapter->client_register = scx200_acb_reg;
+	adapter->client_unregister = scx200_acb_unreg;
+
+	init_MUTEX(&iface->sem);
+
+	sprintf(description, "NatSemi SCx200 ACCESS.bus [%s]", adapter->name);
+	if (request_region(base, 8, description) == 0) {
+		printk(KERN_ERR NAME ": %s, can't allocate io 0x%x-0x%x\n", 
+		       adapter->name, base, base + 8-1);
+		rc = -EBUSY;
+		goto errout;
+	}
+	iface->base = base;
+
+	rc = scx200_acb_probe(iface);
+	if (rc) {
+		printk(KERN_WARNING NAME ": %s, probe failed\n", adapter->name);
+		goto errout;
+	}
+
+	scx200_acb_reset(iface);
+
+	if (i2c_add_adapter(adapter) < 0) {
+		printk(KERN_ERR NAME ": %s, failed to register\n", adapter->name);
+		rc = -ENODEV;
+		goto errout;
+	}
+
+	lock_kernel();
+	iface->next = scx200_acb_list;
+	scx200_acb_list = iface;
+	unlock_kernel();
+
+	return 0;
+
+ errout:
+	if (iface) {
+		if (iface->base)
+			release_region(iface->base, 8);
+		kfree(iface);
+	}
+	return rc;
+}
+
+static int __init scx200_acb_init(void)
+{
+	int i;
+	int rc;
+
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
+
+	/* Verify that this really is a SCx200 processor */
+	if (pci_find_device(PCI_VENDOR_ID_NS,
+			    PCI_DEVICE_ID_NS_SCx200_BRIDGE,
+			    NULL) == NULL)
+		return -ENODEV;
+
+	rc = -ENXIO;
+	for (i = 0; i < MAX_DEVICES; ++i) {
+		if (base[i] > 0)
+			rc = scx200_acb_create(base[i], i);
+	}
+	if (scx200_acb_list)
+		return 0;
+	return rc;
+}
+
+static void __exit scx200_acb_cleanup(void)
+{
+	struct scx200_acb_iface *iface;
+	lock_kernel();
+	while ((iface = scx200_acb_list) != NULL) {
+		scx200_acb_list = iface->next;
+		unlock_kernel();
+
+		i2c_del_adapter(&iface->adapter);
+		release_region(iface->base, 8);
+		kfree(iface);
+		lock_kernel();
+	}
+	unlock_kernel();
+}
+
+module_init(scx200_acb_init);
+module_exit(scx200_acb_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
+        c-basic-offset: 8
+    End:
+*/
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/i2c/scx200_i2c.c linux.20pre10-ac2/drivers/i2c/scx200_i2c.c
--- linux.20pre10/drivers/i2c/scx200_i2c.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/i2c/scx200_i2c.c	2002-10-10 23:56:47.000000000 +0100
@@ -0,0 +1,156 @@
+/* linux/drivers/i2c/scx200_i2c.c 
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   National Semiconductor SCx200 I2C bus on GPIO pins
+
+   Based on i2c-velleman.c Copyright (C) 1995-96, 2000 Simon G. Vogl
+
+   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., 675 Mass Ave, Cambridge, MA 02139, USA.		     
+*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <asm/io.h>
+
+#include <linux/scx200_gpio.h>
+
+#define NAME "scx200_i2c"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
+MODULE_DESCRIPTION("NatSemi SCx200 I2C Driver");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(scl, "i");
+MODULE_PARM_DESC(scl, "GPIO line for SCL");
+MODULE_PARM(sda, "i");
+MODULE_PARM_DESC(sda, "GPIO line for SDA");
+
+static int scl = CONFIG_SCx200_I2C_SCL;
+static int sda = CONFIG_SCx200_I2C_SDA;
+
+static void scx200_i2c_setscl(void *data, int state)
+{
+	scx200_gpio_set(scl, state);
+}
+
+static void scx200_i2c_setsda(void *data, int state)
+{
+	scx200_gpio_set(sda, state);
+} 
+
+static int scx200_i2c_getscl(void *data)
+{
+	return scx200_gpio_get(scl);
+}
+
+static int scx200_i2c_getsda(void *data)
+{
+	return scx200_gpio_get(sda);
+}
+
+static int scx200_i2c_reg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static int scx200_i2c_unreg(struct i2c_client *client)
+{
+	return 0;
+}
+
+static void scx200_i2c_inc_use(struct i2c_adapter *adap)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void scx200_i2c_dec_use(struct i2c_adapter *adap)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+/* ------------------------------------------------------------------------
+ * Encapsulate the above functions in the correct operations structure.
+ * This is only done when more than one hardware adapter is supported.
+ */
+
+static struct i2c_algo_bit_data scx200_i2c_data = {
+	NULL,
+	scx200_i2c_setsda,
+	scx200_i2c_setscl,
+	scx200_i2c_getsda,
+	scx200_i2c_getscl,
+	10, 10, 100,		/* waits, timeout */
+};
+
+static struct i2c_adapter scx200_i2c_ops = {
+	.name              = "NatSemi SCx200 I2C",
+	.id		   = I2C_HW_B_VELLE,
+	.algo_data	   = &scx200_i2c_data,
+	.inc_use	   = scx200_i2c_inc_use,
+	.dec_use	   = scx200_i2c_dec_use,
+	.client_register   = scx200_i2c_reg,
+	.client_unregister = scx200_i2c_unreg,
+};
+
+int scx200_i2c_init(void)
+{
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 I2C Driver\n");
+
+	if (!scx200_gpio_present()) {
+		printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
+		return -ENODEV;
+	}
+
+	printk(KERN_DEBUG NAME ": SCL=GPIO%02u, SDA=GPIO%02u\n", 
+	       scl, sda);
+
+	if (scl == -1 || sda == -1 || scl == sda) {
+		printk(KERN_ERR NAME ": scl and sda must be specified\n");
+		return -EINVAL;
+	}
+
+	/* Configure GPIOs as open collector outputs */
+	scx200_gpio_configure(scl, ~2, 5);
+	scx200_gpio_configure(sda, ~2, 5);
+
+	if (i2c_bit_add_bus(&scx200_i2c_ops) < 0) {
+		printk(KERN_ERR NAME ": adapter %s registration failed\n", 
+		       scx200_i2c_ops.name);
+		return -ENODEV;
+	}
+	
+	return 0;
+}
+
+void scx200_i2c_cleanup(void)
+{
+	i2c_bit_del_bus(&scx200_i2c_ops);
+}
+
+module_init(scx200_i2c_init);
+module_exit(scx200_i2c_cleanup);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../.. SUBDIRS=drivers/i2c modules"
+        c-basic-offset: 8
+    End:
+*/
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/aec62xx.c linux.20pre10-ac2/drivers/ide/aec62xx.c
--- linux.20pre10/drivers/ide/aec62xx.c	2002-10-09 21:36:50.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/aec62xx.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,582 +0,0 @@
-/*
- * linux/drivers/ide/aec62xx.c		Version 0.09	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/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 */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-
-static int aec62xx_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;
-	u8 art = 0, uart = 0;
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			p += sprintf(p, "\n                                AEC6210 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-			p += sprintf(p, "\n                                AEC6260 No Bios Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			p += sprintf(p, "\n                                AEC6260 Chipset.\n");
-			break;
-		default:
-			p += sprintf(p, "\n                                AEC62?? Chipset.\n");
-			break;
-	}
-
-        /*
-         * 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");
-	(void) pci_read_config_byte(bmide_dev, 0x4a, &art);
-	p += sprintf(p, "                %sabled                         %sabled\n",
-		(art&0x02)?" en":"dis",(art&0x04)?" en":"dis");
-	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 ");
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			(void) pci_read_config_byte(bmide_dev, 0x54, &art);
-			p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)         %s(%s)           %s(%s)\n",
-				(c0&0x20)?((art&0x03)?"UDMA":" DMA"):" PIO",
-				(art&0x02)?"2":(art&0x01)?"1":"0",
-				(c0&0x40)?((art&0x0c)?"UDMA":" DMA"):" PIO",
-				(art&0x08)?"2":(art&0x04)?"1":"0",
-				(c1&0x20)?((art&0x30)?"UDMA":" DMA"):" PIO",
-				(art&0x20)?"2":(art&0x10)?"1":"0",
-				(c1&0x40)?((art&0xc0)?"UDMA":" DMA"):" PIO",
-				(art&0x80)?"2":(art&0x40)?"1":"0");
-			(void) pci_read_config_byte(bmide_dev, 0x40, &art);
-			p += sprintf(p, "Active:         0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
-			p += sprintf(p, "             0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x44, &art);
-			p += sprintf(p, "            0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x46, &art);
-			p += sprintf(p, "              0x%02x\n", art);
-			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
-			p += sprintf(p, "Recovery:       0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
-			p += sprintf(p, "             0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x45, &art);
-			p += sprintf(p, "            0x%02x", art);
-			(void) pci_read_config_byte(bmide_dev, 0x47, &art);
-			p += sprintf(p, "              0x%02x\n", art);
-			break;
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			(void) pci_read_config_byte(bmide_dev, 0x44, &art);
-			p += sprintf(p, "DMA Mode:       %s(%s)          %s(%s)",
-				(c0&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
-				((art&0x06)==0x06)?"4":((art&0x05)==0x05)?"4":((art&0x04)==0x04)?"3":((art&0x03)==0x03)?"2":((art&0x02)==0x02)?"1":((art&0x01)==0x01)?"0":"?",
-				(c0&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
-				((art&0x60)==0x60)?"4":((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(bmide_dev, 0x45, &art);
-			p += sprintf(p, "         %s(%s)           %s(%s)\n",
-				(c1&0x20)?((art&0x07)?"UDMA":" DMA"):" PIO",
-				((art&0x06)==0x06)?"4":((art&0x05)==0x05)?"4":((art&0x04)==0x04)?"3":((art&0x03)==0x03)?"2":((art&0x02)==0x02)?"1":((art&0x01)==0x01)?"0":"?",
-				(c1&0x40)?((art&0x70)?"UDMA":" DMA"):" PIO",
-				((art&0x60)==0x60)?"4":((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(bmide_dev, 0x40, &art);
-			p += sprintf(p, "Active:         0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
-			p += sprintf(p, "             0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
-			p += sprintf(p, "            0x%02x", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
-			p += sprintf(p, "              0x%02x\n", HIGH_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x40, &art);
-			p += sprintf(p, "Recovery:       0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x41, &art);
-			p += sprintf(p, "             0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x42, &art);
-			p += sprintf(p, "            0x%02x", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x43, &art);
-			p += sprintf(p, "              0x%02x\n", LOW_4(art));
-			(void) pci_read_config_byte(bmide_dev, 0x49, &uart);
-			p += sprintf(p, "reg49h = 0x%02x ", uart);
-			(void) pci_read_config_byte(bmide_dev, 0x4a, &uart);
-			p += sprintf(p, "reg4ah = 0x%02x\n", uart);
-			break;
-		default:
-			break;
-	}
-
-	return p-buffer;/* => must be less than 4k! */
-}
-#endif	/* defined(DISPLAY_AEC62xx_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte aec62xx_proc = 0;
-
-#ifdef CONFIG_AEC62XX_TUNING
-
-struct chipset_bus_clock_list_entry {
-	byte		xfer_speed;
-
-	byte		chipset_settings_34;
-	byte		ultra_settings_34;
-
-	byte		chipset_settings_33;
-	byte		ultra_settings_33;
-};
-
-struct chipset_bus_clock_list_entry aec62xx_base [] = {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	{	XFER_UDMA_4,	0x41,	0x04,	0x31,	0x05	},
-	{	XFER_UDMA_3,	0x41,	0x03,	0x31,	0x04	},
-	{	XFER_UDMA_2,	0x41,	0x02,	0x31,	0x03	},
-	{	XFER_UDMA_1,	0x41,	0x01,	0x31,	0x02	},
-	{	XFER_UDMA_0,	0x41,	0x01,	0x31,	0x01	},
-
-	{	XFER_MW_DMA_2,	0x41,	0x00,	0x31,	0x00	},
-	{	XFER_MW_DMA_1,	0x42,	0x00,	0x31,	0x00	},
-	{	XFER_MW_DMA_0,	0x7a,	0x00,	0x0a,	0x00	},
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	{	XFER_PIO_4,	0x41,	0x00,	0x31,	0x00	},
-	{	XFER_PIO_3,	0x43,	0x00,	0x33,	0x00	},
-	{	XFER_PIO_2,	0x78,	0x00,	0x08,	0x00	},
-	{	XFER_PIO_1,	0x7a,	0x00,	0x0a,	0x00	},
-	{	XFER_PIO_0,	0x70,	0x00,	0x00,	0x00	},
-	{	0,		0x00,	0x00,	0x00,	0x00	}
-};
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * 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)
-{
-	int bus_speed = system_bus_clock();
-
-	for ( ; chipset_table->xfer_speed ; chipset_table++)
-		if (chipset_table->xfer_speed == speed) {
-			return ((byte) ((bus_speed <= 33) ? chipset_table->chipset_settings_33 : chipset_table->chipset_settings_34));
-		}
-	return 0x00;
-}
-
-static byte pci_bus_clock_list_ultra (byte speed, struct chipset_bus_clock_list_entry * chipset_table)
-{
-	int bus_speed = system_bus_clock();
-
-	for ( ; chipset_table->xfer_speed ; chipset_table++)
-		if (chipset_table->xfer_speed == speed) {
-			return ((byte) ((bus_speed <= 33) ? chipset_table->ultra_settings_33 : chipset_table->ultra_settings_34));
-		}
-	return 0x00;
-}
-
-static int aec6210_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	int err			= 0;
-	unsigned short d_conf	= 0x0000;
-	byte ultra		= 0x00;
-	byte ultra_conf		= 0x00;
-	byte tmp0		= 0x00;
-	byte tmp1		= 0x00;
-	byte tmp2		= 0x00;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	pci_read_config_word(dev, 0x40|(2*drive->dn), &d_conf);
-	tmp0 = pci_bus_clock_list(speed, aec62xx_base);
-	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, aec62xx_base);
-	tmp2 = ((ultra_conf << (2*drive->dn)) | (tmp1 & ~(3 << (2*drive->dn))));
-	pci_write_config_byte(dev, 0x54, tmp2);
-
-	__restore_flags(flags);	/* local CPU only */
-
-	err = ide_config_drive_speed(drive, speed);
-	return(err);
-}
-
-static int aec6260_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	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;
-	int err			= 0;
-	byte drive_conf		= 0x00;
-	byte ultra_conf		= 0x00;
-	byte ultra		= 0x00;
-	byte tmp1		= 0x00;
-	byte tmp2		= 0x00;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	pci_read_config_byte(dev, 0x40|drive->dn, &drive_conf);
-	drive_conf = pci_bus_clock_list(speed, aec62xx_base);
-	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, aec62xx_base);
-	tmp2 = ((ultra_conf << (4*unit)) | (tmp1 & ~(7 << (4*unit))));
-	pci_write_config_byte(dev, ultra_pci, tmp2);
-	__restore_flags(flags);	/* local CPU only */
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return(err);
-}
-
-
-static int aec62xx_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
-		return ((int) aec6210_tune_chipset(drive, speed));
-	} else {
-		return ((int) aec6260_tune_chipset(drive, speed));
-	}
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_aec6210_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	byte unit		= (drive->select.b.unit & 0x01);
-	unsigned long dma_base	= hwif->dma_base;
-	byte speed		= -1;
-
-	if (drive->media != ide_disk)
-		return ((int) ide_dma_off_quietly);
-
-	if (((id->dma_ultra & 0x0010) ||
-	     (id->dma_ultra & 0x0008) ||
-	     (id->dma_ultra & 0x0004)) && (ultra)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
-		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) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-	} else {
- 		return ((int) ide_dma_off_quietly);
- 	}
-
-	outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	(void) aec6210_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_aec6260_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	byte unit		= (drive->select.b.unit & 0x01);
-	unsigned long dma_base	= hwif->dma_base;
-	byte speed		= -1;
-	byte ultra66		= eighty_ninty_three(drive);
-
-	if (drive->media != ide_disk)
-		return ((int) ide_dma_off_quietly);
-
-	if ((id->dma_ultra & 0x0010) && (ultra) && (ultra66)) {
-		speed = XFER_UDMA_4;
-	} else if ((id->dma_ultra & 0x0008) && (ultra) && (ultra66)) {
-		speed = XFER_UDMA_3;
-	} else if ((id->dma_ultra & 0x0004) && (ultra)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
-		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) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-	} else {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	(void) aec6260_tune_chipset(drive, speed);
-
-	return ((int)	((id->dma_ultra >> 11) & 3) ? 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_chipset_for_dma (ide_drive_t *drive, byte ultra)
-{
-	switch(HWIF(drive)->pci_dev->device) {	
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			return config_aec6210_chipset_for_dma(drive, ultra);
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			return config_aec6260_chipset_for_dma(drive, ultra);
-		default:
-			return ((int) ide_dma_off_quietly);
-	}
-}
-
-#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;
-	}
-
-	switch(HWIF(drive)->pci_dev->device) {
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-			(void) aec6210_tune_chipset(drive, speed);
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			(void) aec6260_tune_chipset(drive, speed);
-		default:
-			break;
-        }
-}
-
-#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 & 0x001F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, 1);
-				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, 0);
-				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, 0);
-			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)
-{
-	switch (func) {
-		case ide_dma_check:
-			return config_drive_xfer_rate(drive);
-		case ide_dma_lostirq:
-		case ide_dma_timeout:
-			switch(HWIF(drive)->pci_dev->device) {
-				case PCI_DEVICE_ID_ARTOP_ATP860:
-				case PCI_DEVICE_ID_ARTOP_ATP860R:
-//					{
-//						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;
-				default:
-					break;
-			}
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-#endif /* CONFIG_AEC62XX_TUNING */
-
-unsigned int __init pci_init_aec62xx (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_AEC62XX_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!aec62xx_proc) {
-		aec62xx_proc = 1;
-		bmide_dev = dev;
-		aec62xx_display_info = &aec62xx_get_info;
-	}
-#endif /* DISPLAY_AEC62XX_TIMINGS && CONFIG_PROC_FS */
-
-	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)
-{
-#ifdef CONFIG_AEC62XX_TUNING
-	hwif->tuneproc = &aec62xx_tune_drive;
-	hwif->speedproc = &aec62xx_tune_chipset;
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base)
-		hwif->dmaproc = &aec62xx_dmaproc;
-#else /* !CONFIG_BLK_DEV_IDEDMA */
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-#endif /* CONFIG_AEC62XX_TUNING */
-}
-
-void __init ide_dmacapable_aec62xx (ide_hwif_t *hwif, unsigned long dmabase)
-{
-#ifdef CONFIG_AEC62XX_TUNING
-	unsigned long flags;
-	byte reg54h = 0;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	pci_read_config_byte(hwif->pci_dev, 0x54, &reg54h);
-	pci_write_config_byte(hwif->pci_dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F));
-
-	__restore_flags(flags);	/* local CPU only */
-#endif /* CONFIG_AEC62XX_TUNING */
-	ide_setup_dma(hwif, dmabase, 8);
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ali14xx.c linux.20pre10-ac2/drivers/ide/ali14xx.c
--- linux.20pre10/drivers/ide/ali14xx.c	2002-10-09 21:36:50.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ali14xx.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,226 +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 inb(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;
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	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);
-	restore_flags(flags);	/* all CPUs */
-}
-
-/*
- * Auto-detect the IDE controller port.
- */
-static int __init findPort (void)
-{
-	int i;
-	byte t;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	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);
-				__restore_flags(flags);	/* local CPU only */
-				if (t != 0x50)
-					return 0;
-				return 1;  /* success */
-			}
-		}
-		outb_p(regOff, basePort);
-	}
-	__restore_flags(flags);	/* local CPU only */
-	return 0;
-}
-
-/*
- * Initialize controller registers with default values.
- */
-static int __init initRegisters (void) {
-	RegInitializer *p;
-	byte t;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	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);
-	__restore_flags(flags);	/* local CPU only */
-	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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/alim15x3.c linux.20pre10-ac2/drivers/ide/alim15x3.c
--- linux.20pre10/drivers/ide/alim15x3.c	2002-10-09 21:36:50.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/alim15x3.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,705 +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 = 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) */
-
-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->index ? 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;
-	}
-	__save_flags(flags);
-	__cli();
-	
-	/* 
-	 * PIO mode => ATA FIFO on, ATAPI FIFO off
-	 */
-	pci_read_config_byte(dev, portFIFO, &cd_dma_fifo);
-	if (drive->media==ide_disk) {
-		if (hwif->index) {
-			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->index) {
-			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);
-	__restore_flags(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 int ali15x3_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif = HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte unit		= (drive->select.b.unit & 0x01);
-	byte tmpbyte		= 0x00;
-	int m5229_udma		= hwif->channel? 0x57 : 0x56;
-	int err			= 0;
-
-	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);
-	}
-
-	err = ide_config_drive_speed(drive, speed);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (speed >= XFER_SW_DMA_0) {
-		unsigned long dma_base = hwif->dma_base;
-
-		outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-	}
-
-	if (speed >= XFER_UDMA_0) {
-		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 */
-
-	drive->current_speed = speed;
-
-	return (err);
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive)
-{
-	ali15x3_tune_drive(drive, 5);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_chipset_for_dma (ide_drive_t *drive, byte ultra33)
-{
-	struct hd_driveid *id	= drive->id;
-	byte speed		= 0x00;
-	byte ultra66		= eighty_ninty_three(drive);
-	byte ultra100		= (m5229_revision>=0xc4) ? 1 : 0;
-	int  rval;
-
-	if ((id->dma_ultra & 0x0020) && (ultra100) && (ultra66) && (ultra33)) {
-		speed = XFER_UDMA_5;
-	} else if ((id->dma_ultra & 0x0010) && (ultra66) && (ultra33)) {
-		speed = XFER_UDMA_4;
-	} else if ((id->dma_ultra & 0x0008) && (ultra66) && (ultra33)) {
-		speed = XFER_UDMA_3;
-	} else if ((id->dma_ultra & 0x0004) && (ultra33)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra33)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra33)) {
-		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) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-	} else {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	(void) ali15x3_tune_chipset(drive, speed);
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	rval = (int)(	((id->dma_ultra >> 11) & 3) ? 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 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 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;
-	byte can_ultra_dma		= ali15x3_can_ultra(drive);
-
-	if ((m5229_revision<=0x20) && (drive->media!=ide_disk))
-		return hwif->dmaproc(ide_dma_off_quietly, drive);
-
-	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, can_ultra_dma);
-				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, can_ultra_dma);
-				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, can_ultra_dma);
-			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);
-	}
-	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 */
-
-unsigned int __init pci_init_ali15x3 (struct pci_dev *dev, const char *name)
-{
-	unsigned long fixdma_base = pci_resource_start(dev, 4);
-
-	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
-		 */
-		outb(inb(fixdma_base+2) & 0x60, fixdma_base+2);
-
-		if (inb(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) */
-
-	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;
-
-	__save_flags(flags);
-	__cli();
-
-	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);
-		}
-		/*
-		 * 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 {
-		/*
-		 * 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);
-		/*
-		 * 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);
-
-	__restore_flags(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->tuneproc = &ali15x3_tune_drive;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->speedproc = &ali15x3_tune_chipset;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if ((hwif->dma_base) && (m5229_revision >= 0x20)) {
-		/*
-		 * M1543C or newer for DMAing
-		 */
-		hwif->dmaproc = &ali15x3_dmaproc;
-		hwif->autodma = 1;
-	}
-
-	if (noautodma)
-		hwif->autodma = 0;
-#else
-	hwif->autodma = 0;
-#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);
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/amd74xx.c linux.20pre10-ac2/drivers/ide/amd74xx.c
--- linux.20pre10/drivers/ide/amd74xx.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/amd74xx.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,513 +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 */
-extern char *ide_media_verbose(ide_drive_t *);
-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_p((unsigned short)bibma + 0x02);
-	c1 = inb_p((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;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-static unsigned int amd74xx_swdma_check (struct pci_dev *dev)
-{
-	unsigned int class_rev;
-
-	if ((dev->device == PCI_DEVICE_ID_AMD_VIPER_7411) ||
-	    (dev->device == PCI_DEVICE_ID_AMD_VIPER_7441))
-		return 0;
-
-	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;
-}
-
-/*
- * Here is where all the hard work goes to program the chipset.
- *
- */
-static int amd74xx_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	int err			= 0;
-	byte unit		= (drive->select.b.unit & 0x01);
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	unsigned long dma_base	= hwif->dma_base;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	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);
-
-#ifdef DEBUG
-	printk("%s:%d: Speed 0x%02x UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n",
-		drive->name, drive->dn, speed, ultra_timing, dma_pio_timing, pio_timing);
-#endif
-
-	ultra_timing	&= ~0xC7;
-	dma_pio_timing	&= ~0xFF;
-	pio_timing	&= ~(0x03 << drive->dn);
-
-#ifdef DEBUG
-	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n",
-		drive->name, ultra_timing, dma_pio_timing, pio_timing);
-#endif
-
-	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);
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-#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);
-
-#ifdef DEBUG
-	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x\n",
-		drive->name, ultra_timing, dma_pio_timing, pio_timing);
-#endif
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (speed > XFER_PIO_4) {
-		outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-	} else {
-		outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return (err);
-}
-
-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) amd74xx_tune_chipset(drive, speed);
-	drive->current_speed = speed;
-}
-
-static void amd74xx_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) 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)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	struct hd_driveid *id	= drive->id;
-	byte udma_66		= eighty_ninty_three(drive);
-	byte udma_100		= ((dev->device==PCI_DEVICE_ID_AMD_VIPER_7411)||
-				   (dev->device==PCI_DEVICE_ID_AMD_VIPER_7441)) ? 1 : 0;
-	byte speed		= 0x00;
-	int  rval;
-
-	if (udma_100)
-		udma_66 = eighty_ninty_three(drive);
-
-	if ((id->dma_ultra & 0x0020) && (udma_66) && (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) {
-		speed = XFER_UDMA_2;
-	} else if (id->dma_ultra & 0x0002) {
-		speed = XFER_UDMA_1;
-	} else if (id->dma_ultra & 0x0001) {
-		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 {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	(void) amd74xx_tune_chipset(drive, speed);
-
-	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 :
-						     ide_dma_off_quietly);
-
-	return rval;
-}
-
-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 & 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:
-
-		config_chipset_for_pio(drive);
-	}
-	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
-		 */
-		outb(inb(fixdma_base+2) & 0x60, fixdma_base+2);
-
-		if (inb(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_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 */
-}
-
-void __init ide_init_amd74xx (ide_hwif_t *hwif)
-{
-	hwif->tuneproc = &amd74xx_tune_drive;
-	hwif->speedproc = &amd74xx_tune_chipset;
-
-#ifndef CONFIG_BLK_DEV_IDEDMA
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-	return;
-#else
-
-	if (hwif->dma_base) {
-		hwif->dmaproc = &amd74xx_dmaproc;
-		if (!noautodma)
-			hwif->autodma = 1;
-	} else {
-		hwif->autodma = 0;
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
-
-void __init ide_dmacapable_amd74xx (ide_hwif_t *hwif, unsigned long dmabase)
-{
-	ide_setup_dma(hwif, dmabase, 8);
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/arm/icside.c linux.20pre10-ac2/drivers/ide/arm/icside.c
--- linux.20pre10/drivers/ide/arm/icside.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/arm/icside.c	2002-09-12 13:38:25.000000000 +0100
@@ -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 ddir)
+{
+	return HWIF(drive)->sg_nents = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq, ddir);
+}
+
+/* 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, PCI_DMA_FROMDEVICE);
+	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, PCI_DMA_TODEVICE);
+	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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/arm/Makefile linux.20pre10-ac2/drivers/ide/arm/Makefile
--- linux.20pre10/drivers/ide/arm/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/arm/Makefile	2002-08-29 23:47:56.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/arm/rapide.c linux.20pre10-ac2/drivers/ide/arm/rapide.c
--- linux.20pre10/drivers/ide/arm/rapide.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/arm/rapide.c	2002-08-29 23:47:56.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ataraid.c linux.20pre10-ac2/drivers/ide/ataraid.c
--- linux.20pre10/drivers/ide/ataraid.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ataraid.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,313 +0,0 @@
-/*
-   ataraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
-
-   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, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-   		
-   
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <asm/semaphore.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-#include <linux/kdev_t.h>
-#include <linux/swap.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#include "ataraid.h"
-
-                                        
-static int ataraid_hardsect_size[256];
-static int ataraid_blksize_size[256];
-
-static struct raid_device_operations* ataraid_ops[16];
-
-static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int ataraid_open(struct inode * inode, struct file * filp);
-static int ataraid_release(struct inode * inode, struct file * filp);
-static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh);
-
-
-struct gendisk ataraid_gendisk;
-static int ataraid_gendisk_sizes[256];
-static int ataraid_readahead[256];
-
-static struct block_device_operations ataraid_fops = {
-	owner:			THIS_MODULE,
-	open:                   ataraid_open,
-	release:                ataraid_release,
-	ioctl:                  ataraid_ioctl,
-};
-                
-
-
-static DECLARE_MUTEX(ataraid_sem);
-
-/* Bitmap for the devices currently in use */
-static unsigned int ataraiduse;
-
-
-/* stub fops functions */
-
-static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)  
-{
-	int minor;
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-	
-	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->ioctl))
-		return (ataraid_ops[minor]->ioctl)(inode,file,cmd,arg);
-	return -EINVAL;
-}
-
-static int ataraid_open(struct inode * inode, struct file * filp)
-{
-	int minor;
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-
-	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->open))
-		return (ataraid_ops[minor]->open)(inode,filp);
-	return -EINVAL;
-}
-
-
-static int ataraid_release(struct inode * inode, struct file * filp)
-{
-	int minor;
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-
-	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->release))
-		return (ataraid_ops[minor]->release)(inode,filp);
-	return -EINVAL;
-}
-
-static int ataraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	int minor;
-	int retval;
-	minor = MINOR(bh->b_rdev)>>SHIFT;
-
-	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->make_request)) {
-		
-		retval= (ataraid_ops[minor]->make_request)(q,rw,bh);
-		if (retval == -1) {
-			ataraid_split_request(q,rw,bh);		
-			return 0;
-		} else
-			return retval;
-	}
-	return -EINVAL;
-}
-
-struct buffer_head *ataraid_get_bhead(void)
-{
-	void *ptr = NULL;
-	while (!ptr) {
-		ptr=kmalloc(sizeof(struct buffer_head),GFP_NOIO);
-		if (!ptr)
-			yield();
-	}
-	return ptr;
-}
-
-EXPORT_SYMBOL(ataraid_get_bhead);
-
-struct ataraid_bh_private *ataraid_get_private(void)
-{
-	void *ptr = NULL;
-	while (!ptr) {
-		ptr=kmalloc(sizeof(struct ataraid_bh_private),GFP_NOIO);
-		if (!ptr)
-			yield();
-	}
-	return ptr;
-}
-
-EXPORT_SYMBOL(ataraid_get_private);
-
-void ataraid_end_request(struct buffer_head *bh, int uptodate)
-{
-	struct ataraid_bh_private *private = bh->b_private;
-
-	if (private==NULL)
-		BUG();
-
-	if (atomic_dec_and_test(&private->count)) {
-		private->parent->b_end_io(private->parent,uptodate);
-		private->parent = NULL;
-		kfree(private);
-	}
-	kfree(bh);
-}
-
-EXPORT_SYMBOL(ataraid_end_request);
-
-static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	struct buffer_head *bh1,*bh2;
-	struct ataraid_bh_private *private;
-	bh1=ataraid_get_bhead();
-	bh2=ataraid_get_bhead();
-
-	/* If either of those ever fails we're doomed */
-	if ((!bh1)||(!bh2))
-		BUG();
-	private = ataraid_get_private();
-	if (private==NULL)
-		BUG();
-	
-	memcpy(bh1, bh, sizeof(*bh));
-	memcpy(bh2, bh, sizeof(*bh));
-	
-	bh1->b_end_io = ataraid_end_request;
-	bh2->b_end_io = ataraid_end_request;
-
-	bh2->b_rsector += bh->b_size >> 10;
-	bh1->b_size /= 2;
-	bh2->b_size /= 2;
-	private->parent = bh;
-
-	bh1->b_private = private;
-	bh2->b_private = private;
-	atomic_set(&private->count,2);
-
-	bh2->b_data +=  bh->b_size/2;
-
-	generic_make_request(rw,bh1);
-	generic_make_request(rw,bh2);
-}
-
-
-
-
-/* device register / release functions */
-
-
-int ataraid_get_device(struct raid_device_operations *fops)
-{
-	int bit;
-	down(&ataraid_sem);
-	if (ataraiduse==~0U) {
-		up(&ataraid_sem);
-		return -ENODEV;
-	}
-	bit=ffz(ataraiduse); 
-	ataraiduse |= 1<<bit;
-	ataraid_ops[bit] = fops;
-	up(&ataraid_sem);
-	return bit;
-}
-
-void ataraid_release_device(int device)
-{
-	down(&ataraid_sem);
-	
-	if ((ataraiduse & (1<<device))==0)
-		BUG();	/* device wasn't registered at all */
-	
-	ataraiduse &= ~(1<<device);
-	ataraid_ops[device] = NULL;
-	up(&ataraid_sem);
-}
-
-void ataraid_register_disk(int device,long size)
-{
-	register_disk(&ataraid_gendisk, MKDEV(ATAMAJOR,16*device),16,
-		&ataraid_fops,size);
-
-}
-
-static __init int ataraid_init(void) 
-{
-	int i;
-        for(i=0;i<256;i++)
-	{
-        	ataraid_hardsect_size[i] = 512;
-		ataraid_blksize_size[i] = 1024;  
-		ataraid_readahead[i] = 1023;
-	}
-	
-	if (blksize_size[ATAMAJOR]==NULL)
-		blksize_size[ATAMAJOR] = ataraid_blksize_size;
-	if (hardsect_size[ATAMAJOR]==NULL)
-		hardsect_size[ATAMAJOR] = ataraid_hardsect_size;
-	
-	
-	/* setup the gendisk structure */	
-	ataraid_gendisk.part = kmalloc(256 * sizeof(struct hd_struct),GFP_KERNEL);
-	if (ataraid_gendisk.part==NULL) {
-		printk(KERN_ERR "ataraid: Couldn't allocate memory, aborting \n");
-		return -1;
-	}
-	
-	memset(&ataraid_gendisk.part[0],0,256*sizeof(struct hd_struct));
-	
-	
-	ataraid_gendisk.major       = ATAMAJOR;
-	ataraid_gendisk.major_name  = "ataraid";
-	ataraid_gendisk.minor_shift = 4;
-	ataraid_gendisk.max_p	    = 15;
-	ataraid_gendisk.sizes	    = &ataraid_gendisk_sizes[0];
-	ataraid_gendisk.nr_real	    = 16;
-	ataraid_gendisk.fops        = &ataraid_fops;
-	
-	
-	add_gendisk(&ataraid_gendisk);
-			
-	if (register_blkdev(ATAMAJOR, "ataraid", &ataraid_fops)) {
-		printk(KERN_ERR "ataraid: Could not get major %d \n",ATAMAJOR);
-		return -1;
-	}
-	
-	                
-	
-	blk_queue_make_request(BLK_DEFAULT_QUEUE(ATAMAJOR),ataraid_make_request);
-                                                                                     	
-	return 0;                                                        	
-}
-
-
-static void __exit ataraid_exit(void)
-{
-	unregister_blkdev(ATAMAJOR, "ataraid");
-	hardsect_size[ATAMAJOR] = NULL;
-	blk_size[ATAMAJOR] = NULL;
-	blksize_size[ATAMAJOR] = NULL;                       
-	max_readahead[ATAMAJOR] = NULL;
-
-	del_gendisk(&ataraid_gendisk);
-        
-	if (ataraid_gendisk.part) {
-		kfree(ataraid_gendisk.part);
-		ataraid_gendisk.part = NULL;
-	}
-}
-
-module_init(ataraid_init);
-module_exit(ataraid_exit);
-
-
-
-EXPORT_SYMBOL(ataraid_get_device);
-EXPORT_SYMBOL(ataraid_release_device);
-EXPORT_SYMBOL(ataraid_gendisk);
-EXPORT_SYMBOL(ataraid_register_disk);
-MODULE_LICENSE("GPL");
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ataraid.h linux.20pre10-ac2/drivers/ide/ataraid.h
--- linux.20pre10/drivers/ide/ataraid.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ataraid.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,72 +0,0 @@
-/*
-   ataraid.h  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
-
-   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, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-   		
-   
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/semaphore.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#define ATAMAJOR 114
-#define SHIFT 4
-#define MINOR_MASK 15
-#define MAJOR_MASK 15
-
-                                        
-/* raid_device_operations is a light struct block_device_operations with an
-   added method for make_request */
-struct raid_device_operations {
-	int (*open) (struct inode *, struct file *);
-	int (*release) (struct inode *, struct file *);
-	int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
-	int (*make_request) (request_queue_t *q, int rw, struct buffer_head * bh);
-};
-
-
-struct geom {
-	unsigned char heads;
-	unsigned int cylinders;
-	unsigned char sectors;
-};
-
-/* structure for the splitting of bufferheads */
-
-struct ataraid_bh_private {
-	struct buffer_head *parent;
-	atomic_t count;
-};
-
-extern struct gendisk ataraid_gendisk;
-
-extern int ataraid_get_device(struct raid_device_operations *fops);
-extern void ataraid_release_device(int device);
-extern int get_blocksize(kdev_t dev);
-extern void ataraid_register_disk(int device,long size);
-extern struct buffer_head *ataraid_get_bhead(void);
-extern struct ataraid_bh_private *ataraid_get_private(void);
-extern void ataraid_end_request(struct buffer_head *bh, int uptodate);
-
-
-
-
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/buddha.c linux.20pre10-ac2/drivers/ide/buddha.c
--- linux.20pre10/drivers/ide/buddha.c	2002-10-09 21:36:50.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/buddha.c	1970-01-01 01:00:00.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/cmd640.c linux.20pre10-ac2/drivers/ide/cmd640.c
--- linux.20pre10/drivers/ide/cmd640.c	2002-10-09 21:36:50.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/cmd640.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,856 +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;
-
-	save_flags(flags);
-	cli();
-	outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
-	outb_p(val, (reg & 3) | 0xcfc);
-	restore_flags(flags);
-}
-
-static byte get_cmd640_reg_pci1 (unsigned short reg)
-{
-	byte b;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
-	b = inb_p((reg & 3) | 0xcfc);
-	restore_flags(flags);
-	return b;
-}
-
-/* PCI method 2 access (from CMD datasheet) */
-
-static void put_cmd640_reg_pci2 (unsigned short reg, byte val)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outb_p(0x10, 0xcf8);
-	outb_p(val, cmd640_key + reg);
-	outb_p(0, 0xcf8);
-	restore_flags(flags);
-}
-
-static byte get_cmd640_reg_pci2 (unsigned short reg)
-{
-	byte b;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outb_p(0x10, 0xcf8);
-	b = inb_p(cmd640_key + reg);
-	outb_p(0, 0xcf8);
-	restore_flags(flags);
-	return b;
-}
-
-/* VLB access */
-
-static void put_cmd640_reg_vlb (unsigned short reg, byte val)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outb_p(reg, cmd640_key);
-	outb_p(val, cmd640_key + 4);
-	restore_flags(flags);
-}
-
-static byte get_cmd640_reg_vlb (unsigned short reg)
-{
-	byte b;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	outb_p(reg, cmd640_key);
-	b = inb_p(cmd640_key + 4);
-	restore_flags(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;
-
-	save_flags(flags);
-	cli();
-
-	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) {
-			restore_flags(flags);
-			return 0; /* nothing responded */
-		}
-	}
-	restore_flags(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;
-
-	save_flags(flags);
-	cli();
-	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);
-	restore_flags(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
-	 */
-	save_flags (flags);
-	cli();
-	/*
-	 * 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));
-	restore_flags(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 */
-
-/*
- * 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;
-		if (probe_for_cmd640_pci1())
-			bus_type = "PCI (type1)";
-		else if (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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/cmd64x.c linux.20pre10-ac2/drivers/ide/cmd64x.c
--- linux.20pre10/drivers/ide/cmd64x.c	2002-10-09 21:36:50.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/cmd64x.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,1163 +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-2000  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 int cmd64x_get_info(char *, char **, off_t, int);
-static int cmd680_get_info(char *, char **, off_t, int);
-extern int (*cmd64x_display_info)(char *, char **, off_t, int); /* ide-proc.c */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-
-static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	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 */
-	u8 hi_byte = 0, lo_byte = 0;
-
-	switch(bmide_dev->device) {
-		case PCI_DEVICE_ID_CMD_649:
-			p += sprintf(p, "\n                                CMD649 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_CMD_648:
-			p += sprintf(p, "\n                                CMD648 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_CMD_646:
-			p += sprintf(p, "\n                                CMD646 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_CMD_643:
-			p += sprintf(p, "\n                                CMD643 Chipset.\n");
-			break;
-		default:
-			p += sprintf(p, "\n                                CMD64? Chipse.\n");
-			break;
-	}
-	(void) pci_read_config_byte(bmide_dev, CFR,       &reg50);
-	(void) pci_read_config_byte(bmide_dev, ARTTIM0,   &reg53);
-	(void) pci_read_config_byte(bmide_dev, DRWTIM0,   &reg54);
-	(void) pci_read_config_byte(bmide_dev, ARTTIM1,   &reg55);
-	(void) pci_read_config_byte(bmide_dev, DRWTIM1,   &reg56);
-	(void) pci_read_config_byte(bmide_dev, ARTTIM2,   &reg57);
-	(void) pci_read_config_byte(bmide_dev, DRWTIM2,   &reg58);
-	(void) pci_read_config_byte(bmide_dev, DRWTIM3,   &reg5b);
-	(void) pci_read_config_byte(bmide_dev, MRDMODE,   &reg71);
-	(void) pci_read_config_byte(bmide_dev, BMIDESR0,  &reg72);
-	(void) pci_read_config_byte(bmide_dev, UDIDETCR0, &reg73);
-	(void) pci_read_config_byte(bmide_dev, BMIDESR1,  &reg7a);
-	(void) pci_read_config_byte(bmide_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)         %s(%s)           %s(%s)\n",
-		(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"):"?",
-		(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");
-
-	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);
-
-	return p-buffer;	/* => must be less than 4k! */
-}
-
-static int cmd680_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	p += sprintf(p, "\n                                CMD680 Chipset.\n");
-	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 p-buffer;	/* => must be less than 4k! */
-}
-
-#endif	/* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte cmd64x_proc = 0;
-byte cmd680_proc = 0;
-
-/*
- * 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;
-	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
-	 */
-	__save_flags (flags);
-	__cli();
-	/*
-	 * Program the address_setup clocks into ARTTIM reg,
-	 * and then the active/recovery counts into the DRWTIM reg
-	 */
-	(void) pci_read_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave], &temp_b);
-	(void) pci_write_config_byte(HWIF(drive)->pci_dev, arttim_regs[channel][slave],
-		((byte) setup_count) | (temp_b & 0x3f));
-	(void) pci_write_config_byte(HWIF(drive)->pci_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]);
-	__restore_flags(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 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);
-		drive->current_speed = speed;
-	}
-}
-
-static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
-        if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680) {
-		config_cmd680_chipset_for_pio(drive, set_speed);
-	} else {
-		config_cmd64x_chipset_for_pio(drive, set_speed);
-	}
-}
-
-static int cmd64x_tune_chipset (ide_drive_t *drive, byte speed)
-{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	int err			= 0;
-
-	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;
-
-	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);
-	switch(speed) {
-		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;
-#else
-	int err			= 0;
-
-		switch(speed) {
-#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);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	err = ide_config_drive_speed(drive, speed);
-
-	drive->current_speed = speed;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	regD |= (unit ? 0x40 : 0x20);
-	(void) pci_write_config_byte(dev, pciD, regD);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	return err;
-}
-
-static int cmd680_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	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 dma_pci		= 0;
-	u8 udma_pci		= 0;
-	u8 mode_pci		= 0;
-	u8 scsc			= 0;
-	u16 ultra		= 0;
-	u16 multi		= 0;
-	int err			= 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);
-	}
-
-	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);
-
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return err;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int config_cmd64x_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	byte speed		= 0x00;
-	byte set_pio		= 0x00;
-	byte udma_33		= ((rev >= 0x05) || (ultra_66)) ? 1 : 0;
-	byte udma_66		= eighty_ninty_three(drive);
-	byte udma_100		= 0;
-	int rval;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_649: udma_100 = 1; break;
-		case PCI_DEVICE_ID_CMD_648:
-		case PCI_DEVICE_ID_CMD_646:
-		case PCI_DEVICE_ID_CMD_643:
-		default:
-			break;
-	}
-
-	if (drive->media != ide_disk) {
-		cmdprintk("CMD64X: drive->media != ide_disk at double check, inital check failed!!\n");
-		return ((int) ide_dma_off);
-	}
-
-	/* 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.
-	 */
-	if ((id->dma_ultra & 0x0020) && (udma_100) && (udma_66) && (udma_33)) {
-		speed = XFER_UDMA_5;
-	} else if ((id->dma_ultra & 0x0010) && (udma_66) && (udma_33)) {
-		speed = XFER_UDMA_4;
-	} else if ((id->dma_ultra & 0x0008) && (udma_66) && (udma_33)) {
-		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) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-	} else {
-		set_pio = 1;
-	}
-
-	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 (cmd64x_tune_chipset(drive, speed))
-		return ((int) ide_dma_off);
-
-	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) ? ide_dma_on :
-						     ide_dma_off_quietly);
-
-	return rval;
-}
-
-static int config_cmd680_chipset_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	byte udma_66		= eighty_ninty_three(drive);
-	byte speed		= 0x00;
-	byte set_pio		= 0x00;
-	int rval;
-
-	if ((id->dma_ultra & 0x0040) && (udma_66))	speed = XFER_UDMA_6;
-	else if ((id->dma_ultra & 0x0020) && (udma_66))	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)		speed = XFER_UDMA_2;
-	else if (id->dma_ultra & 0x0002)		speed = XFER_UDMA_1;
-	else if (id->dma_ultra & 0x0001)		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 {
-		set_pio = 1;
-	}
-
-	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 (cmd680_tune_chipset(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 config_chipset_for_dma (ide_drive_t *drive, unsigned int rev, byte ultra_66)
-{
-	if (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_CMD_680)
-		return (config_cmd680_chipset_for_dma(drive));
-	return (config_cmd64x_chipset_for_dma(drive, rev, ultra_66));
-}
-
-static int cmd64x_config_drive_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;
-	unsigned int class_rev	= 0;
-	byte can_ultra_33	= 0;
-	byte can_ultra_66	= 0;
-	byte can_ultra_100	= 0;
-	byte can_ultra_133	= 0;
-	ide_dma_action_t dma_func = ide_dma_on;
-
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;	
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_680:
-			can_ultra_133 = 1;
-		case PCI_DEVICE_ID_CMD_649:
-			can_ultra_100 = 1;
-		case PCI_DEVICE_ID_CMD_648:
-			can_ultra_66  = 1;
-		case PCI_DEVICE_ID_CMD_643:
-			can_ultra_33  = 1;
-			break;
-		case PCI_DEVICE_ID_CMD_646:
-			can_ultra_33  = (class_rev >= 0x05) ? 1 : 0;
-			can_ultra_66  = 0;
-			can_ultra_100 = 0;
-			break;
-		default:
-			return hwif->dmaproc(ide_dma_off, drive);
-	}
-
-	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) && (can_ultra_33)) {
-			if (id->dma_ultra & 0x007F) {
-				/* Force if Capable UltraDMA */
-				dma_func = config_chipset_for_dma(drive, class_rev, can_ultra_66);
-				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, class_rev, 0);
-				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, class_rev, 0);
-			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_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	byte dma_stat		= 0;
-	byte dma_alt_stat	= 0;
-	byte mask		= (HWIF(drive)->channel) ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0;
-	unsigned long dma_base	= HWIF(drive)->dma_base;
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	byte jack_slap		= ((dev->device == PCI_DEVICE_ID_CMD_648) || (dev->device == PCI_DEVICE_ID_CMD_649)) ? 1 : 0;
-
-	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;
-			outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-			dma_stat = inb(dma_base+2);		/* get DMA status */
-			outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
-			if (jack_slap) {
-				byte dma_intr	= 0;
-				byte dma_mask	= (HWIF(drive)->channel) ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
-				byte dma_reg	= (HWIF(drive)->channel) ? ARTTIM2 : CFR;
-				(void) pci_read_config_byte(dev, dma_reg, &dma_intr);
-				/*
-				 * DAMN BMIDE is not connected to PCI space!
-				 * Have to manually jack-slap that bitch!
-				 * To allow the PCI side to read incoming interrupts.
-				 */
-				(void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask);	/* clear the INTR bit */
-			}
-			ide_destroy_dmatable(drive);		/* purge DMA mappings */
-			return (dma_stat & 7) != 4;		/* verify good DMA status */
-		case ide_dma_test_irq:	/* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = inb(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 (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-		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;
-			dma_stat = inb(dma_base+2);		/* get DMA status */
-			outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-			outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
-			ide_destroy_dmatable(drive);		/* and free any DMA resources */
-			return (dma_stat & 7) != 4;		/* verify good DMA status */
-		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);
-	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);
-
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!cmd64x_proc) {
-		cmd64x_proc = 1;
-		bmide_dev = dev;
-		cmd64x_display_info = &cmd680_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 */
-
-#if defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!cmd64x_proc) {
-		cmd64x_proc = 1;
-		bmide_dev = dev;
-		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)
-{
-	if (dev->device == PCI_DEVICE_ID_CMD_680)
-		return cmd680_pci_init (dev, name);
-	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)
-{
-	struct pci_dev *dev	= hwif->pci_dev;
-	if (dev->device == PCI_DEVICE_ID_CMD_680)
-		return cmd680_ata66(hwif);
-	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;
-
-	if (!hwif->dma_base)
-		return;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	switch(dev->device) {
-		case PCI_DEVICE_ID_CMD_680:
-			hwif->busproc	= &cmd680_busproc;
-			hwif->dmaproc	= &cmd680_dmaproc;
-			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:
-			hwif->dmaproc	= &cmd64x_dmaproc;
-			hwif->tuneproc	= &cmd64x_tuneproc;
-			hwif->speedproc = &cmd64x_tune_chipset;
-			break;
-		case PCI_DEVICE_ID_CMD_646:
-			hwif->chipset = ide_cmd646;
-			if (class_rev == 0x01) {
-				hwif->dmaproc = &cmd646_1_dmaproc;
-			} else {
-				hwif->dmaproc = &cmd64x_dmaproc;
-			}
-			hwif->tuneproc	= &cmd64x_tuneproc;
-			hwif->speedproc	= &cmd64x_tune_chipset;
-			break;
-		default:
-			break;
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/Config.in linux.20pre10-ac2/drivers/ide/Config.in
--- linux.20pre10/drivers/ide/Config.in	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/Config.in	2002-09-19 11:38:53.000000000 +0100
@@ -16,17 +16,6 @@
    dep_mbool '    Use multi-mode by default' CONFIG_IDEDISK_MULTI_MODE $CONFIG_BLK_DEV_IDEDISK
    dep_mbool '    Auto-Geometry Resizing support' CONFIG_IDEDISK_STROKE $CONFIG_BLK_DEV_IDEDISK
 
-   define_bool CONFIG_BLK_DEV_IDEDISK_VENDOR n
-   dep_mbool '    Fujitsu Vendor Specific' CONFIG_BLK_DEV_IDEDISK_FUJITSU $CONFIG_BLK_DEV_IDEDISK_VENDOR
-   dep_mbool '    IBM Vendor Specific' CONFIG_BLK_DEV_IDEDISK_IBM $CONFIG_BLK_DEV_IDEDISK_VENDOR
-   dep_mbool '    Maxtor Vendor Specific' CONFIG_BLK_DEV_IDEDISK_MAXTOR $CONFIG_BLK_DEV_IDEDISK_VENDOR
-   dep_mbool '    Quantum Vendor Specific' CONFIG_BLK_DEV_IDEDISK_QUANTUM $CONFIG_BLK_DEV_IDEDISK_VENDOR
-   dep_mbool '    Seagate Vendor Specific' CONFIG_BLK_DEV_IDEDISK_SEAGATE $CONFIG_BLK_DEV_IDEDISK_VENDOR
-   dep_mbool '    Western Digital Vendor Specific' CONFIG_BLK_DEV_IDEDISK_WD $CONFIG_BLK_DEV_IDEDISK_VENDOR
-
-   define_bool CONFIG_BLK_DEV_COMMERIAL n
-   dep_mbool '    TiVo Commerial Application Specific' CONFIG_BLK_DEV_TIVO $CONFIG_BLK_DEV_COMMERIAL
-
    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
@@ -34,7 +23,7 @@
    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
@@ -42,9 +31,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
 	 bool '  Generic PCI IDE chipset support' CONFIG_BLK_DEV_IDEPCI
 	 if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
+	    dep_bool '    Generic PCI IDE 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
@@ -53,46 +42,41 @@
             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 and CMD680 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_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
-	    dep_mbool '      HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_IDEDMA_PCI_WIP
-	    dep_bool '    HPT366/368/370 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
-	    if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" -o "$CONFIG_MIPS" = "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
+            define_bool CONFIG_BLK_DEV_ADMA $CONFIG_BLK_DEV_IDEDMA_PCI
+
+	    dep_tristate '    AEC62XX chipset support' CONFIG_BLK_DEV_AEC62XX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    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_tristate '    AMD Viper support' CONFIG_BLK_DEV_AMD74XX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool    '      AMD Viper ATA-66 Override' CONFIG_AMD74XX_OVERRIDE $CONFIG_BLK_DEV_AMD74XX
+	    dep_tristate '    CMD64{3|6|8|9} chipset support' CONFIG_BLK_DEV_CMD64X $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    CY82C693 chipset support' CONFIG_BLK_DEV_CY82C693 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    Cyrix CS5530 MediaGX chipset support' CONFIG_BLK_DEV_CS5530 $CONFIG_BLK_DEV_IDEDMA_PCI
+  	    dep_tristate '    HPT34X chipset support' CONFIG_BLK_DEV_HPT34X $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_mbool    '      HPT34X AUTODMA support (WIP)' CONFIG_HPT34X_AUTODMA $CONFIG_BLK_DEV_HPT34X $CONFIG_IDEDMA_PCI_WIP
+	    dep_tristate '    HPT366/368/370 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    Intel PIIXn chipsets support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
 	    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 '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
-#	    dep_mbool '   Pacific Digital A-DMA support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC_ADMA $CONFIG_BLK_DEV_ADMA $CONFIG_IDEDMA_PCI_WIP $CONFIG_EXPERIMENTAL
-	    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 '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX
-	    dep_bool '    ServerWorks OSB4/CSB5 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
-	    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 '    Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL
-	    dep_bool '    VIA82CXXX chipset support' CONFIG_BLK_DEV_VIA82CXXX $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    nVidia NFORCE support' CONFIG_BLK_DEV_NFORCE $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    NS87415 chipset support' CONFIG_BLK_DEV_NS87415 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621 $CONFIG_EXPERIMENTAL
+	    dep_tristate '    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_tristate '    PROMISE PDC202{68|69|70|71|75|76|77} support' CONFIG_BLK_DEV_PDC202XX_NEW $CONFIG_BLK_DEV_IDEDMA_PCI
+		# FIXME - probably wants to be one for old and for new
+	    dep_bool     '      Special FastTrak Feature' CONFIG_PDC202XX_FORCE $CONFIG_BLK_DEV_PDC202XX_NEW
+	    dep_tristate '    RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_X86
+	    dep_tristate '    ServerWorks OSB4/CSB5/CSB6 chipsets support' CONFIG_BLK_DEV_SVWKS $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    Silicon Image chipset support' CONFIG_BLK_DEV_SIIMAGE $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    SiS5513 chipset support' CONFIG_BLK_DEV_SIS5513 $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_X86
+	    dep_tristate '    SLC90E66 chipset support' CONFIG_BLK_DEV_SLC90E66 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    Tekram TRM290 chipset support' CONFIG_BLK_DEV_TRM290 $CONFIG_BLK_DEV_IDEDMA_PCI
+	    dep_tristate '    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_tristate '    Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 $CONFIG_BLK_DEV_IDEPCI
 	    fi
          fi
       fi
@@ -149,14 +133,12 @@
       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
@@ -184,7 +166,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 \
@@ -195,16 +196,19 @@
      "$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
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/cs5530.c linux.20pre10-ac2/drivers/ide/cs5530.c
--- linux.20pre10/drivers/ide/cs5530.c	2002-10-09 21:36:50.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/cs5530.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,374 +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 */
-extern char *ide_media_verbose(ide_drive_t *);
-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;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * Set a new transfer mode at the drive
- */
-int cs5530_set_xfer_mode (ide_drive_t *drive, byte mode)
-{
-	int error = 0;
-
-	printk("%s: cs5530_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode));
-	error = ide_config_drive_speed(drive, mode);
-
-	return error;
-}
-
-/*
- * 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 */
-	outb(inb(hwif->dma_base+2)&~(unit?0x40:0x20), hwif->dma_base+2); /* 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 */
-	}
-	outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2);	/* 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;
-	}
-
-	save_flags(flags);
-	cli();	/* 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);
-
-	restore_flags(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)
-{
-	if (hwif->mate)
-		hwif->serialized = hwif->mate->serialized = 1;
-	if (!hwif->dma_base) {
-		hwif->autodma = 0;
-	} else {
-		unsigned int basereg, d0_timings;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		hwif->dmaproc  = &cs5530_dmaproc;
-#else
-		hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-		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 */
-		}
-	}
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/cy82c693.c linux.20pre10-ac2/drivers/ide/cy82c693.c
--- linux.20pre10/drivers/ide/cy82c693.c	2002-10-09 21:36:50.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/cy82c693.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,449 +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;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		hwif->dmaproc = &cy82c693_dmaproc;
-		if (!noautodma)
-			hwif->autodma = 1;
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/dtc2278.c linux.20pre10-ac2/drivers/ide/dtc2278.c
--- linux.20pre10/drivers/ide/dtc2278.c	2002-10-09 21:36:50.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/dtc2278.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,134 +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) {
-		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, byte pio)
-{
-	unsigned long flags;
-
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-
-	if (pio >= 3) {
-		save_flags(flags);	/* all CPUs */
-		cli();			/* all CPUs */
-		/*
-		 * This enables PIO mode4 (3?) on the first interface
-		 */
-		sub22(1,0xc3);
-		sub22(0,0xa0);
-		restore_flags(flags);	/* all CPUs */
-	} 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;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	/*
-	 * 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
-	__restore_flags(flags);	/* local CPU only */
-
-	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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/falconide.c linux.20pre10-ac2/drivers/ide/falconide.c
--- linux.20pre10/drivers/ide/falconide.c	2002-10-09 21:36:50.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/falconide.c	1970-01-01 01:00:00.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/gayle.c linux.20pre10-ac2/drivers/ide/gayle.c
--- linux.20pre10/drivers/ide/gayle.c	2002-10-09 21:36:50.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/gayle.c	1970-01-01 01:00:00.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/hd.c linux.20pre10-ac2/drivers/ide/hd.c
--- linux.20pre10/drivers/ide/hd.c	2002-10-09 21:36:50.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/hd.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,918 +0,0 @@
-/*
- *  linux/drivers/ide/hd.c
- *
- *  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/devfs_fs_kernel.h>
-#include <linux/kernel.h>
-#include <linux/hdreg.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>
-
-#define REALLY_SLOW_IO
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#define MAJOR_NR HD_MAJOR
-#include <linux/blk.h>
-
-#ifdef __arm__
-#undef  HD_IRQ
-#endif
-#include <asm/irq.h>
-#ifdef __arm__
-#define HD_IRQ IRQ_HARDDISK
-#endif
-
-static int revalidate_hddisk(kdev_t, int);
-
-#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 access_count[MAX_HD];
-static char busy[MAX_HD];
-static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
-
-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 hd_struct hd[MAX_HD<<6];
-static int hd_sizes[MAX_HD<<6];
-static int hd_blocksizes[MAX_HD<<6];
-static int hd_hardsectsizes[MAX_HD<<6];
-static int hd_maxsect[MAX_HD<<6];
-
-static struct timer_list device_timer;
-
-#define SET_TIMER 							\
-	do {								\
-		mod_timer(&device_timer, jiffies + TIMEOUT_VALUE);	\
-	} while (0)
-
-#define CLEAR_TIMER del_timer(&device_timer);
-
-#undef SET_INTR
-
-#define SET_INTR(x) \
-if ((DEVICE_INTR = (x)) != NULL) \
-	SET_TIMER; \
-else \
-	CLEAR_TIMER;
-
-
-#if (HD_DELAY > 0)
-unsigned long last_req;
-
-unsigned long read_timer(void)
-{
-	unsigned long t, flags;
-	int i;
-
-	save_flags(flags);
-	cli();
-	t = jiffies * 11932;
-    	outb_p(0, 0x43);
-	i = inb_p(0x40);
-	i |= inb(0x40) << 8;
-	restore_flags(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)
-{
-	unsigned long flags;
-	char devc;
-
-	devc = !QUEUE_EMPTY ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
-	save_flags (flags);
-	sti();
-#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 (!QUEUE_EMPTY)
-				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	/* verbose errors */
-	restore_flags (flags);
-}
-
-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_INTR(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 (QUEUE_EMPTY)
-		return;
-	dev = DEVICE_NR(CURRENT->rq_dev);
-	if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
-		end_request(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(1);
-	if (i > 0) {
-		SET_INTR(&read_intr);
-		return;
-	}
-	(void) inb_p(HD_STATUS);
-#if (HD_DELAY > 0)
-	last_req = read_timer();
-#endif
-	if (!QUEUE_EMPTY)
-		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->bh && !SUBSECTOR(i)))
-		end_request(1);
-	if (i > 0) {
-		SET_INTR(&write_intr);
-		outsw(HD_DATA,CURRENT->buffer,256);
-		sti();
-	} 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;
-
-	DEVICE_INTR = NULL;
-	if (QUEUE_EMPTY)
-		return;
-	disable_irq(HD_IRQ);
-	sti();
-	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(0);
-	}
-	cli();
-	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(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 (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE) return;
-	if (DEVICE_INTR)
-		return;
-repeat:
-	del_timer(&device_timer);
-	sti();
-	INIT_REQUEST;
-	if (reset) {
-		cli();
-		reset_hd();
-		return;
-	}
-	dev = MINOR(CURRENT->rq_dev);
-	block = CURRENT->sector;
-	nsect = CURRENT->nr_sectors;
-	if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects || ((block+nsect) > hd[dev].nr_sects)) {
-#ifdef DEBUG
-		if (dev >= (NR_HD<<6))
-			printk("hd: bad minor number: device=%s\n",
-			       kdevname(CURRENT->rq_dev));
-		else
-			printk("hd%c: bad access: block=%d, count=%d\n",
-				(MINOR(CURRENT->rq_dev)>>6)+'a', block, nsect);
-#endif
-		end_request(0);
-		goto repeat;
-	}
-	block += hd[dev].start_sect;
-	dev >>= 6;
-	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->cmd == READ) {
-		hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
-		if (reset)
-			goto repeat;
-		return;
-	}
-	if (CURRENT->cmd == 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);
-		return;
-	}
-	panic("unknown hd-command");
-}
-
-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) || !(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 = hd[MINOR(inode->i_rdev)].start_sect;
-			return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; 
-		}
-
-         	case BLKGETSIZE:   /* Return device size */
-			return put_user(hd[MINOR(inode->i_rdev)].nr_sects, 
-					(unsigned long *) arg);
-         	case BLKGETSIZE64:
-			return put_user((u64)hd[MINOR(inode->i_rdev)].nr_sects << 9, 
-					(u64 *) arg);
-
-		case BLKRRPART: /* Re-read partition tables */
-			if (!capable(CAP_SYS_ADMIN))
-				return -EACCES;
-			return revalidate_hddisk(inode->i_rdev, 1);
-
-		case BLKROSET:
-		case BLKROGET:
-		case BLKRASET:
-		case BLKRAGET:
-		case BLKFLSBUF:
-		case BLKPG:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
-
-		default:
-			return -EINVAL;
-	}
-}
-
-static int hd_open(struct inode * inode, struct file * filp)
-{
-	int target;
-	target =  DEVICE_NR(inode->i_rdev);
-
-	if (target >= NR_HD)
-		return -ENODEV;
-	while (busy[target])
-		sleep_on(&busy_wait);
-	access_count[target]++;
-	return 0;
-}
-
-/*
- * Releasing a block device means we sync() it, so that it can safely
- * be forgotten about...
- */
-static int hd_release(struct inode * inode, struct file * file)
-{
-        int target =  DEVICE_NR(inode->i_rdev);
-	access_count[target]--;
-	return 0;
-}
-
-extern struct block_device_operations hd_fops;
-
-static struct gendisk hd_gendisk = {
-	major:		MAJOR_NR,
-	major_name:	"hd",
-	minor_shift:	6,
-	max_p:		1 << 6,
-	part:		hd,
-	sizes:		hd_sizes,
-	fops:		&hd_fops,
-};
-	
-static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	void (*handler)(void) = DEVICE_INTR;
-
-	DEVICE_INTR = NULL;
-	del_timer(&device_timer);
-	if (!handler)
-		handler = unexpected_hd_interrupt;
-	handler();
-	sti();
-}
-
-static struct block_device_operations hd_fops = {
-	open:		hd_open,
-	release:	hd_release,
-	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;
-
-	for(drive=0; drive < (MAX_HD << 6); drive++) {
-		hd_blocksizes[drive] = 1024;
-		hd_hardsectsizes[drive] = 512;
-		hd_maxsect[drive]=255;
-	}
-	blksize_size[MAJOR_NR] = hd_blocksizes;
-	hardsect_size[MAJOR_NR] = hd_hardsectsizes;
-	max_sectors[MAJOR_NR] = hd_maxsect;
-
-#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++) {
-		hd[drive<<6].nr_sects = hd_info[drive].head *
-			hd_info[drive].sect * hd_info[drive].cyl;
-		printk ("hd%c: %ldMB, CHS=%d/%d/%d\n", drive+'a',
-			hd[drive<<6].nr_sects / 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;
-	}
-	request_region(HD_DATA, 8, "hd");
-	request_region(HD_CMD, 1, "hd(cmd)");
-
-	hd_gendisk.nr_real = NR_HD;
-
-	for(drive=0; drive < NR_HD; drive++)
-		register_disk(&hd_gendisk, MKDEV(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 (devfs_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), DEVICE_REQUEST);
-	read_ahead[MAJOR_NR] = 8;		/* 8 sector (4kB) read-ahead */
-	add_gendisk(&hd_gendisk);
-	init_timer(&device_timer);
-	device_timer.function = hd_times_out;
-	hd_geninit();
-	return 0;
-}
-
-#define DEVICE_BUSY busy[target]
-#define USAGE access_count[target]
-#define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl)
-/* We assume that the BIOS parameters do not change, so the disk capacity
-   will not change */
-#undef MAYBE_REINIT
-#define GENDISK_STRUCT hd_gendisk
-
-/*
- * This routine is called to flush all partitions and partition tables
- * for a changed disk, and then re-read the new partition table.
- * If we are revalidating a disk because of a media change, then we
- * enter with usage == 0.  If we are using an ioctl, we automatically have
- * usage == 1 (we need an open channel to use an ioctl :-), so this
- * is our limit.
- */
-static int revalidate_hddisk(kdev_t dev, int maxusage)
-{
-	int target;
-	struct gendisk * gdev;
-	int max_p;
-	int start;
-	int i;
-	long flags;
-
-	target = DEVICE_NR(dev);
-	gdev = &GENDISK_STRUCT;
-
-	save_flags(flags);
-	cli();
-	if (DEVICE_BUSY || USAGE > maxusage) {
-		restore_flags(flags);
-		return -EBUSY;
-	}
-	DEVICE_BUSY = 1;
-	restore_flags(flags);
-
-	max_p = gdev->max_p;
-	start = target << gdev->minor_shift;
-
-	for (i=max_p - 1; i >=0 ; i--) {
-		int minor = start + i;
-		invalidate_device(MKDEV(MAJOR_NR, minor), 1);
-		gdev->part[minor].start_sect = 0;
-		gdev->part[minor].nr_sects = 0;
-	}
-
-#ifdef MAYBE_REINIT
-	MAYBE_REINIT;
-#endif
-
-	grok_partitions(gdev, target, 1<<6, CAPACITY);
-
-	DEVICE_BUSY = 0;
-	wake_up(&busy_wait);
-	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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/hpt34x.c linux.20pre10-ac2/drivers/ide/hpt34x.c
--- linux.20pre10/drivers/ide/hpt34x.c	2002-10-09 21:36:50.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/hpt34x.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,437 +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
-
-#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 */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-
-static int hpt34x_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                                HPT34X 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;	/* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte hpt34x_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-static void hpt34x_clear_chipset (ide_drive_t *drive)
-{
-	unsigned int reg1	= 0, tmp1 = 0;
-	unsigned int reg2	= 0, tmp2 = 0;
-
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x44, &reg1);
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
-	tmp1 = ((0x00 << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
-	tmp2 = (reg2 & ~(0x11 << drive->dn));
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
-}
-
-static int hpt34x_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	int			err;
-	byte			hi_speed, lo_speed;
-	unsigned int reg1	= 0, tmp1 = 0;
-	unsigned int reg2	= 0, tmp2 = 0;
-
-	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(HWIF(drive)->pci_dev, 0x44, &reg1);
-	pci_read_config_dword(HWIF(drive)->pci_dev, 0x48, &reg2);
-	tmp1 = ((lo_speed << (3*drive->dn)) | (reg1 & ~(7 << (3*drive->dn))));
-	tmp2 = ((hi_speed << drive->dn) | reg2);
-	err = ide_config_drive_speed(drive, speed);
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x44, tmp1);
-	pci_write_config_dword(HWIF(drive)->pci_dev, 0x48, tmp2);
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-#if HPT343_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d (0x%04x 0x%04x) (0x%04x 0x%04x)" \
-		" (0x%02x 0x%02x) 0x%04x\n",
-		drive->name, ide_xfer_verbose(speed),
-		drive->dn, reg1, tmp1, reg2, tmp2,
-		hi_speed, lo_speed, err);
-#endif /* HPT343_DEBUG_DRIVE_INFO */
-
-	drive->current_speed = speed;
-	return(err);
-}
-
-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 : 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) hpt34x_tune_chipset(drive, speed);
-}
-
-static void hpt34x_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;
-	}
-	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, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	byte speed		= 0x00;
-
-	if (drive->media != ide_disk)
-		return ((int) ide_dma_off_quietly);
-
-	hpt34x_clear_chipset(drive);
-
-	if ((id->dma_ultra & 0x0010) && ultra) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0008) && ultra) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0004) && ultra) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && ultra) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && ultra) {
-		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) {
-		speed = XFER_SW_DMA_2;
-	} else if (id->dma_1word & 0x0002) {
-		speed = XFER_SW_DMA_1;
-	} else if (id->dma_1word & 0x0001) {
-		speed = XFER_SW_DMA_0;
-        } else {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	(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;
-
-	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, 1);
-				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, 0);
-				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, 0);
-			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);
-	}
-
-#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);
-	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;
-			outb(reading, dma_base);		/* specify r/w */
-			outb(inb(dma_base+2)|6, dma_base+2);	/* clear INTR & ERROR flags */
-			drive->waiting_for_dma = 1;
-			if (drive->media != ide_disk)
-				return 0;
-			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);	/* issue cmd to drive */
-			OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-			return 0;
-		case ide_dma_end:	/* returns 1 on error, 0 otherwise */
-			drive->waiting_for_dma = 0;
-			outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-			dma_stat = inb(dma_base+2);		/* get DMA status */
-			outb(dma_stat|6, dma_base+2);		/* clear the INTR & ERROR bits */
-			ide_destroy_dmatable(drive);		/* purge DMA mappings */
-			return (dma_stat & 7) != 4;		/* verify good DMA status */
-		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 short cmd;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	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);
-	}
-
-	pci_write_config_word(dev, PCI_COMMAND, cmd & ~PCI_COMMAND_IO);
-	dev->resource[0].start = (hpt34xIoBase + 0x20);
-	dev->resource[1].start = (hpt34xIoBase + 0x34);
-	dev->resource[2].start = (hpt34xIoBase + 0x28);
-	dev->resource[3].start = (hpt34xIoBase + 0x3c);
-	for(i=0; i<4; i++)
-		dev->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO;
-	/*
-	 * Since 20-23 can be assigned and are R/W, we correct them.
-	 */
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, dev->resource[0].start);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, dev->resource[1].start);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_2, dev->resource[2].start);
-	pci_write_config_dword(dev, PCI_BASE_ADDRESS_3, dev->resource[3].start);
-	pci_write_config_word(dev, PCI_COMMAND, cmd);
-
-	__restore_flags(flags);	/* local CPU only */
-
-#if defined(DISPLAY_HPT34X_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!hpt34x_proc) {
-		hpt34x_proc = 1;
-		bmide_dev = dev;
-		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)
-{
-	hwif->tuneproc = &hpt34x_tune_drive;
-	hwif->speedproc = &hpt34x_tune_chipset;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		unsigned short pcicmd = 0;
-
-		pci_read_config_word(hwif->pci_dev, PCI_COMMAND, &pcicmd);
-		if (!noautodma)
-			hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0;
-		else
-			hwif->autodma = 0;
-
-		hwif->dmaproc = &hpt34x_dmaproc;
-	} else {
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	}
-#else /* !CONFIG_BLK_DEV_IDEDMA */
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/hpt366.c linux.20pre10-ac2/drivers/ide/hpt366.c
--- linux.20pre10/drivers/ide/hpt366.c	2002-10-09 21:36:50.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/hpt366.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,1233 +0,0 @@
-/*
- * linux/drivers/ide/hpt366.c		Version 0.22	20 Sep 2001
- *
- * Copyright (C) 1999-2000		Andre Hedrick <andre@linux-ide.org>
- * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
- * May be copied or modified under the terms of the GNU General Public License
- *
- * 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
-/*#define HPT_DELAY_INTERRUPT*/
-/*#define 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) */
-
-extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
-
-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 [] = {
-
-	{	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 [] = {
-
-	{	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 [] = {
-
-	{	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	}
-};
-
-#if 1
-/* these are the current (4 sep 2001) timings from highpoint */
-struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
-        {       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_hpt370[] = {
-	{       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       }
-};
-#else
-/* from highpoint documentation. these are old values */
-struct chipset_bus_clock_list_entry thirty_three_base_hpt370[] = {
-	{	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      }
-};
-#endif
-
-struct chipset_bus_clock_list_entry fifty_base_hpt370[] = {
-	{       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      }
-};
-
-#define HPT366_DEBUG_DRIVE_INFO		0
-#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 pci_rev_check_hpt3xx(struct pci_dev *dev);
-static unsigned int pci_rev2_check_hpt3xx(struct pci_dev *dev);
-byte hpt366_proc = 0;
-byte hpt363_shared_irq;
-byte hpt363_shared_pin;
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-#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 */
-extern char *ide_media_verbose(ide_drive_t *);
-
-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"};
-	int i;
-
-	p += sprintf(p, "\n                             "
-		"HighPoint HPT366/368/370\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;
-		u8 c0, c1;
-
-		pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-		class_rev &= 0xff;
-
-		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 (pci_rev_check_hpt3xx(dev)) {
-			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 pci_rev_check_hpt3xx (struct pci_dev *dev)
-{
-	unsigned int class_rev;
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-	return ((int) (class_rev > 0x02) ? 1 : 0);
-}
-
-static unsigned int pci_rev2_check_hpt3xx (struct pci_dev *dev)
-{
-	unsigned int class_rev;
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-	return ((int) (class_rev > 0x01) ? 1 : 0);
-}
-
-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 speed)
-{
-	byte regtime		= (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
-	byte regfast		= (HWIF(drive)->channel) ? 0x55 : 0x51;
-			/*
-			 * since the channel is always 0 it does not matter.
-			 */
-
-	unsigned int reg1	= 0;
-	unsigned int reg2	= 0;
-	byte drive_fast		= 0;
-
-	/*
-	 * Disable the "fast interrupt" prediction. 
-	 */
-	pci_read_config_byte(HWIF(drive)->pci_dev, regfast, &drive_fast);
-	if (drive_fast & 0x02)
-		pci_write_config_byte(HWIF(drive)->pci_dev, regfast, drive_fast & ~0x20);
-
-	pci_read_config_dword(HWIF(drive)->pci_dev, regtime, &reg1);
-	/* detect bus speed by looking at control reg timing: */
-	switch((reg1 >> 8) & 7) {
-		case 5:
-			reg2 = pci_bus_clock_list(speed, forty_base);
-			break;
-		case 9:
-			reg2 = pci_bus_clock_list(speed, twenty_five_base);
-			break;
-		default:
-		case 7:
-			reg2 = pci_bus_clock_list(speed, thirty_three_base);
-			break;
-	}
-#if 0
-	/* this is a nice idea ... */
-	list_conf = pci_bus_clock_list(speed,
-				       (struct chipset_bus_clock_list_entry *)
-				       dev->sysdata);
-#endif
-	/*
-	 * Disable on-chip PIO FIFO/buffer (to avoid problems handling I/O errors later)
-	 */
-	if (speed >= XFER_MW_DMA_0) {
-		reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
-	} else {
-		reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
-	}	
-	reg2 &= ~0x80000000;
-
-	pci_write_config_dword(HWIF(drive)->pci_dev, regtime, reg2);
-}
-
-static void hpt370_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	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(HWIF(drive)->pci_dev, regfast, new_fast);
-
-	list_conf = pci_bus_clock_list(speed, 
-				       (struct chipset_bus_clock_list_entry *)
-				       dev->sysdata);
-
-	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 int hpt3xx_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
-		return -1;
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
-		hpt370_tune_chipset(drive, speed);
-        } else {
-                hpt366_tune_chipset(drive, speed);
-        }
-	drive->current_speed = speed;
-	return ((int) 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) hpt3xx_tune_chipset(drive, speed);
-}
-
-static void hpt3xx_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) 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 speed		= 0x00;
-	byte ultra66		= eighty_ninty_three(drive);
-	int  rval;
-
-	if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
-		return ((int) ide_dma_off_quietly);
-
-	if ((id->dma_ultra & 0x0020) &&
-	    (!check_in_drive_lists(drive, bad_ata100_5)) &&
-	    (HPT370_ALLOW_ATA100_5) &&
-	    (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) &&
-	    (ultra66)) {
-		speed = XFER_UDMA_5;
-	} else if ((id->dma_ultra & 0x0010) &&
-		   (!check_in_drive_lists(drive, bad_ata66_4)) &&
-		   (HPT366_ALLOW_ATA66_4) &&
-		   (ultra66)) {
-		speed = XFER_UDMA_4;
-	} else if ((id->dma_ultra & 0x0008) &&
-		   (!check_in_drive_lists(drive, bad_ata66_3)) &&
-		   (HPT366_ALLOW_ATA66_3) &&
-		   (ultra66)) {
-		speed = XFER_UDMA_3;
-	} else if (id->dma_ultra && (!check_in_drive_lists(drive, bad_ata33))) {
-		if (id->dma_ultra & 0x0004) {
-			speed = XFER_UDMA_2;
-		} else if (id->dma_ultra & 0x0002) {
-			speed = XFER_UDMA_1;
-		} else if (id->dma_ultra & 0x0001) {
-			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 {
-		return ((int) ide_dma_off_quietly);
-	}
-
-	(void) hpt3xx_tune_chipset(drive, speed);
-
-	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 :
-						     ide_dma_off_quietly);
-	return rval;
-}
-
-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) {
-		/* drives in the quirk_list may not like intr setups/cleanups */
-	} else {
-		OUT_BYTE((drive)->ctl|2, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]);
-	}
-}
-
-void hpt3xx_maskproc (ide_drive_t *drive, int mask)
-{
-	if (drive->quirk_list) {
-		if (pci_rev_check_hpt3xx(HWIF(drive)->pci_dev)) {
-			byte reg5a = 0;
-			pci_read_config_byte(HWIF(drive)->pci_dev, 0x5a, &reg5a);
-			if (((reg5a & 0x10) >> 4) != mask)
-				pci_write_config_byte(HWIF(drive)->pci_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;
-
-	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 & 0x002F) {
-				/* 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:
-
-		config_chipset_for_pio(drive);
-	}
-	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)
-{
-	byte reg50h = 0, reg52h = 0, reg5ah = 0, dma_stat = 0;
-	unsigned long dma_base = HWIF(drive)->dma_base;
-
-	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 = inb(dma_base+2);
-			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-		case ide_dma_lostirq:
-			pci_read_config_byte(HWIF(drive)->pci_dev, 0x50, &reg50h);
-			pci_read_config_byte(HWIF(drive)->pci_dev, 0x52, &reg52h);
-			pci_read_config_byte(HWIF(drive)->pci_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(HWIF(drive)->pci_dev, 0x5a, reg5ah & ~0x10);
-			/* fall through to a reset */
-#if 0
-		case ide_dma_begin:
-		case ide_dma_end:
-			/* reset the chips state over and over.. */
-			pci_write_config_byte(HWIF(drive)->pci_dev, 0x51, 0x13);
-#endif
-			break;
-		case ide_dma_timeout:
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-
-int hpt370_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
-{
-	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 = inb(dma_base+2);
-			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-
-		case ide_dma_end:
-			dma_stat = inb(dma_base + 2);
-			if (dma_stat & 0x01) {
-				udelay(20); /* wait a little */
-				dma_stat = inb(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(hwif->pci_dev, reginfo, 
-					     &dma_stat); 
-			printk("%s: %d bytes in FIFO\n", drive->name, 
-			       dma_stat);
-			pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
-			udelay(10);
-			dma_stat = inb(dma_base);
-			outb(dma_stat & ~0x1, dma_base); /* stop dma */
-			dma_stat = inb(dma_base + 2); 
-			outb(dma_stat | 0x6, dma_base+2); /* clear errors */
-			/* fallthrough */
-
-#ifdef HPT_RESET_STATE_ENGINE
-	        case ide_dma_begin:
-#endif
-			pci_write_config_byte(hwif->pci_dev, regstate, 0x37);
-			udelay(10);
-			break;
-
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#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);
-	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(hwif->pci_dev, tristate, &tri_reg);
-	pci_read_config_byte(hwif->pci_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(hwif->pci_dev, 0x59, bus_reg);
-	pci_write_config_word(hwif->pci_dev, tristate, tri_reg);
-
-	return 0;
-}
-
-static void __init init_hpt370(struct pci_dev *dev)
-{
-	int adjust, i;
-	u16 freq;
-	u32 pll;
-	byte reg5bh;
-
-	/*
-	 * 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;
-		dev->sysdata = (void *) thirty_three_base_hpt370;
-		printk("HPT370: using 33MHz PCI clock\n");
-	} else if (freq < 0xb0) {
-		pll = F_LOW_PCI_40;
-	} else if (freq < 0xc8) {
-		pll = F_LOW_PCI_50;
-		dev->sysdata = (void *) fifty_base_hpt370;
-		printk("HPT370: using 50MHz PCI clock\n");
-	} else {
-		pll = F_LOW_PCI_66;
-		dev->sysdata = (void *) sixty_six_base_hpt370;
-		printk("HPT370: 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->sysdata) 
-		goto init_hpt370_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);
-				dev->sysdata = (void *) fifty_base_hpt370;
-				printk("HPT370: using 50MHz internal PLL\n");
-				goto init_hpt370_done;
-			}
-		}
-pll_recal:
-		if (adjust & 1)
-			pll -= (adjust >> 1);
-		else
-			pll += (adjust >> 1);
-	} 
-
-init_hpt370_done:
-	/* reset state engine */
-	pci_write_config_byte(dev, 0x50, 0x37); 
-	pci_write_config_byte(dev, 0x54, 0x37); 
-	udelay(100);
-}
-
-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 (pci_rev_check_hpt3xx(dev)) {
-		init_hpt370(dev);
-		hpt_devs[n_hpt_devs++] = dev;
-	} else {
-		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)
-{
-	int hpt_rev;
-
-	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
-
-	hpt_rev = pci_rev_check_hpt3xx(hwif->pci_dev);
-	if (hpt_rev) {
-		/* set up ioctl for power status. note: power affects both
-		 * drives on each channel */
-		hwif->busproc   = &hpt370_busproc;
-	}
-
-	if (pci_rev2_check_hpt3xx(hwif->pci_dev)) {
-		/* do nothing now but will split device types */
-		hwif->resetproc = &hpt3xx_reset;
-/*
- * don't do until we can parse out the cobalt box argh ...
- *		hwif->busproc   = &hpt3xx_tristate;
- */
-	}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		if (hpt_rev) {
-			byte reg5ah = 0;
-			pci_read_config_byte(hwif->pci_dev, 0x5a, &reg5ah);
-			if (reg5ah & 0x10)	/* interrupt force enable */
-				pci_write_config_byte(hwif->pci_dev, 0x5a, reg5ah & ~0x10);
-			hwif->dmaproc = &hpt370_dmaproc;
-		} else {
-			hwif->dmaproc = &hpt366_dmaproc;
-		}
-		if (!noautodma)
-			hwif->autodma = 1;
-		else
-			hwif->autodma = 0;
-	} else {
-		hwif->autodma = 0;
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	}
-#else /* !CONFIG_BLK_DEV_IDEDMA */
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-#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 = inb(dmabase+2);
-	byte primary	= hwif->channel ? 0x4b : 0x43;
-	byte secondary	= hwif->channel ? 0x4f : 0x47;
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	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) outb(dma_new, dmabase+2);
-
-	__restore_flags(flags);	/* local CPU only */
-
-	ide_setup_dma(hwif, dmabase, 8);
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/hptraid.c linux.20pre10-ac2/drivers/ide/hptraid.c
--- linux.20pre10/drivers/ide/hptraid.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/hptraid.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,436 +0,0 @@
-/*
-   hptraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
-
-   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, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-
-   Based on work
-   	Copyleft  (C) 2001 by Wilfried Weissmann <wweissmann@gmx.at>
-	Copyright (C) 1994-96 Marc ZYNGIER <zyngier@ufr-info-p7.ibp.fr>
-   Based on work done by Sren Schmidt for FreeBSD
-
-   
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/kernel.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#include "ataraid.h"
-
-static int hptraid_open(struct inode * inode, struct file * filp);
-static int hptraid_release(struct inode * inode, struct file * filp);
-static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int hptraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
-
-
-
-struct hptdisk {
-	kdev_t	device;
-	unsigned long sectors;
-	struct block_device *bdev;
-};
-
-struct hptraid {
-	unsigned int stride;
-	unsigned int disks;
-	unsigned long sectors;
-	struct geom geom;
-	
-	struct hptdisk disk[8];
-	
-	unsigned long cutoff[8];
-	unsigned int cutoff_disks[8];	
-};
-
-static struct raid_device_operations hptraid_ops = {
-	open:                   hptraid_open,
-	release:                hptraid_release,
-	ioctl:			hptraid_ioctl,
-	make_request:		hptraid_make_request
-};
-
-static struct hptraid raid[16];
-
-static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	unsigned int minor;
-	unsigned char val;
-	unsigned long sectors;
-	
-	if (!inode || !inode->i_rdev) 	
-		return -EINVAL;
-
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-	
-	switch (cmd) {
-         	case BLKGETSIZE:   /* Return device size */
-			if (!arg)  return -EINVAL;
-			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
-			if (MINOR(inode->i_rdev)&15)
-				return put_user(sectors, (unsigned long *) arg);
-			return put_user(raid[minor].sectors , (unsigned long *) arg);
-			break;
-			
-
-		case HDIO_GETGEO:
-		{
-			struct hd_geometry *loc = (struct hd_geometry *) arg;
-			unsigned short bios_cyl;
-			
-			if (!loc) return -EINVAL;
-			val = 255;
-			if (put_user(val, (byte *) &loc->heads)) return -EFAULT;
-			val=63;
-			if (put_user(val, (byte *) &loc->sectors)) return -EFAULT;
-			bios_cyl = raid[minor].sectors/63/255;
-			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
-				(unsigned long *) &loc->start)) return -EFAULT;
-			return 0;
-		}
-
-		case HDIO_GETGEO_BIG:
-		{
-			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
-			unsigned int bios_cyl;
-			if (!loc) return -EINVAL;
-			val = 255;
-			if (put_user(val, (byte *) &loc->heads)) return -EFAULT;
-			val = 63;
-			if (put_user(val, (byte *) &loc->sectors)) return -EFAULT;
-			bios_cyl = raid[minor].sectors/63/255;
-			if (put_user(bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
-				(unsigned long *) &loc->start)) return -EFAULT;
-			return 0;
-		}
-			
-		default:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
-	};
-
-	return 0;
-}
-
-
-static int hptraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	unsigned long rsect;
-	unsigned long rsect_left,rsect_accum = 0;
-	unsigned long block;
-	unsigned int disk=0,real_disk=0;
-	int i;
-	int device;
-	struct hptraid *thisraid;
-
-	rsect = bh->b_rsector;
-
-	/* Ok. We need to modify this sector number to a new disk + new sector number. 
-	 * If there are disks of different sizes, this gets tricky. 
-	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
-	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
-	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
-	 * and the last 1Gb is disk 3 only.
-	 *
-	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
-	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
-	 * point, we have to divide by one less.
-	 */
-	
-	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
-	thisraid = &raid[device];
-	if (thisraid->stride==0)
-		thisraid->stride=1;
-
-	/* Partitions need adding of the start sector of the partition to the requested sector */
-	
-	rsect += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
-
-	/* Woops we need to split the request to avoid crossing a stride barrier */
-	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
-		return -1;
-	}
-			
-	rsect_left = rsect;
-	
-	for (i=0;i<8;i++) {
-		if (thisraid->cutoff_disks[i]==0)
-			break;
-		if (rsect > thisraid->cutoff[i]) {
-			/* we're in the wrong area so far */
-			rsect_left -= thisraid->cutoff[i];
-			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
-		} else {
-			block = rsect_left / thisraid->stride;
-			disk = block % thisraid->cutoff_disks[i];
-			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
-			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
-			break;
-		}
-	}
-	
-	for (i=0;i<8;i++) {
-		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
-			real_disk = i;
-			break;
-		}
-		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
-			disk--;
-		}
-		
-	}
-	disk = real_disk;
-	
-	/* All but the first disk have a 10 sector offset */
-	if (i>0)
-		rsect+=10;
-		
-	
-	/*
-	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
-	 * is the only IO operation happening on this bh.
-	 */
-	 
-	bh->b_rdev = thisraid->disk[disk].device;
-	bh->b_rsector = rsect;
-
-	/*
-	 * Let the main block layer submit the IO and resolve recursion:
-	 */
-	return 1;
-}
-
-
-#include "hptraid.h"
-
-static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
-{
-	int ret = -EINVAL;
-	struct buffer_head *bh = NULL;
-	kdev_t dev = MKDEV(major,minor);
-	
-	if (blksize_size[major]==NULL)	 /* device doesn't exist */
-		return -EINVAL;
-	
-
-	/* Superblock is at 4096+412 bytes */
-	set_blocksize (dev, 4096);
-	bh = bread (dev, 1, 4096);
-
-	
-	if (bh) {
-		memcpy (buffer, bh->b_data, bufsize);
-	} else {
-		printk(KERN_ERR "hptraid: Error reading superblock.\n");
-		goto abort;
-	}
-	ret = 0;
-abort:
-	if (bh)
-		brelse (bh);
-	return ret;
-}
-
-static unsigned long maxsectors (int major,int minor)
-{
-	unsigned long lba = 0;
-	kdev_t dev;
-	ide_drive_t *ideinfo;
-	
-	dev = MKDEV(major,minor);
-	ideinfo = get_info_ptr (dev);
-	if (ideinfo==NULL)
-		return 0;
-	
-	
-	/* first sector of the last cluster */
-	if (ideinfo->head==0) 
-		return 0;
-	if (ideinfo->sect==0)
-		return 0;
-	lba = (ideinfo->capacity);
-
-	return lba;
-}
-
-static void __init probedisk(int major, int minor,int device)
-{
-	int i;
-        struct highpoint_raid_conf *prom;
-	static unsigned char block[4096];
-	struct block_device *bdev;
-	
-	if (maxsectors(major,minor)==0)
-		return;
-	
-        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
-        	return;
-                                                                                                                 
-        prom = (struct highpoint_raid_conf*)&block[512];
-                
-        if (prom->magic!=  0x5a7816f0)
-        	return;
-        if (prom->type) {
-        	printk(KERN_INFO "hptraid: only RAID0 is supported currently\n");
-        	return;
-        }
-
-	i = prom->disk_number;
-	if (i<0)
-		return;
-	if (i>8) 
-		return;
-
-	bdev = bdget(MKDEV(major,minor));
-	if (bdev && blkdev_get(bdev,FMODE_READ|FMODE_WRITE,0,BDEV_RAW) == 0) {
-        	int j=0;
-        	struct gendisk *gd;
-		raid[device].disk[i].bdev = bdev;
-        	/* This is supposed to prevent others from stealing our underlying disks */
-		/* now blank the /proc/partitions table for the wrong partition table,
-		   so that scripts don't accidentally mount it and crash the kernel */
-		 /* XXX: the 0 is an utter hack  --hch */
-		gd=get_gendisk(MKDEV(major, 0));
-		if (gd!=NULL) {
-			for (j=1+(minor<<gd->minor_shift);j<((minor+1)<<gd->minor_shift);j++) 
-				gd->part[j].nr_sects=0;					
-		}
-        }
-	raid[device].disk[i].device = MKDEV(major,minor);
-	raid[device].disk[i].sectors = maxsectors(major,minor);
-	raid[device].stride = (1<<prom->raid0_shift);
-	raid[device].disks = prom->raid_disks;
-	raid[device].sectors = prom->total_secs;
-			
-}
-
-static void __init fill_cutoff(int device)
-{
-	int i,j;
-	unsigned long smallest;
-	unsigned long bar;
-	int count;
-	
-	bar = 0;
-	for (i=0;i<8;i++) {
-		smallest = ~0;
-		for (j=0;j<8;j++) 
-			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
-				smallest = raid[device].disk[j].sectors;
-		count = 0;
-		for (j=0;j<8;j++) 
-			if (raid[device].disk[j].sectors >= smallest)
-				count++;
-		
-		smallest = smallest * count;		
-		bar = smallest;
-		raid[device].cutoff[i] = smallest;
-		raid[device].cutoff_disks[i] = count;
-		
-	}
-}
-
-
-static __init int hptraid_init_one(int device)
-{
-	int i,count;
-
-	probedisk(IDE0_MAJOR,  0, device);
-	probedisk(IDE0_MAJOR, 64, device);
-	probedisk(IDE1_MAJOR,  0, device);
-	probedisk(IDE1_MAJOR, 64, device);
-	probedisk(IDE2_MAJOR,  0, device);
-	probedisk(IDE2_MAJOR, 64, device);
-	probedisk(IDE3_MAJOR,  0, device);
-	probedisk(IDE3_MAJOR, 64, device);
-	probedisk(IDE4_MAJOR,  0, device);
-	probedisk(IDE4_MAJOR, 64, device);
-	probedisk(IDE5_MAJOR,  0, device);
-	probedisk(IDE5_MAJOR, 64, device);
-
-	fill_cutoff(device);
-	
-	/* Initialize the gendisk structure */
-	
-	ataraid_register_disk(device,raid[device].sectors);
-
-	count=0;
-	printk(KERN_INFO "Highpoint HPT370 Softwareraid driver for linux version 0.01\n");
-		
-	for (i=0;i<8;i++) {
-		if (raid[device].disk[i].device!=0) {
-			printk(KERN_INFO "Drive %i is %li Mb \n",
-				i,raid[device].disk[i].sectors/2048);
-			count++;
-		}
-	}
-	if (count) {
-		printk(KERN_INFO "Raid array consists of %i drives. \n",count);
-		return 0;
-	} else {
-		printk(KERN_INFO "No raid array found\n");
-		return -ENODEV;
-	}
-	
-}
-
-static __init int hptraid_init(void)
-{
-	int retval,device;
-	
-	device=ataraid_get_device(&hptraid_ops);
-	if (device<0)
-		return -ENODEV;
-	retval = hptraid_init_one(device);
-	if (retval)
-		ataraid_release_device(device);
-	return retval;
-}
-
-static void __exit hptraid_exit (void)
-{
-	int i,device;
-	for (device = 0; device<16; device++) {
-		for (i=0;i<8;i++)  {
-			struct block_device *bdev = raid[device].disk[i].bdev;
-			raid[device].disk[i].bdev = NULL;
-			if (bdev)
-				blkdev_put(bdev, BDEV_RAW);
-		}       
-		if (raid[device].sectors)
-			ataraid_release_device(device);
-	}
-}
-
-static int hptraid_open(struct inode * inode, struct file * filp) 
-{
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-static int hptraid_release(struct inode * inode, struct file * filp)
-{	
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-module_init(hptraid_init);
-module_exit(hptraid_exit);
-MODULE_LICENSE("GPL");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/hptraid.h linux.20pre10-ac2/drivers/ide/hptraid.h
--- linux.20pre10/drivers/ide/hptraid.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/hptraid.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,77 +0,0 @@
-/*-
- * Copyright (c) 2000,2001 Sren Schmidt <sos@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer,
- *    without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-                            
-struct highpoint_raid_conf
-{
-       int8_t  filler1[32];
-       u_int32_t       magic;
-#define HPT_MAGIC_OK   0x5a7816f0
-#define HPT_MAGIC_BAD  0x5a7816fd  
-
-       u_int32_t       magic_0;
-       u_int32_t       magic_1;
-       u_int32_t       order;  
-#define HPT_O_MIRROR   0x01  
-#define HPT_O_STRIPE   0x02
-#define HPT_O_OK       0x04
-
-       u_int8_t        raid_disks;
-       u_int8_t        raid0_shift; 
-       u_int8_t        type;
-#define HPT_T_RAID_0   0x00 
-#define HPT_T_RAID_1   0x01
-#define HPT_T_RAID_01_RAID_0   0x02
-#define HPT_T_SPAN             0x03
-#define HPT_T_RAID_3           0x04   
-#define HPT_T_RAID_5           0x05
-#define HPT_T_SINGLEDISK       0x06
-#define HPT_T_RAID_01_RAID_1   0x07
-
-       u_int8_t        disk_number;
-       u_int32_t       total_secs; 
-       u_int32_t       disk_mode;  
-       u_int32_t       boot_mode;
-       u_int8_t        boot_disk; 
-       u_int8_t        boot_protect;
-       u_int8_t        error_log_entries;
-       u_int8_t        error_log_index;  
-       struct
-       {
-               u_int32_t       timestamp;
-               u_int8_t        reason;   
-#define HPT_R_REMOVED          0xfe      
-#define HPT_R_BROKEN           0xff      
-
-               u_int8_t        disk;
-               u_int8_t        status;
-               u_int8_t        sectors;
-               u_int32_t       lba;
-       } errorlog[32];
-       u_int8_t        filler[60];
-};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ht6560b.c linux.20pre10-ac2/drivers/ide/ht6560b.c
--- linux.20pre10/drivers/ide/ht6560b.c	2002-10-09 21:36:50.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ht6560b.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,343 +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;
-	
-	__save_flags (flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	
-	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) inb(HT_CONFIG_PORT);
-		(void) inb(HT_CONFIG_PORT);
-		(void) inb(HT_CONFIG_PORT);
-		(void) inb(HT_CONFIG_PORT);
-		outb(select, HT_CONFIG_PORT);
-		/*
-		 * Set timing for this drive:
-		 */
-		outb(timing, IDE_SELECT_REG);
-		(void) inb(IDE_STATUS_REG);
-#ifdef DEBUG
-		printk("ht6560b: %s: select=%#x timing=%#x\n", drive->name, select, timing);
-#endif
-	}
-	__restore_flags (flags);	/* local CPU only */
-}
-
-/*
- * Autodetection and initialization of ht6560b
- */
-static int __init try_to_init_ht6560b(void)
-{
-	byte 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 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;
-	
-	save_flags (flags);	/* all CPUs */
-	cli();		        /* all CPUs */
-	
-	/*
-	 *  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;
-	}
-	
-	restore_flags (flags);	/* all CPUs */
-	
-#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);
-	
-	save_flags (flags);	/* all CPUs */
-	cli();		        /* all CPUs */
-	
-	drive->drive_data &= 0xff00;
-	drive->drive_data |= timing;
-	
-	restore_flags (flags);	/* all CPUs */
-	
-#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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/icside.c linux.20pre10-ac2/drivers/ide/icside.c
--- linux.20pre10/drivers/ide/icside.c	2002-10-09 21:36:50.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/icside.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,766 +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>
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * 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 = (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;
-				ide_end_request(1, HWGROUP(drive));
-			}
-			return ide_stopped;
-		}
-		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
-		       drive->name, dma_stat);
-	}
-	return ide_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);
-	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.
-		 */
-		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, reading ? DMA_MODE_READ
-			     : DMA_MODE_WRITE);
-
-		drive->waiting_for_dma = 1;
-		if (drive->media != ide_disk)
-			return 0;
-
-		ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
-		OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA,
-			 IDE_COMMAND_REG);
-
-	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 inb((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
-	 */
-	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);
-		}
-		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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-adma.c linux.20pre10-ac2/drivers/ide/ide-adma.c
--- linux.20pre10/drivers/ide/ide-adma.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-adma.c	1970-01-01 01:00:00.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide.c linux.20pre10-ac2/drivers/ide/ide.c
--- linux.20pre10/drivers/ide/ide.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide.c	2002-09-30 17:17:24.000000000 +0100
@@ -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>
@@ -159,71 +159,87 @@
 
 #include "ide_modes.h"
 
-#ifdef CONFIG_KMOD
 #include <linux/kmod.h>
-#endif /* CONFIG_KMOD */
-
-#ifdef CONFIG_IDE_TASKFILE_IO
-#  define __TASKFILE__IO
-#else /* CONFIG_IDE_TASKFILE_IO */
-#  undef __TASKFILE__IO
-#endif /* CONFIG_IDE_TASKFILE_IO */
-
-#ifdef __TASKFILE__IO
-#else /* !__TASKFILE__IO */
-#endif /* __TASKFILE__IO */
 
 /* 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 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 */
 
-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 */
-
-#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)
 /*
  * ide_lock is used by the Atari code to obtain access to the IDE interrupt,
  * which is shared between several drivers.
  */
-static int	ide_lock;
+static int ide_intr_lock;
 #endif /* __mc68000__ || CONFIG_APUS */
 
+#ifdef CONFIG_IDEDMA_AUTO
 int noautodma = 0;
+#else
+int noautodma = 1;
+#endif
+
+EXPORT_SYMBOL(noautodma);
+
 
 /*
  * ide_modules keeps track of the available IDE chipset/probe/driver modules.
  */
+ide_module_t *ide_chipsets;
 ide_module_t *ide_modules;
 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;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
+	
+	/* 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 |= inb(0x40) << 8;
-	__restore_flags(flags);	/* local CPU only */
+	i |= inb_p(0x40) << 8;
+	local_irq_restore(flags);
 	return (t - i);
 }
 #endif /* DISK_RECOVERY_TIME */
@@ -231,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 */
 }
 
@@ -264,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];
 
@@ -279,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_waitqueue_head(&drive->wqueue);
 	}
 }
@@ -296,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)
@@ -319,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.
@@ -359,212 +359,34 @@
 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(KERN_INFO "ide: Assuming %dMHz system bus speed "
+			"for PIO modes%s\n", system_bus_speed,
 			idebus_parameter ? "" : "; override with idebus=xx");
 	}
 	return system_bus_speed;
 }
 
-#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 do_vlb_sync (ide_ioreg_t port) {
-	(void) inb (port);
-	(void) inb (port);
-	(void) inb (port);
-}
-#endif /* SUPPORT_VLB_SYNC */
-
-/*
- * This is used for most PIO data transfers *from* the IDE interface
- */
-void ide_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;
-			__save_flags(flags);	/* local CPU only */
-			__cli();		/* local CPU only */
-			do_vlb_sync(IDE_NSECTOR_REG);
-			insl(IDE_DATA_REG, buffer, wcount);
-			__restore_flags(flags);	/* local CPU only */
-		} 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 ide_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;
-			__save_flags(flags);	/* local CPU only */
-			__cli();		/* local CPU only */
-			do_vlb_sync(IDE_NSECTOR_REG);
-			outsl(IDE_DATA_REG, buffer, wcount);
-			__restore_flags(flags);	/* local CPU only */
-		} 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 */
-	ide_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 */
-	ide_output_data (drive, buffer, bytecount / 4);
-	if ((bytecount & 0x03) >= 2)
-		outsw (IDE_DATA_REG, ((byte *)buffer) + (bytecount & ~0x03), 1);
-}
-
-/*
- * Needed for PCI irq sharing
- */
-//static inline
-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
-	udelay(1);	/* need to guarantee 400ns since last command was issued */
-#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 */
-}
-
 /*
  * This is our end_request replacement function.
  */
-void ide_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
+int ide_end_request (ide_drive_t *drive, int uptodate)
 {
 	struct request *rq;
 	unsigned long flags;
-	ide_drive_t *drive = hwgroup->drive;
+	int ret = 1;
 
 	spin_lock_irqsave(&io_request_lock, flags);
-	rq = hwgroup->rq;
+	rq = HWGROUP(drive)->rq;
 
 	/*
 	 * decide whether to reenable DMA -- 3 is a random magic for now,
@@ -572,43 +394,23 @@
 	 */
 	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
 		drive->state = 0;
-		hwgroup->hwif->dmaproc(ide_dma_on, drive);
+		HWGROUP(drive)->hwif->ide_dma_on(drive);
 	}
 
-	if (!end_that_request_first(rq, uptodate, hwgroup->drive->name)) {
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
 		add_blkdev_randomness(MAJOR(rq->rq_dev));
 		blkdev_dequeue_request(rq);
-        	hwgroup->rq = NULL;
+		HWGROUP(drive)->rq = NULL;
 		end_that_request_last(rq);
+		ret = 0;
 	}
-	spin_unlock_irqrestore(&io_request_lock, flags);
-}
 
-/*
- * 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(&io_request_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(&io_request_lock, flags);
+	return ret;
 }
 
+EXPORT_SYMBOL(ide_end_request);
+
 /*
  * current_capacity() returns the capacity (in sectors) of a drive
  * according to its current geometry/LBA settings.
@@ -622,248 +424,21 @@
 	return 0;
 }
 
-extern struct block_device_operations ide_fops[];
-/*
- * ide_geninit() is called exactly *once* for each interface.
- */
-void ide_geninit (ide_hwif_t *hwif)
-{
-	unsigned int unit;
-	struct gendisk *gd = hwif->gd;
-
-	for (unit = 0; unit < MAX_DRIVES; ++unit) {
-		ide_drive_t *drive = &hwif->drives[unit];
-
-		if (!drive->present)
-			continue;
-		if (drive->media!=ide_disk && drive->media!=ide_floppy)
-			continue;
-		register_disk(gd,MKDEV(hwif->major,unit<<PARTN_BITS),
-#ifdef CONFIG_BLK_DEV_ISAPNP
-			(drive->forced_geom && drive->noprobe) ? 1 :
-#endif /* CONFIG_BLK_DEV_ISAPNP */
-			1<<PARTN_BITS, ide_fops,
-			current_capacity(drive));
-	}
-}
-
-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 (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
-			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 (0 < (signed long)(hwgroup->poll_timeout - jiffies)) {
-			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);
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	/* 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;
-		ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL);
-		__restore_flags (flags);	/* local CPU only */
-		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) {
-		__restore_flags(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;
-	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 */
-
-	__restore_flags (flags);	/* local CPU only */
-	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;
 
@@ -874,57 +449,61 @@
 	switch(rq->cmd) {
 		case IDE_DRIVE_CMD:
 		{
-			byte *args = (byte *) rq->buffer;
-			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+			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);
 			}
 			break;
 		}
 		case IDE_DRIVE_TASK:
 		{
-			byte *args = (byte *) rq->buffer;
-			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+			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);
 			}
 			break;
 		}
 		case IDE_DRIVE_TASKFILE:
 		{
 			ide_task_t *args = (ide_task_t *) rq->special;
-			rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+			if (rq->errors == 0)
+				rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+				
 			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);
 				}
 			}
 			break;
@@ -939,22 +518,24 @@
 	spin_unlock_irqrestore(&io_request_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;
 
-	__save_flags (flags);	/* local CPU only */
-	ide__sti();		/* local CPU only */
-	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
+	local_irq_set(flags);
+	printk(KERN_WARNING "%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 ");
@@ -967,13 +548,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 ");
@@ -983,30 +564,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)
@@ -1016,10 +597,12 @@
 #endif	/* FANCY_STATUS_DUMPS */
 		printk("\n");
 	}
-	__restore_flags (flags);	/* local CPU only */
+	local_irq_restore(flags);
 	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
@@ -1027,7 +610,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;
 
@@ -1035,23 +618,33 @@
 		return;
 	while (i > 0) {
 		u32 buffer[16];
-		unsigned int wcount = (i > 16) ? 16 : i;
+		u32 wcount = (i > 16) ? 16 : i;
+
 		i -= wcount;
-		ide_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
+ */
+
 /*
  * 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->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) {
 		rq->errors = 1;
@@ -1065,32 +658,46 @@
 		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) {
+				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;
+			}
 		}
+media_out:
 		if ((stat & DRQ_STAT) && rq->cmd != WRITE)
 			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) {
 		if (drive->driver != NULL)
-			DRIVER(drive)->end_request(0, HWGROUP(drive));
+			DRIVER(drive)->end_request(drive, 0);
 		else
-	 		ide_end_request(0, HWGROUP(drive));
+	 		ide_end_request(drive, 0);
 	} else {
 		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
 			++rq->errors;
@@ -1103,51 +710,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)
 {
-	ide_set_handler (drive, handler, WAIT_CMD, NULL);
+	ide_hwif_t *hwif = HWIF(drive);
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	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;
 
-	ide__sti();	/* local CPU only */
+	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;
-		ide_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 ide_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;
 
@@ -1155,77 +773,27 @@
 	printk("%s: do_special: 0x%02x\n", drive->name, s->all);
 #endif
 	if (s->b.set_tune) {
-		ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
 		s->b.set_tune = 0;
-		if (tuneproc != NULL)
-			tuneproc(drive, drive->tune_req);
+		if (HWIF(drive)->tuneproc != NULL)
+			HWIF(drive)->tuneproc(drive, drive->tune_req);
 	} else if (drive->driver != NULL) {
 		return DRIVER(drive)->special(drive);
 	} else if (s->all) {
-		printk("%s: bad special flag: 0x%02x\n", drive->name, s->all);
+		printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, s->all);
 		s->all = 0;
 	}
 	return ide_stopped;
 }
 
-/*
- * 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) {
-		__save_flags(flags);	/* local CPU only */
-		ide__sti();		/* local CPU only */
-		timeout += jiffies;
-		while ((stat = GET_STAT()) & BUSY_STAT) {
-			if (0 < (signed long)(jiffies - timeout)) {
-				__restore_flags(flags);	/* local CPU only */
-				*startstop = ide_error(drive, "status timeout", stat);
-				return 1;
-			}
-		}
-		__restore_flags(flags);	/* local CPU only */
-	}
-	/*
-	 * 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 = ide_error(drive, "status error", stat);
-	return 1;
-}
+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);
  	switch(rq->cmd) {
  		case IDE_DRIVE_TASKFILE:
  		{
@@ -1233,48 +801,14 @@
  
  			if (!(args)) break;
  
-#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]);
-	printk("TF.2=x%02x ", args->tfRegister[IDE_NSECTOR_OFFSET]);
-	printk("TF.3=x%02x ", args->tfRegister[IDE_SECTOR_OFFSET]);
-	printk("TF.4=x%02x ", args->tfRegister[IDE_LCYL_OFFSET]);
-	printk("TF.5=x%02x ", args->tfRegister[IDE_HCYL_OFFSET]);
-	printk("TF.6=x%02x ", args->tfRegister[IDE_SELECT_OFFSET]);
-	printk("TF.7=x%02x\n", args->tfRegister[IDE_COMMAND_OFFSET]);
-	printk(KERN_INFO "%s: ", drive->name);
-//	printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET_HOB]);
-	printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET_HOB]);
-	printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET_HOB]);
-	printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET_HOB]);
-	printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET_HOB]);
-	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 */
-
-//			if (args->tf_out_flags.all == 0) {
- 			do_taskfile(drive,
- 				(struct hd_drive_task_hdr *)&args->tfRegister,
-				(struct hd_drive_hob_hdr *)&args->hobRegister,
- 				args->handler);
-//			} else {
-//				return flagged_taskfile(drive, args);
-//			} 
-
- 			if (((args->command_type == IDE_DRIVE_TASK_RAW_WRITE) ||
- 			     (args->command_type == IDE_DRIVE_TASK_OUT)) &&
-			      args->prehandler && args->handler)
-				return args->prehandler(drive, rq);
- 			return ide_started;
+			if (args->tf_out_flags.all != 0) 
+				return flagged_taskfile(drive, args);
+			return do_rw_taskfile(drive, args);
  		}
  		case IDE_DRIVE_TASK:
  		{
- 			byte *args = rq->buffer;
- 			byte sel;
+ 			u8 *args = rq->buffer;
+ 			u8 sel;
  
  			if (!(args)) break;
 #ifdef DEBUG
@@ -1287,20 +821,20 @@
  			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;
  		}
  		case IDE_DRIVE_CMD:
  		{
- 			byte *args = rq->buffer;
+ 			u8 *args = rq->buffer;
  
  			if (!(args)) break;
 #ifdef DEBUG
@@ -1311,14 +845,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;
  		}
@@ -1332,16 +866,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, blockend;
@@ -1349,30 +887,41 @@
 	ide_hwif_t *hwif = HWIF(drive);
 
 #ifdef DEBUG
-	printk("%s: start_request: current=0x%08lx\n", hwif->name, (unsigned long) rq);
+	printk("%s: start_request: current=0x%08lx\n",
+		hwif->name, (unsigned long) rq);
 #endif
+
 	/* bail early if we've exceeded max_failures */
 	if (drive->max_failures && (drive->failures > drive->max_failures)) {
 		goto kill_rq;
 	}
 
+	/*
+	 * bail early if we've sent a device to sleep, however how to wake
+	 * this needs to be a masked flag.  FIXME for proper operations.
+	 */
+	if (drive->suspend_reset) {
+		goto kill_rq;
+	}
+
 	if (unit >= MAX_DRIVES) {
-		printk("%s: bad device number: %s\n", hwif->name, kdevname(rq->rq_dev));
+		printk(KERN_ERR "%s: bad device number: %s\n",
+			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);
+		printk(KERN_ERR "%s: block not locked\n", drive->name);
 		goto kill_rq;
 	}
 #endif
 	block    = rq->sector;
 	blockend = block + rq->nr_sectors;
 
-	if ((rq->cmd == READ || rq->cmd == WRITE) &&
+	if (blk_fs_request(rq) &&
 	    (drive->media == ide_disk || drive->media == ide_floppy)) {
 		if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) {
-			printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name,
+			printk(KERN_ERR "%s%c: bad access: block=%ld, count=%ld\n", drive->name,
 			 (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors);
 			goto kill_rq;
 		}
@@ -1387,15 +936,16 @@
 	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);
+		printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
 		return startstop;
 	}
 	if (!drive->special.all) {
 		switch(rq->cmd) {
 			case IDE_DRIVE_CMD:
 			case IDE_DRIVE_TASK:
+				return execute_drive_cmd(drive, rq);
 			case IDE_DRIVE_TASKFILE:
 				return execute_drive_cmd(drive, rq);
 			default:
@@ -1404,33 +954,28 @@
 		if (drive->driver != NULL) {
 			return (DRIVER(drive)->do_request(drive, rq, block));
 		}
-		printk("%s: media type %d not supported\n", drive->name, drive->media);
+		printk(KERN_WARNING "%s: media type %d not supported\n", drive->name, drive->media);
 		goto kill_rq;
 	}
 	return do_special(drive);
 kill_rq:
 	if (drive->driver != NULL)
-		DRIVER(drive)->end_request(0, HWGROUP(drive));
+		DRIVER(drive)->end_request(drive, 0);
 	else
-		ide_end_request(0, HWGROUP(drive));
+		ide_end_request(drive, 0);
 	return ide_stopped;
 }
 
-ide_startstop_t restart_request (ide_drive_t *drive)
-{
-	ide_hwgroup_t *hwgroup = HWGROUP(drive);
-	unsigned long flags;
-	struct request *rq;
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	hwgroup->handler = NULL;
-	del_timer(&hwgroup->timer);
-	rq = hwgroup->rq;
-	spin_unlock_irqrestore(&io_request_lock, flags);
+EXPORT_SYMBOL(start_request);
 
-	return start_request(drive, rq);
+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.
@@ -1442,6 +987,8 @@
 	drive->sleep = timeout + jiffies;
 }
 
+EXPORT_SYMBOL(ide_stall_queue);
+
 #define WAKEUP(drive)	((drive)->service_start + 2 * (drive)->service_time)
 
 /*
@@ -1455,12 +1002,12 @@
 	best = NULL;
 	drive = hwgroup->drive;
 	do {
-		if (!list_empty(&drive->queue.queue_head) && (!drive->sleep || 0 <= (signed long)(jiffies - drive->sleep))) {
+		if (!blk_queue_empty(&drive->queue) && (!drive->sleep || time_after_eq(jiffies, drive->sleep))) {
 			if (!best
 			 || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep)))
 			 || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive))))
 			{
-				if( !drive->queue.plugged )
+				if (!blk_queue_plugged(&drive->queue))
 					best = drive;
 			}
 		}
@@ -1468,10 +1015,10 @@
 	if (best && best->nice1 && !best->sleep && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) {
 		long t = (signed long)(WAKEUP(best) - jiffies);
 		if (t >= WAIT_MIN_SLEEP) {
-			/*
-			 * We *may* have some time to spare, but first let's see if
-			 * someone can potentially benefit from our nice mood today..
-			 */
+		/*
+		 * We *may* have some time to spare, but first let's see if
+		 * someone can potentially benefit from our nice mood today..
+		 */
 			drive = best->next;
 			do {
 				if (!drive->sleep
@@ -1532,9 +1079,11 @@
 	struct request	*rq;
 	ide_startstop_t	startstop;
 
-	ide_get_lock(&ide_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);
 
-	__cli();	/* necessary paranoia: ensure IRQs are masked on local CPU */
+	/* necessary paranoia: ensure IRQs are masked on local CPU */
+	local_irq_disable();
 
 	while (!hwgroup->busy) {
 		hwgroup->busy = 1;
@@ -1548,42 +1097,53 @@
 					sleep = drive->sleep;
 			} while ((drive = drive->next) != hwgroup->drive);
 			if (sleep) {
-				/*
-				 * Take a short snooze, and then wake up this hwgroup again.
-				 * This gives other hwgroups on the same a chance to
-				 * play fairly with us, just in case there are big differences
-				 * in relative throughputs.. don't want to hog the cpu too much.
-				 */
-				if (0 < (signed long)(jiffies + WAIT_MIN_SLEEP - sleep)) 
+		/*
+		 * Take a short snooze, and then wake up this hwgroup again.
+		 * This gives other hwgroups on the same a chance to
+		 * play fairly with us, just in case there are big differences
+		 * in relative throughputs.. don't want to hog the cpu too much.
+		 */
+				if (time_before(sleep, jiffies + WAIT_MIN_SLEEP))
 					sleep = jiffies + WAIT_MIN_SLEEP;
 #if 1
 				if (timer_pending(&hwgroup->timer))
-					printk("ide_set_handler: timer already active\n");
+					printk(KERN_ERR "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_intr_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;
 		drive->sleep = 0;
 		drive->service_start = jiffies;
 
-		if ( drive->queue.plugged )	/* paranoia */
-			printk("%s: Huh? nuking plugged queue\n", drive->name);
+		/* paranoia */
+		if (blk_queue_plugged(&drive->queue))
+			printk(KERN_ERR "%s: Huh? nuking plugged queue\n", drive->name);
 
-		rq = hwgroup->rq = blkdev_entry_next_request(&drive->queue.queue_head);
+		rq = blkdev_entry_next_request(&drive->queue.queue_head);
+		hwgroup->rq = rq;
 		/*
 		 * Some systems have trouble with IDE IRQs arriving while
 		 * the driver is still setting things up.  So, here we disable
@@ -1595,7 +1155,8 @@
 		if (masked_irq && hwif->irq != masked_irq)
 			disable_irq_nosync(hwif->irq);
 		spin_unlock(&io_request_lock);
-		ide__sti();	/* allow other IRQs while we start this request */
+		local_irq_enable();
+			/* allow other IRQs while we start this request */
 		startstop = start_request(drive, rq);
 		spin_lock_irq(&io_request_lock);
 		if (masked_irq && hwif->irq != masked_irq)
@@ -1605,6 +1166,8 @@
 	}
 }
 
+EXPORT_SYMBOL(ide_do_request);
+
 /*
  * ide_get_queue() returns the queue which corresponds to a given device.
  */
@@ -1615,6 +1178,8 @@
 	return &hwif->drives[DEVICE_NR(dev) & 1].queue;
 }
 
+EXPORT_SYMBOL(ide_get_queue);
+
 /*
  * Passes the stuff to ide_do_request
  */
@@ -1636,13 +1201,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);
+	printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);
+	(void) hwif->ide_dma_timeout(drive);
 
 	/*
 	 * disable dma for now, but remember that we did so because of
@@ -1651,7 +1216,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
@@ -1663,9 +1228,12 @@
 	rq->errors = 0;
 	rq->sector = rq->bh->b_rsector;
 	rq->current_nr_sectors = rq->bh->b_size >> 9;
+	rq->hard_cur_sectors = rq->current_nr_sectors;
 	rq->buffer = rq->bh->b_data;
 }
 
+EXPORT_SYMBOL(ide_dma_timeout_retry);
+
 /*
  * ide_timer_expiry() is our timeout function for all drive operations.
  * But note that it can also be invoked as a result of a "sleep" operation
@@ -1696,14 +1264,14 @@
 	} else {
 		ide_drive_t *drive = hwgroup->drive;
 		if (!drive) {
-			printk("ide_timer_expiry: hwgroup->drive was NULL\n");
+			printk(KERN_ERR "ide_timer_expiry: hwgroup->drive was NULL\n");
 			hwgroup->handler = NULL;
 		} else {
 			ide_hwif_t *hwif;
-			ide_startstop_t startstop;
+			ide_startstop_t startstop = ide_stopped;
 			if (!hwgroup->busy) {
 				hwgroup->busy = 1;	/* paranoia */
-				printk("%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name);
+				printk(KERN_ERR "%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name);
 			}
 			if ((expiry = hwgroup->expiry) != NULL) {
 				/* continue */
@@ -1718,31 +1286,35 @@
 			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(&io_request_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 */
-			__cli();	/* local CPU only, as if we were handling an interrupt */
+
+			/* local CPU only,
+			 * as if we were handling an interrupt */
+			local_irq_disable();
 			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);
+				printk(KERN_ERR "%s: lost interrupt\n", drive->name);
 				startstop = handler(drive);
 			} else {
 				if (drive->waiting_for_dma) {
 					startstop = ide_stopped;
 					ide_dma_timeout_retry(drive);
 				} else
-					startstop = ide_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;
@@ -1756,6 +1328,8 @@
 	spin_unlock_irqrestore(&io_request_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.
@@ -1781,7 +1355,7 @@
  */
 static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
 {
-	byte stat;
+	u8 stat;
 	ide_hwif_t *hwif = hwgroup->hwif;
 
 	/*
@@ -1789,15 +1363,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 (0 < (signed long)(jiffies - (last_msgtime + HZ))) {
+				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(KERN_ERR "%s%s: unexpected interrupt, "
+						"status=0x%02x, count=%ld\n",
+						hwif->name,
+						(hwif->next==hwgroup->hwif) ? "" : "(?)", stat, count);
 				}
 			}
 		}
@@ -1824,7 +1400,8 @@
 		return;
 	}
 
-	if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) {
+	if ((handler = hwgroup->handler) == NULL ||
+	    hwgroup->poll_timeout != 0) {
 		/*
 		 * Not expecting an interrupt from this drive.
 		 * That means this could be:
@@ -1838,7 +1415,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 */
 		{
 			/*
@@ -1849,9 +1426,10 @@
 #ifdef CONFIG_BLK_DEV_IDEPCI
 		} else {
 			/*
-			 * Whack the status register, just in case we have a leftover pending IRQ.
+			 * 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(&io_request_lock, flags);
@@ -1860,16 +1438,18 @@
 	drive = hwgroup->drive;
 	if (!drive) {
 		/*
-		 * This should NEVER happen, and there isn't much we could do about it here.
+		 * This should NEVER happen, and there isn't much
+		 * we could do about it here.
 		 */
 		spin_unlock_irqrestore(&io_request_lock, flags);
 		return;
 	}
 	if (!drive_is_ready(drive)) {
 		/*
-		 * This happens regularly when we share a PCI IRQ with another device.
-		 * Unfortunately, it can also happen with some buggy drives that trigger
-		 * the IRQ before their status register is up to date.  Hopefully we have
+		 * This happens regularly when we share a PCI IRQ with
+		 * another device.  Unfortunately, it can also happen
+		 * with some buggy drives that trigger the IRQ before
+		 * their status register is up to date.  Hopefully we have
 		 * enough advance overhead that the latter isn't a problem.
 		 */
 		spin_unlock_irqrestore(&io_request_lock, flags);
@@ -1877,15 +1457,17 @@
 	}
 	if (!hwgroup->busy) {
 		hwgroup->busy = 1;	/* paranoia */
-		printk("%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name);
+		printk(KERN_ERR "%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name);
 	}
 	hwgroup->handler = NULL;
 	del_timer(&hwgroup->timer);
 	spin_unlock(&io_request_lock);
 
 	if (drive->unmask)
-		ide__sti();	/* local CPU only */
-	startstop = handler(drive);		/* service this interrupt, may set handler for next interrupt */
+		local_irq_enable();
+
+	/* service this interrupt, may set handler for next interrupt */
+	startstop = handler(drive);
 	spin_lock_irq(&io_request_lock);
 
 	/*
@@ -1902,12 +1484,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(KERN_ERR "%s: ide_intr: huh? expected NULL handler "
+				"on exit\n", drive->name);
 		}
 	}
 	spin_unlock_irqrestore(&io_request_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.
@@ -1915,9 +1500,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) {
@@ -1926,11 +1508,7 @@
 			unsigned unit = DEVICE_NR(i_rdev);
 			if (unit < MAX_DRIVES) {
 				ide_drive_t *drive = &hwif->drives[unit];
-#if 0
-				if ((drive->present) && (drive->part[minor].nr_sects))
-#else
 				if (drive->present)
-#endif
 					return drive;
 			}
 			break;
@@ -1939,6 +1517,8 @@
 	return NULL;
 }
 
+EXPORT_SYMBOL(get_info_ptr);
+
 /*
  * This function is intended to be used prior to invoking ide_do_drive_cmd().
  */
@@ -1948,6 +1528,8 @@
 	rq->cmd = IDE_DRIVE_CMD;
 }
 
+EXPORT_SYMBOL(ide_init_drive_cmd);
+
 /*
  * This function issues a special IDE device request
  * onto the request queue.
@@ -1978,7 +1560,8 @@
 	unsigned long flags;
 	ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	unsigned int major = HWIF(drive)->major;
-	struct list_head *queue_head = &drive->queue.queue_head;
+	request_queue_t *q = &drive->queue;
+	struct list_head *queue_head = &q->queue_head;
 	DECLARE_COMPLETION(wait);
 
 #ifdef CONFIG_BLK_DEV_PDC4030
@@ -1991,7 +1574,7 @@
 	if (action == ide_wait)
 		rq->waiting = &wait;
 	spin_lock_irqsave(&io_request_lock, flags);
-	if (list_empty(queue_head) || action == ide_preempt) {
+	if (blk_queue_empty(q) || action == ide_preempt) {
 		if (action == ide_preempt)
 			hwgroup->rq = NULL;
 	} else {
@@ -2004,13 +1587,17 @@
 	ide_do_request(hwgroup, 0);
 	spin_unlock_irqrestore(&io_request_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);
+
 /*
  * This routine is called to flush all partitions and partition tables
  * for a changed disk, and then re-read the new partition table.
@@ -2058,7 +1645,9 @@
 	return 0;
 }
 
-static void revalidate_drives (void)
+EXPORT_SYMBOL(ide_revalidate_disk);
+
+static void revalidate_drives (int revaldiate)
 {
 	ide_hwif_t *hwif;
 	ide_drive_t *drive;
@@ -2070,26 +1659,28 @@
 			drive = &ide_hwifs[index].drives[unit];
 			if (drive->revalidate) {
 				drive->revalidate = 0;
-				if (!initializing)
+				if ((!initializing) && (revaldiate))
 					(void) ide_revalidate_disk(MKDEV(hwif->major, unit<<PARTN_BITS));
 			}
 		}
 	}
 }
 
-static void ide_probe_module (void)
+void ide_probe_module (int revaldiate)
 {
 	if (!ide_probe) {
-#if defined(CONFIG_KMOD) && defined(CONFIG_BLK_DEV_IDE_MODULE)
+#if  defined(CONFIG_BLK_DEV_IDE_MODULE)
 		(void) request_module("ide-probe-mod");
-#endif /* (CONFIG_KMOD) && (CONFIG_BLK_DEV_IDE_MODULE) */
+#endif
 	} else {
 		(void) ide_probe->init();
 	}
-	revalidate_drives();
+	revalidate_drives(revaldiate);
 }
 
-static void ide_driver_module (void)
+EXPORT_SYMBOL(ide_probe_module);
+
+void ide_driver_module (int revaldiate)
 {
 	int index;
 	ide_module_t *module = ide_modules;
@@ -2097,15 +1688,17 @@
 	for (index = 0; index < MAX_HWIFS; ++index)
 		if (ide_hwifs[index].present)
 			goto search;
-	ide_probe_module();
+	ide_probe_module(revaldiate);
 search:
 	while (module) {
 		(void) module->init();
 		module = module->next;
 	}
-	revalidate_drives();
+	revalidate_drives(revaldiate);
 }
 
+EXPORT_SYMBOL(ide_driver_module);
+
 static int ide_open (struct inode * inode, struct file * filp)
 {
 	ide_drive_t *drive;
@@ -2113,29 +1706,28 @@
 	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
 		return -ENXIO;
 	if (drive->driver == NULL)
-		ide_driver_module();
-#ifdef CONFIG_KMOD
+		ide_driver_module(1);
 	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 */
+	
+	/* The locking here isnt enough, but this is hard to fix
+	   in the 2.4 cases */
 	while (drive->busy)
 		sleep_on(&drive->wqueue);
 	drive->usage++;
-	if (drive->driver != NULL)
+	if (drive->driver != NULL && !drive->dead)
 		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;
 }
@@ -2156,22 +1748,6 @@
 	return 0;
 }
 
-int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
-{
-	if (!drive->present || drive->busy || drive->usage)
-		goto abort;
-	if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
-		goto abort;
-	strncpy(drive->driver_req, driver, 9);
-	ide_driver_module();
-	drive->driver_req[0] = 0;
-	ide_driver_module();
-	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 },
@@ -2179,6 +1755,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
@@ -2186,36 +1766,33 @@
  */
 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);
+		}
+	}
 }
 
-void ide_unregister (unsigned int index)
+EXPORT_SYMBOL(hwif_unregister);
+
+extern void init_hwif_data(unsigned int index);
+
+int ide_unregister (unsigned int index)
 {
 	struct gendisk *gd;
 	ide_drive_t *drive, *d;
@@ -2227,9 +1804,9 @@
 	ide_hwif_t old_hwif;
 
 	if (index >= MAX_HWIFS)
-		return;
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
+		BUG();
+		
+	spin_lock_irqsave(&io_request_lock, flags);
 	hwif = &ide_hwifs[index];
 	if (!hwif->present)
 		goto abort;
@@ -2239,7 +1816,7 @@
 			continue;
 		if (drive->busy || drive->usage)
 			goto abort;
-		if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+		if (drive->driver != NULL && DRIVER(drive)->shutdown(drive))
 			goto abort;
 	}
 	hwif->present = 0;
@@ -2247,11 +1824,13 @@
 	/*
 	 * All clear?  Then blow away the buffer cache
 	 */
-	sti();
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		drive = &hwif->drives[unit];
 		if (!drive->present)
 			continue;
+		if (drive->driver != NULL)
+			DRIVER(drive)->cleanup(drive);
 		minor = drive->select.b.unit << PARTN_BITS;
 		for (p = 0; p < (1<<PARTN_BITS); ++p) {
 			if (drive->part[p].nr_sects > 0) {
@@ -2263,7 +1842,8 @@
 		destroy_proc_ide_drives(hwif);
 #endif
 	}
-	cli();
+
+	spin_lock_irqsave(&io_request_lock, flags);
 	hwgroup = hwif->hwgroup;
 
 	/*
@@ -2293,7 +1873,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)
@@ -2323,7 +1903,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) */
 
@@ -2343,49 +1930,136 @@
 		kfree(gd->sizes);
 		kfree(gd->part);
 		if (gd->de_arr)
-			kfree (gd->de_arr);
+			kfree(gd->de_arr);
 		if (gd->flags)
-			kfree (gd->flags);
+			kfree(gd->flags);
 		kfree(gd);
 		hwif->gd = NULL;
 	}
-	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->OUTSW		= old_hwif.OUTSW;
+	hwif->OUTSL		= old_hwif.OUTSL;
+
+	hwif->INB		= old_hwif.INB;
+	hwif->INW		= old_hwif.INW;
+	hwif->INL		= old_hwif.INL;
+	hwif->INSW		= old_hwif.INSW;
+	hwif->INSL		= old_hwif.INSL;
+#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;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return 0;
+
 abort:
-	restore_flags(flags);	/* all CPUs */
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return 1;
+	
 }
 
+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
@@ -2394,7 +2068,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;
 
@@ -2420,8 +2098,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.
@@ -2459,11 +2142,11 @@
 	hwif->chipset = hw->chipset;
 
 	if (!initializing) {
-		ide_probe_module();
+		ide_probe_module(1);
 #ifdef CONFIG_PROC_FS
 		create_proc_ide_interfaces();
 #endif
-		ide_driver_module();
+		ide_driver_module(1);
 	}
 
 	if (hwifp)
@@ -2472,6 +2155,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.
@@ -2484,6 +2169,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;
@@ -2495,12 +2182,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;
@@ -2510,6 +2203,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;
@@ -2523,6 +2218,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;
@@ -2595,19 +2292,20 @@
 	while (hwgroup->busy) {
 		unsigned long lflags;
 		spin_unlock_irq(&io_request_lock);
-		__save_flags(lflags);	/* local CPU only */
-		__sti();		/* local CPU only; needed for jiffies */
-		if (0 < (signed long)(jiffies - timeout)) {
-			__restore_flags(lflags);	/* local CPU only */
-			printk("%s: channel busy\n", drive->name);
+		local_irq_set(lflags);
+		if (time_after(jiffies, timeout)) {
+			local_irq_restore(lflags);
+			printk(KERN_ERR "%s: channel busy\n", drive->name);
 			return -EBUSY;
 		}
-		__restore_flags(lflags);	/* local CPU only */
+		local_irq_restore(lflags);
 		spin_lock_irq(&io_request_lock);
 	}
 	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.
@@ -2648,6 +2346,8 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_write_setting);
+
 static int set_io_32bit(ide_drive_t *drive, int arg)
 {
 	drive->io_32bit = arg;
@@ -2662,10 +2362,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)->ide_dma_check == NULL)
 		return -EPERM;
-	if (HWIF(drive)->dmaproc(arg ? ide_dma_on : ide_dma_off, drive))
-		return -EIO;
+	if (arg) {
+		if (HWIF(drive)->ide_dma_on(drive)) return -EIO;
+	} else {
+		if (HWIF(drive)->ide_dma_off(drive)) return -EIO;
+	}
 	return 0;
 }
 
@@ -2678,55 +2383,60 @@
 	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;
 }
 
-void ide_add_generic_settings (ide_drive_t *drive)
+static int set_xfer_rate (ide_drive_t *drive, int arg)
 {
-/*
- *			drive	setting name		read/write access				read ioctl		write ioctl		data type	min	max				mul_factor	div_factor	data pointer			set function
- */
-	ide_add_setting(drive,	"io_32bit",		drive->no_io_32bit ? SETTING_READ : SETTING_RW,	HDIO_GET_32BIT,		HDIO_SET_32BIT,		TYPE_BYTE,	0,	1 + (SUPPORT_VLB_SYNC << 1),	1,		1,		&drive->io_32bit,		set_io_32bit);
-	ide_add_setting(drive,	"keepsettings",		SETTING_RW,					HDIO_GET_KEEPSETTINGS,	HDIO_SET_KEEPSETTINGS,	TYPE_BYTE,	0,	1,				1,		1,		&drive->keep_settings,		NULL);
-	ide_add_setting(drive,	"nice1",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->nice1,			NULL);
-	ide_add_setting(drive,	"pio_mode",		SETTING_WRITE,					-1,			HDIO_SET_PIO_MODE,	TYPE_BYTE,	0,	255,				1,		1,		NULL,				set_pio_mode);
-	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,	69,				1,		1,		&drive->init_speed,		NULL);
-	ide_add_setting(drive,	"current_speed",	SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	69,				1,		1,		&drive->current_speed,		NULL);
-	ide_add_setting(drive,	"number",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	3,				1,		1,		&drive->dn,			NULL);
+	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_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf)
+int ide_atapi_to_scsi (ide_drive_t *drive, int arg)
 {
-	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);
+	if (drive->media == ide_disk) {
+		drive->scsi = 0;
+		return 0;
+	}
+	if (drive->driver != NULL) {
+		if (DRIVER(drive)->cleanup(drive)) {
+			drive->scsi = 0;
+			return 0;
+		}
+	}
+	drive->scsi = (u8) arg;
+	ide_attach_drive(drive);
+	return 0;
 }
 
-int ide_wait_cmd_task (ide_drive_t *drive, byte *buf)
+void ide_add_generic_settings (ide_drive_t *drive)
 {
-	struct request rq;
-
-	ide_init_drive_cmd(&rq);
-	rq.cmd = IDE_DRIVE_TASK;
-	rq.buffer = buf;
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
+/*
+ *			drive	setting name		read/write access				read ioctl		write ioctl		data type	min	max				mul_factor	div_factor	data pointer			set function
+ */
+	ide_add_setting(drive,	"io_32bit",		drive->no_io_32bit ? SETTING_READ : SETTING_RW,	HDIO_GET_32BIT,		HDIO_SET_32BIT,		TYPE_BYTE,	0,	1 + (SUPPORT_VLB_SYNC << 1),	1,		1,		&drive->io_32bit,		set_io_32bit);
+	ide_add_setting(drive,	"keepsettings",		SETTING_RW,					HDIO_GET_KEEPSETTINGS,	HDIO_SET_KEEPSETTINGS,	TYPE_BYTE,	0,	1,				1,		1,		&drive->keep_settings,		NULL);
+	ide_add_setting(drive,	"nice1",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,		1,		&drive->nice1,			NULL);
+	ide_add_setting(drive,	"pio_mode",		SETTING_WRITE,					-1,			HDIO_SET_PIO_MODE,	TYPE_BYTE,	0,	255,				1,		1,		NULL,				set_pio_mode);
+	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,	"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,		set_xfer_rate);
+	ide_add_setting(drive,	"number",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	3,				1,		1,		&drive->dn,			NULL);
+	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);
 }
 
 /*
@@ -2747,19 +2457,53 @@
 #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 ));
 }
 
-int ide_reinit_drive (ide_drive_t *drive)
+EXPORT_SYMBOL(system_bus_clock);
+
+int ide_replace_subdriver (ide_drive_t *drive, const char *driver)
+{
+	if (!drive->present || drive->busy || drive->usage || drive->dead)
+		goto abort;
+	if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+		goto abort;
+	strncpy(drive->driver_req, driver, 9);
+	ide_driver_module(0);
+	drive->driver_req[0] = 0;
+	ide_driver_module(0);
+	if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver))
+		return 0;
+abort:
+	return 1;
+}
+
+EXPORT_SYMBOL(ide_replace_subdriver);
+
+int ide_attach_drive (ide_drive_t *drive)
 {
+	/* Someone unplugged the device on us */
+	if(drive->dead)
+		return 1;
+		
+#ifdef CONFIG_BLK_DEV_IDESCSI
+	if (drive->scsi) {
+		extern int idescsi_attach(ide_drive_t *drive);
+		if (idescsi_attach(drive))
+			return 0;
+	}
+#endif /* CONFIG_BLK_DEV_IDESCSI */
+
 	switch (drive->media) {
 #ifdef CONFIG_BLK_DEV_IDECD
 		case ide_cdrom:
 		{
-			extern int ide_cdrom_reinit(ide_drive_t *drive);
-			if (ide_cdrom_reinit(drive))
+			extern int ide_cdrom_attach(ide_drive_t *drive);
+			if (ide_cdrom_attach(drive))
 				return 1;
 			break;
 		}
@@ -2767,8 +2511,8 @@
 #ifdef CONFIG_BLK_DEV_IDEDISK
 		case ide_disk:
 		{
-			extern int idedisk_reinit(ide_drive_t *drive);
-			if (idedisk_reinit(drive))
+			extern int idedisk_attach(ide_drive_t *drive);
+			if (idedisk_attach(drive))
 				return 1;
 			break;
 		}
@@ -2776,8 +2520,8 @@
 #ifdef CONFIG_BLK_DEV_IDEFLOPPY
 		case ide_floppy:
 		{
-			extern int idefloppy_reinit(ide_drive_t *drive);
-			if (idefloppy_reinit(drive))
+			extern int idefloppy_attach(ide_drive_t *drive);
+			if (idefloppy_attach(drive))
 				return 1;
 			break;
 		}
@@ -2785,28 +2529,20 @@
 #ifdef CONFIG_BLK_DEV_IDETAPE
 		case ide_tape:
 		{
-			extern int idetape_reinit(ide_drive_t *drive);
-			if (idetape_reinit(drive))
+			extern int idetape_attach(ide_drive_t *drive);
+			if (idetape_attach(drive))
 				return 1;
 			break;
 		}
 #endif /* CONFIG_BLK_DEV_IDETAPE */
-#ifdef CONFIG_BLK_DEV_IDESCSI
-/*
- *              {
- *                      extern int idescsi_reinit(ide_drive_t *drive);
- *                      if (idescsi_reinit(drive))
- *                              return 1;
- *                      break;
- * }
- */
-#endif /* CONFIG_BLK_DEV_IDESCSI */
 		default:
 			return 1;
 	}
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_attach_drive);
+
 static int ide_ioctl (struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
@@ -2838,11 +2574,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)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
 			return 0;
@@ -2852,8 +2588,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->bios_head, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(drive->bios_sect, (byte *) &loc->sectors)) 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(drive->bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
 			if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
@@ -2864,8 +2600,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)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
@@ -2918,68 +2654,15 @@
 #endif /* CONFIG_IDE_TASK_IOCTL */
 
 		case HDIO_DRIVE_CMD:
-		{
-			byte args[4], *argbuf = args;
-			byte xfer_rate = 0;
-			int argsize = 4;
-			ide_task_t tfargs;
-
 			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
 				return -EACCES;
-			if (NULL == (void *) arg)
-				return ide_do_drive_cmd(drive, &rq, ide_wait);
-			if (copy_from_user(args, (void *)arg, 4))
-				return -EFAULT;
+			return ide_cmd_ioctl(drive, inode, file, cmd, arg);
 
-			tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
-			tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
-			tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
-			tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
-			tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
-			tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
-			tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
-
-			if (args[3]) {
-				argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
-				argbuf = kmalloc(argsize, GFP_KERNEL);
-				if (argbuf == NULL)
-					return -ENOMEM;
-				memcpy(argbuf, args, 4);
-			}
-
-			if (set_transfer(drive, &tfargs)) {
-				xfer_rate = args[1];
-				if (ide_ata66_check(drive, &tfargs))
-					goto abort;
-			}
-
-			err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
-
-			if (!err && xfer_rate) {
-				/* active-retuning-calls future */
-				if ((HWIF(drive)->speedproc) != NULL)
-					HWIF(drive)->speedproc(drive, xfer_rate);
-				ide_driveid_update(drive);
-			}
-		abort:
-			if (copy_to_user((void *)arg, argbuf, argsize))
-				err = -EFAULT;
-			if (argsize > 4)
-				kfree(argbuf);
-			return err;
-		}
 		case HDIO_DRIVE_TASK:
-		{
-			byte args[7], *argbuf = args;
-			int argsize = 7;
-			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES;
-			if (copy_from_user(args, (void *)arg, 7))
-				return -EFAULT;
-			err = ide_wait_cmd_task(drive, argbuf);
-			if (copy_to_user((void *)arg, argbuf, argsize))
-				err = -EFAULT;
-			return err;
-		}
+			if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+				return -EACCES;
+			return ide_task_ioctl(drive, inode, file, cmd, arg);
+
 		case HDIO_SCAN_HWIF:
 		{
 			int args[3];
@@ -3011,18 +2694,15 @@
 		case HDIO_DRIVE_RESET:
 		{
 			unsigned long flags;
-			ide_hwgroup_t *hwgroup = HWGROUP(drive);
-
 			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
 #if 1
 			spin_lock_irqsave(&io_request_lock, flags);
-			if (hwgroup->handler != NULL) {
-				printk("%s: ide_set_handler: handler not null; %p\n", drive->name, hwgroup->handler);
-				(void) hwgroup->handler(drive);
-//				hwgroup->handler = NULL;
-//				hwgroup->expiry	= NULL;
-				hwgroup->timer.expires = jiffies + 0;;
-				del_timer(&hwgroup->timer);
+			if ( HWGROUP(drive)->handler != NULL) {
+				printk(KERN_ERR "%s: ide_set_handler: handler not null; %p\n", drive->name, HWGROUP(drive)->handler);
+				(void) HWGROUP(drive)->handler(drive);
+//				HWGROUP(drive)->handler = NULL;
+				HWGROUP(drive)->expiry	= NULL;
+				del_timer(&HWGROUP(drive)->timer);
 			}
 			spin_unlock_irqrestore(&io_request_lock, flags);
 
@@ -3085,33 +2765,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.
@@ -3274,7 +2927,7 @@
 	    strncmp(s,"hd",2))		/* hdx= & hdxlun= */
 		return 0;
 
-	printk("ide_setup: %s", s);
+	printk(KERN_INFO "ide_setup: %s", s);
 	init_ide_data ();
 
 #ifdef CONFIG_BLK_DEV_IDEDOUBLER
@@ -3288,7 +2941,7 @@
 #endif /* CONFIG_BLK_DEV_IDEDOUBLER */
 
 	if (!strcmp(s, "ide=nodma")) {
-		printk("IDE: Prevented DMA\n");
+		printk(" : Prevented DMA\n");
 		noautodma = 1;
 		return 1;
 	}
@@ -3418,7 +3071,7 @@
 		const char *ide_words[] = {
 			"noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66",
 			"minus8", "minus9", "minus10",
-			"four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", "nohighio", NULL };
+			"four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL };
 		hw = s[3] - '0';
 		hwif = &ide_hwifs[hw];
 		i = match_parm(&s[4], ide_words, vals, 3);
@@ -3437,10 +3090,6 @@
 		}
 
 		switch (i) {
-			case -19: /* nohighio */
-				hwif->no_highio = 1;
-				printk("%s: disabled high i/o capability\n", hwif->name);
-				goto done;
 #ifdef CONFIG_BLK_DEV_PDC4030
 			case -18: /* "dc4030" */
 			{
@@ -3580,21 +3229,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);
-#else
-#ifdef CONFIG_BLK_DEV_RZ1000
-		{
-			extern void ide_probe_for_rz100x(void);
-			ide_probe_for_rz100x();
-		}
-#endif /* CONFIG_BLK_DEV_RZ1000 */
-#endif /* CONFIG_BLK_DEV_IDEPCI */
 	}
-#endif /* CONFIG_PCI */
+#endif /* CONFIG_BLK_DEV_IDEPCI */
 
 #ifdef CONFIG_ETRAX_IDE
 	{
@@ -3676,39 +3316,8 @@
 #endif /* CONFIG_BLK_DEV_ISAPNP */
 }
 
-void __init ide_init_builtin_drivers (void)
+void __init ide_init_builtin_subdrivers (void)
 {
-	/*
-	 * Probe for special PCI and other "known" interface chipsets
-	 */
-	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_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 */
-
-	(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 */
-#endif /* CONFIG_BLK_DEV_IDE */
-
-#ifdef CONFIG_PROC_FS
-	proc_ide_create();
-#endif
-
-	/*
-	 * Attempt to match drivers for the available drives
-	 */
 #ifdef CONFIG_BLK_DEV_IDEDISK
 	(void) idedisk_init();
 #endif /* CONFIG_BLK_DEV_IDEDISK */
@@ -3730,32 +3339,131 @@
 #endif /* CONFIG_BLK_DEV_IDESCSI */
 }
 
+#ifndef CLASSIC_BUILTINS_METHOD
+#  ifndef DIRECT_HWIF_PROBE_ATTACH_METHOD
+#    ifdef FAKE_CLASSIC_ATTACH_METHOD
+/*
+ * Attempt to match drivers for the available drives
+ */
+void ide_attach_devices (void)
+{
+	ide_hwif_t *hwif;
+	ide_drive_t *drive;
+	int i, unit;
+
+	for (i = 0; i < MAX_HWIFS; i++) {
+		hwif = &ide_hwifs[i];
+		if (!hwif->present)
+			continue;
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			drive = &hwif->drives[unit];
+			if (drive->present && !drive->dead)
+				ide_attach_drive(drive);
+		}
+	}
+}
+#    endif /* FAKE_CLASSIC_ATTACH_METHOD */
+#  endif /* DIRECT_HWIF_PROBE_ATTACH_METHOD */
+#endif /* CLASSIC_BUILTINS_METHOD */
+
+void __init ide_init_builtin_drivers (void)
+{
+	/*
+	 * Probe for special PCI and other "known" interface chipsets
+	 */
+	probe_for_hwifs ();
+
+#ifdef CONFIG_BLK_DEV_IDE
+	if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET])
+		ide_get_lock(&ide_intr_lock, NULL, NULL); /* for atari only */
+
+	(void) ideprobe_init();
+
+	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
+	proc_ide_create();
+#endif
+
+#ifdef CLASSIC_BUILTINS_METHOD
+	ide_init_builtin_subdrivers();
+#else /* ! CLASSIC_BUILTINS_METHOD */
+#  ifndef DIRECT_HWIF_PROBE_ATTACH_METHOD
+#    ifdef FAKE_CLASSIC_ATTACH_METHOD
+	ide_attach_devices();
+#    endif /* FAKE_CLASSIC_ATTACH_METHOD */
+#  endif /* DIRECT_HWIF_PROBE_ATTACH_METHOD */
+#endif /* CLASSIC_BUILTINS_METHOD */
+}
+
+/*
+ *	Actually unregister the subdriver. Called with the
+ *	request lock dropped.
+ */
+ 
 static int default_cleanup (ide_drive_t *drive)
 {
 	return ide_unregister_subdriver(drive);
 }
 
+/*
+ *	Check if we can unregister the subdriver. Called with the
+ *	request lock held.
+ */
+ 
+static int default_shutdown(ide_drive_t *drive)
+{
+	if (drive->usage || drive->busy ||
+	    drive->driver == NULL || DRIVER(drive)->busy) {
+		return 1;
+	}
+	drive->dead = 1;
+	return 0;
+}
+
 static int default_standby (ide_drive_t *drive)
 {
 	return 0;
 }
 
+static int default_suspend (ide_drive_t *drive)
+{
+	return 0;
+}
+
+static int default_resume (ide_drive_t *drive)
+{
+	return 0;
+}
+
 static int default_flushcache (ide_drive_t *drive)
 {
 	return 0;
 }
 
-static ide_startstop_t default_do_request(ide_drive_t *drive, struct request *rq, unsigned long block)
+static ide_startstop_t default_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	ide_end_request(0, HWGROUP(drive));
+	ide_end_request(drive, 0);
 	return ide_stopped;
 }
- 
-static void default_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
+
+static int default_end_request (ide_drive_t *drive, int uptodate)
+{
+	return ide_end_request(drive, uptodate);
+}
+
+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, u8 stat)
 {
-	ide_end_request(uptodate, hwgroup);
+	return ide_error(drive, msg, stat);
 }
-  
+
 static int default_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file,
 			  unsigned int cmd, unsigned long arg)
 {
@@ -3795,9 +3503,15 @@
 	return ide_stopped;
 }
 
-static int default_reinit (ide_drive_t *drive)
+static int default_init (void)
+{
+	return 0;
+}
+
+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;
 }
@@ -3807,10 +3521,15 @@
 	ide_driver_t *d = drive->driver;
 
 	if (d->cleanup == NULL)		d->cleanup = default_cleanup;
+	if (d->shutdown == NULL)	d->shutdown = default_shutdown;
 	if (d->standby == NULL)		d->standby = default_standby;
+	if (d->suspend == NULL)		d->suspend = default_suspend;
+	if (d->resume == NULL)		d->resume = default_resume;
 	if (d->flushcache == NULL)	d->flushcache = default_flushcache;
 	if (d->do_request == NULL)	d->do_request = default_do_request;
 	if (d->end_request == NULL)	d->end_request = default_end_request;
+	if (d->sense == NULL)		d->sense = default_sense;
+	if (d->error == NULL)		d->error = default_error;
 	if (d->ioctl == NULL)		d->ioctl = default_ioctl;
 	if (d->open == NULL)		d->open = default_open;
 	if (d->release == NULL)		d->release = default_release;
@@ -3818,10 +3537,11 @@
 	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->init == NULL)		d->init = default_init;
+	if (d->attach == NULL)		d->attach = default_attach;
 }
 
-ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n)
+ide_drive_t *ide_scan_devices (u8 media, const char *name, ide_driver_t *driver, int n)
 {
 	unsigned int unit, index, i;
 
@@ -3834,37 +3554,34 @@
 			char *req = drive->driver_req;
 			if (*req && !strstr(name, req))
 				continue;
-			if (drive->present && drive->media == media && drive->driver == driver && ++i > n)
+			if (drive->present && drive->media == media &&
+			    drive->driver == driver && ++i > n)
 				return drive;
 		}
 	}
 	return NULL;
 }
 
+EXPORT_SYMBOL(ide_scan_devices);
+
 int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version)
 {
 	unsigned long flags;
 	
-	save_flags(flags);		/* all CPUs */
-	cli();				/* all CPUs */
-	if (version != IDE_SUBDRIVER_VERSION || !drive->present || drive->driver != NULL || drive->busy || drive->usage) {
-		restore_flags(flags);	/* all CPUs */
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (version != IDE_SUBDRIVER_VERSION || !drive->present ||
+	    drive->driver != NULL || drive->busy || drive->usage) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return 1;
 	}
 	drive->driver = driver;
 	setup_driver_defaults(drive);
-	restore_flags(flags);		/* all CPUs */
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	if (drive->autotune != 2) {
-		if (driver->supports_dma && HWIF(drive)->dmaproc != NULL) {
-			/*
-			 * Force DMAing for the beginning of the check.
-			 * Some chipsets appear to do interesting things,
-			 * if not checked and cleared.
-			 *   PARANOIA!!!
-			 */
-			(void) (HWIF(drive)->dmaproc(ide_dma_off_quietly, drive));
-			(void) (HWIF(drive)->dmaproc(ide_dma_check, 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;
 	}
@@ -3877,14 +3594,16 @@
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_register_subdriver);
+
 int ide_unregister_subdriver (ide_drive_t *drive)
 {
 	unsigned long flags;
 	
-	save_flags(flags);		/* all CPUs */
-	cli();				/* all CPUs */
-	if (drive->usage || drive->busy || drive->driver == NULL || DRIVER(drive)->busy) {
-		restore_flags(flags);	/* all CPUs */
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (drive->usage || drive->busy ||
+	    drive->driver == NULL || DRIVER(drive)->busy) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return 1;
 	}
 #if defined(CONFIG_BLK_DEV_ISAPNP) && defined(CONFIG_ISAPNP) && defined(MODULE)
@@ -3896,10 +3615,12 @@
 #endif
 	auto_remove_settings(drive);
 	drive->driver = NULL;
-	restore_flags(flags);		/* all CPUs */
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_unregister_subdriver);
+
 int ide_register_module (ide_module_t *module)
 {
 	ide_module_t *p = ide_modules;
@@ -3911,10 +3632,12 @@
 	}
 	module->next = ide_modules;
 	ide_modules = module;
-	revalidate_drives();
+	revalidate_drives(1);
 	return 0;
 }
 
+EXPORT_SYMBOL(ide_register_module);
+
 void ide_unregister_module (ide_module_t *module)
 {
 	ide_module_t **p;
@@ -3924,6 +3647,8 @@
 		*p = (*p)->next;
 }
 
+EXPORT_SYMBOL(ide_unregister_module);
+
 struct block_device_operations ide_fops[] = {{
 	owner:			THIS_MODULE,
 	open:			ide_open,
@@ -3933,10 +3658,34 @@
 	revalidate:		ide_revalidate_disk
 }};
 
-EXPORT_SYMBOL(ide_hwifs);
-EXPORT_SYMBOL(ide_register_module);
-EXPORT_SYMBOL(ide_unregister_module);
-EXPORT_SYMBOL(ide_spin_wait_hwgroup);
+EXPORT_SYMBOL(ide_fops);
+
+/*
+ * ide_geninit() is called exactly *once* for each interface.
+ */
+void ide_geninit (ide_hwif_t *hwif)
+{
+	unsigned int unit;
+	struct gendisk *gd = hwif->gd;
+
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		ide_drive_t *drive = &hwif->drives[unit];
+
+		if (!drive->present)
+			continue;
+		if (drive->media!=ide_disk && drive->media!=ide_floppy)
+			continue;
+		register_disk(gd,MKDEV(hwif->major,unit<<PARTN_BITS),
+#ifdef CONFIG_BLK_DEV_ISAPNP
+			(drive->forced_geom && drive->noprobe) ? 1 :
+#endif /* CONFIG_BLK_DEV_ISAPNP */
+			1<<PARTN_BITS, ide_fops,
+			current_capacity(drive));
+	}
+}
+
+EXPORT_SYMBOL(ide_geninit);
+
 
 /*
  * Probe module
@@ -3944,65 +3693,7 @@
 devfs_handle_t ide_devfs_handle;
 
 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_scan_devices);
-EXPORT_SYMBOL(ide_register_subdriver);
-EXPORT_SYMBOL(ide_unregister_subdriver);
-EXPORT_SYMBOL(ide_replace_subdriver);
-EXPORT_SYMBOL(ide_input_data);
-EXPORT_SYMBOL(ide_output_data);
-EXPORT_SYMBOL(atapi_input_bytes);
-EXPORT_SYMBOL(atapi_output_bytes);
-EXPORT_SYMBOL(drive_is_ready);
-EXPORT_SYMBOL(ide_set_handler);
-EXPORT_SYMBOL(ide_dump_status);
-EXPORT_SYMBOL(ide_error);
-EXPORT_SYMBOL(ide_fixstring);
-EXPORT_SYMBOL(ide_wait_stat);
-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_disk);
-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(ide_reinit_drive);
 
 static int ide_notify_reboot (struct notifier_block *this, unsigned long event, void *x)
 {
@@ -4019,7 +3710,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];
@@ -4036,8 +3727,11 @@
 				if (drive->driver != NULL && DRIVER(drive)->standby(drive))
 				continue;
 
-			if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))
+			if (drive->driver != NULL)
+			{
+				DRIVER(drive)->cleanup(drive);
 				continue;
+			}
 		}
 	}
 	printk("\n");
@@ -4060,12 +3754,16 @@
 
 	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();
+
+#ifndef CLASSIC_BUILTINS_METHOD
+	ide_init_builtin_subdrivers();
+#endif /* CLASSIC_BUILTINS_METHOD */
 
 	initializing = 1;
 	ide_init_builtin_drivers();
@@ -4128,5 +3826,6 @@
 #else /* !MODULE */
 
 __setup("", ide_setup);
+module_init(ide_init);
 
 #endif /* MODULE */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-cd.c linux.20pre10-ac2/drivers/ide/ide-cd.c
--- linux.20pre10/drivers/ide/ide-cd.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-cd.c	2002-09-29 21:30:31.000000000 +0100
@@ -540,7 +540,124 @@
 }
 
 
-static void cdrom_end_request (int uptodate, ide_drive_t *drive)
+/*
+ * 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(&io_request_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->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		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(&io_request_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;
+
+	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 (status.b.bsy)
+		printk("Busy ");
+	else {
+		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 ((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 error.all;
+}
+
+/*
+ * ide_error() takes action based on the error returned by the drive.
+ */
+ide_startstop_t ide_cdrom_error (ide_drive_t *drive, const char *msg, byte stat)
+{
+	struct request *rq;
+	byte err;
+
+	err = ide_cdrom_dump_status(drive, msg, stat);
+	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)
+		return ide_stopped;
+	/* retry only "normal" I/O: */
+	if (rq->cmd == IDE_DRIVE_CMD || rq->cmd == IDE_DRIVE_TASK) {
+		rq->errors = 1;
+		ide_end_drive_cmd(drive, stat, err);
+		return ide_stopped;
+	}
+
+	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 (HWIF(drive)->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
+		/* force an abort */
+		HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
+	if (rq->errors >= ERROR_MAX) {
+		DRIVER(drive)->end_request(drive, 0);
+	} else {
+		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+			++rq->errors;
+			return ide_do_reset(drive);
+		}
+		++rq->errors;
+	}
+	return ide_stopped;
+}
+
+static void cdrom_end_request (ide_drive_t *drive, int uptodate)
 {
 	struct request *rq = HWGROUP(drive)->rq;
 
@@ -550,11 +667,10 @@
 			(struct packet_command *) pc->sense,
 			(struct request_sense *) (pc->buffer - pc->c[4]));
 	}
-	if (rq->cmd == READ || rq->cmd == WRITE)
-		if (!rq->current_nr_sectors)
-			uptodate = 1;
+	if (blk_fs_request(rq) && !rq->current_nr_sectors)
+		uptodate = 1;
 
-	ide_end_request (uptodate, HWGROUP(drive));
+	ide_cdrom_end_request(drive, uptodate);
 }
 
 
@@ -568,14 +684,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) {
@@ -591,8 +706,8 @@
 
 		pc = (struct packet_command *) rq->buffer;
 		pc->stat = 1;
-		cdrom_end_request (1, drive);
-		*startstop = ide_error (drive, "request sense failure", stat);
+		cdrom_end_request(drive, 1);
+		*startstop = DRIVER(drive)->error(drive, "request sense failure", stat);
 		return 1;
 
 	} else if (rq->cmd == PACKET_COMMAND) {
@@ -628,11 +743,11 @@
 		}
 
 		pc->stat = 1;
-		cdrom_end_request (1, drive);
+		cdrom_end_request(drive, 1);
 
 		if ((stat & ERR_STAT) != 0)
 			cdrom_queue_request_sense(drive, wait, pc->sense, pc);
-	} else {
+	} else if (blk_fs_request(rq)) {
 		/* Handle errors from READ and WRITE requests. */
 
 		if (sense_key == NOT_READY) {
@@ -641,7 +756,7 @@
 
 			/* Fail the request. */
 			printk ("%s: tray open\n", drive->name);
-			cdrom_end_request (0, drive);
+			cdrom_end_request(drive, 0);
 		} else if (sense_key == UNIT_ATTENTION) {
 			/* Media change. */
 			cdrom_saw_media_change (drive);
@@ -650,21 +765,26 @@
 			   But be sure to give up if we've retried
 			   too many times. */
 			if (++rq->errors > ERROR_MAX)
-				cdrom_end_request (0, drive);
+				cdrom_end_request(drive, 0);
 		} else if (sense_key == ILLEGAL_REQUEST ||
 			   sense_key == DATA_PROTECT) {
 			/* No point in retrying after an illegal
 			   request or data protect error.*/
 			ide_dump_status (drive, "command error", stat);
-			cdrom_end_request (0, drive);
+			cdrom_end_request(drive, 0);
 		} else if ((err & ~ABRT_ERR) != 0) {
 			/* Go to the default handler
 			   for other errors. */
-			*startstop = ide_error (drive, "cdrom_decode_status", stat);
+			*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 (0, drive);
+			cdrom_end_request(drive, 0);
 		}
 
 		/* If we got a CHECK_CONDITION status,
@@ -723,33 +843,34 @@
 
 	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));
-
 	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+		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);
 	}
 }
@@ -770,27 +891,37 @@
 	unsigned char *cmd_buf	= pc->c;
 	int cmd_len		= sizeof(pc->c);
 	unsigned int timeout	= pc->timeout;
+	struct cdrom_info *info = drive->driver_data;
 	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;
 	}
 
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		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);
+
+	/* Start the DMA if need be */
+	if (info->dma)
+		(void) HWIF(drive)->ide_dma_begin(drive);
+
 	return ide_started;
 }
 
@@ -828,7 +959,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;
@@ -838,7 +969,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;
 	}
 }
@@ -864,14 +995,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... */
@@ -879,7 +1010,7 @@
 			drive->name, ireason);
 	}
 
-	cdrom_end_request (0, drive);
+	cdrom_end_request(drive, 0);
 	return -1;
 }
 
@@ -891,6 +1022,7 @@
 	int stat;
 	int ireason, len, sectors_to_transfer, nskip;
 	struct cdrom_info *info = drive->driver_data;
+	u8 lowcyl = 0, highcyl = 0;
 	int i, dma = info->dma, dma_error = 0;
 	ide_startstop_t startstop;
 
@@ -899,8 +1031,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))
@@ -910,16 +1042,19 @@
 		if (!dma_error) {
 			for (i = rq->nr_sectors; i > 0;) {
 				i -= rq->current_nr_sectors;
-				ide_end_request(1, HWGROUP(drive));
+				ide_cdrom_end_request(drive, 1);
 			}
 			return ide_stopped;
 		} else
-			return ide_error (drive, "dma error", stat);
+			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) {
@@ -928,9 +1063,9 @@
 		if (rq->current_nr_sectors > 0) {
 			printk ("%s: cdrom_read_intr: data underrun (%ld blocks)\n",
 				drive->name, rq->current_nr_sectors);
-			cdrom_end_request (0, drive);
+			cdrom_end_request(drive, 0);
 		} else
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 		return ide_stopped;
 	}
 
@@ -944,13 +1079,13 @@
 	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 (0, drive);
+		cdrom_end_request(drive, 0);
 		return ide_stopped;
 	}
 
@@ -965,7 +1100,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;
@@ -979,7 +1114,7 @@
 		/* If we've filled the present buffer but there's another
 		   chained buffer after it, move on. */
 		if (rq->current_nr_sectors == 0 && rq->nr_sectors)
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 
 		/* If the buffers are full, cache the rest of the data in our
 		   internal buffer. */
@@ -996,7 +1131,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;
@@ -1007,8 +1142,10 @@
 		}
 	}
 
-	/* Done moving data!
-	   Wait for another interrupt. */
+	if (HWGROUP(drive)->handler != NULL)    /* paranoia check */
+		BUG();
+
+	/* Done moving data!  Wait for another interrupt. */
 	ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL);
 	return ide_started;
 }
@@ -1031,7 +1168,7 @@
 	       rq->sector >= info->sector_buffered &&
 	       rq->sector < info->sector_buffered + info->nsectors_buffered) {
 		if (rq->current_nr_sectors == 0)
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 
 		memcpy (rq->buffer,
 			info->buffer +
@@ -1046,13 +1183,13 @@
 	/* If we've satisfied the current request,
 	   terminate it successfully. */
 	if (rq->nr_sectors == 0) {
-		cdrom_end_request (1, drive);
+		cdrom_end_request(drive, 1);
 		return -1;
 	}
 
 	/* Move on to the next buffer if needed. */
 	if (rq->current_nr_sectors == 0)
-		cdrom_end_request (1, drive);
+		cdrom_end_request(drive, 1);
 
 	/* If this condition does not hold, then the kluge i use to
 	   represent the number of sectors to skip at the start of a transfer
@@ -1060,9 +1197,9 @@
 	   paranoid and check. */
 	if (rq->current_nr_sectors < (rq->bh->b_size >> SECTOR_BITS) &&
 	    (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 (0, drive);
+		cdrom_end_request(drive, 0);
 		return -1;
 	}
 
@@ -1101,7 +1238,7 @@
 			(rq->sector % CD_FRAMESIZE != 0)) {
 			printk ("%s: cdrom_start_read_continuation: buffer botch (%lu)\n",
 				drive->name, rq->current_nr_sectors);
-			cdrom_end_request (0, drive);
+			cdrom_end_request(drive, 0);
 			return ide_stopped;
 		}
 		sector -= nskip;
@@ -1147,7 +1284,7 @@
 		return startstop;
 	CDROM_CONFIG_FLAGS(drive)->seeking = 1;
 
-	if (retry && jiffies - info->start_seek > IDECD_SEEK_TIMER) {
+	if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) {
 		if (--retry == 0) {
 			/*
 			 * this condition is far too common, to bother
@@ -1189,7 +1326,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);
 }
 
 static inline int cdrom_merge_requests(struct request *rq, struct request *nxt)
@@ -1263,7 +1400,7 @@
 {
 	struct cdrom_info *info = drive->driver_data;
 	struct request *rq = HWGROUP(drive)->rq;
-	int minor = MINOR (rq->rq_dev);
+	int minor = MINOR(rq->rq_dev);
 
 	/* If the request is relative to a partition, fix it up to refer to the
 	   absolute address.  */
@@ -1313,14 +1450,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. */
@@ -1337,7 +1478,7 @@
 		}
 
 		if (pc->buflen == 0)
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 		else {
 			/* Comment this out, because this always happens 
 			   right after a reset occurs, and it is annoying to 
@@ -1347,7 +1488,7 @@
 				drive->name, pc->buflen);
 			*/
 			pc->stat = 1;
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 		}
 		return ide_stopped;
 	}
@@ -1359,14 +1500,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. */
@@ -1378,14 +1519,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. */
@@ -1398,8 +1539,11 @@
 		pc->stat = 1;
 	}
 
+	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;
 }
 
@@ -1430,7 +1574,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);
 }
 
 
@@ -1462,7 +1606,7 @@
 		ide_init_drive_cmd (&req);
 		req.cmd = PACKET_COMMAND;
 		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) {
@@ -1472,7 +1616,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
@@ -1513,7 +1657,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 {
@@ -1522,7 +1666,7 @@
 			drive->name, ireason);
 	}
 
-	cdrom_end_request(0, drive);
+	cdrom_end_request(drive, 0);
 	return 1;
 }
 
@@ -1531,6 +1675,7 @@
 	int stat, ireason, len, sectors_to_transfer, uptodate;
 	struct cdrom_info *info = drive->driver_data;
 	int i, dma_error = 0, dma = info->dma;
+	u8 lowcyl = 0, highcyl = 0;
 	ide_startstop_t startstop;
 
 	struct request *rq = HWGROUP(drive)->rq;
@@ -1538,9 +1683,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);
 		}
 	}
 
@@ -1554,19 +1699,22 @@
 	 */
 	if (dma) {
 		if (dma_error)
-			return ide_error(drive, "dma error", stat);
+			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_end_request(1, HWGROUP(drive));
+			ide_cdrom_end_request(drive, 1);
 		}
 		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) {
@@ -1579,7 +1727,7 @@
 			drive->name, rq->current_nr_sectors);
 			uptodate = 0;
 		}
-		cdrom_end_request(uptodate, drive);
+		cdrom_end_request(drive, uptodate);
 		return ide_stopped;
 	}
 
@@ -1607,7 +1755,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;
@@ -1620,9 +1768,12 @@
 		 * current buffer complete, move on
 		 */
 		if (rq->current_nr_sectors == 0 && rq->nr_sectors)
-			cdrom_end_request (1, drive);
+			cdrom_end_request(drive, 1);
 	}
 
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+
 	/* re-arm handler */
 	ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL);
 	return ide_started;
@@ -1662,7 +1813,7 @@
 	 * writes *must* be 2kB frame aligned
 	 */
 	if ((rq->nr_sectors & 3) || (rq->sector & 3)) {
-		cdrom_end_request(0, drive);
+		cdrom_end_request(drive, 0);
 		return ide_stopped;
 	}
 
@@ -1698,11 +1849,10 @@
 		case WRITE:
 		case READ: {
 			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) {
+					if (time_before(jiffies, info->start_seek + IDECD_SEEK_TIMEOUT)) {
 						ide_stall_queue(drive, IDECD_SEEK_TIMER);
 						return ide_stopped;
 					}
@@ -1711,9 +1861,9 @@
 				CDROM_CONFIG_FLAGS(drive)->seeking = 0;
 			}
 			if (IDE_LARGE_SEEK(info->last_block, block, IDECD_SEEK_THRESHOLD) && drive->dsc_overlap)
-				action = cdrom_start_seek (drive, block);
+				action = cdrom_start_seek(drive, block);
 			else {
-				if (rq->cmd == READ)
+				if (rq_data_dir(rq) == READ)
 					action = cdrom_start_read(drive, block);
 				else
 					action = cdrom_start_write(drive, rq);
@@ -1728,13 +1878,13 @@
 		}
 
 		case RESET_DRIVE_COMMAND: {
-			cdrom_end_request(1, drive);
+			cdrom_end_request(drive, 1);
 			return ide_do_reset(drive);
 		}
 
 		default: {
 			printk("ide-cd: bad cmd %d\n", rq->cmd);
-			cdrom_end_request(0, drive);
+			cdrom_end_request(drive, 0);
 			return ide_stopped;
 		}
 	}
@@ -1836,7 +1986,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
@@ -1846,7 +1996,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;
 	}
 	
@@ -1855,7 +2005,7 @@
 		stat = 0;
 
 	if (stat == 0)
-		CDROM_STATE_FLAGS (drive)->door_locked = lockflag;
+		CDROM_STATE_FLAGS(drive)->door_locked = lockflag;
 
 	return stat;
 }
@@ -1880,7 +2030,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,
@@ -1929,7 +2079,7 @@
 	if (msf_flag)
 		pc.c[1] = 2;
 
-	return cdrom_queue_packet_command (drive, &pc);
+	return cdrom_queue_packet_command(drive, &pc);
 }
 
 
@@ -1969,9 +2119,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 */
 
@@ -2009,7 +2159,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
@@ -2026,18 +2176,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,
@@ -2059,7 +2209,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 */
 
@@ -2082,7 +2232,7 @@
 	drive->part[0].nr_sects = 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;
 }
@@ -2308,7 +2458,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;
@@ -2380,10 +2530,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;
 }
 
@@ -2476,8 +2626,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;
@@ -2535,30 +2685,30 @@
 	struct cdrom_device_info *devinfo = &info->devinfo;
 	int minor = (drive->select.b.unit) << PARTN_BITS;
 
-	devinfo->dev = MKDEV (HWIF(drive)->major, minor);
+	devinfo->dev = MKDEV(HWIF(drive)->major, minor);
 	devinfo->ops = &ide_cdrom_dops;
 	devinfo->mask = 0;
-	devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
+	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,
@@ -2612,9 +2762,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;
 	}
 
@@ -2622,38 +2772,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;
 	}
 
@@ -2662,21 +2812,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;
 	}
 
@@ -2687,26 +2838,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");
 
@@ -2741,42 +2892,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;
@@ -2787,11 +2938,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 &&
@@ -2799,36 +2950,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
@@ -2857,7 +3008,16 @@
 	if (CDROM_CONFIG_FLAGS(drive)->dvd_ram)
 		set_device_ro(MKDEV(HWIF(drive)->major, 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;
@@ -2872,7 +3032,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
@@ -2902,7 +3062,7 @@
 static
 int ide_cdrom_check_media_change (ide_drive_t *drive)
 {
-	return cdrom_media_changed(MKDEV (HWIF (drive)->major,
+	return cdrom_media_changed(MKDEV (HWIF(drive)->major,
 			(drive->select.b.unit) << PARTN_BITS));
 }
 
@@ -2950,35 +3110,47 @@
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *devinfo = &info->devinfo;
 
-	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;
 	return 0;
 }
 
-int ide_cdrom_reinit (ide_drive_t *drive);
+int ide_cdrom_init(void);
+int ide_cdrom_attach (ide_drive_t *drive);
 
 static ide_driver_t ide_cdrom_driver = {
 	name:			"ide-cdrom",
 	version:		IDECD_VERSION,
 	media:			ide_cdrom,
 	busy:			0,
+#ifdef CONFIG_IDEDMA_ONLYDISK
+	supports_dma:		0,
+#else
 	supports_dma:		1,
+#endif
 	supports_dsc_overlap:	1,
 	cleanup:		ide_cdrom_cleanup,
 	standby:		NULL,
+	suspend:		NULL,
+	resume:			NULL,
 	flushcache:		NULL,
 	do_request:		ide_do_rw_cdrom,
-	end_request:		NULL,
+	end_request:		ide_cdrom_end_request,
+	sense:			ide_cdrom_dump_status,
+	error:			ide_cdrom_error,
 	ioctl:			ide_cdrom_ioctl,
 	open:			ide_cdrom_open,
 	release:		ide_cdrom_release,
@@ -2988,12 +3160,12 @@
 	capacity:		ide_cdrom_capacity,
 	special:		NULL,
 	proc:			NULL,
-	reinit:			ide_cdrom_reinit,
+	init:			ide_cdrom_init,
+	attach:			ide_cdrom_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 };
 
-int ide_cdrom_init(void);
 static ide_module_t ide_cdrom_module = {
 	IDE_DRIVER_MODULE,
 	ide_cdrom_init,
@@ -3007,35 +3179,46 @@
 MODULE_PARM(ignore, "s");
 MODULE_DESCRIPTION("ATAPI CD-ROM Driver");
 
-int ide_cdrom_reinit (ide_drive_t *drive)
+int ide_cdrom_attach (ide_drive_t *drive)
 {
 	struct cdrom_info *info;
 	int failed = 0;
 
+	if (drive->scsi) {
+		printk("ide-cd: passing drive %s to ide-scsi emulation.\n",
+			drive->name);
+		return 1;
+	}
+
 	MOD_INC_USE_COUNT;
 	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);
+		MOD_DEC_USE_COUNT;
 		return 1;
 	}
-	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(KERN_ERR "ide-cd: %s: Failed to register the driver "
+			"with ide.c\n", drive->name);
+		kfree(info);
+		MOD_DEC_USE_COUNT;
 		return 1;
 	}
-	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)) {
 		DRIVER(drive)->busy--;
-		if (ide_cdrom_cleanup (drive))
-			printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
+		if (ide_cdrom_cleanup(drive))
+			printk("%s: ide_cdrom_cleanup failed in "
+				"ide_cdrom_init\n", drive->name);
+		MOD_DEC_USE_COUNT;
 		return 1;
 	}
 	DRIVER(drive)->busy--;
 	failed--;
 
-	ide_register_module(&ide_cdrom_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
@@ -3045,41 +3228,51 @@
 	ide_drive_t *drive;
 	int failed = 0;
 
-	while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, &ide_cdrom_driver, failed)) != NULL)
-		if (ide_cdrom_cleanup (drive)) {
-			printk ("%s: cleanup_module() called while still busy\n", drive->name);
+	while ((drive = ide_scan_devices(ide_cdrom, ide_cdrom_driver.name,
+			&ide_cdrom_driver, failed)) != NULL)
+		if (ide_cdrom_cleanup(drive)) {
+			printk("%s: cleanup_module() called while still "
+				"busy\n", drive->name);
 			failed++;
 		}
-	ide_unregister_module (&ide_cdrom_module);
+	ide_unregister_module(&ide_cdrom_module);
 }
- 
+
 int ide_cdrom_init(void)
 {
+#ifdef CLASSIC_BUILTINS_METHOD
 	ide_drive_t *drive;
 	struct cdrom_info *info;
 	int failed = 0;
-
+#endif /* CLASSIC_BUILTINS_METHOD */
 	MOD_INC_USE_COUNT;
-	while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, NULL, failed++)) != NULL) {
+#ifdef CLASSIC_BUILTINS_METHOD
+	while ((drive = ide_scan_devices(ide_cdrom,
+			ide_cdrom_driver.name, NULL, failed++)) != NULL) {
 		/* skip drives that we were told to ignore */
 		if (ignore != NULL) {
 			if (strstr(ignore, drive->name)) {
-				printk("ide-cd: ignoring drive %s\n", drive->name);
+				printk("ide-cd: ignoring drive %s\n",
+					drive->name);
 				continue;
 			}
 		}
 		if (drive->scsi) {
-			printk("ide-cd: passing drive %s to ide-scsi emulation.\n", drive->name);
+			printk("ide-cd: passing drive %s to ide-scsi "
+				"emulation.\n", drive->name);
 			continue;
 		}
 		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);
 			continue;
 		}
-		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);
 			continue;
 		}
 		memset (info, 0, sizeof (struct cdrom_info));
@@ -3088,12 +3281,14 @@
 		if (ide_cdrom_setup (drive)) {
 			DRIVER(drive)->busy--;
 			if (ide_cdrom_cleanup (drive))
-				printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
+				printk ("%s: ide_cdrom_cleanup failed in "
+					"ide_cdrom_init\n", drive->name);
 			continue;
 		}
 		DRIVER(drive)->busy--;
 		failed--;
 	}
+#endif /* CLASSIC_BUILTINS_METHOD */
 	ide_register_module(&ide_cdrom_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-cd.h linux.20pre10-ac2/drivers/ide/ide-cd.h
--- linux.20pre10/drivers/ide/ide-cd.h	2002-10-09 21:36:51.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-cd.h	2002-10-11 00:35:04.000000000 +0100
@@ -437,7 +437,7 @@
 
 	byte     curlba[3];
 	byte     nslots;
-	__u8 short slot_tablelen;
+	__u16	slot_tablelen;
 };
 
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-cs.c linux.20pre10-ac2/drivers/ide/ide-cs.c
--- linux.20pre10/drivers/ide/ide-cs.c	2002-10-09 21:36:51.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-cs.c	1970-01-01 01:00:00.000000000 +0100
@@ -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)
-	    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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-disk.c linux.20pre10-ac2/drivers/ide/ide-disk.c
--- linux.20pre10/drivers/ide/ide-disk.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-disk.c	2002-09-30 17:19:50.000000000 +0100
@@ -1,5 +1,9 @@
 /*
- *  linux/drivers/ide/ide-disk.c	Version 1.10	June 9, 2000
+ *  linux/drivers/ide/ide-disk.c	Version 1.16	April 7, 2002
+ *
+ *  Copyright (C) 1998-2002  Linux ATA Developemt
+ *				Andre Hedrick <andre@linux-ide.org>
+ *
  *
  *  Copyright (C) 1994-1998  Linus Torvalds & authors (see below)
  */
@@ -29,10 +33,14 @@
  * Version 1.10		request queue changes, Ultra DMA 100
  * Version 1.11		added 48-bit lba
  * Version 1.12		adding taskfile io access method
- *			Highmem I/O support, Jens Axboe <axboe@suse.de>
+ * Version 1.13		added standby and flush-cache for notifier
+ * Version 1.14		added acoustic-wcache
+ * Version 1.15		convert all calls to ide_raw_taskfile
+ *				since args will return register content.
+ * Version 1.16		added suspend-resume-checkpower
  */
 
-#define IDEDISK_VERSION	"1.12"
+#define IDEDISK_VERSION	"1.16"
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
@@ -49,6 +57,9 @@
 #include <linux/genhd.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+
+#define _IDE_DISK
+
 #include <linux/ide.h>
 
 #include <asm/byteorder.h>
@@ -56,48 +67,27 @@
 #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
-
-#ifdef CONFIG_IDE_TASKFILE_IO
-#  undef __TASKFILE__IO /* define __TASKFILE__IO */
-#else /* CONFIG_IDE_TASKFILE_IO */
-#  undef __TASKFILE__IO
-#endif /* CONFIG_IDE_TASKFILE_IO */
+/* FIXME: soem day we shouldnt need to look in here! */
 
-#ifndef __TASKFILE__IO
-
-static void idedisk_bswap_data (void *buffer, int wcount)
-{
-	u16 *p = buffer;
-
-	while (wcount--) {
-		*p = *p << 8 | *p >> 8; p++;
-		*p = *p << 8 | *p >> 8; p++;
-	}
-}
+#include "legacy/pdc4030.h"
 
-static inline void idedisk_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
-{
-	ide_input_data(drive, buffer, wcount);
-	if (drive->bswap)
-		idedisk_bswap_data(buffer, wcount);
-}
+static int driver_blocked;
 
-static inline void idedisk_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
+static inline u32 idedisk_read_24 (ide_drive_t *drive)
 {
-	if (drive->bswap) {
-		idedisk_bswap_data(buffer, wcount);
-		ide_output_data(drive, buffer, wcount);
-		idedisk_bswap_data(buffer, wcount);
-	} else
-		ide_output_data(drive, buffer, wcount);
+#if 0
+	return	(HWIF(drive)->INB(IDE_HCYL_REG)<<16) |
+		(HWIF(drive)->INB(IDE_LCYL_REG)<<8) |
+		 HWIF(drive)->INB(IDE_SECTOR_REG);
+#else
+	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;
+#endif
 }
 
-#endif /* __TASKFILE__IO */
+static int idedisk_end_request(ide_drive_t *drive, int uptodate);
 
 /*
  * lba_capacity_is_ok() performs a sanity check on the claimed "lba_capacity"
@@ -127,7 +117,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;
@@ -149,31 +139,32 @@
 	return 0;	/* lba_capacity value may be bad */
 }
 
-#ifndef __TASKFILE__IO
+#ifndef CONFIG_IDE_TASKFILE_IO
 
 /*
  * read_intr() is the handler for disk read/multread interrupts
  */
 static ide_startstop_t read_intr (ide_drive_t *drive)
 {
-	byte stat;
-	int i;
-	unsigned int msect, nsect;
-	unsigned long flags;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u32 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 ide_error(drive, "read_intr", stat);
+			return DRIVER(drive)->error(drive, "read_intr", stat);
 		}
 		/* no data yet, so wait for another interrupt */
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
 		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
 		return ide_started;
 	}
-
-	msect = drive->mult_count;
+	
 read_next:
 	rq = HWGROUP(drive)->rq;
 	if (msect) {
@@ -183,22 +174,31 @@
 	} else
 		nsect = 1;
 	to = ide_map_buffer(rq, &flags);
-	idedisk_input_data(drive, to, nsect * SECTOR_WORDS);
+	taskfile_input_data(drive, to, nsect * SECTOR_WORDS);
+
 #ifdef DEBUG
 	printk("%s:  read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n",
 		drive->name, rq->sector, rq->sector+nsect-1,
 		(unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect);
 #endif
+
 	ide_unmap_buffer(to, &flags);
 	rq->sector += nsect;
 	rq->errors = 0;
 	i = (rq->nr_sectors -= nsect);
 	if (((long)(rq->current_nr_sectors -= nsect)) <= 0)
-		ide_end_request(1, HWGROUP(drive));
+		idedisk_end_request(drive, 1);
+	/*
+	 * Another BH Page walker and DATA INTERGRITY Questioned on ERROR.
+	 * If passed back up on multimode read, BAD DATA could be ACKED
+	 * to FILE SYSTEMS above ...
+	 */
 	if (i > 0) {
 		if (msect)
 			goto read_next;
-		ide_set_handler (drive, &read_intr, WAIT_CMD, NULL);
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+		ide_set_handler(drive, &read_intr, WAIT_CMD, NULL);
                 return ide_started;
 	}
         return ide_stopped;
@@ -209,13 +209,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;
+	u32 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",
@@ -228,20 +231,23 @@
 			i = --rq->nr_sectors;
 			--rq->current_nr_sectors;
 			if (((long)rq->current_nr_sectors) <= 0)
-				ide_end_request(1, hwgroup);
+				idedisk_end_request(drive, 1);
 			if (i > 0) {
 				unsigned long flags;
 				char *to = ide_map_buffer(rq, &flags);
-				idedisk_output_data (drive, to, SECTOR_WORDS);
+				taskfile_output_data(drive, to, SECTOR_WORDS);
 				ide_unmap_buffer(to, &flags);
-				ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
+				if (HWGROUP(drive)->handler != NULL)
+					BUG();
+				ide_set_handler(drive, &write_intr, WAIT_CMD, NULL);
                                 return ide_started;
 			}
                         return ide_stopped;
 		}
-		return ide_stopped;	/* the original code did this here (?) */
+		/* the original code did this here (?) */
+		return ide_stopped;
 	}
-	return ide_error(drive, "write_intr", stat);
+	return DRIVER(drive)->error(drive, "write_intr", stat);
 }
 
 /*
@@ -254,22 +260,27 @@
  * 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!
+ *
+ * The update and return to BH is a BLOCK Layer Fakey to get more data
+ * to satisfy the hardware atomic segment.  If the hardware atomic segment
+ * is shorter or smaller than the BH segment then we should be OKAY.
+ * This is only valid if we can rewind the rq->current_nr_sectors counter.
  */
 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;
   		int nsect = rq->current_nr_sectors;
 		unsigned long flags;
-
+ 
 		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;
@@ -285,6 +296,7 @@
 				rq->bh = bh;
 				rq->current_nr_sectors = bh->b_size >> 9;
 				rq->hard_cur_sectors = rq->current_nr_sectors;
+				rq->buffer             = bh->b_data;
 			}
 		}
 
@@ -292,7 +304,7 @@
 		 * Ok, we're all setup for the interrupt
 		 * re-entering us on the last transfer.
 		 */
-		idedisk_output_data(drive, buffer, nsect<<7);
+		taskfile_output_data(drive, buffer, nsect<<7);
 		ide_unmap_buffer(buffer, &flags);
 	} while (mcount);
 
@@ -304,12 +316,14 @@
  */
 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;
+	u32 i = 0;
+	u8 stat;
 
-	if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
+	if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG),
+			DRIVE_READY, drive->bad_wstat)) {
 		if (stat & DRQ_STAT) {
 			/*
 			 *	The drive wants data. Remember rq is the copy
@@ -318,7 +332,9 @@
 			if (rq->nr_sectors) {
 				if (ide_multwrite(drive, drive->mult_count))
 					return ide_stopped;
-				ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL);
+				if (HWGROUP(drive)->handler != NULL)
+					BUG();
+				ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL);
 				return ide_started;
 			}
 		} else {
@@ -328,24 +344,19 @@
 			 */
 			if (!rq->nr_sectors) {	/* all done? */
 				rq = hwgroup->rq;
-				for (i = rq->nr_sectors; i > 0;){
+				for (i = rq->nr_sectors; i > 0;) {
 					i -= rq->current_nr_sectors;
-					ide_end_request(1, hwgroup);
+					idedisk_end_request(drive, 1);
 				}
 				return ide_stopped;
 			}
 		}
-		return ide_stopped;	/* the original code did this here (?) */
+		/* the original code did this here (?) */
+		return ide_stopped;
 	}
-	return ide_error(drive, "multwrite_intr", stat);
+	return DRIVER(drive)->error(drive, "multwrite_intr", stat);
 }
-#endif /* __TASKFILE__IO */
 
-#ifdef __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,
@@ -354,230 +365,32 @@
  */
 static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	if (rq->cmd == READ)
-		goto good_command;
-	if (rq->cmd == WRITE)
-		goto good_command;
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
+	task_ioreg_t command	= WIN_NOP;
+	ata_nsector_t		nsectors;
 
-	printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
-	ide_end_request(0, HWGROUP(drive));
-	return ide_stopped;
+	nsectors.all		= (u16) rq->nr_sectors;
 
-good_command:
+	if (driver_blocked)
+		panic("Request while ide driver is blocked?");
 
-#ifdef CONFIG_BLK_DEV_PDC4030
-	if (IS_PDC4030_DRIVE) {
-		extern ide_startstop_t promise_rw_disk(ide_drive_t *, struct request *, unsigned long);
+#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))	/* 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);
-
-	/* 28-bit CHS : DIE DIE DIE piece of legacy crap!!! */
-	return chs_rw_disk(drive, rq, (unsigned long) block);
-}
-
-static task_ioreg_t get_command (ide_drive_t *drive, int cmd)
-{
-	int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
-
-#if 1
-	lba48bit = drive->addressing;
-#endif
-
-	if ((cmd == READ) && (drive->using_dma))
-		return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA;
-	else if ((cmd == READ) && (drive->mult_count))
-		return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD;
-	else if (cmd == READ)
-		return (lba48bit) ? WIN_READ_EXT : WIN_READ;
-	else if ((cmd == WRITE) && (drive->using_dma))
-		return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
-	else if ((cmd == WRITE) && (drive->mult_count))
-		return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
-	else if (cmd == WRITE)
-		return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE;
-	else
-		return WIN_NOP;
-}
-
-static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
-{
-	struct hd_drive_task_hdr	taskfile;
-	struct hd_drive_hob_hdr		hobfile;
-	ide_task_t			args;
-
-	task_ioreg_t command	= get_command(drive, rq->cmd);
-	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);
-
-	memset(&taskfile, 0, sizeof(task_struct_t));
-	memset(&hobfile, 0, sizeof(hob_struct_t));
-
-	taskfile.sector_count	= (rq->nr_sectors==256)?0x00:rq->nr_sectors;
-	taskfile.sector_number	= sect;
-	taskfile.low_cylinder	= cyl;
-	taskfile.high_cylinder	= (cyl>>8);
-	taskfile.device_head	= head;
-	taskfile.device_head	|= drive->select.all;
-	taskfile.command	= command;
-
-#ifdef DEBUG
-	printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ");
-	if (lba)	printk("LBAsect=%lld, ", block);
-	else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
-	printk("sectors=%ld, ", rq->nr_sectors);
-	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
-#endif
-
-	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
-	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
-	args.command_type	= ide_cmd_type_parser(&args);
-	args.prehandler		= ide_pre_handler_parser(&taskfile, &hobfile);
-	args.handler		= ide_handler_parser(&taskfile, &hobfile);
-	args.posthandler	= NULL;
-	args.rq			= (struct request *) rq;
-	args.block		= block;
-	rq->special		= NULL;
-	rq->special		= (ide_task_t *)&args;
-
-	return do_rw_taskfile(drive, &args);
-}
-
-static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
-{
-	struct hd_drive_task_hdr	taskfile;
-	struct hd_drive_hob_hdr		hobfile;
-	ide_task_t			args;
-
-	task_ioreg_t command	= get_command(drive, rq->cmd);
-
-	memset(&taskfile, 0, sizeof(task_struct_t));
-	memset(&hobfile, 0, sizeof(hob_struct_t));
-
-	taskfile.sector_count	= (rq->nr_sectors==256)?0x00:rq->nr_sectors;
-	taskfile.sector_number	= block;
-	taskfile.low_cylinder	= (block>>=8);
-	taskfile.high_cylinder	= (block>>=8);
-	taskfile.device_head	= ((block>>8)&0x0f);
-	taskfile.device_head	|= drive->select.all;
-	taskfile.command	= command;
-
-
-#ifdef DEBUG
-	printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ");
-	if (lba)	printk("LBAsect=%lld, ", block);
-	else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
-	printk("sectors=%ld, ", rq->nr_sectors);
-	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
-#endif
-
-	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
-	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
-	args.command_type	= ide_cmd_type_parser(&args);
-	args.prehandler		= ide_pre_handler_parser(&taskfile, &hobfile);
-	args.handler		= ide_handler_parser(&taskfile, &hobfile);
-	args.posthandler	= NULL;
-	args.rq			= (struct request *) rq;
-	args.block		= block;
-	rq->special		= NULL;
-	rq->special		= (ide_task_t *)&args;
-
-	return do_rw_taskfile(drive, &args);
-}
-
-/*
- * 268435455  == 137439 MB or 28bit limit
- * 320173056  == 163929 MB or 48bit addressing
- * 1073741822 == 549756 MB or 48bit addressing fake drive
- */
-
-static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block)
-{
-	struct hd_drive_task_hdr	taskfile;
-	struct hd_drive_hob_hdr		hobfile;
-	ide_task_t			args;
-
-	task_ioreg_t command	= get_command(drive, rq->cmd);
-
-	memset(&taskfile, 0, sizeof(task_struct_t));
-	memset(&hobfile, 0, sizeof(hob_struct_t));
-
-	taskfile.sector_count	= rq->nr_sectors;
-	hobfile.sector_count	= (rq->nr_sectors>>8);
-
-	if (rq->nr_sectors == 65536) {
-		taskfile.sector_count	= 0x00;
-		hobfile.sector_count	= 0x00;
-	}
-
-	taskfile.sector_number	= block;	/* low lba */
-	taskfile.low_cylinder	= (block>>=8);	/* mid lba */
-	taskfile.high_cylinder	= (block>>=8);	/* hi  lba */
-	hobfile.sector_number	= (block>>=8);	/* low lba */
-	hobfile.low_cylinder	= (block>>=8);	/* mid lba */
-	hobfile.high_cylinder	= (block>>=8);	/* hi  lba */
-	taskfile.device_head	= drive->select.all;
-	hobfile.device_head	= taskfile.device_head;
-	hobfile.control		= (drive->ctl|0x80);
-	taskfile.command	= command;
-
-#ifdef DEBUG
-	printk("%s: %sing: ", drive->name, (rq->cmd==READ) ? "read" : "writ");
-	if (lba)	printk("LBAsect=%lld, ", block);
-	else		printk("CHS=%d/%d/%d, ", cyl, head, sect);
-	printk("sectors=%ld, ", rq->nr_sectors);
-	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
-#endif
-
-	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));
-	memcpy(args.hobRegister, &hobfile, sizeof(struct hd_drive_hob_hdr));
-	args.command_type	= ide_cmd_type_parser(&args);
-	args.prehandler		= ide_pre_handler_parser(&taskfile, &hobfile);
-	args.handler		= ide_handler_parser(&taskfile, &hobfile);
-	args.posthandler	= NULL;
-	args.rq			= (struct request *) rq;
-	args.block		= block;
-	rq->special		= NULL;
-	rq->special		= (ide_task_t *)&args;
-
-	return do_rw_taskfile(drive, &args);
-}
-
-#else /* !__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 (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
+		hwif->OUTB(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)) {
+		if (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[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);
@@ -587,7 +400,8 @@
 //			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",
+			printk("%s: %sing: LBAsect=%lu, sectors=%ld, "
+				"buffer=0x%08lx, LBAsect=0x%012lx\n",
 				drive->name,
 				(rq->cmd==READ)?"read":"writ",
 				block,
@@ -599,87 +413,88 @@
 				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);
+			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",
+			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);
+				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);
+			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;
-		OUT_BYTE(sect,IDE_SECTOR_REG);
+		hwif->OUTB(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);
+		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
 	}
-#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->cmd == READ) {
+
+	if (rq_data_dir(rq) == READ) {
 #ifdef CONFIG_BLK_DEV_IDEDMA
-		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))
+		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);
-		if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
-			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);
-		}
+
+		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;
-	}
-	if (rq->cmd == WRITE) {
+	} 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)))
+		if (drive->using_dma && !(HWIF(drive)->ide_dma_write(drive)))
 			return ide_started;
 #endif /* CONFIG_BLK_DEV_IDEDMA */
-		if ((drive->id->cfs_enable_2 & 0x0400) && (drive->addressing)) {
-			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,
+
+		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)
-			__cli();	/* local CPU only */
+			local_irq_disable();
 		if (drive->mult_count) {
 			ide_hwgroup_t *hwgroup = HWGROUP(drive);
 	/*
@@ -690,8 +505,12 @@
 	 * 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;
@@ -703,36 +522,210 @@
 			}
 		} else {
 			unsigned long flags;
-			char *buffer = ide_map_buffer(rq, &flags);
-			ide_set_handler (drive, &write_intr, WAIT_CMD, NULL);
-			idedisk_output_data(drive, buffer, SECTOR_WORDS);
-			ide_unmap_buffer(buffer, &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(to, &flags);
 		}
 		return ide_started;
 	}
 	printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
-	ide_end_request(0, HWGROUP(drive));
+	idedisk_end_request(drive, 0);
 	return ide_stopped;
 }
 
-#endif /* __TASKFILE__IO */
+#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,
+ * 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 (!blk_fs_request(rq)) {
+		printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);
+		idedisk_end_request(drive, 0);
+		return ide_stopped;
+	}
+
+	/*
+	 * 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->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);
+
+	/* 28-bit CHS : DIE DIE DIE piece of legacy crap!!! */
+	return chs_rw_disk(drive, rq, (unsigned long) block);
+}
+
+static task_ioreg_t get_command (ide_drive_t *drive, int cmd)
+{
+	int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
+
+#if 1
+	lba48bit = (drive->addressing == 1) ? 1 : 0;
+#endif
+
+	if ((cmd == READ) && (drive->using_dma))
+		return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA;
+	else if ((cmd == READ) && (drive->mult_count))
+		return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD;
+	else if (cmd == READ)
+		return (lba48bit) ? WIN_READ_EXT : WIN_READ;
+	else if ((cmd == WRITE) && (drive->using_dma))
+		return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+	else if ((cmd == WRITE) && (drive->mult_count))
+		return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;
+	else if (cmd == WRITE)
+		return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE;
+	else
+		return WIN_NOP;
+}
+
+static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	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);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
+
+	memset(&args, 0, sizeof(ide_task_t));
+
+	sectors	= (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;
+	args.tfRegister[IDE_SECTOR_OFFSET]	= sect;
+	args.tfRegister[IDE_LCYL_OFFSET]	= cyl;
+	args.tfRegister[IDE_HCYL_OFFSET]	= (cyl>>8);
+	args.tfRegister[IDE_SELECT_OFFSET]	= head;
+	args.tfRegister[IDE_SELECT_OFFSET]	|= drive->select.all;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= command;
+	args.command_type			= ide_cmd_type_parser(&args);
+	args.rq					= (struct request *) rq;
+	rq->special				= (ide_task_t *)&args;
+	return do_rw_taskfile(drive, &args);
+}
+
+static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
+{
+	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);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
+
+	memset(&args, 0, sizeof(ide_task_t));
+
+	sectors = (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;
+	args.tfRegister[IDE_SECTOR_OFFSET]	= block;
+	args.tfRegister[IDE_LCYL_OFFSET]	= (block>>=8);
+	args.tfRegister[IDE_HCYL_OFFSET]	= (block>>=8);
+	args.tfRegister[IDE_SELECT_OFFSET]	= ((block>>8)&0x0f);
+	args.tfRegister[IDE_SELECT_OFFSET]	|= drive->select.all;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= command;
+	args.command_type			= ide_cmd_type_parser(&args);
+	args.rq					= (struct request *) rq;
+	rq->special				= (ide_task_t *)&args;
+	return do_rw_taskfile(drive, &args);
+}
+
+/*
+ * 268435455  == 137439 MB or 28bit limit
+ * 320173056  == 163929 MB or 48bit addressing
+ * 1073741822 == 549756 MB or 48bit addressing fake drive
+ */
+
+static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block)
+{
+	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);
+	printk("sectors=%ld, ", rq->nr_sectors);
+	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);
+#endif
+
+	memset(&args, 0, sizeof(ide_task_t));
+
+	sectors = (rq->nr_sectors == 65536) ? 0 : rq->nr_sectors;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;
+	args.tfRegister[IDE_SECTOR_OFFSET]	= block;	/* low lba */
+	args.tfRegister[IDE_LCYL_OFFSET]	= (block>>=8);	/* mid lba */
+	args.tfRegister[IDE_HCYL_OFFSET]	= (block>>=8);	/* hi  lba */
+	args.tfRegister[IDE_SELECT_OFFSET]	= drive->select.all;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= command;
+	args.hobRegister[IDE_NSECTOR_OFFSET_HOB]= sectors >> 8;
+	args.hobRegister[IDE_SECTOR_OFFSET_HOB]	= (block>>=8);	/* low lba */
+	args.hobRegister[IDE_LCYL_OFFSET_HOB]	= (block>>=8);	/* mid lba */
+	args.hobRegister[IDE_HCYL_OFFSET_HOB]	= (block>>=8);	/* hi  lba */
+	args.hobRegister[IDE_SELECT_OFFSET_HOB]	= drive->select.all;
+	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
+	args.command_type			= ide_cmd_type_parser(&args);
+	args.rq					= (struct request *) rq;
+	rq->special				= (ide_task_t *)&args;
+	return do_rw_taskfile(drive, &args);
+}
+
+#endif /* CONFIG_IDE_TASKFILE_IO */
 
 static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	MOD_INC_USE_COUNT;
 	if (drive->removable && drive->usage == 1) {
-		struct hd_drive_task_hdr taskfile;
-		struct hd_drive_hob_hdr hobfile;
-		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-		taskfile.command = WIN_DOORLOCK;
+		ide_task_t args;
+		memset(&args, 0, sizeof(ide_task_t));
+		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK;
+		args.command_type = ide_cmd_type_parser(&args);
 		check_disk_change(inode->i_rdev);
 		/*
 		 * Ignore the return code from door_lock,
 		 * since the open() has already succeeded,
 		 * and the door_lock is irrelevant at this point.
 		 */
-		if (drive->doorlocking && ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
+		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
 			drive->doorlocking = 0;
 	}
 	return 0;
@@ -743,13 +736,12 @@
 static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	if (drive->removable && !drive->usage) {
-		struct hd_drive_task_hdr taskfile;
-		struct hd_drive_hob_hdr hobfile;
-		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-		taskfile.command = WIN_DOORUNLOCK;
+		ide_task_t args;
+		memset(&args, 0, sizeof(ide_task_t));
+		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK;
+		args.command_type = ide_cmd_type_parser(&args);
 		invalidate_bdev(inode->i_bdev, 0);
-		if (drive->doorlocking && ide_wait_taskfile(drive, &taskfile, &hobfile, NULL))
+		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))
 			drive->doorlocking = 0;
 	}
 	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
@@ -761,7 +753,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)
@@ -771,6 +764,198 @@
 			current_capacity(drive));
 }
 
+static int idedisk_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&io_request_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->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		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(&io_request_lock, flags);
+	return ret;
+}
+
+static u8 idedisk_dump_status (ide_drive_t *drive, const char *msg, u8 stat)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+	unsigned long flags;
+	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)
+		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 ");
+	}
+	printk("}");
+#endif	/* FANCY_STATUS_DUMPS */
+	printk("\n");
+	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+		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("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 low = 0, high = 0;
+				low = idedisk_read_24(drive);
+				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 {
+				u8 cur = hwif->INB(IDE_SELECT_REG);
+				if (cur & 0x40) {	/* using LBA? */
+					printk(", LBAsect=%ld", (unsigned long)
+					 ((cur&0xf)<<24)
+					 |(hwif->INB(IDE_HCYL_REG)<<16)
+					 |(hwif->INB(IDE_LCYL_REG)<<8)
+					 | hwif->INB(IDE_SECTOR_REG));
+				} else {
+					printk(", CHS=%d/%d/%d",
+					 (hwif->INB(IDE_HCYL_REG)<<8) +
+					  hwif->INB(IDE_LCYL_REG),
+					  cur & 0xf,
+					  hwif->INB(IDE_SECTOR_REG));
+				}
+			}
+			if (HWGROUP(drive) && HWGROUP(drive)->rq)
+				printk(", sector=%ld",
+					HWGROUP(drive)->rq->sector);
+		}
+	}
+#endif	/* FANCY_STATUS_DUMPS */
+	printk("\n");
+	local_irq_restore(flags);
+	return err;
+}
+
+ide_startstop_t idedisk_error (ide_drive_t *drive, const char *msg, u8 stat)
+{
+	ide_hwif_t *hwif;
+	struct request *rq;
+	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: */
+	switch (rq->cmd) {
+		case IDE_DRIVE_CMD:
+		case IDE_DRIVE_TASK:
+		case IDE_DRIVE_TASKFILE:
+			rq->errors = 1;
+			ide_end_drive_cmd(drive, stat, err);
+			return ide_stopped;
+#if 0
+		case IDE_DRIVE_TASKFILE:
+			rq->errors = 1;
+			ide_end_taskfile(drive, stat, err);
+			return ide_stopped;
+#endif
+		default:
+			break;
+	}
+
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {
+		/* other bits are useless when BUSY */
+		rq->errors |= ERROR_RESET;
+	} else if (stat & ERR_STAT) {
+		/* err has different meaning on cdrom and tape */
+		if (err == ABRT_ERR) {
+			if (drive->select.b.lba &&
+			    /* some newer drives don't support WIN_SPECIFY */
+			    hwif->INB(IDE_COMMAND_REG) == 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;
+		}
+	}
+	if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ) {
+		/*
+		 * try_to_flush_leftover_data() is invoked in response to
+		 * a drive unexpectedly having its DRQ_STAT bit set.  As
+		 * an alternative to resetting the drive, this routine
+		 * tries to clear the condition by read a sector's worth
+		 * of data from the drive.  Of course, this may not help
+		 * if the drive is *waiting* for data from *us*.
+		 */
+		while (i > 0) {
+			u32 buffer[16];
+			unsigned int wcount = (i > 16) ? 16 : i;
+			i -= wcount;
+			taskfile_input_data(drive, buffer, wcount);
+		}
+	}
+	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);
+	else {
+		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
+			++rq->errors;
+			return ide_do_reset(drive);
+		}
+		if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
+			drive->special.b.recalibrate = 1;
+		++rq->errors;
+	}
+	return ide_stopped;
+}
+
 /*
  * Queries for true maximum capacity of the drive.
  * Returns maximum LBA address (> 0) of the drive, 0 if failed.
@@ -780,16 +965,11 @@
 	ide_task_t args;
 	unsigned long addr = 0;
 
-	if (!(drive->id->command_set_1 & 0x0400) &&
-	    !(drive->id->cfs_enable_2 & 0x0100))
-		return addr;
-
 	/* Create IDE/ATA command request structure */
 	memset(&args, 0, sizeof(ide_task_t));
 	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX;
-	args.handler				= task_no_data_intr;
-
+	args.command_type			= ide_cmd_type_parser(&args);
 	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 
@@ -814,8 +994,7 @@
 
 	args.tfRegister[IDE_SELECT_OFFSET]	= 0x40;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_READ_NATIVE_MAX_EXT;
-	args.handler				= task_no_data_intr;
-
+	args.command_type			= ide_cmd_type_parser(&args);
         /* submit command request */
         ide_raw_taskfile(drive, &args, NULL);
 
@@ -851,7 +1030,7 @@
 	args.tfRegister[IDE_HCYL_OFFSET]	= ((addr_req >> 16) & 0xff);
 	args.tfRegister[IDE_SELECT_OFFSET]	= ((addr_req >> 24) & 0x0f) | 0x40;
 	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SET_MAX;
-	args.handler				= task_no_data_intr;
+	args.command_type			= ide_cmd_type_parser(&args);
 	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 	/* if OK, read new maximum address value */
@@ -883,7 +1062,7 @@
 	args.hobRegister[IDE_HCYL_OFFSET_HOB]	= ((addr_req >>= 8) & 0xff);
 	args.hobRegister[IDE_SELECT_OFFSET_HOB]	= 0x40;
 	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);
-        args.handler				= task_no_data_intr;
+	args.command_type			= ide_cmd_type_parser(&args);
 	/* submit command request */
 	ide_raw_taskfile(drive, &args, NULL);
 	/* if OK, compute maximum address value */
@@ -899,6 +1078,8 @@
 	return addr_set;
 }
 
+#endif /* CONFIG_IDEDISK_STROKE */
+
 /*
  * Tests if the drive supports Host Protected Area feature.
  * Returns true if supported, false otherwise.
@@ -906,12 +1087,11 @@
 static inline int idedisk_supports_host_protected_area(ide_drive_t *drive)
 {
 	int flag = (drive->id->cfs_enable_1 & 0x0400) ? 1 : 0;
-	printk("%s: host protected area => %d\n", drive->name, flag);
+	if (flag)
+		printk("%s: host protected area => %d\n", drive->name, flag);
 	return flag;
 }
 
-#endif /* CONFIG_IDEDISK_STROKE */
-
 /*
  * Compute drive->capacity, the full capacity of the drive
  * Called with drive->id != NULL.
@@ -937,6 +1117,8 @@
 	drive->capacity48 = 0;
 	drive->select.b.lba = 0;
 
+	(void) idedisk_supports_host_protected_area(drive);
+
 	if (id->cfs_enable_2 & 0x0400) {
 		capacity_2 = id->lba_capacity_2;
 		drive->head		= drive->bios_head = 255;
@@ -955,10 +1137,11 @@
 				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 */
 		}
+		drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect);
 		drive->bios_cyl		= drive->cyl;
 		drive->capacity48	= capacity_2;
 		drive->capacity		= (unsigned long) capacity_2;
@@ -981,7 +1164,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 */
 	}
@@ -989,7 +1172,7 @@
 	drive->capacity = capacity;
 
 	if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400)) {
-                drive->capacity48 = id->lba_capacity_2;
+		drive->capacity48 = id->lba_capacity_2;
 		drive->head = 255;
 		drive->sect = 63;
 		drive->cyl = (unsigned long)(drive->capacity48) / (drive->head * drive->sect);
@@ -1008,47 +1191,40 @@
 	special_t *s = &drive->special;
 
 	if (s->b.set_geometry) {
-		struct hd_drive_task_hdr taskfile;
-		struct hd_drive_hob_hdr hobfile;
-		ide_handler_t *handler = NULL;
-
-		memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-		memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-
 		s->b.set_geometry	= 0;
-		taskfile.sector_number	= drive->sect;
-		taskfile.low_cylinder	= drive->cyl;
-		taskfile.high_cylinder	= drive->cyl>>8;
-		taskfile.device_head	= ((drive->head-1)|drive->select.all)&0xBF;
 		if (!IS_PDC4030_DRIVE) {
-			taskfile.sector_count	= drive->sect;
-			taskfile.command	= WIN_SPECIFY;
-			handler			= ide_handler_parser(&taskfile, &hobfile);
+			ide_task_t args;
+			memset(&args, 0, sizeof(ide_task_t));
+			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
+			args.tfRegister[IDE_SECTOR_OFFSET]  = drive->sect;
+			args.tfRegister[IDE_LCYL_OFFSET]    = drive->cyl;
+			args.tfRegister[IDE_HCYL_OFFSET]    = drive->cyl>>8;
+			args.tfRegister[IDE_SELECT_OFFSET]  = ((drive->head-1)|drive->select.all)&0xBF;
+			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SPECIFY;
+			args.command_type = ide_cmd_type_parser(&args);
+			do_rw_taskfile(drive, &args);
 		}
-		do_taskfile(drive, &taskfile, &hobfile, handler);
 	} else if (s->b.recalibrate) {
 		s->b.recalibrate = 0;
 		if (!IS_PDC4030_DRIVE) {
-			struct hd_drive_task_hdr taskfile;
-			struct hd_drive_hob_hdr hobfile;
-			memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-			memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-			taskfile.sector_count	= drive->sect;
-			taskfile.command	= WIN_RESTORE;
-			do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+			ide_task_t args;
+			memset(&args, 0, sizeof(ide_task_t));
+			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->sect;
+			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_RESTORE;
+			args.command_type = ide_cmd_type_parser(&args);
+			do_rw_taskfile(drive, &args);
 		}
 	} else if (s->b.set_multmode) {
 		s->b.set_multmode = 0;
 		if (drive->id && drive->mult_req > drive->id->max_multsect)
 			drive->mult_req = drive->id->max_multsect;
 		if (!IS_PDC4030_DRIVE) {
-			struct hd_drive_task_hdr taskfile;
-			struct hd_drive_hob_hdr hobfile;
-			memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-			memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-			taskfile.sector_count	= drive->mult_req;
-			taskfile.command	= WIN_SETMULT;
-			do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+			ide_task_t args;
+			memset(&args, 0, sizeof(ide_task_t));
+			args.tfRegister[IDE_NSECTOR_OFFSET] = drive->mult_req;
+			args.tfRegister[IDE_COMMAND_OFFSET] = WIN_SETMULT;
+			args.command_type = ide_cmd_type_parser(&args);
+			do_rw_taskfile(drive, &args);
 		}
 	} else if (s->all) {
 		int special = s->all;
@@ -1078,45 +1254,44 @@
 
 static int smart_enable(ide_drive_t *drive)
 {
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	taskfile.feature	= SMART_ENABLE;
-	taskfile.low_cylinder	= SMART_LCYL_PASS;
-	taskfile.high_cylinder	= SMART_HCYL_PASS;
-	taskfile.command	= WIN_SMART;
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
-}
-
-static int get_smart_values(ide_drive_t *drive, byte *buf)
-{
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	taskfile.feature	= SMART_READ_VALUES;
-	taskfile.sector_count	= 0x01;
-	taskfile.low_cylinder	= SMART_LCYL_PASS;
-	taskfile.high_cylinder	= SMART_HCYL_PASS;
-	taskfile.command	= WIN_SMART;
+	ide_task_t args;
+
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_ENABLE;
+	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
+	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
+	args.command_type			= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, NULL);
+}
+
+static int get_smart_values(ide_drive_t *drive, u8 *buf)
+{
+	ide_task_t args;
+
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_READ_VALUES;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
+	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
+	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
+	args.command_type			= ide_cmd_type_parser(&args);
 	(void) smart_enable(drive);
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
+	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)
 {
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	taskfile.feature	= SMART_READ_THRESHOLDS;
-	taskfile.sector_count	= 0x01;
-	taskfile.low_cylinder	= SMART_LCYL_PASS;
-	taskfile.high_cylinder	= SMART_HCYL_PASS;
-	taskfile.command	= WIN_SMART;
+	ide_task_t args;
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= SMART_READ_THRESHOLDS;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= 0x01;
+	args.tfRegister[IDE_LCYL_OFFSET]	= SMART_LCYL_PASS;
+	args.tfRegister[IDE_HCYL_OFFSET]	= SMART_HCYL_PASS;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SMART;
+	args.command_type			= ide_cmd_type_parser(&args);
 	(void) smart_enable(drive);
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
+	return ide_raw_taskfile(drive, &args, buf);
 }
 
 static int proc_idedisk_read_cache
@@ -1185,23 +1360,12 @@
 
 #endif	/* CONFIG_PROC_FS */
 
+/*
+ * This is tightly woven into the driver->do_special can not touch.
+ * DON'T do it again until a total personality rewrite is committed.
+ */
 static int set_multcount(ide_drive_t *drive, int arg)
 {
-#ifdef __TASKFILE__IO
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-
-	if (drive->special.b.set_multmode)
-		return -EBUSY;
-
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	taskfile.sector_count	= drive->mult_req;
-	taskfile.command	= WIN_SETMULT;
-	drive->mult_req		= arg;
-	drive->special.b.set_multmode = 1;
-	ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
-#else /* !__TASKFILE__IO */
 	struct request rq;
 
 	if (drive->special.b.set_multmode)
@@ -1211,7 +1375,6 @@
 	drive->mult_req = arg;
 	drive->special.b.set_multmode = 1;
 	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
-#endif /* __TASKFILE__IO */
 	return (drive->mult_count == arg) ? 0 : -EIO;
 }
 
@@ -1227,57 +1390,112 @@
 
 static int write_cache (ide_drive_t *drive, int arg)
 {
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	taskfile.feature	= (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
-	taskfile.command	= WIN_SETFEATURES;
+	ide_task_t args;
 
 	if (!(drive->id->cfs_enable_2 & 0x3000))
 		return 1;
 
-	(void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ?
+			SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
+	args.command_type			= ide_cmd_type_parser(&args);
+	(void) ide_raw_taskfile(drive, &args, NULL);
+
 	drive->wcache = arg;
 	return 0;
 }
 
+static int call_idedisk_standby (ide_drive_t *drive, int arg)
+{
+	ide_task_t args;
+	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);
+	return ide_raw_taskfile(drive, &args, NULL);
+}
+
 static int do_idedisk_standby (ide_drive_t *drive)
 {
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	taskfile.command	= WIN_STANDBYNOW1;
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	return call_idedisk_standby(drive, 0);
+}
+
+static int call_idedisk_suspend (ide_drive_t *drive, int arg)
+{
+	ide_task_t args;
+	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);
+	return ide_raw_taskfile(drive, &args, NULL);
+}
+
+static int do_idedisk_suspend (ide_drive_t *drive)
+{
+	if (drive->suspend_reset)
+		return 1;
+
+	return call_idedisk_suspend(drive, 0);
+}
+
+#if 0
+static int call_idedisk_checkpower (ide_drive_t *drive, int arg)
+{
+	ide_task_t args;
+	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);
+	ide_raw_taskfile(drive, &args, NULL);
+#if 0
+if (errno != EIO || args[0] != 0 || args[1] != 0)
+   state = "unknown";
+else
+   state = "sleeping";
+} else {
+   state = (args[2] == 255) ? "active/idle" : "standby";
+#endif
+	return 0;
+}
+
+static int do_idedisk_checkpower (ide_drive_t *drive)
+{
+	return call_idedisk_checkpower(drive, 0);
+}
+#endif
+
+static int do_idedisk_resume (ide_drive_t *drive)
+{
+	if (!drive->suspend_reset)
+		return 1;
+	return 0;
 }
 
 static int do_idedisk_flushcache (ide_drive_t *drive)
 {
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	if (drive->id->cfs_enable_2 & 0x2400) {
-		taskfile.command	= WIN_FLUSH_CACHE_EXT;
-	} else {
-		taskfile.command	= WIN_FLUSH_CACHE;
-	}
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	ide_task_t args;
+
+	memset(&args, 0, sizeof(ide_task_t));
+	if (drive->id->cfs_enable_2 & 0x2400)
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE_EXT;
+	else
+		args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_FLUSH_CACHE;
+	args.command_type	 		= ide_cmd_type_parser(&args);
+	return ide_raw_taskfile(drive, &args, NULL);
 }
 
 static int set_acoustic (ide_drive_t *drive, int arg)
 {
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-
-	taskfile.feature	= (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM;
-	taskfile.sector_count	= arg;
+	ide_task_t args;
 
-	taskfile.command	= WIN_SETFEATURES;
-	(void) ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
+	memset(&args, 0, sizeof(ide_task_t));
+	args.tfRegister[IDE_FEATURE_OFFSET]	= (arg) ? SETFEATURES_EN_AAM :
+							  SETFEATURES_DIS_AAM;
+	args.tfRegister[IDE_NSECTOR_OFFSET]	= arg;
+	args.tfRegister[IDE_COMMAND_OFFSET]	= WIN_SETFEATURES;
+	args.command_type = ide_cmd_type_parser(&args);
+	ide_raw_taskfile(drive, &args, NULL);
 	drive->acoustic = arg;
 	return 0;
 }
@@ -1286,9 +1504,11 @@
 {
 	drive->addressing =  0;
 
+	if (HWIF(drive)->addressing)
+		return 0;
+
 	if (!(drive->id->cfs_enable_2 & 0x0400))
                 return -EIO;
-
 	drive->addressing = arg;
 	return 0;
 }
@@ -1321,12 +1541,35 @@
  	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)
 {
 	int i;
 	
 	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);
 
@@ -1337,7 +1580,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 
 		 */
@@ -1355,6 +1598,14 @@
 		break;
 	}
 
+#if 1
+	(void) probe_lba_addressing(drive, 1);
+#else
+	/* if using 48-bit addressing bump the request size up */
+	if (probe_lba_addressing(drive, 1))
+		blk_queue_max_sectors(&drive->queue, 2048);
+#endif
+
 	/* Extract geometry if we did not already have one for the drive */
 	if (!drive->cyl || !drive->head || !drive->sect) {
 		drive->cyl     = drive->bios_cyl  = id->cyls;
@@ -1402,7 +1653,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");
 
@@ -1424,10 +1675,9 @@
 	drive->no_io_32bit = id->dword_io ? 1 : 0;
 	if (drive->id->cfs_enable_2 & 0x3000)
 		write_cache(drive, (id->cfs_enable_2 & 0x3000));
-	(void) probe_lba_addressing(drive, 1);
 }
 
-static int idedisk_cleanup (ide_drive_t *drive)
+static int idedisk_cleanup(ide_drive_t *drive)
 {
 	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
 		if (do_idedisk_flushcache(drive))
@@ -1436,7 +1686,8 @@
 	return ide_unregister_subdriver(drive);
 }
 
-int idedisk_reinit(ide_drive_t *drive);
+int idedisk_init (void);
+int idedisk_attach(ide_drive_t *drive);
 
 /*
  *      IDE subdriver functions, registered with ide.c
@@ -1450,10 +1701,14 @@
 	supports_dsc_overlap:	0,
 	cleanup:		idedisk_cleanup,
 	standby:		do_idedisk_standby,
+	suspend:		do_idedisk_suspend,
+	resume:			do_idedisk_resume,
 	flushcache:		do_idedisk_flushcache,
 	do_request:		do_rw_disk,
-	end_request:		NULL,
-	ioctl:			NULL,
+	end_request:		idedisk_end_request,
+	sense:			idedisk_dump_status,
+	error:			idedisk_error,
+	ioctl:			idedisk_ioctl,
 	open:			idedisk_open,
 	release:		idedisk_release,
 	media_change:		idedisk_media_change,
@@ -1462,12 +1717,12 @@
 	capacity:		idedisk_capacity,
 	special:		idedisk_special,
 	proc:			idedisk_proc,
-	reinit:			idedisk_reinit,
+	init:			idedisk_init,
+	attach:			idedisk_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 };
 
-int idedisk_init (void);
 static ide_module_t idedisk_module = {
 	IDE_DRIVER_MODULE,
 	idedisk_init,
@@ -1477,30 +1732,30 @@
 
 MODULE_DESCRIPTION("ATA DISK Driver");
 
-int idedisk_reinit (ide_drive_t *drive)
+int idedisk_attach (ide_drive_t *drive)
 {
-	int failed = 0;
+	int ret = 0;
 
 	MOD_INC_USE_COUNT;
-
-	if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) {
-		printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
-		return 1;
+	if (ide_register_subdriver(drive,
+			&idedisk_driver, IDE_SUBDRIVER_VERSION)) {
+		printk(KERN_ERR "ide-disk: %s: Failed to register the "
+			"driver with ide.c\n", drive->name);
+		ret= 1;
+		goto bye_game_over;
 	}
 	DRIVER(drive)->busy++;
 	idedisk_setup(drive);
 	if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
-		printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
+		printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",
+			drive->name, drive->head);
 		(void) idedisk_cleanup(drive);
-		DRIVER(drive)->busy--;
-		return 1;
+		ret= 1;
 	}
 	DRIVER(drive)->busy--;
-	failed--;
-
-	ide_register_module(&idedisk_module);
+bye_game_over:
 	MOD_DEC_USE_COUNT;
-	return 0;
+	return ret;
 }
 
 static void __exit idedisk_exit (void)
@@ -1508,14 +1763,17 @@
 	ide_drive_t *drive;
 	int failed = 0;
 
-	while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, &idedisk_driver, failed)) != NULL) {
+	while ((drive = ide_scan_devices(ide_disk, idedisk_driver.name,
+			&idedisk_driver, failed)) != NULL) {
 		if (idedisk_cleanup (drive)) {
-			printk (KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name);
+			printk(KERN_ERR "%s: cleanup_module() called while "
+				"still busy\n", drive->name);
 			failed++;
 		}
-		/* We must remove proc entries defined in this module.
-		   Otherwise we oops while accessing these entries */
 #ifdef CONFIG_PROC_FS
+		/* We must remove proc entries defined in this module.
+		 * Otherwise we oops while accessing these entries
+		 */
 		if (drive->proc)
 			ide_remove_proc_entries(drive->proc, idedisk_proc);
 #endif
@@ -1525,19 +1783,28 @@
 
 int idedisk_init (void)
 {
+#ifdef CLASSIC_BUILTINS_METHOD
 	ide_drive_t *drive;
 	int failed = 0;
-	
+#endif /* CLASSIC_BUILTINS_METHOD */
+
 	MOD_INC_USE_COUNT;
-	while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, NULL, failed++)) != NULL) {
-		if (ide_register_subdriver (drive, &idedisk_driver, IDE_SUBDRIVER_VERSION)) {
-			printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);
+
+#ifdef CLASSIC_BUILTINS_METHOD
+	while ((drive = ide_scan_devices(ide_disk,
+			idedisk_driver.name, NULL, failed++)) != NULL) {
+		if (ide_register_subdriver(drive,
+				&idedisk_driver, IDE_SUBDRIVER_VERSION)) {
+			printk(KERN_ERR "ide-disk: %s: Failed to register "
+				"the driver with ide.c\n", drive->name);
 			continue;
 		}
 		DRIVER(drive)->busy++;
 		idedisk_setup(drive);
-		if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {
-			printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n", drive->name, drive->head);
+		if ((!drive->head || drive->head > 16) &&
+		    (!drive->select.b.lba)) {
+			printk(KERN_ERR "%s: INVALID GEOMETRY: %d "
+				"PHYSICAL HEADS?\n", drive->name, drive->head);
 			(void) idedisk_cleanup(drive);
 			DRIVER(drive)->busy--;
 			continue;
@@ -1545,11 +1812,85 @@
 		DRIVER(drive)->busy--;
 		failed--;
 	}
+#endif /* CLASSIC_BUILTINS_METHOD */
+
 	ide_register_module(&idedisk_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
+ide_startstop_t panic_box(ide_drive_t *drive)
+{
+#if 0
+	panic("%s: Attempted to corrupt something: ide operation "
+#else
+	printk(KERN_ERR "%s: Attempted to corrupt something: ide operation "
+#endif
+		"was pending accross suspend/resume.\n", drive->name);
+	return ide_stopped;
+}
+
+int ide_disks_busy(void)
+{
+	int i;
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
+		if (!hwgroup) continue;
+		if ((hwgroup->handler) && (hwgroup->handler != panic_box))
+			return 1;
+	}
+	return 0;
+}
+
+void ide_disk_suspend(void)
+{
+	int i;
+	while (ide_disks_busy()) {
+		printk("*");
+		schedule();
+	}
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
+
+		if (!hwgroup) continue;
+		hwgroup->handler_save = hwgroup->handler;
+		hwgroup->handler = panic_box;
+	}
+	driver_blocked = 1;
+	if (ide_disks_busy())
+		panic("How did you get that request through?!");
+}
+
+/* unsuspend and resume should be equal in the ideal world */
+
+void ide_disk_unsuspend(void)
+{
+	int i;
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
+
+		if (!hwgroup) continue;
+		hwgroup->handler = NULL; /* hwgroup->handler_save; */
+		hwgroup->handler_save = NULL;
+	}
+	driver_blocked = 0;
+}
+
+void ide_disk_resume(void)
+{
+	int i;
+	for (i=0; i<MAX_HWIFS; i++) {
+		struct hwgroup_s *hwgroup = ide_hwifs[i].hwgroup;
+
+		if (!hwgroup) continue;
+		if (hwgroup->handler != panic_box)
+			panic("Handler was not set to panic?");
+		hwgroup->handler_save = NULL;
+		hwgroup->handler = NULL;
+	}
+	driver_blocked = 0;
+}
+
 module_init(idedisk_init);
 module_exit(idedisk_exit);
 MODULE_LICENSE("GPL");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-dma.c linux.20pre10-ac2/drivers/ide/ide-dma.c
--- linux.20pre10/drivers/ide/ide-dma.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-dma.c	2002-09-12 13:38:25.000000000 +0100
@@ -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,23 +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 */
-
-extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
-
 #ifdef CONFIG_IDEDMA_NEW_DRIVE_LISTINGS
 
 struct drive_list_entry {
@@ -123,7 +110,6 @@
 
 	{ "WDC AC11000H"	,	"ALL"		},
 	{ "WDC AC22100H"	,	"ALL"		},
-	{ "WDC AC31000H"	,	"ALL"		},
 	{ "WDC AC32500H"	,	"ALL"		},
 	{ "WDC AC33100H"	,	"ALL"		},
 	{ "WDC AC31600H"	,	"ALL"		},
@@ -204,103 +190,68 @@
 #endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */
 
 /*
- * 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))
-
-/*
  * dma_intr() is the handler for disk read/write DMA interrupts
  */
 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;
+	//		rq = HWGROUP(drive)->rq;
 			for (i = rq->nr_sectors; i > 0;) {
 				i -= rq->current_nr_sectors;
-				ide_end_request(1, HWGROUP(drive));
+				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 ide_error(drive, "dma_intr", stat);
+	return DRIVER(drive)->error(drive, "dma_intr", stat);
 }
 
-static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq)
+EXPORT_SYMBOL_GPL(ide_dma_intr);
+
+static int ide_build_sglist (ide_hwif_t *hwif, struct request *rq, int ddir)
 {
 	struct buffer_head *bh;
 	struct scatterlist *sg = hwif->sg_table;
-	unsigned long lastdataend = ~0UL;
 	int nents = 0;
 
 	if (hwif->sg_dma_active)
 		BUG();
 
-	if (rq->cmd == READ)
-		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-	else
-		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
-
 	bh = rq->bh;
 	do {
-		struct scatterlist *sge;
-
-		/*
-		 * continue segment from before?
-		 */
-		if (bh_phys(bh) == lastdataend) {
-			sg[nents - 1].length += bh->b_size;
-			lastdataend += bh->b_size;
-			continue;
-		}
+		unsigned char *virt_addr = bh->b_data;
+		unsigned int size = bh->b_size;
 
-		/*
-		 * start new segment
-		 */
 		if (nents >= PRD_ENTRIES)
 			return 0;
 
-		sge = &sg[nents];
-		memset(sge, 0, sizeof(*sge));
-
-		if (bh->b_page) {
-			sge->page = bh->b_page;
-			sge->offset = bh_offset(bh);
-		} else {
-			if (((unsigned long) bh->b_data) < PAGE_SIZE)
-				BUG();
-
-			sge->address = bh->b_data;
+		while ((bh = bh->b_reqnext) != NULL) {
+			if ((virt_addr + size) != (unsigned char *) bh->b_data)
+				break;
+			size += bh->b_size;
 		}
-
-		sge->length = bh->b_size;
-		lastdataend = bh_phys(bh) + bh->b_size;
+		memset(&sg[nents], 0, sizeof(*sg));
+		sg[nents].address = virt_addr;
+		sg[nents].length = size;
+		if(size == 0)
+			BUG();
 		nents++;
-	} while ((bh = bh->b_reqnext) != NULL);
+	} while (bh != NULL);
 
-	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
+	if(nents == 0)
+		BUG();
+		
+	hwif->sg_dma_direction = ddir;
+	return pci_map_sg(hwif->pci_dev, sg, nents, ddir);
 }
 
 static int ide_raw_build_sglist (ide_hwif_t *hwif, struct request *rq)
@@ -308,16 +259,14 @@
 	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->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA) ||
-//	    (args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA_EXT))
 	if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
 		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
 	else
 		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
-	
+#if 1
 	if (sector_count > 128) {
 		memset(&sg[nents], 0, sizeof(*sg));
 		sg[nents].address = virt_addr;
@@ -330,7 +279,20 @@
 	sg[nents].address = virt_addr;
 	sg[nents].length =  sector_count  * SECTOR_SIZE;
 	nents++;
-   
+#else
+        while (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++;
+#endif
 	return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction);
 }
 
@@ -339,28 +301,25 @@
  * 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, int ddir)
 {
-	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->cmd == IDE_DRIVE_TASKFILE)
-		HWIF(drive)->sg_nents = i = ide_raw_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
+	if (rq->cmd == IDE_DRIVE_TASKFILE)
+		hwif->sg_nents = i = ide_raw_build_sglist(hwif, rq);
 	else
-		HWIF(drive)->sg_nents = i = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq);
+		hwif->sg_nents = i = ide_build_sglist(hwif, rq, ddir);
 
 	if (!i)
 		return 0;
 
-	sg = HWIF(drive)->sg_table;
-	while (i) {
+	sg = hwif->sg_table;
+	while (i && sg_dma_len(sg)) {
 		u32 cur_addr;
 		u32 cur_len;
 
@@ -374,35 +333,36 @@
 		 */
 
 		while (cur_len) {
-			u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
-			
-			if (count++ >= PRD_ENTRIES)
-				BUG();
-
-			if (bcount > cur_len)
-				bcount = cur_len;
-			*table++ = cpu_to_le32(cur_addr);
-			xcount = bcount & 0xffff;
-			if (is_trm290_chipset)
-				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.
-				 */
-				if (count++ >= PRD_ENTRIES)
-					goto use_pio_instead;
-
-				*table++ = cpu_to_le32(0x8000);
-				*table++ = cpu_to_le32(cur_addr + 0x8000);
-				xcount = 0x8000;
+			if (count++ >= PRD_ENTRIES) {
+				printk("%s: DMA table too small\n", drive->name);
+				goto use_pio_instead;
+			} else {
+				u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);
+
+				if (bcount > cur_len)
+					bcount = cur_len;
+				*table++ = cpu_to_le32(cur_addr);
+				xcount = bcount & 0xffff;
+				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.
+	 */
+					if (count++ >= PRD_ENTRIES) {
+						printk("%s: DMA table too small\n", drive->name);
+						goto use_pio_instead;
+					}
+					*table++ = cpu_to_le32(0x8000);
+					*table++ = cpu_to_le32(cur_addr + 0x8000);
+					xcount = 0x8000;
+				}
+				*table++ = cpu_to_le32(xcount);
+				cur_addr += bcount;
+				cur_len -= bcount;
 			}
-			*table++ = cpu_to_le32(xcount);
-			cur_addr += bcount;
-			cur_len -= bcount;
 		}
 
 		sg++;
@@ -410,20 +370,22 @@
 	}
 
 	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 */
 }
 
+EXPORT_SYMBOL_GPL(ide_build_dmatable);
+
 /* Teardown mappings after DMA has completed.  */
 void ide_destroy_dmatable (ide_drive_t *drive)
 {
@@ -435,336 +397,448 @@
 	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;
-}
+EXPORT_SYMBOL_GPL(ide_destroy_dmatable);
 
 static int config_drive_for_dma (ide_drive_t *drive)
 {
-	int config_allows_dma = 1;
 	struct hd_driveid *id = drive->id;
 	ide_hwif_t *hwif = HWIF(drive);
 
-#ifdef CONFIG_IDEDMA_ONLYDISK
-	if (drive->media != ide_disk)
-		config_allows_dma = 0;
-#endif
-
-	if (id && (id->capability & 1) && hwif->autodma && config_allows_dma) {
+	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 CONFIG_BLK_DEV_IDEDMA_TIMEOUT
 /*
  * 1 dmaing, 2 error, 4 intr
  */
 static int dma_timer_expiry (ide_drive_t *drive)
 {
-	byte dma_stat = inb(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 ide_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 /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
-static ide_startstop_t ide_dma_timeout_revovery (ide_drive_t *drive)
+
+static void ide_toggle_bounce(ide_drive_t *drive, int on)
+{
+	u64 addr = BLK_BOUNCE_HIGH;	/* dma64_addr_t */
+
+	if (on && drive->media == ide_disk) {
+		if (!PCI_DMA_BUS_IS_PHYS)
+			addr = BLK_BOUNCE_ANY;
+		else
+			addr = HWIF(drive)->pci_dev->dma_mask;
+	}
+
+	blk_queue_bounce_limit(&drive->queue, addr);
+}
+
+int __ide_dma_host_off (ide_drive_t *drive)
 {
-	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
 	ide_hwif_t *hwif	= HWIF(drive);
-	int enable_dma		= drive->using_dma;
-	unsigned long flags;
-	ide_startstop_t startstop;
-
-	spin_lock_irqsave(&io_request_lock, flags);
-	hwgroup->handler = NULL;
-	del_timer(&hwgroup->timer);
-	spin_unlock_irqrestore(&io_request_lock, flags);
+	u8 unit			= (drive->select.b.unit & 0x01);
+	u8 dma_stat		= hwif->INB(hwif->dma_status);
 
-	drive->waiting_for_dma = 0;
+	hwif->OUTB((dma_stat & ~(1<<(5+unit))), hwif->dma_status);
+	return 0;
+}
 
-	startstop = ide_do_reset(drive);
+EXPORT_SYMBOL(__ide_dma_host_off);
 
-	if ((enable_dma) && !(drive->using_dma))
-		(void) hwif->dmaproc(ide_dma_on, drive);
+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);
+}
 
-	return startstop;
+EXPORT_SYMBOL(__ide_dma_off_quietly);
+
+int __ide_dma_off (ide_drive_t *drive)
+{
+	printk("%s: DMA disabled\n", drive->name);
+	return HWIF(drive)->ide_dma_off_quietly(drive);
 }
-#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
 
-static inline void ide_toggle_bounce(ide_drive_t *drive, int on)
+EXPORT_SYMBOL(__ide_dma_off);
+
+int __ide_dma_host_on (ide_drive_t *drive)
 {
-	dma64_addr_t addr = BLK_BOUNCE_HIGH;
+	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);
 
-	if (HWIF(drive)->no_highio || HWIF(drive)->pci_dev == NULL)
-		return;
+		hwif->OUTB((dma_stat|(1<<(5+unit))), hwif->dma_status);
+		return 0;
+	}
+	return 1;
+}
 
-	if (on && drive->media == ide_disk) {
-		if (!PCI_DMA_BUS_IS_PHYS)
-			addr = BLK_BOUNCE_ANY;
-		else
-			addr = HWIF(drive)->pci_dev->dma_mask;
+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);
+}
+
+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);
+	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, PCI_DMA_FROMDEVICE)))
+		/* 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 = 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);
 
-	blk_queue_bounce_limit(&drive->queue, addr);
+	return HWIF(drive)->ide_dma_count(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_read);
+
+int __ide_dma_write (ide_drive_t *drive /*, struct request *rq */)
 {
-//	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
-	ide_hwif_t *hwif		= HWIF(drive);
-	unsigned long dma_base		= hwif->dma_base;
-	byte unit			= (drive->select.b.unit & 0x01);
-	unsigned int count, reading = 0, set_high = 1;
-	byte dma_stat;
-
-	switch (func) {
-		case ide_dma_off:
-			printk("%s: DMA disabled\n", drive->name);
-		case ide_dma_off_quietly:
-			set_high = 0;
-			outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-		case ide_dma_on:
-			drive->using_dma = (func == ide_dma_on);
-			if (drive->using_dma)
-				outb(inb(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)))
-				return 1;	/* try PIO instead of DMA */
-			outl(hwif->dmatable_dma, dma_base + 4); /* PRD table */
-			outb(reading, dma_base);			/* specify r/w */
-			outb(inb(dma_base+2)|6, dma_base+2);		/* clear INTR & ERROR flags */
-			drive->waiting_for_dma = 1;
-			if (drive->media != ide_disk)
-				return 0;
-#ifdef CONFIG_BLK_DEV_IDEDMA_TIMEOUT
-			ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL);	/* issue cmd to drive */
-#else /* !CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
-			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry);	/* issue cmd to drive */
-#endif /* CONFIG_BLK_DEV_IDEDMA_TIMEOUT */
-			if ((HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) &&
-			    (drive->addressing == 1)) {
-				ide_task_t *args = HWGROUP(drive)->rq->special;
-				OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
-			} else if (drive->addressing) {
-				OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
-			} else {
-				OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-			}
-			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.
-			 */
-			outb(inb(dma_base)|1, dma_base);		/* start DMA */
-			return 0;
-		case ide_dma_end: /* returns 1 on error, 0 otherwise */
-			drive->waiting_for_dma = 0;
-			outb(inb(dma_base)&~1, dma_base);	/* stop DMA */
-			dma_stat = inb(dma_base+2);		/* get DMA status */
-			outb(dma_stat|6, dma_base+2);	/* clear the INTR & ERROR bits */
-			ide_destroy_dmatable(drive);	/* purge DMA mappings */
-			return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;	/* verify good DMA status */
-		case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */
-			dma_stat = inb(dma_base+2);
+	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, PCI_DMA_TODEVICE)))
+		/* 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 = 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 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) {
-				byte stat = GET_STAT();
-				outb(dma_base+2, dma_stat & 0xE4);
-			}
+	if (dma_stat & 4) {
+		u8 stat = hwif->INB(IDE_STATUS_REG);
+		hwif->OUTB(hwif->dma_status, dma_stat & 0xE4);
+	}
 #endif
-			return (dma_stat & 4) == 4;	/* return 1 if INTR asserted */
-		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 CONFIG_BLK_DEV_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.
-			 */
-			outb(0x00, dma_base);		/* stop DMA */
-			dma_stat = inb(dma_base+2);	/* get DMA status */
-			outb(dma_stat|6, dma_base+2);	/* clear the INTR & ERROR bits */
-			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_revovery(drive);
-
-			printk("%s: %s: (restart_request) Lets do it again!" \
-				"stat = 0x%02x, dma_stat = 0x%02x\n",
-				drive->name, ide_dmafunc_verbose(func),
-				GET_STAT(), dma_stat);
-
-			return restart_request(drive);  // BUG: return types do not match!!
-//#else
-//			return HWGROUP(drive)->handler(drive);
-#endif /* CONFIG_BLK_DEV_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);
+	/* 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);
+
 /*
- * Needed for allowing full modular support of ide-driver
+ * Used for HOST FIFO counters for VDMA
+ * PIO over DMA, effective ATA-Bridge operator.
  */
-int ide_release_dma (ide_hwif_t *hwif)
+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);
+
+void ide_release_dma_engine (ide_hwif_t *hwif)
 {
 	if (hwif->dmatable_cpu) {
 		pci_free_consistent(hwif->pci_dev,
@@ -777,128 +851,190 @@
 		kfree(hwif->sg_table);
 		hwif->sg_table = NULL;
 	}
+}
+
+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)
 {
-	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;
+	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)
+{
+	hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
+						  PRD_ENTRIES * PRD_BYTES,
+						  &hwif->dmatable_dma);
 	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 = inb(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;
+/*
+ * 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;
 
-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;
-		}
+	if (ide_allocate_dma_engine(hwif)) {
+		ide_release_dma(hwif);
+		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;
-	}
-#endif /* CONFIG_BLK_DEV_IDEDMA_FORCED */
+	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 (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:
-				outb(inb(dma_base+2) & 0x60, dma_base+2);
-				if (inb(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 ((inb(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->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();
 }
+
+EXPORT_SYMBOL_GPL(ide_setup_dma);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-features.c linux.20pre10-ac2/drivers/ide/ide-features.c
--- linux.20pre10/drivers/ide/ide-features.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-features.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,385 +0,0 @@
-/*
- * linux/drivers/block/ide-features.c	Version 0.04	June 9, 2000
- *
- *  Copyright (C) 1999-2000	Linus Torvalds & authors (see below)
- *  
- *  Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
- *
- *  Extracts if ide.c to address the evolving transfer rate code for
- *  the SETFEATURES_XFER callouts.  Various parts of any given function
- *  are credited to previous ATA-IDE maintainers.
- *
- *  Auto-CRC downgrade for Ultra DMA(ing)
- *
- *  May be copied or modified under the terms of the GNU General Public License
- */
-
-#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>
-
-/*
- * A Verbose noise maker for debugging on the attempted transfer rates.
- */
-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");
-	}
-}
-
-/*
- *
- */
-char *ide_media_verbose (ide_drive_t *drive)
-{
-	switch (drive->media) {
-		case ide_scsi:		return("scsi   ");
-		case ide_disk:		return("disk   ");
-		case ide_optical:	return("optical");
-		case ide_cdrom:		return("cdrom  ");
-		case ide_tape:		return("tape   ");
-		case ide_floppy:	return("floppy ");
-		default:		return("???????");
-	}
-}
-
-/*
- * A Verbose noise maker for debugging on the attempted dmaing calls.
- */
-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_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");
-	}
-}
-
-/*
- *
- */
-byte 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;
-	}
-}
-
-/*
- * Update the 
- */
-int ide_driveid_update (ide_drive_t *drive)
-{
-	/*
-	 * Re-read drive->id for possible DMA mode
-	 * change (copied from ide-probe.c)
-	 */
-	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 (0 < (signed long)(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;
-	}
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only; some systems need this */
-	SELECT_MASK(HWIF(drive), drive, 0);
-	id = kmalloc(SECTOR_WORDS*4, GFP_ATOMIC);
-	if (!id) {
-		__restore_flags(flags);	/* local CPU only */
-		return 0;
-	}
-	ide_input_data(drive, id, SECTOR_WORDS);
-	(void) GET_STAT();	/* clear drive IRQ */
-	ide__sti();		/* local CPU only */
-	__restore_flags(flags);	/* local CPU only */
-	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;
-}
-
-/*
- * Verify that we are doing an approved SETFEATURES_XFER with respect
- * to the hardware being able to support request.  Since some hardware
- * can improperly report capabilties, we check to see if the host adapter
- * in combination with the device (usually a disk) properly detect
- * and acknowledge each end of the ribbon.
- */
-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)) {
-		if (!HWIF(drive)->udma_four) {
-			printk("%s: Speed warnings UDMA 3/4/5 is not functional.\n", HWIF(drive)->name);
-			return 1;
-		}
-#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;
-		}
-	}
-	return 0;
-}
-
-/*
- * 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;
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- *  All hosts that use the 80c ribbon mus use!
- */
-byte eighty_ninty_three (ide_drive_t *drive)
-{
-#ifdef CONFIG_BLK_DEV_IDEPCI
-	if (HWIF(drive)->pci_devid.vid==0x105a)
-	    return(HWIF(drive)->udma_four);
-#endif
-	/* PDC202XX: that's because some HDD will return wrong info */
-	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 // CONFIG_BLK_DEV_IDEDMA
-
-/*
- * 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_hwif_t *hwif = HWIF(drive);
-	int	i, error = 1;
-	byte stat;
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
-	byte unit = (drive->select.b.unit & 0x01);
-	outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2);
-#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(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;
-		__save_flags(flags);	/* local CPU only */
-		ide__sti();		/* local CPU only -- for jiffies */
-		timeout = jiffies + WAIT_CMD;
-		while ((stat = GET_STAT()) & BUSY_STAT) {
-			if (0 < (signed long)(jiffies - timeout))
-				break;
-		}
-		__restore_flags(flags); /* local CPU only */
-	}
-
-	/*
-	 * 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;
-		}
-	}
-
-	SELECT_MASK(HWIF(drive), 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_PIO_4) {
-		outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2);
-	} else {
-		outb(inb(hwif->dma_base+2) & ~(1<<(5+unit)), hwif->dma_base+2);
-	}
-#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;
-	}
-	return error;
-}
-
-EXPORT_SYMBOL(ide_auto_reduce_xfer);
-EXPORT_SYMBOL(ide_driveid_update);
-EXPORT_SYMBOL(ide_ata66_check);
-EXPORT_SYMBOL(set_transfer);
-#ifdef CONFIG_BLK_DEV_IDEDMA
-EXPORT_SYMBOL(eighty_ninty_three);
-#endif // CONFIG_BLK_DEV_IDEDMA
-EXPORT_SYMBOL(ide_config_drive_speed);
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-floppy.c linux.20pre10-ac2/drivers/ide/ide-floppy.c
--- linux.20pre10/drivers/ide/ide-floppy.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-floppy.c	2002-09-06 14:05:58.000000000 +0100
@@ -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 */
@@ -349,20 +361,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))
 
 /*
  *	Error codes which are returned in rq->errors to the higher part
@@ -371,170 +383,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.
  */
@@ -668,32 +516,61 @@
 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(&io_request_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->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		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(&io_request_lock, flags);
+	return ret;
+}
+
 /*
- *	idefloppy_end_request is used to finish servicing a request.
+ *	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 void idefloppy_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
+static int idefloppy_do_end_request (ide_drive_t *drive, int uptodate)
 {
-	ide_drive_t *drive = hwgroup->drive;
 	idefloppy_floppy_t *floppy = drive->driver_data;
-	struct request *rq = hwgroup->rq;
+	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) {
@@ -705,13 +582,16 @@
 		floppy->failed_pc = NULL;
 	/* Why does this happen? */
 	if (!rq)
-		return;
-	if (!IDEFLOPPY_RQ_CMD (rq->cmd)) {
-		ide_end_request (uptodate, hwgroup);
-		return;
+		return 0;
+	if (!IDEFLOPPY_RQ_CMD(rq->cmd)) {
+		/* our real local end request function */
+		idefloppy_end_request(drive, uptodate);
+		return 0;
 	}
 	rq->errors = error;
-	ide_end_drive_cmd (drive, 0, 0);
+	/* fixme: need to move this local also */
+	ide_end_drive_cmd(drive, 0, 0);
+	return 0;
 }
 
 static void idefloppy_input_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
@@ -724,18 +604,21 @@
 		if (pc->b_count == bh->b_size) {
 			rq->sector += rq->current_nr_sectors;
 			rq->nr_sectors -= rq->current_nr_sectors;
-			idefloppy_end_request (1, HWGROUP(drive));
+			idefloppy_do_end_request(drive, 1);
 			if ((bh = rq->bh) != NULL)
 				pc->b_count = 0;
 		}
 		if (bh == NULL) {
-			printk (KERN_ERR "%s: bh == NULL in idefloppy_input_buffers, bcount == %d\n", drive->name, bcount);
-			idefloppy_discard_data (drive, bcount);
+			printk(KERN_ERR "%s: bh == NULL in "
+				"idefloppy_input_buffers, bcount == %d\n",
+				drive->name, bcount);
+			idefloppy_discard_data(drive, bcount);
 			return;
 		}
-		count = IDEFLOPPY_MIN (bh->b_size - pc->b_count, bcount);
-		atapi_input_bytes (drive, bh->b_data + pc->b_count, count);
-		bcount -= count; pc->b_count += count;
+		count = IDEFLOPPY_MIN(bh->b_size - pc->b_count, bcount);
+		HWIF(drive)->atapi_input_bytes(drive, bh->b_data + pc->b_count, count);
+		bcount -= count;
+		pc->b_count += count;
 	}
 }
 
@@ -749,20 +632,24 @@
 		if (!pc->b_count) {
 			rq->sector += rq->current_nr_sectors;
 			rq->nr_sectors -= rq->current_nr_sectors;
-			idefloppy_end_request (1, HWGROUP(drive));
+			idefloppy_do_end_request(drive, 1);
 			if ((bh = rq->bh) != NULL) {
 				pc->b_data = bh->b_data;
 				pc->b_count = bh->b_size;
 			}
 		}
 		if (bh == NULL) {
-			printk (KERN_ERR "%s: bh == NULL in idefloppy_output_buffers, bcount == %d\n", drive->name, bcount);
+			printk(KERN_ERR "%s: bh == 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);
+		HWIF(drive)->atapi_output_bytes(drive, pc->b_data, count);
+		bcount -= count;
+		pc->b_data += count;
+		pc->b_count -= count;
 	}
 }
 
@@ -773,7 +660,7 @@
 	struct buffer_head *bh = rq->bh;
 
 	while ((bh = rq->bh) != NULL)
-		idefloppy_end_request (1, HWGROUP(drive));
+		idefloppy_do_end_request(drive, 1);
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -784,17 +671,17 @@
  */
 static void idefloppy_queue_pc_head (ide_drive_t *drive,idefloppy_pc_t *pc,struct request *rq)
 {
-	ide_init_drive_cmd (rq);
-	rq->buffer = (char *) pc;
+	ide_init_drive_cmd(rq);
+	rq->buffer = (char *)pc;
 	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++]);
 }
@@ -803,8 +690,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++]);
 }
 
@@ -816,14 +703,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 */
 }
 
@@ -832,14 +725,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_end_request (1,HWGROUP (drive));
+		idefloppy_analyze_error(drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer);
+		idefloppy_do_end_request(drive, 1);
 	} else {
-		printk (KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
-		idefloppy_end_request (0,HWGROUP (drive));
+		printk(KERN_ERR "Error in REQUEST SENSE itself - Aborting request!\n");
+		idefloppy_do_end_request(drive, 0);
 	}
 }
 
@@ -851,10 +744,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_end_request (floppy->pc->error ? 0:1, HWGROUP(drive));
+	idefloppy_do_end_request(drive, floppy->pc->error ? 0 : 1);
 }
 
 /*
@@ -862,7 +755,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;
@@ -874,7 +767,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;
@@ -890,13 +783,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);
 }
 
 /*
@@ -906,24 +799,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");
@@ -931,83 +825,116 @@
 	}
 #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);
 
-		ide__sti();	/* local CPU only */
+		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);
-				ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);
+				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);
 				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;
-
-	ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
+	/* Update the current position */
+	pc->actually_transferred += bcount.all;
+	pc->current_position += bcount.all;
+
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL);		/* And set the interrupt handler again */
 	return ide_started;
 }
 
@@ -1020,19 +947,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)) {
-		printk (KERN_ERR "ide-floppy: 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-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);
-	}
-	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 */
+		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while "
+				"issuing a packet command\n");
+		return ide_do_reset(drive);
+	}
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	/* 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;
 }
 
@@ -1053,35 +986,42 @@
 {
 	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)) {
-		printk (KERN_ERR "ide-floppy: 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-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);
+		printk(KERN_ERR "ide-floppy: (IO,CoD) != (0,1) "
+				"while issuing a packet command\n");
+		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.
 	 */
-	ide_set_handler (drive, 
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	ide_set_handler(drive, 
 	  &idefloppy_pc_intr, 		/* service routine for packet command */
-	  floppy->ticks,			/* wait this long before "failing" */
+	  floppy->ticks,		/* wait this long before "failing" */
 	  &idefloppy_transfer_pc2);	/* fail == transfer_pc2 */
 	return ide_started;
 }
@@ -1092,81 +1032,109 @@
 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)) {
-				;
-      printk( KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
-				drive->name, pc->c[0], floppy->sense_key, floppy->asc, floppy->ascq);
+		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",
+						drive->name, pc->c[0],
+						floppy->sense_key,
+						floppy->asc, floppy->ascq);
 			}
-			pc->error = IDEFLOPPY_ERROR_GENERAL;		/* Giving up */
+			/* 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 = IDE_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)) {
-		ide_set_handler (drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL);
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */
+	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);
+		/* 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);
 	}
 }
@@ -1177,24 +1145,25 @@
 	printk (KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n");
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
-	idefloppy_end_request(1, HWGROUP(drive));
+	idefloppy_do_end_request(drive, 1);
 	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;
@@ -1204,13 +1173,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 */
@@ -1225,11 +1194,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);
@@ -1242,15 +1211,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;
 }
@@ -1267,28 +1237,29 @@
 	int blocks = rq->nr_sectors / floppy->bs_factor;
 	
 #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] = rq->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] = rq->cmd == READ ? IDEFLOPPY_READ10_CMD : IDEFLOPPY_WRITE10_CMD;
-		put_unaligned (htons (blocks), (unsigned short *) &pc->c[7]);
+		put_unaligned(htons(blocks), (u16 *) &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 = rq->cmd == READ ? 0 : rq->bh->b_size;
 	if (rq->cmd == WRITE)
-		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);
 }
 
 /*
@@ -1300,40 +1271,49 @@
 	idefloppy_pc_t *pc;
 
 #if IDEFLOPPY_DEBUG_LOG
-	printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
-	printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+	printk(KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",
+		rq->rq_status, (unsigned int) rq->rq_dev, rq->cmd, rq->errors);
+	printk(KERN_INFO "sector: %ld, nr_sectors: %ld, "
+			"current_nr_sectors: %ld\n", rq->sector,
+			rq->nr_sectors, rq->current_nr_sectors);
 #endif /* IDEFLOPPY_DEBUG_LOG */
 
 	if (rq->errors >= ERROR_MAX) {
 		if (floppy->failed_pc != NULL)
-			printk (KERN_ERR "ide-floppy: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
-				drive->name, floppy->failed_pc->c[0], floppy->sense_key, floppy->asc, floppy->ascq);
+			printk(KERN_ERR "ide-floppy: %s: I/O error, pc = %2x,"
+					" key = %2x, asc = %2x, ascq = %2x\n",
+				drive->name, floppy->failed_pc->c[0],
+				floppy->sense_key, floppy->asc, floppy->ascq);
 		else
-			printk (KERN_ERR "ide-floppy: %s: I/O error\n", drive->name);
-		idefloppy_end_request (0, HWGROUP(drive));
+			printk(KERN_ERR "ide-floppy: %s: I/O error\n",
+				drive->name);
+		idefloppy_do_end_request(drive, 0);
 		return ide_stopped;
 	}
 	switch (rq->cmd) {
 		case READ:
 		case WRITE:
-			if (rq->sector % floppy->bs_factor || rq->nr_sectors % floppy->bs_factor) {
-				printk ("%s: unsupported r/w request size\n", drive->name);
-				idefloppy_end_request (0, HWGROUP(drive));
+			if (rq->sector % floppy->bs_factor ||
+			    rq->nr_sectors % floppy->bs_factor) {
+				printk("%s: unsupported r/w request size\n",
+					drive->name);
+				idefloppy_do_end_request(drive, 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);
 			break;
 		case IDEFLOPPY_PC_RQ:
 			pc = (idefloppy_pc_t *) rq->buffer;
 			break;
 		default:
-			printk (KERN_ERR "ide-floppy: unsupported command %x in request queue\n", rq->cmd);
-			idefloppy_end_request (0,HWGROUP (drive));
+			printk(KERN_ERR "ide-floppy: unsupported command %x"
+				" in request queue\n", rq->cmd);
+			idefloppy_do_end_request(drive, 0);
 			return ide_stopped;
 	}
 	pc->rq = rq;
-	return idefloppy_issue_pc (drive, pc);
+	return idefloppy_issue_pc(drive, pc);
 }
 
 /*
@@ -1344,10 +1324,10 @@
 {
 	struct request rq;
 
-	ide_init_drive_cmd (&rq);
+	ide_init_drive_cmd(&rq);
 	rq.buffer = (char *) pc;
 	rq.cmd = IDEFLOPPY_PC_RQ;
-	return ide_do_drive_cmd (drive, &rq, ide_wait);
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
 /*
@@ -1362,23 +1342,26 @@
 	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, %d sector size, %d rpm\n",
-			drive->name, capacity / 1024, page->cyls, page->heads, page->sectors,
+		printk(KERN_INFO "%s: %dkB, %d/%d/%d CHS, %d kBps, "
+				"%d sector size, %d rpm\n",
+			drive->name, capacity / 1024, page->cyls,
+			page->heads, page->sectors,
 			page->transfer_rate / 8, page->sector_size, page->rpm);
 
 	floppy->flexible_disk_page = *page;
@@ -1387,8 +1370,8 @@
 	drive->bios_sect = page->sectors;
 	lba_capacity = floppy->blocks * floppy->block_size;
 	if (capacity < lba_capacity) {
-		printk (KERN_NOTICE "%s: The disk reports a capacity of %d bytes, "
-			"but the drive only handles %d\n",
+		printk(KERN_NOTICE "%s: The disk reports a capacity of %d "
+			"bytes, but the drive only handles %d\n",
 			drive->name, lba_capacity, capacity);
 		floppy->blocks = floppy->block_size ? capacity / floppy->block_size : 0;
 	}
@@ -1402,18 +1385,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);
 }
 
@@ -1434,58 +1417,76 @@
 	floppy->blocks = floppy->bs_factor = 0;
 	drive->part[0].nr_sects = 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);
+        if (!test_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags)) {
+		(void) idefloppy_get_flexible_disk_page(drive);
 	}
 
 	drive->part[0].nr_sects = floppy->blocks * floppy->bs_factor;
@@ -1532,18 +1533,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
@@ -1551,18 +1552,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))
@@ -1603,19 +1603,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);
 }
 
@@ -1636,35 +1636,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;
 
-		__save_flags(flags);
-		__cli();
-		status.all=GET_STAT();
-		__restore_flags(flags);
+		local_irq_save(flags);
+		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);
@@ -1694,12 +1689,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:
@@ -1715,16 +1710,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,
@@ -1763,7 +1755,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;
@@ -1773,8 +1765,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)
@@ -1795,16 +1787,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_rdev);
-	}
-	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;
@@ -1823,12 +1813,12 @@
 	if (!drive->usage) {
 		idefloppy_floppy_t *floppy = drive->driver_data;
 
-		invalidate_bdev (inode->i_bdev, 0);
+		invalidate_bdev(inode->i_bdev, 0);
 
 		/* 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);
@@ -1843,7 +1833,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);
 }
 
 /*
@@ -1875,109 +1865,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;
@@ -1999,7 +1994,6 @@
 	ide_add_setting(drive,	"file_readahead",	SETTING_RW,					BLKFRAGET,		BLKFRASET,		TYPE_INTA,	0,	INT_MAX,			1,	1024,	&max_readahead[major][minor],	NULL);
 	ide_add_setting(drive,	"max_kb_per_request",	SETTING_RW,					BLKSECTGET,		BLKSECTSET,		TYPE_INTA,	1,	255,				1,	2,	&max_sectors[major][minor],	NULL);
 	ide_add_setting(drive,	"ticks",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	255,				1,	1,	&floppy->ticks,		NULL);
-
 }
 
 /*
@@ -2011,14 +2005,14 @@
 	int major = HWIF(drive)->major, i;
 	int minor = drive->select.b.unit << PARTN_BITS;
 
-	*((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.
@@ -2030,8 +2024,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;
@@ -2044,15 +2037,14 @@
 	*      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) {
 		for (i = 0; i < 1 << PARTN_BITS; i++)
 			max_sectors[major][minor + i] = 64;
 		set_bit(IDEFLOPPY_CLIK_DRIVE, &floppy->flags);
 	}
 
 
-	(void) idefloppy_get_capacity (drive);
+	(void) idefloppy_get_capacity(drive);
 	idefloppy_add_settings(drive);
 	for (i = 0; i < MAX_DRIVES; ++i) {
 		ide_hwif_t *hwif = HWIF(drive);
@@ -2069,10 +2061,11 @@
 {
 	idefloppy_floppy_t *floppy = drive->driver_data;
 
-	if (ide_unregister_subdriver (drive))
+	if (ide_unregister_subdriver(drive))
 		return 1;
+
 	drive->driver_data = NULL;
-	kfree (floppy);
+	kfree(floppy);
 	return 0;
 }
 
@@ -2089,7 +2082,8 @@
 
 #endif	/* CONFIG_PROC_FS */
 
-int idefloppy_reinit(ide_drive_t *drive);
+int idefloppy_init (void);
+int idefloppy_attach(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -2099,13 +2093,21 @@
 	version:		IDEFLOPPY_VERSION,
 	media:			ide_floppy,
 	busy:			0,
+#ifdef CONFIG_IDEDMA_ONLYDISK
+	supports_dma:		0,
+#else
 	supports_dma:		1,
+#endif
 	supports_dsc_overlap:	0,
 	cleanup:		idefloppy_cleanup,
 	standby:		NULL,
+	suspend:		NULL,
+	resume:			NULL,
 	flushcache:		NULL,
 	do_request:		idefloppy_do_request,
-	end_request:		idefloppy_end_request,
+	end_request:		idefloppy_do_end_request,
+	sense:			NULL,
+	error:			NULL,
 	ioctl:			idefloppy_ioctl,
 	open:			idefloppy_open,
 	release:		idefloppy_release,
@@ -2115,12 +2117,12 @@
 	capacity:		idefloppy_capacity,
 	special:		NULL,
 	proc:			idefloppy_proc,
-	reinit:			idefloppy_reinit,
+	init:			idefloppy_init,
+	attach:			idefloppy_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 };
 
-int idefloppy_init (void);
 static ide_module_t idefloppy_module = {
 	IDE_DRIVER_MODULE,
 	idefloppy_init,
@@ -2128,38 +2130,45 @@
 	NULL
 };
 
-int idefloppy_reinit (ide_drive_t *drive)
+int idefloppy_attach (ide_drive_t *drive)
 {
 	idefloppy_floppy_t *floppy;
-	int failed = 0;
+	int ret = 0;
 
 	MOD_INC_USE_COUNT;
-	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) {
-		if (!idefloppy_identify_device (drive, drive->id)) {
-			printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
-			continue;
-		}
-		if (drive->scsi) {
-			printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
-			continue;
-		}
-		if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
-			printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
-			continue;
-		}
-		if (ide_register_subdriver (drive, &idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
-			printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
-			kfree (floppy);
-			continue;
-		}
-		DRIVER(drive)->busy++;
-		idefloppy_setup (drive, floppy);
-		DRIVER(drive)->busy--;
-		failed--;
-	}
-	ide_register_module(&idefloppy_module);
+	if (!idefloppy_identify_device(drive, drive->id)) {
+		printk(KERN_ERR "ide-floppy: %s: not supported by this "
+			"version of ide-floppy\n", drive->name);
+			ret = 1;
+			goto bye_game_over;
+	}
+	if (drive->scsi) {
+		printk("ide-floppy: passing drive %s to ide-scsi "
+			"emulation.\n", drive->name);
+		ret = 1;
+		goto bye_game_over;
+	}
+	if ((floppy = (idefloppy_floppy_t *) kmalloc(sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
+		printk(KERN_ERR "ide-floppy: %s: Can't allocate a floppy "
+			"structure\n", drive->name);
+		ret = 1;
+		goto bye_game_over;
+	}
+	if (ide_register_subdriver(drive,
+			&idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
+		printk(KERN_ERR "ide-floppy: %s: Failed to register the "
+			"driver with ide.c\n", drive->name);
+		kfree(floppy);
+		ret = 1;
+		goto bye_game_over;
+	}
+	DRIVER(drive)->busy++;
+	idefloppy_setup(drive, floppy);
+	DRIVER(drive)->busy--;
+
+bye_game_over:
 	MOD_DEC_USE_COUNT;
-	return 0;
+	return ret;
 }
 
 MODULE_DESCRIPTION("ATAPI FLOPPY Driver");
@@ -2169,9 +2178,11 @@
 	ide_drive_t *drive;
 	int failed = 0;
 
-	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, &idefloppy_driver, failed)) != NULL) {
-		if (idefloppy_cleanup (drive)) {
-			printk ("%s: cleanup_module() called while still busy\n", drive->name);
+	while ((drive = ide_scan_devices(ide_floppy, idefloppy_driver.name,
+			&idefloppy_driver, failed)) != NULL) {
+		if (idefloppy_cleanup(drive)) {
+			printk("%s: cleanup_module() called while still "
+				"busy\n", drive->name);
 			failed++;
 		}
 		/* We must remove proc entries defined in this module.
@@ -2184,40 +2195,47 @@
 	ide_unregister_module(&idefloppy_module);
 }
 
-/*
- *	idefloppy_init will register the driver for each floppy.
- */
 int idefloppy_init (void)
 {
+#ifdef CLASSIC_BUILTINS_METHOD
 	ide_drive_t *drive;
 	idefloppy_floppy_t *floppy;
 	int failed = 0;
 
 	printk("ide-floppy driver " IDEFLOPPY_VERSION "\n");
+#endif /* CLASSIC_BUILTINS_METHOD */
 	MOD_INC_USE_COUNT;
-	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) {
-		if (!idefloppy_identify_device (drive, drive->id)) {
-			printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name);
+#ifdef CLASSIC_BUILTINS_METHOD
+	while ((drive = ide_scan_devices(ide_floppy,
+			idefloppy_driver.name, NULL, failed++)) != NULL) {
+		if (!idefloppy_identify_device(drive, drive->id)) {
+			printk(KERN_ERR "ide-floppy: %s: not supported by "
+				"this version of ide-floppy\n", drive->name);
 			continue;
 		}
 		if (drive->scsi) {
-			printk("ide-floppy: passing drive %s to ide-scsi emulation.\n", drive->name);
-			continue;
-		}
-		if ((floppy = (idefloppy_floppy_t *) kmalloc (sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
-			printk (KERN_ERR "ide-floppy: %s: Can't allocate a floppy structure\n", drive->name);
+			printk("ide-floppy: passing drive %s to ide-scsi "
+				"emulation.\n", drive->name);
 			continue;
 		}
-		if (ide_register_subdriver (drive, &idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
-			printk (KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
-			kfree (floppy);
+		if ((floppy = (idefloppy_floppy_t *) kmalloc(sizeof (idefloppy_floppy_t), GFP_KERNEL)) == NULL) {
+			printk(KERN_ERR "ide-floppy: %s: Can't allocate a "
+				"floppy structure\n", drive->name);
 			continue;
 		}
+		if (ide_register_subdriver(drive,
+				&idefloppy_driver, IDE_SUBDRIVER_VERSION)) {
+			printk(KERN_ERR "ide-floppy: %s: Failed to register "
+				"the driver with ide.c\n", drive->name);
+			kfree(floppy);
+                        continue;
+                }
 		DRIVER(drive)->busy++;
-		idefloppy_setup (drive, floppy);
+		idefloppy_setup(drive, floppy);
 		DRIVER(drive)->busy--;
 		failed--;
 	}
+#endif /* CLASSIC_BUILTINS_METHOD */
 	ide_register_module(&idefloppy_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-geometry.c linux.20pre10-ac2/drivers/ide/ide-geometry.c
--- linux.20pre10/drivers/ide/ide-geometry.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-geometry.c	2002-09-06 14:23:56.000000000 +0100
@@ -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,13 +23,11 @@
  * 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 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 @@
 	drive->part[0].nr_sects = 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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-iops.c linux.20pre10-ac2/drivers/ide/ide-iops.c
--- linux.20pre10/drivers/ide/ide-iops.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-iops.c	2002-09-18 20:32:25.000000000 +0100
@@ -0,0 +1,1252 @@
+/*
+ * 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 u8 ide_inb (u32 port)
+{
+	return (u8) inb(port);
+}
+
+static u16 ide_inw (u32 port)
+{
+	return (u16) inw(port);
+}
+
+static void ide_insw (u32 port, void *addr, u32 count)
+{
+	return insw(port, addr, count);
+}
+
+static u32 ide_inl (u32 port)
+{
+	return (u32) inl(port);
+}
+
+static void ide_insl (u32 port, void *addr, u32 count)
+{
+	insl(port, addr, count);
+}
+
+static void ide_outb (u8 addr, u32 port)
+{
+	outb(addr, port);
+}
+
+static void ide_outw (u16 addr, u32 port)
+{
+	outw(addr, port);
+}
+
+static void ide_outsw (u32 port, void *addr, u32 count)
+{
+	outsw(port, addr, count);
+}
+
+static void ide_outl (u32 addr, u32 port)
+{
+	outl(addr, port);
+}
+
+static void ide_outsl (u32 port, void *addr, u32 count)
+{
+	return outsl(port, addr, count);
+}
+
+void default_hwif_iops (ide_hwif_t *hwif)
+{
+	hwif->OUTB	= ide_outb;
+	hwif->OUTW	= ide_outw;
+	hwif->OUTL	= ide_outl;
+	hwif->OUTSW	= ide_outsw;
+	hwif->OUTSL	= ide_outsl;
+	hwif->INB	= ide_inb;
+	hwif->INW	= ide_inw;
+	hwif->INL	= ide_inl;
+	hwif->INSW	= ide_insw;
+	hwif->INSL	= ide_insl;
+}
+
+EXPORT_SYMBOL(default_hwif_iops);
+
+static u8 ide_mm_inb (u32 port)
+{
+	return (u8) readb(port);
+}
+
+static u16 ide_mm_inw (u32 port)
+{
+	return (u16) readw(port);
+}
+
+static void ide_mm_insw (u32 port, void *addr, u32 count)
+{
+#ifdef CONFIG_PPC
+	/* Can we move the barrier out of the loop ? */
+	while (count--) { *(u16 *)addr = __raw_readw(port); iobarrier_r(); addr += 2; }
+#else /* everything else is sane benh */
+	while (count--) { *(u16 *)addr = readw(port); addr += 2; }
+#endif
+}
+
+static u32 ide_mm_inl (u32 port)
+{
+	return (u32) readl(port);
+}
+
+static void ide_mm_insl (u32 port, void *addr, u32 count)
+{
+#ifdef CONFIG_PPC
+	/* Can we move the barrier out of the loop ? */
+	while (count--) { *(u32 *)addr = __raw_readl(port); iobarrier_r(); addr += 4; }
+#else /* everything else is sane benh */
+	while (count--) { *(u32 *)addr = readl(port); addr += 4; }
+#endif
+}
+
+static void ide_mm_outb (u8 value, u32 port)
+{
+	writeb(value, port);
+}
+
+static void ide_mm_outw (u16 value, u32 port)
+{
+	writew(value, port);
+}
+
+static void ide_mm_outsw (u32 port, void *addr, u32 count)
+{
+#ifdef CONFIG_PPC
+	/* Can we move the barrier out of the loop ? */
+	while (count--) { __raw_writew(*(u16 *)addr, port); iobarrier_w(); addr += 2; }
+#else /* everything else is sane benh */
+	while (count--) { writew(*(u16 *)addr, port); addr += 2; }
+#endif
+}
+
+static void ide_mm_outl (u32 value, u32 port)
+{
+	writel(value, port);
+}
+
+static void ide_mm_outsl (u32 port, void *addr, u32 count)
+{
+#ifdef CONFIG_PPC
+	while (count--) { __raw_writel(*(u32 *)addr, port); iobarrier_w(); addr += 4; }
+#else /* everything else is sane benh */
+	while (count--) { writel(*(u32 *)addr, port); addr += 4; }
+#endif
+}
+
+void default_hwif_mmiops (ide_hwif_t *hwif)
+{
+	hwif->OUTB	= ide_mm_outb;
+	hwif->OUTW	= ide_mm_outw;
+	hwif->OUTL	= ide_mm_outl;
+	hwif->OUTSW	= ide_mm_outsw;
+	hwif->OUTSL	= ide_mm_outsl;
+	hwif->INB	= ide_mm_inb;
+	hwif->INW	= ide_mm_inw;
+	hwif->INL	= ide_mm_inl;
+	hwif->INSW	= ide_mm_insw;
+	hwif->INSL	= ide_mm_insl;
+}
+
+EXPORT_SYMBOL(default_hwif_mmiops);
+
+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);
+
+/*
+ * 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);
+
+/*
+ * 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 (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
+			hwif->INSL(IDE_DATA_REG, buffer, wcount);
+	} else {
+		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 (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
+			hwif->OUTSL(IDE_DATA_REG, buffer, wcount);
+	} else {
+		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(&io_request_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(&io_request_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(&io_request_lock, flags);
+		HWGROUP(drive)->handler = NULL;
+		del_timer(&HWGROUP(drive)->timer);
+		spin_unlock_irqrestore(&io_request_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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-lib.c linux.20pre10-ac2/drivers/ide/ide-lib.c
--- linux.20pre10/drivers/ide/ide-lib.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-lib.c	2002-09-11 00:50:42.000000000 +0100
@@ -0,0 +1,388 @@
+#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>
+
+#include "ide_modes.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);
+
+const ide_pio_timings_t ide_pio_timings[6] = {
+	{ 70,	165,	600 },	/* PIO Mode 0 */
+	{ 50,	125,	383 },	/* PIO Mode 1 */
+	{ 30,	100,	240 },	/* PIO Mode 2 */
+	{ 30,	80,	180 },	/* PIO Mode 3 with IORDY */
+	{ 25,	70,	120 },	/* PIO Mode 4 with IORDY */
+	{ 20,	50,	100 }	/* PIO Mode 5 with IORDY (nonstandard) */
+};
+
+EXPORT_SYMBOL_GPL(ide_pio_timings);
+
+/*
+ * Black list. Some drives incorrectly report their maximal PIO mode,
+ * at least in respect to CMD640. Here we keep info on some known drives.
+ */
+static struct ide_pio_info {
+	const char	*name;
+	int		pio;
+} ide_pio_blacklist [] = {
+/*	{ "Conner Peripherals 1275MB - CFS1275A", 4 }, */
+	{ "Conner Peripherals 540MB - CFS540A", 3 },
+
+	{ "WDC AC2700",  3 },
+	{ "WDC AC2540",  3 },
+	{ "WDC AC2420",  3 },
+	{ "WDC AC2340",  3 },
+	{ "WDC AC2250",  0 },
+	{ "WDC AC2200",  0 },
+	{ "WDC AC21200", 4 },
+	{ "WDC AC2120",  0 },
+	{ "WDC AC2850",  3 },
+	{ "WDC AC1270",  3 },
+	{ "WDC AC1170",  1 },
+	{ "WDC AC1210",  1 },
+	{ "WDC AC280",   0 },
+/*	{ "WDC AC21000", 4 }, */
+	{ "WDC AC31000", 3 },
+	{ "WDC AC31200", 3 },
+/*	{ "WDC AC31600", 4 }, */
+
+	{ "Maxtor 7131 AT", 1 },
+	{ "Maxtor 7171 AT", 1 },
+	{ "Maxtor 7213 AT", 1 },
+	{ "Maxtor 7245 AT", 1 },
+	{ "Maxtor 7345 AT", 1 },
+	{ "Maxtor 7546 AT", 3 },
+	{ "Maxtor 7540 AV", 3 },
+
+	{ "SAMSUNG SHD-3121A", 1 },
+	{ "SAMSUNG SHD-3122A", 1 },
+	{ "SAMSUNG SHD-3172A", 1 },
+
+/*	{ "ST51080A", 4 },
+ *	{ "ST51270A", 4 },
+ *	{ "ST31220A", 4 },
+ *	{ "ST31640A", 4 },
+ *	{ "ST32140A", 4 },
+ *	{ "ST3780A",  4 },
+ */
+	{ "ST5660A",  3 },
+	{ "ST3660A",  3 },
+	{ "ST3630A",  3 },
+	{ "ST3655A",  3 },
+	{ "ST3391A",  3 },
+	{ "ST3390A",  1 },
+	{ "ST3600A",  1 },
+	{ "ST3290A",  0 },
+	{ "ST3144A",  0 },
+	{ "ST3491A",  1 },	/* reports 3, should be 1 or 2 (depending on */	
+				/* drive) according to Seagates FIND-ATA program */
+
+	{ "QUANTUM ELS127A", 0 },
+	{ "QUANTUM ELS170A", 0 },
+	{ "QUANTUM LPS240A", 0 },
+	{ "QUANTUM LPS210A", 3 },
+	{ "QUANTUM LPS270A", 3 },
+	{ "QUANTUM LPS365A", 3 },
+	{ "QUANTUM LPS540A", 3 },
+	{ "QUANTUM LIGHTNING 540A", 3 },
+	{ "QUANTUM LIGHTNING 730A", 3 },
+
+        { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */
+        { "QUANTUM FIREBALL_640", 3 }, 
+        { "QUANTUM FIREBALL_1080", 3 },
+        { "QUANTUM FIREBALL_1280", 3 },
+	{ NULL,	0 }
+};
+
+/**
+ *	ide_scan_pio_blacklist 	-	check for a blacklisted drive
+ *	@model: Drive model string
+ *
+ *	This routine searches the ide_pio_blacklist for an entry
+ *	matching the start/whole of the supplied model name.
+ *
+ *	Returns -1 if no match found.
+ *	Otherwise returns the recommended PIO mode from ide_pio_blacklist[].
+ */
+
+static int ide_scan_pio_blacklist (char *model)
+{
+	struct ide_pio_info *p;
+
+	for (p = ide_pio_blacklist; p->name != NULL; p++) {
+		if (strncmp(p->name, model, strlen(p->name)) == 0)
+			return p->pio;
+	}
+	return -1;
+}
+
+/**
+ *	ide_get_best_pio_mode	-	get PIO mode fro drive
+ *	@driver: drive to consider
+ *	@mode_wanted: preferred mode
+ *	@max_mode: highest allowed
+ *	@d: pio data
+ *
+ *	This routine returns the recommended PIO settings for a given drive,
+ *	based on the drive->id information and the ide_pio_blacklist[].
+ *	This is used by most chipset support modules when "auto-tuning".
+ *
+ *	Drive PIO mode auto selection
+ */
+
+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;
+	int use_iordy = 0;
+	struct hd_driveid* id = drive->id;
+	int overridden  = 0;
+	int blacklisted = 0;
+
+	if (mode_wanted != 255) {
+		pio_mode = mode_wanted;
+	} else if (!drive->id) {
+		pio_mode = 0;
+	} else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
+		overridden = 1;
+		blacklisted = 1;
+		use_iordy = (pio_mode > 2);
+	} else {
+		pio_mode = id->tPIO;
+		if (pio_mode > 2) {	/* 2 is maximum allowed tPIO value */
+			pio_mode = 2;
+			overridden = 1;
+		}
+		if (id->field_valid & 2) {	  /* drive implements ATA2? */
+			if (id->capability & 8) { /* drive supports use_iordy? */
+				use_iordy = 1;
+				cycle_time = id->eide_pio_iordy;
+				if (id->eide_pio_modes & 7) {
+					overridden = 0;
+					if (id->eide_pio_modes & 4)
+						pio_mode = 5;
+					else if (id->eide_pio_modes & 2)
+						pio_mode = 4;
+					else
+						pio_mode = 3;
+				}
+			} else {
+				cycle_time = id->eide_pio;
+			}
+		}
+
+#if 0
+		if (drive->id->major_rev_num & 0x0004) printk("ATA-2 ");
+#endif
+
+		/*
+		 * Conservative "downgrade" for all pre-ATA2 drives
+		 */
+		if (pio_mode && pio_mode < 4) {
+			pio_mode--;
+			overridden = 1;
+#if 0
+			use_iordy = (pio_mode > 2);
+#endif
+			if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time)
+				cycle_time = 0; /* use standard timing */
+		}
+	}
+	if (pio_mode > max_mode) {
+		pio_mode = max_mode;
+		cycle_time = 0;
+	}
+	if (d) {
+		d->pio_mode = pio_mode;
+		d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time;
+		d->use_iordy = use_iordy;
+		d->overridden = overridden;
+		d->blacklisted = blacklisted;
+	}
+	return pio_mode;
+}
+
+EXPORT_SYMBOL_GPL(ide_get_best_pio_mode);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-m8xx.c linux.20pre10-ac2/drivers/ide/ide-m8xx.c
--- linux.20pre10/drivers/ide/ide-m8xx.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-m8xx.c	1970-01-01 01:00:00.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide_modes.h linux.20pre10-ac2/drivers/ide/ide_modes.h
--- linux.20pre10/drivers/ide/ide_modes.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide_modes.h	2002-09-11 00:51:02.000000000 +0100
@@ -16,8 +16,6 @@
  * breaking the fragile cmd640.c support.
  */
 
-#ifdef CONFIG_BLK_DEV_IDE_MODES
-
 /*
  * Standard (generic) timings for PIO modes, from ATA2 specification.
  * These timings are for access to the IDE data port register *only*.
@@ -31,206 +29,13 @@
 } 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 */
-
-const ide_pio_timings_t ide_pio_timings[6] = {
-	{ 70,	165,	600 },	/* PIO Mode 0 */
-	{ 50,	125,	383 },	/* PIO Mode 1 */
-	{ 30,	100,	240 },	/* PIO Mode 2 */
-	{ 30,	80,	180 },	/* PIO Mode 3 with IORDY */
-	{ 25,	70,	120 },	/* PIO Mode 4 with IORDY */
-	{ 20,	50,	100 }	/* PIO Mode 5 with IORDY (nonstandard) */
-};
-
-/*
- * Black list. Some drives incorrectly report their maximal PIO mode,
- * at least in respect to CMD640. Here we keep info on some known drives.
- */
-static struct ide_pio_info {
-	const char	*name;
-	int		pio;
-} ide_pio_blacklist [] = {
-/*	{ "Conner Peripherals 1275MB - CFS1275A", 4 }, */
-	{ "Conner Peripherals 540MB - CFS540A", 3 },
-
-	{ "WDC AC2700",  3 },
-	{ "WDC AC2540",  3 },
-	{ "WDC AC2420",  3 },
-	{ "WDC AC2340",  3 },
-	{ "WDC AC2250",  0 },
-	{ "WDC AC2200",  0 },
-	{ "WDC AC21200", 4 },
-	{ "WDC AC2120",  0 },
-	{ "WDC AC2850",  3 },
-	{ "WDC AC1270",  3 },
-	{ "WDC AC1170",  1 },
-	{ "WDC AC1210",  1 },
-	{ "WDC AC280",   0 },
-/*	{ "WDC AC21000", 4 }, */
-	{ "WDC AC31000", 3 },
-	{ "WDC AC31200", 3 },
-/*	{ "WDC AC31600", 4 }, */
-
-	{ "Maxtor 7131 AT", 1 },
-	{ "Maxtor 7171 AT", 1 },
-	{ "Maxtor 7213 AT", 1 },
-	{ "Maxtor 7245 AT", 1 },
-	{ "Maxtor 7345 AT", 1 },
-	{ "Maxtor 7546 AT", 3 },
-	{ "Maxtor 7540 AV", 3 },
-
-	{ "SAMSUNG SHD-3121A", 1 },
-	{ "SAMSUNG SHD-3122A", 1 },
-	{ "SAMSUNG SHD-3172A", 1 },
-
-/*	{ "ST51080A", 4 },
- *	{ "ST51270A", 4 },
- *	{ "ST31220A", 4 },
- *	{ "ST31640A", 4 },
- *	{ "ST32140A", 4 },
- *	{ "ST3780A",  4 },
- */
-	{ "ST5660A",  3 },
-	{ "ST3660A",  3 },
-	{ "ST3630A",  3 },
-	{ "ST3655A",  3 },
-	{ "ST3391A",  3 },
-	{ "ST3390A",  1 },
-	{ "ST3600A",  1 },
-	{ "ST3290A",  0 },
-	{ "ST3144A",  0 },
-	{ "ST3491A",  1 },	/* reports 3, should be 1 or 2 (depending on */	
-				/* drive) according to Seagates FIND-ATA program */
-
-	{ "QUANTUM ELS127A", 0 },
-	{ "QUANTUM ELS170A", 0 },
-	{ "QUANTUM LPS240A", 0 },
-	{ "QUANTUM LPS210A", 3 },
-	{ "QUANTUM LPS270A", 3 },
-	{ "QUANTUM LPS365A", 3 },
-	{ "QUANTUM LPS540A", 3 },
-	{ "QUANTUM LIGHTNING 540A", 3 },
-	{ "QUANTUM LIGHTNING 730A", 3 },
-
-        { "QUANTUM FIREBALL_540", 3 }, /* Older Quantum Fireballs don't work */
-        { "QUANTUM FIREBALL_640", 3 }, 
-        { "QUANTUM FIREBALL_1080", 3 },
-        { "QUANTUM FIREBALL_1280", 3 },
-	{ NULL,	0 }
-};
-
-/*
- * This routine searches the ide_pio_blacklist for an entry
- * matching the start/whole of the supplied model name.
- *
- * Returns -1 if no match found.
- * Otherwise returns the recommended PIO mode from ide_pio_blacklist[].
- */
-int ide_scan_pio_blacklist (char *model)
-{
-	struct ide_pio_info *p;
-
-	for (p = ide_pio_blacklist; p->name != NULL; p++) {
-		if (strncmp(p->name, model, strlen(p->name)) == 0)
-			return p->pio;
-	}
-	return -1;
-}
-
-/*
- * This routine returns the recommended PIO settings for a given drive,
- * based on the drive->id information and the ide_pio_blacklist[].
- * This is used by most chipset support modules when "auto-tuning".
- */
-
-/*
- * 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)
-{
-	int pio_mode;
-	int cycle_time = 0;
-	int use_iordy = 0;
-	struct hd_driveid* id = drive->id;
-	int overridden  = 0;
-	int blacklisted = 0;
-
-	if (mode_wanted != 255) {
-		pio_mode = mode_wanted;
-	} else if (!drive->id) {
-		pio_mode = 0;
-	} else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
-		overridden = 1;
-		blacklisted = 1;
-		use_iordy = (pio_mode > 2);
-	} else {
-		pio_mode = id->tPIO;
-		if (pio_mode > 2) {	/* 2 is maximum allowed tPIO value */
-			pio_mode = 2;
-			overridden = 1;
-		}
-		if (id->field_valid & 2) {	  /* drive implements ATA2? */
-			if (id->capability & 8) { /* drive supports use_iordy? */
-				use_iordy = 1;
-				cycle_time = id->eide_pio_iordy;
-				if (id->eide_pio_modes & 7) {
-					overridden = 0;
-					if (id->eide_pio_modes & 4)
-						pio_mode = 5;
-					else if (id->eide_pio_modes & 2)
-						pio_mode = 4;
-					else
-						pio_mode = 3;
-				}
-			} else {
-				cycle_time = id->eide_pio;
-			}
-		}
-
-#if 0
-		if (drive->id->major_rev_num & 0x0004) printk("ATA-2 ");
-#endif
-
-		/*
-		 * Conservative "downgrade" for all pre-ATA2 drives
-		 */
-		if (pio_mode && pio_mode < 4) {
-			pio_mode--;
-			overridden = 1;
-#if 0
-			use_iordy = (pio_mode > 2);
-#endif
-			if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time)
-				cycle_time = 0; /* use standard timing */
-		}
-	}
-	if (pio_mode > max_mode) {
-		pio_mode = max_mode;
-		cycle_time = 0;
-	}
-	if (d) {
-		d->pio_mode = pio_mode;
-		d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time;
-		d->use_iordy = use_iordy;
-		d->overridden = overridden;
-		d->blacklisted = blacklisted;
-	}
-	return pio_mode;
-}
-
-#endif /* _IDE_C */
-#endif /* CONFIG_BLK_DEV_IDE_MODES */
 #endif /* _IDE_MODES_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-pci.c linux.20pre10-ac2/drivers/ide/ide-pci.c
--- linux.20pre10/drivers/ide/ide-pci.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-pci.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,1007 +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.  
- */
-
-#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_ICH0	((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_ICH	((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_ICH2	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_9})
-#define DEVID_ICH2M	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801BA_8})
-#define DEVID_ICH3M	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801CA_10})
-#define DEVID_ICH3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801CA_11})
-#define DEVID_ICH4	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801DB_11})
-#define DEVID_CICH	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82801E_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_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_PDC20270  ((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270})
-#define DEVID_PDC20269	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269})
-#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_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_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_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_VIPER_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_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 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 PCI_AEC62XX	&pci_init_aec62xx
-#define ATA66_AEC62XX	&ata66_aec62xx
-#define INIT_AEC62XX	&ide_init_aec62xx
-#define DMA_AEC62XX	&ide_dmacapable_aec62xx
-#else
-#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 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 PCI_ALI15X3	&pci_init_ali15x3
-#define ATA66_ALI15X3	&ata66_ali15x3
-#define INIT_ALI15X3	&ide_init_ali15x3
-#define DMA_ALI15X3	&ide_dmacapable_ali15x3
-#else
-#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 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 PCI_AMD74XX	&pci_init_amd74xx
-#define ATA66_AMD74XX	&ata66_amd74xx
-#define INIT_AMD74XX	&ide_init_amd74xx
-#define DMA_AMD74XX	&ide_dmacapable_amd74xx
-#else
-#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 unsigned int pci_init_cy82c693(struct pci_dev *, const char *);
-extern void ide_init_cy82c693(ide_hwif_t *);
-#define PCI_CY82C693	&pci_init_cy82c693
-#define INIT_CY82C693	&ide_init_cy82c693
-#else
-#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 unsigned int pci_init_hpt34x(struct pci_dev *, const char *);
-extern void ide_init_hpt34x(ide_hwif_t *);
-#define PCI_HPT34X	&pci_init_hpt34x
-#define INIT_HPT34X	&ide_init_hpt34x
-#else
-#define PCI_HPT34X	NULL
-#define INIT_HPT34X	IDE_IGNORE
-#endif
-
-#ifdef CONFIG_BLK_DEV_HPT366
-extern byte hpt363_shared_irq;
-extern byte hpt363_shared_pin;
-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 PCI_HPT366	&pci_init_hpt366
-#define ATA66_HPT366	&ata66_hpt366
-#define INIT_HPT366	&ide_init_hpt366
-#define DMA_HPT366	&ide_dmacapable_hpt366
-#else
-static byte hpt363_shared_irq;
-static byte hpt363_shared_pin;
-#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 ide_init_opti621(ide_hwif_t *);
-#define INIT_OPTI621	&ide_init_opti621
-#else
-#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 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 PCI_PDC202XX	&pci_init_pdc202xx
-#define ATA66_PDC202XX	&ata66_pdc202xx
-#define INIT_PDC202XX	&ide_init_pdc202xx
-#else
-#define PCI_PDC202XX	NULL
-#define ATA66_PDC202XX	NULL
-#define INIT_PDC202XX	NULL
-#endif
-
-#ifdef CONFIG_BLK_DEV_PIIX
-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 PCI_PIIX	&pci_init_piix
-#define ATA66_PIIX	&ata66_piix
-#define INIT_PIIX	&ide_init_piix
-#else
-#define PCI_PIIX	NULL
-#define ATA66_PIIX	NULL
-#define INIT_PIIX	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_IT8172
-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 PCI_IT8172	&pci_init_it8172
-#define INIT_IT8172	&ide_init_it8172
-#else
-#define PCI_IT8172	NULL
-#define ATA66_IT8172	NULL
-#define INIT_IT8172	NULL
-#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 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 *);
-#define PCI_SVWKS	&pci_init_svwks
-#define ATA66_SVWKS	&ata66_svwks
-#define INIT_SVWKS	&ide_init_svwks
-#else
-#define PCI_SVWKS	NULL
-#define ATA66_SVWKS	NULL
-#define INIT_SVWKS	IDE_NO_DRIVER
-#endif
-
-#ifdef CONFIG_BLK_DEV_SIS5513
-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 PCI_SIS5513	&pci_init_sis5513
-#define ATA66_SIS5513	&ata66_sis5513
-#define INIT_SIS5513	&ide_init_sis5513
-#else
-#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
-
-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" */
-} ide_pci_enablebit_t;
-
-typedef struct ide_pci_device_s {
-	ide_pci_devid_t		devid;
-	char			*name;
-	unsigned int		(*init_chipset)(struct pci_dev *dev, const char *name);
-	unsigned int		(*ata66_check)(ide_hwif_t *hwif);
-	void 			(*init_hwif)(ide_hwif_t *hwif);
-	void			(*dma_init)(ide_hwif_t *hwif, unsigned long dmabase);
-	ide_pci_enablebit_t	enablebits[2];
-	byte			bootable;
-	unsigned int		extra;
-} ide_pci_device_t;
-
-static ide_pci_device_t ide_pci_chipsets[] __initdata = {
-	{DEVID_PIIXa,	"PIIX",		NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIXb,	"PIIX",		NULL,		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_MPIIX,	"MPIIX",	NULL,		NULL,		INIT_PIIX,	NULL,		{{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX3,	"PIIX3",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_PIIX4,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_ICH0,	"ICH0", 	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4E2,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH,	"ICH",  	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4U2,	"PIIX4",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_PIIX4NX,	"PIIX4",	PCI_PIIX,	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH2,	"ICH2", 	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH2M,	"ICH2M",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH3M,	"ICH3M",	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH3,	"ICH3", 	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_ICH4,	"ICH4", 	PCI_PIIX,	ATA66_PIIX,	INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-	{DEVID_CICH,	"C-ICH",	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,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_MR_IDE,	"VP_IDE",	PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
-	{DEVID_VP_IDE,	"VP_IDE",	PCI_VIA82CXXX,	ATA66_VIA82CXXX,INIT_VIA82CXXX,	DMA_VIA82CXXX,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
-#ifndef CONFIG_PDC202XX_FORCE
-        {DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	16 },
-        {DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
-        {DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	48 },
-        {DEVID_PDC20267,"PDC20267",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	48 },
-#else /* !CONFIG_PDC202XX_FORCE */
-	{DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	NULL,		INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}}, 	OFF_BOARD,	16 },
-	{DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
-	{DEVID_PDC20265,"PDC20265",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
-	{DEVID_PDC20267,"PDC20267",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
-#endif
-	{DEVID_PDC20268,"PDC20268",	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_PDC20270,"PDC20270",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_PDC20269,"PDC20269",	PCI_PDC202XX,	ATA66_PDC202XX,	 INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_PDC20275,"PDC20275",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_PDC20276,"PDC20276",	PCI_PDC202XX,	ATA66_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_RZ1000,	"RZ1000",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_RZ1001,	"RZ1001",	NULL,		NULL,		INIT_RZ1000,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_SAMURAI,	"SAMURAI",	NULL,		NULL,		INIT_SAMURAI,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CMD640,	"CMD640",	NULL,		NULL,		IDE_IGNORE,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_NS87410,	"NS87410",	NULL,		NULL,		NULL,		NULL,		{{0x43,0x08,0x08}, {0x47,0x08,0x08}}, 	ON_BOARD,	0 },
-	{DEVID_SIS5513,	"SIS5513",	PCI_SIS5513,	ATA66_SIS5513,	INIT_SIS5513,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	ON_BOARD,	0 },
-	{DEVID_CMD643,	"CMD643",	PCI_CMD64X,	NULL,		INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CMD646,	"CMD646",	PCI_CMD64X,	NULL,		INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x51,0x80,0x80}}, 	ON_BOARD,	0 },
-	{DEVID_CMD648,	"CMD648",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CMD649,	"CMD649",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-#ifndef CONFIG_BLK_DEV_CMD680
-	{DEVID_CMD680,	"CMD680",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-#else /* CONFIG_BLK_DEV_CMD680 */
-	{DEVID_CMD680,	"CMD680",	PCI_CMD64X,	ATA66_CMD64X,	INIT_CMD64X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-#endif /* !CONFIG_BLK_DEV_CMD680 */
-	{DEVID_HT6565,	"HT6565",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_OPTI621,	"OPTI621",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_OPTI621X,"OPTI621X",	NULL,		NULL,		INIT_OPTI621,	NULL,		{{0x45,0x80,0x00}, {0x40,0x08,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_TRM290,	"TRM290",	NULL,		NULL,		INIT_TRM290,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_NS87415,	"NS87415",	NULL,		NULL,		INIT_NS87415,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_AEC6210,	"AEC6210",	PCI_AEC62XX,	NULL,		INIT_AEC62XX,	DMA_AEC62XX,	{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}}, 	OFF_BOARD,	0 },
-	{DEVID_AEC6260,	"AEC6260",	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	0 },
-	{DEVID_AEC6260R,"AEC6260R",	PCI_AEC62XX,	ATA66_AEC62XX,	INIT_AEC62XX,	NULL,		{{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},	OFF_BOARD,	0 },
-	{DEVID_W82C105,	"W82C105",	PCI_W82C105,	NULL,		INIT_W82C105,	DMA_W82C105,	{{0x40,0x01,0x01}, {0x40,0x10,0x10}}, 	ON_BOARD,	0 },
-	{DEVID_UM8673F,	"UM8673F",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_UM8886A,	"UM8886A",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_UM8886BF,"UM8886BF",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}}, 	ON_BOARD,	0 },
-	{DEVID_HPT34X,	"HPT34X",	PCI_HPT34X,	NULL,		INIT_HPT34X,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	NEVER_BOARD,	16 },
-	{DEVID_HPT366,	"HPT366",	PCI_HPT366,	ATA66_HPT366,	INIT_HPT366,	DMA_HPT366,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	240 },
-	{DEVID_ALI15X3,	"ALI15X3",	PCI_ALI15X3,	ATA66_ALI15X3,	INIT_ALI15X3,	DMA_ALI15X3,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CY82C693,"CY82C693",	PCI_CY82C693,	NULL,		INIT_CY82C693,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_HINT,	"HINT_IDE",	NULL,		NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CS5530,	"CS5530",	PCI_CS5530,	NULL,		INIT_CS5530,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_AMD7401,	"AMD7401",	NULL,		NULL,		NULL,		DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_AMD7409,	"AMD7409",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_AMD7411,	"AMD7411",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_AMD7441,	"AMD7441",	PCI_AMD74XX,	ATA66_AMD74XX,	INIT_AMD74XX,	DMA_AMD74XX,	{{0x40,0x01,0x01}, {0x40,0x02,0x02}},	ON_BOARD,	0 },
-	{DEVID_PDCADMA,	"PDCADMA",	PCI_PDCADMA,	ATA66_PDCADMA,	INIT_PDCADMA,	DMA_PDCADMA,	{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	OFF_BOARD,	0 },
-	{DEVID_SLC90E66,"SLC90E66",	PCI_SLC90E66,	ATA66_SLC90E66,	INIT_SLC90E66,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}},	ON_BOARD,	0 },
-        {DEVID_OSB4,    "ServerWorks OSB4",		PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_CSB5,	"ServerWorks CSB5",		PCI_SVWKS,	ATA66_SVWKS,	INIT_SVWKS,	NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
-	{DEVID_ITE8172G,"IT8172G",	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,		{{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_PROMISE_20246:
-		case PCI_DEVICE_ID_PROMISE_20262:
-		case PCI_DEVICE_ID_PROMISE_20265:
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_ARTOP_ATP850UF:
-		case PCI_DEVICE_ID_ARTOP_ATP860:
-		case PCI_DEVICE_ID_ARTOP_ATP860R:
-			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.
- */
-static 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)) {
-		if(pci_enable_device_bars(dev, 1<<4))
-		{
-			printk(KERN_WARNING "%s: (ide_setup_pci_device:) Could not enable device.\n", d->name);
-			return;
-		}
-		printk(KERN_INFO "%s: BIOS setup was incomplete.\n", d->name);
-	}
-
-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;
-
-	if (IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT34X)) {
-		/* see comments in hpt34x.c on why..... */
-		char *chipset_names[] = {"HPT343", "HPT345"};
-		strcpy(d->name, chipset_names[(pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0]);
-		d->bootable = (pcicmd & PCI_COMMAND_MEMORY) ? OFF_BOARD : NEVER_BOARD;
-	}
-
-	printk("%s: chipset revision %d\n", d->name, class_rev);
-
-	/*
-	 * Can we trust the reported IRQ?
-	 */
-	pciirq = dev->irq;
-	
-#ifdef CONFIG_PDC202XX_FORCE
-	if (dev->class >> 8 == PCI_CLASS_STORAGE_RAID) {
-		/*
-		 * By rights we want to ignore Promise FastTrak and SuperTrak
-		 * series here, those use own driver.
-		 */
-		if (dev->vendor == PCI_VENDOR_ID_PROMISE) {
-			printk(KERN_INFO "ide: Skipping Promise RAID controller.\n");
-			return;
-		}
-	}
-#endif /* CONFIG_PDC202XX_FORCE */
-	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 ((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_PDC20265) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20267) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20268) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20270) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20269) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20275) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20276) ||
-		    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_HPT34X) ||
-		    IDE_PCI_DEVID_EQ(d->devid, DEVID_HPT366) ||
-		    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);
-}
-
-static void __init pdc20270_device_order_fixup (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);
-}
-
-static void __init hpt366_device_order_fixup (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;
-	if (class_rev > 5)
-		class_rev = 5;
-	
-	strcpy(d->name, chipset_names[class_rev]);
-
-	switch(class_rev) {
-		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
-				/* I forgot why I did this once, but it fixed something. */
-				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);
-}
-
-/*
- * 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 (IDE_PCI_DEVID_EQ(d->devid, DEVID_OPTI621V) && !(PCI_FUNC(dev->devfn) & 1))
-		return;
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
-		return;	/* CY82C693 is more than only a IDE controller */
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_ITE8172G) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
-		return;	/* IT8172G is also more than only an IDE controller */
-	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, DEVID_HPT366))
-		hpt366_device_order_fixup(dev, d);
-	else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20270))
-		pdc20270_device_order_fixup(dev, d);
-	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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-pmac.c linux.20pre10-ac2/drivers/ide/ide-pmac.c
--- linux.20pre10/drivers/ide/ide-pmac.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-pmac.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,1794 +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 char *ide_dmafunc_verbose(ide_dma_action_t dmafunc);
-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.
- */
-#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));
-}
-
-
-/* Note: We don't use the generic routine here because for some
- * yet unexplained reasons, it cause some media-bay CD-ROMs to
- * lockup the bus. Strangely, this new version of the code is
- * almost identical to the generic one and works, I've not yet
- * managed to figure out what bit is causing the lockup in the
- * generic code, possibly a timing issue...
- * 
- * --BenH
- */
-static int __pmac
-wait_for_ready(ide_drive_t *drive)
-{
-	/* Timeout bumped for some powerbooks */
-	int timeout = 2000;
-	byte stat;
-
-	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 "ide_pmac: wait_for_ready, error status: %x\n", stat);
-		}
-		return 1;
-	}
-	return 0;
-}
-
-static int __pmac
-pmac_ide_do_setfeature(ide_drive_t *drive, byte command)
-{
-	int result = 1;
-	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)) {
-		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);
-	result = wait_for_ready(drive);
-	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;
-		hwif->drives[0].unmask = 1;
-		hwif->drives[1].unmask = 1;
-#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;
-	unsigned long lastdataend = ~0UL;
-	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 {
-		struct scatterlist *sge;
-		unsigned int size = bh->b_size;
-
-		/* continue segment from before? */
-		if (bh_phys(bh) == lastdataend) {
-			sg[nents-1].length += size;
-			lastdataend += size;
-			continue;
-		}
-
-		/* start new segment */
-		if (nents >= MAX_DCMDS)
-			return 0;
-
-		sge = &sg[nents];
-		memset(sge, 0, sizeof(*sge));
-
-		if (bh->b_page) {
-			sge->page = bh->b_page;
-			sge->offset = bh_offset(bh);
-		} else {
-			if ((unsigned long)bh->b_data < PAGE_SIZE)
-				BUG();
-			sge->address = bh->b_data;
-		}
-		sge->length = size;
-		lastdataend = bh_phys(bh) + size;
-		nents++;
-	} while ((bh = bh->b_reqnext) != 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->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA) ||
-//	    (args->tfRegister[IDE_COMMAND_OFFSET] == WIN_WRITEDMA_EXT))
-	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 inline void pmac_ide_toggle_bounce(ide_drive_t *drive, int on)
-{
-	dma64_addr_t addr = BLK_BOUNCE_HIGH;
-
-	if (HWIF(drive)->no_highio || HWIF(drive)->pci_dev == NULL)
-		return;
-
-	if (on && drive->media == ide_disk) {
-		if (!PCI_DMA_BUS_IS_PHYS)
-			addr = BLK_BOUNCE_ANY;
-		else
-			addr = HWIF(drive)->pci_dev->dma_mask;
-	}
-
-	blk_queue_bounce_limit(&drive->queue, addr);
-}
-
-static int __pmac
-pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	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;
-		pmac_ide_toggle_bounce(drive, 0);
-		break;
-	case ide_dma_on:
-	case ide_dma_check:
-		pmac_ide_check_dma(drive);
-		if (drive->using_dma)
-			pmac_ide_toggle_bounce(drive, 1);
-		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;
-		ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
-		if ((HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) &&
-		    (drive->addressing == 1)) {
-			ide_task_t *args = HWGROUP(drive)->rq->special;
-			OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
-		} else if (drive->addressing) {
-			OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
-		} else {
-			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-		}
-	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 */
-		outb(drive->select.all, base+0x60);
-		(void)inb(base+0x60);
-		udelay(100);
-		outb(0x0, base+0x30);
-		outb(0x0, base+0x20);
-		outb(0x0, base+0x40);
-		outb(0x0, base+0x50);
-		outb(0xe0, base+0x70);
-		outb(0x2, base+0x160);   
-		for (j = 0; j < 10; j++) {
-			int status;
-			mdelay(100);
-			status = 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_check_dma(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(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(&io_request_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);
-		outb(drive->select.all, base + 0x60);
-		if (inb(base + 0x60) != drive->select.all)
-			continue;
-		status = 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.
- * 
- * Well, actually, that sorta works on the iBook2 when the CD-ROM is
- * a slave, though it will fail to spin_wait_hwgroup for the slave
- * device as it is marked busy by the master sleep code. Well, it's
- * probably not worth fixing now as we don't have sleep code for
- * ATAPI devices anyway. Future kernels will hopefully deal with
- * IDE PM in a more generic way.
- */
-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(&io_request_lock);
-		}
-	}
-	if (gotone)
-		mdelay(1000);
-		
-	return NOTIFY_DONE;
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-pnp.c linux.20pre10-ac2/drivers/ide/ide-pnp.c
--- linux.20pre10/drivers/ide/ide-pnp.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-pnp.c	2002-08-29 23:47:56.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-probe.c linux.20pre10-ac2/drivers/ide/ide-probe.c
--- linux.20pre10/drivers/ide/ide-probe.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-probe.c	2002-09-30 16:24:11.000000000 +0100
@@ -52,34 +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 */
+	hwif->ata_input_data(drive, id, SECTOR_WORDS);
 
-	ide_input_data(drive, id, SECTOR_WORDS);		/* read 512 bytes of id info */
-	ide__sti();	/* local CPU only */
+	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;
 	}
@@ -93,27 +128,30 @@
 		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;
+	drive->dead = 0;
 
 	/*
 	 * 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(drive)->channel == 1 && HWIF(drive)->chipset == ide_pdc4030) {
+		if (hwif->channel == 1 && hwif->chipset == ide_pdc4030) {
 			printk(" -- not supported on 2nd Promise port\n");
 			goto err_misc;
 		}
@@ -121,19 +159,23 @@
 		switch (type) {
 			case ide_floppy:
 				if (!strstr(id->model, "CD-ROM")) {
-					if (!strstr(id->model, "oppy") && !strstr(id->model, "poyp") && !strstr(id->model, "ZIP"))
+					if (!strstr(id->model, "oppy") &&
+					    !strstr(id->model, "poyp") &&
+					    !strstr(id->model, "ZIP"))
 						printk("cdrom or floppy?, assuming ");
 					if (drive->media != ide_cdrom) {
 						printk ("FLOPPY");
 						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
 				/* kludge for Apple PowerBook internal zip */
-				if (!strstr(id->model, "CD-ROM") && strstr(id->model, "ZIP")) {
+				if (!strstr(id->model, "CD-ROM") &&
+				    strstr(id->model, "ZIP")) {
 					printk ("FLOPPY");
 					type = ide_floppy;
 					break;
@@ -164,18 +206,21 @@
 		drive->removable = 1;
 	/*
 	 * Prevent long system lockup probing later for non-existant
-	 * slave drive if the hwif is actually a flash memory card of some variety:
+	 * 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(drive)->drives[1^drive->select.b.unit];
+		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),drive);
+	printk("%s DISK drive\n", (drive->is_flash) ? "CFA" : "ATA" );
+	QUIRK_LIST(drive);
 	return;
 
 err_misc:
@@ -195,95 +240,117 @@
  *		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);
 	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 (0 < (signed long)(jiffies - timeout)) {
-			return 1;	/* drive timed-out */
+		if (time_after(jiffies, timeout)) {
+			/* 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;
-		__save_flags(flags);	/* local CPU only */
-		__cli();		/* 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 */
-		__restore_flags(flags);	/* local CPU only */
-	} else
-		rc = 2;			/* drive refused ID */
+
+		/* local CPU only; some systems need this */
+		local_irq_save(flags);
+		/* 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 {
+		/* 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;
 	int autoprobe = 0;
 	unsigned long cookie = 0;
 
-	if (IDE_CONTROL_REG && !HWIF(drive)->irq) {
+	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(drive)->irq) {
+		if (!hwif->irq) {
 			if (irq > 0) {
-				HWIF(drive)->irq = irq;
-			} else {	/* Mmmm.. multiple IRQs.. don't know which was ours */
-				printk("%s: IRQ probe failed (0x%lx)\n", drive->name, cookie);
+				hwif->irq = irq;
+			} 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(drive)->chipset == ide_cmd640) {
-					printk("%s: Hmmm.. probably a driver problem.\n", drive->name);
+				if (hwif->chipset == ide_cmd640) {
+					printk("%s: Hmmm.. probably a driver "
+						"problem.\n", drive->name);
 					CMD640_DUMP_REGS;
 				}
 #endif /* CMD640_DUMP_REGS */
@@ -311,11 +378,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;
 	}
@@ -324,44 +393,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)
-	 || 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 */
+	if (OK_STAT((hwif->INB(IDE_STATUS_REG)), READY_STAT, BUSY_STAT) ||
+	    drive->present || cmd == WIN_PIDENTIFY) {
+		/* 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;
 }
@@ -371,12 +460,13 @@
  */
 static void enable_nest (ide_drive_t *drive)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long timeout;
 
-	printk("%s: enabling %s -- ", HWIF(drive)->name, drive->id->model);
-	SELECT_DRIVE(HWIF(drive), drive);
+	printk("%s: enabling %s -- ", hwif->name, drive->id->model);
+	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)) {
@@ -384,14 +474,20 @@
 			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);
 	}
 }
 
@@ -401,102 +497,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;
-	}
+	u32 i = 0;
 
-	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);
-
-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;
@@ -506,8 +599,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
 
@@ -516,61 +608,91 @@
 	    (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;	
 	}
 
-	__save_flags(flags);	/* local CPU only */
-	__sti();		/* local CPU only; needed for jiffies and irq probing */
+	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,
 	 * but a lot of cdrom drives are configured as single slaves.
 	 */
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[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 || !hwif->mate->present) {
+			if (hwif->chipset != ide_4drives ||
+			    !hwif->mate->present) {
 				hwif_register(hwif);
 			}
 		}
 	}
 	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]);
-		} while ((stat & BUSY_STAT) && 0 < (signed long)(timeout - jiffies));
+			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+		} while ((stat & BUSY_STAT) && time_after(timeout, jiffies));
 
 	}
-	__restore_flags(flags);	/* local CPU only */
+	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) {
-			ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;
-			if (tuneproc != NULL && drive->autotune == 1)
-				tuneproc(drive, 255);	/* auto-tune PIO mode */
+			if (hwif->tuneproc != NULL && drive->autotune == 1)
+				/* auto-tune PIO mode */
+				hwif->tuneproc(drive, 255);
+			/*
+			 * 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->ide_dma_off_quietly(drive);
+				hwif->ide_dma_check(drive);
+			}
 		}
 	}
 }
 
+EXPORT_SYMBOL(probe_hwif);
+
 #if MAX_HWIFS > 1
 /*
  * save_match() is used to simplify logic in init_irq() below.
@@ -583,18 +705,20 @@
  *
  * 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;
 
 	if (m && m->hwgroup && m->hwgroup != new->hwgroup) {
 		if (!new->hwgroup)
 			return;
-		printk("%s: potential irq problem with %s and %s\n", hwif->name, new->name, m->name);
+		printk("%s: potential irq problem with %s and %s\n",
+			hwif->name, new->name, m->name);
 	}
 	if (!m || m->irq != hwif->irq) /* don't undo a prior perfect match */
 		*match = new;
 }
+EXPORT_SYMBOL(save_match);
 #endif /* MAX_HWIFS > 1 */
 
 /*
@@ -614,6 +738,7 @@
 	}
 }
 
+#undef __IRQ_HELL_SPIN
 /*
  * This routine sets up the irq for an ide interface, and creates a new
  * hwgroup for the irq/hwif if none was previously assigned.
@@ -627,20 +752,26 @@
  * 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
 	
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
+#ifndef __IRQ_HELL_SPIN
+	save_and_cli(flags);
+#else
+	spin_lock_irqsave(&io_request_lock, flags);
+#endif
 
 	hwif->hwgroup = NULL;
 #if MAX_HWIFS > 1
@@ -652,7 +783,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);
 				}
 			}
@@ -677,7 +809,11 @@
 	} else {
 		hwgroup = new_hwgroup;
 		if (!hwgroup) {
-			restore_flags(flags);	/* all CPUs */
+#ifndef __IRQ_HELL_SPIN
+			restore_flags(flags);
+#else
+			spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 			return 1;
 		}
 		memset(hwgroup, 0, sizeof(ide_hwgroup_t));
@@ -695,19 +831,30 @@
 	 * 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);
-			restore_flags(flags);	/* all CPUs */
+#ifndef __IRQ_HELL_SPIN
+			restore_flags(flags);
+#else
+			spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 			return 1;
 		}
 	}
@@ -735,10 +882,16 @@
 		printk("%s : Adding missed hwif to hwgroup!!\n", hwif->name);
 #endif
 	}
-	restore_flags(flags);	/* all CPUs; safe now that hwif->hwgroup is set up */
+
+	/* all CPUs; safe now that hwif->hwgroup is set up */
+#ifndef __IRQ_HELL_SPIN
+	restore_flags(flags);
+#else
+	spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 
 #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);
@@ -748,7 +901,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)
@@ -758,6 +911,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
@@ -771,34 +926,27 @@
 	int *bs, *max_sect, *max_ra;
 	extern devfs_handle_t ide_devfs_handle;
 
-#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 (sizeof(struct gendisk), GFP_KERNEL);
+	gd        = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
 	if (!gd)
 		goto err_kmalloc_gd;
-	memset (gd, 0, sizeof(struct gendisk));
-	gd->sizes = kmalloc (minors * sizeof(int), GFP_KERNEL);
+	memset(gd, 0, sizeof(struct gendisk));
+	
+	gd->sizes = kmalloc(minors * sizeof(int), GFP_KERNEL);
 	if (!gd->sizes)
 		goto err_kmalloc_gd_sizes;
-	gd->part  = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL);
+	gd->part  = kmalloc(minors * sizeof(struct hd_struct), GFP_KERNEL);
 	if (!gd->part)
 		goto err_kmalloc_gd_part;
-	bs        = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	bs        = kmalloc(minors*sizeof(int), GFP_KERNEL);
 	if (!bs)
 		goto err_kmalloc_bs;
-	max_sect  = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	max_sect  = kmalloc(minors*sizeof(int), GFP_KERNEL);
 	if (!max_sect)
 		goto err_kmalloc_max_sect;
-	max_ra    = kmalloc (minors*sizeof(int), GFP_KERNEL);
+	max_ra    = kmalloc(minors*sizeof(int), GFP_KERNEL);
 	if (!max_ra)
 		goto err_kmalloc_max_ra;
 
@@ -813,55 +961,49 @@
 		/*
 		 * IDE can do up to 128K per request == 256
 		 */
-		*max_sect++ = ((hwif->chipset == ide_pdc4030) ? 127 : 128);
+		*max_sect++ = ((hwif->rqsize) ? hwif->rqsize : 128);
 		*max_ra++ = vm_max_readahead;
 	}
 
 	for (unit = 0; unit < units; ++unit)
 		hwif->drives[unit].part = &gd->part[unit << PARTN_BITS];
 
-	gd->major	= hwif->major;		/* our major device number */
-	gd->major_name	= IDE_MAJOR_NAME;	/* treated special in genhd.c */
-	gd->minor_shift	= PARTN_BITS;		/* num bits for partitions */
-	gd->max_p	= 1<<PARTN_BITS;	/* 1 + max partitions / drive */
-	gd->nr_real	= units;		/* current num real drives */
-	gd->real_devices= hwif;			/* ptr to internal data */
-	gd->next	= NULL;			/* linked list of major devs */
-	gd->fops        = ide_fops;             /* file operations */
-	gd->de_arr	= kmalloc (sizeof *gd->de_arr * units, GFP_KERNEL);
-	gd->flags	= kmalloc (sizeof *gd->flags * units, GFP_KERNEL);
+	/* our major device number */
+	gd->major	= hwif->major;
+	/* treated special in genhd.c */
+	gd->major_name	= IDE_MAJOR_NAME;
+	/* num bits for partitions */
+	gd->minor_shift	= PARTN_BITS;
+	/* 1 + max partitions / drive */
+	gd->max_p	= 1<<PARTN_BITS;
+	/* current num real drives */
+	gd->nr_real	= units;
+	/* ptr to internal data */
+	gd->real_devices= hwif;
+	/* linked list of major devs */
+	gd->next	= NULL;
+	/* file operations */
+	gd->fops        = ide_fops;
+	gd->de_arr	= kmalloc(sizeof *gd->de_arr * units, GFP_KERNEL);
+	gd->flags	= kmalloc(sizeof *gd->flags * units, GFP_KERNEL);
 	if (gd->de_arr)
-		memset (gd->de_arr, 0, sizeof *gd->de_arr * units);
+		memset(gd->de_arr, 0, sizeof *gd->de_arr * units);
 	if (gd->flags)
-		memset (gd->flags, 0, sizeof *gd->flags * units);
+		memset(gd->flags, 0, sizeof *gd->flags * units);
 
 	hwif->gd = gd;
 	add_gendisk(gd);
 
 	for (unit = 0; unit < units; ++unit) {
-#if 1
 		char name[64];
 		ide_add_generic_settings(hwif->drives + unit);
-		hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + unit);
+//		hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + 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);
 		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);
-			hwif->drives[unit].dn = ((hwif->channel ? 2 : 0) + 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;
 
@@ -880,7 +1022,9 @@
 	return;
 }
 
-static int hwif_init (ide_hwif_t *hwif)
+EXPORT_SYMBOL(init_gendisk);
+
+int hwif_init (ide_hwif_t *hwif)
 {
 	if (!hwif->present)
 		return 0;
@@ -893,15 +1037,18 @@
 	}
 #ifdef CONFIG_BLK_DEV_HD
 	if (hwif->irq == HD_IRQ && hwif->io_ports[IDE_DATA_OFFSET] != HD_DATA) {
-		printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", hwif->name);
+		printk("%s: CANNOT SHARE IRQ WITH OLD "
+			"HARDDISK DRIVER (hd.c)\n", hwif->name);
 		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 (devfs_register_blkdev (hwif->major, hwif->name, ide_fops)) {
-		printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", hwif->name, hwif->major);
+		printk("%s: UNABLE TO GET MAJOR NUMBER %d\n",
+			hwif->name, hwif->major);
 		return (hwif->present = 0);
 	}
 	
@@ -912,14 +1059,15 @@
 		 *	this port and try that.
 		 */
 		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);
+			printk("%s: Disabled unable to get IRQ %d.\n",
+				hwif->name, i);
+			(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",
@@ -942,19 +1090,51 @@
 	return hwif->present;
 }
 
+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);
 
+#ifndef HWIF_PROBE_CLASSIC_METHOD
+int probe_hwif_init (ide_hwif_t *hwif)
+{
+	hwif->initializing = 1;
+	probe_hwif(hwif);
+	hwif_init(hwif);
+
+#ifndef CLASSIC_BUILTINS_METHOD
+#  ifndef FAKE_CLASSIC_ATTACH_METHOD
+#    ifdef DIRECT_HWIF_PROBE_ATTACH_METHOD
+	if (hwif->present) {
+		u16 unit = 0;
+		for (unit = 0; unit < MAX_DRIVES; ++unit) {
+			ide_drive_t *drive = &hwif->drives[unit];
+			if (drive->present)
+				ide_attach_drive(drive);
+		}
+	}
+#    endif /* DIRECT_HWIF_PROBE_ATTACH_METHOD */
+#  endif /* FAKE_CLASSIC_ATTACH_METHOD */
+#endif /* CLASSIC_BUILTINS_METHOD */
+	hwif->initializing = 0;
+	return 0;
+}
+
+EXPORT_SYMBOL(probe_hwif_init);
+
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
 int ideprobe_init (void);
 static ide_module_t ideprobe_module = {
 	IDE_PROBE_MODULE,
@@ -975,12 +1155,20 @@
 	/*
 	 * Probe for drives in the usual way.. CMOS/BIOS, then poke at ports
 	 */
+#ifdef HWIF_PROBE_CLASSIC_METHOD
 	for (index = 0; index < MAX_HWIFS; ++index)
 		if (probe[index])
 			probe_hwif(&ide_hwifs[index]);
+
 	for (index = 0; index < MAX_HWIFS; ++index)
 		if (probe[index])
 			hwif_init(&ide_hwifs[index]);
+#else /* HWIF_PROBE_CLASSIC_METHOD */
+	for (index = 0; index < MAX_HWIFS; ++index)
+		if (probe[index])
+			probe_hwif_init(&ide_hwifs[index]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+
 	if (!ide_probe)
 		ide_probe = &ideprobe_module;
 	MOD_DEC_USE_COUNT;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-proc.c linux.20pre10-ac2/drivers/ide/ide-proc.c
--- linux.20pre10/drivers/ide/ide-proc.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-proc.c	2002-09-06 14:06:52.000000000 +0100
@@ -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>
@@ -74,59 +77,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;
@@ -160,6 +110,17 @@
 
 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 */
+
+#undef __PROC_HELL
+
 static int proc_ide_write_config
 	(struct file *file, const char *buffer, unsigned long count, void *data)
 {
@@ -181,7 +142,11 @@
 	 * Do one full pass to verify all parameters,
 	 * then do another to actually write the regs.
 	 */
+#ifndef __PROC_HELL
 	save_flags(flags);	/* all CPUs */
+#else
+	spin_lock_irqsave(&io_request_lock, flags);
+#endif
 	do {
 		const char *p;
 		if (for_real) {
@@ -190,15 +155,32 @@
 			ide_hwgroup_t *mategroup = NULL;
 			if (hwif->mate && hwif->mate->hwgroup)
 				mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup);
+#ifndef __PROC_HELL
 			cli();	/* all CPUs; ensure all writes are done together */
-			while (mygroup->busy || (mategroup && mategroup->busy)) {
+#else
+			spin_lock_irqsave(&io_request_lock, flags);
+#endif
+			while (mygroup->busy ||
+			       (mategroup && mategroup->busy)) {
+#ifndef __PROC_HELL
 				sti();	/* all CPUs */
-				if (0 < (signed long)(jiffies - timeout)) {
+#else
+				spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+				if (time_after(jiffies, timeout)) {
 					printk("/proc/ide/%s/config: channel(s) busy, cannot write\n", hwif->name);
+#ifndef __PROC_HELL
 					restore_flags(flags);	/* all CPUs */
+#else
+					spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 					return -EBUSY;
 				}
+#ifndef __PROC_HELL
 				cli();	/* all CPUs */
+#else
+				spin_lock_irqsave(&io_request_lock, flags);
+#endif
 			}
 		}
 		p = buffer;
@@ -213,7 +195,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";
@@ -281,7 +263,11 @@
 							break;
 					}
 					if (rc) {
+#ifndef __PROC_HELL
 						restore_flags(flags);	/* all CPUs */
+#else
+						spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 						printk("proc_ide_write_config: error writing %s at bus %02x dev %02x reg 0x%x value 0x%x\n",
 							msg, dev->bus->number, dev->devfn, reg, val);
 						printk("proc_ide_write_config: error %d\n", rc);
@@ -311,11 +297,11 @@
  * 
  */
 					switch (digits) {
-						case 2:	outb(val, reg);
+						case 2:	hwif->OUTB(val, reg);
 							break;
-						case 4:	outw(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 */
@@ -323,15 +309,23 @@
 			}
 		}
 	} while (!for_real++);
+#ifndef __PROC_HELL
 	restore_flags(flags);	/* all CPUs */
+#else
+	spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	return count;
 parse_error:
+#ifndef __PROC_HELL
 	restore_flags(flags);	/* all CPUs */
+#else
+	spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
 	printk("parse error\n");
 	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;
@@ -340,20 +334,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 */
@@ -362,6 +362,7 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
+EXPORT_SYMBOL(proc_ide_read_config);
 
 static int ide_getdigit(char c)
 {
@@ -373,7 +374,7 @@
 	return digit;
 }
 
-static int proc_ide_read_drivers
+int proc_ide_read_drivers
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	char		*out = page;
@@ -384,14 +385,17 @@
 	while (p) {
 		driver = (ide_driver_t *) p->info;
 		if (driver)
-			out += sprintf(out, "%s version %s\n", driver->name, driver->version);
+			out += sprintf(out, "%s version %s\n",
+				driver->name, driver->version);
 		p = p->next;
 	}
 	len = out - page;
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_read_imodel
+EXPORT_SYMBOL(proc_ide_read_drivers);
+
+int proc_ide_read_imodel
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_hwif_t	*hwif = (ide_hwif_t *) data;
@@ -421,7 +425,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;
@@ -434,7 +440,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;
@@ -446,31 +454,21 @@
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
-static int proc_ide_get_identify(ide_drive_t *drive, byte *buf)
-{
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-
-	taskfile.sector_count = 0x01;
-	taskfile.command = (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY ;
-
-	return ide_wait_taskfile(drive, &taskfile, &hobfile, buf);
-}
+EXPORT_SYMBOL(proc_ide_read_channel);
 
-static int proc_ide_read_identify
+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;
 	int		len = 0, i = 0;
 
-	if (drive && !proc_ide_get_identify(drive, page)) {
+	if (drive && !taskfile_lib_get_identify(drive, page)) {
 		unsigned short *val = (unsigned short *) page;
 		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;
@@ -480,7 +478,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;
@@ -510,9 +510,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;
@@ -587,6 +589,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)
 {
@@ -598,10 +602,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)
 {
@@ -609,24 +615,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;
@@ -636,11 +650,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;
@@ -652,7 +669,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;
@@ -676,6 +695,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 },
@@ -702,6 +723,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)
@@ -712,7 +735,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;
@@ -742,6 +767,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;
@@ -769,6 +796,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;
@@ -783,19 +812,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 },
@@ -823,7 +854,9 @@
 	}
 }
 
-static void destroy_proc_ide_interfaces(void)
+EXPORT_SYMBOL(create_proc_ide_interfaces);
+
+void destroy_proc_ide_interfaces(void)
 {
 	int	h;
 
@@ -844,8 +877,34 @@
 	}
 }
 
+EXPORT_SYMBOL(destroy_proc_ide_interfaces);
+
+#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 */
+
 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 */
+
 	proc_ide_root = proc_mkdir("ide", 0);
 	if (!proc_ide_root) return;
 
@@ -854,120 +913,40 @@
 	create_proc_read_entry("drivers", 0, proc_ide_root,
 				proc_ide_read_drivers, NULL);
 
-#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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-sibyte.c linux.20pre10-ac2/drivers/ide/ide-sibyte.c
--- linux.20pre10/drivers/ide/ide-sibyte.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-sibyte.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,333 +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_regs.h>
-#include <asm/sibyte/sb1250_int.h>
-#include <asm/sibyte/sb1250_genbus.h>
-#include <asm/sibyte/64bit.h>
-#include <asm/sibyte/board.h>
-
-/* Note: this should be general for any board using IDE on GenBus */
-
-extern struct ide_ops std_ide_ops;
-
-static ide_hwif_t *sb_ide_hwif = NULL;
-static unsigned long ide_base;
-
-#define SIBYTE_IDE_BASE        (KSEG1ADDR(ide_base)-mips_io_port_base)
-#define SIBYTE_IDE_REG(pcaddr) (SIBYTE_IDE_BASE + ((pcaddr)<<5))
-
-/*
- * We are limiting the number of PCI-IDE devices to leave room for
- * GenBus IDE (and possibly PCMCIA/CF?)
- */
-static int sibyte_ide_default_irq(ide_ioreg_t base)
-{
-	return 0;
-}
-
-static ide_ioreg_t sibyte_ide_default_io_base(int index)
-{
-	return 0;
-}
-
-static void sibyte_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port,
-				       ide_ioreg_t ctrl_port, int *irq)
-{
-	std_ide_ops.ide_init_hwif_ports(hw, data_port, ctrl_port, irq);
-}
-
-static int sibyte_ide_request_irq(unsigned int irq,
-                                void (*handler)(int,void *, struct pt_regs *),
-                                unsigned long flags, const char *device,
-                                void *dev_id)
-{
-	return request_irq(irq, handler, flags, device, dev_id);
-}
-
-static void sibyte_ide_free_irq(unsigned int irq, void *dev_id)
-{
-	free_irq(irq, dev_id);
-}
-
-static inline int is_sibyte_ide(ide_ioreg_t from)
-{
-	return (sb_ide_hwif &&
-		((from == sb_ide_hwif->io_ports[IDE_DATA_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_ERROR_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_NSECTOR_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_SECTOR_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_LCYL_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_HCYL_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_SELECT_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_STATUS_OFFSET]) ||
-		 (from == sb_ide_hwif->io_ports[IDE_CONTROL_OFFSET])));
-}
-
-static int sibyte_ide_check_region(ide_ioreg_t from, unsigned int extent)
-{
-	/* Figure out if it's the SiByte IDE; if so, don't do anything
-           since our I/O space is in a weird place. */
-	if (is_sibyte_ide(from))
-		return 0;
-	else
-#ifdef CONFIG_BLK_DEV_IDE
-		return std_ide_ops.ide_check_region(from, extent);
-#else
-		return 0;
-#endif
-}
-
-static void sibyte_ide_request_region(ide_ioreg_t from, unsigned int extent,
-				     const char *name)
-{
-#ifdef CONFIG_BLK_DEV_IDE
-	if (!is_sibyte_ide(from))
-		std_ide_ops.ide_request_region(from, extent, name);
-#endif
-}
-
-static void sibyte_ide_release_region(ide_ioreg_t from, unsigned int extent)
-{
-#ifdef CONFIG_BLK_DEV_IDE
-	if (!is_sibyte_ide(from))
-		std_ide_ops.ide_release_region(from, extent);
-#endif
-}
-
-struct ide_ops sibyte_ide_ops = {
-	&sibyte_ide_default_irq,
-	&sibyte_ide_default_io_base,
-	&sibyte_ide_init_hwif_ports,
-	&sibyte_ide_request_irq,
-	&sibyte_ide_free_irq,
-	&sibyte_ide_check_region,
-	&sibyte_ide_request_region,
-	&sibyte_ide_release_region
-};
-
-/*
- * I/O operations. The FPGA for SiByte generic bus IDE deals with
- * byte-swapping for us, so we can't share the I/O macros with other
- * IDE (e.g. PCI-IDE) devices.
- */
-
-#define sibyte_outb(val,port)					\
-do {								\
-	*(volatile u8 *)(mips_io_port_base + (port)) = val;	\
-} while(0)
-
-#define sibyte_outw(val,port)					\
-do {								\
-	*(volatile u16 *)(mips_io_port_base + (port)) = val;	\
-} while(0)
-
-#define sibyte_outl(val,port)					\
-do {								\
-	*(volatile u32 *)(mips_io_port_base + (port)) = val;	\
-} while(0)
-
-static inline unsigned char sibyte_inb(unsigned long port)
-{
-	return (*(volatile u8 *)(mips_io_port_base + (port)));
-}
-
-static inline unsigned short sibyte_inw(unsigned long port)
-{
-	return (*(volatile u16 *)(mips_io_port_base + (port)));
-}
-
-static inline unsigned int sibyte_inl(unsigned long port)
-{
-	return (*(volatile u32 *)(mips_io_port_base + (port)));
-}
-
-
-static inline void sibyte_outsb(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		sibyte_outb(*(u8 *)addr, port);
-		addr++;
-	}
-}
-
-static inline void sibyte_insb(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		*(u8 *)addr = sibyte_inb(port);
-		addr++;
-	}
-}
-
-static inline void sibyte_outsw(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		sibyte_outw(*(u16 *)addr, port);
-		addr += 2;
-	}
-}
-
-static inline void sibyte_insw(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		*(u16 *)addr = sibyte_inw(port);
-		addr += 2;
-	}
-}
-
-static inline void sibyte_outsl(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		sibyte_outl(*(u32 *)addr, port);
-		addr += 4;
-	}
-}
-
-static inline void sibyte_insl(unsigned long port, void *addr, unsigned int count)
-{
-	while (count--) {
-		*(u32 *)addr = sibyte_inl(port);
-		addr += 4;
-	}
-}
-
-static void sibyte_ideproc(ide_ide_action_t action, ide_drive_t *drive,
-			   void *buffer, unsigned int count)
-{
-	/*  slow? vlb_sync? */
-	switch (action) {
-	case ideproc_ide_input_data:
-		if (drive->io_32bit) {
-			sibyte_insl(IDE_DATA_REG, buffer, count);
-		} else {
-			sibyte_insw(IDE_DATA_REG, buffer, count<<1);
-		}
-		break;
-	case ideproc_ide_output_data:
-		if (drive->io_32bit) {
-			sibyte_outsl(IDE_DATA_REG, buffer, count);
-		} else {
-			sibyte_outsw(IDE_DATA_REG, buffer, count<<1);
-		}
-		break;
-	case ideproc_atapi_input_bytes:
-		count++;
-		if (drive->io_32bit) {
-			sibyte_insl(IDE_DATA_REG, buffer, count>>2);
-		} else {
-			sibyte_insw(IDE_DATA_REG, buffer, count>>1);
-		}
-		if ((count & 3) >= 2)
-			sibyte_insw(IDE_DATA_REG, (char *)buffer + (count & ~3), 1);
-		break;
-	case ideproc_atapi_output_bytes:
-		count++;
-		if (drive->io_32bit) {
-			sibyte_outsl(IDE_DATA_REG, buffer, count>>2);
-		} else {
-			sibyte_outsw(IDE_DATA_REG, buffer, count>>1);
-		}
-		if ((count & 3) >= 2)
-			sibyte_outsw(IDE_DATA_REG, (char *)buffer + (count & ~3), 1);
-		break;
-	}
-}
-
-/*
- * selectproc and intrproc aren't really necessary, since
- * byte-swapping doesn't affect byte ops; they are included for
- * consistency.
- */
-static void sibyte_selectproc(ide_drive_t *drive)
-{
-	sibyte_outb(drive->select.all, IDE_SELECT_REG);
-}
-
-static void sibyte_intrproc(ide_drive_t *drive)
-{
-	sibyte_outb(drive->ctl|2, IDE_CONTROL_REG);
-}
-
-void __init sibyte_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 SiByte onboard IDE driver in ide_hwifs[].  Not enabled.\n");
-		return;
-	}
-
-	/* Find memory base address */
-#ifdef __MIPSEL__
-	/* Pass1 workaround (bug 1624) */
-	if (sb1250_pass == K_SYS_REVISION_PASS1)
-		ide_base = G_IO_START_ADDR(csr_in32(4+(IO_SPACE_BASE|A_IO_EXT_REG(R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS))))) << S_IO_ADDRBASE;
-	else
-#endif
-		ide_base = G_IO_START_ADDR(csr_in32(IO_SPACE_BASE|A_IO_EXT_REG(R_IO_EXT_REG(R_IO_EXT_START_ADDR, IDE_CS)))) << S_IO_ADDRBASE;
-
-	/*
-	 * Set up our stuff; we're a little odd because our io_ports
-	 * aren't in the usual place, and byte-swapping isn't
-	 * necessary.
-	 */
-	hwif = &ide_hwifs[i];
-	hwif->hw.io_ports[IDE_DATA_OFFSET]    = SIBYTE_IDE_REG(0x1f0);
-	hwif->hw.io_ports[IDE_ERROR_OFFSET]   = SIBYTE_IDE_REG(0x1f1);
-	hwif->hw.io_ports[IDE_NSECTOR_OFFSET] = SIBYTE_IDE_REG(0x1f2);
-	hwif->hw.io_ports[IDE_SECTOR_OFFSET]  = SIBYTE_IDE_REG(0x1f3);
-	hwif->hw.io_ports[IDE_LCYL_OFFSET]    = SIBYTE_IDE_REG(0x1f4);
-	hwif->hw.io_ports[IDE_HCYL_OFFSET]    = SIBYTE_IDE_REG(0x1f5);
-	hwif->hw.io_ports[IDE_SELECT_OFFSET]  = SIBYTE_IDE_REG(0x1f6);
-	hwif->hw.io_ports[IDE_STATUS_OFFSET]  = SIBYTE_IDE_REG(0x1f7);
-	hwif->hw.io_ports[IDE_CONTROL_OFFSET] = SIBYTE_IDE_REG(0x3f6);
-	hwif->hw.irq                          = K_INT_GB_IDE;
-	hwif->irq                             = K_INT_GB_IDE;
-	hwif->noprobe                         = 0;
-	/* Use our own non-byte-swapping routines */
-	hwif->ideproc                         = sibyte_ideproc;
-	hwif->selectproc                      = sibyte_selectproc;
-	hwif->intrproc                        = sibyte_intrproc;
-
-	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
-	printk("SiByte onboard IDE configured as device %i\n", i);
-	sb_ide_hwif = hwif;
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-tape.c linux.20pre10-ac2/drivers/ide/ide-tape.c
--- linux.20pre10/drivers/ide/ide-tape.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-tape.c	2002-09-06 14:07:01.000000000 +0100
@@ -416,7 +416,6 @@
 #include <linux/errno.h>
 #include <linux/genhd.h>
 #include <linux/slab.h>
-#include <linux/pci.h>
 #include <linux/ide.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
@@ -724,22 +723,28 @@
 	struct buffer_head *bh;
 	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;
 
 /*
  *	Packet command flag bits.
  */
-#define	PC_ABORT			0	/* Set when an error is considered normal - We won't retry */
-#define PC_WAIT_FOR_DSC			1	/* 1 When polling for DSC on a media access command */
-#define PC_DMA_RECOMMENDED		2	/* 1 when we prefer to use DMA if possible */
-#define	PC_DMA_IN_PROGRESS		3	/* 1 while DMA in progress */
-#define	PC_DMA_ERROR			4	/* 1 when encountered problem during DMA */
-#define	PC_WRITING			5	/* Data direction */
+/* Set when an error is considered normal - We won't retry */
+#define	PC_ABORT			0
+/* 1 When polling for DSC on a media access command */
+#define PC_WAIT_FOR_DSC			1
+/* 1 when we prefer to use DMA if possible */
+#define PC_DMA_RECOMMENDED		2
+/* 1 while DMA in progress */
+#define	PC_DMA_IN_PROGRESS		3
+/* 1 when encountered problem during DMA */
+#define	PC_DMA_ERROR			4
+/* Data direction */
+#define	PC_WRITING			5
 
 /*
  *	Capabilities and Mechanical Status Page
@@ -814,6 +819,7 @@
  *	REQUEST SENSE packet command result - Data Format.
  */
 typedef struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
 	unsigned	error_code	:7;	/* Current of deferred errors */
 	unsigned	valid		:1;	/* The information field conforms to QIC-157C */
 	__u8		reserved1	:8;	/* Segment Number - Reserved */
@@ -822,6 +828,18 @@
 	unsigned	ili		:1;	/* Incorrect Length Indicator */
 	unsigned	eom		:1;	/* End Of Medium */
 	unsigned	filemark 	:1;	/* Filemark */
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	unsigned	valid		:1;
+	unsigned	error_code	:7;
+	__u8		reserved1	:8;
+	unsigned	filemark	:1;
+	unsigned	eom		:1;
+	unsigned	ili		:1;
+	unsigned	reserved2_4	:1;
+	unsigned	sense_key	:4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
 	__u32		information __attribute__ ((packed));
 	__u8		asl;			/* Additional sense length (n-7) */
 	__u32		command_specific;	/* Additional command specific information */
@@ -860,12 +878,17 @@
 	 *	required since an additional packet command is needed before the
 	 *	retry, to get detailed information on what went wrong.
 	 */
-	idetape_pc_t *pc;			/* Current packet command */
-	idetape_pc_t *failed_pc; 		/* Last failed packet command */
-	idetape_pc_t pc_stack[IDETAPE_PC_STACK];/* Packet command stack */
-	int pc_stack_index;			/* Next free packet command storage space */
+	/* Current packet command */
+	idetape_pc_t *pc;
+	/* Last failed packet command */
+	idetape_pc_t *failed_pc;
+	/* Packet command stack */
+	idetape_pc_t pc_stack[IDETAPE_PC_STACK];
+	/* Next free packet command storage space */
+	int pc_stack_index;
 	struct request rq_stack[IDETAPE_PC_STACK];
-	int rq_stack_index;			/* We implement a circular array */
+	/* We implement a circular array */
+	int rq_stack_index;
 
 	/*
 	 *	DSC polling variables.
@@ -879,38 +902,48 @@
 	 *	to ide.c only one at a time.
 	 */
 	struct request *postponed_rq;
-	unsigned long dsc_polling_start;	/* The time in which we started polling for DSC */
-	struct timer_list dsc_timer;		/* Timer used to poll for dsc */
-	unsigned long best_dsc_rw_frequency;	/* Read/Write dsc polling frequency */
-	unsigned long dsc_polling_frequency;	/* The current polling frequency */
-	unsigned long dsc_timeout;		/* Maximum waiting time */
+	/* The time in which we started polling for DSC */
+	unsigned long dsc_polling_start;
+	/* Timer used to poll for dsc */
+	struct timer_list dsc_timer;
+	/* Read/Write dsc polling frequency */
+	unsigned long best_dsc_rw_frequency;
+	/* The current polling frequency */
+	unsigned long dsc_polling_frequency;
+	/* Maximum waiting time */
+	unsigned long dsc_timeout;
 
 	/*
 	 *	Read position information
 	 */
-	byte partition;
-	unsigned int first_frame_position;		/* Current block */
+	u8 partition;
+	/* Current block */
+	unsigned int first_frame_position;
 	unsigned int last_frame_position;
 	unsigned int blocks_in_buffer;
 
 	/*
 	 *	Last error information
 	 */
-	byte sense_key, asc, ascq;
+	u8 sense_key, asc, ascq;
 
 	/*
 	 *	Character device operation
 	 */
 	unsigned int minor;
-	char name[4];					/* device name */
-	idetape_chrdev_direction_t chrdev_direction;	/* Current character device data transfer direction */
+	/* device name */
+	char name[4];
+	/* Current character device data transfer direction */
+	idetape_chrdev_direction_t chrdev_direction;
 
 	/*
 	 *	Device information
 	 */
-	unsigned short tape_block_size;			/* Usually 512 or 1024 bytes */
+	/* Usually 512 or 1024 bytes */
+	unsigned short tape_block_size;
 	int user_bs_factor;
-	idetape_capabilities_page_t capabilities;	/* Copy of the tape's Capabilities and Mechanical Page */
+	/* Copy of the tape's Capabilities and Mechanical Page */
+	idetape_capabilities_page_t capabilities;
 
 	/*
 	 *	Active data transfer request parameters.
@@ -925,8 +958,10 @@
 	 *	The data buffer size is chosen based on the tape's
 	 *	recommendation.
 	 */
-	struct request *active_data_request;	/* Pointer to the request which is waiting in the device request queue */
-	int stage_size;				/* Data buffer size (chosen based on the tape's recommendation */
+	/* Pointer to the request, waiting in the device request queue */
+	struct request *active_data_request;
+	/* Data buffer size (chosen based on the tape's recommendation */
+	int stage_size;
 	idetape_stage_t *merge_stage;
 	int merge_stage_size;
 	struct buffer_head *bh;
@@ -939,19 +974,30 @@
 	 *	To accomplish non-pipelined mode, we simply set the following
 	 *	variables to zero (or NULL, where appropriate).
 	 */
-	int nr_stages;				/* Number of currently used stages */
-	int nr_pending_stages;			/* Number of pending stages */
-	int max_stages, min_pipeline, max_pipeline; /* We will not allocate more than this number of stages */
-	idetape_stage_t *first_stage;		/* The first stage which will be removed from the pipeline */
-	idetape_stage_t *active_stage;		/* The currently active stage */
-	idetape_stage_t *next_stage;		/* Will be serviced after the currently active request */
-	idetape_stage_t *last_stage;		/* New requests will be added to the pipeline here */
-	idetape_stage_t *cache_stage;		/* Optional free stage which we can use */
+	/* Number of currently used stages */
+	int nr_stages;
+	/* Number of pending stages */
+	int nr_pending_stages;
+	/* We will not allocate more than this number of stages */
+	int max_stages, min_pipeline, max_pipeline;
+	/* The first stage which will be removed from the pipeline */
+	idetape_stage_t *first_stage;
+	/* The currently active stage */
+	idetape_stage_t *active_stage;
+	/* Will be serviced after the currently active request */
+	idetape_stage_t *next_stage;
+	/* New requests will be added to the pipeline here */
+	idetape_stage_t *last_stage;
+	/* Optional free stage which we can use */
+	idetape_stage_t *cache_stage;
 	int pages_per_stage;
-	int excess_bh_size;			/* Wasted space in each stage */
+	/* Wasted space in each stage */
+	int excess_bh_size;
 
-	unsigned long flags;			/* Status/Action flags: long for set_bit */
-	spinlock_t spinlock;			/* protects the ide-tape queue */
+	/* Status/Action flags: long for set_bit */
+	unsigned long flags;
+	/* protects the ide-tape queue */
+	spinlock_t spinlock;
 
 	/*
 	 * Measures average tape speed
@@ -960,31 +1006,44 @@
 	int avg_size;
 	int avg_speed;
 
-	idetape_request_sense_result_t sense;	/* last sense information */
+	/* last sense information */
+	idetape_request_sense_result_t sense;
 
 	char vendor_id[10];
 	char product_id[18];
 	char firmware_revision[6];
 	int firmware_revision_num;
 
-	int door_locked;			/* the door is currently locked */
+	/* the door is currently locked */
+	int door_locked;
 
 	/*
 	 * OnStream flags
 	 */
-	int onstream;				/* the tape is an OnStream tape */
-	int raw;				/* OnStream raw access (32.5KB block size) */
-	int cur_frames;				/* current number of frames in internal buffer */
-	int max_frames;				/* max number of frames in internal buffer */
-	int logical_blk_num;			/* logical block number */
-	__u16 wrt_pass_cntr;			/* write pass counter */
-	__u32 update_frame_cntr;		/* update frame counter */
+	/* the tape is an OnStream tape */
+	int onstream;
+	/* OnStream raw access (32.5KB block size) */
+	int raw;
+	/* current number of frames in internal buffer */
+	int cur_frames;
+	/* max number of frames in internal buffer */
+	int max_frames;
+	/* logical block number */
+	int logical_blk_num;
+	/* write pass counter */
+	__u16 wrt_pass_cntr;
+	/* update frame counter */
+	__u32 update_frame_cntr;
 	struct completion *waiting;
-	int onstream_write_error;		/* write error recovery active */
-	int header_ok;				/* header frame verified ok */
-	int linux_media;			/* reading linux-specifc media */
+	/* write error recovery active */
+	int onstream_write_error;
+	/* header frame verified ok */
+	int header_ok;
+	/* reading linux-specifc media */
+	int linux_media;
 	int linux_media_version;
-	char application_sig[5];		/* application signature */
+	/* application signature */
+	char application_sig[5];
 	int filemark_cnt;
 	int first_mark_addr;
 	int last_mark_addr;
@@ -997,8 +1056,10 @@
 	 * Optimize the number of "buffer filling"
 	 * mode sense commands.
 	 */
-	unsigned long last_buffer_fill;		/* last time in which we issued fill cmd */
-	int req_buffer_fill;			/* buffer fill command requested */
+	/* last time in which we issued fill cmd */
+	unsigned long last_buffer_fill;
+	/* buffer fill command requested */
+	int req_buffer_fill;
 	int writes_since_buffer_fill;
 	int reads_since_buffer_fill;
 
@@ -1007,7 +1068,8 @@
 	 * be postponed, to avoid an infinite postpone
 	 * deadlock.
 	 */
-	int postpone_cnt;			/* request postpone count limit */
+	/* request postpone count limit */
+	int postpone_cnt;
 
 	/*
 	 * Measures number of frames:
@@ -1040,11 +1102,17 @@
 	 * Speed regulation negative feedback loop
 	 */
 	int speed_control;
-	int pipeline_head_speed, controlled_pipeline_head_speed, uncontrolled_pipeline_head_speed;
-	int controlled_last_pipeline_head, uncontrolled_last_pipeline_head;
-	unsigned long uncontrolled_pipeline_head_time, controlled_pipeline_head_time;
-	int controlled_previous_pipeline_head, uncontrolled_previous_pipeline_head;
-	unsigned long controlled_previous_head_time, uncontrolled_previous_head_time;
+	int pipeline_head_speed;
+	int controlled_pipeline_head_speed;
+	int uncontrolled_pipeline_head_speed;
+	int controlled_last_pipeline_head;
+	int uncontrolled_last_pipeline_head;
+	unsigned long uncontrolled_pipeline_head_time;
+	unsigned long controlled_pipeline_head_time;
+	int controlled_previous_pipeline_head;
+	int uncontrolled_previous_pipeline_head;
+	unsigned long controlled_previous_head_time;
+	unsigned long uncontrolled_previous_head_time;
 	int restart_speed_control_req;
 
         /*
@@ -1164,101 +1232,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.
@@ -1432,41 +1405,60 @@
  * 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: {
 			char buf[22];
-			sprintf(buf, "IDETAPE_SENSE (0x%02x)", idetape_sense_key);
+			sprintf(buf, "IDETAPE_SENSE (0x%02x)",
+				idetape_sense_key);
 			return(buf);
 		}
 
 	}
 }
 
-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");
-		case IDETAPE_REWIND_CMD:		return("REWIND_CMD");
-		case IDETAPE_REQUEST_SENSE_CMD:		return("REQUEST_SENSE_CMD");
-		case IDETAPE_READ_CMD:			return("READ_CMD");
-		case IDETAPE_WRITE_CMD:			return("WRITE_CMD");
-		case IDETAPE_WRITE_FILEMARK_CMD:	return("WRITE_FILEMARK_CMD");
-		case IDETAPE_SPACE_CMD:			return("SPACE_CMD");
-		case IDETAPE_INQUIRY_CMD:		return("INQUIRY_CMD");
-		case IDETAPE_ERASE_CMD:			return("ERASE_CMD");
-		case IDETAPE_MODE_SENSE_CMD:		return("MODE_SENSE_CMD");
-		case IDETAPE_MODE_SELECT_CMD:		return("MODE_SELECT_CMD");
-		case IDETAPE_LOAD_UNLOAD_CMD:		return("LOAD_UNLOAD_CMD");
-		case IDETAPE_PREVENT_CMD:		return("PREVENT_CMD");
-		case IDETAPE_LOCATE_CMD:		return("LOCATE_CMD");
-		case IDETAPE_READ_POSITION_CMD:		return("READ_POSITION_CMD");
-		case IDETAPE_READ_BUFFER_CMD:		return("READ_BUFFER_CMD");
-		case IDETAPE_SET_SPEED_CMD:		return("SET_SPEED_CMD");
+		case IDETAPE_TEST_UNIT_READY_CMD:
+			return("TEST_UNIT_READY_CMD");
+		case IDETAPE_REWIND_CMD:
+			return("REWIND_CMD");
+		case IDETAPE_REQUEST_SENSE_CMD:
+			return("REQUEST_SENSE_CMD");
+		case IDETAPE_READ_CMD:
+			return("READ_CMD");
+		case IDETAPE_WRITE_CMD:
+			return("WRITE_CMD");
+		case IDETAPE_WRITE_FILEMARK_CMD:
+			return("WRITE_FILEMARK_CMD");
+		case IDETAPE_SPACE_CMD:
+			return("SPACE_CMD");
+		case IDETAPE_INQUIRY_CMD:
+			return("INQUIRY_CMD");
+		case IDETAPE_ERASE_CMD:
+			return("ERASE_CMD");
+		case IDETAPE_MODE_SENSE_CMD:
+			return("MODE_SENSE_CMD");
+		case IDETAPE_MODE_SELECT_CMD:
+			return("MODE_SELECT_CMD");
+		case IDETAPE_LOAD_UNLOAD_CMD:
+			return("LOAD_UNLOAD_CMD");
+		case IDETAPE_PREVENT_CMD:
+			return("PREVENT_CMD");
+		case IDETAPE_LOCATE_CMD:
+			return("LOCATE_CMD");
+		case IDETAPE_READ_POSITION_CMD:
+			return("READ_POSITION_CMD");
+		case IDETAPE_READ_BUFFER_CMD:
+			return("READ_BUFFER_CMD");
+		case IDETAPE_SET_SPEED_CMD:
+			return("SET_SPEED_CMD");
 		default: {
 				char buf[20];
-				sprintf(buf, "CMD (0x%02x)", idetape_command_key);
+				sprintf(buf, "CMD (0x%02x)",
+					idetape_command_key);
 				return(buf);
 			}
 	}
@@ -1482,13 +1474,13 @@
 static void idetape_write_release (struct inode *inode);
 
 /*
- *	Too bad. The drive wants to send us data which we are not ready to accept.
- *	Just throw it away.
+ * Too bad. The drive wants to send us data which we are not ready to accept.
+ * Just throw it away.
  */
 static void idetape_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 idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
@@ -1499,13 +1491,14 @@
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_input_buffers\n");
-			idetape_discard_data (drive, bcount);
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
+			idetape_discard_data(drive, bcount);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), bcount);
-		atapi_input_bytes (drive, bh->b_data + atomic_read(&bh->b_count), count);
+		count = IDE_MIN(bh->b_size - atomic_read(&bh->b_count), bcount);
+		HWIF(drive)->atapi_input_bytes(drive, bh->b_data + atomic_read(&bh->b_count), count);
 		bcount -= count;
 		atomic_add(count, &bh->b_count);
 		if (atomic_read(&bh->b_count) == bh->b_size) {
@@ -1525,12 +1518,13 @@
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_output_buffers\n");
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (pc->b_count, bcount);
-		atapi_output_bytes (drive, pc->b_data, count);
+		count = IDE_MIN(pc->b_count, bcount);
+		HWIF(drive)->atapi_output_bytes(drive, pc->b_data, count);
 		bcount -= count;
 		pc->b_data += count;
 		pc->b_count -= count;
@@ -1550,16 +1544,17 @@
 	struct buffer_head *bh = pc->bh;
 	int count, bcount = pc->actually_transferred;
 
-	if (test_bit (PC_WRITING, &pc->flags))
+	if (test_bit(PC_WRITING, &pc->flags))
 		return;
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_update_buffers\n");
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size, bcount);
+		count = IDE_MIN(bh->b_size, bcount);
 		atomic_set(&bh->b_count, count);
 		if (atomic_read(&bh->b_count) == bh->b_size)
 			bh = bh->b_reqnext;
@@ -1581,9 +1576,10 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 5)
-		printk (KERN_INFO "ide-tape: pc_stack_index=%d\n",tape->pc_stack_index);
+		printk(KERN_INFO "ide-tape: pc_stack_index=%d\n",
+			tape->pc_stack_index);
 #endif /* IDETAPE_DEBUG_LOG */
-	if (tape->pc_stack_index==IDETAPE_PC_STACK)
+	if (tape->pc_stack_index == IDETAPE_PC_STACK)
 		tape->pc_stack_index=0;
 	return (&tape->pc_stack[tape->pc_stack_index++]);
 }
@@ -1607,9 +1603,10 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 5)
-		printk (KERN_INFO "ide-tape: rq_stack_index=%d\n",tape->rq_stack_index);
+		printk(KERN_INFO "ide-tape: rq_stack_index=%d\n",
+			tape->rq_stack_index);
 #endif /* IDETAPE_DEBUG_LOG */
-	if (tape->rq_stack_index==IDETAPE_PC_STACK)
+	if (tape->rq_stack_index == IDETAPE_PC_STACK)
 		tape->rq_stack_index=0;
 	return (&tape->rq_stack[tape->rq_stack_index++]);
 }
@@ -1619,7 +1616,7 @@
  */
 static void idetape_init_pc (idetape_pc_t *pc)
 {
-	memset (pc->c, 0, 12);
+	memset(pc->c, 0, 12);
 	pc->retries = 0;
 	pc->flags = 0;
 	pc->request_transfer = 0;
@@ -1649,19 +1646,23 @@
 	 *	give up retrying.
 	 */
 	if (tape->debug_level >= 1)
-		printk (KERN_INFO "ide-tape: pc = %x, sense key = %x, asc = %x, ascq = %x\n",
-				pc->c[0], result->sense_key, result->asc, result->ascq);
+		printk(KERN_INFO "ide-tape: pc = %x, sense key = %x, "
+			"asc = %x, ascq = %x\n",
+			pc->c[0], result->sense_key,
+			result->asc, result->ascq);
 #if IDETAPE_DEBUG_LOG_VERBOSE
 	if (tape->debug_level >= 1)
-		printk (KERN_INFO "ide-tape: pc = %s, sense key = %x, asc = %x, ascq = %x\n",
-			idetape_command_key_verbose((byte) pc->c[0]),
+		printk (KERN_INFO "ide-tape: pc = %s, sense key = %x, "
+			"asc = %x, ascq = %x\n",
+			idetape_command_key_verbose((u8) pc->c[0]),
 			result->sense_key,
 			result->asc,
 			result->ascq);
 #endif /* IDETAPE_DEBUG_LOG_VERBOSE */
 #endif /* IDETAPE_DEBUG_LOG */
 
-	if (tape->onstream && result->sense_key == 2 && result->asc == 0x53 && result->ascq == 2) {
+	if (tape->onstream && result->sense_key == 2 &&
+	    result->asc == 0x53 && result->ascq == 2) {
 		clear_bit(PC_DMA_ERROR, &pc->flags);
 		ide_stall_queue(drive, HZ / 2);
 		return;
@@ -1671,27 +1672,29 @@
 	/*
 	 *	Correct pc->actually_transferred by asking the tape.
 	 */
-	if (test_bit (PC_DMA_ERROR, &pc->flags)) {
-		pc->actually_transferred = pc->request_transfer - tape->tape_block_size * ntohl (get_unaligned (&result->information));
-		idetape_update_buffers (pc);
+	if (test_bit(PC_DMA_ERROR, &pc->flags)) {
+		pc->actually_transferred = pc->request_transfer - tape->tape_block_size * ntohl(get_unaligned (&result->information));
+		idetape_update_buffers(pc);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 	if (pc->c[0] == IDETAPE_READ_CMD && result->filemark) {
 		pc->error = IDETAPE_ERROR_FILEMARK;
-		set_bit (PC_ABORT, &pc->flags);
+		set_bit(PC_ABORT, &pc->flags);
 	}
 	if (pc->c[0] == IDETAPE_WRITE_CMD) {
-		if (result->eom || (result->sense_key == 0xd && result->asc == 0x0 && result->ascq == 0x2)) {
+		if (result->eom || (result->sense_key == 0xd &&
+		    result->asc == 0x0 && result->ascq == 0x2)) {
 			pc->error = IDETAPE_ERROR_EOD;
-			set_bit (PC_ABORT, &pc->flags);
+			set_bit(PC_ABORT, &pc->flags);
 		}
 	}
 	if (pc->c[0] == IDETAPE_READ_CMD || pc->c[0] == IDETAPE_WRITE_CMD) {
 		if (result->sense_key == 8) {
 			pc->error = IDETAPE_ERROR_EOD;
-			set_bit (PC_ABORT, &pc->flags);
+			set_bit(PC_ABORT, &pc->flags);
 		}
-		if (!test_bit (PC_ABORT, &pc->flags) && (tape->onstream || pc->actually_transferred))
+		if (!test_bit(PC_ABORT, &pc->flags) &&
+		    (tape->onstream || pc->actually_transferred))
 			pc->retries = IDETAPE_MAX_PC_RETRIES + 1;
 	}
 }
@@ -1703,7 +1706,8 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name);
+		printk(KERN_INFO "ide-tape: %s: %s called\n",
+			tape->name, __FUNCTION__);
 #endif
 	while (stage) {
 		if (stage->rq.cmd == IDETAPE_WRITE_RQ)
@@ -1725,11 +1729,12 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_active_next_stage\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 #if IDETAPE_DEBUG_BUGS
 	if (stage == NULL) {
-		printk (KERN_ERR "ide-tape: bug: Trying to activate a non existing stage\n");
+		printk(KERN_ERR "ide-tape: bug: Trying to activate a "
+			"non existing stage\n");
 		return;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */	
@@ -1755,7 +1760,7 @@
 	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_increase_max_pipeline_stages\n");
+		printk (KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	tape->max_stages += increase;
@@ -1776,21 +1781,21 @@
 		if (bh->b_data != NULL) {
 			size = (int) bh->b_size;
 			while (size > 0) {
-				free_page ((unsigned long) bh->b_data);
+				free_page((unsigned long) bh->b_data);
 				size -= PAGE_SIZE;
 				bh->b_data += PAGE_SIZE;
 			}
 		}
 		prev_bh = bh;
 		bh = bh->b_reqnext;
-		kfree (prev_bh);
+		kfree(prev_bh);
 	}
-	kfree (stage);
+	kfree(stage);
 }
 
 static void idetape_kfree_stage (idetape_tape_t *tape, idetape_stage_t *stage)
 {
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 }
 
 /*
@@ -1804,29 +1809,32 @@
 	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_remove_stage_head\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 #if IDETAPE_DEBUG_BUGS
 	if (tape->first_stage == NULL) {
-		printk (KERN_ERR "ide-tape: bug: tape->first_stage is NULL\n");
+		printk(KERN_ERR "ide-tape: bug: tape->first_stage is NULL\n");
 		return;		
 	}
 	if (tape->active_stage == tape->first_stage) {
-		printk (KERN_ERR "ide-tape: bug: Trying to free our active pipeline stage\n");
+		printk(KERN_ERR "ide-tape: bug: Trying to free our "
+			"active pipeline stage\n");
 		return;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 	stage = tape->first_stage;
 	tape->first_stage = stage->next;
-	idetape_kfree_stage (tape, stage);
+	idetape_kfree_stage(tape, stage);
 	tape->nr_stages--;
 	if (tape->first_stage == NULL) {
 		tape->last_stage = NULL;
 #if IDETAPE_DEBUG_BUGS
 		if (tape->next_stage != NULL)
-			printk (KERN_ERR "ide-tape: bug: tape->next_stage != NULL\n");
+			printk(KERN_ERR "ide-tape: bug: "
+				"tape->next_stage != NULL\n");
 		if (tape->nr_stages)
-			printk (KERN_ERR "ide-tape: bug: nr_stages should be 0 now\n");
+			printk(KERN_ERR "ide-tape: bug: nr_stages should "
+				"be 0 now\n");
 #endif /* IDETAPE_DEBUG_BUGS */
 	}
 }
@@ -1835,10 +1843,9 @@
  *	idetape_end_request is used to finish servicing a request, and to
  *	insert a pending pipeline request into the main device queue.
  */
-static void idetape_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
+static int idetape_end_request (ide_drive_t *drive, int uptodate)
 {
-	ide_drive_t *drive = hwgroup->drive;
-	struct request *rq = hwgroup->rq;
+	struct request *rq = HWGROUP(drive)->rq;
 	idetape_tape_t *tape = drive->driver_data;
 	unsigned long flags;
 	int error;
@@ -1851,7 +1858,7 @@
 
 #if IDETAPE_DEBUG_LOG
         if (tape->debug_level >= 4)
-	printk (KERN_INFO "ide-tape: Reached idetape_end_request\n");
+		printk (KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	switch (uptodate) {
@@ -1864,7 +1871,8 @@
 		tape->failed_pc = NULL;
 
 	spin_lock_irqsave(&tape->spinlock, flags);
-	if (tape->active_data_request == rq) {		/* The request was a pipelined data transfer request */
+	if (tape->active_data_request == rq) {
+		/* The request was a pipelined data transfer request */
 		tape->active_stage = NULL;
 		tape->active_data_request = NULL;
 		tape->nr_pending_stages--;
@@ -1893,11 +1901,13 @@
 			}
 			remove_stage = 1;
 			if (error) {
-				set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+				set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 				if (error == IDETAPE_ERROR_EOD)
-					idetape_abort_pipeline (drive);
-				if (tape->onstream && !tape->raw && error == IDETAPE_ERROR_GENERAL && tape->sense.sense_key == 3) {
-					clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+					idetape_abort_pipeline(drive);
+				if (tape->onstream && !tape->raw &&
+				    error == IDETAPE_ERROR_GENERAL &&
+				    tape->sense.sense_key == 3) {
+					clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 					printk(KERN_ERR "ide-tape: %s: write error, enabling error recovery\n", tape->name);
 					tape->onstream_write_error = OS_WRITE_ERROR;
 					remove_stage = 0;
@@ -1910,7 +1920,7 @@
 			}
 		} else if (rq->cmd == IDETAPE_READ_RQ) {
 			if (error == IDETAPE_ERROR_EOD) {
-				set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+				set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 				idetape_abort_pipeline(drive);
 			}
 		}
@@ -1920,18 +1930,19 @@
 			/*
 			 *	Insert the next request into the request queue.
 			 */
-			(void) ide_do_drive_cmd (drive, tape->active_data_request, ide_end);
+			(void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
 		} else if (!error) {
 			if (!tape->onstream)
-				idetape_increase_max_pipeline_stages (drive);
+				idetape_increase_max_pipeline_stages(drive);
 		}
 	}
-	ide_end_drive_cmd (drive, 0, 0);
+	ide_end_drive_cmd(drive, 0, 0);
 	if (remove_stage)
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 	if (tape->active_data_request == NULL)
 		clear_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
 	spin_unlock_irqrestore(&tape->spinlock, flags);
+	return 0;
 }
 
 static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive)
@@ -1940,21 +1951,22 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 	if (!tape->pc->error) {
-		idetape_analyze_error (drive, (idetape_request_sense_result_t *) tape->pc->buffer);
-		idetape_end_request (1, HWGROUP (drive));
+		idetape_analyze_error(drive, (idetape_request_sense_result_t *) tape->pc->buffer);
+		idetape_end_request(drive, 1);
 	} else {
-		printk (KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n");
-		idetape_end_request (0, HWGROUP (drive));
+		printk(KERN_ERR "ide-tape: Error in REQUEST SENSE "
+			"itself - Aborting request!\n");
+		idetape_end_request(drive, 0);
 	}
 	return ide_stopped;
 }
 
 static void idetape_create_request_sense_cmd (idetape_pc_t *pc)
 {
-	idetape_init_pc (pc);	
+	idetape_init_pc(pc);	
 	pc->c[0] = IDETAPE_REQUEST_SENSE_CMD;
 	pc->c[4] = 20;
 	pc->request_transfer = 18;
@@ -1982,10 +1994,10 @@
  */
 static void idetape_queue_pc_head (ide_drive_t *drive,idetape_pc_t *pc,struct request *rq)
 {
-	ide_init_drive_cmd (rq);
+	ide_init_drive_cmd(rq);
 	rq->buffer = (char *) pc;
 	rq->cmd = IDETAPE_PC_RQ1;
-	(void) ide_do_drive_cmd (drive, rq, ide_preempt);
+	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
 
 /*
@@ -1998,14 +2010,14 @@
 	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);
+	error.all = HWIF(drive)->INB(IDE_ERROR_REG);
 	pc = idetape_next_pc_storage (drive);
 	rq = idetape_next_rq_storage (drive);
-	idetape_create_request_sense_cmd (pc);
-	set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
-	idetape_queue_pc_head (drive, pc, rq);
+	idetape_create_request_sense_cmd(pc);
+	set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
+	idetape_queue_pc_head(drive, pc, rq);
 	return ide_stopped;
 }
 
@@ -2037,9 +2049,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;
@@ -2050,14 +2062,16 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_pc_intr interrupt handler\n");
+		printk(KERN_INFO "ide-tape: Reached idetape_pc_intr "
+				"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 (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+		if (HWIF(drive)->ide_dma_end(drive)) {
 			/*
 			 * A DMA error is sometimes expected. For example,
 			 * if the tape is crossing a filemark during a
@@ -2081,106 +2095,144 @@
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
-	if (!status.b.drq) {						/* No more interrupts */
+	if (!status.b.drq) {			/* No more interrupts */
 		cmd_time = (jiffies - tape->cmd_start_time) * 1000 / HZ;
 		tape->max_cmd_time = IDE_MAX(cmd_time, tape->max_cmd_time);
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 2)
-			printk (KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred);
+			printk(KERN_INFO "ide-tape: Packet command completed, "
+				"%d bytes transferred\n",
+				pc->actually_transferred);
 #endif /* IDETAPE_DEBUG_LOG */
-		clear_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
 
-		ide__sti();	/* local CPU only */
+		local_irq_enable();
 
 #if SIMULATE_ERRORS
-		if ((pc->c[0] == IDETAPE_WRITE_CMD || pc->c[0] == IDETAPE_READ_CMD) && (++error_sim_count % 100) == 0) {
-			printk(KERN_INFO "ide-tape: %s: simulating error\n", tape->name);
+		if ((pc->c[0] == IDETAPE_WRITE_CMD ||
+		     pc->c[0] == IDETAPE_READ_CMD) &&
+		    (++error_sim_count % 100) == 0) {
+			printk(KERN_INFO "ide-tape: %s: simulating error\n",
+				tape->name);
 			status.b.check = 1;
 		}
 #endif
 		if (status.b.check && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD)
 			status.b.check = 0;
-		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 IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 1)
-				printk (KERN_INFO "ide-tape: %s: I/O error, ",tape->name);
+				printk(KERN_INFO "ide-tape: %s: I/O error, ",
+					tape->name);
 #endif /* IDETAPE_DEBUG_LOG */
 			if (pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-				printk (KERN_ERR "ide-tape: I/O error in request sense command\n");
-				return ide_do_reset (drive);
+				printk(KERN_ERR "ide-tape: I/O error in "
+					"request sense command\n");
+				return ide_do_reset(drive);
 			}
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 1)
-				printk(KERN_INFO "ide-tape: [cmd %x]: check condition\n", pc->c[0]);
+				printk(KERN_INFO "ide-tape: [cmd %x]: check "
+					"condition\n", pc->c[0]);
 #endif
-			return idetape_retry_pc (drive);				/* Retry operation */
+			/* Retry operation */
+			return idetape_retry_pc(drive);
 		}
 		pc->error = 0;
-		if (!tape->onstream && test_bit (PC_WAIT_FOR_DSC, &pc->flags) && !status.b.dsc) {	/* Media access command */
+		if (!tape->onstream &&
+		    test_bit(PC_WAIT_FOR_DSC, &pc->flags) &&
+		    !status.b.dsc) {
+			/* Media access command */
 			tape->dsc_polling_start = jiffies;
 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST;
 			tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
-			idetape_postpone_request (drive);		/* Allow ide.c to handle other requests */
+			/* Allow ide.c to handle other requests */
+			idetape_postpone_request(drive);
 			return ide_stopped;
 		}
 		if (tape->failed_pc == pc)
 			tape->failed_pc = NULL;
-		return pc->callback(drive);			/* Command finished - Call the callback function */
+		/* Command finished - Call the callback function */
+		return pc->callback(drive);
 	}
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
-		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);
-		return ide_do_reset (drive);
+	if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
+		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)->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-tape: CoD != 0 in idetape_pc_intr\n");
-		return ide_do_reset (drive);
+		printk(KERN_ERR "ide-tape: CoD != 0 in idetape_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-tape: We wanted to %s, ", ireason.b.io ? "Write":"Read");
-		printk (KERN_ERR "ide-tape: but the tape 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-tape: We wanted to %s, ",
+			ireason.b.io ? "Write":"Read");
+		printk(KERN_ERR "ide-tape: but the tape 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-tape: The tape wants to send us more data than expected - discarding data\n");
-				idetape_discard_data (drive, bcount.all);
-				ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
+				printk(KERN_ERR "ide-tape: The tape wants to "
+					"send us more data than expected "
+					"- discarding data\n");
+				idetape_discard_data(drive, bcount.all);
+				if (HWGROUP(drive)->handler != NULL)
+					BUG();
+				ide_set_handler(drive,
+						&idetape_pc_intr,
+						IDETAPE_WAIT_CMD,
+						NULL);
 				return ide_started;
 			}
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 2)
-				printk (KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n");
+				printk(KERN_NOTICE "ide-tape: The tape wants "
+					"to send us more data than expected "
+					"- allowing transfer\n");
 #endif /* IDETAPE_DEBUG_LOG */
 		}
 	}
-	if (test_bit (PC_WRITING, &pc->flags)) {
+	if (test_bit(PC_WRITING, &pc->flags)) {
 		if (pc->bh != NULL)
-			idetape_output_buffers (drive, pc, bcount.all);
+			idetape_output_buffers(drive, pc, bcount.all);
 		else
-			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 {
 		if (pc->bh != NULL)
-			idetape_input_buffers (drive, pc, bcount.all);
+			idetape_input_buffers(drive, pc, bcount.all);
 		else
-			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);
 	}
-	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 IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all);
+		printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes "
+			"on that interrupt\n", pc->c[0], bcount.all);
 #endif
-	ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);	/* And set the interrupt handler again */
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	/* And set the interrupt handler again */
+	ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
 	return ide_started;
 }
 
@@ -2217,9 +2269,9 @@
  *
  *	4.	When the packet command is finished, it will be checked for errors.
  *
- *	5.	In case an error was found, we queue a request sense packet command
- *		in front of the request queue and retry the operation up to
- *		IDETAPE_MAX_PC_RETRIES times.
+ *	5.	In case an error was found, we queue a request sense packet
+ *		command in front of the request queue and retry the operation
+ *		upto IDETAPE_MAX_PC_RETRIES times.
  *
  *	6.	In case no error was found, or we decided to give up and not
  *		to retry again, the callback function will be called and then
@@ -2230,52 +2282,64 @@
 {
 	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;
 
-	if (ide_wait_stat (&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
-		printk (KERN_ERR "ide-tape: 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-tape: 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);
 	while (retries-- && (!ireason.b.cod || ireason.b.io)) {
-		printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, retrying\n");
+		printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing "
+				"a packet command, retrying\n");
 		udelay(100);
-		ireason.all = IN_BYTE(IDE_IREASON_REG);
+		ireason.all = HWIF(drive)->INB(IDE_IREASON_REG);
 		if (retries == 0) {
-			printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing a packet command, ignoring\n");
+			printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while "
+					"issuing a packet command, ignoring\n");
 			ireason.b.cod = 1;
 			ireason.b.io = 0;
 		}
 	}
 	if (!ireason.b.cod || ireason.b.io) {
-		printk (KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing a packet command\n");
-		return ide_do_reset (drive);
+		printk(KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing "
+				"a packet command\n");
+		return ide_do_reset(drive);
 	}
 	tape->cmd_start_time = jiffies;
-	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 */
+	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+		BUG();
+	/* 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;
-	int dma_ok = 0;
+	atapi_feature_t feature;
+	atapi_bcount_t bcount;
 
 #if IDETAPE_DEBUG_BUGS
-	if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-		printk (KERN_ERR "ide-tape: possible ide-tape.c bug - Two request sense in serial were issued\n");
+	if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD &&
+	    pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
+		printk(KERN_ERR "ide-tape: possible ide-tape.c bug - "
+			"Two request sense in serial were issued\n");
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 
 	if (tape->failed_pc == NULL && pc->c[0] != IDETAPE_REQUEST_SENSE_CMD)
 		tape->failed_pc = pc;
-	tape->pc = pc;							/* Set the current packet command */
+	/* Set the current packet command */
+	tape->pc = pc;
 
-	if (pc->retries > IDETAPE_MAX_PC_RETRIES || test_bit (PC_ABORT, &pc->flags)) {
+	if (pc->retries > IDETAPE_MAX_PC_RETRIES ||
+	    test_bit(PC_ABORT, &pc->flags)) {
 		/*
 		 *	We will "abort" retrying a packet command in case
 		 *	a legitimate error code was received (crossing a
@@ -2283,55 +2347,79 @@
 		 *	example).
 		 */
 		if (!test_bit (PC_ABORT, &pc->flags)) {
-			if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD && tape->sense_key == 2 &&
-			      tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8))) {
-				printk (KERN_ERR "ide-tape: %s: I/O error, pc = %2x, key = %2x, asc = %2x, ascq = %2x\n",
-					tape->name, pc->c[0], tape->sense_key, tape->asc, tape->ascq);
-				if (tape->onstream && pc->c[0] == IDETAPE_READ_CMD && tape->sense_key == 3 && tape->asc == 0x11)  /* AJN-1: 11 should be 0x11 */
+			if (!(pc->c[0] == IDETAPE_TEST_UNIT_READY_CMD &&
+			      tape->sense_key == 2 && tape->asc == 4 &&
+			     (tape->ascq == 1 || tape->ascq == 8))) {
+				printk(KERN_ERR "ide-tape: %s: I/O error, "
+						"pc = %2x, key = %2x, "
+						"asc = %2x, ascq = %2x\n",
+						tape->name, pc->c[0],
+						tape->sense_key, tape->asc,
+						tape->ascq);
+				if (tape->onstream &&
+				    pc->c[0] == IDETAPE_READ_CMD &&
+				    tape->sense_key == 3 &&
+				    tape->asc == 0x11)
+					/* AJN-1: 11 should be 0x11 */
 					printk(KERN_ERR "ide-tape: %s: enabling read error recovery\n", tape->name);
 			}
-			pc->error = IDETAPE_ERROR_GENERAL;		/* Giving up */
+			/* Giving up */
+			pc->error = IDETAPE_ERROR_GENERAL;
 		}
 		tape->failed_pc = NULL;
 		return pc->callback(drive);
 	}
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: Retry number - %d\n", pc->retries);
+		printk(KERN_INFO "ide-tape: Retry number - %d\n", pc->retries);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	pc->retries++;
-	pc->actually_transferred = 0;					/* We haven't transferred any data yet */
-	pc->current_position=pc->buffer;
-	bcount.all=pc->request_transfer;				/* Request to transfer the entire buffer at once */
+	/* We haven't transferred any data yet */
+	pc->actually_transferred = 0;
+	pc->current_position = pc->buffer;
+	/* Request to transfer the entire buffer at once */
+	bcount.all = pc->request_transfer;
 
 #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_and_clear_bit(PC_DMA_ERROR, &pc->flags)) {
+		printk(KERN_WARNING "ide-tape: DMA disabled, "
+				"reverting to PIO\n");
+		(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)) {
+			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 */
 	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);
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+		ide_set_handler(drive,
+				&idetape_transfer_pc,
+				IDETAPE_WAIT_CMD,
+				NULL);
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return ide_started;
 	} else {
-		OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG);
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
 		return idetape_transfer_pc(drive);
 	}
 }
@@ -2348,22 +2436,22 @@
 		printk (KERN_INFO "ide-tape: Reached idetape_pc_callback\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
-	idetape_end_request (tape->pc->error ? 0 : 1, HWGROUP(drive));
+	idetape_end_request(drive, tape->pc->error ? 0 : 1);
 	return ide_stopped;
 }
 
 /*
  *	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;
 	if (page_code != IDETAPE_BLOCK_DESCRIPTOR)
-		pc->c[1] = 8;			/* DBD = 1 - Don't return block descriptors */
+		pc->c[1] = 8;	/* DBD = 1 - Don't return block descriptors */
 	pc->c[2] = page_code;
-	pc->c[3] = 255;				/* Don't limit the returned information */
-	pc->c[4] = 255;				/* (We will just discard data in that case) */
+	pc->c[3] = 255;		/* Don't limit the returned information */
+	pc->c[4] = 255;		/* (We will just discard data in that case) */
 	if (page_code == IDETAPE_BLOCK_DESCRIPTOR)
 		pc->request_transfer = 12;
 	else if (page_code == IDETAPE_CAPABILITIES_PAGE)
@@ -2391,13 +2479,15 @@
 	}
 	tape->tape_still_time = (jiffies - tape->tape_still_time_begin) * 1000 / HZ;
 #if USE_IOTRACE
-	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
+	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head,
+			tape->tape_head, tape->minor);
 #endif
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 1)
-		printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n", tape->cur_frames, tape->max_frames);
+		printk(KERN_INFO "ide-tape: buffer fill callback, %d/%d\n",
+			tape->cur_frames, tape->max_frames);
 #endif
-	idetape_end_request (tape->pc->error ? 0 : 1, HWGROUP(drive));
+	idetape_end_request(drive, tape->pc->error ? 0 : 1);
 	return ide_stopped;
 }
 
@@ -2429,7 +2519,8 @@
 	else if (time_after(jiffies, tape->controlled_previous_head_time))
 		tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_previous_head_time);
 
-	if (tape->nr_pending_stages < tape->max_stages /*- 1 */) { /* -1 for read mode error recovery */
+	if (tape->nr_pending_stages < tape->max_stages /*- 1 */) {
+		/* -1 for read mode error recovery */
 		if (time_after(jiffies, tape->uncontrolled_previous_head_time + 10 * HZ)) {
 			tape->uncontrolled_pipeline_head_time = jiffies;
 			tape->uncontrolled_pipeline_head_speed = (tape->pipeline_head - tape->uncontrolled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->uncontrolled_previous_head_time);
@@ -2465,15 +2556,21 @@
 {
 	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();
+		printk(KERN_INFO "ide-tape: bug: "
+			"onstream, media_access_finished\n");
+
+	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);
-			return idetape_retry_pc (drive);			/* Retry operation */
+		if (status.b.check) {
+			/* Error detected */
+			printk(KERN_ERR "ide-tape: %s: I/O error, ",
+					tape->name);
+			/* Retry operation */
+			return idetape_retry_pc(drive);
 		}
 		pc->error = 0;
 		if (tape->failed_pc == pc)
@@ -2510,16 +2607,16 @@
 
 #if IDETAPE_DEBUG_LOG	
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_rw_callback\n");
+		printk(KERN_INFO "ide-tape: Reached idetape_rw_callback\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
 	tape->first_frame_position += blocks;
 	rq->current_nr_sectors -= blocks;
 
 	if (!tape->pc->error)
-		idetape_end_request (1, HWGROUP (drive));
+		idetape_end_request(drive, 1);
 	else
-		idetape_end_request (tape->pc->error, HWGROUP (drive));
+		idetape_end_request(drive, tape->pc->error);
 	return ide_stopped;
 }
 
@@ -2528,7 +2625,7 @@
 	struct buffer_head *p = bh;
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_READ_CMD;
-	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
+	put_unaligned(htonl (length), (unsigned int *) &pc->c[1]);
 	pc->c[1] = 1;
 	pc->callback = &idetape_rw_callback;
 	pc->bh = bh;
@@ -2543,11 +2640,11 @@
 	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;
-			set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 		} else
 			pc->request_transfer = 0;
 	}
@@ -2558,7 +2655,7 @@
 	int size = 32768;
 
 	struct buffer_head *p = bh;
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_READ_BUFFER_CMD;
 	pc->c[1] = IDETAPE_RETRIEVE_FAULTY_BLOCK;
 	pc->c[7] = size >> 8;
@@ -2577,9 +2674,9 @@
 static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
 {
 	struct buffer_head *p = bh;
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_WRITE_CMD;
-	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
+	put_unaligned(htonl (length), (unsigned int *) &pc->c[1]);
 	pc->c[1] = 1;
 	pc->callback = &idetape_rw_callback;
 	set_bit (PC_WRITING, &pc->flags);
@@ -2596,17 +2693,49 @@
 	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;
-			set_bit (PC_DMA_RECOMMENDED, &pc->flags);
+			set_bit(PC_DMA_RECOMMENDED, &pc->flags);
 		} else
 			pc->request_transfer = 0;
 	}
 }
 
 /*
+ * 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(&io_request_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->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		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(&io_request_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)
@@ -2614,35 +2743,42 @@
 	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 (tape->debug_level >= 5)
-		printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
+		printk(KERN_INFO "ide-tape: rq_status: %d, "
+			"rq_dev: %u, cmd: %d, errors: %d\n", rq->rq_status,
+			(unsigned int) rq->rq_dev, rq->cmd, rq->errors);
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+		printk(KERN_INFO "ide-tape: sector: %ld, "
+			"nr_sectors: %ld, current_nr_sectors: %ld\n",
+			rq->sector, rq->nr_sectors, rq->current_nr_sectors);
 #endif /* IDETAPE_DEBUG_LOG */
 
-	if (!IDETAPE_RQ_CMD (rq->cmd)) {
+	if (!IDETAPE_RQ_CMD(rq->cmd)) {
 		/*
 		 *	We do not support buffer cache originated requests.
 		 */
-		printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%d)\n", drive->name, rq->cmd);
-		ide_end_request (0, HWGROUP (drive));			/* Let the common code handle it */
+		printk(KERN_NOTICE "ide-tape: %s: Unsupported command in "
+			"request queue (%d)\n", drive->name, rq->cmd);
+		idetape_do_end_request(drive, 0);
 		return ide_stopped;
 	}
 
 	/*
 	 *	Retry a failed packet command
 	 */
-	if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
-		return idetape_issue_packet_command (drive, tape->failed_pc);
+	if (tape->failed_pc != NULL &&
+	    tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
+		return idetape_issue_packet_command(drive, tape->failed_pc);
 	}
 #if IDETAPE_DEBUG_BUGS
 	if (postponed_rq != NULL)
 		if (rq != postponed_rq) {
-			printk (KERN_ERR "ide-tape: ide-tape.c bug - Two DSC requests were queued\n");
-			idetape_end_request (0, HWGROUP (drive));
+			printk(KERN_ERR "ide-tape: ide-tape.c bug - "
+					"Two DSC requests were queued\n");
+			idetape_end_request(drive, 0);
 			return ide_stopped;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -2653,7 +2789,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
@@ -2662,7 +2798,7 @@
 	if (tape->onstream)
 		status.b.dsc = 1;
 	if (!drive->dsc_overlap && rq->cmd != IDETAPE_PC_RQ2)
-		set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
+		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
 
 	/*
 	 * For the OnStream tape, check the current status of the tape
@@ -2674,7 +2810,8 @@
 	 */
 	if (tape->tape_still_time > 100 && tape->tape_still_time < 200)
 		tape->measure_insert_time = 1;
-	if (tape->req_buffer_fill && (rq->cmd == IDETAPE_WRITE_RQ || rq->cmd == IDETAPE_READ_RQ)) {
+	if (tape->req_buffer_fill &&
+	    (rq->cmd == IDETAPE_WRITE_RQ || rq->cmd == IDETAPE_READ_RQ)) {
 		tape->req_buffer_fill = 0;
 		tape->writes_since_buffer_fill = 0;
 		tape->reads_since_buffer_fill = 0;
@@ -2699,7 +2836,8 @@
 			tape->insert_speed > tape->max_insert_speed ) ) && rq->nr_sectors) ) ) {
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 4)
-			printk(KERN_INFO "ide-tape: postponing request, cmd %d, cur %d, max %d\n",
+			printk(KERN_INFO "ide-tape: postponing request, "
+					"cmd %d, cur %d, max %d\n",
 				rq->cmd, tape->cur_frames, tape->max_frames);
 #endif
 		if (tape->postpone_cnt++ < 500) {
@@ -2708,25 +2846,28 @@
 		}
 #if ONSTREAM_DEBUG
 		else if (tape->debug_level >= 4) 
-			printk(KERN_INFO "ide-tape: %s: postpone_cnt %d\n", tape->name, tape->postpone_cnt);
+			printk(KERN_INFO "ide-tape: %s: postpone_cnt %d\n",
+				tape->name, tape->postpone_cnt);
 #endif
 	}
-	if (!test_and_clear_bit (IDETAPE_IGNORE_DSC, &tape->flags) && !status.b.dsc) {
+	if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) &&
+	    !status.b.dsc) {
 		if (postponed_rq == NULL) {
 			tape->dsc_polling_start = jiffies;
 			tape->dsc_polling_frequency = tape->best_dsc_rw_frequency;
 			tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
 		} else if ((signed long) (jiffies - tape->dsc_timeout) > 0) {
-			printk (KERN_ERR "ide-tape: %s: DSC timeout\n", tape->name);
+			printk(KERN_ERR "ide-tape: %s: DSC timeout\n",
+				tape->name);
 			if (rq->cmd == IDETAPE_PC_RQ2) {
-				idetape_media_access_finished (drive);
+				idetape_media_access_finished(drive);
 				return ide_stopped;
 			} else {
-				return ide_do_reset (drive);
+				return ide_do_reset(drive);
 			}
 		} else if (jiffies - tape->dsc_polling_start > IDETAPE_DSC_MA_THRESHOLD)
 			tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW;
-		idetape_postpone_request (drive);
+		idetape_postpone_request(drive);
 		return ide_stopped;
 	}
 	switch (rq->cmd) {
@@ -2743,8 +2884,8 @@
 				if (time_after(jiffies, tape->last_buffer_fill + 5 * HZ / 100))
 					tape->req_buffer_fill = 1;
 			}
-			pc = idetape_next_pc_storage (drive);
-			idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			pc = idetape_next_pc_storage(drive);
+			idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, rq->bh);
 			break;
 		case IDETAPE_WRITE_RQ:
 			tape->buffer_head++;
@@ -2760,39 +2901,41 @@
 					tape->req_buffer_fill = 1;
 				calculate_speeds(drive);
 			}
-			pc = idetape_next_pc_storage (drive);
-			idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			pc = idetape_next_pc_storage(drive);
+			idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, rq->bh);
 			break;
 		case IDETAPE_READ_BUFFER_RQ:
 			tape->postpone_cnt = 0;
-			pc = idetape_next_pc_storage (drive);
-			idetape_create_read_buffer_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			pc = idetape_next_pc_storage(drive);
+			idetape_create_read_buffer_cmd(tape, pc, rq->current_nr_sectors, rq->bh);
 			break;
 		case IDETAPE_ABORTED_WRITE_RQ:
 			rq->cmd = IDETAPE_WRITE_RQ;
-			idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
+			idetape_end_request(drive, IDETAPE_ERROR_EOD);
 			return ide_stopped;
 		case IDETAPE_ABORTED_READ_RQ:
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 2)
-				printk(KERN_INFO "ide-tape: %s: detected aborted read rq\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: detected "
+					"aborted read rq\n", tape->name);
 #endif
 			rq->cmd = IDETAPE_READ_RQ;
-			idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
+			idetape_end_request(drive, IDETAPE_ERROR_EOD);
 			return ide_stopped;
 		case IDETAPE_PC_RQ1:
 			pc = (idetape_pc_t *) rq->buffer;
 			rq->cmd = IDETAPE_PC_RQ2;
 			break;
 		case IDETAPE_PC_RQ2:
-			idetape_media_access_finished (drive);
+			idetape_media_access_finished(drive);
 			return ide_stopped;
 		default:
-			printk (KERN_ERR "ide-tape: bug in IDETAPE_RQ_CMD macro\n");
-			idetape_end_request (0, HWGROUP (drive));
+			printk(KERN_ERR "ide-tape: bug in "
+				"IDETAPE_RQ_CMD macro\n");
+			idetape_end_request(drive, 0);
 			return ide_stopped;
 	}
-	return idetape_issue_packet_command (drive, pc);
+	return idetape_issue_packet_command(drive, pc);
 }
 
 /*
@@ -2826,11 +2969,11 @@
 	int pages = tape->pages_per_stage;
 	char *b_data;
 
-	if ((stage = (idetape_stage_t *) kmalloc (sizeof (idetape_stage_t),GFP_KERNEL)) == NULL)
+	if ((stage = (idetape_stage_t *) kmalloc(sizeof(idetape_stage_t),GFP_KERNEL)) == NULL)
 		return NULL;
 	stage->next = NULL;
 
-	bh = stage->bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL);
+	bh = stage->bh = (struct buffer_head *) kmalloc(sizeof(struct buffer_head), GFP_KERNEL);
 	if (bh == NULL)
 		goto abort;
 	bh->b_reqnext = NULL;
@@ -2840,7 +2983,7 @@
 		memset(bh->b_data, 0, PAGE_SIZE);
 	bh->b_size = PAGE_SIZE;
 	atomic_set(&bh->b_count, full ? bh->b_size : 0);
-	set_bit (BH_Lock, &bh->b_state);
+	set_bit(BH_Lock, &bh->b_state);
 
 	while (--pages) {
 		if ((b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
@@ -2861,15 +3004,15 @@
 			continue;
 		}
 		prev_bh = bh;
-		if ((bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL)) == NULL) {
-			free_page ((unsigned long) b_data);
+		if ((bh = (struct buffer_head *) kmalloc(sizeof(struct buffer_head), GFP_KERNEL)) == NULL) {
+			free_page((unsigned long) b_data);
 			goto abort;
 		}
 		bh->b_reqnext = NULL;
 		bh->b_data = b_data;
 		bh->b_size = PAGE_SIZE;
 		atomic_set(&bh->b_count, full ? bh->b_size : 0);
-		set_bit (BH_Lock, &bh->b_state);
+		set_bit(BH_Lock, &bh->b_state);
 		prev_bh->b_reqnext = bh;
 	}
 	bh->b_size -= tape->excess_bh_size;
@@ -2879,7 +3022,7 @@
 		stage->aux = (os_aux_t *) (bh->b_data + bh->b_size - OS_AUX_SIZE);
 	return stage;
 abort:
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 	return NULL;
 }
 
@@ -2889,7 +3032,7 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_kmalloc_stage\n");
+		printk (KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (tape->nr_stages >= tape->max_stages)
@@ -2898,7 +3041,7 @@
 		tape->cache_stage = NULL;
 		return cache_stage;
 	}
-	return __idetape_kmalloc_stage (tape, 0, 0);
+	return __idetape_kmalloc_stage(tape, 0, 0);
 }
 
 static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char *buf, int n)
@@ -2909,12 +3052,13 @@
 	while (n) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_from_user\n");
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), n);
-		copy_from_user (bh->b_data + atomic_read(&bh->b_count), buf, count);
+		count = IDE_MIN(bh->b_size - atomic_read(&bh->b_count), n);
+		copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count);
 		n -= count;
 		atomic_add(count, &bh->b_count);
 		buf += count;
@@ -2935,12 +3079,13 @@
 	while (n) {
 #if IDETAPE_DEBUG_BUGS
 		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_to_user\n");
+			printk(KERN_ERR "ide-tape: bh == NULL in %s\n",
+				__FUNCTION__);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (tape->b_count, n);
-		copy_to_user (buf, tape->b_data, count);
+		count = IDE_MIN(tape->b_count, n);
+		copy_to_user(buf, tape->b_data, count);
 		n -= count;
 		tape->b_data += count;
 		tape->b_count -= count;
@@ -2960,9 +3105,9 @@
 	struct buffer_head *bh = tape->merge_stage->bh;
 	
 	tape->bh = bh;
-	if (tape->chrdev_direction == idetape_direction_write)
+	if (tape->chrdev_direction == idetape_direction_write) {
 		atomic_set(&bh->b_count, 0);
-	else {
+	} else {
 		tape->b_data = bh->b_data;
 		tape->b_count = atomic_read(&bh->b_count);
 	}
@@ -2973,9 +3118,12 @@
 	struct buffer_head *tmp;
 	os_aux_t *tmp_aux;
 
-	tmp = stage->bh; tmp_aux = stage->aux;
-	stage->bh = tape->merge_stage->bh; stage->aux = tape->merge_stage->aux;
-	tape->merge_stage->bh = tmp; tape->merge_stage->aux = tmp_aux;
+	tmp = stage->bh;
+	tmp_aux = stage->aux;
+	stage->bh = tape->merge_stage->bh;
+	stage->aux = tape->merge_stage->aux;
+	tape->merge_stage->bh = tmp;
+	tape->merge_stage->aux = tmp_aux;
 	idetape_init_merge_stage (tape);
 }
 
@@ -2989,10 +3137,10 @@
 	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_add_stage_tail\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 	spin_lock_irqsave(&tape->spinlock, flags);
-	stage->next=NULL;
+	stage->next = NULL;
 	if (tape->last_stage != NULL)
 		tape->last_stage->next=stage;
 	else
@@ -3058,10 +3206,13 @@
 		else
 			dat->dat_list[0].flags = OS_DAT_FLAGS_DATA;
 		dat->dat_list[0].reserved = 0;
-	} 
-	aux->filemark_cnt = ntohl(tape->filemark_cnt);		/* shouldn't this be htonl ?? */
-	aux->phys_fm = ntohl(0xffffffff);			/* shouldn't this be htonl ?? */
-	aux->last_mark_addr = ntohl(tape->last_mark_addr);	/* shouldn't this be htonl ?? */
+	}
+	/* shouldn't this be htonl ?? */
+	aux->filemark_cnt = ntohl(tape->filemark_cnt);
+	/* shouldn't this be htonl ?? */
+	aux->phys_fm = ntohl(0xffffffff);
+	/* shouldn't this be htonl ?? */
+	aux->last_mark_addr = ntohl(tape->last_mark_addr);
 }
 
 /*
@@ -3078,7 +3229,8 @@
 
 #if IDETAPE_DEBUG_BUGS
 	if (rq == NULL || !IDETAPE_RQ_CMD (rq->cmd)) {
-		printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n");
+		printk(KERN_ERR "ide-tape: bug: Trying to sleep on "
+			"non-valid request\n");
 		return;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -3098,35 +3250,39 @@
 	
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_read_position_callback\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (!tape->pc->error) {
 		result = (idetape_read_position_result_t *) tape->pc->buffer;
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 2)
-			printk (KERN_INFO "ide-tape: BOP - %s\n",result->bop ? "Yes":"No");
+			printk(KERN_INFO "ide-tape: BOP - %s\n",
+				result->bop ? "Yes":"No");
 		if (tape->debug_level >= 2)
-			printk (KERN_INFO "ide-tape: EOP - %s\n",result->eop ? "Yes":"No");
+			printk(KERN_INFO "ide-tape: EOP - %s\n",
+				result->eop ? "Yes":"No");
 #endif /* IDETAPE_DEBUG_LOG */
 		if (result->bpu) {
-			printk (KERN_INFO "ide-tape: Block location is unknown to the tape\n");
-			clear_bit (IDETAPE_ADDRESS_VALID, &tape->flags);
-			idetape_end_request (0, HWGROUP (drive));
+			printk(KERN_INFO "ide-tape: Block location is "
+				"unknown to the tape\n");
+			clear_bit(IDETAPE_ADDRESS_VALID, &tape->flags);
+			idetape_end_request(drive, 0);
 		} else {
 #if IDETAPE_DEBUG_LOG
 			if (tape->debug_level >= 2)
-				printk (KERN_INFO "ide-tape: Block Location - %u\n", ntohl (result->first_block));
+				printk(KERN_INFO "ide-tape: Block Location "
+					"- %u\n", ntohl(result->first_block));
 #endif /* IDETAPE_DEBUG_LOG */
 			tape->partition = result->partition;
-			tape->first_frame_position = ntohl (result->first_block);
-			tape->last_frame_position = ntohl (result->last_block);
+			tape->first_frame_position = ntohl(result->first_block);
+			tape->last_frame_position = ntohl(result->last_block);
 			tape->blocks_in_buffer = result->blocks_in_buffer[2];
-			set_bit (IDETAPE_ADDRESS_VALID, &tape->flags);
-			idetape_end_request (1, HWGROUP (drive));
+			set_bit(IDETAPE_ADDRESS_VALID, &tape->flags);
+			idetape_end_request(drive, 1);
 		}
 	} else {
-		idetape_end_request (0, HWGROUP (drive));
+		idetape_end_request(drive, 0);
 	}
 	return ide_stopped;
 }
@@ -3143,12 +3299,12 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_WRITE_FILEMARK_CMD;
 	if (tape->onstream)
 		pc->c[1] = 1; /* Immed bit */
 	pc->c[4] = write_filemark;  /* not used for OnStream ?? */
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
@@ -3165,8 +3321,8 @@
  *	ide_do_drive_cmd from ide.c
  *	cdrom_queue_request and cdrom_queue_packet_command from ide-cd.c
  *
- *	We add a special packet command request to the tail of the request queue,
- *	and wait for it to be serviced.
+ *	We add a special packet command request to the tail of the request
+ *	queue, and wait for it to be serviced.
  *
  *	This is not to be called from within the request handling part
  *	of the driver ! We allocate here data in the stack, and it is valid
@@ -3183,17 +3339,17 @@
 {
 	struct request rq;
 
-	ide_init_drive_cmd (&rq);
+	ide_init_drive_cmd(&rq);
 	rq.buffer = (char *) pc;
 	rq.cmd = IDETAPE_PC_RQ1;
-	return ide_do_drive_cmd (drive, &rq, ide_wait);
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
 static void idetape_create_load_unload_cmd (ide_drive_t *drive, idetape_pc_t *pc,int cmd)
 {
 	idetape_tape_t *tape = drive->driver_data;
 
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_LOAD_UNLOAD_CMD;
 	pc->c[4] = cmd;
 	if (tape->onstream) {
@@ -3201,7 +3357,7 @@
 		if (cmd == !IDETAPE_LU_LOAD_MASK)
 			pc->c[4] = 4;
 	}
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
@@ -3219,13 +3375,14 @@
 		if (!__idetape_queue_pc_tail(drive, &pc))
 			return 0;
 		if (tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2) {
-			idetape_create_load_unload_cmd (drive, &pc, IDETAPE_LU_LOAD_MASK);
+			idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK);
 			__idetape_queue_pc_tail(drive, &pc);
 			idetape_create_test_unit_ready_cmd(&pc);
 			if (!__idetape_queue_pc_tail(drive, &pc))
 				return 0;
 		}
-		if (!(tape->sense_key == 2 && tape->asc == 4 && (tape->ascq == 1 || tape->ascq == 8)))
+		if (!(tape->sense_key == 2 && tape->asc == 4 &&
+		    (tape->ascq == 1 || tape->ascq == 8)))
 			break;
 		current->state = TASK_INTERRUPTIBLE;
   		schedule_timeout(HZ / 10);
@@ -3241,9 +3398,13 @@
 	rc = __idetape_queue_pc_tail(drive, pc);
 	if (rc)
 		return rc;
-	if (tape->onstream && test_bit(PC_WAIT_FOR_DSC, &pc->flags))
-		rc = idetape_wait_ready(drive, 60 * 10 * HZ);   /* AJN-4: Changed from 5 to 10 minutes;
-                          because retension takes approx. 8:20 with Onstream 30GB tape */
+	if (tape->onstream && test_bit(PC_WAIT_FOR_DSC, &pc->flags)) {
+		/* AJN-4: Changed from 5 to 10 minutes;
+		 * because retension takes approx.
+		 * 8:20 with Onstream 30GB tape
+		 */
+		rc = idetape_wait_ready(drive, 60 * 10 * HZ);
+	}
 	return rc;
 }
 
@@ -3261,7 +3422,7 @@
 
 static void idetape_create_read_position_cmd (idetape_pc_t *pc)
 {
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_READ_POSITION_CMD;
 	pc->request_transfer = 20;
 	pc->callback = &idetape_read_position_callback;
@@ -3275,14 +3436,14 @@
 
 #if IDETAPE_DEBUG_LOG
         if (tape->debug_level >= 4)
-	printk (KERN_INFO "ide-tape: Reached idetape_read_position\n");
+		printk (KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
 #ifdef NO_LONGER_REQUIRED
 	idetape_flush_tape_buffers(drive);
 #endif
 	idetape_create_read_position_cmd(&pc);
-	if (idetape_queue_pc_tail (drive, &pc))
+	if (idetape_queue_pc_tail(drive, &pc))
 		return -1;
 	position = tape->first_frame_position;
 #ifdef NO_LONGER_REQUIRED
@@ -3290,7 +3451,11 @@
 		if ((position != tape->last_frame_position - tape->blocks_in_buffer) &&
 		    (position != tape->last_frame_position + tape->blocks_in_buffer)) {
 			if (tape->blocks_in_buffer == 0) {
-				printk("ide-tape: %s: correcting read position %d, %d, %d\n", tape->name, position, tape->last_frame_position, tape->blocks_in_buffer);
+				printk("ide-tape: %s: correcting read "
+					"position %d, %d, %d\n",
+					tape->name, position,
+					tape->last_frame_position,
+					tape->blocks_in_buffer);
 				position = tape->last_frame_position;
 				tape->first_frame_position = position;
 			}
@@ -3300,17 +3465,17 @@
 	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;
 
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_LOCATE_CMD;
 	if (tape->onstream)
 		pc->c[1] = 1; /* Immediate bit */
 	else
 		pc->c[1] = 2;
-	put_unaligned (htonl (block), (unsigned int *) &pc->c[3]);
+	put_unaligned(htonl(block), (unsigned int *) &pc->c[3]);
 	pc->c[8] = partition;
 	if (tape->onstream)
                 /*
@@ -3319,7 +3484,7 @@
                  * data in the drive to this new position!
                  */
 		pc->c[9] = skip << 7;
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
@@ -3347,7 +3512,7 @@
 		return 0;
 	tape->merge_stage_size = 0;
 	if (tape->merge_stage != NULL) {
-		__idetape_kfree_stage (tape->merge_stage);
+		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
 	tape->chrdev_direction = idetape_direction_none;
@@ -3357,13 +3522,13 @@
 
 	spin_lock_irqsave(&tape->spinlock, flags);
 	tape->next_stage = NULL;
-	if (idetape_pipeline_active (tape))
+	if (idetape_pipeline_active(tape))
 		idetape_wait_for_request(drive, tape->active_data_request);
 	spin_unlock_irqrestore(&tape->spinlock, flags);
 
 	cnt = tape->nr_stages - tape->nr_pending_stages;
 	while (tape->first_stage != NULL)
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 	tape->nr_pending_stages = 0;
 	tape->max_stages = tape->min_pipeline;
 	return cnt;
@@ -3378,7 +3543,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;
@@ -3387,13 +3552,13 @@
 	if (tape->chrdev_direction == idetape_direction_read)
 		__idetape_discard_read_pipeline(drive);
 	idetape_wait_ready(drive, 60 * 5 * HZ);
-	idetape_create_locate_cmd (drive, &pc, block, partition, skip);
-	retval = idetape_queue_pc_tail (drive, &pc);
+	idetape_create_locate_cmd(drive, &pc, block, partition, skip);
+	retval = idetape_queue_pc_tail(drive, &pc);
 	if (retval)
 		return (retval);
 
-	idetape_create_read_position_cmd (&pc);
-	return (idetape_queue_pc_tail (drive, &pc));
+	idetape_create_read_position_cmd(&pc);
+	return (idetape_queue_pc_tail(drive, &pc));
 }
 
 static void idetape_discard_read_pipeline (ide_drive_t *drive, int restore_position)
@@ -3407,11 +3572,13 @@
 		position = idetape_read_position(drive);
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: address %u, nr_stages %d\n", position, cnt);
+			printk(KERN_INFO "ide-tape: address %u, nr_stages %d\n",
+				position, cnt);
 #endif
 		seek = position > cnt ? position - cnt : 0;
 		if (idetape_position_tape(drive, seek, 0, 0)) {
-			printk(KERN_INFO "ide-tape: %s: position_tape failed in discard_pipeline()\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: position_tape "
+				"failed in discard_pipeline()\n", tape->name);
 			return;
 		}
 	}
@@ -3421,7 +3588,7 @@
 {
 	idetape_pc_t pc;
 
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_BUFFER_FILLING_PAGE);
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_BUFFER_FILLING_PAGE);
 	pc.callback = idetape_onstream_buffer_fill_callback;
 	(void) idetape_queue_pc_tail(drive, &pc);
 }
@@ -3437,29 +3604,30 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: idetape_queue_rw_tail: cmd=%d\n",cmd);
+		printk(KERN_INFO "ide-tape: %s: cmd=%d\n", __FUNCTION__, cmd);
 #endif /* IDETAPE_DEBUG_LOG */
 #if IDETAPE_DEBUG_BUGS
 	if (idetape_pipeline_active (tape)) {
-		printk (KERN_ERR "ide-tape: bug: the pipeline is active in idetape_queue_rw_tail\n");
+		printk(KERN_ERR "ide-tape: bug: the pipeline is active in %s\n",
+			__FUNCTION__);
 		return (0);
 	}
 #endif /* IDETAPE_DEBUG_BUGS */	
 
-	ide_init_drive_cmd (&rq);
+	ide_init_drive_cmd(&rq);
 	rq.bh = bh;
 	rq.cmd = cmd;
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
 	if (tape->onstream)
 		tape->postpone_cnt = 600;
-	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
+	(void) ide_do_drive_cmd(drive, &rq, ide_wait);
 
 	if (cmd != IDETAPE_READ_RQ && cmd != IDETAPE_WRITE_RQ)
 		return 0;
 
 	if (tape->merge_stage)
-		idetape_init_merge_stage (tape);
+		idetape_init_merge_stage(tape);
 	if (rq.errors == IDETAPE_ERROR_GENERAL)
 		return -EIO;
 	return (tape->tape_block_size * (blocks-rq.current_nr_sectors));
@@ -3517,7 +3685,8 @@
 	idetape_update_stats(drive);
 #if ONSTREAM_DEBUG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: %s: frames left in buffer: %d\n", tape->name, tape->cur_frames);
+		printk(KERN_INFO "ide-tape: %s: frames left in buffer: %d\n",
+			tape->name, tape->cur_frames);
 #endif
 }
 
@@ -3578,12 +3747,12 @@
 
 	if (tape->next_stage == NULL)
 		return;
-	if (!idetape_pipeline_active (tape)) {
+	if (!idetape_pipeline_active(tape)) {
 		if (tape->onstream_write_error)
 			idetape_onstream_write_error_recovery(drive);
 		set_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags);
-		idetape_active_next_stage (drive);
-		(void) ide_do_drive_cmd (drive, tape->active_data_request, ide_end);
+		idetape_active_next_stage(drive);
+		(void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end);
 	}
 }
 
@@ -3599,41 +3768,41 @@
 {
 	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;
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
 static void idetape_create_mode_select_cmd (idetape_pc_t *pc, int length)
 {
-	idetape_init_pc (pc);
-	set_bit (PC_WRITING, &pc->flags);
+	idetape_init_pc(pc);
+	set_bit(PC_WRITING, &pc->flags);
 	pc->c[0] = IDETAPE_MODE_SELECT_CMD;
 	pc->c[1] = 0x10;
-	put_unaligned (htons(length), (unsigned short *) &pc->c[3]);
+	put_unaligned(htons(length), (unsigned short *) &pc->c[3]);
 	pc->request_transfer = 255;
 	pc->callback = &idetape_pc_callback;
 }
 
 static void idetape_create_erase_cmd (idetape_pc_t *pc)
 {
-	idetape_init_pc (pc);
+	idetape_init_pc(pc);
 	pc->c[0] = IDETAPE_ERASE_CMD;
 	pc->c[1] = 1;
-	set_bit (PC_WAIT_FOR_DSC, &pc->flags);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	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);
+	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);
+	set_bit(PC_WAIT_FOR_DSC, &pc->flags);
 	pc->callback = &idetape_pc_callback;
 }
 
@@ -3662,48 +3831,70 @@
 		return 1;
 	}
 	if (rq->errors == IDETAPE_ERROR_GENERAL) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, read error\n", tape->name, tape->first_frame_position);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"read error\n", tape->name, tape->first_frame_position);
 		return 0;
 	}
 	if (rq->errors == IDETAPE_ERROR_EOD) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, eod\n", tape->name, tape->first_frame_position);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, eod\n",
+			tape->name, tape->first_frame_position);
 		return 0;
 	}
 	if (ntohl(aux->format_id) != 0) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, format_id %u\n", tape->name, tape->first_frame_position, ntohl(aux->format_id));
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"format_id %u\n", tape->name,
+			tape->first_frame_position, ntohl(aux->format_id));
 		return 0;
 	}
 	if (memcmp(aux->application_sig, tape->application_sig, 4) != 0) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, incorrect application signature\n", tape->name, tape->first_frame_position);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"incorrect application signature\n",
+			tape->name, tape->first_frame_position);
 		return 0;
 	}
 	if (aux->frame_type != OS_FRAME_TYPE_DATA &&
 	    aux->frame_type != OS_FRAME_TYPE_EOD &&
 	    aux->frame_type != OS_FRAME_TYPE_MARKER) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, frame type %x\n", tape->name, tape->first_frame_position, aux->frame_type);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, frame "
+			"type %x\n", tape->name,
+			tape->first_frame_position, aux->frame_type);
 		return 0;
 	}
 	if (par->partition_num != OS_DATA_PARTITION) {
 		if (!tape->linux_media || tape->linux_media_version != 2) {
-			printk(KERN_INFO "ide-tape: %s: skipping frame %d, partition num %d\n", tape->name, tape->first_frame_position, par->partition_num);
+			printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+				"partition num %d\n", tape->name,
+				tape->first_frame_position, par->partition_num);
 			return 0;
 		}
 	}
 	if (par->par_desc_ver != OS_PARTITION_VERSION) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, partition version %d\n", tape->name, tape->first_frame_position, par->par_desc_ver);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"partition version %d\n", tape->name,
+			tape->first_frame_position, par->par_desc_ver);
 		return 0;
 	}
 	if (ntohs(par->wrt_pass_cntr) != tape->wrt_pass_cntr) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, wrt_pass_cntr %d (expected %d)(logical_blk_num %u)\n", tape->name, tape->first_frame_position, ntohs(par->wrt_pass_cntr), tape->wrt_pass_cntr, ntohl(aux->logical_blk_num));
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"wrt_pass_cntr %d (expected %d)(logical_blk_num %u)\n",
+			tape->name, tape->first_frame_position,
+			ntohs(par->wrt_pass_cntr), tape->wrt_pass_cntr,
+			ntohl(aux->logical_blk_num));
 		return 0;
 	}
 	if (aux->frame_seq_num != aux->logical_blk_num) {
-		printk(KERN_INFO "ide-tape: %s: skipping frame %d, seq != logical\n", tape->name, tape->first_frame_position);
+		printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+			"seq != logical\n", tape->name,
+			tape->first_frame_position);
 		return 0;
 	}
-	if (logical_blk_num != -1 && ntohl(aux->logical_blk_num) != logical_blk_num) {
+	if (logical_blk_num != -1 &&
+	     ntohl(aux->logical_blk_num) != logical_blk_num) {
 		if (!quiet)
-			printk(KERN_INFO "ide-tape: %s: skipping frame %d, logical_blk_num %u (expected %d)\n", tape->name, tape->first_frame_position, ntohl(aux->logical_blk_num), logical_blk_num);
+			printk(KERN_INFO "ide-tape: %s: skipping frame %d, "
+				"logical_blk_num %u (expected %d)\n",
+				tape->name, tape->first_frame_position,
+				ntohl(aux->logical_blk_num), logical_blk_num);
 		return 0;
 	}
 	if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
@@ -3746,7 +3937,7 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_add_chrdev_write_request\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 
      	/*
@@ -3755,31 +3946,32 @@
 	 */
 	while ((new_stage = idetape_kmalloc_stage (tape)) == NULL) {
 		spin_lock_irqsave(&tape->spinlock, flags);
-		if (idetape_pipeline_active (tape)) {
+		if (idetape_pipeline_active(tape)) {
 			idetape_wait_for_request(drive, tape->active_data_request);
 			spin_unlock_irqrestore(&tape->spinlock, flags);
 		} else {
 			spin_unlock_irqrestore(&tape->spinlock, flags);
-			idetape_insert_pipeline_into_queue (drive);
-			if (idetape_pipeline_active (tape))
+			idetape_insert_pipeline_into_queue(drive);
+			if (idetape_pipeline_active(tape))
 				continue;
 			/*
 			 *	Linux is short on memory. Fallback to
 			 *	non-pipelined operation mode for this request.
 			 */
-			return idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
+			return idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
 		}
 	}
 	rq = &new_stage->rq;
-	ide_init_drive_cmd (rq);
+	ide_init_drive_cmd(rq);
 	rq->cmd = IDETAPE_WRITE_RQ;
-	rq->sector = tape->first_frame_position;	/* Doesn't actually matter - We always assume sequential access */
+	/* Doesn't actually matter - We always assume sequential access */
+	rq->sector = tape->first_frame_position;
 	rq->nr_sectors = rq->current_nr_sectors = blocks;
 
 	idetape_switch_buffers (tape, new_stage);
 	idetape_init_stage(drive, new_stage, OS_FRAME_TYPE_DATA, tape->logical_blk_num);
 	tape->logical_blk_num++;
-	idetape_add_stage_tail (drive, new_stage);
+	idetape_add_stage_tail(drive, new_stage);
 	tape->pipeline_head++;
 #if USE_IOTRACE
 	IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
@@ -3813,10 +4005,11 @@
 		} else if (tape->onstream) {
 			idetape_update_stats(drive);
 			if (tape->cur_frames > 5)
-				idetape_insert_pipeline_into_queue (drive);
+				idetape_insert_pipeline_into_queue(drive);
 		}
 	}
-	if (test_and_clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags))		/* Return a deferred error */
+	if (test_and_clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
+		/* Return a deferred error */
 		return -EIO;
 	return blocks;
 }
@@ -3831,7 +4024,7 @@
 	unsigned long flags;
 
 	while (tape->next_stage || idetape_pipeline_active(tape)) {
-		idetape_insert_pipeline_into_queue (drive);
+		idetape_insert_pipeline_into_queue(drive);
 		spin_lock_irqsave(&tape->spinlock, flags);
 		if (idetape_pipeline_active(tape))
 			idetape_wait_for_request(drive, tape->active_data_request);
@@ -3847,11 +4040,12 @@
 	
 #if IDETAPE_DEBUG_BUGS
 	if (tape->chrdev_direction != idetape_direction_write) {
-		printk (KERN_ERR "ide-tape: bug: Trying to empty write pipeline, but we are not writing.\n");
+		printk(KERN_ERR "ide-tape: bug: Trying to empty write "
+			"pipeline, but we are not writing.\n");
 		return;
 	}
 	if (tape->merge_stage_size > tape->stage_size) {
-		printk (KERN_ERR "ide-tape: bug: merge_buffer too big\n");
+		printk(KERN_ERR "ide-tape: bug: merge_buffer too big\n");
 		tape->merge_stage_size = tape->stage_size;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -3878,15 +4072,15 @@
 				bh = bh->b_reqnext;
 			}
 		}
-		(void) idetape_add_chrdev_write_request (drive, blocks);
+		(void) idetape_add_chrdev_write_request(drive, blocks);
 		tape->merge_stage_size = 0;
 	}
-	idetape_wait_for_pipeline (drive);
+	idetape_wait_for_pipeline(drive);
 	if (tape->merge_stage != NULL) {
-		__idetape_kfree_stage (tape->merge_stage);
+		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
-	clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+	clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 	tape->chrdev_direction = idetape_direction_none;
 
 	/*
@@ -3897,10 +4091,14 @@
 	 */
 	tape->max_stages = tape->min_pipeline;
 #if IDETAPE_DEBUG_BUGS
-	if (tape->first_stage != NULL || tape->next_stage != NULL || tape->last_stage != NULL || tape->nr_stages != 0) {
-		printk (KERN_ERR "ide-tape: ide-tape pipeline bug, "
-		"first_stage %p, next_stage %p, last_stage %p, nr_stages %d\n",
-		tape->first_stage, tape->next_stage, tape->last_stage, tape->nr_stages);
+	if (tape->first_stage != NULL ||
+	    tape->next_stage != NULL ||
+	    tape->last_stage != NULL ||
+	    tape->nr_stages != 0) {
+		printk(KERN_ERR "ide-tape: ide-tape pipeline bug, "
+			"first_stage %p, next_stage %p, last_stage %p, "
+			"nr_stages %d\n", tape->first_stage,
+			tape->next_stage, tape->last_stage, tape->nr_stages);
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 }
@@ -3928,14 +4126,16 @@
 	int bytes_read;
 	int blocks = tape->capabilities.ctl;
 
-	if (tape->chrdev_direction != idetape_direction_read) {		/* Initialize read operation */
+	/* Initialize read operation */
+	if (tape->chrdev_direction != idetape_direction_read) {
 		if (tape->chrdev_direction == idetape_direction_write) {
-			idetape_empty_write_pipeline (drive);
-			idetape_flush_tape_buffers (drive);
+			idetape_empty_write_pipeline(drive);
+			idetape_flush_tape_buffers(drive);
 		}
 #if IDETAPE_DEBUG_BUGS
 		if (tape->merge_stage || tape->merge_stage_size) {
-			printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n");
+			printk(KERN_ERR "ide-tape: merge_stage_size "
+				"should be 0 now\n");
 			tape->merge_stage_size = 0;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -3949,9 +4149,9 @@
 		 *	is switched from completion mode to buffer available
 		 *	mode.
 		 */
-		bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bh);
+		bytes_read = idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bh);
 		if (bytes_read < 0) {
-			kfree (tape->merge_stage);
+			kfree(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return bytes_read;
@@ -3959,18 +4159,19 @@
 	}
 	if (tape->restart_speed_control_req)
 		idetape_restart_speed_control(drive);
-	ide_init_drive_cmd (&rq);
+	ide_init_drive_cmd(&rq);
 	rq.cmd = IDETAPE_READ_RQ;
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
-	if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) && tape->nr_stages <= max_stages) {
-		new_stage = idetape_kmalloc_stage (tape);
+	if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) &&
+	    tape->nr_stages <= max_stages) {
+		new_stage = idetape_kmalloc_stage(tape);
 		while (new_stage != NULL) {
 			new_stage->rq = rq;
-			idetape_add_stage_tail (drive, new_stage);
+			idetape_add_stage_tail(drive, new_stage);
 			if (tape->nr_stages >= max_stages)
 				break;
-			new_stage = idetape_kmalloc_stage (tape);
+			new_stage = idetape_kmalloc_stage(tape);
 		}
 	}
 	if (!idetape_pipeline_active(tape)) {
@@ -3979,11 +4180,11 @@
 			tape->insert_time = jiffies;
 			tape->insert_size = 0;
 			tape->insert_speed = 0;
-			idetape_insert_pipeline_into_queue (drive);
+			idetape_insert_pipeline_into_queue(drive);
 		} else if (tape->onstream) {
 			idetape_update_stats(drive);
 			if (tape->cur_frames < tape->max_frames - 5)
-				idetape_insert_pipeline_into_queue (drive);
+				idetape_insert_pipeline_into_queue(drive);
 		}
 	}
 	return 0;
@@ -4000,7 +4201,9 @@
 	 */
 	while (1) {
 		if (cnt++ > 1000) {   /* AJN: was 100 */
-			printk(KERN_INFO "ide-tape: %s: couldn't find logical block %d, aborting\n", tape->name, logical_blk_num);
+			printk(KERN_INFO "ide-tape: %s: couldn't find "
+				"logical block %d, aborting\n",
+				tape->name, logical_blk_num);
 			return 0;
 		}
 		idetape_initiate_read(drive, max_stages);
@@ -4012,21 +4215,31 @@
 #endif
 				clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 				position = idetape_read_position(drive);
-				printk(KERN_INFO "ide-tape: %s: blank block detected at %d\n", tape->name, position);
+				printk(KERN_INFO "ide-tape: %s: blank block "
+					"detected at %d\n", tape->name,
+					position);
 				if (position >= 3000 && position < 3080)
-					position += 32;  /* Why is this check and number ??? MM */
-				if (position >= OS_DATA_ENDFRAME1 && position < 3000)
+					/* Why is this check and number ??? MM */
+					position += 32;
+				if (position >= OS_DATA_ENDFRAME1 &&
+				    position < 3000)
 					position = 3000;
 				else
 					/*
-					 * compensate for write errors that generally skip 80 frames,
-					 * expect around 20 read errors in a row...
+					 * compensate for write errors that
+					 * generally skip 80 frames, expect
+					 * around 20 read errors in a row...
 					 */
 					position += 60;
-				if (position >= OS_DATA_ENDFRAME1 && position < 3000)
+				if (position >= OS_DATA_ENDFRAME1 &&
+				    position < 3000)
 					position = 3000;
 				printk(KERN_INFO "ide-tape: %s: positioning tape to block %d\n", tape->name, position);
-				if (position == 3000)  /* seems to be needed to correctly position at block 3000 MM */
+
+				/* seems to be needed to correctly position
+				 * at block 3000 MM
+				 */
+				if (position == 3000)
 					idetape_position_tape(drive, 0, 0, 0);
 				idetape_position_tape(drive, position, 0, 0);
 				cnt += 40;
@@ -4069,7 +4282,8 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_add_chrdev_read_request, %d blocks\n", blocks);
+		printk(KERN_INFO "ide-tape: Reached %s, %d blocks\n",
+			__FUNCTION__, blocks);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	/*
@@ -4083,17 +4297,19 @@
 		}
 		if (test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
 		 	return 0;
-		return idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh);
+		return idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh);
 	}
 	rq_ptr = &tape->first_stage->rq;
 	bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
 	rq_ptr->nr_sectors = rq_ptr->current_nr_sectors = 0;
 
 
-	if (tape->onstream && !tape->raw && tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
+	if (tape->onstream && !tape->raw &&
+	    tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: %s: EOD reached\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: EOD reached\n",
+				tape->name);
 #endif
 		return 0;
 	}
@@ -4101,20 +4317,21 @@
 		return 0;
 	if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK) {
 		idetape_switch_buffers (tape, tape->first_stage);
-		set_bit (IDETAPE_FILEMARK, &tape->flags);
+		set_bit(IDETAPE_FILEMARK, &tape->flags);
 #if USE_IOTRACE
 		IO_trace(IO_IDETAPE_FIFO, tape->pipeline_head, tape->buffer_head, tape->tape_head, tape->minor);
 #endif
 		calculate_speeds(drive);
 	} else {
-		idetape_switch_buffers (tape, tape->first_stage);
+		idetape_switch_buffers(tape, tape->first_stage);
 		if (rq_ptr->errors == IDETAPE_ERROR_GENERAL) {
 #if ONSTREAM_DEBUG
 			if (tape->debug_level >= 1)
-				printk(KERN_INFO "ide-tape: error detected, bytes_read %d\n", bytes_read);
+				printk(KERN_INFO "ide-tape: error detected, "
+					"bytes_read %d\n", bytes_read);
 #endif
 		}
-		clear_bit (IDETAPE_FILEMARK, &tape->flags);
+		clear_bit(IDETAPE_FILEMARK, &tape->flags);
 		spin_lock_irqsave(&tape->spinlock, flags);
 		idetape_remove_stage_head (drive);
 		spin_unlock_irqrestore(&tape->spinlock, flags);
@@ -4126,9 +4343,10 @@
 		calculate_speeds(drive);
 	}
 #if IDETAPE_DEBUG_BUGS
-	if (bytes_read > blocks*tape->tape_block_size) {
-		printk (KERN_ERR "ide-tape: bug: trying to return more bytes than requested\n");
-		bytes_read=blocks*tape->tape_block_size;
+	if (bytes_read > blocks * tape->tape_block_size) {
+		printk(KERN_ERR "ide-tape: bug: trying to return more "
+			"bytes than requested\n");
+		bytes_read = blocks * tape->tape_block_size;
 	}
 #endif /* IDETAPE_DEBUG_BUGS */
 	return (bytes_read);
@@ -4142,16 +4360,16 @@
 	
 	while (bcount) {
 		bh = tape->merge_stage->bh;
-		count = IDE_MIN (tape->stage_size, bcount);
+		count = IDE_MIN(tape->stage_size, bcount);
 		bcount -= count;
 		blocks = count / tape->tape_block_size;
 		while (count) {
 			atomic_set(&bh->b_count, IDE_MIN (count, bh->b_size));
-			memset (bh->b_data, 0, atomic_read(&bh->b_count));
+			memset(bh->b_data, 0, atomic_read(&bh->b_count));
 			count -= atomic_read(&bh->b_count);
 			bh = bh->b_reqnext;
 		}
-		idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
+		idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
 	}
 }
 
@@ -4162,7 +4380,7 @@
 	struct request *rq;
 	int size = 0;
 
-	idetape_wait_for_pipeline (drive);
+	idetape_wait_for_pipeline(drive);
 	stage = tape->first_stage;
 	while (stage != NULL) {
 		rq = &stage->rq;
@@ -4187,16 +4405,16 @@
 	idetape_tape_t *tape = drive->driver_data;
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: Reached idetape_rewind_tape\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */	
 	
-	idetape_create_rewind_cmd (drive, &pc);
-	retval = idetape_queue_pc_tail (drive, &pc);
+	idetape_create_rewind_cmd(drive, &pc);
+	retval = idetape_queue_pc_tail(drive, &pc);
 	if (retval)
 		return retval;
 
-	idetape_create_read_position_cmd (&pc);
-	retval = idetape_queue_pc_tail (drive, &pc);
+	idetape_create_read_position_cmd(&pc);
+	retval = idetape_queue_pc_tail(drive, &pc);
 	if (retval)
 		return retval;
 	tape->logical_blk_num = 0;
@@ -4218,7 +4436,7 @@
 
 #if IDETAPE_DEBUG_LOG	
 	if (tape->debug_level >= 4)
-		printk (KERN_INFO "ide-tape: Reached idetape_blkdev_ioctl\n");
+		printk(KERN_INFO "ide-tape: Reached %s\n", __FUNCTION__);
 #endif /* IDETAPE_DEBUG_LOG */
 	switch (cmd) {
 		case 0x0340:
@@ -4248,7 +4466,7 @@
 {
 	MOD_INC_USE_COUNT;
 #if ONSTREAM_DEBUG
-        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_blkdev_open\n");
+        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in %s\n", __FUNCTION__);
 #endif
 	return 0;
 }
@@ -4257,7 +4475,7 @@
 {
 	MOD_DEC_USE_COUNT;
 #if ONSTREAM_DEBUG
-        printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_blkdev_release\n");
+        printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in %s\n", __FUNCTION__);
 #endif
 }
 
@@ -4268,7 +4486,7 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 	if (tape != NULL)
-		set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
+		set_bit(IDETAPE_IGNORE_DSC, &tape->flags);
 }
 
 /*
@@ -4291,7 +4509,8 @@
 	unsigned long flags;
 
 	if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_bwd\n", tape->name);
+		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk "
+			"num in space_filemarks_bwd\n", tape->name);
 		return -EIO;
 	}
 	while (cnt != mt_count) {
@@ -4300,16 +4519,20 @@
 			return -EIO;
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: positioning to last mark at %d\n", last_mark_addr);
+			printk(KERN_INFO "ide-tape: positioning to last "
+			"mark at %d\n", last_mark_addr);
 #endif
 		idetape_position_tape(drive, last_mark_addr, 0, 0);
 		cnt++;
 		if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-			printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: couldn't get logical "
+				"blk num in space_filemarks\n", tape->name);
 			return -EIO;
 		}
 		if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-			printk(KERN_INFO "ide-tape: %s: expected to find marker at block %d, not found\n", tape->name, last_mark_addr);
+			printk(KERN_INFO "ide-tape: %s: expected to find "
+				"marker at block %d, not found\n",
+				tape->name, last_mark_addr);
 			return -EIO;
 		}
 	}
@@ -4334,12 +4557,14 @@
 	unsigned long flags;
 
 	if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwd\n", tape->name);
+		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk "
+			"num in space_filemarks_fwd\n", tape->name);
 		return -EIO;
 	}
 	while (1) {
 		if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-			printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: couldn't get logical "
+				"blk num in space_filemarks\n", tape->name);
 			return -EIO;
 		}
 		if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_MARKER)
@@ -4347,19 +4572,20 @@
 		if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
 #if ONSTREAM_DEBUG
 			if (tape->debug_level >= 2)
-				printk(KERN_INFO "ide-tape: %s: space_fwd: EOD reached\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: space_fwd: "
+					"EOD reached\n", tape->name);
 #endif
 			return -EIO;
 		}
 		if (cnt == mt_count)
 			break;
 		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 		spin_unlock_irqrestore(&tape->spinlock, flags);
 	}
 	if (mt_op == MTFSF) {
 		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 		tape->logical_blk_num++;
 		spin_unlock_irqrestore(&tape->spinlock, flags);
 	}
@@ -4377,7 +4603,8 @@
 	unsigned long flags;
 
 	if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwd\n", tape->name);
+		printk(KERN_INFO "ide-tape: %s: couldn't get logical blk "
+			"num in space_filemarks_fwd\n", tape->name);
 		return -EIO;
 	}
 
@@ -4390,22 +4617,27 @@
 		if (tape->first_stage->aux->frame_type == OS_FRAME_TYPE_EOD) {
 #if ONSTREAM_DEBUG
 			if (tape->debug_level >= 2)
-				printk(KERN_INFO "ide-tape: %s: space_fwd: EOD reached\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: space_fwd: "
+					"EOD reached\n", tape->name);
 #endif
 			return -EIO;
 		}
 		if (ntohl(tape->first_stage->aux->filemark_cnt) == 0) {
 			if (tape->first_mark_addr == -1) {
-				printk(KERN_INFO "ide-tape: %s: reverting to slow filemark space\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: reverting to "
+					"slow filemark space\n", tape->name);
 				return idetape_onstream_space_over_filemarks_forward_slow(drive, mt_op, mt_count);
 			}
 			idetape_position_tape(drive, tape->first_mark_addr, 0, 0);
 			if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-				printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks_fwd_fast\n", tape->name);
+				printk(KERN_INFO "ide-tape: %s: couldn't get "
+					"logical blk num in %s\n",							__FUNCTION__, tape->name);
 				return -EIO;
 			}
 			if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-				printk(KERN_INFO "ide-tape: %s: expected to find filemark at %d\n", tape->name, tape->first_mark_addr);
+				printk(KERN_INFO "ide-tape: %s: expected to "
+					"find filemark at %d\n",
+					tape->name, tape->first_mark_addr);
 				return -EIO;
 			}
 		} else {
@@ -4418,7 +4650,8 @@
 	while (cnt != mt_count) {
 		next_mark_addr = ntohl(tape->first_stage->aux->next_mark_addr);
 		if (!next_mark_addr || next_mark_addr > tape->eod_frame_addr) {
-			printk(KERN_INFO "ide-tape: %s: reverting to slow filemark space\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: reverting to slow "
+				"filemark space\n", tape->name);
 			return idetape_onstream_space_over_filemarks_forward_slow(drive, mt_op, mt_count - cnt);
 #if ONSTREAM_DEBUG
 		} else if (tape->debug_level >= 2) {
@@ -4428,17 +4661,20 @@
 		idetape_position_tape(drive, next_mark_addr, 0, 0);
 		cnt++;
 		if (!idetape_get_logical_blk(drive, -1, 10, 0)) {
-			printk(KERN_INFO "ide-tape: %s: couldn't get logical blk num in space_filemarks\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: couldn't get logical "
+				"blk num in space_filemarks\n", tape->name);
 			return -EIO;
 		}
 		if (tape->first_stage->aux->frame_type != OS_FRAME_TYPE_MARKER) {
-			printk(KERN_INFO "ide-tape: %s: expected to find marker at block %d, not found\n", tape->name, next_mark_addr);
+			printk(KERN_INFO "ide-tape: %s: expected to find "
+				"marker at block %d, not found\n",
+				tape->name, next_mark_addr);
 			return -EIO;
 		}
 	}
 	if (mt_op == MTFSF) {
 		spin_lock_irqsave(&tape->spinlock, flags);
-		idetape_remove_stage_head (drive);
+		idetape_remove_stage_head(drive);
 		tape->logical_blk_num++;
 		spin_unlock_irqrestore(&tape->spinlock, flags);
 	}
@@ -4485,7 +4721,7 @@
 		 *	filemarks.
 		 */
 		tape->merge_stage_size = 0;
-		clear_bit (IDETAPE_FILEMARK, &tape->flags);
+		clear_bit(IDETAPE_FILEMARK, &tape->flags);
 		while (tape->first_stage != NULL) {
 			idetape_wait_first_stage(drive);
 			if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK)
@@ -4494,7 +4730,7 @@
 				switch (mt_op) {
 					case MTFSF:
 						spin_lock_irqsave(&tape->spinlock, flags);
-						idetape_remove_stage_head (drive);
+						idetape_remove_stage_head(drive);
 						spin_unlock_irqrestore(&tape->spinlock, flags);
 					case MTFSFM:
 						return (0);
@@ -4503,10 +4739,10 @@
 				}
 			}
 			spin_lock_irqsave(&tape->spinlock, flags);
-			idetape_remove_stage_head (drive);
+			idetape_remove_stage_head(drive);
 			spin_unlock_irqrestore(&tape->spinlock, flags);
 		}
-		idetape_discard_read_pipeline (drive, 1);
+		idetape_discard_read_pipeline(drive, 1);
 	}
 
 	/*
@@ -4515,27 +4751,28 @@
 	 */
 	switch (mt_op) {
 		case MTFSF:
-			idetape_create_space_cmd (&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_create_space_cmd(&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTFSFM:
 			if (!tape->capabilities.sprev)
 				return (-EIO);
-			retval = idetape_space_over_filemarks (drive, MTFSF, mt_count-count);
+			retval = idetape_space_over_filemarks(drive, MTFSF, mt_count-count);
 			if (retval) return (retval);
-			return (idetape_space_over_filemarks (drive, MTBSF, 1));
+			return (idetape_space_over_filemarks(drive, MTBSF, 1));
 		case MTBSF:
 			if (!tape->capabilities.sprev)
 				return (-EIO);
-			idetape_create_space_cmd (&pc,-(mt_count+count),IDETAPE_SPACE_OVER_FILEMARK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_create_space_cmd(&pc,-(mt_count+count),IDETAPE_SPACE_OVER_FILEMARK);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTBSFM:
 			if (!tape->capabilities.sprev)
 				return (-EIO);
-			retval = idetape_space_over_filemarks (drive, MTBSF, mt_count+count);
+			retval = idetape_space_over_filemarks(drive, MTBSF, mt_count+count);
 			if (retval) return (retval);
-			return (idetape_space_over_filemarks (drive, MTFSF, 1));
+			return (idetape_space_over_filemarks(drive, MTFSF, 1));
 		default:
-			printk (KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
+			printk(KERN_ERR "ide-tape: MTIO operation %d not "
+				"supported\n", mt_op);
 			return (-EIO);
 	}
 }
@@ -4562,7 +4799,7 @@
 				    size_t count, loff_t *ppos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
 	ssize_t bytes_read,temp, actually_read = 0, rc;
 
@@ -4571,17 +4808,21 @@
 		return -ENXIO;
 	}
 	if (tape->onstream && (count != tape->tape_block_size)) {
-		printk(KERN_ERR "ide-tape: %s: use %d bytes as block size (%Zd used)\n", tape->name, tape->tape_block_size, count);
+		printk(KERN_ERR "ide-tape: %s: use %d bytes as block size "
+			"(%Zd used)\n", tape->name,
+			tape->tape_block_size, count);
 		return -EINVAL;
 	}
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %Zd\n", count);
+		printk (KERN_INFO "ide-tape: Reached %s, count %Zd\n",
+			__FUNCTION__, count);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (tape->chrdev_direction != idetape_direction_read) {
-		if (test_bit (IDETAPE_DETECT_BS, &tape->flags))
-			if (count > tape->tape_block_size && (count % tape->tape_block_size) == 0)
+		if (test_bit(IDETAPE_DETECT_BS, &tape->flags))
+			if (count > tape->tape_block_size &&
+			    (count % tape->tape_block_size) == 0)
 				tape->user_bs_factor = count / tape->tape_block_size;
 	}
 	if ((rc = idetape_initiate_read(drive, tape->max_stages)) < 0)
@@ -4589,42 +4830,45 @@
 	if (count == 0)
 		return (0);
 	if (tape->merge_stage_size) {
-		actually_read = IDE_MIN (tape->merge_stage_size, count);
-		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, actually_read);
+		actually_read = IDE_MIN(tape->merge_stage_size, count);
+		idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read);
 		buf += actually_read;
 		tape->merge_stage_size -= actually_read;
 		count -= actually_read;
 	}
 	while (count >= tape->stage_size) {
-		bytes_read = idetape_add_chrdev_read_request (drive, tape->capabilities.ctl);
+		bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
 		if (bytes_read <= 0)
 			goto finish;
-		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, bytes_read);
+		idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read);
 		buf += bytes_read;
 		count -= bytes_read;
 		actually_read += bytes_read;
 	}
 	if (count) {
-		bytes_read=idetape_add_chrdev_read_request (drive, tape->capabilities.ctl);
+		bytes_read=idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
 		if (bytes_read <= 0)
 			goto finish;
-		temp = IDE_MIN (count, bytes_read);
-		idetape_copy_stage_to_user (tape, buf, tape->merge_stage, temp);
+		temp = IDE_MIN(count, bytes_read);
+		idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp);
 		actually_read += temp;
 		tape->merge_stage_size = bytes_read-temp;
 	}
 finish:
-	if (!actually_read && test_bit (IDETAPE_FILEMARK, &tape->flags)) {
+	if (!actually_read && test_bit(IDETAPE_FILEMARK, &tape->flags)) {
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: %s: spacing over filemark\n", tape->name);
+			printk(KERN_INFO "ide-tape: %s: spacing over "
+				"filemark\n", tape->name);
 #endif
 		idetape_space_over_filemarks (drive, MTFSF, 1);
 		return 0;
 	}
-	if (tape->onstream && !actually_read && test_and_clear_bit(IDETAPE_READ_ERROR, &tape->flags)) {
-		printk(KERN_ERR "ide-tape: %s: unrecovered read error on logical block number %d, skipping\n",
-					tape->name, tape->logical_blk_num);
+	if (tape->onstream && !actually_read &&
+	    test_and_clear_bit(IDETAPE_READ_ERROR, &tape->flags)) {
+		printk(KERN_ERR "ide-tape: %s: unrecovered read error on "
+			"logical block number %d, skipping\n",
+			tape->name, tape->logical_blk_num);
 		tape->logical_blk_num++;
 		return -EIO;
 	}
@@ -4649,21 +4893,25 @@
 	position = idetape_read_position(drive);
 #if ONSTREAM_DEBUG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: current position (2) %d, lblk %d\n", position, tape->logical_blk_num);
+		printk(KERN_INFO "ide-tape: current position (2) %d, "
+			"lblk %d\n", position, tape->logical_blk_num);
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: current position (2) tape block %d\n", tape->last_frame_position);
+		printk(KERN_INFO "ide-tape: current position (2) tape "
+			"block %d\n", tape->last_frame_position);
 #endif
 	idetape_position_tape(drive, last_mark_addr, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't read last marker\n", tape->name);
-		__idetape_kfree_stage (stage);
+	if (!idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 1, stage->bh)) {
+		printk(KERN_INFO "ide-tape: %s: couldn't read last marker\n",
+			tape->name);
+		__idetape_kfree_stage(stage);
 		idetape_position_tape(drive, position, 0, 0);
 		return;
 	}
 	aux = stage->aux;
 	if (aux->frame_type != OS_FRAME_TYPE_MARKER) {
-		printk(KERN_INFO "ide-tape: %s: expected to find marker at addr %d\n", tape->name, last_mark_addr);
-		__idetape_kfree_stage (stage);
+		printk(KERN_INFO "ide-tape: %s: expected to find marker "
+			"at addr %d\n", tape->name, last_mark_addr);
+		__idetape_kfree_stage(stage);
 		idetape_position_tape(drive, position, 0, 0);
 		return;
 	}
@@ -4673,13 +4921,14 @@
 #endif
 	aux->next_mark_addr = htonl(next_mark_addr);
 	idetape_position_tape(drive, last_mark_addr, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't write back marker frame at %d\n", tape->name, last_mark_addr);
-		__idetape_kfree_stage (stage);
+	if (!idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+		printk(KERN_INFO "ide-tape: %s: couldn't write back marker "
+			"frame at %d\n", tape->name, last_mark_addr);
+		__idetape_kfree_stage(stage);
 		idetape_position_tape(drive, position, 0, 0);
 		return;
 	}
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 	idetape_flush_tape_buffers (drive);
 	idetape_position_tape(drive, position, 0, 0);
 	return;
@@ -4702,18 +4951,20 @@
 #if ONSTREAM_DEBUG
 	printk(KERN_INFO "write_filler: positioning failed it returned %d\n", rc);
 #endif
-	if (rc != 0) 
-		return;	/* don't write fillers if we cannot position the tape. */
+	if (rc != 0)
+		/* don't write fillers if we cannot position the tape. */
+		return;
 
 	strcpy(stage->bh->b_data, "Filler");
 	while (cnt--) {
-		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
-			printk(KERN_INFO "ide-tape: %s: write_filler: couldn't write header frame\n", tape->name);
-			__idetape_kfree_stage (stage);
+		if (!idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+			printk(KERN_INFO "ide-tape: %s: write_filler: "
+				"couldn't write header frame\n", tape->name);
+			__idetape_kfree_stage(stage);
 			return;
 		}
 	}
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 }
 
 static void __idetape_write_header (ide_drive_t *drive, int block, int cnt)
@@ -4741,14 +4992,14 @@
 	header.partition.eod_frame_addr = htonl(tape->eod_frame_addr);
 	memcpy(stage->bh->b_data, &header, sizeof(header));
 	while (cnt--) {
-		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+		if (!idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
 			printk(KERN_INFO "ide-tape: %s: couldn't write header frame\n", tape->name);
-			__idetape_kfree_stage (stage);
+			__idetape_kfree_stage(stage);
 			return;
 		}
 	}
-	__idetape_kfree_stage (stage);
-	idetape_flush_tape_buffers (drive);
+	__idetape_kfree_stage(stage);
+	idetape_flush_tape_buffers(drive);
 }
 
 static void idetape_write_header (ide_drive_t *drive, int locate_eod)
@@ -4767,7 +5018,9 @@
 	if (locate_eod) {
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
-			printk(KERN_INFO "ide-tape: %s: locating back to eod frame addr %d\n", tape->name, tape->eod_frame_addr);
+			printk(KERN_INFO "ide-tape: %s: locating back to "
+				"eod frame addr %d\n", tape->name,
+				tape->eod_frame_addr);
 #endif
 		idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
 	}
@@ -4777,7 +5030,7 @@
 				     size_t count, loff_t *ppos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
 	ssize_t retval, actually_written = 0;
 	int position;
@@ -4794,13 +5047,14 @@
 
 	if (tape->onstream) {
 		if (count != tape->tape_block_size) {
-			printk(KERN_ERR "ide-tape: %s: chrdev_write: use %d bytes as block size (%Zd used)\n",
-					tape->name, tape->tape_block_size, count);
+			printk(KERN_ERR "ide-tape: %s: chrdev_write: "
+				"use %d bytes as block size (%Zd used)\n",
+				tape->name, tape->tape_block_size, count);
 			return -EINVAL;
 		}
 		/*
-		 * Check if we reach the end of the tape. Just assume the whole pipeline
-		 * is filled with write requests!
+		 * Check if we reach the end of the tape. Just assume the whole
+		 * pipeline is filled with write requests!
 		 */
 		if (tape->first_frame_position + tape->nr_stages >= tape->capacity - OS_EW)  {
 #if ONSTREAM_DEBUG
@@ -4812,19 +5066,20 @@
 		}
 	}
 
-	if (tape->chrdev_direction != idetape_direction_write) {	/* Initialize write operation */
+	/* Initialize write operation */
+	if (tape->chrdev_direction != idetape_direction_write) {
 		if (tape->chrdev_direction == idetape_direction_read)
-			idetape_discard_read_pipeline (drive, 1);
+			idetape_discard_read_pipeline(drive, 1);
 #if IDETAPE_DEBUG_BUGS
 		if (tape->merge_stage || tape->merge_stage_size) {
-			printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n");
+			printk(KERN_ERR "ide-tape: merge_stage_size should be 0 now\n");
 			tape->merge_stage_size = 0;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		if ((tape->merge_stage = __idetape_kmalloc_stage (tape, 0, 0)) == NULL)
+		if ((tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0)) == NULL)
 			return -ENOMEM;
 		tape->chrdev_direction = idetape_direction_write;
-		idetape_init_merge_stage (tape);
+		idetape_init_merge_stage(tape);
 
 		if (tape->onstream) {
 			position = idetape_read_position(drive);
@@ -4860,9 +5115,9 @@
 		 *	is switched from completion mode to buffer available
 		 *	mode.
 		 */
-		retval = idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bh);
+		retval = idetape_queue_rw_tail(drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bh);
 		if (retval < 0) {
-			kfree (tape->merge_stage);
+			kfree(tape->merge_stage);
 			tape->merge_stage = NULL;
 			tape->chrdev_direction = idetape_direction_none;
 			return retval;
@@ -4879,35 +5134,35 @@
 	if (tape->merge_stage_size) {
 #if IDETAPE_DEBUG_BUGS
 		if (tape->merge_stage_size >= tape->stage_size) {
-			printk (KERN_ERR "ide-tape: bug: merge buffer too big\n");
+			printk(KERN_ERR "ide-tape: bug: merge buffer too big\n");
 			tape->merge_stage_size = 0;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		actually_written = IDE_MIN (tape->stage_size - tape->merge_stage_size, count);
-		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, actually_written);
+		actually_written = IDE_MIN(tape->stage_size - tape->merge_stage_size, count);
+		idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written);
 		buf += actually_written;
 		tape->merge_stage_size += actually_written;
 		count -= actually_written;
 
 		if (tape->merge_stage_size == tape->stage_size) {
 			tape->merge_stage_size = 0;
-			retval = idetape_add_chrdev_write_request (drive, tape->capabilities.ctl);
+			retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
 			if (retval <= 0)
 				return (retval);
 		}
 	}
 	while (count >= tape->stage_size) {
-		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, tape->stage_size);
+		idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size);
 		buf += tape->stage_size;
 		count -= tape->stage_size;
-		retval = idetape_add_chrdev_write_request (drive, tape->capabilities.ctl);
+		retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
 		actually_written += tape->stage_size;
 		if (retval <= 0)
 			return (retval);
 	}
 	if (count) {
-		actually_written+=count;
-		idetape_copy_stage_from_user (tape, tape->merge_stage, buf, count);
+		actually_written += count;
+		idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count);
 		tape->merge_stage_size += count;
 	}
 	return (actually_written);
@@ -4920,19 +5175,20 @@
 	idetape_pc_t pc;
 
 	if (!tape->onstream) {
-		idetape_create_write_filemark_cmd(drive, &pc, 1);	/* Write a filemark */
-		if (idetape_queue_pc_tail (drive, &pc)) {
-			printk (KERN_ERR "ide-tape: Couldn't write a filemark\n");
+		/* Write a filemark */
+		idetape_create_write_filemark_cmd(drive, &pc, 1);
+		if (idetape_queue_pc_tail(drive, &pc)) {
+			printk(KERN_ERR "ide-tape: Couldn't write a filemark\n");
 			return -EIO;
 		}
 	} else if (!tape->raw) {
 		last_mark_addr = idetape_read_position(drive);
-		tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
+		tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
 		if (tape->merge_stage != NULL) {
 			idetape_init_stage(drive, tape->merge_stage, OS_FRAME_TYPE_MARKER, tape->logical_blk_num);
-			idetape_pad_zeros (drive, tape->stage_size);
+			idetape_pad_zeros(drive, tape->stage_size);
 			tape->logical_blk_num++;
-			__idetape_kfree_stage (tape->merge_stage);
+			__idetape_kfree_stage(tape->merge_stage);
 			tape->merge_stage = NULL;
 		}
 		if (tape->filemark_cnt)
@@ -4950,11 +5206,11 @@
 
 	if (!tape->onstream || tape->raw)
 		return;
-	tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
+	tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
 	if (tape->merge_stage != NULL) {
 		tape->eod_frame_addr = idetape_read_position(drive);
 		idetape_init_stage(drive, tape->merge_stage, OS_FRAME_TYPE_EOD, tape->logical_blk_num);
-		idetape_pad_zeros (drive, tape->stage_size);
+		idetape_pad_zeros(drive, tape->stage_size);
 		__idetape_kfree_stage (tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
@@ -4989,7 +5245,9 @@
 error:
 	tape->speed_control = speed_control;
 	tape->restart_speed_control_req = 1;
-	printk(KERN_INFO "ide-tape: %s: couldn't seek to logical block %d (at %d), %d retries\n", tape->name, logical_blk_num, tape->logical_blk_num, retries);
+	printk(KERN_INFO "ide-tape: %s: couldn't seek to logical block %d "
+		"(at %d), %d retries\n", tape->name, logical_blk_num,
+		tape->logical_blk_num, retries);
 	return -EIO;
 ok:
 	tape->speed_control = speed_control;
@@ -5068,7 +5326,8 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 1)
-		printk (KERN_INFO "ide-tape: Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%d\n",mt_op,mt_count);
+		printk(KERN_INFO "ide-tape: Handling MTIOCTOP "
+			"ioctl: mt_op=%d, mt_count=%d\n", mt_op, mt_count);
 #endif /* IDETAPE_DEBUG_LOG */
 	/*
 	 *	Commands which need our pipelined read-ahead stages.
@@ -5080,41 +5339,41 @@
 		case MTBSFM:
 			if (!mt_count)
 				return (0);
-			return (idetape_space_over_filemarks (drive,mt_op,mt_count));
+			return (idetape_space_over_filemarks(drive,mt_op,mt_count));
 		default:
 			break;
 	}
 	switch (mt_op) {
 		case MTWEOF:
-			idetape_discard_read_pipeline (drive, 1);
+			idetape_discard_read_pipeline(drive, 1);
 			for (i = 0; i < mt_count; i++) {
 				retval = idetape_write_filemark(drive);
 				if (retval) return retval;
 			}
 			return (0);
 		case MTREW:
-			idetape_discard_read_pipeline (drive, 0);
+			idetape_discard_read_pipeline(drive, 0);
 			if (idetape_rewind_tape(drive))
 				return -EIO;
 			if (tape->onstream && !tape->raw)
 				return idetape_position_tape(drive, OS_DATA_STARTFRAME1, 0, 0);
 			return 0;
 		case MTLOAD:
-			idetape_discard_read_pipeline (drive, 0);
-			idetape_create_load_unload_cmd (drive, &pc, IDETAPE_LU_LOAD_MASK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_discard_read_pipeline(drive, 0);
+			idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTUNLOAD:
 		case MTOFFL:
-			idetape_discard_read_pipeline (drive, 0);
-			idetape_create_load_unload_cmd (drive, &pc,!IDETAPE_LU_LOAD_MASK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_discard_read_pipeline(drive, 0);
+			idetape_create_load_unload_cmd(drive, &pc,!IDETAPE_LU_LOAD_MASK);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTNOP:
-			idetape_discard_read_pipeline (drive, 0);
-			return (idetape_flush_tape_buffers (drive));
+			idetape_discard_read_pipeline(drive, 0);
+			return (idetape_flush_tape_buffers(drive));
 		case MTRETEN:
-			idetape_discard_read_pipeline (drive, 0);
-			idetape_create_load_unload_cmd (drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_discard_read_pipeline(drive, 0);
+			idetape_create_load_unload_cmd(drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTEOM:
 			if (tape->onstream) {
 #if ONSTREAM_DEBUG
@@ -5128,8 +5387,8 @@
 					return -EIO;
 				return 0;
 			}
-			idetape_create_space_cmd (&pc, 0, IDETAPE_SPACE_TO_EOD);
-			return (idetape_queue_pc_tail (drive, &pc));
+			idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTERASE:
 			if (tape->onstream) {
 				tape->eod_frame_addr = OS_DATA_STARTFRAME1;
@@ -5137,7 +5396,7 @@
 				tape->first_mark_addr = tape->last_mark_addr = -1;
 				idetape_position_tape(drive, tape->eod_frame_addr, 0, 0);
 				idetape_write_eod(drive);
-				idetape_flush_tape_buffers (drive);
+				idetape_flush_tape_buffers(drive);
 				idetape_write_header(drive, 0);
 				/*
 				 * write filler frames to the unused frames...
@@ -5145,13 +5404,13 @@
 				 */
 				idetape_write_filler(drive, OS_DATA_STARTFRAME1 - 10, 10);
 				idetape_write_filler(drive, OS_DATA_ENDFRAME1, 10);
-				idetape_flush_tape_buffers (drive);
-				(void) idetape_rewind_tape (drive);
+				idetape_flush_tape_buffers(drive);
+				(void) idetape_rewind_tape(drive);
 				return 0;
 			}
-			(void) idetape_rewind_tape (drive);
-			idetape_create_erase_cmd (&pc);
-			return (idetape_queue_pc_tail (drive, &pc));
+			(void) idetape_rewind_tape(drive);
+			idetape_create_erase_cmd(&pc);
+			return (idetape_queue_pc_tail(drive, &pc));
 		case MTSETBLK:
 			if (tape->onstream) {
 				if (mt_count != tape->tape_block_size) {
@@ -5164,21 +5423,21 @@
 				if (mt_count < tape->tape_block_size || mt_count % tape->tape_block_size)
 					return -EIO;
 				tape->user_bs_factor = mt_count / tape->tape_block_size;
-				clear_bit (IDETAPE_DETECT_BS, &tape->flags);
+				clear_bit(IDETAPE_DETECT_BS, &tape->flags);
 			} else
-				set_bit (IDETAPE_DETECT_BS, &tape->flags);
+				set_bit(IDETAPE_DETECT_BS, &tape->flags);
 			return 0;
 		case MTSEEK:
 			if (!tape->onstream || tape->raw) {
-				idetape_discard_read_pipeline (drive, 0);
-				return idetape_position_tape (drive, mt_count * tape->user_bs_factor, tape->partition, 0);
+				idetape_discard_read_pipeline(drive, 0);
+				return idetape_position_tape(drive, mt_count * tape->user_bs_factor, tape->partition, 0);
 			}
 			return idetape_seek_logical_blk(drive, mt_count);
 		case MTSETPART:
-			idetape_discard_read_pipeline (drive, 0);
+			idetape_discard_read_pipeline(drive, 0);
 			if (tape->onstream)
 				return -EIO;
-			return (idetape_position_tape (drive, 0, mt_count, 0));
+			return (idetape_position_tape(drive, 0, mt_count, 0));
 		case MTFSR:
 		case MTBSR:
 			if (tape->onstream) {
@@ -5187,26 +5446,26 @@
 				if (mt_op == MTFSR)
 					return idetape_seek_logical_blk(drive, tape->logical_blk_num + mt_count);
 				else {
-					idetape_discard_read_pipeline (drive, 0);
+					idetape_discard_read_pipeline(drive, 0);
 					return idetape_seek_logical_blk(drive, tape->logical_blk_num - mt_count);
 				}
 			}
 		case MTLOCK:
 			if (!idetape_create_prevent_cmd(drive, &pc, 1))
 				return 0;
-			retval = idetape_queue_pc_tail (drive, &pc);
+			retval = idetape_queue_pc_tail(drive, &pc);
 			if (retval) return retval;
 			tape->door_locked = DOOR_EXPLICITLY_LOCKED;
 			return 0;
 		case MTUNLOCK:
 			if (!idetape_create_prevent_cmd(drive, &pc, 0))
 				return 0;
-			retval = idetape_queue_pc_tail (drive, &pc);
+			retval = idetape_queue_pc_tail(drive, &pc);
 			if (retval) return retval;
 			tape->door_locked = DOOR_UNLOCKED;
 			return 0;
 		default:
-			printk (KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
+			printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op);
 			return (-EIO);
 	}
 }
@@ -5236,7 +5495,7 @@
  */
 static int idetape_chrdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
 	struct mtop mtop;
 	struct mtget mtget;
@@ -5245,30 +5504,30 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_chrdev_ioctl, cmd=%u\n",cmd);
+		printk(KERN_INFO "ide-tape: Reached idetape_chrdev_ioctl, cmd=%u\n",cmd);
 #endif /* IDETAPE_DEBUG_LOG */
 
 	tape->restart_speed_control_req = 1;
 	if (tape->chrdev_direction == idetape_direction_write) {
-		idetape_empty_write_pipeline (drive);
-		idetape_flush_tape_buffers (drive);
+		idetape_empty_write_pipeline(drive);
+		idetape_flush_tape_buffers(drive);
 	}
 	if (cmd == MTIOCGET || cmd == MTIOCPOS) {
-		block_offset = idetape_pipeline_size (drive) / (tape->tape_block_size * tape->user_bs_factor);
+		block_offset = idetape_pipeline_size(drive) / (tape->tape_block_size * tape->user_bs_factor);
 		if ((position = idetape_read_position(drive)) < 0)
 			return -EIO;
 	}
 	switch (cmd) {
 		case MTIOCTOP:
-			if (copy_from_user ((char *) &mtop, (char *) arg, sizeof (struct mtop)))
+			if (copy_from_user((char *) &mtop, (char *) arg, sizeof (struct mtop)))
 				return -EFAULT;
-			return (idetape_mtioctop (drive,mtop.mt_op,mtop.mt_count));
+			return (idetape_mtioctop(drive,mtop.mt_op,mtop.mt_count));
 		case MTIOCGET:
-			memset (&mtget, 0, sizeof (struct mtget));
+			memset(&mtget, 0, sizeof (struct mtget));
 			mtget.mt_type = MT_ISSCSI2;
-			if (!tape->onstream || tape->raw)
+			if (!tape->onstream || tape->raw) {
 				mtget.mt_blkno = position / tape->user_bs_factor - block_offset;
-			else {
+			} else {
 				if (!idetape_get_logical_blk(drive, -1, 10, 0))
 					mtget.mt_blkno = -1;
 				else
@@ -5297,8 +5556,8 @@
 			return 0;
 		default:
 			if (tape->chrdev_direction == idetape_direction_read)
-				idetape_discard_read_pipeline (drive, 1);
-			return (idetape_blkdev_ioctl (drive,inode,file,cmd,arg));
+				idetape_discard_read_pipeline(drive, 1);
+			return (idetape_blkdev_ioctl(drive,inode,file,cmd,arg));
 	}
 }
 
@@ -5318,7 +5577,7 @@
 	tape->wrt_pass_cntr = 0;
 	tape->eod_frame_addr = OS_DATA_STARTFRAME1;
 	tape->first_mark_addr = tape->last_mark_addr = -1;
-	stage = __idetape_kmalloc_stage (tape, 0, 0);
+	stage = __idetape_kmalloc_stage(tape, 0, 0);
 	if (stage == NULL)
 		return 0;
 #if ONSTREAM_DEBUG
@@ -5326,16 +5585,17 @@
 		printk(KERN_INFO "ide-tape: %s: reading header\n", tape->name);
 #endif
 	idetape_position_tape(drive, block, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
-		printk(KERN_INFO "ide-tape: %s: couldn't read header frame\n", tape->name);
-		__idetape_kfree_stage (stage);
+	if (!idetape_queue_rw_tail(drive, IDETAPE_READ_RQ, 1, stage->bh)) {
+		printk(KERN_INFO "ide-tape: %s: couldn't read header frame\n",
+			tape->name);
+		__idetape_kfree_stage(stage);
 		return 0;
 	}
 	header = (os_header_t *) stage->bh->b_data;
 	aux = stage->aux;
 	if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0) {
 		printk(KERN_INFO "ide-tape: %s: invalid header identification string\n", tape->name);
-		__idetape_kfree_stage (stage);
+		__idetape_kfree_stage(stage);
 		return 0;
 	}
 	if (header->major_rev != 1 || (header->minor_rev > OS_ADR_MINREV))
@@ -5354,17 +5614,21 @@
 		tape->linux_media = 1;
 		tape->linux_media_version = tape->application_sig[3] - '0';
 		if (tape->linux_media_version != 3)
-			printk(KERN_INFO "ide-tape: %s: Linux media version %d detected (current 3)\n",
-					 tape->name, tape->linux_media_version);
+			printk(KERN_INFO "ide-tape: %s: Linux media version "
+				"%d detected (current 3)\n",
+				 tape->name, tape->linux_media_version);
 	} else {
-		printk(KERN_INFO "ide-tape: %s: non Linux media detected (%s)\n", tape->name, tape->application_sig);
+		printk(KERN_INFO "ide-tape: %s: non Linux media detected "
+			"(%s)\n", tape->name, tape->application_sig);
 		tape->linux_media = 0;
 	}
 #if ONSTREAM_DEBUG
 	if (tape->debug_level >= 2)
-		printk(KERN_INFO "ide-tape: %s: detected write pass counter %d, eod frame addr %d\n", tape->name, tape->wrt_pass_cntr, tape->eod_frame_addr);
+		printk(KERN_INFO "ide-tape: %s: detected write pass "
+			"counter %d, eod frame addr %d\n", tape->name,
+			tape->wrt_pass_cntr, tape->eod_frame_addr);
 #endif
-	__idetape_kfree_stage (stage);
+	__idetape_kfree_stage(stage);
 	return 1;
 }
 
@@ -5385,7 +5649,8 @@
 	for (block = 0xbae; block < 0xbb3; block++) /* 2990 - 2994 */
 		if (__idetape_analyze_headers(drive, block))
 			goto ok;
-	printk(KERN_ERR "ide-tape: %s: failed to find valid ADRL header\n", tape->name);
+	printk(KERN_ERR "ide-tape: %s: failed to find valid ADRL header\n",
+		tape->name);
 	return 0;
 ok:
 	if (position < OS_DATA_STARTFRAME1)
@@ -5403,23 +5668,23 @@
 	ide_drive_t *drive;
 	idetape_tape_t *tape;
 	idetape_pc_t pc;
-	unsigned int minor=MINOR (inode->i_rdev);
+	unsigned int minor = MINOR(inode->i_rdev);
 			
 #if IDETAPE_DEBUG_LOG
 	printk (KERN_INFO "ide-tape: Reached idetape_chrdev_open\n");
 #endif /* IDETAPE_DEBUG_LOG */
 	
-	if ((drive = get_drive_ptr (inode->i_rdev)) == NULL)
+	if ((drive = get_drive_ptr(inode->i_rdev)) == NULL)
 		return -ENXIO;
 	tape = drive->driver_data;
 
-	if (test_and_set_bit (IDETAPE_BUSY, &tape->flags))
+	if (test_and_set_bit(IDETAPE_BUSY, &tape->flags))
 		return -EBUSY;
 	MOD_INC_USE_COUNT;
 	if (!tape->onstream) {	
 		idetape_read_position(drive);
-		if (!test_bit (IDETAPE_ADDRESS_VALID, &tape->flags))
-			(void) idetape_rewind_tape (drive);
+		if (!test_bit(IDETAPE_ADDRESS_VALID, &tape->flags))
+			(void) idetape_rewind_tape(drive);
 	} else {
 		if (minor & 64) {
 			tape->tape_block_size = tape->stage_size = 32768 + 512;
@@ -5438,12 +5703,12 @@
 	}
 	idetape_read_position(drive);
 	MOD_DEC_USE_COUNT;
-	clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
+	clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags);
 
 	if (tape->chrdev_direction == idetape_direction_none) {
 		MOD_INC_USE_COUNT;
 		if (idetape_create_prevent_cmd(drive, &pc, 1)) {
-			if (!idetape_queue_pc_tail (drive, &pc)) {
+			if (!idetape_queue_pc_tail(drive, &pc)) {
 				if (tape->door_locked != DOOR_EXPLICITLY_LOCKED)
 					tape->door_locked = DOOR_LOCKED;
 			}
@@ -5458,22 +5723,22 @@
 
 static void idetape_write_release (struct inode *inode)
 {
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
-	unsigned int minor=MINOR (inode->i_rdev);
+	unsigned int minor = MINOR(inode->i_rdev);
 
-	idetape_empty_write_pipeline (drive);
-	tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
+	idetape_empty_write_pipeline(drive);
+	tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0);
 	if (tape->merge_stage != NULL) {
-		idetape_pad_zeros (drive, tape->tape_block_size * (tape->user_bs_factor - 1));
-		__idetape_kfree_stage (tape->merge_stage);
+		idetape_pad_zeros(drive, tape->tape_block_size * (tape->user_bs_factor - 1));
+		__idetape_kfree_stage(tape->merge_stage);
 		tape->merge_stage = NULL;
 	}
 	idetape_write_filemark(drive);
 	idetape_write_eod(drive);
-	idetape_flush_tape_buffers (drive);
+	idetape_flush_tape_buffers(drive);
 	idetape_write_header(drive, minor >= 128);
-	idetape_flush_tape_buffers (drive);
+	idetape_flush_tape_buffers(drive);
 
 	return;
 }
@@ -5483,16 +5748,16 @@
  */
 static int idetape_chrdev_release (struct inode *inode, struct file *filp)
 {
-	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
+	ide_drive_t *drive = get_drive_ptr(inode->i_rdev);
 	idetape_tape_t *tape;
 	idetape_pc_t pc;
-	unsigned int minor=MINOR (inode->i_rdev);
+	unsigned int minor = MINOR(inode->i_rdev);
 
 	lock_kernel();
 	tape = drive->driver_data;
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 3)
-		printk (KERN_INFO "ide-tape: Reached idetape_chrdev_release\n");
+		printk(KERN_INFO "ide-tape: Reached idetape_chrdev_release\n");
 #endif /* IDETAPE_DEBUG_LOG */
 
 	if (tape->chrdev_direction == idetape_direction_write) {
@@ -5500,25 +5765,25 @@
 	}
 	if (tape->chrdev_direction == idetape_direction_read) {
 		if (minor < 128)
-			idetape_discard_read_pipeline (drive, 1);
+			idetape_discard_read_pipeline(drive, 1);
 		else
-			idetape_wait_for_pipeline (drive);
+			idetape_wait_for_pipeline(drive);
 	}
 	if (tape->cache_stage != NULL) {
-		__idetape_kfree_stage (tape->cache_stage);
+		__idetape_kfree_stage(tape->cache_stage);
 		tape->cache_stage = NULL;
 	}
 	if (minor < 128)
-		(void) idetape_rewind_tape (drive);
+		(void) idetape_rewind_tape(drive);
 	if (tape->chrdev_direction == idetape_direction_none) {
 		if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) {
 			if (idetape_create_prevent_cmd(drive, &pc, 0))
-				if (!idetape_queue_pc_tail (drive, &pc))
+				if (!idetape_queue_pc_tail(drive, &pc))
 					tape->door_locked = DOOR_UNLOCKED;
 		}
 		MOD_DEC_USE_COUNT;
 	}
-	clear_bit (IDETAPE_BUSY, &tape->flags);
+	clear_bit(IDETAPE_BUSY, &tape->flags);
 	unlock_kernel();
 	return 0;
 }
@@ -5545,107 +5810,107 @@
 	*((unsigned short *) &gcw) = id->config;
 
 #if IDETAPE_DEBUG_INFO
-	printk (KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
-	printk (KERN_INFO "ide-tape: Protocol Type: ");
+	printk(KERN_INFO "ide-tape: Dumping ATAPI Identify Device tape parameters\n");
+	printk(KERN_INFO "ide-tape: Protocol Type: ");
 	switch (gcw.protocol) {
-		case 0: case 1: printk (KERN_INFO "ATA\n");break;
-		case 2:	printk (KERN_INFO "ATAPI\n");break;
-		case 3: printk (KERN_INFO "Reserved (Unknown to ide-tape)\n");break;
+		case 0: case 1: printk(KERN_INFO "ATA\n");break;
+		case 2:	printk(KERN_INFO "ATAPI\n");break;
+		case 3: printk(KERN_INFO "Reserved (Unknown to ide-tape)\n");break;
 	}
-	printk (KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);	
+	printk(KERN_INFO "ide-tape: Device Type: %x - ",gcw.device_type);	
 	switch (gcw.device_type) {
-		case 0: printk (KERN_INFO "Direct-access Device\n");break;
-		case 1: printk (KERN_INFO "Streaming Tape Device\n");break;
-		case 2: case 3: case 4: printk (KERN_INFO "Reserved\n");break;
-		case 5: printk (KERN_INFO "CD-ROM Device\n");break;
-		case 6: printk (KERN_INFO "Reserved\n");
-		case 7: printk (KERN_INFO "Optical memory Device\n");break;
-		case 0x1f: printk (KERN_INFO "Unknown or no Device type\n");break;
-		default: printk (KERN_INFO "Reserved\n");
+		case 0: printk(KERN_INFO "Direct-access Device\n");break;
+		case 1: printk(KERN_INFO "Streaming Tape Device\n");break;
+		case 2: case 3: case 4: printk(KERN_INFO "Reserved\n");break;
+		case 5: printk(KERN_INFO "CD-ROM Device\n");break;
+		case 6: printk(KERN_INFO "Reserved\n");
+		case 7: printk(KERN_INFO "Optical memory Device\n");break;
+		case 0x1f: printk(KERN_INFO "Unknown or no Device type\n");break;
+		default: printk(KERN_INFO "Reserved\n");
 	}
-	printk (KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");	
-	printk (KERN_INFO "ide-tape: Command Packet DRQ Type: ");
+	printk(KERN_INFO "ide-tape: Removable: %s",gcw.removable ? "Yes\n":"No\n");	
+	printk(KERN_INFO "ide-tape: Command Packet DRQ Type: ");
 	switch (gcw.drq_type) {
-		case 0: printk (KERN_INFO "Microprocessor DRQ\n");break;
-		case 1: printk (KERN_INFO "Interrupt DRQ\n");break;
-		case 2: printk (KERN_INFO "Accelerated DRQ\n");break;
-		case 3: printk (KERN_INFO "Reserved\n");break;
+		case 0: printk(KERN_INFO "Microprocessor DRQ\n");break;
+		case 1: printk(KERN_INFO "Interrupt DRQ\n");break;
+		case 2: printk(KERN_INFO "Accelerated DRQ\n");break;
+		case 3: printk(KERN_INFO "Reserved\n");break;
 	}
-	printk (KERN_INFO "ide-tape: Command Packet Size: ");
+	printk(KERN_INFO "ide-tape: Command Packet Size: ");
 	switch (gcw.packet_size) {
-		case 0: printk (KERN_INFO "12 bytes\n");break;
-		case 1: printk (KERN_INFO "16 bytes\n");break;
-		default: printk (KERN_INFO "Reserved\n");break;
-	}
-	printk (KERN_INFO "ide-tape: Model: %.40s\n",id->model);
-	printk (KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
-	printk (KERN_INFO "ide-tape: Serial Number: %.20s\n",id->serial_no);
-	printk (KERN_INFO "ide-tape: Write buffer size: %d bytes\n",id->buf_size*512);
-	printk (KERN_INFO "ide-tape: DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
-	printk (KERN_INFO "ide-tape: ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
-	printk (KERN_INFO "ide-tape: PIO Cycle Timing Category: %d\n",id->tPIO);
-	printk (KERN_INFO "ide-tape: DMA Cycle Timing Category: %d\n",id->tDMA);
-	printk (KERN_INFO "ide-tape: Single Word DMA supported modes: ");
+		case 0: printk(KERN_INFO "12 bytes\n");break;
+		case 1: printk(KERN_INFO "16 bytes\n");break;
+		default: printk(KERN_INFO "Reserved\n");break;
+	}
+	printk(KERN_INFO "ide-tape: Model: %.40s\n",id->model);
+	printk(KERN_INFO "ide-tape: Firmware Revision: %.8s\n",id->fw_rev);
+	printk(KERN_INFO "ide-tape: Serial Number: %.20s\n",id->serial_no);
+	printk(KERN_INFO "ide-tape: Write buffer size: %d bytes\n",id->buf_size*512);
+	printk(KERN_INFO "ide-tape: DMA: %s",id->capability & 0x01 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: LBA: %s",id->capability & 0x02 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: IORDY can be disabled: %s",id->capability & 0x04 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: IORDY supported: %s",id->capability & 0x08 ? "Yes\n":"Unknown\n");
+	printk(KERN_INFO "ide-tape: ATAPI overlap supported: %s",id->capability & 0x20 ? "Yes\n":"No\n");
+	printk(KERN_INFO "ide-tape: PIO Cycle Timing Category: %d\n",id->tPIO);
+	printk(KERN_INFO "ide-tape: DMA Cycle Timing Category: %d\n",id->tDMA);
+	printk(KERN_INFO "ide-tape: Single Word DMA supported modes: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_1word & mask)
-			printk (KERN_INFO "%d ",i);
+			printk(KERN_INFO "%d ",i);
 		if (id->dma_1word & (mask << 8))
-			printk (KERN_INFO "(active) ");
+			printk(KERN_INFO "(active) ");
 	}
-	printk (KERN_INFO "\n");
-	printk (KERN_INFO "ide-tape: Multi Word DMA supported modes: ");
+	printk(KERN_INFO "\n");
+	printk(KERN_INFO "ide-tape: Multi Word DMA supported modes: ");
 	for (i=0,mask=1;i<8;i++,mask=mask << 1) {
 		if (id->dma_mword & mask)
-			printk (KERN_INFO "%d ",i);
+			printk(KERN_INFO "%d ",i);
 		if (id->dma_mword & (mask << 8))
-			printk (KERN_INFO "(active) ");
+			printk(KERN_INFO "(active) ");
 	}
-	printk (KERN_INFO "\n");
+	printk(KERN_INFO "\n");
 	if (id->field_valid & 0x0002) {
-		printk (KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
-		printk (KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
+		printk(KERN_INFO "ide-tape: Enhanced PIO Modes: %s\n",id->eide_pio_modes & 1 ? "Mode 3":"None");
+		printk(KERN_INFO "ide-tape: Minimum Multi-word DMA cycle per word: ");
 		if (id->eide_dma_min == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk(KERN_INFO "Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_dma_min);
+			printk(KERN_INFO "%d ns\n",id->eide_dma_min);
 
-		printk (KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: ");
+		printk(KERN_INFO "ide-tape: Manufacturer\'s Recommended Multi-word cycle: ");
 		if (id->eide_dma_time == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk(KERN_INFO "Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_dma_time);
+			printk(KERN_INFO "%d ns\n",id->eide_dma_time);
 
-		printk (KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: ");
+		printk(KERN_INFO "ide-tape: Minimum PIO cycle without IORDY: ");
 		if (id->eide_pio == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk(KERN_INFO "Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_pio);
+			printk(KERN_INFO "%d ns\n",id->eide_pio);
 
-		printk (KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: ");
+		printk(KERN_INFO "ide-tape: Minimum PIO cycle with IORDY: ");
 		if (id->eide_pio_iordy == 0)
-			printk (KERN_INFO "Not supported\n");
+			printk(KERN_INFO "Not supported\n");
 		else
-			printk (KERN_INFO "%d ns\n",id->eide_pio_iordy);
+			printk(KERN_INFO "%d ns\n",id->eide_pio_iordy);
 		
 	} else
-		printk (KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
+		printk(KERN_INFO "ide-tape: According to the device, fields 64-70 are not valid.\n");
 #endif /* IDETAPE_DEBUG_INFO */
 
 	/* Check that we can support this device */
 
 	if (gcw.protocol !=2 )
-		printk (KERN_ERR "ide-tape: Protocol is not ATAPI\n");
+		printk(KERN_ERR "ide-tape: Protocol is not ATAPI\n");
 	else if (gcw.device_type != 1)
-		printk (KERN_ERR "ide-tape: Device type is not set to tape\n");
+		printk(KERN_ERR "ide-tape: Device type is not set to tape\n");
 	else if (!gcw.removable)
-		printk (KERN_ERR "ide-tape: The removable flag is not set\n");
+		printk(KERN_ERR "ide-tape: The removable flag is not set\n");
 	else if (gcw.packet_size != 0) {
-		printk (KERN_ERR "ide-tape: Packet size is not 12 bytes long\n");
+		printk(KERN_ERR "ide-tape: Packet size is not 12 bytes long\n");
 		if (gcw.packet_size == 1)
-			printk (KERN_ERR "ide-tape: Sorry, padding to 16 bytes is still not supported\n");
+			printk(KERN_ERR "ide-tape: Sorry, padding to 16 bytes is still not supported\n");
 	} else
 		return 1;
 	return 0;
@@ -5672,8 +5937,8 @@
 	pc.buffer[4 + 5] = vendor[3];
 	pc.buffer[4 + 6] = 0;
 	pc.buffer[4 + 7] = 0;
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: Couldn't set vendor name to %s\n", vendor);
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: Couldn't set vendor name to %s\n", vendor);
 
 }
 
@@ -5694,8 +5959,8 @@
 	pc.buffer[4 + 1] = 2;
 	pc.buffer[4 + 2] = 4;
 	pc.buffer[4 + 3] = retries;
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: Couldn't set retries to %d\n", retries);
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: Couldn't set retries to %d\n", retries);
 }
 #endif
 
@@ -5711,9 +5976,9 @@
 	/*
 	 * Get the current block size from the block size mode page
 	 */
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_BLOCK_SIZE_PAGE);
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: can't get tape block size mode page\n");
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_SIZE_PAGE);
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: can't get tape block size mode page\n");
 	header = (idetape_mode_parameter_header_t *) pc.buffer;
 	bs = (idetape_block_size_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
 
@@ -5733,8 +5998,8 @@
 	bs->record32 = 0;
 	bs->record32_5 = 1;
 	idetape_create_mode_select_cmd(&pc, sizeof(*header) + sizeof(*bs));
-	if (idetape_queue_pc_tail (drive, &pc))
-		printk (KERN_ERR "ide-tape: Couldn't set tape block size mode page\n");
+	if (idetape_queue_pc_tail(drive, &pc))
+		printk(KERN_ERR "ide-tape: Couldn't set tape block size mode page\n");
 
 #if ONSTREAM_DEBUG
 	/*
@@ -5756,8 +6021,8 @@
 	idetape_inquiry_result_t *inquiry;
 	
 	idetape_create_inquiry_cmd(&pc);
-	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name);
+	if (idetape_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name);
 		return;
 	}
 	inquiry = (idetape_inquiry_result_t *) pc.buffer;
@@ -5809,9 +6074,9 @@
 	idetape_mode_parameter_header_t *header;
 	onstream_tape_paramtr_page_t *prm;
 	
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_PARAMTR_PAGE);
-	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: Can't get tape parameters page - probably no tape inserted in onstream drive\n");
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_PARAMTR_PAGE);
+	if (idetape_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-tape: Can't get tape parameters page - probably no tape inserted in onstream drive\n");
 		return;
 	}
 	header = (idetape_mode_parameter_header_t *) pc.buffer;
@@ -5819,7 +6084,7 @@
 
         tape->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
         if (debug) {
-	    printk (KERN_INFO "ide-tape: %s <-> %s: Tape length %dMB (%d frames/track, %d tracks = %d blocks, density: %dKbpi)\n",
+	    printk(KERN_INFO "ide-tape: %s <-> %s: Tape length %dMB (%d frames/track, %d tracks = %d blocks, density: %dKbpi)\n",
                drive->name, tape->name, tape->capacity/32, ntohs(prm->segtrk), ntohs(prm->trks), tape->capacity, prm->density);
         }
 
@@ -5838,20 +6103,22 @@
 	idetape_mode_parameter_header_t *header;
 	idetape_capabilities_page_t *capabilities;
 	
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_CAPABILITIES_PAGE);
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_CAPABILITIES_PAGE);
 	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: Can't get tape parameters - assuming some default values\n");
-		tape->tape_block_size = 512; tape->capabilities.ctl = 52;
-		tape->capabilities.speed = 450; tape->capabilities.buffer_size = 6 * 52;
+		printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming some default values\n");
+		tape->tape_block_size = 512;
+		tape->capabilities.ctl = 52;
+		tape->capabilities.speed = 450;
+		tape->capabilities.buffer_size = 6 * 52;
 		return;
 	}
 	header = (idetape_mode_parameter_header_t *) pc.buffer;
 	capabilities = (idetape_capabilities_page_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t) + header->bdl);
 
-	capabilities->max_speed = ntohs (capabilities->max_speed);
-	capabilities->ctl = ntohs (capabilities->ctl);
-	capabilities->speed = ntohs (capabilities->speed);
-	capabilities->buffer_size = ntohs (capabilities->buffer_size);
+	capabilities->max_speed = ntohs(capabilities->max_speed);
+	capabilities->ctl = ntohs(capabilities->ctl);
+	capabilities->speed = ntohs(capabilities->speed);
+	capabilities->buffer_size = ntohs(capabilities->buffer_size);
 
 	if (!capabilities->speed) {
 		printk(KERN_INFO "ide-tape: %s: overriding capabilities->speed (assuming 650KB/sec)\n", drive->name);
@@ -5871,33 +6138,33 @@
 		tape->tape_block_size = 32768;
 
 #if IDETAPE_DEBUG_INFO
-	printk (KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n");
-	printk (KERN_INFO "ide-tape: Mode Parameter Header:\n");
-	printk (KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length);
-	printk (KERN_INFO "ide-tape: Medium Type - %d\n",header->medium_type);
-	printk (KERN_INFO "ide-tape: Device Specific Parameter - %d\n",header->dsp);
-	printk (KERN_INFO "ide-tape: Block Descriptor Length - %d\n",header->bdl);
+	printk(KERN_INFO "ide-tape: Dumping the results of the MODE SENSE packet command\n");
+	printk(KERN_INFO "ide-tape: Mode Parameter Header:\n");
+	printk(KERN_INFO "ide-tape: Mode Data Length - %d\n",header->mode_data_length);
+	printk(KERN_INFO "ide-tape: Medium Type - %d\n",header->medium_type);
+	printk(KERN_INFO "ide-tape: Device Specific Parameter - %d\n",header->dsp);
+	printk(KERN_INFO "ide-tape: Block Descriptor Length - %d\n",header->bdl);
 	
-	printk (KERN_INFO "ide-tape: Capabilities and Mechanical Status Page:\n");
-	printk (KERN_INFO "ide-tape: Page code - %d\n",capabilities->page_code);
-	printk (KERN_INFO "ide-tape: Page length - %d\n",capabilities->page_length);
-	printk (KERN_INFO "ide-tape: Read only - %s\n",capabilities->ro ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports error correction - %s\n",capabilities->ecc ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Supports 32768 bytes block size / Restricted byte count for PIO transfers - %s\n",capabilities->blk32768 ? "Yes":"No");
-	printk (KERN_INFO "ide-tape: Maximum supported speed in KBps - %d\n",capabilities->max_speed);
-	printk (KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl);
-	printk (KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed);	
-	printk (KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512);
+	printk(KERN_INFO "ide-tape: Capabilities and Mechanical Status Page:\n");
+	printk(KERN_INFO "ide-tape: Page code - %d\n",capabilities->page_code);
+	printk(KERN_INFO "ide-tape: Page length - %d\n",capabilities->page_length);
+	printk(KERN_INFO "ide-tape: Read only - %s\n",capabilities->ro ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports reverse space - %s\n",capabilities->sprev ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports erase initiated formatting - %s\n",capabilities->efmt ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports QFA two Partition format - %s\n",capabilities->qfa ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports locking the medium - %s\n",capabilities->lock ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: The volume is currently locked - %s\n",capabilities->locked ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: The device defaults in the prevent state - %s\n",capabilities->prevent ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports ejecting the medium - %s\n",capabilities->eject ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports error correction - %s\n",capabilities->ecc ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports data compression - %s\n",capabilities->cmprs ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports 512 bytes block size - %s\n",capabilities->blk512 ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports 1024 bytes block size - %s\n",capabilities->blk1024 ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Supports 32768 bytes block size / Restricted byte count for PIO transfers - %s\n",capabilities->blk32768 ? "Yes":"No");
+	printk(KERN_INFO "ide-tape: Maximum supported speed in KBps - %d\n",capabilities->max_speed);
+	printk(KERN_INFO "ide-tape: Continuous transfer limits in blocks - %d\n",capabilities->ctl);
+	printk(KERN_INFO "ide-tape: Current speed in KBps - %d\n",capabilities->speed);	
+	printk(KERN_INFO "ide-tape: Buffer size - %d\n",capabilities->buffer_size*512);
 #endif /* IDETAPE_DEBUG_INFO */
 }
 
@@ -5913,9 +6180,9 @@
 	idetape_mode_parameter_header_t *header;
 	idetape_parameter_block_descriptor_t *block_descrp;
 	
-	idetape_create_mode_sense_cmd (&pc, IDETAPE_BLOCK_DESCRIPTOR);
-	if (idetape_queue_pc_tail (drive, &pc)) {
-		printk (KERN_ERR "ide-tape: Can't get block descriptor\n");
+	idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR);
+	if (idetape_queue_pc_tail(drive, &pc)) {
+		printk(KERN_ERR "ide-tape: Can't get block descriptor\n");
 		if (tape->tape_block_size == 0) {
 			printk(KERN_WARNING "ide-tape: Cannot deal with zero block size, assume 32k\n");
 			tape->tape_block_size =  32768;
@@ -5926,9 +6193,10 @@
 	block_descrp = (idetape_parameter_block_descriptor_t *) (pc.buffer + sizeof(idetape_mode_parameter_header_t));
 	tape->tape_block_size =( block_descrp->length[0]<<16) + (block_descrp->length[1]<<8) + block_descrp->length[2];
 #if IDETAPE_DEBUG_INFO
-	printk (KERN_INFO "ide-tape: Adjusted block size - %d\n", tape->tape_block_size);
+	printk(KERN_INFO "ide-tape: Adjusted block size - %d\n", tape->tape_block_size);
 #endif /* IDETAPE_DEBUG_INFO */
 }
+
 static void idetape_add_settings (ide_drive_t *drive)
 {
 	idetape_tape_t *tape = drive->driver_data;
@@ -5984,29 +6252,24 @@
 	int stage_size;
 	struct sysinfo si;
 
-	memset (tape, 0, sizeof (idetape_tape_t));
+	memset(tape, 0, sizeof (idetape_tape_t));
 	spin_lock_init(&tape->spinlock);
 	drive->driver_data = tape;
-	drive->ready_stat = 0;			/* An ATAPI device ignores DRDY */
+	/* An ATAPI device ignores DRDY */
+	drive->ready_stat = 0;
 	if (strstr(drive->id->model, "OnStream DI-"))
 		tape->onstream = 1;
-	drive->dsc_overlap = 1;
-#ifdef CONFIG_BLK_DEV_IDEPCI
-	if (!tape->onstream && HWIF(drive)->pci_dev != NULL) {
-		/*
-		 * These two ide-pci host adapters appear to need DSC overlap disabled.
-		 * This probably needs further analysis.
-		 */
-		if ((HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) ||
-		    (HWIF(drive)->pci_dev->device == PCI_DEVICE_ID_TTI_HPT343)) {
-			printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n", tape->name);
-		    	drive->dsc_overlap = 0;
-		}
+	drive->dsc_overlap = (HWIF(drive)->no_dsc) ? 0 : 1;
+	if (HWIF(drive)->no_dsc) {
+		printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n",
+			tape->name);
+		drive->dsc_overlap = 0;
 	}
-#endif /* CONFIG_BLK_DEV_IDEPCI */
 	tape->drive = drive;
 	tape->minor = minor;
-	tape->name[0] = 'h'; tape->name[1] = 't'; tape->name[2] = '0' + minor;
+	tape->name[0] = 'h';
+	tape->name[1] = 't';
+	tape->name[2] = '0' + minor;
 	tape->chrdev_direction = idetape_direction_none;
 	tape->pc = tape->pc_stack;
 	tape->max_insert_speed = 10000;
@@ -6044,7 +6307,7 @@
 	 *	Select the "best" DSC read/write polling frequency
 	 *	and pipeline size.
 	 */
-	speed = IDE_MAX (tape->capabilities.speed, tape->capabilities.max_speed);
+	speed = IDE_MAX(tape->capabilities.speed, tape->capabilities.max_speed);
 
 	tape->max_stages = speed * 1000 * 10 / tape->stage_size;
 
@@ -6052,7 +6315,7 @@
 	 * 	Limit memory use for pipeline to 10% of physical memory
 	 */
 	si_meminfo(&si);
-	if ( tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10)
+	if (tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10)
 		tape->max_stages = si.totalram * si.mem_unit / (10 * tape->stage_size);
 	tape->min_pipeline = tape->max_stages;
 	tape->max_pipeline = tape->max_stages * 2;
@@ -6070,11 +6333,15 @@
 	 *	Ensure that the number we got makes sense; limit
 	 *	it within IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX.
 	 */
-	tape->best_dsc_rw_frequency = IDE_MAX (IDE_MIN (t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN);
-	printk (KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, %dkB pipeline, %lums tDSC%s\n",
-		drive->name, tape->name, tape->capabilities.speed, (tape->capabilities.buffer_size * 512) / tape->stage_size,
-		tape->stage_size / 1024, tape->max_stages * tape->stage_size / 1024,
-		tape->best_dsc_rw_frequency * 1000 / HZ, drive->using_dma ? ", DMA":"");
+	tape->best_dsc_rw_frequency = IDE_MAX(IDE_MIN(t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN);
+	printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, "
+		"%dkB pipeline, %lums tDSC%s\n",
+		drive->name, tape->name, tape->capabilities.speed,
+		(tape->capabilities.buffer_size * 512) / tape->stage_size,
+		tape->stage_size / 1024,
+		tape->max_stages * tape->stage_size / 1024,
+		tape->best_dsc_rw_frequency * 1000 / HZ,
+		drive->using_dma ? ", DMA":"");
 
 	idetape_add_settings(drive);
 }
@@ -6085,24 +6352,24 @@
 	int minor = tape->minor;
 	unsigned long flags;
 
-	save_flags (flags);	/* all CPUs (overkill?) */
-	cli();			/* all CPUs (overkill?) */
-	if (test_bit (IDETAPE_BUSY, &tape->flags) || tape->first_stage != NULL || tape->merge_stage_size || drive->usage) {
-		restore_flags(flags);	/* all CPUs (overkill?) */
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (test_bit(IDETAPE_BUSY, &tape->flags) || drive->usage ||
+	    tape->first_stage != NULL || tape->merge_stage_size) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return 1;
 	}
 	idetape_chrdevs[minor].drive = NULL;
-	restore_flags (flags);	/* all CPUs (overkill?) */
+	spin_unlock_irqrestore(&io_request_lock, flags);
 	DRIVER(drive)->busy = 0;
-	(void) ide_unregister_subdriver (drive);
+	(void) ide_unregister_subdriver(drive);
 	drive->driver_data = NULL;
-	devfs_unregister (tape->de_r);
-	devfs_unregister (tape->de_n);
-	kfree (tape);
+	devfs_unregister(tape->de_r);
+	devfs_unregister(tape->de_n);
+	kfree(tape);
 	for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++)
 		if (idetape_chrdevs[minor].drive != NULL)
 			return 0;
-	devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
+	devfs_unregister_chrdev(IDETAPE_MAJOR, "ht");
 	idetape_chrdev_present = 0;
 	return 0;
 }
@@ -6132,7 +6399,8 @@
 
 #endif
 
-int idetape_reinit(ide_drive_t *drive);
+int idetape_init (void);
+int idetape_attach(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -6142,13 +6410,21 @@
 	version:		IDETAPE_VERSION,
 	media:			ide_tape,
 	busy:			1,
+#ifdef CONFIG_IDEDMA_ONLYDISK
+	supports_dma:		0,
+#else
 	supports_dma:		1,
+#endif
 	supports_dsc_overlap: 	1,
 	cleanup:		idetape_cleanup,
 	standby:		NULL,
+	suspend:		NULL,
+	resume:			NULL,
 	flushcache:		NULL,
 	do_request:		idetape_do_request,
 	end_request:		idetape_end_request,
+	sense:			NULL,
+	error:			NULL,
 	ioctl:			idetape_blkdev_ioctl,
 	open:			idetape_blkdev_open,
 	release:		idetape_blkdev_release,
@@ -6156,13 +6432,14 @@
 	revalidate:		NULL,
 	pre_reset:		idetape_pre_reset,
 	capacity:		NULL,
+	special:		NULL,
 	proc:			idetape_proc,
-	reinit:			idetape_reinit,
+	init:			idetape_init,
+	attach:			idetape_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 };
 
-int idetape_init (void);
 static ide_module_t idetape_module = {
 	IDE_DRIVER_MODULE,
 	idetape_init,
@@ -6182,90 +6459,62 @@
 	release:	idetape_chrdev_release,
 };
 
-int idetape_reinit (ide_drive_t *drive)
+int idetape_attach (ide_drive_t *drive)
 {
-#if 0
 	idetape_tape_t *tape;
-	int minor, failed = 0, supported = 0;
-/* DRIVER(drive)->busy++; */
+	int minor = 0, ret = 0;
+
 	MOD_INC_USE_COUNT;
-#if ONSTREAM_DEBUG
-        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
-#endif
-	if (!idetape_chrdev_present)
-		for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
-			idetape_chrdevs[minor].drive = NULL;
 
-	if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) {
-		ide_register_module (&idetape_module);
-		MOD_DEC_USE_COUNT;
-#if ONSTREAM_DEBUG
-		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
-#endif
-		return 0;
-	}
-	if (!idetape_chrdev_present &&
-	    devfs_register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) {
-		printk (KERN_ERR "ide-tape: Failed to register character device interface\n");
-		MOD_DEC_USE_COUNT;
-#if ONSTREAM_DEBUG
-		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
-#endif
-		return -EBUSY;
-	}
-	do {
-		if (!idetape_identify_device (drive, drive->id)) {
-			printk (KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
-			continue;
-		}
-		if (drive->scsi) {
-			if (strstr(drive->id->model, "OnStream DI-30")) {
-				printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model);
-			} else {
-				printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
-				continue;
-			}
-		}
-		tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
-		if (tape == NULL) {
-			printk (KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
-			continue;
-		}
-		if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) {
-			printk (KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
-			kfree (tape);
-			continue;
-		}
-		for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
-		idetape_setup (drive, tape, minor);
-		idetape_chrdevs[minor].drive = drive;
-		tape->de_r =
-		    devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
+	if (!idetape_identify_device(drive, drive->id)) {
+		printk(KERN_ERR "ide-tape: %s: not supported by this "
+			"version of ide-tape\n", drive->name);
+			ret = 1;
+			goto bye_game_over;
+	}
+	if (drive->scsi) {
+		if (strstr(drive->id->model, "OnStream DI-30")) {
+			printk("ide-tape: ide-scsi emulation is not "
+				"supported for %s.\n", drive->id->model);
+		} else {
+			printk("ide-tape: passing drive %s to ide-scsi "
+				"emulation.\n", drive->name);
+			ret = 1;
+			goto bye_game_over;
+		}
+	}
+	tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
+	if (tape == NULL) {
+		printk(KERN_ERR "ide-tape: %s: Can't allocate a "
+			"tape structure\n", drive->name);
+		ret = 1;
+		goto bye_game_over;
+	}
+	if (ide_register_subdriver(drive,
+			&idetape_driver, IDE_SUBDRIVER_VERSION)) {
+		printk(KERN_ERR "ide-tape: %s: Failed to register the "
+				"driver with ide.c\n", drive->name);
+		kfree(tape);
+		ret = 1;
+		goto bye_game_over;
+	}
+	for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
+	idetape_setup (drive, tape, minor);
+	idetape_chrdevs[minor].drive = drive;
+	tape->de_r = devfs_register(drive->de, "mt", DEVFS_FL_DEFAULT,
 				    HWIF(drive)->major, minor,
 				    S_IFCHR | S_IRUGO | S_IWUGO,
 				    &idetape_fops, NULL);
-		tape->de_n =
-		    devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
+	tape->de_n = devfs_register(drive->de, "mtn", DEVFS_FL_DEFAULT,
 				    HWIF(drive)->major, minor + 128,
 				    S_IFCHR | S_IRUGO | S_IWUGO,
 				    &idetape_fops, NULL);
-		devfs_register_tape (tape->de_r);
-		supported++; failed--;
-	} while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL);
-	if (!idetape_chrdev_present && !supported) {
-		devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
-	} else
-		idetape_chrdev_present = 1;
-	ide_register_module (&idetape_module);
+	devfs_register_tape(tape->de_r);
+
+bye_game_over:
 	MOD_DEC_USE_COUNT;
-#if ONSTREAM_DEBUG
-	printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
-#endif
 
-	return 0;
-#else
-	return 1;
-#endif
+	return ret;
 }
 
 MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver");
@@ -6278,94 +6527,118 @@
 
 	for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++) {
 		drive = idetape_chrdevs[minor].drive;
-		if (drive != NULL && idetape_cleanup (drive))
-		printk (KERN_ERR "ide-tape: %s: cleanup_module() called while still busy\n", drive->name);
+		if (drive != NULL && idetape_cleanup(drive))
+			printk(KERN_ERR "ide-tape: %s: cleanup_module() "
+				"called while still busy\n", drive->name);
 	}
+#ifdef CONFIG_PROC_FS
+	if (drive->proc)
+		ide_remove_proc_entries(drive->proc, idetape_proc);
+#endif
+
 	ide_unregister_module(&idetape_module);
 }
 
-/*
- *	idetape_init will register the driver for each tape.
- */
 int idetape_init (void)
 {
+#ifdef CLASSIC_BUILTINS_METHOD
 	ide_drive_t *drive;
 	idetape_tape_t *tape;
 	int minor, failed = 0, supported = 0;
 /* DRIVER(drive)->busy++; */
 	MOD_INC_USE_COUNT;
 #if ONSTREAM_DEBUG
-        printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
+	printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_init\n");
 #endif
 	if (!idetape_chrdev_present)
 		for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
 			idetape_chrdevs[minor].drive = NULL;
-
-	if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) {
-		ide_register_module (&idetape_module);
+	if ((drive = ide_scan_devices(ide_tape, idetape_driver.name,
+			NULL, failed++)) == NULL) {
+		ide_register_module(&idetape_module);
 		MOD_DEC_USE_COUNT;
 #if ONSTREAM_DEBUG
-		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in "
+			"idetape_init\n");
 #endif
 		return 0;
 	}
 	if (!idetape_chrdev_present &&
-	    devfs_register_chrdev (IDETAPE_MAJOR, "ht", &idetape_fops)) {
-		printk (KERN_ERR "ide-tape: Failed to register character device interface\n");
+	    devfs_register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) {
+		printk(KERN_ERR "ide-tape: Failed to register character "
+			"device interface\n");
 		MOD_DEC_USE_COUNT;
 #if ONSTREAM_DEBUG
-		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
+		printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in "
+			"idetape_init\n");
 #endif
 		return -EBUSY;
 	}
 	do {
-		if (!idetape_identify_device (drive, drive->id)) {
-			printk (KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name);
+		if (!idetape_identify_device(drive, drive->id)) {
+			printk(KERN_ERR "ide-tape: %s: not supported by this "
+				"version of ide-tape\n", drive->name);
 			continue;
 		}
 		if (drive->scsi) {
 			if (strstr(drive->id->model, "OnStream DI-")) {
-				printk("ide-tape: ide-scsi emulation is not supported for %s.\n", drive->id->model);
+				printk("ide-tape: ide-scsi emulation is not "
+					"supported for %s.\n",
+					drive->id->model);
 			} else {
-				printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name);
+				printk("ide-tape: passing drive %s to "
+					"ide-scsi emulation.\n", drive->name);
 				continue;
 			}
 		}
 		tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
 		if (tape == NULL) {
-			printk (KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name);
+			printk(KERN_ERR "ide-tape: %s: Can't allocate a tape "
+				"structure\n", drive->name);
 			continue;
 		}
-		if (ide_register_subdriver (drive, &idetape_driver, IDE_SUBDRIVER_VERSION)) {
-			printk (KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
-			kfree (tape);
+		if (ide_register_subdriver(drive,
+				&idetape_driver, IDE_SUBDRIVER_VERSION)) {
+			printk(KERN_ERR "ide-tape: %s: Failed to register the "
+				"driver with ide.c\n", drive->name);
+			kfree(tape);
 			continue;
 		}
 		for (minor = 0; idetape_chrdevs[minor].drive != NULL; minor++);
-		idetape_setup (drive, tape, minor);
+		idetape_setup(drive, tape, minor);
 		idetape_chrdevs[minor].drive = drive;
 		tape->de_r =
-		    devfs_register (drive->de, "mt", DEVFS_FL_DEFAULT,
+		    devfs_register(drive->de, "mt", DEVFS_FL_DEFAULT,
 				    HWIF(drive)->major, minor,
 				    S_IFCHR | S_IRUGO | S_IWUGO,
 				    &idetape_fops, NULL);
 		tape->de_n =
-		    devfs_register (drive->de, "mtn", DEVFS_FL_DEFAULT,
+		    devfs_register(drive->de, "mtn", DEVFS_FL_DEFAULT,
 				    HWIF(drive)->major, minor + 128,
 				    S_IFCHR | S_IRUGO | S_IWUGO,
 				    &idetape_fops, NULL);
-		devfs_register_tape (tape->de_r);
-		supported++; failed--;
-	} while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL);
+		devfs_register_tape(tape->de_r);
+		supported++;
+		failed--;
+	} while ((drive = ide_scan_devices(ide_tape,
+			idetape_driver.name, NULL, failed++)) != NULL);
 	if (!idetape_chrdev_present && !supported) {
-		devfs_unregister_chrdev (IDETAPE_MAJOR, "ht");
+		devfs_unregister_chrdev(IDETAPE_MAJOR, "ht");
 	} else
 		idetape_chrdev_present = 1;
-	ide_register_module (&idetape_module);
+#else /* ! CLASSIC_BUILTINS_METHOD */
+	int minor = 0;
+
+	if (idetape_chrdev_present)
+		return 0;
+	idetape_chrdev_present = 1;
+	for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ )
+		idetape_chrdevs[minor].drive = NULL;
+	devfs_register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops);
+	MOD_INC_USE_COUNT;
+#endif /* CLASSIC_BUILTINS_METHOD */
+	ide_register_module(&idetape_module);
 	MOD_DEC_USE_COUNT;
-#if ONSTREAM_DEBUG
-	printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_init\n");
-#endif
 	return 0;
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ide-taskfile.c linux.20pre10-ac2/drivers/ide/ide-taskfile.c
--- linux.20pre10/drivers/ide/ide-taskfile.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ide-taskfile.c	2002-09-18 20:33:50.000000000 +0100
@@ -1,12 +1,29 @@
 /*
- * linux/drivers/ide/ide-taskfile.c	Version 0.20	Oct 11, 2000
+ * linux/drivers/ide/ide-taskfile.c	Version 0.33	April 11, 2002
  *
- *  Copyright (C) 2000		Michael Cornwell <cornwell@acm.org>
- *  Copyright (C) 2000		Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 2000-2002	Michael Cornwell <cornwell@acm.org>
+ *  Copyright (C) 2000-2002	Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 2001-2002	Klaus Smolin
+ *					IBM Storage Technology Division
  *
- *  May be copied or modified under the terms of the GNU General Public License
+ *  The big the bad and the ugly.
  *
- * IDE_DEBUG(__LINE__);
+ *  Problems to be fixed because of BH interface or the lack therefore.
+ *
+ *  Fill me in stupid !!!
+ *
+ *  HOST:
+ *	General refers to the Controller and Driver "pair".
+ *  DATA HANDLER:
+ *	Under the context of Linux it generally refers to an interrupt handler.
+ *	However, it correctly describes the 'HOST'
+ *  DATA BLOCK:
+ *	The amount of data needed to be transfered as predefined in the
+ *	setup of the device.
+ *  STORAGE ATOMIC:
+ *	The 'DATA BLOCK' associated to the 'DATA HANDLER', and can be as
+ *	small as a single sector or as large as the entire command block
+ *	request.
  */
 
 #include <linux/config.h>
@@ -34,27 +51,50 @@
 #include <asm/io.h>
 #include <asm/bitops.h>
 
-#ifdef CONFIG_IDE_TASKFILE_IO
-#  define __TASKFILE__IO
-#else /* CONFIG_IDE_TASKFILE_IO */
-#  undef __TASKFILE__IO
-#endif /* CONFIG_IDE_TASKFILE_IO */
-
 #define DEBUG_TASKFILE	0	/* unset when fixed */
 
 #if DEBUG_TASKFILE
-#define DTF(x...) printk(##x)
+#define DTF(x...) printk(x)
 #else
 #define DTF(x...)
 #endif
 
+/*
+ *
+ */
+#define task_rq_offset(rq) \
+	(((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE)
+
+/*
+ * for now, taskfile requests are special :/
+ *
+ * However, upon the creation of the atapi version of packet_command
+ * data-phase ISR plus it own diagnostics and extensions for direct access
+ * (ioctl,read,write,rip,stream -- atapi), the kmap/kunmap for PIO will
+ * come localized.
+ */
+inline char *task_map_rq (struct request *rq, unsigned long *flags)
+{
+	if (rq->bh)
+		return ide_map_buffer(rq, flags);
+	return rq->buffer + task_rq_offset(rq);
+}
+
+inline void task_unmap_rq (struct request *rq, char *buf, unsigned long *flags)
+{
+	if (rq->bh)
+		ide_unmap_buffer(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;
@@ -65,381 +105,178 @@
 	}
 }
 
-#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) inb (port);
-	(void) inb (port);
-	(void) inb (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 = drive->io_32bit;
-
-	if (io_32bit) {
-#if SUPPORT_VLB_SYNC
-		if (io_32bit & 2) {
-			unsigned long flags;
-			__save_flags(flags);	/* local CPU only */
-			__cli();		/* local CPU only */
-			task_vlb_sync(IDE_NSECTOR_REG);
-			insl(IDE_DATA_REG, buffer, wcount);
-			__restore_flags(flags);	/* local CPU only */
-		} 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 = drive->io_32bit;
-
-	if (io_32bit) {
-#if SUPPORT_VLB_SYNC
-		if (io_32bit & 2) {
-			unsigned long flags;
-			__save_flags(flags);	/* local CPU only */
-			__cli();		/* local CPU only */
-			task_vlb_sync(IDE_NSECTOR_REG);
-			outsl(IDE_DATA_REG, buffer, wcount);
-			__restore_flags(flags);	/* local CPU only */
-		} 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);
-	}
-}
-
 
-static inline 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);
 }
 
-static inline 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);
 	}
 }
 
-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) ? 0xE0 : 0xEF;
-
-	/* (ks/hs): Moved to start, do not use for multiple out commands */
-	if (task->handler != task_mulout_intr) {
-		if (IDE_CONTROL_REG)
-			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
-		SELECT_MASK(HWIF(drive), drive, 0);
-	}
-
-	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);
-	if (task->handler != NULL) {
-#if 0
-		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
-		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-		/*
-		 * warning check for race between handler and prehandler for
-		 * writing first block of data.  however since we are well
-		 * inside the boundaries of the seek, we should be okay.
-		 */
-		if (task->prehandler != NULL) {
-			return task->prehandler(drive, task->rq);
-		}
-#else
-		ide_startstop_t startstop;
-
-		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
-		OUT_BYTE(taskfile->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;
-		}
-		/* (ks/hs): Fixed Multi Write */
-		if ((taskfile->command != WIN_MULTWRITE) &&
-		    (taskfile->command != WIN_MULTWRITE_EXT)) {
-			struct request *rq = HWGROUP(drive)->rq;
-		/* For Write_sectors we need to stuff the first sector */
-			taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
-			rq->current_nr_sectors--;
-		} else {
-		/* Stuff first sector(s) by implicitly calling the handler */
-			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;
-				}
-			}
-			return task->handler(drive);
-		}
-#endif
-	} else {
-		/* 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)));
-	}
-
-	return ide_started;
-}
+EXPORT_SYMBOL(taskfile_output_data);
 
-void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler)
+int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf)
 {
-	struct hd_driveid *id = drive->id;
-	byte HIHI = (drive->addressing) ? 0xE0 : 0xEF;
-
-	/* (ks/hs): Moved to start, do not use for multiple out commands */
-	if (*handler != task_mulout_intr) {
-		if (IDE_CONTROL_REG)
-			OUT_BYTE(drive->ctl, IDE_CONTROL_REG);  /* clear nIEN */
-		SELECT_MASK(HWIF(drive), drive, 0);
-	}
-
-	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);
-	}
+	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);
+}
 
-	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);
+EXPORT_SYMBOL(taskfile_lib_get_identify);
 
-	OUT_BYTE((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
-	if (handler != NULL) {
-		ide_set_handler (drive, handler, WAIT_CMD, NULL);
-		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-	} else {
-		/* 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)));
-	}
+#ifdef CONFIG_IDE_TASK_IOCTL_DEBUG
+void debug_taskfile (ide_drive_t *drive, ide_task_t *args)
+{
+	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]);
+	printk("TF.2=x%02x ", args->tfRegister[IDE_NSECTOR_OFFSET]);
+	printk("TF.3=x%02x ", args->tfRegister[IDE_SECTOR_OFFSET]);
+	printk("TF.4=x%02x ", args->tfRegister[IDE_LCYL_OFFSET]);
+	printk("TF.5=x%02x ", args->tfRegister[IDE_HCYL_OFFSET]);
+	printk("TF.6=x%02x ", args->tfRegister[IDE_SELECT_OFFSET]);
+	printk("TF.7=x%02x\n", args->tfRegister[IDE_COMMAND_OFFSET]);
+	printk(KERN_INFO "%s: ", drive->name);
+//	printk("HTF.0=x%02x ", args->hobRegister[IDE_DATA_OFFSET_HOB]);
+	printk("HTF.1=x%02x ", args->hobRegister[IDE_FEATURE_OFFSET_HOB]);
+	printk("HTF.2=x%02x ", args->hobRegister[IDE_NSECTOR_OFFSET_HOB]);
+	printk("HTF.3=x%02x ", args->hobRegister[IDE_SECTOR_OFFSET_HOB]);
+	printk("HTF.4=x%02x ", args->hobRegister[IDE_LCYL_OFFSET_HOB]);
+	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 */
 
-#if 0
-ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
+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;
-
-	/*
-	 * (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);
-		}
-        }
-
-	if (IDE_CONTROL_REG)
-		OUT_BYTE(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */
-	SELECT_MASK(HWIF(drive), drive, 0);
-
-	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);
+	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 */
 
-	/* (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);
+	/* 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);
+
+	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);
 
-        /*
-	 * (KS) Do not modify the specified taskfile. We want to have a
-	 * universal pass through, so we must execute ALL specified values.
-	 *
-	 * (KS) The drive head register is mandatory.
-	 * Don't care about the out flags !
-	 */
-	OUT_BYTE(taskfile->device_head | drive->select.all, IDE_SELECT_REG);
+	hwif->OUTB((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
 	if (task->handler != NULL) {
-#if 0
-		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
-		OUT_BYTE(taskfile->command, IDE_COMMAND_REG);
-		/*
-		 * warning check for race between handler and prehandler for
-		 * writing first block of data.  however since we are well
-		 * inside the boundaries of the seek, we should be okay.
-		 */
-		if (task->prehandler != NULL) {
+		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);
-		}
-#else
-		ide_startstop_t startstop;
-
-		ide_set_handler (drive, task->handler, WAIT_CMD, NULL);
-
-		/*
-		 * (KS) The drive command register is also mandatory.
-		 * Don't care about the out flags !
-		 */
-		OUT_BYTE(taskfile->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;
-		}
-		/* (ks/hs): Fixed Multi Write */
-		if ((taskfile->command != WIN_MULTWRITE) &&
-		    (taskfile->command != WIN_MULTWRITE_EXT)) {
-			struct request *rq = HWGROUP(drive)->rq;
-		/* For Write_sectors we need to stuff the first sector */
-			taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
-			rq->current_nr_sectors--;
+		return ide_started;
+	}
+	/* for dma commands we down set the handler */
+#if 0
+	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;
 		} else {
-		/* Stuff first sector(s) by implicitly calling the handler */
-			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;
-				}
-			}
-			return task->handler(drive);
+			if (hwif->ide_dma_write(drive))
+				return ide_stopped;
 		}
-#endif
 	} else {
-		/* 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)));
-	}
+		if (!drive->using_dma && (task->handler == NULL))
+			return ide_stopped;
 
+		switch(taskfile->command) {
+			case WIN_WRITEDMA_ONCE:
+			case WIN_WRITEDMA:
+			case WIN_WRITEDMA_EXT:
+				hwif->ide_dma_write(drive);
+				break;
+			case WIN_READDMA_ONCE:
+			case WIN_READDMA:
+			case WIN_READDMA_EXT:
+			case WIN_IDENTIFY_DMA:
+				hwif->ide_dma_read(drive);
+				break;
+			default:
+				if (task->handler == NULL)
+					return ide_stopped;
+		}
+	}
 	return ide_started;
-}
+#else
+	switch(taskfile->command) {
+		case WIN_WRITEDMA_ONCE:
+		case WIN_WRITEDMA:
+		case WIN_WRITEDMA_EXT:
+			if (drive->using_dma && !(hwif->ide_dma_write(drive)));
+				return ide_started;
+		case WIN_READDMA_ONCE:
+		case WIN_READDMA:
+		case WIN_READDMA_EXT:
+		case WIN_IDENTIFY_DMA:
+			if (drive->using_dma && !(hwif->ide_dma_read(drive)));
+				return ide_started;
+		default:
+			break;
+	}
+	return ide_stopped;
 #endif
+}
+
+EXPORT_SYMBOL(do_rw_taskfile);
 
-#if 0
 /*
  * 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;
 
-	__save_flags (flags);	/* local CPU only */
-	ide__sti();		/* local CPU only */
+	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 ");
@@ -452,61 +289,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=%llu", (__u64) HWGROUP(drive)->rq->sector);
 			}
+			if (HWGROUP(drive)->rq)
+				printk(", sector=%lu",
+					HWGROUP(drive)->rq->sector);
 		}
+media_out:
 #endif  /* FANCY_STATUS_DUMPS */
 		printk("\n");
 	}
-	__restore_flags (flags);	/* local CPU only */
+	local_irq_restore(flags);
 	return err;
 }
 
+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;
@@ -519,28 +361,39 @@
 
 	command = args->tfRegister[IDE_COMMAND_OFFSET];
 
-	rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
+	if (rq->errors == 0)
+		rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
 
+	if (args->tf_in_flags.b.data) {
+		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
 /*	taskfile_settings_update(drive, args, command); */
 
+	if (args->posthandler != NULL)
+		args->posthandler(drive, args);
+#endif
+
 	spin_lock_irqsave(&io_request_lock, flags);
 	blkdev_dequeue_request(rq);
 	HWGROUP(drive)->rq = NULL;
@@ -548,6 +401,8 @@
 	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
+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
@@ -565,53 +420,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) {
 		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) {
-		if (drive->driver != NULL)
-			DRIVER(drive)->end_request(0, HWGROUP(drive));
-		else
-			ide_end_request(0, HWGROUP(drive));
+		DRIVER(drive)->end_request(drive, 0);
 	} else {
 		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
 			++rq->errors;
@@ -623,20 +493,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;
@@ -646,282 +514,373 @@
 	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)
 {
-	byte stat;
+	ide_hwif_t *hwif = HWIF(drive);
+	int retries = 5;
+	u8 stat;
+
+	while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--)
+		udelay(10);
 
-	if (OK_STAT(stat=GET_STAT(),READY_STAT,BAD_STAT))
+	if (OK_STAT(stat, READY_STAT, BAD_STAT))
 		return ide_stopped;
 
 	if (stat & (ERR_STAT|DRQ_STAT))
-		return ide_error(drive, "set_geometry_intr", stat);
+		return DRIVER(drive)->error(drive, "set_geometry_intr", stat);
 
-	ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL);
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	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))
-		return ide_error(drive, "recal_intr", 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__sti();	/* local CPU only */
-
-	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
-		return ide_error(drive, "task_no_data_intr", stat); /* calls ide_end_drive_cmd */
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat;
 
+	local_irq_enable();
+	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
+ * Handler for command with PIO data-in phase, READ
+ */
+/*
+ * FIXME before 2.4 enable ...
+ *	DATA integrity issue upon error. <andre@linux-ide.org>
  */
 ide_startstop_t task_in_intr (ide_drive_t *drive)
 {
-	byte stat		= GET_STAT();
-	byte io_32bit		= drive->io_32bit;
 	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)) {
-			return ide_error(drive, "task_in_intr", stat);
+#if 0
+			DTF("%s: attempting to recover last " \
+				"sector counter status=0x%02x\n",
+				drive->name, stat);
+			/*
+			 * Expect a BUG BOMB if we attempt to rewind the
+			 * offset in the BH aka PAGE in the current BLOCK
+			 * segment.  This is different than the HOST segment.
+			 */
+#endif
+			if (!rq->bh)
+				rq->current_nr_sectors++;
+			return DRIVER(drive)->error(drive, "task_in_intr", stat);
 		}
 		if (!(stat & BUSY_STAT)) {
 			DTF("task_in_intr to Soon wait for next interrupt\n");
-			ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
+			if (HWGROUP(drive)->handler == NULL)
+				ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
 			return ide_started;  
 		}
 	}
-	DTF("stat: %02x\n", stat);
-	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-	DTF("Read: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
-
-	drive->io_32bit = 0;
-	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
-	drive->io_32bit = io_32bit;
-
-	if (--rq->current_nr_sectors <= 0) {
-		/* (hs): swapped next 2 lines */
-		DTF("Request Ended stat: %02x\n", GET_STAT());
-		ide_end_request(1, HWGROUP(drive));
-	} else {
-		ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);
-		return ide_started;
-	}
-	return ide_stopped;
-}
+#if 0
 
-#undef ALTSTAT_SCREW_UP
+	/*
+	 * Holding point for a brain dump of a thought :-/
+	 */
 
-#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;
+	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
+		DTF("%s: READ attempting to recover last " \
+			"sector counter status=0x%02x\n",
+			drive->name, stat);
+		rq->current_nr_sectors++;
+		return DRIVER(drive)->error(drive, "task_in_intr", stat);
+        }
+	if (!rq->current_nr_sectors)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
+
+	if (--rq->current_nr_sectors <= 0)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
+#endif
 
-	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;
-		}
-	}
+	pBuf = task_map_rq(rq, &flags);
+	DTF("Read: %p, rq->current_nr_sectors: %d, stat: %02x\n",
+		pBuf, (int) rq->current_nr_sectors, stat);
+	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
+	task_unmap_rq(rq, pBuf, &flags);
+	/*
+	 * 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
+	 * hwif->INB(IDE_STATUS_REG); return.
+	 */
+	if (--rq->current_nr_sectors <= 0)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
 	/*
-	 * (ks/hs): Read Status AFTER Alternate Status Register
+	 * ERM, it is techincally legal to leave/exit here but it makes
+	 * a mess of the code ...
 	 */
-	return(GET_STAT());
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
+	return ide_started;
 }
 
-/*
- * (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)
 {
-	unsigned int		msect, nsect;
-
-#ifdef ALTSTAT_SCREW_UP
-	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "read");
-#else
-	byte stat		= GET_STAT();
-#endif /* ALTSTAT_SCREW_UP */
-
-	byte io_32bit		= drive->io_32bit;
+	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)) {
-			return ide_error(drive, "task_mulin_intr", stat);
+			if (!rq->bh) {
+				rq->current_nr_sectors += drive->mult_count;
+				/*
+				 * NOTE: could rewind beyond beginning :-/
+				 */
+			} else {
+				printk("%s: MULTI-READ assume all data " \
+					"transfered is bad status=0x%02x\n",
+					drive->name, stat);
+			}
+			return DRIVER(drive)->error(drive, "task_mulin_intr", stat);
 		}
 		/* no data yet, so wait for another interrupt */
-		ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
+		if (HWGROUP(drive)->handler == NULL)
+			ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL);
 		return ide_started;
 	}
 
-	/* (ks/hs): Fixed Multi-Sector transfer */
-	msect = drive->mult_count;
-
-#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) {
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
+		pBuf = task_map_rq(rq, &flags);
+		DTF("Multiread: %p, nsect: %d, msect: %d, " \
+			" rq->current_nr_sectors: %d\n",
+			pBuf, nsect, msect, rq->current_nr_sectors);
+		taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+		task_unmap_rq(rq, pBuf, &flags);
+		rq->errors = 0;
+		rq->current_nr_sectors -= nsect;
+		msect -= nsect;
 		/*
-		 * (ks/hs): Drive supports multi-sector transfer,
-		 * drive->mult_count was not set
+		 * 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 hwif->INB(IDE_STATUS_REG); return.
 		 */
-		nsect = 1;
-		while (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);
-			drive->io_32bit = 0;
-			taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
-			drive->io_32bit = io_32bit;
-			rq->errors = 0;
-			rq->current_nr_sectors -= nsect;
-			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "read");
-		}
-		ide_end_request(1, HWGROUP(drive));
-		return ide_stopped;
-	}
-#endif /* ALTSTAT_SCREW_UP */
+		if (!rq->current_nr_sectors) {
+			if (!DRIVER(drive)->end_request(drive, 1))
+				return ide_stopped;
+		}
+	} while (msect);
+	if (HWGROUP(drive)->handler == NULL)
+		ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL);
+	return ide_started;
+}
 
-	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);
-	drive->io_32bit = 0;
-	taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
-	drive->io_32bit = io_32bit;
-	rq->errors = 0;
-	rq->current_nr_sectors -= nsect;
-	if (rq->current_nr_sectors != 0) {
-		ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
-		return ide_started;
-	}
-	ide_end_request(1, HWGROUP(drive));
-	return ide_stopped;
-}
+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.
+ */
 ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
 {
-	ide_task_t *args = rq->special;
+	char *pBuf		= NULL;
+	unsigned long flags;
 	ide_startstop_t startstop;
 
-	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");
+	if (ide_wait_stat(&startstop, drive, DATA_READY,
+			drive->bad_wstat, WAIT_DRQ)) {
+		printk(KERN_ERR "%s: no DRQ after issuing WRITE%s\n",
+			drive->name,
+			drive->addressing ? "_EXT" : "");
 		return startstop;
 	}
-
-	/* (ks/hs): Fixed Multi Write */
-	if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) &&
-	    (args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) {
-		/* For Write_sectors we need to stuff the first sector */
-		taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
-		rq->current_nr_sectors--;
-		return ide_started;
-	} else {
-		/*
-		 * (ks/hs): Stuff the first sector(s)
-		 * by implicitly calling the handler
-		 */
-		if (!(drive_is_ready(drive))) {
-			int i;
-			/*
-			 * (ks/hs): FIXME: Replace hard-coded
-			 *               100, error handling?
-			 */
-			for (i=0; i<100; i++) {
-				if (drive_is_ready(drive))
-					break;
-			}
-		}
-		return args->handler(drive);
-	}
+	/* For Write_sectors we need to stuff the first sector */
+	pBuf = task_map_rq(rq, &flags);
+	taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+	rq->current_nr_sectors--;
+	task_unmap_rq(rq, pBuf, &flags);
 	return ide_started;
 }
 
+EXPORT_SYMBOL(pre_task_out_intr);
+
 /*
- * Handler for command with PIO data-out phase
+ * Handler for command with PIO data-out phase WRITE
+ *
+ * WOOHOO this is a CORRECT STATE DIAGRAM NOW, <andre@linux-ide.org>
  */
 ide_startstop_t task_out_intr (ide_drive_t *drive)
 {
-	byte stat		= GET_STAT();
-	byte io_32bit		= drive->io_32bit;
+	ide_hwif_t *hwif	= HWIF(drive);
 	struct request *rq	= HWGROUP(drive)->rq;
 	char *pBuf		= NULL;
+	unsigned long flags;
+	u8 stat;
 
-	if (!rq->current_nr_sectors) { 
-		ide_end_request(1, HWGROUP(drive));
-		return ide_stopped;
-	}
-
-	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
-		return ide_error(drive, "task_out_intr", stat);
+	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);
+		rq->current_nr_sectors++;
+		return DRIVER(drive)->error(drive, "task_out_intr", stat);
 	}
+	/*
+	 * Safe to update request for partial completions.
+	 * We have a good STATUS CHECK!!!
+	 */
+	if (!rq->current_nr_sectors)
+		if (!DRIVER(drive)->end_request(drive, 1))
+			return ide_stopped;
 	if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {
 		rq = HWGROUP(drive)->rq;
-		pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
-		DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
-		drive->io_32bit = 0;
+		pBuf = task_map_rq(rq, &flags);
+		DTF("write: %p, rq->current_nr_sectors: %d\n",
+			pBuf, (int) rq->current_nr_sectors);
 		taskfile_output_data(drive, pBuf, SECTOR_WORDS);
-		drive->io_32bit = io_32bit;
+		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_WORSTCASE, NULL);
+	return ide_started;
+}
 
-	if (rq->current_nr_sectors <= 0) {
-		ide_end_request(1, HWGROUP(drive));
-	} else {
-		ide_set_handler(drive, &task_out_intr, WAIT_CMD, 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;
+
+#if 0
+	/*
+	 * assign private copy for multi-write
+	 */
+	memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request));
+#endif
+
+	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->addressing ? "MULTWRITE_EXT" : "MULTWRITE");
+		return startstop;
 	}
-	return ide_stopped;
+#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))
+				if (!rq->bh) {
+					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();
+#else
+	if (!(drive_is_ready(drive))) {
+		int i;
+		for (i=0; i<100; i++) {
+			if (drive_is_ready(drive))
+				break;
+		}
+	}
+#endif
+	/*
+	 * WARNING :: if the drive as not acked good status we may not
+	 * 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.
+ */
 /*
  * Handler for command write multiple
  * Called directly from execute_drive_cmd for the first bunch of sectors,
@@ -929,93 +888,119 @@
  */
 ide_startstop_t task_mulout_intr (ide_drive_t *drive)
 {
-	unsigned int		msect, nsect;
-
-#ifdef ALTSTAT_SCREW_UP
-	byte stat	= altstat_multi_busy(drive, GET_ALTSTAT(), "write");
-#else
-	byte stat		= GET_STAT();
-#endif /* ALTSTAT_SCREW_UP */
-
-	byte io_32bit		= drive->io_32bit;
-	struct request *rq	= HWGROUP(drive)->rq;
-	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
-	char *pBuf		= NULL;
+	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;
+	unsigned int msect		= drive->mult_count;
+	unsigned int nsect;
+	unsigned long flags;
 
 	/*
 	 * (ks/hs): Handle last IRQ on multi-sector transfer,
-	 * occurs after all data was sent
+	 * occurs after all data was sent in this chunk
 	 */
 	if (rq->current_nr_sectors == 0) {
-		if (stat & (ERR_STAT|DRQ_STAT))
-			return ide_error(drive, "task_mulout_intr", stat);
-		ide_end_request(1, HWGROUP(drive));
-		return ide_stopped;
+		if (stat & (ERR_STAT|DRQ_STAT)) {
+			if (!rq->bh) {
+                                rq->current_nr_sectors += drive->mult_count;
+				/*
+				 * NOTE: could rewind beyond beginning :-/
+				 */
+			} else {
+				printk("%s: MULTI-WRITE assume all data " \
+					"transfered is bad status=0x%02x\n",
+					drive->name, stat);
+			}
+			return DRIVER(drive)->error(drive, "task_mulout_intr", stat);
+		}
+		if (!rq->bh)
+			DRIVER(drive)->end_request(drive, 1);
+		return startstop;
 	}
-
+	/*
+	 * DON'T be lazy code the above and below togather !!!
+	 */
 	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
-			return ide_error(drive, "task_mulout_intr", stat);
+			if (!rq->bh) {
+				rq->current_nr_sectors += drive->mult_count;
+				/*
+				 * NOTE: could rewind beyond beginning :-/
+				 */
+			} else {
+				printk("%s: MULTI-WRITE assume all data " \
+					"transfered is bad status=0x%02x\n",
+					drive->name, stat);
+			}
+			return DRIVER(drive)->error(drive, "task_mulout_intr", stat);
 		}
 		/* no data yet, so wait for another interrupt */
-		if (hwgroup->handler == NULL)
-			ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+		if (HWGROUP(drive)->handler == NULL)
+			ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL);
 		return ide_started;
 	}
 
-	/* (ks/hs): See task_mulin_intr */
-	msect = drive->mult_count;
-
-#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 = 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);
-			drive->io_32bit = 0;
-			taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
-			drive->io_32bit = io_32bit;
-			rq->errors = 0;
-			rq->current_nr_sectors -= nsect;
-			stat = altstat_multi_poll(drive, GET_ALTSTAT(), "write");
+#ifndef ALTERNATE_STATE_DIAGRAM_MULTI_OUT
+	if (HWGROUP(drive)->handler != NULL) {
+		unsigned long lflags;
+		spin_lock_irqsave(&io_request_lock, lflags);
+		HWGROUP(drive)->handler = NULL;
+		del_timer(&HWGROUP(drive)->timer);
+		spin_unlock_irqrestore(&io_request_lock, lflags);
+	}
+#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */
+
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
+		pBuf = task_map_rq(rq, &flags);
+		DTF("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;
+		/*
+		 * 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  hwif->INB(IDE_STATUS_REG); return.
+		 */
+		if (!rq->current_nr_sectors) {
+			if (!DRIVER(drive)->end_request(drive, 1))
+				if (!rq->bh)
+					return ide_stopped;
 		}
-		ide_end_request(1, HWGROUP(drive));
-		return ide_stopped;
-	}
-#endif /* ALTSTAT_SCREW_UP */
-
-	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);
-	drive->io_32bit = 0;
-	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
-	drive->io_32bit = io_32bit;
+	} while (msect);
 	rq->errors = 0;
-	rq->current_nr_sectors -= nsect;
-	if (hwgroup->handler == NULL)
-		ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL);
+	if (HWGROUP(drive)->handler == 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:
-//		case WIN_WRITEDMA:
-//		case WIN_WRITEDMA_QUEUED:
-//		case WIN_WRITEDMA_EXT:
-//		case WIN_WRITEDMA_QUEUED_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:
 		case CFA_WRITE_SECT_WO_ERASE:
@@ -1025,13 +1010,22 @@
 		case WIN_SMART:
 			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:
+				/* IDE_DRIVE_TASK_OUT */
 		default:
 			break;
 	}
 	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) {
@@ -1040,6 +1034,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:
@@ -1051,11 +1046,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:
@@ -1074,13 +1074,16 @@
 		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;
 		case WIN_SPECIFY:
 			return &set_geometry_intr;
-		case WIN_RESTORE:
+		case WIN_RECAL:
+	//	case WIN_RESTORE:
 			return &recal_intr;
+		case WIN_NOP:
 		case WIN_DIAGNOSE:
 		case WIN_FLUSH_CACHE:
 		case WIN_FLUSH_CACHE_EXT:
@@ -1111,11 +1114,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:
@@ -1130,14 +1135,31 @@
 	}	
 }
 
+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) {
+		case WIN_SPECIFY:	/* set_geometry_intr */
+		case WIN_RESTORE:	/* recal_intr */
+		case WIN_SETMULT:	/* set_multmode_intr */
+		default:
+			return(NULL);
+	}
+}
+
+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;
 
-	args->prehandler = ide_pre_handler_parser(taskfile, hobfile);
-	args->handler = ide_handler_parser(taskfile, hobfile);
+	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);
+	args->posthandler	= ide_post_handler_parser(taskfile, hobfile);
 
 	switch(args->tfRegister[IDE_COMMAND_OFFSET]) {
 		case WIN_IDENTIFY:
@@ -1145,18 +1167,28 @@
 			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:
 			return IDE_DRIVE_TASK_RAW_WRITE;
 		case WIN_SECURITY_DISABLE:
 		case WIN_SECURITY_ERASE_UNIT:
@@ -1178,12 +1210,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:
@@ -1191,20 +1225,32 @@
 #endif
 		case WIN_SETFEATURES:
 			switch(args->tfRegister[IDE_FEATURE_OFFSET]) {
+				case SETFEATURES_EN_8BIT:
+				case SETFEATURES_EN_WCACHE:
+					return IDE_DRIVE_TASK_NO_DATA;
 				case SETFEATURES_XFER:
 					return IDE_DRIVE_TASK_SET_XFER;
 				case SETFEATURES_DIS_DEFECT:
 				case SETFEATURES_EN_APM:
 				case SETFEATURES_DIS_MSN:
+				case SETFEATURES_DIS_RETRY:
+				case SETFEATURES_EN_AAM:
+				case SETFEATURES_RW_LONG:
+				case SETFEATURES_SET_CACHE:
+				case SETFEATURES_DIS_RLA:
 				case SETFEATURES_EN_RI:
 				case SETFEATURES_EN_SI:
 				case SETFEATURES_DIS_RPOD:
 				case SETFEATURES_DIS_WCACHE:
 				case SETFEATURES_EN_DEFECT:
 				case SETFEATURES_DIS_APM:
+				case SETFEATURES_EN_ECC:
 				case SETFEATURES_EN_MSN:
+				case SETFEATURES_EN_RETRY:
 				case SETFEATURES_EN_RLA:
 				case SETFEATURES_PREFETCH:
+				case SETFEATURES_4B_RW_LONG:
+				case SETFEATURES_DIS_AAM:
 				case SETFEATURES_EN_RPOD:
 				case SETFEATURES_DIS_RI:
 				case SETFEATURES_DIS_SI:
@@ -1215,6 +1261,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:
@@ -1253,6 +1300,8 @@
 	}
 }
 
+EXPORT_SYMBOL(ide_cmd_type_parser);
+
 /*
  * This function is intended to be used prior to invoking ide_do_drive_cmd().
  */
@@ -1262,127 +1311,158 @@
 	rq->cmd = IDE_DRIVE_TASK_NO_DATA;
 }
 
-/*
- * This is kept for internal use only !!!
- * This is an internal call and nobody in user-space has a damn
- * reason to call this taskfile.
- *
- * ide_raw_taskfile is the one that user-space executes.
- */
-int ide_wait_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf)
-{
-	struct request rq;
-	ide_task_t args;
+EXPORT_SYMBOL(ide_init_drive_taskfile);
 
-	memset(&args, 0, sizeof(ide_task_t));
+#if 1
 
-	args.tfRegister[IDE_DATA_OFFSET]         = taskfile->data;
-	args.tfRegister[IDE_FEATURE_OFFSET]      = taskfile->feature;
-	args.tfRegister[IDE_NSECTOR_OFFSET]      = taskfile->sector_count;
-	args.tfRegister[IDE_SECTOR_OFFSET]       = taskfile->sector_number;
-	args.tfRegister[IDE_LCYL_OFFSET]         = taskfile->low_cylinder;
-	args.tfRegister[IDE_HCYL_OFFSET]         = taskfile->high_cylinder;
-	args.tfRegister[IDE_SELECT_OFFSET]       = taskfile->device_head;
-	args.tfRegister[IDE_COMMAND_OFFSET]      = taskfile->command;
-
-	args.hobRegister[IDE_DATA_OFFSET_HOB]    = hobfile->data;
-	args.hobRegister[IDE_FEATURE_OFFSET_HOB] = hobfile->feature;
-	args.hobRegister[IDE_NSECTOR_OFFSET_HOB] = hobfile->sector_count;
-	args.hobRegister[IDE_SECTOR_OFFSET_HOB]  = hobfile->sector_number;
-	args.hobRegister[IDE_LCYL_OFFSET_HOB]    = hobfile->low_cylinder;
-	args.hobRegister[IDE_HCYL_OFFSET_HOB]    = hobfile->high_cylinder;
-	args.hobRegister[IDE_SELECT_OFFSET_HOB]  = hobfile->device_head;
-	args.hobRegister[IDE_CONTROL_OFFSET_HOB] = hobfile->control;
+int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf)
+{
+	struct request rq;
 
 	ide_init_drive_taskfile(&rq);
-	/* This is kept for internal use only !!! */
-	args.command_type = ide_cmd_type_parser (&args);
-	if (args.command_type != IDE_DRIVE_TASK_NO_DATA)
-		rq.current_nr_sectors = rq.nr_sectors = (hobfile->sector_count << 8) | taskfile->sector_count;
-
 	rq.cmd = IDE_DRIVE_TASKFILE;
 	rq.buffer = buf;
-	rq.special = &args;
+
+	/*
+	 * (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)
+			rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
+		/*	rq.hard_cur_sectors	*/
+		else
+			rq.current_nr_sectors = rq.nr_sectors = data_size / SECTOR_SIZE;
+		/*	rq.hard_cur_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;
 	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;
-	ide_init_drive_taskfile(&rq);
-	rq.cmd = IDE_DRIVE_TASKFILE;
-	rq.buffer = 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 (args->command_type != IDE_DRIVE_TASK_NO_DATA)
-		rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];
+	if (HWIF(drive)->chipset == ide_pdc4030 && buf != NULL)
+		return -ENOSYS; /* special drive cmds not supported */
 
-	rq.special = args;
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
+	memset(rq, 0, sizeof(*rq));
+	rq->cmd = IDE_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(&io_request_lock, flags);
+	queue_head = queue_head->prev;
+	list_add(&rq->queue, queue_head);
+	ide_do_request(hwgroup, 0);
+	spin_unlock_irqrestore(&io_request_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)
 {
 	return("unknown");
 }
 
-char * ide_task_cmd_verbose (byte task)
+char * ide_task_cmd_verbose (u8 task)
 {
 	return("unknown");
 }
 #endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
 
-/*
- *  The taskfile glue table
- *
- *  reqtask.data_phase	reqtask.req_cmd
- *  			args.command_type		args.handler
- *
- *  TASKFILE_P_OUT_DMAQ	??				??
- *  TASKFILE_P_IN_DMAQ	??				??
- *  TASKFILE_P_OUT_DMA	??				??
- *  TASKFILE_P_IN_DMA	??				??
- *  TASKFILE_P_OUT	??				??
- *  TASKFILE_P_IN	??				??
- *
- *  TASKFILE_OUT_DMAQ	IDE_DRIVE_TASK_RAW_WRITE	NULL
- *  TASKFILE_IN_DMAQ	IDE_DRIVE_TASK_IN		NULL
- *
- *  TASKFILE_OUT_DMA	IDE_DRIVE_TASK_RAW_WRITE	NULL
- *  TASKFILE_IN_DMA	IDE_DRIVE_TASK_IN		NULL
- *
- *  TASKFILE_IN_OUT	??				??
- *
- *  TASKFILE_MULTI_OUT	IDE_DRIVE_TASK_RAW_WRITE	task_mulout_intr
- *  TASKFILE_MULTI_IN	IDE_DRIVE_TASK_IN		task_mulin_intr
- *
- *  TASKFILE_OUT	IDE_DRIVE_TASK_RAW_WRITE	task_out_intr
- *  TASKFILE_OUT	IDE_DRIVE_TASK_OUT		task_out_intr
- *
- *  TASKFILE_IN		IDE_DRIVE_TASK_IN		task_in_intr
- *  TASKFILE_NO_DATA	IDE_DRIVE_TASK_NO_DATA		task_no_data_intr
- *
- *  			IDE_DRIVE_TASK_SET_XFER		task_no_data_intr
- *  			IDE_DRIVE_TASK_INVALID
- *
- */
-
 #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;
+	u8 io_32bit		= drive->io_32bit;
+
+//	printk("IDE Taskfile ...\n");
 
 	req_task = kmalloc(tasksize, GFP_KERNEL);
 	if (req_task == NULL) return -ENOMEM;
@@ -1423,8 +1503,7 @@
 		}
 	}
 
-	memset(argsptr, 0, HDIO_DRIVE_TASK_HDR_SIZE);
-	memset(hobsptr, 0, HDIO_DRIVE_HOB_HDR_SIZE);
+	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);
 
@@ -1440,64 +1519,61 @@
 		ide_task_cmd_verbose(args.tfRegister[IDE_COMMAND_OFFSET]));
 #endif /* CONFIG_IDE_TASK_IOCTL_DEBUG */
 
+	drive->io_32bit = 0;
 	switch(req_task->data_phase) {
 		case TASKFILE_OUT_DMAQ:
 		case TASKFILE_OUT_DMA:
-			args.prehandler = NULL;
-			args.handler = NULL;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, outbuf);
+			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
 			break;
 		case TASKFILE_IN_DMAQ:
 		case TASKFILE_IN_DMA:
-			args.prehandler = NULL;
-			args.handler = NULL;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, inbuf);
+			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
 			break;
 		case TASKFILE_IN_OUT:
 #if 0
 			args.prehandler = &pre_task_out_intr;
 			args.handler = &task_out_intr;
 			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, outbuf);
+			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
 			args.prehandler = NULL;
 			args.handler = &task_in_intr;
 			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, inbuf);
+			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
 			break;
 #else
 			err = -EFAULT;
 			goto abort;
 #endif
 		case TASKFILE_MULTI_OUT:
-			if (drive->mult_count) {
-				args.prehandler = &pre_task_out_intr;
-				args.handler = &task_mulout_intr;
-				args.posthandler = NULL;
-				err = ide_raw_taskfile(drive, &args, outbuf);
-			} else {
+			if (!drive->mult_count) {
 				/* (hs): give up if multcount is not set */
 				printk("%s: %s Multimode Write " \
 					"multcount is not set\n",
-					 drive->name, __FUNCTION__);
+					drive->name, __FUNCTION__);
 				err = -EPERM;
 				goto abort;
 			}
+			if (args.tf_out_flags.all != 0) {
+				args.prehandler = &flagged_pre_task_mulout_intr;
+				args.handler = &flagged_task_mulout_intr;
+			} else {
+				args.prehandler = &pre_task_mulout_intr;
+				args.handler = &task_mulout_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
 			break;
 		case TASKFILE_OUT:
-			args.prehandler = &pre_task_out_intr;
-			args.handler = &task_out_intr;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, outbuf);
+			if (args.tf_out_flags.all != 0) {
+				args.prehandler = &flagged_pre_task_out_intr;
+				args.handler    = &flagged_task_out_intr;
+			} else {
+				args.prehandler = &pre_task_out_intr;
+				args.handler = &task_out_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskout, outbuf);
 			break;
 		case TASKFILE_MULTI_IN:
-			if (drive->mult_count) {
-				args.prehandler = NULL;
-				args.handler = &task_mulin_intr;
-				args.posthandler = NULL;
-				err = ide_raw_taskfile(drive, &args, inbuf);
-			} else {
+			if (!drive->mult_count) {
 				/* (hs): give up if multcount is not set */
 				printk("%s: %s Multimode Read failure " \
 					"multcount is not set\n",
@@ -1505,23 +1581,30 @@
 				err = -EPERM;
 				goto abort;
 			}
+			if (args.tf_out_flags.all != 0) {
+				args.handler = &flagged_task_mulin_intr;
+			} else {
+				args.handler = &task_mulin_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
 			break;
 		case TASKFILE_IN:
-			args.prehandler = NULL;
-			args.handler = &task_in_intr;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, inbuf);
+			if (args.tf_out_flags.all != 0) {
+				args.handler = &flagged_task_in_intr;
+			} else {
+				args.handler = &task_in_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, taskin, inbuf);
 			break;
 		case TASKFILE_NO_DATA:
-			args.prehandler = NULL;
-			args.handler = &task_no_data_intr;
-			args.posthandler = NULL;
-			err = ide_raw_taskfile(drive, &args, NULL);
+			if (args.tf_out_flags.all != 0) {
+				args.handler = &flagged_task_no_data_intr;
+			} else {
+				args.handler = &task_no_data_intr;
+			}
+			err = ide_diag_taskfile(drive, &args, 0, NULL);
 			break;
 		default:
-			args.prehandler = NULL;
-			args.handler = NULL;
-			args.posthandler = NULL;
 			err = -EFAULT;
 			goto abort;
 	}
@@ -1555,153 +1638,596 @@
 		kfree(outbuf);
 	if (inbuf != NULL)
 		kfree(inbuf);
+
+//	printk("IDE Taskfile ioctl ended. rc = %i\n", err);
+
+	drive->io_32bit = io_32bit;
+
 	return err;
 }
 
-EXPORT_SYMBOL(task_read_24);
-EXPORT_SYMBOL(do_rw_taskfile);
-EXPORT_SYMBOL(do_taskfile);
-// EXPORT_SYMBOL(flagged_taskfile);
+EXPORT_SYMBOL(ide_taskfile_ioctl);
 
-//EXPORT_SYMBOL(ide_end_taskfile);
+int ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
+{
+	struct request rq;
+	u8 buffer[4];
 
-EXPORT_SYMBOL(set_multmode_intr);
-EXPORT_SYMBOL(set_geometry_intr);
-EXPORT_SYMBOL(recal_intr);
+	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(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(task_mulout_intr);
+EXPORT_SYMBOL(ide_wait_cmd);
 
-EXPORT_SYMBOL(ide_init_drive_taskfile);
-EXPORT_SYMBOL(ide_wait_taskfile);
-EXPORT_SYMBOL(ide_raw_taskfile);
-EXPORT_SYMBOL(ide_pre_handler_parser);
-EXPORT_SYMBOL(ide_handler_parser);
-EXPORT_SYMBOL(ide_cmd_type_parser);
-EXPORT_SYMBOL(ide_taskfile_ioctl);
+/*
+ * FIXME : this needs to map into at taskfile. <andre@linux-ide.org>
+ */
+int ide_cmd_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+#if 1
+	int err = 0;
+	u8 args[4], *argbuf = args;
+	u8 xfer_rate = 0;
+	int argsize = 4;
+	ide_task_t tfargs;
 
-#ifdef CONFIG_PKT_TASK_IOCTL
+	if (NULL == (void *) arg) {
+		struct request rq;
+		ide_init_drive_cmd(&rq);
+		return ide_do_drive_cmd(drive, &rq, ide_wait);
+	}
 
-#if 0
+	if (copy_from_user(args, (void *)arg, 4))
+		return -EFAULT;
+
+	memset(&tfargs, 0, sizeof(ide_task_t));
+	tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
+	tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
+	tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
+	tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
+	tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
+
+	if (args[3]) {
+		argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
+		argbuf = kmalloc(argsize, GFP_KERNEL);
+		if (argbuf == NULL)
+			return -ENOMEM;
+		memcpy(argbuf, args, 4);
+	}
+	if (set_transfer(drive, &tfargs)) {
+		xfer_rate = args[1];
+		if (ide_ata66_check(drive, &tfargs))
+			goto abort;
+	}
+
+	err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
+
+	if (!err && xfer_rate) {
+		/* active-retuning-calls future */
+		if ((HWIF(drive)->speedproc) != NULL)
+			HWIF(drive)->speedproc(drive, xfer_rate);
+		ide_driveid_update(drive);
+	}
+abort:
+	if (copy_to_user((void *)arg, argbuf, argsize))
+		err = -EFAULT;
+	if (argsize > 4)
+		kfree(argbuf);
+	return err;
+
+#else
+
+	int err = 0;
+	u8 args[4], *argbuf = args;
+	u8 xfer_rate = 0;
+	int argsize = 0;
+	ide_task_t tfargs;
+
+	if (NULL == (void *) arg) {
+		struct request rq;
+		ide_init_drive_cmd(&rq);
+		return ide_do_drive_cmd(drive, &rq, ide_wait);
+	}
+
+	if (copy_from_user(args, (void *)arg, 4))
+		return -EFAULT;
+
+	memset(&tfargs, 0, sizeof(ide_task_t));
+	tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
+	tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
+	tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];
+	tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;
+	tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;
+	tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
+
+	if (args[3]) {
+		argsize = (SECTOR_WORDS * 4 * args[3]);
+		argbuf = kmalloc(argsize, GFP_KERNEL);
+		if (argbuf == NULL)
+			return -ENOMEM;
+	}
+
+	if (set_transfer(drive, &tfargs)) {
+		xfer_rate = args[1];
+		if (ide_ata66_check(drive, &tfargs))
+			goto abort;
+	}
+
+	tfargs.command_type = ide_cmd_type_parser(&tfargs);
+	err = ide_raw_taskfile(drive, &tfargs, argbuf);
+
+	if (!err && xfer_rate) {
+		/* active-retuning-calls future */
+		if ((HWIF(drive)->speedproc) != NULL)
+			HWIF(drive)->speedproc(drive, xfer_rate);
+		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];
+	args[3] = 0;
+
+	if (copy_to_user((void *)arg, argbuf, 4))
+		err = -EFAULT;
+	if (argbuf != NULL) {
+		if (copy_to_user((void *)arg, argbuf + 4, argsize))
+			err = -EFAULT;
+		kfree(argbuf);
+	}
+	return err;
+
+#endif
+}
+
+EXPORT_SYMBOL(ide_cmd_ioctl);
+
+int ide_wait_cmd_task (ide_drive_t *drive, u8 *buf)
 {
+	struct request rq;
 
-{ /* start cdrom */
+	ide_init_drive_cmd(&rq);
+	rq.cmd = IDE_DRIVE_TASK;
+	rq.buffer = buf;
+	return ide_do_drive_cmd(drive, &rq, ide_wait);
+}
 
-	struct cdrom_info *info = drive->driver_data;
+EXPORT_SYMBOL(ide_wait_cmd_task);
 
-	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");
+/*
+ * 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;
+	u8 args[7], *argbuf = args;
+	int argsize = 7;
+
+	if (copy_from_user(args, (void *)arg, 7))
+		return -EFAULT;
+	err = ide_wait_cmd_task(drive, argbuf);
+	if (copy_to_user((void *)arg, argbuf, argsize))
+		err = -EFAULT;
+	return err;
+}
+
+EXPORT_SYMBOL(ide_task_ioctl);
+
+/*
+ * 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
+
+
+#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 (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 (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)
+		/* clear nIEN */
+		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
+	SELECT_MASK(drive, 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 (task->tf_out_flags.b.data) {
+		u16 data =  taskfile->data + (hobfile->data << 8);
+		hwif->OUTW(data, IDE_DATA_REG);
+	}
+
+	/* (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);
+
+	/* (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);
+
+        /*
+	 * (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;
+}
+
+EXPORT_SYMBOL(flagged_taskfile);
+
+ide_startstop_t flagged_task_no_data_intr (ide_drive_t *drive)
+{
+	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); 
 	}
 
-	/* Set up the controller registers. */
-	OUT_BYTE (info->dma, IDE_FEATURE_REG);
-	OUT_BYTE (0, IDE_NSECTOR_REG);
-	OUT_BYTE (0, IDE_SECTOR_REG);
+	ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG));
 
-	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_stopped;
+}
+
+/*
+ * Handler for command with PIO data-in phase
+ */
+ide_startstop_t flagged_task_in_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;
+	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);
 
-	if (info->dma)
-		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));
+	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
 
-	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 */
+	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;
-	} else {
-		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
-		return (*handler) (drive);
 	}
+	/*
+	 * (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));
 
-} /* end cdrom */
+	return ide_stopped;
+}
 
-{ /* start floppy */
+ide_startstop_t flagged_task_mulin_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;
+	int retries             = 5;
+	unsigned int msect, nsect;
 
-	idefloppy_floppy_t *floppy = drive->driver_data;
-	idefloppy_bcount_reg_t bcount;
-	int dma_ok = 0;
+	if (rq->current_nr_sectors == 0) 
+		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (no data requested)", stat); 
 
-	floppy->pc=pc;		/* Set the current packet command */
+	msect = drive->mult_count;
+	if (msect == 0) 
+		return DRIVER(drive)->error(drive, "flagged_task_mulin_intr (multimode not set)", stat); 
 
-	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);
+	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); 
+	}
 
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (test_and_clear_bit (PC_DMA_ERROR, &pc->flags)) {
-		(void) HWIF(drive)->dmaproc(ide_dma_off, drive);
+	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;
 	}
-	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);
+	/*
+	 * (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));
 
-#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));
+	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)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u8 stat			= hwif->INB(IDE_STATUS_REG);
+	ide_startstop_t startstop;
+
+	if (!rq->current_nr_sectors) {
+		return DRIVER(drive)->error(drive, "flagged_pre_task_out_intr (write data not specified)", stat);
 	}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-} /* end floppy */
+	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;
+	}
 
-{ /* start tape */
+	taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
+	--rq->current_nr_sectors;
 
-	idetape_tape_t *tape = drive->driver_data;
+	return ide_started;
+}
 
-#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 */
+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 (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);
+	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 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_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;
 }
-#endif
+
+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 (!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)
+{
+	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;
+	}
+
+	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;
+}
+
+/*
+ * 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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/it8172.c linux.20pre10-ac2/drivers/ide/it8172.c
--- linux.20pre10/drivers/ide/it8172.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/it8172.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,286 +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 void it8172_tune_drive (ide_drive_t *drive, byte pio);
-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING)
-static byte it8172_dma_2_pio (byte xfer_rate);
-static int it8172_tune_chipset (ide_drive_t *drive, byte speed);
-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 void it8172_tune_drive (ide_drive_t *drive, byte pio)
-{
-    unsigned long flags;
-    u16 drive_enables;
-    u32 drive_timing;
-    int is_slave	= (&HWIF(drive)->drives[1] == drive);
-    
-    pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-    pci_read_config_word(HWIF(drive)->pci_dev, 0x40, &drive_enables);
-    pci_read_config_dword(HWIF(drive)->pci_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;
-    }
-
-    save_flags(flags);
-    cli();
-    pci_write_config_word(HWIF(drive)->pci_dev, 0x40, drive_enables);
-    restore_flags(flags);
-}
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING)
-/*
- *
- */
-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 speed)
-{
-    ide_hwif_t *hwif	= HWIF(drive);
-    struct pci_dev *dev	= hwif->pci_dev;
-    int a_speed		= 3 << (drive->dn * 4);
-    int u_flag		= 1 << drive->dn;
-    int u_speed		= 0;
-    int err		= 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) {
-    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;
-    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));
-
-    if (!drive->init_speed)
-	drive->init_speed = speed;
-    err = ide_config_drive_speed(drive, speed);
-    drive->current_speed = speed;
-    return err;
-}
-
-static int it8172_config_chipset_for_dma (ide_drive_t *drive)
-{
-    struct hd_driveid *id = drive->id;
-    byte speed;
-
-    if (id->dma_ultra & 0x0010) {
-	speed = XFER_UDMA_2;
-    } else if (id->dma_ultra & 0x0008) {
-	speed = XFER_UDMA_1;
-    } else if (id->dma_ultra & 0x0004) {
-	speed = XFER_UDMA_2;
-    } else if (id->dma_ultra & 0x0002) {
-	speed = XFER_UDMA_1;
-    } else if (id->dma_ultra & 0x0001) {
-	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) {
-	speed = XFER_SW_DMA_2;
-    } else {
-	speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 4, NULL);
-    }
-
-    (void) it8172_tune_chipset(drive, speed);
-
-    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 it8172_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-    switch (func) {
-    case ide_dma_check:
-	return ide_dmaproc((ide_dma_action_t)it8172_config_chipset_for_dma(drive),
-			   drive);
-    default :
-	break;
-    }
-    /* Other cases are done by generic IDE-DMA code. */
-    return ide_dmaproc(func, drive);
-}
-
-#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_IT8172_TUNING) */
-
-
-unsigned int __init pci_init_it8172 (struct pci_dev *dev, const char *name)
-{
-    unsigned char progif;
-    
-    /*
-     * Place both IDE interfaces into PCI "native" mode
-     */
-    (void)pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
-    (void)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->tuneproc = &it8172_tune_drive;
-    hwif->drives[0].autotune = 1;
-    hwif->drives[1].autotune = 1;
-
-    if (!hwif->dma_base)
-	return;
-
-#ifndef CONFIG_BLK_DEV_IDEDMA
-    hwif->autodma = 0;
-#else /* CONFIG_BLK_DEV_IDEDMA */
-#ifdef CONFIG_IT8172_TUNING
-    hwif->autodma = 1;
-    hwif->dmaproc = &it8172_dmaproc;
-    hwif->speedproc = &it8172_tune_chipset;
-#endif /* CONFIG_IT8172_TUNING */
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-
-    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;
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/legacy/ali14xx.c linux.20pre10-ac2/drivers/ide/legacy/ali14xx.c
--- linux.20pre10/drivers/ide/legacy/ali14xx.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/legacy/ali14xx.c	2002-09-06 14:07:58.000000000 +0100
@@ -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(&io_request_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(&io_request_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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/legacy/buddha.c linux.20pre10-ac2/drivers/ide/legacy/buddha.c
--- linux.20pre10/drivers/ide/legacy/buddha.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/legacy/buddha.c	2002-08-29 23:47:56.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/legacy/dtc2278.c linux.20pre10-ac2/drivers/ide/legacy/dtc2278.c
--- linux.20pre10/drivers/ide/legacy/dtc2278.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/legacy/dtc2278.c	2002-09-06 14:07:58.000000000 +0100
@@ -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(&io_request_lock, flags);
+		/*
+		 * This enables PIO mode4 (3?) on the first interface
+		 */
+		sub22(1,0xc3);
+		sub22(0,0xa0);
+		spin_unlock_irqrestore(&io_request_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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/legacy/falconide.c linux.20pre10-ac2/drivers/ide/legacy/falconide.c
--- linux.20pre10/drivers/ide/legacy/falconide.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/legacy/falconide.c	2002-08-29 23:47:56.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/legacy/gayle.c linux.20pre10-ac2/drivers/ide/legacy/gayle.c
--- linux.20pre10/drivers/ide/legacy/gayle.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/legacy/gayle.c	2002-08-29 23:47:56.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/legacy/hd.c linux.20pre10-ac2/drivers/ide/legacy/hd.c
--- linux.20pre10/drivers/ide/legacy/hd.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/legacy/hd.c	2002-09-10 23:39:54.000000000 +0100
@@ -0,0 +1,926 @@
+/*
+ *  linux/drivers/ide/hd.c
+ *
+ *  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/devfs_fs_kernel.h>
+#include <linux/kernel.h>
+#include <linux/hdreg.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/ide.h>
+
+#define REALLY_SLOW_IO
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#define MAJOR_NR HD_MAJOR
+#include <linux/blk.h>
+
+#ifdef __arm__
+#undef  HD_IRQ
+#endif
+#include <asm/irq.h>
+#ifdef __arm__
+#define HD_IRQ IRQ_HARDDISK
+#endif
+
+static int revalidate_hddisk(kdev_t, int);
+
+#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 access_count[MAX_HD];
+static char busy[MAX_HD];
+static DECLARE_WAIT_QUEUE_HEAD(busy_wait);
+
+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 hd_struct hd[MAX_HD<<6];
+static int hd_sizes[MAX_HD<<6];
+static int hd_blocksizes[MAX_HD<<6];
+static int hd_hardsectsizes[MAX_HD<<6];
+static int hd_maxsect[MAX_HD<<6];
+
+static struct timer_list device_timer;
+
+#define SET_TIMER 							\
+	do {								\
+		mod_timer(&device_timer, jiffies + TIMEOUT_VALUE);	\
+	} while (0)
+
+#define CLEAR_TIMER del_timer(&device_timer);
+
+#undef SET_INTR
+
+#define SET_INTR(x) \
+if ((DEVICE_INTR = (x)) != NULL) \
+	SET_TIMER; \
+else \
+	CLEAR_TIMER;
+
+
+#if (HD_DELAY > 0)
+unsigned long last_req;
+
+unsigned long read_timer(void)
+{
+	unsigned long t, flags;
+	int i;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	t = jiffies * 11932;
+    	outb_p(0, 0x43);
+	i = inb_p(0x40);
+	i |= inb(0x40) << 8;
+	spin_unlock_irqrestore(&io_request_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)
+{
+	unsigned long flags;
+	char devc;
+
+	devc = !QUEUE_EMPTY ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
+	save_flags (flags);
+	sti();
+#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 (!QUEUE_EMPTY)
+				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	/* verbose errors */
+	restore_flags (flags);
+}
+
+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_INTR(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();
+}
+
+void do_reset_hd(void)
+{
+	DEVICE_INTR = NULL;
+	reset = 1;
+	reset_hd();
+}
+
+/*
+ * 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 (QUEUE_EMPTY)
+		return;
+	dev = DEVICE_NR(CURRENT->rq_dev);
+	if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
+		end_request(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(1);
+	if (i > 0) {
+		SET_INTR(&read_intr);
+		return;
+	}
+	(void) inb_p(HD_STATUS);
+#if (HD_DELAY > 0)
+	last_req = read_timer();
+#endif
+	if (!QUEUE_EMPTY)
+		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->bh && !SUBSECTOR(i)))
+		end_request(1);
+	if (i > 0) {
+		SET_INTR(&write_intr);
+		outsw(HD_DATA,CURRENT->buffer,256);
+		sti();
+	} 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;
+
+	DEVICE_INTR = NULL;
+	if (QUEUE_EMPTY)
+		return;
+	disable_irq(HD_IRQ);
+	sti();
+	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(0);
+	}
+	cli();
+	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(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 (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE) return;
+	if (DEVICE_INTR)
+		return;
+repeat:
+	del_timer(&device_timer);
+	sti();
+	INIT_REQUEST;
+	if (reset) {
+		cli();
+		reset_hd();
+		return;
+	}
+	dev = MINOR(CURRENT->rq_dev);
+	block = CURRENT->sector;
+	nsect = CURRENT->nr_sectors;
+	if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects || ((block+nsect) > hd[dev].nr_sects)) {
+#ifdef DEBUG
+		if (dev >= (NR_HD<<6))
+			printk("hd: bad minor number: device=%s\n",
+			       kdevname(CURRENT->rq_dev));
+		else
+			printk("hd%c: bad access: block=%d, count=%d\n",
+				(MINOR(CURRENT->rq_dev)>>6)+'a', block, nsect);
+#endif
+		end_request(0);
+		goto repeat;
+	}
+	block += hd[dev].start_sect;
+	dev >>= 6;
+	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->cmd == READ) {
+		hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
+		if (reset)
+			goto repeat;
+		return;
+	}
+	if (CURRENT->cmd == 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);
+		return;
+	}
+	panic("unknown hd-command");
+}
+
+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) || !(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 = hd[MINOR(inode->i_rdev)].start_sect;
+			return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; 
+		}
+
+         	case BLKGETSIZE:   /* Return device size */
+			return put_user(hd[MINOR(inode->i_rdev)].nr_sects, 
+					(unsigned long *) arg);
+         	case BLKGETSIZE64:
+			return put_user((u64)hd[MINOR(inode->i_rdev)].nr_sects << 9, 
+					(u64 *) arg);
+
+		case BLKRRPART: /* Re-read partition tables */
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+			return revalidate_hddisk(inode->i_rdev, 1);
+
+		case BLKROSET:
+		case BLKROGET:
+		case BLKRASET:
+		case BLKRAGET:
+		case BLKFLSBUF:
+		case BLKPG:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+
+		default:
+			return -EINVAL;
+	}
+}
+
+static int hd_open(struct inode * inode, struct file * filp)
+{
+	int target;
+	target =  DEVICE_NR(inode->i_rdev);
+
+	if (target >= NR_HD)
+		return -ENODEV;
+	while (busy[target])
+		sleep_on(&busy_wait);
+	access_count[target]++;
+	return 0;
+}
+
+/*
+ * Releasing a block device means we sync() it, so that it can safely
+ * be forgotten about...
+ */
+static int hd_release(struct inode * inode, struct file * file)
+{
+        int target =  DEVICE_NR(inode->i_rdev);
+	access_count[target]--;
+	return 0;
+}
+
+extern struct block_device_operations hd_fops;
+
+static struct gendisk hd_gendisk = {
+	major:		MAJOR_NR,
+	major_name:	"hd",
+	minor_shift:	6,
+	max_p:		1 << 6,
+	part:		hd,
+	sizes:		hd_sizes,
+	fops:		&hd_fops,
+};
+	
+static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	void (*handler)(void) = DEVICE_INTR;
+
+	DEVICE_INTR = NULL;
+	del_timer(&device_timer);
+	if (!handler)
+		handler = unexpected_hd_interrupt;
+	handler();
+	sti();
+}
+
+static struct block_device_operations hd_fops = {
+	open:		hd_open,
+	release:	hd_release,
+	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;
+
+	for(drive=0; drive < (MAX_HD << 6); drive++) {
+		hd_blocksizes[drive] = 1024;
+		hd_hardsectsizes[drive] = 512;
+		hd_maxsect[drive]=255;
+	}
+	blksize_size[MAJOR_NR] = hd_blocksizes;
+	hardsect_size[MAJOR_NR] = hd_hardsectsizes;
+	max_sectors[MAJOR_NR] = hd_maxsect;
+
+#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++) {
+		hd[drive<<6].nr_sects = hd_info[drive].head *
+			hd_info[drive].sect * hd_info[drive].cyl;
+		printk ("hd%c: %ldMB, CHS=%d/%d/%d\n", drive+'a',
+			hd[drive<<6].nr_sects / 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;
+	}
+	request_region(HD_DATA, 8, "hd");
+	request_region(HD_CMD, 1, "hd(cmd)");
+
+	hd_gendisk.nr_real = NR_HD;
+
+	for(drive=0; drive < NR_HD; drive++)
+		register_disk(&hd_gendisk, MKDEV(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 (devfs_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), DEVICE_REQUEST);
+	read_ahead[MAJOR_NR] = 8;		/* 8 sector (4kB) read-ahead */
+	add_gendisk(&hd_gendisk);
+	init_timer(&device_timer);
+	device_timer.function = hd_times_out;
+	hd_geninit();
+	return 0;
+}
+
+#define DEVICE_BUSY busy[target]
+#define USAGE access_count[target]
+#define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl)
+/* We assume that the BIOS parameters do not change, so the disk capacity
+   will not change */
+#undef MAYBE_REINIT
+#define GENDISK_STRUCT hd_gendisk
+
+/*
+ * This routine is called to flush all partitions and partition tables
+ * for a changed disk, and then re-read the new partition table.
+ * If we are revalidating a disk because of a media change, then we
+ * enter with usage == 0.  If we are using an ioctl, we automatically have
+ * usage == 1 (we need an open channel to use an ioctl :-), so this
+ * is our limit.
+ */
+static int revalidate_hddisk(kdev_t dev, int maxusage)
+{
+	int target;
+	struct gendisk * gdev;
+	int max_p;
+	int start;
+	int i;
+	long flags;
+
+	target = DEVICE_NR(dev);
+	gdev = &GENDISK_STRUCT;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (DEVICE_BUSY || USAGE > maxusage) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return -EBUSY;
+	}
+	DEVICE_BUSY = 1;
+	spin_unlock_irqrestore(&io_request_lock, flags);
+
+	max_p = gdev->max_p;
+	start = target << gdev->minor_shift;
+
+	for (i=max_p - 1; i >=0 ; i--) {
+		int minor = start + i;
+		invalidate_device(MKDEV(MAJOR_NR, minor), 1);
+		gdev->part[minor].start_sect = 0;
+		gdev->part[minor].nr_sects = 0;
+	}
+
+#ifdef MAYBE_REINIT
+	MAYBE_REINIT;
+#endif
+
+	grok_partitions(gdev, target, 1<<6, CAPACITY);
+
+	DEVICE_BUSY = 0;
+	wake_up(&busy_wait);
+	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);
+
+module_init(hd_init);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/legacy/ht6560b.c linux.20pre10-ac2/drivers/ide/legacy/ht6560b.c
--- linux.20pre10/drivers/ide/legacy/ht6560b.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/legacy/ht6560b.c	2002-09-06 14:07:58.000000000 +0100
@@ -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(&io_request_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(&io_request_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(&io_request_lock, flags);
+	
+	drive->drive_data &= 0xff00;
+	drive->drive_data |= timing;
+	
+	spin_unlock_irqrestore(&io_request_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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/legacy/ide-cs.c linux.20pre10-ac2/drivers/ide/legacy/ide-cs.c
--- linux.20pre10/drivers/ide/legacy/ide-cs.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/legacy/ide-cs.c	2002-09-30 16:55:43.000000000 +0100
@@ -0,0 +1,494 @@
+/*======================================================================
+
+    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) {
+        /* FIXME: if this fails we need to queue the cleanup somehow
+           -- need to investigate the required PCMCIA magic */
+	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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/legacy/macide.c linux.20pre10-ac2/drivers/ide/legacy/macide.c
--- linux.20pre10/drivers/ide/legacy/macide.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/legacy/macide.c	2002-08-29 23:47:56.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/legacy/Makefile linux.20pre10-ac2/drivers/ide/legacy/Makefile
--- linux.20pre10/drivers/ide/legacy/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/legacy/Makefile	2002-09-10 23:41:05.000000000 +0100
@@ -0,0 +1,27 @@
+
+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
+
+# Last of all
+obj-$(CONFIG_BLK_DEV_HD)		+= hd.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/legacy/pdc4030.c linux.20pre10-ac2/drivers/ide/legacy/pdc4030.c
--- linux.20pre10/drivers/ide/legacy/pdc4030.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/legacy/pdc4030.c	2002-09-06 01:02:16.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/legacy/pdc4030.h linux.20pre10-ac2/drivers/ide/legacy/pdc4030.h
--- linux.20pre10/drivers/ide/legacy/pdc4030.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/legacy/pdc4030.h	2002-09-18 14:26:33.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/legacy/q40ide.c linux.20pre10-ac2/drivers/ide/legacy/q40ide.c
--- linux.20pre10/drivers/ide/legacy/q40ide.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/legacy/q40ide.c	2002-09-14 21:48:51.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/legacy/qd65xx.c linux.20pre10-ac2/drivers/ide/legacy/qd65xx.c
--- linux.20pre10/drivers/ide/legacy/qd65xx.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/legacy/qd65xx.c	2002-09-06 14:07:58.000000000 +0100
@@ -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(&io_request_lock, flags);
+	outb(content,reg);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+u8 __init qd_read_reg (u8 reg)
+{
+	unsigned long flags;
+	u8 read;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	read = inb(reg);
+	spin_unlock_irqrestore(&io_request_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(&io_request_lock, flags);
+	savereg = inb_p(port);
+	outb_p(QD_TESTVAL, port);	/* safe value */
+	readreg = inb_p(port);
+	outb(savereg, port);
+	spin_unlock_irqrestore(&io_request_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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/legacy/qd65xx.h linux.20pre10-ac2/drivers/ide/legacy/qd65xx.h
--- linux.20pre10/drivers/ide/legacy/qd65xx.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/legacy/qd65xx.h	2002-08-29 23:47:56.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/legacy/umc8672.c linux.20pre10-ac2/drivers/ide/legacy/umc8672.c
--- linux.20pre10/drivers/ide/legacy/umc8672.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/legacy/umc8672.c	2002-09-06 14:07:58.000000000 +0100
@@ -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(&io_request_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(&io_request_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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/macide.c linux.20pre10-ac2/drivers/ide/macide.c
--- linux.20pre10/drivers/ide/macide.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/macide.c	1970-01-01 01:00:00.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/Makefile linux.20pre10-ac2/drivers/ide/Makefile
--- linux.20pre10/drivers/ide/Makefile	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/Makefile	2002-09-10 23:41:23.000000000 +0100
@@ -10,80 +10,50 @@
 
 O_TARGET := idedriver.o
 
-export-objs		:= ide.o ide-features.o ide-probe.o ide-taskfile.o ataraid.o
-list-multi		:= ide-mod.o ide-probe-mod.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
+
+all-subdirs	:= arm legacy pci ppc raid
+mod-subdirs	:= arm legacy pci ppc raid
 
 obj-y		:=
 obj-m		:=
 ide-obj-y	:=
 
-obj-$(CONFIG_BLK_DEV_HD)	+= hd.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_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_ADMA)		+= ide-adma.o
-ide-obj-$(CONFIG_BLK_DEV_IDEDMA_PCI)	+= ide-dma.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_SIBYTE)	+= ide-sibyte.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_PDC_ADMA)	+= pdcadma.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
-ide-obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= ide-m8xx.o
-
-# The virtualised raid layers MUST come after the ide itself or bad stuff
-# will happen.
-obj-$(CONFIG_BLK_DEV_ATARAID)		+= ataraid.o
-obj-$(CONFIG_BLK_DEV_ATARAID_PDC)	+= pdcraid.o
-obj-$(CONFIG_BLK_DEV_ATARAID_HPT)	+= hptraid.o
+subdir-$(CONFIG_BLK_DEV_IDE) += legacy ppc arm raid pci
 
-ide-obj-$(CONFIG_PROC_FS)		+= ide-proc.o
+# First come modules that register themselves with the core
 
-ide-mod-objs		:= ide.o ide-features.o ide-taskfile.o $(ide-obj-y)
-ide-probe-mod-objs	:= ide-probe.o ide-geometry.o
+ifeq ($(CONFIG_BLK_DEV_IDE),y)
+  obj-y		+= pci/idedriver-pci.o
+endif
+
+# Core IDE code - must come before legacy
+
+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_IDEPCI)		+= setup-pci.o
+obj-$(CONFIG_BLK_DEV_IDEDMA_PCI)	+= ide-dma.o
+obj-$(CONFIG_BLK_DEV_ISAPNP)		+= ide-pnp.o
 
-include $(TOPDIR)/Rules.make
 
-ide-mod.o: $(ide-mod-objs)
-	$(LD) -r -o $@ $(ide-mod-objs)
+ifeq ($(CONFIG_BLK_DEV_IDE),y)
+obj-$(CONFIG_PROC_FS)			+= ide-proc.o
+endif
 
-ide-probe-mod.o: $(ide-probe-mod-objs)
-	$(LD) -r -o $@ $(ide-probe-mod-objs)
+ifeq ($(CONFIG_BLK_DEV_IDE),y)
+  obj-y		+= legacy/idedriver-legacy.o
+  obj-y		+= ppc/idedriver-ppc.o
+  obj-y		+= arm/idedriver-arm.o
+endif
+
+
+ifeq ($(CONFIG_BLK_DEV_IDE),y)
+# RAID must be last of all
+  obj-y		+= raid/idedriver-raid.o
+endif
+
+include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ns87415.c linux.20pre10-ac2/drivers/ide/ns87415.c
--- linux.20pre10/drivers/ide/ns87415.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ns87415.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,193 +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;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	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);
-	}
-
-	__restore_flags(flags);	/* local CPU only */
-}
-
-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 = inb(hwif->dma_base+2);
-			outb(inb(hwif->dma_base)&~1, hwif->dma_base);	/* stop DMA */
-			outb(inb(hwif->dma_base)|6, hwif->dma_base);	/* from ERRATA: clear the INTR & ERROR bits */
-			ide_destroy_dmatable(drive);			/* and free any DMA resources */
-			return (dma_stat & 7) != 4;		/* verify good DMA status */
-		case ide_dma_write:
-		case ide_dma_read:
-			ns87415_prepare_drive(drive, 1);	/* select DMA xfer */
-			if (!ide_dmaproc(func, drive))		/* use standard DMA stuff */
-				return 0;
-			ns87415_prepare_drive(drive, 0);	/* DMA failed: select PIO xfer */
-			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
-
-	/* 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;
-		outb(12, hwif->io_ports[IDE_CONTROL_OFFSET]);
-		udelay(10);
-		outb(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
-		do {
-			udelay(50);
-			stat = inb(hwif->io_ports[IDE_STATUS_OFFSET]);
-                	if (stat == 0xff)
-                        	break;
-        	} while ((stat & BUSY_STAT) && --timeout);
-#endif
-	}
-
-	if (hwif->dma_base)
-		outb(0x60, hwif->dma_base + 2);
-
-	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 */
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base)
-		hwif->dmaproc = &ns87415_dmaproc;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	hwif->selectproc = &ns87415_selectproc;
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/opti621.c linux.20pre10-ac2/drivers/ide/opti621.c
--- linux.20pre10/drivers/ide/opti621.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/opti621.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,316 +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/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.
- */
-{
-	inw(reg_base+1);
-	inw(reg_base+1);
-	outb(3, reg_base+2);
-	outb(value, reg_base+reg);
-	outb(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;
-	inw(reg_base+1);
-	inw(reg_base+1);
-	outb(3, reg_base+2);
-	ret=inb(reg_base+reg);
-	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, 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
-
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-
-     	reg_base = hwif->io_ports[IDE_DATA_OFFSET];
-	outb(0xc0, reg_base+CNTRL_REG);	/* allow Register-B */
-	outb(0xff, reg_base+5);		/* hmm, setupvic.exe does this ;-) */
-	inb(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 */
-
-	restore_flags(flags);	/* all CPUs */
-}
-
-/*
- * ide_init_opti621() is called once for each hwif found at boot.
- */
-void __init ide_init_opti621 (ide_hwif_t *hwif)
-{
-	hwif->drives[0].drive_data = PIO_DONT_KNOW;
-	hwif->drives[1].drive_data = PIO_DONT_KNOW;
-	hwif->tuneproc = &opti621_tune_drive;
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/adma100.c linux.20pre10-ac2/drivers/ide/pci/adma100.c
--- linux.20pre10/drivers/ide/pci/adma100.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/adma100.c	2002-08-29 23:47:56.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/adma100.h linux.20pre10-ac2/drivers/ide/pci/adma100.h
--- linux.20pre10/drivers/ide/pci/adma100.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/adma100.h	2002-10-11 00:35:04.000000000 +0100
@@ -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[] __devinitdata = {
+	{
+		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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/aec62xx.c linux.20pre10-ac2/drivers/ide/pci/aec62xx.c
--- linux.20pre10/drivers/ide/pci/aec62xx.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/aec62xx.c	2002-09-18 12:49:26.000000000 +0100
@@ -0,0 +1,583 @@
+/*
+ * 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"  };
+	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(&io_request_lock, flags);
+		pci_read_config_byte(dev, 0x54, &reg54h);
+		pci_write_config_byte(dev, 0x54, reg54h & ~(hwif->channel ? 0xF0 : 0x0F));
+		spin_unlock_irqrestore(&io_request_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);
+}
+
+/**
+ *	aec62xx_init_one	-	called when a AEC is found
+ *	@dev: the aec62xx device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit aec62xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &aec62xx_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	aec62xx_remove_one	-	called when an AEC is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect an AEC device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void aec62xx_remove_one(struct pci_dev *dev)
+{
+	printk("AEC62xx removal not yet supported.\n");
+}
+
+static struct pci_device_id aec62xx_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP850UF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP860R,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
+	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"AEC62xx IDE",
+	id_table:	aec62xx_pci_tbl,
+	probe:		aec62xx_init_one,
+	remove:		__devexit_p(aec62xx_remove_one),
+};
+
+static int aec62xx_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void aec62xx_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(aec62xx_ide_init);
+module_exit(aec62xx_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for ARTOP AEC62xx IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/aec62xx.h linux.20pre10-ac2/drivers/ide/pci/aec62xx.h
--- linux.20pre10/drivers/ide/pci/aec62xx.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/aec62xx.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,175 @@
+#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[] __devinitdata = {
+	{	/* 0 */
+		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,
+	},{	/* 1 */
+		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,
+	},{	/* 2 */
+		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,
+	},{	/* 3 */
+		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,
+	},{	/* 4 */
+		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,
+	}
+};
+
+#endif /* AEC62XX_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/alim15x3.c linux.20pre10-ac2/drivers/ide/pci/alim15x3.c
--- linux.20pre10/drivers/ide/pci/alim15x3.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/alim15x3.c	2002-09-18 12:49:08.000000000 +0100
@@ -0,0 +1,908 @@
+/*
+ * 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/module.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. We might have no north found on some zany
+	 * box without a device at 0:0.0. The ALi bridge will be at
+	 * 0:0.0 so if we didn't find one we know what is cooking.
+	 */
+	if (north && 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 *);
+
+
+/**
+ *	alim15x3_init_one	-	set up an ALi15x3 IDE controller
+ *	@dev: PCI device to set up
+ *
+ *	Perform the actual set up for an ALi15x3 that has been found by the
+ *	hot plug layer.
+ */
+ 
+static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &ali15x3_chipsets[id->driver_data];
+#if defined(CONFIG_SPARC64)
+	d->init_hwif = init_hwif_common_ali15x3;
+#endif /* CONFIG_SPARC64 */
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+
+/**
+ *	ali15x3_remove_one	-	called with an ALi is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect an ALi device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void ali15x3_remove_one(struct pci_dev *dev)
+{
+	printk("ALi removal not yet supported.\n");
+}
+
+static struct pci_device_id alim15x3_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"ALI15x3 IDE",
+	id_table:	alim15x3_pci_tbl,
+	probe:		alim15x3_init_one,
+	remove:		__devexit_p(ali15x3_remove_one),
+};
+
+static int ali15x3_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void ali15x3_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(ali15x3_ide_init);
+module_exit(ali15x3_ide_exit);
+
+MODULE_AUTHOR("Michael Aubry, Andrzej Krzysztofowicz, CJ, Andre Hedrick, Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for ALi 15x3 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/alim15x3.h linux.20pre10-ac2/drivers/ide/pci/alim15x3.h
--- linux.20pre10/drivers/ide/pci/alim15x3.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/alim15x3.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,55 @@
+#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 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[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_AL,
+		device:		PCI_DEVICE_ID_AL_M5229,
+		name:		"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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/amd74xx.c linux.20pre10-ac2/drivers/ide/pci/amd74xx.c
--- linux.20pre10/drivers/ide/pci/amd74xx.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/amd74xx.c	2002-09-18 12:48:53.000000000 +0100
@@ -0,0 +1,453 @@
+/*
+ * 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/module.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 int __devinit amd74xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &amd74xx_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	amd74xx_remove_one	-	called with an AMD IDE is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect an AMD IDE device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void amd74xx_remove_one(struct pci_dev *dev)
+{
+	printk("AMD IDE removal not yet supported.\n");
+}
+
+static struct pci_device_id amd74xx_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7441,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, 	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"AMD IDE",
+	id_table:	amd74xx_pci_tbl,
+	probe:		amd74xx_init_one,
+	remove:		__devexit_p(amd74xx_remove_one),
+};
+
+static int amd74xx_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void amd74xx_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(amd74xx_ide_init);
+module_exit(amd74xx_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for AMD IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/amd74xx.h linux.20pre10-ac2/drivers/ide/pci/amd74xx.h
--- linux.20pre10/drivers/ide/pci/amd74xx.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/amd74xx.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,106 @@
+#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 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[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_AMD,
+		device:		PCI_DEVICE_ID_AMD_COBRA_7401,
+		name:		"AMD7401",
+		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
+	},{	/* 1 */
+		vendor:		PCI_VENDOR_ID_AMD,
+		device:		PCI_DEVICE_ID_AMD_VIPER_7409,
+		name:		"AMD7409",
+		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
+	},{	/* 2 */
+		vendor:		PCI_VENDOR_ID_AMD,
+		device:		PCI_DEVICE_ID_AMD_VIPER_7411,
+		name:		"AMD7411",
+		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
+	},{	/* 3 */
+		vendor:		PCI_VENDOR_ID_AMD,
+		device:		PCI_DEVICE_ID_AMD_OPUS_7441,
+		name:		"AMD7441",
+		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
+	},{	/* 4 */
+		vendor:		PCI_VENDOR_ID_AMD,
+		device:		PCI_DEVICE_ID_AMD_8111_IDE,
+		name:		"AMD8111",
+		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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/cmd640.c linux.20pre10-ac2/drivers/ide/pci/cmd640.c
--- linux.20pre10/drivers/ide/pci/cmd640.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/cmd640.c	2002-09-06 14:08:22.000000000 +0100
@@ -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(&io_request_lock, flags);
+	outb_p((reg & 0xfc) | cmd640_key, 0xcf8);
+	outb_p(val, (reg & 3) | 0xcfc);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+static u8 get_cmd640_reg_pci1 (u16 reg)
+{
+	u8 b;
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	outb_p((reg & 0xfc) | cmd640_key, 0xcf8);
+	b = inb_p((reg & 3) | 0xcfc);
+	spin_unlock_irqrestore(&io_request_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(&io_request_lock, flags);
+	outb_p(0x10, 0xcf8);
+	outb_p(val, cmd640_key + reg);
+	outb_p(0, 0xcf8);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+static u8 get_cmd640_reg_pci2 (u16 reg)
+{
+	u8 b;
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	outb_p(0x10, 0xcf8);
+	b = inb_p(cmd640_key + reg);
+	outb_p(0, 0xcf8);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return b;
+}
+
+/* VLB access */
+
+static void put_cmd640_reg_vlb (u16 reg, u8 val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	outb_p(reg, cmd640_key);
+	outb_p(val, cmd640_key + 4);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+}
+
+static u8 get_cmd640_reg_vlb (u16 reg)
+{
+	u8 b;
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	outb_p(reg, cmd640_key);
+	b = inb_p(cmd640_key + 4);
+	spin_unlock_irqrestore(&io_request_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(&io_request_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(&io_request_lock, flags);
+			return 0; /* nothing responded */
+		}
+	}
+	spin_unlock_irqrestore(&io_request_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(&io_request_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(&io_request_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(&io_request_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(&io_request_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(&io_request_lock, flags);
+	outb(0x01, 0xCFB);
+	tmp = inl(0xCF8);
+	outl(0x80000000, 0xCF8);
+	if (inl(0xCF8) == 0x80000000) {
+		outl(tmp, 0xCF8);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return 1;
+	}
+	outl(tmp, 0xCF8);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	return 0;
+}
+
+static int pci_conf2(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	outb(0x00, 0xCFB);
+	outb(0x00, 0xCF8);
+	outb(0x00, 0xCFA);
+	if (inb(0xCF8) == 0x00 && inb(0xCF8) == 0x00) {
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		return 1;
+	}
+	spin_unlock_irqrestore(&io_request_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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/cmd640.h linux.20pre10-ac2/drivers/ide/pci/cmd640.h
--- linux.20pre10/drivers/ide/pci/cmd640.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/cmd640.h	2002-10-11 00:35:04.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/cmd64x.c linux.20pre10-ac2/drivers/ide/pci/cmd64x.c
--- linux.20pre10/drivers/ide/pci/cmd64x.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/cmd64x.c	2002-09-18 20:36:14.000000000 +0100
@@ -0,0 +1,824 @@
+/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
+ *
+ * linux/drivers/ide/cmd64x.c		Version 1.30	Sept 10, 2002
+ *
+ * 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/module.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)
+		hwif->ultra_mask = (class_rev > 0x04) ? 0x07 : 0x80;
+	if (dev->device == PCI_DEVICE_ID_CMD_648)
+		hwif->ultra_mask = 0x1f;
+
+#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 */
+}
+
+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 *);
+
+static int __devinit cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &cmd64x_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	cmd64x_remove_one	-	called with an CMD64x is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect a CMD64x device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void cmd64x_remove_one(struct pci_dev *dev)
+{
+	printk("CMD64x removal not yet supported.\n");
+}
+
+static struct pci_device_id cmd64x_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"CMD64x IDE",
+	id_table:	cmd64x_pci_tbl,
+	probe:		cmd64x_init_one,
+	remove:		__devexit_p(cmd64x_remove_one),
+};
+
+static int cmd64x_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void cmd64x_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(cmd64x_ide_init);
+module_exit(cmd64x_ide_exit);
+
+MODULE_AUTHOR("Eddie Dost, David Miller, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for CMD64x IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/cmd64x.h linux.20pre10-ac2/drivers/ide/pci/cmd64x.h
--- linux.20pre10/drivers/ide/pci/cmd64x.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/cmd64x.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,147 @@
+#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 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[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_CMD,
+		device:		PCI_DEVICE_ID_CMD_643,
+		name:		"CMD643",
+		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,
+	},{	/* 1 */
+		vendor:		PCI_VENDOR_ID_CMD,
+		device:		PCI_DEVICE_ID_CMD_646,
+		name:		"CMD646",
+		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,
+	},{	/* 2 */
+		vendor:		PCI_VENDOR_ID_CMD,
+		device:	PCI_DEVICE_ID_CMD_648,
+		name:		"CMD648",
+		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_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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/cs5530.c linux.20pre10-ac2/drivers/ide/pci/cs5530.c
--- linux.20pre10/drivers/ide/pci/cs5530.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/cs5530.c	2002-09-18 12:48:25.000000000 +0100
@@ -0,0 +1,476 @@
+/*
+ * linux/drivers/ide/cs5530.c		Version 0.7	Sept 10, 2002
+ *
+ * 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/module.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(&io_request_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(&io_request_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 *);
+
+
+static int __devinit cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &cs5530_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	cs5530_remove_one	-	called when a CS5530 is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect an Cyrix device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void cs5530_remove_one(struct pci_dev *dev)
+{
+	printk("Cyrix removal not yet supported.\n");
+}
+
+static struct pci_device_id cs5530_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"CS5530 IDE",
+	id_table:	cs5530_pci_tbl,
+	probe:		cs5530_init_one,
+	remove:		__devexit_p(cs5530_remove_one),
+};
+
+static int cs5530_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void cs5530_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(cs5530_ide_init);
+module_exit(cs5530_ide_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for Cyrix/NS 5530 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/cs5530.h linux.20pre10-ac2/drivers/ide/pci/cs5530.h
--- linux.20pre10/drivers/ide/pci/cs5530.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/cs5530.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,54 @@
+#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 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[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_CYRIX,
+		device:		PCI_DEVICE_ID_CYRIX_5530_IDE,
+		name:		"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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/cy82c693.c linux.20pre10-ac2/drivers/ide/pci/cy82c693.c
--- linux.20pre10/drivers/ide/pci/cy82c693.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/cy82c693.c	2002-09-18 12:48:04.000000000 +0100
@@ -0,0 +1,474 @@
+/*
+ * linux/drivers/ide/cy82c693.c		Version 0.40	Sep. 10, 2002
+ *
+ *  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
+ *
+ * Ancient 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/module.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 *);
+
+static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &cy82c693_chipsets[id->driver_data];
+        if ((!(PCI_FUNC(dev->devfn) & 1) ||
+	    (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))))
+		return 0;	/* CY82C693 is more than only a IDE controller */
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	cy82c693_remove_one	-	called with an Cypress is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect an Cypress device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void cy82c693_remove_one(struct pci_dev *dev)
+{
+	printk("Cypress removal not yet supported.\n");
+}
+
+static struct pci_device_id cy82c693_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"Cypress IDE",
+	id_table:	cy82c693_pci_tbl,
+	probe:		cy82c693_init_one,
+	remove:		__devexit_p(cy82c693_remove_one),
+};
+
+static int cy82c693_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void cy82c693_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(cy82c693_ide_init);
+module_exit(cy82c693_ide_exit);
+
+MODULE_AUTHOR("Andreas Krebs, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for the Cypress CY82C693 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/cy82c693.h linux.20pre10-ac2/drivers/ide/pci/cy82c693.h
--- linux.20pre10/drivers/ide/pci/cy82c693.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/cy82c693.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,93 @@
+#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 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[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_CONTAQ,
+		device:		PCI_DEVICE_ID_CONTAQ_82C693,
+		name:		"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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/generic.c linux.20pre10-ac2/drivers/ide/pci/generic.c
--- linux.20pre10/drivers/ide/pci/generic.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/generic.c	2002-09-18 12:47:01.000000000 +0100
@@ -0,0 +1,162 @@
+/*
+ *  linux/drivers/ide/generic.c		Version 0.10	Sept 11, 2002
+ *
+ *  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/module.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 *);
+
+#if 0
+
+	/* Logic to add back later on */
+	
+	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;
+#endif	
+
+/**
+ *	generic_init_one	-	called when a PIIX is found
+ *	@dev: the generic device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &generic_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	if ((d->vendor == PCI_VENDOR_ID_UMC) &&
+	    (d->device == PCI_DEVICE_ID_UMC_UM8886A) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)))
+		return 1; /* UM8886A/BF pair */
+
+	if ((d->vendor == PCI_VENDOR_ID_OPTI) &&
+	    (d->device == PCI_DEVICE_ID_OPTI_82C558) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)))
+		return 1;
+
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	generic_remove_one	-	called when PCI IDE is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect an IDE device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void generic_remove_one(struct pci_dev *dev)
+{
+	printk("PCI IDE removal not yet supported\n");
+}
+
+static struct pci_device_id generic_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_NS,     PCI_DEVICE_ID_NS_87410,            PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8673F,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8886A,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ PCI_VENDOR_ID_UMC,    PCI_DEVICE_ID_UMC_UM8886BF,        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+	{ PCI_VENDOR_ID_HINT,   PCI_DEVICE_ID_HINT_VXPROII_IDE,    PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+	{ PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_82C561,          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
+	{ PCI_VENDOR_ID_OPTI,   PCI_DEVICE_ID_OPTI_82C558,         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"PCI IDE",
+	id_table:	generic_pci_tbl,
+	probe:		generic_init_one,
+	remove:		__devexit_p(generic_remove_one),
+};
+
+static int generic_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void generic_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(generic_ide_init);
+module_exit(generic_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for generic PCI IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/generic.h linux.20pre10-ac2/drivers/ide/pci/generic.h
--- linux.20pre10/drivers/ide/pci/generic.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/generic.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,161 @@
+#ifndef IDE_GENERIC_H
+#define IDE_GENERIC_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+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[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_NS,
+		device:		PCI_DEVICE_ID_NS_87410,
+		name:		"NS87410",
+		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,
+        },{	/* 1 */
+		vendor:		PCI_VENDOR_ID_PCTECH,
+		device:		PCI_DEVICE_ID_PCTECH_SAMURAI_IDE,
+		name:		"SAMURAI",
+		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,
+	},{	/* 2 */
+		vendor:		PCI_VENDOR_ID_HOLTEK,
+		device:		PCI_DEVICE_ID_HOLTEK_6565,
+		name:		"HT6565",
+		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,
+	},{	/* 3 */
+		vendor:		PCI_VENDOR_ID_UMC,
+		device:		PCI_DEVICE_ID_UMC_UM8673F,
+		name:		"UM8673F",
+		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,
+	},{	/* 4 */
+		vendor:		PCI_VENDOR_ID_UMC,
+		device:		PCI_DEVICE_ID_UMC_UM8886A,
+		name:		"UM8886A",
+		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,
+	},{	/* 5 */
+		vendor:		PCI_VENDOR_ID_UMC,
+		device:		PCI_DEVICE_ID_UMC_UM8886BF,
+		name:		"UM8886BF",
+		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,
+	},{	/* 6 */
+		vendor:		PCI_VENDOR_ID_HINT,
+		device:		PCI_DEVICE_ID_HINT_VXPROII_IDE,
+		name:		"HINT_IDE",
+		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,
+	},{	/* 7 */
+		vendor:		PCI_VENDOR_ID_VIA,
+		device:		PCI_DEVICE_ID_VIA_82C561,
+		name:		"VIA_IDE",
+		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,
+	},{	/* 8 */
+		vendor:		PCI_VENDOR_ID_OPTI,
+		device:		PCI_DEVICE_ID_OPTI_82C558,
+		name:		"OPTI621V",
+		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[] __devinitdata = {
+	{	/* 0 */
+		vendor:		0,
+		device:		0,
+		name:		"PCI_IDE",
+		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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/hpt34x.c linux.20pre10-ac2/drivers/ide/pci/hpt34x.c
--- linux.20pre10/drivers/ide/pci/hpt34x.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/hpt34x.c	2002-09-18 12:47:50.000000000 +0100
@@ -0,0 +1,383 @@
+/*
+ * linux/drivers/ide/hpt34x.c		Version 0.40	Sept 10, 2002
+ *
+ * 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/module.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 int __devinit hpt34x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &hpt34x_chipsets[id->driver_data];
+	static char *chipset_names[] = {"HPT343", "HPT345"};
+	u16 pcicmd = 0;
+
+	pci_read_config_word(dev, PCI_COMMAND, &pcicmd);
+
+	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);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	hpt34x_remove_one	-	called with an hpt34x is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect an hpt34x device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void hpt34x_remove_one(struct pci_dev *dev)
+{
+	printk("hpt34x removal not yet supported\n");
+}
+
+static struct pci_device_id hpt34x_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"HPT34x IDE",
+	id_table:	hpt34x_pci_tbl,
+	probe:		hpt34x_init_one,
+	remove:		__devexit_p(hpt34x_remove_one),
+};
+
+static int hpt34x_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void hpt34x_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(hpt34x_ide_init);
+module_exit(hpt34x_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for Highpoint 34x IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/hpt34x.h linux.20pre10-ac2/drivers/ide/pci/hpt34x.h
--- linux.20pre10/drivers/ide/pci/hpt34x.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/hpt34x.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,60 @@
+#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 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[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_TTI,
+		device:		PCI_DEVICE_ID_TTI_HPT343,
+		name:		"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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/hpt366.c linux.20pre10-ac2/drivers/ide/pci/hpt366.c
--- linux.20pre10/drivers/ide/pci/hpt366.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/hpt366.c	2002-09-18 12:47:35.000000000 +0100
@@ -0,0 +1,1238 @@
+/*
+ * linux/drivers/ide/hpt366.c		Version 0.34	Sept 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/module.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);
+}
+
+
+/**
+ *	hpt366_init_one	-	called when an HPT366 is found
+ *	@dev: the hpt366 device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit hpt366_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &hpt366_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	hpt366_remove_one	-	called when an HPT366 is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect a HPT366 device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void hpt366_remove_one(struct pci_dev *dev)
+{
+	printk("HPT366 removal not yet supported.\n");
+}
+
+static struct pci_device_id hpt366_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"HPT366 IDE",
+	id_table:	hpt366_pci_tbl,
+	probe:		hpt366_init_one,
+	remove:		__devexit_p(hpt366_remove_one),
+};
+
+static int hpt366_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void hpt366_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(hpt366_ide_init);
+module_exit(hpt366_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for Highpoint HPT366 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/hpt366.h linux.20pre10-ac2/drivers/ide/pci/hpt366.h
--- linux.20pre10/drivers/ide/pci/hpt366.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/hpt366.h	2002-10-11 00:35:04.000000000 +0100
@@ -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[] __devinitdata = {
+	{	/* 0 */
+		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
+	},{	/* 1 */
+		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
+	},{	/* 2 */
+		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
+	},{	/* 3 */
+		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
+	},{	/* 4 */
+		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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/it8172.c linux.20pre10-ac2/drivers/ide/pci/it8172.c
--- linux.20pre10/drivers/ide/pci/it8172.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/it8172.c	2002-09-18 12:44:01.000000000 +0100
@@ -0,0 +1,354 @@
+/*
+ *
+ * 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/module.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(&io_request_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(&io_request_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 int __devinit it8172_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &it8172_chipsets[id->driver_data];
+        if ((!(PCI_FUNC(dev->devfn) & 1) ||
+            (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))))
+                return 1; /* IT8172 is more than only a IDE controller */
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	it8172_remove_one	-	called with an IT8172 is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect an IT8172 device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void it8172_remove_one(struct pci_dev *dev)
+{
+	printk("IT8172 removal not yet supported.\n");
+}
+
+static struct pci_device_id it8172_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"IT8172IDE",
+	id_table:	it8172_pci_tbl,
+	probe:		it8172_init_one,
+	remove:		__devexit_p(it8172_remove_one),
+};
+
+static int it8172_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void it8172_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(it8172_ide_init);
+module_exit(it8172_ide_exit);
+
+MODULE_AUTHOR("SteveL@mvista.com");
+MODULE_DESCRIPTION("PCI driver module for ITE 8172 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/it8172.h linux.20pre10-ac2/drivers/ide/pci/it8172.h
--- linux.20pre10/drivers/ide/pci/it8172.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/it8172.h	2002-10-11 00:35:04.000000000 +0100
@@ -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[] __devinitdata = {
+	{	/* 0 */
+		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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/Makefile linux.20pre10-ac2/drivers/ide/pci/Makefile
--- linux.20pre10/drivers/ide/pci/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/Makefile	2002-09-11 20:25:59.000000000 +0100
@@ -0,0 +1,41 @@
+
+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_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
+
+# Must appear at the end of the block
+obj-$(CONFIG_BLK_DEV_GENERIC)		+= generic.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/ns87415.c linux.20pre10-ac2/drivers/ide/pci/ns87415.c
--- linux.20pre10/drivers/ide/pci/ns87415.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/ns87415.c	2002-09-18 12:43:24.000000000 +0100
@@ -0,0 +1,285 @@
+/*
+ * linux/drivers/ide/ns87415.c		Version 2.00  Sep. 10, 2002
+ *
+ * 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/module.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 int __devinit ns87415_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &ns87415_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	ns87415_remove_one	-	called with an NS87415 is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect an NS87415 device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void ns87415_remove_one(struct pci_dev *dev)
+{
+	printk("NS87415 removal not yet supported.\n");
+}
+
+static struct pci_device_id ns87415_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"NS87415IDE",
+	id_table:	ns87415_pci_tbl,
+	probe:		ns87415_init_one,
+	remove:		__devexit_p(ns87415_remove_one),
+};
+
+static int ns87415_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void ns87415_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(ns87415_ide_init);
+module_exit(ns87415_ide_exit);
+
+MODULE_AUTHOR("Mark Lord, Eddie Dost, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for NS87415 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/ns87415.h linux.20pre10-ac2/drivers/ide/pci/ns87415.h
--- linux.20pre10/drivers/ide/pci/ns87415.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/ns87415.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,33 @@
+#ifndef NS87415_H
+#define NS87415_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+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[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_NS,
+		device:		PCI_DEVICE_ID_NS_87415,
+		name:		"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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/nvidia.c linux.20pre10-ac2/drivers/ide/pci/nvidia.c
--- linux.20pre10/drivers/ide/pci/nvidia.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/nvidia.c	2002-09-18 12:43:08.000000000 +0100
@@ -0,0 +1,392 @@
+/*
+ * 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/module.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)
+{
+	static const u8 drive_pci[] = { 0x63, 0x62, 0x61, 0x60 };
+	static const 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 *);
+
+static int __devinit nforce_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &nvidia_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	nforce_remove_one	-	called with an nForce is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect an nForce device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void nforce_remove_one(struct pci_dev *dev)
+{
+	printk("nForce removal not yet supported.\n");
+}
+
+static struct pci_device_id nforce_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"nForce IDE",
+	id_table:	nforce_pci_tbl,
+	probe:		nforce_init_one,
+	remove:		__devexit_p(nforce_remove_one),
+};
+
+static int nforce_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void nforce_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(nforce_ide_init);
+module_exit(nforce_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for nVidia nForce IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/nvidia.h linux.20pre10-ac2/drivers/ide/pci/nvidia.h
--- linux.20pre10/drivers/ide/pci/nvidia.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/nvidia.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,50 @@
+#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 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[] __devinitdata = {
+	{
+		vendor:		PCI_VENDOR_ID_NVIDIA,
+		device:		PCI_DEVICE_ID_NVIDIA_NFORCE_IDE,
+		name:		"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,
+	}
+};
+
+
+#endif /* NFORCE_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/opti621.c linux.20pre10-ac2/drivers/ide/pci/opti621.c
--- linux.20pre10/drivers/ide/pci/opti621.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/opti621.c	2002-09-18 12:42:54.000000000 +0100
@@ -0,0 +1,420 @@
+/*
+ *  linux/drivers/ide/opti621.c		Version 0.7	Sept 10, 2002
+ *
+ *  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/module.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(&io_request_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(&io_request_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);
+}
+
+static int __devinit opti621_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &opti621_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	opti621_remove_one	-	called with an Opti621 is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect an Opti621 device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void opti621_remove_one(struct pci_dev *dev)
+{
+	printk("Opti621 removal not yet supported.\n");
+}
+
+static struct pci_device_id opti621_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"Opti621 IDE",
+	id_table:	opti621_pci_tbl,
+	probe:		opti621_init_one,
+	remove:		__devexit_p(opti621_remove_one),
+};
+
+static int opti621_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void opti621_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(opti621_ide_init);
+module_exit(opti621_ide_exit);
+
+MODULE_AUTHOR("Jaromir Koutek, Jan Harkes, Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for Opti621 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/opti621.h linux.20pre10-ac2/drivers/ide/pci/opti621.h
--- linux.20pre10/drivers/ide/pci/opti621.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/opti621.h	2002-10-11 00:35:04.000000000 +0100
@@ -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[] __devinitdata = {
+	{	/* 0 */
+		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,
+	},{	/* 1 */
+		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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/pdc202xx_new.c linux.20pre10-ac2/drivers/ide/pci/pdc202xx_new.c
--- linux.20pre10/drivers/ide/pci/pdc202xx_new.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/pdc202xx_new.c	2002-09-18 12:42:27.000000000 +0100
@@ -0,0 +1,718 @@
+/*
+ *  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/module.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);
+}
+
+/**
+ *	pdc202new_init_one	-	called when a pdc202xx is found
+ *	@dev: the pdc202new device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit pdc202new_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &pdcnew_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	pdc202new_remove_one	-	called when a pdc202xx is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect an IDE device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void pdc202new_remove_one(struct pci_dev *dev)
+{
+	printk("Promise IDE removal not yet supported.\n");
+}
+
+static struct pci_device_id pdc202new_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"Promise IDE",
+	id_table:	pdc202new_pci_tbl,
+	probe:		pdc202new_init_one,
+	remove:		__devexit_p(pdc202new_remove_one),
+};
+
+static int pdc202new_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void pdc202new_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(pdc202new_ide_init);
+module_exit(pdc202new_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
+MODULE_DESCRIPTION("PCI driver module for Promise PDC20268 and higher");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/pdc202xx_new.h linux.20pre10-ac2/drivers/ide/pci/pdc202xx_new.h
--- linux.20pre10/drivers/ide/pci/pdc202xx_new.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/pdc202xx_new.h	2002-10-11 00:35:04.000000000 +0100
@@ -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[] __devinitdata = {
+	{	/* 0 */
+		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,
+	},{	/* 1 */
+		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,
+	},{	/* 2 */
+		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,
+	},{	/* 3 */
+		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,
+	},{	/* 4 */
+		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,
+	},{	/* 5 */
+		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,
+	},{	/* 6 */
+		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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/pdc202xx_old.c linux.20pre10-ac2/drivers/ide/pci/pdc202xx_old.c
--- linux.20pre10/drivers/ide/pci/pdc202xx_old.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/pdc202xx_old.c	2002-09-18 20:37:39.000000000 +0100
@@ -0,0 +1,995 @@
+/*
+ *  linux/drivers/ide/pdc202xx.c	Version 0.36	Sept 11, 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/module.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;
+		case PCI_DEVICE_ID_PROMISE_20246:
+			ultra_66 = 0;
+			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 high_16	= hwif->dma_master;
+		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_data_dir(rq) == 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 high_16	= hwif->dma_master;
+		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);
+	u32 high_16		= hwif->dma_master;
+	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);
+}
+
+/**
+ *	pdc202xx_init_one	-	called when a PDC202xx is found
+ *	@dev: the pdc202xx device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &pdc202xx_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	pdc202xx_remove_one	-	called with the IDE to be unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect an IDE device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void pdc202xx_remove_one(struct pci_dev *dev)
+{
+	printk("Promise IDE removal not yet supported.\n");
+}
+
+static struct pci_device_id pdc202xx_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"Promise Old IDE",
+	id_table:	pdc202xx_pci_tbl,
+	probe:		pdc202xx_init_one,
+	remove:		__devexit_p(pdc202xx_remove_one),
+};
+
+static int pdc202xx_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void pdc202xx_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(pdc202xx_ide_init);
+module_exit(pdc202xx_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick, Frank Tiernan");
+MODULE_DESCRIPTION("PCI driver module for older Promise IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/pdc202xx_old.h linux.20pre10-ac2/drivers/ide/pci/pdc202xx_old.h
--- linux.20pre10/drivers/ide/pci/pdc202xx_old.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/pdc202xx_old.h	2002-10-11 00:35:04.000000000 +0100
@@ -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[] __devinitdata = {
+	{	/* 0 */
+		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,
+	},{	/* 1 */
+		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,
+	},{	/* 2 */
+		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,
+	},{	/* 3 */
+		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,
+	},{	/* 4 */
+		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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/pdcadma.c linux.20pre10-ac2/drivers/ide/pci/pdcadma.c
--- linux.20pre10/drivers/ide/pci/pdcadma.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/pdcadma.c	2002-09-18 12:41:34.000000000 +0100
@@ -0,0 +1,182 @@
+/*
+ * linux/drivers/ide/pdcadma.c		Version 0.05	Sept 10, 2002
+ *
+ * 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 int __devinit pdcadma_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &pdcadma_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 1;
+}
+
+/**
+ *	pdcadma_remove_one	-	called when a PDCADMA is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect a PDCADMA device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void pdcadma_remove_one(struct pci_dev *dev)
+{
+	printk("PDCADMA removal not yet supported.\n");
+}
+
+static struct pci_device_id pdcadma_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_PDC, PCI_DEVICE_ID_PDC_1841, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"PDCADMA-IDE",
+	id_table:	pdcadma_pci_tbl,
+	probe:		pdcadma_init_one,
+	remove:		__devexit_p(pdcadma_remove_one),
+};
+
+static int pdcadma_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void pdcadma_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(pdcadma_ide_init);
+module_exit(pdcadma_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for PDCADMA IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/pdcadma.h linux.20pre10-ac2/drivers/ide/pci/pdcadma.h
--- linux.20pre10/drivers/ide/pci/pdcadma.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/pdcadma.h	2002-10-11 00:35:04.000000000 +0100
@@ -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[] __devinitdata = {
+	{	/* 0 */
+		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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/piix.c linux.20pre10-ac2/drivers/ide/pci/piix.c
--- linux.20pre10/drivers/ide/pci/piix.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/piix.c	2002-09-18 21:26:54.000000000 +0100
@@ -0,0 +1,744 @@
+/*
+ *  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/module.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(&io_request_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(&io_request_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 __devinit 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_init_one	-	called when a PIIX is found
+ *	@dev: the piix device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit piix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &piix_pci_info[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	piix_remove_one	-	called with a PIIX is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect a PIIX device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void piix_remove_one(struct pci_dev *dev)
+{
+	printk("PIIX removal not yet supported.\n");
+}
+
+static struct pci_device_id piix_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371FB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82372FB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX,   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_11,PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14},
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_11, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"PIIX IDE",
+	id_table:	piix_pci_tbl,
+	probe:		piix_init_one,
+	remove:		__devexit_p(piix_remove_one),
+};
+
+static int piix_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void piix_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(piix_ide_init);
+module_exit(piix_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick, Andrzej Krzysztofowicz");
+MODULE_DESCRIPTION("PCI driver module for Intel PIIX IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/piix.h linux.20pre10-ac2/drivers/ide/pci/piix.h
--- linux.20pre10/drivers/ide/pci/piix.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/piix.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,275 @@
+#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[] __devinitdata = {
+	{
+		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 __devinit 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);
+
+
+/*
+ *	Table of the various PIIX capability blocks
+ *
+ */
+ 
+static ide_pci_device_t piix_pci_info[] __devinitdata = {
+	{	/* 0 */
+		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,
+	},{	/* 1 */
+		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,
+	},{	/* 2 */
+		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,
+	},{	/* 3 */
+		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,
+	},{	/* 4 */
+		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,
+	},{	/* 5 */
+		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,
+	},{	/* 6 */
+		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,
+	},{	/* 7 */
+		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,
+	},{	/* 8 */
+		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,
+	},{	/* 9 */
+		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,
+	},{	/* 10 */
+		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,
+	},{	/* 11 */
+		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,
+	},{	/* 12 */
+		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,
+	},{	/* 13 */
+		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,
+	},{	/* 14 */
+		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,
+	},{	/* 15 */
+		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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/rz1000.c linux.20pre10-ac2/drivers/ide/pci/rz1000.c
--- linux.20pre10/drivers/ide/pci/rz1000.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/rz1000.c	2002-09-18 12:41:18.000000000 +0100
@@ -0,0 +1,113 @@
+/*
+ *  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/module.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 int __devinit rz1000_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &rz1000_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	rz1000_remove_one	-	called with an RZ1000 is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect an RZ1000 device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void rz1000_remove_one(struct pci_dev *dev)
+{
+	printk("RZ1000 removal not yet supported.\n");
+}
+
+static struct pci_device_id rz1000_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"RZ1000 IDE",
+	id_table:	rz1000_pci_tbl,
+	probe:		rz1000_init_one,
+	remove:		__devexit_p(rz1000_remove_one),
+};
+
+static int rz1000_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void rz1000_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(rz1000_ide_init);
+module_exit(rz1000_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for RZ1000 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/rz1000.h linux.20pre10-ac2/drivers/ide/pci/rz1000.h
--- linux.20pre10/drivers/ide/pci/rz1000.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/rz1000.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,45 @@
+#ifndef RZ100X_H
+#define RZ100X_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static void init_hwif_rz1000(ide_hwif_t *);
+
+static ide_pci_device_t rz1000_chipsets[] __devinitdata = {
+{
+		vendor:		PCI_VENDOR_ID_PCTECH,
+		device:		PCI_DEVICE_ID_PCTECH_RZ1000,
+		name:		"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_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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/serverworks.c linux.20pre10-ac2/drivers/ide/pci/serverworks.c
--- linux.20pre10/drivers/ide/pci/serverworks.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/serverworks.c	2002-09-18 12:40:59.000000000 +0100
@@ -0,0 +1,840 @@
+/*
+ * linux/drivers/ide/serverworks.c		Version 0.7	10 Sept 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/module.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);
+}
+
+
+/**
+ *	svwks_init_one	-	called when a OSB/CSB is found
+ *	@dev: the svwks device
+ *	@id: the matching pci id
+ *
+ *	Called when the PCI registration layer (or the IDE initialization)
+ *	finds a device matching our IDE device tables.
+ */
+ 
+static int __devinit svwks_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &serverworks_chipsets[id->driver_data];
+
+	if (dev->device != d->device)
+		BUG();
+	d->init_setup(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	svwks_remove_one	-	called when an OSB/CSB is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect a SVWKS device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void svwks_remove_one(struct pci_dev *dev)
+{
+	printk("SVWKS removal not yet supported.\n");
+}
+
+static struct pci_device_id svwks_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"Serverworks IDE",
+	id_table:	svwks_pci_tbl,
+	probe:		svwks_init_one,
+	remove:		__devexit_p(svwks_remove_one),
+#if 0	/* FIXME: implement */
+	suspend:	,
+	resume:		,
+#endif
+};
+
+static int svwks_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void svwks_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(svwks_ide_init);
+module_exit(svwks_ide_exit);
+
+MODULE_AUTHOR("Michael Aubry. Andrzej Krzysztofowicz, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for Serverworks OSB4/CSB5/CSB6 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/serverworks.h linux.20pre10-ac2/drivers/ide/pci/serverworks.h
--- linux.20pre10/drivers/ide/pci/serverworks.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/serverworks.h	2002-10-11 00:35:04.000000000 +0100
@@ -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[] __devinitdata = {
+	{	/* 0 */
+		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,
+	},{	/* 1 */
+		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,
+	},{	/* 2 */
+		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,
+	},{	/* 3 */
+		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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/siimage.c linux.20pre10-ac2/drivers/ide/pci/siimage.c
--- linux.20pre10/drivers/ide/pci/siimage.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/siimage.c	2002-09-18 12:40:31.000000000 +0100
@@ -0,0 +1,894 @@
+/*
+ * linux/drivers/ide/siimage.c		Version 1.01	Sept 11, 2002
+ *
+ * Copyright (C) 2001-2002	Andre Hedrick <andre@linux-ide.org>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.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 int __devinit siimage_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &siimage_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	siimage_remove_one	-	called when an SI IDE is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect an IDE device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void siimage_remove_one(struct pci_dev *dev)
+{
+	printk("SiImage IDE removal not yet supported.\n");
+}
+
+static struct pci_device_id siimage_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"SiI IDE",
+	id_table:	siimage_pci_tbl,
+	probe:		siimage_init_one,
+	remove:		__devexit_p(siimage_remove_one),
+};
+
+static int siimage_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void siimage_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(siimage_ide_init);
+module_exit(siimage_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for SiI IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/siimage.h linux.20pre10-ac2/drivers/ide/pci/siimage.h
--- linux.20pre10/drivers/ide/pci/siimage.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/siimage.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,150 @@
+#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 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[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_CMD,
+		device:		PCI_DEVICE_ID_SII_680,
+		name:		"SiI680",
+		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,
+	},{	/* 1 */
+		vendor:		PCI_VENDOR_ID_CMD,
+		device:		PCI_DEVICE_ID_SII_3112,
+		name:		"SiI3112 Serial ATA",
+		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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/sis5513.c linux.20pre10-ac2/drivers/ide/pci/sis5513.c
--- linux.20pre10/drivers/ide/pci/sis5513.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/sis5513.c	2002-09-18 12:39:17.000000000 +0100
@@ -0,0 +1,1079 @@
+/*
+ * linux/drivers/ide/sis5513.c		Version 0.14ac	Sept 11, 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/module.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 int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &sis5513_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	sis5513_remove_one	-	called when SIS IDE is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect a SIS IDE device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void sis5513_remove_one(struct pci_dev *dev)
+{
+	printk("SIS IDE removal not yet supported.\n");
+}
+
+static struct pci_device_id sis5513_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"SIS IDE",
+	id_table:	sis5513_pci_tbl,
+	probe:		sis5513_init_one,
+	remove:		__devexit_p(sis5513_remove_one),
+};
+
+static int sis5513_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void sis5513_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(sis5513_ide_init);
+module_exit(sis5513_ide_exit);
+
+MODULE_AUTHOR("Lionel Bouton, L C Chang, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for SIS IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/sis5513.h linux.20pre10-ac2/drivers/ide/pci/sis5513.h
--- linux.20pre10/drivers/ide/pci/sis5513.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/sis5513.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,54 @@
+#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 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[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_SI,
+		device:		PCI_DEVICE_ID_SI_5513,
+		name:		"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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/sl82c105.c linux.20pre10-ac2/drivers/ide/pci/sl82c105.c
--- linux.20pre10/drivers/ide/pci/sl82c105.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/sl82c105.c	2002-09-18 12:40:09.000000000 +0100
@@ -0,0 +1,336 @@
+/*
+ * 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 <linuyx/module.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 int __devinit sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &slc82c105_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	sl82c105_remove_one	-	called with an SLC82c105 is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect an W82C105 device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void sl82c105_remove_one(struct pci_dev *dev)
+{
+	printk("W82C105 removal not yet supported.\n");
+}
+
+static struct pci_device_id sl82c105_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"W82C105 IDE",
+	id_table:	sl82c105_pci_tbl,
+	probe:		sl82c105_init_one,
+	remove:		__devexit_p(sl82c105_remove_one),
+};
+
+static int sl82c105_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void sl82c105_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(sl82c105_ide_init);
+module_exit(sl82c105_ide_exit);
+
+MODULE_DESCRIPTION("PCI driver module for W82C105 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/sl82c105.h linux.20pre10-ac2/drivers/ide/pci/sl82c105.h
--- linux.20pre10/drivers/ide/pci/sl82c105.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/sl82c105.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,34 @@
+#ifndef W82C105_H
+#define W82C105_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+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[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_WINBOND,
+		device:		PCI_DEVICE_ID_WINBOND_82C105,
+		name:		"W82C105",
+		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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/slc90e66.c linux.20pre10-ac2/drivers/ide/pci/slc90e66.c
--- linux.20pre10/drivers/ide/pci/slc90e66.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/slc90e66.c	2002-09-18 12:39:51.000000000 +0100
@@ -0,0 +1,421 @@
+/*
+ *  linux/drivers/ide/slc90e66.c	Version 0.11	September 11, 2002
+ *
+ *  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/module.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(&io_request_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(&io_request_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 int __devinit slc90e66_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &slc90e66_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	slc90e66_remove_one	-	called with an slc90e66 is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect an slc90e66 device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void slc90e66_remove_one(struct pci_dev *dev)
+{
+	printk("slc90e66 removal not yet supported.\n");
+}
+
+static struct pci_device_id slc90e66_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"SLC90e66 IDE",
+	id_table:	slc90e66_pci_tbl,
+	probe:		slc90e66_init_one,
+	remove:		__devexit_p(slc90e66_remove_one),
+};
+
+static int slc90e66_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void slc90e66_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(slc90e66_ide_init);
+module_exit(slc90e66_ide_exit);
+
+MODULE_AUTHOR("Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for SLC90E66 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/slc90e66.h linux.20pre10-ac2/drivers/ide/pci/slc90e66.h
--- linux.20pre10/drivers/ide/pci/slc90e66.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/slc90e66.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,56 @@
+#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 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[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_EFAR,
+		device:		PCI_DEVICE_ID_EFAR_SLC90E66_1,
+		name:		"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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/trm290.c linux.20pre10-ac2/drivers/ide/pci/trm290.c
--- linux.20pre10/drivers/ide/pci/trm290.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/trm290.c	2002-09-18 12:39:30.000000000 +0100
@@ -0,0 +1,452 @@
+/*
+ *  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/module.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, PCI_DMA_TODEVICE))) {
+		/* 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->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 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, PCI_DMA_FROMDEVICE))) {
+		/* 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->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 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 *);
+
+static int __devinit trm290_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &trm290_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	trm290_remove_one	-	called when an trm290 is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect a trm290 device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void trm290_remove_one(struct pci_dev *dev)
+{
+	printk("trm290 removal not yet supported.\n");
+}
+
+static struct pci_device_id trm290_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"TRM290 IDE",
+	id_table:	trm290_pci_tbl,
+	probe:		trm290_init_one,
+	remove:		__devexit_p(trm290_remove_one),
+};
+
+static int trm290_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void trm290_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(trm290_ide_init);
+module_exit(trm290_ide_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("PCI driver module for Tekram TRM290 IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/trm290.h linux.20pre10-ac2/drivers/ide/pci/trm290.h
--- linux.20pre10/drivers/ide/pci/trm290.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/trm290.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,32 @@
+#ifndef TRM290_H
+#define TRM290_H
+
+#include <linux/config.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+extern void init_hwif_trm290(ide_hwif_t *);
+
+static ide_pci_device_t trm290_chipsets[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_TEKRAM,
+		device:		PCI_DEVICE_ID_TEKRAM_DC290,
+		name:		"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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/via82cxxx.c linux.20pre10-ac2/drivers/ide/pci/via82cxxx.c
--- linux.20pre10/drivers/ide/pci/via82cxxx.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/via82cxxx.c	2002-09-18 12:38:56.000000000 +0100
@@ -0,0 +1,691 @@
+/*
+ * $Id: via82cxxx.c,v 3.35-ac2 2002/09/111 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/module.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:                        %#lx", 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 *);
+
+static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	ide_pci_device_t *d = &via82cxxx_chipsets[id->driver_data];
+	if (dev->device != d->device)
+		BUG();
+	ide_setup_pci_device(dev, d);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/**
+ *	via_remove_one	-	called with a VIA IDE interface is unplugged
+ *	@dev: the device that was removed
+ *
+ *	Disconnect a VIA IDE device that has been unplugged either by hotplug
+ *	or by a more civilized notification scheme. Not yet supported.
+ */
+ 
+static void via_remove_one(struct pci_dev *dev)
+{
+	printk("VIA IDE removal not yet supported.\n");
+}
+
+static struct pci_device_id via_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ 0, },
+};
+
+static struct pci_driver driver = {
+	name:		"VIA IDE",
+	id_table:	via_pci_tbl,
+	probe:		via_init_one,
+	remove:		__devexit_p(via_remove_one),
+};
+
+static int via_ide_init(void)
+{
+	return ide_pci_register_driver(&driver);
+}
+
+static void via_ide_exit(void)
+{
+	ide_pci_unregister_driver(&driver);
+}
+
+module_init(via_ide_init);
+module_exit(via_ide_exit);
+
+MODULE_AUTHOR("Vojtech Pavlik, Michel Aubry, Jeff Garzik, Andre Hedrick");
+MODULE_DESCRIPTION("PCI driver module for VIA IDE");
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pci/via82cxxx.h linux.20pre10-ac2/drivers/ide/pci/via82cxxx.h
--- linux.20pre10/drivers/ide/pci/via82cxxx.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pci/via82cxxx.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,67 @@
+#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 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[] __devinitdata = {
+	{	/* 0 */
+		vendor:		PCI_VENDOR_ID_VIA,
+		device:		PCI_DEVICE_ID_VIA_82C576_1,
+		name:		"VP_IDE",
+		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,
+	},{	/* 1 */
+		vendor:		PCI_VENDOR_ID_VIA,
+		device:		PCI_DEVICE_ID_VIA_82C586_1,
+		name:		"VP_IDE",
+		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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pdc202xx.c linux.20pre10-ac2/drivers/ide/pdc202xx.c
--- linux.20pre10/drivers/ide/pdc202xx.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pdc202xx.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,1188 +0,0 @@
-/*
- *  linux/drivers/ide/pdc202xx.c	Version 0.32	Feb. 27, 2002
- *
- *  Copyright (C) 1998-2000	Andre Hedrick <andre@linux-ide.org>
- *  May be copied or modified under the terms of the GNU General Public License
- *
- *  Promise Ultra66 cards with BIOS v1.11 this
- *  compiled into the kernel if you have more than one card installed.
- *
- *  Promise Ultra100 cards with BIOS v2.01 this
- *  compiled into the kernel if you have more than one card installed.
- *
- *  Promise Ultra100TX2 with BIOS v2.10 & Ultra133TX2 with BIOS v2.20
- *  support 8 hard drives on UDMA mode.
- *
- *  Linux kernel will misunderstand FastTrak ATA-RAID series as Ultra
- *  IDE Controller, UNLESS you enable "CONFIG_PDC202XX_FORCE"
- *  That's you can use FastTrak ATA-RAID controllers as IDE controllers.
- *
- *  History :
- *  05/22/01    v1.20 b1
- *           (1) support PDC20268
- *           (2) fix cable judge function
- *  08/22/01    v1.20 b2
- *           (1) support ATA-133 PDC20269/75
- *           (2) support UDMA Mode 6
- *           (3) fix proc report information
- *           (4) set ATA133 timing
- *           (5) fix ultra dma bit 14 selectable
- *           (6) support 32bit LBA
- *  09/11/01    v1.20 b3 
- *           (1) fix eighty_ninty_three()
- *           (2) fix offset address 0x1c~0x1f
- *  10/30/01    v1.20 b4
- *           (1) fix 48bit LBA HOB bit
- *           (2) force rescan drive under PIO modes if need
- *  11/02/01    v1.20.0.5
- *           (1) could be patched with ext3 filesystem code
- *  11/06/01    v1.20.0.6
- *           (1) fix LBA48 drive running without Promise controllers
- *           (2) fix LBA48 drive running under PIO modes
- *  01/28/02    v1.20.0.6
- *           (1) release for linux IDE Group kernel 2.4.18
- *           (2) add version and controller info to proc
- *  05/23/02    v1.20.0.7
- *           (1) disable PDC20262 running with 48bit
- *           (2) Add quirk drive lists for PDC20265/67
- *
- *  Copyright (C) 1999-2002 Promise Technology, Inc.
- *  Author: Frank Tiernan <frankt@promise.com>
- *          PROMISE pdc202xx IDE Controller driver MAINTAINERS
- *  Released under terms of General Public License
- */
- 
-#define VERSION	"1.20.0.7"
-#define VERDATE "2002-05-23"
-#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 */
-extern char *ide_media_verbose(ide_drive_t *);
-static struct pci_dev *bmide_dev;
-static struct hd_driveid *id[4];
-static int speed_rate[4];
-
-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;
-	u16 word88 = 0;
-	int udmasel[4] = {0,0,0,0}, piosel[4] = {0,0,0,0};
-	int i = 0, hd = 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, "\nPROMISE Ultra series driver Ver %s %s Adapter: ", VERSION, VERDATE);
-	switch(dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20275:
-			p += sprintf(p, "MBUltra133\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20269:
-			p += sprintf(p, "Ultra133 TX2\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20268:
-			p += sprintf(p, "Ultra100 TX2\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20267:
-			p += sprintf(p, "Ultra100\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20265:
-			p += sprintf(p, "Ultra100 on M/B\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20262:
-			p += sprintf(p, "Ultra66\n");
-			break;
-		case PCI_DEVICE_ID_PROMISE_20246:
-			p += sprintf(p, "Ultra33\n");
-			reg50h |= 0x0c00;
-			break;
-		default:
-			p += sprintf(p, "Ultra Series\n");
-			break;
-	}
-
-	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                           %s\n",
-		(sc1a & 0x01) ? "MASTER" : "PCI   ",
-		(sc1b & 0x01) ? "MASTER" : "PCI   ");
-	p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n");
-	p += sprintf(p, "DMA enabled:    %s              %s             %s               %s\n",
-		(id[0]!=NULL && (c0&0x20))?"yes":"no ",(id[1]!=NULL && (c0&0x40))?"yes":"no ",
-		(id[2]!=NULL && (c1&0x20))?"yes":"no ",(id[3]!=NULL && (c1&0x40))?"yes":"no ");
-	for( hd = 0; hd < 4 ; hd++) {
-		if (id[hd] == NULL)
-			continue;
-		word88 = id[hd]->dma_ultra;
-		for ( i = 7 ; i >= 0 ; i--)
-			if (word88 >> (i+8)) {
-				udmasel[hd] = i;	/* get select UDMA mode */
-				break;
-			}
-		piosel[hd] = (id[hd]->eide_pio_modes >= 0x02) ? 4 : 3;
-        }
-	p += sprintf(p, "UDMA Mode:      %d                %d               %d                 %d\n",
-		udmasel[0], udmasel[1], udmasel[2], udmasel[3]);
-	p += sprintf(p, "PIO Mode:       %d                %d               %d                 %d\n",
-		piosel[0], piosel[1], piosel[2], piosel[3]);
-#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;
-	
-	p = pdc202xx_info(buffer, bmide_dev);
-	return p-buffer;	/* => must be less than 4k! */
-}
-#endif  /* defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS) */
-
-byte pdc202xx_proc = 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
-};
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/* 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 */
-
-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 speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	unsigned int		drive_conf;
-	int			err = 0, i = 0, j = hwif->channel ? 2 : 0 ;
-	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);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (speed >= XFER_SW_DMA_0) {
-		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);
-		}
-	} else {
-#else
-	{
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		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);
-		}
-	}
-
-	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);
-
-	for ( i = 0; i < 2; i++)
-		if (hwif->drives[i].present)
-	  		id[i+j] = hwif->drives[i].id;	/* get identify structs */
-
-	switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		/* case XFER_UDMA_6: */
-		case XFER_UDMA_5:
-		case XFER_UDMA_4:	TB = 0x20; TC = 0x01; break;	/* speed 8 == UDMA mode 4 */
-		case XFER_UDMA_3:	TB = 0x40; TC = 0x02; break;	/* speed 7 == UDMA mode 3 */
-		case XFER_UDMA_2:	TB = 0x20; TC = 0x01; break;	/* speed 6 == UDMA mode 2 */
-		case XFER_UDMA_1:	TB = 0x40; TC = 0x02; break;	/* speed 5 == UDMA mode 1 */
-		case XFER_UDMA_0:	TB = 0x60; TC = 0x03; break;	/* speed 4 == UDMA mode 0 */
-		case XFER_MW_DMA_2:	TB = 0x60; TC = 0x03; break;	/* speed 4 == MDMA mode 2 */
-		case XFER_MW_DMA_1:	TB = 0x60; TC = 0x04; break;	/* speed 3 == MDMA mode 1 */
-		case XFER_MW_DMA_0:	TB = 0x60; TC = 0x05; break;	/* speed 2 == MDMA mode 0 */
-		case XFER_SW_DMA_2:	TB = 0x60; TC = 0x05; break;	/* speed 0 == SDMA mode 2 */
-		case XFER_SW_DMA_1:	TB = 0x80; TC = 0x06; break;	/* speed 1 == SDMA mode 1 */
-		case XFER_SW_DMA_0:	TB = 0xC0; TC = 0x0B; break;	/* speed 0 == SDMA mode 0 */
-#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;
-	}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-        if (speed >= XFER_SW_DMA_0) {
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
-		pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC);
-	} else {
-#else
-	{
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-		pci_write_config_byte(dev, (drive_pci), AP|TA);
-		pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB);
-	}
-
-#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 (!drive->init_speed)
-		drive->init_speed = speed;
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-
-#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 err;
-}
-
-static int pdc202xx_new_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	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;
-	int set_speed		= 0, i=0, j=hwif->channel ? 2:0;
-	int                     err;
-
-	/* Setting tHOLD bit to 0 if using UDMA mode 2 */
-	if (speed == XFER_UDMA_2) {
-		OUT_BYTE((thold + adj), indexreg);
-		OUT_BYTE((IN_BYTE(datareg) & 0x7f), datareg);
-	}
-	
-	/* We need to set ATA133 timing if ATA133 drives exist */
-	if (speed>=XFER_UDMA_6)
-		set_speed=1;
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-#if PDC202XX_DEBUG_DRIVE_INFO
-	printk("%s: Before set_feature = %s, word88 = %#x\n",
-		drive->name, ide_xfer_verbose(speed), drive->id->dma_ultra );
-#endif /* PDC202XX_DEBUG_DRIVE_INFO */
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;	
-	for ( i = 0 ; i < 2 ; i++)
-		if (hwif->drives[i].present) {
-	  		id[i+j] = hwif->drives[i].id;	/* get identify structs */
-	 		speed_rate[i+j] = speed;	/* get current speed */
-	 	}
-	if (set_speed) {
-		for (i=0; i<4; i++) {
-			if (id[i]==NULL)
-				continue;
-			switch(speed_rate[i]) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-				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:
-			}
-		}
-	}
-	return err;
-}
-
-/*   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, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	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 new_chip		= 0;
-	byte unit		= (drive->select.b.unit & 0x01);
-	unsigned int		drive_conf;
-	byte			drive_pci = 0;
-	byte			test1, test2, speed = -1;
-	byte			AP;
-	unsigned short		EP;
-	byte CLKSPD		= 0;
-	byte clockreg		= high_16 + 0x11;
-	byte udma_33		= ultra;
-	byte udma_66		= ((eighty_ninty_three(drive)) && udma_33) ? 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;
-	byte ultra_100		= ((id->dma_ultra & 0x0020) ||
-				   (ultra_66)) ? 1 : 0;
-	byte ultra_133		= ((id->dma_ultra & 0x0040) ||
-				   (ultra_100)) ? 1 : 0;
-
-	switch(dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		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));
-			new_chip = 1;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-			udma_100 = (udma_66) ? 1 : 0;
-			OUT_BYTE(0x0b, (hwif->dma_base + 1));
-			cable = ((IN_BYTE((hwif->dma_base + 3)) & 0x04));
-			new_chip = 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);
-			new_chip = 0;
-			CLKSPD = IN_BYTE(clockreg);
-			break;
-		case PCI_DEVICE_ID_PROMISE_20262:
-			pci_read_config_word(dev, 0x50, &EP);
-			cable = (EP & c_mask);
-			new_chip = 0;
-			CLKSPD = IN_BYTE(clockreg);
-			break;
-		default:
-			udma_100 = 0; udma_133 = 0; cable = 0; new_chip = 1;
-			break;
-	}
-
-	/*
-	 * 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) || (ultra_100) || (ultra_133)) && (cable)) {
-#ifdef DEBUG
-		printk("ULTRA66: %s channel of Ultra 66 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 (!new_chip)
-		OUT_BYTE(CLKSPD & ~mask, clockreg);
-		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; udma_100 = 0; udma_133 = 0;
-	} else {
-		if ((ultra_66) || (ultra_100) || (ultra_133)) {
-			/*
-			 * 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 & 0x0040) ||
-				    (hwif->drives[!(drive->dn%2)].id->dma_ultra
-& 0x0020) ||
-				    (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0010) ||
-				    (hwif->drives[!(drive->dn%2)].id->dma_ultra & 0x0008)) {
-					OUT_BYTE(CLKSPD | mask, clockreg);
-				} else {
-					OUT_BYTE(CLKSPD & ~mask, clockreg);
-				}
-			} else { /* udma4 drive by itself */
-				OUT_BYTE(CLKSPD | mask, clockreg);
-			}
-		}
-	}
-
-	if (new_chip)	goto chipset_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)
-		return ide_dma_off_quietly;
-	
-	if (new_chip) {
-		if (id->capability & 4) {	/* IORDY_EN & PREFETCH_EN */
-			OUT_BYTE((iordy + adj), indexreg);
-			OUT_BYTE((IN_BYTE(datareg)|0x03), datareg);
-		}
-	}
-	else {
-		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);
-	}
-
-	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)&&(!new_chip))	speed = XFER_SW_DMA_2;
-	else if ((id->dma_1word & 0x0002)&&(!new_chip))	speed = XFER_SW_DMA_1;
-	else if ((id->dma_1word & 0x0001)&&(!new_chip))	speed = XFER_SW_DMA_0;
-	else {
-		/* restore original pci-config space */
-		if (!new_chip)
-			pci_write_config_dword(dev, drive_pci, drive_conf);
-		return ide_dma_off_quietly;
-	}
-
-	outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-	(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;
-
-	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, 1);
-				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, 0);
-				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, 0);
-			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:
-		(void) config_chipset_for_pio(drive, 5);
-	}
-
-	return HWIF(drive)->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 hardware48fix	= 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 dma_base	= hwif->dma_base;
-	unsigned long atapi_port= hwif->channel ? high_16+0x24 : high_16+0x20;
-
-	switch (dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-			newchip = 1;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-			hardware48fix = 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.
-			 */
-			/* Enable ATAPI UDMA port for 48bit data on PDC20267 */
-			if ((drive->addressing) && (hardware48fix)) {
-				struct request *rq = HWGROUP(drive)->rq;
-				unsigned long word_count = 0;
-				unsigned long hankval = 0;
-				byte	clockreg = high_16 + 0x11;
-				
-				OUT_BYTE(clock|(hwif->channel ? 0x08:0x02), clockreg);
-				word_count = (rq->nr_sectors << 8);
-				hankval = (rq->cmd == READ) ? 0x05<<24 : 0x06<<24;
-				hankval = hankval | word_count ;
-				outl(hankval, atapi_port);
-			}  
-			break;
-		case ide_dma_end:
-			/* Disable ATAPI UDMA port for 48bit data on PDC20267 */
-			if ((drive->addressing) && (hardware48fix)) {
-				unsigned long hankval = 0;
-				byte	clockreg = high_16 + 0x11;
-				
-			    	outl(hankval, atapi_port);	/* zero out extra */
-				clock = IN_BYTE(clockreg);
-				OUT_BYTE(clock & ~(hwif->channel ? 0x08:0x02), clockreg);
-			}
-			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(drive)->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(drive)->resetproc != NULL)
-				HWIF(drive)->resetproc(drive);
-		default:
-			break;
-	}
-	return ide_dmaproc(func, drive);	/* use standard DMA stuff */
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-void pdc202xx_reset (ide_drive_t *drive)
-{
-	OUT_BYTE(0x04,IDE_CONTROL_REG);
-	mdelay(1000);
-	OUT_BYTE(0x00,IDE_CONTROL_REG);
-	mdelay(1000);
-	printk("PDC202XX: %s channel reset.\n",
-		HWIF(drive)->channel ? "Secondary" : "Primary");
-}
-
-/*
- * 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		= inb(high_16 + 0x001f);
-
-	if (!hwif)
-		return -EINVAL;
-
-//	hwif->bus_state = state;
-
-	if (state) {
-		outb(sc1f | 0x08, high_16 + 0x001f);
-	} else {
-		outb(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);
-
-	OUT_BYTE(udma_speed_flag | 0x10, high_16 + 0x001f);
-	mdelay(100);
-	OUT_BYTE(udma_speed_flag & ~0x10, high_16 + 0x001f);
-	mdelay(2000);	/* 2 seconds ?! */
-
-	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);
-	}
-	
-	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 */
-
-#if defined(DISPLAY_PDC202XX_TIMINGS) && defined(CONFIG_PROC_FS)
-	if (!pdc202xx_proc) {
-		pdc202xx_proc = 1;
-		bmide_dev = dev;
-		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_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-			OUT_BYTE(0x0b, (hwif->dma_base + 1));
-			return (!(IN_BYTE((hwif->dma_base + 3)) & 0x04));
-			/* check 80pin cable */
-		default:
-			pci_read_config_word(hwif->pci_dev, 0x50, &CIS);
-			return (!(CIS & mask));
-			/* check 80pin cable */
-	}
-}
-
-void __init ide_init_pdc202xx (ide_hwif_t *hwif)
-{
-	hwif->tuneproc  = &pdc202xx_tune_drive;
-	hwif->quirkproc = &pdc202xx_quirkproc;
-	hwif->resetproc = &pdc202xx_reset;
-
-        switch(hwif->pci_dev->device) {
-		case PCI_DEVICE_ID_PROMISE_20276:
-		case PCI_DEVICE_ID_PROMISE_20275:
-		case PCI_DEVICE_ID_PROMISE_20269:
-		case PCI_DEVICE_ID_PROMISE_20268:
-		case PCI_DEVICE_ID_PROMISE_20270:
-			hwif->speedproc = &pdc202xx_new_tune_chipset;
-			break;
-		case PCI_DEVICE_ID_PROMISE_20267:
-		case PCI_DEVICE_ID_PROMISE_20265:
-		case PCI_DEVICE_ID_PROMISE_20262:
-			hwif->busproc   = &pdc202xx_tristate;
-		case PCI_DEVICE_ID_PROMISE_20246:
-			hwif->speedproc = &pdc202xx_tune_chipset;
-		default:
-			break;
-	}
-
-#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 */
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		hwif->dmaproc = &pdc202xx_dmaproc;
-		if (!noautodma)
-			hwif->autodma = 1;
-	} else {
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-		hwif->autodma = 0;
-	}
-#else /* !CONFIG_BLK_DEV_IDEDMA */
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pdc4030.c linux.20pre10-ac2/drivers/ide/pdc4030.c
--- linux.20pre10/drivers/ide/pdc4030.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pdc4030.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,578 +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"
-
-#ifdef CONFIG_IDE_TASKFILE_IO
-#  define __TASKFILE__IO
-#else /* CONFIG_IDE_TASKFILE_IO */
-#  undef __TASKFILE__IO
-#endif /* CONFIG_IDE_TASKFILE_IO */
-
-/*
- * 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;
-	}
-	ide_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
-		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;
-
-	if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
-		return ide_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;
-	ide_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
-#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, (unsigned long) rq->buffer,
-	       rq->nr_sectors-nsect);
-#endif
-	rq->sector += nsect;
-	rq->buffer += nsect<<9;
-	rq->errors = 0;
-	rq->nr_sectors -= nsect;
-	total_remaining = rq->nr_sectors;
-	if ((rq->current_nr_sectors -= nsect) <= 0) {
-		ide_end_request(1, HWGROUP(drive));
-	}
-/*
- * 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) {
-			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
-			return ide_started;
-		}
-		printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left "
-		       "!DRQ !BUSY\n", drive->name);
-		return ide_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)) {
-			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 ide_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
-	for (i = rq->nr_sectors; i > 0; ) {
-		i -= rq->current_nr_sectors;
-		ide_end_request(1, hwgroup);
-	}
-	return ide_stopped;
-}
-
-/*
- * 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)) {
-			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 ide_error (drive, "write timeout", GET_STAT());
-	}
-
-	/*
-	 * Now write out last 4 sectors and poll for not BUSY
-	 */
-	ide_multwrite(drive, 4);
-	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-	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
-	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
-
-	/*
-	 * 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 (ide_multwrite(drive, rq->nr_sectors - 4))
-			return ide_stopped;
-		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		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 (ide_multwrite(drive, rq->nr_sectors))
-			return ide_stopped;
-		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
-		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
-		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.
- */
-ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq)
-{
-	ide_startstop_t startstop;
-	unsigned long timeout;
-	byte stat;
-
-	switch(rq->cmd) {
-		case READ:
-#ifndef __TASKFILE__IO
-			OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG);
-#endif
-/*
- * 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
-					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 __TASKFILE__IO
-			OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG);
-#endif
-			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)
-				__cli();	/* local CPU only */
-			HWGROUP(drive)->wrq = *rq; /* scratchpad */
-			return promise_write(drive);
-		default:
-			printk("KERN_WARNING %s: bad command: %d\n", drive->name, rq->cmd);
-			ide_end_request(0, HWGROUP(drive));
-			return ide_stopped;
-	}
-}
-
-#ifdef __TASKFILE__IO
-
-ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
-{
-	struct hd_drive_task_hdr taskfile;
-
-	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;
-
-	do_taskfile(drive, &taskfile, NULL, NULL);
-	return do_pdc4030_io(drive, rq);
-}
-#endif
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pdc4030.h linux.20pre10-ac2/drivers/ide/pdc4030.h
--- linux.20pre10/drivers/ide/pdc4030.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pdc4030.h	1970-01-01 01:00:00.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pdcraid.c linux.20pre10-ac2/drivers/ide/pdcraid.c
--- linux.20pre10/drivers/ide/pdcraid.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pdcraid.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,646 +0,0 @@
-/*
-   pdcraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
-
-   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, or (at your option)
-   any later version.
-   
-   You should have received a copy of the GNU General Public License
-   (for example /usr/src/linux/COPYING); if not, write to the Free
-   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
-   
-   Authors: 	Arjan van de Ven <arjanv@redhat.com>
-   		
-   Based on work done by Sren Schmidt for FreeBSD  
-
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/blkdev.h>
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/ioctl.h>
-
-#include <linux/ide.h>
-#include <asm/uaccess.h>
-
-#include "ataraid.h"
-
-static int pdcraid_open(struct inode * inode, struct file * filp);
-static int pdcraid_release(struct inode * inode, struct file * filp);
-static int pdcraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
-static int pdcraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
-static int pdcraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
-
-struct disk_dev {
-	int major;
-	int minor;
-	int device;
-};
-
-static struct disk_dev devlist[]= {
-	{IDE0_MAJOR,  0,  -1 },
-	{IDE0_MAJOR, 64,  -1 },
-	{IDE1_MAJOR,  0,  -1 },
-	{IDE1_MAJOR, 64,  -1 },
-	{IDE2_MAJOR,  0,  -1 },
-	{IDE2_MAJOR, 64,  -1 },
-	{IDE3_MAJOR,  0,  -1 },
-	{IDE3_MAJOR, 64,  -1 },
-	{IDE4_MAJOR,  0,  -1 },
-	{IDE4_MAJOR, 64,  -1 },
-	{IDE5_MAJOR,  0,  -1 },
-	{IDE5_MAJOR, 64,  -1 },
-	{IDE6_MAJOR,  0,  -1 },
-	{IDE6_MAJOR, 64,  -1 },
-};
-
-
-struct pdcdisk {
-	kdev_t	device;
-	unsigned long sectors;
-	struct block_device *bdev;
-	unsigned long last_pos;
-};
-
-struct pdcraid {
-	unsigned int stride;
-	unsigned int disks;
-	unsigned long sectors;
-	struct geom geom;
-	
-	struct pdcdisk disk[8];
-	
-	unsigned long cutoff[8];
-	unsigned int cutoff_disks[8];
-};
-
-static struct raid_device_operations pdcraid0_ops = {
-        open:                   pdcraid_open,
-	release:                pdcraid_release,
-	ioctl:			pdcraid_ioctl,
-	make_request:		pdcraid0_make_request
-};
-
-static struct raid_device_operations pdcraid1_ops = {
-        open:                   pdcraid_open,
-	release:                pdcraid_release,
-	ioctl:			pdcraid_ioctl,
-	make_request:		pdcraid1_make_request
-};
-
-static struct pdcraid raid[16];
-
-
-static int pdcraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	unsigned int minor;
-   	unsigned long sectors;
-
-	if (!inode || !inode->i_rdev) 
-		return -EINVAL;
-
-	minor = MINOR(inode->i_rdev)>>SHIFT;
-	
-	switch (cmd) {
-
-         	case BLKGETSIZE:   /* Return device size */
- 			if (!arg)  return -EINVAL;
-			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
-			if (MINOR(inode->i_rdev)&15)
-				return put_user(sectors, (unsigned long *) arg);
-			return put_user(raid[minor].sectors , (unsigned long *) arg);
-			break;
-			
-
-		case HDIO_GETGEO:
-		{
-			struct hd_geometry *loc = (struct hd_geometry *) arg;
-			unsigned short bios_cyl = raid[minor].geom.cylinders; /* truncate */
-			
-			if (!loc) return -EINVAL;
-			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
-			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
-				(unsigned long *) &loc->start)) return -EFAULT;
-			return 0;
-		}
-
-		case HDIO_GETGEO_BIG:
-		{
-			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
-			if (!loc) return -EINVAL;
-			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
-			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
-			if (put_user(raid[minor].geom.cylinders, (unsigned int *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
-				(unsigned long *) &loc->start)) return -EFAULT;
-			return 0;
-		}
-
-			
-		case BLKROSET:
-		case BLKROGET:
-		case BLKSSZGET:
-			return blk_ioctl(inode->i_rdev, cmd, arg);
-
-		default:
-			printk("Invalid ioctl \n");
-			return -EINVAL;
-	};
-
-	return 0;
-}
-
-
-unsigned long partition_map_normal(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
-{
-	return block + partition_off;
-}
-
-unsigned long partition_map_linux(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
-{
-	unsigned long newblock;
-	
-	newblock = stride - (partition_off%stride); if (newblock == stride) newblock = 0;
-	newblock += block;
-	newblock = newblock % partition_size;
-	newblock += partition_off;
-	
-	return newblock;
-}
-
-static int funky_remap[8] = { 0, 1,  2, 3, 4, 5, 6, 7 };
-
-unsigned long partition_map_linux_raid0_4disk(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
-{
-	unsigned long newblock,temp,temp2;
-	
-	newblock = stride - (partition_off%stride); if (newblock == stride) newblock = 0;
-
-	if (block < (partition_size / (8*stride))*8*stride ) {
-		temp = block % stride;
-		temp2 = block / stride;
-		temp2 = ((temp2>>3)<<3)|(funky_remap[temp2&7]);
-		block = temp2*stride+temp;
-	}
-
-	
-	newblock += block;
-	newblock = newblock % partition_size;
-	newblock += partition_off;
-	
-	return newblock;
-}
-
-
-
-static int pdcraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	unsigned long rsect;
-	unsigned long rsect_left,rsect_accum = 0;
-	unsigned long block;
-	unsigned int disk=0,real_disk=0;
-	int i;
-	int device;
-	struct pdcraid *thisraid;
-
-	rsect = bh->b_rsector;
-	
-	/* Ok. We need to modify this sector number to a new disk + new sector number. 
-	 * If there are disks of different sizes, this gets tricky. 
-	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
-	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
-	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
-	 * and the last 1Gb is disk 3 only.
-	 *
-	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
-	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
-	 * point, we have to divide by one less.
-	 */
-	
-	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
-	thisraid = &raid[device];
-	if (thisraid->stride==0)
-		thisraid->stride=1;
-
-	/* Partitions need adding of the start sector of the partition to the requested sector */
-	
-	rsect = partition_map_normal(rsect, ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect, ataraid_gendisk.part[MINOR(bh->b_rdev)].nr_sects, thisraid->stride);
-
-	/* Woops we need to split the request to avoid crossing a stride barrier */
-	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
-		return -1;  
-	}
-	
-	rsect_left = rsect;
-	
-	for (i=0;i<8;i++) {
-		if (thisraid->cutoff_disks[i]==0)
-			break;
-		if (rsect > thisraid->cutoff[i]) {
-			/* we're in the wrong area so far */
-			rsect_left -= thisraid->cutoff[i];
-			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
-		} else {
-			block = rsect_left / thisraid->stride;
-			disk = block % thisraid->cutoff_disks[i];
-			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
-			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
-			break;
-		}
-	}
-	
-	for (i=0;i<8;i++) {
-		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
-			real_disk = i;
-			break;
-		}
-		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
-			disk--;
-		}
-		
-	}
-	disk = real_disk;
-		
-	
-	/*
-	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
-	 * is the only IO operation happening on this bh.
-	 */
-	bh->b_rdev = thisraid->disk[disk].device;
-	bh->b_rsector = rsect;
-
-	/*
-	 * Let the main block layer submit the IO and resolve recursion:
-	 */
-	return 1;
-}
-
-static int pdcraid1_write_request(request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	struct buffer_head *bh1;
-	struct ataraid_bh_private *private;
-	int device;
-	int i;
-
-	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
-	private = ataraid_get_private();
-	if (private==NULL)
-		BUG();
-
-	private->parent = bh;
-	
-	atomic_set(&private->count,raid[device].disks);
-
-
-	for (i = 0; i< raid[device].disks; i++) { 
-		bh1=ataraid_get_bhead();
-		/* If this ever fails we're doomed */
-		if (!bh1)
-			BUG();
-	
-		/* dupe the bufferhead and update the parts that need to be different */
-		memcpy(bh1, bh, sizeof(*bh));
-		
-		bh1->b_end_io = ataraid_end_request;
-		bh1->b_private = private;
-		bh1->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect; /* partition offset */
-		bh1->b_rdev = raid[device].disk[i].device;
-
-		/* update the last known head position for the drive */
-		raid[device].disk[i].last_pos = bh1->b_rsector+(bh1->b_size>>9);
-
-		generic_make_request(rw,bh1);
-	}
-	return 0;
-}
-
-static int pdcraid1_read_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	int device;
-	int dist;
-	int bestsofar,bestdist,i;
-	static int previous;
-
-	/* Reads are simple in principle. Pick a disk and go. 
-	   Initially I cheat by just picking the one which the last known
-	   head position is closest by.
-	   Later on, online/offline checking and performance needs adding */
-	
-	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
-	bh->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
-
-	bestsofar = 0; 
-	bestdist = raid[device].disk[0].last_pos - bh->b_rsector;
-	if (bestdist<0) 
-		bestdist=-bestdist;
-	if (bestdist>4095)
-		bestdist=4095;
-
-	for (i=1 ; i<raid[device].disks; i++) {
-		dist = raid[device].disk[i].last_pos - bh->b_rsector;
-		if (dist<0) 
-			dist = -dist;
-		if (dist>4095)
-			dist=4095;
-		
-		if (bestdist==dist) {  /* it's a tie; try to do some read balancing */
-			if ((previous>bestsofar)&&(previous<=i))  
-				bestsofar = i;
-			previous = (previous + 1) % raid[device].disks;
-		} else if (bestdist>dist) {
-			bestdist = dist;
-			bestsofar = i;
-		}
-	
-	}
-	
-	bh->b_rdev = raid[device].disk[bestsofar].device; 
-	raid[device].disk[bestsofar].last_pos = bh->b_rsector+(bh->b_size>>9);
-
-	/*
-	 * Let the main block layer submit the IO and resolve recursion:
-	 */
-                          	
-	return 1;
-}
-
-
-static int pdcraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
-{
-	/* Read and Write are totally different cases; split them totally here */
-	if (rw==READA)
-		rw = READ;
-	
-	if (rw==READ)
-		return pdcraid1_read_request(q,rw,bh);
-	else
-		return pdcraid1_write_request(q,rw,bh);
-}
-
-#include "pdcraid.h"
-
-static unsigned long calc_pdcblock_offset (int major,int minor)
-{
-	unsigned long lba = 0;
-	kdev_t dev;
-	ide_drive_t *ideinfo;
-	
-	dev = MKDEV(major,minor);
-	ideinfo = get_info_ptr (dev);
-	if (ideinfo==NULL)
-		return 0;
-	
-	
-	/* first sector of the last cluster */
-	if (ideinfo->head==0) 
-		return 0;
-	if (ideinfo->sect==0)
-		return 0;
-	lba = (ideinfo->capacity / (ideinfo->head*ideinfo->sect));
-	lba = lba * (ideinfo->head*ideinfo->sect);
-	lba = lba - ideinfo->sect;
-
-	return lba;
-}
-
-
-static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
-{
-	int ret = -EINVAL;
-	struct buffer_head *bh = NULL;
-	kdev_t dev = MKDEV(major,minor);
-	unsigned long sb_offset;
-
-	if (blksize_size[major]==NULL)   /* device doesn't exist */
-		return -EINVAL;
-                       
-	
-	/*
-	 * Calculate the position of the superblock,
-	 * it's at first sector of the last cylinder
-	 */
-	sb_offset = calc_pdcblock_offset(major,minor)/8;
-	/* The /8 transforms sectors into 4Kb blocks */
-
-	if (sb_offset==0)
-		return -1;	
-	
-	set_blocksize (dev, 4096);
-
-	bh = bread (dev, sb_offset, 4096);
-	
-	if (bh) {
-		memcpy (buffer, bh->b_data, bufsize);
-	} else {
-		printk(KERN_ERR "pdcraid: Error reading superblock.\n");
-		goto abort;
-	}
-	ret = 0;
-abort:
-	if (bh)
-		brelse (bh);
-	return ret;
-}
-
-static unsigned int calc_sb_csum (unsigned int* ptr)
-{	
-	unsigned int sum;
-	int count;
-	
-	sum = 0;
-	for (count=0;count<511;count++)
-		sum += *ptr++;
-	
-	return sum;
-}
-
-static int cookie = 0;
-
-static void __init probedisk(int devindex,int device, int raidlevel)
-{
-	int i;
-	int major, minor;
-        struct promise_raid_conf *prom;
-	static unsigned char block[4096];
-	struct block_device *bdev;
-
-	if (devlist[devindex].device!=-1) /* already assigned to another array */
-		return;
-	
-	major = devlist[devindex].major;
-	minor = devlist[devindex].minor; 
-
-        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
-        	return;
-                                                                                                                 
-        prom = (struct promise_raid_conf*)&block[512];
-
-        /* the checksums must match */
-	if (prom->checksum != calc_sb_csum((unsigned int*)prom))
-		return;
-	if (prom->raid.type!=raidlevel) /* different raidlevel */
-		return;
-
-	if ((cookie!=0) && (cookie != prom->raid.magic_1)) /* different array */
-		return;
-	
-	cookie = prom->raid.magic_1;
-
-	/* This looks evil. But basically, we have to search for our adapternumber
-	   in the arraydefinition, both of which are in the superblock */	
-        for (i=0;(i<prom->raid.total_disks)&&(i<8);i++) {
-        	if ( (prom->raid.disk[i].channel== prom->raid.channel) &&
-        	     (prom->raid.disk[i].device == prom->raid.device) ) {
-
-        	        bdev = bdget(MKDEV(major,minor));
-        	        if (bdev && blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW) == 0) {
-				raid[device].disk[i].bdev = bdev;
-			}
-			raid[device].disk[i].device = MKDEV(major,minor);
-			raid[device].disk[i].sectors = prom->raid.disk_secs;
-			raid[device].stride = (1<<prom->raid.raid0_shift);
-			raid[device].disks = prom->raid.total_disks;
-			raid[device].sectors = prom->raid.total_secs;
-			raid[device].geom.heads = prom->raid.heads+1;
-			raid[device].geom.sectors = prom->raid.sectors;
-			raid[device].geom.cylinders = prom->raid.cylinders+1;
-			devlist[devindex].device=device;
-        	     }
-        }
-	               
-}
-
-static void __init fill_cutoff(int device)
-{
-	int i,j;
-	unsigned long smallest;
-	unsigned long bar;
-	int count;
-	
-	bar = 0;
-	for (i=0;i<8;i++) {
-		smallest = ~0;
-		for (j=0;j<8;j++) 
-			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
-				smallest = raid[device].disk[j].sectors;
-		count = 0;
-		for (j=0;j<8;j++) 
-			if (raid[device].disk[j].sectors >= smallest)
-				count++;
-				
-		smallest = smallest * count;
-		bar = smallest;
-		raid[device].cutoff[i] = smallest;
-		raid[device].cutoff_disks[i] = count;
-	}
-}
-			   
-static __init int pdcraid_init_one(int device,int raidlevel)
-{
-	int i, count;
-
-	for (i=0; i<14; i++)
-		probedisk(i, device, raidlevel);
-	
-	if (raidlevel==0)
-		fill_cutoff(device);
-	
-	/* Initialize the gendisk structure */
-	
-	ataraid_register_disk(device,raid[device].sectors);        
-		
-	count=0;
-	
-	for (i=0;i<8;i++) {
-		if (raid[device].disk[i].device!=0) {
-			printk(KERN_INFO "Drive %i is %li Mb (%i / %i) \n",
-				i,raid[device].disk[i].sectors/2048,MAJOR(raid[device].disk[i].device),MINOR(raid[device].disk[i].device));
-			count++;
-		}
-	}
-	if (count) {
-		printk(KERN_INFO "Raid%i array consists of %i drives. \n",raidlevel,count);
-		return 0;
-	} else {
-		return -ENODEV;
-	}
-}
-
-static __init int pdcraid_init(void)
-{
-	int retval, device, count = 0;
-
-	do {
-		cookie = 0;
-		device=ataraid_get_device(&pdcraid0_ops);
-		if (device<0)
-			break;
-		retval = pdcraid_init_one(device,0);
-		if (retval) {
-			ataraid_release_device(device);
-			break;
-		} else {
-			count++;
-		}
-	} while (1);
-
-	do {
-	
-		cookie = 0;
-		device=ataraid_get_device(&pdcraid1_ops);
-		if (device<0)
-			break;
-		retval = pdcraid_init_one(device,1);
-		if (retval) {
-			ataraid_release_device(device);
-			break;
-		} else {
-			count++;
-		}
-	} while (1);
-
-	if (count) {
-		printk(KERN_INFO "Promise Fasttrak(tm) Softwareraid driver for linux version 0.03beta\n");
-		return 0;
-	}
-	printk(KERN_DEBUG "Promise Fasttrak(tm) Softwareraid driver 0.03beta: No raid array found\n");
-	return -ENODEV;
-}
-
-static void __exit pdcraid_exit (void)
-{
-	int i,device;
-	for (device = 0; device<16; device++) {
-		for (i=0;i<8;i++) {
-			struct block_device *bdev = raid[device].disk[i].bdev;
-			raid[device].disk[i].bdev = NULL;
-			if (bdev)
-				blkdev_put(bdev, BDEV_RAW);
-		}	
-		if (raid[device].sectors)
-			ataraid_release_device(device);
-	}
-}
-
-static int pdcraid_open(struct inode * inode, struct file * filp) 
-{
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-static int pdcraid_release(struct inode * inode, struct file * filp)
-{	
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-module_init(pdcraid_init);
-module_exit(pdcraid_exit);
-MODULE_LICENSE("GPL");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/pdcraid.h linux.20pre10-ac2/drivers/ide/pdcraid.h
--- linux.20pre10/drivers/ide/pdcraid.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/pdcraid.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,47 +0,0 @@
-struct promise_raid_conf {
-    char                promise_id[24];
-
-    u32             dummy_0;
-    u32             magic_0;
-    u32             dummy_1;
-    u32             magic_1;
-    u16             dummy_2;
-    u8              filler1[470];
-    struct {
-        u32 flags;                          /* 0x200 */
-        u8          dummy_0;
-        u8          disk_number;
-        u8          channel;
-        u8          device;
-        u32         magic_0;
-        u32         dummy_1;
-        u32         dummy_2;                /* 0x210 */
-        u32         disk_secs;
-        u32         dummy_3;
-        u16         dummy_4;
-        u8          status;
-        u8          type;
-        u8        total_disks;            /* 0x220 */
-        u8        raid0_shift;
-        u8        raid0_disks;
-        u8        array_number;
-        u32       total_secs;
-        u16       cylinders;
-        u8        heads;
-        u8        sectors;
-        u32         magic_1;
-        u32         dummy_5;                /* 0x230 */
-        struct {
-            u16     dummy_0;
-            u8      channel;
-            u8      device;
-            u32     magic_0;
-            u32     disk_number;
-        } disk[8];
-    } raid;
-    u32             filler2[346];
-    u32            checksum;
-};
-
-#define PR_MAGIC        "Promise Technology, Inc."
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/piix.c linux.20pre10-ac2/drivers/ide/piix.c
--- linux.20pre10/drivers/ide/piix.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/piix.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,542 +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 */
-extern char *ide_media_verbose(ide_drive_t *);
-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;
-
-	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_82801DB_11:
-	        case PCI_DEVICE_ID_INTEL_82801E_11:
-			p += sprintf(p, "\n                                Intel PIIX4 Ultra 100 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_INTEL_82372FB_1:
-		case PCI_DEVICE_ID_INTEL_82801AA_1:
-			p += sprintf(p, "\n                                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, "\n                                Intel PIIX4 Ultra 33 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_INTEL_82371SB_1:
-			p += sprintf(p, "\n                                Intel PIIX3 Chipset.\n");
-			break;
-		case PCI_DEVICE_ID_INTEL_82371MX:
-			p += sprintf(p, "\n                                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, "\n                                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;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_PIIX_TUNING)
-/*
- *
- */
-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;
-	}
-}
-#endif /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_PIIX_TUNING) */
-
-/*
- *  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)
-{
-	unsigned long flags;
-	u16 master_data;
-	byte slave_data;
-	int is_slave		= (&HWIF(drive)->drives[1] == drive);
-	int master_port		= HWIF(drive)->index ? 0x42 : 0x40;
-	int slave_port		= 0x44;
-				 /* 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);
-	pci_read_config_word(HWIF(drive)->pci_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(HWIF(drive)->pci_dev, slave_port, &slave_data);
-		slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0);
-		slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1])
-					   << (HWIF(drive)->index ? 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);
-	}
-	save_flags(flags);
-	cli();
-	pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data);
-	if (is_slave)
-		pci_write_config_byte(HWIF(drive)->pci_dev, slave_port, slave_data);
-	restore_flags(flags);
-}
-
-#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_PIIX_TUNING)
-static int piix_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte maslave		= hwif->channel ? 0x42 : 0x40;
-	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 err			= 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) {
-		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;
-		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);
-		}
-	}
-	if (speed < XFER_UDMA_0) {
-		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));
-
-#if PIIX_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* PIIX_DEBUG_DRIVE_INFO */
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return err;
-}
-
-static int piix_config_drive_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;
-	byte			speed;
-
-	byte udma_66		= eighty_ninty_three(drive);
-	int ultra100		= ((dev->device == PCI_DEVICE_ID_INTEL_82801BA_8) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801BA_9) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801CA_10) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801CA_11) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801DB_11) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801E_11)) ? 1 : 0;
-	int ultra66		= ((ultra100) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801AA_1) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82372FB_1)) ? 1 : 0;
-	int ultra		= ((ultra66) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82371AB) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82443MX_1) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82451NX) ||
-				   (dev->device == PCI_DEVICE_ID_INTEL_82801AB_1)) ? 1 : 0;
-
-	if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) {
-		speed = XFER_UDMA_5;
-	} else if ((id->dma_ultra & 0x0010) && (ultra)) {
-		speed = ((udma_66) && (ultra66)) ? XFER_UDMA_4 : XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0008) && (ultra)) {
-		speed = ((udma_66) && (ultra66)) ? XFER_UDMA_3 : XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0004) && (ultra)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
-		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_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-        } else {
-		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-	}
-
-	(void) piix_tune_chipset(drive, speed);
-
-	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 void config_chipset_for_pio (ide_drive_t *drive)
-{
-	piix_tune_drive(drive, ide_get_best_pio_mode(drive, 255, 5, NULL));
-}
-
-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 & 0x003F) {
-				/* 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:
-		config_chipset_for_pio(drive);
-	}
-	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 /* defined(CONFIG_BLK_DEV_IDEDMA) && (CONFIG_PIIX_TUNING) */
-
-unsigned int __init pci_init_piix (struct pci_dev *dev, const char *name)
-{
-#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->tuneproc = &piix_tune_drive;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-
-	if (!hwif->dma_base)
-		return;
-
-#ifndef CONFIG_BLK_DEV_IDEDMA
-	hwif->autodma = 0;
-#else /* CONFIG_BLK_DEV_IDEDMA */
-#ifdef CONFIG_PIIX_TUNING
-	if (!noautodma)
-		hwif->autodma = 1;
-	hwif->dmaproc = &piix_dmaproc;
-	hwif->speedproc = &piix_tune_chipset;
-#endif /* CONFIG_PIIX_TUNING */
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ppc/Makefile linux.20pre10-ac2/drivers/ide/ppc/Makefile
--- linux.20pre10/drivers/ide/ppc/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ppc/Makefile	2002-08-29 23:47:56.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ppc/mpc8xx.c linux.20pre10-ac2/drivers/ide/ppc/mpc8xx.c
--- linux.20pre10/drivers/ide/ppc/mpc8xx.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ppc/mpc8xx.c	2002-08-29 23:47:56.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ppc/pmac.c linux.20pre10-ac2/drivers/ide/ppc/pmac.c
--- linux.20pre10/drivers/ide/ppc/pmac.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ppc/pmac.c	2002-09-12 13:38:25.000000000 +0100
@@ -0,0 +1,1786 @@
+/*
+ * 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, int data_dir)
+{
+	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();
+		
+	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);
+
+	pmif->sg_dma_direction = data_dir;
+	return pci_map_sg(hwif->pci_dev, sg, nents, data_dir);
+}
+
+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;
+	int data_dir;
+
+	/* 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);
+
+	if (wr)
+		data_dir = PCI_DMA_TODEVICE;
+	else
+		data_dir = PCI_DMA_FROMDEVICE;
+
+	/* 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, data_dir);
+	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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/ppc/swarm.c linux.20pre10-ac2/drivers/ide/ppc/swarm.c
--- linux.20pre10/drivers/ide/ppc/swarm.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/ppc/swarm.c	2002-08-29 23:47:56.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/q40ide.c linux.20pre10-ac2/drivers/ide/q40ide.c
--- linux.20pre10/drivers/ide/q40ide.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/q40ide.c	1970-01-01 01:00:00.000000000 +0100
@@ -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,
-			(ide_ioreg_t)pcide_bases[i]+0x206,
-			0, NULL, q40ide_default_irq(pcide_bases[i]));
-	ide_register_hw(&hw, NULL);
-    }
-}
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/qd65xx.c linux.20pre10-ac2/drivers/ide/qd65xx.c
--- linux.20pre10/drivers/ide/qd65xx.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/qd65xx.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,456 +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;
-
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	outb(content,reg);
-	restore_flags(flags);	/* all CPUs */
-}
-
-byte __init qd_read_reg (byte reg)
-{
-	unsigned long flags;
-	byte read;
-
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	read = inb(reg);
-	restore_flags(flags);	/* all CPUs */
-	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;
-
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	savereg = inb_p(port);
-	outb_p(QD_TESTVAL,port);	/* safe value */
-	readreg = inb_p(port);
-	outb(savereg,port);
-	restore_flags(flags);	/* all CPUs */
-
-	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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/qd65xx.h linux.20pre10-ac2/drivers/ide/qd65xx.h
--- linux.20pre10/drivers/ide/qd65xx.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/qd65xx.h	1970-01-01 01:00:00.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/raid/ataraid.c linux.20pre10-ac2/drivers/ide/raid/ataraid.c
--- linux.20pre10/drivers/ide/raid/ataraid.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/raid/ataraid.c	2002-08-29 23:47:56.000000000 +0100
@@ -0,0 +1,317 @@
+/*
+   ataraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
+
+   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, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors: 	Arjan van de Ven <arjanv@redhat.com>
+   		
+   
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/semaphore.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+#include <linux/kdev_t.h>
+#include <linux/swap.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#include "ataraid.h"
+
+                                        
+static int ataraid_hardsect_size[256];
+static int ataraid_blksize_size[256];
+
+static struct raid_device_operations* ataraid_ops[16];
+
+static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int ataraid_open(struct inode * inode, struct file * filp);
+static int ataraid_release(struct inode * inode, struct file * filp);
+static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh);
+
+
+struct gendisk ataraid_gendisk;
+static int ataraid_gendisk_sizes[256];
+static int ataraid_readahead[256];
+
+static struct block_device_operations ataraid_fops = {
+	owner:			THIS_MODULE,
+	open:                   ataraid_open,
+	release:                ataraid_release,
+	ioctl:                  ataraid_ioctl,
+};
+                
+
+
+static DECLARE_MUTEX(ataraid_sem);
+
+/* Bitmap for the devices currently in use */
+static unsigned int ataraiduse;
+
+
+/* stub fops functions */
+
+static int ataraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)  
+{
+	int minor;
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+	
+	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->ioctl))
+		return (ataraid_ops[minor]->ioctl)(inode,file,cmd,arg);
+	return -EINVAL;
+}
+
+static int ataraid_open(struct inode * inode, struct file * filp)
+{
+	int minor;
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+
+	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->open))
+		return (ataraid_ops[minor]->open)(inode,filp);
+	return -EINVAL;
+}
+
+
+static int ataraid_release(struct inode * inode, struct file * filp)
+{
+	int minor;
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+
+	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->release))
+		return (ataraid_ops[minor]->release)(inode,filp);
+	return -EINVAL;
+}
+
+static int ataraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	int minor;
+	int retval;
+	minor = MINOR(bh->b_rdev)>>SHIFT;
+
+	if ((ataraid_ops[minor])&&(ataraid_ops[minor]->make_request)) {
+		
+		retval= (ataraid_ops[minor]->make_request)(q,rw,bh);
+		if (retval == -1) {
+			ataraid_split_request(q,rw,bh);		
+			return 0;
+		} else
+			return retval;
+	}
+	return -EINVAL;
+}
+
+struct buffer_head *ataraid_get_bhead(void)
+{
+	void *ptr = NULL;
+	while (!ptr) {
+		ptr=kmalloc(sizeof(struct buffer_head),GFP_NOIO);
+		if (!ptr) {
+			__set_current_state(TASK_RUNNING);
+			yield();
+		}
+	}
+	return ptr;
+}
+
+EXPORT_SYMBOL(ataraid_get_bhead);
+
+struct ataraid_bh_private *ataraid_get_private(void)
+{
+	void *ptr = NULL;
+	while (!ptr) {
+		ptr=kmalloc(sizeof(struct ataraid_bh_private),GFP_NOIO);
+		if (!ptr) {
+			__set_current_state(TASK_RUNNING);
+			yield();
+		}
+	}
+	return ptr;
+}
+
+EXPORT_SYMBOL(ataraid_get_private);
+
+void ataraid_end_request(struct buffer_head *bh, int uptodate)
+{
+	struct ataraid_bh_private *private = bh->b_private;
+
+	if (private==NULL)
+		BUG();
+
+	if (atomic_dec_and_test(&private->count)) {
+		private->parent->b_end_io(private->parent,uptodate);
+		private->parent = NULL;
+		kfree(private);
+	}
+	kfree(bh);
+}
+
+EXPORT_SYMBOL(ataraid_end_request);
+
+static void ataraid_split_request(request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	struct buffer_head *bh1,*bh2;
+	struct ataraid_bh_private *private;
+	bh1=ataraid_get_bhead();
+	bh2=ataraid_get_bhead();
+
+	/* If either of those ever fails we're doomed */
+	if ((!bh1)||(!bh2))
+		BUG();
+	private = ataraid_get_private();
+	if (private==NULL)
+		BUG();
+	
+	memcpy(bh1, bh, sizeof(*bh));
+	memcpy(bh2, bh, sizeof(*bh));
+	
+	bh1->b_end_io = ataraid_end_request;
+	bh2->b_end_io = ataraid_end_request;
+
+	bh2->b_rsector += bh->b_size >> 10;
+	bh1->b_size /= 2;
+	bh2->b_size /= 2;
+	private->parent = bh;
+
+	bh1->b_private = private;
+	bh2->b_private = private;
+	atomic_set(&private->count,2);
+
+	bh2->b_data +=  bh->b_size/2;
+
+	generic_make_request(rw,bh1);
+	generic_make_request(rw,bh2);
+}
+
+
+
+
+/* device register / release functions */
+
+
+int ataraid_get_device(struct raid_device_operations *fops)
+{
+	int bit;
+	down(&ataraid_sem);
+	if (ataraiduse==~0U) {
+		up(&ataraid_sem);
+		return -ENODEV;
+	}
+	bit=ffz(ataraiduse); 
+	ataraiduse |= 1<<bit;
+	ataraid_ops[bit] = fops;
+	up(&ataraid_sem);
+	return bit;
+}
+
+void ataraid_release_device(int device)
+{
+	down(&ataraid_sem);
+	
+	if ((ataraiduse & (1<<device))==0)
+		BUG();	/* device wasn't registered at all */
+	
+	ataraiduse &= ~(1<<device);
+	ataraid_ops[device] = NULL;
+	up(&ataraid_sem);
+}
+
+void ataraid_register_disk(int device,long size)
+{
+	register_disk(&ataraid_gendisk, MKDEV(ATAMAJOR,16*device),16,
+		&ataraid_fops,size);
+
+}
+
+static __init int ataraid_init(void) 
+{
+	int i;
+        for(i=0;i<256;i++)
+	{
+        	ataraid_hardsect_size[i] = 512;
+		ataraid_blksize_size[i] = 1024;  
+		ataraid_readahead[i] = 1023;
+	}
+	
+	if (blksize_size[ATAMAJOR]==NULL)
+		blksize_size[ATAMAJOR] = ataraid_blksize_size;
+	if (hardsect_size[ATAMAJOR]==NULL)
+		hardsect_size[ATAMAJOR] = ataraid_hardsect_size;
+	
+	
+	/* setup the gendisk structure */	
+	ataraid_gendisk.part = kmalloc(256 * sizeof(struct hd_struct),GFP_KERNEL);
+	if (ataraid_gendisk.part==NULL) {
+		printk(KERN_ERR "ataraid: Couldn't allocate memory, aborting \n");
+		return -1;
+	}
+	
+	memset(&ataraid_gendisk.part[0],0,256*sizeof(struct hd_struct));
+	
+	
+	ataraid_gendisk.major       = ATAMAJOR;
+	ataraid_gendisk.major_name  = "ataraid";
+	ataraid_gendisk.minor_shift = 4;
+	ataraid_gendisk.max_p	    = 15;
+	ataraid_gendisk.sizes	    = &ataraid_gendisk_sizes[0];
+	ataraid_gendisk.nr_real	    = 16;
+	ataraid_gendisk.fops        = &ataraid_fops;
+	
+	
+	add_gendisk(&ataraid_gendisk);
+			
+	if (register_blkdev(ATAMAJOR, "ataraid", &ataraid_fops)) {
+		printk(KERN_ERR "ataraid: Could not get major %d \n",ATAMAJOR);
+		return -1;
+	}
+	
+	                
+	
+	blk_queue_make_request(BLK_DEFAULT_QUEUE(ATAMAJOR),ataraid_make_request);
+                                                                                     	
+	return 0;                                                        	
+}
+
+
+static void __exit ataraid_exit(void)
+{
+	unregister_blkdev(ATAMAJOR, "ataraid");
+	hardsect_size[ATAMAJOR] = NULL;
+	blk_size[ATAMAJOR] = NULL;
+	blksize_size[ATAMAJOR] = NULL;                       
+	max_readahead[ATAMAJOR] = NULL;
+
+	del_gendisk(&ataraid_gendisk);
+        
+	if (ataraid_gendisk.part) {
+		kfree(ataraid_gendisk.part);
+		ataraid_gendisk.part = NULL;
+	}
+}
+
+module_init(ataraid_init);
+module_exit(ataraid_exit);
+
+
+
+EXPORT_SYMBOL(ataraid_get_device);
+EXPORT_SYMBOL(ataraid_release_device);
+EXPORT_SYMBOL(ataraid_gendisk);
+EXPORT_SYMBOL(ataraid_register_disk);
+MODULE_LICENSE("GPL");
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/raid/ataraid.h linux.20pre10-ac2/drivers/ide/raid/ataraid.h
--- linux.20pre10/drivers/ide/raid/ataraid.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/raid/ataraid.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,72 @@
+/*
+   ataraid.h  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
+
+   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, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors: 	Arjan van de Ven <arjanv@redhat.com>
+   		
+   
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/semaphore.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#define ATAMAJOR 114
+#define SHIFT 4
+#define MINOR_MASK 15
+#define MAJOR_MASK 15
+
+                                        
+/* raid_device_operations is a light struct block_device_operations with an
+   added method for make_request */
+struct raid_device_operations {
+	int (*open) (struct inode *, struct file *);
+	int (*release) (struct inode *, struct file *);
+	int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
+	int (*make_request) (request_queue_t *q, int rw, struct buffer_head * bh);
+};
+
+
+struct geom {
+	unsigned char heads;
+	unsigned int cylinders;
+	unsigned char sectors;
+};
+
+/* structure for the splitting of bufferheads */
+
+struct ataraid_bh_private {
+	struct buffer_head *parent;
+	atomic_t count;
+};
+
+extern struct gendisk ataraid_gendisk;
+
+extern int ataraid_get_device(struct raid_device_operations *fops);
+extern void ataraid_release_device(int device);
+extern int get_blocksize(kdev_t dev);
+extern void ataraid_register_disk(int device,long size);
+extern struct buffer_head *ataraid_get_bhead(void);
+extern struct ataraid_bh_private *ataraid_get_private(void);
+extern void ataraid_end_request(struct buffer_head *bh, int uptodate);
+
+
+
+
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/raid/hptraid.c linux.20pre10-ac2/drivers/ide/raid/hptraid.c
--- linux.20pre10/drivers/ide/raid/hptraid.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/raid/hptraid.c	2002-08-29 23:47:56.000000000 +0100
@@ -0,0 +1,436 @@
+/*
+   hptraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
+
+   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, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors: 	Arjan van de Ven <arjanv@redhat.com>
+
+   Based on work
+   	Copyleft  (C) 2001 by Wilfried Weissmann <wweissmann@gmx.at>
+	Copyright (C) 1994-96 Marc ZYNGIER <zyngier@ufr-info-p7.ibp.fr>
+   Based on work done by Sren Schmidt for FreeBSD
+
+   
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#include "ataraid.h"
+
+static int hptraid_open(struct inode * inode, struct file * filp);
+static int hptraid_release(struct inode * inode, struct file * filp);
+static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int hptraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+
+
+
+struct hptdisk {
+	kdev_t	device;
+	unsigned long sectors;
+	struct block_device *bdev;
+};
+
+struct hptraid {
+	unsigned int stride;
+	unsigned int disks;
+	unsigned long sectors;
+	struct geom geom;
+	
+	struct hptdisk disk[8];
+	
+	unsigned long cutoff[8];
+	unsigned int cutoff_disks[8];	
+};
+
+static struct raid_device_operations hptraid_ops = {
+	open:                   hptraid_open,
+	release:                hptraid_release,
+	ioctl:			hptraid_ioctl,
+	make_request:		hptraid_make_request
+};
+
+static struct hptraid raid[16];
+
+static int hptraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	unsigned int minor;
+	unsigned char val;
+	unsigned long sectors;
+	
+	if (!inode || !inode->i_rdev) 	
+		return -EINVAL;
+
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+	
+	switch (cmd) {
+         	case BLKGETSIZE:   /* Return device size */
+			if (!arg)  return -EINVAL;
+			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
+			if (MINOR(inode->i_rdev)&15)
+				return put_user(sectors, (unsigned long *) arg);
+			return put_user(raid[minor].sectors , (unsigned long *) arg);
+			break;
+			
+
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry *loc = (struct hd_geometry *) arg;
+			unsigned short bios_cyl;
+			
+			if (!loc) return -EINVAL;
+			val = 255;
+			if (put_user(val, (byte *) &loc->heads)) return -EFAULT;
+			val=63;
+			if (put_user(val, (byte *) &loc->sectors)) return -EFAULT;
+			bios_cyl = raid[minor].sectors/63/255;
+			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+		case HDIO_GETGEO_BIG:
+		{
+			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+			unsigned int bios_cyl;
+			if (!loc) return -EINVAL;
+			val = 255;
+			if (put_user(val, (byte *) &loc->heads)) return -EFAULT;
+			val = 63;
+			if (put_user(val, (byte *) &loc->sectors)) return -EFAULT;
+			bios_cyl = raid[minor].sectors/63/255;
+			if (put_user(bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+			
+		default:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+	};
+
+	return 0;
+}
+
+
+static int hptraid_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	unsigned long rsect;
+	unsigned long rsect_left,rsect_accum = 0;
+	unsigned long block;
+	unsigned int disk=0,real_disk=0;
+	int i;
+	int device;
+	struct hptraid *thisraid;
+
+	rsect = bh->b_rsector;
+
+	/* Ok. We need to modify this sector number to a new disk + new sector number. 
+	 * If there are disks of different sizes, this gets tricky. 
+	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
+	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
+	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
+	 * and the last 1Gb is disk 3 only.
+	 *
+	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
+	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
+	 * point, we have to divide by one less.
+	 */
+	
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	thisraid = &raid[device];
+	if (thisraid->stride==0)
+		thisraid->stride=1;
+
+	/* Partitions need adding of the start sector of the partition to the requested sector */
+	
+	rsect += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
+
+	/* Woops we need to split the request to avoid crossing a stride barrier */
+	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
+		return -1;
+	}
+			
+	rsect_left = rsect;
+	
+	for (i=0;i<8;i++) {
+		if (thisraid->cutoff_disks[i]==0)
+			break;
+		if (rsect > thisraid->cutoff[i]) {
+			/* we're in the wrong area so far */
+			rsect_left -= thisraid->cutoff[i];
+			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
+		} else {
+			block = rsect_left / thisraid->stride;
+			disk = block % thisraid->cutoff_disks[i];
+			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
+			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
+			break;
+		}
+	}
+	
+	for (i=0;i<8;i++) {
+		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
+			real_disk = i;
+			break;
+		}
+		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
+			disk--;
+		}
+		
+	}
+	disk = real_disk;
+	
+	/* All but the first disk have a 10 sector offset */
+	if (i>0)
+		rsect+=10;
+		
+	
+	/*
+	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
+	 * is the only IO operation happening on this bh.
+	 */
+	 
+	bh->b_rdev = thisraid->disk[disk].device;
+	bh->b_rsector = rsect;
+
+	/*
+	 * Let the main block layer submit the IO and resolve recursion:
+	 */
+	return 1;
+}
+
+
+#include "hptraid.h"
+
+static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
+{
+	int ret = -EINVAL;
+	struct buffer_head *bh = NULL;
+	kdev_t dev = MKDEV(major,minor);
+	
+	if (blksize_size[major]==NULL)	 /* device doesn't exist */
+		return -EINVAL;
+	
+
+	/* Superblock is at 4096+412 bytes */
+	set_blocksize (dev, 4096);
+	bh = bread (dev, 1, 4096);
+
+	
+	if (bh) {
+		memcpy (buffer, bh->b_data, bufsize);
+	} else {
+		printk(KERN_ERR "hptraid: Error reading superblock.\n");
+		goto abort;
+	}
+	ret = 0;
+abort:
+	if (bh)
+		brelse (bh);
+	return ret;
+}
+
+static unsigned long maxsectors (int major,int minor)
+{
+	unsigned long lba = 0;
+	kdev_t dev;
+	ide_drive_t *ideinfo;
+	
+	dev = MKDEV(major,minor);
+	ideinfo = get_info_ptr (dev);
+	if (ideinfo==NULL)
+		return 0;
+	
+	
+	/* first sector of the last cluster */
+	if (ideinfo->head==0) 
+		return 0;
+	if (ideinfo->sect==0)
+		return 0;
+	lba = (ideinfo->capacity);
+
+	return lba;
+}
+
+static void __init probedisk(int major, int minor,int device)
+{
+	int i;
+        struct highpoint_raid_conf *prom;
+	static unsigned char block[4096];
+	struct block_device *bdev;
+	
+	if (maxsectors(major,minor)==0)
+		return;
+	
+        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
+        	return;
+                                                                                                                 
+        prom = (struct highpoint_raid_conf*)&block[512];
+                
+        if (prom->magic!=  0x5a7816f0)
+        	return;
+        if (prom->type) {
+        	printk(KERN_INFO "hptraid: only RAID0 is supported currently\n");
+        	return;
+        }
+
+	i = prom->disk_number;
+	if (i<0)
+		return;
+	if (i>8) 
+		return;
+
+	bdev = bdget(MKDEV(major,minor));
+	if (bdev && blkdev_get(bdev,FMODE_READ|FMODE_WRITE,0,BDEV_RAW) == 0) {
+        	int j=0;
+        	struct gendisk *gd;
+		raid[device].disk[i].bdev = bdev;
+        	/* This is supposed to prevent others from stealing our underlying disks */
+		/* now blank the /proc/partitions table for the wrong partition table,
+		   so that scripts don't accidentally mount it and crash the kernel */
+		 /* XXX: the 0 is an utter hack  --hch */
+		gd=get_gendisk(MKDEV(major, 0));
+		if (gd!=NULL) {
+			for (j=1+(minor<<gd->minor_shift);j<((minor+1)<<gd->minor_shift);j++) 
+				gd->part[j].nr_sects=0;					
+		}
+        }
+	raid[device].disk[i].device = MKDEV(major,minor);
+	raid[device].disk[i].sectors = maxsectors(major,minor);
+	raid[device].stride = (1<<prom->raid0_shift);
+	raid[device].disks = prom->raid_disks;
+	raid[device].sectors = prom->total_secs;
+			
+}
+
+static void __init fill_cutoff(int device)
+{
+	int i,j;
+	unsigned long smallest;
+	unsigned long bar;
+	int count;
+	
+	bar = 0;
+	for (i=0;i<8;i++) {
+		smallest = ~0;
+		for (j=0;j<8;j++) 
+			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
+				smallest = raid[device].disk[j].sectors;
+		count = 0;
+		for (j=0;j<8;j++) 
+			if (raid[device].disk[j].sectors >= smallest)
+				count++;
+		
+		smallest = smallest * count;		
+		bar = smallest;
+		raid[device].cutoff[i] = smallest;
+		raid[device].cutoff_disks[i] = count;
+		
+	}
+}
+
+
+static __init int hptraid_init_one(int device)
+{
+	int i,count;
+
+	probedisk(IDE0_MAJOR,  0, device);
+	probedisk(IDE0_MAJOR, 64, device);
+	probedisk(IDE1_MAJOR,  0, device);
+	probedisk(IDE1_MAJOR, 64, device);
+	probedisk(IDE2_MAJOR,  0, device);
+	probedisk(IDE2_MAJOR, 64, device);
+	probedisk(IDE3_MAJOR,  0, device);
+	probedisk(IDE3_MAJOR, 64, device);
+	probedisk(IDE4_MAJOR,  0, device);
+	probedisk(IDE4_MAJOR, 64, device);
+	probedisk(IDE5_MAJOR,  0, device);
+	probedisk(IDE5_MAJOR, 64, device);
+
+	fill_cutoff(device);
+	
+	/* Initialize the gendisk structure */
+	
+	ataraid_register_disk(device,raid[device].sectors);
+
+	count=0;
+	printk(KERN_INFO "Highpoint HPT370 Softwareraid driver for linux version 0.01\n");
+		
+	for (i=0;i<8;i++) {
+		if (raid[device].disk[i].device!=0) {
+			printk(KERN_INFO "Drive %i is %li Mb \n",
+				i,raid[device].disk[i].sectors/2048);
+			count++;
+		}
+	}
+	if (count) {
+		printk(KERN_INFO "Raid array consists of %i drives. \n",count);
+		return 0;
+	} else {
+		printk(KERN_INFO "No raid array found\n");
+		return -ENODEV;
+	}
+	
+}
+
+static __init int hptraid_init(void)
+{
+	int retval,device;
+	
+	device=ataraid_get_device(&hptraid_ops);
+	if (device<0)
+		return -ENODEV;
+	retval = hptraid_init_one(device);
+	if (retval)
+		ataraid_release_device(device);
+	return retval;
+}
+
+static void __exit hptraid_exit (void)
+{
+	int i,device;
+	for (device = 0; device<16; device++) {
+		for (i=0;i<8;i++)  {
+			struct block_device *bdev = raid[device].disk[i].bdev;
+			raid[device].disk[i].bdev = NULL;
+			if (bdev)
+				blkdev_put(bdev, BDEV_RAW);
+		}       
+		if (raid[device].sectors)
+			ataraid_release_device(device);
+	}
+}
+
+static int hptraid_open(struct inode * inode, struct file * filp) 
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+static int hptraid_release(struct inode * inode, struct file * filp)
+{	
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+module_init(hptraid_init);
+module_exit(hptraid_exit);
+MODULE_LICENSE("GPL");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/raid/hptraid.h linux.20pre10-ac2/drivers/ide/raid/hptraid.h
--- linux.20pre10/drivers/ide/raid/hptraid.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/raid/hptraid.h	2002-08-29 23:47:56.000000000 +0100
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2000,2001 Sren Schmidt <sos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+                            
+struct highpoint_raid_conf
+{
+       int8_t  filler1[32];
+       u_int32_t       magic;
+#define HPT_MAGIC_OK   0x5a7816f0
+#define HPT_MAGIC_BAD  0x5a7816fd  
+
+       u_int32_t       magic_0;
+       u_int32_t       magic_1;
+       u_int32_t       order;  
+#define HPT_O_MIRROR   0x01  
+#define HPT_O_STRIPE   0x02
+#define HPT_O_OK       0x04
+
+       u_int8_t        raid_disks;
+       u_int8_t        raid0_shift; 
+       u_int8_t        type;
+#define HPT_T_RAID_0   0x00 
+#define HPT_T_RAID_1   0x01
+#define HPT_T_RAID_01_RAID_0   0x02
+#define HPT_T_SPAN             0x03
+#define HPT_T_RAID_3           0x04   
+#define HPT_T_RAID_5           0x05
+#define HPT_T_SINGLEDISK       0x06
+#define HPT_T_RAID_01_RAID_1   0x07
+
+       u_int8_t        disk_number;
+       u_int32_t       total_secs; 
+       u_int32_t       disk_mode;  
+       u_int32_t       boot_mode;
+       u_int8_t        boot_disk; 
+       u_int8_t        boot_protect;
+       u_int8_t        error_log_entries;
+       u_int8_t        error_log_index;  
+       struct
+       {
+               u_int32_t       timestamp;
+               u_int8_t        reason;   
+#define HPT_R_REMOVED          0xfe      
+#define HPT_R_BROKEN           0xff      
+
+               u_int8_t        disk;
+               u_int8_t        status;
+               u_int8_t        sectors;
+               u_int32_t       lba;
+       } errorlog[32];
+       u_int8_t        filler[60];
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/raid/Makefile linux.20pre10-ac2/drivers/ide/raid/Makefile
--- linux.20pre10/drivers/ide/raid/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/raid/Makefile	2002-08-29 23:47:56.000000000 +0100
@@ -0,0 +1,18 @@
+
+O_TARGET := idedriver-raid.o
+
+obj-y		:=
+obj-m		:=
+
+export-objs := ataraid.o
+
+# The virtualised raid layers MUST come after the ide itself or bad stuff
+# will happen.
+
+obj-$(CONFIG_BLK_DEV_ATARAID)		+= ataraid.o
+obj-$(CONFIG_BLK_DEV_ATARAID_PDC)	+= pdcraid.o
+obj-$(CONFIG_BLK_DEV_ATARAID_HPT)	+= hptraid.o
+
+EXTRA_CFLAGS	:= -I../
+
+include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/raid/pdcraid.c linux.20pre10-ac2/drivers/ide/raid/pdcraid.c
--- linux.20pre10/drivers/ide/raid/pdcraid.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/raid/pdcraid.c	2002-08-29 23:47:56.000000000 +0100
@@ -0,0 +1,646 @@
+/*
+   pdcraid.c  Copyright (C) 2001 Red Hat, Inc. All rights reserved.
+
+   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, or (at your option)
+   any later version.
+   
+   You should have received a copy of the GNU General Public License
+   (for example /usr/src/linux/COPYING); if not, write to the Free
+   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
+   
+   Authors: 	Arjan van de Ven <arjanv@redhat.com>
+   		
+   Based on work done by Sren Schmidt for FreeBSD  
+
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/genhd.h>
+#include <linux/ioctl.h>
+
+#include <linux/ide.h>
+#include <asm/uaccess.h>
+
+#include "ataraid.h"
+
+static int pdcraid_open(struct inode * inode, struct file * filp);
+static int pdcraid_release(struct inode * inode, struct file * filp);
+static int pdcraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int pdcraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+static int pdcraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh);
+
+struct disk_dev {
+	int major;
+	int minor;
+	int device;
+};
+
+static struct disk_dev devlist[]= {
+	{IDE0_MAJOR,  0,  -1 },
+	{IDE0_MAJOR, 64,  -1 },
+	{IDE1_MAJOR,  0,  -1 },
+	{IDE1_MAJOR, 64,  -1 },
+	{IDE2_MAJOR,  0,  -1 },
+	{IDE2_MAJOR, 64,  -1 },
+	{IDE3_MAJOR,  0,  -1 },
+	{IDE3_MAJOR, 64,  -1 },
+	{IDE4_MAJOR,  0,  -1 },
+	{IDE4_MAJOR, 64,  -1 },
+	{IDE5_MAJOR,  0,  -1 },
+	{IDE5_MAJOR, 64,  -1 },
+	{IDE6_MAJOR,  0,  -1 },
+	{IDE6_MAJOR, 64,  -1 },
+};
+
+
+struct pdcdisk {
+	kdev_t	device;
+	unsigned long sectors;
+	struct block_device *bdev;
+	unsigned long last_pos;
+};
+
+struct pdcraid {
+	unsigned int stride;
+	unsigned int disks;
+	unsigned long sectors;
+	struct geom geom;
+	
+	struct pdcdisk disk[8];
+	
+	unsigned long cutoff[8];
+	unsigned int cutoff_disks[8];
+};
+
+static struct raid_device_operations pdcraid0_ops = {
+        open:                   pdcraid_open,
+	release:                pdcraid_release,
+	ioctl:			pdcraid_ioctl,
+	make_request:		pdcraid0_make_request
+};
+
+static struct raid_device_operations pdcraid1_ops = {
+        open:                   pdcraid_open,
+	release:                pdcraid_release,
+	ioctl:			pdcraid_ioctl,
+	make_request:		pdcraid1_make_request
+};
+
+static struct pdcraid raid[16];
+
+
+static int pdcraid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	unsigned int minor;
+   	unsigned long sectors;
+
+	if (!inode || !inode->i_rdev) 
+		return -EINVAL;
+
+	minor = MINOR(inode->i_rdev)>>SHIFT;
+	
+	switch (cmd) {
+
+         	case BLKGETSIZE:   /* Return device size */
+ 			if (!arg)  return -EINVAL;
+			sectors = ataraid_gendisk.part[MINOR(inode->i_rdev)].nr_sects;
+			if (MINOR(inode->i_rdev)&15)
+				return put_user(sectors, (unsigned long *) arg);
+			return put_user(raid[minor].sectors , (unsigned long *) arg);
+			break;
+			
+
+		case HDIO_GETGEO:
+		{
+			struct hd_geometry *loc = (struct hd_geometry *) arg;
+			unsigned short bios_cyl = raid[minor].geom.cylinders; /* truncate */
+			
+			if (!loc) return -EINVAL;
+			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
+			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+		case HDIO_GETGEO_BIG:
+		{
+			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
+			if (!loc) return -EINVAL;
+			if (put_user(raid[minor].geom.heads, (byte *) &loc->heads)) return -EFAULT;
+			if (put_user(raid[minor].geom.sectors, (byte *) &loc->sectors)) return -EFAULT;
+			if (put_user(raid[minor].geom.cylinders, (unsigned int *) &loc->cylinders)) return -EFAULT;
+			if (put_user((unsigned)ataraid_gendisk.part[MINOR(inode->i_rdev)].start_sect,
+				(unsigned long *) &loc->start)) return -EFAULT;
+			return 0;
+		}
+
+			
+		case BLKROSET:
+		case BLKROGET:
+		case BLKSSZGET:
+			return blk_ioctl(inode->i_rdev, cmd, arg);
+
+		default:
+			printk("Invalid ioctl \n");
+			return -EINVAL;
+	};
+
+	return 0;
+}
+
+
+unsigned long partition_map_normal(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
+{
+	return block + partition_off;
+}
+
+unsigned long partition_map_linux(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
+{
+	unsigned long newblock;
+	
+	newblock = stride - (partition_off%stride); if (newblock == stride) newblock = 0;
+	newblock += block;
+	newblock = newblock % partition_size;
+	newblock += partition_off;
+	
+	return newblock;
+}
+
+static int funky_remap[8] = { 0, 1,  2, 3, 4, 5, 6, 7 };
+
+unsigned long partition_map_linux_raid0_4disk(unsigned long block, unsigned long partition_off, unsigned long partition_size, int stride)
+{
+	unsigned long newblock,temp,temp2;
+	
+	newblock = stride - (partition_off%stride); if (newblock == stride) newblock = 0;
+
+	if (block < (partition_size / (8*stride))*8*stride ) {
+		temp = block % stride;
+		temp2 = block / stride;
+		temp2 = ((temp2>>3)<<3)|(funky_remap[temp2&7]);
+		block = temp2*stride+temp;
+	}
+
+	
+	newblock += block;
+	newblock = newblock % partition_size;
+	newblock += partition_off;
+	
+	return newblock;
+}
+
+
+
+static int pdcraid0_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	unsigned long rsect;
+	unsigned long rsect_left,rsect_accum = 0;
+	unsigned long block;
+	unsigned int disk=0,real_disk=0;
+	int i;
+	int device;
+	struct pdcraid *thisraid;
+
+	rsect = bh->b_rsector;
+	
+	/* Ok. We need to modify this sector number to a new disk + new sector number. 
+	 * If there are disks of different sizes, this gets tricky. 
+	 * Example with 3 disks (1Gb, 4Gb and 5 GB):
+	 * The first 3 Gb of the "RAID" are evenly spread over the 3 disks.
+	 * Then things get interesting. The next 2Gb (RAID view) are spread across disk 2 and 3
+	 * and the last 1Gb is disk 3 only.
+	 *
+	 * the way this is solved is like this: We have a list of "cutoff" points where everytime
+	 * a disk falls out of the "higher" count, we mark the max sector. So once we pass a cutoff
+	 * point, we have to divide by one less.
+	 */
+	
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	thisraid = &raid[device];
+	if (thisraid->stride==0)
+		thisraid->stride=1;
+
+	/* Partitions need adding of the start sector of the partition to the requested sector */
+	
+	rsect = partition_map_normal(rsect, ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect, ataraid_gendisk.part[MINOR(bh->b_rdev)].nr_sects, thisraid->stride);
+
+	/* Woops we need to split the request to avoid crossing a stride barrier */
+	if ((rsect/thisraid->stride) != ((rsect+(bh->b_size/512)-1)/thisraid->stride)) {
+		return -1;  
+	}
+	
+	rsect_left = rsect;
+	
+	for (i=0;i<8;i++) {
+		if (thisraid->cutoff_disks[i]==0)
+			break;
+		if (rsect > thisraid->cutoff[i]) {
+			/* we're in the wrong area so far */
+			rsect_left -= thisraid->cutoff[i];
+			rsect_accum += thisraid->cutoff[i]/thisraid->cutoff_disks[i];
+		} else {
+			block = rsect_left / thisraid->stride;
+			disk = block % thisraid->cutoff_disks[i];
+			block = (block / thisraid->cutoff_disks[i]) * thisraid->stride;
+			rsect = rsect_accum + (rsect_left % thisraid->stride) + block;
+			break;
+		}
+	}
+	
+	for (i=0;i<8;i++) {
+		if ((disk==0) && (thisraid->disk[i].sectors > rsect_accum)) {
+			real_disk = i;
+			break;
+		}
+		if ((disk>0) && (thisraid->disk[i].sectors >= rsect_accum)) {
+			disk--;
+		}
+		
+	}
+	disk = real_disk;
+		
+	
+	/*
+	 * The new BH_Lock semantics in ll_rw_blk.c guarantee that this
+	 * is the only IO operation happening on this bh.
+	 */
+	bh->b_rdev = thisraid->disk[disk].device;
+	bh->b_rsector = rsect;
+
+	/*
+	 * Let the main block layer submit the IO and resolve recursion:
+	 */
+	return 1;
+}
+
+static int pdcraid1_write_request(request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	struct buffer_head *bh1;
+	struct ataraid_bh_private *private;
+	int device;
+	int i;
+
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	private = ataraid_get_private();
+	if (private==NULL)
+		BUG();
+
+	private->parent = bh;
+	
+	atomic_set(&private->count,raid[device].disks);
+
+
+	for (i = 0; i< raid[device].disks; i++) { 
+		bh1=ataraid_get_bhead();
+		/* If this ever fails we're doomed */
+		if (!bh1)
+			BUG();
+	
+		/* dupe the bufferhead and update the parts that need to be different */
+		memcpy(bh1, bh, sizeof(*bh));
+		
+		bh1->b_end_io = ataraid_end_request;
+		bh1->b_private = private;
+		bh1->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect; /* partition offset */
+		bh1->b_rdev = raid[device].disk[i].device;
+
+		/* update the last known head position for the drive */
+		raid[device].disk[i].last_pos = bh1->b_rsector+(bh1->b_size>>9);
+
+		generic_make_request(rw,bh1);
+	}
+	return 0;
+}
+
+static int pdcraid1_read_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	int device;
+	int dist;
+	int bestsofar,bestdist,i;
+	static int previous;
+
+	/* Reads are simple in principle. Pick a disk and go. 
+	   Initially I cheat by just picking the one which the last known
+	   head position is closest by.
+	   Later on, online/offline checking and performance needs adding */
+	
+	device = (bh->b_rdev >> SHIFT)&MAJOR_MASK;
+	bh->b_rsector += ataraid_gendisk.part[MINOR(bh->b_rdev)].start_sect;
+
+	bestsofar = 0; 
+	bestdist = raid[device].disk[0].last_pos - bh->b_rsector;
+	if (bestdist<0) 
+		bestdist=-bestdist;
+	if (bestdist>4095)
+		bestdist=4095;
+
+	for (i=1 ; i<raid[device].disks; i++) {
+		dist = raid[device].disk[i].last_pos - bh->b_rsector;
+		if (dist<0) 
+			dist = -dist;
+		if (dist>4095)
+			dist=4095;
+		
+		if (bestdist==dist) {  /* it's a tie; try to do some read balancing */
+			if ((previous>bestsofar)&&(previous<=i))  
+				bestsofar = i;
+			previous = (previous + 1) % raid[device].disks;
+		} else if (bestdist>dist) {
+			bestdist = dist;
+			bestsofar = i;
+		}
+	
+	}
+	
+	bh->b_rdev = raid[device].disk[bestsofar].device; 
+	raid[device].disk[bestsofar].last_pos = bh->b_rsector+(bh->b_size>>9);
+
+	/*
+	 * Let the main block layer submit the IO and resolve recursion:
+	 */
+                          	
+	return 1;
+}
+
+
+static int pdcraid1_make_request (request_queue_t *q, int rw, struct buffer_head * bh)
+{
+	/* Read and Write are totally different cases; split them totally here */
+	if (rw==READA)
+		rw = READ;
+	
+	if (rw==READ)
+		return pdcraid1_read_request(q,rw,bh);
+	else
+		return pdcraid1_write_request(q,rw,bh);
+}
+
+#include "pdcraid.h"
+
+static unsigned long calc_pdcblock_offset (int major,int minor)
+{
+	unsigned long lba = 0;
+	kdev_t dev;
+	ide_drive_t *ideinfo;
+	
+	dev = MKDEV(major,minor);
+	ideinfo = get_info_ptr (dev);
+	if (ideinfo==NULL)
+		return 0;
+	
+	
+	/* first sector of the last cluster */
+	if (ideinfo->head==0) 
+		return 0;
+	if (ideinfo->sect==0)
+		return 0;
+	lba = (ideinfo->capacity / (ideinfo->head*ideinfo->sect));
+	lba = lba * (ideinfo->head*ideinfo->sect);
+	lba = lba - ideinfo->sect;
+
+	return lba;
+}
+
+
+static int read_disk_sb (int major, int minor, unsigned char *buffer,int bufsize)
+{
+	int ret = -EINVAL;
+	struct buffer_head *bh = NULL;
+	kdev_t dev = MKDEV(major,minor);
+	unsigned long sb_offset;
+
+	if (blksize_size[major]==NULL)   /* device doesn't exist */
+		return -EINVAL;
+                       
+	
+	/*
+	 * Calculate the position of the superblock,
+	 * it's at first sector of the last cylinder
+	 */
+	sb_offset = calc_pdcblock_offset(major,minor)/8;
+	/* The /8 transforms sectors into 4Kb blocks */
+
+	if (sb_offset==0)
+		return -1;	
+	
+	set_blocksize (dev, 4096);
+
+	bh = bread (dev, sb_offset, 4096);
+	
+	if (bh) {
+		memcpy (buffer, bh->b_data, bufsize);
+	} else {
+		printk(KERN_ERR "pdcraid: Error reading superblock.\n");
+		goto abort;
+	}
+	ret = 0;
+abort:
+	if (bh)
+		brelse (bh);
+	return ret;
+}
+
+static unsigned int calc_sb_csum (unsigned int* ptr)
+{	
+	unsigned int sum;
+	int count;
+	
+	sum = 0;
+	for (count=0;count<511;count++)
+		sum += *ptr++;
+	
+	return sum;
+}
+
+static int cookie = 0;
+
+static void __init probedisk(int devindex,int device, int raidlevel)
+{
+	int i;
+	int major, minor;
+        struct promise_raid_conf *prom;
+	static unsigned char block[4096];
+	struct block_device *bdev;
+
+	if (devlist[devindex].device!=-1) /* already assigned to another array */
+		return;
+	
+	major = devlist[devindex].major;
+	minor = devlist[devindex].minor; 
+
+        if (read_disk_sb(major,minor,(unsigned char*)&block,sizeof(block)))
+        	return;
+                                                                                                                 
+        prom = (struct promise_raid_conf*)&block[512];
+
+        /* the checksums must match */
+	if (prom->checksum != calc_sb_csum((unsigned int*)prom))
+		return;
+	if (prom->raid.type!=raidlevel) /* different raidlevel */
+		return;
+
+	if ((cookie!=0) && (cookie != prom->raid.magic_1)) /* different array */
+		return;
+	
+	cookie = prom->raid.magic_1;
+
+	/* This looks evil. But basically, we have to search for our adapternumber
+	   in the arraydefinition, both of which are in the superblock */	
+        for (i=0;(i<prom->raid.total_disks)&&(i<8);i++) {
+        	if ( (prom->raid.disk[i].channel== prom->raid.channel) &&
+        	     (prom->raid.disk[i].device == prom->raid.device) ) {
+
+        	        bdev = bdget(MKDEV(major,minor));
+        	        if (bdev && blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW) == 0) {
+				raid[device].disk[i].bdev = bdev;
+			}
+			raid[device].disk[i].device = MKDEV(major,minor);
+			raid[device].disk[i].sectors = prom->raid.disk_secs;
+			raid[device].stride = (1<<prom->raid.raid0_shift);
+			raid[device].disks = prom->raid.total_disks;
+			raid[device].sectors = prom->raid.total_secs;
+			raid[device].geom.heads = prom->raid.heads+1;
+			raid[device].geom.sectors = prom->raid.sectors;
+			raid[device].geom.cylinders = prom->raid.cylinders+1;
+			devlist[devindex].device=device;
+        	     }
+        }
+	               
+}
+
+static void __init fill_cutoff(int device)
+{
+	int i,j;
+	unsigned long smallest;
+	unsigned long bar;
+	int count;
+	
+	bar = 0;
+	for (i=0;i<8;i++) {
+		smallest = ~0;
+		for (j=0;j<8;j++) 
+			if ((raid[device].disk[j].sectors < smallest) && (raid[device].disk[j].sectors>bar))
+				smallest = raid[device].disk[j].sectors;
+		count = 0;
+		for (j=0;j<8;j++) 
+			if (raid[device].disk[j].sectors >= smallest)
+				count++;
+				
+		smallest = smallest * count;
+		bar = smallest;
+		raid[device].cutoff[i] = smallest;
+		raid[device].cutoff_disks[i] = count;
+	}
+}
+			   
+static __init int pdcraid_init_one(int device,int raidlevel)
+{
+	int i, count;
+
+	for (i=0; i<14; i++)
+		probedisk(i, device, raidlevel);
+	
+	if (raidlevel==0)
+		fill_cutoff(device);
+	
+	/* Initialize the gendisk structure */
+	
+	ataraid_register_disk(device,raid[device].sectors);        
+		
+	count=0;
+	
+	for (i=0;i<8;i++) {
+		if (raid[device].disk[i].device!=0) {
+			printk(KERN_INFO "Drive %i is %li Mb (%i / %i) \n",
+				i,raid[device].disk[i].sectors/2048,MAJOR(raid[device].disk[i].device),MINOR(raid[device].disk[i].device));
+			count++;
+		}
+	}
+	if (count) {
+		printk(KERN_INFO "Raid%i array consists of %i drives. \n",raidlevel,count);
+		return 0;
+	} else {
+		return -ENODEV;
+	}
+}
+
+static __init int pdcraid_init(void)
+{
+	int retval, device, count = 0;
+
+	do {
+		cookie = 0;
+		device=ataraid_get_device(&pdcraid0_ops);
+		if (device<0)
+			break;
+		retval = pdcraid_init_one(device,0);
+		if (retval) {
+			ataraid_release_device(device);
+			break;
+		} else {
+			count++;
+		}
+	} while (1);
+
+	do {
+	
+		cookie = 0;
+		device=ataraid_get_device(&pdcraid1_ops);
+		if (device<0)
+			break;
+		retval = pdcraid_init_one(device,1);
+		if (retval) {
+			ataraid_release_device(device);
+			break;
+		} else {
+			count++;
+		}
+	} while (1);
+
+	if (count) {
+		printk(KERN_INFO "Promise Fasttrak(tm) Softwareraid driver for linux version 0.03beta\n");
+		return 0;
+	}
+	printk(KERN_DEBUG "Promise Fasttrak(tm) Softwareraid driver 0.03beta: No raid array found\n");
+	return -ENODEV;
+}
+
+static void __exit pdcraid_exit (void)
+{
+	int i,device;
+	for (device = 0; device<16; device++) {
+		for (i=0;i<8;i++) {
+			struct block_device *bdev = raid[device].disk[i].bdev;
+			raid[device].disk[i].bdev = NULL;
+			if (bdev)
+				blkdev_put(bdev, BDEV_RAW);
+		}	
+		if (raid[device].sectors)
+			ataraid_release_device(device);
+	}
+}
+
+static int pdcraid_open(struct inode * inode, struct file * filp) 
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+static int pdcraid_release(struct inode * inode, struct file * filp)
+{	
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+module_init(pdcraid_init);
+module_exit(pdcraid_exit);
+MODULE_LICENSE("GPL");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/raid/pdcraid.h linux.20pre10-ac2/drivers/ide/raid/pdcraid.h
--- linux.20pre10/drivers/ide/raid/pdcraid.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/raid/pdcraid.h	2002-08-29 23:47:56.000000000 +0100
@@ -0,0 +1,47 @@
+struct promise_raid_conf {
+    char                promise_id[24];
+
+    u32             dummy_0;
+    u32             magic_0;
+    u32             dummy_1;
+    u32             magic_1;
+    u16             dummy_2;
+    u8              filler1[470];
+    struct {
+        u32 flags;                          /* 0x200 */
+        u8          dummy_0;
+        u8          disk_number;
+        u8          channel;
+        u8          device;
+        u32         magic_0;
+        u32         dummy_1;
+        u32         dummy_2;                /* 0x210 */
+        u32         disk_secs;
+        u32         dummy_3;
+        u16         dummy_4;
+        u8          status;
+        u8          type;
+        u8        total_disks;            /* 0x220 */
+        u8        raid0_shift;
+        u8        raid0_disks;
+        u8        array_number;
+        u32       total_secs;
+        u16       cylinders;
+        u8        heads;
+        u8        sectors;
+        u32         magic_1;
+        u32         dummy_5;                /* 0x230 */
+        struct {
+            u16     dummy_0;
+            u8      channel;
+            u8      device;
+            u32     magic_0;
+            u32     disk_number;
+        } disk[8];
+    } raid;
+    u32             filler2[346];
+    u32            checksum;
+};
+
+#define PR_MAGIC        "Promise Technology, Inc."
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/rapide.c linux.20pre10-ac2/drivers/ide/rapide.c
--- linux.20pre10/drivers/ide/rapide.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/rapide.c	1970-01-01 01:00:00.000000000 +0100
@@ -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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/rz1000.c linux.20pre10-ac2/drivers/ide/rz1000.c
--- linux.20pre10/drivers/ide/rz1000.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/rz1000.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,97 +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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/serverworks.c linux.20pre10-ac2/drivers/ide/serverworks.c
--- linux.20pre10/drivers/ide/serverworks.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/serverworks.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,675 +0,0 @@
-/*
- * linux/drivers/ide/serverworks.c		Version 0.3	26 Oct 2001
- *
- * May be copied or modified under the terms of the GNU General Public License
- *
- * 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. ***
- *
- *
- * here's the default lspci:
- *
- * 00:0f.1 IDE interface: ServerWorks: Unknown device 0211 (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: 255
- *	Region 4: I/O ports at c200
- * 00: 66 11 11 02 05 01 00 02 00 8a 01 01 00 ff 80 00
- * 10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 20: 01 c2 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 00 00 00 00
- * 40: 99 99 99 99 ff ff ff ff 0c 0c 00 00 00 00 00 00
- * 50: 00 00 00 00 00 00 00 00 00 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
- *
- * 00:0f.1 IDE interface: ServerWorks: Unknown device 0212 (rev 92) (prog-if 8a [Master SecP PriP])
- *         Subsystem: ServerWorks: Unknown device 0212
- *         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, cache line size 08
- *         Region 0: I/O ports at 01f0
- *         Region 1: I/O ports at 03f4
- *         Region 2: I/O ports at 0170
- *         Region 3: I/O ports at 0374
- *         Region 4: I/O ports at 08b0
- *         Region 5: I/O ports at 1000
- *
- * 00:0f.1 IDE interface: ServerWorks: Unknown device 0212 (rev 92)
- * 00: 66 11 12 02 05 00 00 02 92 8a 01 01 08 40 80 00
- * 10: f1 01 00 00 f5 03 00 00 71 01 00 00 75 03 00 00
- * 20: b1 08 00 00 01 10 00 00 00 00 00 00 66 11 12 02
- * 30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- * 40: 4f 4f 4f 4f 20 ff ff ff f0 50 44 44 00 00 00 00
- * 50: 00 00 00 00 07 00 44 02 0f 04 03 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
- *
- *
- */
-
-#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>
-
-static struct pci_dev *bmide_dev;
-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 */
-extern char *ide_media_verbose(ide_drive_t *);
-
-static int svwks_get_info (char *buffer, char **addr, off_t offset, int count)
-{
-	char *p = buffer;
-	u32 bibma = pci_resource_start(bmide_dev, 4);
-	u32 reg40, reg44;
-	u16 reg48, reg56;
-	u8  reg54, c0=0, c1=0;
-
-	pci_read_config_dword(bmide_dev, 0x40, &reg40);
-	pci_read_config_dword(bmide_dev, 0x44, &reg44);
-	pci_read_config_word(bmide_dev, 0x48, &reg48);
-	pci_read_config_byte(bmide_dev, 0x54, &reg54);
-	pci_read_config_word(bmide_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(bmide_dev->device) {
-		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",
-				     bmide_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":"?");
-	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) */
-
-byte svwks_proc = 0;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-static struct pci_dev *isa_dev;
-
-static int svwks_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	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		= (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-	unsigned long dma_base	= hwif->dma_base;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-	int err;
-
-	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);
-
-        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);
-
-#ifdef DEBUG
-	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
-		drive->name, ultra_timing, dma_timing, pio_timing);
-#endif
-
-	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;
-	}
-
-#ifdef DEBUG
-	printk("%s: UDMA 0x%02x DMAPIO 0x%02x PIO 0x%02x ",
-		drive->name, ultra_timing, dma_timing, pio_timing);
-#endif
-
-#if SVWKS_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* SVWKS_DEBUG_DRIVE_INFO */
-
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-
-	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);
-	
-	if (speed > XFER_PIO_4)
-		outb(inb(dma_base+2)|(1<<(5+unit)), dma_base+2);
-	else
-		outb(inb(dma_base+2) & ~(1<<(5+unit)), dma_base+2);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return err;
-}
-
-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;
-	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	byte udma_66	= eighty_ninty_three(drive);
-	int ultra66	= (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ? 1 : 0;
-	int ultra100 	= (ultra66 && svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 1 : 0;
-	byte speed;
-
-	if ((id->dma_ultra & 0x0020) && (udma_66) && (ultra100)) {
-		speed = XFER_UDMA_5;
-	} else if (id->dma_ultra & 0x0010) {
-		speed = ((udma_66) && (ultra66)) ? XFER_UDMA_4 : XFER_UDMA_2;
-	} else if (id->dma_ultra & 0x0008) {
-		speed = ((udma_66) && (ultra66)) ? XFER_UDMA_3 : XFER_UDMA_1;
-	} else if (id->dma_ultra & 0x0004) {
-		speed = XFER_UDMA_2;
-	} else if (id->dma_ultra & 0x0002) {
-		speed = XFER_UDMA_1;
-	} else if (id->dma_ultra & 0x0001) {
-		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_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-	} else {
-		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-	}
-
-	(void) svwks_tune_chipset(drive, speed);
-
-	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;
-
-	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);
-	}
-	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(inb(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(!(inb(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 : South Bridge and IDE */
-	else if (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) {
-		/* 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;
-		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)
-	if (!svwks_proc) {
-		svwks_proc = 1;
-		bmide_dev = dev;
-		svwks_display_info = &svwks_get_info;
-	}
-#endif /* DISPLAY_SVWKS_TIMINGS && CONFIG_PROC_FS */
-	return 0;
-}
-
-/* On Dell PowerEdge servers with a CSB5, 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)
-		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;
-
-	/* 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;
-
-#ifndef CONFIG_BLK_DEV_IDEDMA
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-	hwif->autodma = 0;
-#else /* CONFIG_BLK_DEV_IDEDMA */
-	if (hwif->dma_base) {
-#ifdef CONFIG_IDEDMA_AUTO
-		if (!noautodma)
-			hwif->autodma = 1;
-#endif	
-		hwif->dmaproc = &svwks_dmaproc;
-	} else {
-		hwif->autodma = 0;
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
-	}
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/setup-pci.c linux.20pre10-ac2/drivers/ide/setup-pci.c
--- linux.20pre10/drivers/ide/setup-pci.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/setup-pci.c	2002-09-11 20:25:24.000000000 +0100
@@ -0,0 +1,866 @@
+/*
+ *  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)
+{
+#ifdef HWIF_PROBE_CLASSIC_METHOD
+	(void) do_ide_setup_pci_device(dev, d, 1);
+#else /* HWIF_PROBE_CLASSIC_METHOD */
+	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]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+}
+
+EXPORT_SYMBOL_GPL(ide_setup_pci_device);
+
+void ide_setup_pci_devices (struct pci_dev *dev, struct pci_dev *dev2, ide_pci_device_t *d)
+{
+#ifdef HWIF_PROBE_CLASSIC_METHOD
+	(void) do_ide_setup_pci_device(dev, d, 1);
+	(void) do_ide_setup_pci_device(dev2, d, 1);
+#else /* HWIF_PROBE_CLASSIC_METHOD */
+	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]);
+#endif /* HWIF_PROBE_CLASSIC_METHOD */
+}
+
+EXPORT_SYMBOL_GPL(ide_setup_pci_devices);
+
+/*
+ *	Module interfaces
+ */
+ 
+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_pci_register_driver(struct pci_driver *driver)
+{
+	if(!pre_init)
+		return pci_module_init(driver);
+	list_add_tail(&driver->node, &ide_pci_drivers);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(ide_pci_register_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_pci_unregister_driver(struct pci_driver *driver)
+{
+	if(!pre_init)
+		pci_unregister_driver(driver);
+	else
+		list_del(&driver->node);
+}
+
+EXPORT_SYMBOL_GPL(ide_pci_unregister_driver);
+
+/**
+ *	ide_scan_pcidev		-	find an IDE driver for a device
+ *	@dev: PCI device to check
+ *
+ *	Look for an IDE driver to handle the device we are considering.
+ *	This is only used during boot up to get the ordering correct. After
+ *	boot up the pci layer takes over the job.
+ */
+ 
+static int __init ide_scan_pcidev(struct pci_dev *dev)
+{
+	struct list_head *l;
+	struct pci_driver *d;
+	
+	list_for_each(l, &ide_pci_drivers)
+	{
+		d = list_entry(l, struct pci_driver, node);
+		if(d->id_table)
+		{
+			const struct pci_device_id *id = pci_match_device(d->id_table, dev);
+			if(id != NULL)
+			{
+				if(d->probe(dev, id) >= 0)
+				{
+					dev->driver = d;
+					return 1;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+/**
+ *	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;
+	struct pci_driver *d;
+	struct list_head *l, *n;
+
+	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);
+		}
+	}
+	
+	/*
+	 *	Hand the drivers over to the PCI layer now we
+	 *	are post init.
+	 */
+
+	list_for_each_safe(l, n, &ide_pci_drivers)
+	{
+		list_del(l);
+		d = list_entry(l, struct pci_driver, node);
+		pci_register_driver(d);
+	}
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/sis5513.c linux.20pre10-ac2/drivers/ide/sis5513.c
--- linux.20pre10/drivers/ide/sis5513.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/sis5513.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,861 +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;
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-
-/*
- * 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);
-	drive->current_speed = speed;
-	return ide_config_drive_speed(drive, speed);
-}
-
-static int sis5513_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-
-	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
-	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;
-	}
-
-#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));	
-	}
-	drive->current_speed = speed;
-#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, byte ultra)
-{
-	struct hd_driveid *id	= drive->id;
-	ide_hwif_t *hwif	= HWIF(drive);
-
-	byte			speed = 0;
-
-	byte unit		= (drive->select.b.unit & 0x01);
-	byte udma_66		= eighty_ninty_three(drive);
-
-#ifdef DEBUG
-	printk("SIS5513: config_chipset_for_dma, drive %d, ultra %d\n",
-	       drive->dn, ultra);
-#endif
-
-	if ((id->dma_ultra & 0x0020) && ultra && udma_66 && (chipset_family >= ATA_100a))
-		speed = XFER_UDMA_5;
-	else if ((id->dma_ultra & 0x0010) && ultra && udma_66 && (chipset_family >= ATA_66))
-		speed = XFER_UDMA_4;
-	else if ((id->dma_ultra & 0x0008) && ultra && udma_66 && (chipset_family >= ATA_66))
-		speed = XFER_UDMA_3;
-	else if ((id->dma_ultra & 0x0004) && ultra && (chipset_family >= ATA_33))
-		speed = XFER_UDMA_2;
-	else if ((id->dma_ultra & 0x0002) && ultra && (chipset_family >= ATA_33))
-		speed = XFER_UDMA_1;
-	else if ((id->dma_ultra & 0x0001) && ultra && (chipset_family >= ATA_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)
-		speed = XFER_SW_DMA_2;
-	else if (id->dma_1word & 0x0002)
-		speed = XFER_SW_DMA_1;
-	else if (id->dma_1word & 0x0001)
-		speed = XFER_SW_DMA_0;
-	else
-		return ((int) ide_dma_off_quietly);
-
-	outb(inb(hwif->dma_base+2)|(1<<(5+unit)), hwif->dma_base+2);
-
-	sis5513_tune_chipset(drive, speed);
-
-	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_off_quietly;
-
-	(void) config_chipset_for_pio(drive, 5);
-
-	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, 1);
-				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, 0);
-				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, 0);
-			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:
-		(void) config_chipset_for_pio(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;
-
-	if (!(hwif->dma_base))
-		return;
-
-	if (host_dev) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		if (chipset_family > ATA_16) {
-			hwif->autodma = noautodma ? 0 : 1;
-			hwif->dmaproc = &sis5513_dmaproc;
-		} else {
-#endif
-			hwif->autodma = 0;
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		}
-#endif
-	}
-	return;
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/sl82c105.c linux.20pre10-ac2/drivers/ide/sl82c105.c
--- linux.20pre10/drivers/ide/sl82c105.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/sl82c105.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,274 +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"
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-/*
- * 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 = inb(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;
-	}
-	outb(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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/slc90e66.c linux.20pre10-ac2/drivers/ide/slc90e66.c
--- linux.20pre10/drivers/ide/slc90e66.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/slc90e66.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,396 +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 */
-extern char *ide_media_verbose(ide_drive_t *);
-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;
-
-extern char *ide_xfer_verbose (byte xfer_rate);
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-/*
- *
- */
-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;
-	}
-}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
-
-/*
- *  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)
-{
-	unsigned long flags;
-	u16 master_data;
-	byte slave_data;
-	int is_slave		= (&HWIF(drive)->drives[1] == drive);
-	int master_port		= HWIF(drive)->index ? 0x42 : 0x40;
-	int slave_port		= 0x44;
-				 /* 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);
-	pci_read_config_word(HWIF(drive)->pci_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(HWIF(drive)->pci_dev, slave_port, &slave_data);
-		slave_data = slave_data & (HWIF(drive)->index ? 0x0f : 0xf0);
-		slave_data = slave_data | ((timings[pio][0] << 2) | (timings[pio][1]
-					   << (HWIF(drive)->index ? 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);
-	}
-	save_flags(flags);
-	cli();
-	pci_write_config_word(HWIF(drive)->pci_dev, master_port, master_data);
-	if (is_slave)
-		pci_write_config_byte(HWIF(drive)->pci_dev, slave_port, slave_data);
-	restore_flags(flags);
-}
-
-#ifdef CONFIG_BLK_DEV_IDEDMA
-static int slc90e66_tune_chipset (ide_drive_t *drive, byte speed)
-{
-	ide_hwif_t *hwif	= HWIF(drive);
-	struct pci_dev *dev	= hwif->pci_dev;
-	byte maslave		= hwif->channel ? 0x42 : 0x40;
-	int a_speed		= 7 << (drive->dn * 4);
-	int u_flag		= 1 << drive->dn;
-	int u_speed		= 0;
-	int err			= 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) {
-		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;
-#if 0	/* allow PIO modes */
-		default:		return -1;
-#endif
-	}
-
-	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);
-		}
-	}
-	if (speed < XFER_UDMA_0) {
-		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));
-
-#if SLC90E66_DEBUG_DRIVE_INFO
-	printk("%s: %s drive%d\n", drive->name, ide_xfer_verbose(speed), drive->dn);
-#endif /* SLC90E66_DEBUG_DRIVE_INFO */
-	if (!drive->init_speed)
-		drive->init_speed = speed;
-	err = ide_config_drive_speed(drive, speed);
-	drive->current_speed = speed;
-	return err;
-}
-
-static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
-{
-	struct hd_driveid *id	= drive->id;
-	int ultra		= 1;
-	byte speed		= 0;
-	byte udma_66		= eighty_ninty_three(drive);
-
-#if 1 /* allow PIO modes */
-	if (!HWIF(drive)->autodma) {
-		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-		(void) slc90e66_tune_chipset(drive, speed);
-		return ((int) ide_dma_off_quietly);
-	}
-#endif
-	if ((id->dma_ultra & 0x0010) && (ultra)) {
-		speed = (udma_66) ? XFER_UDMA_4 : XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0008) && (ultra)) {
-		speed = (udma_66) ? XFER_UDMA_3 : XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0004) && (ultra)) {
-		speed = XFER_UDMA_2;
-	} else if ((id->dma_ultra & 0x0002) && (ultra)) {
-		speed = XFER_UDMA_1;
-	} else if ((id->dma_ultra & 0x0001) && (ultra)) {
-		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_1word & 0x0004) {
-		speed = XFER_SW_DMA_2;
-        } else {
-		speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-	}
-
-	(void) slc90e66_tune_chipset(drive, speed);
-
-	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 slc90e66_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
-{
-	switch (func) {
-		case ide_dma_check:
-			 return ide_dmaproc((ide_dma_action_t) slc90e66_config_drive_for_dma(drive), 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)
-{
-#if 1
-	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 */
-#else
-	byte ata66 = 0;
-#endif
-	return ata66;
-}
-
-void __init ide_init_slc90e66 (ide_hwif_t *hwif)
-{
-	if (!hwif->irq)
-		hwif->irq = hwif->channel ? 15 : 14;
-
-	hwif->tuneproc = &slc90e66_tune_drive;
-	hwif->drives[0].autotune = 1;
-	hwif->drives[1].autotune = 1;
-
-	if (!hwif->dma_base)
-		return;
-
-	hwif->autodma = 0;
-#ifdef CONFIG_BLK_DEV_IDEDMA 
-	if (!noautodma)
-		hwif->autodma = 1;
-	hwif->dmaproc = &slc90e66_dmaproc;
-	hwif->speedproc = &slc90e66_tune_chipset;
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/trm290.c linux.20pre10-ac2/drivers/ide/trm290.c
--- linux.20pre10/drivers/ide/trm290.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/trm290.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,289 +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);
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-
-	if (reg != hwif->select_data) {
-		hwif->select_data = reg;
-		outb(0x51|(hwif->channel<<3), hwif->config_data+1);	/* set PIO/DMA */
-		outw(reg & 0xff, hwif->config_data);
-	}
-
-	/* enable IRQ if not probing */
-	if (drive->present) {
-		reg = inw(hwif->config_data+3) & 0x13;
-		reg &= ~(1 << hwif->channel);
-		outw(reg, hwif->config_data+3);
-	}
-
-	__restore_flags(flags);	/* local CPU only */
-}
-
-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);
-	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)))
-				break;		/* try PIO instead of DMA */
-			trm290_prepare_drive(drive, 1);	/* select DMA xfer */
-			outl(hwif->dmatable_dma|reading|writing, hwif->dma_base);
-			drive->waiting_for_dma = 1;
-			outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */
-			if (drive->media != ide_disk)
-				return 0;
-			ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);
-			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
-			return 0;
-		case ide_dma_begin:
-			return 0;
-		case ide_dma_end:
-			drive->waiting_for_dma = 0;
-			ide_destroy_dmatable(drive);		/* purge DMA mappings */
-			return (inw(hwif->dma_base+2) != 0x00ff);
-		case ide_dma_test_irq:
-			return (inw(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);
-	}
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	/* put config reg into first byte of hwif->select_data */
-	outb(0x51|(hwif->channel<<3), hwif->config_data+1);
-	hwif->select_data = 0x21;			/* select PIO as default */
-	outb(hwif->select_data, hwif->config_data);
-	reg = inb(hwif->config_data+3);			/* get IRQ info */
-	reg = (reg & 0x10) | 0x03;			/* mask IRQs for both ports */
-	outb(reg, hwif->config_data+3);
-	__restore_flags(flags);	/* local CPU only */
-
-	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;
-
-		outb(0x54|(hwif->channel<<3), hwif->config_data+1);
-		old = inw(hwif->config_data) & ~1;
-		if (old != compat && inb(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;
-			outw(compat|1, hwif->config_data);
-			printk("%s: control basereg workaround: old=0x%04x, new=0x%04x\n", hwif->name, old, inw(hwif->config_data) & ~1);
-		}
-	}
-#endif
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/umc8672.c linux.20pre10-ac2/drivers/ide/umc8672.c
--- linux.20pre10/drivers/ide/umc8672.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/umc8672.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,160 +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]);
-	save_flags(flags);	/* all CPUs */
-	cli();			/* all CPUs */
-	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);
-	}
-	restore_flags(flags);	/* all CPUs */
-}
-
-void __init init_umc8672 (void)	/* called from ide.c */
-{
-	unsigned long flags;
-
-	__save_flags(flags);	/* local CPU only */
-	__cli();		/* local CPU only */
-	if (check_region(0x108, 2)) {
-		__restore_flags(flags);
-		printk("\numc8672: PORTS 0x108-0x109 ALREADY IN USE\n");
-		return;
-	}
-	outb_p (0x5A,0x108); /* enable umc */
-	if (in_umc (0xd5) != 0xa0)
-	{
-		__restore_flags(flags);	/* local CPU only */
-		printk ("umc8672: not found\n");
-		return;  
-	}
-	outb_p (0xa5,0x108); /* disable umc */
-
-	umc_set_speeds (current_speeds);
-	__restore_flags(flags);	/* local CPU only */
-
-	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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/ide/via82cxxx.c linux.20pre10-ac2/drivers/ide/via82cxxx.c
--- linux.20pre10/drivers/ide/via82cxxx.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/ide/via82cxxx.c	1970-01-01 01:00:00.000000000 +0100
@@ -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 = 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);
-
-	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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/isdn/hisax/config.c linux.20pre10-ac2/drivers/isdn/hisax/config.c
--- linux.20pre10/drivers/isdn/hisax/config.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/isdn/hisax/config.c	2002-09-30 17:23:32.000000000 +0100
@@ -1526,7 +1526,8 @@
 	       nrcards, (nrcards > 1) ? "s" : "");
 
 	/* Install only, if at least one card found */
-	HiSax_inithardware(NULL);
+	if (!HiSax_inithardware(NULL))
+		return -ENODEV;
 	return 0;
 
  out_tei:
@@ -1594,7 +1595,8 @@
 	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
 	       nrcards, (nrcards > 1) ? "s" : "");
 
-	HiSax_inithardware(busy_flag);
+	if (!HiSax_inithardware(busy_flag))
+		return -ENODEV;
 	printk(KERN_NOTICE "HiSax: module installed\n");
 #endif
 	return 0;
@@ -1636,7 +1638,8 @@
 	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
 	       nrcards, (nrcards > 1) ? "s" : "");
 
-	HiSax_inithardware(busy_flag);
+	if (!HiSax_inithardware(busy_flag))
+		return -ENODEV;
 	printk(KERN_NOTICE "HiSax: module installed\n");
 #endif
 	return 0;
@@ -1678,7 +1681,8 @@
 	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
 	       nrcards, (nrcards > 1) ? "s" : "");
 
-	HiSax_inithardware(busy_flag);
+	if (!HiSax_inithardware(busy_flag))
+		return -ENODEV;
 	printk(KERN_NOTICE "HiSax: module installed\n");
 #endif
 	return 0;
@@ -1720,7 +1724,8 @@
 	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
 	       nrcards, (nrcards > 1) ? "s" : "");
 
-	HiSax_inithardware(busy_flag);
+	if (!HiSax_inithardware(busy_flag))
+		return -ENODEV;
 	printk(KERN_NOTICE "HiSax: module installed\n");
 #endif
 	return 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/isdn/hisax/st5481.h linux.20pre10-ac2/drivers/isdn/hisax/st5481.h
--- linux.20pre10/drivers/isdn/hisax/st5481.h	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/isdn/hisax/st5481.h	2002-10-11 00:35:04.000000000 +0100
@@ -218,6 +218,19 @@
 
 #define L1_EVENT_COUNT (EV_TIMER3 + 1)
 
+#if (__GNUC__ > 2)
+
+#define ERR(format, arg...) \
+printk(KERN_ERR __FILE__ ": %s: " format "\n" , __FUNCTION__ , ## arg)
+
+#define WARN(format, arg...) \
+printk(KERN_WARNING __FILE__ ": %s: " format "\n" , __FUNCTION__ , ## arg)
+
+#define INFO(format, arg...) \
+printk(KERN_INFO __FILE__ ": %s: " format "\n" , __FUNCTION__ , ## arg)
+
+#else
+
 #define ERR(format, arg...) \
 printk(KERN_ERR __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
 
@@ -227,6 +240,8 @@
 #define INFO(format, arg...) \
 printk(KERN_INFO __FILE__ ": " __FUNCTION__ ": " format "\n" , ## arg)
 
+#endif
+
 #include "st5481_hdlc.h"
 #include "fsm.h"
 #include "hisax_if.h"
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/macintosh/apm_emu.c linux.20pre10-ac2/drivers/macintosh/apm_emu.c
--- linux.20pre10/drivers/macintosh/apm_emu.c	2002-10-09 21:36:54.000000000 +0100
+++ linux.20pre10-ac2/drivers/macintosh/apm_emu.c	2002-09-27 14:05:45.000000000 +0100
@@ -183,7 +183,7 @@
 static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos)
 {
 	struct apm_user *	as;
-	int			i;
+	size_t			i;
 	apm_event_t		event;
 	DECLARE_WAITQUEUE(wait, current);
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/md/Config.in linux.20pre10-ac2/drivers/md/Config.in
--- linux.20pre10/drivers/md/Config.in	2002-10-09 21:36:57.000000000 +0100
+++ linux.20pre10-ac2/drivers/md/Config.in	2002-08-12 22:42:29.000000000 +0100
@@ -14,5 +14,8 @@
 dep_tristate '  Multipath I/O support' CONFIG_MD_MULTIPATH $CONFIG_BLK_DEV_MD
 
 dep_tristate ' Logical volume manager (LVM) support' CONFIG_BLK_DEV_LVM $CONFIG_MD
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   dep_tristate ' Device-mapper support (EXPERIMENTAL)' CONFIG_BLK_DEV_DM $CONFIG_MD
+fi
 
 endmenu
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/md/dm.c linux.20pre10-ac2/drivers/md/dm.c
--- linux.20pre10/drivers/md/dm.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/md/dm.c	2002-08-15 13:15:20.000000000 +0100
@@ -0,0 +1,1158 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm.h"
+
+#include <linux/blk.h>
+#include <linux/blkpg.h>
+
+/* we only need this for the lv_bmap struct definition, not happy */
+#include <linux/lvm.h>
+
+#define DEFAULT_READ_AHEAD 64
+
+static const char *_name = DM_NAME;
+
+static int major = 0;
+static int _major = 0;
+
+struct io_hook {
+	struct mapped_device *md;
+	struct target *target;
+	int rw;
+
+	void (*end_io) (struct buffer_head * bh, int uptodate);
+	void *context;
+};
+
+static kmem_cache_t *_io_hook_cache;
+
+static struct mapped_device *_devs[MAX_DEVICES];
+static struct rw_semaphore _dev_locks[MAX_DEVICES];
+
+/*
+ * This lock is only held by dm_create and dm_set_name to avoid
+ * race conditions where someone else may create a device with
+ * the same name.
+ */
+static spinlock_t _create_lock = SPIN_LOCK_UNLOCKED;
+
+/* block device arrays */
+static int _block_size[MAX_DEVICES];
+static int _blksize_size[MAX_DEVICES];
+static int _hardsect_size[MAX_DEVICES];
+
+static devfs_handle_t _dev_dir;
+
+static int request(request_queue_t * q, int rw, struct buffer_head *bh);
+static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb);
+
+/*
+ * Protect the mapped_devices referenced from _dev[]
+ */
+struct mapped_device *dm_get_r(int minor)
+{
+	struct mapped_device *md;
+
+	if (minor >= MAX_DEVICES)
+		return NULL;
+
+	down_read(_dev_locks + minor);
+	md = _devs[minor];
+	if (!md)
+		up_read(_dev_locks + minor);
+	return md;
+}
+
+struct mapped_device *dm_get_w(int minor)
+{
+	struct mapped_device *md;
+
+	if (minor >= MAX_DEVICES)
+		return NULL;
+
+	down_write(_dev_locks + minor);
+	md = _devs[minor];
+	if (!md)
+		up_write(_dev_locks + minor);
+	return md;
+}
+
+static int namecmp(struct mapped_device *md, const char *name, int nametype)
+{
+	switch (nametype) {
+	case DM_LOOKUP_BY_NAME:
+		return strcmp(md->name, name);
+		break;
+
+	case DM_LOOKUP_BY_UUID:
+		if (!md->uuid)
+			return -1;	/* never equal */
+
+		return strcmp(md->uuid, name);
+		break;
+
+	default:
+		DMWARN("Unknown comparison type in namecmp: %d", nametype);
+		BUG();
+	}
+
+	return -1;
+}
+
+/*
+ * The interface (eg, ioctl) will probably access the devices
+ * through these slow 'by name' locks, this needs improving at
+ * some point if people start playing with *large* numbers of dm
+ * devices.
+ */
+struct mapped_device *dm_get_name_r(const char *name, int nametype)
+{
+	int i;
+	struct mapped_device *md;
+
+	for (i = 0; i < MAX_DEVICES; i++) {
+		md = dm_get_r(i);
+		if (md) {
+			if (!namecmp(md, name, nametype))
+				return md;
+
+			dm_put_r(md);
+		}
+	}
+
+	return NULL;
+}
+
+struct mapped_device *dm_get_name_w(const char *name, int nametype)
+{
+	int i;
+	struct mapped_device *md;
+
+	/*
+	 * To avoid getting write locks on all the devices we try
+	 * and promote a read lock to a write lock, this can
+	 * fail, in which case we just start again.
+	 */
+
+      restart:
+	for (i = 0; i < MAX_DEVICES; i++) {
+		md = dm_get_r(i);
+		if (!md)
+			continue;
+
+		if (namecmp(md, name, nametype)) {
+			dm_put_r(md);
+			continue;
+		}
+
+		/* found it */
+		dm_put_r(md);
+
+		md = dm_get_w(i);
+		if (!md)
+			goto restart;
+
+		if (namecmp(md, name, nametype)) {
+			dm_put_w(md);
+			goto restart;
+		}
+
+		return md;
+	}
+
+	return NULL;
+}
+
+void dm_put_r(struct mapped_device *md)
+{
+	int minor = MINOR(md->dev);
+
+	if (minor >= MAX_DEVICES)
+		return;
+
+	up_read(_dev_locks + minor);
+}
+
+void dm_put_w(struct mapped_device *md)
+{
+	int minor = MINOR(md->dev);
+
+	if (minor >= MAX_DEVICES)
+		return;
+
+	up_write(_dev_locks + minor);
+}
+
+/*
+ * Setup and tear down the driver
+ */
+static __init void init_locks(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_DEVICES; i++)
+		init_rwsem(_dev_locks + i);
+}
+
+static __init int local_init(void)
+{
+	int r;
+
+	init_locks();
+
+	/* allocate a slab for the io-hooks */
+	if (!_io_hook_cache &&
+	    !(_io_hook_cache = kmem_cache_create("dm io hooks",
+						 sizeof(struct io_hook),
+						 0, 0, NULL, NULL)))
+		return -ENOMEM;
+
+	_major = major;
+	r = devfs_register_blkdev(_major, _name, &dm_blk_dops);
+	if (r < 0) {
+		DMERR("register_blkdev failed");
+		kmem_cache_destroy(_io_hook_cache);
+		return r;
+	}
+
+	if (!_major)
+		_major = r;
+
+	/* set up the arrays */
+	read_ahead[_major] = DEFAULT_READ_AHEAD;
+	blk_size[_major] = _block_size;
+	blksize_size[_major] = _blksize_size;
+	hardsect_size[_major] = _hardsect_size;
+
+	blk_queue_make_request(BLK_DEFAULT_QUEUE(_major), request);
+
+	_dev_dir = devfs_mk_dir(0, DM_DIR, NULL);
+
+	return 0;
+}
+
+static void local_exit(void)
+{
+	if (kmem_cache_destroy(_io_hook_cache))
+		DMWARN("io_hooks still allocated during unregistration");
+	_io_hook_cache = NULL;
+
+	if (devfs_unregister_blkdev(_major, _name) < 0)
+		DMERR("devfs_unregister_blkdev failed");
+
+	read_ahead[_major] = 0;
+	blk_size[_major] = NULL;
+	blksize_size[_major] = NULL;
+	hardsect_size[_major] = NULL;
+	_major = 0;
+
+	DMINFO("cleaned up");
+}
+
+/*
+ * We have a lot of init/exit functions, so it seems easier to
+ * store them in an array.  The disposable macro 'xx'
+ * expands a prefix into a pair of function names.
+ */
+static struct {
+	int (*init)(void);
+	void (*exit)(void);
+
+} _inits[] = {
+#define xx(n) {n ## _init, n ## _exit},
+	xx(local)
+	xx(dm_target)
+	xx(dm_linear)
+	xx(dm_stripe)
+	xx(dm_snapshot)
+	xx(dm_interface)
+#undef xx
+};
+
+static int __init dm_init(void)
+{
+	const int count = sizeof(_inits) / sizeof(*_inits);
+
+	int r, i;
+
+	for (i = 0; i < count; i++) {
+		r = _inits[i].init();
+		if (r)
+			goto bad;
+	}
+
+	return 0;
+
+      bad:
+	while (i--)
+		_inits[i].exit();
+
+	return r;
+}
+
+static void __exit dm_exit(void)
+{
+	int i = sizeof(_inits) / sizeof(*_inits);
+
+	dm_destroy_all();
+	while (i--)
+		_inits[i].exit();
+}
+
+/*
+ * Block device functions
+ */
+static int dm_blk_open(struct inode *inode, struct file *file)
+{
+	struct mapped_device *md;
+
+	md = dm_get_w(MINOR(inode->i_rdev));
+	if (!md)
+		return -ENXIO;
+
+	md->use_count++;
+	dm_put_w(md);
+
+	return 0;
+}
+
+static int dm_blk_close(struct inode *inode, struct file *file)
+{
+	struct mapped_device *md;
+
+	md = dm_get_w(MINOR(inode->i_rdev));
+	if (!md)
+		return -ENXIO;
+
+	if (md->use_count < 1)
+		DMWARN("incorrect reference count found in mapped_device");
+
+	md->use_count--;
+	dm_put_w(md);
+
+	return 0;
+}
+
+/* In 512-byte units */
+#define VOLUME_SIZE(minor) (_block_size[(minor)] << 1)
+
+static int dm_blk_ioctl(struct inode *inode, struct file *file,
+			uint command, unsigned long a)
+{
+	int minor = MINOR(inode->i_rdev);
+	long size;
+
+	if (minor >= MAX_DEVICES)
+		return -ENXIO;
+
+	switch (command) {
+	case BLKROSET:
+	case BLKROGET:
+	case BLKRASET:
+	case BLKRAGET:
+	case BLKFLSBUF:
+	case BLKSSZGET:
+		//case BLKRRPART: /* Re-read partition tables */
+		//case BLKPG:
+	case BLKELVGET:
+	case BLKELVSET:
+	case BLKBSZGET:
+	case BLKBSZSET:
+		return blk_ioctl(inode->i_rdev, command, a);
+		break;
+
+	case BLKGETSIZE:
+		size = VOLUME_SIZE(minor);
+		if (copy_to_user((void *) a, &size, sizeof(long)))
+			return -EFAULT;
+		break;
+
+	case BLKGETSIZE64:
+		size = VOLUME_SIZE(minor);
+		if (put_user((u64) ((u64) size) << 9, (u64 *) a))
+			return -EFAULT;
+		break;
+
+	case BLKRRPART:
+		return -ENOTTY;
+
+	case LV_BMAP:
+		return dm_user_bmap(inode, (struct lv_bmap *) a);
+
+	default:
+		DMWARN("unknown block ioctl 0x%x", command);
+		return -ENOTTY;
+	}
+
+	return 0;
+}
+
+static inline struct io_hook *alloc_io_hook(void)
+{
+	return kmem_cache_alloc(_io_hook_cache, GFP_NOIO);
+}
+
+static inline void free_io_hook(struct io_hook *ih)
+{
+	kmem_cache_free(_io_hook_cache, ih);
+}
+
+/*
+ * FIXME: We need to decide if deferred_io's need
+ * their own slab, I say no for now since they are
+ * only used when the device is suspended.
+ */
+static inline struct deferred_io *alloc_deferred(void)
+{
+	return kmalloc(sizeof(struct deferred_io), GFP_NOIO);
+}
+
+static inline void free_deferred(struct deferred_io *di)
+{
+	kfree(di);
+}
+
+/*
+ * Call a target's optional error function if an I/O failed.
+ */
+static inline int call_err_fn(struct io_hook *ih, struct buffer_head *bh)
+{
+	dm_err_fn err = ih->target->type->err;
+
+	if (err)
+		return err(bh, ih->rw, ih->target->private);
+
+	return 0;
+}
+
+/*
+ * bh->b_end_io routine that decrements the pending count
+ * and then calls the original bh->b_end_io fn.
+ */
+static void dec_pending(struct buffer_head *bh, int uptodate)
+{
+	struct io_hook *ih = bh->b_private;
+
+	if (!uptodate && call_err_fn(ih, bh))
+		return;
+
+	if (atomic_dec_and_test(&ih->md->pending))
+		/* nudge anyone waiting on suspend queue */
+		wake_up(&ih->md->wait);
+
+	bh->b_end_io = ih->end_io;
+	bh->b_private = ih->context;
+	free_io_hook(ih);
+
+	bh->b_end_io(bh, uptodate);
+}
+
+/*
+ * Add the bh to the list of deferred io.
+ */
+static int queue_io(struct buffer_head *bh, int rw)
+{
+	struct deferred_io *di = alloc_deferred();
+	struct mapped_device *md;
+
+	if (!di)
+		return -ENOMEM;
+
+	md = dm_get_w(MINOR(bh->b_rdev));
+	if (!md) {
+		free_deferred(di);
+		return -ENXIO;
+	}
+
+	if (!md->suspended) {
+		dm_put_w(md);
+		free_deferred(di);
+		return 1;
+	}
+
+	di->bh = bh;
+	di->rw = rw;
+	di->next = md->deferred;
+	md->deferred = di;
+
+	dm_put_w(md);
+
+	return 0;		/* deferred successfully */
+}
+
+/*
+ * Do the bh mapping for a given leaf
+ */
+static inline int __map_buffer(struct mapped_device *md,
+			       struct buffer_head *bh, int rw, int leaf)
+{
+	int r;
+	dm_map_fn fn;
+	void *context;
+	struct io_hook *ih = NULL;
+	struct target *ti = md->map->targets + leaf;
+
+	fn = ti->type->map;
+	context = ti->private;
+
+	ih = alloc_io_hook();
+
+	if (!ih)
+		return -1;
+
+	ih->md = md;
+	ih->rw = rw;
+	ih->target = ti;
+	ih->end_io = bh->b_end_io;
+	ih->context = bh->b_private;
+
+	r = fn(bh, rw, context);
+
+	if (r > 0) {
+		/* hook the end io request fn */
+		atomic_inc(&md->pending);
+		bh->b_end_io = dec_pending;
+		bh->b_private = ih;
+
+	} else if (r == 0)
+		/* we don't need to hook */
+		free_io_hook(ih);
+
+	else if (r < 0) {
+		free_io_hook(ih);
+		return -1;
+	}
+
+	return r;
+}
+
+/*
+ * Search the btree for the correct target.
+ */
+static inline int __find_node(struct dm_table *t, struct buffer_head *bh)
+{
+	int l, n = 0, k = 0;
+	offset_t *node;
+
+	for (l = 0; l < t->depth; l++) {
+		n = get_child(n, k);
+		node = get_node(t, l, n);
+
+		for (k = 0; k < KEYS_PER_NODE; k++)
+			if (node[k] >= bh->b_rsector)
+				break;
+	}
+
+	return (KEYS_PER_NODE * n) + k;
+}
+
+static int request(request_queue_t * q, int rw, struct buffer_head *bh)
+{
+	struct mapped_device *md;
+	int r, minor = MINOR(bh->b_rdev);
+	unsigned int block_size = _blksize_size[minor];
+
+	md = dm_get_r(minor);
+	if (!md) {
+		buffer_IO_error(bh);
+		return 0;
+	}
+
+	/*
+	 * Sanity checks.
+	 */
+	if (bh->b_size > block_size)
+		DMERR("request is larger than block size "
+		      "b_size (%d), block size (%d)",
+		      bh->b_size, block_size);
+
+	if (bh->b_rsector & ((bh->b_size >> 9) - 1))
+		DMERR("misaligned block requested logical "
+		      "sector (%lu), b_size (%d)",
+		      bh->b_rsector, bh->b_size);
+
+	/*
+	 * If we're suspended we have to queue
+	 * this io for later.
+	 */
+	while (md->suspended) {
+		dm_put_r(md);
+
+		if (rw == READA)
+			goto bad_no_lock;
+
+		r = queue_io(bh, rw);
+
+		if (r < 0)
+			goto bad_no_lock;
+
+		else if (r == 0)
+			return 0;	/* deferred successfully */
+
+		/*
+		 * We're in a while loop, because someone could suspend
+		 * before we get to the following read lock.
+		 */
+		md = dm_get_r(minor);
+		if (!md) {
+			buffer_IO_error(bh);
+			return 0;
+		}
+	}
+
+	if ((r = __map_buffer(md, bh, rw, __find_node(md->map, bh))) < 0)
+		goto bad;
+
+	dm_put_r(md);
+	return r;
+
+      bad:
+	dm_put_r(md);
+
+      bad_no_lock:
+	buffer_IO_error(bh);
+	return 0;
+}
+
+static int check_dev_size(int minor, unsigned long block)
+{
+	/* FIXME: check this */
+	unsigned long max_sector = (_block_size[minor] << 1) + 1;
+	unsigned long sector = (block + 1) * (_blksize_size[minor] >> 9);
+
+	return (sector > max_sector) ? 0 : 1;
+}
+
+/*
+ * Creates a dummy buffer head and maps it (for lilo).
+ */
+static int do_bmap(kdev_t dev, unsigned long block,
+		   kdev_t * r_dev, unsigned long *r_block)
+{
+	struct mapped_device *md;
+	struct buffer_head bh;
+	int minor = MINOR(dev), r;
+	struct target *t;
+
+	md = dm_get_r(minor);
+	if (!md)
+		return -ENXIO;
+
+	if (md->suspended) {
+		dm_put_r(md);
+		return -EPERM;
+	}
+
+	if (!check_dev_size(minor, block)) {
+		dm_put_r(md);
+		return -EINVAL;
+	}
+
+	/* setup dummy bh */
+	memset(&bh, 0, sizeof(bh));
+	bh.b_blocknr = block;
+	bh.b_dev = bh.b_rdev = dev;
+	bh.b_size = _blksize_size[minor];
+	bh.b_rsector = block * (bh.b_size >> 9);
+
+	/* find target */
+	t = md->map->targets + __find_node(md->map, &bh);
+
+	/* do the mapping */
+	r = t->type->map(&bh, READ, t->private);
+
+	*r_dev = bh.b_rdev;
+	*r_block = bh.b_rsector / (bh.b_size >> 9);
+
+	dm_put_r(md);
+	return r;
+}
+
+/*
+ * Marshals arguments and results between user and kernel space.
+ */
+static int dm_user_bmap(struct inode *inode, struct lv_bmap *lvb)
+{
+	unsigned long block, r_block;
+	kdev_t r_dev;
+	int r;
+
+	if (get_user(block, &lvb->lv_block))
+		return -EFAULT;
+
+	if ((r = do_bmap(inode->i_rdev, block, &r_dev, &r_block)))
+		return r;
+
+	if (put_user(kdev_t_to_nr(r_dev), &lvb->lv_dev) ||
+	    put_user(r_block, &lvb->lv_block))
+		return -EFAULT;
+
+	return 0;
+}
+
+/*
+ * See if the device with a specific minor # is free.  The write
+ * lock is held when it returns successfully.
+ */
+static inline int specific_dev(int minor, struct mapped_device *md)
+{
+	if (minor >= MAX_DEVICES) {
+		DMWARN("request for a mapped_device beyond MAX_DEVICES (%d)",
+		       MAX_DEVICES);
+		return -1;
+	}
+
+	down_write(_dev_locks + minor);
+	if (_devs[minor]) {
+		/* in use */
+		up_write(_dev_locks + minor);
+		return -1;
+	}
+
+	return minor;
+}
+
+/*
+ * Find the first free device.  Again the write lock is held on
+ * success.
+ */
+static int any_old_dev(struct mapped_device *md)
+{
+	int i;
+
+	for (i = 0; i < MAX_DEVICES; i++)
+		if (specific_dev(i, md) != -1)
+			return i;
+
+	return -1;
+}
+
+/*
+ * Allocate and initialise a blank device.
+ * Caller must ensure uuid is null-terminated.
+ * Device is returned with a write lock held.
+ */
+static struct mapped_device *alloc_dev(const char *name, const char *uuid,
+				       int minor)
+{
+	struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL);
+	int len;
+
+	if (!md) {
+		DMWARN("unable to allocate device, out of memory.");
+		return NULL;
+	}
+
+	memset(md, 0, sizeof(*md));
+
+	/*
+	 * This grabs the write lock if it succeeds.
+	 */
+	minor = (minor < 0) ? any_old_dev(md) : specific_dev(minor, md);
+	if (minor < 0) {
+		kfree(md);
+		return NULL;
+	}
+
+	md->dev = MKDEV(_major, minor);
+	md->suspended = 0;
+
+	strncpy(md->name, name, sizeof(md->name) - 1);
+	md->name[sizeof(md->name) - 1] = '\0';
+
+	/*
+	 * Copy in the uuid.
+	 */
+	if (uuid && *uuid) {
+		len = strlen(uuid) + 1;
+		if (!(md->uuid = kmalloc(len, GFP_KERNEL))) {
+			DMWARN("unable to allocate uuid - out of memory.");
+			kfree(md);
+			return NULL;
+		}
+		strcpy(md->uuid, uuid);
+	}
+
+	init_waitqueue_head(&md->wait);
+	return md;
+}
+
+static int __register_device(struct mapped_device *md)
+{
+	md->devfs_entry =
+	    devfs_register(_dev_dir, md->name, DEVFS_FL_CURRENT_OWNER,
+			   MAJOR(md->dev), MINOR(md->dev),
+			   S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
+			   &dm_blk_dops, NULL);
+
+	return 0;
+}
+
+static int __unregister_device(struct mapped_device *md)
+{
+	devfs_unregister(md->devfs_entry);
+	return 0;
+}
+
+/*
+ * The hardsect size for a mapped device is the largest hardsect size
+ * from the devices it maps onto.
+ */
+static int __find_hardsect_size(struct list_head *devices)
+{
+	int result = 512, size;
+	struct list_head *tmp;
+
+	list_for_each(tmp, devices) {
+		struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
+		size = get_hardsect_size(dd->dev);
+		if (size > result)
+			result = size;
+	}
+
+	return result;
+}
+
+/*
+ * Bind a table to the device.
+ */
+static int __bind(struct mapped_device *md, struct dm_table *t)
+{
+	int minor = MINOR(md->dev);
+
+	md->map = t;
+
+	if (!t->num_targets) {
+		_block_size[minor] = 0;
+		_blksize_size[minor] = BLOCK_SIZE;
+		_hardsect_size[minor] = 0;
+		return 0;
+	}
+
+	/* in k */
+	_block_size[minor] = (t->highs[t->num_targets - 1] + 1) >> 1;
+
+	_blksize_size[minor] = BLOCK_SIZE;
+	_hardsect_size[minor] = __find_hardsect_size(&t->devices);
+	register_disk(NULL, md->dev, 1, &dm_blk_dops, _block_size[minor]);
+
+	return 0;
+}
+
+static void __unbind(struct mapped_device *md)
+{
+	int minor = MINOR(md->dev);
+
+	dm_table_destroy(md->map);
+	md->map = NULL;
+
+	_block_size[minor] = 0;
+	_blksize_size[minor] = 0;
+	_hardsect_size[minor] = 0;
+}
+
+static int check_name(const char *name)
+{
+	struct mapped_device *md;
+
+	if (strchr(name, '/') || strlen(name) > DM_NAME_LEN) {
+		DMWARN("invalid device name");
+		return -1;
+	}
+
+	md = dm_get_name_r(name, DM_LOOKUP_BY_NAME);
+	if (md) {
+		dm_put_r(md);
+		DMWARN("device name already in use");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int check_uuid(const char *uuid)
+{
+	struct mapped_device *md;
+
+	if (uuid) {
+		md = dm_get_name_r(uuid, DM_LOOKUP_BY_UUID);
+		if (md) {
+			dm_put_r(md);
+			DMWARN("device uuid already in use");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Constructor for a new device.
+ */
+int dm_create(const char *name, const char *uuid, int minor, int ro,
+	      struct dm_table *table)
+{
+	int r;
+	struct mapped_device *md;
+
+	spin_lock(&_create_lock);
+	if (check_name(name) || check_uuid(uuid)) {
+		spin_unlock(&_create_lock);
+		return -EINVAL;
+	}
+
+	md = alloc_dev(name, uuid, minor);
+	if (!md) {
+		spin_unlock(&_create_lock);
+		return -ENXIO;
+	}
+	minor = MINOR(md->dev);
+	_devs[minor] = md;
+
+	r = __register_device(md);
+	if (r)
+		goto err;
+
+	r = __bind(md, table);
+	if (r)
+		goto err;
+
+	dm_set_ro(md, ro);
+
+	spin_unlock(&_create_lock);
+	dm_put_w(md);
+	return 0;
+
+      err:
+	_devs[minor] = NULL;
+	if (md->uuid)
+		kfree(md->uuid);
+
+	dm_put_w(md);
+	kfree(md);
+	spin_unlock(&_create_lock);
+	return r;
+}
+
+/*
+ * Renames the device.  No lock held.
+ */
+int dm_set_name(const char *name, int nametype, const char *newname)
+{
+	int r;
+	struct mapped_device *md;
+
+	spin_lock(&_create_lock);
+	if (check_name(newname) < 0) {
+		spin_unlock(&_create_lock);
+		return -EINVAL;
+	}
+
+	md = dm_get_name_w(name, nametype);
+	if (!md) {
+		spin_unlock(&_create_lock);
+		return -ENXIO;
+	}
+
+	r = __unregister_device(md);
+	if (r)
+		goto out;
+
+	strcpy(md->name, newname);
+	r = __register_device(md);
+
+      out:
+	dm_put_w(md);
+	spin_unlock(&_create_lock);
+	return r;
+}
+
+/*
+ * Destructor for the device.  You cannot destroy an open
+ * device.  Write lock must be held before calling.
+ * Caller must dm_put_w(md) then kfree(md) if call was successful.
+ */
+int dm_destroy(struct mapped_device *md)
+{
+	int minor, r;
+
+	if (md->use_count)
+		return -EPERM;
+
+	r = __unregister_device(md);
+	if (r)
+		return r;
+
+	minor = MINOR(md->dev);
+	_devs[minor] = NULL;
+	__unbind(md);
+
+	if (md->uuid)
+		kfree(md->uuid);
+
+	return 0;
+}
+
+/*
+ * Destroy all devices - except open ones
+ */
+void dm_destroy_all(void)
+{
+	int i, some_destroyed, r;
+	struct mapped_device *md;
+
+	do {
+		some_destroyed = 0;
+		for (i = 0; i < MAX_DEVICES; i++) {
+			md = dm_get_w(i);
+			if (!md)
+				continue;
+
+			r = dm_destroy(md);
+			dm_put_w(md);
+
+			if (!r) {
+				kfree(md);
+				some_destroyed = 1;
+			}
+		}
+	} while (some_destroyed);
+}
+
+/*
+ * Sets or clears the read-only flag for the device.  Write lock
+ * must be held.
+ */
+void dm_set_ro(struct mapped_device *md, int ro)
+{
+	md->read_only = ro;
+	set_device_ro(md->dev, ro);
+}
+
+/*
+ * Requeue the deferred buffer_heads by calling generic_make_request.
+ */
+static void flush_deferred_io(struct deferred_io *c)
+{
+	struct deferred_io *n;
+
+	while (c) {
+		n = c->next;
+		generic_make_request(c->rw, c->bh);
+		free_deferred(c);
+		c = n;
+	}
+}
+
+/*
+ * Swap in a new table (destroying old one).  Write lock must be
+ * held.
+ */
+int dm_swap_table(struct mapped_device *md, struct dm_table *table)
+{
+	int r;
+
+	/* device must be suspended */
+	if (!md->suspended)
+		return -EPERM;
+
+	__unbind(md);
+
+	r = __bind(md, table);
+	if (r)
+		return r;
+
+	return 0;
+}
+
+/*
+ * We need to be able to change a mapping table under a mounted
+ * filesystem.  for example we might want to move some data in
+ * the background.  Before the table can be swapped with
+ * dm_bind_table, dm_suspend must be called to flush any in
+ * flight buffer_heads and ensure that any further io gets
+ * deferred.  Write lock must be held.
+ */
+int dm_suspend(struct mapped_device *md)
+{
+	int minor = MINOR(md->dev);
+	DECLARE_WAITQUEUE(wait, current);
+
+	if (md->suspended)
+		return -EINVAL;
+
+	md->suspended = 1;
+	dm_put_w(md);
+
+	/* wait for all the pending io to flush */
+	add_wait_queue(&md->wait, &wait);
+	current->state = TASK_UNINTERRUPTIBLE;
+	do {
+		md = dm_get_w(minor);
+		if (!md) {
+			/* Caller expects to free this lock. Yuck. */
+			down_write(_dev_locks + minor);
+			return -ENXIO;
+		}
+
+		if (!atomic_read(&md->pending))
+			break;
+
+		dm_put_w(md);
+		schedule();
+
+	} while (1);
+
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&md->wait, &wait);
+
+	return 0;
+}
+
+int dm_resume(struct mapped_device *md)
+{
+	int minor = MINOR(md->dev);
+	struct deferred_io *def;
+
+	if (!md->suspended || !md->map->num_targets)
+		return -EINVAL;
+
+	md->suspended = 0;
+	def = md->deferred;
+	md->deferred = NULL;
+
+	dm_put_w(md);
+	flush_deferred_io(def);
+	run_task_queue(&tq_disk);
+
+	if (!dm_get_w(minor)) {
+		/* FIXME: yuck */
+		down_write(_dev_locks + minor);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+struct block_device_operations dm_blk_dops = {
+	open:		dm_blk_open,
+	release:	dm_blk_close,
+	ioctl:		dm_blk_ioctl,
+	owner:		THIS_MODULE
+};
+
+/*
+ * module hooks
+ */
+module_init(dm_init);
+module_exit(dm_exit);
+
+MODULE_PARM(major, "i");
+MODULE_PARM_DESC(major, "The major number of the device mapper");
+MODULE_DESCRIPTION(DM_NAME " driver");
+MODULE_AUTHOR("Joe Thornber <thornber@sistina.com>");
+MODULE_LICENSE("GPL");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/md/dm-exception-store.c linux.20pre10-ac2/drivers/md/dm-exception-store.c
--- linux.20pre10/drivers/md/dm-exception-store.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/md/dm-exception-store.c	2002-08-12 22:44:36.000000000 +0100
@@ -0,0 +1,724 @@
+/*
+ * dm-snapshot.c
+ *
+ * Copyright (C) 2001-2002 Sistina Software (UK) Limited.
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm-snapshot.h"
+#include "kcopyd.h"
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+
+#define SECTOR_SIZE 512
+#define SECTOR_SHIFT 9
+
+/*-----------------------------------------------------------------
+ * Persistent snapshots, by persistent we mean that the snapshot
+ * will survive a reboot.
+ *---------------------------------------------------------------*/
+
+/*
+ * We need to store a record of which parts of the origin have
+ * been copied to the snapshot device.  The snapshot code
+ * requires that we copy exception chunks to chunk aligned areas
+ * of the COW store.  It makes sense therefore, to store the
+ * metadata in chunk size blocks.
+ *
+ * There is no backward or forward compatibility implemented,
+ * snapshots with different disk versions than the kernel will
+ * not be usable.  It is expected that "lvcreate" will blank out
+ * the start of a fresh COW device before calling the snapshot
+ * constructor.
+ *
+ * The first chunk of the COW device just contains the header.
+ * After this there is a chunk filled with exception metadata,
+ * followed by as many exception chunks as can fit in the
+ * metadata areas.
+ *
+ * All on disk structures are in little-endian format.  The end
+ * of the exceptions info is indicated by an exception with a
+ * new_chunk of 0, which is invalid since it would point to the
+ * header chunk.
+ */
+
+/*
+ * Magic for persistent snapshots: "SnAp" - Feeble isn't it.
+ */
+#define SNAP_MAGIC 0x70416e53
+
+/*
+ * The on-disk version of the metadata.
+ */
+#define SNAPSHOT_DISK_VERSION 1
+
+struct disk_header {
+	uint32_t magic;
+
+	/*
+	 * Is this snapshot valid.  There is no way of recovering
+	 * an invalid snapshot.
+	 */
+	int valid;
+
+	/*
+	 * Simple, incrementing version. no backward
+	 * compatibility.
+	 */
+	uint32_t version;
+
+	/* In sectors */
+	uint32_t chunk_size;
+};
+
+struct disk_exception {
+	uint64_t old_chunk;
+	uint64_t new_chunk;
+};
+
+struct commit_callback {
+	void (*callback)(void *, int success);
+	void *context;
+};
+
+/*
+ * The top level structure for a persistent exception store.
+ */
+struct pstore {
+	struct dm_snapshot *snap;	/* up pointer to my snapshot */
+	int version;
+	int valid;
+	uint32_t chunk_size;
+	uint32_t exceptions_per_area;
+
+	/*
+	 * Now that we have an asynchronous kcopyd there is no
+	 * need for large chunk sizes, so it wont hurt to have a
+	 * whole chunks worth of metadata in memory at once.
+	 */
+	void *area;
+	struct kiobuf *iobuf;
+
+	/*
+	 * Used to keep track of which metadata area the data in
+	 * 'chunk' refers to.
+	 */
+	uint32_t current_area;
+
+	/*
+	 * The next free chunk for an exception.
+	 */
+	uint32_t next_free;
+
+	/*
+	 * The index of next free exception in the current
+	 * metadata area.
+	 */
+	uint32_t current_committed;
+
+	atomic_t pending_count;
+	uint32_t callback_count;
+	struct commit_callback *callbacks;
+};
+
+/*
+ * For performance reasons we want to defer writing a committed
+ * exceptions metadata to disk so that we can amortise away this
+ * exensive operation.
+ *
+ * For the initial version of this code we will remain with
+ * synchronous io.  There are some deadlock issues with async
+ * that I haven't yet worked out.
+ */
+static int do_io(int rw, struct kcopyd_region *where, struct kiobuf *iobuf)
+{
+	int i, sectors_per_block, nr_blocks, start;
+	int blocksize = get_hardsect_size(where->dev);
+	int status;
+
+	sectors_per_block = blocksize / SECTOR_SIZE;
+
+	nr_blocks = where->count / sectors_per_block;
+	start = where->sector / sectors_per_block;
+
+	for (i = 0; i < nr_blocks; i++)
+		iobuf->blocks[i] = start++;
+
+	iobuf->length = where->count << 9;
+	iobuf->locked = 1;
+
+	status = brw_kiovec(rw, 1, &iobuf, where->dev, iobuf->blocks,
+			    blocksize);
+	if (status != (where->count << 9))
+		return -EIO;
+
+	return 0;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION ( 2, 4, 19)
+/*
+ * FIXME: Remove once 2.4.19 has been released.
+ */
+struct page *vmalloc_to_page(void *vmalloc_addr)
+{
+	unsigned long addr = (unsigned long) vmalloc_addr;
+	struct page *page = NULL;
+	pmd_t *pmd;
+	pte_t *pte;
+	pgd_t *pgd;
+
+	pgd = pgd_offset_k(addr);
+	if (!pgd_none(*pgd)) {
+		pmd = pmd_offset(pgd, addr);
+		if (!pmd_none(*pmd)) {
+			pte = pte_offset(pmd, addr);
+			if (pte_present(*pte)) {
+				page = pte_page(*pte);
+			}
+		}
+	}
+	return page;
+}
+#endif
+
+static int allocate_iobuf(struct pstore *ps)
+{
+	size_t i, r = -ENOMEM, len, nr_pages;
+	struct page *page;
+
+	len = ps->chunk_size << SECTOR_SHIFT;
+
+	/*
+	 * Allocate the chunk_size block of memory that will hold
+	 * a single metadata area.
+	 */
+	ps->area = vmalloc(len);
+	if (!ps->area)
+		return r;
+
+	if (alloc_kiovec(1, &ps->iobuf))
+		goto bad;
+
+	nr_pages = ps->chunk_size / (PAGE_SIZE / SECTOR_SIZE);
+	r = expand_kiobuf(ps->iobuf, nr_pages);
+	if (r)
+		goto bad;
+
+	/*
+	 * We lock the pages for ps->area into memory since they'll be
+	 * doing a lot of io.
+	 */
+	for (i = 0; i < nr_pages; i++) {
+		page = vmalloc_to_page(ps->area + (i * PAGE_SIZE));
+		LockPage(page);
+		ps->iobuf->maplist[i] = page;
+		ps->iobuf->nr_pages++;
+	}
+
+	ps->iobuf->nr_pages = nr_pages;
+	ps->iobuf->offset = 0;
+
+	return 0;
+
+      bad:
+	if (ps->iobuf)
+		free_kiovec(1, &ps->iobuf);
+
+	if (ps->area)
+		vfree(ps->area);
+	ps->iobuf = NULL;
+	return r;
+}
+
+static void free_iobuf(struct pstore *ps)
+{
+	int i;
+
+	for (i = 0; i < ps->iobuf->nr_pages; i++)
+		UnlockPage(ps->iobuf->maplist[i]);
+	ps->iobuf->locked = 0;
+
+	free_kiovec(1, &ps->iobuf);
+	vfree(ps->area);
+}
+
+/*
+ * Read or write a chunk aligned and sized block of data from a device.
+ */
+static int chunk_io(struct pstore *ps, uint32_t chunk, int rw)
+{
+	int r;
+	struct kcopyd_region where;
+
+	where.dev = ps->snap->cow->dev;
+	where.sector = ps->chunk_size * chunk;
+	where.count = ps->chunk_size;
+
+	r = do_io(rw, &where, ps->iobuf);
+	if (r)
+		return r;
+
+	return 0;
+}
+
+/*
+ * Read or write a metadata area.  Remembering to skip the first
+ * chunk which holds the header.
+ */
+static int area_io(struct pstore *ps, uint32_t area, int rw)
+{
+	int r;
+	uint32_t chunk;
+
+	/* convert a metadata area index to a chunk index */
+	chunk = 1 + ((ps->exceptions_per_area + 1) * area);
+
+	r = chunk_io(ps, chunk, rw);
+	if (r)
+		return r;
+
+	ps->current_area = area;
+	return 0;
+}
+
+static int zero_area(struct pstore *ps, uint32_t area)
+{
+	memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT);
+	return area_io(ps, area, WRITE);
+}
+
+static int read_header(struct pstore *ps, int *new_snapshot)
+{
+	int r;
+	struct disk_header *dh;
+
+	r = chunk_io(ps, 0, READ);
+	if (r)
+		return r;
+
+	dh = (struct disk_header *) ps->area;
+
+	if (dh->magic == 0) {
+		*new_snapshot = 1;
+
+	} else if (dh->magic == SNAP_MAGIC) {
+		*new_snapshot = 0;
+		ps->valid = dh->valid;
+		ps->version = dh->version;
+		ps->chunk_size = dh->chunk_size;
+
+	} else {
+		DMWARN("Invalid/corrupt snapshot");
+		r = -ENXIO;
+	}
+
+	return r;
+}
+
+static int write_header(struct pstore *ps)
+{
+	struct disk_header *dh;
+
+	memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT);
+
+	dh = (struct disk_header *) ps->area;
+	dh->magic = SNAP_MAGIC;
+	dh->valid = ps->valid;
+	dh->version = ps->version;
+	dh->chunk_size = ps->chunk_size;
+
+	return chunk_io(ps, 0, WRITE);
+}
+
+/*
+ * Access functions for the disk exceptions, these do the endian conversions.
+ */
+static struct disk_exception *get_exception(struct pstore *ps, uint32_t index)
+{
+	if (index >= ps->exceptions_per_area)
+		return NULL;
+
+	return ((struct disk_exception *) ps->area) + index;
+}
+
+static int read_exception(struct pstore *ps,
+			  uint32_t index, struct disk_exception *result)
+{
+	struct disk_exception *e;
+
+	e = get_exception(ps, index);
+	if (!e)
+		return -EINVAL;
+
+	/* copy it */
+	result->old_chunk = le64_to_cpu(e->old_chunk);
+	result->new_chunk = le64_to_cpu(e->new_chunk);
+
+	return 0;
+}
+
+static int write_exception(struct pstore *ps,
+			   uint32_t index, struct disk_exception *de)
+{
+	struct disk_exception *e;
+
+	e = get_exception(ps, index);
+	if (!e)
+		return -EINVAL;
+
+	/* copy it */
+	e->old_chunk = cpu_to_le64(de->old_chunk);
+	e->new_chunk = cpu_to_le64(de->new_chunk);
+
+	return 0;
+}
+
+/*
+ * Registers the exceptions that are present in the current area.
+ * 'full' is filled in to indicate if the area has been
+ * filled.
+ */
+static int insert_exceptions(struct pstore *ps, int *full)
+{
+	int i, r;
+	struct disk_exception de;
+
+	/* presume the area is full */
+	*full = 1;
+
+	for (i = 0; i < ps->exceptions_per_area; i++) {
+		r = read_exception(ps, i, &de);
+
+		if (r)
+			return r;
+
+		/*
+		 * If the new_chunk is pointing at the start of
+		 * the COW device, where the first metadata area
+		 * is we know that we've hit the end of the
+		 * exceptions.  Therefore the area is not full.
+		 */
+		if (de.new_chunk == 0LL) {
+			ps->current_committed = i;
+			*full = 0;
+			break;
+		}
+
+		/*
+		 * Keep track of the start of the free chunks.
+		 */
+		if (ps->next_free <= de.new_chunk)
+			ps->next_free = de.new_chunk + 1;
+
+		/*
+		 * Otherwise we add the exception to the snapshot.
+		 */
+		r = dm_add_exception(ps->snap, de.old_chunk, de.new_chunk);
+		if (r)
+			return r;
+	}
+
+	return 0;
+}
+
+static int read_exceptions(struct pstore *ps)
+{
+	uint32_t area;
+	int r, full = 1;
+
+	/*
+	 * Keeping reading chunks and inserting exceptions until
+	 * we find a partially full area.
+	 */
+	for (area = 0; full; area++) {
+		r = area_io(ps, area, READ);
+		if (r)
+			return r;
+
+		r = insert_exceptions(ps, &full);
+		if (r)
+			return r;
+
+		area++;
+	}
+
+	return 0;
+}
+
+static inline struct pstore *get_info(struct exception_store *store)
+{
+	return (struct pstore *) store->context;
+}
+
+static int persistent_percentfull(struct exception_store *store)
+{
+	struct pstore *ps = get_info(store);
+	return (ps->next_free * store->snap->chunk_size * 100) /
+	    get_dev_size(store->snap->cow->dev);
+}
+
+static void persistent_destroy(struct exception_store *store)
+{
+	struct pstore *ps = get_info(store);
+
+	vfree(ps->callbacks);
+	free_iobuf(ps);
+	kfree(ps);
+}
+
+static int persistent_prepare(struct exception_store *store,
+			      struct exception *e)
+{
+	struct pstore *ps = get_info(store);
+	uint32_t stride;
+	offset_t size = get_dev_size(store->snap->cow->dev);
+
+	/* Is there enough room ? */
+	if (size <= (ps->next_free * store->snap->chunk_size))
+		return -ENOSPC;
+
+	e->new_chunk = ps->next_free;
+
+	/*
+	 * Move onto the next free pending, making sure to take
+	 * into account the location of the metadata chunks.
+	 */
+	stride = (ps->exceptions_per_area + 1);
+	if (!(++ps->next_free % stride))
+		ps->next_free++;
+
+	atomic_inc(&ps->pending_count);
+	return 0;
+}
+
+static void persistent_commit(struct exception_store *store,
+			      struct exception *e,
+			      void (*callback) (void *, int success),
+			      void *callback_context)
+{
+	int r, i;
+	struct pstore *ps = get_info(store);
+	struct disk_exception de;
+	struct commit_callback *cb;
+
+	de.old_chunk = e->old_chunk;
+	de.new_chunk = e->new_chunk;
+	write_exception(ps, ps->current_committed++, &de);
+
+	/*
+	 * Add the callback to the back of the array.  This code
+	 * is the only place where the callback array is
+	 * manipulated, and we know that it will never be called
+	 * multiple times concurrently.
+	 */
+	cb = ps->callbacks + ps->callback_count++;
+	cb->callback = callback;
+	cb->context = callback_context;
+
+	/*
+	 * If there are no more exceptions in flight, or we have
+	 * filled this metadata area we commit the exceptions to
+	 * disk.
+	 */
+	if (atomic_dec_and_test(&ps->pending_count) ||
+	    (ps->current_committed == ps->exceptions_per_area)) {
+		r = area_io(ps, ps->current_area, WRITE);
+		if (r)
+			ps->valid = 0;
+
+		for (i = 0; i < ps->callback_count; i++) {
+			cb = ps->callbacks + i;
+			cb->callback(cb->context, r == 0 ? 1 : 0);
+		}
+
+		ps->callback_count = 0;
+	}
+
+	/*
+	 * Have we completely filled the current area ?
+	 */
+	if (ps->current_committed == ps->exceptions_per_area) {
+		ps->current_committed = 0;
+		r = zero_area(ps, ps->current_area + 1);
+		if (r)
+			ps->valid = 0;
+	}
+}
+
+static void persistent_drop(struct exception_store *store)
+{
+	struct pstore *ps = get_info(store);
+
+	ps->valid = 0;
+	if (write_header(ps))
+		DMWARN("write header failed");
+}
+
+int dm_create_persistent(struct exception_store *store, uint32_t chunk_size)
+{
+	int r, new_snapshot;
+	struct pstore *ps;
+
+	/* allocate the pstore */
+	ps = kmalloc(sizeof(*ps), GFP_KERNEL);
+	if (!ps)
+		return -ENOMEM;
+
+	ps->snap = store->snap;
+	ps->valid = 1;
+	ps->version = SNAPSHOT_DISK_VERSION;
+	ps->chunk_size = chunk_size;
+	ps->exceptions_per_area = (chunk_size << SECTOR_SHIFT) /
+	    sizeof(struct disk_exception);
+	ps->next_free = 2;	/* skipping the header and first area */
+	ps->current_committed = 0;
+
+	r = allocate_iobuf(ps);
+	if (r)
+		goto bad;
+
+	/*
+	 * Allocate space for all the callbacks.
+	 */
+	ps->callback_count = 0;
+	atomic_set(&ps->pending_count, 0);
+	ps->callbacks = vcalloc(ps->exceptions_per_area,
+				sizeof(*ps->callbacks));
+
+	if (!ps->callbacks)
+		goto bad;
+
+	/*
+	 * Read the snapshot header.
+	 */
+	r = read_header(ps, &new_snapshot);
+	if (r)
+		goto bad;
+
+	/*
+	 * Do we need to setup a new snapshot ?
+	 */
+	if (new_snapshot) {
+		r = write_header(ps);
+		if (r) {
+			DMWARN("write_header failed");
+			goto bad;
+		}
+
+		r = zero_area(ps, 0);
+		if (r) {
+			DMWARN("zero_area(0) failed");
+			goto bad;
+		}
+
+	} else {
+		/*
+		 * Sanity checks.
+		 */
+		if (ps->chunk_size != chunk_size) {
+			DMWARN("chunk size for existing snapshot different "
+			       "from that requested");
+			r = -EINVAL;
+			goto bad;
+		}
+
+		if (ps->version != SNAPSHOT_DISK_VERSION) {
+			DMWARN("unable to handle snapshot disk version %d",
+			       ps->version);
+			r = -EINVAL;
+			goto bad;
+		}
+
+		/*
+		 * Read the metadata.
+		 */
+		r = read_exceptions(ps);
+		if (r)
+			goto bad;
+	}
+
+	store->destroy = persistent_destroy;
+	store->prepare_exception = persistent_prepare;
+	store->commit_exception = persistent_commit;
+	store->drop_snapshot = persistent_drop;
+	store->percent_full = persistent_percentfull;
+	store->context = ps;
+
+	return r;
+
+      bad:
+	if (ps) {
+		if (ps->callbacks)
+			vfree(ps->callbacks);
+
+		if (ps->iobuf)
+			free_iobuf(ps);
+
+		kfree(ps);
+	}
+	return r;
+}
+
+/*-----------------------------------------------------------------
+ * Implementation of the store for non-persistent snapshots.
+ *---------------------------------------------------------------*/
+struct transient_c {
+	offset_t next_free;
+};
+
+void transient_destroy(struct exception_store *store)
+{
+	kfree(store->context);
+}
+
+int transient_prepare(struct exception_store *store, struct exception *e)
+{
+	struct transient_c *tc = (struct transient_c *) store->context;
+	offset_t size = get_dev_size(store->snap->cow->dev);
+
+	if (size < (tc->next_free + store->snap->chunk_size))
+		return -1;
+
+	e->new_chunk = sector_to_chunk(store->snap, tc->next_free);
+	tc->next_free += store->snap->chunk_size;
+
+	return 0;
+}
+
+void transient_commit(struct exception_store *store,
+		      struct exception *e,
+		      void (*callback) (void *, int success),
+		      void *callback_context)
+{
+	/* Just succeed */
+	callback(callback_context, 1);
+}
+
+static int transient_percentfull(struct exception_store *store)
+{
+	struct transient_c *tc = (struct transient_c *) store->context;
+	return (tc->next_free * 100) / get_dev_size(store->snap->cow->dev);
+}
+
+int dm_create_transient(struct exception_store *store,
+			struct dm_snapshot *s, int blocksize, void **error)
+{
+	struct transient_c *tc;
+
+	memset(store, 0, sizeof(*store));
+	store->destroy = transient_destroy;
+	store->prepare_exception = transient_prepare;
+	store->commit_exception = transient_commit;
+	store->percent_full = transient_percentfull;
+	store->snap = s;
+
+	tc = kmalloc(sizeof(struct transient_c), GFP_KERNEL);
+	if (!tc)
+		return -ENOMEM;
+
+	tc->next_free = 0;
+	store->context = tc;
+
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/md/dm.h linux.20pre10-ac2/drivers/md/dm.h
--- linux.20pre10/drivers/md/dm.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/md/dm.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,241 @@
+/*
+ * Internal header file for device mapper
+ *
+ * Copyright (C) 2001 Sistina Software
+ *
+ * This file is released under the LGPL.
+ */
+
+#ifndef DM_INTERNAL_H
+#define DM_INTERNAL_H
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/major.h>
+#include <linux/iobuf.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/compatmac.h>
+#include <linux/cache.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/ctype.h>
+#include <linux/device-mapper.h>
+#include <linux/list.h>
+#include <linux/init.h>
+
+#define DM_NAME "device-mapper"	/* Name for messaging */
+#define DM_DRIVER_EMAIL "lvm-devel@lists.sistina.com"
+#define MAX_DEPTH 16
+#define NODE_SIZE L1_CACHE_BYTES
+#define KEYS_PER_NODE (NODE_SIZE / sizeof(offset_t))
+#define CHILDREN_PER_NODE (KEYS_PER_NODE + 1)
+#define MAX_ARGS 32
+#define MAX_DEVICES 256
+
+/*
+ * List of devices that a metadevice uses and should open/close.
+ */
+struct dm_dev {
+	atomic_t count;
+	struct list_head list;
+
+	int mode;
+
+	kdev_t dev;
+	struct block_device *bd;
+};
+
+/*
+ * I/O that had to be deferred while we were suspended
+ */
+struct deferred_io {
+	int rw;
+	struct buffer_head *bh;
+	struct deferred_io *next;
+};
+
+/*
+ * Btree leaf - this does the actual mapping
+ */
+struct target {
+	struct target_type *type;
+	void *private;
+};
+
+/*
+ * The btree
+ */
+struct dm_table {
+	/* btree table */
+	int depth;
+	int counts[MAX_DEPTH];	/* in nodes */
+	offset_t *index[MAX_DEPTH];
+
+	int num_targets;
+	int num_allocated;
+	offset_t *highs;
+	struct target *targets;
+
+	/*
+	 * Indicates the rw permissions for the new logical
+	 * device.  This should be a combination of FMODE_READ
+	 * and FMODE_WRITE.
+	 */
+	int mode;
+
+	/* a list of devices used by this table */
+	struct list_head devices;
+
+	/*
+	 * A waitqueue for processes waiting for something
+	 * interesting to happen to this table.
+	 */
+	wait_queue_head_t eventq;
+};
+
+/*
+ * The actual device struct
+ */
+struct mapped_device {
+	kdev_t dev;
+	char name[DM_NAME_LEN];
+	char *uuid;
+
+	int use_count;
+	int suspended;
+	int read_only;
+
+	/* a list of io's that arrived while we were suspended */
+	atomic_t pending;
+	wait_queue_head_t wait;
+	struct deferred_io *deferred;
+
+	struct dm_table *map;
+
+	/* used by dm-fs.c */
+	devfs_handle_t devfs_entry;
+};
+
+extern struct block_device_operations dm_blk_dops;
+
+/* dm-target.c */
+int dm_target_init(void);
+struct target_type *dm_get_target_type(const char *name);
+void dm_put_target_type(struct target_type *t);
+void dm_target_exit(void);
+
+/*
+ * Destructively splits argument list to pass to ctr.
+ */
+int split_args(int max, int *argc, char **argv, char *input);
+
+/* dm.c */
+struct mapped_device *dm_get_r(int minor);
+struct mapped_device *dm_get_w(int minor);
+
+/*
+ * There are two ways to lookup a device.
+ */
+enum {
+	DM_LOOKUP_BY_NAME,
+	DM_LOOKUP_BY_UUID
+};
+
+struct mapped_device *dm_get_name_r(const char *name, int nametype);
+struct mapped_device *dm_get_name_w(const char *name, int nametype);
+
+void dm_put_r(struct mapped_device *md);
+void dm_put_w(struct mapped_device *md);
+
+/*
+ * Call with no lock.
+ */
+int dm_create(const char *name, const char *uuid, int minor, int ro,
+	      struct dm_table *table);
+int dm_set_name(const char *name, int nametype, const char *newname);
+void dm_destroy_all(void);
+
+/*
+ * You must have the write lock before calling the remaining md
+ * methods.
+ */
+int dm_destroy(struct mapped_device *md);
+void dm_set_ro(struct mapped_device *md, int ro);
+
+/*
+ * The device must be suspended before calling this method.
+ */
+int dm_swap_table(struct mapped_device *md, struct dm_table *t);
+
+/*
+ * A device can still be used while suspended, but I/O is deferred.
+ */
+int dm_suspend(struct mapped_device *md);
+int dm_resume(struct mapped_device *md);
+
+/* dm-table.c */
+int dm_table_create(struct dm_table **result, int mode);
+void dm_table_destroy(struct dm_table *t);
+
+int dm_table_add_target(struct dm_table *t, offset_t highs,
+			struct target_type *type, void *private);
+int dm_table_complete(struct dm_table *t);
+
+/*
+ * Event handling
+ */
+void dm_table_event(struct dm_table *t);
+
+#define DMWARN(f, x...) printk(KERN_WARNING DM_NAME ": " f "\n" , ## x)
+#define DMERR(f, x...) printk(KERN_ERR DM_NAME ": " f "\n" , ## x)
+#define DMINFO(f, x...) printk(KERN_INFO DM_NAME ": " f "\n" , ## x)
+
+/*
+ * Calculate the index of the child node of the n'th node k'th key.
+ */
+static inline int get_child(int n, int k)
+{
+	return (n * CHILDREN_PER_NODE) + k;
+}
+
+/*
+ * Return the n'th node of level l from table t.
+ */
+static inline offset_t *get_node(struct dm_table *t, int l, int n)
+{
+	return t->index[l] + (n * KEYS_PER_NODE);
+}
+
+static inline int array_too_big(unsigned long fixed, unsigned long obj,
+				unsigned long num)
+{
+	return (num > (ULONG_MAX - fixed) / obj);
+}
+
+
+/*
+ * Targets
+ */
+int dm_linear_init(void);
+void dm_linear_exit(void);
+
+int dm_stripe_init(void);
+void dm_stripe_exit(void);
+
+int dm_snapshot_init(void);
+void dm_snapshot_exit(void);
+
+
+/*
+ * Init functions for the user interface to device-mapper.  At
+ * the moment an ioctl interface on a special char device is
+ * used.  A filesystem based interface would be a nicer way to
+ * go.
+ */
+int __init dm_interface_init(void);
+void dm_interface_exit(void);
+
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/md/dm-ioctl.c linux.20pre10-ac2/drivers/md/dm-ioctl.c
--- linux.20pre10/drivers/md/dm-ioctl.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/md/dm-ioctl.c	2002-08-12 22:45:52.000000000 +0100
@@ -0,0 +1,830 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm.h"
+
+#include <linux/miscdevice.h>
+#include <linux/dm-ioctl.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+
+/*-----------------------------------------------------------------
+ * Implementation of the ioctl commands
+ *---------------------------------------------------------------*/
+
+/*
+ * All the ioctl commands get dispatched to functions with this
+ * prototype.
+ */
+typedef int (*ioctl_fn)(struct dm_ioctl *param, struct dm_ioctl *user);
+
+/*
+ * This is really a debug only call.
+ */
+static int remove_all(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+	dm_destroy_all();
+	return 0;
+}
+
+/*
+ * Check a string doesn't overrun the chunk of
+ * memory we copied from userland.
+ */
+static int valid_str(char *str, void *begin, void *end)
+{
+	while (((void *) str >= begin) && ((void *) str < end))
+		if (!*str++)
+			return 0;
+
+	return -EINVAL;
+}
+
+static int next_target(struct dm_target_spec *last, uint32_t next,
+		       void *begin, void *end,
+		       struct dm_target_spec **spec, char **params)
+{
+	*spec = (struct dm_target_spec *)
+	    ((unsigned char *) last + next);
+	*params = (char *) (*spec + 1);
+
+	if (*spec < (last + 1) || ((void *) *spec > end))
+		return -EINVAL;
+
+	return valid_str(*params, begin, end);
+}
+
+/*
+ * Checks to see if there's a gap in the table.
+ * Returns true iff there is a gap.
+ */
+static int gap(struct dm_table *table, struct dm_target_spec *spec)
+{
+	if (!table->num_targets)
+		return (spec->sector_start > 0) ? 1 : 0;
+
+	if (spec->sector_start != table->highs[table->num_targets - 1] + 1)
+		return 1;
+
+	return 0;
+}
+
+static int populate_table(struct dm_table *table, struct dm_ioctl *args)
+{
+	int i = 0, r, first = 1, argc;
+	struct dm_target_spec *spec;
+	char *params, *argv[MAX_ARGS];
+	struct target_type *ttype;
+	void *context, *begin, *end;
+	offset_t highs = 0;
+
+	if (!args->target_count) {
+		DMWARN("populate_table: no targets specified");
+		return -EINVAL;
+	}
+
+	begin = (void *) args;
+	end = begin + args->data_size;
+
+#define PARSE_ERROR(msg) {DMWARN(msg); return -EINVAL;}
+
+	for (i = 0; i < args->target_count; i++) {
+
+		if (first)
+			r = next_target((struct dm_target_spec *) args,
+					args->data_start,
+					begin, end, &spec, &params);
+		else
+			r = next_target(spec, spec->next, begin, end,
+					&spec, &params);
+
+		if (r)
+			PARSE_ERROR("unable to find target");
+
+		/* Look up the target type */
+		ttype = dm_get_target_type(spec->target_type);
+		if (!ttype)
+			PARSE_ERROR("unable to find target type");
+
+		if (gap(table, spec))
+			PARSE_ERROR("gap in target ranges");
+
+		/* Split up the parameter list */
+		if (split_args(MAX_ARGS, &argc, argv, params) < 0)
+			PARSE_ERROR("Too many arguments");
+
+		/* Build the target */
+		if (ttype->ctr(table, spec->sector_start, spec->length,
+			       argc, argv, &context)) {
+			DMWARN("%s: target constructor failed",
+			       (char *) context);
+			return -EINVAL;
+		}
+
+		/* Add the target to the table */
+		highs = spec->sector_start + (spec->length - 1);
+		if (dm_table_add_target(table, highs, ttype, context))
+			PARSE_ERROR("internal error adding target to table");
+
+		first = 0;
+	}
+
+#undef PARSE_ERROR
+
+	r = dm_table_complete(table);
+	return r;
+}
+
+/*
+ * Round up the ptr to the next 'align' boundary.  Obviously
+ * 'align' must be a power of 2.
+ */
+static inline void *align_ptr(void *ptr, unsigned int align)
+{
+	align--;
+	return (void *) (((unsigned long) (ptr + align)) & ~align);
+}
+
+/*
+ * Copies a dm_ioctl and an optional additional payload to
+ * userland.
+ */
+static int results_to_user(struct dm_ioctl *user, struct dm_ioctl *param,
+			   void *data, uint32_t len)
+{
+	int r;
+	void *ptr = NULL;
+
+	if (data) {
+		ptr = align_ptr(user + 1, sizeof(unsigned long));
+		param->data_start = ptr - (void *) user;
+	}
+
+	/*
+	 * The version number has already been filled in, so we
+	 * just copy later fields.
+	 */
+	r = copy_to_user(&user->data_size, &param->data_size,
+			 sizeof(*param) - sizeof(param->version));
+	if (r)
+		return -EFAULT;
+
+	if (data) {
+		if (param->data_start + len > param->data_size)
+			return -ENOSPC;
+
+		if (copy_to_user(ptr, data, len))
+			r = -EFAULT;
+	}
+
+	return r;
+}
+
+/*
+ * Fills in a dm_ioctl structure, ready for sending back to
+ * userland.
+ */
+static void __info(struct mapped_device *md, struct dm_ioctl *param)
+{
+	param->flags = DM_EXISTS_FLAG;
+	if (md->suspended)
+		param->flags |= DM_SUSPEND_FLAG;
+	if (md->read_only)
+		param->flags |= DM_READONLY_FLAG;
+
+	strncpy(param->name, md->name, sizeof(param->name));
+
+	if (md->uuid)
+		strncpy(param->uuid, md->uuid, sizeof(param->uuid) - 1);
+	else
+		param->uuid[0] = '\0';
+
+	param->open_count = md->use_count;
+	param->dev = kdev_t_to_nr(md->dev);
+	param->target_count = md->map->num_targets;
+}
+
+/*
+ * Always use UUID for lookups if it's present, otherwise use name.
+ */
+static inline char *lookup_name(struct dm_ioctl *param)
+{
+	return (*param->uuid) ? param->uuid : param->name;
+}
+
+static inline int lookup_type(struct dm_ioctl *param)
+{
+	return (*param->uuid) ? DM_LOOKUP_BY_UUID : DM_LOOKUP_BY_NAME;
+}
+
+#define ALIGNMENT sizeof(int)
+static void *_align(void *ptr, unsigned int a)
+{
+	register unsigned long align = --a;
+
+	return (void *) (((unsigned long) ptr + align) & ~align);
+}
+
+/*
+ * Copies device info back to user space, used by
+ * the create and info ioctls.
+ */
+static int info(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+	struct mapped_device *md;
+
+	param->flags = 0;
+
+	md = dm_get_name_r(lookup_name(param), lookup_type(param));
+	if (!md)
+		/*
+		 * Device not found - returns cleared exists flag.
+		 */
+		goto out;
+
+	__info(md, param);
+	dm_put_r(md);
+
+      out:
+	return results_to_user(user, param, NULL, 0);
+}
+
+static inline int get_mode(struct dm_ioctl *param)
+{
+	int mode = FMODE_READ | FMODE_WRITE;
+
+	if (param->flags & DM_READONLY_FLAG)
+		mode = FMODE_READ;
+
+	return mode;
+}
+
+static int create(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+	int r, ro;
+	struct dm_table *t;
+	int minor;
+
+	r = dm_table_create(&t, get_mode(param));
+	if (r)
+		return r;
+
+	r = populate_table(t, param);
+	if (r) {
+		dm_table_destroy(t);
+		return r;
+	}
+
+	minor = (param->flags & DM_PERSISTENT_DEV_FLAG) ?
+	    MINOR(to_kdev_t(param->dev)) : -1;
+
+	ro = (param->flags & DM_READONLY_FLAG) ? 1 : 0;
+
+	r = dm_create(param->name, param->uuid, minor, ro, t);
+	if (r) {
+		dm_table_destroy(t);
+		return r;
+	}
+
+	r = info(param, user);
+	return r;
+}
+
+
+
+/*
+ * Build up the status struct for each target
+ */
+static int __status(struct mapped_device *md, struct dm_ioctl *param,
+		    char *outbuf, int *len)
+{
+	int i;
+	struct dm_target_spec *spec;
+	uint64_t sector = 0LL;
+	char *outptr;
+	status_type_t type;
+
+	if (param->flags & DM_STATUS_TABLE_FLAG)
+		type = STATUSTYPE_TABLE;
+	else
+		type = STATUSTYPE_INFO;
+
+	outptr = outbuf;
+
+	/* Get all the target info */
+	for (i = 0; i < md->map->num_targets; i++) {
+		struct target_type *tt = md->map->targets[i].type;
+		offset_t high = md->map->highs[i];
+
+		if (outptr - outbuf +
+		    sizeof(struct dm_target_spec) > param->data_size)
+			    return -ENOMEM;
+
+		spec = (struct dm_target_spec *) outptr;
+
+		spec->status = 0;
+		spec->sector_start = sector;
+		spec->length = high - sector + 1;
+		strncpy(spec->target_type, tt->name, sizeof(spec->target_type));
+
+		outptr += sizeof(struct dm_target_spec);
+
+		/* Get the status/table string from the target driver */
+		if (tt->status)
+			tt->status(type, outptr,
+				   outbuf + param->data_size - outptr,
+				   md->map->targets[i].private);
+		else
+			outptr[0] = '\0';
+
+		outptr += strlen(outptr) + 1;
+		_align(outptr, ALIGNMENT);
+
+		sector = high + 1;
+
+		spec->next = outptr - outbuf;
+	}
+
+	param->target_count = md->map->num_targets;
+	*len = outptr - outbuf;
+
+	return 0;
+}
+
+/*
+ * Return the status of a device as a text string for each
+ * target.
+ */
+static int get_status(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+	struct mapped_device *md;
+	int len = 0;
+	int ret;
+	char *outbuf = NULL;
+
+	md = dm_get_name_r(lookup_name(param), lookup_type(param));
+	if (!md)
+		/*
+		 * Device not found - returns cleared exists flag.
+		 */
+		goto out;
+
+	/* We haven't a clue how long the resultant data will be so
+	   just allocate as much as userland has allowed us and make sure
+	   we don't overun it */
+	outbuf = kmalloc(param->data_size, GFP_KERNEL);
+	if (!outbuf)
+		goto out;
+	/*
+	 * Get the status of all targets
+	 */
+	__status(md, param, outbuf, &len);
+
+	/*
+	 * Setup the basic dm_ioctl structure.
+	 */
+	__info(md, param);
+
+      out:
+	if (md)
+		dm_put_r(md);
+
+	ret = results_to_user(user, param, outbuf, len);
+
+	if (outbuf)
+		kfree(outbuf);
+
+	return ret;
+}
+
+/*
+ * Wait for a device to report an event
+ */
+static int wait_device_event(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+	struct mapped_device *md;
+	DECLARE_WAITQUEUE(wq, current);
+
+	md = dm_get_name_r(lookup_name(param), lookup_type(param));
+	if (!md)
+		/*
+		 * Device not found - returns cleared exists flag.
+		 */
+		goto out;
+	/*
+	 * Setup the basic dm_ioctl structure.
+	 */
+	__info(md, param);
+
+	/*
+	 * Wait for a notification event
+	 */
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&md->map->eventq, &wq);
+
+	dm_put_r(md);
+
+	schedule();
+	set_current_state(TASK_RUNNING);
+
+      out:
+	return results_to_user(user, param, NULL, 0);
+}
+
+/*
+ * Retrieves a list of devices used by a particular dm device.
+ */
+static int dep(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+	int count, r;
+	struct mapped_device *md;
+	struct list_head *tmp;
+	size_t len = 0;
+	struct dm_target_deps *deps = NULL;
+
+	md = dm_get_name_r(lookup_name(param), lookup_type(param));
+	if (!md)
+		goto out;
+
+	/*
+	 * Setup the basic dm_ioctl structure.
+	 */
+	__info(md, param);
+
+	/*
+	 * Count the devices.
+	 */
+	count = 0;
+	list_for_each(tmp, &md->map->devices)
+	    count++;
+
+	/*
+	 * Allocate a kernel space version of the dm_target_status
+	 * struct.
+	 */
+	if (array_too_big(sizeof(*deps), sizeof(*deps->dev), count)) {
+		dm_put_r(md);
+		return -ENOMEM;
+	}
+
+	len = sizeof(*deps) + (sizeof(*deps->dev) * count);
+	deps = kmalloc(len, GFP_KERNEL);
+	if (!deps) {
+		dm_put_r(md);
+		return -ENOMEM;
+	}
+
+	/*
+	 * Fill in the devices.
+	 */
+	deps->count = count;
+	count = 0;
+	list_for_each(tmp, &md->map->devices) {
+		struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
+		deps->dev[count++] = kdev_t_to_nr(dd->dev);
+	}
+	dm_put_r(md);
+
+      out:
+	r = results_to_user(user, param, deps, len);
+
+	kfree(deps);
+	return r;
+}
+
+static int remove(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+	int r;
+	struct mapped_device *md;
+
+	md = dm_get_name_w(lookup_name(param), lookup_type(param));
+	if (!md)
+		return -ENXIO;
+
+	r = dm_destroy(md);
+	dm_put_w(md);
+	if (!r)
+		kfree(md);
+
+	return r;
+}
+
+static int suspend(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+	int r;
+	struct mapped_device *md;
+
+	md = dm_get_name_w(lookup_name(param), lookup_type(param));
+	if (!md)
+		return -ENXIO;
+
+	r = (param->flags & DM_SUSPEND_FLAG) ? dm_suspend(md) : dm_resume(md);
+	dm_put_w(md);
+
+	return r;
+}
+
+static int reload(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+	int r;
+	struct mapped_device *md;
+	struct dm_table *t;
+
+	r = dm_table_create(&t, get_mode(param));
+	if (r)
+		return r;
+
+	r = populate_table(t, param);
+	if (r) {
+		dm_table_destroy(t);
+		return r;
+	}
+
+	md = dm_get_name_w(lookup_name(param), lookup_type(param));
+	if (!md) {
+		dm_table_destroy(t);
+		return -ENXIO;
+	}
+
+	r = dm_swap_table(md, t);
+	if (r) {
+		dm_put_w(md);
+		dm_table_destroy(t);
+		return r;
+	}
+
+	dm_set_ro(md, (param->flags & DM_READONLY_FLAG) ? 1 : 0);
+	dm_put_w(md);
+
+	r = info(param, user);
+	return r;
+}
+
+static int rename(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+	char *newname = (char *) param + param->data_start;
+
+	if (valid_str(newname, (void *) param,
+		      (void *) param + param->data_size) ||
+	    dm_set_name(lookup_name(param), lookup_type(param), newname)) {
+		DMWARN("Invalid new logical volume name supplied.");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+/*-----------------------------------------------------------------
+ * Implementation of open/close/ioctl on the special char
+ * device.
+ *---------------------------------------------------------------*/
+static int ctl_open(struct inode *inode, struct file *file)
+{
+	/* only root can open this */
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+static int ctl_close(struct inode *inode, struct file *file)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static ioctl_fn lookup_ioctl(unsigned int cmd)
+{
+	static struct {
+		int cmd;
+		ioctl_fn fn;
+	} _ioctls[] = {
+		{DM_VERSION_CMD, NULL},	/* version is dealt with elsewhere */
+		{DM_REMOVE_ALL_CMD, remove_all},
+		{DM_DEV_CREATE_CMD, create},
+		{DM_DEV_REMOVE_CMD, remove},
+		{DM_DEV_RELOAD_CMD, reload},
+		{DM_DEV_RENAME_CMD, rename},
+		{DM_DEV_SUSPEND_CMD, suspend},
+		{DM_DEV_DEPS_CMD, dep},
+		{DM_DEV_STATUS_CMD, info},
+		{DM_TARGET_STATUS_CMD, get_status},
+		{DM_TARGET_WAIT_CMD, wait_device_event},
+	};
+	static int nelts = sizeof(_ioctls) / sizeof(*_ioctls);
+
+	return (cmd >= nelts) ? NULL : _ioctls[cmd].fn;
+}
+
+/*
+ * As well as checking the version compatibility this always
+ * copies the kernel interface version out.
+ */
+static int check_version(int cmd, struct dm_ioctl *user)
+{
+	uint32_t version[3];
+	int r = 0;
+
+	if (copy_from_user(version, user->version, sizeof(version)))
+		return -EFAULT;
+
+	if ((DM_VERSION_MAJOR != version[0]) ||
+	    (DM_VERSION_MINOR < version[1])) {
+		DMWARN("ioctl interface mismatch: "
+		       "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)",
+		       DM_VERSION_MAJOR, DM_VERSION_MINOR,
+		       DM_VERSION_PATCHLEVEL,
+		       version[0], version[1], version[2], cmd);
+		r = -EINVAL;
+	}
+
+	/*
+	 * Fill in the kernel version.
+	 */
+	version[0] = DM_VERSION_MAJOR;
+	version[1] = DM_VERSION_MINOR;
+	version[2] = DM_VERSION_PATCHLEVEL;
+	if (copy_to_user(user->version, version, sizeof(version)))
+		return -EFAULT;
+
+	return r;
+}
+
+static void free_params(struct dm_ioctl *param)
+{
+	vfree(param);
+}
+
+static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param)
+{
+	struct dm_ioctl tmp, *dmi;
+
+	if (copy_from_user(&tmp, user, sizeof(tmp)))
+		return -EFAULT;
+
+	if (tmp.data_size < sizeof(tmp))
+		return -EINVAL;
+
+	dmi = (struct dm_ioctl *) vmalloc(tmp.data_size);
+	if (!dmi)
+		return -ENOMEM;
+
+	if (copy_from_user(dmi, user, tmp.data_size)) {
+		vfree(dmi);
+		return -EFAULT;
+	}
+
+	*param = dmi;
+	return 0;
+}
+
+static int validate_params(uint cmd, struct dm_ioctl *param)
+{
+	/* Ignores parameters */
+	if (cmd == DM_REMOVE_ALL_CMD)
+		return 0;
+
+	/* Unless creating, either name of uuid but not both */
+	if (cmd != DM_DEV_CREATE_CMD) {
+		if ((!*param->uuid && !*param->name) ||
+		    (*param->uuid && *param->name)) {
+			DMWARN("one of name or uuid must be supplied");
+			return -EINVAL;
+		}
+	}
+
+	/* Ensure strings are terminated */
+	param->name[DM_NAME_LEN - 1] = '\0';
+	param->uuid[DM_UUID_LEN - 1] = '\0';
+
+	return 0;
+}
+
+static int ctl_ioctl(struct inode *inode, struct file *file,
+		     uint command, ulong u)
+{
+
+	int r = 0, cmd;
+	struct dm_ioctl *param;
+	struct dm_ioctl *user = (struct dm_ioctl *) u;
+	ioctl_fn fn = NULL;
+
+	if (_IOC_TYPE(command) != DM_IOCTL)
+		return -ENOTTY;
+
+	cmd = _IOC_NR(command);
+
+	/*
+	 * Check the interface version passed in.  This also
+	 * writes out the kernel's interface version.
+	 */
+	r = check_version(cmd, user);
+	if (r)
+		return r;
+
+	/*
+	 * Nothing more to do for the version command.
+	 */
+	if (cmd == DM_VERSION_CMD)
+		return 0;
+
+	fn = lookup_ioctl(cmd);
+	if (!fn) {
+		DMWARN("dm_ctl_ioctl: unknown command 0x%x", command);
+		return -ENOTTY;
+	}
+
+	/*
+	 * Copy the parameters into kernel space.
+	 */
+	r = copy_params(user, &param);
+	if (r)
+		return r;
+
+	r = validate_params(cmd, param);
+	if (r) {
+		free_params(param);
+		return r;
+	}
+
+	r = fn(param, user);
+	free_params(param);
+	return r;
+}
+
+static struct file_operations _ctl_fops = {
+	open:	 ctl_open,
+	release: ctl_close,
+	ioctl:	 ctl_ioctl,
+	owner:	 THIS_MODULE,
+};
+
+static devfs_handle_t _ctl_handle;
+
+static struct miscdevice _dm_misc = {
+	minor: MISC_DYNAMIC_MINOR,
+	name:  DM_NAME,
+	fops:  &_ctl_fops
+};
+
+static int __init dm_devfs_init(void) {
+	int r;
+	char rname[64];
+
+	r = devfs_generate_path(_dm_misc.devfs_handle, rname + 3,
+				sizeof rname - 3);
+	if (r == -ENOSYS)
+		return 0;	/* devfs not present */
+
+	if (r < 0) {
+		DMERR("devfs_generate_path failed for control device");
+		return r;
+	}
+
+	strncpy(rname + r, "../", 3);
+	r = devfs_mk_symlink(NULL, DM_DIR "/control",
+			     DEVFS_FL_DEFAULT, rname + r, &_ctl_handle, NULL);
+	if (r) {
+		DMERR("devfs_mk_symlink failed for control device");
+		return r;
+	}
+	devfs_auto_unregister(_dm_misc.devfs_handle, _ctl_handle);
+
+	return 0;
+}
+
+/* Create misc character device and link to DM_DIR/control */
+int __init dm_interface_init(void)
+{
+	int r;
+
+	r = misc_register(&_dm_misc);
+	if (r) {
+		DMERR("misc_register failed for control device");
+		return r;
+	}
+
+	r = dm_devfs_init();
+	if (r) {
+		misc_deregister(&_dm_misc);
+		return r;
+	}
+
+	DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR,
+	       DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA,
+	       DM_DRIVER_EMAIL);
+
+	return 0;
+}
+
+void dm_interface_exit(void)
+{
+	if (misc_deregister(&_dm_misc) < 0)
+		DMERR("misc_deregister failed for control device");
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/md/dm-linear.c linux.20pre10-ac2/drivers/md/dm-linear.c
--- linux.20pre10/drivers/md/dm-linear.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/md/dm-linear.c	2002-08-12 22:45:52.000000000 +0100
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm.h"
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+
+/*
+ * Linear: maps a linear range of a device.
+ */
+struct linear_c {
+	long delta;		/* FIXME: we need a signed offset type */
+	long start;		/* For display only */
+	struct dm_dev *dev;
+};
+
+/*
+ * Construct a linear mapping: <dev_path> <offset>
+ */
+static int linear_ctr(struct dm_table *t, offset_t b, offset_t l,
+		      int argc, char **argv, void **context)
+{
+	struct linear_c *lc;
+	unsigned long start;	/* FIXME: unsigned long long */
+	char *end;
+
+	if (argc != 2) {
+		*context = "dm-linear: Not enough arguments";
+		return -EINVAL;
+	}
+
+	lc = kmalloc(sizeof(*lc), GFP_KERNEL);
+	if (lc == NULL) {
+		*context = "dm-linear: Cannot allocate linear context";
+		return -ENOMEM;
+	}
+
+	start = simple_strtoul(argv[1], &end, 10);
+	if (*end) {
+		*context = "dm-linear: Invalid device sector";
+		goto bad;
+	}
+
+	if (dm_table_get_device(t, argv[0], start, l, t->mode, &lc->dev)) {
+		*context = "dm-linear: Device lookup failed";
+		goto bad;
+	}
+
+	lc->delta = (int) start - (int) b;
+	lc->start = start;
+	*context = lc;
+	return 0;
+
+      bad:
+	kfree(lc);
+	return -EINVAL;
+}
+
+static void linear_dtr(struct dm_table *t, void *c)
+{
+	struct linear_c *lc = (struct linear_c *) c;
+
+	dm_table_put_device(t, lc->dev);
+	kfree(c);
+}
+
+static int linear_map(struct buffer_head *bh, int rw, void *context)
+{
+	struct linear_c *lc = (struct linear_c *) context;
+
+	bh->b_rdev = lc->dev->dev;
+	bh->b_rsector = bh->b_rsector + lc->delta;
+
+	return 1;
+}
+
+static int linear_status(status_type_t type, char *result, int maxlen,
+			 void *context)
+{
+	struct linear_c *lc = (struct linear_c *) context;
+
+	switch (type) {
+	case STATUSTYPE_INFO:
+		result[0] = '\0';
+		break;
+
+	case STATUSTYPE_TABLE:
+		snprintf(result, maxlen, "%s %ld", kdevname(lc->dev->dev),
+			 lc->start);
+		break;
+	}
+	return 0;
+}
+
+static struct target_type linear_target = {
+	name:	"linear",
+	module:	THIS_MODULE,
+	ctr:	linear_ctr,
+	dtr:	linear_dtr,
+	map:	linear_map,
+	status:	linear_status,
+};
+
+int __init dm_linear_init(void)
+{
+	int r = dm_register_target(&linear_target);
+
+	if (r < 0)
+		DMERR("linear: register failed %d", r);
+
+	return r;
+}
+
+void dm_linear_exit(void)
+{
+	int r = dm_unregister_target(&linear_target);
+
+	if (r < 0)
+		DMERR("linear: unregister failed %d", r);
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/md/dm-snapshot.c linux.20pre10-ac2/drivers/md/dm-snapshot.c
--- linux.20pre10/drivers/md/dm-snapshot.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/md/dm-snapshot.c	2002-08-12 22:45:52.000000000 +0100
@@ -0,0 +1,1169 @@
+/*
+ * dm-snapshot.c
+ *
+ * Copyright (C) 2001-2002 Sistina Software (UK) Limited.
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/blkdev.h>
+#include <linux/mempool.h>
+#include <linux/device-mapper.h>
+
+#include "dm-snapshot.h"
+#include "kcopyd.h"
+
+/*
+ * FIXME: Remove this before release.
+ */
+#if 0
+#define DMDEBUG(x...) DMWARN( ## x)
+#else
+#define DMDEBUG(x...)
+#endif
+
+/*
+ * The percentage increment we will wake up users at
+ */
+#define WAKE_UP_PERCENT 5
+
+/*
+ * Hard sector size used all over the kernel
+ */
+#define SECTOR_SIZE 512
+
+/*
+ * kcopyd priority of snapshot operations
+ */
+#define SNAPSHOT_COPY_PRIORITY 2
+
+struct pending_exception {
+	struct exception e;
+
+	/*
+	 * Origin buffers waiting for this to complete are held
+	 * in a list (using b_reqnext).
+	 */
+	struct buffer_head *origin_bhs;
+	struct buffer_head *snapshot_bhs;
+
+	/*
+	 * Other pending_exceptions that are processing this
+	 * chunk.  When this list is empty, we know we can
+	 * complete the origins.
+	 */
+	struct list_head siblings;
+
+	/* Pointer back to snapshot context */
+	struct dm_snapshot *snap;
+
+	/*
+	 * 1 indicates the exception has already been sent to
+	 * kcopyd.
+	 */
+	int started;
+};
+
+/*
+ * Hash table mapping origin volumes to lists of snapshots and
+ * a lock to protect it
+ */
+static kmem_cache_t *exception_cache;
+static kmem_cache_t *pending_cache;
+static mempool_t *pending_pool;
+
+/*
+ * One of these per registered origin, held in the snapshot_origins hash
+ */
+struct origin {
+	/* The origin device */
+	kdev_t dev;
+
+	struct list_head hash_list;
+
+	/* List of snapshots for this origin */
+	struct list_head snapshots;
+};
+
+/*
+ * Size of the hash table for origin volumes. If we make this
+ * the size of the minors list then it should be nearly perfect
+ */
+#define ORIGIN_HASH_SIZE 256
+#define ORIGIN_MASK      0xFF
+static struct list_head *_origins;
+static struct rw_semaphore _origins_lock;
+
+static int init_origin_hash(void)
+{
+	int i;
+
+	_origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head),
+			   GFP_KERNEL);
+	if (!_origins) {
+		DMERR("Device mapper: Snapshot: unable to allocate memory");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < ORIGIN_HASH_SIZE; i++)
+		INIT_LIST_HEAD(_origins + i);
+	init_rwsem(&_origins_lock);
+
+	return 0;
+}
+
+static void exit_origin_hash(void)
+{
+	kfree(_origins);
+}
+
+static inline unsigned int origin_hash(kdev_t dev)
+{
+	return MINOR(dev) & ORIGIN_MASK;
+}
+
+static struct origin *__lookup_origin(kdev_t origin)
+{
+	struct list_head *slist;
+	struct list_head *ol;
+	struct origin *o;
+
+	ol = &_origins[origin_hash(origin)];
+	list_for_each(slist, ol) {
+		o = list_entry(slist, struct origin, hash_list);
+
+		if (o->dev == origin)
+			return o;
+	}
+
+	return NULL;
+}
+
+static void __insert_origin(struct origin *o)
+{
+	struct list_head *sl = &_origins[origin_hash(o->dev)];
+	list_add_tail(&o->hash_list, sl);
+}
+
+/*
+ * Make a note of the snapshot and its origin so we can look it
+ * up when the origin has a write on it.
+ */
+static int register_snapshot(struct dm_snapshot *snap)
+{
+	struct origin *o;
+	kdev_t dev = snap->origin->dev;
+
+	down_write(&_origins_lock);
+	o = __lookup_origin(dev);
+
+	if (!o) {
+		/* New origin */
+		o = kmalloc(sizeof(*o), GFP_KERNEL);
+		if (!o) {
+			up_write(&_origins_lock);
+			return -ENOMEM;
+		}
+
+		/* Initialise the struct */
+		INIT_LIST_HEAD(&o->snapshots);
+		o->dev = dev;
+
+		__insert_origin(o);
+	}
+
+	list_add_tail(&snap->list, &o->snapshots);
+
+	up_write(&_origins_lock);
+	return 0;
+}
+
+static void unregister_snapshot(struct dm_snapshot *s)
+{
+	struct origin *o;
+
+	down_write(&_origins_lock);
+	o = __lookup_origin(s->origin->dev);
+
+	list_del(&s->list);
+	if (list_empty(&o->snapshots)) {
+		list_del(&o->hash_list);
+		kfree(o);
+	}
+
+	up_write(&_origins_lock);
+}
+
+/*
+ * Implementation of the exception hash tables.
+ */
+static int init_exception_table(struct exception_table *et, uint32_t size)
+{
+	int i;
+
+	et->hash_mask = size - 1;
+	et->table = vcalloc(size, sizeof(struct list_head));
+	if (!et->table)
+		return -ENOMEM;
+
+	for (i = 0; i < size; i++)
+		INIT_LIST_HEAD(et->table + i);
+
+	return 0;
+}
+
+static void exit_exception_table(struct exception_table *et, kmem_cache_t *mem)
+{
+	struct list_head *slot, *entry, *temp;
+	struct exception *ex;
+	int i, size;
+
+	size = et->hash_mask + 1;
+	for (i = 0; i < size; i++) {
+		slot = et->table + i;
+
+		list_for_each_safe(entry, temp, slot) {
+			ex = list_entry(entry, struct exception, hash_list);
+			kmem_cache_free(mem, ex);
+		}
+	}
+
+	vfree(et->table);
+}
+
+/*
+ * FIXME: check how this hash fn is performing.
+ */
+static inline uint32_t exception_hash(struct exception_table *et, chunk_t chunk)
+{
+	return chunk & et->hash_mask;
+}
+
+static void insert_exception(struct exception_table *eh, struct exception *e)
+{
+	struct list_head *l = &eh->table[exception_hash(eh, e->old_chunk)];
+	list_add(&e->hash_list, l);
+}
+
+static inline void remove_exception(struct exception *e)
+{
+	list_del(&e->hash_list);
+}
+
+/*
+ * Return the exception data for a sector, or NULL if not
+ * remapped.
+ */
+static struct exception *lookup_exception(struct exception_table *et,
+					  chunk_t chunk)
+{
+	struct list_head *slot, *el;
+	struct exception *e;
+
+	slot = &et->table[exception_hash(et, chunk)];
+	list_for_each(el, slot) {
+		e = list_entry(el, struct exception, hash_list);
+		if (e->old_chunk == chunk)
+			return e;
+	}
+
+	return NULL;
+}
+
+static inline struct exception *alloc_exception(void)
+{
+	struct exception *e;
+
+	e = kmem_cache_alloc(exception_cache, GFP_NOIO);
+	if (!e)
+		e = kmem_cache_alloc(exception_cache, GFP_ATOMIC);
+
+	return e;
+}
+
+static inline void free_exception(struct exception *e)
+{
+	kmem_cache_free(exception_cache, e);
+}
+
+static inline struct pending_exception *alloc_pending_exception(void)
+{
+	return mempool_alloc(pending_pool, GFP_NOIO);
+}
+
+static inline void free_pending_exception(struct pending_exception *pe)
+{
+	mempool_free(pe, pending_pool);
+}
+
+int dm_add_exception(struct dm_snapshot *s, chunk_t old, chunk_t new)
+{
+	struct exception *e;
+
+	e = alloc_exception();
+	if (!e)
+		return -ENOMEM;
+
+	e->old_chunk = old;
+	e->new_chunk = new;
+	insert_exception(&s->complete, e);
+	return 0;
+}
+
+/*
+ * Hard coded magic.
+ */
+static int calc_max_buckets(void)
+{
+	unsigned long mem;
+
+	mem = num_physpages << PAGE_SHIFT;
+	mem /= 50;
+	mem /= sizeof(struct list_head);
+
+	return mem;
+}
+
+/*
+ * Rounds a number down to a power of 2.
+ */
+static inline uint32_t round_down(uint32_t n)
+{
+	while (n & (n - 1))
+		n &= (n - 1);
+	return n;
+}
+
+/*
+ * Allocate room for a suitable hash table.
+ */
+static int init_hash_tables(struct dm_snapshot *s)
+{
+	offset_t hash_size, cow_dev_size, origin_dev_size, max_buckets;
+
+	/*
+	 * Calculate based on the size of the original volume or
+	 * the COW volume...
+	 */
+	cow_dev_size = get_dev_size(s->cow->dev);
+	origin_dev_size = get_dev_size(s->origin->dev);
+	max_buckets = calc_max_buckets();
+
+	hash_size = min(origin_dev_size, cow_dev_size) / s->chunk_size;
+	hash_size = min(hash_size, max_buckets);
+
+	/* Round it down to a power of 2 */
+	hash_size = round_down(hash_size);
+	if (init_exception_table(&s->complete, hash_size))
+		return -ENOMEM;
+
+	/*
+	 * Allocate hash table for in-flight exceptions
+	 * Make this smaller than the real hash table
+	 */
+	hash_size >>= 3;
+	if (!hash_size)
+		hash_size = 64;
+
+	if (init_exception_table(&s->pending, hash_size)) {
+		exit_exception_table(&s->complete, exception_cache);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/*
+ * Round a number up to the nearest 'size' boundary.  size must
+ * be a power of 2.
+ */
+static inline ulong round_up(ulong n, ulong size)
+{
+	size--;
+	return (n + size) & ~size;
+}
+
+/*
+ * Construct a snapshot mapping: <origin_dev> <COW-dev> <p/n> <chunk-size>
+ */
+static int snapshot_ctr(struct dm_table *t, offset_t b, offset_t l,
+			int argc, char **argv, void **context)
+{
+	struct dm_snapshot *s;
+	unsigned long chunk_size;
+	int r = -EINVAL;
+	char *persistent;
+	char *origin_path;
+	char *cow_path;
+	char *value;
+	int blocksize;
+
+	if (argc < 4) {
+		*context = "dm-snapshot: requires exactly 4 arguments";
+		r = -EINVAL;
+		goto bad;
+	}
+
+	origin_path = argv[0];
+	cow_path = argv[1];
+	persistent = argv[2];
+
+	if ((*persistent & 0x5f) != 'P' && (*persistent & 0x5f) != 'N') {
+		*context = "Persistent flag is not P or N";
+		r = -EINVAL;
+		goto bad;
+	}
+
+	chunk_size = simple_strtoul(argv[3], &value, 10);
+	if (chunk_size == 0 || value == NULL) {
+		*context = "Invalid chunk size";
+		r = -EINVAL;
+		goto bad;
+	}
+
+	s = kmalloc(sizeof(*s), GFP_KERNEL);
+	if (s == NULL) {
+		*context = "Cannot allocate snapshot context private structure";
+		r = -ENOMEM;
+		goto bad;
+	}
+
+	r = dm_table_get_device(t, origin_path, 0, 0, FMODE_READ, &s->origin);
+	if (r) {
+		*context = "Cannot get origin device";
+		goto bad_free;
+	}
+
+	r = dm_table_get_device(t, cow_path, 0, 0,
+				FMODE_READ | FMODE_WRITE, &s->cow);
+	if (r) {
+		dm_table_put_device(t, s->origin);
+		*context = "Cannot get COW device";
+		goto bad_free;
+	}
+
+	/*
+	 * Chunk size must be multiple of page size.  Silently
+	 * round up if it's not.
+	 */
+	chunk_size = round_up(chunk_size, PAGE_SIZE / SECTOR_SIZE);
+
+	/* Validate the chunk size against the device block size */
+	blocksize = get_hardsect_size(s->cow->dev);
+	if (chunk_size % (blocksize / SECTOR_SIZE)) {
+		*context = "Chunk size is not a multiple of device blocksize";
+		r = -EINVAL;
+		goto bad_putdev;
+	}
+
+	/* Check the sizes are small enough to fit in one kiovec */
+	if (chunk_size > KIO_MAX_SECTORS) {
+		*context = "Chunk size is too big";
+		r = -EINVAL;
+		goto bad_putdev;
+	}
+
+	/* Check chunk_size is a power of 2 */
+	if (chunk_size & (chunk_size - 1)) {
+		*context = "Chunk size is not a power of 2";
+		r = -EINVAL;
+		goto bad_putdev;
+	}
+
+	s->chunk_size = chunk_size;
+	s->chunk_mask = chunk_size - 1;
+	s->type = *persistent;
+	for (s->chunk_shift = 0; chunk_size;
+	     s->chunk_shift++, chunk_size >>= 1)
+		;
+	s->chunk_shift--;
+
+	s->valid = 1;
+	s->last_percent = 0;
+	s->table = t;
+	init_rwsem(&s->lock);
+
+	/* Allocate hash table for COW data */
+	if (init_hash_tables(s)) {
+		*context = "Unable to allocate hash table space";
+		r = -ENOMEM;
+		goto bad_putdev;
+	}
+
+	/*
+	 * Check the persistent flag - done here because we need the iobuf
+	 * to check the LV header
+	 */
+	s->store.snap = s;
+
+	if ((*persistent & 0x5f) == 'P')
+		r = dm_create_persistent(&s->store, s->chunk_size);
+	else
+		r = dm_create_transient(&s->store, s, blocksize, context);
+
+	if (r) {
+		*context = "Couldn't create exception store";
+		r = -EINVAL;
+		goto bad_free1;
+	}
+
+	/* Flush IO to the origin device */
+#if LVM_VFS_ENHANCEMENT
+	fsync_dev_lockfs(s->origin->dev);
+#else
+	fsync_dev(s->origin->dev);
+#endif
+
+	/* Add snapshot to the list of snapshots for this origin */
+	if (register_snapshot(s)) {
+		r = -EINVAL;
+		*context = "Cannot register snapshot origin";
+		goto bad_free2;
+	}
+#if LVM_VFS_ENHANCEMENT
+	unlockfs(s->origin->dev);
+#endif
+	kcopyd_inc_client_count();
+
+	*context = s;
+	return 0;
+
+      bad_free2:
+	s->store.destroy(&s->store);
+
+      bad_free1:
+	exit_exception_table(&s->pending, pending_cache);
+	exit_exception_table(&s->complete, exception_cache);
+
+      bad_putdev:
+	dm_table_put_device(t, s->cow);
+	dm_table_put_device(t, s->origin);
+
+      bad_free:
+	kfree(s);
+
+      bad:
+	return r;
+}
+
+static void snapshot_dtr(struct dm_table *t, void *context)
+{
+	struct dm_snapshot *s = (struct dm_snapshot *) context;
+
+	dm_table_event(s->table);
+
+	unregister_snapshot(s);
+
+	exit_exception_table(&s->pending, pending_cache);
+	exit_exception_table(&s->complete, exception_cache);
+
+	/* Deallocate memory used */
+	s->store.destroy(&s->store);
+
+	dm_table_put_device(t, s->origin);
+	dm_table_put_device(t, s->cow);
+	kfree(s);
+
+	kcopyd_dec_client_count();
+}
+
+/*
+ * We hold lists of buffer_heads, using the b_reqnext field.
+ */
+static void queue_buffer(struct buffer_head **queue, struct buffer_head *bh)
+{
+	bh->b_reqnext = *queue;
+	*queue = bh;
+}
+
+/*
+ * Flush a list of buffers.
+ */
+static void flush_buffers(struct buffer_head *bh)
+{
+	struct buffer_head *n;
+
+	DMDEBUG("begin flush");
+	while (bh) {
+		n = bh->b_reqnext;
+		bh->b_reqnext = NULL;
+		DMDEBUG("flushing %p", bh);
+		generic_make_request(WRITE, bh);
+		bh = n;
+	}
+
+	run_task_queue(&tq_disk);
+}
+
+/*
+ * Error a list of buffers.
+ */
+static void error_buffers(struct buffer_head *bh)
+{
+	struct buffer_head *n;
+
+	while (bh) {
+		n = bh->b_reqnext;
+		bh->b_reqnext = NULL;
+		buffer_IO_error(bh);
+		bh = n;
+	}
+}
+
+static void pending_complete(struct pending_exception *pe, int success)
+{
+	struct exception *e;
+	struct dm_snapshot *s = pe->snap;
+
+	if (success) {
+		e = alloc_exception();
+		if (!e) {
+			printk("Unable to allocate exception.");
+			down_write(&s->lock);
+			s->store.drop_snapshot(&s->store);
+			s->valid = 0;
+			up_write(&s->lock);
+			return;
+		}
+
+		/*
+		 * Add a proper exception, and remove the
+		 * inflight exception from the list.
+		 */
+		down_write(&s->lock);
+
+		memcpy(e, &pe->e, sizeof(*e));
+		insert_exception(&s->complete, e);
+		remove_exception(&pe->e);
+
+		/* Submit any pending write BHs */
+		up_write(&s->lock);
+
+		flush_buffers(pe->snapshot_bhs);
+		DMDEBUG("Exception completed successfully.");
+
+		/* Notify any interested parties */
+		if (s->store.percent_full) {
+			int pc = s->store.percent_full(&s->store);
+
+			if (pc >= s->last_percent + WAKE_UP_PERCENT) {
+				dm_table_event(s->table);
+				s->last_percent = pc - pc % WAKE_UP_PERCENT;
+			}
+		}
+
+	} else {
+		/* Read/write error - snapshot is unusable */
+		DMERR("Error reading/writing snapshot");
+
+		down_write(&s->lock);
+		s->store.drop_snapshot(&s->store);
+		s->valid = 0;
+		remove_exception(&pe->e);
+		up_write(&s->lock);
+
+		error_buffers(pe->snapshot_bhs);
+
+		dm_table_event(s->table);
+		DMDEBUG("Exception failed.");
+	}
+
+	if (list_empty(&pe->siblings))
+		flush_buffers(pe->origin_bhs);
+	else
+		list_del(&pe->siblings);
+
+	free_pending_exception(pe);
+}
+
+static void commit_callback(void *context, int success)
+{
+	struct pending_exception *pe = (struct pending_exception *) context;
+	pending_complete(pe, success);
+}
+
+/*
+ * Called when the copy I/O has finished.  kcopyd actually runs
+ * this code so don't block.
+ */
+static void copy_callback(int err, void *context)
+{
+	struct pending_exception *pe = (struct pending_exception *) context;
+	struct dm_snapshot *s = pe->snap;
+
+	if (err)
+		pending_complete(pe, 0);
+
+	else
+		/* Update the metadata if we are persistent */
+		s->store.commit_exception(&s->store, &pe->e, commit_callback,
+					  pe);
+}
+
+/*
+ * Dispatches the copy operation to kcopyd.
+ */
+static inline void start_copy(struct pending_exception *pe)
+{
+	struct dm_snapshot *s = pe->snap;
+	struct kcopyd_region src, dest;
+
+	src.dev = s->origin->dev;
+	src.sector = chunk_to_sector(s, pe->e.old_chunk);
+	src.count = s->chunk_size;
+
+	dest.dev = s->cow->dev;
+	dest.sector = chunk_to_sector(s, pe->e.new_chunk);
+	dest.count = s->chunk_size;
+
+	if (!pe->started) {
+		/* Hand over to kcopyd */
+		kcopyd_copy(&src, &dest, copy_callback, pe);
+		pe->started = 1;
+	}
+}
+
+/*
+ * Looks to see if this snapshot already has a pending exception
+ * for this chunk, otherwise it allocates a new one and inserts
+ * it into the pending table.
+ */
+static struct pending_exception *find_pending_exception(struct dm_snapshot *s,
+							struct buffer_head *bh)
+{
+	struct exception *e;
+	struct pending_exception *pe;
+	chunk_t chunk = sector_to_chunk(s, bh->b_rsector);
+
+	/*
+	 * Is there a pending exception for this already ?
+	 */
+	e = lookup_exception(&s->pending, chunk);
+	if (e) {
+		/* cast the exception to a pending exception */
+		pe = list_entry(e, struct pending_exception, e);
+
+	} else {
+		/* Create a new pending exception */
+		pe = alloc_pending_exception();
+		if (!pe) {
+			DMWARN("Couldn't allocate pending exception.");
+			return NULL;
+		}
+
+		pe->e.old_chunk = chunk;
+		pe->origin_bhs = pe->snapshot_bhs = NULL;
+		INIT_LIST_HEAD(&pe->siblings);
+		pe->snap = s;
+		pe->started = 0;
+
+		if (s->store.prepare_exception(&s->store, &pe->e)) {
+			free_pending_exception(pe);
+			s->valid = 0;
+			return NULL;
+		}
+
+		insert_exception(&s->pending, &pe->e);
+	}
+
+	return pe;
+}
+
+static inline void remap_exception(struct dm_snapshot *s, struct exception *e,
+				   struct buffer_head *bh)
+{
+	bh->b_rdev = s->cow->dev;
+	bh->b_rsector = chunk_to_sector(s, e->new_chunk) +
+	    (bh->b_rsector & s->chunk_mask);
+}
+
+static int snapshot_map(struct buffer_head *bh, int rw, void *context)
+{
+	struct exception *e;
+	struct dm_snapshot *s = (struct dm_snapshot *) context;
+	int r = 1;
+	chunk_t chunk;
+	struct pending_exception *pe;
+
+	chunk = sector_to_chunk(s, bh->b_rsector);
+
+	/* Full snapshots are not usable */
+	if (!s->valid)
+		return -1;
+
+	/*
+	 * Write to snapshot - higher level takes care of RW/RO
+	 * flags so we should only get this if we are
+	 * writeable.
+	 */
+	if (rw == WRITE) {
+
+		down_write(&s->lock);
+
+		/* If the block is already remapped - use that, else remap it */
+		e = lookup_exception(&s->complete, chunk);
+		if (e)
+			remap_exception(s, e, bh);
+
+		else {
+			pe = find_pending_exception(s, bh);
+
+			if (!pe) {
+				s->store.drop_snapshot(&s->store);
+				s->valid = 0;
+			}
+
+			queue_buffer(&pe->snapshot_bhs, bh);
+			start_copy(pe);
+			r = 0;
+		}
+
+		up_write(&s->lock);
+
+	} else {
+		/*
+		 * FIXME: this read path scares me because we
+		 * always use the origin when we have a pending
+		 * exception.  However I can't think of a
+		 * situation where this is wrong - ejt.
+		 */
+
+		/* Do reads */
+		down_read(&s->lock);
+
+		/* See if it it has been remapped */
+		e = lookup_exception(&s->complete, chunk);
+		if (e)
+			remap_exception(s, e, bh);
+		else
+			bh->b_rdev = s->origin->dev;
+
+		up_read(&s->lock);
+	}
+
+	return r;
+}
+
+static void list_merge(struct list_head *l1, struct list_head *l2)
+{
+	struct list_head *l1_n, *l2_p;
+
+	l1_n = l1->next;
+	l2_p = l2->prev;
+
+	l1->next = l2;
+	l2->prev = l1;
+
+	l2_p->next = l1_n;
+	l1_n->prev = l2_p;
+}
+
+static int __origin_write(struct list_head *snapshots, struct buffer_head *bh)
+{
+	int r = 1;
+	struct list_head *sl;
+	struct dm_snapshot *snap;
+	struct exception *e;
+	struct pending_exception *pe, *last = NULL;
+	chunk_t chunk;
+
+	/* Do all the snapshots on this origin */
+	list_for_each(sl, snapshots) {
+		snap = list_entry(sl, struct dm_snapshot, list);
+
+		/* Only deal with valid snapshots */
+		if (!snap->valid)
+			continue;
+
+		down_write(&snap->lock);
+
+		/*
+		 * Remember, different snapshots can have
+		 * different chunk sizes.
+		 */
+		chunk = sector_to_chunk(snap, bh->b_rsector);
+
+		/*
+		 * Check exception table to see if block
+		 * is already remapped in this snapshot
+		 * and trigger an exception if not.
+		 */
+		e = lookup_exception(&snap->complete, chunk);
+		if (!e) {
+			pe = find_pending_exception(snap, bh);
+			if (!pe) {
+				snap->store.drop_snapshot(&snap->store);
+				snap->valid = 0;
+
+			} else {
+				if (last)
+					list_merge(&pe->siblings,
+						   &last->siblings);
+
+				last = pe;
+				r = 0;
+			}
+		}
+
+		up_write(&snap->lock);
+	}
+
+	/*
+	 * Now that we have a complete pe list we can start the copying.
+	 */
+	if (last) {
+		pe = last;
+		do {
+			down_write(&pe->snap->lock);
+			queue_buffer(&pe->origin_bhs, bh);
+			start_copy(pe);
+			up_write(&pe->snap->lock);
+			pe = list_entry(pe->siblings.next,
+					struct pending_exception, siblings);
+
+		} while (pe != last);
+	}
+
+	return r;
+}
+
+static int snapshot_status(status_type_t type, char *result,
+			   int maxlen, void *context)
+{
+	struct dm_snapshot *snap = (struct dm_snapshot *) context;
+	char cow[16];
+	char org[16];
+
+	switch (type) {
+	case STATUSTYPE_INFO:
+		if (!snap->valid)
+			snprintf(result, maxlen, "Invalid");
+		else {
+			if (snap->store.percent_full)
+				snprintf(result, maxlen, "%d%%",
+					 snap->store.percent_full(&snap->
+								  store));
+			else
+				snprintf(result, maxlen, "Unknown");
+		}
+		break;
+
+	case STATUSTYPE_TABLE:
+		/*
+		 * kdevname returns a static pointer so we need
+		 * to make private copies if the output is to
+		 * make sense.
+		 */
+		strncpy(cow, kdevname(snap->cow->dev), sizeof(cow));
+		strncpy(org, kdevname(snap->origin->dev), sizeof(org));
+		snprintf(result, maxlen, "%s %s %c %ld", org, cow,
+			 snap->type, snap->chunk_size);
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * Called on a write from the origin driver.
+ */
+int do_origin(struct dm_dev *origin, struct buffer_head *bh)
+{
+	struct origin *o;
+	int r;
+
+	down_read(&_origins_lock);
+	o = __lookup_origin(origin->dev);
+	if (!o)
+		BUG();
+
+	r = __origin_write(&o->snapshots, bh);
+	up_read(&_origins_lock);
+
+	return r;
+}
+
+/*
+ * Origin: maps a linear range of a device, with hooks for snapshotting.
+ */
+
+/*
+ * Construct an origin mapping: <dev_path>
+ * The context for an origin is merely a 'struct dm_dev *'
+ * pointing to the real device.
+ */
+static int origin_ctr(struct dm_table *t, offset_t b, offset_t l,
+		      int argc, char **argv, void **context)
+{
+	int r;
+	struct dm_dev *dev;
+
+	if (argc != 1) {
+		*context = "dm-origin: incorrect number of arguments";
+		return -EINVAL;
+	}
+
+	r = dm_table_get_device(t, argv[0], 0, l, t->mode, &dev);
+	if (r) {
+		*context = "Cannot get target device";
+		return r;
+	}
+
+	*context = dev;
+
+	return 0;
+}
+
+static void origin_dtr(struct dm_table *t, void *c)
+{
+	struct dm_dev *dev = (struct dm_dev *) c;
+	dm_table_put_device(t, dev);
+}
+
+static int origin_map(struct buffer_head *bh, int rw, void *context)
+{
+	struct dm_dev *dev = (struct dm_dev *) context;
+	bh->b_rdev = dev->dev;
+
+	/* Only tell snapshots if this is a write */
+	return (rw == WRITE) ? do_origin(dev, bh) : 1;
+}
+
+static int origin_status(status_type_t type, char *result,
+			 int maxlen, void *context)
+{
+	struct dm_dev *dev = (struct dm_dev *) context;
+
+	switch (type) {
+	case STATUSTYPE_INFO:
+		result[0] = '\0';
+		break;
+
+	case STATUSTYPE_TABLE:
+		snprintf(result, maxlen, "%s", kdevname(dev->dev));
+		break;
+	}
+
+	return 0;
+}
+
+static struct target_type origin_target = {
+	name:	"snapshot-origin",
+	module:	THIS_MODULE,
+	ctr:	origin_ctr,
+	dtr:	origin_dtr,
+	map:	origin_map,
+	status:	origin_status,
+	err:	NULL
+};
+
+static struct target_type snapshot_target = {
+	name:	"snapshot",
+	module:	THIS_MODULE,
+	ctr:	snapshot_ctr,
+	dtr:	snapshot_dtr,
+	map:	snapshot_map,
+	status:	snapshot_status,
+	err:	NULL
+};
+
+int __init dm_snapshot_init(void)
+{
+	int r;
+
+	r = dm_register_target(&snapshot_target);
+	if (r) {
+		DMERR("snapshot target register failed %d", r);
+		return r;
+	}
+
+	r = dm_register_target(&origin_target);
+	if (r < 0) {
+		DMERR("Device mapper: Origin: register failed %d\n", r);
+		goto bad1;
+	}
+
+	r = init_origin_hash();
+	if (r) {
+		DMERR("init_origin_hash failed.");
+		goto bad2;
+	}
+
+	exception_cache = kmem_cache_create("dm-snapshot-ex",
+					    sizeof(struct exception),
+					    __alignof__(struct exception),
+					    0, NULL, NULL);
+	if (!exception_cache) {
+		DMERR("Couldn't create exception cache.");
+		r = -ENOMEM;
+		goto bad3;
+	}
+
+	pending_cache =
+	    kmem_cache_create("dm-snapshot-in",
+			      sizeof(struct pending_exception),
+			      __alignof__(struct pending_exception),
+			      0, NULL, NULL);
+	if (!pending_cache) {
+		DMERR("Couldn't create pending cache.");
+		r = -ENOMEM;
+		goto bad4;
+	}
+
+	pending_pool = mempool_create(128, mempool_alloc_slab,
+				      mempool_free_slab, pending_cache);
+	if (!pending_pool) {
+		DMERR("Couldn't create pending pool.");
+		r = -ENOMEM;
+		goto bad5;
+	}
+
+	return 0;
+
+      bad5:
+	kmem_cache_destroy(pending_cache);
+      bad4:
+	kmem_cache_destroy(exception_cache);
+      bad3:
+	exit_origin_hash();
+      bad2:
+	dm_unregister_target(&origin_target);
+      bad1:
+	dm_unregister_target(&snapshot_target);
+	return r;
+}
+
+void dm_snapshot_exit(void)
+{
+	int r;
+
+	r = dm_unregister_target(&snapshot_target);
+	if (r)
+		DMERR("snapshot unregister failed %d", r);
+
+	r = dm_unregister_target(&origin_target);
+	if (r)
+		DMERR("origin unregister failed %d", r);
+
+	exit_origin_hash();
+	mempool_destroy(pending_pool);
+	kmem_cache_destroy(pending_cache);
+	kmem_cache_destroy(exception_cache);
+}
+
+/*
+ * 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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/md/dm-snapshot.h linux.20pre10-ac2/drivers/md/dm-snapshot.h
--- linux.20pre10/drivers/md/dm-snapshot.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/md/dm-snapshot.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,147 @@
+/*
+ * dm-snapshot.c
+ *
+ * Copyright (C) 2001-2002 Sistina Software (UK) Limited.
+ *
+ * This file is released under the GPL.
+ */
+
+#ifndef DM_SNAPSHOT_H
+#define DM_SNAPSHOT_H
+
+#include "dm.h"
+#include <linux/blkdev.h>
+
+struct exception_table {
+	uint32_t hash_mask;
+	struct list_head *table;
+};
+
+/*
+ * The snapshot code deals with largish chunks of the disk at a
+ * time. Typically 64k - 256k.
+ */
+/* FIXME: can we get away with limiting these to a uint32_t ? */
+typedef offset_t chunk_t;
+
+/*
+ * An exception is used where an old chunk of data has been
+ * replaced by a new one.
+ */
+struct exception {
+	struct list_head hash_list;
+
+	chunk_t old_chunk;
+	chunk_t new_chunk;
+};
+
+/*
+ * Abstraction to handle the meta/layout of exception stores (the
+ * COW device).
+ */
+struct exception_store {
+
+	/*
+	 * Destroys this object when you've finished with it.
+	 */
+	void (*destroy) (struct exception_store *store);
+
+	/*
+	 * Find somewhere to store the next exception.
+	 */
+	int (*prepare_exception) (struct exception_store *store,
+				  struct exception *e);
+
+	/*
+	 * Update the metadata with this exception.
+	 */
+	void (*commit_exception) (struct exception_store *store,
+				  struct exception *e,
+				  void (*callback) (void *, int success),
+				  void *callback_context);
+
+	/*
+	 * The snapshot is invalid, note this in the metadata.
+	 */
+	void (*drop_snapshot) (struct exception_store *store);
+
+	/*
+	 * Return the %age full of the snapshot
+	 */
+	int (*percent_full) (struct exception_store *store);
+
+	struct dm_snapshot *snap;
+	void *context;
+};
+
+struct dm_snapshot {
+	struct rw_semaphore lock;
+	struct dm_table *table;
+
+	struct dm_dev *origin;
+	struct dm_dev *cow;
+
+	/* List of snapshots per Origin */
+	struct list_head list;
+
+	/* Size of data blocks saved - must be a power of 2 */
+	chunk_t chunk_size;
+	chunk_t chunk_mask;
+	chunk_t chunk_shift;
+
+	/* You can't use a snapshot if this is 0 (e.g. if full) */
+	int valid;
+
+	/* Used for display of table */
+	char type;
+
+	/* The last percentage we notified */
+	int last_percent;
+
+	struct exception_table pending;
+	struct exception_table complete;
+
+	/* The on disk metadata handler */
+	struct exception_store store;
+};
+
+/*
+ * Used by the exception stores to load exceptions hen
+ * initialising.
+ */
+int dm_add_exception(struct dm_snapshot *s, chunk_t old, chunk_t new);
+
+/*
+ * Constructor and destructor for the default persistent
+ * store.
+ */
+int dm_create_persistent(struct exception_store *store, uint32_t chunk_size);
+
+int dm_create_transient(struct exception_store *store,
+			struct dm_snapshot *s, int blocksize, void **error);
+
+/*
+ * Return the number of sectors in the device.
+ */
+static inline offset_t get_dev_size(kdev_t dev)
+{
+	int *sizes;
+
+	sizes = blk_size[MAJOR(dev)];
+	if (sizes)
+		return sizes[MINOR(dev)] << 1;
+
+	return 0;
+}
+
+static inline chunk_t sector_to_chunk(struct dm_snapshot *s, offset_t sector)
+{
+	return (sector & ~s->chunk_mask) >> s->chunk_shift;
+}
+
+static inline offset_t chunk_to_sector(struct dm_snapshot *s, chunk_t chunk)
+{
+	return chunk << s->chunk_shift;
+}
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/md/dm-stripe.c linux.20pre10-ac2/drivers/md/dm-stripe.c
--- linux.20pre10/drivers/md/dm-stripe.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/md/dm-stripe.c	2002-08-12 22:45:52.000000000 +0100
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm.h"
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+
+struct stripe {
+	struct dm_dev *dev;
+	offset_t physical_start;
+};
+
+struct stripe_c {
+	offset_t logical_start;
+	uint32_t stripes;
+
+	/* The size of this target / num. stripes */
+	uint32_t stripe_width;
+
+	/* stripe chunk size */
+	uint32_t chunk_shift;
+	offset_t chunk_mask;
+
+	struct stripe stripe[0];
+};
+
+static inline struct stripe_c *alloc_context(int stripes)
+{
+	size_t len;
+
+	if (array_too_big(sizeof(struct stripe_c), sizeof(struct stripe),
+			  stripes))
+		return NULL;
+
+	len = sizeof(struct stripe_c) + (sizeof(struct stripe) * stripes);
+
+	return kmalloc(len, GFP_KERNEL);
+}
+
+/*
+ * Parse a single <dev> <sector> pair
+ */
+static int get_stripe(struct dm_table *t, struct stripe_c *sc,
+		      int stripe, char **argv)
+{
+	char *end;
+	unsigned long start;
+
+	start = simple_strtoul(argv[1], &end, 10);
+	if (*end)
+		return -EINVAL;
+
+	if (dm_table_get_device(t, argv[0], start, sc->stripe_width,
+				t->mode, &sc->stripe[stripe].dev))
+		return -ENXIO;
+
+	sc->stripe[stripe].physical_start = start;
+	return 0;
+}
+
+/*
+ * Construct a striped mapping.
+ * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+
+ */
+static int stripe_ctr(struct dm_table *t, offset_t b, offset_t l,
+		      int argc, char **argv, void **context)
+{
+	struct stripe_c *sc;
+	uint32_t stripes;
+	uint32_t chunk_size;
+	char *end;
+	int r, i;
+
+	if (argc < 2) {
+		*context = "dm-stripe: Not enough arguments";
+		return -EINVAL;
+	}
+
+	stripes = simple_strtoul(argv[0], &end, 10);
+	if (*end) {
+		*context = "dm-stripe: Invalid stripe count";
+		return -EINVAL;
+	}
+
+	chunk_size = simple_strtoul(argv[1], &end, 10);
+	if (*end) {
+		*context = "dm-stripe: Invalid chunk_size";
+		return -EINVAL;
+	}
+
+	if (l % stripes) {
+		*context = "dm-stripe: Target length not divisable by "
+		    "number of stripes";
+		return -EINVAL;
+	}
+
+	sc = alloc_context(stripes);
+	if (!sc) {
+		*context = "dm-stripe: Memory allocation for striped context "
+		    "failed";
+		return -ENOMEM;
+	}
+
+	sc->logical_start = b;
+	sc->stripes = stripes;
+	sc->stripe_width = l / stripes;
+
+	/*
+	 * chunk_size is a power of two
+	 */
+	if (!chunk_size || (chunk_size & (chunk_size - 1))) {
+		*context = "dm-stripe: Invalid chunk size";
+		kfree(sc);
+		return -EINVAL;
+	}
+
+	sc->chunk_mask = chunk_size - 1;
+	for (sc->chunk_shift = 0; chunk_size; sc->chunk_shift++)
+		chunk_size >>= 1;
+	sc->chunk_shift--;
+
+	/*
+	 * Get the stripe destinations.
+	 */
+	for (i = 0; i < stripes; i++) {
+		if (argc < 2) {
+			*context = "dm-stripe: Not enough destinations "
+			    "specified";
+			kfree(sc);
+			return -EINVAL;
+		}
+
+		argv += 2;
+
+		r = get_stripe(t, sc, i, argv);
+		if (r < 0) {
+			*context = "dm-stripe: Couldn't parse stripe "
+			    "destination";
+			while (i--)
+				dm_table_put_device(t, sc->stripe[i].dev);
+			kfree(sc);
+			return r;
+		}
+	}
+
+	*context = sc;
+	return 0;
+}
+
+static void stripe_dtr(struct dm_table *t, void *c)
+{
+	unsigned int i;
+	struct stripe_c *sc = (struct stripe_c *) c;
+
+	for (i = 0; i < sc->stripes; i++)
+		dm_table_put_device(t, sc->stripe[i].dev);
+
+	kfree(sc);
+}
+
+static int stripe_map(struct buffer_head *bh, int rw, void *context)
+{
+	struct stripe_c *sc = (struct stripe_c *) context;
+
+	offset_t offset = bh->b_rsector - sc->logical_start;
+	uint32_t chunk = (uint32_t) (offset >> sc->chunk_shift);
+	uint32_t stripe = chunk % sc->stripes;	/* 32bit modulus */
+	chunk = chunk / sc->stripes;
+
+	bh->b_rdev = sc->stripe[stripe].dev->dev;
+	bh->b_rsector = sc->stripe[stripe].physical_start +
+	    (chunk << sc->chunk_shift) + (offset & sc->chunk_mask);
+	return 1;
+}
+
+static int stripe_status(status_type_t type, char *result, int maxlen,
+			 void *context)
+{
+	struct stripe_c *sc = (struct stripe_c *) context;
+	int offset;
+	int i;
+
+	switch (type) {
+	case STATUSTYPE_INFO:
+		result[0] = '\0';
+		break;
+
+	case STATUSTYPE_TABLE:
+		offset = snprintf(result, maxlen, "%d %ld",
+				  sc->stripes, sc->chunk_mask + 1);
+		for (i = 0; i < sc->stripes; i++) {
+			offset +=
+			    snprintf(result + offset, maxlen - offset,
+				     " %s %ld",
+				     kdevname(sc->stripe[i].dev->dev),
+				     sc->stripe[i].physical_start);
+		}
+		break;
+	}
+	return 0;
+}
+
+static struct target_type stripe_target = {
+	name:	"striped",
+	module:	THIS_MODULE,
+	ctr:	stripe_ctr,
+	dtr:	stripe_dtr,
+	map:	stripe_map,
+	status:	stripe_status,
+};
+
+int __init dm_stripe_init(void)
+{
+	int r;
+
+	r = dm_register_target(&stripe_target);
+	if (r < 0)
+		DMWARN("striped target registration failed");
+
+	return r;
+}
+
+void dm_stripe_exit(void)
+{
+	if (dm_unregister_target(&stripe_target))
+		DMWARN("striped target unregistration failed");
+
+	return;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/md/dm-table.c linux.20pre10-ac2/drivers/md/dm-table.c
--- linux.20pre10/drivers/md/dm-table.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/md/dm-table.c	2002-08-12 22:45:52.000000000 +0100
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm.h"
+
+#include <linux/blkdev.h>
+
+/* ceiling(n / size) * size */
+static inline unsigned long round_up(unsigned long n, unsigned long size)
+{
+	unsigned long r = n % size;
+	return n + (r ? (size - r) : 0);
+}
+
+/* ceiling(n / size) */
+static inline unsigned long div_up(unsigned long n, unsigned long size)
+{
+	return round_up(n, size) / size;
+}
+
+/* similar to ceiling(log_size(n)) */
+static uint int_log(unsigned long n, unsigned long base)
+{
+	int result = 0;
+
+	while (n > 1) {
+		n = div_up(n, base);
+		result++;
+	}
+
+	return result;
+}
+
+/*
+ * return the highest key that you could lookup
+ * from the n'th node on level l of the btree.
+ */
+static offset_t high(struct dm_table *t, int l, int n)
+{
+	for (; l < t->depth - 1; l++)
+		n = get_child(n, CHILDREN_PER_NODE - 1);
+
+	if (n >= t->counts[l])
+		return (offset_t) - 1;
+
+	return get_node(t, l, n)[KEYS_PER_NODE - 1];
+}
+
+/*
+ * fills in a level of the btree based on the
+ * highs of the level below it.
+ */
+static int setup_btree_index(int l, struct dm_table *t)
+{
+	int n, k;
+	offset_t *node;
+
+	for (n = 0; n < t->counts[l]; n++) {
+		node = get_node(t, l, n);
+
+		for (k = 0; k < KEYS_PER_NODE; k++)
+			node[k] = high(t, l + 1, get_child(n, k));
+	}
+
+	return 0;
+}
+
+/*
+ * highs, and targets are managed as dynamic
+ * arrays during a table load.
+ */
+static int alloc_targets(struct dm_table *t, int num)
+{
+	offset_t *n_highs;
+	struct target *n_targets;
+	int n = t->num_targets;
+
+	/*
+	 * Allocate both the target array and offset array at once.
+	 */
+	n_highs = (offset_t *) vcalloc(sizeof(struct target) + sizeof(offset_t),
+				       num);
+	if (!n_highs)
+		return -ENOMEM;
+
+	n_targets = (struct target *) (n_highs + num);
+
+	if (n) {
+		memcpy(n_highs, t->highs, sizeof(*n_highs) * n);
+		memcpy(n_targets, t->targets, sizeof(*n_targets) * n);
+	}
+
+	memset(n_highs + n, -1, sizeof(*n_highs) * (num - n));
+	if (t->highs)
+		vfree(t->highs);
+
+	t->num_allocated = num;
+	t->highs = n_highs;
+	t->targets = n_targets;
+
+	return 0;
+}
+
+int dm_table_create(struct dm_table **result, int mode)
+{
+	struct dm_table *t = kmalloc(sizeof(*t), GFP_NOIO);
+
+	if (!t)
+		return -ENOMEM;
+
+	memset(t, 0, sizeof(*t));
+	INIT_LIST_HEAD(&t->devices);
+
+	/* allocate a single node's worth of targets to begin with */
+	if (alloc_targets(t, KEYS_PER_NODE)) {
+		kfree(t);
+		t = NULL;
+		return -ENOMEM;
+	}
+
+	init_waitqueue_head(&t->eventq);
+	t->mode = mode;
+	*result = t;
+	return 0;
+}
+
+static void free_devices(struct list_head *devices)
+{
+	struct list_head *tmp, *next;
+
+	for (tmp = devices->next; tmp != devices; tmp = next) {
+		struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
+		next = tmp->next;
+		kfree(dd);
+	}
+}
+
+void dm_table_destroy(struct dm_table *t)
+{
+	int i;
+
+	/* destroying the table counts as an event */
+	dm_table_event(t);
+
+	/* free the indexes (see dm_table_complete) */
+	if (t->depth >= 2)
+		vfree(t->index[t->depth - 2]);
+
+	/* free the targets */
+	for (i = 0; i < t->num_targets; i++) {
+		struct target *tgt = &t->targets[i];
+
+		dm_put_target_type(t->targets[i].type);
+
+		if (tgt->type->dtr)
+			tgt->type->dtr(t, tgt->private);
+	}
+
+	vfree(t->highs);
+
+	/* free the device list */
+	if (t->devices.next != &t->devices) {
+		DMWARN("devices still present during destroy: "
+		       "dm_table_remove_device calls missing");
+
+		free_devices(&t->devices);
+	}
+
+	kfree(t);
+}
+
+/*
+ * Checks to see if we need to extend highs or targets.
+ */
+static inline int check_space(struct dm_table *t)
+{
+	if (t->num_targets >= t->num_allocated)
+		return alloc_targets(t, t->num_allocated * 2);
+
+	return 0;
+}
+
+/*
+ * Convert a device path to a kdev_t.
+ */
+int lookup_device(const char *path, kdev_t *dev)
+{
+	int r;
+	struct nameidata nd;
+	struct inode *inode;
+
+	if (!path_init(path, LOOKUP_FOLLOW, &nd))
+		return 0;
+
+	if ((r = path_walk(path, &nd)))
+		goto bad;
+
+	inode = nd.dentry->d_inode;
+	if (!inode) {
+		r = -ENOENT;
+		goto bad;
+	}
+
+	if (!S_ISBLK(inode->i_mode)) {
+		r = -EINVAL;
+		goto bad;
+	}
+
+	*dev = inode->i_rdev;
+
+      bad:
+	path_release(&nd);
+	return r;
+}
+
+/*
+ * See if we've already got a device in the list.
+ */
+static struct dm_dev *find_device(struct list_head *l, kdev_t dev)
+{
+	struct list_head *tmp;
+
+	list_for_each(tmp, l) {
+		struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
+		if (dd->dev == dev)
+			return dd;
+	}
+
+	return NULL;
+}
+
+/*
+ * Open a device so we can use it as a map destination.
+ */
+static int open_dev(struct dm_dev *d)
+{
+	int err;
+
+	if (d->bd)
+		BUG();
+
+	if (!(d->bd = bdget(kdev_t_to_nr(d->dev))))
+		return -ENOMEM;
+
+	if ((err = blkdev_get(d->bd, d->mode, 0, BDEV_FILE)))
+			return err;
+
+	return 0;
+}
+
+/*
+ * Close a device that we've been using.
+ */
+static void close_dev(struct dm_dev *d)
+{
+	if (!d->bd)
+		return;
+
+	blkdev_put(d->bd, BDEV_FILE);
+	d->bd = NULL;
+}
+
+/*
+ * If possible (ie. blk_size[major] is set), this
+ * checks an area of a destination device is
+ * valid.
+ */
+static int check_device_area(kdev_t dev, offset_t start, offset_t len)
+{
+	int *sizes;
+	offset_t dev_size;
+
+	if (!(sizes = blk_size[MAJOR(dev)]) || !(dev_size = sizes[MINOR(dev)]))
+		/* we don't know the device details,
+		 * so give the benefit of the doubt */
+		return 1;
+
+	/* convert to 512-byte sectors */
+	dev_size <<= 1;
+
+	return ((start < dev_size) && (len <= (dev_size - start)));
+}
+
+/*
+ * This upgrades the mode on an already open dm_dev.  Being
+ * careful to leave things as they were if we fail to reopen the
+ * device.
+ */
+static int upgrade_mode(struct dm_dev *dd, int new_mode)
+{
+	int r;
+	struct dm_dev dd_copy;
+
+	memcpy(&dd_copy, dd, sizeof(dd_copy));
+
+	dd->mode |= new_mode;
+	dd->bd = NULL;
+	r = open_dev(dd);
+	if (!r)
+		close_dev(&dd_copy);
+	else
+		memcpy(dd, &dd_copy, sizeof(dd_copy));
+
+	return r;
+}
+
+/*
+ * Add a device to the list, or just increment the usage count
+ * if it's already present.
+ */
+int dm_table_get_device(struct dm_table *t, const char *path,
+			offset_t start, offset_t len, int mode,
+			struct dm_dev **result)
+{
+	int r;
+	kdev_t dev;
+	struct dm_dev *dd;
+	int major, minor;
+
+	if (sscanf(path, "%x:%x", &major, &minor) == 2) {
+		/* Extract the major/minor numbers */
+		dev = MKDEV(major, minor);
+	} else {
+		/* convert the path to a device */
+		if ((r = lookup_device(path, &dev)))
+			return r;
+	}
+
+	dd = find_device(&t->devices, dev);
+	if (!dd) {
+		dd = kmalloc(sizeof(*dd), GFP_KERNEL);
+		if (!dd)
+			return -ENOMEM;
+
+		dd->mode = mode;
+		dd->dev = dev;
+		dd->bd = NULL;
+
+		if ((r = open_dev(dd))) {
+			kfree(dd);
+			return r;
+		}
+
+		atomic_set(&dd->count, 0);
+		list_add(&dd->list, &t->devices);
+
+	} else if (dd->mode != (mode | dd->mode)) {
+		r = upgrade_mode(dd, mode);
+		if (r)
+			return r;
+	}
+	atomic_inc(&dd->count);
+
+	if (!check_device_area(dd->dev, start, len)) {
+		DMWARN("device %s too small for target", path);
+		dm_table_put_device(t, dd);
+		return -EINVAL;
+	}
+
+	*result = dd;
+
+	return 0;
+}
+
+/*
+ * Decrement a devices use count and remove it if neccessary.
+ */
+void dm_table_put_device(struct dm_table *t, struct dm_dev *dd)
+{
+	if (atomic_dec_and_test(&dd->count)) {
+		close_dev(dd);
+		list_del(&dd->list);
+		kfree(dd);
+	}
+}
+
+/*
+ * Adds a target to the map
+ */
+int dm_table_add_target(struct dm_table *t, offset_t highs,
+			struct target_type *type, void *private)
+{
+	int r, n;
+
+	if ((r = check_space(t)))
+		return r;
+
+	n = t->num_targets++;
+	t->highs[n] = highs;
+	t->targets[n].type = type;
+	t->targets[n].private = private;
+
+	return 0;
+}
+
+static int setup_indexes(struct dm_table *t)
+{
+	int i, total = 0;
+	offset_t *indexes;
+
+	/* allocate the space for *all* the indexes */
+	for (i = t->depth - 2; i >= 0; i--) {
+		t->counts[i] = div_up(t->counts[i + 1], CHILDREN_PER_NODE);
+		total += t->counts[i];
+	}
+
+	indexes = (offset_t *) vcalloc(total, (unsigned long) NODE_SIZE);
+	if (!indexes)
+		return -ENOMEM;
+
+	/* set up internal nodes, bottom-up */
+	for (i = t->depth - 2, total = 0; i >= 0; i--) {
+		t->index[i] = indexes;
+		indexes += (KEYS_PER_NODE * t->counts[i]);
+		setup_btree_index(i, t);
+	}
+
+	return 0;
+}
+
+/*
+ * Builds the btree to index the map
+ */
+int dm_table_complete(struct dm_table *t)
+{
+	int leaf_nodes, r = 0;
+
+	/* how many indexes will the btree have ? */
+	leaf_nodes = div_up(t->num_targets, KEYS_PER_NODE);
+	t->depth = 1 + int_log(leaf_nodes, CHILDREN_PER_NODE);
+
+	/* leaf layer has already been set up */
+	t->counts[t->depth - 1] = leaf_nodes;
+	t->index[t->depth - 1] = t->highs;
+
+	if (t->depth >= 2)
+		r = setup_indexes(t);
+
+	return r;
+}
+
+void dm_table_event(struct dm_table *t)
+{
+	wake_up_interruptible(&t->eventq);
+}
+
+EXPORT_SYMBOL(dm_table_get_device);
+EXPORT_SYMBOL(dm_table_put_device);
+EXPORT_SYMBOL(dm_table_event);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/md/dm-target.c linux.20pre10-ac2/drivers/md/dm-target.c
--- linux.20pre10/drivers/md/dm-target.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/md/dm-target.c	2002-08-12 22:42:29.000000000 +0100
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm.h"
+
+#include <linux/kmod.h>
+
+struct tt_internal {
+	struct target_type tt;
+
+	struct list_head list;
+	long use;
+};
+
+static LIST_HEAD(_targets);
+static rwlock_t _lock = RW_LOCK_UNLOCKED;
+
+#define DM_MOD_NAME_SIZE 32
+
+/*
+ * Destructively splits up the argument list to pass to ctr.
+ */
+int split_args(int max, int *argc, char **argv, char *input)
+{
+	char *start, *end = input, *out;
+	*argc = 0;
+
+	while (1) {
+		start = end;
+
+		/* Skip whitespace */
+		while (*start && isspace(*start))
+			start++;
+
+		if (!*start)
+			break;	/* success, we hit the end */
+
+		/* 'out' is used to remove any back-quotes */
+		end = out = start;
+		while (*end) {
+			/* Everything apart from '\0' can be quoted */
+			if (*end == '\\' && *(end + 1)) {
+				*out++ = *(end + 1);
+				end += 2;
+				continue;
+			}
+
+			if (isspace(*end))
+				break;	/* end of token */
+
+			*out++ = *end++;
+		}
+
+		/* have we already filled the array ? */
+		if ((*argc + 1) > max)
+			return -EINVAL;
+
+		/* we know this is whitespace */
+		if (*end)
+			end++;
+
+		/* terminate the string and put it in the array */
+		*out = '\0';
+		argv[*argc] = start;
+		(*argc)++;
+	}
+
+	return 0;
+}
+
+static inline struct tt_internal *__find_target_type(const char *name)
+{
+	struct list_head *tih;
+	struct tt_internal *ti;
+
+	list_for_each(tih, &_targets) {
+		ti = list_entry(tih, struct tt_internal, list);
+
+		if (!strcmp(name, ti->tt.name))
+			return ti;
+	}
+
+	return NULL;
+}
+
+static struct tt_internal *get_target_type(const char *name)
+{
+	struct tt_internal *ti;
+
+	read_lock(&_lock);
+	ti = __find_target_type(name);
+
+	if (ti) {
+		if (ti->use == 0 && ti->tt.module)
+			__MOD_INC_USE_COUNT(ti->tt.module);
+		ti->use++;
+	}
+	read_unlock(&_lock);
+
+	return ti;
+}
+
+static void load_module(const char *name)
+{
+	char module_name[DM_MOD_NAME_SIZE] = "dm-";
+
+	/* Length check for strcat() below */
+	if (strlen(name) > (DM_MOD_NAME_SIZE - 4))
+		return;
+
+	strcat(module_name, name);
+	request_module(module_name);
+
+	return;
+}
+
+struct target_type *dm_get_target_type(const char *name)
+{
+	struct tt_internal *ti = get_target_type(name);
+
+	if (!ti) {
+		load_module(name);
+		ti = get_target_type(name);
+	}
+
+	return ti ? &ti->tt : NULL;
+}
+
+void dm_put_target_type(struct target_type *t)
+{
+	struct tt_internal *ti = (struct tt_internal *) t;
+
+	read_lock(&_lock);
+	if (--ti->use == 0 && ti->tt.module)
+		__MOD_DEC_USE_COUNT(ti->tt.module);
+
+	if (ti->use < 0)
+		BUG();
+	read_unlock(&_lock);
+
+	return;
+}
+
+static struct tt_internal *alloc_target(struct target_type *t)
+{
+	struct tt_internal *ti = kmalloc(sizeof(*ti), GFP_KERNEL);
+
+	if (ti) {
+		memset(ti, 0, sizeof(*ti));
+		ti->tt = *t;
+	}
+
+	return ti;
+}
+
+int dm_register_target(struct target_type *t)
+{
+	int rv = 0;
+	struct tt_internal *ti = alloc_target(t);
+
+	if (!ti)
+		return -ENOMEM;
+
+	write_lock(&_lock);
+	if (__find_target_type(t->name))
+		rv = -EEXIST;
+	else
+		list_add(&ti->list, &_targets);
+
+	write_unlock(&_lock);
+	return rv;
+}
+
+int dm_unregister_target(struct target_type *t)
+{
+	struct tt_internal *ti;
+
+	write_lock(&_lock);
+	if (!(ti = __find_target_type(t->name))) {
+		write_unlock(&_lock);
+		return -EINVAL;
+	}
+
+	if (ti->use) {
+		write_unlock(&_lock);
+		return -ETXTBSY;
+	}
+
+	list_del(&ti->list);
+	kfree(ti);
+
+	write_unlock(&_lock);
+	return 0;
+}
+
+/*
+ * io-err: always fails an io, useful for bringing
+ * up LV's that have holes in them.
+ */
+static int io_err_ctr(struct dm_table *t, offset_t b, offset_t l,
+		      int argc, char **args, void **context)
+{
+	*context = NULL;
+	return 0;
+}
+
+static void io_err_dtr(struct dm_table *t, void *c)
+{
+	/* empty */
+	return;
+}
+
+static int io_err_map(struct buffer_head *bh, int rw, void *context)
+{
+	buffer_IO_error(bh);
+	return 0;
+}
+
+static struct target_type error_target = {
+	name:	"error",
+	ctr:	io_err_ctr,
+	dtr:	io_err_dtr,
+	map:	io_err_map,
+	status:	NULL,
+};
+
+int dm_target_init(void)
+{
+	return dm_register_target(&error_target);
+}
+
+void dm_target_exit(void)
+{
+	if (dm_unregister_target(&error_target))
+		DMWARN("error target unregistration failed");
+}
+
+EXPORT_SYMBOL(dm_register_target);
+EXPORT_SYMBOL(dm_unregister_target);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/md/kcopyd.c linux.20pre10-ac2/drivers/md/kcopyd.c
--- linux.20pre10/drivers/md/kcopyd.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/md/kcopyd.c	2002-08-12 22:46:01.000000000 +0100
@@ -0,0 +1,841 @@
+/*
+ * Copyright (C) 2002 Sistina Software (UK) Limited.
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/blkdev.h>
+#include <linux/device-mapper.h>
+#include <linux/mempool.h>
+#include <asm/atomic.h>
+#include <linux/pagemap.h>
+#include <linux/locks.h>
+
+#include "kcopyd.h"
+
+/* FIXME: this is only needed for the DMERR macros */
+#include "dm.h"
+
+/*
+ * Hard sector size used all over the kernel.
+ */
+#define SECTOR_SIZE 512
+#define SECTOR_SHIFT 9
+
+static void wake_kcopyd(void);
+
+/*-----------------------------------------------------------------
+ * We reserve our own pool of preallocated pages that are
+ * only used for kcopyd io.
+ *---------------------------------------------------------------*/
+
+/*
+ * FIXME: This should be configurable.
+ */
+#define NUM_PAGES 512
+
+static DECLARE_MUTEX(_pages_lock);
+static int _num_free_pages;
+static struct page *_pages_array[NUM_PAGES];
+static DECLARE_MUTEX(start_lock);
+
+static int init_pages(void)
+{
+	int i;
+	struct page *p;
+
+	for (i = 0; i < NUM_PAGES; i++) {
+		p = alloc_page(GFP_KERNEL);
+		if (!p)
+			goto bad;
+
+		LockPage(p);
+		_pages_array[i] = p;
+	}
+
+	_num_free_pages = NUM_PAGES;
+	return 0;
+
+      bad:
+	while (i--)
+		__free_page(_pages_array[i]);
+	return -ENOMEM;
+}
+
+static void exit_pages(void)
+{
+	int i;
+	struct page *p;
+
+	for (i = 0; i < NUM_PAGES; i++) {
+		p = _pages_array[i];
+		UnlockPage(p);
+		__free_page(p);
+	}
+
+	_num_free_pages = 0;
+}
+
+static int kcopyd_get_pages(int num, struct page **result)
+{
+	int i;
+
+	down(&_pages_lock);
+	if (_num_free_pages < num) {
+		up(&_pages_lock);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < num; i++) {
+		_num_free_pages--;
+		result[i] = _pages_array[_num_free_pages];
+	}
+	up(&_pages_lock);
+
+	return 0;
+}
+
+static void kcopyd_free_pages(int num, struct page **result)
+{
+	int i;
+
+	down(&_pages_lock);
+	for (i = 0; i < num; i++)
+		_pages_array[_num_free_pages++] = result[i];
+	up(&_pages_lock);
+}
+
+/*-----------------------------------------------------------------
+ * We keep our own private pool of buffer_heads.  These are just
+ * held in a list on the b_reqnext field.
+ *---------------------------------------------------------------*/
+
+/*
+ * Make sure we have enough buffers to always keep the pages
+ * occupied.  So we assume the worst case scenario where blocks
+ * are the size of a single sector.
+ */
+#define NUM_BUFFERS NUM_PAGES * (PAGE_SIZE / SECTOR_SIZE)
+
+static spinlock_t _buffer_lock = SPIN_LOCK_UNLOCKED;
+static struct buffer_head *_all_buffers;
+static struct buffer_head *_free_buffers;
+
+static int init_buffers(void)
+{
+	int i;
+	struct buffer_head *buffers;
+
+	buffers = vcalloc(NUM_BUFFERS, sizeof(struct buffer_head));
+	if (!buffers) {
+		DMWARN("Couldn't allocate buffer heads.");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < NUM_BUFFERS; i++) {
+		if (i < NUM_BUFFERS - 1)
+			buffers[i].b_reqnext = &buffers[i + 1];
+		init_waitqueue_head(&buffers[i].b_wait);
+		INIT_LIST_HEAD(&buffers[i].b_inode_buffers);
+	}
+
+	_all_buffers = _free_buffers = buffers;
+	return 0;
+}
+
+static void exit_buffers(void)
+{
+	vfree(_all_buffers);
+}
+
+static struct buffer_head *alloc_buffer(void)
+{
+	struct buffer_head *r;
+	int flags;
+
+	spin_lock_irqsave(&_buffer_lock, flags);
+
+	if (!_free_buffers)
+		r = NULL;
+	else {
+		r = _free_buffers;
+		_free_buffers = _free_buffers->b_reqnext;
+		r->b_reqnext = NULL;
+	}
+
+	spin_unlock_irqrestore(&_buffer_lock, flags);
+
+	return r;
+}
+
+/*
+ * Only called from interrupt context.
+ */
+static void free_buffer(struct buffer_head *bh)
+{
+	int flags, was_empty;
+
+	spin_lock_irqsave(&_buffer_lock, flags);
+	was_empty = (_free_buffers == NULL) ? 1 : 0;
+	bh->b_reqnext = _free_buffers;
+	_free_buffers = bh;
+	spin_unlock_irqrestore(&_buffer_lock, flags);
+
+	/*
+	 * If the buffer list was empty then kcopyd probably went
+	 * to sleep because it ran out of buffer heads, so let's
+	 * wake it up.
+	 */
+	if (was_empty)
+		wake_kcopyd();
+}
+
+/*-----------------------------------------------------------------
+ * kcopyd_jobs need to be allocated by the *clients* of kcopyd,
+ * for this reason we use a mempool to prevent the client from
+ * ever having to do io (which could cause a
+ * deadlock).
+ *---------------------------------------------------------------*/
+#define MIN_JOBS NUM_PAGES
+
+static kmem_cache_t *_job_cache = NULL;
+static mempool_t *_job_pool = NULL;
+
+/*
+ * We maintain three lists of jobs:
+ *
+ * i)   jobs waiting for pages
+ * ii)  jobs that have pages, and are waiting for the io to be issued.
+ * iii) jobs that have completed.
+ *
+ * All three of these are protected by job_lock.
+ */
+
+static spinlock_t _job_lock = SPIN_LOCK_UNLOCKED;
+
+static LIST_HEAD(_complete_jobs);
+static LIST_HEAD(_io_jobs);
+static LIST_HEAD(_pages_jobs);
+
+static int init_jobs(void)
+{
+	INIT_LIST_HEAD(&_complete_jobs);
+	INIT_LIST_HEAD(&_io_jobs);
+	INIT_LIST_HEAD(&_pages_jobs);
+
+	_job_cache = kmem_cache_create("kcopyd-jobs", sizeof(struct kcopyd_job),
+				       __alignof__(struct kcopyd_job),
+				       0, NULL, NULL);
+	if (!_job_cache)
+		return -ENOMEM;
+
+	_job_pool = mempool_create(MIN_JOBS, mempool_alloc_slab,
+				   mempool_free_slab, _job_cache);
+	if (!_job_pool) {
+		kmem_cache_destroy(_job_cache);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void exit_jobs(void)
+{
+	mempool_destroy(_job_pool);
+	kmem_cache_destroy(_job_cache);
+}
+
+struct kcopyd_job *kcopyd_alloc_job(void)
+{
+	struct kcopyd_job *job;
+
+	job = mempool_alloc(_job_pool, GFP_KERNEL);
+	if (!job)
+		return NULL;
+
+	memset(job, 0, sizeof(*job));
+	return job;
+}
+
+void kcopyd_free_job(struct kcopyd_job *job)
+{
+	mempool_free(job, _job_pool);
+}
+
+/*
+ * Functions to push and pop a job onto the head of a given job
+ * list.
+ */
+static inline struct kcopyd_job *pop(struct list_head *jobs)
+{
+	struct kcopyd_job *job = NULL;
+	int flags;
+
+	spin_lock_irqsave(&_job_lock, flags);
+
+	if (!list_empty(jobs)) {
+		job = list_entry(jobs->next, struct kcopyd_job, list);
+		list_del(&job->list);
+	}
+	spin_unlock_irqrestore(&_job_lock, flags);
+
+	return job;
+}
+
+static inline void push(struct list_head *jobs, struct kcopyd_job *job)
+{
+	int flags;
+
+	spin_lock_irqsave(&_job_lock, flags);
+	list_add(&job->list, jobs);
+	spin_unlock_irqrestore(&_job_lock, flags);
+}
+
+/*
+ * Completion function for one of our buffers.
+ */
+static void end_bh(struct buffer_head *bh, int uptodate)
+{
+	struct kcopyd_job *job = bh->b_private;
+
+	mark_buffer_uptodate(bh, uptodate);
+	unlock_buffer(bh);
+
+	if (!uptodate)
+		job->err = -EIO;
+
+	/* are we the last ? */
+	if (atomic_dec_and_test(&job->nr_incomplete)) {
+		push(&_complete_jobs, job);
+		wake_kcopyd();
+	}
+
+	free_buffer(bh);
+}
+
+static void dispatch_bh(struct kcopyd_job *job,
+			struct buffer_head *bh, int block)
+{
+	int p;
+
+	/*
+	 * Add in the job offset
+	 */
+	bh->b_blocknr = (job->disk.sector >> job->block_shift) + block;
+
+	p = block >> job->bpp_shift;
+	block &= job->bpp_mask;
+
+	bh->b_dev = B_FREE;
+	bh->b_size = job->block_size;
+	set_bh_page(bh, job->pages[p], ((block << job->block_shift) +
+					job->offset) << SECTOR_SHIFT);
+	bh->b_this_page = bh;
+
+	init_buffer(bh, end_bh, job);
+
+	bh->b_dev = job->disk.dev;
+	bh->b_state = ((1 << BH_Mapped) | (1 << BH_Lock) | (1 << BH_Req));
+
+	set_bit(BH_Uptodate, &bh->b_state);
+	if (job->rw == WRITE)
+		clear_bit(BH_Dirty, &bh->b_state);
+
+	submit_bh(job->rw, bh);
+}
+
+/*
+ * These three functions process 1 item from the corresponding
+ * job list.
+ *
+ * They return:
+ * < 0: error
+ *   0: success
+ * > 0: can't process yet.
+ */
+static int run_complete_job(struct kcopyd_job *job)
+{
+	job->callback(job);
+	return 0;
+}
+
+/*
+ * Request io on as many buffer heads as we can currently get for
+ * a particular job.
+ */
+static int run_io_job(struct kcopyd_job *job)
+{
+	unsigned int block;
+	struct buffer_head *bh;
+
+	for (block = atomic_read(&job->nr_requested);
+	     block < job->nr_blocks; block++) {
+		bh = alloc_buffer();
+		if (!bh)
+			break;
+
+		atomic_inc(&job->nr_requested);
+		dispatch_bh(job, bh, block);
+	}
+
+	return (block == job->nr_blocks) ? 0 : 1;
+}
+
+static int run_pages_job(struct kcopyd_job *job)
+{
+	int r;
+
+	job->nr_pages = (job->disk.count + job->offset) /
+	    (PAGE_SIZE / SECTOR_SIZE);
+	r = kcopyd_get_pages(job->nr_pages, job->pages);
+
+	if (!r) {
+		/* this job is ready for io */
+		push(&_io_jobs, job);
+		return 0;
+	}
+
+	if (r == -ENOMEM)
+		/* can complete now */
+		return 1;
+
+	return r;
+}
+
+/*
+ * Run through a list for as long as possible.  Returns the count
+ * of successful jobs.
+ */
+static int process_jobs(struct list_head *jobs, int (*fn) (struct kcopyd_job *))
+{
+	struct kcopyd_job *job;
+	int r, count = 0;
+
+	while ((job = pop(jobs))) {
+
+		r = fn(job);
+
+		if (r < 0) {
+			/* error this rogue job */
+			job->err = r;
+			push(&_complete_jobs, job);
+			break;
+		}
+
+		if (r > 0) {
+			/*
+			 * We couldn't service this job ATM, so
+			 * push this job back onto the list.
+			 */
+			push(jobs, job);
+			break;
+		}
+
+		count++;
+	}
+
+	return count;
+}
+
+/*
+ * kcopyd does this every time it's woken up.
+ */
+static void do_work(void)
+{
+	int count;
+
+	/*
+	 * We loop round until there is no more work to do.
+	 */
+	do {
+		count = process_jobs(&_complete_jobs, run_complete_job);
+		count += process_jobs(&_io_jobs, run_io_job);
+		count += process_jobs(&_pages_jobs, run_pages_job);
+
+	} while (count);
+
+	run_task_queue(&tq_disk);
+}
+
+/*-----------------------------------------------------------------
+ * The daemon
+ *---------------------------------------------------------------*/
+static atomic_t _kcopyd_must_die;
+static DECLARE_MUTEX(_run_lock);
+static DECLARE_WAIT_QUEUE_HEAD(_job_queue);
+
+static int kcopyd(void *arg)
+{
+	DECLARE_WAITQUEUE(wq, current);
+
+	daemonize();
+	strcpy(current->comm, "kcopyd");
+	atomic_set(&_kcopyd_must_die, 0);
+
+	add_wait_queue(&_job_queue, &wq);
+
+	down(&_run_lock);
+	up(&start_lock);
+
+	while (1) {
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		if (atomic_read(&_kcopyd_must_die))
+			break;
+
+		do_work();
+		schedule();
+	}
+
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&_job_queue, &wq);
+
+	up(&_run_lock);
+
+	return 0;
+}
+
+static int start_daemon(void)
+{
+	static pid_t pid = 0;
+
+	down(&start_lock);
+
+	pid = kernel_thread(kcopyd, NULL, 0);
+	if (pid <= 0) {
+		DMERR("Failed to start kcopyd thread");
+		return -EAGAIN;
+	}
+
+	/*
+	 * wait for the daemon to up this mutex.
+	 */
+	down(&start_lock);
+	up(&start_lock);
+
+	return 0;
+}
+
+static int stop_daemon(void)
+{
+	atomic_set(&_kcopyd_must_die, 1);
+	wake_kcopyd();
+	down(&_run_lock);
+	up(&_run_lock);
+
+	return 0;
+}
+
+static void wake_kcopyd(void)
+{
+	wake_up_interruptible(&_job_queue);
+}
+
+static int calc_shift(unsigned int n)
+{
+	int s;
+
+	for (s = 0; n; s++, n >>= 1)
+		;
+
+	return --s;
+}
+
+static void calc_block_sizes(struct kcopyd_job *job)
+{
+	job->block_size = get_hardsect_size(job->disk.dev);
+	job->block_shift = calc_shift(job->block_size / SECTOR_SIZE);
+	job->bpp_shift = PAGE_SHIFT - job->block_shift - SECTOR_SHIFT;
+	job->bpp_mask = (1 << job->bpp_shift) - 1;
+	job->nr_blocks = job->disk.count >> job->block_shift;
+	atomic_set(&job->nr_requested, 0);
+	atomic_set(&job->nr_incomplete, job->nr_blocks);
+}
+
+int kcopyd_io(struct kcopyd_job *job)
+{
+	calc_block_sizes(job);
+	push(job->pages[0] ? &_io_jobs : &_pages_jobs, job);
+	wake_kcopyd();
+	return 0;
+}
+
+/*-----------------------------------------------------------------
+ * The copier is implemented on top of the simpler async io
+ * daemon above.
+ *---------------------------------------------------------------*/
+struct copy_info {
+	kcopyd_notify_fn notify;
+	void *notify_context;
+
+	struct kcopyd_region to;
+};
+
+#define MIN_INFOS 128
+static kmem_cache_t *_copy_cache = NULL;
+static mempool_t *_copy_pool = NULL;
+
+static int init_copier(void)
+{
+	_copy_cache = kmem_cache_create("kcopyd-info",
+					sizeof(struct copy_info),
+					__alignof__(struct copy_info),
+					0, NULL, NULL);
+	if (!_copy_cache)
+		return -ENOMEM;
+
+	_copy_pool = mempool_create(MIN_INFOS, mempool_alloc_slab,
+				    mempool_free_slab, _copy_cache);
+	if (!_copy_pool) {
+		kmem_cache_destroy(_copy_cache);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void exit_copier(void)
+{
+	if (_copy_pool)
+		mempool_destroy(_copy_pool);
+
+	if (_copy_cache)
+		kmem_cache_destroy(_copy_cache);
+}
+
+static inline struct copy_info *alloc_copy_info(void)
+{
+	return mempool_alloc(_copy_pool, GFP_KERNEL);
+}
+
+static inline void free_copy_info(struct copy_info *info)
+{
+	mempool_free(info, _copy_pool);
+}
+
+void copy_complete(struct kcopyd_job *job)
+{
+	struct copy_info *info = (struct copy_info *) job->context;
+
+	if (info->notify)
+		info->notify(job->err, info->notify_context);
+
+	free_copy_info(info);
+
+	kcopyd_free_pages(job->nr_pages, job->pages);
+
+	kcopyd_free_job(job);
+}
+
+static void page_write_complete(struct kcopyd_job *job)
+{
+	struct copy_info *info = (struct copy_info *) job->context;
+	int i;
+
+	if (info->notify)
+		info->notify(job->err, info->notify_context);
+
+	free_copy_info(info);
+	for (i = 0; i < job->nr_pages; i++)
+		put_page(job->pages[i]);
+
+	kcopyd_free_job(job);
+}
+
+/*
+ * These callback functions implement the state machine that copies regions.
+ */
+void copy_write(struct kcopyd_job *job)
+{
+	struct copy_info *info = (struct copy_info *) job->context;
+
+	if (job->err && info->notify) {
+		info->notify(job->err, job->context);
+		kcopyd_free_job(job);
+		free_copy_info(info);
+		return;
+	}
+
+	job->rw = WRITE;
+	memcpy(&job->disk, &info->to, sizeof(job->disk));
+	job->callback = copy_complete;
+	job->context = info;
+
+	/*
+	 * Queue the write.
+	 */
+	kcopyd_io(job);
+}
+
+int kcopyd_write_pages(struct kcopyd_region *to, int nr_pages,
+		       struct page **pages, int offset, kcopyd_notify_fn fn,
+		       void *context)
+{
+	struct copy_info *info;
+	struct kcopyd_job *job;
+	int i;
+
+	/*
+	 * Allocate a new copy_info.
+	 */
+	info = alloc_copy_info();
+	if (!info)
+		return -ENOMEM;
+
+	job = kcopyd_alloc_job();
+	if (!job) {
+		free_copy_info(info);
+		return -ENOMEM;
+	}
+
+	/*
+	 * set up for the write.
+	 */
+	info->notify = fn;
+	info->notify_context = context;
+	memcpy(&info->to, to, sizeof(*to));
+
+	/* Get the pages */
+	job->nr_pages = nr_pages;
+	for (i = 0; i < nr_pages; i++) {
+		get_page(pages[i]);
+		job->pages[i] = pages[i];
+	}
+
+	job->rw = WRITE;
+
+	memcpy(&job->disk, &info->to, sizeof(job->disk));
+	job->offset = offset;
+	calc_block_sizes(job);
+	job->callback = page_write_complete;
+	job->context = info;
+
+	/*
+	 * Trigger job.
+	 */
+	kcopyd_io(job);
+	return 0;
+}
+
+int kcopyd_copy(struct kcopyd_region *from, struct kcopyd_region *to,
+		kcopyd_notify_fn fn, void *context)
+{
+	struct copy_info *info;
+	struct kcopyd_job *job;
+
+	/*
+	 * Allocate a new copy_info.
+	 */
+	info = alloc_copy_info();
+	if (!info)
+		return -ENOMEM;
+
+	job = kcopyd_alloc_job();
+	if (!job) {
+		free_copy_info(info);
+		return -ENOMEM;
+	}
+
+	/*
+	 * set up for the read.
+	 */
+	info->notify = fn;
+	info->notify_context = context;
+	memcpy(&info->to, to, sizeof(*to));
+
+	job->rw = READ;
+	memcpy(&job->disk, from, sizeof(*from));
+
+	job->offset = 0;
+	calc_block_sizes(job);
+	job->callback = copy_write;
+	job->context = info;
+
+	/*
+	 * Trigger job.
+	 */
+	kcopyd_io(job);
+	return 0;
+}
+
+/*-----------------------------------------------------------------
+ * Unit setup
+ *---------------------------------------------------------------*/
+static struct {
+	int (*init) (void);
+	void (*exit) (void);
+
+} _inits[] = {
+#define xx(n) { init_ ## n, exit_ ## n}
+	xx(pages),
+	xx(buffers),
+	xx(jobs),
+	xx(copier)
+#undef xx
+};
+
+static int _client_count = 0;
+static DECLARE_MUTEX(_client_count_sem);
+
+static int kcopyd_init(void)
+{
+	const int count = sizeof(_inits) / sizeof(*_inits);
+
+	int r, i;
+
+	for (i = 0; i < count; i++) {
+		r = _inits[i].init();
+		if (r)
+			goto bad;
+	}
+
+	start_daemon();
+	return 0;
+
+      bad:
+	while (i--)
+		_inits[i].exit();
+
+	return r;
+}
+
+static void kcopyd_exit(void)
+{
+	int i = sizeof(_inits) / sizeof(*_inits);
+
+	if (stop_daemon())
+		DMWARN("Couldn't stop kcopyd.");
+
+	while (i--)
+		_inits[i].exit();
+}
+
+void kcopyd_inc_client_count(void)
+{
+	/*
+	 * What I need here is an atomic_test_and_inc that returns
+	 * the previous value of the atomic...  In its absence I lock
+	 * an int with a semaphore. :-(
+	 */
+	down(&_client_count_sem);
+	if (_client_count == 0)
+		kcopyd_init();
+	_client_count++;
+
+	up(&_client_count_sem);
+}
+
+void kcopyd_dec_client_count(void)
+{
+	down(&_client_count_sem);
+	if (--_client_count == 0)
+		kcopyd_exit();
+
+	up(&_client_count_sem);
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/md/kcopyd.h linux.20pre10-ac2/drivers/md/kcopyd.h
--- linux.20pre10/drivers/md/kcopyd.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/md/kcopyd.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2001 Sistina Software
+ *
+ * This file is released under the GPL.
+ */
+
+#ifndef DM_KCOPYD_H
+#define DM_KCOPYD_H
+
+/*
+ * Needed for the definition of offset_t.
+ */
+#include <linux/device-mapper.h>
+#include <linux/iobuf.h>
+
+struct kcopyd_region {
+	kdev_t dev;
+	offset_t sector;
+	offset_t count;
+};
+
+#define MAX_KCOPYD_PAGES 128
+
+struct kcopyd_job {
+	struct list_head list;
+
+	/*
+	 * Error state of the job.
+	 */
+	int err;
+
+	/*
+	 * Either READ or WRITE
+	 */
+	int rw;
+
+	/*
+	 * The source or destination for the transfer.
+	 */
+	struct kcopyd_region disk;
+
+	int nr_pages;
+	struct page *pages[MAX_KCOPYD_PAGES];
+
+	/*
+	 * Shifts and masks that will be useful when dispatching
+	 * each buffer_head.
+	 */
+	offset_t offset;
+	offset_t block_size;
+	offset_t block_shift;
+	offset_t bpp_shift;	/* blocks per page */
+	offset_t bpp_mask;
+
+	/*
+	 * nr_blocks is how many buffer heads will have to be
+	 * displatched to service this job, nr_requested is how
+	 * many have been dispatched and nr_complete is how many
+	 * have come back.
+	 */
+	unsigned int nr_blocks;
+	atomic_t nr_requested;
+	atomic_t nr_incomplete;
+
+	/*
+	 * Set this to ensure you are notified when the job has
+	 * completed.  'context' is for callback to use.
+	 */
+	void (*callback)(struct kcopyd_job *job);
+	void *context;
+};
+
+/*
+ * Low level async io routines.
+ */
+struct kcopyd_job *kcopyd_alloc_job(void);
+void kcopyd_free_job(struct kcopyd_job *job);
+
+int kcopyd_queue_job(struct kcopyd_job *job);
+
+/*
+ * Submit a copy job to kcopyd.  This is built on top of the
+ * previous three fns.
+ */
+typedef void (*kcopyd_notify_fn)(int err, void *context);
+
+int kcopyd_copy(struct kcopyd_region *from, struct kcopyd_region *to,
+		kcopyd_notify_fn fn, void *context);
+
+int kcopyd_write_pages(struct kcopyd_region *to, int nr_pages,
+		       struct page **pages, int offset, kcopyd_notify_fn fn,
+		       void *context);
+
+/*
+ * We only want kcopyd to reserve resources if someone is
+ * actually using it.
+ */
+void kcopyd_inc_client_count(void);
+void kcopyd_dec_client_count(void);
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/md/Makefile linux.20pre10-ac2/drivers/md/Makefile
--- linux.20pre10/drivers/md/Makefile	2002-10-09 21:36:57.000000000 +0100
+++ linux.20pre10-ac2/drivers/md/Makefile	2002-08-12 22:44:36.000000000 +0100
@@ -4,9 +4,11 @@
 
 O_TARGET	:= mddev.o
 
-export-objs	:= md.o xor.o
+export-objs	:= md.o xor.o dm-table.o dm-target.o kcopyd.o
 list-multi	:= lvm-mod.o
 lvm-mod-objs	:= lvm.o lvm-snap.o lvm-fs.o
+dm-mod-objs	:= dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \
+		   dm-ioctl.o dm-snapshot.o dm-exception-store.o kcopyd.o
 
 # Note: link order is important.  All raid personalities
 # and xor.o must come before md.o, as they each initialise 
@@ -20,8 +22,12 @@
 obj-$(CONFIG_MD_MULTIPATH)	+= multipath.o
 obj-$(CONFIG_BLK_DEV_MD)	+= md.o
 obj-$(CONFIG_BLK_DEV_LVM)	+= lvm-mod.o
+obj-$(CONFIG_BLK_DEV_DM)	+= dm-mod.o
 
 include $(TOPDIR)/Rules.make
 
 lvm-mod.o: $(lvm-mod-objs)
 	$(LD) -r -o $@ $(lvm-mod-objs)
+
+dm-mod.o: $(dm-mod-objs)
+	$(LD) -r -o $@ $(dm-mod-objs)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/md/md.c linux.20pre10-ac2/drivers/md/md.c
--- linux.20pre10/drivers/md/md.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/md/md.c	2002-09-30 17:33:02.000000000 +0100
@@ -77,7 +77,7 @@
  */
 
 static int sysctl_speed_limit_min = 100;
-static int sysctl_speed_limit_max = 100000;
+static int sysctl_speed_limit_max = 10000;
 
 static struct ctl_table_header *raid_table_header;
 
@@ -2936,8 +2936,6 @@
 	 * bdflush, otherwise bdflush will deadlock if there are too
 	 * many dirty RAID5 blocks.
 	 */
-	current->policy = SCHED_OTHER;
-	current->nice = -20;
 	md_unlock_kernel();
 
 	complete(thread->event);
@@ -3391,11 +3389,6 @@
 	       "(but not more than %d KB/sec) for reconstruction.\n",
 	       sysctl_speed_limit_max);
 
-	/*
-	 * Resync has low priority.
-	 */
-	current->nice = 19;
-
 	is_mddev_idle(mddev); /* this also initializes IO event counters */
 	for (m = 0; m < SYNC_MARKS; m++) {
 		mark[m] = jiffies;
@@ -3473,16 +3466,13 @@
 		currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
 
 		if (currspeed > sysctl_speed_limit_min) {
-			current->nice = 19;
-
 			if ((currspeed > sysctl_speed_limit_max) ||
 					!is_mddev_idle(mddev)) {
 				current->state = TASK_INTERRUPTIBLE;
 				md_schedule_timeout(HZ/4);
 				goto repeat;
 			}
-		} else
-			current->nice = -20;
+		}
 	}
 	printk(KERN_INFO "md: md%d: sync done.\n",mdidx(mddev));
 	err = 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/media/video/Makefile linux.20pre10-ac2/drivers/media/video/Makefile
--- linux.20pre10/drivers/media/video/Makefile	2002-10-09 21:36:56.000000000 +0100
+++ linux.20pre10-ac2/drivers/media/video/Makefile	2002-09-27 14:07:56.000000000 +0100
@@ -1,5 +1,5 @@
 #
-# Makefile for the kernel character device drivers.
+# Makefile for the video capture/playback device drivers.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
 # removes any old dependencies. DON'T put your own dependencies here
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/media/video/meye.c linux.20pre10-ac2/drivers/media/video/meye.c
--- linux.20pre10/drivers/media/video/meye.c	2002-10-09 21:36:56.000000000 +0100
+++ linux.20pre10-ac2/drivers/media/video/meye.c	2002-09-29 21:34:25.000000000 +0100
@@ -861,7 +861,7 @@
 
 		mchip_free_frame();
 	}
-out:
+out: ;
 }
 
 /****************************************************************************/
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/mtd/maps/Config.in linux.20pre10-ac2/drivers/mtd/maps/Config.in
--- linux.20pre10/drivers/mtd/maps/Config.in	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/mtd/maps/Config.in	2002-10-10 23:56:47.000000000 +0100
@@ -30,6 +30,7 @@
    dep_tristate '  JEDEC Flash device mapped on Mixcom piggyback card' CONFIG_MTD_MIXMEM $CONFIG_MTD_JEDEC
    dep_tristate '  JEDEC Flash device mapped on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC
    dep_tristate '  JEDEC Flash device mapped on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC
+   dep_tristate '  Flash device mapped with DOCCS on NatSemi SCx200' CONFIG_MTD_SCx200_DOCFLASH $CONFIG_MTD_CFI
    dep_tristate '  BIOS flash chip on Intel L440GX boards' CONFIG_MTD_L440GX $CONFIG_MTD_JEDECPROBE
    dep_tristate ' ROM connected to AMD766 southbridge' CONFIG_MTD_AMD766ROM $CONFIG_MTD_GEN_PROBE   
    dep_tristate ' ROM connected to Intel Hub Controller 2' CONFIG_MTD_ICH2ROM $CONFIG_MTD_JEDECPROBE
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/mtd/maps/Makefile linux.20pre10-ac2/drivers/mtd/maps/Makefile
--- linux.20pre10/drivers/mtd/maps/Makefile	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/mtd/maps/Makefile	2002-10-10 23:56:47.000000000 +0100
@@ -32,6 +32,7 @@
 obj-$(CONFIG_MTD_NETSC520)	+= netsc520.o
 obj-$(CONFIG_MTD_SUN_UFLASH)    += sun_uflash.o
 obj-$(CONFIG_MTD_VMAX)		+= vmax301.o
+obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o
 obj-$(CONFIG_MTD_DBOX2)		+= dbox2-flash.o
 obj-$(CONFIG_MTD_OCELOT)	+= ocelot.o
 obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/mtd/maps/scx200_docflash.c linux.20pre10-ac2/drivers/mtd/maps/scx200_docflash.c
--- linux.20pre10/drivers/mtd/maps/scx200_docflash.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/mtd/maps/scx200_docflash.c	2002-10-10 23:56:47.000000000 +0100
@@ -0,0 +1,268 @@
+/* linux/drivers/mtd/maps/scx200_docflash.c 
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   National Semiconductor SCx200 flash mapped with DOCCS
+*/
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <linux/pci.h>
+#include <linux/scx200.h>
+
+#define NAME "scx200_docflash"
+
+MODULE_AUTHOR("Christer Weinigel <wingel@hack.org>");
+MODULE_DESCRIPTION("NatSemi SCx200 DOCCS Flash Driver");
+MODULE_LICENSE("GPL");
+
+/* Set this to one if you want to partition the flash */
+#define PARTITION 1
+
+MODULE_PARM(probe, "i");
+MODULE_PARM_DESC(probe, "Probe for a BIOS mapping");
+MODULE_PARM(size, "i");
+MODULE_PARM_DESC(size, "Size of the flash mapping");
+MODULE_PARM(width, "i");
+MODULE_PARM_DESC(width, "Data width of the flash mapping (8/16)");
+MODULE_PARM(flashtype, "s");
+MODULE_PARM_DESC(flashtype, "Type of MTD probe to do");
+
+static int probe = 0;		/* Don't autoprobe */
+static unsigned size = 0x1000000; /* 16 MB the whole ISA address space */
+static unsigned width = 8;	/* Default to 8 bits wide */
+static char *flashtype = "cfi_probe";
+
+static struct resource docmem = {
+	.flags = IORESOURCE_MEM,
+	.name  = "NatSemi SCx200 DOCCS Flash",
+};
+
+static struct mtd_info *mymtd;
+
+#if PARTITION
+static struct mtd_partition partition_info[] = {
+	{ 
+		.name   = "DOCCS Boot kernel", 
+		.offset = 0, 
+		.size   = 0xc0000
+	},
+	{ 
+		.name   = "DOCCS Low BIOS", 
+		.offset = 0xc0000, 
+		.size   = 0x40000
+	},
+	{ 
+		.name   = "DOCCS File system", 
+		.offset = 0x100000, 
+		.size   = ~0	/* calculate from flash size */
+	},
+	{ 
+		.name   = "DOCCS High BIOS", 
+		.offset = ~0, 	/* calculate from flash size */
+		.size   = 0x80000
+	},
+};
+#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
+#endif
+
+static __u8 scx200_docflash_read8(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readb(map->map_priv_1 + ofs);
+}
+
+static __u16 scx200_docflash_read16(struct map_info *map, unsigned long ofs)
+{
+	return __raw_readw(map->map_priv_1 + ofs);
+}
+
+static void scx200_docflash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+	memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+static void scx200_docflash_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+	__raw_writeb(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void scx200_docflash_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+	__raw_writew(d, map->map_priv_1 + adr);
+	mb();
+}
+
+static void scx200_docflash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+	memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+static struct map_info scx200_docflash_map = {
+	.name      = "NatSemi SCx200 DOCCS Flash",
+	.read8     = scx200_docflash_read8,
+	.read16    = scx200_docflash_read16,
+	.copy_from = scx200_docflash_copy_from,
+	.write8    = scx200_docflash_write8,
+	.write16   = scx200_docflash_write16,
+	.copy_to   = scx200_docflash_copy_to
+};
+
+int __init init_scx200_docflash(void)
+{
+	unsigned u;
+	unsigned base;
+	unsigned ctrl;
+	unsigned pmr;
+	struct pci_dev *bridge;
+
+	printk(KERN_DEBUG NAME ": NatSemi SCx200 DOCCS Flash Driver\n");
+
+	if ((bridge = pci_find_device(PCI_VENDOR_ID_NS, 
+				      PCI_DEVICE_ID_NS_SCx200_BRIDGE,
+				      NULL)) == NULL)
+		return -ENODEV;
+	
+	if (!scx200_cb_probe(SCx200_CB_BASE)) {
+		printk(KERN_WARNING NAME ": no configuration block found\n");
+		return -ENODEV;
+	}
+
+	if (probe) {
+		/* Try to use the present flash mapping if any */
+		pci_read_config_dword(bridge, SCx200_DOCCS_BASE, &base);
+		pci_read_config_dword(bridge, SCx200_DOCCS_CTRL, &ctrl);
+		pmr = inl(SCx200_CB_BASE + SCx200_PMR);
+
+		if (base == 0
+		    || (ctrl & 0x07000000) != 0x07000000
+		    || (ctrl & 0x0007ffff) == 0)
+			return -ENODEV;
+
+		size = ((ctrl&0x1fff)<<13) + (1<<13);
+
+		for (u = size; u > 1; u >>= 1)
+			;
+		if (u != 1)
+			return -ENODEV;
+
+		if (pmr & (1<<6))
+			width = 16;
+		else
+			width = 8;
+
+		docmem.start = base;
+		docmem.end = base + size;
+
+		if (request_resource(&iomem_resource, &docmem)) {
+			printk(KERN_ERR NAME ": unable to allocate memory for flash mapping\n");
+			return -ENOMEM;
+		}
+	} else {
+		for (u = size; u > 1; u >>= 1)
+			;
+		if (u != 1) {
+			printk(KERN_ERR NAME ": invalid size for flash mapping\n");
+			return -EINVAL;
+		}
+		
+		if (width != 8 && width != 16) {
+			printk(KERN_ERR NAME ": invalid bus width for flash mapping\n");
+			return -EINVAL;
+		}
+		
+		if (allocate_resource(&iomem_resource, &docmem, 
+				      size,
+				      0xc0000000, 0xffffffff, 
+				      size, NULL, NULL)) {
+			printk(KERN_ERR NAME ": unable to allocate memory for flash mapping\n");
+			return -ENOMEM;
+		}
+		
+		ctrl = 0x07000000 | ((size-1) >> 13);
+
+		printk(KERN_INFO "DOCCS BASE=0x%08lx, CTRL=0x%08lx\n", (long)docmem.start, (long)ctrl);
+		
+		pci_write_config_dword(bridge, SCx200_DOCCS_BASE, docmem.start);
+		pci_write_config_dword(bridge, SCx200_DOCCS_CTRL, ctrl);
+		pmr = inl(SCx200_CB_BASE + SCx200_PMR);
+		
+		if (width == 8) {
+			pmr &= ~(1<<6);
+		} else {
+			pmr |= (1<<6);
+		}
+		outl(pmr, SCx200_CB_BASE + SCx200_PMR);
+	}
+	
+       	printk(KERN_INFO NAME ": DOCCS mapped at 0x%lx-0x%lx, width %d\n", 
+	       docmem.start, docmem.end, width);
+
+	scx200_docflash_map.size = size;
+	if (width == 8)
+		scx200_docflash_map.buswidth = 1;
+	else
+		scx200_docflash_map.buswidth = 2;
+
+	scx200_docflash_map.map_priv_1 = (unsigned long)ioremap(docmem.start, scx200_docflash_map.size);
+	if (!scx200_docflash_map.map_priv_1) {
+		printk(KERN_ERR NAME ": failed to ioremap the flash\n");
+		release_resource(&docmem);
+		return -EIO;
+	}
+
+	mymtd = do_map_probe(flashtype, &scx200_docflash_map);
+	if (!mymtd) {
+		printk(KERN_ERR NAME ": unable to detect flash\n");
+		iounmap((void *)scx200_docflash_map.map_priv_1);
+		release_resource(&docmem);
+		return -ENXIO;
+	}
+
+	if (size < mymtd->size)
+		printk(KERN_WARNING NAME ": warning, flash mapping is smaller than flash size\n");
+
+	mymtd->module = THIS_MODULE;
+
+#if PARTITION
+	partition_info[3].offset = mymtd->size-partition_info[3].size;
+	partition_info[2].size = partition_info[3].offset-partition_info[2].offset;
+	add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS);
+#else
+	add_mtd_device(mymtd);
+#endif
+	return 0;
+}
+
+static void __exit cleanup_scx200_docflash(void)
+{
+	if (mymtd) {
+#if PARTITION
+		del_mtd_partitions(mymtd);
+#else
+		del_mtd_device(mymtd);
+#endif
+		map_destroy(mymtd);
+	}
+	if (scx200_docflash_map.map_priv_1) {
+		iounmap((void *)scx200_docflash_map.map_priv_1);
+		release_resource(&docmem);
+	}
+}
+
+module_init(init_scx200_docflash);
+module_exit(cleanup_scx200_docflash);
+
+/*
+    Local variables:
+        compile-command: "make -k -C ../../.. SUBDIRS=drivers/mtd/maps modules"
+        c-basic-offset: 8
+    End:
+*/
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/net/3c59x.c linux.20pre10-ac2/drivers/net/3c59x.c
--- linux.20pre10/drivers/net/3c59x.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/net/3c59x.c	2002-09-26 21:59:08.000000000 +0100
@@ -166,6 +166,11 @@
     - Rename wait_for_completion() to issue_and_wait() to avoid completion.h
       clash.
 
+    LK1.1.18ac 01Jul02 akpm
+     - Fix for undocumented transceiver power-up bit on some 3c566B's
+       (Donald Becker, Rahul Karnik)
+ 
+
     - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3 for more details.
     - Also see Documentation/networking/vortex.txt
 */
@@ -181,8 +186,8 @@
 
 
 #define DRV_NAME	"3c59x"
-#define DRV_VERSION	"LK1.1.16"
-#define DRV_RELDATE	"19 July 2001"
+#define DRV_VERSION	"LK1.1.18-ac"
+#define DRV_RELDATE	"1 July 2002"
 
 
 
@@ -400,7 +405,7 @@
 	EEPROM_8BIT=0x10,	/* AKPM: Uses 0x230 as the base bitmaps for EEPROM reads */
 	HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100,
 	INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400, MAX_COLLISION_RESET=0x800,
-	EEPROM_OFFSET=0x1000, HAS_HWCKSM=0x2000 };
+	EEPROM_OFFSET=0x1000, HAS_HWCKSM=0x2000, WNO_XCVR_PWR=0x4000 };
 
 enum vortex_chips {
 	CH_3C590 = 0,
@@ -508,7 +513,7 @@
 									HAS_HWCKSM, 128, },
 	{"3c556B Laptop Hurricane",
 	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR|
-									HAS_HWCKSM, 128, },
+	                                WNO_XCVR_PWR|HAS_HWCKSM, 128, },
 	{"3c575 [Megahertz] 10/100 LAN 	CardBus",
 	PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
 
@@ -1198,6 +1203,10 @@
 		if (vp->drv_flags & INVERT_MII_PWR)
 			n |= 0x4000;
 		outw(n, ioaddr + Wn2_ResetOptions);
+		if (vp->drv_flags & WNO_XCVR_PWR) {
+			EL3WINDOW(0);
+			outw(0x0800, ioaddr);
+		}
 	}
 
 	/* Extract our information from the EEPROM data. */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/net/appletalk/Config.in linux.20pre10-ac2/drivers/net/appletalk/Config.in
--- linux.20pre10/drivers/net/appletalk/Config.in	2002-10-09 21:36:46.000000000 +0100
+++ linux.20pre10-ac2/drivers/net/appletalk/Config.in	2002-10-11 00:13:14.000000000 +0100
@@ -6,8 +6,10 @@
 comment 'Appletalk devices'
 dep_mbool 'Appletalk interfaces support' CONFIG_DEV_APPLETALK $CONFIG_ATALK
 if [ "$CONFIG_DEV_APPLETALK" = "y" ]; then
-   tristate '  Apple/Farallon LocalTalk PC support' CONFIG_LTPC
-   tristate '  COPS LocalTalk PC support' CONFIG_COPS
+   if [ "$CONFIG_ISA" = "y" -o "$CONFIG_EISA" = "y" ]; then
+      tristate '  Apple/Farallon LocalTalk PC support' CONFIG_LTPC
+      tristate '  COPS LocalTalk PC support' CONFIG_COPS
+   fi
    if [ "$CONFIG_COPS" != "n" ]; then
       bool '    Dayna firmware support' CONFIG_COPS_DAYNA
       bool '    Tangent firmware support' CONFIG_COPS_TANGENT
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/net/gt96100eth.c linux.20pre10-ac2/drivers/net/gt96100eth.c
--- linux.20pre10/drivers/net/gt96100eth.c	2002-10-09 21:36:46.000000000 +0100
+++ linux.20pre10-ac2/drivers/net/gt96100eth.c	2002-09-29 20:07:12.000000000 +0100
@@ -256,7 +256,7 @@
 		gt96100_delay(1);
 
 		if (--timedout == 0) {
-			printk(KERN_ERR __FUNCTION__ ": busy timeout!!\n");
+			printk(KERN_ERR "%s: busy timeout!!\n", __FUNCTION__);
 			return -ENODEV;
 		}
 	}
@@ -270,7 +270,7 @@
 		gt96100_delay(1);
 	
 		if (--timedout == 0) {
-			printk(KERN_ERR __FUNCTION__ ": timeout!!\n");
+			printk(KERN_ERR "%s: timeout!!\n", __FUNCTION__);
 			return -ENODEV;
 		}
 	}
@@ -322,7 +322,7 @@
 		gt96100_delay(1);
 	
 		if (--timedout == 0) {
-			printk(KERN_ERR __FUNCTION__ ": busy timeout!!\n");
+			printk(KERN_ERR "%s: busy timeout!!\n", __FUNCTION__);
 			return -1;
 		}
 	}
@@ -339,7 +339,7 @@
 	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
 	int i;
 
-	dbg(0, __FUNCTION__ ": txno/txni/cnt=%d/%d/%d\n",
+	dbg(0, "%s: txno/txni/cnt=%d/%d/%d\n", __FUNCTION__,
 	    gp->tx_next_out, gp->tx_next_in, gp->tx_count);
 
 	for (i=0; i<TX_RING_SIZE; i++)
@@ -352,7 +352,7 @@
 	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
 	int i;
 
-	dbg(0, __FUNCTION__ ": rxno=%d\n", gp->rx_next_out);
+	dbg(0, "%s: rxno=%d\n", __FUNCTION__, gp->rx_next_out);
 
 	for (i=0; i<RX_RING_SIZE; i++)
 		dump_rx_desc(0, dev, i);
@@ -403,9 +403,8 @@
 	unsigned char* skbdata;
     
 	if (dbg_lvl <= GT96100_DEBUG) {
-		dbg(dbg_lvl, __FUNCTION__
-		    ": skb=%p, skb->data=%p, skb->len=%d\n",
-		    skb, skb->data, skb->len);
+		dbg(dbg_lvl, "%s: skb=%p, skb->data=%p, skb->len=%d\n",
+		    __FUNCTION__, skb, skb->data, skb->len);
 
 		skbdata = (unsigned char*)KSEG1ADDR(skb->data);
     
@@ -435,11 +434,11 @@
 	tblEntry1 |= (u32)addr[4] << 11;
 	tblEntry1 |= (u32)addr[3] << 19;
 	tblEntry1 |= ((u32)addr[2] & 0x1f) << 27;
-	dbg(3, __FUNCTION__ ": tblEntry1=%x\n", tblEntry1);
+	dbg(3, "%s: tblEntry1=%x\n", __FUNCTION__, tblEntry1);
 	tblEntry0 = ((u32)addr[2] >> 5) & 0x07;
 	tblEntry0 |= (u32)addr[1] << 3;
 	tblEntry0 |= (u32)addr[0] << 11;
-	dbg(3, __FUNCTION__ ": tblEntry0=%x\n", tblEntry0);
+	dbg(3, "%s: tblEntry0=%x\n", __FUNCTION__, tblEntry0);
 
 #if 0
 
@@ -453,7 +452,7 @@
 			((ctmp&0x20)<<1) | ((ctmp&0x40)>>1);
 	}
 
-	dump_hw_addr(3, dev, __FUNCTION__ ": nib swap/invt addr=", hash_ea);
+	dump_hw_addr(3, dev, "%s: nib swap/invt addr=", __FUNCTION__, hash_ea);
     
 	if (gp->hash_mode == 0) {
 		hashResult = ((u16)hash_ea[0] & 0xfc) << 7;
@@ -467,19 +466,19 @@
 		return -1; // don't support hash mode 1
 	}
 
-	dbg(3, __FUNCTION__ ": hashResult=%x\n", hashResult);
+	dbg(3, "%s: hashResult=%x\n", __FUNCTION__, hashResult);
 
 	tblEntryAddr =
 		(u32 *)(&gp->hash_table[((u32)hashResult & 0x7ff) << 3]);
     
-	dbg(3, __FUNCTION__ ": tblEntryAddr=%p\n", tblEntryAddr);
+	dbg(3, "%s: tblEntryAddr=%p\n", tblEntryAddr, __FUNCTION__);
 
 	for (i=0; i<HASH_HOP_NUMBER; i++) {
 		if ((*tblEntryAddr & hteValid) &&
 		    !(*tblEntryAddr & hteSkip)) {
 			// This entry is already occupied, go to next entry
 			tblEntryAddr += 2;
-			dbg(3, __FUNCTION__ ": skipping to %p\n",
+			dbg(3, "%s: skipping to %p\n", __FUNCTION__, 
 			    tblEntryAddr);
 		} else {
 			memset(tblEntryAddr, 0, 8);
@@ -490,7 +489,7 @@
 	}
 
 	if (i >= HASH_HOP_NUMBER) {
-		err(__FUNCTION__ ": expired!\n");
+		err("%s: expired!\n", __FUNCTION__);
 		return -1; // Couldn't find an unused entry
 	}
 
@@ -552,7 +551,7 @@
 	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
 	int timedout = 100; // wait up to 100 msec for hard stop to complete
 
-	dbg(3, __FUNCTION__ "\n");
+	dbg(3, "%s\n", __FUNCTION__);
 
 	// Return if neither Rx or Tx abort bits are set
 	if (!(abort_bits & (sdcmrAR | sdcmrAT)))
@@ -566,7 +565,7 @@
 	// abort any Rx/Tx DMA immediately
 	GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, abort_bits);
 
-	dbg(3, __FUNCTION__ ": SDMA comm = %x\n",
+	dbg(3, "%s: SDMA comm = %x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM));
 
 	// wait for abort to complete
@@ -575,7 +574,7 @@
 		gt96100_delay(1);
 	
 		if (--timedout == 0) {
-			err(__FUNCTION__ ": timeout!!\n");
+			err("%s: timeout!!\n", __FUNCTION__);
 			break;
 		}
 	}
@@ -589,7 +588,7 @@
 {
 	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
 
-	dbg(3, __FUNCTION__ "\n");
+	dbg(3, "%s\n", __FUNCTION__);
 
 	disable_ether_irq(dev);
 
@@ -701,8 +700,7 @@
 	struct net_device *dev = NULL;
     
 	if (gtif->irq < 0) {
-		printk(KERN_ERR __FUNCTION__
-		       ": irq unknown - probing not supported\n");
+		printk(KERN_ERR "%s: irq unknown - probing not supported\n", __FUNCTION_);
 		return -ENODEV;
 	}
     
@@ -726,13 +724,12 @@
 	// probe for the external PHY
 	if ((phy_id1 = read_MII(phy_addr, 2)) <= 0 ||
 	    (phy_id2 = read_MII(phy_addr, 3)) <= 0) {
-		printk(KERN_ERR __FUNCTION__
-		       ": no PHY found on MII%d\n", port_num);
+		printk(KERN_ERR "%s: no PHY found on MII%d\n", __FUNCTION__, port_num);
 		return -ENODEV;
 	}
 	
 	if (!request_region(gtif->iobase, GT96100_ETH_IO_SIZE, "GT96100ETH")) {
-		printk(KERN_ERR __FUNCTION__ ": request_region failed\n");
+		printk(KERN_ERR "%s: request_region failed\n", __FUNCTION__);
 		return -EBUSY;
 	}
 
@@ -745,7 +742,7 @@
 	dev->irq = gtif->irq;
 
 	if ((retval = parse_mac_addr(dev, gtif->mac_str))) {
-		err(__FUNCTION__ ": MAC address parse failed\n");
+		err("%s: MAC address parse failed\n", __FUNCTION__);
 		retval = -EINVAL;
 		goto free_region;
 	}
@@ -809,7 +806,7 @@
 		}
 	}
     
-	dbg(3, __FUNCTION__ ": rx_ring=%p, tx_ring=%p\n",
+	dbg(3, "%s: rx_ring=%p, tx_ring=%p\n", __FUNCTION__,
 	    gp->rx_ring, gp->tx_ring);
 
 	// Allocate Rx Hash Table
@@ -826,7 +823,7 @@
 		}
 	}
     
-	dbg(3, __FUNCTION__ ": hash=%p\n", gp->hash_table);
+	dbg(3, "%s: hash=%p\n", __FUNCTION__, gp->hash_table);
 
 	spin_lock_init(&gp->lock);
     
@@ -849,7 +846,7 @@
 	if (dev->priv != NULL)
 		kfree (dev->priv);
 	kfree (dev);
-	err(__FUNCTION__ " failed.  Returns %d\n", retval);
+	err("%s failed.  Returns %d\n", __FUNCTION__, retval);
 	return retval;
 }
 
@@ -956,10 +953,10 @@
 	u32 tmp;
 	u16 mii_reg;
     
-	dbg(3, __FUNCTION__ ": dev=%p\n", dev);
-	dbg(3, __FUNCTION__ ": scs10_lo=%4x, scs10_hi=%4x\n",
+	dbg(3, "%s: dev=%p\n", __FUNCTION__, dev);
+	dbg(3, "%s: scs10_lo=%4x, scs10_hi=%4x\n", __FUNCTION__, 
 	    GT96100_READ(0x8), GT96100_READ(0x10));
-	dbg(3, __FUNCTION__ ": scs32_lo=%4x, scs32_hi=%4x\n",
+	dbg(3, "%s: scs32_lo=%4x, scs32_hi=%4x\n", __FUNCTION__,
 	    GT96100_READ(0x18), GT96100_READ(0x20));
     
 	// Stop and disable Port
@@ -974,7 +971,7 @@
 	tmp |= (1<<31);
 #endif
 	GT96100_WRITE(GT96100_CIU_ARBITER_CONFIG, tmp);
-	dbg(3, __FUNCTION__ ": CIU Config=%x/%x\n",
+	dbg(3, "%s: CIU Config=%x/%x\n", __FUNCTION__, 
 	    tmp, GT96100_READ(GT96100_CIU_ARBITER_CONFIG));
 
 	// Set routing.
@@ -999,19 +996,19 @@
 	gt96100_add_hash_entry(dev, dev->dev_addr);
 	// Set-up DMA ptr to hash table
 	GT96100ETH_WRITE(gp, GT96100_ETH_HASH_TBL_PTR, gp->hash_table_dma);
-	dbg(3, __FUNCTION__ ": Hash Tbl Ptr=%x\n",
+	dbg(3, "%s: Hash Tbl Ptr=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_HASH_TBL_PTR));
 
 	// Setup Tx
 	reset_tx(dev);
 
-	dbg(3, __FUNCTION__ ": Curr Tx Desc Ptr0=%x\n",
+	dbg(3, "%s: Curr Tx Desc Ptr0=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_CURR_TX_DESC_PTR0));
 
 	// Setup Rx
 	reset_rx(dev);
 
-	dbg(3, __FUNCTION__ ": 1st/Curr Rx Desc Ptr0=%x/%x\n",
+	dbg(3, "%s: 1st/Curr Rx Desc Ptr0=%x/%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_1ST_RX_DESC_PTR0),
 	    GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0));
 
@@ -1023,7 +1020,7 @@
 	mii_reg |= 2;  /* enable mii interrupt */
 	write_MII(gp->phy_addr, 0x11, mii_reg);
 	
-	dbg(3, __FUNCTION__ ": PhyAD=%x\n",
+	dbg(3, "%s: PhyAD=%x\n", __FUNCTION__,
 	    GT96100_READ(GT96100_ETH_PHY_ADDR_REG));
 
 	// setup DMA
@@ -1038,17 +1035,17 @@
 			 sdcrBLMR | sdcrBLMT |
 			 (0xf<<sdcrRCBit) | sdcrRIFB | (3<<sdcrBSZBit));
 #endif
-	dbg(3, __FUNCTION__ ": SDMA Config=%x\n",
+	dbg(3, "%s: SDMA Config=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_SDMA_CONFIG));
 
 	// start Rx DMA
 	GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD);
-	dbg(3, __FUNCTION__ ": SDMA Comm=%x\n",
+	dbg(3, "%s: SDMA Comm=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM));
     
 	// enable this port (set hash size to 1/2K)
 	GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, pcrEN | pcrHS);
-	dbg(3, __FUNCTION__ ": Port Config=%x\n",
+	dbg(3, "%s: Port Config=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG));
     
 	/*
@@ -1068,7 +1065,7 @@
 			 pcxrFCTL | pcxrFCTLen | pcxrFLP |
 			 pcxrPRIOrxOverride | pcxrMIBclrMode);
     
-	dbg(3, __FUNCTION__ ": Port Config Ext=%x\n",
+	dbg(3, "%s: Port Config Ext=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG_EXT));
 
 	netif_start_queue(dev);
@@ -1090,7 +1087,7 @@
     
 	MOD_INC_USE_COUNT;
 
-	dbg(2, __FUNCTION__ ": dev=%p\n", dev);
+	dbg(2, "%s: dev=%p\n", __FUNCTION__, dev);
 
 	// Initialize and startup the GT-96100 ethernet port
 	if ((retval = gt96100_init(dev))) {
@@ -1107,7 +1104,7 @@
 		return retval;
 	}
 	
-	dbg(2, __FUNCTION__ ": Initialization done.\n");
+	dbg(2, "%s: Initialization done.\n", __FUNCTION__);
 
 	return 0;
 }
@@ -1115,7 +1112,7 @@
 static int
 gt96100_close(struct net_device *dev)
 {
-	dbg(3, __FUNCTION__ ": dev=%p\n", dev);
+	dbg(3, "%s: dev=%p\n", __FUNCTION__, dev);
 
 	// stop the device
 	if (netif_device_present(dev)) {
@@ -1141,7 +1138,7 @@
 
 	nextIn = gp->tx_next_in;
 
-	dbg(3, __FUNCTION__ ": nextIn=%d\n", nextIn);
+	dbg(3, "%s: nextIn=%d\n", __FUNCTION__, nextIn);
     
 	if (gp->tx_count >= TX_RING_SIZE) {
 		warn("Tx Ring full, pkt dropped.\n");
@@ -1151,14 +1148,14 @@
 	}
     
 	if (!(gp->last_psr & psrLink)) {
-		err(__FUNCTION__ ": Link down, pkt dropped.\n");
+		err("%s: Link down, pkt dropped.\n", __FUNCTION__);
 		gp->stats.tx_dropped++;
 		spin_unlock_irqrestore(&gp->lock, flags);
 		return 1;
 	}
     
 	if (dma32_to_cpu(gp->tx_ring[nextIn].cmdstat) & txOwn) {
-		err(__FUNCTION__ ": device owns descriptor, pkt dropped.\n");
+		err("%s: device owns descriptor, pkt dropped.\n", __FUNCTION__);
 		gp->stats.tx_dropped++;
 		// stop the queue, so Tx timeout can fix it
 		netif_stop_queue(dev);
@@ -1211,7 +1208,7 @@
 	gt96100_rd_t *rd;
 	u32 cmdstat;
     
-	dbg(3, __FUNCTION__ ": dev=%p, status=%x\n", dev, status);
+	dbg(3, "%s: dev=%p, status=%x\n", __FUNCTION__, dev, status);
 
 	cdp = (GT96100ETH_READ(gp, GT96100_ETH_1ST_RX_DESC_PTR0)
 	       - gp->rx_ring_dma) / sizeof(gt96100_rd_t);
@@ -1226,7 +1223,7 @@
 		rd = &gp->rx_ring[nextOut];
 		cmdstat = dma32_to_cpu(rd->cmdstat);
 	
-		dbg(4, __FUNCTION__ ": Rx desc cmdstat=%x, nextOut=%d\n",
+		dbg(4, "%s: Rx desc cmdstat=%x, nextOut=%d\n", __FUNCTION__,
 		    cmdstat, nextOut);
 
 		if (cmdstat & (u32)rxOwn) {
@@ -1268,8 +1265,7 @@
 				 * the deal with this packet? Good question,
 				 * let's dump it out.
 				 */
-				err(__FUNCTION__
-				    ": desc not first and last!\n");
+				err("%s: desc not first and last!\n", __FUNCTION__);
 				dump_rx_desc(0, dev, nextOut);
 			}
 			cmdstat |= (u32)rxOwn;
@@ -1283,8 +1279,7 @@
 		/* Create new skb. */
 		skb = dev_alloc_skb(pkt_len+2);
 		if (skb == NULL) {
-			err(__FUNCTION__
-			    ": Memory squeeze, dropping packet.\n");
+			err("%s: Memory squeeze, dropping packet.\n", __FUNCTION__);
 			gp->stats.rx_dropped++;
 			cmdstat |= (u32)rxOwn;
 			rd->cmdstat = cpu_to_dma32(cmdstat);
@@ -1306,7 +1301,7 @@
 	}
     
 	if (nextOut == gp->rx_next_out)
-		dbg(3, __FUNCTION__ ": RxCDP did not increment?\n");
+		dbg(3, "%s: RxCDP did not increment?\n", __FUNCTION__);
 
 	gp->rx_next_out = nextOut;
 	return 0;
@@ -1334,7 +1329,7 @@
 		td = &gp->tx_ring[nextOut];
 		cmdstat = dma32_to_cpu(td->cmdstat);
 	
-		dbg(3, __FUNCTION__ ": Tx desc cmdstat=%x, nextOut=%d\n",
+		dbg(3, "%s: Tx desc cmdstat=%x, nextOut=%d\n", __FUNCTION__,
 		    cmdstat, nextOut);
 	
 		if (cmdstat & (u32)txOwn) {
@@ -1347,7 +1342,7 @@
 	
 		// increment Tx error stats
 		if (cmdstat & (u32)txErrorSummary) {
-			dbg(2, __FUNCTION__ ": Tx error, cmdstat = %x\n",
+			dbg(2, "%s: Tx error, cmdstat = %x\n", __FUNCTION__,
 			    cmdstat);
 			gp->stats.tx_errors++;
 			if (cmdstat & (u32)txReTxLimit)
@@ -1368,8 +1363,7 @@
 			gp->tx_full = 0;
 			if (gp->last_psr & psrLink) {
 				netif_wake_queue(dev);
-				dbg(2, __FUNCTION__
-				    ": Tx Ring was full, queue waked\n");
+				dbg(2, "%s: Tx Ring was full, queue waked\n", __FUNCTION_);
 			}
 		}
 	
@@ -1378,24 +1372,24 @@
 	
 		// free the skb
 		if (gp->tx_skbuff[nextOut]) {
-			dbg(3, __FUNCTION__ ": good Tx, skb=%p\n",
+			dbg(3, "%s: good Tx, skb=%p\n", __FUNCTION__,
 			    gp->tx_skbuff[nextOut]);
 			dev_kfree_skb_irq(gp->tx_skbuff[nextOut]);
 			gp->tx_skbuff[nextOut] = NULL;
 		} else {
-			err(__FUNCTION__ ": no skb!\n");
+			err("%s: no skb!\n", __FUNCTION__);
 		}
 	}
 
 	gp->tx_next_out = nextOut;
 
 	if (gt96100_check_tx_consistent(gp)) {
-		err(__FUNCTION__ ": Tx queue inconsistent!\n");
+		err("%s: Tx queue inconsistent!\n", __FUNCTION__);
 	}
     
 	if ((status & icrTxEndLow) && gp->tx_count != 0) {
 		// we must restart the DMA
-		dbg(3, __FUNCTION__ ": Restarting Tx DMA\n");
+		dbg(3, "%s: Restarting Tx DMA\n", __FUNCTION__);
 		GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM,
 				 sdcmrERD | sdcmrTXDL);
 	}
@@ -1410,11 +1404,11 @@
 	u32 status;
     
 	if (dev == NULL) {
-		err(__FUNCTION__ ": null dev ptr\n");
+		err("%s: null dev ptr\n", __FUNCTION__);
 		return;
 	}
 
-	dbg(3, __FUNCTION__ ": entry, icr=%x\n",
+	dbg(3, "%s: entry, icr=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE));
 
 	spin_lock(&gp->lock);
@@ -1449,13 +1443,13 @@
 		
 				if ((psr & psrLink) && !gp->tx_full &&
 				    netif_queue_stopped(dev)) {
-					dbg(0, __FUNCTION__
-					    ": Link up, waking queue.\n");
+					dbg(0, ": Link up, waking queue.\n",
+					    __FUNCTION_);
 					netif_wake_queue(dev);
 				} else if (!(psr & psrLink) &&
 					   !netif_queue_stopped(dev)) {
-					dbg(0, __FUNCTION__
-					    "Link down, stopping queue.\n");
+					dbg(0, "Link down, stopping queue.\n",
+					    __FUNCTION__);
 					netif_stop_queue(dev);
 				}
 
@@ -1475,13 +1469,13 @@
 	
 		// Now check TX errors (RX errors were handled in gt96100_rx)
 		if (status & icrTxErrorLow) {
-			err(__FUNCTION__ ": Tx resource error\n");
+			err("%s: Tx resource error\n", __FUNCTION__);
 			if (--gp->intr_work_done == 0)
 				break;
 		}
 	
 		if (status & icrTxUdr) {
-			err(__FUNCTION__ ": Tx underrun error\n");
+			err("%s: Tx underrun error\n", __FUNCTION__);
 			if (--gp->intr_work_done == 0)
 				break;
 		}
@@ -1490,10 +1484,10 @@
 	if (gp->intr_work_done == 0) {
 		// ACK any remaining pending interrupts
 		GT96100ETH_WRITE(gp, GT96100_ETH_INT_CAUSE, 0);
-		dbg(3, __FUNCTION__ ": hit max work\n");
+		dbg(3, "%s: hit max work\n", __FUNCTION__);
 	}
     
-	dbg(3, __FUNCTION__ ": exit, icr=%x\n",
+	dbg(3, "%s: exit, icr=%x\n", __FUNCTION__,
 	    GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE));
 
 	spin_unlock(&gp->lock);
@@ -1532,7 +1526,7 @@
 	unsigned long flags;
 	//struct dev_mc_list *mcptr;
     
-	dbg(3, __FUNCTION__ ": dev=%p, flags=%x\n", dev, dev->flags);
+	dbg(3, "%s: dev=%p, flags=%x\n", __FUNCTION__, dev, dev->flags);
 
 	// stop the Receiver DMA
 	abort(dev, sdcmrAR);
@@ -1575,7 +1569,7 @@
 	struct gt96100_private *gp = (struct gt96100_private *)dev->priv;
 	unsigned long flags;
 
-	dbg(3, __FUNCTION__ ": dev=%p\n", dev);
+	dbg(3, "%s: dev=%p\n", __FUNCTION__, dev);
 
 	if (netif_device_present(dev)) {
 		spin_lock_irqsave (&gp->lock, flags);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/net/irda/irtty.c linux.20pre10-ac2/drivers/net/irda/irtty.c
--- linux.20pre10/drivers/net/irda/irtty.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/net/irda/irtty.c	2002-08-13 14:30:24.000000000 +0100
@@ -46,19 +46,6 @@
 
 static int qos_mtt_bits = 0x03;      /* 5 ms or more */
 
-/* To workaround some of the difference in the serial driver over various
- * arch, some people have introduced TIOCM_MODEM_BITS.
- * Unfortunately, this is not yet defined on all architectures, so
- * we make sure the code is still usable. - Jean II */
-#ifndef TIOCM_MODEM_BITS
-#warning "Please define TIOCM_MODEM_BITS in termios.h !"
-#ifdef TIOCM_OUT2
-#define TIOCM_MODEM_BITS	TIOCM_OUT2	/* Most architectures */
-#else
-#define TIOCM_MODEM_BITS	0		/* Not defined for ARM */
-#endif
-#endif
-
 /* Network device fuction prototypes */
 static int  irtty_hard_xmit(struct sk_buff *skb, struct net_device *dev);
 static int  irtty_net_init(struct net_device *dev);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/net/natsemi.c linux.20pre10-ac2/drivers/net/natsemi.c
--- linux.20pre10/drivers/net/natsemi.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/net/natsemi.c	2002-09-17 15:04:30.000000000 +0100
@@ -1750,7 +1750,7 @@
 		if ((np->tx_config & TxDrthMask) < 62)
 			np->tx_config += 2;
 		if (netif_msg_tx_err(np))
-			printk(KERN_NOTICE 
+			printk(KERN_INFO
 				"%s: increased Tx threshold, txcfg %#08x.\n",
 				dev->name, np->tx_config);
 		writel(np->tx_config, ioaddr + TxConfig);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/net/pcmcia/wavelan_cs.c linux.20pre10-ac2/drivers/net/pcmcia/wavelan_cs.c
--- linux.20pre10/drivers/net/pcmcia/wavelan_cs.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/net/pcmcia/wavelan_cs.c	2002-09-29 20:13:32.000000000 +0100
@@ -707,7 +707,7 @@
   
   while(wavepoint!=NULL)
     {
-      if(wavepoint->last_seen < jiffies-CELL_TIMEOUT)
+      if(time_after(jiffies, wavepoint->last_seen + CELL_TIMEOUT))
 	{
 #ifdef WAVELAN_ROAMING_DEBUG
 	  printk(KERN_DEBUG "WaveLAN: Bye bye %.4X\n",wavepoint->nwid);
@@ -1890,7 +1890,8 @@
 }
 #endif	/* HISTOGRAM */
 
-static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+static inline int
+wl_netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
 {
 	u32 ethcmd;
 		
@@ -1933,7 +1934,7 @@
 #endif
 
   if (cmd == SIOCETHTOOL)
-    return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+    return wl_netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
 
   /* Disable interrupts & save flags */
   wv_splhi(lp, &flags);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/net/pcnet32.c linux.20pre10-ac2/drivers/net/pcnet32.c
--- linux.20pre10/drivers/net/pcnet32.c	2002-10-09 21:36:44.000000000 +0100
+++ linux.20pre10-ac2/drivers/net/pcnet32.c	2002-08-06 15:42:06.000000000 +0100
@@ -1,5 +1,5 @@
-/* pcnet32.c: An AMD PCnet32 ethernet driver for linux. */
-/*
+/* pcnet32.c: An AMD PCnet32 ethernet driver for linux.
+ *
  *	Copyright 1996-1999 Thomas Bogendoerfer
  * 
  *	Derived from the lance driver written 1993,1994,1995 by Donald Becker.
@@ -543,7 +543,7 @@
     /* initialize variables */
     fdx = mii = fset = dxsuflo = ltint = 0;
     chip_version = (chip_version >> 12) & 0xffff;
-
+    
     switch (chip_version) {
     case 0x2420:
 	chipname = "PCnet/PCI 79C970"; /* PCI */
@@ -1175,19 +1175,12 @@
 		    if (err_status & 0x04000000) lp->stats.tx_aborted_errors++;
 		    if (err_status & 0x08000000) lp->stats.tx_carrier_errors++;
 		    if (err_status & 0x10000000) lp->stats.tx_window_errors++;
-#ifndef DO_DXSUFLO
 		    if (err_status & 0x40000000) {
 			lp->stats.tx_fifo_errors++;
-			/* Ackk!  On FIFO errors the Tx unit is turned off! */
-			/* Remove this verbosity later! */
-			printk(KERN_ERR "%s: Tx FIFO error! CSR0=%4.4x\n",
-			       dev->name, csr0);
-			must_restart = 1;
-		    }
-#else
-		    if (err_status & 0x40000000) {
-			lp->stats.tx_fifo_errors++;
-			if (! lp->dxsuflo) {  /* If controller doesn't recover ... */
+#ifdef DO_DXSUFLO
+			if (! lp->dxsuflo) 
+#endif
+			{  /* If controller doesn't recover ... */
 			    /* Ackk!  On FIFO errors the Tx unit is turned off! */
 			    /* Remove this verbosity later! */
 			    printk(KERN_ERR "%s: Tx FIFO error! CSR0=%4.4x\n",
@@ -1195,7 +1188,6 @@
 			    must_restart = 1;
 			}
 		    }
-#endif
 		} else {
 		    if (status & 0x1800)
 			lp->stats.collisions++;
@@ -1722,12 +1714,13 @@
     }
 }
 
+
 module_init(pcnet32_init_module);
 module_exit(pcnet32_cleanup_module);
 
 /*
  * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c pcnet32.c"
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include/linux -Wall -Wstrict-prototypes -O2 -m486 -c pcnet32.c"
  *  c-indent-level: 4
  *  tab-width: 8
  * End:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/net/ppp_generic.c linux.20pre10-ac2/drivers/net/ppp_generic.c
--- linux.20pre10/drivers/net/ppp_generic.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/net/ppp_generic.c	2002-10-07 21:32:43.000000000 +0100
@@ -844,7 +844,7 @@
 	ppp_xmit_process(ppp);
 	return 0;
 
- err1:
+err1:
 	kfree_skb(skb);
 	++ppp->stats.tx_dropped;
 	return 0;
@@ -1998,7 +1998,7 @@
 		}
 	}
 
- err1:
+err1:
 	return err;
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/net/tokenring/lanstreamer.c linux.20pre10-ac2/drivers/net/tokenring/lanstreamer.c
--- linux.20pre10/drivers/net/tokenring/lanstreamer.c	2002-10-09 21:36:44.000000000 +0100
+++ linux.20pre10-ac2/drivers/net/tokenring/lanstreamer.c	2002-09-30 17:49:49.000000000 +0100
@@ -65,6 +65,7 @@
  *  11/05/01 - Restructured the interrupt function, added delays, reduced the 
  *             the number of TX descriptors to 1, which together can prevent 
  *             the card from locking up the box - <yoder1@us.ibm.com>
+ *  09/27/02 - New PCI interface + bug fix. - <yoder1@us.ibm.com>
  *  
  *  To Do:
  *
@@ -136,7 +137,7 @@
  */
 
 static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan\n"
-                        "              v0.5.1 03/04/02 - Kent Yoder";
+                        "              v0.5.2 09/30/02 - Kent Yoder";
 
 static struct pci_device_id streamer_pci_tbl[] __initdata = {
 	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, PCI_ANY_ID, PCI_ANY_ID,},
@@ -250,6 +251,12 @@
   dev_streamer=streamer_priv;
 #endif
 #endif
+ 
+  if(pci_set_dma_mask(pdev, 0xFFFFFFFF)) {
+    printk(KERN_ERR "%s: No suitable PCI mapping available.\n", dev->name);
+    rc = -ENODEV;
+    goto err_out;
+  }
   
   if (pci_enable_device(pdev)) {
     printk(KERN_ERR "lanstreamer: unable to enable pci device\n");
@@ -481,9 +488,11 @@
 		data=((u8 *)skb->data)+sizeof(struct streamer_rx_desc);
 		rx_ring->forward=0;
 		rx_ring->status=0;
-		rx_ring->buffer=virt_to_bus(data);
+		rx_ring->buffer=cpu_to_le32(pci_map_single(streamer_priv->pci_dev, data, 
+							512, PCI_DMA_FROMDEVICE));
 		rx_ring->framelen_buflen=512; 
-		writel(virt_to_bus(rx_ring),streamer_mmio+RXBDA);
+		writel(cpu_to_le32(pci_map_single(streamer_priv->pci_dev, rx_ring, 512, PCI_DMA_FROMDEVICE)),
+			streamer_mmio+RXBDA);
 	}
 
 #if STREAMER_DEBUG
@@ -499,6 +508,8 @@
 			printk(KERN_ERR
 			       "IBM PCI tokenring card not responding\n");
 			release_region(dev->base_addr, STREAMER_IO_SPACE);
+			if (skb)
+				dev_kfree_skb(skb);
 			return -1;
 		}
 	}
@@ -773,14 +784,19 @@
 
 		skb->dev = dev;
 
-		streamer_priv->streamer_rx_ring[i].forward = virt_to_bus(&streamer_priv->streamer_rx_ring[i + 1]);
+		streamer_priv->streamer_rx_ring[i].forward = 
+			cpu_to_le32(pci_map_single(streamer_priv->pci_dev, &streamer_priv->streamer_rx_ring[i + 1],
+					sizeof(struct streamer_rx_desc), PCI_DMA_FROMDEVICE));
 		streamer_priv->streamer_rx_ring[i].status = 0;
-		streamer_priv->streamer_rx_ring[i].buffer = virt_to_bus(skb->data);
+		streamer_priv->streamer_rx_ring[i].buffer = 
+			cpu_to_le32(pci_map_single(streamer_priv->pci_dev, skb->data,
+					      streamer_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE));
 		streamer_priv->streamer_rx_ring[i].framelen_buflen = streamer_priv->pkt_buf_sz;
 		streamer_priv->rx_ring_skb[i] = skb;
 	}
 	streamer_priv->streamer_rx_ring[STREAMER_RX_RING_SIZE - 1].forward =
-				virt_to_bus(&streamer_priv->streamer_rx_ring[0]);
+				cpu_to_le32(pci_map_single(streamer_priv->pci_dev, &streamer_priv->streamer_rx_ring[0],
+						sizeof(struct streamer_rx_desc), PCI_DMA_FROMDEVICE));
 
 	if (i == 0) {
 		printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled\n", dev->name);
@@ -790,8 +806,12 @@
 
 	streamer_priv->rx_ring_last_received = STREAMER_RX_RING_SIZE - 1;	/* last processed rx status */
 
-	writel(virt_to_bus(&streamer_priv->streamer_rx_ring[0]), streamer_mmio + RXBDA);
-	writel(virt_to_bus(&streamer_priv->streamer_rx_ring[STREAMER_RX_RING_SIZE - 1]), streamer_mmio + RXLBDA);
+	writel(cpu_to_le32(pci_map_single(streamer_priv->pci_dev, &streamer_priv->streamer_rx_ring[0],
+				sizeof(struct streamer_rx_desc), PCI_DMA_TODEVICE)), 
+		streamer_mmio + RXBDA);
+	writel(cpu_to_le32(pci_map_single(streamer_priv->pci_dev, &streamer_priv->streamer_rx_ring[STREAMER_RX_RING_SIZE - 1],
+				sizeof(struct streamer_rx_desc), PCI_DMA_TODEVICE)), 
+		streamer_mmio + RXLBDA);
 
 	/* set bus master interrupt event mask */
 	writew(MISR_RX_NOBUF | MISR_RX_EOF, streamer_mmio + MISR_MASK);
@@ -807,7 +827,10 @@
 
 	writew(~BMCTL_TX2_DIS, streamer_mmio + BMCTL_RUM);	/* Enables TX channel 2 */
 	for (i = 0; i < STREAMER_TX_RING_SIZE; i++) {
-		streamer_priv->streamer_tx_ring[i].forward = virt_to_bus(&streamer_priv->streamer_tx_ring[i + 1]);
+		streamer_priv->streamer_tx_ring[i].forward = cpu_to_le32(pci_map_single(streamer_priv->pci_dev, 
+										&streamer_priv->streamer_tx_ring[i + 1],
+										sizeof(struct streamer_tx_desc),
+										PCI_DMA_TODEVICE));
 		streamer_priv->streamer_tx_ring[i].status = 0;
 		streamer_priv->streamer_tx_ring[i].bufcnt_framelen = 0;
 		streamer_priv->streamer_tx_ring[i].buffer = 0;
@@ -817,7 +840,8 @@
 		streamer_priv->streamer_tx_ring[i].rsvd3 = 0;
 	}
 	streamer_priv->streamer_tx_ring[STREAMER_TX_RING_SIZE - 1].forward =
-					virt_to_bus(&streamer_priv->streamer_tx_ring[0]);
+					cpu_to_le32(pci_map_single(streamer_priv->pci_dev, &streamer_priv->streamer_tx_ring[0],
+							sizeof(struct streamer_tx_desc), PCI_DMA_TODEVICE));
 
 	streamer_priv->free_tx_ring_entries = STREAMER_TX_RING_SIZE;
 	streamer_priv->tx_ring_free = 0;	/* next entry in tx ring to use */
@@ -915,6 +939,11 @@
 				skb->dev = dev;
 
 				if (buffer_cnt == 1) {
+					/* release the DMA mapping */
+					pci_unmap_single(streamer_priv->pci_dev, 
+						le32_to_cpu(streamer_priv->streamer_rx_ring[rx_ring_last_received].buffer),
+						streamer_priv->pkt_buf_sz, 
+						PCI_DMA_FROMDEVICE);
 					skb2 = streamer_priv->rx_ring_skb[rx_ring_last_received];
 #if STREAMER_DEBUG_PACKETS
 					{
@@ -934,20 +963,29 @@
 					/* recycle this descriptor */
 					streamer_priv->streamer_rx_ring[rx_ring_last_received].status = 0;
 					streamer_priv->streamer_rx_ring[rx_ring_last_received].framelen_buflen = streamer_priv->pkt_buf_sz;
-					streamer_priv->streamer_rx_ring[rx_ring_last_received].buffer = virt_to_bus(skb->data);
-					streamer_priv-> rx_ring_skb[rx_ring_last_received] = skb;
+					streamer_priv->streamer_rx_ring[rx_ring_last_received].buffer = 
+						cpu_to_le32(pci_map_single(streamer_priv->pci_dev, skb->data, streamer_priv->pkt_buf_sz,
+								PCI_DMA_FROMDEVICE));
+					streamer_priv->rx_ring_skb[rx_ring_last_received] = skb;
 					/* place recycled descriptor back on the adapter */
-					writel(virt_to_bus(&streamer_priv->streamer_rx_ring[rx_ring_last_received]),streamer_mmio + RXLBDA);
+					writel(cpu_to_le32(pci_map_single(streamer_priv->pci_dev, 
+									&streamer_priv->streamer_rx_ring[rx_ring_last_received],
+									sizeof(struct streamer_rx_desc), PCI_DMA_FROMDEVICE)),
+						streamer_mmio + RXLBDA);
 					/* pass the received skb up to the protocol */
 					netif_rx(skb2);
 				} else {
 					do {	/* Walk the buffers */
-						memcpy(skb_put(skb, length),bus_to_virt(rx_desc->buffer), length);	/* copy this fragment */
+						pci_unmap_single(streamer_priv->pci_dev, le32_to_cpu(rx_desc->buffer), length, PCI_DMA_FROMDEVICE), 
+						memcpy(skb_put(skb, length), (void *)rx_desc->buffer, length);	/* copy this fragment */
 						streamer_priv->streamer_rx_ring[rx_ring_last_received].status = 0;
 						streamer_priv->streamer_rx_ring[rx_ring_last_received].framelen_buflen = streamer_priv->pkt_buf_sz;
 						
 						/* give descriptor back to the adapter */
-						writel(virt_to_bus(&streamer_priv->streamer_rx_ring[rx_ring_last_received]), streamer_mmio + RXLBDA);
+						writel(cpu_to_le32(pci_map_single(streamer_priv->pci_dev, 
+									&streamer_priv->streamer_rx_ring[rx_ring_last_received],
+									length, PCI_DMA_FROMDEVICE)), 
+							streamer_mmio + RXLBDA);
 
 						if (rx_desc->status & 0x80000000)
 							break;	/* this descriptor completes the frame */
@@ -1114,7 +1152,8 @@
 	if (streamer_priv->free_tx_ring_entries) {
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].status = 0;
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00020000 | skb->len;
-		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].buffer = virt_to_bus(skb->data);
+		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].buffer = 
+			cpu_to_le32(pci_map_single(streamer_priv->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE));
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd1 = skb->len;
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd2 = 0;
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].rsvd3 = 0;
@@ -1135,7 +1174,10 @@
 		}
 #endif
 
-		writel(virt_to_bus (&streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free]),streamer_mmio + TX2LFDA);
+		writel(cpu_to_le32(pci_map_single(streamer_priv->pci_dev, 
+					&streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free],
+					sizeof(struct streamer_tx_desc), PCI_DMA_TODEVICE)),
+			streamer_mmio + TX2LFDA);
 		(void)readl(streamer_mmio + TX2LFDA);
 
 		streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/net/tokenring/olympic.c linux.20pre10-ac2/drivers/net/tokenring/olympic.c
--- linux.20pre10/drivers/net/tokenring/olympic.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/net/tokenring/olympic.c	2002-10-11 00:21:45.000000000 +0100
@@ -56,8 +56,15 @@
  * 07/19/01 - Improve bad LAA reporting, strip out freemem
  *	      into a separate function, its called from 3 
  *	      different places now. 
- * 02/09/01 - Replaced sleep_on. 
- *
+ * 02/09/02 - Replaced sleep_on. 
+ * 03/01/02 - Replace access to several registers from 32 bit to 
+ * 	      16 bit. Fixes alignment errors on PPC 64 bit machines.
+ * 	      Thanks to Al Trautman for this one.
+ * 03/10/02 - Fix BUG in arb_cmd. Bug was there all along but was
+ * 	      silently ignored until the error checking code 
+ * 	      went into version 1.0.0 
+ * 06/04/02 - Add correct start up sequence for the cardbus adapters.
+ * 	      Required for strict compliance with pci power mgmt specs.
  *  To Do:
  *
  *	     Wake on lan	
@@ -111,7 +118,7 @@
  */
 
 static char version[] __devinitdata = 
-"Olympic.c v1.0.0 2/9/02  - Peter De Schrijver & Mike Phillips" ; 
+"Olympic.c v1.0.5 6/04/02 - Peter De Schrijver & Mike Phillips" ; 
 
 static char *open_maj_error[]  = {"No error", "Lobe Media Test", "Physical Insertion",
 				   "Address Verification", "Neighbor Notification (Ring Poll)",
@@ -296,9 +303,10 @@
 	spin_lock_init(&olympic_priv->olympic_lock) ; 
 
 	/* Needed for cardbus */
-	if(!(readl(olympic_mmio+BCTL) & BCTL_MODE_INDICATOR))
+	if(!(readl(olympic_mmio+BCTL) & BCTL_MODE_INDICATOR)) {
 		writel(readl(olympic_priv->olympic_mmio+FERMASK)|FERMASK_INT_BIT, olympic_mmio+FERMASK);
-
+	}
+	
 #if OLYMPIC_DEBUG
 	printk("BCTL: %x\n",readl(olympic_mmio+BCTL));
 	printk("GPR: %x\n",readw(olympic_mmio+GPR));
@@ -311,24 +319,42 @@
 	writel(readl(olympic_mmio+BCTL)|BCTL_MIMREB,olympic_mmio+BCTL);
 	
 	if (olympic_priv->olympic_ring_speed  == 0) { /* Autosense */
-		writel(readl(olympic_mmio+GPR)|GPR_AUTOSENSE,olympic_mmio+GPR);
+		writew(readw(olympic_mmio+GPR)|GPR_AUTOSENSE,olympic_mmio+GPR);
 		if (olympic_priv->olympic_message_level) 
 			printk(KERN_INFO "%s: Ringspeed autosense mode on\n",olympic_priv->olympic_card_name);
 	} else if (olympic_priv->olympic_ring_speed == 16) {
 		if (olympic_priv->olympic_message_level) 
 			printk(KERN_INFO "%s: Trying to open at 16 Mbps as requested\n", olympic_priv->olympic_card_name);
-		writel(GPR_16MBPS, olympic_mmio+GPR);
+		writew(GPR_16MBPS, olympic_mmio+GPR);
 	} else if (olympic_priv->olympic_ring_speed == 4) {
 		if (olympic_priv->olympic_message_level) 
 			printk(KERN_INFO "%s: Trying to open at 4 Mbps as requested\n", olympic_priv->olympic_card_name) ; 
-		writel(0, olympic_mmio+GPR);
+		writew(0, olympic_mmio+GPR);
 	} 
 	
-	writel(readl(olympic_mmio+GPR)|GPR_NEPTUNE_BF,olympic_mmio+GPR);
+	writew(readw(olympic_mmio+GPR)|GPR_NEPTUNE_BF,olympic_mmio+GPR);
 
 #if OLYMPIC_DEBUG
 	printk("GPR = %x\n",readw(olympic_mmio + GPR) ) ; 
 #endif
+	/* Solo has been paused to meet the Cardbus power
+	 * specs if the adapter is cardbus. Check to 
+	 * see its been paused and then restart solo. The
+	 * adapter should set the pause bit within 1 second.
+	 */
+
+	if(!(readl(olympic_mmio+BCTL) & BCTL_MODE_INDICATOR)) { 
+		t=jiffies;
+		while (!readl(olympic_mmio+CLKCTL) & CLKCTL_PAUSE) { 
+			schedule() ; 
+			if(jiffies-t > 2*HZ) { 
+				printk(KERN_ERR "IBM Cardbus tokenring adapter not responsing.\n") ; 
+				return -ENODEV;
+			}
+		}
+		writel(readl(olympic_mmio+CLKCTL) & ~CLKCTL_PAUSE, olympic_mmio+CLKCTL) ; 
+	}
+	
 	/* start solo init */
 	writel((1<<15),olympic_mmio+SISR_MASK_SUM);
 
@@ -341,13 +367,13 @@
 		}
 	}
 	
-	writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
+	writel(readw(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
 
 #if OLYMPIC_DEBUG
 	printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA));
 #endif
 
-	init_srb=olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWO)) & (~0xf800));
+	init_srb=olympic_priv->olympic_lap + ((readw(olympic_mmio+LAPWWO)) & (~0xf800));
 
 #if OLYMPIC_DEBUG		
 {
@@ -422,11 +448,11 @@
 
 	/* adapter is closed, so SRB is pointed to by LAPWWO */
 
-	writel(readl(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
-	init_srb=olympic_priv->olympic_lap + ((readl(olympic_mmio+LAPWWO)) & (~0xf800));
+	writel(readw(olympic_mmio+LAPWWO),olympic_mmio+LAPA);
+	init_srb=olympic_priv->olympic_lap + ((readw(olympic_mmio+LAPWWO)) & (~0xf800));
 	
 #if OLYMPIC_DEBUG
-	printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA));
+	printk("LAPWWO: %x, LAPA: %x\n",readw(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA));
 	printk("SISR Mask = %04x\n", readl(olympic_mmio+SISR_MASK));
 	printk("Before the open command \n");
 #endif	
@@ -486,7 +512,7 @@
             			olympic_priv->srb_queued=0;
             			break;
         		}
-			if ((jiffies-t) > 60*HZ) { 
+			if ((jiffies-t) > 10*HZ) { 
 				printk(KERN_WARNING "%s: SRB timed out. \n",dev->name) ; 
 				olympic_priv->srb_queued=0;
 				break ; 
@@ -495,7 +521,7 @@
     		}
 		remove_wait_queue(&olympic_priv->srb_wait,&wait) ; 
 		set_current_state(TASK_RUNNING) ; 
-
+		olympic_priv->srb_queued = 0 ; 
 #if OLYMPIC_DEBUG
 		printk("init_srb(%p): ",init_srb);
 		for(i=0;i<20;i++)
@@ -629,7 +655,8 @@
 	printk(" stat_ring[7]: %p\n", &(olympic_priv->olympic_rx_status_ring[7])  );
 
 	printk("RXCDA: %x, rx_ring[0]: %p\n",readl(olympic_mmio+RXCDA),&olympic_priv->olympic_rx_ring[0]);
-	printk("Rx_ring_dma_addr = %08x, rx_status_dma_addr = %08x\n",olympic_priv->rx_ring_dma_addr,olympic_priv->rx_status_ring_dma_addr) ; 
+	printk("Rx_ring_dma_addr = %08x, rx_status_dma_addr =
+%08x\n",olympic_priv->rx_ring_dma_addr,olympic_priv->rx_status_ring_dma_addr) ; 
 #endif
 
 	writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) | i,olympic_mmio+RXENQ);
@@ -790,7 +817,7 @@
 			   	   	   first. Ideally all frames would be in a single buffer, this can be tuned by
                                	   	   altering the buffer size. If the length of the packet is less than
 					   1500 bytes we're going to copy it over anyway to stop packets getting
-					   dropped from sockets with buffers small than our pkt_buf_sz. */
+					   dropped from sockets with buffers smaller than our pkt_buf_sz. */
 				
  					if (buffer_cnt==1) {
 						olympic_priv->rx_ring_last_received++ ; 
@@ -1097,10 +1124,13 @@
 	writel(readl(olympic_mmio+BCTL)&~(3<<13),olympic_mmio+BCTL);
 
 #if OLYMPIC_DEBUG
+	{
+	int i ; 
 	printk("srb(%p): ",srb);
 	for(i=0;i<4;i++)
 		printk("%x ",readb(srb+i));
 	printk("\n");
+	}
 #endif
 	free_irq(dev->irq,dev);
 
@@ -1369,8 +1399,7 @@
 	arb_block = (u8 *)(olympic_priv->olympic_lap + olympic_priv->arb) ; 
 	asb_block = (u8 *)(olympic_priv->olympic_lap + olympic_priv->asb) ; 
 	srb = (u8 *)(olympic_priv->olympic_lap + olympic_priv->srb) ; 
-	writel(readl(olympic_mmio+LAPA),olympic_mmio+LAPWWO);
-
+	
 	if (readb(arb_block+0) == ARB_RECEIVE_DATA) { /* Receive.data, MAC frames */
 
 		header_len = readb(arb_block+8) ; /* 802.5 Token-Ring Header Length */	
@@ -1423,7 +1452,7 @@
 		/* Now tell the card we have dealt with the received frame */
 
 		/* Set LISR Bit 1 */
-		writel(LISR_ARB_FREE,olympic_priv->olympic_lap + LISR_SUM);
+		writel(LISR_ARB_FREE,olympic_priv->olympic_mmio + LISR_SUM);
 
 		/* Is the ASB free ? */ 	
 		
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/net/tokenring/olympic.h linux.20pre10-ac2/drivers/net/tokenring/olympic.h
--- linux.20pre10/drivers/net/tokenring/olympic.h	2002-10-09 21:36:44.000000000 +0100
+++ linux.20pre10-ac2/drivers/net/tokenring/olympic.h	2002-10-11 00:21:45.000000000 +0100
@@ -91,6 +91,7 @@
 #define TIMER 0x50
 
 #define CLKCTL 0x74
+#define CLKCTL_PAUSE (1<<15) 
 
 #define PM_CON 0x4
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/net/wan/cycx_x25.c linux.20pre10-ac2/drivers/net/wan/cycx_x25.c
--- linux.20pre10/drivers/net/wan/cycx_x25.c	2002-10-09 21:36:44.000000000 +0100
+++ linux.20pre10-ac2/drivers/net/wan/cycx_x25.c	2002-09-29 20:06:20.000000000 +0100
@@ -1446,7 +1446,7 @@
         unsigned char *ptr;
 
         if ((skb = dev_alloc_skb(1)) == NULL) {
-                printk(KERN_ERR __FUNCTION__ ": out of memory\n");
+                printk(KERN_ERR "%s: out of memory\n", __FUNCTION__);
                 return;
         }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/pci/pci.c linux.20pre10-ac2/drivers/pci/pci.c
--- linux.20pre10/drivers/pci/pci.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/pci/pci.c	2002-09-26 22:01:23.000000000 +0100
@@ -28,7 +28,7 @@
 #include <asm/page.h>
 #include <asm/dma.h>	/* isa_dma_bridge_buggy */
 
-#undef DEBUG
+#define DEBUG
 
 #ifdef DEBUG
 #define DBG(x...) printk(x)
@@ -1199,6 +1199,8 @@
 	}
 }
 
+EXPORT_SYMBOL(pci_read_bridge_bases);
+
 static struct pci_bus * __devinit pci_alloc_bus(void)
 {
 	struct pci_bus *b;
@@ -1258,7 +1260,8 @@
  * them, we proceed to assigning numbers to the remaining buses in
  * order to avoid overlaps between old and new bus numbers.
  */
-static int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass)
+
+int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass)
 {
 	unsigned int buses;
 	unsigned short cr;
@@ -1329,6 +1332,8 @@
 	return max;
 }
 
+EXPORT_SYMBOL(pci_scan_bridge);
+
 /*
  * Read interrupt line and base address registers.
  * The architecture-dependent code can tweak these, of course.
@@ -1682,7 +1687,7 @@
 	return error;
 }
 
-static int pci_pm_suspend(u32 state)
+int pci_pm_suspend(u32 state)
 {
 	struct list_head *list;
 	struct pci_bus *bus;
@@ -2153,12 +2158,12 @@
 EXPORT_SYMBOL(pci_do_scan_bus);
 EXPORT_SYMBOL(pci_scan_slot);
 EXPORT_SYMBOL(pci_scan_bus);
+EXPORT_SYMBOL(pci_scan_device);
 #ifdef CONFIG_PROC_FS
 EXPORT_SYMBOL(pci_proc_attach_device);
 EXPORT_SYMBOL(pci_proc_detach_device);
 EXPORT_SYMBOL(pci_proc_attach_bus);
 EXPORT_SYMBOL(pci_proc_detach_bus);
-EXPORT_SYMBOL(proc_bus_pci_dir);
 #endif
 #endif
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/pci/pci.ids linux.20pre10-ac2/drivers/pci/pci.ids
--- linux.20pre10/drivers/pci/pci.ids	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/pci/pci.ids	2002-10-10 23:53:35.000000000 +0100
@@ -2617,6 +2617,7 @@
 10fc  I-O Data Device, Inc.
 # What's in the cardbus end of a Sony ACR-A01 card, comes with newer Vaio CD-RW drives
 	0003  Cardbus IDE Controller
+	0005  Cardbus SCSI CBSC II
 10fd  Soyo Computer, Inc
 10fe  Fast Multimedia AG
 10ff  NCube
@@ -3027,6 +3028,12 @@
 1144  Cincinnati Milacron
 	0001  Noservo controller
 1145  Workbit Corporation
+	f007  NinjaSCSI-32 KME
+	8007  NinjaSCSI-32 Workbit
+	f010  NinjaSCSI-32 Workbit
+	f012  NinjaSCSI-32 Logitec
+	f013  NinjaSCSI-32 Logitec
+	f015  NinjaSCSI-32 Melco
 1146  Force Computers
 1147  Interface Corp
 1148  Syskonnect (Schneider & Koch)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/pci/quirks.c linux.20pre10-ac2/drivers/pci/quirks.c
--- linux.20pre10/drivers/pci/quirks.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/pci/quirks.c	2002-09-29 20:35:39.000000000 +0100
@@ -477,6 +477,24 @@
 }
 
 /*
+ * Common misconfiguration of the MediaGX/Geode PCI master that will
+ * reduce PCI bandwidth from 70MB/s to 25MB/s.  See the GXM/GXLV/GX1
+ * datasheets found at http://www.national.com/ds/GX for info on what
+ * these bits do.  <christer@weinigel.se>
+ */
+ 
+static void __init quirk_mediagx_master(struct pci_dev *dev)
+{
+	u8 reg;
+	pci_read_config_byte(dev, 0x41, &reg);
+	if (reg & 2) {
+		reg &= ~2;
+		printk(KERN_INFO "PCI: Fixup for MediaGX/Geode Slave Disconnect Boundary (0x41=0x%02x)\n", reg);
+                pci_write_config_byte(dev, 0x41, reg);
+	}
+}
+
+/*
  *  The main table of quirks.
  */
 
@@ -538,6 +556,8 @@
 	 */
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82380FB,	quirk_transparent_bridge },
 
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_CYRIX,	PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master },
+
 	{ 0 }
 };
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/pcmcia/cardbus.c linux.20pre10-ac2/drivers/pcmcia/cardbus.c
--- linux.20pre10/drivers/pcmcia/cardbus.c	2002-10-09 21:36:54.000000000 +0100
+++ linux.20pre10-ac2/drivers/pcmcia/cardbus.c	2002-09-17 23:40:47.000000000 +0100
@@ -221,6 +221,190 @@
 	return;
 }
 
+struct pci_dev *cb_scan_slot(struct pci_dev *temp, struct list_head *list)
+{
+	struct pci_bus *bus = temp->bus;
+	struct pci_dev *dev;
+	struct pci_dev *first_dev = NULL;
+	int func = 0;
+	int is_multi = 0;
+	u8 hdr_type;
+
+	for (func = 0; func < 8; func++, temp->devfn++) {
+		if (func && !is_multi)		/* not a multi-function device */
+			continue;
+		if (pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type))
+			continue;
+		temp->hdr_type = hdr_type & 0x7f;
+
+		dev = pci_scan_device(temp);
+		if (!dev)
+			continue;
+		sprintf(dev->name, "PCI device %04x:%04x", dev->vendor, dev->device);
+		if (!func) {
+			is_multi = hdr_type & 0x80;
+			first_dev = dev;
+		}
+
+		list_add_tail(&dev->global_list, list);
+		/* Fix up broken headers */
+//FIXME		pci_fixup_device(PCI_FIXUP_HEADER, dev);
+	}
+	return first_dev;
+}
+
+static unsigned int cb_scan_new_bus(struct pci_bus *bus, int irq);
+
+static int cb_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int irq)
+{
+	unsigned int buses;
+	unsigned short cr;
+	struct pci_bus *child;
+	int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
+
+	pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
+	printk("Scanning behind PCI bridge %s, config %06x\n", dev->slot_name, buses & 0xffffff);
+	/*
+	 * We need to assign a number to this bus which we always
+	 * do in the second pass. We also keep all address decoders
+	 * on the bridge disabled during scanning.  FIXME: Why?
+	 */
+	pci_read_config_word(dev, PCI_COMMAND, &cr);
+	pci_write_config_word(dev, PCI_COMMAND, 0x0000);
+	pci_write_config_word(dev, PCI_STATUS, 0xffff);
+
+	child = pci_add_new_bus(bus, dev, ++max);
+	buses = (buses & 0xff000000)
+	      | ((unsigned int)(child->primary)     <<  0)
+	      | ((unsigned int)(child->secondary)   <<  8)
+	      | ((unsigned int)(child->subordinate) << 16);
+	/*
+	 * We need to blast all three values with a single write.
+	 */
+	pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
+	if (!is_cardbus) {
+		/* Now we can scan all subordinate buses... */
+		max = cb_scan_new_bus(child, irq);
+	} else {
+		/*
+		 * For CardBus bridges, we leave 4 bus numbers
+		 * as cards with a PCI-to-PCI bridge can be
+		 * inserted later.
+		 */
+		max += 3;
+	}
+	/*
+	 * Set the subordinate bus number to its real value.
+	 */
+	child->subordinate = max;
+	pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
+	pci_write_config_word(dev, PCI_COMMAND, cr);
+	sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
+	return max;
+}
+
+static unsigned int cb_scan_new_bus(struct pci_bus *bus, int irq)
+{
+	unsigned int devfn, max;
+	struct list_head *ln, *ln_tmp;
+	struct pci_dev *dev, dev0;
+	struct list_head found;
+	
+	INIT_LIST_HEAD(&found);
+	
+	printk("Scanning bus %02x\n", bus->number);
+	max = bus->secondary;
+
+	/* Create a device template */
+	memset(&dev0, 0, sizeof(dev0));
+	dev0.bus = bus;
+	dev0.sysdata = bus->sysdata;
+
+	/* Go find them, Rover! */
+	for (devfn = 0; devfn < 0x100; devfn += 8) {
+		dev0.devfn = devfn;
+		cb_scan_slot(&dev0, &found);
+	}
+
+	/*
+	 * After performing arch-dependent fixup of the bus, look behind
+	 * all PCI-to-PCI bridges on this bus.
+	 */
+	printk("Fixups for bus %02x\n", bus->number);
+	pci_read_bridge_bases(bus);
+
+	list_for_each_safe(ln, ln_tmp, &found)
+	{
+		int i;
+		u8 irq_pin;
+		dev = pci_dev_g(ln);
+		pci_set_power_state(dev, 0);
+		for(i=0;i<6;i++)
+		{
+			struct resource *r = dev->resource + i;
+			if(!r->start && r->end)
+				pci_assign_resource(dev, i);
+		}
+		/* Does this function have an interrupt at all? */
+		pci_readb(dev, PCI_INTERRUPT_PIN, &irq_pin);
+		if (irq_pin) {
+			dev->irq = irq;
+			pci_writeb(dev, PCI_INTERRUPT_LINE, irq);
+		}
+
+		pci_enable_device(dev); /* XXX check return */
+		pci_insert_device(dev, bus);
+		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+			max = cb_scan_bridge(bus, dev, max, irq);
+	}
+
+	/*
+	 * We've scanned the bus and so we know all about what's on
+	 * the other side of any bridges that may be on this bus plus
+	 * any devices.
+	 *
+	 * Return how far we've got finding sub-buses.
+	 */
+	printk("Bus scan for %02x returning with max=%02x\n", bus->number, max);
+	return max;
+}
+
+static int program_bridge(struct pci_dev *bridge)
+{
+	u32 l;
+	
+	/* Set up the top and bottom of the PCI I/O segment for this bus. */
+	pci_read_config_dword(bridge, PCI_IO_BASE, &l);
+	l &= 0xffff0000;
+	l |= (bridge->resource[7].start >> 8) & 0x00f0;
+	l |= bridge->resource[7].end & 0xf000;
+	pci_write_config_dword(bridge, PCI_IO_BASE, l);
+
+	/* Clear upper 16 bits of I/O base/limit. */
+	pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0);
+
+	/* Clear out the upper 32 bits of PREF base/limit. */
+	pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
+	pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
+
+	/* Set up the top and bottom of the PCI Memory segment
+	   for this bus. */
+	l = (bridge->resource[8].start >> 16) & 0xfff0;
+	l |= bridge->resource[8].end & 0xfff00000;
+	pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
+
+	/* Set up PREF base/limit. */
+	l = (bridge->resource[9].start >> 16) & 0xfff0;
+	l |= bridge->resource[9].end & 0xfff00000;
+	pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
+
+	/* FIXME - 0x0c if our ISA VGA is behind it. It looks like X
+	   can handle this itself - CHECK */
+	l = 0x04;
+	pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, l);
+}
+
+
 /*=====================================================================
 
     cb_alloc() and cb_free() allocate and free the kernel data
@@ -280,14 +464,57 @@
 		dev->hdr_type = hdr & 0x7f;
 
 		pci_setup_device(dev);
-
-		/* FIXME: Do we need to enable the expansion ROM? */
-		for (r = 0; r < 7; r++) {
-			struct resource *res = dev->resource + r;
-			if (res->flags)
-				pci_assign_resource(dev, r);
+		
+		if(dev->hdr_type == 1)
+		{
+			int max = bus->secondary;
+			int idx;
+			struct resource *res, *pres;
+			printk(KERN_INFO "Cardbus: Bridge found - we suck.\n");
+			pci_read_bridge_bases(bus);
+			for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_BRIDGE_RESOURCES + 3; idx++) {
+				res = &dev->resource[idx];
+				/* This is ugly - pci_read_bridge_bases should have
+				   done it for us. Need to find out why it doesnt
+				   before fixing it */
+				if(idx == PCI_BRIDGE_RESOURCES) 
+					res->flags = IORESOURCE_IO | PCI_IO_RANGE_TYPE_32;
+				if(idx == PCI_BRIDGE_RESOURCES+1)
+					res->flags |= IORESOURCE_MEM;
+				if(idx == PCI_BRIDGE_RESOURCES+2)
+					res->flags |= IORESOURCE_MEM|IORESOURCE_PREFETCH;
+				/* Ignore any existing values in the chip */
+				res->start = 0;
+				/* Find the parent resource */
+				pres = pci_find_parent_resource(dev, res);
+				if(!pres)
+				{
+					printk(KERN_ERR "No parent resource for %lx\n", res->flags);
+					continue;
+				}
+				printk(KERN_ERR "Allocating for type %lx, in bus resource.\n", res->flags);
+				/* Hog the entire space */
+				res->start = pres->start;
+				if(idx != PCI_BRIDGE_RESOURCES)
+					res->end = pres->end;
+				else	/* Still working this out - FIXME */
+					res->end = res->start + 255;
+				if (!pres || request_resource(pres, res) < 0)
+					printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, dev->slot_name);
+			}
+			program_bridge(dev);
+			max = cb_scan_bridge(bus, dev, max, irq);
+			printk(KERN_INFO "Cardbus: Bridge scanned.\n");
+		}
+		else
+		{			
+			/* FIXME: Do we need to enable the expansion ROM? */
+			for (r = 0; r < 7; r++) {
+				struct resource *res = dev->resource + r;
+				if (res->flags)
+					pci_assign_resource(dev, r);
+			}
 		}
-
 		/* Does this function have an interrupt at all? */
 		pci_readb(dev, PCI_INTERRUPT_PIN, &irq_pin);
 		if (irq_pin) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/pcmcia/i82092.c linux.20pre10-ac2/drivers/pcmcia/i82092.c
--- linux.20pre10/drivers/pcmcia/i82092.c	2002-10-09 21:36:54.000000000 +0100
+++ linux.20pre10-ac2/drivers/pcmcia/i82092.c	2002-09-29 20:32:03.000000000 +0100
@@ -25,6 +25,8 @@
 #include "i82092aa.h"
 #include "i82365.h"
 
+MODULE_LICENSE("GPL");
+
 /* PCI core routines */
 static struct pci_device_id i82092aa_pci_ids[] = {
 	{
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/pcmcia/yenta.c linux.20pre10-ac2/drivers/pcmcia/yenta.c
--- linux.20pre10/drivers/pcmcia/yenta.c	2002-10-09 21:36:54.000000000 +0100
+++ linux.20pre10-ac2/drivers/pcmcia/yenta.c	2002-08-26 14:27:29.000000000 +0100
@@ -2,6 +2,11 @@
  * Regular lowlevel cardbus driver ("yenta")
  *
  * (C) Copyright 1999, 2000 Linus Torvalds
+ *
+ * Changelog:
+ * Aug 2002: Manfred Spraul <manfred@colorfullife.com>
+ * 	Dynamically adjust the size of the bridge resource
+ * 	
  */
 #include <linux/init.h>
 #include <linux/pci.h>
@@ -704,6 +709,15 @@
 	return 0;
 }
 
+/*
+ * Use an adaptive allocation for the memory resource,
+ * sometimes the size behind pci bridges is limited:
+ * 1/8 of the size of the io window of the parent.
+ * max 4 MB, min 16 kB.
+ */
+#define BRIDGE_SIZE_MAX	4*1024*1024
+#define BRIDGE_SIZE_MIN	16*1024
+
 static void yenta_allocate_res(pci_socket_t *socket, int nr, unsigned type)
 {
 	struct pci_bus *bus;
@@ -735,21 +749,42 @@
 	if (start && end > start) {
 		res->start = start;
 		res->end = end;
-		request_resource(root, res);
-		return;
+		if (request_resource(root, res) == 0)
+			return;
+		printk(KERN_INFO "yenta %s: Preassigned resource %d busy, reconfiguring...\n",
+				socket->dev->slot_name, nr);
+		res->start = res->end = 0;
 	}
 
-	align = size = 4*1024*1024;
-	min = PCIBIOS_MIN_MEM; max = ~0U;
 	if (type & IORESOURCE_IO) {
 		align = 1024;
 		size = 256;
 		min = 0x4000;
 		max = 0xffff;
+	} else {
+		unsigned long avail = root->end - root->start;
+		int i;
+		align = size = BRIDGE_SIZE_MAX;
+		if (size > avail/8) {
+			size=(avail+1)/8;
+			/* round size down to next power of 2 */
+			i = 0;
+			while ((size /= 2) != 0)
+				i++;
+			size = 1 << i;
+		}
+		if (size < BRIDGE_SIZE_MIN)
+			size = BRIDGE_SIZE_MIN;
+		align = size;
+		min = PCIBIOS_MIN_MEM; max = ~0U;
 	}
 		
-	if (allocate_resource(root, res, size, min, max, align, NULL, NULL) < 0)
+	if (allocate_resource(root, res, size, min, max, align, NULL, NULL) < 0) {
+		printk(KERN_INFO "yenta %s: no resource of type %x available, trying to continue...\n",
+				socket->dev->slot_name, type);
+		res->start = res->end = 0;
 		return;
+	}
 
 	config_writel(socket, offset, res->start);
 	config_writel(socket, offset+4, res->end);
@@ -767,6 +802,20 @@
 }
 
 /*
+ * Free the bridge mappings for the device..
+ */
+static void yenta_free_resources(pci_socket_t *socket)
+{
+	int i;
+	for (i=0;i<4;i++) {
+		struct resource *res;
+		res = socket->dev->resource + PCI_BRIDGE_RESOURCES + i;
+		if (res->start != 0 && res->end != 0)
+			release_resource(res);
+		res->start = res->end = 0;
+	}
+}
+/*
  * Close it down - release our resources and go home..
  */
 static void yenta_close(pci_socket_t *sock)
@@ -782,6 +831,7 @@
 
 	if (sock->base)
 		iounmap(sock->base);
+	yenta_free_resources(sock);
 }
 
 #include "ti113x.h"
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/pnp/Config.in linux.20pre10-ac2/drivers/pnp/Config.in
--- linux.20pre10/drivers/pnp/Config.in	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/pnp/Config.in	2002-08-06 15:42:11.000000000 +0100
@@ -8,4 +8,8 @@
 
 dep_tristate '  ISA Plug and Play support' CONFIG_ISAPNP $CONFIG_PNP
 
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   dep_bool '  PNPBIOS support (EXPERIMENTAL)' CONFIG_PNPBIOS $CONFIG_PNP
+fi
+
 endmenu
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/pnp/isapnp.c linux.20pre10-ac2/drivers/pnp/isapnp.c
--- linux.20pre10/drivers/pnp/isapnp.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/pnp/isapnp.c	2002-09-29 20:33:20.000000000 +0100
@@ -1049,11 +1049,19 @@
 	isapnp_wait();
 	isapnp_key();
 	isapnp_wake(csn);
-#if 1	/* to avoid malfunction when the isapnptools package is used */
-	isapnp_set_rdp();
-	udelay(1000);	/* delay 1000us */
-	write_address(0x01);
-	udelay(1000);	/* delay 1000us */
+#if 1
+	/* to avoid malfunction when the isapnptools package is used */
+	/* we must set RDP to our value again */
+	/* it is possible to set RDP only in the isolation phase */ 
+	/*   Jens Thoms Toerring <Jens.Toerring@physik.fu-berlin.de> */
+	isapnp_write_byte(0x02, 0x04);	/* clear CSN of card */
+	mdelay(2);			/* is this necessary? */
+	isapnp_wake(csn);		/* bring card into sleep state */
+	isapnp_wake(0);			/* bring card into isolation state */
+	isapnp_set_rdp();		/* reset the RDP port */
+	udelay(1000);			/* delay 1000us */
+	isapnp_write_byte(0x06, csn);	/* reset CSN to previous value */
+	udelay(250);			/* is this necessary? */
 #endif
 	if (logdev >= 0)
 		isapnp_device(logdev);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/pnp/Makefile linux.20pre10-ac2/drivers/pnp/Makefile
--- linux.20pre10/drivers/pnp/Makefile	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/pnp/Makefile	2002-08-06 15:42:11.000000000 +0100
@@ -10,15 +10,22 @@
 
 O_TARGET := pnp.o
 
-export-objs := isapnp.o
-list-multi := isa-pnp.o
+export-objs := isapnp.o pnpbios_core.o
+multi-objs := isa-pnp.o pnpbios.o
 
-proc-$(CONFIG_PROC_FS) = isapnp_proc.o
-isa-pnp-objs := isapnp.o quirks.o $(proc-y)
+isa-pnp-proc-$(CONFIG_PROC_FS) = isapnp_proc.o
+pnpbios-proc-$(CONFIG_PROC_FS) = pnpbios_proc.o
+
+isa-pnp-objs := isapnp.o quirks.o $(isa-pnp-proc-y)
+pnpbios-objs := pnpbios_core.o $(pnpbios-proc-y)
 
 obj-$(CONFIG_ISAPNP) += isa-pnp.o
+obj-$(CONFIG_PNPBIOS) += pnpbios.o
 
 include $(TOPDIR)/Rules.make
 
 isa-pnp.o: $(isa-pnp-objs)
 	$(LD) $(LD_RFLAG) -r -o $@ $(isa-pnp-objs)
+
+pnpbios.o: $(pnpbios-objs)
+	$(LD) $(LD_RFLAG) -r -o $@ $(pnpbios-objs)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/pnp/pnpbios_core.c linux.20pre10-ac2/drivers/pnp/pnpbios_core.c
--- linux.20pre10/drivers/pnp/pnpbios_core.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/pnp/pnpbios_core.c	2002-08-06 15:42:11.000000000 +0100
@@ -0,0 +1,1352 @@
+/*
+ * PnP BIOS services
+ * 
+ * Originally (C) 1998 Christian Schmidt <schmidt@digadd.de>
+ * Modifications (c) 1998 Tom Lees <tom@lpsg.demon.co.uk>
+ * Minor reorganizations by David Hinds <dahinds@users.sourceforge.net>
+ * Modifications (c) 2001,2002 by Thomas Hood <jdthood@mail.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, 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
+ *
+ * References:
+ *   Compaq Computer Corporation, Phoenix Technologies Ltd., Intel Corporation
+ *   Plug and Play BIOS Specification, Version 1.0A, May 5, 1994
+ *   Plug and Play BIOS Clarification Paper, October 6, 1994
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/kernel.h>
+#include <linux/pnpbios.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <asm/desc.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/kmod.h>
+#include <linux/completion.h>
+#include <linux/spinlock.h>
+#include <asm/system.h>
+
+
+/*
+ *
+ * PnP BIOS INTERFACE
+ *
+ */
+
+/* PnP BIOS signature: "$PnP" */
+#define PNP_SIGNATURE   (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24))
+
+#pragma pack(1)
+union pnp_bios_expansion_header {
+	struct {
+		u32 signature;    /* "$PnP" */
+		u8 version;	  /* in BCD */
+		u8 length;	  /* length in bytes, currently 21h */
+		u16 control;	  /* system capabilities */
+		u8 checksum;	  /* all bytes must add up to 0 */
+
+		u32 eventflag;    /* phys. address of the event flag */
+		u16 rmoffset;     /* real mode entry point */
+		u16 rmcseg;
+		u16 pm16offset;   /* 16 bit protected mode entry */
+		u32 pm16cseg;
+		u32 deviceID;	  /* EISA encoded system ID or 0 */
+		u16 rmdseg;	  /* real mode data segment */
+		u32 pm16dseg;	  /* 16 bit pm data segment base */
+	} fields;
+	char chars[0x21];	  /* To calculate the checksum */
+};
+#pragma pack()
+
+static struct {
+	u16	offset;
+	u16	segment;
+} pnp_bios_callpoint;
+
+static union pnp_bios_expansion_header * pnp_bios_hdr = NULL;
+
+/* The PnP BIOS entries in the GDT */
+#define PNP_GDT    (0x0060)
+#define PNP_CS32   (PNP_GDT+0x00)	/* segment for calling fn */
+#define PNP_CS16   (PNP_GDT+0x08)	/* code segment for BIOS */
+#define PNP_DS     (PNP_GDT+0x10)	/* data segment for BIOS */
+#define PNP_TS1    (PNP_GDT+0x18)	/* transfer data segment */
+#define PNP_TS2    (PNP_GDT+0x20)	/* another data segment */
+
+/* 
+ * These are some opcodes for a "static asmlinkage"
+ * As this code is *not* executed inside the linux kernel segment, but in a
+ * alias at offset 0, we need a far return that can not be compiled by
+ * default (please, prove me wrong! this is *really* ugly!) 
+ * This is the only way to get the bios to return into the kernel code,
+ * because the bios code runs in 16 bit protected mode and therefore can only
+ * return to the caller if the call is within the first 64kB, and the linux
+ * kernel begins at offset 3GB...
+ */
+
+asmlinkage void pnp_bios_callfunc(void);
+
+__asm__(
+	".text			\n"
+	__ALIGN_STR "\n"
+	SYMBOL_NAME_STR(pnp_bios_callfunc) ":\n"
+	"	pushl %edx	\n"
+	"	pushl %ecx	\n"
+	"	pushl %ebx	\n"
+	"	pushl %eax	\n"
+	"	lcallw " SYMBOL_NAME_STR(pnp_bios_callpoint) "\n"
+	"	addl $16, %esp	\n"
+	"	lret		\n"
+	".previous		\n"
+);
+
+#define Q_SET_SEL(selname, address, size) \
+set_base (gdt [(selname) >> 3], __va((u32)(address))); \
+set_limit (gdt [(selname) >> 3], size)
+
+#define Q2_SET_SEL(selname, address, size) \
+set_base (gdt [(selname) >> 3], (u32)(address)); \
+set_limit (gdt [(selname) >> 3], size)
+
+/*
+ * At some point we want to use this stack frame pointer to unwind
+ * after PnP BIOS oopses. 
+ */
+ 
+u32 pnp_bios_fault_esp;
+u32 pnp_bios_fault_eip;
+u32 pnp_bios_is_utter_crap = 0;
+
+static spinlock_t pnp_bios_lock;
+
+static inline u16 call_pnp_bios(u16 func, u16 arg1, u16 arg2, u16 arg3,
+                                u16 arg4, u16 arg5, u16 arg6, u16 arg7,
+                                void *ts1_base, u32 ts1_size,
+                                void *ts2_base, u32 ts2_size)
+{
+	unsigned long flags;
+	u16 status;
+
+	/*
+	 * PnP BIOSes are generally not terribly re-entrant.
+	 * Also, don't rely on them to save everything correctly.
+	 */
+	if(pnp_bios_is_utter_crap)
+		return PNP_FUNCTION_NOT_SUPPORTED;
+
+	/* On some boxes IRQ's during PnP BIOS calls are deadly.  */
+	spin_lock_irqsave(&pnp_bios_lock, flags);
+
+	if (ts1_size)
+		Q2_SET_SEL(PNP_TS1, ts1_base, ts1_size);
+	if (ts2_size)
+		Q2_SET_SEL(PNP_TS2, ts2_base, ts2_size);
+
+	__asm__ __volatile__(
+	        "pushl %%ebp\n\t"
+		"pushl %%edi\n\t"
+		"pushl %%esi\n\t"
+		"pushl %%ds\n\t"
+		"pushl %%es\n\t"
+		"pushl %%fs\n\t"
+		"pushl %%gs\n\t"
+		"pushfl\n\t"
+		"movl %%esp, pnp_bios_fault_esp\n\t"
+		"movl $1f, pnp_bios_fault_eip\n\t"
+		"lcall %5,%6\n\t"
+		"1:popfl\n\t"
+		"popl %%gs\n\t"
+		"popl %%fs\n\t"
+		"popl %%es\n\t"
+		"popl %%ds\n\t"
+	        "popl %%esi\n\t"
+		"popl %%edi\n\t"
+		"popl %%ebp\n\t"
+		: "=a" (status)
+		: "0" ((func) | (((u32)arg1) << 16)),
+		  "b" ((arg2) | (((u32)arg3) << 16)),
+		  "c" ((arg4) | (((u32)arg5) << 16)),
+		  "d" ((arg6) | (((u32)arg7) << 16)),
+		  "i" (PNP_CS32),
+		  "i" (0)
+		: "memory"
+	);
+	spin_unlock_irqrestore(&pnp_bios_lock, flags);
+	
+	/* If we get here and this is set then the PnP BIOS faulted on us. */
+	if(pnp_bios_is_utter_crap)
+	{
+		printk(KERN_ERR "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue.\n");
+		printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"pnpbios=off\" option to operate stably.\n");
+		printk(KERN_ERR "PnPBIOS: Check with your vendor for an updated BIOS.\n");
+	}
+
+	return status;
+}
+
+
+/*
+ *
+ * UTILITY FUNCTIONS
+ *
+ */
+
+static void pnpbios_warn_unexpected_status(const char * module, u16 status)
+{
+	printk(KERN_ERR "PnPBIOS: %s: Unexpected status 0x%x\n", module, status);
+}
+
+void *pnpbios_kmalloc(size_t size, int f)
+{
+	void *p = kmalloc( size, f );
+	if ( p == NULL )
+		printk(KERN_ERR "PnPBIOS: kmalloc() failed\n");
+	return p;
+}
+
+/*
+ * Call this only after init time
+ */
+static inline int pnp_bios_present(void)
+{
+	return (pnp_bios_hdr != NULL);
+}
+
+/* Forward declaration */
+static void update_devlist( u8 nodenum, struct pnp_bios_node *data );
+
+
+/*
+ *
+ * PnP BIOS ACCESS FUNCTIONS
+ *
+ */
+
+#define PNP_GET_NUM_SYS_DEV_NODES       0x00
+#define PNP_GET_SYS_DEV_NODE            0x01
+#define PNP_SET_SYS_DEV_NODE            0x02
+#define PNP_GET_EVENT                   0x03
+#define PNP_SEND_MESSAGE                0x04
+#define PNP_GET_DOCKING_STATION_INFORMATION 0x05
+#define PNP_SET_STATIC_ALLOCED_RES_INFO 0x09
+#define PNP_GET_STATIC_ALLOCED_RES_INFO 0x0a
+#define PNP_GET_APM_ID_TABLE            0x0b
+#define PNP_GET_PNP_ISA_CONFIG_STRUC    0x40
+#define PNP_GET_ESCD_INFO               0x41
+#define PNP_READ_ESCD                   0x42
+#define PNP_WRITE_ESCD                  0x43
+
+/*
+ * Call PnP BIOS with function 0x00, "get number of system device nodes"
+ */
+static int __pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
+{
+	u16 status;
+	if (!pnp_bios_present())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2, PNP_TS1, PNP_DS, 0, 0,
+			       data, sizeof(struct pnp_dev_node_info), 0, 0);
+	data->no_nodes &= 0xff;
+	return status;
+}
+
+int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
+{
+	int status = __pnp_bios_dev_node_info( data );
+	if ( status )
+		pnpbios_warn_unexpected_status( "dev_node_info", status );
+	return status;
+}
+
+/*
+ * Note that some PnP BIOSes (e.g., on Sony Vaio laptops) die a horrible
+ * death if they are asked to access the "current" configuration.
+ * Therefore, if it's a matter of indifference, it's better to call
+ * get_dev_node() and set_dev_node() with boot=1 rather than with boot=0.
+ */
+
+/* 
+ * Call PnP BIOS with function 0x01, "get system device node"
+ * Input: *nodenum = desired node, 
+ *        boot = whether to get nonvolatile boot (!=0)
+ *               or volatile current (0) config
+ * Output: *nodenum=next node or 0xff if no more nodes
+ */
+static int __pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
+{
+	u16 status;
+	if (!pnp_bios_present())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	if ( !boot & pnpbios_dont_use_current_config )
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2, boot ? 2 : 1, PNP_DS, 0,
+			       nodenum, sizeof(char), data, 65536);
+	return status;
+}
+
+int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
+{
+	int status;
+	status =  __pnp_bios_get_dev_node( nodenum, boot, data );
+	if ( status )
+		pnpbios_warn_unexpected_status( "get_dev_node", status );
+	return status;
+}
+
+
+/*
+ * Call PnP BIOS with function 0x02, "set system device node"
+ * Input: *nodenum = desired node, 
+ *        boot = whether to set nonvolatile boot (!=0)
+ *               or volatile current (0) config
+ */
+static int __pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
+{
+	u16 status;
+	if (!pnp_bios_present())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	if ( !boot & pnpbios_dont_use_current_config )
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1, boot ? 2 : 1, PNP_DS, 0, 0,
+			       data, 65536, 0, 0);
+	return status;
+}
+
+int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
+{
+	int status;
+	status =  __pnp_bios_set_dev_node( nodenum, boot, data );
+	if ( status ) {
+		pnpbios_warn_unexpected_status( "set_dev_node", status );
+		return status;
+	}
+	if ( !boot ) { /* Update devlist */
+		u8 thisnodenum = nodenum;
+		status =  pnp_bios_get_dev_node( &nodenum, boot, data );
+		if ( status )
+			return status;
+		update_devlist( thisnodenum, data );
+	}
+	return status;
+}
+
+#if needed
+/*
+ * Call PnP BIOS with function 0x03, "get event"
+ */
+static int pnp_bios_get_event(u16 *event)
+{
+	u16 status;
+	if (!pnp_bios_present())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	status = call_pnp_bios(PNP_GET_EVENT, 0, PNP_TS1, PNP_DS, 0, 0 ,0 ,0,
+			       event, sizeof(u16), 0, 0);
+	return status;
+}
+#endif
+
+#if needed
+/* 
+ * Call PnP BIOS with function 0x04, "send message"
+ */
+static int pnp_bios_send_message(u16 message)
+{
+	u16 status;
+	if (!pnp_bios_present())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	status = call_pnp_bios(PNP_SEND_MESSAGE, message, PNP_DS, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+	return status;
+}
+#endif
+
+#ifdef CONFIG_HOTPLUG
+/*
+ * Call PnP BIOS with function 0x05, "get docking station information"
+ */
+static int pnp_bios_dock_station_info(struct pnp_docking_station_info *data)
+{
+	u16 status;
+	if (!pnp_bios_present())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
+			       data, sizeof(struct pnp_docking_station_info), 0, 0);
+	return status;
+}
+#endif
+
+#if needed
+/*
+ * Call PnP BIOS with function 0x09, "set statically allocated resource
+ * information"
+ */
+static int pnp_bios_set_stat_res(char *info)
+{
+	u16 status;
+	if (!pnp_bios_present())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	status = call_pnp_bios(PNP_SET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
+			       info, *((u16 *) info), 0, 0);
+	return status;
+}
+#endif
+
+/*
+ * Call PnP BIOS with function 0x0a, "get statically allocated resource
+ * information"
+ */
+static int __pnp_bios_get_stat_res(char *info)
+{
+	u16 status;
+	if (!pnp_bios_present())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
+			       info, 65536, 0, 0);
+	return status;
+}
+
+int pnp_bios_get_stat_res(char *info)
+{
+	int status;
+	status = __pnp_bios_get_stat_res( info );
+	if ( status )
+		pnpbios_warn_unexpected_status( "get_stat_res", status );
+	return status;
+}
+
+#if needed
+/*
+ * Call PnP BIOS with function 0x0b, "get APM id table"
+ */
+static int pnp_bios_apm_id_table(char *table, u16 *size)
+{
+	u16 status;
+	if (!pnp_bios_present())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	status = call_pnp_bios(PNP_GET_APM_ID_TABLE, 0, PNP_TS2, 0, PNP_TS1, PNP_DS, 0, 0,
+			       table, *size, size, sizeof(u16));
+	return status;
+}
+#endif
+
+/*
+ * Call PnP BIOS with function 0x40, "get isa pnp configuration structure"
+ */
+static int __pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
+{
+	u16 status;
+	if (!pnp_bios_present())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
+			       data, sizeof(struct pnp_isa_config_struc), 0, 0);
+	return status;
+}
+
+int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
+{
+	int status;
+	status = __pnp_bios_isapnp_config( data );
+	if ( status )
+		pnpbios_warn_unexpected_status( "isapnp_config", status );
+	return status;
+}
+
+/*
+ * Call PnP BIOS with function 0x41, "get ESCD info"
+ */
+static int __pnp_bios_escd_info(struct escd_info_struc *data)
+{
+	u16 status;
+	if (!pnp_bios_present())
+		return ESCD_FUNCTION_NOT_SUPPORTED;
+	status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4, PNP_TS1, PNP_DS,
+			       data, sizeof(struct escd_info_struc), 0, 0);
+	return status;
+}
+
+int pnp_bios_escd_info(struct escd_info_struc *data)
+{
+	int status;
+	status = __pnp_bios_escd_info( data );
+	if ( status )
+		pnpbios_warn_unexpected_status( "escd_info", status );
+	return status;
+}
+
+/*
+ * Call PnP BIOS function 0x42, "read ESCD"
+ * nvram_base is determined by calling escd_info
+ */
+static int __pnp_bios_read_escd(char *data, u32 nvram_base)
+{
+	u16 status;
+	if (!pnp_bios_present())
+		return ESCD_FUNCTION_NOT_SUPPORTED;
+	status = call_pnp_bios(PNP_READ_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0,
+			       data, 65536, (void *)nvram_base, 65536);
+	return status;
+}
+
+int pnp_bios_read_escd(char *data, u32 nvram_base)
+{
+	int status;
+	status = __pnp_bios_read_escd( data, nvram_base );
+	if ( status )
+		pnpbios_warn_unexpected_status( "read_escd", status );
+	return status;
+}
+
+#if needed
+/*
+ * Call PnP BIOS function 0x43, "write ESCD"
+ */
+static int pnp_bios_write_escd(char *data, u32 nvram_base)
+{
+	u16 status;
+	if (!pnp_bios_present())
+		return ESCD_FUNCTION_NOT_SUPPORTED;
+	status = call_pnp_bios(PNP_WRITE_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0,
+			       data, 65536, nvram_base, 65536);
+	return status;
+}
+#endif
+
+
+/*
+ *
+ * DOCKING FUNCTIONS
+ *
+ */
+
+#ifdef CONFIG_HOTPLUG
+
+static int unloading = 0;
+static struct completion unload_sem;
+
+/*
+ * (Much of this belongs in a shared routine somewhere)
+ */
+ 
+static int pnp_dock_event(int dock, struct pnp_docking_station_info *info)
+{
+	char *argv [3], **envp, *buf, *scratch;
+	int i = 0, value;
+
+	if (!hotplug_path [0])
+		return -ENOENT;
+	if (!current->fs->root) {
+		return -EAGAIN;
+	}
+	if (!(envp = (char **) pnpbios_kmalloc (20 * sizeof (char *), GFP_KERNEL))) {
+		return -ENOMEM;
+	}
+	if (!(buf = pnpbios_kmalloc (256, GFP_KERNEL))) {
+		kfree (envp);
+		return -ENOMEM;
+	}
+
+	/* only one standardized param to hotplug command: type */
+	argv [0] = hotplug_path;
+	argv [1] = "dock";
+	argv [2] = 0;
+
+	/* minimal command environment */
+	envp [i++] = "HOME=/";
+	envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+
+#ifdef	DEBUG
+	/* hint that policy agent should enter no-stdout debug mode */
+	envp [i++] = "DEBUG=kernel";
+#endif
+	/* extensible set of named bus-specific parameters,
+	 * supporting multiple driver selection algorithms.
+	 */
+	scratch = buf;
+
+	/* action:  add, remove */
+	envp [i++] = scratch;
+	scratch += sprintf (scratch, "ACTION=%s", dock?"add":"remove") + 1;
+
+	/* Report the ident for the dock */
+	envp [i++] = scratch;
+	scratch += sprintf (scratch, "DOCK=%x/%x/%x",
+		info->location_id, info->serial, info->capabilities);
+	envp[i] = 0;
+	
+	value = call_usermodehelper (argv [0], argv, envp);
+	kfree (buf);
+	kfree (envp);
+	return 0;
+}
+
+/*
+ * Poll the PnP docking at regular intervals
+ */
+static int pnp_dock_thread(void * unused)
+{
+	static struct pnp_docking_station_info now;
+	int docked = -1, d = 0;
+	daemonize();
+	reparent_to_init();
+	strcpy(current->comm, "kpnpbiosd");
+	while(!unloading && !signal_pending(current))
+	{
+		int status;
+		
+		/*
+		 * Poll every 2 seconds
+		 */
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ*2);
+		if(signal_pending(current))
+			break;
+
+		status = pnp_bios_dock_station_info(&now);
+
+		switch(status)
+		{
+			/*
+			 * No dock to manage
+			 */
+			case PNP_FUNCTION_NOT_SUPPORTED:
+				complete_and_exit(&unload_sem, 0);
+			case PNP_SYSTEM_NOT_DOCKED:
+				d = 0;
+				break;
+			case PNP_SUCCESS:
+				d = 1;
+				break;
+			default:
+				pnpbios_warn_unexpected_status( "pnp_dock_thread", status );
+				continue;
+		}
+		if(d != docked)
+		{
+			if(pnp_dock_event(d, &now)==0)
+			{
+				docked = d;
+#if 0
+				printk(KERN_INFO "PnPBIOS: Docking station %stached\n", docked?"at":"de");
+#endif
+			}
+		}
+	}	
+	complete_and_exit(&unload_sem, 0);
+}
+
+#endif   /* CONFIG_HOTPLUG */
+
+
+/*
+ *
+ * NODE DATA PARSING FUNCTIONS
+ *
+ */
+
+static void add_irqresource(struct pci_dev *dev, int irq)
+{
+	int i = 0;
+	while (!(dev->irq_resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_IRQ) i++;
+	if (i < DEVICE_COUNT_IRQ) {
+		dev->irq_resource[i].start = (unsigned long) irq;
+		dev->irq_resource[i].flags = IORESOURCE_IRQ;  // Also clears _UNSET flag
+	}
+}
+
+static void add_dmaresource(struct pci_dev *dev, int dma)
+{
+	int i = 0;
+	while (!(dev->dma_resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_DMA) i++;
+	if (i < DEVICE_COUNT_DMA) {
+		dev->dma_resource[i].start = (unsigned long) dma;
+		dev->dma_resource[i].flags = IORESOURCE_DMA;  // Also clears _UNSET flag
+	}
+}
+
+static void add_ioresource(struct pci_dev *dev, int io, int len)
+{
+	int i = 0;
+	while (!(dev->resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_RESOURCE) i++;
+	if (i < DEVICE_COUNT_RESOURCE) {
+		dev->resource[i].start = (unsigned long) io;
+		dev->resource[i].end = (unsigned long)(io + len - 1);
+		dev->resource[i].flags = IORESOURCE_IO;  // Also clears _UNSET flag
+	}
+}
+
+static void add_memresource(struct pci_dev *dev, int mem, int len)
+{
+	int i = 0;
+	while (!(dev->resource[i].flags & IORESOURCE_UNSET) && i < DEVICE_COUNT_RESOURCE) i++;
+	if (i < DEVICE_COUNT_RESOURCE) {
+		dev->resource[i].start = (unsigned long) mem;
+		dev->resource[i].end = (unsigned long)(mem + len - 1);
+		dev->resource[i].flags = IORESOURCE_MEM;  // Also clears _UNSET flag
+	}
+}
+
+static void node_resource_data_to_dev(struct pnp_bios_node *node, struct pci_dev *dev)
+{
+	unsigned char *p = node->data, *lastp=NULL;
+	int i;
+
+	/*
+	 * First, set resource info to default values
+	 */
+	for (i=0;i<DEVICE_COUNT_RESOURCE;i++) {
+		dev->resource[i].start = 0;  // "disabled"
+		dev->resource[i].flags = IORESOURCE_UNSET;
+	}
+	for (i=0;i<DEVICE_COUNT_IRQ;i++) {
+		dev->irq_resource[i].start = (unsigned long)-1;  // "disabled"
+		dev->irq_resource[i].flags = IORESOURCE_UNSET;
+	}
+	for (i=0;i<DEVICE_COUNT_DMA;i++) {
+		dev->dma_resource[i].start = (unsigned long)-1;  // "disabled"
+		dev->dma_resource[i].flags = IORESOURCE_UNSET;
+	}
+
+	/*
+	 * Fill in dev resource info
+	 */
+        while ( (char *)p < ((char *)node->data + node->size )) {
+        	if(p==lastp) break;
+
+                if( p[0] & 0x80 ) {// large item
+			switch (p[0] & 0x7f) {
+			case 0x01: // memory
+			{
+				int io = *(short *) &p[4];
+				int len = *(short *) &p[10];
+				add_memresource(dev, io, len);
+				break;
+			}
+			case 0x02: // device name
+			{
+				int len = *(short *) &p[1];
+				memcpy(dev->name, p + 3, len >= 80 ? 79 : len);
+				break;
+			}
+			case 0x05: // 32-bit memory
+			{
+				int io = *(int *) &p[4];
+				int len = *(int *) &p[16];
+				add_memresource(dev, io, len);
+				break;
+			}
+			case 0x06: // fixed location 32-bit memory
+			{
+				int io = *(int *) &p[4];
+				int len = *(int *) &p[8];
+				add_memresource(dev, io, len);
+				break;
+			}
+			} /* switch */
+                        lastp = p+3;
+                        p = p + p[1] + p[2]*256 + 3;
+                        continue;
+                }
+                if ((p[0]>>3) == 0x0f) // end tag
+                        break;
+                switch (p[0]>>3) {
+                case 0x04: // irq
+                {
+                        int i, mask, irq = -1;
+                        mask= p[1] + p[2]*256;
+                        for (i=0;i<16;i++, mask=mask>>1)
+                                if(mask & 0x01) irq=i;
+			add_irqresource(dev, irq);
+                        break;
+                }
+                case 0x05: // dma
+                {
+                        int i, mask, dma = -1;
+                        mask = p[1];
+                        for (i=0;i<8;i++, mask = mask>>1)
+                                if(mask & 0x01) dma=i;
+			add_dmaresource(dev, dma);
+                        break;
+                }
+                case 0x08: // io
+                {
+			int io= p[2] + p[3] *256;
+			int len = p[7];
+			add_ioresource(dev, io, len);
+                        break;
+                }
+		case 0x09: // fixed location io
+		{
+			int io = p[1] + p[2] * 256;
+			int len = p[3];
+			add_ioresource(dev, io, len);
+			break;
+		}
+                } /* switch */
+                lastp=p+1;
+                p = p + (p[0] & 0x07) + 1;
+
+        } /* while */
+
+        return;
+}
+
+
+/*
+ *
+ * DEVICE LIST MANAGEMENT FUNCTIONS
+ *
+ *
+ * Some of these are exported to give public access
+ *
+ * Question: Why maintain a device list when the PnP BIOS can 
+ * list devices for us?  Answer: Some PnP BIOSes can't report
+ * the current configuration, only the boot configuration.
+ * The boot configuration can be changed, so we need to keep
+ * a record of what the configuration was when we booted;
+ * presumably it continues to describe the current config.
+ * For those BIOSes that can change the current config, we
+ * keep the information in the devlist up to date.
+ *
+ * Note that it is currently assumed that the list does not
+ * grow or shrink in size after init time, and slot_name
+ * never changes.  The list is protected by a spinlock.
+ */
+
+static LIST_HEAD(pnpbios_devices);
+
+static spinlock_t pnpbios_devices_lock;
+
+static int inline insert_device(struct pci_dev *dev)
+{
+
+	/*
+	 * FIXME: Check for re-add of existing node;
+	 * return -1 if node already present
+	 */
+
+	/* We don't lock because we only do this at init time */
+	list_add_tail(&dev->global_list, &pnpbios_devices);
+
+	return 0;
+}
+
+#define HEX(id,a) hex[((id)>>a) & 15]
+#define CHAR(id,a) (0x40 + (((id)>>a) & 31))
+//
+static void inline pnpid32_to_pnpid(u32 id, char *str)
+{
+	const char *hex = "0123456789abcdef";
+
+	id = be32_to_cpu(id);
+	str[0] = CHAR(id, 26);
+	str[1] = CHAR(id, 21);
+	str[2] = CHAR(id,16);
+	str[3] = HEX(id, 12);
+	str[4] = HEX(id, 8);
+	str[5] = HEX(id, 4);
+	str[6] = HEX(id, 0);
+	str[7] = '\0';
+
+	return;
+}                                              
+//
+#undef CHAR
+#undef HEX 
+
+/*
+ * Build a linked list of pci_devs in order of ascending node number
+ * Called only at init time.
+ */
+static void __init build_devlist(void)
+{
+	u8 nodenum;
+	unsigned int nodes_got = 0;
+	unsigned int devs = 0;
+	struct pnp_bios_node *node;
+	struct pnp_dev_node_info node_info;
+	struct pci_dev *dev;
+	
+	if (!pnp_bios_present())
+		return;
+
+	if (pnp_bios_dev_node_info(&node_info) != 0)
+		return;
+
+	node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+	if (!node)
+		return;
+
+	for(nodenum=0; nodenum<0xff; ) {
+		u8 thisnodenum = nodenum;
+		/* We build the list from the "boot" config because
+		 * asking for the "current" config causes some
+		 * BIOSes to crash.
+		 */
+		if (pnp_bios_get_dev_node(&nodenum, (char )1 , node))
+			break;
+		nodes_got++;
+		dev =  pnpbios_kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
+		if (!dev)
+			break;
+		memset(dev,0,sizeof(struct pci_dev));
+		dev->devfn = thisnodenum;
+		memcpy(dev->name,"PNPBIOS",8);
+		pnpid32_to_pnpid(node->eisa_id,dev->slot_name);
+		node_resource_data_to_dev(node,dev);
+		if(insert_device(dev)<0)
+			kfree(dev);
+		else
+			devs++;
+		if (nodenum <= thisnodenum) {
+			printk(KERN_ERR "PnPBIOS: build_devlist: Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", (unsigned int)nodenum, (unsigned int)thisnodenum);
+			break;
+		}
+	}
+	kfree(node);
+
+	printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver\n",
+		nodes_got, nodes_got != 1 ? "s" : "", devs);
+}
+
+static struct pci_dev *find_device_by_nodenum( u8 nodenum )
+{
+	struct pci_dev *dev;
+
+	pnpbios_for_each_dev(dev) {
+		if(dev->devfn == nodenum)
+			return dev;
+	}
+
+	return NULL;
+}
+
+static void update_devlist( u8 nodenum, struct pnp_bios_node *data )
+{
+	unsigned long flags;
+	struct pci_dev *dev;
+
+	spin_lock_irqsave(&pnpbios_devices_lock, flags);
+	dev = find_device_by_nodenum( nodenum );
+	if ( dev ) {
+		node_resource_data_to_dev(data,dev);
+	}
+	spin_unlock_irqrestore(&pnpbios_devices_lock, flags);
+
+	return;
+}
+
+
+/*
+ *
+ * DRIVER REGISTRATION FUNCTIONS
+ *
+ *
+ * Exported to give public access
+ *
+ */
+
+static LIST_HEAD(pnpbios_drivers);
+
+static const struct pnpbios_device_id *
+match_device(const struct pnpbios_device_id *ids, const struct pci_dev *dev)
+{
+	while (*ids->id)
+	{
+		if(memcmp(ids->id, dev->slot_name, 7)==0)
+			return ids;
+		ids++;
+	}
+	return NULL;
+}
+
+static int announce_device(struct pnpbios_driver *drv, struct pci_dev *dev)
+{
+	const struct pnpbios_device_id *id;
+	struct pci_dev tmpdev;
+	int ret;
+
+	if (drv->id_table) {
+		id = match_device(drv->id_table, dev);
+		if (!id)
+			return 0;
+	} else
+		id = NULL;
+
+	memcpy( &tmpdev, dev, sizeof(struct pci_dev));
+	tmpdev.global_list.prev = NULL;
+	tmpdev.global_list.next = NULL;
+
+	dev_probe_lock();
+	/* Obviously, probe() should not call any pnpbios functions */
+	ret = drv->probe(&tmpdev, id);
+	dev_probe_unlock();
+	if (ret < 1)
+		return 0;
+
+	dev->driver = (void *)drv;
+
+	return 1;
+}
+
+/**
+ * pnpbios_register_driver - register a new pci driver
+ * @drv: the driver structure to register
+ * 
+ * Adds the driver structure to the list of registered drivers
+ *
+ * For each device in the pnpbios device list that matches one of
+ * the ids in drv->id_table, calls the driver's "probe" function with
+ * arguments (1) a pointer to a *temporary* struct pci_dev containing
+ * resource info for the device, and (2) a pointer to the id string
+ * of the device.  Expects the probe function to return 1 if the
+ * driver claims the device (otherwise 0) in which case, marks the
+ * device as having this driver.
+ * 
+ * Returns the number of pci devices which were claimed by the driver
+ * during registration.  The driver remains registered even if the
+ * return value is zero.
+ */
+int pnpbios_register_driver(struct pnpbios_driver *drv)
+{
+	struct pci_dev *dev;
+	unsigned long flags;
+	int count = 0;
+
+	list_add_tail(&drv->node, &pnpbios_drivers);
+	spin_lock_irqsave(&pnpbios_devices_lock, flags);
+	pnpbios_for_each_dev(dev) {
+		if (!pnpbios_dev_driver(dev))
+			count += announce_device(drv, dev);
+	}
+	spin_unlock_irqrestore(&pnpbios_devices_lock, flags);
+	return count;
+}
+
+EXPORT_SYMBOL(pnpbios_register_driver);
+
+/**
+ * pnpbios_unregister_driver - unregister a pci driver
+ * @drv: the driver structure to unregister
+ * 
+ * Deletes the driver structure from the list of registered PnPBIOS
+ * drivers, gives it a chance to clean up by calling its "remove"
+ * function for each device it was responsible for, and marks those
+ * devices as driverless.
+ */
+void pnpbios_unregister_driver(struct pnpbios_driver *drv)
+{
+	unsigned long flags;
+	struct pci_dev *dev;
+
+	list_del(&drv->node);
+	spin_lock_irqsave(&pnpbios_devices_lock, flags);
+	pnpbios_for_each_dev(dev) {
+		if (dev->driver == (void *)drv) {
+			if (drv->remove)
+				drv->remove(dev);
+			dev->driver = NULL;
+		}
+	}
+	spin_unlock_irqrestore(&pnpbios_devices_lock, flags);
+}
+
+EXPORT_SYMBOL(pnpbios_unregister_driver);
+
+
+/*
+ *
+ * RESOURCE RESERVATION FUNCTIONS
+ *
+ *
+ * Used only at init time
+ *
+ */
+
+static void __init reserve_ioport_range(char *pnpid, int start, int end)
+{
+	struct resource *res;
+	char *regionid;
+
+#if 0
+	/*
+	 * TEMPORARY hack to work around the fact that the
+	 * floppy driver inappropriately reserves ioports 0x3f0 and 0x3f1
+	 * Remove this once the floppy driver is fixed.
+	 */
+	if (
+		(0x3f0 >= start && 0x3f0 <= end)
+		|| (0x3f1 >= start && 0x3f1 <= end)
+	) {
+		printk(KERN_INFO
+			"PnPBIOS: %s: ioport range 0x%x-0x%x NOT reserved\n",
+			pnpid, start, end
+		);
+		return;
+	}
+#endif
+
+	regionid = pnpbios_kmalloc(16, GFP_KERNEL);
+	if ( regionid == NULL )
+		return;
+	snprintf(regionid, 16, "PnPBIOS %s", pnpid);
+	res = request_region(start,end-start+1,regionid);
+	if ( res == NULL )
+		kfree( regionid );
+	else
+		res->flags &= ~IORESOURCE_BUSY;
+	/*
+	 * Failures at this point are usually harmless. pci quirks for
+	 * example do reserve stuff they know about too, so we may well
+	 * have double reservations.
+	 */
+	printk(KERN_INFO
+		"PnPBIOS: %s: ioport range 0x%x-0x%x %s reserved\n",
+		pnpid, start, end,
+		NULL != res ? "has been" : "could not be"
+	);
+
+	return;
+}
+
+static void __init reserve_resources_of_dev( struct pci_dev *dev )
+{
+	int i;
+
+	for (i=0;i<DEVICE_COUNT_RESOURCE;i++) {
+		if ( dev->resource[i].flags & IORESOURCE_UNSET )
+			/* end of resources */
+			break;
+		if (dev->resource[i].flags & IORESOURCE_IO) {
+			/* ioport */
+			if ( dev->resource[i].start == 0 )
+				/* disabled */
+				/* Do nothing */
+				continue;
+			if ( dev->resource[i].start < 0x100 )
+				/*
+				 * Below 0x100 is only standard PC hardware
+				 * (pics, kbd, timer, dma, ...)
+				 * We should not get resource conflicts there,
+				 * and the kernel reserves these anyway
+				 * (see arch/i386/kernel/setup.c).
+				 * So, do nothing
+				 */
+				continue;
+			if ( dev->resource[i].end < dev->resource[i].start )
+				/* invalid endpoint */
+				/* Do nothing */
+				continue;
+			reserve_ioport_range(
+				dev->slot_name,
+				dev->resource[i].start,
+				dev->resource[i].end
+			);
+		} else if (dev->resource[i].flags & IORESOURCE_MEM) {
+			/* iomem */
+			/* For now do nothing */
+			continue;
+		} else {
+			/* Neither ioport nor iomem */
+			/* Do nothing */
+			continue;
+		}
+	}
+
+	return;
+}
+
+static void __init reserve_resources( void )
+{
+	struct pci_dev *dev;
+
+	pnpbios_for_each_dev(dev) {
+		if (
+			0 != strcmp(dev->slot_name,"PNP0c01") &&  /* memory controller */
+			0 != strcmp(dev->slot_name,"PNP0c02")     /* system peripheral: other */
+		) {
+			continue;
+		}  
+		reserve_resources_of_dev(dev);
+	}
+
+	return;
+}
+
+
+/* 
+ *
+ * INIT AND EXIT
+ *
+ */
+
+extern int is_sony_vaio_laptop;
+
+static int pnpbios_disabled; /* = 0 */
+static int dont_reserve_resources; /* = 0 */
+int pnpbios_dont_use_current_config; /* = 0 */
+
+#ifndef MODULE
+static int __init pnpbios_setup(char *str)
+{
+	int invert;
+
+	while ((str != NULL) && (*str != '\0')) {
+		if (strncmp(str, "off", 3) == 0)
+			pnpbios_disabled=1;
+		if (strncmp(str, "on", 2) == 0)
+			pnpbios_disabled=0;
+		invert = (strncmp(str, "no-", 3) == 0);
+		if (invert)
+			str += 3;
+		if (strncmp(str, "curr", 4) == 0)
+			pnpbios_dont_use_current_config = invert;
+		if (strncmp(str, "res", 3) == 0)
+			dont_reserve_resources = invert;
+		str = strchr(str, ',');
+		if (str != NULL)
+			str += strspn(str, ", \t");
+	}
+
+	return 1;
+}
+
+__setup("pnpbios=", pnpbios_setup);
+#endif
+
+int __init pnpbios_init(void)
+{
+	union pnp_bios_expansion_header *check;
+	u8 sum;
+	int i, length, r;
+
+	spin_lock_init(&pnp_bios_lock);
+	spin_lock_init(&pnpbios_devices_lock);
+
+	if(pnpbios_disabled) {
+		printk(KERN_INFO "PnPBIOS: Disabled\n");
+		return -ENODEV;
+	}
+
+	if ( is_sony_vaio_laptop )
+		pnpbios_dont_use_current_config = 1;
+
+	/*
+ 	 * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS
+	 * structure and, if one is found, sets up the selectors and
+	 * entry points
+	 */
+	for (check = (union pnp_bios_expansion_header *) __va(0xf0000);
+	     check < (union pnp_bios_expansion_header *) __va(0xffff0);
+	     ((void *) (check)) += 16) {
+		if (check->fields.signature != PNP_SIGNATURE)
+			continue;
+		length = check->fields.length;
+		if (!length)
+			continue;
+		for (sum = 0, i = 0; i < length; i++)
+			sum += check->chars[i];
+		if (sum)
+			continue;
+		if (check->fields.version < 0x10) {
+			printk(KERN_WARNING "PnPBIOS: PnP BIOS version %d.%d is not supported\n",
+			       check->fields.version >> 4,
+			       check->fields.version & 15);
+			continue;
+		}
+		printk(KERN_INFO "PnPBIOS: Found PnP BIOS installation structure at 0x%p\n", check);
+		printk(KERN_INFO "PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%x\n",
+                       check->fields.version >> 4, check->fields.version & 15,
+		       check->fields.pm16cseg, check->fields.pm16offset,
+		       check->fields.pm16dseg);
+		Q2_SET_SEL(PNP_CS32, &pnp_bios_callfunc, 64 * 1024);
+		Q_SET_SEL(PNP_CS16, check->fields.pm16cseg, 64 * 1024);
+		Q_SET_SEL(PNP_DS, check->fields.pm16dseg, 64 * 1024);
+		pnp_bios_callpoint.offset = check->fields.pm16offset;
+		pnp_bios_callpoint.segment = PNP_CS16;
+		pnp_bios_hdr = check;
+		break;
+	}
+	if (!pnp_bios_present())
+		return -ENODEV;
+	build_devlist();
+	if ( ! dont_reserve_resources )
+		reserve_resources();
+#ifdef CONFIG_PROC_FS
+	r = pnpbios_proc_init();
+	if (r)
+		return r;
+#endif
+	return 0;
+}
+
+static int pnpbios_thread_init(void)
+{
+#ifdef CONFIG_HOTPLUG	
+	init_completion(&unload_sem);
+	if(kernel_thread(pnp_dock_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL)>0)
+		unloading = 0;
+#endif		
+	return 0;
+}
+
+#ifndef MODULE
+
+/* init/main.c calls pnpbios_init early */
+
+/* Start the kernel thread later: */
+module_init(pnpbios_thread_init);
+
+#else
+
+/*
+ * N.B.: Building pnpbios as a module hasn't been fully implemented
+ */
+
+MODULE_LICENSE("GPL");
+
+static int pnpbios_init_all(void)
+{
+	int r;
+	r = pnpbios_init();
+	if (r)
+		return r;
+	r = pnpbios_thread_init();
+	if (r)
+		return r;
+	return 0;
+}
+
+static void __exit pnpbios_exit(void)
+{
+#ifdef CONFIG_HOTPLUG
+	unloading = 1;
+	wait_for_completion(&unload_sem);
+#endif
+	pnpbios_proc_exit();
+	/* We ought to free resources here */
+	return;
+}
+
+module_init(pnpbios_init_all);
+module_exit(pnpbios_exit);
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/pnp/pnpbios_proc.c linux.20pre10-ac2/drivers/pnp/pnpbios_proc.c
--- linux.20pre10/drivers/pnp/pnpbios_proc.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/pnp/pnpbios_proc.c	2002-08-11 21:28:12.000000000 +0100
@@ -0,0 +1,278 @@
+/*
+ * /proc/bus/pnp interface for Plug and Play devices
+ *
+ * Written by David Hinds, dahinds@users.sourceforge.net
+ * Modified by Thomas Hood, jdthood@mail.com
+ *
+ * The .../devices and .../<node> and .../boot/<node> files are
+ * utilized by the lspnp and setpnp utilities, supplied with the
+ * pcmcia-cs package.
+ *     http://pcmcia-cs.sourceforge.net
+ *
+ * The .../escd file is utilized by the lsescd utility written by
+ * Gunther Mayer.
+ *     http://home.t-online.de/home/gunther.mayer/lsescd
+ *
+ * The .../legacy_device_resources file is not used yet.
+ *
+ * The other files are human-readable.
+ */
+
+//#include <pcmcia/config.h>
+#define __NO_VERSION__
+//#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/pnpbios.h>
+
+static struct proc_dir_entry *proc_pnp = NULL;
+static struct proc_dir_entry *proc_pnp_boot = NULL;
+static struct pnp_dev_node_info node_info;
+
+static int proc_read_pnpconfig(char *buf, char **start, off_t pos,
+                               int count, int *eof, void *data)
+{
+	struct pnp_isa_config_struc pnps;
+
+	if (pnp_bios_isapnp_config(&pnps))
+		return -EIO;
+	return snprintf(buf, count,
+		"structure_revision %d\n"
+		"number_of_CSNs %d\n"
+		"ISA_read_data_port 0x%x\n",
+		pnps.revision,
+		pnps.no_csns,
+		pnps.isa_rd_data_port
+	);
+}
+
+static int proc_read_escdinfo(char *buf, char **start, off_t pos,
+                              int count, int *eof, void *data)
+{
+	struct escd_info_struc escd;
+
+	if (pnp_bios_escd_info(&escd))
+		return -EIO;
+	return snprintf(buf, count,
+		"min_ESCD_write_size %d\n"
+		"ESCD_size %d\n"
+		"NVRAM_base 0x%x\n",
+		escd.min_escd_write_size,
+		escd.escd_size,
+		escd.nv_storage_base
+	);
+}
+
+#define MAX_SANE_ESCD_SIZE (32*1024)
+static int proc_read_escd(char *buf, char **start, off_t pos,
+                          int count, int *eof, void *data)
+{
+	struct escd_info_struc escd;
+	char *tmpbuf;
+	int escd_size, escd_left_to_read, n;
+
+	if (pnp_bios_escd_info(&escd))
+		return -EIO;
+
+	/* sanity check */
+	if (escd.escd_size > MAX_SANE_ESCD_SIZE) {
+		printk(KERN_ERR "PnPBIOS: proc_read_escd: ESCD size reported by BIOS escd_info call is too great\n");
+		return -EFBIG;
+	}
+
+	tmpbuf = pnpbios_kmalloc(escd.escd_size, GFP_KERNEL);
+	if (!tmpbuf) return -ENOMEM;
+
+	if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base))
+		return -EIO;
+
+	escd_size = (unsigned char)(tmpbuf[0]) + (unsigned char)(tmpbuf[1])*256;
+
+	/* sanity check */
+	if (escd_size > MAX_SANE_ESCD_SIZE) {
+		printk(KERN_ERR "PnPBIOS: proc_read_escd: ESCD size reported by BIOS read_escd call is too great\n");
+		return -EFBIG;
+	}
+
+	escd_left_to_read = escd_size - pos;
+	if (escd_left_to_read < 0) escd_left_to_read = 0;
+	if (escd_left_to_read == 0) *eof = 1;
+	n = min(count,escd_left_to_read);
+	memcpy(buf, tmpbuf + pos, n);
+	kfree(tmpbuf);
+	*start = buf;
+	return n;
+}
+
+static int proc_read_legacyres(char *buf, char **start, off_t pos,
+                               int count, int *eof, void *data)
+{
+	/* Assume that the following won't overflow the buffer */
+	if (pnp_bios_get_stat_res(buf)) 
+		return -EIO;
+
+	return count;  // FIXME: Return actual length
+}
+
+static int proc_read_devices(char *buf, char **start, off_t pos,
+                             int count, int *eof, void *data)
+{
+	struct pnp_bios_node *node;
+	u8 nodenum;
+	char *p = buf;
+
+	if (pos >= 0xff)
+		return 0;
+
+	node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+	if (!node) return -ENOMEM;
+
+	for (nodenum=pos; nodenum<0xff; ) {
+		u8 thisnodenum = nodenum;
+		/* 26 = the number of characters per line sprintf'ed */
+		if ((p - buf + 26) > count)
+			break;
+		if (pnp_bios_get_dev_node(&nodenum, 1, node))
+			break;
+		p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n",
+			     node->handle, node->eisa_id,
+			     node->type_code[0], node->type_code[1],
+			     node->type_code[2], node->flags);
+		if (nodenum <= thisnodenum) {
+			printk(KERN_ERR "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", "PnPBIOS: proc_read_devices:", (unsigned int)nodenum, (unsigned int)thisnodenum);
+			*eof = 1;
+			break;
+		}
+	}
+	kfree(node);
+	if (nodenum == 0xff)
+		*eof = 1;
+	*start = (char *)((off_t)nodenum - pos);
+	return p - buf;
+}
+
+static int proc_read_node(char *buf, char **start, off_t pos,
+                          int count, int *eof, void *data)
+{
+	struct pnp_bios_node *node;
+	int boot = (long)data >> 8;
+	u8 nodenum = (long)data;
+	int len;
+
+	node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+	if (!node) return -ENOMEM;
+	if (pnp_bios_get_dev_node(&nodenum, boot, node))
+		return -EIO;
+	len = node->size - sizeof(struct pnp_bios_node);
+	memcpy(buf, node->data, len);
+	kfree(node);
+	return len;
+}
+
+static int proc_write_node(struct file *file, const char *buf,
+                           unsigned long count, void *data)
+{
+	struct pnp_bios_node *node;
+	int boot = (long)data >> 8;
+	u8 nodenum = (long)data;
+
+	node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+	if (!node) return -ENOMEM;
+	if ( pnp_bios_get_dev_node(&nodenum, boot, node) )
+		return -EIO;
+	if (count != node->size - sizeof(struct pnp_bios_node))
+		return -EINVAL;
+	memcpy(node->data, buf, count);
+	if (pnp_bios_set_dev_node(node->handle, boot, node) != 0)
+	    return -EINVAL;
+	kfree(node);
+	return count;
+}
+
+/*
+ * When this is called, pnpbios functions are assumed to
+ * work and the pnpbios_dont_use_current_config flag
+ * should already have been set to the appropriate value
+ */
+int __init pnpbios_proc_init( void )
+{
+	struct pnp_bios_node *node;
+	struct proc_dir_entry *ent;
+	char name[3];
+	u8 nodenum;
+
+	if (pnp_bios_dev_node_info(&node_info))
+		return -EIO;
+	
+	proc_pnp = proc_mkdir("pnp", proc_bus);
+	if (!proc_pnp)
+		return -EIO;
+	proc_pnp_boot = proc_mkdir("boot", proc_pnp);
+	if (!proc_pnp_boot)
+		return -EIO;
+	create_proc_read_entry("devices", 0, proc_pnp, proc_read_devices, NULL);
+	create_proc_read_entry("configuration_info", 0, proc_pnp, proc_read_pnpconfig, NULL);
+	create_proc_read_entry("escd_info", S_IRUSR, proc_pnp, proc_read_escdinfo, NULL);
+	create_proc_read_entry("escd", S_IRUSR, proc_pnp, proc_read_escd, NULL);
+	create_proc_read_entry("legacy_device_resources", 0, proc_pnp, proc_read_legacyres, NULL);
+	
+	node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL);
+	if (!node)
+		return -ENOMEM;
+
+	for (nodenum=0; nodenum<0xff; ) {
+		u8 thisnodenum = nodenum;
+		if (pnp_bios_get_dev_node(&nodenum, 1, node) != 0)
+			break;
+		sprintf(name, "%02x", node->handle);
+		if ( !pnpbios_dont_use_current_config ) {
+			ent = create_proc_entry(name, 0, proc_pnp);
+			if (ent) {
+				ent->read_proc = proc_read_node;
+				ent->write_proc = proc_write_node;
+				ent->data = (void *)(long)(node->handle);
+			}
+		}
+		ent = create_proc_entry(name, 0, proc_pnp_boot);
+		if (ent) {
+			ent->read_proc = proc_read_node;
+			ent->write_proc = proc_write_node;
+			ent->data = (void *)(long)(node->handle+0x100);
+		}
+		if (nodenum <= thisnodenum) {
+			printk(KERN_ERR "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", "PnPBIOS: proc_init:", (unsigned int)nodenum, (unsigned int)thisnodenum);
+			break;
+		}
+	}
+	kfree(node);
+
+	return 0;
+}
+
+void __exit pnpbios_proc_exit(void)
+{
+	int i;
+	char name[3];
+	
+	if (!proc_pnp) return;
+
+	for (i=0; i<0xff; i++) {
+		sprintf(name, "%02x", i);
+		if ( !pnpbios_dont_use_current_config )
+			remove_proc_entry(name, proc_pnp);
+		remove_proc_entry(name, proc_pnp_boot);
+	}
+	remove_proc_entry("legacy_device_resources", proc_pnp);
+	remove_proc_entry("escd", proc_pnp);
+	remove_proc_entry("escd_info", proc_pnp);
+	remove_proc_entry("configuration_info", proc_pnp);
+	remove_proc_entry("devices", proc_pnp);
+	remove_proc_entry("boot", proc_pnp);
+	remove_proc_entry("pnp", proc_bus);
+
+	return;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/aic7xxx/aic7770.c linux.20pre10-ac2/drivers/scsi/aic7xxx/aic7770.c
--- linux.20pre10/drivers/scsi/aic7xxx/aic7770.c	2002-10-09 21:36:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/aic7xxx/aic7770.c	2002-10-11 00:15:00.000000000 +0100
@@ -273,8 +273,8 @@
 
 	if (bootverbose)
 		printf("%s: Reading SEEPROM...", ahc_name(ahc));
-	have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)&sc,
-					/*start_addr*/0, sizeof(sc)/2);
+	have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)sc,
+					/*start_addr*/0, sizeof(*sc)/2);
 
 	if (have_seeprom) {
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/Config.in linux.20pre10-ac2/drivers/scsi/Config.in
--- linux.20pre10/drivers/scsi/Config.in	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/Config.in	2002-10-10 23:53:35.000000000 +0100
@@ -204,6 +204,7 @@
 if [ "$CONFIG_X86" = "y" ]; then
    dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
 fi
+dep_tristate 'Workbit NinjaSCSI-32Bi/UDE support' CONFIG_SCSI_NSP32 $CONFIG_SCSI
 #
 # Note - this is a very special 'host' adapter that simulates the presence of some disks.
 # It can come in very handy for troubleshooting.  Anyone else is welcome to use it - all
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/cpqfcTSchip.h linux.20pre10-ac2/drivers/scsi/cpqfcTSchip.h
--- linux.20pre10/drivers/scsi/cpqfcTSchip.h	2002-10-09 21:36:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/cpqfcTSchip.h	2002-09-12 14:25:01.000000000 +0100
@@ -18,6 +18,7 @@
  * General Public License for more details.
  * Written by Don Zimmerman
 */
+
 #ifndef CPQFCTSCHIP_H
 #define CPQFCTSCHIP_H
 #ifndef TACHYON_CHIP_INC
@@ -29,210 +30,211 @@
 #define FC_PH43			0x09
 #define FC_PH3			0x20
 
-#define TACHLITE_TS_RX_SIZE     1024  // max inbound frame size
+#define TACHLITE_TS_RX_SIZE     1024	// max inbound frame size
 // "I" prefix is for Include
 
-#define IVENDID    0x00  // word
-#define IDEVID     0x02
-#define ITLCFGCMD 0x04
-#define IMEMBASE   0x18    // Tachyon
-#define ITLMEMBASE   0x1C  // Tachlite
-#define IIOBASEL   0x10    // Tachyon I/O base address, lower 256 bytes
-#define IIOBASEU   0x14    // Tachyon I/O base address, upper 256 bytes
-#define ITLIOBASEL   0x14  // TachLite I/O base address, lower 256 bytes
-#define ITLIOBASEU   0x18  // TachLite I/O base address, upper 256 bytes
-#define ITLRAMBASE   0x20  // TL on-board RAM start
-#define ISROMBASE  0x24
-#define IROMBASE   0x30
-
-#define ICFGCMD    0x04    // PCI config - PCI config access (word)
-#define ICFGSTAT   0x06    // PCI status (R - word)
-#define IRCTR_WCTR 0x1F2   // ROM control / pre-fetch wait counter
-#define IPCIMCTR   0x1F3   // PCI master control register
-#define IINTPEND   0x1FD   // Interrupt pending (I/O Upper - Tachyon & TL)
-#define IINTEN     0x1FE   // Interrupt enable  (I/O Upper - Tachyon & TL)
-#define IINTSTAT   0x1FF   // Interrupt status  (I/O Upper - Tachyon & TL)
+#define IVENDID		0x00	// word
+#define IDEVID		0x02
+#define ITLCFGCMD	0x04
+#define IMEMBASE	0x18	// Tachyon
+#define ITLMEMBASE	0x1C	// Tachlite
+#define IIOBASEL	0x10	// Tachyon I/O base address, lower 256 bytes
+#define IIOBASEU	0x14	// Tachyon I/O base address, upper 256 bytes
+#define ITLIOBASEL	0x14	// TachLite I/O base address, lower 256 bytes
+#define ITLIOBASEU	0x18	// TachLite I/O base address, upper 256 bytes
+#define ITLRAMBASE	0x20	// TL on-board RAM start
+#define ISROMBASE	0x24
+#define IROMBASE	0x30
+
+#define ICFGCMD		0x04	// PCI config - PCI config access (word)
+#define ICFGSTAT	0x06	// PCI status (R - word)
+#define IRCTR_WCTR	0x1F2	// ROM control / pre-fetch wait counter
+#define IPCIMCTR	0x1F3	// PCI master control register
+#define IINTPEND	0x1FD	// Interrupt pending (I/O Upper - Tachyon & TL)
+#define IINTEN		0x1FE	// Interrupt enable  (I/O Upper - Tachyon & TL)
+#define IINTSTAT	0x1FF	// Interrupt status  (I/O Upper - Tachyon & TL)
 
 #define IMQ_BASE            0x80
 #define IMQ_LENGTH          0x84
 #define IMQ_CONSUMER_INDEX  0x88
-#define IMQ_PRODUCER_INDEX  0x8C   // Tach copies its INDX to bits 0-7 of value
+#define IMQ_PRODUCER_INDEX  0x8C 	// Tach copies its INDX to bits 0-7 of value
 
 /*
 // IOBASE UPPER
-#define SFSBQ_BASE            0x00   // single-frame sequences
+#define SFSBQ_BASE            0x00	// single-frame sequences
 #define SFSBQ_LENGTH          0x04
 #define SFSBQ_PRODUCER_INDEX  0x08
-#define SFSBQ_CONSUMER_INDEX  0x0C   // (R)
+#define SFSBQ_CONSUMER_INDEX  0x0C	// (R)
 #define SFS_BUFFER_LENGTH     0X10
-                              // SCSI-FCP hardware assists
-#define SEST_BASE             0x40   // SSCI Exchange State Table
+	                          	// SCSI-FCP hardware assists
+#define SEST_BASE             0x40	// SSCI Exchange State Table
 #define SEST_LENGTH           0x44
 #define SCSI_BUFFER_LENGTH    0x48
 #define SEST_LINKED_LIST      0x4C
 
 #define TACHYON_My_ID         0x6C
-#define TACHYON_CONFIGURATION 0x84   // (R/W) reset val 2
+#define TACHYON_CONFIGURATION 0x84	// (R/W) reset val 2
 #define TACHYON_CONTROL       0x88
-#define TACHYON_STATUS        0x8C   // (R)
-#define TACHYON_FLUSH_SEST    0x90   // (R/W)
-#define TACHYON_EE_CREDIT_TMR 0x94   // (R)
-#define TACHYON_BB_CREDIT_TMR 0x98   // (R)
-#define TACHYON_RCV_FRAME_ERR 0x9C   // (R)
-#define FRAME_MANAGER_CONFIG  0xC0   // (R/W)
+#define TACHYON_STATUS        0x8C	// (R)
+#define TACHYON_FLUSH_SEST    0x90	// (R/W)
+#define TACHYON_EE_CREDIT_TMR 0x94	// (R)
+#define TACHYON_BB_CREDIT_TMR 0x98	// (R)
+#define TACHYON_RCV_FRAME_ERR 0x9C	// (R)
+#define FRAME_MANAGER_CONFIG  0xC0	// (R/W)
 #define FRAME_MANAGER_CONTROL 0xC4
-#define FRAME_MANAGER_STATUS  0xC8   // (R)
+#define FRAME_MANAGER_STATUS  0xC8	// (R)
 #define FRAME_MANAGER_ED_TOV  0xCC
-#define FRAME_MANAGER_LINK_ERR1 0xD0   // (R)
-#define FRAME_MANAGER_LINK_ERR2 0xD4   // (R)
-#define FRAME_MANAGER_TIMEOUT2  0xD8   // (W)
-#define FRAME_MANAGER_BB_CREDIT 0xDC   // (R)
-#define FRAME_MANAGER_WWN_HI    0xE0   // (R/W)
-#define FRAME_MANAGER_WWN_LO    0xE4   // (R/W)
-#define FRAME_MANAGER_RCV_AL_PA 0xE8   // (R)
-#define FRAME_MANAGER_PRIMITIVE 0xEC   // {K28.5} byte1 byte2 byte3
+#define FRAME_MANAGER_LINK_ERR1 0xD0	// (R)
+#define FRAME_MANAGER_LINK_ERR2 0xD4	// (R)
+#define FRAME_MANAGER_TIMEOUT2  0xD8	// (W)
+#define FRAME_MANAGER_BB_CREDIT 0xDC	// (R)
+#define FRAME_MANAGER_WWN_HI    0xE0	// (R/W)
+#define FRAME_MANAGER_WWN_LO    0xE4	// (R/W)
+#define FRAME_MANAGER_RCV_AL_PA 0xE8	// (R)
+#define FRAME_MANAGER_PRIMITIVE 0xEC	// {K28.5} byte1 byte2 byte3
 */
-		    
-#define TL_MEM_ERQ_BASE                    0x0 //ERQ Base
-#define TL_IO_ERQ_BASE                     0x0 //ERQ base
 
-#define TL_MEM_ERQ_LENGTH                  0x4 //ERQ Length
-#define TL_IO_ERQ_LENGTH                   0x4 //ERQ Length
+#define TL_MEM_ERQ_BASE                 0x0	//ERQ Base
+#define TL_IO_ERQ_BASE                  0x0	//ERQ base
+
+#define TL_MEM_ERQ_LENGTH               0x4	//ERQ Length
+#define TL_IO_ERQ_LENGTH                0x4	//ERQ Length
 
-#define TL_MEM_ERQ_PRODUCER_INDEX          0x8 //ERQ Producer Index  register
-#define TL_IO_ERQ_PRODUCER_INDEX           0x8 //ERQ Producer Index  register
+#define TL_MEM_ERQ_PRODUCER_INDEX       0x8	//ERQ Producer Index  register
+#define TL_IO_ERQ_PRODUCER_INDEX	0x8	//ERQ Producer Index  register
 
-#define TL_MEM_ERQ_CONSUMER_INDEX_ADR 0xC //ERQ Consumer Index address register
-#define TL_IO_ERQ_CONSUMER_INDEX_ADR  0xC //ERQ Consumer Index address register
+#define TL_MEM_ERQ_CONSUMER_INDEX_ADR	0xC	//ERQ Consumer Index address register
+#define TL_IO_ERQ_CONSUMER_INDEX_ADR	0xC	//ERQ Consumer Index address register
 
-#define TL_MEM_ERQ_CONSUMER_INDEX     0xC //ERQ Consumer Index 
-#define TL_IO_ERQ_CONSUMER_INDEX      0xC //ERQ Consumer Index 
+#define TL_MEM_ERQ_CONSUMER_INDEX     	0xC	//ERQ Consumer Index
+#define TL_IO_ERQ_CONSUMER_INDEX      	0xC	//ERQ Consumer Index
 
-#define TL_MEM_SFQ_BASE               0x50 //SFQ Base
-#define TL_IO_SFQ_BASE                0x50 //SFQ base
+#define TL_MEM_SFQ_BASE               	0x50	//SFQ Base
+#define TL_IO_SFQ_BASE                	0x50	//SFQ base
 
-#define TL_MEM_SFQ_LENGTH             0x54 //SFQ Length
-#define TL_IO_SFQ_LENGTH              0x54 //SFQ Length
+#define TL_MEM_SFQ_LENGTH             	0x54	//SFQ Length
+#define TL_IO_SFQ_LENGTH              	0x54	//SFQ Length
 
-#define TL_MEM_SFQ_CONSUMER_INDEX     0x58 //SFQ Consumer Index
-#define TL_IO_SFQ_CONSUMER_INDEX      0x58 //SFQ Consumer Index
+#define TL_MEM_SFQ_CONSUMER_INDEX     	0x58	//SFQ Consumer Index
+#define TL_IO_SFQ_CONSUMER_INDEX      	0x58	//SFQ Consumer Index
 
-#define TL_MEM_IMQ_BASE               0x80 //IMQ Base
-#define TL_IO_IMQ_BASE                0x80 //IMQ base
+#define TL_MEM_IMQ_BASE               	0x80	//IMQ Base
+#define TL_IO_IMQ_BASE                	0x80	//IMQ base
 
-#define TL_MEM_IMQ_LENGTH             0x84 //IMQ Length
-#define TL_IO_IMQ_LENGTH              0x84 //IMQ Length
+#define TL_MEM_IMQ_LENGTH             	0x84	//IMQ Length
+#define TL_IO_IMQ_LENGTH              	0x84	//IMQ Length
 
-#define TL_MEM_IMQ_CONSUMER_INDEX     0x88 //IMQ Consumer Index
-#define TL_IO_IMQ_CONSUMER_INDEX      0x88 //IMQ Consumer Index
+#define TL_MEM_IMQ_CONSUMER_INDEX     	0x88	//IMQ Consumer Index
+#define TL_IO_IMQ_CONSUMER_INDEX      	0x88	//IMQ Consumer Index
 
-#define TL_MEM_IMQ_PRODUCER_INDEX_ADR 0x8C //IMQ Producer Index address register
-#define TL_IO_IMQ_PRODUCER_INDEX_ADR  0x8C //IMQ Producer Index address register
+#define TL_MEM_IMQ_PRODUCER_INDEX_ADR 	0x8C	//IMQ Producer Index address register
+#define TL_IO_IMQ_PRODUCER_INDEX_ADR  	0x8C	//IMQ Producer Index address register
 
-#define TL_MEM_SEST_BASE              0x140 //SFQ Base
-#define TL_IO_SEST_BASE               0x40 //SFQ base
+#define TL_MEM_SEST_BASE              	0x140	//SFQ Base
+#define TL_IO_SEST_BASE               	0x40	//SFQ base
 
-#define TL_MEM_SEST_LENGTH            0x144 //SFQ Length
-#define TL_IO_SEST_LENGTH             0x44 //SFQ Length
+#define TL_MEM_SEST_LENGTH            	0x144	//SFQ Length
+#define TL_IO_SEST_LENGTH             	0x44	//SFQ Length
 
-#define TL_MEM_SEST_LINKED_LIST       0x14C
+#define TL_MEM_SEST_LINKED_LIST       	0x14C
 
-#define TL_MEM_SEST_SG_PAGE           0x168  // Extended Scatter/Gather page size
+#define TL_MEM_SEST_SG_PAGE           	0x168	// Extended Scatter/Gather page size
 
-#define TL_MEM_TACH_My_ID             0x16C
-#define TL_IO_TACH_My_ID              0x6C //My AL_PA ID
+#define TL_MEM_TACH_My_ID             	0x16C
+#define TL_IO_TACH_My_ID              	0x6C	//My AL_PA ID
 
-#define TL_MEM_TACH_CONFIG            0x184 //Tachlite Configuration register
-#define TL_IO_CONFIG                  0x84 //Tachlite Configuration register
+#define TL_MEM_TACH_CONFIG            	0x184	//Tachlite Configuration register
+#define TL_IO_CONFIG                  	0x84	//Tachlite Configuration register
 
-#define TL_MEM_TACH_CONTROL           0x188 //Tachlite Control register
-#define TL_IO_CTR                     0x88 //Tachlite Control register
+#define TL_MEM_TACH_CONTROL           	0x188	//Tachlite Control register
+#define TL_IO_CTR                     	0x88	//Tachlite Control register
 
-#define TL_MEM_TACH_STATUS            0x18C //Tachlite Status register
-#define TL_IO_STAT                    0x8C //Tachlite Status register
+#define TL_MEM_TACH_STATUS            	0x18C	//Tachlite Status register
+#define TL_IO_STAT                    	0x8C	//Tachlite Status register
 
-#define TL_MEM_FM_CONFIG        0x1C0 //Frame Manager Configuration register
-#define TL_IO_FM_CONFIG         0xC0 //Frame Manager Configuration register
+#define TL_MEM_FM_CONFIG        	0x1C0	//Frame Manager Configuration register
+#define TL_IO_FM_CONFIG         	0xC0	//Frame Manager Configuration register
 
-#define TL_MEM_FM_CONTROL       0x1C4 //Frame Manager Control
-#define TL_IO_FM_CTL            0xC4 //Frame Manager Control
+#define TL_MEM_FM_CONTROL       	0x1C4	//Frame Manager Control
+#define TL_IO_FM_CTL            	0xC4	//Frame Manager Control
 
-#define TL_MEM_FM_STATUS        0x1C8 //Frame Manager Status
-#define TL_IO_FM_STAT           0xC8 //Frame Manager Status
+#define TL_MEM_FM_STATUS        	0x1C8	//Frame Manager Status
+#define TL_IO_FM_STAT           	0xC8	//Frame Manager Status
 
-#define TL_MEM_FM_LINK_STAT1    0x1D0 //Frame Manager Link Status 1
-#define TL_IO_FM_LINK_STAT1     0xD0 //Frame Manager Link Status 1
+#define TL_MEM_FM_LINK_STAT1    	0x1D0	//Frame Manager Link Status 1
+#define TL_IO_FM_LINK_STAT1     	0xD0	//Frame Manager Link Status 1
 
-#define TL_MEM_FM_LINK_STAT2    0x1D4 //Frame Manager Link Status 2
-#define TL_IO_FM_LINK_STAT2     0xD4 //Frame Manager Link Status 2
+#define TL_MEM_FM_LINK_STAT2    	0x1D4	//Frame Manager Link Status 2
+#define TL_IO_FM_LINK_STAT2     	0xD4	//Frame Manager Link Status 2
 
-#define TL_MEM_FM_TIMEOUT2      0x1D8   // (W)
+#define TL_MEM_FM_TIMEOUT2      	0x1D8	// (W)
 
-#define TL_MEM_FM_BB_CREDIT0    0x1DC
+#define TL_MEM_FM_BB_CREDIT0    	0x1DC
 
-#define TL_MEM_FM_WWN_HI        0x1E0 //Frame Manager World Wide Name High
-#define TL_IO_FM_WWN_HI         0xE0 //Frame Manager World Wide Name High
+#define TL_MEM_FM_WWN_HI        	0x1E0	//Frame Manager World Wide Name High
+#define TL_IO_FM_WWN_HI         	0xE0	//Frame Manager World Wide Name High
 
-#define TL_MEM_FM_WWN_LO        0x1E4 //Frame Manager World Wide Name LOW
-#define TL_IO_FM_WWN_LO         0xE4 //Frame Manager World Wide Name Low
+#define TL_MEM_FM_WWN_LO        	0x1E4	//Frame Manager World Wide Name LOW
+#define TL_IO_FM_WWN_LO         	0xE4	//Frame Manager World Wide Name Low
 
-#define TL_MEM_FM_RCV_AL_PA     0x1E8 //Frame Manager AL_PA Received register
-#define TL_IO_FM_ALPA           0xE8 //Frame Manager AL_PA Received register
+#define TL_MEM_FM_RCV_AL_PA     	0x1E8	//Frame Manager AL_PA Received register
+#define TL_IO_FM_ALPA           	0xE8	//Frame Manager AL_PA Received register
 
-#define TL_MEM_FM_ED_TOV           0x1CC
+#define TL_MEM_FM_ED_TOV        	0x1CC
 
-#define TL_IO_ROMCTR            0xFA //TL PCI ROM Control Register
-#define TL_IO_PCIMCTR           0xFB //TL PCI Master Control Register
-#define TL_IO_SOFTRST           0xFC //Tachlite Configuration register
-#define TL_MEM_SOFTRST          0x1FC //Tachlite Configuration register
+#define TL_IO_ROMCTR            	0xFA	//TL PCI ROM Control Register
+#define TL_IO_PCIMCTR           	0xFB	//TL PCI Master Control Register
+#define TL_IO_SOFTRST           	0xFC	//Tachlite Configuration register
+#define TL_MEM_SOFTRST          	0x1FC	//Tachlite Configuration register
 
 // completion message types (bit 8 set means Interrupt generated)
 // CM_Type
-#define OUTBOUND_COMPLETION        0
-#define ERROR_IDLE_COMPLETION   0x01
-#define OUT_HI_PRI_COMPLETION   0x01
-#define INBOUND_MFS_COMPLETION  0x02
-#define INBOUND_000_COMPLETION  0x03
-#define INBOUND_SFS_COMPLETION  0x04  // Tachyon & TachLite
-#define ERQ_FROZEN_COMPLETION   0x06  // TachLite
-#define INBOUND_C1_TIMEOUT      0x05
-#define INBOUND_BUSIED_FRAME    0x06
-#define SFS_BUF_WARN            0x07
-#define FCP_FROZEN_COMPLETION   0x07  // TachLite
-#define MFS_BUF_WARN            0x08
-#define IMQ_BUF_WARN            0x09
-#define FRAME_MGR_INTERRUPT     0x0A
-#define READ_STATUS             0x0B
-#define INBOUND_SCSI_DATA_COMPLETION  0x0C
-#define INBOUND_FCP_XCHG_COMPLETION   0x0C  // TachLite
-#define INBOUND_SCSI_DATA_COMMAND     0x0D
-#define BAD_SCSI_FRAME                0x0E
-#define INB_SCSI_STATUS_COMPLETION    0x0F
-#define BUFFER_PROCESSED_COMPLETION   0x11
+
+#define OUTBOUND_COMPLETION     	   0
+#define ERROR_IDLE_COMPLETION   	0x01
+#define OUT_HI_PRI_COMPLETION   	0x01
+#define INBOUND_MFS_COMPLETION  	0x02
+#define INBOUND_000_COMPLETION  	0x03
+#define INBOUND_SFS_COMPLETION  	0x04	// Tachyon & TachLite
+#define ERQ_FROZEN_COMPLETION   	0x06	// TachLite
+#define INBOUND_C1_TIMEOUT      	0x05
+#define INBOUND_BUSIED_FRAME    	0x06
+#define SFS_BUF_WARN            	0x07
+#define FCP_FROZEN_COMPLETION   	0x07	// TachLite
+#define MFS_BUF_WARN            	0x08
+#define IMQ_BUF_WARN            	0x09
+#define FRAME_MGR_INTERRUPT     	0x0A
+#define READ_STATUS             	0x0B
+#define INBOUND_SCSI_DATA_COMPLETION  	0x0C
+#define INBOUND_FCP_XCHG_COMPLETION   	0x0C	// TachLite
+#define INBOUND_SCSI_DATA_COMMAND     	0x0D
+#define BAD_SCSI_FRAME                	0x0E
+#define INB_SCSI_STATUS_COMPLETION    	0x0F
+#define BUFFER_PROCESSED_COMPLETION   	0x11
 
 // FC-AL (Tachyon) Loop Port State Machine defs
 // (loop "Up" states)
-#define MONITORING 0x0
-#define ARBITRATING 0x1
-#define ARBITRAT_WON 0x2
-#define OPEN 0x3
-#define OPENED 0x4
-#define XMITTD_CLOSE 0x5
-#define RCVD_CLOSE 0x6
-#define TRANSFER 0x7
+#define MONITORING			0x0
+#define ARBITRATING			0x1
+#define ARBITRAT_WON			0x2
+#define OPEN				0x3
+#define OPENED				0x4
+#define XMITTD_CLOSE			0x5
+#define RCVD_CLOSE			0x6
+#define TRANSFER			0x7
 
 // (loop "Down" states)
-#define INITIALIZING 0x8
-#define O_I_INIT 0x9
-#define O_I_PROTOCOL 0xa
-#define O_I_LIP_RCVD 0xb
-#define HOST_CONTROL 0xc
-#define LOOP_FAIL 0xd
+#define INITIALIZING			0x8
+#define O_I_INIT			0x9
+#define O_I_PROTOCOL			0xa
+#define O_I_LIP_RCVD			0xb
+#define HOST_CONTROL			0xc
+#define LOOP_FAIL			0xd
 // (no 0xe)
-#define OLD_PORT 0xf
+#define OLD_PORT			0xf
 
 
 
 #define TACHYON_CHIP_INC
 #endif
-#endif /* CPQFCTSCHIP_H */
+#endif				/* CPQFCTSCHIP_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/cpqfcTScontrol.c linux.20pre10-ac2/drivers/scsi/cpqfcTScontrol.c
--- linux.20pre10/drivers/scsi/cpqfcTScontrol.c	2002-10-09 21:36:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/cpqfcTScontrol.c	2002-09-12 17:31:39.000000000 +0100
@@ -28,46 +28,40 @@
    Hewlitt Packard Manual Part Number 5968-1083E.
 */
 
-#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-
 #include <linux/blk.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/ioport.h>  // request_region() prototype
+#include <linux/ioport.h>	// request_region() prototype
 #include <linux/sched.h>
-#include <linux/slab.h>  // need "kfree" for ext. S/G pages
+#include <linux/slab.h>		// need "kfree" for ext. S/G pages
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/unistd.h>
-#include <asm/io.h>  // struct pt_regs for IRQ handler & Port I/O
+#include <asm/io.h>		// struct pt_regs for IRQ handler & Port I/O
 #include <asm/irq.h>
 #include <linux/spinlock.h>
 
 #include "sd.h"
-#include "hosts.h"   // Scsi_Host definition for INT handler
+#include "hosts.h"		// Scsi_Host definition for INT handler
 #include "cpqfcTSchip.h"
 #include "cpqfcTSstructs.h"
 
 //#define IMQ_DEBUG 1
 
 static void fcParseLinkStatusCounters(TACHYON * fcChip);
-static void CpqTsGetSFQEntry(TACHYON * fcChip, 
-	      USHORT pi, ULONG * buffr, BOOLEAN UpdateChip); 
+static void CpqTsGetSFQEntry(TACHYON * fcChip, u16 pi, u32 * buffr, u8 UpdateChip);
 
-static void 
-cpqfc_free_dma_consistent(CPQFCHBA *cpqfcHBAdata)
+static void cpqfc_free_dma_consistent(CPQFCHBA * cpqfcHBAdata)
 {
-  	// free up the primary EXCHANGES struct and Link Q
+	// free up the primary EXCHANGES struct and Link Q
 	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
 
 	if (fcChip->Exchanges != NULL)
-		pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_EXCHANGES),
-			fcChip->Exchanges, fcChip->exch_dma_handle);
+		pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_EXCHANGES), fcChip->Exchanges, fcChip->exch_dma_handle);
 	fcChip->Exchanges = NULL;
 	if (cpqfcHBAdata->fcLQ != NULL)
-		pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_LINK_QUE),
-			cpqfcHBAdata->fcLQ, cpqfcHBAdata->fcLQ_dma_handle);
+		pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_LINK_QUE), cpqfcHBAdata->fcLQ, cpqfcHBAdata->fcLQ_dma_handle);
 	cpqfcHBAdata->fcLQ = NULL;
 }
 
@@ -76,281 +70,236 @@
 // in non-symbolic (i.e. memory dump) debugging
 // opcode defines placement of Queues (e.g. local/external RAM)
 
-int CpqTsCreateTachLiteQues( void* pHBA, int opcode)
+int CpqTsCreateTachLiteQues(void *pHBA, int opcode)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) pHBA;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+
+	int iStatus = 0;
+	unsigned long ulAddr;
+	dma_addr_t ERQdma, IMQdma, SPQdma, SESTdma;
+	int i;
+
+	// NOTE! fcMemManager() will return system virtual addresses.
+	// System (kernel) virtual addresses, though non-paged, still
+	// aren't physical addresses.  Convert to PHYSICAL_ADDRESS for Tachyon's
+	// DMA use.
+	ENTER("CreateTachLiteQues");
+
+
+	// Allocate primary EXCHANGES array...
+	fcChip->Exchanges = NULL;
+	cpqfcHBAdata->fcLQ = NULL;
+
+	printk("Allocating %u for %u Exchanges ", (u32) sizeof(FC_EXCHANGES), TACH_MAX_XID);
+	fcChip->Exchanges = pci_alloc_consistent(cpqfcHBAdata->PciDev, sizeof(FC_EXCHANGES), &fcChip->exch_dma_handle);
+	printk("@ %p\n", fcChip->Exchanges);
 
-  int iStatus=0;
-  unsigned long ulAddr;
-  dma_addr_t ERQdma, IMQdma, SPQdma, SESTdma;
-  int i;
-
-  // NOTE! fcMemManager() will return system virtual addresses.
-  // System (kernel) virtual addresses, though non-paged, still
-  // aren't physical addresses.  Convert to PHYSICAL_ADDRESS for Tachyon's
-  // DMA use.
-  ENTER("CreateTachLiteQues");
-
-
-  // Allocate primary EXCHANGES array...
-  fcChip->Exchanges = NULL;
-  cpqfcHBAdata->fcLQ = NULL;
-  
-  printk("Allocating %u for %u Exchanges ", 
-	  (ULONG)sizeof(FC_EXCHANGES), TACH_MAX_XID);
-  fcChip->Exchanges = pci_alloc_consistent(cpqfcHBAdata->PciDev, 
-			sizeof(FC_EXCHANGES), &fcChip->exch_dma_handle);
-  printk("@ %p\n", fcChip->Exchanges);
-
-  if( fcChip->Exchanges == NULL ) // fatal error!!
-  {
-    printk("pci_alloc_consistent failure on Exchanges: fatal error\n");
-    return -1;
-  }
-  // zero out the entire EXCHANGE space
-  memset( fcChip->Exchanges, 0, sizeof( FC_EXCHANGES));  
-
-
-  printk("Allocating %u for LinkQ ", (ULONG)sizeof(FC_LINK_QUE));
-  cpqfcHBAdata->fcLQ = pci_alloc_consistent(cpqfcHBAdata->PciDev,
-				 sizeof( FC_LINK_QUE), &cpqfcHBAdata->fcLQ_dma_handle);
-  printk("@ %p (%u elements)\n", cpqfcHBAdata->fcLQ, FC_LINKQ_DEPTH);
-  memset( cpqfcHBAdata->fcLQ, 0, sizeof( FC_LINK_QUE));
-
-  if( cpqfcHBAdata->fcLQ == NULL ) // fatal error!!
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent() failure on fc Link Que: fatal error\n");
-    return -1;
-  }
-  // zero out the entire EXCHANGE space
-  memset( cpqfcHBAdata->fcLQ, 0, sizeof( FC_LINK_QUE));  
-  
-  // Verify that basic Tach I/O registers are not NULL  
-  if( !fcChip->Registers.ReMapMemBase )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("HBA base address NULL: fatal error\n");
-    return -1;
-  }
-
-
-  // Initialize the fcMemManager memory pairs (stores allocated/aligned
-  // pairs for future freeing)
-  memset( cpqfcHBAdata->dynamic_mem, 0, sizeof(cpqfcHBAdata->dynamic_mem));
-  
-
-  // Allocate Tach's Exchange Request Queue (each ERQ entry 32 bytes)
-  
-  fcChip->ERQ = fcMemManager( cpqfcHBAdata->PciDev, 
-			&cpqfcHBAdata->dynamic_mem[0], 
-			sizeof( TachLiteERQ ), 32*(ERQ_LEN), 0L, &ERQdma);
-  if( !fcChip->ERQ )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent/alignment failure on ERQ: fatal error\n");
-    return -1;
-  }
-  fcChip->ERQ->length = ERQ_LEN-1;
-  ulAddr = (ULONG) ERQdma; 
+	if (fcChip->Exchanges == NULL)	// fatal error!!
+	{
+		printk("pci_alloc_consistent failure on Exchanges: fatal error\n");
+		return -1;
+	}
+	// zero out the entire EXCHANGE space
+	memset(fcChip->Exchanges, 0, sizeof(FC_EXCHANGES));
+
+
+	printk("Allocating %u for LinkQ ", (u32) sizeof(FC_LINK_QUE));
+	cpqfcHBAdata->fcLQ = pci_alloc_consistent(cpqfcHBAdata->PciDev, sizeof(FC_LINK_QUE), &cpqfcHBAdata->fcLQ_dma_handle);
+	printk("@ %p (%u elements)\n", cpqfcHBAdata->fcLQ, FC_LINKQ_DEPTH);
+	memset(cpqfcHBAdata->fcLQ, 0, sizeof(FC_LINK_QUE));
+
+	if (cpqfcHBAdata->fcLQ == NULL)	// fatal error!!
+	{
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk("pci_alloc_consistent() failure on fc Link Que: fatal error\n");
+		return -1;
+	}
+	// zero out the entire EXCHANGE space
+	memset(cpqfcHBAdata->fcLQ, 0, sizeof(FC_LINK_QUE));
+
+	// Verify that basic Tach I/O registers are not NULL  
+	if (!fcChip->Registers.ReMapMemBase) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk("HBA base address NULL: fatal error\n");
+		return -1;
+	}
+
+	// Initialize the fcMemManager memory pairs (stores allocated/aligned
+	// pairs for future freeing)
+	memset(cpqfcHBAdata->dynamic_mem, 0, sizeof(cpqfcHBAdata->dynamic_mem));
+
+
+	// Allocate Tach's Exchange Request Queue (each ERQ entry 32 bytes)
+
+	fcChip->ERQ = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], sizeof(TachLiteERQ), 32 * (ERQ_LEN), 0L, &ERQdma);
+	if (!fcChip->ERQ) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk("pci_alloc_consistent/alignment failure on ERQ: fatal error\n");
+		return -1;
+	}
+	fcChip->ERQ->length = ERQ_LEN - 1;
+	ulAddr = (u32) ERQdma;
 #if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! ERQ ptr %p exceeds Tachyon's 32-bit register size\n",
-		    (void*)ulAddr);
-    return -1;  // failed
-  }
+	if ((ulAddr >> 32)) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk(" FATAL! ERQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
+		return -1;	// failed
+	}
 #endif
-  fcChip->ERQ->base = (ULONG)ulAddr;  // copy for quick reference
+	fcChip->ERQ->base = (u32) ulAddr;	// copy for quick reference
 
 
-  // Allocate Tach's Inbound Message Queue (32 bytes per entry)
-  
-  fcChip->IMQ = fcMemManager( cpqfcHBAdata->PciDev, 
-		  &cpqfcHBAdata->dynamic_mem[0],
-		  sizeof( TachyonIMQ ), 32*(IMQ_LEN), 0L, &IMQdma );
-  if( !fcChip->IMQ )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent/alignment failure on IMQ: fatal error\n");
-    return -1;
-  }
-  fcChip->IMQ->length = IMQ_LEN-1;
+	// Allocate Tach's Inbound Message Queue (32 bytes per entry)
 
-  ulAddr = IMQdma;
+	fcChip->IMQ = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], sizeof(TachyonIMQ), 32 * (IMQ_LEN), 0L, &IMQdma);
+	if (!fcChip->IMQ) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk("pci_alloc_consistent/alignment failure on IMQ: fatal error\n");
+		return -1;
+	}
+	fcChip->IMQ->length = IMQ_LEN - 1;
+
+	ulAddr = IMQdma;
 #if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n",
-		    (void*)ulAddr);
-    return -1;  // failed
-  }
+	if ((ulAddr >> 32)) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
+		return -1;	// failed
+	}
 #endif
-  fcChip->IMQ->base = (ULONG)ulAddr;  // copy for quick reference
+	fcChip->IMQ->base = (u32) ulAddr;	// copy for quick reference
 
 
-  // Allocate Tach's  Single Frame Queue (64 bytes per entry)
-  fcChip->SFQ = fcMemManager( cpqfcHBAdata->PciDev, 
-		  &cpqfcHBAdata->dynamic_mem[0],
-		  sizeof( TachLiteSFQ ), 64*(SFQ_LEN),0L, &SPQdma );
-  if( !fcChip->SFQ )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent/alignment failure on SFQ: fatal error\n");
-    return -1;
-  }
-  fcChip->SFQ->length = SFQ_LEN-1;      // i.e. Que length [# entries -
-                                       // min. 32; max.  4096 (0xffff)]
-  
-  ulAddr = SPQdma;
+	// Allocate Tach's  Single Frame Queue (64 bytes per entry)
+	fcChip->SFQ = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], sizeof(TachLiteSFQ), 64 * (SFQ_LEN), 0L, &SPQdma);
+	if (!fcChip->SFQ) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk("pci_alloc_consistent/alignment failure on SFQ: fatal error\n");
+		return -1;
+	}
+	fcChip->SFQ->length = SFQ_LEN - 1;	// i.e. Que length [# entries -
+	// min. 32; max.  4096 (0xffff)]
+
+	ulAddr = SPQdma;
 #if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n",
-		    (void*)ulAddr);
-    return -1;  // failed
-  }
+	if ((ulAddr >> 32)) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
+		return -1;	// failed
+	}
 #endif
-  fcChip->SFQ->base = (ULONG)ulAddr;  // copy for quick reference
+	fcChip->SFQ->base = (u32) ulAddr;	// copy for quick reference
 
 
-  // Allocate SCSI Exchange State Table; aligned nearest @sizeof
-  // power-of-2 boundary
-  // LIVE DANGEROUSLY!  Assume the boundary for SEST mem will
-  // be on physical page (e.g. 4k) boundary.
-  printk("Allocating %u for TachSEST for %u Exchanges\n", 
-		 (ULONG)sizeof(TachSEST), TACH_SEST_LEN);
-  fcChip->SEST = fcMemManager( cpqfcHBAdata->PciDev,
-		  &cpqfcHBAdata->dynamic_mem[0],
-		  sizeof(TachSEST),  4, 0L, &SESTdma );
-//		  sizeof(TachSEST),  64*TACH_SEST_LEN, 0L );
-  if( !fcChip->SEST )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk("pci_alloc_consistent/alignment failure on SEST: fatal error\n");
-    return -1;
-  }
+	// Allocate SCSI Exchange State Table; aligned nearest @sizeof
+	// power-of-2 boundary
+	// LIVE DANGEROUSLY!  Assume the boundary for SEST mem will
+	// be on physical page (e.g. 4k) boundary.
+	printk("Allocating %u for TachSEST for %u Exchanges\n", (u32) sizeof(TachSEST), TACH_SEST_LEN);
+	fcChip->SEST = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], sizeof(TachSEST), 4, 0L, &SESTdma);
+//                sizeof(TachSEST),  64*TACH_SEST_LEN, 0L );
+	if (!fcChip->SEST) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk("pci_alloc_consistent/alignment failure on SEST: fatal error\n");
+		return -1;
+	}
 
-  for( i=0; i < TACH_SEST_LEN; i++)  // for each exchange
-      fcChip->SEST->sgPages[i] = NULL;
+	for (i = 0; i < TACH_SEST_LEN; i++)	// for each exchange
+		fcChip->SEST->sgPages[i] = NULL;
 
-  fcChip->SEST->length = TACH_SEST_LEN;  // e.g. DON'T subtract one 
-                                       // (TL/TS UG, pg 153)
+	fcChip->SEST->length = TACH_SEST_LEN;	// e.g. DON'T subtract one 
+	// (TL/TS UG, pg 153)
 
-  ulAddr = SESTdma; 
+	ulAddr = SESTdma;
 #if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n",
-		    (void*)ulAddr);
-    return -1;  // failed
-  }
+	if ((ulAddr >> 32)) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
+		return -1;	// failed
+	}
 #endif
-  fcChip->SEST->base = (ULONG)ulAddr;  // copy for quick reference
+	fcChip->SEST->base = (u32) ulAddr;	// copy for quick reference
+
+
+	// Now that structures are defined,
+	// fill in Tachyon chip registers...
+
+	// EEEEEEEE  EXCHANGE REQUEST QUEUE
 
+	writel(fcChip->ERQ->base, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
 
-			      // Now that structures are defined,
-			      // fill in Tachyon chip registers...
+	writel(fcChip->ERQ->length, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_LENGTH));
 
-			      // EEEEEEEE  EXCHANGE REQUEST QUEUE
 
-  writel( fcChip->ERQ->base, 
-    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
-      
-  writel( fcChip->ERQ->length,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_LENGTH));
-     
+	fcChip->ERQ->producerIndex = 0L;
+	writel(fcChip->ERQ->producerIndex, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX));
 
-  fcChip->ERQ->producerIndex = 0L;
-  writel( fcChip->ERQ->producerIndex,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX));
-      
 
-		// NOTE! write consumer index last, since the write
-		// causes Tachyon to process the other registers
+	// NOTE! write consumer index last, since the write
+	// causes Tachyon to process the other registers
 
-  ulAddr = ((unsigned long)&fcChip->ERQ->consumerIndex - 
-		(unsigned long)fcChip->ERQ) + (unsigned long) ERQdma;
+	ulAddr = ((unsigned long) &fcChip->ERQ->consumerIndex - (unsigned long) fcChip->ERQ) + (unsigned long) ERQdma;
 
-  // NOTE! Tachyon DMAs to the ERQ consumer Index host
-		// address; must be correctly aligned
-  writel( (ULONG)ulAddr,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_CONSUMER_INDEX_ADR));
+	// NOTE! Tachyon DMAs to the ERQ consumer Index host
+	// address; must be correctly aligned
+	writel((u32) ulAddr, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_CONSUMER_INDEX_ADR));
 
 
 
-				 // IIIIIIIIIIIII  INBOUND MESSAGE QUEUE
-				 // Tell Tachyon where the Que starts
+	// IIIIIIIIIIIII  INBOUND MESSAGE QUEUE
+	// Tell Tachyon where the Que starts
 
-  // set the Host's pointer for Tachyon to access
+	// set the Host's pointer for Tachyon to access
 
-  printk("  cpqfcTS: writing IMQ BASE %Xh  ", fcChip->IMQ->base );
-  writel( fcChip->IMQ->base, 
-    (fcChip->Registers.ReMapMemBase + IMQ_BASE));
+	printk("  cpqfcTS: writing IMQ BASE %Xh  ", fcChip->IMQ->base);
+	writel(fcChip->IMQ->base, (fcChip->Registers.ReMapMemBase + IMQ_BASE));
 
-  writel( fcChip->IMQ->length,
-    (fcChip->Registers.ReMapMemBase + IMQ_LENGTH));
+	writel(fcChip->IMQ->length, (fcChip->Registers.ReMapMemBase + IMQ_LENGTH));
 
-  writel( fcChip->IMQ->consumerIndex,
-    (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
+	writel(fcChip->IMQ->consumerIndex, (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
 
 
-		// NOTE: TachLite DMAs to the producerIndex host address
-		// must be correctly aligned with address bits 1-0 cleared
-    // Writing the BASE register clears the PI register, so write it last
-  ulAddr = ((unsigned long)&fcChip->IMQ->producerIndex - 
-		(unsigned long)fcChip->IMQ) + (unsigned long) IMQdma;
+	// NOTE: TachLite DMAs to the producerIndex host address
+	// must be correctly aligned with address bits 1-0 cleared
+	// Writing the BASE register clears the PI register, so write it last
+	ulAddr = ((unsigned long) &fcChip->IMQ->producerIndex - (unsigned long) fcChip->IMQ) + (unsigned long) IMQdma;
 
 #if BITS_PER_LONG > 32
-  if( (ulAddr >> 32) )
-  {
-    cpqfc_free_dma_consistent(cpqfcHBAdata);
-    printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n",
-		    (void*)ulAddr);
-    return -1;  // failed
-  }
+	if ((ulAddr >> 32)) {
+		cpqfc_free_dma_consistent(cpqfcHBAdata);
+		printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n", (void *) ulAddr);
+		return -1;	// failed
+	}
 #endif
 //#if DBG
-  printk("  PI %Xh\n", (ULONG)ulAddr );
+	printk("  PI %Xh\n", (u32) ulAddr);
 //#endif
-  writel( (ULONG)ulAddr, 
-    (fcChip->Registers.ReMapMemBase + IMQ_PRODUCER_INDEX));
+	writel((u32) ulAddr, (fcChip->Registers.ReMapMemBase + IMQ_PRODUCER_INDEX));
+
 
 
+	// SSSSSSSSSSSSSSS SINGLE FRAME SEQUENCE
+	// Tell TachLite where the Que starts
 
-				 // SSSSSSSSSSSSSSS SINGLE FRAME SEQUENCE
-				 // Tell TachLite where the Que starts
+	writel(fcChip->SFQ->base, (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_BASE));
 
-  writel( fcChip->SFQ->base, 
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_BASE));
+	writel(fcChip->SFQ->length, (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_LENGTH));
 
-  writel( fcChip->SFQ->length,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_LENGTH));
 
+	// tell TachLite where SEST table is & how long
+	writel(fcChip->SEST->base, (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE));
 
-         // tell TachLite where SEST table is & how long
-  writel( fcChip->SEST->base,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE));
+	printk("  cpqfcTS: SEST %p(virt): Wrote base %Xh @ %p\n", fcChip->SEST, fcChip->SEST->base, fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE);
 
-  printk("  cpqfcTS: SEST %p(virt): Wrote base %Xh @ %p\n",
-    fcChip->SEST, fcChip->SEST->base, 
-    fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE);
+	writel(fcChip->SEST->length, (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_LENGTH));
 
-  writel( fcChip->SEST->length,
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_LENGTH));
-      
-  writel( (TL_EXT_SG_PAGE_COUNT-1),
-    (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_SG_PAGE));
+	writel((TL_EXT_SG_PAGE_COUNT - 1), (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_SG_PAGE));
 
 
-  LEAVE("CreateTachLiteQues");
+	LEAVE("CreateTachLiteQues");
 
-  return iStatus;
+	return iStatus;
 }
 
 
@@ -361,83 +310,79 @@
 
 int CpqTsResetTachLite(void *pHBA, int type)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  ULONG ulBuff, i;
-  int ret_status=0; // def. success
-
-  ENTER("ResetTach");
-  
-  switch(type)
-  {
-
-    case CLEAR_FCPORTS:
-
-      // in case he was running previously, mask Tach's interrupt
-      writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN));
-      
-     // de-allocate mem for any Logged in ports
-      // (e.g., our module is unloading)
-      // search the forward linked list, de-allocating
-      // the memory we allocated when the port was initially logged in
-      {
-        PFC_LOGGEDIN_PORT pLoggedInPort = fcChip->fcPorts.pNextPort;
-        PFC_LOGGEDIN_PORT ptr;
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) pHBA;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	u32 ulBuff, i;
+	int ret_status = 0;	// def. success
+
+	ENTER("ResetTach");
+
+	switch (type) {
+
+	case CLEAR_FCPORTS:
+
+		// in case he was running previously, mask Tach's interrupt
+		writeb(0, (fcChip->Registers.ReMapMemBase + IINTEN));
+
+		// de-allocate mem for any Logged in ports
+		// (e.g., our module is unloading)
+		// search the forward linked list, de-allocating
+		// the memory we allocated when the port was initially logged in
+		{
+			PFC_LOGGEDIN_PORT pLoggedInPort = fcChip->fcPorts.pNextPort;
+			PFC_LOGGEDIN_PORT ptr;
 //        printk("checking for allocated LoggedInPorts...\n");
-			
-        while( pLoggedInPort )
-        {
-          ptr = pLoggedInPort;
-          pLoggedInPort = ptr->pNextPort;
-//	  printk("kfree(%p) on FC LoggedInPort port_id 0x%06lX\n",
-//			  ptr, ptr->port_id);
-          kfree( ptr );
-        }
-      }
-      // (continue resetting hardware...)
-
-    case 1:                   // RESTART Tachyon (power-up state)
-
-      // in case he was running previously, mask Tach's interrupt
-      writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN));
-			      // turn OFF laser (NOTE: laser is turned
-                              // off during reset, because GPIO4 is cleared
-                              // to 0 by reset action - see TLUM, sec 7.22)
-                              // However, CPQ 64-bit HBAs have a "health
-                              // circuit" which keeps laser ON for a brief
-                              // period after it is turned off ( < 1s)
-      
-      fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 0);
-  
-
-
-            // soft reset timing constraints require:
-            //   1. set RST to 1
-            //   2. read SOFTRST register 
-            //      (128 times per R. Callison code)
-            //   3. clear PCI ints
-            //   4. clear RST to 0
-      writel( 0xff000001L,
-        (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
-        
-      for( i=0; i<128; i++)
-        ulBuff = readl( fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST);
-
-        // clear the soft reset
-      for( i=0; i<8; i++)
-  	writel( 0, (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
-
-               
-
-			       // clear out our copy of Tach regs,
-			       // because they must be invalid now,
-			       // since TachLite reset all his regs.
-      CpqTsDestroyTachLiteQues(cpqfcHBAdata,0); // remove Host-based Que structs
-      cpqfcTSClearLinkStatusCounters(fcChip);  // clear our s/w accumulators
-                               // lower bits give GBIC info
-      fcChip->Registers.TYstatus.value = 
-	              readl( fcChip->Registers.TYstatus.address );
-      break;
+
+			while (pLoggedInPort) {
+				ptr = pLoggedInPort;
+				pLoggedInPort = ptr->pNextPort;
+//        printk("kfree(%p) on FC LoggedInPort port_id 0x%06lX\n",
+//                        ptr, ptr->port_id);
+				kfree(ptr);
+			}
+		}
+		// (continue resetting hardware...)
+
+	case 1:		// RESTART Tachyon (power-up state)
+
+		// in case he was running previously, mask Tach's interrupt
+		writeb(0, (fcChip->Registers.ReMapMemBase + IINTEN));
+		// turn OFF laser (NOTE: laser is turned
+		// off during reset, because GPIO4 is cleared
+		// to 0 by reset action - see TLUM, sec 7.22)
+		// However, CPQ 64-bit HBAs have a "health
+		// circuit" which keeps laser ON for a brief
+		// period after it is turned off ( < 1s)
+
+		fcChip->LaserControl(fcChip->Registers.ReMapMemBase, 0);
+
+
+
+		// soft reset timing constraints require:
+		//   1. set RST to 1
+		//   2. read SOFTRST register 
+		//      (128 times per R. Callison code)
+		//   3. clear PCI ints
+		//   4. clear RST to 0
+		writel(0xff000001L, (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
+
+		for (i = 0; i < 128; i++)
+			ulBuff = readl(fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST);
+
+		// clear the soft reset
+		for (i = 0; i < 8; i++)
+			writel(0, (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
+
+
+
+		// clear out our copy of Tach regs,
+		// because they must be invalid now,
+		// since TachLite reset all his regs.
+		CpqTsDestroyTachLiteQues(cpqfcHBAdata, 0);	// remove Host-based Que structs
+		cpqfcTSClearLinkStatusCounters(fcChip);	// clear our s/w accumulators
+		// lower bits give GBIC info
+		fcChip->Registers.TYstatus.value = readl(fcChip->Registers.TYstatus.address);
+		break;
 
 /*
     case 2:                   // freeze SCSI
@@ -447,12 +392,12 @@
 
     break;
 */
-    default:
-      ret_status = -1;  // invalid option passed to RESET function
-      break;
-  }
-  LEAVE("ResetTach");
-  return ret_status;
+	default:
+		ret_status = -1;	// invalid option passed to RESET function
+		break;
+	}
+	LEAVE("ResetTach");
+	return ret_status;
 }
 
 
@@ -461,18 +406,18 @@
 
 
 // 'addrBase' is IOBaseU for both TachLite and (older) Tachyon
-int CpqTsLaserControl( void* addrBase, int opcode )
+int CpqTsLaserControl(void *addrBase, int opcode)
 {
-  ULONG dwBuff;
+	u32 dwBuff;
 
-  dwBuff = readl((addrBase + TL_MEM_TACH_CONTROL) ); // read TL Control reg
-                                                    // (change only bit 4)
-  if( opcode == 1)
-    dwBuff |= ~0xffffffefL; // set - ON
-  else
-    dwBuff &= 0xffffffefL;  // clear - OFF
-  writel( dwBuff, (addrBase + TL_MEM_TACH_CONTROL)); // write TL Control reg
-  return 0;
+	dwBuff = readl((addrBase + TL_MEM_TACH_CONTROL));	// read TL Control reg
+	// (change only bit 4)
+	if (opcode == 1)
+		dwBuff |= ~0xffffffefL;	// set - ON
+	else
+		dwBuff &= 0xffffffefL;	// clear - OFF
+	writel(dwBuff, (addrBase + TL_MEM_TACH_CONTROL));	// write TL Control reg
+	return 0;
 }
 
 
@@ -484,102 +429,93 @@
 //   external loopback (GBIC - no FC loop)
 //   no loopback: L_PORT, external cable from GBIC required
 
-int CpqTsInitializeFrameManager( void *pChip, int opcode)
+int CpqTsInitializeFrameManager(void *pChip, int opcode)
 {
-  PTACHYON fcChip;
-  int iStatus;
-  ULONG wwnLo, wwnHi; // for readback verification
-
-  ENTER("InitializeFrameManager");
-  fcChip = (PTACHYON)pChip;
-  if( !fcChip->Registers.ReMapMemBase )   // undefined controller?
-    return -1;
-
-  // TL/TS UG, pg. 184
-  // 0x0065 = 100ms for RT_TOV
-  // 0x01f5 = 500ms for ED_TOV
-  // 0x07D1 = 2000ms 
-  fcChip->Registers.ed_tov.value = 0x006507D1; 
-  writel( fcChip->Registers.ed_tov.value,
-    (fcChip->Registers.ed_tov.address));
-      
-
-  // Set LP_TOV to the FC-AL2 specified 2 secs.
-  // TL/TS UG, pg. 185
-  writel( 0x07d00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
-
-
-  // Now try to read the WWN from the adapter's NVRAM
-  iStatus = CpqTsReadWriteWWN( fcChip, 1); // '1' for READ
-
-  if( iStatus )   // NVRAM read failed?
-  {
-    printk(" WARNING! HBA NVRAM WWN read failed - make alias\n");
-    // make up a WWN.  If NULL or duplicated on loop, FC loop may hang!
-
-
-    fcChip->Registers.wwn_hi = (__u32)jiffies;
-    fcChip->Registers.wwn_hi |= 0x50000000L;
-    fcChip->Registers.wwn_lo = 0x44556677L;
-  }
-
-  
-  writel( fcChip->Registers.wwn_hi, 
-	  fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI);
-  
-  writel( fcChip->Registers.wwn_lo, 
-	  fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
-	  
-
-  // readback for verification:
-  wwnHi = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI ); 
-          
-  wwnLo = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
-  // test for correct chip register WRITE/READ
-  DEBUG_PCI( printk("  WWN %08X%08X\n",
-    fcChip->Registers.wwn_hi, fcChip->Registers.wwn_lo ) );
-    
-  if( wwnHi != fcChip->Registers.wwn_hi ||
-      wwnLo != fcChip->Registers.wwn_lo )
-  {
-    printk( "cpqfcTS: WorldWideName register load failed\n");
-    return -1; // FAILED!
-  }
-
-
-
-			// set Frame Manager Initialize command
-  fcChip->Registers.FMcontrol.value = 0x06;
-
-  // Note: for test/debug purposes, we may use "Hard" address,
-  // but we completely support "soft" addressing, including
-  // dynamically changing our address.
-  if( fcChip->Options.intLoopback == 1 )            // internal loopback
-    fcChip->Registers.FMconfig.value = 0x0f002080L;
-  else if( fcChip->Options.extLoopback == 1 )            // internal loopback
-    fcChip->Registers.FMconfig.value = 0x0f004080L;
-  else                  // L_Port
-    fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start)
+	PTACHYON fcChip;
+	int iStatus;
+	u32 wwnLo, wwnHi;	// for readback verification
+
+	ENTER("InitializeFrameManager");
+	fcChip = (PTACHYON) pChip;
+	if (!fcChip->Registers.ReMapMemBase)	// undefined controller?
+		return -1;
+
+	// TL/TS UG, pg. 184
+	// 0x0065 = 100ms for RT_TOV
+	// 0x01f5 = 500ms for ED_TOV
+	// 0x07D1 = 2000ms 
+	fcChip->Registers.ed_tov.value = 0x006507D1;
+	writel(fcChip->Registers.ed_tov.value, (fcChip->Registers.ed_tov.address));
+
+
+	// Set LP_TOV to the FC-AL2 specified 2 secs.
+	// TL/TS UG, pg. 185
+	writel(0x07d00010, fcChip->Registers.ReMapMemBase + TL_MEM_FM_TIMEOUT2);
+
+
+	// Now try to read the WWN from the adapter's NVRAM
+	iStatus = CpqTsReadWriteWWN(fcChip, 1);	// '1' for READ
+
+	if (iStatus)		// NVRAM read failed?
+	{
+		printk(" WARNING! HBA NVRAM WWN read failed - make alias\n");
+		// make up a WWN.  If NULL or duplicated on loop, FC loop may hang!
+
+
+		fcChip->Registers.wwn_hi = (__u32) jiffies;
+		fcChip->Registers.wwn_hi |= 0x50000000L;
+		fcChip->Registers.wwn_lo = 0x44556677L;
+	}
+
+
+	writel(fcChip->Registers.wwn_hi, fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI);
+
+	writel(fcChip->Registers.wwn_lo, fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
+
+
+	// readback for verification:
+	wwnHi = readl(fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI);
+
+	wwnLo = readl(fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
+	// test for correct chip register WRITE/READ
+	DEBUG_PCI(printk("  WWN %08X%08X\n", fcChip->Registers.wwn_hi, fcChip->Registers.wwn_lo));
+
+	if (wwnHi != fcChip->Registers.wwn_hi || wwnLo != fcChip->Registers.wwn_lo) {
+		printk("cpqfcTS: WorldWideName register load failed\n");
+		return -1;	// FAILED!
+	}
+
+
+	// set Frame Manager Initialize command
+	fcChip->Registers.FMcontrol.value = 0x06;
+
+	// Note: for test/debug purposes, we may use "Hard" address,
+	// but we completely support "soft" addressing, including
+	// dynamically changing our address.
+	if (fcChip->Options.intLoopback == 1)	// internal loopback
+		fcChip->Registers.FMconfig.value = 0x0f002080L;
+	else if (fcChip->Options.extLoopback == 1)	// internal loopback
+		fcChip->Registers.FMconfig.value = 0x0f004080L;
+	else			// L_Port
+		fcChip->Registers.FMconfig.value = 0x55000100L;	// hard address (55h start)
 //    fcChip->Registers.FMconfig.value = 0x01000080L; // soft address (can't pick)
 //    fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start)
-		
-  // write config to FM
 
-  if( !fcChip->Options.intLoopback && !fcChip->Options.extLoopback )
-                               // (also need LASER for real LOOP)
-    fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 1); // turn on LASER
-
-  writel( fcChip->Registers.FMconfig.value,
-    fcChip->Registers.FMconfig.address);
-    
-
-			       // issue INITIALIZE command to FM - ACTION!
-  writel( fcChip->Registers.FMcontrol.value,
-    fcChip->Registers.FMcontrol.address);
-    
-  LEAVE("InitializeFrameManager");
-  
-  return 0;
+	// write config to FM
+
+	if (!fcChip->Options.intLoopback && !fcChip->Options.extLoopback)
+		// (also need LASER for real LOOP)
+		fcChip->LaserControl(fcChip->Registers.ReMapMemBase, 1);	// turn on LASER
+
+	writel(fcChip->Registers.FMconfig.value, fcChip->Registers.FMconfig.address);
+
+
+	// issue INITIALIZE command to FM - ACTION!
+	writel(fcChip->Registers.FMcontrol.value, fcChip->Registers.FMcontrol.address);
+
+	LEAVE("InitializeFrameManager");
+
+	return 0;
 }
 
 
@@ -588,102 +524,94 @@
 
 // This "look ahead" function examines the IMQ for occurence of
 // "type".  Returns 1 if found, 0 if not.
-static int PeekIMQEntry( PTACHYON fcChip, ULONG type)
+static int PeekIMQEntry(PTACHYON fcChip, u32 type)
 {
-  ULONG CI = fcChip->IMQ->consumerIndex;
-  ULONG PI = fcChip->IMQ->producerIndex; // snapshot of IMQ indexes
-  
-  while( CI != PI )
-  {                             // proceed with search
-    if( (++CI) >= IMQ_LEN ) CI = 0; // rollover check
-    
-    switch( type )
-    {
-      case ELS_LILP_FRAME:
-      {
-      // first, we need to find an Inbound Completion message,
-      // If we find it, check the incoming frame payload (1st word)
-      // for LILP frame
-        if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x104 )
-        { 
-          TachFCHDR_GCMND* fchs;
-          ULONG ulFibreFrame[2048/4];  // max DWORDS in incoming FC Frame
-	  USHORT SFQpi = (USHORT)(fcChip->IMQ->QEntry[CI].word[0] & 0x0fffL);
-
-	  CpqTsGetSFQEntry( fcChip,
-            SFQpi,        // SFQ producer ndx         
-	    ulFibreFrame, // contiguous dest. buffer
-	    FALSE);       // DON'T update chip--this is a "lookahead"
-          
-	  fchs = (TachFCHDR_GCMND*)&ulFibreFrame;
-          if( fchs->pl[0] == ELS_LILP_FRAME)
-	  {
-            return 1; // found the LILP frame!
-	  }
-	  else
-	  {
-	    // keep looking...
-	  }
-	}  
-      }
-      break;
+	u32 CI = fcChip->IMQ->consumerIndex;
+	u32 PI = fcChip->IMQ->producerIndex;	// snapshot of IMQ indexes
 
-      case OUTBOUND_COMPLETION:
-        if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x00 )
-	{
+	while (CI != PI) {	// proceed with search
+		if ((++CI) >= IMQ_LEN)
+			CI = 0;	// rollover check
+
+		switch (type) {
+		case ELS_LILP_FRAME:
+			{
+				// first, we need to find an Inbound Completion message,
+				// If we find it, check the incoming frame payload (1st word)
+				// for LILP frame
+				if ((fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x104) {
+					TachFCHDR_GCMND *fchs;
+					u32 ulFibreFrame[2048 / 4];	// max DWORDS in incoming FC Frame
+					u16 SFQpi = (u16) (fcChip->IMQ->QEntry[CI].word[0] & 0x0fffL);
+
+					CpqTsGetSFQEntry(fcChip, SFQpi,	// SFQ producer ndx         
+							 ulFibreFrame,	// contiguous dest. buffer
+							 FALSE);	// DON'T update chip--this is a "lookahead"
+
+					fchs = (TachFCHDR_GCMND *) & ulFibreFrame;
+					if (fchs->pl[0] == ELS_LILP_FRAME) {
+						return 1;	// found the LILP frame!
+					} else {
+						// keep looking...
+					}
+				}
+			}
+			break;
+
+		case OUTBOUND_COMPLETION:
+			if ((fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x00) {
+
+				// any OCM errors?
+				if (fcChip->IMQ->QEntry[CI].word[2] & 0x7a000000L)
+					return 1;	// found OCM error
+			}
+			break;
 
-          // any OCM errors?
-          if( fcChip->IMQ->QEntry[CI].word[2] & 0x7a000000L )
-            return 1;   	    // found OCM error
-	}
-      break;
 
 
-      
-      default:
-      break;
-    }
-  }
-  return 0; // failed to find "type"
+		default:
+			break;
+		}
+	}
+	return 0;		// failed to find "type"
 }
 
-			
-static void SetTachTOV( CPQFCHBA* cpqfcHBAdata)
+
+static void SetTachTOV(CPQFCHBA * cpqfcHBAdata)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip; 
-  
-  // TL/TS UG, pg. 184
-  // 0x0065 = 100ms for RT_TOV
-  // 0x01f5 = 500ms for ED_TOV
-  // 0x07d1 = 2000ms for ED_TOV
-
-  // SANMark Level 1 requires an "initialization backoff"
-  // (See "SANMark Test Suite Level 1":
-  // initialization_timeout.fcal.SANMark-1.fc)
-  // We have to use 2sec, 24sec, then 128sec when login/
-  // port discovery processes fail to complete.
-  
-  // when port discovery completes (logins done), we set
-  // ED_TOV to 500ms -- this is the normal operational case
-  // On the first Link Down, we'll move to 2 secs (7D1 ms)
-  if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x1f5)
-    fcChip->Registers.ed_tov.value = 0x006507D1; 
-  
-  // If we get another LST after we moved TOV to 2 sec,
-  // increase to 24 seconds (5DC1 ms) per SANMark!
-  else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x7D1)
-    fcChip->Registers.ed_tov.value = 0x00655DC1; 
-
-  // If we get still another LST, set the max TOV (Tachyon
-  // has only 16 bits for ms timer, so the max is 65.5 sec)
-  else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x5DC1)
-    fcChip->Registers.ed_tov.value = 0x0065FFFF; 
-
-  writel( fcChip->Registers.ed_tov.value,
-    (fcChip->Registers.ed_tov.address));
-  // keep the same 2sec LP_TOV 
-  writel( 0x07D00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
-}	
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+
+	// TL/TS UG, pg. 184
+	// 0x0065 = 100ms for RT_TOV
+	// 0x01f5 = 500ms for ED_TOV
+	// 0x07d1 = 2000ms for ED_TOV
+
+	// SANMark Level 1 requires an "initialization backoff"
+	// (See "SANMark Test Suite Level 1":
+	// initialization_timeout.fcal.SANMark-1.fc)
+	// We have to use 2sec, 24sec, then 128sec when login/
+	// port discovery processes fail to complete.
+
+	// when port discovery completes (logins done), we set
+	// ED_TOV to 500ms -- this is the normal operational case
+	// On the first Link Down, we'll move to 2 secs (7D1 ms)
+	if ((fcChip->Registers.ed_tov.value & 0xFFFF) <= 0x1f5)
+		fcChip->Registers.ed_tov.value = 0x006507D1;
+
+	// If we get another LST after we moved TOV to 2 sec,
+	// increase to 24 seconds (5DC1 ms) per SANMark!
+	else if ((fcChip->Registers.ed_tov.value & 0xFFFF) <= 0x7D1)
+		fcChip->Registers.ed_tov.value = 0x00655DC1;
+
+	// If we get still another LST, set the max TOV (Tachyon
+	// has only 16 bits for ms timer, so the max is 65.5 sec)
+	else if ((fcChip->Registers.ed_tov.value & 0xFFFF) <= 0x5DC1)
+		fcChip->Registers.ed_tov.value = 0x0065FFFF;
+
+	writel(fcChip->Registers.ed_tov.value, (fcChip->Registers.ed_tov.address));
+	// keep the same 2sec LP_TOV 
+	writel(0x07D00010, fcChip->Registers.ReMapMemBase + TL_MEM_FM_TIMEOUT2);
+}
 
 
 // The IMQ is an array with IMQ_LEN length, each element (QEntry)
@@ -709,924 +637,844 @@
 
 int CpqTsProcessIMQEntry(void *host)
 {
-  struct Scsi_Host *HostAdapter = (struct Scsi_Host *)host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip; 
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  int iStatus;
-  USHORT i, RPCset, DPCset;
-  ULONG x_ID;
-  ULONG ulBuff, dwStatus;
-  TachFCHDR_GCMND* fchs;
-  ULONG ulFibreFrame[2048/4];  // max number of DWORDS in incoming Fibre Frame
-  UCHAR ucInboundMessageType;  // Inbound CM, dword 3 "type" field
-
-  ENTER("ProcessIMQEntry");
-   
-
-				// check TachLite's IMQ producer index -
-				// is a new message waiting for us?
-				// equal indexes means empty que
+	struct Scsi_Host *HostAdapter = (struct Scsi_Host *) host;
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	int iStatus;
+	u16 i, RPCset, DPCset;
+	u32 x_ID;
+	u32 ulBuff, dwStatus;
+	TachFCHDR_GCMND *fchs;
+	u32 ulFibreFrame[2048 / 4];	// max number of DWORDS in incoming Fibre Frame
+	u8 ucInboundMessageType;	// Inbound CM, dword 3 "type" field
+
+	ENTER("ProcessIMQEntry");
+
+
+	// check TachLite's IMQ producer index -
+	// is a new message waiting for us?
+	// equal indexes means empty que
 
-  if( fcChip->IMQ->producerIndex != fcChip->IMQ->consumerIndex )
-  {                             // need to process message
+	if (fcChip->IMQ->producerIndex != fcChip->IMQ->consumerIndex) {	// need to process message
 
 
 #ifdef IMQ_DEBUG
-    printk("PI %X, CI %X  type: %X\n", 
-      fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex,
-      fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type);
-#endif                                
-    // Examine Completion Messages in IMQ
-    // what CM_Type?
-    switch( (UCHAR)(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type
-                    & 0xffL) )
-    {
-    case OUTBOUND_COMPLETION:
-
-      // Remarks:
-      // x_IDs (OX_ID, RX_ID) are partitioned by SEST entries
-      // (starting at 0), and SFS entries (starting at
-      // SEST_LEN -- outside the SEST space).
-      // Psuedo code:
-      // x_ID (OX_ID or RX_ID) from message is Trans_ID or SEST index
-      // range check - x_ID
-      //   if x_ID outside 'Transactions' length, error - exit
-      // if any OCM error, copy error status to Exchange slot
-      // if FCP ASSIST transaction (x_ID within SEST),
-      //   call fcComplete (to App)
-      // ...
-
-
-      ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1];
-      x_ID = ulBuff & 0x7fffL;     // lower 14 bits SEST_Index/Trans_ID
-                                     // Range check CM OX/RX_ID value...
-      if( x_ID < TACH_MAX_XID )   // don't go beyond array space
-      {
-
-
-	if( ulBuff & 0x20000000L ) // RPC -Response Phase Complete?
-          RPCset = 1;              // (SEST transactions only)
-        else
-          RPCset = 0;
-
-        if( ulBuff & 0x40000000L ) // DPC -Data Phase Complete?
-          DPCset = 1;              // (SEST transactions only)
-        else
-          DPCset = 0;
-                // set the status for this Outbound transaction's ID
-        dwStatus = 0L;
-        if( ulBuff & 0x10000000L ) // SPE? (SEST Programming Error)
-            dwStatus |= SESTPROG_ERR;
-
-        ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2];
-        if( ulBuff & 0x7a000000L ) // any other errs?
-        {
-          if( ulBuff & 0x40000000L )
-            dwStatus |= INV_ENTRY;
-          if( ulBuff & 0x20000000L )
-            dwStatus |= FRAME_TO;        // FTO
-          if( ulBuff & 0x10000000L )
-            dwStatus |= HOSTPROG_ERR;
-          if( ulBuff & 0x08000000L )
-            dwStatus |= LINKFAIL_TX;
-          if( ulBuff & 0x02000000L )
-            dwStatus |= ABORTSEQ_NOTIFY;  // ASN
-        }
-
-	  
-	if( dwStatus )          // any errors?
-        {
-                  // set the Outbound Completion status
-          Exchanges->fcExchange[ x_ID ].status |= dwStatus;
-
-          // if this Outbound frame was for a SEST entry, automatically
-          // reque it in the case of LINKFAIL (it will restart on PDISC)
-          if( x_ID < TACH_SEST_LEN )
-          {
-
-            printk(" #OCM error %Xh x_ID %X# ", 
-		    dwStatus, x_ID);
-
-	    Exchanges->fcExchange[x_ID].timeOut = 30000; // seconds default
-                                                 
-
-	    // We Q ABTS for each exchange.
-	    // NOTE: We can get FRAME_TO on bad alpa (device gone).  Since
-	    // bad alpa is reported before FRAME_TO, examine the status
-	    // flags to see if the device is removed.  If so, DON'T
-	    // post an ABTS, since it will be terminated by the bad alpa
-	    // message.
-	    if( dwStatus & FRAME_TO ) // check for device removed...
-	    {
-	      if( !(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) )
-	      { 
-		// presumes device is still there: send ABTS.
-  
-                cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
-	      }
-	    }
-	    else  // Abort all other errors
-	    {
-              cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
-	    }
-
-            // if the HPE bit is set, we have to CLose the LOOP
-            // (see TL/TS UG, pg. 239)
-
-            if( dwStatus &= HOSTPROG_ERR )
-            // set CL bit (see TL/TS UG, pg. 172)
-              writel( 4, fcChip->Registers.FMcontrol.address);
-          }
-        }
-          // NOTE: we don't necessarily care about ALL completion messages...
-                                      // SCSI resp. complete OR
-        if( ((x_ID < TACH_SEST_LEN) && RPCset)|| 
-             (x_ID >= TACH_SEST_LEN) )  // non-SCSI command
-        {
-              // exchange done; complete to upper levels with status
-              // (if necessary) and free the exchange slot
-            
-
-          if( x_ID >= TACH_SEST_LEN ) // Link Service Outbound frame?
-                                    // A Request or Reply has been sent
-          {                         // signal waiting WorkerThread
-
-            up( cpqfcHBAdata->TYOBcomplete);   // frame is OUT of Tach
-
-                                    // WorkerThread will complete Xchng
-          }
-          else  // X_ID is for FCP assist (SEST)
-          {
-              // TBD (target mode)
+		printk("PI %X, CI %X  type: %X\n", fcChip->IMQ->producerIndex, fcChip->IMQ->consumerIndex, fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type);
+#endif
+		// Examine Completion Messages in IMQ
+		// what CM_Type?
+		switch ((u8) (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type & 0xffL)) {
+		case OUTBOUND_COMPLETION:
+
+			// Remarks:
+			// x_IDs (OX_ID, RX_ID) are partitioned by SEST entries
+			// (starting at 0), and SFS entries (starting at
+			// SEST_LEN -- outside the SEST space).
+			// Psuedo code:
+			// x_ID (OX_ID or RX_ID) from message is Trans_ID or SEST index
+			// range check - x_ID
+			//   if x_ID outside 'Transactions' length, error - exit
+			// if any OCM error, copy error status to Exchange slot
+			// if FCP ASSIST transaction (x_ID within SEST),
+			//   call fcComplete (to App)
+			// ...
+
+
+			ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1];
+			x_ID = ulBuff & 0x7fffL;	// lower 14 bits SEST_Index/Trans_ID
+			// Range check CM OX/RX_ID value...
+			if (x_ID < TACH_MAX_XID)	// don't go beyond array space
+			{
+
+
+				if (ulBuff & 0x20000000L)	// RPC -Response Phase Complete?
+					RPCset = 1;	// (SEST transactions only)
+				else
+					RPCset = 0;
+
+				if (ulBuff & 0x40000000L)	// DPC -Data Phase Complete?
+					DPCset = 1;	// (SEST transactions only)
+				else
+					DPCset = 0;
+				// set the status for this Outbound transaction's ID
+				dwStatus = 0L;
+				if (ulBuff & 0x10000000L)	// SPE? (SEST Programming Error)
+					dwStatus |= SESTPROG_ERR;
+
+				ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2];
+				if (ulBuff & 0x7a000000L)	// any other errs?
+				{
+					if (ulBuff & 0x40000000L)
+						dwStatus |= INV_ENTRY;
+					if (ulBuff & 0x20000000L)
+						dwStatus |= FRAME_TO;	// FTO
+					if (ulBuff & 0x10000000L)
+						dwStatus |= HOSTPROG_ERR;
+					if (ulBuff & 0x08000000L)
+						dwStatus |= LINKFAIL_TX;
+					if (ulBuff & 0x02000000L)
+						dwStatus |= ABORTSEQ_NOTIFY;	// ASN
+				}
+
+
+				if (dwStatus)	// any errors?
+				{
+					// set the Outbound Completion status
+					Exchanges->fcExchange[x_ID].status |= dwStatus;
+
+					// if this Outbound frame was for a SEST entry, automatically
+					// reque it in the case of LINKFAIL (it will restart on PDISC)
+					if (x_ID < TACH_SEST_LEN) {
+
+						printk(" #OCM error %Xh x_ID %X# ", dwStatus, x_ID);
+
+						Exchanges->fcExchange[x_ID].timeOut = 30000;	// seconds default
+
+
+						// We Q ABTS for each exchange.
+						// NOTE: We can get FRAME_TO on bad alpa (device gone).  Since
+						// bad alpa is reported before FRAME_TO, examine the status
+						// flags to see if the device is removed.  If so, DON'T
+						// post an ABTS, since it will be terminated by the bad alpa
+						// message.
+						if (dwStatus & FRAME_TO)	// check for device removed...
+						{
+							if (!(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)) {
+								// presumes device is still there: send ABTS.
+
+								cpqfcTSPutLinkQue(cpqfcHBAdata, BLS_ABTS, &x_ID);
+							}
+						} else	// Abort all other errors
+						{
+							cpqfcTSPutLinkQue(cpqfcHBAdata, BLS_ABTS, &x_ID);
+						}
+
+						// if the HPE bit is set, we have to CLose the LOOP
+						// (see TL/TS UG, pg. 239)
+
+						if (dwStatus &= HOSTPROG_ERR)
+							// set CL bit (see TL/TS UG, pg. 172)
+							writel(4, fcChip->Registers.FMcontrol.address);
+					}
+				}
+				// NOTE: we don't necessarily care about ALL completion messages...
+				// SCSI resp. complete OR
+				if (((x_ID < TACH_SEST_LEN) && RPCset) || (x_ID >= TACH_SEST_LEN))	// non-SCSI command
+				{
+					// exchange done; complete to upper levels with status
+					// (if necessary) and free the exchange slot
+
+
+					if (x_ID >= TACH_SEST_LEN)	// Link Service Outbound frame?
+						// A Request or Reply has been sent
+					{	// signal waiting WorkerThread
+
+						up(cpqfcHBAdata->TYOBcomplete);	// frame is OUT of Tach
+
+						// WorkerThread will complete Xchng
+					} else	// X_ID is for FCP assist (SEST)
+					{
+						// TBD (target mode)
 //            fcCompleteExchange( fcChip, x_ID); // TRE completed
-          }
-        }
-      }
-      else  // ERROR CONDITION!  bogus x_ID in completion message
-      {
-
-        printk(" ProcessIMQ (OBCM) x_id out of range %Xh\n", x_ID);
-
-      }
+					}
+				}
+			} else	// ERROR CONDITION!  bogus x_ID in completion message
+			{
 
+				printk(" ProcessIMQ (OBCM) x_id out of range %Xh\n", x_ID);
 
+			}
 
-          // Load the Frame Manager's error counters.  We check them here
-          // because presumably the link is up and healthy enough for the
-          // counters to be meaningful (i.e., don't check them while loop
-          // is initializing).
-      fcChip->Registers.FMLinkStatus1.value =    // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus1.address);
-                  
-      fcChip->Registers.FMLinkStatus2.value =    // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus2.address);
-            
 
-      fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators
-    break;
 
+			// Load the Frame Manager's error counters.  We check them here
+			// because presumably the link is up and healthy enough for the
+			// counters to be meaningful (i.e., don't check them while loop
+			// is initializing).
+			fcChip->Registers.FMLinkStatus1.value =	// get TL's counter
+			    readl(fcChip->Registers.FMLinkStatus1.address);
 
+			fcChip->Registers.FMLinkStatus2.value =	// get TL's counter
+			    readl(fcChip->Registers.FMLinkStatus2.address);
 
-    case ERROR_IDLE_COMPLETION:  // TachLite Error Idle...
-    
-    // We usually get this when the link goes down during heavy traffic.
-    // For now, presume that if SEST Exchanges are open, we will
-    // get this as our cue to INVALIDATE all SEST entries
-    // (and we OWN all the SEST entries).
-    // See TL/TS UG, pg. 53
-    
-      for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
-      {
-
-        // Does this VALid SEST entry need to be invalidated for Abort?
-        fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF; 
-      }
-      
-      CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachyon, if Link OK
 
-    break;
+			fcParseLinkStatusCounters(fcChip);	// load into 6 s/w accumulators
+			break;
+
+
+
+		case ERROR_IDLE_COMPLETION:	// TachLite Error Idle...
+
+			// We usually get this when the link goes down during heavy traffic.
+			// For now, presume that if SEST Exchanges are open, we will
+			// get this as our cue to INVALIDATE all SEST entries
+			// (and we OWN all the SEST entries).
+			// See TL/TS UG, pg. 53
+
+			for (x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) {
+
+				// Does this VALid SEST entry need to be invalidated for Abort?
+				fcChip->SEST->u[x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
+			}
+
+			CpqTsUnFreezeTachlite(fcChip, 2);	// unfreeze Tachyon, if Link OK
+
+			break;
+
+
+		case INBOUND_SFS_COMPLETION:	//0x04
+			// NOTE! we must process this SFQ message to avoid SFQ filling
+			// up and stopping TachLite.  Incoming commands are placed here,
+			// as well as 'unknown' frames (e.g. LIP loop position data)
+			// write this CM's producer index to global...
+			// TL/TS UG, pg 234:
+			// Type: 0 - reserved
+			//       1 - Unassisted FCP
+			//       2 - BAD FCP
+			//       3 - Unkown Frame
+			//       4-F reserved
+
 
+			fcChip->SFQ->producerIndex = (u16)
+			    (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] & 0x0fffL);
 
-    case INBOUND_SFS_COMPLETION:  //0x04
-          // NOTE! we must process this SFQ message to avoid SFQ filling
-          // up and stopping TachLite.  Incoming commands are placed here,
-          // as well as 'unknown' frames (e.g. LIP loop position data)
-          // write this CM's producer index to global...
-          // TL/TS UG, pg 234:
-          // Type: 0 - reserved
-          //       1 - Unassisted FCP
-          //       2 - BAD FCP
-          //       3 - Unkown Frame
-          //       4-F reserved
-
-
-      fcChip->SFQ->producerIndex = (USHORT)
-        (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] & 0x0fffL);
-
-
-      ucInboundMessageType = 0;  // default to useless frame
-
-        // we can only process two Types: 1, Unassisted FCP, and 3, Unknown
-        // Also, we aren't interested in processing frame fragments
-        // so don't Que anything with 'LKF' bit set
-      if( !(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] 
-        & 0x40000000) )  // 'LKF' link failure bit clear?
-      {
-        ucInboundMessageType = (UCHAR)  // ICM DWord3, "Type"
-        (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] & 0x0fL);
-      }
-      else
-      {
-	fcChip->fcStats.linkFailRX++;
+
+			ucInboundMessageType = 0;	// default to useless frame
+
+			// we can only process two Types: 1, Unassisted FCP, and 3, Unknown
+			// Also, we aren't interested in processing frame fragments
+			// so don't Que anything with 'LKF' bit set
+			if (!(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2]
+			      & 0x40000000))	// 'LKF' link failure bit clear?
+			{
+				ucInboundMessageType = (u8)	// ICM DWord3, "Type"
+				    (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] & 0x0fL);
+			} else {
+				fcChip->fcStats.linkFailRX++;
 //        printk("LKF (link failure) bit set on inbound message\n");
-      }
+			}
+
+			// clears SFQ entry from Tachyon buffer; copies to contiguous ulBuff
+			CpqTsGetSFQEntry(fcChip,	// i.e. this Device Object
+					 (u16) fcChip->SFQ->producerIndex,	// SFQ producer ndx         
+					 ulFibreFrame, TRUE);	// contiguous destination buffer, update chip
+
+			// analyze the incoming frame outside the INT handler...
+			// (i.e., Worker)
+
+			if (ucInboundMessageType == 1) {
+				fchs = (TachFCHDR_GCMND *) ulFibreFrame;	// cast to examine IB frame
+				// don't fill up our Q with garbage - only accept FCP-CMND  
+				// or XRDY frames
+				if ((fchs->d_id & 0xFF000000) == 0x06000000)	// CMND
+				{
+					// someone sent us a SCSI command
 
-          // clears SFQ entry from Tachyon buffer; copies to contiguous ulBuff
-      CpqTsGetSFQEntry(
-        fcChip,                  // i.e. this Device Object
-        (USHORT)fcChip->SFQ->producerIndex,  // SFQ producer ndx         
-        ulFibreFrame, TRUE);    // contiguous destination buffer, update chip
-                     
-        // analyze the incoming frame outside the INT handler...
-        // (i.e., Worker)
-
-      if( ucInboundMessageType == 1 )
-      {
-        fchs = (TachFCHDR_GCMND*)ulFibreFrame; // cast to examine IB frame
-        // don't fill up our Q with garbage - only accept FCP-CMND  
-        // or XRDY frames
-        if( (fchs->d_id & 0xFF000000) == 0x06000000 ) // CMND
-        {
-	  // someone sent us a SCSI command
-	  
 //          fcPutScsiQue( cpqfcHBAdata, 
 //                        SFQ_UNASSISTED_FCP, ulFibreFrame); 
-	}
-	else if( ((fchs->d_id & 0xFF000000) == 0x07000000) || // RSP (status)
-            (fchs->d_id & 0xFF000000) == 0x05000000 )  // XRDY  
-	{
-	  ULONG x_ID;
-	  // Unfortunately, ABTS requires a Freeze on the chip so
-	  // we can modify the shared memory SEST.  When frozen,
-	  // any received Exchange frames cannot be processed by
-	  // Tachyon, so they will be dumped in here.  It is too
-	  // complex to attempt the reconstruct these frames in
-	  // the correct Exchange context, so we simply seek to
-	  // find status or transfer ready frames, and cause the
-	  // exchange to complete with errors before the timeout
-	  // expires.  We use a Linux Scsi Cmnd result code that
-	  // causes immediate retry.
-	  
-
-	  // Do we have an open exchange that matches this s_id
-	  // and ox_id?
-	  for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
-	  {
-            if( (fchs->s_id & 0xFFFFFF) == 
-                 (Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF) 
-		       &&
-                (fchs->ox_rx_id & 0xFFFF0000) == 
-                 (Exchanges->fcExchange[x_ID].fchs.ox_rx_id & 0xFFFF0000) )
-	    {
-    //          printk(" #R/X frame x_ID %08X# ", fchs->ox_rx_id );
-              // simulate the anticipated error - since the
-	      // SEST was frozen, frames were lost...
-              Exchanges->fcExchange[ x_ID ].status |= SFQ_FRAME;
-              
-	      // presumes device is still there: send ABTS.
-              cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
-	      break;  // done
-	    }
-	  }
-	}
-	  
-      }
-          
-      else if( ucInboundMessageType == 3)
-      {
-        // FC Link Service frames (e.g. PLOGI, ACC) come in here.  
-        cpqfcTSPutLinkQue( cpqfcHBAdata, SFQ_UNKNOWN, ulFibreFrame); 
-                          
-      }
+				} else if (((fchs->d_id & 0xFF000000) == 0x07000000) ||	// RSP (status)
+					   (fchs->d_id & 0xFF000000) == 0x05000000)	// XRDY  
+				{
+					u32 x_ID;
+					// Unfortunately, ABTS requires a Freeze on the chip so
+					// we can modify the shared memory SEST.  When frozen,
+					// any received Exchange frames cannot be processed by
+					// Tachyon, so they will be dumped in here.  It is too
+					// complex to attempt the reconstruct these frames in
+					// the correct Exchange context, so we simply seek to
+					// find status or transfer ready frames, and cause the
+					// exchange to complete with errors before the timeout
+					// expires.  We use a Linux Scsi Cmnd result code that
+					// causes immediate retry.
+
+
+					// Do we have an open exchange that matches this s_id
+					// and ox_id?
+					for (x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) {
+						if ((fchs->s_id & 0xFFFFFF) == (Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF)
+						    && (fchs->ox_rx_id & 0xFFFF0000) == (Exchanges->fcExchange[x_ID].fchs.ox_rx_id & 0xFFFF0000)) {
+							//          printk(" #R/X frame x_ID %08X# ", fchs->ox_rx_id );
+							// simulate the anticipated error - since the
+							// SEST was frozen, frames were lost...
+							Exchanges->fcExchange[x_ID].status |= SFQ_FRAME;
+
+							// presumes device is still there: send ABTS.
+							cpqfcTSPutLinkQue(cpqfcHBAdata, BLS_ABTS, &x_ID);
+							break;	// done
+						}
+					}
+				}
+
+			}
+
+			else if (ucInboundMessageType == 3) {
+				// FC Link Service frames (e.g. PLOGI, ACC) come in here.  
+				cpqfcTSPutLinkQue(cpqfcHBAdata, SFQ_UNKNOWN, ulFibreFrame);
+
+			}
 
-      else if( ucInboundMessageType == 2 ) // "bad FCP"?
-      {
+			else if (ucInboundMessageType == 2)	// "bad FCP"?
+			{
 #ifdef IMQ_DEBUG
-        printk("Bad FCP incoming frame discarded\n");
+				printk("Bad FCP incoming frame discarded\n");
 #endif
-      }
+			}
 
-      else // don't know this type
-      {
-#ifdef IMQ_DEBUG 
-        printk("Incoming frame discarded, type: %Xh\n", ucInboundMessageType);
+			else	// don't know this type
+			{
+#ifdef IMQ_DEBUG
+				printk("Incoming frame discarded, type: %Xh\n", ucInboundMessageType);
 #endif
-      }
-        
-        // Check the Frame Manager's error counters.  We check them here
-        // because presumably the link is up and healthy enough for the
-        // counters to be meaningful (i.e., don't check them while loop
-        // is initializing).
-      fcChip->Registers.FMLinkStatus1.value =    // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus1.address);
-                  
-
-      fcChip->Registers.FMLinkStatus2.value =    // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus2.address);
-                
-
-      break;
+			}
 
+			// Check the Frame Manager's error counters.  We check them here
+			// because presumably the link is up and healthy enough for the
+			// counters to be meaningful (i.e., don't check them while loop
+			// is initializing).
+			fcChip->Registers.FMLinkStatus1.value =	// get TL's counter
+			    readl(fcChip->Registers.FMLinkStatus1.address);
 
 
+			fcChip->Registers.FMLinkStatus2.value =	// get TL's counter
+			    readl(fcChip->Registers.FMLinkStatus2.address);
 
-                    // We get this CM because we issued a freeze
-                    // command to stop outbound frames.  We issue the
-                    // freeze command at Link Up time; when this message
-                    // is received, the ERQ base can be switched and PDISC
-                    // frames can be sent.
-
-      
-    case ERQ_FROZEN_COMPLETION:  // note: expect ERQ followed immediately
-                                 // by FCP when freezing TL
-      fcChip->Registers.TYstatus.value =         // read what's frozen
-        readl(fcChip->Registers.TYstatus.address);
-      // (do nothing; wait for FCP frozen message)
-      break;
-    case FCP_FROZEN_COMPLETION:
-      
-      fcChip->Registers.TYstatus.value =         // read what's frozen
-        readl(fcChip->Registers.TYstatus.address);
-      
-      // Signal the kernel thread to proceed with SEST modification
-      up( cpqfcHBAdata->TachFrozen);
-
-      break;
 
+			break;
 
 
-    case INBOUND_C1_TIMEOUT:
-    case MFS_BUF_WARN:
-    case IMQ_BUF_WARN:
-    break;
 
 
+			// We get this CM because we issued a freeze
+			// command to stop outbound frames.  We issue the
+			// freeze command at Link Up time; when this message
+			// is received, the ERQ base can be switched and PDISC
+			// frames can be sent.
 
 
+		case ERQ_FROZEN_COMPLETION:	// note: expect ERQ followed immediately
+			// by FCP when freezing TL
+			fcChip->Registers.TYstatus.value =	// read what's frozen
+			    readl(fcChip->Registers.TYstatus.address);
+			// (do nothing; wait for FCP frozen message)
+			break;
+		case FCP_FROZEN_COMPLETION:
 
-        // In older Tachyons, we 'clear' the internal 'core' interrupt state
-        // by reading the FMstatus register.  In newer TachLite (Tachyon),
-        // we must WRITE the register
-        // to clear the condition (TL/TS UG, pg 179)
-    case FRAME_MGR_INTERRUPT:
-    {
-      PFC_LOGGEDIN_PORT pLoggedInPort; 
-
-      fcChip->Registers.FMstatus.value = 
-        readl( fcChip->Registers.FMstatus.address );
-                
-      // PROBLEM: It is possible, especially with "dumb" hubs that
-      // don't automatically LIP on by-pass of ports that are going
-      // away, for the hub by-pass process to destroy critical 
-      // ordered sets of a frame.  The result of this is a hung LPSM
-      // (Loop Port State Machine), which on Tachyon results in a
-      // (default 2 sec) Loop State Timeout (LST) FM message.  We 
-      // want to avoid this relatively huge timeout by detecting
-      // likely scenarios which will result in LST.
-      // To do this, we could examine FMstatus for Loss of Synchronization
-      // and/or Elastic Store (ES) errors.  Of these, Elastic Store is better
-      // because we get this indication more quickly than the LOS.
-      // Not all ES errors are harmfull, so we don't want to LIP on every
-      // ES.  Instead, on every ES, detect whether our LPSM in in one
-      // of the LST states: ARBITRATING, OPEN, OPENED, XMITTED CLOSE,
-      // or RECEIVED CLOSE.  (See TL/TS UG, pg. 181)
-      // If any of these LPSM states are detected
-      // in combination with the LIP while LDn is not set, 
-      // send an FM init (LIP F7,F7 for loops)!
-      // It is critical to the physical link stability NOT to reset (LIP)
-      // more than absolutely necessary; this is a basic premise of the
-      // SANMark level 1 spec.
-      {
-	ULONG Lpsm = (fcChip->Registers.FMstatus.value & 0xF0) >>4;
-	
-	if( (fcChip->Registers.FMstatus.value & 0x400)  // ElasticStore?
-                      &&
-            !(fcChip->Registers.FMstatus.value & 0x100) // NOT LDn
-	              &&
-            !(fcChip->Registers.FMstatus.value & 0x1000)) // NOT LF
-	{
-	  if( (Lpsm != 0) || // not MONITORING? or
-	      !(Lpsm & 0x8) )// not already offline?
-	  {
-	  // now check the particular LST states...
-            if( (Lpsm == ARBITRATING) || (Lpsm == OPEN) ||
-	      (Lpsm == OPENED)      || (Lpsm == XMITTD_CLOSE) ||
-	      (Lpsm == RCVD_CLOSE) )
-	    {
-	      // re-init the loop before it hangs itself!
-              printk(" #req FMinit on E-S: LPSM %Xh# ",Lpsm);
-
-
-	      fcChip->fcStats.FMinits++;
-              writel( 6, fcChip->Registers.FMcontrol.address); // LIP
-	    }
-	  }
-	}
-	else if( fcChip->Registers.FMstatus.value & 0x40000 ) // LST?
-	{
-          printk(" #req FMinit on LST, LPSM %Xh# ",Lpsm);
-	 
-          fcChip->fcStats.FMinits++;
-          writel( 6, fcChip->Registers.FMcontrol.address);  // LIP
-	}  
-      }
-
-
-      // clear only the 'interrupting' type bits for this REG read
-      writel( (fcChip->Registers.FMstatus.value & 0xff3fff00L),
-        fcChip->Registers.FMstatus.address);
-                          
-
-               // copy frame manager status to unused ULONG slot
-      fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] =
-          fcChip->Registers.FMstatus.value; // (for debugging)
-
-
-          // Load the Frame Manager's error counters.  We check them here
-          // because presumably the link is up and healthy enough for the
-          // counters to be meaningful (i.e., don't check them while loop
-          // is initializing).
-      fcChip->Registers.FMLinkStatus1.value =   // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus1.address);
-            
-      fcChip->Registers.FMLinkStatus2.value =   // get TL's counter
-        readl(fcChip->Registers.FMLinkStatus2.address);
-          
-          // Get FM BB_Credit Zero Reg - does not clear on READ
-      fcChip->Registers.FMBB_CreditZero.value =   // get TL's counter
-        readl(fcChip->Registers.FMBB_CreditZero.address);
-            
-
-
-      fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators
-
-
-               // LINK DOWN
-
-      if( fcChip->Registers.FMstatus.value & 0x100L ) // Link DOWN bit
-      {                                 
-	
-#ifdef IMQ_DEBUG
-        printk("LinkDn\n");
-#endif
-        printk(" #LDn# ");
-        
-        fcChip->fcStats.linkDown++;
-        
-	SetTachTOV( cpqfcHBAdata);  // must set according to SANMark
+			fcChip->Registers.TYstatus.value =	// read what's frozen
+			    readl(fcChip->Registers.TYstatus.address);
 
-	// Check the ERQ - force it to be "empty" to prevent Tach
-	// from sending out frames before we do logins.
+			// Signal the kernel thread to proceed with SEST modification
+			up(cpqfcHBAdata->TachFrozen);
 
+			break;
+
+
+
+		case INBOUND_C1_TIMEOUT:
+		case MFS_BUF_WARN:
+		case IMQ_BUF_WARN:
+			break;
+
+
+
+
+
+			// In older Tachyons, we 'clear' the internal 'core' interrupt state
+			// by reading the FMstatus register.  In newer TachLite (Tachyon),
+			// we must WRITE the register
+			// to clear the condition (TL/TS UG, pg 179)
+		case FRAME_MGR_INTERRUPT:
+			{
+				PFC_LOGGEDIN_PORT pLoggedInPort;
+
+				fcChip->Registers.FMstatus.value = readl(fcChip->Registers.FMstatus.address);
+
+				// PROBLEM: It is possible, especially with "dumb" hubs that
+				// don't automatically LIP on by-pass of ports that are going
+				// away, for the hub by-pass process to destroy critical 
+				// ordered sets of a frame.  The result of this is a hung LPSM
+				// (Loop Port State Machine), which on Tachyon results in a
+				// (default 2 sec) Loop State Timeout (LST) FM message.  We 
+				// want to avoid this relatively huge timeout by detecting
+				// likely scenarios which will result in LST.
+				// To do this, we could examine FMstatus for Loss of Synchronization
+				// and/or Elastic Store (ES) errors.  Of these, Elastic Store is better
+				// because we get this indication more quickly than the LOS.
+				// Not all ES errors are harmfull, so we don't want to LIP on every
+				// ES.  Instead, on every ES, detect whether our LPSM in in one
+				// of the LST states: ARBITRATING, OPEN, OPENED, XMITTED CLOSE,
+				// or RECEIVED CLOSE.  (See TL/TS UG, pg. 181)
+				// If any of these LPSM states are detected
+				// in combination with the LIP while LDn is not set, 
+				// send an FM init (LIP F7,F7 for loops)!
+				// It is critical to the physical link stability NOT to reset (LIP)
+				// more than absolutely necessary; this is a basic premise of the
+				// SANMark level 1 spec.
+				{
+					u32 Lpsm = (fcChip->Registers.FMstatus.value & 0xF0) >> 4;
+
+					if ((fcChip->Registers.FMstatus.value & 0x400)	// ElasticStore?
+					    && !(fcChip->Registers.FMstatus.value & 0x100)	// NOT LDn
+					    && !(fcChip->Registers.FMstatus.value & 0x1000))	// NOT LF
+					{
+						if ((Lpsm != 0) ||	// not MONITORING? or
+						    !(Lpsm & 0x8))	// not already offline?
+						{
+							// now check the particular LST states...
+							if ((Lpsm == ARBITRATING) || (Lpsm == OPEN) || (Lpsm == OPENED) || (Lpsm == XMITTD_CLOSE) || (Lpsm == RCVD_CLOSE)) {
+								// re-init the loop before it hangs itself!
+								printk(" #req FMinit on E-S: LPSM %Xh# ", Lpsm);
+
+
+								fcChip->fcStats.FMinits++;
+								writel(6, fcChip->Registers.FMcontrol.address);	// LIP
+							}
+						}
+					} else if (fcChip->Registers.FMstatus.value & 0x40000)	// LST?
+					{
+						printk(" #req FMinit on LST, LPSM %Xh# ", Lpsm);
+
+						fcChip->fcStats.FMinits++;
+						writel(6, fcChip->Registers.FMcontrol.address);	// LIP
+					}
+				}
+
+
+				// clear only the 'interrupting' type bits for this REG read
+				writel((fcChip->Registers.FMstatus.value & 0xff3fff00L), fcChip->Registers.FMstatus.address);
+
+
+				// copy frame manager status to unused u32 slot
+				fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] = fcChip->Registers.FMstatus.value;	// (for debugging)
+
+
+				// Load the Frame Manager's error counters.  We check them here
+				// because presumably the link is up and healthy enough for the
+				// counters to be meaningful (i.e., don't check them while loop
+				// is initializing).
+				fcChip->Registers.FMLinkStatus1.value =	// get TL's counter
+				    readl(fcChip->Registers.FMLinkStatus1.address);
+
+				fcChip->Registers.FMLinkStatus2.value =	// get TL's counter
+				    readl(fcChip->Registers.FMLinkStatus2.address);
+
+				// Get FM BB_Credit Zero Reg - does not clear on READ
+				fcChip->Registers.FMBB_CreditZero.value =	// get TL's counter
+				    readl(fcChip->Registers.FMBB_CreditZero.address);
+
+
+
+				fcParseLinkStatusCounters(fcChip);	// load into 6 s/w accumulators
+
+
+				// LINK DOWN
+
+				if (fcChip->Registers.FMstatus.value & 0x100L)	// Link DOWN bit
+				{
 
-  	if( fcChip->ERQ->producerIndex != fcChip->ERQ->consumerIndex)
-	{
-//	  printk("#ERQ PI != CI#");
-          CpqTsFreezeTachlite( fcChip, 1); // freeze ERQ only	  
-	  fcChip->ERQ->producerIndex = fcChip->ERQ->consumerIndex = 0;
- 	  writel( fcChip->ERQ->base, 
-	    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
-          // re-writing base forces ERQ PI to equal CI
-  
-	}
-		
-	// link down transition occurred -- port_ids can change
-        // on next LinkUp, so we must invalidate current logins
-        // (and any I/O in progress) until PDISC or PLOGI/PRLI
-        // completes
-        {
-          pLoggedInPort = &fcChip->fcPorts; 
-          while( pLoggedInPort ) // for all ports which are expecting
-                                 // PDISC after the next LIP, set the
-                                 // logoutTimer
-          {
-
-	    if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?
-            {
-              pLoggedInPort->LOGO_timer = 3;  // we want 2 seconds
-                                              // but Timer granularity
-                                              // is 1 second
-            }
-                                // suspend any I/O in progress until
-                                // PDISC received...
-            pLoggedInPort->prli = FALSE;   // block FCP-SCSI commands
-	    
-            pLoggedInPort = pLoggedInPort->pNextPort;
-          }  // ... all Previously known ports checked
-        }
-        
-	// since any hot plugging device may NOT support LILP frames
-	// (such as early Tachyon chips), clear this flag indicating
-	// we shouldn't use (our copy of) a LILP map.
-	// If we receive an LILP frame, we'll set it again.
-	fcChip->Options.LILPin = 0; // our LILPmap is invalid
-        cpqfcHBAdata->PortDiscDone = 0; // must re-validate FC ports!
-
-          // also, we want to invalidate (i.e. INITIATOR_ABORT) any
-          // open Login exchanges, in case the LinkDown happened in the
-          // middle of logins.  It's possible that some ports already
-          // ACCepted login commands which we have not processed before
-          // another LinkDown occurred.  Any accepted Login exhanges are
-          // invalidated by LinkDown, even before they are acknowledged.
-          // It's also possible for a port to have a Queued Reply or Request
-          // for login which was interrupted by LinkDown; it may come later,
-          // but it will be unacceptable to us.
-
-          // we must scan the entire exchange space, find every Login type
-          // originated by us, and abort it. This is NOT an abort due to
-          // timeout, so we don't actually send abort to the other port -
-          // we just complete it to free up the fcExchange slot.
-
-        for( i=TACH_SEST_LEN; i< TACH_MAX_XID; i++)
-        {                     // looking for Extended Link Serv.Exchanges
-          if( Exchanges->fcExchange[i].type == ELS_PDISC ||
-              Exchanges->fcExchange[i].type == ELS_PLOGI ||
-              Exchanges->fcExchange[i].type == ELS_PRLI ) 
-          {
-              // ABORT the exchange!
 #ifdef IMQ_DEBUG
-            printk("Originator ABORT x_id %Xh, type %Xh, port_id %Xh on LDn\n",
-              i, Exchanges->fcExchange[i].type,
-            Exchanges->fcExchange[i].fchs.d_id);
+					printk("LinkDn\n");
 #endif
+					printk(" #LDn# ");
 
-            Exchanges->fcExchange[i].status |= INITIATOR_ABORT;
-            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, i); // abort on LDn
-          }
-        }
-
-      }
-
-             // ################   LINK UP   ##################
-      if( fcChip->Registers.FMstatus.value & 0x200L ) // Link Up bit
-      {                                 // AL_PA could have changed
-
-          // We need the following code, duplicated from LinkDn condition,
-          // because it's possible for the Tachyon to re-initialize (hard
-          // reset) without ever getting a LinkDn indication.
-        pLoggedInPort = &fcChip->fcPorts; 
-        while( pLoggedInPort )   // for all ports which are expecting
-                                 // PDISC after the next LIP, set the
-                                 // logoutTimer
-        {
-          if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?
-          {
-            pLoggedInPort->LOGO_timer = 3;  // we want 2 seconds
-                                              // but Timer granularity
-                                              // is 1 second
-             
-                                  // suspend any I/O in progress until
-                                  // PDISC received...
-
-          }
-          pLoggedInPort = pLoggedInPort->pNextPort;
-        }  // ... all Previously known ports checked
- 
-          // CpqTs acquired AL_PA in register AL_PA (ACQ_ALPA)
-        fcChip->Registers.rcv_al_pa.value = 
-          readl(fcChip->Registers.rcv_al_pa.address);
- 
-	// Now, if our acquired address is DIFFERENT from our
-        // previous one, we are not allow to do PDISC - we
-        // must go back to PLOGI, which will terminate I/O in
-        // progress for ALL logged in FC devices...
-	// (This is highly unlikely).
+					fcChip->fcStats.linkDown++;
 
-	if( (fcChip->Registers.my_al_pa & 0xFF) != 
-	    ((fcChip->Registers.rcv_al_pa.value >> 16) &0xFF) )
-	{
+					SetTachTOV(cpqfcHBAdata);	// must set according to SANMark
 
-//	  printk(" #our HBA port_id changed!# "); // FC port_id changed!!	
+					// Check the ERQ - force it to be "empty" to prevent Tach
+					// from sending out frames before we do logins.
 
-	  pLoggedInPort = &fcChip->fcPorts; 
-          while( pLoggedInPort ) // for all ports which are expecting
-                                 // PDISC after the next LIP, set the
-                                 // logoutTimer
-          {
-	    pLoggedInPort->pdisc  = FALSE;
-            pLoggedInPort->prli = FALSE;
-            pLoggedInPort = pLoggedInPort->pNextPort;
-          }  // ... all Previously known ports checked
-
-	  // when the port_id changes, we must terminate
-	  // all open exchanges.
-          cpqfcTSTerminateExchange( cpqfcHBAdata, NULL, PORTID_CHANGED);
-
-	}
-	               
-	// Replace the entire 24-bit port_id.  We only know the
-	// lower 8 bits (alpa) from Tachyon; if a FLOGI is done,
-	// we'll get the upper 16-bits from the FLOGI ACC frame.
-	// If someone plugs into Fabric switch, we'll do FLOGI and
-	// get full 24-bit port_id; someone could then remove and
-	// hot-plug us into a dumb hub.  If we send a 24-bit PLOGI
-	// to a "private" loop device, it might blow up.
-	// Consequently, we force the upper 16-bits of port_id to
-	// be re-set on every LinkUp transition
-        fcChip->Registers.my_al_pa =
-          (fcChip->Registers.rcv_al_pa.value >> 16) & 0xFF;
-
-              
-              // copy frame manager status to unused ULONG slot
-        fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =
-          fcChip->Registers.my_al_pa; // (for debugging)
-
-              // for TachLite, we need to write the acquired al_pa
-              // back into the FMconfig register, because after
-              // first initialization, the AQ (prev. acq.) bit gets
-              // set, causing TL FM to use the AL_PA field in FMconfig.
-              // (In Tachyon, FM writes the acquired AL_PA for us.)
-        ulBuff = readl( fcChip->Registers.FMconfig.address);
-        ulBuff &= 0x00ffffffL;  // mask out current al_pa
-        ulBuff |= ( fcChip->Registers.my_al_pa << 24 ); // or in acq. al_pa
-        fcChip->Registers.FMconfig.value = ulBuff; // copy it back
-        writel( fcChip->Registers.FMconfig.value,  // put in TachLite
-          fcChip->Registers.FMconfig.address);
-            
 
+					if (fcChip->ERQ->producerIndex != fcChip->ERQ->consumerIndex) {
+//        printk("#ERQ PI != CI#");
+						CpqTsFreezeTachlite(fcChip, 1);	// freeze ERQ only     
+						fcChip->ERQ->producerIndex = fcChip->ERQ->consumerIndex = 0;
+						writel(fcChip->ERQ->base, (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
+						// re-writing base forces ERQ PI to equal CI
+
+					}
+					// link down transition occurred -- port_ids can change
+					// on next LinkUp, so we must invalidate current logins
+					// (and any I/O in progress) until PDISC or PLOGI/PRLI
+					// completes
+					{
+						pLoggedInPort = &fcChip->fcPorts;
+						while (pLoggedInPort)	// for all ports which are expecting
+							// PDISC after the next LIP, set the
+							// logoutTimer
+						{
+
+							if (pLoggedInPort->pdisc)	// expecting PDISC within 2 sec?
+							{
+								pLoggedInPort->LOGO_timer = 3;	// we want 2 seconds
+								// but Timer granularity
+								// is 1 second
+							}
+							// suspend any I/O in progress until
+							// PDISC received...
+							pLoggedInPort->prli = FALSE;	// block FCP-SCSI commands
+
+							pLoggedInPort = pLoggedInPort->pNextPort;
+						}	// ... all Previously known ports checked
+					}
+
+					// since any hot plugging device may NOT support LILP frames
+					// (such as early Tachyon chips), clear this flag indicating
+					// we shouldn't use (our copy of) a LILP map.
+					// If we receive an LILP frame, we'll set it again.
+					fcChip->Options.LILPin = 0;	// our LILPmap is invalid
+					cpqfcHBAdata->PortDiscDone = 0;	// must re-validate FC ports!
+
+					// also, we want to invalidate (i.e. INITIATOR_ABORT) any
+					// open Login exchanges, in case the LinkDown happened in the
+					// middle of logins.  It's possible that some ports already
+					// ACCepted login commands which we have not processed before
+					// another LinkDown occurred.  Any accepted Login exhanges are
+					// invalidated by LinkDown, even before they are acknowledged.
+					// It's also possible for a port to have a Queued Reply or Request
+					// for login which was interrupted by LinkDown; it may come later,
+					// but it will be unacceptable to us.
+
+					// we must scan the entire exchange space, find every Login type
+					// originated by us, and abort it. This is NOT an abort due to
+					// timeout, so we don't actually send abort to the other port -
+					// we just complete it to free up the fcExchange slot.
+
+					for (i = TACH_SEST_LEN; i < TACH_MAX_XID; i++) {	// looking for Extended Link Serv.Exchanges
+						if (Exchanges->fcExchange[i].type == ELS_PDISC || Exchanges->fcExchange[i].type == ELS_PLOGI || Exchanges->fcExchange[i].type == ELS_PRLI) {
+							// ABORT the exchange!
 #ifdef IMQ_DEBUG
-        printk("#LUp %Xh, FMstat 0x%08X#", 
-		fcChip->Registers.my_al_pa, fcChip->Registers.FMstatus.value);
+							printk("Originator ABORT x_id %Xh, type %Xh, port_id %Xh on LDn\n", i, Exchanges->fcExchange[i].type, Exchanges->fcExchange[i].fchs.d_id);
 #endif
 
-              // also set the WRITE-ONLY My_ID Register (for Fabric
-              // initialization)
-        writel( fcChip->Registers.my_al_pa,
-          fcChip->Registers.ReMapMemBase +TL_MEM_TACH_My_ID);
-          
-
-        fcChip->fcStats.linkUp++;
-
-                                     // reset TL statistics counters
-                                     // (we ignore these error counters
-                                     // while link is down)
-        ulBuff =                     // just reset TL's counter
-                 readl( fcChip->Registers.FMLinkStatus1.address);
-          
-        ulBuff =                     // just reset TL's counter
-                 readl( fcChip->Registers.FMLinkStatus2.address);
-
-          // for initiator, need to start verifying ports (e.g. PDISC)
+							Exchanges->fcExchange[i].status |= INITIATOR_ABORT;
+							cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, i);	// abort on LDn
+						}
+					}
+
+				}
+				// ################   LINK UP   ##################
+				if (fcChip->Registers.FMstatus.value & 0x200L)	// Link Up bit
+				{	// AL_PA could have changed
+
+					// We need the following code, duplicated from LinkDn condition,
+					// because it's possible for the Tachyon to re-initialize (hard
+					// reset) without ever getting a LinkDn indication.
+					pLoggedInPort = &fcChip->fcPorts;
+					while (pLoggedInPort)	// for all ports which are expecting
+						// PDISC after the next LIP, set the
+						// logoutTimer
+					{
+						if (pLoggedInPort->pdisc)	// expecting PDISC within 2 sec?
+						{
+							pLoggedInPort->LOGO_timer = 3;	// we want 2 seconds
+							// but Timer granularity
+							// is 1 second
+
+							// suspend any I/O in progress until
+							// PDISC received...
+
+						}
+						pLoggedInPort = pLoggedInPort->pNextPort;
+					}	// ... all Previously known ports checked
+
+					// CpqTs acquired AL_PA in register AL_PA (ACQ_ALPA)
+					fcChip->Registers.rcv_al_pa.value = readl(fcChip->Registers.rcv_al_pa.address);
+
+					// Now, if our acquired address is DIFFERENT from our
+					// previous one, we are not allow to do PDISC - we
+					// must go back to PLOGI, which will terminate I/O in
+					// progress for ALL logged in FC devices...
+					// (This is highly unlikely).
+
+					if ((fcChip->Registers.my_al_pa & 0xFF) != ((fcChip->Registers.rcv_al_pa.value >> 16) & 0xFF)) {
+
+//        printk(" #our HBA port_id changed!# "); // FC port_id changed!!       
+
+						pLoggedInPort = &fcChip->fcPorts;
+						while (pLoggedInPort)	// for all ports which are expecting
+							// PDISC after the next LIP, set the
+							// logoutTimer
+						{
+							pLoggedInPort->pdisc = FALSE;
+							pLoggedInPort->prli = FALSE;
+							pLoggedInPort = pLoggedInPort->pNextPort;
+						}	// ... all Previously known ports checked
+
+						// when the port_id changes, we must terminate
+						// all open exchanges.
+						cpqfcTSTerminateExchange(cpqfcHBAdata, NULL, PORTID_CHANGED);
+
+					}
+					// Replace the entire 24-bit port_id.  We only know the
+					// lower 8 bits (alpa) from Tachyon; if a FLOGI is done,
+					// we'll get the upper 16-bits from the FLOGI ACC frame.
+					// If someone plugs into Fabric switch, we'll do FLOGI and
+					// get full 24-bit port_id; someone could then remove and
+					// hot-plug us into a dumb hub.  If we send a 24-bit PLOGI
+					// to a "private" loop device, it might blow up.
+					// Consequently, we force the upper 16-bits of port_id to
+					// be re-set on every LinkUp transition
+					fcChip->Registers.my_al_pa = (fcChip->Registers.rcv_al_pa.value >> 16) & 0xFF;
+
+
+					// copy frame manager status to unused u32 slot
+					fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] = fcChip->Registers.my_al_pa;	// (for debugging)
+
+					// for TachLite, we need to write the acquired al_pa
+					// back into the FMconfig register, because after
+					// first initialization, the AQ (prev. acq.) bit gets
+					// set, causing TL FM to use the AL_PA field in FMconfig.
+					// (In Tachyon, FM writes the acquired AL_PA for us.)
+					ulBuff = readl(fcChip->Registers.FMconfig.address);
+					ulBuff &= 0x00ffffffL;	// mask out current al_pa
+					ulBuff |= (fcChip->Registers.my_al_pa << 24);	// or in acq. al_pa
+					fcChip->Registers.FMconfig.value = ulBuff;	// copy it back
+					writel(fcChip->Registers.FMconfig.value,	// put in TachLite
+					       fcChip->Registers.FMconfig.address);
 
 
+#ifdef IMQ_DEBUG
+					printk("#LUp %Xh, FMstat 0x%08X#", fcChip->Registers.my_al_pa, fcChip->Registers.FMstatus.value);
+#endif
 
-         
-      
-      
-	CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachlite, if Link OK
-	
-	// Tachyon creates an interesting problem for us on LILP frames.
-	// Instead of writing the incoming LILP frame into the SFQ before
-	// indicating LINK UP (the actual order of events), Tachyon tells
-	// us LINK UP, and later us the LILP.  So we delay, then examine the
-	// IMQ for an Inbound CM (x04); if found, we can set
-	// LINKACTIVE after processing the LILP.  Otherwise, just proceed.
-	// Since Tachyon imposes this time delay (and doesn't tell us
-	// what it is), we have to impose a delay before "Peeking" the IMQ
-	// for Tach hardware (DMA) delivery.
-	// Processing LILP is required by SANMark
-	udelay( 1000);  // microsec delay waiting for LILP (if it comes)
-        if( PeekIMQEntry( fcChip, ELS_LILP_FRAME) )
-	{  // found SFQ LILP, which will post LINKACTIVE	  
-//	  printk("skipping LINKACTIVE post\n");
+					// also set the WRITE-ONLY My_ID Register (for Fabric
+					// initialization)
+					writel(fcChip->Registers.my_al_pa, fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
+
+
+					fcChip->fcStats.linkUp++;
+
+					// reset TL statistics counters
+					// (we ignore these error counters
+					// while link is down)
+					ulBuff =	// just reset TL's counter
+					    readl(fcChip->Registers.FMLinkStatus1.address);
+
+					ulBuff =	// just reset TL's counter
+					    readl(fcChip->Registers.FMLinkStatus2.address);
+
+					// for initiator, need to start verifying ports (e.g. PDISC)
 
-	}
-	else
-          cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, ulFibreFrame);  
-      }
 
 
 
-      // ******* Set Fabric Login indication ********
-      if( fcChip->Registers.FMstatus.value & 0x2000 )
-      {
-	printk(" #Fabric# ");
-        fcChip->Options.fabric = 1;
-      }
-      else
-        fcChip->Options.fabric = 0;
-
-      
-      
-                             // ******* LIP(F8,x) or BAD AL_PA? ********
-      if( fcChip->Registers.FMstatus.value & 0x30000L )
-      {
-                        // copy the error AL_PAs
-        fcChip->Registers.rcv_al_pa.value = 
-          readl(fcChip->Registers.rcv_al_pa.address);
-            
-                        // Bad AL_PA?
-        if( fcChip->Registers.FMstatus.value & 0x10000L )
-        {
-          PFC_LOGGEDIN_PORT pLoggedInPort;
-        
-                       // copy "BAD" al_pa field
-          fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =
-              (fcChip->Registers.rcv_al_pa.value & 0xff00L) >> 8;
-
-	  pLoggedInPort = fcFindLoggedInPort( fcChip,
-            NULL,     // DON'T search Scsi Nexus
-            fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1], // port id
-            NULL,     // DON'T search linked list for FC WWN
-            NULL);    // DON'T care about end of list
- 
-	  if( pLoggedInPort )
-	  {
-            // Just in case we got this BAD_ALPA because a device
-	    // quietly disappeared (can happen on non-managed hubs such 
-	    // as the Vixel Rapport 1000),
-	    // do an Implicit Logout.  We never expect this on a Logged
-	    // in port (but do expect it on port discovery).
-	    // (As a reasonable alternative, this could be changed to 
-	    // simply start the implicit logout timer, giving the device
-	    // several seconds to "come back".)
-	    // 
-	    printk(" #BAD alpa %Xh# ",
-		   fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1]);
-            cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
-	  }
-        }
-                        // LIP(f8,x)?
-        if( fcChip->Registers.FMstatus.value & 0x20000L )
-        {
-                        // for debugging, copy al_pa field
-          fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] =
-              (fcChip->Registers.rcv_al_pa.value & 0xffL);
-                        // get the other port's al_pa
-                        // (one that sent LIP(F8,?) )
-        }
-      }
-
-                             // Elastic store err
-      if( fcChip->Registers.FMstatus.value & 0x400L )
-      {
-            // don't count e-s if loop is down!
-        if( !(USHORT)(fcChip->Registers.FMstatus.value & 0x80) )
-          fcChip->fcStats.e_stores++;
-          
-      }
-    }
-    break;
-
 
-    case INBOUND_FCP_XCHG_COMPLETION:  // 0x0C
 
-    // Remarks:
-    // On Tachlite TL/TS, we get this message when the data phase
-    // of a SEST inbound transfer is complete.  For example, if a WRITE command
-    // was received with OX_ID 0, we might respond with XFER_RDY with
-    // RX_ID 8001.  This would start the SEST controlled data phases.  When
-    // all data frames are received, we get this inbound completion. This means
-    // we should send a status frame to complete the status phase of the 
-    // FCP-SCSI exchange, using the same OX_ID,RX_ID that we used for data
-    // frames.
-    // See Outbound CM discussion of x_IDs
-    // Psuedo Code
-    //   Get SEST index (x_ID)
-    //     x_ID out of range, return (err condition)
-    //   set status bits from 2nd dword
-    //   free transactionID & SEST entry
-    //   call fcComplete with transactionID & status
-
-      ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0];
-      x_ID = ulBuff & 0x7fffL;  // lower 14 bits SEST_Index/Trans_ID
-                                // (mask out MSB "direction" bit)
-                                // Range check CM OX/RX_ID value...
-      if( x_ID < TACH_SEST_LEN )  // don't go beyond SEST array space
-      {
+					CpqTsUnFreezeTachlite(fcChip, 2);	// unfreeze Tachlite, if Link OK
+
+					// Tachyon creates an interesting problem for us on LILP frames.
+					// Instead of writing the incoming LILP frame into the SFQ before
+					// indicating LINK UP (the actual order of events), Tachyon tells
+					// us LINK UP, and later us the LILP.  So we delay, then examine the
+					// IMQ for an Inbound CM (x04); if found, we can set
+					// LINKACTIVE after processing the LILP.  Otherwise, just proceed.
+					// Since Tachyon imposes this time delay (and doesn't tell us
+					// what it is), we have to impose a delay before "Peeking" the IMQ
+					// for Tach hardware (DMA) delivery.
+					// Processing LILP is required by SANMark
+					udelay(1000);	// microsec delay waiting for LILP (if it comes)
+					if (PeekIMQEntry(fcChip, ELS_LILP_FRAME)) {	// found SFQ LILP, which will post LINKACTIVE          
+//        printk("skipping LINKACTIVE post\n");
+
+					} else
+						cpqfcTSPutLinkQue(cpqfcHBAdata, LINKACTIVE, ulFibreFrame);
+				}
+
+
+				// ******* Set Fabric Login indication ********
+				if (fcChip->Registers.FMstatus.value & 0x2000) {
+					printk(" #Fabric# ");
+					fcChip->Options.fabric = 1;
+				} else
+					fcChip->Options.fabric = 0;
+
+
+
+				// ******* LIP(F8,x) or BAD AL_PA? ********
+				if (fcChip->Registers.FMstatus.value & 0x30000L) {
+					// copy the error AL_PAs
+					fcChip->Registers.rcv_al_pa.value = readl(fcChip->Registers.rcv_al_pa.address);
+
+					// Bad AL_PA?
+					if (fcChip->Registers.FMstatus.value & 0x10000L) {
+						PFC_LOGGEDIN_PORT pLoggedInPort;
+
+						// copy "BAD" al_pa field
+						fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] = (fcChip->Registers.rcv_al_pa.value & 0xff00L) >> 8;
+
+						pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// DON'T search Scsi Nexus
+										   fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1],	// port id
+										   NULL,	// DON'T search linked list for FC WWN
+										   NULL);	// DON'T care about end of list
+
+						if (pLoggedInPort) {
+							// Just in case we got this BAD_ALPA because a device
+							// quietly disappeared (can happen on non-managed hubs such 
+							// as the Vixel Rapport 1000),
+							// do an Implicit Logout.  We never expect this on a Logged
+							// in port (but do expect it on port discovery).
+							// (As a reasonable alternative, this could be changed to 
+							// simply start the implicit logout timer, giving the device
+							// several seconds to "come back".)
+							// 
+							printk(" #BAD alpa %Xh# ", fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1]);
+							cpqfcTSImplicitLogout(cpqfcHBAdata, pLoggedInPort);
+						}
+					}
+					// LIP(f8,x)?
+					if (fcChip->Registers.FMstatus.value & 0x20000L) {
+						// for debugging, copy al_pa field
+						fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] = (fcChip->Registers.rcv_al_pa.value & 0xffL);
+						// get the other port's al_pa
+						// (one that sent LIP(F8,?) )
+					}
+				}
+				// Elastic store err
+				if (fcChip->Registers.FMstatus.value & 0x400L) {
+					// don't count e-s if loop is down!
+					if (!(u16) (fcChip->Registers.FMstatus.value & 0x80))
+						fcChip->fcStats.e_stores++;
+
+				}
+			}
+			break;
+
+
+		case INBOUND_FCP_XCHG_COMPLETION:	// 0x0C
+
+			// Remarks:
+			// On Tachlite TL/TS, we get this message when the data phase
+			// of a SEST inbound transfer is complete.  For example, if a WRITE command
+			// was received with OX_ID 0, we might respond with XFER_RDY with
+			// RX_ID 8001.  This would start the SEST controlled data phases.  When
+			// all data frames are received, we get this inbound completion. This means
+			// we should send a status frame to complete the status phase of the 
+			// FCP-SCSI exchange, using the same OX_ID,RX_ID that we used for data
+			// frames.
+			// See Outbound CM discussion of x_IDs
+			// Psuedo Code
+			//   Get SEST index (x_ID)
+			//     x_ID out of range, return (err condition)
+			//   set status bits from 2nd dword
+			//   free transactionID & SEST entry
+			//   call fcComplete with transactionID & status
+
+			ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0];
+			x_ID = ulBuff & 0x7fffL;	// lower 14 bits SEST_Index/Trans_ID
+			// (mask out MSB "direction" bit)
+			// Range check CM OX/RX_ID value...
+			if (x_ID < TACH_SEST_LEN)	// don't go beyond SEST array space
+			{
 
 //#define FCP_COMPLETION_DBG 1
 #ifdef FCP_COMPLETION_DBG
-        printk(" FCP_CM x_ID %Xh, status %Xh, Cmnd %p\n", 
-          x_ID, ulBuff, Exchanges->fcExchange[x_ID].Cmnd);
+				printk(" FCP_CM x_ID %Xh, status %Xh, Cmnd %p\n", x_ID, ulBuff, Exchanges->fcExchange[x_ID].Cmnd);
 #endif
-        if( ulBuff & 0x08000000L ) // RPC -Response Phase Complete - or -
-                                   // time to send response frame?
-          RPCset = 1;             // (SEST transaction)
-        else
-          RPCset = 0;
-                // set the status for this Inbound SCSI transaction's ID
-        dwStatus = 0L;
-        if( ulBuff & 0x70000000L ) // any errs?
-        {
-          
-          if( ulBuff & 0x40000000L )
-            dwStatus |= LINKFAIL_RX;
-          
-	  if( ulBuff & 0x20000000L )
-            dwStatus |= COUNT_ERROR;
-          
-          if( ulBuff & 0x10000000L )
-            dwStatus |= OVERFLOW;
-        }
-      
-	
-	  // FCP transaction done - copy status
-        Exchanges->fcExchange[ x_ID ].status = dwStatus;
-
-
-        // Did the exchange get an FCP-RSP response frame?
-        // (Note the little endian/big endian FC payload difference)
-
-        if( RPCset )             // SEST transaction Response frame rec'd
-        {
-    	  // complete the command in our driver...
-          cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev,fcChip, x_ID);
-
-        }  // end "RPCset"
-	
-        else  // ("target" logic)
-        {
-            // Tachlite says all data frames have been received - now it's time
-            // to analyze data transfer (successful?), then send a response 
-            // frame for this exchange
-
-          ulFibreFrame[0] = x_ID; // copy for later reference
-
-          // if this was a TWE, we have to send satus response
-          if( Exchanges->fcExchange[ x_ID].type == SCSI_TWE )
-	  {
+				if (ulBuff & 0x08000000L)	// RPC -Response Phase Complete - or -
+					// time to send response frame?
+					RPCset = 1;	// (SEST transaction)
+				else
+					RPCset = 0;
+				// set the status for this Inbound SCSI transaction's ID
+				dwStatus = 0L;
+				if (ulBuff & 0x70000000L)	// any errs?
+				{
+
+					if (ulBuff & 0x40000000L)
+						dwStatus |= LINKFAIL_RX;
+
+					if (ulBuff & 0x20000000L)
+						dwStatus |= COUNT_ERROR;
+
+					if (ulBuff & 0x10000000L)
+						dwStatus |= OVERFLOW;
+				}
+
+				// FCP transaction done - copy status
+				Exchanges->fcExchange[x_ID].status = dwStatus;
+
+
+				// Did the exchange get an FCP-RSP response frame?
+				// (Note the little endian/big endian FC payload difference)
+
+				if (RPCset)	// SEST transaction Response frame rec'd
+				{
+					// complete the command in our driver...
+					cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, x_ID);
+
+				}	// end "RPCset"
+
+				else	// ("target" logic)
+				{
+					// Tachlite says all data frames have been received - now it's time
+					// to analyze data transfer (successful?), then send a response 
+					// frame for this exchange
+
+					ulFibreFrame[0] = x_ID;	// copy for later reference
+
+					// if this was a TWE, we have to send satus response
+					if (Exchanges->fcExchange[x_ID].type == SCSI_TWE) {
 //            fcPutScsiQue( cpqfcHBAdata, 
 //                NEED_FCP_RSP, ulFibreFrame);  // (ulFibreFrame not used here)
-	  }
-        }
-      }
-      else  // ERROR CONDITION!  bogus x_ID in completion message
-      {
-        printk("IN FCP_XCHG: bad x_ID: %Xh\n", x_ID);
-      }
+					}
+				}
+			} else	// ERROR CONDITION!  bogus x_ID in completion message
+			{
+				printk("IN FCP_XCHG: bad x_ID: %Xh\n", x_ID);
+			}
 
-    break;
+			break;
 
 
 
 
-    case INBOUND_SCSI_DATA_COMMAND:
-    case BAD_SCSI_FRAME:
-    case INB_SCSI_STATUS_COMPLETION:
-    case BUFFER_PROCESSED_COMPLETION:
-    break;
-    }
+		case INBOUND_SCSI_DATA_COMMAND:
+		case BAD_SCSI_FRAME:
+		case INB_SCSI_STATUS_COMPLETION:
+		case BUFFER_PROCESSED_COMPLETION:
+			break;
+		}
+
+		// Tachyon is producing;
+		// we are consuming
+		fcChip->IMQ->consumerIndex++;	// increment OUR consumerIndex
+		if (fcChip->IMQ->consumerIndex >= IMQ_LEN)	// check for rollover
+			fcChip->IMQ->consumerIndex = 0L;	// reset it
+
+
+		if (fcChip->IMQ->producerIndex == fcChip->IMQ->consumerIndex) {	// all Messages are processed -
+			iStatus = 0;	// no more messages to process
+
+		} else
+			iStatus = 1;	// more messages to process
+
+		// update TachLite's ConsumerIndex... (clears INTA_L)
+		// NOTE: according to TL/TS UG, the 
+		// "host must return completion messages in sequential order".
+		// Does this mean one at a time, in the order received?  We
+		// presume so.
+
+		writel(fcChip->IMQ->consumerIndex, (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
 
-					   // Tachyon is producing;
-					   // we are consuming
-    fcChip->IMQ->consumerIndex++;             // increment OUR consumerIndex
-    if( fcChip->IMQ->consumerIndex >= IMQ_LEN)// check for rollover
-      fcChip->IMQ->consumerIndex = 0L;        // reset it
-
-
-    if( fcChip->IMQ->producerIndex == fcChip->IMQ->consumerIndex )
-    {                           // all Messages are processed -
-      iStatus = 0;              // no more messages to process
-
-    }
-    else
-      iStatus = 1;              // more messages to process
-
-    // update TachLite's ConsumerIndex... (clears INTA_L)
-    // NOTE: according to TL/TS UG, the 
-    // "host must return completion messages in sequential order".
-    // Does this mean one at a time, in the order received?  We
-    // presume so.
-
-    writel( fcChip->IMQ->consumerIndex,
-      (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
-		    
 #if IMQ_DEBUG
-    printk("Process IMQ: writing consumer ndx %d\n ", 
-      fcChip->IMQ->consumerIndex);
-    printk("PI %X, CI %X\n", 
-    fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex );
+		printk("Process IMQ: writing consumer ndx %d\n ", fcChip->IMQ->consumerIndex);
+		printk("PI %X, CI %X\n", fcChip->IMQ->producerIndex, fcChip->IMQ->consumerIndex);
 #endif
-  
 
 
-  }
-  else
-  {
-   // hmmm... why did we get interrupted/called with no message?
-    iStatus = -1;               // nothing to process
+
+	} else {
+		// hmmm... why did we get interrupted/called with no message?
+		iStatus = -1;	// nothing to process
 #if IMQ_DEBUG
-    printk("Process IMQ: no message PI %Xh  CI %Xh", 
-      fcChip->IMQ->producerIndex,
-      fcChip->IMQ->consumerIndex);
+		printk("Process IMQ: no message PI %Xh  CI %Xh", fcChip->IMQ->producerIndex, fcChip->IMQ->consumerIndex);
 #endif
-  }
+	}
 
-  LEAVE("ProcessIMQEntry");
-  
-  return iStatus;
+	LEAVE("ProcessIMQEntry");
+
+	return iStatus;
 }
 
 
@@ -1648,31 +1496,29 @@
 //  -1 on fatal error
 //   0 on success
 
-int CpqTsInitializeTachLite( void *pHBA, int opcode1, int opcode2)
+int CpqTsInitializeTachLite(void *pHBA, int opcode1, int opcode2)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  ULONG ulBuff;
-  UCHAR bBuff;
-  int iStatus=-1;  // assume failure
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) pHBA;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	u32 ulBuff;
+	u8 bBuff;
+	int iStatus = -1;	// assume failure
 
-  ENTER("InitializeTachLite");
+	ENTER("InitializeTachLite");
 
-  // verify board's base address (sanity check)
+	// verify board's base address (sanity check)
 
-  if( !fcChip->Registers.ReMapMemBase)                // NULL address for card?
-    return -1;                         // FATAL error!
+	if (!fcChip->Registers.ReMapMemBase)	// NULL address for card?
+		return -1;	// FATAL error!
 
 
 
-  switch( opcode1 )
-  {
-    case 1:       // restore hardware to power-on (hard) restart
+	switch (opcode1) {
+	case 1:		// restore hardware to power-on (hard) restart
 
 
-      iStatus = fcChip->ResetTachyon( 
-		  cpqfcHBAdata, opcode2); // laser off, reset hardware
-				      // de-allocate aligned buffers
+		iStatus = fcChip->ResetTachyon(cpqfcHBAdata, opcode2);	// laser off, reset hardware
+		// de-allocate aligned buffers
 
 
 /* TBD      // reset FC link Q (producer and consumer = 0)
@@ -1680,17 +1526,17 @@
 
 */
 
-      if( iStatus )
-        break;
+		if (iStatus)
+			break;
 
-    case 2:       // Config PCI/Tachyon registers
-      // NOTE: For Tach TL/TS, bit 31 must be set to 1.  For TS chips, a read
-      // of bit 31 indicates state of M66EN signal; if 1, chip may run at 
-      // 33-66MHz  (see TL/TS UG, pg 159)
+	case 2:		// Config PCI/Tachyon registers
+		// NOTE: For Tach TL/TS, bit 31 must be set to 1.  For TS chips, a read
+		// of bit 31 indicates state of M66EN signal; if 1, chip may run at 
+		// 33-66MHz  (see TL/TS UG, pg 159)
 
-      ulBuff = 0x80000000;  // TachLite Configuration Register
+		ulBuff = 0x80000000;	// TachLite Configuration Register
 
-      writel( ulBuff, fcChip->Registers.TYconfig.address);
+		writel(ulBuff, fcChip->Registers.TYconfig.address);
 //      ulBuff = 0x0147L;  // CpqTs PCI CFGCMD register
 //      WritePCIConfiguration( fcChip->Backplane.bus,
 //                           fcChip->Backplane.slot, TLCFGCMD, ulBuff, 4);
@@ -1698,80 +1544,70 @@
 //      ReadPCIConfiguration( fcChip->Backplane.bus,
 //                           fcChip->Backplane.slot, TLCFGCMD, &ulBuff, 4);
 
-      // read back for reference...
-      fcChip->Registers.TYconfig.value = 
-         readl( fcChip->Registers.TYconfig.address );
-
-      // what is the PCI bus width?
-      pci_read_config_byte( cpqfcHBAdata->PciDev,
-                                0x43, // PCIMCTR offset
-                                &bBuff);
-      
-      fcChip->Registers.PCIMCTR = bBuff;
-
-      // set string identifying the chip on the circuit board
-
-      fcChip->Registers.TYstatus.value =
-        readl( fcChip->Registers.TYstatus.address);
-      
-      {
+		// read back for reference...
+		fcChip->Registers.TYconfig.value = readl(fcChip->Registers.TYconfig.address);
+
+		// what is the PCI bus width?
+		pci_read_config_byte(cpqfcHBAdata->PciDev, 0x43,	// PCIMCTR offset
+				     &bBuff);
+
+		fcChip->Registers.PCIMCTR = bBuff;
+
+		// set string identifying the chip on the circuit board
+
+		fcChip->Registers.TYstatus.value = readl(fcChip->Registers.TYstatus.address);
+
+		{
 // Now that we are supporting multiple boards, we need to change
 // this logic to check for PCI vendor/device IDs...
 // for now, quick & dirty is simply checking Chip rev
-	
-	ULONG RevId = (fcChip->Registers.TYstatus.value &0x3E0)>>5;
-	UCHAR Minor = (UCHAR)(RevId & 0x3);
-	UCHAR Major = (UCHAR)((RevId & 0x1C) >>2);
-  
-        printk("  HBA Tachyon RevId %d.%d\n", Major, Minor);
-  	if( (Major == 1) && (Minor == 2) )
-        {
-	  sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS12);
-
-	}
-	else if( (Major == 1) && (Minor == 3) )
-        {
-	  sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS13);
-	}
-	else if( (Major == 2) && (Minor == 1) )
-        {
-	  sprintf( cpqfcHBAdata->fcChip.Name, SAGILENT_XL2_21);
-	}
-	else
-	  sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE_UNKNOWN);
-      }
+
+			u32 RevId = (fcChip->Registers.TYstatus.value & 0x3E0) >> 5;
+			u8 Minor = (u8) (RevId & 0x3);
+			u8 Major = (u8) ((RevId & 0x1C) >> 2);
+
+			printk("  HBA Tachyon RevId %d.%d\n", Major, Minor);
+			if ((Major == 1) && (Minor == 2)) {
+				sprintf(cpqfcHBAdata->fcChip.Name, STACHLITE66_TS12);
+
+			} else if ((Major == 1) && (Minor == 3)) {
+				sprintf(cpqfcHBAdata->fcChip.Name, STACHLITE66_TS13);
+			} else if ((Major == 2) && (Minor == 1)) {
+				sprintf(cpqfcHBAdata->fcChip.Name, SAGILENT_XL2_21);
+			} else
+				sprintf(cpqfcHBAdata->fcChip.Name, STACHLITE_UNKNOWN);
+		}
 
 
 
-    case 3:       // allocate mem, set Tachyon Que registers
-      iStatus = CpqTsCreateTachLiteQues( cpqfcHBAdata, opcode2);
+	case 3:		// allocate mem, set Tachyon Que registers
+		iStatus = CpqTsCreateTachLiteQues(cpqfcHBAdata, opcode2);
+
+		if (iStatus)
+			break;
+
+		// now that the Queues exist, Tach can DMA to them, so
+		// we can begin processing INTs
+		// INTEN register - enable INT (TachLite interrupt)
+		writeb(0x1F, fcChip->Registers.ReMapMemBase + IINTEN);
+
+		// Fall through
+	case 4:		// Config Fame Manager, Init Loop Command, laser on
+
+		// L_PORT or loopback
+		// depending on Options
+		iStatus = CpqTsInitializeFrameManager(fcChip, 0);
+		if (iStatus) {
+			// failed to initialize Frame Manager
+			break;
+		}
 
-      if( iStatus )
-        break;
-
-      // now that the Queues exist, Tach can DMA to them, so
-      // we can begin processing INTs
-      // INTEN register - enable INT (TachLite interrupt)
-      writeb( 0x1F, fcChip->Registers.ReMapMemBase + IINTEN);
-
-	// Fall through
-    case 4:       // Config Fame Manager, Init Loop Command, laser on
-
-                 // L_PORT or loopback
-                 // depending on Options
-      iStatus = CpqTsInitializeFrameManager( fcChip,0 );
-      if( iStatus )
-      {
-           // failed to initialize Frame Manager
-	      break;
-      }
-
-    default:
-      break;
-  }
-  LEAVE("InitializeTachLite");
-  
-  return iStatus;
+	default:
+		break;
+	}
+	LEAVE("InitializeTachLite");
+
+	return iStatus;
 }
 
 
@@ -1782,101 +1618,86 @@
 // Order of allocation: see other function
 
 
-int CpqTsDestroyTachLiteQues( void *pHBA, int opcode)
+int CpqTsDestroyTachLiteQues(void *pHBA, int opcode)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  USHORT i, iStatus=0;
-  void* vPtr;  // mem Align manager sets this to the freed address on success
-  unsigned long ulPtr;  // for 64-bit pointer cast (e.g. Alpa machine)
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PSGPAGES j, next;
-
-  ENTER("DestroyTachLiteQues");
-
-  if( fcChip->SEST )
-  {
-                // search out and free Pool for Extended S/G list pages
-
-    for( i=0; i < TACH_SEST_LEN; i++)  // for each exchange
-    {
-      // It's possible that extended S/G pages were allocated, mapped, and
-      // not cleared due to error conditions or O/S driver termination.
-      // Make sure they're all gone.
-      if (Exchanges->fcExchange[i].Cmnd != NULL) 
-      	cpqfc_pci_unmap(cpqfcHBAdata->PciDev, Exchanges->fcExchange[i].Cmnd, 
-			fcChip, i); // undo DMA mappings.
-
-      for (j=fcChip->SEST->sgPages[i] ; j != NULL ; j = next) {
-		next = j->next;
-		kfree(j);
-      }
-      fcChip->SEST->sgPages[i] = NULL;
-    }
-    ulPtr = (unsigned long)fcChip->SEST;
-    vPtr = fcMemManager( cpqfcHBAdata->PciDev, 
-		    &cpqfcHBAdata->dynamic_mem[0],
-		    0,0, (ULONG)ulPtr, NULL ); // 'free' mem
-    fcChip->SEST = 0L;  // null invalid ptr
-    if( !vPtr )
-    {
-      printk("SEST mem not freed\n");
-      iStatus = -1;
-    }
-  }
-
-  if( fcChip->SFQ )
-  {
-
-    ulPtr = (unsigned long)fcChip->SFQ;
-    vPtr = fcMemManager( cpqfcHBAdata->PciDev, 
-		    &cpqfcHBAdata->dynamic_mem[0],
-		    0,0, (ULONG)ulPtr, NULL ); // 'free' mem
-    fcChip->SFQ = 0L;  // null invalid ptr
-    if( !vPtr )
-    {
-      printk("SFQ mem not freed\n");
-      iStatus = -2;
-    }
-  }
-
-
-  if( fcChip->IMQ )
-  {
-      // clear Indexes to show empty Queue
-    fcChip->IMQ->producerIndex = 0;
-    fcChip->IMQ->consumerIndex = 0;
-
-    ulPtr = (unsigned long)fcChip->IMQ;
-    vPtr = fcMemManager( cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0],
-		    0,0, (ULONG)ulPtr, NULL ); // 'free' mem
-    fcChip->IMQ = 0L;  // null invalid ptr
-    if( !vPtr )
-    {
-      printk("IMQ mem not freed\n");
-      iStatus = -3;
-    }
-  }
-
-  if( fcChip->ERQ )         // release memory blocks used by the queues
-  {
-    ulPtr = (unsigned long)fcChip->ERQ;
-    vPtr = fcMemManager( cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0],
-		    0,0, (ULONG)ulPtr, NULL ); // 'free' mem
-    fcChip->ERQ = 0L;  // null invalid ptr
-    if( !vPtr )
-    {
-      printk("ERQ mem not freed\n");
-      iStatus = -4;
-    }
-  }
-    
-  // free up the primary EXCHANGES struct and Link Q
-  cpqfc_free_dma_consistent(cpqfcHBAdata);
-  
-  LEAVE("DestroyTachLiteQues");
-  
-  return iStatus;     // non-zero (failed) if any memory not freed
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) pHBA;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	u16 i, iStatus = 0;
+	void *vPtr;		// mem Align manager sets this to the freed address on success
+	unsigned long ulPtr;	// for 64-bit pointer cast (e.g. Alpa machine)
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	PSGPAGES j, next;
+
+	ENTER("DestroyTachLiteQues");
+
+	if (fcChip->SEST) {
+		// search out and free Pool for Extended S/G list pages
+
+		for (i = 0; i < TACH_SEST_LEN; i++)	// for each exchange
+		{
+			// It's possible that extended S/G pages were allocated, mapped, and
+			// not cleared due to error conditions or O/S driver termination.
+			// Make sure they're all gone.
+			if (Exchanges->fcExchange[i].Cmnd != NULL)
+				cpqfc_pci_unmap(cpqfcHBAdata->PciDev, Exchanges->fcExchange[i].Cmnd, fcChip, i);	// undo DMA mappings.
+
+			for (j = fcChip->SEST->sgPages[i]; j != NULL; j = next) {
+				next = j->next;
+				kfree(j);
+			}
+			fcChip->SEST->sgPages[i] = NULL;
+		}
+		ulPtr = (unsigned long) fcChip->SEST;
+		vPtr = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], 0, 0, (u32) ulPtr, NULL);	// 'free' mem
+		fcChip->SEST = 0L;	// null invalid ptr
+		if (!vPtr) {
+			printk("SEST mem not freed\n");
+			iStatus = -1;
+		}
+	}
+
+	if (fcChip->SFQ) {
+
+		ulPtr = (unsigned long) fcChip->SFQ;
+		vPtr = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], 0, 0, (u32) ulPtr, NULL);	// 'free' mem
+		fcChip->SFQ = 0L;	// null invalid ptr
+		if (!vPtr) {
+			printk("SFQ mem not freed\n");
+			iStatus = -2;
+		}
+	}
+
+
+	if (fcChip->IMQ) {
+		// clear Indexes to show empty Queue
+		fcChip->IMQ->producerIndex = 0;
+		fcChip->IMQ->consumerIndex = 0;
+
+		ulPtr = (unsigned long) fcChip->IMQ;
+		vPtr = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], 0, 0, (u32) ulPtr, NULL);	// 'free' mem
+		fcChip->IMQ = 0L;	// null invalid ptr
+		if (!vPtr) {
+			printk("IMQ mem not freed\n");
+			iStatus = -3;
+		}
+	}
+
+	if (fcChip->ERQ)	// release memory blocks used by the queues
+	{
+		ulPtr = (unsigned long) fcChip->ERQ;
+		vPtr = fcMemManager(cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0], 0, 0, (u32) ulPtr, NULL);	// 'free' mem
+		fcChip->ERQ = 0L;	// null invalid ptr
+		if (!vPtr) {
+			printk("ERQ mem not freed\n");
+			iStatus = -4;
+		}
+	}
+	// free up the primary EXCHANGES struct and Link Q
+	cpqfc_free_dma_consistent(cpqfcHBAdata);
+
+	LEAVE("DestroyTachLiteQues");
+
+	return iStatus;		// non-zero (failed) if any memory not freed
 }
 
 
@@ -1896,44 +1717,35 @@
 //   length from the completion message.  The caller passes a buffer large
 //   enough for the complete message (max 2k).
 
-static void CpqTsGetSFQEntry(
-         PTACHYON fcChip,
-         USHORT producerNdx,
-         ULONG *ulDestPtr,            // contiguous destination buffer
-	 BOOLEAN UpdateChip)
+static void CpqTsGetSFQEntry(PTACHYON fcChip, u16 producerNdx, u32 * ulDestPtr,	// contiguous destination buffer
+			     u8 UpdateChip)
 {
-  ULONG total_bytes=0;
-  ULONG consumerIndex = fcChip->SFQ->consumerIndex;
-  
-				// check passed copy of SFQ producer index -
-				// is a new message waiting for us?
-				// equal indexes means SFS is copied
-
-  while( producerNdx != consumerIndex )
-  {                             // need to process message
-    total_bytes += 64;   // maintain count to prevent writing past buffer
-                   // don't allow copies over Fibre Channel defined length!
-    if( total_bytes <= 2048 )
-    {
-      memcpy( ulDestPtr, 
-              &fcChip->SFQ->QEntry[consumerIndex],
-              64 );  // each SFQ entry is 64 bytes
-      ulDestPtr += 16;   // advance pointer to next 64 byte block
-    }
-		         // Tachyon is producing,
-                         // and we are consuming
-
-    if( ++consumerIndex >= SFQ_LEN)// check for rollover
-      consumerIndex = 0L;        // reset it
-  }
-
-  // if specified, update the Tachlite chip ConsumerIndex...
-  if( UpdateChip )
-  {
-    fcChip->SFQ->consumerIndex = consumerIndex;
-    writel( fcChip->SFQ->consumerIndex,
-      fcChip->Registers.SFQconsumerIndex.address);
-  }
+	u32 total_bytes = 0;
+	u32 consumerIndex = fcChip->SFQ->consumerIndex;
+
+	// check passed copy of SFQ producer index -
+	// is a new message waiting for us?
+	// equal indexes means SFS is copied
+
+	while (producerNdx != consumerIndex) {	// need to process message
+		total_bytes += 64;	// maintain count to prevent writing past buffer
+		// don't allow copies over Fibre Channel defined length!
+		if (total_bytes <= 2048) {
+			memcpy(ulDestPtr, &fcChip->SFQ->QEntry[consumerIndex], 64);	// each SFQ entry is 64 bytes
+			ulDestPtr += 16;	// advance pointer to next 64 byte block
+		}
+		// Tachyon is producing,
+		// and we are consuming
+
+		if (++consumerIndex >= SFQ_LEN)	// check for rollover
+			consumerIndex = 0L;	// reset it
+	}
+
+	// if specified, update the Tachlite chip ConsumerIndex...
+	if (UpdateChip) {
+		fcChip->SFQ->consumerIndex = consumerIndex;
+		writel(fcChip->SFQ->consumerIndex, fcChip->Registers.SFQconsumerIndex.address);
+	}
 }
 
 
@@ -1944,42 +1756,38 @@
 // we routinely RESUME by clearing these bits, but only if the loop is up
 // to avoid ERROR IDLE messages forever.
 
-void CpqTsUnFreezeTachlite( void *pChip, int type )
+void CpqTsUnFreezeTachlite(void *pChip, int type)
 {
-  PTACHYON fcChip = (PTACHYON)pChip;
-  fcChip->Registers.TYcontrol.value = 
-    readl(fcChip->Registers.TYcontrol.address);
-            
-  // (bit 4 of value is GBIC LASER)
-  // if we 'unfreeze' the core machines before the loop is healthy
-  // (i.e. FLT, OS, LS failure bits set in FMstatus)
-  // we can get 'error idle' messages forever.  Verify that
-  // FMstatus (Link Status) is OK before unfreezing.
-
-  if( !(fcChip->Registers.FMstatus.value & 0x07000000L) && // bits clear?
-      !(fcChip->Registers.FMstatus.value & 0x80  ))  // Active LPSM?
-  {
-    fcChip->Registers.TYcontrol.value &=  ~0x300L; // clear FEQ, FFA
-    if( type == 1 )  // unfreeze ERQ only
-    {
+	PTACHYON fcChip = (PTACHYON) pChip;
+	fcChip->Registers.TYcontrol.value = readl(fcChip->Registers.TYcontrol.address);
+
+	// (bit 4 of value is GBIC LASER)
+	// if we 'unfreeze' the core machines before the loop is healthy
+	// (i.e. FLT, OS, LS failure bits set in FMstatus)
+	// we can get 'error idle' messages forever.  Verify that
+	// FMstatus (Link Status) is OK before unfreezing.
+
+	if (!(fcChip->Registers.FMstatus.value & 0x07000000L) &&	// bits clear?
+	    !(fcChip->Registers.FMstatus.value & 0x80))	// Active LPSM?
+	{
+		fcChip->Registers.TYcontrol.value &= ~0x300L;	// clear FEQ, FFA
+		if (type == 1)	// unfreeze ERQ only
+		{
 //      printk("Unfreezing ERQ\n");
-      fcChip->Registers.TYcontrol.value |= 0x10000L; // set REQ
-    }
-    else             // unfreeze both ERQ and FCP-ASSIST (SEST)
-    {
+			fcChip->Registers.TYcontrol.value |= 0x10000L;	// set REQ
+		} else		// unfreeze both ERQ and FCP-ASSIST (SEST)
+		{
 //      printk("Unfreezing ERQ & FCP-ASSIST\n");
 
-                     // set ROF, RIF, REQ - resume Outbound FCP, Inbnd FCP, ERQ
-      fcChip->Registers.TYcontrol.value |= 0x70000L; // set ROF, RIF, REQ
-    }
-
-    writel( fcChip->Registers.TYcontrol.value,
-      fcChip->Registers.TYcontrol.address);
-              
-  }
-          // readback for verify (TachLite still frozen?)
-  fcChip->Registers.TYstatus.value = 
-    readl(fcChip->Registers.TYstatus.address);
+			// set ROF, RIF, REQ - resume Outbound FCP, Inbnd FCP, ERQ
+			fcChip->Registers.TYcontrol.value |= 0x70000L;	// set ROF, RIF, REQ
+		}
+
+		writel(fcChip->Registers.TYcontrol.value, fcChip->Registers.TYcontrol.address);
+
+	}
+	// readback for verify (TachLite still frozen?)
+	fcChip->Registers.TYstatus.value = readl(fcChip->Registers.TYstatus.address);
 }
 
 
@@ -1990,21 +1798,19 @@
 // This freeze function will result in FCP & ERQ FROZEN completion
 // messages (per argument "type").
 
-void CpqTsFreezeTachlite( void *pChip, int type )
+void CpqTsFreezeTachlite(void *pChip, int type)
 {
-  PTACHYON fcChip = (PTACHYON)pChip;
-  fcChip->Registers.TYcontrol.value = 
-    readl(fcChip->Registers.TYcontrol.address);
-    
-                     //set FFA, FEQ - freezes SCSI assist and ERQ
-  if( type == 1)    // freeze ERQ only
-    fcChip->Registers.TYcontrol.value |= 0x100L; // (bit 4 is laser)
-  else              // freeze both FCP assists (SEST) and ERQ
-    fcChip->Registers.TYcontrol.value |= 0x300L; // (bit 4 is laser)
-  
-  writel( fcChip->Registers.TYcontrol.value,
-    fcChip->Registers.TYcontrol.address);
-              
+	PTACHYON fcChip = (PTACHYON) pChip;
+	fcChip->Registers.TYcontrol.value = readl(fcChip->Registers.TYcontrol.address);
+
+	//set FFA, FEQ - freezes SCSI assist and ERQ
+	if (type == 1)		// freeze ERQ only
+		fcChip->Registers.TYcontrol.value |= 0x100L;	// (bit 4 is laser)
+	else			// freeze both FCP assists (SEST) and ERQ
+		fcChip->Registers.TYcontrol.value |= 0x300L;	// (bit 4 is laser)
+
+	writel(fcChip->Registers.TYcontrol.value, fcChip->Registers.TYcontrol.address);
+
 }
 
 
@@ -2018,8 +1824,8 @@
 
 void fcParseLinkStatusCounters(PTACHYON fcChip)
 {
-  UCHAR bBuff;
-  ULONG ulBuff;
+	u8 bBuff;
+	u32 ulBuff;
 
 
 // The BB0 timer usually increments when TL is initialized, resulting
@@ -2028,61 +1834,58 @@
 // Also, reading the register does not clear it, so we have to keep an
 // additional static counter to detect rollover (yuk).
 
-  if( fcChip->fcStats.lastBB0timer == 0L)  // TL was reset? (ignore 1st values)
-  {
-                           // get TL's register counter - the "last" count
-    fcChip->fcStats.lastBB0timer = 
-      fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
-  }
-  else  // subsequent pass - check for rollover
-  {
-                              // "this" count
-    ulBuff = fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
-    if( fcChip->fcStats.lastBB0timer > ulBuff ) // rollover happened
-    {
-                                // counter advanced to max...
-      fcChip->fcStats.BB0_Timer += (0x00FFFFFFL - fcChip->fcStats.lastBB0timer);
-      fcChip->fcStats.BB0_Timer += ulBuff;  // plus some more
-
-
-    }
-    else // no rollover -- more counts or no change
-    {
-      fcChip->fcStats.BB0_Timer +=  (ulBuff - fcChip->fcStats.lastBB0timer);
+	if (fcChip->fcStats.lastBB0timer == 0L)	// TL was reset? (ignore 1st values)
+	{
+		// get TL's register counter - the "last" count
+		fcChip->fcStats.lastBB0timer = fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
+	} else			// subsequent pass - check for rollover
+	{
+		// "this" count
+		ulBuff = fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
+		if (fcChip->fcStats.lastBB0timer > ulBuff)	// rollover happened
+		{
+			// counter advanced to max...
+			fcChip->fcStats.BB0_Timer += (0x00FFFFFFL - fcChip->fcStats.lastBB0timer);
+			fcChip->fcStats.BB0_Timer += ulBuff;	// plus some more
+
+
+		} else		// no rollover -- more counts or no change
+		{
+			fcChip->fcStats.BB0_Timer += (ulBuff - fcChip->fcStats.lastBB0timer);
 
-    }
+		}
 
-    fcChip->fcStats.lastBB0timer = ulBuff;
-  }
+		fcChip->fcStats.lastBB0timer = ulBuff;
+	}
 
 
 
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 24);
-  fcChip->fcStats.LossofSignal += bBuff;
+	bBuff = (u8) (fcChip->Registers.FMLinkStatus1.value >> 24);
+	fcChip->fcStats.LossofSignal += bBuff;
 
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 16);
-  fcChip->fcStats.BadRXChar += bBuff;
+	bBuff = (u8) (fcChip->Registers.FMLinkStatus1.value >> 16);
+	fcChip->fcStats.BadRXChar += bBuff;
 
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 8);
-  fcChip->fcStats.LossofSync += bBuff;
+	bBuff = (u8) (fcChip->Registers.FMLinkStatus1.value >> 8);
+	fcChip->fcStats.LossofSync += bBuff;
 
 
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 24);
-  fcChip->fcStats.Rx_EOFa += bBuff;
+	bBuff = (u8) (fcChip->Registers.FMLinkStatus2.value >> 24);
+	fcChip->fcStats.Rx_EOFa += bBuff;
 
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 16);
-  fcChip->fcStats.Dis_Frm += bBuff;
+	bBuff = (u8) (fcChip->Registers.FMLinkStatus2.value >> 16);
+	fcChip->fcStats.Dis_Frm += bBuff;
 
-  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 8);
-  fcChip->fcStats.Bad_CRC += bBuff;
+	bBuff = (u8) (fcChip->Registers.FMLinkStatus2.value >> 8);
+	fcChip->fcStats.Bad_CRC += bBuff;
 }
 
 
 void cpqfcTSClearLinkStatusCounters(PTACHYON fcChip)
 {
-  ENTER("ClearLinkStatusCounters");
-  memset( &fcChip->fcStats, 0, sizeof( FCSTATS));
-  LEAVE("ClearLinkStatusCounters");
+	ENTER("ClearLinkStatusCounters");
+	memset(&fcChip->fcStats, 0, sizeof(FCSTATS));
+	LEAVE("ClearLinkStatusCounters");
 
 }
 
@@ -2110,77 +1913,74 @@
 // be correctly loaded by Tachyon silicon.  In the login payload, bytes
 // must be correctly swapped for Big Endian format.
 
-int CpqTsReadWriteWWN( PVOID pChip, int Read)
+int CpqTsReadWriteWWN(void * pChip, int Read)
 {
-  PTACHYON fcChip = (PTACHYON)pChip;
+	PTACHYON fcChip = (PTACHYON) pChip;
 #define NVRAM_SIZE 512
-  unsigned short i, count = NVRAM_SIZE;
-  UCHAR nvRam[NVRAM_SIZE], WWNbuf[8];
-  ULONG ulBuff;
-  int iStatus=-1;  // assume failure
-  int WWNoffset;
-
-  ENTER("ReadWriteWWN");
-  // Now try to read the WWN from the adapter's NVRAM
-
-  if( Read )  // READing NVRAM WWN?
-  {
-    ulBuff = cpqfcTS_ReadNVRAM( fcChip->Registers.TYstatus.address,
-                              fcChip->Registers.TYcontrol.address,
-                              count, &nvRam[0] );
-
-    if( ulBuff )   // NVRAM read successful?
-    {
-      iStatus = 0; // success!
-      
-                   // for engineering/ prototype boards, the data may be
-                   // invalid (GIGO, usually all "FF"); this prevents the
-                   // parse routine from working correctly, which means
-                   // nothing will be written to our passed buffer.
-
-      WWNoffset = cpqfcTS_GetNVRAM_data( WWNbuf, nvRam );
-
-      if( !WWNoffset ) // uninitialized NVRAM -- copy bytes directly
-      {
-        printk( "CAUTION: Copying NVRAM data on fcChip\n");
-        for( i= 0; i < 8; i++)
-          WWNbuf[i] = nvRam[i +0x2f]; // dangerous! some formats won't work
-      }
-      
-      fcChip->Registers.wwn_hi = 0L;
-      fcChip->Registers.wwn_lo = 0L;
-      for( i=0; i<4; i++)  // WWN bytes are big endian in NVRAM
-      {
-        ulBuff = 0L;
-        ulBuff = (ULONG)(WWNbuf[i]) << (8 * (3-i));
-        fcChip->Registers.wwn_hi |= ulBuff;
-      }
-      for( i=0; i<4; i++)  // WWN bytes are big endian in NVRAM
-      {
-        ulBuff = 0L;
-        ulBuff = (ULONG)(WWNbuf[i+4]) << (8 * (3-i));
-        fcChip->Registers.wwn_lo |= ulBuff;
-      }
-    }  // done reading
-    else
-    {
-
-      printk( "cpqfcTS: NVRAM read failed\n");
-
-    }
-  }
-
-  else  // WRITE
-  {
-
-    // NOTE: WRITE not supported & not used in released driver.
-
-   
-    printk("ReadWriteNRAM: can't write NVRAM; aborting write\n");
-  }
-  
-  LEAVE("ReadWriteWWN");
-  return iStatus;
+	unsigned short i, count = NVRAM_SIZE;
+	u8 nvRam[NVRAM_SIZE], WWNbuf[8];
+	u32 ulBuff;
+	int iStatus = -1;	// assume failure
+	int WWNoffset;
+
+	ENTER("ReadWriteWWN");
+	// Now try to read the WWN from the adapter's NVRAM
+
+	if (Read)		// READing NVRAM WWN?
+	{
+		ulBuff = cpqfcTS_ReadNVRAM(fcChip->Registers.TYstatus.address, fcChip->Registers.TYcontrol.address, count, &nvRam[0]);
+
+		if (ulBuff)	// NVRAM read successful?
+		{
+			iStatus = 0;	// success!
+
+			// for engineering/ prototype boards, the data may be
+			// invalid (GIGO, usually all "FF"); this prevents the
+			// parse routine from working correctly, which means
+			// nothing will be written to our passed buffer.
+
+			WWNoffset = cpqfcTS_GetNVRAM_data(WWNbuf, nvRam);
+
+			if (!WWNoffset)	// uninitialized NVRAM -- copy bytes directly
+			{
+				printk("CAUTION: Copying NVRAM data on fcChip\n");
+				for (i = 0; i < 8; i++)
+					WWNbuf[i] = nvRam[i + 0x2f];	// dangerous! some formats won't work
+			}
+
+			fcChip->Registers.wwn_hi = 0L;
+			fcChip->Registers.wwn_lo = 0L;
+			for (i = 0; i < 4; i++)	// WWN bytes are big endian in NVRAM
+			{
+				ulBuff = 0L;
+				ulBuff = (u32) (WWNbuf[i]) << (8 * (3 - i));
+				fcChip->Registers.wwn_hi |= ulBuff;
+			}
+			for (i = 0; i < 4; i++)	// WWN bytes are big endian in NVRAM
+			{
+				ulBuff = 0L;
+				ulBuff = (u32) (WWNbuf[i + 4]) << (8 * (3 - i));
+				fcChip->Registers.wwn_lo |= ulBuff;
+			}
+		}		// done reading
+		else {
+
+			printk("cpqfcTS: NVRAM read failed\n");
+
+		}
+	}
+
+	else			// WRITE
+	{
+
+		// NOTE: WRITE not supported & not used in released driver.
+
+
+		printk("ReadWriteNRAM: can't write NVRAM; aborting write\n");
+	}
+
+	LEAVE("ReadWriteWWN");
+	return iStatus;
 }
 
 
@@ -2192,39 +1992,36 @@
 // adapter does not use the NM24C03 chip, so this function only works on
 // Compaq's adapters.
 
-int CpqTsReadWriteNVRAM( PVOID pChip, PVOID buf, int Read)
+int CpqTsReadWriteNVRAM(void * pChip, void * buf, int Read)
 {
-  PTACHYON fcChip = (PTACHYON)pChip;
+	PTACHYON fcChip = (PTACHYON) pChip;
 #define NVRAM_SIZE 512
-  ULONG ulBuff;
-  UCHAR *ucPtr = buf; // cast caller's void ptr to UCHAR array
-  int iStatus=-1;  // assume failure
-
-     
-  if( Read )  // READing NVRAM?
-  {
-    ulBuff = cpqfcTS_ReadNVRAM(   // TRUE on success
-                fcChip->Registers.TYstatus.address,
-                fcChip->Registers.TYcontrol.address,
-                256,            // bytes to write
-                ucPtr );        // source ptr
-
-
-    if( ulBuff )
-      iStatus = 0; // success
-    else
-    {
+	u32 ulBuff;
+	u8 *ucPtr = buf;	// cast caller's void ptr to u8 array
+	int iStatus = -1;	// assume failure
+
+
+	if (Read)		// READing NVRAM?
+	{
+		ulBuff = cpqfcTS_ReadNVRAM(	// TRUE on success
+						  fcChip->Registers.TYstatus.address, fcChip->Registers.TYcontrol.address, 256,	// bytes to write
+						  ucPtr);	// source ptr
+
+
+		if (ulBuff)
+			iStatus = 0;	// success
+		else {
 #ifdef DBG
-      printk( "CAUTION: NVRAM read failed\n");
+			printk("CAUTION: NVRAM read failed\n");
 #endif
-    }
-  }  // done reading
+		}
+	}			// done reading
 
-  else  // WRITING NVRAM 
-  {
+	else			// WRITING NVRAM 
+	{
+
+		printk("cpqfcTS: WRITE of FC Controller's NVRAM disabled\n");
+	}
 
-    printk("cpqfcTS: WRITE of FC Controller's NVRAM disabled\n");
-  }
-    
-  return iStatus;
+	return iStatus;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/cpqfcTS.h linux.20pre10-ac2/drivers/scsi/cpqfcTS.h
--- linux.20pre10/drivers/scsi/cpqfcTS.h	2002-10-09 21:36:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/cpqfcTS.h	2002-10-09 22:15:47.000000000 +0100
@@ -5,40 +5,40 @@
 // These functions are required by the Linux SCSI layers
 extern int cpqfcTS_detect(Scsi_Host_Template *);
 extern int cpqfcTS_release(struct Scsi_Host *);
-extern const char * cpqfcTS_info(struct Scsi_Host *);
+extern const char *cpqfcTS_info(struct Scsi_Host *);
 extern int cpqfcTS_proc_info(char *, char **, off_t, int, int, int);
-extern int cpqfcTS_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
+extern int cpqfcTS_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 extern int cpqfcTS_abort(Scsi_Cmnd *);
 extern int cpqfcTS_reset(Scsi_Cmnd *, unsigned int);
-extern int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd);
+extern int cpqfcTS_eh_abort(Scsi_Cmnd * Cmnd);
 extern int cpqfcTS_eh_device_reset(Scsi_Cmnd *);
 extern int cpqfcTS_biosparam(Disk *, kdev_t, int[]);
-extern int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg);
+extern int cpqfcTS_ioctl(Scsi_Device * ScsiDev, int Cmnd, void *arg);
 
 // note: since Tachyon TS supports an extended scatter/gather
 // linked list of infinite length (with linked Ext S/G pages,
 // limited only by available physical memory) we use SG_ALL.
 
 #define CPQFCTS {                                \
- detect:                 cpqfcTS_detect,         \
- release:                cpqfcTS_release,        \
- info:                   cpqfcTS_info,           \
- proc_info:              cpqfcTS_proc_info,      \
- ioctl:                  cpqfcTS_ioctl,          \
- queuecommand:           cpqfcTS_queuecommand,   \
- eh_device_reset_handler:   cpqfcTS_eh_device_reset,   \
- eh_abort_handler:       cpqfcTS_eh_abort,       \
- reset:                  cpqfcTS_reset,          \
- abort:                  cpqfcTS_abort,		 \
- bios_param:             cpqfcTS_biosparam,      \
- can_queue:              CPQFCTS_REQ_QUEUE_LEN,  \
- this_id:                -1,                     \
- sg_tablesize:           SG_ALL,                 \
- cmd_per_lun:            CPQFCTS_CMD_PER_LUN,    \
- present:                0,                      \
- unchecked_isa_dma:      0,                      \
- use_clustering:         ENABLE_CLUSTERING,      \
- use_new_eh_code:        1			 \
+	detect:                 cpqfcTS_detect,         \
+	release:                cpqfcTS_release,        \
+	info:                   cpqfcTS_info,           \
+	proc_info:              cpqfcTS_proc_info,      \
+	ioctl:                  cpqfcTS_ioctl,          \
+	queuecommand:           cpqfcTS_queuecommand,   \
+	eh_device_reset_handler:   cpqfcTS_eh_device_reset,   \
+	eh_abort_handler:       cpqfcTS_eh_abort,       \
+	reset:                  cpqfcTS_reset,    	\
+	abort:                  cpqfcTS_abort,		\
+	bios_param:             cpqfcTS_biosparam,	\
+	can_queue:              CPQFCTS_REQ_QUEUE_LEN,	\
+	this_id:                -1,               	\
+	sg_tablesize:           SG_ALL,           	\
+	cmd_per_lun:            CPQFCTS_CMD_PER_LUN,	\
+	present:                0,              	\
+	unchecked_isa_dma:      0,              	\
+	use_clustering:         ENABLE_CLUSTERING,	\
+	use_new_eh_code:        1			\
 }
 
-#endif /* CPQFCTS_H */ 
+#endif				/* CPQFCTS_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/cpqfcTSi2c.c linux.20pre10-ac2/drivers/scsi/cpqfcTSi2c.c
--- linux.20pre10/drivers/scsi/cpqfcTSi2c.c	2002-10-09 21:36:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/cpqfcTSi2c.c	2002-09-12 18:06:29.000000000 +0100
@@ -25,121 +25,105 @@
 // Orignal source author unknown
 
 #include <linux/types.h>
-enum boolean { FALSE, TRUE } ;
-
-
-#ifndef UCHAR
-typedef __u8 UCHAR;
-#endif
-#ifndef BOOLEAN
-typedef __u8 BOOLEAN;
-#endif
-#ifndef USHORT
-typedef __u16 USHORT;
-#endif
-#ifndef ULONG
-typedef __u32 ULONG;
-#endif
-
-
 #include <linux/string.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
-#include <asm/io.h>  // struct pt_regs for IRQ handler & Port I/O
+#include <asm/io.h>		// struct pt_regs for IRQ handler & Port I/O
 
 #include "cpqfcTSchip.h"
 
-static void tl_i2c_tx_byte( void* GPIOout, UCHAR data );
-/*static BOOLEAN tl_write_i2c_page_portion( void* GPIOin, void* GPIOout,
-  USHORT startOffset,  // e.g. 0x2f for WWN start
-  USHORT count,
-  UCHAR *buf );
-*/
+static void tl_i2c_tx_byte(void *GPIOout, u8 data);
 
-//
-// Tachlite GPIO2, GPIO3 (I2C) DEFINES
-// The NVRAM chip NM24C03 defines SCL (serial clock) and SDA (serial data)
-// GPIO2 drives SDA, and GPIO3 drives SCL
-// 
-// Since Tachlite inverts the state of the GPIO 0-3 outputs, SET writes 0
-// and clear writes 1. The input lines (read in TL status) is NOT inverted
-// This really helps confuse the code and debugging.
+/*
+ * Tachlite GPIO2, GPIO3 (I2C) DEFINES
+ * The NVRAM chip NM24C03 defines SCL (serial clock) and SDA (serial data)
+ * GPIO2 drives SDA, and GPIO3 drives SCL
+ * 
+ * Since Tachlite inverts the state of the GPIO 0-3 outputs, SET writes 0
+ * and clear writes 1. The input lines (read in TL status) is NOT inverted
+ * This really helps confuse the code and debugging.
+ */
+ 
+#define SET_DATA_HI		0x0
+#define SET_DATA_LO		0x8
+#define SET_CLOCK_HI		0x0
+#define SET_CLOCK_LO		0x4
 
-#define SET_DATA_HI  0x0
-#define SET_DATA_LO  0x8
-#define SET_CLOCK_HI 0x0
-#define SET_CLOCK_LO 0x4
+#define SENSE_DATA_HI		0x8
+#define SENSE_DATA_LO		0x0
+#define SENSE_CLOCK_HI		0x4
+#define SENSE_CLOCK_LO		0x0
 
-#define SENSE_DATA_HI  0x8
-#define SENSE_DATA_LO  0x0
-#define SENSE_CLOCK_HI 0x4
-#define SENSE_CLOCK_LO 0x0
+#define SLAVE_READ_ADDRESS	0xA1
+#define SLAVE_WRITE_ADDRESS	0xA0
 
-#define SLAVE_READ_ADDRESS    0xA1
-#define SLAVE_WRITE_ADDRESS   0xA0
-					      
 
-static void i2c_delay(ULONG mstime);
-static void tl_i2c_clock_pulse( UCHAR , void* GPIOout);
-static UCHAR tl_read_i2c_data( void* );
+static void i2c_delay(u32 mstime);
+static void tl_i2c_clock_pulse(u8, void *GPIOout);
+static u8 tl_read_i2c_data(void *);
 
 
 //-----------------------------------------------------------------------------
 //
-//      Name:   I2C_RX_ACK
+//      Name:   tl_i2c_rx_ack
 //
 //      This routine receives an acknowledge over the I2C bus.
 //
 //-----------------------------------------------------------------------------
-static unsigned short tl_i2c_rx_ack( void* GPIOin, void* GPIOout )
+static unsigned short tl_i2c_rx_ack(void *GPIOin, void *GPIOout)
 {
-  unsigned long value;
+	unsigned long value;
 
 	// do clock pulse, let data line float high
-  tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
+	tl_i2c_clock_pulse(SET_DATA_HI, GPIOout);
 
 	// slave must drive data low for acknowledge
-  value = tl_read_i2c_data( GPIOin);
-  if (value & SENSE_DATA_HI )
-    return( FALSE );
+	value = tl_read_i2c_data(GPIOin);
+	if (value & SENSE_DATA_HI)
+		return 0;
 
-  return( TRUE );
+	return 1;
 }
+
 //-----------------------------------------------------------------------------
 //
-//      Name:   READ_I2C_REG
+//      Name:   tl_read_i2c_reg
 //
 //      This routine reads the I2C control register using the global
 //      IO address stored in gpioreg.
 //
 //-----------------------------------------------------------------------------
-static UCHAR tl_read_i2c_data( void* gpioreg )
+static u8 tl_read_i2c_data(void *gpioreg)
 {
-  return( (UCHAR)(readl( gpioreg ) & 0x08L) ); // GPIO3
+	return ((u8) (readl(gpioreg) & 0x08L));	// GPIO3
 }
+
 //-----------------------------------------------------------------------------
 //
-//      Name:   WRITE_I2C_REG
+//      Name:   tl_write_i2c_reg
 //
 //      This routine writes the I2C control register using the global
 //      IO address stored in gpioreg.
 //      In Tachlite, we don't want to modify other bits in TL Control reg.
 //
 //-----------------------------------------------------------------------------
-static void tl_write_i2c_reg( void* gpioregOUT, UCHAR value )
+static void tl_write_i2c_reg(void *gpioregOUT, u8 value)
 {
-  ULONG  temp;
+	u32 temp;
 
 	// First read the register and clear out the old bits
-  temp = readl( gpioregOUT ) & 0xfffffff3L;
+	temp = readl(gpioregOUT) & 0xfffffff3L;
 
 	// Now or in the new data and send it back out
-  writel( temp | value, gpioregOUT);
+	writel(temp | value, gpioregOUT);
+	
+	/* PCI posting ???? */
 }
+
 //-----------------------------------------------------------------------------
 //
-//      Name:   I2C_TX_START
+//      Name:   tl_i2c_tx_start
 //
 //      This routine transmits a start condition over the I2C bus.
 //      1. Set SCL (clock, GPIO2) HIGH, set SDA (data, GPIO3) HIGH,
@@ -149,165 +133,162 @@
 //      NOTE! In TL control reg., output 1 means chip sees LOW
 //
 //-----------------------------------------------------------------------------
-static unsigned short tl_i2c_tx_start( void* GPIOin, void* GPIOout )
+static unsigned short tl_i2c_tx_start(void *GPIOin, void *GPIOout)
 {
-  unsigned short i;
-  ULONG value;
+	unsigned short i;
+	u32 value;
 
-  if ( !(tl_read_i2c_data(GPIOin) & SENSE_DATA_HI))
-  {
-    // start with clock high, let data float high
-    tl_write_i2c_reg(  GPIOout, SET_DATA_HI | SET_CLOCK_HI );
-
-    // keep sending clock pulses if slave is driving data line
-    for (i = 0; i < 10; i++)
-    {
-      tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
-
-      if ( tl_read_i2c_data(GPIOin) & SENSE_DATA_HI )
-	break;
-    }
+	if (!(tl_read_i2c_data(GPIOin) & SENSE_DATA_HI)) {
+		// start with clock high, let data float high
+		tl_write_i2c_reg(GPIOout, SET_DATA_HI | SET_CLOCK_HI);
+
+		// keep sending clock pulses if slave is driving data line
+		for (i = 0; i < 10; i++) {
+			tl_i2c_clock_pulse(SET_DATA_HI, GPIOout);
+
+			if (tl_read_i2c_data(GPIOin) & SENSE_DATA_HI)
+				break;
+		}
 
 		// if he's still driving data low after 10 clocks, abort
-    value = tl_read_i2c_data( GPIOin ); // read status
-    if (!(value & 0x08) )
-      return( FALSE );
-  }
-
+		value = tl_read_i2c_data(GPIOin);	// read status
+		if (!(value & 0x08))
+			return 0;
+	}
 
 	// To START, bring data low while clock high
-  tl_write_i2c_reg(  GPIOout, SET_CLOCK_HI | SET_DATA_LO );
+	tl_write_i2c_reg(GPIOout, SET_CLOCK_HI | SET_DATA_LO);
 
-  i2c_delay(0);
+	udelay(5);
 
-  return( TRUE );                           // TX start successful
+	return 1;		// TX start successful
 }
+
 //-----------------------------------------------------------------------------
 //
-//      Name:   I2C_TX_STOP
+//      Name:   tl_i2c_tx_stop
 //
 //      This routine transmits a stop condition over the I2C bus.
 //
 //-----------------------------------------------------------------------------
 
-static unsigned short tl_i2c_tx_stop( void* GPIOin, void* GPIOout )
+static unsigned short tl_i2c_tx_stop(void *GPIOin, void *GPIOout)
 {
-  int i;
+	int i;
 
-  for (i = 0; i < 10; i++) 
-  {
-  // Send clock pulse, drive data line low
-    tl_i2c_clock_pulse( SET_DATA_LO, GPIOout );
+	for (i = 0; i < 10; i++) {
+		// Send clock pulse, drive data line low
+		tl_i2c_clock_pulse(SET_DATA_LO, GPIOout);
 
-  // To STOP, bring data high while clock high
-    tl_write_i2c_reg(  GPIOout, SET_DATA_HI | SET_CLOCK_HI );
+		// To STOP, bring data high while clock high
+		tl_write_i2c_reg(GPIOout, SET_DATA_HI | SET_CLOCK_HI);
 
-  // Give the data line time to float high
-    i2c_delay(0);
+		// Give the data line time to float high
+		udelay(5);
 
-  // If slave is driving data line low, there's a problem; retry
-    if ( tl_read_i2c_data(GPIOin) & SENSE_DATA_HI )
-      return( TRUE );  // TX STOP successful!
-  }
+		// If slave is driving data line low, there's a problem; retry
+		if (tl_read_i2c_data(GPIOin) & SENSE_DATA_HI)
+			return 1;	// TX STOP successful!
+	}
 
-  return( FALSE );                      // error
+	return 0;		// error
 }
+
 //-----------------------------------------------------------------------------
 //
-//      Name:   I2C_TX_uchar
+//      Name:   tl_i2c_tx_byte
 //
 //      This routine transmits a byte across the I2C bus.
 //
 //-----------------------------------------------------------------------------
-static void tl_i2c_tx_byte( void* GPIOout, UCHAR data )
+static void tl_i2c_tx_byte(void *GPIOout, u8 data)
 {
-  UCHAR bit;
+	u8 bit;
 
-  for (bit = 0x80; bit; bit >>= 1)
-  {
-    if( data & bit )
-      tl_i2c_clock_pulse( (UCHAR)SET_DATA_HI, GPIOout);
-    else
-      tl_i2c_clock_pulse( (UCHAR)SET_DATA_LO, GPIOout);
-  }  
+	for (bit = 0x80; bit; bit >>= 1) {
+		if (data & bit)
+			tl_i2c_clock_pulse((u8) SET_DATA_HI, GPIOout);
+		else
+			tl_i2c_clock_pulse((u8) SET_DATA_LO, GPIOout);
+	}
 }
+
 //-----------------------------------------------------------------------------
 //
-//      Name:   I2C_RX_uchar
+//      Name:   tl_i2c_rx_byte
 //
 //      This routine receives a byte across the I2C bus.
 //
 //-----------------------------------------------------------------------------
-static UCHAR tl_i2c_rx_byte( void* GPIOin, void* GPIOout )
+static u8 tl_i2c_rx_byte(void *GPIOin, void *GPIOout)
 {
-  UCHAR bit;
-  UCHAR data = 0;
+	u8 bit;
+	u8 data = 0;
 
 
-  for (bit = 0x80; bit; bit >>= 1) {
-    // do clock pulse, let data line float high
-    tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
+	for (bit = 0x80; bit; bit >>= 1) {
+		// do clock pulse, let data line float high
+		tl_i2c_clock_pulse(SET_DATA_HI, GPIOout);
 
-    // read data line
-    if ( tl_read_i2c_data( GPIOin) & 0x08 )
-      data |= bit;
-  }
+		// read data line
+		if (tl_read_i2c_data(GPIOin) & 0x08)
+			data |= bit;
+	}
 
-  return (data);
+	return (data);
 }
+
 //*****************************************************************************
 //*****************************************************************************
 // Function:   read_i2c_nvram
-// Arguments:  UCHAR count     number of bytes to read
-//             UCHAR *buf      area to store the bytes read
+// Arguments:  u8 count     number of bytes to read
+//             u8 *buf      area to store the bytes read
 // Returns:    0 - failed
 //             1 - success
 //*****************************************************************************
 //*****************************************************************************
-unsigned long cpqfcTS_ReadNVRAM( void* GPIOin, void* GPIOout , USHORT count,
-	UCHAR *buf )
+unsigned long cpqfcTS_ReadNVRAM(void *GPIOin, void *GPIOout, u16 count, u8 * buf)
 {
-  unsigned short i;
+	unsigned short i;
 
-  if( !( tl_i2c_tx_start(GPIOin, GPIOout) ))
-    return FALSE;
+	if (!(tl_i2c_tx_start(GPIOin, GPIOout)))
+		return 0;
 
-  // Select the NVRAM for "dummy" write, to set the address
-  tl_i2c_tx_byte( GPIOout , SLAVE_WRITE_ADDRESS );
-  if ( !tl_i2c_rx_ack(GPIOin, GPIOout ) )
-    return( FALSE );
-
-  // Now send the address where we want to start reading  
-  tl_i2c_tx_byte( GPIOout , 0 );
-  if ( !tl_i2c_rx_ack(GPIOin, GPIOout ) )
-    return( FALSE );
-
-  // Send a repeated start condition and select the
-  //  slave for reading now.
-  if( tl_i2c_tx_start(GPIOin, GPIOout) )
-    tl_i2c_tx_byte( GPIOout, SLAVE_READ_ADDRESS );
-
-  if ( !tl_i2c_rx_ack(GPIOin, GPIOout) )
-    return( FALSE );
-
-  // this loop will now read out the data and store it
-  //  in the buffer pointed to by buf
-  for ( i=0; i<count; i++) 
-  {
-    *buf++ = tl_i2c_rx_byte(GPIOin, GPIOout);
-
-    // Send ACK by holding data line low for 1 clock
-    if ( i < (count-1) )
-      tl_i2c_clock_pulse( 0x08, GPIOout );
-    else {
-	// Don't send ack for final byte
-      tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
-    }
-  }
+	// Select the NVRAM for "dummy" write, to set the address
+	tl_i2c_tx_byte(GPIOout, SLAVE_WRITE_ADDRESS);
+	if (!tl_i2c_rx_ack(GPIOin, GPIOout))
+		return 0;
+
+	// Now send the address where we want to start reading  
+	tl_i2c_tx_byte(GPIOout, 0);
+	if (!tl_i2c_rx_ack(GPIOin, GPIOout))
+		return 0;
+
+	// Send a repeated start condition and select the
+	//  slave for reading now.
+	if (tl_i2c_tx_start(GPIOin, GPIOout))
+		tl_i2c_tx_byte(GPIOout, SLAVE_READ_ADDRESS);
+
+	if (!tl_i2c_rx_ack(GPIOin, GPIOout))
+		return 0;
+
+	// this loop will now read out the data and store it
+	//  in the buffer pointed to by buf
+	for (i = 0; i < count; i++) {
+		*buf++ = tl_i2c_rx_byte(GPIOin, GPIOout);
+
+		// Send ACK by holding data line low for 1 clock
+		if (i < (count - 1))
+			tl_i2c_clock_pulse(0x08, GPIOout);
+		else {
+			// Don't send ack for final byte
+			tl_i2c_clock_pulse(SET_DATA_HI, GPIOout);
+		}
+	}
 
-  tl_i2c_tx_stop(GPIOin, GPIOout);
+	tl_i2c_tx_stop(GPIOin, GPIOout);
 
-  return( TRUE );
+	return 1;
 }
 
 //****************************************************************
@@ -320,22 +301,22 @@
 //
 //****************************************************************
 
-static void tl_set_clock(void* gpioreg)
+static void tl_set_clock(void *gpioreg)
 {
-  ULONG ret_val;
+	u32 ret_val;
 
-  ret_val = readl( gpioreg );
-  ret_val &= 0xffffffFBL;  // clear GPIO2 (SCL)
-  writel( ret_val, gpioreg);
+	ret_val = readl(gpioreg);
+	ret_val &= 0xffffffFBL;	// clear GPIO2 (SCL)
+	writel(ret_val, gpioreg);
 }
 
-static void tl_clr_clock(void* gpioreg)
+static void tl_clr_clock(void *gpioreg)
 {
-  ULONG ret_val;
+	u32 ret_val;
 
-  ret_val = readl( gpioreg );
-  ret_val |= SET_CLOCK_LO;
-  writel( ret_val, gpioreg);
+	ret_val = readl(gpioreg);
+	ret_val |= SET_CLOCK_LO;
+	writel(ret_val, gpioreg);
 }
 
 //*****************************************************************
@@ -345,33 +326,33 @@
 //
 //
 //*****************************************************************
-static void tl_i2c_clock_pulse( UCHAR value, void* GPIOout  )
+static void tl_i2c_clock_pulse(u8 value, void *GPIOout)
 {
-  ULONG ret_val;
+	u32 ret_val;
 
-  // clear the clock bit
-  tl_clr_clock( GPIOout );
+	// clear the clock bit
+	tl_clr_clock(GPIOout);
 
-  i2c_delay(0);
+	udelay(5);
 
 
-  // read the port to preserve non-I2C bits
-  ret_val = readl( GPIOout );
+	// read the port to preserve non-I2C bits
+	ret_val = readl(GPIOout);
 
-  // clear the data & clock bits
-  ret_val &= 0xFFFFFFf3;
+	// clear the data & clock bits
+	ret_val &= 0xFFFFFFf3;
 
-  // write the value passed in...
-  // data can only change while clock is LOW!
-  ret_val |= value;           // the data
-  ret_val |= SET_CLOCK_LO;    // the clock
-  writel( ret_val, GPIOout );
+	// write the value passed in...
+	// data can only change while clock is LOW!
+	ret_val |= value;	// the data
+	ret_val |= SET_CLOCK_LO;	// the clock
+	writel(ret_val, GPIOout);
 
-  i2c_delay(0);
+	udelay(5);
 
 
-  //set clock bit
-  tl_set_clock( GPIOout);
+	//set clock bit
+	tl_set_clock(GPIOout);
 }
 
 
@@ -384,110 +365,71 @@
 //
 //
 //*****************************************************************
-int cpqfcTS_GetNVRAM_data( UCHAR *wwnbuf, UCHAR *buf )
+int cpqfcTS_GetNVRAM_data(u8 * wwnbuf, u8 * buf)
 {
-  ULONG len;
-  ULONG sub_len;
-  ULONG ptr_inc;
-  ULONG i;
-  ULONG j;
-  UCHAR *data_ptr;
-  UCHAR  z;
-  UCHAR  name;
-  UCHAR  sub_name;
-  UCHAR  done;
-  int iReturn=0;  // def. 0 offset is failure to find WWN field
-  
-
-	  
-  data_ptr = (UCHAR *)buf;
-
-  done = FALSE;
-  i = 0;
-
-  while ( (i < 128) && (!done) ) 
-  {
-    z = data_ptr[i];\
-    if ( !(z & 0x80) )  
-    {	
-      len  = 1 + (z & 0x07);
-
-      name = (z & 0x78) >> 3;
-      if (name == 0x0F)
-        done = TRUE;
-    }
-    else 
-    {
-      name = z & 0x7F;
-      len  = 3 + data_ptr[i+1] + (data_ptr[i+2] << 8);
-           
-      switch (name) 
-      {
-      case 0x0D:
-	//
-	  j = i + 3;
-	  //
-	  if ( data_ptr[j] == 0x3b ) {
-	    len = 6;
-	    break;
-	  }
-
-	  while ( j<(i+len) ) {
-	    sub_name = (data_ptr[j] & 0x3f);
-	    sub_len  = data_ptr[j+1] + 
-	               (data_ptr[j+2] << 8);
-            ptr_inc  = sub_len + 3; 
-	    switch (sub_name) 
-	    {
-	    case 0x3C:
-              memcpy( wwnbuf, &data_ptr[j+3], 8);
-              iReturn = j+3;
-              break;
-            default:
-              break;
-	    }
-	    j += ptr_inc;
-          }
-	  break;
-        default:
-	  break;
-      }  
-    }  
-  //
-    i += len;
-  }  // end while 
-  return iReturn;
+	u32 len;
+	u32 sub_len;
+	u32 ptr_inc;
+	u32 i;
+	u32 j;
+	u8 *data_ptr;
+	u8 z;
+	u8 name;
+	u8 sub_name;
+	u8 done;
+	int ret = 0;	// def. 0 offset is failure to find WWN field
+
+
+
+	data_ptr = (u8 *) buf;
+
+	done = 0;
+	i = 0;
+
+	while (i < 128 && !done) {
+		z = data_ptr[i];
+		if (!(z & 0x80)) {
+			len = 1 + (z & 0x07);
+
+			name = (z & 0x78) >> 3;
+			if (name == 0x0F)
+				done = 1;
+		} else {
+			name = z & 0x7F;
+			len = 3 + data_ptr[i + 1] + (data_ptr[i + 2] << 8);
+
+			switch (name) {
+			case 0x0D:
+				//
+				j = i + 3;
+				//
+				if (data_ptr[j] == 0x3b) {
+					len = 6;
+					break;
+				}
+
+				while (j < (i + len)) {
+					sub_name = (data_ptr[j] & 0x3f);
+					sub_len = data_ptr[j + 1] + (data_ptr[j + 2] << 8);
+					ptr_inc = sub_len + 3;
+					switch (sub_name) {
+					case 0x3C:
+						memcpy(wwnbuf, &data_ptr[j + 3], 8);
+						ret = j + 3;
+						break;
+					default:
+						break;
+					}
+					j += ptr_inc;
+				}
+				break;
+			default:
+				break;
+			}
+		}
+		//
+		i += len;
+	}			// end while 
+	return ret;
 }
 
-
-
-
-
-// define a short 5 micro sec delay, and longer (ms) delay
-
-static void i2c_delay(ULONG mstime)
-{
-  ULONG i;
-  
-// NOTE: we only expect to use these delays when reading
-// our adapter's NVRAM, which happens only during adapter reset.
-// Delay technique from "Linux Device Drivers", A. Rubini 
-// (1st Ed.) pg 137.
-
-//  printk(" delay %lx  ", mstime);
-  if( mstime ) // ms delay?
-  {
-    // delay technique
-    for( i=0; i < mstime; i++)
-      udelay(1000); // 1ms per loop
-	
-  }
-  else  // 5 micro sec delay
-  
-    udelay( 5 ); // micro secs
-  
-//  printk("done\n");
-}
-
-
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/cpqfcTSinit.c linux.20pre10-ac2/drivers/scsi/cpqfcTSinit.c
--- linux.20pre10/drivers/scsi/cpqfcTSinit.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/cpqfcTSinit.c	2002-09-12 17:59:27.000000000 +0100
@@ -29,8 +29,6 @@
 */
 
 
-#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-
 #include <linux/blk.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -39,17 +37,16 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/timer.h>
-#include <linux/ioport.h>  // request_region() prototype
-#include <linux/vmalloc.h> // ioremap()
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,7)
+#include <linux/ioport.h>	// request_region() prototype
+#include <linux/slab.h>
+#include <linux/vmalloc.h>	// ioremap()
 #include <linux/completion.h>
-#endif
 #ifdef __alpha__
 #define __KERNEL_SYSCALLS__
 #endif
 #include <asm/unistd.h>
 #include <asm/io.h>
-#include <asm/uaccess.h>   // ioctl related
+#include <asm/uaccess.h>	// ioctl related
 #include <asm/irq.h>
 #include <linux/spinlock.h>
 #include "sd.h"
@@ -61,48 +58,21 @@
 
 #include "cpqfcTS.h"
 
-#include <linux/config.h>  
+#include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h> 
+#include <linux/version.h>
 
 /* Embedded module documentation macros - see module.h */
 MODULE_AUTHOR("Compaq Computer Corporation");
 MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.1.1");
 MODULE_LICENSE("GPL");
-  
-int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, unsigned int reset_flags);
-
-// This struct was originally defined in 
-// /usr/src/linux/include/linux/proc_fs.h
-// since it's only partially implemented, we only use first
-// few fields...
-// NOTE: proc_fs changes in 2.4 kernel
-
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
-static struct proc_dir_entry proc_scsi_cpqfcTS =
-{
-  PROC_SCSI_CPQFCTS,           // ushort low_ino (enumerated list)
-  7,                           // ushort namelen
-  DEV_NAME,                    // const char* name
-  S_IFDIR | S_IRUGO | S_IXUGO, // mode_t mode
-  2                            // nlink_t nlink
-	                       // etc. ...
-};
 
+int cpqfcTS_TargetDeviceReset(Scsi_Device * ScsiDev, unsigned int reset_flags);
 
-#endif
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,7)
-#  define CPQFC_DECLARE_COMPLETION(x) DECLARE_COMPLETION(x)
-#  define CPQFC_WAITING waiting
-#  define CPQFC_COMPLETE(x) complete(x)
-#  define CPQFC_WAIT_FOR_COMPLETION(x) wait_for_completion(x);
-#else
-#  define CPQFC_DECLARE_COMPLETION(x) DECLARE_MUTEX_LOCKED(x)
-#  define CPQFC_WAITING sem
-#  define CPQFC_COMPLETE(x) up(x)
-#  define CPQFC_WAIT_FOR_COMPLETION(x) down(x)
-#endif
+#define CPQFC_DECLARE_COMPLETION(x) DECLARE_COMPLETION(x)
+#define CPQFC_WAITING waiting
+#define CPQFC_COMPLETE(x) complete(x)
+#define CPQFC_WAIT_FOR_COMPLETION(x) wait_for_completion(x);
 
 /* local function to load our per-HBA (local) data for chip
    registers, FC link state, all FC exchanges, etc.
@@ -112,120 +82,86 @@
    Name) are not necessary.
    
 */
-static void Cpqfc_initHBAdata( CPQFCHBA *cpqfcHBAdata, struct pci_dev *PciDev )
+static void Cpqfc_initHBAdata(CPQFCHBA * cpqfcHBAdata, struct pci_dev *PciDev)
 {
-             
-  cpqfcHBAdata->PciDev = PciDev; // copy PCI info ptr
 
-  // since x86 port space is 64k, we only need the lower 16 bits
-  cpqfcHBAdata->fcChip.Registers.IOBaseL = 
-    PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
-  
-  cpqfcHBAdata->fcChip.Registers.IOBaseU = 
-    PciDev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK;
-  
-  // 32-bit memory addresses
-  cpqfcHBAdata->fcChip.Registers.MemBase = 
-    PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK;
-
-  cpqfcHBAdata->fcChip.Registers.ReMapMemBase = 
-    ioremap( PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK,
-             0x200);
-  
-  cpqfcHBAdata->fcChip.Registers.RAMBase = 
-    PciDev->resource[4].start;
-  
-  cpqfcHBAdata->fcChip.Registers.SROMBase =  // NULL for HP TS adapter
-    PciDev->resource[5].start;
-  
-  // now the Tachlite chip registers
-  // the REGISTER struct holds both the physical address & last
-  // written value (some TL registers are WRITE ONLY)
-
-  cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_SFQ_CONSUMER_INDEX;
-
-  cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX;
-      
-  // TL Frame Manager
-  cpqfcHBAdata->fcChip.Registers.FMconfig.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONFIG;
-  cpqfcHBAdata->fcChip.Registers.FMcontrol.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONTROL;
-  cpqfcHBAdata->fcChip.Registers.FMstatus.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_STATUS;
-  cpqfcHBAdata->fcChip.Registers.FMLinkStatus1.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT1;
-  cpqfcHBAdata->fcChip.Registers.FMLinkStatus2.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT2;
-  cpqfcHBAdata->fcChip.Registers.FMBB_CreditZero.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_BB_CREDIT0;
-      
-      // TL Control Regs
-  cpqfcHBAdata->fcChip.Registers.TYconfig.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONFIG;
-  cpqfcHBAdata->fcChip.Registers.TYcontrol.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONTROL;
-  cpqfcHBAdata->fcChip.Registers.TYstatus.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_STATUS;
-  cpqfcHBAdata->fcChip.Registers.rcv_al_pa.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_RCV_AL_PA;
-  cpqfcHBAdata->fcChip.Registers.ed_tov.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_ED_TOV;
-
-
-  cpqfcHBAdata->fcChip.Registers.INTEN.address = 
-	        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTEN;
-  cpqfcHBAdata->fcChip.Registers.INTPEND.address = 
-	        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTPEND;
-  cpqfcHBAdata->fcChip.Registers.INTSTAT.address = 
-        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTSTAT;
-
-  DEBUG_PCI(printk("  cpqfcHBAdata->fcChip.Registers. :\n"));
-  DEBUG_PCI(printk("    IOBaseL = %x\n", 
-    cpqfcHBAdata->fcChip.Registers.IOBaseL));
-  DEBUG_PCI(printk("    IOBaseU = %x\n", 
-    cpqfcHBAdata->fcChip.Registers.IOBaseU));
-  
-  printk(" ioremap'd Membase: %p\n", cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
-  
-  DEBUG_PCI(printk("    SFQconsumerIndex.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address));
-  DEBUG_PCI(printk("    ERQproducerIndex.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address));
-  DEBUG_PCI(printk("    TYconfig.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.TYconfig.address));
-  DEBUG_PCI(printk("    FMconfig.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.FMconfig.address));
-  DEBUG_PCI(printk("    FMcontrol.address = %p\n", 
-    cpqfcHBAdata->fcChip.Registers.FMcontrol.address));
-
-  // set default options for FC controller (chip)
-  cpqfcHBAdata->fcChip.Options.initiator = 1;  // default: SCSI initiator
-  cpqfcHBAdata->fcChip.Options.target = 0;     // default: SCSI target
-  cpqfcHBAdata->fcChip.Options.extLoopback = 0;// default: no loopback @GBIC
-  cpqfcHBAdata->fcChip.Options.intLoopback = 0;// default: no loopback inside chip
-
-  // set highest and lowest FC-PH version the adapter/driver supports
-  // (NOT strict compliance)
-  cpqfcHBAdata->fcChip.highest_FCPH_ver = FC_PH3;
-  cpqfcHBAdata->fcChip.lowest_FCPH_ver = FC_PH43;
-
-  // set function points for this controller / adapter
-  cpqfcHBAdata->fcChip.ResetTachyon = CpqTsResetTachLite;
-  cpqfcHBAdata->fcChip.FreezeTachyon = CpqTsFreezeTachlite;
-  cpqfcHBAdata->fcChip.UnFreezeTachyon = CpqTsUnFreezeTachlite;
-  cpqfcHBAdata->fcChip.CreateTachyonQues = CpqTsCreateTachLiteQues;
-  cpqfcHBAdata->fcChip.DestroyTachyonQues = CpqTsDestroyTachLiteQues;
-  cpqfcHBAdata->fcChip.InitializeTachyon = CpqTsInitializeTachLite;  
-  cpqfcHBAdata->fcChip.LaserControl = CpqTsLaserControl;  
-  cpqfcHBAdata->fcChip.ProcessIMQEntry = CpqTsProcessIMQEntry;
-  cpqfcHBAdata->fcChip.InitializeFrameManager = CpqTsInitializeFrameManager;;  
-  cpqfcHBAdata->fcChip.ReadWriteWWN = CpqTsReadWriteWWN;
-  cpqfcHBAdata->fcChip.ReadWriteNVRAM = CpqTsReadWriteNVRAM;
+	cpqfcHBAdata->PciDev = PciDev;	// copy PCI info ptr
+
+	// since x86 port space is 64k, we only need the lower 16 bits
+	cpqfcHBAdata->fcChip.Registers.IOBaseL = PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
+	cpqfcHBAdata->fcChip.Registers.IOBaseU = PciDev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK;
+
+	// 32-bit memory addresses
+	cpqfcHBAdata->fcChip.Registers.MemBase = PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK;
+	cpqfcHBAdata->fcChip.Registers.ReMapMemBase = ioremap(PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK, 0x200);
+	cpqfcHBAdata->fcChip.Registers.RAMBase = PciDev->resource[4].start;
+	cpqfcHBAdata->fcChip.Registers.SROMBase = PciDev->resource[5].start; // NULL for HP TS adapter
+
+	// now the Tachlite chip registers
+	// the REGISTER struct holds both the physical address & last
+	// written value (some TL registers are WRITE ONLY)
+
+	cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_SFQ_CONSUMER_INDEX;
+
+	cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX;
+
+	// TL Frame Manager
+	cpqfcHBAdata->fcChip.Registers.FMconfig.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONFIG;
+	cpqfcHBAdata->fcChip.Registers.FMcontrol.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONTROL;
+	cpqfcHBAdata->fcChip.Registers.FMstatus.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_STATUS;
+	cpqfcHBAdata->fcChip.Registers.FMLinkStatus1.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT1;
+	cpqfcHBAdata->fcChip.Registers.FMLinkStatus2.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT2;
+	cpqfcHBAdata->fcChip.Registers.FMBB_CreditZero.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_BB_CREDIT0;
+
+	// TL Control Regs
+	cpqfcHBAdata->fcChip.Registers.TYconfig.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONFIG;
+	cpqfcHBAdata->fcChip.Registers.TYcontrol.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONTROL;
+	cpqfcHBAdata->fcChip.Registers.TYstatus.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_STATUS;
+	cpqfcHBAdata->fcChip.Registers.rcv_al_pa.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_RCV_AL_PA;
+	cpqfcHBAdata->fcChip.Registers.ed_tov.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_ED_TOV;
+
+
+	cpqfcHBAdata->fcChip.Registers.INTEN.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTEN;
+	cpqfcHBAdata->fcChip.Registers.INTPEND.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTPEND;
+	cpqfcHBAdata->fcChip.Registers.INTSTAT.address = cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTSTAT;
+
+	DEBUG_PCI(printk("  cpqfcHBAdata->fcChip.Registers. :\n"));
+	DEBUG_PCI(printk("    IOBaseL = %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseL));
+	DEBUG_PCI(printk("    IOBaseU = %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseU));
+
+	printk(" ioremap'd Membase: %p\n", cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
+
+	DEBUG_PCI(printk("    SFQconsumerIndex.address = %p\n", cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address));
+	DEBUG_PCI(printk("    ERQproducerIndex.address = %p\n", cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address));
+	DEBUG_PCI(printk("    TYconfig.address = %p\n", cpqfcHBAdata->fcChip.Registers.TYconfig.address));
+	DEBUG_PCI(printk("    FMconfig.address = %p\n", cpqfcHBAdata->fcChip.Registers.FMconfig.address));
+	DEBUG_PCI(printk("    FMcontrol.address = %p\n", cpqfcHBAdata->fcChip.Registers.FMcontrol.address));
+
+	// set default options for FC controller (chip)
+	cpqfcHBAdata->fcChip.Options.initiator = 1;	// default: SCSI initiator
+	cpqfcHBAdata->fcChip.Options.target = 0;	// default: SCSI target
+	cpqfcHBAdata->fcChip.Options.extLoopback = 0;	// default: no loopback @GBIC
+	cpqfcHBAdata->fcChip.Options.intLoopback = 0;	// default: no loopback inside chip
+
+	// set highest and lowest FC-PH version the adapter/driver supports
+	// (NOT strict compliance)
+	cpqfcHBAdata->fcChip.highest_FCPH_ver = FC_PH3;
+	cpqfcHBAdata->fcChip.lowest_FCPH_ver = FC_PH43;
+
+	// set function points for this controller / adapter
+	cpqfcHBAdata->fcChip.ResetTachyon = CpqTsResetTachLite;
+	cpqfcHBAdata->fcChip.FreezeTachyon = CpqTsFreezeTachlite;
+	cpqfcHBAdata->fcChip.UnFreezeTachyon = CpqTsUnFreezeTachlite;
+	cpqfcHBAdata->fcChip.CreateTachyonQues = CpqTsCreateTachLiteQues;
+	cpqfcHBAdata->fcChip.DestroyTachyonQues = CpqTsDestroyTachLiteQues;
+	cpqfcHBAdata->fcChip.InitializeTachyon = CpqTsInitializeTachLite;
+	cpqfcHBAdata->fcChip.LaserControl = CpqTsLaserControl;
+	cpqfcHBAdata->fcChip.ProcessIMQEntry = CpqTsProcessIMQEntry;
+	cpqfcHBAdata->fcChip.InitializeFrameManager = CpqTsInitializeFrameManager;;
+	cpqfcHBAdata->fcChip.ReadWriteWWN = CpqTsReadWriteWWN;
+	cpqfcHBAdata->fcChip.ReadWriteNVRAM = CpqTsReadWriteNVRAM;
+
 
- 
 
 }
 
@@ -233,28 +169,27 @@
 /* (borrowed from linux/drivers/scsi/hosts.c) */
 static void launch_FCworker_thread(struct Scsi_Host *HostAdapter)
 {
-  DECLARE_MUTEX_LOCKED(sem);
+	DECLARE_MUTEX_LOCKED(sem);
+
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
+
+	ENTER("launch_FC_worker_thread");
 
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
+	cpqfcHBAdata->notify_wt = &sem;
 
-  ENTER("launch_FC_worker_thread");
-             
-  cpqfcHBAdata->notify_wt = &sem;
-
-  /* must unlock before kernel_thread(), for it may cause a reschedule. */
-  spin_unlock_irq(&io_request_lock);
-  kernel_thread((int (*)(void *))cpqfcTSWorkerThread, 
-                          (void *) HostAdapter, 0);
-  /*
-   * Now wait for the kernel error thread to initialize itself
-
-   */
-  down (&sem);
-  spin_lock_irq(&io_request_lock);
-  cpqfcHBAdata->notify_wt = NULL;
+	/* must unlock before kernel_thread(), for it may cause a reschedule. */
+	spin_unlock_irq(&io_request_lock);
+	kernel_thread((int (*)(void *)) cpqfcTSWorkerThread, (void *) HostAdapter, 0);
+	/*
+	 * Now wait for the kernel error thread to initialize itself
+
+	 */
+	down(&sem);
+	spin_lock_irq(&io_request_lock);
+	cpqfcHBAdata->notify_wt = NULL;
+
+	LEAVE("launch_FC_worker_thread");
 
-  LEAVE("launch_FC_worker_thread");
- 
 }
 
 
@@ -279,436 +214,391 @@
 };
 
 
-int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
+int cpqfcTS_detect(Scsi_Host_Template * ScsiHostTemplate)
 {
-  int NumberOfAdapters=0; // how many of our PCI adapters are found?
-  struct pci_dev *PciDev = NULL;
-  struct Scsi_Host *HostAdapter = NULL;
-  CPQFCHBA *cpqfcHBAdata = NULL; 
-  struct timer_list *cpqfcTStimer = NULL;
-  int i;
+	int NumberOfAdapters = 0;	// how many of our PCI adapters are found?
+	struct pci_dev *PciDev = NULL;
+	struct Scsi_Host *HostAdapter = NULL;
+	CPQFCHBA *cpqfcHBAdata = NULL;
+	struct timer_list *cpqfcTStimer = NULL;
+	int i;
 
-  ENTER("cpqfcTS_detect");
+	ENTER("cpqfcTS_detect");
 
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
-  ScsiHostTemplate->proc_dir = &proc_scsi_cpqfcTS;
+	ScsiHostTemplate->proc_dir = &proc_scsi_cpqfcTS;
 #else
-  ScsiHostTemplate->proc_name = "cpqfcTS";
+	ScsiHostTemplate->proc_name = "cpqfcTS";
 #endif
 
-  if( pci_present() == 0) // no PCI busses?
-  {
-    printk( "  no PCI bus?@#!\n");
-    return NumberOfAdapters;
-  }
-
-  for( i=0; i < HBA_TYPES; i++)
-  {
-    // look for all HBAs of each type
-
-    while((PciDev = pci_find_device(cpqfc_boards[i].vendor_id,
-				    cpqfc_boards[i].device_id, PciDev)))
-    {
-
-      if (pci_set_dma_mask(PciDev, CPQFCTS_DMA_MASK) != 0) {
-	printk(KERN_WARNING 
-		"cpqfc: HBA cannot support required DMA mask, skipping.\n");
-	continue;
-      }
-
-      // NOTE: (kernel 2.2.12-32) limits allocation to 128k bytes...
-      printk(" scsi_register allocating %d bytes for FC HBA\n",
-		      (ULONG)sizeof(CPQFCHBA));
-
-      HostAdapter = scsi_register( ScsiHostTemplate, sizeof( CPQFCHBA ) );
-      
-      if(HostAdapter == NULL)
-      	continue;
-      DEBUG_PCI( printk("  HBA found!\n"));
-      DEBUG_PCI( printk("  HostAdapter->PciDev->irq = %u\n", PciDev->irq) );
-      DEBUG_PCI(printk("  PciDev->baseaddress[0]= %lx\n", 
-				PciDev->resource[0].start));
-      DEBUG_PCI(printk("  PciDev->baseaddress[1]= %lx\n", 
-				PciDev->resource[1].start));
-      DEBUG_PCI(printk("  PciDev->baseaddress[2]= %lx\n", 
-				PciDev->resource[2].start));
-      DEBUG_PCI(printk("  PciDev->baseaddress[3]= %lx\n", 
-				PciDev->resource[3].start));
-
-      scsi_set_pci_device(HostAdapter, PciDev);      
-      HostAdapter->irq = PciDev->irq;  // copy for Scsi layers
-      
-      // HP Tachlite uses two (255-byte) ranges of Port I/O (lower & upper),
-      // for a total I/O port address space of 512 bytes.
-      // mask out the I/O port address (lower) & record
-      HostAdapter->io_port = (unsigned int)
-	     PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
-      HostAdapter->n_io_port = 0xff;
-      
-      // i.e., expect 128 targets (arbitrary number), while the
-      //  RA-4000 supports 32 LUNs
-      HostAdapter->max_id =  0;   // incremented as devices log in    
-      HostAdapter->max_lun = CPQFCTS_MAX_LUN;         // LUNs per FC device
-      HostAdapter->max_channel = CPQFCTS_MAX_CHANNEL; // multiple busses?
-      
-      // get the pointer to our HBA specific data... (one for
-      // each HBA on the PCI bus(ses)).
-      cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-      
-      // make certain our data struct is clear
-      memset( cpqfcHBAdata, 0, sizeof( CPQFCHBA ) );
-
-
-      // initialize our HBA info
-      cpqfcHBAdata->HBAnum = NumberOfAdapters;
-
-      cpqfcHBAdata->HostAdapter = HostAdapter; // back ptr
-      Cpqfc_initHBAdata( cpqfcHBAdata, PciDev ); // fill MOST fields
-     
-      cpqfcHBAdata->HBAnum = NumberOfAdapters;
-      cpqfcHBAdata->hba_spinlock = SPIN_LOCK_UNLOCKED;
-
-      // request necessary resources and check for conflicts
-      if( request_irq( HostAdapter->irq,
-		       cpqfcTS_intr_handler,
-	               SA_INTERRUPT | SA_SHIRQ,
-	               DEV_NAME,
-		       HostAdapter) )
-      {
-	printk(" IRQ %u already used\n", HostAdapter->irq);
-        scsi_unregister( HostAdapter);
-	continue;
-      }
-
-      // Since we have two 256-byte I/O port ranges (upper
-      // and lower), check them both
-      if( check_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff) )
-      {
-	printk("  cpqfcTS address in use: %x\n", 
-			cpqfcHBAdata->fcChip.Registers.IOBaseU);
-	free_irq( HostAdapter->irq, HostAdapter);
-        scsi_unregister( HostAdapter);
-	continue;
-      }	
-      
-      if( check_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff) )
-      {
-  	printk("  cpqfcTS address in use: %x\n", 
-	      			cpqfcHBAdata->fcChip.Registers.IOBaseL);
-	free_irq( HostAdapter->irq, HostAdapter);
-        scsi_unregister( HostAdapter);
-	continue;
-      }	
-      
-      // OK, we should be able to grab everything we need now.
-      request_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff, DEV_NAME);
-      request_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff, DEV_NAME);
-      DEBUG_PCI(printk("  Requesting 255 I/O addresses @ %x\n",
-        cpqfcHBAdata->fcChip.Registers.IOBaseL ));
-      DEBUG_PCI(printk("  Requesting 255 I/O addresses @ %x\n",
-        cpqfcHBAdata->fcChip.Registers.IOBaseU ));
-
-      
-      // start our kernel worker thread
-
-      launch_FCworker_thread(HostAdapter);
-
-
-      // start our TimerTask...
-
-      cpqfcTStimer = &cpqfcHBAdata->cpqfcTStimer;
-
-      init_timer( cpqfcTStimer); // Linux clears next/prev values
-      cpqfcTStimer->expires = jiffies + HZ; // one second
-      cpqfcTStimer->data = (unsigned long)cpqfcHBAdata; // this adapter
-      cpqfcTStimer->function = cpqfcTSheartbeat; // handles timeouts, housekeeping
-
-      add_timer( cpqfcTStimer);  // give it to Linux
-
-
-      // now initialize our hardware...
-      if (cpqfcHBAdata->fcChip.InitializeTachyon( cpqfcHBAdata, 1,1)) {
-	printk(KERN_WARNING "cpqfc: initialization of HBA hardware failed.\n");
-	// FIXME: might want to do something better than nothing here.
-      }
-
-      cpqfcHBAdata->fcStatsTime = jiffies;  // (for FC Statistics delta)
-      
-      // give our HBA time to initialize and login current devices...
-      {
-	// The Brocade switch (e.g. 2400, 2010, etc.) as of March 2000,
-	// has the following algorithm for FL_Port startup:
-	// Time(sec) Action
-	// 0:        Device Plugin and LIP(F7,F7) transmission
-	// 1.0       LIP incoming
-        // 1.027     LISA incoming, no CLS! (link not up)
-	// 1.028     NOS incoming (switch test for N_Port)
-        // 1.577     ED_TOV expired, transmit LIPs again	
-	// 3.0       LIP(F8,F7) incoming (switch passes Tach Prim.Sig)
-	// 3.028     LILP received, link up, FLOGI starts
-	// slowest(worst) case, measured on 1Gb Finisar GT analyzer
-	
-	unsigned long stop_time;
-
-        spin_unlock_irq(&io_request_lock);
-	stop_time = jiffies + 4*HZ;
-        while ( time_before(jiffies, stop_time) ) 
-	  	schedule();  // (our worker task needs to run)
+	if (pci_present() == 0)	// no PCI busses?
+	{
+		printk("  no PCI bus?@#!\n");
+		return NumberOfAdapters;
+	}
 
-	spin_lock_irq(&io_request_lock);
-      }
-      
-      NumberOfAdapters++; 
-    } // end of while()
-  }
-
-  LEAVE("cpqfcTS_detect");
- 
-  return NumberOfAdapters;
-}
-
-static void my_ioctl_done (Scsi_Cmnd * SCpnt)
-{
-    struct request * req;
-    
-    req = &SCpnt->request;
-    req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */
-  
-    if (req->CPQFC_WAITING != NULL)
-	CPQFC_COMPLETE(req->CPQFC_WAITING);
-}   
-
-
-
-int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg)
-{
-  int result = 0;
-  struct Scsi_Host *HostAdapter = ScsiDev->host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  PFC_LOGGEDIN_PORT pLoggedInPort;
-  Scsi_Cmnd DumCmnd;
-  int i, j;
-  VENDOR_IOCTL_REQ ioc;
-  cpqfc_passthru_t *vendor_cmd;
-  Scsi_Device *SDpnt;
-  Scsi_Cmnd *ScsiPassThruCmnd;
-
-  ENTER("cpqfcTS_ioctl ");
-  
-  // can we find an FC device mapping to this SCSI target?
-  DumCmnd.channel = ScsiDev->channel;		// For searching
-  DumCmnd.target  = ScsiDev->id;
-  pLoggedInPort = fcFindLoggedInPort( fcChip,
-    &DumCmnd, // search Scsi Nexus
-    0,        // DON'T search linked list for FC port id
-    NULL,     // DON'T search linked list for FC WWN
-    NULL);    // DON'T care about end of list
- 
-  if( pLoggedInPort == NULL )      // not found!
-  {
-    result = -ENXIO;
-  }
- 
-  else  // we know what FC device to operate on...
-  {
-	// printk("ioctl CMND %d", Cmnd);
-    switch (Cmnd) 
-    {
-      // Passthrough provides a mechanism to bypass the RAID
-      // or other controller and talk directly to the devices
-      // (e.g. physical disk drive)
-      // Passthrough commands, unfortunately, tend to be vendor
-      // specific; this is tailored to COMPAQ's RAID (RA4x00)
-      case CPQFCTS_SCSI_PASSTHRU:
-      {
-	void *buf = NULL; // for kernel space buffer for user data
-	
-	if( !arg)
-	  return -EINVAL;
-
-	// must be super user to send stuff directly to the
-	// controller and/or physical drives...
-	if( !suser() )
-	  return -EPERM;
-
-	// copy the caller's struct to our space.
-        if( copy_from_user( &ioc, arg, sizeof( VENDOR_IOCTL_REQ)))
-		return( -EFAULT);
+	for (i = 0; i < HBA_TYPES; i++) {
+		// look for all HBAs of each type
 
-	vendor_cmd = ioc.argp;  // i.e., CPQ specific command struct
+		while ((PciDev = pci_find_device(cpqfc_boards[i].vendor_id, cpqfc_boards[i].device_id, PciDev))) {
 
-	// If necessary, grab a kernel/DMA buffer
-	if( vendor_cmd->len)
-	{
-  	  buf = kmalloc( vendor_cmd->len, GFP_KERNEL);
-	  if( !buf)
-	    return -ENOMEM;
-	}
-
-        // Now build a SCSI_CMND to pass down...
-	// This function allocates and sets Scsi_Cmnd ptrs such as
-	//  ->channel, ->target, ->host
-        ScsiPassThruCmnd = scsi_allocate_device(ScsiDev, 1, 1);
-
-        // Need data from user?
-	// make sure caller's buffer is in kernel space.
-	if( (vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) &&
-	    vendor_cmd->len)
-        if(  copy_from_user( buf, vendor_cmd->bufp, vendor_cmd->len))
-		return( -EFAULT);
-	    
-	// copy the CDB (if/when MAX_COMMAND_SIZE is 16, remove copy below)
-        memcpy( &ScsiPassThruCmnd->cmnd[0], 
-		&vendor_cmd->cdb[0], 
-		MAX_COMMAND_SIZE);  
-        // we want to copy all 16 bytes into the FCP-SCSI CDB,
-	// although the actual passthru only uses up to the
-	// first 12.
-	
-	ScsiPassThruCmnd->cmd_len = 16; // sizeof FCP-SCSI CDB
-
-	// Unfortunately, the SCSI command cmnd[] field has only
-	// 12 bytes.  Ideally the MAX_COMMAND_SIZE should be increased
-	// to 16 for newer Fibre Channel and SCSI-3 larger CDBs.
-	// However, to avoid a mandatory kernel rebuild, we use the SCp
-	// spare field to store the extra 4 bytes ( ugly :-(
+			if (pci_set_dma_mask(PciDev, CPQFCTS_DMA_MASK) != 0) {
+				printk(KERN_WARNING "cpqfc: HBA cannot support required DMA mask, skipping.\n");
+				continue;
+			}
+			// NOTE: (kernel 2.2.12-32) limits allocation to 128k bytes...
+			printk(" scsi_register allocating %d bytes for FC HBA\n", (u32) sizeof(CPQFCHBA));
+
+			HostAdapter = scsi_register(ScsiHostTemplate, sizeof(CPQFCHBA));
+
+			if (HostAdapter == NULL)
+				continue;
+			DEBUG_PCI(printk("  HBA found!\n"));
+			DEBUG_PCI(printk("  HostAdapter->PciDev->irq = %u\n", PciDev->irq));
+			DEBUG_PCI(printk("  PciDev->baseaddress[0]= %lx\n", PciDev->resource[0].start));
+			DEBUG_PCI(printk("  PciDev->baseaddress[1]= %lx\n", PciDev->resource[1].start));
+			DEBUG_PCI(printk("  PciDev->baseaddress[2]= %lx\n", PciDev->resource[2].start));
+			DEBUG_PCI(printk("  PciDev->baseaddress[3]= %lx\n", PciDev->resource[3].start));
+
+			scsi_set_pci_device(HostAdapter, PciDev);
+			HostAdapter->irq = PciDev->irq;	// copy for Scsi layers
+
+			// HP Tachlite uses two (255-byte) ranges of Port I/O (lower & upper),
+			// for a total I/O port address space of 512 bytes.
+			// mask out the I/O port address (lower) & record
+			HostAdapter->io_port = (unsigned int)
+			    PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
+			HostAdapter->n_io_port = 0xff;
+
+			// i.e., expect 128 targets (arbitrary number), while the
+			//  RA-4000 supports 32 LUNs
+			HostAdapter->max_id = 0;	// incremented as devices log in    
+			HostAdapter->max_lun = CPQFCTS_MAX_LUN;	// LUNs per FC device
+			HostAdapter->max_channel = CPQFCTS_MAX_CHANNEL;	// multiple busses?
+
+			// get the pointer to our HBA specific data... (one for
+			// each HBA on the PCI bus(ses)).
+			cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
+
+			// make certain our data struct is clear
+			memset(cpqfcHBAdata, 0, sizeof(CPQFCHBA));
+
+
+			// initialize our HBA info
+			cpqfcHBAdata->HBAnum = NumberOfAdapters;
+
+			cpqfcHBAdata->HostAdapter = HostAdapter;	// back ptr
+			Cpqfc_initHBAdata(cpqfcHBAdata, PciDev);	// fill MOST fields
+
+			cpqfcHBAdata->HBAnum = NumberOfAdapters;
+			cpqfcHBAdata->hba_spinlock = SPIN_LOCK_UNLOCKED;
+
+			// request necessary resources and check for conflicts
+			if (request_irq(HostAdapter->irq, cpqfcTS_intr_handler, SA_INTERRUPT | SA_SHIRQ, DEV_NAME, HostAdapter)) {
+				printk(" IRQ %u already used\n", HostAdapter->irq);
+				scsi_unregister(HostAdapter);
+				continue;
+			}
+			// Since we have two 256-byte I/O port ranges (upper
+			// and lower), check them both
+			if (check_region(cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff)) {
+				printk("  cpqfcTS address in use: %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseU);
+				free_irq(HostAdapter->irq, HostAdapter);
+				scsi_unregister(HostAdapter);
+				continue;
+			}
+
+			if (check_region(cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff)) {
+				printk("  cpqfcTS address in use: %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseL);
+				free_irq(HostAdapter->irq, HostAdapter);
+				scsi_unregister(HostAdapter);
+				continue;
+			}
+			// OK, we should be able to grab everything we need now.
+			request_region(cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff, DEV_NAME);
+			request_region(cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff, DEV_NAME);
+			DEBUG_PCI(printk("  Requesting 255 I/O addresses @ %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseL));
+			DEBUG_PCI(printk("  Requesting 255 I/O addresses @ %x\n", cpqfcHBAdata->fcChip.Registers.IOBaseU));
+
+
+			// start our kernel worker thread
+
+			launch_FCworker_thread(HostAdapter);
+
+
+			// start our TimerTask...
+
+			cpqfcTStimer = &cpqfcHBAdata->cpqfcTStimer;
+
+			init_timer(cpqfcTStimer);	// Linux clears next/prev values
+			cpqfcTStimer->expires = jiffies + HZ;	// one second
+			cpqfcTStimer->data = (unsigned long) cpqfcHBAdata;	// this adapter
+			cpqfcTStimer->function = cpqfcTSheartbeat;	// handles timeouts, housekeeping
+
+			add_timer(cpqfcTStimer);	// give it to Linux
+
+
+			// now initialize our hardware...
+			if (cpqfcHBAdata->fcChip.InitializeTachyon(cpqfcHBAdata, 1, 1)) {
+				printk(KERN_WARNING "cpqfc: initialization of HBA hardware failed.\n");
+				// FIXME: might want to do something better than nothing here.
+			}
+
+			cpqfcHBAdata->fcStatsTime = jiffies;	// (for FC Statistics delta)
+
+			// give our HBA time to initialize and login current devices...
+			{
+				// The Brocade switch (e.g. 2400, 2010, etc.) as of March 2000,
+				// has the following algorithm for FL_Port startup:
+				// Time(sec) Action
+				// 0:        Device Plugin and LIP(F7,F7) transmission
+				// 1.0       LIP incoming
+				// 1.027     LISA incoming, no CLS! (link not up)
+				// 1.028     NOS incoming (switch test for N_Port)
+				// 1.577     ED_TOV expired, transmit LIPs again        
+				// 3.0       LIP(F8,F7) incoming (switch passes Tach Prim.Sig)
+				// 3.028     LILP received, link up, FLOGI starts
+				// slowest(worst) case, measured on 1Gb Finisar GT analyzer
+
+				unsigned long stop_time;
+
+				spin_unlock_irq(&io_request_lock);
+				stop_time = jiffies + 4 * HZ;
+				while (time_before(jiffies, stop_time))
+					schedule();	// (our worker task needs to run)
 
-	if( MAX_COMMAND_SIZE < 16)
+				spin_lock_irq(&io_request_lock);
+			}
+
+			NumberOfAdapters++;
+		}		// end of while()
+	}
+
+	LEAVE("cpqfcTS_detect");
+
+	return NumberOfAdapters;
+}
+
+static void my_ioctl_done(Scsi_Cmnd * SCpnt)
+{
+	struct request *req;
+
+	req = &SCpnt->request;
+	req->rq_status = RQ_SCSI_DONE;	/* Busy, but indicate request done */
+
+	if (req->CPQFC_WAITING != NULL)
+		CPQFC_COMPLETE(req->CPQFC_WAITING);
+}
+
+
+
+int cpqfcTS_ioctl(Scsi_Device * ScsiDev, int Cmnd, void *arg)
+{
+	int result = 0;
+	struct Scsi_Host *HostAdapter = ScsiDev->host;
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	PFC_LOGGEDIN_PORT pLoggedInPort;
+	Scsi_Cmnd DumCmnd;
+	int i, j;
+	VENDOR_IOCTL_REQ ioc;
+	cpqfc_passthru_t *vendor_cmd;
+	Scsi_Device *SDpnt;
+	Scsi_Cmnd *ScsiPassThruCmnd;
+
+	ENTER("cpqfcTS_ioctl ");
+
+	// can we find an FC device mapping to this SCSI target?
+	DumCmnd.channel = ScsiDev->channel;	// For searching
+	DumCmnd.target = ScsiDev->id;
+	pLoggedInPort = fcFindLoggedInPort(fcChip, &DumCmnd,	// search Scsi Nexus
+					   0,	// DON'T search linked list for FC port id
+					   NULL,	// DON'T search linked list for FC WWN
+					   NULL);	// DON'T care about end of list
+
+	if (pLoggedInPort == NULL)	// not found!
 	{
-          memcpy( &ScsiPassThruCmnd->SCp.buffers_residual,
-		  &vendor_cmd->cdb[12], 4);
-	}	  
-                  
-	
-        ScsiPassThruCmnd->SCp.sent_command = 1; // PASSTHRU!
-	                                        // suppress LUN masking
-	                                        // and VSA logic
-
-	// Use spare fields to copy FCP-SCSI LUN address info...
-        ScsiPassThruCmnd->SCp.phase = vendor_cmd->bus;
-	ScsiPassThruCmnd->SCp.have_data_in = vendor_cmd->pdrive;
-
-        // We copy the scheme used by scsi.c to submit commands
-	// to our own HBA.  We do this in order to stall the
-	// thread calling the IOCTL until it completes, and use
-	// the same "_quecommand" function for synchronizing
-	// FC Link events with our "worker thread".
-
-        {
-          CPQFC_DECLARE_COMPLETION(wait);
-          ScsiPassThruCmnd->request.CPQFC_WAITING = &wait;
-          // eventually gets us to our own _quecommand routine
-          scsi_do_cmd( ScsiPassThruCmnd, &vendor_cmd->cdb[0], 
-	       buf, 
-	       vendor_cmd->len, 
-	       my_ioctl_done, 
-	       10*HZ, 1);// timeout,retries
-          // Other I/Os can now resume; we wait for our ioctl
-	  // command to complete
-	  CPQFC_WAIT_FOR_COMPLETION(&wait);
-          ScsiPassThruCmnd->request.CPQFC_WAITING = NULL;
-        }
-	
-        result = ScsiPassThruCmnd->result;
+		result = -ENXIO;
+	}
 
-        // copy any sense data back to caller
-        if( result != 0 )
+	else			// we know what FC device to operate on...
 	{
-	  memcpy( vendor_cmd->sense_data, // see struct def - size=40
-		  ScsiPassThruCmnd->sense_buffer, 
-		  sizeof(ScsiPassThruCmnd->sense_buffer)); 
-	}
-        SDpnt = ScsiPassThruCmnd->device;
-        scsi_release_command(ScsiPassThruCmnd); // "de-allocate"
-        ScsiPassThruCmnd = NULL;
-
-        // if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
-        //  (*SDpnt->scsi_request_fn)();
-
-        wake_up(&SDpnt->scpnt_wait);
-
-	// need to pass data back to user (space)?
-	if( (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) &&
-	     vendor_cmd->len )
-        if(  copy_to_user( vendor_cmd->bufp, buf, vendor_cmd->len))
-		return( -EFAULT);
-
-        if( buf) 
-	  kfree( buf);
-
-        return result;
-      }
-      
-      case CPQFCTS_GETPCIINFO:
-      {
-	cpqfc_pci_info_struct pciinfo;
-	
-	if( !arg)
-	  return -EINVAL;
-
-         	
-	
-        pciinfo.bus = cpqfcHBAdata->PciDev->bus->number;
-        pciinfo.dev_fn = cpqfcHBAdata->PciDev->devfn;  
-	pciinfo.board_id = cpqfcHBAdata->PciDev->device |
-			  (cpqfcHBAdata->PciDev->vendor <<16); 
-	      
-        if(copy_to_user( arg, &pciinfo, sizeof(cpqfc_pci_info_struct)))
-		return( -EFAULT);
-        return 0;
-      }
-
-      case CPQFCTS_GETDRIVVER:
-      {
-	DriverVer_type DriverVer = 
-		CPQFCTS_DRIVER_VER( VER_MAJOR,VER_MINOR,VER_SUBMINOR);
-	
-	if( !arg)
-	  return -EINVAL;
-
-        if(copy_to_user( arg, &DriverVer, sizeof(DriverVer)))
-		return( -EFAULT);
-        return 0;
-      }
-
-
-
-      case CPQFC_IOCTL_FC_TARGET_ADDRESS:
-      result = 
-        verify_area(VERIFY_WRITE, arg, sizeof(Scsi_FCTargAddress));
-      if (result) 
-	break;
- 
-      put_user(pLoggedInPort->port_id,
-		&((Scsi_FCTargAddress *) arg)->host_port_id);
- 
-      for( i=3,j=0; i>=0; i--)   	// copy the LOGIN port's WWN
-        put_user(pLoggedInPort->u.ucWWN[i], 
-		&((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
-      for( i=7; i>3; i--)		// copy the LOGIN port's WWN
-        put_user(pLoggedInPort->u.ucWWN[i], 
-		&((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
-        break;
-
-
-      case CPQFC_IOCTL_FC_TDR:
-          
-        result = cpqfcTS_TargetDeviceReset( ScsiDev, 0);
-
-        break;
-
-
-
-
-    default:
-      result = -EINVAL;
-      break;
-    }
-  }
+		// printk("ioctl CMND %d", Cmnd);
+		switch (Cmnd) {
+			// Passthrough provides a mechanism to bypass the RAID
+			// or other controller and talk directly to the devices
+			// (e.g. physical disk drive)
+			// Passthrough commands, unfortunately, tend to be vendor
+			// specific; this is tailored to COMPAQ's RAID (RA4x00)
+		case CPQFCTS_SCSI_PASSTHRU:
+			{
+				void *buf = NULL;	// for kernel space buffer for user data
+
+				if (!arg)
+					return -EINVAL;
+
+				// must be super user to send stuff directly to the
+				// controller and/or physical drives...
+				if (!suser())
+					return -EPERM;
+
+				// copy the caller's struct to our space.
+				if (copy_from_user(&ioc, arg, sizeof(VENDOR_IOCTL_REQ)))
+					return (-EFAULT);
+
+				vendor_cmd = ioc.argp;	// i.e., CPQ specific command struct
+
+				// If necessary, grab a kernel/DMA buffer
+				if (vendor_cmd->len) {
+					buf = kmalloc(vendor_cmd->len, GFP_KERNEL);
+					if (!buf)
+						return -ENOMEM;
+				}
+				// Now build a SCSI_CMND to pass down...
+				// This function allocates and sets Scsi_Cmnd ptrs such as
+				//  ->channel, ->target, ->host
+				ScsiPassThruCmnd = scsi_allocate_device(ScsiDev, 1, 1);
+
+				// Need data from user?
+				// make sure caller's buffer is in kernel space.
+				if ((vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) && vendor_cmd->len)
+					if (copy_from_user(buf, vendor_cmd->bufp, vendor_cmd->len))
+						return (-EFAULT);
+
+				// copy the CDB (if/when MAX_COMMAND_SIZE is 16, remove copy below)
+				memcpy(&ScsiPassThruCmnd->cmnd[0], &vendor_cmd->cdb[0], MAX_COMMAND_SIZE);
+				// we want to copy all 16 bytes into the FCP-SCSI CDB,
+				// although the actual passthru only uses up to the
+				// first 12.
+
+				ScsiPassThruCmnd->cmd_len = 16;	// sizeof FCP-SCSI CDB
+
+				// Unfortunately, the SCSI command cmnd[] field has only
+				// 12 bytes.  Ideally the MAX_COMMAND_SIZE should be increased
+				// to 16 for newer Fibre Channel and SCSI-3 larger CDBs.
+				// However, to avoid a mandatory kernel rebuild, we use the SCp
+				// spare field to store the extra 4 bytes ( ugly :-(
+
+				if (MAX_COMMAND_SIZE < 16) {
+					memcpy(&ScsiPassThruCmnd->SCp.buffers_residual, &vendor_cmd->cdb[12], 4);
+				}
+
+
+				ScsiPassThruCmnd->SCp.sent_command = 1;	// PASSTHRU!
+				// suppress LUN masking
+				// and VSA logic
+
+				// Use spare fields to copy FCP-SCSI LUN address info...
+				ScsiPassThruCmnd->SCp.phase = vendor_cmd->bus;
+				ScsiPassThruCmnd->SCp.have_data_in = vendor_cmd->pdrive;
+
+				// We copy the scheme used by scsi.c to submit commands
+				// to our own HBA.  We do this in order to stall the
+				// thread calling the IOCTL until it completes, and use
+				// the same "_quecommand" function for synchronizing
+				// FC Link events with our "worker thread".
+
+				{
+					CPQFC_DECLARE_COMPLETION(wait);
+					ScsiPassThruCmnd->request.CPQFC_WAITING = &wait;
+					// eventually gets us to our own _quecommand routine
+					scsi_do_cmd(ScsiPassThruCmnd, &vendor_cmd->cdb[0], buf, vendor_cmd->len, my_ioctl_done, 10 * HZ, 1);	// timeout,retries
+					// Other I/Os can now resume; we wait for our ioctl
+					// command to complete
+					CPQFC_WAIT_FOR_COMPLETION(&wait);
+					ScsiPassThruCmnd->request.CPQFC_WAITING = NULL;
+				}
+
+				result = ScsiPassThruCmnd->result;
+
+				// copy any sense data back to caller
+				if (result != 0) {
+					memcpy(vendor_cmd->sense_data,	// see struct def - size=40
+					       ScsiPassThruCmnd->sense_buffer, sizeof(ScsiPassThruCmnd->sense_buffer));
+				}
+				SDpnt = ScsiPassThruCmnd->device;
+				scsi_release_command(ScsiPassThruCmnd);	// "de-allocate"
+				ScsiPassThruCmnd = NULL;
+
+				// if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
+				//  (*SDpnt->scsi_request_fn)();
 
-  LEAVE("cpqfcTS_ioctl");
-  return result;
+				wake_up(&SDpnt->scpnt_wait);
+
+				// need to pass data back to user (space)?
+				if ((vendor_cmd->rw_flag == VENDOR_READ_OPCODE) && vendor_cmd->len)
+					if (copy_to_user(vendor_cmd->bufp, buf, vendor_cmd->len))
+						return (-EFAULT);
+
+				if (buf)
+					kfree(buf);
+
+				return result;
+			}
+
+		case CPQFCTS_GETPCIINFO:
+			{
+				cpqfc_pci_info_struct pciinfo;
+
+				if (!arg)
+					return -EINVAL;
+
+
+
+				pciinfo.bus = cpqfcHBAdata->PciDev->bus->number;
+				pciinfo.dev_fn = cpqfcHBAdata->PciDev->devfn;
+				pciinfo.board_id = cpqfcHBAdata->PciDev->device | (cpqfcHBAdata->PciDev->vendor << 16);
+
+				if (copy_to_user(arg, &pciinfo, sizeof(cpqfc_pci_info_struct)))
+					return (-EFAULT);
+				return 0;
+			}
+
+		case CPQFCTS_GETDRIVVER:
+			{
+				DriverVer_type DriverVer = CPQFCTS_DRIVER_VER(VER_MAJOR, VER_MINOR, VER_SUBMINOR);
+
+				if (!arg)
+					return -EINVAL;
+
+				if (copy_to_user(arg, &DriverVer, sizeof(DriverVer)))
+					return (-EFAULT);
+				return 0;
+			}
+
+
+
+		case CPQFC_IOCTL_FC_TARGET_ADDRESS:
+			result = verify_area(VERIFY_WRITE, arg, sizeof(Scsi_FCTargAddress));
+			if (result)
+				break;
+
+			put_user(pLoggedInPort->port_id, &((Scsi_FCTargAddress *) arg)->host_port_id);
+
+			for (i = 3, j = 0; i >= 0; i--)	// copy the LOGIN port's WWN
+				put_user(pLoggedInPort->u.ucWWN[i], &((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
+			for (i = 7; i > 3; i--)	// copy the LOGIN port's WWN
+				put_user(pLoggedInPort->u.ucWWN[i], &((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
+			break;
+
+
+		case CPQFC_IOCTL_FC_TDR:
+
+			result = cpqfcTS_TargetDeviceReset(ScsiDev, 0);
+
+			break;
+
+
+
+
+		default:
+			result = -EINVAL;
+			break;
+		}
+	}
+
+	LEAVE("cpqfcTS_ioctl");
+	return result;
 }
 
 
@@ -718,84 +608,73 @@
 
 int cpqfcTS_release(struct Scsi_Host *HostAdapter)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; 
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
 
 
-  ENTER("cpqfcTS_release");
-	
-  DEBUG_PCI( printk(" cpqfcTS: delete timer...\n"));
-  del_timer( &cpqfcHBAdata->cpqfcTStimer);  
-    
-  // disable the hardware...
-  DEBUG_PCI( printk(" disable hardware, destroy queues, free mem\n"));
-  cpqfcHBAdata->fcChip.ResetTachyon( cpqfcHBAdata, CLEAR_FCPORTS);
-
-  // kill kernel thread
-  if( cpqfcHBAdata->worker_thread ) // (only if exists)
-  {
-    DECLARE_MUTEX_LOCKED(sem);  // synchronize thread kill
-
-    cpqfcHBAdata->notify_wt = &sem;
-    DEBUG_PCI( printk(" killing kernel thread\n"));
-    send_sig( SIGKILL, cpqfcHBAdata->worker_thread, 1);
-    down( &sem);
-    cpqfcHBAdata->notify_wt = NULL;
-    
-  }
-
-  // free Linux resources
-  DEBUG_PCI( printk(" cpqfcTS: freeing resources...\n"));
-  free_irq( HostAdapter->irq, HostAdapter);
-  scsi_unregister( HostAdapter);
-  release_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff);
-  release_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff);
- /* we get "vfree: bad address" executing this - need to investigate... 
-  if( (void*)((unsigned long)cpqfcHBAdata->fcChip.Registers.MemBase) !=
-      cpqfcHBAdata->fcChip.Registers.ReMapMemBase)
-    vfree( cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
-*/
+	ENTER("cpqfcTS_release");
+
+	DEBUG_PCI(printk(" cpqfcTS: delete timer...\n"));
+	del_timer(&cpqfcHBAdata->cpqfcTStimer);
 
-  LEAVE("cpqfcTS_release");
-  return 0;
+	// disable the hardware...
+	DEBUG_PCI(printk(" disable hardware, destroy queues, free mem\n"));
+	cpqfcHBAdata->fcChip.ResetTachyon(cpqfcHBAdata, CLEAR_FCPORTS);
+
+	// kill kernel thread
+	if (cpqfcHBAdata->worker_thread)	// (only if exists)
+	{
+		DECLARE_MUTEX_LOCKED(sem);	// synchronize thread kill
+
+		cpqfcHBAdata->notify_wt = &sem;
+		DEBUG_PCI(printk(" killing kernel thread\n"));
+		send_sig(SIGKILL, cpqfcHBAdata->worker_thread, 1);
+		down(&sem);
+		cpqfcHBAdata->notify_wt = NULL;
+
+	}
+	// free Linux resources
+	DEBUG_PCI(printk(" cpqfcTS: freeing resources...\n"));
+	free_irq(HostAdapter->irq, HostAdapter);
+	scsi_unregister(HostAdapter);
+	release_region(cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff);
+	release_region(cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff);
+	/* we get "vfree: bad address" executing this - need to investigate... 
+	   if( (void*)((unsigned long)cpqfcHBAdata->fcChip.Registers.MemBase) !=
+	   cpqfcHBAdata->fcChip.Registers.ReMapMemBase)
+	   vfree( cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
+	 */
+
+	LEAVE("cpqfcTS_release");
+	return 0;
 }
 
 
-const char * cpqfcTS_info(struct Scsi_Host *HostAdapter)
+const char *cpqfcTS_info(struct Scsi_Host *HostAdapter)
 {
-  static char buf[300];
-  CPQFCHBA *cpqfcHBA;
-  int BusSpeed, BusWidth;
-  
-  // get the pointer to our Scsi layer HBA buffer  
-  cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata;
-
-  BusWidth = (cpqfcHBA->fcChip.Registers.PCIMCTR &0x4) > 0 ?
-               64 : 32;
-
-  if( cpqfcHBA->fcChip.Registers.TYconfig.value & 0x80000000)
-    BusSpeed = 66;
-  else
-    BusSpeed = 33;
-
-  sprintf(buf, 
-"%s: WWN %08X%08X\n on PCI bus %d device 0x%02x irq %d IObaseL 0x%x, MEMBASE 0x%x\nPCI bus width %d bits, bus speed %d MHz\nFCP-SCSI Driver v%d.%d.%d",
-      cpqfcHBA->fcChip.Name, 
-      cpqfcHBA->fcChip.Registers.wwn_hi,
-      cpqfcHBA->fcChip.Registers.wwn_lo,
-      cpqfcHBA->PciDev->bus->number,
-      cpqfcHBA->PciDev->device,  
-      HostAdapter->irq,
-      cpqfcHBA->fcChip.Registers.IOBaseL,
-      cpqfcHBA->fcChip.Registers.MemBase,
-      BusWidth,
-      BusSpeed,
-      VER_MAJOR, VER_MINOR, VER_SUBMINOR
-);
-
-  
-  cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
-  cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
-  return buf;
+	static char buf[300];
+	CPQFCHBA *cpqfcHBA;
+	int BusSpeed, BusWidth;
+
+	// get the pointer to our Scsi layer HBA buffer  
+	cpqfcHBA = (CPQFCHBA *) HostAdapter->hostdata;
+
+	BusWidth = (cpqfcHBA->fcChip.Registers.PCIMCTR & 0x4) > 0 ? 64 : 32;
+
+	if (cpqfcHBA->fcChip.Registers.TYconfig.value & 0x80000000)
+		BusSpeed = 66;
+	else
+		BusSpeed = 33;
+
+	sprintf(buf,
+		"%s: WWN %08X%08X\n on PCI bus %d device 0x%02x irq %d IObaseL 0x%x, MEMBASE 0x%x\nPCI bus width %d bits, bus speed %d MHz\nFCP-SCSI Driver v%d.%d.%d",
+		cpqfcHBA->fcChip.Name,
+		cpqfcHBA->fcChip.Registers.wwn_hi,
+		cpqfcHBA->fcChip.Registers.wwn_lo, cpqfcHBA->PciDev->bus->number, cpqfcHBA->PciDev->device, HostAdapter->irq, cpqfcHBA->fcChip.Registers.IOBaseL, cpqfcHBA->fcChip.Registers.MemBase, BusWidth, BusSpeed, VER_MAJOR, VER_MINOR, VER_SUBMINOR);
+
+
+	cpqfcTSDecodeGBICtype(&cpqfcHBA->fcChip, &buf[strlen(buf)]);
+	cpqfcTSGetLPSM(&cpqfcHBA->fcChip, &buf[strlen(buf)]);
+	return buf;
 }
 
 //
@@ -806,178 +685,167 @@
 // programming to use it to make programming a little simpler. This piece
 // of coding is borrowed from ncr53c8xx.c with some modifications 
 //
-struct info_str
-{
-        char *buffer;			// Pointer to output buffer
-        int buflength;			// It's length
-        int bufoffset;			// File offset corresponding with buf[0]
-	int buffillen;			// Current filled length 
-        int filpos;			// Current file offset
+struct info_str {
+	char *buffer;		// Pointer to output buffer
+	int buflength;		// It's length
+	int bufoffset;		// File offset corresponding with buf[0]
+	int buffillen;		// Current filled length 
+	int filpos;		// Current file offset
 };
 
 static void copy_mem_info(struct info_str *info, char *data, int datalen)
 {
 
-  if (info->filpos < info->bufoffset) {	// Current offset before buffer offset
-    if (info->filpos + datalen <= info->bufoffset) {
-      info->filpos += datalen; 		// Discard if completely before buffer
-      return;
-    } else {				// Partial copy, set to begin
-      data += (info->bufoffset - info->filpos);
-      datalen  -= (info->bufoffset - info->filpos);
-      info->filpos = info->bufoffset;
-    }
-  }
-
-  info->filpos += datalen;		// Update current offset
+	if (info->filpos < info->bufoffset) {	// Current offset before buffer offset
+		if (info->filpos + datalen <= info->bufoffset) {
+			info->filpos += datalen;	// Discard if completely before buffer
+			return;
+		} else {	// Partial copy, set to begin
+			data += (info->bufoffset - info->filpos);
+			datalen -= (info->bufoffset - info->filpos);
+			info->filpos = info->bufoffset;
+		}
+	}
+
+	info->filpos += datalen;	// Update current offset
 
-  if (info->buffillen == info->buflength) // Buffer full, discard
-    return;
+	if (info->buffillen == info->buflength)	// Buffer full, discard
+		return;
 
-  if (info->buflength - info->buffillen < datalen)  // Overflows buffer ?
-    datalen = info->buflength - info->buffillen;
+	if (info->buflength - info->buffillen < datalen)	// Overflows buffer ?
+		datalen = info->buflength - info->buffillen;
 
-  memcpy(info->buffer + info->buffillen, data, datalen);
-  info->buffillen += datalen;
+	memcpy(info->buffer + info->buffillen, data, datalen);
+	info->buffillen += datalen;
 }
 
 static int copy_info(struct info_str *info, char *fmt, ...)
 {
-        va_list args;
-        char buf[400];
-        int len;
-
-        va_start(args, fmt);
-        len = vsprintf(buf, fmt, args);
-        va_end(args);
+	va_list args;
+	char buf[400];
+	int len;
+
+	va_start(args, fmt);
+	len = vsprintf(buf, fmt, args);
+	va_end(args);
 
-        copy_mem_info(info, buf, len);
-        return len;
+	copy_mem_info(info, buf, len);
+	return len;
 }
 
 
 // Routine to get data for /proc RAM filesystem
 //
-int cpqfcTS_proc_info (char *buffer, char **start, off_t offset, int length, 
-		       int hostno, int inout)
+int cpqfcTS_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
 {
-  struct Scsi_Host *host;
-  Scsi_Cmnd DumCmnd;
-  int Chan, Targ, i;
-  struct info_str info;
-  CPQFCHBA *cpqfcHBA;
-  PTACHYON fcChip;
-  PFC_LOGGEDIN_PORT pLoggedInPort;
-  char buf[81];
-
-  // Search the Scsi host list for our controller
-  for (host=scsi_hostlist; host; host=host->next)
-    if (host->host_no == hostno)
-      break;
-
-  if (!host) return -ESRCH;
-
-  if (inout) return -EINVAL;
-
-  // get the pointer to our Scsi layer HBA buffer  
-  cpqfcHBA = (CPQFCHBA *)host->hostdata;
-  fcChip = &cpqfcHBA->fcChip;
-  
-  *start 	  = buffer;
-
-  info.buffer     = buffer;
-  info.buflength  = length;
-  info.bufoffset  = offset;
-  info.filpos     = 0;
-  info.buffillen  = 0;
-  copy_info(&info, "Driver version = %d.%d.%d", VER_MAJOR, VER_MINOR, VER_SUBMINOR); 
-  cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[0]);
-  cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
-  copy_info(&info, "%s\n", buf); 
+	struct Scsi_Host *host;
+	Scsi_Cmnd DumCmnd;
+	int Chan, Targ, i;
+	struct info_str info;
+	CPQFCHBA *cpqfcHBA;
+	PTACHYON fcChip;
+	PFC_LOGGEDIN_PORT pLoggedInPort;
+	char buf[81];
+
+	// Search the Scsi host list for our controller
+	for (host = scsi_hostlist; host; host = host->next)
+		if (host->host_no == hostno)
+			break;
+
+	if (!host)
+		return -ESRCH;
+
+	if (inout)
+		return -EINVAL;
+
+	// get the pointer to our Scsi layer HBA buffer  
+	cpqfcHBA = (CPQFCHBA *) host->hostdata;
+	fcChip = &cpqfcHBA->fcChip;
+
+	*start = buffer;
+
+	info.buffer = buffer;
+	info.buflength = length;
+	info.bufoffset = offset;
+	info.filpos = 0;
+	info.buffillen = 0;
+	copy_info(&info, "Driver version = %d.%d.%d", VER_MAJOR, VER_MINOR, VER_SUBMINOR);
+	cpqfcTSDecodeGBICtype(&cpqfcHBA->fcChip, &buf[0]);
+	cpqfcTSGetLPSM(&cpqfcHBA->fcChip, &buf[strlen(buf)]);
+	copy_info(&info, "%s\n", buf);
 
 #define DISPLAY_WWN_INFO
 #ifdef DISPLAY_WWN_INFO
-  copy_info(&info, "WWN database: (\"port_id: 000000\" means disconnected)\n");
-  for ( Chan=0; Chan <= host->max_channel; Chan++) {
-    DumCmnd.channel = Chan;
-    for (Targ=0; Targ <= host->max_id; Targ++) {
-      DumCmnd.target = Targ;
-      if ((pLoggedInPort = fcFindLoggedInPort( fcChip,
-	    			&DumCmnd, // search Scsi Nexus
-    				0,        // DON'T search list for FC port id
-    				NULL,     // DON'T search list for FC WWN
-    				NULL))){   // DON'T care about end of list
-	copy_info(&info, "Host: scsi%d Channel: %02d TargetId: %02d -> WWN: ",
-			   hostno, Chan, Targ);
-        for( i=3; i>=0; i--)        // copy the LOGIN port's WWN
-          copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
-        for( i=7; i>3; i--)             // copy the LOGIN port's WWN
-          copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
-	copy_info(&info, " port_id: %06X\n", pLoggedInPort->port_id); 
-      }
-    }
-  }
+	copy_info(&info, "WWN database: (\"port_id: 000000\" means disconnected)\n");
+	for (Chan = 0; Chan <= host->max_channel; Chan++) {
+		DumCmnd.channel = Chan;
+		for (Targ = 0; Targ <= host->max_id; Targ++) {
+			DumCmnd.target = Targ;
+			if ((pLoggedInPort = fcFindLoggedInPort(fcChip, &DumCmnd,	// search Scsi Nexus
+								0,	// DON'T search list for FC port id
+								NULL,	// DON'T search list for FC WWN
+								NULL))) {	// DON'T care about end of list
+				copy_info(&info, "Host: scsi%d Channel: %02d TargetId: %02d -> WWN: ", hostno, Chan, Targ);
+				for (i = 3; i >= 0; i--)	// copy the LOGIN port's WWN
+					copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
+				for (i = 7; i > 3; i--)	// copy the LOGIN port's WWN
+					copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
+				copy_info(&info, " port_id: %06X\n", pLoggedInPort->port_id);
+			}
+		}
+	}
 #endif
 
 
 
-  
-  
+
+
 // Unfortunately, the proc_info buffer isn't big enough
 // for everything we would like...
 // For FC stats, compile this and turn off WWN stuff above  
 //#define DISPLAY_FC_STATS
 #ifdef DISPLAY_FC_STATS
 // get the Fibre Channel statistics
-  {
-    int DeltaSecs = (jiffies - cpqfcHBA->fcStatsTime) / HZ;
-    int days,hours,minutes,secs;
-    
-    days = DeltaSecs / (3600*24); // days
-    hours = (DeltaSecs% (3600*24)) / 3600; // hours
-    minutes = (DeltaSecs%3600 /60); // minutes
-    secs =  DeltaSecs%60;  // secs
-copy_info( &info, "Fibre Channel Stats (time dd:hh:mm:ss %02u:%02u:%02u:%02u\n",
-      days, hours, minutes, secs);
-  }
-    
-  cpqfcHBA->fcStatsTime = jiffies;  // (for next delta)
-
-  copy_info( &info, "  LinkUp           %9u     LinkDown      %u\n",
-        fcChip->fcStats.linkUp, fcChip->fcStats.linkDown);
-        
-  copy_info( &info, "  Loss of Signal   %9u     Loss of Sync  %u\n",
-    fcChip->fcStats.LossofSignal, fcChip->fcStats.LossofSync);
-		  
-  copy_info( &info, "  Discarded Frames %9u     Bad CRC Frame %u\n",
-    fcChip->fcStats.Dis_Frm, fcChip->fcStats.Bad_CRC);
-
-  copy_info( &info, "  TACH LinkFailTX  %9u     TACH LinkFailRX     %u\n",
-    fcChip->fcStats.linkFailTX, fcChip->fcStats.linkFailRX);
-  
-  copy_info( &info, "  TACH RxEOFa      %9u     TACH Elastic Store  %u\n",
-    fcChip->fcStats.Rx_EOFa, fcChip->fcStats.e_stores);
-
-  copy_info( &info, "  BufferCreditWait %9uus   TACH FM Inits %u\n",
-    fcChip->fcStats.BB0_Timer*10, fcChip->fcStats.FMinits );
-	
-  copy_info( &info, "  FC-2 Timeouts    %9u     FC-2 Logouts  %u\n",
-    fcChip->fcStats.timeouts, fcChip->fcStats.logouts); 
-        
-  copy_info( &info, "  FC-2 Aborts      %9u     FC-4 Aborts   %u\n",
-    fcChip->fcStats.FC2aborted, fcChip->fcStats.FC4aborted);
-   
-  // clear the counters
-  cpqfcTSClearLinkStatusCounters( fcChip);
+	{
+		int DeltaSecs = (jiffies - cpqfcHBA->fcStatsTime) / HZ;
+		int days, hours, minutes, secs;
+
+		days = DeltaSecs / (3600 * 24);	// days
+		hours = (DeltaSecs % (3600 * 24)) / 3600;	// hours
+		minutes = (DeltaSecs % 3600 / 60);	// minutes
+		secs = DeltaSecs % 60;	// secs
+		copy_info(&info, "Fibre Channel Stats (time dd:hh:mm:ss %02u:%02u:%02u:%02u\n", days, hours, minutes, secs);
+	}
+
+	cpqfcHBA->fcStatsTime = jiffies;	// (for next delta)
+
+	copy_info(&info, "  LinkUp           %9u     LinkDown      %u\n", fcChip->fcStats.linkUp, fcChip->fcStats.linkDown);
+
+	copy_info(&info, "  Loss of Signal   %9u     Loss of Sync  %u\n", fcChip->fcStats.LossofSignal, fcChip->fcStats.LossofSync);
+
+	copy_info(&info, "  Discarded Frames %9u     Bad CRC Frame %u\n", fcChip->fcStats.Dis_Frm, fcChip->fcStats.Bad_CRC);
+
+	copy_info(&info, "  TACH LinkFailTX  %9u     TACH LinkFailRX     %u\n", fcChip->fcStats.linkFailTX, fcChip->fcStats.linkFailRX);
+
+	copy_info(&info, "  TACH RxEOFa      %9u     TACH Elastic Store  %u\n", fcChip->fcStats.Rx_EOFa, fcChip->fcStats.e_stores);
+
+	copy_info(&info, "  BufferCreditWait %9uus   TACH FM Inits %u\n", fcChip->fcStats.BB0_Timer * 10, fcChip->fcStats.FMinits);
+
+	copy_info(&info, "  FC-2 Timeouts    %9u     FC-2 Logouts  %u\n", fcChip->fcStats.timeouts, fcChip->fcStats.logouts);
+
+	copy_info(&info, "  FC-2 Aborts      %9u     FC-4 Aborts   %u\n", fcChip->fcStats.FC2aborted, fcChip->fcStats.FC4aborted);
+
+	// clear the counters
+	cpqfcTSClearLinkStatusCounters(fcChip);
 #endif
-	
-  return info.buffillen;
+
+	return info.buffillen;
 }
 
 
 #if DEBUG_CMND
 
-UCHAR *ScsiToAscii( UCHAR ScsiCommand)
+u8 *ScsiToAscii(u8 ScsiCommand)
 {
 
 /*++
@@ -1000,152 +868,148 @@
 --*/
 
 
-   switch (ScsiCommand)
-   {
-      case 0x00:
-         return( "Test Unit Ready" );
+	switch (ScsiCommand) {
+	case 0x00:
+		return ("Test Unit Ready");
 
-      case 0x01:
-         return( "Rezero Unit or Rewind" );
+	case 0x01:
+		return ("Rezero Unit or Rewind");
 
-      case 0x02:
-         return( "Request Block Address" );
+	case 0x02:
+		return ("Request Block Address");
 
-      case 0x03:
-         return( "Requese Sense" );
+	case 0x03:
+		return ("Requese Sense");
 
-      case 0x04:
-         return( "Format Unit" );
+	case 0x04:
+		return ("Format Unit");
 
-      case 0x05:
-         return( "Read Block Limits" );
+	case 0x05:
+		return ("Read Block Limits");
 
-      case 0x07:
-         return( "Reassign Blocks" );
+	case 0x07:
+		return ("Reassign Blocks");
 
-      case 0x08:
-         return( "Read (6)" );
+	case 0x08:
+		return ("Read (6)");
 
-      case 0x0a:
-         return( "Write (6)" );
+	case 0x0a:
+		return ("Write (6)");
 
-      case 0x0b:
-         return( "Seek (6)" );
+	case 0x0b:
+		return ("Seek (6)");
 
-      case 0x12:
-         return( "Inquiry" );
+	case 0x12:
+		return ("Inquiry");
 
-      case 0x15:
-         return( "Mode Select (6)" );
+	case 0x15:
+		return ("Mode Select (6)");
 
-      case 0x16:
-         return( "Reserve" );
+	case 0x16:
+		return ("Reserve");
 
-      case 0x17:
-         return( "Release" );
+	case 0x17:
+		return ("Release");
 
-      case 0x1a:
-         return( "ModeSen(6)" );
+	case 0x1a:
+		return ("ModeSen(6)");
 
-      case 0x1b:
-         return( "Start/Stop Unit" );
+	case 0x1b:
+		return ("Start/Stop Unit");
 
-      case 0x1c:
-         return( "Receive Diagnostic Results" );
+	case 0x1c:
+		return ("Receive Diagnostic Results");
 
-      case 0x1d:
-         return( "Send Diagnostic" );
+	case 0x1d:
+		return ("Send Diagnostic");
 
-      case 0x25:
-         return( "Read Capacity" );
+	case 0x25:
+		return ("Read Capacity");
 
-      case 0x28:
-         return( "Read (10)" );
+	case 0x28:
+		return ("Read (10)");
 
-      case 0x2a:
-         return( "Write (10)" );
+	case 0x2a:
+		return ("Write (10)");
 
-      case 0x2b:
-         return( "Seek (10)" );
+	case 0x2b:
+		return ("Seek (10)");
 
-      case 0x2e:
-         return( "Write and Verify" );
+	case 0x2e:
+		return ("Write and Verify");
 
-      case 0x2f:
-         return( "Verify" );
+	case 0x2f:
+		return ("Verify");
 
-      case 0x34:
-         return( "Pre-Fetch" );
+	case 0x34:
+		return ("Pre-Fetch");
 
-      case 0x35:
-         return( "Synchronize Cache" );
+	case 0x35:
+		return ("Synchronize Cache");
 
-      case 0x37:
-         return( "Read Defect Data (10)" );
+	case 0x37:
+		return ("Read Defect Data (10)");
 
-      case 0x3b:
-         return( "Write Buffer" );
+	case 0x3b:
+		return ("Write Buffer");
 
-      case 0x3c:
-         return( "Read Buffer" );
+	case 0x3c:
+		return ("Read Buffer");
 
-      case 0x3e:
-         return( "Read Long" );
+	case 0x3e:
+		return ("Read Long");
 
-      case 0x3f:
-         return( "Write Long" );
+	case 0x3f:
+		return ("Write Long");
 
-      case 0x41:
-         return( "Write Same" );
+	case 0x41:
+		return ("Write Same");
 
-      case 0x4c:
-         return( "Log Select" );
+	case 0x4c:
+		return ("Log Select");
 
-      case 0x4d:
-         return( "Log Sense" );
+	case 0x4d:
+		return ("Log Sense");
 
-      case 0x56:
-         return( "Reserve (10)" );
+	case 0x56:
+		return ("Reserve (10)");
 
-      case 0x57:
-         return( "Release (10)" );
+	case 0x57:
+		return ("Release (10)");
 
-      case 0xa0:
-         return( "ReportLuns" );
+	case 0xa0:
+		return ("ReportLuns");
 
-      case 0xb7:
-         return( "Read Defect Data (12)" );
+	case 0xb7:
+		return ("Read Defect Data (12)");
 
-      case 0xca:
-         return( "Peripheral Device Addressing SCSI Passthrough" );
+	case 0xca:
+		return ("Peripheral Device Addressing SCSI Passthrough");
 
-      case 0xcb:
-         return( "Compaq Array Firmware Passthrough" );
+	case 0xcb:
+		return ("Compaq Array Firmware Passthrough");
 
-      default:
-         return( NULL );
-   }
+	default:
+		return (NULL);
+	}
 
-} // end ScsiToAscii()
+}				// end ScsiToAscii()
 
 void cpqfcTS_print_scsi_cmd(Scsi_Cmnd * cmd)
 {
 
-printk("cpqfcTS: (%s) chnl 0x%02x, trgt = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", 
-    ScsiToAscii( cmd->cmnd[0]), cmd->channel, cmd->target, cmd->lun, cmd->cmd_len);
+	printk("cpqfcTS: (%s) chnl 0x%02x, trgt = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", ScsiToAscii(cmd->cmnd[0]), cmd->channel, cmd->target, cmd->lun, cmd->cmd_len);
 
-if( cmd->cmnd[0] == 0)   // Test Unit Ready?
-{
-  int i;
+	if (cmd->cmnd[0] == 0)	// Test Unit Ready?
+	{
+		int i;
 
-  printk("Cmnd->request_bufflen = 0x%X, ->use_sg = %d, ->bufflen = %d\n",
-    cmd->request_bufflen, cmd->use_sg, cmd->bufflen);
-  printk("Cmnd->request_buffer = %p, ->sglist_len = %d, ->buffer = %p\n",
-    cmd->request_buffer, cmd->sglist_len, cmd->buffer);
-  for (i = 0; i < cmd->cmd_len; i++)
-    printk("0x%02x ", cmd->cmnd[i]);
-  printk("\n");
-}
+		printk("Cmnd->request_bufflen = 0x%X, ->use_sg = %d, ->bufflen = %d\n", cmd->request_bufflen, cmd->use_sg, cmd->bufflen);
+		printk("Cmnd->request_buffer = %p, ->sglist_len = %d, ->buffer = %p\n", cmd->request_buffer, cmd->sglist_len, cmd->buffer);
+		for (i = 0; i < cmd->cmd_len; i++)
+			printk("0x%02x ", cmd->cmnd[i]);
+		printk("\n");
+	}
 
 }
 
@@ -1154,51 +1018,48 @@
 
 
 
-static void QueCmndOnBoardLock( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
+static void QueCmndOnBoardLock(CPQFCHBA * cpqfcHBAdata, Scsi_Cmnd * Cmnd)
 {
-  int i;
+	int i;
 
-  for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++)
-  {    // find spare slot
-    if( cpqfcHBAdata->BoardLockCmnd[i] == NULL )
-    {
-      cpqfcHBAdata->BoardLockCmnd[i] = Cmnd;
+	for (i = 0; i < CPQFCTS_REQ_QUEUE_LEN; i++) {	// find spare slot
+		if (cpqfcHBAdata->BoardLockCmnd[i] == NULL) {
+			cpqfcHBAdata->BoardLockCmnd[i] = Cmnd;
 //      printk(" BoardLockCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",
 //        i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
-      break;
-    }
-  }
-  if( i >= CPQFCTS_REQ_QUEUE_LEN)
-  {
-    printk(" cpqfcTS WARNING: Lost Cmnd %p on BoardLock Q full!", Cmnd);
-  }
+			break;
+		}
+	}
+	if (i >= CPQFCTS_REQ_QUEUE_LEN) {
+		printk(" cpqfcTS WARNING: Lost Cmnd %p on BoardLock Q full!", Cmnd);
+	}
 
 }
 
 
-static void QueLinkDownCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
+static void QueLinkDownCmnd(CPQFCHBA * cpqfcHBAdata, Scsi_Cmnd * Cmnd)
 {
-  int indx;
+	int indx;
 
-  // Remember the command ptr so we can return; we'll complete when
-  // the device comes back, causing immediate retry
-  for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++)//, SCptr++)
-  {
-    if( cpqfcHBAdata->LinkDnCmnd[indx] == NULL ) // available?
-    {
+	// Remember the command ptr so we can return; we'll complete when
+	// the device comes back, causing immediate retry
+	for (indx = 0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++)	//, SCptr++)
+	{
+		if (cpqfcHBAdata->LinkDnCmnd[indx] == NULL)	// available?
+		{
 #ifdef DUMMYCMND_DBG
-      printk(" @add Cmnd %p to LnkDnCmnd[%d]@ ", Cmnd,indx);
+			printk(" @add Cmnd %p to LnkDnCmnd[%d]@ ", Cmnd, indx);
 #endif
-      cpqfcHBAdata->LinkDnCmnd[indx] = Cmnd;
-      break;
-    }
-  }
-
-  if( indx >= CPQFCTS_REQ_QUEUE_LEN ) // no space for Cmnd??
-  {
-    // this will result in an _abort call later (with possible trouble)
-    printk("no buffer for LinkDnCmnd!! %p\n", Cmnd);
-  }
+			cpqfcHBAdata->LinkDnCmnd[indx] = Cmnd;
+			break;
+		}
+	}
+
+	if (indx >= CPQFCTS_REQ_QUEUE_LEN)	// no space for Cmnd??
+	{
+		// this will result in an _abort call later (with possible trouble)
+		printk("no buffer for LinkDnCmnd!! %p\n", Cmnd);
+	}
 }
 
 
@@ -1211,185 +1072,162 @@
 // for cases that don't go to the hardware like scsi cmds destined
 // for LUNs we know don't exist, so this code might be simplified...)
 
-static void QueBadTargetCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
+static void QueBadTargetCmnd(CPQFCHBA * cpqfcHBAdata, Scsi_Cmnd * Cmnd)
 {
-  int i;
-    //    printk(" can't find target %d\n", Cmnd->target);
+	int i;
+	//    printk(" can't find target %d\n", Cmnd->target);
 
-  for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
-  {    // find spare slot
-    if( cpqfcHBAdata->BadTargetCmnd[i] == NULL )
-    {
-      cpqfcHBAdata->BadTargetCmnd[i] = Cmnd;
+	for (i = 0; i < CPQFCTS_MAX_TARGET_ID; i++) {	// find spare slot
+		if (cpqfcHBAdata->BadTargetCmnd[i] == NULL) {
+			cpqfcHBAdata->BadTargetCmnd[i] = Cmnd;
 //      printk(" BadTargetCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",
 //          i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
-      break;
-    }
-  }
+			break;
+		}
+	}
 }
 
 
 // This is the "main" entry point for Linux Scsi commands --
 // it all starts here.
 
-int cpqfcTS_queuecommand(Scsi_Cmnd *Cmnd, void (* done)(Scsi_Cmnd *))
+int cpqfcTS_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
 {
-  struct Scsi_Host *HostAdapter = Cmnd->host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  TachFCHDR_GCMND fchs;  // only use for FC destination id field  
-  PFC_LOGGEDIN_PORT pLoggedInPort;
-  ULONG ulStatus, SESTtype;
-  LONG ExchangeID;
+	struct Scsi_Host *HostAdapter = Cmnd->host;
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	TachFCHDR_GCMND fchs;	// only use for FC destination id field  
+	PFC_LOGGEDIN_PORT pLoggedInPort;
+	u32 ulStatus, SESTtype;
+	s32 ExchangeID;
+
+
 
 
+	ENTER("cpqfcTS_queuecommand");
 
+	PCI_TRACEO((u32) Cmnd, 0x98)
 
-  ENTER("cpqfcTS_queuecommand");
-      
-  PCI_TRACEO( (ULONG)Cmnd, 0x98)
-      
-  
-  Cmnd->scsi_done = done;
-#ifdef DEBUG_CMND  
-  cpqfcTS_print_scsi_cmd( Cmnd);
+
+	    Cmnd->scsi_done = done;
+#ifdef DEBUG_CMND
+	cpqfcTS_print_scsi_cmd(Cmnd);
 #endif
 
-  // prevent board contention with kernel thread...  
-  
-   if( cpqfcHBAdata->BoardLock )
-  {
+	// prevent board contention with kernel thread...  
+
+	if (cpqfcHBAdata->BoardLock) {
 //    printk(" @BrdLck Hld@ ");
-    QueCmndOnBoardLock( cpqfcHBAdata, Cmnd);
-  }
-  
-  else
-  {
-
-    // in the current system (2.2.12), this routine is called
-    // after spin_lock_irqsave(), so INTs are disabled. However,
-    // we might have something pending in the LinkQ, which
-    // might cause the WorkerTask to run.  In case that
-    // happens, make sure we lock it out.
-    
-    
-    
-    PCI_TRACE( 0x98) 
-    CPQ_SPINLOCK_HBA( cpqfcHBAdata)
-    PCI_TRACE( 0x98) 
-	    
-  // can we find an FC device mapping to this SCSI target?
-    pLoggedInPort = fcFindLoggedInPort( fcChip,
-      Cmnd,     // search Scsi Nexus
-      0,        // DON'T search linked list for FC port id
-      NULL,     // DON'T search linked list for FC WWN
-      NULL);    // DON'T care about end of list
- 
-    if( pLoggedInPort == NULL )      // not found!
-    {
+		QueCmndOnBoardLock(cpqfcHBAdata, Cmnd);
+	}
+
+	else {
+
+		// in the current system (2.2.12), this routine is called
+		// after spin_lock_irqsave(), so INTs are disabled. However,
+		// we might have something pending in the LinkQ, which
+		// might cause the WorkerTask to run.  In case that
+		// happens, make sure we lock it out.
+
+
+
+		PCI_TRACE(0x98)
+		    CPQ_SPINLOCK_HBA(cpqfcHBAdata)
+		    PCI_TRACE(0x98)
+		    // can we find an FC device mapping to this SCSI target?
+		    pLoggedInPort = fcFindLoggedInPort(fcChip, Cmnd,	// search Scsi Nexus
+						       0,	// DON'T search linked list for FC port id
+						       NULL,	// DON'T search linked list for FC WWN
+						       NULL);	// DON'T care about end of list
+
+		if (pLoggedInPort == NULL)	// not found!
+		{
 //    printk(" @Q bad targ cmnd %p@ ", Cmnd);
-      QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
-    }
-    else if (Cmnd->lun >= CPQFCTS_MAX_LUN)
-    {
-      printk(KERN_WARNING "cpqfc: Invalid LUN: %d\n", Cmnd->lun);
-      QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
-    } 
-
-    else  // we know what FC device to send to...
-    {
-
-      // does this device support FCP target functions?
-      // (determined by PRLI field)
-
-      if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) )
-      {
-        printk(" Doesn't support TARGET functions port_id %Xh\n",
-          pLoggedInPort->port_id );
-        QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
-      }
-
-    // In this case (previous login OK), the device is temporarily
-    // unavailable waiting for re-login, in which case we expect it
-    // to be back in between 25 - 500ms.  
-    // If the FC port doesn't log back in within several seconds
-    // (i.e. implicit "logout"), or we get an explicit logout,
-    // we set "device_blocked" in Scsi_Device struct; in this
-    // case 30 seconds will elapse before Linux/Scsi sends another
-    // command to the device.
-      else if( pLoggedInPort->prli != TRUE )
-      {
+			QueBadTargetCmnd(cpqfcHBAdata, Cmnd);
+		} else if (Cmnd->lun >= CPQFCTS_MAX_LUN) {
+			printk(KERN_WARNING "cpqfc: Invalid LUN: %d\n", Cmnd->lun);
+			QueBadTargetCmnd(cpqfcHBAdata, Cmnd);
+		}
+
+		else		// we know what FC device to send to...
+		{
+
+			// does this device support FCP target functions?
+			// (determined by PRLI field)
+
+			if (!(pLoggedInPort->fcp_info & TARGET_FUNCTION)) {
+				printk(" Doesn't support TARGET functions port_id %Xh\n", pLoggedInPort->port_id);
+				QueBadTargetCmnd(cpqfcHBAdata, Cmnd);
+			}
+			// In this case (previous login OK), the device is temporarily
+			// unavailable waiting for re-login, in which case we expect it
+			// to be back in between 25 - 500ms.  
+			// If the FC port doesn't log back in within several seconds
+			// (i.e. implicit "logout"), or we get an explicit logout,
+			// we set "device_blocked" in Scsi_Device struct; in this
+			// case 30 seconds will elapse before Linux/Scsi sends another
+			// command to the device.
+			else if (pLoggedInPort->prli != TRUE) {
 //      printk("Device (Chnl/Target %d/%d) invalid PRLI, port_id %06lXh\n",
 //        Cmnd->channel, Cmnd->target, pLoggedInPort->port_id);
-        QueLinkDownCmnd( cpqfcHBAdata, Cmnd);
-//    Need to use "blocked" flag??   	
-//	Cmnd->device->device_blocked = TRUE; // just let it timeout
-      }
-      else  // device supports TARGET functions, and is logged in...
-      {
-      // (context of fchs is to "reply" to...)
-        fchs.s_id = pLoggedInPort->port_id; // destination FC address
-
-      // what is the data direction?  For data TO the device,
-      // we need IWE (Intiator Write Entry).  Otherwise, IRE.
-
-        if( Cmnd->cmnd[0] == WRITE_10 ||
-  	  Cmnd->cmnd[0] == WRITE_6 ||
-	  Cmnd->cmnd[0] == WRITE_BUFFER ||      
-	  Cmnd->cmnd[0] == VENDOR_WRITE_OPCODE ||  // CPQ specific 
-	  Cmnd->cmnd[0] == MODE_SELECT )
-        {
-          SESTtype = SCSI_IWE; // data from HBA to Device
-        }
-        else
-          SESTtype = SCSI_IRE; // data from Device to HBA
-    	  
-        ulStatus = cpqfcTSBuildExchange(
-          cpqfcHBAdata,
-          SESTtype,     // e.g. Initiator Read Entry (IRE)
-          &fchs,        // we are originator; only use d_id
-          Cmnd,         // Linux SCSI command (with scatter/gather list)
-          &ExchangeID );// fcController->fcExchanges index, -1 if failed
+				QueLinkDownCmnd(cpqfcHBAdata, Cmnd);
+//    Need to use "blocked" flag??      
+//      Cmnd->device->device_blocked = TRUE; // just let it timeout
+			} else	// device supports TARGET functions, and is logged in...
+			{
+				// (context of fchs is to "reply" to...)
+				fchs.s_id = pLoggedInPort->port_id;	// destination FC address
+
+				// what is the data direction?  For data TO the device,
+				// we need IWE (Intiator Write Entry).  Otherwise, IRE.
+
+				if (Cmnd->cmnd[0] == WRITE_10 || Cmnd->cmnd[0] == WRITE_6 || Cmnd->cmnd[0] == WRITE_BUFFER || Cmnd->cmnd[0] == VENDOR_WRITE_OPCODE ||	// CPQ specific 
+				    Cmnd->cmnd[0] == MODE_SELECT) {
+					SESTtype = SCSI_IWE;	// data from HBA to Device
+				} else
+					SESTtype = SCSI_IRE;	// data from Device to HBA
+
+				ulStatus = cpqfcTSBuildExchange(cpqfcHBAdata, SESTtype,	// e.g. Initiator Read Entry (IRE)
+								&fchs,	// we are originator; only use d_id
+								Cmnd,	// Linux SCSI command (with scatter/gather list)
+								&ExchangeID);	// fcController->fcExchanges index, -1 if failed
+
+				if (!ulStatus)	// Exchange setup?
+
+				{
+					if (cpqfcHBAdata->BoardLock) {
+						TriggerHBA(fcChip->Registers.ReMapMemBase, 0);
+						printk(" @bl! %d, xID %Xh@ ", current->pid, ExchangeID);
+					}
+
+					ulStatus = cpqfcTSStartExchange(cpqfcHBAdata, ExchangeID);
+					if (!ulStatus) {
+						PCI_TRACEO(ExchangeID, 0xB8)
+						    // submitted to Tach's Outbound Que (ERQ PI incremented)
+						    // waited for completion for ELS type (Login frames issued
+						    // synchronously)
+					} else
+						// check reason for Exchange not being started - we might
+						// want to Queue and start later, or fail with error
+					{
+						printk("quecommand: cpqfcTSStartExchange failed: %Xh\n", ulStatus);
+					}
+				}	// end good BuildExchange status
+
+				else	// SEST table probably full  -- why? hardware hang?
+				{
+					printk("quecommand: cpqfcTSBuildExchange faild: %Xh\n", ulStatus);
+				}
+			}	// end can't do FCP-SCSI target functions
+		}		// end can't find target (FC device)
 
-        if( !ulStatus ) // Exchange setup?
-   
-        {
-          if( cpqfcHBAdata->BoardLock )
-          {
-    TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
-	    printk(" @bl! %d, xID %Xh@ ", current->pid, ExchangeID);
-          }
-
-	  ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-	  if( !ulStatus )
-          {
-            PCI_TRACEO( ExchangeID, 0xB8) 
-          // submitted to Tach's Outbound Que (ERQ PI incremented)
-          // waited for completion for ELS type (Login frames issued
-          // synchronously)
-	  }
-          else
-            // check reason for Exchange not being started - we might
-            // want to Queue and start later, or fail with error
-          {
-            printk("quecommand: cpqfcTSStartExchange failed: %Xh\n", ulStatus );
-          }
-        }            // end good BuildExchange status
-        
-        else  // SEST table probably full  -- why? hardware hang?
-        {
-	  printk("quecommand: cpqfcTSBuildExchange faild: %Xh\n", ulStatus);
-        }
-      }  // end can't do FCP-SCSI target functions
-    } // end can't find target (FC device)
-
-    CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
-  }
-	
-  PCI_TRACEO( (ULONG)Cmnd, 0x9C) 
-  LEAVE("cpqfcTS_queuecommand");
-  return 0;
-}    
+		CPQ_SPINUNLOCK_HBA(cpqfcHBAdata)
+	}
+
+	PCI_TRACEO((u32) Cmnd, 0x9C)
+	    LEAVE("cpqfcTS_queuecommand");
+	return 0;
+}
 
 
 // Entry point for upper Scsi layer intiated abort.  Typically
@@ -1403,148 +1241,140 @@
 // errors, it should be considered a driver error and reported to
 // the author.
 
-int cpqfcTS_abort(Scsi_Cmnd *Cmnd)
+int cpqfcTS_abort(Scsi_Cmnd * Cmnd)
 {
-//	printk(" cpqfcTS_abort called?? \n");
- 	return 0;
+//      printk(" cpqfcTS_abort called?? \n");
+	return 0;
 }
- 
-int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd)
+
+int cpqfcTS_eh_abort(Scsi_Cmnd * Cmnd)
 {
 
-  struct Scsi_Host *HostAdapter = Cmnd->host;
-  // get the pointer to our Scsi layer HBA buffer  
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  int i;
-  ENTER("cpqfcTS_eh_abort");
-
-  Cmnd->result = DID_ABORT <<16;  // assume we'll find it
-
-  printk(" @Linux _abort Scsi_Cmnd %p ", Cmnd);
-  // See if we can find a Cmnd pointer that matches...
-  // The most likely case is we accepted the command
-  // from Linux Scsi (e.g. ceated a SEST entry) and it
-  // got lost somehow.  If we can't find any reference
-  // to the passed pointer, we can only presume it
-  // got completed as far as our driver is concerned.
-  // If we found it, we will try to abort it through
-  // common mechanism.  If FC ABTS is successful (ACC)
-  // or is rejected (RJT) by target, we will call
-  // Scsi "done" quickly.  Otherwise, the ABTS will timeout
-  // and we'll call "done" later.
-
-  // Search the SEST exchanges for a matching Cmnd ptr.
-  for( i=0; i< TACH_SEST_LEN; i++)
-  {
-    if( Exchanges->fcExchange[i].Cmnd == Cmnd )
-    {
-      
-      // found it!
-      printk(" x_ID %Xh, type %Xh\n", i, Exchanges->fcExchange[i].type);
-
-      Exchanges->fcExchange[i].status = INITIATOR_ABORT; // seconds default
-      Exchanges->fcExchange[i].timeOut = 10; // seconds default (changed later)
-
-      // Since we need to immediately return the aborted Cmnd to Scsi 
-      // upper layers, we can't make future reference to any of it's 
-      // fields (e.g the Nexus).
-
-      cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i);
-
-      break;
-    }
-  }
-
-  if( i >= TACH_SEST_LEN ) // didn't find Cmnd ptr in chip's SEST?
-  {
-    // now search our non-SEST buffers (i.e. Cmnd waiting to
-    // start on the HBA or waiting to complete with error for retry).
-    
-    // first check BadTargetCmnd
-    for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
-    { 
-      if( cpqfcHBAdata->BadTargetCmnd[i] == Cmnd )
-      {
-        cpqfcHBAdata->BadTargetCmnd[i] = NULL;
-	printk("in BadTargetCmnd Q\n");
-	goto Done; // exit
-      }
-    }
-
-    // if not found above...
-
-    for( i=0; i < CPQFCTS_REQ_QUEUE_LEN; i++)
-    {
-      if( cpqfcHBAdata->LinkDnCmnd[i] == Cmnd ) 
-      {
-	cpqfcHBAdata->LinkDnCmnd[i] = NULL;
-	printk("in LinkDnCmnd Q\n");
-	goto Done;
-      }
-    }
-
-
-    for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++)
-    {    // find spare slot
-      if( cpqfcHBAdata->BoardLockCmnd[i] == Cmnd )
-      {
-        cpqfcHBAdata->BoardLockCmnd[i] = NULL;
-	printk("in BoardLockCmnd Q\n");
-	goto Done;
-      }
-    }
-    
-    Cmnd->result = DID_ERROR <<16;  // Hmmm...
-    printk("Not found! ");
+	struct Scsi_Host *HostAdapter = Cmnd->host;
+	// get the pointer to our Scsi layer HBA buffer  
+	CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *) HostAdapter->hostdata;
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	int i;
+	ENTER("cpqfcTS_eh_abort");
+
+	Cmnd->result = DID_ABORT << 16;	// assume we'll find it
+
+	printk(" @Linux _abort Scsi_Cmnd %p ", Cmnd);
+	// See if we can find a Cmnd pointer that matches...
+	// The most likely case is we accepted the command
+	// from Linux Scsi (e.g. ceated a SEST entry) and it
+	// got lost somehow.  If we can't find any reference
+	// to the passed pointer, we can only presume it
+	// got completed as far as our driver is concerned.
+	// If we found it, we will try to abort it through
+	// common mechanism.  If FC ABTS is successful (ACC)
+	// or is rejected (RJT) by target, we will call
+	// Scsi "done" quickly.  Otherwise, the ABTS will timeout
+	// and we'll call "done" later.
+
+	// Search the SEST exchanges for a matching Cmnd ptr.
+	for (i = 0; i < TACH_SEST_LEN; i++) {
+		if (Exchanges->fcExchange[i].Cmnd == Cmnd) {
+
+			// found it!
+			printk(" x_ID %Xh, type %Xh\n", i, Exchanges->fcExchange[i].type);
+
+			Exchanges->fcExchange[i].status = INITIATOR_ABORT;	// seconds default
+			Exchanges->fcExchange[i].timeOut = 10;	// seconds default (changed later)
+
+			// Since we need to immediately return the aborted Cmnd to Scsi 
+			// upper layers, we can't make future reference to any of it's 
+			// fields (e.g the Nexus).
+
+			cpqfcTSPutLinkQue(cpqfcHBAdata, BLS_ABTS, &i);
+
+			break;
+		}
+	}
+
+	if (i >= TACH_SEST_LEN)	// didn't find Cmnd ptr in chip's SEST?
+	{
+		// now search our non-SEST buffers (i.e. Cmnd waiting to
+		// start on the HBA or waiting to complete with error for retry).
+
+		// first check BadTargetCmnd
+		for (i = 0; i < CPQFCTS_MAX_TARGET_ID; i++) {
+			if (cpqfcHBAdata->BadTargetCmnd[i] == Cmnd) {
+				cpqfcHBAdata->BadTargetCmnd[i] = NULL;
+				printk("in BadTargetCmnd Q\n");
+				goto Done;	// exit
+			}
+		}
+
+		// if not found above...
+
+		for (i = 0; i < CPQFCTS_REQ_QUEUE_LEN; i++) {
+			if (cpqfcHBAdata->LinkDnCmnd[i] == Cmnd) {
+				cpqfcHBAdata->LinkDnCmnd[i] = NULL;
+				printk("in LinkDnCmnd Q\n");
+				goto Done;
+			}
+		}
+
+
+		for (i = 0; i < CPQFCTS_REQ_QUEUE_LEN; i++) {	// find spare slot
+			if (cpqfcHBAdata->BoardLockCmnd[i] == Cmnd) {
+				cpqfcHBAdata->BoardLockCmnd[i] = NULL;
+				printk("in BoardLockCmnd Q\n");
+				goto Done;
+			}
+		}
+
+		Cmnd->result = DID_ERROR << 16;	// Hmmm...
+		printk("Not found! ");
 //    panic("_abort");
-  }
-  
-Done:
-  
+	}
+
+      Done:
+
 //    panic("_abort");
-  LEAVE("cpqfcTS_eh_abort");
-  return 0;  // (see scsi.h)
-}    
+	LEAVE("cpqfcTS_eh_abort");
+	return 0;		// (see scsi.h)
+}
 
 
 // FCP-SCSI Target Device Reset
 // See dpANS Fibre Channel Protocol for SCSI
 // X3.269-199X revision 12, pg 25
 
-int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, 
-                               unsigned int reset_flags)
+int cpqfcTS_TargetDeviceReset(Scsi_Device * ScsiDev, unsigned int reset_flags)
 {
-  int timeout = 10*HZ;
-  int retries = 1;
-  char scsi_cdb[12];
-  int result;
-  Scsi_Cmnd * SCpnt;
-  Scsi_Device * SDpnt;
-
-
-  // printk("   ENTERING cpqfcTS_TargetDeviceReset() - flag=%d \n",reset_flags);
-
-  if (ScsiDev->host->eh_active) return FAILED;
-
-  memset( scsi_cdb, 0, sizeof( scsi_cdb));
-
-  scsi_cdb[0] = RELEASE;
-
-  // allocate with wait = true, interruptible = false 
-  SCpnt = scsi_allocate_device(ScsiDev, 1, 0);
-  {
-    CPQFC_DECLARE_COMPLETION(wait);
-        
-    SCpnt->SCp.buffers_residual = FCP_TARGET_RESET;
-
-	SCpnt->request.CPQFC_WAITING = &wait;
-	scsi_do_cmd(SCpnt,  scsi_cdb, NULL,  0, my_ioctl_done,  timeout, retries);
-	CPQFC_WAIT_FOR_COMPLETION(&wait);
-	SCpnt->request.CPQFC_WAITING = NULL;
-  }
-    
+	int timeout = 10 * HZ;
+	int retries = 1;
+	char scsi_cdb[12];
+	int result;
+	Scsi_Cmnd *SCpnt;
+	Scsi_Device *SDpnt;
+
+
+	// printk("   ENTERING cpqfcTS_TargetDeviceReset() - flag=%d \n",reset_flags);
+
+	if (ScsiDev->host->eh_active)
+		return FAILED;
+
+	memset(scsi_cdb, 0, sizeof(scsi_cdb));
+
+	scsi_cdb[0] = RELEASE;
+
+	// allocate with wait = true, interruptible = false 
+	SCpnt = scsi_allocate_device(ScsiDev, 1, 0);
+	{
+		CPQFC_DECLARE_COMPLETION(wait);
+
+		SCpnt->SCp.buffers_residual = FCP_TARGET_RESET;
+
+		SCpnt->request.CPQFC_WAITING = &wait;
+		scsi_do_cmd(SCpnt, scsi_cdb, NULL, 0, my_ioctl_done, timeout, retries);
+		CPQFC_WAIT_FOR_COMPLETION(&wait);
+		SCpnt->request.CPQFC_WAITING = NULL;
+	}
+
 /*
       if(driver_byte(SCpnt->result) != 0)
 	  switch(SCpnt->sense_buffer[2] & 0xf) {
@@ -1577,41 +1407,41 @@
 		   SCpnt->sense_buffer[2] & 0xf);
 	    
       };
-*/    
-  result = SCpnt->result;
+*/
+	result = SCpnt->result;
 
-  SDpnt = SCpnt->device;
-  scsi_release_command(SCpnt);
-  SCpnt = NULL;
+	SDpnt = SCpnt->device;
+	scsi_release_command(SCpnt);
+	SCpnt = NULL;
 
-  // if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
-  // 	(*SDpnt->scsi_request_fn)();
+	// if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
+	//    (*SDpnt->scsi_request_fn)();
 
-  wake_up(&SDpnt->scpnt_wait);
-  // printk("   LEAVING cpqfcTS_TargetDeviceReset() - return SUCCESS \n");
-  return SUCCESS;
+	wake_up(&SDpnt->scpnt_wait);
+	// printk("   LEAVING cpqfcTS_TargetDeviceReset() - return SUCCESS \n");
+	return SUCCESS;
 }
 
 
-int cpqfcTS_eh_device_reset(Scsi_Cmnd *Cmnd)
+int cpqfcTS_eh_device_reset(Scsi_Cmnd * Cmnd)
 {
-  int retval;
-  Scsi_Device *SDpnt = Cmnd->device;
-  // printk("   ENTERING cpqfcTS_eh_device_reset() \n");
-  spin_unlock_irq(&io_request_lock);
-  retval = cpqfcTS_TargetDeviceReset( SDpnt, 0);
-  spin_lock_irq(&io_request_lock);
-  return retval;
+	int retval;
+	Scsi_Device *SDpnt = Cmnd->device;
+	// printk("   ENTERING cpqfcTS_eh_device_reset() \n");
+	spin_unlock_irq(&io_request_lock);
+	retval = cpqfcTS_TargetDeviceReset(SDpnt, 0);
+	spin_lock_irq(&io_request_lock);
+	return retval;
 }
 
-	
-int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
+
+int cpqfcTS_reset(Scsi_Cmnd * Cmnd, unsigned int reset_flags)
 {
 
-  ENTER("cpqfcTS_reset");
+	ENTER("cpqfcTS_reset");
 
-  LEAVE("cpqfcTS_reset");
-  return SCSI_RESET_ERROR;      /* Bus Reset Not supported */
+	LEAVE("cpqfcTS_reset");
+	return SCSI_RESET_ERROR;	/* Bus Reset Not supported */
 }
 
 /* This function determines the bios parameters for a given
@@ -1621,228 +1451,210 @@
    (from hosts.h)
 */
 
-int cpqfcTS_biosparam(Disk *disk, kdev_t n, int ip[])
+int cpqfcTS_biosparam(Disk * disk, kdev_t n, int ip[])
 {
-  int size = disk->capacity;
-  
-  ENTER("cpqfcTS_biosparam");
-  ip[0] = 64;
-  ip[1] = 32;
-  ip[2] = size >> 11;
-  
-  if( ip[2] > 1024 )
-  {
-    ip[0] = 255;
-    ip[1] = 63;
-    ip[2] = size / (ip[0] * ip[1]);
-  }
-
-  LEAVE("cpqfcTS_biosparam");
-  return 0;
-}    
+	int size = disk->capacity;
 
+	ENTER("cpqfcTS_biosparam");
+	ip[0] = 64;
+	ip[1] = 32;
+	ip[2] = size >> 11;
+
+	if (ip[2] > 1024) {
+		ip[0] = 255;
+		ip[1] = 63;
+		ip[2] = size / (ip[0] * ip[1]);
+	}
 
+	LEAVE("cpqfcTS_biosparam");
+	return 0;
+}
 
-void cpqfcTS_intr_handler( int irq, 
-		void *dev_id, 
-		struct pt_regs *regs)
-{
-
-  unsigned long flags, InfLoopBrk=0;
-  struct Scsi_Host *HostAdapter = dev_id;
-  CPQFCHBA *cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata;
-  int MoreMessages = 1; // assume we have something to do
-  UCHAR IntPending;
-  
-  ENTER("intr_handler");
-
-  spin_lock_irqsave( &io_request_lock, flags);
-  // is this our INT?
-  IntPending = readb( cpqfcHBA->fcChip.Registers.INTPEND.address);
 
-  // broken boards can generate messages forever, so
-  // prevent the infinite loop
+
+void cpqfcTS_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+
+	unsigned long flags, InfLoopBrk = 0;
+	struct Scsi_Host *HostAdapter = dev_id;
+	CPQFCHBA *cpqfcHBA = (CPQFCHBA *) HostAdapter->hostdata;
+	int MoreMessages = 1;	// assume we have something to do
+	u8 IntPending;
+
+	ENTER("intr_handler");
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	// is this our INT?
+	IntPending = readb(cpqfcHBA->fcChip.Registers.INTPEND.address);
+
+	// broken boards can generate messages forever, so
+	// prevent the infinite loop
 #define INFINITE_IMQ_BREAK 10000
-  if( IntPending )
-  {
-    
-    // mask our HBA interrupts until we handle it...
-    writeb( 0, cpqfcHBA->fcChip.Registers.INTEN.address);
-
-    if( IntPending & 0x4) // "INT" - Tach wrote to IMQ
-    {
-      while( (++InfLoopBrk < INFINITE_IMQ_BREAK) && (MoreMessages ==1) ) 
-      {
-        MoreMessages = CpqTsProcessIMQEntry( HostAdapter); // ret 0 when done
-      }
-      if( InfLoopBrk >= INFINITE_IMQ_BREAK )
-      {
-        printk("WARNING: Compaq FC adapter generating excessive INTs -REPLACE\n");
-        printk("or investigate alternate causes (e.g. physical FC layer)\n");
-      }
-
-      else  // working normally - re-enable INTs and continue
-        writeb( 0x1F, cpqfcHBA->fcChip.Registers.INTEN.address);
-    
-    }  // (...ProcessIMQEntry() clears INT by writing IMQ consumer)
-    else  // indications of errors or problems...
-          // these usually indicate critical system hardware problems.
-    {
-      if( IntPending & 0x10 )
-  	printk(" cpqfcTS adapter external memory parity error detected\n");
-      if( IntPending & 0x8 )
-  	printk(" cpqfcTS adapter PCI master address crossed 45-bit boundary\n");
-      if( IntPending & 0x2 )
-	printk(" cpqfcTS adapter DMA error detected\n");
-      if( IntPending & 0x1 ) {
-  	UCHAR IntStat;
-  	printk(" cpqfcTS adapter PCI error detected\n");
-  	IntStat = readb( cpqfcHBA->fcChip.Registers.INTSTAT.address);
-	if (IntStat & 0x4) printk("(INT)\n");
-	if (IntStat & 0x8) 
-		printk("CRS: PCI master address crossed 46 bit bouandary\n");
-	if (IntStat & 0x10) printk("MRE: external memory parity error.\n");
-      }
-    }      
-  }
-  spin_unlock_irqrestore( &io_request_lock, flags);
-  LEAVE("intr_handler");
+	if (IntPending) {
+
+		// mask our HBA interrupts until we handle it...
+		writeb(0, cpqfcHBA->fcChip.Registers.INTEN.address);
+
+		if (IntPending & 0x4)	// "INT" - Tach wrote to IMQ
+		{
+			while ((++InfLoopBrk < INFINITE_IMQ_BREAK) && (MoreMessages == 1)) {
+				MoreMessages = CpqTsProcessIMQEntry(HostAdapter);	// ret 0 when done
+			}
+			if (InfLoopBrk >= INFINITE_IMQ_BREAK) {
+				printk("WARNING: Compaq FC adapter generating excessive INTs -REPLACE\n");
+				printk("or investigate alternate causes (e.g. physical FC layer)\n");
+			}
+
+			else	// working normally - re-enable INTs and continue
+				writeb(0x1F, cpqfcHBA->fcChip.Registers.INTEN.address);
+
+		}		// (...ProcessIMQEntry() clears INT by writing IMQ consumer)
+		else		// indications of errors or problems...
+			// these usually indicate critical system hardware problems.
+		{
+			if (IntPending & 0x10)
+				printk(" cpqfcTS adapter external memory parity error detected\n");
+			if (IntPending & 0x8)
+				printk(" cpqfcTS adapter PCI master address crossed 45-bit boundary\n");
+			if (IntPending & 0x2)
+				printk(" cpqfcTS adapter DMA error detected\n");
+			if (IntPending & 0x1) {
+				u8 IntStat;
+				printk(" cpqfcTS adapter PCI error detected\n");
+				IntStat = readb(cpqfcHBA->fcChip.Registers.INTSTAT.address);
+				if (IntStat & 0x4)
+					printk("(INT)\n");
+				if (IntStat & 0x8)
+					printk("CRS: PCI master address crossed 46 bit bouandary\n");
+				if (IntStat & 0x10)
+					printk("MRE: external memory parity error.\n");
+			}
+		}
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	LEAVE("intr_handler");
 }
 
 
 
 
-int cpqfcTSDecodeGBICtype( PTACHYON fcChip, char cErrorString[])
-{
-        // Verify GBIC type (if any) and correct Tachyon Port State Machine
-        // (GBIC) module definition is:
-        // GPIO1, GPIO0, GPIO4 for MD2, MD1, MD0.  The input states appear
-        // to be inverted -- i.e., a setting of 111 is read when there is NO
-        // GBIC present.  The Module Def (MD) spec says 000 is "no GBIC"
-        // Hard code the bit states to detect Copper, 
-        // Long wave (single mode), Short wave (multi-mode), and absent GBIC
-
-  ULONG ulBuff;
-
-  sprintf( cErrorString, "\nGBIC detected: ");
-
-  ulBuff = fcChip->Registers.TYstatus.value & 0x13; 
-  switch( ulBuff )
-  {
-  case 0x13:  // GPIO4, GPIO1, GPIO0 = 111; no GBIC!
-    sprintf( &cErrorString[ strlen( cErrorString)],
-            "NONE! ");
-    return FALSE;          
-          
-       
-  case 0x11:   // Copper GBIC detected
-    sprintf( &cErrorString[ strlen( cErrorString)],
-            "Copper. ");
-    break;
-
-  case 0x10:   // Long-wave (single mode) GBIC detected
-    sprintf( &cErrorString[ strlen( cErrorString)],
-        "Long-wave. ");
-    break;
-  case 0x1:    // Short-wave (multi mode) GBIC detected
-    sprintf( &cErrorString[ strlen( cErrorString)],
-        "Short-wave. ");
-    break;
-  default:     // unknown GBIC - presumably it will work (?)
-    sprintf( &cErrorString[ strlen( cErrorString)],
-            "Unknown. ");
-          
-    break;
-  }  // end switch GBIC detection
-
-  return TRUE;
-}
+int cpqfcTSDecodeGBICtype(PTACHYON fcChip, char cErrorString[])
+{
+	// Verify GBIC type (if any) and correct Tachyon Port State Machine
+	// (GBIC) module definition is:
+	// GPIO1, GPIO0, GPIO4 for MD2, MD1, MD0.  The input states appear
+	// to be inverted -- i.e., a setting of 111 is read when there is NO
+	// GBIC present.  The Module Def (MD) spec says 000 is "no GBIC"
+	// Hard code the bit states to detect Copper, 
+	// Long wave (single mode), Short wave (multi-mode), and absent GBIC
 
+	u32 ulBuff;
 
+	sprintf(cErrorString, "\nGBIC detected: ");
 
+	ulBuff = fcChip->Registers.TYstatus.value & 0x13;
+	switch (ulBuff) {
+	case 0x13:		// GPIO4, GPIO1, GPIO0 = 111; no GBIC!
+		sprintf(&cErrorString[strlen(cErrorString)], "NONE! ");
+		return FALSE;
 
 
+	case 0x11:		// Copper GBIC detected
+		sprintf(&cErrorString[strlen(cErrorString)], "Copper. ");
+		break;
+
+	case 0x10:		// Long-wave (single mode) GBIC detected
+		sprintf(&cErrorString[strlen(cErrorString)], "Long-wave. ");
+		break;
+	case 0x1:		// Short-wave (multi mode) GBIC detected
+		sprintf(&cErrorString[strlen(cErrorString)], "Short-wave. ");
+		break;
+	default:		// unknown GBIC - presumably it will work (?)
+		sprintf(&cErrorString[strlen(cErrorString)], "Unknown. ");
 
-int cpqfcTSGetLPSM( PTACHYON fcChip, char cErrorString[])
-{
-  // Tachyon's Frame Manager LPSM in LinkDown state?
-  // (For non-loop port, check PSM instead.)
-  // return string with state and FALSE is Link Down
-
-  int LinkUp;
-
-  if( fcChip->Registers.FMstatus.value & 0x80 ) 
-    LinkUp = FALSE;
-  else
-    LinkUp = TRUE;
-
-  sprintf( &cErrorString[ strlen( cErrorString)],
-    " LPSM %Xh ", 
-     (fcChip->Registers.FMstatus.value >>4) & 0xf );
-
-
-  switch( fcChip->Registers.FMstatus.value & 0xF0)
-  {
-                    // bits set in LPSM
-    case 0x10:
-      sprintf( &cErrorString[ strlen( cErrorString)], "ARB");
-      break;
-    case 0x20:
-      sprintf( &cErrorString[ strlen( cErrorString)], "ARBwon");
-      break;
-    case 0x30:
-      sprintf( &cErrorString[ strlen( cErrorString)], "OPEN");
-      break;
-    case 0x40:
-      sprintf( &cErrorString[ strlen( cErrorString)], "OPENed");
-      break;
-    case 0x50:
-      sprintf( &cErrorString[ strlen( cErrorString)], "XmitCLS");
-      break;
-    case 0x60:
-      sprintf( &cErrorString[ strlen( cErrorString)], "RxCLS");
-      break;
-    case 0x70:
-      sprintf( &cErrorString[ strlen( cErrorString)], "Xfer");
-      break;
-    case 0x80:
-      sprintf( &cErrorString[ strlen( cErrorString)], "Init");
-      break;
-    case 0x90:
-      sprintf( &cErrorString[ strlen( cErrorString)], "O-IInitFin");
-      break;
-    case 0xa0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "O-IProtocol");
-      break;
-    case 0xb0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "O-ILipRcvd");
-      break;
-    case 0xc0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "HostControl");
-      break;
-    case 0xd0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "LoopFail");
-      break;
-    case 0xe0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "Offline");
-      break;
-    case 0xf0:
-      sprintf( &cErrorString[ strlen( cErrorString)], "OldPort");
-      break;
-    case 0:
-    default:
-      sprintf( &cErrorString[ strlen( cErrorString)], "Monitor");
-      break;
-
-  }
+		break;
+	}			// end switch GBIC detection
 
-  return LinkUp;
+	return TRUE;
 }
 
 
 
 
-#include "linux/slab.h"
+
+
+int cpqfcTSGetLPSM(PTACHYON fcChip, char cErrorString[])
+{
+	// Tachyon's Frame Manager LPSM in LinkDown state?
+	// (For non-loop port, check PSM instead.)
+	// return string with state and FALSE is Link Down
+
+	int LinkUp;
+
+	if (fcChip->Registers.FMstatus.value & 0x80)
+		LinkUp = FALSE;
+	else
+		LinkUp = TRUE;
+
+	sprintf(&cErrorString[strlen(cErrorString)], " LPSM %Xh ", (fcChip->Registers.FMstatus.value >> 4) & 0xf);
+
+
+	switch (fcChip->Registers.FMstatus.value & 0xF0) {
+		// bits set in LPSM
+	case 0x10:
+		sprintf(&cErrorString[strlen(cErrorString)], "ARB");
+		break;
+	case 0x20:
+		sprintf(&cErrorString[strlen(cErrorString)], "ARBwon");
+		break;
+	case 0x30:
+		sprintf(&cErrorString[strlen(cErrorString)], "OPEN");
+		break;
+	case 0x40:
+		sprintf(&cErrorString[strlen(cErrorString)], "OPENed");
+		break;
+	case 0x50:
+		sprintf(&cErrorString[strlen(cErrorString)], "XmitCLS");
+		break;
+	case 0x60:
+		sprintf(&cErrorString[strlen(cErrorString)], "RxCLS");
+		break;
+	case 0x70:
+		sprintf(&cErrorString[strlen(cErrorString)], "Xfer");
+		break;
+	case 0x80:
+		sprintf(&cErrorString[strlen(cErrorString)], "Init");
+		break;
+	case 0x90:
+		sprintf(&cErrorString[strlen(cErrorString)], "O-IInitFin");
+		break;
+	case 0xa0:
+		sprintf(&cErrorString[strlen(cErrorString)], "O-IProtocol");
+		break;
+	case 0xb0:
+		sprintf(&cErrorString[strlen(cErrorString)], "O-ILipRcvd");
+		break;
+	case 0xc0:
+		sprintf(&cErrorString[strlen(cErrorString)], "HostControl");
+		break;
+	case 0xd0:
+		sprintf(&cErrorString[strlen(cErrorString)], "LoopFail");
+		break;
+	case 0xe0:
+		sprintf(&cErrorString[strlen(cErrorString)], "Offline");
+		break;
+	case 0xf0:
+		sprintf(&cErrorString[strlen(cErrorString)], "OldPort");
+		break;
+	case 0:
+	default:
+		sprintf(&cErrorString[strlen(cErrorString)], "Monitor");
+		break;
+
+	}
+
+	return LinkUp;
+}
 
 // Dynamic memory allocation alignment routines
 // HP's Tachyon Fibre Channel Controller chips require
@@ -1885,96 +1697,86 @@
 // we need about 8 allocations per HBA.  Figuring at most 10 HBAs per server
 // size the dynamic_mem array at 80.
 
-void* fcMemManager( struct pci_dev *pdev, ALIGNED_MEM *dynamic_mem, 
-		   ULONG n_alloc, ULONG ab, ULONG u32_AlignedAddress,
-			dma_addr_t *dma_handle)
-{
-  USHORT allocBoundary=1;   // compiler specific - worst case 1
-                                  // best case - replace malloc() call
-                                  // with function that allocates exactly
-                                  // at desired boundary
-
-  unsigned long ulAddress;
-  ULONG t_alloc, i;
-  void *alloc_address = 0;  // def. error code / address not found
-  LONG mask;                // must be 32-bits wide!
-
-  ENTER("fcMemManager");
-  if( u32_AlignedAddress )          // are we freeing existing memory?
-  {
+void *fcMemManager(struct pci_dev *pdev, ALIGNED_MEM * dynamic_mem, u32 n_alloc, u32 ab, u32 u32_AlignedAddress, dma_addr_t * dma_handle)
+{
+	u16 allocBoundary = 1;	// compiler specific - worst case 1
+	// best case - replace malloc() call
+	// with function that allocates exactly
+	// at desired boundary
+
+	unsigned long ulAddress;
+	u32 t_alloc, i;
+	void *alloc_address = 0;	// def. error code / address not found
+	s32 mask;		// must be 32-bits wide!
+
+	ENTER("fcMemManager");
+	if (u32_AlignedAddress)	// are we freeing existing memory?
+	{
 //    printk(" freeing AlignedAddress %Xh\n", u32_AlignedAddress);
-    for( i=0; i<DYNAMIC_ALLOCATIONS; i++) // look for the base address
-    {
+		for (i = 0; i < DYNAMIC_ALLOCATIONS; i++)	// look for the base address
+		{
 //    printk("dynamic_mem[%u].AlignedAddress %lX\n", i, dynamic_mem[i].AlignedAddress);
-      if( dynamic_mem[i].AlignedAddress == u32_AlignedAddress )
-      {
-        alloc_address = dynamic_mem[i].BaseAllocated; // 'success' status
-	pci_free_consistent(pdev,dynamic_mem[i].size, 
-				alloc_address, 
-				dynamic_mem[i].dma_handle);
-        dynamic_mem[i].BaseAllocated = 0;   // clear for next use
-        dynamic_mem[i].AlignedAddress = 0;
-        dynamic_mem[i].size = 0;
-        break;                        // quit for loop; done
-      }
-    }
-  }
-  else if( n_alloc )                   // want new memory?
-  {
-    dma_addr_t handle;
-    t_alloc = n_alloc + (ab - allocBoundary); // pad bytes for alignment
+			if (dynamic_mem[i].AlignedAddress == u32_AlignedAddress) {
+				alloc_address = dynamic_mem[i].BaseAllocated;	// 'success' status
+				pci_free_consistent(pdev, dynamic_mem[i].size, alloc_address, dynamic_mem[i].dma_handle);
+				dynamic_mem[i].BaseAllocated = 0;	// clear for next use
+				dynamic_mem[i].AlignedAddress = 0;
+				dynamic_mem[i].size = 0;
+				break;	// quit for loop; done
+			}
+		}
+	} else if (n_alloc)	// want new memory?
+	{
+		dma_addr_t handle;
+		t_alloc = n_alloc + (ab - allocBoundary);	// pad bytes for alignment
 //    printk("pci_alloc_consistent() for Tach alignment: %ld bytes\n", t_alloc);
 
 // (would like to) allow thread block to free pages 
-    alloc_address =                  // total bytes (NumberOfBytes)
-      pci_alloc_consistent(pdev, t_alloc, &handle); 
+		alloc_address =	// total bytes (NumberOfBytes)
+		    pci_alloc_consistent(pdev, t_alloc, &handle);
 
-                                  // now mask off least sig. bits of address
-    if( alloc_address )           // (only if non-NULL)
-    {
-                                  // find place to store ptr, so we
-                                  // can free it later...
-
-      mask = (LONG)(ab - 1);            // mask all low-order bits
-      mask = ~mask;                            // invert bits
-      for( i=0; i<DYNAMIC_ALLOCATIONS; i++) // look for free slot
-      {
-        if( dynamic_mem[i].BaseAllocated == 0) // take 1st available
-        {
-          dynamic_mem[i].BaseAllocated = alloc_address;// address from O/S
-          dynamic_mem[i].dma_handle = handle;
-	  if (dma_handle != NULL) 
-	  {
+		// now mask off least sig. bits of address
+		if (alloc_address)	// (only if non-NULL)
+		{
+			// find place to store ptr, so we
+			// can free it later...
+
+			mask = (s32) (ab - 1);	// mask all low-order bits
+			mask = ~mask;	// invert bits
+			for (i = 0; i < DYNAMIC_ALLOCATIONS; i++)	// look for free slot
+			{
+				if (dynamic_mem[i].BaseAllocated == 0)	// take 1st available
+				{
+					dynamic_mem[i].BaseAllocated = alloc_address;	// address from O/S
+					dynamic_mem[i].dma_handle = handle;
+					if (dma_handle != NULL) {
 //             printk("handle = %p, ab=%d, boundary = %d, mask=0x%08x\n", 
-//			handle, ab, allocBoundary, mask);
-	    *dma_handle = (dma_addr_t) 
-		((((ULONG)handle) + (ab - allocBoundary)) & mask);
-	  }
-          dynamic_mem[i].size = t_alloc;
-          break;
-        }
-      }
-      ulAddress = (unsigned long)alloc_address;
-      
-      ulAddress += (ab - allocBoundary);    // add the alignment bytes-
-                                            // then truncate address...
-      alloc_address = (void*)(ulAddress & mask);
-      
-      dynamic_mem[i].AlignedAddress = 
-	(ULONG)(ulAddress & mask); // 32bit Tach address
-      memset( alloc_address, 0, n_alloc );  // clear new memory
-    }
-    else  // O/S dynamic mem alloc failed!
-      alloc_address = 0;  // (for debugging breakpt)
+//                      handle, ab, allocBoundary, mask);
+						*dma_handle = (dma_addr_t)
+						    ((((u32) handle) + (ab - allocBoundary)) & mask);
+					}
+					dynamic_mem[i].size = t_alloc;
+					break;
+				}
+			}
+			ulAddress = (unsigned long) alloc_address;
+
+			ulAddress += (ab - allocBoundary);	// add the alignment bytes-
+			// then truncate address...
+			alloc_address = (void *) (ulAddress & mask);
+
+			dynamic_mem[i].AlignedAddress = (u32) (ulAddress & mask);	// 32bit Tach address
+			memset(alloc_address, 0, n_alloc);	// clear new memory
+		} else		// O/S dynamic mem alloc failed!
+			alloc_address = 0;	// (for debugging breakpt)
 
-  }
+	}
 
-  LEAVE("fcMemManager");
-  return alloc_address;  // good (or NULL) address
+	LEAVE("fcMemManager");
+	return alloc_address;	// good (or NULL) address
 }
 
 
 static Scsi_Host_Template driver_template = CPQFCTS;
 
 #include "scsi_module.c"
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/cpqfcTSioctl.h linux.20pre10-ac2/drivers/scsi/cpqfcTSioctl.h
--- linux.20pre10/drivers/scsi/cpqfcTSioctl.h	2002-10-09 21:36:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/cpqfcTSioctl.h	2002-09-12 14:26:06.000000000 +0100
@@ -4,71 +4,38 @@
 
 #define CCPQFCTS_IOC_MAGIC 'Z'
 
-typedef struct 
-{
-  __u8 bus;
-  __u8 dev_fn;
-  __u32 board_id;
+typedef struct {
+	__u8 bus;
+	__u8 dev_fn;
+	__u32 board_id;
 } cpqfc_pci_info_struct;
 
 typedef __u32 DriverVer_type;
-/*
-typedef union
-{
-  struct  // Peripheral Unit Device
-  { 
-    __u8 Bus:6;
-    __u8 Mode:2;  // b00
-    __u8 Dev;
-  } PeripDev;
-  struct  // Volume Set Address
-  { 
-    __u8 DevMSB:6;
-    __u8 Mode:2;  // b01
-    __u8 DevLSB;
-  } LogDev;
-  struct  // Logical Unit Device (SCSI-3, SCC-2 defined)
-  { 
-    __u8 Targ:6;
-    __u8 Mode:2;  // b10
-    __u8 Dev:5;
-    __u8 Bus:3;
-
-  } LogUnit;
-} SCSI3Addr_struct;
-
-
-typedef struct
-{
-  SCSI3Addr_struct FCP_Nexus;
-  __u8 cdb[16];
-} PassThru_Command_struct;
-*/
 
 /* this is nearly duplicated in idashare.h */
 typedef struct {
-  int	lc;    		/* Controller number */
-  int	node;		/* Node (box) number */
-  int	ld;		/* Logical Drive on this box, if required */
-  __u32 nexus;          /* SCSI Nexus */
-  void	*argp;		/* Argument pointer */
+	int lc;			/* Controller number */
+	int node;		/* Node (box) number */
+	int ld;			/* Logical Drive on this box, if required */
+	__u32 nexus;		/* SCSI Nexus */
+	void *argp;		/* Argument pointer */
 } VENDOR_IOCTL_REQ;
 
 
 typedef struct {
-  char	cdb[16];	/* SCSI CDB for the pass-through */
-  ushort bus;		/* Target bus on the box */
-  ushort pdrive;	/* Physical drive on the box */
-  int len;              /* Length of the data area of the CDB */
-  int sense_len;	/* Length of the sense data */
-  char sense_data[40];  /* Sense data */
-  void *bufp;		/* Data area for the CDB */
-  char rw_flag;		/* Read CDB or Write CDB */
+	char cdb[16];		/* SCSI CDB for the pass-through */
+	ushort bus;		/* Target bus on the box */
+	ushort pdrive;		/* Physical drive on the box */
+	int len;		/* Length of the data area of the CDB */
+	int sense_len;		/* Length of the sense data */
+	char sense_data[40];	/* Sense data */
+	void *bufp;		/* Data area for the CDB */
+	char rw_flag;		/* Read CDB or Write CDB */
 } cpqfc_passthru_t;
 
 /*
-** Defines for the IOCTLS.
-*/
+ * Defines for the IOCTLS.
+ */
 
 #define VENDOR_READ_OPCODE			0x26
 #define VENDOR_WRITE_OPCODE			0x27
@@ -78,17 +45,22 @@
 
 #define CPQFCTS_SCSI_PASSTHRU _IOWR( CCPQFCTS_IOC_MAGIC,11, VENDOR_IOCTL_REQ)
 
-/* We would rather have equivalent generic, low-level driver agnostic 
-ioctls that do what CPQFC_IOCTL_FC_TARGET_ADDRESS and 
-CPQFC_IOCTL_FC_TDR 0x5388 do, but currently, we do not have them, 
-consequently applications would have to know they are talking to cpqfc. */
-   
-/* Used to get Fibre Channel WWN and port_id from device */
-// #define CPQFC_IOCTL_FC_TARGET_ADDRESS 0x5387
+/*
+ *	We would rather have equivalent generic, low-level driver agnostic 
+ *	ioctls that do what CPQFC_IOCTL_FC_TARGET_ADDRESS and 
+ *	CPQFC_IOCTL_FC_TDR 0x5388 do, but currently, we do not have them, 
+ *	consequently applications would have to know they are talking to cpqfc.
+ */
+
+/*
+ *	Used to get Fibre Channel WWN and port_id from device
+ */
+
 #define CPQFC_IOCTL_FC_TARGET_ADDRESS \
 	_IOR( CCPQFCTS_IOC_MAGIC, 13, Scsi_FCTargAddress)
 
-/* Used to invoke Target Defice Reset for Fibre Channel */
-// #define CPQFC_IOCTL_FC_TDR 0x5388
+/*
+ *	Used to invoke Target Defice Reset for Fibre Channel
+ */
+ 
 #define CPQFC_IOCTL_FC_TDR _IO( CCPQFCTS_IOC_MAGIC, 15)
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/cpqfcTSstructs.h linux.20pre10-ac2/drivers/scsi/cpqfcTSstructs.h
--- linux.20pre10/drivers/scsi/cpqfcTSstructs.h	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/cpqfcTSstructs.h	2002-10-09 22:15:47.000000000 +0100
@@ -17,77 +17,83 @@
  * General Public License for more details.
  * Written by Don Zimmerman
 */
+
 #ifndef CPQFCTSSTRUCTS_H
 #define CPQFCTSSTRUCTS_H
 
-#include <linux/timer.h>  // timer declaration in our host data
-#include <linux/tqueue.h> // task queue sched
+#include <linux/timer.h>	// timer declaration in our host data
+#include <linux/tqueue.h>	// task queue sched
 #include <asm/atomic.h>
 #include "cpqfcTSioctl.h"
 
+/* FIXME - this is crap */
 #define DbgDelay(secs) { int wait_time; printk( " DbgDelay %ds ", secs); \
                          for( wait_time=jiffies + (secs*HZ); \
 		         time_before(jiffies, wait_time) ;) ; }
 
 #define CPQFCTS_DRIVER_VER(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-// don't forget to also change MODULE_DESCRIPTION in cpqfcTSinit.c
+/* don't forget to also change MODULE_DESCRIPTION in cpqfcTSinit.c */
 #define VER_MAJOR 2
 #define VER_MINOR 1
 #define VER_SUBMINOR 1
 
-// Macros for kernel (esp. SMP) tracing using a PCI analyzer
-// (e.g. x86).
+/*
+ *	Macros for kernel (esp. SMP) tracing using a PCI analyzer
+ *	(e.g. x86).
+ */
+ 
 //#define PCI_KERNEL_TRACE
 #ifdef PCI_KERNEL_TRACE
-#define PCI_TRACE(x) inl( fcChip->Registers.IOBaseL +x);
-#define PCI_TRACEO(x,y) outl( x, (fcChip->Registers.IOBaseL +y));
+#define PCI_TRACE(x)		inl( fcChip->Registers.IOBaseL +x);
+#define PCI_TRACEO(x,y) 	outl( x, (fcChip->Registers.IOBaseL +y));
 #else
 
-#define PCI_TRACE(x) 
+#define PCI_TRACE(x)
 #define PCI_TRACEO(x,y)
 #endif
 
-			 
-//#define DEBUG_CMND 1   // debug output for Linux Scsi CDBs
-//#define DUMMYCMND_DBG 1
+
+//#define DEBUG_CMND		1   // debug output for Linux Scsi CDBs
+//#define DUMMYCMND_DBG		1
 
 //#define DEBUG_CPQFCTS 1
 //#undef DEBUG_CPQFCTS 
 #ifdef DEBUG_CPQFCTS
-#define ENTER(x)	printk("cpqfcts : entering %s()\n", x);
-#define LEAVE(x)	printk("cpqfcts : leaving %s()\n", x);
-#define DEBUG(x)	x
+#define ENTER(x)		printk("cpqfcts : entering %s()\n", x);
+#define LEAVE(x)		printk("cpqfcts : leaving %s()\n", x);
+#define DEBUG(x)		x
 #else
 #define ENTER(x)
 #define LEAVE(x)
 #define DEBUG(x)
 #endif				/* DEBUG_CPQFCTS */
 
-//#define DEBUG_CPQFCTS_PCI 1
+//#define DEBUG_CPQFCTS_PCI	1
 //#undef DEBUG_CPQFCTS_PCI
 #if DEBUG_CPQFCTS_PCI
-#define DEBUG_PCI(x)	x
+#define DEBUG_PCI(x)		x
 #else
 #define DEBUG_PCI(x)
 #endif				/* DEBUG_CPQFCTS_PCI */
 
-#define STACHLITE66_TS12  "Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.2"
-#define STACHLITE66_TS13  "Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.3"
-#define STACHLITE_UNKNOWN "Compaq FibreChannel HBA Tachyon Chip/Board Ver??"
-#define SAGILENT_XL2_21   "Agilent FC HBA, Tachyon XL2 HPFC-5200B/2.1"
+#define STACHLITE66_TS12	"Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.2"
+#define STACHLITE66_TS13	"Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.3"
+#define STACHLITE_UNKNOWN	"Compaq FibreChannel HBA Tachyon Chip/Board Ver??"
+#define SAGILENT_XL2_21		"Agilent FC HBA, Tachyon XL2 HPFC-5200B/2.1"
 
 // PDA is Peripheral Device Address, VSA is Volume Set Addressing
 // Linux SCSI parameters
-#define CPQFCTS_MAX_TARGET_ID 64
+#define CPQFCTS_MAX_TARGET_ID	64
 
 // Note, changing CPQFCTS_MAX_LUN to less than 32 (e.g, 8) will result in
 // strange behavior if a box with more than, e.g. 8, is on the loop.
-#define CPQFCTS_MAX_LUN 32    // The RA-4x00 supports 32 (Linux SCSI supports 8)
-#define CPQFCTS_MAX_CHANNEL 0 // One FC port on cpqfcTS HBA
+#define CPQFCTS_MAX_LUN		32	// The RA-4x00 supports 32 (Linux SCSI supports 8)
+#define CPQFCTS_MAX_CHANNEL 	0	// One FC port on cpqfcTS HBA
 
-#define CPQFCTS_CMD_PER_LUN 15 // power of 2 -1, must be >0 
-#define CPQFCTS_REQ_QUEUE_LEN (TACH_SEST_LEN/2) // must be < TACH_SEST_LEN
+#define CPQFCTS_CMD_PER_LUN	15	// power of 2 -1, must be >0
+#define CPQFCTS_REQ_QUEUE_LEN	(TACH_SEST_LEN/2)	// must be < TACH_SEST_LEN
 
+/* FIMXME - these are crpa too */
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
 #ifndef DECLARE_MUTEX_LOCKED
 #define DECLARE_MUTEX_LOCKED(sem) struct semaphore sem = MUTEX_LOCKED
@@ -95,205 +101,194 @@
 
 #define DEV_NAME "cpqfcTS"
 
-struct SupportedPCIcards
-{
-  __u16 vendor_id;
-  __u16 device_id;
+struct SupportedPCIcards {
+	__u16 vendor_id;
+	__u16 device_id;
 };
-			 
-// nn:nn denotes bit field
-                            // TachyonHeader struct def.
-                            // the fields shared with ODB
-                            // need to have same value
-
-
-
-
-#ifndef BYTE
-//typedef UCHAR BYTE;
-typedef __u8 BYTE;
-#endif
-#ifndef UCHAR
-typedef __u8 UCHAR;
-#endif
-#ifndef LONG
-typedef __s32 LONG;
-#endif
-#ifndef ULONG
-typedef __u32 ULONG;
-#endif
-#ifndef PVOID
-typedef void * PVOID;
-#endif
-#ifndef USHORT
-typedef __u16 USHORT;
-#endif
-#ifndef BOOLEAN
-typedef __u8 BOOLEAN;
-#endif
-
-
-// macro for FC-PH reject codes
-// payload format for LS_RJT (FC payloads are big endian):
-//     byte  0         1         2         3  (MSB)
-// DWORD 0   01        00        00        00
-// DWORD 1   resvd     code      expl.     vendor
 
+/*
+ *	nn:nn denotes bit field
+ *	TachyonHeader struct def.
+ *	the fields shared with ODB
+ *	need to have same value
+ */
+ 
+/*
+ * macro for FC-PH reject codes
+ * payload format for LS_RJT (FC payloads are big endian):
+ *     byte  0         1         2         3  (MSB)
+ * DWORD 0   01        00        00        00
+ * DWORD 1   resvd     code      expl.     vendor
+ */
 #define LS_RJT_REASON( code, expl) (( code<<8) | (expl <<16))
 
-
 #define TachLiteSTATUS 0x12
 
-// Fibre Channel EXCHANGE status codes for Tachyon chips/ driver software
-// 32-bit ERROR word defines
-#define INVALID_ARGS 0x1
-#define LNKDWN_OSLS  0x2
-#define LNKDWN_LASER 0x4
-#define OUTQUE_FULL  0x8
-#define DRIVERQ_FULL 0x10
-#define SEST_FULL    0x20
-#define BAD_ALPA     0x40
-#define OVERFLOW     0x80  // inbound CM
-#define COUNT_ERROR     0x100  // inbound CM
-#define LINKFAIL_RX     0x200  // inbound CM
-#define ABORTSEQ_NOTIFY 0x400  // outbound CM
-#define LINKFAIL_TX     0x800  // outbound CM
-#define HOSTPROG_ERR     0x1000  // outbound CM
-#define FRAME_TO         0x2000  // outbound CM
-#define INV_ENTRY        0x4000  // outbound CM
-#define SESTPROG_ERR     0x8000  // outbound CM
-#define OUTBOUND_TIMEOUT 0x10000L // timeout waiting for Tachyon outbound CM
-#define INITIATOR_ABORT  0x20000L // initiator exchange timeout or O/S ABORT
-#define MEMPOOL_FAIL     0x40000L // O/S memory pool allocation failed
-#define FC2_TIMEOUT      0x80000L // driver timeout for lost frames
-#define TARGET_ABORT     0x100000L // ABTS received from FC port
-#define EXCHANGE_QUEUED  0x200000L // e.g. Link State was LDn on fcStart
-#define PORTID_CHANGED   0x400000L // fc Port address changed
-#define DEVICE_REMOVED   0x800000L // fc Port address changed
-// Several error scenarios result in SEST Exchange frames 
-// unexpectedly arriving in the SFQ
-#define SFQ_FRAME        0x1000000L // SFQ frames from open Exchange
-
-// Maximum number of Host Bus Adapters (HBA) / controllers supported
-// only important for mem allocation dimensions - increase as necessary
-
+/*
+ *	Fibre Channel EXCHANGE status codes for Tachyon chips/ driver software
+ *	32-bit ERROR word defines
+ */
+#define INVALID_ARGS 		0x1
+#define LNKDWN_OSLS  		0x2
+#define LNKDWN_LASER 		0x4
+#define OUTQUE_FULL  		0x8
+#define DRIVERQ_FULL 		0x10
+#define SEST_FULL    		0x20
+#define BAD_ALPA     		0x40
+#define OVERFLOW     		0x80		// inbound CM
+#define COUNT_ERROR     	0x100		// inbound CM
+#define LINKFAIL_RX     	0x200		// inbound CM
+#define ABORTSEQ_NOTIFY 	0x400		// outbound CM
+#define LINKFAIL_TX     	0x800		// outbound CM
+#define HOSTPROG_ERR     	0x1000		// outbound CM
+#define FRAME_TO         	0x2000		// outbound CM
+#define INV_ENTRY        	0x4000		// outbound CM
+#define SESTPROG_ERR     	0x8000		// outbound CM
+#define OUTBOUND_TIMEOUT 	0x10000L	// timeout waiting for Tachyon outbound CM
+#define INITIATOR_ABORT  	0x20000L	// initiator exchange timeout or O/S ABORT
+#define MEMPOOL_FAIL     	0x40000L	// O/S memory pool allocation failed
+#define FC2_TIMEOUT      	0x80000L	// driver timeout for lost frames
+#define TARGET_ABORT     	0x100000L	// ABTS received from FC port
+#define EXCHANGE_QUEUED  	0x200000L	// e.g. Link State was LDn on fcStart
+#define PORTID_CHANGED   	0x400000L	// fc Port address changed
+#define DEVICE_REMOVED   	0x800000L	// fc Port address changed
+/*
+ *	Several error scenarios result in SEST Exchange frames 
+ *	unexpectedly arriving in the SFQ
+ */
+#define SFQ_FRAME		0x1000000L	// SFQ frames from open Exchange
+
+/*
+ *	Maximum number of Host Bus Adapters (HBA) / controllers supported
+ *	only important for mem allocation dimensions - increase as necessary
+ */
+ 
 #define MAX_ADAPTERS 8
-#define MAX_RX_PAYLOAD 1024  // hardware dependent max frame payload
-// Tach header struc defines
-#define SOFi3 0x7
-#define SOFf  0x8
-#define SOFn3 0xB
-#define EOFn  0x5
-#define EOFt  0x6
+#define MAX_RX_PAYLOAD 1024			// hardware dependent max frame payload
+
+/*
+ *	Tach header struct defines
+ */
+
+#define SOFi3			0x7
+#define SOFf			0x8
+#define SOFn3			0xB
+#define EOFn			0x5
+#define EOFt			0x6
 
 // FCP R_CTL defines
-#define FCP_CMND 0x6
-#define FCP_XFER_RDY 0x5
-#define FCP_RSP 0x7
-#define FCP_RESPONSE 0x777 // (arbitrary #)
-#define NEED_FCP_RSP 0x77  // (arbitrary #)
-#define FCP_DATA 0x1
-
-#define RESET_TACH 0x100 // Reset Tachyon/TachLite
-#define SCSI_IWE 0x2000  // initiator write entry (for SEST)
-#define SCSI_IRE 0x3000  // initiator read entry (for SEST)
-#define SCSI_TRE 0x400  // target read entry (for SEST)
-#define SCSI_TWE 0x500  // target write entry (for SEST)
-#define TOGGLE_LASER 0x800
-#define LIP 0x900
-#define CLEAR_FCPORTS 99 // (arbitrary #) free mem for Logged in ports
-#define FMINIT 0x707     // (arbitrary) for Frame Manager Init command
-
-// BLS == Basic Link Service
-// ELS == Extended Link Service
-#define BLS_NOP 4
-#define BLS_ABTS 0x10   // FC-PH Basic Link Service Abort Sequence
-#define BLS_ABTS_ACC 0x100  // FC-PH Basic Link Service Abort Sequence Accept
-#define BLS_ABTS_RJT 0x101  // FC-PH Basic Link Service Abort Sequence Reject
-#define ELS_PLOGI 0x03  // FC-PH Port Login (arbitrary assign)
-#define ELS_SCR   0x70  // (arb assign) State Change Registration (Fabric)
-#define FCS_NSR   0x72  // (arb assign) Name Service Request (Fabric)
-#define ELS_FLOGI 0x44  // (arb assign) Fabric Login
-#define ELS_FDISC 0x41  // (arb assign) Fabric Discovery (Login)
-#define ELS_PDISC 0x50  // FC-PH2 Port Discovery
-#define ELS_ABTX  0x06  // FC-PH Abort Exchange 
-#define ELS_LOGO 0x05   // FC-PH Port Logout
-#define ELS_PRLI 0x20   // FCP-SCSI Process Login
-#define ELS_PRLO 0x21   // FCP-SCSI Process Logout
-#define ELS_LOGO_ACC 0x07   // {FC-PH} Port Logout Accept
-#define ELS_PLOGI_ACC 0x08  // {FC-PH} Port Login Accept
-#define ELS_ACC 0x18        // {FC-PH} (generic) ACCept
-#define ELS_PRLI_ACC 0x22  // {FCP-SCSI} Process Login Accept
-#define ELS_RJT 0x1000000
-#define SCSI_REPORT_LUNS 0x0A0
-#define REPORT_LUNS 0xA0 // SCSI-3 command op-code
-#define FCP_TARGET_RESET 0x200
-
-#define ELS_LILP_FRAME 0x00000711 // 1st payload word of LILP frame
-
-#define SFQ_UNASSISTED_FCP  1  // ICM, DWord3, "Type" unassisted FCP
-#define SFQ_UNKNOWN         0x31 // (arbitrary) ICM, DWord3, "Type" unknown
-
-// these "LINK" bits refer to loop or non-loop
-#define LINKACTIVE 0x2    // fcLinkQ type - LINK UP Tachyon FM 'Lup' bit set
-#define LINKDOWN 0xf2     // fcLinkQ type - LINK DOWN Tachyon FM 'Ldn' bit set
+#define FCP_CMND		0x6
+#define FCP_XFER_RDY		0x5
+#define FCP_RSP			0x7
+#define FCP_RESPONSE		0x777		// (arbitrary #)
+#define NEED_FCP_RSP		0x77		// (arbitrary #)
+#define FCP_DATA		0x1
+
+#define RESET_TACH 		0x100		// Reset Tachyon/TachLite
+#define SCSI_IWE 		0x2000		// initiator write entry (for SEST)
+#define SCSI_IRE 		0x3000		// initiator read entry (for SEST)
+#define SCSI_TRE 		0x400		// target read entry (for SEST)
+#define SCSI_TWE 		0x500		// target write entry (for SEST)
+#define TOGGLE_LASER 		0x800
+#define LIP			0x900
+#define CLEAR_FCPORTS		99		// (arbitrary #) free mem for Logged in ports
+#define FMINIT			0x707		// (arbitrary) for Frame Manager Init command
+
+/*
+ *	BLS == Basic Link Service
+ *	ELS == Extended Link Service
+ */
+ 
+#define BLS_NOP 		4
+#define BLS_ABTS		0x10		// FC-PH Basic Link Service Abort Sequence
+#define BLS_ABTS_ACC		0x100		// FC-PH Basic Link Service Abort Sequence Accept
+#define BLS_ABTS_RJT		0x101		// FC-PH Basic Link Service Abort Sequence Reject
+#define ELS_PLOGI		0x03		// FC-PH Port Login (arbitrary assign)
+#define ELS_SCR			0x70		// (arb assign) State Change Registration (Fabric)
+#define FCS_NSR			0x72		// (arb assign) Name Service Request (Fabric)
+#define ELS_FLOGI		0x44		// (arb assign) Fabric Login
+#define ELS_FDISC		0x41		// (arb assign) Fabric Discovery (Login)
+#define ELS_PDISC		0x50		// FC-PH2 Port Discovery
+#define ELS_ABTX		0x06		// FC-PH Abort Exchange
+#define ELS_LOGO		0x05		// FC-PH Port Logout
+#define ELS_PRLI		0x20		// FCP-SCSI Process Login
+#define ELS_PRLO		0x21		// FCP-SCSI Process Logout
+#define ELS_LOGO_ACC		0x07		// {FC-PH} Port Logout Accept
+#define ELS_PLOGI_ACC		0x08		// {FC-PH} Port Login Accept
+#define ELS_ACC			0x18		// {FC-PH} (generic) ACCept
+#define ELS_PRLI_ACC		0x22		// {FCP-SCSI} Process Login Accept
+#define ELS_RJT			0x1000000
+#define SCSI_REPORT_LUNS	0x0A0
+#define REPORT_LUNS		0xA0		// SCSI-3 command op-code
+#define FCP_TARGET_RESET	0x200
+
+#define ELS_LILP_FRAME		0x00000711	// 1st payload word of LILP frame
+
+#define SFQ_UNASSISTED_FCP	1		// ICM, DWord3, "Type" unassisted FCP
+#define SFQ_UNKNOWN      	0x31		// (arbitrary) ICM, DWord3, "Type" unknown
+
+/*
+ * These "LINK" bits refer to loop or non-loop
+ */
+#define LINKACTIVE		0x2		// fcLinkQ type - LINK UP Tachyon FM 'Lup' bit set
+#define LINKDOWN		0xf2		// fcLinkQ type - LINK DOWN Tachyon FM 'Ldn' bit set
 
 //#define VOLUME_SET_ADDRESSING 1 // "channel" or "bus" 1
 
-typedef struct      // 32 bytes hdr ONLY (e.g. FCP_DATA buffer for SEST)
+typedef struct			// 32 bytes hdr ONLY (e.g. FCP_DATA buffer for SEST)
 {
-  ULONG reserved;   // dword 0 (don't use)
-  ULONG sof_eof;
-  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
-  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
-  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
-  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
-  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
-  ULONG ro;         // dword 7 - relative offset
+	__u32 reserved;		// dword 0 (don't use)
+	__u32 sof_eof;
+	__u32 d_id;		// dword 2 - 31:24 R_CTL, 23:0 D_ID
+	__u32 s_id;		// dword 3 - 31:24 CS_CTL, 23:0 S_ID
+	__u32 f_ctl;		// dword 4 - 31:24 Type,  23:0 F_CTL
+	__u32 seq_cnt;		// dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
+	__u32 ox_rx_id;		// dword 6 - 31:16 OX_ID,  15:0 RX_ID
+	__u32 ro;		// dword 7 - relative offset
 } TachFCHDR;
 
-                    // NOTE!! the following struct MUST be 64 bytes.
-typedef struct      // 32 bytes hdr + 32 bytes payload
+				// NOTE!! the following struct MUST be 64 bytes.
+typedef struct			// 32 bytes hdr + 32 bytes payload
 {
-  ULONG reserved;   // dword 0 (don't use - must clear to 0)
-  ULONG sof_eof;    // dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
-  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
-  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
-  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
-  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
-  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
-  ULONG ro;  // dword 7 - relative offset
+	__u32 reserved;		// dword 0 (don't use - must clear to 0)
+	__u32 sof_eof;		// dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
+	__u32 d_id;		// dword 2 - 31:24 R_CTL, 23:0 D_ID
+	__u32 s_id;		// dword 3 - 31:24 CS_CTL, 23:0 S_ID
+	__u32 f_ctl;		// dword 4 - 31:24 Type,  23:0 F_CTL
+	__u32 seq_cnt;		// dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
+	__u32 ox_rx_id;		// dword 6 - 31:16 OX_ID,  15:0 RX_ID
+	__u32 ro;		// dword 7 - relative offset
 //---------
-  __u32 pl[8];              // dwords 8-15 frame data payload
+	__u32 pl[8];		// dwords 8-15 frame data payload
 } TachFCHDR_CMND;
 
 
-typedef struct      // 32 bytes hdr + 120 bytes payload
+typedef struct			// 32 bytes hdr + 120 bytes payload
 {
-  ULONG reserved;   // dword 0 (don't use - must clear to 0)
-  ULONG sof_eof;    // dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
-  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
-  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
-  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
-  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
-  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
-  ULONG ro;  // dword 7 - relative offset
+	__u32 reserved;		// dword 0 (don't use - must clear to 0)
+	__u32 sof_eof;		// dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
+	__u32 d_id;		// dword 2 - 31:24 R_CTL, 23:0 D_ID
+	__u32 s_id;		// dword 3 - 31:24 CS_CTL, 23:0 S_ID
+	__u32 f_ctl;		// dword 4 - 31:24 Type,  23:0 F_CTL
+	__u32 seq_cnt;		// dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
+	__u32 ox_rx_id;		// dword 6 - 31:16 OX_ID,  15:0 RX_ID
+	__u32 ro;		// dword 7 - relative offset
 //---------
-  __u32 pl[30];              // largest necessary payload (for LOGIN cmnds)
+	__u32 pl[30];		// largest necessary payload (for LOGIN cmnds)
 } TachFCHDR_GCMND;
 
-typedef struct      // 32 bytes hdr + 64 bytes payload
+typedef struct			// 32 bytes hdr + 64 bytes payload
 {
-  ULONG reserved;   // dword 0 (don't use)
-  ULONG sof_eof;
-  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
-  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
-  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
-  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
-  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
-  ULONG ro;  // dword 7 - relative offset
+	__u32 reserved;		// dword 0 (don't use)
+	__u32 sof_eof;
+	__u32 d_id;		// dword 2 - 31:24 R_CTL, 23:0 D_ID
+	__u32 s_id;		// dword 3 - 31:24 CS_CTL, 23:0 S_ID
+	__u32 f_ctl;		// dword 4 - 31:24 Type,  23:0 F_CTL
+	__u32 seq_cnt;		// dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
+	__u32 ox_rx_id;		// dword 6 - 31:16 OX_ID,  15:0 RX_ID
+	__u32 ro;		// dword 7 - relative offset
 //---------
-  __u32 pl[18]; // payload for FCP-RSP (response buffer) RA-4x00 is 72bytes
+	__u32 pl[18];		// payload for FCP-RSP (response buffer) RA-4x00 is 72bytes
 } TachFCHDR_RSP;
 
 
@@ -302,11 +297,11 @@
 
 
 // Inbound Message Queue structures...
-typedef struct              // each entry 8 words (32 bytes)
+typedef struct			// each entry 8 words (32 bytes)
 {
-  ULONG type;               // IMQ completion message types
-  ULONG word[7];            // remainder of structure
-                            // interpreted by IMQ type
+	__u32 type;		// IMQ completion message types
+	__u32 word[7];		// remainder of structure
+				// interpreted by IMQ type
 } TachyonIMQE;
 
 
@@ -314,114 +309,114 @@
 // ERQ       - Exchange Request Queue (for outbound commands)
 // SFQ       - Single Frame Queue (for incoming frames)
 
-                            // Define Tachyon Outbound Command Que
-                            // (Since many Tachyon registers are Read
-                            // only, maintain copies for debugging)
-                            // most Tach ques need power-of-2 sizes,
-                            // where registers are loaded with po2 -1
-#define TACH_SEST_LEN 512   // TachLite SEST
+				// Define Tachyon Outbound Command Que
+				// (Since many Tachyon registers are Read
+				// only, maintain copies for debugging)
+				// most Tach ques need power-of-2 sizes,
+				// where registers are loaded with po2 -1
+#define TACH_SEST_LEN 512	// TachLite SEST
 
-#define ELS_EXCHANGES 64    // e.g. PLOGI, RSCN, ...
+#define ELS_EXCHANGES 64	// e.g. PLOGI, RSCN, ...
 // define the total number of outstanding (simultaneous) exchanges
-#define TACH_MAX_XID (TACH_SEST_LEN + ELS_EXCHANGES)  // ELS exchanges
+#define TACH_MAX_XID (TACH_SEST_LEN + ELS_EXCHANGES)	// ELS exchanges
 
-#define ERQ_LEN 128         // power of 2, max 4096
+#define ERQ_LEN 128		// power of 2, max 4096
 
 // Inbound Message Queue structures...
-#define IMQ_LEN 512              // minimum 4 entries [(power of 2) - 1]
-typedef struct                   // 8 words - 32 bytes
+#define IMQ_LEN 512		// minimum 4 entries [(power of 2) - 1]
+typedef struct			// 8 words - 32 bytes
 {
-  TachyonIMQE QEntry[IMQ_LEN];
-  ULONG producerIndex;   // IMQ Producer Index register
-                                 // @32 byte align
-  ULONG consumerIndex;   // Consumer Index register (in Tachyon)
-  ULONG length;          // Length register
-  ULONG base;
-} TachyonIMQ;                    // @ 32 * IMQ_LEN align
+	TachyonIMQE QEntry[IMQ_LEN];
+	__u32 producerIndex;	// IMQ Producer Index register
+	// @32 byte align
+	__u32 consumerIndex;	// Consumer Index register (in Tachyon)
+	__u32 length;		// Length register
+	__u32 base;
+} TachyonIMQ;			// @ 32 * IMQ_LEN align
 
 
 
-typedef struct           // inbound completion message
+typedef struct			// inbound completion message
 {
-  ULONG Type;
-  ULONG Index;
-  ULONG TransferLength;
+	__u32 Type;
+	__u32 Index;
+	__u32 TransferLength;
 } TachyonInbCM;
 
 
 
 // arbitrary numeric tags for TL structures
-#define TL_FCHS 1  // TachLite Fibre Channel Header Structure
-#define TL_IWE 2  // initiator write entry (for SEST)
-#define TL_TWE 3  // target write entry (for SEST)
-#define TL_IRE 4  // initiator read entry (for SEST)
-#define TL_TRE 5  // target read entry (for SEST)
-#define TL_IRB 6  // I/O request block
-
-                                // for INCOMING frames
-#define SFQ_LEN 32              // minimum 32 entries, max 4096
-
-typedef struct                  // Single Frame Que
-{
-  TachFCHDR_CMND QEntry[SFQ_LEN]; // must be 64 bytes!!
-  ULONG producerIndex;   // IMQ Producer Index register
-                                 // @32 byte align
-  ULONG consumerIndex;   // Consumer Index register (in Tachyon)
-  ULONG length;          // Length register
-  ULONG base;
+#define TL_FCHS 1		// TachLite Fibre Channel Header Structure
+#define TL_IWE 2		// initiator write entry (for SEST)
+#define TL_TWE 3		// target write entry (for SEST)
+#define TL_IRE 4		// initiator read entry (for SEST)
+#define TL_TRE 5		// target read entry (for SEST)
+#define TL_IRB 6		// I/O request block
+
+				// for INCOMING frames
+#define SFQ_LEN 32		// minimum 32 entries, max 4096
+
+typedef struct			// Single Frame Que
+{
+	TachFCHDR_CMND QEntry[SFQ_LEN];	// must be 64 bytes!!
+	__u32 producerIndex;	// IMQ Producer Index register
+	// @32 byte align
+	__u32 consumerIndex;	// Consumer Index register (in Tachyon)
+	__u32 length;		// Length register
+	__u32 base;
 } TachLiteSFQ;
 
 
-typedef struct                 // I/O Request Block flags
+typedef struct			// I/O Request Block flags
 {
-  UCHAR  BRD : 1;
-  UCHAR      : 1; // reserved
-  UCHAR  SFA : 1;
-  UCHAR  DNC : 1;
-  UCHAR  DIN : 1;
-  UCHAR  DCM : 1;
-  UCHAR  CTS : 1;
-  UCHAR  SBV : 1;  // IRB entry valid - IRB'B' only
+	__u8 BRD:1;
+	 __u8:1;		// reserved
+	__u8 SFA:1;
+	__u8 DNC:1;
+	__u8 DIN:1;
+	__u8 DCM:1;
+	__u8 CTS:1;
+	__u8 SBV:1;		// IRB entry valid - IRB'B' only
 } IRBflags;
 
-typedef struct                  // I/O Request Block
-{                          // Request 'A'
-  ULONG Req_A_SFS_Len;     // total frame len (hdr + payload), min 32
-  ULONG Req_A_SFS_Addr;    // 32-bit pointer to FCHS struct (to be sent)
-  ULONG Req_A_SFS_D_ID;    // 24-bit FC destination (i.e. 8 bit al_pa)
-  ULONG Req_A_Trans_ID;    // X_ID (OX_ID or RX_ID) and/or Index in SEST
-                           // Request 'B'
-  ULONG Req_B_SFS_Len;     // total frame len (hdr + payload), min 32
-  ULONG Req_B_SFS_Addr;    // 32-bit pointer to FCHS struct (to be sent)
-  ULONG Req_B_SFS_D_ID;    // 24-bit FC destination (i.e. 8 bit al_pa)
-  ULONG Req_B_Trans_ID;    // X_ID (OX_ID or RX_ID) and/or Index in SEST
+typedef struct			// I/O Request Block
+{				// Request 'A'
+	__u32 Req_A_SFS_Len;	// total frame len (hdr + payload), min 32
+	__u32 Req_A_SFS_Addr;	// 32-bit pointer to FCHS struct (to be sent)
+	__u32 Req_A_SFS_D_ID;	// 24-bit FC destination (i.e. 8 bit al_pa)
+	__u32 Req_A_Trans_ID;	// X_ID (OX_ID or RX_ID) and/or Index in SEST
+	// Request 'B'
+	__u32 Req_B_SFS_Len;	// total frame len (hdr + payload), min 32
+	__u32 Req_B_SFS_Addr;	// 32-bit pointer to FCHS struct (to be sent)
+	__u32 Req_B_SFS_D_ID;	// 24-bit FC destination (i.e. 8 bit al_pa)
+	__u32 Req_B_Trans_ID;	// X_ID (OX_ID or RX_ID) and/or Index in SEST
 } TachLiteIRB;
 
 
-typedef struct           // TachLite placeholder for IRBs
-{                        // aligned @sizeof(ERQ) for TachLite
-                         // MAX commands is sum of SEST len and ERQ
-                         // we know that each SEST entry requires an
-                         // IRB (ERQ) entry; in addition, we provide
-                         // ERQ_LEN
-  TachLiteIRB QEntry[ERQ_LEN]; // Base register; entries 32 bytes ea.
-  ULONG consumerIndex;   // Consumer Index register
-  ULONG producerIndex;   // ERQ Producer Index register
-  ULONG length;          // Length register
-  ULONG base;            // copy of base ptr for debug
-                         // struct is sized for largest expected cmnd (LOGIN)
+typedef struct			// TachLite placeholder for IRBs
+{				// aligned @sizeof(ERQ) for TachLite
+	// MAX commands is sum of SEST len and ERQ
+	// we know that each SEST entry requires an
+	// IRB (ERQ) entry; in addition, we provide
+	// ERQ_LEN
+	TachLiteIRB QEntry[ERQ_LEN];	// Base register; entries 32 bytes ea.
+	__u32 consumerIndex;	// Consumer Index register
+	__u32 producerIndex;	// ERQ Producer Index register
+	__u32 length;		// Length register
+	__u32 base;		// copy of base ptr for debug
+	// struct is sized for largest expected cmnd (LOGIN)
 } TachLiteERQ;
 
 // for now, just 32 bit DMA, eventually 40something, with code changes
 #define CPQFCTS_DMA_MASK ((unsigned long) (0x00000000FFFFFFFF))
 
-#define TL_MAX_SG_ELEM_LEN 0x7ffff  // Max buffer length a single S/G entry
-				// may represent (a hardware limitation).  The
-				// only reason to ever change this is if you
-				// want to exercise very-hard-to-reach code in
-				// cpqfcTSworker.c:build_SEST_sglist().
+#define TL_MAX_SG_ELEM_LEN 0x7ffff	// Max buffer length a single S/G entry
+					// may represent (a hardware limitation).  The
+					// only reason to ever change this is if you
+					// want to exercise very-hard-to-reach code in
+					// cpqfcTSworker.c:build_SEST_sglist().
 
-#define TL_DANGER_SGPAGES 7  // arbitrary high water mark for # of S/G pages
+#define TL_DANGER_SGPAGES 7	// arbitrary high water mark for # of S/G pages
 				// we must exceed to elicit a warning indicative
 				// of EXTREMELY large data transfers or 
 				// EXTREME memory fragmentation.
@@ -429,236 +424,230 @@
 				// Never seen this is real life, only in 
 				// testing with tricked up driver.)
 
-#define TL_EXT_SG_PAGE_COUNT 256  // Number of Extended Scatter/Gather a/l PAIRS
-                                  // Tachyon register (IOBaseU 0x68)
-                                  // power-of-2 value ONLY!  4 min, 256 max
+#define TL_EXT_SG_PAGE_COUNT 256	// Number of Extended Scatter/Gather a/l PAIRS
+					// Tachyon register (IOBaseU 0x68)
+					// power-of-2 value ONLY!  4 min, 256 max
 
-                          // byte len is #Pairs * 2 ULONG/Pair * 4 bytes/ULONG
+			  // byte len is #Pairs * 2 __u32/Pair * 4 bytes/__u32
 #define TL_EXT_SG_PAGE_BYTELEN (TL_EXT_SG_PAGE_COUNT *2 *4)
 
 
 
 // SEST entry types: IWE, IRE, TWE, TRE
-typedef struct 
-{
-  ULONG Hdr_Len;
-  ULONG Hdr_Addr;
-  ULONG RSP_Len;
-  ULONG RSP_Addr;
-  ULONG Buff_Off;
+typedef struct {
+	__u32 Hdr_Len;
+	__u32 Hdr_Addr;
+	__u32 RSP_Len;
+	__u32 RSP_Addr;
+	__u32 Buff_Off;
 #define USES_EXTENDED_SGLIST(this_sest, x_ID) \
 	(!((this_sest)->u[ x_ID ].IWE.Buff_Off & 0x80000000))
-  ULONG Link;
-  ULONG RX_ID;
-  ULONG Data_Len;
-  ULONG Exp_RO;
-  ULONG Exp_Byte_Cnt;
-   // --- extended/local Gather Len/Address pairs
-  ULONG GLen1;
-  ULONG GAddr1;
-  ULONG GLen2;
-  ULONG GAddr2;
-  ULONG GLen3;
-  ULONG GAddr3;
+	__u32 Link;
+	__u32 RX_ID;
+	__u32 Data_Len;
+	__u32 Exp_RO;
+	__u32 Exp_Byte_Cnt;
+	// --- extended/local Gather Len/Address pairs
+	__u32 GLen1;
+	__u32 GAddr1;
+	__u32 GLen2;
+	__u32 GAddr2;
+	__u32 GLen3;
+	__u32 GAddr3;
 } TachLiteIWE;
 
 
-typedef struct 
-{
-  ULONG Seq_Accum;
-  ULONG reserved;       // must clear to 0
-  ULONG RSP_Len;
-  ULONG RSP_Addr;
-  ULONG Buff_Off;
-  ULONG Buff_Index;           // ULONG 5
-  ULONG Exp_RO;
-  ULONG Byte_Count;
-  ULONG reserved_;      // ULONG 8
-  ULONG Exp_Byte_Cnt;
-   // --- extended/local Scatter Len/Address pairs
-  ULONG SLen1;
-  ULONG SAddr1;
-  ULONG SLen2;
-  ULONG SAddr2;
-  ULONG SLen3;
-  ULONG SAddr3;
+typedef struct {
+	__u32 Seq_Accum;
+	__u32 reserved;		// must clear to 0
+	__u32 RSP_Len;
+	__u32 RSP_Addr;
+	__u32 Buff_Off;
+	__u32 Buff_Index;	// __u32 5
+	__u32 Exp_RO;
+	__u32 Byte_Count;
+	__u32 reserved_;	// __u32 8
+	__u32 Exp_Byte_Cnt;
+	// --- extended/local Scatter Len/Address pairs
+	__u32 SLen1;
+	__u32 SAddr1;
+	__u32 SLen2;
+	__u32 SAddr2;
+	__u32 SLen3;
+	__u32 SAddr3;
 } TachLiteIRE;
 
 
-typedef struct          // Target Write Entry
+typedef struct			// Target Write Entry
 {
-  ULONG Seq_Accum;      // dword 0
-  ULONG reserved;       // dword 1  must clear to 0
-  ULONG Remote_Node_ID;
-  ULONG reserved1;      // dword 3  must clear to 0
-  ULONG Buff_Off;
-  ULONG Buff_Index;     // ULONG 5
-  ULONG Exp_RO;
-  ULONG Byte_Count;
-  ULONG reserved_;      // ULONG 8
-  ULONG Exp_Byte_Cnt;
-   // --- extended/local Scatter Len/Address pairs
-  ULONG SLen1;
-  ULONG SAddr1;
-  ULONG SLen2;
-  ULONG SAddr2;
-  ULONG SLen3;
-  ULONG SAddr3;
+	__u32 Seq_Accum;	// dword 0
+	__u32 reserved;		// dword 1  must clear to 0
+	__u32 Remote_Node_ID;
+	__u32 reserved1;	// dword 3  must clear to 0
+	__u32 Buff_Off;
+	__u32 Buff_Index;	// __u32 5
+	__u32 Exp_RO;
+	__u32 Byte_Count;
+	__u32 reserved_;	// __u32 8
+	__u32 Exp_Byte_Cnt;
+	// --- extended/local Scatter Len/Address pairs
+	__u32 SLen1;
+	__u32 SAddr1;
+	__u32 SLen2;
+	__u32 SAddr2;
+	__u32 SLen3;
+	__u32 SAddr3;
 } TachLiteTWE;
 
-typedef struct      
-{
-  ULONG Hdr_Len;
-  ULONG Hdr_Addr;
-  ULONG RSP_Len;        // DWord 2
-  ULONG RSP_Addr;
-  ULONG Buff_Off;
-  ULONG Buff_Index;     // DWord 5
-  ULONG reserved;
-  ULONG Data_Len;
-  ULONG reserved_;
-  ULONG reserved__;
-   // --- extended/local Gather Len/Address pairs
-  ULONG GLen1;          // DWord A
-  ULONG GAddr1;
-  ULONG GLen2;
-  ULONG GAddr2;
-  ULONG GLen3;
-  ULONG GAddr3;
+typedef struct {
+	__u32 Hdr_Len;
+	__u32 Hdr_Addr;
+	__u32 RSP_Len;		// DWord 2
+	__u32 RSP_Addr;
+	__u32 Buff_Off;
+	__u32 Buff_Index;	// DWord 5
+	__u32 reserved;
+	__u32 Data_Len;
+	__u32 reserved_;
+	__u32 reserved__;
+	// --- extended/local Gather Len/Address pairs
+	__u32 GLen1;		// DWord A
+	__u32 GAddr1;
+	__u32 GLen2;
+	__u32 GAddr2;
+	__u32 GLen3;
+	__u32 GAddr3;
 } TachLiteTRE;
 
 typedef struct ext_sg_page_ptr_t *PSGPAGES;
-typedef struct ext_sg_page_ptr_t 
-{
-  unsigned char page[TL_EXT_SG_PAGE_BYTELEN * 2]; // 2x for alignment
-  dma_addr_t busaddr; 	// need the bus addresses and
-  unsigned int maplen;  // lengths for later pci unmapping.
-  PSGPAGES next;
-} SGPAGES; // linked list of S/G pairs, by Exchange
-
-typedef struct                  // SCSI Exchange State Table
-{
-  union                         // Entry can be IWE, IRE, TWE, TRE
-  {                             // 64 bytes per entry
-    TachLiteIWE IWE;
-    TachLiteIRE IRE;
-    TachLiteTWE TWE;
-    TachLiteTRE TRE;
-  } u[TACH_SEST_LEN];
-
-  TachFCHDR DataHDR[TACH_SEST_LEN]; // for SEST FCP_DATA frame hdr (no pl)
-  TachFCHDR_RSP RspHDR[TACH_SEST_LEN]; // space for SEST FCP_RSP frame
-  PSGPAGES sgPages[TACH_SEST_LEN]; // head of linked list of Pool-allocations
-  ULONG length;          // Length register
-  ULONG base;            // copy of base ptr for debug
+typedef struct ext_sg_page_ptr_t {
+	unsigned char page[TL_EXT_SG_PAGE_BYTELEN * 2];	// 2x for alignment
+	dma_addr_t busaddr;	// need the bus addresses and
+	unsigned int maplen;	// lengths for later pci unmapping.
+	PSGPAGES next;
+} SGPAGES;			// linked list of S/G pairs, by Exchange
+
+typedef struct			// SCSI Exchange State Table
+{
+	union			// Entry can be IWE, IRE, TWE, TRE
+	{			// 64 bytes per entry
+		TachLiteIWE IWE;
+		TachLiteIRE IRE;
+		TachLiteTWE TWE;
+		TachLiteTRE TRE;
+	} u[TACH_SEST_LEN];
+
+	TachFCHDR DataHDR[TACH_SEST_LEN];	// for SEST FCP_DATA frame hdr (no pl)
+	TachFCHDR_RSP RspHDR[TACH_SEST_LEN];	// space for SEST FCP_RSP frame
+	PSGPAGES sgPages[TACH_SEST_LEN];	// head of linked list of Pool-allocations
+	__u32 length;		// Length register
+	__u32 base;		// copy of base ptr for debug
 } TachSEST;
 
 
 
-typedef struct                  // each register has it's own address
-                                // and value (used for write-only regs)
+typedef struct			// each register has it's own address
+				// and value (used for write-only regs)
 {
-  void* address;
-  volatile ULONG value;
+	void *address;
+	volatile __u32 value;
 } FCREGISTER;
 
-typedef struct         // Host copy - TachLite Registers
+typedef struct			// Host copy - TachLite Registers
 {
-  ULONG IOBaseL, IOBaseU;  // I/O port lower and upper TL register addresses
-  ULONG MemBase;           // memory mapped register addresses
-  void* ReMapMemBase;      // O/S VM reference for MemBase
-  ULONG wwn_hi;            // WWN is set once at startup
-  ULONG wwn_lo;
-  ULONG my_al_pa;          // al_pa received after LIP()
-  ULONG ROMCTR;            // flags for on-board RAM/ROM
-  ULONG RAMBase;           // on-board RAM (i.e. some Tachlites)
-  ULONG SROMBase;          // on-board EEPROM (some Tachlites)
-  ULONG PCIMCTR;           // PCI Master Control Reg (has bus width)
-
-  FCREGISTER INTEN;        // copy of interrupt enable mask
-  FCREGISTER INTPEND;      // interrupt pending
-  FCREGISTER INTSTAT;      // interrupt status
-  FCREGISTER SFQconsumerIndex; 
-  FCREGISTER ERQproducerIndex; 
-  FCREGISTER TYconfig;   // TachYon (chip level)
-  FCREGISTER TYcontrol;
-  FCREGISTER TYstatus;
-  FCREGISTER FMconfig;   // Frame Manager (FC loop level)
-  FCREGISTER FMcontrol;
-  FCREGISTER FMstatus;
-  FCREGISTER FMLinkStatus1;
-  FCREGISTER FMLinkStatus2;
-  FCREGISTER FMBB_CreditZero;
-  FCREGISTER status;
-  FCREGISTER ed_tov;     // error detect time-out value
-  FCREGISTER rcv_al_pa;  // received arb. loop physical address
-  FCREGISTER primitive;  // e.g. LIP(), OPN(), ...
+	__u32 IOBaseL, IOBaseU;	// I/O port lower and upper TL register addresses
+	__u32 MemBase;		// memory mapped register addresses
+	void *ReMapMemBase;	// O/S VM reference for MemBase
+	__u32 wwn_hi;		// WWN is set once at startup
+	__u32 wwn_lo;
+	__u32 my_al_pa;		// al_pa received after LIP()
+	__u32 ROMCTR;		// flags for on-board RAM/ROM
+	__u32 RAMBase;		// on-board RAM (i.e. some Tachlites)
+	__u32 SROMBase;		// on-board EEPROM (some Tachlites)
+	__u32 PCIMCTR;		// PCI Master Control Reg (has bus width)
+
+	FCREGISTER INTEN;	// copy of interrupt enable mask
+	FCREGISTER INTPEND;	// interrupt pending
+	FCREGISTER INTSTAT;	// interrupt status
+	FCREGISTER SFQconsumerIndex;
+	FCREGISTER ERQproducerIndex;
+	FCREGISTER TYconfig;	// TachYon (chip level)
+	FCREGISTER TYcontrol;
+	FCREGISTER TYstatus;
+	FCREGISTER FMconfig;	// Frame Manager (FC loop level)
+	FCREGISTER FMcontrol;
+	FCREGISTER FMstatus;
+	FCREGISTER FMLinkStatus1;
+	FCREGISTER FMLinkStatus2;
+	FCREGISTER FMBB_CreditZero;
+	FCREGISTER status;
+	FCREGISTER ed_tov;	// error detect time-out value
+	FCREGISTER rcv_al_pa;	// received arb. loop physical address
+	FCREGISTER primitive;	// e.g. LIP(), OPN(), ...
 } TL_REGISTERS;
 
 
 
-typedef struct 
-{
-  ULONG ok;
-  ULONG invalidArgs;
-  ULONG linkDown;
-  ULONG linkUp;
-  ULONG outQueFull;
-  ULONG SESTFull;
-  ULONG hpe;    // host programming err (from Tach)
-  ULONG FC4aborted; // aborts from Application or upper driver layer
-  ULONG FC2aborted; // aborts from our driver's timeouts
-  ULONG timeouts;   // our driver timeout (on individual exchanges)
-  ULONG logouts;    // explicit - sent LOGO; implicit - device removed
-  ULONG retries;
-  ULONG linkFailTX;
-  ULONG linkFailRX;
-  ULONG CntErrors;  // byte count expected != count received (typ. SEST)
-  ULONG e_stores;   // elastic store errs
-  ULONG resets;     // hard or soft controller resets
-  ULONG FMinits;    // TACH Frame Manager Init (e.g. LIPs)
-  ULONG lnkQueFull;  // too many LOGIN, loop commands
-  ULONG ScsiQueFull; // too many FCP-SCSI inbound frames
-  ULONG LossofSignal;   // FM link status 1 regs
-  ULONG BadRXChar;   // FM link status 1 regs
-  ULONG LossofSync;   // FM link status 1 regs
-  ULONG Rx_EOFa;   // FM link status 2 regs (received EOFa)
-  ULONG Dis_Frm;   // FM link status 2 regs (discarded frames)
-  ULONG Bad_CRC;   // FM link status 2 regs
-  ULONG BB0_Timer; //  FM BB_Credit Zero Timer Reg
-  ULONG loopBreaks; // infinite loop exits
-  ULONG lastBB0timer;  // static accum. buffer needed by Tachlite
+typedef struct {
+	__u32 ok;
+	__u32 invalidArgs;
+	__u32 linkDown;
+	__u32 linkUp;
+	__u32 outQueFull;
+	__u32 SESTFull;
+	__u32 hpe;		// host programming err (from Tach)
+	__u32 FC4aborted;	// aborts from Application or upper driver layer
+	__u32 FC2aborted;	// aborts from our driver's timeouts
+	__u32 timeouts;		// our driver timeout (on individual exchanges)
+	__u32 logouts;		// explicit - sent LOGO; implicit - device removed
+	__u32 retries;
+	__u32 linkFailTX;
+	__u32 linkFailRX;
+	__u32 CntErrors;	// byte count expected != count received (typ. SEST)
+	__u32 e_stores;		// elastic store errs
+	__u32 resets;		// hard or soft controller resets
+	__u32 FMinits;		// TACH Frame Manager Init (e.g. LIPs)
+	__u32 lnkQueFull;	// too many LOGIN, loop commands
+	__u32 ScsiQueFull;	// too many FCP-SCSI inbound frames
+	__u32 LossofSignal;	// FM link status 1 regs
+	__u32 BadRXChar;	// FM link status 1 regs
+	__u32 LossofSync;	// FM link status 1 regs
+	__u32 Rx_EOFa;		// FM link status 2 regs (received EOFa)
+	__u32 Dis_Frm;		// FM link status 2 regs (discarded frames)
+	__u32 Bad_CRC;		// FM link status 2 regs
+	__u32 BB0_Timer;	//  FM BB_Credit Zero Timer Reg
+	__u32 loopBreaks;	// infinite loop exits
+	__u32 lastBB0timer;	// static accum. buffer needed by Tachlite
 } FCSTATS;
 
 
-typedef struct               // Config Options
-{                            // LS Bit first
-  USHORT        : 1;           // bit0:
-  USHORT  flogi : 1;           // bit1: We sent FLOGI - wait for Fabric logins
-  USHORT  fabric: 1;           // bit2: Tachyon detected Fabric (FM stat LG)
-  USHORT  LILPin: 1;           // bit3: We can use an FC-AL LILP frame
-  USHORT  target: 1;           // bit4: this Port has SCSI target capability
-  USHORT  initiator:    1;     // bit5: this Port has SCSI initiator capability
-  USHORT  extLoopback:  1;     // bit6: loopback at GBIC
-  USHORT  intLoopback:  1;     // bit7: loopback in HP silicon
-  USHORT        : 1;           // bit8:
-  USHORT        : 1;           // bit9:
-  USHORT        : 1;           // bit10:
-  USHORT        : 1;           // bit11:
-  USHORT        : 1;           // bit12:
-  USHORT        : 1;           // bit13:
-  USHORT        : 1;           // bit14:
-  USHORT        : 1;           // bit15:
+typedef struct			// Config Options
+{				// LS Bit first
+	__u16:1;		// bit0:
+	__u16 flogi:1;		// bit1: We sent FLOGI - wait for Fabric logins
+	__u16 fabric:1;	// bit2: Tachyon detected Fabric (FM stat LG)
+	__u16 LILPin:1;	// bit3: We can use an FC-AL LILP frame
+	__u16 target:1;	// bit4: this Port has SCSI target capability
+	__u16 initiator:1;	// bit5: this Port has SCSI initiator capability
+	__u16 extLoopback:1;	// bit6: loopback at GBIC
+	__u16 intLoopback:1;	// bit7: loopback in HP silicon
+	 __u16:1;		// bit8:
+	 __u16:1;		// bit9:
+	 __u16:1;		// bit10:
+	 __u16:1;		// bit11:
+	 __u16:1;		// bit12:
+	 __u16:1;		// bit13:
+	 __u16:1;		// bit14:
+	 __u16:1;		// bit15:
 } FC_OPTIONS;
 
 
 
-typedef struct dyn_mem_pair
-{
-  void *BaseAllocated;  // address as allocated from O/S;
-  unsigned long AlignedAddress; // aligned address (used by Tachyon DMA)
-  dma_addr_t dma_handle;
-  size_t size;
+typedef struct dyn_mem_pair {
+	void *BaseAllocated;	// address as allocated from O/S;
+	unsigned long AlignedAddress;	// aligned address (used by Tachyon DMA)
+	dma_addr_t dma_handle;
+	size_t size;
 } ALIGNED_MEM;
 
 
@@ -675,66 +664,63 @@
 #define IMPLICIT_LOGOUT 1
 #define EXPLICIT_LOGOUT 2
 
-typedef struct 
-{
-  UCHAR channel; // SCSI "bus"
-  UCHAR target;
-  UCHAR InqDeviceType;  // byte 0 from SCSI Inquiry response
-  UCHAR VolumeSetAddressing;  // FCP-SCSI LUN coding (40h for VSA)
-  UCHAR LunMasking;     // True if selective presentation supported
-  UCHAR lun[CPQFCTS_MAX_LUN];
+typedef struct {
+	__u8 channel;		// SCSI "bus"
+	__u8 target;
+	__u8 InqDeviceType;	// byte 0 from SCSI Inquiry response
+	__u8 VolumeSetAddressing;	// FCP-SCSI LUN coding (40h for VSA)
+	__u8 LunMasking;	// True if selective presentation supported
+	__u8 lun[CPQFCTS_MAX_LUN];
 } SCSI_NEXUS;
 
 
-typedef struct        
-{
-  union 
-  {
-    UCHAR ucWWN[8];  // a FC 64-bit World Wide Name/ PortID of target
-                     // addressing of single target on single loop...
-    u64 liWWN;
-  } u;
-
-  ULONG port_id;     // a FC 24-bit address of port (lower 8 bits = al_pa)
-
-  Scsi_Cmnd ScsiCmnd;   // command buffer for Report Luns
-#define REPORT_LUNS_PL 256  
-  UCHAR ReportLunsPayload[REPORT_LUNS_PL];
-  
-  SCSI_NEXUS ScsiNexus; // LUNs per FC device
-
-  ULONG LOGO_counter; // might try several times before logging out for good
-  ULONG LOGO_timer;   // after LIP, ports expecting PDISC must time-out and
-                      // LOGOut if successful PDISC not completed in 2 secs
-
-  ULONG concurrent_seq;  // must be 1 or greater
-  ULONG rx_data_size;    // e.g. 128, 256, 1024, 2048 per FC-PH spec
-  ULONG BB_credit;
-  ULONG EE_credit;
-
-  ULONG fcp_info;        // from PRLI (i.e. INITIATOR/ TARGET flags)
-                         // flags for login process
-  BOOLEAN Originator;    // Login sequence Originated (if false, we
-                         // responded to another port's login sequence)
-  BOOLEAN plogi;         // PLOGI frame ACCepted (originated or responded)
-  BOOLEAN pdisc;         // PDISC frame was ORIGINATED (self-login logic)
-  BOOLEAN prli;          // PRLI frame ACCepted (originated or responded)
-  BOOLEAN flogi;         // FLOGI frame ACCepted (originated or responded)
-  BOOLEAN logo;          // port permanently logged out (invalid login param)
-  BOOLEAN flogiReq;      // Fabric login required (set in LIP process)
-  UCHAR highest_ver;
-  UCHAR lowest_ver;
-
-  
-  // when the "target" (actually FC Port) is waiting for login
-  // (e.g. after Link reset), set the device_blocked bit;
-  // after Port completes login, un-block target.
-  UCHAR device_blocked; // see Scsi_Device struct
-
-                    // define singly-linked list of logged-in ports
-                    // once a port_id is identified, it is remembered,
-                    // even if the port is removed indefinitely
-  PVOID pNextPort;  // actually, type PFC_LOGGEDIN_PORT; void for Compiler
+typedef struct {
+	union {
+		__u8 ucWWN[8];	// a FC 64-bit World Wide Name/ PortID of target
+		// addressing of single target on single loop...
+		u64 liWWN;
+	} u;
+
+	__u32 port_id;		// a FC 24-bit address of port (lower 8 bits = al_pa)
+
+	Scsi_Cmnd ScsiCmnd;	// command buffer for Report Luns
+#define REPORT_LUNS_PL 256
+	__u8 ReportLunsPayload[REPORT_LUNS_PL];
+
+	SCSI_NEXUS ScsiNexus;	// LUNs per FC device
+
+	__u32 LOGO_counter;	// might try several times before logging out for good
+	__u32 LOGO_timer;	// after LIP, ports expecting PDISC must time-out and
+	// LOGOut if successful PDISC not completed in 2 secs
+
+	__u32 concurrent_seq;	// must be 1 or greater
+	__u32 rx_data_size;	// e.g. 128, 256, 1024, 2048 per FC-PH spec
+	__u32 BB_credit;
+	__u32 EE_credit;
+
+	__u32 fcp_info;		// from PRLI (i.e. INITIATOR/ TARGET flags)
+	// flags for login process
+	__u8 Originator;	// Login sequence Originated (if false, we
+	// responded to another port's login sequence)
+	__u8 plogi;		// PLOGI frame ACCepted (originated or responded)
+	__u8 pdisc;		// PDISC frame was ORIGINATED (self-login logic)
+	__u8 prli;		// PRLI frame ACCepted (originated or responded)
+	__u8 flogi;		// FLOGI frame ACCepted (originated or responded)
+	__u8 logo;		// port permanently logged out (invalid login param)
+	__u8 flogiReq;	// Fabric login required (set in LIP process)
+	__u8 highest_ver;
+	__u8 lowest_ver;
+
+
+	// when the "target" (actually FC Port) is waiting for login
+	// (e.g. after Link reset), set the device_blocked bit;
+	// after Port completes login, un-block target.
+	__u8 device_blocked;	// see Scsi_Device struct
+
+	// define singly-linked list of logged-in ports
+	// once a port_id is identified, it is remembered,
+	// even if the port is removed indefinitely
+	void * pNextPort;	// actually, type PFC_LOGGEDIN_PORT; void for Compiler
 
 } FC_LOGGEDIN_PORT, *PFC_LOGGEDIN_PORT;
 
@@ -742,16 +728,15 @@
 
 // This serves as the ESB (Exchange Status Block),
 // and has timeout counter; used for ABORTs
-typedef struct                
-{                                  // FC-1 X_IDs
-  ULONG type;            // ELS_PLOGI, SCSI_IWE, ... (0 if free)
-  PFC_LOGGEDIN_PORT pLoggedInPort; // FC device on other end of Exchange
-  Scsi_Cmnd *Cmnd;       // Linux SCSI command packet includes S/G list
-  ULONG timeOut;         // units of ??, DEC by driver, Abort when 0
-  ULONG reTries;         // need one or more retries?
-  ULONG status;          // flags indicating errors (0 if none)
-  TachLiteIRB IRB;       // I/O Request Block, gets copied to ERQ
-  TachFCHDR_GCMND fchs;  // location of IRB's Req_A_SFS_Addr
+typedef struct {		// FC-1 X_IDs
+	__u32 type;		// ELS_PLOGI, SCSI_IWE, ... (0 if free)
+	PFC_LOGGEDIN_PORT pLoggedInPort;	// FC device on other end of Exchange
+	Scsi_Cmnd *Cmnd;	// Linux SCSI command packet includes S/G list
+	__u32 timeOut;		// units of ??, DEC by driver, Abort when 0
+	__u32 reTries;		// need one or more retries?
+	__u32 status;		// flags indicating errors (0 if none)
+	TachLiteIRB IRB;	// I/O Request Block, gets copied to ERQ
+	TachFCHDR_GCMND fchs;	// location of IRB's Req_A_SFS_Addr
 } FC_EXCHANGE, *PFC_EXCHANGE;
 
 // Unfortunately, Linux limits our kmalloc() allocations to 128k.
@@ -761,9 +746,9 @@
 // (In other words, this cumbersome indirection is necessary
 // because of kernel memory allocation constraints!)
 
-typedef struct // we will allocate this dynamically
+typedef struct			// we will allocate this dynamically
 {
-  FC_EXCHANGE fcExchange[ TACH_MAX_XID ];
+	FC_EXCHANGE fcExchange[TACH_MAX_XID];
 } FC_EXCHANGES;
 
 
@@ -776,95 +761,89 @@
 
 
 
-typedef struct
-{
-  char Name[64]; // name of controller ("HP Tachlite TL Rev2.0, 33MHz, 64bit bus")
-  //PVOID  pAdapterDevExt; // back pointer to device object/extension
-  ULONG ChipType;        // local numeric key for Tachyon Type / Rev.
-  ULONG status;              // our Driver - logical status
-  
-  TL_REGISTERS Registers;    // reg addresses & host memory copies
-                             // FC-4 mapping of 'transaction' to X_IDs
-  UCHAR LILPmap[32*4];       // Loop Position Map of ALPAs (late FC-AL only)
-  FC_OPTIONS Options;        // e.g. Target, Initiator, loopback...
-  UCHAR highest_FCPH_ver;    // FC-PH version limits
-  UCHAR lowest_FCPH_ver;     // FC-PH version limits
-
-  FC_EXCHANGES *Exchanges;  
-  ULONG fcLsExchangeLRU;       // Least Recently Used counter (Link Service)
-  ULONG fcSestExchangeLRU;       // Least Recently Used counter (FCP-SCSI)
-  FC_LOGGEDIN_PORT fcPorts;  // linked list of every FC port ever seen
-  FCSTATS fcStats;           // FC comm err counters
-
-                             // Host memory QUEUE pointers
-  TachLiteERQ *ERQ;          // Exchange Request Que 
-  TachyonIMQ *IMQ;           // Inbound Message Que 
-  TachLiteSFQ *SFQ;          // Single Frame Queue
-  TachSEST *SEST;            // SCSI Exchange State Table
-
-  dma_addr_t exch_dma_handle;
-
-  // these function pointers are for "generic" functions, which are
-  // replaced with Host Bus Adapter types at
-  // runtime.
-  int (*CreateTachyonQues)( void* , int);
-  int (*DestroyTachyonQues)( void* , int);
-  int (*LaserControl)(void*, int );   // e.g. On/Off
-  int (*ResetTachyon)(void*, int );
-  void (*FreezeTachyon)(void*, int );
-  void (*UnFreezeTachyon)(void*, int );
-  int (*InitializeTachyon)(void*, int, int );
-  int (*InitializeFrameManager)(void*, int );
-  int (*ProcessIMQEntry)(void*);
-  int (*ReadWriteWWN)(void*, int ReadWrite);
-  int (*ReadWriteNVRAM)(void*, void*, int ReadWrite);
+typedef struct {
+	char Name[64];		// name of controller ("HP Tachlite TL Rev2.0, 33MHz, 64bit bus")
+	//void *  pAdapterDevExt; // back pointer to device object/extension
+	__u32 ChipType;		// local numeric key for Tachyon Type / Rev.
+	__u32 status;		// our Driver - logical status
+
+	TL_REGISTERS Registers;	// reg addresses & host memory copies
+	// FC-4 mapping of 'transaction' to X_IDs
+	__u8 LILPmap[32 * 4];	// Loop Position Map of ALPAs (late FC-AL only)
+	FC_OPTIONS Options;	// e.g. Target, Initiator, loopback...
+	__u8 highest_FCPH_ver;	// FC-PH version limits
+	__u8 lowest_FCPH_ver;	// FC-PH version limits
+
+	FC_EXCHANGES *Exchanges;
+	__u32 fcLsExchangeLRU;	// Least Recently Used counter (Link Service)
+	__u32 fcSestExchangeLRU;	// Least Recently Used counter (FCP-SCSI)
+	FC_LOGGEDIN_PORT fcPorts;	// linked list of every FC port ever seen
+	FCSTATS fcStats;	// FC comm err counters
+
+	// Host memory QUEUE pointers
+	TachLiteERQ *ERQ;	// Exchange Request Que 
+	TachyonIMQ *IMQ;	// Inbound Message Que 
+	TachLiteSFQ *SFQ;	// Single Frame Queue
+	TachSEST *SEST;		// SCSI Exchange State Table
+
+	dma_addr_t exch_dma_handle;
+
+	// these function pointers are for "generic" functions, which are
+	// replaced with Host Bus Adapter types at
+	// runtime.
+	int (*CreateTachyonQues) (void *, int);
+	int (*DestroyTachyonQues) (void *, int);
+	int (*LaserControl) (void *, int);	// e.g. On/Off
+	int (*ResetTachyon) (void *, int);
+	void (*FreezeTachyon) (void *, int);
+	void (*UnFreezeTachyon) (void *, int);
+	int (*InitializeTachyon) (void *, int, int);
+	int (*InitializeFrameManager) (void *, int);
+	int (*ProcessIMQEntry) (void *);
+	int (*ReadWriteWWN) (void *, int ReadWrite);
+	int (*ReadWriteNVRAM) (void *, void *, int ReadWrite);
 
 } TACHYON, *PTACHYON;
 
 
 void cpqfcTSClearLinkStatusCounters(TACHYON * fcChip);
 
-int CpqTsCreateTachLiteQues( void* pHBA, int opcode);
-int CpqTsDestroyTachLiteQues( void* , int);
-int CpqTsInitializeTachLite( void *pHBA, int opcode1, int opcode2);
+int CpqTsCreateTachLiteQues(void *pHBA, int opcode);
+int CpqTsDestroyTachLiteQues(void *, int);
+int CpqTsInitializeTachLite(void *pHBA, int opcode1, int opcode2);
 
-int CpqTsProcessIMQEntry(void* pHBA);
+int CpqTsProcessIMQEntry(void *pHBA);
 int CpqTsResetTachLite(void *pHBA, int type);
 void CpqTsFreezeTachlite(void *pHBA, int type);
 void CpqTsUnFreezeTachlite(void *pHBA, int type);
 int CpqTsInitializeFrameManager(void *pHBA, int);
-int CpqTsLaserControl( void* addrBase, int opcode );
-int CpqTsReadWriteWWN(void*, int ReadWrite);
-int CpqTsReadWriteNVRAM(void*, void* data, int ReadWrite);
-
-void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter);
-void cpqfcTSWorkerThread( void *host);
-
-int cpqfcTS_GetNVRAM_data( UCHAR *wwnbuf, UCHAR *buf );
-ULONG cpqfcTS_ReadNVRAM( void* GPIOin, void* GPIOout , USHORT count,
-	UCHAR *buf );
-
-BOOLEAN tl_write_i2c_nvram( void* GPIOin, void* GPIOout,
-  USHORT startOffset,  // e.g. 0x2f for WWN start
-  USHORT count,
-  UCHAR *buf );
+int CpqTsLaserControl(void *addrBase, int opcode);
+int CpqTsReadWriteWWN(void *, int ReadWrite);
+int CpqTsReadWriteNVRAM(void *, void *data, int ReadWrite);
+
+void cpqfcTS_WorkTask(struct Scsi_Host *HostAdapter);
+void cpqfcTSWorkerThread(void *host);
+
+int cpqfcTS_GetNVRAM_data(__u8 * wwnbuf, __u8 * buf);
+__u32 cpqfcTS_ReadNVRAM(void *GPIOin, void *GPIOout, __u16 count, __u8 * buf);
+
+__u8 tl_write_i2c_nvram(void *GPIOin, void *GPIOout, __u16 startOffset,	// e.g. 0x2f for WWN start
+			   __u16 count, __u8 * buf);
 
 
 // define misc functions 
-int cpqfcTSGetLPSM( PTACHYON fcChip, char cErrorString[]);
-int cpqfcTSDecodeGBICtype( PTACHYON fcChip, char cErrorString[]);
-void* fcMemManager( struct pci_dev *pdev,
-		ALIGNED_MEM *dyn_mem_pair, ULONG n_alloc, ULONG ab,
-                   ULONG ulAlignedAddress, dma_addr_t *dma_handle);
+int cpqfcTSGetLPSM(PTACHYON fcChip, char cErrorString[]);
+int cpqfcTSDecodeGBICtype(PTACHYON fcChip, char cErrorString[]);
+void *fcMemManager(struct pci_dev *pdev, ALIGNED_MEM * dyn_mem_pair, __u32 n_alloc, __u32 ab, __u32 ulAlignedAddress, dma_addr_t * dma_handle);
 
-void BigEndianSwap(  UCHAR *source, UCHAR *dest,  USHORT cnt);
+void BigEndianSwap(__u8 * source, __u8 * dest, __u16 cnt);
+
+//__u32 virt_to_phys( void * virtaddr );
 
-//ULONG virt_to_phys( PVOID virtaddr );
-                  
 
 // Linux interrupt handler
-void cpqfcTS_intr_handler( int irq,void *dev_id,struct pt_regs *regs);
-void cpqfcTSheartbeat( unsigned long ptr );
+void cpqfcTS_intr_handler(int irq, void *dev_id, struct pt_regs *regs);
+void cpqfcTSheartbeat(unsigned long ptr);
 
 
 
@@ -872,19 +851,17 @@
 // need 4 bytes for x_ID, and a Scsi_Cmnd (~284 bytes)
 //#define LINKQ_ITEM_SIZE ((4+sizeof(Scsi_Cmnd)+3)/4)
 #define LINKQ_ITEM_SIZE (3*16)
-typedef struct
-{
-  ULONG Type;              // e.g. LINKUP, SFQENTRY, PDISC, BLS_ABTS, ...
-  ULONG ulBuff[ LINKQ_ITEM_SIZE ];
+typedef struct {
+	__u32 Type;		// e.g. LINKUP, SFQENTRY, PDISC, BLS_ABTS, ...
+	__u32 ulBuff[LINKQ_ITEM_SIZE];
 } LINKQ_ITEM;
 
 #define FC_LINKQ_DEPTH TACH_MAX_XID
-typedef struct
-{
-  ULONG producer;
-  ULONG consumer;  // when producer equals consumer, Q empty
+typedef struct {
+	__u32 producer;
+	__u32 consumer;		// when producer equals consumer, Q empty
 
-  LINKQ_ITEM Qitem[ FC_LINKQ_DEPTH ];
+	LINKQ_ITEM Qitem[FC_LINKQ_DEPTH];
 
 } FC_LINK_QUE, *PFC_LINK_QUE;
 
@@ -893,18 +870,16 @@
      // User thread processes
 #define FC_SCSIQ_DEPTH 32
 
-typedef struct
-{
-  int Type;              // e.g. SCSI
-  ULONG ulBuff[ 3*16 ];
+typedef struct {
+	int Type;		// e.g. SCSI
+	__u32 ulBuff[3 * 16];
 } SCSIQ_ITEM;
 
-typedef struct
-{
-  ULONG producer;
-  ULONG consumer;  // when producer equals consumer, Q empty
+typedef struct {
+	__u32 producer;
+	__u32 consumer;		// when producer equals consumer, Q empty
 
-  SCSIQ_ITEM Qitem[ FC_SCSIQ_DEPTH ];
+	SCSIQ_ITEM Qitem[FC_SCSIQ_DEPTH];
 
 } FC_SCSI_QUE, *PFC_SCSI_QUE;
 
@@ -912,44 +887,43 @@
 
 
 
-#define DYNAMIC_ALLOCATIONS 4  // Tachyon aligned allocations: ERQ,IMQ,SFQ,SEST
+#define DYNAMIC_ALLOCATIONS 4	// Tachyon aligned allocations: ERQ,IMQ,SFQ,SEST
 
 // Linux space allocated per HBA (chip state, etc.)
-typedef struct 
-{
-  struct Scsi_Host *HostAdapter; // back pointer to Linux Scsi struct
+typedef struct {
+	struct Scsi_Host *HostAdapter;	// back pointer to Linux Scsi struct
+
+	TACHYON fcChip;		// All Tachyon registers, Queues, functions
+	ALIGNED_MEM dynamic_mem[DYNAMIC_ALLOCATIONS];
+
+	struct pci_dev *PciDev;
+	dma_addr_t fcLQ_dma_handle;
+
+	Scsi_Cmnd *LinkDnCmnd[CPQFCTS_REQ_QUEUE_LEN];	// collects Cmnds during LDn
+	// (for Acceptable targets)
+	Scsi_Cmnd *BoardLockCmnd[CPQFCTS_REQ_QUEUE_LEN];	// SEST was full
+
+	Scsi_Cmnd *BadTargetCmnd[CPQFCTS_MAX_TARGET_ID];	// missing targets
+
+	u_char HBAnum;		// 0-based host number
+
 
-  TACHYON fcChip;    // All Tachyon registers, Queues, functions
-  ALIGNED_MEM dynamic_mem[DYNAMIC_ALLOCATIONS];
+	struct timer_list cpqfcTStimer;	// FC utility timer for implicit
+	// logouts, FC protocol timeouts, etc.
+	int fcStatsTime;	// Statistics delta reporting time
 
-  struct pci_dev *PciDev;
-  dma_addr_t fcLQ_dma_handle;
+	struct task_struct *worker_thread;	// our kernel thread
+	int PortDiscDone;	// set by SendLogins(), cleared by LDn
 
-  Scsi_Cmnd *LinkDnCmnd[CPQFCTS_REQ_QUEUE_LEN]; // collects Cmnds during LDn
-                                                // (for Acceptable targets)
-  Scsi_Cmnd *BoardLockCmnd[CPQFCTS_REQ_QUEUE_LEN]; // SEST was full
-  
-  Scsi_Cmnd *BadTargetCmnd[CPQFCTS_MAX_TARGET_ID]; // missing targets
-
-  u_char HBAnum;     // 0-based host number
-
-
-  struct timer_list cpqfcTStimer; // FC utility timer for implicit
-                                  // logouts, FC protocol timeouts, etc.
-  int fcStatsTime;  // Statistics delta reporting time
-
-  struct task_struct *worker_thread; // our kernel thread
-  int PortDiscDone;    // set by SendLogins(), cleared by LDn
-  
-  struct semaphore *TachFrozen;
-  struct semaphore *TYOBcomplete;    // handshake for Tach outbound frames
-  struct semaphore *fcQueReady;      // FibreChannel work for our kernel thread
-  struct semaphore *notify_wt;       // synchronizes kernel thread kill
-  struct semaphore *BoardLock;
-  
-  PFC_LINK_QUE fcLQ;             // the WorkerThread operates on this
+	struct semaphore *TachFrozen;
+	struct semaphore *TYOBcomplete;	// handshake for Tach outbound frames
+	struct semaphore *fcQueReady;	// FibreChannel work for our kernel thread
+	struct semaphore *notify_wt;	// synchronizes kernel thread kill
+	struct semaphore *BoardLock;
 
-  spinlock_t hba_spinlock;           // held/released by WorkerThread
+	PFC_LINK_QUE fcLQ;	// the WorkerThread operates on this
+
+	spinlock_t hba_spinlock;	// held/released by WorkerThread
 
 } CPQFCHBA;
 
@@ -958,69 +932,41 @@
 
 
 
-void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,
-		PFC_LOGGEDIN_PORT pFcPort);
+void cpqfcTSImplicitLogout(CPQFCHBA * cpqfcHBAdata, PFC_LOGGEDIN_PORT pFcPort);
+
+
+void cpqfcTSTerminateExchange(CPQFCHBA *, SCSI_NEXUS * target, int);
+
+PFC_LOGGEDIN_PORT fcPortLoggedIn(CPQFCHBA * cpqfcHBAdata, TachFCHDR_GCMND * fchs, __u8, __u8);
+void fcProcessLoggedIn(CPQFCHBA * cpqfcHBAdata, TachFCHDR_GCMND * fchs);
+
+
+__u32 cpqfcTSBuildExchange(CPQFCHBA * cpqfcHBAdata, __u32 type,	// e.g. PLOGI
+			   TachFCHDR_GCMND * InFCHS,	// incoming FCHS
+			   void *Data,	// the CDB, scatter/gather, etc.  
+			   __s32 * ExchangeID);	// allocated exchange ID
+
+__u32 cpqfcTSStartExchange(CPQFCHBA * cpqfcHBAdata, __s32 ExchangeID);
+
+void cpqfcTSCompleteExchange(struct pci_dev *pcidev, PTACHYON fcChip, __u32 exchange_ID);
+
+
+PFC_LOGGEDIN_PORT fcFindLoggedInPort(PTACHYON fcChip, Scsi_Cmnd * Cmnd,	// (We want the channel/target/lun Nexus from Cmnd)
+				     __u32 port_id,	// search linked list for al_pa, or
+				     __u8 wwn[8],	// search linked list for WWN, or...
+				     PFC_LOGGEDIN_PORT * pLastLoggedInPort);
 
+void cpqfcTSPutLinkQue(CPQFCHBA * cpqfcHBAdata, int Type, void *QueContent);
 
-void cpqfcTSTerminateExchange( CPQFCHBA*, SCSI_NEXUS *target, int );
+void fcPutScsiQue(CPQFCHBA * cpqfcHBAdata, int Type, void *QueContent);
 
-PFC_LOGGEDIN_PORT fcPortLoggedIn( 
-   CPQFCHBA *cpqfcHBAdata, 
-   TachFCHDR_GCMND* fchs, 
-   BOOLEAN, 
-   BOOLEAN);
-void fcProcessLoggedIn( 
-   CPQFCHBA *cpqfcHBAdata, TachFCHDR_GCMND* fchs);
-
-
-ULONG cpqfcTSBuildExchange( 
-  CPQFCHBA *cpqfcHBAdata,
-  ULONG type, // e.g. PLOGI
-  TachFCHDR_GCMND* InFCHS,  // incoming FCHS
-  void *Data,               // the CDB, scatter/gather, etc.  
-  LONG *ExchangeID );       // allocated exchange ID
-
-ULONG cpqfcTSStartExchange( 
-  CPQFCHBA *cpqfcHBAdata,
-  LONG ExchangeID );
-
-void cpqfcTSCompleteExchange( 
-       struct pci_dev *pcidev,
-       PTACHYON fcChip, 
-       ULONG exchange_ID);
-
-
-PFC_LOGGEDIN_PORT  fcFindLoggedInPort( 
-  PTACHYON fcChip, 
-  Scsi_Cmnd *Cmnd,  // (We want the channel/target/lun Nexus from Cmnd)
-  ULONG port_id,  // search linked list for al_pa, or
-  UCHAR wwn[8],    // search linked list for WWN, or...
-  PFC_LOGGEDIN_PORT *pLastLoggedInPort
-);
-
-void cpqfcTSPutLinkQue( 
-  CPQFCHBA *cpqfcHBAdata, 
-  int Type, 
-  void *QueContent);
-
-void fcPutScsiQue( 
-  CPQFCHBA *cpqfcHBAdata, 
-  int Type, 
-  void *QueContent);
-
-void fcLinkQReset(
-   CPQFCHBA *);
-void fcScsiQReset(
-   CPQFCHBA *);
-void fcSestReset(
-   CPQFCHBA *);
-
-void cpqfc_pci_unmap(struct pci_dev *pcidev, 
-	Scsi_Cmnd *cmd, 
-	PTACHYON fcChip, 
-	ULONG x_ID);
+void fcLinkQReset(CPQFCHBA *);
+void fcScsiQReset(CPQFCHBA *);
+void fcSestReset(CPQFCHBA *);
 
-extern const UCHAR valid_al_pa[];
+void cpqfc_pci_unmap(struct pci_dev *pcidev, Scsi_Cmnd * cmd, PTACHYON fcChip, __u32 x_ID);
+
+extern const __u8 valid_al_pa[];
 extern const int number_of_al_pa;
 
 #define FCP_RESID_UNDER   0x80000
@@ -1036,37 +982,35 @@
 #define FCP_TASKFUNCTION_FAIL      0x5000000
 
 // FCP-SCSI response status struct
-typedef struct  // see "TachFCHDR_RSP" definition - 64 bytes
+typedef struct			// see "TachFCHDR_RSP" definition - 64 bytes
 {
-  __u32 reserved;
-  __u32 reserved1;
-  __u32 fcp_status;    // field validity and SCSI status
-  __u32 fcp_resid;
-  __u32 fcp_sns_len;   // length of FCP_SNS_INFO field
-  __u32 fcp_rsp_len;   // length of FCP_RSP_INFO field (expect 8)
-  __u32 fcp_rsp_info;  // 4 bytes of FCP protocol response information
-  __u32 fcp_rsp_info2; // (4 more bytes, since most implementations use 8)
-  __u8  fcp_sns_info[36]; // bytes for SCSI sense (ASC, ASCQ)
+	__u32 reserved;
+	__u32 reserved1;
+	__u32 fcp_status;	// field validity and SCSI status
+	__u32 fcp_resid;
+	__u32 fcp_sns_len;	// length of FCP_SNS_INFO field
+	__u32 fcp_rsp_len;	// length of FCP_RSP_INFO field (expect 8)
+	__u32 fcp_rsp_info;	// 4 bytes of FCP protocol response information
+	__u32 fcp_rsp_info2;	// (4 more bytes, since most implementations use 8)
+	__u8 fcp_sns_info[36];	// bytes for SCSI sense (ASC, ASCQ)
 
 } FCP_STATUS_RESPONSE, *PFCP_STATUS_RESPONSE;
 
 
 // Fabric State Change Registration
-typedef struct scrpl
-{
-  __u32 command;
-  __u32 function;
+typedef struct scrpl {
+	__u32 command;
+	__u32 function;
 } SCR_PL;
 
 // Fabric Name Service Request
-typedef struct nsrpl
-{
-  __u32 CT_Rev;  // (& IN_ID)   WORD 0
-  __u32 FCS_Type;            // WORD 1
-  __u32 Command_code;        // WORD 2
-  __u32 reason_code;         // WORD 3
-  __u32 FCP;                 // WORD 4 (lower byte)
-  
+typedef struct nsrpl {
+	__u32 CT_Rev;		// (& IN_ID)   WORD 0
+	__u32 FCS_Type;		// WORD 1
+	__u32 Command_code;	// WORD 2
+	__u32 reason_code;	// WORD 3
+	__u32 FCP;		// WORD 4 (lower byte)
+
 } NSR_PL;
 
 
@@ -1089,12 +1033,12 @@
 					// PDISC after a LIP.
 #define E_D_TOV			2	// Minimum Time to wait for Sequence
 					// Completion.
-#define R_A_TOV			0	// Minimum Time for Target to wait 
+#define R_A_TOV			0	// Minimum Time for Target to wait
 					// before reclaiming resources.
 //
-//	R_CTL Field
+//      R_CTL Field
 //
-//	Routing Bits (31-28)
+//      Routing Bits (31-28)
 //
 #define FC4_DEVICE_DATA		0x00000000
 #define EXT_LINK_DATA		0x20000000
@@ -1105,7 +1049,7 @@
 #define ROUTING_MASK		0xF0000000
 
 //
-//	Information Bits (27-24)
+//      Information Bits (27-24)
 //
 #define UNCAT_INFORMATION	0x00000000
 #define SOLICITED_DATA		0x01000000
@@ -1117,20 +1061,20 @@
 #define COMMAND_STATUS		0x07000000
 #define INFO_MASK		0x0F000000
 //
-//	(Link Control Codes)
+//      (Link Control Codes)
 //
 #define ACK_1			0x00000000
 #define ACK_0_OR_N		0x01000000
-#define P_RJT			0x02000000 
-#define F_RJT			0x03000000 
+#define P_RJT			0x02000000
+#define F_RJT			0x03000000
 #define P_BSY			0x04000000
 #define FABRIC_BUSY_TO_DF	0x05000000	// Fabric Busy to Data Frame
 #define FABRIC_BUSY_TO_LC	0x06000000	// Fabric Busy to Link Ctl Frame
 #define LINK_CREDIT_RESET	0x07000000
 //
-//	(Link Service Command Codes)
+//      (Link Service Command Codes)
 //
-//#define LS_RJT			0x01000000	// LS Reject
+//#define LS_RJT                        0x01000000      // LS Reject
 
 #define LS_ACC			0x02000000	// LS Accept
 #define LS_PLOGI		0x03000000	// N_PORT Login
@@ -1156,11 +1100,11 @@
 #define LS_FDISC		0x51000000	// Fabric Discovery
 #define LS_ADISC		0x52000000	// Discover Address
 #define LS_RNC			0x53000000	// Report Node Capability
-#define LS_SCR                  0x62000000      // State Change Registration
-#define LS_MASK			0xFF000000	
+#define LS_SCR                  0x62000000	// State Change Registration
+#define LS_MASK			0xFF000000
 
 //
-// 	TYPE Bit Masks
+//      TYPE Bit Masks
 //
 #define BASIC_LINK_SERVICE	0x00000000
 #define EXT_LINK_SERVICE	0x01000000
@@ -1186,35 +1130,35 @@
 #define TYPE_MASK		0xFF000000
 
 typedef struct {
-	UCHAR seq_id_valid;
-	UCHAR seq_id;
-	USHORT reserved;  // 2 bytes reserved
-	ULONG ox_rx_id;
-	USHORT low_seq_cnt;
-	USHORT high_seq_cnt;
+	__u8 seq_id_valid;
+	__u8 seq_id;
+	__u16 reserved;	// 2 bytes reserved
+	__u32 ox_rx_id;
+	__u16 low_seq_cnt;
+	__u16 high_seq_cnt;
 } BA_ACC_PAYLOAD;
 
 typedef struct {
-	UCHAR reserved;
-	UCHAR reason_code;
-	UCHAR reason_explain;
-	UCHAR vendor_unique;
+	__u8 reserved;
+	__u8 reason_code;
+	__u8 reason_explain;
+	__u8 vendor_unique;
 } BA_RJT_PAYLOAD;
 
 
 typedef struct {
-	ULONG 	command_code;
-	ULONG 	sid;
-	USHORT	ox_id;
-	USHORT	rx_id;
+	__u32 command_code;
+	__u32 sid;
+	__u16 ox_id;
+	__u16 rx_id;
 } RRQ_MESSAGE;
 
 typedef struct {
-	ULONG command_code;
-	UCHAR vendor;
-	UCHAR explain;
-	UCHAR reason;
-	UCHAR reserved;
+	__u32 command_code;
+	__u8 vendor;
+	__u8 explain;
+	__u8 reason;
+	__u8 reserved;
 } REJECT_MESSAGE;
 
 
@@ -1244,9 +1188,9 @@
 
 #define X_ID_INTERLOCK		0x2000
 
-#define ERROR_POLICY		0x1800		// Error Policy Supported
-#define ERROR_DISCARD		0x00		// Only Discard Supported
-#define ERROR_DISC_PROCESS	0x02		// Discard and process supported
+#define ERROR_POLICY		0x1800	// Error Policy Supported
+#define ERROR_DISCARD		0x00	// Only Discard Supported
+#define ERROR_DISC_PROCESS	0x02	// Discard and process supported
 
 #define NODE_ID			0x01
 #define IEEE_EXT		0x20
@@ -1255,88 +1199,87 @@
 // Categories Supported Per Sequence
 //
 #define	CATEGORIES_PER_SEQUENCE	0x300
-#define ONE_CATEGORY_SEQUENCE	0x00		// 1 Category per Sequence
-#define TWO_CATEGORY_SEQUENCE	0x01		// 2 Categories per Sequence
-#define MANY_CATEGORY_SEQUENCE	0x03		// > 2 Categories/Sequence
+#define ONE_CATEGORY_SEQUENCE	0x00	// 1 Category per Sequence
+#define TWO_CATEGORY_SEQUENCE	0x01	// 2 Categories per Sequence
+#define MANY_CATEGORY_SEQUENCE	0x03	// > 2 Categories/Sequence
 
 typedef struct {
 
-	USHORT initiator_control;
-	USHORT service_options;
+	__u16 initiator_control;
+	__u16 service_options;
 
-	USHORT rx_data_size;
-	USHORT recipient_control;
+	__u16 rx_data_size;
+	__u16 recipient_control;
 
-	USHORT ee_credit;
-	USHORT concurrent_sequences;
+	__u16 ee_credit;
+	__u16 concurrent_sequences;
 
-	USHORT reserved;
-	USHORT open_sequences;
+	__u16 reserved;
+	__u16 open_sequences;
 
 } CLASS_PARAMETERS;
 
 typedef struct {
-	ULONG	login_cmd;
+	__u32 login_cmd;
 	//
 	// Common Service Parameters
 	//
 	struct {
 
-		USHORT bb_credit;
-		UCHAR lowest_ver;
-		UCHAR highest_ver;
+		__u16 bb_credit;
+		__u8 lowest_ver;
+		__u8 highest_ver;
 
-		USHORT bb_rx_size;
-		USHORT common_features;
+		__u16 bb_rx_size;
+		__u16 common_features;
 
-		USHORT rel_offset;
-		USHORT concurrent_seq;
+		__u16 rel_offset;
+		__u16 concurrent_seq;
 
 
-		ULONG e_d_tov;
+		__u32 e_d_tov;
 	} cmn_services;
 
 	//
 	// Port Name
 	//
-	UCHAR port_name[8];
+	__u8 port_name[8];
 
 	//
 	// Node/Fabric Name
 	//
-	UCHAR node_name[8];
+	__u8 node_name[8];
 
 	//
 	// Class 1, 2 and 3 Service Parameters
 	//
-	CLASS_PARAMETERS	class1;
-	CLASS_PARAMETERS	class2;
-	CLASS_PARAMETERS	class3;
+	CLASS_PARAMETERS class1;
+	CLASS_PARAMETERS class2;
+	CLASS_PARAMETERS class3;
 
-	ULONG reserved[4];
+	__u32 reserved[4];
 
 	//
 	// Vendor Version Level
 	//
-	UCHAR		vendor_id[2];
-	UCHAR		vendor_version[6];
-	ULONG		buffer_size;
-	USHORT		rxid_start;
-	USHORT		total_rxids;
+	__u8 vendor_id[2];
+	__u8 vendor_version[6];
+	__u32 buffer_size;
+	__u16 rxid_start;
+	__u16 total_rxids;
 } LOGIN_PAYLOAD;
 
 
-typedef struct
-{
-  ULONG cmd;  // 4 bytes
-  UCHAR n_port_identifier[3];
-  UCHAR reserved;
-  UCHAR port_name[8];
+typedef struct {
+	__u32 cmd;		// 4 bytes
+	__u8 n_port_identifier[3];
+	__u8 reserved;
+	__u8 port_name[8];
 } LOGOUT_PAYLOAD;
 
 
 //
-//	PRLI Request Service Parameter Defines
+//      PRLI Request Service Parameter Defines
 //
 #define PRLI_ACC			0x01
 #define PRLI_REQ			0x02
@@ -1361,54 +1304,54 @@
 #define NO_MULTI_PAGE		0x700
 
 typedef struct {
-	USHORT	payload_length;
-	UCHAR	page_length;
-	UCHAR	cmd;
+	__u16 payload_length;
+	__u8 page_length;
+	__u8 cmd;
+
 
+	__u32 valid;
 
-	ULONG	valid;
+	__u32 orig_process_associator;
 
-	ULONG	orig_process_associator;
+	__u32 resp_process_associator;
 
-	ULONG	resp_process_associator;
-	
-	ULONG	fcp_info;
+	__u32 fcp_info;
 } PRLI_REQUEST;
 
 typedef struct {
 
-	USHORT	payload_length;
-	UCHAR	page_length;
-	UCHAR	cmd;
+	__u16 payload_length;
+	__u8 page_length;
+	__u8 cmd;
 
-	ULONG	valid;
-	ULONG	orig_process_associator;
+	__u32 valid;
+	__u32 orig_process_associator;
 
-	ULONG	resp_process_associator;
-	ULONG	reserved;
+	__u32 resp_process_associator;
+	__u32 reserved;
 } PRLO_REQUEST;
 
 typedef struct {
-	ULONG	cmd;
+	__u32 cmd;
+
+	__u32 hard_address;
 
-	ULONG	hard_address;
-	
-	UCHAR	port_name[8];
+	__u8 port_name[8];
 
-	UCHAR	node_name[8];
+	__u8 node_name[8];
 
-	ULONG	s_id;
+	__u32 s_id;
 } ADISC_PAYLOAD;
 
 struct ext_sg_entry_t {
 	__u32 len:18;		/* buffer length, bits 0-17 */
 	__u32 uba:13;		/* upper bus address bits 18-31 */
 	__u32 lba;		/* lower bus address bits 0-31 */
-}; 
+};
 
 // J. McCarty's LINK.H
 //
-//	LS_RJT Reason Codes
+//      LS_RJT Reason Codes
 //
 
 #define INVALID_COMMAND_CODE	0x01
@@ -1420,7 +1363,7 @@
 #define LS_VENDOR_UNIQUE	0xFF
 
 //
-// 	LS_RJT Reason Codes Explanations
+//      LS_RJT Reason Codes Explanations
 //
 #define NO_REASON		0x00
 #define OPTIONS_ERROR		0x01
@@ -1439,38 +1382,38 @@
 #define CMD_IN_PROCESS		0x19
 #define INVALID_IDENTIFIER	0x1F	// Invalid N_PORT Identifier
 #define INVALID_SEQ_ID		0x21
-#define ABT_INVALID_XCHNG	0x23 	// Attempt to Abort an invalid Exchange
-#define ABT_INACTIVE_XCHNG	0x25 	// Attempt to Abort an inactive Exchange
+#define ABT_INVALID_XCHNG	0x23	// Attempt to Abort an invalid Exchange
+#define ABT_INACTIVE_XCHNG	0x25	// Attempt to Abort an inactive Exchange
 #define NEED_REC_QUAL		0x27	// Recovery Qualifier required
 #define NO_LOGIN_RESOURCES	0x29	// No resources to support login
 #define NO_DATA			0x2A	// Unable to supply requested data
 #define	REQUEST_NOT_SUPPORTED	0x2C	// Request Not Supported
 
 //
-//	Link Control Codes
+//      Link Control Codes
 //
 
 //
-//	P_BSY Action Codes
+//      P_BSY Action Codes
 //
 #define SEQUENCE_TERMINATED	0x01000000
 #define SEQUENCE_ACTIVE		0x02000000
 
 //
-//	P_BSY Reason Codes
+//      P_BSY Reason Codes
 //
 #define PHYS_NPORT_BUSY		0x010000
 #define NPORT_RESOURCE_BUSY	0x020000
 
 //
-// 	P_RJT, F_RJT Action Codes
+//      P_RJT, F_RJT Action Codes
 //
 
 #define RETRYABLE_ERROR		0x01000000
 #define NON_RETRYABLE_ERROR	0x02000000
 
 //
-// 	P_RJT, F_RJT Reason Codes
+//      P_RJT, F_RJT Reason Codes
 //
 #define INVALID_D_ID		0x010000
 #define INVALID_S_ID		0x020000
@@ -1500,7 +1443,7 @@
 #define P_VENDOR_UNIQUE		0xFF0000
 
 //
-// 	BA_RJT Reason Codes
+//      BA_RJT Reason Codes
 //
 #define BA_INVALID_COMMAND	0x00010000
 #define BA_LOGICAL_ERROR	0x00030000
@@ -1509,7 +1452,7 @@
 #define BA_UNABLE_TO_PERFORM	0x00090000
 
 //
-// 	BA_RJT Reason Explanation Codes
+//      BA_RJT Reason Explanation Codes
 //
 #define BA_NO_REASON		0x00000000
 #define BA_INVALID_OX_RX	0x00000300
@@ -1517,5 +1460,4 @@
 
 
 
-#endif /* CPQFCTSSTRUCTS_H	*/
-
+#endif				/* CPQFCTSSTRUCTS_H      */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/cpqfcTStrigger.c linux.20pre10-ac2/drivers/scsi/cpqfcTStrigger.c
--- linux.20pre10/drivers/scsi/cpqfcTStrigger.c	2002-10-09 21:36:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/cpqfcTStrigger.c	2002-09-12 17:22:57.000000000 +0100
@@ -12,22 +12,22 @@
 #include <linux/pci.h>
 #include <asm/io.h>
 
-void TriggerHBA( void* IOBaseUpper, int Print)
+void TriggerHBA(void *io_upper, int print)
 {
-  __u32 long value;
+	__u32 long value;
 
-  // get initial value in hopes of not modifying any other GPIO line
-  IOBaseUpper += 0x188;  // TachTL/TS Control reg
-  
-  value = readl( IOBaseUpper);
-  // set HIGH to trigger external analyzer (tested on Dolche Finisar 1Gb GTA)
-  // The Finisar anaylzer triggers on low-to-high TTL transition
-  value |= 0x01; // set bit 0
+	// get initial value in hopes of not modifying any other GPIO line
+	io_upper += 0x188;	// TachTL/TS Control reg
 
-  writel( value, IOBaseUpper);
+	value = readl(io_upper);
+	// set HIGH to trigger external analyzer (tested on Dolche Finisar 1Gb GTA)
+	// The Finisar anaylzer triggers on low-to-high TTL transition
+	value |= 0x01;		// set bit 0
 
-  if( Print)
-    printk( " -GPIO0 set- ");
+	writel(value, io_upper);
+
+	if (print)
+		printk(" -GPIO0 set- ");
 }
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/cpqfcTStrigger.h linux.20pre10-ac2/drivers/scsi/cpqfcTStrigger.h
--- linux.20pre10/drivers/scsi/cpqfcTStrigger.h	2002-10-09 21:36:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/cpqfcTStrigger.h	2002-09-12 14:18:26.000000000 +0100
@@ -1,8 +1,7 @@
 // don't do this unless you have the right hardware!
 #define TRIGGERABLE_HBA 0
 #if TRIGGERABLE_HBA
-void TriggerHBA( void*, int);
+void TriggerHBA(void *, int);
 #else
 #define TriggerHBA(x, y)
 #endif
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/cpqfcTSworker.c linux.20pre10-ac2/drivers/scsi/cpqfcTSworker.c
--- linux.20pre10/drivers/scsi/cpqfcTSworker.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/cpqfcTSworker.c	2002-09-12 18:46:16.000000000 +0100
@@ -44,7 +44,7 @@
 
 
 #include "sd.h"
-#include "hosts.h"   // struct Scsi_Host definition for T handler
+#include "hosts.h"		// struct Scsi_Host definition for T handler
 #include "cpqfcTSchip.h"
 #include "cpqfcTSstructs.h"
 #include "cpqfcTStrigger.h"
@@ -116,724 +116,579 @@
 
 // local functions
 
-static void SetLoginFields(
-  PFC_LOGGEDIN_PORT pLoggedInPort,
-  TachFCHDR_GCMND* fchs,
-  BOOLEAN PDisc,
-  BOOLEAN Originator);
+static void SetLoginFields(PFC_LOGGEDIN_PORT pLoggedInPort, TachFCHDR_GCMND * fchs, u8 PDisc, u8 Originator);
 
-static void AnalyzeIncomingFrame( 
-       CPQFCHBA *cpqfcHBAdata,
-       ULONG QNdx );
+static void AnalyzeIncomingFrame(CPQFCHBA * dev, u32 QNdx);
 
-static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds );
+static void SendLogins(CPQFCHBA * dev, __u32 * FabricPortIds);
 
-static int verify_PLOGI( PTACHYON fcChip,
-      TachFCHDR_GCMND* fchs, ULONG* reject_explain);
-static int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain);
+static int verify_PLOGI(PTACHYON fcChip, TachFCHDR_GCMND * fchs, u32 * reject_explain);
+static int verify_PRLI(TachFCHDR_GCMND * fchs, u32 * reject_explain);
 
-static void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type);
-static void BuildLinkServicePayload( 
-              PTACHYON fcChip, ULONG type, void* payload);
+static void LoadWWN(PTACHYON fcChip, u8 * dest, u8 type);
+static void BuildLinkServicePayload(PTACHYON fcChip, u32 type, void *payload);
 
-static void UnblockScsiDevice( struct Scsi_Host *HostAdapter, 
-        PFC_LOGGEDIN_PORT pLoggedInPort);
+static void UnblockScsiDevice(struct Scsi_Host *HostAdapter, PFC_LOGGEDIN_PORT pLoggedInPort);
 
-static void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID);
+static void cpqfcTSCheckandSnoopFCP(PTACHYON fcChip, u32 x_ID);
 
-static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata);
+static void CompleteBoardLockCmnd(CPQFCHBA * dev);
 
-static void RevalidateSEST( struct Scsi_Host *HostAdapter, 
-		        PFC_LOGGEDIN_PORT pLoggedInPort);
+static void RevalidateSEST(struct Scsi_Host *HostAdapter, PFC_LOGGEDIN_PORT pLoggedInPort);
 
-static void IssueReportLunsCommand( 
-              CPQFCHBA* cpqfcHBAdata, 
-	      TachFCHDR_GCMND* fchs);
+static void IssueReportLunsCommand(CPQFCHBA * dev, TachFCHDR_GCMND * fchs);
 
 // (see scsi_error.c comments on kernel task creation)
 
-void cpqfcTSWorkerThread( void *host)
+void cpqfcTSWorkerThread(void *host)
 {
-  struct Scsi_Host *HostAdapter = (struct Scsi_Host*)host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; 
+	struct Scsi_Host *shpnt = (struct Scsi_Host *) host;
+	CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
 #ifdef PCI_KERNEL_TRACE
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	PTACHYON fcChip = &dev->fcChip;
 #endif
-  struct fs_struct *fs;
-  DECLARE_MUTEX_LOCKED(fcQueReady);
-  DECLARE_MUTEX_LOCKED(fcTYOBcomplete); 
-  DECLARE_MUTEX_LOCKED(TachFrozen);  
-  DECLARE_MUTEX_LOCKED(BoardLock);  
+	struct fs_struct *fs;
+	DECLARE_MUTEX_LOCKED(fcQueReady);
+	DECLARE_MUTEX_LOCKED(fcTYOBcomplete);
+	DECLARE_MUTEX_LOCKED(TachFrozen);
+	DECLARE_MUTEX_LOCKED(BoardLock);
 
-  ENTER("WorkerThread");
+	ENTER("WorkerThread");
 
-  lock_kernel();
+	lock_kernel();
 	/*
 	 * If we were started as result of loading a module, close all of the
 	 * user space pages.  We don't need them, and if we didn't close them
 	 * they would be locked into memory.
+	 *
+	 * FIXME: should use daemonize!
 	 */
-  exit_mm(current);
+	exit_mm(current);
 
-  current->session = 1;
-  current->pgrp = 1;
-	
-  /* Become as one with the init task */
-	
-  exit_fs(current);	/* current->fs->count--; */
-  fs = init_task.fs;
-  // Some kernels compiled for SMP, while actually running
-  // on a uniproc machine, will return NULL for this call
-  if( !fs)
-  {
-    printk(" cpqfcTS FATAL: fs is NULL! Is this an SMP kernel on uniproc machine?\n ");
-  }
- 
-  else
-  { 
-    current->fs = fs;
-    atomic_inc(&fs->count);
-  }
+	current->session = 1;
+	current->pgrp = 1;
 
-  siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
+	/* Become as one with the init task */
 
+	exit_fs(current);	/* current->fs->count--; */
+	fs = init_task.fs;
+	current->fs = fs;
+	atomic_inc(&fs->count);
 
-  /*
-   * Set the name of this process.
-   */
-  sprintf(current->comm, "cpqfcTS_wt_%d", HostAdapter->host_no);
+	siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
 
-  cpqfcHBAdata->fcQueReady = &fcQueReady;  // primary wait point
-  cpqfcHBAdata->TYOBcomplete = &fcTYOBcomplete;
-  cpqfcHBAdata->TachFrozen = &TachFrozen;
-    
- 
-  cpqfcHBAdata->worker_thread = current;
-  
-  unlock_kernel();
 
-  if( cpqfcHBAdata->notify_wt != NULL )
-    up( cpqfcHBAdata->notify_wt); // OK to continue
+	/*
+	 * Set the name of this process.
+	 */
+	sprintf(current->comm, "cpqfcTS_wt_%d", shpnt->host_no);
 
-  while(1)
-  {
-    unsigned long flags;
+	dev->fcQueReady = &fcQueReady;	// primary wait point
+	dev->TYOBcomplete = &fcTYOBcomplete;
+	dev->TachFrozen = &TachFrozen;
 
-    down_interruptible( &fcQueReady);  // wait for something to do
 
-    if (signal_pending(current) )
-      break;
-    
-    PCI_TRACE( 0x90)
-    // first, take the IO lock so the SCSI upper layers can't call
-    // into our _quecommand function (this also disables INTs)
-    spin_lock_irqsave( &io_request_lock, flags); // STOP _que function
-    PCI_TRACE( 0x90)
-         
-    CPQ_SPINLOCK_HBA( cpqfcHBAdata)
-    // next, set this pointer to indicate to the _quecommand function
-    // that the board is in use, so it should que the command and 
-    // immediately return (we don't actually require the semaphore function
-    // in this driver rev)
+	dev->worker_thread = current;
 
-    cpqfcHBAdata->BoardLock = &BoardLock;
+	unlock_kernel();
 
-    PCI_TRACE( 0x90)
+	if (dev->notify_wt != NULL)
+		up(dev->notify_wt);	// OK to continue
 
-    // release the IO lock (and re-enable interrupts)
-    spin_unlock_irqrestore( &io_request_lock, flags);
+	while (1) {
+		unsigned long flags;
 
-    // disable OUR HBA interrupt (keep them off as much as possible
-    // during error recovery)
-    disable_irq( cpqfcHBAdata->HostAdapter->irq);
+		down_interruptible(&fcQueReady);	// wait for something to do
 
-    // OK, let's process the Fibre Channel Link Q and do the work
-    cpqfcTS_WorkTask( HostAdapter);
+		if (signal_pending(current))
+			break;
 
-    // hopefully, no more "work" to do;
-    // re-enable our INTs for "normal" completion processing
-    enable_irq( cpqfcHBAdata->HostAdapter->irq);
- 
+		PCI_TRACE(0x90)
+		// first, take the IO lock so the SCSI upper layers can't call
+		// into our _quecommand function (this also disables INTs)
+		spin_lock_irqsave(&io_request_lock, flags);	// STOP _que function
+		PCI_TRACE(0x90)
 
-    cpqfcHBAdata->BoardLock = NULL; // allow commands to be queued
-    CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
+		CPQ_SPINLOCK_HBA(dev)
+		// next, set this pointer to indicate to the _quecommand function
+		// that the board is in use, so it should que the command and 
+		// immediately return (we don't actually require the semaphore function
+		// in this driver rev)
+		dev->BoardLock = &BoardLock;
 
+		PCI_TRACE(0x90)
+		// release the IO lock (and re-enable interrupts)
+		spin_unlock_irqrestore(&io_request_lock, flags);
 
-    // Now, complete any Cmnd we Q'd up while BoardLock was held
+		// disable OUR HBA interrupt (keep them off as much as possible
+		// during error recovery)
+		disable_irq(dev->HostAdapter->irq);
 
-    CompleteBoardLockCmnd( cpqfcHBAdata);
-  
+		// OK, let's process the Fibre Channel Link Q and do the work
+		cpqfcTS_WorkTask(shpnt);
 
-  }
-  // hopefully, the signal was for our module exit...
-  if( cpqfcHBAdata->notify_wt != NULL )
-    up( cpqfcHBAdata->notify_wt); // yep, we're outta here
+		// hopefully, no more "work" to do;
+		// re-enable our INTs for "normal" completion processing
+		enable_irq(dev->HostAdapter->irq);
+
+
+		dev->BoardLock = NULL;	// allow commands to be queued
+		CPQ_SPINUNLOCK_HBA(dev)
+
+		// Now, complete any Cmnd we Q'd up while BoardLock was held
+		CompleteBoardLockCmnd(dev);
+
+
+	}
+	// hopefully, the signal was for our module exit...
+	if (dev->notify_wt != NULL)
+		up(dev->notify_wt);	// yep, we're outta here
 }
 
 
 // Freeze Tachyon routine.
-// If Tachyon is already frozen, return FALSE
-// If Tachyon is not frozen, call freeze function, return TRUE
+// If Tachyon is already frozen, return 0
+// If Tachyon is not frozen, call freeze function, return 1
 //
-static BOOLEAN FreezeTach( CPQFCHBA *cpqfcHBAdata)
+static u8 FreezeTach(CPQFCHBA * dev)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  BOOLEAN FrozeTach = FALSE;
-  // It's possible that the chip is already frozen; if so,
-  // "Freezing" again will NOT! generate another Freeze
-  // Completion Message.
-
-  if( (fcChip->Registers.TYstatus.value & 0x70000) != 0x70000)
-  {  // (need to freeze...)
-    fcChip->FreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
-
-    // 2. Get Tach freeze confirmation
-    // (synchronize SEST manipulation with Freeze Completion Message)
-    // we need INTs on so semaphore can be set.	
-    enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Semaphore
-    down_interruptible( cpqfcHBAdata->TachFrozen); // wait for INT handler sem.
-    // can we TIMEOUT semaphore wait?? TBD
-    disable_irq( cpqfcHBAdata->HostAdapter->irq); 
-
-    FrozeTach = TRUE;
-  }  // (else, already frozen)
- 
-  return FrozeTach;
-}  
-
-
-
+	PTACHYON fcChip = &dev->fcChip;
+	u8 FrozeTach = 0;
+	// It's possible that the chip is already frozen; if so,
+	// "Freezing" again will NOT! generate another Freeze
+	// Completion Message.
+
+	if ((fcChip->Registers.TYstatus.value & 0x70000) != 0x70000) {	// (need to freeze...)
+		fcChip->FreezeTachyon(fcChip, 2);	// both ERQ and FCP assists
+		// 2. Get Tach freeze confirmation
+		// (synchronize SEST manipulation with Freeze Completion Message)
+		// we need INTs on so semaphore can be set. 
+		enable_irq(dev->HostAdapter->irq);	// only way to get Semaphore
+		down_interruptible(dev->TachFrozen);	// wait for INT handler sem.
+		// can we TIMEOUT semaphore wait?? TBD
+		disable_irq(dev->HostAdapter->irq);
+		FrozeTach = 1;
+	}			// (else, already frozen)
+	return FrozeTach;
+}
 
 // This is the kernel worker thread task, which processes FC
 // tasks which were queued by the Interrupt handler or by
 // other WorkTask functions.
 
 #define DBG 1
+
 //#undef DBG
-void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter)
+void cpqfcTS_WorkTask(struct Scsi_Host *shpnt)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG QconsumerNdx;
-  LONG ExchangeID;
-  ULONG ulStatus=0;
-  TachFCHDR_GCMND fchs;
-  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
-
-  ENTER("WorkTask");
-
-  // copy current index to work on
-  QconsumerNdx = fcLQ->consumer;
-
-  PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x90)
-  
-
-  // NOTE: when this switch completes, we will "consume" the Que item
-//  printk("Que type %Xh\n", fcLQ->Qitem[QconsumerNdx].Type);
-  switch( fcLQ->Qitem[QconsumerNdx].Type )
-  {
-      // incoming frame - link service (ACC, UNSOL REQ, etc.)
-      // or FCP-SCSI command
-    case SFQ_UNKNOWN:  
-      AnalyzeIncomingFrame( cpqfcHBAdata, QconsumerNdx );
+	CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 QconsumerNdx;
+	s32 ExchangeID;
+	u32 ulStatus = 0;
+	TachFCHDR_GCMND fchs;
+	PFC_LINK_QUE fcLQ = dev->fcLQ;
+
+	ENTER("WorkTask");
+
+	// copy current index to work on
+	QconsumerNdx = fcLQ->consumer;
+
+	PCI_TRACEO(fcLQ->Qitem[QconsumerNdx].Type, 0x90)
+
+	// NOTE: when this switch completes, we will "consume" the Que item
+	//  printk("Que type %Xh\n", fcLQ->Qitem[QconsumerNdx].Type);
+	switch (fcLQ->Qitem[QconsumerNdx].Type) 
+	{
+		// incoming frame - link service (ACC, UNSOL REQ, etc.)
+		// or FCP-SCSI command
+	case SFQ_UNKNOWN:
+		AnalyzeIncomingFrame(dev, QconsumerNdx);
+		break;
 
-      break;
-  
-    
-    
-    case EXCHANGE_QUEUED:  // an Exchange (i.e. FCP-SCSI) was previously
-                           // Queued because the link was down.  The  
-                           // heartbeat timer detected it and Queued it here.
-                           // We attempt to start it again, and if
-                           // successful we clear the EXCHANGE_Q flag.
-                           // If the link doesn't come up, the Exchange
-                           // will eventually time-out.
-
-      ExchangeID = (LONG)  // x_ID copied from DPC timeout function
-                   fcLQ->Qitem[QconsumerNdx].ulBuff[0];
-
-      // It's possible that a Q'd exchange could have already
-      // been started by other logic (e.g. ABTS process)
-      // Don't start if already started (Q'd flag clear)
-
-      if( Exchanges->fcExchange[ExchangeID].status & EXCHANGE_QUEUED )
-      {
-//        printk(" *Start Q'd x_ID %Xh: type %Xh ", 
-//          ExchangeID, Exchanges->fcExchange[ExchangeID].type);
-      
-        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID);
-        if( !ulStatus )
-        {
-//          printk("success* ");
-        }	
-        else
-        {
+	case EXCHANGE_QUEUED:	
+		// an Exchange (i.e. FCP-SCSI) was previously
+		// Queued because the link was down.  The  
+		// heartbeat timer detected it and Queued it here.
+		// We attempt to start it again, and if
+		// successful we clear the EXCHANGE_Q flag.
+		// If the link doesn't come up, the Exchange
+		// will eventually time-out.
+
+		ExchangeID = (s32) fcLQ->Qitem[QconsumerNdx].ulBuff[0]; // x_ID copied from DPC timeout function
+
+		// It's possible that a Q'd exchange could have already
+		// been started by other logic (e.g. ABTS process)
+		// Don't start if already started (Q'd flag clear)
+
+		if (Exchanges->fcExchange[ExchangeID].status & EXCHANGE_QUEUED) {
+//      		printk(" *Start Q'd x_ID %Xh: type %Xh ", 
+//				ExchangeID, Exchanges->fcExchange[ExchangeID].type);
+
+			ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+			if (!ulStatus) {
+//				printk("success* ");
+			} else {
 #ifdef DBG
-      
-          if( ulStatus == EXCHANGE_QUEUED)
-            printk("Queued* ");
-          else
-            printk("failed* ");
-		
+				if (ulStatus == EXCHANGE_QUEUED)
+					printk("Queued* ");
+				else
+					printk("failed* ");
 #endif
-	} 
-      }
-      break;
+			}
+		}
+		break;
 
+	case LINKDOWN:
+		// (lots of things already done in INT handler) future here?
+		break;
 
-    case LINKDOWN:  
-      // (lots of things already done in INT handler) future here?
-      break;
-    
-    
-    case LINKACTIVE:   // Tachyon set the Lup bit in FM status
-                       // NOTE: some misbehaving FC ports (like Tach2.1)
-                       // can re-LIP immediately after a LIP completes.
-      
-      // if "initiator", need to verify LOGs with ports
-//      printk("\n*LNKUP* ");
+	case LINKACTIVE:	// Tachyon set the Lup bit in FM status
+		// NOTE: some misbehaving FC ports (like Tach2.1)
+		// can re-LIP immediately after a LIP completes.
+		// if "initiator", need to verify LOGs with ports
+//		printk("\n*LNKUP* ");
+
+		if (fcChip->Options.initiator)
+			SendLogins(dev, NULL);	// PLOGI or PDISC, based on fcPort data
+		// if SendLogins successfully completes, PortDiscDone
+		// will be set.
+		// If SendLogins was successful, then we expect to get incoming
+		// ACCepts or REJECTs, which are handled below.
+		break;
 
-      if( fcChip->Options.initiator )
-        SendLogins( cpqfcHBAdata, NULL ); // PLOGI or PDISC, based on fcPort data
-                  // if SendLogins successfully completes, PortDiscDone
-                  // will be set.
-      
-      
-      // If SendLogins was successful, then we expect to get incoming
-      // ACCepts or REJECTs, which are handled below.
+		// LinkService and Fabric request/reply processing
+	case ELS_FDISC:	// need to send Fabric Discovery (Login)
+	case ELS_FLOGI:	// need to send Fabric Login
+	case ELS_SCR:		// need to send State Change Registration
+	case FCS_NSR:		// need to send Name Service Request
+	case ELS_PLOGI:	// need to send PLOGI
+	case ELS_ACC:		// send generic ACCept
+	case ELS_PLOGI_ACC:	// need to send ELS ACCept frame to recv'd PLOGI
+	case ELS_PRLI_ACC:	// need to send ELS ACCept frame to recv'd PRLI
+	case ELS_LOGO:		// need to send ELS LOGO (logout)
+	case ELS_LOGO_ACC:	// need to send ELS ACCept frame to recv'd PLOGI
+	case ELS_RJT:		// ReJecT reply
+	case ELS_PRLI:		// need to send ELS PRLI
+
+
+//		printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type);
+		// if PortDiscDone is not set, it means the SendLogins routine
+		// failed to complete -- assume that LDn occurred, so login frames
+		// are invalid
+		if (!dev->PortDiscDone)	// cleared by LDn
+		{
+			printk("Discard Q'd ELS login frame\n");
+			break;
+		}
 
-      break;
+		ulStatus = cpqfcTSBuildExchange(dev, fcLQ->Qitem[QconsumerNdx].Type,	// e.g. PLOGI
+						(TachFCHDR_GCMND *)
+						fcLQ->Qitem[QconsumerNdx].ulBuff,	// incoming fchs
+						NULL,	// no data (no scatter/gather list)
+						&ExchangeID);	// fcController->fcExchanges index, -1 if failed
+
+		if (!ulStatus)	// Exchange setup?
+		{
+			ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+			if (!ulStatus) {
+				// submitted to Tach's Outbound Que (ERQ PI incremented)
+				// waited for completion for ELS type (Login frames issued
+				// synchronously)
+			} else
+				// check reason for Exchange not being started - we might
+				// want to Queue and start later, or fail with error
+			{
 
-    // LinkService and Fabric request/reply processing
-    case ELS_FDISC:      // need to send Fabric Discovery (Login)
-    case ELS_FLOGI:      // need to send Fabric Login
-    case ELS_SCR:        // need to send State Change Registration
-    case FCS_NSR:        // need to send Name Service Request
-    case ELS_PLOGI:      // need to send PLOGI
-    case ELS_ACC:        // send generic ACCept
-    case ELS_PLOGI_ACC:  // need to send ELS ACCept frame to recv'd PLOGI
-    case ELS_PRLI_ACC:   // need to send ELS ACCept frame to recv'd PRLI
-    case ELS_LOGO:      // need to send ELS LOGO (logout)
-    case ELS_LOGO_ACC:  // need to send ELS ACCept frame to recv'd PLOGI
-    case ELS_RJT:         // ReJecT reply
-    case ELS_PRLI:       // need to send ELS PRLI
- 
-    
-//      printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type);
-      // if PortDiscDone is not set, it means the SendLogins routine
-      // failed to complete -- assume that LDn occurred, so login frames
-      // are invalid
-      if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
-      {
-        printk("Discard Q'd ELS login frame\n");
-        break;  
-      }
-
-      ulStatus = cpqfcTSBuildExchange(
-          cpqfcHBAdata,
-          fcLQ->Qitem[QconsumerNdx].Type, // e.g. PLOGI
-          (TachFCHDR_GCMND*)
-            fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
-          NULL,         // no data (no scatter/gather list)
-          &ExchangeID );// fcController->fcExchanges index, -1 if failed
-
-      if( !ulStatus ) // Exchange setup?
-      {
-        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-        if( !ulStatus )
-        {
-          // submitted to Tach's Outbound Que (ERQ PI incremented)
-          // waited for completion for ELS type (Login frames issued
-          // synchronously)
-        }
-        else
-          // check reason for Exchange not being started - we might
-          // want to Queue and start later, or fail with error
-        {
-
-        }
-      }
-
-      else   // Xchange setup failed...
-        printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
-
-      break;
-
-    case SCSI_REPORT_LUNS:
-      // pass the incoming frame (actually, it's a PRLI frame)
-      // so we can send REPORT_LUNS, in order to determine VSA/PDU
-      // FCP-SCSI Lun address mode
-      IssueReportLunsCommand( cpqfcHBAdata, (TachFCHDR_GCMND*)
-            fcLQ->Qitem[QconsumerNdx].ulBuff); 
+			}
+		}
 
-      break;
-      
+		else		// Xchange setup failed...
+			printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus);
 
+		break;
 
+	case SCSI_REPORT_LUNS:
+		// pass the incoming frame (actually, it's a PRLI frame)
+		// so we can send REPORT_LUNS, in order to determine VSA/PDU
+		// FCP-SCSI Lun address mode
+		IssueReportLunsCommand(dev, (TachFCHDR_GCMND *)
+				       fcLQ->Qitem[QconsumerNdx].ulBuff);
 
-    case BLS_ABTS:       // need to ABORT one or more exchanges
-    {
-      LONG x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0];
-      BOOLEAN FrozeTach = FALSE;   
-     
-      if( x_ID > TACH_SEST_LEN )  // (in)sanity check
-      {
-//	printk( " cpqfcTS ERROR! BOGUS x_ID %Xh", x_ID);
-	break;
-      }
-
-
-      if( Exchanges->fcExchange[ x_ID].Cmnd == NULL ) // should be RARE
-      {
-//	printk(" ABTS %Xh Scsi Cmnd null! ", x_ID);
-	
-       break;  // nothing to abort!
-      }
+		break;
 
+	case BLS_ABTS:		// need to ABORT one or more exchanges
+		{
+			s32 x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0];
+			u8 FrozeTach = 0;
+
+			if (x_ID > TACH_SEST_LEN)	// (in)sanity check
+			{
+//				printk( " cpqfcTS ERROR! BOGUS x_ID %Xh", x_ID);
+				break;
+			}
+			if (Exchanges->fcExchange[x_ID].Cmnd == NULL)	// should be RARE
+			{
+//				printk(" ABTS %Xh Scsi Cmnd null! ", x_ID);
+				break;	// nothing to abort!
+			}
 //#define ABTS_DBG
 #ifdef ABTS_DBG
-      printk("INV SEST[%X] ", x_ID); 
-      if( Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT)
-      {
-        printk("FC2TO");
-      }
-      if( Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)
-      {
-        printk("IA");
-      }
-      if( Exchanges->fcExchange[x_ID].status & PORTID_CHANGED)
-      {
-        printk("PORTID");
-      }
-      if( Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)
-      {
-        printk("DEVRM");
-      }
-      if( Exchanges->fcExchange[x_ID].status & LINKFAIL_TX)
-      {
-        printk("LKF");
-      }
-      if( Exchanges->fcExchange[x_ID].status & FRAME_TO)
-      {
-        printk("FRMTO");
-      }
-      if( Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY)
-      {
-        printk("ABSQ");
-      }
-      if( Exchanges->fcExchange[x_ID].status & SFQ_FRAME)
-      {
-        printk("SFQFR");
-      }
-
-      if( Exchanges->fcExchange[ x_ID].type == 0x2000)
-        printk(" WR");
-      else if( Exchanges->fcExchange[ x_ID].type == 0x3000)
-        printk(" RD");
-      else if( Exchanges->fcExchange[ x_ID].type == 0x10)
-        printk(" ABTS");
-      else
-        printk(" %Xh", Exchanges->fcExchange[ x_ID].type); 
-
-      if( !(Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT))
-      {
-	printk(" Cmd %p, ", 
-          Exchanges->fcExchange[ x_ID].Cmnd);
-
-        printk(" brd/chn/trg/lun %d/%d/%d/%d port_id %06X\n", 
-          cpqfcHBAdata->HBAnum,
-          Exchanges->fcExchange[ x_ID].Cmnd->channel,
-          Exchanges->fcExchange[ x_ID].Cmnd->target,
-          Exchanges->fcExchange[ x_ID].Cmnd->lun,
-          Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
-      }
-      else  // assume that Cmnd ptr is invalid on _abort()
-      {
-	printk(" Cmd ptr invalid\n");
-      }
-     
-#endif      
-
-      
-      // Steps to ABORT a SEST exchange:
-      // 1. Freeze TL SCSI assists & ERQ (everything)
-      // 2. Receive FROZEN inbound CM (must succeed!)
-      // 3. Invalidate x_ID SEST entry 
-      // 4. Resume TL SCSI assists & ERQ (everything)
-      // 5. Build/start on exchange - change "type" to BLS_ABTS,
-      //    timeout to X sec (RA_TOV from PLDA is actually 0)
-      // 6. Set Exchange Q'd status if ABTS cannot be started,
-      //    or simply complete Exchange in "Terminate" condition
-
-  PCI_TRACEO( x_ID, 0xB4)
-      
-      // 1 & 2 . Freeze Tach & get confirmation of freeze
-      FrozeTach = FreezeTach( cpqfcHBAdata);
-
-      // 3. OK, Tachyon is frozen, so we can invalidate SEST exchange.
-      // FC2_TIMEOUT means we are originating the abort, while
-      // TARGET_ABORT means we are ACCepting an abort.
-      // LINKFAIL_TX, ABORTSEQ_NOFITY, INV_ENTRY or FRAME_TO are 
-      // all from Tachyon:
-      // Exchange was corrupted by LDn or other FC physical failure
-      // INITIATOR_ABORT means the upper layer driver/application
-      // requested the abort.
-
-
-	  
-      // clear bit 31 (VALid), to invalidate & take control from TL
-      fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
-
-
-      // examine and Tach's "Linked List" for IWEs that 
-      // received (nearly) simultaneous transfer ready (XRDY) 
-      // repair linked list if necessary (TBD!)
-      // (If we ignore the "Linked List", we will time out
-      // WRITE commands where we received the FCP-SCSI XFRDY
-      // frame (because Tachyon didn't processes it).  Linked List
-      // management should be done as an optimization.
-
-//       readl( fcChip->Registers.ReMapMemBase+TL_MEM_SEST_LINKED_LIST ));
-
-
-      
-
-      // 4. Resume all Tachlite functions (for other open Exchanges)
-      // as quickly as possible to allow other exchanges to other ports
-      // to resume.  Freezing Tachyon may cause cascading errors, because
-      // any received SEST frame cannot be processed by the SEST.
-      // Don't "unfreeze" unless Link is operational
-      if( FrozeTach )  // did we just freeze it (above)?
-        fcChip->UnFreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
-      
-
-  PCI_TRACEO( x_ID, 0xB4)
-
-      // Note there is no confirmation that the chip is "unfrozen".  Also,
-      // if the Link is down when unfreeze is called, it has no effect.
-      // Chip will unfreeze when the Link is back up.
-
-      // 5. Now send out Abort commands if possible
-      // Some Aborts can't be "sent" (Port_id changed or gone);
-      // if the device is gone, there is no port_id to send the ABTS to.
-
-      if( !(Exchanges->fcExchange[ x_ID].status & PORTID_CHANGED)
-			  &&
-          !(Exchanges->fcExchange[ x_ID].status & DEVICE_REMOVED) )
-      {
-        Exchanges->fcExchange[ x_ID].type = BLS_ABTS;
-        fchs.s_id = Exchanges->fcExchange[ x_ID].fchs.d_id;
-        ulStatus = cpqfcTSBuildExchange(
-          cpqfcHBAdata,
-          BLS_ABTS,
-          &fchs,        // (uses only s_id)
-          NULL,         // (no scatter/gather list for ABTS)
-          &x_ID );// ABTS on this Exchange ID
-
-        if( !ulStatus ) // Exchange setup build OK?
-        {
-
-            // ABTS may be needed because an Exchange was corrupted
-            // by a Link disruption.  If the Link is UP, we can
-	    // presume that this ABTS can start immediately; otherwise,
-	    // set Que'd status so the Login functions
-            // can restart it when the FC physical Link is restored
-          if( ((fcChip->Registers.FMstatus.value &0xF0) &0x80)) // loop init?
-          {			    
-//                printk(" *set Q status x_ID %Xh on LDn* ", x_ID);
-                Exchanges->fcExchange[ x_ID].status |= EXCHANGE_QUEUED;
-          }
-
-          else  // what FC device (port_id) does the Cmd belong to?
-          {
-            PFC_LOGGEDIN_PORT pLoggedInPort = 
-              Exchanges->fcExchange[ x_ID].pLoggedInPort;
-            
-            // if Port is logged in, we might start the abort.
-	
-            if( (pLoggedInPort != NULL) 
-			      &&
-                (pLoggedInPort->prli == TRUE) ) 
-            {
-              // it's possible that an Exchange has already been Queued
-              // to start after Login completes.  Check and don't
-	      // start it (again) here if Q'd status set
-//	    printk(" ABTS xchg %Xh ", x_ID);            
- 	      if( Exchanges->fcExchange[x_ID].status & EXCHANGE_QUEUED)
-	      {
-//		    printk("already Q'd ");
-	      }
-	      else
-	      {
-//	            printk("starting ");
-		
-                fcChip->fcStats.FC2aborted++; 
-                ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
-                if( !ulStatus )
-                {
-                    // OK
-                    // submitted to Tach's Outbound Que (ERQ PI incremented)
-                }
-                else
-                {
-/*                   printk("ABTS exchange start failed -status %Xh, x_ID %Xh ",
-                        ulStatus, x_ID);
-*/
-                } 
-	      }
-	    }
-	    else
-	    {
-/*         	  printk(" ABTS NOT starting xchg %Xh, %p ",
-			       x_ID, pLoggedInPort);
-	          if( pLoggedInPort )
-	            printk("prli %d ", pLoggedInPort->prli);
-*/
-	    }		
- 	  }
-        }
-        else  // what the #@!
-        {  // how do we fail to build an Exchange for ABTS??
-              printk("ABTS exchange build failed -status %Xh, x_ID %Xh\n",
-                ulStatus, x_ID);
-        }
-      }
-      else   // abort without ABTS -- just complete exchange/Cmnd to Linux
-      {
-//            printk(" *Terminating x_ID %Xh on %Xh* ", 
-//		    x_ID, Exchanges->fcExchange[x_ID].status);
-        cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, x_ID);
-
-      }
-    } // end of ABTS case
-      break;
-
-
-
-    case BLS_ABTS_ACC:   // need to ACCept one ABTS
-                         // (NOTE! this code not updated for Linux yet..)
-      
-
-      printk(" *ABTS_ACC* ");
-      // 1. Freeze TL
-
-      fcChip->FreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
+			printk("INV SEST[%X] ", x_ID);
+			if (Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT) {
+				printk("FC2TO");
+			}
+			if (Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT) {
+				printk("IA");
+			}
+			if (Exchanges->fcExchange[x_ID].status & PORTID_CHANGED) {
+				printk("PORTID");
+			}
+			if (Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) {
+				printk("DEVRM");
+			}
+			if (Exchanges->fcExchange[x_ID].status & LINKFAIL_TX) {
+				printk("LKF");
+			}
+			if (Exchanges->fcExchange[x_ID].status & FRAME_TO) {
+				printk("FRMTO");
+			}
+			if (Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY) {
+				printk("ABSQ");
+			}
+			if (Exchanges->fcExchange[x_ID].status & SFQ_FRAME) {
+				printk("SFQFR");
+			}
 
-      memcpy(  // copy the incoming ABTS frame
-        &fchs,
-        fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
-        sizeof( fchs));
-
-      // 3. OK, Tachyon is frozen so we can invalidate SEST entry 
-      // (if necessary)
-      // Status FC2_TIMEOUT means we are originating the abort, while
-      // TARGET_ABORT means we are ACCepting an abort
-      
-      ExchangeID = fchs.ox_rx_id & 0x7FFF; // RX_ID for exchange
-//      printk("ABTS ACC for Target ExchangeID %Xh\n", ExchangeID);
+			if (Exchanges->fcExchange[x_ID].type == 0x2000)
+				printk(" WR");
+			else if (Exchanges->fcExchange[x_ID].type == 0x3000)
+				printk(" RD");
+			else if (Exchanges->fcExchange[x_ID].type == 0x10)
+				printk(" ABTS");
+			else
+				printk(" %Xh", Exchanges->fcExchange[x_ID].type);
+
+			if (!(Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)) {
+				printk(" Cmd %p, ", Exchanges->fcExchange[x_ID].Cmnd);
+
+				printk(" brd/chn/trg/lun %d/%d/%d/%d port_id %06X\n",
+				       dev->HBAnum, Exchanges->fcExchange[x_ID].Cmnd->channel, Exchanges->fcExchange[x_ID].Cmnd->target, Exchanges->fcExchange[x_ID].Cmnd->lun, Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF);
+			} else	// assume that Cmnd ptr is invalid on _abort()
+			{
+				printk(" Cmd ptr invalid\n");
+			}
+#endif
+			// Steps to ABORT a SEST exchange:
+			// 1. Freeze TL SCSI assists & ERQ (everything)
+			// 2. Receive FROZEN inbound CM (must succeed!)
+			// 3. Invalidate x_ID SEST entry 
+			// 4. Resume TL SCSI assists & ERQ (everything)
+			// 5. Build/start on exchange - change "type" to BLS_ABTS,
+			//    timeout to X sec (RA_TOV from PLDA is actually 0)
+			// 6. Set Exchange Q'd status if ABTS cannot be started,
+			//    or simply complete Exchange in "Terminate" condition
+
+			PCI_TRACEO(x_ID, 0xB4)
+			    // 1 & 2 . Freeze Tach & get confirmation of freeze
+			    FrozeTach = FreezeTach(dev);
+
+			// 3. OK, Tachyon is frozen, so we can invalidate SEST exchange.
+			// FC2_TIMEOUT means we are originating the abort, while
+			// TARGET_ABORT means we are ACCepting an abort.
+			// LINKFAIL_TX, ABORTSEQ_NOFITY, INV_ENTRY or FRAME_TO are 
+			// all from Tachyon:
+			// Exchange was corrupted by LDn or other FC physical failure
+			// INITIATOR_ABORT means the upper layer driver/application
+			// requested the abort.
+
+			// clear bit 31 (VALid), to invalidate & take control from TL
+			fcChip->SEST->u[x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
+
+			// examine and Tach's "Linked List" for IWEs that 
+			// received (nearly) simultaneous transfer ready (XRDY) 
+			// repair linked list if necessary (TBD!)
+			// (If we ignore the "Linked List", we will time out
+			// WRITE commands where we received the FCP-SCSI XFRDY
+			// frame (because Tachyon didn't processes it).  Linked List
+			// management should be done as an optimization.
+
+//			readl( fcChip->Registers.ReMapMemBase+TL_MEM_SEST_LINKED_LIST ));
+
+			// 4. Resume all Tachlite functions (for other open Exchanges)
+			// as quickly as possible to allow other exchanges to other ports
+			// to resume.  Freezing Tachyon may cause cascading errors, because
+			// any received SEST frame cannot be processed by the SEST.
+			// Don't "unfreeze" unless Link is operational
+			if (FrozeTach)	// did we just freeze it (above)?
+				fcChip->UnFreezeTachyon(fcChip, 2);	// both ERQ and FCP assists
+
+			PCI_TRACEO(x_ID, 0xB4)
+			    // Note there is no confirmation that the chip is "unfrozen".  Also,
+			    // if the Link is down when unfreeze is called, it has no effect.
+			    // Chip will unfreeze when the Link is back up.
+			    // 5. Now send out Abort commands if possible
+			    // Some Aborts can't be "sent" (Port_id changed or gone);
+			    // if the device is gone, there is no port_id to send the ABTS to.
+			if (!(Exchanges->fcExchange[x_ID].status & PORTID_CHANGED)
+				&& !(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)) {
+				Exchanges->fcExchange[x_ID].type = BLS_ABTS;
+				fchs.s_id = Exchanges->fcExchange[x_ID].fchs.d_id;
+				ulStatus = cpqfcTSBuildExchange(dev, BLS_ABTS, &fchs,	// (uses only s_id)
+								NULL,	// (no scatter/gather list for ABTS)
+								&x_ID);	// ABTS on this Exchange ID
+
+				if (!ulStatus)	// Exchange setup build OK?
+				{
+
+					// ABTS may be needed because an Exchange was corrupted
+					// by a Link disruption.  If the Link is UP, we can
+					// presume that this ABTS can start immediately; otherwise,
+					// set Que'd status so the Login functions
+					// can restart it when the FC physical Link is restored
+					if (((fcChip->Registers.FMstatus.value & 0xF0) & 0x80))	// loop init?
+					{
+//						printk(" *set Q status x_ID %Xh on LDn* ", x_ID);
+						Exchanges->fcExchange[x_ID].status |= EXCHANGE_QUEUED;
+					}
+
+					else	// what FC device (port_id) does the Cmd belong to?
+					{
+						PFC_LOGGEDIN_PORT pLoggedInPort = Exchanges->fcExchange[x_ID].pLoggedInPort;
+
+						// if Port is logged in, we might start the abort.
+
+						if ((pLoggedInPort != NULL)
+						    && (pLoggedInPort->prli == 1)) {
+							// it's possible that an Exchange has already been Queued
+							// to start after Login completes.  Check and don't
+							// start it (again) here if Q'd status set
+//							printk(" ABTS xchg %Xh ", x_ID);            
+							if (Exchanges->fcExchange[x_ID].status & EXCHANGE_QUEUED) {
+//								printk("already Q'd ");
+							} else {
+//								printk("starting ");
+								fcChip->fcStats.FC2aborted++;
+								ulStatus = cpqfcTSStartExchange(dev, x_ID);
+								if (!ulStatus) {
+									// OK
+									// submitted to Tach's Outbound Que (ERQ PI incremented)
+								} else {
+//									printk("ABTS exchange start failed -status %Xh, x_ID %Xh ", ulStatus, x_ID);
+								}
+							}
+						}
+					}
+				} else	// what the #@!
+				{	// how do we fail to build an Exchange for ABTS??
+					printk("ABTS exchange build failed -status %Xh, x_ID %Xh\n", ulStatus, x_ID);
+				}
+			} else	// abort without ABTS -- just complete exchange/Cmnd to Linux
+			{
+//				printk(" *Terminating x_ID %Xh on %Xh* ", 
+//					x_ID, Exchanges->fcExchange[x_ID].status);
+				cpqfcTSCompleteExchange(dev->PciDev, fcChip, x_ID);
 
+			}
+		}		// end of ABTS case
+		break;
 
-      // sanity check on received ExchangeID
-      if( Exchanges->fcExchange[ ExchangeID].status == TARGET_ABORT )
-      {
-          // clear bit 31 (VALid), to invalidate & take control from TL
-//          printk("Invalidating SEST exchange %Xh\n", ExchangeID);
-          fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len &= 0x7FFFFFFF;
-      }
-
-
-      // 4. Resume all Tachlite functions (for other open Exchanges)
-      // as quickly as possible to allow other exchanges to other ports
-      // to resume.  Freezing Tachyon for too long may royally screw
-      // up everything!
-      fcChip->UnFreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
-      
-      // Note there is no confirmation that the chip is "unfrozen".  Also,
-      // if the Link is down when unfreeze is called, it has no effect.
-      // Chip will unfreeze when the Link is back up.
+	case BLS_ABTS_ACC:	// need to ACCept one ABTS
+		// (NOTE! this code not updated for Linux yet..)
+		printk(" *ABTS_ACC* ");
+		// 1. Freeze TL
+
+		fcChip->FreezeTachyon(fcChip, 2);	// both ERQ and FCP assists
+		memcpy(		// copy the incoming ABTS frame
+			      &fchs, fcLQ->Qitem[QconsumerNdx].ulBuff,	// incoming fchs
+			      sizeof(fchs));
+
+		// 3. OK, Tachyon is frozen so we can invalidate SEST entry 
+		// (if necessary)
+		// Status FC2_TIMEOUT means we are originating the abort, while
+		// TARGET_ABORT means we are ACCepting an abort
+
+		ExchangeID = fchs.ox_rx_id & 0x7FFF;	// RX_ID for exchange
+//		printk("ABTS ACC for Target ExchangeID %Xh\n", ExchangeID);
+
+		// sanity check on received ExchangeID
+		if (Exchanges->fcExchange[ExchangeID].status == TARGET_ABORT) {
+			// clear bit 31 (VALid), to invalidate & take control from TL
+//			printk("Invalidating SEST exchange %Xh\n", ExchangeID);
+			fcChip->SEST->u[ExchangeID].IWE.Hdr_Len &= 0x7FFFFFFF;
+		}
 
-      // 5. Now send out Abort ACC reply for this exchange
-      Exchanges->fcExchange[ ExchangeID].type = BLS_ABTS_ACC;
-      
-      fchs.s_id = Exchanges->fcExchange[ ExchangeID].fchs.d_id;
-      ulStatus = cpqfcTSBuildExchange(
-            cpqfcHBAdata,
-            BLS_ABTS_ACC,
-            &fchs,
-            NULL,         // no data (no scatter/gather list)
-            &ExchangeID );// fcController->fcExchanges index, -1 if failed
-
-      if( !ulStatus ) // Exchange setup?
-      {
-        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-        if( !ulStatus )
-        {
-          // submitted to Tach's Outbound Que (ERQ PI incremented)
-          // waited for completion for ELS type (Login frames issued
-          // synchronously)
-        }
-        else
-          // check reason for Exchange not being started - we might
-          // want to Queue and start later, or fail with error
-        {
-
-        } 
-      }
-      break;
-
-
-    case BLS_ABTS_RJT:   // need to ReJecT one ABTS; reject implies the
-                         // exchange doesn't exist in the TARGET context.
-                         // ExchangeID has to come from LinkService space.
-
-      printk(" *ABTS_RJT* ");
-      ulStatus = cpqfcTSBuildExchange(
-            cpqfcHBAdata,
-            BLS_ABTS_RJT,
-            (TachFCHDR_GCMND*)
-              fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
-            NULL,         // no data (no scatter/gather list)
-            &ExchangeID );// fcController->fcExchanges index, -1 if failed
-
-      if( !ulStatus ) // Exchange setup OK?
-      {
-        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-        // If it fails, we aren't required to retry.
-      }
-      if( ulStatus )
-      {
-        printk("Failed to send BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
-      }
-      else
-      {
-        printk("Sent BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
-      
-      }
+		// 4. Resume all Tachlite functions (for other open Exchanges)
+		// as quickly as possible to allow other exchanges to other ports
+		// to resume.  Freezing Tachyon for too long may royally screw
+		// up everything!
+		fcChip->UnFreezeTachyon(fcChip, 2);	// both ERQ and FCP assists
+
+		// Note there is no confirmation that the chip is "unfrozen".  Also,
+		// if the Link is down when unfreeze is called, it has no effect.
+		// Chip will unfreeze when the Link is back up.
+
+		// 5. Now send out Abort ACC reply for this exchange
+		Exchanges->fcExchange[ExchangeID].type = BLS_ABTS_ACC;
+
+		fchs.s_id = Exchanges->fcExchange[ExchangeID].fchs.d_id;
+		ulStatus = cpqfcTSBuildExchange(dev, BLS_ABTS_ACC, &fchs, NULL,	// no data (no scatter/gather list)
+						&ExchangeID);	// fcController->fcExchanges index, -1 if failed
+
+		if (!ulStatus)	// Exchange setup?
+		{
+			ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+			if (!ulStatus) {
+				// submitted to Tach's Outbound Que (ERQ PI incremented)
+				// waited for completion for ELS type (Login frames issued
+				// synchronously)
+			} else
+				// check reason for Exchange not being started - we might
+				// want to Queue and start later, or fail with error
+			{
 
-      break;
+			}
+		}
+		break;
 
+	case BLS_ABTS_RJT:	// need to ReJecT one ABTS; reject implies the
+		// exchange doesn't exist in the TARGET context.
+		// ExchangeID has to come from LinkService space.
+
+		printk(" *ABTS_RJT* ");
+		ulStatus = cpqfcTSBuildExchange(dev, BLS_ABTS_RJT, (TachFCHDR_GCMND *)
+						fcLQ->Qitem[QconsumerNdx].ulBuff,	// incoming fchs
+						NULL,	// no data (no scatter/gather list)
+						&ExchangeID);	// fcController->fcExchanges index, -1 if failed
+
+		if (!ulStatus)	// Exchange setup OK?
+		{
+			ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+			// If it fails, we aren't required to retry.
+		}
+		if (ulStatus) {
+			printk("Failed to send BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
+		} else {
+			printk("Sent BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
 
+		}
+		break;
 
-    default:
-      break;
-  }                   // end switch
-//doNothing:
-    // done with this item - now set the NEXT index
+	default:
+		break;
+	}			// end switch
+	// done with this item - now set the NEXT index
 
-  if( QconsumerNdx+1 >= FC_LINKQ_DEPTH ) // rollover test
-  {
-    fcLQ->consumer = 0;
-  }
-  else
-  { 
-    fcLQ->consumer++;
-  }
+	if (QconsumerNdx + 1 >= FC_LINKQ_DEPTH)	// rollover test
+		fcLQ->consumer = 0;
+	else
+		fcLQ->consumer++;
 
-  PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x94)
+	PCI_TRACEO(fcLQ->Qitem[QconsumerNdx].Type, 0x94)
 
-  LEAVE("WorkTask");
-  return;
+	LEAVE("WorkTask");
+	return;
 }
 
 
@@ -845,115 +700,89 @@
 // This circular Q works like Tachyon's que - the producer points to the next
 // (unused) entry.  Called by Interrupt handler, WorkerThread, Timer
 // sputlinkq
-void cpqfcTSPutLinkQue( CPQFCHBA *cpqfcHBAdata,
-  int Type, 
-  void *QueContent)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-//  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
-  ULONG ndx;
-  
-  ENTER("cpqfcTSPutLinkQ");
-
-  ndx = fcLQ->producer;
-  
-  ndx += 1;  // test for Que full
-
-
-  
-  if( ndx >= FC_LINKQ_DEPTH ) // rollover test
-    ndx = 0;
+void cpqfcTSPutLinkQue(CPQFCHBA * dev, int Type, void *QueContent)
+{
+	PTACHYON fcChip = &dev->fcChip;
+//	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	PFC_LINK_QUE fcLQ = dev->fcLQ;
+	u32 ndx;
 
-  if( ndx == fcLQ->consumer )   // QUE full test
-  {
-                       // QUE was full! lost LK command (fatal to logic)
-    fcChip->fcStats.lnkQueFull++;
+	ENTER("cpqfcTSPutLinkQ");
 
-    printk("*LinkQ Full!*");
-    TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
-/*
-    {
-      int i;
-      printk("LinkQ PI %d, CI %d\n", fcLQ->producer,
-        fcLQ->consumer);
-		      
-      for( i=0; i< FC_LINKQ_DEPTH; )
-      {
-	printk(" [%d]%Xh ", i, fcLQ->Qitem[i].Type);
-	if( (++i %8) == 0) printk("\n");
-      }
-  
-    }
-*/    
-    printk( "cpqfcTS: WARNING!! PutLinkQue - FULL!\n"); // we're hung
-  }
-  else                        // QUE next element
-  {
-    // Prevent certain multiple (back-to-back) requests.
-    // This is important in that we don't want to issue multiple
-    // ABTS for the same Exchange, or do multiple FM inits, etc.
-    // We can never be sure of the timing of events reported to
-    // us by Tach's IMQ, which can depend on system/bus speeds,
-    // FC physical link circumstances, etc.
-     
-    if( (fcLQ->producer != fcLQ->consumer)
-	    && 
-        (Type == FMINIT)  )
-    {
-      LONG lastNdx;  // compute previous producer index
-      if( fcLQ->producer)
-        lastNdx = fcLQ->producer- 1;
-      else
-	lastNdx = FC_LINKQ_DEPTH-1;
+	ndx = fcLQ->producer;
 
+	ndx += 1;		// test for Que full
 
-      if( fcLQ->Qitem[lastNdx].Type == FMINIT)
-      {
-//        printk(" *skip FMINIT Q post* ");
-//        goto DoneWithPutQ;
-      }
 
-    }
 
-    // OK, add the Q'd item...
-    
-    fcLQ->Qitem[fcLQ->producer].Type = Type;
-   
-    memcpy(
-        fcLQ->Qitem[fcLQ->producer].ulBuff,
-        QueContent, 
-        sizeof(fcLQ->Qitem[fcLQ->producer].ulBuff));
+	if (ndx >= FC_LINKQ_DEPTH)	// rollover test
+		ndx = 0;
 
-    fcLQ->producer = ndx;  // increment Que producer
+	if (ndx == fcLQ->consumer)	// QUE full test
+	{
+		// QUE was full! lost LK command (fatal to logic)
+		fcChip->fcStats.lnkQueFull++;
 
-    // set semaphore to wake up Kernel (worker) thread
-    // 
-    up( cpqfcHBAdata->fcQueReady );
-  }
+		printk("*LinkQ Full!*");
+		TriggerHBA(fcChip->Registers.ReMapMemBase, 1);
+/*
+		{
+			int i;
+			printk("LinkQ PI %d, CI %d\n", fcLQ->producer, fcLQ->consumer);
+		      
+			for( i=0; i< FC_LINKQ_DEPTH; )
+			{
+				printk(" [%d]%Xh ", i, fcLQ->Qitem[i].Type);
+				if( (++i %8) == 0)
+					printk("\n");
+			}
+		}
+*/
+		printk("cpqfcTS: WARNING!! PutLinkQue - FULL!\n");	// we're hung
+	}
+	else			// QUE next element
+	{
+		// Prevent certain multiple (back-to-back) requests.
+		// This is important in that we don't want to issue multiple
+		// ABTS for the same Exchange, or do multiple FM inits, etc.
+		// We can never be sure of the timing of events reported to
+		// us by Tach's IMQ, which can depend on system/bus speeds,
+		// FC physical link circumstances, etc.
+
+		if ((fcLQ->producer != fcLQ->consumer)
+		    && (Type == FMINIT)) {
+			s32 lastNdx;	// compute previous producer index
+			if (fcLQ->producer)
+				lastNdx = fcLQ->producer - 1;
+			else
+				lastNdx = FC_LINKQ_DEPTH - 1;
+
+
+			if (fcLQ->Qitem[lastNdx].Type == FMINIT) {
+//      			printk(" *skip FMINIT Q post* ");
+//        			goto DoneWithPutQ;
+			}
 
+		}
+		// OK, add the Q'd item...
+		fcLQ->Qitem[fcLQ->producer].Type = Type;
+		memcpy(fcLQ->Qitem[fcLQ->producer].ulBuff, QueContent, sizeof(fcLQ->Qitem[fcLQ->producer].ulBuff));
+		fcLQ->producer = ndx;	// increment Que producer
+		// set semaphore to wake up Kernel (worker) thread
+		up(dev->fcQueReady);
+	}
 //DoneWithPutQ:
-
-  LEAVE("cpqfcTSPutLinkQ");
+	LEAVE("cpqfcTSPutLinkQ");
 }
 
-
-
-
 // reset device ext FC link Q
-void cpqfcTSLinkQReset( CPQFCHBA *cpqfcHBAdata)
-   
+void cpqfcTSLinkQReset(CPQFCHBA * dev)
 {
-  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
-  fcLQ->producer = 0;
-  fcLQ->consumer = 0;
-
+	PFC_LINK_QUE fcLQ = dev->fcLQ;
+	fcLQ->producer = 0;
+	fcLQ->consumer = 0;
 }
 
-
-
-
-
 // When Tachyon gets an unassisted FCP-SCSI frame, post here so
 // an arbitrary context thread (e.g. IOCTL loopback test function)
 // can process it.
@@ -961,17 +790,15 @@
 // (NOTE: Not revised for Linux)
 // This Q works like Tachyon's que - the producer points to the next
 // (unused) entry.
-void cpqfcTSPutScsiQue( CPQFCHBA *cpqfcHBAdata,
-  int Type, 
-  void *QueContent)
+void cpqfcTSPutScsiQue(CPQFCHBA * dev, int Type, void *QueContent)
 {
-//  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-//  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+//  CPQFCHBA *dev = (CPQFCHBA *)shpnt->hostdata;
+//  PTACHYON fcChip = &dev->fcChip;
 
-//  ULONG ndx;
+//  u32 ndx;
 
-//  ULONG *pExchangeID;
-//  LONG ExchangeID;
+//  u32 *pExchangeID;
+//  s32 ExchangeID;
 
 /*
   KeAcquireSpinLockAtDpcLevel( &pDevExt->fcScsiQueLock);
@@ -999,7 +826,7 @@
       // copied an FCP response frame into a buffer pointed to by the SEST
       // entry.  That buffer is allocated in the SEST structure at ->RspHDR.
       // Copy the RspHDR for use by the Que handler.
-      pExchangeID = (ULONG *)QueContent;
+      pExchangeID = (u32 *)QueContent;
       
       memcpy(
 	      pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
@@ -1020,175 +847,127 @@
 
     KeSetEvent( &pDevExt->TYIBscsi,  // signal any waiting thread
        0,                    // no priority boost
-		   FALSE );              // no waiting later for this event
+		   0 );              // no waiting later for this event
   }
   KeReleaseSpinLockFromDpcLevel( &pDevExt->fcScsiQueLock);
 */
 }
 
+static void ProcessELS_Request(CPQFCHBA *, TachFCHDR_GCMND *);
+static void ProcessELS_Reply(CPQFCHBA *, TachFCHDR_GCMND *);
+static void ProcessFCS_Reply(CPQFCHBA *, TachFCHDR_GCMND *);
 
-
-
-
-
-
-static void ProcessELS_Request( CPQFCHBA*,TachFCHDR_GCMND*);
-
-static void ProcessELS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
-
-static void ProcessFCS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
-
-void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,
-		PFC_LOGGEDIN_PORT pFcPort)
+void cpqfcTSImplicitLogout(CPQFCHBA * dev, PFC_LOGGEDIN_PORT pFcPort)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+	PTACHYON fcChip = &dev->fcChip;
 
-  if( pFcPort->port_id != 0xFFFC01 ) // don't care about Fabric
-  {
-    fcChip->fcStats.logouts++;
-    printk("cpqfcTS: Implicit logout of WWN %08X%08X, port_id %06X\n", 
-        (ULONG)pFcPort->u.liWWN,
-        (ULONG)(pFcPort->u.liWWN >>32),
-	pFcPort->port_id);
-
-  // Terminate I/O with this (Linux) Scsi target
-    cpqfcTSTerminateExchange( cpqfcHBAdata, 
-                            &pFcPort->ScsiNexus,
-	                    DEVICE_REMOVED);
-  }
-			
-  // Do an "implicit logout" - we can't really Logout the device
-  // (i.e. with LOGOut Request) because of port_id confusion
-  // (i.e. the Other port has no port_id).
-  // A new login for that WWN will have to re-write port_id (0 invalid)
-  pFcPort->port_id = 0;  // invalid!
-  pFcPort->pdisc = FALSE;
-  pFcPort->prli = FALSE;
-  pFcPort->plogi = FALSE;
-  pFcPort->flogi = FALSE;
-  pFcPort->LOGO_timer = 0;
-  pFcPort->device_blocked = TRUE; // block Scsi Requests
-  pFcPort->ScsiNexus.VolumeSetAddressing=0;	
+	if (pFcPort->port_id != 0xFFFC01)	// don't care about Fabric
+	{
+		fcChip->fcStats.logouts++;
+		printk("cpqfcTS: Implicit logout of WWN %08X%08X, port_id %06X\n", (u32) pFcPort->u.liWWN, (u32) (pFcPort->u.liWWN >> 32), pFcPort->port_id);
+
+		// Terminate I/O with this (Linux) Scsi target
+		cpqfcTSTerminateExchange(dev, &pFcPort->ScsiNexus, DEVICE_REMOVED);
+	}
+	// Do an "implicit logout" - we can't really Logout the device
+	// (i.e. with LOGOut Request) because of port_id confusion
+	// (i.e. the Other port has no port_id).
+	// A new login for that WWN will have to re-write port_id (0 invalid)
+	pFcPort->port_id = 0;	// invalid!
+	pFcPort->pdisc = 0;
+	pFcPort->prli = 0;
+	pFcPort->plogi = 0;
+	pFcPort->flogi = 0;
+	pFcPort->LOGO_timer = 0;
+	pFcPort->device_blocked = 1;	// block Scsi Requests
+	pFcPort->ScsiNexus.VolumeSetAddressing = 0;
 }
 
-  
+
 // On FC-AL, there is a chance that a previously known device can
 // be quietly removed (e.g. with non-managed hub), 
 // while a NEW device (with different WWN) took the same alpa or
 // even 24-bit port_id.  This chance is unlikely but we must always
 // check for it.
-static void TestDuplicatePortId( CPQFCHBA* cpqfcHBAdata,
-		PFC_LOGGEDIN_PORT pLoggedInPort)
+
+static void TestDuplicatePortId(CPQFCHBA * dev, PFC_LOGGEDIN_PORT pLoggedInPort)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  // set "other port" at beginning of fcPorts list
-  PFC_LOGGEDIN_PORT pOtherPortWithPortId = fcChip->fcPorts.pNextPort;
-  while( pOtherPortWithPortId ) 
-  {
-    if( (pOtherPortWithPortId->port_id == 
-         pLoggedInPort->port_id) 
-		    &&
-         (pOtherPortWithPortId != pLoggedInPort) )
-    {
-      // trouble!  (Implicitly) Log the other guy out
-      printk(" *port_id %Xh is duplicated!* ", 
-        pOtherPortWithPortId->port_id);
-      cpqfcTSImplicitLogout( cpqfcHBAdata, pOtherPortWithPortId); 
-   }
-    pOtherPortWithPortId = pOtherPortWithPortId->pNextPort;
-  }
+	PTACHYON fcChip = &dev->fcChip;
+	// set "other port" at beginning of fcPorts list
+	PFC_LOGGEDIN_PORT pOtherPortWithPortId = fcChip->fcPorts.pNextPort;
+	while (pOtherPortWithPortId) {
+		if ((pOtherPortWithPortId->port_id == pLoggedInPort->port_id)
+		    && (pOtherPortWithPortId != pLoggedInPort)) {
+			// trouble!  (Implicitly) Log the other guy out
+			printk(" *port_id %Xh is duplicated!* ", pOtherPortWithPortId->port_id);
+			cpqfcTSImplicitLogout(dev, pOtherPortWithPortId);
+		}
+		pOtherPortWithPortId = pOtherPortWithPortId->pNextPort;
+	}
 }
 
-
-
-
-
-
 // Dynamic Memory Allocation for newly discovered FC Ports.
 // For simplicity, maintain fcPorts structs for ALL
 // for discovered devices, including those we never do I/O with
 // (e.g. Fabric addresses)
 
-static PFC_LOGGEDIN_PORT CreateFcPort( 
-	  CPQFCHBA* cpqfcHBAdata, 
-	  PFC_LOGGEDIN_PORT pLastLoggedInPort, 
-	  TachFCHDR_GCMND* fchs,
-	  LOGIN_PAYLOAD* plogi)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  PFC_LOGGEDIN_PORT pNextLoggedInPort = NULL;
-  int i;
-
-
-  printk("cpqfcTS: New FC port %06Xh WWN: ", fchs->s_id);
-  for( i=3; i>=0; i--)   // copy the LOGIN port's WWN
-    printk("%02X", plogi->port_name[i]);
-  for( i=7; i>3; i--)   // copy the LOGIN port's WWN
-    printk("%02X", plogi->port_name[i]);
-
-
-  // allocate mem for new port
-  // (these are small and rare allocations...)
-  pNextLoggedInPort = kmalloc( sizeof( FC_LOGGEDIN_PORT), GFP_ATOMIC );
-
-    
-  // allocation succeeded?  Fill out NEW PORT
-  if( pNextLoggedInPort )
-  {    
-                              // clear out any garbage (sometimes exists)
-    memset( pNextLoggedInPort, 0, sizeof( FC_LOGGEDIN_PORT));
-
-
-    // If we login to a Fabric, we don't want to treat it
-    // as a SCSI device...
-    if( (fchs->s_id & 0xFFF000) != 0xFFF000)
-    {
-      int i;
-      
-      // create a unique "virtual" SCSI Nexus (for now, just a
-      // new target ID) -- we will update channel/target on REPORT_LUNS
-      // special case for very first SCSI target...
-      if( cpqfcHBAdata->HostAdapter->max_id == 0)
-      {
-        pNextLoggedInPort->ScsiNexus.target = 0;
-        fcChip->fcPorts.ScsiNexus.target = -1; // don't use "stub"
-      }
-      else
-      {
-        pNextLoggedInPort->ScsiNexus.target =
-          cpqfcHBAdata->HostAdapter->max_id;
-      }
-
-      // initialize the lun[] Nexus struct for lun masking      
-      for( i=0; i< CPQFCTS_MAX_LUN; i++)
-        pNextLoggedInPort->ScsiNexus.lun[i] = 0xFF; // init to NOT USED
-      
-      pNextLoggedInPort->ScsiNexus.channel = 0; // cpqfcTS has 1 FC port
-      
-      printk(" SCSI Chan/Trgt %d/%d", 
-          pNextLoggedInPort->ScsiNexus.channel,
-          pNextLoggedInPort->ScsiNexus.target);
- 
-      // tell Scsi layers about the new target...
-      cpqfcHBAdata->HostAdapter->max_id++; 
-//    printk("HostAdapter->max_id = %d\n",
-//      cpqfcHBAdata->HostAdapter->max_id);		    
-    }                          
-    else
-    {
-      // device is NOT SCSI (in case of Fabric)
-      pNextLoggedInPort->ScsiNexus.target = -1;  // invalid
-    }
+static PFC_LOGGEDIN_PORT CreateFcPort(CPQFCHBA * dev, PFC_LOGGEDIN_PORT pLastLoggedInPort, TachFCHDR_GCMND * fchs, LOGIN_PAYLOAD * plogi)
+{
+	PTACHYON fcChip = &dev->fcChip;
+	PFC_LOGGEDIN_PORT pNextLoggedInPort = NULL;
+	int i;
+
+	printk("cpqfcTS: New FC port %06Xh WWN: ", fchs->s_id);
+	for (i = 3; i >= 0; i--)	// copy the LOGIN port's WWN
+		printk("%02X", plogi->port_name[i]);
+	for (i = 7; i > 3; i--)	// copy the LOGIN port's WWN
+		printk("%02X", plogi->port_name[i]);
+
+	// allocate mem for new port
+	// (these are small and rare allocations...)
+	pNextLoggedInPort = kmalloc(sizeof(FC_LOGGEDIN_PORT), GFP_ATOMIC);
+
+	// allocation succeeded?  Fill out NEW PORT
+	if (pNextLoggedInPort) {
+		// clear out any garbage (sometimes exists)
+		memset(pNextLoggedInPort, 0, sizeof(FC_LOGGEDIN_PORT));
+		// If we login to a Fabric, we don't want to treat it
+		// as a SCSI device...
+		if ((fchs->s_id & 0xFFF000) != 0xFFF000) {
+			int i;
+
+			// create a unique "virtual" SCSI Nexus (for now, just a
+			// new target ID) -- we will update channel/target on REPORT_LUNS
+			// special case for very first SCSI target...
+			if (dev->HostAdapter->max_id == 0) {
+				pNextLoggedInPort->ScsiNexus.target = 0;
+				fcChip->fcPorts.ScsiNexus.target = -1;	// don't use "stub"
+			} else {
+				pNextLoggedInPort->ScsiNexus.target = dev->HostAdapter->max_id;
+			}
 
-	  // create forward link to new port
-    pLastLoggedInPort->pNextPort = pNextLoggedInPort;
-    printk("\n");
-
-  }     
-  return pNextLoggedInPort;  // NULL on allocation failure
-}   // end NEW PORT (WWN) logic
+			// initialize the lun[] Nexus struct for lun masking      
+			for (i = 0; i < CPQFCTS_MAX_LUN; i++)
+				pNextLoggedInPort->ScsiNexus.lun[i] = 0xFF;	// init to NOT USED
+
+			pNextLoggedInPort->ScsiNexus.channel = 0;	// cpqfcTS has 1 FC port
+			printk(" SCSI Chan/Trgt %d/%d", pNextLoggedInPort->ScsiNexus.channel, pNextLoggedInPort->ScsiNexus.target);
+			// tell Scsi layers about the new target...
+			dev->HostAdapter->max_id++;
+//			printk("HostAdapter->max_id = %d\n",
+//				dev->HostAdapter->max_id);                 
+		} else {
+			// device is NOT SCSI (in case of Fabric)
+			pNextLoggedInPort->ScsiNexus.target = -1;	// invalid
+		}
 
+		// create forward link to new port
+		pLastLoggedInPort->pNextPort = pNextLoggedInPort;
+		printk("\n");
 
+	}
+	return pNextLoggedInPort;	// NULL on allocation failure
+}				// end NEW PORT (WWN) logic
 
 // For certain cases, we want to terminate exchanges without
 // sending ABTS to the device.  Examples include when an FC
@@ -1200,870 +979,620 @@
 // Since we must ensure that Tachyon is not operating on the
 // exchange, we have to freeze the chip
 // sterminateex
-void cpqfcTSTerminateExchange( 
-  CPQFCHBA* cpqfcHBAdata, SCSI_NEXUS *ScsiNexus, int TerminateStatus)
+
+void cpqfcTSTerminateExchange(CPQFCHBA * dev, SCSI_NEXUS * ScsiNexus, int TerminateStatus)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG x_ID;
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 x_ID;
+
+	if (ScsiNexus) {
+//		printk("TerminateExchange: ScsiNexus chan/target %d/%d\n",
+//			ScsiNexus->channel, ScsiNexus->target);
+	}
+	for (x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) {
+		if (Exchanges->fcExchange[x_ID].type)	// in use?
+		{
+			if (ScsiNexus == NULL)	// our HBA changed - term. all
+			{
+				Exchanges->fcExchange[x_ID].status = TerminateStatus;
+				cpqfcTSPutLinkQue(dev, BLS_ABTS, &x_ID);
+			} else {
+				// If a device, according to WWN, has been removed, it's
+				// port_id may be used by another working device, so we
+				// have to terminate by SCSI target, NOT port_id.
+				if (Exchanges->fcExchange[x_ID].Cmnd)	// Cmnd in progress?
+				{
+					if ((Exchanges->fcExchange[x_ID].Cmnd->target == ScsiNexus->target)
+					    && (Exchanges->fcExchange[x_ID].Cmnd->channel == ScsiNexus->channel)) {
+						Exchanges->fcExchange[x_ID].status = TerminateStatus;
+						cpqfcTSPutLinkQue(dev, BLS_ABTS, &x_ID);	// timed-out
+					}
+				}
+				// (in case we ever need it...)
+				// all SEST structures have a remote node ID at SEST DWORD 2
+				//          if( (fcChip->SEST->u[ x_ID ].TWE.Remote_Node_ID >> 8)
+				//                ==  port_id)
+			}
+		}
+	}
+}
 
-  if( ScsiNexus )
-  {
-//    printk("TerminateExchange: ScsiNexus chan/target %d/%d\n",
-//		    ScsiNexus->channel, ScsiNexus->target);
+static void ProcessELS_Request(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
+{
+	PTACHYON fcChip = &dev->fcChip;
+//	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+//	u32 ox_id = (fchs->ox_rx_id >>16);
+	PFC_LOGGEDIN_PORT pLoggedInPort = NULL, pLastLoggedInPort;
+	u8 NeedReject = 0;
+	u32 ls_reject_code = 0;	// default don'n know??
 
-  } 
-  
-  for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
-  {
-    if( Exchanges->fcExchange[x_ID].type )  // in use?
-    {
-      if( ScsiNexus == NULL ) // our HBA changed - term. all
-      {
-	Exchanges->fcExchange[x_ID].status = TerminateStatus;
-        cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); 
-      }
-      else
-      {
-	// If a device, according to WWN, has been removed, it's
-	// port_id may be used by another working device, so we
-	// have to terminate by SCSI target, NOT port_id.
-        if( Exchanges->fcExchange[x_ID].Cmnd) // Cmnd in progress?
-	{	                 
-	  if( (Exchanges->fcExchange[x_ID].Cmnd->target == ScsiNexus->target)
-			&&
-            (Exchanges->fcExchange[x_ID].Cmnd->channel == ScsiNexus->channel)) 
-          {
-            Exchanges->fcExchange[x_ID].status = TerminateStatus;
-            cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); // timed-out
-          }
-	}
-
-	// (in case we ever need it...)
-	// all SEST structures have a remote node ID at SEST DWORD 2
-        //          if( (fcChip->SEST->u[ x_ID ].TWE.Remote_Node_ID >> 8)
-        //                ==  port_id)
-      } 
-    }
-  }
-}
 
+	// Check the incoming frame for a supported ELS type
+	switch (fchs->pl[0] & 0xFFFF) 
+	{
+	case 0x0050:	
+		//  PDISC?
+		// Payload for PLOGI and PDISC is identical (request & reply)
+		if (!verify_PLOGI(fcChip, fchs, &ls_reject_code))	// valid payload?
+		{
+			LOGIN_PAYLOAD logi;	// FC-PH Port Login
+
+			// PDISC payload OK. If critical login fields
+			// (e.g. WWN) matches last login for this port_id,
+			// we may resume any prior exchanges
+			// with the other port
+
+			BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
+
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+							   0,	// don't search linked list for port_id
+							   &logi.port_name[0],	// search linked list for WWN
+							   &pLastLoggedInPort);	// must return non-NULL; when a port_id
+			// is not found, this pointer marks the
+			// end of the singly linked list
+
+			if (pLoggedInPort != NULL)	// WWN found (prior login OK)
+			{
+				if ((fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id) {
+					// Yes.  We were expecting PDISC?
+					if (pLoggedInPort->pdisc) {
+						// Yes; set fields accordingly.     (PDISC, not Originator)
+						SetLoginFields(pLoggedInPort, fchs, 1, 0);
+						// send 'ACC' reply 
+						cpqfcTSPutLinkQue(dev, ELS_PLOGI_ACC,	// (PDISC same as PLOGI ACC)
+								  fchs);
+						// OK to resume I/O...
+					} else {
+						printk("Not expecting PDISC (pdisc=0)\n");
+						NeedReject = 1;
+						// set reject reason code 
+						ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+					}
+				} else {
+					if (pLoggedInPort->port_id != 0) {
+						printk("PDISC PortID change: old %Xh, new %Xh\n", pLoggedInPort->port_id, fchs->s_id & 0xFFFFFF);
+					}
+					NeedReject = 1;
+					// set reject reason code 
+					ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+				}
+			} else {
+				printk("PDISC Request from unknown WWN\n");
+				NeedReject = 1;
+				// set reject reason code 
+				ls_reject_code = LS_RJT_REASON(LOGICAL_ERROR, INVALID_PORT_NAME);
+			}
 
-static void ProcessELS_Request( 
-              CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-//  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-//  ULONG ox_id = (fchs->ox_rx_id >>16);
-  PFC_LOGGEDIN_PORT pLoggedInPort=NULL, pLastLoggedInPort;
-  BOOLEAN NeedReject = FALSE;
-  ULONG ls_reject_code = 0; // default don'n know??
+		}
+		else		// Payload unacceptable
+		{
+			printk("payload unacceptable\n");
+			NeedReject = 1;	// reject code already set
 
+		}
+		if (NeedReject) {
+			u32 port_id;
+			// The PDISC failed.  Set login struct flags accordingly,
+			// terminate any I/O to this port, and Q a PLOGI
+			if (pLoggedInPort) {
+				pLoggedInPort->pdisc = 0;
+				pLoggedInPort->prli = 0;
+				pLoggedInPort->plogi = 0;
+
+				cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+				port_id = pLoggedInPort->port_id;
+			} else {
+				port_id = fchs->s_id & 0xFFFFFF;
+			}
+			fchs->reserved = ls_reject_code;	// borrow this (unused) field
+			cpqfcTSPutLinkQue(dev, ELS_RJT, fchs);
+		}
+		break;
 
-  // Check the incoming frame for a supported ELS type
-  switch( fchs->pl[0] & 0xFFFF)
-  {
-  case 0x0050: //  PDISC?
+	case 0x0003:
+		//  PLOGI?
+		// Payload for PLOGI and PDISC is identical (request & reply)
+		if (!verify_PLOGI(fcChip, fchs, &ls_reject_code))	// valid payload?
+		{
+			LOGIN_PAYLOAD logi;	// FC-PH Port Login
+			u8 NeedReject = 0;
+
+			// PDISC payload OK. If critical login fields
+			// (e.g. WWN) matches last login for this port_id,
+			// we may resume any prior exchanges
+			// with the other port
+
+			BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+							   0,	// don't search linked list for port_id
+							   &logi.port_name[0],	// search linked list for WWN
+							   &pLastLoggedInPort);	// must return non-NULL; when a port_id
+			// is not found, this pointer marks the
+			// end of the singly linked list
+			if (pLoggedInPort == NULL)	// WWN not found -New Port
+			{
+				pLoggedInPort = CreateFcPort(dev, pLastLoggedInPort, fchs, &logi);
+				if (pLoggedInPort == NULL) {
+					printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
+					// Now Q a LOGOut Request, since we won't be talking to that device
+					NeedReject = 1;
+					// set reject reason code 
+					ls_reject_code = LS_RJT_REASON(LOGICAL_ERROR, NO_LOGIN_RESOURCES);
+				}
+			}
+			if (!NeedReject) {
+				// OK - we have valid fcPort ptr; set fields accordingly.   
+				//                         (not PDISC, not Originator)
+				SetLoginFields(pLoggedInPort, fchs, 0, 0);
+				// send 'ACC' reply 
+				cpqfcTSPutLinkQue(dev, ELS_PLOGI_ACC,	// (PDISC same as PLOGI ACC)
+						  fchs);
+			}
+		}
+		else		// Payload unacceptable
+		{
+			printk("payload unacceptable\n");
+			NeedReject = 1;	// reject code already set
+		}
+		if (NeedReject) {
+			// The PDISC failed.  Set login struct flags accordingly,
+			// terminate any I/O to this port, and Q a PLOGI
+			pLoggedInPort->pdisc = 0;
+			pLoggedInPort->prli = 0;
+			pLoggedInPort->plogi = 0;
 
-    // Payload for PLOGI and PDISC is identical (request & reply)
-    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
-    {
-      LOGIN_PAYLOAD logi;       // FC-PH Port Login
-      
-      // PDISC payload OK. If critical login fields
-      // (e.g. WWN) matches last login for this port_id,
-      // we may resume any prior exchanges
-      // with the other port
+			fchs->reserved = ls_reject_code;	// borrow this (unused) field
 
-      
-      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-   
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-	     NULL,     // don't search Scsi Nexus
-	     0,        // don't search linked list for port_id
-             &logi.port_name[0],     // search linked list for WWN
-             &pLastLoggedInPort);  // must return non-NULL; when a port_id
-                                   // is not found, this pointer marks the
-                                   // end of the singly linked list
-    
-      if( pLoggedInPort != NULL)   // WWN found (prior login OK)
-      { 
-           
- 	if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
-	{
-          // Yes.  We were expecting PDISC?
-          if( pLoggedInPort->pdisc )
-	  {
-	    // Yes; set fields accordingly.     (PDISC, not Originator)
-            SetLoginFields( pLoggedInPort, fchs, TRUE, FALSE);
-       
-            // send 'ACC' reply 
-            cpqfcTSPutLinkQue( cpqfcHBAdata, 
-                          ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
-                          fchs );
-
-	    // OK to resume I/O...
-	  }
-	  else
- 	  {
-	    printk("Not expecting PDISC (pdisc=FALSE)\n");
-	    NeedReject = TRUE;
-	    // set reject reason code 
-            ls_reject_code = 
-              LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
-	  }
-	}
-	else
-	{
-	  if( pLoggedInPort->port_id != 0)
-	  {
-  	    printk("PDISC PortID change: old %Xh, new %Xh\n",
-              pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
-	  }
-          NeedReject = TRUE;
-          // set reject reason code 
-          ls_reject_code = 
-	    LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
-		  
-	}
-      }
-      else
-      {
-	printk("PDISC Request from unknown WWN\n");
-        NeedReject = TRUE;
-          
-	// set reject reason code 
-        ls_reject_code = 
-          LS_RJT_REASON( LOGICAL_ERROR, INVALID_PORT_NAME);
-      }
+			// send 'RJT' reply 
+			cpqfcTSPutLinkQue(dev, ELS_RJT, fchs);
+		}
+		// terminate any exchanges with this device...
+		if (pLoggedInPort) {
+			cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+		}
+		break;
 
-    }
-    else // Payload unacceptable
-    {
-      printk("payload unacceptable\n");
-      NeedReject = TRUE;  // reject code already set
-      
-    }
+	case 0x1020:		// PRLI?
+		{
+			u8 NeedReject = 1;
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+							   (fchs->s_id & 0xFFFFFF),	// search linked list for port_id
+							   NULL,	// DON'T search linked list for WWN
+							   NULL);	// don't care
+
+			if (pLoggedInPort == NULL) {
+				// huh?
+				printk(" Unexpected PRLI Request -not logged in!\n");
+				// set reject reason code 
+				ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+				// Q a LOGOut here?
+			} else {
+				// verify the PRLI ACC payload
+				if (!verify_PRLI(fchs, &ls_reject_code)) {
+					// PRLI Reply is acceptable; were we expecting it?
+					if (pLoggedInPort->plogi) {
+						// yes, we expected the PRLI ACC  (not PDISC; not Originator)
+						SetLoginFields(pLoggedInPort, fchs, 0, 0);
+						// Q an ACCept Reply
+						cpqfcTSPutLinkQue(dev, ELS_PRLI_ACC, fchs);
+						NeedReject = 0;
+					} else {
+						// huh?
+						printk(" (unexpected) PRLI REQEST with plogi 0\n");
+						// set reject reason code 
+						ls_reject_code = LS_RJT_REASON(PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+						// Q a LOGOut here?
+					}
+				} else {
+					printk(" PRLI REQUEST payload failed verify\n");
+					// (reject code set by "verify")
+					// Q a LOGOut here?
+				}
+			}
 
-    if( NeedReject)
-    {
-      ULONG port_id;
-      // The PDISC failed.  Set login struct flags accordingly,
-      // terminate any I/O to this port, and Q a PLOGI
-      if( pLoggedInPort )
-      {
-        pLoggedInPort->pdisc = FALSE;
-        pLoggedInPort->prli = FALSE;
-        pLoggedInPort->plogi = FALSE;
-	
-        cpqfcTSTerminateExchange( cpqfcHBAdata, 
-          &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
-	port_id = pLoggedInPort->port_id;
-      }
-      else
-      {
-	port_id = fchs->s_id &0xFFFFFF;
-      }
-      fchs->reserved = ls_reject_code; // borrow this (unused) field
-      cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
-    }
-   
-    break;
+			if (NeedReject) {
+				// Q a ReJecT Reply with reason code
+				fchs->reserved = ls_reject_code;
+				cpqfcTSPutLinkQue(dev, ELS_RJT,	// Q Type
+						  fchs);
+			}
+		}
+		break;
 
+	case 0x0005:		// LOGOut?
+		{
+			// was this LOGOUT because we sent a ELS_PDISC to an FC device
+			// with changed (or new) port_id, or does the port refuse 
+			// to communicate to us?
+			// We maintain a logout counter - if we get 3 consecutive LOGOuts,
+			// give up!
+			LOGOUT_PAYLOAD logo;
+			u8 GiveUpOnDevice = 0;
+			u32 ls_reject_code = 0;
+
+			BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logo, sizeof(logo));
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+							   0,	// don't search linked list for port_id
+							   &logo.port_name[0],	// search linked list for WWN
+							   NULL);	// don't care about end of list
+
+			if (pLoggedInPort)	// found the device?
+			{
+				// Q an ACC reply 
+				cpqfcTSPutLinkQue(dev, ELS_LOGO_ACC,	// Q Type
+						  fchs);	// device to respond to
+				// set login struct fields (LOGO_counter increment)
+				SetLoginFields(pLoggedInPort, fchs, 0, 0);
+				// are we an Initiator?
+				if (fcChip->Options.initiator) {
+					// we're an Initiator, so check if we should 
+					// try (another?) login
+					// Fabrics routinely log out from us after
+					// getting device info - don't try to log them
+					// back in.
+					if ((fchs->s_id & 0xFFF000) == 0xFFF000) {
+						;	// do nothing
+					} else if (pLoggedInPort->LOGO_counter <= 3) {
+						// try (another) login (PLOGI request)
+						cpqfcTSPutLinkQue(dev, ELS_PLOGI,	// Q Type
+								  fchs);
+						// Terminate I/O with "retry" potential
+						cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+					} else {
+						printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n", fchs->s_id && 0xFFFFFF);
+						GiveUpOnDevice = 1;
+					}
+				} else {
+					GiveUpOnDevice = 1;
+				}
+
+				if (GiveUpOnDevice == 1) {
+					cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, DEVICE_REMOVED);
+				}
+			} else	// we don't know this WWN!
+			{
+				// Q a ReJecT Reply with reason code
+				fchs->reserved = ls_reject_code;
+				cpqfcTSPutLinkQue(dev, ELS_RJT,	// Q Type
+						  fchs);
+			}
+		}
+		break;
 
+			// FABRIC only case
+	case 0x0461:	// ELS RSCN (Registered State Change Notification)?
+		{
+			int Ports;
+			int i;
+			__u32 Buff;
+			// Typically, one or more devices have been added to or dropped
+			// from the Fabric.
+			// The format of this frame is defined in FC-FLA (Rev 2.7, Aug 1997)
+			// The first 32-bit word has a 2-byte Payload Length, which
+			// includes the 4 bytes of the first word.  Consequently,
+			// this PL len must never be less than 4, must be a multiple of 4,
+			// and has a specified max value 256.
+			// (Endianess!)
+			Ports = ((fchs->pl[0] >> 24) - 4) / 4;
+			Ports = Ports > 63 ? 63 : Ports;
+
+			printk(" RSCN ports: %d\n", Ports);
+			if (Ports <= 0)	// huh?
+			{
+				// ReJecT the command
+				fchs->reserved = LS_RJT_REASON(UNABLE_TO_PERFORM, 0);
+
+				cpqfcTSPutLinkQue(dev, ELS_RJT,	// Q Type
+						  fchs);
+
+				break;
+			} else	// Accept the command
+			{
+				cpqfcTSPutLinkQue(dev, ELS_ACC,	// Q Type
+						  fchs);
+			}
 
-  case 0x0003: //  PLOGI?
+			// Check the "address format" to determine action.
+			// We have 3 cases:
+			// 0 = Port Address; 24-bit address of affected device
+			// 1 = Area Address; MS 16 bits valid
+			// 2 = Domain Address; MS 8 bits valid
+			for (i = 0; i < Ports; i++) {
+				BigEndianSwap((u8 *) & fchs->pl[i + 1], (u8 *) & Buff, 4);
+				switch (Buff & 0xFF000000) {
+				case 0:	// Port Address?
+				case 0x01000000:	// Area Domain?
+				case 0x02000000:	// Domain Address
+					// For example, "port_id" 0x201300 
+					// OK, let's try a Name Service Request (Query)
+					fchs->s_id = 0xFFFFFC;	// Name Server Address
+					cpqfcTSPutLinkQue(dev, FCS_NSR, fchs);
+					break;
+				default:	// huh? new value on version change?
+					break;
+				}
+			}
+		}
+		break;
+	default:
+		// don't support this request (yet)
+		// set reject reason code 
+		fchs->reserved = LS_RJT_REASON(UNABLE_TO_PERFORM, REQUEST_NOT_SUPPORTED);
+		cpqfcTSPutLinkQue(dev, ELS_RJT,	fchs);	// Q Type
+		break;
+	}
+}
 
-    // Payload for PLOGI and PDISC is identical (request & reply)
-    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
-    {
-      LOGIN_PAYLOAD logi;       // FC-PH Port Login
-      BOOLEAN NeedReject = FALSE;
-      
-      // PDISC payload OK. If critical login fields
-      // (e.g. WWN) matches last login for this port_id,
-      // we may resume any prior exchanges
-      // with the other port
 
-      
-      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-   
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-	     NULL,       // don't search Scsi Nexus
-	     0,        // don't search linked list for port_id
-             &logi.port_name[0],     // search linked list for WWN
-             &pLastLoggedInPort);  // must return non-NULL; when a port_id
-                                   // is not found, this pointer marks the
-                                   // end of the singly linked list
-    
-      if( pLoggedInPort == NULL)   // WWN not found -New Port
-      { 
-      	pLoggedInPort = CreateFcPort( 
-			  cpqfcHBAdata, 
-			  pLastLoggedInPort, 
-			  fchs,
-			  &logi);
-        if( pLoggedInPort == NULL )
-        {
-          printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
-          // Now Q a LOGOut Request, since we won't be talking to that device
-	
-          NeedReject = TRUE;  
-	  
-          // set reject reason code 
-          ls_reject_code = 
-            LS_RJT_REASON( LOGICAL_ERROR, NO_LOGIN_RESOURCES);
-	    
+static void ProcessELS_Reply(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
+{
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 ox_id = (fchs->ox_rx_id >> 16);
+	u32 ls_reject_code;
+	PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
+
+	// If this is a valid reply, then we MUST have sent a request.
+	// Verify that we can find a valid request OX_ID corresponding to
+	// this reply
+
+	if (Exchanges->fcExchange[(fchs->ox_rx_id >> 16)].type == 0) {
+		printk(" *Discarding ACC/RJT frame, xID %04X/%04X* ", ox_id, fchs->ox_rx_id & 0xffff);
+		goto Quit;	// exit this routine
 	}
-      }
-      if( !NeedReject )
-      {
-      
-        // OK - we have valid fcPort ptr; set fields accordingly.   
-	//                         (not PDISC, not Originator)
-        SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE); 
-
-        // send 'ACC' reply 
-        cpqfcTSPutLinkQue( cpqfcHBAdata, 
-                      ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
-                      fchs );
-      }
-    }
-    else // Payload unacceptable
-    {
-      printk("payload unacceptable\n");
-      NeedReject = TRUE;  // reject code already set
-    }
 
-    if( NeedReject)
-    {
-      // The PDISC failed.  Set login struct flags accordingly,
-      // terminate any I/O to this port, and Q a PLOGI
-      pLoggedInPort->pdisc = FALSE;
-      pLoggedInPort->prli = FALSE;
-      pLoggedInPort->plogi = FALSE;
-	
-      fchs->reserved = ls_reject_code; // borrow this (unused) field
+	// Is the reply a RJT (reject)?
+	if ((fchs->pl[0] & 0xFFFFL) == 0x01)	// Reject reply?
+	{
+		//  ******  REJECT REPLY  ********
+		switch (Exchanges->fcExchange[ox_id].type) {
+		case ELS_FDISC:	// we sent out Fabric Discovery
+		case ELS_FLOGI:	// we sent out FLOGI
+			printk("RJT received on Fabric Login from %Xh, reason %Xh\n", fchs->s_id, fchs->pl[1]);
+			break;
+		default:
+			break;
+		}
+		goto Done;
+	}
+	// OK, we have an ACCept...
+	// What's the ACC type? (according to what we sent)
+	switch (Exchanges->fcExchange[ox_id].type) {
+	case ELS_PLOGI:	// we sent out PLOGI
+		if (!verify_PLOGI(fcChip, fchs, &ls_reject_code)) {
+			LOGIN_PAYLOAD logi;	// FC-PH Port Login
+			// login ACC payload acceptable; search for WWN in our list
+			// of fcPorts
+			BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+						   0,	// don't search linked list for port_id
+						   &logi.port_name[0],	// search linked list for WWN
+						   &pLastLoggedInPort);	// must return non-NULL; when a port_id
+			// is not found, this pointer marks the
+			// end of the singly linked list
+			if (pLoggedInPort == NULL)	// WWN not found - new port
+			{
+				pLoggedInPort = CreateFcPort(dev, pLastLoggedInPort, fchs, &logi);
+				if (pLoggedInPort == NULL) {
+					printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
+					// Now Q a LOGOut Request, since we won't be talking to that device
+					goto Done;	// exit with error! dropped login frame
+				}
+			} else	// WWN was already known.  Ensure that any open
+				// exchanges for this WWN are terminated.
+				// NOTE: It's possible that a device can change its 
+				// 24-bit port_id after a Link init or Fabric change 
+				// (e.g. LIP or Fabric RSCN).  In that case, the old
+				// 24-bit port_id may be duplicated, or no longer exist.
+			{
+				cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+			}
 
-      // send 'RJT' reply 
-      cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
-    }
-   
-    // terminate any exchanges with this device...
-    if( pLoggedInPort )
-    {
-      cpqfcTSTerminateExchange( cpqfcHBAdata, 
-        &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
-    }
-    break;
+			// We have an fcPort struct - set fields accordingly
+			// not PDISC, originator 
+			SetLoginFields(pLoggedInPort, fchs, 0, 1);
+			// We just set a "port_id"; is it duplicated?
+			TestDuplicatePortId(dev, pLoggedInPort);
+			// For Fabric operation, we issued PLOGI to 0xFFFFFC
+			// so we can send SCR (State Change Registration) 
+			// Check for this special case...
+			if (fchs->s_id == 0xFFFFFC) {
+				// PLOGI ACC was a Fabric response... issue SCR
+				fchs->s_id = 0xFFFFFD;	// address for SCR
+				cpqfcTSPutLinkQue(dev, ELS_SCR, fchs);
+			}
+			else {
+				// Now we need a PRLI to enable FCP-SCSI operation
+				// set flags and Q up a ELS_PRLI
+				cpqfcTSPutLinkQue(dev, ELS_PRLI, fchs);
+			}
+		} else {
+			// login payload unacceptable - reason in ls_reject_code
+			// Q up a Logout Request
+			printk("Login Payload unacceptable\n");
+		}
+		break;
 
+		// PDISC logic very similar to PLOGI, except we never want
+		// to allocate mem for "new" port, and we set flags differently
+		// (might combine later with PLOGI logic for efficiency)  
+	case ELS_PDISC:	// we sent out PDISC
+		if (!verify_PLOGI(fcChip, fchs, &ls_reject_code)) {
+			LOGIN_PAYLOAD logi;	// FC-PH Port Login
+			u8 NeedLogin = 0;
+
+			// login payload acceptable; search for WWN in our list
+			// of (previously seen) fcPorts
+			BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
+
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+							   0,	// don't search linked list for port_id
+							   &logi.port_name[0],	// search linked list for WWN
+							   &pLastLoggedInPort);	// must return non-NULL; when a port_id
+			// is not found, this pointer marks the
+			// end of the singly linked list
+			if (pLoggedInPort != NULL)	// WWN found?
+			{
+				// WWN has same port_id as last login?  (Of course, a properly
+				// working FC device should NEVER ACCept a PDISC if it's
+				// port_id changed, but check just in case...)
+				if ((fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id) {
+					// Yes.  We were expecting PDISC?
+					if (pLoggedInPort->pdisc) {
+						int i;
+
+
+						// PDISC expected -- set fields.  (PDISC, Originator)
+						SetLoginFields(pLoggedInPort, fchs, 1, 1);
+
+						// We are ready to resume FCP-SCSI to this device...
+						// Do we need to start anything that was Queued?
+
+						for (i = 0; i < TACH_SEST_LEN; i++) {
+							// see if any exchange for this PDISC'd port was queued
+							if (((fchs->s_id & 0xFFFFFF) == (Exchanges->fcExchange[i].fchs.d_id & 0xFFFFFF))
+							    && (Exchanges->fcExchange[i].status & EXCHANGE_QUEUED)) {
+								fchs->reserved = i;	// copy ExchangeID
+//						                printk(" *Q x_ID %Xh after PDISC* ",i);
+
+								cpqfcTSPutLinkQue(dev, EXCHANGE_QUEUED, fchs);
+							}
+						}
+						// Complete commands Q'd while we were waiting for Login
+						UnblockScsiDevice(dev->HostAdapter, pLoggedInPort);
+					} else {
+						printk("Not expecting PDISC (pdisc=0)\n");
+						NeedLogin = 1;
+					}
+				} else {
+					printk("PDISC PortID change: old %Xh, new %Xh\n", pLoggedInPort->port_id, fchs->s_id & 0xFFFFFF);
+					NeedLogin = 1;
+				}
+			} else {
+				printk("PDISC ACC from unknown WWN\n");
+				NeedLogin = 1;
+			}
 
+			if (NeedLogin) {
+				// The PDISC failed.  Set login struct flags accordingly,
+				// terminate any I/O to this port, and Q a PLOGI
+				if (pLoggedInPort)	// FC device previously known?
+				{
+					cpqfcTSPutLinkQue(dev, ELS_LOGO, fchs);	// Qtype has port_id to send to 
+					// There are a variety of error scenarios which can result
+					// in PDISC failure, so as a catchall, add the check for
+					// duplicate port_id.
+					TestDuplicatePortId(dev, pLoggedInPort);
+
+					// TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
+					pLoggedInPort->pdisc = 0;
+					pLoggedInPort->prli = 0;
+					pLoggedInPort->plogi = 0;
+
+					cpqfcTSTerminateExchange(dev, &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+				}
+				cpqfcTSPutLinkQue(dev, ELS_PLOGI, fchs);
+			}
+		} else {
+			// login payload unacceptable - reason in ls_reject_code
+			// Q up a Logout Request
+			printk("ERROR: Login Payload unacceptable!\n");
 
-  case 0x1020:  // PRLI?
-  {
-    BOOLEAN NeedReject = TRUE;
-    pLoggedInPort = fcFindLoggedInPort( 
-           fcChip, 
-           NULL,       // don't search Scsi Nexus
-	   (fchs->s_id & 0xFFFFFF),  // search linked list for port_id
-           NULL,     // DON'T search linked list for WWN
-           NULL);    // don't care
-      
-    if( pLoggedInPort == NULL ) 
-    {
-      // huh?
-      printk(" Unexpected PRLI Request -not logged in!\n");
-
-      // set reject reason code 
-      ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
-      
-      // Q a LOGOut here?
-    }
-    else
-    {
-      // verify the PRLI ACC payload
-      if( !verify_PRLI( fchs, &ls_reject_code) )
-      {
-        // PRLI Reply is acceptable; were we expecting it?
-        if( pLoggedInPort->plogi ) 
-        { 
-  	  // yes, we expected the PRLI ACC  (not PDISC; not Originator)
-          SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
-
-          // Q an ACCept Reply
-	  cpqfcTSPutLinkQue( cpqfcHBAdata,
-                        ELS_PRLI_ACC, 
-                        fchs );   
-	  
-	  NeedReject = FALSE;
-	}
-        else
-        {
-          // huh?
-          printk(" (unexpected) PRLI REQEST with plogi FALSE\n");
-
-          // set reject reason code 
-          ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
-    
-    	  // Q a LOGOut here?
-	  
-        }
-      }
-      else
-      {
-        printk(" PRLI REQUEST payload failed verify\n");
-        // (reject code set by "verify")
-
-        // Q a LOGOut here?
-      }
-    }
-
-    if( NeedReject )
-    {
-      // Q a ReJecT Reply with reason code
-      fchs->reserved = ls_reject_code;
-      cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_RJT, // Q Type
-                    fchs );  
-    }
-  }
-    break;
- 
-
-    
-
-  case  0x0005:  // LOGOut?
-  {
-  // was this LOGOUT because we sent a ELS_PDISC to an FC device
-  // with changed (or new) port_id, or does the port refuse 
-  // to communicate to us?
-  // We maintain a logout counter - if we get 3 consecutive LOGOuts,
-  // give up!
-    LOGOUT_PAYLOAD logo;
-    BOOLEAN GiveUpOnDevice = FALSE;
-    ULONG ls_reject_code = 0;
-    
-    BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logo, sizeof(logo));
-
-    pLoggedInPort = fcFindLoggedInPort( 
-           fcChip, 
-           NULL,     // don't search Scsi Nexus
-	   0,        // don't search linked list for port_id
-           &logo.port_name[0],     // search linked list for WWN
-           NULL);    // don't care about end of list
-    
-    if( pLoggedInPort ) // found the device?
-    {
-      // Q an ACC reply 
-      cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_LOGO_ACC, // Q Type
-                    fchs );       // device to respond to
-
-      // set login struct fields (LOGO_counter increment)
-      SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
-      
-      // are we an Initiator?
-      if( fcChip->Options.initiator)  
-      {
-        // we're an Initiator, so check if we should 
-	// try (another?) login
-
-	// Fabrics routinely log out from us after
-	// getting device info - don't try to log them
-	// back in.
-	if( (fchs->s_id & 0xFFF000) == 0xFFF000 )
-	{
-	  ; // do nothing
-	}
-	else if( pLoggedInPort->LOGO_counter <= 3)
-	{
-	  // try (another) login (PLOGI request)
-	  
-          cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_PLOGI, // Q Type
-                    fchs );  
-	
-	  // Terminate I/O with "retry" potential
-	  cpqfcTSTerminateExchange( cpqfcHBAdata, 
-			            &pLoggedInPort->ScsiNexus,
-				    PORTID_CHANGED);
-	}
-	else
-	{
-	  printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n",
-			  fchs->s_id &&0xFFFFFF);
-	  GiveUpOnDevice = TRUE;
-	}
-      }
-      else
-      {
-	GiveUpOnDevice = TRUE;
-      }
-
-
-      if( GiveUpOnDevice == TRUE )
-      {
-        cpqfcTSTerminateExchange( cpqfcHBAdata, 
-	                          &pLoggedInPort->ScsiNexus,
-		                  DEVICE_REMOVED);
-      }
-    }  
-    else  // we don't know this WWN!
-    {
-      // Q a ReJecT Reply with reason code
-      fchs->reserved = ls_reject_code;
-      cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_RJT, // Q Type
-                    fchs );  
-    }
-  }
-    break;
-
-
-
-
-  // FABRIC only case
-  case 0x0461:  // ELS RSCN (Registered State Change Notification)?
-  {
-    int Ports;
-    int i;
-    __u32 Buff;
-    // Typically, one or more devices have been added to or dropped
-    // from the Fabric.
-    // The format of this frame is defined in FC-FLA (Rev 2.7, Aug 1997)
-    // The first 32-bit word has a 2-byte Payload Length, which
-    // includes the 4 bytes of the first word.  Consequently,
-    // this PL len must never be less than 4, must be a multiple of 4,
-    // and has a specified max value 256.
-    // (Endianess!)
-    Ports = ((fchs->pl[0] >>24) - 4) / 4;
-    Ports = Ports > 63 ? 63 : Ports;
-    
-    printk(" RSCN ports: %d\n", Ports);
-    if( Ports <= 0 )  // huh?
-    {
-      // ReJecT the command
-      fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 0);
-    
-      cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_RJT, // Q Type
-                    fchs ); 
-      
-      break;
-    }
-    else  // Accept the command
-    {
-       cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_ACC, // Q Type
-                    fchs ); 
-    }
-    
-      // Check the "address format" to determine action.
-      // We have 3 cases:
-      // 0 = Port Address; 24-bit address of affected device
-      // 1 = Area Address; MS 16 bits valid
-      // 2 = Domain Address; MS 8 bits valid
-    for( i=0; i<Ports; i++)
-    { 
-      BigEndianSwap( (UCHAR*)&fchs->pl[i+1],(UCHAR*)&Buff, 4);
-      switch( Buff & 0xFF000000)
-      {
-
-      case 0:  // Port Address?
-	
-      case 0x01000000: // Area Domain?
-      case 0x02000000: // Domain Address
-        // For example, "port_id" 0x201300 
-	// OK, let's try a Name Service Request (Query)
-      fchs->s_id = 0xFFFFFC;  // Name Server Address
-      cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
-
-      break;
-	
-	
-      default:  // huh? new value on version change?
-      break;
-      }
-    }
-  }    
-  break;    
-
-
-
-    
-  default:  // don't support this request (yet)
-    // set reject reason code 
-    fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 
-		                    REQUEST_NOT_SUPPORTED);
-    
-    cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_RJT, // Q Type
-                    fchs );     
-    break;  
-  }
-}
-
-
-static void ProcessELS_Reply( 
-		CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG ox_id = (fchs->ox_rx_id >>16);
-  ULONG ls_reject_code;
-  PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
-  
-  // If this is a valid reply, then we MUST have sent a request.
-  // Verify that we can find a valid request OX_ID corresponding to
-  // this reply
-
-  
-  if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
-  {
-    printk(" *Discarding ACC/RJT frame, xID %04X/%04X* ", 
-		    ox_id, fchs->ox_rx_id & 0xffff);
-    goto Quit;  // exit this routine
-  }
-
-
-  // Is the reply a RJT (reject)?
-  if( (fchs->pl[0] & 0xFFFFL) == 0x01) // Reject reply?
-  {
-//  ******  REJECT REPLY  ********
-    switch( Exchanges->fcExchange[ox_id].type )
-    {
-	  
-    case ELS_FDISC:  // we sent out Fabric Discovery
-    case ELS_FLOGI:  // we sent out FLOGI
-
-      printk("RJT received on Fabric Login from %Xh, reason %Xh\n", 
-        fchs->s_id, fchs->pl[1]);    
-
-    break;
-
-    default:
-    break;
-    }
-      
-    goto Done;
-  }
-
-  // OK, we have an ACCept...
-  // What's the ACC type? (according to what we sent)
-  switch( Exchanges->fcExchange[ox_id].type )
-  {
-	  
-  case ELS_PLOGI:  // we sent out PLOGI
-    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
-    {
-      LOGIN_PAYLOAD logi;       // FC-PH Port Login
-      
-      // login ACC payload acceptable; search for WWN in our list
-      // of fcPorts
-      
-      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-   
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-	     NULL,     // don't search Scsi Nexus
-	     0,        // don't search linked list for port_id
-             &logi.port_name[0],     // search linked list for WWN
-             &pLastLoggedInPort);  // must return non-NULL; when a port_id
-                                   // is not found, this pointer marks the
-                                   // end of the singly linked list
-    
-      if( pLoggedInPort == NULL)         // WWN not found - new port
-      {
+		}
+		break;
 
-	pLoggedInPort = CreateFcPort( 
-			  cpqfcHBAdata, 
-			  pLastLoggedInPort, 
-			  fchs,
-			  &logi);
-
-        if( pLoggedInPort == NULL )
-        {
-          printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
-          // Now Q a LOGOut Request, since we won't be talking to that device
-	
-          goto Done;  // exit with error! dropped login frame
-	}
-      }
-      else      // WWN was already known.  Ensure that any open
-	        // exchanges for this WWN are terminated.
-      	// NOTE: It's possible that a device can change its 
-	// 24-bit port_id after a Link init or Fabric change 
-	// (e.g. LIP or Fabric RSCN).  In that case, the old
-	// 24-bit port_id may be duplicated, or no longer exist.
-      {
-
-        cpqfcTSTerminateExchange( cpqfcHBAdata, 
-          &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
-      }
-
-      // We have an fcPort struct - set fields accordingly
-                                    // not PDISC, originator 
-      SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
-			
-      // We just set a "port_id"; is it duplicated?
-      TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
-
-      // For Fabric operation, we issued PLOGI to 0xFFFFFC
-      // so we can send SCR (State Change Registration) 
-      // Check for this special case...
-      if( fchs->s_id == 0xFFFFFC ) 
-      {
-        // PLOGI ACC was a Fabric response... issue SCR
-	fchs->s_id = 0xFFFFFD;  // address for SCR
-        cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_SCR, fchs);
-      }
-
-      else
-      {
-      // Now we need a PRLI to enable FCP-SCSI operation
-      // set flags and Q up a ELS_PRLI
-        cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PRLI, fchs);
-      }
-    }
-    else
-    {
-      // login payload unacceptable - reason in ls_reject_code
-      // Q up a Logout Request
-      printk("Login Payload unacceptable\n");
+	case ELS_PRLI:		// we sent out PRLI
+		pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search Scsi Nexus
+						   (fchs->s_id & 0xFFFFFF),	// search linked list for port_id
+						   NULL,	// DON'T search linked list for WWN
+						   NULL);	// don't care
+
+		if (pLoggedInPort == NULL) {
+			// huh?
+			printk(" Unexpected PRLI ACCept frame!\n");
+			// Q a LOGOut here?
+			goto Done;
+		}
+		// verify the PRLI ACC payload
+		if (!verify_PRLI(fchs, &ls_reject_code)) {
+			// PRLI Reply is acceptable; were we expecting it?
+			if (pLoggedInPort->plogi) {
+				// yes, we expected the PRLI ACC  (not PDISC; Originator)
+				SetLoginFields(pLoggedInPort, fchs, 0, 1);
+				// OK, let's send a REPORT_LUNS command to determine
+				// whether VSA or PDA FCP-LUN addressing is used.
+				cpqfcTSPutLinkQue(dev, SCSI_REPORT_LUNS, fchs);
+				// It's possible that a device we were talking to changed 
+				// port_id, and has logged back in.  This function ensures
+				// that I/O will resume.
+				UnblockScsiDevice(dev->HostAdapter, pLoggedInPort);
+			} else {
+				// huh?
+				printk(" (unexpected) PRLI ACCept with plogi 0\n");
+				// Q a LOGOut here?
+				goto Done;
+			}
+		} else {
+			printk(" PRLI ACCept payload failed verify\n");
+			// Q a LOGOut here?
+		}
+		break;
 
-    }
-    break;
+	case ELS_FLOGI:	// we sent out FLOGI (Fabric Login)
+		// update the upper 16 bits of our port_id in Tachyon
+		// the switch adds those upper 16 bits when responding
+		// to us (i.e. we are the destination_id)
+		fcChip->Registers.my_al_pa = (fchs->d_id & 0xFFFFFF);
+		writel(fcChip->Registers.my_al_pa, fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
+
+		// now send out a PLOGI to the well known port_id 0xFFFFFC
+		fchs->s_id = 0xFFFFFC;
+		cpqfcTSPutLinkQue(dev, ELS_PLOGI, fchs);
+		break;
 
 
-  // PDISC logic very similar to PLOGI, except we never want
-  // to allocate mem for "new" port, and we set flags differently
-  // (might combine later with PLOGI logic for efficiency)  
-  case ELS_PDISC:  // we sent out PDISC
-    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
-    {
-      LOGIN_PAYLOAD logi;       // FC-PH Port Login
-      BOOLEAN NeedLogin = FALSE;
-      
-      // login payload acceptable; search for WWN in our list
-      // of (previously seen) fcPorts
-      
-      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
-   
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-	     NULL,     // don't search Scsi Nexus
-	     0,        // don't search linked list for port_id
-             &logi.port_name[0],     // search linked list for WWN
-             &pLastLoggedInPort);  // must return non-NULL; when a port_id
-                                   // is not found, this pointer marks the
-                                   // end of the singly linked list
-    
-      if( pLoggedInPort != NULL)   // WWN found?
-      {
-        // WWN has same port_id as last login?  (Of course, a properly
-	// working FC device should NEVER ACCept a PDISC if it's
-	// port_id changed, but check just in case...)
-	if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
-	{
-          // Yes.  We were expecting PDISC?
-          if( pLoggedInPort->pdisc )
-	  {
-            int i;
-	    
-	    
-	    // PDISC expected -- set fields.  (PDISC, Originator)
-            SetLoginFields( pLoggedInPort, fchs, TRUE, TRUE);
+	case ELS_FDISC:	// we sent out FDISC (Fabric Discovery (Login))
+		printk(" ELS_FDISC success ");
+		break;
 
-	    // We are ready to resume FCP-SCSI to this device...
-            // Do we need to start anything that was Queued?
+	case ELS_SCR:		// we sent out State Change Registration
+		// now we can issue Name Service Request to find any
+		// Fabric-connected devices we might want to login to.
+		fchs->s_id = 0xFFFFFC;	// Name Server Address
+		cpqfcTSPutLinkQue(dev, FCS_NSR, fchs);
+		break;
 
-            for( i=0; i< TACH_SEST_LEN; i++)
-            {
-              // see if any exchange for this PDISC'd port was queued
-              if( ((fchs->s_id &0xFFFFFF) == 
-                   (Exchanges->fcExchange[i].fchs.d_id & 0xFFFFFF))
-                      &&
-                  (Exchanges->fcExchange[i].status & EXCHANGE_QUEUED))
-              {
-                fchs->reserved = i; // copy ExchangeID
-//                printk(" *Q x_ID %Xh after PDISC* ",i);
-
-                cpqfcTSPutLinkQue( cpqfcHBAdata, EXCHANGE_QUEUED, fchs );
-              }
-            }
-
-	    // Complete commands Q'd while we were waiting for Login
-
-	    UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
-	  }
-	  else
-	  {
-	    printk("Not expecting PDISC (pdisc=FALSE)\n");
-	    NeedLogin = TRUE;
-	  }
+	default:
+		printk(" *Discarding unknown ACC frame, xID %04X/%04X* ", ox_id, fchs->ox_rx_id & 0xffff);
+		break;
 	}
-	else
-	{
-	  printk("PDISC PortID change: old %Xh, new %Xh\n",
-            pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
-          NeedLogin = TRUE;
-		  
-	}
-      }
-      else
-      {
-	printk("PDISC ACC from unknown WWN\n");
-        NeedLogin = TRUE;
-      }
-
-      if( NeedLogin)
-      {
-	
-        // The PDISC failed.  Set login struct flags accordingly,
-	// terminate any I/O to this port, and Q a PLOGI
-	if( pLoggedInPort )  // FC device previously known?
-	{
-
-          cpqfcTSPutLinkQue( cpqfcHBAdata,
-                    ELS_LOGO, // Q Type
-                    fchs );   // has port_id to send to 
-
-	  // There are a variety of error scenarios which can result
-  	  // in PDISC failure, so as a catchall, add the check for
-	  // duplicate port_id.
-	  TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
-
-//    TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
-          pLoggedInPort->pdisc = FALSE;
-          pLoggedInPort->prli = FALSE;
-          pLoggedInPort->plogi = FALSE;
-	
-          cpqfcTSTerminateExchange( cpqfcHBAdata, 
-	    &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
-        }
-        cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs );
-      }
-    }
-    else
-    {
-      // login payload unacceptable - reason in ls_reject_code
-      // Q up a Logout Request
-      printk("ERROR: Login Payload unacceptable!\n");
-
-    }
-   
-    break;
-    
-
-
-  case ELS_PRLI:  // we sent out PRLI
-
-
-    pLoggedInPort = fcFindLoggedInPort( 
-           fcChip, 
-           NULL,       // don't search Scsi Nexus
-	   (fchs->s_id & 0xFFFFFF),  // search linked list for port_id
-           NULL,     // DON'T search linked list for WWN
-           NULL);    // don't care
-      
-    if( pLoggedInPort == NULL ) 
-    {
-      // huh?
-      printk(" Unexpected PRLI ACCept frame!\n");
-
-      // Q a LOGOut here?
-
-      goto Done;
-    }
-
-    // verify the PRLI ACC payload
-    if( !verify_PRLI( fchs, &ls_reject_code) )
-    {
-      // PRLI Reply is acceptable; were we expecting it?
-      if( pLoggedInPort->plogi ) 
-      { 
-	// yes, we expected the PRLI ACC  (not PDISC; Originator)
-	SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
-
-        // OK, let's send a REPORT_LUNS command to determine
-	// whether VSA or PDA FCP-LUN addressing is used.
-	
-        cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
-	
-	// It's possible that a device we were talking to changed 
-	// port_id, and has logged back in.  This function ensures
-	// that I/O will resume.
-        UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
-
-      }
-      else
-      {
-        // huh?
-        printk(" (unexpected) PRLI ACCept with plogi FALSE\n");
-
-        // Q a LOGOut here?
-        goto Done;
-      }
-    }
-    else
-    {
-      printk(" PRLI ACCept payload failed verify\n");
-
-      // Q a LOGOut here?
-    }
-
-    break;
- 
-  case ELS_FLOGI:  // we sent out FLOGI (Fabric Login)
-
-    // update the upper 16 bits of our port_id in Tachyon
-    // the switch adds those upper 16 bits when responding
-    // to us (i.e. we are the destination_id)
-    fcChip->Registers.my_al_pa = (fchs->d_id & 0xFFFFFF);
-    writel( fcChip->Registers.my_al_pa,  
-      fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
-
-    // now send out a PLOGI to the well known port_id 0xFFFFFC
-    fchs->s_id = 0xFFFFFC;
-    cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs);
-  
-   break; 
-
-
-  case ELS_FDISC:  // we sent out FDISC (Fabric Discovery (Login))
-
-   printk( " ELS_FDISC success ");
-   break;
-   
-
-  case ELS_SCR:  // we sent out State Change Registration
-    // now we can issue Name Service Request to find any
-    // Fabric-connected devices we might want to login to.
-   
-	
-    fchs->s_id = 0xFFFFFC;  // Name Server Address
-    cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
-    
-
-    break;
-
-    
-  default:
-    printk(" *Discarding unknown ACC frame, xID %04X/%04X* ", 
-   		    ox_id, fchs->ox_rx_id & 0xffff);
-    break;
-  }
-
-  
 Done:
-  // Regardless of whether the Reply is valid or not, the
-  // the exchange is done - complete
-  cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, (fchs->ox_rx_id >>16)); 
-	  
-Quit:    
-  return;
+	// Regardless of whether the Reply is valid or not, the
+	// the exchange is done - complete
+	cpqfcTSCompleteExchange(dev->PciDev, fcChip, (fchs->ox_rx_id >> 16));
+Quit:
+	return;
 }
 
 
@@ -2075,352 +1604,263 @@
 // This is where we process the Directory (Name) Service Reply
 // to know which devices are on the Fabric
 
-static void ProcessFCS_Reply( 
-	CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
+static void ProcessFCS_Reply(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG ox_id = (fchs->ox_rx_id >>16);
-//  ULONG ls_reject_code;
-//  PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
-  
-  // If this is a valid reply, then we MUST have sent a request.
-  // Verify that we can find a valid request OX_ID corresponding to
-  // this reply
-
-  if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
-  {
-    printk(" *Discarding Reply frame, xID %04X/%04X* ", 
-		    ox_id, fchs->ox_rx_id & 0xffff);
-    goto Quit;  // exit this routine
-  }
-
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 ox_id = (fchs->ox_rx_id >> 16);
+//	u32 ls_reject_code;
+//	PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
+
+	// If this is a valid reply, then we MUST have sent a request.
+	// Verify that we can find a valid request OX_ID corresponding to
+	// this reply
+
+	if (Exchanges->fcExchange[(fchs->ox_rx_id >> 16)].type == 0) {
+		printk(" *Discarding Reply frame, xID %04X/%04X* ", ox_id, fchs->ox_rx_id & 0xffff);
+		goto Quit;	// exit this routine
+	}
 
-  // OK, we were expecting it.  Now check to see if it's a
-  // "Name Service" Reply, and if so force a re-validation of
-  // Fabric device logins (i.e. Start the login timeout and
-  // send PDISC or PLOGI)
-  // (Endianess Byte Swap?)
-  if( fchs->pl[1] == 0x02FC )  // Name Service
-  {
-    // got a new (or NULL) list of Fabric attach devices... 
-    // Invalidate current logins
-    
-    PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
-    while( pLoggedInPort ) // for all ports which are expecting
-                           // PDISC after the next LIP, set the
-                           // logoutTimer
-    {
+	// OK, we were expecting it.  Now check to see if it's a
+	// "Name Service" Reply, and if so force a re-validation of
+	// Fabric device logins (i.e. Start the login timeout and
+	// send PDISC or PLOGI)
+	// (Endianess Byte Swap?)
+	if (fchs->pl[1] == 0x02FC)	// Name Service
+	{
+		// got a new (or NULL) list of Fabric attach devices... 
+		// Invalidate current logins
 
-      if( (pLoggedInPort->port_id & 0xFFFF00)  // Fabric device?
-		      &&
-          (pLoggedInPort->port_id != 0xFFFFFC) ) // NOT the F_Port
-      {
-        pLoggedInPort->LOGO_timer = 6;  // what's the Fabric timeout??
-                                // suspend any I/O in progress until
-                                // PDISC received...
-        pLoggedInPort->prli = FALSE;   // block FCP-SCSI commands
-      }
-	    
-      pLoggedInPort = pLoggedInPort->pNextPort;
-    }
-    
-    if( fchs->pl[2] == 0x0280)  // ACCept?
-    {
-      // Send PLOGI or PDISC to these Fabric devices
-      SendLogins( cpqfcHBAdata, &fchs->pl[4] );  
-    }
+		PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
+		while (pLoggedInPort)	// for all ports which are expecting
+			// PDISC after the next LIP, set the
+			// logoutTimer
+		{
+
+			if ((pLoggedInPort->port_id & 0xFFFF00)	// Fabric device?
+			    && (pLoggedInPort->port_id != 0xFFFFFC))	// NOT the F_Port
+			{
+				pLoggedInPort->LOGO_timer = 6;	// what's the Fabric timeout??
+				// suspend any I/O in progress until
+				// PDISC received...
+				pLoggedInPort->prli = 0;	// block FCP-SCSI commands
+			}
 
+			pLoggedInPort = pLoggedInPort->pNextPort;
+		}
 
-    // As of this writing, the only reason to reject is because NO
-    // devices are left on the Fabric.  We already started
-    // "logged out" timers; if the device(s) don't come
-    // back, we'll do the implicit logout in the heart beat 
-    // timer routine
-    else  // ReJecT
-    {
-      // this just means no Fabric device is visible at this instant
-    } 
-  }
+		if (fchs->pl[2] == 0x0280)	// ACCept?
+		{
+			// Send PLOGI or PDISC to these Fabric devices
+			SendLogins(dev, &fchs->pl[4]);
+		}
+		// As of this writing, the only reason to reject is because NO
+		// devices are left on the Fabric.  We already started
+		// "logged out" timers; if the device(s) don't come
+		// back, we'll do the implicit logout in the heart beat 
+		// timer routine
+		else		// ReJecT
+		{
+			// this just means no Fabric device is visible at this instant
+		}
+	}
+	// Regardless of whether the Reply is valid or not, the
+	// the exchange is done - complete
+	cpqfcTSCompleteExchange(dev->PciDev, fcChip, (fchs->ox_rx_id >> 16));
 
-  // Regardless of whether the Reply is valid or not, the
-  // the exchange is done - complete
-  cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, (fchs->ox_rx_id >>16));
-	  
-Quit:    
-  return;
+Quit:
+	return;
 }
 
-
-
-
-
-
-
-static void AnalyzeIncomingFrame( 
-        CPQFCHBA *cpqfcHBAdata,
-        ULONG QNdx )
+static void AnalyzeIncomingFrame(CPQFCHBA * dev, u32 QNdx)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
-  TachFCHDR_GCMND* fchs = 
-    (TachFCHDR_GCMND*)fcLQ->Qitem[QNdx].ulBuff;
-//  ULONG ls_reject_code;  // reason for rejecting login
-  LONG ExchangeID;
-//  FC_LOGGEDIN_PORT *pLoggedInPort;
-  BOOLEAN AbortAccept;  
-
-  ENTER("AnalyzeIncomingFrame");
-
-
-
-  switch( fcLQ->Qitem[QNdx].Type) // FCP or Unknown
-  {
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	PFC_LINK_QUE fcLQ = dev->fcLQ;
+	TachFCHDR_GCMND *fchs = (TachFCHDR_GCMND *) fcLQ->Qitem[QNdx].ulBuff;
+//	u32 ls_reject_code;  // reason for rejecting login
+	s32 ExchangeID;
+//	FC_LOGGEDIN_PORT *pLoggedInPort;
+	u8 AbortAccept;
 
-  case SFQ_UNKNOWN:  // unknown frame (e.g. LIP position frame, NOP, etc.)
- 
+	ENTER("AnalyzeIncomingFrame");
 
-      // *********  FC-4 Device Data/ Fibre Channel Service *************
-    if( ((fchs->d_id &0xF0000000) == 0)   // R_CTL (upper nibble) 0x0?
-                &&   
-      (fchs->f_ctl & 0x20000000) )  // TYPE 20h is Fibre Channel Service
-    {
-
-      // ************** FCS Reply **********************
-
-      if( (fchs->d_id & 0xff000000L) == 0x03000000L)  // (31:23 R_CTL)
-      {
-	ProcessFCS_Reply( cpqfcHBAdata, fchs );
-
-      }  // end of  FCS logic
-
-    }
-    
-
-      // ***********  Extended Link Service **************
-
-    else if( fchs->d_id & 0x20000000   // R_CTL 0x2?
-                  &&   
-      (fchs->f_ctl & 0x01000000) )  // TYPE = 1
-    {
-
-                           // these frames are either a response to
-                           // something we sent (0x23) or "unsolicited"
-                           // frames (0x22).
-
-
-      // **************Extended Link REPLY **********************
-                           // R_CTL Solicited Control Reply
-
-      if( (fchs->d_id & 0xff000000L) == 0x23000000L)  // (31:23 R_CTL)
-      {
-
-	ProcessELS_Reply( cpqfcHBAdata, fchs );
-
-      }  // end of  "R_CTL Solicited Control Reply"
-
-
-
-
-       // **************Extended Link REQUEST **********************
-       // (unsolicited commands from another port or task...)
-
-                           // R_CTL Ext Link REQUEST
-      else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
-              (fchs->ox_rx_id != 0xFFFFFFFFL) ) // (ignore LIP frame)
-      {
-
-
-
-	ProcessELS_Request( cpqfcHBAdata, fchs );
-
-      }
-
-
-
-        // ************** LILP **********************
-      else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
-               (fchs->ox_rx_id == 0xFFFFFFFFL)) // (e.g., LIP frames)
-
-      {
-        // SANMark specifies that when available, we must use
-	// the LILP frame to determine which ALPAs to send Port Discovery
-	// to...
-
-        if( fchs->pl[0] == 0x0711L) //  ELS_PLOGI?
+	switch (fcLQ->Qitem[QNdx].Type)	// FCP or Unknown
 	{
-//	  UCHAR *ptr = (UCHAR*)&fchs->pl[1];
-//	  printk(" %d ALPAs found\n", *ptr);
-	  memcpy( fcChip->LILPmap, &fchs->pl[1], 32*4); // 32 DWORDs
-	  fcChip->Options.LILPin = 1; // our LILPmap is valid!
-	  // now post to make Port Discovery happen...
-          cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, fchs);  
-	}
-      }
-    }
-
-     
-    // *****************  BASIC LINK SERVICE *****************
-    
-    else if( fchs->d_id & 0x80000000  // R_CTL:
-                    &&           // Basic Link Service Request
-           !(fchs->f_ctl & 0xFF000000) )  // type=0 for BLS
-    {
+	case SFQ_UNKNOWN:	// unknown frame (e.g. LIP position frame, NOP, etc.)
+		// *********  FC-4 Device Data/ Fibre Channel Service *************
+		if (((fchs->d_id & 0xF0000000) == 0)	// R_CTL (upper nibble) 0x0?
+		    && (fchs->f_ctl & 0x20000000))	// TYPE 20h is Fibre Channel Service
+		{
+			// ************** FCS Reply **********************
+			if ((fchs->d_id & 0xff000000L) == 0x03000000L)	// (31:23 R_CTL)
+			{
+				ProcessFCS_Reply(dev, fchs);
+			}	// end of  FCS logic
+		}
+		// ***********  Extended Link Service **************
+		else if (fchs->d_id & 0x20000000	// R_CTL 0x2?
+			 && (fchs->f_ctl & 0x01000000))	// TYPE = 1
+		{
+			// these frames are either a response to
+			// something we sent (0x23) or "unsolicited"
+			// frames (0x22).
+			// **************Extended Link REPLY **********************
+			// R_CTL Solicited Control Reply
+			if ((fchs->d_id & 0xff000000L) == 0x23000000L)	// (31:23 R_CTL)
+			{
+				ProcessELS_Reply(dev, fchs);
+			}	// end of  "R_CTL Solicited Control Reply"
+			// **************Extended Link REQUEST **********************
+			// (unsolicited commands from another port or task...)
+			// R_CTL Ext Link REQUEST
+			else if ((fchs->d_id & 0xff000000L) == 0x22000000L && (fchs->ox_rx_id != 0xFFFFFFFFL))	// (ignore LIP frame)
+			{
+				ProcessELS_Request(dev, fchs);
+			}
+			// ************** LILP **********************
+			else if ((fchs->d_id & 0xff000000L) == 0x22000000L && (fchs->ox_rx_id == 0xFFFFFFFFL))	// (e.g., LIP frames)
+			{
+				// SANMark specifies that when available, we must use
+				// the LILP frame to determine which ALPAs to send Port Discovery
+				// to...
+				if (fchs->pl[0] == 0x0711L)	//  ELS_PLOGI?
+				{
+//					u8 *ptr = (u8*)&fchs->pl[1];
+//					printk(" %d ALPAs found\n", *ptr);
+					memcpy(fcChip->LILPmap, &fchs->pl[1], 32 * 4);	// 32 DWORDs
+					fcChip->Options.LILPin = 1;	// our LILPmap is valid!
+					// now post to make Port Discovery happen...
+					cpqfcTSPutLinkQue(dev, LINKACTIVE, fchs);
+				}
+			}
+		}
+		// *****************  BASIC LINK SERVICE *****************
+		else if (fchs->d_id & 0x80000000	// R_CTL:
+			 &&	// Basic Link Service Request
+			 !(fchs->f_ctl & 0xFF000000))	// type=0 for BLS
+		{
+			// Check for ABTS (Abort Sequence)
+			if ((fchs->d_id & 0x8F000000) == 0x81000000) {
+				// look for OX_ID, S_ID pair that matches in our
+				// fcExchanges table; if found, reply with ACCept and complete
+				// the exchange
+
+				// Per PLDA, an ABTS is sent by an initiator; therefore
+				// assume that if we have an exhange open to the port who
+				// sent ABTS, it will be the d_id of what we sent.  
+				for (ExchangeID = 0, AbortAccept = 0; ExchangeID < TACH_SEST_LEN; ExchangeID++) {
+					// Valid "target" exchange 24-bit port_id matches? 
+					// NOTE: For the case of handling Intiator AND Target
+					// functions on the same chip, we can have TWO Exchanges
+					// with the same OX_ID -- OX_ID/FFFF for the CMND, and
+					// OX_ID/RX_ID for the XRDY or DATA frame(s).  Ideally,
+					// we would like to support ABTS from Initiators or Targets,
+					// but it's not clear that can be supported on Tachyon for
+					// all cases (requires more investigation).
+
+					if ((Exchanges->fcExchange[ExchangeID].type == SCSI_TWE || Exchanges->fcExchange[ExchangeID].type == SCSI_TRE)
+					    && ((Exchanges->fcExchange[ExchangeID].fchs.d_id & 0xFFFFFF) == (fchs->s_id & 0xFFFFFF))) {
+
+						// target xchnge port_id matches -- how about OX_ID?
+						if ((Exchanges->fcExchange[ExchangeID].fchs.ox_rx_id & 0xFFFF0000)
+						    == (fchs->ox_rx_id & 0xFFFF0000))
+							// yes! post ACCept response; will be completed by fcStart
+						{
+							Exchanges->fcExchange[ExchangeID].status = TARGET_ABORT;
+
+							// copy (add) rx_id field for simplified ACCept reply
+							fchs->ox_rx_id = Exchanges->fcExchange[ExchangeID].fchs.ox_rx_id;
+
+							cpqfcTSPutLinkQue(dev, BLS_ABTS_ACC,	// Q Type 
+									  fchs);	// void QueContent
+							AbortAccept = 1;
+							printk("ACCepting ABTS for x_ID %8.8Xh, SEST pair %8.8Xh\n", fchs->ox_rx_id, Exchanges->fcExchange[ExchangeID].fchs.ox_rx_id);
+							break;	// ABTS can affect only ONE exchange -exit loop
+						}
+					}
+				}	// end of FOR loop
+				if (!AbortAccept)	// can't ACCept ABTS - send Reject
+				{
+					printk("ReJecTing: can't find ExchangeID %8.8Xh for ABTS command\n", fchs->ox_rx_id);
+					if (Exchanges->fcExchange[ExchangeID].type && !(fcChip->SEST->u[ExchangeID].IWE.Hdr_Len & 0x80000000)) {
+						cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+					} else {
+						printk("Unexpected ABTS ReJecT! SEST[%X] Dword 0: %Xh\n", ExchangeID, fcChip->SEST->u[ExchangeID].IWE.Hdr_Len);
+					}
+				}
+			}
+			// Check for BLS {ABTS? (Abort Sequence)} ACCept
+			else if ((fchs->d_id & 0x8F000000) == 0x84000000) {
+				// target has responded with ACC for our ABTS;
+				// complete the indicated exchange with ABORTED status 
+				// Make no checks for correct RX_ID, since
+				// all we need to conform ABTS ACC is the OX_ID.
+				// Verify that the d_id matches!
 
-      // Check for ABTS (Abort Sequence)
-      if( (fchs->d_id & 0x8F000000) == 0x81000000)
-      {
-        // look for OX_ID, S_ID pair that matches in our
-        // fcExchanges table; if found, reply with ACCept and complete
-        // the exchange
-
-        // Per PLDA, an ABTS is sent by an initiator; therefore
-        // assume that if we have an exhange open to the port who
-        // sent ABTS, it will be the d_id of what we sent.  
-        for( ExchangeID = 0, AbortAccept=FALSE;
-             ExchangeID < TACH_SEST_LEN; ExchangeID++)
-        {
-            // Valid "target" exchange 24-bit port_id matches? 
-            // NOTE: For the case of handling Intiator AND Target
-            // functions on the same chip, we can have TWO Exchanges
-            // with the same OX_ID -- OX_ID/FFFF for the CMND, and
-            // OX_ID/RX_ID for the XRDY or DATA frame(s).  Ideally,
-            // we would like to support ABTS from Initiators or Targets,
-            // but it's not clear that can be supported on Tachyon for
-            // all cases (requires more investigation).
-            
-          if( (Exchanges->fcExchange[ ExchangeID].type == SCSI_TWE ||
-               Exchanges->fcExchange[ ExchangeID].type == SCSI_TRE)
-                  &&
-             ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
-             (fchs->s_id & 0xFFFFFF)) )
-          {
-              
-              // target xchnge port_id matches -- how about OX_ID?
-            if( (Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id &0xFFFF0000)
-                    == (fchs->ox_rx_id & 0xFFFF0000) )
-                    // yes! post ACCept response; will be completed by fcStart
-            {
-              Exchanges->fcExchange[ ExchangeID].status = TARGET_ABORT;
-                
-                // copy (add) rx_id field for simplified ACCept reply
-              fchs->ox_rx_id = 
-                Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id;
-                
-              cpqfcTSPutLinkQue( cpqfcHBAdata,
-                            BLS_ABTS_ACC, // Q Type 
-                            fchs );    // void QueContent
-              AbortAccept = TRUE;
-      printk("ACCepting ABTS for x_ID %8.8Xh, SEST pair %8.8Xh\n", 
-             fchs->ox_rx_id, Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id);
-              break;      // ABTS can affect only ONE exchange -exit loop
-            }
-          }
-        }  // end of FOR loop
-        if( !AbortAccept ) // can't ACCept ABTS - send Reject
-        {
-      printk("ReJecTing: can't find ExchangeID %8.8Xh for ABTS command\n", 
-            fchs->ox_rx_id);
-          if( Exchanges->fcExchange[ ExchangeID].type 
-                &&
-              !(fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len
-               & 0x80000000))
-          {
-            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
-          }
-          else
-          {
-            printk("Unexpected ABTS ReJecT! SEST[%X] Dword 0: %Xh\n", 
-              ExchangeID, fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len);
-          }
-        }
-      }
-
-      // Check for BLS {ABTS? (Abort Sequence)} ACCept
-      else if( (fchs->d_id & 0x8F000000) == 0x84000000)
-      {
-        // target has responded with ACC for our ABTS;
-	// complete the indicated exchange with ABORTED status 
-        // Make no checks for correct RX_ID, since
-	// all we need to conform ABTS ACC is the OX_ID.
-        // Verify that the d_id matches!
- 
-        ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
-//	printk("ABTS ACC x_ID 0x%04X 0x%04X, status %Xh\n", 
+				ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF;	// x_id from ACC
+//      printk("ABTS ACC x_ID 0x%04X 0x%04X, status %Xh\n", 
 //          fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff,
 //          Exchanges->fcExchange[ExchangeID].status);
+				if (ExchangeID < TACH_SEST_LEN)	// x_ID makes sense
+				{
+					// Does "target" exchange 24-bit port_id match? 
+					// (See "NOTE" above for handling Intiator AND Target in
+					// the same device driver)
+					// First, if this is a target response, then we originated
+					// (initiated) it with BLS_ABTS:
+
+					if ((Exchanges->fcExchange[ExchangeID].type == BLS_ABTS) &&
+					    // Second, does the source of this ACC match the destination
+					    // of who we originally sent it to?
+					    ((Exchanges->fcExchange[ExchangeID].fchs.d_id & 0xFFFFFF) == (fchs->s_id & 0xFFFFFF))) {
+						cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+					}
+				}
+			}
+			// Check for BLS {ABTS? (Abort Sequence)} ReJecT
+			else if ((fchs->d_id & 0x8F000000) == 0x85000000) {
+				// target has responded with RJT for our ABTS;
+				// complete the indicated exchange with ABORTED status 
+				// Make no checks for correct RX_ID, since
+				// all we need to conform ABTS ACC is the OX_ID.
+				// Verify that the d_id matches!
+
+				ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF;	// x_id from ACC
+//				printk("BLS_ABTS RJT on Exchange 0x%04X 0x%04X\n", 
+//					fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff);
+
+				if (ExchangeID < TACH_SEST_LEN)	// x_ID makes sense
+				{
+					// Does "target" exchange 24-bit port_id match? 
+					// (See "NOTE" above for handling Intiator AND Target in
+					// the same device driver)
+					// First, if this is a target response, then we originated
+					// (initiated) it with BLS_ABTS:
+
+					if ((Exchanges->fcExchange[ExchangeID].type == BLS_ABTS)
+
+					    &&
+					    // Second, does the source of this ACC match the destination
+					    // of who we originally sent it to?
+					    ((Exchanges->fcExchange[ExchangeID].fchs.d_id & 0xFFFFFF) == (fchs->s_id & 0xFFFFFF))) {
+						// YES! NOTE: There is a bug in CPQ's RA-4000 box 
+						// where the "reason code" isn't returned in the payload
+						// For now, simply presume the reject is because the target
+						// already completed the exchange...
+
+//						printk("complete x_ID %Xh on ABTS RJT\n", ExchangeID);
+						cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+					}
+				}
+			}	// end of ABTS check
+		}		// end of Basic Link Service Request
+		break;
 
-
-	
-        if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
-        {
-            // Does "target" exchange 24-bit port_id match? 
-            // (See "NOTE" above for handling Intiator AND Target in
-            // the same device driver)
-            // First, if this is a target response, then we originated
-	    // (initiated) it with BLS_ABTS:
-	  
-          if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
-
-                  &&
-	    // Second, does the source of this ACC match the destination
-            // of who we originally sent it to?
-             ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
-             (fchs->s_id & 0xFFFFFF)) )
-          {
-            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID );
-	  }
-        }              
-      }
-      // Check for BLS {ABTS? (Abort Sequence)} ReJecT
-      else if( (fchs->d_id & 0x8F000000) == 0x85000000)
-      {
-        // target has responded with RJT for our ABTS;
-	// complete the indicated exchange with ABORTED status 
-        // Make no checks for correct RX_ID, since
-	// all we need to conform ABTS ACC is the OX_ID.
-        // Verify that the d_id matches!
- 
-        ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
-//	printk("BLS_ABTS RJT on Exchange 0x%04X 0x%04X\n", 
-//          fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff);
-
-        if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
-	{  
-            // Does "target" exchange 24-bit port_id match? 
-            // (See "NOTE" above for handling Intiator AND Target in
-            // the same device driver)
-            // First, if this is a target response, then we originated
-	    // (initiated) it with BLS_ABTS:
-		  
-          if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
-
-                  &&
-	    // Second, does the source of this ACC match the destination
-            // of who we originally sent it to?
-             ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
-             (fchs->s_id & 0xFFFFFF)) )
-          {
-	    // YES! NOTE: There is a bug in CPQ's RA-4000 box 
-	    // where the "reason code" isn't returned in the payload
-	    // For now, simply presume the reject is because the target
-	    // already completed the exchange...
-	    
-//            printk("complete x_ID %Xh on ABTS RJT\n", ExchangeID);
-            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID );
-	  }
-	} 
-      }  // end of ABTS check
-    }  // end of Basic Link Service Request
-    break;
-  
-    default:
-      printk("AnalyzeIncomingFrame: unknown type: %Xh(%d)\n",
-        fcLQ->Qitem[QNdx].Type,
-        fcLQ->Qitem[QNdx].Type);
-    break;
-  }
+	default:
+		printk("AnalyzeIncomingFrame: unknown type: %Xh(%d)\n", fcLQ->Qitem[QNdx].Type, fcLQ->Qitem[QNdx].Type);
+		break;
+	}
 }
 
 
@@ -2428,506 +1868,433 @@
 // initialization (e.g. LIP).
 // Also may be called if from Fabric Name Service logic.
 
-static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds )
+static void SendLogins(CPQFCHBA * dev, __u32 * FabricPortIds)
 {
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG ulStatus=0;
-  TachFCHDR_GCMND fchs;  // copy fields for transmission
-  int i;
-  ULONG loginType;
-  LONG ExchangeID;
-  PFC_LOGGEDIN_PORT pLoggedInPort;
-  __u32 PortIds[ number_of_al_pa];
-  int NumberOfPorts=0;
-
-  // We're going to presume (for now) that our limit of Fabric devices
-  // is the same as the number of alpa on a private loop (126 devices).
-  // (Of course this could be changed to support however many we have
-  // memory for).
-  memset( &PortIds[0], 0, sizeof(PortIds));
-   
-  // First, check if this login is for our own Link Initialization
-  // (e.g. LIP on FC-AL), or if we have knowledge of Fabric devices
-  // from a switch.  If we are logging into Fabric devices, we'll
-  // have a non-NULL FabricPortId pointer
-  
-  if( FabricPortIds != NULL) // may need logins
-  {
-    int LastPort=FALSE;
-    i = 0;
-    while( !LastPort)
-    {
-      // port IDs From NSR payload; byte swap needed?
-      BigEndianSwap( (UCHAR*)FabricPortIds, (UCHAR*)&PortIds[i], 4);
- 
-//      printk("FPortId[%d] %Xh ", i, PortIds[i]);
-      if( PortIds[i] & 0x80000000)
-	LastPort = TRUE;
-      
-      PortIds[i] &= 0xFFFFFF; // get 24-bit port_id
-      // some non-Fabric devices (like the Crossroads Fibre/Scsi bridge)
-      // erroneously use ALPA 0.
-      if( PortIds[i]  ) // need non-zero port_id...
-        i++;
-      
-      if( i >= number_of_al_pa ) // (in)sanity check
-	break;
-      FabricPortIds++;  // next...
-    }
-
-    NumberOfPorts = i;
-//    printk("NumberOf Fabric ports %d", NumberOfPorts);
-  }
-  
-  else  // need to send logins on our "local" link
-  {
-  
-    // are we a loop port?  If so, check for reception of LILP frame,
-    // and if received use it (SANMark requirement)
-    if( fcChip->Options.LILPin )
-    {
-      int j=0;
-      // sanity check on number of ALPAs from LILP frame...
-      // For format of LILP frame, see FC-AL specs or 
-      // "Fibre Channel Bench Reference", J. Stai, 1995 (ISBN 1-879936-17-8)
-      // First byte is number of ALPAs
-      i = fcChip->LILPmap[0] >= (32*4) ? 32*4 : fcChip->LILPmap[0];
-      NumberOfPorts = i;
-//      printk(" LILP alpa count %d ", i);
-      while( i > 0)
-      {
-	PortIds[j] = fcChip->LILPmap[1+ j];
-	j++; i--;
-      }
-    }
-    else  // have to send login to everybody
-    {
-      int j=0;
-      i = number_of_al_pa;
-      NumberOfPorts = i;
-      while( i > 0)
-      {
-        PortIds[j] = valid_al_pa[j]; // all legal ALPAs
-	j++; i--;
-      }
-    }
-  }
-
-
-  // Now we have a copy of the port_ids (and how many)...
-  for( i = 0; i < NumberOfPorts; i++)
-  {
-    // 24-bit FC Port ID
-    fchs.s_id = PortIds[i];  // note: only 8-bits used for ALPA
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 ulStatus = 0;
+	TachFCHDR_GCMND fchs;	// copy fields for transmission
+	int i;
+	u32 loginType;
+	s32 ExchangeID;
+	PFC_LOGGEDIN_PORT pLoggedInPort;
+	__u32 PortIds[number_of_al_pa];
+	int NumberOfPorts = 0;
+
+	// We're going to presume (for now) that our limit of Fabric devices
+	// is the same as the number of alpa on a private loop (126 devices).
+	// (Of course this could be changed to support however many we have
+	// memory for).
+	memset(&PortIds[0], 0, sizeof(PortIds));
+
+	// First, check if this login is for our own Link Initialization
+	// (e.g. LIP on FC-AL), or if we have knowledge of Fabric devices
+	// from a switch.  If we are logging into Fabric devices, we'll
+	// have a non-NULL FabricPortId pointer
 
-
-    // don't log into ourselves (Linux Scsi disk scan will stop on
-    // no TARGET support error on us, and quit trying for rest of devices)
-    if( (fchs.s_id & 0xFF ) == (fcChip->Registers.my_al_pa & 0xFF) )
-      continue;
-
-    // fabric login needed?
-    if( (fchs.s_id == 0) || 
-        (fcChip->Options.fabric == 1) )
-    {
-      fcChip->Options.flogi = 1;  // fabric needs longer for login
-      // Do we need FLOGI or FDISC?
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-             NULL,           // don't search SCSI Nexus
-             0xFFFFFC,       // search linked list for Fabric port_id
-             NULL,           // don't search WWN
-             NULL);          // (don't care about end of list)
-
-      if( pLoggedInPort )    // If found, we have prior experience with
-                             // this port -- check whether PDISC is needed
-      {
-        if( pLoggedInPort->flogi )
+	if (FabricPortIds != NULL)	// may need logins
 	{
-	  // does the switch support FDISC?? (FLOGI for now...)
-          loginType = ELS_FLOGI;  // prior FLOGI still valid
-	}
-        else
-          loginType = ELS_FLOGI;  // expired FLOGI
-      }
-      else                      // first FLOGI?
-        loginType = ELS_FLOGI;  
-
-
-      fchs.s_id = 0xFFFFFE;   // well known F_Port address
-
-      // Fabrics are not required to support FDISC, and
-      // it's not clear if that helps us anyway, since
-      // we'll want a Name Service Request to re-verify
-      // visible devices...
-      // Consequently, we always want our upper 16 bit
-      // port_id to be zero (we'll be rejected if we
-      // use our prior port_id if we've been plugged into
-      // a different switch port).
-      // Trick Tachyon to send to ALPA 0 (see TL/TS UG, pg 87)
-      // If our ALPA is 55h for instance, we want the FC frame
-      // s_id to be 0x000055, while Tach's my_al_pa register
-      // must be 0x000155, to force an OPN at ALPA 0 
-      // (the Fabric port)
-      fcChip->Registers.my_al_pa &= 0xFF; // only use ALPA for FLOGI
-      writel( fcChip->Registers.my_al_pa | 0x0100,  
-        fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
-    }
+		int LastPort = 0;
+		i = 0;
+		while (!LastPort) {
+			// port IDs From NSR payload; byte swap needed?
+			BigEndianSwap((u8 *) FabricPortIds, (u8 *) & PortIds[i], 4);
+
+//			printk("FPortId[%d] %Xh ", i, PortIds[i]);
+			if (PortIds[i] & 0x80000000)
+				LastPort = 1;
+
+			PortIds[i] &= 0xFFFFFF;	// get 24-bit port_id
+			// some non-Fabric devices (like the Crossroads Fibre/Scsi bridge)
+			// erroneously use ALPA 0.
+			if (PortIds[i])	// need non-zero port_id...
+				i++;
+
+			if (i >= number_of_al_pa)	// (in)sanity check
+				break;
+			FabricPortIds++;	// next...
+		}
 
-    else // not FLOGI...
-    {
-      // should we send PLOGI or PDISC?  Check if any prior port_id
-      // (e.g. alpa) completed a PLOGI/PRLI exchange by checking 
-      // the pdisc flag.
-
-      pLoggedInPort = fcFindLoggedInPort( 
-             fcChip, 
-             NULL,           // don't search SCSI Nexus
-             fchs.s_id,      // search linked list for al_pa
-             NULL,           // don't search WWN
-             NULL);          // (don't care about end of list)
-
-             
-
-      if( pLoggedInPort )      // If found, we have prior experience with
-                             // this port -- check whether PDISC is needed
-      {
-        if( pLoggedInPort->pdisc )
+		NumberOfPorts = i;
+//    printk("NumberOf Fabric ports %d", NumberOfPorts);
+	}
+	else			// need to send logins on our "local" link
 	{
-          loginType = ELS_PDISC;  // prior PLOGI and PRLI maybe still valid
-           
+		// are we a loop port?  If so, check for reception of LILP frame,
+		// and if received use it (SANMark requirement)
+		if (fcChip->Options.LILPin) {
+			int j = 0;
+			// sanity check on number of ALPAs from LILP frame...
+			// For format of LILP frame, see FC-AL specs or 
+			// "Fibre Channel Bench Reference", J. Stai, 1995 (ISBN 1-879936-17-8)
+			// First byte is number of ALPAs
+			i = fcChip->LILPmap[0] >= (32 * 4) ? 32 * 4 : fcChip->LILPmap[0];
+			NumberOfPorts = i;
+//			printk(" LILP alpa count %d ", i);
+			while (i > 0) {
+				PortIds[j] = fcChip->LILPmap[1 + j];
+				j++;
+				i--;
+			}
+		}
+		else		// have to send login to everybody
+		{
+			int j = 0;
+			i = number_of_al_pa;
+			NumberOfPorts = i;
+			while (i > 0) {
+				PortIds[j] = valid_al_pa[j];	// all legal ALPAs
+				j++;
+				i--;
+			}
+		}
 	}
-        else
-          loginType = ELS_PLOGI;  // prior knowledge, but can't use PDISC
-      }
-      else                      // never talked to this port_id before
-        loginType = ELS_PLOGI;  // prior knowledge, but can't use PDISC
-    }
-
-
-    
-    ulStatus = cpqfcTSBuildExchange(
-          cpqfcHBAdata,
-          loginType,            // e.g. PLOGI
-          &fchs,        // no incoming frame (we are originator)
-          NULL,         // no data (no scatter/gather list)
-          &ExchangeID );// fcController->fcExchanges index, -1 if failed
 
-    if( !ulStatus ) // Exchange setup OK?
-    {
-      ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
-      if( !ulStatus )
-      {
-          // submitted to Tach's Outbound Que (ERQ PI incremented)
-          // waited for completion for ELS type (Login frames issued
-          // synchronously)
+	// Now we have a copy of the port_ids (and how many)...
+	for (i = 0; i < NumberOfPorts; i++) {
+		// 24-bit FC Port ID
+		fchs.s_id = PortIds[i];	// note: only 8-bits used for ALPA
+		// don't log into ourselves (Linux Scsi disk scan will stop on
+		// no TARGET support error on us, and quit trying for rest of devices)
+		if ((fchs.s_id & 0xFF) == (fcChip->Registers.my_al_pa & 0xFF))
+			continue;
+		// fabric login needed?
+		if ((fchs.s_id == 0) || (fcChip->Options.fabric == 1)) {
+			fcChip->Options.flogi = 1;	// fabric needs longer for login
+			// Do we need FLOGI or FDISC?
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search SCSI Nexus
+							   0xFFFFFC,	// search linked list for Fabric port_id
+							   NULL,	// don't search WWN
+							   NULL);	// (don't care about end of list)
+
+			if (pLoggedInPort)	// If found, we have prior experience with
+				// this port -- check whether PDISC is needed
+			{
+				if (pLoggedInPort->flogi) {
+					// does the switch support FDISC?? (FLOGI for now...)
+					loginType = ELS_FLOGI;	// prior FLOGI still valid
+				} else
+					loginType = ELS_FLOGI;	// expired FLOGI
+			} else	// first FLOGI?
+				loginType = ELS_FLOGI;
+
+			fchs.s_id = 0xFFFFFE;	// well known F_Port address
+
+			// Fabrics are not required to support FDISC, and
+			// it's not clear if that helps us anyway, since
+			// we'll want a Name Service Request to re-verify
+			// visible devices...
+			// Consequently, we always want our upper 16 bit
+			// port_id to be zero (we'll be rejected if we
+			// use our prior port_id if we've been plugged into
+			// a different switch port).
+			// Trick Tachyon to send to ALPA 0 (see TL/TS UG, pg 87)
+			// If our ALPA is 55h for instance, we want the FC frame
+			// s_id to be 0x000055, while Tach's my_al_pa register
+			// must be 0x000155, to force an OPN at ALPA 0 
+			// (the Fabric port)
+			fcChip->Registers.my_al_pa &= 0xFF;	// only use ALPA for FLOGI
+			writel(fcChip->Registers.my_al_pa | 0x0100, fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
+		}
+		else		// not FLOGI...
+		{
+			// should we send PLOGI or PDISC?  Check if any prior port_id
+			// (e.g. alpa) completed a PLOGI/PRLI exchange by checking 
+			// the pdisc flag.
+
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// don't search SCSI Nexus
+							   fchs.s_id,	// search linked list for al_pa
+							   NULL,	// don't search WWN
+							   NULL);	// (don't care about end of list)
+
+			if (pLoggedInPort)	// If found, we have prior experience with
+				// this port -- check whether PDISC is needed
+			{
+				if (pLoggedInPort->pdisc) {
+					loginType = ELS_PDISC;	// prior PLOGI and PRLI maybe still valid
+				} else
+					loginType = ELS_PLOGI;	// prior knowledge, but can't use PDISC
+			} else	// never talked to this port_id before
+				loginType = ELS_PLOGI;	// prior knowledge, but can't use PDISC
+		}
 
-	if( loginType == ELS_PDISC )
-	{
-	  // now, we really shouldn't Revalidate SEST exchanges until
-	  // we get an ACC reply from our target and verify that
-	  // the target address/WWN is unchanged.  However, when a fast
-	  // target gets the PDISC, they can send SEST Exchange data
-	  // before we even get around to processing the PDISC ACC.
-	  // Consequently, we lose the I/O.
-	  // To avoid this, go ahead and Revalidate when the PDISC goes
-	  // out, anticipating that the ACC will be truly acceptable
-	  // (this happens 99.9999....% of the time).
-	  // If we revalidate a SEST write, and write data goes to a
-	  // target that is NOT the one we originated the WRITE to,
-	  // that target is required (FCP-SCSI specs, etc) to discard 
-	  // our WRITE data.
-
-          // Re-validate SEST entries (Tachyon hardware assists)
-          RevalidateSEST( cpqfcHBAdata->HostAdapter, pLoggedInPort); 
-    //TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
-	}
-      }
-      else  // give up immediately on error
-      {
+		ulStatus = cpqfcTSBuildExchange(dev, loginType,	// e.g. PLOGI
+						&fchs,	// no incoming frame (we are originator)
+						NULL,	// no data (no scatter/gather list)
+						&ExchangeID);	// fcController->fcExchanges index, -1 if failed
+
+		if (!ulStatus)	// Exchange setup OK?
+		{
+			ulStatus = cpqfcTSStartExchange(dev, ExchangeID);
+			if (!ulStatus) {
+				// submitted to Tach's Outbound Que (ERQ PI incremented)
+				// waited for completion for ELS type (Login frames issued
+				// synchronously)
+
+				if (loginType == ELS_PDISC) {
+					// now, we really shouldn't Revalidate SEST exchanges until
+					// we get an ACC reply from our target and verify that
+					// the target address/WWN is unchanged.  However, when a fast
+					// target gets the PDISC, they can send SEST Exchange data
+					// before we even get around to processing the PDISC ACC.
+					// Consequently, we lose the I/O.
+					// To avoid this, go ahead and Revalidate when the PDISC goes
+					// out, anticipating that the ACC will be truly acceptable
+					// (this happens 99.9999....% of the time).
+					// If we revalidate a SEST write, and write data goes to a
+					// target that is NOT the one we originated the WRITE to,
+					// that target is required (FCP-SCSI specs, etc) to discard 
+					// our WRITE data.
+
+					// Re-validate SEST entries (Tachyon hardware assists)
+					RevalidateSEST(dev->HostAdapter, pLoggedInPort);
+					//TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
+				}
+			} else	// give up immediately on error
+			{
 #ifdef LOGIN_DBG
-        printk("SendLogins: fcStartExchange failed: %Xh\n", ulStatus );
+				printk("SendLogins: fcStartExchange failed: %Xh\n", ulStatus);
 #endif
-        break;
-      }
+				break;
+			}
+
 
-              
-      if( fcChip->Registers.FMstatus.value & 0x080 ) // LDn during Port Disc.
-      {
-        ulStatus = LNKDWN_OSLS;
+			if (fcChip->Registers.FMstatus.value & 0x080)	// LDn during Port Disc.
+			{
+				ulStatus = LNKDWN_OSLS;
 #ifdef LOGIN_DBG
-        printk("SendLogins: PortDisc aborted (LDn) @alpa %Xh\n", fchs.s_id);
+				printk("SendLogins: PortDisc aborted (LDn) @alpa %Xh\n", fchs.s_id);
 #endif
-        break;
-      }
-        // Check the exchange for bad status (i.e. FrameTimeOut),
-        // and complete on bad status (most likely due to BAD_ALPA)
-        // on LDn, DPC function may already complete (ABORT) a started
-        // exchange, so check type first (type = 0 on complete).
-      if( Exchanges->fcExchange[ExchangeID].status )
-      {
-#ifdef LOGIN_DBG 
- 	printk("completing x_ID %X on status %Xh\n", 
-          ExchangeID, Exchanges->fcExchange[ExchangeID].status);
+				break;
+			}
+			// Check the exchange for bad status (i.e. FrameTimeOut),
+			// and complete on bad status (most likely due to BAD_ALPA)
+			// on LDn, DPC function may already complete (ABORT) a started
+			// exchange, so check type first (type = 0 on complete).
+			if (Exchanges->fcExchange[ExchangeID].status) {
+#ifdef LOGIN_DBG
+				printk("completing x_ID %X on status %Xh\n", ExchangeID, Exchanges->fcExchange[ExchangeID].status);
 #endif
-        cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
-      }
-    }
-    else   // Xchange setup failed...
-    {
+				cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+			}
+		} else		// Xchange setup failed...
+		{
 #ifdef LOGIN_DBG
-      printk("FC: cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
+			printk("FC: cpqfcTSBuildExchange failed: %Xh\n", ulStatus);
 #endif
-      break;
-    }
-  }
-  if( !ulStatus )
-  {
-    // set the event signifying that all ALPAs were sent out.
+			break;
+		}
+	}
+	if (!ulStatus) {
+		// set the event signifying that all ALPAs were sent out.
 #ifdef LOGIN_DBG
-    printk("SendLogins: PortDiscDone\n");
+		printk("SendLogins: PortDiscDone\n");
 #endif
-    cpqfcHBAdata->PortDiscDone = 1;
-
-
-    // TL/TS UG, pg. 184
-    // 0x0065 = 100ms for RT_TOV
-    // 0x01f5 = 500ms for ED_TOV
-    fcChip->Registers.ed_tov.value = 0x006501f5L; 
-    writel( fcChip->Registers.ed_tov.value,
-      (fcChip->Registers.ed_tov.address));
-
-    // set the LP_TOV back to ED_TOV (i.e. 500 ms)
-    writel( 0x00000010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
-  }
-  else
-  {
-    printk("SendLogins: failed at xchng %Xh, alpa %Xh, status %Xh\n", 
-      ExchangeID, fchs.s_id, ulStatus);
-  }
-  LEAVE("SendLogins");
+		dev->PortDiscDone = 1;
+		// TL/TS UG, pg. 184
+		// 0x0065 = 100ms for RT_TOV
+		// 0x01f5 = 500ms for ED_TOV
+		fcChip->Registers.ed_tov.value = 0x006501f5L;
+		writel(fcChip->Registers.ed_tov.value, (fcChip->Registers.ed_tov.address));
+
+		// set the LP_TOV back to ED_TOV (i.e. 500 ms)
+		writel(0x00000010, fcChip->Registers.ReMapMemBase + TL_MEM_FM_TIMEOUT2);
+	} else {
+		printk("SendLogins: failed at xchng %Xh, alpa %Xh, status %Xh\n", ExchangeID, fchs.s_id, ulStatus);
+	}
+	LEAVE("SendLogins");
 
 }
 
-
 // for REPORT_LUNS documentation, see "In-Depth Exploration of Scsi",
 // D. Deming, 1994, pg 7-19 (ISBN 1-879936-08-9)
-static void ScsiReportLunsDone(Scsi_Cmnd *Cmnd)
+static void ScsiReportLunsDone(Scsi_Cmnd * Cmnd)
 {
-  struct Scsi_Host *HostAdapter = Cmnd->host;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PFC_LOGGEDIN_PORT pLoggedInPort; 
-  int LunListLen=0;
-  int i;
-  ULONG x_ID = 0xFFFFFFFF;
-  UCHAR *ucBuff = Cmnd->request_buffer;
-
-//  printk("cpqfcTS: ReportLunsDone \n");
-  // first, we need to find the Exchange for this command,
-  // so we can find the fcPort struct to make the indicated
-  // changes.
-  for( i=0; i< TACH_SEST_LEN; i++)
-  {
-    if( Exchanges->fcExchange[i].type   // exchange defined?
-                   &&
-       (Exchanges->fcExchange[i].Cmnd == Cmnd) ) // matches?
-	      
-    {
-      x_ID = i;  // found exchange!
-      break;
-    }
-  }
-  if( x_ID == 0xFFFFFFFF)
-  {
-//    printk("cpqfcTS: ReportLuns failed - no FC Exchange\n");
-    goto Done;  // Report Luns FC Exchange gone; 
-                // exchange probably Terminated by Implicit logout
-  }
+	struct Scsi_Host *shpnt = Cmnd->host;
+	CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	PFC_LOGGEDIN_PORT pLoggedInPort;
+	int LunListLen = 0;
+	int i;
+	u32 x_ID = 0xFFFFFFFF;
+	u8 *ucBuff = Cmnd->request_buffer;
+
+	//  printk("cpqfcTS: ReportLunsDone \n");
+	// first, we need to find the Exchange for this command,
+	// so we can find the fcPort struct to make the indicated
+	// changes.
+	for (i = 0; i < TACH_SEST_LEN; i++) {
+		if (Exchanges->fcExchange[i].type	// exchange defined?
+		    && (Exchanges->fcExchange[i].Cmnd == Cmnd))	// matches?
+
+		{
+			x_ID = i;	// found exchange!
+			break;
+		}
+	}
+	if (x_ID == 0xFFFFFFFF) {
+//		printk("cpqfcTS: ReportLuns failed - no FC Exchange\n");
+		goto Done;	// Report Luns FC Exchange gone; 
+		// exchange probably Terminated by Implicit logout
+	}
 
+	// search linked list for the port_id we sent INQUIRY to
+	pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// DON'T search Scsi Nexus (we will set it)
+					   Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF, NULL,	// DON'T search linked list for FC WWN
+					   NULL);	// DON'T care about end of list
+
+	if (!pLoggedInPort) {
+//		printk("cpqfcTS: ReportLuns failed - device gone\n");
+		goto Done;	// error! can't find logged in Port
+	}
+	LunListLen = ucBuff[3];
+	LunListLen += ucBuff[2] >> 8;
 
-  // search linked list for the port_id we sent INQUIRY to
-  pLoggedInPort = fcFindLoggedInPort( fcChip,
-    NULL,     // DON'T search Scsi Nexus (we will set it)
-    Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,        
-    NULL,     // DON'T search linked list for FC WWN
-    NULL);    // DON'T care about end of list
- 
-  if( !pLoggedInPort )
-  {
-//    printk("cpqfcTS: ReportLuns failed - device gone\n");
-    goto Done; // error! can't find logged in Port
-  }    
-  LunListLen = ucBuff[3];
-  LunListLen += ucBuff[2]>>8;
+	if (!LunListLen)	// failed
+	{
+		// generically speaking, a soft error means we should retry...
+		if ((Cmnd->result >> 16) == DID_SOFT_ERROR) {
+			if (((Cmnd->sense_buffer[2] & 0xF) == 0x6) && (Cmnd->sense_buffer[12] == 0x29))	// Sense Code "reset"
+			{
+				TachFCHDR_GCMND *fchs = &Exchanges->fcExchange[x_ID].fchs;
+				// did we fail because of "check condition, device reset?"
+				// e.g. the device was reset (i.e., at every power up)
+				// retry the Report Luns
+
+				// who are we sending it to?
+				// we know this because we have a copy of the command
+				// frame from the original Report Lun command -
+				// switch the d_id/s_id fields, because the Exchange Build
+				// context is "reply to source".
 
-  if( !LunListLen )  // failed
-  {
-    // generically speaking, a soft error means we should retry...
-    if( (Cmnd->result >> 16) == DID_SOFT_ERROR )
-    {
-      if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
-	        (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
-      {
-        TachFCHDR_GCMND *fchs = &Exchanges->fcExchange[ x_ID].fchs;
-      // did we fail because of "check condition, device reset?"
-      // e.g. the device was reset (i.e., at every power up)
-      // retry the Report Luns
-      
-      // who are we sending it to?
-      // we know this because we have a copy of the command
-      // frame from the original Report Lun command -
-      // switch the d_id/s_id fields, because the Exchange Build
-      // context is "reply to source".
-      
-        fchs->s_id = fchs->d_id; // (temporarily re-use the struct)
-        cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
-      }
-    }
-    else  // probably, the device doesn't support Report Luns
-      pLoggedInPort->ScsiNexus.VolumeSetAddressing = 0;  
-  }
-  else  // we have LUN info - check VSA mode
-  {
-    // for now, assume all LUNs will have same addr mode
-    // for VSA, payload byte 8 will be 0x40; otherwise, 0
-    pLoggedInPort->ScsiNexus.VolumeSetAddressing = ucBuff[8];  
-      
-    // Since we got a Report Luns answer, set lun masking flag
-    pLoggedInPort->ScsiNexus.LunMasking = 1;
+				fchs->s_id = fchs->d_id;	// (temporarily re-use the struct)
+				cpqfcTSPutLinkQue(dev, SCSI_REPORT_LUNS, fchs);
+			}
+		} else		// probably, the device doesn't support Report Luns
+			pLoggedInPort->ScsiNexus.VolumeSetAddressing = 0;
+	} else			// we have LUN info - check VSA mode
+	{
+		// for now, assume all LUNs will have same addr mode
+		// for VSA, payload byte 8 will be 0x40; otherwise, 0
+		pLoggedInPort->ScsiNexus.VolumeSetAddressing = ucBuff[8];
 
-    if( LunListLen > 8*CPQFCTS_MAX_LUN)   // We expect CPQFCTS_MAX_LUN max
-      LunListLen = 8*CPQFCTS_MAX_LUN;
+		// Since we got a Report Luns answer, set lun masking flag
+		pLoggedInPort->ScsiNexus.LunMasking = 1;
+
+		if (LunListLen > 8 * CPQFCTS_MAX_LUN)	// We expect CPQFCTS_MAX_LUN max
+			LunListLen = 8 * CPQFCTS_MAX_LUN;
 
 /*   
-    printk("Device WWN %08X%08X Reports Luns @: ", 
-          (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF), 
-          (ULONG)(pLoggedInPort->u.liWWN>>32));
+		printk("Device WWN %08X%08X Reports Luns @: ", 
+			(u32)(pLoggedInPort->u.liWWN &0xFFFFFFFF), 
+			(u32)(pLoggedInPort->u.liWWN>>32));
 	    
-    for( i=8; i<LunListLen+8; i+=8)
-    {  
-      printk("%02X%02X ", ucBuff[i], ucBuff[i+1] );
-    }
-    printk("\n");
+		for( i=8; i<LunListLen+8; i+=8)
+		{  
+			printk("%02X%02X ", ucBuff[i], ucBuff[i+1] );
+		}
+		printk("\n");
 */
-    
-    // Since the device was kind enough to tell us where the
-    // LUNs are, lets ensure they are contiguous for Linux's
-    // SCSI driver scan, which expects them to start at 0.
-    // Since Linux only supports 8 LUNs, only copy the first
-    // eight from the report luns command
-
-    // e.g., the Compaq RA4x00 f/w Rev 2.54 and above may report
-    // LUNs 4001, 4004, etc., because other LUNs are masked from
-    // this HBA (owned by someone else).  We'll make those appear as
-    // LUN 0, 1... to Linux
-    {
-      int j;
-      int AppendLunList = 0;
-      // Walk through the LUN list.  The 'j' array number is
-      // Linux's lun #, while the value of .lun[j] is the target's
-      // lun #.
-      // Once we build a LUN list, it's possible for a known device 
-      // to go offline while volumes (LUNs) are added.  Later,
-      // the device will do another PLOGI ... Report Luns command,
-      // and we must not alter the existing Linux Lun map.
-      // (This will be very rare).
-      for( j=0; j < CPQFCTS_MAX_LUN; j++)
-      {
-        if( pLoggedInPort->ScsiNexus.lun[j] != 0xFF )
-	{
-	  AppendLunList = 1;
-	  break;
-	}
-      }
-      if( AppendLunList )
-      {
-	int k;
-        int FreeLunIndex;
-//        printk("cpqfcTS: AppendLunList\n");
-
-	// If we get a new Report Luns, we cannot change
-	// any existing LUN mapping! (Only additive entry)
-	// For all LUNs in ReportLun list
-	// if RL lun != ScsiNexus lun
-	//   if RL lun present in ScsiNexus lun[], continue
-	//   else find ScsiNexus lun[]==FF and add, continue
-	
-        for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
-	{
-          if( pLoggedInPort->ScsiNexus.lun[j] != ucBuff[i+1] )
-	  {
-	    // something changed from the last Report Luns
-	    printk(" cpqfcTS: Report Lun change!\n");
-	    for( k=0, FreeLunIndex=CPQFCTS_MAX_LUN; 
-                 k < CPQFCTS_MAX_LUN; k++)
-            {
-	      if( pLoggedInPort->ScsiNexus.lun[k] == 0xFF)
-	      {
-		FreeLunIndex = k;
-		break;
-	      }
-              if( pLoggedInPort->ScsiNexus.lun[k] == ucBuff[i+1] )
-		break; // we already masked this lun
-	    }
-	    if( k >= CPQFCTS_MAX_LUN )
-	    {
-	      printk(" no room for new LUN %d\n", ucBuff[i+1]);
-	    }
-	    else if( k == FreeLunIndex )  // need to add LUN
-	    {
-	      pLoggedInPort->ScsiNexus.lun[k] = ucBuff[i+1];
-//	      printk("add [%d]->%02d\n", k, pLoggedInPort->ScsiNexus.lun[k]);
-	      
-	    }
-	    else
-	    {
-	      // lun already known
-	    }
-	    break;
-	  }
-	}
-	// print out the new list...
-	for( j=0; j< CPQFCTS_MAX_LUN; j++)
-	{
-	  if( pLoggedInPort->ScsiNexus.lun[j] == 0xFF)
-	    break; // done
-//	  printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
-	}
-      }
-      else
-      {
-//	  printk("Linux SCSI LUNs[] -> Device LUNs: ");
-	// first time - this is easy
-        for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
-	{
-          pLoggedInPort->ScsiNexus.lun[j] = ucBuff[i+1];
-//	  printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
+
+		// Since the device was kind enough to tell us where the
+		// LUNs are, lets ensure they are contiguous for Linux's
+		// SCSI driver scan, which expects them to start at 0.
+		// Since Linux only supports 8 LUNs, only copy the first
+		// eight from the report luns command
+
+		// e.g., the Compaq RA4x00 f/w Rev 2.54 and above may report
+		// LUNs 4001, 4004, etc., because other LUNs are masked from
+		// this HBA (owned by someone else).  We'll make those appear as
+		// LUN 0, 1... to Linux
+		{
+			int j;
+			int AppendLunList = 0;
+			// Walk through the LUN list.  The 'j' array number is
+			// Linux's lun #, while the value of .lun[j] is the target's
+			// lun #.
+			// Once we build a LUN list, it's possible for a known device 
+			// to go offline while volumes (LUNs) are added.  Later,
+			// the device will do another PLOGI ... Report Luns command,
+			// and we must not alter the existing Linux Lun map.
+			// (This will be very rare).
+			for (j = 0; j < CPQFCTS_MAX_LUN; j++) {
+				if (pLoggedInPort->ScsiNexus.lun[j] != 0xFF) {
+					AppendLunList = 1;
+					break;
+				}
+			}
+			if (AppendLunList) {
+				int k;
+				int FreeLunIndex;
+//				printk("cpqfcTS: AppendLunList\n");
+
+				// If we get a new Report Luns, we cannot change
+				// any existing LUN mapping! (Only additive entry)
+				// For all LUNs in ReportLun list
+				// if RL lun != ScsiNexus lun
+				//   if RL lun present in ScsiNexus lun[], continue
+				//   else find ScsiNexus lun[]==FF and add, continue
+
+				for (i = 8, j = 0; i < LunListLen + 8 && j < CPQFCTS_MAX_LUN; i += 8, j++) {
+					if (pLoggedInPort->ScsiNexus.lun[j] != ucBuff[i + 1]) {
+						// something changed from the last Report Luns
+						printk(" cpqfcTS: Report Lun change!\n");
+						for (k = 0, FreeLunIndex = CPQFCTS_MAX_LUN; k < CPQFCTS_MAX_LUN; k++) {
+							if (pLoggedInPort->ScsiNexus.lun[k] == 0xFF) {
+								FreeLunIndex = k;
+								break;
+							}
+							if (pLoggedInPort->ScsiNexus.lun[k] == ucBuff[i + 1])
+								break;	// we already masked this lun
+						}
+						if (k >= CPQFCTS_MAX_LUN) {
+							printk(" no room for new LUN %d\n", ucBuff[i + 1]);
+						} else if (k == FreeLunIndex)	// need to add LUN
+						{
+							pLoggedInPort->ScsiNexus.lun[k] = ucBuff[i + 1];
+//							printk("add [%d]->%02d\n", k, pLoggedInPort->ScsiNexus.lun[k]);
+
+						} else {
+							// lun already known
+						}
+						break;
+					}
+				}
+				// print out the new list...
+				for (j = 0; j < CPQFCTS_MAX_LUN; j++) {
+					if (pLoggedInPort->ScsiNexus.lun[j] == 0xFF)
+						break;	// done
+//					printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
+				}
+			} else {
+//				printk("Linux SCSI LUNs[] -> Device LUNs: ");
+				// first time - this is easy
+				for (i = 8, j = 0; i < LunListLen + 8 && j < CPQFCTS_MAX_LUN; i += 8, j++) {
+					pLoggedInPort->ScsiNexus.lun[j] = ucBuff[i + 1];
+//					printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
+				}
+//				printk("\n");
+			}
+		}
 	}
-//	printk("\n");
-      }
-    }
-  }
 
-Done:  ;
+      Done:;
 }
 
-static void 
-call_scsi_done(Scsi_Cmnd *Cmnd)
+static void call_scsi_done(Scsi_Cmnd * Cmnd)
 {
 	// We have to reinitialize sent_command here, so the scsi-mid
 	// layer won't re-use the scsi command leaving it set incorrectly.
 	// (incorrectly for our purposes...it's normally unused.)
 
-        if (Cmnd->SCp.sent_command != 0) {	// was it a passthru?
+	if (Cmnd->SCp.sent_command != 0) {	// was it a passthru?
 		Cmnd->SCp.sent_command = 0;
 		Cmnd->result &= 0xff00ffff;
-		Cmnd->result |= (DID_PASSTHROUGH << 16);  // prevents retry
+		Cmnd->result |= (DID_PASSTHROUGH << 16);	// prevents retry
 	}
 	if (Cmnd->scsi_done != NULL)
-		(*Cmnd->scsi_done)(Cmnd);
+		(*Cmnd->scsi_done) (Cmnd);
 }
 
 // After successfully getting a "Process Login" (PRLI) from an
@@ -2939,361 +2306,301 @@
 // driver model, which expects a contiguous LUNs starting at 0,
 // will use the ReportLuns info to map from "device" to "Linux" 
 // LUNs.
-static void IssueReportLunsCommand( 
-              CPQFCHBA* cpqfcHBAdata, 
-	      TachFCHDR_GCMND* fchs)
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  PFC_LOGGEDIN_PORT pLoggedInPort; 
-  Scsi_Cmnd *Cmnd;
-  LONG x_ID;
-  ULONG ulStatus;
-  UCHAR *ucBuff;
-
-  if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
-  {
-    printk("Discard Q'd ReportLun command\n");
-    goto Done;
-  }
-
-  // find the device (from port_id) we're talking to
-  pLoggedInPort = fcFindLoggedInPort( fcChip,
-        NULL,     // DON'T search Scsi Nexus 
-  	fchs->s_id & 0xFFFFFF,        
-	NULL,     // DON'T search linked list for FC WWN
-        NULL);    // DON'T care about end of list
-  if( pLoggedInPort ) // we'd BETTER find it!
-  {
-
-
-    if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) )
-      goto Done;  // forget it - FC device not a "target"
-
-    // now use the port's Scsi Command buffer for the 
-    // Report Luns Command
- 
-    Cmnd = &pLoggedInPort->ScsiCmnd; 
-    ucBuff = pLoggedInPort->ReportLunsPayload;
-    
-    memset( Cmnd, 0, sizeof(Scsi_Cmnd));
-    memset( ucBuff, 0, REPORT_LUNS_PL);
-    
-    Cmnd->scsi_done = ScsiReportLunsDone;
-    Cmnd->host = cpqfcHBAdata->HostAdapter;
-
-    Cmnd->request_buffer = pLoggedInPort->ReportLunsPayload; 
-    Cmnd->request_bufflen = REPORT_LUNS_PL; 
-	    
-    Cmnd->cmnd[0] = 0xA0;
-    Cmnd->cmnd[8] = REPORT_LUNS_PL >> 8;
-    Cmnd->cmnd[9] = (UCHAR)REPORT_LUNS_PL;
-    Cmnd->cmd_len = 12;
-
-    Cmnd->channel = pLoggedInPort->ScsiNexus.channel;
-    Cmnd->target = pLoggedInPort->ScsiNexus.target;
+static void IssueReportLunsCommand(CPQFCHBA * dev, TachFCHDR_GCMND * fchs)
+{
+	PTACHYON fcChip = &dev->fcChip;
+	PFC_LOGGEDIN_PORT pLoggedInPort;
+	Scsi_Cmnd *Cmnd;
+	s32 x_ID;
+	u32 ulStatus;
+	u8 *ucBuff;
 
-	    
-    ulStatus = cpqfcTSBuildExchange(
-      cpqfcHBAdata,
-      SCSI_IRE, 
-      fchs,
-      Cmnd,         // buffer for Report Lun data
-      &x_ID );// fcController->fcExchanges index, -1 if failed
+	if (!dev->PortDiscDone)	// cleared by LDn
+	{
+		printk("Discard Q'd ReportLun command\n");
+		goto Done;
+	}
+	// find the device (from port_id) we're talking to
+	pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// DON'T search Scsi Nexus 
+					   fchs->s_id & 0xFFFFFF, NULL,	// DON'T search linked list for FC WWN
+					   NULL);	// DON'T care about end of list
+	if (pLoggedInPort)	// we'd BETTER find it!
+	{
 
-    if( !ulStatus ) // Exchange setup?
-    {
-      ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
-      if( !ulStatus )
-      {
-        // submitted to Tach's Outbound Que (ERQ PI incremented)
-        // waited for completion for ELS type (Login frames issued
-        // synchronously)
-      }
-      else
-        // check reason for Exchange not being started - we might
-        // want to Queue and start later, or fail with error
-      {
-  
-      }
-    }
 
-    else   // Xchange setup failed...
-      printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
-  }
-  else     // like, we just got a PRLI ACC, and now the port is gone?
-  {
-    printk(" can't send ReportLuns - no login for port_id %Xh\n",
-	    fchs->s_id & 0xFFFFFF);
-  }
+		if (!(pLoggedInPort->fcp_info & TARGET_FUNCTION))
+			goto Done;	// forget it - FC device not a "target"
 
+		// now use the port's Scsi Command buffer for the 
+		// Report Luns Command
 
+		Cmnd = &pLoggedInPort->ScsiCmnd;
+		ucBuff = pLoggedInPort->ReportLunsPayload;
 
-Done: ;
+		memset(Cmnd, 0, sizeof(Scsi_Cmnd));
+		memset(ucBuff, 0, REPORT_LUNS_PL);
+
+		Cmnd->scsi_done = ScsiReportLunsDone;
+		Cmnd->host = dev->HostAdapter;
+
+		Cmnd->request_buffer = pLoggedInPort->ReportLunsPayload;
+		Cmnd->request_bufflen = REPORT_LUNS_PL;
+
+		Cmnd->cmnd[0] = 0xA0;
+		Cmnd->cmnd[8] = REPORT_LUNS_PL >> 8;
+		Cmnd->cmnd[9] = (u8) REPORT_LUNS_PL;
+		Cmnd->cmd_len = 12;
+
+		Cmnd->channel = pLoggedInPort->ScsiNexus.channel;
+		Cmnd->target = pLoggedInPort->ScsiNexus.target;
+
+
+		ulStatus = cpqfcTSBuildExchange(dev, SCSI_IRE, fchs, Cmnd,	// buffer for Report Lun data
+						&x_ID);	// fcController->fcExchanges index, -1 if failed
+
+		if (!ulStatus)	// Exchange setup?
+		{
+			ulStatus = cpqfcTSStartExchange(dev, x_ID);
+			if (!ulStatus) {
+				// submitted to Tach's Outbound Que (ERQ PI incremented)
+				// waited for completion for ELS type (Login frames issued
+				// synchronously)
+			} else
+				// check reason for Exchange not being started - we might
+				// want to Queue and start later, or fail with error
+			{
+			}
+		}
 
+		else		// Xchange setup failed...
+			printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus);
+	} else			// like, we just got a PRLI ACC, and now the port is gone?
+	{
+		printk(" can't send ReportLuns - no login for port_id %Xh\n", fchs->s_id & 0xFFFFFF);
+	}
+Done:;
 }
 
-
-
-
-
-
-
-static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata)
+static void CompleteBoardLockCmnd(CPQFCHBA * dev)
 {
-  int i;
-  for( i = CPQFCTS_REQ_QUEUE_LEN-1; i>= 0; i--)
-  {
-    if( cpqfcHBAdata->BoardLockCmnd[i] != NULL )
-    {
-      Scsi_Cmnd *Cmnd = cpqfcHBAdata->BoardLockCmnd[i];
-      cpqfcHBAdata->BoardLockCmnd[i] = NULL;
-      Cmnd->result = (DID_SOFT_ERROR << 16);  // ask for retry
-//      printk(" BoardLockCmnd[%d] %p Complete, chnl/target/lun %d/%d/%d\n",
-//        i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
-      call_scsi_done(Cmnd);
-    }
-  }
+	int i;
+	for (i = CPQFCTS_REQ_QUEUE_LEN - 1; i >= 0; i--) {
+		if (dev->BoardLockCmnd[i] != NULL) {
+			Scsi_Cmnd *Cmnd = dev->BoardLockCmnd[i];
+			dev->BoardLockCmnd[i] = NULL;
+			Cmnd->result = (DID_SOFT_ERROR << 16);	// ask for retry
+//			printk(" BoardLockCmnd[%d] %p Complete, chnl/target/lun %d/%d/%d\n",
+//				i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
+			call_scsi_done(Cmnd);
+		}
+	}
 }
 
+// runs every 1 second for FC exchange timeouts and implicit FC device logouts
 
+void cpqfcTSheartbeat(unsigned long ptr)
+{
+	CPQFCHBA *dev = (CPQFCHBA *) ptr;
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
+	u32 i;
+	unsigned long flags;
+	DECLARE_MUTEX_LOCKED(BoardLock);
 
+	PCI_TRACE(0xA8)
 
+	if (dev->BoardLock)	// Worker Task Running?
+		goto Skip;
 
+	spin_lock_irqsave(&io_request_lock, flags);	// STOP _que function
 
-// runs every 1 second for FC exchange timeouts and implicit FC device logouts
-
-void cpqfcTSheartbeat( unsigned long ptr )
-{
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)ptr;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts; 
-  ULONG i;
-  unsigned long flags;
-  DECLARE_MUTEX_LOCKED(BoardLock);
-  
-  PCI_TRACE( 0xA8)
-
-  if( cpqfcHBAdata->BoardLock) // Worker Task Running?
-    goto Skip;
-
-  spin_lock_irqsave( &io_request_lock, flags); // STOP _que function
-
-  PCI_TRACE( 0xA8)
-
-
-  cpqfcHBAdata->BoardLock = &BoardLock; // stop Linux SCSI command queuing
-  
-  // release the IO lock (and re-enable interrupts)
-  spin_unlock_irqrestore( &io_request_lock, flags);
-  
-  // Ensure no contention from  _quecommand or Worker process 
-  CPQ_SPINLOCK_HBA( cpqfcHBAdata)
-  
-  PCI_TRACE( 0xA8)
-  
-
-  disable_irq( cpqfcHBAdata->HostAdapter->irq);  // our IRQ
-
-  // Complete the "bad target" commands (normally only used during
-  // initialization, since we aren't supposed to call "scsi_done"
-  // inside the queuecommand() function).  (this is overly contorted,
-  // scsi_done can be safely called from queuecommand for
-  // this bad target case.  May want to simplify this later)
+	PCI_TRACE(0xA8)
 
-  for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
-  {
-    if( cpqfcHBAdata->BadTargetCmnd[i] )
-    {
-      Scsi_Cmnd *Cmnd = cpqfcHBAdata->BadTargetCmnd[i];
-      cpqfcHBAdata->BadTargetCmnd[i] = NULL;
-      Cmnd->result = (DID_BAD_TARGET << 16);
-      call_scsi_done(Cmnd);
-    }
-    else
-      break;
-  }
+	dev->BoardLock = &BoardLock;	// stop Linux SCSI command queuing
 
-  
-  // logged in ports -- re-login check (ports required to verify login with
-  // PDISC after LIP within 2 secs)
-
-  // prevent contention
-  while( pLoggedInPort ) // for all ports which are expecting
-                         // PDISC after the next LIP, check to see if
-                         // time is up!
-  {
-      // Important: we only detect "timeout" condition on TRANSITION
-      // from non-zero to zero
-    if( pLoggedInPort->LOGO_timer )  // time-out "armed"?
-    {
-      if( !(--pLoggedInPort->LOGO_timer) ) // DEC from 1 to 0?
-      {
-          // LOGOUT time!  Per PLDA, PDISC hasn't complete in 2 secs, so
-          // issue LOGO request and destroy all I/O with other FC port(s).
-        
-/*          
-        printk(" ~cpqfcTS heartbeat: LOGOut!~ ");
-        printk("Linux SCSI Chanl/Target %d/%d (port_id %06Xh) WWN %08X%08X\n", 
-        pLoggedInPort->ScsiNexus.channel, 
-        pLoggedInPort->ScsiNexus.target, 
-	pLoggedInPort->port_id,
-          (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF), 
-          (ULONG)(pLoggedInPort->u.liWWN>>32));
+	// release the IO lock (and re-enable interrupts)
+	spin_unlock_irqrestore(&io_request_lock, flags);
 
-*/
-        cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
+	// Ensure no contention from  _quecommand or Worker process 
+	CPQ_SPINLOCK_HBA(dev)
 
-      }
-      // else simply decremented - maybe next time...
-    }
-    pLoggedInPort = pLoggedInPort->pNextPort;
-  }
+	PCI_TRACE(0xA8)
 
+	disable_irq(dev->HostAdapter->irq);	// our IRQ
 
+	// Complete the "bad target" commands (normally only used during
+	// initialization, since we aren't supposed to call "scsi_done"
+	// inside the queuecommand() function).  (this is overly contorted,
+	// scsi_done can be safely called from queuecommand for
+	// this bad target case.  May want to simplify this later)
 
-  
-  
-  // ************  FC EXCHANGE TIMEOUT CHECK **************
-  
-  for( i=0; i< TACH_MAX_XID; i++)
-  {
-    if( Exchanges->fcExchange[i].type )  // exchange defined?
-    {
+	for (i = 0; i < CPQFCTS_MAX_TARGET_ID; i++) {
+		if (dev->BadTargetCmnd[i]) {
+			Scsi_Cmnd *Cmnd = dev->BadTargetCmnd[i];
+			dev->BadTargetCmnd[i] = NULL;
+			Cmnd->result = (DID_BAD_TARGET << 16);
+			call_scsi_done(Cmnd);
+		} else
+			break;
+	}
 
-      if( !Exchanges->fcExchange[i].timeOut ) // time expired
-      {
-        // Set Exchange timeout status
-        Exchanges->fcExchange[i].status |= FC2_TIMEOUT;
-
-        if( i >= TACH_SEST_LEN ) // Link Service Exchange
-        {
-          cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, i);  // Don't "abort" LinkService
-        }
-        
-        else  // SEST Exchange TO -- may post ABTS to Worker Thread Que
-        {
-	  // (Make sure we don't keep timing it out; let other functions
-	  // complete it or set the timeOut as needed)
-	  Exchanges->fcExchange[i].timeOut = 30000; // seconds default
-
-          if( Exchanges->fcExchange[i].type 
-                  & 
-              (BLS_ABTS | BLS_ABTS_ACC )  )
-          {
-	    // For BLS_ABTS*, an upper level might still have
-	    // an outstanding command waiting for low-level completion.
-	    // Also, in the case of a WRITE, we MUST get confirmation
-	    // of either ABTS ACC or RJT before re-using the Exchange.
-	    // It's possible that the RAID cache algorithm can hang
-	    // if we fail to complete a WRITE to a LBA, when a READ
-	    // comes later to that same LBA.  Therefore, we must
-	    // ensure that the target verifies receipt of ABTS for
-	    // the exchange
-	   
-	    printk("~TO Q'd ABTS (x_ID %Xh)~ ", i); 
-//            TriggerHBA( fcChip->Registers.ReMapMemBase);
-
-	    // On timeout of a ABTS exchange, check to
-	    // see if the FC device has a current valid login.
-	    // If so, restart it.
-	    pLoggedInPort = fcFindLoggedInPort( fcChip,
-              Exchanges->fcExchange[i].Cmnd, // find Scsi Nexus
-              0,        // DON'T search linked list for FC port id
-	      NULL,     // DON'T search linked list for FC WWN
-              NULL);    // DON'T care about end of list
-
-	    // device exists?
-	    if( pLoggedInPort ) // device exists?
-	    {
-	      if( pLoggedInPort->prli ) // logged in for FCP-SCSI?
-	      {
-		// attempt to restart the ABTS
-		printk(" ~restarting ABTS~ ");
-                cpqfcTSStartExchange( cpqfcHBAdata, i );
-
-	      }
-	    }
-          }
-	  else  // not an ABTS
-	  { 
-           
-            // We expect the WorkerThread to change the xchng type to
-            // abort and set appropriate timeout.
-            cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i ); // timed-out
-	  }
-        }
-      }
-      else  // time not expired...
-      {
-        // decrement timeout: 1 or more seconds left
-        --Exchanges->fcExchange[i].timeOut;
-      }
-    }
-  }
 
+	// logged in ports -- re-login check (ports required to verify login with
+	// PDISC after LIP within 2 secs)
 
-  enable_irq( cpqfcHBAdata->HostAdapter->irq);
- 
+	// prevent contention
+	while (pLoggedInPort)	// for all ports which are expecting
+				// PDISC after the next LIP, check to see if
+				// time is up!
+	{
+		// Important: we only detect "timeout" condition on TRANSITION
+		// from non-zero to zero
+		if (pLoggedInPort->LOGO_timer)	// time-out "armed"?
+		{
+			if (!(--pLoggedInPort->LOGO_timer))	// DEC from 1 to 0?
+			{
+				// LOGOUT time!  Per PLDA, PDISC hasn't complete in 2 secs, so
+				// issue LOGO request and destroy all I/O with other FC port(s).
 
-  CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
+/*          
+			        printk(" ~cpqfcTS heartbeat: LOGOut!~ ");
+        			printk("Linux SCSI Chanl/Target %d/%d (port_id %06Xh) WWN %08X%08X\n", 
+				        pLoggedInPort->ScsiNexus.channel, 
+				        pLoggedInPort->ScsiNexus.target, 
+					pLoggedInPort->port_id,
+				        (u32)(pLoggedInPort->u.liWWN &0xFFFFFFFF), 
+				        (u32)(pLoggedInPort->u.liWWN>>32));
+*/
+				cpqfcTSImplicitLogout(dev, pLoggedInPort);
 
-  cpqfcHBAdata->BoardLock = NULL; // Linux SCSI commands may be queued
+			}
+			// else simply decremented - maybe next time...
+		}
+		pLoggedInPort = pLoggedInPort->pNextPort;
+	}
 
-  // Now, complete any Cmnd we Q'd up while BoardLock was held
+	// ************  FC EXCHANGE TIMEOUT CHECK **************
 
-  CompleteBoardLockCmnd( cpqfcHBAdata);
- 
+	for (i = 0; i < TACH_MAX_XID; i++) {
+		if (Exchanges->fcExchange[i].type)	// exchange defined?
+		{
+
+			if (!Exchanges->fcExchange[i].timeOut)	// time expired
+			{
+				// Set Exchange timeout status
+				Exchanges->fcExchange[i].status |= FC2_TIMEOUT;
+
+				if (i >= TACH_SEST_LEN)	// Link Service Exchange
+				{
+					cpqfcTSCompleteExchange(dev->PciDev, fcChip, i);	// Don't "abort" LinkService
+				}
+				else	// SEST Exchange TO -- may post ABTS to Worker Thread Que
+				{
+					// (Make sure we don't keep timing it out; let other functions
+					// complete it or set the timeOut as needed)
+					Exchanges->fcExchange[i].timeOut = 30000;	// seconds default
+
+					if (Exchanges->fcExchange[i].type & (BLS_ABTS | BLS_ABTS_ACC)) {
+						// For BLS_ABTS*, an upper level might still have
+						// an outstanding command waiting for low-level completion.
+						// Also, in the case of a WRITE, we MUST get confirmation
+						// of either ABTS ACC or RJT before re-using the Exchange.
+						// It's possible that the RAID cache algorithm can hang
+						// if we fail to complete a WRITE to a LBA, when a READ
+						// comes later to that same LBA.  Therefore, we must
+						// ensure that the target verifies receipt of ABTS for
+						// the exchange
+
+						printk("~TO Q'd ABTS (x_ID %Xh)~ ", i);
+//						TriggerHBA( fcChip->Registers.ReMapMemBase);
+
+						// On timeout of a ABTS exchange, check to
+						// see if the FC device has a current valid login.
+						// If so, restart it.
+						pLoggedInPort = fcFindLoggedInPort(fcChip, Exchanges->fcExchange[i].Cmnd,	// find Scsi Nexus
+										   0,	// DON'T search linked list for FC port id
+										   NULL,	// DON'T search linked list for FC WWN
+										   NULL);	// DON'T care about end of list
+						// device exists?
+						if (pLoggedInPort)	// device exists?
+						{
+							if (pLoggedInPort->prli)	// logged in for FCP-SCSI?
+							{
+								// attempt to restart the ABTS
+								printk(" ~restarting ABTS~ ");
+								cpqfcTSStartExchange(dev, i);
+
+							}
+						}
+					} else	// not an ABTS
+					{
+
+						// We expect the WorkerThread to change the xchng type to
+						// abort and set appropriate timeout.
+						cpqfcTSPutLinkQue(dev, BLS_ABTS, &i);	// timed-out
+					}
+				}
+			} else	// time not expired...
+			{
+				// decrement timeout: 1 or more seconds left
+				--Exchanges->fcExchange[i].timeOut;
+			}
+		}
+	}
 
-  // restart the timer to run again (1 sec later)
+	enable_irq(dev->HostAdapter->irq);
+	CPQ_SPINUNLOCK_HBA(dev)
+	dev->BoardLock = NULL;	// Linux SCSI commands may be queued
+	// Now, complete any Cmnd we Q'd up while BoardLock was held
+	CompleteBoardLockCmnd(dev);
+	// restart the timer to run again (1 sec later)
 Skip:
-  mod_timer( &cpqfcHBAdata->cpqfcTStimer, jiffies + HZ);
-  
-  PCI_TRACEO( i, 0xA8)
-  return;
+	mod_timer(&dev->cpqfcTStimer, jiffies + HZ);
+	PCI_TRACEO(i, 0xA8)
+	return;
 }
 
 
 // put valid FC-AL physical address in spec order
-static const UCHAR valid_al_pa[]={
-    0xef, 0xe8, 0xe4, 0xe2, 
-    0xe1, 0xE0, 0xDC, 0xDA, 
-    0xD9, 0xD6, 0xD5, 0xD4, 
-    0xD3, 0xD2, 0xD1, 0xCe, 
-    0xCd, 0xCc, 0xCb, 0xCa, 
-    0xC9, 0xC7, 0xC6, 0xC5, 
-    0xC3, 0xBc, 0xBa, 0xB9,
-    0xB6, 0xB5, 0xB4, 0xB3, 
-    0xB2, 0xB1, 0xae, 0xad,
-    0xAc, 0xAb, 0xAa, 0xA9, 
-
-    0xA7, 0xA6, 0xA5, 0xA3, 
-    0x9f, 0x9e, 0x9d, 0x9b, 
-    0x98, 0x97, 0x90, 0x8f, 
-    0x88, 0x84, 0x82, 0x81, 
-    0x80, 0x7c, 0x7a, 0x79, 
-    0x76, 0x75, 0x74, 0x73, 
-    0x72, 0x71, 0x6e, 0x6d, 
-    0x6c, 0x6b, 0x6a, 0x69, 
-    0x67, 0x66, 0x65, 0x63, 
-    0x5c, 0x5a, 0x59, 0x56, 
-    
-    0x55, 0x54, 0x53, 0x52, 
-    0x51, 0x4e, 0x4d, 0x4c, 
-    0x4b, 0x4a, 0x49, 0x47, 
-    0x46, 0x45, 0x43, 0x3c,
-    0x3a, 0x39, 0x36, 0x35, 
-    0x34, 0x33, 0x32, 0x31, 
-    0x2e, 0x2d, 0x2c, 0x2b, 
-    0x2a, 0x29, 0x27, 0x26, 
-    0x25, 0x23, 0x1f, 0x1E,
-    0x1d, 0x1b, 0x18, 0x17, 
-
-    0x10, 0x0f, 8, 4, 2, 1 }; // ALPA 0 (Fabric) is special case
-
-const int number_of_al_pa = (sizeof(valid_al_pa) );
+static const u8 valid_al_pa[] = {
+	0xef, 0xe8, 0xe4, 0xe2,
+	0xe1, 0xE0, 0xDC, 0xDA,
+	0xD9, 0xD6, 0xD5, 0xD4,
+	0xD3, 0xD2, 0xD1, 0xCe,
+	0xCd, 0xCc, 0xCb, 0xCa,
+	0xC9, 0xC7, 0xC6, 0xC5,
+	0xC3, 0xBc, 0xBa, 0xB9,
+	0xB6, 0xB5, 0xB4, 0xB3,
+	0xB2, 0xB1, 0xae, 0xad,
+	0xAc, 0xAb, 0xAa, 0xA9,
+
+	0xA7, 0xA6, 0xA5, 0xA3,
+	0x9f, 0x9e, 0x9d, 0x9b,
+	0x98, 0x97, 0x90, 0x8f,
+	0x88, 0x84, 0x82, 0x81,
+	0x80, 0x7c, 0x7a, 0x79,
+	0x76, 0x75, 0x74, 0x73,
+	0x72, 0x71, 0x6e, 0x6d,
+	0x6c, 0x6b, 0x6a, 0x69,
+	0x67, 0x66, 0x65, 0x63,
+	0x5c, 0x5a, 0x59, 0x56,
+
+	0x55, 0x54, 0x53, 0x52,
+	0x51, 0x4e, 0x4d, 0x4c,
+	0x4b, 0x4a, 0x49, 0x47,
+	0x46, 0x45, 0x43, 0x3c,
+	0x3a, 0x39, 0x36, 0x35,
+	0x34, 0x33, 0x32, 0x31,
+	0x2e, 0x2d, 0x2c, 0x2b,
+	0x2a, 0x29, 0x27, 0x26,
+	0x25, 0x23, 0x1f, 0x1E,
+	0x1d, 0x1b, 0x18, 0x17,
 
+	0x10, 0x0f, 8, 4, 2, 1
+};				// ALPA 0 (Fabric) is special case
 
+const int number_of_al_pa = (sizeof(valid_al_pa));
 
 // this function looks up an al_pa from the table of valid al_pa's
 // we decrement from the last decimal loop ID, because soft al_pa
@@ -3306,16 +2613,16 @@
 //  -1      - invalid al_pa (not all 8 bit values are legal)
 
 #if (0)
-static int GetLoopID( ULONG al_pa )
+static int GetLoopID(u32 al_pa)
 {
-  int i;
+	int i;
 
-  for( i = number_of_al_pa -1; i >= 0; i--)  // dec.
-  {
-    if( valid_al_pa[i] == (UCHAR)al_pa )  // take lowest 8 bits
-      return i;  // success - found valid al_pa; return decimal LoopID
-  }
-  return -1; // failed - not found
+	for (i = number_of_al_pa - 1; i >= 0; i--)	// dec.
+	{
+		if (valid_al_pa[i] == (u8) al_pa)	// take lowest 8 bits
+			return i;	// success - found valid al_pa; return decimal LoopID
+	}
+	return -1;		// failed - not found
 }
 #endif
 
@@ -3330,739 +2637,616 @@
 //     (NULL if not found)
 //   pLastLoggedInPort - ptr to last struct (for adding new ones)
 // 
-PFC_LOGGEDIN_PORT  fcFindLoggedInPort( 
-  PTACHYON fcChip, 
-  Scsi_Cmnd *Cmnd, // search linked list for Scsi Nexus (channel/target/lun)
-  ULONG port_id,   // search linked list for al_pa, or
-  UCHAR wwn[8],    // search linked list for WWN, or...
-  PFC_LOGGEDIN_PORT *pLastLoggedInPort )
-             
-{
-  PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts; 
-  BOOLEAN target_id_valid=FALSE;
-  BOOLEAN port_id_valid=FALSE;
-  BOOLEAN wwn_valid=FALSE;
-  int i;
-
-
-  if( Cmnd != NULL )
-    target_id_valid = TRUE;
-  
-  else if( port_id ) // note! 24-bit NULL address is illegal
-    port_id_valid = TRUE;
+PFC_LOGGEDIN_PORT fcFindLoggedInPort(PTACHYON fcChip, Scsi_Cmnd * Cmnd,	// search linked list for Scsi Nexus (channel/target/lun)
+				     u32 port_id,	// search linked list for al_pa, or
+				     u8 wwn[8],	// search linked list for WWN, or...
+				     PFC_LOGGEDIN_PORT * pLastLoggedInPort)
+{
+	PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
+	u8 target_id_valid = 0;
+	u8 port_id_valid = 0;
+	u8 wwn_valid = 0;
+	int i;
+
+
+	if (Cmnd != NULL)
+		target_id_valid = 1;
+
+	else if (port_id)	// note! 24-bit NULL address is illegal
+		port_id_valid = 1;
+
+	else {
+		if (wwn)	// non-null arg? (OK to pass NULL when not searching WWN)
+		{
+			for (i = 0; i < 8; i++)	// valid WWN passed?  NULL WWN invalid
+			{
+				if (wwn[i] != 0)
+					wwn_valid = 1;	// any non-zero byte makes (presumably) valid
+			}
+		}
+	}
+	// check other options ...
 
-  else
-  {
-    if( wwn ) // non-null arg? (OK to pass NULL when not searching WWN)
-    {
-      for( i=0; i<8; i++)  // valid WWN passed?  NULL WWN invalid
-      {
-        if( wwn[i] != 0 )
-          wwn_valid = TRUE;  // any non-zero byte makes (presumably) valid
-      }
-    }
-  }
-                // check other options ...
 
+	// In case multiple search options are given, we use a priority
+	// scheme:
+	// While valid pLoggedIn Ptr
+	//   If port_id is valid
+	//     if port_id matches, return Ptr
+	//   If wwn is valid
+	//     if wwn matches, return Ptr
+	//   Next Ptr in list
+	//
+	// Return NULL (not found)
 
-  // In case multiple search options are given, we use a priority
-  // scheme:
-  // While valid pLoggedIn Ptr
-  //   If port_id is valid
-  //     if port_id matches, return Ptr
-  //   If wwn is valid
-  //     if wwn matches, return Ptr
-  //   Next Ptr in list
-  //
-  // Return NULL (not found)
- 
-      
-  while( pLoggedInPort ) // NULL marks end of list (1st ptr always valid)
-  {
-    if( pLastLoggedInPort ) // caller's pointer valid?
-      *pLastLoggedInPort = pLoggedInPort;  // end of linked list
-    
-    if( target_id_valid )
-    {
-      // check Linux Scsi Cmnd for channel/target Nexus match
-      // (all luns are accessed through matching "pLoggedInPort")
-      if( (pLoggedInPort->ScsiNexus.target == Cmnd->target)
-                &&
-          (pLoggedInPort->ScsiNexus.channel == Cmnd->channel))
-      {
-        // For "passthru" modes, the IOCTL caller is responsible
-	// for setting the FCP-LUN addressing
-	if( !Cmnd->SCp.sent_command ) // NOT passthru?
+
+	while (pLoggedInPort)	// NULL marks end of list (1st ptr always valid)
 	{
-	
-          // set the FCP-LUN addressing type
-          Cmnd->SCp.phase = pLoggedInPort->ScsiNexus.VolumeSetAddressing;	
-
-          // set the Device Type we got from the snooped INQUIRY string
-	  Cmnd->SCp.Message = pLoggedInPort->ScsiNexus.InqDeviceType;
-
-	  // handle LUN masking; if not "default" (illegal) lun value,
-	  // the use it.  These lun values are set by a successful
-	  // Report Luns command
-          if( pLoggedInPort->ScsiNexus.LunMasking == 1) 
-	  {
-            // we KNOW all the valid LUNs... 0xFF is invalid!
-            Cmnd->SCp.have_data_in = pLoggedInPort->ScsiNexus.lun[Cmnd->lun];
-	    if (pLoggedInPort->ScsiNexus.lun[Cmnd->lun] == 0xFF)
-		return NULL;
-	    // printk("xlating lun %d to 0x%02x\n", Cmnd->lun, 
-            //	pLoggedInPort->ScsiNexus.lun[Cmnd->lun]);
-	  }
-	  else
-	    Cmnd->SCp.have_data_in = Cmnd->lun; // Linux & target luns match
-	}
-	break; // found it!
-      }
-    }
-    
-    if( port_id_valid ) // look for alpa first
-    {
-      if( pLoggedInPort->port_id == port_id )
-          break;  // found it!
-    }
-    if( wwn_valid ) // look for wwn second
-    {
+		if (pLastLoggedInPort)	// caller's pointer valid?
+			*pLastLoggedInPort = pLoggedInPort;	// end of linked list
 
-      if( !memcmp( &pLoggedInPort->u.ucWWN[0], &wwn[0], 8))
-      {  
-                 // all 8 bytes of WWN match
-        break;   // found it!
-      }
-    }
-                
-    pLoggedInPort = pLoggedInPort->pNextPort; // try next port
-  }
+		if (target_id_valid) {
+			// check Linux Scsi Cmnd for channel/target Nexus match
+			// (all luns are accessed through matching "pLoggedInPort")
+			if ((pLoggedInPort->ScsiNexus.target == Cmnd->target)
+			    && (pLoggedInPort->ScsiNexus.channel == Cmnd->channel)) {
+				// For "passthru" modes, the IOCTL caller is responsible
+				// for setting the FCP-LUN addressing
+				if (!Cmnd->SCp.sent_command)	// NOT passthru?
+				{
+
+					// set the FCP-LUN addressing type
+					Cmnd->SCp.phase = pLoggedInPort->ScsiNexus.VolumeSetAddressing;
+
+					// set the Device Type we got from the snooped INQUIRY string
+					Cmnd->SCp.Message = pLoggedInPort->ScsiNexus.InqDeviceType;
+
+					// handle LUN masking; if not "default" (illegal) lun value,
+					// the use it.  These lun values are set by a successful
+					// Report Luns command
+					if (pLoggedInPort->ScsiNexus.LunMasking == 1) {
+						// we KNOW all the valid LUNs... 0xFF is invalid!
+						Cmnd->SCp.have_data_in = pLoggedInPort->ScsiNexus.lun[Cmnd->lun];
+						if (pLoggedInPort->ScsiNexus.lun[Cmnd->lun] == 0xFF)
+							return NULL;
+						// printk("xlating lun %d to 0x%02x\n", Cmnd->lun, 
+						//  pLoggedInPort->ScsiNexus.lun[Cmnd->lun]);
+					} else
+						Cmnd->SCp.have_data_in = Cmnd->lun;	// Linux & target luns match
+				}
+				break;	// found it!
+			}
+		}
 
-  return pLoggedInPort;
-}
+		if (port_id_valid)	// look for alpa first
+		{
+			if (pLoggedInPort->port_id == port_id)
+				break;	// found it!
+		}
+		if (wwn_valid)	// look for wwn second
+		{
 
+			if (!memcmp(&pLoggedInPort->u.ucWWN[0], &wwn[0], 8)) {
+				// all 8 bytes of WWN match
+				break;	// found it!
+			}
+		}
 
+		pLoggedInPort = pLoggedInPort->pNextPort;	// try next port
+	}
 
+	return pLoggedInPort;
+}
 
 // 
 // We need to examine the SEST table and re-validate
 // any open Exchanges for this LoggedInPort
 // To make Tachyon pay attention, Freeze FCP assists,
 // set VAL bits, Unfreeze FCP assists
-static void RevalidateSEST( struct Scsi_Host *HostAdapter, 
-		        PFC_LOGGEDIN_PORT pLoggedInPort)
+static void RevalidateSEST(struct Scsi_Host *shpnt, PFC_LOGGEDIN_PORT pLoggedInPort)
 {
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG x_ID;
-  BOOLEAN TachFroze = FALSE;
-  
-  
-  // re-validate any SEST exchanges that are permitted
-  // to survive the link down (e.g., good PDISC performed)
-  for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
-  {
-
-    // If the SEST entry port_id matches the pLoggedInPort,
-    // we need to re-validate
-    if( (Exchanges->fcExchange[ x_ID].type == SCSI_IRE)
-         || 
-	(Exchanges->fcExchange[ x_ID].type == SCSI_IWE))
-    {
-		     
-      if( (Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF)  // (24-bit port ID)
-            == pLoggedInPort->port_id) 
-      {
-//	printk(" re-val xID %Xh ", x_ID);
-        if( !TachFroze )  // freeze if not already frozen
-          TachFroze |= FreezeTach( cpqfcHBAdata);
-        fcChip->SEST->u[ x_ID].IWE.Hdr_Len |= 0x80000000; // set VAL bit
-      }
-    } 
-  }
-
-  if( TachFroze) 
-  { 
-    fcChip->UnFreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
-  }
-} 
+	CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 x_ID;
+	u8 TachFroze = 0;
+
+
+	// re-validate any SEST exchanges that are permitted
+	// to survive the link down (e.g., good PDISC performed)
+	for (x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++) {
+
+		// If the SEST entry port_id matches the pLoggedInPort,
+		// we need to re-validate
+		if ((Exchanges->fcExchange[x_ID].type == SCSI_IRE)
+		    || (Exchanges->fcExchange[x_ID].type == SCSI_IWE)) {
+			if ((Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF) == pLoggedInPort->port_id) 	// (24-bit port ID)
+			{
+//				printk(" re-val xID %Xh ", x_ID);
+				if (!TachFroze)	// freeze if not already frozen
+					TachFroze |= FreezeTach(dev);
+				fcChip->SEST->u[x_ID].IWE.Hdr_Len |= 0x80000000;	// set VAL bit
+			}
+		}
+	}
+	if (TachFroze) {
+		fcChip->UnFreezeTachyon(fcChip, 2);	// both ERQ and FCP assists
+	}
+}
 
 
 // Complete an Linux Cmnds that we Queued because
 // our FC link was down (cause immediate retry)
 
-static void UnblockScsiDevice( struct Scsi_Host *HostAdapter, 
-		        PFC_LOGGEDIN_PORT pLoggedInPort)
+static void UnblockScsiDevice(struct Scsi_Host *shpnt, PFC_LOGGEDIN_PORT pLoggedInPort)
 {
-//  Scsi_Device *sdev = HostAdapter->host_queue;
-  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
-  Scsi_Cmnd* *SCptr = &cpqfcHBAdata->LinkDnCmnd[0];
-  Scsi_Cmnd *Cmnd;
-  int indx;
-
- 
-  
-  // if the device was previously "blocked", make sure
-  // we unblock it so Linux SCSI will resume
-
-  pLoggedInPort->device_blocked = FALSE; // clear our flag
-
-  // check the Link Down command ptr buffer;
-  // we can complete now causing immediate retry
-  for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++, SCptr++)
-  {
-    if( *SCptr != NULL ) // scsi command to complete?
-    {
+//  Scsi_Device *sdev = shpnt->host_queue;
+	CPQFCHBA *dev = (CPQFCHBA *) shpnt->hostdata;
+	Scsi_Cmnd **SCptr = &dev->LinkDnCmnd[0];
+	Scsi_Cmnd *Cmnd;
+	int indx;
+
+	// if the device was previously "blocked", make sure
+	// we unblock it so Linux SCSI will resume
+
+	pLoggedInPort->device_blocked = 0;	// clear our flag
+
+	// check the Link Down command ptr buffer;
+	// we can complete now causing immediate retry
+	for (indx = 0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++, SCptr++) {
+		if (*SCptr != NULL)	// scsi command to complete?
+		{
 #ifdef DUMMYCMND_DBG
-      printk("complete Cmnd %p in LinkDnCmnd[%d]\n", *SCptr,indx);
+			printk("complete Cmnd %p in LinkDnCmnd[%d]\n", *SCptr, indx);
 #endif
-      Cmnd = *SCptr;
-
+			Cmnd = *SCptr;
 
-      // Are there any Q'd commands for this target?
-      if( (Cmnd->target == pLoggedInPort->ScsiNexus.target)
-	       &&
-          (Cmnd->channel == pLoggedInPort->ScsiNexus.channel) )
-      {
-        Cmnd->result = (DID_SOFT_ERROR <<16); // force retry
-        if( Cmnd->scsi_done == NULL) 
-	{
-          printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n",
-		  pLoggedInPort->port_id);
-	  Cmnd->SCp.sent_command = 0;
+			// Are there any Q'd commands for this target?
+			if ((Cmnd->target == pLoggedInPort->ScsiNexus.target)
+			    && (Cmnd->channel == pLoggedInPort->ScsiNexus.channel)) {
+				Cmnd->result = (DID_SOFT_ERROR << 16);	// force retry
+				if (Cmnd->scsi_done == NULL) {
+					printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n", pLoggedInPort->port_id);
+					Cmnd->SCp.sent_command = 0;
+				} else
+					call_scsi_done(Cmnd);
+				*SCptr = NULL;	// free this slot for next use
+			}
+		}
 	}
-	else
-	  call_scsi_done(Cmnd);
-        *SCptr = NULL;  // free this slot for next use
-      }
-    }
-  }
 }
 
-  
+
 //#define WWN_DBG 1
 
-static void SetLoginFields(
-  PFC_LOGGEDIN_PORT pLoggedInPort,
-  TachFCHDR_GCMND* fchs,
-  BOOLEAN PDisc,
-  BOOLEAN Originator)
-{
-  LOGIN_PAYLOAD logi;       // FC-PH Port Login
-  PRLI_REQUEST prli;  // copy for BIG ENDIAN switch
-  int i;
+static void SetLoginFields(PFC_LOGGEDIN_PORT pLoggedInPort, TachFCHDR_GCMND * fchs, u8 PDisc, u8 Originator)
+{
+	LOGIN_PAYLOAD logi;	// FC-PH Port Login
+	PRLI_REQUEST prli;	// copy for BIG ENDIAN switch
+	int i;
 #ifdef WWN_DBG
-  ULONG ulBuff;
+	u32 ulBuff;
 #endif
 
-  BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
+	BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & logi, sizeof(logi));
 
-  pLoggedInPort->Originator = Originator;
-  pLoggedInPort->port_id = fchs->s_id & 0xFFFFFF;
-  
-  switch( fchs->pl[0] & 0xffff )
-  {
-  case 0x00000002:  //  PLOGI or PDISC ACCept?
-    if( PDisc )     // PDISC accept
-      goto PDISC_case;
-
-  case 0x00000003:  //  ELS_PLOGI or ELS_PLOGI_ACC
-
-  // Login BB_credit typically 0 for Tachyons
-    pLoggedInPort->BB_credit = logi.cmn_services.bb_credit;
-
-    // e.g. 128, 256, 1024, 2048 per FC-PH spec
-    // We have to use this when setting up SEST Writes,
-    // since that determines frame size we send.
-    pLoggedInPort->rx_data_size = logi.class3.rx_data_size;
-    pLoggedInPort->plogi = TRUE;
-    pLoggedInPort->pdisc = FALSE;
-    pLoggedInPort->prli = FALSE;    // ELS_PLOGI resets
-    pLoggedInPort->flogi = FALSE;   // ELS_PLOGI resets
-    pLoggedInPort->logo = FALSE;    // ELS_PLOGI resets
-    pLoggedInPort->LOGO_counter = 0;// ELS_PLOGI resets
-    pLoggedInPort->LOGO_timer = 0;// ELS_PLOGI resets
-
-    // was this PLOGI to a Fabric?
-    if( pLoggedInPort->port_id == 0xFFFFFC ) // well know address
-      pLoggedInPort->flogi = TRUE;
+	pLoggedInPort->Originator = Originator;
+	pLoggedInPort->port_id = fchs->s_id & 0xFFFFFF;
+
+	switch (fchs->pl[0] & 0xffff) {
+	case 0x00000002:	//  PLOGI or PDISC ACCept?
+		if (PDisc)	// PDISC accept
+			goto PDISC_case;
+
+	case 0x00000003:	//  ELS_PLOGI or ELS_PLOGI_ACC
+
+		// Login BB_credit typically 0 for Tachyons
+		pLoggedInPort->BB_credit = logi.cmn_services.bb_credit;
+
+		// e.g. 128, 256, 1024, 2048 per FC-PH spec
+		// We have to use this when setting up SEST Writes,
+		// since that determines frame size we send.
+		pLoggedInPort->rx_data_size = logi.class3.rx_data_size;
+		pLoggedInPort->plogi = 1;
+		pLoggedInPort->pdisc = 0;
+		pLoggedInPort->prli = 0;	// ELS_PLOGI resets
+		pLoggedInPort->flogi = 0;	// ELS_PLOGI resets
+		pLoggedInPort->logo = 0;	// ELS_PLOGI resets
+		pLoggedInPort->LOGO_counter = 0;	// ELS_PLOGI resets
+		pLoggedInPort->LOGO_timer = 0;	// ELS_PLOGI resets
+
+		// was this PLOGI to a Fabric?
+		if (pLoggedInPort->port_id == 0xFFFFFC)	// well know address
+			pLoggedInPort->flogi = 1;
 
 
-    for( i=0; i<8; i++)   // copy the LOGIN port's WWN
-      pLoggedInPort->u.ucWWN[i] = logi.port_name[i];  
+		for (i = 0; i < 8; i++)	// copy the LOGIN port's WWN
+			pLoggedInPort->u.ucWWN[i] = logi.port_name[i];
 
 #ifdef WWN_DBG
-    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
-    if( pLoggedInPort->Originator)
-      printk("o");
-    else
-      printk("r");
-    printk("PLOGI port_id %Xh, WWN %08X",
-      pLoggedInPort->port_id, ulBuff);
+		ulBuff = (u32) pLoggedInPort->u.liWWN;
+		if (pLoggedInPort->Originator)
+			printk("o");
+		else
+			printk("r");
+		printk("PLOGI port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
 
-    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
-    printk("%08Xh fcPort %p\n", ulBuff, pLoggedInPort);
+		ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
+		printk("%08Xh fcPort %p\n", ulBuff, pLoggedInPort);
 #endif
-    break;
-
-
-
-  
-  case 0x00000005:  //  ELS_LOGO (logout)
-
+		break;
 
-    pLoggedInPort->plogi = FALSE;
-    pLoggedInPort->pdisc = FALSE;
-    pLoggedInPort->prli = FALSE;   // ELS_PLOGI resets
-    pLoggedInPort->flogi = FALSE;  // ELS_PLOGI resets
-    pLoggedInPort->logo = TRUE;    // ELS_PLOGI resets
-    pLoggedInPort->LOGO_counter++; // ELS_PLOGI resets
-    pLoggedInPort->LOGO_timer = 0;
+	case 0x00000005:	//  ELS_LOGO (logout)
+		pLoggedInPort->plogi = 0;
+		pLoggedInPort->pdisc = 0;
+		pLoggedInPort->prli = 0;	// ELS_PLOGI resets
+		pLoggedInPort->flogi = 0;	// ELS_PLOGI resets
+		pLoggedInPort->logo = 1;	// ELS_PLOGI resets
+		pLoggedInPort->LOGO_counter++;	// ELS_PLOGI resets
+		pLoggedInPort->LOGO_timer = 0;
 #ifdef WWN_DBG
-    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
-    if( pLoggedInPort->Originator)
-      printk("o");
-    else
-      printk("r");
-    printk("LOGO port_id %Xh, WWN %08X",
-      pLoggedInPort->port_id, ulBuff);
+		ulBuff = (u32) pLoggedInPort->u.liWWN;
+		if (pLoggedInPort->Originator)
+			printk("o");
+		else
+			printk("r");
+		printk("LOGO port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
 
-    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
-    printk("%08Xh\n", ulBuff);
+		ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
+		printk("%08Xh\n", ulBuff);
 #endif
-    break;
-
-
+		break;
 
-PDISC_case:
-  case 0x00000050: //  ELS_PDISC or ELS_PDISC_ACC
-    pLoggedInPort->LOGO_timer = 0;  // stop the time-out
-      
-    pLoggedInPort->prli = TRUE;     // ready to accept FCP-SCSI I/O
-    
+	PDISC_case:
+	case 0x00000050:	//  ELS_PDISC or ELS_PDISC_ACC
+		pLoggedInPort->LOGO_timer = 0;	// stop the time-out
 
-      
+		pLoggedInPort->prli = 1;	// ready to accept FCP-SCSI I/O
 #ifdef WWN_DBG
-    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
-    if( pLoggedInPort->Originator)
-      printk("o");
-    else
-      printk("r");
-    printk("PDISC port_id %Xh, WWN %08X",
-      pLoggedInPort->port_id, ulBuff);
+		ulBuff = (u32) pLoggedInPort->u.liWWN;
+		if (pLoggedInPort->Originator)
+			printk("o");
+		else
+			printk("r");
+		printk("PDISC port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
 
-    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
-    printk("%08Xh\n", ulBuff);
+		ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
+		printk("%08Xh\n", ulBuff);
 #endif
+		break;
 
-
-    
-    break;
-
-
-    
-  case  0x1020L: //  PRLI?
-  case  0x1002L: //  PRLI ACCept?
-    BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli, sizeof(prli));
-
-    pLoggedInPort->fcp_info = prli.fcp_info; // target/initiator flags
-    pLoggedInPort->prli = TRUE;  // PLOGI resets, PDISC doesn't
-
-    pLoggedInPort->pdisc = TRUE;  // expect to send (or receive) PDISC
-                                  // next time
-    pLoggedInPort->LOGO_timer = 0;  // will be set next LinkDown
+	case 0x1020L:		//  PRLI?
+	case 0x1002L:		//  PRLI ACCept?
+		BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & prli, sizeof(prli));
+
+		pLoggedInPort->fcp_info = prli.fcp_info;	// target/initiator flags
+		pLoggedInPort->prli = 1;	// PLOGI resets, PDISC doesn't
+
+		pLoggedInPort->pdisc = 1;	// expect to send (or receive) PDISC
+		// next time
+		pLoggedInPort->LOGO_timer = 0;	// will be set next LinkDown
 #ifdef WWN_DBG
-    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
-    if( pLoggedInPort->Originator)
-      printk("o");
-    else
-      printk("r");
-    printk("PRLI port_id %Xh, WWN %08X",
-      pLoggedInPort->port_id, ulBuff);
+		ulBuff = (u32) pLoggedInPort->u.liWWN;
+		if (pLoggedInPort->Originator)
+			printk("o");
+		else
+			printk("r");
+		printk("PRLI port_id %Xh, WWN %08X", pLoggedInPort->port_id, ulBuff);
 
-    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
-      printk("%08Xh\n", ulBuff);
+		ulBuff = (u32) (pLoggedInPort->u.liWWN >> 32);
+		printk("%08Xh\n", ulBuff);
 #endif
-
-    break;
-
-  }
-
-  return;
+		break;
+	}
+	return;
 }
 
-
-
-
-
-
-static void BuildLinkServicePayload( PTACHYON fcChip, ULONG type, void* payload)
+static void BuildLinkServicePayload(PTACHYON fcChip, u32 type, void *payload)
 {
-  LOGIN_PAYLOAD *plogi;  // FC-PH Port Login
-  LOGIN_PAYLOAD PlogiPayload;   // copy for BIG ENDIAN switch
-  PRLI_REQUEST  *prli;          // FCP-SCSI Process Login
-  PRLI_REQUEST  PrliPayload;    // copy for BIG ENDIAN switch
-  LOGOUT_PAYLOAD  *logo;
-  LOGOUT_PAYLOAD  LogoutPayload;
-//  PRLO_REQUEST  *prlo;
-//  PRLO_REQUEST  PrloPayload;
-  REJECT_MESSAGE rjt, *prjt;
-
-  memset( &PlogiPayload, 0, sizeof( PlogiPayload));
-  plogi = &PlogiPayload;    // load into stack buffer,
-                                // then BIG-ENDIAN switch a copy to caller
-
-
-  switch( type )  // payload type can be ELS_PLOGI, ELS_PRLI, ADISC, ...
-  {
-    case ELS_FDISC:
-    case ELS_FLOGI:
-    case ELS_PLOGI_ACC:   // FC-PH PORT Login Accept
-    case ELS_PLOGI:   // FC-PH PORT Login
-    case ELS_PDISC:   // FC-PH2 Port Discovery - same payload as ELS_PLOGI
-      plogi->login_cmd = LS_PLOGI;
-      if( type == ELS_PDISC)
-        plogi->login_cmd = LS_PDISC;
-      else if( type == ELS_PLOGI_ACC )
-        plogi->login_cmd = LS_ACC;
-
-      plogi->cmn_services.bb_credit = 0x00;
-      plogi->cmn_services.lowest_ver = fcChip->lowest_FCPH_ver;
-      plogi->cmn_services.highest_ver = fcChip->highest_FCPH_ver;
-      plogi->cmn_services.bb_rx_size = TACHLITE_TS_RX_SIZE;
-      plogi->cmn_services.common_features = CONTINUOSLY_INCREASING |
-              RANDOM_RELATIVE_OFFSET;
-
-             // fill in with World Wide Name based Port Name - 8 UCHARs
-             // get from Tach registers WWN hi & lo
-      LoadWWN( fcChip, plogi->port_name, 0);
-             // fill in with World Wide Name based Node/Fabric Name - 8 UCHARs
-             // get from Tach registers WWN hi & lo
-      LoadWWN( fcChip, plogi->node_name, 1);
-
-	// For Seagate Drives.
-	//
-      plogi->cmn_services.common_features |= 0x800;
-      plogi->cmn_services.rel_offset = 0xFE;
-      plogi->cmn_services.concurrent_seq = 1;
-      plogi->class1.service_options = 0x00;
-      plogi->class2.service_options = 0x00;
-      plogi->class3.service_options = CLASS_VALID;
-      plogi->class3.initiator_control = 0x00;
-      plogi->class3.rx_data_size = MAX_RX_PAYLOAD;
-      plogi->class3.recipient_control =
-             ERROR_DISCARD | ONE_CATEGORY_SEQUENCE;
-      plogi->class3.concurrent_sequences = 1;
-      plogi->class3.open_sequences = 1;
-      plogi->vendor_id[0] = 'C'; plogi->vendor_id[1] = 'Q';
-      plogi->vendor_version[0] = 'C'; plogi->vendor_version[1] = 'Q';
-      plogi->vendor_version[2] = ' '; plogi->vendor_version[3] = '0';
-      plogi->vendor_version[4] = '0'; plogi->vendor_version[5] = '0';
-
-
-      // FLOGI specific fields... (see FC-FLA, Rev 2.7, Aug 1999, sec 5.1)
-      if( (type == ELS_FLOGI) || (type == ELS_FDISC) )
-      {
-        if( type == ELS_FLOGI )
-  	  plogi->login_cmd = LS_FLOGI;  
-	else
-  	  plogi->login_cmd = LS_FDISC;  
-
-        plogi->cmn_services.lowest_ver = 0x20;
-        plogi->cmn_services.common_features = 0x0800;
-        plogi->cmn_services.rel_offset = 0;
-        plogi->cmn_services.concurrent_seq = 0;
-
-        plogi->class3.service_options = 0x8800;
-        plogi->class3.rx_data_size = 0;
-        plogi->class3.recipient_control = 0;
-        plogi->class3.concurrent_sequences = 0;
-        plogi->class3.open_sequences = 0;
-      }
-      
-              // copy back to caller's buff, w/ BIG ENDIAN swap
-      BigEndianSwap( (UCHAR*)&PlogiPayload, payload,  sizeof(PlogiPayload));
-      break;
-
-    
-    case ELS_ACC:       // generic Extended Link Service ACCept	    
-      plogi->login_cmd = LS_ACC;
-              // copy back to caller's buff, w/ BIG ENDIAN swap
-      BigEndianSwap( (UCHAR*)&PlogiPayload, payload,  4);
-      break;
-
-
-      
-    case ELS_SCR:    // Fabric State Change Registration
-    {
-      SCR_PL scr;     // state change registration
-
-      memset( &scr, 0, sizeof(scr));
-
-      scr.command = LS_SCR;  // 0x62000000
-                             // see FC-FLA, Rev 2.7, Table A.22 (pg 82)
-      scr.function = 3;      // 1 = Events detected by Fabric
-                             // 2 = N_Port detected registration
-                             // 3 = Full registration
-      
-      // copy back to caller's buff, w/ BIG ENDIAN swap
-      BigEndianSwap( (UCHAR*)&scr, payload,  sizeof(SCR_PL));
-    }
-    
-    break;
-
-    
-    case FCS_NSR:    // Fabric Name Service Request
-    {
-      NSR_PL nsr;    // Name Server Req. payload
-
-      memset( &nsr, 0, sizeof(NSR_PL));
-
-                             // see Brocade Fabric Programming Guide,
-                             // Rev 1.3, pg 4-44
-      nsr.CT_Rev = 0x01000000;
-      nsr.FCS_Type = 0xFC020000;
-      nsr.Command_code = 0x01710000;
-      nsr.FCP = 8;
-     
-      // copy back to caller's buff, w/ BIG ENDIAN swap
-      BigEndianSwap( (UCHAR*)&nsr, payload,  sizeof(NSR_PL));
-    }
-    
-    break;
-
-
-
-    
-    case ELS_LOGO:   // FC-PH PORT LogOut
-      logo = &LogoutPayload;    // load into stack buffer,
-                                // then BIG-ENDIAN switch a copy to caller
-      logo->cmd = LS_LOGO;
-                                // load the 3 UCHARs of the node name
-                                // (if private loop, upper two UCHARs 0)
-      logo->reserved = 0;
-
-      logo->n_port_identifier[0] = (UCHAR)(fcChip->Registers.my_al_pa);
-      logo->n_port_identifier[1] =
-                     (UCHAR)(fcChip->Registers.my_al_pa>>8);
-      logo->n_port_identifier[2] =
-                     (UCHAR)(fcChip->Registers.my_al_pa>>16);
-             // fill in with World Wide Name based Port Name - 8 UCHARs
-             // get from Tach registers WWN hi & lo
-      LoadWWN( fcChip, logo->port_name, 0);
-
-      BigEndianSwap( (UCHAR*)&LogoutPayload,
-                     payload,  sizeof(LogoutPayload) );  // 16 UCHAR struct
-      break;
-
-
-    case ELS_LOGO_ACC:     // Logout Accept (FH-PH pg 149, table 74)
-      logo = &LogoutPayload;    // load into stack buffer,
-                                // then BIG-ENDIAN switch a copy to caller
-      logo->cmd = LS_ACC;
-      BigEndianSwap( (UCHAR*)&LogoutPayload, payload, 4 );  // 4 UCHAR cmnd
-      break;
-      
-
-    case ELS_RJT:          // ELS_RJT link service reject (FH-PH pg 155)
-
-      prjt = (REJECT_MESSAGE*)payload;  // pick up passed data
-      rjt.command_code = ELS_RJT;
-                       // reverse fields, because of Swap that follows...
-      rjt.vendor = prjt->reserved; // vendor specific
-      rjt.explain = prjt->reason; //
-      rjt.reason = prjt->explain; //
-      rjt.reserved = prjt->vendor; //
-                       // BIG-ENDIAN switch a copy to caller
-      BigEndianSwap( (UCHAR*)&rjt, payload, 8 );  // 8 UCHAR cmnd
-      break;
+	LOGIN_PAYLOAD *plogi;	// FC-PH Port Login
+	LOGIN_PAYLOAD PlogiPayload;	// copy for BIG ENDIAN switch
+	PRLI_REQUEST *prli;	// FCP-SCSI Process Login
+	PRLI_REQUEST PrliPayload;	// copy for BIG ENDIAN switch
+	LOGOUT_PAYLOAD *logo;
+	LOGOUT_PAYLOAD LogoutPayload;
+//	PRLO_REQUEST  *prlo;
+//	PRLO_REQUEST  PrloPayload;
+	REJECT_MESSAGE rjt, *prjt;
+
+	memset(&PlogiPayload, 0, sizeof(PlogiPayload));
+	plogi = &PlogiPayload;	// load into stack buffer,
+	// then BIG-ENDIAN switch a copy to caller
 
+	switch (type)		// payload type can be ELS_PLOGI, ELS_PRLI, ADISC, ...
+	{
+	case ELS_FDISC:
+	case ELS_FLOGI:
+	case ELS_PLOGI_ACC:	// FC-PH PORT Login Accept
+	case ELS_PLOGI:	// FC-PH PORT Login
+	case ELS_PDISC:	// FC-PH2 Port Discovery - same payload as ELS_PLOGI
+		plogi->login_cmd = LS_PLOGI;
+		if (type == ELS_PDISC)
+			plogi->login_cmd = LS_PDISC;
+		else if (type == ELS_PLOGI_ACC)
+			plogi->login_cmd = LS_ACC;
+
+		plogi->cmn_services.bb_credit = 0x00;
+		plogi->cmn_services.lowest_ver = fcChip->lowest_FCPH_ver;
+		plogi->cmn_services.highest_ver = fcChip->highest_FCPH_ver;
+		plogi->cmn_services.bb_rx_size = TACHLITE_TS_RX_SIZE;
+		plogi->cmn_services.common_features = CONTINUOSLY_INCREASING | RANDOM_RELATIVE_OFFSET;
+
+		// fill in with World Wide Name based Port Name - 8 u8s
+		// get from Tach registers WWN hi & lo
+		LoadWWN(fcChip, plogi->port_name, 0);
+		// fill in with World Wide Name based Node/Fabric Name - 8 u8s
+		// get from Tach registers WWN hi & lo
+		LoadWWN(fcChip, plogi->node_name, 1);
+
+		// For Seagate Drives.
+		//
+		plogi->cmn_services.common_features |= 0x800;
+		plogi->cmn_services.rel_offset = 0xFE;
+		plogi->cmn_services.concurrent_seq = 1;
+		plogi->class1.service_options = 0x00;
+		plogi->class2.service_options = 0x00;
+		plogi->class3.service_options = CLASS_VALID;
+		plogi->class3.initiator_control = 0x00;
+		plogi->class3.rx_data_size = MAX_RX_PAYLOAD;
+		plogi->class3.recipient_control = ERROR_DISCARD | ONE_CATEGORY_SEQUENCE;
+		plogi->class3.concurrent_sequences = 1;
+		plogi->class3.open_sequences = 1;
+		plogi->vendor_id[0] = 'C';
+		plogi->vendor_id[1] = 'Q';
+		plogi->vendor_version[0] = 'C';
+		plogi->vendor_version[1] = 'Q';
+		plogi->vendor_version[2] = ' ';
+		plogi->vendor_version[3] = '0';
+		plogi->vendor_version[4] = '0';
+		plogi->vendor_version[5] = '0';
+
+		// FLOGI specific fields... (see FC-FLA, Rev 2.7, Aug 1999, sec 5.1)
+		if ((type == ELS_FLOGI) || (type == ELS_FDISC)) {
+			if (type == ELS_FLOGI)
+				plogi->login_cmd = LS_FLOGI;
+			else
+				plogi->login_cmd = LS_FDISC;
+
+			plogi->cmn_services.lowest_ver = 0x20;
+			plogi->cmn_services.common_features = 0x0800;
+			plogi->cmn_services.rel_offset = 0;
+			plogi->cmn_services.concurrent_seq = 0;
+
+			plogi->class3.service_options = 0x8800;
+			plogi->class3.rx_data_size = 0;
+			plogi->class3.recipient_control = 0;
+			plogi->class3.concurrent_sequences = 0;
+			plogi->class3.open_sequences = 0;
+		}
+		// copy back to caller's buff, w/ BIG ENDIAN swap
+		BigEndianSwap((u8 *) & PlogiPayload, payload, sizeof(PlogiPayload));
+		break;
 
+	case ELS_ACC:		// generic Extended Link Service ACCept     
+		plogi->login_cmd = LS_ACC;
+		// copy back to caller's buff, w/ BIG ENDIAN swap
+		BigEndianSwap((u8 *) & PlogiPayload, payload, 4);
+		break;
 
+	case ELS_SCR:		// Fabric State Change Registration
+		{
+			SCR_PL scr;	// state change registration
+
+			memset(&scr, 0, sizeof(scr));
+
+			scr.command = LS_SCR;	// 0x62000000
+			// see FC-FLA, Rev 2.7, Table A.22 (pg 82)
+			scr.function = 3;	// 1 = Events detected by Fabric
+			// 2 = N_Port detected registration
+			// 3 = Full registration
 
+			// copy back to caller's buff, w/ BIG ENDIAN swap
+			BigEndianSwap((u8 *) & scr, payload, sizeof(SCR_PL));
+		}
+		break;
 
-    case ELS_PRLI_ACC:  // Process Login ACCept
-    case ELS_PRLI:  // Process Login
-    case ELS_PRLO:  // Process Logout
-      memset( &PrliPayload, 0, sizeof( PrliPayload));
-      prli = &PrliPayload;      // load into stack buffer,
+	case FCS_NSR:		// Fabric Name Service Request
+		{
+			NSR_PL nsr;	// Name Server Req. payload
+
+			memset(&nsr, 0, sizeof(NSR_PL));
+
+			// see Brocade Fabric Programming Guide,
+			// Rev 1.3, pg 4-44
+			nsr.CT_Rev = 0x01000000;
+			nsr.FCS_Type = 0xFC020000;
+			nsr.Command_code = 0x01710000;
+			nsr.FCP = 8;
 
-      if( type == ELS_PRLI )
-        prli->cmd = 0x20;  // Login
-      else if( type == ELS_PRLO )
-        prli->cmd = 0x21;  // Logout
-      else if( type == ELS_PRLI_ACC )
-      {
-        prli->cmd = 0x02;  // Login ACCept
-        prli->valid = REQUEST_EXECUTED;
-      }
+			// copy back to caller's buff, w/ BIG ENDIAN swap
+			BigEndianSwap((u8 *) & nsr, payload, sizeof(NSR_PL));
+		}
+		break;
 
+	case ELS_LOGO:		// FC-PH PORT LogOut
+		logo = &LogoutPayload;	// load into stack buffer,
+		// then BIG-ENDIAN switch a copy to caller
+		logo->cmd = LS_LOGO;
+		// load the 3 u8s of the node name
+		// (if private loop, upper two u8s 0)
+		logo->reserved = 0;
+
+		logo->n_port_identifier[0] = (u8) (fcChip->Registers.my_al_pa);
+		logo->n_port_identifier[1] = (u8) (fcChip->Registers.my_al_pa >> 8);
+		logo->n_port_identifier[2] = (u8) (fcChip->Registers.my_al_pa >> 16);
+		// fill in with World Wide Name based Port Name - 8 u8s
+		// get from Tach registers WWN hi & lo
+		LoadWWN(fcChip, logo->port_name, 0);
 
-      prli->valid |= SCSI_FCP | ESTABLISH_PAIR;
-      prli->fcp_info = READ_XFER_RDY;
-      prli->page_length = 0x10;
-      prli->payload_length = 20;
-                                // Can be initiator AND target
+		BigEndianSwap((u8 *) & LogoutPayload, payload, sizeof(LogoutPayload));	// 16 u8 struct
+		break;
 
-      if( fcChip->Options.initiator )
-        prli->fcp_info |= INITIATOR_FUNCTION;
-      if( fcChip->Options.target )
-        prli->fcp_info |= TARGET_FUNCTION;
+	case ELS_LOGO_ACC:	// Logout Accept (FH-PH pg 149, table 74)
+		logo = &LogoutPayload;	// load into stack buffer,
+		// then BIG-ENDIAN switch a copy to caller
+		logo->cmd = LS_ACC;
+		BigEndianSwap((u8 *) & LogoutPayload, payload, 4);	// 4 u8 cmnd
+		break;
 
-      BigEndianSwap( (UCHAR*)&PrliPayload, payload,  prli->payload_length);
-      break;
+	case ELS_RJT:		// ELS_RJT link service reject (FH-PH pg 155)
+		prjt = (REJECT_MESSAGE *) payload;	// pick up passed data
+		rjt.command_code = ELS_RJT;
+		// reverse fields, because of Swap that follows...
+		rjt.vendor = prjt->reserved;	// vendor specific
+		rjt.explain = prjt->reason;	//
+		rjt.reason = prjt->explain;	//
+		rjt.reserved = prjt->vendor;	//
+		// BIG-ENDIAN switch a copy to caller
+		BigEndianSwap((u8 *) & rjt, payload, 8);	// 8 u8 cmnd
+		break;
 
+	case ELS_PRLI_ACC:	// Process Login ACCept
+	case ELS_PRLI:		// Process Login
+	case ELS_PRLO:		// Process Logout
+		memset(&PrliPayload, 0, sizeof(PrliPayload));
+		prli = &PrliPayload;	// load into stack buffer,
+
+		if (type == ELS_PRLI)
+			prli->cmd = 0x20;	// Login
+		else if (type == ELS_PRLO)
+			prli->cmd = 0x21;	// Logout
+		else if (type == ELS_PRLI_ACC) {
+			prli->cmd = 0x02;	// Login ACCept
+			prli->valid = REQUEST_EXECUTED;
+		}
+		prli->valid |= SCSI_FCP | ESTABLISH_PAIR;
+		prli->fcp_info = READ_XFER_RDY;
+		prli->page_length = 0x10;
+		prli->payload_length = 20;
+		// Can be initiator AND target
+
+		if (fcChip->Options.initiator)
+			prli->fcp_info |= INITIATOR_FUNCTION;
+		if (fcChip->Options.target)
+			prli->fcp_info |= TARGET_FUNCTION;
 
+		BigEndianSwap((u8 *) & PrliPayload, payload, prli->payload_length);
+		break;
 
-    default:  // no can do - programming error
-      printk(" BuildLinkServicePayload unknown!\n");
-      break;
-  }
+	default:		// no can do - programming error
+		printk(" BuildLinkServicePayload unknown!\n");
+		break;
+	}
 }
 
-// loads 8 UCHARs for PORT name or NODE name base on
+// loads 8 u8s for PORT name or NODE name base on
 // controller's WWN.
-void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type)
+void LoadWWN(PTACHYON fcChip, u8 * dest, u8 type)
 {
-  UCHAR* bPtr, i;
-
-  switch( type )
-  {
-    case 0:  // Port_Name
-      bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
-      for( i =0; i<4; i++)
-        dest[i] = *bPtr++;
-      bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
-      for( i =4; i<8; i++)
-        dest[i] = *bPtr++;
-      break;
-    case 1:  // Node/Fabric _Name
-      bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
-      for( i =0; i<4; i++)
-        dest[i] = *bPtr++;
-      bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
-      for( i =4; i<8; i++)
-        dest[i] = *bPtr++;
-      break;
-  }
-  
-}
+	u8 *bPtr, i;
 
+	switch (type) {
+	case 0:		// Port_Name
+		bPtr = (u8 *) & fcChip->Registers.wwn_hi;
+		for (i = 0; i < 4; i++)
+			dest[i] = *bPtr++;
+		bPtr = (u8 *) & fcChip->Registers.wwn_lo;
+		for (i = 4; i < 8; i++)
+			dest[i] = *bPtr++;
+		break;
+	case 1:		// Node/Fabric _Name
+		bPtr = (u8 *) & fcChip->Registers.wwn_hi;
+		for (i = 0; i < 4; i++)
+			dest[i] = *bPtr++;
+		bPtr = (u8 *) & fcChip->Registers.wwn_lo;
+		for (i = 4; i < 8; i++)
+			dest[i] = *bPtr++;
+		break;
+	}
 
+}
 
 // We check the Port Login payload for required values.  Note that
 // ELS_PLOGI and ELS_PDISC (Port DISCover) use the same payload.
 
+int verify_PLOGI(PTACHYON fcChip, TachFCHDR_GCMND * fchs, u32 * reject_explain)
+{
+	LOGIN_PAYLOAD login;
 
-int verify_PLOGI( PTACHYON fcChip,
-                  TachFCHDR_GCMND* fchs, 
-                  ULONG* reject_explain)
-{
-  LOGIN_PAYLOAD	login;
-
-                  // source, dest, len (should be mult. of 4)
-  BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&login,  sizeof(login));
-
-                            // check FC version
-                            // if other port's highest supported version
-                            // is less than our lowest, and 
-                            // if other port's lowest
-  if( login.cmn_services.highest_ver < fcChip->lowest_FCPH_ver ||
-      login.cmn_services.lowest_ver > fcChip->highest_FCPH_ver )
-  {
-    *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
-    return LOGICAL_ERROR;
-  }
-
-                            // Receive Data Field Size must be >=128
-                            // per FC-PH
-  if (login.cmn_services.bb_rx_size < 128)
-  {
-    *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, DATA_FIELD_SIZE_ERROR);
-    return LOGICAL_ERROR;
-  }
+	// source, dest, len (should be mult. of 4)
+	BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & login, sizeof(login));
 
-                            // Only check Class 3 params
-  if( login.class3.service_options & CLASS_VALID)
-  {
-    if (login.class3.rx_data_size < 128)
-    {
-      *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INVALID_CSP);
-      return LOGICAL_ERROR;
-    }
-    if( login.class3.initiator_control & XID_REQUIRED)
-    {
-      *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INITIATOR_CTL_ERROR);
-      return LOGICAL_ERROR;
-    }
-  }
-  return 0;   // success
+	// check FC version
+	// if other port's highest supported version
+	// is less than our lowest, and 
+	// if other port's lowest
+	if (login.cmn_services.highest_ver < fcChip->lowest_FCPH_ver || login.cmn_services.lowest_ver > fcChip->highest_FCPH_ver) {
+		*reject_explain = LS_RJT_REASON(LOGICAL_ERROR, OPTIONS_ERROR);
+		return LOGICAL_ERROR;
+	}
+	// Receive Data Field Size must be >=128
+	// per FC-PH
+	if (login.cmn_services.bb_rx_size < 128) {
+		*reject_explain = LS_RJT_REASON(LOGICAL_ERROR, DATA_FIELD_SIZE_ERROR);
+		return LOGICAL_ERROR;
+	}
+	// Only check Class 3 params
+	if (login.class3.service_options & CLASS_VALID) {
+		if (login.class3.rx_data_size < 128) {
+			*reject_explain = LS_RJT_REASON(LOGICAL_ERROR, INVALID_CSP);
+			return LOGICAL_ERROR;
+		}
+		if (login.class3.initiator_control & XID_REQUIRED) {
+			*reject_explain = LS_RJT_REASON(LOGICAL_ERROR, INITIATOR_CTL_ERROR);
+			return LOGICAL_ERROR;
+		}
+	}
+	return 0;		// success
 }
 
-
-
-
-int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain)
+int verify_PRLI(TachFCHDR_GCMND * fchs, u32 * reject_explain)
 {
-  PRLI_REQUEST prli;  // buffer for BIG ENDIAN
+	PRLI_REQUEST prli;	// buffer for BIG ENDIAN
 
-                  // source, dest, len (should be mult. of 4)
-  BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli,  sizeof(prli));
+	// source, dest, len (should be mult. of 4)
+	BigEndianSwap((u8 *) & fchs->pl[0], (u8 *) & prli, sizeof(prli));
 
-  if( prli.fcp_info == 0 )  // i.e., not target or initiator?
-  {
-    *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
-    return LOGICAL_ERROR;
-  }
+	if (prli.fcp_info == 0)	// i.e., not target or initiator?
+	{
+		*reject_explain = LS_RJT_REASON(LOGICAL_ERROR, OPTIONS_ERROR);
+		return LOGICAL_ERROR;
+	}
 
-  return 0;  // success
+	return 0;		// success
 }
 
-
-// SWAP UCHARs as required by Fibre Channel (i.e. BIG ENDIAN)
+// SWAP u8s as required by Fibre Channel (i.e. BIG ENDIAN)
 // INPUTS:
-//   source   - ptr to LITTLE ENDIAN ULONGS
-//   cnt      - number of UCHARs to switch (should be mult. of ULONG)
+//   source   - ptr to LITTLE ENDIAN u32S
+//   cnt      - number of u8s to switch (should be mult. of u32)
 // OUTPUTS:
 //   dest     - ptr to BIG ENDIAN copy
 // RETURN:
 //   none
 //
-void BigEndianSwap( UCHAR *source, UCHAR *dest,  USHORT cnt)
+void BigEndianSwap(u8 * source, u8 * dest, u16 cnt)
 {
-  int i,j;
+	int i, j;
 
-  source+=3;   // start at MSB of 1st ULONG
-  for( j=0; j < cnt; j+=4, source+=4, dest+=4)  // every ULONG
-  {
-    for( i=0; i<4; i++)  // every UCHAR in ULONG
-          *(dest+i) = *(source-i);
-  }
+	source += 3;		// start at MSB of 1st u32
+	for (j = 0; j < cnt; j += 4, source += 4, dest += 4)	// every u32
+	{
+		for (i = 0; i < 4; i++)	// every u8 in u32
+			*(dest + i) = *(source - i);
+	}
 }
 
-
-
-
 // Build FC Exchanges............
 
-static void  buildFCPstatus( 
-  PTACHYON fcChip, 
-  ULONG ExchangeID);
-
-static LONG FindFreeExchange( PTACHYON fcChip, ULONG type );
-
-static ULONG build_SEST_sgList( 
-  struct pci_dev *pcidev,
-  ULONG *SESTalPairStart,
-  Scsi_Cmnd *Cmnd,
-  ULONG *sgPairs,
-  PSGPAGES *sgPages_head  // link list of TL Ext. S/G pages from O/S Pool
-);
-
-static int build_FCP_payload( Scsi_Cmnd *Cmnd, 
-  UCHAR* payload, ULONG type, ULONG fcp_dl );
-
+static void buildFCPstatus(PTACHYON fcChip, u32 ExchangeID);
+static s32 FindFreeExchange(PTACHYON fcChip, u32 type);
+static u32 build_SEST_sgList(struct pci_dev *pcidev, u32 * SESTalPairStart, Scsi_Cmnd * Cmnd, u32 * sgPairs, PSGPAGES * sgPages_head);	// link list of TL Ext. S/G pages from O/S Pool
+static int build_FCP_payload(Scsi_Cmnd * Cmnd, u8 * payload, u32 type, u32 fcp_dl);
 
 /*
                              IRB
@@ -4118,7 +3302,7 @@
 // SEST entry, and several frame headers and data buffers all
 // logically linked together.
 // Inputs:
-//   cpqfcHBAdata  - controller struct
+//   dev  - controller struct
 //   type          - PLOGI, SCSI_IWE, etc.
 //   InFCHS        - Incoming Tachlite FCHS which prompted this exchange
 //                   (only s_id set if we are originating)
@@ -4143,990 +3327,807 @@
 // return success
 
 //sbuildex
-ULONG cpqfcTSBuildExchange(
-  CPQFCHBA *cpqfcHBAdata,
-  ULONG type, // e.g. PLOGI
-  TachFCHDR_GCMND* InFCHS,  // incoming FCHS
-  void *Data,               // the CDB, scatter/gather, etc.  
-  LONG *fcExchangeIndex )   // points to allocated exchange, 
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG ulStatus = 0;  // assume OK
-  USHORT ox_ID, rx_ID=0xFFFF;
-  ULONG SfsLen=0L;
-  TachLiteIRB* pIRB;
-  IRBflags IRB_flags;
-  UCHAR *pIRB_flags = (UCHAR*)&IRB_flags;
-  TachFCHDR_GCMND* CMDfchs;
-  TachFCHDR* dataHDR;     // 32 byte HEADER ONLY FCP-DATA buffer
-  TachFCHDR_RSP* rspHDR;     // 32 byte header + RSP payload
-  Scsi_Cmnd *Cmnd = (Scsi_Cmnd*)Data;   // Linux Scsi CDB, S/G, ...
-  TachLiteIWE* pIWE;
-  TachLiteIRE* pIRE;
-  TachLiteTWE* pTWE;
-  TachLiteTRE* pTRE;
-  ULONG fcp_dl;           // total byte length of DATA transferred
-  ULONG fl;               // frame length (FC frame size, 128, 256, 512, 1024)
-  ULONG sgPairs;          // number of valid scatter/gather pairs
-  int FCP_SCSI_command;
-  BA_ACC_PAYLOAD *ba_acc;
-  BA_RJT_PAYLOAD *ba_rjt;
-
-                          // check passed ARGS
-  if( !fcChip->ERQ )      // NULL ptr means uninitialized Tachlite chip
-    return INVALID_ARGS;
-
-
-  if( type == SCSI_IRE ||
-      type == SCSI_TRE ||
-      type == SCSI_IWE ||
-      type == SCSI_TWE)
-    FCP_SCSI_command = 1;
-
-  else
-    FCP_SCSI_command = 0;
-
-
-                     // for commands that pass payload data (e.g. SCSI write)
-                     // examine command struct - verify that the
-                     // length of s/g buffers is adequate for total payload
-                     // length (end of list is NULL address)
-
-  if( FCP_SCSI_command )
-  {
-    if( Data )     // must have data descriptor (S/G list -- at least
-                   // one address with at least 1 byte of data)
-    {
-      // something to do (later)?
-    }
-
-    else
-      return INVALID_ARGS;  // invalid DATA ptr
-  }
-
-    
-
-         // we can build an Exchange for later Queuing (on the TL chip)
-         // if an empty slot is available in the DevExt for this controller
-         // look for available Exchange slot...
-
-  if( type != FCP_RESPONSE &&
-      type != BLS_ABTS &&
-      type != BLS_ABTS_ACC )  // already have Exchange slot!
-    *fcExchangeIndex = FindFreeExchange( fcChip, type );
-
-  if( *fcExchangeIndex != -1 )   // Exchange is available?
-  {
-                     // assign tmp ptr (shorthand)
-    CMDfchs = &Exchanges->fcExchange[ *fcExchangeIndex].fchs; 
-
-    if( Cmnd != NULL ) // (necessary for ABTS cases)
-    {
-      Exchanges->fcExchange[ *fcExchangeIndex].Cmnd = Cmnd; // Linux Scsi
-      Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort = 
-	fcFindLoggedInPort( fcChip,
-          Exchanges->fcExchange[ *fcExchangeIndex].Cmnd, // find Scsi Nexus
-          0,        // DON'T search linked list for FC port id
-	  NULL,     // DON'T search linked list for FC WWN
-          NULL);    // DON'T care about end of list
-
-    }
-
-
-                     // Build the command frame header (& data) according
-                     // to command type
-
-                     // fields common for all SFS frame types
-    CMDfchs->reserved = 0L; // must clear
-    CMDfchs->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; LCr=0, no TS
-    
-             // get the destination port_id from incoming FCHS
-             // (initialized before calling if we're Originator)
-             // Frame goes to port it was from - the source_id
-    
-    CMDfchs->d_id = InFCHS->s_id &0xFFFFFF; // destination (add R_CTL later)
-    CMDfchs->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
+u32 cpqfcTSBuildExchange(CPQFCHBA * dev, u32 type,	// e.g. PLOGI
+			   TachFCHDR_GCMND * InFCHS,	// incoming FCHS
+			   void *Data,	// the CDB, scatter/gather, etc.  
+			   s32 * fcExchangeIndex)	// points to allocated exchange, 
+{
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 ulStatus = 0;	// assume OK
+	u16 ox_ID, rx_ID = 0xFFFF;
+	u32 SfsLen = 0L;
+	TachLiteIRB *pIRB;
+	IRBflags IRB_flags;
+	u8 *pIRB_flags = (u8 *) & IRB_flags;
+	TachFCHDR_GCMND *CMDfchs;
+	TachFCHDR *dataHDR;	// 32 byte HEADER ONLY FCP-DATA buffer
+	TachFCHDR_RSP *rspHDR;	// 32 byte header + RSP payload
+	Scsi_Cmnd *Cmnd = (Scsi_Cmnd *) Data;	// Linux Scsi CDB, S/G, ...
+	TachLiteIWE *pIWE;
+	TachLiteIRE *pIRE;
+	TachLiteTWE *pTWE;
+	TachLiteTRE *pTRE;
+	u32 fcp_dl;		// total byte length of DATA transferred
+	u32 fl;		// frame length (FC frame size, 128, 256, 512, 1024)
+	u32 sgPairs;		// number of valid scatter/gather pairs
+	int FCP_SCSI_command;
+	BA_ACC_PAYLOAD *ba_acc;
+	BA_RJT_PAYLOAD *ba_rjt;
+
+	// check passed ARGS
+	if (!fcChip->ERQ)	// NULL ptr means uninitialized Tachlite chip
+		return INVALID_ARGS;
 
-
-    // now enter command-specific fields
-    switch( type )
-    {
-
-    case BLS_NOP:   // FC defined basic link service command NO-OP
-                // ensure unique X_IDs! (use tracking function)
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 32L;        // add len to LSB (header only - no payload)
-
-                   // TYPE[31-24] 00 Basic Link Service
-                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-      CMDfchs->d_id |= 0x80000000L;  // R_CTL = 80 for NOP (Basic Link Ser.)
-      CMDfchs->f_ctl = 0x00310000L;  // xchng originator, 1st seq,....
-      CMDfchs->seq_cnt = 0x0L;
-      CMDfchs->ox_rx_id = 0xFFFF;        // RX_ID for now; OX_ID on start
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-      CMDfchs->pl[0] = 0xaabbccddL;   // words 8-15 frame data payload (n/a)
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // seconds
-                                      // (NOP should complete ~instantly)
-      break;
-
-
-    
-    
-    case BLS_ABTS_ACC:  // Abort Sequence ACCept
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 32 + 12;    // add len to LSB (header + 3 DWORD payload)
-
-      CMDfchs->d_id |= 0x84000000L;  // R_CTL = 84 for BASIC ACCept
-                   // TYPE[31-24] 00 Basic Link Service
-                   // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
-      CMDfchs->f_ctl = 0x00910000L;  // xchnge responder, last seq, xfer SI
-                   // CMDfchs->seq_id & count might be set from DataHdr?
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
-                        // (Timeout in case of weird error)
-      
-      // now set the ACCept payload...
-      ba_acc = (BA_ACC_PAYLOAD*)&CMDfchs->pl[0];
-      memset( ba_acc, 0, sizeof( BA_ACC_PAYLOAD));
-      // Since PLDA requires (only) entire Exchange aborts, we don't need
-      // to worry about what the last sequence was.
-
-      // We expect that a "target" task is accepting the abort, so we
-      // can use the OX/RX ID pair 
-      ba_acc->ox_rx_id = CMDfchs->ox_rx_id;
- 
-      // source, dest, #bytes
-      BigEndianSwap((UCHAR *)&CMDfchs->ox_rx_id, (UCHAR *)&ba_acc->ox_rx_id, 4);
-
-      ba_acc->low_seq_cnt = 0;
-      ba_acc->high_seq_cnt = 0xFFFF;
-
-
-      break;
-    
-
-    case BLS_ABTS_RJT:  // Abort Sequence ACCept
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 32 + 12;    // add len to LSB (header + 3 DWORD payload)
-
-      CMDfchs->d_id |= 0x85000000L;  // R_CTL = 85 for BASIC ReJecT
-                   // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
-                   // TYPE[31-24] 00 Basic Link Service
-      CMDfchs->f_ctl = 0x00910000L;  // xchnge responder, last seq, xfer SI
-                   // CMDfchs->seq_id & count might be set from DataHdr?
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
-                        // (Timeout in case of weird error)
-      
-      CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // copy from sender!
-      
-      // now set the ReJecT payload...
-      ba_rjt = (BA_RJT_PAYLOAD*)&CMDfchs->pl[0];
-      memset( ba_rjt, 0, sizeof( BA_RJT_PAYLOAD));
-
-      // We expect that a "target" task couldn't find the Exhange in the
-      // array of active exchanges, so we use a new LinkService X_ID.
-      // See Reject payload description in FC-PH (Rev 4.3), pg. 140
-      ba_rjt->reason_code = 0x09; // "unable to perform command request"
-      ba_rjt->reason_explain = 0x03; // invalid OX/RX ID pair
-
-
-      break;
-    
-    
-    case BLS_ABTS:   // FC defined basic link service command ABTS 
-                     // Abort Sequence
-                     
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 32L;        // add len to LSB (header only - no payload)
-
-                   // TYPE[31-24] 00 Basic Link Service
-                   // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
-      CMDfchs->d_id |= 0x81000000L;  // R_CTL = 81 for ABTS
-      CMDfchs->f_ctl = 0x00110000L;  // xchnge originator, last seq, xfer SI
-                   // CMDfchs->seq_id & count might be set from DataHdr?
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
-                        // (ABTS must timeout when responder is gone)
-      break;
-
-    
-    
-    case FCS_NSR:    // Fabric Name Service Request
-       Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
-
-
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
-                         // OX_ID, linked to Driver Transaction ID
-                         // (fix-up at Queing time)
-      CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
-                                    // OX_ID set at ERQueing time
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += (32L + sizeof(NSR_PL)); // add len (header & NSR payload)
-
-      CMDfchs->d_id |= 0x02000000L;  // R_CTL = 02 for -
-                                   // Name Service Request: Unsolicited 
-                   // TYPE[31-24] 01 Extended Link Service
-                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-      CMDfchs->f_ctl = 0x20210000L;
-                   // OX_ID will be fixed-up at Tachyon enqueing time
-      CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-      BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
-
-   
-    
-    
-    
-    
-      break;
-    
-    
-    
-    
-    case ELS_PLOGI:  // FC-PH extended link service command Port Login
-      // (May, 2000)
-      // NOTE! This special case facilitates SANMark testing.  The SANMark
-      // test script for initialization-timeout.fcal.SANMark-1.fc
-      // "eats" the OPN() primitive without issuing an R_RDY, causing
-      // Tachyon to report LST (loop state timeout), which causes a
-      // LIP.  To avoid this, simply send out the frame (i.e. assuming a
-      // buffer credit of 1) without waiting for R_RDY.  Many FC devices
-      // (other than Tachyon) have been doing this for years.  We don't
-      // ever want to do this for non-Link Service frames unless the
-      // other device really did report non-zero login BB credit (i.e.
-      // in the PLOGI ACCept frame).
-//      CMDfchs->sof_eof |= 0x00000400L;  // LCr=1
-    
-    case ELS_FDISC:  // Fabric Discovery (Login)
-    case ELS_FLOGI:  // Fabric Login
-    case ELS_SCR:    // Fabric State Change Registration
-    case ELS_LOGO:   // FC-PH extended link service command Port Logout
-    case ELS_PDISC:  // FC-PH extended link service cmnd Port Discovery
-    case ELS_PRLI:   // FC-PH extended link service cmnd Process Login
-
-      Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
-
-
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
-                         // OX_ID, linked to Driver Transaction ID
-                         // (fix-up at Queing time)
-      CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
-                                    // OX_ID set at ERQueing time
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      if( type == ELS_LOGO )
-        SfsLen += (32L + 16L); //  add len (header & PLOGI payload)
-      else if( type == ELS_PRLI )
-        SfsLen += (32L + 20L); //  add len (header & PRLI payload)
-      else if( type == ELS_SCR )
-        SfsLen += (32L + sizeof(SCR_PL)); //  add len (header & SCR payload)
-      else
-        SfsLen += (32L + 116L); //  add len (header & PLOGI payload)
-
-      CMDfchs->d_id |= 0x22000000L;  // R_CTL = 22 for -
-                                   // Extended Link_Data: Unsolicited Control
-                   // TYPE[31-24] 01 Extended Link Service
-                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-      CMDfchs->f_ctl = 0x01210000L;
-                   // OX_ID will be fixed-up at Tachyon enqueing time
-      CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-      BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
-
-      break;
-
-
-
-    case ELS_LOGO_ACC: // FC-PH extended link service logout accept
-    case ELS_RJT:          // extended link service reject (add reason)
-    case ELS_ACC:      // ext. link service generic accept
-    case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
-    case ELS_PRLI_ACC: // ext. link service process login accept
-
-
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // assume done
-                // ensure unique X_IDs! (use tracking function)
-                // OX_ID from initiator cmd
-      ox_ID = (USHORT)(InFCHS->ox_rx_id >> 16); 
-      rx_ID = 0xFFFF; // RX_ID, linked to Driver Exchange ID
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (not SEST index)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      if( type == ELS_RJT )
-      {
-        SfsLen += (32L + 8L); //  add len (header + payload)
-
-        // ELS_RJT reason codes (utilize unused "reserved" field)
-        CMDfchs->pl[0] = 1;
-        CMDfchs->pl[1] = InFCHS->reserved;  
-          
-      }
-      else if( (type == ELS_LOGO_ACC) || (type == ELS_ACC)  )
-        SfsLen += (32L + 4L); //  add len (header + payload)
-      else if( type == ELS_PLOGI_ACC )
-        SfsLen += (32L + 116L); //  add len (header + payload)
-      else if( type == ELS_PRLI_ACC )
-        SfsLen += (32L + 20L); //  add len (header + payload)
-
-      CMDfchs->d_id |= 0x23000000L;  // R_CTL = 23 for -
-                                   // Extended Link_Data: Control Reply
-                   // TYPE[31-24] 01 Extended Link Service
-                   // f_ctl[23:0] exchg responder, last seq, e_s, tsi
-      CMDfchs->f_ctl = 0x01990000L;
-      CMDfchs->seq_cnt = 0x0L;
-      CMDfchs->ox_rx_id = 0L;        // clear
-      CMDfchs->ox_rx_id = ox_ID; // load upper 16 bits
-      CMDfchs->ox_rx_id <<= 16;      // shift them
-
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-      BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
-
-      break;
-
-
-                         // Fibre Channel SCSI 'originator' sequences...
-                         // (originator means 'initiator' in FCP-SCSI)
-
-    case SCSI_IWE: // TachLite Initiator Write Entry
-    {
-      PFC_LOGGEDIN_PORT pLoggedInPort = 
-        Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort;
-
-      Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // FC2 timeout
-                       
-      // first, build FCP_CMND
-      // unique X_ID fix-ups in StartExchange 
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS FCP-CMND (not SEST index)
-
-      // NOTE: unlike FC LinkService login frames, normal
-      // SCSI commands are sent without outgoing verification
-      IRB_flags.DCM = 1;    // Disable completion message for Cmnd frame
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 64L;        // add len to LSB (header & CMND payload)
-
-      CMDfchs->d_id |= (0x06000000L);  // R_CTL = 6 for command
-
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-                   //             valid RO
-      CMDfchs->f_ctl = 0x08210008L;
-      CMDfchs->seq_cnt = 0x0L;
-      CMDfchs->ox_rx_id = 0L;        // clear for now (-or- in later)
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-                   // now, fill out FCP-DATA header
-                   // (use buffer inside SEST object)
-      dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
-      dataHDR->reserved = 0L; // must clear
-      dataHDR->sof_eof = 0x75002000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
-      dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
-      dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] xfer S.I.| valid RO
-      dataHDR->f_ctl = 0x08010008L;
-      dataHDR->seq_cnt = 0x02000000L;  // sequence ID: df_ctl : seqence count
-      dataHDR->ox_rx_id = 0L;        // clear; fix-up dataHDR fields later
-      dataHDR->ro = 0x0L;    // relative offset (n/a)
-
-                   // Now setup the SEST entry
-      pIWE = &fcChip->SEST->u[ *fcExchangeIndex ].IWE;
-      
-                   // fill out the IWE:
-
-                // VALid entry:Dir outbound:DCM:enable CM:enal INT: FC frame len
-      pIWE->Hdr_Len = 0x8e000020L; // data frame Len always 32 bytes
-      
-      
-      // from login parameters with other port, what's the largest frame
-      // we can send? 
-      if( pLoggedInPort == NULL) 
-      {
-	ulStatus = INVALID_ARGS;  // failed! give up
-	break;
-      }
-      if( pLoggedInPort->rx_data_size  >= 2048)
-        fl = 0x00020000;  // 2048 code (only support 1024!)
-      else if( pLoggedInPort->rx_data_size  >= 1024)
-        fl = 0x00020000;  // 1024 code
-      else if( pLoggedInPort->rx_data_size  >= 512)
-        fl = 0x00010000;  // 512 code
-      else
-	fl = 0;  // 128 bytes -- should never happen
-      
-      
-      pIWE->Hdr_Len |= fl; // add xmit FC frame len for data phase
-      pIWE->Hdr_Addr = fcChip->SEST->base + 
-		((unsigned long)&fcChip->SEST->DataHDR[*fcExchangeIndex] - 
-			(unsigned long)fcChip->SEST);
-
-      pIWE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
-      pIWE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-      
-      memset( &fcChip->SEST->RspHDR[ *fcExchangeIndex].pl, 0, 
-        sizeof( FCP_STATUS_RESPONSE) );  // clear out previous status
- 
-      pIWE->RSP_Addr = fcChip->SEST->base + 
-		((unsigned long)&fcChip->SEST->RspHDR[*fcExchangeIndex] - 
-			(unsigned long)fcChip->SEST);
-
-                   // Do we need local or extended gather list?
-                   // depends on size - we can handle 3 len/addr pairs
-                   // locally.
-
-      fcp_dl = build_SEST_sgList( 
-	cpqfcHBAdata->PciDev,
-        &pIWE->GLen1, 
-        Cmnd,       // S/G list
-        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
-        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-
-      if( !fcp_dl ) // error building S/G list?
-      {
-        ulStatus = MEMPOOL_FAIL;
-        break;      // give up
-      }
-
-                             // Now that we know total data length in
-                             // the passed S/G buffer, set FCP CMND frame
-      build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
-
-
-      
-      if( sgPairs > 3 )  // need extended s/g list
-        pIWE->Buff_Off = 0x78000000L; // extended data | (no offset)
-      else               // local data pointers (in SEST)
-        pIWE->Buff_Off = 0xf8000000L; // local data | (no offset)
-
-                              // ULONG 5
-      pIWE->Link = 0x0000ffffL;   // Buff_Index | Link
-
-      pIWE->RX_ID = 0x0L;     // DWord 6: RX_ID set by target XFER_RDY
-
-                                      // DWord 7
-      pIWE->Data_Len = 0L;    // TL enters rcv'd XFER_RDY BURST_LEN
-      pIWE->Exp_RO = 0L;      // DWord 8
-                              // DWord 9
-      pIWE->Exp_Byte_Cnt = fcp_dl;  // sum of gather buffers
-    }
-    break;
-
-
-
-
-
-    case SCSI_IRE: // TachLite Initiator Read Entry
-
-      if( Cmnd->timeout != 0)
-      {
-//	printk("Cmnd->timeout %d\n", Cmnd->timeout);
-	// per Linux Scsi
-        Exchanges->fcExchange[ *fcExchangeIndex].timeOut = Cmnd->timeout;
-      }
-      else  // use our best guess, based on FC & device
-      {
-
-        if( Cmnd->SCp.Message == 1 ) // Tape device? (from INQUIRY)	
-	{
-	  // turn off our timeouts (for now...)
-          Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 0xFFFFFFFF; 
-	}
+	if (type == SCSI_IRE || type == SCSI_TRE || type == SCSI_IWE || type == SCSI_TWE)
+		FCP_SCSI_command = 1;
 	else
-	{
-          Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
-          Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // per SCSI req.
-	}
-      }
-
-  
-      // first, build FCP_CMND
-
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS FCP-CMND (not SEST index)
-                            // NOTE: unlike FC LinkService login frames,
-                            // normal SCSI commands are sent "open loop"
-      IRB_flags.DCM = 1;    // Disable completion message for Cmnd frame
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += 64L;        // add len to LSB (header & CMND payload)
-
-      CMDfchs->d_id |= (0x06000000L);  // R_CTL = 6 for command
-
-             // TYPE[31-24] 8 for FCP SCSI
-             // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
-             //             valid RO
-      CMDfchs->f_ctl = 0x08210008L;
-      CMDfchs->seq_cnt = 0x0L;
-      // x_ID & data direction bit set later
-      CMDfchs->ox_rx_id = 0xFFFF;        // clear
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-
-
-                   // Now setup the SEST entry
-      pIRE = &fcChip->SEST->u[ *fcExchangeIndex ].IRE;
-
-      // fill out the IRE:
-      // VALid entry:Dir outbound:enable CM:enal INT:
-      pIRE->Seq_Accum = 0xCE000000L; // VAL,DIR inbound,DCM| INI,DAT,RSP
-
-      pIRE->reserved = 0L;
-      pIRE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
-      pIRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-
-      pIRE->RSP_Addr = fcChip->SEST->base + 
-		((unsigned long)&fcChip->SEST->RspHDR[*fcExchangeIndex] - 
-			(unsigned long)fcChip->SEST);
-      
-                   // Do we need local or extended gather list?
-                   // depends on size - we can handle 3 len/addr pairs
-                   // locally.
-
-      fcp_dl = build_SEST_sgList( 
-	cpqfcHBAdata->PciDev,
-        &pIRE->SLen1, 
-        Cmnd,       // SCSI command Data desc. with S/G list
-        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
-        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-      
-      
-      if( !fcp_dl ) // error building S/G list?
-      {
-	// It is permissible to have a ZERO LENGTH Read command.
-	// If there is the case, simply set fcp_dl (and Exp_Byte_Cnt)
-	// to 0 and continue.
-	if( Cmnd->request_bufflen == 0 )
-	{
-	  fcp_dl = 0; // no FC DATA frames expected
+		FCP_SCSI_command = 0;
 
+	// for commands that pass payload data (e.g. SCSI write)
+	// examine command struct - verify that the
+	// length of s/g buffers is adequate for total payload
+	// length (end of list is NULL address)
+
+	if (FCP_SCSI_command) {
+		if (Data)	// must have data descriptor (S/G list -- at least
+			// one address with at least 1 byte of data)
+		{
+			// something to do (later)?
+		}
+		else
+			return INVALID_ARGS;	// invalid DATA ptr
 	}
-	else
-	{
-          ulStatus = MEMPOOL_FAIL;
-          break;      // give up
-	}
-      }
-
-      // now that we know the S/G length, build CMND payload
-      build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
-
-      
-      if( sgPairs > 3 )  // need extended s/g list
-        pIRE->Buff_Off = 0x00000000; // DWord 4: extended s/g list, no offset
-      else
-        pIRE->Buff_Off = 0x80000000; // local data, no offset
-      
-      pIRE->Buff_Index = 0x0L;    // DWord 5: Buff_Index | Reserved
-
-      pIRE->Exp_RO  = 0x0L;       // DWord 6: Expected Rel. Offset
-
-      pIRE->Byte_Count = 0;  // DWord 7: filled in by TL on err
-      pIRE->reserved_ = 0;   // DWord 8: reserved
-                             // NOTE: 0 length READ is OK.
-      pIRE->Exp_Byte_Cnt = fcp_dl;// DWord 9: sum of scatter buffers
-      
-      break;
-
-
-
-
-                         // Fibre Channel SCSI 'responder' sequences...
-                         // (originator means 'target' in FCP-SCSI)
-    case SCSI_TWE: // TachLite Target Write Entry
-
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
-
-                       // first, build FCP_CMND
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (XFER_RDY)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
-
-      CMDfchs->d_id |= (0x05000000L);  // R_CTL = 5 for XFER_RDY
-
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] exchg responder, 1st seq, xfer S.I.
-                //             valid RO
-      CMDfchs->f_ctl = 0x08810008L;
-      CMDfchs->seq_cnt = 0x01000000; // sequence ID: df_ctl: sequence count
-                       // use originator (other port's) OX_ID
-      CMDfchs->ox_rx_id = InFCHS->ox_rx_id;     // we want upper 16 bits
-      CMDfchs->ro = 0x0L;    // relative offset (n/a)
-
-                   // now, fill out FCP-RSP header
-                   // (use buffer inside SEST object)
-
-      rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
-      rspHDR->reserved = 0L; // must clear
-      rspHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
-      rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
-      rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] responder|last seq| xfer S.I.
-      rspHDR->f_ctl = 0x08910000L;
-      rspHDR->seq_cnt = 0x03000000;  // sequence ID
-      rspHDR->ox_rx_id = InFCHS->ox_rx_id; // gives us OX_ID
-      rspHDR->ro = 0x0L;    // relative offset (n/a)
-
-
-                   // Now setup the SEST entry
-                   
-      pTWE = &fcChip->SEST->u[ *fcExchangeIndex ].TWE;
-
-      // fill out the TWE:
-
-      // VALid entry:Dir outbound:enable CM:enal INT:
-      pTWE->Seq_Accum = 0xC4000000L;  // upper word flags
-      pTWE->reserved = 0L;
-      pTWE->Remote_Node_ID = 0L; // no more auto RSP frame! (TL/TS change)
-      pTWE->Remote_Node_ID |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-      
-
-                   // Do we need local or extended gather list?
-                   // depends on size - we can handle 3 len/addr pairs
-                   // locally.
-
-      fcp_dl = build_SEST_sgList( 
-	cpqfcHBAdata->PciDev,
-        &pTWE->SLen1, 
-        Cmnd,       // S/G list
-        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
-        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-      
-      
-      if( !fcp_dl ) // error building S/G list?
-      {
-        ulStatus = MEMPOOL_FAIL;
-        break;      // give up
-      }
-
-      // now that we know the S/G length, build CMND payload
-      build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
-
-      
-      if( sgPairs > 3 )  // need extended s/g list
-        pTWE->Buff_Off = 0x00000000; // extended s/g list, no offset
-      else
-        pTWE->Buff_Off = 0x80000000; // local data, no offset
-      
-      pTWE->Buff_Index = 0;     // Buff_Index | Link
-      pTWE->Exp_RO = 0;
-      pTWE->Byte_Count = 0;  // filled in by TL on err
-      pTWE->reserved_ = 0;
-      pTWE->Exp_Byte_Cnt = fcp_dl;// sum of scatter buffers
-      
-      break;
-
-
-
-
-
-
-    case SCSI_TRE: // TachLite Target Read Entry
-
-      // It doesn't make much sense for us to "time-out" a READ,
-      // but we'll use it for design consistency and internal error recovery.
-      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
-
-      // I/O request block settings...
-      *pIRB_flags = 0;      // clear IRB flags
-                                  // check PRLI (process login) info
-                                  // to see if Initiator Requires XFER_RDY
-                                  // if not, don't send one!
-                                  // { PRLI check...}
-      IRB_flags.SFA = 0;    // don't send XFER_RDY - start data
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
-
 
-      
-      // now, fill out FCP-DATA header
-                   // (use buffer inside SEST object)
-      dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
-
-      dataHDR->reserved = 0L; // must clear
-      dataHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn no UAM; no CLS,noLCr,no TS
-      dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
-      dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
-
-
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] exchg responder, not 1st seq, xfer S.I.
-                   //             valid RO
-      dataHDR->f_ctl = 0x08810008L;
-      dataHDR->seq_cnt = 0x01000000;  // sequence ID (no XRDY)
-      dataHDR->ox_rx_id = InFCHS->ox_rx_id & 0xFFFF0000; // we want upper 16 bits
-      dataHDR->ro = 0x0L;    // relative offset (n/a)
-
-                   // now, fill out FCP-RSP header
-                   // (use buffer inside SEST object)
-      rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
-
-      rspHDR->reserved = 0L; // must clear
-      rspHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
-      rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
-      rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
-                   // TYPE[31-24] 8 for FCP SCSI
-                   // f_ctl[23:0] responder|last seq| xfer S.I.
-      rspHDR->f_ctl = 0x08910000L;
-      rspHDR->seq_cnt = 0x02000000;  // sequence ID: df_ctl: sequence count
-
-      rspHDR->ro = 0x0L;    // relative offset (n/a)
-
-
-      // Now setup the SEST entry
-      pTRE = &fcChip->SEST->u[ *fcExchangeIndex ].TRE;
-
-
-      // VALid entry:Dir outbound:enable CM:enal INT:
-      pTRE->Hdr_Len = 0x86010020L; // data frame Len always 32 bytes
-      pTRE->Hdr_Addr =  // bus address of dataHDR;
-            fcChip->SEST->base + 
-		((unsigned long)&fcChip->SEST->DataHDR[ *fcExchangeIndex ] -
-			(unsigned long)fcChip->SEST);
-	
-      pTRE->RSP_Len = 64L; // hdr+data (TL assisted RSP frame)
-      pTRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
-      pTRE->RSP_Addr = // bus address of rspHDR
-		fcChip->SEST->base + 
-			((unsigned long)&fcChip->SEST->RspHDR[ *fcExchangeIndex ] -
-				(unsigned long)fcChip->SEST);
-
-                   // Do we need local or extended gather list?
-                   // depends on size - we can handle 3 len/addr pairs
-                   // locally.
-
-      fcp_dl = build_SEST_sgList( 
-	cpqfcHBAdata->PciDev,
-        &pTRE->GLen1, 
-        Cmnd,       // S/G list
-        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
-        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
-      
-      
-      if( !fcp_dl ) // error building S/G list?
-      {
-        ulStatus = MEMPOOL_FAIL;
-        break;      // give up
-      }
-
-      // no payload or command to build -- READ doesn't need XRDY
-
-      
-      if( sgPairs > 3 )  // need extended s/g list
-        pTRE->Buff_Off = 0x78000000L; // extended data | (no offset)
-      else               // local data pointers (in SEST)
-        pTRE->Buff_Off = 0xf8000000L; // local data | (no offset)
-
-                                            // ULONG 5
-      pTRE->Buff_Index = 0L;   // Buff_Index | reserved
-      pTRE->reserved = 0x0L;   // DWord 6
-
-                                     // DWord 7: NOTE: zero length will
-                                     // hang TachLite!
-      pTRE->Data_Len = fcp_dl; // e.g. sum of scatter buffers
-
-      pTRE->reserved_ = 0L;     // DWord 8
-      pTRE->reserved__ = 0L;    // DWord 9
-
-      break;
+	// we can build an Exchange for later Queuing (on the TL chip)
+	// if an empty slot is available in the DevExt for this controller
+	// look for available Exchange slot...
 
+	if (type != FCP_RESPONSE && type != BLS_ABTS && type != BLS_ABTS_ACC)	// already have Exchange slot!
+		*fcExchangeIndex = FindFreeExchange(fcChip, type);
 
+	if (*fcExchangeIndex != -1)	// Exchange is available?
+	{
+		// assign tmp ptr (shorthand)
+		CMDfchs = &Exchanges->fcExchange[*fcExchangeIndex].fchs;
 
+		if (Cmnd != NULL)	// (necessary for ABTS cases)
+		{
+			Exchanges->fcExchange[*fcExchangeIndex].Cmnd = Cmnd;	// Linux Scsi
+			Exchanges->fcExchange[*fcExchangeIndex].pLoggedInPort = fcFindLoggedInPort(fcChip, Exchanges->fcExchange[*fcExchangeIndex].Cmnd,	// find Scsi Nexus
+												   0,	// DON'T search linked list for FC port id
+												   NULL,	// DON'T search linked list for FC WWN
+												   NULL);	// DON'T care about end of list
+		}
 
+		// Build the command frame header (& data) according
+		// to command type
 
-    
-
-    case FCP_RESPONSE: 
-                  // Target response frame: this sequence uses an OX/RX ID
-                  // pair from a completed SEST exchange.  We built most
-                  // of the response frame when we created the TWE/TRE.
-
-      *pIRB_flags = 0;      // clear IRB flags
-      IRB_flags.SFA = 1;    // send SFS (RSP)
-      SfsLen = *pIRB_flags;
-
-      SfsLen <<= 24;        // shift flags to MSB
-      SfsLen += sizeof(TachFCHDR_RSP);// add SFS len (header & RSP payload)
-      
-
-      Exchanges->fcExchange[ *fcExchangeIndex].type = 
-        FCP_RESPONSE; // change Exchange type to "response" phase
-
-      // take advantage of prior knowledge of OX/RX_ID pair from
-      // previous XFER outbound frame (still in fchs of exchange)
-      fcChip->SEST->RspHDR[ *fcExchangeIndex ].ox_rx_id = 
-        CMDfchs->ox_rx_id;
-
-      // Check the status of the DATA phase of the exchange so we can report
-      // status to the initiator
-      buildFCPstatus( fcChip, *fcExchangeIndex); // set RSP payload fields
-
-      memcpy(
-        CMDfchs,  // re-use same XFER fchs for Response frame
-        &fcChip->SEST->RspHDR[ *fcExchangeIndex ],
-        sizeof( TachFCHDR_RSP ));
-      
-        
-      break;
+		// fields common for all SFS frame types
+		CMDfchs->reserved = 0L;	// must clear
+		CMDfchs->sof_eof = 0x75000000L;	// SOFi3:EOFn  no UAM; LCr=0, no TS
+
+		// get the destination port_id from incoming FCHS
+		// (initialized before calling if we're Originator)
+		// Frame goes to port it was from - the source_id
+
+		CMDfchs->d_id = InFCHS->s_id & 0xFFFFFF;	// destination (add R_CTL later)
+		CMDfchs->s_id = fcChip->Registers.my_al_pa;	// CS_CTL = 0
+
+		// now enter command-specific fields
+		switch (type) {
+		case BLS_NOP:	// FC defined basic link service command NO-OP
+			// ensure unique X_IDs! (use tracking function)
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += 32L;	// add len to LSB (header only - no payload)
+
+			// TYPE[31-24] 00 Basic Link Service
+			// f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+			CMDfchs->d_id |= 0x80000000L;	// R_CTL = 80 for NOP (Basic Link Ser.)
+			CMDfchs->f_ctl = 0x00310000L;	// xchng originator, 1st seq,....
+			CMDfchs->seq_cnt = 0x0L;
+			CMDfchs->ox_rx_id = 0xFFFF;	// RX_ID for now; OX_ID on start
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+			CMDfchs->pl[0] = 0xaabbccddL;	// words 8-15 frame data payload (n/a)
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 1;	// seconds
+			// (NOP should complete ~instantly)
+			break;
+
+		case BLS_ABTS_ACC:	// Abort Sequence ACCept
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += 32 + 12;	// add len to LSB (header + 3 DWORD payload)
+
+			CMDfchs->d_id |= 0x84000000L;	// R_CTL = 84 for BASIC ACCept
+			// TYPE[31-24] 00 Basic Link Service
+			// f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
+			CMDfchs->f_ctl = 0x00910000L;	// xchnge responder, last seq, xfer SI
+			// CMDfchs->seq_id & count might be set from DataHdr?
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 5;	// seconds
+			// (Timeout in case of weird error)
+
+			// now set the ACCept payload...
+			ba_acc = (BA_ACC_PAYLOAD *) & CMDfchs->pl[0];
+			memset(ba_acc, 0, sizeof(BA_ACC_PAYLOAD));
+			// Since PLDA requires (only) entire Exchange aborts, we don't need
+			// to worry about what the last sequence was.
+
+			// We expect that a "target" task is accepting the abort, so we
+			// can use the OX/RX ID pair 
+			ba_acc->ox_rx_id = CMDfchs->ox_rx_id;
+
+			// source, dest, #bytes
+			BigEndianSwap((u8 *) & CMDfchs->ox_rx_id, (u8 *) & ba_acc->ox_rx_id, 4);
+
+			ba_acc->low_seq_cnt = 0;
+			ba_acc->high_seq_cnt = 0xFFFF;
+			break;
+
+		case BLS_ABTS_RJT:	// Abort Sequence ACCept
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += 32 + 12;	// add len to LSB (header + 3 DWORD payload)
+
+			CMDfchs->d_id |= 0x85000000L;	// R_CTL = 85 for BASIC ReJecT
+			// f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
+			// TYPE[31-24] 00 Basic Link Service
+			CMDfchs->f_ctl = 0x00910000L;	// xchnge responder, last seq, xfer SI
+			// CMDfchs->seq_id & count might be set from DataHdr?
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 5;	// seconds
+			// (Timeout in case of weird error)
+
+			CMDfchs->ox_rx_id = InFCHS->ox_rx_id;	// copy from sender!
+
+			// now set the ReJecT payload...
+			ba_rjt = (BA_RJT_PAYLOAD *) & CMDfchs->pl[0];
+			memset(ba_rjt, 0, sizeof(BA_RJT_PAYLOAD));
+
+			// We expect that a "target" task couldn't find the Exhange in the
+			// array of active exchanges, so we use a new LinkService X_ID.
+			// See Reject payload description in FC-PH (Rev 4.3), pg. 140
+			ba_rjt->reason_code = 0x09;	// "unable to perform command request"
+			ba_rjt->reason_explain = 0x03;	// invalid OX/RX ID pair
+			break;
+
+		case BLS_ABTS:	// FC defined basic link service command ABTS 
+			// Abort Sequence
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += 32L;	// add len to LSB (header only - no payload)
+
+			// TYPE[31-24] 00 Basic Link Service
+			// f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
+			CMDfchs->d_id |= 0x81000000L;	// R_CTL = 81 for ABTS
+			CMDfchs->f_ctl = 0x00110000L;	// xchnge originator, last seq, xfer SI
+			// CMDfchs->seq_id & count might be set from DataHdr?
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 2;	// seconds
+			// (ABTS must timeout when responder is gone)
+			break;
+
+		case FCS_NSR:	// Fabric Name Service Request
+			Exchanges->fcExchange[*fcExchangeIndex].reTries = 2;
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 2;	// seconds
+			// OX_ID, linked to Driver Transaction ID
+			// (fix-up at Queing time)
+			CMDfchs->ox_rx_id = 0xFFFF;	// RX_ID - Responder (target) to modify
+			// OX_ID set at ERQueing time
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += (32L + sizeof(NSR_PL));	// add len (header & NSR payload)
+			CMDfchs->d_id |= 0x02000000L;	// R_CTL = 02 for -
+			// Name Service Request: Unsolicited 
+			// TYPE[31-24] 01 Extended Link Service
+			// f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+			CMDfchs->f_ctl = 0x20210000L;
+			// OX_ID will be fixed-up at Tachyon enqueing time
+			CMDfchs->seq_cnt = 0;	// seq ID, DF_ctl, seq cnt
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+			BuildLinkServicePayload(fcChip, type, &CMDfchs->pl[0]);
+			break;
+
+		case ELS_PLOGI:	// FC-PH extended link service command Port Login
+			// (May, 2000)
+			// NOTE! This special case facilitates SANMark testing.  The SANMark
+			// test script for initialization-timeout.fcal.SANMark-1.fc
+			// "eats" the OPN() primitive without issuing an R_RDY, causing
+			// Tachyon to report LST (loop state timeout), which causes a
+			// LIP.  To avoid this, simply send out the frame (i.e. assuming a
+			// buffer credit of 1) without waiting for R_RDY.  Many FC devices
+			// (other than Tachyon) have been doing this for years.  We don't
+			// ever want to do this for non-Link Service frames unless the
+			// other device really did report non-zero login BB credit (i.e.
+			// in the PLOGI ACCept frame).
+//			CMDfchs->sof_eof |= 0x00000400L;  // LCr=1
+
+		case ELS_FDISC:	// Fabric Discovery (Login)
+		case ELS_FLOGI:	// Fabric Login
+		case ELS_SCR:	// Fabric State Change Registration
+		case ELS_LOGO:	// FC-PH extended link service command Port Logout
+		case ELS_PDISC:	// FC-PH extended link service cmnd Port Discovery
+		case ELS_PRLI:	// FC-PH extended link service cmnd Process Login
+			Exchanges->fcExchange[*fcExchangeIndex].reTries = 2;
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 2;	// seconds
+			// OX_ID, linked to Driver Transaction ID
+			// (fix-up at Queing time)
+			CMDfchs->ox_rx_id = 0xFFFF;	// RX_ID - Responder (target) to modify
+			// OX_ID set at ERQueing time
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+			SfsLen <<= 24;	// shift flags to MSB
+			if (type == ELS_LOGO)
+				SfsLen += (32L + 16L);	//  add len (header & PLOGI payload)
+			else if (type == ELS_PRLI)
+				SfsLen += (32L + 20L);	//  add len (header & PRLI payload)
+			else if (type == ELS_SCR)
+				SfsLen += (32L + sizeof(SCR_PL));	//  add len (header & SCR payload)
+			else
+				SfsLen += (32L + 116L);	//  add len (header & PLOGI payload)
+
+			CMDfchs->d_id |= 0x22000000L;	// R_CTL = 22 for -
+			// Extended Link_Data: Unsolicited Control
+			// TYPE[31-24] 01 Extended Link Service
+			// f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+			CMDfchs->f_ctl = 0x01210000L;
+			// OX_ID will be fixed-up at Tachyon enqueing time
+			CMDfchs->seq_cnt = 0;	// seq ID, DF_ctl, seq cnt
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+
+			BuildLinkServicePayload(fcChip, type, &CMDfchs->pl[0]);
+			break;
+
+		case ELS_LOGO_ACC:	// FC-PH extended link service logout accept
+		case ELS_RJT:	// extended link service reject (add reason)
+		case ELS_ACC:	// ext. link service generic accept
+		case ELS_PLOGI_ACC:	// ext. link service login accept (PLOGI or PDISC)
+		case ELS_PRLI_ACC:	// ext. link service process login accept
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 1;	// assume done
+			// ensure unique X_IDs! (use tracking function)
+			// OX_ID from initiator cmd
+			ox_ID = (u16) (InFCHS->ox_rx_id >> 16);
+			rx_ID = 0xFFFF;	// RX_ID, linked to Driver Exchange ID
+
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (not SEST index)
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			if (type == ELS_RJT) {
+				SfsLen += (32L + 8L);	//  add len (header + payload)
+
+				// ELS_RJT reason codes (utilize unused "reserved" field)
+				CMDfchs->pl[0] = 1;
+				CMDfchs->pl[1] = InFCHS->reserved;
+
+			} else if ((type == ELS_LOGO_ACC) || (type == ELS_ACC))
+				SfsLen += (32L + 4L);	//  add len (header + payload)
+			else if (type == ELS_PLOGI_ACC)
+				SfsLen += (32L + 116L);	//  add len (header + payload)
+			else if (type == ELS_PRLI_ACC)
+				SfsLen += (32L + 20L);	//  add len (header + payload)
+
+			CMDfchs->d_id |= 0x23000000L;	// R_CTL = 23 for -
+			// Extended Link_Data: Control Reply
+			// TYPE[31-24] 01 Extended Link Service
+			// f_ctl[23:0] exchg responder, last seq, e_s, tsi
+			CMDfchs->f_ctl = 0x01990000L;
+			CMDfchs->seq_cnt = 0x0L;
+			CMDfchs->ox_rx_id = 0L;	// clear
+			CMDfchs->ox_rx_id = ox_ID;	// load upper 16 bits
+			CMDfchs->ox_rx_id <<= 16;	// shift them
+
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+
+			BuildLinkServicePayload(fcChip, type, &CMDfchs->pl[0]);
+			break;
+
+			// Fibre Channel SCSI 'originator' sequences...
+			// (originator means 'initiator' in FCP-SCSI)
+		case SCSI_IWE:	// TachLite Initiator Write Entry
+			{
+				PFC_LOGGEDIN_PORT pLoggedInPort = Exchanges->fcExchange[*fcExchangeIndex].pLoggedInPort;
+
+				Exchanges->fcExchange[*fcExchangeIndex].reTries = 1;
+				Exchanges->fcExchange[*fcExchangeIndex].timeOut = 7;	// FC2 timeout
+
+				// first, build FCP_CMND
+				// unique X_ID fix-ups in StartExchange 
+
+				*pIRB_flags = 0;	// clear IRB flags
+				IRB_flags.SFA = 1;	// send SFS FCP-CMND (not SEST index)
+
+				// NOTE: unlike FC LinkService login frames, normal
+				// SCSI commands are sent without outgoing verification
+				IRB_flags.DCM = 1;	// Disable completion message for Cmnd frame
+				SfsLen = *pIRB_flags;
+
+				SfsLen <<= 24;	// shift flags to MSB
+				SfsLen += 64L;	// add len to LSB (header & CMND payload)
+
+				CMDfchs->d_id |= (0x06000000L);	// R_CTL = 6 for command
+
+				// TYPE[31-24] 8 for FCP SCSI
+				// f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+				//             valid RO
+				CMDfchs->f_ctl = 0x08210008L;
+				CMDfchs->seq_cnt = 0x0L;
+				CMDfchs->ox_rx_id = 0L;	// clear for now (-or- in later)
+				CMDfchs->ro = 0x0L;	// relative offset (n/a)
+
+				// now, fill out FCP-DATA header
+				// (use buffer inside SEST object)
+				dataHDR = &fcChip->SEST->DataHDR[*fcExchangeIndex];
+				dataHDR->reserved = 0L;	// must clear
+				dataHDR->sof_eof = 0x75002000L;	// SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
+				dataHDR->d_id = (InFCHS->s_id | 0x01000000L);	// R_CTL= FCP_DATA
+				dataHDR->s_id = fcChip->Registers.my_al_pa;	// CS_CTL = 0
+				// TYPE[31-24] 8 for FCP SCSI
+				// f_ctl[23:0] xfer S.I.| valid RO
+				dataHDR->f_ctl = 0x08010008L;
+				dataHDR->seq_cnt = 0x02000000L;	// sequence ID: df_ctl : seqence count
+				dataHDR->ox_rx_id = 0L;	// clear; fix-up dataHDR fields later
+				dataHDR->ro = 0x0L;	// relative offset (n/a)
+
+				// Now setup the SEST entry
+				pIWE = &fcChip->SEST->u[*fcExchangeIndex].IWE;
+
+				// fill out the IWE:
+
+				// VALid entry:Dir outbound:DCM:enable CM:enal INT: FC frame len
+				pIWE->Hdr_Len = 0x8e000020L;	// data frame Len always 32 bytes
+
+
+				// from login parameters with other port, what's the largest frame
+				// we can send? 
+				if (pLoggedInPort == NULL) {
+					ulStatus = INVALID_ARGS;	// failed! give up
+					break;
+				}
+				if (pLoggedInPort->rx_data_size >= 2048)
+					fl = 0x00020000;	// 2048 code (only support 1024!)
+				else if (pLoggedInPort->rx_data_size >= 1024)
+					fl = 0x00020000;	// 1024 code
+				else if (pLoggedInPort->rx_data_size >= 512)
+					fl = 0x00010000;	// 512 code
+				else
+					fl = 0;	// 128 bytes -- should never happen
+
+
+				pIWE->Hdr_Len |= fl;	// add xmit FC frame len for data phase
+				pIWE->Hdr_Addr = fcChip->SEST->base + ((unsigned long) &fcChip->SEST->DataHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+				pIWE->RSP_Len = sizeof(TachFCHDR_RSP);	// hdr+data (recv'd RSP frame)
+				pIWE->RSP_Len |= (InFCHS->s_id << 8);	// MS 24 bits Remote_ID
+
+				memset(&fcChip->SEST->RspHDR[*fcExchangeIndex].pl, 0, sizeof(FCP_STATUS_RESPONSE));	// clear out previous status
+
+				pIWE->RSP_Addr = fcChip->SEST->base + ((unsigned long) &fcChip->SEST->RspHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+				// Do we need local or extended gather list?
+				// depends on size - we can handle 3 len/addr pairs
+				// locally.
+
+				fcp_dl = build_SEST_sgList(dev->PciDev, &pIWE->GLen1, Cmnd,	// S/G list
+							   &sgPairs,	// return # of pairs in S/G list (from "Data" descriptor)
+							   &fcChip->SEST->sgPages[*fcExchangeIndex]);	// (for Freeing later)
+
+				if (!fcp_dl)	// error building S/G list?
+				{
+					ulStatus = MEMPOOL_FAIL;
+					break;	// give up
+				}
+				// Now that we know total data length in
+				// the passed S/G buffer, set FCP CMND frame
+				build_FCP_payload(Cmnd, (u8 *) & CMDfchs->pl[0], type, fcp_dl);
+
+
+
+				if (sgPairs > 3)	// need extended s/g list
+					pIWE->Buff_Off = 0x78000000L;	// extended data | (no offset)
+				else	// local data pointers (in SEST)
+					pIWE->Buff_Off = 0xf8000000L;	// local data | (no offset)
+
+				// u32 5
+				pIWE->Link = 0x0000ffffL;	// Buff_Index | Link
+
+				pIWE->RX_ID = 0x0L;	// DWord 6: RX_ID set by target XFER_RDY
+
+				// DWord 7
+				pIWE->Data_Len = 0L;	// TL enters rcv'd XFER_RDY BURST_LEN
+				pIWE->Exp_RO = 0L;	// DWord 8
+				// DWord 9
+				pIWE->Exp_Byte_Cnt = fcp_dl;	// sum of gather buffers
+			}
+			break;
 
-    default:
-      printk("cpqfcTS: don't know how to build FC type: %Xh(%d)\n", type,type);
-      break;
+		case SCSI_IRE:	// TachLite Initiator Read Entry
+			if (Cmnd->timeout != 0) {
+//      printk("Cmnd->timeout %d\n", Cmnd->timeout);
+				// per Linux Scsi
+				Exchanges->fcExchange[*fcExchangeIndex].timeOut = Cmnd->timeout;
+			} else	// use our best guess, based on FC & device
+			{
+
+				if (Cmnd->SCp.Message == 1)	// Tape device? (from INQUIRY)     
+				{
+					// turn off our timeouts (for now...)
+					Exchanges->fcExchange[*fcExchangeIndex].timeOut = 0xFFFFFFFF;
+				} else {
+					Exchanges->fcExchange[*fcExchangeIndex].reTries = 1;
+					Exchanges->fcExchange[*fcExchangeIndex].timeOut = 7;	// per SCSI req.
+				}
+			}
+			// first, build FCP_CMND
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS FCP-CMND (not SEST index)
+			// NOTE: unlike FC LinkService login frames,
+			// normal SCSI commands are sent "open loop"
+			IRB_flags.DCM = 1;	// Disable completion message for Cmnd frame
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += 64L;	// add len to LSB (header & CMND payload)
+
+			CMDfchs->d_id |= (0x06000000L);	// R_CTL = 6 for command
+
+			// TYPE[31-24] 8 for FCP SCSI
+			// f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+			//             valid RO
+			CMDfchs->f_ctl = 0x08210008L;
+			CMDfchs->seq_cnt = 0x0L;
+			// x_ID & data direction bit set later
+			CMDfchs->ox_rx_id = 0xFFFF;	// clear
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+			// Now setup the SEST entry
+			pIRE = &fcChip->SEST->u[*fcExchangeIndex].IRE;
+			// fill out the IRE:
+			// VALid entry:Dir outbound:enable CM:enal INT:
+			pIRE->Seq_Accum = 0xCE000000L;	// VAL,DIR inbound,DCM| INI,DAT,RSP
+
+			pIRE->reserved = 0L;
+			pIRE->RSP_Len = sizeof(TachFCHDR_RSP);	// hdr+data (recv'd RSP frame)
+			pIRE->RSP_Len |= (InFCHS->s_id << 8);	// MS 24 bits Remote_ID
+
+			pIRE->RSP_Addr = fcChip->SEST->base + ((unsigned long) &fcChip->SEST->RspHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+			// Do we need local or extended gather list?
+			// depends on size - we can handle 3 len/addr pairs
+			// locally.
+
+			fcp_dl = build_SEST_sgList(dev->PciDev, &pIRE->SLen1, Cmnd,	// SCSI command Data desc. with S/G list
+						   &sgPairs,	// return # of pairs in S/G list (from "Data" descriptor)
+						   &fcChip->SEST->sgPages[*fcExchangeIndex]);	// (for Freeing later)
+
+
+			if (!fcp_dl)	// error building S/G list?
+			{
+				// It is permissible to have a ZERO LENGTH Read command.
+				// If there is the case, simply set fcp_dl (and Exp_Byte_Cnt)
+				// to 0 and continue.
+				if (Cmnd->request_bufflen == 0) {
+					fcp_dl = 0;	// no FC DATA frames expected
+
+				} else {
+					ulStatus = MEMPOOL_FAIL;
+					break;	// give up
+				}
+			}
+			// now that we know the S/G length, build CMND payload
+			build_FCP_payload(Cmnd, (u8 *) & CMDfchs->pl[0], type, fcp_dl);
 
-    }
 
-    
-    
-    if( !ulStatus)  // no errors above?
-    {
-      // FCHS is built; now build IRB
+			if (sgPairs > 3)	// need extended s/g list
+				pIRE->Buff_Off = 0x00000000;	// DWord 4: extended s/g list, no offset
+			else
+				pIRE->Buff_Off = 0x80000000;	// local data, no offset
+
+			pIRE->Buff_Index = 0x0L;	// DWord 5: Buff_Index | Reserved
+
+			pIRE->Exp_RO = 0x0L;	// DWord 6: Expected Rel. Offset
+
+			pIRE->Byte_Count = 0;	// DWord 7: filled in by TL on err
+			pIRE->reserved_ = 0;	// DWord 8: reserved
+			// NOTE: 0 length READ is OK.
+			pIRE->Exp_Byte_Cnt = fcp_dl;	// DWord 9: sum of scatter buffers
+			break;
+
+			// Fibre Channel SCSI 'responder' sequences...
+			// (originator means 'target' in FCP-SCSI)
+		case SCSI_TWE:	// TachLite Target Write Entry
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 10;	// per SCSI req.
+			// first, build FCP_CMND
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (XFER_RDY)
+			SfsLen = *pIRB_flags;
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += (32L + 12L);	// add SFS len (header & XFER_RDY payload)
+
+			CMDfchs->d_id |= (0x05000000L);	// R_CTL = 5 for XFER_RDY
+
+			// TYPE[31-24] 8 for FCP SCSI
+			// f_ctl[23:0] exchg responder, 1st seq, xfer S.I.
+			//             valid RO
+			CMDfchs->f_ctl = 0x08810008L;
+			CMDfchs->seq_cnt = 0x01000000;	// sequence ID: df_ctl: sequence count
+			// use originator (other port's) OX_ID
+			CMDfchs->ox_rx_id = InFCHS->ox_rx_id;	// we want upper 16 bits
+			CMDfchs->ro = 0x0L;	// relative offset (n/a)
+
+			// now, fill out FCP-RSP header
+			// (use buffer inside SEST object)
+
+			rspHDR = &fcChip->SEST->RspHDR[*fcExchangeIndex];
+			rspHDR->reserved = 0L;	// must clear
+			rspHDR->sof_eof = 0x75000000L;	// SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
+			rspHDR->d_id = (InFCHS->s_id | 0x07000000L);	// R_CTL= FCP_RSP
+			rspHDR->s_id = fcChip->Registers.my_al_pa;	// CS_CTL = 0
+			// TYPE[31-24] 8 for FCP SCSI
+			// f_ctl[23:0] responder|last seq| xfer S.I.
+			rspHDR->f_ctl = 0x08910000L;
+			rspHDR->seq_cnt = 0x03000000;	// sequence ID
+			rspHDR->ox_rx_id = InFCHS->ox_rx_id;	// gives us OX_ID
+			rspHDR->ro = 0x0L;	// relative offset (n/a)
+			// Now setup the SEST entry
+
+			pTWE = &fcChip->SEST->u[*fcExchangeIndex].TWE;
+			// fill out the TWE:
+
+			// VALid entry:Dir outbound:enable CM:enal INT:
+			pTWE->Seq_Accum = 0xC4000000L;	// upper word flags
+			pTWE->reserved = 0L;
+			pTWE->Remote_Node_ID = 0L;	// no more auto RSP frame! (TL/TS change)
+			pTWE->Remote_Node_ID |= (InFCHS->s_id << 8);	// MS 24 bits Remote_ID
+
+			// Do we need local or extended gather list?
+			// depends on size - we can handle 3 len/addr pairs
+			// locally.
+
+			fcp_dl = build_SEST_sgList(dev->PciDev, &pTWE->SLen1, Cmnd,	// S/G list
+						   &sgPairs,	// return # of pairs in S/G list (from "Data" descriptor)
+						   &fcChip->SEST->sgPages[*fcExchangeIndex]);	// (for Freeing later)
+
+			if (!fcp_dl)	// error building S/G list?
+			{
+				ulStatus = MEMPOOL_FAIL;
+				break;	// give up
+			}
+			// now that we know the S/G length, build CMND payload
+			build_FCP_payload(Cmnd, (u8 *) & CMDfchs->pl[0], type, fcp_dl);
 
-      // link the just built FCHS (the "command") to the IRB entry 
-      // for this Exchange.
-      pIRB = &Exchanges->fcExchange[ *fcExchangeIndex].IRB; 
-    
-                          // len & flags according to command type above
-      pIRB->Req_A_SFS_Len = SfsLen;  // includes IRB flags & len
-      pIRB->Req_A_SFS_Addr = // TL needs physical addr of frame to send
-		fcChip->exch_dma_handle + (unsigned long)CMDfchs - 
-			(unsigned long)Exchanges;
-
-      pIRB->Req_A_SFS_D_ID = CMDfchs->d_id << 8; // Dest_ID must be consistent!
-
-    // Exchange is complete except for "fix-up" fields to be set
-    // at Tachyon Queuing time:
-    //    IRB->Req_A_Trans_ID (OX_ID/ RX_ID):  
-    //        for SEST entry, lower bits correspond to actual FC Exchange ID
-    //    fchs->OX_ID or RX_ID
-    }
-    else
-    {
-#ifdef DBG     
-      printk( "FC Error: SEST build Pool Allocation failed\n");
+			if (sgPairs > 3)	// need extended s/g list
+				pTWE->Buff_Off = 0x00000000;	// extended s/g list, no offset
+			else
+				pTWE->Buff_Off = 0x80000000;	// local data, no offset
+
+			pTWE->Buff_Index = 0;	// Buff_Index | Link
+			pTWE->Exp_RO = 0;
+			pTWE->Byte_Count = 0;	// filled in by TL on err
+			pTWE->reserved_ = 0;
+			pTWE->Exp_Byte_Cnt = fcp_dl;	// sum of scatter buffers
+			break;
+
+		case SCSI_TRE:	// TachLite Target Read Entry
+			// It doesn't make much sense for us to "time-out" a READ,
+			// but we'll use it for design consistency and internal error recovery.
+			Exchanges->fcExchange[*fcExchangeIndex].timeOut = 10;	// per SCSI req.
+			// I/O request block settings...
+			*pIRB_flags = 0;	// clear IRB flags
+			// check PRLI (process login) info
+			// to see if Initiator Requires XFER_RDY
+			// if not, don't send one!
+			// { PRLI check...}
+			IRB_flags.SFA = 0;	// don't send XFER_RDY - start data
+			SfsLen = *pIRB_flags;
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += (32L + 12L);	// add SFS len (header & XFER_RDY payload)
+
+			// now, fill out FCP-DATA header
+			// (use buffer inside SEST object)
+			dataHDR = &fcChip->SEST->DataHDR[*fcExchangeIndex];
+
+			dataHDR->reserved = 0L;	// must clear
+			dataHDR->sof_eof = 0x75000000L;	// SOFi3:EOFn no UAM; no CLS,noLCr,no TS
+			dataHDR->d_id = (InFCHS->s_id | 0x01000000L);	// R_CTL= FCP_DATA
+			dataHDR->s_id = fcChip->Registers.my_al_pa;	// CS_CTL = 0
+
+			// TYPE[31-24] 8 for FCP SCSI
+			// f_ctl[23:0] exchg responder, not 1st seq, xfer S.I.
+			//             valid RO
+			dataHDR->f_ctl = 0x08810008L;
+			dataHDR->seq_cnt = 0x01000000;	// sequence ID (no XRDY)
+			dataHDR->ox_rx_id = InFCHS->ox_rx_id & 0xFFFF0000;	// we want upper 16 bits
+			dataHDR->ro = 0x0L;	// relative offset (n/a)
+
+			// now, fill out FCP-RSP header
+			// (use buffer inside SEST object)
+			rspHDR = &fcChip->SEST->RspHDR[*fcExchangeIndex];
+
+			rspHDR->reserved = 0L;	// must clear
+			rspHDR->sof_eof = 0x75000000L;	// SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
+			rspHDR->d_id = (InFCHS->s_id | 0x07000000L);	// R_CTL= FCP_RSP
+			rspHDR->s_id = fcChip->Registers.my_al_pa;	// CS_CTL = 0
+			// TYPE[31-24] 8 for FCP SCSI
+			// f_ctl[23:0] responder|last seq| xfer S.I.
+			rspHDR->f_ctl = 0x08910000L;
+			rspHDR->seq_cnt = 0x02000000;	// sequence ID: df_ctl: sequence count
+			rspHDR->ro = 0x0L;	// relative offset (n/a)
+
+			// Now setup the SEST entry
+			pTRE = &fcChip->SEST->u[*fcExchangeIndex].TRE;
+
+			// VALid entry:Dir outbound:enable CM:enal INT:
+			pTRE->Hdr_Len = 0x86010020L;	// data frame Len always 32 bytes
+			pTRE->Hdr_Addr =	// bus address of dataHDR;
+			    fcChip->SEST->base + ((unsigned long) &fcChip->SEST->DataHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+			pTRE->RSP_Len = 64L;	// hdr+data (TL assisted RSP frame)
+			pTRE->RSP_Len |= (InFCHS->s_id << 8);	// MS 24 bits Remote_ID
+			pTRE->RSP_Addr =	// bus address of rspHDR
+			    fcChip->SEST->base + ((unsigned long) &fcChip->SEST->RspHDR[*fcExchangeIndex] - (unsigned long) fcChip->SEST);
+
+			// Do we need local or extended gather list?
+			// depends on size - we can handle 3 len/addr pairs
+			// locally.
+
+			fcp_dl = build_SEST_sgList(dev->PciDev, &pTRE->GLen1, Cmnd,	// S/G list
+						   &sgPairs,	// return # of pairs in S/G list (from "Data" descriptor)
+						   &fcChip->SEST->sgPages[*fcExchangeIndex]);	// (for Freeing later)
+
+			if (!fcp_dl)	// error building S/G list?
+			{
+				ulStatus = MEMPOOL_FAIL;
+				break;	// give up
+			}
+			// no payload or command to build -- READ doesn't need XRDY
+			if (sgPairs > 3)	// need extended s/g list
+				pTRE->Buff_Off = 0x78000000L;	// extended data | (no offset)
+			else	// local data pointers (in SEST)
+				pTRE->Buff_Off = 0xf8000000L;	// local data | (no offset)
+
+			// u32 5
+			pTRE->Buff_Index = 0L;	// Buff_Index | reserved
+			pTRE->reserved = 0x0L;	// DWord 6
+
+			// DWord 7: NOTE: zero length will
+			// hang TachLite!
+			pTRE->Data_Len = fcp_dl;	// e.g. sum of scatter buffers
+
+			pTRE->reserved_ = 0L;	// DWord 8
+			pTRE->reserved__ = 0L;	// DWord 9
+
+			break;
+
+		case FCP_RESPONSE:
+			// Target response frame: this sequence uses an OX/RX ID
+			// pair from a completed SEST exchange.  We built most
+			// of the response frame when we created the TWE/TRE.
+
+			*pIRB_flags = 0;	// clear IRB flags
+			IRB_flags.SFA = 1;	// send SFS (RSP)
+			SfsLen = *pIRB_flags;
+
+			SfsLen <<= 24;	// shift flags to MSB
+			SfsLen += sizeof(TachFCHDR_RSP);	// add SFS len (header & RSP payload)
+			Exchanges->fcExchange[*fcExchangeIndex].type = FCP_RESPONSE;	// change Exchange type to "response" phase
+
+			// take advantage of prior knowledge of OX/RX_ID pair from
+			// previous XFER outbound frame (still in fchs of exchange)
+			fcChip->SEST->RspHDR[*fcExchangeIndex].ox_rx_id = CMDfchs->ox_rx_id;
+
+			// Check the status of the DATA phase of the exchange so we can report
+			// status to the initiator
+			buildFCPstatus(fcChip, *fcExchangeIndex);	// set RSP payload fields
+
+			memcpy(CMDfchs,	// re-use same XFER fchs for Response frame
+			       &fcChip->SEST->RspHDR[*fcExchangeIndex], sizeof(TachFCHDR_RSP));
+			break;
+
+		default:
+			printk("cpqfcTS: don't know how to build FC type: %Xh(%d)\n", type, type);
+			break;
+		}
+		if (!ulStatus)	// no errors above?
+		{
+			// FCHS is built; now build IRB
+
+			// link the just built FCHS (the "command") to the IRB entry 
+			// for this Exchange.
+			pIRB = &Exchanges->fcExchange[*fcExchangeIndex].IRB;
+
+			// len & flags according to command type above
+			pIRB->Req_A_SFS_Len = SfsLen;	// includes IRB flags & len
+			pIRB->Req_A_SFS_Addr =	// TL needs physical addr of frame to send
+			    fcChip->exch_dma_handle + (unsigned long) CMDfchs - (unsigned long) Exchanges;
+
+			pIRB->Req_A_SFS_D_ID = CMDfchs->d_id << 8;	// Dest_ID must be consistent!
+
+			// Exchange is complete except for "fix-up" fields to be set
+			// at Tachyon Queuing time:
+			//    IRB->Req_A_Trans_ID (OX_ID/ RX_ID):  
+			//        for SEST entry, lower bits correspond to actual FC Exchange ID
+			//    fchs->OX_ID or RX_ID
+		} else {
+#ifdef DBG
+			printk("FC Error: SEST build Pool Allocation failed\n");
 #endif
-      // return resources...
-      cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, *fcExchangeIndex);  // SEST build failed
-    }
-  }
-  else  // no Exchanges available
-  {
-    ulStatus = SEST_FULL;
-    printk( "FC Error: no fcExchanges available\n");
-  }
-  return ulStatus;
+			// return resources...
+			cpqfcTSCompleteExchange(dev->PciDev, fcChip, *fcExchangeIndex);	// SEST build failed
+		}
+	} else			// no Exchanges available
+	{
+		ulStatus = SEST_FULL;
+		printk("FC Error: no fcExchanges available\n");
+	}
+	return ulStatus;
 }
 
-
-
-
-
-
 // set RSP payload fields
-static void  buildFCPstatus( PTACHYON fcChip, ULONG ExchangeID) 
+static void buildFCPstatus(PTACHYON fcChip, u32 ExchangeID)
 {
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID];  // shorthand
-  PFCP_STATUS_RESPONSE pFcpStatus;
-  
-  memset( &fcChip->SEST->RspHDR[ ExchangeID ].pl, 0,
-    sizeof( FCP_STATUS_RESPONSE) );
-  if( pExchange->status ) // something wrong?
-  {
-    pFcpStatus = (PFCP_STATUS_RESPONSE)  // cast RSP buffer for this xchng
-      &fcChip->SEST->RspHDR[ ExchangeID ].pl;
-    if( pExchange->status & COUNT_ERROR )
-    {
-      
-      // set FCP response len valid (so we can report count error)
-      pFcpStatus->fcp_status |= FCP_RSP_LEN_VALID;
-      pFcpStatus->fcp_rsp_len = 0x04000000;  // 4 byte len (BIG Endian)
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID];	// shorthand
+	PFCP_STATUS_RESPONSE pFcpStatus;
 
-      pFcpStatus->fcp_rsp_info = FCP_DATA_LEN_NOT_BURST_LEN; // RSP_CODE
-    }
-  }
+	memset(&fcChip->SEST->RspHDR[ExchangeID].pl, 0, sizeof(FCP_STATUS_RESPONSE));
+	if (pExchange->status)	// something wrong?
+	{
+		pFcpStatus = (PFCP_STATUS_RESPONSE)	// cast RSP buffer for this xchng
+		    & fcChip->SEST->RspHDR[ExchangeID].pl;
+		if (pExchange->status & COUNT_ERROR) {
+
+			// set FCP response len valid (so we can report count error)
+			pFcpStatus->fcp_status |= FCP_RSP_LEN_VALID;
+			pFcpStatus->fcp_rsp_len = 0x04000000;	// 4 byte len (BIG Endian)
+
+			pFcpStatus->fcp_rsp_info = FCP_DATA_LEN_NOT_BURST_LEN;	// RSP_CODE
+		}
+	}
 }
 
 
-static dma_addr_t 
-cpqfc_pci_map_sg_page(
-    		struct pci_dev *pcidev,
-		ULONG *hw_paddr, 	// where to put phys addr for HW use
-		void *sgp_vaddr,	// the virtual address of the sg page 
-	 	dma_addr_t *umap_paddr,	// where to put phys addr for unmap
-		unsigned int *maplen,	// where to store sg entry length
-		int PairCount)		// number of sg pairs used in the page.	
+static dma_addr_t cpqfc_pci_map_sg_page(struct pci_dev *pcidev, u32 * hw_paddr,	// where to put phys addr for HW use
+					void *sgp_vaddr,	// the virtual address of the sg page 
+					dma_addr_t * umap_paddr,	// where to put phys addr for unmap
+					unsigned int *maplen,	// where to store sg entry length
+					int PairCount)	// number of sg pairs used in the page. 
 {
 	unsigned long aligned_addr = (unsigned long) sgp_vaddr;
 
 	*maplen = PairCount * 8;
-        aligned_addr += TL_EXT_SG_PAGE_BYTELEN;
-        aligned_addr &= ~(TL_EXT_SG_PAGE_BYTELEN -1);
-	
-	*umap_paddr = pci_map_single(pcidev, (void *) aligned_addr, 
-				*maplen, PCI_DMA_TODEVICE);
-	*hw_paddr = (ULONG) *umap_paddr;
+	aligned_addr += TL_EXT_SG_PAGE_BYTELEN;
+	aligned_addr &= ~(TL_EXT_SG_PAGE_BYTELEN - 1);
+
+	*umap_paddr = pci_map_single(pcidev, (void *) aligned_addr, *maplen, PCI_DMA_TODEVICE);
+	*hw_paddr = (u32) * umap_paddr;
 
 #       if BITS_PER_LONG > 32
-       		if( *umap_paddr >>32 ) {
-       	  		printk("cqpfcTS:Tach SG DMA addr %p>32 bits\n", 
-	  			(void*)umap_paddr);
-       			return 0;
-       		}
+	if (*umap_paddr >> 32) {
+		printk("cqpfcTS:Tach SG DMA addr %p>32 bits\n", (void *) umap_paddr);
+		return 0;
+	}
 #       endif
 	return *umap_paddr;
 }
 
-static void
-cpqfc_undo_SEST_mappings(struct pci_dev *pcidev,
-			unsigned long contigaddr, int len, int dir,
-  			struct scatterlist *sgl, int use_sg,
-    			PSGPAGES *sgPages_head,
-			int allocated_pages)
+static void cpqfc_undo_SEST_mappings(struct pci_dev *pcidev, unsigned long contigaddr, int len, int dir, struct scatterlist *sgl, int use_sg, PSGPAGES * sgPages_head, int allocated_pages)
 {
 	PSGPAGES i, next;
 
@@ -5136,14 +4137,12 @@
 	if (sgl != NULL)
 		pci_unmap_sg(pcidev, sgl, use_sg, dir);
 
-	for (i=*sgPages_head; i != NULL ;i = next)
-	{
-		pci_unmap_single(pcidev, i->busaddr, i->maplen, 
-			scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
-		i->busaddr = (dma_addr_t) NULL; 
-		i->maplen = 0L; 
+	for (i = *sgPages_head; i != NULL; i = next) {
+		pci_unmap_single(pcidev, i->busaddr, i->maplen, scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
+		i->busaddr = (dma_addr_t) NULL;
+		i->maplen = 0L;
 		next = i->next;
-		kfree(i); 
+		kfree(i);
 	}
 	*sgPages_head = NULL;
 }
@@ -5166,380 +4165,331 @@
 
 static int ap_hi_water = TL_DANGER_SGPAGES;
 
-static ULONG build_SEST_sgList( 
-    struct pci_dev *pcidev,
-    ULONG *SESTalPairStart,  // the 3 len/address buffers in SEST
-    Scsi_Cmnd *Cmnd,
-    ULONG *sgPairs, 
-    PSGPAGES *sgPages_head)  // link list of TL Ext. S/G pages from O/S Pool
-    
+static u32 build_SEST_sgList(struct pci_dev *pcidev, u32 * SESTalPairStart,	// the 3 len/address buffers in SEST
+			       Scsi_Cmnd * Cmnd, u32 * sgPairs, PSGPAGES * sgPages_head)	// link list of TL Ext. S/G pages from O/S Pool
 {
-  ULONG i, AllocatedPages=0; // Tach Ext. S/G page allocations
-  ULONG* alPair = SESTalPairStart;
-  ULONG* ext_sg_page_phys_addr_place = NULL;
-  int PairCount;
-  unsigned long ulBuff, contigaddr;
-  ULONG total_data_len=0; // (in bytes)
-  ULONG bytes_to_go = Cmnd->request_bufflen; // total xfer (S/G sum)
-  ULONG thisMappingLen;
-  struct scatterlist *sgl = NULL;  // S/G list (Linux format)
-  int sg_count, totalsgs; 
-  dma_addr_t busaddr;
-  unsigned long thislen, offset;
-  PSGPAGES *sgpage = sgPages_head;
-  PSGPAGES prev_page = NULL;
-
-# define WE_HAVE_SG_LIST (sgl != (unsigned long) NULL)
-  contigaddr = (unsigned long) NULL;
-
-  if( !Cmnd->use_sg )  // no S/G list?
-  {
-	if (bytes_to_go <= TL_MAX_SG_ELEM_LEN)
-	{
-    		*sgPairs = 1;	// use "local" S/G pair in SEST entry
-				// (for now, ignore address bits above #31)
+	u32 i, AllocatedPages = 0;	// Tach Ext. S/G page allocations
+	u32 *alPair = SESTalPairStart;
+	u32 *ext_sg_page_phys_addr_place = NULL;
+	int PairCount;
+	unsigned long ulBuff, contigaddr;
+	u32 total_data_len = 0;	// (in bytes)
+	u32 bytes_to_go = Cmnd->request_bufflen;	// total xfer (S/G sum)
+	u32 thisMappingLen;
+	struct scatterlist *sgl = NULL;	// S/G list (Linux format)
+	int sg_count, totalsgs;
+	dma_addr_t busaddr;
+	unsigned long thislen, offset;
+	PSGPAGES *sgpage = sgPages_head;
+	PSGPAGES prev_page = NULL;
 
-		*alPair++ = bytes_to_go; // bits 18-0, length
+# define WE_HAVE_SG_LIST (sgl != (unsigned long) NULL)
+	contigaddr = (unsigned long) NULL;
 
-		if (bytes_to_go != 0) {
-			contigaddr = ulBuff = pci_map_single(pcidev, 
-				Cmnd->request_buffer, 
-				Cmnd->request_bufflen,
-				scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
-			// printk("ms %p ", ulBuff);
-		}
-		else {
-			// No data transfer, (e.g.: Test Unit Ready)
-			// printk("btg=0 ");
-			*sgPairs = 0;
-			memset(alPair, 0, sizeof(*alPair));
-			return 0;
-		}
+	if (!Cmnd->use_sg)	// no S/G list?
+	{
+		if (bytes_to_go <= TL_MAX_SG_ELEM_LEN) {
+			*sgPairs = 1;	// use "local" S/G pair in SEST entry
+			// (for now, ignore address bits above #31)
+
+			*alPair++ = bytes_to_go;	// bits 18-0, length
+
+			if (bytes_to_go != 0) {
+				contigaddr = ulBuff = pci_map_single(pcidev, Cmnd->request_buffer, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+				// printk("ms %p ", ulBuff);
+			} else {
+				// No data transfer, (e.g.: Test Unit Ready)
+				// printk("btg=0 ");
+				*sgPairs = 0;
+				memset(alPair, 0, sizeof(*alPair));
+				return 0;
+			}
 
 #		if BITS_PER_LONG > 32
-    			if( ulBuff >>32 ) {
-      				printk("FATAL! Tachyon DMA address %p "
-					"exceeds 32 bits\n", (void*)ulBuff );
-      				return 0;
-    			}
+			if (ulBuff >> 32) {
+				printk("FATAL! Tachyon DMA address %p " "exceeds 32 bits\n", (void *) ulBuff);
+				return 0;
+			}
 #		endif
-    		*alPair = (ULONG)ulBuff;      
-    		return bytes_to_go;
-	} 
-	else	// We have a single large (too big) contiguous buffer.
-	{	// We will have to break it up.  We'll use the scatter
-		// gather code way below, but use contigaddr instead
-		// of sg_dma_addr(). (this is a very rare case).
-
-		unsigned long btg;
-		contigaddr = pci_map_single(pcidev, Cmnd->request_buffer, 
-				Cmnd->request_bufflen,
-				scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
-
-		// printk("contigaddr = %p, len = %d\n", 
-		//	(void *) contigaddr, bytes_to_go);
-		totalsgs = 0;
-		for (btg = bytes_to_go; btg > 0; ) {
-			btg -= ( btg > TL_MAX_SG_ELEM_LEN ? 
-				TL_MAX_SG_ELEM_LEN : btg );
-			totalsgs++;
-		}
-		sgl = NULL;
-		*sgPairs = totalsgs;
-	}
-  }
-  else  // we do have a scatter gather list
-  {
-	// [TBD - update for Linux to support > 32 bits addressing]
-	// since the format for local & extended S/G lists is different,
-	// check if S/G pairs exceeds 3.
-	// *sgPairs = Cmnd->use_sg; Nope, that's wrong.
- 
-	sgl = (struct scatterlist*)Cmnd->request_buffer;  
-	sg_count = pci_map_sg(pcidev, sgl, Cmnd->use_sg, 
-		scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
-        // printk("sgl = %p, sg_count = %d\n", (void *) sgl, sg_count);
-  	if( sg_count <= 3 ) {
-
-	// we need to be careful here that no individual mapping
-	// is too large, and if any is, that breaking it up
-	// doesn't push us over 3 sgs, or, if it does, that we
-	// handle that case.  Tachyon can take 0x7FFFF bits for length,
-	// but sg structure uses "unsigned int", on the face of it, 
-	// up to 0xFFFFFFFF or even more.
-
-		int i;
-		unsigned long thislen;
-
-		totalsgs = 0;
-		for (i=0;i<sg_count;i++) {
-      			thislen = sg_dma_len(&sgl[i]);
-			while (thislen >= TL_MAX_SG_ELEM_LEN) {
+			*alPair = (u32) ulBuff;
+			return bytes_to_go;
+		} else		// We have a single large (too big) contiguous buffer.
+		{		// We will have to break it up.  We'll use the scatter
+			// gather code way below, but use contigaddr instead
+			// of sg_dma_addr(). (this is a very rare case).
+
+			unsigned long btg;
+			contigaddr = pci_map_single(pcidev, Cmnd->request_buffer, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+
+			// printk("contigaddr = %p, len = %d\n", 
+			//      (void *) contigaddr, bytes_to_go);
+			totalsgs = 0;
+			for (btg = bytes_to_go; btg > 0;) {
+				btg -= (btg > TL_MAX_SG_ELEM_LEN ? TL_MAX_SG_ELEM_LEN : btg);
 				totalsgs++;
-				thislen -= TL_MAX_SG_ELEM_LEN;
 			}
-			if (thislen > 0) totalsgs++;
+			sgl = NULL;
+			*sgPairs = totalsgs;
 		}
-		*sgPairs = totalsgs;
-  	} else totalsgs = 999; // as a first estimate, definitely >3, 
-			      
-	// if (totalsgs != sg_count) 
-	//	printk("totalsgs = %d, sgcount=%d\n",totalsgs,sg_count);
-  }
+	} else			// we do have a scatter gather list
+	{
+		// [TBD - update for Linux to support > 32 bits addressing]
+		// since the format for local & extended S/G lists is different,
+		// check if S/G pairs exceeds 3.
+		// *sgPairs = Cmnd->use_sg; Nope, that's wrong.
+
+		sgl = (struct scatterlist *) Cmnd->request_buffer;
+		sg_count = pci_map_sg(pcidev, sgl, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+		// printk("sgl = %p, sg_count = %d\n", (void *) sgl, sg_count);
+		if (sg_count <= 3) {
+
+			// we need to be careful here that no individual mapping
+			// is too large, and if any is, that breaking it up
+			// doesn't push us over 3 sgs, or, if it does, that we
+			// handle that case.  Tachyon can take 0x7FFFF bits for length,
+			// but sg structure uses "unsigned int", on the face of it, 
+			// up to 0xFFFFFFFF or even more.
+
+			int i;
+			unsigned long thislen;
+
+			totalsgs = 0;
+			for (i = 0; i < sg_count; i++) {
+				thislen = sg_dma_len(&sgl[i]);
+				while (thislen >= TL_MAX_SG_ELEM_LEN) {
+					totalsgs++;
+					thislen -= TL_MAX_SG_ELEM_LEN;
+				}
+				if (thislen > 0)
+					totalsgs++;
+			}
+			*sgPairs = totalsgs;
+		} else
+			totalsgs = 999;	// as a first estimate, definitely >3, 
 
-  // printk("totalsgs = %d, sgcount=%d\n", totalsgs, sg_count);
-  if( totalsgs <= 3 ) // can (must) use "local" SEST list
-  {
-    while( bytes_to_go)
-    {
-      offset = 0L;
+		// if (totalsgs != sg_count) 
+		//      printk("totalsgs = %d, sgcount=%d\n",totalsgs,sg_count);
+	}
 
-      if ( WE_HAVE_SG_LIST ) 
-	thisMappingLen = sg_dma_len(sgl);
-      else					// or contiguous buffer?
-	thisMappingLen = bytes_to_go;
+	// printk("totalsgs = %d, sgcount=%d\n", totalsgs, sg_count);
+	if (totalsgs <= 3)	// can (must) use "local" SEST list
+	{
+		while (bytes_to_go) {
+			offset = 0L;
 
-      while (thisMappingLen > 0)
-      {  
-	thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? 
-		TL_MAX_SG_ELEM_LEN : thisMappingLen;
-	bytes_to_go = bytes_to_go - thislen;
+			if (WE_HAVE_SG_LIST)
+				thisMappingLen = sg_dma_len(sgl);
+			else	// or contiguous buffer?
+				thisMappingLen = bytes_to_go;
 
-	// we have L/A pair; L = thislen, A = physicalAddress
-	// load into SEST...
+			while (thisMappingLen > 0) {
+				thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? TL_MAX_SG_ELEM_LEN : thisMappingLen;
+				bytes_to_go = bytes_to_go - thislen;
 
-	total_data_len += thislen;
-	*alPair = thislen; // bits 18-0, length
+				// we have L/A pair; L = thislen, A = physicalAddress
+				// load into SEST...
 
-	alPair++;
+				total_data_len += thislen;
+				*alPair = thislen;	// bits 18-0, length
 
-	if ( WE_HAVE_SG_LIST ) 
-		ulBuff = sg_dma_address(sgl) + offset;
-	else
-		ulBuff = contigaddr + offset;
+				alPair++;
 
-	offset += thislen;
+				if (WE_HAVE_SG_LIST)
+					ulBuff = sg_dma_address(sgl) + offset;
+				else
+					ulBuff = contigaddr + offset;
+
+				offset += thislen;
 
 #	if BITS_PER_LONG > 32
-		if( ulBuff >>32 ) {
-        		printk("cqpfcTS: 2Tach DMA address %p > 32 bits\n", 
-				(void*)ulBuff );
-		    printk("%s = %p, offset = %ld\n", 
-			WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr",
-			WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr,
-				offset);
-        		return 0;
-      		}
+				if (ulBuff >> 32) {
+					printk("cqpfcTS: 2Tach DMA address %p > 32 bits\n", (void *) ulBuff);
+					printk("%s = %p, offset = %ld\n", WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr", WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr, offset);
+					return 0;
+				}
 #	endif
-        *alPair++ = (ULONG)ulBuff; // lower 32 bits (31-0)
-	thisMappingLen -= thislen;
-      }
+				*alPair++ = (u32) ulBuff;	// lower 32 bits (31-0)
+				thisMappingLen -= thislen;
+			}
 
-      if ( WE_HAVE_SG_LIST ) ++sgl;  // next S/G pair
-	else if (bytes_to_go != 0) printk("BTG not zero!\n");
+			if (WE_HAVE_SG_LIST)
+				++sgl;	// next S/G pair
+			else if (bytes_to_go != 0)
+				printk("BTG not zero!\n");
 
 #     ifdef DBG_SEST_SGLIST
-	printk("L=%d ", thisMappingLen);
-	printk("btg=%d ", bytes_to_go);
+			printk("L=%d ", thisMappingLen);
+			printk("btg=%d ", bytes_to_go);
 #     endif
 
-    }
-    // printk("i:%d\n", *sgPairs);
-  }
-  else    // more than 3 pairs requires Extended S/G page (Pool Allocation)
-  {
-    // clear out SEST DWORDs (local S/G addr) C-F (A-B set in following logic)
-    for( i=2; i<6; i++)
-      alPair[i] = 0;
-
-    PairCount = TL_EXT_SG_PAGE_COUNT;    // forces initial page allocation
-    totalsgs = 0;
-    while( bytes_to_go )
-    {
-      // Per SEST format, we can support 524287 byte lengths per
-      // S/G pair.  Typical user buffers are 4k, and very rarely
-      // exceed 12k due to fragmentation of physical memory pages.
-      // However, on certain O/S system (not "user") buffers (on platforms 
-      // with huge memories), it's possible to exceed this
-      // length in a single S/G address/len mapping, so we have to handle
-      // that.
-
-      offset = 0L;
-      if ( WE_HAVE_SG_LIST ) 
-	thisMappingLen = sg_dma_len(sgl);
-      else
-	thisMappingLen = bytes_to_go;
-
-      while (thisMappingLen > 0)
-      {
-	thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? 
-		TL_MAX_SG_ELEM_LEN : thisMappingLen;
-	// printk("%d/%d/%d\n", thislen, thisMappingLen, bytes_to_go);
-      
-  	// should we load into "this" extended S/G page, or allocate
-	// new page?
-
-	if( PairCount >= TL_EXT_SG_PAGE_COUNT )
+		}
+		// printk("i:%d\n", *sgPairs);
+	} else			// more than 3 pairs requires Extended S/G page (Pool Allocation)
 	{
-	  // Now, we have to map the previous page, (triggering buffer bounce)
-	  // The first time thru the loop, there won't be a previous page.
-	  if (prev_page != NULL) // is there a prev page? 
-	  {
-		// this code is normally kind of hard to trigger, 
-		// you have to use up more than 256 scatter gather 
-		// elements to get here.  Cranking down TL_MAX_SG_ELEM_LEN
-		// to an absurdly low value (128 bytes or so) to artificially
-		// break i/o's into a zillion pieces is how I tested it. 
-		busaddr = cpqfc_pci_map_sg_page(pcidev,
-				ext_sg_page_phys_addr_place,
-				prev_page->page,
-        			&prev_page->busaddr,
-        			&prev_page->maplen,
-				PairCount);
-          } 
-          // Allocate the TL Extended S/G list page.  We have
-          // to allocate twice what we want to ensure required TL alignment
-          // (Tachlite TL/TS User Man. Rev 6.0, p 168)
-          // We store the original allocated PVOID so we can free later
-	  *sgpage = kmalloc( sizeof(SGPAGES), GFP_ATOMIC);
-	  if ( ! *sgpage )
-          {
-		printk("cpqfc: Allocation failed @ %d S/G page allocations\n",
-			AllocatedPages);
-		total_data_len = 0;  // failure!! Ext. S/G is All-or-none affair
-
-	        // unmap the previous mappings, if any.
-
-	        cpqfc_undo_SEST_mappings(pcidev, contigaddr, 
-			Cmnd->request_bufflen,
-			scsi_to_pci_dma_dir(Cmnd->sc_data_direction),
-  			sgl, Cmnd->use_sg, sgPages_head, AllocatedPages+1);
-
-		// FIXME: testing shows that if we get here, 
-		// it's bad news.  (this has been this way for a long 
-		// time though, AFAIK.  Not that that excuses it.)
-
-		return 0; // give up (and probably hang the system)
-          }
-                               // clear out memory we just allocated
-	  memset( (*sgpage)->page,0,TL_EXT_SG_PAGE_BYTELEN*2);
-	  (*sgpage)->next = NULL;
-	  (*sgpage)->busaddr = (dma_addr_t) NULL;
-	  (*sgpage)->maplen = 0L;
-      
-	  // align the memory - TL requires sizeof() Ext. S/G page alignment.
-	  // We doubled the actual required size so we could mask off LSBs 
-	  // to get desired offset 
-
-	  ulBuff = (unsigned long) (*sgpage)->page;
-	  ulBuff += TL_EXT_SG_PAGE_BYTELEN;
-	  ulBuff &= ~(TL_EXT_SG_PAGE_BYTELEN -1);
-
-	  // set pointer, in SEST if first Ext. S/G page, or in last pair
-	  // of linked Ext. S/G pages... (Only 32-bit PVOIDs, so just 
-	  // load lower 32 bits)
-	  // NOTE: the Len field must be '0' if this is the first Ext. S/G
-	  // pointer in SEST, and not 0 otherwise (we know thislen != 0).
+		// clear out SEST DWORDs (local S/G addr) C-F (A-B set in following logic)
+		for (i = 2; i < 6; i++)
+			alPair[i] = 0;
 
-	  *alPair = (alPair != SESTalPairStart) ? thislen : 0;
+		PairCount = TL_EXT_SG_PAGE_COUNT;	// forces initial page allocation
+		totalsgs = 0;
+		while (bytes_to_go) {
+			// Per SEST format, we can support 524287 byte lengths per
+			// S/G pair.  Typical user buffers are 4k, and very rarely
+			// exceed 12k due to fragmentation of physical memory pages.
+			// However, on certain O/S system (not "user") buffers (on platforms 
+			// with huge memories), it's possible to exceed this
+			// length in a single S/G address/len mapping, so we have to handle
+			// that.
+
+			offset = 0L;
+			if (WE_HAVE_SG_LIST)
+				thisMappingLen = sg_dma_len(sgl);
+			else
+				thisMappingLen = bytes_to_go;
+
+			while (thisMappingLen > 0) {
+				thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? TL_MAX_SG_ELEM_LEN : thisMappingLen;
+				// printk("%d/%d/%d\n", thislen, thisMappingLen, bytes_to_go);
+
+				// should we load into "this" extended S/G page, or allocate
+				// new page?
+
+				if (PairCount >= TL_EXT_SG_PAGE_COUNT) {
+					// Now, we have to map the previous page, (triggering buffer bounce)
+					// The first time thru the loop, there won't be a previous page.
+					if (prev_page != NULL)	// is there a prev page? 
+					{
+						// this code is normally kind of hard to trigger, 
+						// you have to use up more than 256 scatter gather 
+						// elements to get here.  Cranking down TL_MAX_SG_ELEM_LEN
+						// to an absurdly low value (128 bytes or so) to artificially
+						// break i/o's into a zillion pieces is how I tested it. 
+						busaddr = cpqfc_pci_map_sg_page(pcidev, ext_sg_page_phys_addr_place, prev_page->page, &prev_page->busaddr, &prev_page->maplen, PairCount);
+					}
+					// Allocate the TL Extended S/G list page.  We have
+					// to allocate twice what we want to ensure required TL alignment
+					// (Tachlite TL/TS User Man. Rev 6.0, p 168)
+					// We store the original allocated PVOID so we can free later
+					*sgpage = kmalloc(sizeof(SGPAGES), GFP_ATOMIC);
+					if (!*sgpage) {
+						printk("cpqfc: Allocation failed @ %d S/G page allocations\n", AllocatedPages);
+						total_data_len = 0;	// failure!! Ext. S/G is All-or-none affair
+
+						// unmap the previous mappings, if any.
+
+						cpqfc_undo_SEST_mappings(pcidev, contigaddr, Cmnd->request_bufflen, scsi_to_pci_dma_dir(Cmnd->sc_data_direction), sgl, Cmnd->use_sg, sgPages_head, AllocatedPages + 1);
+
+						// FIXME: testing shows that if we get here, 
+						// it's bad news.  (this has been this way for a long 
+						// time though, AFAIK.  Not that that excuses it.)
+
+						return 0;	// give up (and probably hang the system)
+					}
+					// clear out memory we just allocated
+					memset((*sgpage)->page, 0, TL_EXT_SG_PAGE_BYTELEN * 2);
+					(*sgpage)->next = NULL;
+					(*sgpage)->busaddr = (dma_addr_t) NULL;
+					(*sgpage)->maplen = 0L;
+
+					// align the memory - TL requires sizeof() Ext. S/G page alignment.
+					// We doubled the actual required size so we could mask off LSBs 
+					// to get desired offset 
+
+					ulBuff = (unsigned long) (*sgpage)->page;
+					ulBuff += TL_EXT_SG_PAGE_BYTELEN;
+					ulBuff &= ~(TL_EXT_SG_PAGE_BYTELEN - 1);
+
+					// set pointer, in SEST if first Ext. S/G page, or in last pair
+					// of linked Ext. S/G pages... (Only 32-bit PVOIDs, so just 
+					// load lower 32 bits)
+					// NOTE: the Len field must be '0' if this is the first Ext. S/G
+					// pointer in SEST, and not 0 otherwise (we know thislen != 0).
+
+					*alPair = (alPair != SESTalPairStart) ? thislen : 0;
 
 #	  ifdef DBG_SEST_SGLIST
-        	printk("PairCount %d @%p even %Xh, ", 
-			PairCount, alPair, *alPair);
+					printk("PairCount %d @%p even %Xh, ", PairCount, alPair, *alPair);
 #	  endif
 
-	  // Save the place where we need to store the physical
-	  // address of this scatter gather page which we get when we map it
-	  // (and mapping we can do only after we fill it in.)
-	  alPair++;  // next DWORD, will contain phys addr of the ext page
-	  ext_sg_page_phys_addr_place = alPair;
-
-	  // Now, set alPair = the virtual addr of the (Extended) S/G page
-	  // which will accept the Len/ PhysicalAddress pairs
-	  alPair = (ULONG *) ulBuff;
-
-	  AllocatedPages++;
-	  if (AllocatedPages >= ap_hi_water)
-	  {
-		// This message should rarely, if ever, come out.
-		// Previously (cpqfc version <= 2.0.5) the driver would
-		// just puke if more than 4 SG pages were used, and nobody
-		// ever complained about that.  This only comes out if 
-		// more than 8 pages are used.
-
-		printk(KERN_WARNING
-		"cpqfc: Possible danger.  %d scatter gather pages used.\n"
-			"cpqfc: detected seemingly extreme memory "
-			"fragmentation or huge data transfers.\n", 
-			AllocatedPages);
-		ap_hi_water = AllocatedPages+1;
-	  }
-		
-	  PairCount = 1;  // starting new Ext. S/G page
-	  prev_page = (*sgpage);  // remember this page, for next time thru
-	  sgpage = &((*sgpage)->next);
-	}  // end of new TL Ext. S/G page allocation
+					// Save the place where we need to store the physical
+					// address of this scatter gather page which we get when we map it
+					// (and mapping we can do only after we fill it in.)
+					alPair++;	// next DWORD, will contain phys addr of the ext page
+					ext_sg_page_phys_addr_place = alPair;
+
+					// Now, set alPair = the virtual addr of the (Extended) S/G page
+					// which will accept the Len/ PhysicalAddress pairs
+					alPair = (u32 *) ulBuff;
+
+					AllocatedPages++;
+					if (AllocatedPages >= ap_hi_water) {
+						// This message should rarely, if ever, come out.
+						// Previously (cpqfc version <= 2.0.5) the driver would
+						// just puke if more than 4 SG pages were used, and nobody
+						// ever complained about that.  This only comes out if 
+						// more than 8 pages are used.
+
+						printk(KERN_WARNING "cpqfc: Possible danger.  %d scatter gather pages used.\n" "cpqfc: detected seemingly extreme memory " "fragmentation or huge data transfers.\n", AllocatedPages);
+						ap_hi_water = AllocatedPages + 1;
+					}
+
+					PairCount = 1;	// starting new Ext. S/G page
+					prev_page = (*sgpage);	// remember this page, for next time thru
+					sgpage = &((*sgpage)->next);
+				}	// end of new TL Ext. S/G page allocation
+
+				*alPair = thislen;	// bits 18-0, length (range check above)
 
-	*alPair = thislen; // bits 18-0, length (range check above)
-      
 #	ifdef DBG_SEST_SGLIST
-	  printk("PairCount %d @%p, even %Xh, ", PairCount, alPair, *alPair);
+				printk("PairCount %d @%p, even %Xh, ", PairCount, alPair, *alPair);
 #	endif
 
-	alPair++;    // next DWORD, physical address 
+				alPair++;	// next DWORD, physical address 
 
-	if ( WE_HAVE_SG_LIST ) 
-		ulBuff = sg_dma_address(sgl) + offset;
-	else
-		ulBuff = contigaddr + offset;
-	offset += thislen;
+				if (WE_HAVE_SG_LIST)
+					ulBuff = sg_dma_address(sgl) + offset;
+				else
+					ulBuff = contigaddr + offset;
+				offset += thislen;
 
 #	if BITS_PER_LONG > 32
-          if( ulBuff >>32 )
-	  {
-	    printk("cqpfcTS: 1Tach DMA address %p > 32 bits\n", (void*)ulBuff );
-	    printk("%s = %p, offset = %ld\n", 
-		WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr",
-		WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr,
-			offset);
-	    return 0;
-	  }
+				if (ulBuff >> 32) {
+					printk("cqpfcTS: 1Tach DMA address %p > 32 bits\n", (void *) ulBuff);
+					printk("%s = %p, offset = %ld\n", WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr", WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr, offset);
+					return 0;
+				}
 #	endif
 
-	*alPair = (ULONG) ulBuff; // lower 32 bits (31-0)
+				*alPair = (u32) ulBuff;	// lower 32 bits (31-0)
 
 #       ifdef DBG_SEST_SGLIST
-        printk("odd %Xh\n", *alPair);
+				printk("odd %Xh\n", *alPair);
 #       endif
-	alPair++;    // next DWORD, next address/length pair
-                                           
-	PairCount++; // next Length/Address pair
-
-	// if (PairCount > pc_hi_water)
-	// {
-		// printk("pc hi = %d ", PairCount);
-		// pc_hi_water = PairCount;
-	// }
-	bytes_to_go -= thislen;
-	total_data_len += thislen;  
-	thisMappingLen -= thislen;
-	totalsgs++;
-      } // while (thisMappingLen > 0)
-      if ( WE_HAVE_SG_LIST ) sgl++;  // next S/G pair
-    } // while (bytes_to_go)
-
-    // printk("Totalsgs=%d\n", totalsgs);
-    *sgPairs = totalsgs;
-
-    // PCI map (and bounce) the last (and usually only) extended SG page
-    busaddr = cpqfc_pci_map_sg_page(pcidev,
-		ext_sg_page_phys_addr_place,
-		prev_page->page, 
-		&prev_page->busaddr, 
-		&prev_page->maplen,
-		PairCount);
-  }
-  return total_data_len;
+				alPair++;	// next DWORD, next address/length pair
+
+				PairCount++;	// next Length/Address pair
+
+				// if (PairCount > pc_hi_water)
+				// {
+				// printk("pc hi = %d ", PairCount);
+				// pc_hi_water = PairCount;
+				// }
+				bytes_to_go -= thislen;
+				total_data_len += thislen;
+				thisMappingLen -= thislen;
+				totalsgs++;
+			}	// while (thisMappingLen > 0)
+			if (WE_HAVE_SG_LIST)
+				sgl++;	// next S/G pair
+		}		// while (bytes_to_go)
+
+		// printk("Totalsgs=%d\n", totalsgs);
+		*sgPairs = totalsgs;
+
+		// PCI map (and bounce) the last (and usually only) extended SG page
+		busaddr = cpqfc_pci_map_sg_page(pcidev, ext_sg_page_phys_addr_place, prev_page->page, &prev_page->busaddr, &prev_page->maplen, PairCount);
+	}
+	return total_data_len;
 }
 
 
@@ -5554,268 +4504,249 @@
 // 0 if successful
 // non-zero on error
 //sstartex
-ULONG cpqfcTSStartExchange( 
-  CPQFCHBA *cpqfcHBAdata,                      
-  LONG ExchangeID )
-{
-  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ ExchangeID ]; // shorthand
-  USHORT producer, consumer;
-  ULONG ulStatus=0;
-  short int ErqIndex;
-  BOOLEAN CompleteExchange = FALSE;  // e.g. ACC replies are complete
-  BOOLEAN SestType=FALSE;
-  ULONG InboundData=0;
 
-  // We will manipulate Tachlite chip registers here to successfully
-  // start exchanges. 
+u32 cpqfcTSStartExchange(CPQFCHBA * dev, s32 ExchangeID)
+{
+	PTACHYON fcChip = &dev->fcChip;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID];	// shorthand
+	u16 producer, consumer;
+	u32 ulStatus = 0;
+	short int ErqIndex;
+	u8 CompleteExchange = 0;	// e.g. ACC replies are complete
+	u8 SestType = 0;
+	u32 InboundData = 0;
 
-  // Check that link is not down -- we can't start an exchange on a
-  // down link!
+	// We will manipulate Tachlite chip registers here to successfully
+	// start exchanges. 
 
-  if( fcChip->Registers.FMstatus.value & 0x80) // LPSM offline?
-  {
-printk("fcStartExchange: PSM offline (%Xh), x_ID %Xh, type %Xh, port_id %Xh\n",
-         fcChip->Registers.FMstatus.value & 0xFF,
-         ExchangeID,
-         pExchange->type,
-         pExchange->fchs.d_id);
+	// Check that link is not down -- we can't start an exchange on a
+	// down link!
 
-    if( ExchangeID >= TACH_SEST_LEN )  // Link Service Outbound frame?
-    {
-      // Our most popular LinkService commands are port discovery types
-      // (PLOGI/ PDISC...), which are implicitly nullified by Link Down
-      // events, so it makes no sense to Que them.  However, ABTS should
-      // be queued, since exchange sequences are likely destroyed by
-      // Link Down events, and we want to notify other ports of broken
-      // sequences by aborting the corresponding exchanges.
-      if( pExchange->type != BLS_ABTS )
-      {
-	ulStatus = LNKDWN_OSLS;
-	goto Done;
-        // don't Que most LinkServ exchanges on LINK DOWN
-      }
-    }
+	if (fcChip->Registers.FMstatus.value & 0x80)	// LPSM offline?
+	{
+		printk("fcStartExchange: PSM offline (%Xh), x_ID %Xh, type %Xh, port_id %Xh\n", fcChip->Registers.FMstatus.value & 0xFF, ExchangeID, pExchange->type, pExchange->fchs.d_id);
 
-    printk("fcStartExchange: Que x_ID %Xh, type %Xh\n", 
-      ExchangeID, pExchange->type);
-    pExchange->status |= EXCHANGE_QUEUED;
-    ulStatus = EXCHANGE_QUEUED;
-    goto Done;
-  }
+		if (ExchangeID >= TACH_SEST_LEN)	// Link Service Outbound frame?
+		{
+			// Our most popular LinkService commands are port discovery types
+			// (PLOGI/ PDISC...), which are implicitly nullified by Link Down
+			// events, so it makes no sense to Que them.  However, ABTS should
+			// be queued, since exchange sequences are likely destroyed by
+			// Link Down events, and we want to notify other ports of broken
+			// sequences by aborting the corresponding exchanges.
+			if (pExchange->type != BLS_ABTS) {
+				ulStatus = LNKDWN_OSLS;
+				goto Done;
+				// don't Que most LinkServ exchanges on LINK DOWN
+			}
+		}
 
-  // Make sure ERQ has available space.
-  
-  producer = (USHORT)fcChip->ERQ->producerIndex; // copies for logical arith.
-  consumer = (USHORT)fcChip->ERQ->consumerIndex;
-  producer++;  // We are testing for full que by incrementing
-  
-  if( producer >= ERQ_LEN )  // rollover condition?
-    producer = 0;
-  if( consumer != producer ) // ERQ not full?
-  {
-    // ****************** Need Atomic access to chip registers!!********
-    
-    // remember ERQ PI for copying IRB
-    ErqIndex = (USHORT)fcChip->ERQ->producerIndex; 
-    fcChip->ERQ->producerIndex = producer; // this is written to Tachyon
-               // we have an ERQ slot! If SCSI command, need SEST slot
-               // otherwise we are done.
-
-    // Note that Tachyon requires that bit 15 of the OX_ID or RX_ID be
-    // set according to direction of data to/from Tachyon for SEST assists.
-    // For consistency, enforce this rule for Link Service (non-SEST)
-    // exchanges as well.
-
-    // fix-up the X_ID field in IRB
-    pExchange->IRB.Req_A_Trans_ID = ExchangeID & 0x7FFF; // 15-bit field
-
-    // fix-up the X_ID field in fchs -- depends on Originator or Responder,
-    // outgoing or incoming data?
-    switch( pExchange->type )
-    {
-               // ORIGINATOR types...  we're setting our OX_ID and
-               // defaulting the responder's RX_ID to 0xFFFF
-    
-    case SCSI_IRE:
-      // Requirement: set MSB of x_ID for Incoming TL data
-      // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
-      InboundData = 0x8000;
-
-    case SCSI_IWE:   
-      SestType = TRUE;
-      pExchange->fchs.ox_rx_id = (ExchangeID | InboundData);
-      pExchange->fchs.ox_rx_id <<= 16;     // MSW shift
-      pExchange->fchs.ox_rx_id |= 0xffff;  // add default RX_ID
-      
-      // now fix-up the Data HDR OX_ID (TL automatically does rx_id)
-      // (not necessary for IRE -- data buffer unused)
-      if( pExchange->type == SCSI_IWE)
-      {
-        fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id = 
-          pExchange->fchs.ox_rx_id;
-
-      }
-
-      break;
-
-
-    case FCS_NSR:  // ext. link service Name Service Request
-    case ELS_SCR:  // ext. link service State Change Registration
-    case ELS_FDISC:// ext. link service login
-    case ELS_FLOGI:// ext. link service login
-    case ELS_LOGO: // FC-PH extended link service logout
-    case BLS_NOP:  // Basic link service No OPeration
-    case ELS_PLOGI:// ext. link service login (PLOGI)
-    case ELS_PDISC:// ext. link service login (PDISC)
-    case ELS_PRLI: // ext. link service process login
-
-      pExchange->fchs.ox_rx_id = ExchangeID;
-      pExchange->fchs.ox_rx_id <<= 16;  // MSW shift
-      pExchange->fchs.ox_rx_id |= 0xffff;  // and RX_ID
+		printk("fcStartExchange: Que x_ID %Xh, type %Xh\n", ExchangeID, pExchange->type);
+		pExchange->status |= EXCHANGE_QUEUED;
+		ulStatus = EXCHANGE_QUEUED;
+		goto Done;
+	}
+	// Make sure ERQ has available space.
 
-      break;
-      
+	producer = (u16) fcChip->ERQ->producerIndex;	// copies for logical arith.
+	consumer = (u16) fcChip->ERQ->consumerIndex;
+	producer++;		// We are testing for full que by incrementing
+
+	if (producer >= ERQ_LEN)	// rollover condition?
+		producer = 0;
+	if (consumer != producer)	// ERQ not full?
+	{
+		// ****************** Need Atomic access to chip registers!!********
 
+		// remember ERQ PI for copying IRB
+		ErqIndex = (u16) fcChip->ERQ->producerIndex;
+		fcChip->ERQ->producerIndex = producer;	// this is written to Tachyon
+		// we have an ERQ slot! If SCSI command, need SEST slot
+		// otherwise we are done.
+
+		// Note that Tachyon requires that bit 15 of the OX_ID or RX_ID be
+		// set according to direction of data to/from Tachyon for SEST assists.
+		// For consistency, enforce this rule for Link Service (non-SEST)
+		// exchanges as well.
+
+		// fix-up the X_ID field in IRB
+		pExchange->IRB.Req_A_Trans_ID = ExchangeID & 0x7FFF;	// 15-bit field
+
+		// fix-up the X_ID field in fchs -- depends on Originator or Responder,
+		// outgoing or incoming data?
+		switch (pExchange->type) {
+			// ORIGINATOR types...  we're setting our OX_ID and
+			// defaulting the responder's RX_ID to 0xFFFF
+
+		case SCSI_IRE:
+			// Requirement: set MSB of x_ID for Incoming TL data
+			// (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
+			InboundData = 0x8000;
+
+		case SCSI_IWE:
+			SestType = 1;
+			pExchange->fchs.ox_rx_id = (ExchangeID | InboundData);
+			pExchange->fchs.ox_rx_id <<= 16;	// MSW shift
+			pExchange->fchs.ox_rx_id |= 0xffff;	// add default RX_ID
+
+			// now fix-up the Data HDR OX_ID (TL automatically does rx_id)
+			// (not necessary for IRE -- data buffer unused)
+			if (pExchange->type == SCSI_IWE) {
+				fcChip->SEST->DataHDR[ExchangeID].ox_rx_id = pExchange->fchs.ox_rx_id;
 
+			}
 
-               // RESPONDER types... we must set our RX_ID while preserving
-               // sender's OX_ID
-               // outgoing (or no) data
-    case ELS_RJT:       // extended link service reject 
-    case ELS_LOGO_ACC: // FC-PH extended link service logout accept
-    case ELS_ACC:      // ext. generic link service accept
-    case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
-    case ELS_PRLI_ACC: // ext. link service process login accept
-
-      CompleteExchange = TRUE;   // Reply (ACC or RJT) is end of exchange
-      pExchange->fchs.ox_rx_id |= (ExchangeID & 0xFFFF);
-
-      break;
-
-
-      // since we are a Responder, OX_ID should already be set by
-      // cpqfcTSBuildExchange().  We need to -OR- in RX_ID
-    case SCSI_TWE:
-      SestType = TRUE;
-      // Requirement: set MSB of x_ID for Incoming TL data
-      // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
-
-      pExchange->fchs.ox_rx_id &= 0xFFFF0000;  // clear RX_ID
-      // Requirement: set MSB of RX_ID for Incoming TL data
-      // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
-      pExchange->fchs.ox_rx_id |= (ExchangeID | 0x8000);
-      break;
-          
-    
-    case SCSI_TRE:
-      SestType = TRUE;
-      
-      // there is no XRDY for SEST target read; the data
-      // header needs to be updated. Also update the RSP
-      // exchange IDs for the status frame, in case it is sent automatically
-      fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id |= ExchangeID;
-      fcChip->SEST->RspHDR[ ExchangeID ].ox_rx_id = 
-        fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
-      
-      // for easier FCP response logic (works for TWE and TRE), 
-      // copy exchange IDs.  (Not needed if TRE 'RSP' bit set)
-      pExchange->fchs.ox_rx_id =
-        fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
-
-      break;
+			break;
 
 
-    case FCP_RESPONSE:  // using existing OX_ID/ RX_ID pair,
-                        // start SFS FCP-RESPONSE frame
-      // OX/RX_ID should already be set! (See "fcBuild" above)
-      CompleteExchange = TRUE;   // RSP is end of FCP-SCSI exchange
+		case FCS_NSR:	// ext. link service Name Service Request
+		case ELS_SCR:	// ext. link service State Change Registration
+		case ELS_FDISC:	// ext. link service login
+		case ELS_FLOGI:	// ext. link service login
+		case ELS_LOGO:	// FC-PH extended link service logout
+		case BLS_NOP:	// Basic link service No OPeration
+		case ELS_PLOGI:	// ext. link service login (PLOGI)
+		case ELS_PDISC:	// ext. link service login (PDISC)
+		case ELS_PRLI:	// ext. link service process login
 
-      
-      break;
+			pExchange->fchs.ox_rx_id = ExchangeID;
+			pExchange->fchs.ox_rx_id <<= 16;	// MSW shift
+			pExchange->fchs.ox_rx_id |= 0xffff;	// and RX_ID
 
+			break;
 
-    case BLS_ABTS_RJT:  // uses new RX_ID, since SEST x_ID non-existent
-    case BLS_ABTS_ACC:  // using existing OX_ID/ RX_ID pair from SEST entry
-      CompleteExchange = TRUE;   // ACC or RJT marks end of FCP-SCSI exchange
-    case BLS_ABTS:  // using existing OX_ID/ RX_ID pair from SEST entry
 
 
-      break;
 
+			// RESPONDER types... we must set our RX_ID while preserving
+			// sender's OX_ID
+			// outgoing (or no) data
+		case ELS_RJT:	// extended link service reject 
+		case ELS_LOGO_ACC:	// FC-PH extended link service logout accept
+		case ELS_ACC:	// ext. generic link service accept
+		case ELS_PLOGI_ACC:	// ext. link service login accept (PLOGI or PDISC)
+		case ELS_PRLI_ACC:	// ext. link service process login accept
 
-    default:
-      printk("Error on fcStartExchange: undefined type %Xh(%d)\n",
-        pExchange->type, pExchange->type);
-      return INVALID_ARGS;
-    }
-    
-    
-      // X_ID fields are entered -- copy IRB to Tachyon's ERQ
-    
+			CompleteExchange = 1;	// Reply (ACC or RJT) is end of exchange
+			pExchange->fchs.ox_rx_id |= (ExchangeID & 0xFFFF);
 
-    memcpy(
-        &fcChip->ERQ->QEntry[ ErqIndex ],  // dest.
-        &pExchange->IRB,
-        32);  // fixed (hardware) length!
-
-    PCI_TRACEO( ExchangeID, 0xA0)
-
-    // ACTION!  May generate INT and IMQ entry
-    writel( fcChip->ERQ->producerIndex,
-          fcChip->Registers.ERQproducerIndex.address);
+			break;
 
-  
-    if( ExchangeID >= TACH_SEST_LEN )  // Link Service Outbound frame?
-    {
-    
-      // wait for completion! (TDB -- timeout and chip reset)
-      
 
-  PCI_TRACEO( ExchangeID, 0xA4)
-  
-      enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Sem.
-      
-      down_interruptible( cpqfcHBAdata->TYOBcomplete); 
-  
-      disable_irq( cpqfcHBAdata->HostAdapter->irq);
-  PCI_TRACE( 0xA4)
-
-      // On login exchanges, BAD_ALPA (non-existent port_id) results in 
-      // FTO (Frame Time Out) on the Outbound Completion message.
-      // If we got an FTO status, complete the exchange (free up slot)
-      if( CompleteExchange ||   // flag from Reply frames
-          pExchange->status )   // typically, can get FRAME_TO
-      {
-    	cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);  
-      }
-    }
+			// since we are a Responder, OX_ID should already be set by
+			// cpqfcTSBuildExchange().  We need to -OR- in RX_ID
+		case SCSI_TWE:
+			SestType = 1;
+			// Requirement: set MSB of x_ID for Incoming TL data
+			// (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
 
-    else                         // SEST Exchange
-    {
-      ulStatus = 0;   // ship & pray success (e.g. FCP-SCSI)
-      
-      if( CompleteExchange )   // by Type of exchange (e.g. end-of-xchng)
-      {
-    	cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);  
-      }
-       
-      else
-        pExchange->status &= ~EXCHANGE_QUEUED;  // clear ExchangeQueued flag 
+			pExchange->fchs.ox_rx_id &= 0xFFFF0000;	// clear RX_ID
+			// Requirement: set MSB of RX_ID for Incoming TL data
+			// (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
+			pExchange->fchs.ox_rx_id |= (ExchangeID | 0x8000);
+			break;
 
-    }
-  }
 
-  
-  else                // ERQ 'producer' = 'consumer' and QUE is full
-  {
-    ulStatus = OUTQUE_FULL; // Outbound (ERQ) Que full
-  }
- 
-Done: 
-  PCI_TRACE( 0xA0)
-  return ulStatus; 
+		case SCSI_TRE:
+			SestType = 1;
+
+			// there is no XRDY for SEST target read; the data
+			// header needs to be updated. Also update the RSP
+			// exchange IDs for the status frame, in case it is sent automatically
+			fcChip->SEST->DataHDR[ExchangeID].ox_rx_id |= ExchangeID;
+			fcChip->SEST->RspHDR[ExchangeID].ox_rx_id = fcChip->SEST->DataHDR[ExchangeID].ox_rx_id;
+
+			// for easier FCP response logic (works for TWE and TRE), 
+			// copy exchange IDs.  (Not needed if TRE 'RSP' bit set)
+			pExchange->fchs.ox_rx_id = fcChip->SEST->DataHDR[ExchangeID].ox_rx_id;
+
+			break;
+
+
+		case FCP_RESPONSE:	// using existing OX_ID/ RX_ID pair,
+			// start SFS FCP-RESPONSE frame
+			// OX/RX_ID should already be set! (See "fcBuild" above)
+			CompleteExchange = 1;	// RSP is end of FCP-SCSI exchange
+
+
+			break;
+
+
+		case BLS_ABTS_RJT:	// uses new RX_ID, since SEST x_ID non-existent
+		case BLS_ABTS_ACC:	// using existing OX_ID/ RX_ID pair from SEST entry
+			CompleteExchange = 1;	// ACC or RJT marks end of FCP-SCSI exchange
+		case BLS_ABTS:	// using existing OX_ID/ RX_ID pair from SEST entry
+
+
+			break;
+
+
+		default:
+			printk("Error on fcStartExchange: undefined type %Xh(%d)\n", pExchange->type, pExchange->type);
+			return INVALID_ARGS;
+		}
+
+
+		// X_ID fields are entered -- copy IRB to Tachyon's ERQ
+
+
+		memcpy(&fcChip->ERQ->QEntry[ErqIndex],	// dest.
+		       &pExchange->IRB, 32);	// fixed (hardware) length!
+
+		PCI_TRACEO(ExchangeID, 0xA0)
+		    // ACTION!  May generate INT and IMQ entry
+		    writel(fcChip->ERQ->producerIndex, fcChip->Registers.ERQproducerIndex.address);
+
+
+		if (ExchangeID >= TACH_SEST_LEN)	// Link Service Outbound frame?
+		{
+
+			// wait for completion! (TDB -- timeout and chip reset)
+
+
+			PCI_TRACEO(ExchangeID, 0xA4)
+
+			    enable_irq(dev->HostAdapter->irq);	// only way to get Sem.
+
+			down_interruptible(dev->TYOBcomplete);
+
+			disable_irq(dev->HostAdapter->irq);
+			PCI_TRACE(0xA4)
+			    // On login exchanges, BAD_ALPA (non-existent port_id) results in 
+			    // FTO (Frame Time Out) on the Outbound Completion message.
+			    // If we got an FTO status, complete the exchange (free up slot)
+			    if (CompleteExchange ||	// flag from Reply frames
+				pExchange->status)	// typically, can get FRAME_TO
+			{
+				cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+			}
+		}
+
+		else		// SEST Exchange
+		{
+			ulStatus = 0;	// ship & pray success (e.g. FCP-SCSI)
+
+			if (CompleteExchange)	// by Type of exchange (e.g. end-of-xchng)
+			{
+				cpqfcTSCompleteExchange(dev->PciDev, fcChip, ExchangeID);
+			}
+
+			else
+				pExchange->status &= ~EXCHANGE_QUEUED;	// clear ExchangeQueued flag 
+
+		}
+	}
+
+
+	else			// ERQ 'producer' = 'consumer' and QUE is full
+	{
+		ulStatus = OUTQUE_FULL;	// Outbound (ERQ) Que full
+	}
+
+      Done:
+	PCI_TRACE(0xA0)
+	    return ulStatus;
 }
 
 
@@ -5839,408 +4770,364 @@
 // (Least Recently Used) scheme.
 
 
-static LONG FindFreeExchange( PTACHYON fcChip, ULONG type )
+static s32 FindFreeExchange(PTACHYON fcChip, u32 type)
 {
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  ULONG i;
-  ULONG ulStatus=-1;  // assume failure
-
-
-  if( type == SCSI_IRE ||
-      type == SCSI_TRE ||
-      type == SCSI_IWE ||
-      type == SCSI_TWE)
-  {
-        // SCSI type - X_IDs should be from 0 to TACH_SEST_LEN-1
-    if( fcChip->fcSestExchangeLRU >= TACH_SEST_LEN) // rollover?
-      fcChip->fcSestExchangeLRU = 0;
-    i = fcChip->fcSestExchangeLRU; // typically it's already free!
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	u32 i;
+	u32 ulStatus = -1;	// assume failure
+
+
+	if (type == SCSI_IRE || type == SCSI_TRE || type == SCSI_IWE || type == SCSI_TWE) {
+		// SCSI type - X_IDs should be from 0 to TACH_SEST_LEN-1
+		if (fcChip->fcSestExchangeLRU >= TACH_SEST_LEN)	// rollover?
+			fcChip->fcSestExchangeLRU = 0;
+		i = fcChip->fcSestExchangeLRU;	// typically it's already free!
+
+		if (Exchanges->fcExchange[i].type == 0)	// check for "free" element
+		{
+			ulStatus = 0;	// success!
+		}
 
-    if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
-    {
-      ulStatus = 0; // success!
-    }
-    
-    else
-    {         // YUK! we need to do a linear search for free element.
-              // Fragmentation of the fcExchange array is due to excessively
-              // long completions or timeouts.
-      
-      while( TRUE )
-      {
-        if( ++i >= TACH_SEST_LEN ) // rollover check
-          i = 0;  // beginning of SEST X_IDs
-
-//        printk( "looping for SCSI xchng ID: i=%d, type=%Xh\n", 
-//         i, Exchanges->fcExchange[i].type);
-
-        if( Exchanges->fcExchange[i].type == 0 ) // "free"?
-        {
-          ulStatus = 0; // success!
-          break;
-        }
-        if( i == fcChip->fcSestExchangeLRU ) // wrapped-around array?
-        {
-          printk( "SEST X_ID space full\n");
-          break;       // failed - prevent inf. loop
-        }
-      }
-    }
-    fcChip->fcSestExchangeLRU = i + 1; // next! (rollover check next pass)
-  }
+		else {		// YUK! we need to do a linear search for free element.
+			// Fragmentation of the fcExchange array is due to excessively
+			// long completions or timeouts.
+
+			while (1) {
+				if (++i >= TACH_SEST_LEN)	// rollover check
+					i = 0;	// beginning of SEST X_IDs
+
+//					printk( "looping for SCSI xchng ID: i=%d, type=%Xh\n", 
+//						i, Exchanges->fcExchange[i].type);
+
+				if (Exchanges->fcExchange[i].type == 0)	// "free"?
+				{
+					ulStatus = 0;	// success!
+					break;
+				}
+				if (i == fcChip->fcSestExchangeLRU)	// wrapped-around array?
+				{
+					printk("SEST X_ID space full\n");
+					break;	// failed - prevent inf. loop
+				}
+			}
+		}
+		fcChip->fcSestExchangeLRU = i + 1;	// next! (rollover check next pass)
+	}
+	else			// Link Service type - X_IDs should be from TACH_SEST_LEN 
+				// to TACH_MAX_XID
+	{
+		if (fcChip->fcLsExchangeLRU >= TACH_MAX_XID ||	// range check
+		    fcChip->fcLsExchangeLRU < TACH_SEST_LEN)	// (e.g. startup)
+			fcChip->fcLsExchangeLRU = TACH_SEST_LEN;
+
+		i = fcChip->fcLsExchangeLRU;	// typically it's already free!
+		if (Exchanges->fcExchange[i].type == 0)	// check for "free" element
+		{
+			ulStatus = 0;	// success!
+		}
 
-  
-  
-  else  // Link Service type - X_IDs should be from TACH_SEST_LEN 
-        // to TACH_MAX_XID
-  {
-    if( fcChip->fcLsExchangeLRU >= TACH_MAX_XID || // range check
-        fcChip->fcLsExchangeLRU < TACH_SEST_LEN ) // (e.g. startup)
-      fcChip->fcLsExchangeLRU = TACH_SEST_LEN;
+		else {		// YUK! we need to do a linear search for free element
+			// Fragmentation of the fcExchange array is due to excessively
+			// long completions or timeouts.
+
+			while (1) {
+				if (++i >= TACH_MAX_XID)	// rollover check
+					i = TACH_SEST_LEN;	// beginning of Link Service X_IDs
+
+//				printk( "looping for xchng ID: i=%d, type=%Xh\n", 
+//					i, Exchanges->fcExchange[i].type);
+
+				if (Exchanges->fcExchange[i].type == 0)	// "free"?
+				{
+					ulStatus = 0;	// success!
+					break;
+				}
+				if (i == fcChip->fcLsExchangeLRU)	// wrapped-around array?
+				{
+					printk("LinkService X_ID space full\n");
+					break;	// failed - prevent inf. loop
+				}
+			}
+		}
+		fcChip->fcLsExchangeLRU = i + 1;	// next! (rollover check next pass)
 
-    i = fcChip->fcLsExchangeLRU; // typically it's already free!
-    if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
-    {
-      ulStatus = 0; // success!
-    }
-    
-    else
-    {         // YUK! we need to do a linear search for free element
-              // Fragmentation of the fcExchange array is due to excessively
-              // long completions or timeouts.
-      
-      while( TRUE )
-      {
-        if( ++i >= TACH_MAX_XID ) // rollover check
-          i = TACH_SEST_LEN;// beginning of Link Service X_IDs
-
-//        printk( "looping for xchng ID: i=%d, type=%Xh\n", 
-//         i, Exchanges->fcExchange[i].type);
-
-        if( Exchanges->fcExchange[i].type == 0 ) // "free"?
-        {
-          ulStatus = 0; // success!
-          break;
-        }
-        if( i == fcChip->fcLsExchangeLRU ) // wrapped-around array?
-        {
-          printk( "LinkService X_ID space full\n");
-          break;       // failed - prevent inf. loop
-        }
-      }
-    }
-    fcChip->fcLsExchangeLRU = i + 1; // next! (rollover check next pass)
+	}
 
-  }
+	if (!ulStatus)		// success?
+		Exchanges->fcExchange[i].type = type;	// allocate it.
 
-  if( !ulStatus )  // success?
-    Exchanges->fcExchange[i].type = type; // allocate it.
-  
-  else
-    i = -1;  // error - all exchanges "open"
+	else
+		i = -1;		// error - all exchanges "open"
 
-  return i;  
+	return i;
 }
 
-static void
-cpqfc_pci_unmap_extended_sg(struct pci_dev *pcidev,
-	PTACHYON fcChip,
-	ULONG x_ID)
+static void cpqfc_pci_unmap_extended_sg(struct pci_dev *pcidev, PTACHYON fcChip, u32 x_ID)
 {
 	// Unmaps the memory regions used to hold the scatter gather lists
 
 	PSGPAGES i;
 
 	// Were there any such regions needing unmapping?
-	if (! USES_EXTENDED_SGLIST(fcChip->SEST, x_ID))
-		return;	// No such regions, we're outta here.
+	if (!USES_EXTENDED_SGLIST(fcChip->SEST, x_ID))
+		return;		// No such regions, we're outta here.
 
 	// for each extended scatter gather region needing unmapping... 
-	for (i=fcChip->SEST->sgPages[x_ID] ; i != NULL ; i = i->next)
-		pci_unmap_single(pcidev, i->busaddr, i->maplen,
-			scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
+	for (i = fcChip->SEST->sgPages[x_ID]; i != NULL; i = i->next)
+		pci_unmap_single(pcidev, i->busaddr, i->maplen, scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
 }
 
 // Called also from cpqfcTScontrol.o, so can't be static
-void
-cpqfc_pci_unmap(struct pci_dev *pcidev, 
-	Scsi_Cmnd *cmd, 
-	PTACHYON fcChip, 
-	ULONG x_ID)
+void cpqfc_pci_unmap(struct pci_dev *pcidev, Scsi_Cmnd * cmd, PTACHYON fcChip, u32 x_ID)
 {
 	// Undo the DMA mappings
 	if (cmd->use_sg) {	// Used scatter gather list for data buffer?
 		cpqfc_pci_unmap_extended_sg(pcidev, fcChip, x_ID);
-		pci_unmap_sg(pcidev, cmd->buffer, cmd->use_sg,
-			scsi_to_pci_dma_dir(cmd->sc_data_direction));
+		pci_unmap_sg(pcidev, cmd->buffer, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
 		// printk("umsg %d\n", cmd->use_sg);
-	}
-	else if (cmd->request_bufflen) {
+	} else if (cmd->request_bufflen) {
 		// printk("ums %p ", fcChip->SEST->u[ x_ID ].IWE.GAddr1);
-		pci_unmap_single(pcidev, fcChip->SEST->u[ x_ID ].IWE.GAddr1,
-			cmd->request_bufflen,
-			scsi_to_pci_dma_dir(cmd->sc_data_direction));
-	}	 
+		pci_unmap_single(pcidev, fcChip->SEST->u[x_ID].IWE.GAddr1, cmd->request_bufflen, scsi_to_pci_dma_dir(cmd->sc_data_direction));
+	}
 }
 
 // We call this routine to free an Exchange for any reason:
 // completed successfully, completed with error, aborted, etc.
 
-// returns FALSE if Exchange failed and "retry" is acceptable
-// returns TRUE if Exchange was successful, or retry is impossible
+// returns 0 if Exchange failed and "retry" is acceptable
+// returns 1 if Exchange was successful, or retry is impossible
 // (e.g. port/device gone).
 //scompleteexchange
 
-void cpqfcTSCompleteExchange( 
-       struct pci_dev *pcidev,
-       PTACHYON fcChip, 
-       ULONG x_ID)
-{
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  int already_unmapped = 0;
-  
-  if( x_ID < TACH_SEST_LEN ) // SEST-based (or LinkServ for FCP exchange)
-  {
-    if( Exchanges->fcExchange[ x_ID ].Cmnd == NULL ) // what#@!
-    {
-//      TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
-      printk(" x_ID %Xh, type %Xh, NULL ptr!\n", x_ID,
-			Exchanges->fcExchange[ x_ID ].type);
+void cpqfcTSCompleteExchange(struct pci_dev *pcidev, PTACHYON fcChip, u32 x_ID)
+{
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	int already_unmapped = 0;
 
-      goto CleanUpSestResources;  // this path should be very rare.
-    }
+	if (x_ID < TACH_SEST_LEN)	// SEST-based (or LinkServ for FCP exchange)
+	{
+		if (Exchanges->fcExchange[x_ID].Cmnd == NULL)	// what#@!
+		{
+//			TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
+			printk(" x_ID %Xh, type %Xh, NULL ptr!\n", x_ID, Exchanges->fcExchange[x_ID].type);
 
-    // we have Linux Scsi Cmnd ptr..., now check our Exchange status
-    // to decide how to complete this SEST FCP exchange
+			goto CleanUpSestResources;	// this path should be very rare.
+		}
+		// we have Linux Scsi Cmnd ptr..., now check our Exchange status
+		// to decide how to complete this SEST FCP exchange
 
-    if( Exchanges->fcExchange[ x_ID ].status ) // perhaps a Tach indicated problem,
-                                             // or abnormal exchange completion
-    {
-      // set FCP Link statistics
-     
-      if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT)
-        fcChip->fcStats.timeouts++;
-      if( Exchanges->fcExchange[ x_ID ].status & INITIATOR_ABORT)
-        fcChip->fcStats.FC4aborted++;
-      if( Exchanges->fcExchange[ x_ID ].status & COUNT_ERROR)
-        fcChip->fcStats.CntErrors++;
-      if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX)
-        fcChip->fcStats.linkFailTX++;
-      if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_RX)
-        fcChip->fcStats.linkFailRX++;
-      if( Exchanges->fcExchange[ x_ID ].status & OVERFLOW)
-        fcChip->fcStats.CntErrors++;
-
-      // First, see if the Scsi upper level initiated an ABORT on this
-      // exchange...
-      if( Exchanges->fcExchange[ x_ID ].status == INITIATOR_ABORT )
-      {
-        printk(" DID_ABORT, x_ID %Xh, Cmnd %p ", 
-            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-        goto CleanUpSestResources;  // (we don't expect Linux _aborts)
-      }
-
-      // Did our driver timeout the Exchange, or did Tachyon indicate
-      // a failure during transmission?  Ask for retry with "SOFT_ERROR"
-      else if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT) 
-      {
-//        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
-//            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
-      }
-      
-      // Did frame(s) for an open exchange arrive in the SFQ,
-      // meaning the SEST was unable to process them?
-      else if( Exchanges->fcExchange[ x_ID ].status & SFQ_FRAME) 
-      {
-//        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
-//            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
-      }
-      
-      // Did our driver timeout the Exchange, or did Tachyon indicate
-      // a failure during transmission?  Ask for retry with "SOFT_ERROR"
-      else if( 
-               (Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX) ||
-               (Exchanges->fcExchange[ x_ID ].status & PORTID_CHANGED) ||
-	       (Exchanges->fcExchange[ x_ID ].status & FRAME_TO)    ||
-	       (Exchanges->fcExchange[ x_ID ].status & INV_ENTRY)    ||
-	       (Exchanges->fcExchange[ x_ID ].status & ABORTSEQ_NOTIFY)    )
-
-
-      {
-//        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
-//            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
-
-
-      }
-
-      // e.g., a LOGOut happened, or device never logged back in.
-      else if( Exchanges->fcExchange[ x_ID ].status & DEVICE_REMOVED) 
-      {
-//	printk(" *LOGOut or timeout on login!* ");
-	// trigger?
-//        TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
-
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_BAD_TARGET <<16);
-      }      
-		
-		      
-      // Did Tachyon indicate a CNT error?  We need further analysis
-      // to determine if the exchange is acceptable
-      else if( Exchanges->fcExchange[ x_ID ].status == COUNT_ERROR)
-      {
-        UCHAR ScsiStatus;
-        FCP_STATUS_RESPONSE *pFcpStatus = 
-	  (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
-
-      	ScsiStatus = pFcpStatus->fcp_status >>24;
-  
-	// If the command is a SCSI Read/Write type, we don't tolerate
-	// count errors of any kind; assume the count error is due to
-	// a dropped frame and ask for retry...
-	
-	if(( (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x8) ||
-	    (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x28) ||		
-            (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0xA) ||
-            (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x2A) )
-	                   &&
-                     ScsiStatus == 0 )
-	{
-          // ask for retry
-/*          printk("COUNT_ERROR retry, x_ID %Xh, status %Xh, Cmnd %p\n", 
-            x_ID, Exchanges->fcExchange[ x_ID ].status,
-            Exchanges->fcExchange[ x_ID ].Cmnd);*/
-          Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
-	}
-	
-	else  // need more analysis
-	{
-	  cpqfcTSCheckandSnoopFCP(fcChip, x_ID);  // (will set ->result)
-	}
-      }
-      
-      // default: NOTE! We don't ever want to get here.  Getting here
-      // implies something new is happening that we've never had a test
-      // case for.  Need code maintenance!  Return "ERROR"
-      else
-      {
-	unsigned int stat = Exchanges->fcExchange[ x_ID ].status;
-        printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p", 
-          Exchanges->fcExchange[ x_ID ].status, x_ID, 
-	  Exchanges->fcExchange[ x_ID ].Cmnd);
-
-	if (stat & INVALID_ARGS)	printk(" INVALID_ARGS ");
-	if (stat & LNKDWN_OSLS)		printk(" LNKDWN_OSLS ");
-	if (stat & LNKDWN_LASER)	printk(" LNKDWN_LASER ");
-	if (stat & OUTQUE_FULL)		printk(" OUTQUE_FULL ");
-	if (stat & DRIVERQ_FULL)	printk(" DRIVERQ_FULL ");
-	if (stat & SEST_FULL)		printk(" SEST_FULL ");
-	if (stat & BAD_ALPA)		printk(" BAD_ALPA ");
-	if (stat & OVERFLOW)		printk(" OVERFLOW ");
-	if (stat & COUNT_ERROR)		printk(" COUNT_ERROR ");
-	if (stat & LINKFAIL_RX)		printk(" LINKFAIL_RX ");
-	if (stat & ABORTSEQ_NOTIFY)	printk(" ABORTSEQ_NOTIFY ");
-	if (stat & LINKFAIL_TX)		printk(" LINKFAIL_TX ");
-	if (stat & HOSTPROG_ERR)	printk(" HOSTPROG_ERR ");
-	if (stat & FRAME_TO)		printk(" FRAME_TO ");
-	if (stat & INV_ENTRY)		printk(" INV_ENTRY ");
-	if (stat & SESTPROG_ERR)	printk(" SESTPROG_ERR ");
-	if (stat & OUTBOUND_TIMEOUT)	printk(" OUTBOUND_TIMEOUT ");
-	if (stat & INITIATOR_ABORT)	printk(" INITIATOR_ABORT ");
-	if (stat & MEMPOOL_FAIL)	printk(" MEMPOOL_FAIL ");
-	if (stat & FC2_TIMEOUT)		printk(" FC2_TIMEOUT ");
-	if (stat & TARGET_ABORT)	printk(" TARGET_ABORT ");
-	if (stat & EXCHANGE_QUEUED)	printk(" EXCHANGE_QUEUED ");
-	if (stat & PORTID_CHANGED)	printk(" PORTID_CHANGED ");
-	if (stat & DEVICE_REMOVED)	printk(" DEVICE_REMOVED ");
-	if (stat & SFQ_FRAME)		printk(" SFQ_FRAME ");
-	printk("\n");
+		if (Exchanges->fcExchange[x_ID].status)	// perhaps a Tach indicated problem,
+			// or abnormal exchange completion
+		{
+			// set FCP Link statistics
+
+			if (Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT)
+				fcChip->fcStats.timeouts++;
+			if (Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)
+				fcChip->fcStats.FC4aborted++;
+			if (Exchanges->fcExchange[x_ID].status & COUNT_ERROR)
+				fcChip->fcStats.CntErrors++;
+			if (Exchanges->fcExchange[x_ID].status & LINKFAIL_TX)
+				fcChip->fcStats.linkFailTX++;
+			if (Exchanges->fcExchange[x_ID].status & LINKFAIL_RX)
+				fcChip->fcStats.linkFailRX++;
+			if (Exchanges->fcExchange[x_ID].status & OVERFLOW)
+				fcChip->fcStats.CntErrors++;
+
+			// First, see if the Scsi upper level initiated an ABORT on this
+			// exchange...
+			if (Exchanges->fcExchange[x_ID].status == INITIATOR_ABORT) {
+				printk(" DID_ABORT, x_ID %Xh, Cmnd %p ", x_ID, Exchanges->fcExchange[x_ID].Cmnd);
+				goto CleanUpSestResources;	// (we don't expect Linux _aborts)
+			}
+			// Did our driver timeout the Exchange, or did Tachyon indicate
+			// a failure during transmission?  Ask for retry with "SOFT_ERROR"
+			else if (Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT) {
+//				printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
+//					x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+				Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
+			}
+			// Did frame(s) for an open exchange arrive in the SFQ,
+			// meaning the SEST was unable to process them?
+			else if (Exchanges->fcExchange[x_ID].status & SFQ_FRAME) {
+//				printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
+//					x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+				Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
+			}
+			// Did our driver timeout the Exchange, or did Tachyon indicate
+			// a failure during transmission?  Ask for retry with "SOFT_ERROR"
+			else if ((Exchanges->fcExchange[x_ID].status & LINKFAIL_TX) ||
+				 (Exchanges->fcExchange[x_ID].status & PORTID_CHANGED) || (Exchanges->fcExchange[x_ID].status & FRAME_TO) || (Exchanges->fcExchange[x_ID].status & INV_ENTRY) || (Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY))
+
+			{
+//				printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
+//					x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+				Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
 
-        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_ERROR <<16);
-      }
-    }
-    else    // definitely no Tach problem, but perhaps an FCP problem
-    {
-      // set FCP Link statistic
-      fcChip->fcStats.ok++;
-      cpqfcTSCheckandSnoopFCP( fcChip, x_ID);  // (will set ->result)    
-    }
 
-    cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, 
-			fcChip, x_ID); // undo DMA mappings.
-    already_unmapped = 1;
-
-    // OK, we've set the Scsi "->result" field, so proceed with calling
-    // Linux Scsi "done" (if not NULL), and free any kernel memory we
-    // may have allocated for the exchange.
-
-  PCI_TRACEO( (ULONG)Exchanges->fcExchange[x_ID].Cmnd, 0xAC);
-    // complete the command back to upper Scsi drivers
-    if( Exchanges->fcExchange[ x_ID ].Cmnd->scsi_done != NULL)
-    {
-      // Calling "done" on an Linux _abort() aborted
-      // Cmnd causes a kernel panic trying to re-free mem.
-      // Actually, we shouldn't do anything with an _abort CMND
-      if( Exchanges->fcExchange[ x_ID ].Cmnd->result != (DID_ABORT<<16) )
-      {
-        PCI_TRACE(0xAC)
-	call_scsi_done(Exchanges->fcExchange[ x_ID ].Cmnd);
-      }
-      else
-      {
-	Exchanges->fcExchange[ x_ID ].Cmnd->SCp.sent_command = 0;
-//	printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n",
-//			x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
-      }
-    }
-    else{
-	Exchanges->fcExchange[ x_ID ].Cmnd->SCp.sent_command = 0;
-      printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID,
-	Exchanges->fcExchange[ x_ID ].type, 
-	Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0]);	      
-      printk(" cpqfcTS: Null scsi_done function pointer!\n");
-    }
+			}
+			// e.g., a LOGOut happened, or device never logged back in.
+			else if (Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) {
+//				printk(" *LOGOut or timeout on login!* ");
+//				trigger?
+//				TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
+				Exchanges->fcExchange[x_ID].Cmnd->result = (DID_BAD_TARGET << 16);
+			}
+
+			// Did Tachyon indicate a CNT error?  We need further analysis
+			// to determine if the exchange is acceptable
+			else if (Exchanges->fcExchange[x_ID].status == COUNT_ERROR) {
+				u8 ScsiStatus;
+				FCP_STATUS_RESPONSE *pFcpStatus = (PFCP_STATUS_RESPONSE) & fcChip->SEST->RspHDR[x_ID].pl;
+
+				ScsiStatus = pFcpStatus->fcp_status >> 24;
+
+				// If the command is a SCSI Read/Write type, we don't tolerate
+				// count errors of any kind; assume the count error is due to
+				// a dropped frame and ask for retry...
+
+				if (((Exchanges->fcExchange[x_ID].Cmnd->cmnd[0] == 0x8) || (Exchanges->fcExchange[x_ID].Cmnd->cmnd[0] == 0x28) || (Exchanges->fcExchange[x_ID].Cmnd->cmnd[0] == 0xA) || (Exchanges->fcExchange[x_ID].Cmnd->cmnd[0] == 0x2A))
+				    && ScsiStatus == 0) {
+					// ask for retry
+//					printk("COUNT_ERROR retry, x_ID %Xh, status %Xh, Cmnd %p\n", 
+//						x_ID, Exchanges->fcExchange[ x_ID ].status,
+//						Exchanges->fcExchange[ x_ID ].Cmnd);
+					Exchanges->fcExchange[x_ID].Cmnd->result = (DID_SOFT_ERROR << 16);
+				}
+
+				else	// need more analysis
+				{
+					cpqfcTSCheckandSnoopFCP(fcChip, x_ID);	// (will set ->result)
+				}
+			}
+			// default: NOTE! We don't ever want to get here.  Getting here
+			// implies something new is happening that we've never had a test
+			// case for.  Need code maintenance!  Return "ERROR"
+			else {
+				unsigned int stat = Exchanges->fcExchange[x_ID].status;
+				printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p", Exchanges->fcExchange[x_ID].status, x_ID, Exchanges->fcExchange[x_ID].Cmnd);
+
+				if (stat & INVALID_ARGS)
+					printk(" INVALID_ARGS ");
+				if (stat & LNKDWN_OSLS)
+					printk(" LNKDWN_OSLS ");
+				if (stat & LNKDWN_LASER)
+					printk(" LNKDWN_LASER ");
+				if (stat & OUTQUE_FULL)
+					printk(" OUTQUE_FULL ");
+				if (stat & DRIVERQ_FULL)
+					printk(" DRIVERQ_FULL ");
+				if (stat & SEST_FULL)
+					printk(" SEST_FULL ");
+				if (stat & BAD_ALPA)
+					printk(" BAD_ALPA ");
+				if (stat & OVERFLOW)
+					printk(" OVERFLOW ");
+				if (stat & COUNT_ERROR)
+					printk(" COUNT_ERROR ");
+				if (stat & LINKFAIL_RX)
+					printk(" LINKFAIL_RX ");
+				if (stat & ABORTSEQ_NOTIFY)
+					printk(" ABORTSEQ_NOTIFY ");
+				if (stat & LINKFAIL_TX)
+					printk(" LINKFAIL_TX ");
+				if (stat & HOSTPROG_ERR)
+					printk(" HOSTPROG_ERR ");
+				if (stat & FRAME_TO)
+					printk(" FRAME_TO ");
+				if (stat & INV_ENTRY)
+					printk(" INV_ENTRY ");
+				if (stat & SESTPROG_ERR)
+					printk(" SESTPROG_ERR ");
+				if (stat & OUTBOUND_TIMEOUT)
+					printk(" OUTBOUND_TIMEOUT ");
+				if (stat & INITIATOR_ABORT)
+					printk(" INITIATOR_ABORT ");
+				if (stat & MEMPOOL_FAIL)
+					printk(" MEMPOOL_FAIL ");
+				if (stat & FC2_TIMEOUT)
+					printk(" FC2_TIMEOUT ");
+				if (stat & TARGET_ABORT)
+					printk(" TARGET_ABORT ");
+				if (stat & EXCHANGE_QUEUED)
+					printk(" EXCHANGE_QUEUED ");
+				if (stat & PORTID_CHANGED)
+					printk(" PORTID_CHANGED ");
+				if (stat & DEVICE_REMOVED)
+					printk(" DEVICE_REMOVED ");
+				if (stat & SFQ_FRAME)
+					printk(" SFQ_FRAME ");
+				printk("\n");
+
+				Exchanges->fcExchange[x_ID].Cmnd->result = (DID_ERROR << 16);
+			}
+		} else		// definitely no Tach problem, but perhaps an FCP problem
+		{
+			// set FCP Link statistic
+			fcChip->fcStats.ok++;
+			cpqfcTSCheckandSnoopFCP(fcChip, x_ID);	// (will set ->result)    
+		}
+
+		cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, fcChip, x_ID);	// undo DMA mappings.
+		already_unmapped = 1;
+
+		// OK, we've set the Scsi "->result" field, so proceed with calling
+		// Linux Scsi "done" (if not NULL), and free any kernel memory we
+		// may have allocated for the exchange.
+
+		PCI_TRACEO((u32) Exchanges->fcExchange[x_ID].Cmnd, 0xAC);
+		// complete the command back to upper Scsi drivers
+		if (Exchanges->fcExchange[x_ID].Cmnd->scsi_done != NULL) {
+			// Calling "done" on an Linux _abort() aborted
+			// Cmnd causes a kernel panic trying to re-free mem.
+			// Actually, we shouldn't do anything with an _abort CMND
+			if (Exchanges->fcExchange[x_ID].Cmnd->result != (DID_ABORT << 16)) {
+				PCI_TRACE(0xAC)
+				    call_scsi_done(Exchanges->fcExchange[x_ID].Cmnd);
+			} else {
+				Exchanges->fcExchange[x_ID].Cmnd->SCp.sent_command = 0;
+//				printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n",
+//					x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+			}
+		} else {
+			Exchanges->fcExchange[x_ID].Cmnd->SCp.sent_command = 0;
+			printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID, Exchanges->fcExchange[x_ID].type, Exchanges->fcExchange[x_ID].Cmnd->cmnd[0]);
+			printk(" cpqfcTS: Null scsi_done function pointer!\n");
+		}
 
 
-    // Now, clean up non-Scsi_Cmnd items...
+		// Now, clean up non-Scsi_Cmnd items...
 CleanUpSestResources:
-   
-    if (!already_unmapped) 
-	cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, 
-			fcChip, x_ID); // undo DMA mappings.
-
-    // Was an Extended Scatter/Gather page allocated?  We know
-    // this by checking DWORD 4, bit 31 ("LOC") of SEST entry
-    if( !(fcChip->SEST->u[ x_ID ].IWE.Buff_Off & 0x80000000))
-    {
-      PSGPAGES p, next;
 
-      // extended S/G list was used -- Free the allocated ext. S/G pages
-      for (p = fcChip->SEST->sgPages[x_ID]; p != NULL; p = next) {
-	 next = p->next;
-	 kfree(p);
-      }
-      fcChip->SEST->sgPages[x_ID] = NULL;
-    }
-  
-    Exchanges->fcExchange[ x_ID ].Cmnd = NULL; 
-  }  // Done with FCP (SEST) exchanges
-
-
-  // the remaining logic is common to ALL Exchanges: 
-  // FCP(SEST) and LinkServ.
-
-  Exchanges->fcExchange[ x_ID ].type = 0; // there -- FREE!  
-  Exchanges->fcExchange[ x_ID ].status = 0; 
-
-  PCI_TRACEO( x_ID, 0xAC)
-     
-  
-  return;
-}   // (END of CompleteExchange function)
- 
+		if (!already_unmapped)
+			cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, fcChip, x_ID);	// undo DMA mappings.
+
+		// Was an Extended Scatter/Gather page allocated?  We know
+		// this by checking DWORD 4, bit 31 ("LOC") of SEST entry
+		if (!(fcChip->SEST->u[x_ID].IWE.Buff_Off & 0x80000000)) {
+			PSGPAGES p, next;
+
+			// extended S/G list was used -- Free the allocated ext. S/G pages
+			for (p = fcChip->SEST->sgPages[x_ID]; p != NULL; p = next) {
+				next = p->next;
+				kfree(p);
+			}
+			fcChip->SEST->sgPages[x_ID] = NULL;
+		}
+
+		Exchanges->fcExchange[x_ID].Cmnd = NULL;
+	}			// Done with FCP (SEST) exchanges
+
+
+	// the remaining logic is common to ALL Exchanges: 
+	// FCP(SEST) and LinkServ.
+
+	Exchanges->fcExchange[x_ID].type = 0;	// there -- FREE!  
+	Exchanges->fcExchange[x_ID].status = 0;
+
+	PCI_TRACEO(x_ID, 0xAC)
+}				// (END of CompleteExchange function)
+
 
 
 
@@ -6249,161 +5136,137 @@
 // device types, etc., to facilitate the Fibre-Channel to SCSI
 // "mapping".  
 // (Watch for BIG Endian confusion on some payload fields)
-void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID)
+void cpqfcTSCheckandSnoopFCP(PTACHYON fcChip, u32 x_ID)
 {
-  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
-  Scsi_Cmnd *Cmnd = Exchanges->fcExchange[ x_ID].Cmnd;
-  FCP_STATUS_RESPONSE *pFcpStatus = 
-    (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
-  UCHAR ScsiStatus;
+	FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+	Scsi_Cmnd *Cmnd = Exchanges->fcExchange[x_ID].Cmnd;
+	FCP_STATUS_RESPONSE *pFcpStatus = (PFCP_STATUS_RESPONSE) & fcChip->SEST->RspHDR[x_ID].pl;
+	u8 ScsiStatus;
 
-  ScsiStatus = pFcpStatus->fcp_status >>24;
+	ScsiStatus = pFcpStatus->fcp_status >> 24;
 
 #ifdef FCP_COMPLETION_DBG
-  printk("ScsiStatus = 0x%X\n", ScsiStatus);
-#endif	
+	printk("ScsiStatus = 0x%X\n", ScsiStatus);
+#endif
 
-  // First, check FCP status
-  if( pFcpStatus->fcp_status & FCP_RSP_LEN_VALID )
-  {
-    // check response code (RSP_CODE) -- most popular is bad len
-    // 1st 4 bytes of rsp info -- only byte 3 interesting
-    if( pFcpStatus->fcp_rsp_info & FCP_DATA_LEN_NOT_BURST_LEN )
-    { 
+	// First, check FCP status
+	if (pFcpStatus->fcp_status & FCP_RSP_LEN_VALID) {
+		// check response code (RSP_CODE) -- most popular is bad len
+		// 1st 4 bytes of rsp info -- only byte 3 interesting
+		if (pFcpStatus->fcp_rsp_info & FCP_DATA_LEN_NOT_BURST_LEN) {
 
-      // do we EVER get here?
-      printk("cpqfcTS: FCP data len not burst len, x_ID %Xh\n", x_ID);
-    }
-  }
+			// do we EVER get here?
+			printk("cpqfcTS: FCP data len not burst len, x_ID %Xh\n", x_ID);
+		}
+	}
+	// for now, go by the ScsiStatus, and manipulate certain
+	// commands when necessary...
+	if (ScsiStatus == 0)	// SCSI status byte "good"?
+	{
+		Cmnd->result = 0;	// everything's OK
 
-  // for now, go by the ScsiStatus, and manipulate certain
-  // commands when necessary...
-  if( ScsiStatus == 0) // SCSI status byte "good"?
-  {
-    Cmnd->result = 0; // everything's OK
+		if ((Cmnd->cmnd[0] == INQUIRY)) {
+			u8 *InquiryData = Cmnd->request_buffer;
+			PFC_LOGGEDIN_PORT pLoggedInPort;
+
+			// We need to manipulate INQUIRY
+			// strings for COMPAQ RAID controllers to force
+			// Linux to scan additional LUNs.  Namely, set
+			// the Inquiry string byte 2 (ANSI-approved version)
+			// to 2.
+
+			if (!memcmp(&InquiryData[8], "COMPAQ", 6)) {
+				InquiryData[2] = 0x2;	// claim SCSI-2 compliance,
+				// so multiple LUNs may be scanned.
+				// (no SCSI-2 problems known in CPQ)
+			}
+			// snoop the Inquiry to detect Disk, Tape, etc. type
+			// (search linked list for the port_id we sent INQUIRY to)
+			pLoggedInPort = fcFindLoggedInPort(fcChip, NULL,	// DON'T search Scsi Nexus (we will set it)
+							   Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF, NULL,	// DON'T search linked list for FC WWN
+							   NULL);	// DON'T care about end of list
+
+			if (pLoggedInPort) {
+				pLoggedInPort->ScsiNexus.InqDeviceType = InquiryData[0];
+			} else {
+				printk("cpqfcTS: can't find LoggedIn FC port %06X for INQUIRY\n", Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF);
+			}
+		}
+	}
 
-    if( (Cmnd->cmnd[0] == INQUIRY)) 
-    {
-      UCHAR *InquiryData = Cmnd->request_buffer;
-      PFC_LOGGEDIN_PORT pLoggedInPort;
+	// Scsi Status not good -- pass it back to caller 
 
-      // We need to manipulate INQUIRY
-      // strings for COMPAQ RAID controllers to force
-      // Linux to scan additional LUNs.  Namely, set
-      // the Inquiry string byte 2 (ANSI-approved version)
-      // to 2.
-
-      if( !memcmp( &InquiryData[8], "COMPAQ", 6 ))
-      {
-        InquiryData[2] = 0x2;  // claim SCSI-2 compliance,
-                               // so multiple LUNs may be scanned.
-                               // (no SCSI-2 problems known in CPQ)
-      }
-        
-      // snoop the Inquiry to detect Disk, Tape, etc. type
-      // (search linked list for the port_id we sent INQUIRY to)
-      pLoggedInPort = fcFindLoggedInPort( fcChip,
-        NULL,     // DON'T search Scsi Nexus (we will set it)
-        Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,        
-        NULL,     // DON'T search linked list for FC WWN
-        NULL);    // DON'T care about end of list
- 
-      if( pLoggedInPort )
-      {
-        pLoggedInPort->ScsiNexus.InqDeviceType = InquiryData[0];
-      }
-      else
-      {
-	printk("cpqfcTS: can't find LoggedIn FC port %06X for INQUIRY\n",
-          Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
-      }
-    }
-  }
+	else {
+		Cmnd->result = ScsiStatus;	// SCSI status byte is 1st
 
+		// check for valid "sense" data
 
-  // Scsi Status not good -- pass it back to caller 
+		if (pFcpStatus->fcp_status & FCP_SNS_LEN_VALID) {	// limit Scsi Sense field length!
+			int SenseLen = pFcpStatus->fcp_sns_len >> 24;	// (BigEndian) lower byte
 
-  else
-  {
-    Cmnd->result = ScsiStatus; // SCSI status byte is 1st
-    
-    // check for valid "sense" data
+			SenseLen = SenseLen > sizeof(Cmnd->sense_buffer) ? sizeof(Cmnd->sense_buffer) : SenseLen;
 
-    if( pFcpStatus->fcp_status & FCP_SNS_LEN_VALID ) 
-    {            // limit Scsi Sense field length!
-      int SenseLen = pFcpStatus->fcp_sns_len >>24; // (BigEndian) lower byte
-      
-      SenseLen = SenseLen > sizeof( Cmnd->sense_buffer) ? 
-        sizeof( Cmnd->sense_buffer) : SenseLen;
-	   
-
-#ifdef FCP_COMPLETION_DBG	    
-      printk("copy sense_buffer %p, len %d, result %Xh\n",
-        Cmnd->sense_buffer, SenseLen, Cmnd->result);
-#endif	  
-
-      // NOTE: There is some dispute over the FCP response
-      // format.  Most FC devices assume that FCP_RSP_INFO
-      // is 8 bytes long, in spite of the fact that FCP_RSP_LEN
-      // is (virtually) always 0 and the field is "invalid".  
-      // Some other devices assume that
-      // the FCP_SNS_INFO begins after FCP_RSP_LEN bytes (i.e. 0)
-      // when the FCP_RSP is invalid (this almost appears to be
-      // one of those "religious" issues).
-      // Consequently, we test the usual position of FCP_SNS_INFO
-      // for 7Xh, since the SCSI sense format says the first
-      // byte ("error code") should be 0x70 or 0x71.  In practice,
-      // we find that every device does in fact have 0x70 or 0x71
-      // in the first byte position, so this test works for all
-      // FC devices.  
-      // (This logic is especially effective for the CPQ/DEC HSG80
-      // & HSG60 controllers).
-
-      if( (pFcpStatus->fcp_sns_info[0] & 0x70) == 0x70 )
-        memcpy( Cmnd->sense_buffer, 
-          &pFcpStatus->fcp_sns_info[0], SenseLen);
-      else
-      {
-        unsigned char *sbPtr = 
-		(unsigned char *)&pFcpStatus->fcp_sns_info[0];
-        sbPtr -= 8;  // back up 8 bytes hoping to find the
-	             // start of the sense buffer
-        memcpy( Cmnd->sense_buffer, sbPtr, SenseLen);
-      }
-
-      // in the special case of Device Reset, tell upper layer
-      // to immediately retry (with SOFT_ERROR status)
-      // look for Sense Key Unit Attention (0x6) with ASC Device
-      // Reset (0x29)
-      //	    printk("SenseLen %d, Key = 0x%X, ASC = 0x%X\n",
-      //		    SenseLen, Cmnd->sense_buffer[2], 
-      //                   Cmnd->sense_buffer[12]);
-      if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
-	        (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
-      {
-        Cmnd->result |= (DID_SOFT_ERROR << 16); // "Host" status byte 3rd
-      }
- 
-      // check for SenseKey "HARDWARE ERROR", ASC InternalTargetFailure
-      else if(  ((Cmnd->sense_buffer[2] & 0xF) == 0x4) &&  // "hardware error"
-      	        (Cmnd->sense_buffer[12] == 0x44) ) // Addtl. Sense Code 
-      {
+
+#ifdef FCP_COMPLETION_DBG
+			printk("copy sense_buffer %p, len %d, result %Xh\n", Cmnd->sense_buffer, SenseLen, Cmnd->result);
+#endif
+
+			// NOTE: There is some dispute over the FCP response
+			// format.  Most FC devices assume that FCP_RSP_INFO
+			// is 8 bytes long, in spite of the fact that FCP_RSP_LEN
+			// is (virtually) always 0 and the field is "invalid".  
+			// Some other devices assume that
+			// the FCP_SNS_INFO begins after FCP_RSP_LEN bytes (i.e. 0)
+			// when the FCP_RSP is invalid (this almost appears to be
+			// one of those "religious" issues).
+			// Consequently, we test the usual position of FCP_SNS_INFO
+			// for 7Xh, since the SCSI sense format says the first
+			// byte ("error code") should be 0x70 or 0x71.  In practice,
+			// we find that every device does in fact have 0x70 or 0x71
+			// in the first byte position, so this test works for all
+			// FC devices.  
+			// (This logic is especially effective for the CPQ/DEC HSG80
+			// & HSG60 controllers).
+
+			if ((pFcpStatus->fcp_sns_info[0] & 0x70) == 0x70)
+				memcpy(Cmnd->sense_buffer, &pFcpStatus->fcp_sns_info[0], SenseLen);
+			else {
+				unsigned char *sbPtr = (unsigned char *) &pFcpStatus->fcp_sns_info[0];
+				sbPtr -= 8;	// back up 8 bytes hoping to find the
+				// start of the sense buffer
+				memcpy(Cmnd->sense_buffer, sbPtr, SenseLen);
+			}
+
+			// in the special case of Device Reset, tell upper layer
+			// to immediately retry (with SOFT_ERROR status)
+			// look for Sense Key Unit Attention (0x6) with ASC Device
+			// Reset (0x29)
+			//            printk("SenseLen %d, Key = 0x%X, ASC = 0x%X\n",
+			//                    SenseLen, Cmnd->sense_buffer[2], 
+			//                   Cmnd->sense_buffer[12]);
+			if (((Cmnd->sense_buffer[2] & 0xF) == 0x6) && (Cmnd->sense_buffer[12] == 0x29))	// Sense Code "reset"
+			{
+				Cmnd->result |= (DID_SOFT_ERROR << 16);	// "Host" status byte 3rd
+			}
+			// check for SenseKey "HARDWARE ERROR", ASC InternalTargetFailure
+			else if (((Cmnd->sense_buffer[2] & 0xF) == 0x4) &&	// "hardware error"
+				 (Cmnd->sense_buffer[12] == 0x44))	// Addtl. Sense Code 
+			{
 //        printk("HARDWARE_ERROR, Channel/Target/Lun %d/%d/%d\n",
-//		Cmnd->channel, Cmnd->target, Cmnd->lun);
-      	Cmnd->result |= (DID_ERROR << 16); // "Host" status byte 3rd
-      }
-      
-    }  // (end of sense len valid)
+//              Cmnd->channel, Cmnd->target, Cmnd->lun);
+				Cmnd->result |= (DID_ERROR << 16);	// "Host" status byte 3rd
+			}
 
-    // there is no sense data to help out Linux's Scsi layers...
-    // We'll just return the Scsi status and hope he will "do the 
-    // right thing"
-    else
-    {
-      // as far as we know, the Scsi status is sufficient
-      Cmnd->result |= (DID_OK << 16); // "Host" status byte 3rd
-    }
-  }
+		}		// (end of sense len valid)
+
+		// there is no sense data to help out Linux's Scsi layers...
+		// We'll just return the Scsi status and hope he will "do the 
+		// right thing"
+		else {
+			// as far as we know, the Scsi status is sufficient
+			Cmnd->result |= (DID_OK << 16);	// "Host" status byte 3rd
+		}
+	}
 }
 
 
@@ -6413,118 +5276,108 @@
 // remember BIG ENDIAN payload - DWord values must be byte-reversed
 // (hence the affinity for byte pointer building).
 
-static int build_FCP_payload( Scsi_Cmnd *Cmnd, 
-      UCHAR* payload, ULONG type, ULONG fcp_dl )
+static int build_FCP_payload(Scsi_Cmnd * Cmnd, u8 * payload, u32 type, u32 fcp_dl)
 {
-  int i;
+	int i;
 
-  
-  switch( type)
-  {
-		  
-    case SCSI_IWE: 
-    case SCSI_IRE:        
-      // 8 bytes FCP_LUN
-      // Peripheral Device or Volume Set addressing, and LUN mapping
-      // When the FC port was looked up, we copied address mode
-      // and any LUN mask to the scratch pad SCp.phase & .mode
-
-      *payload++ = (UCHAR)Cmnd->SCp.phase;
-
-      // Now, because of "lun masking" 
-      // (aka selective storage presentation),
-      // the contiguous Linux Scsi lun number may not match the
-      // device's lun number, so we may have to "map".  
-      
-      *payload++ = (UCHAR)Cmnd->SCp.have_data_in;
-      
-      // We don't know of anyone in the FC business using these 
-      // extra "levels" of addressing.  In fact, confusion still exists
-      // just using the FIRST level... ;-)
-      
-      *payload++ = 0;  // 2nd level addressing
-      *payload++ = 0;
-      *payload++ = 0;  // 3rd level addressing
-      *payload++ = 0;
-      *payload++ = 0;  // 4th level addressing
-      *payload++ = 0;
-
-      // 4 bytes Control Field FCP_CNTL
-      *payload++ = 0;    // byte 0: (MSB) reserved
-      *payload++ = 0;    // byte 1: task codes
-
-                         // byte 2: task management flags
-      // another "use" of the spare field to accomplish TDR
-      // note combination needed
-      if( (Cmnd->cmnd[0] == RELEASE) &&
-          (Cmnd->SCp.buffers_residual == FCP_TARGET_RESET) )
-      {
-        Cmnd->cmnd[0] = 0;    // issue "Test Unit Ready" for TDR
-        *payload++ = 0x20;    // target device reset bit
-      }
-      else
-        *payload++ = 0;    // no TDR
-		      // byte 3: (LSB) execution management codes
-		      // bit 0 write, bit 1 read (don't set together)
-      
-      if( fcp_dl != 0 )
-      {
-        if( type == SCSI_IWE )         // WRITE
-          *payload++ = 1;
-        else                           // READ
-          *payload++ = 2;
-      }
-      else
-      {
-	// On some devices, if RD or WR bits are set,
-	// and fcp_dl is 0, they will generate an error on the command.
-	// (i.e., if direction is specified, they insist on a length).
-	*payload++ = 0;                // no data (necessary for CPQ)
-      }
-
-
-      // NOTE: clean this up if/when MAX_COMMAND_SIZE is increased to 16
-      // FCP_CDB allows 16 byte SCSI command descriptor blk;
-      // Linux SCSI CDB array is MAX_COMMAND_SIZE (12 at this time...)
-      for( i=0; (i < Cmnd->cmd_len) && i < MAX_COMMAND_SIZE; i++)
-	*payload++ = Cmnd->cmnd[i];
-
-      if( Cmnd->cmd_len == 16 )
-      {
-        memcpy( payload, &Cmnd->SCp.buffers_residual, 4);
-      }
-      payload+= (16 - i);  
-
-		      // FCP_DL is largest number of expected data bytes
-		      // per CDB (i.e. read/write command)
-      *payload++ = (UCHAR)(fcp_dl >>24);  // (MSB) 8 bytes data len FCP_DL
-      *payload++ = (UCHAR)(fcp_dl >>16);
-      *payload++ = (UCHAR)(fcp_dl >>8);
-      *payload++ = (UCHAR)fcp_dl;    // (LSB)
-      break;
-
-    case SCSI_TWE:          // need FCP_XFER_RDY
-      *payload++ = 0;     // (4 bytes) DATA_RO (MSB byte 0)
-      *payload++ = 0;
-      *payload++ = 0;
-      *payload++ = 0;     // LSB (byte 3)
-			     // (4 bytes) BURST_LEN
-			     // size of following FCP_DATA payload
-      *payload++ = (UCHAR)(fcp_dl >>24);  // (MSB) 8 bytes data len FCP_DL
-      *payload++ = (UCHAR)(fcp_dl >>16);
-      *payload++ = (UCHAR)(fcp_dl >>8);
-      *payload++ = (UCHAR)fcp_dl;    // (LSB)
-		       // 4 bytes RESERVED
-      *payload++ = 0;
-      *payload++ = 0;
-      *payload++ = 0;
-      *payload++ = 0;
-      break;
 
-    default:
-      break;
-  }
+	switch (type) {
 
-  return 0;
-}
+	case SCSI_IWE:
+	case SCSI_IRE:
+		// 8 bytes FCP_LUN
+		// Peripheral Device or Volume Set addressing, and LUN mapping
+		// When the FC port was looked up, we copied address mode
+		// and any LUN mask to the scratch pad SCp.phase & .mode
+
+		*payload++ = (u8) Cmnd->SCp.phase;
+
+		// Now, because of "lun masking" 
+		// (aka selective storage presentation),
+		// the contiguous Linux Scsi lun number may not match the
+		// device's lun number, so we may have to "map".  
+
+		*payload++ = (u8) Cmnd->SCp.have_data_in;
+
+		// We don't know of anyone in the FC business using these 
+		// extra "levels" of addressing.  In fact, confusion still exists
+		// just using the FIRST level... ;-)
+
+		*payload++ = 0;	// 2nd level addressing
+		*payload++ = 0;
+		*payload++ = 0;	// 3rd level addressing
+		*payload++ = 0;
+		*payload++ = 0;	// 4th level addressing
+		*payload++ = 0;
+
+		// 4 bytes Control Field FCP_CNTL
+		*payload++ = 0;	// byte 0: (MSB) reserved
+		*payload++ = 0;	// byte 1: task codes
+
+		// byte 2: task management flags
+		// another "use" of the spare field to accomplish TDR
+		// note combination needed
+		if ((Cmnd->cmnd[0] == RELEASE) && (Cmnd->SCp.buffers_residual == FCP_TARGET_RESET)) {
+			Cmnd->cmnd[0] = 0;	// issue "Test Unit Ready" for TDR
+			*payload++ = 0x20;	// target device reset bit
+		} else
+			*payload++ = 0;	// no TDR
+		// byte 3: (LSB) execution management codes
+		// bit 0 write, bit 1 read (don't set together)
+
+		if (fcp_dl != 0) {
+			if (type == SCSI_IWE)	// WRITE
+				*payload++ = 1;
+			else	// READ
+				*payload++ = 2;
+		} else {
+			// On some devices, if RD or WR bits are set,
+			// and fcp_dl is 0, they will generate an error on the command.
+			// (i.e., if direction is specified, they insist on a length).
+			*payload++ = 0;	// no data (necessary for CPQ)
+		}
+
+
+		// NOTE: clean this up if/when MAX_COMMAND_SIZE is increased to 16
+		// FCP_CDB allows 16 byte SCSI command descriptor blk;
+		// Linux SCSI CDB array is MAX_COMMAND_SIZE (12 at this time...)
+		for (i = 0; (i < Cmnd->cmd_len) && i < MAX_COMMAND_SIZE; i++)
+			*payload++ = Cmnd->cmnd[i];
+
+		if (Cmnd->cmd_len == 16) {
+			memcpy(payload, &Cmnd->SCp.buffers_residual, 4);
+		}
+		payload += (16 - i);
 
+		// FCP_DL is largest number of expected data bytes
+		// per CDB (i.e. read/write command)
+		*payload++ = (u8) (fcp_dl >> 24);	// (MSB) 8 bytes data len FCP_DL
+		*payload++ = (u8) (fcp_dl >> 16);
+		*payload++ = (u8) (fcp_dl >> 8);
+		*payload++ = (u8) fcp_dl;	// (LSB)
+		break;
+
+	case SCSI_TWE:		// need FCP_XFER_RDY
+		*payload++ = 0;	// (4 bytes) DATA_RO (MSB byte 0)
+		*payload++ = 0;
+		*payload++ = 0;
+		*payload++ = 0;	// LSB (byte 3)
+		// (4 bytes) BURST_LEN
+		// size of following FCP_DATA payload
+		*payload++ = (u8) (fcp_dl >> 24);	// (MSB) 8 bytes data len FCP_DL
+		*payload++ = (u8) (fcp_dl >> 16);
+		*payload++ = (u8) (fcp_dl >> 8);
+		*payload++ = (u8) fcp_dl;	// (LSB)
+		// 4 bytes RESERVED
+		*payload++ = 0;
+		*payload++ = 0;
+		*payload++ = 0;
+		*payload++ = 0;
+		break;
+
+	default:
+		break;
+	}
+
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/hosts.c linux.20pre10-ac2/drivers/scsi/hosts.c
--- linux.20pre10/drivers/scsi/hosts.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/hosts.c	2002-08-13 14:34:11.000000000 +0100
@@ -81,8 +81,8 @@
 struct Scsi_Host * scsi_hostlist;
 struct Scsi_Device_Template * scsi_devicelist;
 
-int max_scsi_hosts;
-int next_scsi_host;
+int max_scsi_hosts;	/* host_no for next new host */
+int next_scsi_host;	/* count of registered scsi hosts */
 
 void
 scsi_unregister(struct Scsi_Host * sh){
@@ -107,21 +107,8 @@
     if (shn) shn->host_registered = 0;
     /* else {} : This should not happen, we should panic here... */
     
-    /* If we are removing the last host registered, it is safe to reuse
-     * its host number (this avoids "holes" at boot time) (DB) 
-     * It is also safe to reuse those of numbers directly below which have
-     * been released earlier (to avoid some holes in numbering).
-     */
-    if(sh->host_no == max_scsi_hosts - 1) {
-	while(--max_scsi_hosts >= next_scsi_host) {
-	    shpnt = scsi_hostlist;
-	    while(shpnt && shpnt->host_no != max_scsi_hosts - 1)
-		shpnt = shpnt->next;
-	    if(shpnt)
-		break;
-	}
-    }
     next_scsi_host--;
+
     kfree((char *) sh);
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/hosts.h linux.20pre10-ac2/drivers/scsi/hosts.h
--- linux.20pre10/drivers/scsi/hosts.h	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/hosts.h	2002-10-11 00:35:04.000000000 +0100
@@ -291,9 +291,17 @@
      */
     unsigned emulated:1;
 
+    /*
+     * True for drivers that can do I/O from highmem
+     */
     unsigned highmem_io:1;
 
     /*
+     * True for drivers which can handle variable length IO
+     */
+    unsigned can_do_varyio:1;
+
+    /*
      * Name of proc directory
      */
     char *proc_name;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/ide-scsi.c linux.20pre10-ac2/drivers/scsi/ide-scsi.c
--- linux.20pre10/drivers/scsi/ide-scsi.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/ide-scsi.c	2002-09-06 00:56:59.000000000 +0100
@@ -1,7 +1,8 @@
 /*
- * linux/drivers/scsi/ide-scsi.c	Version 0.9		Jul   4, 1999
+ * linux/drivers/scsi/ide-scsi.c	Version 0.93    June 10, 2002
  *
  * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il>
+ * Copyright (C) 2001 - 2002 Andre Hedrick <andre@linux-ide.org>
  */
 
 /*
@@ -27,11 +28,19 @@
  *                        detection of devices with CONFIG_SCSI_MULTI_LUN
  * Ver 0.8   Feb 05 99   Optical media need translation too. Reverse 0.7.
  * Ver 0.9   Jul 04 99   Fix a bug in SG_SET_TRANSFORM.
+ * Ver 0.91  Jan 06 02   Added 'ignore' parameter when ide-scsi is a module
+ *                        so that use of scsi emulation can be made independent
+ *                        of load order when other IDE drivers are modules.
+ *                        Chris Ebenezer <chriseb@pobox.com>
+ * Ver 0.92  Mar 21 02   Include DevFs support
+ *                        Borsenkow Andrej <Andrej.Borsenkow@mow.siemens.ru>
+ * Ver 0.93  Jun 10 02   Fix "off by one" error in transforms
  */
 
-#define IDESCSI_VERSION "0.9"
+#define IDESCSI_VERSION "0.93"
 
 #include <linux/module.h>
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
@@ -53,76 +62,76 @@
 #include "ide-scsi.h"
 #include <scsi/sg.h>
 
-#define IDESCSI_DEBUG_LOG		0
+#define IDESCSI_DEBUG_LOG	0
 
 typedef struct idescsi_pc_s {
-	u8 c[12];				/* Actual packet bytes */
-	int request_transfer;			/* Bytes to transfer */
-	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 */
-	struct scatterlist *sg;			/* Scatter gather table */
-	int b_count;				/* Bytes transferred from current entry */
-	Scsi_Cmnd *scsi_cmd;			/* SCSI command */
-	void (*done)(Scsi_Cmnd *);		/* Scsi completion routine */
-	unsigned long flags;			/* Status/Action flags */
-	unsigned long timeout;			/* Command timeout */
+	u8 c[12];			/* Actual packet bytes */
+	int request_transfer;		/* Bytes to transfer */
+	int actually_transferred;	/* Bytes actually transferred */
+	int buffer_size;		/* Size of our data buffer */
+	struct request *rq;		/* The corresponding request */
+	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 */
+	void (*done)(Scsi_Cmnd *);	/* Scsi completion routine */
+	unsigned long flags;		/* Status/Action flags */
+	unsigned long timeout;		/* Command timeout */
 } idescsi_pc_t;
 
 /*
  *	Packet command status bits.
  */
-#define PC_DMA_IN_PROGRESS		0	/* 1 while DMA in progress */
-#define PC_WRITING			1	/* Data direction */
-#define PC_TRANSFORM			2	/* transform SCSI commands */
+#define PC_DMA_IN_PROGRESS	0	/* 1 while DMA in progress */
+#define PC_WRITING		1	/* Data direction */
+#define PC_TRANSFORM		2	/* transform SCSI commands */
 
 /*
  *	SCSI command transformation layer
  */
-#define IDESCSI_TRANSFORM		0	/* Enable/Disable transformation */
-#define IDESCSI_SG_TRANSFORM		1	/* /dev/sg transformation */
+#define IDESCSI_TRANSFORM	0	/* Enable/Disable transformation */
+#define IDESCSI_SG_TRANSFORM	1	/* /dev/sg transformation */
 
 /*
  *	Log flags
  */
-#define IDESCSI_LOG_CMD			0	/* Log SCSI commands */
+#define IDESCSI_LOG_CMD		0	/* Log SCSI commands */
+
+#define IDESCSI_DEVFS
 
 typedef struct {
 	ide_drive_t *drive;
-	idescsi_pc_t *pc;			/* Current packet command */
-	unsigned long flags;			/* Status/Action flags */
-	unsigned long transform;		/* SCSI cmd translation layer */
-	unsigned long log;			/* log flags */
+	idescsi_pc_t *pc;		/* Current packet command */
+	unsigned long flags;		/* Status/Action flags */
+	unsigned long transform;	/* SCSI cmd translation layer */
+	unsigned long log;		/* log flags */
+	int id;				/* id */
+#ifdef IDESCSI_DEVFS
+	devfs_handle_t de;		/* pointer to IDE device */
+#endif /* IDESCSI_DEVFS */
 } idescsi_scsi_t;
 
 /*
  *	Per ATAPI device status bits.
  */
-#define IDESCSI_DRQ_INTERRUPT		0	/* DRQ interrupt device */
+#define IDESCSI_DRQ_INTERRUPT	0	/* DRQ interrupt device */
 
 /*
  *	ide-scsi requests.
  */
-#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 */
+#define IDESCSI_PC_RQ		90
 
 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);
 }
 
 /*
@@ -134,13 +143,15 @@
 
 	while (bcount) {
 		if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
-			printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n");
-			idescsi_discard_data (drive, bcount);
+			printk(KERN_ERR "ide-scsi: scatter gather "
+				"table too small, discarding data\n");
+			idescsi_discard_data(drive, bcount);
 			return;
 		}
-		count = IDE_MIN (pc->sg->length - pc->b_count, bcount);
-		atapi_input_bytes (drive, pc->sg->address + pc->b_count, count);
-		bcount -= count; pc->b_count += count;
+		count = IDE_MIN(pc->sg->length - pc->b_count, bcount);
+		HWIF(drive)->atapi_input_bytes(drive, pc->sg->address + pc->b_count, count);
+		bcount -= count;
+		pc->b_count += count;
 		if (pc->b_count == pc->sg->length) {
 			pc->sg++;
 			pc->b_count = 0;
@@ -154,13 +165,15 @@
 
 	while (bcount) {
 		if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
-			printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n");
-			idescsi_output_zeros (drive, bcount);
+			printk(KERN_ERR "ide-scsi: scatter gather table "
+				"too small, padding with zeros\n");
+			idescsi_output_zeros(drive, bcount);
 			return;
 		}
-		count = IDE_MIN (pc->sg->length - pc->b_count, bcount);
-		atapi_output_bytes (drive, pc->sg->address + pc->b_count, count);
-		bcount -= count; pc->b_count += count;
+		count = IDE_MIN(pc->sg->length - pc->b_count, bcount);
+		HWIF(drive)->atapi_output_bytes(drive, pc->sg->address + pc->b_count, count);
+		bcount -= count;
+		pc->b_count += count;
 		if (pc->b_count == pc->sg->length) {
 			pc->sg++;
 			pc->b_count = 0;
@@ -181,26 +194,38 @@
 		return;
 	if (drive->media == ide_cdrom || drive->media == ide_optical) {
 		if (c[0] == READ_6 || c[0] == WRITE_6) {
-			c[8] = c[4];		c[5] = c[3];		c[4] = c[2];
-			c[3] = c[1] & 0x1f;	c[2] = 0;		c[1] &= 0xe0;
+			c[8] = c[4];
+			c[5] = c[3];
+			c[4] = c[2];
+			c[3] = c[1] & 0x1f;
+			c[2] = 0;
+			c[1] &= 0xe0;
 			c[0] += (READ_10 - READ_6);
 		}
 		if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) {
+			unsigned short new_len;
 			if (!scsi_buf)
 				return;
 			if ((atapi_buf = kmalloc(pc->buffer_size + 4, GFP_ATOMIC)) == NULL)
 				return;
 			memset(atapi_buf, 0, pc->buffer_size + 4);
 			memset (c, 0, 12);
-			c[0] = sc[0] | 0x40;	c[1] = sc[1];		c[2] = sc[2];
-			c[8] = sc[4] + 4;	c[9] = sc[5];
-			if (sc[4] + 4 > 255)
-				c[7] = sc[4] + 4 - 255;
+			c[0] = sc[0] | 0x40;
+			c[1] = sc[1];
+			c[2] = sc[2];
+ 			new_len = sc[4] + 4;
+			c[8] = new_len;
+			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 */
-				atapi_buf[3] = scsi_buf[2];	/* Device specific parameter */
-				atapi_buf[7] = scsi_buf[3];	/* Block descriptor length */
+				/* Mode data length */
+				atapi_buf[1] = scsi_buf[0];
+				/* Medium type */
+				atapi_buf[2] = scsi_buf[1];
+				/* Device specific parameter */
+				atapi_buf[3] = scsi_buf[2];
+				/* Block descriptor length */
+				atapi_buf[7] = scsi_buf[3];
 				memcpy(atapi_buf + 8, scsi_buf + 4, pc->buffer_size - 4);
 			}
 			pc->buffer = atapi_buf;
@@ -220,15 +245,21 @@
 		return;
 	if (drive->media == ide_cdrom || drive->media == ide_optical) {
 		if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) {
-			scsi_buf[0] = atapi_buf[1];		/* Mode data length */
-			scsi_buf[1] = atapi_buf[2];		/* Medium type */
-			scsi_buf[2] = atapi_buf[3];		/* Device specific parameter */
-			scsi_buf[3] = atapi_buf[7];		/* Block descriptor length */
+			/* Mode data length */
+			scsi_buf[0] = atapi_buf[1];
+			/* Medium type */
+			scsi_buf[1] = atapi_buf[2];
+			/* Device specific parameter */
+			scsi_buf[2] = atapi_buf[3];
+			/* Block descriptor length */
+			scsi_buf[3] = atapi_buf[7];
 			memcpy(scsi_buf + 4, atapi_buf + 8, pc->request_transfer - 8);
 		}
 		if (pc->c[0] == INQUIRY) {
-			scsi_buf[2] |= 2;			/* ansi_revision */
-			scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2;	/* response data format */
+			/* ansi_revision */
+			scsi_buf[2] |= 2;
+			/* response data format */
+			scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2;
 		}
 	}
 	if (atapi_buf && atapi_buf != scsi_buf)
@@ -256,47 +287,83 @@
 	printk("]\n");
 }
 
-static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup)
+static int idescsi_do_end_request (ide_drive_t *drive, int uptodate)
+{
+	struct request *rq;
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&io_request_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->ide_dma_on(drive);
+	}
+
+	if (!end_that_request_first(rq, uptodate, drive->name)) {
+		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(&io_request_lock, flags);
+	return ret;
+}
+
+static int idescsi_end_request (ide_drive_t *drive, int uptodate)
 {
-	ide_drive_t *drive = hwgroup->drive;
 	idescsi_scsi_t *scsi = drive->driver_data;
-	struct request *rq = hwgroup->rq;
+	struct request *rq = HWGROUP(drive)->rq;
 	idescsi_pc_t *pc = (idescsi_pc_t *) rq->buffer;
 	int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
 	u8 *scsi_buf;
 	unsigned long flags;
 
 	if (rq->cmd != IDESCSI_PC_RQ) {
-		ide_end_request (uptodate, hwgroup);
-		return;
+		idescsi_do_end_request(drive, uptodate);
+		return 0;
 	}
-	ide_end_drive_cmd (drive, 0, 0);
+	ide_end_drive_cmd(drive, 0, 0);
 	if (rq->errors >= ERROR_MAX) {
 		pc->scsi_cmd->result = DID_ERROR << 16;
 		if (log)
-			printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number);
+			printk("ide-scsi: %s: I/O error for %lu\n",
+				drive->name, pc->scsi_cmd->serial_number);
 	} else if (rq->errors) {
 		pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);
 		if (log)
-			printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number);
+			printk("ide-scsi: %s: check condition for %lu\n",
+				drive->name, pc->scsi_cmd->serial_number);
 	} else {
 		pc->scsi_cmd->result = DID_OK << 16;
-		idescsi_transform_pc2 (drive, pc);
+		idescsi_transform_pc2(drive, pc);
 		if (log) {
-			printk ("ide-scsi: %s: suc %lu", drive->name, pc->scsi_cmd->serial_number);
-			if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) {
+			printk("ide-scsi: %s: suc %lu", drive->name,
+				pc->scsi_cmd->serial_number);
+			if (!test_bit(PC_WRITING, &pc->flags) &&
+			    pc->actually_transferred &&
+			    pc->actually_transferred <= 1024 &&
+			    pc->buffer) {
 				printk(", rst = ");
 				scsi_buf = pc->scsi_cmd->request_buffer;
 				hexdump(scsi_buf, IDE_MIN(16, pc->scsi_cmd->request_bufflen));
 			} else printk("\n");
 		}
 	}
-	spin_lock_irqsave(&io_request_lock,flags);	
+	spin_lock_irqsave(&io_request_lock, flags);	
 	pc->done(pc->scsi_cmd);
-	spin_unlock_irqrestore(&io_request_lock,flags);
-	idescsi_free_bh (rq->bh);
-	kfree(pc); kfree(rq);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	idescsi_free_bh(rq->bh);
+	kfree(pc);
+	kfree(rq);
 	scsi->pc = NULL;
+	return 0;
 }
 
 static inline unsigned long get_timeout(idescsi_pc_t *pc)
@@ -310,84 +377,107 @@
 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;
+	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
-	printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n");
+	printk(KERN_INFO "ide-scsi: Reached idescsi_pc_intr "
+		"interrupt handler\n");
 #endif /* IDESCSI_DEBUG_LOG */
 
-	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+	if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) {
 #if IDESCSI_DEBUG_LOG
-		printk ("ide-scsi: %s: DMA complete\n", drive->name);
+		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));
+		pc->actually_transferred = pc->request_transfer;
+		(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);
-		ide__sti();
-		if (status & ERR_STAT)
+			printk(KERN_INFO "Packet command completed, %d "
+				"bytes transferred\n",
+				pc->actually_transferred);
+		local_irq_enable();
+		if (status.b.check)
 			rq->errors++;
-		idescsi_end_request (1, HWGROUP(drive));
+		idescsi_end_request(drive, 1);
 		return ide_stopped;
 	}
-	bcount = IN_BYTE (IDE_BCOUNTH_REG) << 8 | IN_BYTE (IDE_BCOUNTL_REG);
-	ireason = IN_BYTE (IDE_IREASON_REG);
 
-	if (ireason & IDESCSI_IREASON_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) {
+	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.b.cod) {
+		printk(KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");
+		return ide_do_reset(drive);
+	}
+	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);
 					if (pc->sg)
 						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);
+						HWIF(drive)->atapi_input_bytes(drive, pc->current_position, temp);
+					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);
-				ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);
+				idescsi_discard_data(drive, bcount.all - temp);
+				if (HWGROUP(drive)->handler != NULL)
+					BUG();
+				ide_set_handler(drive,
+						&idescsi_pc_intr,
+						get_timeout(pc),
+						NULL);
 				return ide_started;
 			}
 #if IDESCSI_DEBUG_LOG
-			printk (KERN_NOTICE "ide-scsi: The scsi wants to send us more data than expected - allowing transfer\n");
+			printk(KERN_NOTICE "ide-scsi: The scsi wants to send "
+				"us more data than expected - "
+				"allowing transfer\n");
 #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;
-
-	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);	/* And set the interrupt handler again */
+	/* Update the current position */
+	pc->actually_transferred += bcount.all;
+	pc->current_position += bcount.all;
+
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	/* And set the interrupt handler again */
+	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);
 	return ide_started;
 }
 
@@ -395,20 +485,29 @@
 {
 	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");
-		return ide_do_reset (drive);
+
+	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 */
+	HWIF(drive)->atapi_output_bytes(drive, scsi->pc->c, 12);
 	return ide_started;
 }
 
@@ -418,36 +517,50 @@
 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 */
 
-	if (drive->using_dma && rq->bh)
-		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);
+	/* Set the current packet command */
+	scsi->pc = pc;
+	/* We haven't transferred any data yet */
+	pc->actually_transferred = 0;
+	pc->current_position = pc->buffer;
+	/* Request to transfer the entire buffer at once */
+	bcount.all = IDE_MIN(pc->request_transfer, 63 * 1024);
+
+	if (drive->using_dma && rq->bh) {
+		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);
 	}
 }
 
@@ -457,19 +570,30 @@
 static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
 #if IDESCSI_DEBUG_LOG
-	printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
-	printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+	printk(KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",
+		rq->rq_status, (unsigned int) rq->rq_dev, rq->cmd, rq->errors);
+	printk(KERN_INFO "sector: %ld, nr_sectors: %ld, "
+		"current_nr_sectors: %ld\n", rq->sector,
+		rq->nr_sectors, rq->current_nr_sectors);
 #endif /* IDESCSI_DEBUG_LOG */
 
 	if (rq->cmd == IDESCSI_PC_RQ) {
-		return idescsi_issue_pc (drive, (idescsi_pc_t *) rq->buffer);
+		return idescsi_issue_pc(drive, (idescsi_pc_t *) rq->buffer);
 	}
-	printk (KERN_ERR "ide-scsi: %s: unsupported command in request queue (%x)\n", drive->name, rq->cmd);
-	idescsi_end_request (0,HWGROUP (drive));
+	printk(KERN_ERR "ide-scsi: %s: unsupported command in request "
+		"queue (%x)\n", drive->name, rq->cmd);
+	idescsi_end_request(drive, 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 -EINVAL;
+}
+
+static int idescsi_ide_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
 {
 	MOD_INC_USE_COUNT;
 	return 0;
@@ -482,6 +606,7 @@
 
 static ide_drive_t *idescsi_drives[MAX_HWIFS * MAX_DRIVES];
 static int idescsi_initialized = 0;
+static int drive_count = 0;
 
 static void idescsi_add_settings(ide_drive_t *drive)
 {
@@ -502,34 +627,58 @@
  */
 static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi, int id)
 {
+	int minor = (drive->select.b.unit) << PARTN_BITS;
+
 	DRIVER(drive)->busy++;
 	idescsi_drives[id] = drive;
 	drive->driver_data = scsi;
 	drive->ready_stat = 0;
-	memset (scsi, 0, sizeof (idescsi_scsi_t));
+	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_DRQ_INTERRUPT, &scsi->flags);
 	set_bit(IDESCSI_TRANSFORM, &scsi->transform);
 	clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
 #if IDESCSI_DEBUG_LOG
 	set_bit(IDESCSI_LOG_CMD, &scsi->log);
 #endif /* IDESCSI_DEBUG_LOG */
 	idescsi_add_settings(drive);
+#ifdef IDESCSI_DEVFS
+	scsi->de = devfs_register(drive->de, "generic", DEVFS_FL_DEFAULT,
+					HWIF(drive)->major, minor,
+					S_IFBLK | S_IRUSR | S_IWUSR,
+					ide_fops, NULL);
+#endif /* IDESCSI_DEVFS */
+	drive_count++;
+	DRIVER(drive)->busy--;
 }
 
 static int idescsi_cleanup (ide_drive_t *drive)
 {
 	idescsi_scsi_t *scsi = drive->driver_data;
 
-	if (ide_unregister_subdriver (drive))
+	if (ide_unregister_subdriver(drive)) {
+		printk("%s: %s: failed to unregister! \n",
+			__FUNCTION__, drive->name);
+		printk("%s: usage %d, busy %d, driver %p, Dbusy %d\n",
+			drive->name, drive->usage, drive->busy,
+			drive->driver, DRIVER(drive)->busy);
 		return 1;
+	}
+	idescsi_drives[scsi->id] = NULL;
+#ifdef IDESCSI_DEVFS
+	if (scsi->de)
+		devfs_unregister(scsi->de);
+#endif /* IDESCSI_DEVFS */
 	drive->driver_data = NULL;
-	kfree (scsi);
+	kfree(scsi);
+	drive_count--;
 	return 0;
 }
 
-int idescsi_reinit(ide_drive_t *drive);
+int idescsi_init(void);
+int idescsi_attach(ide_drive_t *drive);
 
 /*
  *	IDE subdriver functions, registered with ide.c
@@ -539,15 +688,23 @@
 	version:		IDESCSI_VERSION,
 	media:			ide_scsi,
 	busy:			0,
+#ifdef CONFIG_IDEDMA_ONLYDISK
+	supports_dma:		0,
+#else
 	supports_dma:		1,
+#endif
 	supports_dsc_overlap:	0,
 	cleanup:		idescsi_cleanup,
 	standby:		NULL,
+	suspend:		NULL,
+	resume:			NULL,
 	flushcache:		NULL,
 	do_request:		idescsi_do_request,
 	end_request:		idescsi_end_request,
-	ioctl:			NULL,
-	open:			idescsi_open,
+	sense:			NULL,
+	error:			NULL,
+	ioctl:			idescsi_do_ioctl,
+	open:			idescsi_ide_open,
 	release:		idescsi_ide_release,
 	media_change:		NULL,
 	revalidate:		NULL,
@@ -555,12 +712,12 @@
 	capacity:		NULL,
 	special:		NULL,
 	proc:			NULL,
-	reinit:			idescsi_reinit,
+	init:			idescsi_init,
+	attach:			idescsi_attach,
 	ata_prebuilder:		NULL,
 	atapi_prebuilder:	NULL,
 };
 
-int idescsi_init (void);
 static ide_module_t idescsi_module = {
 	IDE_DRIVER_MODULE,
 	idescsi_init,
@@ -568,51 +725,91 @@
 	NULL
 };
 
-int idescsi_reinit (ide_drive_t *drive)
+int idescsi_attach (ide_drive_t *drive)
 {
-#if 0
 	idescsi_scsi_t *scsi;
-	byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
-	int i, failed, id;
-
-	if (!idescsi_initialized)
-		return 0;
-	for (i = 0; i < MAX_HWIFS * MAX_DRIVES; i++)
-		idescsi_drives[i] = NULL;
+	u8 media[] = {	TYPE_DISK,		/* 0x00 */
+			TYPE_TAPE,		/* 0x01 */
+			TYPE_PRINTER,		/* 0x02 */
+			TYPE_PROCESSOR,		/* 0x03 */
+			TYPE_WORM,		/* 0x04 */
+			TYPE_ROM,		/* 0x05 */
+			TYPE_SCANNER,		/* 0x06 */
+			TYPE_MOD,		/* 0x07 */
+			255};
+	int i = 0, ret = 0, id = 0;
+//	int id = 2 * HWIF(drive)->index + drive->select.b.unit;
+//	int id = drive_count + 1;
+
+	for (id = 0; id < MAX_HWIFS*MAX_DRIVES; id++)
+		if (idescsi_drives[id] == NULL)
+			break;
+
+	printk("%s: id = %d\n", drive->name, id);
+
+	if ((!idescsi_initialized) || (drive->media == ide_disk)) {
+		printk(KERN_ERR "ide-scsi: (%sinitialized) %s: "
+				"media-type (%ssupported)\n",
+			(idescsi_initialized) ? "" : "! ",
+			drive->name,
+			(drive->media == ide_disk) ? "! " : "");
+		return (drive->media == ide_disk) ? 2 : 0;
+	}
 
 	MOD_INC_USE_COUNT;
+
 	for (i = 0; media[i] != 255; i++) {
-		failed = 0;
-		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) {
+		if (drive->media != media[i])
+			continue;
+		else
+			break;
+	}
 
-			if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) {
-				printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name);
-				continue;
-			}
-			if (ide_register_subdriver (drive, &idescsi_driver, IDE_SUBDRIVER_VERSION)) {
-				printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name);
-				kfree (scsi);
-				continue;
-			}
-			for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++);
-				idescsi_setup (drive, scsi, id);
-			failed--;
-		}
+	if ((scsi = (idescsi_scsi_t *) kmalloc(sizeof(idescsi_scsi_t), GFP_KERNEL)) == NULL) {
+		printk(KERN_ERR "ide-scsi: %s: Can't allocate a scsi "
+			"structure\n", drive->name);
+		ret = 1;
+		goto bye_game_over;
 	}
-	ide_register_module(&idescsi_module);
+	if (ide_register_subdriver(drive, &idescsi_driver,
+			IDE_SUBDRIVER_VERSION)) {
+		printk(KERN_ERR "ide-scsi: %s: Failed to register the "
+			"driver with ide.c\n", drive->name);
+		kfree(scsi);
+		ret = 1;
+		goto bye_game_over;
+	}
+
+	idescsi_setup(drive, scsi, id);
+
+//	scan_scsis(HBA, 1, channel, id, lun);
+bye_game_over:
 	MOD_DEC_USE_COUNT;
-#endif
-	return 0;
+	return ret;
 }
 
-/*
- *	idescsi_init will register the driver for each scsi.
- */
+#ifdef MODULE
+/* options */
+char *ignore = NULL;
+
+MODULE_PARM(ignore, "s");
+#endif
+
 int idescsi_init (void)
 {
+#ifdef CLASSIC_BUILTINS_METHOD
 	ide_drive_t *drive;
 	idescsi_scsi_t *scsi;
-	byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
+	u8 media[] = {  TYPE_DISK,		/* 0x00 */
+			TYPE_TAPE,		/* 0x01 */
+			TYPE_PRINTER,		/* 0x02 */
+			TYPE_PROCESSOR,		/* 0x03 */
+			TYPE_WORM,		/* 0x04 */
+			TYPE_ROM,		/* 0x05 */
+			TYPE_SCANNER,		/* 0x06 */
+			TYPE_MOD,		/* 0x07 */
+			255};
+
 	int i, failed, id;
 
 	if (idescsi_initialized)
@@ -623,22 +820,47 @@
 	MOD_INC_USE_COUNT;
 	for (i = 0; media[i] != 255; i++) {
 		failed = 0;
-		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) {
+		while ((drive = ide_scan_devices(media[i],
+				idescsi_driver.name, NULL, failed++)) != NULL) {
+#ifdef MODULE
+			/* skip drives we were told to ignore */
+			if (ignore != NULL && strstr(ignore, drive->name)) {
+				printk("ide-scsi: ignoring drive %s\n",
+					drive->name);
+				continue;
+			}
+#endif
 
-			if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) {
-				printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name);
+		if ((scsi = (idescsi_scsi_t *) kmalloc(sizeof(idescsi_scsi_t), GFP_KERNEL)) == NULL) {
+				printk(KERN_ERR "ide-scsi: %s: Can't allocate "
+					"a scsi structure\n", drive->name);
 				continue;
 			}
-			if (ide_register_subdriver (drive, &idescsi_driver, IDE_SUBDRIVER_VERSION)) {
-				printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name);
-				kfree (scsi);
+			if (ide_register_subdriver(drive, &idescsi_driver,
+					IDE_SUBDRIVER_VERSION)) {
+				printk(KERN_ERR "ide-scsi: %s: Failed to "
+					"register the driver with ide.c\n",
+					drive->name);
+				kfree(scsi);
 				continue;
 			}
-			for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++);
-				idescsi_setup (drive, scsi, id);
+			for (id = 0;
+				id < MAX_HWIFS*MAX_DRIVES && idescsi_drives[id];
+					id++);
+				idescsi_setup(drive, scsi, id);
 			failed--;
 		}
 	}
+#else /* ! CLASSIC_BUILTINS_METHOD */
+	int i;
+
+	if (idescsi_initialized)
+		return 0;
+	idescsi_initialized = 1;
+	for (i = 0; i < MAX_HWIFS * MAX_DRIVES; i++)
+		idescsi_drives[i] = NULL;
+	MOD_INC_USE_COUNT;
+#endif /* CLASSIC_BUILTINS_METHOD */
 	ide_register_module(&idescsi_module);
 	MOD_DEC_USE_COUNT;
 	return 0;
@@ -652,9 +874,11 @@
 
 	host_template->proc_name = "ide-scsi";
 	host = scsi_register(host_template, 0);
-	if(host == NULL)
+	if (host == NULL) {
+		printk(KERN_WARNING "%s: host failure!\n", __FUNCTION__);
 		return 0;
-		
+	}
+
 	for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++)
 		last_lun = IDE_MAX(last_lun, idescsi_drives[id]->last_lun);
 	host->max_id = id;
@@ -701,32 +925,36 @@
 {
 	struct buffer_head *bh, *bhp, *first_bh;
 
-	if ((first_bh = bhp = bh = kmalloc (sizeof(struct buffer_head), GFP_ATOMIC)) == NULL)
+	if ((first_bh = bhp = bh = kmalloc(sizeof(struct buffer_head), GFP_ATOMIC)) == NULL)
 		goto abort;
-	memset (bh, 0, sizeof (struct buffer_head));
+	memset(bh, 0, sizeof(struct buffer_head));
 	bh->b_reqnext = NULL;
 	while (--count) {
-		if ((bh = kmalloc (sizeof(struct buffer_head), GFP_ATOMIC)) == NULL)
+		if ((bh = kmalloc(sizeof(struct buffer_head), GFP_ATOMIC)) == NULL)
 			goto abort;
-		memset (bh, 0, sizeof (struct buffer_head));
+		memset(bh, 0, sizeof(struct buffer_head));
 		bhp->b_reqnext = bh;
 		bhp = bh;
 		bh->b_reqnext = NULL;
 	}
 	return first_bh;
 abort:
-	idescsi_free_bh (first_bh);
+	idescsi_free_bh(first_bh);
 	return NULL;
 }
 
 static inline int idescsi_set_direction (idescsi_pc_t *pc)
 {
 	switch (pc->c[0]) {
-		case READ_6: case READ_10: case READ_12:
-			clear_bit (PC_WRITING, &pc->flags);
+		case READ_6:
+		case READ_10:
+		case READ_12:
+			clear_bit(PC_WRITING, &pc->flags);
 			return 0;
-		case WRITE_6: case WRITE_10: case WRITE_12:
-			set_bit (PC_WRITING, &pc->flags);
+		case WRITE_6:
+		case WRITE_10:
+		case WRITE_12:
+			set_bit(PC_WRITING, &pc->flags);
 			return 0;
 		default:
 			return 1;
@@ -744,12 +972,17 @@
 	if (idescsi_set_direction(pc))
 		return NULL;
 	if (segments) {
-		if ((first_bh = bh = idescsi_kmalloc_bh (segments)) == NULL)
+		if ((first_bh = bh = idescsi_kmalloc_bh(segments)) == NULL)
 			return NULL;
 #if IDESCSI_DEBUG_LOG
-		printk ("ide-scsi: %s: building DMA table, %d segments, %dkB total\n", drive->name, segments, pc->request_transfer >> 10);
+		printk("ide-scsi: %s: building DMA table, %d segments, "
+			"%dkB total\n", drive->name, segments,
+			pc->request_transfer >> 10);
 #endif /* IDESCSI_DEBUG_LOG */
 		while (segments--) {
+#if 1
+			bh->b_data = sg->address;
+#else
 			if (sg->address) {
 				bh->b_page = virt_to_page(sg->address);
 				bh->b_data = (char *) ((unsigned long) sg->address & ~PAGE_MASK);
@@ -757,7 +990,7 @@
 				bh->b_page = sg->page;
 				bh->b_data = (char *) sg->offset;
 			}
-
+#endif
 			bh->b_size = sg->length;
 			bh = bh->b_reqnext;
 			sg++;
@@ -766,10 +999,12 @@
 		/*
 		 * non-sg requests are guarenteed not to reside in highmem /jens
 		 */
-		if ((first_bh = bh = idescsi_kmalloc_bh (1)) == NULL)
+		if ((first_bh = bh = idescsi_kmalloc_bh(1)) == NULL)
 			return NULL;
 #if IDESCSI_DEBUG_LOG
-		printk ("ide-scsi: %s: building DMA table for a single buffer (%dkB)\n", drive->name, pc->request_transfer >> 10);
+		printk("ide-scsi: %s: building DMA table for a single "
+			"buffer (%dkB)\n", drive->name,
+			pc->request_transfer >> 10);
 #endif /* IDESCSI_DEBUG_LOG */
 		bh->b_data = pc->scsi_cmd->request_buffer;
 		bh->b_size = pc->request_transfer;
@@ -794,21 +1029,22 @@
 	idescsi_pc_t *pc = NULL;
 
 	if (!drive) {
-		printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->target);
+		printk(KERN_ERR "ide-scsi: drive id %d not present\n",
+			cmd->target);
 		goto abort;
 	}
 	scsi = drive->driver_data;
-	pc = kmalloc (sizeof (idescsi_pc_t), GFP_ATOMIC);
-	rq = kmalloc (sizeof (struct request), GFP_ATOMIC);
+	pc = kmalloc(sizeof(idescsi_pc_t), GFP_ATOMIC);
+	rq = kmalloc(sizeof(struct request), GFP_ATOMIC);
 	if (rq == NULL || pc == NULL) {
-		printk (KERN_ERR "ide-scsi: %s: out of memory\n", drive->name);
+		printk(KERN_ERR "ide-scsi: %s: out of memory\n", drive->name);
 		goto abort;
 	}
 
-	memset (pc->c, 0, 12);
+	memset(pc->c, 0, 12);
 	pc->flags = 0;
 	pc->rq = rq;
-	memcpy (pc->c, cmd->cmnd, cmd->cmd_len);
+	memcpy(pc->c, cmd->cmnd, cmd->cmd_len);
 	if (cmd->use_sg) {
 		pc->buffer = NULL;
 		pc->sg = cmd->request_buffer;
@@ -824,28 +1060,30 @@
 
 	if (should_transform(drive, cmd))
 		set_bit(PC_TRANSFORM, &pc->flags);
-	idescsi_transform_pc1 (drive, pc);
+	idescsi_transform_pc1(drive, pc);
 
 	if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {
-		printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number);
+		printk("ide-scsi: %s: que %lu, cmd = ",
+			drive->name, cmd->serial_number);
 		hexdump(cmd->cmnd, cmd->cmd_len);
 		if (memcmp(pc->c, cmd->cmnd, cmd->cmd_len)) {
-			printk ("ide-scsi: %s: que %lu, tsl = ", drive->name, cmd->serial_number);
+			printk("ide-scsi: %s: que %lu, tsl = ",
+				drive->name, cmd->serial_number);
 			hexdump(pc->c, 12);
 		}
 	}
 
-	ide_init_drive_cmd (rq);
+	ide_init_drive_cmd(rq);
 	rq->buffer = (char *) pc;
-	rq->bh = idescsi_dma_bh (drive, pc);
+	rq->bh = idescsi_dma_bh(drive, pc);
 	rq->cmd = IDESCSI_PC_RQ;
 	spin_unlock_irq(&io_request_lock);
-	(void) ide_do_drive_cmd (drive, rq, ide_end);
+	(void) ide_do_drive_cmd(drive, rq, ide_end);
 	spin_lock_irq(&io_request_lock);
 	return 0;
 abort:
-	if (pc) kfree (pc);
-	if (rq) kfree (rq);
+	if (pc) kfree(pc);
+	if (rq) kfree(rq);
 	cmd->result = DID_ERROR << 16;
 	done(cmd);
 	return 0;
@@ -858,6 +1096,9 @@
 
 int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags)
 {
+	ide_drive_t *drive	= idescsi_drives[cmd->target];
+
+	(void) ide_do_reset(drive);
 	return SCSI_RESET_SUCCESS;
 }
 
@@ -877,24 +1118,25 @@
 
 static int __init init_idescsi_module(void)
 {
+	drive_count = 0;
 	idescsi_init();
 	idescsi_template.module = THIS_MODULE;
-	scsi_register_module (MODULE_SCSI_HA, &idescsi_template);
+	scsi_register_module(MODULE_SCSI_HA, &idescsi_template);
 	return 0;
 }
 
 static void __exit exit_idescsi_module(void)
 {
 	ide_drive_t *drive;
-	byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
+	u8 media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};
 	int i, failed;
 
-	scsi_unregister_module (MODULE_SCSI_HA, &idescsi_template);
+	scsi_unregister_module(MODULE_SCSI_HA, &idescsi_template);
 	for (i = 0; media[i] != 255; i++) {
 		failed = 0;
-		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, &idescsi_driver, failed)) != NULL)
-			if (idescsi_cleanup (drive)) {
-				printk ("%s: exit_idescsi_module() called while still busy\n", drive->name);
+		while ((drive = ide_scan_devices(media[i], idescsi_driver.name, &idescsi_driver, failed)) != NULL)
+			if (idescsi_cleanup(drive)) {
+				printk("%s: exit_idescsi_module() called while still busy\n", drive->name);
 				failed++;
 			}
 	}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/ide-scsi.h linux.20pre10-ac2/drivers/scsi/ide-scsi.h
--- linux.20pre10/drivers/scsi/ide-scsi.h	2002-10-09 21:36:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/ide-scsi.h	2002-09-06 00:53:46.000000000 +0100
@@ -16,22 +16,22 @@
 extern int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags);
 extern int idescsi_bios (Disk *disk, kdev_t dev, int *parm);
 
-#define IDESCSI  {								\
-	name:            "idescsi",		/* name		*/		\
-	detect:          idescsi_detect,	/* detect	*/		\
-	release:         idescsi_release,	/* release	*/		\
-	info:            idescsi_info,		/* info		*/		\
-	ioctl:           idescsi_ioctl,		/* ioctl        */		\
-	queuecommand:    idescsi_queue,		/* queuecommand */		\
-	abort:           idescsi_abort,		/* abort	*/		\
-	reset:           idescsi_reset,		/* reset	*/		\
-	bios_param:      idescsi_bios,		/* bios_param	*/		\
-	can_queue:       10,			/* can_queue	*/		\
-	this_id:         -1,			/* this_id	*/		\
-	sg_tablesize:    256,			/* sg_tablesize	*/		\
-	cmd_per_lun:     5,			/* cmd_per_lun	*/		\
-	use_clustering:  DISABLE_CLUSTERING,	/* clustering	*/		\
-	emulated:        1			/* emulated     */		\
+#define IDESCSI  {							\
+	name:            "idescsi",		/* name		*/	\
+	detect:          idescsi_detect,	/* detect	*/	\
+	release:         idescsi_release,	/* release	*/	\
+	info:            idescsi_info,		/* info		*/	\
+	ioctl:           idescsi_ioctl,		/* ioctl        */	\
+	queuecommand:    idescsi_queue,		/* queuecommand */	\
+	abort:           idescsi_abort,		/* abort	*/	\
+	reset:           idescsi_reset,		/* reset	*/	\
+	bios_param:      idescsi_bios,		/* bios_param	*/	\
+	can_queue:       10,			/* can_queue	*/	\
+	this_id:         -1,			/* this_id	*/	\
+	sg_tablesize:    256,			/* sg_tablesize	*/	\
+	cmd_per_lun:     5,			/* cmd_per_lun	*/	\
+	use_clustering:  DISABLE_CLUSTERING,	/* clustering	*/	\
+	emulated:        1			/* emulated     */	\
 }
 
 #endif /* IDESCSI_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/Makefile linux.20pre10-ac2/drivers/scsi/Makefile
--- linux.20pre10/drivers/scsi/Makefile	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/Makefile	2002-10-10 23:53:35.000000000 +0100
@@ -127,6 +127,7 @@
 obj-$(CONFIG_SCSI_FCAL)		+= fcal.o
 obj-$(CONFIG_SCSI_CPQFCTS)	+= cpqfc.o
 obj-$(CONFIG_SCSI_LASI700)	+= lasi700.o 53c700.o
+obj-$(CONFIG_SCSI_NSP32)	+= nsp32.o
 
 subdir-$(CONFIG_ARCH_ACORN)	+= ../acorn/scsi
 obj-$(CONFIG_ARCH_ACORN)	+= ../acorn/scsi/acorn-scsi.o
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/nsp32.c linux.20pre10-ac2/drivers/scsi/nsp32.c
--- linux.20pre10/drivers/scsi/nsp32.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/nsp32.c	2002-10-10 23:53:14.000000000 +0100
@@ -0,0 +1,3526 @@
+/*
+ * NinjaSCSI-32Bi Cardbus, NinjaSCSI-32UDE PCI/CardBus SCSI driver
+ * Copyright (C) 2001, 2002
+ *      YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
+ *      GOTO Masanori <gotom@debian.or.jp>
+ *
+ * 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, 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.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include <scsi/scsi_ioctl.h>
+#include <scsi/scsi.h>
+
+#include "nsp32.h"
+
+
+static int trans_mode = 0;	/* default: BIOS */
+static int auto_param = 0;	/* default: ON */
+MODULE_PARM(trans_mode, "i");
+MODULE_PARM(auto_param, "i");
+MODULE_PARM_DESC(trans_mode, "transfer mode (0: BIOS 1: Async 2: Ultra20M");
+MODULE_PARM_DESC(auto_param, "AutoParameter mode (0: ON 1: OFF)");
+#define ASYNC_MODE    1
+#define ULTRA20M_MODE 2
+
+MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>, GOTO Masanori <gotom@debian.or.jp>");
+MODULE_DESCRIPTION("Workbit NinjaSCSI-32Bi/UDE PCI/CardBus SCSI host bus adapter module");
+MODULE_LICENSE("GPL");
+
+static const char *nsp32_release_version = "1.0";
+
+
+/*
+ * structure for DMA/Scatter Gather list
+ */
+#define AUTOPARAM_SIZE		(sizeof(int)*0x15)	/* 4x15H = 0x60 */
+#define NSP_SG_SIZE		SG_ALL
+#define NSP32_SG_END_SGT	0x80000000		/* Last SGT marker */
+#define NSP32_SG_CNT_MASK	0x1FFFF
+
+struct nsp32_sgtable {
+	unsigned long		addr;		/* transfer address */
+	unsigned long		len;		/* transfer length.
+						   Bit (24-32) is for SGT_END */
+};
+
+struct nsp32_sglun {
+	struct nsp32_sgtable sgt[NSP_SG_SIZE+1];	/* SG table */
+};
+
+
+/*
+ * host data structure
+ */
+/* message in/out buffer */
+#define MSGOUTBUF_MAX	13  /* 13 is ok ? */
+#define MSGINBUF_MAX	13
+
+/* flag for trans_method */
+#define NSP32_TRANSFER_BUSMASTER	BIT(0)
+#define NSP32_TRANSFER_MMIO		BIT(1)	/* Not supported yet */
+#define NSP32_TRANSFER_PIO		BIT(2)	/* Not supported yet */
+
+
+/*
+ * SCSI TARGET/LUN definition
+ */
+#define NSP32_HOST_SCSIID	7	/* SCSI initiator is everytime defined as 7 */
+#define MAX_TARGET		8
+#define MAX_LUN			8	/* XXX: In SPI3, max number of LUN is 64. */
+
+
+/*
+ * structure for synchronous transfer negotiation data
+ */
+#define SYNC_NOT_YET	0
+#define SYNC_OK		1
+#define SYNC_NG		2
+
+struct nsp32_sync_table {
+	unsigned char	period_num;	/* period number */
+	unsigned char	ackwidth;	/* ack width designated by period */
+	unsigned char	start_period;	/* search range - start period */
+	unsigned char	end_period;	/* search range - end period */
+};
+
+
+/*
+ * structure for target device static data
+ */
+/* flag for nsp32_target.sync_flag */
+#define SDTR_INITIATOR		BIT(0)	/* sending SDTR from initiator */
+#define SDTR_TARGET		BIT(1)	/* sending SDTR from target */
+#define SDTR_DONE		BIT(2)	/* exchanging SDTR has been processed */
+
+/* syncronous period value for nsp32_target.config_max */
+#define FAST5M			0x32
+#define FAST10M			0x19
+#define ULTRA20M		0x0c
+
+/* flag for nsp32_target.{sync_offset}, period */
+#define ASYNC_OFFSET		0	/* asynchronous transfer */
+#define SYNC_OFFSET		0xf	/* synchronous transfer max offset */
+
+/* syncreg:
+      07 06 05 04 03 02 01 00
+      ---PERIOD-- ---OFFSET--   */
+#define TO_SYNCREG(period, offset)	(period << 4 | offset)
+
+struct nsp32_target {
+	unsigned char	syncreg;	/* value for SYNCREG  */
+	unsigned char	ackwidth;	/* value for ACKWIDTH */
+	unsigned char	offset;		/* sync offset (0-15) */
+	int		sync_flag;	/* SDTR_*, 0 */
+	int		limit_entry;	/* max speed limit entry designated
+					   by EEPROM configuration */
+};
+
+typedef struct _nsp32_hw_data {
+	int IrqNumber;
+	int BaseAddress;
+	int NumAddress;
+#define NSP32_MMIO_OFFSET 0x0800
+	unsigned long MmioAddress;
+	unsigned long length;
+
+	Scsi_Cmnd *CurrentSC;
+
+	struct pci_dev *Pci;
+	const struct pci_device_id *pci_devid;
+	struct Scsi_Host *Host;
+	spinlock_t Lock;
+
+	char info_str[100];
+
+	/* allocated memory region */
+	struct nsp32_lunt	*lunt_list;	/* kmalloc region for lunt */
+	struct nsp32_sglun	*sg_list;	/* sglist virtual address */
+	dma_addr_t		sgaddr;		/* physical address of hw_sg_table */
+	unsigned char		*autoparam;	/* auto parameter transfer region */
+	dma_addr_t		apaddr;		/* physical address of autoparam */
+	int 			cur_entry;	/* current sgt entry */
+
+	/* target/LUN */
+	struct nsp32_lunt	*curlunt;	/* Current connected LUN table */
+	struct nsp32_lunt	*lunt[MAX_TARGET][MAX_LUN];  /* All LUN table */
+	struct nsp32_target	*curtarget;	/* Current connected SCSI ID */
+	struct nsp32_target	target[MAX_TARGET];	     /* SCSI ID */
+	int			pid;		/* Current connected target ID */
+	int			plun;		/* Current connected target LUN */
+
+	/* behavior setting parameters */
+	int			trans_method;	/* transfer method flag */
+	int			resettime;	/* Reset time */
+	int 			clock;	       	/* clock dividing flag */
+	struct nsp32_sync_table	*synct;		/* sync_table determined by clock */
+	int			syncnum;	/* the max number of synct element */
+
+	/* message buffer */
+        unsigned char	msgoutbuf[MSGOUTBUF_MAX]; /* msgout buffer */
+	char		msgoutlen;		  /* msgoutbuf length */
+	unsigned char	msginbuf[MSGINBUF_MAX];	  /* megin buffer */
+	char		msginlen;		  /* msginbuf length */
+
+
+} nsp32_hw_data;
+static nsp32_hw_data nsp32_data_base;  /* probe <-> detect glue */
+
+
+/*
+ * TIME definition
+ */
+#define RESET_HOLD_TIME		10000	/* reset time in us (SCSI-2 says the
+					   minimum is 25us) */
+#define SEL_TIMEOUT_TIME	10000	/* 250ms defined in SCSI specification
+					   (25.6us/1unit) */
+#define ARBIT_TIMEOUT_TIME	100	/* 100us */
+#define REQSACK_TIMEOUT_TIME	10000	/* max wait time for REQ/SACK assertion
+					   or negation, 10000us == 10ms */
+
+/*
+ * structure for connected LUN dynamic data
+ *
+ * Note: Currently tagged queuing is disabled, each nsp32_lunt holds
+ *       one SCSI command and one state.
+ */
+#define DISCPRIV_OK		BIT(0)		/* DISCPRIV Enable mode */
+#define MSGIN03			BIT(1)		/* Auto Msg In 03 Flag */
+
+struct nsp32_lunt {
+	Scsi_Cmnd		*SCpnt;		/* Current Handling Scsi_Cmnd */
+	unsigned long		save_datp;	/* Save Data Pointer - saved position from initial address */
+	int			msgin03;	/* auto msg in 03 flag */
+	unsigned int		sg_num;		/* Total number of SG entries */
+	int			cur_entry;	/* Current SG entry number */
+	struct nsp32_sglun	*sglun;		/* sg table per lun */
+	long			sglun_paddr;	/* sglun physical address */
+};
+
+
+/*
+ * Period/AckWidth speed conversion table
+ *
+ * Note: This period/ackwidth speed table must be in descending order.
+ */
+static struct nsp32_sync_table nsp32_sync_table_40M[] = {
+     /* {PNo, AW,  SP,   EP}  Speed(MB/s) Period AckWidth */
+	{0x1, 0, 0x0c, 0x0c},	/*  20.0 :  50ns,  25ns */
+	{0x2, 0, 0x0d, 0x18},	/*  13.3 :  75ns,  25ns */
+	{0x3, 1, 0x19, 0x19},	/*  10.0 : 100ns,  50ns */
+	{0x4, 1, 0x1a, 0x1f},	/*   8.0 : 125ns,  50ns */
+	{0x5, 2, 0x20, 0x25},	/*   6.7 : 150ns,  75ns */
+	{0x6, 2, 0x26, 0x31},	/*   5.7 : 175ns,  75ns */
+	{0x7, 3, 0x32, 0x32},	/*   5.0 : 200ns, 100ns */
+	{0x8, 3, 0x33, 0x38},	/*   4.4 : 225ns, 100ns */
+	{0x9, 3, 0x39, 0x3e},	/*   4.0 : 250ns, 100ns */
+};
+static const int nsp32_table_40M_num =
+		sizeof(nsp32_sync_table_40M)/sizeof(struct nsp32_sync_table);
+
+static struct nsp32_sync_table nsp32_sync_table_20M[] = {
+	{0x1, 0, 0x19, 0x19},	/* 10.0 : 100ns,  50ns */
+	{0x2, 0, 0x1a, 0x25},	/*  6.7 : 150ns,  50ns */
+	{0x3, 1, 0x26, 0x32},	/*  5.0 : 200ns, 100ns */
+	{0x4, 1, 0x33, 0x3e},	/*  4.0 : 250ns, 100ns */
+	{0x5, 2, 0x3f, 0x4b},	/*  3.3 : 300ns, 150ns */
+	{0x6, 2, 0x4c, 0x57},	/*  2.8 : 350ns, 150ns */
+	{0x7, 3, 0x58, 0x64},	/*  2.5 : 400ns, 200ns */
+	{0x8, 3, 0x65, 0x70},	/*  2.2 : 450ns, 200ns */
+	{0x9, 3, 0x71, 0x7d},	/*  2.0 : 500ns, 200ns */
+};
+static const int nsp32_table_20M_num =
+		sizeof(nsp32_sync_table_20M)/sizeof(struct nsp32_sync_table);
+
+static struct nsp32_sync_table nsp32_sync_table_pci[] = {
+	{0x1, 0, 0x0c, 0x0f},	/* 16.6 :  60ns,  30ns */
+	{0x2, 0, 0x10, 0x16},	/* 11.1 :  90ns,  30ns */
+	{0x3, 1, 0x17, 0x1e},	/*  8.3 : 120ns,  60ns */
+	{0x4, 1, 0x1f, 0x25},	/*  6.7 : 150ns,  60ns */
+	{0x5, 2, 0x26, 0x2d},	/*  5.6 : 180ns,  90ns */
+	{0x6, 2, 0x2e, 0x34},	/*  4.8 : 210ns,  90ns */
+	{0x7, 3, 0x35, 0x3c},	/*  4.2 : 240ns, 120ns */
+	{0x8, 3, 0x3d, 0x43},	/*  3.7 : 270ns, 120ns */
+	{0x9, 3, 0x44, 0x4b}, 	/*  3.3 : 300ns, 120ns */
+};
+static const int nsp32_table_pci_num =
+		sizeof(nsp32_sync_table_pci)/sizeof(struct nsp32_sync_table);
+
+/*
+ * function declaration
+ */
+static int nsp32_detect(Scsi_Host_Template *);
+static int nsp32_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static const char *nsp32_info(struct Scsi_Host *);
+static int nsp32_eh_abort(Scsi_Cmnd *);
+static int nsp32_eh_bus_reset(Scsi_Cmnd *);
+static int nsp32_eh_host_reset(Scsi_Cmnd *);
+static int nsp32_reset(Scsi_Cmnd *, unsigned int);
+static int nsp32_release(struct Scsi_Host *);
+static int nsp32_proc_info(char *, char **, off_t, int, int, int);
+static int __devinit nsp32_probe(struct pci_dev *, const struct pci_device_id *);
+static void __devexit nsp32_remove(struct pci_dev *);
+static int __init init_nsp32(void);
+static void __exit exit_nsp32(void);
+
+static void nsp32_message(char *, int, char *, char *, ...);
+static void nsp32_dmessage(char *, int, int, char *, ...);
+static void nsp32_build_identify(nsp32_hw_data *, Scsi_Cmnd *);
+static void nsp32_build_sdtr(nsp32_hw_data *, unsigned char, unsigned char);
+static void nsp32_build_nop(nsp32_hw_data *);
+static void nsp32_build_reject(nsp32_hw_data *);
+static int nsp32hw_start_selection(Scsi_Cmnd *, nsp32_hw_data *);
+static int nsp32_selection_autoscsi(Scsi_Cmnd *, nsp32_hw_data *);
+static int nsp32_reselection(nsp32_hw_data *, unsigned char);
+static int nsp32hw_setup_sg_table(Scsi_Cmnd *, nsp32_hw_data *);
+static int nsp32hw_init(struct Scsi_Host *);
+static void nsp32_scsi_done(nsp32_hw_data *, Scsi_Cmnd *);
+static int nsp32_busfree_occur(nsp32_hw_data *, unsigned short);
+static void nsp32_adjust_busfree(nsp32_hw_data *, unsigned int);
+static void nsp32_msgout_occur(nsp32_hw_data *);
+static void nsp32_restart_autoscsi(nsp32_hw_data *, unsigned short);
+static void nsp32_msgin_occur(nsp32_hw_data *, unsigned long, unsigned short);
+static void nsp32_analyze_sdtr(nsp32_hw_data *);
+static int nsp32_search_period_entry(nsp32_hw_data *,struct nsp32_target *, unsigned char);
+static void nsp32_set_async(nsp32_hw_data *, struct nsp32_target *);
+static void nsp32_set_max_sync(nsp32_hw_data *, struct nsp32_target *, unsigned char *, unsigned char *);
+static void nsp32_set_sync_entry(nsp32_hw_data *, struct nsp32_target *, int, unsigned char);
+static void nsp32_wait_req(nsp32_hw_data *, int);
+static void nsp32_wait_sack(nsp32_hw_data *, int);
+static void nsp32_sack_assert(nsp32_hw_data *);
+static void nsp32_sack_negate(nsp32_hw_data *);
+static void nsp32_do_bus_reset(nsp32_hw_data *);
+static void do_nsp32_isr(int, void *, struct pt_regs *);
+
+static int nsp32_getprom_param(nsp32_hw_data *);
+static int nsp32_getprom_new(nsp32_hw_data *);
+static int nsp32_getprom_standard(nsp32_hw_data *);
+static int nsp32_prom_read(nsp32_hw_data *, int);
+static void nsp32_prom_start(nsp32_hw_data *);
+static void nsp32_prom_stop(nsp32_hw_data *);
+static void nsp32_prom_write(nsp32_hw_data *, int);
+static int nsp32_prom_fetch(nsp32_hw_data *);
+static inline void nsp32_prom_set(nsp32_hw_data *, int, int);
+static inline int nsp32_prom_get(nsp32_hw_data *, int);
+
+
+/*
+ * max_sectors is currently limited up to 128.
+ */
+static Scsi_Host_Template driver_template = {
+	.proc_name =			"nsp32",
+	.name =				"Workbit NinjaSCSI-32Bi/UDE",
+	.proc_info =			nsp32_proc_info,
+	.detect =			nsp32_detect,
+	.info =				nsp32_info,
+	.queuecommand =			nsp32_queuecommand,
+	.can_queue =			1,
+	.sg_tablesize =			NSP_SG_SIZE,
+	.max_sectors =			128,
+	.cmd_per_lun =			1,
+	.this_id =			7,
+	.use_clustering =		DISABLE_CLUSTERING,
+	.eh_abort_handler =       	nsp32_eh_abort,
+	.eh_device_reset_handler =	NULL,
+	.eh_bus_reset_handler =		nsp32_eh_bus_reset,
+	.eh_host_reset_handler =	nsp32_eh_host_reset,
+	.reset =			nsp32_reset,
+	.release =			nsp32_release,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2))
+	.use_new_eh_code =        	1,
+#else
+	/* .highmem_io =		1,	*/
+#endif
+};
+
+#include "nsp32_io.h"
+
+/*
+ * debug, error print
+ */
+#define nsp32_msg(type, args...) \
+	nsp32_message(__FUNCTION__, __LINE__, (type), ## args)
+#define nsp32_dbg(mask, args...) \
+	nsp32_dmessage(__FUNCTION__, __LINE__, (mask), ## args)
+
+#ifndef NSP32_DEBUG
+# define NSP32_DEBUG_MASK		0x000000
+#else
+# define NSP32_DEBUG_MASK		0xffffff
+#endif
+
+#define NSP32_DEBUG_QUEUECOMMAND	0x000001
+#define NSP32_DEBUG_REGISTER		0x000002
+#define NSP32_DEBUG_AUTOSCSI		0x000004
+#define NSP32_DEBUG_INTR		0x000008
+#define NSP32_DEBUG_SGLIST		0x000010
+#define NSP32_DEBUG_BUSFREE		0x000020
+#define NSP32_DEBUG_CDB_CONTENTS	0x000040
+#define NSP32_DEBUG_RESELECTION		0x000080
+#define NSP32_DEBUG_MSGINOCCUR		0x000100
+#define NSP32_DEBUG_EEPROM		0x000200
+#define NSP32_DEBUG_MSGOUTOCCUR		0x000400
+#define NSP32_DEBUG_BUSRESET		0x000800
+#define NSP32_DEBUG_RESTART		0x001000
+#define NSP32_DEBUG_SYNC		0x002000
+#define NSP32_DEBUG_WAIT		0x004000
+#define NSP32_DEBUG_TARGETFLAG		0x008000
+#define NSP32_DEBUG_PROC		0x010000
+#define NSP32_DEBUG_INIT		0x020000
+#define NSP32_SPECIAL_PRINT_REGISTER	0x100000
+
+#define NSP32_DEBUG_BUF_LEN		100
+
+static void nsp32_message(char *func, int line, char *type, char *fmt, ...)
+{
+	va_list args;
+	char buf[NSP32_DEBUG_BUF_LEN];
+
+	va_start(args, fmt);
+	vsprintf(buf, fmt, args);
+	va_end(args);
+
+#ifndef NSP32_DEBUG
+	printk("%snsp32: %s\n", type, buf);
+#else
+	printk("%snsp32: %s (%d): %s\n", type, func, line, buf);
+#endif
+}
+
+static void nsp32_dmessage(char *func, int line, int mask, char *fmt, ...)
+{
+	va_list args;
+	char buf[NSP32_DEBUG_BUF_LEN];
+
+	va_start(args, fmt);
+	vsprintf(buf, fmt, args);
+	va_end(args);
+
+	if (mask & NSP32_DEBUG_MASK) {
+		printk("Ninja: %d %s (%d): %s\n", mask, func, line, buf);
+	}
+}
+
+#ifdef NSP32_DEBUG
+# include "nsp32_debug.c"
+#else
+# define show_command(arg)   /* */
+# define show_busphase(arg)  /* */
+# define show_autophase(arg) /* */
+#endif
+
+#ifdef NSP32_DEBUG
+static int pc_debug = NSP32_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(/*KERN_DEBUG*/ args)
+#else
+#define DEBUG(n, args...)
+#endif
+
+
+/*
+ * IDENTIFY Message
+ */
+static void nsp32_build_identify(nsp32_hw_data *data, Scsi_Cmnd *SCpnt)
+{
+	int pos = data->msgoutlen;
+
+	data->msgoutbuf[pos++] =
+		0x80 |		/* Identify */
+#if 0
+		/* XXX: Auto DiscPriv detection is progressing... */
+		0x40 |		/* DiscPriv */
+#endif
+		SCpnt->lun;	/* LUNTRN */
+
+	data->msgoutlen = pos;
+}
+
+/*
+ * SDTR Message Routine
+ */
+static void nsp32_build_sdtr(nsp32_hw_data *data,
+			     unsigned char period, unsigned char offset)
+{
+	int pos = data->msgoutlen;
+
+	data->msgoutbuf[pos++] = EXTENDED_MESSAGE;
+	data->msgoutbuf[pos++] = EXTENDED_SDTR_LEN;
+	data->msgoutbuf[pos++] = EXTENDED_SDTR;
+	data->msgoutbuf[pos++] = period;
+	data->msgoutbuf[pos++] = offset;
+
+	data->msgoutlen = pos;
+}
+
+/*
+ * No Operation Message
+ */
+static void nsp32_build_nop(nsp32_hw_data *data)
+{
+	int pos = data->msgoutlen;
+
+	if (pos != 0) {
+		nsp32_msg(KERN_WARNING,
+			  "Some messages are already contained!");
+		return;
+	}
+
+	data->msgoutbuf[pos++] = NOP;
+	data->msgoutlen = pos;
+}
+
+/*
+ * Reject Message
+ */
+static void nsp32_build_reject(nsp32_hw_data *data)
+{
+	int pos = data->msgoutlen;
+
+	data->msgoutbuf[pos++] = MESSAGE_REJECT;
+	data->msgoutlen = pos;
+}
+	
+/*
+ * timer
+ */
+#if 0
+static void nsp32_start_timer(Scsi_Cmnd *SCpnt, int time)
+{
+	unsigned int base = SCpnt->host->io_port;
+
+	DEBUG(0, __func__ " time=%d\n", time);
+
+	if (time & (~TIMER_CNT_MASK)) {
+		printk("timer set overflow\n");
+	}
+
+	nsp32_write2(base, TIMER_SET, time & TIMER_CNT_MASK);
+}
+#endif
+
+
+/*
+ * set SCSI command and other parameter to asic, and start selection phase
+ */
+static int nsp32hw_start_selection(Scsi_Cmnd *SCpnt, nsp32_hw_data *data)
+{
+	unsigned int   host_id = SCpnt->host->this_id;
+	unsigned int   base    = SCpnt->host->io_port;
+	unsigned char  target  = SCpnt->target;
+	unsigned char  *param  = data->autoparam;
+	unsigned char  phase, arbit;
+	int	       i, time;
+	unsigned int   msgout;
+	unsigned long  l;
+	unsigned short s;
+
+	/*
+	 * check bus free
+	 */
+	phase = nsp32_read1(base, SCSI_BUS_MONITOR);
+	if (phase != BUSMON_BUS_FREE) {
+		nsp32_msg(KERN_WARNING, "bus busy");
+		show_busphase(phase & BUSMON_PHASE_MASK);
+		SCpnt->result = DID_BUS_BUSY << 16;
+		return FALSE;
+	}
+
+	/*
+	 * message out
+	 *
+	 * Note: If the range of msgoutlen is 1 - 3, fill scsi_msgout.
+	 *       over 3 messages needs another routine.
+	 */
+	if (data->msgoutlen == 0) {
+		nsp32_msg(KERN_ERR, "SCSI MsgOut without any message!");
+		SCpnt->result = DID_ERROR << 16;
+		return FALSE;
+	} else if (data->msgoutlen > 0 && data->msgoutlen <= 3) {
+		msgout = 0;
+		for (i=0; i<data->msgoutlen; i++) {
+			/*
+			 * the sending order of the message is:
+			 *  MCNT 3: MSG#0 -> MSG#1 -> MSG#2
+			 *  MCNT 2:          MSG#1 -> MSG#2
+			 *  MCNT 1:                   MSG#2    
+			 */
+			msgout >>= 8;
+			msgout |= (unsigned int)(data->msgoutbuf[i] << 24);
+		}
+		msgout |= MV_VALID;	/* MV valid */
+		msgout |= (unsigned int)data->msgoutlen; /* len */
+	} else {
+		/* data->msgoutlen > 3 */
+		msgout = 0;
+	}
+
+	/*
+	 * setup asic parameter
+	 */
+	memset(param, 0, AUTOPARAM_SIZE);
+
+	/* cdb */
+	for (i=0; i<SCpnt->cmd_len; i++) {
+		param[4*i] = SCpnt->cmnd[i];
+	}
+
+	/* message out */
+	param[4*0x10 +0] = (msgout & 0x000000ff) >> 0;
+	param[4*0x10 +1] = (msgout & 0x0000ff00) >> 8;
+	param[4*0x10 +2] = (msgout & 0x00ff0000) >> 16;
+	param[4*0x10 +3] = (msgout & 0xff000000) >> 24;
+
+	/* syncreg, ackwidth, target id, sampleing rate */
+	param[4*0x11 +0] = data->curtarget->syncreg;
+	param[4*0x11 +1] = data->curtarget->ackwidth;
+	param[4*0x11 +2] = BIT(host_id) | BIT(target);
+	param[4*0x11 +3] = 0;
+
+	/* command control */
+	s = (CLEAR_CDB_FIFO_POINTER | AUTOSCSI_START |
+	     AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02 | AUTO_ATN);
+	param[4*0x12 +0] = (s & 0x00ff) >> 0;
+	param[4*0x12 +1] = (s & 0xff00) >> 8;
+
+	/* transfer control */
+	s = 0;
+	switch (data->trans_method) {
+	case NSP32_TRANSFER_BUSMASTER:
+		s |= BM_START;
+		break;
+	case NSP32_TRANSFER_MMIO:
+		s |= CB_MMIO_MODE;
+		break;
+	case NSP32_TRANSFER_PIO:
+		s |= CB_IO_MODE;
+		break;
+	default:
+		nsp32_msg(KERN_ERR, "unknown trans_method");
+	}
+	/*
+	 * ORed BLIEND_MODE, FIFO intr is decreased, instead of PCI bus waits.
+	 * For bus master transfer, it's taken off.
+	 */
+	s |= (TRANSFER_GO | ALL_COUNTER_CLR);
+	param[4*0x12 +2] = (s & 0x00ff) >> 0;
+	param[4*0x12 +3] = (s & 0xff00) >> 8;
+
+	/* sg table addr */
+	l = data->curlunt->sglun_paddr;
+	param[4*0x13 +0] = (l & 0x000000ff) >> 0;
+	param[4*0x13 +1] = (l & 0x0000ff00) >> 8;
+	param[4*0x13 +2] = (l & 0x00ff0000) >> 16;
+	param[4*0x13 +3] = (l & 0xff000000) >> 24;
+
+	/*
+	 * transfer parameter to asic
+	 */
+	nsp32_write4(base, SGT_ADR,         virt_to_bus(param));
+	nsp32_write2(base, COMMAND_CONTROL, CLEAR_CDB_FIFO_POINTER |
+		                            AUTO_PARAMETER         );
+
+	/*
+	 * Arbitration Status Check
+	 *	
+	 * Note: Arbitration counter is wait during ARBIT_GO is not lifting.
+	 *	 Using udelay(1) consumes CPU time and system time, but 
+	 *	 arbitration delay time is defined minimal 2.4us in SCSI
+	 *	 specification, thus udelay works as coarse grained wait timer.
+	 */
+	time = 0;
+	do {
+		arbit = nsp32_read1(base, ARBIT_STATUS);
+		nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit=0x%x", arbit);
+	} while ((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&
+		 (time++ <= 1000));
+
+	nsp32_dbg(NSP32_DEBUG_AUTOSCSI,
+		  "arbit: 0x%x, delay time: %d", arbit, time);
+
+	if (arbit & ARBIT_WIN) {
+		SCpnt->result = DID_OK << 16;
+		/* PCI LED on! */
+		nsp32_index_write1(base, EXT_PORT, LED_ON);
+	} else if (arbit & ARBIT_FAIL) {
+		SCpnt->result = DID_BUS_BUSY << 16;
+		nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR);
+		return FALSE;
+	} else {
+		/* unknown error or ARBIT_GO timeout */
+		nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit fail");
+		SCpnt->result = DID_NO_CONNECT << 16;
+		nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR);
+		return FALSE;
+        }
+
+	/*
+	 * clear Arbit
+	 */
+	nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR);
+
+	return TRUE;
+}
+
+
+/*
+ * Selection with AUTO SCSI (without AUTO PARAMETER)
+ */
+static int nsp32_selection_autoscsi(Scsi_Cmnd *SCpnt, nsp32_hw_data *data)
+{
+	unsigned char	phase;
+	unsigned char	arbit;
+	int		status;
+	int		i;
+	unsigned short	command	= 0;
+	int		time = 0;
+	unsigned int	msgout = 0;
+	unsigned short	execph;
+	unsigned int	base = data->BaseAddress;
+
+	/*
+	 * IRQ disable
+	 */
+	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
+
+	/*
+	 * check bus line
+	 */
+	phase = nsp32_read1(base, SCSI_BUS_MONITOR);
+	if(((phase & BUSMON_BSY) == 1) ||
+	   (phase & BUSMON_SEL) == 1) {
+		nsp32_msg(KERN_WARNING, "bus busy");
+		SCpnt->result = DID_BUS_BUSY << 16;
+		status = 1;
+		goto out;
+        }
+
+	/*
+	 * clear execph
+	 */
+	execph = nsp32_read2(base, SCSI_EXECUTE_PHASE);
+
+	/*
+	 * clear FIFO counter to set CDBs
+	 */
+	nsp32_write2(base, COMMAND_CONTROL, CLEAR_CDB_FIFO_POINTER);
+
+	/*
+	 * set CDB0 - CDB15
+	 */
+	for (i=0; i<SCpnt->cmd_len; i++) {
+		nsp32_write1(base, COMMAND_DATA, SCpnt->cmnd[i]);
+        }
+	nsp32_dbg(NSP32_DEBUG_CDB_CONTENTS, "CDB[0]=[0x%x]", SCpnt->cmnd[i]);
+
+	/*
+	 * set SCSIOUT LATCH(initiator)/TARGET(target) (ORed) ID
+	 */
+	nsp32_write1(base, SCSI_OUT_LATCH_TARGET_ID,
+		((1 << NSP32_HOST_SCSIID) | (1 << SCpnt->target)));
+
+	/*
+	 * set SCSI MSGOUT REG
+	 *
+	 * Note: If the range of msgoutlen is 1 - 3, fill scsi_msgout.
+	 *       over 3 messages needs another routine.
+	 */
+	if (data->msgoutlen == 0) {
+		nsp32_msg(KERN_ERR, 
+			  "SCSI MsgOut without any message!");
+		SCpnt->result = DID_ERROR << 16;
+		status = 1;
+		goto out;
+	} else if (data->msgoutlen > 0 && data->msgoutlen <= 3) {
+		msgout = 0;
+		for (i=0; i<data->msgoutlen; i++) {
+			/*
+			 * the sending order of the message is:
+			 *  MCNT 3: MSG#0 -> MSG#1 -> MSG#2
+			 *  MCNT 2:          MSG#1 -> MSG#2
+			 *  MCNT 1:                   MSG#2    
+			 */
+			msgout >>= 8;
+			msgout |= (unsigned int)(data->msgoutbuf[i] << 24);
+		}
+		msgout |= MV_VALID;	/* MV valid */
+		msgout |= (unsigned int)data->msgoutlen; /* len */
+		nsp32_write4(base, SCSI_MSG_OUT, msgout);
+	} else {
+		/* data->msgoutlen > 3 */
+		nsp32_write4(base, SCSI_MSG_OUT, 0);
+	}
+
+	/*
+	 * set selection timeout(= 250ms)
+	 */
+	nsp32_write2(base, SEL_TIME_OUT, SEL_TIMEOUT_TIME);
+
+	/*
+	 * set smpl rate
+	 * 
+	 * TODO: smpl_rate (BASE+0F) is 0 when internal clock = 40MHz.
+	 *      check other internal clock!
+	 */
+	nsp32_write1(base, SREQ_SMPL_RATE, 0);
+
+	/*
+	 * clear Arbit
+	 */
+	nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR);
+
+	/*
+	 * set SYNCREG
+	 * Don't set BM_START_ADR before setting this register.
+	 */
+	nsp32_write1(base, SYNC_REG, data->curtarget->syncreg);
+
+	/*
+	 * set ACKWIDTH
+	 */
+	nsp32_write1(base, ACK_WIDTH, data->curtarget->ackwidth);
+
+	nsp32_dbg(NSP32_DEBUG_AUTOSCSI,
+		  "syncreg=0x%x, ackwidth=0x%x, sgtpaddr=0x%x, id=0x%x",
+		  nsp32_read1(base, SYNC_REG), nsp32_read1(base, ACK_WIDTH),
+		  nsp32_read4(base, SGT_ADR), nsp32_read1(base, SCSI_OUT_LATCH_TARGET_ID));
+	nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "msgoutlen=%d, msgout=0x%x",
+		  data->msgoutlen, msgout);
+
+	/*
+	 * set SGT ADDR (physical address)
+	 */
+	nsp32_write4(base, SGT_ADR, data->curlunt->sglun_paddr);
+
+	/*
+	 * set TRANSFER CONTROL REG
+	 */
+	command = 0;
+	command |= ( TRANSFER_GO | ALL_COUNTER_CLR);
+	if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
+		if (SCpnt->request_bufflen > 0) {
+			command |= BM_START;
+		}
+	} else if (data->trans_method & NSP32_TRANSFER_MMIO) {
+		command |= CB_MMIO_MODE;
+	} else if (data->trans_method & NSP32_TRANSFER_PIO) {
+		command |= CB_IO_MODE;
+	}
+	nsp32_write2(base, TRANSFER_CONTROL, command);
+
+	/*
+	 * start AUTO SCSI, kick off arbitration
+	 */
+	command = 0;
+	command |= (CLEAR_CDB_FIFO_POINTER
+		    | AUTOSCSI_START
+		    | AUTO_MSGIN_00_OR_04
+		    | AUTO_MSGIN_02 
+		    | AUTO_ATN);
+	nsp32_write2(base, COMMAND_CONTROL, command);
+
+	/*
+	 * Arbitration Status Check
+	 *	
+	 * Note: Arbitration counter is wait during ARBIT_GO is not lifting.
+	 *	 Using udelay(1) consumes CPU time and system time, but 
+	 *	 arbitration delay time is defined minimal 2.4us in SCSI
+	 *	 specification, thus udelay works as coarse grained wait timer.
+	 */
+	time = 0;
+	while(1) {
+		arbit = nsp32_read1(base, ARBIT_STATUS);
+		if(arbit & ARBIT_GO) {
+			udelay(1);
+			time++;
+			if ( time > ARBIT_TIMEOUT_TIME ) {
+				/* something lock up! guess no connection */
+				SCpnt->result = DID_NO_CONNECT << 16;
+				status = FALSE;
+				goto out;
+			}
+		} else {
+			break;
+		}
+	};
+
+	nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit: 0x%x, delay time: %d", arbit, time);
+
+	/*
+	 * check Arbitration Status Result
+	 */
+	if(arbit & ARBIT_WIN) {
+		/* Arbitration succeeded */
+		status = TRUE;
+		SCpnt->result = DID_OK << 16;
+		/* PCI LED on! */
+		nsp32_index_write1(base, EXT_PORT, LED_ON);
+	} else if(arbit & ARBIT_FAIL) {
+		/* Arbitration failed */
+		status = FALSE;
+		SCpnt->result = DID_BUS_BUSY << 16;
+	} else {
+		/* unknown error? */
+		status = FALSE;
+		SCpnt->result = DID_ERROR << 16;
+		SCpnt->result = DID_NO_CONNECT << 16;
+	}
+
+	/*
+	 * clear Arbit
+	 */
+	nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR);
+
+ out:
+	/*
+	 * IRQ enable
+	 */
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+	return(status);
+}
+
+
+/*
+ * reselection
+ *
+ * Note: This reselection routine is called from msgin_occur,
+ *	 reselection target id&lun must be already set.
+ *	 SCSI-2 says IDENTIFY implies RESTORE_POINTER operation.
+ */
+static int nsp32_reselection(nsp32_hw_data *data, unsigned char newlun)
+{
+	unsigned int base = data->BaseAddress;
+	unsigned char tmpid, newid;
+
+	nsp32_dbg(NSP32_DEBUG_RESELECTION, "enter");
+
+	/*
+	 * calculate reselected SCSI ID
+	 */
+	tmpid = nsp32_read1(base, RESELECT_ID);
+	tmpid &= 0x7f;
+	newid = 0;
+	while (tmpid) {
+		if (tmpid & 1) {
+			break;
+		}
+		tmpid >>= 1;
+		newid++;
+	}
+
+	/*
+	 * If reselected New ID:LUN is not existed
+	 * or current nexus is not existed, unexpected
+	 * reselection is occured. Send reject message.
+	 */
+	if (newid >= MAX_TARGET || newlun >= MAX_LUN) {
+		nsp32_msg(KERN_WARNING, "unknown id/lun");
+		return FALSE;
+	} else if(data->lunt[newid][newlun]->SCpnt == NULL) {
+		nsp32_msg(KERN_WARNING, "no SCSI command is processing");
+		return FALSE;
+	}
+
+	data->pid       = newid;
+	data->plun      = newlun;
+	data->curtarget = &data->target[newid];
+	data->curlunt   = data->lunt[newid][newlun];
+
+	/* reset SACK/SavedACK counter (or ALL clear?) */
+	nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK);
+
+	return TRUE;
+}
+
+
+/*
+ * nsp32hw_setup_sg_table - build scatter gather list for transfer data
+ *			    with bus master.
+ *
+ * Note: NinjaSCSI-32Bi/UDE bus master can not transfer over 64KB at a time.
+ */
+static int nsp32hw_setup_sg_table(Scsi_Cmnd *SCpnt, nsp32_hw_data *data)
+{
+	struct scatterlist *sgl;
+	struct nsp32_sgtable *sgt = data->curlunt->sglun->sgt;
+	int num, i;
+
+	if (SCpnt->request_bufflen == 0) {
+		return TRUE;
+	}
+
+	if (sgt == NULL) {
+		nsp32_dbg(NSP32_DEBUG_SGLIST, "SGT == null");
+		return FALSE;
+	}
+
+	if (SCpnt->use_sg) {
+		sgl = (struct scatterlist *)SCpnt->request_buffer;
+		num = pci_map_sg(data->Pci, sgl, SCpnt->use_sg,
+				 scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+		for (i=0; i<num; i++) {
+			/*
+			 * Build nsp32_sglist, substitute sg dma addresses.
+			 */
+			sgt[i].addr = cpu_to_le32(sg_dma_address(sgl));
+			sgt[i].len  = cpu_to_le32(sg_dma_len(sgl));
+			sgl++;
+
+			if (sgt[i].len > 65536) {
+				nsp32_msg(KERN_ERR,
+					"can't transfer over 64KB at a time");
+				return FALSE;
+			}
+			nsp32_dbg(NSP32_DEBUG_SGLIST,
+				  "num 0x%x : addr 0x%lx len 0x%x",
+				  i, sgt[i].addr, sgt[i].len);
+		}
+		sgt[num-1].len |= NSP32_SG_END_SGT; /* set end mark */
+	} else {
+		SCpnt->SCp.have_data_in	= pci_map_single(data->Pci,
+			SCpnt->request_buffer, SCpnt->request_bufflen,
+			scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+		sgt[0].addr = cpu_to_le32(SCpnt->SCp.have_data_in);
+		sgt[0].len  = cpu_to_le32(SCpnt->request_bufflen);
+		sgt[0].len |= NSP32_SG_END_SGT; /* set end mark */
+
+		nsp32_dbg(NSP32_DEBUG_SGLIST, "single : addr 0x%lx len=0x%x",
+			  sgt[0].addr, sgt[0].len);
+	}
+
+	return TRUE;
+}
+
+static int nsp32_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->host->hostdata;
+	struct nsp32_target *target;
+	struct nsp32_lunt *curlunt;
+	int ret;
+
+	nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
+		  "enter. target: 0x%x LUN: 0x%x cmnd: 0x%x cmndlen: 0x%x "
+		  "use_sg: 0x%x reqbuf: 0x%lx reqlen: 0x%x",
+		  SCpnt->target, SCpnt->lun, SCpnt->cmnd[0], SCpnt->cmd_len,
+		  SCpnt->use_sg, SCpnt->request_buffer, SCpnt->request_bufflen);
+
+	if (data->CurrentSC != NULL ) {
+		nsp32_msg(KERN_ERR, "Currentsc != NULL. Cancel this command request");
+		data->CurrentSC = NULL;
+		SCpnt->result   = DID_NO_CONNECT << 16;
+		done(SCpnt);
+
+		return 1;
+	}
+
+	/* check target ID is not same as this initiator ID */
+	if (SCpnt->target == NSP32_HOST_SCSIID) {
+		SCpnt->result = DID_BAD_TARGET << 16;
+		done(SCpnt);
+		return 1;
+	}
+
+	/* check target LUN is allowable value */
+	if (SCpnt->lun >= MAX_LUN) {
+		SCpnt->result = DID_BAD_TARGET << 16;
+		done(SCpnt);
+		return 1;
+	}
+
+	show_command(SCpnt);
+
+	SCpnt->scsi_done     = done;
+	data->CurrentSC      = SCpnt;
+	SCpnt->SCp.Status    = CHECK_CONDITION;
+	SCpnt->SCp.Message   = 0;
+	SCpnt->resid         = 0; //SCpnt->request_bufflen;
+
+	SCpnt->SCp.ptr		    = (char *) SCpnt->request_buffer;
+	SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
+	SCpnt->SCp.buffer	    = NULL;
+	SCpnt->SCp.buffers_residual = 0;
+
+	/* initialize data */
+	data->msgoutlen		= 0;
+	data->msginlen		= 0;
+	curlunt			= data->lunt[SCpnt->target][SCpnt->lun];
+	curlunt->SCpnt		= SCpnt;
+	curlunt->save_datp	= 0;
+	curlunt->msgin03	= FALSE;
+	data->curlunt		= curlunt;
+	data->pid		= SCpnt->target;
+	data->plun		= SCpnt->lun;
+
+	ret = nsp32hw_setup_sg_table(SCpnt, data);
+	if (ret == FALSE) {
+		SCpnt->result = DID_ERROR << 16;
+		nsp32_scsi_done(data, SCpnt);
+	}
+
+	/* Build IDENTIFY */
+	nsp32_build_identify(data, SCpnt);
+
+	/* 
+	 * If target is the first time to transfer after the reset
+	 * (target don't have SDTR_DONE and SDTR_INITIATOR), sync
+	 * message SDTR is needed to do synchronous transfer.
+	 */
+	target = &data->target[SCpnt->target];
+	data->curtarget = target;
+
+	if (!(target->sync_flag & (SDTR_DONE | SDTR_INITIATOR | SDTR_TARGET))) {
+		unsigned char period, offset;
+
+		if (trans_mode != ASYNC_MODE) {
+			nsp32_set_max_sync(data, target, &period, &offset);
+			nsp32_build_sdtr(data, period, offset);
+			target->sync_flag |= SDTR_INITIATOR;
+		} else {
+			nsp32_set_async(data, target);
+			target->sync_flag |= SDTR_DONE;
+		}
+
+		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
+			  "SDTR: entry: %d start_period: 0x%x offset: 0x%x\n",
+			  target->limit_entry, period, offset);
+	} else if (target->sync_flag & SDTR_INITIATOR) {
+		/*
+		 * It was negotiating SDTR with target, sending from the
+		 * initiator, but there are no chance to remove this flag.
+		 * Set async because we don't get proper negotiation.
+		 */
+		nsp32_set_async(data, target);
+		target->sync_flag &= ~SDTR_INITIATOR;
+		target->sync_flag |= SDTR_DONE;
+
+		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
+			  "SDTR_INITIATOR: fall back to async");
+	} else if (target->sync_flag & SDTR_TARGET) {
+		/*
+		 * It was negotiating SDTR with target, sending from target,
+		 * but there are no chance to remove this flag.  Set async
+		 * because we don't get proper negotiation.
+		 */
+		nsp32_set_async(data, target);
+		target->sync_flag &= ~SDTR_TARGET;
+		target->sync_flag |= SDTR_DONE;
+
+		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
+			  "Unknown SDTR from target is reached, fall back to async.");
+	}
+
+	nsp32_dbg(NSP32_DEBUG_TARGETFLAG,
+		  "target: %d sync_flag: 0x%x syncreg: 0x%x ackwidth: 0x%x",
+		  SCpnt->target, target->sync_flag, target->syncreg,
+		  target->ackwidth);
+
+	/* Selection */
+	if (auto_param == 0) {
+		ret = nsp32hw_start_selection(SCpnt, data);
+	} else {
+		ret = nsp32_selection_autoscsi(SCpnt, data);
+	}
+
+	if (ret != TRUE) {
+		nsp32_scsi_done(data, SCpnt);
+		return 1;
+	}
+
+	return 0;
+}
+
+/* initialize asic */
+static int nsp32hw_init(struct Scsi_Host *host)
+{
+	unsigned int  base = host->io_port;
+	unsigned short irq_stat;
+	unsigned long lc_reg;
+	unsigned char power;
+	nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata;
+
+	lc_reg = nsp32_index_read4(base, CFG_LATE_CACHE);
+	if ((lc_reg & 0xff00) == 0) {
+		lc_reg |= (0x20 << 8);
+		nsp32_index_write2(base, CFG_LATE_CACHE, lc_reg & 0xffff);
+	}
+
+	nsp32_write2(base, IRQ_CONTROL,      IRQ_CONTROL_ALL_IRQ_MASK);
+	nsp32_write2(base, TRANSFER_CONTROL, 0);
+	nsp32_write4(base, BM_CNT,           0);
+	nsp32_write2(base, SCSI_EXECUTE_PHASE, 0);
+
+	do {
+		irq_stat = nsp32_read2(base, IRQ_STATUS);
+	} while (irq_stat & IRQSTATUS_ANY_IRQ);
+	nsp32_dbg(NSP32_DEBUG_INIT, "irq_stat 0x%x", irq_stat);
+
+	/*
+	 * Fill FIFO_FULL_SHLD, FIFO_EMPTY_SHLD. Below parameter is
+	 *  designated by specification.
+	 */
+	if ((data->trans_method & NSP32_TRANSFER_PIO) ||
+	    (data->trans_method & NSP32_TRANSFER_MMIO)) {
+		nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT, 0x40);
+	} else if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
+		nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT, 0x10);
+	}
+	nsp32_index_write1(base, FIFO_EMPTY_SHLD_COUNT, 0x60);
+
+	nsp32_dbg(NSP32_DEBUG_INIT, "full 0x%x emp 0x%x",
+		  nsp32_index_read1(base, FIFO_FULL_SHLD_COUNT),
+		  nsp32_index_read1(base, FIFO_EMPTY_SHLD_COUNT));
+
+	nsp32_index_write1(base, CLOCK_DIV, data->clock);
+	nsp32_index_write1(base, BM_CYCLE, MEMRD_CMD1 | SGT_AUTO_PARA_MEMED_CMD);
+	nsp32_write1(base, PARITY_CONTROL, 0);	/* parity check is disable */
+
+	/*
+	 * initialize I_MISC_WRRD register
+	 * 
+	 * Note: Designated parameters is obeyed as following:
+	 *	MISC_SCSI_DIRECTION_DETECTOR_SELECT: It must be set.
+	 *	MISC_MASTER_TERMINATION_SELECT:      It must be set.
+	 *	MISC_BMREQ_NEGATE_TIMING_SEL:	     It should be set.
+	 *	MISC_AUTOSEL_TIMING_SEL:	     It should be set.
+	 *	MISC_BMSTOP_CHANGE2_NONDATA_PHASE:   It should be set.
+	 *	MISC_DELAYED_BMSTART:		     It's selected for safety.
+	 *
+	 * Note: If MISC_BMSTOP_CHANGE2_NONDATA_PHASE is set, then
+	 *	we have to set TRANSFERCONTROL_BM_START as 0 and set
+	 *	appropriate value before restarting bus master transfer.
+	 */
+	nsp32_index_write2(base, MISC_WR,
+			   (SCSI_DIRECTION_DETECTOR_SELECT |
+			    DELAYED_BMSTART |
+			    MASTER_TERMINATION_SELECT |
+			    BMREQ_NEGATE_TIMING_SEL |
+			    AUTOSEL_TIMING_SEL |
+			    BMSTOP_CHANGE2_NONDATA_PHASE));
+
+	nsp32_index_write1(base, TERM_PWR_CONTROL, 0);
+	power = nsp32_index_read1(base, TERM_PWR_CONTROL);
+	if (!(power & SENSE)) {
+		nsp32_msg(KERN_INFO, "term power on");
+		nsp32_index_write1(base, TERM_PWR_CONTROL, BPWR);
+	}
+
+	nsp32_write2(base, TIMER_SET, TIMER_STOP);
+	nsp32_write2(base, TIMER_SET, TIMER_STOP);
+
+	nsp32_write1(base, SYNC_REG,  0);
+	nsp32_write1(base, ACK_WIDTH, 0);
+	nsp32_write2(base, SEL_TIME_OUT, 10000); /* 25us x10000 = 250ms defined in SCSI */
+
+	/*
+	 * enable to select designated IRQ (except for
+	 * IRQSELECT_SERR, IRQSELECT_PERR, IRQSELECT_BMCNTERR)
+	 */
+	nsp32_index_write2(base, IRQ_SELECT, IRQSELECT_TIMER_IRQ         |
+			                     IRQSELECT_SCSIRESET_IRQ     |
+			                     IRQSELECT_FIFO_SHLD_IRQ     |
+			                     IRQSELECT_RESELECT_IRQ      |
+			                     IRQSELECT_PHASE_CHANGE_IRQ  |
+			                     IRQSELECT_AUTO_SCSI_SEQ_IRQ |
+			                     //IRQSELECT_BMCNTERR_IRQ    |
+			                     IRQSELECT_TARGET_ABORT_IRQ  |
+			                     IRQSELECT_MASTER_ABORT_IRQ );
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+	/* PCI LED off */
+	nsp32_index_write1(base, EXT_PORT_DDR, LED_OFF);
+	nsp32_index_write1(base, EXT_PORT, LED_OFF);
+
+	return TRUE;
+}
+
+
+/* interrupt routine */
+static void do_nsp32_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	nsp32_hw_data *data = dev_id;
+	unsigned int base = data->BaseAddress;
+	Scsi_Cmnd *SCpnt = data->CurrentSC;
+	unsigned short auto_stat, irq_stat, trans_stat;
+	unsigned char busmon, busphase;
+	unsigned long flags;
+	int ret;
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	struct Scsi_Host *host = data->Host;
+	spin_lock_irqsave(host->host_lock, flags);
+#else
+	spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+	/*
+	 * IRQ check, then enable IRQ mask
+	 */
+	irq_stat = nsp32_read2(base, IRQ_STATUS);
+	nsp32_dbg(NSP32_DEBUG_INTR, 
+		  "enter IRQ: %d, IRQstatus: 0x%x", irq, irq_stat);
+	/* is this interrupt comes from Ninja asic? */
+	if ((irq_stat & IRQSTATUS_ANY_IRQ) == 0) {
+		nsp32_msg(KERN_INFO, "spurious interrupt: irq other 0x%x", irq_stat);
+		goto out2;
+	}
+	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
+
+	busmon = nsp32_read1(base, SCSI_BUS_MONITOR);
+	busphase = busmon & BUSMON_PHASE_MASK;
+
+	trans_stat = nsp32_read2(base, TRANSFER_STATUS);
+	if ((irq_stat == 0xffff) && (trans_stat == 0xffff)) {
+		nsp32_msg(KERN_INFO, "card disconnect");
+		if (data->CurrentSC != NULL) {
+			nsp32_msg(KERN_INFO, "clean up current SCSI command");
+			SCpnt->result = DID_BAD_TARGET << 16;
+			nsp32_scsi_done(data, SCpnt);
+		}
+		goto out;
+	}
+
+	/* Timer IRQ */
+	if (irq_stat & IRQSTATUS_TIMER_IRQ) {
+		DEBUG(0, "timer stop\n");
+		nsp32_write2(base, TIMER_SET, TIMER_STOP);
+		goto out;
+	}
+
+	/* SCSI reset */
+	if (irq_stat & IRQSTATUS_SCSIRESET_IRQ) {
+		nsp32_msg(KERN_INFO, "detected someone do bus reset");
+		nsp32_do_bus_reset(data);
+		if (SCpnt != NULL) {
+			SCpnt->result = DID_RESET << 16;
+			nsp32_scsi_done(data, SCpnt);
+		}
+		goto out;
+	}
+	
+	if (SCpnt == NULL) {
+		nsp32_msg(KERN_WARNING, "SCpnt==NULL this can't be happen\n");
+		nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x\n", irq_stat, trans_stat);
+		goto out;
+	}
+
+	/*
+	 * AutoSCSI Interrupt.
+	 * Note: This interrupt is occured when AutoSCSI is finished.  Then
+	 * check SCSIEXECUTEPHASE, and do appropriate action.  Each phases are
+	 * recorded when AutoSCSI sequencer has been processed.
+	 */
+	if(irq_stat & IRQSTATUS_AUTOSCSI_IRQ) {
+		/* getting SCSI executed phase */
+		auto_stat = nsp32_read2(base, SCSI_EXECUTE_PHASE);
+		nsp32_write2(base, SCSI_EXECUTE_PHASE, 0);
+
+		/* Selection Timeout, go busfree phase. */
+		if (auto_stat & SELECTION_TIMEOUT) {
+			nsp32_dbg(NSP32_DEBUG_INTR,
+				  "selection timeout occured");
+
+			SCpnt->result = DID_TIME_OUT << 16;
+			nsp32_scsi_done(data, SCpnt);
+			goto out;
+		}
+
+		if (auto_stat & MSGOUT_PHASE) {
+			/*
+			 * MsgOut phase was processed.
+			 * If MSG_IN_OCCUER is not set, then MsgOut phase is
+			 * completed. Thus, msgoutlen must reset.  Otherwise,
+			 * nothing to do here. If MSG_OUT_OCCUER is occured,
+			 * then we will encounter the condition and check.
+			 */
+			if (!(auto_stat & MSG_IN_OCCUER) &&
+			     (data->msgoutlen <= 3)) {
+				/*
+				 * !MSG_IN_OCCUER && msgoutlen <=3
+				 *   ---> AutoSCSI with MSGOUTreg is processed.
+				 */
+				data->msgoutlen = 0;
+			};
+
+			nsp32_dbg(NSP32_DEBUG_INTR, "MsgOut phase processed");
+		}
+
+		if ((auto_stat & DATA_IN_PHASE) &&
+		    (SCpnt->resid > 0) &&
+		    ((nsp32_read2(base, FIFO_REST_CNT) & FIFO_REST_MASK) != 0)) {
+			printk( "auto+fifo\n");
+			//nsp32_pio_read(SCpnt);
+		}
+
+		if (auto_stat & (DATA_IN_PHASE | DATA_OUT_PHASE)) {
+			/* DATA_IN_PHASE/DATA_OUT_PHASE was processed. */
+			nsp32_dbg(NSP32_DEBUG_INTR,
+				  "Data in/out phase processed");
+
+			/* read BMCNT, SGT pointer addr */
+			nsp32_dbg(NSP32_DEBUG_INTR, "BMCNT=0x%lx", 
+				    nsp32_read4(base, BM_CNT));
+			nsp32_dbg(NSP32_DEBUG_INTR, "addr=0x%lx", 
+				    nsp32_read4(base, SGT_ADR));
+			nsp32_dbg(NSP32_DEBUG_INTR, "SACK=0x%lx", 
+				    nsp32_read4(base, SACK_CNT));
+			nsp32_dbg(NSP32_DEBUG_INTR, "SSACK=0x%lx", 
+				    nsp32_read4(base, SAVED_SACK_CNT));
+			
+		}
+
+		/*
+		 * MsgIn Occur
+		 */
+		if (auto_stat & MSG_IN_OCCUER) {
+			nsp32_msgin_occur(data, irq_stat, auto_stat);
+		}
+
+		/*
+		 * MsgOut Occur
+		 */
+		if (auto_stat & MSG_OUT_OCCUER) {
+			nsp32_msgout_occur(data);
+		}
+
+		/*
+		 * Bus Free Occur
+		 */
+		if (auto_stat & BUS_FREE_OCCUER) {
+			ret = nsp32_busfree_occur(data, auto_stat);
+			if (ret == TRUE) {
+				goto out;
+			}
+		}
+
+		if (auto_stat & STATUS_PHASE) {
+			/*
+			 * Read CSB and substitute CSB for SCpnt->result
+			 * to save status phase stutas byte.
+			 * scsi error handler checks host_byte (DID_*:
+			 * low level driver to indicate status), then checks 
+			 * status_byte (SCSI status byte).
+			 */
+			SCpnt->result =	(int)nsp32_read1(base, SCSI_CSB_IN);
+		}
+
+		if (auto_stat & ILLEGAL_PHASE) {
+			/* Illegal phase is detected. SACK is not back. */
+			nsp32_msg(KERN_WARNING, 
+				  "AUTO SCSI ILLEGAL PHASE OCCUR!!!!");
+
+			/* TODO: currently we don't have any action... bus reset? */
+
+			/*
+			 * To send back SACK, assert, wait, and negate.
+			 */
+			nsp32_sack_assert(data);
+			nsp32_wait_req(data, NEGATE);
+			nsp32_sack_negate(data);
+
+		}
+
+		if (auto_stat & COMMAND_PHASE) {
+			/* nothing to do */
+			nsp32_dbg(NSP32_DEBUG_INTR, "Command phase processed");
+		}
+
+		if (auto_stat & AUTOSCSI_BUSY) {
+			/* AutoSCSI is running */
+		}
+
+		show_autophase(auto_stat);
+	}
+
+	/* FIFO_SHLD_IRQ */
+	if (irq_stat & IRQSTATUS_FIFO_SHLD_IRQ) {
+		nsp32_dbg(NSP32_DEBUG_INTR, "FIFO IRQ");
+
+		switch(busphase) {
+		case BUSPHASE_DATA_OUT:
+			printk( "write\n");
+
+			//nsp32_pio_write(SCpnt);
+
+			break;
+
+		case BUSPHASE_DATA_IN:
+			printk( "read\n");
+
+			//nsp32_pio_read(SCpnt);
+
+			break;
+
+		case BUSPHASE_STATUS:
+			//DEBUG(0, "fifo/status\n");
+
+			SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN);
+
+			break;
+		default:
+			printk("fifo/other phase?\n");
+			printk("irq_stat=0x%x trans_stat=0x%x\n", irq_stat, trans_stat);
+			show_busphase(busphase);
+			break;
+		}
+
+		goto out;
+	}
+
+	/* Phase Change IRQ */
+	if (irq_stat & IRQSTATUS_PHASE_CHANGE_IRQ) {
+		nsp32_dbg(NSP32_DEBUG_INTR, "phase change IRQ");
+
+		switch(busphase) {
+		case BUSPHASE_MESSAGE_IN:
+			nsp32_dbg(NSP32_DEBUG_INTR, "phase chg/msg in");
+			nsp32_msgin_occur(data, irq_stat, 0);
+			break;
+		default:
+			nsp32_msg(KERN_WARNING, "phase chg/other phase?");
+			nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x\n",
+				  irq_stat, trans_stat);
+			show_busphase(busphase);
+			break;
+		}
+		goto out;
+	}
+
+	/* PCI_IRQ */
+	if (irq_stat & IRQSTATUS_PCI_IRQ) {
+		nsp32_dbg(NSP32_DEBUG_INTR, "PCI IRQ occured");
+		/* Do nothing */
+	}
+
+	/* BMCNTERR_IRQ */
+	if (irq_stat & IRQSTATUS_BMCNTERR_IRQ) {
+		nsp32_msg(KERN_ERR, "Received unexpected BMCNTERR IRQ! ");
+		/*
+		 * TODO: To be implemented improving bus master
+		 * transfer reliablity when BMCNTERR is occured in
+		 * AutoSCSI phase described in specification.
+		 */
+	}
+
+#if 0
+	printk("irq_stat=0x%x trans_stat=0x%x\n", irq_stat, trans_stat);
+	show_busphase(busphase);
+#endif
+
+ out:
+	/* disable IRQ mask */
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+ out2:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	spin_unlock_irqrestore(&io_request_lock, flags);
+#else
+	spin_unlock_irqrestore(host->host_lock, flags);
+#endif
+
+	nsp32_dbg(NSP32_DEBUG_INTR, "exit");
+
+	return;
+}
+
+#undef SPRINTF
+#define SPRINTF(args...) \
+        do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
+static int nsp32_proc_info(char  *buffer,
+			   char **start,
+			   off_t  offset,
+			   int    length,
+			   int    hostno,
+			   int    inout)
+{
+	char *pos = buffer;
+	int thislength;
+	unsigned long flags;
+	nsp32_hw_data *data;
+	struct Scsi_Host *host = NULL;
+	unsigned int base;
+	unsigned char mode_reg;
+
+	/* Write is not supported, just return. */
+	if (inout == TRUE) {
+		return -EINVAL;
+	}
+
+	/* search this HBA host */
+	for (host=scsi_hostlist; host; host=host->next) {
+		if (host->host_no == hostno) {
+			break;
+		}
+	}
+	if (host == NULL) {
+		return -ESRCH;
+	}
+	data = (nsp32_hw_data *)host->hostdata;
+	base = host->io_port;
+
+	SPRINTF("NinjaSCSI-32 status\n\n");
+	SPRINTF("Driver version:        %s\n",		nsp32_release_version);
+	SPRINTF("SCSI host No.:         %d\n",		hostno);
+	SPRINTF("IRQ:                   %d\n",		host->irq);
+	SPRINTF("IO:                    0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
+	SPRINTF("MMIO(virtual address): 0x%lx\n",	host->base);
+	SPRINTF("sg_tablesize:          %d\n",		host->sg_tablesize);
+	SPRINTF("Chip revision:         %d\n",		(nsp32_read2(base, INDEX_REG) >> 8) - 0x4f);
+
+	mode_reg = nsp32_index_read1(base, CHIP_MODE);
+
+#ifdef CONFIG_PM
+	//SPRINTF("Power Management:      %s\n",          (mode_reg & OPTF) ? "yes" : "no");
+#endif
+	SPRINTF("OEM:                   %s\n",          nsp32_model[mode_reg & (OEM0|OEM1)]);
+
+	spin_lock_irqsave(&(data->Lock), flags);
+	SPRINTF("CurrentSC:             0x%p\n\n",      data->CurrentSC);
+	spin_unlock_irqrestore(&(data->Lock), flags);
+
+	thislength = pos - (buffer + offset);
+
+	if(thislength < 0) {
+		*start = 0;
+                return 0;
+        }
+
+
+	thislength = MIN(thislength, length);
+	*start = buffer + offset;
+
+	return thislength;
+}
+#undef SPRINTF
+
+/*
+ * Note: n_io_port is defined as 0x7f because I/O register port is
+ *	 assigned as:
+ *	0x800-0x8ff: memory mapped I/O port
+ *	0x900-0xbff: (map same 0x800-0x8ff I/O port image repeatedly)
+ *	0xc00-0xfff: CardBus status registers
+ */
+static int nsp32_detect(Scsi_Host_Template *sht)
+{
+	struct Scsi_Host *host;	/* registered host structure */
+	int ret;
+	nsp32_hw_data *data;
+	int i, j;
+
+	nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
+
+	/*
+	 * register this HBA as SCSI device
+	 */
+	host = scsi_register(sht, sizeof(nsp32_hw_data));
+	if (host == NULL) {
+		nsp32_msg (KERN_ERR, "failed to scsi register");
+		goto err;
+	}
+
+	/*
+	 * set nsp32_hw_data
+	 */
+	data = (nsp32_hw_data *)host->hostdata;
+	memset(data, 0, sizeof(nsp32_hw_data));
+
+	data->IrqNumber   = nsp32_data_base.IrqNumber;
+	data->BaseAddress = nsp32_data_base.BaseAddress;
+	data->NumAddress  = nsp32_data_base.NumAddress; 
+	data->MmioAddress = nsp32_data_base.MmioAddress;
+	data->Pci         = nsp32_data_base.Pci;
+	data->pci_devid   = nsp32_data_base.pci_devid;
+
+	host->irq         = data->IrqNumber;
+	host->io_port	  = data->BaseAddress;
+	host->unique_id	  = data->BaseAddress;
+	host->n_io_port	  = data->NumAddress;
+	host->base        = data->MmioAddress;
+	scsi_set_pci_device(host, data->Pci);
+
+	data->Host        = host;
+	spin_lock_init(&(data->Lock));
+
+	data->curlunt     = NULL;
+	data->curtarget   = NULL;
+
+	/*
+	 * Bus master transfer mode is supported currently.
+	 */
+	data->trans_method	= NSP32_TRANSFER_BUSMASTER;
+
+	/*
+	 * Set clock div, CLOCK_4 (HBA has external clock, and
+	 * dividing * 100ns/4).
+	 * Currently CLOCK_4 has only tested, not for CLOCK_2/PCICLK yet.
+	 */
+	data->clock = CLOCK_4;
+
+	/*
+	 * Select appropriate nsp32_sync_table and set I_CLOCKDIV.
+	 */
+	switch (data->clock) {
+	case CLOCK_4:
+		/* If data->clock is CLOCK_4, then select 40M sync table. */
+		data->synct = nsp32_sync_table_40M;
+		data->syncnum = nsp32_table_40M_num;
+		break;
+	case CLOCK_2:
+		/* If data->clock is CLOCK_2, then select 20M sync table. */
+		data->synct = nsp32_sync_table_20M;
+		data->syncnum = nsp32_table_20M_num;
+		break;
+	case PCICLK:
+		/* If data->clock is PCICLK, then select pci sync table. */
+		data->synct = nsp32_sync_table_pci;
+		data->syncnum = nsp32_table_pci_num;
+		break;
+	default:
+		nsp32_msg(KERN_WARNING,
+			  "Invalid clock div is selected, set CLOCK_4.");
+		/* Use default value CLOCK_4 */
+		data->clock = CLOCK_4;
+		data->synct = nsp32_sync_table_40M;
+		data->syncnum = nsp32_table_40M_num;
+	}
+
+	/*
+	 * setup nsp32_lunt
+	 */
+	data->lunt_list = (struct nsp32_lunt *)
+		kmalloc(sizeof(struct nsp32_lunt) * MAX_TARGET * MAX_LUN,
+			GFP_KERNEL);
+	if (data->lunt_list == NULL) {
+		nsp32_msg(KERN_ERR, "cannot allocate LUN memory");
+		goto scsi_unregister;
+	}
+	nsp32_dbg(NSP32_DEBUG_REGISTER, "0x%x 0x%x",
+		  data->lunt_list, sizeof(struct nsp32_lunt)*MAX_TARGET*MAX_LUN);
+
+	/*
+	 * setup DMA 
+	 */
+	if (pci_set_dma_mask(data->Pci, 0xffffffffUL)) {
+		nsp32_msg (KERN_ERR, "failed to set PCI DMA mask");
+		goto kfree_lunt;
+	}
+
+	/*
+	 * allocate autoparam DMA resource.
+	 */
+	data->autoparam = pci_alloc_consistent(data->Pci, AUTOPARAM_SIZE, &data->apaddr);
+	if (data->autoparam == NULL) {
+		nsp32_msg(KERN_ERR, "failed to allocate DMA memory");
+		goto kfree_lunt;
+	}
+
+	/*
+	 * allocate scatter-gather DMA resource.
+	 */
+	data->sg_list = pci_alloc_consistent(data->Pci, 
+			(sizeof(struct nsp32_sgtable) * NSP_SG_SIZE * MAX_TARGET * MAX_LUN),
+			 &data->sgaddr);
+	if (data->sg_list == NULL) {
+		nsp32_msg(KERN_ERR, "failed to allocate DMA memory");
+		goto free_autoparam;
+	}
+
+	for (i=0; i<MAX_TARGET; i++) {
+		for (j=0; j<MAX_LUN; j++) {
+			data->lunt[i][j] = data->lunt_list + (i * MAX_LUN + j);
+		}
+	}
+
+	for (i=0; i<MAX_TARGET; i++) {
+		for (j=0; j<MAX_LUN; j++) {
+			struct nsp32_lunt *lp = data->lunt[i][j];
+			lp->sglun = (struct nsp32_sglun *)
+				(data->sg_list + (i * MAX_LUN + j));
+			lp->sglun_paddr = data->sgaddr +
+				(long)((i * MAX_LUN + j) 
+				       * sizeof(struct nsp32_sglun));
+			lp->SCpnt = NULL;
+			lp->save_datp = 0;
+			lp->msgin03 = FALSE;
+			lp->sg_num = 0;
+			lp->cur_entry = 0;
+		}
+	}
+
+	/*
+	 * setup target
+	 */
+	for (i=0; i<MAX_TARGET; i++) {
+		struct nsp32_target *target = &data->target[i];
+
+		target->limit_entry  = 0;
+		target->sync_flag    = 0;
+		nsp32_set_async(data, target);
+	}
+
+	/*
+	 * EEPROM check
+	 */
+	ret = nsp32_getprom_param(data);
+	if (ret == FALSE) {
+		data->resettime = 3;	/* default 3 */
+	}
+
+	/*
+	 * setup HBA
+	 */
+	nsp32hw_init(host);
+
+	snprintf(data->info_str, sizeof(data->info_str),
+		 "NinjaSCSI-32Bi/UDE: irq %d, io 0x%lx+0x%x",
+		 host->irq, host->io_port, host->n_io_port);
+
+	sht->name = data->info_str;
+
+	/*
+	 * SCSI bus reset
+	 *
+	 * Note: It's important to reset SCSI bus in initialization phase.
+	 *     NinjaSCSI-32Bi/UDE HBA EEPROM seems to exchange SDTR when system is
+	 *     coming up, so SCSI devices connected to HBA is set as
+	 *     un-asynchronous mode.  It brings the merit that this HBA is
+	 *     ready to start synchronous transfer without any preparation,
+	 *     but we are difficult to control transfer speed.  In addition,
+	 *     it prevents device transfer speed from effecting EEPROM start-up
+	 *     SDTR.  NinjaSCSI-32Bi/UDE has the feature if EEPROM is set as Auto
+	 *     Mode, then FAST-10M is selected when SCSI devices are connected
+	 *     same or more than 4 devices.  It should be avoided depending on
+	 *     this specification Thus, resetting the SCSI bus restores all
+	 *     connected SCSI devices to asynchronous mode, then this driver
+	 *     put SDTR safely later, and we can control all SCSI device
+	 *     transfer mode.
+	 */
+	nsp32_do_bus_reset(data);
+
+	ret = request_irq(host->irq, do_nsp32_isr, SA_SHIRQ, "nsp32", data);
+	if (ret < 0) {
+		nsp32_msg(KERN_ERR, "Unable to allocate IRQ for NSP32 "
+			  "SCSI PCI controller. Interrupt: %d\n", host->irq);
+		goto free_sg_list;
+	}
+
+        /*
+         * PCI IO register
+         */
+	if(!request_region(host->io_port, host->n_io_port, "nsp32")) {
+		nsp32_msg(KERN_ERR, 
+			  "I/O region 0x%lx+0x%lx is already used",
+			  data->BaseAddress, data->length);
+		goto free_irq;
+        }
+
+	return 1;
+
+ free_irq:
+	free_irq(host->irq, data);
+
+ free_autoparam:
+	pci_free_consistent(data->Pci, AUTOPARAM_SIZE, data->autoparam, data->apaddr);
+	
+ free_sg_list:
+	pci_free_consistent(data->Pci,
+		(sizeof(struct nsp32_sgtable) * NSP_SG_SIZE * MAX_TARGET * MAX_LUN),
+		data->sg_list, data->sgaddr);
+	
+ kfree_lunt:
+	kfree(data->lunt_list);
+
+ scsi_unregister:
+	scsi_unregister(host);
+
+ err:
+	return 0;
+}
+
+static int nsp32_release(struct Scsi_Host *shpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)shpnt->hostdata;
+
+	if (data->lunt_list) {
+		kfree(data->lunt_list);
+	}
+
+	if (data->autoparam) {
+		pci_free_consistent(data->Pci, AUTOPARAM_SIZE,
+					data->autoparam, data->apaddr);
+	}
+
+	if (data->sg_list) {
+		pci_free_consistent(data->Pci, 
+			(sizeof(struct nsp32_sgtable) * NSP_SG_SIZE * MAX_TARGET * MAX_LUN),
+			data->sg_list, data->sgaddr);
+	}
+
+	DEBUG(0, "free irq\n");
+	if (shpnt->irq) {
+		free_irq(shpnt->irq, data);
+	}
+
+	DEBUG(0, "free io\n");
+	if (shpnt->io_port && shpnt->n_io_port) {
+		release_region(shpnt->io_port, shpnt->n_io_port);
+	}
+
+	if (data->MmioAddress != 0) {
+		iounmap((void *)(data->MmioAddress));
+	}
+
+	return 0;
+}
+
+static const char *nsp32_info(struct Scsi_Host *shpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)shpnt->hostdata;
+
+	return data->info_str;
+}
+
+
+/*
+ * error handler
+ */
+static int nsp32_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+{
+	nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%p why=%d\n", SCpnt, reset_flags);
+
+	nsp32_eh_bus_reset(SCpnt);
+
+	return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+}
+
+static int nsp32_eh_abort(Scsi_Cmnd *SCpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->host->hostdata;
+	unsigned int base = data->BaseAddress;
+
+	nsp32_msg(KERN_WARNING, "abort");
+
+	if (data->curlunt->SCpnt == NULL) {
+		return (FAILED);
+	}
+
+	if (data->curtarget->sync_flag & (SDTR_INITIATOR | SDTR_TARGET)) {
+		/* reset SDTR negotiation */
+		data->curtarget->sync_flag = 0;
+	}
+
+	nsp32_write2(base, TRANSFER_CONTROL, 0);
+	nsp32_write2(base, BM_CNT, 0);
+
+	return (FAILED);
+}
+
+static int nsp32_eh_bus_reset(Scsi_Cmnd *SCpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->host->hostdata;
+	unsigned int base = data->BaseAddress;
+
+	nsp32_msg(KERN_INFO, "Bus Reset");	
+	nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%x", SCpnt);
+
+	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
+	nsp32_do_bus_reset(data);
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+	return SUCCESS;	/* SCSI bus reset is succeeded at any time. */
+}
+
+static void nsp32_do_bus_reset(nsp32_hw_data *data)
+{
+	unsigned int base = data->BaseAddress;
+	unsigned short intrdat;
+	int i;
+
+	/*
+	 * stop all transfer
+	 * clear TRANSFERCONTROL_BM_START
+	 * clear counter
+	 */
+	nsp32_write2(base, TRANSFER_CONTROL, 0);
+	nsp32_write4(base, BM_CNT,           0);
+	nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK);
+
+	/*
+	 * fall back to asynchronous transfer mode
+	 * initialize SDTR negotiation flag
+	 */
+	for (i=0; i<MAX_TARGET; i++) {
+		struct nsp32_target *target = &data->target[i];
+
+		target->sync_flag = 0;
+		nsp32_set_async(data, target);
+	}
+
+	/*
+	 * reset SCSI bus
+	 */
+	nsp32_write1(base, SCSI_BUS_CONTROL, BUSCTL_RST);
+	udelay(RESET_HOLD_TIME);
+	nsp32_write1(base, SCSI_BUS_CONTROL, 0);
+	for(i = 0; i < 5; i++) {
+		intrdat = nsp32_read2(base, IRQ_STATUS); /* dummy read */
+		nsp32_dbg(NSP32_DEBUG_BUSRESET, "irq:1: 0x%x", intrdat);
+        }
+
+	data->CurrentSC = NULL;
+}
+
+static int nsp32_eh_host_reset(Scsi_Cmnd *SCpnt)
+{
+	struct Scsi_Host *host = SCpnt->host;
+	nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata;
+	unsigned int base = data->BaseAddress;
+
+	nsp32_msg(KERN_INFO, "Host Reset");	
+	nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%x", SCpnt);
+
+	nsp32hw_init(host);
+	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
+	nsp32_do_bus_reset(data);
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+	return SUCCESS;	/* Host reset is succeeded at any time. */
+}
+
+/*
+ * PCI/Cardbus probe/remove routine
+ */
+static int __devinit nsp32_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	int ret;
+	nsp32_hw_data *data = &nsp32_data_base;
+
+	nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
+
+        ret = pci_enable_device(pdev);
+	if (ret) {
+		nsp32_msg(KERN_ERR, "failed to enable pci device");
+		return ret;
+	}
+
+	data->Pci = pdev;
+	data->pci_devid = id;
+	data->IrqNumber = pdev->irq;
+	data->BaseAddress = pci_resource_start(pdev, 0);
+	data->NumAddress = pci_resource_len(pdev, 0);
+	data->MmioAddress = (unsigned long)ioremap_nocache(
+		pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
+
+	pci_set_master(pdev);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2))
+	scsi_register_host(&driver_template);
+#else
+	scsi_register_module(MODULE_SCSI_HA, &driver_template);
+#endif
+
+	nsp32_msg(KERN_INFO, "nsp32 irq: %i mmio: 0x%lx slot: %s model: %s",
+		  pdev->irq, data->MmioAddress, pdev->slot_name,
+		  nsp32_model[id->driver_data]);
+
+	nsp32_dbg(NSP32_DEBUG_REGISTER, "exit");
+
+	return 0;
+}
+
+static void __devexit nsp32_remove(struct pci_dev *pdev)
+{
+	nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
+	
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2))
+	scsi_unregister_host(&driver_template);
+#else
+	scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+#endif
+}
+
+static struct pci_device_id nsp32_pci_table[] __devinitdata = {
+	{
+		vendor:      PCI_VENDOR_ID_IODATA,
+		device:      PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_IODATA,
+	},
+	{
+		vendor:      PCI_VENDOR_ID_WORKBIT,
+		device:      PCI_DEVICE_ID_NINJASCSI_32BI_KME,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_KME,
+	},
+	{
+		vendor:      PCI_VENDOR_ID_WORKBIT,
+		device:      PCI_DEVICE_ID_NINJASCSI_32BI_WBT,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_WORKBIT,
+	},
+	{
+		vendor:      PCI_VENDOR_ID_WORKBIT,
+		device:      PCI_DEVICE_ID_WORKBIT_STANDARD,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_PCI_WORKBIT,
+	},
+	{
+		vendor:      PCI_VENDOR_ID_WORKBIT,
+		device:      PCI_DEVICE_ID_NINJASCSI_32BI_LOGITEC,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_EXT_ROM,
+	},
+	{
+		vendor:      PCI_VENDOR_ID_WORKBIT,
+		device:      PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_PCI_LOGITEC,
+	},
+	{
+		vendor:      PCI_VENDOR_ID_WORKBIT,
+		device:      PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO,
+		subvendor:   PCI_ANY_ID,
+		subdevice:   PCI_ANY_ID,
+		driver_data: MODEL_PCI_MELCO,
+	},
+	{0,0,},
+};
+MODULE_DEVICE_TABLE(pci, nsp32_pci_table);
+
+static struct pci_driver nsp32_driver = {
+	.name =		"nsp32",
+	.id_table =	nsp32_pci_table,
+	.probe =	nsp32_probe,
+	.remove =	nsp32_remove,
+#ifdef CONFIG_PM
+/*	.suspend =	nsp32_suspend,*/
+/*	.resume =	nsp32_resume,*/
+#endif
+};
+
+static int __init init_nsp32(void) {
+	return pci_module_init(&nsp32_driver);
+}
+
+static void __exit exit_nsp32(void) {
+	pci_unregister_driver(&nsp32_driver);
+}
+
+module_init(init_nsp32);
+module_exit(exit_nsp32);
+
+
+/*
+ * Reset parameters and call scsi_done for data->curlunt.
+ * Be careful setting SCpnt->result = DID_* before calling this function.
+ */
+static void nsp32_scsi_done(nsp32_hw_data *data, Scsi_Cmnd *SCpnt)
+{
+	unsigned int base = data->BaseAddress;
+
+	/*
+	 * unmap pci
+	 */
+	if (SCpnt->request_bufflen == 0) {
+		goto skip;
+	}
+
+	if (SCpnt->use_sg) {
+		pci_unmap_sg(data->Pci,
+			(struct scatterlist *)SCpnt->buffer,
+			SCpnt->use_sg,
+			scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+	} else {
+		pci_unmap_single(data->Pci,
+			(u32)SCpnt->SCp.have_data_in,
+			SCpnt->request_bufflen,
+			scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+	}
+
+ skip:
+	/*
+	 * clear TRANSFERCONTROL_BM_START
+	 */
+	nsp32_write2(base, TRANSFER_CONTROL, 0);
+	nsp32_write4(base, BM_CNT, 0);
+
+	/*
+	 * call scsi_done
+	 */
+	(*SCpnt->scsi_done)(SCpnt);
+
+	/*
+	 * reset parameters
+	 */
+	data->curlunt->SCpnt = NULL;
+	data->curlunt = NULL;
+	data->curtarget = NULL;
+	data->CurrentSC = NULL;
+}
+
+
+/*
+ * Bus Free Occur
+ *
+ * Current Phase is BUSFREE. AutoSCSI is automatically execute BUSFREE phase
+ * with ACK reply when below condition is matched:
+ *	MsgIn 00: Command Complete.
+ *	MsgIn 02: Save Data Pointer.
+ *	MsgIn 04: Diconnect.
+ * In other case, unexpected BUSFREE is detected.
+ */
+static int nsp32_busfree_occur(nsp32_hw_data *data, unsigned short execph)
+{
+	Scsi_Cmnd *SCpnt = data->curlunt->SCpnt;
+	unsigned int base = data->BaseAddress;
+
+	nsp32_dbg(NSP32_DEBUG_BUSFREE, "enter");
+
+	nsp32_write4(base, BM_CNT, 0);
+	nsp32_write2(base, TRANSFER_CONTROL, 0);
+
+	/*
+	 * MsgIn 02: Save Data Pointer
+	 *
+	 * VALID:
+	 *   Save Data Pointer is received. Adjust pointer.
+	 *   
+	 * NO-VALID:
+	 *   SCSI-3 says if Save Data Pointer is not received, then we restart
+	 *   processing and we can't adjust any SCSI data pointer in next data
+	 *   phase.
+	 */
+	if (execph & MSGIN_02_VALID) {
+		nsp32_dbg(NSP32_DEBUG_BUSFREE, "MsgIn02_Valid");
+
+		/*
+		 * Check sack_cnt/saved_sack_cnt, then adjust sg table if
+		 * needed.
+		 */
+		if (!(execph & MSGIN_00_VALID) && 
+		    ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE))) {
+			unsigned int sacklen, s_sacklen;
+
+			/*
+			 * Read SACK count and SAVEDSACK count, then compare.
+			 */
+			sacklen   = nsp32_read4(base, SACK_CNT);
+			s_sacklen = nsp32_read4(base, SAVED_SACK_CNT);
+
+			/*
+			 * If SAVEDSACKCNT == 0, it means SavedDataPointer is
+			 * come after data transfering.
+			 */
+			if (s_sacklen > 0) {
+				/*
+				 * Comparing between sack and savedsack to
+				 * check the condition of AutoMsgIn03.
+				 *
+				 * If they are same, set msgin03 == TRUE,
+				 * COMMANDCONTROL_AUTO_MSGIN_03 is enabled at
+				 * reselection.  On the other hand, if they
+				 * aren't same, set msgin03 == FALSE, and
+				 * COMMANDCONTROL_AUTO_MSGIN_03 is disabled at
+				 * reselection.
+				 */
+				if (sacklen != s_sacklen) {
+					data->curlunt->msgin03 = FALSE;
+				} else {
+					data->curlunt->msgin03 = TRUE;
+				}
+
+				nsp32_adjust_busfree(data, s_sacklen);
+			}
+		}
+
+		/* This value has not substitude with valid value yet... */
+		//data->curlunt->save_datp = data->cur_datp;
+	} else {
+		/*
+		 * no processing.
+		 */
+	}
+	
+	if (execph & MSGIN_03_VALID) {
+		/* MsgIn03 was valid to be processed. No need processing. */
+	}
+
+	/*
+	 * target SDTR check
+	 */
+	if (data->curtarget->sync_flag & SDTR_INITIATOR) {
+		/*
+		 * SDTR negotiation pulled by the initiator has not
+		 * finished yet. Fall back to ASYNC mode.
+		 */
+		nsp32_set_async(data, data->curtarget);
+		data->curtarget->sync_flag &= ~SDTR_INITIATOR;
+		data->curtarget->sync_flag |= SDTR_DONE;
+	} else if (data->curtarget->sync_flag & SDTR_TARGET) {
+		/*
+		 * SDTR negotiation pulled by the target has been
+		 * negotiating.
+		 */
+		if (execph & (MSGIN_00_VALID | MSGIN_04_VALID)) {
+			/* 
+			 * If valid message is received, then
+			 * negotiation is succeeded.
+			 */
+		} else {
+			/*
+			 * On the contrary, if unexpected bus free is
+			 * occured, then negotiation is failed. Fall
+			 * back to ASYNC mode.
+			 */
+			nsp32_set_async(data, data->curtarget);
+		}
+		data->curtarget->sync_flag &= ~SDTR_TARGET;
+		data->curtarget->sync_flag |= SDTR_DONE;
+	}
+	
+	/*
+	 * It is always ensured by SCSI standard that initiator
+	 * switches into Bus Free Phase after
+	 * receiving message 00 (Command Complete), 04 (Disconnect).
+	 * It's the reason that processing here is valid.
+	 */
+	if (execph & MSGIN_00_VALID) {
+		/* MsgIn 00: Command Complete */
+		nsp32_dbg(NSP32_DEBUG_BUSFREE, "command complete");
+
+		SCpnt->SCp.Status  = nsp32_read1(base, SCSI_CSB_IN);
+		SCpnt->SCp.Message = 0;
+		nsp32_dbg(NSP32_DEBUG_BUSFREE, 
+			  "normal end stat=0x%x resid=0x%x\n",
+			  SCpnt->SCp.Status, SCpnt->resid);
+		SCpnt->result = 
+			(DID_OK << 16) | (SCpnt->SCp.Message << 8) | (SCpnt->SCp.Status << 0);
+		nsp32_scsi_done(data, SCpnt);
+		/* All operation is done */
+		return (TRUE);
+	} else if (execph & MSGIN_04_VALID) {
+		/* MsgIn 04: Disconnect */
+		SCpnt->SCp.Status  = nsp32_read1(base, SCSI_CSB_IN);
+		SCpnt->SCp.Message = 4;
+		
+		nsp32_dbg(NSP32_DEBUG_BUSFREE, "disconnect");
+		return (TRUE);
+	} else {
+		/* Unexpected bus free */
+		nsp32_msg(KERN_WARNING, "unexpected bus free occured");
+
+		/* DID_ERROR? */
+		//SCpnt->result   = (DID_OK << 16) | (SCpnt->SCp.Message << 8) | (SCpnt->SCp.Status << 0);
+		SCpnt->result = DID_ERROR << 16;
+		nsp32_scsi_done(data, SCpnt);
+		return (TRUE);
+	}
+	return (FALSE);
+}
+
+
+/*
+ * nsp32_adjust_busfree - adjusting SG table
+ *
+ * Note: This driver adjust the SG table using SCSI ACK
+ *       counter instead of BMCNT counter!
+ */
+static void nsp32_adjust_busfree(nsp32_hw_data *data, unsigned int s_sacklen)
+{
+	int old_entry = data->cur_entry;
+	int new_entry;
+	struct nsp32_sgtable *sgt = data->curlunt->sglun->sgt;
+	unsigned int restlen, sentlen;
+	int sg_num = data->curlunt->sg_num;
+
+	/* adjust saved SACK count with 4 byte start address boundary */
+	s_sacklen -= sgt[old_entry].addr & 3;
+
+	/*
+	 * calculate new_entry from sack count and each sgt[].len 
+	 * calculate the byte which is intent to send
+	 */
+	sentlen = 0;
+	for (new_entry = old_entry; new_entry < sg_num; new_entry++) {
+		sentlen += (sgt[new_entry].len & ~NSP32_SG_END_SGT);
+		if (sentlen > s_sacklen) {
+			break;
+		}
+	}
+
+	/* all sgt is processed */
+	if (new_entry == sg_num) {
+		goto last;
+	}
+
+	if (sentlen == s_sacklen) {
+		/* XXX: confirm it's ok or not */
+		/* In this case, it's ok because we are at 
+		   the head element of the sg. restlen is correctly calculated. */
+	}
+
+	/* calculate the rest length for transfering */
+	restlen = sentlen - s_sacklen;
+	
+	/* update adjusting current SG table entry */
+	sgt[new_entry].addr += (sgt[new_entry].len - restlen);
+	sgt[new_entry].len = restlen;
+
+	/* set cur_entry with new_entry */
+	data->cur_entry = new_entry;
+	
+	return;
+
+ last:
+	/* update hostdata and lun */
+
+	return;
+}
+
+
+/*
+ * It's called MsgOut phase occur.
+ * NinjaSCSI-32Bi/UDE automatically processes up to 3 messages in
+ * message out phase. It, however, has more than 3 messages,
+ * HBA creates the interrupt and we have to process by hand.
+ */
+static void nsp32_msgout_occur(nsp32_hw_data *data)
+{
+	unsigned int base = data->BaseAddress;
+	//unsigned short command;
+	long new_sgtp;
+	int i;
+	
+	nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR,
+		  "enter: msgoutlen: 0x%x", data->msgoutlen);
+
+	/*
+	 * If MsgOut phase is occured without having any
+	 * message, then No_Operation is sent (SCSI-2).
+	 */
+	if (data->msgoutlen == 0) {
+		nsp32_build_nop(data);
+	}
+
+	/*
+	 * Set SGTP ADDR current entry for restarting AUTOSCSI, 
+	 * because SGTP is incremented next point.
+	 * There is few statement in the specification...
+	 */
+ 	new_sgtp = data->curlunt->sglun_paddr
+		+ data->curlunt->cur_entry * sizeof(struct nsp32_sgtable);
+
+	/*
+	 * send messages
+	 */
+	for (i=0; i<data->msgoutlen; i++) {
+		nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR,
+			  "%d : 0x%x", i, data->msgoutbuf[i]);
+
+		/*
+		 * Check REQ is asserted.
+		 */
+		nsp32_wait_req(data, ASSERT);
+
+		if (i == (data->msgoutlen - 1)) {
+			/*
+			 * If the last message, set the AutoSCSI restart
+			 * before send back the ack message. AutoSCSI
+			 * restart automatically negate ATN signal.
+			 */
+			//command = (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02);
+			//nsp32_restart_autoscsi(data, command);
+			nsp32_write2(base, COMMAND_CONTROL,
+					 (CLEAR_CDB_FIFO_POINTER |
+					  AUTO_COMMAND_PHASE |
+					  AUTOSCSI_RESTART |
+					  AUTO_MSGIN_00_OR_04 |
+					  AUTO_MSGIN_02 ));
+		}
+		/*
+		 * Write data with SACK, then wait sack is
+		 * automatically negated.
+		 */
+		nsp32_write1(base, SCSI_DATA_WITH_ACK, data->msgoutbuf[i]);
+		nsp32_wait_sack(data, NEGATE);
+
+		nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "bus: 0x%x\n",
+			  nsp32_read1(base, SCSI_BUS_MONITOR));
+	};
+
+	data->msgoutlen = 0;
+
+	nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "exit");
+}
+
+/*
+ * Restart AutoSCSI
+ *
+ * Note: Restarting AutoSCSI needs set:
+ *		SYNC_REG, ACK_WIDTH, SGT_ADR, TRANSFER_CONTROL
+ */
+static void nsp32_restart_autoscsi(nsp32_hw_data *data, unsigned short command)
+{
+	unsigned int base = data->BaseAddress;
+	unsigned short transfer = 0;
+	Scsi_Cmnd *SCpnt = data->curlunt->SCpnt;
+
+	nsp32_dbg(NSP32_DEBUG_RESTART, "enter");
+
+	if (data->curtarget == NULL || data->curlunt == NULL) {
+		nsp32_msg(KERN_ERR, "Target or Lun is invalid");
+	}
+
+	/*
+	 * set SYNC_REG
+	 * Don't set BM_START_ADR before setting this register.
+	 */
+	nsp32_write1(base, SYNC_REG, data->curtarget->syncreg);
+
+	/*
+	 * set ACKWIDTH
+	 */
+	nsp32_write1(base, ACK_WIDTH, data->curtarget->ackwidth);
+
+	/*
+	 * set SGT ADDR (physical address)
+	 */
+	nsp32_write4(base, SGT_ADR, data->curlunt->sglun_paddr);
+
+	/*
+	 * set TRANSFER CONTROL REG
+	 */
+	transfer = 0;
+	transfer |= (TRANSFER_GO | ALL_COUNTER_CLR);
+	if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
+		if (SCpnt->request_bufflen > 0) {
+			transfer |= BM_START;
+		}
+	} else if (data->trans_method & NSP32_TRANSFER_MMIO) {
+		transfer |= CB_MMIO_MODE;
+	} else if (data->trans_method & NSP32_TRANSFER_PIO) {
+		transfer |= CB_IO_MODE;
+	}
+	nsp32_write2(base, TRANSFER_CONTROL, transfer);
+
+	/*
+	 * restart AutoSCSI
+	 *
+	 * TODO: COMMANDCONTROL_AUTO_COMMAND_PHASE is needed ?
+	 */
+	command |= (CLEAR_CDB_FIFO_POINTER |
+		    AUTO_COMMAND_PHASE |
+		    AUTOSCSI_RESTART);
+	nsp32_write2(base, COMMAND_CONTROL, command);
+
+	nsp32_dbg(NSP32_DEBUG_RESTART, "exit");
+}
+
+
+/*
+ * cannot run automatically message in occur
+ */
+static void nsp32_msgin_occur(nsp32_hw_data *data, unsigned long irq_status,
+			unsigned short execph)
+{
+	unsigned int base = data->BaseAddress;
+	unsigned char msg;
+	unsigned char msgtype;
+	unsigned char newlun;
+	unsigned short command = 0;
+	int msgclear = TRUE;
+	long new_sgtp;
+	int ret;
+
+	/*
+	 * read first message
+	 *    Use SCSIDATA_W_ACK instead of SCSIDATAIN, because the procedure
+	 *    of Message-In have to be processed before sending back SCSI ACK.
+	 */
+	msg = nsp32_read1(base, SCSI_DATA_IN);
+	data->msginbuf[(unsigned char)data->msginlen] = msg;
+	msgtype = data->msginbuf[0];
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR,
+		  "enter: msglen: 0x%x msgin: 0x%x msgtype: 0x%x",
+		  data->msginlen, msg, msgtype);
+
+	/*
+	 * TODO: We need checking whether bus phase is message in?
+	 */
+
+	/*
+	 * assert SCSI ACK
+	 */
+	nsp32_sack_assert(data);
+
+	/*
+	 * processing IDENTIFY
+	 */
+	if (msgtype & 0x80) {
+		if (!(irq_status & IRQSTATUS_RESELECT_OCCUER)) {
+			/* Invalid (non reselect) phase */
+			goto reject;
+		}
+
+		newlun = msgtype & 0x1f; /* TODO: SPI-3 compliant? */
+		ret = nsp32_reselection(data, newlun);
+		if (ret == TRUE) {
+			goto restart;
+		} else {
+			goto reject;
+		}
+	}
+	
+	/*
+	 * processing messages except for IDENTIFY
+	 *
+	 * TODO: Messages are all SCSI-2 terminology. SCSI-3 compliance is TODO.
+	 */
+	switch (msgtype) {
+	/*
+	 * 1-byte message
+	 */
+	case COMMAND_COMPLETE:
+	case DISCONNECT:
+		/*
+		 * These messages should not be occured.
+		 * They should be processed on AutoSCSI sequencer.
+		 */
+		nsp32_msg(KERN_WARNING, 
+			   "unexpected message of AutoSCSI MsgIn: 0x%x", msg);
+		break;
+		
+	case RESTORE_POINTERS:
+		/*
+		 * AutoMsgIn03 is disabled, and HBA gets this message.
+		 */
+
+		if ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE)) {
+			unsigned int s_sacklen;
+
+			s_sacklen = nsp32_read4(base, SAVED_SACK_CNT);
+			if ((execph & MSGIN_02_VALID) && (s_sacklen > 0)) {
+				nsp32_adjust_busfree(data, s_sacklen);
+			} else {
+				/* No need to rewrite SGT */
+			}
+		}
+		data->curlunt->msgin03 = FALSE;
+
+		/* Update with the new value */
+
+		/* reset SACK/SavedACK counter (or ALL clear?) */
+		nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK);
+
+		/*
+		 * set new sg pointer
+		 */
+		new_sgtp = data->curlunt->sglun_paddr + 
+			data->curlunt->cur_entry * sizeof(struct nsp32_sgtable);
+		nsp32_write4(base, SGT_ADR, new_sgtp);
+
+		break;
+
+	case SAVE_POINTERS:
+		/*
+		 * These messages should not be occured.
+		 * They should be processed on AutoSCSI sequencer.
+		 */
+		nsp32_msg (KERN_WARNING, 
+			   "unexpected message of AutoSCSI MsgIn: SAVE_POINTERS");
+		
+		break;
+		
+	case MESSAGE_REJECT:
+		/* If previous message_out is sending SDTR, and get 
+		   message_reject from target, SDTR negotiation is failed */
+		if (data->curtarget->sync_flag &
+				(SDTR_INITIATOR | SDTR_TARGET)) {
+			/*
+			 * Current target is negotiating SDTR, but it's
+			 * failed.  Fall back to async transfer mode, and set
+			 * SDTR_DONE.
+			 */
+			nsp32_set_async(data, data->curtarget);
+			data->curtarget->sync_flag &= ~SDTR_INITIATOR;
+			data->curtarget->sync_flag |= SDTR_DONE;
+
+		}
+		break;
+
+	case LINKED_CMD_COMPLETE:
+	case LINKED_FLG_CMD_COMPLETE:
+		/* queue tag is not supported currently */
+		nsp32_msg (KERN_WARNING, 
+			   "unsupported message: 0x%x", msgtype);
+		break;
+
+	case INITIATE_RECOVERY:
+		/* staring ECA (Extended Contingent Allegiance) state. */
+		/* This message is declined in SPI2 or later. */
+
+		goto reject;
+
+	/*
+	 * 2-byte message
+	 */
+	case SIMPLE_QUEUE_TAG:
+	case 0x23:
+		/*
+		 * 0x23: Ignore_Wide_Residue is not declared in scsi.h.
+		 * No support is needed.
+		 */
+		if (data->msginlen >= 1) {
+			goto reject;
+		}
+
+		/* current position is 1-byte of 2 byte */
+		msgclear = FALSE;
+
+		break;
+
+	/*
+	 * extended message
+	 */
+	case EXTENDED_MESSAGE:
+		if (data->msginlen < 1) {
+			/*
+			 * Current position does not reach 2-byte
+			 * (2-byte is extended message length).
+			 */
+			msgclear = FALSE;
+			break;
+		}
+
+		if ((data->msginbuf[1] + 1) > data->msginlen) {
+			/*
+			 * Current extended message has msginbuf[1] + 2
+			 * (msginlen starts counting from 0, so buf[1] + 1).
+			 * If current message position is not finished,
+			 * continue receiving message.
+			 */
+			msgclear = FALSE;
+			break;
+		}
+
+		/*
+		 * Reach here means regular length of each type of 
+		 * extended messages.
+		 */
+		switch (data->msginbuf[2]) {
+		case EXTENDED_MODIFY_DATA_POINTER:
+			/* TODO */
+			goto reject; /* not implemented yet */
+			break;
+
+		case EXTENDED_SDTR:
+			/*
+			 * Exchange this message between initiator and target.
+			 */
+			if (data->msginlen != EXTENDED_SDTR_LEN + 1) {
+				/*
+				 * received inappropriate message.
+				 */
+				goto reject;
+				break;
+			}
+
+			nsp32_analyze_sdtr(data);
+
+			break;
+
+		case EXTENDED_EXTENDED_IDENTIFY:
+			/* SCSI-I only, not supported. */
+			goto reject; /* not implemented yet */
+
+			break;
+
+		case EXTENDED_WDTR:
+			goto reject; /* not implemented yet */
+
+			break;
+			
+		default:
+			goto reject;
+		}
+		break;
+		
+	default:
+		goto reject;
+	}
+
+ restart:
+	if (msgclear == TRUE) {
+		data->msginlen = 0;
+
+		/*
+		 * If restarting AutoSCSI, but there are some message to out
+		 * (msgoutlen > 0), set AutoATN, and set SCSIMSGOUT as 0
+		 * (MV_VALID = 0). When commandcontrol is written with
+		 * AutoSCSI restart, at the same time MsgOutOccur should be
+		 * happened (however, such situation is really possible...?).
+		 */
+		if (data->msgoutlen > 0) {	
+			nsp32_write4(base, SCSI_MSG_OUT, 0);
+			command |= AUTO_ATN;
+		}
+
+		/*
+		 * restart AutoSCSI
+		 * If it's failed, COMMANDCONTROL_AUTO_COMMAND_PHASE is needed.
+		 */
+		command |= (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02);
+
+		/*
+		 * If current msgin03 is TRUE, then flag on.
+		 */
+		if (data->curlunt->msgin03 == TRUE) {
+			command |= AUTO_MSGIN_03;
+		}
+		data->curlunt->msgin03 = FALSE;
+	} else {
+		data->msginlen++;
+	}
+
+	/*
+	 * restart AutoSCSI
+	 */
+	nsp32_restart_autoscsi(data, command);
+
+	/*
+	 * wait SCSI REQ negate for REQ-ACK handshake
+	 */
+	nsp32_wait_req(data, NEGATE);
+
+	/*
+	 * negate SCSI ACK
+	 */
+	nsp32_sack_negate(data);
+
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit");
+
+	return;
+
+ reject:
+	nsp32_msg(KERN_WARNING, 
+		  "invalid or unsupported MessageIn, rejected. "
+		  "current msg: 0x%x (len: 0x%x), processing msg: 0x%x",
+		  msg, data->msginlen, msgtype);
+	nsp32_build_reject(data);
+	data->msginlen = 0;
+
+	goto restart;
+}
+
+/*
+ * 
+ */
+static void nsp32_analyze_sdtr(nsp32_hw_data *data)
+{
+	struct nsp32_target *target = data->curtarget;
+	struct nsp32_sync_table *synct;
+	unsigned char get_period = data->msginbuf[3];
+	unsigned char get_offset = data->msginbuf[4];
+	int entry;
+	int syncnum;
+
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "enter");
+
+	synct = data->synct;
+	syncnum = data->syncnum;
+
+	/*
+	 * If this inititor sent the SDTR message, then target responds SDTR,
+	 * initiator SYNCREG, ACKWIDTH from SDTR parameter.
+	 * Messages are not appropriate, then send back reject message.
+	 * If initiator did not send the SDTR, but target sends SDTR, 
+	 * initiator calculator the appropriate parameter and send back SDTR.
+	 */	
+	if (target->sync_flag & SDTR_INITIATOR) {
+		/*
+		 * Initiator sent SDTR, the target responds and
+		 * send back negotiation SDTR.
+		 */
+		nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target responds SDTR");
+	
+		target->sync_flag &= ~SDTR_INITIATOR;
+		target->sync_flag |= SDTR_DONE;
+
+		/*
+		 * offset:
+		 */
+		if (get_offset > SYNC_OFFSET) {
+			/*
+			 * Negotiation is failed, the target send back
+			 * unexpected offset value.
+			 */
+			goto reject;
+		}
+		
+		if (get_offset == ASYNC_OFFSET) {
+			/*
+			 * Negotiation is succeeded, the target want
+			 * to fall back into asynchronous transfer mode.
+			 */
+			goto async;
+		}
+
+		/*
+		 * period:
+		 *    Check whether sync period is too short. If too short,
+		 *    fall back to async mode. If it's ok, then investigate
+		 *    the received sync period. If sync period is acceptable
+		 *    between sync table start_period and end_period, then
+		 *    set this I_T nexus as sent offset and period.
+		 *    If it's not acceptable, send back reject and fall back
+		 *    to async mode.
+		 */
+		if (get_period < data->synct[0].period_num) {
+			/*
+			 * Negotiation is failed, the target send back
+			 * unexpected period value.
+			 */
+			goto reject;
+		}
+
+		entry = nsp32_search_period_entry(data, target, get_period);
+
+		if (entry < 0) {
+			/*
+			 * Target want to use long period which is not 
+			 * acceptable NinjaSCSI-32Bi/UDE.
+			 */
+			goto reject;
+		}
+
+		/*
+		 * Set new sync table and offset in this I_T nexus.
+		 */
+		nsp32_set_sync_entry(data, target, entry, get_offset);
+	} else {
+		/* Target send SDTR to initiator. */
+		nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target send SDTR");
+	
+		target->sync_flag |= SDTR_INITIATOR;
+
+		/* offset: */
+		if (get_offset > SYNC_OFFSET) {
+			/* send back as SYNC_OFFSET */
+			get_offset = SYNC_OFFSET;
+		}
+
+		/* period: */
+		if (get_period < data->synct[0].period_num) {
+			get_period = data->synct[0].period_num;
+		}
+
+		entry = nsp32_search_period_entry(data, target, get_period);
+
+		if (get_offset == ASYNC_OFFSET || entry < 0) {
+			nsp32_set_async(data, target);
+			nsp32_build_sdtr(data, 0, ASYNC_OFFSET);
+		} else {
+			nsp32_set_sync_entry(data, target, entry, get_offset);
+			nsp32_build_sdtr(data, get_period, get_offset);
+		}
+	}
+	
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit");
+	return;
+
+ reject:
+	/*
+	 * If the current message is unacceptable, send back to the target
+	 * with reject message.
+	 */
+	nsp32_build_reject(data);
+
+ async:
+	nsp32_set_async(data, target);	/* set as ASYNC transfer mode */
+
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit: set async");
+	return;
+}
+
+
+/*
+ * Search config entry number matched in sync_table from given
+ * target and speed period value. If failed to search, return negative value.
+ */
+static int nsp32_search_period_entry(nsp32_hw_data *data,
+			      struct nsp32_target *target,
+			      unsigned char period)
+{
+	int i;
+
+	if (target->limit_entry >= data->syncnum) {
+		nsp32_msg(KERN_ERR, "limit_entry exceeds syncnum!");
+		target->limit_entry = 0;
+	}
+
+	for (i=target->limit_entry; i<data->syncnum; i++) {
+		if (period >= data->synct[i].start_period &&
+		    period <= data->synct[i].end_period) {
+				break;
+		}
+	}
+
+	/*
+	 * Check given period value is over the sync_table value.
+	 * If so, return max value.
+	 */
+	if (i == data->syncnum) {
+		i = -1;
+	}
+
+	return i;
+}
+
+
+/*
+ * target <-> initiator use ASYNC transfer
+ */
+static void nsp32_set_async(nsp32_hw_data *data, struct nsp32_target *target)
+{
+	unsigned char period = data->synct[target->limit_entry].period_num;
+
+	target->offset   = ASYNC_OFFSET;
+	target->syncreg  = TO_SYNCREG(period, ASYNC_OFFSET);
+	target->ackwidth = 0;
+
+	nsp32_dbg(NSP32_DEBUG_SYNC, "set async");
+}
+
+
+/*
+ * target <-> initiator use maximum SYNC transfer
+ */
+static void nsp32_set_max_sync(nsp32_hw_data *data,
+			       struct nsp32_target *target,
+			       unsigned char *period, unsigned char *offset)
+{
+	unsigned char period_num, ackwidth;
+
+	period_num = data->synct[target->limit_entry].period_num;
+	*period    = data->synct[target->limit_entry].start_period;
+	ackwidth   = data->synct[target->limit_entry].ackwidth;
+	*offset    = SYNC_OFFSET;
+
+	target->syncreg  = TO_SYNCREG(period_num, *offset);
+	target->ackwidth = ackwidth;
+	target->offset   = *offset;
+}
+
+
+/*
+ * target <-> initiator use entry number speed
+ */
+static void nsp32_set_sync_entry(nsp32_hw_data *data,
+				 struct nsp32_target *target,
+				 int entry, unsigned char offset)
+{
+	unsigned char period, ackwidth;
+
+	period   = data->synct[entry].period_num;
+	ackwidth = data->synct[entry].ackwidth;
+	offset  = offset;
+
+	target->syncreg  = TO_SYNCREG(period, offset);
+	target->ackwidth = ackwidth;
+	target->offset   = offset;
+
+	nsp32_dbg(NSP32_DEBUG_SYNC, "set sync");
+}
+
+
+/*
+ * It waits until SCSI REQ becomes assertion or negation state.
+ *
+ * Note: If nsp32_msgin_occur is called, we asserts SCSI ACK. Then
+ *     connected target responds SCSI REQ negation.  We have to wait
+ *     SCSI REQ becomes negation in order to negate SCSI ACK signal for
+ *     REQ-ACK handshake.
+ */
+static void nsp32_wait_req(nsp32_hw_data *data, int state)
+{
+	unsigned int base = data->BaseAddress;
+	int wait_time = 0;
+	unsigned char bus;
+
+	if (!((state == ASSERT) || (state == NEGATE))) {
+		nsp32_msg(KERN_ERR, "unknown state designation");
+	}
+	state <<= 5; /* REQ is BIT(5) */
+
+	do {
+		bus = nsp32_read1(base, SCSI_BUS_MONITOR);
+		if ((bus & BUSMON_REQ) == state) {
+			nsp32_dbg(NSP32_DEBUG_WAIT, 
+				  "wait_time: %d", wait_time);
+			return;
+		}
+		udelay(1);
+		wait_time++;
+	} while (wait_time < REQSACK_TIMEOUT_TIME);
+
+	nsp32_msg(KERN_WARNING, "wait REQ timeout, state: %d", state);
+}
+
+/*
+ * It waits until SCSI SACK becomes assertion or negation state.
+ */
+static void nsp32_wait_sack(nsp32_hw_data *data, int state)
+{
+	unsigned int base = data->BaseAddress;
+	int wait_time = 0;
+	unsigned char bus;
+
+	if (!((state == ASSERT) || (state == NEGATE))) {
+		nsp32_msg(KERN_ERR, "unknown state designation");
+	}
+	state <<= 4; /* ACK is BIT(4) */
+
+	do {
+		bus = nsp32_read1(base, SCSI_BUS_MONITOR);
+		if ((bus & BUSMON_ACK) == state) {
+			nsp32_dbg(NSP32_DEBUG_WAIT,
+				  "wait_time: %d", wait_time);
+			return;
+		}
+		udelay(1);
+		wait_time++;
+	} while (wait_time < REQSACK_TIMEOUT_TIME);
+
+	nsp32_msg(KERN_WARNING, "wait SACK timeout, state: %d", state);
+}
+
+/*
+ * assert SCSI ACK
+ *
+ * Note: SCSI ACK assertion needs with ACKENB=1, AUTODIRECTION=1.
+ */
+static void nsp32_sack_assert(nsp32_hw_data *data)
+{
+	unsigned char busctrl;
+	unsigned int base = data->BaseAddress;
+
+	busctrl  = nsp32_read1(base, SCSI_BUS_CONTROL);
+	busctrl	|= (BUSCTL_ACK | AUTODIRECTION | ACKENB);
+	nsp32_write1(base, SCSI_BUS_CONTROL,busctrl);
+}
+
+/*
+ * negate SCSI ACK
+ */
+static void nsp32_sack_negate(nsp32_hw_data *data)
+{
+	unsigned char busctrl;
+	unsigned int base = data->BaseAddress;
+
+	busctrl  = nsp32_read1(base, SCSI_BUS_CONTROL);
+	busctrl	&= ~BUSCTL_ACK;
+	nsp32_write1(base, SCSI_BUS_CONTROL, busctrl);
+}
+
+
+
+/*
+ * getting EEPROM parameter
+ */
+static int nsp32_getprom_param(nsp32_hw_data *data)
+{
+	int vendor = data->pci_devid->vendor;
+	int device = data->pci_devid->device;
+	int ret, val, i;
+
+	/*
+	 * EEPROM checking.
+	 */
+	ret = nsp32_prom_read(data, 0x7e);
+	if (ret != 0x55) {
+		nsp32_msg(KERN_INFO, "No EEPROM detected: 0x%x", ret);
+		return (FALSE);
+	}
+	ret = nsp32_prom_read(data, 0x7f);
+	if (ret != 0xaa) {
+		nsp32_msg(KERN_INFO, "Invalid number: 0x%x", ret);
+		return (FALSE);
+	}
+
+	/*
+	 * check EEPROM type
+	 */
+	if (vendor == PCI_VENDOR_ID_WORKBIT &&
+	    device == PCI_DEVICE_ID_WORKBIT_STANDARD) {
+		ret = nsp32_getprom_standard(data);
+	} else if (vendor == PCI_VENDOR_ID_WORKBIT &&
+		   device == PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC) {
+		ret = nsp32_getprom_new(data);
+	} else if (vendor == PCI_VENDOR_ID_WORKBIT &&
+		   device == PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO ) {
+		ret = nsp32_getprom_new(data);
+	} else {
+		nsp32_msg(KERN_WARNING, "Unknown EEPROM");
+		ret = FALSE;
+	}
+
+	/* for debug : SPROM data full checking */
+	for (i=0; i<=0x1f; i++) {
+		val = nsp32_prom_read(data, i);
+		nsp32_dbg(NSP32_DEBUG_EEPROM,
+			  "rom address 0x%x : 0x%x", i, val);
+	}
+
+	return (ret);
+}
+
+
+/*
+ * AT24C01A (Logitec: LHA-600S), AT24C02 (Melco Buffalo: IFC-USLP) data map:
+ *
+ *   ROMADDR
+ *   0x00 - 0x06 :  Device Synchronous Transfer Period (SCSI ID 0 - 6) 
+ *			Value 0x0: ASYNC, 0x0c: Ultra-20M, 0x19: Fast-10M
+ *   0x07        :  HBA Synchronous Transfer Period
+ *			Value 0: AutoSync, 1: Manual Setting
+ *   0x08 - 0x0f :  Not Used? (0x0)
+ *   0x10        :  Bus Termination
+ * 			Value 0: Auto[ON], 1: ON, 2: OFF
+ *   0x11        :  Not Used? (0)
+ *   0x12        :  Bus Reset Delay Time (0x03)
+ *   0x13        :  Bootable CD Support
+ *			Value 0: Disable, 1: Enable
+ *   0x14        :  Device Scan
+ *			Bit   7  6  5  4  3  2  1  0
+ *			      |  <----------------->
+ * 			      |    SCSI ID: Value 0: Skip, 1: YES
+ *			      |->  Value 0: ALL scan,  Value 1: Manual
+ *   0x15 - 0x1b :  Not Used? (0)
+ *   0x1c        :  Constant? (0x01) (clock div?)
+ *   0x1d - 0x7c :  Not Used (0xff)
+ *   0x7d	 :  Not Used? (0xff)
+ *   0x7e        :  Constant (0x55), HBA chip revision
+ *   0x7f        :  Constant (0xaa), HBA value
+ */
+static int nsp32_getprom_new(nsp32_hw_data *data)
+{
+	int ret, i;
+	int auto_sync;
+	struct nsp32_target *target;
+	int entry;
+
+	/*
+	 * Reset time which is designated by EEPROM.
+	 *
+	 * TODO: Not used yet.
+	 */
+	data->resettime = nsp32_prom_read(data, 0x12);
+
+	/*
+	 * HBA Synchronous Transfer Period
+	 *
+	 * Note: auto_sync = 0: auto, 1: manual.  Ninja SCSI HBA spec says
+	 *	that if auto_sync is 0 (auto), and connected SCSI devices are
+	 *	same or lower than 3, then transfer speed is set as ULTRA-20M.
+	 *	On the contrary if connected SCSI devices are same or higher
+	 *	than 4, then transfer speed is set as FAST-10M.
+	 *
+	 *	I break this rule. The number of connected SCSI devices are
+	 *	only ignored. If auto_sync is 0 (auto), then transfer speed is
+	 *	forced as ULTRA-20M.
+	 */
+	ret = nsp32_prom_read(data, 0x07);
+	switch (ret) {
+	case 0:
+		auto_sync = TRUE;
+		break;
+	case 1:
+		auto_sync = FALSE;
+		break;
+	default:
+		nsp32_msg(KERN_WARNING,
+			  "Unsupported Auto Sync mode."
+			  "Fall back to manual mode.");
+		auto_sync = TRUE;
+	}
+
+	if (trans_mode == ULTRA20M_MODE) {
+		auto_sync = TRUE;
+	}
+
+	/*
+	 * each device Synchronous Transfer Period
+	 */
+	for (i=0; i<NSP32_HOST_SCSIID; i++) {
+		target = &data->target[i];
+		if (auto_sync == TRUE) {
+			target->limit_entry = 0;   /* set as ULTRA20M */
+		} else {
+			ret = nsp32_prom_read(data, i);
+			entry = nsp32_search_period_entry(data, target, ret);
+			if (entry < 0) {
+				/* search failed... set maximum speed */
+				entry = 0;
+			}
+			target->limit_entry = entry;
+		}
+	}
+
+	return (TRUE);
+}
+
+
+/*
+ * ? (I-O Data: SC-NBD) data map:
+ *
+ *   ROMADDR
+ *   0x00 - 0x06 :  Device Synchronous Transfer Period (SCSI ID 0 - 6) 
+ *			Value 0x0: 20MB/S, 0x1: 10MB/S, 0x2: 5MB/S, 0x3: ASYNC
+ *   0x07        :  0 (HBA Synchronous Transfer Period: Auto Sync)
+ *   0x08 - 0x0f :  Not Used? (0x0)
+ *   0x10        :  Transfer Mode
+ *			Value 0: PIO, 1: Busmater
+ *   0x11        :  Bus Reset Delay Time (0x00-0x20)
+ *   0x12        :  Bus Termination
+ * 			Value 0: Disable, 1: Enable
+ *   0x13 - 0x19 :  Disconnection
+ *			Value 0: Disable, 1: Enable
+ *   0x1a - 0x7c :  Not Used? (0)
+ *   0x7d	 :  Not Used? (0xf8)
+ *   0x7e        :  Constant (0x55), HBA chip revision
+ *   0x7f        :  Constant (0xaa), HBA value
+ */
+static int nsp32_getprom_standard(nsp32_hw_data *data)
+{
+	int ret, i;
+	struct nsp32_target *target;
+	int entry, val;
+
+	/*
+	 * Reset time which is designated by EEPROM.
+	 *
+	 * TODO: Not used yet.
+	 */
+	data->resettime = nsp32_prom_read(data, 0x11);
+
+	/*
+	 * each device Synchronous Transfer Period
+	 */
+	for (i=0; i<NSP32_HOST_SCSIID; i++) {
+		target = &data->target[i];
+		ret = nsp32_prom_read(data, i);
+		switch (ret) {
+		case 0:		/* 20MB/s */
+			val = 0x0c;
+			break;
+		case 1:		/* 10MB/s */
+			val = 0x19;
+			break;
+		case 2:		/* 5MB/s */
+			val = 0x32;
+			break;
+		case 3:		/* ASYNC */
+			val = 0x0;
+			break;
+		default:	/* default 20MB/s */
+			val = 0x0c;
+		}
+		entry = nsp32_search_period_entry(data, target, val);
+		if (entry < 0 || trans_mode == ULTRA20M_MODE) {
+			/* search failed... set maximum speed */
+			entry = 0;
+		}
+		target->limit_entry = entry;
+	}
+
+	return (TRUE);
+}
+
+
+/*
+ * Atmel AT24C01A (drived in 5V) serial EEPROM routines
+ */
+static int nsp32_prom_read(nsp32_hw_data *data, int romaddr)
+{
+	int i, val;
+
+	/* start condition */
+	nsp32_prom_start(data);
+
+	/* device address */
+	nsp32_prom_write(data, 1);	/* 1 */
+	nsp32_prom_write(data, 0);	/* 0 */
+	nsp32_prom_write(data, 1);	/* 1 */
+	nsp32_prom_write(data, 0);	/* 0 */
+	nsp32_prom_write(data, 0);	/* A2: 0 (GND) */
+	nsp32_prom_write(data, 0);	/* A1: 0 (GND) */
+	nsp32_prom_write(data, 0);	/* A0: 0 (GND) */
+
+	/* R/W: W for dummy write */
+	nsp32_prom_write(data, 0);
+
+	/* ack */
+	nsp32_prom_write(data, 0);
+
+	/* word address */
+	for (i=7; i>=0; i--) {
+		nsp32_prom_write(data, ((romaddr >> i) & 1));
+	}
+
+	/* ack */
+	nsp32_prom_write(data, 0);
+
+	/* start condition */
+	nsp32_prom_start(data);
+
+	/* device address */
+	nsp32_prom_write(data, 1);	/* 1 */
+	nsp32_prom_write(data, 0);	/* 0 */
+	nsp32_prom_write(data, 1);	/* 1 */
+	nsp32_prom_write(data, 0);	/* 0 */
+	nsp32_prom_write(data, 0);	/* A2: 0 (GND) */
+	nsp32_prom_write(data, 0);	/* A1: 0 (GND) */
+	nsp32_prom_write(data, 0);	/* A0: 0 (GND) */
+
+	/* R/W: R */
+	nsp32_prom_write(data, 1);
+
+	/* ack */
+	nsp32_prom_write(data, 0);
+
+	/* data... */
+	val = 0;
+	for (i=7; i>=0; i--) {
+		val += (nsp32_prom_fetch(data) << i);
+	}
+	
+	/* no ack */
+	nsp32_prom_write(data, 1);
+
+	/* stop condition */
+	nsp32_prom_stop(data);
+
+	return (val);
+}
+
+static void nsp32_prom_start (nsp32_hw_data *data)
+{
+	/* start condition */
+	nsp32_prom_set(data, SCL, 1);
+	nsp32_prom_set(data, SDA, 1);
+	nsp32_prom_set(data, ENA, 1);	/* output mode */
+	nsp32_prom_set(data, SDA, 0);	/* keeping SCL=1 and transiting
+					 * SDA 1->0 is start condition */
+	nsp32_prom_set(data, SCL, 0);
+}
+
+static void nsp32_prom_stop (nsp32_hw_data *data)
+{
+	/* stop condition */
+	nsp32_prom_set(data, SCL, 1);
+	nsp32_prom_set(data, SDA, 0);
+	nsp32_prom_set(data, ENA, 1);	/* output mode */
+	nsp32_prom_set(data, SDA, 1);
+	nsp32_prom_set(data, SCL, 0);
+}
+
+static void nsp32_prom_write (nsp32_hw_data *data, int val)
+{
+	/* write */
+	nsp32_prom_set(data, SDA, val);
+	nsp32_prom_set(data, SCL, 1);
+	nsp32_prom_set(data, SCL, 0);
+}
+
+static int nsp32_prom_fetch (nsp32_hw_data *data)
+{
+	int val;
+
+	/* read */
+	nsp32_prom_set(data, ENA, 0);	/* input mode */
+	nsp32_prom_set(data, SCL, 1);
+	val = nsp32_prom_get(data, SDA);
+	nsp32_prom_set(data, SCL, 0);
+	nsp32_prom_set(data, ENA, 1);	/* output mode */
+	return (val);
+}
+
+static inline void nsp32_prom_set(nsp32_hw_data *data, int bit, int val)
+{
+	int cur;
+	int base = data->BaseAddress;
+
+	switch(val) {
+	case 0:
+		cur = nsp32_index_read1(base, SERIAL_ROM_CTL);
+		nsp32_index_write1(base, SERIAL_ROM_CTL, cur & ~bit);
+		break;
+	case 1:
+		cur = nsp32_index_read1(base, SERIAL_ROM_CTL);
+		nsp32_index_write1(base, SERIAL_ROM_CTL, cur | bit);
+		break;
+	default:
+		nsp32_msg(KERN_ERR, "val must be 0 or 1");
+		return;
+	}
+
+	udelay(10);
+}
+
+static inline int nsp32_prom_get(nsp32_hw_data *data, int bit)
+{
+	int ret;
+	int base = data->BaseAddress;
+
+	ret = nsp32_index_read1(base, SERIAL_ROM_CTL) & bit;
+	switch (ret) {
+	case 0:
+		ret = 0;
+		break;
+	case SDA:
+		ret = 1;
+		break;
+	default:
+		nsp32_msg(KERN_ERR, "return value is not appropriate");
+	}
+
+	udelay(10);
+
+	return (ret);
+}
+
+/* end */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/nsp32_debug.c linux.20pre10-ac2/drivers/scsi/nsp32_debug.c
--- linux.20pre10/drivers/scsi/nsp32_debug.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/nsp32_debug.c	2002-10-10 23:53:14.000000000 +0100
@@ -0,0 +1,262 @@
+/*
+ * Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus SCSI Host Bus Adapter driver
+ * Debug routine
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License.
+ */
+
+/*
+ * Show the command data of a command
+ */
+static const char unknown[] = "UNKNOWN";
+
+static const char * group_0_commands[] = {
+/* 00-03 */ "Test Unit Ready", "Rezero Unit", unknown, "Request Sense",
+/* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks",
+/* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown,
+/* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry",  
+/* 13-16 */ unknown, "Recover Buffered Data", "Mode Select", "Reserve",
+/* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit",
+/* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", 
+/* 1e-1f */ "Prevent/Allow Medium Removal", unknown,
+};
+
+
+static const char *group_1_commands[] = {
+/* 20-22 */  unknown, unknown, unknown,
+/* 23-28 */ unknown, unknown, "Read Capacity", unknown, unknown, "Read (10)",
+/* 29-2d */ unknown, "Write (10)", "Seek (10)", unknown, unknown,
+/* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal",
+/* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", 
+/* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data",
+/* 38-3c */ "Medium Scan", "Compare","Copy Verify", "Write Buffer", "Read Buffer",
+/* 3d-3f */ "Update Block", "Read Long",  "Write Long",
+};
+
+
+static const char *group_2_commands[] = {
+/* 40-41 */ "Change Definition", "Write Same", 
+/* 42-48 */ "Read Sub-Ch(cd)", "Read TOC", "Read Header(cd)", "Play Audio(cd)", unknown, "Play Audio MSF(cd)", "Play Audio Track/Index(cd)", 
+/* 49-4f */ "Play Track Relative(10)(cd)", unknown, "Pause/Resume(cd)", "Log Select", "Log Sense", unknown, unknown,
+/* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)",
+/* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown,
+/* 5c-5f */ unknown, unknown, unknown,
+};
+
+#define group(opcode) (((opcode) >> 5) & 7)
+
+#define RESERVED_GROUP  0
+#define VENDOR_GROUP    1
+#define NOTEXT_GROUP    2
+
+static const char **commands[] = {
+    group_0_commands, group_1_commands, group_2_commands, 
+    (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, 
+    (const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP, 
+    (const char **) VENDOR_GROUP
+};
+
+static const char reserved[] = "RESERVED";
+static const char vendor[] = "VENDOR SPECIFIC";
+
+static void print_opcodek(unsigned char opcode)
+{
+	const char **table = commands[ group(opcode) ];
+
+	switch ((unsigned long) table) {
+	case RESERVED_GROUP:
+		printk("%s[%02x] ", reserved, opcode); 
+		break;
+	case NOTEXT_GROUP:
+		printk("%s(notext)[%02x] ", unknown, opcode); 
+		break;
+	case VENDOR_GROUP:
+		printk("%s[%02x] ", vendor, opcode); 
+		break;
+	default:
+		if (table[opcode & 0x1f] != unknown)
+			printk("%s[%02x] ", table[opcode & 0x1f], opcode);
+		else
+			printk("%s[%02x] ", unknown, opcode);
+		break;
+	}
+}
+
+static void print_commandk (unsigned char *command)
+{
+	int i,s;
+//	printk(KERN_DEBUG);
+	print_opcodek(command[0]);
+	/*printk(KERN_DEBUG __func__ " ");*/
+	if ((command[0] >> 5) == 6 ||
+	    (command[0] >> 5) == 7 ) {
+		s = 12; /* vender specific */
+	} else {
+		s = COMMAND_SIZE(command[0]);
+	}
+
+	for ( i = 1; i < s; ++i) {
+		printk("%02x ", command[i]);
+	}
+
+	switch (s) {
+	case 6:
+		printk("LBA=%d len=%d",
+		       (((unsigned int)command[1] & 0x0f) << 16) |
+		       ( (unsigned int)command[2]         <<  8) |
+		       ( (unsigned int)command[3]              ),
+		       (unsigned int)command[4]
+			);
+		break;
+	case 10:
+		printk("LBA=%d len=%d",
+		       ((unsigned int)command[2] << 24) |
+		       ((unsigned int)command[3] << 16) |
+		       ((unsigned int)command[4] <<  8) |
+		       ((unsigned int)command[5]      ),
+		       ((unsigned int)command[7] <<  8) |
+		       ((unsigned int)command[8]      )
+		       );
+		break;
+	case 12:
+		printk("LBA=%d len=%d",
+		       ((unsigned int)command[2] << 24) |
+		       ((unsigned int)command[3] << 16) |
+		       ((unsigned int)command[4] <<  8) |
+		       ((unsigned int)command[5]      ),
+		       ((unsigned int)command[6] << 24) |
+		       ((unsigned int)command[7] << 16) |
+		       ((unsigned int)command[8] <<  8) |
+		       ((unsigned int)command[9]      )
+		       );
+		break;
+	default:
+		break;
+	}
+	printk("\n");
+}
+
+static void show_command(Scsi_Cmnd *ptr)
+{
+	print_commandk(ptr->cmnd);
+}
+
+static void show_busphase(unsigned char stat)
+{
+	switch(stat) {
+	case BUSPHASE_COMMAND:
+		printk( "BUSPHASE_COMMAND\n");
+		break;
+	case BUSPHASE_MESSAGE_IN:
+		printk( "BUSPHASE_MESSAGE_IN\n");
+		break;
+	case BUSPHASE_MESSAGE_OUT:
+		printk( "BUSPHASE_MESSAGE_OUT\n");
+		break;
+	case BUSPHASE_DATA_IN:
+		printk( "BUSPHASE_DATA_IN\n");
+		break;
+	case BUSPHASE_DATA_OUT:
+		printk( "BUSPHASE_DATA_OUT\n");
+		break;
+	case BUSPHASE_STATUS:
+		printk( "BUSPHASE_STATUS\n");
+		break;
+	case BUSPHASE_SELECT:
+		printk( "BUSPHASE_SELECT\n");
+		break;
+	default:
+		printk( "BUSPHASE_other: 0x%x\n", stat);
+		break;
+	}
+}
+
+static void show_autophase(unsigned short i)
+{
+	printk("auto: 0x%x,", i);
+
+	if(i & COMMAND_PHASE) {
+		printk(" cmd");
+	}
+	if(i & DATA_IN_PHASE) {
+		printk(" din");
+	}
+	if(i & DATA_OUT_PHASE) {
+		printk(" dout");
+	}
+	if(i & MSGOUT_PHASE) {
+		printk(" mout");
+	}
+	if(i & STATUS_PHASE) {
+		printk(" stat");
+	}
+	if(i & ILLEGAL_PHASE) {
+		printk(" ill");
+	}
+	if(i & BUS_FREE_OCCUER) {
+		printk(" bfree-o");
+	}
+	if(i & MSG_IN_OCCUER) {
+		printk(" min-o");
+	}
+	if(i & MSG_OUT_OCCUER) {
+		printk(" mout-o");
+	}
+	if(i & SELECTION_TIMEOUT) {
+		printk(" sel");
+	}
+	if(i & MSGIN_00_VALID) {
+		printk(" m0");
+	}
+	if(i & MSGIN_02_VALID) {
+		printk(" m2");
+	}
+	if(i & MSGIN_03_VALID) {
+		printk(" m3");
+	}
+	if(i & MSGIN_04_VALID) {
+		printk(" m4");
+	}
+	if(i & AUTOSCSI_BUSY) {
+		printk(" busy");
+	}
+
+	printk("\n");
+}
+
+static void nsp32_print_register(int base)
+{
+	if (!(NSP32_DEBUG_MASK & NSP32_SPECIAL_PRINT_REGISTER))
+		return;
+
+	printk("Phase=0x%x, ", nsp32_read1(base, SCSI_BUS_MONITOR));
+	printk("OldPhase=0x%x, ", nsp32_index_read1(base, OLD_SCSI_PHASE));
+	printk("syncreg=0x%x, ", nsp32_read1(base, SYNC_REG));
+	printk("ackwidth=0x%x, ", nsp32_read1(base, ACK_WIDTH));
+	printk("sgtpaddr=0x%lx, ", nsp32_read4(base, SGT_ADR));
+	printk("scsioutlatch=0x%x, ", nsp32_read1(base, SCSI_OUT_LATCH_TARGET_ID));
+	printk("msgout=0x%lx, ", nsp32_read4(base, SCSI_MSG_OUT));
+	printk("miscrd=0x%x, ", nsp32_index_read2(base, MISC_WR));
+	printk("seltimeout=0x%x, ", nsp32_read2(base, SEL_TIME_OUT));
+	printk("sreqrate=0x%x, ", nsp32_read1(base, SREQ_SMPL_RATE));
+	printk("transStatus=0x%x, ", nsp32_read2(base, TRANSFER_STATUS));
+	printk("reselectid=0x%x, ", nsp32_read2(base, COMMAND_CONTROL));
+	printk("arbit=0x%x, ", nsp32_read1(base, ARBIT_STATUS));
+	printk("BmStart=0x%lx, ", nsp32_read4(base, BM_START_ADR));
+	printk("BmCount=0x%lx, ", nsp32_read4(base, BM_CNT));
+	printk("SackCnt=0x%lx, ", nsp32_read4(base, SACK_CNT));
+	printk("SReqCnt=0x%lx, ", nsp32_read4(base, SREQ_CNT));
+	printk("SavedSackCnt=0x%lx, ", nsp32_read4(base, SAVED_SACK_CNT));
+	printk("ScsiBusControl=0x%x, ", nsp32_read1(base, SCSI_BUS_CONTROL));
+	printk("FifoRestCnt=0x%x, ", nsp32_read2(base, FIFO_REST_CNT));
+	printk("CdbIn=0x%x, ", nsp32_read1(base, SCSI_CSB_IN));
+	printk("\n");
+
+	if (0) {
+		printk("execph=0x%x, ", nsp32_read2(base, SCSI_EXECUTE_PHASE));
+		printk("IrqStatus=0x%x, ", nsp32_read2(base, IRQ_STATUS));
+		printk("\n");
+	}
+}
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/nsp32.h linux.20pre10-ac2/drivers/scsi/nsp32.h
--- linux.20pre10/drivers/scsi/nsp32.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/nsp32.h	2002-10-10 23:53:14.000000000 +0100
@@ -0,0 +1,429 @@
+/*
+ * Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus SCSI Host Bus Adapter driver
+ * Basic data header
+ *
+ * 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, 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.
+*/
+
+#ifndef _NSP32_H
+#define _NSP32_H
+
+
+//#define NSP32_DEBUG 9
+
+
+/*
+ * VENDOR/DEVICE ID
+ */
+#define PCI_VENDOR_ID_IODATA  0x10fc
+#define PCI_VENDOR_ID_WORKBIT 0x1145
+
+#define PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II  0x0005
+#define PCI_DEVICE_ID_NINJASCSI_32BI_KME      0xf007
+#define PCI_DEVICE_ID_NINJASCSI_32BI_WBT      0x8007
+#define PCI_DEVICE_ID_WORKBIT_STANDARD        0xf010
+#define PCI_DEVICE_ID_WORKBIT_DUALEDGE        0xf011
+#define PCI_DEVICE_ID_NINJASCSI_32BI_LOGITEC  0xf012
+#define PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC 0xf013
+#define PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO   0xf015
+
+/*
+ * MODEL
+ */
+enum {
+	MODEL_IODATA        = 0,
+	MODEL_KME           = 1,
+	MODEL_WORKBIT       = 2,
+	MODEL_EXT_ROM       = 3,
+	MODEL_PCI_WORKBIT   = 4,
+	MODEL_PCI_LOGITEC   = 5,
+	MODEL_PCI_MELCO     = 6,
+};
+
+static char * nsp32_model[] = {
+	"I-O DATA CBSC-II",
+	"KME SCSI card",
+	"Workbit duo SCSI card",
+	"External ROM",
+	"Workbit Standard/IO Data PCI card",
+	"Logitec PCI card",
+	"Melco PCI card",
+};
+
+
+/*
+ * SCSI Generic Definitions
+ */
+#define EXTENDED_SDTR_LEN	0x03
+
+
+/*
+ * MACRO
+ */
+#define BIT(x)    (1UL << (x))
+#ifndef MIN
+# define MIN(a,b)  ((a) > (b) ? (b) : (a))
+#endif
+
+/*
+ * BASIC Definitions
+ */
+#ifndef TRUE
+# define TRUE  1
+#endif
+#ifndef FALSE
+# define FALSE 0
+#endif
+#define ASSERT 1
+#define NEGATE 0
+
+
+/*******************/
+/* normal register */
+/*******************/
+/*
+ * Don't access below register with Double Word:
+ * +00, +04, +08, +0c, +64, +80, +84, +88, +90, +c4, +c8, +cc, +d0.
+ */
+#define IRQ_CONTROL 0x00	/* BASE+00, W, W */
+#define IRQ_STATUS  0x00	/* BASE+00, W, R */
+# define IRQSTATUS_LATCHED_MSG      BIT(0)
+# define IRQSTATUS_LATCHED_IO       BIT(1)
+# define IRQSTATUS_LATCHED_CD       BIT(2)
+# define IRQSTATUS_LATCHED_BUS_FREE BIT(3)
+# define IRQSTATUS_RESELECT_OCCUER  BIT(4)
+# define IRQSTATUS_PHASE_CHANGE_IRQ BIT(5)
+# define IRQSTATUS_SCSIRESET_IRQ    BIT(6)
+# define IRQSTATUS_TIMER_IRQ        BIT(7)
+# define IRQSTATUS_FIFO_SHLD_IRQ    BIT(8)
+# define IRQSTATUS_PCI_IRQ	    BIT(9)
+# define IRQSTATUS_BMCNTERR_IRQ     BIT(10)
+# define IRQSTATUS_AUTOSCSI_IRQ     BIT(11)
+# define PCI_IRQ_MASK               BIT(12)
+# define TIMER_IRQ_MASK             BIT(13)
+# define FIFO_IRQ_MASK              BIT(14)
+# define SCSI_IRQ_MASK              BIT(15)
+# define IRQ_CONTROL_ALL_IRQ_MASK   0xf000
+# define IRQSTATUS_ANY_IRQ          (IRQSTATUS_RESELECT_OCCUER	| \
+				     IRQSTATUS_PHASE_CHANGE_IRQ	| \
+				     IRQSTATUS_SCSIRESET_IRQ	| \
+				     IRQSTATUS_TIMER_IRQ	| \
+				     IRQSTATUS_FIFO_SHLD_IRQ	| \
+				     IRQSTATUS_PCI_IRQ		| \
+				     IRQSTATUS_BMCNTERR_IRQ	| \
+				     IRQSTATUS_AUTOSCSI_IRQ	)
+
+#define TRANSFER_CONTROL 0x02	/* BASE+02, W, W */
+#define TRANSFER_STATUS  0x02	/* BASE+02, W, R */
+# define CB_MMIO_MODE        BIT(0)
+# define CB_IO_MODE          BIT(1)
+# define BM_TEST             BIT(2)
+# define BM_TEST_DIR         BIT(3)
+# define DUAL_EDGE_ENABLE    BIT(4)
+# define NO_TRANSFER_TO_HOST BIT(5)
+# define TRANSFER_GO         BIT(7)
+# define BLIEND_MODE         BIT(8)
+# define BM_START            BIT(9)
+# define ADVANCED_BM_WRITE   BIT(10)
+# define BM_SINGLE_MODE      BIT(11)
+# define FIFO_TRUE_FULL      BIT(12)
+# define FIFO_TRUE_EMPTY     BIT(13)
+# define ALL_COUNTER_CLR     BIT(14)
+# define FIFOTEST            BIT(15)
+
+#define INDEX_REG 0x04		/* BASE+04, Byte(R/W), Word(R) */
+
+#define TIMER_SET 0x06		/* BASE+06, W, R/W */
+# define TIMER_CNT_MASK 0xff
+# define TIMER_STOP     BIT(8)
+
+#define DATA_REG_LOW 0x08	/* BASE+08, LowW, R/W */
+#define DATA_REG_HI  0x0a	/* BASE+0a, Hi-W, R/W */
+
+#define FIFO_REST_CNT 0x0c	/* BASE+0c, W, R/W */
+# define FIFO_REST_MASK       0x1ff
+# define FIFO_EMPTY_SHLD_FLAG BIT(14)
+# define FIFO_FULL_SHLD_FLAG  BIT(15)
+
+#define SREQ_SMPL_RATE 0x0f	/* BASE+0f, B, R/W */
+# define SREQSMPLRATE_RATE0 BIT(0)
+# define SREQSMPLRATE_RATE1 BIT(1)
+# define SAMPLING_ENABLE    BIT(2)
+
+#define SCSI_BUS_CONTROL 0x10	/* BASE+10, B, R/W */
+# define BUSCTL_SEL         BIT(0)
+# define BUSCTL_RST         BIT(1)
+# define BUSCTL_DATAOUT_ENB BIT(2)
+# define BUSCTL_ATN         BIT(3)
+# define BUSCTL_ACK         BIT(4)
+# define BUSCTL_BSY         BIT(5)
+# define AUTODIRECTION      BIT(6)
+# define ACKENB             BIT(7)
+
+#define CLR_COUNTER 0x12	/* BASE+12, B, W */
+# define ACK_COUNTER_CLR       BIT(0)
+# define SREQ_COUNTER_CLR      BIT(1)
+# define FIFO_HOST_POINTER_CLR BIT(2)
+# define FIFO_REST_COUNT_CLR   BIT(3)
+# define BM_COUNTER_CLR        BIT(4)
+# define SAVED_ACK_CLR         BIT(5)
+# define CLRCOUNTER_ALLMASK    (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5))
+
+#define SCSI_BUS_MONITOR 0x12	/* BASE+12, B, R */
+# define BUSMON_MSG BIT(0)
+# define BUSMON_IO  BIT(1)
+# define BUSMON_CD  BIT(2)
+# define BUSMON_BSY BIT(3)
+# define BUSMON_ACK BIT(4)
+# define BUSMON_REQ BIT(5)
+# define BUSMON_SEL BIT(6)
+# define BUSMON_ATN BIT(7)
+
+#define COMMAND_DATA 0x14	/* BASE+14, B, R/W */
+
+#define PARITY_CONTROL 0x16	/* BASE+16, B, R/W */
+# define PARITY_CHECK_ENABLE BIT(0)
+# define PARITY_ERROR_CLEAR  BIT(1)
+#define PARITY_STATUS  0x16
+//# define PARITY_CHECK_ENABLE BIT(0)
+# define PARITY_ERROR_NORMAL BIT(1)
+# define PARITY_ERROR_LSB    BIT(1)
+# define PARITY_ERROR_MSB    BIT(2)
+
+#define RESELECT_ID 0x18	/* BASE+18, B, R */
+
+#define COMMAND_CONTROL 0x18	/* BASE+18, W, W */
+# define CLEAR_CDB_FIFO_POINTER BIT(0)
+# define AUTO_COMMAND_PHASE     BIT(1)
+# define AUTOSCSI_START         BIT(2)
+# define AUTOSCSI_RESTART       BIT(3)
+# define AUTO_PARAMETER         BIT(4)
+# define AUTO_ATN               BIT(5)
+# define AUTO_MSGIN_00_OR_04    BIT(6)
+# define AUTO_MSGIN_02          BIT(7)
+# define AUTO_MSGIN_03          BIT(8)
+
+#define SET_ARBIT 0x1a		/* BASE+1a, B, W */
+# define ARBIT_GO    BIT(0)
+# define ARBIT_CLEAR BIT(1)
+
+#define ARBIT_STATUS 0x1a	/* BASE+1a, B, R */
+//# define ARBIT_GO             BIT(0)
+# define ARBIT_WIN            BIT(1)
+# define ARBIT_FAIL           BIT(2)
+# define AUTO_PARAMETER_VALID BIT(3)
+# define SGT_VALID            BIT(4)
+
+#define SYNC_REG 0x1c	/* BASE+1c, B, R/W */
+
+#define ACK_WIDTH 0x1d	/* BASE+1d, B, R/W */
+
+#define SCSI_DATA_WITH_ACK 0x20	/* BASE+20, B, R/W */
+#define SCSI_OUT_LATCH_TARGET_ID 0x22	/* BASE+22, B, W */
+#define SCSI_DATA_IN 0x22	/* BASE+22, B, R */
+
+#define SCAM_CONTROL 0x24	/* BASE+24, B, W */
+#define SCAM_STATUS  0x24	/* BASE+24, B, R */
+# define SCAM_MSG    BIT(0)
+# define SCAM_IO     BIT(1)
+# define SCAM_CD     BIT(2)
+# define SCAM_BSY    BIT(3)
+# define SCAM_SEL    BIT(4)
+# define SCAM_XFEROK BIT(5)
+
+#define SCAM_DATA 0x26	/* BASE+26, B, R/W */
+# define SD0					BIT(0)
+# define SD1					BIT(1)
+# define SD2					BIT(2)
+# define SD3					BIT(3)
+# define SD4					BIT(4)
+# define SD5					BIT(5)
+# define SD6					BIT(6)
+# define SD7					BIT(7)
+
+#define SACK_CNT 0x28	/* BASE+28, DW, R/W */
+#define SREQ_CNT 0x2c	/* BASE+2c, DW, R/W */
+
+#define FIFO_DATA_LOW 0x30	/* BASE+30, B/W/DW, R/W */
+#define FIFO_DATA_HIGH 0x32	/* BASE+32, B/W, R/W */
+#define BM_START_ADR 0x34	/* BASE+34, DW, R/W */
+
+#define BM_CNT 0x38	/* BASE+38, DW, R/W */
+# define BM_COUNT_MASK 0x0001ffff
+# define SGTEND        BIT(31)
+
+#define SGT_ADR 0x3c	/* BASE+3c, DW, R/W */
+#define WAIT_REG 0x40	/* Bi only */
+
+#define SCSI_EXECUTE_PHASE 0x40	/* BASE+40, W, R */
+# define COMMAND_PHASE     BIT(0)
+# define DATA_IN_PHASE     BIT(1)
+# define DATA_OUT_PHASE    BIT(2)
+# define MSGOUT_PHASE      BIT(3)
+# define STATUS_PHASE      BIT(4)
+# define ILLEGAL_PHASE     BIT(5)
+# define BUS_FREE_OCCUER   BIT(6)
+# define MSG_IN_OCCUER     BIT(7)
+# define MSG_OUT_OCCUER    BIT(8)
+# define SELECTION_TIMEOUT BIT(9)
+# define MSGIN_00_VALID    BIT(10)
+# define MSGIN_02_VALID    BIT(11)
+# define MSGIN_03_VALID    BIT(12)
+# define MSGIN_04_VALID    BIT(13)
+# define AUTOSCSI_BUSY     BIT(15)
+
+#define SCSI_CSB_IN 0x42	/* BASE+42, B, R */
+
+#define SCSI_MSG_OUT 0x44	/* BASE+44, DW, R/W */
+# define MSGOUT_COUNT_MASK (BIT(0)|BIT(1))
+# define MV_VALID	      BIT(7)
+
+#define SEL_TIME_OUT 0x48	/* BASE+48, W, R/W */
+#define SAVED_SACK_CNT 0x4c	/* BASE+4c, DW, R */
+
+#define HTOSDATADELAY		0x50	/* BASE+50, B, R/W */
+#define STOHDATADELAY		0x54	/* BASE+54, B, R/W */
+#define ACKSUMCHECKRD		0x58	/* BASE+58, W, R */
+#define REQSUMCHECKRD		0x5c	/* BASE+5c, W, R */
+
+
+/********************/
+/* indexed register */
+/********************/
+
+#define CLOCK_DIV 0x00	/* BASE+08, IDX+00, B, R/W */
+# define CLOCK_2		BIT(0)	/* MCLK/2 */
+# define CLOCK_4		BIT(1)	/* MCLK/4 */
+# define PCICLK			BIT(7)	/* PCICLK (33MHz) */
+
+#define TERM_PWR_CONTROL 0x01	/* BASE+08, IDX+01, B, R/W */
+# define BPWR  BIT(0)
+# define SENSE BIT(1)	/* Read Only */
+
+#define EXT_PORT_DDR 0x02	/* BASE+08, IDX+02, B, R/W */
+#define EXT_PORT     0x03	/* BASE+08, IDX+03, B, R/W */
+# define LED_ON	 0
+# define LED_OFF 1
+
+#define IRQ_SELECT 0x04	/* BASE+08, IDX+04, W, R/W */
+# define IRQSELECT_RESELECT_IRQ      BIT(0)
+# define IRQSELECT_PHASE_CHANGE_IRQ  BIT(1)
+# define IRQSELECT_SCSIRESET_IRQ     BIT(2)
+# define IRQSELECT_TIMER_IRQ         BIT(3)
+# define IRQSELECT_FIFO_SHLD_IRQ     BIT(4)
+# define IRQSELECT_TARGET_ABORT_IRQ  BIT(5)
+# define IRQSELECT_MASTER_ABORT_IRQ  BIT(6)
+# define IRQSELECT_SERR_IRQ          BIT(7)
+# define IRQSELECT_PERR_IRQ          BIT(8)
+# define IRQSELECT_BMCNTERR_IRQ      BIT(9)
+# define IRQSELECT_AUTO_SCSI_SEQ_IRQ BIT(10)
+
+#define OLD_SCSI_PHASE 0x05	/* BASE+08, IDX+05, B, R */
+# define OLD_MSG  BIT(0)
+# define OLD_IO   BIT(1)
+# define OLD_CD   BIT(2)
+# define OLD_BUSY BIT(3)
+
+#define FIFO_FULL_SHLD_COUNT 0x06	/* BASE+08, IDX+06, B, R/W */
+#define FIFO_EMPTY_SHLD_COUNT 0x07	/* BASE+08, IDX+07, B, R/W */
+
+#define EXP_ROM_CONTROL 0x08	/* BASE+08, IDX+08, B, R/W */
+
+#define EXP_ROM_ADRL		0x09	/* BASE+08, IDX+09, W, R/W */
+
+#define EXP_ROM_DATA		0x0a	/* BASE+08, IDX+0a, B, R/W */
+
+#define CHIP_MODE 0x0b	/* Bi only */
+# define OEM0 BIT(1)
+# define OEM1 BIT(2)
+# define OPTB BIT(3)
+# define OPTC BIT(4)
+# define OPTD BIT(5)
+# define OPTE BIT(6)
+# define OPTF BIT(7)
+
+#define MISC_WR 0x0c	/* BASE+08, IDX+0c, W, R/W */
+#define MISC_RD 0x0c
+# define SCSI_DIRECTION_DETECTOR_SELECT BIT(0)
+# define SCSI2_HOST_DIRECTION_VALID	BIT(1)	/* Read only */
+# define HOST2_SCSI_DIRECTION_VALID	BIT(2)	/* Read only */
+# define DELAYED_BMSTART                BIT(3)
+# define MASTER_TERMINATION_SELECT      BIT(4)
+# define BMREQ_NEGATE_TIMING_SEL        BIT(5)
+# define AUTOSEL_TIMING_SEL             BIT(6)
+# define MISC_MABORT_MASK		BIT(7)
+# define BMSTOP_CHANGE2_NONDATA_PHASE	BIT(8)
+
+#define BM_CYCLE 0x0d	/* BASE+08, IDX+0d, B, R/W */
+# define BM_CYCLE0		 BIT(0)
+# define BM_CYCLE1		 BIT(1)
+# define BM_FRAME_ASSERT_TIMING	 BIT(2)
+# define BM_IRDY_ASSERT_TIMING	 BIT(3)
+# define BM_SINGLE_BUS_MASTER	 BIT(4)
+# define MEMRD_CMD0              BIT(5)
+# define SGT_AUTO_PARA_MEMED_CMD BIT(6)
+# define MEMRD_CMD1              BIT(7)
+
+
+#define SREQ_EDGH 0x0e	/* BASE+08, IDX+0e, B, W */
+# define SREQ_EDGH_SELECT BIT(0)
+
+#define UP_CNT		0x0f	/* BASE+08, IDX+0f, B, W */
+#define CFG_CMD_STR      0x10	/* BASE+08, IDX+10, W, R */
+#define CFG_LATE_CACHE   0x11	/* BASE+08, IDX+11, W, R/W */
+#define CFG_BASE_ADR_1   0x12	/* BASE+08, IDX+12, W, R */
+#define CFG_BASE_ADR_2   0x13	/* BASE+08, IDX+13, W, R */
+#define CFG_INLINE       0x14	/* BASE+08, IDX+14, W, R */
+
+#define SERIAL_ROM_CTL	0x15	/* BASE+08, IDX+15, B, R */
+# define SCL 					BIT(0)
+# define ENA					BIT(1)
+# define SDA					BIT(2)
+
+#define FIFO_HST_POINTER	0x16	/* BASE+08, IDX+16, B, R/W */
+#define SREQ_DELAY		0x17	/* BASE+08, IDX+17, B, R/W */
+#define SACK_DELAY		0x18	/* BASE+08, IDX+18, B, R/W */
+#define SREQ_NOISE_CANCEL	0x19	/* BASE+08, IDX+19, B, R/W */
+#define SDP_NOISE_CANCEL	0x1a	/* BASE+08, IDX+1a, B, R/W */
+#define DELAY_TEST		0x1b	/* BASE+08, IDX+1b, B, R/W */
+#define SD0_NOISE_CANCEL	0x20	/* BASE+08, IDX+20, B, R/W */
+#define SD1_NOISE_CANCEL	0x21	/* BASE+08, IDX+21, B, R/W */
+#define SD2_NOISE_CANCEL	0x22	/* BASE+08, IDX+22, B, R/W */
+#define SD3_NOISE_CANCEL	0x23	/* BASE+08, IDX+23, B, R/W */
+#define SD4_NOISE_CANCEL	0x24	/* BASE+08, IDX+24, B, R/W */
+#define SD5_NOISE_CANCEL	0x25	/* BASE+08, IDX+25, B, R/W */
+#define SD6_NOISE_CANCEL	0x26	/* BASE+08, IDX+26, B, R/W */
+#define SD7_NOISE_CANCEL	0x27	/* BASE+08, IDX+27, B, R/W */
+
+
+/*
+ * Useful Bus Monitor status combinations.
+ */
+#define BUSMON_BUS_FREE    0
+#define BUSMON_COMMAND     ( BUSMON_BSY |                          BUSMON_CD | BUSMON_REQ )
+#define BUSMON_MESSAGE_IN  ( BUSMON_BSY | BUSMON_MSG | BUSMON_IO | BUSMON_CD | BUSMON_REQ )
+#define BUSMON_MESSAGE_OUT ( BUSMON_BSY | BUSMON_MSG |             BUSMON_CD | BUSMON_REQ )
+#define BUSMON_DATA_IN     ( BUSMON_BSY |              BUSMON_IO |             BUSMON_REQ )
+#define BUSMON_DATA_OUT    ( BUSMON_BSY |                                      BUSMON_REQ )
+#define BUSMON_STATUS      ( BUSMON_BSY |              BUSMON_IO | BUSMON_CD | BUSMON_REQ )
+#define BUSMON_RESELECT    (                           BUSMON_IO                          | BUSMON_SEL)
+#define BUSMON_PHASE_MASK  (              BUSMON_MSG | BUSMON_IO | BUSMON_CD              | BUSMON_SEL)
+
+#define BUSPHASE_COMMAND     ( BUSMON_COMMAND     & BUSMON_PHASE_MASK )
+#define BUSPHASE_MESSAGE_IN  ( BUSMON_MESSAGE_IN  & BUSMON_PHASE_MASK )
+#define BUSPHASE_MESSAGE_OUT ( BUSMON_MESSAGE_OUT & BUSMON_PHASE_MASK )
+#define BUSPHASE_DATA_IN     ( BUSMON_DATA_IN     & BUSMON_PHASE_MASK )
+#define BUSPHASE_DATA_OUT    ( BUSMON_DATA_OUT    & BUSMON_PHASE_MASK )
+#define BUSPHASE_STATUS      ( BUSMON_STATUS      & BUSMON_PHASE_MASK )
+#define BUSPHASE_SELECT      ( BUSMON_SEL | BUSMON_IO )
+
+#endif _NSP32_H
+/* end */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/nsp32_io.h linux.20pre10-ac2/drivers/scsi/nsp32_io.h
--- linux.20pre10/drivers/scsi/nsp32_io.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/nsp32_io.h	2002-10-10 23:53:14.000000000 +0100
@@ -0,0 +1,269 @@
+/*
+ * Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus SCSI Host Bus Adapter driver
+ * I/O routine
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License.
+ */
+
+#ifndef _NSP32_IO_H
+#define _NSP32_IO_H
+
+static inline void nsp32_write1(unsigned int  base,
+				unsigned int  index,
+				unsigned char val)
+{
+	outb(val, (base + index));
+}
+
+static inline unsigned char nsp32_read1(unsigned int base,
+					unsigned int index)
+{
+	return inb(base + index);
+}
+
+static inline void nsp32_write2(unsigned int  base,
+				unsigned int  index,
+				unsigned short val)
+{
+	outw(cpu_to_le16(val), (base + index));
+}
+
+static inline unsigned short nsp32_read2(unsigned int base,
+					 unsigned int index)
+{
+	return le16_to_cpu(inw(base + index));
+}
+
+static inline void nsp32_write4(unsigned int  base,
+				unsigned int  index,
+				unsigned long val)
+{
+	outl(cpu_to_le32(val), (base + index));
+}
+
+static inline unsigned long nsp32_read4(unsigned int base,
+					unsigned int index)
+{
+	return le32_to_cpu(inl(base + index));
+}
+
+/*==============================================*/
+
+static inline void nsp32_mmio_write1(unsigned long base,
+				     unsigned int  index,
+				     unsigned char val)
+{
+	volatile unsigned char *ptr;
+
+	ptr = (unsigned char *)(base + NSP32_MMIO_OFFSET + index);
+
+	*ptr = val;
+}
+
+static inline unsigned char nsp32_mmio_read1(unsigned long base,
+					     unsigned int  index)
+{
+	volatile unsigned char *ptr;
+
+	ptr = (unsigned char *)(base + NSP32_MMIO_OFFSET + index);
+
+	return *ptr;
+}
+
+static inline void nsp32_mmio_write2(unsigned long base,
+				     unsigned int  index,
+				     unsigned short val)
+{
+	volatile unsigned short *ptr;
+
+	ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + index);
+
+	*ptr = cpu_to_le16(val);
+}
+
+static inline unsigned short nsp32_mmio_read2(unsigned long base,
+					      unsigned int  index)
+{
+	volatile unsigned short *ptr;
+
+	//printk(__FUNCTION__ "\n");
+
+	ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + index);
+
+	return le16_to_cpu(*ptr);
+}
+
+static inline void nsp32_mmio_write4(unsigned long base,
+				     unsigned int  index,
+				     unsigned long val)
+{
+	volatile unsigned long *ptr;
+
+	ptr = (unsigned long *)(base + NSP32_MMIO_OFFSET + index);
+
+	*ptr = cpu_to_le32(val);
+}
+
+static inline unsigned long nsp32_mmio_read4(unsigned long base,
+					     unsigned int  index)
+{
+	volatile unsigned long *ptr;
+
+	//printk(__FUNCTION__ "\n");
+
+	ptr = (unsigned long *)(base + NSP32_MMIO_OFFSET + index);
+
+	return le32_to_cpu(*ptr);
+}
+
+
+/*=============================================*/
+
+
+static inline unsigned char nsp32_index_read1(unsigned int base,
+					      unsigned int reg)
+{
+	outb(reg, base + INDEX_REG);
+	return inb(base + DATA_REG_LOW);
+}
+
+static inline void nsp32_index_write1(unsigned int  base,
+				      unsigned int  reg,
+				      unsigned char val)
+{
+	outb(reg, base + INDEX_REG);
+	outb(val, base + DATA_REG_LOW);
+}
+
+static inline unsigned short nsp32_index_read2(unsigned int base,
+					       unsigned int reg)
+{
+	outb(reg, base + INDEX_REG);
+	return le16_to_cpu(inw(base + DATA_REG_LOW));
+}
+
+static inline void nsp32_index_write2(unsigned int  base,
+				      unsigned int  reg,
+				      unsigned short val)
+{
+	outb(reg, base + INDEX_REG);
+	outw(cpu_to_le16(val), base + DATA_REG_LOW);
+}
+
+static inline unsigned long nsp32_index_read4(unsigned int base,
+					      unsigned int reg)
+{
+	unsigned long h,l;
+
+	outb(reg, base + INDEX_REG);
+	l = le16_to_cpu(inw(base + DATA_REG_LOW));
+	h = le16_to_cpu(inw(base + DATA_REG_HI ));
+
+	return ((h << 16) | l);
+}
+
+static inline void nsp32_index_write4(unsigned int  base,
+				      unsigned int  reg,
+				      unsigned long val)
+{
+	unsigned long h,l;
+
+	h = (val & 0xffff0000) >> 16;
+	l = (val & 0x0000ffff) >> 0;
+
+	outb(reg, base + INDEX_REG);
+	outw(cpu_to_le16(l), base + DATA_REG_LOW);
+	outw(cpu_to_le16(h), base + DATA_REG_HI);
+}
+
+
+/* ===================================*/
+
+static inline unsigned char nsp32_mmio_index_read1(unsigned int base,
+						   unsigned int reg)
+{
+	volatile unsigned short *index_ptr, *data_ptr;
+
+	index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG);
+	data_ptr  = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW);
+
+	*index_ptr = reg;
+
+	return ((*data_ptr) & 0xff);
+}
+
+static inline void nsp32_mmio_index_write1(unsigned int base,
+					   unsigned int reg,
+					   unsigned char val)
+{
+	volatile unsigned short *index_ptr, *data_ptr;
+
+	index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG);
+	data_ptr  = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW);
+
+	*index_ptr = reg;
+	*data_ptr  = (unsigned short)val;
+}
+
+static inline unsigned short nsp32_mmio_index_read2(unsigned int base,
+						    unsigned int reg)
+{
+	volatile unsigned short *index_ptr, *data_ptr;
+
+	index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG);
+	data_ptr  = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW);
+
+	*index_ptr = reg;
+
+	return le16_to_cpu(*data_ptr);
+}
+
+static inline void nsp32_mmio_index_write2(unsigned int base,
+					   unsigned int reg,
+					   unsigned short val)
+{
+	volatile unsigned short *index_ptr, *data_ptr;
+
+	index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG);
+	data_ptr  = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW);
+
+	*index_ptr = reg;
+	*data_ptr  = val;
+}
+
+/*-------------------------------------------------------------------*/
+
+static inline void nsp32_multi_read4(unsigned int   BaseAddr,
+				     unsigned int   Register,
+				     void          *buf,
+				     unsigned long  count)
+{
+	insl(BaseAddr + Register, buf, count);
+}
+
+static inline void nsp32_fifo_read(unsigned int   base,
+				   void          *buf,
+				   unsigned long  count)
+{
+	//DEBUG(0, __FUNCTION__ "() buf=0x%p, count=0x%lx*4\n", buf, count);
+	nsp32_multi_read4(base, FIFO_DATA_LOW, buf, count);
+}
+
+static inline void nsp32_multi_write4(unsigned int   BaseAddr,
+				      unsigned int   Register,
+				      void          *buf,
+				      unsigned long  count)
+{
+	outsl(BaseAddr + Register, buf, count);
+}
+
+static inline void nsp32_fifo_write(unsigned int   base,
+				    void          *buf,
+				    unsigned long  count)
+{
+	nsp32_multi_write4(base, FIFO_DATA_LOW, buf, count);
+}
+
+#endif _NSP32_IO_H
+/* end */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/qlogicisp.h linux.20pre10-ac2/drivers/scsi/qlogicisp.h
--- linux.20pre10/drivers/scsi/qlogicisp.h	2002-10-09 21:36:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/qlogicisp.h	2002-08-06 15:42:07.000000000 +0100
@@ -84,7 +84,8 @@
 	cmd_per_lun:		1,					   \
 	present:		0,					   \
 	unchecked_isa_dma:	0,					   \
-	use_clustering:		DISABLE_CLUSTERING			   \
+	use_clustering:		DISABLE_CLUSTERING,			   \
+	can_do_varyio:		1					   \
 }
 
 #endif /* _QLOGICISP_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/scsi.c linux.20pre10-ac2/drivers/scsi/scsi.c
--- linux.20pre10/drivers/scsi/scsi.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/scsi.c	2002-09-29 21:03:20.000000000 +0100
@@ -352,8 +352,9 @@
                                 int interruptable)
 {
  	struct Scsi_Host *host;
-  	Scsi_Cmnd *SCpnt = NULL;
+  	Scsi_Cmnd *SCpnt;
 	Scsi_Device *SDpnt;
+	struct list_head	*lp;
 	unsigned long flags;
   
   	if (!device)
@@ -364,7 +365,6 @@
 	spin_lock_irqsave(&device_request_lock, flags);
  
 	while (1 == 1) {
-		SCpnt = NULL;
 		if (!device->device_blocked) {
 			if (device->single_lun) {
 				/*
@@ -404,26 +404,21 @@
 					 * If asked to wait, we need to wait, otherwise
 					 * return NULL.
 					 */
-					SCpnt = NULL;
 					goto busy;
 				}
 			}
 			/*
-			 * Now we can check for a free command block for this device.
+			 * Is there a free command block for this device?
 			 */
-			for (SCpnt = device->device_queue; SCpnt; SCpnt = SCpnt->next) {
-				if (SCpnt->request.rq_status == RQ_INACTIVE)
-					break;
-			}
+			if (!list_empty(&device->sdev_free_q))
+				goto found;
 		}
+
 		/*
-		 * If we couldn't find a free command block, and we have been
+		 * Couldn't find a free command block, and we have been
 		 * asked to wait, then do so.
 		 */
-		if (SCpnt) {
-			break;
-		}
-      busy:
+busy:
 		/*
 		 * If we have been asked to wait for a free block, then
 		 * wait here.
@@ -475,12 +470,20 @@
                                         return NULL;
                                 }
                         }
+			continue;
 		} else {
                         spin_unlock_irqrestore(&device_request_lock, flags);
 			return NULL;
 		}
 	}
 
+found:
+	lp = device->sdev_free_q.next;
+	list_del(lp);
+	SCpnt = list_entry(lp, Scsi_Cmnd, sc_list);
+	if (SCpnt->request.rq_status != RQ_INACTIVE)
+		BUG();
+
 	SCpnt->request.rq_status = RQ_SCSI_BUSY;
 	SCpnt->request.waiting = NULL;	/* And no one is waiting for this
 					 * to complete */
@@ -526,6 +529,9 @@
 
         SDpnt = SCpnt->device;
 
+	/* command is now free - add to list */
+	list_add(&SCpnt->sc_list, &SDpnt->sdev_free_q);
+
 	SCpnt->request.rq_status = RQ_INACTIVE;
 	SCpnt->state = SCSI_STATE_UNUSED;
 	SCpnt->owner = SCSI_OWNER_NOBODY;
@@ -1333,14 +1339,10 @@
  */
 int scsi_retry_command(Scsi_Cmnd * SCpnt)
 {
-	memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd,
-	       sizeof(SCpnt->data_cmnd));
-	SCpnt->request_buffer = SCpnt->buffer;
-	SCpnt->request_bufflen = SCpnt->bufflen;
-	SCpnt->use_sg = SCpnt->old_use_sg;
-	SCpnt->cmd_len = SCpnt->old_cmd_len;
-	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
-	SCpnt->underflow = SCpnt->old_underflow;
+	/*
+	 * Restore the SCSI command state.
+	 */
+	scsi_setup_cmd_retry(SCpnt);
 
         /*
          * Zero the sense information from the last time we tried
@@ -1448,6 +1450,7 @@
  	spin_lock_irqsave(&device_request_lock, flags);
 	for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCnext) {
 		SDpnt->device_queue = SCnext = SCpnt->next;
+		list_del(&SCpnt->sc_list);
 		kfree((char *) SCpnt);
 	}
 	SDpnt->has_cmdblocks = 0;
@@ -1484,6 +1487,7 @@
 			SDpnt->queue_depth = 1; /* live to fight another day */
 	}
 	SDpnt->device_queue = NULL;
+	INIT_LIST_HEAD(&SDpnt->sdev_free_q);
 
 	for (j = 0; j < SDpnt->queue_depth; j++) {
 		SCpnt = (Scsi_Cmnd *)
@@ -1513,6 +1517,7 @@
 		SDpnt->device_queue = SCpnt;
 		SCpnt->state = SCSI_STATE_UNUSED;
 		SCpnt->owner = SCSI_OWNER_NOBODY;
+		list_add(&SCpnt->sc_list, &SDpnt->sdev_free_q);
 	}
 	if (j < SDpnt->queue_depth) {	/* low on space (D.Gilbert 990424) */
 		printk(KERN_WARNING "scsi_build_commandblocks: want=%d, space for=%d blocks\n",
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/scsi_error.c linux.20pre10-ac2/drivers/scsi/scsi_error.c
--- linux.20pre10/drivers/scsi/scsi_error.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/scsi_error.c	2002-09-29 21:03:32.000000000 +0100
@@ -385,16 +385,10 @@
  */
 STATIC int scsi_eh_retry_command(Scsi_Cmnd * SCpnt)
 {
-	memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd,
-	       sizeof(SCpnt->data_cmnd));
-	SCpnt->request_buffer = SCpnt->buffer;
-	SCpnt->request_bufflen = SCpnt->bufflen;
-	SCpnt->use_sg = SCpnt->old_use_sg;
-	SCpnt->cmd_len = SCpnt->old_cmd_len;
-	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
-	SCpnt->underflow = SCpnt->old_underflow;
-
-	scsi_send_eh_cmnd(SCpnt, SCpnt->timeout_per_command);
+	do {
+		scsi_setup_cmd_retry(SCpnt);
+		scsi_send_eh_cmnd(SCpnt, SCpnt->timeout_per_command);
+	} while (SCpnt->eh_state == NEEDS_RETRY);
 
 	/*
 	 * Hey, we are done.  Let's look to see what happened.
@@ -425,12 +419,6 @@
 
 	ASSERT_LOCK(&io_request_lock, 0);
 
-	memcpy((void *) SCpnt->cmnd, (void *) generic_sense,
-	       sizeof(generic_sense));
-
-	if (SCpnt->device->scsi_level <= SCSI_2)
-		SCpnt->cmnd[1] = SCpnt->lun << 5;
-
 	scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma)
 	    ? &scsi_result0[0] : kmalloc(512, GFP_ATOMIC | GFP_DMA);
 
@@ -438,24 +426,40 @@
 		printk("cannot allocate scsi_result in scsi_request_sense.\n");
 		return FAILED;
 	}
-	/*
-	 * Zero the sense buffer.  Some host adapters automatically always request
-	 * sense, so it is not a good idea that SCpnt->request_buffer and
-	 * SCpnt->sense_buffer point to the same address (DB).
-	 * 0 is not a valid sense code. 
-	 */
-	memset((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
-	memset((void *) scsi_result, 0, 256);
 
 	saved_result = SCpnt->result;
-	SCpnt->request_buffer = scsi_result;
-	SCpnt->request_bufflen = 256;
-	SCpnt->use_sg = 0;
-	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
-	SCpnt->sc_data_direction = SCSI_DATA_READ;
-	SCpnt->underflow = 0;
 
-	scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
+	do {
+		memcpy((void *) SCpnt->cmnd, (void *) generic_sense,
+		       sizeof(generic_sense));
+
+		if (SCpnt->device->scsi_level <= SCSI_2)
+			SCpnt->cmnd[1] = SCpnt->lun << 5;
+
+		/*
+		 * Zero the sense buffer.  Some host adapters automatically
+		 * always request sense, so it is not a good idea that
+		 * SCpnt->request_buffer and SCpnt->sense_buffer point to
+		 * the same address (DB).  0 is not a valid sense code. 
+		 */
+		memset((void *) SCpnt->sense_buffer, 0,
+		       sizeof(SCpnt->sense_buffer));
+		memset((void *) scsi_result, 0, 256);
+
+		SCpnt->request_buffer = scsi_result;
+		SCpnt->request_bufflen = 256;
+		SCpnt->use_sg = 0;
+		SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+		SCpnt->sc_data_direction = SCSI_DATA_READ;
+		SCpnt->underflow = 0;
+
+		scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
+		/*
+		 * If the SCSI device responded with "logical unit
+		 * is in process of becoming ready", we need to
+		 * retry this command.
+		 */
+	} while (SCpnt->eh_state == NEEDS_RETRY);
 
 	/* Last chance to have valid sense data */
 	if (!scsi_sense_valid(SCpnt))
@@ -497,26 +501,34 @@
 	static unsigned char tur_command[6] =
 	{TEST_UNIT_READY, 0, 0, 0, 0, 0};
 
-	memcpy((void *) SCpnt->cmnd, (void *) tur_command,
-	       sizeof(tur_command));
+	do {
+		memcpy((void *) SCpnt->cmnd, (void *) tur_command,
+		       sizeof(tur_command));
 
-	if (SCpnt->device->scsi_level <= SCSI_2)
-		SCpnt->cmnd[1] = SCpnt->lun << 5;
+		if (SCpnt->device->scsi_level <= SCSI_2)
+			SCpnt->cmnd[1] = SCpnt->lun << 5;
 
-	/*
-	 * Zero the sense buffer.  The SCSI spec mandates that any
-	 * untransferred sense data should be interpreted as being zero.
-	 */
-	memset((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
+		/*
+		 * Zero the sense buffer.  The SCSI spec mandates that any
+		 * untransferred sense data should be interpreted as being zero.
+		 */
+		memset((void *) SCpnt->sense_buffer, 0,
+		       sizeof(SCpnt->sense_buffer));
 
-	SCpnt->request_buffer = NULL;
-	SCpnt->request_bufflen = 0;
-	SCpnt->use_sg = 0;
-	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
-	SCpnt->underflow = 0;
-	SCpnt->sc_data_direction = SCSI_DATA_NONE;
+		SCpnt->request_buffer = NULL;
+		SCpnt->request_bufflen = 0;
+		SCpnt->use_sg = 0;
+		SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+		SCpnt->underflow = 0;
+		SCpnt->sc_data_direction = SCSI_DATA_NONE;
 
-	scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
+		scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
+		/*
+		 * If the SCSI device responded with "logical unit
+		 * is in process of becoming ready", we need to
+		 * retry this command.
+		 */
+	} while (SCpnt->eh_state == NEEDS_RETRY);
 
 	/*
 	 * When we eventually call scsi_finish, we really wish to complete
@@ -589,7 +601,6 @@
 
 	host = SCpnt->host;
 
-      retry:
 	/*
 	 * We will use a queued command if possible, otherwise we will emulate the
 	 * queuing and calling of completion function ourselves.
@@ -672,14 +683,13 @@
 		SCSI_LOG_ERROR_RECOVERY(3,
 			printk("scsi_send_eh_cmnd: scsi_eh_completed_normally %x\n", ret));
 		switch (ret) {
-		case SUCCESS:
-			SCpnt->eh_state = SUCCESS;
-			break;
-		case NEEDS_RETRY:
-			goto retry;
-		case FAILED:
 		default:
-			SCpnt->eh_state = FAILED;
+			ret = FAILED;
+			/*FALLTHROUGH*/
+		case FAILED:
+		case NEEDS_RETRY:
+		case SUCCESS:
+			SCpnt->eh_state = ret;
 			break;
 		}
 	} else {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/scsi.h linux.20pre10-ac2/drivers/scsi/scsi.h
--- linux.20pre10/drivers/scsi/scsi.h	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/scsi.h	2002-10-11 00:35:04.000000000 +0100
@@ -465,6 +465,7 @@
 				   int sectors);
 extern struct Scsi_Device_Template *scsi_get_request_dev(struct request *);
 extern int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt);
+extern void scsi_setup_cmd_retry(Scsi_Cmnd *SCpnt);
 extern int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int);
 extern void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
 			       int block_sectors);
@@ -558,6 +559,7 @@
 	int (*scsi_init_io_fn) (Scsi_Cmnd *);	/* Used to initialize
 						   new request */
 	Scsi_Cmnd *device_queue;	/* queue of SCSI Command structures */
+	struct list_head sdev_free_q;	/* list of free cmds */
 
 /* public: */
 	unsigned int id, lun, channel;
@@ -775,6 +777,8 @@
 						 * received on original command 
 						 * (auto-sense) */
 
+	struct list_head sc_list;	/* Inactive cmd list linkage, guarded
+					 * by device_request_lock. */
 	unsigned flags;
 
 	/*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/scsi_lib.c linux.20pre10-ac2/drivers/scsi/scsi_lib.c
--- linux.20pre10/drivers/scsi/scsi_lib.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/scsi_lib.c	2002-09-29 21:03:45.000000000 +0100
@@ -208,6 +208,30 @@
 }
 
 /*
+ * Function:	scsi_setup_cmd_retry()
+ *
+ * Purpose:	Restore the command state for a retry
+ *
+ * Arguments:	SCpnt	- command to be restored
+ *
+ * Returns:	Nothing
+ *
+ * Notes:	Immediately prior to retrying a command, we need
+ *		to restore certain fields that we saved above.
+ */
+void scsi_setup_cmd_retry(Scsi_Cmnd *SCpnt)
+{
+	memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd,
+	       sizeof(SCpnt->data_cmnd));
+	SCpnt->request_buffer = SCpnt->buffer;
+	SCpnt->request_bufflen = SCpnt->bufflen;
+	SCpnt->use_sg = SCpnt->old_use_sg;
+	SCpnt->cmd_len = SCpnt->old_cmd_len;
+	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
+	SCpnt->underflow = SCpnt->old_underflow;
+}
+
+/*
  * Function:    scsi_queue_next_request()
  *
  * Purpose:     Handle post-processing of completed commands.
@@ -720,7 +744,7 @@
 			printk("scsi%d: ERROR on channel %d, id %d, lun %d, CDB: ",
 			       SCpnt->host->host_no, (int) SCpnt->channel,
 			       (int) SCpnt->target, (int) SCpnt->lun);
-			print_command(SCpnt->cmnd);
+			print_command(SCpnt->data_cmnd);
 			print_sense("sd", SCpnt);
 			SCpnt = scsi_end_request(SCpnt, 0, block_sectors);
 			return;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/scsi_scan.c linux.20pre10-ac2/drivers/scsi/scsi_scan.c
--- linux.20pre10/drivers/scsi/scsi_scan.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/scsi_scan.c	2002-09-14 21:50:54.000000000 +0100
@@ -162,7 +162,7 @@
 	{"DELL", "PV530F",    "*", BLIST_SPARSELUN | BLIST_LARGELUN}, // Dell PV 530F
 	{"EMC", "SYMMETRIX", "*", BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
 	{"HP", "A6189A", "*", BLIST_SPARSELUN |  BLIST_LARGELUN}, // HP VA7400, by Alar Aun
-	{"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},			/* HP XP Arrays */
+	{"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},	/* HP XP Arrays */
 	{"CMD", "CRA-7280", "*", BLIST_SPARSELUN | BLIST_LARGELUN},   // CMD RAID Controller
 	{"CNSI", "G7324", "*", BLIST_SPARSELUN | BLIST_LARGELUN},     // Chaparral G7324 RAID
 	{"CNSi", "G8324", "*", BLIST_SPARSELUN},     // Chaparral G8324 RAID
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/sd.c linux.20pre10-ac2/drivers/scsi/sd.c
--- linux.20pre10/drivers/scsi/sd.c	2002-10-09 21:36:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/sd.c	2002-09-30 17:37:33.000000000 +0100
@@ -95,6 +95,7 @@
 static int *sd_blocksizes;
 static int *sd_hardsizes;	/* Hardware sector size */
 static int *sd_max_sectors;
+static char *sd_varyio;
 
 static int check_scsidisk_media_change(kdev_t);
 static int fop_revalidate_scsidisk(kdev_t);
@@ -848,10 +849,13 @@
 			break;
 		}
 
-		/* Look for non-removable devices that return NOT_READY.
+		/* Look for non-removable devices that return NOT_READY,
+		 * and don't require manual intervention.
 		 * Issue command to spin up drive for these cases. */
 		if (the_result && !rscsi_disks[i].device->removable &&
-		    SRpnt->sr_sense_buffer[2] == NOT_READY) {
+		    SRpnt->sr_sense_buffer[2] == NOT_READY &&
+		    ! ( SRpnt->sr_sense_buffer[12] == 0x04 &&   /* ASC */
+			SRpnt->sr_sense_buffer[13] == 0x03 )) { /* ASCQ */
 			unsigned long time1;
 			if (!spintime) {
 				printk("%s: Spinning up disk...", nbuff);
@@ -1140,6 +1144,12 @@
 	if (!sd_max_sectors)
 		goto cleanup_max_sectors;
 
+	sd_varyio = kmalloc((sd_template.dev_max << 4), GFP_ATOMIC);
+	if (!sd_varyio)
+		goto cleanup_varyio;
+
+	memset(sd_varyio, 0, (sd_template.dev_max << 4)); 
+
 	for (i = 0; i < sd_template.dev_max << 4; i++) {
 		sd_blocksizes[i] = 1024;
 		sd_hardsizes[i] = 512;
@@ -1204,6 +1214,8 @@
 	kfree(sd_gendisks);
 	sd_gendisks = NULL;
 cleanup_sd_gendisks:
+	kfree(sd_varyio);
+cleanup_varyio:
 	kfree(sd_max_sectors);
 cleanup_max_sectors:
 	kfree(sd_hardsizes);
@@ -1268,6 +1280,8 @@
 	return 1;
 }
 
+#define SD_DISK_MAJOR(i)	SD_MAJOR((i) >> 4)
+
 static int sd_attach(Scsi_Device * SDp)
 {
         unsigned int devnum;
@@ -1306,6 +1320,14 @@
 	printk("Attached scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n",
 	       SDp->removable ? "removable " : "",
 	       nbuff, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
+
+	if (SDp->host->hostt->can_do_varyio) {
+		if (blkdev_varyio[SD_DISK_MAJOR(i)] == NULL) {
+			blkdev_varyio[SD_DISK_MAJOR(i)] = 
+				sd_varyio + ((i / SCSI_DISKS_PER_MAJOR) << 8);
+		}
+		memset(blkdev_varyio[SD_DISK_MAJOR(i)] + (devnum << 4), 1, 16);
+	}
 	return 0;
 }
 
@@ -1438,6 +1460,7 @@
 		kfree(sd_sizes);
 		kfree(sd_blocksizes);
 		kfree(sd_hardsizes);
+		kfree(sd_varyio);
 		for (i = 0; i < N_USED_SD_MAJORS; i++) {
 #if 0 /* XXX aren't we forgetting to deallocate something? */
 			kfree(sd_gendisks[i].de_arr);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/sd.h linux.20pre10-ac2/drivers/scsi/sd.h
--- linux.20pre10/drivers/scsi/sd.h	2002-10-09 21:36:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/sd.h	2002-10-11 00:35:04.000000000 +0100
@@ -24,13 +24,13 @@
 #endif
 
 typedef struct scsi_disk {
-	unsigned capacity;	/* size in blocks */
 	Scsi_Device *device;
-	unsigned char ready;	/* flag ready for FLOPTICAL */
-	unsigned char write_prot;	/* flag write_protect for rmvable dev */
-	unsigned char sector_bit_size;	/* sector_size = 2 to the  bit size power */
-	unsigned char sector_bit_shift;		/* power of 2 sectors per FS block */
+	unsigned capacity;		/* size in blocks */
+	unsigned char sector_bit_size;	/* sector_size = 2 to the bit size power */
+	unsigned char sector_bit_shift;	/* power of 2 sectors per FS block */
 	unsigned has_part_table:1;	/* has partition table */
+	unsigned ready:1;		/* flag ready for FLOPTICAL */
+	unsigned write_prot:1;		/* flag write_protect for rmvable dev */
 } Scsi_Disk;
 
 extern int revalidate_scsidisk(kdev_t dev, int maxusage);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/scsi/sim710_d.h linux.20pre10-ac2/drivers/scsi/sim710_d.h
--- linux.20pre10/drivers/scsi/sim710_d.h	2002-10-09 21:36:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/scsi/sim710_d.h	2002-08-06 15:42:07.000000000 +0100
@@ -18,15 +18,12 @@
 
 ABSOLUTE reselected_identify = 0
 ABSOLUTE msgin_buf = 0
+ABSOLUTE msg_reject = 0
+ABSOLUTE test1_src = 0
+ABSOLUTE test1_dst = 0
 
 
 
-ABSOLUTE int_bad_extmsg1a	= 0xab930000
-ABSOLUTE int_bad_extmsg1b	= 0xab930001
-ABSOLUTE int_bad_extmsg2a	= 0xab930002
-ABSOLUTE int_bad_extmsg2b	= 0xab930003
-ABSOLUTE int_bad_extmsg3a	= 0xab930004
-ABSOLUTE int_bad_extmsg3b	= 0xab930005
 ABSOLUTE int_bad_msg1		= 0xab930006
 ABSOLUTE int_bad_msg2		= 0xab930007
 ABSOLUTE int_bad_msg3		= 0xab930008
@@ -50,7 +47,7 @@
 ABSOLUTE int_disc2		= 0xab93001a
 ABSOLUTE int_disc3		= 0xab93001b
 ABSOLUTE int_not_rej		= 0xab93001c
-
+ABSOLUTE int_test1		= 0xab93001d
 
 
 
@@ -65,6 +62,9 @@
 
 
 
+ABSOLUTE did_reject	= 0x01
+
+
 
 
 
@@ -74,1641 +74,1709 @@
 
 at 0x00000000 : */	0x60000200,0x00000000,
 /*
-	MOVE SCRATCH0 & 0 TO SCRATCH0
-
-at 0x00000002 : */	0x7c340000,0x00000000,
-/*
 	; Enable selection timer
 	MOVE CTEST7 & 0xef TO CTEST7
 
-at 0x00000004 : */	0x7c1bef00,0x00000000,
+at 0x00000002 : */	0x7c1bef00,0x00000000,
 /*
 	SELECT ATN FROM dsa_select, reselect
 
-at 0x00000006 : */	0x43000000,0x00000c48,
+at 0x00000004 : */	0x43000000,0x00000cd0,
 /*
 	JUMP get_status, WHEN STATUS
 
-at 0x00000008 : */	0x830b0000,0x000000a0,
+at 0x00000006 : */	0x830b0000,0x00000098,
 /*
 	; Disable selection timer
 	MOVE CTEST7 | 0x10 TO CTEST7
 
-at 0x0000000a : */	0x7a1b1000,0x00000000,
+at 0x00000008 : */	0x7a1b1000,0x00000000,
 /*
 	MOVE SCRATCH0 | had_select TO SCRATCH0
 
-at 0x0000000c : */	0x7a340100,0x00000000,
+at 0x0000000a : */	0x7a340100,0x00000000,
 /*
 	INT int_sel_no_ident, IF NOT MSG_OUT
 
-at 0x0000000e : */	0x9e020000,0xab930013,
+at 0x0000000c : */	0x9e020000,0xab930013,
 /*
 	MOVE SCRATCH0 | had_msgout TO SCRATCH0
 
-at 0x00000010 : */	0x7a340200,0x00000000,
+at 0x0000000e : */	0x7a340200,0x00000000,
 /*
 	MOVE FROM dsa_msgout, when MSG_OUT
 
-at 0x00000012 : */	0x1e000000,0x00000008,
+at 0x00000010 : */	0x1e000000,0x00000008,
 /*
 ENTRY done_ident
 done_ident:
 	JUMP get_status, IF STATUS
 
-at 0x00000014 : */	0x830a0000,0x000000a0,
+at 0x00000012 : */	0x830a0000,0x00000098,
 /*
 redo_msgin1:
 	JUMP get_msgin1, WHEN MSG_IN
 
-at 0x00000016 : */	0x870b0000,0x00000920,
+at 0x00000014 : */	0x870b0000,0x00000918,
 /*
 	INT int_sel_not_cmd, IF NOT CMD
 
-at 0x00000018 : */	0x9a020000,0xab930014,
+at 0x00000016 : */	0x9a020000,0xab930014,
 /*
 ENTRY resume_cmd
 resume_cmd:
 	MOVE SCRATCH0 | had_cmdout TO SCRATCH0
 
-at 0x0000001a : */	0x7a340400,0x00000000,
+at 0x00000018 : */	0x7a340400,0x00000000,
 /*
 	MOVE FROM dsa_cmnd, WHEN CMD
 
-at 0x0000001c : */	0x1a000000,0x00000010,
+at 0x0000001a : */	0x1a000000,0x00000010,
 /*
 ENTRY resume_pmm
 resume_pmm:
 redo_msgin2:
 	JUMP get_msgin2, WHEN MSG_IN
 
-at 0x0000001e : */	0x870b0000,0x00000a20,
+at 0x0000001c : */	0x870b0000,0x00000a48,
 /*
 	JUMP get_status, IF STATUS
 
-at 0x00000020 : */	0x830a0000,0x000000a0,
+at 0x0000001e : */	0x830a0000,0x00000098,
 /*
 	JUMP input_data, IF DATA_IN
 
-at 0x00000022 : */	0x810a0000,0x000000e0,
+at 0x00000020 : */	0x810a0000,0x000000d8,
 /*
 	JUMP output_data, IF DATA_OUT
 
-at 0x00000024 : */	0x800a0000,0x000004f8,
+at 0x00000022 : */	0x800a0000,0x000004f0,
 /*
 	INT int_cmd_bad_phase
 
-at 0x00000026 : */	0x98080000,0xab930009,
+at 0x00000024 : */	0x98080000,0xab930009,
 /*
 
 get_status:
 	; Disable selection timer
 	MOVE CTEST7 | 0x10 TO CTEST7
 
-at 0x00000028 : */	0x7a1b1000,0x00000000,
+at 0x00000026 : */	0x7a1b1000,0x00000000,
 /*
 	MOVE FROM dsa_status, WHEN STATUS
 
-at 0x0000002a : */	0x1b000000,0x00000018,
+at 0x00000028 : */	0x1b000000,0x00000018,
 /*
 	INT int_status_not_msgin, WHEN NOT MSG_IN
 
-at 0x0000002c : */	0x9f030000,0xab930015,
+at 0x0000002a : */	0x9f030000,0xab930015,
 /*
 	MOVE FROM dsa_msgin, WHEN MSG_IN
 
-at 0x0000002e : */	0x1f000000,0x00000020,
+at 0x0000002c : */	0x1f000000,0x00000020,
 /*
 	INT int_not_cmd_complete, IF NOT 0x00
 
-at 0x00000030 : */	0x98040000,0xab930012,
+at 0x0000002e : */	0x98040000,0xab930012,
 /*
 	CLEAR ACK
 
-at 0x00000032 : */	0x60000040,0x00000000,
+at 0x00000030 : */	0x60000040,0x00000000,
 /*
 ENTRY wait_disc_complete
 wait_disc_complete:
 	WAIT DISCONNECT
 
-at 0x00000034 : */	0x48000000,0x00000000,
+at 0x00000032 : */	0x48000000,0x00000000,
 /*
 	INT int_cmd_complete
 
-at 0x00000036 : */	0x98080000,0xab93000a,
+at 0x00000034 : */	0x98080000,0xab93000a,
 /*
 
 input_data:
 	MOVE SCRATCH0 | had_datain TO SCRATCH0
 
-at 0x00000038 : */	0x7a340800,0x00000000,
+at 0x00000036 : */	0x7a340800,0x00000000,
 /*
 ENTRY patch_input_data
 patch_input_data:
 	JUMP 0
 
-at 0x0000003a : */	0x80080000,0x00000000,
+at 0x00000038 : */	0x80080000,0x00000000,
 /*
 	MOVE FROM dsa_datain+0x0000, WHEN DATA_IN
 
-at 0x0000003c : */	0x19000000,0x00000028,
+at 0x0000003a : */	0x19000000,0x00000028,
 /*
 	MOVE FROM dsa_datain+0x0008, WHEN DATA_IN
 
-at 0x0000003e : */	0x19000000,0x00000030,
+at 0x0000003c : */	0x19000000,0x00000030,
 /*
 	MOVE FROM dsa_datain+0x0010, WHEN DATA_IN
 
-at 0x00000040 : */	0x19000000,0x00000038,
+at 0x0000003e : */	0x19000000,0x00000038,
 /*
 	MOVE FROM dsa_datain+0x0018, WHEN DATA_IN
 
-at 0x00000042 : */	0x19000000,0x00000040,
+at 0x00000040 : */	0x19000000,0x00000040,
 /*
 	MOVE FROM dsa_datain+0x0020, WHEN DATA_IN
 
-at 0x00000044 : */	0x19000000,0x00000048,
+at 0x00000042 : */	0x19000000,0x00000048,
 /*
 	MOVE FROM dsa_datain+0x0028, WHEN DATA_IN
 
-at 0x00000046 : */	0x19000000,0x00000050,
+at 0x00000044 : */	0x19000000,0x00000050,
 /*
 	MOVE FROM dsa_datain+0x0030, WHEN DATA_IN
 
-at 0x00000048 : */	0x19000000,0x00000058,
+at 0x00000046 : */	0x19000000,0x00000058,
 /*
 	MOVE FROM dsa_datain+0x0038, WHEN DATA_IN
 
-at 0x0000004a : */	0x19000000,0x00000060,
+at 0x00000048 : */	0x19000000,0x00000060,
 /*
 	MOVE FROM dsa_datain+0x0040, WHEN DATA_IN
 
-at 0x0000004c : */	0x19000000,0x00000068,
+at 0x0000004a : */	0x19000000,0x00000068,
 /*
 	MOVE FROM dsa_datain+0x0048, WHEN DATA_IN
 
-at 0x0000004e : */	0x19000000,0x00000070,
+at 0x0000004c : */	0x19000000,0x00000070,
 /*
 	MOVE FROM dsa_datain+0x0050, WHEN DATA_IN
 
-at 0x00000050 : */	0x19000000,0x00000078,
+at 0x0000004e : */	0x19000000,0x00000078,
 /*
 	MOVE FROM dsa_datain+0x0058, WHEN DATA_IN
 
-at 0x00000052 : */	0x19000000,0x00000080,
+at 0x00000050 : */	0x19000000,0x00000080,
 /*
 	MOVE FROM dsa_datain+0x0060, WHEN DATA_IN
 
-at 0x00000054 : */	0x19000000,0x00000088,
+at 0x00000052 : */	0x19000000,0x00000088,
 /*
 	MOVE FROM dsa_datain+0x0068, WHEN DATA_IN
 
-at 0x00000056 : */	0x19000000,0x00000090,
+at 0x00000054 : */	0x19000000,0x00000090,
 /*
 	MOVE FROM dsa_datain+0x0070, WHEN DATA_IN
 
-at 0x00000058 : */	0x19000000,0x00000098,
+at 0x00000056 : */	0x19000000,0x00000098,
 /*
 	MOVE FROM dsa_datain+0x0078, WHEN DATA_IN
 
-at 0x0000005a : */	0x19000000,0x000000a0,
+at 0x00000058 : */	0x19000000,0x000000a0,
 /*
 	MOVE FROM dsa_datain+0x0080, WHEN DATA_IN
 
-at 0x0000005c : */	0x19000000,0x000000a8,
+at 0x0000005a : */	0x19000000,0x000000a8,
 /*
 	MOVE FROM dsa_datain+0x0088, WHEN DATA_IN
 
-at 0x0000005e : */	0x19000000,0x000000b0,
+at 0x0000005c : */	0x19000000,0x000000b0,
 /*
 	MOVE FROM dsa_datain+0x0090, WHEN DATA_IN
 
-at 0x00000060 : */	0x19000000,0x000000b8,
+at 0x0000005e : */	0x19000000,0x000000b8,
 /*
 	MOVE FROM dsa_datain+0x0098, WHEN DATA_IN
 
-at 0x00000062 : */	0x19000000,0x000000c0,
+at 0x00000060 : */	0x19000000,0x000000c0,
 /*
 	MOVE FROM dsa_datain+0x00a0, WHEN DATA_IN
 
-at 0x00000064 : */	0x19000000,0x000000c8,
+at 0x00000062 : */	0x19000000,0x000000c8,
 /*
 	MOVE FROM dsa_datain+0x00a8, WHEN DATA_IN
 
-at 0x00000066 : */	0x19000000,0x000000d0,
+at 0x00000064 : */	0x19000000,0x000000d0,
 /*
 	MOVE FROM dsa_datain+0x00b0, WHEN DATA_IN
 
-at 0x00000068 : */	0x19000000,0x000000d8,
+at 0x00000066 : */	0x19000000,0x000000d8,
 /*
 	MOVE FROM dsa_datain+0x00b8, WHEN DATA_IN
 
-at 0x0000006a : */	0x19000000,0x000000e0,
+at 0x00000068 : */	0x19000000,0x000000e0,
 /*
 	MOVE FROM dsa_datain+0x00c0, WHEN DATA_IN
 
-at 0x0000006c : */	0x19000000,0x000000e8,
+at 0x0000006a : */	0x19000000,0x000000e8,
 /*
 	MOVE FROM dsa_datain+0x00c8, WHEN DATA_IN
 
-at 0x0000006e : */	0x19000000,0x000000f0,
+at 0x0000006c : */	0x19000000,0x000000f0,
 /*
 	MOVE FROM dsa_datain+0x00d0, WHEN DATA_IN
 
-at 0x00000070 : */	0x19000000,0x000000f8,
+at 0x0000006e : */	0x19000000,0x000000f8,
 /*
 	MOVE FROM dsa_datain+0x00d8, WHEN DATA_IN
 
-at 0x00000072 : */	0x19000000,0x00000100,
+at 0x00000070 : */	0x19000000,0x00000100,
 /*
 	MOVE FROM dsa_datain+0x00e0, WHEN DATA_IN
 
-at 0x00000074 : */	0x19000000,0x00000108,
+at 0x00000072 : */	0x19000000,0x00000108,
 /*
 	MOVE FROM dsa_datain+0x00e8, WHEN DATA_IN
 
-at 0x00000076 : */	0x19000000,0x00000110,
+at 0x00000074 : */	0x19000000,0x00000110,
 /*
 	MOVE FROM dsa_datain+0x00f0, WHEN DATA_IN
 
-at 0x00000078 : */	0x19000000,0x00000118,
+at 0x00000076 : */	0x19000000,0x00000118,
 /*
 	MOVE FROM dsa_datain+0x00f8, WHEN DATA_IN
 
-at 0x0000007a : */	0x19000000,0x00000120,
+at 0x00000078 : */	0x19000000,0x00000120,
 /*
 	MOVE FROM dsa_datain+0x0100, WHEN DATA_IN
 
-at 0x0000007c : */	0x19000000,0x00000128,
+at 0x0000007a : */	0x19000000,0x00000128,
 /*
 	MOVE FROM dsa_datain+0x0108, WHEN DATA_IN
 
-at 0x0000007e : */	0x19000000,0x00000130,
+at 0x0000007c : */	0x19000000,0x00000130,
 /*
 	MOVE FROM dsa_datain+0x0110, WHEN DATA_IN
 
-at 0x00000080 : */	0x19000000,0x00000138,
+at 0x0000007e : */	0x19000000,0x00000138,
 /*
 	MOVE FROM dsa_datain+0x0118, WHEN DATA_IN
 
-at 0x00000082 : */	0x19000000,0x00000140,
+at 0x00000080 : */	0x19000000,0x00000140,
 /*
 	MOVE FROM dsa_datain+0x0120, WHEN DATA_IN
 
-at 0x00000084 : */	0x19000000,0x00000148,
+at 0x00000082 : */	0x19000000,0x00000148,
 /*
 	MOVE FROM dsa_datain+0x0128, WHEN DATA_IN
 
-at 0x00000086 : */	0x19000000,0x00000150,
+at 0x00000084 : */	0x19000000,0x00000150,
 /*
 	MOVE FROM dsa_datain+0x0130, WHEN DATA_IN
 
-at 0x00000088 : */	0x19000000,0x00000158,
+at 0x00000086 : */	0x19000000,0x00000158,
 /*
 	MOVE FROM dsa_datain+0x0138, WHEN DATA_IN
 
-at 0x0000008a : */	0x19000000,0x00000160,
+at 0x00000088 : */	0x19000000,0x00000160,
 /*
 	MOVE FROM dsa_datain+0x0140, WHEN DATA_IN
 
-at 0x0000008c : */	0x19000000,0x00000168,
+at 0x0000008a : */	0x19000000,0x00000168,
 /*
 	MOVE FROM dsa_datain+0x0148, WHEN DATA_IN
 
-at 0x0000008e : */	0x19000000,0x00000170,
+at 0x0000008c : */	0x19000000,0x00000170,
 /*
 	MOVE FROM dsa_datain+0x0150, WHEN DATA_IN
 
-at 0x00000090 : */	0x19000000,0x00000178,
+at 0x0000008e : */	0x19000000,0x00000178,
 /*
 	MOVE FROM dsa_datain+0x0158, WHEN DATA_IN
 
-at 0x00000092 : */	0x19000000,0x00000180,
+at 0x00000090 : */	0x19000000,0x00000180,
 /*
 	MOVE FROM dsa_datain+0x0160, WHEN DATA_IN
 
-at 0x00000094 : */	0x19000000,0x00000188,
+at 0x00000092 : */	0x19000000,0x00000188,
 /*
 	MOVE FROM dsa_datain+0x0168, WHEN DATA_IN
 
-at 0x00000096 : */	0x19000000,0x00000190,
+at 0x00000094 : */	0x19000000,0x00000190,
 /*
 	MOVE FROM dsa_datain+0x0170, WHEN DATA_IN
 
-at 0x00000098 : */	0x19000000,0x00000198,
+at 0x00000096 : */	0x19000000,0x00000198,
 /*
 	MOVE FROM dsa_datain+0x0178, WHEN DATA_IN
 
-at 0x0000009a : */	0x19000000,0x000001a0,
+at 0x00000098 : */	0x19000000,0x000001a0,
 /*
 	MOVE FROM dsa_datain+0x0180, WHEN DATA_IN
 
-at 0x0000009c : */	0x19000000,0x000001a8,
+at 0x0000009a : */	0x19000000,0x000001a8,
 /*
 	MOVE FROM dsa_datain+0x0188, WHEN DATA_IN
 
-at 0x0000009e : */	0x19000000,0x000001b0,
+at 0x0000009c : */	0x19000000,0x000001b0,
 /*
 	MOVE FROM dsa_datain+0x0190, WHEN DATA_IN
 
-at 0x000000a0 : */	0x19000000,0x000001b8,
+at 0x0000009e : */	0x19000000,0x000001b8,
 /*
 	MOVE FROM dsa_datain+0x0198, WHEN DATA_IN
 
-at 0x000000a2 : */	0x19000000,0x000001c0,
+at 0x000000a0 : */	0x19000000,0x000001c0,
 /*
 	MOVE FROM dsa_datain+0x01a0, WHEN DATA_IN
 
-at 0x000000a4 : */	0x19000000,0x000001c8,
+at 0x000000a2 : */	0x19000000,0x000001c8,
 /*
 	MOVE FROM dsa_datain+0x01a8, WHEN DATA_IN
 
-at 0x000000a6 : */	0x19000000,0x000001d0,
+at 0x000000a4 : */	0x19000000,0x000001d0,
 /*
 	MOVE FROM dsa_datain+0x01b0, WHEN DATA_IN
 
-at 0x000000a8 : */	0x19000000,0x000001d8,
+at 0x000000a6 : */	0x19000000,0x000001d8,
 /*
 	MOVE FROM dsa_datain+0x01b8, WHEN DATA_IN
 
-at 0x000000aa : */	0x19000000,0x000001e0,
+at 0x000000a8 : */	0x19000000,0x000001e0,
 /*
 	MOVE FROM dsa_datain+0x01c0, WHEN DATA_IN
 
-at 0x000000ac : */	0x19000000,0x000001e8,
+at 0x000000aa : */	0x19000000,0x000001e8,
 /*
 	MOVE FROM dsa_datain+0x01c8, WHEN DATA_IN
 
-at 0x000000ae : */	0x19000000,0x000001f0,
+at 0x000000ac : */	0x19000000,0x000001f0,
 /*
 	MOVE FROM dsa_datain+0x01d0, WHEN DATA_IN
 
-at 0x000000b0 : */	0x19000000,0x000001f8,
+at 0x000000ae : */	0x19000000,0x000001f8,
 /*
 	MOVE FROM dsa_datain+0x01d8, WHEN DATA_IN
 
-at 0x000000b2 : */	0x19000000,0x00000200,
+at 0x000000b0 : */	0x19000000,0x00000200,
 /*
 	MOVE FROM dsa_datain+0x01e0, WHEN DATA_IN
 
-at 0x000000b4 : */	0x19000000,0x00000208,
+at 0x000000b2 : */	0x19000000,0x00000208,
 /*
 	MOVE FROM dsa_datain+0x01e8, WHEN DATA_IN
 
-at 0x000000b6 : */	0x19000000,0x00000210,
+at 0x000000b4 : */	0x19000000,0x00000210,
 /*
 	MOVE FROM dsa_datain+0x01f0, WHEN DATA_IN
 
-at 0x000000b8 : */	0x19000000,0x00000218,
+at 0x000000b6 : */	0x19000000,0x00000218,
 /*
 	MOVE FROM dsa_datain+0x01f8, WHEN DATA_IN
 
-at 0x000000ba : */	0x19000000,0x00000220,
+at 0x000000b8 : */	0x19000000,0x00000220,
 /*
 	MOVE FROM dsa_datain+0x0200, WHEN DATA_IN
 
-at 0x000000bc : */	0x19000000,0x00000228,
+at 0x000000ba : */	0x19000000,0x00000228,
 /*
 	MOVE FROM dsa_datain+0x0208, WHEN DATA_IN
 
-at 0x000000be : */	0x19000000,0x00000230,
+at 0x000000bc : */	0x19000000,0x00000230,
 /*
 	MOVE FROM dsa_datain+0x0210, WHEN DATA_IN
 
-at 0x000000c0 : */	0x19000000,0x00000238,
+at 0x000000be : */	0x19000000,0x00000238,
 /*
 	MOVE FROM dsa_datain+0x0218, WHEN DATA_IN
 
-at 0x000000c2 : */	0x19000000,0x00000240,
+at 0x000000c0 : */	0x19000000,0x00000240,
 /*
 	MOVE FROM dsa_datain+0x0220, WHEN DATA_IN
 
-at 0x000000c4 : */	0x19000000,0x00000248,
+at 0x000000c2 : */	0x19000000,0x00000248,
 /*
 	MOVE FROM dsa_datain+0x0228, WHEN DATA_IN
 
-at 0x000000c6 : */	0x19000000,0x00000250,
+at 0x000000c4 : */	0x19000000,0x00000250,
 /*
 	MOVE FROM dsa_datain+0x0230, WHEN DATA_IN
 
-at 0x000000c8 : */	0x19000000,0x00000258,
+at 0x000000c6 : */	0x19000000,0x00000258,
 /*
 	MOVE FROM dsa_datain+0x0238, WHEN DATA_IN
 
-at 0x000000ca : */	0x19000000,0x00000260,
+at 0x000000c8 : */	0x19000000,0x00000260,
 /*
 	MOVE FROM dsa_datain+0x0240, WHEN DATA_IN
 
-at 0x000000cc : */	0x19000000,0x00000268,
+at 0x000000ca : */	0x19000000,0x00000268,
 /*
 	MOVE FROM dsa_datain+0x0248, WHEN DATA_IN
 
-at 0x000000ce : */	0x19000000,0x00000270,
+at 0x000000cc : */	0x19000000,0x00000270,
 /*
 	MOVE FROM dsa_datain+0x0250, WHEN DATA_IN
 
-at 0x000000d0 : */	0x19000000,0x00000278,
+at 0x000000ce : */	0x19000000,0x00000278,
 /*
 	MOVE FROM dsa_datain+0x0258, WHEN DATA_IN
 
-at 0x000000d2 : */	0x19000000,0x00000280,
+at 0x000000d0 : */	0x19000000,0x00000280,
 /*
 	MOVE FROM dsa_datain+0x0260, WHEN DATA_IN
 
-at 0x000000d4 : */	0x19000000,0x00000288,
+at 0x000000d2 : */	0x19000000,0x00000288,
 /*
 	MOVE FROM dsa_datain+0x0268, WHEN DATA_IN
 
-at 0x000000d6 : */	0x19000000,0x00000290,
+at 0x000000d4 : */	0x19000000,0x00000290,
 /*
 	MOVE FROM dsa_datain+0x0270, WHEN DATA_IN
 
-at 0x000000d8 : */	0x19000000,0x00000298,
+at 0x000000d6 : */	0x19000000,0x00000298,
 /*
 	MOVE FROM dsa_datain+0x0278, WHEN DATA_IN
 
-at 0x000000da : */	0x19000000,0x000002a0,
+at 0x000000d8 : */	0x19000000,0x000002a0,
 /*
 	MOVE FROM dsa_datain+0x0280, WHEN DATA_IN
 
-at 0x000000dc : */	0x19000000,0x000002a8,
+at 0x000000da : */	0x19000000,0x000002a8,
 /*
 	MOVE FROM dsa_datain+0x0288, WHEN DATA_IN
 
-at 0x000000de : */	0x19000000,0x000002b0,
+at 0x000000dc : */	0x19000000,0x000002b0,
 /*
 	MOVE FROM dsa_datain+0x0290, WHEN DATA_IN
 
-at 0x000000e0 : */	0x19000000,0x000002b8,
+at 0x000000de : */	0x19000000,0x000002b8,
 /*
 	MOVE FROM dsa_datain+0x0298, WHEN DATA_IN
 
-at 0x000000e2 : */	0x19000000,0x000002c0,
+at 0x000000e0 : */	0x19000000,0x000002c0,
 /*
 	MOVE FROM dsa_datain+0x02a0, WHEN DATA_IN
 
-at 0x000000e4 : */	0x19000000,0x000002c8,
+at 0x000000e2 : */	0x19000000,0x000002c8,
 /*
 	MOVE FROM dsa_datain+0x02a8, WHEN DATA_IN
 
-at 0x000000e6 : */	0x19000000,0x000002d0,
+at 0x000000e4 : */	0x19000000,0x000002d0,
 /*
 	MOVE FROM dsa_datain+0x02b0, WHEN DATA_IN
 
-at 0x000000e8 : */	0x19000000,0x000002d8,
+at 0x000000e6 : */	0x19000000,0x000002d8,
 /*
 	MOVE FROM dsa_datain+0x02b8, WHEN DATA_IN
 
-at 0x000000ea : */	0x19000000,0x000002e0,
+at 0x000000e8 : */	0x19000000,0x000002e0,
 /*
 	MOVE FROM dsa_datain+0x02c0, WHEN DATA_IN
 
-at 0x000000ec : */	0x19000000,0x000002e8,
+at 0x000000ea : */	0x19000000,0x000002e8,
 /*
 	MOVE FROM dsa_datain+0x02c8, WHEN DATA_IN
 
-at 0x000000ee : */	0x19000000,0x000002f0,
+at 0x000000ec : */	0x19000000,0x000002f0,
 /*
 	MOVE FROM dsa_datain+0x02d0, WHEN DATA_IN
 
-at 0x000000f0 : */	0x19000000,0x000002f8,
+at 0x000000ee : */	0x19000000,0x000002f8,
 /*
 	MOVE FROM dsa_datain+0x02d8, WHEN DATA_IN
 
-at 0x000000f2 : */	0x19000000,0x00000300,
+at 0x000000f0 : */	0x19000000,0x00000300,
 /*
 	MOVE FROM dsa_datain+0x02e0, WHEN DATA_IN
 
-at 0x000000f4 : */	0x19000000,0x00000308,
+at 0x000000f2 : */	0x19000000,0x00000308,
 /*
 	MOVE FROM dsa_datain+0x02e8, WHEN DATA_IN
 
-at 0x000000f6 : */	0x19000000,0x00000310,
+at 0x000000f4 : */	0x19000000,0x00000310,
 /*
 	MOVE FROM dsa_datain+0x02f0, WHEN DATA_IN
 
-at 0x000000f8 : */	0x19000000,0x00000318,
+at 0x000000f6 : */	0x19000000,0x00000318,
 /*
 	MOVE FROM dsa_datain+0x02f8, WHEN DATA_IN
 
-at 0x000000fa : */	0x19000000,0x00000320,
+at 0x000000f8 : */	0x19000000,0x00000320,
 /*
 	MOVE FROM dsa_datain+0x0300, WHEN DATA_IN
 
-at 0x000000fc : */	0x19000000,0x00000328,
+at 0x000000fa : */	0x19000000,0x00000328,
 /*
 	MOVE FROM dsa_datain+0x0308, WHEN DATA_IN
 
-at 0x000000fe : */	0x19000000,0x00000330,
+at 0x000000fc : */	0x19000000,0x00000330,
 /*
 	MOVE FROM dsa_datain+0x0310, WHEN DATA_IN
 
-at 0x00000100 : */	0x19000000,0x00000338,
+at 0x000000fe : */	0x19000000,0x00000338,
 /*
 	MOVE FROM dsa_datain+0x0318, WHEN DATA_IN
 
-at 0x00000102 : */	0x19000000,0x00000340,
+at 0x00000100 : */	0x19000000,0x00000340,
 /*
 	MOVE FROM dsa_datain+0x0320, WHEN DATA_IN
 
-at 0x00000104 : */	0x19000000,0x00000348,
+at 0x00000102 : */	0x19000000,0x00000348,
 /*
 	MOVE FROM dsa_datain+0x0328, WHEN DATA_IN
 
-at 0x00000106 : */	0x19000000,0x00000350,
+at 0x00000104 : */	0x19000000,0x00000350,
 /*
 	MOVE FROM dsa_datain+0x0330, WHEN DATA_IN
 
-at 0x00000108 : */	0x19000000,0x00000358,
+at 0x00000106 : */	0x19000000,0x00000358,
 /*
 	MOVE FROM dsa_datain+0x0338, WHEN DATA_IN
 
-at 0x0000010a : */	0x19000000,0x00000360,
+at 0x00000108 : */	0x19000000,0x00000360,
 /*
 	MOVE FROM dsa_datain+0x0340, WHEN DATA_IN
 
-at 0x0000010c : */	0x19000000,0x00000368,
+at 0x0000010a : */	0x19000000,0x00000368,
 /*
 	MOVE FROM dsa_datain+0x0348, WHEN DATA_IN
 
-at 0x0000010e : */	0x19000000,0x00000370,
+at 0x0000010c : */	0x19000000,0x00000370,
 /*
 	MOVE FROM dsa_datain+0x0350, WHEN DATA_IN
 
-at 0x00000110 : */	0x19000000,0x00000378,
+at 0x0000010e : */	0x19000000,0x00000378,
 /*
 	MOVE FROM dsa_datain+0x0358, WHEN DATA_IN
 
-at 0x00000112 : */	0x19000000,0x00000380,
+at 0x00000110 : */	0x19000000,0x00000380,
 /*
 	MOVE FROM dsa_datain+0x0360, WHEN DATA_IN
 
-at 0x00000114 : */	0x19000000,0x00000388,
+at 0x00000112 : */	0x19000000,0x00000388,
 /*
 	MOVE FROM dsa_datain+0x0368, WHEN DATA_IN
 
-at 0x00000116 : */	0x19000000,0x00000390,
+at 0x00000114 : */	0x19000000,0x00000390,
 /*
 	MOVE FROM dsa_datain+0x0370, WHEN DATA_IN
 
-at 0x00000118 : */	0x19000000,0x00000398,
+at 0x00000116 : */	0x19000000,0x00000398,
 /*
 	MOVE FROM dsa_datain+0x0378, WHEN DATA_IN
 
-at 0x0000011a : */	0x19000000,0x000003a0,
+at 0x00000118 : */	0x19000000,0x000003a0,
 /*
 	MOVE FROM dsa_datain+0x0380, WHEN DATA_IN
 
-at 0x0000011c : */	0x19000000,0x000003a8,
+at 0x0000011a : */	0x19000000,0x000003a8,
 /*
 	MOVE FROM dsa_datain+0x0388, WHEN DATA_IN
 
-at 0x0000011e : */	0x19000000,0x000003b0,
+at 0x0000011c : */	0x19000000,0x000003b0,
 /*
 	MOVE FROM dsa_datain+0x0390, WHEN DATA_IN
 
-at 0x00000120 : */	0x19000000,0x000003b8,
+at 0x0000011e : */	0x19000000,0x000003b8,
 /*
 	MOVE FROM dsa_datain+0x0398, WHEN DATA_IN
 
-at 0x00000122 : */	0x19000000,0x000003c0,
+at 0x00000120 : */	0x19000000,0x000003c0,
 /*
 	MOVE FROM dsa_datain+0x03a0, WHEN DATA_IN
 
-at 0x00000124 : */	0x19000000,0x000003c8,
+at 0x00000122 : */	0x19000000,0x000003c8,
 /*
 	MOVE FROM dsa_datain+0x03a8, WHEN DATA_IN
 
-at 0x00000126 : */	0x19000000,0x000003d0,
+at 0x00000124 : */	0x19000000,0x000003d0,
 /*
 	MOVE FROM dsa_datain+0x03b0, WHEN DATA_IN
 
-at 0x00000128 : */	0x19000000,0x000003d8,
+at 0x00000126 : */	0x19000000,0x000003d8,
 /*
 	MOVE FROM dsa_datain+0x03b8, WHEN DATA_IN
 
-at 0x0000012a : */	0x19000000,0x000003e0,
+at 0x00000128 : */	0x19000000,0x000003e0,
 /*
 	MOVE FROM dsa_datain+0x03c0, WHEN DATA_IN
 
-at 0x0000012c : */	0x19000000,0x000003e8,
+at 0x0000012a : */	0x19000000,0x000003e8,
 /*
 	MOVE FROM dsa_datain+0x03c8, WHEN DATA_IN
 
-at 0x0000012e : */	0x19000000,0x000003f0,
+at 0x0000012c : */	0x19000000,0x000003f0,
 /*
 	MOVE FROM dsa_datain+0x03d0, WHEN DATA_IN
 
-at 0x00000130 : */	0x19000000,0x000003f8,
+at 0x0000012e : */	0x19000000,0x000003f8,
 /*
 	MOVE FROM dsa_datain+0x03d8, WHEN DATA_IN
 
-at 0x00000132 : */	0x19000000,0x00000400,
+at 0x00000130 : */	0x19000000,0x00000400,
 /*
 	MOVE FROM dsa_datain+0x03e0, WHEN DATA_IN
 
-at 0x00000134 : */	0x19000000,0x00000408,
+at 0x00000132 : */	0x19000000,0x00000408,
 /*
 	MOVE FROM dsa_datain+0x03e8, WHEN DATA_IN
 
-at 0x00000136 : */	0x19000000,0x00000410,
+at 0x00000134 : */	0x19000000,0x00000410,
 /*
 	MOVE FROM dsa_datain+0x03f0, WHEN DATA_IN
 
-at 0x00000138 : */	0x19000000,0x00000418,
+at 0x00000136 : */	0x19000000,0x00000418,
 /*
 	MOVE FROM dsa_datain+0x03f8, WHEN DATA_IN
 
-at 0x0000013a : */	0x19000000,0x00000420,
+at 0x00000138 : */	0x19000000,0x00000420,
 /*
 	JUMP end_data_trans
 
-at 0x0000013c : */	0x80080000,0x00000908,
+at 0x0000013a : */	0x80080000,0x00000900,
 /*
 
 output_data:
 	MOVE SCRATCH0 | had_dataout TO SCRATCH0
 
-at 0x0000013e : */	0x7a341000,0x00000000,
+at 0x0000013c : */	0x7a341000,0x00000000,
 /*
 ENTRY patch_output_data
 patch_output_data:
 	JUMP 0
 
-at 0x00000140 : */	0x80080000,0x00000000,
+at 0x0000013e : */	0x80080000,0x00000000,
 /*
 	MOVE FROM dsa_dataout+0x0000, WHEN DATA_OUT
 
-at 0x00000142 : */	0x18000000,0x00000428,
+at 0x00000140 : */	0x18000000,0x00000428,
 /*
 	MOVE FROM dsa_dataout+0x0008, WHEN DATA_OUT
 
-at 0x00000144 : */	0x18000000,0x00000430,
+at 0x00000142 : */	0x18000000,0x00000430,
 /*
 	MOVE FROM dsa_dataout+0x0010, WHEN DATA_OUT
 
-at 0x00000146 : */	0x18000000,0x00000438,
+at 0x00000144 : */	0x18000000,0x00000438,
 /*
 	MOVE FROM dsa_dataout+0x0018, WHEN DATA_OUT
 
-at 0x00000148 : */	0x18000000,0x00000440,
+at 0x00000146 : */	0x18000000,0x00000440,
 /*
 	MOVE FROM dsa_dataout+0x0020, WHEN DATA_OUT
 
-at 0x0000014a : */	0x18000000,0x00000448,
+at 0x00000148 : */	0x18000000,0x00000448,
 /*
 	MOVE FROM dsa_dataout+0x0028, WHEN DATA_OUT
 
-at 0x0000014c : */	0x18000000,0x00000450,
+at 0x0000014a : */	0x18000000,0x00000450,
 /*
 	MOVE FROM dsa_dataout+0x0030, WHEN DATA_OUT
 
-at 0x0000014e : */	0x18000000,0x00000458,
+at 0x0000014c : */	0x18000000,0x00000458,
 /*
 	MOVE FROM dsa_dataout+0x0038, WHEN DATA_OUT
 
-at 0x00000150 : */	0x18000000,0x00000460,
+at 0x0000014e : */	0x18000000,0x00000460,
 /*
 	MOVE FROM dsa_dataout+0x0040, WHEN DATA_OUT
 
-at 0x00000152 : */	0x18000000,0x00000468,
+at 0x00000150 : */	0x18000000,0x00000468,
 /*
 	MOVE FROM dsa_dataout+0x0048, WHEN DATA_OUT
 
-at 0x00000154 : */	0x18000000,0x00000470,
+at 0x00000152 : */	0x18000000,0x00000470,
 /*
 	MOVE FROM dsa_dataout+0x0050, WHEN DATA_OUT
 
-at 0x00000156 : */	0x18000000,0x00000478,
+at 0x00000154 : */	0x18000000,0x00000478,
 /*
 	MOVE FROM dsa_dataout+0x0058, WHEN DATA_OUT
 
-at 0x00000158 : */	0x18000000,0x00000480,
+at 0x00000156 : */	0x18000000,0x00000480,
 /*
 	MOVE FROM dsa_dataout+0x0060, WHEN DATA_OUT
 
-at 0x0000015a : */	0x18000000,0x00000488,
+at 0x00000158 : */	0x18000000,0x00000488,
 /*
 	MOVE FROM dsa_dataout+0x0068, WHEN DATA_OUT
 
-at 0x0000015c : */	0x18000000,0x00000490,
+at 0x0000015a : */	0x18000000,0x00000490,
 /*
 	MOVE FROM dsa_dataout+0x0070, WHEN DATA_OUT
 
-at 0x0000015e : */	0x18000000,0x00000498,
+at 0x0000015c : */	0x18000000,0x00000498,
 /*
 	MOVE FROM dsa_dataout+0x0078, WHEN DATA_OUT
 
-at 0x00000160 : */	0x18000000,0x000004a0,
+at 0x0000015e : */	0x18000000,0x000004a0,
 /*
 	MOVE FROM dsa_dataout+0x0080, WHEN DATA_OUT
 
-at 0x00000162 : */	0x18000000,0x000004a8,
+at 0x00000160 : */	0x18000000,0x000004a8,
 /*
 	MOVE FROM dsa_dataout+0x0088, WHEN DATA_OUT
 
-at 0x00000164 : */	0x18000000,0x000004b0,
+at 0x00000162 : */	0x18000000,0x000004b0,
 /*
 	MOVE FROM dsa_dataout+0x0090, WHEN DATA_OUT
 
-at 0x00000166 : */	0x18000000,0x000004b8,
+at 0x00000164 : */	0x18000000,0x000004b8,
 /*
 	MOVE FROM dsa_dataout+0x0098, WHEN DATA_OUT
 
-at 0x00000168 : */	0x18000000,0x000004c0,
+at 0x00000166 : */	0x18000000,0x000004c0,
 /*
 	MOVE FROM dsa_dataout+0x00a0, WHEN DATA_OUT
 
-at 0x0000016a : */	0x18000000,0x000004c8,
+at 0x00000168 : */	0x18000000,0x000004c8,
 /*
 	MOVE FROM dsa_dataout+0x00a8, WHEN DATA_OUT
 
-at 0x0000016c : */	0x18000000,0x000004d0,
+at 0x0000016a : */	0x18000000,0x000004d0,
 /*
 	MOVE FROM dsa_dataout+0x00b0, WHEN DATA_OUT
 
-at 0x0000016e : */	0x18000000,0x000004d8,
+at 0x0000016c : */	0x18000000,0x000004d8,
 /*
 	MOVE FROM dsa_dataout+0x00b8, WHEN DATA_OUT
 
-at 0x00000170 : */	0x18000000,0x000004e0,
+at 0x0000016e : */	0x18000000,0x000004e0,
 /*
 	MOVE FROM dsa_dataout+0x00c0, WHEN DATA_OUT
 
-at 0x00000172 : */	0x18000000,0x000004e8,
+at 0x00000170 : */	0x18000000,0x000004e8,
 /*
 	MOVE FROM dsa_dataout+0x00c8, WHEN DATA_OUT
 
-at 0x00000174 : */	0x18000000,0x000004f0,
+at 0x00000172 : */	0x18000000,0x000004f0,
 /*
 	MOVE FROM dsa_dataout+0x00d0, WHEN DATA_OUT
 
-at 0x00000176 : */	0x18000000,0x000004f8,
+at 0x00000174 : */	0x18000000,0x000004f8,
 /*
 	MOVE FROM dsa_dataout+0x00d8, WHEN DATA_OUT
 
-at 0x00000178 : */	0x18000000,0x00000500,
+at 0x00000176 : */	0x18000000,0x00000500,
 /*
 	MOVE FROM dsa_dataout+0x00e0, WHEN DATA_OUT
 
-at 0x0000017a : */	0x18000000,0x00000508,
+at 0x00000178 : */	0x18000000,0x00000508,
 /*
 	MOVE FROM dsa_dataout+0x00e8, WHEN DATA_OUT
 
-at 0x0000017c : */	0x18000000,0x00000510,
+at 0x0000017a : */	0x18000000,0x00000510,
 /*
 	MOVE FROM dsa_dataout+0x00f0, WHEN DATA_OUT
 
-at 0x0000017e : */	0x18000000,0x00000518,
+at 0x0000017c : */	0x18000000,0x00000518,
 /*
 	MOVE FROM dsa_dataout+0x00f8, WHEN DATA_OUT
 
-at 0x00000180 : */	0x18000000,0x00000520,
+at 0x0000017e : */	0x18000000,0x00000520,
 /*
 	MOVE FROM dsa_dataout+0x0100, WHEN DATA_OUT
 
-at 0x00000182 : */	0x18000000,0x00000528,
+at 0x00000180 : */	0x18000000,0x00000528,
 /*
 	MOVE FROM dsa_dataout+0x0108, WHEN DATA_OUT
 
-at 0x00000184 : */	0x18000000,0x00000530,
+at 0x00000182 : */	0x18000000,0x00000530,
 /*
 	MOVE FROM dsa_dataout+0x0110, WHEN DATA_OUT
 
-at 0x00000186 : */	0x18000000,0x00000538,
+at 0x00000184 : */	0x18000000,0x00000538,
 /*
 	MOVE FROM dsa_dataout+0x0118, WHEN DATA_OUT
 
-at 0x00000188 : */	0x18000000,0x00000540,
+at 0x00000186 : */	0x18000000,0x00000540,
 /*
 	MOVE FROM dsa_dataout+0x0120, WHEN DATA_OUT
 
-at 0x0000018a : */	0x18000000,0x00000548,
+at 0x00000188 : */	0x18000000,0x00000548,
 /*
 	MOVE FROM dsa_dataout+0x0128, WHEN DATA_OUT
 
-at 0x0000018c : */	0x18000000,0x00000550,
+at 0x0000018a : */	0x18000000,0x00000550,
 /*
 	MOVE FROM dsa_dataout+0x0130, WHEN DATA_OUT
 
-at 0x0000018e : */	0x18000000,0x00000558,
+at 0x0000018c : */	0x18000000,0x00000558,
 /*
 	MOVE FROM dsa_dataout+0x0138, WHEN DATA_OUT
 
-at 0x00000190 : */	0x18000000,0x00000560,
+at 0x0000018e : */	0x18000000,0x00000560,
 /*
 	MOVE FROM dsa_dataout+0x0140, WHEN DATA_OUT
 
-at 0x00000192 : */	0x18000000,0x00000568,
+at 0x00000190 : */	0x18000000,0x00000568,
 /*
 	MOVE FROM dsa_dataout+0x0148, WHEN DATA_OUT
 
-at 0x00000194 : */	0x18000000,0x00000570,
+at 0x00000192 : */	0x18000000,0x00000570,
 /*
 	MOVE FROM dsa_dataout+0x0150, WHEN DATA_OUT
 
-at 0x00000196 : */	0x18000000,0x00000578,
+at 0x00000194 : */	0x18000000,0x00000578,
 /*
 	MOVE FROM dsa_dataout+0x0158, WHEN DATA_OUT
 
-at 0x00000198 : */	0x18000000,0x00000580,
+at 0x00000196 : */	0x18000000,0x00000580,
 /*
 	MOVE FROM dsa_dataout+0x0160, WHEN DATA_OUT
 
-at 0x0000019a : */	0x18000000,0x00000588,
+at 0x00000198 : */	0x18000000,0x00000588,
 /*
 	MOVE FROM dsa_dataout+0x0168, WHEN DATA_OUT
 
-at 0x0000019c : */	0x18000000,0x00000590,
+at 0x0000019a : */	0x18000000,0x00000590,
 /*
 	MOVE FROM dsa_dataout+0x0170, WHEN DATA_OUT
 
-at 0x0000019e : */	0x18000000,0x00000598,
+at 0x0000019c : */	0x18000000,0x00000598,
 /*
 	MOVE FROM dsa_dataout+0x0178, WHEN DATA_OUT
 
-at 0x000001a0 : */	0x18000000,0x000005a0,
+at 0x0000019e : */	0x18000000,0x000005a0,
 /*
 	MOVE FROM dsa_dataout+0x0180, WHEN DATA_OUT
 
-at 0x000001a2 : */	0x18000000,0x000005a8,
+at 0x000001a0 : */	0x18000000,0x000005a8,
 /*
 	MOVE FROM dsa_dataout+0x0188, WHEN DATA_OUT
 
-at 0x000001a4 : */	0x18000000,0x000005b0,
+at 0x000001a2 : */	0x18000000,0x000005b0,
 /*
 	MOVE FROM dsa_dataout+0x0190, WHEN DATA_OUT
 
-at 0x000001a6 : */	0x18000000,0x000005b8,
+at 0x000001a4 : */	0x18000000,0x000005b8,
 /*
 	MOVE FROM dsa_dataout+0x0198, WHEN DATA_OUT
 
-at 0x000001a8 : */	0x18000000,0x000005c0,
+at 0x000001a6 : */	0x18000000,0x000005c0,
 /*
 	MOVE FROM dsa_dataout+0x01a0, WHEN DATA_OUT
 
-at 0x000001aa : */	0x18000000,0x000005c8,
+at 0x000001a8 : */	0x18000000,0x000005c8,
 /*
 	MOVE FROM dsa_dataout+0x01a8, WHEN DATA_OUT
 
-at 0x000001ac : */	0x18000000,0x000005d0,
+at 0x000001aa : */	0x18000000,0x000005d0,
 /*
 	MOVE FROM dsa_dataout+0x01b0, WHEN DATA_OUT
 
-at 0x000001ae : */	0x18000000,0x000005d8,
+at 0x000001ac : */	0x18000000,0x000005d8,
 /*
 	MOVE FROM dsa_dataout+0x01b8, WHEN DATA_OUT
 
-at 0x000001b0 : */	0x18000000,0x000005e0,
+at 0x000001ae : */	0x18000000,0x000005e0,
 /*
 	MOVE FROM dsa_dataout+0x01c0, WHEN DATA_OUT
 
-at 0x000001b2 : */	0x18000000,0x000005e8,
+at 0x000001b0 : */	0x18000000,0x000005e8,
 /*
 	MOVE FROM dsa_dataout+0x01c8, WHEN DATA_OUT
 
-at 0x000001b4 : */	0x18000000,0x000005f0,
+at 0x000001b2 : */	0x18000000,0x000005f0,
 /*
 	MOVE FROM dsa_dataout+0x01d0, WHEN DATA_OUT
 
-at 0x000001b6 : */	0x18000000,0x000005f8,
+at 0x000001b4 : */	0x18000000,0x000005f8,
 /*
 	MOVE FROM dsa_dataout+0x01d8, WHEN DATA_OUT
 
-at 0x000001b8 : */	0x18000000,0x00000600,
+at 0x000001b6 : */	0x18000000,0x00000600,
 /*
 	MOVE FROM dsa_dataout+0x01e0, WHEN DATA_OUT
 
-at 0x000001ba : */	0x18000000,0x00000608,
+at 0x000001b8 : */	0x18000000,0x00000608,
 /*
 	MOVE FROM dsa_dataout+0x01e8, WHEN DATA_OUT
 
-at 0x000001bc : */	0x18000000,0x00000610,
+at 0x000001ba : */	0x18000000,0x00000610,
 /*
 	MOVE FROM dsa_dataout+0x01f0, WHEN DATA_OUT
 
-at 0x000001be : */	0x18000000,0x00000618,
+at 0x000001bc : */	0x18000000,0x00000618,
 /*
 	MOVE FROM dsa_dataout+0x01f8, WHEN DATA_OUT
 
-at 0x000001c0 : */	0x18000000,0x00000620,
+at 0x000001be : */	0x18000000,0x00000620,
 /*
 	MOVE FROM dsa_dataout+0x0200, WHEN DATA_OUT
 
-at 0x000001c2 : */	0x18000000,0x00000628,
+at 0x000001c0 : */	0x18000000,0x00000628,
 /*
 	MOVE FROM dsa_dataout+0x0208, WHEN DATA_OUT
 
-at 0x000001c4 : */	0x18000000,0x00000630,
+at 0x000001c2 : */	0x18000000,0x00000630,
 /*
 	MOVE FROM dsa_dataout+0x0210, WHEN DATA_OUT
 
-at 0x000001c6 : */	0x18000000,0x00000638,
+at 0x000001c4 : */	0x18000000,0x00000638,
 /*
 	MOVE FROM dsa_dataout+0x0218, WHEN DATA_OUT
 
-at 0x000001c8 : */	0x18000000,0x00000640,
+at 0x000001c6 : */	0x18000000,0x00000640,
 /*
 	MOVE FROM dsa_dataout+0x0220, WHEN DATA_OUT
 
-at 0x000001ca : */	0x18000000,0x00000648,
+at 0x000001c8 : */	0x18000000,0x00000648,
 /*
 	MOVE FROM dsa_dataout+0x0228, WHEN DATA_OUT
 
-at 0x000001cc : */	0x18000000,0x00000650,
+at 0x000001ca : */	0x18000000,0x00000650,
 /*
 	MOVE FROM dsa_dataout+0x0230, WHEN DATA_OUT
 
-at 0x000001ce : */	0x18000000,0x00000658,
+at 0x000001cc : */	0x18000000,0x00000658,
 /*
 	MOVE FROM dsa_dataout+0x0238, WHEN DATA_OUT
 
-at 0x000001d0 : */	0x18000000,0x00000660,
+at 0x000001ce : */	0x18000000,0x00000660,
 /*
 	MOVE FROM dsa_dataout+0x0240, WHEN DATA_OUT
 
-at 0x000001d2 : */	0x18000000,0x00000668,
+at 0x000001d0 : */	0x18000000,0x00000668,
 /*
 	MOVE FROM dsa_dataout+0x0248, WHEN DATA_OUT
 
-at 0x000001d4 : */	0x18000000,0x00000670,
+at 0x000001d2 : */	0x18000000,0x00000670,
 /*
 	MOVE FROM dsa_dataout+0x0250, WHEN DATA_OUT
 
-at 0x000001d6 : */	0x18000000,0x00000678,
+at 0x000001d4 : */	0x18000000,0x00000678,
 /*
 	MOVE FROM dsa_dataout+0x0258, WHEN DATA_OUT
 
-at 0x000001d8 : */	0x18000000,0x00000680,
+at 0x000001d6 : */	0x18000000,0x00000680,
 /*
 	MOVE FROM dsa_dataout+0x0260, WHEN DATA_OUT
 
-at 0x000001da : */	0x18000000,0x00000688,
+at 0x000001d8 : */	0x18000000,0x00000688,
 /*
 	MOVE FROM dsa_dataout+0x0268, WHEN DATA_OUT
 
-at 0x000001dc : */	0x18000000,0x00000690,
+at 0x000001da : */	0x18000000,0x00000690,
 /*
 	MOVE FROM dsa_dataout+0x0270, WHEN DATA_OUT
 
-at 0x000001de : */	0x18000000,0x00000698,
+at 0x000001dc : */	0x18000000,0x00000698,
 /*
 	MOVE FROM dsa_dataout+0x0278, WHEN DATA_OUT
 
-at 0x000001e0 : */	0x18000000,0x000006a0,
+at 0x000001de : */	0x18000000,0x000006a0,
 /*
 	MOVE FROM dsa_dataout+0x0280, WHEN DATA_OUT
 
-at 0x000001e2 : */	0x18000000,0x000006a8,
+at 0x000001e0 : */	0x18000000,0x000006a8,
 /*
 	MOVE FROM dsa_dataout+0x0288, WHEN DATA_OUT
 
-at 0x000001e4 : */	0x18000000,0x000006b0,
+at 0x000001e2 : */	0x18000000,0x000006b0,
 /*
 	MOVE FROM dsa_dataout+0x0290, WHEN DATA_OUT
 
-at 0x000001e6 : */	0x18000000,0x000006b8,
+at 0x000001e4 : */	0x18000000,0x000006b8,
 /*
 	MOVE FROM dsa_dataout+0x0298, WHEN DATA_OUT
 
-at 0x000001e8 : */	0x18000000,0x000006c0,
+at 0x000001e6 : */	0x18000000,0x000006c0,
 /*
 	MOVE FROM dsa_dataout+0x02a0, WHEN DATA_OUT
 
-at 0x000001ea : */	0x18000000,0x000006c8,
+at 0x000001e8 : */	0x18000000,0x000006c8,
 /*
 	MOVE FROM dsa_dataout+0x02a8, WHEN DATA_OUT
 
-at 0x000001ec : */	0x18000000,0x000006d0,
+at 0x000001ea : */	0x18000000,0x000006d0,
 /*
 	MOVE FROM dsa_dataout+0x02b0, WHEN DATA_OUT
 
-at 0x000001ee : */	0x18000000,0x000006d8,
+at 0x000001ec : */	0x18000000,0x000006d8,
 /*
 	MOVE FROM dsa_dataout+0x02b8, WHEN DATA_OUT
 
-at 0x000001f0 : */	0x18000000,0x000006e0,
+at 0x000001ee : */	0x18000000,0x000006e0,
 /*
 	MOVE FROM dsa_dataout+0x02c0, WHEN DATA_OUT
 
-at 0x000001f2 : */	0x18000000,0x000006e8,
+at 0x000001f0 : */	0x18000000,0x000006e8,
 /*
 	MOVE FROM dsa_dataout+0x02c8, WHEN DATA_OUT
 
-at 0x000001f4 : */	0x18000000,0x000006f0,
+at 0x000001f2 : */	0x18000000,0x000006f0,
 /*
 	MOVE FROM dsa_dataout+0x02d0, WHEN DATA_OUT
 
-at 0x000001f6 : */	0x18000000,0x000006f8,
+at 0x000001f4 : */	0x18000000,0x000006f8,
 /*
 	MOVE FROM dsa_dataout+0x02d8, WHEN DATA_OUT
 
-at 0x000001f8 : */	0x18000000,0x00000700,
+at 0x000001f6 : */	0x18000000,0x00000700,
 /*
 	MOVE FROM dsa_dataout+0x02e0, WHEN DATA_OUT
 
-at 0x000001fa : */	0x18000000,0x00000708,
+at 0x000001f8 : */	0x18000000,0x00000708,
 /*
 	MOVE FROM dsa_dataout+0x02e8, WHEN DATA_OUT
 
-at 0x000001fc : */	0x18000000,0x00000710,
+at 0x000001fa : */	0x18000000,0x00000710,
 /*
 	MOVE FROM dsa_dataout+0x02f0, WHEN DATA_OUT
 
-at 0x000001fe : */	0x18000000,0x00000718,
+at 0x000001fc : */	0x18000000,0x00000718,
 /*
 	MOVE FROM dsa_dataout+0x02f8, WHEN DATA_OUT
 
-at 0x00000200 : */	0x18000000,0x00000720,
+at 0x000001fe : */	0x18000000,0x00000720,
 /*
 	MOVE FROM dsa_dataout+0x0300, WHEN DATA_OUT
 
-at 0x00000202 : */	0x18000000,0x00000728,
+at 0x00000200 : */	0x18000000,0x00000728,
 /*
 	MOVE FROM dsa_dataout+0x0308, WHEN DATA_OUT
 
-at 0x00000204 : */	0x18000000,0x00000730,
+at 0x00000202 : */	0x18000000,0x00000730,
 /*
 	MOVE FROM dsa_dataout+0x0310, WHEN DATA_OUT
 
-at 0x00000206 : */	0x18000000,0x00000738,
+at 0x00000204 : */	0x18000000,0x00000738,
 /*
 	MOVE FROM dsa_dataout+0x0318, WHEN DATA_OUT
 
-at 0x00000208 : */	0x18000000,0x00000740,
+at 0x00000206 : */	0x18000000,0x00000740,
 /*
 	MOVE FROM dsa_dataout+0x0320, WHEN DATA_OUT
 
-at 0x0000020a : */	0x18000000,0x00000748,
+at 0x00000208 : */	0x18000000,0x00000748,
 /*
 	MOVE FROM dsa_dataout+0x0328, WHEN DATA_OUT
 
-at 0x0000020c : */	0x18000000,0x00000750,
+at 0x0000020a : */	0x18000000,0x00000750,
 /*
 	MOVE FROM dsa_dataout+0x0330, WHEN DATA_OUT
 
-at 0x0000020e : */	0x18000000,0x00000758,
+at 0x0000020c : */	0x18000000,0x00000758,
 /*
 	MOVE FROM dsa_dataout+0x0338, WHEN DATA_OUT
 
-at 0x00000210 : */	0x18000000,0x00000760,
+at 0x0000020e : */	0x18000000,0x00000760,
 /*
 	MOVE FROM dsa_dataout+0x0340, WHEN DATA_OUT
 
-at 0x00000212 : */	0x18000000,0x00000768,
+at 0x00000210 : */	0x18000000,0x00000768,
 /*
 	MOVE FROM dsa_dataout+0x0348, WHEN DATA_OUT
 
-at 0x00000214 : */	0x18000000,0x00000770,
+at 0x00000212 : */	0x18000000,0x00000770,
 /*
 	MOVE FROM dsa_dataout+0x0350, WHEN DATA_OUT
 
-at 0x00000216 : */	0x18000000,0x00000778,
+at 0x00000214 : */	0x18000000,0x00000778,
 /*
 	MOVE FROM dsa_dataout+0x0358, WHEN DATA_OUT
 
-at 0x00000218 : */	0x18000000,0x00000780,
+at 0x00000216 : */	0x18000000,0x00000780,
 /*
 	MOVE FROM dsa_dataout+0x0360, WHEN DATA_OUT
 
-at 0x0000021a : */	0x18000000,0x00000788,
+at 0x00000218 : */	0x18000000,0x00000788,
 /*
 	MOVE FROM dsa_dataout+0x0368, WHEN DATA_OUT
 
-at 0x0000021c : */	0x18000000,0x00000790,
+at 0x0000021a : */	0x18000000,0x00000790,
 /*
 	MOVE FROM dsa_dataout+0x0370, WHEN DATA_OUT
 
-at 0x0000021e : */	0x18000000,0x00000798,
+at 0x0000021c : */	0x18000000,0x00000798,
 /*
 	MOVE FROM dsa_dataout+0x0378, WHEN DATA_OUT
 
-at 0x00000220 : */	0x18000000,0x000007a0,
+at 0x0000021e : */	0x18000000,0x000007a0,
 /*
 	MOVE FROM dsa_dataout+0x0380, WHEN DATA_OUT
 
-at 0x00000222 : */	0x18000000,0x000007a8,
+at 0x00000220 : */	0x18000000,0x000007a8,
 /*
 	MOVE FROM dsa_dataout+0x0388, WHEN DATA_OUT
 
-at 0x00000224 : */	0x18000000,0x000007b0,
+at 0x00000222 : */	0x18000000,0x000007b0,
 /*
 	MOVE FROM dsa_dataout+0x0390, WHEN DATA_OUT
 
-at 0x00000226 : */	0x18000000,0x000007b8,
+at 0x00000224 : */	0x18000000,0x000007b8,
 /*
 	MOVE FROM dsa_dataout+0x0398, WHEN DATA_OUT
 
-at 0x00000228 : */	0x18000000,0x000007c0,
+at 0x00000226 : */	0x18000000,0x000007c0,
 /*
 	MOVE FROM dsa_dataout+0x03a0, WHEN DATA_OUT
 
-at 0x0000022a : */	0x18000000,0x000007c8,
+at 0x00000228 : */	0x18000000,0x000007c8,
 /*
 	MOVE FROM dsa_dataout+0x03a8, WHEN DATA_OUT
 
-at 0x0000022c : */	0x18000000,0x000007d0,
+at 0x0000022a : */	0x18000000,0x000007d0,
 /*
 	MOVE FROM dsa_dataout+0x03b0, WHEN DATA_OUT
 
-at 0x0000022e : */	0x18000000,0x000007d8,
+at 0x0000022c : */	0x18000000,0x000007d8,
 /*
 	MOVE FROM dsa_dataout+0x03b8, WHEN DATA_OUT
 
-at 0x00000230 : */	0x18000000,0x000007e0,
+at 0x0000022e : */	0x18000000,0x000007e0,
 /*
 	MOVE FROM dsa_dataout+0x03c0, WHEN DATA_OUT
 
-at 0x00000232 : */	0x18000000,0x000007e8,
+at 0x00000230 : */	0x18000000,0x000007e8,
 /*
 	MOVE FROM dsa_dataout+0x03c8, WHEN DATA_OUT
 
-at 0x00000234 : */	0x18000000,0x000007f0,
+at 0x00000232 : */	0x18000000,0x000007f0,
 /*
 	MOVE FROM dsa_dataout+0x03d0, WHEN DATA_OUT
 
-at 0x00000236 : */	0x18000000,0x000007f8,
+at 0x00000234 : */	0x18000000,0x000007f8,
 /*
 	MOVE FROM dsa_dataout+0x03d8, WHEN DATA_OUT
 
-at 0x00000238 : */	0x18000000,0x00000800,
+at 0x00000236 : */	0x18000000,0x00000800,
 /*
 	MOVE FROM dsa_dataout+0x03e0, WHEN DATA_OUT
 
-at 0x0000023a : */	0x18000000,0x00000808,
+at 0x00000238 : */	0x18000000,0x00000808,
 /*
 	MOVE FROM dsa_dataout+0x03e8, WHEN DATA_OUT
 
-at 0x0000023c : */	0x18000000,0x00000810,
+at 0x0000023a : */	0x18000000,0x00000810,
 /*
 	MOVE FROM dsa_dataout+0x03f0, WHEN DATA_OUT
 
-at 0x0000023e : */	0x18000000,0x00000818,
+at 0x0000023c : */	0x18000000,0x00000818,
 /*
 	MOVE FROM dsa_dataout+0x03f8, WHEN DATA_OUT
 
-at 0x00000240 : */	0x18000000,0x00000820,
+at 0x0000023e : */	0x18000000,0x00000820,
 /*
 ENTRY end_data_trans
 end_data_trans:
 redo_msgin3:
 	JUMP get_status, WHEN STATUS
 
-at 0x00000242 : */	0x830b0000,0x000000a0,
+at 0x00000240 : */	0x830b0000,0x00000098,
 /*
 	JUMP get_msgin3, WHEN MSG_IN
 
-at 0x00000244 : */	0x870b0000,0x00000b20,
+at 0x00000242 : */	0x870b0000,0x00000b78,
 /*
 	INT int_data_bad_phase
 
-at 0x00000246 : */	0x98080000,0xab93000b,
+at 0x00000244 : */	0x98080000,0xab93000b,
 /*
 
 get_msgin1:
 	MOVE SCRATCH0 | had_msgin TO SCRATCH0
 
-at 0x00000248 : */	0x7a344000,0x00000000,
+at 0x00000246 : */	0x7a344000,0x00000000,
 /*
 	MOVE 1, msgin_buf, WHEN MSG_IN
 
-at 0x0000024a : */	0x0f000001,0x00000000,
+at 0x00000248 : */	0x0f000001,0x00000000,
 /*
 	JUMP ext_msg1, IF 0x01		; Extended Message
 
-at 0x0000024c : */	0x800c0001,0x00000968,
+at 0x0000024a : */	0x800c0001,0x00000960,
 /*
 	JUMP ignore_msg1, IF 0x02	; Save Data Pointers
 
-at 0x0000024e : */	0x800c0002,0x00000958,
+at 0x0000024c : */	0x800c0002,0x00000950,
 /*
 	JUMP ignore_msg1, IF 0x03	; Save Restore Pointers
 
-at 0x00000250 : */	0x800c0003,0x00000958,
+at 0x0000024e : */	0x800c0003,0x00000950,
 /*
 	JUMP disc1, IF 0x04		; Disconnect
 
-at 0x00000252 : */	0x800c0004,0x000009c8,
+at 0x00000250 : */	0x800c0004,0x000009f0,
 /*
 	INT int_bad_msg1
 
-at 0x00000254 : */	0x98080000,0xab930006,
+at 0x00000252 : */	0x98080000,0xab930006,
 /*
 ignore_msg1:
 	CLEAR ACK
 
-at 0x00000256 : */	0x60000040,0x00000000,
+at 0x00000254 : */	0x60000040,0x00000000,
 /*
 	JUMP redo_msgin1
 
-at 0x00000258 : */	0x80080000,0x00000058,
+at 0x00000256 : */	0x80080000,0x00000050,
 /*
 ext_msg1:
 	MOVE SCRATCH0 | had_extmsg TO SCRATCH0
 
-at 0x0000025a : */	0x7a348000,0x00000000,
+at 0x00000258 : */	0x7a348000,0x00000000,
 /*
 	CLEAR ACK
 
-at 0x0000025c : */	0x60000040,0x00000000,
+at 0x0000025a : */	0x60000040,0x00000000,
 /*
 	MOVE 1, msgin_buf + 1, WHEN MSG_IN
 
-at 0x0000025e : */	0x0f000001,0x00000001,
+at 0x0000025c : */	0x0f000001,0x00000001,
 /*
-	JUMP ext_msg1a, IF 0x03
+	JUMP reject_msg1, IF NOT 0x03	; Only handle SDTR
 
-at 0x00000260 : */	0x800c0003,0x00000990,
+at 0x0000025e : */	0x80040003,0x000009b0,
 /*
-	INT int_bad_extmsg1a
+	CLEAR ACK
 
-at 0x00000262 : */	0x98080000,0xab930000,
+at 0x00000260 : */	0x60000040,0x00000000,
+/*
+	MOVE 1, msgin_buf + 2, WHEN MSG_IN
+
+at 0x00000262 : */	0x0f000001,0x00000002,
+/*
+	JUMP reject_msg1, IF NOT 0x01	; Only handle SDTR
+
+at 0x00000264 : */	0x80040001,0x000009b0,
 /*
-ext_msg1a:
 	CLEAR ACK
 
-at 0x00000264 : */	0x60000040,0x00000000,
+at 0x00000266 : */	0x60000040,0x00000000,
 /*
-	MOVE 1, msgin_buf + 2, WHEN MSG_IN
+	MOVE 2, msgin_buf + 3, WHEN MSG_IN
 
-at 0x00000266 : */	0x0f000001,0x00000002,
+at 0x00000268 : */	0x0f000002,0x00000003,
 /*
-	JUMP ext_msg1b, IF 0x01		; Must be SDTR
+	INT int_msg_sdtr1
+
+at 0x0000026a : */	0x98080000,0xab93000c,
+/*
+reject_msg1:
+	MOVE SCRATCH1 | did_reject TO SCRATCH1
 
-at 0x00000268 : */	0x800c0001,0x000009b0,
+at 0x0000026c : */	0x7a350100,0x00000000,
 /*
-	INT int_bad_extmsg1b
+	SET ATN
 
-at 0x0000026a : */	0x98080000,0xab930001,
+at 0x0000026e : */	0x58000008,0x00000000,
 /*
-ext_msg1b:
 	CLEAR ACK
 
-at 0x0000026c : */	0x60000040,0x00000000,
+at 0x00000270 : */	0x60000040,0x00000000,
 /*
-	MOVE 2, msgin_buf + 3, WHEN MSG_IN
+	JUMP reject_msg1a, WHEN NOT MSG_IN
 
-at 0x0000026e : */	0x0f000002,0x00000003,
+at 0x00000272 : */	0x87030000,0x000009e0,
 /*
-	INT int_msg_sdtr1
+	MOVE 1, msgin_buf + 7, WHEN MSG_IN
 
-at 0x00000270 : */	0x98080000,0xab93000c,
+at 0x00000274 : */	0x0f000001,0x00000007,
+/*
+	JUMP reject_msg1
+
+at 0x00000276 : */	0x80080000,0x000009b0,
+/*
+reject_msg1a:
+	MOVE 1, msg_reject, WHEN MSG_OUT
+
+at 0x00000278 : */	0x0e000001,0x00000000,
+/*
+	JUMP redo_msgin1
+
+at 0x0000027a : */	0x80080000,0x00000050,
 /*
 disc1:
 	CLEAR ACK
 
-at 0x00000272 : */	0x60000040,0x00000000,
+at 0x0000027c : */	0x60000040,0x00000000,
 /*
 ENTRY wait_disc1
 wait_disc1:
 	WAIT DISCONNECT
 
-at 0x00000274 : */	0x48000000,0x00000000,
+at 0x0000027e : */	0x48000000,0x00000000,
 /*
 	INT int_disc1
 
-at 0x00000276 : */	0x98080000,0xab930019,
+at 0x00000280 : */	0x98080000,0xab930019,
 /*
 ENTRY resume_msgin1a
 resume_msgin1a:
 	CLEAR ACK
 
-at 0x00000278 : */	0x60000040,0x00000000,
+at 0x00000282 : */	0x60000040,0x00000000,
 /*
 	JUMP redo_msgin1
 
-at 0x0000027a : */	0x80080000,0x00000058,
+at 0x00000284 : */	0x80080000,0x00000050,
 /*
 ENTRY resume_msgin1b
 resume_msgin1b:
 	SET ATN
 
-at 0x0000027c : */	0x58000008,0x00000000,
+at 0x00000286 : */	0x58000008,0x00000000,
 /*
 	CLEAR ACK
 
-at 0x0000027e : */	0x60000040,0x00000000,
+at 0x00000288 : */	0x60000040,0x00000000,
 /*
 	INT int_no_msgout1, WHEN NOT MSG_OUT
 
-at 0x00000280 : */	0x9e030000,0xab93000f,
+at 0x0000028a : */	0x9e030000,0xab93000f,
 /*
 	MOVE SCRATCH0 | had_msgout TO SCRATCH0
 
-at 0x00000282 : */	0x7a340200,0x00000000,
+at 0x0000028c : */	0x7a340200,0x00000000,
 /*
 	MOVE FROM dsa_msgout, when MSG_OUT
 
-at 0x00000284 : */	0x1e000000,0x00000008,
+at 0x0000028e : */	0x1e000000,0x00000008,
 /*
 	JUMP redo_msgin1
 
-at 0x00000286 : */	0x80080000,0x00000058,
+at 0x00000290 : */	0x80080000,0x00000050,
 /*
 
 get_msgin2:
 	MOVE SCRATCH0 | had_msgin TO SCRATCH0
 
-at 0x00000288 : */	0x7a344000,0x00000000,
+at 0x00000292 : */	0x7a344000,0x00000000,
 /*
 	MOVE 1, msgin_buf, WHEN MSG_IN
 
-at 0x0000028a : */	0x0f000001,0x00000000,
+at 0x00000294 : */	0x0f000001,0x00000000,
 /*
 	JUMP ext_msg2, IF 0x01		; Extended Message
 
-at 0x0000028c : */	0x800c0001,0x00000a68,
+at 0x00000296 : */	0x800c0001,0x00000a90,
 /*
 	JUMP ignore_msg2, IF 0x02	; Save Data Pointers
 
-at 0x0000028e : */	0x800c0002,0x00000a58,
+at 0x00000298 : */	0x800c0002,0x00000a80,
 /*
 	JUMP ignore_msg2, IF 0x03	; Save Restore Pointers
 
-at 0x00000290 : */	0x800c0003,0x00000a58,
+at 0x0000029a : */	0x800c0003,0x00000a80,
 /*
 	JUMP disc2, IF 0x04		; Disconnect
 
-at 0x00000292 : */	0x800c0004,0x00000ac8,
+at 0x0000029c : */	0x800c0004,0x00000b20,
 /*
 	INT int_bad_msg2
 
-at 0x00000294 : */	0x98080000,0xab930007,
+at 0x0000029e : */	0x98080000,0xab930007,
 /*
 ignore_msg2:
 	CLEAR ACK
 
-at 0x00000296 : */	0x60000040,0x00000000,
+at 0x000002a0 : */	0x60000040,0x00000000,
 /*
 	JUMP redo_msgin2
 
-at 0x00000298 : */	0x80080000,0x00000078,
+at 0x000002a2 : */	0x80080000,0x00000070,
 /*
 ext_msg2:
 	MOVE SCRATCH0 | had_extmsg TO SCRATCH0
 
-at 0x0000029a : */	0x7a348000,0x00000000,
+at 0x000002a4 : */	0x7a348000,0x00000000,
 /*
 	CLEAR ACK
 
-at 0x0000029c : */	0x60000040,0x00000000,
+at 0x000002a6 : */	0x60000040,0x00000000,
 /*
 	MOVE 1, msgin_buf + 1, WHEN MSG_IN
 
-at 0x0000029e : */	0x0f000001,0x00000001,
+at 0x000002a8 : */	0x0f000001,0x00000001,
+/*
+	JUMP reject_msg2, IF NOT 0x03	; Only handle SDTR
+
+at 0x000002aa : */	0x80040003,0x00000ae0,
+/*
+	CLEAR ACK
+
+at 0x000002ac : */	0x60000040,0x00000000,
 /*
-	JUMP ext_msg2a, IF 0x03
+	MOVE 1, msgin_buf + 2, WHEN MSG_IN
 
-at 0x000002a0 : */	0x800c0003,0x00000a90,
+at 0x000002ae : */	0x0f000001,0x00000002,
 /*
-	INT int_bad_extmsg2a
+	JUMP reject_msg2, IF NOT 0x01	; Only handle SDTR
 
-at 0x000002a2 : */	0x98080000,0xab930002,
+at 0x000002b0 : */	0x80040001,0x00000ae0,
 /*
-ext_msg2a:
 	CLEAR ACK
 
-at 0x000002a4 : */	0x60000040,0x00000000,
+at 0x000002b2 : */	0x60000040,0x00000000,
 /*
-	MOVE 1, msgin_buf + 2, WHEN MSG_IN
+	MOVE 2, msgin_buf + 3, WHEN MSG_IN
+
+at 0x000002b4 : */	0x0f000002,0x00000003,
+/*
+	INT int_msg_sdtr2
 
-at 0x000002a6 : */	0x0f000001,0x00000002,
+at 0x000002b6 : */	0x98080000,0xab93000d,
 /*
-	JUMP ext_msg2b, IF 0x01		; Must be SDTR
+reject_msg2:
+	MOVE SCRATCH1 | did_reject TO SCRATCH1
 
-at 0x000002a8 : */	0x800c0001,0x00000ab0,
+at 0x000002b8 : */	0x7a350100,0x00000000,
 /*
-	INT int_bad_extmsg2b
+	SET ATN
 
-at 0x000002aa : */	0x98080000,0xab930003,
+at 0x000002ba : */	0x58000008,0x00000000,
 /*
-ext_msg2b:
 	CLEAR ACK
 
-at 0x000002ac : */	0x60000040,0x00000000,
+at 0x000002bc : */	0x60000040,0x00000000,
 /*
-	MOVE 2, msgin_buf + 3, WHEN MSG_IN
+	JUMP reject_msg2a, WHEN NOT MSG_IN
 
-at 0x000002ae : */	0x0f000002,0x00000003,
+at 0x000002be : */	0x87030000,0x00000b10,
 /*
-	INT int_msg_sdtr2
+	MOVE 1, msgin_buf + 7, WHEN MSG_IN
+
+at 0x000002c0 : */	0x0f000001,0x00000007,
+/*
+	JUMP reject_msg2
+
+at 0x000002c2 : */	0x80080000,0x00000ae0,
+/*
+reject_msg2a:
+	MOVE 1, msg_reject, WHEN MSG_OUT
+
+at 0x000002c4 : */	0x0e000001,0x00000000,
+/*
+	JUMP redo_msgin2
 
-at 0x000002b0 : */	0x98080000,0xab93000d,
+at 0x000002c6 : */	0x80080000,0x00000070,
 /*
 disc2:
 	CLEAR ACK
 
-at 0x000002b2 : */	0x60000040,0x00000000,
+at 0x000002c8 : */	0x60000040,0x00000000,
 /*
 ENTRY wait_disc2
 wait_disc2:
 	WAIT DISCONNECT
 
-at 0x000002b4 : */	0x48000000,0x00000000,
+at 0x000002ca : */	0x48000000,0x00000000,
 /*
 	INT int_disc2
 
-at 0x000002b6 : */	0x98080000,0xab93001a,
+at 0x000002cc : */	0x98080000,0xab93001a,
 /*
 ENTRY resume_msgin2a
 resume_msgin2a:
 	CLEAR ACK
 
-at 0x000002b8 : */	0x60000040,0x00000000,
+at 0x000002ce : */	0x60000040,0x00000000,
 /*
 	JUMP redo_msgin2
 
-at 0x000002ba : */	0x80080000,0x00000078,
+at 0x000002d0 : */	0x80080000,0x00000070,
 /*
 ENTRY resume_msgin2b
 resume_msgin2b:
 	SET ATN
 
-at 0x000002bc : */	0x58000008,0x00000000,
+at 0x000002d2 : */	0x58000008,0x00000000,
 /*
 	CLEAR ACK
 
-at 0x000002be : */	0x60000040,0x00000000,
+at 0x000002d4 : */	0x60000040,0x00000000,
 /*
 	INT int_no_msgout2, WHEN NOT MSG_OUT
 
-at 0x000002c0 : */	0x9e030000,0xab930010,
+at 0x000002d6 : */	0x9e030000,0xab930010,
 /*
 	MOVE SCRATCH0 | had_msgout TO SCRATCH0
 
-at 0x000002c2 : */	0x7a340200,0x00000000,
+at 0x000002d8 : */	0x7a340200,0x00000000,
 /*
 	MOVE FROM dsa_msgout, when MSG_OUT
 
-at 0x000002c4 : */	0x1e000000,0x00000008,
+at 0x000002da : */	0x1e000000,0x00000008,
 /*
 	JUMP redo_msgin2
 
-at 0x000002c6 : */	0x80080000,0x00000078,
+at 0x000002dc : */	0x80080000,0x00000070,
 /*
 
 get_msgin3:
 	MOVE SCRATCH0 | had_msgin TO SCRATCH0
 
-at 0x000002c8 : */	0x7a344000,0x00000000,
+at 0x000002de : */	0x7a344000,0x00000000,
 /*
 	MOVE 1, msgin_buf, WHEN MSG_IN
 
-at 0x000002ca : */	0x0f000001,0x00000000,
+at 0x000002e0 : */	0x0f000001,0x00000000,
 /*
 	JUMP ext_msg3, IF 0x01		; Extended Message
 
-at 0x000002cc : */	0x800c0001,0x00000b68,
+at 0x000002e2 : */	0x800c0001,0x00000bc0,
 /*
 	JUMP ignore_msg3, IF 0x02	; Save Data Pointers
 
-at 0x000002ce : */	0x800c0002,0x00000b58,
+at 0x000002e4 : */	0x800c0002,0x00000bb0,
 /*
 	JUMP ignore_msg3, IF 0x03	; Save Restore Pointers
 
-at 0x000002d0 : */	0x800c0003,0x00000b58,
+at 0x000002e6 : */	0x800c0003,0x00000bb0,
 /*
 	JUMP disc3, IF 0x04		; Disconnect
 
-at 0x000002d2 : */	0x800c0004,0x00000bc8,
+at 0x000002e8 : */	0x800c0004,0x00000c50,
 /*
 	INT int_bad_msg3
 
-at 0x000002d4 : */	0x98080000,0xab930008,
+at 0x000002ea : */	0x98080000,0xab930008,
 /*
 ignore_msg3:
 	CLEAR ACK
 
-at 0x000002d6 : */	0x60000040,0x00000000,
+at 0x000002ec : */	0x60000040,0x00000000,
 /*
 	JUMP redo_msgin3
 
-at 0x000002d8 : */	0x80080000,0x00000908,
+at 0x000002ee : */	0x80080000,0x00000900,
 /*
 ext_msg3:
 	MOVE SCRATCH0 | had_extmsg TO SCRATCH0
 
-at 0x000002da : */	0x7a348000,0x00000000,
+at 0x000002f0 : */	0x7a348000,0x00000000,
 /*
 	CLEAR ACK
 
-at 0x000002dc : */	0x60000040,0x00000000,
+at 0x000002f2 : */	0x60000040,0x00000000,
 /*
 	MOVE 1, msgin_buf + 1, WHEN MSG_IN
 
-at 0x000002de : */	0x0f000001,0x00000001,
+at 0x000002f4 : */	0x0f000001,0x00000001,
 /*
-	JUMP ext_msg3a, IF 0x03
+	JUMP reject_msg3, IF NOT 0x03	; Only handle SDTR
 
-at 0x000002e0 : */	0x800c0003,0x00000b90,
+at 0x000002f6 : */	0x80040003,0x00000c10,
 /*
-	INT int_bad_extmsg3a
+	CLEAR ACK
 
-at 0x000002e2 : */	0x98080000,0xab930004,
+at 0x000002f8 : */	0x60000040,0x00000000,
+/*
+	MOVE 1, msgin_buf + 2, WHEN MSG_IN
+
+at 0x000002fa : */	0x0f000001,0x00000002,
+/*
+	JUMP reject_msg3, IF NOT 0x01	; Only handle  SDTR
+
+at 0x000002fc : */	0x80040001,0x00000c10,
 /*
-ext_msg3a:
 	CLEAR ACK
 
-at 0x000002e4 : */	0x60000040,0x00000000,
+at 0x000002fe : */	0x60000040,0x00000000,
 /*
-	MOVE 1, msgin_buf + 2, WHEN MSG_IN
+	MOVE 2, msgin_buf + 3, WHEN MSG_IN
+
+at 0x00000300 : */	0x0f000002,0x00000003,
+/*
+	INT int_msg_sdtr3
 
-at 0x000002e6 : */	0x0f000001,0x00000002,
+at 0x00000302 : */	0x98080000,0xab93000e,
 /*
-	JUMP ext_msg3b, IF 0x01		; Must be SDTR
+reject_msg3:
+	MOVE SCRATCH1 | did_reject TO SCRATCH1
 
-at 0x000002e8 : */	0x800c0001,0x00000bb0,
+at 0x00000304 : */	0x7a350100,0x00000000,
 /*
-	INT int_bad_extmsg3b
+	SET ATN
 
-at 0x000002ea : */	0x98080000,0xab930005,
+at 0x00000306 : */	0x58000008,0x00000000,
 /*
-ext_msg3b:
 	CLEAR ACK
 
-at 0x000002ec : */	0x60000040,0x00000000,
+at 0x00000308 : */	0x60000040,0x00000000,
 /*
-	MOVE 2, msgin_buf + 3, WHEN MSG_IN
+	JUMP reject_msg3a, WHEN NOT MSG_IN
 
-at 0x000002ee : */	0x0f000002,0x00000003,
+at 0x0000030a : */	0x87030000,0x00000c40,
 /*
-	INT int_msg_sdtr3
+	MOVE 1, msgin_buf + 7, WHEN MSG_IN
+
+at 0x0000030c : */	0x0f000001,0x00000007,
+/*
+	JUMP reject_msg3
+
+at 0x0000030e : */	0x80080000,0x00000c10,
+/*
+reject_msg3a:
+	MOVE 1, msg_reject, WHEN MSG_OUT
 
-at 0x000002f0 : */	0x98080000,0xab93000e,
+at 0x00000310 : */	0x0e000001,0x00000000,
+/*
+	JUMP redo_msgin3
+
+at 0x00000312 : */	0x80080000,0x00000900,
 /*
 disc3:
 	CLEAR ACK
 
-at 0x000002f2 : */	0x60000040,0x00000000,
+at 0x00000314 : */	0x60000040,0x00000000,
 /*
 ENTRY wait_disc3
 wait_disc3:
 	WAIT DISCONNECT
 
-at 0x000002f4 : */	0x48000000,0x00000000,
+at 0x00000316 : */	0x48000000,0x00000000,
 /*
 	INT int_disc3
 
-at 0x000002f6 : */	0x98080000,0xab93001b,
+at 0x00000318 : */	0x98080000,0xab93001b,
 /*
 ENTRY resume_msgin3a
 resume_msgin3a:
 	CLEAR ACK
 
-at 0x000002f8 : */	0x60000040,0x00000000,
+at 0x0000031a : */	0x60000040,0x00000000,
 /*
 	JUMP redo_msgin3
 
-at 0x000002fa : */	0x80080000,0x00000908,
+at 0x0000031c : */	0x80080000,0x00000900,
 /*
 ENTRY resume_msgin3b
 resume_msgin3b:
 	SET ATN
 
-at 0x000002fc : */	0x58000008,0x00000000,
+at 0x0000031e : */	0x58000008,0x00000000,
 /*
 	CLEAR ACK
 
-at 0x000002fe : */	0x60000040,0x00000000,
+at 0x00000320 : */	0x60000040,0x00000000,
 /*
 	INT int_no_msgout3, WHEN NOT MSG_OUT
 
-at 0x00000300 : */	0x9e030000,0xab930011,
+at 0x00000322 : */	0x9e030000,0xab930011,
 /*
 	MOVE SCRATCH0 | had_msgout TO SCRATCH0
 
-at 0x00000302 : */	0x7a340200,0x00000000,
+at 0x00000324 : */	0x7a340200,0x00000000,
 /*
 	MOVE FROM dsa_msgout, when MSG_OUT
 
-at 0x00000304 : */	0x1e000000,0x00000008,
+at 0x00000326 : */	0x1e000000,0x00000008,
 /*
 	JUMP redo_msgin3
 
-at 0x00000306 : */	0x80080000,0x00000908,
+at 0x00000328 : */	0x80080000,0x00000900,
 /*
 
 ENTRY resume_rej_ident
 resume_rej_ident:
 	CLEAR ATN
 
-at 0x00000308 : */	0x60000008,0x00000000,
+at 0x0000032a : */	0x60000008,0x00000000,
 /*
 	MOVE 1, msgin_buf, WHEN MSG_IN
 
-at 0x0000030a : */	0x0f000001,0x00000000,
+at 0x0000032c : */	0x0f000001,0x00000000,
 /*
 	INT int_not_rej, IF NOT 0x07		; Reject
 
-at 0x0000030c : */	0x98040007,0xab93001c,
+at 0x0000032e : */	0x98040007,0xab93001c,
 /*
 	CLEAR ACK
 
-at 0x0000030e : */	0x60000040,0x00000000,
+at 0x00000330 : */	0x60000040,0x00000000,
 /*
 	JUMP done_ident
 
-at 0x00000310 : */	0x80080000,0x00000050,
+at 0x00000332 : */	0x80080000,0x00000048,
 /*
 
 ENTRY reselect
@@ -1716,73 +1784,92 @@
 	; Disable selection timer
 	MOVE CTEST7 | 0x10 TO CTEST7
 
-at 0x00000312 : */	0x7a1b1000,0x00000000,
+at 0x00000334 : */	0x7a1b1000,0x00000000,
 /*
 	WAIT RESELECT resel_err
 
-at 0x00000314 : */	0x50000000,0x00000c70,
+at 0x00000336 : */	0x50000000,0x00000cf8,
 /*
 	INT int_resel_not_msgin, WHEN NOT MSG_IN
 
-at 0x00000316 : */	0x9f030000,0xab930016,
+at 0x00000338 : */	0x9f030000,0xab930016,
 /*
 	MOVE 1, reselected_identify, WHEN MSG_IN
 
-at 0x00000318 : */	0x0f000001,0x00000000,
+at 0x0000033a : */	0x0f000001,0x00000000,
 /*
 	INT int_reselected
 
-at 0x0000031a : */	0x98080000,0xab930017,
+at 0x0000033c : */	0x98080000,0xab930017,
 /*
 resel_err:
 	MOVE CTEST2 & 0x40 TO SFBR
 
-at 0x0000031c : */	0x74164000,0x00000000,
+at 0x0000033e : */	0x74164000,0x00000000,
 /*
 	JUMP selected, IF 0x00
 
-at 0x0000031e : */	0x800c0000,0x00000cb0,
+at 0x00000340 : */	0x800c0000,0x00000d38,
 /*
 	MOVE SFBR & 0 TO SFBR
 
-at 0x00000320 : */	0x7c080000,0x00000000,
+at 0x00000342 : */	0x7c080000,0x00000000,
 /*
 ENTRY patch_new_dsa
 patch_new_dsa:
 	MOVE SFBR | 0x11 TO DSA0
 
-at 0x00000322 : */	0x6a101100,0x00000000,
+at 0x00000344 : */	0x6a101100,0x00000000,
 /*
 	MOVE SFBR | 0x22 TO DSA1
 
-at 0x00000324 : */	0x6a112200,0x00000000,
+at 0x00000346 : */	0x6a112200,0x00000000,
 /*
 	MOVE SFBR | 0x33 TO DSA2
 
-at 0x00000326 : */	0x6a123300,0x00000000,
+at 0x00000348 : */	0x6a123300,0x00000000,
 /*
 	MOVE SFBR | 0x44 TO DSA3
 
-at 0x00000328 : */	0x6a134400,0x00000000,
+at 0x0000034a : */	0x6a134400,0x00000000,
 /*
 	JUMP do_select
 
-at 0x0000032a : */	0x80080000,0x00000000,
+at 0x0000034c : */	0x80080000,0x00000000,
 /*
 
 selected:
 	INT int_selected
 
-at 0x0000032c : */	0x98080000,0xab930018,
+at 0x0000034e : */	0x98080000,0xab930018,
+/*
+
+ENTRY test1
+test1:
+	MOVE MEMORY 4, test1_src, test1_dst
+
+at 0x00000350 : */	0xc0000004,0x00000000,0x00000000,
+/*
+	INT int_test1
+
+at 0x00000353 : */	0x98080000,0xab93001d,
+};
+
+#define A_did_reject	0x00000001
+static u32 A_did_reject_used[] __attribute((unused)) = {
+	0x0000026c,
+	0x000002b8,
+	0x00000304,
 };
 
 #define A_dsa_cmnd	0x00000010
 static u32 A_dsa_cmnd_used[] __attribute((unused)) = {
-	0x0000001d,
+	0x0000001b,
 };
 
 #define A_dsa_datain	0x00000028
 static u32 A_dsa_datain_used[] __attribute((unused)) = {
+	0x0000003b,
 	0x0000003d,
 	0x0000003f,
 	0x00000041,
@@ -1910,11 +1997,11 @@
 	0x00000135,
 	0x00000137,
 	0x00000139,
-	0x0000013b,
 };
 
 #define A_dsa_dataout	0x00000428
 static u32 A_dsa_dataout_used[] __attribute((unused)) = {
+	0x00000141,
 	0x00000143,
 	0x00000145,
 	0x00000147,
@@ -2042,25 +2129,24 @@
 	0x0000023b,
 	0x0000023d,
 	0x0000023f,
-	0x00000241,
 };
 
 #define A_dsa_msgin	0x00000020
 static u32 A_dsa_msgin_used[] __attribute((unused)) = {
-	0x0000002f,
+	0x0000002d,
 };
 
 #define A_dsa_msgout	0x00000008
 static u32 A_dsa_msgout_used[] __attribute((unused)) = {
-	0x00000013,
-	0x00000285,
-	0x000002c5,
-	0x00000305,
+	0x00000011,
+	0x0000028f,
+	0x000002db,
+	0x00000327,
 };
 
 #define A_dsa_select	0x00000000
 static u32 A_dsa_select_used[] __attribute((unused)) = {
-	0x00000006,
+	0x00000004,
 };
 
 #define A_dsa_size	0x00000828
@@ -2069,285 +2155,290 @@
 
 #define A_dsa_status	0x00000018
 static u32 A_dsa_status_used[] __attribute((unused)) = {
-	0x0000002b,
+	0x00000029,
 };
 
 #define A_had_cmdout	0x00000004
 static u32 A_had_cmdout_used[] __attribute((unused)) = {
-	0x0000001a,
+	0x00000018,
 };
 
 #define A_had_datain	0x00000008
 static u32 A_had_datain_used[] __attribute((unused)) = {
-	0x00000038,
+	0x00000036,
 };
 
 #define A_had_dataout	0x00000010
 static u32 A_had_dataout_used[] __attribute((unused)) = {
-	0x0000013e,
+	0x0000013c,
 };
 
 #define A_had_extmsg	0x00000080
 static u32 A_had_extmsg_used[] __attribute((unused)) = {
-	0x0000025a,
-	0x0000029a,
-	0x000002da,
+	0x00000258,
+	0x000002a4,
+	0x000002f0,
 };
 
 #define A_had_msgin	0x00000040
 static u32 A_had_msgin_used[] __attribute((unused)) = {
-	0x00000248,
-	0x00000288,
-	0x000002c8,
+	0x00000246,
+	0x00000292,
+	0x000002de,
 };
 
 #define A_had_msgout	0x00000002
 static u32 A_had_msgout_used[] __attribute((unused)) = {
-	0x00000010,
-	0x00000282,
-	0x000002c2,
-	0x00000302,
+	0x0000000e,
+	0x0000028c,
+	0x000002d8,
+	0x00000324,
 };
 
 #define A_had_select	0x00000001
 static u32 A_had_select_used[] __attribute((unused)) = {
-	0x0000000c,
+	0x0000000a,
 };
 
 #define A_had_status	0x00000020
 static u32 A_had_status_used[] __attribute((unused)) = {
 };
 
-#define A_int_bad_extmsg1a	0xab930000
-static u32 A_int_bad_extmsg1a_used[] __attribute((unused)) = {
-	0x00000263,
-};
-
-#define A_int_bad_extmsg1b	0xab930001
-static u32 A_int_bad_extmsg1b_used[] __attribute((unused)) = {
-	0x0000026b,
-};
-
-#define A_int_bad_extmsg2a	0xab930002
-static u32 A_int_bad_extmsg2a_used[] __attribute((unused)) = {
-	0x000002a3,
-};
-
-#define A_int_bad_extmsg2b	0xab930003
-static u32 A_int_bad_extmsg2b_used[] __attribute((unused)) = {
-	0x000002ab,
-};
-
-#define A_int_bad_extmsg3a	0xab930004
-static u32 A_int_bad_extmsg3a_used[] __attribute((unused)) = {
-	0x000002e3,
-};
-
-#define A_int_bad_extmsg3b	0xab930005
-static u32 A_int_bad_extmsg3b_used[] __attribute((unused)) = {
-	0x000002eb,
-};
-
 #define A_int_bad_msg1	0xab930006
 static u32 A_int_bad_msg1_used[] __attribute((unused)) = {
-	0x00000255,
+	0x00000253,
 };
 
 #define A_int_bad_msg2	0xab930007
 static u32 A_int_bad_msg2_used[] __attribute((unused)) = {
-	0x00000295,
+	0x0000029f,
 };
 
 #define A_int_bad_msg3	0xab930008
 static u32 A_int_bad_msg3_used[] __attribute((unused)) = {
-	0x000002d5,
+	0x000002eb,
 };
 
 #define A_int_cmd_bad_phase	0xab930009
 static u32 A_int_cmd_bad_phase_used[] __attribute((unused)) = {
-	0x00000027,
+	0x00000025,
 };
 
 #define A_int_cmd_complete	0xab93000a
 static u32 A_int_cmd_complete_used[] __attribute((unused)) = {
-	0x00000037,
+	0x00000035,
 };
 
 #define A_int_data_bad_phase	0xab93000b
 static u32 A_int_data_bad_phase_used[] __attribute((unused)) = {
-	0x00000247,
+	0x00000245,
 };
 
 #define A_int_disc1	0xab930019
 static u32 A_int_disc1_used[] __attribute((unused)) = {
-	0x00000277,
+	0x00000281,
 };
 
 #define A_int_disc2	0xab93001a
 static u32 A_int_disc2_used[] __attribute((unused)) = {
-	0x000002b7,
+	0x000002cd,
 };
 
 #define A_int_disc3	0xab93001b
 static u32 A_int_disc3_used[] __attribute((unused)) = {
-	0x000002f7,
+	0x00000319,
 };
 
 #define A_int_msg_sdtr1	0xab93000c
 static u32 A_int_msg_sdtr1_used[] __attribute((unused)) = {
-	0x00000271,
+	0x0000026b,
 };
 
 #define A_int_msg_sdtr2	0xab93000d
 static u32 A_int_msg_sdtr2_used[] __attribute((unused)) = {
-	0x000002b1,
+	0x000002b7,
 };
 
 #define A_int_msg_sdtr3	0xab93000e
 static u32 A_int_msg_sdtr3_used[] __attribute((unused)) = {
-	0x000002f1,
+	0x00000303,
 };
 
 #define A_int_no_msgout1	0xab93000f
 static u32 A_int_no_msgout1_used[] __attribute((unused)) = {
-	0x00000281,
+	0x0000028b,
 };
 
 #define A_int_no_msgout2	0xab930010
 static u32 A_int_no_msgout2_used[] __attribute((unused)) = {
-	0x000002c1,
+	0x000002d7,
 };
 
 #define A_int_no_msgout3	0xab930011
 static u32 A_int_no_msgout3_used[] __attribute((unused)) = {
-	0x00000301,
+	0x00000323,
 };
 
 #define A_int_not_cmd_complete	0xab930012
 static u32 A_int_not_cmd_complete_used[] __attribute((unused)) = {
-	0x00000031,
+	0x0000002f,
 };
 
 #define A_int_not_rej	0xab93001c
 static u32 A_int_not_rej_used[] __attribute((unused)) = {
-	0x0000030d,
+	0x0000032f,
 };
 
 #define A_int_resel_not_msgin	0xab930016
 static u32 A_int_resel_not_msgin_used[] __attribute((unused)) = {
-	0x00000317,
+	0x00000339,
 };
 
 #define A_int_reselected	0xab930017
 static u32 A_int_reselected_used[] __attribute((unused)) = {
-	0x0000031b,
+	0x0000033d,
 };
 
 #define A_int_sel_no_ident	0xab930013
 static u32 A_int_sel_no_ident_used[] __attribute((unused)) = {
-	0x0000000f,
+	0x0000000d,
 };
 
 #define A_int_sel_not_cmd	0xab930014
 static u32 A_int_sel_not_cmd_used[] __attribute((unused)) = {
-	0x00000019,
+	0x00000017,
 };
 
 #define A_int_selected	0xab930018
 static u32 A_int_selected_used[] __attribute((unused)) = {
-	0x0000032d,
+	0x0000034f,
 };
 
 #define A_int_status_not_msgin	0xab930015
 static u32 A_int_status_not_msgin_used[] __attribute((unused)) = {
-	0x0000002d,
+	0x0000002b,
+};
+
+#define A_int_test1	0xab93001d
+static u32 A_int_test1_used[] __attribute((unused)) = {
+	0x00000354,
+};
+
+#define A_msg_reject	0x00000000
+static u32 A_msg_reject_used[] __attribute((unused)) = {
+	0x00000279,
+	0x000002c5,
+	0x00000311,
 };
 
 #define A_msgin_buf	0x00000000
 static u32 A_msgin_buf_used[] __attribute((unused)) = {
-	0x0000024b,
-	0x0000025f,
-	0x00000267,
-	0x0000026f,
-	0x0000028b,
-	0x0000029f,
-	0x000002a7,
+	0x00000249,
+	0x0000025d,
+	0x00000263,
+	0x00000269,
+	0x00000275,
+	0x00000295,
+	0x000002a9,
 	0x000002af,
-	0x000002cb,
-	0x000002df,
-	0x000002e7,
-	0x000002ef,
-	0x0000030b,
+	0x000002b5,
+	0x000002c1,
+	0x000002e1,
+	0x000002f5,
+	0x000002fb,
+	0x00000301,
+	0x0000030d,
+	0x0000032d,
 };
 
 #define A_reselected_identify	0x00000000
 static u32 A_reselected_identify_used[] __attribute((unused)) = {
-	0x00000319,
+	0x0000033b,
+};
+
+#define A_test1_dst	0x00000000
+static u32 A_test1_dst_used[] __attribute((unused)) = {
+	0x00000352,
+};
+
+#define A_test1_src	0x00000000
+static u32 A_test1_src_used[] __attribute((unused)) = {
+	0x00000351,
 };
 
 #define Ent_do_select	0x00000000
-#define Ent_done_ident	0x00000050
-#define Ent_end_data_trans	0x00000908
-#define Ent_patch_input_data	0x000000e8
-#define Ent_patch_new_dsa	0x00000c88
-#define Ent_patch_output_data	0x00000500
-#define Ent_reselect	0x00000c48
-#define Ent_resume_cmd	0x00000068
-#define Ent_resume_msgin1a	0x000009e0
-#define Ent_resume_msgin1b	0x000009f0
-#define Ent_resume_msgin2a	0x00000ae0
-#define Ent_resume_msgin2b	0x00000af0
-#define Ent_resume_msgin3a	0x00000be0
-#define Ent_resume_msgin3b	0x00000bf0
-#define Ent_resume_pmm	0x00000078
-#define Ent_resume_rej_ident	0x00000c20
-#define Ent_wait_disc1	0x000009d0
-#define Ent_wait_disc2	0x00000ad0
-#define Ent_wait_disc3	0x00000bd0
-#define Ent_wait_disc_complete	0x000000d0
+#define Ent_done_ident	0x00000048
+#define Ent_end_data_trans	0x00000900
+#define Ent_patch_input_data	0x000000e0
+#define Ent_patch_new_dsa	0x00000d10
+#define Ent_patch_output_data	0x000004f8
+#define Ent_reselect	0x00000cd0
+#define Ent_resume_cmd	0x00000060
+#define Ent_resume_msgin1a	0x00000a08
+#define Ent_resume_msgin1b	0x00000a18
+#define Ent_resume_msgin2a	0x00000b38
+#define Ent_resume_msgin2b	0x00000b48
+#define Ent_resume_msgin3a	0x00000c68
+#define Ent_resume_msgin3b	0x00000c78
+#define Ent_resume_pmm	0x00000070
+#define Ent_resume_rej_ident	0x00000ca8
+#define Ent_test1	0x00000d40
+#define Ent_wait_disc1	0x000009f8
+#define Ent_wait_disc2	0x00000b28
+#define Ent_wait_disc3	0x00000c58
+#define Ent_wait_disc_complete	0x000000c8
 static u32 LABELPATCHES[] __attribute((unused)) = {
+	0x00000005,
 	0x00000007,
-	0x00000009,
+	0x00000013,
 	0x00000015,
-	0x00000017,
+	0x0000001d,
 	0x0000001f,
 	0x00000021,
 	0x00000023,
-	0x00000025,
-	0x0000013d,
+	0x0000013b,
+	0x00000241,
 	0x00000243,
-	0x00000245,
+	0x0000024b,
 	0x0000024d,
 	0x0000024f,
 	0x00000251,
-	0x00000253,
-	0x00000259,
-	0x00000261,
-	0x00000269,
+	0x00000257,
+	0x0000025f,
+	0x00000265,
+	0x00000273,
+	0x00000277,
 	0x0000027b,
-	0x00000287,
-	0x0000028d,
-	0x0000028f,
+	0x00000285,
 	0x00000291,
-	0x00000293,
+	0x00000297,
 	0x00000299,
-	0x000002a1,
-	0x000002a9,
-	0x000002bb,
+	0x0000029b,
+	0x0000029d,
+	0x000002a3,
+	0x000002ab,
+	0x000002b1,
+	0x000002bf,
+	0x000002c3,
 	0x000002c7,
-	0x000002cd,
-	0x000002cf,
 	0x000002d1,
-	0x000002d3,
-	0x000002d9,
-	0x000002e1,
+	0x000002dd,
+	0x000002e3,
+	0x000002e5,
+	0x000002e7,
 	0x000002e9,
-	0x000002fb,
-	0x00000307,
-	0x00000311,
-	0x00000315,
-	0x0000031f,
-	0x0000032b,
+	0x000002ef,
+	0x000002f7,
+	0x000002fd,
+	0x0000030b,
+	0x0000030f,
+	0x00000313,
+	0x0000031d,
+	0x00000329,
+	0x00000333,
+	0x00000337,
+	0x00000341,
+	0x0000034d,
 };
 
 static struct {
@@ -2356,6 +2447,6 @@
 } EXTERNAL_PATCHES[] __attribute((unused)) = {
 };
 
-static u32 INSTRUCTIONS __attribute((unused))	= 407;
-static u32 PATCHES __attribute((unused))	= 42;
+static u32 INSTRUCTIONS __attribute((unused))	= 426;
+static u32 PATCHES __attribute((unused))	= 51;
 static u32 EXTERNAL_PATCHES_LEN __attribute((unused))	= 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/sound/es1370.c linux.20pre10-ac2/drivers/sound/es1370.c
--- linux.20pre10/drivers/sound/es1370.c	2002-10-09 21:36:49.000000000 +0100
+++ linux.20pre10-ac2/drivers/sound/es1370.c	2002-09-05 15:09:33.000000000 +0100
@@ -2673,7 +2673,8 @@
 	}
 	set_fs(fs);
 	/* register gameport */
-	gameport_register_port(&s->gameport);
+	if(s->gameport.io)
+		gameport_register_port(&s->gameport);
 
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/sound/es1371.c linux.20pre10-ac2/drivers/sound/es1371.c
--- linux.20pre10/drivers/sound/es1371.c	2002-10-09 21:36:49.000000000 +0100
+++ linux.20pre10-ac2/drivers/sound/es1371.c	2002-09-05 15:10:25.000000000 +0100
@@ -2968,7 +2968,8 @@
 	/* turn on S/PDIF output driver if requested */
 	outl(cssr, s->io+ES1371_REG_STATUS);
 	/* register gameport */
-	gameport_register_port(&s->gameport);
+	if(s->gameport.io)
+		gameport_register_port(&s->gameport);
 	/* store it in the driver field */
 	pci_set_drvdata(pcidev, s);
 	/* put it into driver list */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/sound/forte.c linux.20pre10-ac2/drivers/sound/forte.c
--- linux.20pre10/drivers/sound/forte.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/sound/forte.c	2002-10-11 00:19:17.000000000 +0100
@@ -1199,6 +1199,7 @@
 forte_dsp_open (struct inode *inode, struct file *file)
 {
 	struct forte_chip *chip = forte; /* FIXME: HACK FROM HELL! */
+	struct forte_channel *channel;
 
 	if (down_interruptible (&chip->open_sem)) {
 		DPRINTK ("%s: returning -ERESTARTSYS\n", __FUNCTION__);
@@ -1481,7 +1482,7 @@
 {
 	struct forte_chip *chip;
 	struct forte_channel *channel;
-	unsigned int i = bytes, sz;
+	unsigned int i = bytes, sz, ret;
 	unsigned long flags;
 
 	if (ppos != &file->f_pos)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/sound/i810_audio.c linux.20pre10-ac2/drivers/sound/i810_audio.c
--- linux.20pre10/drivers/sound/i810_audio.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/sound/i810_audio.c	2002-09-19 01:44:31.000000000 +0100
@@ -65,6 +65,17 @@
  *	If you need to force a specific rate set the clocking= option
  *
  *	This driver is cursed. (Ben LaHaise)
+ *
+ *
+ *  ICH 4 caveats
+ *
+ *      The ICH4 has the feature, that the codec ID doesn't have to be 
+ *      congruent with the IO connection.
+ * 
+ *      Therefore, from driver version 0.23 on, there is a "codec ID" <->
+ *      "IO register base offset" mapping (card->ac97_id_map) field.
+ *   
+ *      Juergen "George" Sawinski (jsaw) 
  */
  
 #include <linux/module.h>
@@ -116,6 +127,9 @@
 #ifndef PCI_DEVICE_ID_AMD_768_AUDIO
 #define PCI_DEVICE_ID_AMD_768_AUDIO	0x7445
 #endif
+#ifndef PCI_DEVICE_ID_AMD_8111_AC97
+#define PCI_DEVICE_ID_AMD_8111_AC97	0x746d
+#endif
 
 static int ftsodell=0;
 static int strict_clocking=0;
@@ -126,6 +140,7 @@
 //#define DEBUG2
 //#define DEBUG_INTERRUPTS
 //#define DEBUG_MMAP
+//#define DEBUG_MMIO
 
 #define ADC_RUNNING	1
 #define DAC_RUNNING	2
@@ -168,6 +183,11 @@
  * each dma engine has controlling registers.  These goofy
  * names are from the datasheet, but make it easy to write
  * code while leafing through it.
+ *
+ * ICH4 has 6 dma engines, pcm in, pcm out, mic, pcm in 2, 
+ * mic in 2, s/pdif.   Of special interest is the fact that
+ * the upper 3 DMA engines on the ICH4 *must* be accessed
+ * via mmio access instead of pio access.
  */
 
 #define ENUM_ENGINE(PRE,DIG) 									\
@@ -192,6 +212,14 @@
 	CAS	 = 	0x34			/* Codec Write Semaphore Register */
 };
 
+ENUM_ENGINE(MC2,4);     /* Mic In 2 */
+ENUM_ENGINE(PI2,5);     /* PCM In 2 */
+ENUM_ENGINE(SP,6);      /* S/PDIF */
+
+enum {
+	SDM =           0x80                    /* SDATA_IN Map Register */
+};
+
 /* interrupts for a dma engine */
 #define DMA_INT_FIFO		(1<<4)  /* fifo under/over flow */
 #define DMA_INT_COMPLETE	(1<<3)  /* buffer read/write complete and ioc set */
@@ -211,8 +239,7 @@
 #define INT_GPI		(1<<0)
 #define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI)
 
-
-#define DRIVER_VERSION "0.21"
+#define DRIVER_VERSION "0.24"
 
 /* magic numbers to protect our data structures */
 #define I810_CARD_MAGIC		0x5072696E /* "Prin" */
@@ -221,7 +248,7 @@
 #define NR_HW_CH		3
 
 /* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
-#define NR_AC97		2
+#define NR_AC97                 4
 
 /* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit */
 /* stream at a minimum for this card to be happy */
@@ -256,6 +283,25 @@
 	"AMD-8111 IOHub"
 };
 
+/* These are capabilities (and bugs) the chipsets _can_ have */
+static struct {
+	int16_t      nr_ac97;
+#define CAP_MMIO                 0x0001
+#define CAP_20BIT_AUDIO_SUPPORT  0x0002
+	u_int16_t flags;
+} card_cap[] = {
+	{  1, 0x0000 }, /* ICH82801AA */
+	{  1, 0x0000 }, /* ICH82901AB */
+	{  1, 0x0000 }, /* INTEL440MX */
+	{  1, 0x0000 }, /* INTELICH2 */
+	{  2, 0x0000 }, /* INTELICH3 */
+        {  3, 0x0003 }, /* INTELICH4 */
+	/*@FIXME to be verified*/	{  2, 0x0000 }, /* SI7012 */
+	/*@FIXME to be verified*/	{  2, 0x0000 }, /* NVIDIA_NFORCE */
+	/*@FIXME to be verified*/	{  2, 0x0000 }, /* AMD768 */
+	/*@FIXME to be verified*/	{  3, 0x0001 }, /* AMD8111 */
+};
+
 static struct pci_device_id i810_pci_tbl [] __initdata = {
 	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801,
 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82801AA},
@@ -353,7 +399,6 @@
 
 
 struct i810_card {
-	struct i810_channel channel[3];
 	unsigned int magic;
 
 	/* We keep i810 cards in a linked list */
@@ -366,6 +411,7 @@
 	/* PCI device stuff */
 	struct pci_dev * pci_dev;
 	u16 pci_id;
+	u16 pci_id_internal; /* used to access card_cap[] */
 #ifdef CONFIG_PM	
 	u16 pm_suspended;
 	u32 pm_save_state[64/sizeof(u32)];
@@ -375,17 +421,27 @@
 	int dev_audio;
 
 	/* structures for abstraction of hardware facilities, codecs, banks and channels*/
+	u16    ac97_id_map[NR_AC97];
 	struct ac97_codec *ac97_codec[NR_AC97];
 	struct i810_state *states[NR_HW_CH];
+	struct i810_channel *channel;	/* 1:1 to states[] but diff. lifetime */
+	dma_addr_t chandma;
 
 	u16 ac97_features;
 	u16 ac97_status;
 	u16 channels;
 	
 	/* hardware resources */
-	unsigned long iobase;
 	unsigned long ac97base;
+	unsigned long iobase;
 	u32 irq;
+
+	unsigned long ac97base_mmio_phys;
+	unsigned long iobase_mmio_phys;
+	u_int8_t *ac97base_mmio;
+	u_int8_t *iobase_mmio;
+
+	int           use_mmio;
 	
 	/* Function support */
 	struct i810_channel *(*alloc_pcm_channel)(struct i810_card *);
@@ -398,6 +454,12 @@
 	int initializing;
 };
 
+/* extract register offset from codec struct */
+#define IO_REG_OFF(codec) (((struct i810_card *) codec->private_data)->ac97_id_map[codec->id])
+
+/* set LVI from CIV */
+#define CIV_TO_LVI(port, off) outb((inb(port+OFF_CIV)+off) & 31, port+OFF_LVI)
+
 static struct i810_card *devs = NULL;
 
 static int i810_open_mixdev(struct inode *inode, struct file *file);
@@ -405,6 +467,10 @@
 			     unsigned int cmd, unsigned long arg);
 static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg);
 static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
+static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg);
+static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data);
+static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg);
+static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data);
 
 static struct i810_channel *i810_alloc_pcm_channel(struct i810_card *card)
 {
@@ -756,7 +822,8 @@
 	if (dmabuf->count < dmabuf->dmasize && dmabuf->ready && !dmabuf->enable &&
 	    (dmabuf->trigger & PCM_ENABLE_INPUT)) {
 		dmabuf->enable |= ADC_RUNNING;
-		outb((1<<4) | (1<<2) | 1, state->card->iobase + PI_CR);
+		// Interrupt enable, LVI enable, DMA enable
+		outb(0x10 | 0x04 | 0x01, state->card->iobase + PI_CR);
 	}
 }
 
@@ -805,7 +872,8 @@
 	if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
 	    (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
 		dmabuf->enable |= DAC_RUNNING;
-		outb((1<<4) | (1<<2) | 1, state->card->iobase + PO_CR);
+		// Interrupt enable, LVI enable, DMA enable
+		outb(0x10 | 0x04 | 0x01, state->card->iobase + PO_CR);
 	}
 }
 static void start_dac(struct i810_state *state)
@@ -957,7 +1025,7 @@
 	  
 		for(i=0;i<dmabuf->numfrag;i++)
 		{
-			sg->busaddr=virt_to_bus(dmabuf->rawbuf+dmabuf->fragsize*i);
+			sg->busaddr=(u32)dmabuf->dma_handle+dmabuf->fragsize*i;
 			// the card will always be doing 16bit stereo
 			sg->control=dmabuf->fragsamples;
 			if(state->card->pci_id == PCI_DEVICE_ID_SI_7012)
@@ -972,9 +1040,11 @@
 		}
 		spin_lock_irqsave(&state->card->lock, flags);
 		outb(2, state->card->iobase+c->port+OFF_CR);   /* reset DMA machine */
-		outl(virt_to_bus(&c->sg[0]), state->card->iobase+c->port+OFF_BDBAR);
-		outb(0, state->card->iobase+c->port+OFF_CIV);
-		outb(0, state->card->iobase+c->port+OFF_LVI);
+		while( inb(state->card->iobase+c->port+OFF_CR) & 0x02 ) ;
+		outl((u32)state->card->chandma +
+		    c->num*sizeof(struct i810_channel),
+		    state->card->iobase+c->port+OFF_BDBAR);
+		CIV_TO_LVI(state->card->iobase+c->port, 0);
 
 		spin_unlock_irqrestore(&state->card->lock, flags);
 
@@ -1020,13 +1090,13 @@
 		if(rec && dmabuf->count < dmabuf->dmasize &&
 		   (dmabuf->trigger & PCM_ENABLE_INPUT))
 		{
-			outb((inb(port+OFF_CIV)+1)&31, port+OFF_LVI);
+			CIV_TO_LVI(port, 1);
 			__start_adc(state);
 			while( !(inb(port + OFF_CR) & ((1<<4) | (1<<2))) ) ;
 		} else if (!rec && dmabuf->count &&
 			   (dmabuf->trigger & PCM_ENABLE_OUTPUT))
 		{
-			outb((inb(port+OFF_CIV)+1)&31, port+OFF_LVI);
+			CIV_TO_LVI(port, 1);
 			__start_dac(state);
 			while( !(inb(port + OFF_CR) & ((1<<4) | (1<<2))) ) ;
 		}
@@ -1294,7 +1364,6 @@
 				if (dmabuf->enable & ADC_RUNNING)
 					__stop_adc(state);
 				dmabuf->enable = 0;
-				wake_up(&dmabuf->wait);
 #ifdef DEBUG_INTERRUPTS
 				printk(" STOP ");
 #endif
@@ -1740,9 +1809,11 @@
 		}
 		if (c != NULL) {
 			outb(2, state->card->iobase+c->port+OFF_CR);   /* reset DMA machine */
-			outl(virt_to_bus(&c->sg[0]), state->card->iobase+c->port+OFF_BDBAR);
-			outb(0, state->card->iobase+c->port+OFF_CIV);
-			outb(0, state->card->iobase+c->port+OFF_LVI);
+			while ( inb(state->card->iobase+c->port+OFF_CR) & 2 );
+			outl((u32)state->card->chandma +
+			    c->num*sizeof(struct i810_channel),
+			    state->card->iobase+c->port+OFF_BDBAR);
+			CIV_TO_LVI(state->card->iobase+c->port, 0);
 		}
 
 		spin_unlock_irqrestore(&state->card->lock, flags);
@@ -1864,7 +1935,8 @@
 		}
 
 		/* ICH and ICH0 only support 2 channels */
-		if ( state->card->pci_id == 0x2415 || state->card->pci_id == 0x2425 ) 
+		if ( state->card->pci_id == PCI_DEVICE_ID_INTEL_82801 
+		     || state->card->pci_id == PCI_DEVICE_ID_INTEL_82901) 
 			return put_user(2, (int *)arg);
 	
 		/* Multi-channel support was added with ICH2. Bits in */
@@ -1883,12 +1955,14 @@
 
 		switch ( val ) {
 			case 2: /* 2 channels is always supported */
-				outl(state->card->iobase + GLOB_CNT, (i_glob_cnt & 0xcfffff));
+				outl(i_glob_cnt & 0xffcfffff,
+				     state->card->iobase + GLOB_CNT);
 				/* Do we need to change mixer settings????  */
 				break;
 			case 4: /* Supported on some chipsets, better check first */
 				if ( state->card->channels >= 4 ) {
-					outl(state->card->iobase + GLOB_CNT, ((i_glob_cnt & 0xcfffff) | 0x0100000));
+					outl((i_glob_cnt & 0xffcfffff) | 0x100000,
+					      state->card->iobase + GLOB_CNT);
 					/* Do we need to change mixer settings??? */
 				} else {
 					val = ret;
@@ -1896,7 +1970,8 @@
 				break;
 			case 6: /* Supported on some chipsets, better check first */
 				if ( state->card->channels >= 6 ) {
-					outl(state->card->iobase + GLOB_CNT, ((i_glob_cnt & 0xcfffff) | 0x0200000));
+					outl((i_glob_cnt & 0xffcfffff) | 0x200000,
+					      state->card->iobase + GLOB_CNT);
 					/* Do we need to change mixer settings??? */
 				} else {
 					val = ret;
@@ -2414,6 +2489,9 @@
 			i810_set_spdif_output(state, AC97_EA_SPSA_3_4, spdif_locked);
 		} else {
 			i810_set_dac_rate(state, 8000);
+			/* Put the ACLink in 2 channel mode by default */
+			i = inl(card->iobase + GLOB_CNT);
+			outl(i & 0xffcfffff, card->iobase + GLOB_CNT);
 		}
 	}
 		
@@ -2478,27 +2556,86 @@
 
 /* Write AC97 codec registers */
 
-static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg)
+static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg)
 {
 	struct i810_card *card = dev->private_data;
 	int count = 100;
-	u8 reg_set = ((dev->id)?((reg&0x7f)|0x80):(reg&0x7f));
+	u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
+	
+	while(count-- && (readb(card->iobase_mmio + CAS) & 1)) 
+		udelay(1);
+	
+#ifdef DEBUG_MMIO
+	{
+		u16 ans = readw(card->ac97base_mmio + reg_set);
+		printk(KERN_DEBUG "i810_audio: ac97_get_mmio(%d) -> 0x%04X\n", ((int) reg_set) & 0xffff, (u32) ans);
+		return ans;
+	}
+#else
+	return readw(card->ac97base_mmio + reg_set);
+#endif
+}
 
+static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg)
+{
+	struct i810_card *card = dev->private_data;
+	int count = 100;
+	u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
+	
 	while(count-- && (inb(card->iobase + CAS) & 1)) 
 		udelay(1);
 	
 	return inw(card->ac97base + reg_set);
 }
 
-static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
+static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data)
 {
 	struct i810_card *card = dev->private_data;
 	int count = 100;
-	u8 reg_set = ((dev->id)?((reg&0x7f)|0x80):(reg&0x7f));
+	u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
+	
+	while(count-- && (readb(card->iobase_mmio + CAS) & 1)) 
+		udelay(1);
+	
+	writew(data, card->ac97base_mmio + reg_set);
 
+#ifdef DEBUG_MMIO
+	printk(KERN_DEBUG "i810_audio: ac97_set_mmio(0x%04X, %d)\n", (u32) data, ((int) reg_set) & 0xffff);
+#endif
+}
+
+static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data)
+{
+	struct i810_card *card = dev->private_data;
+	int count = 100;
+	u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f);
+	
 	while(count-- && (inb(card->iobase + CAS) & 1)) 
 		udelay(1);
-	outw(data, card->ac97base + reg_set);
+	
+        outw(data, card->ac97base + reg_set);
+}
+
+static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg)
+{
+	struct i810_card *card = dev->private_data;
+	if (card->use_mmio) {
+		return i810_ac97_get_mmio(dev, reg);
+	}
+	else {
+		return i810_ac97_get_io(dev, reg);
+	}
+}
+
+static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
+{
+	struct i810_card *card = dev->private_data;
+	if (card->use_mmio) {
+		i810_ac97_set_mmio(dev, reg, data);
+	}
+	else {
+		i810_ac97_set_io(dev, reg, data);
+	}
 }
 
 
@@ -2523,7 +2660,7 @@
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_timeout(HZ/20);
 		}
-		for (i = 0; i < NR_AC97 && card && !card->initializing; i++)
+		for (i = 0; i < NR_AC97 && card && !card->initializing; i++) 
 			if (card->ac97_codec[i] != NULL &&
 			    card->ac97_codec[i]->dev_mixer == minor) {
 				file->private_data = card->ac97_codec[i];
@@ -2551,10 +2688,18 @@
 /* AC97 codec initialisation.  These small functions exist so we don't
    duplicate code between module init and apm resume */
 
-static inline int i810_ac97_exists(struct i810_card *card,int ac97_number)
+static inline int i810_ac97_exists(struct i810_card *card, int ac97_number)
 {
 	u32 reg = inl(card->iobase + GLOB_STA);
-	return (reg & (0x100 << ac97_number));
+	switch (ac97_number) {
+	case 0:
+		return reg & (1<<8);
+	case 1: 
+		return reg & (1<<9);
+	case 2:
+		return reg & (1<<28);
+	}
+	return 0;
 }
 
 static inline int i810_ac97_enable_variable_rate(struct ac97_codec *codec)
@@ -2577,10 +2722,9 @@
 	/* power it all up */
 	i810_ac97_set(codec, AC97_POWER_CONTROL,
 		      i810_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00);
+
 	/* wait for analog ready */
-	for (i=10;
-	     i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf);
-	     i--)
+	for (i=10; i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--)
 	{
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout(HZ/20);
@@ -2588,11 +2732,18 @@
 	return i;
 }
 
-/* if I knew what this did, I'd give it a better name */
-static int i810_ac97_random_init_stuff(struct i810_card *card)
+/**
+ *	i810_ac97_power_up_bus	-	bring up AC97 link
+ *	@card : ICH audio device to power up
+ *
+ *	Bring up the ACLink AC97 codec bus
+ */
+ 
+static int i810_ac97_power_up_bus(struct i810_card *card)
 {	
 	u32 reg = inl(card->iobase + GLOB_CNT);
 	int i;
+	int primary_codec_id = 0;
 
 	if((reg&2)==0)	/* Cold required */
 		reg|=2;
@@ -2600,8 +2751,13 @@
 		reg|=4;	/* Warm */
 		
 	reg&=~8;	/* ACLink on */
-	outl(reg , card->iobase + GLOB_CNT);
 	
+	/* At this point we deassert AC_RESET # */
+	outl(reg , card->iobase + GLOB_CNT);
+
+	/* We must now allow time for the Codec initialisation.
+	   600mS is the specified time */
+	   	
 	for(i=0;i<10;i++)
 	{
 		if((inl(card->iobase+GLOB_CNT)&4)==0)
@@ -2618,7 +2774,31 @@
 
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(HZ/2);
-	reg = inl(card->iobase + GLOB_STA);
+
+	/*
+	 *	See if the primary codec comes ready. This must happen
+	 *	before we start doing DMA stuff
+	 */	
+	/* see i810_ac97_init for the next 7 lines (jsaw) */
+	inw(card->ac97base);
+	if ((card->pci_id == PCI_DEVICE_ID_INTEL_ICH4)
+	    && (card->use_mmio)) {
+		primary_codec_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
+		printk(KERN_INFO "i810_audio: Primary codec has ID %d\n",
+		       primary_codec_id);
+	}
+
+	if(! i810_ac97_exists(card, primary_codec_id))
+	{
+		printk(KERN_INFO "i810_audio: Codec not ready.. wait.. ");
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ);	/* actually 600mS by the spec */
+
+		if(i810_ac97_exists(card, primary_codec_id))
+			printk("OK\n");
+		else 
+			printk("no response.\n");
+	}
 	inw(card->ac97base);
 	return 1;
 }
@@ -2626,12 +2806,14 @@
 static int __init i810_ac97_init(struct i810_card *card)
 {
 	int num_ac97 = 0;
+	int ac97_id;
 	int total_channels = 0;
+	int nr_ac97_max = card_cap[card->pci_id_internal].nr_ac97;
 	struct ac97_codec *codec;
 	u16 eid;
 	u32 reg;
 
-	if(!i810_ac97_random_init_stuff(card)) return 0;
+	if(!i810_ac97_power_up_bus(card)) return 0;
 
 	/* Number of channels supported */
 	/* What about the codec?  Just because the ICH supports */
@@ -2647,26 +2829,47 @@
 		card->channels = 6;
 	else if ( reg & 0x0100000 )
 		card->channels = 4;
-	printk("i810_audio: Audio Controller supports %d channels.\n", card->channels);
+	printk(KERN_INFO "i810_audio: Audio Controller supports %d channels.\n", card->channels);
+	printk(KERN_INFO "i810_audio: Defaulting to base 2 channel mode.\n");
+	reg = inl(card->iobase + GLOB_CNT);
+	outl(reg & 0xffcfffff, card->iobase + GLOB_CNT);
 		
-	inw(card->ac97base);
+	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) 
+		card->ac97_codec[num_ac97] = NULL;
 
-	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
+	/*@FIXME I don't know, if I'm playing to safe here... (jsaw) */
+	if ((nr_ac97_max > 2) && !card->use_mmio) nr_ac97_max = 2;
 
-		/* Assume codec isn't available until we go through the
-		 * gauntlet below */
-		card->ac97_codec[num_ac97] = NULL;
+	for (num_ac97 = 0; num_ac97 < nr_ac97_max; num_ac97++) {
+		/* codec reset */
+		printk(KERN_INFO "i810_audio: Resetting connection %d\n", num_ac97);
+		if (card->use_mmio) readw(card->ac97base_mmio + 0x80*num_ac97);
+		else inw(card->ac97base + 0x80*num_ac97);
+
+		/* If we have the SDATA_IN Map Register, as on ICH4, we
+		   do not loop thru all possible codec IDs but thru all 
+		   possible IO channels. Bit 0:1 of SDM then holds the 
+		   last codec ID spoken to. 
+		*/
+		if ((card->pci_id == PCI_DEVICE_ID_INTEL_ICH4)
+		    && (card->use_mmio)) {
+			ac97_id = (int) readl(card->iobase_mmio + SDM) & 0x3;
+			printk(KERN_INFO "i810_audio: Connection %d with codec id %d\n",
+			       num_ac97, ac97_id);
+		}
+		else {
+			ac97_id = num_ac97;
+		}
 
 		/* The ICH programmer's reference says you should   */
 		/* check the ready status before probing. So we chk */
 		/*   What do we do if it's not ready?  Wait and try */
 		/*   again, or abort?                               */
-		if (!i810_ac97_exists(card,num_ac97)) {
+		if (!i810_ac97_exists(card, ac97_id)) {
 			if(num_ac97 == 0)
 				printk(KERN_ERR "i810_audio: Primary codec not ready.\n");
-			break; /* I think this works, if not ready stop */
 		}
-
+		
 		if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)
 			return -ENOMEM;
 		memset(codec, 0, sizeof(struct ac97_codec));
@@ -2674,13 +2877,20 @@
 		/* initialize some basic codec information, other fields will be filled
 		   in ac97_probe_codec */
 		codec->private_data = card;
-		codec->id = num_ac97;
+		codec->id = ac97_id;
+		card->ac97_id_map[ac97_id] = num_ac97 * 0x80;
 
-		codec->codec_read = i810_ac97_get;
-		codec->codec_write = i810_ac97_set;
+		if (card->use_mmio) {	
+			codec->codec_read = i810_ac97_get_mmio;
+			codec->codec_write = i810_ac97_set_mmio;
+		}
+		else {
+			codec->codec_read = i810_ac97_get_io;
+			codec->codec_write = i810_ac97_set_io;
+		}
 	
 		if(!i810_ac97_probe_and_powerup(card,codec)) {
-			printk("i810_audio: timed out waiting for codec %d analog ready.\n", num_ac97);
+			printk(KERN_ERR "i810_audio: timed out waiting for codec %d analog ready.\n", ac97_id);
 			kfree(codec);
 			break;	/* it didn't work */
 		}
@@ -2689,7 +2899,7 @@
 		
 		/* Don't attempt to get eid until powerup is complete */
 		eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
-		
+
 		if(eid==0xFFFFFF)
 		{
 			printk(KERN_WARNING "i810_audio: no codec attached ?\n");
@@ -2697,16 +2907,27 @@
 			break;
 		}
 		
+		/* Check for an AC97 1.0 soft modem (ID1) */
+		
+		if(codec->codec_read(codec, AC97_RESET) & 2)
+		{
+			printk(KERN_WARNING "i810_audio: codec %d is an AC97 1.0 softmodem - skipping.\n", ac97_id);
+			kfree(codec);
+			continue;
+		}
+		
+		/* Check for an AC97 2.x soft modem */
+		
 		codec->codec_write(codec, AC97_EXTENDED_MODEM_ID, 0L);
-		if(codec->codec_read(codec, AC97_EXTENDED_MODEM_ID))
+		if(codec->codec_read(codec, AC97_EXTENDED_MODEM_ID) & 1)
 		{
-			printk(KERN_WARNING "i810_audio: codec %d is a softmodem - skipping.\n", num_ac97);
+			printk(KERN_WARNING "i810_audio: codec %d is an AC97 2.x softmodem - skipping.\n", ac97_id);
 			kfree(codec);
 			continue;
 		}
 	
 		card->ac97_features = eid;
-				
+
 		/* Now check the codec for useful features to make up for
 		   the dumbness of the 810 hardware engine */
 
@@ -2720,6 +2941,11 @@
 			}			
 		}
    		
+		/* Turn on the amplifier */
+
+		codec->codec_write(codec, AC97_POWER_CONTROL, 
+			 codec->codec_read(codec, AC97_POWER_CONTROL) & ~0x8000);
+				
 		/* Determine how many channels the codec(s) support   */
 		/*   - The primary codec always supports 2            */
 		/*   - If the codec supports AMAP, surround DACs will */
@@ -2745,7 +2971,7 @@
 				total_channels += 2;
 			if (eid & 0x0140) /* LFE and Center channels */
 				total_channels += 2;
-			printk("i810_audio: AC'97 codec %d supports AMAP, total channels = %d\n", num_ac97, total_channels);
+			printk("i810_audio: AC'97 codec %d supports AMAP, total channels = %d\n", ac97_id, total_channels);
 		} else if (eid & 0x0400) {  /* this only works on 2.2 compliant codecs */
 			eid &= 0xffcf;
 			if((eid & 0xc000) != 0)	{
@@ -2767,14 +2993,14 @@
 			}
 			i810_ac97_set(codec, AC97_EXTENDED_ID, eid);
 			eid = i810_ac97_get(codec, AC97_EXTENDED_ID);
-			printk("i810_audio: AC'97 codec %d, new EID value = 0x%04x\n", num_ac97, eid);
+			printk("i810_audio: AC'97 codec %d, new EID value = 0x%04x\n", ac97_id, eid);
 			if (eid & 0x0080) /* L/R Surround channels */
 				total_channels += 2;
 			if (eid & 0x0140) /* LFE and Center channels */
 				total_channels += 2;
-			printk("i810_audio: AC'97 codec %d, DAC map configured, total channels = %d\n", num_ac97, total_channels);
+			printk("i810_audio: AC'97 codec %d, DAC map configured, total channels = %d\n", ac97_id, total_channels);
 		} else {
-			printk("i810_audio: AC'97 codec %d Unable to map surround DAC's (or DAC's not present), total channels = %d\n", num_ac97, total_channels);
+			printk("i810_audio: AC'97 codec %d Unable to map surround DAC's (or DAC's not present), total channels = %d\n", ac97_id, total_channels);
 		}
 
 		if ((codec->dev_mixer = register_sound_mixer(&i810_mixer_fops, -1)) < 0) {
@@ -2823,6 +3049,8 @@
 		init_MUTEX(&state->open_sem);
 		dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT;
 		dmabuf->trigger = PCM_ENABLE_OUTPUT;
+		i810_set_spdif_output(state, -1, 0);
+		i810_set_dac_channels(state, 2);
 		i810_set_dac_rate(state, 48000);
 		if(prog_dmabuf(state, 0) != 0) {
 			goto config_out_nodmabuf;
@@ -2831,7 +3059,7 @@
 			goto config_out;
 		}
 		dmabuf->count = dmabuf->dmasize;
-		outb(31,card->iobase+dmabuf->write_channel->port+OFF_LVI);
+		CIV_TO_LVI(card->iobase+dmabuf->write_channel->port, 31);
 		save_flags(flags);
 		cli();
 		start_dac(state);
@@ -2839,10 +3067,9 @@
 		mdelay(50);
 		new_offset = i810_get_dma_addr(state, 0);
 		stop_dac(state);
-		outb(2,card->iobase+dmabuf->write_channel->port+OFF_CR);
 		restore_flags(flags);
 		i = new_offset - offset;
-#ifdef DEBUG
+#ifdef DEBUG_INTERRUPTS
 		printk("i810_audio: %d bytes in 50 milliseconds\n", i);
 #endif
 		if(i == 0)
@@ -2884,10 +3111,25 @@
 	memset(card, 0, sizeof(*card));
 
 	card->initializing = 1;
-	card->iobase = pci_resource_start (pci_dev, 1);
-	card->ac97base = pci_resource_start (pci_dev, 0);
 	card->pci_dev = pci_dev;
 	card->pci_id = pci_id->device;
+	card->ac97base = pci_resource_start (pci_dev, 0);
+	card->iobase = pci_resource_start (pci_dev, 1);
+
+	/* if chipset could have mmio capability, check it */ 
+	if (card_cap[pci_id->driver_data].flags & CAP_MMIO) {
+		card->ac97base_mmio_phys = pci_resource_start (pci_dev, 2);
+		card->iobase_mmio_phys = pci_resource_start (pci_dev, 3);
+
+		if ((card->ac97base_mmio_phys) && (card->iobase_mmio_phys)) {
+			card->use_mmio = 1;
+		}
+		else {
+			card->ac97base_mmio_phys = 0;
+			card->iobase_mmio_phys = 0;
+		}
+	}
+
 	card->irq = pci_dev->irq;
 	card->next = devs;
 	card->magic = I810_CARD_MAGIC;
@@ -2899,23 +3141,37 @@
 
 	pci_set_master(pci_dev);
 
-	printk(KERN_INFO "i810: %s found at IO 0x%04lx and 0x%04lx, IRQ %d\n",
-	       card_names[pci_id->driver_data], card->iobase, card->ac97base, 
+	printk(KERN_INFO "i810: %s found at IO 0x%04lx and 0x%04lx, "
+	       "MEM 0x%04lx and 0x%04lx, IRQ %d\n",
+	       card_names[pci_id->driver_data], 
+	       card->iobase, card->ac97base, 
+	       card->ac97base_mmio_phys, card->iobase_mmio_phys,
 	       card->irq);
 
 	card->alloc_pcm_channel = i810_alloc_pcm_channel;
 	card->alloc_rec_pcm_channel = i810_alloc_rec_pcm_channel;
 	card->alloc_rec_mic_channel = i810_alloc_rec_mic_channel;
 	card->free_pcm_channel = i810_free_pcm_channel;
-	card->channel[0].offset = 0;
-	card->channel[0].port = 0x00;
-	card->channel[0].num=0;
-	card->channel[1].offset = 0;
-	card->channel[1].port = 0x10;
-	card->channel[1].num=1;
-	card->channel[2].offset = 0;
-	card->channel[2].port = 0x20;
-	card->channel[2].num=2;
+
+	if ((card->channel = pci_alloc_consistent(pci_dev,
+	    sizeof(struct i810_channel)*NR_HW_CH, &card->chandma)) == NULL) {
+		printk(KERN_ERR "i810: cannot allocate channel DMA memory\n");
+		goto out_mem;
+	}
+
+	{ /* We may dispose of this altogether some time soon, so... */
+		struct i810_channel *cp = card->channel;
+
+		cp[0].offset = 0;
+		cp[0].port = 0x00;
+		cp[0].num = 0;
+		cp[1].offset = 0;
+		cp[1].port = 0x10;
+		cp[1].num = 1;
+		cp[2].offset = 0;
+		cp[2].port = 0x20;
+		cp[2].num = 2;
+	}
 
 	/* claim our iospace and irq */
 	request_region(card->iobase, 64, card_names[pci_id->driver_data]);
@@ -2924,19 +3180,42 @@
 	if (request_irq(card->irq, &i810_interrupt, SA_SHIRQ,
 			card_names[pci_id->driver_data], card)) {
 		printk(KERN_ERR "i810_audio: unable to allocate irq %d\n", card->irq);
-		release_region(card->iobase, 64);
-		release_region(card->ac97base, 256);
-		kfree(card);
-		return -ENODEV;
+		goto out_pio;
+	}
+
+	if (card->use_mmio) {
+		if (request_mem_region(card->ac97base_mmio_phys, 512, "ich_audio MMBAR")) {
+			if ((card->ac97base_mmio = ioremap(card->ac97base_mmio_phys, 512))) { /*@FIXME can ioremap fail? don't know (jsaw) */
+				if (request_mem_region(card->iobase_mmio_phys, 256, "ich_audio MBBAR")) {
+					if ((card->iobase_mmio = ioremap(card->iobase_mmio_phys, 256))) {
+						printk(KERN_INFO "i810: %s mmio at 0x%04lx and 0x%04lx\n",
+						       card_names[pci_id->driver_data], 
+						       (unsigned long) card->ac97base_mmio, 
+						       (unsigned long) card->iobase_mmio); 
+					}
+					else {
+						iounmap(card->ac97base_mmio);
+						release_mem_region(card->ac97base_mmio_phys, 512);
+						release_mem_region(card->iobase_mmio_phys, 512);
+						card->use_mmio = 0;
+					}
+				}
+				else {
+					iounmap(card->ac97base_mmio);
+					release_mem_region(card->ac97base_mmio_phys, 512);
+					card->use_mmio = 0;
+				}
+			}
+		}
+		else {
+			card->use_mmio = 0;
+		}
 	}
 
 	/* initialize AC97 codec and register /dev/mixer */
 	if (i810_ac97_init(card) <= 0) {
-		release_region(card->iobase, 64);
-		release_region(card->ac97base, 256);
 		free_irq(card->irq, card);
-		kfree(card);
-		return -ENODEV;
+		goto out_iospace;
 	}
 	pci_set_drvdata(pci_dev, card);
 
@@ -2949,19 +3228,34 @@
 	if ((card->dev_audio = register_sound_dsp(&i810_audio_fops, -1)) < 0) {
 		int i;
 		printk(KERN_ERR "i810_audio: couldn't register DSP device!\n");
-		release_region(card->iobase, 64);
-		release_region(card->ac97base, 256);
 		free_irq(card->irq, card);
 		for (i = 0; i < NR_AC97; i++)
 		if (card->ac97_codec[i] != NULL) {
 			unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
 			kfree (card->ac97_codec[i]);
 		}
-		kfree(card);
-		return -ENODEV;
+		goto out_iospace;
 	}
+
  	card->initializing = 0;
 	return 0;
+
+out_iospace:
+	if (card->use_mmio) {
+		iounmap(card->ac97base_mmio);
+		iounmap(card->iobase_mmio);
+		release_mem_region(card->ac97base_mmio_phys, 512);
+		release_mem_region(card->iobase_mmio_phys, 256);
+	}
+out_pio:	
+	release_region(card->iobase, 64);
+	release_region(card->ac97base, 256);
+out_chan:
+	pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH,
+	    card->channel, card->chandma);
+out_mem:
+	kfree(card);
+	return -ENODEV;
 }
 
 static void __devexit i810_remove(struct pci_dev *pci_dev)
@@ -2972,6 +3266,12 @@
 	free_irq(card->irq, devs);
 	release_region(card->iobase, 64);
 	release_region(card->ac97base, 256);
+	if (card->use_mmio) {
+		iounmap(card->ac97base_mmio);
+		iounmap(card->iobase_mmio);
+		release_mem_region(card->ac97base_mmio_phys, 512);
+		release_mem_region(card->iobase_mmio_phys, 256);
+	}
 
 	/* unregister audio devices */
 	for (i = 0; i < NR_AC97; i++)
@@ -3054,7 +3354,7 @@
 	   hardware has to be more or less completely reinitialized from
 	   scratch after an apm suspend.  Works For Me.   -dan */
 
-	i810_ac97_random_init_stuff(card);
+	i810_ac97_power_up_bus(card);
 
 	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
 		struct ac97_codec *codec = card->ac97_codec[num_ac97];
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/sound/mad16.c linux.20pre10-ac2/drivers/sound/mad16.c
--- linux.20pre10/drivers/sound/mad16.c	2002-10-09 21:36:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/sound/mad16.c	2002-09-18 12:25:38.000000000 +0100
@@ -367,6 +367,8 @@
 {
 	unsigned char cfg = 0;
 
+	cfg |= (0x0f & mad16_conf);
+
 	if(c931_detected)
 	{
 		/* Bit 0 has reversd meaning. Bits 1 and 2 sese
@@ -404,7 +406,10 @@
 	   and the C931. */
 	cfg = c931_detected ? 0x04 : 0x00;
 
-	mad_write(MC4_PORT, 0x52|cfg);
+	if(mad16_cdsel & 0x20)
+		mad_write(MC4_PORT, 0x62|cfg);  /* opl4 */
+	else
+		mad_write(MC4_PORT, 0x52|cfg);  /* opl3 */
 
 	mad_write(MC5_PORT, 0x3C);	/* Init it into mode2 */
 	mad_write(MC6_PORT, 0x02);	/* Enable WSS, Disable MPU and SB */
@@ -561,10 +566,10 @@
 	 */
 
 	tmp &= ~0x0f;
+	tmp |= (mad16_conf & 0x0f);   /* CD-ROM and joystick bits */
 	mad_write(MC1_PORT, tmp);
 
-	tmp = mad_read(MC2_PORT);
-
+	tmp = mad16_cdsel;
 	mad_write(MC2_PORT, tmp);
 	mad_write(MC3_PORT, 0xf0);	/* Disable SB */
 
@@ -1051,6 +1056,12 @@
 {
 	if (found_mpu)
 		unload_mad16_mpu(&cfg_mpu);
+	if (gameport.io) {
+		/* the gameport was initialized so we must free it up */
+		gameport_unregister_port(&gameport);
+		gameport.io = 0;
+		release_region(0x201, 1);
+	}
 	unload_mad16(&cfg);
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/sound/maestro3.c linux.20pre10-ac2/drivers/sound/maestro3.c
--- linux.20pre10/drivers/sound/maestro3.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/sound/maestro3.c	2002-09-29 22:47:50.000000000 +0100
@@ -2473,7 +2473,7 @@
     if(!external_amp)
         return;
 
-    if (0 <= gpio_pin <= 15) {
+    if (gpio_pin >= 0  && gpio_pin <= 15) {
         polarity_port = 0x1000 + (0x100 * gpio_pin);
     } else {
         switch (card->card_type) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/usb/acm.c linux.20pre10-ac2/drivers/usb/acm.c
--- linux.20pre10/drivers/usb/acm.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/usb/acm.c	2002-09-18 20:54:40.000000000 +0100
@@ -649,6 +649,7 @@
  */
 
 static struct usb_device_id acm_ids[] = {
+	{ USB_DEVICE(0x22B8, 0x1005) },		/* Motorola TimePort 280 */
 	{ USB_DEVICE_INFO(USB_CLASS_COMM, 0, 0) },
 	{ }
 };
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/usb/brlvger.c linux.20pre10-ac2/drivers/usb/brlvger.c
--- linux.20pre10/drivers/usb/brlvger.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/usb/brlvger.c	2002-09-19 01:10:11.000000000 +0100
@@ -209,7 +209,7 @@
     ({ printk(KERN_ERR "Voyager: " args); \
        printk("\n"); })
 #define dbgprint(fmt, args...) \
-    ({ printk(KERN_DEBUG "Voyager: %s: " fmt, __FUNCTION__, ##args); \
+    ({ printk(KERN_DEBUG "Voyager: %s: " fmt, __FUNCTION__ , ##args); \
        printk("\n"); })
 #define dbg(args...) \
     ({ if(debug >= 1) dbgprint(args); })
@@ -586,7 +586,8 @@
 	struct brlvger_priv *priv = file->private_data;
 	char buf[MAX_BRLVGER_CELLS];
 	int ret;
-	int rs, off;
+	size_t rs;
+	loff_t off;
 	__u16 written;
 
 	if(!priv->dev)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/usb/CDCEther.c linux.20pre10-ac2/drivers/usb/CDCEther.c
--- linux.20pre10/drivers/usb/CDCEther.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/usb/CDCEther.c	2002-10-11 00:21:44.000000000 +0100
@@ -313,7 +313,7 @@
 	// into an integer number of USB packets, we force it to send one 
 	// more byte so the device will get a runt USB packet signalling the 
 	// end of the ethernet frame
-	if ( (skb->len) ^ (ether_dev->data_ep_out_size) ) {
+	if ( skb->len % ether_dev->data_ep_out_size) {
 		// It was not an exact multiple
 		// no need to add anything extra
 		count = skb->len;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/usb/devio.c linux.20pre10-ac2/drivers/usb/devio.c
--- linux.20pre10/drivers/usb/devio.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/usb/devio.c	2002-09-29 20:53:37.000000000 +0100
@@ -43,7 +43,7 @@
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
 #include <asm/uaccess.h>
-
+#include <linux/module.h>
 
 struct async {
         struct list_head asynclist;
@@ -1063,6 +1063,8 @@
 	int			size;
 	void			*buf = 0;
 	int			retval = 0;
+       struct usb_interface    *ifp = 0;
+       struct usb_driver       *driver = 0;
 
 	/* get input parameters and alloc buffer */
 	if (copy_from_user(&ctrl, (void *) arg, sizeof (ctrl)))
@@ -1080,32 +1082,55 @@
 		}
 	}
 
-	/* ioctl to device */
-	if (ctrl.ifno < 0) {
-		switch (ctrl.ioctl_code) {
-		/* access/release token for issuing control messages
-		 * ask a particular driver to bind/unbind, ... etc
-		 */
-		}
-		retval = -ENOSYS;
-
-	/* ioctl to the driver which has claimed a given interface */
-	} else {
-		struct usb_interface	*ifp = 0;
-		if (!ps->dev)
-			retval = -ENODEV;
-		else if (ctrl.ifno >= ps->dev->actconfig->bNumInterfaces)
+	if (!ps->dev)
+		retval = -ENODEV;
+	else if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
+		retval = -EINVAL;
+	else switch (ctrl.ioctl_code) {
+	
+	/* disconnect kernel driver from interface, leaving it unbound */
+	case USBDEVFS_DISCONNECT:
+		driver = ifp->driver;
+		if (driver) {
+			down (&driver->serialize);
+			dbg ("disconnect '%s' from dev %d interface %d",
+				driver->name, ps->dev->devnum, ctrl.ifno);
+			driver->disconnect (ps->dev, ifp->private_data);
+			usb_driver_release_interface (driver, ifp);
+			up (&driver->serialize);
+		} else
 			retval = -EINVAL;
-		else {
-			if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
-				retval = -EINVAL;
-			else if (ifp->driver == 0 || ifp->driver->ioctl == 0)
-				retval = -ENOSYS;
-		}
-		if (retval == 0)
+		break;
+		
+	/* let kernel drivers try to (re)bind to the interface */
+	case USBDEVFS_CONNECT:
+		usb_find_interface_driver_for_ifnum (ps->dev, ctrl.ifno);
+		break;
+		
+       /* talk directly to the interface's driver */
+       default:
+		lock_kernel(); /* against module unload */
+               driver = ifp->driver;
+               if (driver == 0 || driver->ioctl == 0) {
+			unlock_kernel();
+			retval = -ENOSYS;
+		} else {
+			if (ifp->driver->owner) {
+				__MOD_INC_USE_COUNT(ifp->driver->owner);
+				unlock_kernel();
+			}
 			/* ifno might usefully be passed ... */
-			retval = ifp->driver->ioctl (ps->dev, ctrl.ioctl_code, buf);
+                       retval = driver->ioctl (ps->dev, ctrl.ioctl_code, buf);
 			/* size = min_t(int, size, retval)? */
+			if (ifp->driver->owner) {
+				__MOD_DEC_USE_COUNT(ifp->driver->owner);
+			} else {
+				unlock_kernel();
+			}
+		}
+		
+		if (retval == -ENOIOCTLCMD)
+			retval = -ENOTTY;
 	}
 
 	/* cleanup and return */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/usb/hcd/ehci-dbg.c linux.20pre10-ac2/drivers/usb/hcd/ehci-dbg.c
--- linux.20pre10/drivers/usb/hcd/ehci-dbg.c	2002-10-09 21:36:54.000000000 +0100
+++ linux.20pre10-ac2/drivers/usb/hcd/ehci-dbg.c	2002-09-29 21:02:14.000000000 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001 by David Brownell
+ * Copyright (c) 2001-2002 by David Brownell
  * 
  * 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
@@ -26,8 +26,10 @@
 
 #ifdef	DEBUG
 
-/* check the values in the HCSPARAMS register - host controller structural parameters */
-/* see EHCI 0.95 Spec, Table 2-4 for each value */
+/* check the values in the HCSPARAMS register
+ * (host controller _Structural_ parameters)
+ * see EHCI spec, Table 2-4 for each value
+ */
 static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
 {
 	u32	params = readl (&ehci->caps->hcs_params);
@@ -55,7 +57,7 @@
 			strcat(buf, tmp);
 		}
 		dbg ("%s: %s portroute %s", 
-			ehci->hcd.bus_name, label,
+			hcd_to_bus (&ehci->hcd)->bus_name, label,
 			buf);
 	}
 }
@@ -67,25 +69,27 @@
 
 #ifdef	DEBUG
 
-/* check the values in the HCCPARAMS register - host controller capability parameters */
-/* see EHCI 0.95 Spec, Table 2-5 for each value */
+/* check the values in the HCCPARAMS register
+ * (host controller _Capability_ parameters)
+ * see EHCI Spec, Table 2-5 for each value
+ * */
 static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
 {
 	u32	params = readl (&ehci->caps->hcc_params);
 
 	if (HCC_EXT_CAPS (params)) {
 		// EHCI 0.96 ... could interpret these (legacy?)
-		dbg ("%s extended capabilities at pci %d",
+		dbg ("%s extended capabilities at pci %2x",
 			label, HCC_EXT_CAPS (params));
 	}
 	if (HCC_ISOC_CACHE (params)) {
-		dbg ("%s hcc_params 0x%04x caching frame %s%s%s",
+		dbg ("%s hcc_params %04x caching frame %s%s%s",
 		     label, params,
 		     HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
 		     HCC_CANPARK (params) ? " park" : "",
 		     HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
 	} else {
-		dbg ("%s hcc_params 0x%04x caching %d uframes %s%s%s",
+		dbg ("%s hcc_params %04x caching %d uframes %s%s%s",
 		     label,
 		     params,
 		     HCC_ISOC_THRES (params),
@@ -102,8 +106,8 @@
 
 #ifdef	DEBUG
 
-#if 0
-static void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
+static void __attribute__((__unused__))
+dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
 	dbg ("%s %p info1 %x info2 %x hw_curr %x qtd_next %x", label,
 		qh, qh->hw_info1, qh->hw_info2,
@@ -117,63 +121,462 @@
 			qh->hw_buf [4]);
 	}
 }
-#endif
+
+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",
+		label, label [0] ? " " : "", status,
+		(status & STS_ASS) ? " Async" : "",
+		(status & STS_PSS) ? " Periodic" : "",
+		(status & STS_RECL) ? " Recl" : "",
+		(status & STS_HALT) ? " Halt" : "",
+		(status & STS_IAA) ? " IAA" : "",
+		(status & STS_FATAL) ? " FATAL" : "",
+		(status & STS_FLR) ? " FLR" : "",
+		(status & STS_PCD) ? " PCD" : "",
+		(status & STS_ERR) ? " ERR" : "",
+		(status & STS_INT) ? " INT" : ""
+		);
+}
+
+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",
+		label, label [0] ? " " : "", enable,
+		(enable & STS_IAA) ? " IAA" : "",
+		(enable & STS_FATAL) ? " FATAL" : "",
+		(enable & STS_FLR) ? " FLR" : "",
+		(enable & STS_PCD) ? " PCD" : "",
+		(enable & STS_ERR) ? " ERR" : "",
+		(enable & STS_INT) ? " INT" : ""
+		);
+}
 
 static const char *const fls_strings [] =
     { "1024", "512", "256", "??" };
 
+static int dbg_command_buf (char *buf, unsigned len, char *label, u32 command)
+{
+	return snprintf (buf, len,
+		"%s%scommand %06x %s=%d ithresh=%d%s%s%s%s period=%s%s %s",
+		label, label [0] ? " " : "", command,
+		(command & CMD_PARK) ? "park" : "(park)",
+		CMD_PARK_CNT (command),
+		(command >> 16) & 0x3f,
+		(command & CMD_LRESET) ? " LReset" : "",
+		(command & CMD_IAAD) ? " IAAD" : "",
+		(command & CMD_ASE) ? " Async" : "",
+		(command & CMD_PSE) ? " Periodic" : "",
+		fls_strings [(command >> 2) & 0x3],
+		(command & CMD_RESET) ? " Reset" : "",
+		(command & CMD_RUN) ? "RUN" : "HALT"
+		);
+}
+
+static int
+dbg_port_buf (char *buf, unsigned len, char *label, int port, u32 status)
+{
+	char	*sig;
+
+	/* signaling state */
+	switch (status & (3 << 10)) {
+	case 0 << 10: sig = "se0"; break;
+	case 1 << 10: sig = "k"; break;		/* low speed */
+	case 2 << 10: sig = "j"; break;
+	default: sig = "?"; break;
+	}
+
+	return snprintf (buf, len,
+		"%s%sport %d status %06x%s%s sig=%s %s%s%s%s%s%s%s%s%s",
+		label, label [0] ? " " : "", port, status,
+		(status & PORT_POWER) ? " POWER" : "",
+		(status & PORT_OWNER) ? " OWNER" : "",
+		sig,
+		(status & PORT_RESET) ? " RESET" : "",
+		(status & PORT_SUSPEND) ? " SUSPEND" : "",
+		(status & PORT_RESUME) ? " RESUME" : "",
+		(status & PORT_OCC) ? " OCC" : "",
+		(status & PORT_OC) ? " OC" : "",
+		(status & PORT_PEC) ? " PEC" : "",
+		(status & PORT_PE) ? " PE" : "",
+		(status & PORT_CSC) ? " CSC" : "",
+		(status & PORT_CONNECT) ? " CONNECT" : ""
+	    );
+}
+
 #else
-#if 0
-static inline void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) {}
-#endif
+static inline void __attribute__((__unused__))
+dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
+{}
+
+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 */
 
 /* functions have the "wrong" filename when they're output... */
+#define dbg_status(ehci, label, status) { \
+	char _buf [80]; \
+	dbg_status_buf (_buf, sizeof _buf, label, status); \
+	dbg ("%s", _buf); \
+}
+
+#define dbg_cmd(ehci, label, command) { \
+	char _buf [80]; \
+	dbg_command_buf (_buf, sizeof _buf, label, command); \
+	dbg ("%s", _buf); \
+}
+
+#define dbg_port(hcd, label, port, status) { \
+	char _buf [80]; \
+	dbg_port_buf (_buf, sizeof _buf, label, port, status); \
+	dbg ("%s", _buf); \
+}
+
+/*-------------------------------------------------------------------------*/
+
+#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)) { \
+		case 0 << 12: tmp = 'f'; break; \
+		case 1 << 12: tmp = 'l'; break; \
+		case 2 << 12: tmp = 'h'; break; \
+		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)
+{
+	struct pci_dev		*pdev;
+	struct ehci_hcd		*ehci;
+	unsigned long		flags;
+	unsigned		temp, size;
+	char			*next;
+	struct ehci_qh		*qh;
+
+	if (off != 0)
+		return 0;
+
+	pdev = container_of (dev, struct pci_dev, dev);
+	ehci = container_of (pci_get_drvdata (pdev), struct ehci_hcd, hcd);
+	next = buf;
+	size = count;
+
+	/* dumps a snapshot of the async schedule.
+	 * usually empty except for long-term bulk reads, or head.
+	 * one QH per line, and TDs we know about
+	 */
+	spin_lock_irqsave (&ehci->lock, flags);
+	if (ehci->async) {
+		qh = ehci->async;
+		do {
+			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_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 ehci_hcd		*ehci;
+	unsigned long		flags;
+	union ehci_shadow	p, *seen;
+	unsigned		temp, size, seen_count;
+	char			*next;
+	unsigned		i, tag;
+
+	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);
+	ehci = container_of (pci_get_drvdata (pdev), struct ehci_hcd, hcd);
+	next = buf;
+	size = count;
+
+	temp = snprintf (next, size, "size = %d\n", ehci->periodic_size);
+	size -= temp;
+	next += temp;
+
+	/* dump a snapshot of the periodic schedule.
+	 * iso changes, interrupt usually doesn't.
+	 */
+	spin_lock_irqsave (&ehci->lock, flags);
+	for (i = 0; i < ehci->periodic_size; i++) {
+		p = ehci->pshadow [i];
+		if (!p.ptr)
+			continue;
+		tag = Q_NEXT_TYPE (ehci->periodic [i]);
+
+		temp = snprintf (next, size, "%4d: ", i);
+		size -= temp;
+		next += temp;
+
+		do {
+			switch (tag) {
+			case Q_TYPE_QH:
+				temp = snprintf (next, size, " qh%d/%p",
+						p.qh->period, p.qh);
+				size -= temp;
+				next += temp;
+				for (temp = 0; temp < seen_count; temp++) {
+					if (seen [temp].ptr == p.ptr)
+						break;
+				}
+				/* show more info the first time around */
+				if (temp == seen_count) {
+					u32	scratch = cpu_to_le32p (
+							&p.qh->hw_info1);
+
+					temp = snprintf (next, size,
+						" (%cs dev%d ep%d [%d/%d] %d)",
+						speed_char (scratch),
+						scratch & 0x007f,
+						(scratch >> 8) & 0x000f,
+						p.qh->usecs, p.qh->c_usecs,
+						scratch >> 16);
+
+					/* FIXME TD info too */
+
+					if (seen_count < DBG_SCHED_LIMIT)
+						seen [seen_count++].qh = p.qh;
+				} else
+					temp = 0;
+				tag = Q_NEXT_TYPE (p.qh->hw_next);
+				p = p.qh->qh_next;
+				break;
+			case Q_TYPE_FSTN:
+				temp = snprintf (next, size,
+					" fstn-%8x/%p", p.fstn->hw_prev,
+					p.fstn);
+				tag = Q_NEXT_TYPE (p.fstn->hw_next);
+				p = p.fstn->fstn_next;
+				break;
+			case Q_TYPE_ITD:
+				temp = snprintf (next, size,
+					" itd/%p", p.itd);
+				tag = Q_NEXT_TYPE (p.itd->hw_next);
+				p = p.itd->itd_next;
+				break;
+			case Q_TYPE_SITD:
+				temp = snprintf (next, size,
+					" sitd/%p", p.sitd);
+				tag = Q_NEXT_TYPE (p.sitd->hw_next);
+				p = p.sitd->sitd_next;
+				break;
+			}
+			size -= temp;
+			next += temp;
+		} while (p.ptr);
+
+		temp = snprintf (next, size, "\n");
+		size -= temp;
+		next += temp;
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	kfree (seen);
+
+	return count - size;
+}
+static DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);
+
+#undef DBG_SCHED_LIMIT
+
+static ssize_t
+show_registers (struct device *dev, char *buf, size_t count, loff_t off)
+{
+	struct pci_dev		*pdev;
+	struct ehci_hcd		*ehci;
+	unsigned long		flags;
+	unsigned		temp, size, i;
+	char			*next, scratch [80];
+	static char		fmt [] = "%*s\n";
+	static char		label [] = "";
+
+	if (off != 0)
+		return 0;
+
+	pdev = container_of (dev, struct pci_dev, dev);
+	ehci = container_of (pci_get_drvdata (pdev), struct ehci_hcd, hcd);
+
+	next = buf;
+	size = count;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	/* Capability Registers */
+	i = readw (&ehci->caps->hci_version);
+	temp = snprintf (next, size, "EHCI %x.%02x, hcd state %d\n",
+		i >> 8, i & 0x0ff, ehci->hcd.state);
+	size -= temp;
+	next += temp;
+
+	// FIXME interpret both types of params
+	i = readl (&ehci->caps->hcs_params);
+	temp = snprintf (next, size, "structural params 0x%08x\n", i);
+	size -= temp;
+	next += temp;
+
+	i = readl (&ehci->caps->hcc_params);
+	temp = snprintf (next, size, "capability params 0x%08x\n", i);
+	size -= temp;
+	next += temp;
+
+	/* Operational Registers */
+	temp = dbg_status_buf (scratch, sizeof scratch, label,
+			readl (&ehci->regs->status));
+	temp = snprintf (next, size, fmt, temp, scratch);
+	size -= temp;
+	next += temp;
+
+	temp = dbg_command_buf (scratch, sizeof scratch, label,
+			readl (&ehci->regs->command));
+	temp = snprintf (next, size, fmt, temp, scratch);
+	size -= temp;
+	next += temp;
+
+	temp = dbg_intr_buf (scratch, sizeof scratch, label,
+			readl (&ehci->regs->intr_enable));
+	temp = snprintf (next, size, fmt, temp, scratch);
+	size -= temp;
+	next += temp;
+
+	temp = snprintf (next, size, "uframe %04x\n",
+			readl (&ehci->regs->frame_index));
+	size -= temp;
+	next += temp;
+
+	for (i = 0; i < HCS_N_PORTS (ehci->hcs_params); i++) {
+		temp = dbg_port_buf (scratch, sizeof scratch, label, i,
+				readl (&ehci->regs->port_status [i]));
+		temp = snprintf (next, size, fmt, temp, scratch);
+		size -= temp;
+		next += temp;
+	}
+
+	if (ehci->reclaim) {
+		temp = snprintf (next, size, "reclaim qh %p%s\n",
+				ehci->reclaim,
+				ehci->reclaim_ready ? " ready" : "");
+		size -= temp;
+		next += temp;
+	}
+
+#ifdef EHCI_STATS
+	temp = snprintf (next, size, "irq normal %ld err %ld reclaim %ld\n",
+		ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim);
+	size -= temp;
+	next += temp;
+
+	temp = snprintf (next, size, "complete %ld unlink %ld qpatch %ld\n",
+		ehci->stats.complete, ehci->stats.unlink, ehci->stats.qpatch);
+	size -= temp;
+	next += temp;
+#endif
+
+	spin_unlock_irqrestore (&ehci->lock, flags);
+
+	return count - size;
+}
+static DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
+
+static inline void create_debug_files (struct ehci_hcd *bus)
+{
+	device_create_file (&bus->hcd.pdev->dev, &dev_attr_async);
+	device_create_file (&bus->hcd.pdev->dev, &dev_attr_periodic);
+	device_create_file (&bus->hcd.pdev->dev, &dev_attr_registers);
+}
+
+static inline void remove_debug_files (struct ehci_hcd *bus)
+{
+	device_remove_file (&bus->hcd.pdev->dev, &dev_attr_async);
+	device_remove_file (&bus->hcd.pdev->dev, &dev_attr_periodic);
+	device_remove_file (&bus->hcd.pdev->dev, &dev_attr_registers);
+}
 
-#define dbg_status(ehci, label, status) \
-	dbg ("%s status 0x%x%s%s%s%s%s%s%s%s%s%s", \
-		label, status, \
-		(status & STS_ASS) ? " Async" : "", \
-		(status & STS_PSS) ? " Periodic" : "", \
-		(status & STS_RECL) ? " Recl" : "", \
-		(status & STS_HALT) ? " Halt" : "", \
-		(status & STS_IAA) ? " IAA" : "", \
-		(status & STS_FATAL) ? " FATAL" : "", \
-		(status & STS_FLR) ? " FLR" : "", \
-		(status & STS_PCD) ? " PCD" : "", \
-		(status & STS_ERR) ? " ERR" : "", \
-		(status & STS_INT) ? " INT" : "" \
-		)
-
-#define dbg_cmd(ehci, label, command) \
-	dbg ("%s %x cmd %s=%d ithresh=%d%s%s%s%s period=%s%s %s", \
-		label, command, \
-		(command & CMD_PARK) ? "park" : "(park)", \
-		CMD_PARK_CNT (command), \
-		(command >> 16) & 0x3f, \
-		(command & CMD_LRESET) ? " LReset" : "", \
-		(command & CMD_IAAD) ? " IAAD" : "", \
-		(command & CMD_ASE) ? " Async" : "", \
-		(command & CMD_PSE) ? " Periodic" : "", \
-		fls_strings [(command >> 2) & 0x3], \
-		(command & CMD_RESET) ? " Reset" : "", \
-		(command & CMD_RUN) ? "RUN" : "HALT" \
-		)
-
-#define dbg_port(hcd, label, port, status) \
-	dbg ("%s port %d status 0x%x%s%s speed=%d%s%s%s%s%s%s%s%s%s", \
-		label, port, status, \
-		(status & PORT_OWNER) ? " OWNER" : "", \
-		(status & PORT_POWER) ? " POWER" : "", \
-		(status >> 10) & 3, \
-		(status & PORT_RESET) ? " RESET" : "", \
-		(status & PORT_SUSPEND) ? " SUSPEND" : "", \
-		(status & PORT_RESUME) ? " RESUME" : "", \
-		(status & PORT_OCC) ? " OCC" : "", \
-		(status & PORT_OC) ? " OC" : "", \
-		(status & PORT_PEC) ? " PEC" : "", \
-		(status & PORT_PE) ? " PE" : "", \
-		(status & PORT_CSC) ? " CSC" : "", \
-		(status & PORT_CONNECT) ? " CONNECT" : "" \
-	    )
+#endif /* STUB_DEBUG_FILES */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/usb/hcd/ehci.h linux.20pre10-ac2/drivers/usb/hcd/ehci.h
--- linux.20pre10/drivers/usb/hcd/ehci.h	2002-10-09 21:36:54.000000000 +0100
+++ linux.20pre10-ac2/drivers/usb/hcd/ehci.h	2002-10-09 22:15:47.000000000 +0100
@@ -21,6 +21,23 @@
 
 /* definitions used for the EHCI driver */
 
+/* statistics can be kept for for tuning/monitoring */
+struct ehci_stats {
+	/* irq usage */
+	unsigned long		normal;
+	unsigned long		error;
+	unsigned long		reclaim;
+
+	/* termination of urbs from core */
+	unsigned long		complete;
+	unsigned long		unlink;
+
+	/* qhs patched to recover from td queueing race
+	 * (can avoid by using 'dummy td', allowing fewer irqs)
+	 */
+	unsigned long		qpatch;
+};
+
 /* ehci_hcd->lock guards shared data against other CPUs:
  *   ehci_hcd:	async, reclaim, periodic (and shadow), ...
  *   hcd_dev:	ep[]
@@ -39,7 +56,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 */
@@ -50,7 +68,7 @@
 
 	union ehci_shadow	*pshadow;	/* mirror hw periodic table */
 	int			next_uframe;	/* scan periodic, start here */
-	unsigned		periodic_urbs;	/* how many urbs scheduled? */
+	unsigned		periodic_sched;	/* periodic activity count */
 
 	/* deferred work from IRQ, etc */
 	struct tasklet_struct	tasklet;
@@ -69,10 +87,19 @@
 	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;
+
+#ifdef EHCI_STATS
+	struct ehci_stats	stats;
+#	define COUNT(x) do { (x)++; } while (0)
+#else
+#	define COUNT(x) do {} while (0)
+#endif
 };
 
 /* unwrap an HCD pointer to get an EHCI_HCD pointer */ 
-#define hcd_to_ehci(hcd_ptr) list_entry(hcd_ptr, struct ehci_hcd, hcd)
+#define hcd_to_ehci(hcd_ptr) container_of(hcd_ptr, struct ehci_hcd, hcd)
 
 /* NOTE:  urb->transfer_flags expected to not use this bit !!! */
 #define EHCI_STATE_UNLINK	0x8000		/* urb being unlinked */
@@ -219,7 +246,6 @@
 
 	/* dma same in urb's qtds, except 1st control qtd (setup buffer) */
 	struct urb		*urb;			/* qtd's urb */
-	dma_addr_t		buf_dma;		/* buffer address */
 	size_t			length;			/* length of buffer */
 } __attribute__ ((aligned (32)));
 
@@ -287,15 +313,20 @@
 	struct list_head	qtd_list;	/* sw qtd list */
 
 	atomic_t		refcount;
-	unsigned short		usecs;		/* intr bandwidth */
-	short			qh_state;
+
+	u8			qh_state;
 #define	QH_STATE_LINKED		1		/* HC sees this */
 #define	QH_STATE_UNLINK		2		/* HC may still see this */
 #define	QH_STATE_IDLE		3		/* HC doesn't see this */
 
-#ifdef EHCI_SOFT_RETRIES
-	int			retries;
-#endif
+	/* periodic schedule info */
+	u8			usecs;		/* intr bandwidth */
+	u8			gap_uf;		/* uframes split/csplit gap */
+	u8			c_usecs;	/* ... split completion bw */
+	unsigned short		period;		/* polling interval */
+	unsigned short		start;		/* where polling starts */
+#define NO_FRAME ((unsigned short)~0)			/* pick new start */
+
 } __attribute__ ((aligned (32)));
 
 /*-------------------------------------------------------------------------*/
@@ -360,6 +391,9 @@
 	union ehci_shadow	sitd_next;	/* ptr to periodic q entry */
 	struct urb		*urb;
 	dma_addr_t		buf_dma;	/* buffer address */
+
+	unsigned short		usecs;		/* start bandwidth */
+	unsigned short		c_usecs;	/* completion bandwidth */
 } __attribute__ ((aligned (32)));
 
 /*-------------------------------------------------------------------------*/
@@ -382,4 +416,39 @@
 	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
+
+static inline int hcd_register_root (struct usb_hcd *hcd)
+{
+	return usb_new_device (hcd_to_bus (hcd)->root_hub);
+}
+
+#else	/* LINUX_VERSION_CODE */
+
+// hcd_to_bus() eventually moves to hcd.h on 2.5 too
+static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
+	{ return &hcd->self; }
+// ... as does hcd_register_root()
+static inline int hcd_register_root (struct usb_hcd *hcd)
+{
+	return usb_register_root_hub (
+		hcd_to_bus (hcd)->root_hub, &hcd->pdev->dev);
+}
+
+#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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/usb/hcd/ehci-hcd.c linux.20pre10-ac2/drivers/usb/hcd/ehci-hcd.c
--- linux.20pre10/drivers/usb/hcd/ehci-hcd.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/usb/hcd/ehci-hcd.c	2002-09-29 21:02:14.000000000 +0100
@@ -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>
@@ -46,8 +52,6 @@
 #include <asm/system.h>
 #include <asm/unaligned.h>
 
-//#undef KERN_DEBUG
-//#define KERN_DEBUG ""
 
 /*-------------------------------------------------------------------------*/
 
@@ -55,21 +59,24 @@
  * EHCI hc_driver implementation ... experimental, incomplete.
  * Based on the final 1.0 register interface specification.
  *
- * There are lots of things to help out with here ... notably
- * everything "periodic", and of course testing with all sorts
- * of usb 2.0 devices and configurations.
- *
  * USB 2.0 shows up in upcoming www.pcmcia.org technology.
  * First was PCMCIA, like ISA; then CardBus, which is PCI.
  * Next comes "CardBay", using USB 2.0 signals.
  *
- * Contains additional contributions by:
- *	Brad Hards
- *	Rory Bolt
- *	...
+ * Contains additional contributions by: Brad Hards, Rory Bolt, and more.
+ * Special thanks to Intel and VIA for providing host controllers to
+ * test this driver on, and Cypress (including In-System Design) for
+ * providing early devices for those host controllers to talk to!
  *
  * HISTORY:
  *
+ * 2002-08-06	Handling for bulk and interrupt transfers is mostly shared;
+ *	only scheduling is different, no arbitrary limitations.
+ * 2002-07-25	Sanity check PCI reads, mostly for better cardbus support,
+ * 	clean up HC run state handshaking.
+ * 2002-05-24	Preliminary FS/LS interrupts, using scheduling shortcuts
+ * 2002-05-11	Clear TT errors for FS/LS ctrl/bulk.  Fill in some other
+ *	missing pieces:  enabling 64bit dma, handoff from BIOS/SMM.
  * 2002-05-07	Some error path cleanups to report better errors; wmb();
  *	use non-CVS version id; better iso bandwidth claim.
  * 2002-04-19	Control/bulk/interrupt submit no longer uses giveback() on
@@ -85,14 +92,22 @@
  * 2001-June	Works with usb-storage and NEC EHCI on 2.4
  */
 
-#define DRIVER_VERSION "2002-May-07"
+#define DRIVER_VERSION "2002-Sep-23"
 #define DRIVER_AUTHOR "David Brownell"
 #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
 
+static const char	hcd_name [] = "ehci-hcd";
+
 
 // #define EHCI_VERBOSE_DEBUG
 // #define have_split_iso
 
+#ifdef DEBUG
+#define EHCI_STATS
+#endif
+
+#define INTR_AUTOMAGIC		/* to be removed later in 2.5 */
+
 /* magic numbers that can affect system performance */
 #define	EHCI_TUNE_CERR		3	/* 0-3 qtd retries; 0 == don't stop */
 #define	EHCI_TUNE_RL_HS		0	/* nak throttle; see 4.9 */
@@ -100,11 +115,20 @@
 #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");
 MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
 
+/* allow irqs at least every N URB completions */
+static int max_completions = 16;
+MODULE_PARM (max_completions, "i");
+MODULE_PARM_DESC (max_completions,
+		"limit for urb completions called with irqs disenabled");
+
 #define	INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT)
 
 /*-------------------------------------------------------------------------*/
@@ -115,42 +139,105 @@
 /*-------------------------------------------------------------------------*/
 
 /*
+ * handshake - spin reading hc until handshake completes or fails
+ * @ptr: address of hc register to be read
+ * @mask: bits to look at in result of read
+ * @done: value of those bits when handshake succeeds
+ * @usec: timeout in microseconds
+ *
+ * Returns negative errno, or zero on success
+ *
+ * Success happens when the "mask" bits have the specified value (hardware
+ * handshake done).  There are two failure modes:  "usec" have passed (major
+ * hardware flakeout), or the register reads as all-ones (hardware removed).
+ *
+ * That last failure should_only happen in cases like physical cardbus eject
+ * before driver shutdown. But it also seems to be caused by bugs in cardbus
+ * bridge shutdown:  shutting down the bridge before the devices using it.
+ */
+static int handshake (u32 *ptr, u32 mask, u32 done, int usec)
+{
+	u32	result;
+
+	do {
+		result = readl (ptr);
+		if (result == ~(u32)0)		/* card removed */
+			return -ENODEV;
+		result &= mask;
+		if (result == done)
+			return 0;
+		udelay (1);
+		usec--;
+	} while (usec > 0);
+	return -ETIMEDOUT;
+}
+
+/*
  * hc states include: unknown, halted, ready, running
  * transitional states are messy just now
  * trying to avoid "running" unless urbs are active
  * a "ready" hc can be finishing prefetched work
  */
 
-/* halt a non-running controller */
-static void ehci_reset (struct ehci_hcd *ehci)
+/* force HC to halt state from unknown (EHCI spec section 2.3) */
+static int ehci_halt (struct ehci_hcd *ehci)
+{
+	u32	temp = readl (&ehci->regs->status);
+
+	if ((temp & STS_HALT) != 0)
+		return 0;
+
+	temp = readl (&ehci->regs->command);
+	temp &= ~CMD_RUN;
+	writel (temp, &ehci->regs->command);
+	return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125);
+}
+
+/* reset a non-running (STS_HALT == 1) controller */
+static int ehci_reset (struct ehci_hcd *ehci)
 {
 	u32	command = readl (&ehci->regs->command);
 
 	command |= CMD_RESET;
 	dbg_cmd (ehci, "reset", command);
 	writel (command, &ehci->regs->command);
-	while (readl (&ehci->regs->command) & CMD_RESET)
-		continue;
 	ehci->hcd.state = USB_STATE_HALT;
+	return handshake (&ehci->regs->command, CMD_RESET, 0, 250);
 }
 
 /* idle the controller (from running) */
 static void ehci_ready (struct ehci_hcd *ehci)
 {
-	u32	command;
+	u32	temp;
 
 #ifdef DEBUG
 	if (!HCD_IS_RUNNING (ehci->hcd.state))
 		BUG ();
 #endif
 
-	while (!(readl (&ehci->regs->status) & (STS_ASS | STS_PSS)))
-		udelay (100);
-	command = readl (&ehci->regs->command);
-	command &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
-	writel (command, &ehci->regs->command);
+	/* wait for any schedule enables/disables to take effect */
+	temp = 0;
+	if (ehci->async)
+		temp = STS_ASS;
+	if (ehci->next_uframe != -1)
+		temp |= STS_PSS;
+	if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+				temp, 16 * 125) != 0) {
+		ehci->hcd.state = USB_STATE_HALT;
+		return;
+	}
+
+	/* then disable anything that's still active */
+	temp = readl (&ehci->regs->command);
+	temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
+	writel (temp, &ehci->regs->command);
 
-	// hardware can take 16 microframes to turn off ...
+	/* hardware can take 16 microframes to turn off ... */
+	if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+				0, 16 * 125) != 0) {
+		ehci->hcd.state = USB_STATE_HALT;
+		return;
+	}
 	ehci->hcd.state = USB_STATE_READY;
 }
 
@@ -165,6 +252,52 @@
 
 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).
+ */
+static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
+{
+	if (cap & (1 << 16)) {
+		int msec = 500;
+
+		/* request handoff to OS */
+		cap &= 1 << 24;
+		pci_write_config_dword (ehci->hcd.pdev, where, cap);
+
+		/* and wait a while for it to happen */
+		do {
+			wait_ms (10);
+			msec -= 10;
+			pci_read_config_dword (ehci->hcd.pdev, where, &cap);
+		} while ((cap & (1 << 16)) && msec);
+		if (cap & (1 << 16)) {
+			info ("BIOS handoff failed (%d, %04x)", where, cap);
+			return 1;
+		} 
+		dbg ("BIOS handoff succeeded");
+	} else
+		dbg ("BIOS handoff not needed");
+	return 0;
+}
+
 /* called by khubd or root hub init threads */
 
 static int ehci_start (struct usb_hcd *hcd)
@@ -172,14 +305,11 @@
 	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;
 
-	// FIXME:  given EHCI 0.96 or later, and a controller with
-	// the USBLEGSUP/USBLEGCTLSTS extended capability, make sure
-	// the BIOS doesn't still own this controller.
-
 	spin_lock_init (&ehci->lock);
 
 	ehci->caps = (struct ehci_caps *) hcd->regs;
@@ -187,9 +317,37 @@
 	dbg_hcs_params (ehci, "ehci_start");
 	dbg_hcc_params (ehci, "ehci_start");
 
+	hcc_params = readl (&ehci->caps->hcc_params);
+
+	/* EHCI 0.96 and later may have "extended capabilities" */
+	temp = HCC_EXT_CAPS (hcc_params);
+	while (temp) {
+		u32		cap;
+
+		pci_read_config_dword (ehci->hcd.pdev, temp, &cap);
+		dbg ("capability %04x at %02x", cap, temp);
+		switch (cap & 0xff) {
+		case 1:			/* BIOS/SMM/... handoff */
+			if (bios_handoff (ehci, temp, cap) != 0)
+				return -EOPNOTSUPP;
+			break;
+		case 0:			/* illegal reserved capability */
+			warn ("illegal capability!");
+			cap = 0;
+			/* FALLTHROUGH */
+		default:		/* unknown */
+			break;
+		}
+		temp = (cap >> 8) & 0xff;
+	}
+
 	/* cache this readonly data; minimize PCI reads */
 	ehci->hcs_params = readl (&ehci->caps->hcs_params);
 
+	/* force HC to halt state */
+	if ((retval = ehci_halt (ehci)) != 0)
+		return retval;
+
 	/*
 	 * hw default: 1K periodic list heads, one per frame.
 	 * periodic_size can shrink by USBCMD update if hcc_params allows.
@@ -197,7 +355,6 @@
 	ehci->periodic_size = DEFAULT_I_TDPS;
 	if ((retval = ehci_mem_init (ehci, SLAB_KERNEL)) < 0)
 		return retval;
-	hcc_params = readl (&ehci->caps->hcc_params);
 
 	/* controllers may cache some of the periodic schedule ... */
 	if (HCC_ISOC_CACHE (hcc_params)) 	// full frame cache
@@ -212,8 +369,10 @@
 	/* controller state:  unknown --> reset */
 
 	/* EHCI spec section 4.1 */
-	// FIXME require STS_HALT before reset...
-	ehci_reset (ehci);
+	if ((retval = ehci_reset (ehci)) != 0) {
+		ehci_mem_cleanup (ehci);
+		return retval;
+	}
 	writel (INTR_MASK, &ehci->regs->intr_enable);
 	writel (ehci->periodic_dma, &ehci->regs->frame_list);
 
@@ -221,23 +380,25 @@
 	 * hcc_params controls whether ehci->regs->segment must (!!!)
 	 * be used; it constrains QH/ITD/SITD and QTD locations.
 	 * pci_pool consistent memory always uses segment zero.
+	 * streaming mappings for I/O buffers, like pci_map_single(),
+	 * can return segments above 4GB, if the device allows.
+	 *
+	 * 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);
-		/*
-		 * FIXME Enlarge pci_set_dma_mask() when possible.  The DMA
-		 * mapping API spec now says that'll affect only single shot
-		 * mappings, and the pci_pool data will stay safe in seg 0.
-		 * That's what we want:  no extra copies for USB transfers.
-		 */
-		info ("restricting 64bit DMA mappings to segment 0 ...");
+		if (!pci_set_dma_mask (ehci->hcd.pdev, 0xffffffffffffffffULL))
+			info ("enabled 64bit PCI DMA (DAC)");
 	}
 
 	/* clear interrupt enables, set irq latency */
 	temp = readl (&ehci->regs->command) & 0xff;
 	if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
-	    log2_irq_thresh = 0;
+		log2_irq_thresh = 0;
 	temp |= 1 << (16 + log2_irq_thresh);
+	// if hc can park (ehci >= 0.96), default is 3 packets per async QH 
 	// keeping default periodic framelist size
 	temp &= ~(CMD_IAAD | CMD_ASE | CMD_PSE),
 	// Philips, Intel, and maybe others need CMD_RUN before the
@@ -251,8 +412,13 @@
 	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->bus->root_hub = udev = usb_alloc_dev (NULL, hcd->bus);
+	bus = hcd_to_bus (hcd);
+	bus->root_hub = udev = usb_alloc_dev (NULL, bus);
 	if (!udev) {
 done2:
 		ehci_mem_cleanup (ehci);
@@ -271,11 +437,10 @@
         /* 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",
-	      ((tempbyte & 0xf0)>>4),
-	      (tempbyte & 0x0f),
-	       temp >> 8,
-	       temp & 0xff);
+	info ("USB %x.%x support enabled, EHCI rev %x.%02x, %s %s",
+	      ((tempbyte & 0xf0)>>4), (tempbyte & 0x0f),
+	       temp >> 8, temp & 0xff,
+	       hcd_name, DRIVER_VERSION);
 
 	/*
 	 * From here on, khubd concurrently accesses the root
@@ -286,19 +451,18 @@
 	 */
 	usb_connect (udev);
 	udev->speed = USB_SPEED_HIGH;
-	if (usb_new_device (udev) != 0) {
+	if (hcd_register_root (hcd) != 0) {
 		if (hcd->state == USB_STATE_RUNNING)
 			ehci_ready (ehci);
-		while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
-			udelay (100);
 		ehci_reset (ehci);
-		// usb_disconnect (udev); 
-		hcd->bus->root_hub = 0;
+		bus->root_hub = 0;
 		usb_free_dev (udev); 
 		retval = -ENODEV;
 		goto done2;
 	}
 
+	create_debug_files (ehci);
+
 	return 0;
 }
 
@@ -308,20 +472,34 @@
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 
-	dbg ("%s: stop", hcd->bus_name);
+	dbg ("%s: stop", hcd_to_bus (hcd)->bus_name);
 
+	/* no more interrupts ... */
 	if (hcd->state == USB_STATE_RUNNING)
 		ehci_ready (ehci);
-	while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
-		udelay (100);
+	if (in_interrupt ())		/* should not happen!! */
+		err ("stopped %s!", RUN_CONTEXT);
+	else
+		del_timer_sync (&ehci->watchdog);
 	ehci_reset (ehci);
 
-	// root hub is shut down separately (first, when possible)
-	scan_async (ehci);
-	if (ehci->next_uframe != -1)
-		scan_periodic (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) */
+	tasklet_disable (&ehci->tasklet);
+	ehci_tasklet ((unsigned long) ehci);
 	ehci_mem_cleanup (ehci);
 
+#ifdef	EHCI_STATS
+	dbg ("irq normal %ld err %ld reclaim %ld",
+		ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim);
+	dbg ("complete %ld unlink %ld qpatch %ld",
+		ehci->stats.complete, ehci->stats.unlink, ehci->stats.qpatch);
+#endif
+
 	dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
 }
 
@@ -343,7 +521,7 @@
 	int			ports;
 	int			i;
 
-	dbg ("%s: suspend to %d", hcd->bus_name, state);
+	dbg ("%s: suspend to %d", hcd_to_bus (hcd)->bus_name, state);
 
 	ports = HCS_N_PORTS (ehci->hcs_params);
 
@@ -360,15 +538,13 @@
 		if ((temp & PORT_PE) == 0
 				|| (temp & PORT_OWNER) != 0)
 			continue;
-dbg ("%s: suspend port %d", hcd->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]);
 	}
 
 	if (hcd->state == USB_STATE_RUNNING)
 		ehci_ready (ehci);
-	while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
-		udelay (100);
 	writel (readl (&ehci->regs->command) & ~CMD_RUN, &ehci->regs->command);
 
 // save pci FLADJ value
@@ -384,7 +560,7 @@
 	int			ports;
 	int			i;
 
-	dbg ("%s: resume", hcd->bus_name);
+	dbg ("%s: resume", hcd_to_bus (hcd)->bus_name);
 
 	ports = HCS_N_PORTS (ehci->hcs_params);
 
@@ -404,7 +580,7 @@
 		if ((temp & PORT_PE) == 0
 				|| (temp & PORT_SUSPEND) != 0)
 			continue;
-dbg ("%s: resume port %d", hcd->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 */
@@ -429,11 +605,15 @@
 {
 	struct ehci_hcd		*ehci = (struct ehci_hcd *) param;
 
+	spin_lock_irq (&ehci->lock);
+
 	if (ehci->reclaim_ready)
 		end_unlink_async (ehci);
 	scan_async (ehci);
 	if (ehci->next_uframe != -1)
 		scan_periodic (ehci);
+
+	spin_unlock_irq (&ehci->lock);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -444,6 +624,12 @@
 	u32			status = readl (&ehci->regs->status);
 	int			bh;
 
+	/* e.g. cardbus physical eject */
+	if (status == ~(u32) 0) {
+		dbg ("%s: device removed!", hcd_to_bus (hcd)->bus_name);
+		goto dead;
+	}
+
 	status &= INTR_MASK;
 	if (!status)			/* irq sharing? */
 		return;
@@ -461,21 +647,30 @@
 	/* INT, ERR, and IAA interrupt rates can be throttled */
 
 	/* normal [4.15.1.2] or error [4.15.1.1] completion */
-	if (likely ((status & (STS_INT|STS_ERR)) != 0))
+	if (likely ((status & (STS_INT|STS_ERR)) != 0)) {
+		if (likely ((status & STS_ERR) == 0))
+			COUNT (ehci->stats.normal);
+		else
+			COUNT (ehci->stats.error);
 		bh = 1;
+	}
 
 	/* complete the unlinking of some qh [4.15.2.3] */
 	if (status & STS_IAA) {
+		COUNT (ehci->stats.reclaim);
 		ehci->reclaim_ready = 1;
 		bh = 1;
 	}
 
 	/* PCI errors [4.15.2.4] */
 	if (unlikely ((status & STS_FATAL) != 0)) {
-		err ("%s: fatal error, state %x", hcd->bus_name, hcd->state);
+		err ("%s: fatal error, state %x",
+			hcd_to_bus (hcd)->bus_name, hcd->state);
+dead:
 		ehci_reset (ehci);
-		// generic layer kills/unlinks all urbs
-		// then tasklet cleans up the rest
+		/* generic layer kills/unlinks all urbs, then
+		 * uses ehci_stop to clean up the rest
+		 */
 		bh = 1;
 	}
 
@@ -495,7 +690,8 @@
  *
  * hcd-specific init for hcpriv hasn't been done yet
  *
- * NOTE:  EHCI queues control and bulk requests transparently, like OHCI.
+ * NOTE:  control, bulk, and interrupt share the same code to append TDs
+ * to a (possibly active) QH, and the same QH scanning code.
  */
 static int ehci_urb_enqueue (
 	struct usb_hcd	*hcd,
@@ -507,10 +703,11 @@
 
 	urb->transfer_flags &= ~EHCI_STATE_UNLINK;
 	INIT_LIST_HEAD (&qtd_list);
-	switch (usb_pipetype (urb->pipe)) {
 
-	case PIPE_CONTROL:
-	case PIPE_BULK:
+	switch (usb_pipetype (urb->pipe)) {
+	// case PIPE_CONTROL:
+	// case PIPE_BULK:
+	default:
 		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
 			return -ENOMEM;
 		return submit_async (ehci, urb, &qtd_list, mem_flags);
@@ -530,9 +727,6 @@
 		dbg ("no split iso support yet");
 		return -ENOSYS;
 #endif /* have_split_iso */
-
-	default:	/* can't happen */
-		return -ENOSYS;
 	}
 }
 
@@ -546,15 +740,22 @@
 	struct ehci_qh		*qh = (struct ehci_qh *) urb->hcpriv;
 	unsigned long		flags;
 
-	dbg ("%s urb_dequeue %p qh state %d",
-		hcd->bus_name, urb, qh->qh_state);
+	dbg ("%s urb_dequeue %p qh %p state %d",
+		hcd_to_bus (hcd)->bus_name, urb, qh, qh->qh_state);
 
 	switch (usb_pipetype (urb->pipe)) {
-	case PIPE_CONTROL:
-	case PIPE_BULK:
+	// case PIPE_CONTROL:
+	// case PIPE_BULK:
+	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;
@@ -564,28 +765,43 @@
 					&& ehci->hcd.state != USB_STATE_HALT
 					) {
 				spin_unlock_irqrestore (&ehci->lock, flags);
-// yeech ... this could spin for up to two frames!
-dbg ("wait for dequeue: state %d, reclaim %p, hcd state %d",
-    qh->qh_state, ehci->reclaim, ehci->hcd.state
-);
-				udelay (100);
+				/* let pending unlinks complete */
+				wait_ms (1);
 				spin_lock_irqsave (&ehci->lock, flags);
 			}
 		}
 		if (qh->qh_state == QH_STATE_LINKED)
 			start_unlink_async (ehci, qh);
 		spin_unlock_irqrestore (&ehci->lock, flags);
-		return 0;
+		break;
 
 	case PIPE_INTERRUPT:
-		intr_deschedule (ehci, urb->start_frame, qh,
-			(urb->dev->speed == USB_SPEED_HIGH)
-			    ? urb->interval
-			    : (urb->interval << 3));
-		if (ehci->hcd.state == USB_STATE_HALT)
-			urb->status = -ESHUTDOWN;
-		qh_completions (ehci, qh, 1);
-		return 0;
+		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);
+			/* qh_state == IDLE */
+		}
+		qh_completions (ehci, qh);
+
+		/* reschedule QH iff another request is queued */
+		if (!list_empty (&qh->qtd_list)
+				&& HCD_IS_RUNNING (ehci->hcd.state)) {
+			int status;
+
+			status = qh_schedule (ehci, qh);
+			spin_unlock_irqrestore (&ehci->lock, flags);
+
+			if (status != 0) {
+				// shouldn't happen often, but ...
+				// FIXME kill those tds' urbs
+				err ("can't reschedule qh %p, err %d",
+					qh, status);
+			}
+			return status;
+		}
+		spin_unlock_irqrestore (&ehci->lock, flags);
+		break;
 
 	case PIPE_ISOCHRONOUS:
 		// itd or sitd ...
@@ -593,9 +809,9 @@
 		// wait till next completion, do it then.
 		// completion irqs can wait up to 1024 msec,
 		urb->transfer_flags |= EHCI_STATE_UNLINK;
-		return 0;
+		break;
 	}
-	return -EINVAL;
+	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -609,42 +825,67 @@
 	int			i;
 	unsigned long		flags;
 
+	/* 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->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++) {
 		if (dev->ep [i]) {
 			struct ehci_qh		*qh;
+			char			*why;
 
 			/* dev->ep never has ITDs or SITDs */
 			qh = (struct ehci_qh *) dev->ep [i];
-			vdbg ("free_config, ep 0x%02x qh %p", i, qh);
-			if (!list_empty (&qh->qtd_list)) {
-				dbg ("ep 0x%02x qh %p not empty!", i, qh);
+
+			/* detect/report non-recoverable errors */
+			if (in_interrupt ()) 
+				why = "disconnect() didn't";
+			else if ((qh->hw_info2 & cpu_to_le32 (0xffff)) != 0
+					&& qh->qh_state != QH_STATE_IDLE)
+				why = "(active periodic)";
+			else
+				why = 0;
+			if (why) {
+				err ("dev %s-%s ep %d-%s error: %s",
+					hcd_to_bus (hcd)->bus_name,
+					udev->devpath,
+					i & 0xf, (i & 0x10) ? "IN" : "OUT",
+					why);
 				BUG ();
 			}
-			dev->ep [i] = 0;
 
-			/* wait_ms() won't spin here -- we're a thread */
+			dev->ep [i] = 0;
+			if (qh->qh_state == QH_STATE_IDLE)
+				goto idle;
+			dbg ("free_config, async ep 0x%02x qh %p", i, qh);
+
+			/* scan_async() empties the ring as it does its work,
+			 * using IAA, but doesn't (yet?) turn it off.  if it
+			 * doesn't empty this qh, likely it's the last entry.
+			 */
 			while (qh->qh_state == QH_STATE_LINKED
 					&& ehci->reclaim
 					&& ehci->hcd.state != USB_STATE_HALT
 					) {
 				spin_unlock_irqrestore (&ehci->lock, flags);
+				/* wait_ms() won't spin, we're a thread;
+				 * and we know IRQ+tasklet can progress
+				 */
 				wait_ms (1);
 				spin_lock_irqsave (&ehci->lock, flags);
 			}
-			if (qh->qh_state == QH_STATE_LINKED) {
+			if (qh->qh_state == QH_STATE_LINKED)
 				start_unlink_async (ehci, qh);
-				while (qh->qh_state != QH_STATE_IDLE) {
-					spin_unlock_irqrestore (&ehci->lock,
-						flags);
-					wait_ms (1);
-					spin_lock_irqsave (&ehci->lock, flags);
-				}
+			while (qh->qh_state != QH_STATE_IDLE
+					&& ehci->hcd.state != USB_STATE_HALT) {
+				spin_unlock_irqrestore (&ehci->lock, flags);
+				wait_ms (1);
+				spin_lock_irqsave (&ehci->lock, flags);
 			}
+idle:
 			qh_put (ehci, qh);
 		}
 	}
@@ -654,50 +895,48 @@
 
 /*-------------------------------------------------------------------------*/
 
-static const char	hcd_name [] = "ehci-hcd";
-
 static const struct hc_driver ehci_driver = {
-	description:		hcd_name,
+	.description =		hcd_name,
 
 	/*
 	 * generic hardware linkage
 	 */
-	irq:			ehci_irq,
-	flags:			HCD_MEMORY | HCD_USB2,
+	.irq =			ehci_irq,
+	.flags =		HCD_MEMORY | HCD_USB2,
 
 	/*
 	 * basic lifecycle operations
 	 */
-	start:			ehci_start,
+	.start =		ehci_start,
 #ifdef	CONFIG_PM
-	suspend:		ehci_suspend,
-	resume:			ehci_resume,
+	.suspend =		ehci_suspend,
+	.resume =		ehci_resume,
 #endif
-	stop:			ehci_stop,
+	.stop =			ehci_stop,
 
 	/*
 	 * memory lifecycle (except per-request)
 	 */
-	hcd_alloc:		ehci_hcd_alloc,
-	hcd_free:		ehci_hcd_free,
+	.hcd_alloc =		ehci_hcd_alloc,
+	.hcd_free =		ehci_hcd_free,
 
 	/*
 	 * managing i/o requests and associated device resources
 	 */
-	urb_enqueue:		ehci_urb_enqueue,
-	urb_dequeue:		ehci_urb_dequeue,
-	free_config:		ehci_free_config,
+	.urb_enqueue =		ehci_urb_enqueue,
+	.urb_dequeue =		ehci_urb_dequeue,
+	.free_config =		ehci_free_config,
 
 	/*
 	 * scheduling support
 	 */
-	get_frame_number:	ehci_get_frame,
+	.get_frame_number =	ehci_get_frame,
 
 	/*
 	 * root hub support
 	 */
-	hub_status_data:	ehci_hub_status_data,
-	hub_control:		ehci_hub_control,
+	.hub_status_data =	ehci_hub_status_data,
+	.hub_control =		ehci_hub_control,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -709,15 +948,15 @@
 
 	/* handle any USB 2.0 EHCI controller */
 
-	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x20),
-	class_mask: 	~0,
-	driver_data:	(unsigned long) &ehci_driver,
+	.class = 		((PCI_CLASS_SERIAL_USB << 8) | 0x20),
+	.class_mask = 	~0,
+	.driver_data =	(unsigned long) &ehci_driver,
 
 	/* no matter who makes it */
-	vendor:		PCI_ANY_ID,
-	device:		PCI_ANY_ID,
-	subvendor:	PCI_ANY_ID,
-	subdevice:	PCI_ANY_ID,
+	.vendor =	PCI_ANY_ID,
+	.device =	PCI_ANY_ID,
+	.subvendor =	PCI_ANY_ID,
+	.subdevice =	PCI_ANY_ID,
 
 }, { /* end: all zeroes */ }
 };
@@ -725,21 +964,20 @@
 
 /* pci driver glue; this is a "new style" PCI driver module */
 static struct pci_driver ehci_pci_driver = {
-	name:		(char *) hcd_name,
-	id_table:	pci_ids,
+	.name =		(char *) hcd_name,
+	.id_table =	pci_ids,
 
-	probe:		usb_hcd_pci_probe,
-	remove:		usb_hcd_pci_remove,
+	.probe =	usb_hcd_pci_probe,
+	.remove =	usb_hcd_pci_remove,
 
 #ifdef	CONFIG_PM
-	suspend:	usb_hcd_pci_suspend,
-	resume:		usb_hcd_pci_resume,
+	.suspend =	usb_hcd_pci_suspend,
+	.resume =	usb_hcd_pci_resume,
 #endif
 };
 
 #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
 
-EXPORT_NO_SYMBOLS;
 MODULE_DESCRIPTION (DRIVER_INFO);
 MODULE_AUTHOR (DRIVER_AUTHOR);
 MODULE_LICENSE ("GPL");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/usb/hcd/ehci-hub.c linux.20pre10-ac2/drivers/usb/hcd/ehci-hub.c
--- linux.20pre10/drivers/usb/hcd/ehci-hub.c	2002-10-09 21:36:54.000000000 +0100
+++ linux.20pre10-ac2/drivers/usb/hcd/ehci-hub.c	2002-09-29 21:02:14.000000000 +0100
@@ -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.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.bus_name, index + 1);
+		dbg ("%s port %d high speed",
+			hcd_to_bus (&ehci->hcd)->bus_name,
+			index + 1);
 
 	return port_status;
 }
@@ -236,7 +239,8 @@
 
 		/* whoever resets must GetPortStatus to complete it!! */
 		if ((temp & PORT_RESET)
-				&& jiffies > ehci->reset_done [wIndex]) {
+				&& time_after (jiffies,
+					ehci->reset_done [wIndex])) {
 			status |= 1 << USB_PORT_FEAT_C_RESET;
 
 			/* force reset to complete */
@@ -310,11 +314,13 @@
 			if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
 					&& PORT_USB11 (temp)) {
 				dbg ("%s port %d low speed, give to companion",
-					hcd->bus_name, wIndex + 1);
+					hcd_to_bus (&ehci->hcd)->bus_name,
+					wIndex + 1);
 				temp |= PORT_OWNER;
 			} else {
 				vdbg ("%s port %d reset",
-					hcd->bus_name, wIndex + 1);
+					hcd_to_bus (&ehci->hcd)->bus_name,
+					wIndex + 1);
 				temp |= PORT_RESET;
 				temp &= ~PORT_PE;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/usb/hcd/ehci-q.c linux.20pre10-ac2/drivers/usb/hcd/ehci-q.c
--- linux.20pre10/drivers/usb/hcd/ehci-q.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/usb/hcd/ehci-q.c	2002-09-29 21:02:14.000000000 +0100
@@ -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
@@ -47,9 +46,11 @@
 qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token)
 {
 	int	i, count;
+	u64	addr = buf;
 
 	/* one buffer entry per 4K ... first might be short or unaligned */
-	qtd->hw_buf [0] = cpu_to_le32 (buf);
+	qtd->hw_buf [0] = cpu_to_le32 ((u32)addr);
+	qtd->hw_buf_hi [0] = cpu_to_le32 ((u32)(addr >> 32));
 	count = 0x1000 - (buf & 0x0fff);	/* rest of that page */
 	if (likely (len < count))		/* ... iff needed */
 		count = len;
@@ -59,7 +60,7 @@
 
 		/* per-qtd limit: from 16K to 20K (best alignment) */
 		for (i = 1; count < len && i < 5; i++) {
-			u64	addr = buf;
+			addr = buf;
 			qtd->hw_buf [i] = cpu_to_le32 ((u32)addr);
 			qtd->hw_buf_hi [i] = cpu_to_le32 ((u32)(addr >> 32));
 			buf += 0x1000;
@@ -144,97 +145,106 @@
 					usb_pipeendpoint (pipe),
 					usb_pipeout (pipe));
 			if (urb->dev->tt && !usb_pipeint (pipe)) {
-err ("must CLEAR_TT_BUFFER, hub port %d%s addr %d ep %d",
-    urb->dev->ttport, /* devpath */
-    urb->dev->tt->multi ? "" : " (all-ports TT)",
-    urb->dev->devnum, usb_pipeendpoint (urb->pipe));
-				// FIXME something (khubd?) should make the hub
-				// CLEAR_TT_BUFFER ASAP, it's blocking other
-				// fs/ls requests... hub_tt_clear_buffer() ?
+#ifdef DEBUG
+				struct usb_device *tt = urb->dev->tt->hub;
+				dbg ("clear tt %s-%s p%d buffer, a%d ep%d",
+					tt->bus->bus_name, tt->devpath,
+    					urb->dev->ttport, urb->dev->devnum,
+    					usb_pipeendpoint (pipe));
+#endif /* DEBUG */
+				usb_hub_tt_clear_buffer (urb->dev, pipe);
 			}
 		}
 	}
 }
 
-static void ehci_urb_complete (
-	struct ehci_hcd		*ehci,
-	dma_addr_t		addr,
-	struct urb		*urb
-) {
-	if (urb->transfer_buffer_length && usb_pipein (urb->pipe))
-		pci_dma_sync_single (ehci->hcd.pdev, addr,
-			urb->transfer_buffer_length,
-			PCI_DMA_FROMDEVICE);
+static void ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb)
+{
+#ifdef	INTR_AUTOMAGIC
+	struct urb		*resubmit = 0;
+	struct usb_device	*dev = 0;
 
-	/* cleanse status if we saw no error */
-	if (likely (urb->status == -EINPROGRESS)) {
-		if (urb->actual_length != urb->transfer_buffer_length
-				&& (urb->transfer_flags & USB_DISABLE_SPD))
-			urb->status = -EREMOTEIO;
-		else
-			urb->status = 0;
-	}
+	static int ehci_urb_enqueue (struct usb_hcd *, struct urb *, int);
+#endif
 
-	/* only report unlinks once */
-	if (likely (urb->status != -ENOENT && urb->status != -ENOTCONN))
-		urb->complete (urb);
-}
+	if (likely (urb->hcpriv != 0)) {
+		struct ehci_qh	*qh = (struct ehci_qh *) urb->hcpriv;
 
-/* urb->lock ignored from here on (hcd is done with urb) */
+		/* S-mask in a QH means it's an interrupt urb */
+		if ((qh->hw_info2 & cpu_to_le32 (0x00ff)) != 0) {
 
-static void ehci_urb_done (
-	struct ehci_hcd		*ehci,
-	dma_addr_t		addr,
-	struct urb		*urb
-) {
-	if (urb->transfer_buffer_length)
-		pci_unmap_single (ehci->hcd.pdev,
-			addr,
-			urb->transfer_buffer_length,
-			usb_pipein (urb->pipe)
-			    ? PCI_DMA_FROMDEVICE
-			    : PCI_DMA_TODEVICE);
-	if (likely (urb->hcpriv != 0)) {
-		qh_put (ehci, (struct ehci_qh *) urb->hcpriv);
+			/* ... update hc-wide periodic stats (for usbfs) */
+			hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs--;
+
+#ifdef	INTR_AUTOMAGIC
+			if (!((urb->status == -ENOENT)
+					|| (urb->status == -ECONNRESET))) {
+				resubmit = usb_get_urb (urb);
+				dev = urb->dev;
+			}
+#endif
+		}
+		qh_put (ehci, qh);
 		urb->hcpriv = 0;
 	}
 
 	if (likely (urb->status == -EINPROGRESS)) {
 		if (urb->actual_length != urb->transfer_buffer_length
-				&& (urb->transfer_flags & USB_DISABLE_SPD))
+				&& (urb->transfer_flags & URB_SHORT_NOT_OK))
 			urb->status = -EREMOTEIO;
 		else
 			urb->status = 0;
 	}
 
-	/* hand off urb ownership */
+	if (likely (urb->status == 0))
+		COUNT (ehci->stats.complete);
+	else if (urb->status == -ECONNRESET || urb->status == -ENOENT)
+		COUNT (ehci->stats.unlink);
+	else
+		COUNT (ehci->stats.error);
+
+	/* complete() can reenter this HCD */
+	spin_unlock (&ehci->lock);
 	usb_hcd_giveback_urb (&ehci->hcd, urb);
+
+#ifdef	INTR_AUTOMAGIC
+	if (resubmit && ((urb->status == -ENOENT)
+				|| (urb->status == -ECONNRESET))) {
+		usb_put_urb (resubmit);
+		resubmit = 0;
+	}
+	// device drivers will soon be doing something like this
+	if (resubmit) {
+		int	status;
+
+		resubmit->dev = dev;
+		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 (&ehci->lock);
 }
 
 
 /*
- * Process completed qtds for a qh, issuing completions if needed.
- * When freeing:  frees qtds, unmaps buf, returns URB to driver.
- * When not freeing (queued periodic qh):  retain qtds, mapping, and urb.
- * 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 number of completions called,
+ * indicating how much "real" work we did.
  */
-static int
-qh_completions (
-	struct ehci_hcd		*ehci,
-	struct ehci_qh		*qh,
-	int			freeing
-) {
+static unsigned
+qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
 	struct ehci_qtd		*qtd, *last;
 	struct list_head	*next, *qtd_list = &qh->qtd_list;
 	int			unlink = 0, halted = 0;
-	unsigned long		flags;
-	int			retval = 0;
+	unsigned		count = 0;
 
-	spin_lock_irqsave (&ehci->lock, flags);
-	if (unlikely (list_empty (qtd_list))) {
-		spin_unlock_irqrestore (&ehci->lock, flags);
-		return retval;
-	}
+	if (unlikely (list_empty (qtd_list)))
+		return count;
 
 	/* scan QTDs till end of list, or we reach an active one */
 	for (qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list),
@@ -248,16 +258,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);
-				if (likely (freeing != 0))
-					ehci_urb_done (ehci, last->buf_dma,
-						last->urb);
-				else
-					ehci_urb_complete (ehci, last->buf_dma,
-						last->urb);
-				spin_lock_irqsave (&ehci->lock, flags);
-				retval++;
+				ehci_urb_done (ehci, last->urb);
+				count++;
 			}
 
 			/* qh overlays can have HC's old cached copies of
@@ -267,10 +269,10 @@
 					&& last->hw_next != qh->hw_qtd_next) {
 				qh->hw_alt_next = last->hw_alt_next;
 				qh->hw_qtd_next = last->hw_next;
+				COUNT (ehci->stats.qpatch);
 			}
 
-			if (likely (freeing != 0))
-				ehci_qtd_free (ehci, last);
+			ehci_qtd_free (ehci, last);
 			last = 0;
 		}
 		next = qtd->qtd_list.next;
@@ -285,9 +287,17 @@
 			|| (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)) {
-			freeing = unlink = 1;
+			unlink = 1;
 			/* status copied below */
 
 		/* QH halts only because of fault (above) or unlink (here). */
@@ -295,13 +305,14 @@
 
 			/* unlinking everything because of HC shutdown? */
 			if (ehci->hcd.state == USB_STATE_HALT) {
-				freeing = unlink = 1;
+				unlink = 1;
 
 			/* explicit unlink, maybe starting here? */
 			} else if (qh->qh_state == QH_STATE_IDLE
 					&& (urb->status == -ECONNRESET
+						|| urb->status == -ESHUTDOWN
 						|| urb->status == -ENOENT)) {
-				freeing = unlink = 1;
+				unlink = 1;
 
 			/* QH halted to unlink urbs _after_ this?  */
 			} else if (!unlink && (token & QTD_STS_ACTIVE) != 0) {
@@ -311,7 +322,7 @@
 
 			/* unlink the rest?  once we start unlinking, after
 			 * a fault or explicit unlink, we unlink all later
-			 * urbs.  usb spec requires that.
+			 * urbs.  usb spec requires that for faults...
 			 */
 			if (unlink && urb->status == -EINPROGRESS)
 				urb->status = -ECONNRESET;
@@ -329,31 +340,7 @@
 		qtd_copy_status (urb, qtd->length, token);
 		spin_unlock (&urb->lock);
 
-		/*
-		 * NOTE:  this won't work right with interrupt urbs that
-		 * need multiple qtds ... only the first scan of qh->qtd_list
-		 * starts at the right qtd, yet multiple scans could happen
-		 * for transfers that are scheduled across multiple uframes. 
-		 * (Such schedules are not currently allowed!)
-		 */
-		if (likely (freeing != 0))
-			list_del (&qtd->qtd_list);
-		else {
-			/* restore everything the HC could change
-			 * from an interrupt QTD
-			 */
-			qtd->hw_token = (qtd->hw_token
-					& __constant_cpu_to_le32 (0x8300))
-				| cpu_to_le32 (qtd->length << 16)
-				| __constant_cpu_to_le32 (QTD_STS_ACTIVE
-					| (EHCI_TUNE_CERR << 10));
-			qtd->hw_buf [0] &= ~__constant_cpu_to_le32 (0x0fff);
-
-			/* this offset, and the length above,
-			 * are likely wrong on QTDs #2..N
-			 */
-			qtd->hw_buf [0] |= cpu_to_le32 (0x0fff & qtd->buf_dma);
-		}
+		list_del (&qtd->qtd_list);
 
 #if 0
 		if (urb->status == -EINPROGRESS)
@@ -364,31 +351,22 @@
 				urb, urb->status, qtd, token,
 				urb->actual_length);
 #endif
+	}
 
-		/* SETUP for control urb? */
-		if (unlikely (QTD_PID (token) == 2))
-			pci_unmap_single (ehci->hcd.pdev,
-				qtd->buf_dma, sizeof (struct usb_ctrlrequest),
-				PCI_DMA_TODEVICE);
+	/* last urb's completion might still need calling */
+	if (likely (last != 0)) {
+		ehci_urb_done (ehci, last->urb);
+		count++;
+		ehci_qtd_free (ehci, last);
 	}
 
-	/* patch up list head? */
+	/* 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)) {
-		if (likely (freeing != 0)) {
-			ehci_urb_done (ehci, last->buf_dma, last->urb);
-			ehci_qtd_free (ehci, last);
-		} else
-			ehci_urb_complete (ehci, last->buf_dma, last->urb);
-		retval++;
-	}
-	return retval;
+	return count;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -403,35 +381,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++;
-			}
-			if (qtd->buf_dma)
-				pci_unmap_single (ehci->hcd.pdev,
-					qtd->buf_dma,
-					size, direction);
-		}
 		ehci_qtd_free (ehci, qtd);
 	}
 }
@@ -447,8 +402,9 @@
 	int			flags
 ) {
 	struct ehci_qtd		*qtd, *qtd_prev;
-	dma_addr_t		buf, map_buf;
+	dma_addr_t		buf;
 	int			len, maxpacket;
+	int			is_input, status_patch = 0;
 	u32			token;
 
 	/*
@@ -466,17 +422,8 @@
 	/* for split transactions, SplitXState initialized to zero */
 
 	if (usb_pipecontrol (urb->pipe)) {
-		/* control request data is passed in the "setup" pid */
-		qtd->buf_dma = pci_map_single (
-					ehci->hcd.pdev,
-					urb->setup_packet,
-					sizeof (struct usb_ctrlrequest),
-					PCI_DMA_TODEVICE);
-		if (unlikely (!qtd->buf_dma))
-			goto cleanup;
-
 		/* SETUP pid */
-		qtd_fill (qtd, qtd->buf_dma, sizeof (struct usb_ctrlrequest),
+		qtd_fill (qtd, urb->setup_dma, sizeof (struct usb_ctrlrequest),
 			token | (2 /* "setup" */ << 8));
 
 		/* ... and always at least one more pid */
@@ -488,29 +435,26 @@
 		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;
 	} 
 
 	/*
 	 * data transfer stage:  buffer setup
 	 */
 	len = urb->transfer_buffer_length;
-	if (likely (len > 0)) {
-		buf = map_buf = pci_map_single (ehci->hcd.pdev,
-			urb->transfer_buffer, len,
-			usb_pipein (urb->pipe)
-			    ? PCI_DMA_FROMDEVICE
-			    : PCI_DMA_TODEVICE);
-		if (unlikely (!buf))
-			goto cleanup;
-	} else
-		buf = map_buf = 0;
+	is_input = usb_pipein (urb->pipe);
+	if (likely (len > 0))
+		buf = urb->transfer_dma;
+	else
+		buf = 0;
 
-	if (!buf || usb_pipein (urb->pipe))
+	if (!buf || is_input)
 		token |= (1 /* "in" */ << 8);
 	/* else it's already initted to "out" pid (0 << 8) */
 
-	maxpacket = usb_maxpacket (urb->dev, urb->pipe,
-			usb_pipeout (urb->pipe));
+	maxpacket = usb_maxpacket (urb->dev, urb->pipe, !is_input) & 0x03ff;
 
 	/*
 	 * buffer gets wrapped in one or more qtds;
@@ -521,7 +465,6 @@
 		int this_qtd_len;
 
 		qtd->urb = urb;
-		qtd->buf_dma = map_buf;
 		this_qtd_len = qtd_fill (qtd, buf, len, token);
 		len -= this_qtd_len;
 		buf += this_qtd_len;
@@ -572,6 +515,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);
@@ -606,6 +562,11 @@
 // That'd mean updating how usbcore talks to HCDs. (2.5?)
 
 
+// high bandwidth multiplier, as encoded in highspeed endpoint descriptors
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+// ... and packet size, for any kind of endpoint descriptor
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x03ff)
+
 /*
  * Each QH holds a qtd list; a QH is used for everything except iso.
  *
@@ -623,6 +584,8 @@
 ) {
 	struct ehci_qh		*qh = ehci_qh_alloc (ehci, flags);
 	u32			info1 = 0, info2 = 0;
+	int			is_input, type;
+	int			maxp = 0;
 
 	if (!qh)
 		return qh;
@@ -633,6 +596,53 @@
 	info1 |= usb_pipeendpoint (urb->pipe) << 8;
 	info1 |= usb_pipedevice (urb->pipe) << 0;
 
+	is_input = usb_pipein (urb->pipe);
+	type = usb_pipetype (urb->pipe);
+	maxp = usb_maxpacket (urb->dev, urb->pipe, !is_input);
+
+	/* Compute interrupt scheduling parameters just once, and save.
+	 * - allowing for high bandwidth, how many nsec/uframe are used?
+	 * - split transactions need a second CSPLIT uframe; same question
+	 * - splits also need a schedule gap (for full/low speed I/O)
+	 * - qh has a polling interval
+	 *
+	 * For control/bulk requests, the HC or TT handles these.
+	 */
+	if (type == PIPE_INTERRUPT) {
+		qh->usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,
+				hb_mult (maxp) * max_packet (maxp));
+		qh->start = NO_FRAME;
+
+		if (urb->dev->speed == USB_SPEED_HIGH) {
+			qh->c_usecs = 0;
+			qh->gap_uf = 0;
+
+			/* FIXME handle HS periods of less than 1 frame. */
+			qh->period = urb->interval >> 3;
+			if (qh->period < 1) {
+				dbg ("intr period %d uframes, NYET!",
+						urb->interval);
+				qh = 0;
+				goto done;
+			}
+		} else {
+			/* gap is f(FS/LS transfer times) */
+			qh->gap_uf = 1 + usb_calc_bus_time (urb->dev->speed,
+					is_input, 0, maxp) / (125 * 1000);
+
+			/* FIXME this just approximates SPLIT/CSPLIT times */
+			if (is_input) {		// SPLIT, gap, CSPLIT+DATA
+				qh->c_usecs = qh->usecs + HS_USECS (0);
+				qh->usecs = HS_USECS (1);
+			} else {		// SPLIT+DATA, gap, CSPLIT
+				qh->usecs += HS_USECS (1);
+				qh->c_usecs = HS_USECS (0);
+			}
+
+			qh->period = urb->interval;
+		}
+	}
+
 	/* using TT? */
 	switch (urb->dev->speed) {
 	case USB_SPEED_LOW:
@@ -642,69 +652,62 @@
 	case USB_SPEED_FULL:
 		/* EPS 0 means "full" */
 		info1 |= (EHCI_TUNE_RL_TT << 28);
-		if (usb_pipecontrol (urb->pipe)) {
+		if (type == PIPE_CONTROL) {
 			info1 |= (1 << 27);	/* for TT */
 			info1 |= 1 << 14;	/* toggle from qtd */
 		}
-		info1 |= usb_maxpacket (urb->dev, urb->pipe,
-					usb_pipeout (urb->pipe)) << 16;
+		info1 |= maxp << 16;
 
 		info2 |= (EHCI_TUNE_MULT_TT << 30);
 		info2 |= urb->dev->ttport << 23;
 		info2 |= urb->dev->tt->hub->devnum << 16;
 
-		/* NOTE:  if (usb_pipeint (urb->pipe)) { scheduler sets c-mask }
-		 * ... and a 0.96 scheduler might use FSTN nodes too
-		 */
+		/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets c-mask } */
+
 		break;
 
 	case USB_SPEED_HIGH:		/* no TT involved */
 		info1 |= (2 << 12);	/* EPS "high" */
 		info1 |= (EHCI_TUNE_RL_HS << 28);
-		if (usb_pipecontrol (urb->pipe)) {
+		if (type == PIPE_CONTROL) {
 			info1 |= 64 << 16;	/* usb2 fixed maxpacket */
 			info1 |= 1 << 14;	/* toggle from qtd */
 			info2 |= (EHCI_TUNE_MULT_HS << 30);
-		} else if (usb_pipebulk (urb->pipe)) {
+		} else if (type == PIPE_BULK) {
 			info1 |= 512 << 16;	/* usb2 fixed maxpacket */
 			info2 |= (EHCI_TUNE_MULT_HS << 30);
-		} else {
-			u32	temp;
-			temp = usb_maxpacket (urb->dev, urb->pipe,
-						usb_pipeout (urb->pipe));
-			info1 |= (temp & 0x3ff) << 16;	/* maxpacket */
-			/* HS intr can be "high bandwidth" */
-			temp = 1 + ((temp >> 11) & 0x03);
-			info2 |= temp << 30;		/* mult */
+		} else {		/* PIPE_INTERRUPT */
+			info1 |= max_packet (maxp) << 16;
+			info2 |= hb_mult (maxp) << 30;
 		}
 		break;
 	default:
-#ifdef DEBUG
-		BUG ();
-#else
-		;
-#endif
+ 		dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
+ 		return 0;
 	}
 
-	/* NOTE:  if (usb_pipeint (urb->pipe)) { scheduler sets s-mask } */
+	/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets s-mask } */
 
 	qh->qh_state = QH_STATE_IDLE;
 	qh->hw_info1 = cpu_to_le32 (info1);
 	qh->hw_info2 = cpu_to_le32 (info2);
 
 	/* initialize sw and hw queues with these qtds */
-	list_splice (qtd_list, &qh->qtd_list);
-	qh_update (qh, list_entry (qtd_list->next, struct ehci_qtd, qtd_list));
+	if (!list_empty (qtd_list)) {
+		list_splice (qtd_list, &qh->qtd_list);
+		qh_update (qh, list_entry (qtd_list->next, struct ehci_qtd, qtd_list));
+	} else {
+		qh->hw_qtd_next = qh->hw_alt_next = EHCI_LIST_END;
+	}
 
 	/* initialize data toggle state */
-	if (!usb_pipecontrol (urb->pipe))
-		clear_toggle (urb->dev,
-			usb_pipeendpoint (urb->pipe),
-			usb_pipeout (urb->pipe),
-			qh);
+	clear_toggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, qh);
 
+done:
 	return qh;
 }
+#undef hb_mult
+#undef hb_packet
 
 /*-------------------------------------------------------------------------*/
 
@@ -719,8 +722,7 @@
 		u32	cmd = readl (&ehci->regs->command);
 
 		/* in case a clear of CMD_ASE didn't take yet */
-		while (readl (&ehci->regs->status) & STS_ASS)
-			udelay (100);
+		(void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
 
 		qh->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD); /* [4.8] */
 		qh->qh_next.qh = qh;
@@ -743,58 +745,58 @@
 	}
 	qh->qh_state = QH_STATE_LINKED;
 	/* qtd completions reported later by interrupt */
+
+	ehci->async_idle = 0;
 }
 
 /*-------------------------------------------------------------------------*/
 
-static int
-submit_async (
+/*
+ * For control/bulk/interrupt, return QH with these TDs appended.
+ * Allocates and initializes the QH if necessary.
+ * Returns null if it can't allocate a QH it needs to.
+ * If the QH has TDs (urbs) already, that's great.
+ */
+static struct ehci_qh *qh_append_tds (
 	struct ehci_hcd		*ehci,
 	struct urb		*urb,
 	struct list_head	*qtd_list,
-	int			mem_flags
-) {
-	struct ehci_qtd		*qtd;
-	struct hcd_dev		*dev;
-	int			epnum;
-	unsigned long		flags;
+	int			epnum,
+	void			**ptr
+)
+{
 	struct ehci_qh		*qh = 0;
 
-	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))
-		epnum |= 0x10;
-
-	vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]",
-		ehci->hcd.bus_name, urb, urb->transfer_buffer_length,
-		epnum & 0x0f, (epnum & 0x10) ? "in" : "out",
-		qtd, dev ? dev->ep [epnum] : (void *)~0);
-
-	spin_lock_irqsave (&ehci->lock, flags);
-
-	qh = (struct ehci_qh *) dev->ep [epnum];
+	qh = (struct ehci_qh *) *ptr;
 	if (likely (qh != 0)) {
-		u32	hw_next = QTD_NEXT (qtd->qtd_dma);
+		struct ehci_qtd	*qtd;
+
+		if (unlikely (list_empty (qtd_list)))
+			qtd = 0;
+		else
+			qtd = list_entry (qtd_list->next, struct ehci_qtd,
+					qtd_list);
 
 		/* maybe patch the qh used for set_address */
 		if (unlikely (epnum == 0
 				&& le32_to_cpu (qh->hw_info1 & 0x7f) == 0))
 			qh->hw_info1 |= cpu_to_le32 (usb_pipedevice(urb->pipe));
 
-		/* is an URB is queued to this qh already? */
-		if (unlikely (!list_empty (&qh->qtd_list))) {
+		/* append to tds already queued to this qh? */
+		if (unlikely (!list_empty (&qh->qtd_list) && qtd)) {
 			struct ehci_qtd		*last_qtd;
 			int			short_rx = 0;
+			u32			hw_next;
 
 			/* update the last qtd's "next" pointer */
 			// dbg_qh ("non-empty qh", ehci, qh);
 			last_qtd = list_entry (qh->qtd_list.prev,
 					struct ehci_qtd, qtd_list);
+			hw_next = QTD_NEXT (qtd->qtd_dma);
 			last_qtd->hw_next = hw_next;
 
 			/* previous urb allows short rx? maybe optimize. */
-			if (!(last_qtd->urb->transfer_flags & USB_DISABLE_SPD)
+			if (!(last_qtd->urb->transfer_flags & URB_SHORT_NOT_OK)
 					&& (epnum & 0x10)) {
 				// only the last QTD for now
 				last_qtd->hw_alt_next = hw_next;
@@ -805,6 +807,7 @@
 			 * Interrupt code must cope with case of HC having it
 			 * cached, and clobbering these updates.
 			 * ... complicates getting rid of extra interrupts!
+			 * (Or:  use dummy td, so cache always stays valid.)
 			 */
 			if (qh->hw_current == cpu_to_le32 (last_qtd->qtd_dma)) {
 				wmb ();
@@ -824,31 +827,62 @@
 			 */
 
 			/* usb_clear_halt() means qh data toggle gets reset */
-			if (usb_pipebulk (urb->pipe)
-					&& unlikely (!usb_gettoggle (urb->dev,
+			if (unlikely (!usb_gettoggle (urb->dev,
 						(epnum & 0x0f),
 						!(epnum & 0x10)))) {
 				clear_toggle (urb->dev,
 					epnum & 0x0f, !(epnum & 0x10), qh);
 			}
-			qh_update (qh, qtd);
+			if (qtd)
+				qh_update (qh, qtd);
 		}
 		list_splice (qtd_list, qh->qtd_list.prev);
 
 	} else {
 		/* can't sleep here, we have ehci->lock... */
 		qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC);
-		if (likely (qh != 0)) {
-			// dbg_qh ("new qh", ehci, qh);
-			dev->ep [epnum] = qh;
-		}
+		// if (qh) dbg_qh ("new qh", ehci, qh);
+		*ptr = qh;
 	}
+	if (qh)
+		urb->hcpriv = qh_get (qh);
+	return qh;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+submit_async (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	int			mem_flags
+) {
+	struct ehci_qtd		*qtd;
+	struct hcd_dev		*dev;
+	int			epnum;
+	unsigned long		flags;
+	struct ehci_qh		*qh = 0;
+
+	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) && !usb_pipecontrol (urb->pipe))
+		epnum |= 0x10;
+
+	vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]",
+		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);
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	qh = qh_append_tds (ehci, urb, qtd_list, epnum, &dev->ep [epnum]);
 
 	/* Control/bulk operations through TTs don't need scheduling,
 	 * the HC and TT handle it when the TT has a buffer ready.
 	 */
 	if (likely (qh != 0)) {
-		urb->hcpriv = qh_get (qh);
 		if (likely (qh->qh_state == QH_STATE_IDLE))
 			qh_link_async (ehci, qh_get (qh));
 	}
@@ -869,16 +903,16 @@
 {
 	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, 1);
+	qh_completions (ehci, qh);
 
-	// 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);
@@ -886,7 +920,6 @@
 		qh_put (ehci, qh);		// refcount from async list
 }
 
-
 /* makes sure the async qh will become idle */
 /* caller must own ehci->lock */
 
@@ -916,13 +949,14 @@
 	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)
-				writel (cmd & ~CMD_ASE, &ehci->regs->command);
-			else {
-				ehci_ready (ehci);
-				while (readl (&ehci->regs->status) & STS_ASS)
-					udelay (100);
-			}
+			writel (cmd & ~CMD_ASE, &ehci->regs->command);
+			(void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
+#if 0
+			// one VT8235 system wants to die with STS_FATAL
+			// unless this qh is leaked here. others seem ok...
+			qh = qh_get (qh);
+			dbg_qh ("async/off", ehci, qh);
+#endif
 		}
 		qh->qh_next.qh = ehci->async = 0;
 
@@ -940,10 +974,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;
@@ -957,48 +987,63 @@
 	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 void
+scan_async (struct ehci_hcd *ehci)
 {
 	struct ehci_qh		*qh;
-	unsigned long		flags;
+	unsigned		count;
 
-	spin_lock_irqsave (&ehci->lock, flags);
 rescan:
 	qh = ehci->async;
+	count = 0;
 	if (likely (qh != 0)) {
 		do {
 			/* clean any finished work for this qh */
 			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, 1);
-
-				spin_lock_irqsave (&ehci->lock, flags);
+				count += qh_completions (ehci, qh);
 				qh_put (ehci, qh);
 			}
 
-			/* unlink idle entries (reduces PCI usage) */
+			/* unlink idle entries, reducing HC PCI usage as
+			 * well as HCD schedule-scanning costs.  removing
+			 * the last qh is deferred, since it's costly.
+			 *
+			 * FIXME don't unlink idle entries so quickly; it
+			 * can penalize (common) half duplex protocols.
+			 */
 			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.
+				} 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);
 				}
 			}
+
+			/* keep latencies down: let any irqs in */
+			if (count > max_completions) {
+				spin_unlock_irq (&ehci->lock);
+				cpu_relax ();
+				spin_lock_irq (&ehci->lock);
+				goto rescan;
+			}
+
 			qh = qh->qh_next.qh;
 			if (!qh)		/* unlinked? */
 				goto rescan;
 		} while (qh != ehci->async);
 	}
-
-	spin_unlock_irqrestore (&ehci->lock, flags);
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/usb/hcd/ehci-sched.c linux.20pre10-ac2/drivers/usb/hcd/ehci-sched.c
--- linux.20pre10/drivers/usb/hcd/ehci-sched.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/usb/hcd/ehci-sched.c	2002-09-29 21:02:14.000000000 +0100
@@ -33,19 +33,6 @@
  * or with "USB On The Go" additions to USB 2.0 ...)
  */
 
-/*
- * Ceiling microseconds (typical) for that many bytes at high speed
- * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
- * to preallocate bandwidth)
- */
-#define EHCI_HOST_DELAY	5	/* nsec, guess */
-#define HS_USECS(bytes) NS_TO_US ( ((55 * 8 * 2083)/1000) \
-	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
-	+ EHCI_HOST_DELAY)
-#define HS_USECS_ISO(bytes) NS_TO_US ( ((long)(38 * 8 * 2.083)) \
-	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
-	+ EHCI_HOST_DELAY)
-	
 static int ehci_get_frame (struct usb_hcd *hcd);
 
 /*-------------------------------------------------------------------------*/
@@ -124,6 +111,9 @@
 			/* is it in the S-mask? */
 			if (q->qh->hw_info2 & cpu_to_le32 (1 << uframe))
 				usecs += q->qh->usecs;
+			/* ... or C-mask? */
+			if (q->qh->hw_info2 & cpu_to_le32 (1 << (8 + uframe)))
+				usecs += q->qh->c_usecs;
 			q = &q->qh->qh_next;
 			break;
 		case Q_TYPE_FSTN:
@@ -181,15 +171,19 @@
 
 /*-------------------------------------------------------------------------*/
 
-static void enable_periodic (struct ehci_hcd *ehci)
+static int enable_periodic (struct ehci_hcd *ehci)
 {
 	u32	cmd;
+	int	status;
 
 	/* did clearing PSE did take effect yet?
 	 * takes effect only at frame boundaries...
 	 */
-	while (readl (&ehci->regs->status) & STS_PSS)
-		udelay (20);
+	status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125);
+	if (status != 0) {
+		ehci->hcd.state = USB_STATE_HALT;
+		return status;
+	}
 
 	cmd = readl (&ehci->regs->command) | CMD_PSE;
 	writel (cmd, &ehci->regs->command);
@@ -199,80 +193,104 @@
 	/* make sure tasklet scans these */
 	ehci->next_uframe = readl (&ehci->regs->frame_index)
 				% (ehci->periodic_size << 3);
+	return 0;
 }
 
-static void disable_periodic (struct ehci_hcd *ehci)
+static int disable_periodic (struct ehci_hcd *ehci)
 {
 	u32	cmd;
+	int	status;
 
 	/* did setting PSE not take effect yet?
 	 * takes effect only at frame boundaries...
 	 */
-	while (!(readl (&ehci->regs->status) & STS_PSS))
-		udelay (20);
+	status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
+	if (status != 0) {
+		ehci->hcd.state = USB_STATE_HALT;
+		return status;
+	}
 
 	cmd = readl (&ehci->regs->command) & ~CMD_PSE;
 	writel (cmd, &ehci->regs->command);
 	/* posted write ... */
 
 	ehci->next_uframe = -1;
+	return 0;
 }
 
 /*-------------------------------------------------------------------------*/
 
+// FIXME microframe periods not yet handled
+
 static void intr_deschedule (
 	struct ehci_hcd	*ehci,
-	unsigned	frame,
 	struct ehci_qh	*qh,
-	unsigned	period
+	int		wait
 ) {
-	unsigned long	flags;
-
-	period >>= 3;		// FIXME microframe periods not handled yet
-
-	spin_lock_irqsave (&ehci->lock, flags);
+	int		status;
+	unsigned	frame = qh->start;
 
 	do {
 		periodic_unlink (ehci, frame, qh);
 		qh_put (ehci, qh);
-		frame += period;
+		frame += qh->period;
 	} while (frame < ehci->periodic_size);
 
 	qh->qh_state = QH_STATE_UNLINK;
 	qh->qh_next.ptr = 0;
-	ehci->periodic_urbs--;
+	ehci->periodic_sched--;
 
 	/* maybe turn off periodic schedule */
-	if (!ehci->periodic_urbs)
-		disable_periodic (ehci);
-	else
+	if (!ehci->periodic_sched)
+		status = disable_periodic (ehci);
+	else {
+		status = 0;
 		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.
 	 * No other threads may be mucking with this qh.
 	 */
-	if (((ehci_get_frame (&ehci->hcd) - frame) % period) == 0)
-		udelay (125);
+	if (((ehci_get_frame (&ehci->hcd) - frame) % qh->period) == 0) {
+		if (wait) {
+			udelay (125);
+			qh->hw_next = EHCI_LIST_END;
+		} else {
+			/* we may not be IDLE yet, but if the qh is empty
+			 * the race is very short.  then if qh also isn't
+			 * rescheduled soon, it won't matter.  otherwise...
+			 */
+			vdbg ("intr_deschedule...");
+		}
+	} else
+		qh->hw_next = EHCI_LIST_END;
 
 	qh->qh_state = QH_STATE_IDLE;
-	qh->hw_next = EHCI_LIST_END;
 
-	vdbg ("descheduled qh %p, per = %d frame = %d count = %d, urbs = %d",
-		qh, period, frame,
-		atomic_read (&qh->refcount), ehci->periodic_urbs);
+	/* update per-qh bandwidth utilization (for usbfs) */
+	hcd_to_bus (&ehci->hcd)->bandwidth_allocated -= 
+		(qh->usecs + qh->c_usecs) / qh->period;
+
+	dbg ("descheduled qh %p, period = %d frame = %d count = %d, urbs = %d",
+		qh, qh->period, frame,
+		atomic_read (&qh->refcount), ehci->periodic_sched);
 }
 
 static int check_period (
 	struct ehci_hcd *ehci, 
 	unsigned	frame,
-	int		uframe,
+	unsigned	uframe,
 	unsigned	period,
 	unsigned	usecs
 ) {
+	/* complete split running into next frame?
+	 * given FSTN support, we could sometimes check...
+	 */
+	if (uframe >= 8)
+		return 0;
+
 	/*
 	 * 80% periodic == 100 usec/uframe available
 	 * convert "usecs we need" to "max already claimed" 
@@ -284,6 +302,8 @@
 
 // FIXME delete when intr_submit handles non-empty queues
 // this gives us a one intr/frame limit (vs N/uframe)
+// ... and also lets us avoid tracking split transactions
+// that might collide at a given TT/hub.
 		if (ehci->pshadow [frame].ptr)
 			return 0;
 
@@ -298,226 +318,203 @@
 	return 1;
 }
 
-static int intr_submit (
-	struct ehci_hcd		*ehci,
-	struct urb		*urb,
-	struct list_head	*qtd_list,
-	int			mem_flags
-) {
-	unsigned		epnum, period;
-	unsigned short		usecs;
-	unsigned long		flags;
-	struct ehci_qh		*qh;
-	struct hcd_dev		*dev;
-	int			status = 0;
+static int check_intr_schedule (
+	struct ehci_hcd		*ehci, 
+	unsigned		frame,
+	unsigned		uframe,
+	const struct ehci_qh	*qh,
+	u32			*c_maskp
+)
+{
+    	int		retval = -ENOSPC;
 
-	/* get endpoint and transfer data */
-	epnum = usb_pipeendpoint (urb->pipe);
-	if (usb_pipein (urb->pipe))
-		epnum |= 0x10;
-	if (urb->dev->speed != USB_SPEED_HIGH) {
-		dbg ("no intr/tt scheduling yet"); 
-		status = -ENOSYS;
+	if (!check_period (ehci, frame, uframe, qh->period, qh->usecs))
+		goto done;
+	if (!qh->c_usecs) {
+		retval = 0;
+		*c_maskp = cpu_to_le32 (0);
 		goto done;
 	}
 
-	/*
-	 * NOTE: current completion/restart logic doesn't handle more than
-	 * one qtd in a periodic qh ... 16-20 KB/urb is pretty big for this.
-	 * such big requests need many periods to transfer.
+	/* This is a split transaction; check the bandwidth available for
+	 * the completion too.  Check both worst and best case gaps: worst
+	 * case is SPLIT near uframe end, and CSPLIT near start ... best is
+	 * vice versa.  Difference can be almost two uframe times, but we
+	 * reserve unnecessary bandwidth (waste it) this way.  (Actually
+	 * even better cases exist, like immediate device NAK.)
 	 *
-	 * FIXME want to change hcd core submit model to expect queuing
-	 * for all transfer types ... not just ISO and (with flag) BULK.
-	 * that means: getting rid of this check; handling the "interrupt
-	 * urb already queued" case below like bulk queuing is handled (no
-	 * errors possible!); and completly getting rid of that annoying
-	 * qh restart logic.  simpler/smaller overall, and more flexible.
+	 * FIXME don't even bother unless we know this TT is idle in that
+	 * range of uframes ... for now, check_period() allows only one
+	 * interrupt transfer per frame, so needn't check "TT busy" status
+	 * when scheduling a split (QH, SITD, or FSTN).
+	 *
+	 * FIXME ehci 0.96 and above can use FSTNs
 	 */
-	if (unlikely (qtd_list->next != qtd_list->prev)) {
-		dbg ("only one intr qtd per urb allowed"); 
-		status = -EINVAL;
+	if (!check_period (ehci, frame, uframe + qh->gap_uf + 1,
+				qh->period, qh->c_usecs))
 		goto done;
-	}
-
-	usecs = HS_USECS (urb->transfer_buffer_length);
-
-	/* FIXME handle HS periods of less than 1 frame. */
-	period = urb->interval >> 3;
-	if (period < 1) {
-		dbg ("intr period %d uframes, NYET!", urb->interval);
-		status = -EINVAL;
+	if (!check_period (ehci, frame, uframe + qh->gap_uf,
+				qh->period, qh->c_usecs))
 		goto done;
-	}
 
-	spin_lock_irqsave (&ehci->lock, flags);
-
-	/* get the qh (must be empty and idle) */
-	dev = (struct hcd_dev *)urb->dev->hcpriv;
-	qh = (struct ehci_qh *) dev->ep [epnum];
-	if (qh) {
-		/* only allow one queued interrupt urb per EP */
-		if (unlikely (qh->qh_state != QH_STATE_IDLE
-				|| !list_empty (&qh->qtd_list))) {
-			dbg ("interrupt urb already queued");
-			status = -EBUSY;
-		} else {
-			/* maybe reset hardware's data toggle in the qh */
-			if (unlikely (!usb_gettoggle (urb->dev, epnum & 0x0f,
-					!(epnum & 0x10)))) {
-				qh->hw_token |=
-					__constant_cpu_to_le32 (QTD_TOGGLE);
-				usb_settoggle (urb->dev, epnum & 0x0f,
-					!(epnum & 0x10), 1);
-			}
-			/* trust the QH was set up as interrupt ... */
-			list_splice (qtd_list, &qh->qtd_list);
-			qh_update (qh, list_entry (qtd_list->next,
-						struct ehci_qtd, qtd_list));
-			qtd_list = &qh->qtd_list;
-		}
-	} else {
-		/* can't sleep here, we have ehci->lock... */
-		qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC);
-		if (likely (qh != 0)) {
-			// dbg ("new INTR qh %p", qh);
-			dev->ep [epnum] = qh;
-			qtd_list = &qh->qtd_list;
-		} else
-			status = -ENOMEM;
-	}
+	*c_maskp = cpu_to_le32 (0x03 << (8 + uframe + qh->gap_uf));
+	retval = 0;
+done:
+	return retval;
+}
 
-	/* Schedule this periodic QH. */
-	if (likely (status == 0)) {
-		unsigned	frame = period;
+static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	int 		status;
+	unsigned	uframe;
+	u32		c_mask;
+	unsigned	frame;		/* 0..(qh->period - 1), or NO_FRAME */
 
-		qh->hw_next = EHCI_LIST_END;
-		qh->usecs = usecs;
+	qh->hw_next = EHCI_LIST_END;
+	frame = qh->start;
 
-		urb->hcpriv = qh_get (qh);
+	/* reuse the previous schedule slots, if we can */
+	if (frame < qh->period) {
+		uframe = ffs (le32_to_cpup (&qh->hw_info2) & 0x00ff);
+		status = check_intr_schedule (ehci, frame, --uframe,
+				qh, &c_mask);
+	} else {
+		uframe = 0;
+		c_mask = 0;
 		status = -ENOSPC;
+	}
 
-		/* pick a set of schedule slots, link the QH into them */
+	/* else scan the schedule to find a group of slots such that all
+	 * uframes have enough periodic bandwidth available.
+	 */
+	if (status) {
+		frame = qh->period - 1;
 		do {
-			int	uframe;
-
-			/* pick a set of slots such that all uframes have
-			 * enough periodic bandwidth available.
-			 *
-			 * FIXME for TT splits, need uframes for start and end.
-			 * FSTNs can put end into next frame (uframes 0 or 1).
-			 */
-			frame--;
 			for (uframe = 0; uframe < 8; uframe++) {
-				if (check_period (ehci, frame, uframe,
-						period, usecs) != 0)
+				status = check_intr_schedule (ehci,
+						frame, uframe, qh,
+						&c_mask);
+				if (status == 0)
 					break;
 			}
-			if (uframe == 8)
-				continue;
+		} while (status && --frame);
+		if (status)
+			goto done;
+		qh->start = frame;
+
+		/* reset S-frame and (maybe) C-frame masks */
+		qh->hw_info2 &= ~0xffff;
+		qh->hw_info2 |= cpu_to_le32 (1 << uframe) | c_mask;
+	} else
+		dbg ("reused previous qh %p schedule", qh);
+
+	/* stuff into the periodic schedule */
+	qh->qh_state = QH_STATE_LINKED;
+	dbg ("scheduled qh %p usecs %d/%d period %d.0 starting %d.%d (gap %d)",
+		qh, qh->usecs, qh->c_usecs,
+		qh->period, frame, uframe, qh->gap_uf);
+	do {
+		if (unlikely (ehci->pshadow [frame].ptr != 0)) {
 
-			/* QH will run once each period, starting there  */
-			urb->start_frame = frame;
-			status = 0;
-
-			/* set S-frame mask */
-			qh->hw_info2 |= cpu_to_le32 (1 << uframe);
-			// dbg_qh ("Schedule INTR qh", ehci, qh);
-
-			/* stuff into the periodic schedule */
-			qh->qh_state = QH_STATE_LINKED;
-			vdbg ("qh %p usecs %d period %d starting %d.%d",
-				qh, qh->usecs, period, frame, uframe);
-			do {
-				if (unlikely (ehci->pshadow [frame].ptr != 0)) {
 // FIXME -- just link toward the end, before any qh with a shorter period,
-// AND handle it already being (implicitly) linked into this frame
-// AS WELL AS updating the check_period() logic
-					BUG ();
-				} else {
-					ehci->pshadow [frame].qh = qh_get (qh);
-					ehci->periodic [frame] =
-						QH_NEXT (qh->qh_dma);
-				}
-				wmb ();
-				frame += period;
-			} while (frame < ehci->periodic_size);
-
-			/* update bandwidth utilization records (for usbfs) */
-			usb_claim_bandwidth (urb->dev, urb, usecs/period, 0);
-
-			/* maybe enable periodic schedule processing */
-			if (!ehci->periodic_urbs++)
-				enable_periodic (ehci);
-			break;
+// AND accomodate it already having been linked here (after some other qh)
+// AS WELL AS updating the schedule checking logic
+
+			BUG ();
+		} else {
+			ehci->pshadow [frame].qh = qh_get (qh);
+			ehci->periodic [frame] =
+				QH_NEXT (qh->qh_dma);
+		}
+		wmb ();
+		frame += qh->period;
+	} while (frame < ehci->periodic_size);
+
+	/* update per-qh bandwidth for usbfs */
+	hcd_to_bus (&ehci->hcd)->bandwidth_allocated += 
+		(qh->usecs + qh->c_usecs) / qh->period;
+
+	/* maybe enable periodic schedule processing */
+	if (!ehci->periodic_sched++)
+		status = enable_periodic (ehci);
+done:
+	return status;
+}
 
-		} while (frame);
+static int intr_submit (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	int			mem_flags
+) {
+	unsigned		epnum;
+	unsigned long		flags;
+	struct ehci_qh		*qh;
+	struct hcd_dev		*dev;
+	int			is_input;
+	int			status = 0;
+	struct list_head	empty;
+
+	/* get endpoint and transfer/schedule data */
+	epnum = usb_pipeendpoint (urb->pipe);
+	is_input = usb_pipein (urb->pipe);
+	if (is_input)
+		epnum |= 0x10;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	dev = (struct hcd_dev *)urb->dev->hcpriv;
+
+	/* get qh and force any scheduling errors */
+	INIT_LIST_HEAD (&empty);
+	qh = qh_append_tds (ehci, urb, &empty, epnum, &dev->ep [epnum]);
+	if (qh == 0) {
+		status = -ENOMEM;
+		goto done;
 	}
-	spin_unlock_irqrestore (&ehci->lock, flags);
+	if (qh->qh_state == QH_STATE_IDLE) {
+		if ((status = qh_schedule (ehci, qh)) != 0)
+			goto done;
+	}
+
+	/* then queue the urb's tds to the qh */
+	qh = qh_append_tds (ehci, urb, qtd_list, epnum, &dev->ep [epnum]);
+	BUG_ON (qh == 0);
+
+	/* ... update usbfs periodic stats */
+	hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs++;
+
 done:
+	spin_unlock_irqrestore (&ehci->lock, flags);
 	if (status)
 		qtd_list_free (ehci, urb, qtd_list);
 
 	return status;
 }
 
-static unsigned long
+static unsigned
 intr_complete (
 	struct ehci_hcd	*ehci,
 	unsigned	frame,
-	struct ehci_qh	*qh,
-	unsigned long	flags		/* caller owns ehci->lock ... */
+	struct ehci_qh	*qh
 ) {
-	struct ehci_qtd	*qtd;
-	struct urb	*urb;
-	int		unlinking;
+	unsigned	count;
 
 	/* nothing to report? */
 	if (likely ((qh->hw_token & __constant_cpu_to_le32 (QTD_STS_ACTIVE))
 			!= 0))
-		return flags;
+		return 0;
 	if (unlikely (list_empty (&qh->qtd_list))) {
 		dbg ("intr qh %p no TDs?", qh);
-		return flags;
+		return 0;
 	}
 	
-	qtd = list_entry (qh->qtd_list.next, struct ehci_qtd, qtd_list);
-	urb = qtd->urb;
-	unlinking = (urb->status == -ENOENT) || (urb->status == -ECONNRESET);
-
-	/* call any completions, after patching for reactivation */
-	spin_unlock_irqrestore (&ehci->lock, flags);
-	/* NOTE:  currently restricted to one qtd per qh! */
-	if (qh_completions (ehci, qh, 0) == 0)
-		urb = 0;
-	spin_lock_irqsave (&ehci->lock, flags);
+	/* handle any completions */
+	count = qh_completions (ehci, qh);
 
-	/* never reactivate requests that were unlinked ... */
-	if (likely (urb != 0)) {
-		if (unlinking
-				|| urb->status == -ECONNRESET
-				|| urb->status == -ENOENT
-				// || (urb->dev == null)
-				|| ehci->hcd.state == USB_STATE_HALT)
-			urb = 0;
-		// FIXME look at all those unlink cases ... we always
-		// need exactly one completion that reports unlink.
-		// the one above might not have been it!
-	}
-
-	/* normally reactivate */
-	if (likely (urb != 0)) {
-		if (usb_pipeout (urb->pipe))
-			pci_dma_sync_single (ehci->hcd.pdev,
-				qtd->buf_dma,
-				urb->transfer_buffer_length,
-				PCI_DMA_TODEVICE);
-		urb->status = -EINPROGRESS;
-		urb->actual_length = 0;
+	if (unlikely (list_empty (&qh->qtd_list)))
+		intr_deschedule (ehci, qh, 0);
 
-		/* patch qh and restart */
-		qh_update (qh, qtd);
-	}
-	return flags;
+	return count;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -527,11 +524,6 @@
 {
 	struct ehci_itd *first_itd = urb->hcpriv;
 
-	pci_unmap_single (ehci->hcd.pdev,
-		first_itd->buf_dma, urb->transfer_buffer_length,
-		usb_pipein (urb->pipe)
-		    ? PCI_DMA_FROMDEVICE
-		    : PCI_DMA_TODEVICE);
 	while (!list_empty (&first_itd->itd_list)) {
 		struct ehci_itd	*itd;
 
@@ -557,6 +549,7 @@
 	u32		buf1;
 	unsigned	i, epnum, maxp, multi;
 	unsigned	length;
+	int		is_input;
 
 	itd->hw_next = EHCI_LIST_END;
 	itd->urb = urb;
@@ -578,7 +571,8 @@
 	 * as encoded in the ep descriptor's maxpacket field
 	 */
 	epnum = usb_pipeendpoint (urb->pipe);
-	if (usb_pipein (urb->pipe)) {
+	is_input = usb_pipein (urb->pipe);
+	if (is_input) {
 		maxp = urb->dev->epmaxpacketin [epnum];
 		buf1 = (1 << 11);
 	} else {
@@ -598,7 +592,7 @@
 			urb->iso_frame_desc [index].length);
 		return -ENOSPC;
 	}
-	itd->usecs = HS_USECS_ISO (length);
+	itd->usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 1, length);
 
 	/* "plus" info in low order bits of buffer pointers */
 	itd->hw_bufp [0] |= cpu_to_le32 ((epnum << 8) | urb->dev->devnum);
@@ -625,16 +619,7 @@
 	int			frame_index;
 	struct ehci_itd		*first_itd, *itd;
 	int			status;
-	dma_addr_t		buf_dma, itd_dma;
-
-	/* set up one dma mapping for this urb */
-	buf_dma = pci_map_single (ehci->hcd.pdev,
-		urb->transfer_buffer, urb->transfer_buffer_length,
-		usb_pipein (urb->pipe)
-		    ? PCI_DMA_FROMDEVICE
-		    : PCI_DMA_TODEVICE);
-	if (buf_dma == 0)
-		return -ENOMEM;
+	dma_addr_t		itd_dma;
 
 	/* allocate/init ITDs */
 	for (frame_index = 0, first_itd = 0;
@@ -648,7 +633,8 @@
 		memset (itd, 0, sizeof *itd);
 		itd->itd_dma = itd_dma;
 
-		status = itd_fill (ehci, itd, urb, frame_index, buf_dma);
+		status = itd_fill (ehci, itd, urb, frame_index,
+				urb->transfer_dma);
 		if (status != 0)
 			goto fail;
 
@@ -737,7 +723,7 @@
 
 	/* calculate the legal range [start,max) */
 	now = readl (&ehci->regs->frame_index) + 1;	/* next uframe */
-	if (!ehci->periodic_urbs)
+	if (!ehci->periodic_sched)
 		now += 8;				/* startup delay */
 	now %= mod;
 	end = now + mod;
@@ -857,8 +843,12 @@
 		usb_claim_bandwidth (urb->dev, urb, usecs, 1);
 
 		/* maybe enable periodic schedule processing */
-		if (!ehci->periodic_urbs++)
-			enable_periodic (ehci);
+		if (!ehci->periodic_sched++) {
+			if ((status =  enable_periodic (ehci)) != 0) {
+				// FIXME deschedule right away
+				err ("itd_schedule, enable = %d", status);
+			}
+		}
 
 		return 0;
 
@@ -873,15 +863,14 @@
 
 #define	ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
 
-static unsigned long
+static unsigned
 itd_complete (
 	struct ehci_hcd	*ehci,
 	struct ehci_itd	*itd,
-	unsigned	uframe,
-	unsigned long	flags
+	unsigned	uframe
 ) {
 	struct urb				*urb = itd->urb;
-	struct iso_packet_descriptor		*desc;
+	struct usb_iso_packet_descriptor	*desc;
 	u32					t;
 
 	/* update status for this uframe's transfers */
@@ -916,7 +905,7 @@
 
 	/* handle completion now? */
 	if ((itd->index + 1) != urb->number_of_packets)
-		return flags;
+		return 0;
 
 	/*
 	 * Always give the urb back to the driver ... expect it to submit
@@ -931,16 +920,17 @@
 	if (urb->status == -EINPROGRESS)
 		urb->status = 0;
 
-	spin_unlock_irqrestore (&ehci->lock, flags);
+	/* complete() can reenter this HCD */
+	spin_unlock (&ehci->lock);
 	usb_hcd_giveback_urb (&ehci->hcd, urb);
-	spin_lock_irqsave (&ehci->lock, flags);
+	spin_lock (&ehci->lock);
 
 	/* defer stopping schedule; completion can submit */
-	ehci->periodic_urbs--;
-	if (!ehci->periodic_urbs)
-		disable_periodic (ehci);
+	ehci->periodic_sched--;
+	if (!ehci->periodic_sched)
+		(void) disable_periodic (ehci);
 
-	return flags;
+	return 1;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -952,10 +942,6 @@
 
 	dbg ("itd_submit urb %p", urb);
 
-	/* NOTE DMA mapping assumes this ... */
-	if (urb->iso_frame_desc [0].offset != 0)
-		return -EINVAL;
-	
 	/* allocate ITDs w/o locking anything */
 	status = itd_urb_transaction (ehci, urb, mem_flags);
 	if (status < 0)
@@ -978,130 +964,21 @@
 /*
  * "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 void
+scan_periodic (struct ehci_hcd *ehci)
 {
 	unsigned	frame, clock, now_uframe, mod;
-	unsigned long	flags;
+	unsigned	count = 0;
 
 	mod = ehci->periodic_size << 3;
-	spin_lock_irqsave (&ehci->lock, flags);
 
 	/*
 	 * When running, scan from last scan point up to "now"
@@ -1122,6 +999,14 @@
 		u32			type, *hw_p;
 		unsigned		uframes;
 
+		/* keep latencies down: let any irqs in */
+		if (count > max_completions) {
+			spin_unlock_irq (&ehci->lock);
+			cpu_relax ();
+			count = 0;
+			spin_lock_irq (&ehci->lock);
+		}
+
 restart:
 		/* scan schedule to _before_ current frame index */
 		if (frame == clock)
@@ -1145,8 +1030,8 @@
 				last = (q.qh->hw_next == EHCI_LIST_END);
 				temp = q.qh->qh_next;
 				type = Q_NEXT_TYPE (q.qh->hw_next);
-				flags = intr_complete (ehci, frame,
-						qh_get (q.qh), flags);
+				count += intr_complete (ehci, frame,
+						qh_get (q.qh));
 				qh_put (ehci, q.qh);
 				q = temp;
 				break;
@@ -1178,8 +1063,8 @@
 						type = Q_NEXT_TYPE (*hw_p);
 
 						/* might free q.itd ... */
-						flags = itd_complete (ehci,
-							temp.itd, uf, flags);
+						count += itd_complete (ehci,
+							temp.itd, uf);
 						break;
 					}
 				}
@@ -1195,7 +1080,7 @@
 #ifdef have_split_iso
 			case Q_TYPE_SITD:
 				last = (q.sitd->hw_next == EHCI_LIST_END);
-				flags = sitd_complete (ehci, q.sitd, flags);
+				sitd_complete (ehci, q.sitd);
 				type = Q_NEXT_TYPE (q.sitd->hw_next);
 
 				// FIXME unlink SITD after split completes
@@ -1241,5 +1126,4 @@
 		} else
 			frame = (frame + 1) % ehci->periodic_size;
 	} 
-	spin_unlock_irqrestore (&ehci->lock, flags);
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/usb/hcd.c linux.20pre10-ac2/drivers/usb/hcd.c
--- linux.20pre10/drivers/usb/hcd.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/usb/hcd.c	2002-09-29 21:01:47.000000000 +0100
@@ -296,7 +296,7 @@
 
 	// serial number
 	} else if (id == 1) {
-		strcpy (buf, hcd->bus_name);
+		strcpy (buf, hcd->bus->bus_name);
 
 	// product description
 	} else if (id == 2) {
@@ -392,7 +392,7 @@
 	case DeviceOutRequest | USB_REQ_SET_ADDRESS:
 		// wValue == urb->dev->devaddr
 		dbg ("%s root hub device address %d",
-			hcd->bus_name, wValue);
+			hcd->bus->bus_name, wValue);
 		break;
 
 	/* INTERFACE REQUESTS (no defined feature/status flags) */
@@ -506,7 +506,7 @@
 					&& rh_status_urb (hcd, urb) != 0) {
 				/* another driver snuck in? */
 				dbg ("%s, can't resubmit roothub status urb?",
-					hcd->bus_name);
+					hcd->bus->bus_name);
 				spin_unlock_irqrestore (&hcd_data_lock, flags);
 				BUG ();
 			}
@@ -687,6 +687,7 @@
 		base);
 
 // FIXME simpler: make "bus" be that data, not pointer to it.
+// (fixed in 2.5)
 	bus = usb_alloc_bus (&hcd_operations);
 	if (bus == NULL) {
 		dbg ("usb_alloc_bus fail");
@@ -695,7 +696,6 @@
 		goto clean_3;
 	}
 	hcd->bus = bus;
-	hcd->bus_name = dev->slot_name;		/* prefer bus->bus_name */
 	bus->bus_name = dev->slot_name;
 	hcd->product_desc = dev->name;
 	bus->hcpriv = (void *) hcd;
@@ -739,14 +739,14 @@
 	hcd = pci_get_drvdata(dev);
 	if (!hcd)
 		return;
-	info ("remove: %s, state %x", hcd->bus_name, hcd->state);
+	info ("remove: %s, state %x", hcd->bus->bus_name, hcd->state);
 
 	if (in_interrupt ()) BUG ();
 
 	hub = hcd->bus->root_hub;
 	hcd->state = USB_STATE_QUIESCING;
 
-	dbg ("%s: roothub graceful disconnect", hcd->bus_name);
+	dbg ("%s: roothub graceful disconnect", hcd->bus->bus_name);
 	usb_disconnect (&hub);
 	// usb_disconnect (&hcd->bus->root_hub);
 
@@ -817,7 +817,7 @@
 	int			retval;
 
 	hcd = pci_get_drvdata(dev);
-	info ("suspend %s to state %d", hcd->bus_name, state);
+	info ("suspend %s to state %d", hcd->bus->bus_name, state);
 
 	pci_save_state (dev, hcd->pci_state);
 
@@ -846,12 +846,12 @@
 	int			retval;
 
 	hcd = pci_get_drvdata(dev);
-	info ("resume %s", hcd->bus_name);
+	info ("resume %s", hcd->bus->bus_name);
 
 	/* guard against multiple resumes (APM bug?) */
 	atomic_inc (&hcd->resume_count);
 	if (atomic_read (&hcd->resume_count) != 1) {
-		err ("concurrent PCI resumes for %s", hcd->bus_name);
+		err ("concurrent PCI resumes for %s", hcd->bus->bus_name);
 		retval = 0;
 		goto done;
 	}
@@ -868,7 +868,8 @@
 
 	retval = hcd->driver->resume (hcd);
 	if (!HCD_IS_RUNNING (hcd->state)) {
-		dbg ("resume %s failure, retval %d", hcd->bus_name, retval);
+		dbg ("resume %s failure, retval %d",
+			hcd->bus->bus_name, retval);
 		hc_died (hcd);
 // FIXME:  recover, reset etc.
 	} else {
@@ -943,7 +944,8 @@
 		list_for_each (urblist, &dev->urb_list) {
 			urb = list_entry (urblist, struct urb, urb_list);
 			dbg ("shutdown %s urb %p pipe %x, current status %d",
-				hcd->bus_name, urb, urb->pipe, urb->status);
+				hcd->bus->bus_name,
+				urb, urb->pipe, urb->status);
 			if (urb->status == -EINPROGRESS)
 				urb->status = -ESHUTDOWN;
 		}
@@ -1067,8 +1069,6 @@
 	if (urb->transfer_buffer_length < 0)
 		return -EINVAL;
 
-	// FIXME set urb->transfer_dma and/or setup_dma 
-
 	if (urb->next) {
 		warn ("use explicit queuing not urb->next");
 		return -EINVAL;
@@ -1186,16 +1186,26 @@
 	if (status)
 		return status;
 
+	// NOTE:  2.5 does this if !URB_NO_DMA_MAP transfer flag
+	if (usb_pipecontrol (urb->pipe))
+		urb->setup_dma = pci_map_single (
+				hcd->pdev,
+				urb->setup_packet,
+				sizeof (struct usb_ctrlrequest),
+				PCI_DMA_TODEVICE);
+	if (urb->transfer_buffer_length != 0)
+		urb->transfer_dma = pci_map_single (
+				hcd->pdev,
+				urb->transfer_buffer,
+				urb->transfer_buffer_length,
+				usb_pipein (urb->pipe)
+				    ? PCI_DMA_FROMDEVICE
+				    : PCI_DMA_TODEVICE);
+
 	if (urb->dev == hcd->bus->root_hub)
 		status = rh_urb_enqueue (hcd, urb);
 	else
 		status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
-	/* urb->dev got nulled if hcd called giveback for us
-	 * NOTE: ref to urb->dev is a race without (2.5) refcounting,
-	 * unless driver only returns status when it didn't giveback 
-	 */
-	if (status && urb->dev)
-		urb_unlink (urb);
 	return status;
 }
 
@@ -1282,25 +1292,25 @@
 		goto done;
 	}
 
-	/* For non-periodic transfers, any status except -EINPROGRESS means
-	 * the HCD has already started to unlink this URB from the hardware.
-	 * In that case, there's no more work to do.
+	/* Any status except -EINPROGRESS means the HCD has already started
+	 * to return this URB to the driver.  In that case, there's no
+	 * more work for us to do.
 	 *
-	 * For periodic transfers, this is the only way to trigger unlinking
-	 * from the hardware.  Since we (currently) overload urb->status to
-	 * tell the driver to unlink, error status might get clobbered ...
-	 * unless that transfer hasn't yet restarted.  One such case is when
-	 * the URB gets unlinked from its completion handler.
+	 * There's much magic because of "automagic resubmit" of interrupt
+	 * transfers, stopped only by explicit unlinking.  We won't issue
+	 * an "it's unlinked" callback more than once, but device drivers
+	 * can need to retry (SMP, -EAGAIN) an unlink request as well as
+	 * fake out the "not yet completed" state (set -EINPROGRESS) if
+	 * unlinking from complete().  Automagic eventually vanishes.
 	 *
 	 * FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED
 	 */
-	switch (usb_pipetype (urb->pipe)) {
-	case PIPE_CONTROL:
-	case PIPE_BULK:
-		if (urb->status != -EINPROGRESS) {
+	if (urb->status != -EINPROGRESS) {
+		if (usb_pipetype (urb->pipe) == PIPE_INTERRUPT)
+			retval = -EAGAIN;
+		else
 			retval = -EINVAL;
-			goto done;
-		}
+		goto done;
 	}
 
 	/* maybe set up to block on completion notification */
@@ -1340,7 +1350,7 @@
 			&& HCD_IS_RUNNING (hcd->state)
 			&& !retval) {
 		dbg ("%s: wait for giveback urb %p",
-			hcd->bus_name, urb);
+			hcd->bus->bus_name, urb);
 		wait_for_completion (&splice.done);
 	} else if ((urb->transfer_flags & USB_ASYNC_UNLINK) && retval == 0) {
 		return -EINPROGRESS;
@@ -1352,7 +1362,7 @@
 bye:
 	if (retval)
 		dbg ("%s: hcd_unlink_urb fail %d",
-		    hcd ? hcd->bus_name : "(no bus?)",
+		    hcd ? hcd->bus->bus_name : "(no bus?)",
 		    retval);
 	return retval;
 }
@@ -1385,7 +1395,7 @@
 	/* device driver problem with refcounts? */
 	if (!list_empty (&dev->urb_list)) {
 		dbg ("free busy dev, %s devnum %d (bug!)",
-			hcd->bus_name, udev->devnum);
+			hcd->bus->bus_name, udev->devnum);
 		return -EINVAL;
 	}
 
@@ -1460,7 +1470,17 @@
 		dbg ("giveback urb %p status %d len %d",
 			urb, urb->status, urb->actual_length);
 
-	// FIXME unmap urb->transfer_dma and/or setup_dma 
+	// NOTE:  2.5 does this if !URB_NO_DMA_MAP transfer flag
+	if (usb_pipecontrol (urb->pipe))
+		pci_unmap_single (hcd->pdev, urb->setup_dma,
+				sizeof (struct usb_ctrlrequest),
+				PCI_DMA_TODEVICE);
+	if (urb->transfer_buffer_length != 0)
+		pci_unmap_single (hcd->pdev, urb->transfer_dma,
+				urb->transfer_buffer_length,
+				usb_pipein (urb->pipe)
+				    ? PCI_DMA_FROMDEVICE
+				    : PCI_DMA_TODEVICE);
 
 	/* pass ownership to the completion handler */
 	urb->complete (urb);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/usb/hcd.h linux.20pre10-ac2/drivers/usb/hcd.h
--- linux.20pre10/drivers/usb/hcd.h	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/usb/hcd.h	2002-10-09 22:15:47.000000000 +0100
@@ -36,7 +36,6 @@
 	struct usb_bus		*bus;		/* hcd is-a bus */
 	struct list_head	hcd_list;
 
-	const char		*bus_name;
 	const char		*product_desc;
 	const char		*description;	/* "ehci-hcd" etc */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/usb/mdc800.c linux.20pre10-ac2/drivers/usb/mdc800.c
--- linux.20pre10/drivers/usb/mdc800.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/usb/mdc800.c	2002-09-19 01:07:28.000000000 +0100
@@ -652,7 +652,7 @@
  */
 static ssize_t mdc800_device_read (struct file *file, char *buf, size_t len, loff_t *pos)
 {
-	int   left=len, sts=len; /* single transfer size */
+	size_t left=len, sts=len; /* single transfer size */
 	char* ptr=buf;
 	DECLARE_WAITQUEUE(wait, current);
 
@@ -746,7 +746,7 @@
  */
 static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t len, loff_t *pos)
 {
-	int i=0;
+	size_t i=0;
 	DECLARE_WAITQUEUE(wait, current);
 
 	down (&mdc800->io_lock);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/usb/printer.c linux.20pre10-ac2/drivers/usb/printer.c
--- linux.20pre10/drivers/usb/printer.c	2002-10-09 21:44:47.000000000 +0100
+++ linux.20pre10-ac2/drivers/usb/printer.c	2002-09-19 01:04:29.000000000 +0100
@@ -562,7 +562,8 @@
 static ssize_t usblp_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct usblp *usblp = file->private_data;
-	int timeout, err = 0, writecount = 0;
+	int timeout, err = 0;
+	size_t writecount = 0;
 
 	while (writecount < count) {
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/usb/storage/isd200.c linux.20pre10-ac2/drivers/usb/storage/isd200.c
--- linux.20pre10/drivers/usb/storage/isd200.c	2002-10-09 21:36:54.000000000 +0100
+++ linux.20pre10-ac2/drivers/usb/storage/isd200.c	2002-08-19 23:43:56.000000000 +0100
@@ -102,13 +102,6 @@
 #define REG_STATUS           0x80
 #define REG_COMMAND          0x80
 
-/* ATA error definitions not in <linux/hdreg.h> */
-#define ATA_ERROR_MEDIA_CHANGE       0x20
-
-/* ATA command definitions not in <linux/hdreg.h> */
-#define ATA_COMMAND_GET_MEDIA_STATUS        0xDA
-#define ATA_COMMAND_MEDIA_EJECT             0xED
-
 /* ATA drive control definitions */
 #define ATA_DC_DISABLE_INTERRUPTS    0x02
 #define ATA_DC_RESET_CONTROLLER      0x04
@@ -353,7 +346,7 @@
         struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0];
         unsigned char error = info->ATARegs[IDE_ERROR_OFFSET];
 
-	if(error & ATA_ERROR_MEDIA_CHANGE) {
+	if(error & MC_ERR) {
 		buf->ErrorCode = 0x70 | SENSE_ERRCODE_VALID;
 		buf->AdditionalSenseLength = 0xb;
 		buf->Flags = UNIT_ATTENTION;
@@ -1472,7 +1465,7 @@
 			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
 			ataCdb->generic.TransferBlockSize = 1;
 			ataCdb->generic.RegisterSelect = REG_COMMAND;
-			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
+			ataCdb->write.CommandByte = WIN_GETMEDIASTATUS;
 			srb->request_bufflen = 0;
 		} else {
 			US_DEBUGP("   Media Status not supported, just report okay\n");
@@ -1493,7 +1486,7 @@
 			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
 			ataCdb->generic.TransferBlockSize = 1;
 			ataCdb->generic.RegisterSelect = REG_COMMAND;
-			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
+			ataCdb->write.CommandByte = WIN_GETMEDIASTATUS;
 			srb->request_bufflen = 0;
 		} else {
 			US_DEBUGP("   Media Status not supported, just report okay\n");
@@ -1625,14 +1618,14 @@
 			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
 			ataCdb->generic.TransferBlockSize = 0;
 			ataCdb->generic.RegisterSelect = REG_COMMAND;
-			ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT;
+			ataCdb->write.CommandByte = WIN_MEDIAEJECT;
 		} else if ((srb->cmnd[4] & 0x3) == 0x1) {
 			US_DEBUGP("   Get Media Status\n");
 			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
 			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
 			ataCdb->generic.TransferBlockSize = 1;
 			ataCdb->generic.RegisterSelect = REG_COMMAND;
-			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
+			ataCdb->write.CommandByte = WIN_GETMEDIASTATUS;
 			srb->request_bufflen = 0;
 		} else {
 			US_DEBUGP("   Nothing to do, just report okay\n");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/usb/storage/unusual_devs.h linux.20pre10-ac2/drivers/usb/storage/unusual_devs.h
--- linux.20pre10/drivers/usb/storage/unusual_devs.h	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/usb/storage/unusual_devs.h	2002-10-07 21:33:35.000000000 +0100
@@ -97,6 +97,15 @@
 		"DVD-CAM DZ-MV100A Camcorder",
 		US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN),
 
+/* Reported by Jan Willamowius <jan@willamowius.de>
+ * The device needs the flags only.
+ */
+UNUSUAL_DEV(  0x04c8, 0x0723, 0x0000, 0x9999,
+		"Konica",
+		"KD-200Z",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_START_STOP),
+
 UNUSUAL_DEV(  0x04cb, 0x0100, 0x0000, 0x2210,
 		"Fujifilm",
 		"FinePix 1400Zoom",
@@ -487,6 +496,17 @@
 		US_FL_MODE_XLATE ),
 #endif
 
+/* Datafab KECF-USB / Sagatek DCS-CF (Datafab DF-UG-07 chip).
+ * Submitted by Marek Michalkiewicz <marekm@amelek.gda.pl>.
+ * Needed for FIX_INQUIRY.  Only revision 1.13 tested.
+ * See also http://martin.wilck.bei.t-online.de/#kecf .
+ */
+UNUSUAL_DEV(  0x07c4, 0xa400, 0x0000, 0xffff,
+		"Datafab",
+		"KECF-USB",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY ),
+
 /* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant
  * to the USB storage specification in two ways:
  * - They tell us they are using transport protocol CBI. In reality they
@@ -506,6 +526,12 @@
  		US_SC_SCSI, US_PR_CB, NULL,
 		US_FL_MODE_XLATE ),
 
+UNUSUAL_DEV(  0x0a16, 0x8888, 0x0100, 0x0100,
+		"IBM",
+		"IBM USB Memory Key",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_FIX_INQUIRY ),
+		
 #ifdef CONFIG_USB_STORAGE_ISD200
 UNUSUAL_DEV(  0x0bf6, 0xa001, 0x0100, 0x0110,
                 "ATI",
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/usb/usb.c linux.20pre10-ac2/drivers/usb/usb.c
--- linux.20pre10/drivers/usb/usb.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/usb/usb.c	2002-09-29 20:53:37.000000000 +0100
@@ -164,6 +164,26 @@
 	}
 }
 
+/*
+ * usb_ifnum_to_ifpos - convert the interface _number_ (as in interface.bInterfaceNumber)
+ * to the interface _position_ (as in dev->actconfig->interface + position)
+ * @dev: the device to use
+ * @ifnum: the interface number (bInterfaceNumber); not interface position
+ *
+ * Note that the number is the same as the position for all interfaces _except_
+ * devices with interfaces not sequentially numbered (e.g., 0, 2, 3, etc).
+ */
+int usb_ifnum_to_ifpos(struct usb_device *dev, unsigned ifnum)
+{
+	int i;
+
+	for (i = 0; i < dev->actconfig->bNumInterfaces; i++)
+		if (dev->actconfig->interface[i].altsetting[0].bInterfaceNumber == ifnum)
+			return i;
+
+	return -EINVAL;
+}
+
 /**
  *	usb_deregister - unregister a USB driver
  *	@driver: USB operations of the driver to unregister
@@ -546,7 +566,6 @@
 	iface->private_data = NULL;
 }
 
-
 /**
  * usb_match_id - find first usb_device_id matching device or interface
  * @dev: the device whose descriptors are considered when matching
@@ -759,6 +778,23 @@
 	return -1;
 }
 
+/*
+ * usb_find_interface_driver_for_ifnum - convert ifnum to ifpos via
+ * usb_ifnum_to_ifpos and call usb_find_interface_driver().
+ * @dev: the device to use
+ * @ifnum: the interface number (bInterfaceNumber); not interface position!
+ *
+ * Note usb_find_interface_driver's ifnum parameter is actually interface position.
+ */
+int usb_find_interface_driver_for_ifnum(struct usb_device *dev, unsigned int ifnum)
+{
+	int ifpos = usb_ifnum_to_ifpos(dev, ifnum);
+
+	if (0 > ifpos)
+		return -EINVAL;
+
+	return usb_find_interface_driver(dev, ifpos);
+}
 
 #ifdef	CONFIG_HOTPLUG
 
@@ -2382,6 +2418,7 @@
  * into the kernel, and other device drivers are built as modules,
  * then these symbols need to be exported for the modules to use.
  */
+EXPORT_SYMBOL(usb_ifnum_to_ifpos);
 EXPORT_SYMBOL(usb_ifnum_to_if);
 EXPORT_SYMBOL(usb_epnum_to_ep_desc);
 
@@ -2396,6 +2433,7 @@
 EXPORT_SYMBOL(usb_free_dev);
 EXPORT_SYMBOL(usb_inc_dev_use);
 
+EXPORT_SYMBOL(usb_find_interface_driver_for_ifnum);
 EXPORT_SYMBOL(usb_driver_claim_interface);
 EXPORT_SYMBOL(usb_interface_claimed);
 EXPORT_SYMBOL(usb_driver_release_interface);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/aty/atyfb_base.c linux.20pre10-ac2/drivers/video/aty/atyfb_base.c
--- linux.20pre10/drivers/video/aty/atyfb_base.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/aty/atyfb_base.c	2002-09-14 21:53:00.000000000 +0100
@@ -360,6 +360,7 @@
 
     /* 3D RAGE Mobility */
     { 0x4c4d, 0x4c4d, 0x00, 0x00, m64n_mob_p,   230,  50, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_MOBIL_BUS },
+    { 0x4c52, 0x4c52, 0x00, 0x00, m64n_mob_p,   230,  40, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_MOBIL_BUS | M64F_MAGIC_POSTDIV | M64F_SDRAM_MAGIC_PLL | M64F_XL_DLL },
     { 0x4c4e, 0x4c4e, 0x00, 0x00, m64n_mob_a,   230,  50, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_MOBIL_BUS },
 #endif /* CONFIG_FB_ATY_CT */
 };
@@ -438,7 +439,7 @@
 
 #endif /* defined(CONFIG_PPC) */
 
-#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_PMAC_BACKLIGHT)
+#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_PMAC_BACKLIGHT) || defined(CONFIG_FB_ATY_CT_VAIO_LCD)
 static void aty_st_lcd(int index, u32 val, const struct fb_info_aty *info)
 {
     unsigned long temp;
@@ -460,7 +461,7 @@
     /* read the register value */
     return aty_ld_le32(LCD_DATA, info);
 }
-#endif /* CONFIG_PMAC_PBOOK || CONFIG_PMAC_BACKLIGHT */
+#endif /* CONFIG_PMAC_PBOOK || CONFIG_PMAC_BACKLIGHT || CONFIG_FB_ATY_CT_VAIO_LCD */
 
 /* ------------------------------------------------------------------------- */
 
@@ -1772,6 +1773,9 @@
 #if defined(CONFIG_PPC)
     int sense;
 #endif
+#if defined(CONFIG_FB_ATY_CT_VAIO_LCD)
+	u32 pm, hs;
+#endif
     u8 pll_ref_div;
 
     info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0);
@@ -2089,6 +2093,35 @@
 	var = default_var;
 #endif /* !__sparc__ */
 #endif /* !CONFIG_PPC */
+#if defined(CONFIG_FB_ATY_CT_VAIO_LCD)
+	/* Power Management */
+	pm=aty_ld_lcd(POWER_MANAGEMENT, info);
+	pm=(pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_PCI;
+	pm|=PWR_MGT_ON;
+	aty_st_lcd(POWER_MANAGEMENT, pm, info);
+	udelay(10);
+	
+	/* OVR_WID_LEFT_RIGHT */
+	hs=aty_ld_le32(OVR_WID_LEFT_RIGHT,info);
+	hs= 0x00000000;
+	aty_st_le32(OVR_WID_LEFT_RIGHT, hs, info);
+	udelay(10);
+
+	/* CONFIG_PANEL */
+	hs=aty_ld_lcd(CONFIG_PANEL,info);
+	hs|=DONT_SHADOW_HEND ;
+	aty_st_lcd(CONFIG_PANEL, hs, info);
+	udelay(10);
+
+#if defined(DEBUG)
+	printk("LCD_INDEX CONFIG_PANEL LCD_GEN_CTRL POWER_MANAGEMENT\n"
+	"%08x  %08x     %08x     %08x\n",
+	aty_ld_le32(LCD_INDEX, info), 
+	aty_ld_lcd(CONFIG_PANEL, info),
+	aty_ld_lcd(LCD_GEN_CTRL, info), 
+	aty_ld_lcd(POWER_MANAGEMENT, info),
+#endif /* DEBUG */	
+#endif /* CONFIG_FB_ATY_CT_VAIO_LCD */
 #endif /* !MODULE */
     if (noaccel)
         var.accel_flags &= ~FB_ACCELF_TEXT;
@@ -2714,6 +2747,23 @@
     /*
      *  Blank the display.
      */
+#if defined(CONFIG_FB_ATY_CT_VAIO_LCD)
+static int set_backlight_enable(int on, struct fb_info_aty *info)
+{
+	unsigned int reg = aty_ld_lcd(POWER_MANAGEMENT, info);
+	if(on) {
+		reg=(reg & ~SUSPEND_NOW) | PWR_BLON;
+	} else {
+		reg=(reg & ~PWR_BLON) | SUSPEND_NOW;
+	}
+	aty_st_lcd(POWER_MANAGEMENT, reg, info);
+	udelay(10);
+#ifdef DEBUG		
+		printk(KERN_INFO "set_backlight_enable(%i): %08x\n", on, aty_ld_lcd(POWER_MANAGEMENT, info) );
+#endif		
+	return 0;
+}
+#endif /* CONFIG_FB_ATY_CT_VAIO_LCD */
 
 static void atyfbcon_blank(int blank, struct fb_info *fb)
 {
@@ -2725,6 +2775,9 @@
     	set_backlight_enable(0);
 #endif /* CONFIG_PMAC_BACKLIGHT */
 
+#if defined(CONFIG_FB_ATY_CT_VAIO_LCD) 
+	set_backlight_enable(!blank, info);
+#endif /* CONFIG_FB_ATY_CT_VAIO_LCD */	
     gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info);
     if (blank > 0)
 	switch (blank-1) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/aty/mach64_ct.c linux.20pre10-ac2/drivers/video/aty/mach64_ct.c
--- linux.20pre10/drivers/video/aty/mach64_ct.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/aty/mach64_ct.c	2002-08-06 15:42:11.000000000 +0100
@@ -178,11 +178,14 @@
     }
     pll->pll_gen_cntl |= mpostdiv<<4;	/* mclk */
 
-    if (M64_HAS(MAGIC_POSTDIV))
-	pll->pll_ext_cntl = 0;
-    else
+#if defined(CONFIG_FB_ATY_CT_VAIO_LCD)
     	pll->pll_ext_cntl = mpostdiv;	/* xclk == mclk */
-
+#else
+	if ( M64_HAS(MAGIC_POSTDIV) )
+		pll->pll_ext_cntl = 0;
+	else
+    		pll->pll_ext_cntl = mpostdiv;	/* xclk == mclk */
+#endif 
     switch (pll->vclk_post_div_real) {
 	case 2:
 	    vpostdiv = 1;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/aty/mach64.h linux.20pre10-ac2/drivers/video/aty/mach64.h
--- linux.20pre10/drivers/video/aty/mach64.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/aty/mach64.h	2002-08-06 15:42:11.000000000 +0100
@@ -1148,6 +1148,8 @@
 #define APC_LUT_MN		0x39
 #define APC_LUT_OP		0x3A
 
+/* Values in CONFIG_PANEL */
+#define DONT_SHADOW_HEND       0x00004000
 
 /* Values in LCD_MISC_CNTL */
 #define BIAS_MOD_LEVEL_MASK	0x0000ff00
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/Config.in linux.20pre10-ac2/drivers/video/Config.in
--- linux.20pre10/drivers/video/Config.in	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/Config.in	2002-09-18 12:20:52.000000000 +0100
@@ -124,22 +124,34 @@
 	 if [ "$CONFIG_FB_MATROX" != "n" ]; then
 	    bool '    Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM
 	    bool '    Mystique support' CONFIG_FB_MATROX_MYSTIQUE
-	    bool '    G100/G200/G400/G450/G550 support' CONFIG_FB_MATROX_G100
+ 	    bool '    G100/G200/G400/G450/G550 support' CONFIG_FB_MATROX_G450
+ 	    if [ "$CONFIG_FB_MATROX_G450" = "n" ]; then
+ 	       bool '    G100/G200/G400 support' CONFIG_FB_MATROX_G100A
+ 	    fi
+ 	    if [ "$CONFIG_FB_MATROX_G450" = "y" -o "$CONFIG_FB_MATROX_G100A" = "y" ]; then
+ 	       define_bool CONFIG_FB_MATROX_G100 y
+ 	    fi
             if [ "$CONFIG_I2C" != "n" ]; then
 	       dep_tristate '      Matrox I2C support' CONFIG_FB_MATROX_I2C $CONFIG_FB_MATROX $CONFIG_I2C_ALGOBIT
 	       if [ "$CONFIG_FB_MATROX_G100" = "y" ]; then
 	          dep_tristate '      G400 second head support' CONFIG_FB_MATROX_MAVEN $CONFIG_FB_MATROX_I2C
 	       fi
             fi
-            dep_tristate '      G450/G550 second head support (mandatory for G550)' CONFIG_FB_MATROX_G450 $CONFIG_FB_MATROX_G100
+            dep_tristate '    Matrox /proc interface' CONFIG_FB_MATROX_PROC $CONFIG_FB_MATROX
 	    bool '    Multihead support' CONFIG_FB_MATROX_MULTIHEAD
 	 fi
 	 tristate '  ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY
 	 if [ "$CONFIG_FB_ATY" != "n" ]; then
 	    bool '    Mach64 GX support (EXPERIMENTAL)' CONFIG_FB_ATY_GX
 	    bool '    Mach64 CT/VT/GT/LT (incl. 3D RAGE) support' CONFIG_FB_ATY_CT
+	       if [ "$CONFIG_FB_ATY_CT" = "y" ]; then
+	          bool '      Sony Vaio C1VE 1024x480 LCD support' CONFIG_FB_ATY_CT_VAIO_LCD
+	       fi
 	 fi
  	 tristate '  ATI Radeon display support (EXPERIMENTAL)' CONFIG_FB_RADEON
+	    if [ "$CONFIG_FB_RADEON" = "y" ]; then
+	       bool '    Sony Vaio C1MV 1280x600 LCD support' CONFIG_FB_RADEON_VAIO_LCD
+	    fi
 	 tristate '  ATI Rage128 display support (EXPERIMENTAL)' CONFIG_FB_ATY128
 	 tristate '  SIS acceleration (EXPERIMENTAL)' CONFIG_FB_SIS
 	 if [ "$CONFIG_FB_SIS" != "n" ]; then
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/matrox/g450_pll.c linux.20pre10-ac2/drivers/video/matrox/g450_pll.c
--- linux.20pre10/drivers/video/matrox/g450_pll.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/matrox/g450_pll.c	2002-09-02 00:06:57.000000000 +0100
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox PCI cards - G450/G550 PLL control.
  *
- * (c) 2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.64 2002/06/10
  *
  * 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
@@ -33,6 +33,10 @@
 	return (ACCESS_FBINFO(features).pll.ref_freq * n + (m >> 1)) / m;
 }
 
+unsigned int g450_mnp2f(CPMINFO unsigned int mnp) {
+	return g450_vco2f(mnp, g450_mnp2vco(PMINFO mnp));
+}
+
 static inline unsigned int pll_freq_delta(unsigned int f1, unsigned int f2) {
 	if (f2 < f1) {
     		f2 = f1 - f2;
@@ -52,40 +56,42 @@
 	m = (mnp >> 16) & 0xFF;
 	p = mnp & 0xFF;
 
-	if (m == 0 || m == 0xFF) {
-		if (m == 0) {
-			if (p & 0x40) {
-				return NO_MORE_MNP;
+	do {
+		if (m == 0 || m == 0xFF) {
+			if (m == 0) {
+				if (p & 0x40) {
+					return NO_MORE_MNP;
+				}
+			        if (p & 3) {
+					p--;
+				} else {
+					p = 0x40;
+				}
+				tvco >>= 1;
+				if (tvco < pi->vcomin) {
+					return NO_MORE_MNP;
+				}
+				*fvco = tvco;
 			}
-		        if (p & 3) {
-				p--;
+
+			p &= 0x43;
+			if (tvco < 550000) {
+/*				p |= 0x00; */
+			} else if (tvco < 700000) {
+				p |= 0x08;
+			} else if (tvco < 1000000) {
+				p |= 0x10;
+			} else if (tvco < 1150000) {
+				p |= 0x18;
 			} else {
-				p = 0x40;
+				p |= 0x20;
 			}
-			tvco >>= 1;
-			if (tvco < pi->vcomin) {
-				return NO_MORE_MNP;
-			}
-			*fvco = tvco;
-		}
-
-		p &= 0x43;
-		if (tvco < 550000) {
-/*			p |= 0x00; */
-		} else if (tvco < 700000) {
-			p |= 0x08;
-		} else if (tvco < 1000000) {
-			p |= 0x10;
-		} else if (tvco < 1150000) {
-			p |= 0x18;
+			m = 9;
 		} else {
-			p |= 0x20;
+			m--;
 		}
-		m = 9;
-	} else {
-		m--;
-	}
-        n = ((tvco * (m+1) + ACCESS_FBINFO(features).pll.ref_freq) / (ACCESS_FBINFO(features).pll.ref_freq * 2)) - 2;
+        	n = ((tvco * (m+1) + ACCESS_FBINFO(features).pll.ref_freq) / (ACCESS_FBINFO(features).pll.ref_freq * 2)) - 2;
+	} while (n < 0x03 || n > 0x7A);
 	return (m << 16) | (n << 8) | p;
 }
 
@@ -219,7 +225,7 @@
 	}
 }
 
-static inline void g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll) {
+void matroxfb_g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll) {
 	if (g450_cmppll(PMINFO mnp, pll)) {
 		g450_setpll(PMINFO mnp, pll);
 	}
@@ -385,10 +391,8 @@
 			unsigned int vco;
 			unsigned int delta;
 
-			if ((mnp & 0xFF00) < 0x0300 || (mnp & 0xFF00) > 0x7A00) {
-				continue;
-			}
 			vco = g450_mnp2vco(PMINFO mnp);
+#if 0			
 			if (pll == M_VIDEO_PLL) {
 				unsigned int big, small;
 
@@ -406,6 +410,7 @@
 					continue;
 				}
 			}
+#endif			
 			delta = pll_freq_delta(fout, g450_vco2f(mnp, vco));
 			for (idx = mnpcount; idx > 0; idx--) {
 				/* == is important; due to nextpll algorithm we get
@@ -426,7 +431,7 @@
 	}
 	/* VideoPLL and PixelPLL matched: do nothing... In all other cases we should get at least one frequency */
 	if (!mnpcount) {
-		return 1;
+		return -EBUSY;
 	}
 	{
 		unsigned long flags;
@@ -435,15 +440,15 @@
 		matroxfb_DAC_lock_irqsave(flags);
 		mnp = g450_checkcache(PMINFO ci, mnparray[0]);
 		if (mnp != NO_MORE_MNP) {
-			g450_setpll_cond(PMINFO mnp, pll);
+			matroxfb_g450_setpll_cond(PMINFO mnp, pll);
 		} else {
 			mnp = g450_findworkingpll(PMINFO pll, mnparray, mnpcount);
 			g450_addcache(ci, mnparray[0], mnp);
 		}
 		updatehwstate_clk(&ACCESS_FBINFO(hw), mnp, pll);
 		matroxfb_DAC_unlock_irqrestore(flags);
+		return mnp;
 	}
-	return 0;
 }
 
 /* It must be greater than number of possible PLL values.
@@ -465,8 +470,10 @@
 }
 
 EXPORT_SYMBOL(matroxfb_g450_setclk);
+EXPORT_SYMBOL(g450_mnp2f);
+EXPORT_SYMBOL(matroxfb_g450_setpll_cond);
 
-MODULE_AUTHOR("(c) 2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_AUTHOR("(c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
 MODULE_DESCRIPTION("Matrox G450/G550 PLL driver");
 
 MODULE_LICENSE("GPL");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/matrox/g450_pll.h linux.20pre10-ac2/drivers/video/matrox/g450_pll.h
--- linux.20pre10/drivers/video/matrox/g450_pll.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/matrox/g450_pll.h	2002-10-11 00:35:04.000000000 +0100
@@ -4,5 +4,7 @@
 #include "matroxfb_base.h"
 
 int matroxfb_g450_setclk(WPMINFO unsigned int fout, unsigned int pll);
+unsigned int g450_mnp2f(CPMINFO unsigned int mnp);
+void matroxfb_g450_setpll_cond(WPMINFO unsigned int mnp, unsigned int pll);
 
 #endif	/* __G450_PLL_H__ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/matrox/i2c-matroxfb.c linux.20pre10-ac2/drivers/video/matrox/i2c-matroxfb.c
--- linux.20pre10/drivers/video/matrox/i2c-matroxfb.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/matrox/i2c-matroxfb.c	2002-09-02 00:06:57.000000000 +0100
@@ -2,9 +2,9 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
- * Version: 1.51 2001/01/19
+ * Version: 1.64 2002/06/10
  *
  * See matroxfb_base.c for contributors.
  *
@@ -30,6 +30,12 @@
 
 /******************************************************/
 
+struct matroxfb_dh_maven_info {
+	struct i2c_bit_adapter	maven;
+	struct i2c_bit_adapter	ddc1;
+	struct i2c_bit_adapter	ddc2;
+};
+
 static int matroxfb_read_gpio(struct matrox_fb_info* minfo) {
 	unsigned long flags;
 	int v;
@@ -40,7 +46,7 @@
 	return v;
 }
 
-static inline void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int val) {
+static void matroxfb_set_gpio(struct matrox_fb_info* minfo, int mask, int val) {
 	unsigned long flags;
 	int v;
 
@@ -53,7 +59,7 @@
 }
 
 /* software I2C functions */
-static void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state) {
+static inline void matroxfb_i2c_set(struct matrox_fb_info* minfo, int mask, int state) {
 	if (state)
 		state = 0;
 	else
@@ -61,68 +67,24 @@
 	matroxfb_set_gpio(minfo, ~mask, state);
 }
 
-static void matroxfb_maven_setsda(void* data, int state) {
-	matroxfb_i2c_set(data, MAT_DATA, state);
-}
-
-static void matroxfb_maven_setscl(void* data, int state) {
-	matroxfb_i2c_set(data, MAT_CLK, state);
-}
-
-static int matroxfb_maven_getsda(void* data) {
-	return (matroxfb_read_gpio(data) & MAT_DATA) ? 1 : 0;
+static void matroxfb_gpio_setsda(void* data, int state) {
+	struct i2c_bit_adapter* b = data;
+	matroxfb_i2c_set(b->minfo, b->mask.data, state);
 }
 
-static int matroxfb_maven_getscl(void* data) {
-	return (matroxfb_read_gpio(data) & MAT_CLK) ? 1 : 0;
+static void matroxfb_gpio_setscl(void* data, int state) {
+	struct i2c_bit_adapter* b = data;
+	matroxfb_i2c_set(b->minfo, b->mask.clock, state);
 }
 
-static void matroxfb_ddc1_setsda(void* data, int state) {
-	matroxfb_i2c_set(data, DDC1_DATA, state);
+static int matroxfb_gpio_getsda(void* data) {
+	struct i2c_bit_adapter* b = data;
+	return (matroxfb_read_gpio(b->minfo) & b->mask.data) ? 1 : 0;
 }
 
-static void matroxfb_ddc1_setscl(void* data, int state) {
-	matroxfb_i2c_set(data, DDC1_CLK, state);
-}
-
-static int matroxfb_ddc1_getsda(void* data) {
-	return (matroxfb_read_gpio(data) & DDC1_DATA) ? 1 : 0;
-}
-
-static int matroxfb_ddc1_getscl(void* data) {
-	return (matroxfb_read_gpio(data) & DDC1_CLK) ? 1 : 0;
-}
-
-static void matroxfb_ddc1b_setsda(void* data, int state) {
-	matroxfb_i2c_set(data, DDC1B_DATA, state);
-}
-
-static void matroxfb_ddc1b_setscl(void* data, int state) {
-	matroxfb_i2c_set(data, DDC1B_CLK, state);
-}
-
-static int matroxfb_ddc1b_getsda(void* data) {
-	return (matroxfb_read_gpio(data) & DDC1B_DATA) ? 1 : 0;
-}
-
-static int matroxfb_ddc1b_getscl(void* data) {
-	return (matroxfb_read_gpio(data) & DDC1B_CLK) ? 1 : 0;
-}
-
-static void matroxfb_ddc2_setsda(void* data, int state) {
-	matroxfb_i2c_set(data, DDC2_DATA, state);
-}
-
-static void matroxfb_ddc2_setscl(void* data, int state) {
-	matroxfb_i2c_set(data, DDC2_CLK, state);
-}
-
-static int matroxfb_ddc2_getsda(void* data) {
-	return (matroxfb_read_gpio(data) & DDC2_DATA) ? 1 : 0;
-}
-
-static int matroxfb_ddc2_getscl(void* data) {
-	return (matroxfb_read_gpio(data) & DDC2_CLK) ? 1 : 0;
+static int matroxfb_gpio_getscl(void* data) {
+	struct i2c_bit_adapter* b = data;
+	return (matroxfb_read_gpio(b->minfo) & b->mask.clock) ? 1 : 0;
 }
 
 static void matroxfb_dh_inc_use(struct i2c_adapter* dummy) {
@@ -133,97 +95,36 @@
 	MOD_DEC_USE_COUNT;
 }
 
-static struct i2c_adapter matroxmaven_i2c_adapter_template =
+static struct i2c_adapter matrox_i2c_adapter_template =
 {
-	"",
-	I2C_HW_B_G400,
-
-	NULL,
-	NULL,
-
-	matroxfb_dh_inc_use,
-	matroxfb_dh_dec_use,
-	NULL,
-	NULL,
-	NULL,
+	.id =		I2C_HW_B_G400,
+	.inc_use =	matroxfb_dh_inc_use,
+	.dec_use =	matroxfb_dh_dec_use,
 };
 
-static struct i2c_algo_bit_data matroxmaven_i2c_algo_template =
+static struct i2c_algo_bit_data matrox_i2c_algo_template =
 {
 	NULL,
-	matroxfb_maven_setsda,
-	matroxfb_maven_setscl,
-	matroxfb_maven_getsda,
-	matroxfb_maven_getscl,
+	matroxfb_gpio_setsda,
+	matroxfb_gpio_setscl,
+	matroxfb_gpio_getsda,
+	matroxfb_gpio_getscl,
 	10, 10, 100,
 };
 
-static struct i2c_adapter matrox_ddc1_adapter_template =
-{
-	"",
-	I2C_HW_B_G400, /* DDC */
-
-	NULL,
-	NULL,
-
-	matroxfb_dh_inc_use,
-	matroxfb_dh_dec_use,
-	NULL,
-	NULL,
-	NULL,
-};
-
-static struct i2c_algo_bit_data matrox_ddc1_algo_template =
-{
-	NULL,
-	matroxfb_ddc1_setsda,
-	matroxfb_ddc1_setscl,
-	matroxfb_ddc1_getsda,
-	matroxfb_ddc1_getscl,
-	10, 10, 100,
-};
-
-static struct i2c_algo_bit_data matrox_ddc1b_algo_template =
-{
-	NULL,
-	matroxfb_ddc1b_setsda,
-	matroxfb_ddc1b_setscl,
-	matroxfb_ddc1b_getsda,
-	matroxfb_ddc1b_getscl,
-	10, 10, 100,
-};
-
-static struct i2c_adapter matrox_ddc2_adapter_template =
-{
-	"",
-	I2C_HW_B_G400,	/* DDC */
-
-	NULL,
-	NULL,
-
-	matroxfb_dh_inc_use, /* should increment matroxfb_maven usage too, this DDC is coupled with maven_client */
-	matroxfb_dh_dec_use, /* should decrement matroxfb_maven usage too */
-	NULL,
-	NULL,
-	NULL,
-};
-
-static struct i2c_algo_bit_data matrox_ddc2_algo_template =
-{
-	NULL,
-	matroxfb_ddc2_setsda,
-	matroxfb_ddc2_setscl,
-	matroxfb_ddc2_getsda,
-	matroxfb_ddc2_getscl,
-	10, 10, 100,
-};
-
-static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo) {
+static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo, 
+		unsigned int data, unsigned int clock, const char* name) {
 	int err;
 
-	b->adapter.data = minfo;
+	b->minfo = minfo;
+	b->mask.data = data;
+	b->mask.clock = clock;
+	b->adapter = matrox_i2c_adapter_template;
+	sprintf(b->adapter.name, name, GET_FB_IDX(minfo->fbcon.node));
+	b->adapter.data = b;
 	b->adapter.algo_data = &b->bac;
-	b->bac.data = minfo;
+	b->bac = matrox_i2c_algo_template;
+	b->bac.data = b;
 	err = i2c_bit_add_bus(&b->adapter);
 	b->initialized = !err;
 	return err;
@@ -236,50 +137,14 @@
 	}
 }
 
-static inline int i2c_maven_init(struct matroxfb_dh_maven_info* minfo2) {
-	struct i2c_bit_adapter *b = &minfo2->maven;
-
-	b->adapter = matroxmaven_i2c_adapter_template;
-	b->bac = matroxmaven_i2c_algo_template;
-	sprintf(b->adapter.name, "MAVEN:fb%u on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
-	return i2c_bus_reg(b, minfo2->primary_dev);
-}
-
 static inline void i2c_maven_done(struct matroxfb_dh_maven_info* minfo2) {
 	i2c_bit_bus_del(&minfo2->maven);
 }
 
-static inline int i2c_ddc1_init(struct matroxfb_dh_maven_info* minfo2) {
-	struct i2c_bit_adapter *b = &minfo2->ddc1;
-
-	b->adapter = matrox_ddc1_adapter_template;
-	b->bac = matrox_ddc1_algo_template;
-	sprintf(b->adapter.name, "DDC:fb%u #0 on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
-	return i2c_bus_reg(b, minfo2->primary_dev);
-}
-
-static inline int i2c_ddc1b_init(struct matroxfb_dh_maven_info* minfo2) {
-	struct i2c_bit_adapter *b = &minfo2->ddc1;
-
-	b->adapter = matrox_ddc1_adapter_template;
-	b->bac = matrox_ddc1b_algo_template;
-	sprintf(b->adapter.name, "DDC:fb%u #0 on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
-	return i2c_bus_reg(b, minfo2->primary_dev);
-}
-
 static inline void i2c_ddc1_done(struct matroxfb_dh_maven_info* minfo2) {
 	i2c_bit_bus_del(&minfo2->ddc1);
 }
 
-static inline int i2c_ddc2_init(struct matroxfb_dh_maven_info* minfo2) {
-	struct i2c_bit_adapter *b = &minfo2->ddc2;
-
-	b->adapter = matrox_ddc2_adapter_template;
-	b->bac = matrox_ddc2_algo_template;
-	sprintf(b->adapter.name, "DDC:fb%u #1 on i2c-matroxfb", GET_FB_IDX(minfo2->primary_dev->fbcon.node));
-	return i2c_bus_reg(b, minfo2->primary_dev);
-}
-
 static inline void i2c_ddc2_done(struct matroxfb_dh_maven_info* minfo2) {
 	i2c_bit_bus_del(&minfo2->ddc2);
 }
@@ -299,24 +164,26 @@
 	matroxfb_DAC_unlock_irqrestore(flags);
 
 	memset(m2info, 0, sizeof(*m2info));
-	m2info->maven.minfo = m2info;
-	m2info->ddc1.minfo = m2info;
-	m2info->ddc2.minfo = m2info;
-	m2info->primary_dev = minfo;
-
-	if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2064W ||
-	    ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2164W ||
-	    ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGA2164W_AGP)
-		err = i2c_ddc1b_init(m2info);
-	else
-		err = i2c_ddc1_init(m2info);
+
+	switch (ACCESS_FBINFO(chip)) {
+		case MGA_2064:
+		case MGA_2164:
+			err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1B_DATA, DDC1B_CLK, "DDC:fb%u #0 on i2c-matroxfb");
+			break;
+		default:
+			err = i2c_bus_reg(&m2info->ddc1, minfo, DDC1_DATA, DDC1_CLK, "DDC:fb%u #0 on i2c-matroxfb");
+			break;
+	}
 	if (err)
 		goto fail_ddc1;
-	if (ACCESS_FBINFO(devflags.maven_capable)) {
-		err = i2c_ddc2_init(m2info);
-		if (err)
+	if (ACCESS_FBINFO(devflags.dualhead)) {
+		err = i2c_bus_reg(&m2info->ddc2, minfo, DDC2_DATA, DDC2_CLK, "DDC:fb%u #1 on i2c-matroxfb");
+		if (err == -ENODEV) {
+			printk(KERN_INFO "i2c-matroxfb: VGA->TV plug detected, DDC unavailable.\n");
+		} else if (err)
 			printk(KERN_INFO "i2c-matroxfb: Could not register secondary output i2c bus. Continuing anyway.\n");
-		err = i2c_maven_init(m2info);
+		/* Register maven bus even on G450/G550 */
+		err = i2c_bus_reg(&m2info->maven, minfo, MAT_DATA, MAT_CLK, "MAVEN:fb%u on i2c-matroxfb");
 		if (err)
 			printk(KERN_INFO "i2c-matroxfb: Could not register Maven i2c bus. Continuing anyway.\n");
 	}
@@ -337,10 +204,10 @@
 }
 
 static struct matroxfb_driver i2c_matroxfb = {
-	LIST_HEAD_INIT(i2c_matroxfb.node),
-	"i2c-matroxfb",
-	i2c_matroxfb_probe,
-	i2c_matroxfb_remove,
+	.node =		LIST_HEAD_INIT(i2c_matroxfb.node),
+	.name =		"i2c-matroxfb",
+	.probe = 	i2c_matroxfb_probe,
+	.remove =	i2c_matroxfb_remove,
 };
 
 static int __init i2c_matroxfb_init(void) {
@@ -355,7 +222,7 @@
 	matroxfb_unregister_driver(&i2c_matroxfb);
 }
 
-MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
 MODULE_DESCRIPTION("Support module providing I2C buses present on Matrox videocards");
 
 module_init(i2c_matroxfb_init);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/matrox/Makefile linux.20pre10-ac2/drivers/video/matrox/Makefile
--- linux.20pre10/drivers/video/matrox/Makefile	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/matrox/Makefile	2002-09-02 02:28:49.000000000 +0100
@@ -7,7 +7,7 @@
 # All of the (potential) objects that export symbols.
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
 
-export-objs    :=  matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o g450_pll.o
+export-objs    :=  matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o g450_pll.o matroxfb_g450.o
 
 # Each configuration option enables a list of files.
 
@@ -15,8 +15,13 @@
 
 obj-$(CONFIG_FB_MATROX)           += matroxfb_base.o matroxfb_accel.o matroxfb_DAC1064.o matroxfb_Ti3026.o matroxfb_misc.o $(my-obj-y)
 obj-$(CONFIG_FB_MATROX_I2C)       += i2c-matroxfb.o
-obj-$(CONFIG_FB_MATROX_MAVEN)     += matroxfb_maven.o matroxfb_crtc2.o
-obj-$(CONFIG_FB_MATROX_G450)	  += matroxfb_g450.o matroxfb_crtc2.o
+ifeq ($(CONFIG_FB_MATROX_MAVEN),y)
+  obj-$(CONFIG_FB_MATROX)     += matroxfb_maven.o matroxfb_crtc2.o
+endif
+ifeq ($(CONFIG_FB_MATROX_G450),y)
+  obj-$(CONFIG_FB_MATROX)	  += matroxfb_g450.o matroxfb_crtc2.o
+endif
+obj-$(CONFIG_FB_MATROX_PROC)	  += matroxfb_proc.o
 
 include $(TOPDIR)/Rules.make
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/matrox/matroxfb_accel.c linux.20pre10-ac2/drivers/video/matrox/matroxfb_accel.c
--- linux.20pre10/drivers/video/matrox/matroxfb_accel.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/matrox/matroxfb_accel.c	2002-09-02 00:06:57.000000000 +0100
@@ -143,6 +143,8 @@
 	ACCESS_FBINFO(accel.m_opmode) = mopmode;
 }
 
+EXPORT_SYMBOL(matrox_cfbX_init);
+
 static void matrox_cfbX_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) {
 	int pixx = p->var.xres_virtual, start, end;
 	CRITFLAGS
@@ -943,7 +945,7 @@
 	CRITEND
 }
 
-void matrox_text_createcursor(WPMINFO struct display* p) {
+static void matrox_text_createcursor(WPMINFO struct display* p) {
 	CRITFLAGS
 
 	if (ACCESS_FBINFO(currcon_display) != p)
@@ -1029,6 +1031,8 @@
 	var->xres_virtual = vxres * hf;
 }
 
+EXPORT_SYMBOL(matrox_text_round);
+
 static int matrox_text_setfont(struct display* p, int width, int height) {
 	DBG("matrox_text_setfont");
 
@@ -1223,6 +1227,8 @@
 	}
 }
 
+EXPORT_SYMBOL(initMatrox);
+
 void matrox_init_putc(WPMINFO struct display* p, void (*dac_createcursor)(WPMINFO struct display* p)) {
 	int i;
 
@@ -1245,4 +1251,7 @@
 		ACCESS_FBINFO(curr.putcs) = matrox_cfbX_putcs;
 	}
 }
+
+EXPORT_SYMBOL(matrox_init_putc);
+
 MODULE_LICENSE("GPL");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/matrox/matroxfb_accel.h linux.20pre10-ac2/drivers/video/matrox/matroxfb_accel.h
--- linux.20pre10/drivers/video/matrox/matroxfb_accel.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/matrox/matroxfb_accel.h	2002-10-11 00:35:04.000000000 +0100
@@ -5,7 +5,6 @@
 
 void matrox_init_putc(WPMINFO struct display* p, void (*)(WPMINFO struct display *p));
 void matrox_cfbX_init(WPMINFO struct display* p);
-void matrox_text_createcursor(WPMINFO struct display* p);
 void matrox_text_round(CPMINFO struct fb_var_screeninfo* var, struct display* p);
 void initMatrox(WPMINFO struct display* p);
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/matrox/matroxfb_base.c linux.20pre10-ac2/drivers/video/matrox/matroxfb_base.c
--- linux.20pre10/drivers/video/matrox/matroxfb_base.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/matrox/matroxfb_base.c	2002-09-02 00:06:57.000000000 +0100
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.64 2002/06/10
  *
  * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
  *
@@ -77,6 +77,15 @@
  *               "Uns Lider" <unslider@miranda.org>
  *                     G100 PLNWT fixes
  *
+ *               "Denis Zaitsev" <zzz@cd-club.ru>
+ *                     Fixes
+ *
+ *               "Mike Pieper" <mike@pieper-family.de>
+ *                     TVOut enhandcements, V4L2 control interface.
+ *
+ *               "Diego Biurrun" <diego@biurrun.de>
+ *                     DFP testing
+ *
  * (following author is not in any relation with this code, but his code
  *  is included in this driver)
  *
@@ -100,6 +109,7 @@
 #include "matroxfb_Ti3026.h"
 #include "matroxfb_maven.h"
 #include "matroxfb_crtc2.h"
+#include "matroxfb_g450.h"
 #include <linux/matroxfb.h>
 #include <asm/uaccess.h>
 
@@ -199,6 +209,7 @@
 	}
 	matroxfb_unregister_device(MINFO);
 	unregister_framebuffer(&ACCESS_FBINFO(fbcon));
+	matroxfb_g450_shutdown(PMINFO2);
 	del_timer_sync(&ACCESS_FBINFO(cursor.timer));
 #ifdef CONFIG_MTRR
 	if (ACCESS_FBINFO(mtrr.vram_valid))
@@ -220,7 +231,7 @@
 
 static int matroxfb_open(struct fb_info *info, int user)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 	DBG_LOOP("matroxfb_open")
 
 	if (ACCESS_FBINFO(dead)) {
@@ -233,7 +244,7 @@
 
 static int matroxfb_release(struct fb_info *info, int user)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 	DBG_LOOP("matroxfb_release")
 
 	if (!(--ACCESS_FBINFO(usecount)) && ACCESS_FBINFO(dead)) {
@@ -245,7 +256,7 @@
 
 static int matroxfb_pan_display(struct fb_var_screeninfo *var, int con,
 		struct fb_info* info) {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 
 	DBG("matroxfb_pan_display")
 
@@ -271,7 +282,7 @@
 
 static int matroxfb_updatevar(int con, struct fb_info *info)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 	DBG("matroxfb_updatevar");
 
 	matrox_pan_var(PMINFO &fb_display[con].var);
@@ -391,12 +402,43 @@
 }
 
 static int matroxfb_decode_var(CPMINFO struct display* p, struct fb_var_screeninfo *var, int *visual, int *video_cmap_len, unsigned int* ydstorg) {
+	struct RGBT {
+		unsigned char bpp;
+		struct {
+			unsigned char offset,
+				      length;
+		} red,
+		  green,
+		  blue,
+		  transp;
+		signed char visual;
+	};
+	static const struct RGBT table[]= {
+#if defined FBCON_HAS_VGATEXT
+		{ 0,{ 0,6},{0,6},{0,6},{ 0,0},MX_VISUAL_PSEUDOCOLOR},
+#endif
+#if defined FBCON_HAS_CFB4 || defined FBCON_HAS_CFB8
+		{ 8,{ 0,8},{0,8},{0,8},{ 0,0},MX_VISUAL_PSEUDOCOLOR},
+#endif
+#if defined FBCON_HAS_CFB16
+		{15,{10,5},{5,5},{0,5},{15,1},MX_VISUAL_DIRECTCOLOR},
+		{16,{11,5},{5,6},{0,5},{ 0,0},MX_VISUAL_DIRECTCOLOR},
+#endif
+#if defined FBCON_HAS_CFB24
+		{24,{16,8},{8,8},{0,8},{ 0,0},MX_VISUAL_DIRECTCOLOR},
+#endif
+#if defined FBCON_HAS_CFB32
+		{32,{16,8},{8,8},{0,8},{24,8},MX_VISUAL_DIRECTCOLOR}
+#endif
+	};
+	struct RGBT const *rgbt;
+	unsigned int bpp = var->bits_per_pixel;
 	unsigned int vramlen;
 	unsigned int memlen;
 
 	DBG("matroxfb_decode_var")
 
-	switch (var->bits_per_pixel) {
+	switch (bpp) {
 #ifdef FBCON_HAS_VGATEXT
 		case 0:	 if (!ACCESS_FBINFO(capable.text)) return -EINVAL;
 			 break;
@@ -425,22 +467,22 @@
 		var->yres_virtual = var->yres;
 	if (var->xres_virtual < var->xres)
 		var->xres_virtual = var->xres;
-	if (var->bits_per_pixel) {
-		var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, var->bits_per_pixel);
-		memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+	if (bpp) {
+		var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, bpp);
+		memlen = var->xres_virtual * bpp * var->yres_virtual / 8;
 		if (memlen > vramlen) {
-			var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel);
-			memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
+			var->yres_virtual = vramlen * 8 / (var->xres_virtual * bpp);
+			memlen = var->xres_virtual * bpp * var->yres_virtual / 8;
 		}
 		/* There is hardware bug that no line can cross 4MB boundary */
 		/* give up for CFB24, it is impossible to easy workaround it */
 		/* for other try to do something */
 		if (!ACCESS_FBINFO(capable.cross4MB) && (memlen > 0x400000)) {
-			if (var->bits_per_pixel == 24) {
+			if (bpp == 24) {
 				/* sorry */
 			} else {
 				unsigned int linelen;
-				unsigned int m1 = linelen = var->xres_virtual * var->bits_per_pixel / 8;
+				unsigned int m1 = linelen = var->xres_virtual * bpp / 8;
 				unsigned int m2 = PAGE_SIZE;	/* or 128 if you do not need PAGE ALIGNED address */
 				unsigned int max_yres;
 
@@ -484,104 +526,43 @@
 	if (var->yoffset + var->yres > var->yres_virtual)
 		var->yoffset = var->yres_virtual - var->yres;
 
-	if (var->bits_per_pixel == 0) {
-		var->red.offset = 0;
-		var->red.length = 6;
-		var->green.offset = 0;
-		var->green.length = 6;
-		var->blue.offset = 0;
-		var->blue.length = 6;
-		var->transp.offset = 0;
-		var->transp.length = 0;
-		*visual = MX_VISUAL_PSEUDOCOLOR;
-	} else if (var->bits_per_pixel == 4) {
-		var->red.offset = 0;
-		var->red.length = 8;
-		var->green.offset = 0;
-		var->green.length = 8;
-		var->blue.offset = 0;
-		var->blue.length = 8;
-		var->transp.offset = 0;
-		var->transp.length = 0;
-		*visual = MX_VISUAL_PSEUDOCOLOR;
-	} else if (var->bits_per_pixel <= 8) {
-		var->red.offset = 0;
-		var->red.length = 8;
-		var->green.offset = 0;
-		var->green.length = 8;
-		var->blue.offset = 0;
-		var->blue.length = 8;
-		var->transp.offset = 0;
-		var->transp.length = 0;
-		*visual = MX_VISUAL_PSEUDOCOLOR;
-	} else {
-		if (var->bits_per_pixel <= 16) {
-			if (var->green.length == 5) {
-				var->red.offset    = 10;
-				var->red.length    = 5;
-				var->green.offset  = 5;
-				var->green.length  = 5;
-				var->blue.offset   = 0;
-				var->blue.length   = 5;
-				var->transp.offset = 15;
-				var->transp.length = 1;
-			} else {
-				var->red.offset    = 11;
-				var->red.length    = 5;
-				var->green.offset  = 5;
-				var->green.length  = 6;
-				var->blue.offset   = 0;
-				var->blue.length   = 5;
-				var->transp.offset = 0;
-				var->transp.length = 0;
-			}
-		} else if (var->bits_per_pixel <= 24) {
-			var->red.offset    = 16;
-			var->red.length    = 8;
-			var->green.offset  = 8;
-			var->green.length  = 8;
-			var->blue.offset   = 0;
-			var->blue.length   = 8;
-			var->transp.offset = 0;
-			var->transp.length = 0;
-		} else {
-			var->red.offset    = 16;
-			var->red.length    = 8;
-			var->green.offset  = 8;
-			var->green.length  = 8;
-			var->blue.offset   = 0;
-			var->blue.length   = 8;
-			var->transp.offset = 24;
-			var->transp.length = 8;
-		}
-		dprintk("matroxfb: truecolor: "
-		       "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
-		       var->transp.length,
-		       var->red.length,
-		       var->green.length,
-		       var->blue.length,
-		       var->transp.offset,
-		       var->red.offset,
-		       var->green.offset,
-		       var->blue.offset);
-		*visual = MX_VISUAL_DIRECTCOLOR;
+	if (bpp == 16 && var->green.length == 5) {
+		bpp--; /* an artifical value - 15 */
 	}
+
+	for (rgbt = table; rgbt->bpp < bpp; rgbt++);
+#define	SETCLR(clr)\
+	var->clr.offset = rgbt->clr.offset;\
+	var->clr.length = rgbt->clr.length
+	SETCLR(red);
+	SETCLR(green);
+	SETCLR(blue);
+	SETCLR(transp);
+#undef	SETCLR
+	*visual = rgbt->visual;
+
+	if (bpp > 8)
+		dprintk("matroxfb: truecolor: "
+			"size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+			var->transp.length, var->red.length, var->green.length, var->blue.length,
+			var->transp.offset, var->red.offset, var->green.offset, var->blue.offset);
+
 	*video_cmap_len = matroxfb_get_cmap_len(var);
 	dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel,
 				var->xres_virtual, var->yres_virtual);
 	return 0;
 }
 
-static int matrox_setcolreg(unsigned regno, unsigned red, unsigned green,
-			    unsigned blue, unsigned transp,
-			    struct fb_info *fb_info)
+static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			      unsigned blue, unsigned transp,
+			      struct fb_info *fb_info)
 {
 	struct display* p;
 #ifdef CONFIG_FB_MATROX_MULTIHEAD
-	struct matrox_fb_info* minfo = (struct matrox_fb_info*)fb_info;
+	struct matrox_fb_info* minfo = list_entry(fb_info, struct matrox_fb_info, fbcon);
 #endif
 
-	DBG("matrox_setcolreg")
+	DBG("matroxfb_setcolreg")
 
 	/*
 	 *  Set a single color register. The values supplied are
@@ -656,15 +637,17 @@
 	return 0;
 }
 
-static void do_install_cmap(WPMINFO struct display* dsp)
+static inline void my_install_cmap(WPMINFO2)
 {
-	DBG("do_install_cmap")
+	/* Do not touch this code if you do not understand what it does! */
+	/* Never try to use do_install_cmap() instead. It is crap. */
+	struct fb_cmap* cmap = &ACCESS_FBINFO(currcon_display)->cmap;
 
-	if (dsp->cmap.len)
-		fb_set_cmap(&dsp->cmap, 1, matrox_setcolreg, &ACCESS_FBINFO(fbcon));
+	if (cmap->len)
+		fb_set_cmap(cmap, 1, matroxfb_setcolreg, &ACCESS_FBINFO(fbcon));
 	else
 		fb_set_cmap(fb_default_cmap(ACCESS_FBINFO(curr.cmap_len)),
-			    1, matrox_setcolreg, &ACCESS_FBINFO(fbcon));
+			    1, matroxfb_setcolreg, &ACCESS_FBINFO(fbcon));
 }
 
 static int matroxfb_get_fix(struct fb_fix_screeninfo *fix, int con,
@@ -673,7 +656,7 @@
 	struct display* p;
 	DBG("matroxfb_get_fix")
 
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 
 	if (ACCESS_FBINFO(dead)) {
 		return -ENXIO;
@@ -684,7 +667,7 @@
 	else
 		p = ACCESS_FBINFO(fbcon.disp);
 
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	memset(fix, 0, sizeof(*fix));
 	strcpy(fix->id,"MATROX");
 
 	fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes);
@@ -706,7 +689,7 @@
 static int matroxfb_get_var(struct fb_var_screeninfo *var, int con,
 			 struct fb_info *info)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 	DBG("matroxfb_get_var")
 
 	if(con < 0)
@@ -720,7 +703,7 @@
 static int matroxfb_set_var(struct fb_var_screeninfo *var, int con,
 			 struct fb_info *info)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 	int err;
 	int visual;
 	int cmap_len;
@@ -760,7 +743,7 @@
 	}
 	display->var = *var;
 	/* cmap */
-	display->screen_base = vaddr_va(ACCESS_FBINFO(video.vbase)) + ydstorg;
+	display->screen_base = ACCESS_FBINFO(fbcon.screen_base) = vaddr_va(ACCESS_FBINFO(video.vbase)) + ydstorg;
 	display->visual = visual;
 	display->ypanstep = 1;
 	display->ywrapstep = 0;
@@ -816,8 +799,10 @@
 
 		{	struct my_timming mt;
 			struct matrox_hw_state* hw;
+			int out;
 
 			matroxfb_var2my(var, &mt);
+			mt.crtc = MATROXFB_SRC_CRTC1;
 			/* CRTC1 delays */
 			switch (var->bits_per_pixel) {
 				case  0:	mt.delay = 31 + 0; break;
@@ -832,6 +817,16 @@
 			del_timer_sync(&ACCESS_FBINFO(cursor.timer));
 			ACCESS_FBINFO(cursor.state) = CM_ERASE;
 
+			down_read(&ACCESS_FBINFO(altout).lock);
+			for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+				if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
+				    ACCESS_FBINFO(outputs[out]).output->compute) {
+					ACCESS_FBINFO(outputs[out]).output->compute(ACCESS_FBINFO(outputs[out]).data, &mt);
+				}
+			}
+			up_read(&ACCESS_FBINFO(altout).lock);
+			ACCESS_FBINFO(crtc1).pixclock = mt.pixclock;
+			ACCESS_FBINFO(crtc1).mnp = mt.mnp;
 			ACCESS_FBINFO(hw_switch->init(PMINFO &mt, display));
 			if (display->type == FB_TYPE_TEXT) {
 				if (fontheight(display))
@@ -847,40 +842,25 @@
 			hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
 			hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
 			hw->CRTCEXT[8] = pos >> 21;
-			if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) {
-				if (ACCESS_FBINFO(primout))
-					ACCESS_FBINFO(primout)->compute(MINFO, &mt);
-			}
-			if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-				down_read(&ACCESS_FBINFO(altout.lock));
-				if (ACCESS_FBINFO(altout.output))
-					ACCESS_FBINFO(altout.output)->compute(ACCESS_FBINFO(altout.device), &mt);
-				up_read(&ACCESS_FBINFO(altout.lock));
-			}
+		
 			ACCESS_FBINFO(hw_switch->restore(PMINFO display));
-			if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) {
-				if (ACCESS_FBINFO(primout))
-					ACCESS_FBINFO(primout)->program(MINFO);
-			}
-			if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-				down_read(&ACCESS_FBINFO(altout.lock));
-				if (ACCESS_FBINFO(altout.output))
-					ACCESS_FBINFO(altout.output)->program(ACCESS_FBINFO(altout.device));
-				up_read(&ACCESS_FBINFO(altout.lock));
+			down_read(&ACCESS_FBINFO(altout).lock);
+			for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+				if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
+				    ACCESS_FBINFO(outputs[out]).output->program) {
+					ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data);
+				}
 			}
 			ACCESS_FBINFO(cursor.redraw) = 1;
-			if (ACCESS_FBINFO(output.ph) & (MATROXFB_OUTPUT_CONN_PRIMARY | MATROXFB_OUTPUT_CONN_DFP)) {
-				if (ACCESS_FBINFO(primout))
-					ACCESS_FBINFO(primout)->start(MINFO);
-			}
-			if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-				down_read(&ACCESS_FBINFO(altout.lock));
-				if (ACCESS_FBINFO(altout.output))
-					ACCESS_FBINFO(altout.output)->start(ACCESS_FBINFO(altout.device));
-				up_read(&ACCESS_FBINFO(altout.lock));
+			for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+				if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 &&
+				    ACCESS_FBINFO(outputs[out]).output->start) {
+					ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data);
+				}
 			}
+			up_read(&ACCESS_FBINFO(altout).lock);
 			matrox_cfbX_init(PMINFO display);
-			do_install_cmap(PMINFO display);
+			my_install_cmap(PMINFO2);
 #if defined(CONFIG_FB_COMPAT_XPMAC)
 			if (console_fb_info == &ACCESS_FBINFO(fbcon)) {
 				int vmode, cmode;
@@ -913,7 +893,7 @@
 
 	DBG("matrox_getcolreg")
 
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 	/*
 	 *  Read a single color register and split it into colors/transparent.
 	 *  Return != 0 for invalid regno.
@@ -933,7 +913,7 @@
 static int matroxfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
 			     struct fb_info *info)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 	struct display* dsp = (con < 0) ? ACCESS_FBINFO(fbcon.disp)
 					: fb_display + con;
 
@@ -959,7 +939,7 @@
 {
 	unsigned int cmap_len;
 	struct display* dsp = (con < 0) ? info->disp : (fb_display + con);
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 
 	DBG("matroxfb_set_cmap")
 
@@ -976,7 +956,7 @@
 			return err;
 	}
 	if (con == ACCESS_FBINFO(currcon)) {			/* current console? */
-		return fb_set_cmap(cmap, kspc, matrox_setcolreg, info);
+		return fb_set_cmap(cmap, kspc, matroxfb_setcolreg, info);
 	} else
 		fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1);
 	return 0;
@@ -1006,11 +986,16 @@
 	return 0;
 }
 
+static struct matrox_altout panellink_output = {
+	.owner   = THIS_MODULE,
+	.name	 = "Panellink output",
+};
+
 static int matroxfb_ioctl(struct inode *inode, struct file *file,
 			  unsigned int cmd, unsigned long arg, int con,
 			  struct fb_info *info)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 	DBG("matroxfb_ioctl")
 
 	if (ACCESS_FBINFO(dead)) {
@@ -1033,80 +1018,74 @@
 		case MATROXFB_SET_OUTPUT_MODE:
 			{
 				struct matroxioc_output_mode mom;
+				struct matrox_altout *oproc;
 				int val;
 
 				if (copy_from_user(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom)))
 					return -EFAULT;
-				if (mom.output >= sizeof(u_int32_t))
-					return -EINVAL;
-				switch (mom.output) {
-					case MATROXFB_OUTPUT_PRIMARY:
-						if (mom.mode != MATROXFB_OUTPUT_MODE_MONITOR)
-							return -EINVAL;
-						/* mode did not change... */
-						return 0;
-					case MATROXFB_OUTPUT_SECONDARY:
+				if (mom.output >= MATROXFB_MAX_OUTPUTS)
+					return -ENXIO;
+				down_read(&ACCESS_FBINFO(altout.lock));
+				oproc = ACCESS_FBINFO(outputs[mom.output]).output;
+				if (!oproc) {
+					val = -ENXIO;
+				} else if (!oproc->verifymode) {
+					if (mom.mode == MATROXFB_OUTPUT_MODE_MONITOR) {
+						val = 0;
+					} else {
 						val = -EINVAL;
-						down_read(&ACCESS_FBINFO(altout.lock));
-						if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.device))
-							val = ACCESS_FBINFO(altout.output)->setmode(ACCESS_FBINFO(altout.device), mom.mode);
-						up_read(&ACCESS_FBINFO(altout.lock));
-						if (val != 1)
-							return val;
-						if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY)
-							matroxfb_switch(ACCESS_FBINFO(currcon), info);
-						if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
+					}
+				} else {
+					val = oproc->verifymode(ACCESS_FBINFO(outputs[mom.output]).data, mom.mode);
+				}
+				if (!val) {
+					if (ACCESS_FBINFO(outputs[mom.output]).mode != mom.mode) {
+						ACCESS_FBINFO(outputs[mom.output]).mode = mom.mode;
+						val = 1;
+					}
+				}
+				up_read(&ACCESS_FBINFO(altout.lock));
+				if (val != 1)
+					return val;
+				switch (ACCESS_FBINFO(outputs[mom.output]).src) {
+					case MATROXFB_SRC_CRTC1:
+						matroxfb_switch(ACCESS_FBINFO(currcon), info);
+						break;
+					case MATROXFB_SRC_CRTC2:
+						{
 							struct matroxfb_dh_fb_info* crtc2;
 
 							down_read(&ACCESS_FBINFO(crtc2.lock));
-							crtc2 = (struct matroxfb_dh_fb_info*)(ACCESS_FBINFO(crtc2.info));
+							crtc2 = ACCESS_FBINFO(crtc2.info);
 							if (crtc2)
 								crtc2->fbcon.switch_con(crtc2->currcon, &crtc2->fbcon);
 							up_read(&ACCESS_FBINFO(crtc2.lock));
 						}
-						return 0;
-					case MATROXFB_OUTPUT_DFP:
-						if (!(ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_DFP))
-							return -ENXIO;
-						if (mom.mode!= MATROXFB_OUTPUT_MODE_MONITOR)
-							return -EINVAL;
-						/* mode did not change... */
-						return 0;
-					default:
-						return -EINVAL;
+						break;
 				}
 				return 0;
 			}
 		case MATROXFB_GET_OUTPUT_MODE:
 			{
 				struct matroxioc_output_mode mom;
+				struct matrox_altout *oproc;
 				int val;
 
 				if (copy_from_user(&mom, (struct matroxioc_output_mode*)arg, sizeof(mom)))
 					return -EFAULT;
-				if (mom.output >= sizeof(u_int32_t))
-					return -EINVAL;
-				switch (mom.output) {
-					case MATROXFB_OUTPUT_PRIMARY:
-						mom.mode = MATROXFB_OUTPUT_MODE_MONITOR;
-						break;
-					case MATROXFB_OUTPUT_SECONDARY:
-						val = -EINVAL;
-						down_read(&ACCESS_FBINFO(altout.lock));
-						if (ACCESS_FBINFO(altout.output) && ACCESS_FBINFO(altout.device))
-							val = ACCESS_FBINFO(altout.output)->getmode(ACCESS_FBINFO(altout.device), &mom.mode);
-						up_read(&ACCESS_FBINFO(altout.lock));
-						if (val)
-							return val;
-						break;
-					case MATROXFB_OUTPUT_DFP:
-						if (!(ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_DFP))
-							return -ENXIO;
-						mom.mode = MATROXFB_OUTPUT_MODE_MONITOR;
-						break;
-					default:
-						return -EINVAL;
+				if (mom.output >= MATROXFB_MAX_OUTPUTS)
+					return -ENXIO;
+				down_read(&ACCESS_FBINFO(altout.lock));
+				oproc = ACCESS_FBINFO(outputs[mom.output]).output;
+				if (!oproc) {
+					val = -ENXIO;
+				} else {
+					mom.mode = ACCESS_FBINFO(outputs[mom.output]).mode;
+					val = 0;
 				}
+				up_read(&ACCESS_FBINFO(altout.lock));
+				if (val)
+					return val;
 				if (copy_to_user((struct matroxioc_output_mode*)arg, &mom, sizeof(mom)))
 					return -EFAULT;
 				return 0;
@@ -1114,55 +1093,248 @@
 		case MATROXFB_SET_OUTPUT_CONNECTION:
 			{
 				u_int32_t tmp;
+				int i;
+				int changes;
 
 				if (copy_from_user(&tmp, (u_int32_t*)arg, sizeof(tmp)))
 					return -EFAULT;
-				if (tmp & ~ACCESS_FBINFO(output.all))
-					return -EINVAL;
-				if (tmp & ACCESS_FBINFO(output.sh))
-					return -EINVAL;
-				if (tmp & MATROXFB_OUTPUT_CONN_DFP) {
-					if (tmp & MATROXFB_OUTPUT_CONN_SECONDARY)
-						return -EINVAL;
-					if (ACCESS_FBINFO(output.sh))
-						return -EINVAL;
+				for (i = 0; i < 32; i++) {
+					if (tmp & (1 << i)) {
+						if (i >= MATROXFB_MAX_OUTPUTS)
+							return -ENXIO;
+						if (!ACCESS_FBINFO(outputs[i]).output)
+							return -ENXIO;
+						switch (ACCESS_FBINFO(outputs[i]).src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC1:
+								break;
+							default:
+								return -EBUSY;
+						}
+					}
 				}
-				if (tmp == ACCESS_FBINFO(output.ph))
+				if (ACCESS_FBINFO(devflags.panellink)) {
+					if (tmp & MATROXFB_OUTPUT_CONN_DFP) {
+						if (tmp & MATROXFB_OUTPUT_CONN_SECONDARY)
+							return -EINVAL;
+						for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+							if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC2) {
+								return -EBUSY;
+							}
+						}
+					}
+				}
+				changes = 0;
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (tmp & (1 << i)) {
+						if (ACCESS_FBINFO(outputs[i]).src != MATROXFB_SRC_CRTC1) {
+							changes = 1;
+							ACCESS_FBINFO(outputs[i]).src = MATROXFB_SRC_CRTC1;
+						}
+					} else if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC1) {
+						changes = 1;
+						ACCESS_FBINFO(outputs[i]).src = MATROXFB_SRC_NONE;
+					}
+				}
+				if (!changes)
 					return 0;
-				ACCESS_FBINFO(output.ph) = tmp;
 				matroxfb_switch(ACCESS_FBINFO(currcon), info);
 				return 0;
 			}
 		case MATROXFB_GET_OUTPUT_CONNECTION:
 			{
-				if (put_user(ACCESS_FBINFO(output.ph), (u_int32_t*)arg))
+				u_int32_t conn = 0;
+				int i;
+
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (ACCESS_FBINFO(outputs[i]).src == MATROXFB_SRC_CRTC1) {
+						conn |= 1 << i;
+					}
+				}
+				if (put_user(conn, (u_int32_t*)arg))
 					return -EFAULT;
 				return 0;
 			}
 		case MATROXFB_GET_AVAILABLE_OUTPUTS:
 			{
-				u_int32_t tmp;
+				u_int32_t conn = 0;
+				int i;
 
-				tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.sh);
-				if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)
-					tmp &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-				if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY)
-					tmp &= ~MATROXFB_OUTPUT_CONN_DFP;
-				if (put_user(tmp, (u_int32_t*)arg))
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (ACCESS_FBINFO(outputs[i]).output) {
+						switch (ACCESS_FBINFO(outputs[i]).src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC1:
+								conn |= 1 << i;
+								break;
+						}
+					}
+				}
+				if (ACCESS_FBINFO(devflags.panellink)) {
+					if (conn & MATROXFB_OUTPUT_CONN_DFP)
+						conn &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
+					if (conn & MATROXFB_OUTPUT_CONN_SECONDARY)
+						conn &= ~MATROXFB_OUTPUT_CONN_DFP;
+				}
+				if (put_user(conn, (u_int32_t*)arg))
 					return -EFAULT;
 				return 0;
 			}
 		case MATROXFB_GET_ALL_OUTPUTS:
 			{
-				if (put_user(ACCESS_FBINFO(output.all), (u_int32_t*)arg))
+				u_int32_t conn = 0;
+				int i;
+
+				for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
+					if (ACCESS_FBINFO(outputs[i]).output) {
+						conn |= 1 << i;
+					}
+				}
+				if (put_user(conn, (u_int32_t*)arg))
+					return -EFAULT;
+				return 0;
+			}
+		case 0x80585600:
+			{
+				struct {
+					char name[32];
+					int type;
+					int inputs;
+					int outputs;
+					int audios;
+					int maxwidth;
+					int maxheight;
+					int minwidth;
+					int minheight;
+					int maxframerate;
+					__u32 flags;
+					__u32 reserved[4];
+				} r;
+				
+				memset(&r, 0, sizeof(r));
+				strcat(r.name, "Matrox TVO");
+				r.type = 2; // output
+				r.inputs = 0;
+				r.outputs = 1;
+				r.audios = 0;
+				r.maxwidth = 1023;	// max visible width
+				r.maxheight = 625;	// max picture height: full PAL
+				r.minwidth = 512;	// min visible width... ~480
+				r.minheight = 480;	// min picture height: visible portion of NTSC
+				r.maxframerate = 60;	// max: NTSC, 60Hz interlaced
+				r.flags = 0;		// nothing is supported...
+				if (copy_to_user((void*)arg, &r, sizeof(r)))
 					return -EFAULT;
 				return 0;
+				
+			}
+		case MATROXFB_TVOQUERYCTRL:
+			{
+				struct matroxfb_queryctrl qctrl;
+				int err;
+
+				if (copy_from_user(&qctrl, (struct matroxfb_queryctrl*)arg, sizeof(qctrl)))
+					return -EFAULT;
+
+				down_read(&ACCESS_FBINFO(altout).lock);
+				if (!ACCESS_FBINFO(outputs[1]).output) {
+					err = -ENXIO;
+				} else if (ACCESS_FBINFO(outputs[1]).output->getqueryctrl) {
+					err = ACCESS_FBINFO(outputs[1]).output->getqueryctrl(ACCESS_FBINFO(outputs[1]).data, &qctrl);
+				} else {
+					err = -EINVAL;
+				}
+				up_read(&ACCESS_FBINFO(altout).lock);
+				if (err >= 0 &&
+				    copy_to_user((struct matroxfb_queryctrl*)arg, &qctrl, sizeof(qctrl)))
+					return -EFAULT;
+				return err;
+			}
+		case MATROXFB_G_TVOCTRL:
+			{
+				struct matroxfb_control ctrl;
+				int err;
+
+				if (copy_from_user(&ctrl, (struct matroxfb_control*)arg, sizeof(ctrl)))
+					return -EFAULT;
+
+				down_read(&ACCESS_FBINFO(altout).lock);
+				if (!ACCESS_FBINFO(outputs[1]).output) {
+					err = -ENXIO;
+				} else if (ACCESS_FBINFO(outputs[1]).output->getctrl) {
+					err = ACCESS_FBINFO(outputs[1]).output->getctrl(ACCESS_FBINFO(outputs[1]).data, &ctrl);
+				} else {
+					err = -EINVAL;
+				}
+				up_read(&ACCESS_FBINFO(altout).lock);
+				if (err >= 0 &&
+				    copy_to_user((struct matroxfb_control*)arg, &ctrl, sizeof(ctrl)))
+					return -EFAULT;
+				return err;
+			}
+		case MATROXFB_S_TVOCTRL:
+			{
+				struct matroxfb_control ctrl;
+				int err;
+
+				if (copy_from_user(&ctrl, (struct matroxfb_control*)arg, sizeof(ctrl)))
+					return -EFAULT;
+
+				down_read(&ACCESS_FBINFO(altout).lock);
+				if (!ACCESS_FBINFO(outputs[1]).output) {
+					err = -ENXIO;
+				} else if (ACCESS_FBINFO(outputs[1]).output->setctrl) {
+					err = ACCESS_FBINFO(outputs[1]).output->setctrl(ACCESS_FBINFO(outputs[1]).data, &ctrl);
+				} else {
+					err = -EINVAL;
+				}
+				up_read(&ACCESS_FBINFO(altout).lock);
+				return err;
 			}
 	}
-	return -EINVAL;
+	return -ENOTTY;
 #undef minfo
 }
 
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+
+static int matroxfb_blank(int blank, struct fb_info *info)
+{
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
+	int seq;
+	int crtc;
+	CRITFLAGS
+
+	DBG("matroxfb_blank")
+
+	if (ACCESS_FBINFO(dead))
+		return 1;
+
+	switch (blank) {
+		case 1:  seq = 0x20; crtc = 0x00; break; /* works ??? */
+		case 2:  seq = 0x20; crtc = 0x10; break;
+		case 3:  seq = 0x20; crtc = 0x20; break;
+		case 4:  seq = 0x20; crtc = 0x30; break;
+		default: seq = 0x00; crtc = 0x00; break;
+	}
+
+	CRITBEGIN
+
+	mga_outb(M_SEQ_INDEX, 1);
+	mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq);
+	mga_outb(M_EXTVGA_INDEX, 1);
+	mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc);
+
+	CRITEND
+	return 0;
+#undef minfo
+}
+
+static void matroxfb_blank24(int blank, struct fb_info *info)
+{
+	matroxfb_blank(blank, info);
+}
+
 static struct fb_ops matroxfb_ops = {
 	owner:		THIS_MODULE,
 	fb_open:	matroxfb_open,
@@ -1178,7 +1350,7 @@
 
 int matroxfb_switch(int con, struct fb_info *info)
 {
-#define minfo ((struct matrox_fb_info*)info)
+#define minfo (list_entry(info, struct matrox_fb_info, fbcon))
 	struct fb_cmap* cmap;
 	struct display *p;
 
@@ -1226,40 +1398,6 @@
 #undef minfo
 }
 
-/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
-
-static void matroxfb_blank(int blank, struct fb_info *info)
-{
-#define minfo ((struct matrox_fb_info*)info)
-	int seq;
-	int crtc;
-	CRITFLAGS
-
-	DBG("matroxfb_blank")
-
-	if (ACCESS_FBINFO(dead))
-		return;
-
-	switch (blank) {
-		case 1:  seq = 0x20; crtc = 0x00; break; /* works ??? */
-		case 2:  seq = 0x20; crtc = 0x10; break;
-		case 3:  seq = 0x20; crtc = 0x20; break;
-		case 4:  seq = 0x20; crtc = 0x30; break;
-		default: seq = 0x00; crtc = 0x00; break;
-	}
-
-	CRITBEGIN
-
-	mga_outb(M_SEQ_INDEX, 1);
-	mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq);
-	mga_outb(M_EXTVGA_INDEX, 1);
-	mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc);
-
-	CRITEND
-
-#undef minfo
-}
-
 #define RSDepth(X)	(((X) >> 8) & 0x0F)
 #define RS8bpp		0x1
 #define RS15bpp		0x2
@@ -1407,10 +1545,10 @@
 #define DEVF_VIDEO64BIT		0x0001
 #define	DEVF_SWAPS		0x0002
 #define DEVF_SRCORG		0x0004
-#define DEVF_BOTHDACS		0x0008	/* put CRTC1 on both outputs by default */
+#define DEVF_DUALHEAD		0x0008
 #define DEVF_CROSS4MB		0x0010
 #define DEVF_TEXT4B		0x0020
-#define DEVF_DDC_8_2		0x0040
+/* #define DEVF_recycled	0x0040	*/
 /* #define DEVF_recycled	0x0080	*/
 #define DEVF_SUPPORT32MB	0x0100
 #define DEVF_ANY_VXRES		0x0200
@@ -1420,14 +1558,14 @@
 #define DEVF_PANELLINK_CAPABLE	0x2000
 #define DEVF_G450DAC		0x4000
 
-#define DEVF_GCORE	(DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB | DEVF_DDC_8_2)
-#define DEVF_G2CORE	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE | DEVF_SRCORG)
+#define DEVF_GCORE	(DEVF_VIDEO64BIT | DEVF_SWAPS | DEVF_CROSS4MB)
+#define DEVF_G2CORE	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_MAVEN_CAPABLE | DEVF_PANELLINK_CAPABLE | DEVF_SRCORG | DEVF_DUALHEAD)
 #define DEVF_G100	(DEVF_GCORE) /* no doc, no vxres... */
 #define DEVF_G200	(DEVF_G2CORE)
 #define DEVF_G400	(DEVF_G2CORE | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2)
 /* if you'll find how to drive DFP... */
-#define DEVF_G450	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG)
-#define DEVF_G550	(DEVF_G450 | DEVF_BOTHDACS)
+#define DEVF_G450	(DEVF_GCORE | DEVF_ANY_VXRES | DEVF_SUPPORT32MB | DEVF_TEXT16B | DEVF_CRTC2 | DEVF_G450DAC | DEVF_SRCORG | DEVF_DUALHEAD)
+#define DEVF_G550	(DEVF_G450)
 
 static struct board {
 	unsigned short vendor, device, rev, svid, sid;
@@ -1621,27 +1759,24 @@
 		ACCESS_FBINFO(devflags.text_type_aux) = FB_AUX_TEXT_MGA_STEP8;
 	}
 #ifdef CONFIG_FB_MATROX_32MB
-	ACCESS_FBINFO(devflags.support32MB) = b->flags & DEVF_SUPPORT32MB;
+	ACCESS_FBINFO(devflags.support32MB) = (b->flags & DEVF_SUPPORT32MB) != 0;
 #endif
 	ACCESS_FBINFO(devflags.precise_width) = !(b->flags & DEVF_ANY_VXRES);
-	ACCESS_FBINFO(devflags.crtc2) = b->flags & DEVF_CRTC2;
-	ACCESS_FBINFO(devflags.maven_capable) = b->flags & DEVF_MAVEN_CAPABLE;
+	ACCESS_FBINFO(devflags.crtc2) = (b->flags & DEVF_CRTC2) != 0;
+	ACCESS_FBINFO(devflags.maven_capable) = (b->flags & DEVF_MAVEN_CAPABLE) != 0;
+	ACCESS_FBINFO(devflags.dualhead) = (b->flags & DEVF_DUALHEAD) != 0;
 	if (b->flags & DEVF_PANELLINK_CAPABLE) {
-		ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_DFP;
+		ACCESS_FBINFO(outputs[2]).data = MINFO;
+		ACCESS_FBINFO(outputs[2]).output = &panellink_output;
 		if (dfp)
-			ACCESS_FBINFO(output.ph) |= MATROXFB_OUTPUT_CONN_DFP;
-	}
-	if (b->flags & DEVF_BOTHDACS) {
-#ifdef CONFIG_FB_MATROX_G450	
-		ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY;
-		ACCESS_FBINFO(output.ph) |= MATROXFB_OUTPUT_CONN_SECONDARY;
-#else
-		printk(KERN_INFO "Only digital output of G550 is now working (in analog mode). Enable G450 support in\n");
-		printk(KERN_INFO "kernel configuration if you have analog monitor connected to G550 analog output.\n");
-#endif
+			ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_CRTC1;
+		else
+			ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_NONE;
+		ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		ACCESS_FBINFO(devflags.panellink) = 1;
 	}
 	ACCESS_FBINFO(devflags.dfp_type) = dfp_type;
-	ACCESS_FBINFO(devflags.g450dac) = b->flags & DEVF_G450DAC;
+	ACCESS_FBINFO(devflags.g450dac) = (b->flags & DEVF_G450DAC) != 0;
 	ACCESS_FBINFO(devflags.textstep) = ACCESS_FBINFO(devflags.vgastep) * ACCESS_FBINFO(devflags.textmode);
 	ACCESS_FBINFO(devflags.textvram) = 65536 / ACCESS_FBINFO(devflags.textmode);
 
@@ -1747,6 +1882,7 @@
 
 	if (!ACCESS_FBINFO(devflags.novga))
 		request_region(0x3C0, 32, "matrox");
+	matroxfb_g450_connect(PMINFO2);
 	ACCESS_FBINFO(hw_switch->reset(PMINFO2));
 
 	ACCESS_FBINFO(fbcon.monspecs.hfmin) = 0;
@@ -1775,7 +1911,7 @@
 	ACCESS_FBINFO(fbcon.disp) = d;
 	ACCESS_FBINFO(fbcon.switch_con) = &matroxfb_switch;
 	ACCESS_FBINFO(fbcon.updatevar) = &matroxfb_updatevar;
-	ACCESS_FBINFO(fbcon.blank) = &matroxfb_blank;
+	ACCESS_FBINFO(fbcon.blank) = &matroxfb_blank24;
 	/* after __init time we are like module... no logo */
 	ACCESS_FBINFO(fbcon.flags) = hotplug ? FBINFO_FLAG_MODULE : FBINFO_FLAG_DEFAULT;
 	ACCESS_FBINFO(video.len_usable) &= PAGE_MASK;
@@ -1907,6 +2043,7 @@
 	}
 	return 0;
 failVideoIO:;
+	matroxfb_g450_shutdown(PMINFO2);
 	mga_iounmap(ACCESS_FBINFO(video.vbase));
 failCtrlIO:;
 	mga_iounmap(ACCESS_FBINFO(mmio.vbase));
@@ -2094,10 +2231,6 @@
 	init_rwsem(&ACCESS_FBINFO(crtc2.lock));
 	init_rwsem(&ACCESS_FBINFO(altout.lock));
 
-	ACCESS_FBINFO(output.all) = MATROXFB_OUTPUT_CONN_PRIMARY;
-	ACCESS_FBINFO(output.ph) = MATROXFB_OUTPUT_CONN_PRIMARY;
-	ACCESS_FBINFO(output.sh) = 0;
-
 	err = initMatrox2(PMINFO d, b);
 	if (!err) {
 #ifndef CONFIG_FB_MATROX_MULTIHEAD
@@ -2511,8 +2644,8 @@
 
 /* *************************** init module code **************************** */
 
-MODULE_AUTHOR("(c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
-MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400/G450");
+MODULE_AUTHOR("(c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Accelerated FBDev driver for Matrox Millennium/Mystique/G100/G200/G400/G450/G550");
 MODULE_LICENSE("GPL");
 
 MODULE_PARM(mem, "i");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/matrox/matroxfb_base.h linux.20pre10-ac2/drivers/video/matrox/matroxfb_base.h
--- linux.20pre10/drivers/video/matrox/matroxfb_base.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/matrox/matroxfb_base.h	2002-10-11 00:35:04.000000000 +0100
@@ -291,6 +291,8 @@
 
 struct my_timming {
 	unsigned int pixclock;
+	int mnp;
+	unsigned int crtc;
 	unsigned int HDisplay;
 	unsigned int HSyncStart;
 	unsigned int HSyncEnd;
@@ -367,6 +369,10 @@
 	u_int16_t hcorr;
 };
 
+struct matrox_crtc2 {
+	u_int32_t ctl, hparam, hsync, vparam, vsync, preload, datactl;
+};
+
 struct matrox_hw_state {
 	u_int32_t	MXoptionReg;
 	unsigned char	DACclk[6];
@@ -384,10 +390,7 @@
 	/* TVOut only */
 	struct mavenregs	maven;
 
-	/* CRTC2 only */
-	/* u_int32_t	TBD */
-
-	unsigned int	vidclk;
+	struct matrox_crtc2	crtc2;
 };
 
 struct matrox_accel_data {
@@ -398,16 +401,28 @@
 	u_int32_t	m_opmode;
 };
 
+struct matroxfb_queryctrl;
+struct matroxfb_control;
+
 struct matrox_altout {
+	struct module	*owner;
+	const char	*name;
 	int		(*compute)(void* altout_dev, struct my_timming* input);
 	int		(*program)(void* altout_dev);
 	int		(*start)(void* altout_dev);
-	void		(*incuse)(void* altout_dev);
-	void		(*decuse)(void* altout_dev);
-	int		(*setmode)(void* altout_dev, u_int32_t mode);
-	int		(*getmode)(void* altout_dev, u_int32_t* mode);
+	int		(*verifymode)(void* altout_dev, u_int32_t mode);
+	int		(*getqueryctrl)(void* altout_dev,
+					struct matroxfb_queryctrl* ctrl);
+	int		(*getctrl)(void* altout_dev, 
+				   struct matroxfb_control* ctrl);
+	int		(*setctrl)(void* altout_dev, 
+				   struct matroxfb_control* ctrl);
 };
 
+#define MATROXFB_SRC_NONE	0
+#define MATROXFB_SRC_CRTC1	1
+#define MATROXFB_SRC_CRTC2	2
+
 enum mga_chip { MGA_2064, MGA_2164, MGA_1064, MGA_1164, MGA_G100, MGA_G200, MGA_G400, MGA_G450, MGA_G550 };
 
 struct matrox_bios {
@@ -424,9 +439,9 @@
 
 struct matrox_switch;
 struct matroxfb_driver;
+struct matroxfb_dh_fb_info;
 
 struct matrox_fb_info {
-	/* fb_info must be first */
 	struct fb_info		fbcon;
 
 	struct list_head	next_fb;
@@ -442,21 +457,19 @@
 	struct pci_dev*		pcidev;
 
 	struct {
-		u_int32_t	all;
-		u_int32_t	ph;
-		u_int32_t	sh;
-			      } output;
-	struct matrox_altout*	primout;
-	struct {
-	struct fb_info*		info;
 	struct rw_semaphore	lock;
-			      } crtc2;
 	struct {
-	struct matrox_altout*	output;
-	void*			device;
-	struct rw_semaphore	lock;
+		int brightness, contrast, saturation, hue, gamma;
+		int testout, deflicker;
+				} tvo_params;
 			      } altout;
-
+#define MATROXFB_MAX_OUTPUTS		3
+	struct {
+	unsigned int		src;
+	struct matrox_altout*	output;
+	void*			data;
+	unsigned int		mode;
+			      } outputs[MATROXFB_MAX_OUTPUTS];
 #define MATROXFB_MAX_FB_DRIVERS		5
 	struct matroxfb_driver* (drivers[MATROXFB_MAX_FB_DRIVERS]);
 	void*			(drivers_data[MATROXFB_MAX_FB_DRIVERS]);
@@ -545,6 +558,8 @@
 		int		memtype;
 		int		g450dac;
 		int		dfp_type;
+		int		panellink;	/* G400 DFP possible (not G450/G550) */
+		int		dualhead;
 		unsigned int	fbResource;
 			      } devflags;
 	struct display_switch	dispsw;
@@ -561,6 +576,16 @@
 			      } cursor;
 	struct matrox_bios	bios;
 	struct {
+		unsigned int	pixclock;
+		int		mnp;
+			      } crtc1;
+	struct {
+		unsigned int 	pixclock;
+		int		mnp;
+	struct matroxfb_dh_fb_info*	info;
+	struct rw_semaphore	lock;
+			      } crtc2;
+	struct {
 		struct matrox_pll_limits	pixel;
 		struct matrox_pll_limits	system;
 		struct matrox_pll_limits	video;
@@ -625,7 +650,7 @@
 #define PMINFO   PMINFO2 ,
 
 static inline struct matrox_fb_info* mxinfo(const struct display* p) {
-	return (struct matrox_fb_info*)p->fb_info;
+	return list_entry(p->fb_info, struct matrox_fb_info, fbcon);
 }
 
 #define PMXINFO(p)	   mxinfo(p),
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/matrox/matroxfb_crtc2.c linux.20pre10-ac2/drivers/video/matrox/matroxfb_crtc2.c
--- linux.20pre10/drivers/video/matrox/matroxfb_crtc2.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/matrox/matroxfb_crtc2.c	2002-09-02 00:06:57.000000000 +0100
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.64 2002/06/10
  *
  */
 
@@ -28,8 +28,8 @@
 
 static int matroxfb_dh_getcolreg(unsigned regno, unsigned *red, unsigned *green,
 		unsigned *blue, unsigned *transp, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
-	if (regno > 16)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
+	if (regno >= 16)
 		return 1;
 	*red = m2info->palette[regno].red;
 	*blue = m2info->palette[regno].blue;
@@ -41,10 +41,10 @@
 
 static int matroxfb_dh_setcolreg(unsigned regno, unsigned red, unsigned green,
 		unsigned blue, unsigned transp, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	struct display* p;
 
-	if (regno > 16)
+	if (regno >= 16)
 		return 1;
 	m2info->palette[regno].red = red;
 	m2info->palette[regno].blue = blue;
@@ -84,86 +84,129 @@
 #undef m2info
 }
 
-static void do_install_cmap(struct matroxfb_dh_fb_info* m2info, struct display* p) {
-	if (p->cmap.len)
-		fb_set_cmap(&p->cmap, 1, matroxfb_dh_setcolreg, &m2info->fbcon);
+static inline void my_install_cmap(struct matroxfb_dh_fb_info* m2info)
+{
+	/* Do not touch this code if you do not understand what it does! */
+	/* Never try to use do_install_cmap() instead. It is crap. */
+	struct fb_cmap* cmap = &m2info->currcon_display->cmap;
+	
+	if (cmap->len)
+		fb_set_cmap(cmap, 1, matroxfb_dh_setcolreg, &m2info->fbcon);
 	else
 		fb_set_cmap(fb_default_cmap(16), 1, matroxfb_dh_setcolreg, &m2info->fbcon);
 }
 
+
 static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info,
 		struct my_timming* mt,
 		struct display* p,
 		int mode,
 		unsigned int pos) {
-	u_int32_t tmp;
+	struct matrox_crtc2 c2;
 	MINFO_FROM(m2info->primary_dev);
 
 	switch (mode) {
 		case 15:
-			tmp = 0x00200000;
+			c2.ctl = 0x00200000;
 			break;
 		case 16:
-			tmp = 0x00400000;
+			c2.ctl = 0x00400000;
 			break;
 /*		case 32: */
 		default:
-			tmp = 0x00800000;
+			c2.ctl = 0x00800000;
 			break;
 	}
-
-	if (ACCESS_FBINFO(output.sh)) {
-		tmp |= 0x00000001;	/* enable CRTC2 */
-
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-			if (ACCESS_FBINFO(devflags.g450dac)) {
-				tmp |= 0x00000006; /* source from secondary pixel PLL */
-				/* no vidrst */
-			} else {
-				tmp |= 0x00000002; /* source from VDOCLK */
-				tmp |= 0xC0000000; /* enable vvidrst & hvidrst */
-				/* MGA TVO is our clock source */
+	c2.ctl |= 0x00000001;	/* enable CRTC2 */
+	c2.datactl = 0;
+	if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) {
+		if (ACCESS_FBINFO(devflags.g450dac)) {
+			c2.ctl |= 0x00000006; /* source from secondary pixel PLL */
+			/* no vidrst when in monitor mode */
+			if (ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
+				c2.ctl |=  0xC0001000; /* Enable H/V vidrst */
 			}
-		} else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
-			tmp |= 0x00000004; /* source from pixclock */
-			/* PIXPLL is our clock source */
-		}
-
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY)
-			tmp |= 0x00100000;	/* connect CRTC2 to DAC */
+		} else {
+			c2.ctl |= 0x00000002; /* source from VDOCLK */
+			c2.ctl |= 0xC0000000; /* enable vvidrst & hvidrst */
+			/* MGA TVO is our clock source */
+		}
+	} else if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) {
+		c2.ctl |= 0x00000004; /* source from pixclock */
+		/* PIXPLL is our clock source */
+	}
+	if (ACCESS_FBINFO(outputs[0]).src == MATROXFB_SRC_CRTC2) {
+		c2.ctl |= 0x00100000;	/* connect CRTC2 to DAC */
 	}
 	if (mt->interlaced) {
-		tmp |= 0x02000000;	/* interlaced, second field is bigger, as G450 apparently ignores it */
+		c2.ctl |= 0x02000000;	/* interlaced, second field is bigger, as G450 apparently ignores it */
 		mt->VDisplay >>= 1;
 		mt->VSyncStart >>= 1;
 		mt->VSyncEnd >>= 1;
 		mt->VTotal >>= 1;
 	}
-	mga_outl(0x3C10, tmp | 0x10000000);	/* depth and so on... 0x10000000 is VIDRST polarity */
-	mga_outl(0x3C14, ((mt->HDisplay - 8) << 16) | (mt->HTotal - 8));
-	mga_outl(0x3C18, ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8));
-	mga_outl(0x3C1C, ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1));
-	mga_outl(0x3C20, ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1));
-	mga_outl(0x3C24, ((mt->VSyncStart) << 16) | (mt->HSyncStart));	/* preload */
+	if ((mt->HTotal & 7) == 2) {
+		c2.datactl |= 0x00000010;
+		mt->HTotal &= ~7;
+	}
+	c2.ctl |= 0x10000000;	/* 0x10000000 is VIDRST polarity */
+	c2.hparam = ((mt->HDisplay - 8) << 16) | (mt->HTotal - 8);
+	c2.hsync = ((mt->HSyncEnd - 8) << 16) | (mt->HSyncStart - 8);
+	c2.vparam = ((mt->VDisplay - 1) << 16) | (mt->VTotal - 1);
+	c2.vsync = ((mt->VSyncEnd - 1) << 16) | (mt->VSyncStart - 1);
+	c2.preload = ((mt->VSyncStart) << 16) | (mt->HSyncStart);
+	mga_outl(0x3C14, c2.hparam);
+	mga_outl(0x3C18, c2.hsync);
+	mga_outl(0x3C1C, c2.vparam);
+	mga_outl(0x3C20, c2.vsync);
+	mga_outl(0x3C24, c2.preload);
 	{
 		u_int32_t linelen = p->var.xres_virtual * (p->var.bits_per_pixel >> 3);
-		if (mt->interlaced) {
+		if (c2.ctl & 0x02000000) {
 			/* field #0 is smaller, so... */
 			mga_outl(0x3C2C, pos);			/* field #1 vmemory start */
 			mga_outl(0x3C28, pos + linelen);	/* field #0 vmemory start */
 			linelen <<= 1;
+			m2info->interlaced = 1;
 		} else {
 			mga_outl(0x3C28, pos);		/* vmemory start */
+			m2info->interlaced = 0;
 		}
 		mga_outl(0x3C40, linelen);
 	}
-	tmp = 0x0FFF0000;		/* line compare */
-	if (mt->sync & FB_SYNC_HOR_HIGH_ACT)
-		tmp |= 0x00000100;
-	if (mt->sync & FB_SYNC_VERT_HIGH_ACT)
-		tmp |= 0x00000200;
-	mga_outl(0x3C44, tmp);
-	mga_outl(0x3C4C, 0);		/* data control */
+	mga_outl(0x3C4C, c2.datactl);		/* data control */
+	if (c2.ctl & 0x02000000) {
+		int i;
+
+		mga_outl(0x3C10, c2.ctl & ~0x02000000);
+                for (i = 0; i < 2; i++) {
+                        unsigned int nl;
+                        unsigned int lastl = 0;
+
+                        while ((nl = mga_inl(0x3C48) & 0xFFF) >= lastl) {
+                                lastl = nl;
+                        }
+                }
+	}
+        mga_outl(0x3C10, c2.ctl);
+	ACCESS_FBINFO(hw).crtc2.ctl = c2.ctl;
+	{
+		u_int32_t tmp;
+
+		tmp = 0x0FFF0000;		/* line compare */
+		if (mt->sync & FB_SYNC_HOR_HIGH_ACT)
+			tmp |= 0x00000100;
+		if (mt->sync & FB_SYNC_VERT_HIGH_ACT)
+			tmp |= 0x00000200;
+		mga_outl(0x3C44, tmp);
+	}
+}
+
+static void matroxfb_dh_disable(struct matroxfb_dh_fb_info* m2info) {
+	MINFO_FROM(m2info->primary_dev);
+
+	mga_outl(0x3C10, 0x00000004);	/* disable CRTC2, CRTC1->DAC1, PLL as clock source */
+	ACCESS_FBINFO(hw).crtc2.ctl = 0x00000004;
 }
 
 static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info,
@@ -176,19 +219,18 @@
 	unsigned int pos;
 	unsigned int linelen;
 	unsigned int pixelsize;
+	MINFO_FROM(m2info->primary_dev);
 
-#define minfo (m2info->primary_dev)
 	pixelsize = var->bits_per_pixel >> 3;
 	linelen = var->xres_virtual * pixelsize;
 	pos = var->yoffset * linelen + var->xoffset * pixelsize;
 	pos += m2info->video.offbase;
-	if (var->vmode & FB_VMODE_INTERLACED) {
+	if (m2info->interlaced) {
 		mga_outl(0x3C2C, pos);
 		mga_outl(0x3C28, pos + linelen);
 	} else {
 		mga_outl(0x3C28, pos);
 	}
-#undef minfo
 }
 
 static int matroxfb_dh_decode_var(struct matroxfb_dh_fb_info* m2info,
@@ -292,7 +334,7 @@
 }
 
 static int matroxfb_dh_open(struct fb_info* info, int user) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	MINFO_FROM(m2info->primary_dev);
 
 	if (MINFO) {
@@ -305,7 +347,7 @@
 }
 
 static int matroxfb_dh_release(struct fb_info* info, int user) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	MINFO_FROM(m2info->primary_dev);
 
 	if (MINFO) {
@@ -316,7 +358,7 @@
 
 static int matroxfb_dh_get_fix(struct fb_fix_screeninfo* fix, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	struct display* p;
 
 	if (con >= 0)
@@ -345,7 +387,7 @@
 
 static int matroxfb_dh_get_var(struct fb_var_screeninfo* var, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	if (con < 0)
 		*var = m2info->fbcon.disp->var;
 	else
@@ -356,7 +398,7 @@
 
 static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	struct display* p;
 	int chgvar;
 	int visual;
@@ -390,7 +432,7 @@
 		chgvar = 0;
 	p->var = *var;
 	/* cmap */
-	p->screen_base = vaddr_va(m2info->video.vbase);
+	p->screen_base = m2info->fbcon.screen_base = vaddr_va(m2info->video.vbase);
 	p->visual = visual;
 	p->ypanstep = 1;
 	p->ywrapstep = 0;
@@ -405,48 +447,52 @@
 	if (con == m2info->currcon) {
 		struct my_timming mt;
 		unsigned int pos;
+		int out;
+		int cnt;
 
 		matroxfb_var2my(var, &mt);
+		mt.crtc = MATROXFB_SRC_CRTC2;
 		/* CRTC2 delay */
 		mt.delay = 34;
 
 		pos = (var->yoffset * var->xres_virtual + var->xoffset) * var->bits_per_pixel >> 3;
 		pos += m2info->video.offbase;
-		DAC1064_global_init(PMINFO2);
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
-			if (ACCESS_FBINFO(primout))
-				ACCESS_FBINFO(primout)->compute(MINFO, &mt);
+		cnt = 0;
+		down_read(&ACCESS_FBINFO(altout).lock);
+		for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+			if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
+				cnt++;
+				if (ACCESS_FBINFO(outputs[out]).output->compute) {
+					ACCESS_FBINFO(outputs[out]).output->compute(ACCESS_FBINFO(outputs[out]).data, &mt);
+				}
+			}
 		}
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-			down_read(&ACCESS_FBINFO(altout.lock));
-			if (ACCESS_FBINFO(altout.output))
-				ACCESS_FBINFO(altout.output)->compute(ACCESS_FBINFO(altout.device), &mt);
-			up_read(&ACCESS_FBINFO(altout.lock));
+		ACCESS_FBINFO(crtc2).pixclock = mt.pixclock;
+		ACCESS_FBINFO(crtc2).mnp = mt.mnp;
+		up_read(&ACCESS_FBINFO(altout).lock);
+		if (cnt) {
+			matroxfb_dh_restore(m2info, &mt, p, mode, pos);
+		} else {
+			matroxfb_dh_disable(m2info);
 		}
-		matroxfb_dh_restore(m2info, &mt, p, mode, pos);
+		DAC1064_global_init(PMINFO2);
 		DAC1064_global_restore(PMINFO2);
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
-			if (ACCESS_FBINFO(primout))
-				ACCESS_FBINFO(primout)->program(MINFO);
-		}
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-			down_read(&ACCESS_FBINFO(altout.lock));
-			if (ACCESS_FBINFO(altout.output))
-				ACCESS_FBINFO(altout.output)->program(ACCESS_FBINFO(altout.device));
-			up_read(&ACCESS_FBINFO(altout.lock));
-		}
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_PRIMARY) {
-			if (ACCESS_FBINFO(primout))
-				ACCESS_FBINFO(primout)->start(MINFO);
+		down_read(&ACCESS_FBINFO(altout).lock);
+		for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+			if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 &&
+			    ACCESS_FBINFO(outputs[out]).output->program) {
+				ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data);
+			}
 		}
-		if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-			down_read(&ACCESS_FBINFO(altout.lock));
-			if (ACCESS_FBINFO(altout.output))
-				ACCESS_FBINFO(altout.output)->start(ACCESS_FBINFO(altout.device));
-			up_read(&ACCESS_FBINFO(altout.lock));
+		for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+			if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2 &&
+			    ACCESS_FBINFO(outputs[out]).output->start) {
+				ACCESS_FBINFO(outputs[out]).output->start(ACCESS_FBINFO(outputs[out]).data);
+			}
 		}
+		up_read(&ACCESS_FBINFO(altout).lock);
 		matroxfb_dh_cfbX_init(m2info, p);
-		do_install_cmap(m2info, p);
+		my_install_cmap(m2info);
 	}
 	return 0;
 #undef m2info
@@ -454,7 +500,7 @@
 
 static int matroxfb_dh_get_cmap(struct fb_cmap* cmap, int kspc, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	struct display* dsp;
 
 	if (con < 0)
@@ -473,7 +519,7 @@
 
 static int matroxfb_dh_set_cmap(struct fb_cmap* cmap, int kspc, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	struct display* dsp;
 
 	if (con < 0)
@@ -497,7 +543,7 @@
 
 static int matroxfb_dh_pan_display(struct fb_var_screeninfo* var, int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
 	    var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
 		return -EINVAL;
@@ -530,7 +576,7 @@
 		unsigned long arg,
 		int con,
 		struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	MINFO_FROM(m2info->primary_dev);
 
 	DBG("matroxfb_crtc2_ioctl")
@@ -557,38 +603,84 @@
 		case MATROXFB_SET_OUTPUT_CONNECTION:
 			{
 				u_int32_t tmp;
+				int out;
+				int changes;
 
 				if (get_user(tmp, (u_int32_t*)arg))
 					return -EFAULT;
-				if (tmp & ~ACCESS_FBINFO(output.all))
-					return -EINVAL;
-				if (tmp & ACCESS_FBINFO(output.ph))
-					return -EINVAL;
-				if (tmp & MATROXFB_OUTPUT_CONN_DFP)
-					return -EINVAL;
-				if ((ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP) && tmp)
-					return -EINVAL;
-				if (tmp == ACCESS_FBINFO(output.sh))
+				for (out = 0; out < 32; out++) {
+					if (tmp & (1 << out)) {
+						if (out >= MATROXFB_MAX_OUTPUTS)
+							return -ENXIO;
+						if (!ACCESS_FBINFO(outputs[out]).output)
+							return -ENXIO;
+						switch (ACCESS_FBINFO(outputs[out]).src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC2:
+								break;
+							default:
+								return -EBUSY;
+						}
+					}
+				}
+				if (ACCESS_FBINFO(devflags.panellink)) {
+					if (tmp & MATROXFB_OUTPUT_CONN_DFP)
+						return -EINVAL;
+					if ((ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) && tmp)
+						return -EBUSY;
+				}
+				changes = 0;
+				for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+					if (tmp & (1 << out)) {
+						if (ACCESS_FBINFO(outputs[out]).src != MATROXFB_SRC_CRTC2) {
+							changes = 1;
+							ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_CRTC2;
+						}
+					} else if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
+						changes = 1;
+						ACCESS_FBINFO(outputs[out]).src = MATROXFB_SRC_NONE;
+					}
+				}
+				if (!changes)
 					return 0;
-				ACCESS_FBINFO(output.sh) = tmp;
 				matroxfb_dh_switch(m2info->currcon, info);
 				return 0;
 			}
 		case MATROXFB_GET_OUTPUT_CONNECTION:
 			{
-				if (put_user(ACCESS_FBINFO(output.sh), (u_int32_t*)arg))
+				u_int32_t conn = 0;
+				int out;
+
+				for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+					if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC2) {
+						conn |= 1 << out;
+					}
+				}
+				if (put_user(conn, (u_int32_t*)arg))
 					return -EFAULT;
 				return 0;
 			}
 		case MATROXFB_GET_AVAILABLE_OUTPUTS:
 			{
-				u_int32_t tmp;
+				u_int32_t tmp = 0;
+				int out;
 
-				/* we do not support DFP from CRTC2 */
-				tmp = ACCESS_FBINFO(output.all) & ~ACCESS_FBINFO(output.ph) & ~MATROXFB_OUTPUT_CONN_DFP;
-				/* CRTC1 in DFP mode disables CRTC2 at all (I know, I'm lazy) */
-				if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)
-					tmp = 0;
+				for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
+					if (ACCESS_FBINFO(outputs[out]).output) {
+						switch (ACCESS_FBINFO(outputs[out]).src) {
+							case MATROXFB_SRC_NONE:
+							case MATROXFB_SRC_CRTC2:
+								tmp |= 1 << out;
+								break;
+						}
+					}
+				}
+				if (ACCESS_FBINFO(devflags.panellink)) {
+					tmp &= ~MATROXFB_OUTPUT_CONN_DFP;
+					if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1) {
+						tmp = 0;
+					}
+				}
 				if (put_user(tmp, (u_int32_t*)arg))
 					return -EFAULT;
 				return 0;
@@ -598,6 +690,24 @@
 #undef m2info
 }
 
+static int matroxfb_dh_blank(int blank, struct fb_info* info) {
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
+	switch (blank) {
+		case 1:
+		case 2:
+		case 3:
+		case 4:
+		default:;
+	}
+	/* do something... */
+	return 0;
+#undef m2info
+}
+
+static void matroxfb_dh_blank24(int blank, struct fb_info* info) {
+	matroxfb_dh_blank(blank, info);
+}
+
 static struct fb_ops matroxfb_dh_ops = {
 	owner:		THIS_MODULE,
 	fb_open:	matroxfb_dh_open,
@@ -612,7 +722,7 @@
 };
 
 static int matroxfb_dh_switch(int con, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	struct fb_cmap* cmap;
 	struct display* p;
 
@@ -635,25 +745,12 @@
 }
 
 static int matroxfb_dh_updatevar(int con, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
+#define m2info (list_entry(info, struct matroxfb_dh_fb_info, fbcon))
 	matroxfb_dh_pan_var(m2info, &fb_display[con].var);
 	return 0;
 #undef m2info
 }
 
-static void matroxfb_dh_blank(int blank, struct fb_info* info) {
-#define m2info ((struct matroxfb_dh_fb_info*)info)
-	switch (blank) {
-		case 1:
-		case 2:
-		case 3:
-		case 4:
-		default:;
-	}
-	/* do something... */
-#undef m2info
-}
-
 static struct fb_var_screeninfo matroxfb_dh_defined = {
 		640,480,640,480,/* W,H, virtual W,H */
 		0,0,		/* offset */
@@ -692,7 +789,7 @@
 	m2info->fbcon.disp = d;
 	m2info->fbcon.switch_con = &matroxfb_dh_switch;
 	m2info->fbcon.updatevar = &matroxfb_dh_updatevar;
-	m2info->fbcon.blank = &matroxfb_dh_blank;
+	m2info->fbcon.blank = &matroxfb_dh_blank24;
 	m2info->fbcon.flags = FBINFO_FLAG_DEFAULT;
 	m2info->currcon = -1;
 	m2info->currcon_display = d;
@@ -722,11 +819,10 @@
 	/*
 	 *  If we have unused output, connect CRTC2 to it...
 	 */
-	if ((ACCESS_FBINFO(output.all) & MATROXFB_OUTPUT_CONN_SECONDARY) && 
-	   !(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) &&
-	   !(ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)) {
-		ACCESS_FBINFO(output.sh) |= MATROXFB_OUTPUT_CONN_SECONDARY;
-		ACCESS_FBINFO(output.sh) &= ~MATROXFB_OUTPUT_CONN_DFP;
+	if (ACCESS_FBINFO(outputs[1]).output &&
+	    ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_NONE &&
+	    ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_NONE) {
+		ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_CRTC2;
 	}
 
 	matroxfb_dh_set_var(&matroxfb_dh_defined, -2, &m2info->fbcon);
@@ -739,7 +835,7 @@
 	}
 	down_write(&ACCESS_FBINFO(crtc2.lock));
 	oldcrtc2 = ACCESS_FBINFO(crtc2.info);
-	ACCESS_FBINFO(crtc2.info) = &m2info->fbcon;
+	ACCESS_FBINFO(crtc2.info) = m2info;
 	up_write(&ACCESS_FBINFO(crtc2.lock));
 	if (oldcrtc2) {
 		printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 already present: %p\n",
@@ -768,16 +864,16 @@
 #define minfo (m2info->primary_dev)
 	if (m2info->fbcon_registered) {
 		int id;
-		struct fb_info* crtc2;
+		struct matroxfb_dh_fb_info* crtc2;
 
 		down_write(&ACCESS_FBINFO(crtc2.lock));
 		crtc2 = ACCESS_FBINFO(crtc2.info);
-		if (crtc2 == &m2info->fbcon)
+		if (crtc2 == m2info)
 			ACCESS_FBINFO(crtc2.info) = NULL;
 		up_write(&ACCESS_FBINFO(crtc2.lock));
-		if (crtc2 != &m2info->fbcon) {
+		if (crtc2 != m2info) {
 			printk(KERN_ERR "matroxfb_crtc2: Internal consistency check failed: crtc2 mismatch at unload: %p != %p\n",
-				crtc2, &m2info->fbcon);
+				crtc2, m2info);
 			printk(KERN_ERR "matroxfb_crtc2: Expect kernel crash after module unload.\n");
 			return;
 		}
@@ -815,6 +911,7 @@
 
 static void matroxfb_crtc2_remove(struct matrox_fb_info* minfo, void* crtc2) {
 	matroxfb_dh_deregisterfb(crtc2);
+	kfree(crtc2);
 }
 
 static struct matroxfb_driver crtc2 = {
@@ -831,7 +928,7 @@
 	matroxfb_unregister_driver(&crtc2);
 }
 
-MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
 MODULE_DESCRIPTION("Matrox G400 CRTC2 driver");
 MODULE_LICENSE("GPL");
 module_init(matroxfb_crtc2_init);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/matrox/matroxfb_crtc2.h linux.20pre10-ac2/drivers/video/matrox/matroxfb_crtc2.h
--- linux.20pre10/drivers/video/matrox/matroxfb_crtc2.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/matrox/matroxfb_crtc2.h	2002-10-11 00:35:04.000000000 +0100
@@ -29,6 +29,8 @@
 
 	int			currcon;
 	struct display*		currcon_display;
+	
+	int			interlaced:1;
 
 	union {
 #ifdef FBCON_HAS_CFB16
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/matrox/matroxfb_DAC1064.c linux.20pre10-ac2/drivers/video/matrox/matroxfb_DAC1064.c
--- linux.20pre10/drivers/video/matrox/matroxfb_DAC1064.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/matrox/matroxfb_DAC1064.c	2002-09-02 00:06:57.000000000 +0100
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.64 2002/06/10
  *
  * See matroxfb_base.c for contributors.
  *
@@ -161,37 +161,20 @@
 	unsigned int p;
 
 	DBG("DAC1064_calcclock")
+	
+	/* only for devices older than G450 */
 
 	fvco = PLL_calcclock(PMINFO freq, fmax, in, feed, &p);
 	
-	if (ACCESS_FBINFO(devflags.g450dac)) {
-		if (fvco <= 300000)		/* 276-324 */
-			;
-		else if (fvco <= 400000)	/* 378-438 */
-			p |= 0x08;
-		else if (fvco <= 550000)	/* 540-567 */
-			p |= 0x10;
-		else if (fvco <= 690000)	/* 675-695 */
-			p |= 0x18;
-		else if (fvco <= 800000)	/* 776-803 */
-			p |= 0x20;
-		else if (fvco <= 891000)	/* 891-891 */
-			p |= 0x28;
-		else if (fvco <= 940000)	/* 931-945 */
-			p |= 0x30;
-		else				/* <959 */
-			p |= 0x38;
-	} else {
-		p = (1 << p) - 1;
-		if (fvco <= 100000)
-			;
-		else if (fvco <= 140000)
-			p |= 0x08;
-		else if (fvco <= 180000)
-			p |= 0x10;
-		else
-			p |= 0x18;
-	}
+	p = (1 << p) - 1;
+	if (fvco <= 100000)
+		;
+	else if (fvco <= 140000)
+		p |= 0x08;
+	else if (fvco <= 180000)
+		p |= 0x10;
+	else
+		p |= 0x18;
 	*post = p;
 }
 
@@ -293,31 +276,164 @@
 	hw->MXoptionReg = mx;
 }
 
+static void g450_set_plls(WPMINFO2) {
+	u_int32_t c2_ctl;
+	unsigned int pxc;
+	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
+	int pixelmnp;
+	int videomnp;
+	
+	c2_ctl = hw->crtc2.ctl & ~0x4007;	/* Clear PLL + enable for CRTC2 */
+	c2_ctl |= 0x0001;			/* Enable CRTC2 */
+	hw->DACreg[POS1064_XPWRCTRL] &= ~0x02;	/* Stop VIDEO PLL */
+	pixelmnp = ACCESS_FBINFO(crtc1).mnp;
+	videomnp = ACCESS_FBINFO(crtc2).mnp;
+	if (videomnp < 0) {
+		c2_ctl &= ~0x0001;			/* Disable CRTC2 */
+		hw->DACreg[POS1064_XPWRCTRL] &= ~0x10;	/* Powerdown CRTC2 */
+	} else if (ACCESS_FBINFO(crtc2).pixclock == ACCESS_FBINFO(features).pll.ref_freq) {
+		c2_ctl |=  0x4002;	/* Use reference directly */
+	} else if (videomnp == pixelmnp) {
+		c2_ctl |=  0x0004;	/* Use pixel PLL */
+	} else {
+		if (0 == ((videomnp ^ pixelmnp) & 0xFFFFFF00)) {
+			/* PIXEL and VIDEO PLL must not use same frequency. We modify N
+			   of PIXEL PLL in such case because of VIDEO PLL may be source
+			   of TVO clocks, and chroma subcarrier is derived from its
+			   pixel clocks */
+			pixelmnp += 0x000100;
+		}
+		c2_ctl |=  0x0006;	/* Use video PLL */
+		hw->DACreg[POS1064_XPWRCTRL] |= 0x02;
+		
+		outDAC1064(PMINFO M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
+		matroxfb_g450_setpll_cond(PMINFO videomnp, M_VIDEO_PLL);
+	}
+
+	hw->DACreg[POS1064_XPIXCLKCTRL] &= ~M1064_XPIXCLKCTRL_PLL_UP;
+	if (pixelmnp >= 0) {
+		hw->DACreg[POS1064_XPIXCLKCTRL] |= M1064_XPIXCLKCTRL_PLL_UP;
+		
+		outDAC1064(PMINFO M1064_XPIXCLKCTRL, hw->DACreg[POS1064_XPIXCLKCTRL]);
+		matroxfb_g450_setpll_cond(PMINFO pixelmnp, M_PIXEL_PLL_C);
+	}
+	if (c2_ctl != hw->crtc2.ctl) {
+		hw->crtc2.ctl = c2_ctl;
+		mga_outl(0x3C10, c2_ctl);
+	}
+
+	pxc = ACCESS_FBINFO(crtc1).pixclock;
+	if (pxc == 0 || ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC2) {
+		pxc = ACCESS_FBINFO(crtc2).pixclock;
+	}
+	if (ACCESS_FBINFO(chip) == MGA_G550) {
+		if (pxc < 45000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x00;	/* 0-50 */
+		} else if (pxc < 55000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x08;	/* 34-62 */
+		} else if (pxc < 70000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x10;	/* 42-78 */
+		} else if (pxc < 85000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x18;	/* 62-92 */
+		} else if (pxc < 100000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x20;	/* 74-108 */
+		} else if (pxc < 115000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x28;	/* 94-122 */
+		} else if (pxc < 125000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x30;	/* 108-132 */
+		} else {
+			hw->DACreg[POS1064_XPANMODE] = 0x38;	/* 120-168 */
+		}
+	} else {
+		/* G450 */
+		if (pxc < 45000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x00;	/* 0-54 */
+		} else if (pxc < 65000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x08;	/* 38-70 */
+		} else if (pxc < 85000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x10;	/* 56-96 */
+		} else if (pxc < 105000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x18;	/* 80-114 */
+		} else if (pxc < 135000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x20;	/* 102-144 */
+		} else if (pxc < 160000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x28;	/* 132-166 */
+		} else if (pxc < 175000) {
+			hw->DACreg[POS1064_XPANMODE] = 0x30;	/* 154-182 */
+		} else {
+			hw->DACreg[POS1064_XPANMODE] = 0x38;	/* 170-204 */
+		}
+	}
+}
+
 void DAC1064_global_init(WPMINFO2) {
 	struct matrox_hw_state* hw = &ACCESS_FBINFO(hw);
 
 	hw->DACreg[POS1064_XMISCCTRL] &= M1064_XMISCCTRL_DAC_WIDTHMASK;
 	hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_LUT_EN;
 	hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL;
-	hw->DACreg[POS1064_XOUTPUTCONN] = 0x01;	/* output #1 enabled */
-	if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-		if (ACCESS_FBINFO(devflags.g450dac)) {
-			hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_PLL2;
-			hw->DACreg[POS1064_XOUTPUTCONN] = 0x05;	/* output #1 enabled; CRTC1 connected to output #2 */
-		} else {
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		hw->DACreg[POS1064_XPWRCTRL] = 0x1F;	/* powerup everything */
+		hw->DACreg[POS1064_XOUTPUTCONN] = 0x00;	/* disable outputs */
+		hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
+		switch (ACCESS_FBINFO(outputs[0]).src) {
+			case MATROXFB_SRC_CRTC1:
+			case MATROXFB_SRC_CRTC2:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x01;	/* enable output; CRTC1/2 selection is in CRTC2 ctl */
+				break;
+			case MATROXFB_SRC_NONE:
+				hw->DACreg[POS1064_XMISCCTRL] &= ~M1064_XMISCCTRL_DAC_EN;
+				break;
+		}
+		switch (ACCESS_FBINFO(outputs[1]).src) {
+			case MATROXFB_SRC_CRTC1:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x04;
+				break;
+			case MATROXFB_SRC_CRTC2:
+				if (ACCESS_FBINFO(outputs[1]).mode == MATROXFB_OUTPUT_MODE_MONITOR) {
+					hw->DACreg[POS1064_XOUTPUTCONN] |= 0x08;
+				} else {
+					hw->DACreg[POS1064_XOUTPUTCONN] |= 0x0C;
+				}
+				break;
+			case MATROXFB_SRC_NONE:
+				hw->DACreg[POS1064_XPWRCTRL] &= ~0x01;		/* Poweroff DAC2 */
+				break;
+		}
+		switch (ACCESS_FBINFO(outputs[2]).src) {
+			case MATROXFB_SRC_CRTC1:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x20;
+				break;
+			case MATROXFB_SRC_CRTC2:
+				hw->DACreg[POS1064_XOUTPUTCONN] |= 0x40;
+				break;
+			case MATROXFB_SRC_NONE:
+#if 0
+				/* HELP! If we boot without DFP connected to DVI, we can
+				   poweroff TMDS. But if we boot with DFP connected,
+				   TMDS generated clocks are used instead of ALL pixclocks
+				   available... If someone knows which register
+				   handles it, please reveal this secret to me... */			
+				hw->DACreg[POS1064_XPWRCTRL] &= ~0x04;		/* Poweroff TMDS */
+#endif				
+				break;
+		}
+		/* Now set timming related variables... */
+		g450_set_plls(PMINFO2);
+	} else {
+		if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1) {
 			hw->DACreg[POS1064_XPIXCLKCTRL] = M1064_XPIXCLKCTRL_PLL_UP | M1064_XPIXCLKCTRL_EN | M1064_XPIXCLKCTRL_SRC_EXT;
 			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_MAFC12;
-		}
-	} else if (ACCESS_FBINFO(output.sh) & MATROXFB_OUTPUT_CONN_SECONDARY) {
-		hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12;
-		hw->DACreg[POS1064_XOUTPUTCONN] = 0x09; /* output #1 enabled; CRTC2 connected to output #2 */
-	} else if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_DFP)
-		hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12;
-	else
-		hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS;
+		} else if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC2) {
+			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_MAFC | G400_XMISCCTRL_VDO_C2_MAFC12;
+		} else if (ACCESS_FBINFO(outputs[2]).src == MATROXFB_SRC_CRTC1)
+			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_PANELLINK | G400_XMISCCTRL_VDO_MAFC12;
+		else
+			hw->DACreg[POS1064_XMISCCTRL] |= GX00_XMISCCTRL_MFC_DIS;
 
-	if ((ACCESS_FBINFO(output.ph) | ACCESS_FBINFO(output.sh)) & MATROXFB_OUTPUT_CONN_PRIMARY)
-		hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
+		if (ACCESS_FBINFO(outputs[0]).src != MATROXFB_SRC_NONE)
+			hw->DACreg[POS1064_XMISCCTRL] |= M1064_XMISCCTRL_DAC_EN;
+	}
 }
 
 void DAC1064_global_restore(WPMINFO2) {
@@ -329,8 +445,9 @@
 		outDAC1064(PMINFO 0x20, 0x04);
 		outDAC1064(PMINFO 0x1F, ACCESS_FBINFO(devflags.dfp_type));
 		if (ACCESS_FBINFO(devflags.g450dac)) {
-			outDAC1064(PMINFO M1064_XSYNCCTRL, 0xCC);	/* only matrox know... */
-			outDAC1064(PMINFO M1064_XPWRCTRL, 0x1F);	/* powerup everything */
+			outDAC1064(PMINFO M1064_XSYNCCTRL, 0xCC);
+			outDAC1064(PMINFO M1064_XPWRCTRL, hw->DACreg[POS1064_XPWRCTRL]);
+			outDAC1064(PMINFO M1064_XPANMODE, hw->DACreg[POS1064_XPANMODE]);
 			outDAC1064(PMINFO M1064_XOUTPUTCONN, hw->DACreg[POS1064_XOUTPUTCONN]);
 		}
 	}
@@ -368,13 +485,13 @@
 			return 1;	/* unsupported depth */
 		}
 	}
-
-	DAC1064_global_init(PMINFO2);
 	hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl);
 	hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK;
 	hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN;
 	hw->DACreg[POS1064_XCURADDL] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 10;
 	hw->DACreg[POS1064_XCURADDH] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 18;
+
+	DAC1064_global_init(PMINFO2);
 	return 0;
 }
 
@@ -471,13 +588,8 @@
 #endif
 }
 
-static int m1064_compute(void* outdev, struct my_timming* m) {
-#define minfo ((struct matrox_fb_info*)outdev)
-#ifdef CONFIG_FB_MATROX_G450
-	if (ACCESS_FBINFO(devflags.g450dac)) {
-		matroxfb_g450_setclk(PMINFO m->pixclock, M_PIXEL_PLL_C);
-	} else 
-#endif
+static int m1064_compute(void* out, struct my_timming* m) {
+#define minfo ((struct matrox_fb_info*)out)
 	{
 		int i;
 		int tmout;
@@ -504,37 +616,28 @@
 	return 0;
 }
 
-static int m1064_program(void* outdev) {
-	/* nothing, hardware is set in m1064_compute */
-	return 0;
-}
-
-static int m1064_start(void* outdev) {
-	/* nothing */
-	return 0;
-}
-
-static void m1064_incuse(void* outdev) {
-	/* nothing yet; MODULE_INC_USE in future... */
-}
-
-static void m1064_decuse(void* outdev) {
-	/* nothing yet; MODULE_DEC_USE in future... */
-}
+static struct matrox_altout m1064 = {
+	.owner   = THIS_MODULE,
+	.name	 = "Primary output",
+	.compute = m1064_compute,
+};
 
-static int m1064_setmode(void* outdev, u_int32_t mode) {
-	if (mode != MATROXFB_OUTPUT_MODE_MONITOR)
-		return -EINVAL;
+static int g450_compute(void* out, struct my_timming* m) {
+#define minfo ((struct matrox_fb_info*)out)
+	if (m->mnp < 0) {
+		m->mnp = matroxfb_g450_setclk(PMINFO m->pixclock, (m->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
+		if (m->mnp >= 0) {
+			m->pixclock = g450_mnp2f(PMINFO m->mnp);
+		}
+	}
+#undef minfo
 	return 0;
 }
 
-static struct matrox_altout m1064 = {
-	m1064_compute,
-	m1064_program,
-	m1064_start,
-	m1064_incuse,
-	m1064_decuse,
-	m1064_setmode
+static struct matrox_altout g450out = {
+	.owner   = THIS_MODULE,
+	.name	 = "Primary output",
+	.compute = g450_compute,
 };
 
 #endif /* NEED_DAC1064 */
@@ -680,7 +783,10 @@
 	ACCESS_FBINFO(features.accel.has_cacheflush) = 1;
 	ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor;
 
-	ACCESS_FBINFO(primout) = &m1064;
+	ACCESS_FBINFO(outputs[0]).output = &m1064;
+	ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
+	ACCESS_FBINFO(outputs[0]).data = MINFO;
+	ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
 
 	if (ACCESS_FBINFO(devflags.noinit))
 		return 0;	/* do not modify settings */
@@ -726,8 +832,13 @@
 	    ((ACCESS_FBINFO(values).reg.opt3 & 0x300000) == 0x300000)) {
 		matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(values.pll.video), M_VIDEO_PLL);
 	} else {
-		/* slow down video clocks... */
-		matroxfb_g450_setclk(PMINFO 0, M_VIDEO_PLL);
+		unsigned long flags;
+		unsigned int pwr;
+		
+		matroxfb_DAC_lock_irqsave(flags);
+		pwr = inDAC1064(PMINFO M1064_XPWRCTRL) & ~0x02;
+		outDAC1064(PMINFO M1064_XPWRCTRL, pwr);
+		matroxfb_DAC_unlock_irqrestore(flags);
 	}
 	matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(values.pll.system), M_SYSTEM_PLL);
 	
@@ -864,7 +975,14 @@
 	ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100
 			? ACCESS_FBINFO(devflags.sgram) : 1;
 
-	ACCESS_FBINFO(primout) = &m1064;
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		ACCESS_FBINFO(outputs[0]).output = &g450out;
+	} else {
+		ACCESS_FBINFO(outputs[0]).output = &m1064;
+	}
+	ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
+	ACCESS_FBINFO(outputs[0]).data = MINFO;
+	ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
 
 	if (ACCESS_FBINFO(devflags.g450dac)) {
 		/* we must do this always, BIOS does not do it for us
@@ -895,8 +1013,7 @@
 
 		hw->MXoptionReg |= 0x1080;
 		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
-		mga_outl(M_CTLWTST, 0x00000300);
-		/* mga_outl(M_CTLWTST, 0x03258A31); */
+		mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
 		udelay(100);
 		mga_outb(0x1C05, 0x00);
 		mga_outb(0x1C05, 0x80);
@@ -947,17 +1064,18 @@
 		pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION2_REG, reg50);
 
 		if (ACCESS_FBINFO(devflags.memtype) == -1)
-			ACCESS_FBINFO(devflags.memtype) = 0;
-		hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10;
+			hw->MXoptionReg |= ACCESS_FBINFO(values).reg.opt & 0x1C00;
+		else
+			hw->MXoptionReg |= (ACCESS_FBINFO(devflags.memtype) & 7) << 10;
 		if (ACCESS_FBINFO(devflags.sgram))
 			hw->MXoptionReg |= 0x4000;
-		mga_outl(M_CTLWTST, 0x042450A1);
-		mga_outl(M_MEMRDBK, 0x00000108);
+		mga_outl(M_CTLWTST, ACCESS_FBINFO(values).reg.mctlwtst);
+		mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
 		udelay(200);
 		mga_outl(M_MACCESS, 0x00000000);
 		mga_outl(M_MACCESS, 0x00008000);
 		udelay(100);
-		mga_outl(M_MEMRDBK, 0x00000108);
+		mga_outl(M_MEMRDBK, ACCESS_FBINFO(values).reg.memrdbk);
 		hw->MXoptionReg |= 0x00040020;
 	}
 	pci_write_config_dword(ACCESS_FBINFO(pcidev), PCI_OPTION_REG, hw->MXoptionReg);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/matrox/matroxfb_DAC1064.h linux.20pre10-ac2/drivers/video/matrox/matroxfb_DAC1064.h
--- linux.20pre10/drivers/video/matrox/matroxfb_DAC1064.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/matrox/matroxfb_DAC1064.h	2002-10-11 00:35:04.000000000 +0100
@@ -146,6 +146,8 @@
 
 #define M1064_XPWRCTRL		0xA0
 
+#define M1064_XPANMODE		0xA2
+
 enum POS1064 {
 	POS1064_XCURADDL=0, POS1064_XCURADDH, POS1064_XCURCTRL,
 	POS1064_XCURCOL0RED, POS1064_XCURCOL0GREEN, POS1064_XCURCOL0BLUE,
@@ -156,7 +158,7 @@
 	POS1064_XGENIOCTRL, POS1064_XGENIODATA, POS1064_XZOOMCTRL, POS1064_XSENSETEST,
 	POS1064_XCRCBITSEL,
 	POS1064_XCOLKEYMASKL, POS1064_XCOLKEYMASKH, POS1064_XCOLKEYL, POS1064_XCOLKEYH,
-	POS1064_XOUTPUTCONN };
+	POS1064_XOUTPUTCONN, POS1064_XPANMODE, POS1064_XPWRCTRL };
 
 
 #endif	/* __MATROXFB_DAC1064_H__ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/matrox/matroxfb_g450.c linux.20pre10-ac2/drivers/video/matrox/matroxfb_g450.c
--- linux.20pre10/drivers/video/matrox/matroxfb_g450.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/matrox/matroxfb_g450.c	2002-09-02 00:06:57.000000000 +0100
@@ -2,145 +2,634 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.64 2002/06/02
  *
  * See matroxfb_base.c for contributors.
  *
  */
 
-#include "matroxfb_g450.h"
+#include "matroxfb_base.h"
 #include "matroxfb_misc.h"
 #include "matroxfb_DAC1064.h"
 #include "g450_pll.h"
 #include <linux/matroxfb.h>
 #include <asm/uaccess.h>
+#include <asm/div64.h>
 
-static int matroxfb_g450_compute(void* md, struct my_timming* mt) {
-#define m2info ((struct matroxfb_g450_info*)md)
-#define minfo (m2info->primary_dev)
-	ACCESS_FBINFO(hw).vidclk = mt->pixclock;
-#undef minfo
-#undef m2info
-	return 0;
+/* Definition of the various controls */
+struct mctl {
+	struct matroxfb_queryctrl desc;
+	size_t control;
+};
+
+#define BLMIN	0xF3
+#define WLMAX	0x3FF
+
+static const struct mctl g450_controls[] =
+{	{ { MATROXFB_CID_BRIGHTNESS,
+	  "brightness",
+	  0, WLMAX-BLMIN, 1, 370-BLMIN, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) },
+	{ { MATROXFB_CID_CONTRAST,
+	  "contrast",
+	  0, 1023, 1, 127, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) },
+	{ { MATROXFB_CID_SATURATION,
+	  "saturation",
+	  0, 255, 1, 165, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) },
+	{ { MATROXFB_CID_HUE,
+	  "hue",
+	  0, 255, 1, 0, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
+	{ { MATROXFB_CID_TESTOUT,
+	  "test output",
+	  0, 1, 1, 0, 
+	  MATROXFB_CTRL_TYPE_BOOLEAN, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
+};
+
+#define G450CTRLS (sizeof(g450_controls)/sizeof(g450_controls[0]))
+
+/* Return: positive number: id found
+           -EINVAL:         id not found, return failure
+	   -ENOENT:         id not found, create fake disabled control */
+static int get_ctrl_id(__u32 v4l2_id) {
+	int i;
+
+	for (i = 0; i < G450CTRLS; i++) {
+		if (v4l2_id < g450_controls[i].desc.id) {
+			if (g450_controls[i].desc.id == 0x08000000) {
+				return -EINVAL;
+			}
+			return -ENOENT;
+		}
+		if (v4l2_id == g450_controls[i].desc.id) {
+			return i;
+		}
+	}
+	return -EINVAL;
 }
 
-static int matroxfb_g450_program(void* md) {
-#define m2info ((struct matroxfb_g450_info*)md)
-#define minfo (m2info->primary_dev)
-	matroxfb_g450_setclk(PMINFO ACCESS_FBINFO(hw).vidclk, M_VIDEO_PLL);
-#undef minfo
-#undef m2info	
-	return 0;
+static inline int* get_ctrl_ptr(WPMINFO unsigned int idx) {
+	return (int*)((char*)MINFO + g450_controls[idx].control);
 }
 
-static int matroxfb_g450_start(void* md) {
-	return 0;
+static void tvo_fill_defaults(WPMINFO2) {
+	unsigned int i;
+	
+	for (i = 0; i < G450CTRLS; i++) {
+		*get_ctrl_ptr(PMINFO i) = g450_controls[i].desc.default_value;
+	}
 }
 
-static void matroxfb_g450_incuse(void* md) {
-	MOD_INC_USE_COUNT;
+static int cve2_get_reg(WPMINFO int reg) {
+	unsigned long flags;
+	int val;
+	
+	matroxfb_DAC_lock_irqsave(flags);
+	matroxfb_DAC_out(PMINFO 0x87, reg);
+	val = matroxfb_DAC_in(PMINFO 0x88);
+	matroxfb_DAC_unlock_irqrestore(flags);
+	return val;
 }
 
-static void matroxfb_g450_decuse(void* md) {
-	MOD_DEC_USE_COUNT;
+static void cve2_set_reg(WPMINFO int reg, int val) {
+	unsigned long flags;
+
+	matroxfb_DAC_lock_irqsave(flags);
+	matroxfb_DAC_out(PMINFO 0x87, reg);
+	matroxfb_DAC_out(PMINFO 0x88, val);
+	matroxfb_DAC_unlock_irqrestore(flags);
+}
+
+static void cve2_set_reg10(WPMINFO int reg, int val) {
+	unsigned long flags;
+
+	matroxfb_DAC_lock_irqsave(flags);
+	matroxfb_DAC_out(PMINFO 0x87, reg);
+	matroxfb_DAC_out(PMINFO 0x88, val >> 2);
+	matroxfb_DAC_out(PMINFO 0x87, reg + 1);
+	matroxfb_DAC_out(PMINFO 0x88, val & 3);
+	matroxfb_DAC_unlock_irqrestore(flags);
+}
+
+static void g450_compute_bwlevel(CPMINFO int *bl, int *wl) {
+	const int b = ACCESS_FBINFO(altout.tvo_params.brightness) + BLMIN;
+	const int c = ACCESS_FBINFO(altout.tvo_params.contrast);
+
+	*bl = max(b - c, BLMIN);
+	*wl = min(b + c, WLMAX);
 }
 
-static int matroxfb_g450_set_mode(void* md, u_int32_t arg) {
-	if (arg == MATROXFB_OUTPUT_MODE_MONITOR) {
-		return 1;
+static int g450_query_ctrl(void* md, struct matroxfb_queryctrl *p) {
+	int i;
+	
+	i = get_ctrl_id(p->id);
+	if (i >= 0) {
+		*p = g450_controls[i].desc;
+		return 0;
+	}
+	if (i == -ENOENT) {
+		static const struct matroxfb_queryctrl disctrl = 
+			{ 0, "", 0, 0, 0, 0, 0, 1, 1, "Disabled" };
+			
+		i = p->id;
+		*p = disctrl;
+		p->id = i;
+		sprintf(p->name, "Ctrl #%08X", i);
+		return 0;
 	}
 	return -EINVAL;
 }
 
-static int matroxfb_g450_get_mode(void* md, u_int32_t* arg) {
-	*arg = MATROXFB_OUTPUT_MODE_MONITOR;
+static int g450_set_ctrl(void* md, struct matroxfb_control *p) {
+	int i;
+	MINFO_FROM(md);
+	
+	i = get_ctrl_id(p->id);
+	if (i < 0) return -EINVAL;
+
+	/*
+	 * Check if changed.
+	 */
+	if (p->value == *get_ctrl_ptr(PMINFO i)) return 0;
+
+	/*
+	 * Check limits.
+	 */
+	if (p->value > g450_controls[i].desc.maximum) return -EINVAL;
+	if (p->value < g450_controls[i].desc.minimum) return -EINVAL;
+
+	/*
+	 * Store new value.
+	 */
+	*get_ctrl_ptr(PMINFO i) = p->value;
+
+	switch (p->id) {
+		case MATROXFB_CID_BRIGHTNESS:
+		case MATROXFB_CID_CONTRAST:
+			{
+				int blacklevel, whitelevel;
+				g450_compute_bwlevel(PMINFO &blacklevel, &whitelevel);
+				cve2_set_reg10(PMINFO 0x0e, blacklevel);
+				cve2_set_reg10(PMINFO 0x1e, whitelevel);
+			}
+			break;
+		case MATROXFB_CID_SATURATION:
+			cve2_set_reg(PMINFO 0x20, p->value);
+			cve2_set_reg(PMINFO 0x22, p->value);
+			break;
+		case MATROXFB_CID_HUE:
+			cve2_set_reg(PMINFO 0x25, p->value);
+			break;
+		case MATROXFB_CID_TESTOUT:
+			{
+				unsigned char val = cve2_get_reg (PMINFO 0x05);
+				if (p->value) val |=  0x02;
+				else          val &= ~0x02;
+				cve2_set_reg(PMINFO 0x05, val);
+			}
+			break;
+	}
+	
+
+	return 0;
+}
+
+static int g450_get_ctrl(void* md, struct matroxfb_control *p) {
+	int i;
+	MINFO_FROM(md);
+	
+	i = get_ctrl_id(p->id);
+	if (i < 0) return -EINVAL;
+	p->value = *get_ctrl_ptr(PMINFO i);
 	return 0;
 }
 
-static struct matrox_altout matroxfb_g450_altout = {
-	matroxfb_g450_compute,
-	matroxfb_g450_program,
-	matroxfb_g450_start,
-	matroxfb_g450_incuse,
-	matroxfb_g450_decuse,
-	matroxfb_g450_set_mode,
-	matroxfb_g450_get_mode
+struct output_desc {
+	unsigned int	h_vis;
+	unsigned int	h_f_porch;
+	unsigned int	h_sync;
+	unsigned int	h_b_porch;
+	unsigned long long int	chromasc;
+	unsigned int	burst;
+	unsigned int	v_total;
 };
 
-static int matroxfb_g450_connect(struct matroxfb_g450_info* m2info) {
-	MINFO_FROM(m2info->primary_dev);
+static void computeRegs(WPMINFO struct mavenregs* r, struct my_timming* mt, const struct output_desc* outd) {
+	u_int32_t chromasc;
+	u_int32_t hlen;
+	u_int32_t hsl;
+	u_int32_t hbp;
+	u_int32_t hfp;
+	u_int32_t hvis;
+	unsigned int pixclock;
+	unsigned long long piic;
+	int mnp;
+	int over;
+	
+	r->regs[0x80] = 0x03;	/* | 0x40 for SCART */
 
-	down_write(&ACCESS_FBINFO(altout.lock));
-	ACCESS_FBINFO(altout.device) = m2info;
-	ACCESS_FBINFO(altout.output) = &matroxfb_g450_altout;
-	up_write(&ACCESS_FBINFO(altout.lock));
-	ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY;
-	matroxfb_switch(ACCESS_FBINFO(currcon), (struct fb_info*)MINFO);	
-	return 0;
+	hvis = ((mt->HDisplay << 1) + 3) & ~3;
+	
+	if (hvis >= 2048) {
+		hvis = 2044;
+	}
+	
+	piic = 1000000000ULL * hvis;
+	do_div(piic, outd->h_vis);
+
+	dprintk(KERN_DEBUG "Want %u kHz pixclock\n", (unsigned int)piic);
+	
+	mnp = matroxfb_g450_setclk(PMINFO piic, M_VIDEO_PLL);
+	
+	mt->mnp = mnp;
+	mt->pixclock = g450_mnp2f(PMINFO mnp);
+
+	dprintk(KERN_DEBUG "MNP=%08X\n", mnp);
+
+	pixclock = 1000000000U / mt->pixclock;
+
+	dprintk(KERN_DEBUG "Got %u ps pixclock\n", pixclock);
+
+	piic = outd->chromasc;
+	do_div(piic, mt->pixclock);
+	chromasc = piic;
+	
+	dprintk(KERN_DEBUG "Chroma is %08X\n", chromasc);
+
+	r->regs[0] = piic >> 24;
+	r->regs[1] = piic >> 16;
+	r->regs[2] = piic >>  8;
+	r->regs[3] = piic >>  0;
+	hbp = (((outd->h_b_porch + pixclock) / pixclock)) & ~1;
+	hfp = (((outd->h_f_porch + pixclock) / pixclock)) & ~1;
+	hsl = (((outd->h_sync + pixclock) / pixclock)) & ~1;
+	hlen = hvis + hfp + hsl + hbp;
+	over = hlen & 0x0F;
+	
+	dprintk(KERN_DEBUG "WL: vis=%u, hf=%u, hs=%u, hb=%u, total=%u\n", hvis, hfp, hsl, hbp, hlen);
+
+	if (over) {
+		hfp -= over;
+		hlen -= over;
+		if (over <= 2) {
+		} else if (over < 10) {
+			hfp += 4;
+			hlen += 4;
+		} else {
+			hfp += 16;
+			hlen += 16;
+		}
+	}
+
+	/* maybe cve2 has requirement 800 < hlen < 1184 */
+	r->regs[0x08] = hsl;
+	r->regs[0x09] = (outd->burst + pixclock - 1) / pixclock;	/* burst length */
+	r->regs[0x0A] = hbp;
+	r->regs[0x2C] = hfp;
+	r->regs[0x31] = hvis / 8;
+	r->regs[0x32] = hvis & 7;
+	
+	dprintk(KERN_DEBUG "PG: vis=%04X, hf=%02X, hs=%02X, hb=%02X, total=%04X\n", hvis, hfp, hsl, hbp, hlen);
+
+	r->regs[0x84] = 1;	/* x sync point */
+	r->regs[0x85] = 0;
+	hvis = hvis >> 1;
+	hlen = hlen >> 1;
+	
+	dprintk(KERN_DEBUG "hlen=%u hvis=%u\n", hlen, hvis);
+
+	mt->interlaced = 1;
+
+	mt->HDisplay = hvis & ~7;
+	mt->HSyncStart = mt->HDisplay + 8;
+	mt->HSyncEnd = (hlen & ~7) - 8;
+	mt->HTotal = hlen;
+
+	{
+		int upper;
+		unsigned int vtotal;
+		unsigned int vsyncend;
+		unsigned int vdisplay;
+		
+		vtotal = mt->VTotal;
+		vsyncend = mt->VSyncEnd;
+		vdisplay = mt->VDisplay;
+		if (vtotal < outd->v_total) {
+			unsigned int yovr = outd->v_total - vtotal;
+			
+			vsyncend += yovr >> 1;
+		} else if (vtotal > outd->v_total) {
+			vdisplay = outd->v_total - 4;
+			vsyncend = outd->v_total;
+		}
+		upper = (outd->v_total - vsyncend) >> 1;	/* in field lines */
+		r->regs[0x17] = outd->v_total / 4;
+		r->regs[0x18] = outd->v_total & 3;
+		r->regs[0x33] = upper - 1;	/* upper blanking */
+		r->regs[0x82] = upper;		/* y sync point */
+		r->regs[0x83] = upper >> 8;
+		
+		mt->VDisplay = vdisplay;
+		mt->VSyncStart = outd->v_total - 2;
+		mt->VSyncEnd = outd->v_total;
+		mt->VTotal = outd->v_total;
+	}
+}
+
+static void cve2_init_TVdata(int norm, struct mavenregs* data, const struct output_desc** outd) {
+	static const struct output_desc paloutd = {
+		.h_vis	   = 52148148,	// ps
+		.h_f_porch =  1407407,	// ps
+		.h_sync    =  4666667,	// ps
+		.h_b_porch =  5777778,	// ps
+		.chromasc  = 19042247534182ULL,	// 4433618.750 Hz
+		.burst     =  2518518,	// ps
+		.v_total   =      625,
+	};
+	static const struct output_desc ntscoutd = {
+		.h_vis     = 52888889,	// ps
+		.h_f_porch =  1333333,	// ps
+		.h_sync    =  4666667,	// ps
+		.h_b_porch =  4666667,	// ps
+		.chromasc  = 15374030659475ULL,	// 3579545.454 Hz
+		.burst     =  2418418,	// ps
+		.v_total   =      525,	// lines
+	};
+
+	static const struct mavenregs palregs = { {
+		0x2A, 0x09, 0x8A, 0xCB,	/* 00: chroma subcarrier */
+		0x00,
+		0x00,	/* test */
+		0xF9,	/* modified by code (F9 written...) */
+		0x00,	/* ? not written */
+		0x7E,	/* 08 */
+		0x44,	/* 09 */
+		0x9C,	/* 0A */
+		0x2E,	/* 0B */
+		0x21,	/* 0C */
+		0x00,	/* ? not written */
+//		0x3F, 0x03, /* 0E-0F */
+		0x3C, 0x03,
+		0x3C, 0x03, /* 10-11 */
+		0x1A,	/* 12 */
+		0x2A,	/* 13 */
+		0x1C, 0x3D, 0x14, /* 14-16 */
+		0x9C, 0x01, /* 17-18 */
+		0x00,	/* 19 */
+		0xFE,	/* 1A */
+		0x7E,	/* 1B */
+		0x60,	/* 1C */
+		0x05,	/* 1D */
+//		0x89, 0x03, /* 1E-1F */
+		0xAD, 0x03,
+//		0x72,	/* 20 */
+		0xA5,
+		0x07,	/* 21 */
+//		0x72,	/* 22 */
+		0xA5,
+		0x00,	/* 23 */
+		0x00,	/* 24 */
+		0x00,	/* 25 */
+		0x08,	/* 26 */
+		0x04,	/* 27 */
+		0x00,	/* 28 */
+		0x1A,	/* 29 */
+		0x55, 0x01, /* 2A-2B */
+		0x26,	/* 2C */
+		0x07, 0x7E, /* 2D-2E */
+		0x02, 0x54, /* 2F-30 */
+		0xB0, 0x00, /* 31-32 */
+		0x14,	/* 33 */
+		0x49,	/* 34 */
+		0x00,	/* 35 written multiple times */
+		0x00,	/* 36 not written */
+		0xA3,	/* 37 */
+		0xC8,	/* 38 */
+		0x22,	/* 39 */
+		0x02,	/* 3A */
+		0x22,	/* 3B */
+		0x3F, 0x03, /* 3C-3D */
+		0x00,	/* 3E written multiple times */
+		0x00,	/* 3F not written */
+	} };
+	static struct mavenregs ntscregs = { {
+		0x21, 0xF0, 0x7C, 0x1F,	/* 00: chroma subcarrier */
+		0x00,
+		0x00,	/* test */
+		0xF9,	/* modified by code (F9 written...) */
+		0x00,	/* ? not written */
+		0x7E,	/* 08 */
+		0x43,	/* 09 */
+		0x7E,	/* 0A */
+		0x3D,	/* 0B */
+		0x00,	/* 0C */
+		0x00,	/* ? not written */
+		0x41, 0x00, /* 0E-0F */
+		0x3C, 0x00, /* 10-11 */
+		0x17,	/* 12 */
+		0x21,	/* 13 */
+		0x1B, 0x1B, 0x24, /* 14-16 */
+		0x83, 0x01, /* 17-18 */
+		0x00,	/* 19 */
+		0x0F,	/* 1A */
+		0x0F,	/* 1B */
+		0x60,	/* 1C */
+		0x05,	/* 1D */
+		//0x89, 0x02, /* 1E-1F */
+		0xC0, 0x02, /* 1E-1F */
+		//0x5F,	/* 20 */
+		0x9C,	/* 20 */
+		0x04,	/* 21 */
+		//0x5F,	/* 22 */
+		0x9C,	/* 22 */
+		0x01,	/* 23 */
+		0x02,	/* 24 */
+		0x00,	/* 25 */
+		0x0A,	/* 26 */
+		0x05,	/* 27 */
+		0x00,	/* 28 */
+		0x10,	/* 29 */
+		0xFF, 0x03, /* 2A-2B */
+		0x24,	/* 2C */
+		0x0F, 0x78, /* 2D-2E */
+		0x00, 0x00, /* 2F-30 */
+		0xB2, 0x04, /* 31-32 */
+		0x14,	/* 33 */
+		0x02,	/* 34 */
+		0x00,	/* 35 written multiple times */
+		0x00,	/* 36 not written */
+		0xA3,	/* 37 */
+		0xC8,	/* 38 */
+		0x15,	/* 39 */
+		0x05,	/* 3A */
+		0x3B,	/* 3B */
+		0x3C, 0x00, /* 3C-3D */
+		0x00,	/* 3E written multiple times */
+		0x00,	/* never written */
+	} };
+
+	if (norm == MATROXFB_OUTPUT_MODE_PAL) {
+		*data = palregs;
+		*outd = &paloutd;
+	} else {
+  		*data = ntscregs;
+		*outd = &ntscoutd;
+	}
+ 	return;
 }
 
-static void matroxfb_g450_shutdown(struct matroxfb_g450_info* m2info) {
-	MINFO_FROM(m2info->primary_dev);
+#define LR(x) cve2_set_reg(PMINFO (x), m->regs[(x)])
+static void cve2_init_TV(WPMINFO const struct mavenregs* m) {
+	int i;
+
+	LR(0x80);
+	LR(0x82); LR(0x83);
+	LR(0x84); LR(0x85);
 	
-	if (MINFO) {
-		ACCESS_FBINFO(output.all) &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-		ACCESS_FBINFO(output.ph) &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-		ACCESS_FBINFO(output.sh) &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-		down_write(&ACCESS_FBINFO(altout.lock));
-		ACCESS_FBINFO(altout.device) = NULL;
-		ACCESS_FBINFO(altout.output) = NULL;
-		up_write(&ACCESS_FBINFO(altout.lock));
-		m2info->primary_dev = NULL;
+	cve2_set_reg(PMINFO 0x3E, 0x01);
+	
+	for (i = 0; i < 0x3E; i++) {
+		LR(i);
 	}
+	cve2_set_reg(PMINFO 0x3E, 0x00);
 }
 
-/* we do not have __setup() yet */
-static void* matroxfb_g450_probe(struct matrox_fb_info* minfo) {
-	struct matroxfb_g450_info* m2info;
+static int matroxfb_g450_compute(void* md, struct my_timming* mt) {
+	MINFO_FROM(md);
 
-	/* hardware is not G450... */
-	if (!ACCESS_FBINFO(devflags.g450dac))
-		return NULL;
-	m2info = (struct matroxfb_g450_info*)kmalloc(sizeof(*m2info), GFP_KERNEL);
-	if (!m2info) {
-		printk(KERN_ERR "matroxfb_g450: Not enough memory for G450 DAC control structs\n");
-		return NULL;
+	dprintk(KERN_DEBUG "Computing, mode=%u\n", ACCESS_FBINFO(outputs[1]).mode);
+
+	if (mt->crtc == MATROXFB_SRC_CRTC2 &&
+	    ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
+		const struct output_desc* outd;
+
+		cve2_init_TVdata(ACCESS_FBINFO(outputs[1]).mode, &ACCESS_FBINFO(hw).maven, &outd);
+		{
+			int blacklevel, whitelevel;
+			g450_compute_bwlevel(PMINFO &blacklevel, &whitelevel);
+			ACCESS_FBINFO(hw).maven.regs[0x0E] = blacklevel >> 2;
+			ACCESS_FBINFO(hw).maven.regs[0x0F] = blacklevel & 3;
+			ACCESS_FBINFO(hw).maven.regs[0x1E] = whitelevel >> 2;
+			ACCESS_FBINFO(hw).maven.regs[0x1F] = whitelevel & 3;
+
+			ACCESS_FBINFO(hw).maven.regs[0x20] =
+			ACCESS_FBINFO(hw).maven.regs[0x22] = ACCESS_FBINFO(altout.tvo_params.saturation);
+
+			ACCESS_FBINFO(hw).maven.regs[0x25] = ACCESS_FBINFO(altout.tvo_params.hue);
+
+			if (ACCESS_FBINFO(altout.tvo_params.testout)) {
+				ACCESS_FBINFO(hw).maven.regs[0x05] |= 0x02;
+			}
+		}
+		computeRegs(PMINFO &ACCESS_FBINFO(hw).maven, mt, outd);
+	} else if (mt->mnp < 0) {
+		/* We must program clocks before CRTC2, otherwise interlaced mode
+		   startup may fail */
+		mt->mnp = matroxfb_g450_setclk(PMINFO mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
+		mt->pixclock = g450_mnp2f(PMINFO mt->mnp);
 	}
-	memset(m2info, 0, sizeof(*m2info));
-	m2info->primary_dev = MINFO;
-	if (matroxfb_g450_connect(m2info)) {
-		kfree(m2info);
-		printk(KERN_ERR "matroxfb_g450: G450 DAC failed to initialize\n");
-		return NULL;
+	dprintk(KERN_DEBUG "Pixclock = %u\n", mt->pixclock);
+	return 0;
+}
+
+static int matroxfb_g450_program(void* md) {
+	MINFO_FROM(md);
+	
+	if (ACCESS_FBINFO(outputs[1]).mode != MATROXFB_OUTPUT_MODE_MONITOR) {
+		cve2_init_TV(PMINFO &ACCESS_FBINFO(hw).maven);
 	}
-	return m2info;
+	return 0;
 }
 
-static void matroxfb_g450_remove(struct matrox_fb_info* minfo, void* g450) {
-	matroxfb_g450_shutdown(g450);
-	kfree(g450);
+static int matroxfb_g450_verify_mode(void* md, u_int32_t arg) {
+	MINFO_FROM(md);
+	
+	switch (arg) {
+		case MATROXFB_OUTPUT_MODE_PAL:
+		case MATROXFB_OUTPUT_MODE_NTSC:
+		case MATROXFB_OUTPUT_MODE_MONITOR:
+			return 0;
+	}
+	return -EINVAL;
 }
 
-static struct matroxfb_driver g450 = {
-		name:	"Matrox G450 output #2",
-		probe:	matroxfb_g450_probe,
-		remove:	matroxfb_g450_remove };
+static int g450_dvi_compute(void* md, struct my_timming* mt) {
+	MINFO_FROM(md);
 
-static int matroxfb_g450_init(void) {
-	matroxfb_register_driver(&g450);
+	if (mt->mnp < 0) {
+		mt->mnp = matroxfb_g450_setclk(PMINFO mt->pixclock, (mt->crtc == MATROXFB_SRC_CRTC1) ? M_PIXEL_PLL_C : M_VIDEO_PLL);
+		mt->pixclock = g450_mnp2f(PMINFO mt->mnp);
+	}
 	return 0;
 }
 
-static void matroxfb_g450_exit(void) {
-	matroxfb_unregister_driver(&g450);
+static struct matrox_altout matroxfb_g450_altout = {
+	.owner   = THIS_MODULE,
+	.name	 = "Secondary output",
+	.compute = matroxfb_g450_compute,
+	.program = matroxfb_g450_program,
+	.verifymode = matroxfb_g450_verify_mode,
+	.getqueryctrl = g450_query_ctrl,
+	.getctrl = g450_get_ctrl,
+	.setctrl = g450_set_ctrl,
+};
+
+static struct matrox_altout matroxfb_g450_dvi = {
+	.owner   = THIS_MODULE,
+	.name	 = "DVI output",
+	.compute = g450_dvi_compute,
+};
+
+void matroxfb_g450_connect(WPMINFO2) {
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		down_write(&ACCESS_FBINFO(altout.lock));
+		tvo_fill_defaults(PMINFO2);
+		ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_CRTC1;
+		ACCESS_FBINFO(outputs[1]).data = MINFO;
+		ACCESS_FBINFO(outputs[1]).output = &matroxfb_g450_altout;
+		ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_CRTC1;
+		ACCESS_FBINFO(outputs[2]).data = MINFO;
+		ACCESS_FBINFO(outputs[2]).output = &matroxfb_g450_dvi;
+		ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		up_write(&ACCESS_FBINFO(altout.lock));
+	}
 }
 
-MODULE_AUTHOR("(c) 2000-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
-MODULE_DESCRIPTION("Matrox G450 secondary output driver");
+void matroxfb_g450_shutdown(WPMINFO2) {
+	if (ACCESS_FBINFO(devflags.g450dac)) {
+		down_write(&ACCESS_FBINFO(altout.lock));
+		ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
+		ACCESS_FBINFO(outputs[1]).output = NULL;
+		ACCESS_FBINFO(outputs[1]).data = NULL;
+		ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		ACCESS_FBINFO(outputs[2]).src = MATROXFB_SRC_NONE;
+		ACCESS_FBINFO(outputs[2]).output = NULL;
+		ACCESS_FBINFO(outputs[2]).data = NULL;
+		ACCESS_FBINFO(outputs[2]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		up_write(&ACCESS_FBINFO(altout.lock));
+	}
+}
+
+EXPORT_SYMBOL(matroxfb_g450_connect);
+EXPORT_SYMBOL(matroxfb_g450_shutdown);
+
+MODULE_AUTHOR("(c) 2000-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Matrox G450/G550 output driver");
 MODULE_LICENSE("GPL");
-module_init(matroxfb_g450_init);
-module_exit(matroxfb_g450_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/matrox/matroxfb_g450.h linux.20pre10-ac2/drivers/video/matrox/matroxfb_g450.h
--- linux.20pre10/drivers/video/matrox/matroxfb_g450.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/matrox/matroxfb_g450.h	2002-10-11 00:35:04.000000000 +0100
@@ -1,12 +1,14 @@
 #ifndef __MATROXFB_G450_H__
 #define __MATROXFB_G450_H__
 
-#include <linux/ioctl.h>
 #include "matroxfb_base.h"
 
-struct matroxfb_g450_info {
-	struct matrox_fb_info*	primary_dev;
-	unsigned int		timmings;
-};
+#ifdef CONFIG_FB_MATROX_G450
+void matroxfb_g450_connect(WPMINFO2);
+void matroxfb_g450_shutdown(WPMINFO2);
+#else
+static inline void matroxfb_g450_connect(WPMINFO2) { };
+static inline void matroxfb_g450_shutdown(WPMINFO2) { };
+#endif
 
-#endif /* __MATROXFB_MAVEN_H__ */
+#endif /* __MATROXFB_G450_H__ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/matrox/matroxfb_maven.c linux.20pre10-ac2/drivers/video/matrox/matroxfb_maven.c
--- linux.20pre10/drivers/video/matrox/matroxfb_maven.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/matrox/matroxfb_maven.c	2002-09-02 00:06:57.000000000 +0100
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
  *
- * (c) 1998-2001 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2001/11/29
+ * Version: 1.64 2002/06/10
  *
  * See matroxfb_base.c for contributors.
  *
@@ -30,13 +30,125 @@
 #define MGATVO_B	1
 #define MGATVO_C	2
 
+static const struct maven_gamma {
+  unsigned char reg83;
+  unsigned char reg84;
+  unsigned char reg85;
+  unsigned char reg86;
+  unsigned char reg87;
+  unsigned char reg88;
+  unsigned char reg89;
+  unsigned char reg8a;
+  unsigned char reg8b;
+} maven_gamma[] = {
+  { 131, 57, 223, 15, 117, 212, 251, 91, 156},
+  { 133, 61, 128, 63, 180, 147, 195, 100, 180},
+  { 131, 19, 63, 31, 50, 66, 171, 64, 176},
+  { 0, 0, 0, 31, 16, 16, 16, 100, 200},
+  { 8, 23, 47, 73, 147, 244, 220, 80, 195},
+  { 22, 43, 64, 80, 147, 115, 58, 85, 168},
+  { 34, 60, 80, 214, 147, 212, 188, 85, 167},
+  { 45, 77, 96, 216, 147, 99, 91, 85, 159},
+  { 56, 76, 112, 107, 147, 212, 148, 64, 144},
+  { 65, 91, 128, 137, 147, 196, 17, 69, 148},
+  { 72, 104, 136, 138, 147, 180, 245, 73, 147},
+  { 87, 116, 143, 126, 16, 83, 229, 77, 144},
+  { 95, 119, 152, 254, 244, 83, 221, 77, 151},
+  { 100, 129, 159, 156, 244, 148, 197, 77, 160},
+  { 105, 141, 167, 247, 244, 132, 181, 84, 166},
+  { 105, 147, 168, 247, 244, 245, 181, 90, 170},
+  { 120, 153, 175, 248, 212, 229, 165, 90, 180},
+  { 119, 156, 176, 248, 244, 229, 84, 74, 160},
+  { 119, 158, 183, 248, 244, 229, 149, 78, 165}
+};
+
+/* Definition of the various controls */
+struct mctl {
+	struct matroxfb_queryctrl desc;
+	size_t control;
+};
+
+#define BLMIN	0x0FF
+#define WLMAX	0x3FF
+
+static const struct mctl maven_controls[] =
+{	{ { MATROXFB_CID_BRIGHTNESS,
+	  "brightness",
+	  0, WLMAX - BLMIN, 1, 379 - BLMIN, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) },
+	{ { MATROXFB_CID_CONTRAST,
+	  "contrast",
+	  0, 1023, 1, 127, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) },
+	{ { MATROXFB_CID_SATURATION,
+	  "saturation",
+	  0, 255, 1, 155, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) },
+	{ { MATROXFB_CID_HUE,
+	  "hue",
+	  0, 255, 1, 0, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.hue) },
+	{ { MATROXFB_CID_GAMMA,
+	  "gamma",
+	  0, sizeof(maven_gamma)/sizeof(maven_gamma[0])-1, 1, 3, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.gamma) },
+	{ { MATROXFB_CID_TESTOUT,
+	  "test output",
+	  0, 1, 1, 0, 
+	  MATROXFB_CTRL_TYPE_BOOLEAN, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.testout) },
+	{ { MATROXFB_CID_DEFLICKER,
+	  "deflicker mode",
+	  0, 2, 1, 0, 
+	  MATROXFB_CTRL_TYPE_INTEGER, 0, 0,
+	  "picture"
+	}, offsetof(struct matrox_fb_info, altout.tvo_params.deflicker) },
+
+};
+
+#define MAVCTRLS (sizeof(maven_controls)/sizeof(maven_controls[0]))
+
+/* Return: positive number: id found
+           -EINVAL:         id not found, return failure
+	   -ENOENT:         id not found, create fake disabled control */
+static int get_ctrl_id(__u32 v4l2_id) {
+	int i;
+
+	for (i = 0; i < MAVCTRLS; i++) {
+		if (v4l2_id < maven_controls[i].desc.id) {
+			if (maven_controls[i].desc.id == 0x08000000) {
+				return -EINVAL;
+			}
+			return -ENOENT;
+		}
+		if (v4l2_id == maven_controls[i].desc.id) {
+			return i;
+		}
+	}
+	return -EINVAL;
+}
+
 struct maven_data {
 	struct matrox_fb_info*		primary_head;
 	struct i2c_client*		client;
-	int				mode;
 	int				version;
 };
 
+static int* get_ctrl_ptr(struct maven_data* md, int idx) {
+	return (int*)((char*)(md->primary_head) + maven_controls[idx].control);
+}
+
 static int maven_get_reg(struct i2c_client* c, char reg) {
 	char dst;
 	struct i2c_msg msgs[] = {{ c->addr, I2C_M_REV_DIR_ADDR, sizeof(reg), &reg },
@@ -127,8 +239,8 @@
 	fwant = htotal * vtotal;
 	fmax = pll->vco_freq_max / ctl->den;
 
-	printk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
-		fwant, fxtal, htotal, vtotal, fmax);
+/*	printk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n",
+		fwant, fxtal, htotal, vtotal, fmax);	*/
 	for (p = 1; p <= pll->post_shift_max; p++) {
 		if (fwant * 2 > fmax)
 			break;
@@ -163,9 +275,9 @@
 			ln = ln - scrlen;
 			if (ln > htotal)
 				continue;
-			printk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln);
+			dprintk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln);
 			if (ln > besth2) {
-				printk(KERN_DEBUG "Better...\n");
+				dprintk(KERN_DEBUG "Better...\n");
 				*h2 = besth2 = ln;
 				*post = p;
 				*in = m;
@@ -221,6 +333,38 @@
 	return;
 }
 
+static unsigned char maven_compute_deflicker (const struct maven_data* md) {
+	unsigned char df;
+	
+	df = (md->version == MGATVO_B?0x40:0x00);
+	switch (md->primary_head->altout.tvo_params.deflicker) {
+		case 0:
+/*			df |= 0x00; */
+			break;
+		case 1:
+			df |= 0xB1;
+			break;
+		case 2:
+			df |= 0xA2;
+			break;
+	}
+	return df;
+}
+
+static void maven_compute_bwlevel (const struct maven_data* md,
+				   int *bl, int *wl) {
+	const int b = md->primary_head->altout.tvo_params.brightness + BLMIN;
+	const int c = md->primary_head->altout.tvo_params.contrast;
+
+	*bl = max(b - c, BLMIN);
+	*wl = min(b + c, WLMAX);
+}
+
+static const struct maven_gamma* maven_compute_gamma (const struct maven_data* md) {
+ 	return maven_gamma + md->primary_head->altout.tvo_params.gamma;
+}
+
+
 static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) {
 	static struct mavenregs palregs = { {
 		0x2A, 0x09, 0x8A, 0xCB,	/* 00: chroma subcarrier */
@@ -326,26 +470,50 @@
 		0x00,	/* 3E written multiple times */
 		0x00,	/* never written */
 	}, MODE_NTSC, 525, 60 };
+	MINFO_FROM(md->primary_head);
 
-	if (md->mode & MODE_PAL)
+	if (ACCESS_FBINFO(outputs[1].mode) == MODE_PAL)
 		*data = palregs;
-	else
-		*data = ntscregs;
-
-	data->regs[0x93] = 0xA2;
-
-	/* gamma correction registers */
-	data->regs[0x83] = 0x00;
-	data->regs[0x84] = 0x00;
-	data->regs[0x85] = 0x00;
-	data->regs[0x86] = 0x1F;
-	data->regs[0x87] = 0x10;
-	data->regs[0x88] = 0x10;
-	data->regs[0x89] = 0x10;
-	data->regs[0x8A] = 0x64;	/* 100 */
-	data->regs[0x8B] = 0xC8;	/* 200 */
-
-	return;
+  	else
+  		*data = ntscregs;
+  
+ 	/* Set deflicker */
+ 	data->regs[0x93] = maven_compute_deflicker(md);
+ 
+ 	/* set gamma */
+ 	{
+		const struct maven_gamma* g;
+		g = maven_compute_gamma(md);
+		data->regs[0x83] = g->reg83;
+		data->regs[0x84] = g->reg84;
+		data->regs[0x85] = g->reg85;
+		data->regs[0x86] = g->reg86;
+		data->regs[0x87] = g->reg87;
+		data->regs[0x88] = g->reg88;
+		data->regs[0x89] = g->reg89;
+		data->regs[0x8A] = g->reg8a;
+		data->regs[0x8B] = g->reg8b;
+ 	}
+ 
+ 	/* Set contrast / brightness */
+ 	{
+		int bl, wl;
+		maven_compute_bwlevel (md, &bl, &wl);
+		data->regs[0x0e] = bl >> 2;
+		data->regs[0x0f] = bl & 3;
+		data->regs[0x1e] = wl >> 2;
+		data->regs[0x1f] = wl & 3;
+ 	}
+
+ 	/* Set saturation */
+ 	{
+		data->regs[0x20] =
+		data->regs[0x22] = ACCESS_FBINFO(altout.tvo_params.saturation);
+ 	}
+ 
+ 	/* Set HUE */
+	data->regs[0x25] = ACCESS_FBINFO(altout.tvo_params.hue);
+ 	return;
 }
 
 #define LR(x) maven_set_reg(c, (x), m->regs[(x)])
@@ -386,7 +554,7 @@
 	LRP(0x17);
 	LR(0x0B);
 	LR(0x0C);
-	if (m->mode & MODE_PAL) {
+	if (m->mode == MODE_PAL) {
 		maven_set_reg(c, 0x35, 0x10); /* ... */
 	} else {
 		maven_set_reg(c, 0x35, 0x0F); /* ... */
@@ -424,7 +592,7 @@
 	LR(0x27);
 	LR(0x21);
 	LRP(0x2A);
-	if (m->mode & MODE_PAL)
+	if (m->mode == MODE_PAL)
 		maven_set_reg(c, 0x35, 0x1D);	/* ... */
 	else
 		maven_set_reg(c, 0x35, 0x1C);
@@ -473,7 +641,7 @@
 	LR(0xC2);
 
 	maven_get_reg(c, 0x8D);
-	maven_set_reg(c, 0x8D, 0x00);
+	maven_set_reg(c, 0x8D, 0x04);
 
 	LR(0x20);	/* saturation #1 */
 	LR(0x22);	/* saturation #2 */
@@ -498,7 +666,7 @@
 	LR(0x8B);
 
 	val = maven_get_reg(c, 0x8D);
-	val &= 0x10;			/* 0x10 or anything ored with it */
+	val &= 0x14;			/* 0x10 or anything ored with it */
 	maven_set_reg(c, 0x8D, val);
 
 	LR(0x33);
@@ -524,7 +692,7 @@
 	LR(0x27);
 	LR(0x21);
 	LRP(0x2A);
-	if (m->mode & MODE_PAL)
+	if (m->mode == MODE_PAL)
 		maven_set_reg(c, 0x35, 0x1D);
 	else
 		maven_set_reg(c, 0x35, 0x1C);
@@ -562,7 +730,7 @@
 		unsigned int a, b, c, h2;
 		unsigned int h = ht + 2 + x;
 
-		if (!matroxfb_mavenclock((m->mode & MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
+		if (!matroxfb_mavenclock((m->mode == MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
 			unsigned int diff = h - h2;
 
 			if (diff < err) {
@@ -584,8 +752,8 @@
 	unsigned int tmpi;
 	unsigned int a, bv, c;
 
-	m->mode = md->mode;
-	if (MODE_TV(md->mode)) {
+	m->mode = md->primary_head->outputs[1].mode;
+	if (MODE_TV(m->mode)) {
 		unsigned int lmargin;
 		unsigned int umargin;
 		unsigned int vslen;
@@ -804,7 +972,7 @@
 	m->regs[0xB0] = 0x03;	/* output: monitor */
 	m->regs[0xB1] = 0xA0;	/* ??? */
 	m->regs[0x8C] = 0x20;	/* must be set... */
-	m->regs[0x8D] = 0x00;	/* defaults to 0x10: test signal */
+	m->regs[0x8D] = 0x04;	/* defaults to 0x10: test signal */
 	m->regs[0xB9] = 0x1A;	/* defaults to 0x2C: too bright */
 	m->regs[0xBF] = 0x22;	/* makes picture stable */
 
@@ -849,25 +1017,122 @@
 	return 0;
 }
 
-static inline int maven_resync(struct maven_data* md) {
+static inline int maven_start(struct maven_data* md) {
 	struct i2c_client* c = md->client;
 	maven_set_reg(c, 0x95, 0x20);	/* start whole thing */
 	return 0;
 }
 
-static int maven_set_output_mode(struct maven_data* md, u_int32_t arg) {
-	switch (arg) {
-		case MATROXFB_OUTPUT_MODE_PAL:
-		case MATROXFB_OUTPUT_MODE_NTSC:
-		case MATROXFB_OUTPUT_MODE_MONITOR:
-			md->mode = arg;
-			return 1;
+static int maven_get_queryctrl (struct maven_data* md, 
+				struct matroxfb_queryctrl *p) {
+	int i;
+	
+	i = get_ctrl_id(p->id);
+	if (i >= 0) {
+		*p = maven_controls[i].desc;
+		return 0;
+	}
+	if (i == -ENOENT) {
+		static const struct matroxfb_queryctrl disctrl = 
+			{ 0, "", 0, 0, 0, 0, 0, 1, 1, "Disabled" };
+			
+		i = p->id;
+		*p = disctrl;
+		p->id = i;
+		sprintf(p->name, "Ctrl #%08X", i);
+		return 0;
 	}
 	return -EINVAL;
 }
 
-static int maven_get_output_mode(struct maven_data* md, u_int32_t *arg) {
-	*arg = md->mode;
+static int maven_set_control (struct maven_data* md, 
+			      struct matroxfb_control *p) {
+	int i;
+	
+	i = get_ctrl_id(p->id);
+	if (i < 0) return -EINVAL;
+
+	/*
+	 * Check if changed.
+	 */
+	if (p->value == *get_ctrl_ptr(md, i)) return 0;
+
+	/*
+	 * Check limits.
+	 */
+	if (p->value > maven_controls[i].desc.maximum) return -EINVAL;
+	if (p->value < maven_controls[i].desc.minimum) return -EINVAL;
+
+	/*
+	 * Store new value.
+	 */
+	*get_ctrl_ptr(md, i) = p->value;
+
+	switch (p->id) {
+		case MATROXFB_CID_BRIGHTNESS:
+		case MATROXFB_CID_CONTRAST:
+		{
+		  int blacklevel, whitelevel;
+		  maven_compute_bwlevel(md, &blacklevel, &whitelevel);
+		  blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8);
+		  whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8);
+		  maven_set_reg_pair(md->client, 0x0e, blacklevel);
+		  maven_set_reg_pair(md->client, 0x1e, whitelevel);
+		}
+		break;
+		case MATROXFB_CID_SATURATION:
+		{
+		  maven_set_reg(md->client, 0x20, p->value);
+		  maven_set_reg(md->client, 0x22, p->value);
+		}
+		break;
+		case MATROXFB_CID_HUE:
+		{
+		  maven_set_reg(md->client, 0x25, p->value);
+		}
+		break;
+		case MATROXFB_CID_GAMMA:
+		{
+		  const struct maven_gamma* g;
+		  g = maven_compute_gamma(md);
+		  maven_set_reg(md->client, 0x83, g->reg83);
+		  maven_set_reg(md->client, 0x84, g->reg84);
+		  maven_set_reg(md->client, 0x85, g->reg85);
+		  maven_set_reg(md->client, 0x86, g->reg86);
+		  maven_set_reg(md->client, 0x87, g->reg87);
+		  maven_set_reg(md->client, 0x88, g->reg88);
+		  maven_set_reg(md->client, 0x89, g->reg89);
+		  maven_set_reg(md->client, 0x8a, g->reg8a);
+		  maven_set_reg(md->client, 0x8b, g->reg8b);
+		}
+		break;
+		case MATROXFB_CID_TESTOUT:
+		{
+			unsigned char val 
+			  = maven_get_reg (md->client,0x8d);
+			if (p->value) val |= 0x10;
+			else          val &= ~0x10;
+			maven_set_reg (md->client, 0x8d, val);
+		}
+		break;
+		case MATROXFB_CID_DEFLICKER:
+		{
+		  maven_set_reg(md->client, 0x93, maven_compute_deflicker(md));
+		}
+		break;
+	}
+	
+
+	return 0;
+}
+
+static int maven_get_control (struct maven_data* md, 
+			      struct matroxfb_control *p) {
+	int i;
+	
+	i = get_ctrl_id(p->id);
+	if (i < 0) return -EINVAL;
+	p->value = *get_ctrl_ptr(md, i);
 	return 0;
 }
 
@@ -890,56 +1155,73 @@
 }
 
 static int maven_out_start(void* md) {
-	return maven_resync(md);
+	return maven_start(md);
 }
 
-static void maven_out_incuse(void* md) {
-	if (md)
-		i2c_inc_use_client(((struct maven_data*)md)->client);
+static int maven_out_verify_mode(void* md, u_int32_t arg) {
+	switch (arg) {
+		case MATROXFB_OUTPUT_MODE_PAL:
+		case MATROXFB_OUTPUT_MODE_NTSC:
+		case MATROXFB_OUTPUT_MODE_MONITOR:
+			return 0;
+	}
+	return -EINVAL;
 }
 
-static void maven_out_decuse(void* md) {
-	if (md)
-		i2c_dec_use_client(((struct maven_data*)md)->client);
+static int maven_out_get_queryctrl(void* md, struct matroxfb_queryctrl* p) {
+        return maven_get_queryctrl(md, p);
 }
 
-static int maven_out_set_mode(void* md, u_int32_t arg) {
-	return maven_set_output_mode(md, arg);
+static int maven_out_get_ctrl(void* md, struct matroxfb_control* p) {
+	return maven_get_control(md, p);
 }
 
-static int maven_out_get_mode(void* md, u_int32_t* arg) {
-	return maven_get_output_mode(md, arg);
+static int maven_out_set_ctrl(void* md, struct matroxfb_control* p) {
+	return maven_set_control(md, p);
 }
 
 static struct matrox_altout maven_altout = {
-	maven_out_compute,
-	maven_out_program,
-	maven_out_start,
-	maven_out_incuse,
-	maven_out_decuse,
-	maven_out_set_mode,
-	maven_out_get_mode
+	.owner   = THIS_MODULE,
+	.name	 = "Secondary output",
+	.compute = maven_out_compute,
+	.program = maven_out_program,
+	.start   = maven_out_start,
+	.verifymode = maven_out_verify_mode,
+	.getqueryctrl = maven_out_get_queryctrl,
+	.getctrl = maven_out_get_ctrl,
+	.setctrl = maven_out_set_ctrl,
 };
 
 static int maven_init_client(struct i2c_client* clnt) {
 	struct i2c_adapter* a = clnt->adapter;
 	struct maven_data* md = clnt->data;
-	struct matroxfb_dh_maven_info* m2info __attribute__((unused)) = ((struct i2c_bit_adapter*)a)->minfo;
-	MINFO_FROM(m2info->primary_dev);
+	MINFO_FROM(list_entry(a, struct i2c_bit_adapter, adapter)->minfo);
 
-	md->mode = MODE_MONITOR;
 	md->primary_head = MINFO;
 	md->client = clnt;
 	down_write(&ACCESS_FBINFO(altout.lock));
-	ACCESS_FBINFO(altout.device) = md;
-	ACCESS_FBINFO(altout.output) = &maven_altout;
+	ACCESS_FBINFO(outputs[1]).output = &maven_altout;
+	ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
+	ACCESS_FBINFO(outputs[1]).data = md;
+	ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
 	up_write(&ACCESS_FBINFO(altout.lock));
-	ACCESS_FBINFO(output.all) |= MATROXFB_OUTPUT_CONN_SECONDARY;
 	if (maven_get_reg(clnt, 0xB2) < 0x14) {
 		md->version = MGATVO_B;
+		/* Tweak some things for this old chip */
 	} else {
 		md->version = MGATVO_C;
 	}
+	/*
+	 * Set all parameters to its initial values.
+	 */
+	{
+		unsigned int i;
+
+		for (i = 0; i < MAVCTRLS; ++i) {
+			*get_ctrl_ptr(md, i) = maven_controls[i].desc.default_value;
+		}
+	}
+
 	return 0;
 }
 
@@ -947,13 +1229,14 @@
 	struct maven_data* md = clnt->data;
 
 	if (md->primary_head) {
-		md->primary_head->output.all &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-		md->primary_head->output.ph &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-		md->primary_head->output.sh &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
-		down_write(&md->primary_head->altout.lock);
-		md->primary_head->altout.device = NULL;
-		md->primary_head->altout.output = NULL;
-		up_write(&md->primary_head->altout.lock);
+		MINFO_FROM(md->primary_head);
+
+		down_write(&ACCESS_FBINFO(altout.lock));
+		ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE;
+		ACCESS_FBINFO(outputs[1]).output = NULL;
+		ACCESS_FBINFO(outputs[1]).data = NULL;
+		ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+		up_write(&ACCESS_FBINFO(altout.lock));
 		md->primary_head = NULL;
 	}
 	return 0;
@@ -1066,7 +1349,7 @@
 		i2c_del_driver(&maven_driver);
 }
 
-MODULE_AUTHOR("(c) 1999-2001 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
 MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver");
 MODULE_LICENSE("GPL");
 module_init(matroxfb_maven_init);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/matrox/matroxfb_maven.h linux.20pre10-ac2/drivers/video/matrox/matroxfb_maven.h
--- linux.20pre10/drivers/video/matrox/matroxfb_maven.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/matrox/matroxfb_maven.h	2002-10-11 00:35:04.000000000 +0100
@@ -6,21 +6,15 @@
 #include <linux/i2c-algo-bit.h>
 #include "matroxfb_base.h"
 
-struct matroxfb_dh_maven_info;
-
 struct i2c_bit_adapter {
 	struct i2c_adapter		adapter;
 	int				initialized;
 	struct i2c_algo_bit_data	bac;
-	struct matroxfb_dh_maven_info  *minfo;
-};
-
-struct matroxfb_dh_maven_info {
-	struct matrox_fb_info*	primary_dev;
-
-	struct i2c_bit_adapter	maven;
-	struct i2c_bit_adapter	ddc1;
-	struct i2c_bit_adapter	ddc2;
+	struct matrox_fb_info*		minfo;
+	struct {
+		unsigned int		data;
+		unsigned int		clock;
+				      } mask;
 };
 
 #endif /* __MATROXFB_MAVEN_H__ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/matrox/matroxfb_misc.c linux.20pre10-ac2/drivers/video/matrox/matroxfb_misc.c
--- linux.20pre10/drivers/video/matrox/matroxfb_misc.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/matrox/matroxfb_misc.c	2002-09-02 00:06:57.000000000 +0100
@@ -146,6 +146,7 @@
 	if (!pixclock) pixclock = 10000;	/* 10ns = 100MHz */
 	mt->pixclock = 1000000000 / pixclock;
 	if (mt->pixclock < 1) mt->pixclock = 1;
+	mt->mnp = -1;
 	mt->dblscan = var->vmode & FB_VMODE_DOUBLE;
 	mt->interlaced = var->vmode & FB_VMODE_INTERLACED;
 	mt->HDisplay = var->xres;
@@ -360,7 +361,8 @@
 			  ((hd      & 0x100) >> 7) | /* blanking */
 			  ((hs      & 0x100) >> 6) | /* sync start */
 			   (hbe     & 0x040);	 /* end hor. blanking */
-	if (ACCESS_FBINFO(output.ph) & MATROXFB_OUTPUT_CONN_SECONDARY)
+	/* FIXME: Enable vidrst only on G400, and only if TV-out is used */
+	if (ACCESS_FBINFO(outputs[1]).src == MATROXFB_SRC_CRTC1)
 		hw->CRTCEXT[1] |= 0x88;		/* enable horizontal and vertical vidrst */
 	hw->CRTCEXT[2] =  ((vt & 0xC00) >> 10) |
 			  ((vd & 0x400) >>  8) |	/* disp end */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/matrox/matroxfb_proc.c linux.20pre10-ac2/drivers/video/matrox/matroxfb_proc.c
--- linux.20pre10/drivers/video/matrox/matroxfb_proc.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/matrox/matroxfb_proc.c	2002-09-02 00:06:57.000000000 +0100
@@ -0,0 +1,151 @@
+/*
+ *
+ * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450.
+ *
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
+ *
+ * Version: 1.64 2002/06/10
+ *
+ */
+
+#include "matroxfb_base.h"
+#include <linux/proc_fs.h>
+
+static struct proc_dir_entry* mga_pde;
+
+struct procinfo {
+	struct matrox_fb_info* info;
+	struct proc_dir_entry* pde;
+};
+
+static inline void remove_pde(struct proc_dir_entry* pde) {
+	if (pde) {
+		remove_proc_entry(pde->name, pde->parent);
+	}
+}
+
+#ifndef CONFIG_PROC_FS
+static int bios_read_proc(char* buffer, char** start, off_t offset,
+			  int size, int *eof, void *data) {
+	return 0;
+}
+
+static int pins_read_proc(char* buffer, char** start, off_t offset,
+			  int size, int *eof, void *data) {
+	return 0;
+}
+#else
+/* This macro frees the machine specific function from bounds checking and
+ * this like that... */
+#define PRINT_PROC(fmt,args...)					\
+	do {							\
+		len += sprintf(buffer+len, fmt, ##args );	\
+		if (begin + len > offset + size)		\
+			break;					\
+		if (begin + len < offset) {			\
+			begin += len;				\
+			len = 0;				\
+		}						\
+	} while(0)
+
+static int bios_read_proc(char* buffer, char** start, off_t offset,
+			  int size, int *eof, void *data) {
+	int len = 0;
+	off_t begin = 0;
+	struct matrox_bios* bd = data;
+
+	do {
+		*eof = 0;
+		if (bd->bios_valid) {
+			PRINT_PROC("BIOS:   %u.%u.%u\n", bd->version.vMaj, bd->version.vMin, bd->version.vRev);
+			PRINT_PROC("Output: 0x%02X\n", bd->output.state);
+			PRINT_PROC("TVOut:  %s\n", bd->output.tvout?"yes":"no");
+			PRINT_PROC("PINS:   %s\n", bd->pins_len ? "found" : "not found");
+			PRINT_PROC("Info:   %p\n", bd);
+		} else {
+			PRINT_PROC("BIOS:   Invalid\n");
+		}
+		*eof = 1;
+	} while (0);
+	if (offset >= begin + len)
+		return 0;
+	*start = buffer + (offset - begin);
+	return size < begin + len - offset ? size : begin + len - offset;
+}
+
+static int pins_read_proc(char* buffer, char** start, off_t offset,
+			  int size, int *eof, void *data) {
+	struct matrox_bios* bd = data;
+	
+	if (offset >= bd->pins_len) {
+		*eof = 1;
+		return 0;
+	}
+	if (offset + size >= bd->pins_len) {
+		size = bd->pins_len - offset;
+		*eof = 1;
+	}
+	memcpy(buffer, bd->pins + offset, size);
+	*start = buffer;
+	return size;
+}
+#endif /* CONFIG_PROC_FS */
+
+static void* matroxfb_proc_probe(struct matrox_fb_info* minfo) {
+	struct procinfo* binfo;
+	char b[10];
+
+	binfo = (struct procinfo*)kmalloc(sizeof(*binfo), GFP_KERNEL);
+	if (!binfo) {
+		printk(KERN_ERR "matroxfb_proc: Not enough memory for /proc control structs\n");
+		return NULL;
+	}
+	binfo->info = minfo;
+	sprintf(b, "fb%u", GET_FB_IDX(minfo->fbcon.node));
+	binfo->pde = proc_mkdir(b, mga_pde);
+	if (binfo->pde) {
+		create_proc_read_entry("bios", 0, binfo->pde, bios_read_proc, &minfo->bios);
+		if (minfo->bios.pins_len) {
+			struct proc_dir_entry* p = create_proc_read_entry("pins", 0, binfo->pde, pins_read_proc, &minfo->bios);
+			if (p) {
+				p->size = minfo->bios.pins_len;
+			}
+		}
+	}
+	return binfo;
+}
+
+static void matroxfb_proc_remove(struct matrox_fb_info* minfo, void* binfoI) {
+	struct procinfo* binfo = binfoI;
+
+	if (binfo->pde) {
+		remove_proc_entry("pins", binfo->pde);
+		remove_proc_entry("bios", binfo->pde);
+		remove_pde(binfo->pde);
+	}
+	kfree(binfo);
+}
+
+static struct matroxfb_driver procfn = {
+	.name =		"Matrox /proc driver",
+	.probe =	matroxfb_proc_probe,
+	.remove =	matroxfb_proc_remove
+};
+
+static int matroxfb_proc_init(void) {
+	mga_pde = proc_mkdir("driver/mga", NULL);
+	matroxfb_register_driver(&procfn);
+	return 0;
+}
+
+static void matroxfb_proc_exit(void) {
+	matroxfb_unregister_driver(&procfn);
+	remove_pde(mga_pde);
+}
+
+MODULE_AUTHOR("(c) 2001-2002 Petr Vandrovec <vandrove@vc.cvut.cz>");
+MODULE_DESCRIPTION("Matrox /proc driver");
+MODULE_LICENSE("GPL");
+module_init(matroxfb_proc_init);
+module_exit(matroxfb_proc_exit);
+/* we do not have __setup() */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/matrox/matroxfb_Ti3026.c linux.20pre10-ac2/drivers/video/matrox/matroxfb_Ti3026.c
--- linux.20pre10/drivers/video/matrox/matroxfb_Ti3026.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/matrox/matroxfb_Ti3026.c	2002-09-02 00:06:57.000000000 +0100
@@ -2,11 +2,11 @@
  *
  * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
  *
- * (c) 1998,1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz>
+ * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz>
  *
  * Portions Copyright (c) 2001 Matrox Graphics Inc.
  *
- * Version: 1.62 2000/11/29
+ * Version: 1.64 2002/06/10
  *
  * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
  *
@@ -84,6 +84,7 @@
 #include "matroxfb_Ti3026.h"
 #include "matroxfb_misc.h"
 #include "matroxfb_accel.h"
+#include <linux/matroxfb.h>
 
 #ifdef CONFIG_FB_MATROX_MILLENIUM
 #define outTi3026 matroxfb_DAC_out
@@ -811,6 +812,11 @@
 	ti3026_ramdac_init(PMINFO2);
 }
 
+static struct matrox_altout ti3026_output = {
+	.owner   = THIS_MODULE,
+	.name	 = "Primary output",
+};
+
 static int Ti3026_preinit(WPMINFO2) {
 	static const int vxres_mill2[] = { 512,        640, 768,  800,  832,  960,
 					  1024, 1152, 1280,      1600, 1664, 1920,
@@ -829,6 +835,11 @@
 	ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1;
 	ACCESS_FBINFO(cursor.timer.function) = matroxfb_ti3026_flashcursor;
 
+	ACCESS_FBINFO(outputs[0]).data = MINFO;
+	ACCESS_FBINFO(outputs[0]).output = &ti3026_output;
+	ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1;
+	ACCESS_FBINFO(outputs[0]).mode = MATROXFB_OUTPUT_MODE_MONITOR;
+
 	if (ACCESS_FBINFO(devflags.noinit))
 		return 0;
 	/* preserve VGA I/O, BIOS and PPC */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/modedb.c linux.20pre10-ac2/drivers/video/modedb.c
--- linux.20pre10/drivers/video/modedb.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/modedb.c	2002-08-06 15:42:11.000000000 +0100
@@ -42,6 +42,20 @@
 #define DEFAULT_MODEDB_INDEX	0
 
 static struct fb_videomode modedb[] __initdata = {
+#if defined(CONFIG_FB_ATY_CT_VAIO_LCD) 
+    {
+	/* 1024x480 @ 65 Hz */
+	NULL, 65, 1024, 480, 25203, 24, 24, 1, 17, 144, 4,
+	0, FB_VMODE_NONINTERLACED
+    },
+#endif /* CONFIG_FB_ATY_CT_VAIO_LCD */
+#if defined(CONFIG_FB_RADEON_VAIO_LCD)
+    { 
+      /* 1280x600 @ 72 Hz, 45.288 kHz hsync */
+	NULL, 72, 1280, 600, 13940, 24, 24, 23, 1, 256, 5,
+	FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
+    },
+#endif /* CONFIG_FB_RADEON_VAIO_LCD */
     {
 	/* 640x400 @ 70 Hz, 31.5 kHz hsync */
 	NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2,
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/radeonfb.c linux.20pre10-ac2/drivers/video/radeonfb.c
--- linux.20pre10/drivers/video/radeonfb.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/radeonfb.c	2002-09-18 12:29:07.000000000 +0100
@@ -22,6 +22,13 @@
  *
  *	Special thanks to ATI DevRel team for their hardware donations.
  *
+ * 	2002-04-02	Added MTRR support. Fixed 8bpp acceleration. Added
+ * 			acceleration for 16/32bpp. Applied fix from XFree86
+ * 			for hard crash on accelerator reset. Fixed up the
+ * 			colour stuff. Peter Horton <pdh@colonel-panic.org>
+ * 	2002-04-10	Make ypan work. More colour fixes, all modes >8bpp
+ * 			now DIRECTCOLOR. Match up CRTC and accelerator
+ * 			pitch.
  */
 
 
@@ -73,18 +80,24 @@
 #include <video/fbcon.h> 
 #include <video/fbcon-cfb8.h>
 #include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
 #include <video/fbcon-cfb32.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
 
 #include "radeon.h"
 
 
-#define DEBUG	0
+#define FIX_DEPTH_15		1
+
+#define DEBUG			0
+
+#define _RTRACE(f,a...)		do{printk("radeonfb: " f "\n", ##a);}while(0)
 
 #if DEBUG
-#define RTRACE		printk
+#define RTRACE(f,a...)		_RTRACE(f,##a)
 #else
-#define RTRACE		if(0) printk
+#define RTRACE(f,a...)
 #endif
 
 
@@ -301,17 +314,16 @@
 
 	struct ram_info ram;
 
+#if 0
         u32 hack_crtc_ext_cntl;
         u32 hack_crtc_v_sync_strt_wid;
+#endif
 
 #if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
         union {
 #if defined(FBCON_HAS_CFB16)
                 u_int16_t cfb16[16];
 #endif
-#if defined(FBCON_HAS_CFB24)
-                u_int32_t cfb24[16];
-#endif  
 #if defined(FBCON_HAS_CFB32)
                 u_int32_t cfb32[16];
 #endif  
@@ -476,11 +488,10 @@
 }
 
 
-static inline int var_to_depth(const struct fb_var_screeninfo *var)
+static __inline__ int var_to_depth(const struct fb_var_screeninfo *var)
 {
-	if (var->bits_per_pixel != 16)
-		return var->bits_per_pixel;
-	return (var->green.length == 6) ? 16 : 15;
+	return (var->bits_per_pixel == 16 && var->green.length == 5)? 
+	    15 : var->bits_per_pixel;
 }
 
 
@@ -533,6 +544,7 @@
 #define radeon_engine_reset()		_radeon_engine_reset(rinfo)
 
 
+#if 0
 static __inline__ u8 radeon_get_post_div_bitval(int post_div)
 {
         switch (post_div) {
@@ -554,6 +566,7 @@
                         return 0x02;
         }
 }
+#endif
 
 
 
@@ -596,14 +609,25 @@
         
 static char fontname[40] __initdata;
 static char *mode_option __initdata;
-static char noaccel __initdata = 0;
+static char noaccel /*__initdata*/ = 0;
+static char fb16fix = 0;
 static int panel_yres __initdata = 0;
 static char force_dfp __initdata = 0;
 static struct radeonfb_info *board_list = NULL;
+#ifdef CONFIG_MTRR
+static int enable_mtrr = 1;
+static int mtrr_handle;
+#endif
 
 #ifdef FBCON_HAS_CFB8
 static struct display_switch fbcon_radeon8;
 #endif
+#ifdef FBCON_HAS_CFB16
+static struct display_switch fbcon_radeon16;
+#endif
+#ifdef FBCON_HAS_CFB32
+static struct display_switch fbcon_radeon32;
+#endif
 
 
 /*
@@ -733,6 +757,12 @@
 			force_dfp = 1;
 		} else if (!strncmp(this_opt, "panel_yres:", 11)) {
 			panel_yres = simple_strtoul((this_opt+11), NULL, 0);
+		} else if (!strncmp(this_opt, "fb16fix", 7)) {
+			fb16fix = 1;
+#ifdef CONFIG_MTRR
+		} else if (!strncmp(this_opt, "nomtrr", 6)) {
+			enable_mtrr = 0;
+#endif
                 } else
 			mode_option = this_opt;
         }
@@ -757,7 +787,7 @@
 	u32 tmp;
 	int i, j;
 
-	RTRACE("radeonfb_pci_register BEGIN\n");
+	RTRACE("radeonfb_pci_register BEGIN");
 
 	rinfo = kmalloc (sizeof (struct radeonfb_info), GFP_KERNEL);
 	if (!rinfo) {
@@ -871,6 +901,14 @@
 	/* mem size is bits [28:0], mask off the rest */
 	rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK;
 
+	/* According to XFree86 4.2.0, some production M6's return 0
+	   for 8MB. */
+	if (rinfo->video_ram == 0 && 
+	    (pdev->device == PCI_DEVICE_ID_RADEON_LY || 
+	     pdev->device == PCI_DEVICE_ID_RADEON_LZ)) {
+	    rinfo->video_ram = 8192 * 1024;
+	  }
+
 	/* ram type */
 	tmp = INREG(MEM_SDRAM_MODE_REG);
 	switch ((MEM_CFG_TYPE & tmp) >> 30) {
@@ -920,7 +958,7 @@
 	rinfo->bios_seg = radeon_find_rom(rinfo);
 	radeon_get_pllinfo(rinfo, rinfo->bios_seg);
 
-	RTRACE("radeonfb: probed %s %dk videoram\n", (rinfo->ram_type), (rinfo->video_ram/1024));
+	RTRACE("probed %s %dk videoram", (rinfo->ram_type), (rinfo->video_ram/1024));
 
 #if !defined(__powerpc__)
 	radeon_get_moninfo(rinfo);
@@ -1004,6 +1042,15 @@
 		return -ENODEV;
 	}
 
+#ifdef CONFIG_MTRR
+	if (enable_mtrr) {
+	    mtrr_handle = mtrr_add(rinfo->fb_base_phys, rinfo->video_ram, MTRR_TYPE_WRCOMB, 1);
+	    printk("radeonfb: MTRR enabled\n");
+	}
+#endif
+
+	/* XXX look at this re pitch :pdh */
+
 	if (!noaccel) {
 		/* initialize the engine */
 		radeon_engine_init (rinfo);
@@ -1035,7 +1082,7 @@
 			GET_MON_NAME(rinfo->crtDisp_type));
 	}
 
-	RTRACE("radeonfb_pci_register END\n");
+	RTRACE("radeonfb_pci_register END");
 
 	return 0;
 }
@@ -1052,6 +1099,12 @@
 	/* restore original state */
         radeon_write_mode (rinfo, &rinfo->init_state);
  
+#ifdef CONFIG_MTRR
+	if (enable_mtrr) {
+	    mtrr_del(mtrr_handle, rinfo->fb_base_phys, rinfo->video_ram);
+	    printk("radeonfb: MTRR disabled\n");
+	}
+#endif
         unregister_framebuffer ((struct fb_info *) rinfo);
                 
         iounmap ((void*)rinfo->mmio_base);
@@ -1163,7 +1216,7 @@
         	rinfo->pll.ppll_min = pll.PCLK_min_freq;
         	rinfo->pll.ppll_max = pll.PCLK_max_freq;
 
-		printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d from BIOS\n",
+		_RTRACE("ref_clk=%d, ref_div=%d, xclk=%d from BIOS",
 			rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk);
 	} else {
 #ifdef CONFIG_ALL_PPC
@@ -1183,7 +1236,7 @@
 			rinfo->pll.ppll_min = 12000;
 			rinfo->pll.ppll_max = 35000;
 
-			printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d from OF\n",
+			_RTRACE("ref_clk=%d, ref_div=%d, xclk=%d from OF",
 				rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk);
 
 			return;
@@ -1218,7 +1271,7 @@
 				break;
 		}
 
-		printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d defaults\n",
+		_RTRACE("ref_clk=%d, ref_div=%d, xclk=%d defaults",
 			rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk);
 	}
 }
@@ -1277,7 +1330,7 @@
 {
 #ifdef CONFIG_ALL_PPC
 	if (!radeon_get_EDID_OF(rinfo))
-		RTRACE("radeonfb: could not retrieve EDID from OF\n");
+		RTRACE("radeonfb: could not retrieve EDID from OF");
 #else
 	/* XXX use other methods later */
 #endif
@@ -1509,6 +1562,8 @@
 		rinfo->vSync_width = (unsigned short) ((tmp & FP_V_SYNC_WID_MASK) >>
 					FP_V_SYNC_WID_SHIFT);
 
+		/* XXX some more stuff needs to go here :pdh */
+
 		return 1;
 	}
 
@@ -1548,13 +1603,10 @@
 	radeon_fifo_wait (1);
 	OUTREG(DSTCACHE_MODE, 0);
 
-	/* XXX */
-	rinfo->pitch = ((rinfo->xres * (rinfo->bpp / 8) + 0x3f)) >> 6;
-
 	radeon_fifo_wait (1);
 	temp = INREG(DEFAULT_PITCH_OFFSET);
 	OUTREG(DEFAULT_PITCH_OFFSET, ((temp & 0xc0000000) | 
-				      (rinfo->pitch << 0x16)));
+				      (rinfo->pitch << 16)));
 
 	radeon_fifo_wait (1);
 	OUTREGP(DP_DATATYPE, 0, ~HOST_BIG_ENDIAN_EN);
@@ -1709,30 +1761,22 @@
         switch (disp->var.bits_per_pixel) {
 #ifdef FBCON_HAS_CFB8
                 case 8:
-                        disp->dispsw = &fbcon_cfb8;
+                        disp->dispsw = accel ? &fbcon_radeon8 : &fbcon_cfb8;
                         disp->visual = FB_VISUAL_PSEUDOCOLOR;
                         disp->line_length = disp->var.xres_virtual;
                         break;
 #endif
 #ifdef FBCON_HAS_CFB16
                 case 16:
-                        disp->dispsw = &fbcon_cfb16;
+                        disp->dispsw = accel ? &fbcon_radeon16 : &fbcon_cfb16;
                         disp->dispsw_data = &rinfo->con_cmap.cfb16;
                         disp->visual = FB_VISUAL_DIRECTCOLOR;
                         disp->line_length = disp->var.xres_virtual * 2;
                         break;
 #endif  
-#ifdef FBCON_HAS_CFB32       
-                case 24:
-                        disp->dispsw = &fbcon_cfb24;
-                        disp->dispsw_data = &rinfo->con_cmap.cfb24;
-                        disp->visual = FB_VISUAL_DIRECTCOLOR;
-                        disp->line_length = disp->var.xres_virtual * 4;
-                        break;
-#endif
 #ifdef FBCON_HAS_CFB32
                 case 32:
-                        disp->dispsw = &fbcon_cfb32;
+                        disp->dispsw = accel ? &fbcon_radeon32 : &fbcon_cfb32;
                         disp->dispsw_data = &rinfo->con_cmap.cfb32;
                         disp->visual = FB_VISUAL_DIRECTCOLOR;
                         disp->line_length = disp->var.xres_virtual * 4;
@@ -1742,8 +1786,6 @@
                         printk ("radeonfb: setting fbcon_dummy renderer\n");
                         disp->dispsw = &fbcon_dummy;
         }
-                
-        return;
 }
                         
 
@@ -1765,6 +1807,7 @@
 
 
 
+#if 0
 static int radeonfb_do_maximize(struct radeonfb_info *rinfo,
                                 struct fb_var_screeninfo *var,
                                 struct fb_var_screeninfo *v,
@@ -1825,9 +1868,18 @@
                                 
         return 0;
 }
+#endif
                         
 
 
+static void set_palette_entry(struct radeonfb_info *rinfo, unsigned idx, unsigned red, unsigned grn, unsigned blu)
+{
+	OUTREG(PALETTE_INDEX, idx);
+	OUTREG(PALETTE_DATA, (red << 16) | (grn << 8) | blu);
+
+	udelay(1);	/* is this necessary ? */
+}
+
 /*
  * fb ops
  */
@@ -1850,7 +1902,7 @@
         fix->type_aux = disp->type_aux;
         fix->visual = disp->visual;
 
-        fix->xpanstep = 8;
+        fix->xpanstep = 0;
         fix->ypanstep = 1;
         fix->ywrapstep = 0;
         
@@ -1886,7 +1938,7 @@
         struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
         struct display *disp;
         struct fb_var_screeninfo v;
-        int nom, den, accel;
+        int accel, bytpp, pitch;
         unsigned chgvar = 0;
 
         disp = (con < 0) ? rinfo->info.disp : &fb_display[con];
@@ -1909,110 +1961,97 @@
         switch (v.bits_per_pixel) {
 		case 0 ... 8:
 			v.bits_per_pixel = 8;
-			break;
-		case 9 ... 16:
-			v.bits_per_pixel = 16;
-			break;
-		case 17 ... 24:
-			v.bits_per_pixel = 24;
-			break;
-		case 25 ... 32:
-			v.bits_per_pixel = 32;
-			break;
-		default:
-			return -EINVAL;
-	}
-
-	switch (var_to_depth(&v)) {
-#ifdef FBCON_HAS_CFB8
-                case 8:
-                        nom = den = 1;
-                        disp->line_length = v.xres_virtual;
-                        disp->visual = FB_VISUAL_PSEUDOCOLOR; 
                         v.red.offset = v.green.offset = v.blue.offset = 0;
                         v.red.length = v.green.length = v.blue.length = 8;
                         v.transp.offset = v.transp.length = 0;
-                        break;
-#endif
-                        
-#ifdef FBCON_HAS_CFB16
-		case 15:
-			nom = 2;
-			den = 1;
-			disp->line_length = v.xres_virtual * 2;
-			disp->visual = FB_VISUAL_DIRECTCOLOR;
-			v.red.offset = 10;
-			v.green.offset = 5;
-			v.red.offset = 0;
-			v.red.length = v.green.length = v.blue.length = 5;
-			v.transp.offset = v.transp.length = 0;
 			break;
-                case 16:
-                        nom = 2;
-                        den = 1;
-                        disp->line_length = v.xres_virtual * 2;
-                        disp->visual = FB_VISUAL_DIRECTCOLOR;
-                        v.red.offset = 11;
+		case 9 ... 16:
+#if FIX_DEPTH_15
+			if(v.bits_per_pixel < 16)
+				v.green.length = 5;
+#endif
+			if(v.green.length != 5 && v.green.length != 6)
+				v.green.length = 5;
+			v.bits_per_pixel = 16;
+                        v.red.offset = v.green.length + 5;
                         v.green.offset = 5;
                         v.blue.offset = 0;
                         v.red.length = 5;
-                        v.green.length = 6;
                         v.blue.length = 5;
                         v.transp.offset = v.transp.length = 0;
-                        break;  
-#endif
-                        
-#ifdef FBCON_HAS_CFB24
-                case 24:
-                        nom = 4;
-                        den = 1;
-                        disp->line_length = v.xres_virtual * 3;
-                        disp->visual = FB_VISUAL_DIRECTCOLOR;
+			break;
+		case 17 ... 32:
+			v.bits_per_pixel = 32;
                         v.red.offset = 16;
                         v.green.offset = 8;
                         v.blue.offset = 0;
                         v.red.length = v.blue.length = v.green.length = 8;
+                        /* v.transp.offset = 24; v.transp.length = 8; */
                         v.transp.offset = v.transp.length = 0;
-                        break;
-#endif
-#ifdef FBCON_HAS_CFB32
-                case 32:
-                        nom = 4;
-                        den = 1;
-                        disp->line_length = v.xres_virtual * 4;
-                        disp->visual = FB_VISUAL_DIRECTCOLOR;
-                        v.red.offset = 16;
-                        v.green.offset = 8;
-                        v.blue.offset = 0;
-                        v.red.length = v.blue.length = v.green.length = 8;
-                        v.transp.offset = 24;
-                        v.transp.length = 8;
-                        break;
-#endif
-                default:
-                        printk ("radeonfb: mode %dx%dx%d rejected, color depth invalid\n",
-                                var->xres, var->yres, var->bits_per_pixel);
-                        return -EINVAL;
-        }
+			break;
+		default:
+			return -EINVAL;
+	}
+
+        v.red.msb_right = v.green.msb_right = v.blue.msb_right = v.transp.msb_right = 0;
+
+	bytpp = v.bits_per_pixel >> 3;
+
+	if(v.xres > v.xres_virtual)
+		v.xres_virtual = v.xres;
+	if(v.yres > v.yres_virtual)
+		v.yres_virtual = v.yres;
+
+	/* XXX this is probably wrong for 24bpp, if we ever get it working :pdh */
+
+	pitch = (v.xres_virtual * bytpp + 63) & ~63;
+
+	if(pitch >= 8192)
+		return -EINVAL;
+
+	v.xres_virtual = pitch / bytpp;
+
+	if(v.xres_virtual < v.xres)
+		v.xres = v.xres_virtual;
+	
+	v.yres_virtual = rinfo->video_ram / pitch;
+
+	/* XXX there is some limit here, I chose 8192 :pdh */
 
+	if(v.yres_virtual >= 8192)
+		v.yres_virtual = 8191;
+
+	if(v.yres_virtual < v.yres)
+		v.yres = v.yres_virtual;
+
+#if 0
         if (radeonfb_do_maximize(rinfo, var, &v, nom, den) < 0)
                 return -EINVAL;  
+#endif
                 
+	if(v.xoffset)
+		return -EINVAL;
+
         if (v.xoffset < 0)
                 v.xoffset = 0;
         if (v.yoffset < 0)
                 v.yoffset = 0;
          
         if (v.xoffset > v.xres_virtual - v.xres)
-                v.xoffset = v.xres_virtual - v.xres - 1;
+		return -EINVAL;
                         
         if (v.yoffset > v.yres_virtual - v.yres)
-                v.yoffset = v.yres_virtual - v.yres - 1;
-         
-        v.red.msb_right = v.green.msb_right = v.blue.msb_right =
-                          v.transp.offset = v.transp.length =
-                          v.transp.msb_right = 0;
+		return -EINVAL;
                         
+	/* XXX this shouldn't be here :pdh */
+
+	disp->visual = (v.bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR);
+	disp->line_length = v.xres_virtual * bytpp;
+	disp->ypanstep = 1;
+	disp->ywrapstep = 0;
+	disp->var.yres_virtual = v.yres_virtual;
+
+
         switch (v.activate & FB_ACTIVATE_MASK) {
                 case FB_ACTIVATE_TEST:
                         return 0;
@@ -2024,15 +2063,13 @@
         }
         
         memcpy (&disp->var, &v, sizeof (v));
-        
+
         if (chgvar) {     
-                radeon_set_dispsw(rinfo, disp);
 
-                if (noaccel)
-                        disp->scrollmode = SCROLL_YREDRAW;
-                else
-                        disp->scrollmode = 0;
-                
+		disp->scrollmode = accel ? 0 : SCROLL_YREDRAW;
+
+		radeon_set_dispsw(rinfo, disp);
+
                 if (info && info->changevar)
                         info->changevar(con);
         }
@@ -2099,6 +2136,8 @@
                                  struct fb_info *info)
 {
         struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
+
+#if 0
         u32 offset, xoffset, yoffset;
                 
         xoffset = (var->xoffset + 7) & ~7;
@@ -2111,7 +2150,18 @@
         offset = ((yoffset * var->xres + xoffset) * var->bits_per_pixel) >> 6;
          
         OUTREG(CRTC_OFFSET, offset);
+#endif
+
+	/* XXX no X pan for the moment :pdh */
+
+	if(var->xoffset)
+		return -EINVAL;
         
+	if(var->yoffset + var->yres > var->yres_virtual)
+		return -EINVAL;
+
+	OUTREG(CRTC_OFFSET, var->yoffset * rinfo->pitch);
+
         return 0;
 }
 
@@ -2150,12 +2200,14 @@
                 do_install_cmap(con, info);
         }       
 
+#if 0
         /* XXX absurd hack for X to restore console */
         {   
 		OUTREGP(CRTC_EXT_CNTL, rinfo->hack_crtc_ext_cntl,
 			CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS);
                 OUTREG(CRTC_V_SYNC_STRT_WID, rinfo->hack_crtc_v_sync_strt_wid);
         }
+#endif
 
         return 0;
 }
@@ -2220,18 +2272,7 @@
 
 static int radeon_get_cmap_len (const struct fb_var_screeninfo *var)
 {
-        int rc = 256;            /* reasonable default */
-        
-        switch (var_to_depth(var)) {
-                case 15:
-                        rc = 32;
-                        break;
-		case 16:
-			rc = 64;
-			break;
-        }
-                
-        return rc;
+	return var->bits_per_pixel == 8 ? 256 : 16;
 }
 
 
@@ -2245,10 +2286,9 @@
 	if (regno > 255)
 		return 1;
      
- 	*red = (rinfo->palette[regno].red<<8) | rinfo->palette[regno].red; 
-    	*green = (rinfo->palette[regno].green<<8) | rinfo->palette[regno].green;
-    	*blue = (rinfo->palette[regno].blue<<8) | rinfo->palette[regno].blue;
-    	*transp = 0;
+ 	*red	= (unsigned) rinfo->palette[regno].red << 8;
+    	*green	= (unsigned) rinfo->palette[regno].green << 8;
+    	*blue	= (unsigned) rinfo->palette[regno].blue << 8;
 
 	return 0;
 }                            
@@ -2256,79 +2296,95 @@
 
 
 static int radeon_setcolreg (unsigned regno, unsigned red, unsigned green,
-                             unsigned blue, unsigned transp, struct fb_info *info)
+                             unsigned blue, unsigned alpha, struct fb_info *info)
 {
         struct radeonfb_info *rinfo = (struct radeonfb_info *) info;
-	u32 pindex;
 
-	if (regno > 255)
+	if(regno > 255)
 		return 1;
 
-	red >>= 8;
-	green >>= 8;
-	blue >>= 8;
-	rinfo->palette[regno].red = red;
-	rinfo->palette[regno].green = green;
-	rinfo->palette[regno].blue = blue;
+	red	>>= 8;
+	green	>>= 8;
+	blue	>>= 8;
+	alpha	>>= 8;
+
+	rinfo->palette[regno].red	= red;
+	rinfo->palette[regno].green	= green;
+	rinfo->palette[regno].blue	= blue;
+
+	/* ugly hack so that the software cursor works */
+
+	if(regno == 0) {
+		switch(rinfo->depth) {
+
+			case 16:
+				radeon_setcolreg(63, ~0, ~0, ~0, 0, info);
+				/* */
 
-        /* default */
-        pindex = regno;
-        
-	if (rinfo->bpp == 16) {
-		pindex = regno * 8;
+			case 15:
+				radeon_setcolreg(31, ~0, ~0, ~0, 0, info);
+				break;
 
-		if (rinfo->depth == 16 && regno > 63)
-			return 1;
-		if (rinfo->depth == 15 && regno > 31)
-			return 1;
+			case 32:
+				radeon_setcolreg(255, ~0, ~0, ~0, 0, info);
+				break;
+		}
+	}
 
-		/* For 565, the green component is mixed one order below */
-		if (rinfo->depth == 16) {
-	                OUTREG(PALETTE_INDEX, pindex>>1);
-       	         	OUTREG(PALETTE_DATA, (rinfo->palette[regno>>1].red << 16) |
-                        	(green << 8) | (rinfo->palette[regno>>1].blue));
-                	green = rinfo->palette[regno<<1].green;
-        	}
-	}
-
-	if (rinfo->depth != 16 || regno < 32) {
-		OUTREG(PALETTE_INDEX, pindex);
-		OUTREG(PALETTE_DATA, (red << 16) | (green << 8) | blue);
+	switch(rinfo->depth) {
+
+		case 15:
+			if(regno > 31)
+				return 1;
+			if(regno < 16)
+				rinfo->con_cmap.cfb16[regno] = (regno << 10) | (regno << 5) | regno;
+			regno <<= 3;
+			break;
+
+		case 16:
+
+			if(fb16fix) {
+
+				/* this is just another format of 15 bit mode, the LSB of the   *
+				 * green pixel data is ignored. this is required for "fbtv" and *
+				 * other apps to work correctly at 16bpp, but it means you land *
+				 * up with a sick looking boot logo. the real fix is to run at  *
+				 * 15bpp when you want to use those apps                   :pdh */
+
+				if(regno > 31)
+					return 1;
+				if(regno < 16)
+					rinfo->con_cmap.cfb16[regno] = (regno << 11) | (regno << 6) | regno;
+				regno <<= 3;
+				set_palette_entry(rinfo, regno | 4, red, green, blue);
+
+			} else {
+
+				if(regno > 63)
+					return 1;
+				if(regno < 16)
+					rinfo->con_cmap.cfb16[regno] = (regno << 11) | (regno << 5) | regno;
+				set_palette_entry(rinfo, regno << 2, rinfo->palette[regno >> 1].red,
+					green, rinfo->palette[regno >> 1].blue);
+				if(regno > 31)
+					return 0;
+				regno <<= 1;
+				green = rinfo->palette[regno].green;
+				regno <<= 2;
+			}
+			break;
+
+		case 32:
+			if(regno < 16)
+				rinfo->con_cmap.cfb32[regno] = (regno << 16) | (regno << 8) | regno;
+			break;
 	}
 
- 	if (regno < 16) {
-        	switch (rinfo->depth) {
-#ifdef FBCON_HAS_CFB16
-		        case 15:
-        			rinfo->con_cmap.cfb16[regno] = (regno << 10) | (regno << 5) |
-				                       	 	  regno;   
-			        break;
-		        case 16:
-        			rinfo->con_cmap.cfb16[regno] = (regno << 11) | (regno << 5) |
-				                       	 	  regno;   
-			        break;
-#endif
-#ifdef FBCON_HAS_CFB24
-                        case 24:
-                                rinfo->con_cmap.cfb24[regno] = (regno << 16) | (regno << 8) | regno;
-                                break;
-#endif
-#ifdef FBCON_HAS_CFB32
-	        	case 32: {
-            			u32 i;    
-   
-  		       		i = (regno << 8) | regno;
-            			rinfo->con_cmap.cfb32[regno] = (i << 16) | i;
-		        	break;
-        		}
-#endif
-		}
-        }
+	set_palette_entry(rinfo, regno, red, green, blue);
+
 	return 0;
 }
 
-
-
 static void radeon_save_state (struct radeonfb_info *rinfo,
                                struct radeon_regs *save)
 {
@@ -2379,8 +2435,10 @@
 	int primary_mon = PRIMARY_MONITOR(rinfo);
 	int depth = var_to_depth(mode);
 
+	bytpp = mode->bits_per_pixel >> 3;
 	rinfo->xres = mode->xres;
 	rinfo->yres = mode->yres;
+	rinfo->pitch = mode->xres_virtual * bytpp;
 	rinfo->pixclock = mode->pixclock;
 
 	hSyncStart = mode->xres + mode->right_margin;
@@ -2410,9 +2468,9 @@
 	h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
 	v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
 
-	RTRACE("hStart = %d, hEnd = %d, hTotal = %d\n",
+	RTRACE("hStart = %d, hEnd = %d, hTotal = %d",
 		hSyncStart, hSyncEnd, hTotal);
-	RTRACE("vStart = %d, vEnd = %d, vTotal = %d\n",
+	RTRACE("vStart = %d, vEnd = %d, vTotal = %d",
 		vSyncStart, vSyncEnd, vTotal);
 
 	hsync_wid = (hSyncEnd - hSyncStart) / 8;
@@ -2433,7 +2491,6 @@
 	cSync = mode->sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0;
 
 	format = radeon_get_dstbpp(depth);
-	bytpp = mode->bits_per_pixel >> 3;
 
 	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD))
 		hsync_fudge = hsync_fudge_fp[format-1];
@@ -2469,7 +2526,7 @@
 	newmode.crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) |
 					 (vsync_wid << 16) | (v_sync_pol  << 23));
 
-	newmode.crtc_pitch = (mode->xres >> 3);
+	newmode.crtc_pitch = mode->xres_virtual >> 3;
 	newmode.crtc_pitch |= (newmode.crtc_pitch << 16);
 
 #if defined(__BIG_ENDIAN)
@@ -2485,12 +2542,9 @@
 	}
 #endif
 
-	rinfo->pitch = ((mode->xres * ((mode->bits_per_pixel + 1) / 8) + 0x3f)
-			& ~(0x3f)) / 64;
-
-	RTRACE("h_total_disp = 0x%x\t   hsync_strt_wid = 0x%x\n",
+	RTRACE("h_total_disp = 0x%x  hsync_strt_wid = 0x%x",
 		newmode.crtc_h_total_disp, newmode.crtc_h_sync_strt_wid);
-	RTRACE("v_total_disp = 0x%x\t   vsync_strt_wid = 0x%x\n",
+	RTRACE("v_total_disp = 0x%x  vsync_strt_wid = 0x%x",
 		newmode.crtc_v_total_disp, newmode.crtc_v_sync_strt_wid);
 
 	newmode.xres = mode->xres;
@@ -2499,8 +2553,10 @@
 	rinfo->bpp = mode->bits_per_pixel;
 	rinfo->depth = depth;
 
+#if 0
 	rinfo->hack_crtc_ext_cntl = newmode.crtc_ext_cntl;
 	rinfo->hack_crtc_v_sync_strt_wid = newmode.crtc_v_sync_strt_wid;
+#endif
 
 	if (freq > rinfo->pll.ppll_max)
 		freq = rinfo->pll.ppll_max;
@@ -2538,9 +2594,9 @@
 		newmode.ppll_div_3 = rinfo->fb_div | (post_div->bitvalue << 16);
 	}
 
-	RTRACE("post div = 0x%x\n", rinfo->post_div);
-	RTRACE("fb_div = 0x%x\n", rinfo->fb_div);
-	RTRACE("ppll_div_3 = 0x%x\n", newmode.ppll_div_3);
+	RTRACE("post div = 0x%x", rinfo->post_div);
+	RTRACE("fb_div = 0x%x", rinfo->fb_div);
+	RTRACE("ppll_div_3 = 0x%x", newmode.ppll_div_3);
 
 	/* DDA */
 	vclk_freq = round_div(rinfo->pll.ref_clk * rinfo->fb_div,
@@ -2560,8 +2616,8 @@
 	       xclk_per_trans) << (11 - useable_precision);
 	roff = xclk_per_trans_precise * (32 - 4);
 
-	RTRACE("ron = %d, roff = %d\n", ron, roff);
-	RTRACE("vclk_freq = %d, per = %d\n", vclk_freq, xclk_per_trans_precise);
+	RTRACE("ron = %d, roff = %d", ron, roff);
+	RTRACE("vclk_freq = %d, per = %d", vclk_freq, xclk_per_trans_precise);
 
 	if ((ron + rinfo->ram.rloop) >= roff) {
 		printk("radeonfb: error ron out of range\n");
@@ -2627,6 +2683,11 @@
 		newmode.tmds_crc = rinfo->init_state.tmds_crc;
 		newmode.tmds_transmitter_cntl = rinfo->init_state.tmds_transmitter_cntl;
 
+		/* XXX                                                  :pdh *
+		 * this doesn't work with some DFPs. a different driver that *
+		 * does work loads the FP CRTC registers from initial saved  *
+		 * values and doesn't tweak with tmds_transmitter_cntl ????? */
+
 		if (primary_mon == MT_LCD) {
 			newmode.lvds_gen_cntl |= (LVDS_ON | LVDS_BLON);
 			newmode.fp_gen_cntl &= ~(FP_FPON | FP_TMDS_EN);
@@ -2663,15 +2724,13 @@
 	int primary_mon = PRIMARY_MONITOR(rinfo);
 
 	/* blank screen */
-	OUTREGP(CRTC_EXT_CNTL, CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | CRTC_HSYNC_DIS,
-		~(CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | CRTC_HSYNC_DIS));
+	OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,
+		~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS));
 
 	for (i=0; i<9; i++)
 		OUTREG(common_regs[i].reg, common_regs[i].val);
 
 	OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl);
-	OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,
-		CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS);
 	OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING);
 	OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp);
 	OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid);
@@ -2749,7 +2808,7 @@
 	}
 
 	/* unblank screen */
-	OUTREG8(CRTC_EXT_CNTL + 1, 0);
+	OUTREG(CRTC_EXT_CNTL, mode->crtc_ext_cntl);
 
 	return;
 }
@@ -2973,6 +3032,8 @@
 	width *= fontwidth(p);
 	height *= fontheight(p);
 
+	dp_cntl = 0;
+
 	if (srcy < dsty) {
 		srcy += height - 1;
 		dsty += height - 1;
@@ -2999,22 +3060,8 @@
 }
 
 
-
-static void fbcon_radeon_clear(struct vc_data *conp, struct display *p,
-			       int srcy, int srcx, int height, int width)
+static void fbcon_radeon_clear(struct radeonfb_info *rinfo, int srcy, int srcx, int height, int width, u32 clr)
 {
-	struct radeonfb_info *rinfo = (struct radeonfb_info *)(p->fb_info);
-	u32 clr;
-
-	clr = attr_bgcol_ec(p, conp);
-	clr |= (clr << 8);
-	clr |= (clr << 16);
-
-	srcx *= fontwidth(p);
-	srcy *= fontheight(p);
-	width *= fontwidth(p);
-	height *= fontheight(p);
-
 	radeon_fifo_wait(6);
 	OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl |
 				    GMC_BRUSH_SOLID_COLOR |
@@ -3028,12 +3075,24 @@
 }
 
 
-
 #ifdef FBCON_HAS_CFB8
+static void fbcon_radeon8_clear(struct vc_data *conp, struct display *p,
+		int srcy, int srcx, int height, int width)
+{
+	u32 clr;
+  
+	clr = attr_bgcol_ec(p, conp);
+	clr |= clr << 8;
+
+	fbcon_radeon_clear((struct radeonfb_info *) p->fb_info, srcy * fontheight(p), srcx * fontwidth(p),
+			height * fontheight(p), width * fontwidth(p), clr | (clr << 16));
+}
+
+
 static struct display_switch fbcon_radeon8 = {
 	setup:			fbcon_cfb8_setup,
 	bmove:			fbcon_radeon_bmove,
-	clear:			fbcon_radeon_clear,
+	clear:			fbcon_radeon8_clear,
 	putc:			fbcon_cfb8_putc,
 	putcs:			fbcon_cfb8_putcs,
 	revc:			fbcon_cfb8_revc,
@@ -3041,3 +3100,48 @@
 	fontwidthmask:		FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
 };
 #endif
+
+#ifdef FBCON_HAS_CFB16
+static void fbcon_radeon16_clear(struct vc_data *conp, struct display *p,
+		int srcy, int srcx, int height, int width)
+{
+	u32 clr;
+
+	clr = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
+
+	fbcon_radeon_clear((struct radeonfb_info *) p->fb_info, srcy * fontheight(p), srcx * fontwidth(p),
+			height * fontheight(p), width * fontwidth(p), clr | (clr << 16));
+}
+
+static struct display_switch fbcon_radeon16 = {
+	setup:			fbcon_cfb16_setup,
+	bmove:			fbcon_radeon_bmove,
+	clear:			fbcon_radeon16_clear,
+	putc:			fbcon_cfb16_putc,
+	putcs:			fbcon_cfb16_putcs,
+	revc:			fbcon_cfb16_revc,
+	clear_margins:		fbcon_cfb16_clear_margins,
+	fontwidthmask:		FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+
+#ifdef FBCON_HAS_CFB32
+static void fbcon_radeon32_clear(struct vc_data *conp, struct display *p,
+		int srcy, int srcx, int height, int width)
+{
+	fbcon_radeon_clear((struct radeonfb_info *) p->fb_info, srcy * fontheight(p), srcx * fontwidth(p),
+		height * fontheight(p), width * fontwidth(p), ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)]);
+}
+
+static struct display_switch fbcon_radeon32 = {
+	setup:			fbcon_cfb32_setup,
+	bmove:			fbcon_radeon_bmove,
+	clear:			fbcon_radeon32_clear,
+	putc:			fbcon_cfb32_putc,
+	putcs:			fbcon_cfb32_putcs,
+	revc:			fbcon_cfb32_revc,
+	clear_margins:		fbcon_cfb32_clear_margins,
+  	fontwidthmask:		FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/sis/300vtbl.h linux.20pre10-ac2/drivers/video/sis/300vtbl.h
--- linux.20pre10/drivers/video/sis/300vtbl.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/sis/300vtbl.h	2002-10-11 00:17:32.000000000 +0100
@@ -1,5 +1,7 @@
 
-/* Comments and changes marked with "TW" by Thomas Winischhofer <thomas@winischhofer.net> */
+
+/* Register settings for SiS 300 series */
+
 
 typedef struct _SiS300_StStruct
 {
@@ -12,7 +14,8 @@
 	UCHAR VB_StTVEdgeIndex;
 	UCHAR VB_StTVYFilterIndex;
 } SiS300_StStruct;
-SiS300_StStruct  SiS300_SModeIDTable[]=
+
+static const SiS300_StStruct  SiS300_SModeIDTable[]=
 {
 	{0x01,0x9208,0x01,0x00,0x00,0x00,0x00,0x00},
 	{0x01,0x1210,0x14,0x01,0x01,0x00,0x00,0x00},
@@ -50,7 +53,7 @@
 	UCHAR GRC[9];
 } SiS300_StandTableStruct;
 
-SiS300_StandTableStruct  SiS300_StandTable[]=
+static const SiS300_StandTableStruct  SiS300_StandTable[]=
 { /* TW: @ 0x38d4 in BIOS */
  {0x28,0x18,0x08,0x0800,
   {0x09,0x03,0x00,0x02},
@@ -421,62 +424,62 @@
 	UCHAR REFindex;
 } SiS300_ExtStruct;
 
-SiS300_ExtStruct  SiS300_EModeIDTable[]=
-{ /* TW: Table is identical to BIOS */		/* TW: BIOS offset to Ext2Struct: */
- {0x6a,0x2212,0x47,0x3563,0x0102,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */
- {0x2e,0x0a1b,0x36,0x3539,0x0101,0x08,0x06,0x00,0x00,0x00,0x08},  /* 37c3 */ /* 8bpp bug? */
- /* {0x2e,0x021b,0x36,0x3539,0x0101,0x08,0x06,0x00,0x00,0x00,0x08},  */ /* 37c3 */
- {0x2f,0x021b,0x35,0x3532,0x0100,0x08,0x05,0x00,0x00,0x00,0x10},  /* 37bc */
- {0x30,0x2a1b,0x47,0x3563,0x0103,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */ /* 8bpp bug? */
- /* {0x30,0x221b,0x47,0x3563,0x0103,0x08,0x07,0x00,0x00,0x00,0x00}, */ /* 37ed */
- {0x31,0x0a1b,0xad,0x3630,0x0000,0x08,0x0c,0x00,0x00,0x00,0x11},  /* 38ba */
- {0x32,0x2a1b,0xae,0x3637,0x0000,0x08,0x0d,0x00,0x00,0x00,0x12},  /* 38c1 */
- {0x33,0x0a1d,0xad,0x3630,0x0000,0x08,0x0c,0x00,0x00,0x00,0x11},  /* 38ba */
- {0x34,0x2a1d,0xae,0x3637,0x0000,0x08,0x0d,0x00,0x00,0x00,0x12},  /* 38c1 */
- {0x35,0x0a1f,0xad,0x3630,0x0000,0x08,0x0c,0x00,0x00,0x00,0x11},  /* 38ba */
- {0x36,0x2a1f,0xae,0x3637,0x0000,0x08,0x0d,0x00,0x00,0x00,0x12},  /* 38c1 */
- {0x37,0x0212,0x58,0x358d,0x0104,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */
- {0x38,0x0a1b,0x58,0x358d,0x0105,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */ /* 8bpp bug? */
- /* {0x38,0x021b,0x58,0x358d,0x0105,0x08,0x08,0x00,0x00,0x00,0x13}, */ /* 3817 */
- {0x3a,0x0e3b,0x69,0x35be,0x0107,0x08,0x09,0x00,0x00,0x00,0x1a},  /* 3848 */ /* 8bpp bug? */
- /* {0x3a,0x063b,0x69,0x35be,0x0107,0x08,0x09,0x00,0x00,0x00,0x1a}, */ /* 3848 */
- {0x3c,0x063b,0x7a,0x35d4,0x0130,0x08,0x0a,0x00,0x00,0x00,0x1e},  /* 385e */
- {0x3d,0x067d,0x7a,0x35d4,0x0131,0x08,0x0a,0x00,0x00,0x00,0x1e},  /* 385e */
- {0x40,0x921c,0x00,0x3516,0x010d,0x08,0x00,0x00,0x00,0x00,0x23},  /* 37a0 */
- {0x41,0x921d,0x00,0x3516,0x010e,0x08,0x00,0x00,0x00,0x00,0x23},  /* 37a0 */
- {0x43,0x0a1c,0x36,0x3539,0x0110,0x08,0x06,0x00,0x00,0x00,0x08},  /* 37c3 */
- {0x44,0x0a1d,0x36,0x3539,0x0111,0x08,0x06,0x00,0x00,0x00,0x08},  /* 37c3 */
- {0x46,0x2a1c,0x47,0x3563,0x0113,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */
- {0x47,0x2a1d,0x47,0x3563,0x0114,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */
- {0x49,0x0a3c,0x58,0x358d,0x0116,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */
- {0x4a,0x0a3d,0x58,0x358d,0x0117,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */
- {0x4c,0x0e7c,0x69,0x35be,0x0119,0x08,0x09,0x00,0x00,0x00,0x1a},  /* 3848 */
- {0x4d,0x0e7d,0x69,0x35be,0x011a,0x08,0x09,0x00,0x00,0x00,0x1a},  /* 3848 */
- {0x50,0x921b,0x01,0x351d,0x0132,0x08,0x01,0x00,0x00,0x00,0x24},  /* 37a7 */
- {0x51,0x921b,0x13,0x3524,0x0133,0x08,0x03,0x00,0x00,0x00,0x25},  /* 37ae */
- {0x52,0x921b,0x24,0x352b,0x0134,0x08,0x04,0x00,0x00,0x00,0x26},  /* 37b5 */
- {0x56,0x921d,0x01,0x351d,0x0135,0x08,0x01,0x00,0x00,0x00,0x24},  /* 37a7 */
- {0x57,0x921d,0x13,0x3524,0x0136,0x08,0x03,0x00,0x00,0x00,0x25},  /* 37ae */
- {0x58,0x921d,0x24,0x352b,0x0137,0x08,0x04,0x00,0x00,0x00,0x26},  /* 37b5 */
- {0x59,0x921b,0x00,0x3516,0x0138,0x08,0x00,0x00,0x00,0x00,0x23},  /* 37a0 */
- {0x5d,0x021d,0x35,0x3532,0x0139,0x08,0x05,0x00,0x00,0x00,0x10},  /* 37bc */
- {0x62,0x0a3f,0x36,0x3539,0x013a,0x08,0x06,0x00,0x00,0x00,0x08},  /* 37c3 */
- {0x63,0x2a3f,0x47,0x3563,0x013b,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */
- {0x64,0x0a7f,0x58,0x358d,0x013c,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */
- {0x65,0x0eff,0x69,0x35be,0x013d,0x08,0x09,0x00,0x00,0x00,0x1a},  /* 3848 */
- {0x66,0x06ff,0x7a,0x35d4,0x013e,0x08,0x0a,0x00,0x00,0x00,0x1e},  /* 385e */
- {0x68,0x067b,0x8b,0x35ef,0x013f,0x08,0x0b,0x00,0x00,0x00,0x27},  /* 3879 */
- {0x69,0x06fd,0x8b,0x35ef,0x0140,0x08,0x0b,0x00,0x00,0x00,0x27},  /* 3879 */
- {0x6b,0x07ff,0x8b,0x35ef,0x0000,0x10,0x0b,0x00,0x00,0x00,0x27},  /* 3879 */
- {0x6c,0x067b,0x9c,0x35f6,0x0000,0x08,0x0c,0x00,0x00,0x00,0x28},  /* 3880 */
- {0x6d,0x06fd,0x9c,0x35f6,0x0000,0x10,0x0c,0x00,0x00,0x00,0x28},  /* 3880 */
- {0x6e,0x0e3b,0x6f,0x35b2,0x0000,0x08,0x0e,0x00,0x00,0x00,0x29},  /* 383c */
- {0x6f,0x0e7d,0x6f,0x35b2,0x0000,0x08,0x0e,0x00,0x00,0x00,0x29},  /* 383c */
- {0x7b,0x0eff,0x6f,0x35b2,0x0000,0x08,0x0e,0x00,0x00,0x00,0x29},  /* 383c */
- {0x7c,0x221b,0xb3,0x363e,0x0000,0x08,0x0f,0x00,0x00,0x00,0x2b},  /* 38c8 */
- {0x7d,0x221d,0xb3,0x363e,0x0000,0x08,0x0f,0x00,0x00,0x00,0x2b},  /* 38c8 */
- {0x7e,0x223f,0xb3,0x363e,0x0000,0x08,0x0f,0x00,0x00,0x00,0x2b},  /* 38c8 */
- {0xff,0x0000,0x00,0x0000,0xffff,0x00,0x00,0x00,0x00,0x00,0x00}
+static const SiS300_ExtStruct  SiS300_EModeIDTable[]=
+{
+	{0x6a,0x2212,0x47,0x3563,0x0102,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */  /* 800x600x? */
+	{0x2e,0x0a1b,0x36,0x3539,0x0101,0x08,0x06,0x00,0x00,0x00,0x08},  /* 37c3 */
+	{0x2f,0x021b,0x35,0x3532,0x0100,0x08,0x05,0x00,0x00,0x00,0x10},  /* 37bc */
+	{0x30,0x2a1b,0x47,0x3563,0x0103,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */
+	{0x31,0x0a1b,0xad,0x3630,0x0000,0x08,0x0c,0x00,0x00,0x00,0x11},  /* 38ba */ /* 720x480x8 */
+	{0x32,0x2a1b,0xae,0x3637,0x0000,0x08,0x0d,0x00,0x00,0x00,0x12},  /* 38c1 */ /* 720x576x8 */
+	{0x33,0x0a1d,0xad,0x3630,0x0000,0x08,0x0c,0x00,0x00,0x00,0x11},  /* 38ba */ /* 720x480x16 */
+	{0x34,0x2a1d,0xae,0x3637,0x0000,0x08,0x0d,0x00,0x00,0x00,0x12},  /* 38c1 */ /* 720x576x16 */
+	{0x35,0x0a1f,0xad,0x3630,0x0000,0x08,0x0c,0x00,0x00,0x00,0x11},  /* 38ba */ /* 720x480x32 */
+	{0x36,0x2a1f,0xae,0x3637,0x0000,0x08,0x0d,0x00,0x00,0x00,0x12},  /* 38c1 */ /* 720x576x32 */
+	{0x37,0x0212,0x58,0x358d,0x0104,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */ /* 1024x768x? */
+	{0x38,0x0a1b,0x58,0x358d,0x0105,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */ /* 1024x768x8 */
+	{0x3a,0x0e3b,0x69,0x35be,0x0107,0x08,0x09,0x00,0x00,0x00,0x1a},  /* 3848 */ /* 1280x1024x8 */
+	{0x3c,0x063b,0x7a,0x35d4,0x0130,0x08,0x0a,0x00,0x00,0x00,0x1e},  /* 385e */
+	{0x3d,0x067d,0x7a,0x35d4,0x0131,0x08,0x0a,0x00,0x00,0x00,0x1e},  /* 385e */
+	{0x40,0x921c,0x00,0x3516,0x010d,0x08,0x00,0x00,0x00,0x00,0x23},  /* 37a0 */
+	{0x41,0x921d,0x00,0x3516,0x010e,0x08,0x00,0x00,0x00,0x00,0x23},  /* 37a0 */
+	{0x43,0x0a1c,0x36,0x3539,0x0110,0x08,0x06,0x00,0x00,0x00,0x08},  /* 37c3 */
+	{0x44,0x0a1d,0x36,0x3539,0x0111,0x08,0x06,0x00,0x00,0x00,0x08},  /* 37c3 */
+	{0x46,0x2a1c,0x47,0x3563,0x0113,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */ /* 800x600 */
+	{0x47,0x2a1d,0x47,0x3563,0x0114,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */ /* 800x600 */
+	{0x49,0x0a3c,0x58,0x358d,0x0116,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */
+	{0x4a,0x0a3d,0x58,0x358d,0x0117,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */
+	{0x4c,0x0e7c,0x69,0x35be,0x0119,0x08,0x09,0x00,0x00,0x00,0x1a},  /* 3848 */
+	{0x4d,0x0e7d,0x69,0x35be,0x011a,0x08,0x09,0x00,0x00,0x00,0x1a},  /* 3848 */
+	{0x50,0x921b,0x01,0x351d,0x0132,0x08,0x01,0x00,0x00,0x00,0x24},  /* 37a7 */
+	{0x51,0xb21b,0x13,0x3524,0x0133,0x08,0x03,0x00,0x00,0x00,0x25},  /* 37ae */ /* 400x300 */
+	{0x52,0x921b,0x24,0x352b,0x0134,0x08,0x04,0x00,0x00,0x00,0x26},  /* 37b5 */
+	{0x56,0x921d,0x01,0x351d,0x0135,0x08,0x01,0x00,0x00,0x00,0x24},  /* 37a7 */
+	{0x57,0xb21d,0x13,0x3524,0x0136,0x08,0x03,0x00,0x00,0x00,0x25},  /* 37ae */ /* 400x300 */
+	{0x58,0x921d,0x24,0x352b,0x0137,0x08,0x04,0x00,0x00,0x00,0x26},  /* 37b5 */
+	{0x59,0x921b,0x00,0x3516,0x0138,0x08,0x00,0x00,0x00,0x00,0x23},  /* 37a0 */
+	{0x5c,0x921f,0x24,0x352b,0x0000,0x08,0x04,0x00,0x00,0x00,0x26},  /* TW: inserted 512x384x32 */
+	{0x5d,0x021d,0x35,0x3532,0x0139,0x08,0x05,0x00,0x00,0x00,0x10},  /* 37bc */
+	{0x62,0x0a3f,0x36,0x3539,0x013a,0x08,0x06,0x00,0x00,0x00,0x08},  /* 37c3 */
+	{0x63,0x2a3f,0x47,0x3563,0x013b,0x08,0x07,0x00,0x00,0x00,0x00},  /* 37ed */  /* 800x600 */
+	{0x64,0x0a7f,0x58,0x358d,0x013c,0x08,0x08,0x00,0x00,0x00,0x13},  /* 3817 */
+	{0x65,0x0eff,0x69,0x35be,0x013d,0x08,0x09,0x00,0x00,0x00,0x1a},  /* 3848 */
+	{0x66,0x06ff,0x7a,0x35d4,0x013e,0x08,0x0a,0x00,0x00,0x00,0x1e},  /* 385e */
+	{0x68,0x067b,0x8b,0x35ef,0x013f,0x08,0x0b,0x00,0x00,0x00,0x27},  /* 3879 */
+	{0x69,0x06fd,0x8b,0x35ef,0x0140,0x08,0x0b,0x00,0x00,0x00,0x27},  /* 3879 */
+	{0x6b,0x07ff,0x8b,0x35ef,0x0000,0x10,0x0b,0x00,0x00,0x00,0x27},  /* 3879 */
+	{0x6c,0x067b,0x9c,0x35f6,0x0000,0x08,0x0c,0x00,0x00,0x00,0x28},  /* 3880 */
+	{0x6d,0x06fd,0x9c,0x35f6,0x0000,0x10,0x0c,0x00,0x00,0x00,0x28},  /* 3880 */
+	{0x6e,0x0e3b,0x6f,0x35b2,0x0000,0x08,0x0e,0x00,0x00,0x00,0x29},  /* 383c */  /* 1280x960x8 */
+	{0x6f,0x0e7d,0x6f,0x35b2,0x0000,0x08,0x0e,0x00,0x00,0x00,0x29},  /* 383c */  /* 1280x960x16 */
+	{0x7b,0x0eff,0x6f,0x35b2,0x0000,0x08,0x0e,0x00,0x00,0x00,0x29},  /* 383c */  /* 1280x960x32 */
+	{0x20,0x0a1b,0x54,0x0000,0x0000,0x08,0x0f,0x00,0x00,0x00,0x2b},              /* 1024x600 */
+	{0x21,0x0a3d,0x54,0x0000,0x0000,0x08,0x0f,0x00,0x00,0x00,0x2b},
+	{0x22,0x0a7f,0x54,0x0000,0x0000,0x08,0x0f,0x00,0x00,0x00,0x2b},
+	{0x23,0x0a1b,0xc5,0x0000,0x0000,0x08,0x10,0x00,0x00,0x00,0x2c},              /* 1152x768 */
+	{0x24,0x0a3d,0xc5,0x431d,0x0000,0x08,0x10,0x00,0x00,0x00,0x2c},
+	{0x25,0x0a7f,0xc5,0x431d,0x0000,0x08,0x10,0x00,0x00,0x00,0x2c},
+	{0xff,0x0000,0x00,0x0000,0xffff,0x00,0x00,0x00,0x00,0x00,0x00}
 };
 
 typedef struct _SiS300_Ext2Struct
@@ -491,82 +494,55 @@
 	USHORT ROM_OFFSET;
 } SiS300_Ext2Struct;
 
-SiS300_Ext2Struct  SiS300_RefIndex[]=
+static const SiS300_Ext2Struct  SiS300_RefIndex[]=
 { /* TW: Don't ever insert anything here, table is indexed */
- {0x085f,0x0d,0x03,0x05,0x6a, 800, 600,0x3563},
- {0x0467,0x0e,0x44,0x05,0x6a, 800, 600,0x3568},
- {0x0067,0x4f,0x07,0x48,0x6a, 800, 600,0x356d},
- {0x0067,0x10,0x06,0x8b,0x6a, 800, 600,0x3572},
- {0x0147,0x11,0x08,0x00,0x6a, 800, 600,0x3577},
- {0x0147,0x12,0x0c,0x00,0x6a, 800, 600,0x357c},
- {0x0047,0x51,0x4e,0x00,0x6a, 800, 600,0x3581},
- {0x0047,0x11,0x13,0x00,0x6a, 800, 600,0x3586},
- {0xc85f,0x05,0x00,0x04,0x2e, 640, 480,0x3539},
- {0xc067,0x06,0x02,0x04,0x2e, 640, 480,0x353e},
- {0xc067,0x07,0x02,0x47,0x2e, 640, 480,0x3543},
- {0xc067,0x08,0x03,0x8a,0x2e, 640, 480,0x3548},
- {0xc047,0x09,0x05,0x00,0x2e, 640, 480,0x354d},
- {0xc047,0x0a,0x08,0x00,0x2e, 640, 480,0x3552},
- {0xc047,0x0b,0x0a,0x00,0x2e, 640, 480,0x3557},
- {0xc047,0x0c,0x10,0x00,0x2e, 640, 480,0x355c},
- {0x487f,0x04,0x00,0x00,0x2f, 640, 400,0x3532},
- {0xc00f,0x31,0x01,0x06,0x31,2048,1536,0x3630},
- {0x000f,0x32,0x03,0x06,0x32, 720, 480,0x3637},
- {0x0187,0x15,0x05,0x00,0x37,1024, 768,0x358d},
- /* {0xc877,0x16,0x09,0x06,0x37,1024, 768,0x3592}, <--- different in BIOS */
- {0xc077,0x16,0x09,0x06,0x37,1024, 768,0x3592},
- {0xc067,0x97,0x0b,0x49,0x37,1024, 768,0x3597},
- {0x0267,0x18,0x0d,0x00,0x37,1024, 768,0x359c},
- {0x0047,0x59,0x11,0x8c,0x37,1024, 768,0x35a1},
- {0x0047,0x1a,0x52,0x00,0x37,1024, 768,0x35a6},
- {0x0047,0x5b,0x16,0x00,0x37,1024, 768,0x35ab},
- {0x0387,0x5c,0x4d,0x00,0x3a,1280,1024,0x35be},
- {0x0077,0x1d,0x14,0x07,0x3a,1280,1024,0x35c3},
- {0x0047,0x1e,0x17,0x00,0x3a,1280,1024,0x35c8},
- {0x0007,0x1f,0x98,0x00,0x3a,1280,1024,0x35cd},
- {0x0007,0x60,0x59,0x00,0x3c,1600,1200,0x35d4},
- {0x0007,0x21,0x5a,0x00,0x3c,1600,1200,0x35d9},
- {0x0007,0x22,0x1b,0x00,0x3c,1600,1200,0x35de},
- {0x0007,0x63,0x1d,0x00,0x3c,1600,1200,0x35e3},
- {0x0007,0x24,0x1e,0x00,0x3c,1600,1200,0x35e8},
- /* TW: No 1600x1200 LCD mode? */
- {0x407f,0x00,0x00,0x00,0x40, 320, 200,0x3516},
- {0xc07f,0x01,0x00,0x04,0x50, 320, 240,0x351d},
- {0x0077,0x02,0x04,0x05,0x51, 400, 300,0x3524},
- {0xc077,0x03,0x09,0x06,0x52, 512, 384,0x352b},
- {0x8207,0x25,0x1f,0x00,0x68,1920,1440,0x35ef},
- {0x0007,0x26,0x20,0x00,0x6c,2048,1536,0x35f6},
- {0x0027,0x27,0x14,0x08,0x6e, 720, 576,0x35b2},
- {0x0027,0x27,0x14,0x08,0x6e, 720, 576,0x35b7},
- /* TW: 1280x960 identical to BIOS */
- /* TW:              v--- I doubt this - no CRT2? */
- {0x00df,0x33,0x28,0x00,0x7c,1280, 960,0x363e},
- {0xc05f,0x34,0x28,0x00,0x7c,1280, 960,0x3643},
-#if 0
- /* TW: The LCD modes for 1280x960 are missing! */
- /*     Values guessed! */
- {0x00a7,0x33,0x28,0x08,0x7c,1280, 960,0xDEAD},  /* Do we need an interlace mode? */
- {0xc027,0x34,0x28,0x08,0x7c,1280, 960,0xBEEF},
- /* TW:    |         |---- This is either 0x07 or 0x08  */
-#endif /*  +---- Same as for the non-interlace mode */
- {0xffff,0,0,0,0,0,0,0}
-};
-
-/* TW: These entries are contained in the BIOS but missing in table above: (resolution unknown) */
-#if 0
- /* at 0x3887: (not indexed by EModeIDTable in BIOS either) */
- {0x0057,0x28,0x27,0x08,... }
- {0x0047,0x29,0x06,0x08,... }
- {0x0047,0x2a,0x08,0x08,... } /* table end */
- /* at 0x3898: (not indexed by EModeIDTable in BIOS either)*/
- {0x0057,0x2b,0x09,0x09,... }
- {0x0047,0x2c,0x0d,0x09,... }
- {0x0047,0x2d,0x11,0x09,... } /* table end */
- /* at 0x38a9: (not indexed by EModeIDTable in BIOS either) */
- {0x0057,0x2e,0x14,0x0a,... }
- {0x0047,0x2f,0x17,0x0a,... }
- {0x0047,0x30,0x18,0x0a,... } /* table end */
-#endif
+	{0x085f,0x0d,0x03,0x05,0x6a, 800, 600,0x3563}, /* 00 */
+	{0x0467,0x0e,0x44,0x05,0x6a, 800, 600,0x3568}, /* 01 */
+	{0x0067,0x4f,0x07,0x48,0x6a, 800, 600,0x356d}, /* 02 */
+	{0x0067,0x10,0x06,0x8b,0x6a, 800, 600,0x3572}, /* 03 */
+	{0x0147,0x11,0x08,0x00,0x6a, 800, 600,0x3577}, /* 04 */
+	{0x0147,0x12,0x0c,0x00,0x6a, 800, 600,0x357c}, /* 05 */
+	{0x0047,0x51,0x4e,0x00,0x6a, 800, 600,0x3581}, /* 06 */
+	{0x0047,0x11,0x13,0x00,0x6a, 800, 600,0x3586}, /* 07 */
+	{0xc85f,0x05,0x00,0x04,0x2e, 640, 480,0x3539}, /* 08 */
+	{0xc067,0x06,0x02,0x04,0x2e, 640, 480,0x353e}, /* 09 */
+	{0xc067,0x07,0x02,0x47,0x2e, 640, 480,0x3543}, /* 0a */
+	{0xc067,0x08,0x03,0x8a,0x2e, 640, 480,0x3548}, /* 0b */
+	{0xc047,0x09,0x05,0x00,0x2e, 640, 480,0x354d}, /* 0c */
+	{0xc047,0x0a,0x08,0x00,0x2e, 640, 480,0x3552}, /* 0d */
+	{0xc047,0x0b,0x0a,0x00,0x2e, 640, 480,0x3557}, /* 0e */
+	{0xc047,0x0c,0x10,0x00,0x2e, 640, 480,0x355c}, /* 0f */
+	{0x487f,0x04,0x00,0x00,0x2f, 640, 400,0x3532}, /* 10 */
+	{0xc00f,0x31,0x01,0x06,0x31, 720, 480,0x3630}, /* 11 */
+	{0x000f,0x32,0x03,0x06,0x32, 720, 576,0x3637}, /* 12 */
+	{0x0187,0x15,0x05,0x00,0x37,1024, 768,0x358d}, /* 13 */
+        {0xc877,0x16,0x09,0x06,0x37,1024, 768,0x3592}, /* 14 */
+	{0xc067,0x97,0x0b,0x49,0x37,1024, 768,0x3597}, /* 15 */
+	{0x0267,0x18,0x0d,0x00,0x37,1024, 768,0x359c}, /* 16 */
+	{0x0047,0x59,0x11,0x8c,0x37,1024, 768,0x35a1}, /* 17 */
+	{0x0047,0x1a,0x52,0x00,0x37,1024, 768,0x35a6}, /* 18 */
+	{0x0047,0x5b,0x16,0x00,0x37,1024, 768,0x35ab}, /* 19 */
+	{0x0387,0x5c,0x4d,0x00,0x3a,1280,1024,0x35be}, /* 1a */
+	{0x0077,0x1d,0x14,0x07,0x3a,1280,1024,0x35c3}, /* 1b */
+	{0x0047,0x1e,0x17,0x00,0x3a,1280,1024,0x35c8}, /* 1c */
+	{0x0007,0x1f,0x98,0x00,0x3a,1280,1024,0x35cd}, /* 1d */
+	{0x0007,0x60,0x59,0x00,0x3c,1600,1200,0x35d4}, /* 1e */
+	{0x0007,0x21,0x5a,0x00,0x3c,1600,1200,0x35d9}, /* 1f */
+	{0x0007,0x22,0x1b,0x00,0x3c,1600,1200,0x35de}, /* 20 */
+	{0x0007,0x63,0x1d,0x00,0x3c,1600,1200,0x35e3}, /* 21 */
+	{0x0007,0x24,0x1e,0x00,0x3c,1600,1200,0x35e8}, /* 22 */
+	{0x407f,0x00,0x00,0x00,0x40, 320, 200,0x3516}, /* 23 */
+	{0xc07f,0x01,0x00,0x04,0x50, 320, 240,0x351d}, /* 24 */
+	{0x0077,0x02,0x04,0x05,0x51, 400, 300,0x3524}, /* 25 */
+	{0xc877,0x03,0x09,0x06,0x52, 512, 384,0x352b}, /* 26 */  /* was c077 */
+	{0x8207,0x25,0x1f,0x00,0x68,1920,1440,0x35ef}, /* 27 */
+	{0x0007,0x26,0x20,0x00,0x6c, 720, 480,0x35f6}, /* 28 */
+	{0x0027,0x27,0x14,0x08,0x6e,1280, 960,0x35b2}, /* 29 */
+	{0x0027,0x27,0x14,0x08,0x6e,1280, 960,0x35b7}, /* 2a */
+	{0xc077,0x33,0x09,0x06,0x20,1024, 600,0x0000}, /* 2b */
+	{0xc077,0x34,0x09,0x06,0x23,1152, 768,0x0000}, /* 2c */
+	{0xffff,0,0,0,0,0,0,0}
+};
 
 /*add for 300 oem util*/
 typedef struct _SiS_VBModeIDTableStruct
@@ -581,9 +557,9 @@
 	UCHAR  _VB_LCDVIndex;
 }SiS_VBModeIDTableStruct;
 
-SiS_VBModeIDTableStruct  SiS300_VBModeIDTable[]=
+static const SiS_VBModeIDTableStruct  SiS300_VBModeIDTable[]=
 {
-	{0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+	{0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, /* TW: Identical to 630/301B 2.04.50 BIOS */
 	{0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01},
 	{0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x02},
 	{0x03,0x00,0x00,0x00,0x02,0x00,0x02,0x00},
@@ -633,22 +609,22 @@
 	{0x65,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d},
 	{0x6e,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d},
 	{0x6f,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d},
-	{0x7b,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d}
+	{0x7b,0x00,0x00,0x01,0x00,0x00,0x0b,0x0d},
+	{0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00}  /* TW: added! */
 };
 /*end*/
 
-/* TW: The following table is (now) identical to BIOS */
 typedef struct _SiS300_CRT1TableStruct
 {
 	UCHAR CR[17];
 } SiS300_CRT1TableStruct;
 
-SiS300_CRT1TableStruct  SiS300_CRT1Table[]=
-{ /* at 0x4014 in BIOS */
- {{0x2d,0x27,0x28,0x90,/*0x2b*/ 0x2c,0x80,0xbf,0x1f,  /* <--- was different to BIOS */
+static const SiS300_CRT1TableStruct  SiS300_CRT1Table[]=
+{
+ {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,    /* 0x00 */
   0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
   0x00}},
- {{0x2d,0x27,0x28,0x90,/*0x2b*/ 0x2c,0x80,0x0b,0x3e,  /* <--- was different to BIOS */
+ {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
   0x00}},
  {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0,
@@ -675,7 +651,7 @@
  {{0x66,0x4f,0x4f,0x86,0x56,0x9e,0x03,0x3e,
   0xe4,0x87,0xdf,0xdf,0x04,0x00,0x00,0x01,
   0x00}},
- {{0x6c,0x4f,0x4f,0x83,0x59,0x9e,0x00,0x3e,    /* 10 */
+ {{0x6c,0x4f,0x4f,0x83,0x59,0x9e,0x00,0x3e,    /* 0x0a */
   0xe5,0x8d,0xdf,0xdf,0x01,0x00,0x00,0x01,
   0x00}},
  {{0x63,0x4f,0x4f,0x87,0x56,0x9d,0xfb,0x1f,
@@ -705,7 +681,7 @@
  {{0x7e,0x63,0x63,0x82,0x6c,0x14,0x75,0xe0,
   0x58,0x0b,0x57,0x57,0x76,0x20,0x00,0x06,
   0x01}},
- {{0x7e,0x63,0x63,0x82,0x6c,0x14,0x75,0xe0,   /* 20 */
+ {{0x7e,0x63,0x63,0x82,0x6c,0x14,0x75,0xe0,   /* 0x14 */
   0x58,0x0b,0x57,0x57,0x76,0x20,0x00,0x06,
   0x01}},
  {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f,
@@ -735,7 +711,7 @@
  {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a,
   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
   0x01}},
- {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a,  /* 30 */
+ {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a,  /* 0x1e */
   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
   0x01}},
  {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a,
@@ -758,14 +734,14 @@
   0x00}},
  {{0x3f,0xef,0xef,0x83,0xfd,0x1a,0xda,0x1f,  /* 37: 1920x1440x60Hz */
   0xa0,0x84,0x9f,0x9f,0xdb,0x1f,0x01,0x01,
-  0x00}},  /* TW: TEST, should be 0x30? */
+  0x00}},
  {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba,
   0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05,
   0x00}},
  {{0xdc,0x9f,0x9f,0x00,0xab,0x19,0xe6,0xef,
   0xc0,0xc3,0xbf,0xbf,0xe7,0x10,0x00,0x07,
   0x01}},
- {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,
+ {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,  /* 0x28 */
   0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
   0x01}},
  {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba,
@@ -795,16 +771,15 @@
  {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e,
   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
   0x00}},
- {{0x7b,0x59,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
+ {{0x7b,0x59,0x63,0x9f,0x6a,0x93,0x6f,0xf0,  /* 0x32 */
   0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05,
   0x01}},
- {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15,	/* 1280x960 */
-  0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02,
-  0x00}},
- {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e,	/* 1280x960 */
-  0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02,
-  0x00}}
-  /* end @ 0x4399 */
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1,  /* 0x33 - 1024x600 */
+  0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02,
+  0x01}},
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,  /* 0x34 - 1152x768 */
+  0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
+  0x01}}
 };
 
 typedef struct _SiS300_MCLKDataStruct
@@ -813,7 +788,7 @@
 	USHORT CLOCK;
 } SiS300_MCLKDataStruct;
 
-SiS300_MCLKDataStruct  SiS300_MCLKData[]=
+static const SiS300_MCLKDataStruct  SiS300_MCLKData_630[] =	/* 630 */
 { /* TW: at 0x54 in BIOS */
 	{ 0x5a,0x64,0x80, 66},
 	{ 0xb3,0x45,0x80, 83},
@@ -825,14 +800,26 @@
 	{ 0x37,0x61,0x80,100}
 };
 
+static const SiS300_MCLKDataStruct  SiS300_MCLKData_300[] =  /* 300 */
+{ /* TW: at 0x54 in BIOS */
+	{ 0x68,0x43,0x80,125},
+	{ 0x68,0x43,0x80,125},
+	{ 0x68,0x43,0x80,125},
+	{ 0x37,0x61,0x80,100},
+	{ 0x37,0x61,0x80,100},
+	{ 0x37,0x61,0x80,100},
+	{ 0x37,0x61,0x80,100},
+	{ 0x37,0x61,0x80,100}
+};
+
 typedef struct _SiS300_ECLKDataStruct
 {
 	UCHAR SR2E,SR2F,SR30;
 	USHORT CLOCK;
 } SiS300_ECLKDataStruct;
 
-SiS300_ECLKDataStruct  SiS300_ECLKData[]=
-{ /* TW: at 0x7c in BIOS */
+static const SiS300_ECLKDataStruct  SiS300_ECLKData[]=
+{
 	{ 0x54,0x43,0x80,100},
 	{ 0x53,0x43,0x80,100},
 	{ 0x55,0x43,0x80,100},
@@ -849,8 +836,8 @@
 	USHORT CLOCK;
 } SiS300_VCLKDataStruct;
 
-SiS300_VCLKDataStruct  SiS300_VCLKData[]=
-{ /* TW: At 0x484e in BIOS */
+static const SiS300_VCLKDataStruct  SiS300_VCLKData[]=
+{
 	{ 0x1b,0xe1, 25},
 	{ 0x4e,0xe4, 28},
 	{ 0x57,0xe4, 32},
@@ -863,11 +850,11 @@
 	{ 0x5a,0x64, 65},
 	{ 0x46,0x44, 68},
 	{ 0x3e,0x43, 75},
-	{ 0x6d,0x46, 76},
+	{ 0x6d,0x46, 76}, /* 0x0c: 800x600 | LVDS_2(CH), MITAC(CH);  - LVDS2(CH), A901(301B): 0xb1,0x46, 76 */
 	{ 0x41,0x43, 79},
 	{ 0x31,0x42, 79},
 	{ 0x46,0x25, 85},
-	{ 0x78,0x29, 87},
+	{ 0x78,0x29, 87}, /* 0x10 */
 	{ 0x62,0x44, 95},
 	{ 0x2b,0x22,105},
 	{ 0x49,0x24,106},
@@ -882,37 +869,91 @@
 	{ 0xde,0x26,194},
 	{ 0x54,0x05,203},
 	{ 0x3f,0x03,230},
-	{ 0x30,0x02,234},  /* 0x1f - 1920x1440 */
-	{ 0x24,0x01,266},  /* 0x20 - 2048x1536 */
-	{ 0x52,0x2a, 54},
-	{ 0x52,0x6a, 27},
-	{ 0x62,0x24, 70},
-	{ 0x62,0x64, 70},
-	{ 0xa8,0x4c, 30},
-	{ 0x20,0x26, 33},
+	{ 0x30,0x02,234},
+	{ 0x24,0x01,266},  /* 0x20 */
+	{ 0x52,0x2a, 54},  /* 301 TV */
+	{ 0x52,0x6a, 27},  /* 301 TV */
+	{ 0x62,0x24, 70},  /* 301 TV */
+	{ 0x62,0x64, 70},  /* 301 TV */
+	{ 0xa8,0x4c, 30},  /* 301 TV */
+	{ 0x20,0x26, 33},  /* 301 TV */
 	{ 0x31,0xc2, 39},
-	{ 0xbf,0xc8, 35},  /* 0x28 - 1280x960 ??? that can't be right */
-	{ 0x60,0x36, 30},
+	{ 0xbf,0xc8, 35},  /* 0x28 */
+	{ 0x60,0x36, 30},  /* 0x29  CH/UNTSC TEXT | LVDS_2(CH) - LVDS2(CH), A901(301B), Mitac(CH): 0xe0, 0xb6, 30 */
 	{ 0x40,0x4a, 28},
 	{ 0x9f,0x46, 44},
 	{ 0x97,0x2c, 26},
 	{ 0x44,0xe4, 25},
 	{ 0x7e,0x32, 47},
-	{ 0x8a,0x24, 31},
+	{ 0x8a,0x24, 31},  /* 0x2f  CH/PAL TEXT | LVDS_2(CH), Mitac(CH) -  LVDS2(CH), A901(301B): 0x57, 0xe4, 31 */
 	{ 0x97,0x2c, 26},
 	{ 0xce,0x3c, 39},
 	{ 0x52,0x4a, 36},
 	{ 0x34,0x61, 95},
 	{ 0x78,0x27,108},
-	{ 0xce,0x25,189},  /* TW: This was missing */
-	{ 0xff,0x1b,6625}
+	{ 0xce,0x25,189},
+	{ 0x45,0x6b, 21},  /* 0x36 */  /* TW: Added from Mitac */
+	{ 0xff,0x00,  0}
+};
+
+#if 0 /* TW: This table is in all BIOSes, but not used */
+static const SiS300_VCLKDataStruct  SiS300_VBVCLKData[]=
+{
+	{ 0x1b,0xe1, 25},
+	{ 0x4e,0xe4, 28},
+	{ 0x57,0xe4, 31},
+	{ 0xc3,0xc8, 36},
+	{ 0x42,0x47, 40},
+	{ 0x5d,0xc4, 44},
+	{ 0x52,0x47, 49},
+	{ 0x53,0x47, 50},
+	{ 0x6d,0x66, 56},
+	{ 0x5a,0x64, 65},
+	{ 0x46,0x44, 67},
+	{ 0x29,0x61, 75},
+	{ 0x6d,0x46, 75},
+	{ 0x41,0x43, 78},
+	{ 0x31,0x42, 79},
+	{ 0x46,0x25, 84},
+	{ 0x78,0x29, 86}, /* 0x10 */
+	{ 0x62,0x44, 94},
+	{ 0x2b,0x22,104},
+	{ 0x49,0x24,105},
+	{ 0x43,0x42,108},
+	{ 0x3c,0x23,109},
+	{ 0xe0,0x46,132},
+	{ 0x70,0x25,135},
+	{ 0x41,0x22,157},
+	{ 0x43,0x22,162},
+	{ 0x30,0x21,175},
+	{ 0xc1,0x24,189},
+	{ 0xde,0x26,194},
+	{ 0x70,0x07,202},
+	{ 0x3f,0x03,229},
+	{ 0x30,0x02,234},  /* 0x1f */
+	{ 0x24,0x01,265},  /* 0x20 */
+	{ 0x52,0x2a, 54},
+	{ 0x52,0x6a, 27},
+	{ 0x62,0x24, 70},
+	{ 0x62,0x64, 70},
+	{ 0xa8,0x4c, 30},
+	{ 0x20,0x26, 33},
+	{ 0x31,0xc2, 39},
+	{ 0x2e,0x48, 25},  /* 0x28 */
+	{ 0x24,0x46, 25},  /* 0x29 */
+	{ 0x26,0x64, 28},
+	{ 0x37,0x64, 40},
+	{ 0xa1,0x42,108},
+	{ 0x37,0x61,100},
+	{ 0x78,0x27,108},
+	{ 0xff,0x00,  0}
 };
+#endif
 
-/* TW: at 0x377d in BIOS */
-UCHAR SiS300_ScreenOffset[]=
+static const UCHAR  SiS300_ScreenOffset[] =
 {
 	0x14,0x19,0x20,0x28,0x32,0x40,0x50,
-        0x64,0x78,0x80,0x2d,0x35,0xff
+        0x64,0x78,0x80,0x2d,0x35,0x48,0xff
 };
 
 typedef struct _SiS300_StResInfoStruct
@@ -921,7 +962,7 @@
 	USHORT VTotal;
 } SiS300_StResInfoStruct;
 
-SiS300_StResInfoStruct  SiS300_StResInfo[]=
+static const SiS300_StResInfoStruct  SiS300_StResInfo[] =
 {
 	{ 640,400},
 	{ 640,350},
@@ -938,76 +979,91 @@
 	UCHAR  YChar;
 } SiS300_ModeResInfoStruct;
 
-SiS300_ModeResInfoStruct  SiS300_ModeResInfo[]=
-{ /* TW: At 0x5957 in BIOS */
-	{  320, 200, 8, 8},
-	{  320, 240, 8, 8},
-	{  320, 400, 8, 8},
-	{  400, 300, 8, 8},
-	{  512, 384, 8, 8},
-	{  640, 400, 8,16},
-	{  640, 480, 8,16},
-	{  800, 600, 8,16},
-	{ 1024, 768, 8,16},
-	{ 1280,1024, 8,16},
-	{ 1600,1200, 8,16},
-	{ 1920,1440, 8,16},
-	{ 2048,1536, 8,16},   /* TW: this was missing here, wasn't it? (not in BIOS) */
-	{  720, 480, 8,16},   /*     (otherwise RESINFO index is wrong!) */
-	{  720, 576, 8,16},
-	{ 1280, 960, 8,16}
-};
-
-UCHAR SiS300_OutputSelect =0x40;
-UCHAR SiS300_SoftSetting = 30;
-UCHAR SiS300_SR07=0x10;
-UCHAR SiS300_SR15[8][4]={
-	{0x1,0x9,0xa3,0x0},
-	{0x43,0x43,0x43,0x0},
-	{0x1e,0x1e,0x1e,0x0},
-	{0x2a,0x2a,0x2a,0x0},
-	{0x6,0x6,0x6,0x0},
-	{0x0,0x0,0x0,0x0},
-	{0x0,0x0,0x0,0x0},
-	{0x0,0x0,0x0,0x0}
-};
-UCHAR SiS300_SR1F=0x0;
-UCHAR SiS300_SR21=0x16;
-UCHAR SiS300_SR22=0xb2;
-UCHAR SiS300_SR23=0xf6;
-UCHAR SiS300_SR24=0xd;
-UCHAR SiS300_SR25[]={0x0,0x0};
-UCHAR SiS300_SR31=0x0;
-UCHAR SiS300_SR32=0x11;
-UCHAR SiS300_SR33=0x0;
-UCHAR SiS300_CRT2Data_1_2 = 0x40;
-UCHAR SiS300_CRT2Data_4_D = 0x0;
-UCHAR SiS300_CRT2Data_4_E = 0x0;
-UCHAR SiS300_CRT2Data_4_10 = 0x80;
-USHORT SiS300_RGBSenseData = 0xd1;
-USHORT SiS300_VideoSenseData = 0xb3;
-USHORT SiS300_YCSenseData = 0xb9;
-USHORT SiS300_RGBSenseData2 = 0x0190;     /*301b*/
-USHORT SiS300_VideoSenseData2 = 0x0174;
-USHORT SiS300_YCSenseData2 = 0x016b;
-
-UCHAR SiS300_CR40[5][4];
-UCHAR SiS300_CR49[2];
-UCHAR SiS300_NTSCPhase[]  = {0x21,0xed,0x8a,0x08};
-UCHAR SiS300_PALPhase[]   = {0x2a,0x05,0xd3,0x00};
-UCHAR SiS300_NTSCPhase2[] = {0x21,0xF0,0x7B,0xD6};/*301b*/
-UCHAR SiS300_PALPhase2[]  = {0x2a,0x09,0x86,0xe9};
-UCHAR SiS300_PALMPhase[]  = {0x21,0xE4,0x2E,0x9B};   /*palmn*/
-UCHAR SiS300_PALNPhase[]  = {0x21,0xF4,0x3E,0xBA};
+static const SiS300_ModeResInfoStruct  SiS300_ModeResInfo[] =
+{
+	{  320, 200, 8, 8},  /* 0x00 */
+	{  320, 240, 8, 8},  /* 0x01 */
+	{  320, 400, 8, 8},  /* 0x02 */
+	{  400, 300, 8, 8},  /* 0x03 */
+	{  512, 384, 8, 8},  /* 0x04 */
+	{  640, 400, 8,16},  /* 0x05 */
+	{  640, 480, 8,16},  /* 0x06 */
+	{  800, 600, 8,16},  /* 0x07 */
+	{ 1024, 768, 8,16},  /* 0x08 */
+	{ 1280,1024, 8,16},  /* 0x09 */
+	{ 1600,1200, 8,16},  /* 0x0a */
+	{ 1920,1440, 8,16},  /* 0x0b */
+	{  720, 480, 8,16},  /* 0x0c */
+	{  720, 576, 8,16},  /* 0x0d */
+	{ 1280, 960, 8,16},  /* 0x0e */
+	{ 1024, 600, 8,16},  /* 0x0f */
+	{ 1152, 768, 8,16}   /* 0x10 */
+};
+
+static const UCHAR SiS300_OutputSelect = 0x40;
+
+static const UCHAR SiS300_SoftSetting = 30;
+
+#ifndef LINUX_XF86
+static UCHAR SiS300_SR07 = 0x10;
+#endif
+
+static const UCHAR  SiS300_SR15[8][4] =
+{
+	{0x01,0x09,0xa3,0x00},
+	{0x43,0x43,0x43,0x00},
+	{0x1e,0x1e,0x1e,0x00},
+	{0x2a,0x2a,0x2a,0x00},
+	{0x06,0x06,0x06,0x00},
+	{0x00,0x00,0x00,0x00},
+	{0x00,0x00,0x00,0x00},
+	{0x00,0x00,0x00,0x00}
+};
+
+#ifndef LINUX_XF86
+static UCHAR SiS300_SR1F = 0x00;
+static UCHAR SiS300_SR21 = 0x16;
+static UCHAR SiS300_SR22 = 0xb2;
+static UCHAR SiS300_SR23 = 0xf6;
+static UCHAR SiS300_SR24 = 0x0d;
+static UCHAR SiS300_SR25[] = {0x0,0x0};
+static UCHAR SiS300_SR31 = 0x00;
+static UCHAR SiS300_SR32 = 0x11;
+static UCHAR SiS300_SR33 = 0x00;
+static UCHAR SiS300_CRT2Data_1_2 = 0x40;
+static UCHAR SiS300_CRT2Data_4_D = 0x00;
+static UCHAR SiS300_CRT2Data_4_E = 0x00;
+static UCHAR SiS300_CRT2Data_4_10 = 0x80;
+
+static const USHORT SiS300_RGBSenseData = 0xd1;
+static const USHORT SiS300_VideoSenseData = 0xb3;
+static const USHORT SiS300_YCSenseData = 0xb9;
+static const USHORT SiS300_RGBSenseData2 = 0x0190;     /*301b*/
+static const USHORT SiS300_VideoSenseData2 = 0x0174;
+static const USHORT SiS300_YCSenseData2 = 0x016b;
+
+static const UCHAR SiS300_CR40[5][4];
+
+static UCHAR SiS300_CR49[2];
+#endif
+
+static const UCHAR SiS300_NTSCPhase[]  = {0x21,0xed,0xba,0x08};  /* TW: Was {0x21,0xed,0x8a,0x08}; */
+static const UCHAR SiS300_PALPhase[]   = {0x2a,0x05,0xe3,0x00};  /* TW: Was {0x2a,0x05,0xd3,0x00};  */
+static const UCHAR SiS300_PALMPhase[]  = {0x21,0xE4,0x2E,0x9B};  /* palmn */
+static const UCHAR SiS300_PALNPhase[]  = {0x21,0xF4,0x3E,0xBA};
+static const UCHAR SiS300_NTSCPhase2[] = {0x21,0xF0,0x7B,0xD6};  /* 301b */
+static const UCHAR SiS300_PALPhase2[]  = {0x2a,0x09,0x86,0xe9};  /* 301b */
+static const UCHAR SiS300_PALMPhase2[] = {0x21,0xE6,0xEF,0xA4}; /* TW: palm 301b*/
+static const UCHAR SiS300_PALNPhase2[] = {0x21,0xF6,0x94,0x46}; /* TW: paln 301b*/
 
 typedef struct _SiS300_PanelDelayTblStruct
 {
 	UCHAR timer[2];
 } SiS300_PanelDelayTblStruct;
 
-SiS300_PanelDelayTblStruct SiS300_PanelDelayTbl[]=
+static const SiS300_PanelDelayTblStruct  SiS300_PanelDelayTbl[] =
 {
-	{{0x05,0xaa}},
+	{{0x05,0xaa}}, /* TW: From 2.04.5a */
 	{{0x05,0x14}},
 	{{0x05,0x36}},
 	{{0x05,0x14}},
@@ -1019,10 +1075,30 @@
 	{{0x05,0x14}},
 	{{0x05,0x14}},
 	{{0x05,0x14}},
-	{{0x05,0x64}},
+	{{0x20,0x80}},
+	{{0x05,0x14}},
+	{{0x05,0x40}},
+	{{0x05,0x60}}
+};
+
+static const SiS300_PanelDelayTblStruct  SiS300_PanelDelayTblLVDS[] =
+{
+	{{0x05,0xaa}},
+	{{0x05,0x14}},
+	{{0x05,0x36}},
+	{{0x05,0x14}},
+	{{0x05,0x14}},
+	{{0x05,0x14}},
+	{{0x05,0x90}},
+	{{0x05,0x90}},
 	{{0x05,0x14}},
 	{{0x05,0x14}},
-	{{0x05,0x14}}
+	{{0x05,0x14}},
+	{{0x05,0x14}},  /* 2.07a (JVC): 14,96 */
+	{{0x05,0x28}},  /* 2.04.5c: 20, 80 - Clevo (2.04.2c): 05, 28 */
+	{{0x05,0x14}},
+	{{0x05,0x14}},  /* Some BIOSes: 05, 40 */
+	{{0x05,0x60}}
 };
 
 typedef struct _SiS300_LCDDataStruct
@@ -1035,7 +1111,7 @@
 	USHORT LCDVT;
 } SiS300_LCDDataStruct;
 
-SiS300_LCDDataStruct  SiS300_StLCD1024x768Data[]=
+static const SiS300_LCDDataStruct  SiS300_StLCD1024x768Data[]=
 {
 	{   66,  31, 992, 510,1320, 816},
 	{   66,  31, 992, 510,1320, 816},
@@ -1046,7 +1122,7 @@
 	{    1,   1,1344, 806,1344, 806}
 };
 
-SiS300_LCDDataStruct  SiS300_ExtLCD1024x768Data[]=
+static const SiS300_LCDDataStruct  SiS300_ExtLCD1024x768Data[]=
 {
 	{   12,   5, 896, 512,1344, 806},
 	{   12,   5, 896, 510,1344, 806},
@@ -1063,7 +1139,7 @@
 	{    1,   1,1344, 806,1344, 806}
 };
 
-SiS300_LCDDataStruct  SiS300_St2LCD1024x768Data[]=
+static const SiS300_LCDDataStruct  SiS300_St2LCD1024x768Data[]=
 {
 	{   62,  25, 800, 546,1344, 806},
 	{   32,  15, 930, 546,1344, 806},
@@ -1074,7 +1150,7 @@
 	{    1,   1,1344, 806,1344, 806}
 };
 
-SiS300_LCDDataStruct  SiS300_StLCD1280x1024Data[]=
+static const SiS300_LCDDataStruct  SiS300_StLCD1280x1024Data[]=
 {
 	{    4,   1, 880, 510,1650,1088},
 	{    4,   1, 880, 510,1650,1088},
@@ -1086,7 +1162,7 @@
 	{    1,   1,1688,1066,1688,1066}
 };
 
-SiS300_LCDDataStruct  SiS300_ExtLCD1280x1024Data[]=
+static const SiS300_LCDDataStruct  SiS300_ExtLCD1280x1024Data[]=
 {
 	{  211,  60,1024, 501,1688,1066},
 	{  211,  60,1024, 508,1688,1066},
@@ -1098,7 +1174,7 @@
 	{    1,   1,1688,1066,1688,1066}
 };
 
-SiS300_LCDDataStruct  SiS300_St2LCD1280x1024Data[]=
+static const SiS300_LCDDataStruct  SiS300_St2LCD1280x1024Data[]=
 {
 	{   22,   5, 800, 510,1650,1088},
 	{   22,   5, 800, 510,1650,1088},
@@ -1110,7 +1186,19 @@
 	{    1,   1,1688,1066,1688,1066}
 };
 
-SiS300_LCDDataStruct  SiS300_NoScaleData[]=
+static const SiS300_LCDDataStruct  SiS300_NoScaleData1024x768[]=
+{
+	{    1,   1, 800, 449, 800, 449},
+	{    1,   1, 800, 449, 800, 449},
+	{    1,   1, 900, 449, 900, 449},
+	{    1,   1, 900, 449, 900, 449},
+	{    1,   1, 800, 525, 800, 525},
+	{    1,   1,1056, 628,1056, 628},
+	{    1,   1,1344, 806,1344, 806},
+	{    1,   1,1688,1066,1688,1066}
+};
+
+static const SiS300_LCDDataStruct  SiS300_NoScaleData1280x1024[]=  /* TW: Fake */
 {
 	{    1,   1, 800, 449, 800, 449},
 	{    1,   1, 800, 449, 800, 449},
@@ -1122,7 +1210,7 @@
 	{    1,   1,1688,1066,1688,1066}
 };
 
-SiS300_LCDDataStruct  SiS300_LCD1280x960Data[]=
+static const SiS300_LCDDataStruct  SiS300_LCD1280x960Data[]=
 {
 	{    9,   2, 800, 500,1800,1000},
 	{    9,   2, 800, 500,1800,1000},
@@ -1135,6 +1223,91 @@
 	{    1,   1,1800,1000,1800,1000}
 };
 
+static const SiS300_LCDDataStruct  SiS300_ExtLCD1400x1050Data[] =  /* TW: New */
+{
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS300_LCDDataStruct  SiS300_ExtLCD1600x1200Data[] =  /* TW: New */
+{
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS300_LCDDataStruct  SiS300_StLCD1400x1050Data[] =  /* TW: New */
+{
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS300_LCDDataStruct  SiS300_StLCD1600x1200Data[] =  /* TW: New */
+{
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS300_LCDDataStruct  SiS300_NoScaleData1400x1050[] =  /* TW: New */
+{
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS300_LCDDataStruct  SiS300_NoScaleData1600x1200[] =  /* TW: New */
+{
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+
 typedef struct _SiS300_TVDataStruct
 {
 	USHORT RVBHCMAX;
@@ -1152,7 +1325,7 @@
 	UCHAR RY4COE;
 } SiS300_TVDataStruct;
 
-SiS300_TVDataStruct  SiS300_StPALData[]=
+static const SiS300_TVDataStruct  SiS300_StPALData[]=
 {
 	{    1,   1, 864, 525,1270, 400, 100,   0, 760,0xf4,0xff,0x1c,0x22},
 	{    1,   1, 864, 525,1270, 350, 100,   0, 760,0xf4,0xff,0x1c,0x22},
@@ -1162,7 +1335,7 @@
 	{    1,   1, 864, 525,1270, 600,  50,   0,   0,0xf4,0xff,0x1c,0x22}
 };
 
-SiS300_TVDataStruct  SiS300_ExtPALData[]=
+static const SiS300_TVDataStruct  SiS300_ExtPALData[]=
 {
 	{   27,  10, 848, 448,1270, 530,  50,   0,  50,0xf4,0xff,0x1c,0x22},
 	{  108,  35, 848, 398,1270, 530,  50,   0,  50,0xf4,0xff,0x1c,0x22},
@@ -1171,11 +1344,11 @@
 	{    9,   4, 848, 528,1270, 530,   0,   0,  50,0xf5,0xfb,0x1b,0x2a},
 	{   36,  25,1060, 648,1316, 530, 438,   0, 438,0xeb,0x05,0x25,0x16},
 	{    3,   2,1080, 619,1270, 540, 438,   0, 438,0xf3,0x00,0x1d,0x20},
-	{    1,   1,1170, 821,1270, 520, 686,   0, 686,0xF3,0x00,0x1D,0x20}     /*301b*/
+	{    1,   1,1170, 821,1270, 520, 686,   0, 686,0xF3,0x00,0x1D,0x20}
 
 };
 
-SiS300_TVDataStruct  SiS300_StNTSCData[]=
+static const SiS300_TVDataStruct  SiS300_StNTSCData[]=
 {
 	{    1,   1, 858, 525,1270, 400,  50,   0, 760,0xf1,0x04,0x1f,0x18},
 	{    1,   1, 858, 525,1270, 350,  50,   0, 640,0xf1,0x04,0x1f,0x18},
@@ -1184,7 +1357,7 @@
 	{    1,   1, 858, 525,1270, 480,   0,   0, 760,0xf1,0x04,0x1f,0x18}
 };
 
-SiS300_TVDataStruct  SiS300_ExtNTSCData[]=
+static const SiS300_TVDataStruct  SiS300_ExtNTSCData[]=
 {
 	{  143,  65, 858, 443,1270, 440, 171,   0, 171,0xf1,0x04,0x1f,0x18},
 	{   88,  35, 858, 393,1270, 440, 171,   0, 171,0xf1,0x04,0x1f,0x18},
@@ -1193,59 +1366,128 @@
 	{  143,  76, 836, 523,1270, 440, 224,   0,   0,0xf1,0x05,0x1f,0x16},
 	{  143, 120,1056, 643,1270, 440,   0, 128,   0,0xf4,0x10,0x1c,0x00},
 	{  143,  76, 836, 523,1270, 440,   0, 128,   0,0xee,0x0c,0x22,0x08},
-	{   65,  64,1056, 791,1270, 480, 638,   0,   0,0xf1,0x04,0x1f,0x18} /*301b*/
+	{   65,  64,1056, 791,1270, 480, 638,   0,   0,0xf1,0x04,0x1f,0x18}
 };
 
-SiS_TVDataStruct  SiS300_St1HiTVData[]=
+static const SiS_TVDataStruct  SiS300_St1HiTVData[]=
 {
  	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
 };
 
-SiS_TVDataStruct  SiS300_St2HiTVData[]=
+static const SiS_TVDataStruct  SiS300_St2HiTVData[]=
 {
  	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
 };
 
-SiS_TVDataStruct  SiS300_ExtHiTVData[]=
+static const SiS_TVDataStruct  SiS300_ExtHiTVData[]=
 {
  	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
 };
 
-UCHAR SiS300_NTSCTiming[] = {
+static const UCHAR SiS300_NTSCTiming[] = {
 	0x17,0x1d,0x03,0x09,0x05,0x06,0x0c,0x0c,
 	0x94,0x49,0x01,0x0a,0x06,0x0d,0x04,0x0a,
 	0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x1b,
-	0x0c,0x50,0x00,0x97,0x00,0xda,0x4a,0x17,
-	0x7d,0x05,0x4b,0x00,0x00,0xe2,0x00,0x02,
+/*	0x0c,0x50,0x00,0x97,0x00,0xda,0x4a,0x17,   - old */
+	0x0c,0x50,0x00,0x99,0x00,0xec,0x4a,0x17,  /* new (2.04.5a) */
+/*	0x7d,0x05,0x4b,0x00,0x00,0xe2,0x00,0x02,   - old */
+	0x88,0x00,0x4b,0x00,0x00,0xe2,0x00,0x02,  /* new */
 	0x03,0x0a,0x65,0x9d,0x08,0x92,0x8f,0x40,
 	0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x50,
 	0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00
 };
 
-UCHAR SiS300_PALTiming[] = {
+static const UCHAR SiS300_PALTiming[] = {
 	0x19,0x52,0x35,0x6e,0x04,0x38,0x3d,0x70,
 	0x94,0x49,0x01,0x12,0x06,0x3e,0x35,0x6d,
 	0x06,0x14,0x3e,0x35,0x6d,0x00,0x45,0x2b,
-	0x70,0x50,0x00,0x9b,0x00,0xd9,0x5d,0x17,
-	0x7d,0x05,0x45,0x00,0x00,0xe8,0x00,0x02,
+/*      0x70,0x50,0x00,0x9b,0x00,0xd9,0x5d,0x17,   - old */
+	0x70,0x50,0x00,0x97,0x00,0xd7,0x5d,0x17,  /* new */
+/*	0x7d,0x05,0x45,0x00,0x00,0xe8,0x00,0x02,   -old */
+	0x88,0x00,0x45,0x00,0x00,0xe8,0x00,0x02,  /* new */
 	0x0d,0x00,0x68,0xb0,0x0b,0x92,0x8f,0x40,
 	0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x63,
 	0x00,0x40,0x3e,0x00,0xe1,0x02,0x28,0x00
 };
 
-UCHAR SiS300_HiTVExtTiming[] = {0x00};
-
-UCHAR SiS300_HiTVSt1Timing[] = {0x00};
-
-UCHAR SiS300_HiTVSt2Timing[] = {0x00};
-
-UCHAR SiS300_HiTVTextTiming[] = {0x00};
-
-UCHAR SiS300_HiTVGroup3Data[] = {0x00};
-
-UCHAR SiS300_HiTVGroup3Simu[] = {0x00};
-
-UCHAR SiS300_HiTVGroup3Text[] = {0x00};
+#ifdef oldHV
+static const UCHAR SiS300_HiTVExtTiming[] = {   /* TW: New */
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x64,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x64,0x90,0x33,0x8c,0x18,0x36,0x3e,0x13,
+	0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40,
+	0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40,
+	0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d,
+	0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00
+};
+
+static const UCHAR SiS300_HiTVSt1Timing[] = {   /* TW: New */
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x65,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x65,0x90,0x7b,0xa8,0x03,0xf0,0x87,0x03,
+	0x11,0x15,0x11,0xcf,0x10,0x11,0xcf,0x10,
+	0x35,0x35,0x3b,0x69,0x1d,0x92,0x0f,0x40,
+	0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x86,
+	0xaf,0x5d,0x0e,0x00,0xfc,0xff,0x2d,0x00
+};
+
+static const UCHAR SiS300_HiTVSt2Timing[] = {   /* TW: New */
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x64,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x64,0x90,0x33,0x8c,0x18,0x36,0x3e,0x13,
+	0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40,
+	0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40,
+	0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d,
+	0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00
+};
+
+static const UCHAR SiS300_HiTVTextTiming[] = {   /* TW: New */
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x65,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x65,0x90,0xe7,0xbc,0x03,0x0c,0x97,0x03,
+	0x14,0x78,0x14,0x08,0x20,0x14,0x08,0x20,
+	0xc8,0xc8,0x3b,0xd2,0x26,0x92,0x0f,0x40,
+        0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x96,
+	0x72,0x5c,0x11,0x00,0xfc,0xff,0x32,0x00
+};
+
+static const UCHAR SiS300_HiTVGroup3Data[] = {   /* TW: New */
+        0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0x5f,
+	0x05,0x21,0xb2,0xb2,0x55,0x77,0x2a,0xa6,
+	0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20,
+	0x8c,0x6e,0x60,0x2e,0x58,0x48,0x72,0x44,
+	0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+	0x4f,0x7f,0x03,0xa8,0x7d,0x20,0x1a,0xa9,
+	0x14,0x05,0x03,0x7e,0x64,0x31,0x14,0x75,
+	0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+};
+
+static const UCHAR SiS300_HiTVGroup3Simu[] = {   /* TW: New */
+        0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0x95,
+	0xdb,0x20,0xb8,0xb8,0x55,0x47,0x2a,0xa6,
+	0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20,
+	0x8c,0x6e,0x60,0x15,0x26,0xd3,0xe4,0x11,
+	0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+	0x67,0x36,0x01,0x47,0x0e,0x10,0xbe,0xb4,
+	0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75,
+	0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+};
+
+static const UCHAR SiS300_HiTVGroup3Text[] = {   /* TW: New */
+        0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0xa7,
+	0xf5,0x20,0xce,0xce,0x55,0x47,0x2a,0xa6,
+	0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20,
+	0x8c,0x6e,0x60,0x18,0x2c,0x0c,0x20,0x22,
+	0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+	0x93,0x3c,0x01,0x50,0x2f,0x10,0xf4,0xca,
+	0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75,
+	0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+};
+#endif
 
 typedef struct _SiS300_LVDSDataStruct
 {
@@ -1255,7 +1497,20 @@
 	USHORT LCDVT;
 } SiS300_LVDSDataStruct;
 
-SiS300_LVDSDataStruct  SiS300_LVDS800x600Data_1[]=
+static const SiS300_LVDSDataStruct  SiS300_LVDS320x480Data_1[]=
+{
+	{848, 433,400, 525},
+	{848, 389,400, 525},
+	{848, 433,400, 525},
+	{848, 389,400, 525},
+	{848, 518,400, 525},
+	{1056,628,400, 525},
+	{400, 525,400, 525},
+	{800, 449,1000, 644},
+	{800, 525,1000, 635}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LVDS800x600Data_1[]=
 {
 	{848, 433,1060, 629},
 	{848, 389,1060, 629},
@@ -1268,7 +1523,7 @@
 	{800, 525,1000, 635}
 };
 
-SiS300_LVDSDataStruct  SiS300_LVDS800x600Data_2[]=
+static const SiS300_LVDSDataStruct  SiS300_LVDS800x600Data_2[]=
 {
 	{1056, 628,1056, 628},
 	{1056, 628,1056, 628},
@@ -1281,7 +1536,33 @@
 	{800, 525,1000, 635}
 };
 
-SiS300_LVDSDataStruct  SiS300_LVDS1024x768Data_1[]=
+static const SiS300_LVDSDataStruct  SiS300_LVDS1024x768Data_1[]=
+{
+	{840, 438,1344, 806},
+	{840, 409,1344, 806},
+	{840, 438,1344, 806},
+	{840, 409,1344, 806},
+	{840, 518,1344, 806},
+	{1050, 638,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LVDS1024x768Data_2[]=
+{
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LVDS1280x1024Data_1[]=
 {
 	{840, 438,1344, 806},
 	{840, 409,1344, 806},
@@ -1294,7 +1575,7 @@
 	{800, 525,1280, 813}
 };
 
-SiS300_LVDSDataStruct  SiS300_LVDS1024x768Data_2[]=
+static const SiS300_LVDSDataStruct  SiS300_LVDS1280x1024Data_2[]=
 {
 	{1344, 806,1344, 806},
 	{1344, 806,1344, 806},
@@ -1307,7 +1588,62 @@
 	{800, 525,1280, 813}
 };
 
-SiS300_LVDSDataStruct  SiS300_LVDS1280x1024Data_1[]=
+static const SiS300_LVDSDataStruct  SiS300_LVDS1400x1050Data_1[]=   /* TW: New */
+{
+        {928, 416, 1688, 1066},
+	{928, 366, 1688, 1066},
+	{928, 416, 1688, 1066},
+	{928, 366, 1688, 1066},
+	{928, 496, 1688, 1066},
+	{1088, 616, 1688, 1066},
+	{1312, 784, 1688, 1066},
+	{1568, 1040, 1688, 1066},
+	{1688, 1066, 1688, 1066}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LVDS1400x1050Data_2[]=   /* TW: New */
+{
+        {1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+};
+
+/* TW: New: */
+static const SiS300_LVDSDataStruct  SiS300_LVDS1024x600Data_1[]=
+{
+	{840, 604,1344, 800},
+	{840, 560,1344, 800},
+	{840, 604,1344, 800},
+	{840, 560,1344, 800},
+	{840, 689,1344, 800},
+	{1050, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{800, 449,1280, 789},
+	{800, 525,1280, 785}
+};
+
+/* TW: New: */
+static const SiS300_LVDSDataStruct  SiS300_LVDS1024x600Data_2[]=
+{
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+/* TW: New: */
+static const SiS300_LVDSDataStruct  SiS300_LVDS1152x768Data_1[]=
 {
 	{840, 438,1344, 806},
 	{840, 409,1344, 806},
@@ -1320,7 +1656,8 @@
 	{800, 525,1280, 813}
 };
 
-SiS300_LVDSDataStruct  SiS300_LVDS1280x1024Data_2[]=
+/* TW: New: */
+static const SiS300_LVDSDataStruct  SiS300_LVDS1152x768Data_2[]=
 {
 	{1344, 806,1344, 806},
 	{1344, 806,1344, 806},
@@ -1333,7 +1670,20 @@
 	{800, 525,1280, 813}
 };
 
-SiS300_LVDSDataStruct  SiS300_LVDS640x480Data_1[]=
+/* TW: New in 650/LVDS BIOS - resolution unknown */
+static const SiS300_LVDSDataStruct  SiS300_LVDSXXXxXXXData_1[]=   /* TW: New */
+{
+        { 800, 449, 800, 449},
+	{ 800, 449, 800, 449},
+	{ 900, 449, 900, 449},
+	{ 900, 449, 900, 449},
+	{ 800, 525, 800, 525},
+	{1056, 628,1056, 628},
+	{1344, 806,1344, 806},
+	{1688, 806,1688, 806}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LVDS640x480Data_1[]=
 {
 	{800, 449, 800, 449},
 	{800, 449, 800, 449},
@@ -1346,8 +1696,90 @@
 	{1056, 628,1056, 628}
 };
 
+static const SiS300_LVDSDataStruct  SiS300_LVDS1280x960Data_1[]=   /* TW: New */
+{
+	{840, 438,1344, 806},
+	{840, 409,1344, 806},
+	{840, 438,1344, 806},
+	{840, 409,1344, 806},
+	{840, 518,1344, 806},
+	{1050, 638,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LVDS1280x960Data_2[]=   /* TW: New */
+{
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LCDA1400x1050Data_1[]=   /* TW: New */
+{	/* TW: Might be temporary (invalid) data */
+        {928, 416, 1688, 1066},
+	{928, 366, 1688, 1066},
+	{1008, 416, 1688, 1066},
+	{1008, 366, 1688, 1066},
+	{1200, 530, 1688, 1066},
+	{1088, 616, 1688, 1066},
+	{1312, 784, 1688, 1066},
+	{1568, 1040, 1688, 1066},
+	{1688, 1066, 1688, 1066}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LCDA1400x1050Data_2[]=   /* TW: New */
+{	/* TW: Temporary data. Not valid */
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LCDA1600x1200Data_1[]=   /* TW: New */
+{	/* TW: Temporary data. Not valid */
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS300_LVDSDataStruct  SiS300_LCDA1600x1200Data_2[]=   /* TW: New */
+{	/* TW: Temporary data. Not valid */
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0}
+};
+
+
 /* TW: New: */
-SiS300_LVDSDataStruct  SiS300_CHTVUNTSCData[]=
+static const SiS300_LVDSDataStruct  SiS300_CHTVUNTSCData[]=
 {
 	{840, 600, 840, 600},
 	{840, 600, 840, 600},
@@ -1357,7 +1789,7 @@
 	{1064, 750,1064, 750}
 };
 
-SiS300_LVDSDataStruct  SiS300_CHTVONTSCData[]=
+static const SiS300_LVDSDataStruct  SiS300_CHTVONTSCData[]=
 {
 	{840, 525, 840, 525},
 	{840, 525, 840, 525},
@@ -1367,7 +1799,7 @@
 	{1040, 700,1040, 700}
 };
 
-SiS300_LVDSDataStruct  SiS300_CHTVUPALData[]=
+static const SiS300_LVDSDataStruct  SiS300_CHTVUPALData[]=
 {
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
@@ -1377,7 +1809,7 @@
 	{936, 836, 936, 836}
 };
 
-SiS300_LVDSDataStruct  SiS300_CHTVOPALData[]=
+static const SiS300_LVDSDataStruct  SiS300_CHTVOPALData[]=
 {
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
@@ -1394,7 +1826,7 @@
 	USHORT LCDVDES;
 } SiS300_LVDSDesStruct;
 
-SiS300_LVDSDesStruct  SiS300_PanelType00_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType00_1[]=
 {
 	{0, 626},
 	{0, 624},
@@ -1407,7 +1839,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType01_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType01_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1420,7 +1852,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType02_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType02_1[]=
 {
 	{0, 626},
 	{0, 624},
@@ -1433,7 +1865,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType03_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType03_1[]=
 {
 	{ 8, 436},
 	{ 8, 440},
@@ -1446,7 +1878,7 @@
 	{1343, 794}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType04_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType04_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1459,7 +1891,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType05_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType05_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1472,7 +1904,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType06_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType06_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1485,7 +1917,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType07_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType07_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1498,7 +1930,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType08_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType08_1[]=
 {
 	{1059, 626},
 	{1059, 624},
@@ -1511,7 +1943,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType09_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType09_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1524,7 +1956,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0a_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0a_1[]=
 {
 	{1059, 626},
 	{1059, 624},
@@ -1537,20 +1969,20 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0b_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0b_1[]=
 {
-	{1343, 798},
-	{1343, 794},
-	{1343, 798},
-	{1343, 794},
-	{1343,   0},
-	{1343,   0},
-	{ 0, 805},
-	{ 0, 794},
-	{ 0,   0}
+	{1343, 0},
+	{1343, 0},
+	{1343, 0},
+	{1343, 0},
+	{1343, 0},   /* 640x480 - BIOS 1343, 0 */
+	{1343, 0},
+	{ 0, 799},
+	{ 0, 0},
+	{ 0, 0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0c_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0c_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1563,7 +1995,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0d_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0d_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1576,20 +2008,20 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0e_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0e_1[]=
 {
 	{1343, 798},
 	{1343, 794},
 	{1343, 798},
 	{1343, 794},
-	{1343,   0},
-	{1343,   0},
-	{ 0, 805},
-	{ 0, 794},
-	{ 0,   0}
+	{1343,   0},  /* 640x480 */
+	{1343,   0},  /* 800x600 */
+	{ 0, 805},    /* 1024x768 */
+	{ 0, 794},    /* 1280x1024 */
+	{ 0,   0}     /* 1280x960 - not applicable */
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0f_1[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0f_1[]=
 {
 	{1343, 798},
 	{1343, 794},
@@ -1602,7 +2034,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType00_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType00_2[]=
 {
 	{976, 527},
 	{976, 502},
@@ -1615,7 +2047,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType01_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType01_2[]=
 {
 	{1152, 622},
 	{1152, 597},
@@ -1628,7 +2060,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType02_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType02_2[]=
 {
 	{976, 527},
 	{976, 502},
@@ -1641,7 +2073,7 @@
 	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType03_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType03_2[]=
 {
 	{1152, 622},
 	{1152, 597},
@@ -1654,7 +2086,7 @@
 	{1152, 597}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType04_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType04_2[]=
 {
 	{1152, 622},
 	{1152, 597},
@@ -1667,7 +2099,7 @@
 	{   0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType05_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType05_2[]=
 {
 	{1152, 622},
 	{1152, 597},
@@ -1680,7 +2112,7 @@
 	{   0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType06_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType06_2[]=
 {
 	{1152, 622},
 	{1152, 597},
@@ -1693,7 +2125,7 @@
 	{   0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType07_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType07_2[]=
 {
  	{1152, 622},
  	{1152, 597},
@@ -1706,7 +2138,7 @@
 	{   0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType08_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType08_2[]=
 {
  	{976, 527},
  	{976, 502},
@@ -1719,7 +2151,7 @@
  	{  0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType09_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType09_2[]=
 {
  	{1152, 622},
  	{1152, 597},
@@ -1732,7 +2164,7 @@
  	{   0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0a_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0a_2[]=
 {
  	{976, 527},
  	{976, 502},
@@ -1745,20 +2177,20 @@
  	{  0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0b_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0b_2[]=
 {
- 	{1152, 622},
- 	{1152, 597},
- 	{1152, 622},
- 	{1152, 597},
- 	{1152, 662},
- 	{1232, 722},
- 	{   0, 805},
- 	{   0, 794},
- 	{   0,   0}
+ 	{ 1152, 700},
+ 	{ 1152, 675},
+ 	{ 1152, 700},
+ 	{ 1152, 675},
+ 	{ 1152, 740},
+ 	{ 1232, 799},
+ 	{    0, 799},
+ 	{    0,   0},
+ 	{    0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0c_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0c_2[]=
 {
  	{1152, 622},
  	{1152, 597},
@@ -1771,7 +2203,7 @@
  	{   0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0d_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0d_2[]=
 {
  	{1152, 622},
  	{1152, 597},
@@ -1784,7 +2216,7 @@
  	{   0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0e_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0e_2[]=
 {
  	{1152, 622},
  	{1152, 597},
@@ -1797,7 +2229,7 @@
  	{   0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_PanelType0f_2[]=
+static const SiS300_LVDSDesStruct  SiS300_PanelType0f_2[]=
 {
  	{1152, 622},
  	{1152, 597},
@@ -1810,35 +2242,87 @@
  	{   0,   0}
 };
 
-/*301b*/
-SiS300_LVDSDesStruct SiS300_PanelType1076_1[]=
+static const SiS300_LVDSDesStruct SiS300_PanelType1076_1[]=   /* TW: New */
 {
-	{0x00,0x00}
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+static const SiS300_LVDSDesStruct SiS300_PanelType1076_2[]=   /* TW: New */
+{
+	{ 1152, 622 },
+	{ 1152, 597 },
+	{ 1152, 622 },
+	{ 1152, 597 },
+	{ 1152, 622 },
+	{ 1232, 722 },
+	{    0, 0   },
+	{    0, 794 },
+	{    0, 0   }
+};
+
+static const SiS300_LVDSDesStruct SiS300_PanelType1210_1[]=   /* TW: New */
+{
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+static const SiS300_LVDSDesStruct SiS300_PanelType1210_2[]=   /* TW: New */
+{
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+static const SiS300_LVDSDesStruct SiS300_PanelType1296_1[]=   /* TW: New */
+{
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+static const SiS300_LVDSDesStruct SiS300_PanelType1296_2[]=   /* TW: New */
+{
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
 };
-SiS300_LVDSDesStruct SiS300_PanelType1210_1[]=
-{
-	{0x00,0x00}
-};
-SiS300_LVDSDesStruct SiS300_PanelType1296_1[]=
-{
-	{0x00,0x00}
-};
-SiS300_LVDSDesStruct SiS300_PanelType1076_2[]=
-{
-	{0x00,0x00}
-};
-SiS300_LVDSDesStruct SiS300_PanelType1210_2[]=
-{
-	{0x00,0x00}
-};
-SiS300_LVDSDesStruct SiS300_PanelType1296_2[]=
-{
-	{0x00,0x00}
-};
-/*end 301b*/
+
 
 /* TW: New */
-SiS300_LVDSDesStruct  SiS300_CHTVUNTSCDesData[]=
+static const SiS300_LVDSDesStruct  SiS300_CHTVUNTSCDesData[]=
 {
  	{ 0,   0},
  	{ 0,   0},
@@ -1848,7 +2332,7 @@
  	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_CHTVONTSCDesData[]=
+static const SiS300_LVDSDesStruct  SiS300_CHTVONTSCDesData[]=
 {
  	{ 0,   0},
  	{ 0,   0},
@@ -1858,7 +2342,7 @@
  	{ 0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_CHTVUPALDesData[]=
+static const SiS300_LVDSDesStruct  SiS300_CHTVUPALDesData[]=
 {
  	{256,   0},
  	{256,   0},
@@ -1868,7 +2352,7 @@
  	{  0,   0}
 };
 
-SiS300_LVDSDesStruct  SiS300_CHTVOPALDesData[]=
+static const SiS300_LVDSDesStruct  SiS300_CHTVOPALDesData[]=
 {
  	{256,   0},
  	{256,   0},
@@ -1884,7 +2368,7 @@
 UCHAR CR[15];
 } SiS300_LVDSCRT1DataStruct;
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_1[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_1[]=
 {
 	{{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f,
 	  0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
@@ -1906,7 +2390,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_1[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_1[]=
 { 
 	{{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f,
 	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
@@ -1931,7 +2415,7 @@
 	  0x01} }
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_1[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_1[]=
 {
 	{{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f,
 	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
@@ -1956,7 +2440,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_1_H[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_1_H[]=
 {
 	{{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f,
 	  0x90,0x85,0x8f,0xab,0x30,0x00,0x04,
@@ -1978,7 +2462,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_1_H[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_1_H[]=
 {
 	{{0x37,0x27,0x9B,0x2b,0x94,0xc4,0x1f,
 	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
@@ -2003,7 +2487,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_1_H[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_1_H[]=
 {
 	{{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f,
 	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x04,
@@ -2028,7 +2512,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_2[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_2[]=
 {
 	{{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
 	  0xf4,0x88,0x8f,0x73,0x20,0x00,0x06,
@@ -2050,7 +2534,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_2[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_2[]=
 {
 	{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
 	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
@@ -2075,7 +2559,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_2[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_2[]=
 {
 	{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
 	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
@@ -2100,7 +2584,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_2_H[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT1800x600_2_H[]=
 {
 	{{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
 	  0xf4,0x88,0x8f,0x73,0x20,0x00,0x05,
@@ -2122,7 +2606,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_2_H[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x768_2_H[]=
 {
 	{{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
 	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
@@ -2147,7 +2631,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_2_H[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11280x1024_2_H[]=
 {
 	{{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
 	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
@@ -2172,8 +2656,208 @@
 	  0x01}}
 };
 
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x600_1[] =
+{
+        {{0x64,0x4f,0x88,0x54,0x9f,0x5a,0x3e,
+	  0xe8,0x8f,0x8f,0x5b,0x00,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x2e,0x3e,
+	  0xb9,0x80,0x5d,0x2f,0x00,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x5a,0x3e,
+	  0xe8,0x8f,0x8f,0x5b,0x00,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x2e,0x3e,
+	  0xb9,0x80,0x5d,0x2f,0x00,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0xaf,0xba,
+	  0x3b,0x82,0xdf,0xb0,0x00,0x00,0x01,
+	  0x00}},
+        {{0x7e,0x63,0x82,0x68,0x15,0x1e,0xf1,
+	  0xae,0x85,0x57,0x1f,0x30,0x00,0x26,
+	  0x01}},
+        {{0xa3,0x7f,0x87,0x86,0x97,0x1e,0xf1,
+	  0xae,0x85,0x57,0x1f,0x30,0x00,0x02,
+	  0x01}}
+};
+
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x600_1_H[] =
+{
+        {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+          0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e,
+	  0xe2,0x89,0xdf,0x05,0x00,0x00,0x44,
+	  0x00}},
+        {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0,
+	  0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55,
+	  0x01}},
+        {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01}}
+};
+
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x600_2[] =
+{
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+          0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+	  0x01}},
+        {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+	  0x01}}
+};
+
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11024x600_2_H[] =
+{
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+	  0x01}},
+        {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01}}
+};
+
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11152x768_1[] =
+{
+        {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x04,0x3e,
+	  0xe2,0x89,0xdf,0x05,0x00,0x00,0x01,
+	  0x00}},
+        {{0x7e,0x63,0x82,0x68,0x15,0x7c,0xf0,
+	  0x5a,0x8f,0x57,0x7d,0x20,0x00,0x26,
+	  0x01}},
+        {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+	  0x01}}
+};
+
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11152x768_1_H[] =
+{
+        {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e,
+	  0xe2,0x89,0xdf,0x05,0x00,0x00,0x44,
+	  0x00}},
+        {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0,
+	  0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55,
+	  0x01}},
+        {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01}}
+};
+
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11152x768_2[] =
+{
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+	  0x01}},
+        {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+	  0x01}}
+};
+
+static const SiS300_LVDSCRT1DataStruct  SiS300_LVDSCRT11152x768_2_H[] =
+{
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+	  0x01}},
+        {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01}}
+};
+
 /* TW: New */
-SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1UNTSC[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1UNTSC[]=
 {
 	{{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
 	  0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
@@ -2195,7 +2879,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1ONTSC[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1ONTSC[]=
 {
 	{{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
 	  0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
@@ -2217,7 +2901,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1UPAL[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1UPAL[]=
 {
 	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
 	  0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
@@ -2239,7 +2923,7 @@
 	  0x01 }}
 };
 
-SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1OPAL[]=
+static const SiS300_LVDSCRT1DataStruct  SiS300_CHTVCRT1OPAL[]=
 {
 	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
 	  0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
@@ -2265,58 +2949,58 @@
 /* TW: New */
 typedef struct _SiS300_CHTVRegDataStruct
 {
-	UCHAR Reg[5];
+	UCHAR Reg[16];
 } SiS300_CHTVRegDataStruct;
 
-SiS300_CHTVRegDataStruct SiS300_CHTVReg_UNTSC[] = {
-	{{0x4a,0x94,0x00,0x48,0xfe}},
-	{{0x4a,0x94,0x00,0x48,0xfe}},
-	{{0x4a,0x94,0x00,0x48,0xfe}},
-	{{0x4a,0x94,0x00,0x48,0xfe}},
-	{{0x6a,0x6a,0x00,0x2d,0xfa}}, /* Mode 17: 640x480 NTSC 7/8  */
-	{{0x8d,0xc4,0x00,0x3b,0xfb}}  /* Mode 24: 800x600 NTSC 7/10 */
-};
-
-SiS300_CHTVRegDataStruct SiS300_CHTVReg_ONTSC[] = {
-	{{0x49,0x94,0x00,0x34,0xfe}},
-	{{0x49,0x94,0x00,0x34,0xfe}},
-	{{0x49,0x94,0x00,0x34,0xfe}},
-	{{0x49,0x94,0x00,0x34,0xfe}},
-	{{0x69,0x6a,0x00,0x1e,0xfd}}, /* Mode 16: 640x480 NTSC 1/1 */
-	{{0x8c,0xb4,0x00,0x32,0xf9}}  /* Mode 23: 800x600 NTSC 3/4 */
-};
-
-SiS300_CHTVRegDataStruct SiS300_CHTVReg_UPAL[] = {
-	{{0x41,0x12,0x01,0x50,0x34}},
-	{{0x41,0x12,0x00,0x50,0x00}},
-	{{0x41,0x12,0x01,0x50,0x34}},
-	{{0x41,0x12,0x00,0x50,0x00}},
-	{{0x63,0x94,0x01,0x50,0x30}}, /* Mode 15: 640x480 PAL 5/6 */
+static const SiS300_CHTVRegDataStruct SiS300_CHTVReg_UNTSC[] = {
+	{{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x4a,0x94,0x00,0x48,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x6a,0x6a,0x00,0x2d,0xfa,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 17: 640x480 NTSC 7/8  */
+	{{0x8d,0xc4,0x00,0x3b,0xfb,0,0,0,0,0,0,0,0,0,0,0}}  /* Mode 24: 800x600 NTSC 7/10 */
+};
+
+static const SiS300_CHTVRegDataStruct SiS300_CHTVReg_ONTSC[] = {
+	{{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x49,0x94,0x00,0x34,0xfe,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x69,0x6a,0x00,0x1e,0xfd,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 16: 640x480 NTSC 1/1 */
+	{{0x8c,0xb4,0x00,0x32,0xf9,0,0,0,0,0,0,0,0,0,0,0}}  /* Mode 23: 800x600 NTSC 3/4 */
+};
+
+static const SiS300_CHTVRegDataStruct SiS300_CHTVReg_UPAL[] = {
+	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x63,0x94,0x01,0x50,0x30,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 15: 640x480 PAL 5/6 */
 	/* TW: For 800x600, 3/4 is VERY underscan */
-	{{0x84,0x64,0x01,0x4e,0x2f}}  /* Mode 21: 800x600 PAL 3/4 */
+	{{0x84,0x64,0x01,0x4e,0x2f,0,0,0,0,0,0,0,0,0,0,0}}  /* Mode 21: 800x600 PAL 3/4 */
 	/* TW: Mode 20 is still underscan, use it instead? */
 	/* {{0x83,0x76,0x01,0x40,0x31}} */ /* Mode 20: 800x600 PAL 5/6 */
 };
 
-SiS300_CHTVRegDataStruct SiS300_CHTVReg_OPAL[] = {
-	{{0x41,0x12,0x01,0x50,0x34}}, /* Mode 9: 640x400 PAL 1/1 */
-	{{0x41,0x12,0x00,0x50,0x00}},
-	{{0x41,0x12,0x01,0x50,0x34}},
-	{{0x41,0x12,0x00,0x50,0x00}},
-	{{0x61,0x94,0x01,0x36,0x30}}, /* Mode 14: 640x480 PAL 1/1 */
-	{{0x83,0x76,0x01,0x40,0x31}}  /* Mode 20: 800x600 PAL 5/6 */
+static const SiS300_CHTVRegDataStruct SiS300_CHTVReg_OPAL[] = {
+	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 9: 640x400 PAL 1/1 */
+	{{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x41,0x12,0x01,0x50,0x34,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x41,0x12,0x00,0x50,0x00,0,0,0,0,0,0,0,0,0,0,0}},
+	{{0x61,0x94,0x01,0x36,0x30,0,0,0,0,0,0,0,0,0,0,0}}, /* Mode 14: 640x480 PAL 1/1 */
+	{{0x83,0x76,0x01,0x40,0x31,0,0,0,0,0,0,0,0,0,0,0}}  /* Mode 20: 800x600 PAL 5/6 */
 	/* {{0x81,0x12,0x01,0x50,0x34}}  */ /* TW: (test) Mode 19: 800x600 PAL 1/1 */
 };
 /* TW: New end */
 
 /* TW: New */
-UCHAR SiS300_CHTVVCLKUNTSC[] = {0x29,0x29,0x29,0x29,0x2a,0x2e};
+static const UCHAR SiS300_CHTVVCLKUNTSC[] = {0x29,0x29,0x29,0x29,0x2a,0x2e};
 
-UCHAR SiS300_CHTVVCLKONTSC[] = {0x2c,0x2c,0x2c,0x2c,0x2d,0x2b};
+static const UCHAR SiS300_CHTVVCLKONTSC[] = {0x2c,0x2c,0x2c,0x2c,0x2d,0x2b};
 
-UCHAR SiS300_CHTVVCLKUPAL[]  = {0x2f,0x2f,0x2f,0x2f,0x2f,0x31};
+static const UCHAR SiS300_CHTVVCLKUPAL[]  = {0x2f,0x2f,0x2f,0x2f,0x2f,0x31};
 
-UCHAR SiS300_CHTVVCLKOPAL[]  = {0x2f,0x2f,0x2f,0x2f,0x30,0x32};
+static const UCHAR SiS300_CHTVVCLKOPAL[]  = {0x2f,0x2f,0x2f,0x2f,0x30,0x32};
 /* TW: New end */
 
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/sis/310vtbl.h linux.20pre10-ac2/drivers/video/sis/310vtbl.h
--- linux.20pre10/drivers/video/sis/310vtbl.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/sis/310vtbl.h	2002-10-11 00:17:32.000000000 +0100
@@ -1,3 +1,8 @@
+
+
+/* Register settings for SiS 310/325 series */
+
+
 typedef struct _SiS310_StStruct
 {
 	UCHAR St_ModeID;
@@ -10,7 +15,7 @@
 	UCHAR VB_StTVYFilterIndex;
 } SiS310_StStruct;
 
-SiS310_StStruct SiS310_SModeIDTable[]=
+static const SiS310_StStruct SiS310_SModeIDTable[]=
 {
 	{0x01,0x9208,0x01,0x00,0x00,0x00,0x01,0x00},
 	{0x01,0x1210,0x14,0x01,0x01,0x00,0x01,0x00},
@@ -47,7 +52,7 @@
 	UCHAR GRC[9];
 } SiS310_StandTableStruct;
 
-SiS310_StandTableStruct SiS310_StandTable[]=
+static const SiS310_StandTableStruct SiS310_StandTable[]=
 {
 /* MD_0_200 */
  {
@@ -490,7 +495,7 @@
 	UCHAR Ext_ModeID;
 	USHORT Ext_ModeFlag;
 	USHORT Ext_ModeInfo;
-	USHORT Ext_Point;
+	USHORT Ext_Point;    /* TW: Address of table entry in (older) BIOS image */
 	USHORT Ext_VESAID;
 	UCHAR Ext_VESAMEMSize;
 	UCHAR Ext_RESINFO;
@@ -500,66 +505,89 @@
 	UCHAR REFindex;
 } SiS310_ExtStruct;
 
-SiS310_ExtStruct  SiS310_EModeIDTable[]=
+/* TW: Checked with 650/LVDS and 650/301LVx 1.10.6s */
+static const SiS310_ExtStruct  SiS310_EModeIDTable[]=
 {
-	{0x6a,0x2212,0x0407,0x3a81,0x0102,0x08,0x07,0x00,0x00,0x07,0x00},
-	{0x2e,0x0a1b,0x0306,0x3a57,0x0101,0x08,0x06,0x00,0x00,0x05,0x08},
-	{0x2f,0x0a1b,0x0305,0x3a50,0x0100,0x08,0x05,0x00,0x00,0x05,0x10},
-	{0x30,0x2a1b,0x0407,0x3a81,0x0103,0x08,0x07,0x00,0x00,0x07,0x00},
-	{0x31,0x0a1b,0x030d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},
-	{0x32,0x0a1b,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},
-	{0x33,0x0a1d,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},
-	{0x34,0x2a1d,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},
-	{0x35,0x0a1f,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},
-	{0x36,0x2a1f,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},
-	{0x37,0x0212,0x0508,0x3aab,0x0104,0x08,0x08,0x00,0x00,0x00,0x13},
-	{0x38,0x0a1b,0x0508,0x3aab,0x0105,0x08,0x08,0x00,0x00,0x00,0x13},
-	{0x3a,0x0e3b,0x0609,0x3adc,0x0107,0x08,0x09,0x00,0x00,0x00,0x1a},
-	{0x3c,0x063b,0x070a,0x3af2,0x0130,0x08,0x0a,0x00,0x00,0x00,0x1e},
-	{0x3d,0x067d,0x070a,0x3af2,0x0131,0x08,0x0a,0x00,0x00,0x00,0x1e},
+	{0x6a,0x2212,0x0407,0x3a81,0x0102,0x08,0x07,0x00,0x00,0x07,0x00},          /* 800x600x? */
+	{0x2e,0x0a1b,0x0306,0x3a57,0x0101,0x08,0x06,0x00,0x00,0x05,0x08},          /* 640x480x8 */
+/*	{0x2e,0x021b,0x0306,0x3a57,0x0101,0x08,0x06,0x00,0x00,0x05,0x08},    */    /* 640x480x8 - 650/LVDS BIOS (no CRt2Mode) */
+	{0x2f,0x0a1b,0x0305,0x3a50,0x0100,0x08,0x05,0x00,0x00,0x05,0x10},          /* 640x400x8 */
+/*	{0x2f,0x021b,0x0305,0x3a50,0x0100,0x08,0x05,0x00,0x00,0x05,0x10},    */    /* 640x400x8 - 650/LVDS BIOS (no CRt2Mode) */
+	{0x30,0x2a1b,0x0407,0x3a81,0x0103,0x08,0x07,0x00,0x00,0x07,0x00},          /* 800x600x8 */
+/*	{0x30,0x221b,0x0407,0x3a81,0x0103,0x08,0x07,0x00,0x00,0x07,0x00},    */    /* 800x600x8 - 650/LVDS BIOS (no CRt2Mode) */
+/*      {0x31,0x0a1b,0x030d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},    */    /* 720x480x8 */
+        {0x31,0x0a1b,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},          /* 720x480x8 BIOS (301/LVDS) */
+	{0x32,0x0a1b,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},          /* 720x576x8 */
+	{0x33,0x0a1d,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},          /* 720x480x16 */
+	{0x34,0x2a1d,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},          /* 720x576x16 */
+	{0x35,0x0a1f,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},          /* 720x480x32 */
+	{0x36,0x2a1f,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},          /* 720x576x32 */
+	{0x37,0x0212,0x0508,0x3aab,0x0104,0x08,0x08,0x00,0x00,0x00,0x13},          /* 1024x768x? */
+	{0x38,0x0a1b,0x0508,0x3aab,0x0105,0x08,0x08,0x00,0x00,0x00,0x13},          /* 1024x768x8 */
+/*	{0x38,0x021b,0x0508,0x3aab,0x0105,0x08,0x08,0x00,0x00,0x00,0x13},    */    /* 1024x768x8 - 650/LVDS BIOS (no CRt2Mode)  */
+	{0x3a,0x0e3b,0x0609,0x3adc,0x0107,0x08,0x09,0x00,0x00,0x00,0x1a},          /* 1280x1024x8 */
+/*	{0x3a,0x063b,0x0609,0x3adc,0x0107,0x08,0x09,0x00,0x00,0x00,0x1a},    */    /* 1280x1024x8 - 650/LVDS BIOS*/
+	{0x3c,0x0e3b,0x070a,0x3af2,0x0130,0x08,0x0a,0x00,0x00,0x00,0x1e},          /* 1600x1200x8 */
+/*	{0x3c,0x063b,0x070a,0x3af2,0x0130,0x08,0x0a,0x00,0x00,0x00,0x1e},    */    /* 1600x1200x8 - 650/LVDS BIOS */
+	{0x3d,0x067d,0x070a,0x3af2,0x0131,0x08,0x0a,0x00,0x00,0x00,0x1e},          /* 1600x1200x16 - 650/301LVx - no CRT2Mode? */
 	{0x40,0x9a1c,0x0000,0x3a34,0x010d,0x08,0x00,0x00,0x00,0x04,0x25},
 	{0x41,0x9a1d,0x0000,0x3a34,0x010e,0x08,0x00,0x00,0x00,0x04,0x25},
 	{0x43,0x0a1c,0x0306,0x3a57,0x0110,0x08,0x06,0x00,0x00,0x05,0x08},
-	{0x44,0x0a1d,0x0306,0x3a57,0x0111,0x08,0x06,0x00,0x00,0x05,0x08},
+	{0x44,0x0a1d,0x0306,0x3a57,0x0111,0x08,0x06,0x00,0x00,0x05,0x08},          /* 640x480x16 */
 	{0x46,0x2a1c,0x0407,0x3a81,0x0113,0x08,0x07,0x00,0x00,0x07,0x00},
-	{0x47,0x2a1d,0x0407,0x3a81,0x0114,0x08,0x07,0x00,0x00,0x07,0x00},
+	{0x47,0x2a1d,0x0407,0x3a81,0x0114,0x08,0x07,0x00,0x00,0x07,0x00},          /* 800x600x16 */
 	{0x49,0x0a3c,0x0508,0x3aab,0x0116,0x08,0x08,0x00,0x00,0x00,0x13},
-	{0x4a,0x0a3d,0x0508,0x3aab,0x0117,0x08,0x08,0x00,0x00,0x00,0x13},
+	{0x4a,0x0a3d,0x0508,0x3aab,0x0117,0x08,0x08,0x00,0x00,0x00,0x13},          /* 1024x768x16 */
 	{0x4c,0x0e7c,0x0609,0x3adc,0x0119,0x08,0x09,0x00,0x00,0x00,0x1a},
-	{0x4d,0x0e7d,0x0609,0x3adc,0x011a,0x08,0x09,0x00,0x00,0x00,0x1a},
+	{0x4d,0x0e7d,0x0609,0x3adc,0x011a,0x08,0x09,0x00,0x00,0x00,0x1a},          /* 1280x1024x16 */
 	{0x50,0x9a1b,0x0001,0x3a3b,0x0132,0x08,0x01,0x00,0x00,0x04,0x26},
+/*	{0x50,0x921b,0x0001,0x3a3b,0x0132,0x08,0x01,0x00,0x00,0x04,0x26},     */   /* 650/LVDS BIOS */
 	{0x51,0xba1b,0x0103,0x3a42,0x0133,0x08,0x03,0x00,0x00,0x07,0x27},
-	{0x52,0x9a1b,0x0204,0x3a49,0x0134,0x08,0x04,0x00,0x00,0x00,0x28},
+/*	{0x52,0x9a1b,0x0204,0x3a49,0x0134,0x08,0x04,0x00,0x00,0x00,0x28},  */
+  	{0x52,0xba1b,0x0204,0x3a49,0x0134,0x08,0x04,0x00,0x00,0x00,0x28},          /* 650/301 BIOS */
+/*	{0x52,0xb21b,0x0204,0x3a49,0x0134,0x08,0x04,0x00,0x00,0x00,0x28},     */   /* 650/LVDS BIOS (no CRT2Mode) */
 	{0x56,0x9a1d,0x0001,0x3a3b,0x0135,0x08,0x01,0x00,0x00,0x04,0x26},
 	{0x57,0xba1d,0x0103,0x3a42,0x0136,0x08,0x03,0x00,0x00,0x07,0x27},
-	{0x58,0x9a1d,0x0204,0x3a49,0x0137,0x08,0x04,0x00,0x00,0x00,0x28},
+/*	{0x58,0x9a1d,0x0204,0x3a49,0x0137,0x08,0x04,0x00,0x00,0x00,0x28},  */
+ 	{0x58,0xba1d,0x0204,0x3a49,0x0137,0x08,0x04,0x00,0x00,0x00,0x28},          /* BIOS (301+LVDS) */
 	{0x59,0x9a1b,0x0000,0x3a34,0x0138,0x08,0x00,0x00,0x00,0x04,0x25},
-	{0x5A,0x021b,0x0014,0x3b83,0x0138,0x08,0x01,0x00,0x00,0x04,0x3f}, /*fstn add new mode*/
-	{0x5B,0x0a1d,0x0014,0x3b83,0x0135,0x08,0x01,0x00,0x00,0x04,0x3f}, /*fstn add new mode*/
+/*	{0x59,0x921b,0x0000,0x3a34,0x0138,0x08,0x00,0x00,0x00,0x04,0x25},     */   /* 650/LVDS BIOS (no CRT2Mode) */
+	{0x5A,0x021b,0x0014,0x3b83,0x0138,0x08,0x01,0x00,0x00,0x04,0x3f},          /* 320x480x8 fstn add new mode*/
+	{0x5B,0x0a1d,0x0014,0x3b83,0x0135,0x08,0x01,0x00,0x00,0x04,0x3f},          /* 320x480x16 fstn add new mode*/
+	{0x5c,0xba1f,0x0204,0x3a49,0x0000,0x08,0x04,0x00,0x00,0x00,0x28},          /* TW: inserted 512x384x32 */
 	{0x5d,0x0a1d,0x0305,0x3a50,0x0139,0x08,0x05,0x00,0x00,0x07,0x10},
-	{0x62,0x0a3f,0x0306,0x3a57,0x013a,0x08,0x06,0x00,0x00,0x05,0x08},
-	{0x63,0x2a3f,0x0407,0x3a81,0x013b,0x08,0x07,0x00,0x00,0x07,0x00},
-	{0x64,0x0a7f,0x0508,0x3aab,0x013c,0x08,0x08,0x00,0x00,0x00,0x13},
-	{0x65,0x0eff,0x0609,0x3adc,0x013d,0x08,0x09,0x00,0x00,0x00,0x1a},
-	{0x66,0x06ff,0x070a,0x3af2,0x013e,0x08,0x0a,0x00,0x00,0x00,0x1e},
-	{0x68,0x067b,0x080b,0x3b17,0x013f,0x08,0x0b,0x00,0x00,0x00,0x29},
-	{0x69,0x06fd,0x080b,0x3b17,0x0140,0x08,0x0b,0x00,0x00,0x00,0x29},
-	{0x6b,0x07ff,0x080b,0x3b17,0x0141,0x10,0x0b,0x00,0x00,0x00,0x29},
-	{0x6c,0x067b,0x090c,0x3b37,0x0000,0x08,0x0c,0x00,0x00,0x00,0x2f},
-	{0x6d,0x06fd,0x090c,0x3b37,0x0000,0x10,0x0c,0x00,0x00,0x00,0x2f},
-	{0x6e,0x07ff,0x090c,0x3b37,0x0000,0x10,0x0c,0x00,0x00,0x00,0x2f},
-	{0x70,0x2a1b,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},
-	{0x71,0x0a1b,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},
-	{0x74,0x0a1d,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},
-	{0x75,0x0a3d,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},
-	{0x76,0x2a1f,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},
-	{0x77,0x0a1f,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},
-	{0x78,0x0a3f,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},
-	{0x79,0x0a3b,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},
-	{0x7a,0x2a1d,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},
-	{0x7b,0x0e3b,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},
-	{0x7c,0x0e7d,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},
-	{0x7d,0x0eff,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},
+	{0x62,0x0a3f,0x0306,0x3a57,0x013a,0x08,0x06,0x00,0x00,0x05,0x08},          /* 640x480x32 */
+	{0x63,0x2a3f,0x0407,0x3a81,0x013b,0x08,0x07,0x00,0x00,0x07,0x00},          /* 800x600x32 */
+	{0x64,0x0a7f,0x0508,0x3aab,0x013c,0x08,0x08,0x00,0x00,0x00,0x13},          /* 1024x768x32 */
+	{0x65,0x0eff,0x0609,0x3adc,0x013d,0x08,0x09,0x00,0x00,0x00,0x1a},          /* 1280x1024x32 */
+	{0x66,0x06ff,0x070a,0x3af2,0x013e,0x08,0x0a,0x00,0x00,0x00,0x1e},          /* 1600x1200x32 */
+	{0x68,0x067b,0x080b,0x3b17,0x013f,0x08,0x0b,0x00,0x00,0x00,0x29},          /* 1920x1440x8 */
+	{0x69,0x06fd,0x080b,0x3b17,0x0140,0x08,0x0b,0x00,0x00,0x00,0x29},          /* 1920x1440x16 */
+	{0x6b,0x07ff,0x080b,0x3b17,0x0141,0x10,0x0b,0x00,0x00,0x00,0x29},          /* 1920x1440x32 */
+	{0x6c,0x067b,0x090c,0x3b37,0x0000,0x08,0x0c,0x00,0x00,0x00,0x2f},          /* 2048x1536x8 */
+	{0x6d,0x06fd,0x090c,0x3b37,0x0000,0x10,0x0c,0x00,0x00,0x00,0x2f},          /* 2048x1536x16 */
+	{0x6e,0x07ff,0x090c,0x3b37,0x0000,0x10,0x0c,0x00,0x00,0x00,0x2f},          /* 2048x1536x32 */
+	{0x70,0x2a1b,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},          /* 800x480x8 */
+	{0x71,0x0a1b,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},          /* 1024x576x8 */
+	{0x74,0x0a1d,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},          /* 1024x576x16 */
+	{0x75,0x0a3d,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},	   /* 1280x720x16 */
+	{0x76,0x2a1f,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},          /* 800x480x32 */
+	{0x77,0x0a1f,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},	   /* 1024x576x32 */
+	{0x78,0x0a3f,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},	   /* 1280x720x32 */
+	{0x79,0x0a3b,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},	   /* 1280x720x8 */
+	{0x7a,0x2a1d,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},          /* 800x480x16 */
+	{0x7c,0x0e3b,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},          /* 1280x960x8 - TW */
+	{0x7d,0x0e7d,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},          /* 1280x960x16 - TW */
+	{0x7e,0x0eff,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},          /* 1280x960x32 - TW */
+        /* TW: 650/LVDS BIOS new modes */
+/*	{0x23,0x063b,0x0614,0x36f7,0x0000,0x08,0x14,0x00,0x00,0x00,0x40},  */      /* 1280x768x8 - 650/LVDS BIOS */
+	{0x23,0x0e3b,0x0614,0x36f7,0x0000,0x08,0x14,0x00,0x00,0x00,0x40},          /* 1280x768x8 */
+	{0x24,0x0e7d,0x0614,0x36f7,0x0000,0x08,0x14,0x00,0x00,0x00,0x40},          /* 1280x768x16 */
+	{0x25,0x0eff,0x0614,0x36f7,0x0000,0x08,0x14,0x00,0x00,0x00,0x40},          /* 1280x768x32 */
+	{0x26,0x0e3b,0x0c15,0x36fe,0x0000,0x08,0x15,0x00,0x00,0x00,0x41},          /* 1400x1050x8 */
+/*	{0x26,0x063b,0x0c15,0x36fe,0x0000,0x08,0x15,0x00,0x00,0x00,0x41},    */    /* 1400x1050x8 - 650/LVDS BIOS */
+	{0x27,0x0e7d,0x0c15,0x36fe,0x0000,0x08,0x15,0x00,0x00,0x00,0x41},          /* 1400x1050x16 */
+	{0x28,0x0eff,0x0c15,0x36fe,0x0000,0x08,0x15,0x00,0x00,0x00,0x41},          /* 1400x1050x32*/
 	{0xff,0x0000,0x0000,0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00}
 };
 
@@ -575,9 +603,10 @@
 	USHORT ROM_OFFSET;
 } SiS310_Ext2Struct;
 
-SiS310_Ext2Struct SiS310_RefIndex[]=
+static const SiS310_Ext2Struct SiS310_RefIndex[]=
 {
-	{0x005f,0x0d,0x03,0x05,0x6a, 800, 600,0x3a81}, /* 0x0 */
+/*	{0x005f,0x0d,0x03,0x05,0x6a, 800, 600,0x3a81},    0x0 - TW: Patch for Chrontel 7019  */
+	{0x085f,0x0d,0x03,0x05,0x6a, 800, 600,0x3a81}, /* 0x0 */
 	{0x0467,0x0e,0x04,0x05,0x6a, 800, 600,0x3a86}, /* 0x1 */
 	{0x0067,0x0f,0x08,0x48,0x6a, 800, 600,0x3a8b}, /* 0x2 */
 	{0x0067,0x10,0x07,0x8b,0x6a, 800, 600,0x3a90}, /* 0x3 */
@@ -585,7 +614,8 @@
 	{0x4147,0x12,0x0d,0x00,0x6a, 800, 600,0x3a9a}, /* 0x5 */
 	{0x4047,0x13,0x13,0x00,0x6a, 800, 600,0x3a9f}, /* 0x6 */
 	{0x4047,0x14,0x1c,0x00,0x6a, 800, 600,0x3aa4}, /* 0x7 */
-	{0xc05f,0x05,0x00,0x04,0x2e, 640, 480,0x3a57}, /* 0x8 */
+/*	{0xc05f,0x05,0x00,0x04,0x2e, 640, 480,0x3a57},    0x8 - TW: Patch for Chrontel 7019  */
+	{0xc85f,0x05,0x00,0x04,0x2e, 640, 480,0x3a57}, /* 0x8 */
 	{0xc067,0x06,0x02,0x04,0x2e, 640, 480,0x3a5c}, /* 0x9 */
 	{0xc067,0x07,0x02,0x47,0x2e, 640, 480,0x3a61}, /* 0xa */
 	{0xc067,0x08,0x03,0x8a,0x2e, 640, 480,0x3a66}, /* 0xb */
@@ -638,9 +668,11 @@
 	{0x0057,0x38,0x19,0x0a,0x75,1280, 720,0x3b74}, /* 0x3a */
 	{0x0047,0x39,0x1e,0x0a,0x75,1280, 720,0x3b79}, /* 0x3b */
 	{0x0047,0x3a,0x20,0x0a,0x75,1280, 720,0x3b7e}, /* 0x3c */
-	{0x0027,0x3b,0x19,0x08,0x7b,1280, 960,0x3ad0}, /* 0x3d */
-	{0x0027,0x3b,0x19,0x08,0x7b,1280, 960,0x3ad5}, /* 0x3e */
-	{0xc07f,0x01,0x00,0x06,0x5a, 320, 480,0x3b83}, /* 0x3f */    /*fstn add new mode */
+	{0x0027,0x3b,0x19,0x08,0x7c,1280, 960,0x3ad0}, /* 0x3d */
+	{0x0027,0x3b,0x19,0x08,0x7c,1280, 960,0x3ad5}, /* 0x3e */
+	{0xc07f,0x01,0x00,0x06,0x5a, 320, 480,0x3b83}, /* 0x3f */    /* FSTN mode */
+        {0x0077,0x42,0x12,0x07,0x23,1280, 768,0x0000}, /* 0x40 */    /* TW: 650/LVDS/301LVx new mode */
+	{0x0067,0x43,0x4d,0x08,0x26,1400,1050,0x0000}, /* 0x41 */    /* TW: 650/LVDS/301LVx new mode */
 	{0xffff,0x00,0x00,0x00,0x00,0000,0000,0x0000}
 };
 
@@ -648,203 +680,214 @@
 {
  	UCHAR CR[17];
 } SiS310_CRT1TableStruct;
-SiS310_CRT1TableStruct SiS310_CRT1Table[]=
+
+static const SiS310_CRT1TableStruct SiS310_CRT1Table[]=
 {
  {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
-  0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
-  0x00}}, /* 0x0 */
+   0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
+   0x00}}, /* 0x0 */
  {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
-  0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
-  0x00}}, /* 0x1 */
+   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
+   0x00}}, /* 0x1 */
  {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0,
-  0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05,
-  0x01}}, /* 0x2 */
+   0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05,
+   0x01}}, /* 0x2 */
  {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-  0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
-  0x01}}, /* 0x3 */
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
+   0x01}}, /* 0x3 */
  {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-  0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05,
-  0x00}}, /* 0x4 */
+   0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05,
+   0x00}}, /* 0x4 */
  {{0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,
-  0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
-  0x00}}, /* 0x5 */
+   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
+   0x00}}, /* 0x5 */
  {{0x63,0x4f,0x50,0x86,0x56,0x9b,0x06,0x3e,
-  0xe8,0x8b,0xdf,0xe7,0xff,0x10,0x00,0x01,
-  0x00}}, /* 0x6 */
+   0xe8,0x8b,0xdf,0xe7,0xff,0x10,0x00,0x01,
+   0x00}}, /* 0x6 */
  {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f,
-  0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01,
-  0x00}}, /* 0x7 */
+   0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01,
+   0x00}}, /* 0x7 */
  {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f,
-  0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
-  0x00}}, /* 0x8 */
+   0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
+   0x00}}, /* 0x8 */
  {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f,
-  0xe0,0x83,0xdf,0xdf,0xfc,0x00,0x00,0x05,
-  0x61}}, /* 0x9 */
+   0xe0,0x83,0xdf,0xdf,0xfc,0x00,0x00,0x05,
+   0x61}}, /* 0x9 */
  {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e,
-  0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05,
-  0x61}}, /* 0xa */
+   0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05,
+   0x61}}, /* 0xa */
  {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e,
-  0xe0,0x83,0xdf,0xdf,0x0e,0x10,0x00,0x05,
-  0x61}}, /* 0xb */
+   0xe0,0x83,0xdf,0xdf,0x0e,0x10,0x00,0x05,
+   0x61}}, /* 0xb */
  {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f,
-  0xe6,0x8a,0xe5,0xe5,0xfc,0x00,0x00,0x01,
-  0x00}}, /* 0xc */
+   0xe6,0x8a,0xe5,0xe5,0xfc,0x00,0x00,0x01,
+   0x00}}, /* 0xc */
  {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
-  0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05,
-  0x01}}, /* 0xd */
+   0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05,
+   0x01}}, /* 0xd */
  {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0,
-  0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06,
-  0x01}}, /* 0xe */
+   0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06,
+   0x01}}, /* 0xe */
  {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0,
-  0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06,
-  0x01}}, /* 0xf */
+   0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06,
+   0x01}}, /* 0xf */
  {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0,
-  0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06,
-  0x01}}, /* 0x10 */
+   0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06,
+   0x01}}, /* 0x10 */
  {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0,
-  0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06,
-  0x01}}, /* 0x11 */
+   0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06,
+   0x01}}, /* 0x11 */
  {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0,
-  0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06,
-  0x61}}, /* 0x12 */
+   0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06,
+   0x61}}, /* 0x12 */
  {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0,
-  0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06,
-  0x61}}, /* 0x13 */
+   0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06,
+   0x61}}, /* 0x13 */
  {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0,
-  0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06,
-  0x61}}, /* 0x14 */
+   0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06,
+   0x61}}, /* 0x14 */
  {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f,
-  0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02,
-  0x00}}, /* 0x15 */
+   0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02,
+   0x00}}, /* 0x15 */
  {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
-  0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-  0x01}}, /* 0x16 */
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
+   0x01}}, /* 0x16 */
  {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5,
-  0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-  0x01}}, /* 0x17 */
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
+   0x01}}, /* 0x17 */
  {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5,
-  0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02,
-  0x01}}, /* 0x18 */
+   0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02,
+   0x01}}, /* 0x18 */
  {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5,
-  0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02,
-  0x01}}, /* 0x19 */
+   0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02,
+   0x01}}, /* 0x19 */
  {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5,
-  0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02,
-  0x62}}, /* 0x1a */
+   0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02,
+   0x62}}, /* 0x1a */
  {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5,
-  0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02,
-  0x62}}, /* 0x1b */
+   0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02,
+   0x62}}, /* 0x1b */
  {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba,
-  0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03,
-  0x00}}, /* 0x1c */
+   0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03,
+   0x00}}, /* 0x1c */
  {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a,
-  0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
-  0x01}}, /* 0x1d */
+   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
+   0x01}}, /* 0x1d */
  {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a,
-  0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
-  0x01}}, /* 0x1e */
+   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
+   0x01}}, /* 0x1e */
  {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a,
-  0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07,
-  0x01}}, /* 0x1f */
+   0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07,
+   0x01}}, /* 0x1f */
  {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}}, /* 0x20 */
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x20 */
  {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}}, /* 0x21 */
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x21 @ 4084 */
  {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}}, /* 0x22 */
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x22 */
  {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}}, /* 0x23 */
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x23 */
  {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}}, /* 0x24 */
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x24 */
  {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}}, /* 0x25 */
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x25 */
  {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}}, /* 0x26 */
+   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
+   0x00}}, /* 0x26 */
  {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-  0x00}}, /* 0x27 */
+   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
+   0x00}}, /* 0x27 */
  {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05,
-  0x63}}, /* 0x28 */
+   0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05,
+   0x63}}, /* 0x28 */
  {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05,
-  0x63}}, /* 0x29 */
+   0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05,
+   0x63}}, /* 0x29 */
  {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-  0x00}}, /* 0x2a */
+   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
+   0x00}}, /* 0x2a */
  {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-  0x00}}, /* 0x2b */
+   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
+   0x00}}, /* 0x2b */
  {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-  0x00}}, /* 0x2c */
+   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
+   0x00}}, /* 0x2c */
  {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba,
-  0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05,
-  0x44}}, /* 0x2d */
+   0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05,
+   0x44}}, /* 0x2d */
  {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba,
-  0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05,
-  0x44}}, /* 0x2e */
+   0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05,
+   0x44}}, /* 0x2e */
  {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba,
-  0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05,
-  0x44}}, /* 0x2f */
+   0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05,
+   0x44}}, /* 0x2f */
  {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba,
-  0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05,
-  0x44}}, /* 0x30 */
+   0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05,
+   0x44}}, /* 0x30 */
  {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba,
-  0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05,
-  0x00}}, /* 0x31 */
+   0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05,
+   0x00}}, /* 0x31 */
  {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,
-  0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
-  0x01}}, /* 0x32 */
+   0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
+   0x01}}, /* 0x32 */
  {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba,
-  0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06,
-  0x01}}, /* 0x33 */
+   0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06,
+   0x01}}, /* 0x33 */
  {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba,
-  0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06,
-  0x01}}, /* 0x34 */
+   0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06,
+   0x01}}, /* 0x34 */
  {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1,
-  0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02,
-  0x01}}, /* 0x35 */
+   0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02,
+   0x01}}, /* 0x35 */
  {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1,
-  0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
-  0x01}}, /* 0x36 */
+   0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
+   0x01}}, /* 0x36 */
  {{0xa7,0x7f,0x7f,0x88,0x89,0x15,0x26,0xf1,
-  0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
-  0x01}}, /* 0x37 */
+   0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
+   0x01}}, /* 0x37 */
  {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4,
-  0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
-  0x01}}, /* 0x38 */
+   0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
+   0x01}}, /* 0x38 */
  {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4,
-  0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
-  0x01}}, /* 0x39 */
+   0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
+   0x01}}, /* 0x39 */
  {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4,
-  0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07,
-  0x01}}, /* 0x3a */
+   0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07,
+   0x01}}, /* 0x3a */
  {{0xdc,0x9f,0x9f,0x00,0xab,0x19,0xe6,0xef,
-  0xc0,0xc3,0xbf,0xbf,0xe7,0x10,0x00,0x07,
-  0x01}}, /* 0x3b */
+   0xc0,0xc3,0xbf,0xbf,0xe7,0x10,0x00,0x07,
+   0x01}}, /* 0x3b */
  {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e,
-  0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
-  0x00}}, /* 0x3c */
+   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
+   0x00}}, /* 0x3c */
  {{0x7b,0x59,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
-  0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05,
-  0x01}}, /* 0x3d */
+   0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05,
+   0x01}}, /* 0x3d */
  {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15,
-  0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02,
-  0x00}},/*3e*/
-  {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e,
-  0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02,
-  0x00}} ,/*3f*/
-  {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
-  0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
-  0x00}}/*40*/ 
+   0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02,
+   0x00}}, /* 0x3e */
+ {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e,
+   0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02,
+   0x00}}, /* 0x3f */
+ /* TW: New from 650/LVDS BIOS */
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1,
+   0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02,
+   0x01}},  /* 0x40 */
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
+   0x01}},  /* 0x41 */
+ {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5,
+   0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07,
+   0x01}},  /* 0x42 */
+ {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10,
+   0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03,
+   0x00}}   /* 0x43 */
 };
 
 typedef struct _SiS310_MCLKDataStruct
@@ -853,20 +896,49 @@
 	USHORT CLOCK;
 } SiS310_MCLKDataStruct;
 
-SiS310_MCLKDataStruct SiS310_MCLKData[]=
+static const SiS310_MCLKDataStruct SiS310_MCLKData_0_315[] =
 {
+	{ 0x3b,0x22,0x01,143},   /* TW: Was { 0x5c,0x23,0x01,166}, */
+	{ 0x5c,0x23,0x01,166},
+	{ 0x5c,0x23,0x01,166},
+	{ 0x5c,0x23,0x01,166},
 	{ 0x5c,0x23,0x01,166},
 	{ 0x5c,0x23,0x01,166},
 	{ 0x5c,0x23,0x01,166},
 	{ 0x5c,0x23,0x01,166}
 };
 
+static const SiS310_MCLKDataStruct SiS310_MCLKData_0_650[] =	/* @ 0x54 */
+{
+	{ 0x5a,0x64,0x82, 66},
+	{ 0xb3,0x45,0x82, 83},
+	{ 0x37,0x61,0x82,100},
+	{ 0x37,0x22,0x82,133},
+	{ 0x37,0x61,0x82,100},
+	{ 0x37,0x22,0x82,133},
+	{ 0x37,0x22,0x82,133},
+	{ 0x37,0x22,0x82,133}
+};
+
+static const SiS310_MCLKDataStruct SiS310_MCLKData_1[] =	/* @ 0x155 */
+{
+        { 0x29,0x21,0x82,150},
+	{ 0x5c,0x23,0x82,166},
+	{ 0x65,0x23,0x82,183},
+	{ 0x37,0x21,0x82,200},
+	{ 0x37,0x22,0x82,133},
+	{ 0x37,0x22,0x82,133},
+	{ 0x37,0x22,0x82,133},
+	{ 0x37,0x22,0x82,133}
+};
+
 typedef struct _SiS310_ECLKDataStruct
 {
  	UCHAR SR2E,SR2F,SR30;
  	USHORT CLOCK;
 } SiS310_ECLKDataStruct;
-SiS310_ECLKDataStruct SiS310_ECLKData[]=
+
+static const SiS310_ECLKDataStruct SiS310_ECLKData[]=
 {
 	{ 0x5c,0x23,0x01,166},
 	{ 0x5c,0x23,0x01,166},
@@ -880,9 +952,9 @@
 	USHORT CLOCK;
 } SiS310_VCLKDataStruct;
 
-SiS310_VCLKDataStruct SiS310_VCLKData[]=
+static const SiS310_VCLKDataStruct SiS310_VCLKData[]=
 {
-	{ 0x1b,0xe1, 25}, /* 0x0 */
+	{ 0x1b,0xe1, 25}, /* 0x0 */   /* 650/LVDS BIOS: @ 0x5647 */
 	{ 0x4e,0xe4, 28}, /* 0x1 */
 	{ 0x57,0xe4, 31}, /* 0x2 */
 	{ 0xc3,0xc8, 36}, /* 0x3 */
@@ -893,7 +965,7 @@
 	{ 0x53,0xe2, 50}, /* 0x8 */
 	{ 0x74,0x67, 52}, /* 0x9 */
 	{ 0x6d,0x66, 56}, /* 0xa */
-	{ 0x6c,0xc3, 65}, /* 0xb */
+	{ 0x5a,0x64, 65}, /* 0xb */   /* TW: was 6c c3 - WRONG */
 	{ 0x46,0x44, 67}, /* 0xc */
 	{ 0xb1,0x46, 68}, /* 0xd */
 	{ 0xd3,0x4a, 72}, /* 0xe */
@@ -946,7 +1018,28 @@
 	{ 0x62,0x64, 70}, /* 0x3d */
 	{ 0xa8,0x4c, 30}, /* 0x3e */
 	{ 0x20,0x26, 33}, /* 0x3f */
-	{ 0x31,0xc2, 39}  /* 0x40 */
+	{ 0x31,0xc2, 39}, /* 0x40 */
+	/* TW: 650/LVDS BIOS @ 0x574b new: */
+	{ 0x60,0x36, 30}, /* 0x41 */  /* Chrontel */
+	{ 0x40,0x4a, 28}, /* 0x42 */  /* Chrontel */
+	{ 0x9f,0x46, 44}, /* 0x43 */  /* Chrontel */
+	{ 0x97,0x2c, 26}, /* 0x44 */
+	{ 0x44,0xe4, 25}, /* 0x45 */  /* Chrontel */
+	{ 0x7e,0x32, 47}, /* 0x46 */  /* Chrontel */
+	{ 0x8a,0x24, 31}, /* 0x47 */  /* Chrontel */
+	{ 0x97,0x2c, 26}, /* 0x48 */  /* Chrontel */
+	{ 0xce,0x3c, 39}, /* 0x49 */
+	{ 0x52,0x4a, 36}, /* 0x4a */  /* Chrontel */
+	{ 0x34,0x61, 95}, /* 0x4b */
+	{ 0x78,0x27,108}, /* 0x4c - was 102 */  /* TW: Last entry in 650/301 BIOS */
+	{ 0x66,0x43,123}, /* 0x4d */  /* Modes 0x26-0x28 (1400x1050) */
+	{ 0x41,0x4e, 21}, /* 0x4e */
+	{ 0xa1,0x4a, 29}, /* 0x4f */  /* Chrontel */
+	{ 0x19,0x42, 42}, /* 0x50 */
+	{ 0x54,0x46, 58}, /* 0x51 */  /* Chrontel */
+	{ 0x25,0x42, 61}, /* 0x52 */
+	{ 0x44,0x44, 66}, /* 0x53 */  /* Chrontel */
+	{ 0x3a,0x62, 70}  /* 0x54 */  /* Chrontel */
 };
 
 typedef struct _SiS310_VBVCLKDataStruct
@@ -955,9 +1048,9 @@
 	USHORT CLOCK;
 } SiS310_VBVCLKDataStruct;
 
-SiS310_VBVCLKDataStruct SiS310_VBVCLKData[]=
+static const SiS310_VBVCLKDataStruct SiS310_VBVCLKData[]=
 {
-	{ 0x1b,0xe1, 25}, /* 0x0 */
+	{ 0x1b,0xe1, 25}, /* 0x0 */   /* 650/LVDS BIOS: @ 0x579c */
 	{ 0x4e,0xe4, 28}, /* 0x1 */
 	{ 0x57,0xe4, 31}, /* 0x2 */
 	{ 0xc3,0xc8, 36}, /* 0x3 */
@@ -968,7 +1061,7 @@
 	{ 0x53,0x47, 50}, /* 0x8 */
 	{ 0x74,0x67, 52}, /* 0x9 */
 	{ 0x6d,0x66, 56}, /* 0xa */
-	{ 0x5a,0x64, 65}, /* 0xb */
+	{ 0x35,0x62, 65}, /* 0xb */  /* Was 0x5a,0x64 - 650/LVDS+301 bios: 35,62  */
 	{ 0x46,0x44, 67}, /* 0xc */
 	{ 0xb1,0x46, 68}, /* 0xd */
 	{ 0xd3,0x4a, 72}, /* 0xe */
@@ -1021,11 +1114,21 @@
 	{ 0x62,0x64, 70}, /* 0x3d */
 	{ 0xa8,0x4c, 30}, /* 0x3e */
 	{ 0x20,0x26, 33}, /* 0x3f */
-	{ 0x31,0xc2, 39}  /* 0x40 */
+	{ 0x31,0xc2, 39}, /* 0x40 */
+	/* TW: 650/LVDS+301 BIOS (@ 0x58a0 in LVDS) new: */
+	{ 0x2e,0x48, 25}, /* 0x41 */
+	{ 0x24,0x46, 25}, /* 0x42 */
+	{ 0x26,0x64, 28}, /* 0x43 */
+	{ 0x37,0x64, 40}, /* 0x44 */
+	{ 0xa1,0x42,108}, /* 0x45 */
+	{ 0x37,0x61,100}, /* 0x46 */
+	{ 0x78,0x27,108}  /* 0x47 */
+	/* --- 0x58bc --- */
 };
 
-UCHAR SiS310_ScreenOffset[]= { 0x14,0x19,0x20,0x28,0x32,0x40,
-                               0x50,0x64,0x78,0x80,0x2d,0x35};
+static const UCHAR SiS310_ScreenOffset[]=
+         { 0x14,0x19,0x20,0x28,0x32,0x40,
+           0x50,0x64,0x78,0x80,0x2d,0x35,0x57};  /* TW: Added 1400x1050 offset */
 
 typedef struct _SiS310_StResInfoStruct
 {
@@ -1033,7 +1136,7 @@
 	USHORT VTotal;
 } SiS310_StResInfoStruct;
 
-SiS310_StResInfoStruct SiS310_StResInfo[]=
+static const SiS310_StResInfoStruct SiS310_StResInfo[]=
 {
 	{ 640,400},
 	{ 640,350},
@@ -1050,47 +1153,52 @@
 	UCHAR  YChar;
 } SiS310_ModeResInfoStruct;
 
-SiS310_ModeResInfoStruct SiS310_ModeResInfo[]=
+static const SiS310_ModeResInfoStruct SiS310_ModeResInfo[]=
 {
-	{  320, 200, 8, 8},
-	{  320, 240, 8, 8},
-	{  320, 400, 8, 8},
-	{  400, 300, 8, 8},
-	{  512, 384, 8, 8},
-	{  640, 400, 8,16},
-	{  640, 480, 8,16},
-	{  800, 600, 8,16},
-	{ 1024, 768, 8,16},
-	{ 1280,1024, 8,16},
-	{ 1600,1200, 8,16},
-	{ 1920,1440, 8,16},
-	{ 2048,1536, 8,16},
-	{  720, 480, 8,16},
-	{  720, 576, 8,16},
-	{ 1280, 960, 8,16},
-	{  800, 480, 8,16},
-	{ 1024, 576, 8,16},
-	{ 1280, 720, 8,16}
+	{  320, 200, 8, 8},   /* 0x00 */
+	{  320, 240, 8, 8},   /* 0x01 */
+	{  320, 400, 8, 8},   /* 0x02 */
+	{  400, 300, 8, 8},   /* 0x03 */
+	{  512, 384, 8, 8},   /* 0x04 */
+	{  640, 400, 8,16},   /* 0x05 */
+	{  640, 480, 8,16},   /* 0x06 */
+	{  800, 600, 8,16},   /* 0x07 */
+	{ 1024, 768, 8,16},   /* 0x08 */
+	{ 1280,1024, 8,16},   /* 0x09 */
+	{ 1600,1200, 8,16},   /* 0x0a */
+	{ 1920,1440, 8,16},   /* 0x0b */
+	{ 2048,1536, 8,16},   /* 0x0c */
+	{  720, 480, 8,16},   /* 0x0d */
+	{  720, 576, 8,16},   /* 0x0e */
+	{ 1280, 960, 8,16},   /* 0x0f */
+	{  800, 480, 8,16},   /* 0x10 */
+	{ 1024, 576, 8,16},   /* 0x11 */
+	{ 1280, 720, 8,16},   /* 0x12 */
+	{  856, 480, 8,16},   /* 0x13 19; TW: New */
+	{ 1280, 768, 8,16},   /* 0x14 20; TW: New */
+	{ 1400,1050, 8,16}    /* 0x15 21; TW: New */
 };
 
-UCHAR SiS310_OutputSelect =0x40;
-
-UCHAR SiS310_SoftSetting = 30;
+static const UCHAR SiS310_OutputSelect = 0x40;
 
-UCHAR SiS310_SR07=0x18;
+static const UCHAR SiS310_SoftSetting  = 0x30;   /* TW: RAM setting */
 
-UCHAR SiS310_SR15[8][4]={
+static const UCHAR SiS310_SR15[8][4]={
 	{0x00,0x04,0x60,0x60},
 	{0x0f,0x0f,0x0f,0x0f},
 	{0xba,0xba,0xba,0xba},
 	{0xa9,0xa9,0xac,0xac},
 	{0xa0,0xa0,0xa0,0xa8},
 	{0x00,0x00,0x02,0x02},
-	{0x30,0x30,0x40,0x40},
+ 	{0x30,0x30,0x40,0x40},
 	{0x00,0xa5,0xfb,0xf6}
 };
 
-UCHAR SiS310_CR40[5][4]={
+#ifndef LINUX_XF86
+
+static UCHAR SiS310_SR07 = 0x18;
+
+static const UCHAR SiS310_CR40[5][4]={
 	{0x77,0x77,0x33,0x33},
 	{0x77,0x77,0x33,0x33},
 	{0x00,0x00,0x00,0x00},
@@ -1098,32 +1206,37 @@
 	{0x00,0x00,0xf0,0xf8}
 };
 
-UCHAR SiS310_CR49[]={0xaa,0x88};
-UCHAR SiS310_SR1F=0x0;
-UCHAR SiS310_SR21=0xa5;
-UCHAR SiS310_SR22=0xfb;
-UCHAR SiS310_SR23=0xf6;
-UCHAR SiS310_SR24=0xd;
-UCHAR SiS310_SR25[]={0x33,0x3};
-UCHAR SiS310_SR31=0x0;
-UCHAR SiS310_SR32=0x11;
-UCHAR SiS310_SR33=0x0;
-UCHAR SiS310_CRT2Data_1_2 = 0x0;
-UCHAR SiS310_CRT2Data_4_D = 0x0;
-UCHAR SiS310_CRT2Data_4_E = 0x0;
-UCHAR SiS310_CRT2Data_4_10 = 0x80;
-USHORT SiS310_RGBSenseData = 0xd1;
-USHORT SiS310_VideoSenseData = 0xb9;
-USHORT SiS310_YCSenseData = 0xb3;
-USHORT SiS310_RGBSenseData2 = 0x0190;     /*301b*/
-USHORT SiS310_VideoSenseData2 = 0x0174;
-USHORT SiS310_YCSenseData2 = 0x016b;
-UCHAR SiS310_NTSCPhase[] = {0x21,0xed,0x8a,0x8};
-UCHAR SiS310_PALPhase[] = {0x2a,0x5,0xd3,0x0};
-UCHAR SiS310_NTSCPhase2[] = {0x21,0xF0,0x7B,0xD6};/*301b*/
-UCHAR SiS310_PALPhase2[] = {0x2a,0x09,0x86,0xe9};
-UCHAR SiS310_PALMPhase[] = {0x21,0xE4,0x2E,0x9B};   /*palmn*/
-UCHAR SiS310_PALNPhase[] = {0x21,0xF4,0x3E,0xBA};
+static UCHAR SiS310_CR49[] = {0xaa,0x88};
+static UCHAR SiS310_SR1F = 0x00;
+static UCHAR SiS310_SR21 = 0xa5;
+static UCHAR SiS310_SR22 = 0xfb;
+static UCHAR SiS310_SR23 = 0xf6;
+static UCHAR SiS310_SR24 = 0x0d;
+static UCHAR SiS310_SR25[] = {0x33,0x3};
+static UCHAR SiS310_SR31 = 0x00;
+static UCHAR SiS310_SR32 = 0x11;
+static UCHAR SiS310_SR33 = 0x00;
+static UCHAR SiS310_CRT2Data_1_2  = 0x00;
+static UCHAR SiS310_CRT2Data_4_D  = 0x00;
+static UCHAR SiS310_CRT2Data_4_E  = 0x00;
+static UCHAR SiS310_CRT2Data_4_10 = 0x80;
+static const USHORT SiS310_RGBSenseData    = 0xd1;
+static const USHORT SiS310_VideoSenseData  = 0xb9;
+static const USHORT SiS310_YCSenseData     = 0xb3;
+static const USHORT SiS310_RGBSenseData2   = 0x0190;     /*301b*/
+static const USHORT SiS310_VideoSenseData2 = 0x0174;
+static const USHORT SiS310_YCSenseData2    = 0x016b;
+#endif
+
+static const UCHAR SiS310_NTSCPhase[]    = {0x21,0xed,0xba,0x08};  /* TW: Was {0x21,0xed,0x8a,0x08}; */
+static const UCHAR SiS310_PALPhase[]     = {0x2a,0x05,0xe3,0x00};  /* TW: Was {0x2a,0x05,0xd3,0x00}; */
+static const UCHAR SiS310_PALMPhase[]    = {0x21,0xE4,0x2E,0x9B};  /* TW: palm*/
+static const UCHAR SiS310_PALNPhase[]    = {0x21,0xF4,0x3E,0xBA};  /* TW: paln*/
+static const UCHAR SiS310_NTSCPhase2[]   = {0x21,0xF0,0x7B,0xD6};
+static const UCHAR SiS310_PALPhase2[]    = {0x2a,0x09,0x86,0xe9};
+static const UCHAR SiS310_PALMPhase2[]   = {0x21,0xE6,0xEF,0xA4};  /* TW: palm 301b*/
+static const UCHAR SiS310_PALNPhase2[]   = {0x21,0xF6,0x94,0x46};  /* TW: paln 301b*/
+static const UCHAR SiS310_SpecialPhase[] = {0x1e,0x8c,0x5c,0x7a};
 
 typedef struct _SiS310_LCDDataStruct
 {
@@ -1135,7 +1248,7 @@
 	USHORT LCDVT;
 } SiS310_LCDDataStruct;
 
-SiS310_LCDDataStruct  SiS310_StLCD1024x768Data[]=
+static const SiS310_LCDDataStruct  SiS310_StLCD1024x768Data[]=
 {
 	{   62,  25, 800, 546,1344, 806},
 	{   32,  15, 930, 546,1344, 806},
@@ -1146,7 +1259,7 @@
 	{    1,   1,1344, 806,1344, 806}
 };
 
-SiS310_LCDDataStruct  SiS310_ExtLCD1024x768Data[]=
+static const SiS310_LCDDataStruct  SiS310_ExtLCD1024x768Data[] =   /* TW: Checked */
 {
 	{   12,   5, 896, 512,1344, 806},
 	{   12,   5, 896, 510,1344, 806},
@@ -1163,18 +1276,19 @@
 	{    1,   1,1344, 806,1344, 806}
 };
 
-SiS310_LCDDataStruct  SiS310_St2LCD1024x768Data[]=
+static const SiS310_LCDDataStruct  SiS310_St2LCD1024x768Data[] =  /* TW: Checked */
 {
 	{   62,  25, 800, 546,1344, 806},
 	{   32,  15, 930, 546,1344, 806},
-	{   32,  15, 930, 546,1344, 806},
+/*	{   32,  15, 930, 546,1344, 806},   */
+        {   62,  25, 800, 546,1344, 806},    /* TW: Different in 650/301LV BIOS */
 	{  104,  45, 945, 496,1344, 806},
 	{   62,  25, 800, 546,1344, 806},
 	{   31,  18,1008, 624,1344, 806},
 	{    1,   1,1344, 806,1344, 806}
 };
 
-SiS310_LCDDataStruct  SiS310_StLCD1280x1024Data[]=
+static const SiS310_LCDDataStruct  SiS310_StLCD1280x1024Data[] =
 {
 	{   22,   5, 800, 510,1650,1088},
 	{   22,   5, 800, 510,1650,1088},
@@ -1186,7 +1300,7 @@
 	{    1,   1,1688,1066,1688,1066}
 };
 
-SiS310_LCDDataStruct  SiS310_ExtLCD1280x1024Data[]=
+static const SiS310_LCDDataStruct  SiS310_ExtLCD1280x1024Data[] =  /* TW: Checked */
 {
 	{  211,  60,1024, 501,1688,1066},
 	{  211,  60,1024, 508,1688,1066},
@@ -1198,7 +1312,7 @@
 	{    1,   1,1688,1066,1688,1066}
 };
 
-SiS310_LCDDataStruct  SiS310_St2LCD1280x1024Data[]=
+static const SiS310_LCDDataStruct  SiS310_St2LCD1280x1024Data[] =
 {
 	{   22,   5, 800, 510,1650,1088},
 	{   22,   5, 800, 510,1650,1088},
@@ -1210,8 +1324,17 @@
 	{    1,   1,1688,1066,1688,1066}
 };
 
-SiS310_LCDDataStruct  SiS310_NoScaleData[]=
+static const SiS310_LCDDataStruct  SiS310_NoScaleData1024x768[] =  /* TW: Checked */
 {
+        {    1,   1,1344, 806,1344, 806},
+	{    1,   1,1344, 806,1344, 806},
+	{    1,   1,1344, 806,1344, 806},
+	{    1,   1,1344, 806,1344, 806},
+	{    1,   1,1344, 806,1344, 806},
+	{    1,   1,1344, 806,1344, 806},
+	{    1,   1,1344, 806,1344, 806},
+	{    1,   1,1344, 806,1344, 806}
+#if 0
 	{    1,   1, 800, 449, 800, 449},
 	{    1,   1, 800, 449, 800, 449},
 	{    1,   1, 900, 449, 900, 449},
@@ -1220,9 +1343,22 @@
 	{    1,   1,1056, 628,1056, 628},
 	{    1,   1,1344, 806,1344, 806},
 	{    1,   1,1688,1066,1688,1066}
+#endif
 };
 
-SiS310_LCDDataStruct  SiS310_LCD1280x960Data[]=
+static const SiS310_LCDDataStruct  SiS310_NoScaleData1280x1024[] =  /* TW: New; Checked */
+{
+        {    1,   1,1688,1066,1688,1066},
+	{    1,   1,1688,1066,1688,1066},
+	{    1,   1,1688,1066,1688,1066},
+	{    1,   1,1688,1066,1688,1066},
+	{    1,   1,1688,1066,1688,1066},
+	{    1,   1,1688,1066,1688,1066},
+	{    1,   1,1688,1066,1688,1066},
+	{    1,   1,1688,1066,1688,1066}
+};
+
+static const SiS310_LCDDataStruct  SiS310_LCD1280x960Data[] =
 {
 	{    9,   2, 800, 500,1800,1000},
 	{    9,   2, 800, 500,1800,1000},
@@ -1235,6 +1371,90 @@
 	{    1,   1,1800,1000,1800,1000}
 };
 
+static const SiS310_LCDDataStruct  SiS310_ExtLCD1400x1050Data[] =  /* TW: New */
+{  /* TODO */
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS310_LCDDataStruct  SiS310_ExtLCD1600x1200Data[] =  /* TW: New */
+{  /* TODO */
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS310_LCDDataStruct  SiS310_StLCD1400x1050Data[] =  /* TW: New */
+{  /* TODO */
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS310_LCDDataStruct  SiS310_StLCD1600x1200Data[] =  /* TW: New */
+{  /* TODO */
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS310_LCDDataStruct  SiS310_NoScaleData1400x1050[] =  /* TW: New */
+{  /* TODO */
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
+static const SiS310_LCDDataStruct  SiS310_NoScaleData1600x1200[] =  /* TW: New */
+{  /* TODO */
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0},
+	{    0,   0,   0,   0,   0,   0}
+};
+
 typedef struct _SiS310_TVDataStruct
 {
 	USHORT RVBHCMAX;
@@ -1252,7 +1472,7 @@
 	UCHAR RY4COE;
 } SiS310_TVDataStruct;
 
-SiS310_TVDataStruct  SiS310_StPALData[]=
+static const SiS310_TVDataStruct  SiS310_StPALData[]=
 {
  {    1,   1, 864, 525,1270, 400, 100,   0, 760,0xf4,0xff,0x1c,0x22},
  {    1,   1, 864, 525,1270, 350, 100,   0, 760,0xf4,0xff,0x1c,0x22},
@@ -1262,19 +1482,19 @@
  {    1,   1, 864, 525,1270, 600,  50,   0,   0,0xf4,0xff,0x1c,0x22}
 };
 
-SiS310_TVDataStruct  SiS310_ExtPALData[]=
+static const SiS310_TVDataStruct  SiS310_ExtPALData[]=
 {
  {   27,  10, 848, 448,1270, 530,  50,   0,  50,0xf4,0xff,0x1c,0x22},
  {  108,  35, 848, 398,1270, 530,  50,   0,  50,0xf4,0xff,0x1c,0x22},
  {   12,   5, 954, 448,1270, 530,  50,   0,  50,0xf1,0x04,0x1f,0x18},
  {    9,   4, 960, 463,1644, 438,  50,   0,  50,0xf4,0x0b,0x1c,0x0a},
  {    9,   4, 848, 528,1270, 530,   0,   0,  50,0xf5,0xfb,0x1b,0x2a},
- {   36,  25,1060, 648,1316, 530, 438,   0, 438,0xeb,0x05,0x25,0x16},
+ {   36,  25,1060, 648,1316, 530, 438,   0, 438,0xeb,0x05,0x25,0x16},  /* 800x600 */
  {    3,   2,1080, 619,1270, 540, 438,   0, 438,0xf3,0x00,0x1d,0x20},
  {    1,   1,1170, 821,1270, 520, 686,   0, 686,0xF3,0x00,0x1D,0x20}     /*301b*/
 };
 
-SiS310_TVDataStruct  SiS310_StNTSCData[]=
+static const SiS310_TVDataStruct  SiS310_StNTSCData[]=
 {
  {    1,   1, 858, 525,1270, 400,  50,   0, 760,0xf1,0x04,0x1f,0x18},
  {    1,   1, 858, 525,1270, 350,  50,   0, 640,0xf1,0x04,0x1f,0x18},
@@ -1283,34 +1503,35 @@
  {    1,   1, 858, 525,1270, 480,   0,   0, 760,0xf1,0x04,0x1f,0x18}
 };
 
-SiS310_TVDataStruct  SiS310_ExtNTSCData[]=
+static const SiS310_TVDataStruct  SiS310_ExtNTSCData[]=
 {
  {  143,  65, 858, 443,1270, 440, 171,   0, 171,0xf1,0x04,0x1f,0x18},
  {   88,  35, 858, 393,1270, 440, 171,   0, 171,0xf1,0x04,0x1f,0x18},
  {  143,  70, 924, 443,1270, 440,  92,   0,  92,0xf1,0x04,0x1f,0x18},
  {  143,  70, 924, 393,1270, 440,  92,   0,  92,0xf4,0x0b,0x1c,0x0a},
  {  143,  76, 836, 523,1270, 440, 224,   0,   0,0xf1,0x05,0x1f,0x16},
- {  143, 120,1056, 643,1270, 440,   0, 128,   0,0xf4,0x10,0x1c,0x00},
+ {  143, 120,1056, 643,1270, 440,   0, 128,   0,0xf4,0x10,0x1c,0x00},  /* 800x600 */
  {    2,   1, 858, 503,1270, 480,   0, 128,   0,0xee,0x0c,0x22,0x08},
  {   65,  64,1056, 791,1270, 480, 638,   0,   0,0xEE,0x0C,0x22,0x08} /*301b*/     
 };
 
-SiS310_TVDataStruct  SiS310_St1HiTVData[]=
+/* TW: These tables will need data ! */
+static const SiS310_TVDataStruct  SiS310_St1HiTVData[]=
 {
-	{0x00}
+   	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
 };
 
-SiS310_TVDataStruct  SiS310_St2HiTVData[]=
+static const SiS310_TVDataStruct  SiS310_St2HiTVData[]=
 {
-	{0x00}
+	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
 };
 
-SiS310_TVDataStruct  SiS310_ExtHiTVData[]=
+static const SiS310_TVDataStruct  SiS310_ExtHiTVData[]=
 {
-	{0x00}
+	{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
 };
 
-UCHAR SiS310_NTSCTiming[] = {
+static const UCHAR SiS310_NTSCTiming[] = {   /* TW: New (checked 1.09, 1.10.6s) */
 	0x17,0x1d,0x03,0x09,0x05,0x06,0x0c,0x0c,
 	0x94,0x49,0x01,0x0a,0x06,0x0d,0x04,0x0a,
 	0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x1b,
@@ -1321,7 +1542,7 @@
 	0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00
 };
 
-UCHAR SiS310_PALTiming[] = {
+static const UCHAR SiS310_PALTiming[] = {   /* TW: New (checked 1.09, 1.10.6s) */
 	0x19,0x52,0x35,0x6e,0x04,0x38,0x3d,0x70,
 	0x94,0x49,0x01,0x12,0x06,0x3e,0x35,0x6d,
 	0x06,0x14,0x3e,0x35,0x6d,0x00,0x45,0x2b,
@@ -1332,43 +1553,146 @@
 	0x00,0x40,0x3e,0x00,0xe1,0x02,0x28,0x00
 };
 
-UCHAR SiS310_HiTVExtTiming[] = {0x00};
-
-UCHAR SiS310_HiTVSt1Timing[] = {0x00};
-
-UCHAR SiS310_HiTVSt2Timing[] = {0x00};
-
-UCHAR SiS310_HiTVTextTiming[] = {0x00};
-
-UCHAR SiS310_HiTVGroup3Data[] = {0x00};
-
-UCHAR SiS310_HiTVGroup3Simu[] = {0x00};
-
-UCHAR SiS310_HiTVGroup3Text[] = {0x00};
+#ifdef oldHV
+static const UCHAR SiS310_HiTVExtTiming[] = {   /* TW: New */
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x64,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x64,0x90,0x33,0x8c,0x18,0x36,0x3e,0x13,
+	0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40,
+	0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40,
+	0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d,
+	0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00
+};
+
+static const UCHAR SiS310_HiTVSt1Timing[] = {   /* TW: New */
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x65,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x65,0x90,0x7b,0xa8,0x03,0xf0,0x87,0x03,
+	0x11,0x15,0x11,0xcf,0x10,0x11,0xcf,0x10,
+	0x35,0x35,0x3b,0x69,0x1d,0x92,0x0f,0x40,
+	0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x86,
+	0xaf,0x5d,0x0e,0x00,0xfc,0xff,0x2d,0x00
+};
+
+static const UCHAR SiS310_HiTVSt2Timing[] = {   /* TW: New */
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x64,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x64,0x90,0x33,0x8c,0x18,0x36,0x3e,0x13,
+	0x2a,0xde,0x2a,0x44,0x40,0x2a,0x44,0x40,
+	0x8e,0x8e,0x82,0x07,0x0b,0x92,0x0f,0x40,
+	0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x3d,
+	0x63,0x4f,0x27,0x00,0xfc,0xff,0x6a,0x00
+};
+
+static const UCHAR SiS310_HiTVTextTiming[] = {   /* TW: New */
+        0x32,0x65,0x2c,0x5f,0x08,0x31,0x3a,0x65,
+	0x28,0x02,0x01,0x3d,0x06,0x3e,0x35,0x6d,
+	0x06,0x14,0x3e,0x35,0x6d,0x00,0xc5,0x3f,
+	0x65,0x90,0xe7,0xbc,0x03,0x0c,0x97,0x03,
+	0x14,0x78,0x14,0x08,0x20,0x14,0x08,0x20,
+	0xc8,0xc8,0x3b,0xd2,0x26,0x92,0x0f,0x40,
+        0x60,0x80,0x14,0x90,0x8c,0x60,0x04,0x96,
+	0x72,0x5c,0x11,0x00,0xfc,0xff,0x32,0x00
+};
+
+static const UCHAR SiS310_HiTVGroup3Data[] = {   /* TW: New */
+        0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0x5f,
+	0x05,0x21,0xb2,0xb2,0x55,0x77,0x2a,0xa6,
+	0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20,
+	0x8c,0x6e,0x60,0x2e,0x58,0x48,0x72,0x44,
+	0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+	0x4f,0x7f,0x03,0xa8,0x7d,0x20,0x1a,0xa9,
+	0x14,0x05,0x03,0x7e,0x64,0x31,0x14,0x75,
+	0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+};
+
+static const UCHAR SiS310_HiTVGroup3Simu[] = {   /* TW: New */
+        0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0x95,
+	0xdb,0x20,0xb8,0xb8,0x55,0x47,0x2a,0xa6,
+	0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20,
+	0x8c,0x6e,0x60,0x15,0x26,0xd3,0xe4,0x11,
+	0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+	0x67,0x36,0x01,0x47,0x0e,0x10,0xbe,0xb4,
+	0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75,
+	0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+};
+
+static const UCHAR SiS310_HiTVGroup3Text[] = {   /* TW: New */
+        0x00,0x1a,0x22,0x63,0x62,0x22,0x08,0xa7,
+	0xf5,0x20,0xce,0xce,0x55,0x47,0x2a,0xa6,
+	0x25,0x2f,0x47,0xfa,0xc8,0xff,0x8e,0x20,
+	0x8c,0x6e,0x60,0x18,0x2c,0x0c,0x20,0x22,
+	0x56,0x36,0x4f,0x6e,0x3f,0x80,0x00,0x80,
+	0x93,0x3c,0x01,0x50,0x2f,0x10,0xf4,0xca,
+	0x01,0x05,0x03,0x7e,0x65,0x31,0x14,0x75,
+	0x18,0x05,0x18,0x05,0x4c,0xa8,0x01
+};
+#endif
 
 typedef struct _SiS310_PanelDelayTblStruct
 {
  	UCHAR timer[2];
 } SiS310_PanelDelayTblStruct;
 
-SiS310_PanelDelayTblStruct SiS310_PanelDelayTbl[]=
+static const SiS310_PanelDelayTblStruct SiS310_PanelDelayTbl[]=  /* TW: New */
 {
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}},
-	{{0x00,0x00}}
+        {{0x10,0x40}},		/* TW: from 650/301LVx 1.10.6s BIOS */
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}},
+	{{0x10,0x40}}
+#if 0
+	{{0x28,0xc8}},		/* TW: from 650/301LV BIOS */
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}}
+#endif
+};
+
+static const SiS310_PanelDelayTblStruct SiS310_PanelDelayTblLVDS[]=
+{
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}},
+	{{0x28,0xc8}}
 };
 
 typedef struct _SiS310_LVDSDataStruct
@@ -1379,19 +1703,20 @@
 	USHORT LCDVT;
 } SiS310_LVDSDataStruct;
 
-SiS310_LVDSDataStruct  SiS310_LVDS320x480Data_1[]=
+static const SiS310_LVDSDataStruct  SiS310_LVDS320x480Data_1[]=
 {
-	{848, 433,400,525},
-	{848, 389,400,525},
-	{848, 433,400,525},
-	{848, 389,400,525},
+	{848, 433,400, 525},
+	{848, 389,400, 525},
+	{848, 433,400, 525},
+	{848, 389,400, 525},
 	{848, 518,400, 525},
-	{1056, 628,400,525},
-	{400, 525,400,525},
+	{1056,628,400, 525},
+	{400, 525,400, 525},
 	{800, 449,1000, 644},
 	{800, 525,1000, 635}
 };
-SiS310_LVDSDataStruct  SiS310_LVDS800x600Data_1[]=
+
+static const SiS310_LVDSDataStruct  SiS310_LVDS800x600Data_1[]=   /* TW: New */
 {
 	{848, 433,1060, 629},
 	{848, 389,1060, 629},
@@ -1404,7 +1729,7 @@
 	{800, 525,1000, 635}
 };
 
-SiS310_LVDSDataStruct  SiS310_LVDS800x600Data_2[]=
+static const SiS310_LVDSDataStruct  SiS310_LVDS800x600Data_2[]=   /* TW: New */
 {
 	{1056, 628,1056, 628},
 	{1056, 628,1056, 628},
@@ -1417,7 +1742,33 @@
 	{800, 525,1000, 635}
 };
 
-SiS310_LVDSDataStruct  SiS310_LVDS1024x768Data_1[]=
+static const SiS310_LVDSDataStruct  SiS310_LVDS1024x768Data_1[]=   /* TW: New */
+{
+	{840, 438,1344, 806},
+	{840, 409,1344, 806},
+	{840, 438,1344, 806},
+	{840, 409,1344, 806},
+	{840, 518,1344, 806},    /* 640x480 */
+	{1050, 638,1344, 806},   /* 800x600 */
+	{1344, 806,1344, 806},   /* 1024x768 */
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS310_LVDSDataStruct  SiS310_LVDS1024x768Data_2[]=   /* TW: New */
+{
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS310_LVDSDataStruct  SiS310_LVDS1280x1024Data_1[]=   /* TW: New */
 {
 	{840, 438,1344, 806},
 	{840, 409,1344, 806},
@@ -1430,7 +1781,7 @@
 	{800, 525,1280, 813}
 };
 
-SiS310_LVDSDataStruct  SiS310_LVDS1024x768Data_2[]=
+static const SiS310_LVDSDataStruct  SiS310_LVDS1280x1024Data_2[]=   /* TW: New */
 {
 	{1344, 806,1344, 806},
 	{1344, 806,1344, 806},
@@ -1443,7 +1794,62 @@
 	{800, 525,1280, 813}
 };
 
-SiS310_LVDSDataStruct  SiS310_LVDS1280x1024Data_1[]=
+static const SiS310_LVDSDataStruct  SiS310_LVDS1400x1050Data_1[]=   /* TW: New */
+{
+        {928, 416, 1688, 1066},
+	{928, 366, 1688, 1066},
+	{928, 416, 1688, 1066},
+	{928, 366, 1688, 1066},
+	{928, 496, 1688, 1066},
+	{1088, 616, 1688, 1066},
+	{1312, 784, 1688, 1066},
+	{1568, 1040, 1688, 1066},
+	{1688, 1066, 1688, 1066}
+};
+
+static const SiS310_LVDSDataStruct  SiS310_LVDS1400x1050Data_2[]=   /* TW: New */
+{
+        {1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+	{1688,1066, 1688,1066},
+};
+
+/* TW: New: - from 300 series */
+static const SiS310_LVDSDataStruct  SiS310_LVDS1024x600Data_1[]=
+{
+	{840, 604,1344, 800},
+	{840, 560,1344, 800},
+	{840, 604,1344, 800},
+	{840, 560,1344, 800},
+	{840, 689,1344, 800},
+	{1050, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+/* TW: New: - from 300 series */
+static const SiS310_LVDSDataStruct  SiS310_LVDS1024x600Data_2[]=
+{
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{1344, 800,1344, 800},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+/* TW: New: - from 300 series */
+static const SiS310_LVDSDataStruct  SiS310_LVDS1152x768Data_1[]=
 {
 	{840, 438,1344, 806},
 	{840, 409,1344, 806},
@@ -1456,7 +1862,8 @@
 	{800, 525,1280, 813}
 };
 
-SiS310_LVDSDataStruct  SiS310_LVDS1280x1024Data_2[]=
+/* TW: New: - from 300 series */
+static const SiS310_LVDSDataStruct  SiS310_LVDS1152x768Data_2[]=
 {
 	{1344, 806,1344, 806},
 	{1344, 806,1344, 806},
@@ -1469,7 +1876,20 @@
 	{800, 525,1280, 813}
 };
 
-SiS310_LVDSDataStruct  SiS310_LVDS640x480Data_1[]=
+/* TW: New in 650/LVDS BIOS - pass 1:1 data */
+static const SiS310_LVDSDataStruct  SiS310_LVDSXXXxXXXData_1[]=   /* TW: New */
+{
+        { 800, 449, 800, 449},
+	{ 800, 449, 800, 449},
+	{ 900, 449, 900, 449},
+	{ 900, 449, 900, 449},
+	{ 800, 525, 800, 525},
+	{1056, 628,1056, 628},
+	{1344, 806,1344, 806},
+	{1688, 806,1688, 806}
+};
+
+static const SiS310_LVDSDataStruct  SiS310_LVDS640x480Data_1[]=   /* TW: New */
 {
 	{800, 449, 800, 449},
 	{800, 449, 800, 449},
@@ -1482,44 +1902,129 @@
 	{1056, 628,1056, 628}
 };
 
-SiS310_LVDSDataStruct  SiS310_CHTVUNTSCData[]=
+static const SiS310_LVDSDataStruct  SiS310_LVDS1280x960Data_1[]=   /* TW: New */
 {
-	{840, 600, 840, 600},
-	{840, 600, 840, 600},
-	{840, 600, 840, 600},
-	{840, 600, 840, 600},
-	{784, 600, 784, 600},
-	{1064, 750,1064, 750}
+	{840, 438,1344, 806},
+	{840, 409,1344, 806},
+	{840, 438,1344, 806},
+	{840, 409,1344, 806},
+	{840, 518,1344, 806},
+	{1050, 638,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
 };
 
-SiS310_LVDSDataStruct  SiS310_CHTVONTSCData[]=
+static const SiS310_LVDSDataStruct  SiS310_LVDS1280x960Data_2[]=   /* TW: New */
 {
-	{840, 525, 840, 525},
-	{840, 525, 840, 525},
-	{840, 525, 840, 525},
-	{840, 525, 840, 525},
-	{784, 525, 784, 525},
-	{1040, 700,1040, 700}
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS310_LVDSDataStruct  SiS310_LCDA1400x1050Data_1[]=   /* TW: New */
+{	/* TW: Might be temporary (invalid) data */
+        {928, 416, 1688, 1066},
+	{928, 366, 1688, 1066},
+	{1008, 416, 1688, 1066},
+	{1008, 366, 1688, 1066},
+	{1200, 530, 1688, 1066},
+	{1088, 616, 1688, 1066},
+	{1312, 784, 1688, 1066},
+	{1568, 1040, 1688, 1066},
+	{1688, 1066, 1688, 1066}
+};
+
+static const SiS310_LVDSDataStruct  SiS310_LCDA1400x1050Data_2[]=   /* TW: New */
+{	/* TW: Temporary data. Not valid */
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
+};
+
+static const SiS310_LVDSDataStruct  SiS310_LCDA1600x1200Data_1[]=   /* TW: New */
+{	/* TW: Temporary data. Not valid */
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{1344, 806,1344, 806},
+	{800, 449,1280, 801},
+	{800, 525,1280, 813}
 };
 
-SiS310_LVDSDataStruct  SiS310_CHTVUPALData[]=
+static const SiS310_LVDSDataStruct  SiS310_LCDA1600x1200Data_2[]=   /* TW: New */
+{	/* TW: Temporary data. Not valid */
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0},
+	{0, 0, 0, 0}
+};
+
+static const SiS310_LVDSDataStruct  SiS310_CHTVUNTSCData[]=   /* TW: New */
+{
+	{ 840, 600, 840, 600},
+	{ 840, 600, 840, 600},
+	{ 840, 600, 840, 600},
+	{ 840, 600, 840, 600},
+	{ 784, 600, 784, 600},
+	{1064, 750,1064, 750},
+        {1160, 945,1160, 945}           /* TW: For Ch7019 1024 */
+};
+
+static const SiS310_LVDSDataStruct  SiS310_CHTVONTSCData[]=   /* TW: New */
+{
+	{ 840, 525, 840, 525},
+	{ 840, 525, 840, 525},
+	{ 840, 525, 840, 525},
+	{ 840, 525, 840, 525},
+	{ 784, 525, 784, 525},
+	{1040, 700,1040, 700},
+        {1160, 840,1160, 840}          	/* TW: For Ch7019 1024 */
+};
+
+static const SiS310_LVDSDataStruct  SiS310_CHTVUPALData[]=   /* TW: New */
 {
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
-	{840, 750, 840, 750},
-	{936, 836, 936, 836}
+	{ 840, 625, 840, 625},
+	{ 960, 750, 960, 750},
+	{1400,1000,1400,1000}   	/*  TW: For Ch7019 1024 */
 };
 
-SiS310_LVDSDataStruct  SiS310_CHTVOPALData[]=
+static const SiS310_LVDSDataStruct  SiS310_CHTVOPALData[]=   /* TW: New */
 {
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
 	{1008, 625,1008, 625},
-	{840, 625, 840, 625},
-	{960, 750, 960, 750}
+	{ 840, 625, 840, 625},
+	{ 944, 625, 944, 625},
+        {1400, 875,1400, 875}       	/*  TW: For Ch7019 1024 */
 };
 
 typedef struct _SiS310_LVDSDesStruct
@@ -1528,60 +2033,63 @@
 	USHORT LCDVDES;
 } SiS310_LVDSDesStruct;
 
-SiS310_LVDSDesStruct  SiS310_PanelType00_1[]=
-{
-	{0, 626},
-	{0, 624},
-	{0, 626},
-	{0, 624},
-	{0, 624},
-	{ 0, 627},
-	{ 0, 627},
-	{ 0,   0},
-	{ 0,   0}
-};
+/* TW: PanelType arrays taken from 650/LVDS BIOS 1.10.0 */
 
-SiS310_LVDSDesStruct  SiS310_PanelType01_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType00_1[]=   /* TW: New */
 {
-	{1343, 798},
-	{1343, 794},
-	{1343, 798},
-	{1343, 794},
-	{1343,   0},
-	{1343,   0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0}
+};
+
+static const SiS310_LVDSDesStruct  SiS310_PanelType01_1[]=   /* TW: New */
+{
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
 	{ 0, 805},
-	{ 0, 794},
-	{ 0,   0}
+	{ 0, 0},
+	{ 0, 0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType02_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType02_1[]=   /* TW: New */
 {
-	{0, 626},
-	{0, 624},
-	{0, 626},
-	{0, 624},
-	{0, 624},
-	{ 0, 627},
-	{ 8, 523},
-	{ 0,   0},
-	{ 0,   0}
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 1065},
+	{ 0, 0},
+	{ 0, 0}
 };
 
 
-SiS310_LVDSDesStruct  SiS310_PanelType03_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType03_1[]=   /* TW: New */
 {
-	{ 8, 436},
-	{ 8, 440},
-	{ 8, 436},
-	{ 8, 440},
-	{ 8, 512},
-	{1343, 798},
-	{1343, 794},
-	{1343, 798},
-	{1343, 794}
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType04_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType04_1[]=   /* TW: New */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1594,7 +2102,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType05_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType05_1[]=   /* TW: New */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1607,7 +2115,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType06_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType06_1[]=   /* TW: New */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1620,7 +2128,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType07_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType07_1[]=   /* TW: New */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1633,33 +2141,34 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType08_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType08_1[]=   /* TW: New */
 {
-	{1059, 626},
-	{1059, 624},
-	{1059, 626},
-	{1059, 624},
-	{1059, 624},
-	{ 0, 627},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0}
+};
+
+static const SiS310_LVDSDesStruct  SiS310_PanelType09_1[]=   /* TW: New */
+{
+	{ 0, 448},
+	{ 0, 448},
+	{ 0, 448},
+	{ 0, 448},
+	{ 0, 524},
 	{ 0, 627},
-	{ 0,   0},
-	{ 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType09_1[]=
-{
-	{1343, 798},
-	{1343, 794},
-	{1343, 798},
-	{1343, 794},
-	{1343,   0},
-	{1343,   0},
 	{ 0, 805},
-	{ 0, 794},
-	{ 0,   0}
+	{ 0, 805},
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0a_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0a_1[]=   /* TW: New */
 {
 	{1059, 626},
 	{1059, 624},
@@ -1672,7 +2181,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0b_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0b_1[]=   /* TW: New */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1685,7 +2194,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0c_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0c_1[]=   /* TW: New */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1698,7 +2207,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0d_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0d_1[]=   /* TW: New */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1711,7 +2220,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0e_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0e_1[]=   /* TW: New */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1724,7 +2233,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0f_1[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0f_1[]=   /* TW: New */
 {
 	{1343, 798},
 	{1343, 794},
@@ -1737,20 +2246,20 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType00_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType00_2[]=   /* TW: New */
 {
-	{976, 527},
-	{976, 502},
-	{976, 527},
-	{976, 502},
-	{976, 567},
-	{ 0, 627},
-	{ 0, 627},
+	{980, 528},
+	{980, 503},
+	{980, 528},
+	{980, 503},
+	{980, 568},
+	{ 0, 628},
+	{ 0,   0},
 	{ 0,   0},
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType01_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType01_2[]=   /* TW: New */
 {
 	{1152, 622},
 	{1152, 597},
@@ -1758,51 +2267,51 @@
 	{1152, 597},
 	{1152, 662},
 	{1232, 722},
-	{ 0, 805},
-	{ 0, 794},
+	{ 0, 806},
+	{ 0,   0},
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType02_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType02_2[]=   /* TW: New */
 {
-	{976, 527},
-	{976, 502},
-	{976, 527},
-	{976, 502},
-	{976, 567},
-	{ 0, 627},
-	{ 0, 627},
+	{1368, 754},
+	{1368, 729},
+	{1368, 754},
+	{1368, 729},
+	{1368, 794},
+	{1448, 854},
+	{1560, 938},
+	{   0,1066},
+	{ 0,   0},
 	{ 0,   0},
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType03_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType03_2[]=   /* TW: New */
 {
-	{1152, 622},
-	{1152, 597},
-	{1152, 622},
-	{1152, 597},
-	{1152, 662},
-	{1232, 722},
-	{ 0, 805},
-	{1152, 622},
-	{1152, 597}
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType04_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType04_2[]=   /* TW: New */
 {
-	{1152, 622},
-	{1152, 597},
-	{1152, 622},
-	{1152, 597},
-	{1152, 662},
-	{1232, 722},
-	{ 0, 805},
-	{ 0, 794},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType05_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType05_2[]=   /* TW: New */
 {
 	{1152, 622},
 	{1152, 597},
@@ -1815,7 +2324,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType06_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType06_2[]=   /* TW: New */
 {
 	{1152, 622},
 	{1152, 597},
@@ -1828,7 +2337,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType07_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType07_2[]=   /* TW: New */
 {
 	{1152, 622},
 	{1152, 597},
@@ -1841,7 +2350,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType08_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType08_2[]=   /* TW: New */
 {
 	{976, 527},
 	{976, 502},
@@ -1854,20 +2363,19 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType09_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType09_2[]=   /* TW: New */
 {
-	{1152, 622},
-	{1152, 597},
-	{1152, 622},
-	{1152, 597},
-	{1152, 662},
-	{1232, 722},
-	{ 0, 805},
-	{ 0, 794},
- 	{ 0,   0}
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0},
+	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0a_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0a_2[]=   /* TW: New */
 {
 	{976, 527},
 	{976, 502},
@@ -1880,7 +2388,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0b_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0b_2[]=   /* TW: New */
 {
 	{1152, 622},
 	{1152, 597},
@@ -1893,7 +2401,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0c_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0c_2[]=   /* TW: New */
 {
 	{1152, 622},
 	{1152, 597},
@@ -1906,7 +2414,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0d_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0d_2[]=   /* TW: New */
 {
 	{1152, 622},
 	{1152, 597},
@@ -1919,7 +2427,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0e_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0e_2[]=   /* TW: New */
 {
 	{1152, 622},
 	{1152, 597},
@@ -1932,7 +2440,7 @@
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_PanelType0f_2[]=
+static const SiS310_LVDSDesStruct  SiS310_PanelType0f_2[] =   /* TW: New */
 {
 	{1152, 622},
 	{1152, 597},
@@ -1944,104 +2452,365 @@
 	{ 0, 794},
 	{ 0,   0}
 };
-/*301b*/
-SiS310_LVDSDesStruct SiS310_PanelType1076_1[]=
-{
-	{0x00,0x00}
-};
-SiS310_LVDSDesStruct SiS310_PanelType1210_1[]=
-{
-	{0x00,0x00}
-};
-SiS310_LVDSDesStruct SiS310_PanelType1296_1[]=
-{
-	{0x00,0x00}
-};
-SiS310_LVDSDesStruct SiS310_PanelType1076_2[]=
-{
-	{0x00,0x00}
-};
-SiS310_LVDSDesStruct SiS310_PanelType1210_2[]=
-{
-	{0x00,0x00}
-};
-SiS310_LVDSDesStruct SiS310_PanelType1296_2[]=
-{
-	{0x00,0x00}
+
+static const SiS310_LVDSDesStruct SiS310_PanelType1076_1[]=   /* TW: New */
+{  /* 1024x768 - Checked (1.10.6s) */
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+static const SiS310_LVDSDesStruct SiS310_PanelType1076_2[]=   /* TW: New */
+{  /* 1024x768 - Checked (1.10.6s) */
+	{ 1184, 622 },
+	{ 1184, 597 },
+	{ 1184, 622 },
+	{ 1184, 597 },
+	{ 1152, 622 },
+	{ 1232, 722 },
+	{    0, 0   },
+	{    0, 794 },
+	{    0, 0   }
+};
+
+static const SiS310_LVDSDesStruct SiS310_PanelType1210_1[]=   /* TW: New */
+{  /* 1280x1024 - Checked (1.10.6s) */
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+static const SiS310_LVDSDesStruct SiS310_PanelType1210_2[]=   /* TW: New */
+{  /* 1280x1024 - Checked (1.10.6s) */
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+static const SiS310_LVDSDesStruct SiS310_PanelType1296_1[]=   /* TW: New */
+{  /* 1400x1050 - Checked (1.10.6s) */
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+static const SiS310_LVDSDesStruct SiS310_PanelType1296_2[]=   /* TW: New */
+{  /* 1400x1050 - Checked (1.10.6s) - looks heavily invalid */
+	{ 808 , 740},
+	{ 0   , 715},
+	{ 632 , 740},
+	{ 632 , 715},
+	{ 1307, 780},
+	{ 1387,1157},
+	{ 1499, 924},
+	{ 1627,1052},
+	{ 0 , 0}
+};
+
+static const SiS310_LVDSDesStruct SiS310_PanelType1600_1[]=   /* TW: New */
+{  /* 1600x1200 - Checked (1.10.6s) */
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
+};
+
+static const SiS310_LVDSDesStruct SiS310_PanelType1600_2[]=   /* TW: New */
+{  /* 1600x1200 - Checked (1.10.6s) - looks heavily invalid */
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0},
+	{ 0 , 0}
 };
-/*end 301b*/
 
-SiS310_LVDSDesStruct  SiS310_CHTVUNTSCDesData[]=
+static const SiS310_LVDSDesStruct  SiS310_CHTVUNTSCDesData[]=
 {
 	{ 0,   0},
 	{ 0,   0},
 	{ 0,   0},
 	{ 0,   0},
 	{ 0,   0},
+	{ 0,   0},
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_CHTVONTSCDesData[]=
+static const SiS310_LVDSDesStruct  SiS310_CHTVONTSCDesData[]=
 {
 	{ 0,   0},
 	{ 0,   0},
 	{ 0,   0},
 	{ 0,   0},
 	{ 0,   0},
+	{ 0,   0},
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_CHTVUPALDesData[]=
+static const SiS310_LVDSDesStruct  SiS310_CHTVUPALDesData[]=
 {
 	{256,   0},
 	{256,   0},
 	{256,   0},
 	{256,   0},
 	{ 0,   0},
+	{ 0,   0},
 	{ 0,   0}
 };
 
-SiS310_LVDSDesStruct  SiS310_CHTVOPALDesData[]=
+static const SiS310_LVDSDesStruct  SiS310_CHTVOPALDesData[]=
 {
 	{256,   0},
 	{256,   0},
 	{256,   0},
 	{256,   0},
 	{ 0,   0},
+	{ 0,   0},
 	{ 0,   0}
 };
 
-/*add for LCDA*/
+typedef struct _SiS310_Part2PortTblStruct
+{
+ 	UCHAR CR[12];
+} SiS310_Part2PortTblStruct;
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1024x768_1[] =
+{
+ {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x2c,0x12,0x9a,0xae,0x88,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x38,0x13,0x16,0x0c,0xe6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x38,0x18,0x16,0x00,0x00,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}}
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1280x1024_1[] =
+{	/* TW: Temporary data, invalid */
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1400x1050_1[] =
+{	/* TW: Temporary data, invalid */
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1600x1200_1[] =
+{	/* TW: Temporary data, invalid */
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1024x768_2[] =
+{
+ {{0x25,0x12,0x51,0x6e,0x48,0x99,0x35,0x89,0x47,0xc1,0x49,0x33}},
+ {{0x2c,0x12,0x38,0x55,0x2f,0x99,0x35,0x89,0x47,0xc1,0x49,0x33}},
+ {{0x25,0x12,0x51,0x6e,0x48,0x99,0x35,0x89,0x47,0xc1,0x49,0x33}},
+ {{0x2c,0x12,0x38,0x55,0x2f,0xc1,0x35,0xb1,0x47,0xe9,0x71,0x33}},
+ {{0x2d,0x12,0x79,0x96,0x70,0x99,0x35,0x89,0x47,0xc1,0x49,0x33}},
+ {{0x29,0x12,0xb5,0xd2,0xac,0xe9,0x35,0xd9,0x47,0x11,0x99,0x33}},
+ {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1280x1024_2[] =
+{
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1400x1050_2[] =
+{
+ {{0x2b,0x12,0xd9,0xe5,0xd5,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x22,0x12,0xc0,0xcc,0xbc,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x2b,0x12,0xd9,0xe5,0xd5,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x22,0x12,0xc0,0xcc,0xbc,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x33,0x13,0x01,0x0d,0xfd,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x3f,0x1b,0x3d,0x49,0x39,0x54,0x23,0xc0,0x27,0x66,0x30,0x42}},
+ {{0x33,0x1b,0x91,0x9d,0x8d,0x8c,0x23,0xf8,0x27,0x9e,0x68,0x42}},
+ {{0x43,0x24,0x11,0x1d,0x0d,0xcc,0x23,0x38,0x37,0xde,0xa8,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1600x1200_2[] =
+{	/* TW: Temporary data, invalid */
+ {{0x2b,0x12,0xd9,0xe5,0xd5,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x22,0x12,0xc0,0xcc,0xbc,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x2b,0x12,0xd9,0xe5,0xd5,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x22,0x12,0xc0,0xcc,0xbc,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x33,0x13,0x01,0x0d,0xfd,0x2c,0x23,0x98,0x27,0x3e,0x08,0x42}},
+ {{0x3f,0x1b,0x3d,0x49,0x39,0x54,0x23,0xc0,0x27,0x66,0x30,0x42}},
+ {{0x33,0x1b,0x91,0x9d,0x8d,0x8c,0x23,0xf8,0x27,0x9e,0x68,0x42}},
+ {{0x43,0x24,0x11,0x1d,0x0d,0xcc,0x23,0x38,0x37,0xde,0xa8,0x42}},
+ {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}}
+};
+
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1024x768_3[] =
+{	/* TW: Data from 650/301LVx 1.10.6s */
+ {{0x25,0x13,0xc9,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x2c,0x13,0x9a,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x25,0x13,0xc9,0x24,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x38,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x38,0x18,0x16,0x00,0x00,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x25,0x13,0xc9,0x25,0xff,0xf9,0x45,0x09,0x07,0xf9,0x09,0x24}}
+#if 0	/* TW: Data from 650/301LV */
+ {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x2c,0x12,0x9a,0xae,0x88,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x25,0x12,0xc9,0xdc,0xb6,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}},
+ {{0x38,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x38,0x18,0x16,0x00,0x00,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x36,0x13,0x13,0x25,0xff,0x59,0x45,0x09,0x07,0xf9,0x09,0x24}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
+#endif
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1280x1024_3[] =
+{	/* TW: Temporary data, invalid */
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1400x1050_3[] =
+{	/* TW: Temporary data, invalid */
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}
+};
+
+static const SiS310_Part2PortTblStruct SiS310_CRT2Part2_1600x1200_3[] =
+{	/* TW: Temporary data, invalid */
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x42}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}},
+  {{0x43,0x24,0x21,0x29,0x19,0xea,0x23,0x0a,0x07,0x32,0xc6,0x32}}
+};
+
 typedef struct _SiS310_LCDACRT1DataStruct
 {
  	UCHAR CR[17];
 }SiS310_LCDACRT1DataStruct;
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT1800x600_1[]=
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT1800x600_1[] =
 {
-{{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x65,0x4f,0x89,0x56,0x83,0x04,0x3e,
-   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
-   0x01}}
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_1[]=
-{
-{{0x73,0x4f,0x4f,0x97,0x55,0x86,0xc4,0x1f,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_1[]=
+{  /* TW: Checked (1.10.6s) */
+ {{0x73,0x4f,0x4f,0x97,0x55,0x86,0xc4,0x1f,
    0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x05,
    0x00}},
  {{0x73,0x4f,0x4f,0x97,0x55,0x86,0x97,0x1f,
@@ -2064,255 +2833,536 @@
    0x01}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_1[]=
-{
-{{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_1[]=
+{  /* Checked (1.10.6s) */
+ {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0xb8,0x1f,
+   0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x06,
    0x00}},
- {{0x63,0x4f,0x87,0x54,0x9f,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+ {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0x86,0x1f,
+   0x5e,0x82,0x5d,0x5d,0x87,0x10,0x00,0x06,
    0x00}},
- {{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+ {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0xb8,0x1f,
+   0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x06,
    0x00}},
- {{0x63,0x4f,0x87,0x54,0x9f,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+ {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0x86,0x1f,
+   0x5e,0x82,0x5d,0x5d,0x87,0x10,0x00,0x06,
    0x00}},
- {{0x63,0x4f,0x87,0x54,0x9f,0x04,0x3e,
-   0xe2,0x89,0xdf,0x05,0x00,0x00,0x01,
+ {{0x7e,0x4f,0x4f,0x82,0x58,0x06,0x08,0x3e,
+   0xe0,0x84,0xdf,0xdf,0x09,0x00,0x00,0x06,
    0x00}},
- {{0x7e,0x63,0x82,0x68,0x15,0x7c,0xf0,
-   0x5a,0x8f,0x57,0x7d,0x20,0x00,0x26,
+ {{0x92,0x63,0x63,0x96,0x6c,0x1a,0x80,0xf0,
+   0x58,0x8c,0x57,0x57,0x81,0x20,0x00,0x06,
    0x01}},
- {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+ {{0xae,0x7f,0x7f,0x92,0x88,0x96,0x28,0xf5,
+   0x00,0x84,0xff,0xff,0x29,0x10,0x00,0x02,
+   0x01}},
+ {{0xce,0x9f,0x9f,0x92,0xa8,0x16,0x28,0x5a,
+   0x00,0x84,0xff,0xff,0x29,0x01,0x00,0x07,
    0x01}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT1800x600_1_H[]=
-{
-{{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x04,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11400x1050_1[]=
+{    /* Checked (1.10.6s) */
+ {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
+   0x93,0x86,0x8f,0x8f,0x9f,0x30,0x00,0x05,
    0x00}},
- {{0x30,0x27,0x94,0x2c,0x92,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x04,
+ {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x6c,0x1f,
+   0x60,0x84,0x5d,0x5d,0x6d,0x10,0x00,0x05,
    0x00}},
- {{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x04,
+ {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
+   0x93,0x86,0x8f,0x8f,0x9f,0x30,0x00,0x05,
    0x00}},
- {{0x30,0x27,0x94,0x2c,0x92,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x04,
+ {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x6c,0x1f,
+   0x60,0x84,0x5d,0x5d,0x6d,0x10,0x00,0x05,
    0x00}},
- {{0x30,0x27,0x94,0x2c,0x92,0x04,0x3e,
-   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x04,
+ {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0xee,0x1f,
+   0xe2,0x86,0xdf,0xdf,0xef,0x10,0x00,0x05,
    0x00}},
- {{0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x05,
-   0x01}}
+ {{0x83,0x63,0x63,0x87,0x68,0x16,0x66,0xf0,
+   0x5a,0x8e,0x57,0x57,0x67,0x20,0x00,0x06,
+   0x01}},
+ {{0x9f,0x7f,0x7f,0x83,0x84,0x92,0x0e,0xf5,
+   0x02,0x86,0xff,0xff,0x0f,0x10,0x00,0x02,
+   0x01}},
+ {{0xbf,0x9f,0x9f,0x83,0xa4,0x12,0x0e,0x5a,
+   0x02,0x86,0xff,0xff,0x0f,0x09,0x00,0x07,
+   0x01}},
+ {{0xce,0xae,0xae,0x92,0xb3,0x01,0x28,0x10,
+   0x1a,0x80,0x19,0x19,0x29,0x0f,0x00,0x03,
+   0x00}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_1_H[]=
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11600x1200_1[]=
+{   /* MISSING */
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}}
+};
+
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT1800x600_1_H[]=
 {
-{{0x37,0x27,0x27,0x9B,0x2b,0x94,0xc4,0x1f,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}}
+};
+
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_1_H[]=
+{  /* TW: Checked (1.10.6s) */
+ {{0x4b,0x27,0x27,0x8f,0x2b,0x03,0xc4,0x1f,
    0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x44,
    0x00}},
- {{0x37,0x27,0x27,0x9B,0x2b,0x94,0x97,0x1f,
+ {{0x4b,0x27,0x27,0x8f,0x2b,0x03,0x97,0x1f,
    0x60,0x87,0x5D,0x5D,0x83,0x01,0x00,0x44,
    0x00}},
- {{0x37,0x27,0x27,0x9B,0x2b,0x94,0xc4,0x1f,
+ {{0x4b,0x27,0x27,0x8f,0x2b,0x03,0xc4,0x1f,
    0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x44,
    0x00}},
- {{0x37,0x27,0x27,0x9B,0x2b,0x94,0x97,0x1f,
+ {{0x4b,0x27,0x27,0x8f,0x2b,0x03,0x97,0x1f,
    0x60,0x87,0x5D,0x5D,0x83,0x01,0x00,0x44,
    0x00}},
- {{0x37,0x27,0x27,0x9B,0x2b,0x94,0x04,0x3e,
-   0xE2,0x89,0xDf,0xDf,0x05,0x00,0x00,0x44,
+ {{0x4b,0x27,0x27,0x8f,0x32,0x1b,0x04,0x3e,
+   0xE2,0x89,0xDf,0xDf,0x05,0x00,0x00,0x45,
    0x00}},
- {{0x41,0x31,0x31,0x85,0x35,0x1d,0x7c,0xf0,
+ {{0x55,0x31,0x31,0x99,0x46,0x1d,0x7c,0xf0,
    0x5A,0x8F,0x57,0x57,0x7D,0x20,0x00,0x55,
    0x01}},
- {{0x4f,0x3F,0x3F,0x93,0x45,0x0D,0x24,0xf5,
+ {{0x63,0x3F,0x3F,0x87,0x4a,0x93,0x24,0xf5,
    0x02,0x88,0xFf,0xFf,0x25,0x10,0x00,0x01,
    0x01}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_1_H[]=
-{
-{{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x04,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_1_H[]=
+{   /* Checked (1.10.6s) */
+ {{0x56,0x27,0x27,0x9a,0x30,0x1e,0xb8,0x1f,
+   0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x05,
    0x00}},
-{{0x2f,0x27,0x93,0x2b,0x90,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x04,
-   0x00}},
- {{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x04,
-   0x00}},
- {{0x2f,0x27,0x93,0x2b,0x90,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x04,
+ {{0x3c,0x4f,0x4f,0x82,0x58,0x06,0x86,0xd1,    /* <-- Invalid data - one byte missing in BIOS */
+   0xbc,0x80,0xbb,0xbb,0xe5,0x00,0x00,0x06,
+   0x01}},
+ {{0x56,0x27,0x27,0x9a,0x30,0x1e,0xb8,0x1f,
+   0x90,0x84,0x8f,0x8f,0xb9,0x30,0x00,0x05,
    0x00}},
- {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e,
-   0xe2,0x89,0xdf,0x05,0x00,0x00,0x04,
+ {{0x3c,0x4f,0x4f,0x82,0x58,0x06,0x86,0xd1,
+   0xbc,0x80,0xbb,0xbb,0xe5,0x00,0x00,0x06,
+   0x01}},
+ {{0x56,0x27,0x27,0x9a,0x30,0x1e,0x08,0x3e,
+   0xe0,0x84,0xdf,0xdf,0x09,0x00,0x00,0x05,
    0x00}},
- {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0,
-   0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55,
+ {{0x60,0x31,0x31,0x84,0x3a,0x88,0x80,0xf0,
+   0x58,0x8c,0x57,0x57,0x81,0x20,0x00,0x01,
    0x01}},
- {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+ {{0x6e,0x3f,0x3f,0x92,0x48,0x96,0x28,0xf5,
+   0x00,0x84,0xff,0xff,0x29,0x10,0x00,0x01,
    0x01}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT1800x600_2[]=
-{ 
-{{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x06,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11400x1050_1_H[]=
+{   /* Checked (1.10.6s) */
+  {{0x47,0x27,0x27,0x8b,0x2c,0x1a,0x9e,0x1f,
+    0x93,0x86,0x8f,0x8f,0x9f,0x30,0x00,0x05,
+    0x00}},
+  {{0x47,0x27,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
+    0x60,0x84,0x5d,0x5d,0x6d,0x10,0x00,0x05,
+    0x00}},
+  {{0x47,0x27,0x27,0x8b,0x30,0x1e,0x9e,0x1f,
+    0x92,0x86,0x8f,0x8f,0x9f,0x30,0x00,0x05,
+    0x00}},
+  {{0x47,0x27,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
+    0x60,0x84,0x5d,0x5d,0x6d,0x10,0x00,0x05,
+    0x00}},
+  {{0x47,0x27,0x27,0x8b,0x2c,0x1a,0xee,0x1f,
+    0xe2,0x86,0xdf,0xdf,0xef,0x10,0x00,0x05,
+    0x00}},
+  {{0x51,0x31,0x31,0x95,0x36,0x04,0x66,0xf0,
+    0x5a,0x8e,0x57,0x57,0x67,0x20,0x00,0x01,
+    0x01}},
+  {{0x5f,0x3f,0x3f,0x83,0x44,0x92,0x0e,0xf5,
+    0x02,0x86,0xff,0xff,0x0f,0x10,0x00,0x01,
+    0x01}},
+  {{0x6f,0x4f,0x4f,0x93,0x54,0x82,0x0e,0x5a,
+    0x02,0x86,0xff,0xff,0x0f,0x09,0x00,0x05,
+    0x01}},
+  {{0x76,0x56,0x56,0x9a,0x5b,0x89,0x28,0x10,
+    0x1c,0x80,0x19,0x19,0x29,0x0b,0x00,0x05,
+    0x00}}
+};
+
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11600x1200_1_H[]=
+{   /* MISSING */
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x06,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x06,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x06,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x7f,0x4f,0x83,0x62,0x12,0x72,0xba,
-   0x1c,0x80,0xdf,0x73,0x00,0x00,0x06,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
-   0x01}}
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_2[]=
-{ 
-{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT1800x600_2[]=
+{
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}}
+};
+
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_2[]=
+{   /* Checked (1.10.6s) */
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x72,0x88,0xdf,0xdf,0x25,0x30,0x00,0x06,
+   0x00}},
+ {{0xa3,0x63,0x63,0x87,0x78,0x89,0x24,0xf1,
+   0xae,0x84,0x57,0x57,0x25,0x30,0x00,0x02,
    0x01}},
- {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
    0x01}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_2[]=
-{
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_2[]=
+{   /* Checked (1.10.6s) */
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x06,
    0x00}},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x06,
    0x00}},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x06,
    0x00}},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x06,
    0x00}},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+ {{0xa3,0x4f,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x72,0x88,0xdf,0xdf,0x25,0x30,0x00,0x06,
    0x00}},
- {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+ {{0xa3,0x63,0x63,0x87,0x78,0x89,0x24,0xf1,
+   0xae,0x84,0x57,0x57,0x25,0x30,0x00,0x02,
    0x01}},
- {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+ {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
    0x01}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT1800x600_2_H[]=
-{ 
-{{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x05,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11400x1050_2[]=
+{    /* Checked (1.10.6s) */
+ {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x8f,0x29,0x21,0x00,0x03,
    0x00}},
- {{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05,
+ {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xc2,0x86,0x5d,0x5d,0x29,0x01,0x00,0x03,
+   0x01}},
+ {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x8f,0x29,0x21,0x00,0x03,
    0x00}},
- {{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x05,
+ {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xc2,0x86,0x5d,0x5d,0x29,0x01,0x00,0x03,
    0x00}},
- {{0x3d,0x27,0x81,0x3a,0x1a,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05,
+ {{0xce,0x4f,0x4f,0x92,0x8c,0x1a,0x28,0x9e,
+   0x03,0x87,0xdf,0xdf,0x29,0x01,0x00,0x03,
    0x00}},
- {{0x3d,0x27,0x81,0x32,0x1a,0x72,0xba,
-   0x1c,0x80,0xdf,0x73,0x00,0x00,0x05,
+ {{0xce,0x63,0x63,0x92,0x96,0x04,0x28,0xd4,
+   0x3f,0x83,0x57,0x57,0x29,0x01,0x00,0x07,
+   0x01}},
+ {{0xce,0x7f,0x7f,0x92,0xa4,0x12,0x28,0xd4,
+   0x93,0x87,0xff,0xff,0x29,0x21,0x00,0x07,
+   0x01}},
+ {{0xce,0x9f,0x9f,0x92,0xb4,0x02,0x28,0x5a,
+   0x13,0x87,0xff,0xff,0x29,0x29,0x00,0x03,
+   0x01}},
+ {{0xce,0xae,0xae,0x92,0xbc,0x0a,0x28,0x10,
+   0x20,0x84,0x19,0x19,0x29,0x0f,0x00,0x03,
+   0x00}}
+};
+
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11600x1200_2[]=
+{    /* MISSING */
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00}},
- {{0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x05,
-   0x01}}
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_2_H[]=
-{ 
-{{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT1800x600_2_H[]=
+{
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}}
+};
+
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11024x768_2_H[]=
+{   /* Checked (1.10.6s) */
+ {{0x4f,0x27,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+ {{0x4f,0x27,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x31,0x87,0x8d,0x5d,0x25,0x30,0x00,0x01,   /* <-- invalid data */
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+ {{0x4f,0x27,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+ {{0x4f,0x27,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+ {{0x4f,0x27,0x27,0x93,0x39,0x01,0x24,0xbb,
+   0x72,0x88,0xdf,0xdf,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+ {{0x4f,0x31,0x31,0x93,0x3e,0x06,0x24,0xf1,
+   0xae,0x84,0x57,0x57,0x25,0x30,0x00,0x01,  /* <-- invalid data */
    0x01 }},
- {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+ {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
    0x01 }}
 };
 
-SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_2_H[]=
-{ 
-{{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11280x1024_2_H[]=
+{   /* Checked (1.10.6s) */
+ {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb,
+   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+ {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb,
+   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+ {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb,
+   0x4a,0x80,0x8f,0x8f,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+ {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb,
+   0x31,0x87,0x5d,0x5d,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+ {{0x4f,0x27,0x27,0x93,0x39,0x81,0x24,0xbb,
+   0x72,0x88,0xdf,0xdf,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x31,0x93,0x3e,0x86,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+ {{0x4f,0x31,0x31,0x93,0x3e,0x86,0x24,0xf1,
+   0xae,0x84,0x57,0x57,0x25,0x30,0x00,0x01,
    0x01 }},
- {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+ {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
    0x01 }}
 };
 
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11400x1050_2_H[]=
+{  /* Checked (1.10.6s) */
+ {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x8f,0x29,0x21,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xc2,0x86,0x5d,0x5d,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x8f,0x29,0x21,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xc2,0x86,0x5d,0x5d,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x27,0x8a,0x64,0x92,0x28,0x9e,
+   0x03,0x87,0xdf,0xdf,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0x9c,0x31,0x31,0x80,0x64,0x92,0x28,0xd4,
+   0x3f,0x83,0x57,0x57,0x29,0x01,0x00,0x06,
+   0x01}},
+ {{0x8e,0x3f,0x3f,0x92,0x64,0x12,0x28,0xd4,
+   0x93,0x87,0xff,0xff,0x29,0x21,0x00,0x06,
+   0x01}},
+ {{0x7e,0x4f,0x4f,0x82,0x64,0x12,0x28,0x5a,
+   0x13,0x87,0xff,0xff,0x29,0x29,0x00,0x06,
+   0x01}},
+ {{0x76,0x56,0x56,0x9a,0x64,0x92,0x28,0x10,
+   0x20,0x84,0x19,0x19,0x29,0x0f,0x00,0x05,
+   0x00}}
+};
+
+static const SiS310_LCDACRT1DataStruct  SiS310_LCDACRT11600x1200_2_H[]=
+{  /* MISSING */
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+   0x00}}
+};
+
 typedef struct _SiS310_LVDSCRT1DataStruct
 {
  	UCHAR CR[15];
 } SiS310_LVDSCRT1DataStruct;
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1320x480_1[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1320x480_1[] =
 {
-{{0x65,0x4f,0x89,0x56,0x83,0xaa,0x1f,
+ {{0x65,0x4f,0x89,0x56,0x83,0xaa,0x1f,
    0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
    0x00 }},
  {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
@@ -2330,412 +3380,958 @@
  {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
    0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
    0x01 }},
-{{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e,
+ {{0x2d,0x27,0x90,0x2c,0x80,0x0b,0x3e,
    0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
    0x00 }}
 };
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1[]=
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1[] =   /* TW: New */
 {
-{{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f,
+ {{0x6b,0x4f,0x8f,0x55,0x85,0xaa,0x1f,
    0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
    0x00 }},
- {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
+ {{0x6b,0x4f,0x8f,0x55,0x85,0x78,0x1f,
    0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
    0x00 }},
- {{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f,
+ {{0x6b,0x4f,0x8f,0x55,0x85,0xaa,0x1f,
    0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
    0x00 }},
- {{0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
+ {{0x6b,0x4f,0x8f,0x55,0x85,0x78,0x1f,
    0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
    0x00 }},
- {{0x65,0x4f,0x89,0x56,0x83,0x04,0x3e,
+ {{0x6b,0x4f,0x8f,0x55,0x85,0xfa,0x1f,
    0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05,
    0x00 }},
- {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
+ {{0x7f,0x63,0x83,0x69,0x19,0x72,0xf0,
    0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
    0x01 }}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_1[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_1[] =    /* TW: New */
 {
-{{0x73,0x4f,0x97,0x55,0x86,0xc4,0x1f,
+ {{0x73,0x4f,0x97,0x53,0x84,0xb4,0x1f,
    0x92,0x89,0x8f,0xb5,0x30,0x00,0x05,
    0x00}},
- {{0x73,0x4f,0x97,0x55,0x86,0x97,0x1f,
+ {{0x73,0x4f,0x97,0x53,0x84,0x82,0x1f,
    0x60,0x87,0x5d,0x83,0x10,0x00,0x05,
    0x00}},
- {{0x73,0x4f,0x97,0x55,0x86,0xc4,0x1f,
+ {{0x73,0x4f,0x97,0x53,0x84,0xb4,0x1f,
    0x92,0x89,0x8f,0xb5,0x30,0x00,0x05,
    0x00}},
- {{0x73,0x4f,0x97,0x55,0x86,0x97,0x1f,
+ {{0x73,0x4f,0x97,0x53,0x84,0x82,0x1f,
    0x60,0x87,0x5d,0x83,0x10,0x00,0x05,
    0x00}},
- {{0x73,0x4f,0x97,0x55,0x86,0x04,0x3e,
+ {{0x73,0x4f,0x97,0x53,0x84,0x04,0x3e,
    0xE2,0x89,0xDf,0x05,0x00,0x00,0x05,
    0x00}},
- {{0x87,0x63,0x8B,0x69,0x1A,0x7c,0xf0,
-   0x5A,0x8F,0x57,0x7D,0x20,0x00,0x26,
+ {{0x87,0x63,0x8B,0x67,0x18,0x7c,0xf0,
+   0x5A,0x81,0x57,0x7D,0x00,0x00,0x06,
    0x01}},
- {{0xA3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xFf,0x25,0x10,0x00,0x02,
+ {{0xA3,0x7f,0x87,0x83,0x94,0x24,0xf5,
+   0x02,0x89,0xFf,0x25,0x10,0x00,0x02,
    0x01}}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_1[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_1[] =    /* TW: New */
 {
-{{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+ {{0x7e,0x4f,0x82,0x56,0x04,0xb8,0x1f,
+   0x90,0x84,0x8f,0xb9,0x30,0x00,0x06,
    0x00 }},
- {{0x63,0x4f,0x87,0x54,0x9f,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+ {{0x7e,0x4f,0x82,0x56,0x04,0x86,0x1f,
+   0x5e,0x82,0x5d,0x87,0x10,0x00,0x06,
    0x00 }},
- {{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+ {{0x7e,0x4f,0x82,0x56,0x04,0xb8,0x1f,
+   0x90,0x84,0x8f,0xb9,0x30,0x00,0x06,
    0x00 }},
- {{0x63,0x4f,0x87,0x54,0x9f,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+ {{0x7e,0x4f,0x82,0x56,0x04,0x86,0x1f,
+   0x5e,0x82,0x5d,0x87,0x10,0x00,0x06,
    0x00 }},
- {{0x63,0x4f,0x87,0x54,0x9f,0x04,0x3e,
-   0xe2,0x89,0xdf,0x05,0x00,0x00,0x01,
+ {{0x7e,0x4f,0x82,0x56,0x04,0x08,0x3e,
+   0xe0,0x84,0xdf,0x09,0x00,0x00,0x06,
    0x00 }},
- {{0x7e,0x63,0x82,0x68,0x15,0x7c,0xf0,
-   0x5a,0x8f,0x57,0x7d,0x20,0x00,0x26,
+ {{0x92,0x63,0x96,0x6a,0x18,0x80,0xf0,
+   0x58,0x8c,0x57,0x81,0x20,0x00,0x06,
    0x01 }},
- {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
-   0x01 }}
+ {{0xae,0x7f,0x92,0x86,0x94,0x28,0xf5,
+   0x00,0x84,0xff,0x29,0x10,0x00,0x02,
+   0x01 }},
+ {{0xce,0x9f,0x92,0xa6,0x14,0x28,0x5a,
+   0x00,0x84,0xff,0x29,0x09,0x00,0x07,
+   0x01}}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1_H[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1_H[] =    /* TW: New */
 {
-{{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x04,
+ {{0x43,0x27,0x87,0x2d,0x1d,0xaa,0x1f,
+   0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
    0x00 }},
- {{0x30,0x27,0x94,0x2c,0x92,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x04,
+ {{0x43,0x27,0x87,0x2d,0x1d,0x78,0x1f,
+   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
    0x00 }},
- {{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x04,
+ {{0x43,0x27,0x87,0x2d,0x1d,0xfa,0x1f,
+   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05,
    0x00 }},
- {{0x30,0x27,0x94,0x2c,0x92,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x04,
+ {{0x43,0x27,0x87,0x2d,0x1d,0x78,0x1f,
+   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
    0x00 }},
- {{0x30,0x27,0x94,0x2c,0x92,0x04,0x3e,
-   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x04,
+ {{0x43,0x27,0x87,0x2d,0x1d,0xfa,0x1f,
+   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05,
    0x00 }},
- {{0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x05,
+ {{0x4d,0x31,0x91,0x37,0x07,0x72,0xf0,
+   0x58,0x8d,0x57,0x73,0x20,0x00,0x01,
    0x01 }}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_1_H[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_1_H[] =    /* TW: New */
 {
-{{0x37,0x27,0x9B,0x2b,0x94,0xc4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+ {{0x4b,0x27,0x8f,0x2b,0x1c,0xb4,0x1f,
+   0x92,0x89,0x8f,0xb5,0x30,0x00,0x05,
    0x00 }},
- {{0x37,0x27,0x9B,0x2b,0x94,0x97,0x1f,
-   0x60,0x87,0x5D,0x83,0x01,0x00,0x44,
+ {{0x4b,0x27,0x8f,0x2b,0x1c,0x82,0x1f,
+   0x60,0x87,0x5D,0x83,0x01,0x00,0x05,
    0x00}},
- {{0x37,0x27,0x9B,0x2b,0x94,0xc4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+ {{0x4b,0x27,0x8f,0x2b,0x1c,0xb4,0x1f,
+   0x92,0x89,0x8f,0xb5,0x30,0x00,0x05,
    0x00}},
- {{0x37,0x27,0x9B,0x2b,0x94,0x97,0x1f,
-   0x60,0x87,0x5D,0x83,0x01,0x00,0x44,
+ {{0x4b,0x27,0x8f,0x2b,0x1c,0x82,0x1f,
+   0x60,0x87,0x5D,0x83,0x01,0x00,0x05,
    0x00}},
- {{0x37,0x27,0x9B,0x2b,0x94,0x04,0x3e,
-   0xE2,0x89,0xDf,0x05,0x00,0x00,0x44,
+ {{0x4b,0x27,0x8f,0x2b,0x1c,0x04,0x3e,
+   0xE2,0x89,0xDf,0x05,0x00,0x00,0x05,
    0x00}},
- {{0x41,0x31,0x85,0x35,0x1d,0x7c,0xf0,
-   0x5A,0x8F,0x57,0x7D,0x20,0x00,0x55,
+ {{0x55,0x31,0x99,0x35,0x06,0x7c,0xf0,
+   0x5A,0x81,0x57,0x7D,0x00,0x00,0x01,
    0x01}},
- {{0x4f,0x3F,0x93,0x45,0x0D,0x24,0xf5,
-   0x02,0x88,0xFf,0x25,0x10,0x00,0x01,
+ {{0x63,0x3F,0x87,0x43,0x94,0x24,0xf5,
+   0x02,0x89,0xFf,0x25,0x10,0x00,0x01,
    0x01 }}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_1_H[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_1_H[] =   /* TW: New */
 {
-{{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x04,
+ {{0x56,0x27,0x9a,0x2e,0x1c,0xb8,0x1f,
+   0x90,0x84,0x8f,0xb9,0x30,0x00,0x05,
    0x00 }},
- {{0x2f,0x27,0x93,0x2b,0x90,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x04,
+ {{0x56,0x27,0x9a,0x2e,0x1c,0x86,0x1f,
+   0x5e,0x82,0x5d,0x87,0x10,0x00,0x05,
    0x00 }},
- {{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x04,
+ {{0x56,0x27,0x9a,0x2e,0x1c,0xb8,0x1f,
+   0x90,0x84,0x8f,0xb9,0x30,0x00,0x05,
    0x00 }},
- {{0x2f,0x27,0x93,0x2b,0x90,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x04,
-   0x00 }},
- {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e,
-   0xe2,0x89,0xdf,0x05,0x00,0x00,0x04,
+ {{0x56,0x27,0x9a,0x2e,0x1c,0x86,0x1f,
+   0x5e,0x82,0x5d,0x87,0x10,0x00,0x05,
+   0x01 }},
+ {{0x56,0x27,0x9a,0x2e,0x1c,0x08,0x3e,
+   0xe0,0x84,0xdf,0x09,0x00,0x00,0x05,
    0x00 }},
- {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0,
-   0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55,
+ {{0x60,0x31,0x84,0x38,0x86,0x80,0xf0,
+   0x58,0x8c,0x57,0x81,0x20,0x00,0x01,
    0x01 }},
- {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+ {{0x6e,0x3f,0x92,0x46,0x94,0x28,0xf5,
+   0x00,0x84,0xff,0x29,0x10,0x00,0x01,
    0x01 }}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_2[]=
-{ 
-{{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x06,
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_2[]=   /* TW: New */
+{
+ {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
+   0xff,0x84,0x8f,0x73,0x00,0x00,0x06,
    0x00 }},
  {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x06,
+   0xe6,0x8b,0x5d,0x73,0x00,0x00,0x06,
    0x00 }},
  {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x06,
+   0xff,0x84,0x8f,0x73,0x00,0x00,0x06,
    0x00 }},
  {{0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x06,
+   0xe6,0x8b,0x5d,0x73,0x00,0x00,0x06,
    0x00 }},
  {{0x7f,0x4f,0x83,0x62,0x12,0x72,0xba,
-   0x1c,0x80,0xdf,0x73,0x00,0x00,0x06,
+   0x27,0x8c,0xdf,0x73,0x00,0x00,0x06,
    0x00 }},
- {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
+ {{0x7f,0x63,0x83,0x69,0x19,0x72,0xf0,
+   0x58,0x8d,0x57,0x73,0x20,0x00,0x06,
    0x01 }}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_2[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_2[] =   /* TW: New */
 { 
-{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
-   0x00 }},
  {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+   0x57,0x8e,0x8f,0x25,0x30,0x00,0x06,
    0x00 }},
  {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+   0x3e,0x85,0x5d,0x25,0x10,0x00,0x06,
    0x00 }},
  {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+   0x57,0x8e,0x8f,0x25,0x30,0x00,0x06,
    0x00 }},
  {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+   0x3e,0x85,0x5d,0x25,0x10,0x00,0x06,
+   0x01 }},
+ {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+   0x7f,0x86,0xdf,0x25,0x10,0x00,0x06,
    0x00 }},
  {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+   0xbb,0x82,0x57,0x25,0x10,0x00,0x02,
    0x01 }},
- {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+ {{0xa3,0x7f,0x87,0x83,0x94,0x24,0xf5,
+   0x02,0x89,0xff,0x25,0x10,0x00,0x02,
    0x01 }}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_2[]=
-{ 
-{{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_2[] =  /* TW: New */
+{
+ {{0xce,0x4f,0x92,0x81,0x0f,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x03,
    0x00 }},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+ {{0xce,0x4f,0x92,0x81,0x0f,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x03,
    0x00 }},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+ {{0xce,0x4f,0x92,0x81,0x0f,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x03,
    0x00 }},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+ {{0xce,0x4f,0x92,0x81,0x0f,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x03,
    0x00 }},
- {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+ {{0xce,0x4f,0x92,0x81,0x0f,0x28,0x9e,
+   0x03,0x87,0xdf,0x29,0x01,0x00,0x03,
    0x00 }},
- {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+ {{0xce,0x63,0x92,0x8b,0x19,0x28,0xd4,
+   0x3f,0x83,0x57,0x29,0x01,0x00,0x03,
    0x01 }},
- {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
-   0x01 }}
+ {{0xce,0x7f,0x92,0x99,0x07,0x28,0xd4,
+   0x93,0x87,0xff,0x29,0x21,0x00,0x07,
+   0x01 }},
+ {{0xce,0x9f,0x92,0xa6,0x14,0x28,0x5a,
+   0x00,0x84,0xff,0x29,0x09,0x00,0x07,
+   0x01}}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_2_H[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_2_H[] =   /* TW: New */
 { 
-{{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x05,
+ {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e,
+   0xff,0x84,0x8f,0x73,0x00,0x00,0x01,
    0x00 }},
- {{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05,
+ {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e,
+   0xd6,0x8b,0x5d,0x73,0x00,0x00,0x01,
    0x00 }},
- {{0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x05,
+ {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e,
+   0xff,0x84,0x8f,0x73,0x00,0x00,0x01,
    0x00 }},
- {{0x3d,0x27,0x81,0x3a,0x1a,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05,
+ {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0x3e,
+   0xd6,0x8b,0x5d,0x73,0x00,0x00,0x01,
    0x00 }},
- {{0x3d,0x27,0x81,0x32,0x1a,0x72,0xba,
-   0x1c,0x80,0xdf,0x73,0x00,0x00,0x05,
+ {{0x57,0x27,0x9b,0x3a,0x0a,0x72,0xba,
+   0x27,0x8c,0xdf,0x73,0x00,0x00,0x01,
    0x00 }},
- {{0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x05,
+ {{0x4d,0x31,0x91,0x3a,0x0a,0x72,0xf0,
+   0x63,0x88,0x57,0x73,0x00,0x00,0x01,
    0x01 }}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_2_H[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_2_H[] =   /* TW: New */
 { 
-{{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+ {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb,
+   0x57,0x8e,0x8f,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+ {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb,
+   0x3e,0x85,0x5d,0x25,0x10,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+ {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb,
+   0x57,0x8e,0x8f,0x25,0x30,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+ {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb,
+   0x3e,0x85,0x5d,0x25,0x10,0x00,0x01,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+ {{0x7b,0x27,0x9f,0x46,0x97,0x24,0xbb,
+   0x7f,0x86,0xdf,0x25,0x10,0x00,0x01,
    0x00 }},
- {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+ {{0x71,0x31,0x95,0x46,0x97,0x24,0xf1,
+   0xbb,0x82,0x57,0x25,0x10,0x00,0x01,
    0x01 }},
- {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+ {{0x63,0x3f,0x87,0x46,0x97,0x24,0xf5,
+   0x0f,0x86,0xff,0x25,0x30,0x00,0x01,
    0x01 }}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_2_H[]=
-{ 
-{{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_2_H[] =   /* TW: New */
+{
+ {{0xa6,0x27,0x8a,0x59,0x87,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x06,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+ {{0xa6,0x27,0x8a,0x59,0x87,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x06,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+ {{0xa6,0x27,0x8a,0x59,0x87,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x06,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+ {{0xa6,0x27,0x8a,0x59,0x87,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x06,
    0x00 }},
- {{0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+ {{0xa6,0x27,0x8a,0x59,0x87,0x28,0x9e,
+   0x03,0x87,0xdf,0x29,0x01,0x00,0x06,
    0x00 }},
- {{0x4f,0x31,0x93,0x3e,0x86,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+ {{0x9c,0x31,0x80,0x59,0x87,0x28,0xd4,
+   0x3f,0x83,0x57,0x29,0x01,0x00,0x06,
    0x01 }},
- {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+ {{0x8e,0x3f,0x92,0x79,0x07,0x28,0xd4,
+   0x93,0x87,0xff,0x29,0x21,0x00,0x06,
+   0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1XXXxXXX_1[] =   /* TW: New */
+{
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x05,
+   0x00}},
+ {{0x5f,0x4f,0x82,0x55,0x81,0x0b,0x3e,
+   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x05,
+   0x00}},
+ {{0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
+   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
+   0x01}},
+ {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+   0x01}},
+ {{0xce,0x9f,0x92,0xa9,0x17,0x24,0xf5,
+   0x02,0x88,0xff,0x25,0x10,0x00,0x07,
+   0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1XXXxXXX_1_H[] =   /* TW: New */
+{
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0xbf,0x1f,
+   0x9c,0x8e,0x96,0xb9,0x30,0x00,0x00,
+   0x00}},
+ {{0x38,0x27,0x9c,0x2c,0x80,0x0b,0x3e,
+   0xe9,0x8b,0xe7,0x04,0x00,0x00,0x00,
+   0x00}},
+ {{0x4d,0x31,0x91,0x3b,0x03,0x72,0xf0,
+   0x58,0x8c,0x57,0x73,0x20,0x00,0x01,
+   0x01}},
+ {{0x63,0x3f,0x87,0x4a,0x92,0x24,0xf5,
    0x02,0x88,0xff,0x25,0x10,0x00,0x01,
    0x01}}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1UNTSC[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_1[] =   /* TW: New */
+{
+ {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
+   0x93,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
+   0x93,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0xee,0x1f,
+   0xe2,0x86,0xdf,0xef,0x10,0x00,0x05,
+   0x00}},
+ {{0x83,0x63,0x87,0x68,0x16,0x66,0xf0,
+   0x5a,0x8e,0x57,0x67,0x20,0x00,0x06,
+   0x01}},
+ {{0x9f,0x7f,0x83,0x84,0x92,0x0e,0xf5,
+   0x02,0x86,0xff,0x0f,0x10,0x00,0x02,
+   0x01}},
+ {{0xbf,0x9f,0x83,0xa4,0x12,0x0e,0x5a,
+   0x02,0x86,0xff,0x0f,0x09,0x00,0x07,
+   0x01}},
+ {{0xce,0xae,0x92,0xb3,0x01,0x28,0x10,
+   0x1a,0x80,0x19,0x29,0x0f,0x00,0x03,
+   0x00}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_1_H[] =   /* TW: New */
+{
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x9e,0x1f,
+   0x93,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x30,0x1e,0x9e,0x1f,
+   0x92,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0xee,0x1f,
+   0xe2,0x86,0xdf,0xef,0x10,0x00,0x05,
+   0x00}},
+ {{0x51,0x31,0x95,0x36,0x04,0x66,0xf0,
+   0x5a,0x8e,0x57,0x67,0x20,0x00,0x01,
+   0x01}},
+ {{0x5f,0x3f,0x83,0x44,0x92,0x0e,0xf5,
+   0x02,0x86,0xff,0x0f,0x10,0x00,0x01,
+   0x01}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x0e,0x5a,
+   0x02,0x86,0xff,0x0f,0x09,0x00,0x05,
+   0x01}},
+ {{0x76,0x56,0x9a,0x5b,0x89,0x28,0x10,
+   0x1c,0x80,0x19,0x29,0x0b,0x00,0x05,
+   0x00}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_2[] =    /* TW: New */
+{
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x03,
+   0x00}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x03,
+   0x01}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x03,
+   0x00}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x03,
+   0x00}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9e,
+   0x03,0x87,0xdf,0x29,0x01,0x00,0x03,
+   0x00}},
+ {{0xce,0x63,0x92,0x96,0x04,0x28,0xd4,
+   0x3f,0x83,0x57,0x29,0x01,0x00,0x07,
+   0x01}},
+ {{0xce,0x7f,0x92,0xa4,0x12,0x28,0xd4,
+   0x93,0x87,0xff,0x29,0x21,0x00,0x07,
+   0x01}},
+ {{0xce,0x9f,0x92,0xb4,0x02,0x28,0x5a,
+   0x13,0x87,0xff,0x29,0x29,0x00,0x03,
+   0x01}},
+ {{0xce,0xae,0x92,0xbc,0x0a,0x28,0x10,
+   0x20,0x84,0x19,0x29,0x0f,0x00,0x03,
+   0x00}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11400x1050_2_H[] =    /* TW: New */
+{
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9e,
+   0x03,0x87,0xdf,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0x9c,0x31,0x80,0x64,0x92,0x28,0xd4,
+   0x3f,0x83,0x57,0x29,0x01,0x00,0x06,
+   0x01}},
+ {{0x8e,0x3f,0x92,0x64,0x12,0x28,0xd4,
+   0x93,0x87,0xff,0x29,0x21,0x00,0x06,
+   0x01}},
+ {{0x7e,0x4f,0x82,0x64,0x12,0x28,0x5a,
+   0x13,0x87,0xff,0x29,0x29,0x00,0x06,
+   0x01}},
+ {{0x76,0x56,0x9a,0x64,0x92,0x28,0x10,
+   0x20,0x84,0x19,0x29,0x0f,0x00,0x05,
+   0x00}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x600_1[] =
+{
+        {{0x64,0x4f,0x88,0x54,0x9f,0x5a,0x3e,
+	  0xe8,0x8f,0x8f,0x5b,0x00,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x2e,0x3e,
+	  0xb9,0x80,0x5d,0x2f,0x00,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x5a,0x3e,
+	  0xe8,0x8f,0x8f,0x5b,0x00,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x2e,0x3e,
+	  0xb9,0x80,0x5d,0x2f,0x00,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0xaf,0xba,
+	  0x3b,0x82,0xdf,0xb0,0x00,0x00,0x01,
+	  0x00}},
+        {{0x7e,0x63,0x82,0x68,0x15,0x1e,0xf1,
+	  0xae,0x85,0x57,0x1f,0x30,0x00,0x26,
+	  0x01}},
+        {{0xa3,0x7f,0x87,0x86,0x97,0x1e,0xf1,
+	  0xae,0x85,0x57,0x1f,0x30,0x00,0x02,
+	  0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x600_1_H[] =
+{
+        {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+          0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e,
+	  0xe2,0x89,0xdf,0x05,0x00,0x00,0x44,
+	  0x00}},
+        {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0,
+	  0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55,
+	  0x01}},
+        {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x600_2[] =
+{
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+          0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+	  0x01}},
+        {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+	  0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x600_2_H[] =
+{
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+	  0x01}},
+        {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11152x768_1[] =
+{
+        {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
+	  0x00}},
+        {{0x64,0x4f,0x88,0x54,0x9f,0x04,0x3e,
+	  0xe2,0x89,0xdf,0x05,0x00,0x00,0x01,
+	  0x00}},
+        {{0x7e,0x63,0x82,0x68,0x15,0x7c,0xf0,
+	  0x5a,0x8f,0x57,0x7d,0x20,0x00,0x26,
+	  0x01}},
+        {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+	  0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11152x768_1_H[] =
+{
+        {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0xc4,0x1f,
+	  0x92,0x89,0x8f,0xb5,0x30,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x97,0x1f,
+	  0x60,0x87,0x5d,0x83,0x10,0x00,0x44,
+	  0x00}},
+        {{0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e,
+	  0xe2,0x89,0xdf,0x05,0x00,0x00,0x44,
+	  0x00}},
+        {{0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0,
+	  0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55,
+	  0x01}},
+        {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11152x768_2[] =
+{
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
+	  0x00}},
+        {{0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x02,
+	  0x01}},
+        {{0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x02,
+	  0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11152x768_2_H[] =
+{
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
+	  0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
+	  0x00}},
+        {{0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1,
+	  0xae,0x84,0x57,0x25,0x30,0x00,0x01,
+	  0x01}},
+        {{0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
+	  0x02,0x88,0xff,0x25,0x10,0x00,0x01,
+	  0x01}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_1[] =  
+{    /* TW: Temporary data - invalid */
+ {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
+   0x93,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x9e,0x1f,
+   0x93,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0xee,0x1f,
+   0xe2,0x86,0xdf,0xef,0x10,0x00,0x05,
+   0x00}},
+ {{0x83,0x63,0x87,0x68,0x16,0x66,0xf0,
+   0x5a,0x8e,0x57,0x67,0x20,0x00,0x06,
+   0x01}},
+ {{0x9f,0x7f,0x83,0x84,0x92,0x0e,0xf5,
+   0x02,0x86,0xff,0x0f,0x10,0x00,0x02,
+   0x01}},
+ {{0xbf,0x9f,0x83,0xa4,0x12,0x0e,0x5a,
+   0x02,0x86,0xff,0x0f,0x09,0x00,0x07,
+   0x01}},
+ {{0xce,0xae,0x92,0xb3,0x01,0x28,0x10,
+   0x1a,0x80,0x19,0x29,0x0f,0x00,0x03,
+   0x00}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_1_H[] =
+{    /* TW: Temporary data - invalid */
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x9e,0x1f,
+   0x93,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x30,0x1e,0x9e,0x1f,
+   0x92,0x86,0x8f,0x9f,0x30,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0x6c,0x1f,
+   0x60,0x84,0x5d,0x6d,0x10,0x00,0x05,
+   0x00}},
+ {{0x47,0x27,0x8b,0x2c,0x1a,0xee,0x1f,
+   0xe2,0x86,0xdf,0xef,0x10,0x00,0x05,
+   0x00}},
+ {{0x51,0x31,0x95,0x36,0x04,0x66,0xf0,
+   0x5a,0x8e,0x57,0x67,0x20,0x00,0x01,
+   0x01}},
+ {{0x5f,0x3f,0x83,0x44,0x92,0x0e,0xf5,
+   0x02,0x86,0xff,0x0f,0x10,0x00,0x01,
+   0x01}},
+ {{0x6f,0x4f,0x93,0x54,0x82,0x0e,0x5a,
+   0x02,0x86,0xff,0x0f,0x09,0x00,0x05,
+   0x01}},
+ {{0x76,0x56,0x9a,0x5b,0x89,0x28,0x10,
+   0x1c,0x80,0x19,0x29,0x0b,0x00,0x05,
+   0x00}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_2[] =
+{    /* TW: Temporary data - invalid */
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x03,
+   0x00}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x03,
+   0x01}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x03,
+   0x00}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x03,
+   0x00}},
+ {{0xce,0x4f,0x92,0x8c,0x1a,0x28,0x9e,
+   0x03,0x87,0xdf,0x29,0x01,0x00,0x03,
+   0x00}},
+ {{0xce,0x63,0x92,0x96,0x04,0x28,0xd4,
+   0x3f,0x83,0x57,0x29,0x01,0x00,0x07,
+   0x01}},
+ {{0xce,0x7f,0x92,0xa4,0x12,0x28,0xd4,
+   0x93,0x87,0xff,0x29,0x21,0x00,0x07,
+   0x01}},
+ {{0xce,0x9f,0x92,0xb4,0x02,0x28,0x5a,
+   0x13,0x87,0xff,0x29,0x29,0x00,0x03,
+   0x01}},
+ {{0xce,0xae,0x92,0xbc,0x0a,0x28,0x10,
+   0x20,0x84,0x19,0x29,0x0f,0x00,0x03,
+   0x00}}
+};
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11600x1200_2_H[] =    /* TW: New */
+{    /* TW: Temporary data - invalid */
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xdb,0x8f,0x8f,0x29,0x21,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9a,
+   0xc2,0x86,0x5d,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0xa6,0x27,0x8a,0x64,0x92,0x28,0x9e,
+   0x03,0x87,0xdf,0x29,0x01,0x00,0x06,
+   0x00}},
+ {{0x9c,0x31,0x80,0x64,0x92,0x28,0xd4,
+   0x3f,0x83,0x57,0x29,0x01,0x00,0x06,
+   0x01}},
+ {{0x8e,0x3f,0x92,0x64,0x12,0x28,0xd4,
+   0x93,0x87,0xff,0x29,0x21,0x00,0x06,
+   0x01}},
+ {{0x7e,0x4f,0x82,0x64,0x12,0x28,0x5a,
+   0x13,0x87,0xff,0x29,0x29,0x00,0x06,
+   0x01}},
+ {{0x76,0x56,0x9a,0x64,0x92,0x28,0x10,
+   0x20,0x84,0x19,0x29,0x0f,0x00,0x05,
+   0x00}}
+};
+
+
+static const SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1UNTSC[] =    /* TW: New */
 { 
-{{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
-   0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
-   0x00 }},
- {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
-   0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,
-   0x00 }},
- {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
-   0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
-   0x00 }},
- {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
-   0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,
-   0x00 }},
- {{0x5d,0x4f,0x81,0x53,0x9c,0x56,0xba,
-   0x18,0x84,0xdf,0x57,0x00,0x00,0x01,
-   0x00 }},
- {{0x80,0x63,0x84,0x6c,0x17,0xec,0xf0,
-   0x90,0x8c,0x57,0xed,0x20,0x00,0x06,
-   0x01 }}
+	{{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+	  0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
+	  0x00 }},
+	{{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+	  0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+	  0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
+	  0x00 }},
+	{{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+	  0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x5d,0x4f,0x81,0x56,0x99,0x56,0xba,
+	  0x0a,0x84,0xdf,0x57,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x80,0x63,0x84,0x6d,0x0f,0xec,0xf0,
+	  0x7a,0x8f,0x57,0xed,0x20,0x00,0x06,
+	  0x01 }},
+	{{0x8c,0x7f,0x90,0x86,0x09,0xaf,0xf5,  /* TW: 1024x768 */
+	  0x36,0x88,0xff,0xb0,0x10,0x00,0x02,
+	  0x01}}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1ONTSC[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1ONTSC[] =    /* TW: New */
 { 
-{{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
-   0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
-   0x00 }},
- {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
-   0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,
-   0x00 }},
- {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
-   0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
-   0x00 }},
- {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
-   0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,
-   0x00 }},
- {{0x5d,0x4f,0x81,0x56,0x9c,0x0b,0x3e,
-   0xe8,0x84,0xdf,0x0c,0x00,0x00,0x01,
-   0x00 }},
- {{0x7d,0x63,0x81,0x6a,0x16,0xba,0xf0,
-   0x7f,0x86,0x57,0xbb,0x00,0x00,0x06,
-   0x01 }}
+	{{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e,
+	  0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
+	  0x00 }},
+	{{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e,
+	  0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e,
+	  0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
+	  0x00 }},
+	{{0x63,0x4f,0x87,0x5a,0x9f,0x0b,0x3e,
+	  0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x5d,0x4f,0x81,0x58,0x9d,0x0b,0x3e,
+	  0xe8,0x84,0xdf,0x0c,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x7d,0x63,0x81,0x68,0x0e,0xba,0xf0,
+	  0x78,0x8a,0x57,0xbb,0x20,0x00,0x06,
+	  0x01 }},
+	{{0x8c,0x7f,0x90,0x82,0x06,0x46,0xf5,   /* TW: 1024x768 */
+	  0x15,0x88,0xff,0x47,0x70,0x00,0x02,
+	  0x01 }}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1UPAL[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1UPAL[] =    /* TW: New */
 { 
-{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
-   0x00 }},
- {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
-   0x00 }},
- {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
-   0x00 }},
- {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
-   0x00 }},
- {{0x64,0x4f,0x88,0x55,0x80,0xec,0xba,
-   0x50,0x84,0xdf,0xed,0x00,0x00,0x05,
-   0x00 }},
- {{0x70,0x63,0x94,0x68,0x8d,0x42,0xf1,
-   0xc8,0x8c,0x57,0xe9,0x20,0x00,0x05,
-   0x01 }}
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
+	  0x00 }},
+	{{0x64,0x4f,0x88,0x5a,0x9f,0x6f,0xba,
+	  0x15,0x83,0xdf,0x70,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x73,0x63,0x97,0x69,0x8b,0xec,0xf0,
+	  0x90,0x8c,0x57,0xed,0x20,0x00,0x05,
+	  0x01 }},
+	{{0xaa,0x7f,0x8e,0x8e,0x96,0xe6,0xf5,   /* TW: 1024x768 */
+	  0x50,0x88,0xff,0xe7,0x10,0x00,0x02,
+	  0x01}}
 };
 
-SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1OPAL[]=
+static const SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1OPAL[] =    /* TW: New */
 { 
-{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
-   0x00 }},
- {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
-   0x00 }},
- {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
-   0x00 }},
- {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
-   0x00 }},
- {{0x64,0x4f,0x88,0x55,0x80,0x6f,0xba,
-   0x20,0x83,0xdf,0x70,0x00,0x00,0x05,
-   0x00 }},
- {{0x73,0x63,0x97,0x69,0x8e,0xec,0xf0,
-   0x90,0x8c,0x57,0xed,0x20,0x00,0x05,
-   0x01 }}
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
+	  0x00 }},
+	{{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+	  0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
+	  0x00 }},
+	{{0x64,0x4f,0x88,0x58,0x9d,0x6f,0xba,
+	  0x15,0x83,0xdf,0x70,0x00,0x00,0x01,
+	  0x00 }},
+	{{0x71,0x63,0x95,0x69,0x8c,0x6f,0xf0,
+	  0x5a,0x8b,0x57,0x70,0x20,0x00,0x05,
+	  0x01 }},
+	{{0xaa,0x7f,0x8e,0x8f,0x96,0x69,0xf5,   /* TW:  1024x768 */
+	  0x28,0x88,0xff,0x6a,0x10,0x00,0x02,
+	  0x01 }}
 };
 
+/* TW: New data for Chrontel 7019 (From 650/LVDS BIOS 1.10.0) */
 typedef struct _SiS310_CHTVRegDataStruct
 {
- 	UCHAR Reg[5];
+ 	UCHAR Reg[16];
 } SiS310_CHTVRegDataStruct;
 
-SiS310_CHTVRegDataStruct SiS310_CHTVReg_UNTSC[] = {
-	{{0x00}}
- };
-
-SiS310_CHTVRegDataStruct SiS310_CHTVReg_ONTSC[] = {
-	{{0x00}}
- };
-
-SiS310_CHTVRegDataStruct SiS310_CHTVReg_UPAL[] = {
-	{{0x00}}
- };
-
-SiS310_CHTVRegDataStruct SiS310_CHTVReg_OPAL[] = {
-	{{0x00}}
- };
-
-UCHAR SiS310_CHTVVCLKUNTSC[]={0x00 };
+static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_UNTSC[] = {
+	{{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x4a,0x77,0xbb,0x94,0x84,0x48,0xfe,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x6a,0x77,0xbb,0x6e,0x84,0x2e,0x02,0x5a,0x04,0x00,0x80,0x20,0x7e,0x80,0x98,0x00}},
+	{{0xcf,0x77,0xb7,0xc8,0x84,0x3b,0x02,0x5a,0x04,0x00,0x80,0x19,0x88,0x30,0x7f,0x00}},
+	{{0xee,0x77,0xbb,0x66,0x87,0x32,0x01,0x5a,0x04,0x00,0x80,0x1b,0xd3,0xf2,0x36,0x00}}
+};
+
+static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_ONTSC[] = {
+	{{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x49,0x77,0xbb,0x7b,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x69,0x77,0xbb,0x6e,0x84,0x1e,0x00,0x5a,0x04,0x00,0x80,0x25,0x1a,0x43,0x04,0x00}},
+	{{0xce,0x77,0xb7,0xb6,0x83,0x2c,0x02,0x5a,0x04,0x00,0x80,0x1c,0x00,0x82,0x97,0x00}},
+	{{0xed,0x77,0xbb,0x66,0x8c,0x21,0x02,0x5a,0x04,0x00,0x80,0x1f,0x9f,0xc1,0x0c,0x00}}
+};
+
+static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_UPAL[] = {
+	{{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x41,0x7f,0xb7,0x80,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x41,0x7f,0xb7,0x34,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x41,0x7f,0xb7,0x12,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x5a,0x05,0x00,0x80,0x26,0x2a,0x55,0x5d,0x00}},
+	{{0xc3,0x7f,0xb7,0x7a,0x84,0x40,0x02,0x5a,0x05,0x00,0x80,0x1f,0x84,0x3d,0x28,0x00}},
+	{{0xe5,0x7f,0xb7,0x1d,0xa7,0x3e,0x04,0x5a,0x05,0x00,0x80,0x20,0x3e,0xe4,0x22,0x00}}
+};
+
+static const SiS310_CHTVRegDataStruct SiS310_CHTVReg_OPAL[] = {
+	{{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x41,0x7f,0xb7,0x36,0xad,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x41,0x7f,0xb7,0x86,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01}},
+	{{0x61,0x7f,0xb7,0x99,0x84,0x35,0x04,0x5a,0x05,0x00,0x80,0x26,0x2a,0x55,0x5d,0x00}},
+	{{0xc1,0x7f,0xb7,0x4d,0x8c,0x1e,0x31,0x5a,0x05,0x00,0x80,0x26,0x78,0x19,0x34,0x00}},
+	{{0xe4,0x7f,0xb7,0x1e,0xaf,0x29,0x37,0x5a,0x05,0x00,0x80,0x25,0x8c,0xb2,0x2a,0x00}}
+};
 
-UCHAR SiS310_CHTVVCLKONTSC[]={0x00 };
+static const UCHAR SiS310_CHTVVCLKUNTSC[] = {0x41,0x41,0x41,0x41,0x42,0x46,0x53};
 
-UCHAR SiS310_CHTVVCLKUPAL[]={0x00 };
+static const UCHAR SiS310_CHTVVCLKONTSC[] = {0x48,0x48,0x48,0x48,0x45,0x43,0x51};
 
-UCHAR SiS310_CHTVVCLKOPAL[]={0x00 };
+static const UCHAR SiS310_CHTVVCLKUPAL[]  = {0x47,0x47,0x47,0x47,0x48,0x4a,0x54};
 
+static const UCHAR SiS310_CHTVVCLKOPAL[]  = {0x47,0x47,0x47,0x47,0x48,0x4f,0x52};
+/* TW: New end */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/sis/325vtbl.h linux.20pre10-ac2/drivers/video/sis/325vtbl.h
--- linux.20pre10/drivers/video/sis/325vtbl.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/sis/325vtbl.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,2323 +0,0 @@
-typedef struct _SiS310_StStruct
-{
- UCHAR St_ModeID;
- USHORT St_ModeFlag;
- UCHAR St_StTableIndex;
- UCHAR St_CRT2CRTC;
- UCHAR St_ResInfo;
- UCHAR VB_StTVFlickerIndex;
- UCHAR VB_StTVEdgeIndex;
- UCHAR VB_StTVYFilterIndex;
-} SiS310_StStruct;
-SiS310_StStruct SiS310_SModeIDTable[]=
-{ {0x01,0x9208,0x01,0x00,0x00,0x00,0x01,0x00},
- {0x01,0x1210,0x14,0x01,0x01,0x00,0x01,0x00},
- {0x01,0x1010,0x17,0x02,0x02,0x00,0x01,0x01},
- {0x03,0x8208,0x03,0x00,0x00,0x00,0x01,0x02},
- {0x03,0x0210,0x16,0x01,0x01,0x00,0x01,0x02},
- {0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03},
- {0x05,0x9209,0x05,0x00,0x00,0x00,0x00,0x04},
- {0x06,0x8209,0x06,0x00,0x00,0x00,0x00,0x05},
- {0x07,0x0000,0x07,0x03,0x03,0x00,0x01,0x03},
- {0x07,0x0000,0x19,0x02,0x02,0x00,0x01,0x03},
- {0x0d,0x920a,0x0d,0x00,0x00,0x00,0x00,0x04},
- {0x0e,0x820a,0x0e,0x00,0x00,0x00,0x00,0x05},
- {0x0f,0x0202,0x11,0x01,0x01,0x00,0x00,0x05},
- {0x10,0x0212,0x12,0x01,0x01,0x00,0x00,0x05},
- {0x11,0x0212,0x1a,0x04,0x04,0x00,0x00,0x05},
- {0x12,0x0212,0x1b,0x04,0x04,0x00,0x00,0x05},
- {0x13,0x021b,0x1c,0x00,0x00,0x00,0x00,0x04},
- {0x12,0x0010,0x18,0x02,0x02,0x00,0x00,0x05},
- {0x12,0x0210,0x18,0x01,0x01,0x00,0x00,0x05},
- {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00}
-};
-
-typedef struct _SiS310_StandTableStruct
-{
- UCHAR CRT_COLS;
- UCHAR ROWS;
- UCHAR CHAR_HEIGHT;
- USHORT CRT_LEN;
- UCHAR SR[4];
- UCHAR MISC;
- UCHAR CRTC[0x19];
- UCHAR ATTR[0x14];
- UCHAR GRC[9];
-} SiS310_StandTableStruct;
-SiS310_StandTableStruct SiS310_StandTable[]=
-{
-/* MD_0_200 */
- {
-  0x28,0x18,0x08,0x0800,
-  {0x09,0x03,0x00,0x02},
-  0x63,
-  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
-   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
-   0x08,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_1_200 */
- {
-  0x28,0x18,0x08,0x0800,
-  {0x09,0x03,0x00,0x02},
-  0x63,
-  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
-   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
-   0x08,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_2_200 */
- {
-  0x50,0x18,0x08,0x1000,
-  {0x01,0x03,0x00,0x02},
-  0x63,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
-   0x08,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_3_200 */
- {
-  0x50,0x18,0x08,0x1000,
-  {0x01,0x03,0x00,0x02},
-  0x63,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
-   0x08,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_4 */
- {
-  0x28,0x18,0x08,0x4000,
-  {0x09,0x03,0x00,0x02},
-  0x63,
-  {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
-   0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2,
-   0xff},
-  {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07,
-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
-   0x01,0x00,0x03,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00,
-   0xff}
- },
-/* MD_5 */
- {
-  0x28,0x18,0x08,0x4000,
-  {0x09,0x03,0x00,0x02},
-  0x63,
-  {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
-   0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2,
-   0xff},
-  {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07,
-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
-   0x01,0x00,0x03,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00,
-   0xff}
- },
-/* MD_6 */
- {
-  0x50,0x18,0x08,0x4000,
-  {0x01,0x01,0x00,0x06},
-  0x63,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xc2,
-   0xff},
-  {0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
-   0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
-   0x01,0x00,0x01,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x00,
-   0xff}
- },
-/* MD_7 */
- {
-  0x50,0x18,0x0e,0x1000,
-  {0x00,0x03,0x00,0x03},
-  0xa6,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
-   0x83,0x85,0x5d,0x28,0x0d,0x63,0xba,0xa3,
-   0xff},
-  {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
-   0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-   0x0e,0x00,0x0f,0x08},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00,
-   0xff}
- },
-/* MDA_DAC */
- {
-  0x00,0x00,0x00,0x0000,
-  {0x00,0x00,0x00,0x15},
-  0x15,
-  {0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-   0x15,0x15,0x15,0x15,0x15,0x15,0x3f,0x3f,
-   0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x00,0x00,
-   0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x15,0x15,0x15,
-   0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-   0x15,0x15,0x15,0x15},
-  {0x15,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
-   0x3f}
- },
-/* CGA_DAC */
- {
-  0x00,0x10,0x04,0x0114,
-  {0x11,0x09,0x15,0x00},
-  0x10,
-  {0x04,0x14,0x01,0x11,0x09,0x15,0x2a,0x3a,
-   0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x2a,0x3a,
-   0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x10,
-   0x04},
-  {0x14,0x01,0x11,0x09,0x15,0x00,0x10,0x04,
-   0x14,0x01,0x11,0x09,0x15,0x2a,0x3a,0x2e,
-   0x3e,0x2b,0x3b,0x2f},
-  {0x3f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f,
-   0x3f}
- },
-/* EGA_DAC */
- {
-  0x00,0x10,0x04,0x0114,
-  {0x11,0x05,0x15,0x20},
-  0x30,
-  {0x24,0x34,0x21,0x31,0x25,0x35,0x08,0x18,
-   0x0c,0x1c,0x09,0x19,0x0d,0x1d,0x28,0x38,
-   0x2c,0x3c,0x29,0x39,0x2d,0x3d,0x02,0x12,
-   0x06},
-  {0x16,0x03,0x13,0x07,0x17,0x22,0x32,0x26,
-   0x36,0x23,0x33,0x27,0x37,0x0a,0x1a,0x0e,
-   0x1e,0x0b,0x1b,0x0f},
-  {0x1f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f,
-   0x3f}
- },
-/* VGA_DAC */
- {
-  0x00,0x10,0x04,0x0114,
-  {0x11,0x09,0x15,0x2a},
-  0x3a,
-  {0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x05,
-   0x08,0x0b,0x0e,0x11,0x14,0x18,0x1c,0x20,
-   0x24,0x28,0x2d,0x32,0x38,0x3f,0x00,0x10,
-   0x1f},
-  {0x2f,0x3f,0x1f,0x27,0x2f,0x37,0x3f,0x2d,
-   0x31,0x36,0x3a,0x3f,0x00,0x07,0x0e,0x15,
-   0x1c,0x0e,0x11,0x15},
-  {0x18,0x1c,0x14,0x16,0x18,0x1a,0x1c,0x00,
-   0x04}
- },
- {
-  0x08,0x0c,0x10,0x0a08,
-  {0x0c,0x0e,0x10,0x0b},
-  0x0c,
-  {0x0d,0x0f,0x10,0x10,0x01,0x08,0x00,0x00,
-   0x00,0x00,0x01,0x00,0x02,0x02,0x01,0x00,
-   0x04,0x04,0x01,0x00,0x05,0x02,0x05,0x00,
-   0x06},
-  {0x01,0x06,0x05,0x06,0x00,0x08,0x01,0x08,
-   0x00,0x07,0x02,0x07,0x06,0x07,0x00,0x00,
-   0x00,0x00,0x00,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x00}
- },
-/* MD_D */
- {
-  0x28,0x18,0x08,0x2000,
-  {0x09,0x0f,0x00,0x06},
-  0x63,
-  {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
-   0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xe3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
-   0x01,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
-   0xff}
- },
-/* MD_E */
- {
-  0x50,0x18,0x08,0x4000,
-  {0x01,0x0f,0x00,0x06},
-  0x63,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xe3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-   0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
-   0x01,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
-   0xff}
- },
-/* ExtVGATable */
- {
-  0x00,0x00,0x00,0x0000,
-  {0x01,0x0f,0x00,0x0e},
-  0x23,
-  {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
-   0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-   0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
-   0x01,0x00,0x00,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
-   0xff}
- },
-/* ROM_SAVEPTR */
- {
-  0x9f,0x3b,0x00,0x00c0,
-  {0x00,0x00,0x00,0x00},
-  0x00,
-  {0x00,0x00,0x00,0x00,0x00,0x00,0xbb,0x3f,
-   0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x00,0x00,0x1a,0x00,0xac,0x3e,0x00,0xc0,
-   0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x00,0x00,0x00,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x00}
- },
-/* MD_F */
- {
-  0x50,0x18,0x0e,0x8000,
-  {0x01,0x0f,0x00,0x06},
-  0xa2,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x82,0x84,0x5d,0x28,0x0f,0x63,0xba,0xe3,
-   0xff},
-  {0x00,0x08,0x00,0x00,0x18,0x18,0x00,0x00,
-   0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00,
-   0x0b,0x00,0x05,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x05,
-   0xff}
- },
-/* MD_10 */
- {
-  0x50,0x18,0x0e,0x8000,
-  {0x01,0x0f,0x00,0x06},
-  0xa3,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x82,0x84,0x5d,0x28,0x0f,0x63,0xba,0xe3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-   0x01,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
-   0xff}
- },
-/* MD_0_350 */
- {
-  0x28,0x18,0x0e,0x0800,
-  {0x09,0x03,0x00,0x02},
-  0xa3,
-  {0x2d,0x27,0x28,0x90,0x2b,0xb1,0xbf,0x1f,
-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
-   0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-   0x08,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_1_350 */
- {
-  0x28,0x18,0x0e,0x0800,
-  {0x09,0x03,0x00,0x02},
-  0xa3,
-  {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
-   0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-   0x08,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_2_350 */
- {
-  0x50,0x18,0x0e,0x1000,
-  {0x01,0x03,0x00,0x02},
-  0xa3,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
-   0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-   0x08,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_3_350 */
- {
-  0x50,0x18,0x0e,0x1000,
-  {0x01,0x03,0x00,0x02},
-  0xa3,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
-   0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-   0x08,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_0_1_400 */
- {
-  0x28,0x18,0x10,0x0800,
-  {0x08,0x03,0x00,0x02},
-  0x67,
-  {0x2d,0x27,0x28,0x90,0x2b,0xb1,0xbf,0x1f,
-   0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-   0x0c,0x00,0x0f,0x08},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_2_3_400 */
- {
-  0x50,0x18,0x10,0x1000,
-  {0x00,0x03,0x00,0x02},
-  0x67,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-   0x0c,0x00,0x0f,0x08},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-   0xff}
- },
-/* MD_7_400 */
- {
-  0x50,0x18,0x10,0x1000,
-  {0x00,0x03,0x00,0x02},
-  0x66,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x28,0x0f,0x96,0xb9,0xa3,
-   0xff},
-  {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
-   0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-   0x0e,0x00,0x0f,0x08},
-  {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00,
-   0xff}
- },
-/* MD_11 */
- {
-  0x50,0x1d,0x10,0xa000,
-  {0x01,0x0f,0x00,0x06},
-  0xe3,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,
-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
-   0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xc3,
-   0xff},
-  {0x00,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
-   0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
-   0x01,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x01,
-   0xff}
- },
-/* ExtEGATable */
- {
-  0x50,0x1d,0x10,0xa000,
-  {0x01,0x0f,0x00,0x06},
-  0xe3,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,
-   0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
-   0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xe3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-   0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-   0x01,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
-   0xff}
- },
-/* MD_13 */
- {
-  0x28,0x18,0x08,0x2000,
-  {0x01,0x0f,0x00,0x0e},
-  0x63,
-  {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,
-   0x9c,0x8e,0x8f,0x28,0x40,0x96,0xb9,0xa3,
-   0xff},
-  {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-   0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
-   0x41,0x00,0x0f,0x00},
-  {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
-   0xff}
- }
-};
-
-typedef struct _SiS310_ExtStruct
-{
- UCHAR Ext_ModeID;
- USHORT Ext_ModeFlag;
- USHORT Ext_ModeInfo;
- USHORT Ext_Point;
- USHORT Ext_VESAID;
- UCHAR Ext_VESAMEMSize;
- UCHAR Ext_RESINFO;
- UCHAR VB_ExtTVFlickerIndex;
- UCHAR VB_ExtTVEdgeIndex;
- UCHAR VB_ExtTVYFilterIndex;
- UCHAR REFindex;
-} SiS310_ExtStruct;
-SiS310_ExtStruct  SiS310_EModeIDTable[]=
-{
- {0x6a,0x2212,0x0407,0x3a81,0x0102,0x08,0x07,0x00,0x00,0x07,0x00},
- {0x2e,0x0a1b,0x0306,0x3a57,0x0101,0x08,0x06,0x00,0x00,0x05,0x08},
- {0x2f,0x0a1b,0x0305,0x3a50,0x0100,0x08,0x05,0x00,0x00,0x05,0x10},
- {0x30,0x2a1b,0x0407,0x3a81,0x0103,0x08,0x07,0x00,0x00,0x07,0x00},
- {0x31,0x0a1b,0x030d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},
- {0x32,0x0a1b,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},
- {0x33,0x0a1d,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},
- {0x34,0x2a1d,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},
- {0x35,0x0a1f,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x11},
- {0x36,0x2a1f,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x12},
- {0x37,0x0212,0x0508,0x3aab,0x0104,0x08,0x08,0x00,0x00,0x00,0x13},
- {0x38,0x0a1b,0x0508,0x3aab,0x0105,0x08,0x08,0x00,0x00,0x00,0x13},
- {0x3a,0x0e3b,0x0609,0x3adc,0x0107,0x08,0x09,0x00,0x00,0x00,0x1a},
- {0x3c,0x063b,0x070a,0x3af2,0x0130,0x08,0x0a,0x00,0x00,0x00,0x1e},
- {0x3d,0x067d,0x070a,0x3af2,0x0131,0x08,0x0a,0x00,0x00,0x00,0x1e},
- {0x40,0x9a1c,0x0000,0x3a34,0x010d,0x08,0x00,0x00,0x00,0x04,0x25},
- {0x41,0x9a1d,0x0000,0x3a34,0x010e,0x08,0x00,0x00,0x00,0x04,0x25},
- {0x43,0x0a1c,0x0306,0x3a57,0x0110,0x08,0x06,0x00,0x00,0x05,0x08},
- {0x44,0x0a1d,0x0306,0x3a57,0x0111,0x08,0x06,0x00,0x00,0x05,0x08},
- {0x46,0x2a1c,0x0407,0x3a81,0x0113,0x08,0x07,0x00,0x00,0x07,0x00},
- {0x47,0x2a1d,0x0407,0x3a81,0x0114,0x08,0x07,0x00,0x00,0x07,0x00},
- {0x49,0x0a3c,0x0508,0x3aab,0x0116,0x08,0x08,0x00,0x00,0x00,0x13},
- {0x4a,0x0a3d,0x0508,0x3aab,0x0117,0x08,0x08,0x00,0x00,0x00,0x13},
- {0x4c,0x0e7c,0x0609,0x3adc,0x0119,0x08,0x09,0x00,0x00,0x00,0x1a},
- {0x4d,0x0e7d,0x0609,0x3adc,0x011a,0x08,0x09,0x00,0x00,0x00,0x1a},
- {0x50,0x9a1b,0x0001,0x3a3b,0x0132,0x08,0x01,0x00,0x00,0x04,0x26},
- {0x51,0xba1b,0x0103,0x3a42,0x0133,0x08,0x03,0x00,0x00,0x07,0x27},
- {0x52,0x9a1b,0x0204,0x3a49,0x0134,0x08,0x04,0x00,0x00,0x00,0x28},
- {0x56,0x9a1d,0x0001,0x3a3b,0x0135,0x08,0x01,0x00,0x00,0x04,0x26},
- {0x57,0xba1d,0x0103,0x3a42,0x0136,0x08,0x03,0x00,0x00,0x07,0x27},
- {0x58,0x9a1d,0x0204,0x3a49,0x0137,0x08,0x04,0x00,0x00,0x00,0x28},
- {0x59,0x9a1b,0x0000,0x3a34,0x0138,0x08,0x00,0x00,0x00,0x04,0x25},
- {0x5d,0x0a1d,0x0305,0x3a50,0x0139,0x08,0x05,0x00,0x00,0x07,0x10},
- {0x62,0x0a3f,0x0306,0x3a57,0x013a,0x08,0x06,0x00,0x00,0x05,0x08},
- {0x63,0x2a3f,0x0407,0x3a81,0x013b,0x08,0x07,0x00,0x00,0x07,0x00},
- {0x64,0x0a7f,0x0508,0x3aab,0x013c,0x08,0x08,0x00,0x00,0x00,0x13},
- {0x65,0x0eff,0x0609,0x3adc,0x013d,0x08,0x09,0x00,0x00,0x00,0x1a},
- {0x66,0x06ff,0x070a,0x3af2,0x013e,0x08,0x0a,0x00,0x00,0x00,0x1e},
- {0x68,0x067b,0x080b,0x3b17,0x013f,0x08,0x0b,0x00,0x00,0x00,0x29},
- {0x69,0x06fd,0x080b,0x3b17,0x0140,0x08,0x0b,0x00,0x00,0x00,0x29},
- {0x6b,0x07ff,0x080b,0x3b17,0x0141,0x10,0x0b,0x00,0x00,0x00,0x29},
- {0x6c,0x067b,0x090c,0x3b37,0x0000,0x08,0x0c,0x00,0x00,0x00,0x2f},
- {0x6d,0x06fd,0x090c,0x3b37,0x0000,0x10,0x0c,0x00,0x00,0x00,0x2f},
- {0x6e,0x07ff,0x090c,0x3b37,0x0000,0x10,0x0c,0x00,0x00,0x00,0x2f},
- {0x70,0x2a1b,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},
- {0x71,0x0a1b,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},
- {0x74,0x0a1d,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},
- {0x75,0x0a3d,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},
- {0x76,0x2a1f,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},
- {0x77,0x0a1f,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},
- {0x78,0x0a3f,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},
- {0x79,0x0a3b,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},
- {0x7a,0x2a1d,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},
- {0x7b,0x0e3b,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},
- {0x7c,0x0e7d,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},
- {0x7d,0x0eff,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x3d},
- {0xff,0x0000,0x0000,0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00}
-};
-
-typedef struct _SiS310_Ext2Struct
-{
- USHORT Ext_InfoFlag;
- UCHAR Ext_CRT1CRTC;
- UCHAR Ext_CRTVCLK;
- UCHAR Ext_CRT2CRTC;
- UCHAR  ModeID;
- USHORT XRes;
- USHORT YRes;
- USHORT ROM_OFFSET;
-} SiS310_Ext2Struct;
-SiS310_Ext2Struct SiS310_RefIndex[]=
-{
- {0x005f,0x0d,0x03,0x05,0x6a, 800, 600,0x3a81}, /* 0x0 */
- {0x0467,0x0e,0x04,0x05,0x6a, 800, 600,0x3a86}, /* 0x1 */
- {0x0067,0x0f,0x08,0x48,0x6a, 800, 600,0x3a8b}, /* 0x2 */
- {0x0067,0x10,0x07,0x8b,0x6a, 800, 600,0x3a90}, /* 0x3 */
- {0x0147,0x11,0x0a,0x00,0x6a, 800, 600,0x3a95}, /* 0x4 */
- {0x4147,0x12,0x0d,0x00,0x6a, 800, 600,0x3a9a}, /* 0x5 */
- {0x4047,0x13,0x13,0x00,0x6a, 800, 600,0x3a9f}, /* 0x6 */
- {0x4047,0x14,0x1c,0x00,0x6a, 800, 600,0x3aa4}, /* 0x7 */
- {0xc05f,0x05,0x00,0x04,0x2e, 640, 480,0x3a57}, /* 0x8 */
- {0xc067,0x06,0x02,0x04,0x2e, 640, 480,0x3a5c}, /* 0x9 */
- {0xc067,0x07,0x02,0x47,0x2e, 640, 480,0x3a61}, /* 0xa */
- {0xc067,0x08,0x03,0x8a,0x2e, 640, 480,0x3a66}, /* 0xb */
- {0x4047,0x09,0x05,0x00,0x2e, 640, 480,0x3a6b}, /* 0xc */
- {0x4047,0x0a,0x09,0x00,0x2e, 640, 480,0x3a70}, /* 0xd */
- {0x4047,0x0b,0x0e,0x00,0x2e, 640, 480,0x3a75}, /* 0xe */
- {0xc047,0x0c,0x15,0x00,0x2e, 640, 480,0x3a7a}, /* 0xf */
- {0x407f,0x04,0x00,0x00,0x2f, 640, 400,0x3a50}, /* 0x10 */
- {0xc00f,0x3c,0x01,0x06,0x31, 720, 480,0x3b85}, /* 0x11 */
- {0x000f,0x3d,0x03,0x06,0x32, 720, 576,0x3b8c}, /* 0x12 */
- {0x0187,0x15,0x06,0x00,0x37,1024, 768,0x3aab}, /* 0x13 */
- {0xc877,0x16,0x0b,0x06,0x37,1024, 768,0x3ab0}, /* 0x14 301b TV1024x768*/
- {0xc067,0x17,0x0f,0x49,0x37,1024, 768,0x3ab5}, /* 0x15 */
- {0x0267,0x18,0x11,0x00,0x37,1024, 768,0x3aba}, /* 0x16 */
- {0x0047,0x19,0x16,0x8c,0x37,1024, 768,0x3abf}, /* 0x17 */
- {0x4047,0x1a,0x1b,0x00,0x37,1024, 768,0x3ac4}, /* 0x18 */
- {0x4047,0x1b,0x1f,0x00,0x37,1024, 768,0x3ac9}, /* 0x19 */
- {0x0387,0x1c,0x11,0x00,0x3a,1280,1024,0x3adc}, /* 0x1a */
- {0x0077,0x1d,0x19,0x07,0x3a,1280,1024,0x3ae1}, /* 0x1b */
- {0x0047,0x1e,0x1e,0x00,0x3a,1280,1024,0x3ae6}, /* 0x1c */
- {0x0007,0x1f,0x20,0x00,0x3a,1280,1024,0x3aeb}, /* 0x1d */
- {0x0007,0x20,0x21,0x00,0x3c,1600,1200,0x3af2}, /* 0x1e */
- {0x0007,0x21,0x22,0x00,0x3c,1600,1200,0x3af7}, /* 0x1f */
- {0x0007,0x22,0x23,0x00,0x3c,1600,1200,0x3afc}, /* 0x20 */
- {0x0007,0x23,0x25,0x00,0x3c,1600,1200,0x3b01}, /* 0x21 */
- {0x0007,0x24,0x26,0x00,0x3c,1600,1200,0x3b06}, /* 0x22 */
- {0x0007,0x25,0x2c,0x00,0x3c,1600,1200,0x3b0b}, /* 0x23 */
- {0x0007,0x26,0x34,0x00,0x3c,1600,1200,0x3b10}, /* 0x24 */
- {0x407f,0x00,0x00,0x00,0x40, 320, 200,0x3a34}, /* 0x25 */
- {0xc07f,0x01,0x00,0x04,0x50, 320, 240,0x3a3b}, /* 0x26 */
- {0x007f,0x02,0x04,0x05,0x51, 400, 300,0x3a42}, /* 0x27 */
- {0xc077,0x03,0x0b,0x06,0x52, 512, 384,0x3a49}, /* 0x28 */
- {0x8007,0x27,0x27,0x00,0x68,1920,1440,0x3b17}, /* 0x29 */
- {0x4007,0x28,0x29,0x00,0x68,1920,1440,0x3b1c}, /* 0x2a */
- {0x4007,0x29,0x2e,0x00,0x68,1920,1440,0x3b21}, /* 0x2b */
- {0x4007,0x2a,0x30,0x00,0x68,1920,1440,0x3b26}, /* 0x2c */
- {0x4007,0x2b,0x35,0x00,0x68,1920,1440,0x3b2b}, /* 0x2d */
- {0x4005,0x2c,0x39,0x00,0x68,1920,1440,0x3b30}, /* 0x2e */
- {0x4007,0x2d,0x2b,0x00,0x6c,2048,1536,0x3b37}, /* 0x2f */
- {0x4007,0x2e,0x31,0x00,0x6c,2048,1536,0x3b3c}, /* 0x30 */
- {0x4007,0x2f,0x33,0x00,0x6c,2048,1536,0x3b41}, /* 0x31 */
- {0x4007,0x30,0x37,0x00,0x6c,2048,1536,0x3b46}, /* 0x32 */
- {0x4005,0x31,0x38,0x00,0x6c,2048,1536,0x3b4b}, /* 0x33 */
- {0x0057,0x32,0x40,0x08,0x70, 800, 480,0x3b52}, /* 0x34 */
- {0x0047,0x33,0x07,0x08,0x70, 800, 480,0x3b57}, /* 0x35 */
- {0x0047,0x34,0x0a,0x08,0x70, 800, 480,0x3b5c}, /* 0x36 */
- {0x0057,0x35,0x0b,0x09,0x71,1024, 576,0x3b63}, /* 0x37 */
- {0x0047,0x36,0x11,0x09,0x71,1024, 576,0x3b68}, /* 0x38 */
- {0x0047,0x37,0x16,0x09,0x71,1024, 576,0x3b6d}, /* 0x39 */
- {0x0057,0x38,0x19,0x0a,0x75,1280, 720,0x3b74}, /* 0x3a */
- {0x0047,0x39,0x1e,0x0a,0x75,1280, 720,0x3b79}, /* 0x3b */
- {0x0047,0x3a,0x20,0x0a,0x75,1280, 720,0x3b7e}, /* 0x3c */
- {0x0027,0x3b,0x19,0x08,0x7b,1280, 960,0x3ad0}, /* 0x3d */
- {0x0027,0x3b,0x19,0x08,0x7b,1280, 960,0x3ad5}, /* 0x3e */
- {0xffff,0x00,0x00,0x00,0x00,0000,0000,0x0000}
-};
-
-typedef struct _SiS310_CRT1TableStruct
-{
- UCHAR CR[17];
-} SiS310_CRT1TableStruct;
-SiS310_CRT1TableStruct SiS310_CRT1Table[]=
-{
- {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
-  0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
-  0x00}, /* 0x0 */
- {0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
-  0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
-  0x00}, /* 0x1 */
- {0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0,
-  0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05,
-  0x01}, /* 0x2 */
- {0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-  0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
-  0x01}, /* 0x3 */
- {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-  0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05,
-  0x00}, /* 0x4 */
- {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,
-  0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
-  0x00}, /* 0x5 */
- {0x63,0x4f,0x50,0x86,0x56,0x9b,0x06,0x3e,
-  0xe8,0x8b,0xdf,0xe7,0xff,0x10,0x00,0x01,
-  0x00}, /* 0x6 */
- {0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f,
-  0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01,
-  0x00}, /* 0x7 */
- {0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f,
-  0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
-  0x00}, /* 0x8 */
- {0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f,
-  0xe0,0x83,0xdf,0xdf,0xfc,0x00,0x00,0x05,
-  0x61}, /* 0x9 */
- {0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e,
-  0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05,
-  0x61}, /* 0xa */
- {0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e,
-  0xe0,0x83,0xdf,0xdf,0x0e,0x10,0x00,0x05,
-  0x61}, /* 0xb */
- {0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f,
-  0xe6,0x8a,0xe5,0xe5,0xfc,0x00,0x00,0x01,
-  0x00}, /* 0xc */
- {0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
-  0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05,
-  0x01}, /* 0xd */
- {0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0,
-  0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06,
-  0x01}, /* 0xe */
- {0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0,
-  0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06,
-  0x01}, /* 0xf */
- {0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0,
-  0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06,
-  0x01}, /* 0x10 */
- {0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0,
-  0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06,
-  0x01}, /* 0x11 */
- {0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0,
-  0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06,
-  0x61}, /* 0x12 */
- {0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0,
-  0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06,
-  0x61}, /* 0x13 */
- {0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0,
-  0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06,
-  0x61}, /* 0x14 */
- {0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f,
-  0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02,
-  0x00}, /* 0x15 */
- {0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
-  0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-  0x01}, /* 0x16 */
- {0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5,
-  0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-  0x01}, /* 0x17 */
- {0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5,
-  0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02,
-  0x01}, /* 0x18 */
- {0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5,
-  0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02,
-  0x01}, /* 0x19 */
- {0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5,
-  0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02,
-  0x62}, /* 0x1a */
- {0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5,
-  0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02,
-  0x62}, /* 0x1b */
- {0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba,
-  0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03,
-  0x00}, /* 0x1c */
- {0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a,
-  0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
-  0x01}, /* 0x1d */
- {0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a,
-  0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
-  0x01}, /* 0x1e */
- {0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a,
-  0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07,
-  0x01}, /* 0x1f */
- {0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}, /* 0x20 */
- {0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}, /* 0x21 */
- {0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}, /* 0x22 */
- {0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}, /* 0x23 */
- {0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}, /* 0x24 */
- {0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}, /* 0x25 */
- {0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-  0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-  0x00}, /* 0x26 */
- {0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-  0x00}, /* 0x27 */
- {0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05,
-  0x63}, /* 0x28 */
- {0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05,
-  0x63}, /* 0x29 */
- {0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-  0x00}, /* 0x2a */
- {0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-  0x00}, /* 0x2b */
- {0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-  0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-  0x00}, /* 0x2c */
- {0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba,
-  0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05,
-  0x44}, /* 0x2d */
- {0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba,
-  0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05,
-  0x44}, /* 0x2e */
- {0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba,
-  0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05,
-  0x44}, /* 0x2f */
- {0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba,
-  0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05,
-  0x44}, /* 0x30 */
- {0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba,
-  0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05,
-  0x00}, /* 0x31 */
- {0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,
-  0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
-  0x01}, /* 0x32 */
- {0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba,
-  0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06,
-  0x01}, /* 0x33 */
- {0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba,
-  0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06,
-  0x01}, /* 0x34 */
- {0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1,
-  0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02,
-  0x01}, /* 0x35 */
- {0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1,
-  0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
-  0x01}, /* 0x36 */
- {0xa7,0x7f,0x7f,0x88,0x89,0x15,0x26,0xf1,
-  0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
-  0x01}, /* 0x37 */
- {0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4,
-  0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
-  0x01}, /* 0x38 */
- {0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4,
-  0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
-  0x01}, /* 0x39 */
- {0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4,
-  0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07,
-  0x01}, /* 0x3a */
- {0xdc,0x9f,0x9f,0x00,0xab,0x19,0xe6,0xef,
-  0xc0,0xc3,0xbf,0xbf,0xe7,0x10,0x00,0x07,
-  0x01}, /* 0x3b */
- {0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e,
-  0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
-  0x00}, /* 0x3c */
- {0x7b,0x59,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
-  0x58,0x8a,0x3f,0x57,0x70,0x20,0x00,0x05,
-  0x01} /* 0x3d */
-};
-
-typedef struct _SiS310_MCLKDataStruct
-{
- UCHAR SR28,SR29,SR2A;
- USHORT CLOCK;
-} SiS310_MCLKDataStruct;
-SiS310_MCLKDataStruct SiS310_MCLKData[]=
-{
- { 0x5c,0x23,0x01,166},
- { 0x5c,0x23,0x01,166},
- { 0x5c,0x23,0x01,166},
- { 0x5c,0x23,0x01,166}
-};
-
-typedef struct _SiS310_ECLKDataStruct
-{
- UCHAR SR2E,SR2F,SR30;
- USHORT CLOCK;
-} SiS310_ECLKDataStruct;
-SiS310_ECLKDataStruct SiS310_ECLKData[]=
-{
- { 0x5c,0x23,0x01,166},
- { 0x5c,0x23,0x01,166},
- { 0x5c,0x23,0x01,166},
- { 0x5c,0x23,0x01,166}
-};
-
-typedef struct _SiS310_VCLKDataStruct
-{
- UCHAR SR2B,SR2C;
- USHORT CLOCK;
-} SiS310_VCLKDataStruct;
-SiS310_VCLKDataStruct SiS310_VCLKData[]=
-{
- { 0x1b,0xe1, 25}, /* 0x0 */
- { 0x4e,0xe4, 28}, /* 0x1 */
- { 0x57,0xe4, 31}, /* 0x2 */
- { 0xc3,0xc8, 36}, /* 0x3 */
- { 0x42,0xe2, 40}, /* 0x4 */
- { 0xfe,0xcd, 43}, /* 0x5 */
- { 0x5d,0xc4, 44}, /* 0x6 */
- { 0x52,0xe2, 49}, /* 0x7 */
- { 0x53,0xe2, 50}, /* 0x8 */
- { 0x74,0x67, 52}, /* 0x9 */
- { 0x6d,0x66, 56}, /* 0xa */
- { 0x6c,0xc3, 65}, /* 0xb */
- { 0x46,0x44, 67}, /* 0xc */
- { 0xb1,0x46, 68}, /* 0xd */
- { 0xd3,0x4a, 72}, /* 0xe */
- { 0x29,0x61, 75}, /* 0xf */
- { 0x6e,0x46, 76}, /* 0x10 */
- { 0x2b,0x61, 78}, /* 0x11 */
- { 0x31,0x42, 79}, /* 0x12 */
- { 0xab,0x44, 83}, /* 0x13 */
- { 0x46,0x25, 84}, /* 0x14 */
- { 0x78,0x29, 86}, /* 0x15 */
- { 0x62,0x44, 94}, /* 0x16 */
- { 0x2b,0x41,104}, /* 0x17 */
- { 0x3a,0x23,105}, /* 0x18 */
- { 0x70,0x44,108}, /* 0x19 */
- { 0x3c,0x23,109}, /* 0x1a */
- { 0x5e,0x43,113}, /* 0x1b */
- { 0xbc,0x44,116}, /* 0x1c */
- { 0xe0,0x46,132}, /* 0x1d */
- { 0x54,0x42,135}, /* 0x1e */
- { 0xea,0x2a,139}, /* 0x1f */
- { 0x41,0x22,157}, /* 0x20 */
- { 0x70,0x24,162}, /* 0x21 */
- { 0x30,0x21,175}, /* 0x22 */
- { 0x4e,0x22,189}, /* 0x23 */
- { 0xde,0x26,194}, /* 0x24 */
- { 0x62,0x06,202}, /* 0x25 */
- { 0x3f,0x03,229}, /* 0x26 */
- { 0xb8,0x06,234}, /* 0x27 */
- { 0x34,0x02,253}, /* 0x28 */
- { 0x58,0x04,255}, /* 0x29 */
- { 0x24,0x01,265}, /* 0x2a */
- { 0x9b,0x02,267}, /* 0x2b */
- { 0x70,0x05,270}, /* 0x2c */
- { 0x25,0x01,272}, /* 0x2d */
- { 0x9c,0x02,277}, /* 0x2e */
- { 0x27,0x01,286}, /* 0x2f */
- { 0x3c,0x02,291}, /* 0x30 */
- { 0xef,0x0a,292}, /* 0x31 */
- { 0xf6,0x0a,310}, /* 0x32 */
- { 0x95,0x01,315}, /* 0x33 */
- { 0xf0,0x09,324}, /* 0x34 */
- { 0xfe,0x0a,331}, /* 0x35 */
- { 0xf3,0x09,332}, /* 0x36 */
- { 0xea,0x08,340}, /* 0x37 */
- { 0xe8,0x07,376}, /* 0x38 */
- { 0xde,0x06,389}, /* 0x39 */
- { 0x52,0x2a, 54}, /* 0x3a */
- { 0x52,0x6a, 27}, /* 0x3b */
- { 0x62,0x24, 70}, /* 0x3c */
- { 0x62,0x64, 70}, /* 0x3d */
- { 0xa8,0x4c, 30}, /* 0x3e */
- { 0x20,0x26, 33}, /* 0x3f */
- { 0x31,0xc2, 39} /* 0x40 */
-};
-
-typedef struct _SiS310_VBVCLKDataStruct
-{
- UCHAR Part4_A,Part4_B;
- USHORT CLOCK;
-} SiS310_VBVCLKDataStruct;
-SiS310_VBVCLKDataStruct SiS310_VBVCLKData[]=
-{
- { 0x1b,0xe1, 25}, /* 0x0 */
- { 0x4e,0xe4, 28}, /* 0x1 */
- { 0x57,0xe4, 31}, /* 0x2 */
- { 0xc3,0xc8, 36}, /* 0x3 */
- { 0x42,0x47, 40}, /* 0x4 */
- { 0xfe,0xcd, 43}, /* 0x5 */
- { 0x5d,0xc4, 44}, /* 0x6 */
- { 0x52,0x47, 49}, /* 0x7 */
- { 0x53,0x47, 50}, /* 0x8 */
- { 0x74,0x67, 52}, /* 0x9 */
- { 0x6d,0x66, 56}, /* 0xa */
- { 0x5a,0x64, 65}, /* 0xb */
- { 0x46,0x44, 67}, /* 0xc */
- { 0xb1,0x46, 68}, /* 0xd */
- { 0xd3,0x4a, 72}, /* 0xe */
- { 0x29,0x61, 75}, /* 0xf */
- { 0x6d,0x46, 75}, /* 0x10 */
- { 0x41,0x43, 78}, /* 0x11 */
- { 0x31,0x42, 79}, /* 0x12 */
- { 0xab,0x44, 83}, /* 0x13 */
- { 0x46,0x25, 84}, /* 0x14 */
- { 0x78,0x29, 86}, /* 0x15 */
- { 0x62,0x44, 94}, /* 0x16 */
- { 0x2b,0x22,104}, /* 0x17 */
- { 0x49,0x24,105}, /* 0x18 */
- { 0xf8,0x2f,108}, /* 0x19 */
- { 0x3c,0x23,109}, /* 0x1a */
- { 0x5e,0x43,113}, /* 0x1b */
- { 0xbc,0x44,116}, /* 0x1c */
- { 0xe0,0x46,132}, /* 0x1d */
- { 0xd4,0x28,135}, /* 0x1e */
- { 0xea,0x2a,139}, /* 0x1f */
- { 0x41,0x22,157}, /* 0x20 */
- { 0x70,0x24,162}, /* 0x21 */
- { 0x30,0x21,175}, /* 0x22 */
- { 0x4e,0x22,189}, /* 0x23 */
- { 0xde,0x26,194}, /* 0x24 */
- { 0x70,0x07,202}, /* 0x25 */
- { 0x3f,0x03,229}, /* 0x26 */
- { 0xb8,0x06,234}, /* 0x27 */
- { 0x34,0x02,253}, /* 0x28 */
- { 0x58,0x04,255}, /* 0x29 */
- { 0x24,0x01,265}, /* 0x2a */
- { 0x9b,0x02,267}, /* 0x2b */
- { 0x70,0x05,270}, /* 0x2c */
- { 0x25,0x01,272}, /* 0x2d */
- { 0x9c,0x02,277}, /* 0x2e */
- { 0x27,0x01,286}, /* 0x2f */
- { 0x3c,0x02,291}, /* 0x30 */
- { 0xef,0x0a,292}, /* 0x31 */
- { 0xf6,0x0a,310}, /* 0x32 */
- { 0x95,0x01,315}, /* 0x33 */
- { 0xf0,0x09,324}, /* 0x34 */
- { 0xfe,0x0a,331}, /* 0x35 */
- { 0xf3,0x09,332}, /* 0x36 */
- { 0xea,0x08,340}, /* 0x37 */
- { 0xe8,0x07,376}, /* 0x38 */
- { 0xde,0x06,389}, /* 0x39 */
- { 0x52,0x2a, 54}, /* 0x3a */
- { 0x52,0x6a, 27}, /* 0x3b */
- { 0x62,0x24, 70}, /* 0x3c */
- { 0x62,0x64, 70}, /* 0x3d */
- { 0xa8,0x4c, 30}, /* 0x3e */
- { 0x20,0x26, 33}, /* 0x3f */
- { 0x31,0xc2, 39} /* 0x40 */
-};
-
-UCHAR SiS310_ScreenOffset[]={ 0x14,0x19,0x20,0x28,0x32,0x40,0x50,0x64,0x78,0x80,0x2d,0x35 };
-
-typedef struct _SiS310_StResInfoStruct
-{
- USHORT HTotal;
- USHORT VTotal;
-} SiS310_StResInfoStruct;
-SiS310_StResInfoStruct SiS310_StResInfo[]=
-{
- { 640,400},
- { 640,350},
- { 720,400},
- { 720,350},
- { 640,480}
-};
-
-typedef struct _SiS310_ModeResInfoStruct
-{
- USHORT HTotal;
- USHORT VTotal;
- UCHAR  XChar;
- UCHAR  YChar;
-} SiS310_ModeResInfoStruct;
-SiS310_ModeResInfoStruct SiS310_ModeResInfo[]=
-{
- {  320, 200, 8, 8},
- {  320, 240, 8, 8},
- {  320, 400, 8, 8},
- {  400, 300, 8, 8},
- {  512, 384, 8, 8},
- {  640, 400, 8,16},
- {  640, 480, 8,16},
- {  800, 600, 8,16},
- { 1024, 768, 8,16},
- { 1280,1024, 8,16},
- { 1600,1200, 8,16},
- { 1920,1440, 8,16},
- { 2048,1536, 8,16},
- {  720, 480, 8,16},
- {  720, 576, 8,16},
- { 1280, 960, 8,16},
- {  800, 480, 8,16},
- { 1024, 576, 8,16},
- { 1280, 720, 8,16}
-};
-
-UCHAR SiS310_OutputSelect = 0;
-UCHAR SiS310_SoftSetting = 30;
-UCHAR SiS310_SR07=0x18;
-UCHAR SiS310_SR15[8][4]={
-{0x0,0x4,0x60,0x60},
-{0xf,0xf,0xf,0xf},
-{0xba,0xba,0xba,0xba},
-{0xa9,0xa9,0xac,0xac},
-{0xa0,0xa0,0xa0,0xa8},
-{0x0,0x0,0x2,0x2},
-{0x30,0x30,0x40,0x40},
-{0x0,0xa5,0xfb,0xf6}
-};
-UCHAR SiS310_CR40[5][4]={
-{0x77,0x77,0x33,0x33},
-{0x77,0x77,0x33,0x33},
-{0x0,0x0,0x0,0x0},
-{0x5b,0x5b,0x3,0x3},
-{0x0,0x0,0xf0,0xf8}
-};
-UCHAR SiS310_CR49[]={0xaa,0x88};
-UCHAR SiS310_SR1F=0x0;
-UCHAR SiS310_SR21=0xa5;
-UCHAR SiS310_SR22=0xfb;
-UCHAR SiS310_SR23=0xf6;
-UCHAR SiS310_SR24=0xd;
-UCHAR SiS310_SR25[]={0x33,0x3};
-UCHAR SiS310_SR31=0x0;
-UCHAR SiS310_SR32=0x11;
-UCHAR SiS310_SR33=0x0;
-UCHAR SiS310_CRT2Data_1_2 = 0x0;
-UCHAR SiS310_CRT2Data_4_D = 0x0;
-UCHAR SiS310_CRT2Data_4_E = 0x0;
-UCHAR SiS310_CRT2Data_4_10 = 0x80;
-USHORT SiS310_RGBSenseData = 0xd1;
-USHORT SiS310_VideoSenseData = 0xb9;
-USHORT SiS310_YCSenseData = 0xb3;
-USHORT SiS310_RGBSenseData2 = 0x0190;     /*301b*/
-USHORT SiS310_VideoSenseData2 = 0x0174;
-USHORT SiS310_YCSenseData2 = 0x016b;
-UCHAR SiS310_NTSCPhase[] = {0x21,0xed,0x8a,0x8};
-
-UCHAR SiS310_PALPhase[] = {0x2a,0x5,0xd3,0x0};
-
-typedef struct _SiS310_LCDDataStruct
-{
- USHORT RVBHCMAX;
- USHORT RVBHCFACT;
- USHORT VGAHT;
- USHORT VGAVT;
- USHORT LCDHT;
- USHORT LCDVT;
-} SiS310_LCDDataStruct;
-SiS310_LCDDataStruct  SiS310_StLCD1024x768Data[]=
-{
- {   62,  25, 800, 546,1344, 806},
- {   32,  15, 930, 546,1344, 806},
- {   32,  15, 930, 546,1344, 806},
- {  104,  45, 945, 496,1344, 806},
- {   62,  25, 800, 546,1344, 806},
- {   31,  18,1008, 624,1344, 806},
- {    1,   1,1344, 806,1344, 806}
-};
-
-SiS310_LCDDataStruct  SiS310_ExtLCD1024x768Data[]=
-{
- {   12,   5, 896, 512,1344, 806},
- {   12,   5, 896, 510,1344, 806},
- {   32,  15,1008, 505,1344, 806},
- {   32,  15,1008, 514,1344, 806},
- {   12,   5, 896, 500,1344, 806},
- {   42,  25,1024, 625,1344, 806},
- {    1,   1,1344, 806,1344, 806},
- {   12,   5, 896, 500,1344, 806},
- {   42,  25,1024, 625,1344, 806},
- {    1,   1,1344, 806,1344, 806},
- {   12,   5, 896, 500,1344, 806},
- {   42,  25,1024, 625,1344, 806},
- {    1,   1,1344, 806,1344, 806}
-};
-
-SiS310_LCDDataStruct  SiS310_St2LCD1024x768Data[]=
-{
- {   62,  25, 800, 546,1344, 806},
- {   32,  15, 930, 546,1344, 806},
- {   32,  15, 930, 546,1344, 806},
- {  104,  45, 945, 496,1344, 806},
- {   62,  25, 800, 546,1344, 806},
- {   31,  18,1008, 624,1344, 806},
- {    1,   1,1344, 806,1344, 806}
-};
-
-SiS310_LCDDataStruct  SiS310_StLCD1280x1024Data[]=
-{
- {   22,   5, 800, 510,1650,1088},
- {   22,   5, 800, 510,1650,1088},
- {  176,  45, 900, 510,1650,1088},
- {  176,  45, 900, 510,1650,1088},
- {   22,   5, 800, 510,1650,1088},
- {   13,   5,1024, 675,1560,1152},
- {   16,   9,1266, 804,1688,1072},
- {    1,   1,1688,1066,1688,1066}
-};
-
-SiS310_LCDDataStruct  SiS310_ExtLCD1280x1024Data[]=
-{
- {  211,  60,1024, 501,1688,1066},
- {  211,  60,1024, 508,1688,1066},
- {  211,  60,1024, 501,1688,1066},
- {  211,  60,1024, 508,1688,1066},
- {  211,  60,1024, 500,1688,1066},
- {  211,  75,1024, 625,1688,1066},
- {  211, 120,1280, 798,1688,1066},
- {    1,   1,1688,1066,1688,1066}
-};
-
-SiS310_LCDDataStruct  SiS310_St2LCD1280x1024Data[]=
-{
- {   22,   5, 800, 510,1650,1088},
- {   22,   5, 800, 510,1650,1088},
- {  176,  45, 900, 510,1650,1088},
- {  176,  45, 900, 510,1650,1088},
- {   22,   5, 800, 510,1650,1088},
- {   13,   5,1024, 675,1560,1152},
- {   16,   9,1266, 804,1688,1072},
- {    1,   1,1688,1066,1688,1066}
-};
-
-SiS310_LCDDataStruct  SiS310_NoScaleData[]=
-{
- {    1,   1, 800, 449, 800, 449},
- {    1,   1, 800, 449, 800, 449},
- {    1,   1, 900, 449, 900, 449},
- {    1,   1, 900, 449, 900, 449},
- {    1,   1, 800, 525, 800, 525},
- {    1,   1,1056, 628,1056, 628},
- {    1,   1,1344, 806,1344, 806},
- {    1,   1,1688,1066,1688,1066}
-};
-
-SiS310_LCDDataStruct  SiS310_LCD1280x960Data[]=
-{
- {    9,   2, 800, 500,1800,1000},
- {    9,   2, 800, 500,1800,1000},
- {    4,   1, 900, 500,1800,1000},
- {    4,   1, 900, 500,1800,1000},
- {    9,   2, 800, 500,1800,1000},
- {   30,  11,1056, 625,1800,1000},
- {    5,   3,1350, 800,1800,1000},
- {    1,   1,1576,1050,1576,1050},
- {    1,   1,1800,1000,1800,1000}
-};
-
-typedef struct _SiS310_TVDataStruct
-{
- USHORT RVBHCMAX;
- USHORT RVBHCFACT;
- USHORT VGAHT;
- USHORT VGAVT;
- USHORT TVHDE;
- USHORT TVVDE;
- USHORT RVBHRS;
- UCHAR FlickerMode;
- USHORT HALFRVBHRS;
- UCHAR RY1COE;
- UCHAR RY2COE;
- UCHAR RY3COE;
- UCHAR RY4COE;
-} SiS310_TVDataStruct;
-SiS310_TVDataStruct  SiS310_StPALData[]=
-{
- {    1,   1, 864, 525,1270, 400, 100,   0, 760,0xf4,0xff,0x1c,0x22},
- {    1,   1, 864, 525,1270, 350, 100,   0, 760,0xf4,0xff,0x1c,0x22},
- {    1,   1, 864, 525,1270, 400,   0,   0, 720,0xf1,0x04,0x1f,0x18},
- {    1,   1, 864, 525,1270, 350,   0,   0, 720,0xf4,0x0b,0x1c,0x0a},
- {    1,   1, 864, 525,1270, 480,  50,   0, 760,0xf4,0xff,0x1c,0x22},
- {    1,   1, 864, 525,1270, 600,  50,   0,   0,0xf4,0xff,0x1c,0x22}
-};
-
-SiS310_TVDataStruct  SiS310_ExtPALData[]=
-{
- {   27,  10, 848, 448,1270, 530,  50,   0,  50,0xf4,0xff,0x1c,0x22},
- {  108,  35, 848, 398,1270, 530,  50,   0,  50,0xf4,0xff,0x1c,0x22},
- {   12,   5, 954, 448,1270, 530,  50,   0,  50,0xf1,0x04,0x1f,0x18},
- {    9,   4, 960, 463,1644, 438,  50,   0,  50,0xf4,0x0b,0x1c,0x0a},
- {    9,   4, 848, 528,1270, 530,   0,   0,  50,0xf5,0xfb,0x1b,0x2a},
- {   36,  25,1060, 648,1316, 530, 438,   0, 438,0xeb,0x05,0x25,0x16},
- {    3,   2,1080, 619,1270, 540, 438,   0, 438,0xf3,0x00,0x1d,0x20},
- {    1,   1,1170, 821,1270, 520, 686,   0, 686,0xF3,0x00,0x1D,0x20}     /*301b*/
-};
-
-SiS310_TVDataStruct  SiS310_StNTSCData[]=
-{
- {    1,   1, 858, 525,1270, 400,  50,   0, 760,0xf1,0x04,0x1f,0x18},
- {    1,   1, 858, 525,1270, 350,  50,   0, 640,0xf1,0x04,0x1f,0x18},
- {    1,   1, 858, 525,1270, 400,   0,   0, 720,0xf1,0x04,0x1f,0x18},
- {    1,   1, 858, 525,1270, 350,   0,   0, 720,0xf4,0x0b,0x1c,0x0a},
- {    1,   1, 858, 525,1270, 480,   0,   0, 760,0xf1,0x04,0x1f,0x18}
-};
-
-SiS310_TVDataStruct  SiS310_ExtNTSCData[]=
-{
- {  143,  65, 858, 443,1270, 440, 171,   0, 171,0xf1,0x04,0x1f,0x18},
- {   88,  35, 858, 393,1270, 440, 171,   0, 171,0xf1,0x04,0x1f,0x18},
- {  143,  70, 924, 443,1270, 440,  92,   0,  92,0xf1,0x04,0x1f,0x18},
- {  143,  70, 924, 393,1270, 440,  92,   0,  92,0xf4,0x0b,0x1c,0x0a},
- {  143,  76, 836, 523,1270, 440, 224,   0,   0,0xf1,0x05,0x1f,0x16},
- {  143, 120,1056, 643,1288, 440,   0, 128,   0,0xf4,0x10,0x1c,0x00},
- {    2,   1, 858, 503,1270, 480,   0, 128,   0,0xee,0x0c,0x22,0x08},
- {   65,  64,1056, 791,1270, 480, 638,   0,   0,0xEE,0x0C,0x22,0x08} /*301b*/     
-};
-
-SiS310_TVDataStruct  SiS310_St1HiTVData[]=
-{
-0x00};
-
-SiS310_TVDataStruct  SiS310_St2HiTVData[]=
-{
-0x00};
-
-SiS310_TVDataStruct  SiS310_ExtHiTVData[]=
-{
-0x00};
-
-UCHAR SiS310_NTSCTiming[] = {
-  0x17,0x1d,0x03,0x09,0x05,0x06,0x0c,0x0c,
-  0x94,0x49,0x01,0x0a,0x06,0x0d,0x04,0x0a,
-  0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x1b,
-  0x0c,0x50,0x00,0x97,0x00,0xda,0x4a,0x17,
-  0x7d,0x05,0x4b,0x00,0x00,0xe2,0x00,0x02,
-  0x03,0x0a,0x65,0x9d,0x08,0x92,0x8f,0x40,
-  0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x50,
-  0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00};
-
-UCHAR SiS310_PALTiming[] = {
-  0x19,0x52,0x35,0x6e,0x04,0x38,0x3d,0x70,
-  0x94,0x49,0x01,0x12,0x06,0x3e,0x35,0x6d,
-  0x06,0x14,0x3e,0x35,0x6d,0x00,0x45,0x2b,
-  0x70,0x50,0x00,0x9b,0x00,0xd9,0x5d,0x17,
-  0x7d,0x05,0x45,0x00,0x00,0xe8,0x00,0x02,
-  0x0d,0x00,0x68,0xb0,0x0b,0x92,0x8f,0x40,
-  0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x63,
-  0x00,0x40,0x3e,0x00,0xe1,0x02,0x28,0x00};
-
-UCHAR SiS310_HiTVExtTiming[] = {0x00};
-
-UCHAR SiS310_HiTVSt1Timing[] = {0x00};
-
-UCHAR SiS310_HiTVSt2Timing[] = {0x00};
-
-UCHAR SiS310_HiTVTextTiming[] = {0x00};
-
-UCHAR SiS310_HiTVGroup3Data[] = {0x00};
-
-UCHAR SiS310_HiTVGroup3Simu[] = {0x00};
-
-UCHAR SiS310_HiTVGroup3Text[] = {0x00};
-
-typedef struct _SiS310_PanelDelayTblStruct
-{
- UCHAR timer[2];
-} SiS310_PanelDelayTblStruct;
-SiS310_PanelDelayTblStruct SiS310_PanelDelayTbl[]=
-{{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00},
-{0x00,0x00}};
-
-typedef struct _SiS310_LVDSDataStruct
-{
- USHORT VGAHT;
- USHORT VGAVT;
- USHORT LCDHT;
- USHORT LCDVT;
-} SiS310_LVDSDataStruct;
-SiS310_LVDSDataStruct  SiS310_LVDS800x600Data_1[]=
-{
- {848, 433,1060, 629},
- {848, 389,1060, 629},
- {848, 433,1060, 629},
- {848, 389,1060, 629},
- {848, 518,1060, 629},
- {1056, 628,1056, 628},
- {1056, 628,1056, 628},
- {800, 449,1000, 644},
- {800, 525,1000, 635}
-};
-
-SiS310_LVDSDataStruct  SiS310_LVDS800x600Data_2[]=
-{
- {1056, 628,1056, 628},
- {1056, 628,1056, 628},
- {1056, 628,1056, 628},
- {1056, 628,1056, 628},
- {1056, 628,1056, 628},
- {1056, 628,1056, 628},
- {1056, 628,1056, 628},
- {800, 449,1000, 644},
- {800, 525,1000, 635}
-};
-
-SiS310_LVDSDataStruct  SiS310_LVDS1024x768Data_1[]=
-{
- {840, 438,1344, 806},
- {840, 409,1344, 806},
- {840, 438,1344, 806},
- {840, 409,1344, 806},
- {840, 518,1344, 806},
- {1050, 638,1344, 806},
- {1344, 806,1344, 806},
- {800, 449,1280, 801},
- {800, 525,1280, 813}
-};
-
-SiS310_LVDSDataStruct  SiS310_LVDS1024x768Data_2[]=
-{
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {800, 449,1280, 801},
- {800, 525,1280, 813}
-};
-
-SiS310_LVDSDataStruct  SiS310_LVDS1280x1024Data_1[]=
-{
- {840, 438,1344, 806},
- {840, 409,1344, 806},
- {840, 438,1344, 806},
- {840, 409,1344, 806},
- {840, 518,1344, 806},
- {1050, 638,1344, 806},
- {1344, 806,1344, 806},
- {800, 449,1280, 801},
- {800, 525,1280, 813}
-};
-
-SiS310_LVDSDataStruct  SiS310_LVDS1280x1024Data_2[]=
-{
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {1344, 806,1344, 806},
- {800, 449,1280, 801},
- {800, 525,1280, 813}
-};
-
-SiS310_LVDSDataStruct  SiS310_LVDS640x480Data_1[]=
-{
- {800, 449, 800, 449},
- {800, 449, 800, 449},
- {800, 449, 800, 449},
- {800, 449, 800, 449},
- {800, 525, 800, 525},
- {1056, 628,1056, 628},
- {1056, 628,1056, 628},
- {1056, 628,1056, 628},
- {1056, 628,1056, 628}
-};
-
-SiS310_LVDSDataStruct  SiS310_CHTVUNTSCData[]=
-{
- {840, 600, 840, 600},
- {840, 600, 840, 600},
- {840, 600, 840, 600},
- {840, 600, 840, 600},
- {784, 600, 784, 600},
- {1064, 750,1064, 750}
-};
-
-SiS310_LVDSDataStruct  SiS310_CHTVONTSCData[]=
-{
- {840, 525, 840, 525},
- {840, 525, 840, 525},
- {840, 525, 840, 525},
- {840, 525, 840, 525},
- {784, 525, 784, 525},
- {1040, 700,1040, 700}
-};
-
-SiS310_LVDSDataStruct  SiS310_CHTVUPALData[]=
-{
- {1008, 625,1008, 625},
- {1008, 625,1008, 625},
- {1008, 625,1008, 625},
- {1008, 625,1008, 625},
- {840, 750, 840, 750},
- {936, 836, 936, 836}
-};
-
-SiS310_LVDSDataStruct  SiS310_CHTVOPALData[]=
-{
- {1008, 625,1008, 625},
- {1008, 625,1008, 625},
- {1008, 625,1008, 625},
- {1008, 625,1008, 625},
- {840, 625, 840, 625},
- {960, 750, 960, 750}
-};
-
-typedef struct _SiS310_LVDSDesStruct
-{
- USHORT LCDHDES;
- USHORT LCDVDES;
-} SiS310_LVDSDesStruct;
-SiS310_LVDSDesStruct  SiS310_PanelType00_1[]=
-{
- {1059, 626},
- {1059, 624},
- {1059, 626},
- {1059, 624},
- {1059, 624},
- { 0, 627},
- { 0, 627},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType01_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType02_1[]=
-{
- {1059, 626},
- {1059, 624},
- {1059, 626},
- {1059, 624},
- {1059, 624},
- { 0, 627},
- { 0, 627},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType03_1[]=
-{
- { 8, 436},
- { 8, 440},
- { 8, 436},
- { 8, 440},
- { 8, 512},
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType04_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType05_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType06_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType07_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType08_1[]=
-{
- {1059, 626},
- {1059, 624},
- {1059, 626},
- {1059, 624},
- {1059, 624},
- { 0, 627},
- { 0, 627},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType09_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0a_1[]=
-{
- {1059, 626},
- {1059, 624},
- {1059, 626},
- {1059, 624},
- {1059, 624},
- { 0, 627},
- { 0, 627},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0b_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0c_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0d_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0e_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0f_1[]=
-{
- {1343, 798},
- {1343, 794},
- {1343, 798},
- {1343, 794},
- {1343,   0},
- {1343,   0},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType00_2[]=
-{
- {976, 527},
- {976, 502},
- {976, 527},
- {976, 502},
- {976, 567},
- { 0, 627},
- { 0, 627},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType01_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType02_2[]=
-{
- {976, 527},
- {976, 502},
- {976, 527},
- {976, 502},
- {976, 567},
- { 0, 627},
- { 0, 627},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType03_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- {1152, 622},
- {1152, 597}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType04_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType05_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType06_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType07_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType08_2[]=
-{
- {976, 527},
- {976, 502},
- {976, 527},
- {976, 502},
- {976, 567},
- { 0, 627},
- { 0, 627},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType09_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0a_2[]=
-{
- {976, 527},
- {976, 502},
- {976, 527},
- {976, 502},
- {976, 567},
- { 0, 627},
- { 0, 627},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0b_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0c_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0d_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0e_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_PanelType0f_2[]=
-{
- {1152, 622},
- {1152, 597},
- {1152, 622},
- {1152, 597},
- {1152, 662},
- {1232, 722},
- { 0, 805},
- { 0, 794},
- { 0,   0}
-};
-/*301b*/
-SiS310_LVDSDesStruct SiS310_PanelType1076_1[]=
-{
-0x00,0x00};
-SiS310_LVDSDesStruct SiS310_PanelType1210_1[]=
-{
-0x00,0x00};
-SiS310_LVDSDesStruct SiS310_PanelType1296_1[]=
-{
-0x00,0x00};
-SiS310_LVDSDesStruct SiS310_PanelType1076_2[]=
-{
-0x00,0x00};
-SiS310_LVDSDesStruct SiS310_PanelType1210_2[]=
-{
-0x00,0x00};
-SiS310_LVDSDesStruct SiS310_PanelType1296_2[]=
-{
-0x00,0x00};
-/*end 301b*/
-
-SiS310_LVDSDesStruct  SiS310_CHTVUNTSCDesData[]=
-{
- { 0,   0},
- { 0,   0},
- { 0,   0},
- { 0,   0},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_CHTVONTSCDesData[]=
-{
- { 0,   0},
- { 0,   0},
- { 0,   0},
- { 0,   0},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_CHTVUPALDesData[]=
-{
- {256,   0},
- {256,   0},
- {256,   0},
- {256,   0},
- { 0,   0},
- { 0,   0}
-};
-
-SiS310_LVDSDesStruct  SiS310_CHTVOPALDesData[]=
-{
- {256,   0},
- {256,   0},
- {256,   0},
- {256,   0},
- { 0,   0},
- { 0,   0}
-};
-
-typedef struct _SiS310_LVDSCRT1DataStruct
-{
- UCHAR CR[17];
-} SiS310_LVDSCRT1DataStruct;
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1[]=
-{{0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
-   0x00 },
- {0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
-   0x00 },
- {0x65,0x4f,0x89,0x56,0x83,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x05,
-   0x00 },
- {0x65,0x4f,0x89,0x56,0x83,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x05,
-   0x00 },
- {0x65,0x4f,0x89,0x56,0x83,0x04,0x3e,
-   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x05,
-   0x00 },
- {0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_1[]=
-{{0x73,0x4f,0x4f,0x97,0x55,0x86,0xc4,0x1f,
-   0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x05,
-   0x00 },
- {0x73,0x4f,0x4f,0x97,0x55,0x86,0x97,0x1f,
-   0x60,0x87,0x5d,0x5d,0x83,0x10,0x00,0x05,
-   0x00 },
- {0x73,0x4f,0x4f,0x97,0x55,0x86,0xc4,0x1f,
-   0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x05,
-   0x00},
- {0x73,0x4f,0x4f,0x97,0x55,0x86,0x97,0x1f,
-   0x60,0x87,0x5d,0x5d,0x83,0x10,0x00,0x05,
-   0x00 },
- {0x73,0x4f,0x4f,0x97,0x55,0x86,0x04,0x3e,
-   0xE2,0x89,0xDf,0xDf,0x05,0x00,0x00,0x05,
-   0x00},
- {0x87,0x63,0x63,0x8B,0x69,0x1A,0x7c,0xf0,
-   0x5A,0x8F,0x57,0x57,0x7D,0x20,0x00,0x26,
-   0x01},
- {0xA3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xFf,0xFf,0x25,0x10,0x00,0x02,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_1[]=
-{{0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
-   0x00 },
- {0x63,0x4f,0x87,0x54,0x9f,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
-   0x00 },
- {0x63,0x4f,0x87,0x54,0x9f,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x01,
-   0x00 },
- {0x63,0x4f,0x87,0x54,0x9f,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x01,
-   0x00 },
- {0x63,0x4f,0x87,0x54,0x9f,0x04,0x3e,
-   0xe2,0x89,0xdf,0x05,0x00,0x00,0x01,
-   0x00 },
- {0x7e,0x63,0x82,0x68,0x15,0x7c,0xf0,
-   0x5a,0x8f,0x57,0x7d,0x20,0x00,0x26,
-   0x01 },
- {0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_1_H[]=
-{{0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x04,
-   0x00 },
- {0x30,0x27,0x94,0x2c,0x92,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x04,
-   0x00 },
- {0x30,0x27,0x94,0x2c,0x92,0xaf,0x1f,
-   0x90,0x85,0x8f,0xab,0x30,0x00,0x04,
-   0x00 },
- {0x30,0x27,0x94,0x2c,0x92,0x83,0x1f,
-   0x5e,0x83,0x5d,0x79,0x10,0x00,0x04,
-   0x00 },
- {0x30,0x27,0x94,0x2c,0x92,0x04,0x3e,
-   0xe0,0x85,0xdf,0xfb,0x10,0x00,0x04,
-   0x00 },
- {0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x05,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_1_H[]=
-{{0x37,0x27,0x27,0x9B,0x2b,0x94,0xc4,0x1f,
-   0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x44,
-   0x00 },
- {0x37,0x27,0x27,0x9B,0x2b,0x94,0x97,0x1f,
-   0x60,0x87,0x5D,0x5D,0x83,0x01,0x00,0x44,
-   0x00},
- {0x37,0x27,0x27,0x9B,0x2b,0x94,0xc4,0x1f,
-   0x92,0x89,0x8f,0x8f,0xb5,0x30,0x00,0x44,
-   0x00},
- {0x37,0x27,0x27,0x9B,0x2b,0x94,0x97,0x1f,
-   0x60,0x87,0x5D,0x5D,0x83,0x01,0x00,0x44,
-   0x00},
- {0x37,0x27,0x27,0x9B,0x2b,0x94,0x04,0x3e,
-   0xE2,0x89,0xDf,0xDf,0x05,0x00,0x00,0x44,
-   0x00},
- {0x41,0x31,0x31,0x85,0x35,0x1d,0x7c,0xf0,
-   0x5A,0x8F,0x57,0x57,0x7D,0x20,0x00,0x55,
-   0x01},
- {0x4f,0x3F,0x3F,0x93,0x45,0x0D,0x24,0xf5,
-   0x02,0x88,0xFf,0xFf,0x25,0x10,0x00,0x01,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_1_H[]=
-{{0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x04,
-   0x00 },
- {0x2f,0x27,0x93,0x2b,0x90,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x04,
-   0x00 },
- {0x2f,0x27,0x93,0x2b,0x90,0xb4,0x1f,
-   0x92,0x89,0x8f,0xb5,0x30,0x00,0x04,
-   0x00 },
- {0x2f,0x27,0x93,0x2b,0x90,0x82,0x1f,
-   0x60,0x87,0x5d,0x83,0x10,0x00,0x04,
-   0x00 },
- {0x2f,0x27,0x93,0x2b,0x90,0x04,0x3e,
-   0xe2,0x89,0xdf,0x05,0x00,0x00,0x04,
-   0x00 },
- {0x3c,0x31,0x80,0x35,0x1c,0x7c,0xf0,
-   0x5a,0x8f,0x57,0x7d,0x20,0x00,0x55,
-   0x01 },
- {0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_2[]=
-{ {0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x06,
-   0x00 },
- {0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x06,
-   0x00 },
- {0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x06,
-   0x00 },
- {0x7f,0x4f,0x83,0x62,0x12,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x06,
-   0x00 },
- {0x7f,0x4f,0x83,0x62,0x12,0x72,0xba,
-   0x1c,0x80,0xdf,0x73,0x00,0x00,0x06,
-   0x00 },
- {0x7f,0x63,0x83,0x6c,0x1c,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x06,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_2[]=
-{ {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x02,
-   0x01 },
- {0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_2[]=
-{ {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x4f,0x87,0x6e,0x9f,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x06,
-   0x00 },
- {0xa3,0x63,0x87,0x78,0x89,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x02,
-   0x01 },
- {0xa3,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x02,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT1800x600_2_H[]=
-{ {0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x05,
-   0x00 },
- {0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05,
-   0x00 },
- {0x3d,0x27,0x81,0x32,0x1a,0x72,0x3e,
-   0xf4,0x88,0x8f,0x73,0x20,0x00,0x05,
-   0x00 },
- {0x3d,0x27,0x81,0x3a,0x1a,0x72,0x3e,
-   0xdb,0x8f,0x5d,0x73,0x20,0x00,0x05,
-   0x00 },
- {0x3d,0x27,0x81,0x32,0x1a,0x72,0xba,
-   0x1c,0x80,0xdf,0x73,0x00,0x00,0x05,
-   0x00 },
- {0x3d,0x31,0x81,0x37,0x1f,0x72,0xf0,
-   0x58,0x8c,0x57,0x73,0x20,0x00,0x05,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11024x768_2_H[]=
-{ {0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x27,0x93,0x39,0x01,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x31,0x93,0x3e,0x06,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x01,
-   0x01 },
- {0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_LVDSCRT11280x1024_2_H[]=
-{ {0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x4a,0x80,0x8f,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x31,0x87,0x5d,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x27,0x93,0x39,0x81,0x24,0xbb,
-   0x72,0x88,0xdf,0x25,0x30,0x00,0x01,
-   0x00 },
- {0x4f,0x31,0x93,0x3e,0x86,0x24,0xf1,
-   0xae,0x84,0x57,0x25,0x30,0x00,0x01,
-   0x01 },
- {0x4f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0x25,0x10,0x00,0x01,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1UNTSC[]=
-{ {0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
-   0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
-   0x00 },
- {0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
-   0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,
-   0x00 },
- {0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
-   0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,
-   0x00 },
- {0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
-   0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,
-   0x00 },
- {0x5d,0x4f,0x81,0x53,0x9c,0x56,0xba,
-   0x18,0x84,0xdf,0x57,0x00,0x00,0x01,
-   0x00 },
- {0x80,0x63,0x84,0x6c,0x17,0xec,0xf0,
-   0x90,0x8c,0x57,0xed,0x20,0x00,0x06,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1ONTSC[]=
-{ {0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
-   0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
-   0x00 },
- {0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
-   0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,
-   0x00 },
- {0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
-   0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,
-   0x00 },
- {0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
-   0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,
-   0x00 },
- {0x5d,0x4f,0x81,0x56,0x9c,0x0b,0x3e,
-   0xe8,0x84,0xdf,0x0c,0x00,0x00,0x01,
-   0x00 },
- {0x7d,0x63,0x81,0x6a,0x16,0xba,0xf0,
-   0x7f,0x86,0x57,0xbb,0x00,0x00,0x06,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1UPAL[]=
-{ {0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
-   0x00 },
- {0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
-   0x00 },
- {0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,
-   0x00 },
- {0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
-   0x00 },
- {0x64,0x4f,0x88,0x55,0x80,0xec,0xba,
-   0x50,0x84,0xdf,0xed,0x00,0x00,0x05,
-   0x00 },
- {0x70,0x63,0x94,0x68,0x8d,0x42,0xf1,
-   0xc8,0x8c,0x57,0xe9,0x20,0x00,0x05,
-   0x01 }};
-
-SiS310_LVDSCRT1DataStruct  SiS310_CHTVCRT1OPAL[]=
-{ {0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
-   0x00 },
- {0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
-   0x00 },
- {0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,
-   0x00 },
- {0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
-   0xde,0x81,0x5d,0x70,0x00,0x00,0x05,
-   0x00 },
- {0x64,0x4f,0x88,0x55,0x80,0x6f,0xba,
-   0x20,0x83,0xdf,0x70,0x00,0x00,0x05,
-   0x00 },
- {0x73,0x63,0x97,0x69,0x8e,0xec,0xf0,
-   0x90,0x8c,0x57,0xed,0x20,0x00,0x05,
-   0x01 }};
-
-typedef struct _SiS310_CHTVRegDataStruct
-{
- UCHAR Reg[5];
-} SiS310_CHTVRegDataStruct;
-SiS310_CHTVRegDataStruct SiS310_CHTVReg_UNTSC[] = {
-0x00 };
-
-SiS310_CHTVRegDataStruct SiS310_CHTVReg_ONTSC[] = {
-0x00 };
-
-SiS310_CHTVRegDataStruct SiS310_CHTVReg_UPAL[] = {
-0x00 };
-
-SiS310_CHTVRegDataStruct SiS310_CHTVReg_OPAL[] = {
-0x00 };
-
-UCHAR SiS310_CHTVVCLKUNTSC[]={0x00 };
-
-UCHAR SiS310_CHTVVCLKONTSC[]={0x00 };
-
-UCHAR SiS310_CHTVVCLKUPAL[]={0x00 };
-
-UCHAR SiS310_CHTVVCLKOPAL[]={0x00 };
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/sis/init301.c linux.20pre10-ac2/drivers/video/sis/init301.c
--- linux.20pre10/drivers/video/sis/init301.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/sis/init301.c	2002-10-11 00:17:32.000000000 +0100
@@ -1,95 +1,165 @@
-/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/init301.c,v 1.3 2000/12/02 01:16:16 dawes Exp $ */
-
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/init301.c,v 1.3 2002/22/04 01:16:16 dawes Exp $ */
 /*
  * Mode switching code (CRT2 section) for SiS 300/540/630/730/315/550/650/740
  * (Universal module for Linux kernel framebuffer, XFree86 4.x)
  *
- * Comments and changes marked with "TW" by Thomas Winischhofer <thomer@winischhofer.net>
+ * Assembler-To-C translation
+ * Parts Copyright 2002 by Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ * Based on BIOS
+ *     1.10.07, 1.10a for SiS650/LVDS+CH7019
+ *     1.07.1b, 1.10.6s for SiS650/301(B/LV), 650/301LVx
+ *     2.04.50 (I) and 2.04.5c (II) for SiS630/301(B)
+ *     2.02.3b, 2.03.02, 2.04.2c, 2.04.5c, 2.07a and 2.08.b3 for 630/LVDS/LVDS+CH7005
+ *     1.09b for 315/301(B)
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holder not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  The copyright holder makes no representations
+ * about the suitability of this software for any purpose.  It is provided
+ * "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  *
  */
 
-/* DEBUG: GetVCLK2Ptr (Mitac bug) - reverted */
+#include "init301.h"
 
-/*
-#ifdef WINCE_HEADER
-#include "precomp.h"
+#if 0
+#define TWNEWPANEL
+#endif
+
+#if 1   /* TW: Emulate 650/301LVx BIOS 1.10.6s (should be set) */
+#define SIS650301NEW
 #endif
-*/
-/*#include "precomp.h"*/
 
-#include "init301.h"
 #ifdef SIS300
 #include "oem300.h"
 #endif
+
 #ifdef SIS315H
 #include "oem310.h"
 #endif
 
+#define SiS_I2CDELAY      1000
+#define SiS_I2CDELAYSHORT  333
+
 BOOLEAN
-SiS_SetCRT2Group301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+SiS_SetCRT2Group301(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
                     PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
    USHORT ModeIdIndex;
    USHORT RefreshRateTableIndex;
 
-   SiS_SetFlag=SiS_SetFlag|ProgrammingCRT2;
-   SiS_SearchModeID(ROMAddr,ModeNo,&ModeIdIndex);
-   SiS_SelectCRT2Rate=4;
-   RefreshRateTableIndex = SiS_GetRatePtrCRT2(ROMAddr,ModeNo,ModeIdIndex);
-   SiS_SaveCRT2Info(ModeNo);
-   SiS_DisableBridge(HwDeviceExtension,BaseAddr);
-   SiS_UnLockCRT2(HwDeviceExtension, BaseAddr);
-   SiS_SetCRT2ModeRegs(BaseAddr,ModeNo,HwDeviceExtension);
-   if(SiS_VBInfo&DisableCRT2Display) {
-     SiS_LockCRT2(HwDeviceExtension, BaseAddr);
-     SiS_DisplayOn();
-     return(FALSE);
+   SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+
+   SiS_SearchModeID(SiS_Pr,ROMAddr,&ModeNo,&ModeIdIndex);
+
+   /* TW: Used for shifting CR33 */
+   SiS_Pr->SiS_SelectCRT2Rate = 4;
+
+   SiS_UnLockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
+
+   RefreshRateTableIndex = SiS_GetRatePtrCRT2(SiS_Pr, ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+
+   SiS_SaveCRT2Info(SiS_Pr,ModeNo);
+
+   if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+      SiS_DisableBridge(SiS_Pr,HwDeviceExtension,BaseAddr);
+      SiS_SetCRT2ModeRegs(SiS_Pr,BaseAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+   }
+
+   if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) {
+      SiS_LockCRT2(SiS_Pr,HwDeviceExtension, BaseAddr);
+      SiS_DisplayOn(SiS_Pr);
+      return(FALSE);
    }
-   /* SetDefCRT2ExtRegs(BaseAddr);   */
-   SiS_GetCRT2Data(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex);
-   /*301b*/
-   if( ((SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS301LV))
-           && (SiS_VBInfo&SetCRT2ToLCDA)) ){
-	SiS_GetLVDSDesData(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex);
+
+   SiS_GetCRT2Data(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                   HwDeviceExtension);
+
+   /* LVDS, 650/301LV(LCDA) and 630/301B BIOS set up Panel Link */
+   if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
+   	SiS_GetLVDSDesData(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+	                   HwDeviceExtension);
+   } else {
+        SiS_Pr->SiS_LCDHDES = SiS_Pr->SiS_LCDVDES = 0;
    }
-   /*end 301b*/
-   if(SiS_IF_DEF_LVDS==1) {
-   	SiS_GetLVDSDesData(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex);
+
+   if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+      SiS_SetGroup1(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+                    HwDeviceExtension,RefreshRateTableIndex);
    }
 
-   SiS_SetGroup1(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
-                 HwDeviceExtension,RefreshRateTableIndex);
+   if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+
+        if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+
+	   SiS_SetGroup2(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+	                 RefreshRateTableIndex,HwDeviceExtension);
+      	   SiS_SetGroup3(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+	                 HwDeviceExtension);
+      	   SiS_SetGroup4(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+	                 RefreshRateTableIndex,HwDeviceExtension);
+      	   SiS_SetGroup5(SiS_Pr,HwDeviceExtension, BaseAddr,ROMAddr,
+	                 ModeNo,ModeIdIndex);
+
+	   /* TW: 630/301B BIOS does all this: */
+	   if(HwDeviceExtension->jChipType < SIS_315H) {
+	      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+	         if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+		    if(!((SiS_Pr->SiS_SetFlag & CRT2IsVGA) && ((ModeNo == 0x03) || (ModeNo = 0x10)))) {
+		       if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+		           SiS_ModCRT1CRTC(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+		                           RefreshRateTableIndex,HwDeviceExtension);
+		       }
+                    }
+		 }
+		 SiS_SetCRT2ECLK(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+		                 RefreshRateTableIndex,HwDeviceExtension);
+              }
+	   }
+
+        }
 
-   /*301b*/
-   if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS301LV))
-   		&& (SiS_VBInfo&SetCRT2ToLCDA)
-		&& (SiS_IF_DEF_LVDS == 0) ) {
-     	if( (SiS_VBType&(VB_SIS301LV|VB_SIS302LV)) && (SiS_VBInfo&SetCRT2ToLCDA) ){
-             	SiS_SetReg1(SiS_Part4Port,0x24,0x0e);
-    	}
-   /* end 301b */
-   } else if((SiS_IF_DEF_LVDS==0) && (!(SiS_VBInfo&SetCRT2ToLCDA))) {
-      	SiS_SetGroup2(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
-	              RefreshRateTableIndex,HwDeviceExtension);
-      	SiS_SetGroup3(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
-	              HwDeviceExtension);
-      	SiS_SetGroup4(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
-	              RefreshRateTableIndex,HwDeviceExtension);
-      	SiS_SetGroup5(BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
    } else {
-     	if(SiS_IF_DEF_CH7005==1) {
-	    if(SiS_VBInfo&SetCRT2ToTV)
+
+        if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+	        if (SiS_Pr->SiS_IF_DEF_TRUMPION == 0) {
+    	 	        SiS_ModCRT1CRTC(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+		                        RefreshRateTableIndex,HwDeviceExtension);
+	        }
+	}
+        if(SiS_Pr->SiS_IF_DEF_FSTN == 0) {
+     	 	SiS_SetCRT2ECLK(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+		          RefreshRateTableIndex,HwDeviceExtension);
+	}
+	if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+     	  if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+	     /* TW: Inserted from 650/LVDS BIOS */
+	     if (SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+	        if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+		    SiS_SetCH701xForLCD(SiS_Pr,HwDeviceExtension,BaseAddr);
+		}
+	     }
+	     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
 	        /* TW: Set Chrontel registers only if CRT2 is TV */
-       		SiS_SetCHTVReg(ROMAddr,ModeNo,ModeIdIndex,
+       		SiS_SetCHTVReg(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
 		               RefreshRateTableIndex);
-     	}
-     	if(!(SiS_LCDResInfo==Panel640x480)){
-    	 	SiS_ModCRT1CRTC(ROMAddr,ModeNo,ModeIdIndex,
-		                RefreshRateTableIndex);
-         	if(!SiS_IF_DEF_FSTN)  /*fstn*/
-     	     		SiS_SetCRT2ECLK(ROMAddr,ModeNo,ModeIdIndex,
-			          RefreshRateTableIndex,HwDeviceExtension);
-     	}
+	     }
+     	  }
+	}
+
    }
 
 #ifdef SIS300
@@ -97,1241 +167,1901 @@
         (HwDeviceExtension->jChipType==SIS_630)||
         (HwDeviceExtension->jChipType==SIS_730)||
         (HwDeviceExtension->jChipType==SIS_300) )
-     	SiS_OEM300Setting(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
+    {
+	if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+       	   SiS_OEM300Setting(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
+	}
+    }
 #endif
 
 #ifdef SIS315H
-   if ( (HwDeviceExtension->jChipType==SIS_315H)||   /* 05/02/01 ynlai for sis550 */
+   if ( (HwDeviceExtension->jChipType==SIS_315H)||
         (HwDeviceExtension->jChipType==SIS_315PRO)||
-        (HwDeviceExtension->jChipType==SIS_550) ||   /* 05/02/01 ynlai for 550 */
-        (HwDeviceExtension->jChipType==SIS_640) ||   /* 08/20/01 chiawen for 640/740 */
-        (HwDeviceExtension->jChipType==SIS_740) ||   /* 09/03/01 chiawen for 640/740 */
-        (HwDeviceExtension->jChipType==SIS_650))     /* 09/03/01 chiawen for 650 */
+        (HwDeviceExtension->jChipType==SIS_550) ||
+        (HwDeviceExtension->jChipType==SIS_640) ||
+        (HwDeviceExtension->jChipType==SIS_740) ||
+        (HwDeviceExtension->jChipType==SIS_650))
    {
-        SiS_OEM310Setting(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
-        SiS_CRT2AutoThreshold(BaseAddr);
+        if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+#ifdef SIS650301NEW
+	   SiS_FinalizeLCD(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex, HwDeviceExtension);
+#else
+	   SiS_OEMLCD(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+#endif
+           SiS_OEM310Setting(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+           SiS_CRT2AutoThreshold(SiS_Pr,BaseAddr);
+        }
    }
 #endif
 
-   SiS_EnableBridge(HwDeviceExtension,BaseAddr);
-   if(SiS_IF_DEF_CH7005==1) {
-	if(SiS_VBInfo&SetCRT2ToTV) {
+   if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+      SiS_EnableBridge(SiS_Pr,HwDeviceExtension,BaseAddr);
+      SiS_DisplayOn(SiS_Pr);
+   }
+
+   if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+	if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
 	     /* TW: Disable LCD panel when using TV */
-	     SiS_SetRegANDOR(SiS_P3c4,0x11,0xFF,0x0C);
+	     SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x11,0x0C);
 	} else {
 	     /* TW: Disable TV when using LCD */
-	     SiS_SetCHTVRegANDOR(0x010E,0xF8);
+	     SiS_SetCH70xxANDOR(SiS_Pr,0x010E,0xF8);
 	}
    }
-   SiS_DisplayOn();
-   SiS_LockCRT2(HwDeviceExtension, BaseAddr);
+
+   SiS_DisplayOn(SiS_Pr);
+
+   if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+      SiS_LockCRT2(SiS_Pr,HwDeviceExtension, BaseAddr);
+   }
+
    return 1;
 }
 
-void
-SiS_SetGroup1(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-              PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex)
+/* TW: Checked with 650/LVDS (1.10.07) and 630+301B/LVDS BIOS */
+BOOLEAN
+SiS_LowModeStuff(SiS_Private *SiS_Pr, USHORT ModeNo,
+                 PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+    USHORT temp,temp1,temp2;
+
+    if((ModeNo != 0x03) && (ModeNo != 0x10) && (ModeNo != 0x12))
+         return(1);
+    temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x11);
+    SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x11,0x80);
+    temp1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x00);
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,0x00,0x55);
+    temp2 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x00);
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,0x00,temp1);
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,0x11,temp);
+    if(HwDeviceExtension->jChipType >= SIS_315H) {
+       if(temp2 == 0x55) return(0);
+       else return(1);
+    } else {
+       if(temp2 != 0x55) return(1);
+       else {
+          SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x35,0x01);
+          return(0);
+       }
+    }
+}
+
+/* TW: Set Part1 registers */
+/* TW: Checked with 650/LVDS (1.10.07), 650/301LV (II) and 630/301B (II) BIOS */
+/* TW: Pass 2: Checked with 650/301LVx 1.10.6s, 630/301B 2.04.5a */
+void
+SiS_SetGroup1(SiS_Private *SiS_Pr,USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+              USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+	      USHORT RefreshRateTableIndex)
 {
-  USHORT  temp=0,tempax=0,tempbx=0,tempcx=0;
-  USHORT  pushbx=0,CRT1Index=0;
-  USHORT  modeflag,resinfo=0;
+  USHORT  temp=0, tempax=0, tempbx=0, tempcx=0, tempbl=0;
+  USHORT  pushbx=0, CRT1Index=0;
+#ifdef SIS315H
+  USHORT  pushcx=0;
+#endif
+  USHORT  modeflag, resinfo=0;
 
   if(ModeNo<=0x13) {
-  	/* TW: Do nothing for std modes */
+	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
   } else {
-    	CRT1Index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
-    	CRT1Index=CRT1Index&0x3F;
-    	resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+    	CRT1Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
   }
 
-  /*301b*/ 
-  if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-         && (SiS_VBInfo&SetCRT2ToLCDA) ) {
-	   /* TW: Do nothing for these bridge types here */
+  /* TW: Removed 301B301LV.. check here; LCDA exists with LVDS as well */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+
+	   /* TW: From 650/LVDS BIOS; 301(B+LV) version does not set Sync  */
+	   if (SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+	       SiS_SetCRT2Sync(SiS_Pr,BaseAddr,ROMAddr,ModeNo,
+                               RefreshRateTableIndex,HwDeviceExtension);
+	   }
+
+	   SiS_SetGroup1_LCDA(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+     	                      HwDeviceExtension,RefreshRateTableIndex);
+
   } else {
-     SiS_SetCRT2Offset(SiS_Part1Port,ROMAddr,ModeNo,ModeIdIndex,
+
+     if( (HwDeviceExtension->jChipType >= SIS_315H) &&
+         (SiS_Pr->SiS_IF_DEF_LVDS == 1) &&
+	 (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+
+        SiS_SetCRT2Sync(SiS_Pr,BaseAddr,ROMAddr,ModeNo,
+                        RefreshRateTableIndex,HwDeviceExtension);
+
+     } else {
+
+        SiS_SetCRT2Offset(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
       		       RefreshRateTableIndex,HwDeviceExtension);
-     if (HwDeviceExtension->jChipType < SIS_315H ) /* 300 series */
-    	   SiS_SetCRT2FIFO(SiS_Part1Port,ROMAddr,ModeNo,
-	                   HwDeviceExtension);
-     else 					   /* 310 series */
-           SiS_SetCRT2FIFO2(SiS_Part1Port,ROMAddr,ModeNo,
-	                   HwDeviceExtension);
 
-     SiS_SetCRT2Sync(BaseAddr,ROMAddr,ModeNo,
-                     RefreshRateTableIndex);
-  }
+        if (HwDeviceExtension->jChipType < SIS_315H ) {
+#ifdef SIS300
+    	      SiS_SetCRT2FIFO_300(SiS_Pr,ROMAddr,ModeNo,HwDeviceExtension);
+#endif
+        } else {
+#ifdef SIS315H
+              SiS_SetCRT2FIFO_310(SiS_Pr,ROMAddr,ModeNo,HwDeviceExtension);
+#endif
+	}
 
-  if (ModeNo<=0x13)
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-  else
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+        SiS_SetCRT2Sync(SiS_Pr,BaseAddr,ROMAddr,ModeNo,
+                        RefreshRateTableIndex,HwDeviceExtension);
 
-  /*301b*/
-  if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-   					&& (SiS_VBInfo&SetCRT2ToLCDA) ) {
-     	SiS_SetGroup1_LCDA(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
-     	                   HwDeviceExtension,RefreshRateTableIndex);
-  /*end 301b*/
-  } else if (HwDeviceExtension->jChipType < SIS_315H ) {
-    /* ------------- 300 series --------------*/
-    temp=(SiS_VGAHT-1)&0x0FF;   					/* BTVGA2HT 0x08,0x09 */
-    SiS_SetReg1(SiS_Part1Port,0x08,temp);
-    temp=(((SiS_VGAHT-1)&0xFF00)>>8)<<4;
-    SiS_SetRegANDOR(SiS_Part1Port,0x09,~0x0F0,temp); 	/* <------------------- */
-
-    temp=(SiS_VGAHDE+12)&0x0FF;                               		/* BTVGA2HDEE 0x0A,0x0C */
-    SiS_SetReg1(SiS_Part1Port,0x0A,temp); 		/* <------------------- */
-        
-    pushbx=SiS_VGAHDE+12;                                     		/* bx  BTVGA@HRS 0x0B,0x0C */
-    tempcx=(SiS_VGAHT-SiS_VGAHDE)>>2;                           	/* cx */
-    tempbx=pushbx+tempcx;
-    tempcx=tempcx<<1;
-    tempcx=tempcx+tempbx;
-    
-    if(SiS_IF_DEF_LVDS==0) {
-      if(SiS_VBInfo&SetCRT2ToRAMDAC){
-        tempbx = SiS_CRT1Table[CRT1Index].CR[4];
-        tempbx = tempbx|((SiS_CRT1Table[CRT1Index].CR[14]&0xC0)<<2);
-        tempbx = (tempbx-1)<<3;
-        tempcx = SiS_CRT1Table[CRT1Index].CR[5];
-        tempcx = tempcx&0x1F;
-        temp = SiS_CRT1Table[CRT1Index].CR[15];
-        temp = (temp&0x04)<<(6-2);
-        tempcx=((tempcx|temp)-1)<<3;
-      }
-    }
-   /*add for hardware request*/
-    if((SiS_VBInfo&SetCRT2ToTV)&&(resinfo==0x08)){
-        if(SiS_VBInfo&SetPALTV){
-      		tempbx=1040;
-      		tempcx=1042;
-      	} else {
-      		tempbx=1040;
-      		tempcx=1042;
-      	}
-    }
+	/* 1. Horizontal setup */
 
-    temp=tempbx&0x00FF;
-    SiS_SetReg1(SiS_Part1Port,0x0B,temp); 		/* <------------------- */
-    
-  } else {
-     /* ---------------------- 310 series ------------------*/
-     if (modeflag&HalfDCLK) { /* for low resolution mode */
-         temp=(SiS_VGAHT/2-1)&0x0FF;                             /* BTVGA2HT 0x08,0x09 */
-         SiS_SetReg1(SiS_Part1Port,0x08,temp);
-         temp=(((SiS_VGAHT/2-1)&0xFF00)>>8)<<4;
-         SiS_SetRegANDOR(SiS_Part1Port,0x09,~0x0F0,temp);
-         temp=(SiS_VGAHDE/2+16)&0x0FF;                           /* BTVGA2HDEE 0x0A,0x0C */
-         SiS_SetReg1(SiS_Part1Port,0x0A,temp);
-
-         pushbx=SiS_VGAHDE/2+16;
-         tempcx=((SiS_VGAHT-SiS_VGAHDE)/2)>>2;                   /* cx */
-         tempbx=pushbx+tempcx;                                   /* bx  BTVGA@HRS 0x0B,0x0C */
-         tempcx=tempcx+tempbx;
-
-         if(SiS_IF_DEF_LVDS==0) {
-             if(SiS_VBInfo&SetCRT2ToRAMDAC){
-                tempbx = SiS_CRT1Table[CRT1Index].CR[4];
-                tempbx = tempbx|((SiS_CRT1Table[CRT1Index].CR[14]&0xC0)<<2);
-                tempbx = (tempbx-3)<<3;         		/*(VGAHRS-3)*8 */
-                tempcx = SiS_CRT1Table[CRT1Index].CR[5];
-                tempcx = tempcx&0x1F;
-                temp = SiS_CRT1Table[CRT1Index].CR[15];
-                temp = (temp&0x04)<<(5-2);      		/*VGAHRE D[5]*/
-                tempcx=((tempcx|temp)-3)<<3;    		/* (VGAHRE-3)*8 */
-             }
-         }
-         tempbx += 4;
-         tempcx += 4;
-         if (tempcx>(SiS_VGAHT/2))
-              tempcx = SiS_VGAHT/2;
-         temp=tempbx&0x00FF;
-         SiS_SetReg1(SiS_Part1Port,0x0B,temp);
-    } else {
-         temp=(SiS_VGAHT-1)&0x0FF;                             	/* BTVGA2HT 0x08,0x09 */
-         SiS_SetReg1(SiS_Part1Port,0x08,temp);
-         temp=(((SiS_VGAHT-1)&0xFF00)>>8)<<4;
-         SiS_SetRegANDOR(SiS_Part1Port,0x09,~0x0F0,temp);
-         temp=(SiS_VGAHDE+16)&0x0FF;                            /* BTVGA2HDEE 0x0A,0x0C */
-         SiS_SetReg1(SiS_Part1Port,0x0A,temp);
-
-         pushbx=SiS_VGAHDE+16;
-         tempcx=(SiS_VGAHT-SiS_VGAHDE)>>2;                      /* cx */
-         tempbx=pushbx+tempcx;                                  /* bx  BTVGA@HRS 0x0B,0x0C */
-         tempcx=tempcx+tempbx;
-      
-         if(SiS_IF_DEF_LVDS==0) {
-             if(SiS_VBInfo&SetCRT2ToRAMDAC){
-                tempbx = SiS_CRT1Table[CRT1Index].CR[4];
-                tempbx = tempbx|((SiS_CRT1Table[CRT1Index].CR[14]&0xC0)<<2);
-                tempbx = (tempbx-3)<<3;         		/*(VGAHRS-3)*8 */
-                tempcx = SiS_CRT1Table[CRT1Index].CR[5];
-                tempcx = tempcx&0x1F;
-                temp = SiS_CRT1Table[CRT1Index].CR[15];
-                temp = (temp&0x04)<<(5-2);      		/*VGAHRE D[5]*/
-                tempcx=((tempcx|temp)-3)<<3;    		/* (VGAHRE-3)*8 */
-                tempbx += 16;
-                tempcx += 16;
-             }
-         }
-         if (tempcx>SiS_VGAHT)
-        	tempcx = SiS_VGAHT;
-        /*add for hardware request*/
-         if((SiS_VBInfo&SetCRT2ToTV)&&(resinfo==0x08)){
-             if(SiS_VBInfo&SetPALTV){
-      		 tempbx=1040;
-      		 tempcx=1042;
-      	     } else {
-      		 tempbx=1040;
-      		 tempcx=1042;
-      	     }
-         }
-         temp=tempbx&0x00FF;
-         SiS_SetReg1(SiS_Part1Port,0x0B,temp);
-     }
-  }
+        if (HwDeviceExtension->jChipType < SIS_315H ) {
+
+#ifdef SIS300
+                /* ------------- 300 series --------------*/
+
+    		temp = (SiS_Pr->SiS_VGAHT - 1) & 0x0FF;   			/* BTVGA2HT 0x08,0x09 */
+    		SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,temp);                   /* TW: CRT2 Horizontal Total */
+
+    		temp = (((SiS_Pr->SiS_VGAHT - 1) & 0xFF00) >> 8) << 4;
+    		SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0f,temp);          /* TW: CRT2 Horizontal Total Overflow [7:4] */
+
+    		temp = (SiS_Pr->SiS_VGAHDE + 12) & 0x0FF;                       /* BTVGA2HDEE 0x0A,0x0C */
+    		SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0A,temp);                   /* TW: CRT2 Horizontal Display Enable End */
+
+    		pushbx = SiS_Pr->SiS_VGAHDE + 12;                               /* bx  BTVGA@HRS 0x0B,0x0C */
+    		tempcx = (SiS_Pr->SiS_VGAHT - SiS_Pr->SiS_VGAHDE) >> 2;
+    		tempbx = pushbx + tempcx;
+    		tempcx <<= 1;
+    		tempcx += tempbx;
+
+    		if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+      			if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC){
+			        CRT1Index &= 0x3F;
+        			tempbx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[4];
+        			tempbx |= ((SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14] & 0xC0) << 2);
+        			tempbx = (tempbx - 1) << 3;
+        			tempcx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[5];
+        			tempcx &= 0x1F;
+        			temp = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[15];
+        			temp = (temp & 0x04) << (6-2);
+        			tempcx = ((tempcx | temp) - 1) << 3;
+      			}
 
-  /* TW: The following is done for all bridge/chip types/series */
+    			if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (resinfo == 0x08)){
+        			if(!(SiS_Pr->SiS_VBInfo & SetPALTV)){
+      					tempbx = 1040;
+      					tempcx = 1042;
+      				}
+    			}
+	        }
 
-#if 1
-  tempax = (tempax&0x00FF)|(tempbx&0xFF00); /* TW: tempax not used above!!!*/
-  tempbx=pushbx;
-  tempbx=(tempbx&0x00FF)|((tempbx&0xFF00)<<4);
-  tempax=tempax|(tempbx&0xFF00);
-  temp=(tempax&0xFF00)>>8;
+    		temp = tempbx & 0x00FF;
+    		SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0B,temp);                   /* TW: CRT2 Horizontal Retrace Start */
 #endif
-#if 0
-  /* TW: new code: */
-  tempax=(tempbx&0xFF00)>>8;
-  tempbx=(((pushbx&0xFF00)>>8)<<4)&0xFF;
-  temp=tempax|tempbx;
-#endif
-  SiS_SetReg1(SiS_Part1Port,0x0C,temp); 		/* <------------------- */
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x0D,temp); 		/* <------------------- */
-  tempcx=SiS_VGAVT-1;
-  temp=tempcx&0x00FF;
-  if(SiS_IF_DEF_CH7005==1) {
-    	if(SiS_VBInfo&SetCRT2ToTV) {
-      		temp--;
-    	}
-  }
-  SiS_SetReg1(SiS_Part1Port,0x0E,temp); 		/* <------------------- */
-  tempbx=SiS_VGAVDE-1;
-  temp=tempbx&0x00FF;
-  /* [Do the same if CH7005==1 as above?] */
-  SiS_SetReg1(SiS_Part1Port,0x0F,temp); 		/* <------------------- */
-  temp=((tempbx&0xFF00)<<3)>>8;
-  temp=temp|((tempcx&0xFF00)>>8);
-  SiS_SetReg1(SiS_Part1Port,0x12,temp); 		/* <------------------- */
-
-  tempax=SiS_VGAVDE;
-  tempbx=SiS_VGAVDE;
-  tempcx=SiS_VGAVT;
-  tempbx=(SiS_VGAVT+SiS_VGAVDE)>>1;                     	/*  BTVGA2VRS     0x10,0x11   */
-  tempcx=((SiS_VGAVT-SiS_VGAVDE)>>4)+tempbx+1;          	/*  BTVGA2VRE     0x11        */
-  if(SiS_IF_DEF_LVDS==0) {
-    	if(SiS_VBInfo & SetCRT2ToRAMDAC){
-      		tempbx = SiS_CRT1Table[CRT1Index].CR[8];
-      		temp = SiS_CRT1Table[CRT1Index].CR[7];
-      		if(temp&0x04) tempbx=tempbx|0x0100;
-      		if(temp&0x80) tempbx=tempbx|0x0200;
-      		temp = SiS_CRT1Table[CRT1Index].CR[13];
-      		if(temp&0x08) tempbx=tempbx|0x0400;
-      		temp = SiS_CRT1Table[CRT1Index].CR[9];
-      		tempcx=(tempcx&0xFF00)|(temp&0x00FF);
-    	}
-  }
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x10,temp); 		/* <------------------- */
-  temp=((tempbx&0xFF00)>>8)<<4;
-  temp=((tempcx&0x000F)|(temp));
-  SiS_SetReg1(SiS_Part1Port,0x11,temp); 		/* <------------------- */
-  if(SiS_IF_DEF_LVDS==0) {
-    	temp=0x20;
-    	if(SiS_LCDResInfo==Panel1280x1024) temp=0x20;
-    	if(SiS_LCDResInfo==Panel1280x960) temp=0x24;
-    	if(SiS_VBInfo&SetCRT2ToTV) temp=0x08;
-    	if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-      		if(SiS_VBInfo&SetInSlaveMode) temp=0x2c;
-      		else temp=0x20;
-    	}
-  } else {
-    	temp=0x20;
-  }
 
-  if (HwDeviceExtension->jChipType < SIS_315H ) {
-    /* ---------- 300 series -------------- */
+ 	} else {
 
-    SiS_SetRegANDOR(SiS_Part1Port,0x13,~0x03C,temp); 	/* <----------------- */
-	/* TW: This register will be adapted according to LCD
-	 *     panel type later in the OEM setup functions.
-	 *     (Various panel types require a different delay
-	 *     such as Clevo 2202; however, on most panels,
-	 *     0x20 does nicely.)
-	 */
+#ifdef SIS315H
+     	   /* ---------------------- 310 series ------------------*/
 
-  } else {
-    /* ----------- 310 series ---------------*/
-    temp >>=2;    /* TW: This is typical SiS code: First calulate temp, then overwrite it... */
-    temp = 0x11;    						/*  ynlai 05/30/2001 for delay compenation  */
-    SiS_SetReg1(SiS_Part1Port,0x2D,temp);
-    /*SiS_SetRegANDOR(SiS_Part1Port,0x2D,~0x00F,temp);*/
-    SiS_SetRegAND(SiS_Part1Port,0x13,0xEF);  			/* BDirectLCD=0 for lcd ?? */
-    tempax=0;
+	        tempcx = SiS_Pr->SiS_VGAHT;				       /* BTVGA2HT 0x08,0x09 */
+		pushcx = tempcx;
+		if(modeflag & HalfDCLK)  tempcx >>= 1;
+		tempcx--;
+
+		temp = tempcx & 0xff;
+		SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,temp);                  /* TW: CRT2 Horizontal Total */
+
+		temp = ((tempcx & 0xff00) >> 8) << 4;
+		SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0F,temp);         /* TW: CRT2 Horizontal Total Overflow [7:4] */
+
+		tempcx = pushcx;					       /* BTVGA2HDEE 0x0A,0x0C */
+		tempbx = SiS_Pr->SiS_VGAHDE;
+		tempcx -= tempbx;
+		tempcx >>= 2;
+		if(modeflag & HalfDCLK) {
+		    tempbx >>= 1;
+		    tempcx >>= 1;
+		}
+		tempbx += 16;
+
+		temp = tempbx & 0xff;
+		SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0A,temp);                  /* TW: CRT2 Horizontal Display Enable End */
+
+		pushbx = tempbx;
+		tempcx >>= 1;
+		tempbx += tempcx;
+		tempcx += tempbx;
+
+		if(SiS_Pr->SiS_IF_DEF_LVDS==0) {
+             	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
+                	tempbx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[4];
+                	tempbx |= ((SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14] & 0xC0) << 2);
+                	tempbx = (tempbx - 3) << 3;         		/*(VGAHRS-3)*8 */
+                	tempcx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[5];
+               		tempcx &= 0x1F;
+                	temp = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[15];
+                	temp = (temp & 0x04) << (5-2);      		/* VGAHRE D[5] */
+                	tempcx = ((tempcx | temp) - 3) << 3;    	/* (VGAHRE-3)*8 */
+                	tempbx += 16;
+                	tempcx += 16;
+			tempax = SiS_Pr->SiS_VGAHT;
+			if (modeflag & HalfDCLK)  tempax >>= 1;
+			tempax--;
+			if (tempcx > tempax)  tempcx = tempax;
+             	   }
+         	   if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (resinfo == 0x08)){
+             	      if(!(SiS_Pr->SiS_VBInfo & SetPALTV)){
+      		 	 tempbx = 1040;
+      		 	 tempcx = 1042;
+      	     	      }
+         	   }
+		   /* TW: Makes no sense, but is in 650/301LVx 1.10.6s */
+         	   if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (resinfo == 0x08)){
+		      if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV)) {
+             	         if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+      		 	    tempbx = 1040;
+      		 	    tempcx = 1042;
+      	     	         }
+		      }
+         	   }
+                }
 
-    if (modeflag&DoubleScanMode) tempax |= 0x80;
-    if (modeflag&HalfDCLK) tempax |= 0x40;
-    SiS_SetRegANDOR(SiS_Part1Port,0x2C,~0x0C0,tempax);
-  }
+		temp = tempbx & 0xff;
+	 	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0B,temp);                 /* TW: CRT2 Horizontal Retrace Start */
 
-  if(SiS_IF_DEF_LVDS==0) {
-    	SiS_SetGroup1_301(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
-	                  HwDeviceExtension,RefreshRateTableIndex);
-  } else {
-    	SiS_SetGroup1_LVDS(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
-	                   HwDeviceExtension,RefreshRateTableIndex);
-  }
+#if 0      /* TW: Old code */
+     	   if (modeflag & HalfDCLK) {  /* for low resolution modes */
+
+         	temp = ((SiS_Pr->SiS_VGAHT / 2) - 1) & 0xFF;                    /* BTVGA2HT 0x08,0x09 */
+         	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,temp);                   /* TW: CRT2 Horizontal Total */
+
+		temp = ((((SiS_Pr->SiS_VGAHT / 2) - 1) & 0xFF00) >> 8) << 4;
+        	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0F,temp);        /* TW: CRT2 Horizontal Total Overflow [7:4] */
+
+         	temp = ((SiS_Pr->SiS_VGAHDE / 2) + 16) & 0xFF;                  /* BTVGA2HDEE 0x0A,0x0C */
+         	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0A,temp);                   /* TW: CRT2 Horizontal Display Enable End */
+
+         	pushbx = (SiS_Pr->SiS_VGAHDE / 2) + 16;
+         	tempcx = ((SiS_Pr->SiS_VGAHT - SiS_Pr->SiS_VGAHDE) / 2) >> 2;           /* cx */
+		if(SiS_Pr->SiS_IF_DEF_LVDS == 1)
+		           tempcx >>= 1;    /* TW: From LVDS 1.10.07; not done on 301(LV) */
+         	tempbx = pushbx + tempcx;                               /* bx  BTVGA@HRS 0x0B,0x0C */
+         	tempcx += tempbx;
+
+         	if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+                   if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC){
+                	tempbx = SiS_CRT1Table[CRT1Index].CR[4];
+                	tempbx |= ((SiS_CRT1Table[CRT1Index].CR[14] & 0xC0) << 2);
+                	tempbx = (tempbx - 3) << 3;         		/*(VGAHRS-3)*8 */
+                	tempcx = SiS_CRT1Table[CRT1Index].CR[5];
+               		tempcx &= 0x1F;
+                	temp = SiS_CRT1Table[CRT1Index].CR[15];
+                	temp = (temp & 0x04) << (5-2);      		/* VGAHRE D[5]  */
+                	tempcx =((tempcx | temp) - 3) << 3;    		/* (VGAHRE-3)*8 */
+             	   }
+                   /* TW: The following is not done in 650/LVDS BIOS  */
+         	   tempbx += 4;
+         	   tempcx += 4;
+
+         	   if (tempcx > (SiS_Pr->SiS_VGAHT / 2))
+              		   tempcx = SiS_Pr->SiS_VGAHT / 2;
+         	}
+
+                temp = tempbx & 0x00FF;
+         	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0B,temp);                  /* TW: CRT2 Horizontal Retrace Start */
+
+    	   } else {			/* for high resolution modes */
+
+         	temp = (SiS_Pr->SiS_VGAHT - 1) & 0xFF;                       	/* BTVGA2HT 0x08,0x09 */
+         	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,temp);                  /* TW: CRT2 Horizontal Total */
+
+         	temp = (((SiS_Pr->SiS_VGAHT - 1) & 0xFF00) >> 8 ) << 4;
+	 	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x09,0x0F,temp);         /* TW: CRT2 Horizontal Total Overflow [7:4] */
+
+         	temp = (SiS_Pr->SiS_VGAHDE + 16) & 0xFF;                       /* BTVGA2HDEE 0x0A,0x0C */
+	 	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0A,temp);                  /* TW: CRT2 Horizontal Display Enable End */
+
+         	pushbx = SiS_Pr->SiS_VGAHDE + 16;
+         	tempcx = (SiS_Pr->SiS_VGAHT - SiS_Pr->SiS_VGAHDE) >> 2;                /* cx */
+
+                /* TW: Done in 650/301LVx 1.10.6s */
+		/* if(SiS_Pr->SiS_IF_DEF_LVDS == 1) */
+                    tempcx >>= 1;    /* TW: From LVDS 1.10.07; not done on 301(LV), done in 301LVx 1.10.6s */
+
+         	tempbx = pushbx + tempcx;                              /* bx  BTVGA@HRS 0x0B,0x0C */
+         	tempcx += tempbx;
+
+         	if(SiS_Pr->SiS_IF_DEF_LVDS==0) {
+             	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC){
+                	tempbx = SiS_CRT1Table[CRT1Index].CR[4];
+                	tempbx |= ((SiS_CRT1Table[CRT1Index].CR[14] & 0xC0) << 2);
+                	tempbx = (tempbx - 3) << 3;         		/*(VGAHRS-3)*8 */
+                	tempcx = SiS_CRT1Table[CRT1Index].CR[5];
+               		tempcx &= 0x1F;
+                	temp = SiS_CRT1Table[CRT1Index].CR[15];
+                	temp = (temp & 0x04) << (5-2);      		/* VGAHRE D[5] */
+                	tempcx = ((tempcx | temp) - 3) << 3;    	/* (VGAHRE-3)*8 */
+                	tempbx += 16;
+                	tempcx += 16;
+             	   }
+		   /* TW: The entire following section is not done in 650/LVDS BIOS */
+         	   if (tempcx > SiS_Pr->SiS_VGAHT)
+        		tempcx = SiS_Pr->SiS_VGAHT;
+
+         	   if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (resinfo == 0x08)){
+             	      if(!(SiS_Pr->SiS_VBInfo & SetPALTV)){
+      		 	 tempbx = 1040;
+      		 	 tempcx = 1042;
+      	     	      }
+         	   }
+                }
+
+         	temp = tempbx & 0x00FF;
+	 	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0B,temp);                 /* TW: CRT2 Horizontal Retrace Start */
+
+	   } /* halfdclk */
+#endif
+#endif  /* SIS315H */
+
+     	}  /* 310 series */
+
+  	/* TW: The following is done for all bridge/chip types/series */
+
+  	tempax = tempbx & 0xFF00;
+  	tempbx = pushbx;
+  	tempbx = (tempbx & 0x00FF) | ((tempbx & 0xFF00) << 4);
+  	tempax |= (tempbx & 0xFF00);
+  	temp = (tempax & 0xFF00) >> 8;
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0C,temp);                        /* TW: Overflow */
+
+  	temp = tempcx & 0x00FF;
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0D,temp);                        /* TW: CRT2 Horizontal Retrace End */
+
+  	/* 2. Vertical setup */
+
+  	tempcx = SiS_Pr->SiS_VGAVT - 1;
+  	temp = tempcx & 0x00FF;
+
+	/* TW: Matches 650/301LV, 650/LVDS, 630/LVDS(CLEVO), 630/LVDS(no-Ch7005) */
+        if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+	     if(HwDeviceExtension->jChipType < SIS_315H) {
+	          if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+		       if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSVIDEO|SetCRT2ToAVIDEO)) {
+		           temp--;
+		       }
+                  }
+	     } else {
+	          if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+ 		      temp--;
+                  }
+             }
+        } else if(HwDeviceExtension->jChipType >= SIS_315H) {
+	    /* TW: Inserted from 650/301LVx 1.10.6s */
+	    temp--;
+	}
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0E,temp);                        /* TW: CRT2 Vertical Total */
+
+  	tempbx = SiS_Pr->SiS_VGAVDE - 1;
+  	temp = tempbx & 0x00FF;
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0F,temp);                        /* TW: CRT2 Vertical Display Enable End */
+
+  	temp = ((tempbx & 0xFF00) << 3) >> 8;
+  	temp |= ((tempcx & 0xFF00) >> 8);
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x12,temp);                        /* TW: Overflow (and HWCursor Test Mode) */
+
+	/* TW: For 650/LVDS (1.10.07), 650/301LVx (1.10.6s) */
+	if(HwDeviceExtension->jChipType >= SIS_315H) {
+           tempbx++;
+   	   tempax = tempbx;
+	   tempcx++;
+	   tempcx -= tempax;
+	   tempcx >>= 2;
+	   tempbx += tempcx;
+	   if(tempcx < 4) tempcx = 4;
+	   tempcx >>= 2;
+	   tempcx += tempbx;
+	   tempcx++;
+	} else {
+	   /* TW: For 630/LVDS/301B: */
+  	   tempbx = (SiS_Pr->SiS_VGAVT + SiS_Pr->SiS_VGAVDE) >> 1;                 /*  BTVGA2VRS     0x10,0x11   */
+  	   tempcx = ((SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) >> 4) + tempbx + 1;  /*  BTVGA2VRE     0x11        */
+	}
+
+  	if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+    	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC){
+      		tempbx = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[8];
+      		temp = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7];
+      		if(temp & 0x04) tempbx |= 0x0100;
+      		if(temp & 0x80) tempbx |= 0x0200;
+      		temp = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13];
+      		if(temp & 0x08) tempbx |= 0x0400;
+      		temp = SiS_Pr->SiS_CRT1Table[CRT1Index].CR[9];
+      		tempcx = (tempcx & 0xFF00) | (temp & 0x00FF);
+    	   }
+  	}
+  	temp = tempbx & 0x00FF;
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x10,temp);           /* TW: CRT2 Vertical Retrace Start */
+
+  	temp = ((tempbx & 0xFF00) >> 8) << 4;
+  	temp |= (tempcx & 0x000F);
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x11,temp);           /* TW: CRT2 Vert. Retrace End; Overflow; "Enable CRTC Check" */
+
+  	/* 3. Panel compensation delay */
+
+  	if (HwDeviceExtension->jChipType < SIS_315H ) {
+
+    	   /* ---------- 300 series -------------- */
+
+	   if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+	        temp = 0x20;
+#if 0           /* TW: Not in 630/301B BIOS */
+		if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) temp = 0x24;
+#endif
+		if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp = 0x08;
+#ifdef oldHV    /* TW: Not in 630/301B BIOS */
+		if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+      		    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) temp = 0x2c;
+      		    else temp = 0x20;
+    	        }
+#endif
+		if((ROMAddr) && (SiS_Pr->SiS_UseROM) && (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
+		    if(ROMAddr[0x220] & 0x80) {
+		        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV-SetCRT2ToHiVisionTV))
+				temp = ROMAddr[0x221];
+			else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV)
+				temp = ROMAddr[0x222];
+		        else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)
+				temp = ROMAddr[0x223];
+			else
+				temp = ROMAddr[0x224];
+			temp &= 0x3c;
+		    }
+		}
+		if(HwDeviceExtension->pdc) {
+			temp = HwDeviceExtension->pdc & 0x3c;
+		}
+	   } else {
+	        temp = 0x20;
+		if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) temp = 0x04;
+		if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+		    if(ROMAddr[0x220] & 0x80) {
+		        temp = ROMAddr[0x220] & 0x3c;
+		    }
+		}
+		if(HwDeviceExtension->pdc) {
+			temp = HwDeviceExtension->pdc & 0x3c;
+		}
+	   }
+
+    	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x03C,temp);         /* TW: Panel Link Delay Compensation; (Software Command Reset; Power Saving) */
+
+  	} else {
+
+      	   /* ----------- 310/325 series ---------------*/
+
+	   if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+                temp = 0x10;
+                if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)  temp = 0x2c;
+    	        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) temp = 0x20;
+    	        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960)  temp = 0x24;
+		if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)                     temp = 0x08;
+		tempbl = 0xF0;
+	   } else {
+	        temp = 0x00;
+		if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) temp = 0x0a;
+		tempbl = 0xF0;
+		if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) tempbl = 0x0F;
+	   }
+#if 0      /* TW: Not done in 650/301LVx 1.10.6s  */
+           if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+                 temp >>= 2;
+	   }
+#endif
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,tempbl,temp);	    /* TW: Panel Link Delay Compensation */
+
+    	   tempax = 0;
+    	   if (modeflag & DoubleScanMode) tempax |= 0x80;
+    	   if (modeflag & HalfDCLK)       tempax |= 0x40;
+    	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2C,0x3f,tempax);
+
+  	}
+
+     }  /* Slavemode */
+
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+
+        /* TW: 630/301B BIOS sets up Panel Link, too! (650/LV does not) */
+        if( (HwDeviceExtension->jChipType < SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
+	                       && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) ) {
+
+	    SiS_SetGroup1_LVDS(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+	                       HwDeviceExtension,RefreshRateTableIndex);
+
+        } else if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {                             
+
+    	    SiS_SetGroup1_301(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+	                      HwDeviceExtension,RefreshRateTableIndex);
+        }
+
+     } else {
+
+        if(HwDeviceExtension->jChipType < SIS_315H) {
+	     SiS_SetGroup1_LVDS(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+	                        HwDeviceExtension,RefreshRateTableIndex);
+	} else {
+	    /* TW: For 650/LVDS */
+            if((!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) || (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+    	         SiS_SetGroup1_LVDS(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+	                            HwDeviceExtension,RefreshRateTableIndex);
+            }
+	}
+
+     }
+   } /* LCDA */
 }
 
+/* TW: Checked against 650/301LV and 630/301B (II) BIOS */
+/* TW: Pass 2: Checked with 650/301LVx (1.10.6s) and 630/301B (2.04.5a) */
 void
-SiS_SetGroup1_301(USHORT  BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+SiS_SetGroup1_301(SiS_Private *SiS_Pr, USHORT  BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
                   PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex)
 {
   USHORT  push1,push2;
   USHORT  tempax,tempbx,tempcx,temp;
   USHORT  resinfo,modeflag;
-  USHORT  CRT1Index;
 
   if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-    	resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+    	resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
   } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-    	resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-    	CRT1Index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
-    	CRT1Index = CRT1Index &0x3F;
-  }
-
-  if(!(SiS_VBInfo&SetInSlaveMode))  return;
-
-  tempax=0xFFFF;
-  if(!(SiS_VBInfo&SetCRT2ToTV)) {
-    	tempax=SiS_GetVGAHT2();
-  }
-  if(modeflag&Charx8Dot) tempcx=0x08;
-  else tempcx=0x09;
-  if(tempax>=SiS_VGAHT) {
-    	tempax=SiS_VGAHT;
-  }
-  if(modeflag&HalfDCLK) {
-    	tempax=tempax>>1;
-  }
-  tempax=(tempax/tempcx)-5;
-  tempbx=tempax;
-  temp=0xFF;                                            	/* set MAX HT */
-  SiS_SetReg1(SiS_Part1Port,0x03,temp);
-
-  tempax=SiS_VGAHDE;                                           	/* 0x04 Horizontal Display End */
-  if(modeflag&HalfDCLK) tempax=tempax>>1;
-  tempax=(tempax/tempcx)-1;
-  tempbx=tempbx|((tempax&0x00FF)<<8);
-  temp=tempax&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x04,temp);
-
-  temp=(tempbx&0xFF00)>>8;
-  if(SiS_VBInfo&SetCRT2ToTV){
-    	temp=temp+2;
-    	if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-      		if(resinfo==7) temp=temp-2;
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  }
+
+  /* TW: The following is only done if bridge is in slave mode: */
+
+  tempax = 0xFFFF;
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV))  tempax = SiS_GetVGAHT2(SiS_Pr);
+
+  /* TW: 630/301B does not check this flag, assumes it is set */
+  /*     650/LV and 650/301LVx BIOS do not check this either; so we set it... */
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+  	modeflag |= Charx8Dot;
+  }
+
+  if(modeflag & Charx8Dot) tempcx = 0x08;
+  else tempcx = 0x09;
+
+  if(tempax >= SiS_Pr->SiS_VGAHT) tempax = SiS_Pr->SiS_VGAHT;
+
+  if(modeflag & HalfDCLK) tempax >>= 1;
+
+  tempax = (tempax / tempcx) - 5;
+  tempbx = tempax & 0xFF;
+
+  temp = 0xFF;                                                  /* set MAX HT */
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x03,temp);
+
+  tempax = SiS_Pr->SiS_VGAHDE;                                 	/* 0x04 Horizontal Display End */
+  if(modeflag & HalfDCLK) tempax >>= 1;
+  tempax = (tempax / tempcx) - 1;
+  tempbx |= ((tempax & 0x00FF) << 8);
+  temp = tempax & 0xFF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x04,temp);
+
+  temp = (tempbx & 0xFF00) >> 8;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV){
+        if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {        
+    	    temp += 2;
+        }
+#ifdef oldHV
+    	if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+            if(resinfo == 7) temp -= 2;
     	}
+#endif
   }
-  SiS_SetReg1(SiS_Part1Port,0x05,temp);                         /* 0x05 Horizontal Display Start */
-  SiS_SetReg1(SiS_Part1Port,0x06,0x03);                       	/* 0x06 Horizontal Blank end     */
-                                                           	/* 0x07 horizontal Retrace Start */
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-    temp=(tempbx&0x00FF)-1;
-    if(!(modeflag&HalfDCLK)) {
-      temp=temp-6;
-      if(SiS_SetFlag&TVSimuMode) {
-        temp=temp-4;
-        if(ModeNo>0x13) temp=temp-10;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x05,temp);                 /* 0x05 Horizontal Display Start */
+
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x06,0x03);                 /* 0x06 Horizontal Blank end     */
+
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+    temp = (tempbx & 0x00FF) - 1;
+    if(!(modeflag & HalfDCLK)) {
+      temp -= 6;
+      if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+        temp -= 2;
+        if(ModeNo > 0x13) temp -= 10;
       }
     }
   } else {
-    tempcx=tempbx&0x00FF;
-    tempbx=(tempbx&0xFF00)>>8;
-    tempcx=(tempcx+tempbx)>>1;
-    temp=(tempcx&0x00FF)+2;
-    if(SiS_VBInfo&SetCRT2ToTV){
-       temp=temp-1;
-       if(!(modeflag&HalfDCLK)){
-          if((modeflag&Charx8Dot)){
-            temp=temp+4;
-            if(SiS_VGAHDE>=800){
-              temp=temp-6;
-            }
+#endif
+    tempcx = tempbx & 0x00FF;
+    tempbx = (tempbx & 0xFF00) >> 8;
+    tempcx = (tempcx + tempbx) >> 1;
+    temp = (tempcx & 0x00FF) + 2;
+    if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV){
+       temp--;
+       if(!(modeflag & HalfDCLK)){
+          if((modeflag & Charx8Dot)){
+             temp += 4;
+             if(SiS_Pr->SiS_VGAHDE >= 800) temp -= 6;
+	     /* TW: Inserted from 650/301 BIOS, 630/301B/301 don't do this */
+             if(HwDeviceExtension->jChipType >= SIS_315H) {
+	         if(SiS_Pr->SiS_VGAHDE == 800) temp += 2;
+             }
           }
-        }
+       }
     } else {
-       if(!(modeflag&HalfDCLK)){
-         temp=temp-4;
-         if(SiS_LCDResInfo!=Panel1280x960) {
-           if(SiS_VGAHDE>=800){
-             temp=temp-7;
-             if(SiS_ModeType==ModeEGA){
-               if(SiS_VGAVDE==1024){
-                 temp=temp+15;
-                 if(SiS_LCDResInfo!=Panel1280x1024){
-                    temp=temp+7;
+       if(!(modeflag & HalfDCLK)) {
+         temp -= 4;
+         if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x960) {
+           if(SiS_Pr->SiS_VGAHDE >= 800){
+             temp -= 7;
+	     if(HwDeviceExtension->jChipType < SIS_315H) {
+	       /* 650/301LV(x) does not do this, 630/301B does */
+               if(SiS_Pr->SiS_ModeType == ModeEGA){
+                 if(SiS_Pr->SiS_VGAVDE == 1024){
+                   temp += 15;
+                   if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024) temp += 7;
                  }
                }
-             }
-             if(SiS_VGAHDE>=1280){
-               if(SiS_LCDResInfo!=Panel1280x960) {
-                 if(SiS_LCDInfo&LCDNonExpanding) {
-                   temp=temp+28;
-                 }
+	     }
+             if(SiS_Pr->SiS_VGAHDE >= 1280){
+               if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x960) {
+                 if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) temp += 28;
                }
              }
            }
          }
        }
     }
+#ifdef oldHV
   }
- 
-  SiS_SetReg1(SiS_Part1Port,0x07,temp);                       	/* 0x07 Horizontal Retrace Start */
-  SiS_SetReg1(SiS_Part1Port,0x08,0);                            /* 0x08 Horizontal Retrace End   */
-  
-  if(SiS_VBInfo&SetCRT2ToTV) {
-        if(SiS_SetFlag&TVSimuMode) {
-            if((ModeNo==0x06)||(ModeNo==0x10)||(ModeNo==0x11)||(ModeNo==0x13)||(ModeNo==0x0F)){
-             	SiS_SetReg1(SiS_Part1Port,0x07,0x5b);
-             	SiS_SetReg1(SiS_Part1Port,0x08,0x03);
-            }
-            if((ModeNo==0x00)||(ModeNo==0x01)) {
-             	if(SiS_VBInfo&SetNTSCTV) {
-             		SiS_SetReg1(SiS_Part1Port,0x07,0x2A);
-             		SiS_SetReg1(SiS_Part1Port,0x08,0x61);
-              	} else {
-             		SiS_SetReg1(SiS_Part1Port,0x07,0x2A);
-             		SiS_SetReg1(SiS_Part1Port,0x08,0x41);
-             		SiS_SetReg1(SiS_Part1Port,0x0C,0xF0);
-            	}
-           }
-           if((ModeNo==0x02)||(ModeNo==0x03)||(ModeNo==0x07)){
-            	if(SiS_VBInfo&SetNTSCTV) {
-           		SiS_SetReg1(SiS_Part1Port,0x07,0x54);
-           		SiS_SetReg1(SiS_Part1Port,0x08,0x00);
-            	} else {
-           		SiS_SetReg1(SiS_Part1Port,0x07,0x55);
-           		SiS_SetReg1(SiS_Part1Port,0x08,0x00);
-           		SiS_SetReg1(SiS_Part1Port,0x0C,0xF0);
-           	}
-           }
-           if((ModeNo==0x04)||(ModeNo==0x05)||(ModeNo==0x0D)||(ModeNo==0x50)){
-            	if(SiS_VBInfo&SetNTSCTV) {
-            		SiS_SetReg1(SiS_Part1Port,0x07,0x30);
-            		SiS_SetReg1(SiS_Part1Port,0x08,0x03);
-            	} else {
-           		SiS_SetReg1(SiS_Part1Port,0x07,0x2f);
-           		SiS_SetReg1(SiS_Part1Port,0x08,0x02);
-                }
-           }
-       } 
+#endif
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,temp);               	/* 0x07 Horizontal Retrace Start */
+
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x00);                 /* 0x08 Horizontal Retrace End   */
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+     if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+            if(ModeNo <= 1) {
+	        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x2a);
+		if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x61);
+		} else {
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x41);
+		}
+	    } else if(SiS_Pr->SiS_ModeType == ModeText) {
+	        if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x54);
+		} else {
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x55);
+		}
+		SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x00);
+	    } else if(ModeNo <= 0x13) {
+	        if(modeflag & HalfDCLK) {
+		    if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+		        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x30);
+			SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x03);
+		    } else {
+		        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x2f);
+			SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x02);
+		    }
+		} else {
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x5b);
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x03);
+		}
+	    } else if( ((HwDeviceExtension->jChipType >= SIS_315H) && (ModeNo == 0x50)) ||
+	               ((HwDeviceExtension->jChipType < SIS_315H) && (resinfo == 0 || resinfo == 1)) ) {
+	        if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x30);
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x03);
+		} else {
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,0x2f);
+		    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x08,0x03);
+		}
+	    }
+
+     }
   }
-  
-  SiS_SetReg1(SiS_Part1Port,0x18,0x03);                         	/* 0x18 SR08    */
-  SiS_SetRegANDOR(SiS_Part1Port,0x19,0xF0,0x00);
-  SiS_SetReg1(SiS_Part1Port,0x09,0xFF);                         	/* 0x09 Set Max VT    */
-
-  tempbx=SiS_VGAVT;
-  push1=tempbx;
-  tempcx=0x121;
-  tempbx=SiS_VGAVDE;                                        		/* 0x0E Virtical Display End */
-  if(tempbx==357) tempbx=350;
-  if(tempbx==360) tempbx=350;
-  if(tempbx==375) tempbx=350;
-  if(tempbx==405) tempbx=400;
-  if(tempbx==420) tempbx=400;
-  if(tempbx==525) tempbx=480;
-  push2=tempbx;
-  if(SiS_VBInfo&SetCRT2ToLCD) {
-    	if(SiS_LCDResInfo==Panel1024x768) {
-      		if(!(SiS_SetFlag&LCDVESATiming)) {
-        		if(tempbx==350) tempbx=tempbx+5;
-        		if(tempbx==480) tempbx=tempbx+5;
+
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x18,0x03);                	/* 0x18 SR08    */
+
+  SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x19,0xF0);
+
+  tempbx = SiS_Pr->SiS_VGAVT;
+  push1 = tempbx;
+
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x09,0xFF);                	/* 0x09 Set Max VT    */
+
+  tempcx = 0x121;
+  tempbx = SiS_Pr->SiS_VGAVDE;                               	/* 0x0E Vertical Display End */
+  if(tempbx == 357) tempbx = 350;
+  if(tempbx == 360) tempbx = 350;
+  if(tempbx == 375) tempbx = 350;
+  if(tempbx == 405) tempbx = 400;
+  if(tempbx == 420) tempbx = 400;
+  if(tempbx == 525) tempbx = 480;
+  push2 = tempbx;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+    	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+      		if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+        		if(tempbx == 350) tempbx += 5;
+        		if(tempbx == 480) tempbx += 5;
       		}
     	}
   }
   tempbx--;
-  temp=tempbx&0x00FF;
+  temp = tempbx & 0x00FF;
   tempbx--;
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x10,temp);                    		/* 0x10 vertical Blank Start */
-  tempbx=push2;
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x10,temp);        		/* 0x10 vertical Blank Start */
+
+  tempbx = push2;
   tempbx--;
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x0E,temp);
-  if(tempbx&0x0100){
-    	tempcx=tempcx|0x0002;
+  temp = tempbx & 0x00FF;
+#if 0
+  /* TW: Missing code from 630/301B 2.04.5a and 650/301LVx 1.10.6s (calles int 2f) */
+  if(xxx()) {
+      if(temp == 0xdf) temp = 0xda;
   }
-  tempax=0x000B;
-  if(modeflag&DoubleScanMode){
-    	tempax=tempax|0x08000;
+#endif
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0E,temp);
+
+  if(tempbx & 0x0100) {
+  	tempcx |= 0x0002;
+	if(SiS_Pr->SiS_VBType & VB_SIS301) tempcx |= 0x000a;
   }
-  if(tempbx&0x0200){
-    	tempcx=tempcx|0x0040;
+
+  tempax = 0x000B;
+  if(modeflag & DoubleScanMode) tempax |= 0x8000;
+
+  if(tempbx & 0x0200) {
+  	tempcx |= 0x0040;
+	if(SiS_Pr->SiS_VBType & VB_SIS301) tempax |= 0x2000;
   }
 
-  temp=(tempax&0xFF00)>>8;
-  SiS_SetReg1(SiS_Part1Port,0x0B,temp);
-  if(tempbx&0x0400){
-    	tempcx=tempcx|0x0600;
+  if(SiS_Pr->SiS_VBType & VB_SIS301) {
+        if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+	      if(SiS_Pr->SiS_VGAVDE == 480) {
+	             tempax = (tempax & 0x00ff) | 0x2000;
+		     if(modeflag & DoubleScanMode)  tempax |= 0x8000;
+	      }
+	}
   }
-  SiS_SetReg1(SiS_Part1Port,0x11,0x00);                         	/* 0x11 Vertival Blank End */
 
-  tempax=push1;
-  tempax=tempax-tempbx;                              			/* 0x0C Vertical Retrace Start */
-  tempax=tempax>>2;
-  push1=tempax;
+  temp = (tempax & 0xFF00) >> 8;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0B,temp);
 
-  if(resinfo!=0x09) {
-    	tempax=tempax<<1;
-    	tempbx=tempax+tempbx;
-  }
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-    	tempbx=tempbx-10;
-  } else {
-    	if(SiS_SetFlag&TVSimuMode) {
-      		if(SiS_VBInfo&SetPALTV) {
-        		tempbx=tempbx+40;
-      		}
+  if(tempbx & 0x0400) tempcx |= 0x0600;
+
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x11,0x00);                	/* 0x11 Vertical Blank End */
+
+  tempax = push1;
+  tempax -= tempbx;
+  tempax >>= 2;
+  push1 = tempax;
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+        /* TW: Inserted from 650/301LVx 1.10.6s */
+        if(ModeNo > 0x13) {
+	    if(resinfo != 0x09) {
+	        tempax <<= 1;
+		tempbx += tempax;
+	    }
+	} else {
+	    if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1400x1050) {
+	        tempax <<= 1;
+		tempbx += tempax;
+	    }
+	}
+  } else if((resinfo != 0x09) || (SiS_Pr->SiS_VBType & VB_SIS301)) {
+    	tempax <<= 1;
+    	tempbx += tempax;
+  }
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+    	tempbx -= 10;
+  } else {
+#endif
+    	if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+      	   if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+	       if(!(SiS_Pr->SiS_HiVision & 0x03)) {
+                    tempbx += 40;
+		    if(HwDeviceExtension->jChipType >= SIS_315H) {
+		       if(SiS_Pr->SiS_VGAHDE == 800) tempbx += 10;
+		    }
+      	       }
+	   }
     	}
+#ifdef oldHV
   }
-  tempax=push1;
-  tempax=tempax>>2;
+#endif
+  tempax = push1;
+  tempax >>= 2;
   tempax++;
-  tempax=tempax+tempbx;
-  push1=tempax;
-  if((SiS_VBInfo&SetPALTV)) {
-    	if(tempbx<=513)  {
-      		if(tempax>=513) {
-        		tempbx=513;
-      		}
+  tempax += tempbx;
+  push1 = tempax;
+  if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+    	if(tempbx <= 513)  {
+      		if(tempax >= 513) tempbx = 513;
     	}
   }
-  temp=(tempbx&0x00FF);
-  SiS_SetReg1(SiS_Part1Port,0x0C,temp);
-  tempbx--;
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x10,temp);
-  if(tempbx&0x0100){
-    	tempcx=tempcx|0x0008;
-  }
-  if(tempbx&0x0200){
-    	SiS_SetRegANDOR(SiS_Part1Port,0x0B,0x0FF,0x20);
-  }
-  tempbx++;
-  if(tempbx&0x0100){
-    	tempcx=tempcx|0x0004;
-  }
-  if(tempbx&0x0200){
-    	tempcx=tempcx|0x0080;
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0C,temp);			/* 0x0C Vertical Retrace Start */
+
+  if(!(SiS_Pr->SiS_VBType & VB_SIS301)) {
+  	tempbx--;
+  	temp = tempbx & 0x00FF;
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x10,temp);
+
+	if(tempbx & 0x0100) tempcx |= 0x0008;
+
+  	if(tempbx & 0x0200) {
+    		SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x0B,0x20);
+	}
+
+  	tempbx++;
   }
-  if(tempbx&0x0400){
-    	tempcx=tempcx|0x0C00;
+  if(tempbx & 0x0100) tempcx |= 0x0004;
+  if(tempbx & 0x0200) tempcx |= 0x0080;
+  if(tempbx & 0x0400) {
+        if(SiS_Pr->SiS_VBType & VB_SIS301) tempcx |= 0x0800;
+  	else                               tempcx |= 0x0C00;
+  }
+
+  tempbx = push1;
+  temp = tempbx & 0x00FF;
+  temp &= 0x0F;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0D,temp);        		/* 0x0D vertical Retrace End */
+
+  if(tempbx & 0x0010) tempcx |= 0x2000;
+
+  temp = tempcx & 0x00FF;
+  if(SiS_Pr->SiS_VBType & VB_SIS301) {
+	if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+	      if(SiS_Pr->SiS_VGAVDE == 480)  temp = 0xa3;
+	}
   }
-  tempbx=push1;
-  temp=tempbx&0x00FF;
-  temp=temp&0x0F;
-  SiS_SetReg1(SiS_Part1Port,0x0D,temp);                    		/* 0x0D vertical Retrace End */
-  if(tempbx&0x0010) {
-    	tempcx=tempcx|0x2000;
-  }
-
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x0A,temp);                    		/* 0x0A CR07 */
-  temp=(tempcx&0x0FF00)>>8;
-  SiS_SetReg1(SiS_Part1Port,0x17,temp);                    		/* 0x17 SR0A */
-  tempax=modeflag;
-  temp=(tempax&0xFF00)>>8;
-
-  temp=(temp>>1)&0x09;
-  SiS_SetReg1(SiS_Part1Port,0x16,temp);                    		/* 0x16 SR01 */
-  SiS_SetReg1(SiS_Part1Port,0x0F,0);                         		/* 0x0F CR14 */
-  SiS_SetReg1(SiS_Part1Port,0x12,0);                         		/* 0x12 CR17 */
-  if(SiS_LCDInfo&LCDRGB18Bit) temp=0x80;
-  else temp=0x00;
-  SiS_SetReg1(SiS_Part1Port,0x1A,temp);                         	/* 0x1A SR0E */
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0A,temp);                    		/* 0x0A CR07 */
+
+  temp = (tempcx & 0xFF00) >> 8;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x17,temp);                    		/* 0x17 SR0A */
+
+  tempax = modeflag;
+  temp = (tempax & 0xFF00) >> 8;
+  temp = (temp >> 1) & 0x09;
+  /* TW: Inserted from 630/301B and 650/301(LV/LVX) BIOS; not in 630/301 BIOS */
+  if(!(SiS_Pr->SiS_VBType & VB_SIS301)) {
+       temp |= 0x01;
+  }
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x16,temp);                    		/* 0x16 SR01 */
+
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0F,0x00);                        		/* 0x0F CR14 */
+
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x12,0x00);                        		/* 0x12 CR17 */
+
+  if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
+       if(HwDeviceExtension->jChipType >= SIS_315H) {
+           /* TW: Inserted from 650/301LVx 1.10.6s */
+           if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x01) {
+	       temp = 0x80;
+	   }
+       } else temp = 0x80;
+  } else  temp = 0x00;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1A,temp);                         	/* 0x1A SR0E */
+
   return;
 }
 
-/* TW: This seems to be for some of 301B/302B/301LV/302LV as well
- *     which confuses me. In init.c, there is code for these bridges
- *     which is executed ONLY if IF_DEF_LVDS is 0. The following
- *     is being called only if IF_DEF_LVDS is NOT 0, and it contains
- *     code for 301B et al as well. Is IF_DEF_LVDS now 0 or 1 on
- *     301B/302B/301LV/302LV?
- */
-void SiS_SetGroup1_LVDS(USHORT  BaseAddr,ULONG ROMAddr,USHORT ModeNo,
-		        USHORT ModeIdIndex,
-                        PSIS_HW_DEVICE_INFO HwDeviceExtension,
-			USHORT RefreshRateTableIndex)
-{
-  USHORT modeflag,resinfo;
-  USHORT push1,push2,tempax,tempbx,tempcx,temp,pushcx;
-  ULONG tempeax=0,tempebx,tempecx,tempvcfact=0;
+/* TW: Checked against 650/LVDS 1.10.07, 630/301B (I,II) and 630/LVDS BIOS */
+void
+SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr,USHORT  BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+		   USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+		   USHORT RefreshRateTableIndex)
+{
+  USHORT modeflag, resinfo;
+  USHORT push1, push2, tempax, tempbx, tempcx, temp, pushcx;
+  ULONG  tempeax=0, tempebx, tempecx, tempvcfact=0;
 
   if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      	/* si+St_ResInfo */
-    	resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+    	resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
   } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     	/* si+Ext_ResInfo */
-    	resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
   }
 
-  tempax=SiS_LCDHDES;
-  tempbx=SiS_HDE;
-  tempcx=SiS_HT;
-
-  tempcx=tempcx-tempbx;                                    		/* HT-HDE  */
-  if(SiS_LCDInfo&LCDNonExpanding) {
-    	if(SiS_LCDResInfo==Panel640x480)  tempbx=640;
-    	if(SiS_LCDResInfo==Panel800x600)  tempbx=800;
-    	if(SiS_LCDResInfo==Panel1024x768) tempbx=1024;
-  }
-  push1=tempax;
-  tempax=tempax+tempbx;                                    		/* lcdhdee  */
-  tempbx=SiS_HT;
-  if(tempax>=tempbx){
-    	tempax=tempax-tempbx;
-  }
-  push2=tempax;	                                                       	/* push ax   lcdhdee  */
-  tempcx=tempcx>>2;                                        		/* temp  */
-  tempcx=tempcx+tempax;                                    		/* lcdhrs  */
-  if(tempcx>=tempbx){
-    	tempcx=tempcx-tempbx;
-  }									/* v ah,cl  */
-  tempax=tempcx;
-  tempax=tempax>>3;                                        		/* BPLHRS */
-  temp=tempax&0x00FF;
-  if(SiS_LCDResInfo==Panel640x480){                         		/*adjust for panel 640x480*/
-      	temp=temp-4;
-  }
-  SiS_SetReg1(SiS_Part1Port,0x14,temp);		/* <------------------ */ 	/* Part1_14h  */
-  temp=(tempax&0x00FF)+10;
-  temp=temp&0x01F;
-  temp=temp|(((tempcx&0x00ff)&0x07)<<5);
-  /*fstn*/
-  if(SiS_IF_DEF_FSTN){
-      	temp=0x20;
-  }
-  SiS_SetReg1(SiS_Part1Port,0x15,temp);    	/* <------------------- */      /* Part1_15h  */
-  tempbx=push2;                                          			/* lcdhdee  */
-  tempcx=push1;                                         			/* lcdhdes  */
-  temp=(tempcx&0x00FF);
-  temp=temp&0x07;                                      				/* BPLHDESKEW  */
-  SiS_SetReg1(SiS_Part1Port,0x1A,temp);   	/* <------------------- */      /* Part1_1Ah  */
-  tempcx=tempcx>>3;                                        			/* BPLHDES */
-  temp=(tempcx&0x00FF);
-  if(ModeNo==0x5b){                            					/*fix fstn mode=5b*/
-      	temp--;
-  }
-  SiS_SetReg1(SiS_Part1Port,0x16,temp);    	/* <------------------- */      /* Part1_16h  */
-  if(tempbx&0x07) tempbx=tempbx+8;
-  tempbx=tempbx>>3;                                        			/* BPLHDEE  */
-  temp=tempbx&0x00FF;
-  if(ModeNo==0x5b){                            					/*fix fstn mode=5b*/
-      	temp--;
-  }
-  SiS_SetReg1(SiS_Part1Port,0x17,temp);   	/* <------------------- */      /* Part1_17h  */
-
-  tempcx=SiS_VGAVT;
-  tempbx=SiS_VGAVDE;
-  tempcx=tempcx-tempbx;                                    			/* GAVT-VGAVDE  */
-  tempbx=SiS_LCDVDES;			                    			/* VGAVDES  */
-
-  push1=tempbx;                                        				/* push bx temppush1 */
-  if(SiS_IF_DEF_TRUMPION==0){
-    	if(SiS_IF_DEF_CH7005==1) {
-      		if(SiS_VBInfo&SetCRT2ToTV) {
-        		tempax=SiS_VGAVDE;
-      		}
-    	}
-    	if(SiS_VBInfo&SetCRT2ToLCD) {
-      		if(SiS_LCDResInfo==Panel640x480)  tempax=480;
-      		if(SiS_LCDResInfo==Panel800x600)  tempax=600;
-      		if(SiS_LCDResInfo==Panel1024x768) tempax=768;
-      		if(SiS_LCDResInfo==Panel320x480)  tempax=480;
-    	}
-  } else tempax=SiS_VGAVDE;
+#ifdef LINUX_XF86
+#ifdef TWDEBUG
+  xf86DrvMsg(0, X_INFO, "(init301: LCDHDES 0x%03x LCDVDES 0x%03x)\n", SiS_Pr->SiS_LCDHDES, SiS_Pr->SiS_LCDVDES);
+  xf86DrvMsg(0, X_INFO, "(init301: HDE     0x%03x VDE     0x%03x)\n", SiS_Pr->SiS_HDE, SiS_Pr->SiS_VDE);
+  xf86DrvMsg(0, X_INFO, "(init301: VGAHDE  0x%03x VGAVDE  0x%03x)\n", SiS_Pr->SiS_VGAHDE, SiS_Pr->SiS_VGAVDE);
+  xf86DrvMsg(0, X_INFO, "(init301: HT      0x%03x VT      0x%03x)\n", SiS_Pr->SiS_HT, SiS_Pr->SiS_VT);
+  xf86DrvMsg(0, X_INFO, "(init301: VGAHT   0x%03x VGAVT   0x%03x)\n", SiS_Pr->SiS_VGAHT, SiS_Pr->SiS_VGAVT);
+#endif
+#endif
 
-  tempbx=tempbx+tempax;
-  tempax=SiS_VT;                                               			/* VT  */
-  if(tempbx>=SiS_VT){
-    	tempbx=tempbx-tempax;
-  }
-  push2=tempbx;                                        				/* push bx  temppush2  */
-  tempcx=tempcx>>1;
-  tempbx=tempbx+tempcx;
-  tempbx++;                                                			/* BPLVRS  */
-  if(tempbx>=tempax){
-    	tempbx=tempbx-tempax;
-  }
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x18,temp);       	/* <------------------- */      /* Part1_18h  */
-  tempcx=tempcx>>3;
-  tempcx=tempcx+tempbx;
-  tempcx++;                                                			/* BPLVRE  */
-  temp=tempcx&0x00FF;
-  temp=temp&0x0F;
-  SiS_SetRegANDOR(SiS_Part1Port,0x19,~0x00F,temp);   /* <-------------- */      /* Part1_19h  */
-
-  temp=(tempbx&0xFF00)>>8;
-  temp=temp&0x07;
-  temp=temp<<3;                                 				/* BPLDESKEW =0 */
-  tempbx=SiS_VGAVDE;
-  if(tempbx!=SiS_VDE){
-    	temp=temp|0x40;
-  }
-  if(SiS_SetFlag&EnableLVDSDDA) {
-    	temp=temp|0x40;
-  }
-  if(SiS_LCDInfo&LCDRGB18Bit) {
-    	temp=temp|0x80;
-  }
-  SiS_SetRegANDOR(SiS_Part1Port,0x1A,0x07,temp);  /* <----------------- */    	/* Part1_1Ah */
-
-  tempecx=SiS_VGAVT;
-  tempebx=SiS_VDE;
-  tempeax=SiS_VGAVDE;
-  tempecx=tempecx-tempeax;                                 			/* VGAVT-VGAVDE  */
-  tempeax=tempeax<<6;
-  temp=(USHORT)(tempeax%tempebx);
-  tempeax=tempeax/tempebx;
-  if(temp!=0){
-    	tempeax++;
-  }
-  tempebx=tempeax;                                        			/* BPLVCFACT  */
-
-  /* TW: Modified according to info from SiS - might be wrong */
-  /* if (!(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))) { */
-  if ((HwDeviceExtension->jChipType == SIS_540)||
-      (HwDeviceExtension->jChipType == SIS_630)||
-      (HwDeviceExtension->jChipType == SIS_730)||
-      (HwDeviceExtension->jChipType == SIS_300)) {
+  /* TW: Set up Panel Link */
 
-  	if(SiS_SetFlag&EnableLVDSDDA) {
-    		tempebx=tempebx&0x003F;
-  	}
-  	temp=(USHORT)(tempebx&0x00FF);
-  	SiS_SetReg1(SiS_Part1Port,0x1E,temp);                       		/* Part1_1Eh */
+  /* 1. Horizontal setup */
 
+  tempax = SiS_Pr->SiS_LCDHDES;
+
+  if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) && (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))) {
+  	tempax -= 8;
   }
-  /*add for 301b different 301*/
-  else if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-    	tempecx=SiS_VGAVT;
-    	tempebx=SiS_VDE;
-    	tempeax=SiS_VGAVDE;
-    	tempecx=tempecx-tempeax;                                 		/* VGAVT-VGAVDE  */
-    	tempeax=tempeax<<18;
-    	temp=(USHORT)(tempeax%tempebx);
-    	tempeax=tempeax/tempebx;
-    	if(temp!=0) tempeax++;
-    	tempebx=tempeax;                                        		/* BPLVCFACT  */
-    	tempvcfact=tempeax;       /*301b*/
-    	temp=(USHORT)(tempebx&0x00FF);
-    	SiS_SetReg1(SiS_Part1Port,0x37,temp);
-    	temp=(USHORT)((tempebx&0x00FF00)>>8);
-    	SiS_SetReg1(SiS_Part1Port,0x36,temp);
-    	temp=(USHORT)((tempebx&0x00030000)>>16);
-    	if(SiS_VDE==SiS_VGAVDE)	temp=temp|0x04;
-    	SiS_SetReg1(SiS_Part1Port,0x35,temp);
-  }
-  /*end for 301b*/
-  
-  tempbx=push2;                                        				/* p bx temppush2 BPLVDEE  */
-  tempcx=push1;			/* pop cx temppush1 NPLVDES */
-  push1=(USHORT)(tempeax&0xFFFF);
-  if(!(SiS_VBInfo&SetInSlaveMode)) {
-   	if(!SiS_IF_DEF_DSTN){
-    		if(SiS_LCDResInfo==Panel800x600) {
-      			if(resinfo==7) tempcx++;
-    		} else {
-      			if(SiS_LCDResInfo==Panel1024x768) {
-        			if(resinfo==8) tempcx++;
-       			}
-     		}
-   	}
-  }
-  temp=(tempbx&0xFF00)>>8;
-  temp=temp&0x07;
-  temp=temp<<3;
-  temp=temp|(((tempcx&0xFF00)>>8)&0x07);
-  SiS_SetReg1(SiS_Part1Port,0x1D,temp);     	/* <------------------- */     	/* Part1_1Dh */
-  temp=tempbx&0x00FF;
-  /*fstn*/
-  if(SiS_IF_DEF_FSTN){
-      	temp=temp+1;
-  }
-  SiS_SetReg1(SiS_Part1Port,0x1C,temp);      	/* <------------------- */   	/* Part1_1Ch  */
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x1B,temp);      	/* <------------------- */     	/* Part1_1Bh  */
-
-  tempecx=SiS_VGAHDE;
-  tempebx=SiS_HDE;
-  tempeax=tempecx;
-  tempeax=tempeax<<16;
-  tempeax=tempeax/tempebx;
-  if(tempebx==tempecx){
-    	tempeax=0xFFFF;
-  }
-  tempecx=tempeax;
-  tempeax=SiS_VGAHT; /* TW: Was SiS_VGAHDE;  - WRONG! - old (wrong) comment: "change VGAHT->VGAHDE"*/
-  tempeax=tempeax<<16;
-  tempeax=tempeax/tempecx;
-  tempecx=tempecx<<16;
-  tempeax=tempeax-1;
-  tempecx=tempecx|(tempeax&0x00FFFF);
-  temp=(USHORT)(tempecx&0x00FF);
-  SiS_SetReg1(SiS_Part1Port,0x1F,temp);  	/* <------------------- */    	/* Part1_1Fh  */
-
-  tempbx = SiS_VDE; /* TW: added this and if statement */
-  if (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-  	tempeax=SiS_VGAVDE;
-  	tempeax=tempeax<<18;          /*301b*/
-  	tempeax=tempeax/tempvcfact;
-  	tempbx=(USHORT) (tempeax&0x0FFFF);
-  }
-
-  if(SiS_LCDResInfo==Panel1024x768) tempbx--;
-
-  if(SiS_SetFlag&EnableLVDSDDA) tempbx=1;
-
-  temp=((tempbx&0xFF00)>>8)<<3;
-  temp=temp|(USHORT)(((tempecx&0x0000FF00)>>8)&0x07);
-  SiS_SetReg1(SiS_Part1Port,0x20,temp);  	/* <------------------- */    	/* Part1_20h */
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x21,temp);  	/* <------------------- */     	/* Part1_21h */
-  tempecx=tempecx>>16;                                     			/* BPLHCFACT  */
-  if(modeflag&HalfDCLK) {
-    	tempecx=tempecx>>1;
-  }
-  temp=(USHORT)((tempecx&0x0000FF00)>>8);
-  SiS_SetReg1(SiS_Part1Port,0x22,temp);     	/* <------------------- */      /* Part1_22h */
-  temp=(USHORT)(tempecx&0x000000FF);
-  SiS_SetReg1(SiS_Part1Port,0x23,temp); 	/* <------------------- */
- /*add dstn new register*/
-  if(SiS_IF_DEF_DSTN){
-     	SiS_SetReg1(SiS_Part1Port,0x1E,0x01);
-     	SiS_SetReg1(SiS_Part1Port,0x25,0x00);
-     	SiS_SetReg1(SiS_Part1Port,0x26,0x00);
-     	SiS_SetReg1(SiS_Part1Port,0x27,0x00);
-     	SiS_SetReg1(SiS_Part1Port,0x28,0x87);
-     	SiS_SetReg1(SiS_Part1Port,0x29,0x5A);
-     	SiS_SetReg1(SiS_Part1Port,0x2A,0x4B);
-     	SiS_SetRegANDOR(SiS_Part1Port,0x44,~0x007,0x03);
-     	tempbx=SiS_HDE;                              				/*Blps=lcdhdee(lcdhdes+HDE) +64*/
-     	tempbx=tempbx+64;
-     	temp=tempbx&0x00FF;
-     	SiS_SetReg1(SiS_Part1Port,0x38,temp);
-     	temp=((tempbx&0xFF00)>>8)<<3;
-     	SiS_SetRegANDOR(SiS_Part1Port,0x35,~0x078,temp);
-     	tempbx=tempbx+32;		       					/*Blpe=lBlps+32*/
-     	temp=tempbx&0x00FF;
-     	/*fstn*/
-     	if(SiS_IF_DEF_FSTN){
-         	temp=0;
-     	}
-     	SiS_SetReg1(SiS_Part1Port,0x39,temp);
-     	SiS_SetReg1(SiS_Part1Port,0x3A,0x00);  /*Bflml=0*/
-     	SiS_SetRegANDOR(SiS_Part1Port,0x3C,~0x007,0x00);
-     	tempbx=SiS_VDE;
-     	tempbx=tempbx/2;
-     	temp=tempbx&0x00FF;
-     	SiS_SetReg1(SiS_Part1Port,0x3B,temp);
-     	temp=((tempbx&0xFF00)>>8)<<3;
-     	SiS_SetRegANDOR(SiS_Part1Port,0x3C,~0x038,temp);
-     	tempeax=SiS_HDE;                       					/* BDxFIFOSTOP= (HDE*4)/128 */
-     	tempeax=tempeax*4;
-     	tempebx=128;
-     	temp=(USHORT)(tempeax%tempebx);
-     	tempeax=tempeax/tempebx;
-     	if(temp!=0){
-      		tempeax++;
-     	}
-     	temp=(USHORT)(tempeax&0x0000003F);
-     	SiS_SetRegANDOR(SiS_Part1Port,0x45,~0x0FF,temp);
-     	SiS_SetReg1(SiS_Part1Port,0x3F,0x00);           			/*BDxWadrst0*/
-     	SiS_SetReg1(SiS_Part1Port,0x3E,0x00);
-     	SiS_SetReg1(SiS_Part1Port,0x3D,0x10);
-     	SiS_SetRegANDOR(SiS_Part1Port,0x3C,~0x040,0x00);
-     	tempax=SiS_HDE;
-     	tempax=tempax>>4;                                			/*BDxWadroff = HDE*4/8/8  */
-     	pushcx=tempax;
-     	temp=tempax&0x00FF;
-     	SiS_SetReg1(SiS_Part1Port,0x43,temp);
-     	temp=((tempax&0xFF00)>>8)<<3;
-     	SiS_SetRegANDOR(SiS_Part1Port,0x44,~0x0F8,temp);
-     	tempax=SiS_VDE;                        					/*BDxWadrst1 = BDxWadrst0+BDxWadroff*VDE*/
-     	tempeax=(tempax*pushcx);
-     	tempebx=0x00100000+tempeax;
-     	temp=(USHORT)tempebx&0x000000FF;
-     	SiS_SetReg1(SiS_Part1Port,0x42,temp);
-     	temp=(USHORT)((tempebx&0x0000FF00)>>8);
-     	SiS_SetReg1(SiS_Part1Port,0x41,temp);
-     	temp=(USHORT)((tempebx&0x00FF0000)>>16);
-     	SiS_SetReg1(SiS_Part1Port,0x40,temp);
-     	temp=(USHORT)((tempebx&0x01000000)>>24);
-     	temp=temp<<7;
-     	SiS_SetRegANDOR(SiS_Part1Port,0x3C,~0x080,temp);
-     	SiS_SetReg1(SiS_Part1Port,0x2F,0x03);
-     	SiS_SetReg1(SiS_Part1Port,0x03,0x50);
-     	SiS_SetReg1(SiS_Part1Port,0x04,0x00);
-     	SiS_SetReg1(SiS_Part1Port,0x2F,0x01);
-     	SiS_SetReg1(SiS_Part1Port,0x13,0x00);
-     	SiS_SetReg1(SiS_P3c4,0x05,0x86);
-     	SiS_SetReg1(SiS_P3c4,0x1e,0x62);
-     	/*fstn*/
-     	if(SiS_IF_DEF_FSTN){
-         	SiS_SetReg1(SiS_P3c4,0x2b,0x1b);
-         	SiS_SetReg1(SiS_P3c4,0x2c,0xe3);
-         	SiS_SetReg1(SiS_P3c4,0x1e,0x62);
-         	SiS_SetReg1(SiS_P3c4,0x2e,0x04);
-         	SiS_SetReg1(SiS_P3c4,0x2f,0x42);
-         	SiS_SetReg1(SiS_P3c4,0x32,0x01);
-         	SiS_SetReg1(SiS_Part1Port,0x2b,0x02);
-         	SiS_SetReg1(SiS_Part1Port,0x2c,0x00);
-         	SiS_SetReg1(SiS_Part1Port,0x2d,0x00);
-     	}
-     	/*end add fstn*/
-     	SiS_SetRegANDOR(SiS_Part1Port,0x19,0x00f,0x30);
-     	SiS_SetReg1(SiS_Part1Port,0x1e,0x7d);
-     	SiS_SetReg1(SiS_Part1Port,0x2e,0xe0);
-  }
-  /*end add dstn*/
-  return;
-}
 
-/*301b*/
-void
-SiS_SetGroup1_LCDA(USHORT  BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                   PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex)
-{
-  USHORT modeflag,resinfo;
-  USHORT push1,push2,tempax,tempbx,tempcx,temp;
-  ULONG tempeax=0,tempebx,tempecx,tempvcfact;/*301b*/
+  tempcx = SiS_Pr->SiS_HT;    				  /* Horiz. Total */
 
-  SiS_SetRegOR(SiS_Part1Port,0x2D,0x20);
-  
-  if(ModeNo<=0x13) {
-    modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-    resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
-  } else {
-    modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-    resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  tempbx = SiS_Pr->SiS_HDE;                               /* Horiz. Display End */
+
+  if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) {
+    if(!SiS_Pr->SiS_IF_DEF_DSTN) {
+ 	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)        tempbx = 800;
+    	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)  tempbx = 1024;
+	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)  tempbx = 1024;  /* TW: not done in BIOS */
+	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768)  tempbx = 1152;  /* TW: not done in BIOS */
+	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempbx = 1280;  /* TW */
+        else if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)   tempbx = 1400;  /* TW */
+    }
   }
+  tempcx = (tempcx - tempbx) >> 2;		 /* HT-HDE / 4 */
 
-  tempax=SiS_LCDHDES;
-  tempbx=SiS_HDE;
-  tempcx=SiS_HT;
-  
-  if(SiS_LCDInfo&LCDNonExpanding) {
-    	if(SiS_LCDResInfo==Panel1280x1024) tempbx=1280;
-    	if(SiS_LCDResInfo==Panel1024x768) tempbx=1024;
-  }
-  tempcx=tempcx-tempbx;                                    	/* HT-HDE  */
-  push1=tempax;
-  tempax=tempax+tempbx;                                    	/* lcdhdee  */
-  tempbx=SiS_HT;
-  if(tempax>=tempbx){
-   	tempax=tempax-tempbx;
-  }
-  push2=tempax;
-                                                           	/* push ax   lcdhdee  */
-  tempcx=tempcx>>2;                                        	/* temp  */
-  tempcx=tempcx+tempax;                                    	/* lcdhrs  */
-  if(tempcx>=tempbx){
-    	tempcx=tempcx-tempbx;
+  push1 = tempax;
+
+  tempax += tempbx;
+
+  if(tempax >= SiS_Pr->SiS_HT) tempax -= SiS_Pr->SiS_HT;
+
+  push2 = tempax;
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+       if(!SiS_Pr->SiS_IF_DEF_DSTN){
+     	  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)        tempcx = 0x0028;
+     	  else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempcx = 0x0030;
+     	  else if( (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) ||
+		   (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) ) {
+	  	if(HwDeviceExtension->jChipType < SIS_315H) {
+		     if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+		           tempcx = 0x0017;
+#ifdef TWNEWPANEL
+			   tempcx = 0x0018;
+#endif
+		     } else {
+		           tempcx = 0x0017;  /* A901; other 301B BIOS 0x0018; */
+		     }
+		} else {
+		     tempcx = 0x0018;
+		}
+	  }
+	  else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)  tempcx = 0x0018;
+     	  else if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)   tempcx = 0x0030;
+       }
   }
-                                                           	/* v ah,cl  */
-  tempax=tempcx;
-  tempax=tempax>>3;                                        	/* BPLHRS */
-  temp=tempax&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x14,temp);                         /* Part1_14h  */
-  temp=(tempax&0x00FF)+10;
-  temp=temp&0x01F;
-  temp=temp|(((tempcx&0x00ff)&0x07)<<5);
-  SiS_SetReg1(SiS_Part1Port,0x15,temp);                         /* Part1_15h  */
-  tempbx=push2;                                          	/* lcdhdee  */
-  tempcx=push1;                                          	/* lcdhdes  */
-  temp=(tempcx&0x00FF);
-  temp=temp&0x07;                                      		/* BPLHDESKEW  */
-  SiS_SetReg1(SiS_Part1Port,0x1A,temp);                         /* Part1_1Ah  */
-  tempcx=tempcx>>3;                                        	/* BPLHDES */
-  temp=(tempcx&0x00FF);
-  SiS_SetReg1(SiS_Part1Port,0x16,temp);                         /* Part1_16h  */
-  if(tempbx&0x07) tempbx=tempbx+8;
-  tempbx=tempbx>>3;                                        	/* BPLHDEE  */
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x17,temp);                        	/* Part1_17h  */
-
-  tempcx=SiS_VGAVT;
-  tempbx=SiS_VGAVDE;
-  tempcx=tempcx-tempbx;                                    	/* GAVT-VGAVDE  */
-  tempbx=SiS_LCDVDES;                                          	/* VGAVDES  */
-  push1=tempbx;                                        		/* push bx temppush1 */
-  if(SiS_IF_DEF_TRUMPION==0){
-    if(SiS_IF_DEF_CH7005==1) {
-      if(SiS_VBInfo&SetCRT2ToTV) {
-        tempax=SiS_VGAVDE;
-      }
-    }
-    if(SiS_LCDResInfo==Panel1024x768) tempax=768;
-    if(SiS_LCDResInfo==Panel1280x1024)  tempax=1024;
-  }
-  else tempax=SiS_VGAVDE;
-  tempbx=tempbx+tempax;
-  tempax=SiS_VT;                                               	/* VT  */
-  if(tempbx>=SiS_VT){
-    tempbx=tempbx-tempax;
-  }
-  push2=tempbx;                                        		/* push bx  temppush2  */
-  tempcx=tempcx>>1;
-  tempbx=tempbx+tempcx;
-  tempbx++;                                                	/* BPLVRS  */
-  if(tempbx>=tempax){
-    tempbx=tempbx-tempax;
+
+  tempcx += tempax;                              /* lcdhrs  */
+  if(tempcx >= SiS_Pr->SiS_HT) tempcx -= SiS_Pr->SiS_HT;
+
+  tempax = tempcx >> 3;                          /* BPLHRS */
+  temp = tempax & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x14,temp);		 /* Part1_14h; TW: Panel Link Horizontal Retrace Start  */
+
+  temp = (tempax & 0x00FF) + 10;
+
+  /* TW: Inserted this entire "if"-section from 650/LVDS BIOS */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+      if(!SiS_Pr->SiS_IF_DEF_DSTN){
+        if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+	  temp += 6;
+          if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel800x600) {
+	    temp++;
+	    if(HwDeviceExtension->jChipType >= SIS_315H) {
+	       if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1024x768) {
+	          temp -= 3;
+	       }
+	    }
+	  }
+        }
+      }
   }
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x18,temp);                         /* Part1_18h  */
-  tempcx=tempcx>>3;
-  tempcx=tempcx+tempbx;
-  tempcx++;                                                	/* BPLVRE  */
-  temp=tempcx&0x00FF;
-  temp=temp&0x0F;
-  SiS_SetRegANDOR(SiS_Part1Port,0x19,~0x00F,temp);               /* Part1_19h  */
-  temp=(tempbx&0xFF00)>>8;
-  temp=temp&0x07;
-  temp=temp<<3;                                 		/* BPLDESKEW =0 */
-  tempbx=SiS_VGAVDE;
-  if(tempbx!=SiS_VDE){
-    temp=temp|0x40;
+
+  temp &= 0x1F;
+  temp |= ((tempcx & 0x0007) << 5);
+  if(SiS_Pr->SiS_IF_DEF_FSTN) temp = 0x20;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x15,temp);    	 /* Part1_15h; TW: Panel Link Horizontal Retrace End/Skew */
+
+  tempbx = push2;
+  tempcx = push1;                                /* lcdhdes  */
+
+  temp = (tempcx & 0x0007);                      /* BPLHDESKEW  */
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1A,temp);   	 /* Part1_1Ah; TW: Panel Link Vertical Retrace Start (2:0) */
+
+  tempcx >>= 3;                                  /* BPLHDES */
+  temp = (tempcx & 0x00FF);
+  if(ModeNo == 0x5b) temp--;                     /* fix fstn mode=5b */
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x16,temp);    	 /* Part1_16h; TW: Panel Link Horizontal Display Enable Start  */
+
+  if(HwDeviceExtension->jChipType < SIS_315H) {  /* TW: Not done in LVDS BIOS 1.10.07 */
+     if(tempbx & 0x07) tempbx += 8;              /* TW: Done in 630/301B and 630/LVDS BIOSes */
+  }
+  tempbx >>= 3;                                  /* BPLHDEE  */
+  temp = tempbx & 0x00FF;
+  if(ModeNo == 0x5b) temp--;			 /* fix fstn mode=5b */
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x17,temp);   	 /* Part1_17h; TW: Panel Link Horizontal Display Enable End  */
+
+  /* 2. Vertical setup */
+
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+
+      /* TW: This entire section from 630/301B and 630/LVDS/LVDS+CH BIOS */
+      tempcx = SiS_Pr->SiS_VGAVT;
+      tempbx = SiS_Pr->SiS_VGAVDE;
+      if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) {
+         if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+	    tempbx = 600;
+	    if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel800x600) {
+	       tempbx = 768;
+	       if( (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1024x768) &&
+	           (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1152x768) ) {
+	 	    tempbx = 600;
+	       }
+	    }
+         }
+      }
+      tempcx -= tempbx;
+
+  } else {
+
+      tempcx = SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE;          /* VGAVT-VGAVDE  */
+
+  }
+
+  tempbx = SiS_Pr->SiS_LCDVDES;	   		 	 	/* VGAVDES  */
+  push1 = tempbx;
+
+  tempax = SiS_Pr->SiS_VGAVDE;
+
+  if((SiS_Pr->SiS_IF_DEF_TRUMPION == 0) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))
+                                && (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)) {
+    	if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	    if(!SiS_Pr->SiS_IF_DEF_DSTN){
+      		if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)        tempax = 600;
+      		else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)  tempax = 768;
+		else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)  tempax = 600;   /* TW */
+      		else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768)  tempax = 768;   /* TW */
+		else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempax = 1024;  /* TW */
+		else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempax = 1050;  /* TW */
+		else                                                          tempax = 600;
+            }
+    	}
   }
-  if(SiS_SetFlag&EnableLVDSDDA) {
-    temp=temp|0x40;
+
+  tempbx += tempax;
+  if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT;
+
+  push2 = tempbx;
+
+  tempcx >>= 1;
+
+  if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)){
+     if(!SiS_Pr->SiS_IF_DEF_DSTN){
+     	if( (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) ||
+	    (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) ) {   /* TW: @@@ TEST - not in BIOS! */
+	     	tempcx = 0x0001;
+     	} else if( (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) ||
+	           (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) ) {
+		if(HwDeviceExtension->jChipType < SIS_315H) {
+		      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+			    tempcx = 0x0002;
+#ifdef TWNEWPANEL
+			    tempcx = 0x0003;
+#endif
+		      } else {
+		            tempcx = 0x0002;   /* TW: A901; other 301B BIOS sets 0x0003; */
+		      }
+		} else tempcx = 0x0003;
+        }
+     	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768)  tempcx = 0x0003;
+     	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempcx = 0x0001;
+     	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempcx = 0x0001;
+     	else 				                              tempcx = 0x0057;
+     }
+  }
+
+  tempbx += tempcx;			 	/* BPLVRS  */
+
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+      tempbx++;
   }
-  if(SiS_LCDInfo&LCDRGB18Bit) {
-    temp=temp|0x80;
+
+  if(tempbx >= SiS_Pr->SiS_VT) tempbx -= SiS_Pr->SiS_VT;
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x18,temp);       	 /* Part1_18h; TW: Panel Link Vertical Retrace Start  */
+
+  tempcx >>= 3;
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+     if( (HwDeviceExtension->jChipType < SIS_315H) &&
+         (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) )     tempcx = 0x0001;
+     else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)  tempcx = 0x0002;
+     else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)    tempcx = 0x0003;
+     else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)   tempcx = 0x0005;
+     else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768)   tempcx = 0x0005;
+     else if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)  {
+     		if(HwDeviceExtension->jChipType < SIS_315H) {
+		        if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+				tempcx = 0x0004;
+#ifdef TWNEWPANEL
+				tempcx = 0x0005;
+#endif
+		        } else {
+				tempcx = 0x0004;   /* A901; Other BIOS sets 0x0005; */
+			}
+		} else {
+			tempcx = 0x0005;
+		}
+     }
   }
-  SiS_SetRegANDOR(SiS_Part1Port,0x1A,0x07,temp);             	/* Part1_1Ah */
-  
-  tempbx=push2;                                        		/* p bx temppush2 BPLVDEE  */
-  tempcx=push1;                                        		/* pop cx temppush1 NPLVDES */
-  push1=(USHORT)(tempeax&0xFFFF);
-    
-  if(!(SiS_VBInfo&SetInSlaveMode)) {
-    if(SiS_LCDResInfo==Panel800x600) {
-      if(resinfo==7) tempcx++;
-    } else {
-      if(SiS_LCDResInfo==Panel1024x768) {
-        if(resinfo==8) tempcx++;
+
+  tempcx = tempcx + tempbx + 1;                  /* BPLVRE  */
+  temp = tempcx & 0x000F;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xf0,temp); /* Part1_19h; TW: Panel Link Vertical Retrace End (3:0); Misc.  */
+
+  temp = ((tempbx & 0x0700) >> 8) << 3;          /* BPLDESKEW =0 */
+  if(SiS_Pr->SiS_VGAVDE != SiS_Pr->SiS_VDE)  temp |= 0x40;
+  if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA)    temp |= 0x40;
+  if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)   {
+      if(HwDeviceExtension->jChipType >= SIS_315H) {
+         if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x01) {	/* TW: Inserted from 650/LVDS 1.10.07 */
+            temp |= 0x80;
+         }
+      } else {
+	 if( (HwDeviceExtension->jChipType == SIS_630) ||
+	     (HwDeviceExtension->jChipType == SIS_730) ) {
+	    if(HwDeviceExtension->jChipRevision >= 0x30) {
+	       temp |= 0x80;
+	    }
+	 }
       }
-    }
+  }         /* TW: in follwing line, 0x87 was 0x07 (modified according to 650/LVDS BIOS) */
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1A,0x87,temp);  /* Part1_1Ah; TW: Panel Link Control Signal (7:3); Vertical Retrace Start (2:0) */
+
+  if (HwDeviceExtension->jChipType < SIS_315H) {
+
+        /* 300 series */
+
+        tempeax = SiS_Pr->SiS_VGAVDE << 6;
+        temp = (USHORT)(tempeax % (ULONG)SiS_Pr->SiS_VDE);
+        tempeax = tempeax / (ULONG)SiS_Pr->SiS_VDE;
+        if(temp != 0) tempeax++;
+        tempebx = tempeax;                         /* BPLVCFACT  */
+
+  	if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA) {
+	     tempebx = 0x003F;
+	}
+
+  	temp = (USHORT)(tempebx & 0x00FF);
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1E,temp);      /* Part1_1Eh; TW: Panel Link Vertical Scaling Factor */
+
+  } else {
+
+        /* 310/325 series */
+
+	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1E,0x23);
+
+	tempeax = SiS_Pr->SiS_VGAVDE << 18;
+    	temp = (USHORT)(tempeax % (ULONG)SiS_Pr->SiS_VDE);
+    	tempeax = tempeax / SiS_Pr->SiS_VDE;
+    	if(temp != 0) tempeax++;
+    	tempebx = tempeax;                         /* BPLVCFACT  */
+        tempvcfact = tempeax;
+    	temp = (USHORT)(tempebx & 0x00FF);
+    	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x37,temp);      /* Part1_37h; TW: Panel Link Vertical Scaling Factor */
+    	temp = (USHORT)((tempebx & 0x00FF00) >> 8);
+    	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x36,temp);      /* Part1_36h; TW: Panel Link Vertical Scaling Factor */
+    	temp = (USHORT)((tempebx & 0x00030000) >> 16);
+    	if(SiS_Pr->SiS_VDE == SiS_Pr->SiS_VGAVDE) temp |= 0x04;
+    	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x35,temp);      /* Part1_35h; TW: Panel Link Vertical Scaling Factor */
+
   }
 
-  temp=(tempbx&0xFF00)>>8;
-  temp=temp&0x07;
-  temp=temp<<3;
-  temp=temp|(((tempcx&0xFF00)>>8)&0x07);
-  SiS_SetReg1(SiS_Part1Port,0x1D,temp);                          /* Part1_1Dh */
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x1C,temp);                          /* Part1_1Ch  */
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x1B,temp);                          /* Part1_1Bh  */ 
-
-  tempecx=SiS_VGAVT;
-  tempebx=SiS_VDE;
-  tempeax=SiS_VGAVDE;
-  tempecx=tempecx-tempeax;                                 	/* VGAVT-VGAVDE  */
-  tempeax=tempeax<<18;
-  temp=(USHORT)(tempeax%tempebx);
-  tempeax=tempeax/tempebx;
-  if(temp!=0){
-    tempeax++;
-  }
-  tempebx=tempeax;                                        	/* BPLVCFACT  */
-  tempvcfact=tempeax;       /*301b*/
-  temp=(USHORT)(tempebx&0x00FF);
-  SiS_SetReg1(SiS_Part1Port,0x37,temp);   
-  temp=(USHORT)((tempebx&0x00FF00)>>8);
-  SiS_SetReg1(SiS_Part1Port,0x36,temp);   
-  temp=(USHORT)((tempebx&0x00030000)>>16);
-  if(SiS_VDE==SiS_VGAVDE) {
-      temp=temp|0x04;
+  tempbx = push2;                                  /* p bx temppush1 BPLVDEE  */
+  tempcx = push1;
+
+  push1 = temp;					   /* TW: For 630/301B and 630/LVDS */
+
+  if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+   	if(!SiS_Pr->SiS_IF_DEF_DSTN){
+		if(HwDeviceExtension->jChipType < SIS_315H) {
+			if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+      				if(resinfo == 15) tempcx++;
+				if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) {
+					if(resinfo == 7) tempcx++;
+		    		}
+			} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
+      				if(resinfo == 7) tempcx++;
+				if(resinfo == 8) tempcx++; /* TW: Doesnt make sense anyway... */
+			} else  if(resinfo == 8) tempcx++;
+		} else {
+			if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
+      				if(resinfo == 7) tempcx++;
+			}
+		}
+	}
   }
-  
-  SiS_SetReg1(SiS_Part1Port,0x35,temp);   
-  
-  tempecx=SiS_VGAHDE;
-  tempebx=SiS_HDE;
-  tempeax=tempecx;
-  tempeax=tempeax<<6;
-  tempeax=tempeax<<10;
-  tempeax=tempeax/tempebx;
-  if(tempebx==tempecx){
-    	tempeax=0xFFFF;
-  }
-  tempecx=tempeax;
-  tempeax=SiS_VGAHDE;  /*301b to change HT->HDE*/
-  tempeax=tempeax<<6;
-  tempeax=tempeax<<10;
-  tempeax=tempeax/tempecx;
-  tempecx=tempecx<<16;
-  tempeax=tempeax-1;
-  tempecx=tempecx|(tempeax&0x00FFFF);
-  temp=(USHORT)(tempecx&0x00FF);
-  SiS_SetReg1(SiS_Part1Port,0x1F,temp);                          /* Part1_1Fh  */
-
-  tempeax=SiS_VGAVDE;
-  tempeax=tempeax<<18;          /*301b*/
-  tempeax=tempeax/tempvcfact;
-  tempbx=(USHORT) (tempeax&0x0FFFF);
-  if(SiS_LCDResInfo==Panel1024x768) tempbx--;
-  if(SiS_SetFlag&EnableLVDSDDA){
-    	tempbx=1;
-  }
-  temp=((tempbx&0xFF00)>>8)<<3;
-  temp=temp|(USHORT)(((tempecx&0x0000FF00)>>8)&0x07);
-  SiS_SetReg1(SiS_Part1Port,0x20,temp);                         /* Part1_20h */
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part1Port,0x21,temp);                         /* Part1_21h */
-  tempecx=tempecx>>16;                                     	/* BPLHCFACT  */
- 
-  temp=(USHORT)((tempecx&0x0000FF00)>>8);
-  SiS_SetReg1(SiS_Part1Port,0x22,temp);                         /* Part1_22h */
-  temp=(USHORT)(tempecx&0x000000FF);
-  SiS_SetReg1(SiS_Part1Port,0x23,temp);
-  
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-  	SiS_SetReg1(SiS_Part1Port,0x1e,0x20);  /* for 650 & 550 lvds part */
+
+  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
+     tempcx = SiS_Pr->SiS_VGAVDE;
+     tempbx = SiS_Pr->SiS_VGAVDE - 1;
+  }
+
+  temp = ((tempbx & 0x0700) >> 8) << 3;
+  temp |= ((tempcx & 0x0700) >> 8);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1D,temp);     	/* Part1_1Dh; TW: Vertical Display Overflow; Control Signal */
+
+  temp = tempbx & 0x00FF;
+  if(SiS_Pr->SiS_IF_DEF_FSTN) temp++;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1C,temp);      	/* Part1_1Ch; TW: Panel Link Vertical Display Enable End  */
+
+  temp = tempcx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1B,temp);      	/* Part1_1Bh; TW: Panel Link Vertical Display Enable Start  */
+
+  /* 3. Additional horizontal setup (scaling, etc) */
+
+  tempecx = SiS_Pr->SiS_VGAHDE;
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     if(modeflag & HalfDCLK)
+        tempecx >>= 1;
+  }
+  tempebx = SiS_Pr->SiS_HDE;
+  if(tempecx == tempebx) tempeax = 0xFFFF;
+  else {
+     tempeax = tempecx;
+     tempeax <<= 16;
+     temp = (USHORT)(tempeax % tempebx);
+     tempeax = tempeax / tempebx;
+     if(HwDeviceExtension->jChipType >= SIS_315H) {
+         if(temp) tempeax++;
+     }
+  }
+  tempecx = tempeax;
+
+  if (HwDeviceExtension->jChipType >= SIS_315H) {
+      tempeax = SiS_Pr->SiS_VGAHDE;
+      if(modeflag & HalfDCLK)
+          tempeax >>= 1;
+      tempeax <<= 16;
+      tempeax = (tempeax / tempecx) - 1;
+  } else {
+      tempeax = ((SiS_Pr->SiS_VGAHT << 16) / tempecx) - 1;
+  }
+  tempecx <<= 16;
+  tempecx |= (tempeax & 0xFFFF);
+  temp = (USHORT)(tempecx & 0x00FF);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1F,temp);  	 /* Part1_1Fh; TW: Panel Link DDA Operational Number in each horiz. line */
+
+  tempbx = SiS_Pr->SiS_VDE;
+  if (HwDeviceExtension->jChipType >= SIS_315H) {
+      tempeax = (SiS_Pr->SiS_VGAVDE << 18) / tempvcfact;
+      tempbx = (USHORT)(tempeax & 0x0FFFF);
+  } else {
+      tempax = SiS_Pr->SiS_VGAVDE << 6;
+      tempbx = push1;
+      tempbx &= 0x3f;
+      if(tempbx == 0) tempbx = 64;
+      tempax = tempax / tempbx;
+      tempbx = tempax;
+  }
+  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) tempbx--;
+  if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA)                 tempbx = 1;
+
+  temp = ((tempbx & 0xFF00) >> 8) << 3;
+  temp |= (USHORT)((tempecx & 0x0700) >> 8);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x20,temp);  	/* Part1_20h; TW: Overflow register */
+
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x21,temp);  	/* Part1_21h; TW: Panel Link Vertical Accumulator Register */
+
+  tempecx >>= 16;                               /* BPLHCFACT  */
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+      if(modeflag & HalfDCLK) tempecx >>= 1;
+  }
+  temp = (USHORT)((tempecx & 0xFF00) >> 8);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x22,temp);     	/* Part1_22h; TW: Panel Link Horizontal Scaling Factor High */
+
+  temp = (USHORT)(tempecx & 0x00FF);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x23,temp);         /* Part1_22h; TW: Panel Link Horizontal Scaling Factor Low */
+
+  /* 630/301B and 630/LVDS do something for 640x480 panels here */
+
+  /* TW: DSTN/FSTN initialisation - hardcoded for 320x480 panel */
+  if(SiS_Pr->SiS_IF_DEF_DSTN){
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1E,0x01);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x25,0x00);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x26,0x00);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x27,0x00);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x28,0x87);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x29,0x5A);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2A,0x4B);
+     	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x007,0x03);
+     	tempbx = SiS_Pr->SiS_HDE + 64;                       	/*Blps = lcdhdee(lcdhdes+HDE) + 64*/
+     	temp = tempbx & 0x00FF;
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x38,temp);
+     	temp=((tempbx & 0xFF00) >> 8) << 3;
+     	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x35,~0x078,temp);
+     	tempbx += 32;		                     		/*Blpe=lBlps+32*/
+     	temp = tempbx & 0x00FF;
+     	if(SiS_Pr->SiS_IF_DEF_FSTN)  temp=0;
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x39,temp);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3A,0x00);        	/*Bflml=0*/
+     	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x007,0x00);
+     	tempbx = SiS_Pr->SiS_VDE / 2;
+     	temp = tempbx & 0x00FF;
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3B,temp);
+     	temp = ((tempbx & 0xFF00) >> 8) << 3;
+     	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x038,temp);
+     	tempeax = SiS_Pr->SiS_HDE << 2;                       	/* BDxFIFOSTOP = (HDE*4)/128 */
+     	tempebx = 128;
+     	temp = (USHORT)(tempeax % tempebx);
+     	tempeax = tempeax / tempebx;
+     	if(temp != 0)  tempeax++;
+     	temp = (USHORT)(tempeax & 0x003F);
+     	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x45,~0x0FF,temp);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3F,0x00);         	/* BDxWadrst0 */
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3E,0x00);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x3D,0x10);
+     	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x040,0x00);
+     	tempax = SiS_Pr->SiS_HDE >> 4;                        	/* BDxWadroff = HDE*4/8/8 */
+     	pushcx = tempax;
+     	temp = tempax & 0x00FF;
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x43,temp);
+     	temp = ((tempax & 0xFF00) >> 8) << 3;
+     	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x44,~0x0F8,temp);
+     	tempax = SiS_Pr->SiS_VDE;                             /*BDxWadrst1 = BDxWadrst0 + BDxWadroff * VDE */
+     	tempeax = (tempax * pushcx);
+     	tempebx = 0x00100000 + tempeax;
+     	temp = (USHORT)tempebx & 0x000000FF;
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x42,temp);
+     	temp = (USHORT)((tempebx & 0x0000FF00)>>8);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x41,temp);
+     	temp = (USHORT)((tempebx & 0x00FF0000)>>16);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x40,temp);
+     	temp = (USHORT)(((tempebx & 0x01000000)>>24) << 7);
+     	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x3C,~0x080,temp);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2F,0x03);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x03,0x50);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x04,0x00);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2F,0x01);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x13,0x00);
+     	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);        /* Unlock */
+     	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1e,0x62);
+     	if(SiS_Pr->SiS_IF_DEF_FSTN){
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2b,0x1b);
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2c,0xe3);
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1e,0x62);
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2e,0x04);
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2f,0x42);
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,0x01);
+         	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2b,0x02);
+         	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2c,0x00);
+         	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2d,0x00);
+     	}
+     	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0f,0x30);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1e,0x7d);
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2e,0xe0);
   }
+
   return;
+
+}
+
+#ifdef SIS315H
+void
+SiS_CRT2AutoThreshold(SiS_Private *SiS_Pr, USHORT BaseAddr)
+{
+  SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x40);
 }
-/*end 301b*/
+#endif
 
-void SiS_SetTPData()
+
+/* TW: For LVDS / 302b/lv - LCDA (this must only be called on 310/325 series!) */
+/* TW: Double-checked against 650/LVDS and 650/301 BIOS */
+void
+SiS_SetGroup1_LCDA(SiS_Private *SiS_Pr, USHORT  BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                   PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex)
 {
+  USHORT modeflag,resinfo;
+  USHORT push1,push2,tempax,tempbx,tempcx,temp;
+  ULONG tempeax=0,tempebx,tempecx,tempvcfact;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1)					/* TW: From 650/LVDS BIOS */
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x04);      	/* TW: From 650/LVDS BIOS */
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1)					/* TW: From 650/LVDS 1.10.07 */
+     SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2D,0x00);			/* TW: From 650/LVDS 1.10.07 */
+  else
+     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2D,0x0f);			/* TW: From 650/301Lvx 1.10.6s */
+
+  if(ModeNo<=0x13) {
+    modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+    resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+  } else {
+    modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  }
+
+  tempax = SiS_Pr->SiS_LCDHDES;
+  tempbx = SiS_Pr->SiS_HDE;
+  tempcx = SiS_Pr->SiS_HT;
+
+  if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) {
+        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)       tempbx = 1024;
+	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempbx = 1400;
+	else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) tempbx = 1600;
+	else 							      tempbx = 1280;
+
+  }
+  tempcx -= tempbx;                        	            	/* HT-HDE  */
+  push1 = tempax;
+  tempax += tempbx;	                                    	/* lcdhdee  */
+  tempbx = SiS_Pr->SiS_HT;
+  if(tempax >= tempbx)	tempax -= tempbx;
+
+  push2 = tempax;						/* push ax   lcdhdee  */
+
+  tempcx >>= 2;
+
+  /* TW: Inserted from 650/301LVx 1.10.6s */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+      if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+          if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)        tempcx = 0x28;
+	  else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) tempcx = 0x30;
+	  else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)  tempcx = 0x18;
+	  else                                                          tempcx = 0x30;
+      }
+  }
+
+  tempcx += tempax;  	                                  	/* lcdhrs  */
+  if(tempcx >= tempbx) tempcx -= tempbx;
+                                                           	/* v ah,cl  */
+  tempax = tempcx;
+  tempax >>= 3;   	                                     	/* BPLHRS */
+  temp = tempax & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x14,temp);                 	/* Part1_14h  */
+
+  temp += 10;
+  temp &= 0x1F;
+  temp |= ((tempcx & 0x07) << 5);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x15,temp);                         /* Part1_15h  */
+
+  tempbx = push2;                                          	/* lcdhdee  */
+  tempcx = push1;                                          	/* lcdhdes  */
+  temp = (tempcx & 0x00FF);
+  temp &= 0x07;                                  		/* BPLHDESKEW  */
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1A,temp);                         /* Part1_1Ah  */
+
+  tempcx >>= 3;   	                                     	/* BPLHDES */
+  temp = tempcx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x16,temp);                         /* Part1_16h  */
+
+  if(tempbx & 0x07) tempbx += 8;
+  tempbx >>= 3;                                        		/* BPLHDEE  */
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x17,temp);                        	/* Part1_17h  */
+
+  tempcx = SiS_Pr->SiS_VGAVT;
+  tempbx = SiS_Pr->SiS_VGAVDE;
+  tempcx -= tempbx; 	                                   	/* GAVT-VGAVDE  */
+  tempbx = SiS_Pr->SiS_LCDVDES;                                	/* VGAVDES  */
+  push1 = tempbx;                                      		/* push bx temppush1 */
+  if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0){
+    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)        tempax = 768;
+    else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)  tempax = 1024;
+    else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)  tempax = 1050;
+    else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200)  tempax = 1200;
+    else                                                           tempax = 960;
+#if 0   /* TW: Removed (650/LVDS BIOS) */
+    if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+        tempax = SiS_Pr->SiS_VGAVDE;
+      }
+    }
+#endif
+  } else tempax = SiS_Pr->SiS_VGAVDE;  /* Trumpion */
+
+  tempbx += tempax;
+  tempax = SiS_Pr->SiS_VT;                                    	/* VT  */
+  if(tempbx >= tempax)  tempbx -= tempax;
+
+  push2 = tempbx;                                      		/* push bx  temppush2  */
+  tempcx >>= 2;	/* TO CHECK - was 1 */
+
+  /* TW: Inserted from 650/301LVx 1.10.6s */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+      if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+          if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)         tempcx = 1;
+	  else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)   tempcx = 3;
+	  else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768)   tempcx = 3;
+	  else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024)  tempcx = 1;
+	  else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)  tempcx = 1;
+	  else                                                           tempcx = 0x0057;
+      }
+  }
+
+  tempbx += tempcx;
+  tempbx++;                                                	/* BPLVRS  */
+  if(tempbx >= tempax)   tempbx -= tempax;
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x18,temp);                         /* Part1_18h  */
+
+  tempcx >>= 3;
+  tempcx += tempbx;
+  tempcx++;                                                	/* BPLVRE  */
+  temp = tempcx & 0x00FF;
+  temp &= 0x0F;
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+     /* TW: Inserted from 650/LVDS BIOS */
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xf0,temp);
+  } else {
+     /* TW: Inserted from 650/301LVx 1.10.6s */
+     temp |= 0xC0;
+     SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xF0,temp);             /* Part1_19h  */
+  }
+
+  temp = (tempbx & 0xFF00) >> 8;
+  temp &= 0x07;
+  temp <<= 3;  		                               		/* BPLDESKEW =0 */
+  tempbx = SiS_Pr->SiS_VGAVDE;
+  if(tempbx != SiS_Pr->SiS_VDE)              temp |= 0x40;
+  if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA)    temp |= 0x40;
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+      /* TW: Inserted from 650/LVDS 1.10.07 */
+      if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)  temp |= 0x80;
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1A,0x87,temp);            /* Part1_1Ah */
+  } else {
+      /* TW: Inserted from 650/301LVx 1.10.6s */
+      if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
+          if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x01) temp |= 0x80;
+      }
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1A,0x87,temp);            /* Part1_1Ah */
+  }
+
+  tempbx = push2;                                      		/* p bx temppush2 BPLVDEE  */
+  tempcx = push1;                                      		/* pop cx temppush1 NPLVDES */
+  push1 = (USHORT)(tempeax & 0xFFFF);
+
+  if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
+      if(resinfo == 7) tempcx++;
+    }
+    /* TW: Inserted from 650/301LVx+LVDS BIOSes */
+    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
+        tempbx = SiS_Pr->SiS_VGAVDE;
+	tempcx = tempbx;
+        tempbx--;
+    }
+  }
+
+  temp = (tempbx & 0xFF00) >> 8;
+  temp &= 0x07;
+  temp <<= 3;
+  temp = temp | (((tempcx & 0xFF00) >> 8) & 0x07);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1D,temp);                          /* Part1_1Dh */
+
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1C,temp);                          /* Part1_1Ch  */
+
+  temp = tempcx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1B,temp);                          /* Part1_1Bh  */
+
+  tempecx = SiS_Pr->SiS_VGAVT;
+  tempebx = SiS_Pr->SiS_VDE;
+  tempeax = SiS_Pr->SiS_VGAVDE;
+  tempecx -= tempeax;    	                             	/* VGAVT-VGAVDE  */
+  tempeax <<= 18;
+  temp = (USHORT)(tempeax % tempebx);
+  tempeax = tempeax / tempebx;
+  if(temp != 0)  tempeax++;
+  tempebx = tempeax;                                        	/* BPLVCFACT  */
+  tempvcfact = tempeax;
+  temp = (USHORT)(tempebx & 0x00FF);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x37,temp);
+
+  temp = (USHORT)((tempebx & 0x00FF00) >> 8);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x36,temp);
+
+  temp = (USHORT)((tempebx & 0x00030000) >> 16);
+  if(SiS_Pr->SiS_VDE == SiS_Pr->SiS_VGAVDE) temp |= 0x04;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x35,temp);
+
+  tempecx = SiS_Pr->SiS_VGAHDE;
+  tempebx = SiS_Pr->SiS_HDE;
+  tempeax = tempecx;
+  tempeax <<= 16;
+  temp = tempeax % tempebx;
+  tempeax = tempeax / tempebx;
+  if(temp) tempeax++;
+  if(tempebx == tempecx)  tempeax = 0xFFFF;
+  tempecx = tempeax;
+  tempeax = SiS_Pr->SiS_VGAHDE;
+  tempeax <<= 16;
+  tempeax = tempeax / tempecx;
+  tempecx <<= 16;
+  tempeax--;
+  tempecx = tempecx | (tempeax & 0xFFFF);
+  temp = (USHORT)(tempecx & 0x00FF);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1F,temp);                          /* Part1_1Fh  */
+
+  tempeax = SiS_Pr->SiS_VGAVDE;
+  tempeax <<= 18;
+  tempeax = tempeax / tempvcfact;
+  tempbx = (USHORT)(tempeax & 0x0FFFF);
+
+  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) tempbx--;
+
+  if(SiS_Pr->SiS_SetFlag & EnableLVDSDDA)  tempbx = 1;
+
+  temp = ((tempbx & 0xFF00) >> 8) << 3;
+  temp = temp | (USHORT)(((tempecx & 0x0000FF00) >> 8) & 0x07);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x20,temp);                         /* Part1_20h */
+
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x21,temp);                         /* Part1_21h */
+
+  tempecx >>= 16;   	                                  	/* BPLHCFACT  */
+  if(modeflag & HalfDCLK) tempecx >>= 1;
+  temp = (USHORT)((tempecx & 0x0000FF00) >> 8);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x22,temp);                         /* Part1_22h */
+
+  temp=(USHORT)(tempecx & 0x000000FF);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x23,temp);
+
+#if 0
+  /* TW: Missing code (calles int 2f) (650/301LVx 1.10.6s) */
+  if(xxx()) {
+      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x0e,0xda);
+  }
+#endif
+
+  /* TW: Only for 650/LVDS and 30xLV/30xLVX */
+  if((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (SiS_Pr->SiS_VBInfo & (VB_SIS30xLV|VB_SIS30xNEW))){
+  	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1e,0x20);
+  }
+
   return;
 }
 
-void SiS_SetCRT2Offset(USHORT SiS_Part1Port,ULONG ROMAddr,USHORT ModeNo,
+/* TW: Double-checked against 650/LVDS (1.10.07) and 650/301 BIOS */
+void SiS_SetCRT2Offset(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
                        USHORT ModeIdIndex ,USHORT RefreshRateTableIndex,
 		       PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT offset;
   UCHAR temp;
 
-  if(SiS_VBInfo&SetInSlaveMode) return;
+  if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) return;
 
-  offset=SiS_GetOffset(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
-                       HwDeviceExtension);
-  temp=(UCHAR)(offset&0xFF);
-  SiS_SetReg1(SiS_Part1Port,0x07,temp);
-  temp=(UCHAR)((offset&0xFF00)>>8);
-  SiS_SetReg1(SiS_Part1Port,0x09,temp);
-  temp=(UCHAR)(((offset>>3)&0xFF)+1);
-  SiS_SetReg1(SiS_Part1Port,0x03,temp);
+  offset = SiS_GetOffset(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                         HwDeviceExtension);
+  temp = (UCHAR)(offset & 0xFF);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07,temp);
+  temp = (UCHAR)((offset & 0xFF00) >> 8);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x09,temp);
+  temp = (UCHAR)(((offset >> 3) & 0xFF) + 1);
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x03,temp);
 }
 
+/* TW: Checked with 650/LVDS and 650/301 BIOS */
 USHORT
-SiS_GetOffset(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+SiS_GetOffset(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
               USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT temp,colordepth;
   USHORT modeinfo,index,infoflag;
-  USHORT ColorDepth[]={0x02,0x04,0x08};  /* TW: Was 1,2,4 */
+#if 0
+  USHORT mode960low, mode960high;
+  USHORT ColorDepth[] = { 0x01, 0x02, 0x04 };
+#endif
 
-  modeinfo = SiS_EModeIDTable[ModeIdIndex].Ext_ModeInfo;
-  infoflag = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+  modeinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeInfo;
+  infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
   if (HwDeviceExtension->jChipType < SIS_315H ) {
-  	/* 300 series */
-    	index=(modeinfo>>4)&0xFF;
+    	index = (modeinfo >> 4) & 0xFF;
+#if 0   /* TW: Modes 1280x960 changed number, so this is redundant */
+	mode960low = 0x7c;
+	mode960high = 0x7e;
+#endif
+  } else {
+    	index = (modeinfo >> 8) & 0xFF;
+#if 0   /* TW: In 650 BIOS (LVDS AND 301), 1280x960 modes are 7b-7d! */
+	mode960low = 0x7c;                    /* TW: This is a bug in both BIOS versions ! */
+	mode960high = 0x7e;		      /* TW: Corrected here in LVDS BIOS 1.10.07, but not in tables! */
+#endif
+  }
+
+#if 0
+  /* TW: Not doing this strange stuff makes 1280x960 at least work on CRT1 */
+  if((ModeNo >= mode960low) && (ModeNo <= mode960high)) {
+    	temp = ModeNo - mode960low;
+    	colordepth = ColorDepth[temp];
+    	temp = 0x6b;  /* TW: Why the heck? */
   } else {
-  	/* 310 series */
-    	index=(modeinfo>>8)&0xFF;
+#endif
+        temp = SiS_Pr->SiS_ScreenOffset[index];
+        colordepth = SiS_GetColorDepth(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex);
+#if 0
   }
-  temp=SiS_ScreenOffset[index];
-  if(infoflag&InterlaceMode){
-    	temp=temp<<1;
-  }
-  colordepth=SiS_GetColorDepth(ROMAddr,ModeNo,ModeIdIndex);
-
-  if((ModeNo>=0x7C)&&(ModeNo<=0x7E)) {
-  	/* TW: For 1280x960 */
-    	temp=ModeNo-0x7C;
-    	colordepth=ColorDepth[temp];
-    	temp=0x6B;
-    	if(infoflag&InterlaceMode){
-      		temp=temp<<1;
-    	}
-   	return(temp*colordepth);
+#endif
+
+  if(infoflag & InterlaceMode) temp <<= 1;
+
+  temp *= colordepth;
+
+  /* TW: For 1400x1050 */
+  if((ModeNo >= 0x26) && (ModeNo <= 0x28)) {
+        colordepth >>= 1;
+	temp += colordepth;
   }
-  else return(temp*colordepth);
+
+  return(temp);
 }
 
+/* TW: Checked with 650/LVDS BIOS */
 USHORT
-SiS_GetColorDepth(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SiS_GetColorDepth(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT ColorDepth[6]={1,2,4,4,6,8};
+  USHORT ColorDepth[6] = { 1, 2, 4, 4, 6, 8};
   SHORT  index;
   USHORT modeflag;
 
-  if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-  }
-  index=(modeflag&ModeInfoFlag)-ModeEGA;
-  if(index<0) index=0;
+  if(ModeNo <= 0x13)
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  else
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+
+  index = (modeflag & ModeInfoFlag) - ModeEGA;
+  if(index < 0) index = 0;
   return(ColorDepth[index]);
 }
 
+/* TW: Checked against 630/301/301B/LVDS, 650/301LVx/LVDS */
 void
-SiS_SetCRT2Sync(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
-                USHORT RefreshRateTableIndex)
+SiS_SetCRT2Sync(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+                USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT tempah=0,infoflag,flag;
+  USHORT tempah=0,tempbl,infoflag,flag;
+
+  flag = 0;
+  tempbl = 0xC0;
 
-  flag=0;
-  infoflag = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
-  if(SiS_IF_DEF_LVDS==1){
-    if(SiS_VBInfo&SetCRT2ToLCD){
-      tempah=SiS_LCDInfo;
-      if(tempah&LCDSync){
-        flag=1;
+  infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {					/* LVDS */
+
+    if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+      tempah = SiS_Pr->SiS_LCDInfo;
+      if(HwDeviceExtension->jChipType >= SIS_315H) {
+          tempbl = tempah & 0xc0;
+      }
+      if(SiS_Pr->SiS_LCDInfo & LCDSync) {
+          flag = 1;
       }
     }
-  }
-  if(flag!=1) tempah=infoflag>>8;
-  tempah=tempah&0xC0;
-  tempah=tempah|0x20;
-  if(!(SiS_LCDInfo&LCDRGB18Bit)) tempah=tempah|0x10;
-  if(SiS_IF_DEF_CH7005==1) tempah=tempah|0xC0;
-  SiS_SetRegANDOR(SiS_Part1Port,0x19,0x3F,tempah);
+    if(flag != 1) tempah = infoflag >> 8;
+    tempah &= 0xC0;
+    tempah |= 0x20;
+    if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
+
+    if (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
+		/* TW: BIOS does something here @@@ */
+    }
+
+    tempah &= 0x3f;
+    tempah |= tempbl;
+    SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
+
+  } else {
+
+     if(HwDeviceExtension->jChipType < SIS_315H) {
+
+        if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {			/* 630 - 301B */
+
+            if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+               tempah = SiS_Pr->SiS_LCDInfo;
+	       if(SiS_Pr->SiS_LCDInfo & LCDSync) {
+                  flag = 1;
+               }
+            }
+            if(flag != 1) tempah = infoflag >> 8;
+            tempah &= 0xC0;
+            tempah |= 0x20;
+
+            if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
+
+            if (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
+	       	/* TW: BIOS does something here @@@ */
+            }
+
+ 	    tempah &= 0x3f;
+  	    tempah |= tempbl;
+            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
+
+         } else {							/* 630 - 301 */
+
+            if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+               tempah = SiS_Pr->SiS_LCDInfo;
+	       if(SiS_Pr->SiS_LCDInfo & LCDNonExpandingShift) { /* ! */
+	          flag = 1;
+	       }
+            }
+            if(flag != 1) tempah = infoflag >> 8;
+            tempah &= 0xC0;
+            tempah |= 0x30;
+            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x3F,tempah);
+
+         }
+
+      } else {
+
+         if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {			/* 310/325 - 301B et al */
+
+            tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);
+            tempah &= 0xC0;
+            tempah |= 0x20;
+            if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
+            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
+
+         } else {							/* 310/325 - 301 */
+
+            tempah = infoflag >> 8;
+            tempah &= 0xC0;
+            tempah |= 0x20;
+
+            if(!(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit)) tempah |= 0x10;
+
+            if (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
+		/* TW: BIOS does something here @@@ */
+            }
+
+            tempah &= 0x3f;
+            tempah |= tempbl;
+            SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0x0F,tempah);
+
+         }
+      }
+   }
 }
 
+/* TW: Set FIFO on 630/730 - not to be called on SiS300 */
+/* TW: Checked against 630/301B BIOS; does not set PCI registers */
 void
-SiS_SetCRT2FIFO(USHORT  SiS_Part1Port,ULONG ROMAddr,USHORT ModeNo,
-                PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
+                    PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT temp,index;
   USHORT modeidindex,refreshratetableindex;
   USHORT VCLK,MCLK,colorth=0,data2;
   ULONG  data,eax;
-  UCHAR  LatencyFactor[] ={
+  UCHAR  LatencyFactor[] = {
   	97, 88, 86, 79, 77, 00,       /*; 64  bit    BQ=2   */
         00, 87, 85, 78, 76, 54,       /*; 64  bit    BQ=1   */
         97, 88, 86, 79, 77, 00,       /*; 128 bit    BQ=2   */
@@ -1341,292 +2071,352 @@
         86, 77, 75, 68, 66, 00,       /*; 128 bit    BQ=2   */
         00, 68, 66, 59, 57, 37};      /*; 128 bit    BQ=1   */
 
-  SiS_SearchModeID(ROMAddr,ModeNo,&modeidindex);
-  SiS_SetFlag=SiS_SetFlag&(~ProgrammingCRT2);
-  SiS_SelectCRT2Rate=0;
-  refreshratetableindex=SiS_GetRatePtrCRT2(ROMAddr,ModeNo,modeidindex);   /* 11.GetRatePtr */
-  if(ModeNo>=0x13) {
-    index=SiS_RefIndex[refreshratetableindex].Ext_CRTVCLK;
-    index=index&0x3F;
-    VCLK=SiS_VCLKData[index].CLOCK;           /* Get VCLK  */
-    index=SiS_GetReg1(SiS_P3c4,0x1A);
-    index=index&07;
-    MCLK=SiS_MCLKData[index].CLOCK;           /* Get MCLK  */
-    data2=SiS_ModeType-0x02;
+  SiS_SearchModeID(SiS_Pr,ROMAddr,&ModeNo,&modeidindex);
+  SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
+  SiS_Pr->SiS_SelectCRT2Rate = 0;
+  refreshratetableindex = SiS_GetRatePtrCRT2(SiS_Pr,ROMAddr,ModeNo,modeidindex,HwDeviceExtension);
+
+  if(ModeNo >= 0x13) {
+    index = SiS_Pr->SiS_RefIndex[refreshratetableindex].Ext_CRTVCLK;
+    index &= 0x3F;
+    VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
+    index = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1A);
+    index &= 0x07;
+    MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK;
+    data2 = SiS_Pr->SiS_ModeType - 0x02;
     switch (data2) {
-      case 0 : 	colorth=1; break;
-      case 1 : 	colorth=1; break;
-      case 2 : 	colorth=2; break;
-      case 3 : 	colorth=2; break;
-      case 4 : 	colorth=3; break;
-      case 5 : 	colorth=4; break;
+      case 0 : 	colorth = 1; break;
+      case 1 : 	colorth = 1; break;
+      case 2 : 	colorth = 2; break;
+      case 3 : 	colorth = 2; break;
+      case 4 : 	colorth = 3; break;
+      case 5 : 	colorth = 4; break;
     }
-    /* data2=(data2*VCLK)/MCLK;   */  /*  bx */
-    data2=(colorth*VCLK)/MCLK;  /* TW */
+    data2 = (colorth * VCLK) / MCLK;  
 
-    temp = SiS_GetReg1(SiS_P3c4,0x14);
+    temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
     temp = ((temp&0x00FF)>>6)<<1;
-    if(temp==0) temp=1;
-    temp=temp<<2;
+    if(temp == 0) temp=1;
+    temp <<= 2;
 
-    data2=temp-data2;
+    data2 = temp - data2;
 
-/*  if(data2%(28*16)) {		 TW: WRONG
-      	data2=data2/(28*16);
+    if((28*16) % data2) {
+      	data2 = (28 * 16) / data2;
       	data2++;
     } else {
-      	data2=data2/(28*16);
-    } */
-    if((28*16)%data2) {		/* TW */
-      	data2=(28*16)/data2;
-      	data2++;
-    } else {
-      	data2=(28*16)/data2;
+      	data2 = (28 * 16) / data2;
     }
 
-    index=0;
-    temp = SiS_GetReg1(SiS_P3c4,0x14);
-    if(temp&0x0080) index=index+12;
+    index = 0;
+    temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+    if(temp & 0x0080) index += 12;
 
+#ifndef LINUX_XF86
     SiS_SetReg4(0xcf8,0x800000A0);
     eax=SiS_GetReg3(0xcfc);
+#else
+  /* TW: We use pci functions X offers. We use tag 0, because
+   * we want to read/write to the host bridge (which is always
+   * 00:00.0 on 630, 730 and 540), not the VGA device.
+   */
+    eax = pciReadLong(0x00000000, 0xA0);
+#endif
     temp=(USHORT)(eax>>24);
-    if(!(temp&0x01)) index=index+24;
+    if(!(temp&0x01)) index += 24;
 
+#ifndef LINUX_XF86
     SiS_SetReg4(0xcf8,0x80000050);
     eax=SiS_GetReg3(0xcfc);
-    temp=(USHORT)(eax>>24);
-    if(temp&0x01) index=index+6;
+#else
+    eax = pciReadLong(0x00000000, 0x50);
+#endif
+    temp=(USHORT)(eax >> 24);
+    if(temp & 0x01) index += 6;
 
-    temp=(temp&0x0F)>>1;
-    index=index+temp;
-    data=LatencyFactor[index];
-    data=data+15;
-    temp = SiS_GetReg1(SiS_P3c4,0x14);
-    if(!(temp&0x80)) data=data+5;
-
-    data=data+data2;
-
-    SiS_SetFlag=SiS_SetFlag|ProgrammingCRT2;
-    data=data*VCLK*colorth;
-    if(data%(MCLK<<4)) {
-      	data=data/(MCLK<<4);
+    temp = (temp & 0x0F) >> 1;
+    index += temp;
+    data = LatencyFactor[index];
+    data += 15;
+    temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+    if(!(temp & 0x80)) data += 5;
+
+    data += data2;
+
+    SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+
+    data = data * VCLK * colorth;
+    if(data % (MCLK << 4)) {
+      	data = data / (MCLK << 4);
       	data++;
     } else {
-      	data=data/(MCLK<<4);
+      	data = data / (MCLK << 4);
     }
 
-/* TW: The following made all the calculations above void... */
-
-#if 0
-    temp=0x16;
-/*  Revision ID  */
-    temp=0x13;
-/*  Revision ID  */
-    SiS_SetRegANDOR(SiS_Part1Port,0x01,~0x01F,temp);
-    SiS_SetRegANDOR(SiS_Part1Port,0x02,~0x01F,temp);
-#endif
-
-   /* TW: We do this instead: */
-
-   temp = SiS_GetReg1(SiS_Part1Port,0x01);
-   if( (HwDeviceExtension->jChipType == SIS_630 ) &&
-	    ((HwDeviceExtension->jChipRevision & 0xf0) == 0x30) ) /* 630s */
-   {
-	temp = (temp & (~0x1F)) | 0x1b;  	/* TW: VESA sets 1b, prev. 0x19 */
-   } else {
+    /* TW: Inserted this entire section */
+    temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x01);
+    if( ( (HwDeviceExtension->jChipType == SIS_630) ||
+         (HwDeviceExtension->jChipType == SIS_730) ) &&
+       (HwDeviceExtension->jChipRevision >= 0x30) ) /* 630s or 730(s?) */
+    {
+	temp = (temp & (~0x1F)) | 0x1b;
+    } else {
 	temp = (temp & (~0x1F)) | 0x16;
-   }
-   SiS_SetReg1(SiS_Part1Port,0x01,temp);  	/* FIFO HIGH? */
+    }
+    SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0xe0,temp);
 
-   if(data <= 6) data = 6;
-   if(data > 0x14) data = 0x14;
-   if (SiS_IF_DEF_LVDS==1) {			/* TW: LVDS doesn't like 0x14 */
-	if(data > 0x13) data = 0x13;
-   }
-   SiS_SetRegANDOR(SiS_Part1Port,0x02,~0x01F,data);  /* FIFO LOW? */
-  /* TW end */
+    if(data <= 6) data = 6;
+    if(data > 0x14) data = 0x14;
+    if( (HwDeviceExtension->jChipType == SIS_630) &&
+        (HwDeviceExtension->jChipRevision >= 0x30) ) /* 630s, NOT 730 */
+    {
+   	if(data > 0x13) data = 0x13;
+    }
+    SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x02,~0x01F,data);
+   /* TW end */
   }
 }
 
+/* TW: Set FIFO on 310 series */
+#ifdef SIS315H
 void
-SiS_SetCRT2FIFO2(USHORT SiS_Part1Port,ULONG ROMAddr,USHORT ModeNo,
-                 PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_SetCRT2FIFO_310(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
+                    PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-#ifdef SIS315H
- UCHAR CombCode[]={1,1,1,4,3,1,3,4,4,1,4,4,5,1,5,4};
- UCHAR CRT2ThLow[]={39,63,55,79,78,102,90,114,55,87,84,116,103,135,119,151};
-#endif
-  USHORT temp,temp1,temp2,temp3;
+
+  UCHAR CombCode[]  = { 1, 1, 1, 4, 3, 1, 3, 4,
+                        4, 1, 4, 4, 5, 1, 5, 4};
+  UCHAR CRT2ThLow[] = { 39, 63, 55, 79, 78,102, 90,114,
+                        55, 87, 84,116,103,135,119,151};
+  USHORT temp3,tempax,tempbx,tempcx;
+  USHORT tempcl, tempch;
   USHORT index;
   USHORT CRT1ModeNo,CRT2ModeNo;
   USHORT ModeIdIndex;
   USHORT RefreshRateTableIndex;
+  USHORT SelectRate_backup;
+
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x01,0x3B);
+
+  CRT1ModeNo = SiS_Pr->SiS_CRT1Mode;                             /* get CRT1 ModeNo */
+  SiS_SearchModeID(SiS_Pr,ROMAddr,&CRT1ModeNo,&ModeIdIndex);
 
-  SiS_SetReg1(SiS_Part1Port,0x1,0x3B);
-  /* CRT1ModeNo=(UCHAR)SiS_GetReg1(SiS_P3d4,0x34); *//* get CRT1 ModeNo */
-  CRT1ModeNo = SiS_CRT1Mode;
-  /* CRT1ModeNo =ModeNo; */
-  SiS_SearchModeID(ROMAddr,CRT1ModeNo,&ModeIdIndex);    /* Get ModeID Table */
-  SiS_SetFlag=SiS_SetFlag& (~ProgrammingCRT2);
-
-  RefreshRateTableIndex=SiS_GetRatePtrCRT2(ROMAddr,CRT1ModeNo,
-                            ModeIdIndex); /* Set REFIndex-> for crt1 refreshrate */
-  index = SiS_GetVCLK2Ptr(ROMAddr,CRT1ModeNo,ModeIdIndex,
+  SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
+  SelectRate_backup = SiS_Pr->SiS_SelectCRT2Rate;
+  SiS_Pr->SiS_SelectCRT2Rate = 0;
+
+  /* Set REFIndex for crt1 refreshrate */
+  RefreshRateTableIndex = SiS_GetRatePtrCRT2(SiS_Pr,ROMAddr,CRT1ModeNo,
+                                             ModeIdIndex,HwDeviceExtension);
+
+  index = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,CRT1ModeNo,ModeIdIndex,
                           RefreshRateTableIndex,HwDeviceExtension);
-  temp1=SiS_VCLKData[index].CLOCK;           /* Get VCLK  */
+  tempax = SiS_Pr->SiS_VCLKData[index].CLOCK;                         /* Get DCLK (VCLK?) */
 
-  temp2= SiS_GetColorDepth(ROMAddr,CRT1ModeNo,ModeIdIndex);
-#ifdef SIS315H
-  index = SiS_Get310DRAMType(ROMAddr);
+  tempbx = SiS_GetColorDepth(SiS_Pr,ROMAddr,CRT1ModeNo,ModeIdIndex); /* Get colordepth */
+  tempbx >>= 1;
+  if(!tempbx) tempbx++;
+
+  tempax *= tempbx;
+
+  tempbx = SiS_GetMCLK(SiS_Pr,ROMAddr, HwDeviceExtension);     /* Get MCLK */
+
+  tempax /= tempbx;
+
+  tempbx = tempax;
+
+#if 0 /* TW: BIOS code is skrewed */
+  if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14) & 0x02) {
+   	tempax = 16;
+  } else {
+    	tempax = 8;
+  }
 #endif
-  temp3=SiS_MCLKData[index].CLOCK;           /* Get MCLK  */
+  tempax = 16;
 
-  temp=SiS_GetReg1(SiS_P3c4,0x14);
-  if (temp&0x02)
-   	temp=16;
-  else
-    	temp=8;
+  tempax -= tempbx;
 
-  temp = temp - temp1*temp2/temp3; /* 16-DRamBus - DCLK*BytePerPixel/MCLK */
+  tempbx = tempax;    /* tempbx = 16-DRamBus - DCLK*BytePerPixel/MCLK */
 
-  if ((52*16 % temp)==0)
-    	temp = 52*16/temp +40;
-  else
-    	temp = 52*16/temp +40 + 1;
+  tempax = ((52 * 16) / tempbx);
+
+  if ((52*16 % tempbx) != 0) {
+    	tempax++;
+  }
+  tempcx = tempax;
+  tempcx += 40;
 
   /* get DRAM latency */
-  temp1=(SiS_GetReg1(SiS_P3c4,0x17)>>3)&0x7; /* SR17[5:3] DRAM Queue depth */
-  temp2=(SiS_GetReg1(SiS_P3c4,0x17)>>6)&0x3; /* SR17[7:6] DRAM Grant length */
+  tempcl = (SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) >> 3) & 0x7;     /* SR17[5:3] DRAM Queue depth */
+  tempch = (SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) >> 6) & 0x3;     /* SR17[7:6] DRAM Grant length */
 
-#ifdef SIS315H
-  if (SiS_Get310DRAMType(ROMAddr)<2)
-  {
-    for (temp3=0;temp3<16;temp3+=2)
-    {
-      if ((CombCode[temp3]==temp1) && (CombCode[temp3+1]==temp2))
-      {
-        temp3 = CRT2ThLow[temp3>>1];
-      }
-    }
-  }
-  else
-  {
-    for (temp3=0;temp3<16;temp3+=2)
-    {
-      if ((CombCode[temp3]==temp1) && (CombCode[temp3+1]==temp2))
-      {
-        temp3 = CRT2ThLow[8+(temp3>>1)];
-      }
+  for (temp3 = 0; temp3 < 16; temp3 += 2) {
+    if ((CombCode[temp3] == tempcl) && (CombCode[temp3+1] == tempch)) {
+      temp3 = CRT2ThLow[temp3 >> 1];
     }
   }
-#endif
 
-  temp +=  temp3; /* CRT1 Request Period */
+  tempcx +=  temp3;                                      /* CRT1 Request Period */
+
+  CRT2ModeNo = ModeNo;                                   /* get CRT2 ModeNo */
+  SiS_SearchModeID(SiS_Pr,ROMAddr,&CRT2ModeNo,&ModeIdIndex);    /* Get ModeID Table */
+
+  SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+  SiS_Pr->SiS_SelectCRT2Rate = SelectRate_backup;
+
+  RefreshRateTableIndex=SiS_GetRatePtrCRT2(SiS_Pr,ROMAddr,CRT1ModeNo,
+                                           ModeIdIndex,HwDeviceExtension);
 
-  CRT2ModeNo = ModeNo; /* get CRT2 ModeNo */
-  SiS_SearchModeID(ROMAddr,CRT2ModeNo,&ModeIdIndex);    /* Get ModeID Table */
-  SiS_SetFlag=SiS_SetFlag|ProgrammingCRT2;
-  RefreshRateTableIndex=SiS_GetRatePtrCRT2(ROMAddr,CRT1ModeNo,
-                        ModeIdIndex);/* Set REFIndex-> for crt1 refreshrate */
-  index = SiS_GetVCLK2Ptr(ROMAddr,CRT2ModeNo,ModeIdIndex,
+  index = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,CRT2ModeNo,ModeIdIndex,
                           RefreshRateTableIndex,HwDeviceExtension);
-  temp1=SiS_VCLKData[index].CLOCK;           /* Get VCLK  */
+  tempax = SiS_Pr->SiS_VCLKData[index].CLOCK;                          /* Get VCLK  */
 
-  temp2= SiS_GetColorDepth(ROMAddr,CRT2ModeNo,ModeIdIndex);
-#ifdef SIS315H
-  index = SiS_Get310DRAMType(ROMAddr);
-#endif
-  temp3=SiS_MCLKData[index].CLOCK;           /* Get MCLK  */
- 
-  if ((temp*temp1*temp2)%(16*temp3)==0)
-    temp = temp*temp1*temp2/(16*temp3);   /* CRT1 Request period * TCLK*BytePerPixel/(MCLK*16) */
-  else 
-    temp = temp*temp1*temp2/(16*temp3)+1; /* CRT1 Request period * TCLK*BytePerPixel/(MCLK*16) */
+  tempbx = SiS_GetColorDepth(SiS_Pr,ROMAddr,CRT2ModeNo,ModeIdIndex);  /* Get colordepth */
+  tempbx >>= 1;
+  if(!tempbx) tempbx++;
 
-  if (temp>0x37)
-    temp = 0x37;
+  tempax *= tempbx;
 
-  SiS_SetRegANDOR(SiS_Part1Port,0x02,~0x3F,temp);
-}
+  tempax *= tempcx;
 
-void
-SiS_GetLVDSDesData(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                   USHORT RefreshRateTableIndex)
+  tempbx = SiS_GetMCLK(SiS_Pr,ROMAddr, HwDeviceExtension);	       /* Get MCLK */
+  tempbx <<= 4;
+
+  tempcx = tempax;
+  tempax /= tempbx;
+  if(tempcx % tempbx) tempax++;		/* CRT1 Request period * TCLK * BytePerPixel / (MCLK*16) */
+
+  if (tempax > 0x37)  tempax = 0x37;
+
+  /* TW: 650/LVDS (1.10.07, 1.10.00), 650/301LV overrule calculated value; 315 does not */
+  if(HwDeviceExtension->jChipType == SIS_650) {
+  	tempax = 0x04;
+  }
+
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x02,~0x3F,tempax);
+}
+
+USHORT
+SiS_GetMCLK(SiS_Private *SiS_Pr, UCHAR *ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT index;
+
+  index = SiS_Get310DRAMType(SiS_Pr,ROMAddr,HwDeviceExtension);
+  if(index >= 4) {
+    index -= 4;
+    return(SiS_Pr->SiS_MCLKData_1[index].CLOCK);
+  } else {
+    return(SiS_Pr->SiS_MCLKData_0[index].CLOCK);
+  }
+}
+#endif
+
+/* TW: Checked against 650/LVDS 1.10.07 BIOS */
+void
+SiS_GetLVDSDesData(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                   USHORT RefreshRateTableIndex,
+		   PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT modeflag;
   USHORT PanelIndex,ResIndex;
-  SiS_LVDSDesStruct  *PanelDesPtr=NULL;
+  const  SiS_LVDSDesStruct *PanelDesPtr = NULL;
 
-  if((SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-       && (SiS_IF_DEF_LVDS == 0) ) {  /*301b*//*for test*/
-     SiS_GetLVDSDesPtrA(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+  if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) ) {
+
+     SiS_GetLVDSDesPtrA(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
                         &PanelIndex,&ResIndex);
      switch (PanelIndex)
      {
-     	case  0: PanelDesPtr = LVDS1024x768Des_1;   break;
-     	case  1: PanelDesPtr = LVDS1280x1024Des_1;  break;
-     	case  2: PanelDesPtr = LVDS1280x960Des_1;   break;
-     	case  3: PanelDesPtr = LVDS1024x768Des_2;   break;
-     	case  4: PanelDesPtr = LVDS1280x1024Des_2;  break;
-     	case  5: PanelDesPtr = LVDS1280x960Des_2;   break;
+     	case  0: PanelDesPtr = SiS_Pr->LVDS1024x768Des_1;   break;  /* --- expanding --- */
+     	case  1: PanelDesPtr = SiS_Pr->LVDS1280x1024Des_1;  break;
+	case  2: PanelDesPtr = SiS_Pr->LVDS1400x1050Des_1;  break;
+	case  3: PanelDesPtr = SiS_Pr->LVDS1600x1200Des_1;  break;
+     	case  4: PanelDesPtr = SiS_Pr->LVDS1024x768Des_2;   break;  /* --- non expanding --- */
+     	case  5: PanelDesPtr = SiS_Pr->LVDS1280x1024Des_2;  break;
+	case  6: PanelDesPtr = SiS_Pr->LVDS1400x1050Des_2;  break;
+	case  7: PanelDesPtr = SiS_Pr->LVDS1600x1200Des_2;  break;
      }
+
   } else {
-     SiS_GetLVDSDesPtr(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
-                       &PanelIndex,&ResIndex);
-#ifdef LINUX_KERNEL
-     if (PanelIndex < 32)	/* >=32 = TV */
-         printk(KERN_INFO "sisfb: LVDS-LCD panel type %d (Resindex %d)\n", PanelIndex, ResIndex);
-#endif
+
+     SiS_GetLVDSDesPtr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                       &PanelIndex,&ResIndex,HwDeviceExtension);
+
      switch (PanelIndex)
      {
-     	case  0: PanelDesPtr = SiS_PanelType00_1;   break;
-     	case  1: PanelDesPtr = SiS_PanelType01_1;   break;
-     	case  2: PanelDesPtr = SiS_PanelType02_1;   break;
-     	case  3: PanelDesPtr = SiS_PanelType03_1;   break;
-     	case  4: PanelDesPtr = SiS_PanelType04_1;   break;
-     	case  5: PanelDesPtr = SiS_PanelType05_1;   break;
-     	case  6: PanelDesPtr = SiS_PanelType06_1;   break;
-     	case  7: PanelDesPtr = SiS_PanelType07_1;   break;
-     	case  8: PanelDesPtr = SiS_PanelType08_1;   break;
-     	case  9: PanelDesPtr = SiS_PanelType09_1;   break;
-     	case 10: PanelDesPtr = SiS_PanelType0a_1;   break;
-     	case 11: PanelDesPtr = SiS_PanelType0b_1;   break;
-     	case 12: PanelDesPtr = SiS_PanelType0c_1;   break;	/* TW: Clevo 2202   */
-     	case 13: PanelDesPtr = SiS_PanelType0d_1;   break;
-     	case 14: PanelDesPtr = SiS_PanelType0e_1;   break;	/* TW: Uniwill N271S2 */
-     	case 15: PanelDesPtr = SiS_PanelType0f_1;   break;
-     	case 16: PanelDesPtr = SiS_PanelType00_2;   break;
-     	case 17: PanelDesPtr = SiS_PanelType01_2;   break;
-     	case 18: PanelDesPtr = SiS_PanelType02_2;   break;
-     	case 19: PanelDesPtr = SiS_PanelType03_2;   break;
-     	case 20: PanelDesPtr = SiS_PanelType04_2;   break;
-     	case 21: PanelDesPtr = SiS_PanelType05_2;   break;
-     	case 22: PanelDesPtr = SiS_PanelType06_2;   break;
-     	case 23: PanelDesPtr = SiS_PanelType07_2;   break;
-     	case 24: PanelDesPtr = SiS_PanelType08_2;   break;
-     	case 25: PanelDesPtr = SiS_PanelType09_2;   break;
-     	case 26: PanelDesPtr = SiS_PanelType0a_2;   break;
-     	case 27: PanelDesPtr = SiS_PanelType0b_2;   break;
-     	case 28: PanelDesPtr = SiS_PanelType0c_2;   break;
-     	case 29: PanelDesPtr = SiS_PanelType0d_2;   break;
-     	case 30: PanelDesPtr = SiS_PanelType0e_2;   break;
-     	case 31: PanelDesPtr = SiS_PanelType0f_2;   break;
-     	case 32: PanelDesPtr = SiS_CHTVUNTSCDesData;   break;
-     	case 33: PanelDesPtr = SiS_CHTVONTSCDesData;   break;
-     	case 34: PanelDesPtr = SiS_CHTVUPALDesData;    break;
-     	case 35: PanelDesPtr = SiS_CHTVOPALDesData;    break;
-     }
-  }
-  SiS_LCDHDES = (PanelDesPtr+ResIndex)->LCDHDES;
-  SiS_LCDVDES = (PanelDesPtr+ResIndex)->LCDVDES;
-
-  if(SiS_LCDInfo&LCDNonExpanding){
-    if(SiS_LCDResInfo>=Panel1024x768){
-      if(ModeNo<=0x13){
-        modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-        if(!(modeflag&HalfDCLK)) {
-          SiS_LCDHDES=320;
+     	case  0: PanelDesPtr = SiS_Pr->SiS_PanelType00_1;   break; /* --- expanding --- | Gericom 1st supersonic (310) */
+     	case  1: PanelDesPtr = SiS_Pr->SiS_PanelType01_1;   break;
+     	case  2: PanelDesPtr = SiS_Pr->SiS_PanelType02_1;   break;
+     	case  3: PanelDesPtr = SiS_Pr->SiS_PanelType03_1;   break;
+     	case  4: PanelDesPtr = SiS_Pr->SiS_PanelType04_1;   break;
+     	case  5: PanelDesPtr = SiS_Pr->SiS_PanelType05_1;   break;
+     	case  6: PanelDesPtr = SiS_Pr->SiS_PanelType06_1;   break;
+     	case  7: PanelDesPtr = SiS_Pr->SiS_PanelType07_1;   break;
+     	case  8: PanelDesPtr = SiS_Pr->SiS_PanelType08_1;   break;
+     	case  9: PanelDesPtr = SiS_Pr->SiS_PanelType09_1;   break;
+     	case 10: PanelDesPtr = SiS_Pr->SiS_PanelType0a_1;   break;
+     	case 11: PanelDesPtr = SiS_Pr->SiS_PanelType0b_1;   break;
+     	case 12: PanelDesPtr = SiS_Pr->SiS_PanelType0c_1;   break;	/* TW: Clevo 2202 (300)  */
+     	case 13: PanelDesPtr = SiS_Pr->SiS_PanelType0d_1;   break;
+     	case 14: PanelDesPtr = SiS_Pr->SiS_PanelType0e_1;   break;	/* TW: Uniwill N271S2 (300) */
+     	case 15: PanelDesPtr = SiS_Pr->SiS_PanelType0f_1;   break;
+     	case 16: PanelDesPtr = SiS_Pr->SiS_PanelType00_2;   break;  /* --- non-expanding --- */
+     	case 17: PanelDesPtr = SiS_Pr->SiS_PanelType01_2;   break;
+     	case 18: PanelDesPtr = SiS_Pr->SiS_PanelType02_2;   break;
+     	case 19: PanelDesPtr = SiS_Pr->SiS_PanelType03_2;   break;
+     	case 20: PanelDesPtr = SiS_Pr->SiS_PanelType04_2;   break;
+     	case 21: PanelDesPtr = SiS_Pr->SiS_PanelType05_2;   break;
+     	case 22: PanelDesPtr = SiS_Pr->SiS_PanelType06_2;   break;
+     	case 23: PanelDesPtr = SiS_Pr->SiS_PanelType07_2;   break;
+     	case 24: PanelDesPtr = SiS_Pr->SiS_PanelType08_2;   break;
+     	case 25: PanelDesPtr = SiS_Pr->SiS_PanelType09_2;   break;
+     	case 26: PanelDesPtr = SiS_Pr->SiS_PanelType0a_2;   break;
+     	case 27: PanelDesPtr = SiS_Pr->SiS_PanelType0b_2;   break;
+     	case 28: PanelDesPtr = SiS_Pr->SiS_PanelType0c_2;   break;     /* TW: Gericom 2200C (300) */
+     	case 29: PanelDesPtr = SiS_Pr->SiS_PanelType0d_2;   break;
+     	case 30: PanelDesPtr = SiS_Pr->SiS_PanelType0e_2;   break;
+     	case 31: PanelDesPtr = SiS_Pr->SiS_PanelType0f_2;   break;
+     	case 32: PanelDesPtr = SiS_Pr->SiS_CHTVUNTSCDesData;   break;
+     	case 33: PanelDesPtr = SiS_Pr->SiS_CHTVONTSCDesData;   break;
+     	case 34: PanelDesPtr = SiS_Pr->SiS_CHTVUPALDesData;    break;
+     	case 35: PanelDesPtr = SiS_Pr->SiS_CHTVOPALDesData;    break;
+     }
+  }
+  SiS_Pr->SiS_LCDHDES = (PanelDesPtr+ResIndex)->LCDHDES;
+  SiS_Pr->SiS_LCDVDES = (PanelDesPtr+ResIndex)->LCDVDES;
+
+  if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding){
+    if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+      if(ModeNo <= 0x13) {
+        modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+	if(!(modeflag & HalfDCLK)) {
+	  SiS_Pr->SiS_LCDHDES = 632;
+	}
+      }
+    } else {
+      if(!(SiS_Pr->SiS_SetFlag & CRT2IsVGA)) {
+        if((HwDeviceExtension->jChipType < SIS_315H) || (SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024)) {  /* TW: New from 650/LVDS 1.10.07 */
+          if(SiS_Pr->SiS_LCDResInfo >= SiS_Pr->SiS_Panel1024x768){
+            if(ModeNo <= 0x13) {
+	      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+	      if(HwDeviceExtension->jChipType < SIS_315H) {
+	         if(!(modeflag & HalfDCLK)) {
+                     SiS_Pr->SiS_LCDHDES = 320;
+		 }
+	      } else {
+	         /* TW: New from 650/LVDS 1.10.07 */
+	         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)
+	             SiS_Pr->SiS_LCDHDES = 480;
+                 if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)
+	             SiS_Pr->SiS_LCDHDES = 804;
+                 if(!(modeflag & HalfDCLK)) {
+                     SiS_Pr->SiS_LCDHDES = 320;
+	             if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050)
+	                SiS_Pr->SiS_LCDHDES = 632;
+                 }
+              }
+            }
+          }
         }
       }
     }
@@ -1634,3597 +2424,6375 @@
   return;
 }
 
+/* TW: Checked against 630/LVDS (2.04.5c) and 650/LVDS (1.10.07) BIOS */
 void
-SiS_GetLVDSDesPtr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+SiS_GetLVDSDesPtr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
                   USHORT RefreshRateTableIndex,USHORT *PanelIndex,
-		  USHORT *ResIndex)
+		  USHORT *ResIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT tempbx,tempal;
+  USHORT tempbx,tempal,modeflag;
+
+  if(ModeNo<=0x13) {
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+	tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  } else {
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+  }
+
+  tempbx = 0;
+  if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+    if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+      tempbx = 32;
+      if(SiS_Pr->SiS_VBInfo & SetPALTV) tempbx += 2;
+      if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx += 1;
+    }
+  }
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+    tempbx = SiS_Pr->SiS_LCDTypeInfo;
+    if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx += 16;
+    /* TW: Inserted from 650/LVDS (1.10.07) BIOS */
+    if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+       if(modeflag & HalfDCLK) tempbx += 16;
+    }
+  }
+  /* TW: Inserted from 630/LVDS and 650/LVDS (1.10.07) BIOS */
+  if(SiS_Pr->SiS_SetFlag & CRT2IsVGA) {
+    if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480)  {
+       tempal = 0x07;
+       if(HwDeviceExtension->jChipType < SIS_315H) {
+          if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x80) tempal++;
+       }
+    }
+  }
 
-  tempbx=0;
-  if(SiS_IF_DEF_CH7005==1) {
-    if(!(SiS_VBInfo&SetCRT2ToLCD)) {
-      tempbx=32;
-      if(SiS_VBInfo&SetPALTV) tempbx=tempbx+2;
-      if(SiS_VBInfo&SetCHTVOverScan) tempbx=tempbx+1;
-    }
-  } 
-  if(SiS_VBInfo&SetCRT2ToLCD) {
-    tempbx=SiS_LCDTypeInfo;
-    if(SiS_LCDInfo&LCDNonExpanding){
-      tempbx=tempbx+16;
-    }
-  }
-  if(ModeNo<=0x13){
-    	tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-  }else{
-    	tempal = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-  }
-  tempal=tempal&0x1F;
-  *PanelIndex=tempbx;
-  *ResIndex=tempal;
+  *PanelIndex = tempbx;
+  *ResIndex = tempal & 0x1F;
 }
 
-/*301b*/
 void
-SiS_GetLVDSDesPtrA(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+SiS_GetLVDSDesPtrA(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
                    USHORT RefreshRateTableIndex,USHORT *PanelIndex,
 		   USHORT *ResIndex)
 {
   USHORT tempbx=0,tempal;
 
-  tempbx=SiS_LCDResInfo-Panel1024x768;
-  if(SiS_LCDInfo&LCDNonExpanding){
-      tempbx=tempbx+3;
-  }
+  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+       tempbx = 3;
+  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
+       tempbx = 4;
+  } else tempbx = SiS_Pr->SiS_LCDResInfo - SiS_Pr->SiS_PanelMinLVDS;
 
-  if(ModeNo<=0x13){
-    	tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-  } else {
-    	tempal = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-  }
-  tempal=tempal&0x1F;
-  *PanelIndex=tempbx;
-  *ResIndex=tempal;
+  if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)  tempbx += 4;
+
+  if(ModeNo<=0x13)
+    	tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  else
+    	tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+
+  *PanelIndex = tempbx;
+  *ResIndex = tempal & 0x1F;
 }
-/*end 301b*/
 
+/* TW: Checked against 650/LVDS (1.10.07), 650/301LV, 650/301LVx (!), 630/301 and 630/301B (II) BIOS */
 void
-SiS_SetCRT2ModeRegs(USHORT BaseAddr,USHORT ModeNo,
+SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT BaseAddr, USHORT ModeNo, USHORT ModeIdIndex,
                     PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT i,j;
-  USHORT tempcl,tempah;
+  USHORT i,j,modeflag;
+  USHORT tempcl,tempah,tempbl,temp;
+
+  if(ModeNo<=0x13) {
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  } else {
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  }
+  
+  /* TW: BIOS does not do this (neither 301 nor LVDS) */
+  /*     (But it's harmless; see SetCRT2Offset) */
+  SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x03,0x00);   /* fix write part1 index 0  BTDRAM bit Bug */
 
-  SiS_SetReg1(SiS_Part1Port,0x03,0x00);   /*fix write part1 index 0  BTDRAM bit Bug*/
+  /* TW: Removed 301B302B301LV302LV check here to match 650/LVDS BIOS */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
 
-  /*301b*/
-  if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-  				&& (SiS_VBInfo&SetCRT2ToLCDA) ) {
+	/* TW:   1. for LVDS/302B/302LV **LCDA** */
 
-	/* TW:   1. for 301B/302B/301LV/302LV (on some of which
-	 *          IF_DEF_LVDS seems to be 1 as well)
-	 */
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xAF,0x40); /* FUNCTION CONTROL */
+      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2E,0xF7);
 
-      SiS_SetRegANDOR(SiS_Part1Port,0x00,~0x050,0x40); /* FUNCTION CONTROL */
-      SiS_SetRegAND(SiS_Part1Port,0x2E,0xF7);
-      SiS_SetRegANDOR(SiS_Part1Port,0x13,0xFB,0x04);
-      SiS_SetRegANDOR(SiS_Part1Port,0x2c,0xCF,0x30);
-      SiS_SetRegANDOR(SiS_Part4Port,0x21,0x3F,0xC0);
-      SiS_SetRegANDOR(SiS_Part4Port,0x23,0x7F,0x00);
-  /*end 301b*/
   } else {
-    for(i=0,j=4;i<3;i++,j++) SiS_SetReg1(SiS_Part1Port,j,0);
 
-    tempcl=SiS_ModeType;
+    for(i=0,j=4; i<3; i++,j++) SiS_SetReg1(SiS_Pr->SiS_Part1Port,j,0);
+
+    tempcl = SiS_Pr->SiS_ModeType;
+
     if(HwDeviceExtension->jChipType < SIS_315H) {
+
       /* ---- 300 series ---- */
-      if(ModeNo>0x13){
-        tempcl=tempcl-ModeVGA;
-        if((tempcl>0)||(tempcl==0)){
-           tempah=((0x010>>tempcl)|0x080);
-        }
-      } else {
-        tempah=0x080;
-      }
-      if(SiS_VBInfo&SetInSlaveMode){
-         tempah=(tempah^0x0A0);
+
+      /* TW: Inserted entire if-section from 630/301B BIOS */
+      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+	  temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32);
+	  temp &= 0xef;
+	  temp |= 0x02;
+	  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+	     temp |= 0x10;
+	     temp &= 0xfd;
+	  }
+	  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
       }
+
+      if(ModeNo > 0x13) {
+        tempcl -= ModeVGA;
+        if((tempcl > 0) || (tempcl == 0)) {      /* TW: tempcl is USHORT -> always true! */
+           tempah = ((0x10 >> tempcl) | 0x80);
+        }
+      } else  tempah = 0x80;
+
+      if(SiS_Pr->SiS_VBInfo & SetInSlaveMode)  tempah ^= 0xA0;
+
     } else {
+
     /* ---- 310 series ---- */
-      if(ModeNo>0x13) {
-        tempcl=tempcl-ModeVGA;
-        if((tempcl>0)||(tempcl==0)){
-           tempah=(0x008>>tempcl);
-           if (tempah==0) tempah=1;
-              tempah |= 0x040;
+
+      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        if(SiS_Pr->SiS_VBInfo & CRT2DisplayFlag) {
+	   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x08);
         }
-      } else {
-       tempah=0x040;
-      }
-  
-      if(SiS_VBInfo&SetInSlaveMode){
-          tempah=(tempah^0x050);
       }
+
+      if(ModeNo > 0x13) {
+        tempcl -= ModeVGA;
+        if((tempcl > 0) || (tempcl == 0)) {  /* TW: tempcl is USHORT -> always true! */
+           tempah = (0x08 >> tempcl);
+           if (tempah == 0) tempah = 1;
+           tempah |= 0x40;
+        }
+      } else  tempah = 0x40;
+
+      if(SiS_Pr->SiS_VBInfo & SetInSlaveMode)  tempah ^= 0x50;
+
     }
 
-    if(SiS_VBInfo&CRT2DisplayFlag){
-      	tempah=0;
+    if(SiS_Pr->SiS_VBInfo & CRT2DisplayFlag)  tempah = 0;
+
+    if(HwDeviceExtension->jChipType < SIS_315H) {
+        SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x00,tempah);  		/* FUNCTION CONTROL */
+    } else {
+        SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x00,0xa0,tempah);  	/* FUNCTION CONTROL */
     }
-    SiS_SetReg1(SiS_Part1Port,0x00,tempah);  /* FUNCTION CONTROL */
 
-    if(SiS_IF_DEF_LVDS==0) {    /* ifdef 301*/
+    if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
 
-	/* TW:   2. for 301 */
+	/* TW:   2. for 301 (301B, 302B 301LV, 302LV non-LCDA) */
 
-    	tempah=0x01;
-    	if(!(SiS_VBInfo&SetInSlaveMode)) {
-      		tempah=(tempah|0x02);
+    	tempah = 0x01;
+    	if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+      		tempah |= 0x02;
     	}
-    	if(!(SiS_VBInfo&SetCRT2ToRAMDAC)) {
-      		tempah=(tempah^0x05);
-      		if(!(SiS_VBInfo&SetCRT2ToLCD)) {
-        		tempah=(tempah^0x01);
+    	if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) {
+      		tempah ^= 0x05;
+      		if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+        		tempah ^= 0x01;
       		}
     	}
 
-    	tempcl=tempah;     /* 05/03/01 ynlai for TV display bug */
+	if(SiS_Pr->SiS_VBInfo & CRT2DisplayFlag)  tempah = 0;
 
     	if(HwDeviceExtension->jChipType < SIS_315H) {
-      		/* 300 series */
-      		tempah=(tempah<<5)&0xFF;
-      		if(SiS_VBInfo&CRT2DisplayFlag){
-        		tempah=0;
-      		}
-      		SiS_SetReg1(SiS_Part1Port,0x01,tempah);
 
-      		tempah=tempah>>5;
+		/* --- 300 series --- */
+
+      		tempah = (tempah << 5) & 0xFF;
+      		SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x01,tempah);
+      		tempah = (tempah >> 5) & 0xFF;
+
     	} else {
-      		/* 310 series */
-      		if(SiS_VBInfo&CRT2DisplayFlag){
-        		tempah=0;
-      		}
-      		tempah = (SiS_GetReg1(SiS_Part1Port,0x2E)&0xF8)|tempah;
-      		SiS_SetReg1(SiS_Part1Port,0x2E,tempah);
-      		tempah=tempcl;
-    	}
 
-    	if((SiS_ModeType==ModeVGA)&&(!(SiS_VBInfo&SetInSlaveMode))){
-      		tempah=tempah|0x010;
-    	}
-      
-     	if(SiS_LCDResInfo==Panel1024x768)
-         	tempah=tempah|0x080;
-  
-    	if((SiS_LCDResInfo==Panel1280x1024)||(SiS_LCDResInfo==Panel1280x960)){
-      		tempah=tempah|0x080;
+		/* --- 310 series --- */
+
+      		SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2E,0xF8,tempah);
+
     	}
-    	if(SiS_VBInfo&SetCRT2ToTV){
-      		if(SiS_VBInfo&SetInSlaveMode){
-        		if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {   /*301b*/
-          			if(SiS_SetFlag&TVSimuMode)
-                			tempah=tempah|0x020;
-        		} else
-          			tempah=tempah|0x020;
+
+    	if((SiS_Pr->SiS_ModeType == ModeVGA) && (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))) {
+      		tempah |= 0x10;
+	}
+
+	/* TW: Inserted from 630/301 BIOS */
+	if((HwDeviceExtension->jChipType < SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301)) {
+		if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+			tempah |= 0x80;
+		}
+	} else {
+		tempah |= 0x80;
+	}
+
+    	if(SiS_Pr->SiS_VBInfo & (SetCRT2ToTV - SetCRT2ToHiVisionTV)){
+      		if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+          		tempah |= 0x20;
       		}
     	}
-    	SiS_SetRegANDOR(SiS_Part4Port,0x0D,~0x0BF,tempah);
-    	tempah=0;
-    	if(SiS_VBInfo&SetCRT2ToTV) {
-      		if(SiS_VBInfo&SetInSlaveMode) {
-       			if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) { /*301b*/
-           		{
-            			SiS_SetFlag=SiS_SetFlag|RPLLDIV2XO;
-            			tempah=tempah|0x40;
-          		}
+
+    	SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0D,0x40,tempah);
+
+    	tempah = 0;
+    	if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+      		if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+       			if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+            			SiS_Pr->SiS_SetFlag |= RPLLDIV2XO;
+            			tempah |= 0x40;
        			} else {
-        			if(!(SiS_SetFlag&TVSimuMode)) {
-          				if(!(SiS_VBInfo&SetCRT2ToHiVisionTV)) {
-            					SiS_SetFlag=SiS_SetFlag|RPLLDIV2XO;
-            					tempah=tempah|0x40;
+        			if(!(SiS_Pr->SiS_SetFlag & TVSimuMode)) {
+#ifdef oldHV
+          				if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV)) {
+#endif
+            					SiS_Pr->SiS_SetFlag |= RPLLDIV2XO;
+            					tempah |= 0x40;
+#ifdef oldHV
           				}
+#endif
         			}
       			}
-     		}
-      		else {
-        		SiS_SetFlag=SiS_SetFlag|RPLLDIV2XO;
-        		tempah=tempah|0x40;
+     		} else {
+        		SiS_Pr->SiS_SetFlag |= RPLLDIV2XO;
+        		tempah |= 0x40;
       		}
     	}
-    	if(SiS_LCDResInfo==Panel1280x1024) tempah=tempah|0x80;
-    	if(SiS_LCDResInfo==Panel1280x960) tempah=tempah|0x80;
-    	SiS_SetReg1(SiS_Part4Port,0x0C,tempah);
+	/* TW: Inserted from 630/301LVx BIOS 1.10.6s */
+	if(HwDeviceExtension->jChipType >= SIS_315H) {
+	    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+	        if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04)
+		    tempah |= 0x40;
+	    }
+	}
+
+	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024 ||
+	            SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) {
+		tempah |= 0x80;
+	}
+
+    	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0C,tempah);
+
     } else {
 
-    	/* TW: 3. for LVDS, _not_ 301B/302B/301LV/302LV */
+    	/* TW: 3. for LVDS */
 
-    	tempah=0;
+	/* TW: Inserted if-statement - Part1Port 0x2e not assigned on 300 series */
+	if(HwDeviceExtension->jChipType >= SIS_315H) {
+
+	   /* TW: Inserted this entire section (BIOS 650/LVDS); added ModeType check
+	    *     (LVDS can only be slave in 8bpp modes)
+	    */
+	   tempah = 0x80;
+	   if( (modeflag & CRT2Mode) && (SiS_Pr->SiS_ModeType > ModeVGA) ) {
+	       if (SiS_Pr->SiS_VBInfo & DriverMode) {
+	           tempah |= 0x02;
+	       }
+	   }
+
+	   if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+               tempah |= 0x02;
+    	   }
+
+	   if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+	       tempah ^= 0x01;
+	   }
+
+	   if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) {
+	       tempah = 1;
+	   }
+
+    	   SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2e,0xF0,tempah);
+
+	} else {
+
+	   /* TW: Inserted entire section from 630/LVDS BIOS (added ModeType check) */
+	   tempah = 0;
+	   if( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) && (SiS_Pr->SiS_ModeType > ModeVGA) ) {
+               	  tempah |= 0x02;
+    	   }
+	   tempah <<= 5;
+
+	   if(SiS_Pr->SiS_VBInfo & DisableCRT2Display)  tempah = 0;
+
+	   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x01,tempah);
+
+	}
 
-    	if((!(SiS_VBInfo&SetInSlaveMode)) &&
-          	    (ModeNo!=0x2e)&&(ModeNo!=0x30)&&(ModeNo!=0x38)&&(ModeNo!=0x3A)) {
-      			tempah=tempah|0x02;
-    	}
-    	SiS_SetRegANDOR(SiS_Part1Port,0x2e,0xF0,tempah); /* <------------------- */
     }
+
   }
 
-  /*301b*/
-  if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
- 				&& (!(SiS_VBInfo&SetCRT2ToLCDA))){
-      if(SiS_IsDualEdge(BaseAddr))
-         SiS_SetRegANDOR(SiS_Part1Port,0x13,0xFB,0x00);
-      else
-         SiS_SetRegANDOR(SiS_Part1Port,0x13,0xFF,0x00);
-      if(SiS_IsDualEdge(BaseAddr))
-         SiS_SetRegANDOR(SiS_Part1Port,0x2c,0xCF,0x00);
-      else
-         SiS_SetRegANDOR(SiS_Part1Port,0x2c,0xFF,0x00);
-      if(SiS_IsDualEdge(BaseAddr))
-         SiS_SetRegANDOR(SiS_Part4Port,0x21,0x3F,0x00);
-      else
-         SiS_SetRegANDOR(SiS_Part4Port,0x21,0xFF,0x00);
+  /* TW: Inserted the entire following section */
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+
+      if(HwDeviceExtension->jChipType >= SIS_315H) {
+
+#ifdef SIS650301NEW    /* TW: This is done in 650/301LVx 1.10.6s BIOS */
+         tempah = 0x04;
+         tempbl = 0xfb;
+         if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+            tempah = 0x00;
+	    if(SiS_IsDualEdge(SiS_Pr, HwDeviceExtension, BaseAddr))
+	       tempbl = 0xff;
+         }
+         SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,tempbl,tempah);   
+
+	 /* TW: This in order to fix "TV-blue-bug" on 315+301 */
+         if(SiS_Pr->SiS_VBType & VB_SIS301) {
+	    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2c,0xCF);           /* RIGHT for 315+301 */
+	 } else {
+	    SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,0xCF,0x30);    /* WRONG for 315+301 */
+	 }
+
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,0x3f,0xc0);
+
+	 tempah = 0x00;
+         tempbl = 0x7f;
+         if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+            tempbl = 0xff;
+	    if(!(SiS_IsDualEdge(SiS_Pr, HwDeviceExtension, BaseAddr)))
+	       tempah |= 0x80;
+         }
+         SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,tempbl,tempah);
+
+#else
+         /* This is done in 650/301LV BIOS instead: */
+         tempah = 0x30;
+	 if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0;
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,0xcf,tempah);
+
+	 tempah = 0xc0;
+	 if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0;
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,0x3f,tempah);
+
+	 tempah = 0x80;
+	 if(SiS_Pr->SiS_VBInfo & DisableCRT2Display) tempah = 0;
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x23,0x7F,tempah);
+#endif
+
+      } else if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+
+         SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x21,0x3f);
+
+         if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | DisableCRT2Display))
+	    SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x23,0x7F);
+	 else
+	    SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x23,0x80);
+
+      }
+
+  } else {  /* LVDS */
+
+      if(HwDeviceExtension->jChipType >= SIS_315H) {
+         tempah = 0x04;
+	 tempbl = 0xfb;
+         if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+            tempah = 0x00;
+	    if(SiS_IsDualEdge(SiS_Pr, HwDeviceExtension, BaseAddr))
+	       tempbl = 0xff;
+         }
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,tempbl,tempah);
+
+	 if(SiS_Pr->SiS_VBInfo & DisableCRT2Display)
+	    SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,0xfb,0x00);
+
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2c,0xcf,0x30);
+      }
 
-      if(SiS_IsDualEdge(BaseAddr))
-         SiS_SetRegANDOR(SiS_Part4Port,0x23,0xFF,0x80);
-       else
-         SiS_SetRegANDOR(SiS_Part4Port,0x23,0xFF,0x00);     
   }
-  /*end 301b*/
+
 }
 
 void
-SiS_GetCRT2Data(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                USHORT RefreshRateTableIndex)
-{
-  if(SiS_IF_DEF_LVDS==0) { /* 301  */
-     if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-        if(SiS_VBInfo&SetCRT2ToLCDA)
-          SiS_GetCRT2DataLVDS(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex);
-        else
-          SiS_GetCRT2Data301(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex);
+SiS_GetCRT2Data(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                USHORT RefreshRateTableIndex,
+		PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+          SiS_GetCRT2DataLVDS(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+	                      HwDeviceExtension);
+        } else {
+	  if((HwDeviceExtension->jChipType < SIS_315H) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)){
+              SiS_GetCRT2Data301(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+	                         HwDeviceExtension);
+	      /* TW: Need LVDS Data for LCD on 630/301B! */
+	      SiS_GetCRT2DataLVDS(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+	                          HwDeviceExtension);
+	  } else {
+	      SiS_GetCRT2Data301(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+	                         HwDeviceExtension);
+          }
+        }
      } else
-     	SiS_GetCRT2Data301(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex);
-     return;
-  } else {  /* LVDS */
-     SiS_GetCRT2DataLVDS(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex);
-     return;
+     	SiS_GetCRT2Data301(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+	                   HwDeviceExtension);
+  } else {
+     SiS_GetCRT2DataLVDS(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                         HwDeviceExtension);
   }
 }
 
+/* Checked with 650/LVDS 1.10.07 BIOS */
 void
-SiS_GetCRT2DataLVDS(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                    USHORT RefreshRateTableIndex)
+SiS_GetCRT2DataLVDS(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                    USHORT RefreshRateTableIndex,
+		    PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-   USHORT tempax,tempbx;
-   USHORT CRT2Index,ResIndex;
-   SiS_LVDSDataStruct *LVDSData=NULL;
-
-   SiS_GetCRT2ResInfo(ROMAddr,ModeNo,ModeIdIndex);
-   /*301b*/
-   if((SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-   	 && (SiS_VBInfo&SetCRT2ToLCDA)) {
-      SiS_GetCRT2PtrA(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+   USHORT CRT2Index, ResIndex;
+   const SiS_LVDSDataStruct *LVDSData = NULL;
+
+   SiS_GetCRT2ResInfo(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+
+   if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+
+      SiS_GetCRT2PtrA(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
                       &CRT2Index,&ResIndex);
+
       switch (CRT2Index) {
-      	case  0:  LVDSData=SiS_LVDS1024x768Data_1;    break;
-      	case  1:  LVDSData=SiS_LVDS1280x1024Data_1;   break;
-      	case  2:  LVDSData=SiS_LVDS1280x1024Data_1;   break;
-    	/*  case  2:  LVDSData=SiS_LVDS1280x960Data_1;  break;*/
-      	case  3:  LVDSData=SiS_LVDS1024x768Data_2;    break;
-      	case  4:  LVDSData=SiS_LVDS1280x1024Data_2;   break;
-      	case  5:  LVDSData=SiS_LVDS1280x1024Data_2;   break;
-    	/*  case  5:  LVDSData=SiS_LVDS1280x960Data_2;  break; */
-       }    
+      	case  0:  LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1;    break;
+      	case  1:  LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_1;   break;
+        case  2:  LVDSData = SiS_Pr->SiS_LVDS1280x960Data_1;    break;
+	case  3:  LVDSData = SiS_Pr->SiS_LCDA1400x1050Data_1;   break;
+	case  4:  LVDSData = SiS_Pr->SiS_LCDA1600x1200Data_1;   break;
+      	case  5:  LVDSData = SiS_Pr->SiS_LVDS1024x768Data_2;    break;
+      	case  6:  LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_2;   break;
+      	case  7:  LVDSData = SiS_Pr->SiS_LVDS1280x960Data_2;    break;
+	case  8:  LVDSData = SiS_Pr->SiS_LCDA1400x1050Data_2;   break;
+	case  9:  LVDSData = SiS_Pr->SiS_LCDA1600x1200Data_2;   break;
+      }
+
    } else {
-      SiS_GetCRT2Ptr(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,&CRT2Index,&ResIndex);
+
+      /* TW: SiS630/301B needs LVDS Data! */
+      if( (HwDeviceExtension->jChipType < SIS_315H) &&
+          (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) &&
+	  (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) )
+              SiS_Pr->SiS_IF_DEF_LVDS = 1;
+
+      SiS_GetCRT2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                     &CRT2Index,&ResIndex,HwDeviceExtension);
+
+      /* TW: SiS630/301B needs LVDS Data! */
+      if( (HwDeviceExtension->jChipType < SIS_315H) &&
+          (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) &&
+	  (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) )
+              SiS_Pr->SiS_IF_DEF_LVDS = 0;
+
       switch (CRT2Index) {
-      	case  0:  LVDSData=SiS_LVDS800x600Data_1;    break;
-      	case  1:  LVDSData=SiS_LVDS1024x768Data_1;   break;
-      	case  2:  LVDSData=SiS_LVDS1280x1024Data_1;  break;
-      	case  3:  LVDSData=SiS_LVDS800x600Data_2;    break;
-      	case  4:  LVDSData=SiS_LVDS1024x768Data_2;   break;
-      	case  5:  LVDSData=SiS_LVDS1280x1024Data_2;  break;
-      	case  6:  LVDSData=SiS_LVDS640x480Data_1;    break;
-      	case  7:  LVDSData=SiS_CHTVUNTSCData;        break;
-      	case  8:  LVDSData=SiS_CHTVONTSCData;        break;
-      	case  9:  LVDSData=SiS_CHTVUPALData;         break;
-      	case 10:  LVDSData=SiS_CHTVOPALData;         break;
-      	case 11:  LVDSData=SiS_LVDS320x480Data_1;    break;
+      	case  0:  LVDSData = SiS_Pr->SiS_LVDS800x600Data_1;    break;
+      	case  1:  LVDSData = SiS_Pr->SiS_LVDS1024x768Data_1;   break;
+      	case  2:  LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_1;  break;
+      	case  3:  LVDSData = SiS_Pr->SiS_LVDS800x600Data_2;    break;
+      	case  4:  LVDSData = SiS_Pr->SiS_LVDS1024x768Data_2;   break;
+      	case  5:  LVDSData = SiS_Pr->SiS_LVDS1280x1024Data_2;  break;
+	case  6:  LVDSData = SiS_Pr->SiS_LVDS640x480Data_1;    break;
+        case  7:  LVDSData = SiS_Pr->SiS_LVDSXXXxXXXData_1;    break;  /* TW: New */
+	case  8:  LVDSData = SiS_Pr->SiS_LVDS1400x1050Data_1;  break;  /* TW: New */
+	case  9:  LVDSData = SiS_Pr->SiS_LVDS1400x1050Data_2;  break;  /* TW: New */
+      	case 10:  LVDSData = SiS_Pr->SiS_CHTVUNTSCData;        break;
+      	case 11:  LVDSData = SiS_Pr->SiS_CHTVONTSCData;        break;
+      	case 12:  LVDSData = SiS_Pr->SiS_CHTVUPALData;         break;
+      	case 13:  LVDSData = SiS_Pr->SiS_CHTVOPALData;         break;
+      	case 14:  LVDSData = SiS_Pr->SiS_LVDS320x480Data_1;    break;
+	case 15:  LVDSData = SiS_Pr->SiS_LVDS1024x600Data_1;   break;  /* TW: New */
+	case 16:  LVDSData = SiS_Pr->SiS_LVDS1152x768Data_1;   break;  /* TW: New */
+	case 17:  LVDSData = SiS_Pr->SiS_LVDS1024x600Data_2;   break;  /* TW: New */
+	case 18:  LVDSData = SiS_Pr->SiS_LVDS1152x768Data_2;   break;  /* TW: New */
      }
    }
-   SiS_VGAHT = (LVDSData+ResIndex)->VGAHT;
-   SiS_VGAVT = (LVDSData+ResIndex)->VGAVT;
-   SiS_HT = (LVDSData+ResIndex)->LCDHT;
-   SiS_VT = (LVDSData+ResIndex)->LCDVT;
-
-  /*301b*/ /* TW: I have NOT added LVDS check here */
-  if( (SiS_IF_DEF_LVDS==0) &&
-      (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))) {/*for test*/
-    if(!(SiS_LCDInfo&LCDNonExpanding)){
-         if(SiS_LCDResInfo==Panel1024x768){
-           tempax=1024;
-           tempbx=768;
+
+   SiS_Pr->SiS_VGAHT = (LVDSData+ResIndex)->VGAHT;
+   SiS_Pr->SiS_VGAVT = (LVDSData+ResIndex)->VGAVT;
+   SiS_Pr->SiS_HT = (LVDSData+ResIndex)->LCDHT;
+   SiS_Pr->SiS_VT = (LVDSData+ResIndex)->LCDVT;
+
+  if((SiS_Pr->SiS_IF_DEF_LVDS == 0) && (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
+
+    if(!(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)){
+         if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768){
+           SiS_Pr->SiS_HDE = 1024;
+           SiS_Pr->SiS_VDE = 768;
+         } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024){
+           SiS_Pr->SiS_HDE = 1280;
+           SiS_Pr->SiS_VDE = 1024;
+	 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050){
+           SiS_Pr->SiS_HDE = 1400;
+           SiS_Pr->SiS_VDE = 1050;
+	 } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200){
+           SiS_Pr->SiS_HDE = 1600;
+           SiS_Pr->SiS_VDE = 1200;
          } else {
-           tempax=1280;
-           tempbx=1024;
-         }
-         SiS_HDE=tempax;
-         SiS_VDE=tempbx;
+	   SiS_Pr->SiS_HDE = 1280;
+	   SiS_Pr->SiS_VDE = 960;
+	 }
     }
+
   } else {
-   if(SiS_IF_DEF_TRUMPION==0){
-     if(SiS_VBInfo&SetCRT2ToLCD){
-       if(!(SiS_LCDInfo&LCDNonExpanding)){
-         if(SiS_LCDResInfo==Panel640x480){
-           tempax=640;
-           tempbx=480;
-         } else if(SiS_LCDResInfo==Panel800x600){
-           tempax=800;
-           tempbx=600;
-         } else if(SiS_LCDResInfo==Panel1024x768){
-           tempax=1024;
-           tempbx=768;
-         } else {
-           tempax=1280;
-           tempbx=1024;
-         }
-         if(SiS_IF_DEF_FSTN){           /*fstn*/
-           tempax=320;
-           tempbx=480;
-         }
-         SiS_HDE=tempax;
-         SiS_VDE=tempbx;
-       }
-     }
-   }
-  } 
-  return;
+
+    if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) {
+      if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) && (!(SiS_Pr->SiS_LCDInfo & LCDPass11))) {
+        if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) {
+          if((!(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)) || (SiS_Pr->SiS_SetFlag & CRT2IsVGA)) {
+            if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
+              SiS_Pr->SiS_HDE = 800;
+              SiS_Pr->SiS_VDE = 600;
+            } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+              SiS_Pr->SiS_HDE = 1024;
+              SiS_Pr->SiS_VDE = 768;
+            } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+              SiS_Pr->SiS_HDE = 1280;
+              SiS_Pr->SiS_VDE = 1024;
+            } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+	      SiS_Pr->SiS_HDE = 1024;
+              SiS_Pr->SiS_VDE = 600;
+	    } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+	      SiS_Pr->SiS_HDE = 1400;
+              SiS_Pr->SiS_VDE = 1050;
+	    } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) {
+	      SiS_Pr->SiS_HDE = 1152;
+	      SiS_Pr->SiS_VDE = 768;
+	    } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x864) {
+	      SiS_Pr->SiS_HDE = 1152;
+	      SiS_Pr->SiS_VDE = 864;
+	    } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) {
+	      SiS_Pr->SiS_HDE = 1280;
+	      SiS_Pr->SiS_VDE = 768;
+	    } else {
+	      SiS_Pr->SiS_HDE = 1600;
+	      SiS_Pr->SiS_VDE = 1200;
+	    }
+            if(SiS_Pr->SiS_IF_DEF_FSTN) {
+              SiS_Pr->SiS_HDE = 320;
+              SiS_Pr->SiS_VDE = 480;
+            }
+          }
+        }
+      }
+    }
+  }
 }
 
+/* TW: Checked against 630/301B BIOS; does not check VDE values for LCD */
 void
-SiS_GetCRT2Data301(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                        USHORT RefreshRateTableIndex)
+SiS_GetCRT2Data301(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                   USHORT RefreshRateTableIndex,
+		   PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT tempax,tempbx,modeflag;
   USHORT resinfo;
   USHORT CRT2Index,ResIndex;
-  SiS_LCDDataStruct *LCDPtr=NULL;
-  SiS_TVDataStruct  *TVPtr=NULL;
+  const SiS_LCDDataStruct *LCDPtr = NULL;
+  const SiS_TVDataStruct  *TVPtr  = NULL;
 
   if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-    	resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+    	resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
   } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-    	resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  }
+  SiS_Pr->SiS_NewFlickerMode = 0;
+  SiS_Pr->SiS_RVBHRS = 50;
+  SiS_Pr->SiS_RY1COE = 0;
+  SiS_Pr->SiS_RY2COE = 0;
+  SiS_Pr->SiS_RY3COE = 0;
+  SiS_Pr->SiS_RY4COE = 0;
+
+  SiS_GetCRT2ResInfo(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+
+  /* TW: For VGA2 ("RAMDAC2") */
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC){
+     SiS_GetRAMDAC2DATA(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                        HwDeviceExtension);
+     return;
   }
-  SiS_NewFlickerMode=0;
-  SiS_RVBHRS=50;
-  SiS_RY1COE=0;
-  SiS_RY2COE=0;
-  SiS_RY3COE=0;
-  SiS_RY4COE=0;
-
-  SiS_GetCRT2ResInfo(ROMAddr,ModeNo,ModeIdIndex);
-  if(SiS_VBInfo&SetCRT2ToRAMDAC){
-    	SiS_GetRAMDAC2DATA(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex);
-    	return;
-  }
-
-  if(SiS_VBInfo&SetCRT2ToTV){
-    SiS_GetCRT2Ptr(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
-                   &CRT2Index,&ResIndex);
+
+  /* TW: For TV */
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+
+    SiS_GetCRT2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                   &CRT2Index,&ResIndex,HwDeviceExtension);
+
     switch (CRT2Index) {
-      case  2:  TVPtr=SiS_ExtHiTVData;   break;
-      case  3:  TVPtr=SiS_ExtPALData;    break;
-      case  4:  TVPtr=SiS_ExtNTSCData;   break;
-      case  7:  TVPtr=SiS_St1HiTVData;   break;
-      case  8:  TVPtr=SiS_StPALData;     break;
-      case  9:  TVPtr=SiS_StNTSCData;    break;
-      case 12:  TVPtr=SiS_St2HiTVData;   break;
-      default:  TVPtr=SiS_StPALData;     break;  /* TW: Just to avoid a crash */
-    }
-
-    SiS_RVBHCMAX = (TVPtr+ResIndex)->RVBHCMAX;
-    SiS_RVBHCFACT = (TVPtr+ResIndex)->RVBHCFACT;
-    SiS_VGAHT = (TVPtr+ResIndex)->VGAHT;
-    SiS_VGAVT = (TVPtr+ResIndex)->VGAVT;
-    SiS_HDE = (TVPtr+ResIndex)->TVHDE;
-    SiS_VDE = (TVPtr+ResIndex)->TVVDE;
-    SiS_RVBHRS = (TVPtr+ResIndex)->RVBHRS;
-    SiS_NewFlickerMode = (TVPtr+ResIndex)->FlickerMode;
-    if(SiS_VBInfo&SetCRT2ToHiVisionTV ) {
-      	if(resinfo==0x08) SiS_NewFlickerMode=0x40;
-      	if(resinfo==0x09) SiS_NewFlickerMode=0x40;
-	if(resinfo==0x10) SiS_NewFlickerMode=0x40;
-    }
-    if(SiS_VBInfo&SetCRT2ToHiVisionTV ) {
-      if(SiS_VGAVDE==350) SiS_SetFlag=SiS_SetFlag|TVSimuMode;
-      tempax=ExtHiTVHT;
-      tempbx=ExtHiTVVT;
-      if(SiS_VBInfo&SetInSlaveMode) {
-        if(SiS_SetFlag&TVSimuMode) {
-          tempax=StHiTVHT;
-          tempbx=StHiTVVT;
-          if(!(modeflag&Charx8Dot)){
-            tempax=StHiTextTVHT;
-            tempbx=StHiTextTVVT;
+#ifdef oldHV
+      case  2:  TVPtr = SiS_Pr->SiS_ExtHiTVData;   break;
+      case  7:  TVPtr = SiS_Pr->SiS_St1HiTVData;   break;
+      case 12:  TVPtr = SiS_Pr->SiS_St2HiTVData;   break;
+#endif
+      case  3:  TVPtr = SiS_Pr->SiS_ExtPALData;    break;
+      case  4:  TVPtr = SiS_Pr->SiS_ExtNTSCData;   break;
+      case  8:  TVPtr = SiS_Pr->SiS_StPALData;     break;
+      case  9:  TVPtr = SiS_Pr->SiS_StNTSCData;    break;
+      default:  TVPtr = SiS_Pr->SiS_StPALData;     break;  /* TW: Just to avoid a crash */
+    }
+
+    SiS_Pr->SiS_RVBHCMAX  = (TVPtr+ResIndex)->RVBHCMAX;
+    SiS_Pr->SiS_RVBHCFACT = (TVPtr+ResIndex)->RVBHCFACT;
+    SiS_Pr->SiS_VGAHT     = (TVPtr+ResIndex)->VGAHT;
+    SiS_Pr->SiS_VGAVT     = (TVPtr+ResIndex)->VGAVT;
+    SiS_Pr->SiS_HDE       = (TVPtr+ResIndex)->TVHDE;
+    SiS_Pr->SiS_VDE       = (TVPtr+ResIndex)->TVVDE;
+    SiS_Pr->SiS_RVBHRS    = (TVPtr+ResIndex)->RVBHRS;
+    SiS_Pr->SiS_NewFlickerMode = (TVPtr+ResIndex)->FlickerMode;
+
+    if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {   /* TW: NOT oldHV! */
+
+      	if(resinfo == 0x08) SiS_Pr->SiS_NewFlickerMode = 0x40;
+      	if(resinfo == 0x09) SiS_Pr->SiS_NewFlickerMode = 0x40;
+	if(resinfo == 0x12) SiS_Pr->SiS_NewFlickerMode = 0x40;
+
+        if(SiS_Pr->SiS_VGAVDE == 350) SiS_Pr->SiS_SetFlag |= TVSimuMode;
+
+        SiS_Pr->SiS_HT = ExtHiTVHT;
+        SiS_Pr->SiS_VT = ExtHiTVVT;
+        if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+          if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+            SiS_Pr->SiS_HT = StHiTVHT;
+            SiS_Pr->SiS_VT = StHiTVVT;
+            if(!(modeflag & Charx8Dot)){
+              SiS_Pr->SiS_HT = StHiTextTVHT;
+              SiS_Pr->SiS_VT = StHiTextTVVT;
+            }
           }
         }
+
+    } else {
+
+      SiS_Pr->SiS_RY1COE = (TVPtr+ResIndex)->RY1COE;
+      SiS_Pr->SiS_RY2COE = (TVPtr+ResIndex)->RY2COE;
+      SiS_Pr->SiS_RY3COE = (TVPtr+ResIndex)->RY3COE;
+      SiS_Pr->SiS_RY4COE = (TVPtr+ResIndex)->RY4COE;
+
+      if(modeflag & HalfDCLK) {
+         SiS_Pr->SiS_RY1COE = 0x00;
+         SiS_Pr->SiS_RY2COE = 0xf4;
+         SiS_Pr->SiS_RY3COE = 0x10;
+         SiS_Pr->SiS_RY4COE = 0x38;
       }
-    }
-    if(!(SiS_VBInfo&SetCRT2ToHiVisionTV)) {
-      SiS_RY1COE = (TVPtr+ResIndex)->RY1COE;
-      SiS_RY2COE = (TVPtr+ResIndex)->RY2COE;
-      if(modeflag&HalfDCLK) {
-        SiS_RY1COE = 0x00;
-        SiS_RY2COE = 0xf4;
-      }
-      SiS_RY3COE = (TVPtr+ResIndex)->RY3COE;
-      SiS_RY4COE = (TVPtr+ResIndex)->RY4COE;
-      if(modeflag&HalfDCLK) {
-        SiS_RY3COE = 0x10;
-        SiS_RY4COE = 0x38;
-      }
-      if(!(SiS_VBInfo&SetPALTV)){
-        tempax=NTSCHT;
-        tempbx=NTSCVT;
-      }
-      else{
-        tempax=PALHT;
-        tempbx=PALVT;
+
+      if(!(SiS_Pr->SiS_VBInfo & SetPALTV)){
+        SiS_Pr->SiS_HT = NTSCHT;
+#if 0   /* TW: Not in 650/301LVx 1.10.6s */
+	if((ModeNo == 0x4a) || (ModeNo == 0x38)) SiS_Pr->SiS_HT = NTSC2HT;
+#endif
+        SiS_Pr->SiS_VT = NTSCVT;
+      } else {
+        SiS_Pr->SiS_HT = PALHT;
+        SiS_Pr->SiS_VT = PALVT;
       }
+
     }
-    SiS_HT=tempax;
-    SiS_VT=tempbx;
+
     return;
   }
 
-  if(SiS_VBInfo&SetCRT2ToLCD){
-    SiS_GetCRT2Ptr(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
-                   &CRT2Index,&ResIndex);
+  /* TW: For LCD */
+  /* TW: Checked against 650/301LV; CRT2Index different (but does not matter) */
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+
+    SiS_GetCRT2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                   &CRT2Index,&ResIndex,HwDeviceExtension);
+
     switch (CRT2Index) {
-      case  0: LCDPtr = SiS_ExtLCD1024x768Data;        break;
-      case  1: LCDPtr = SiS_ExtLCD1280x1024Data;       break;
-      case  5: LCDPtr = SiS_StLCD1024x768Data;         break;
-      case  6: LCDPtr = SiS_StLCD1280x1024Data;        break;
-      case 10: LCDPtr = SiS_St2LCD1024x768Data;        break;
-      case 11: LCDPtr = SiS_St2LCD1280x1024Data;       break;
-      case 13: LCDPtr = SiS_NoScaleData;               break;
-      case 14: LCDPtr = SiS_LCD1280x960Data;           break;
-      default: LCDPtr = SiS_ExtLCD1024x768Data;	       break; /* TW: Just to avoid a crash */
-    }
-
-    SiS_RVBHCMAX = (LCDPtr+ResIndex)->RVBHCMAX;
-    SiS_RVBHCFACT = (LCDPtr+ResIndex)->RVBHCFACT;
-    SiS_VGAHT = (LCDPtr+ResIndex)->VGAHT;
-    SiS_VGAVT = (LCDPtr+ResIndex)->VGAVT;
-    SiS_HT = (LCDPtr+ResIndex)->LCDHT;
-    SiS_VT = (LCDPtr+ResIndex)->LCDVT;
-    tempax=1024;
-    if(SiS_SetFlag&LCDVESATiming) {
-      if(SiS_VGAVDE==350) tempbx=560;
-      else if(SiS_VGAVDE==400) tempbx=640;
-      else tempbx=768;
-    }
-    else {
-      if(SiS_VGAVDE==357) tempbx=527;
-      else if(SiS_VGAVDE==420) tempbx=620;
-      else if(SiS_VGAVDE==525) tempbx=775;
-      else if(SiS_VGAVDE==600) tempbx=775;
-      else if(SiS_VGAVDE==350) tempbx=560;
-      else if(SiS_VGAVDE==400) tempbx=640;
-      else tempbx=768;
-    }
-    if(SiS_LCDResInfo==Panel1280x1024){
-      tempax=1280;
-      if(SiS_VGAVDE==360) tempbx=768;
-      else if(SiS_VGAVDE==375) tempbx=800;
-           else if(SiS_VGAVDE==405) tempbx=864;
-                else tempbx=1024;
-    }
-    if(SiS_LCDResInfo==Panel1280x960){
-      tempax=1280;
-      if(SiS_VGAVDE==350) tempbx=700;
-      else if(SiS_VGAVDE==400) tempbx=800;
-           else if(SiS_VGAVDE==1024) tempbx=960;
-                else tempbx=960;
-    }
-    if(SiS_LCDInfo&LCDNonExpanding) {
-       tempax=SiS_VGAHDE;
-       tempbx=SiS_VGAVDE;
+      case  0: LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data;        break; /* VESA Timing */
+      case  1: LCDPtr = SiS_Pr->SiS_ExtLCD1280x1024Data;       break; /* VESA Timing */
+      case  5: LCDPtr = SiS_Pr->SiS_StLCD1024x768Data;         break; /* Obviously unused */
+      case  6: LCDPtr = SiS_Pr->SiS_StLCD1280x1024Data;        break; /* Obviously unused */
+      case 10: LCDPtr = SiS_Pr->SiS_St2LCD1024x768Data;        break; /* Non-VESA Timing */
+      case 11: LCDPtr = SiS_Pr->SiS_St2LCD1280x1024Data;       break; /* Non-VESA Timing */
+      case 13: LCDPtr = SiS_Pr->SiS_NoScaleData1024x768;       break; /* Non-expanding */
+      case 14: LCDPtr = SiS_Pr->SiS_NoScaleData1280x1024;      break; /* Non-expanding */
+      case 15: LCDPtr = SiS_Pr->SiS_LCD1280x960Data;           break; /* 1280x960 */
+      case 20: LCDPtr = SiS_Pr->SiS_ExtLCD1400x1050Data;       break; /* VESA Timing */
+      case 21: LCDPtr = SiS_Pr->SiS_NoScaleData1400x1050;      break; /* Non-expanding */
+      case 22: LCDPtr = SiS_Pr->SiS_StLCD1400x1050Data;	       break; /* Non-VESA Timing */
+      case 23: LCDPtr = SiS_Pr->SiS_ExtLCD1600x1200Data;       break; /* VESA Timing */
+      case 24: LCDPtr = SiS_Pr->SiS_NoScaleData1600x1200;      break; /* Non-expanding */
+      case 25: LCDPtr = SiS_Pr->SiS_StLCD1600x1200Data;	       break; /* Non-VESA Timing */
+      default: LCDPtr = SiS_Pr->SiS_ExtLCD1024x768Data;	       break; /* Just to avoid a crash */
+    }
+
+    SiS_Pr->SiS_RVBHCMAX  = (LCDPtr+ResIndex)->RVBHCMAX;
+    SiS_Pr->SiS_RVBHCFACT = (LCDPtr+ResIndex)->RVBHCFACT;
+    SiS_Pr->SiS_VGAHT     = (LCDPtr+ResIndex)->VGAHT;
+    SiS_Pr->SiS_VGAVT     = (LCDPtr+ResIndex)->VGAVT;
+    SiS_Pr->SiS_HT        = (LCDPtr+ResIndex)->LCDHT;
+    SiS_Pr->SiS_VT        = (LCDPtr+ResIndex)->LCDVT;
+
+    tempax = 1024;
+    if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
+      if     (SiS_Pr->SiS_VGAVDE == 350) tempbx = 560;
+      else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640;
+      else                               tempbx = 768;
+    } else {
+      if     (SiS_Pr->SiS_VGAVDE == 357) tempbx = 527;
+      else if(SiS_Pr->SiS_VGAVDE == 420) tempbx = 620;
+      else if(SiS_Pr->SiS_VGAVDE == 525) tempbx = 775;
+      else if(SiS_Pr->SiS_VGAVDE == 600) tempbx = 775;
+      else if(SiS_Pr->SiS_VGAVDE == 350) tempbx = 560;
+      else if(SiS_Pr->SiS_VGAVDE == 400) tempbx = 640;
+      else                               tempbx = 768;
+    }
+    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024){
+      tempax = 1280;
+      if     (SiS_Pr->SiS_VGAVDE == 360) tempbx = 768;
+      else if(SiS_Pr->SiS_VGAVDE == 375) tempbx = 800;
+      else if(SiS_Pr->SiS_VGAVDE == 405) tempbx = 864;
+      else                               tempbx = 1024;
+    }
+    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960){
+      tempax = 1280;
+      if     (SiS_Pr->SiS_VGAVDE == 350)  tempbx = 700;
+      else if(SiS_Pr->SiS_VGAVDE == 400)  tempbx = 800;
+      else if(SiS_Pr->SiS_VGAVDE == 1024) tempbx = 960;
+      else                                tempbx = 960;
+    }
+    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050){
+      tempax = 1400;
+      tempbx = 1050;
+    }
+    if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) {
+       tempax = SiS_Pr->SiS_VGAHDE;
+       tempbx = SiS_Pr->SiS_VGAVDE;
     }
-    SiS_HDE=tempax;
-    SiS_VDE=tempbx;
+    SiS_Pr->SiS_HDE = tempax;
+    SiS_Pr->SiS_VDE = tempbx;
     return;
   }
 }
 
 USHORT
-SiS_GetResInfo(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SiS_GetResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
   USHORT resindex;
 
-  if(ModeNo<=0x13){
-    	resindex=SiS_SModeIDTable[ModeIdIndex].St_ResInfo;              /* si+St_ResInfo */
-  } else {
-    	resindex=SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;            	/* si+Ext_ResInfo */
-  }
+  if(ModeNo<=0x13)
+    	resindex=SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+  else
+    	resindex=SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+
   return(resindex);
 }
 
+/* TW: Checked against 650/301LV, 650/LVDS, 630/LVDS, 630/301 and 630/301B BIOS */
 void
-SiS_GetCRT2ResInfo(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SiS_GetCRT2ResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                   PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT xres,yres,modeflag,resindex;
+  USHORT xres,yres,modeflag=0,resindex;
 
-  resindex=SiS_GetResInfo(ROMAddr,ModeNo,ModeIdIndex);
-  if(ModeNo<=0x13){
-    	xres=SiS_StResInfo[resindex].HTotal;
-    	yres=SiS_StResInfo[resindex].VTotal;
-  } else {
-    	xres=SiS_ModeResInfo[resindex].HTotal;                         		/* xres->ax */
-    	yres=SiS_ModeResInfo[resindex].VTotal;                         		/* yres->bx */
-    	modeflag=SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;      		/* si+St_ModeFlag */
-    	if(SiS_IF_DEF_FSTN){							/*fstn*/
-       		xres=xres*2;
-       		yres=yres*2;
-    	} else {
-      		if(modeflag&HalfDCLK) { xres=xres*2;}
-      		if(modeflag&DoubleScanMode) {yres=yres*2;}
-    	}
+  resindex = SiS_GetResInfo(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex);
+
+  if(ModeNo <= 0x13) {
+    	xres = SiS_Pr->SiS_StResInfo[resindex].HTotal;
+    	yres = SiS_Pr->SiS_StResInfo[resindex].VTotal;
+  } else {
+	xres = SiS_Pr->SiS_ModeResInfo[resindex].HTotal;
+    	yres = SiS_Pr->SiS_ModeResInfo[resindex].VTotal;
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
   }
-  if(SiS_IF_DEF_LVDS==0) {
-    	if(SiS_LCDResInfo==Panel1280x1024) {
-      		if(yres==400) yres=405;
-      		if(yres==350) yres=360;
-      		if(SiS_SetFlag&LCDVESATiming) {
-        		if(yres==360) yres=375;
+
+  /* TW: Inserted entire if-section from 650/LVDS BIOS 1.10.07: */
+  if((HwDeviceExtension->jChipType >= SIS_315H) && (SiS_Pr->SiS_IF_DEF_LVDS == 1)) {
+      if((ModeNo != 0x03) && (SiS_Pr->SiS_SetFlag & CRT2IsVGA)) {
+          if(yres == 350) yres = 400;
+      }
+      if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x3a) & 0x01) {
+ 	  if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x34) == 0x12)
+	      yres = 400;
+      }
+  }
+
+  if(ModeNo > 0x13) {
+      if(SiS_Pr->SiS_IF_DEF_FSTN == 1){
+            xres *= 2;
+            yres *= 2;
+      } else {
+  	    if(modeflag & HalfDCLK)       xres *= 2;
+  	    if(modeflag & DoubleScanMode) yres *= 2;
+      }
+  }
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+        /* TW: Inserted from 650/301LV BIOS */
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+                if(xres == 720) xres = 640;
+	} else {
+	   if(xres == 720) xres = 640;
+    	   if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+      		if(yres == 400) yres = 405;
+      		if(yres == 350) yres = 360;
+      		if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
+        		if(yres == 360) yres = 375;
       		}
-   	 }
-    	if(SiS_LCDResInfo==Panel1024x768){
-      		if(!(SiS_SetFlag&LCDVESATiming)) {
-        		if(!(SiS_LCDInfo&LCDNonExpanding)) {
-          			if(yres==350) yres=357;
-          			if(yres==400) yres=420;
-/*          			if(!OldBios)             */
-            			if(yres==480) yres=525;
+   	   }
+    	   if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768){
+      		if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+        		if(!(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)) {
+          			if(yres == 350) yres = 357;
+          			if(yres == 400) yres = 420;
+            			if(yres == 480) yres = 525;
         		}
       		}
-    	}
-  } else { /* LVDS - does not support 720x??? */
-    	if(xres==720) xres=640;
+    	   }
+	   /* TW: Inserted for 630/301B */
+	   if(HwDeviceExtension->jChipType < SIS_315H) {
+	      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+                  if(xres == 720) xres = 640;
+	      }
+	   }
+	}
+  } else {
+    	if(xres == 720) xres = 640;
+	/* TW: Inserted from 650/LVDS and 630/LVDS BIOS */
+	if(SiS_Pr->SiS_SetFlag & CRT2IsVGA) {
+	      yres = 400;
+	      if(HwDeviceExtension->jChipType >= SIS_315H) {
+	          if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x80) yres = 480;
+	      } else {
+	          if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x80) yres = 480;
+	      }
+	}
   }
-  SiS_VGAHDE=xres;
-  SiS_HDE=xres;
-  SiS_VGAVDE=yres;
-  SiS_VDE=yres;
+  SiS_Pr->SiS_VGAHDE = SiS_Pr->SiS_HDE = xres;
+  SiS_Pr->SiS_VGAVDE = SiS_Pr->SiS_VDE = yres;
 }
 
+/* TW: Checked against 650/301 and 650/LVDS (1.10.07) BIOS; modified for new panel resolutions */
+/* TW: Done differently in 630/301B BIOS; but same effect; checked against 630/301 */
 void
-SiS_GetCRT2Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-	       USHORT RefreshRateTableIndex,USHORT *CRT2Index,USHORT *ResIndex)
-{
-  USHORT tempbx,tempal=0;
-  USHORT Flag;
-  if(SiS_IF_DEF_LVDS==0) {
-    	if(SiS_VBInfo&SetCRT2ToLCD){              /* LCD */
-      		tempbx=SiS_LCDResInfo;
-      		tempbx=tempbx-Panel1024x768;
-      		if(!(SiS_SetFlag&LCDVESATiming)) {
-        		tempbx+=5;
-/*      		GetRevisionID();  */
-        		tempbx+=5;
-       		}
+SiS_GetCRT2Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+	       USHORT RefreshRateTableIndex,USHORT *CRT2Index,USHORT *ResIndex,
+	       PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT tempbx=0,tempal=0;
+  USHORT Flag,resinfo=0;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+    	if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {                            /* LCD */
+	        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) {
+			tempbx = 15;
+		} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+		        tempbx = 20;
+			if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx = 21;
+			if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx = 22;
+		} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
+		        tempbx = 23;
+			if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx = 24;
+			if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) tempbx = 25;
+		} else if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) {
+			tempbx = 13;
+			if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) tempbx++;
+		} else {
+      		   tempbx = SiS_Pr->SiS_LCDResInfo - SiS_Pr->SiS_Panel1024x768;
+      		   if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+        		tempbx += 5;
+                        /* GetRevisionID();  */
+			/* TW: BIOS only adds 5 once */
+        		tempbx += 5;
+       		   }
+	        }
      	} else {
-       		if(SiS_VBInfo&SetCRT2ToHiVisionTV){              /* TV */
-         		if(SiS_VGAVDE>480) SiS_SetFlag=SiS_SetFlag&(!TVSimuMode);
-         		tempbx=2;
-         		if(SiS_VBInfo&SetInSlaveMode) {
-            			if(!(SiS_SetFlag&TVSimuMode)) tempbx=10;
+#ifdef oldHV					           /* TV */
+       		if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV){
+         		if(SiS_Pr->SiS_VGAVDE > 480) SiS_Pr->SiS_SetFlag &= (~TVSimuMode); /* TW: Was "(!TVSimuMode)" - WRONG */
+         		tempbx = 2;
+         		if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+            			if(!(SiS_Pr->SiS_SetFlag & TVSimuMode)) tempbx = 12;  /* TW: Was 10! - WRONG */
          		}
        		} else {
-         		if(SiS_VBInfo&SetPALTV){
-           			tempbx=3;
-         		} else {
-           			tempbx=4;
-         		}
-         		if(SiS_SetFlag&TVSimuMode){
-           			tempbx=tempbx+5;
-         		}
+#endif
+         		if(SiS_Pr->SiS_VBInfo & SetPALTV) tempbx = 3;
+         		else tempbx = 4;
+         		if(SiS_Pr->SiS_SetFlag & TVSimuMode) tempbx += 5;
+#ifdef oldHV
        		}
+#endif
      	}
 
-     	if(ModeNo<=0x13){
-       		tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-     	} else {
-       		tempal = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-     	}
-     	tempal=tempal&0x3F;
-     	/*301b*/
-      	if((SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-       					&& (SiS_VBInfo&SetCRT2ToTV)) {
-        	/*look*/
-      		if(tempal==0x06) tempal=0x07;
+     	if(ModeNo <= 0x13)
+       		tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+     	else
+       		tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+
+     	tempal &= 0x3F;
+
+      	if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
+                     && (SiS_Pr->SiS_VBInfo & (SetCRT2ToTV-SetCRT2ToHiVisionTV))) {  /* TW: Added -Hivision (BIOS) */
+      		if(tempal == 0x06) tempal = 0x07;
         }
-   	/*end 301b*/
-     	if((0x31<=ModeNo)&&(ModeNo<=0x35)) tempal=6;
-     	if(SiS_LCDInfo&LCDNonExpanding) tempbx=0x0D;
-     	if(SiS_LCDResInfo==Panel1280x960) tempbx=0x0E;	/* TW !!!! */
-     	*CRT2Index=tempbx;
-     	*ResIndex=tempal;
+
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+            if((ModeNo == 0x31) || (ModeNo == 0x32)) tempal = 6;
+	}
+
+     	*CRT2Index = tempbx;
+     	*ResIndex = tempal;
+
   } else {   /* LVDS */
-    	Flag=1;
-    	tempbx=0;
-    	if(SiS_IF_DEF_CH7005==1) {
-      		if(!(SiS_VBInfo&SetCRT2ToLCD)) {
-        		Flag=0;
-        		tempbx=7;
-        		if(SiS_VBInfo&SetPALTV) tempbx=tempbx+2;
-        		if(SiS_VBInfo&SetCHTVOverScan) tempbx=tempbx+1;
-      		}
-    	}
-    	if(Flag==1) {
-      		tempbx=SiS_LCDResInfo-Panel800x600;
-      		if(SiS_LCDInfo&LCDNonExpanding){
-        		tempbx=tempbx+3;
+
+    	Flag = 1;
+    	tempbx = 0;
+    	if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+      		if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+        		Flag = 0;
+        		tempbx = 10;
+        		if(SiS_Pr->SiS_VBInfo & SetPALTV)        tempbx += 2;
+        		if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx += 1;
       		}
     	}
-     	if(SiS_LCDResInfo==Panel640x480){
-        	tempbx=6;
-      	}
-     	/*fstn*/
-     	if(SiS_IF_DEF_FSTN){
-       	 	if(SiS_LCDResInfo==Panel320x480){
-         		tempbx=11;                        /* not same with asmber code */
-         		tempal=6;	/* TW: That can't work - is being overwritten below... */
+
+    	if(Flag == 1) {
+      		tempbx = SiS_Pr->SiS_LCDResInfo - SiS_Pr->SiS_PanelMinLVDS;
+		if(SiS_Pr->SiS_LCDResInfo <= SiS_Pr->SiS_Panel1280x1024) {
+   	      	    if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)  tempbx += 3;
+		} else {
+		    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+			tempbx = 8;
+			if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)  tempbx++;
+		    }
+        	    if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+			tempbx = 7;
+        	    }
+
+     		    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480)  tempbx = 6;
+
+		    /* TW: Inserted from 630/LVDS 2.04.5c BIOS */
+		    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+			tempbx = 15;
+  		        if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)  tempbx += 2;
+		    }
+		    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) {
+		        tempbx = 16;
+			if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)  tempbx += 2;
+		    }
+		 }
+	}
+
+    	if(ModeNo <= 0x13)
+      		tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+    	else {
+      		tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+		resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+	}
+
+	if(SiS_Pr->SiS_IF_DEF_FSTN){
+       	 	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel320x480){
+         		tempbx = 14;
+         		tempal = 6;
         	}
     	}
 
-	else 				/* TW: .... unless I place an "else" here */
-     
-    	if(ModeNo<=0x13){
-      		tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-    	} else {
-      		tempal = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-    	}
-    	tempal=tempal&0x1F;
-    	*CRT2Index=tempbx;
-    	*ResIndex=tempal;
+	/* TW: Inserted from 650/LVDS BIOS */
+	if(SiS_Pr->SiS_SetFlag & CRT2IsVGA) {
+	        if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel640x480) tempal = 7;
+		if(HwDeviceExtension->jChipType < SIS_315H) {
+		    /* TW: Inserted from 630/LVDS (2.04.5c) and 630/301B (II) BIOS */
+		    if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x80) tempal++;
+		}
+
+	}
+
+	/* TW: Inserted from 630/301B BIOS */
+	if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+	    if(ModeNo > 0x13) {
+	        if((resinfo == 0x0c) || (resinfo == 0x0d))  /* 720 */
+		    tempal = 6;
+	    }
+	}
+
+    	*CRT2Index = tempbx;
+    	*ResIndex = tempal & 0x1F;
   }
 }
 
 void
-SiS_GetCRT2PtrA(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+SiS_GetCRT2PtrA(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
 		USHORT RefreshRateTableIndex,USHORT *CRT2Index,
 		USHORT *ResIndex)
 {
   USHORT tempbx,tempal;
 
-  tempbx=SiS_LCDResInfo-Panel1024x768;
-  if(SiS_LCDInfo&LCDNonExpanding){
-        tempbx=tempbx+3;
-  }
-  if(ModeNo<=0x13){
-      	tempal = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  tempbx = SiS_Pr->SiS_LCDResInfo;
+
+  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
+       tempbx = 4;
+  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+       tempbx = 3;
   } else {
-      	tempal = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+       tempbx -= SiS_Pr->SiS_Panel1024x768;
   }
-  tempal=tempal&0x1F;
-  *CRT2Index=tempbx;
-  *ResIndex=tempal;
-}
-/*end 301b*/
 
-USHORT
-SiS_GetRatePtrCRT2(ULONG ROMAddr, USHORT ModeNo, USHORT ModeIdIndex)
-{
-  /* TW: These tables are being indexed with SiS_LCDResInfo.
-   *     This is equal to the Panel???x??? constants in initdef.h
-   *     and is eg. 2 for 1024x768; these tables were each one
-   *     value too short!
-   */
-  SHORT  LCDRefreshIndex[]  = {0x00,0x00,0x03,0x01,0x01};
-  SHORT  LCDARefreshIndex[] = {0x00,0x00,0x03,0x01,0x01,0x01,0x01,0x01};
-  USHORT RefreshRateTableIndex,i,backup_i;
-  USHORT modeflag,index,temp;
+  if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)  tempbx += 5;
 
-  if (ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-  }else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-  }
+  if(ModeNo <= 0x13)
+      	tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  else
+      	tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+
+  *CRT2Index = tempbx;
+  *ResIndex = tempal & 0x1F;
+}
+
+/* TW: New from 650/301LVx BIOS */
+void
+SiS_GetCRT2Part2Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+		    USHORT RefreshRateTableIndex,USHORT *CRT2Index,
+		    USHORT *ResIndex)
+{
+  USHORT tempbx,tempal;
+
+  if(ModeNo <= 0x13)
+      	tempal = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  else
+      	tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+
+  tempbx = SiS_Pr->SiS_LCDResInfo;
+
+  if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)    tempbx += 16;
+  else if(SiS_Pr->SiS_SetFlag & LCDVESATiming) tempbx += 32;
+
+  *CRT2Index = tempbx;
+  *ResIndex = tempal & 0x3F;
+}
+
+/* TW: Checked against all (incl 650/LVDS (1.10.07), 630/301B, 630/301) BIOSes */
+USHORT
+SiS_GetRatePtrCRT2(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo, USHORT ModeIdIndex,
+                   PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  SHORT  LCDRefreshIndex[] = { 0x00, 0x00, 0x03, 0x01,
+                               0x01, 0x01, 0x01, 0x01,
+			       0x01, 0x01, 0x01, 0x01,
+			       0x01, 0x01, 0x01, 0x01 };
+  USHORT RefreshRateTableIndex,i,backup_i;
+  USHORT modeflag,index,temp,backupindex;
+
+  if (ModeNo <= 0x13)
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  else
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
-  if(SiS_IF_DEF_CH7005==1) {
-    	if(SiS_VBInfo&SetCRT2ToTV) {
-      		if(modeflag&HalfDCLK) return(0);
+  if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+    	if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+      		if(modeflag & HalfDCLK) return(0);
     	}
   }
 
-  if(ModeNo<0x14) return(0xFFFF);
+  if(ModeNo < 0x14) return(0xFFFF);
 
- /* TW: CR33 holds refresh rate index for CRT1 (0-3) and CRT2 (4-7).
+ /* TW: CR33 holds refresh rate index for CRT1 [3:0] and CRT2 [7:4].
   *     On LVDS machines, CRT2 index is always 0 and will be
   *     set to 0 by the following code; this causes the function
-  *     to take the first non-interlaced mode in SiS300_Ext2Struct
-  *     (which is the second 1024x768 mode in case the resolution
-  *     is 1024x768; the first mode in the list is interlaced and
-  *     therefore skipped).
+  *     to take the first non-interlaced mode in SiS_Ext2Struct
   */
 
-  index=SiS_GetReg1(SiS_P3d4,0x33);
-  index=index>>SiS_SelectCRT2Rate;
-  index=index&0x0F;
-  if(SiS_LCDInfo&LCDNonExpanding) index=0;
-  if(index>0) index--;
-
-  if(SiS_SetFlag & ProgrammingCRT2) {
-    	if(SiS_IF_DEF_CH7005==1) {
-      		if(SiS_VBInfo&SetCRT2ToTV) {
-        		index=0;
+  index = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x33);
+  index >>= SiS_Pr->SiS_SelectCRT2Rate;
+  index &= 0x0F;
+  backupindex = index;
+
+  if(index > 0) index--;
+
+  if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) {
+      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA))  index = 0;
+      } else {
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	    if(HwDeviceExtension->jChipType < SIS_315H)    index = 0;
+	    else if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) index = backupindex = 0;
+	}
+      }
+  }
+
+  if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) {
+    	if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+      		if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+        		index = 0;
       		}
     	}
-    	if(SiS_VBInfo&(SetCRT2ToLCD|SetCRT2ToLCDA)) {
-      		if(SiS_IF_DEF_LVDS==0) {
-        		if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-           			temp=LCDARefreshIndex[SiS_LCDResInfo];     /* 301b */
-        		else
-           			temp=LCDRefreshIndex[SiS_LCDResInfo];	   /* 301  */
-        		if(index>temp){
-          			index=temp;
-        		}
-      		} else {  						   /* LVDS */
-        		index=0;
+    	if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+      		if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+		        /* TW: This is not done in 630/301B BIOS */
+           		temp = LCDRefreshIndex[SiS_Pr->SiS_LCDResInfo];
+        		if(index > temp) index = temp;
+      		} else {
+        		index = 0;
       		}
     	}
   }
 
-  RefreshRateTableIndex = SiS_EModeIDTable[ModeIdIndex].REFindex;
-  ModeNo = SiS_RefIndex[RefreshRateTableIndex].ModeID;
+  RefreshRateTableIndex = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
+  ModeNo = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].ModeID;
+
+  /* TW: Inserted from 650/LVDS 1.10.07, 650/301LVx 1.10.6s */
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+    if(!(SiS_Pr->SiS_VBInfo & DriverMode)) {
+      if( (SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_VESAID == 0x105) ||
+          (SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_VESAID == 0x107) ) {
+            if(backupindex <= 1)
+	       RefreshRateTableIndex++;
+      }
+    }
+  }
 
-  i=0;
+  i = 0;
   do {
-    	if (SiS_RefIndex[RefreshRateTableIndex+i].ModeID!=ModeNo) break;
-    	temp = SiS_RefIndex[RefreshRateTableIndex+i].Ext_InfoFlag;
-    	temp=temp&ModeInfoFlag;
-    	if(temp<SiS_ModeType) break;
+    	if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + i].ModeID != ModeNo) break;
+    	temp = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + i].Ext_InfoFlag;
+    	temp &= ModeInfoFlag;
+    	if(temp < SiS_Pr->SiS_ModeType) break;
     	i++;
     	index--;
-  } while(index!=0xFFFF);
+  } while(index != 0xFFFF);
 
-  if(!(SiS_VBInfo&SetCRT2ToRAMDAC)) {
-    	if(SiS_VBInfo&SetInSlaveMode) {
-      		temp=SiS_RefIndex[RefreshRateTableIndex+i-1].Ext_InfoFlag;
-      			if(temp&InterlaceMode) {
-        			i++;
-      			}
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC)) {
+    	if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+      		temp = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + i - 1].Ext_InfoFlag;
+      		if(temp & InterlaceMode) {
+        		i++;
+      		}
     	}
   }
+
   i--;
 
-  if((SiS_SetFlag & ProgrammingCRT2) && (!(SiS_VBInfo & DisableCRT2Display))) {
+  if((SiS_Pr->SiS_SetFlag & ProgrammingCRT2) && (!(SiS_Pr->SiS_VBInfo & DisableCRT2Display))) {
     	backup_i = i;
-    	if (!(SiS_AdjustCRT2Rate(ROMAddr,ModeNo,ModeIdIndex,
-	                             RefreshRateTableIndex,&i))) {
+    	if (!(SiS_AdjustCRT2Rate(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+	                             RefreshRateTableIndex,&i,HwDeviceExtension))) {
 		/* TW: This is for avoiding random data to be used; i is
 		 *     in an undefined state if no matching CRT2 mode is
 		 *     found.
 		 */
 		i = backup_i;
-#ifdef LINUX_KERNEL
-		printk("sisfb: WARNING: No matching CRT2 mode found\n");
-#endif
 	}
   }
 
-  return(RefreshRateTableIndex+i);                			/*return(0x01|(temp1<<1));   */
+  return(RefreshRateTableIndex + i);
 }
 
+/* Checked against all (incl 650/LVDS (1.10.07), 630/301) BIOSes */
 BOOLEAN
-SiS_AdjustCRT2Rate(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                   USHORT RefreshRateTableIndex,USHORT *i)
+SiS_AdjustCRT2Rate(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                   USHORT RefreshRateTableIndex,USHORT *i,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT tempax,tempbx,resinfo;
   USHORT modeflag,infoflag;
 
-  if (ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;    	/* si+St_ModeFlag */
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-  }
+  if (ModeNo <= 0x13)
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  else
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
-  resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-  tempbx = SiS_RefIndex[RefreshRateTableIndex+(*i)].ModeID;
-  tempax=0;
-  if(SiS_IF_DEF_LVDS==0) {
-  	/* TW: For 301 (and which ones of 301B, 302B, 301LV, 302LV ?) */
-    	if(SiS_VBInfo&SetCRT2ToRAMDAC) {
-      		tempax=tempax|SupportRAMDAC2;
-    	}
-    	if(SiS_VBInfo&(SetCRT2ToLCD|SetCRT2ToLCDA)) {        /* 301b */
-      		tempax=tempax|SupportLCD;
-      		if(SiS_LCDResInfo!=Panel1280x1024) {
-        		if(SiS_LCDResInfo!=Panel1280x960) {
-           			if(SiS_LCDInfo&LCDNonExpanding) {
-             				if(resinfo>=9) {
-               					tempax=0;
-               					return(0);
-             				}
+  resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  tempbx = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].ModeID;
+
+  tempax = 0;
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+  	/* TW: For 301, 301B, 302B, 301LV, 302LV */
+    	if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
+      		tempax |= SupportRAMDAC2;
+		if(HwDeviceExtension->jChipType >= SIS_315H) {
+		    tempax |= SupportTV;
+		    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+		        if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+			    if(resinfo == 0x0a) tempax |= SupportTV1024;
+			}
+		    }
+		}
+    	}
+    	if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+      		tempax |= SupportLCD;
+		if(HwDeviceExtension->jChipType >= SIS_315H) {
+                   if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1600x1200) {
+		      if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1400x1050) {
+		         if((resinfo == 6) && (SiS_Pr->SiS_LCDInfo & LCDNonExpanding)) {
+			    tempax |= SupportAllCRT2;
+			    (*i) = 0;   /* TW: Restore RefreshTableIndex (BIOS 650/301LVx 1.10.6s) */
+                            return(1);
+		         } else {
+      		            if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024) {
+        		      if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x960) {
+           			if((resinfo == 6) && (SiS_Pr->SiS_LCDInfo & LCDNonExpanding)) {
+				    return(0);
+				} else {
+             			    if((resinfo >= 9) && (resinfo != 0x14)) {
+               				tempax = 0;
+               				return(0);
+             			    }
            			}
+        		      }
+		            }
+		         }
+		      }
+      		   }
+		} else {
+		  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+		     if((resinfo != 0x0f) && ((resinfo == 4) || (resinfo >= 8))) return(0);
+		  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) {
+		     if((resinfo != 0x10) && (resinfo > 8)) return(0);
+		  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) {
+		     if((resinfo != 0x0e) && (resinfo > 8)) return(0);
+		  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+		     if(resinfo > 9) return(0);
+		  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+		     if(resinfo > 8) return(0);
+		  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
+		     if((resinfo == 4) || (resinfo > 7)) return(0);
+		  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) {
+		     if((resinfo == 4) || (resinfo == 3) || (resinfo > 6)) return(0);
+		  }
+		}
+    	}
+#ifdef oldHV
+    	if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {    /* for HiTV */
+      		tempax |= SupportHiVisionTV;
+      		if(SiS_Pr->SiS_VBInfo & SetInSlaveMode){
+        		if(resinfo == 4) return(0);
+        		if(resinfo == 3) {
+          			if(SiS_Pr->SiS_SetFlag & TVSimuMode) return(0);
         		}
-      		}
-    	}
-    	if(SiS_VBInfo&SetCRT2ToHiVisionTV) {    /* for HiTV */
-      		tempax=tempax|SupportHiVisionTV;
-      		if(SiS_VBInfo&SetInSlaveMode){
-        		if(resinfo==4) return(0);
-        		if(resinfo==3) {
-          			if(SiS_SetFlag&TVSimuMode) return(0);
-        		}
-        		if(resinfo>7) return(0);
+        		if(resinfo > 7) return(0);
       		}
     	} else {
-      		if(SiS_VBInfo&(SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)) {
-        		tempax=tempax|SupportTV;
-       			/*301b*/
-         		if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-             			tempax=tempax|SupportTV1024;
-         		}
-        		/*end 301b*/
-       
-        		if(!(SiS_VBInfo&SetPALTV)) {
-          			if(modeflag&NoSupportSimuTV) {
-            				if(SiS_VBInfo&SetInSlaveMode) {
-              					if(!(SiS_VBInfo&SetNotSimuMode)) {
-                					return 0;
-              					}
-            				}
-          			}
-        		}
-      		}
+#endif
+      	if(SiS_Pr->SiS_VBInfo & (SetCRT2ToAVIDEO|SetCRT2ToSVIDEO|SetCRT2ToSCART)) {
+        	tempax |= SupportTV;
+		tempax |= SupportTV1024;
+		if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+		    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+		        if((SiS_Pr->SiS_VBInfo & SetNotSimuMode) && (SiS_Pr->SiS_VBInfo & SetPALTV)) {
+			     if(resinfo != 8) {
+			         if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
+				     ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != 4)) ) {
+				     tempax &= ~(SupportTV1024);
+				     if(HwDeviceExtension->jChipType >= SIS_315H) {
+                                         if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+				             if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
+			                         ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != 7)) ) {
+			                         if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return(0);
+		                             }
+				         }
+		                     } else {
+				         if( (resinfo != 3) ||
+					     (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+					     (SiS_Pr->SiS_VBInfo & SetNotSimuMode) ) {
+					     if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+						 if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+						     if(resinfo == 3) return(0);
+						     if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return (0);
+						 }
+		                             }
+                                         } else return(0);
+				     }
+				 }
+			     }
+			} else {
+			    tempax &= ~(SupportTV1024);
+			    if(HwDeviceExtension->jChipType >= SIS_315H) {
+			        if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+			            if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
+			                ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != 7)) ) {
+			                if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return(0);
+		                    }
+		                }
+			    } else {
+			        if( (resinfo != 3) ||
+				    (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+				    (SiS_Pr->SiS_VBInfo & SetNotSimuMode) ) {
+				     if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+					 if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+					     if(resinfo == 3) return(0);
+					     if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return (0);
+					 }
+		                     }
+                                } else return(0);
+                            }
+			}
+		    } else {  /* slavemode */
+			if(resinfo != 8) {
+			    if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
+			        ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != 4) ) ) {
+				 tempax &= ~(SupportTV1024);
+				 if(HwDeviceExtension->jChipType >= SIS_315H) {
+				     if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+				         if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
+			                     ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != 7)) ) {
+			                     if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode))  return(0);
+		                         }
+		                     }
+			        } else {
+				    if( (resinfo != 3) ||
+				        (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+				        (SiS_Pr->SiS_VBInfo & SetNotSimuMode) ) {
+				         if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+					     if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+					         if(resinfo == 3) return(0);
+					         if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return (0);
+					     }
+		                         }
+                                    } else return(0);
+				}
+			    }
+			}
+		    }
+		} else {   /* 301 */
+		    tempax &= ~(SupportTV1024);
+		    if(HwDeviceExtension->jChipType >= SIS_315H) {
+		        if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+		            if( (!(SiS_Pr->SiS_VBInfo & SetPALTV)) ||
+			        ((SiS_Pr->SiS_VBInfo & SetPALTV) && (resinfo != 7)) ) {
+			        if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return(0);
+		            }
+		        }
+		    } else {
+		        if( (resinfo != 3) ||
+			    (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+			    (SiS_Pr->SiS_VBInfo & SetNotSimuMode) ) {
+			    if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+			        if((modeflag & NoSupportSimuTV) && (SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+				    if(resinfo == 3) return(0);
+				    if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) return (0);
+				}
+		            }
+                        } else return(0);
+		    }
+		}
+        }
+#ifdef oldHV
     	}
-  } else {
-  	/* TW: for LVDS (and which ones of the SiS bridges?) */
-    	if(SiS_IF_DEF_CH7005==1) {
-      		if(SiS_VBInfo&SetCRT2ToTV) {
-        		tempax=tempax|SupportCHTV;
+#endif
+  } else {	/* TW: for LVDS  */
+
+    	if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+      		if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+        		tempax |= SupportCHTV;
       		}
     	}
-    	if(SiS_VBInfo&SetCRT2ToLCD) {
-      		tempax=tempax|SupportLCD;
-      		if(resinfo>0x08) return(0);       	  /* 1024x768  */
-      		if(SiS_LCDResInfo<Panel1024x768) {
-        		if(resinfo>0x07) return(0);       /*  800x600  */
-        		if(resinfo==0x04) return(0);      /*  512x384  */
-      		}
+    	if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+      		tempax |= SupportLCD;
+		if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x768) {
+		     if((resinfo != 0x14) && (resinfo > 0x09)) return(0);
+		} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+		     if((resinfo != 0x0f) && (resinfo > 0x08)) return(0);
+		} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) {
+		     if((resinfo != 0x10) && (resinfo > 0x08)) return(0);
+		} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+		     if((resinfo != 0x15) && (resinfo > 0x09)) return(0);
+		} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+                     if(resinfo > 0x09) return(0);
+                } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+		     if(resinfo > 0x08) return(0);
+		} else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600){
+		     if(resinfo > 0x07) return(0);
+		     if(resinfo == 0x04) return(0);
+		}
     	}
   }
   /* TW: Look backwards in table for matching CRT2 mode */
-  for(;SiS_RefIndex[RefreshRateTableIndex+(*i)].ModeID==tempbx;(*i)--) {
-     	infoflag = SiS_RefIndex[RefreshRateTableIndex+(*i)].Ext_InfoFlag;
-     	if(infoflag&tempax) {
+  for(; SiS_Pr->SiS_RefIndex[RefreshRateTableIndex+(*i)].ModeID == tempbx; (*i)--) {
+     	infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].Ext_InfoFlag;
+     	if(infoflag & tempax) {
        		return(1);
      	}
-     	if ((*i)==0) break;
+     	if ((*i) == 0) break;
   }
   /* TW: Look through the whole mode-section of the table from the beginning
    *     for a matching CRT2 mode if no mode was found yet.
    */
-  for((*i)=0;;(*i)++) {
-     	infoflag = SiS_RefIndex[RefreshRateTableIndex+(*i)].Ext_InfoFlag;
-     	if(SiS_RefIndex[RefreshRateTableIndex+(*i)].ModeID!=tempbx) {
+  for((*i) = 0; ; (*i)++) {
+     	infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].Ext_InfoFlag;
+     	if(SiS_Pr->SiS_RefIndex[RefreshRateTableIndex + (*i)].ModeID != tempbx) {
        		return(0);
      	}
-     	if(infoflag&tempax) {
+     	if(infoflag & tempax) {
        		return(1);
      	}
   }
   return(1);
 }
 
+/* Checked against 650/LVDS (1.10.07) and 650/301LV BIOS */
 void
-SiS_SaveCRT2Info(USHORT ModeNo)
+SiS_SaveCRT2Info(SiS_Private *SiS_Pr, USHORT ModeNo)
 {
   USHORT temp1,temp2;
 
-  SiS_SetReg1(SiS_P3d4,0x34,ModeNo);  /* reserve CR34 for CRT1 Mode No */
-  temp1=(SiS_VBInfo&SetInSlaveMode)>>8;
-  temp2=~(SetInSlaveMode>>8);
-  SiS_SetRegANDOR(SiS_P3d4,0x31,temp2,temp1);
+  /* TW: We store CRT1 ModeNo in CR34 */
+  SiS_SetReg1(SiS_Pr->SiS_P3d4,0x34,ModeNo);
+  temp1 = (SiS_Pr->SiS_VBInfo & SetInSlaveMode) >> 8;
+  temp2 = ~(SetInSlaveMode >> 8);
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x31,temp2,temp1);
 }
 
+/* TW: Checked against 650+301, 650/LVDS (1.10.07) and 650/301LVx (1.10.6s) BIOS */
 void
-SiS_GetVBInfo301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
-                 USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+              USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT tempax,tempbx,temp;
-  USHORT modeflag;
-  UCHAR  OutputSelect=*pSiS_OutputSelect;
+  USHORT modeflag, resinfo=0;
+  UCHAR  OutputSelect = *SiS_Pr->pSiS_OutputSelect;
 
-  if (ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-  } else {
-   	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  if (ModeNo<=0x13)
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  else {
+   	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
   }
-  SiS_SetFlag=0;
 
-  SiS_ModeType=modeflag&ModeInfoFlag;
-  
-  tempbx=0;
-  if(SiS_BridgeIsOn(BaseAddr)) {
-    	temp=SiS_GetReg1(SiS_P3d4,0x30);
-    	if((SiS_IF_DEF_LVDS==0) && (SiS_VBType&(VB_SIS301LV|VB_SIS302LV))) {
-       		temp=temp&0xbf;                                        	/*301lvds disable CRT2*/
-    	}
-    	if(SiS_IF_DEF_FSTN){                             		/*fstn must set CR30=0x21 */
-       		temp=0x21;
-       		SiS_SetReg1(SiS_P3d4,0x30,temp);
-    	}
-    	tempbx=tempbx|temp;
-    	temp=SiS_GetReg1(SiS_P3d4,0x31);
-    	tempax=temp<<8;
-    	tempbx=tempbx|tempax;
-    	temp=SetCHTVOverScan|SetInSlaveMode|DisableCRT2Display;  	/* ynlai */
-   	temp=0xFFFF^temp;
-    	tempbx=tempbx&temp;
+  SiS_Pr->SiS_SetFlag = 0;
+
+  SiS_Pr->SiS_ModeType = modeflag & ModeInfoFlag;
+
+  tempbx = 0;
+  if(SiS_BridgeIsOn(SiS_Pr,BaseAddr,HwDeviceExtension) == 0) {              /* TW: "== 0" inserted from 630/301B BIOS */
+    	temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+	if(SiS_Pr->SiS_HiVision & 0x03) {	/* TW: New from 650/301LVx 1.10.6s */
+	     temp &= (SetCRT2ToHiVisionTV | SwitchToCRT2 | SetSimuScanMode); 	/* 0x83 */
+	     temp |= SetCRT2ToHiVisionTV;   					/* 0x80 */
+	}
+	if(SiS_Pr->SiS_HiVision & 0x04) {	/* TW: New from 650/301LVx 1.10.6s */
+	     temp &= (SetCRT2ToHiVisionTV | SwitchToCRT2 | SetSimuScanMode); 	/* 0x83 */
+	     temp |= SetCRT2ToSVIDEO;  						/* 0x08 */
+	}
+#if 0   /* TW: Not in 650/301LVx 1.10.6s BIOS */
+    	if(SiS_Pr->SiS_VBType & VB_SIS30xLV) {
+       		temp &= 0xbf;   /* 301lvds disable CRT2RAMDAC */
+    	}
+#endif
+    	if(SiS_Pr->SiS_IF_DEF_FSTN) {   /* fstn must set CR30=0x21 */
+       		temp = (SetCRT2ToLCD | SetSimuScanMode);
+       		SiS_SetReg1(SiS_Pr->SiS_P3d4,0x30,temp);
+    	}
+    	tempbx |= temp;
+    	temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31);
+	tempax = temp << 8;
+        tempax &= (LoadDACFlag | DriverMode | SetDispDevSwitch |        /* TW: Inserted from 650/LVDS+301LV BIOS */
+		         SetNotSimuMode | SetPALTV);                    /* TW: Inserted from 650/LVDS+301LV BIOS */
+    	tempbx |= tempax;
+    	temp = SetCHTVOverScan | SetInSlaveMode | DisableCRT2Display;
+   	temp = 0xFFFF ^ temp;
+    	tempbx &= temp;
 #ifdef SIS315H
-     	/*301b*/
-    	if((SiS_IF_DEF_LVDS==0) && (SiS_VBType&(VB_SIS302B|VB_SIS302LV))){
-       		temp=SiS_GetReg1(SiS_P3d4,0x38);
-       		if(temp==0x03)
-          		tempbx=tempbx|(SetCRT2ToLCDA);
-    	}
-    	/*end301b*/
+	if(HwDeviceExtension->jChipType >= SIS_315H) {
+	   temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+    	   if(SiS_Pr->SiS_VBType & (VB_SIS302B | VB_SIS30xLV | VB_SIS30xNEW)) {
+                if((SiS_GetReg1(SiS_Pr->SiS_P3d4, 0x36) & 0x0f) == SiS_Pr->SiS_Panel1400x1050) {
+		    if(tempbx & SetCRT2ToLCD) {
+		        if(ModeNo <= 0x13) {
+			     if(SiS_CRT2IsLCD(SiS_Pr, BaseAddr)) {
+			          if(!(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & (SetNotSimuMode >> 8))) {
+				      SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x38,0x03);
+				  }
+			     }
+			}
+		    }
+		}
+       		if((temp & (EnableDualEdge | SetToLCDA))
+		          == (EnableDualEdge | SetToLCDA))   /* TW: BIOS only tests these bits, added "& ..." */
+          		tempbx |= SetCRT2ToLCDA;
+    	   }
+	   /* TW: Inserted from 650/LVDS 1.10.07 BIOS: */
+	   if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+	        if(temp & SetToLCDA)
+		        tempbx |= SetCRT2ToLCDA;
+	        if(temp & EnableLVDSHiVision)
+		        tempbx |= SetCRT2ToHiVisionTV;
+	   }
+	}
 #endif
-    	if(SiS_IF_DEF_LVDS==0) {
-      		if(SiS_IF_DEF_HiVision) temp=0x80FC;
-      		else temp=0x807C;
+    	if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+	        temp = SetCRT2ToLCDA   | SetCRT2ToSCART      | SetCRT2ToLCD |
+		       SetCRT2ToRAMDAC | SetCRT2ToSVIDEO     | SetCRT2ToAVIDEO; /* = 0x807C; */
+      		if(SiS_Pr->SiS_IF_DEF_HiVision == 1)
+                     temp |= SetCRT2ToHiVisionTV; /* = 0x80FC; */
     	} else {
-      		if(SiS_IF_DEF_CH7005==1) {
-        		temp = SetCRT2ToTV|SetCRT2ToLCD;
-      		} else {
+                if(HwDeviceExtension->jChipType >= SIS_315H) {
+                    if(SiS_Pr->SiS_IF_DEF_CH70xx != 0)
+        		temp = SetCRT2ToLCDA   | SetCRT2ToSCART |
+			       SetCRT2ToLCD    | SetCRT2ToHiVisionTV |
+			       SetCRT2ToAVIDEO | SetCRT2ToSVIDEO;  /* = 0x80bc */
+      		    else
+        		temp = SetCRT2ToLCDA | SetCRT2ToLCD;
+		} else {
+      		    if(SiS_Pr->SiS_IF_DEF_CH70xx != 0)
+        		temp = SetCRT2ToTV | SetCRT2ToLCD;
+      		    else
         		temp = SetCRT2ToLCD;
-      		}
-    	}
-    	if(!(tempbx&temp)) {
-      		tempax=tempax|DisableCRT2Display;
-      		tempbx=0;
+		}
     	}
-   
-   	if(SiS_IF_DEF_LVDS==0) {
-      		if(tempbx&SetCRT2ToLCDA) {                                    /*301b*/
-        		tempbx=tempbx&(0xFF00|SwitchToCRT2|SetSimuScanMode);
-      		} else if(tempbx&SetCRT2ToRAMDAC) {
-        		tempbx=tempbx&(0xFF00|SetCRT2ToRAMDAC|SwitchToCRT2|SetSimuScanMode);
-      		} else if((tempbx&SetCRT2ToLCD)&&(!(SiS_VBType&VB_NoLCD)) ){              /*301dlvds*/
-        		tempbx=tempbx&(0xFF00|SetCRT2ToLCD|SwitchToCRT2|SetSimuScanMode);
-      		} else if(tempbx&SetCRT2ToSCART){
-        		tempbx=tempbx&(0xFF00|SetCRT2ToSCART|SwitchToCRT2|SetSimuScanMode);
-        		tempbx=tempbx|SetPALTV;
-      		} else if(tempbx&SetCRT2ToHiVisionTV){
-        		tempbx=tempbx&(0xFF00|SetCRT2ToHiVisionTV|SwitchToCRT2|SetSimuScanMode);
-  			/* ynlai begin */
-        		tempbx=tempbx|SetPALTV;
-  			/* ynlai end */
+
+    	if(!(tempbx & temp)) {
+      		tempax = DisableCRT2Display;
+      		tempbx = 0;
+    	}
+
+   	if(SiS_Pr->SiS_IF_DEF_LVDS==0) {
+      		if(tempbx & SetCRT2ToLCDA) {
+        		tempbx &= (0xFF00|SwitchToCRT2|SetSimuScanMode);
+      		} else if(tempbx & SetCRT2ToRAMDAC) {
+        		tempbx &= (0xFF00|SetCRT2ToRAMDAC|SwitchToCRT2|SetSimuScanMode);
+      		} else if((tempbx & SetCRT2ToLCD) && (!(SiS_Pr->SiS_VBType & VB_NoLCD)) ){
+        		tempbx &= (0xFF00|SetCRT2ToLCD|SwitchToCRT2|SetSimuScanMode);
+      		} else if(tempbx & SetCRT2ToSCART){
+        		tempbx &= (0xFF00|SetCRT2ToSCART|SwitchToCRT2|SetSimuScanMode);
+        		tempbx |= SetPALTV;
+		}
+#if 0		/* TW: Not done in 650/301LVx 1.10.6s BIOS */
+      		} else if(tempbx & SetCRT2ToHiVisionTV){
+        		tempbx &= (0xFF00|SetCRT2ToHiVisionTV|SwitchToCRT2|SetSimuScanMode);
+        		tempbx |= SetPALTV;
       		}
+#endif
    	} else { /* LVDS */
-      		if(SiS_IF_DEF_CH7005==1) {
-        		if(tempbx&SetCRT2ToTV)
-          			tempbx=tempbx&(0xFF00|SetCRT2ToTV|SwitchToCRT2|SetSimuScanMode);
+	        if(HwDeviceExtension->jChipType >= SIS_315H) {
+		    if(tempbx & SetCRT2ToLCDA)
+		        tempbx &= (0xFF00|SwitchToCRT2|SetSimuScanMode);
+		}
+      		if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+        	    if(tempbx & SetCRT2ToTV)
+          		 tempbx &= (0xFF00|SetCRT2ToTV|SwitchToCRT2|SetSimuScanMode);
       		}
-      		if(tempbx&SetCRT2ToLCD)
-        		tempbx=tempbx&(0xFF00|SetCRT2ToLCD|SwitchToCRT2|SetSimuScanMode);
+      		if(tempbx & SetCRT2ToLCD) {
+        		tempbx &= (0xFF00|SetCRT2ToLCD|SwitchToCRT2|SetSimuScanMode);
+		}
+	        if(HwDeviceExtension->jChipType >= SIS_315H) {
+		    if(tempbx & SetCRT2ToLCDA)
+		        tempbx |= SetCRT2ToLCD;
+		}
 	}
-    	if(tempax&DisableCRT2Display) {
-      		if(!(tempbx&(SwitchToCRT2|SetSimuScanMode))) {
-        		tempbx=SetSimuScanMode|DisableCRT2Display;
+    	if(tempax & DisableCRT2Display) {
+      		if(!(tempbx & (SwitchToCRT2 | SetSimuScanMode))) {
+        		tempbx = SetSimuScanMode | DisableCRT2Display;
       		}
     	}
-    	if(!(tempbx&DriverMode)){
-      		tempbx=tempbx|SetSimuScanMode;
+    	if(!(tempbx & DriverMode)){
+      		tempbx |= SetSimuScanMode;
     	}
-	/* TW: LVDS bridge can only be slave in 8bpp modes */
-	if ((SiS_IF_DEF_LVDS==1) &&
-		(ModeNo == 0x2e || ModeNo == 0x30 ||
-			ModeNo == 0x38 || ModeNo == 0x3a)) {
-		tempbx=tempbx|SetSimuScanMode|SetInSlaveMode;
+
+	/* TW: LVDS (LCD/TV) and 630+301B (LCD) can only be slave in 8bpp modes */
+	if( (SiS_Pr->SiS_IF_DEF_LVDS == 1) && (SiS_Pr->SiS_ModeType <= ModeVGA) ) {
+		modeflag &= (~CRT2Mode);
+	}
+	if( (HwDeviceExtension->jChipType < SIS_315H) && (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
+	        if(SiS_Pr->SiS_ModeType <= ModeVGA) {
+			if(tempbx & SetCRT2ToLCD) {
+		    		modeflag &= (~CRT2Mode);
+			}
+	        }
 	}
 	/* TW end */
-    	if(!(tempbx&SetSimuScanMode)){
-      		if(tempbx&SwitchToCRT2) {
-        		if(!(modeflag&CRT2Mode)) {
-            			tempbx=tempbx|SetSimuScanMode;
-        		}
 
+    	if(!(tempbx & SetSimuScanMode)){
+      		if(tempbx & SwitchToCRT2) {
+        	    if(!(modeflag & CRT2Mode)) {
+			if( (HwDeviceExtension->jChipType >= SIS_315H) &&
+			        (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) ) {
+			    if(resinfo != 0x0a)
+                                tempbx |= SetSimuScanMode;
+			} else {
+            			tempbx |= SetSimuScanMode;
+	                }
+        	    }
       		} else {
-        		if(!(SiS_BridgeIsEnable(BaseAddr,HwDeviceExtension))) {
-          			if(!(tempbx&DriverMode)) {
-            				if(SiS_BridgeInSlave()) {
-              					tempbx=tempbx|SetInSlaveMode;
-            				}
-          			}
-        		}
-      		}
-    	}
-    	if(!(tempbx&DisableCRT2Display)) {
-     		 if(tempbx&DriverMode) {
-        		if(tempbx&SetSimuScanMode) {
-          			if(!(modeflag&CRT2Mode)) {
-            				tempbx=tempbx|SetInSlaveMode;
-            				if(SiS_IF_DEF_LVDS==0) {
-              					if(tempbx&SetCRT2ToTV) {
-                					if(!(tempbx&SetNotSimuMode))
-								SiS_SetFlag=SiS_SetFlag|TVSimuMode;
-              					}
-            				}
-          			}
-        		}
-      		} else {
-        		tempbx=tempbx|SetInSlaveMode;
-        		if(SiS_IF_DEF_LVDS==0) {
-          			if(tempbx&SetCRT2ToTV) {
-            				if(!(tempbx&SetNotSimuMode))
-						SiS_SetFlag=SiS_SetFlag|TVSimuMode;
-          			}
-        		}
+        	    if(!(SiS_BridgeIsEnable(SiS_Pr,BaseAddr,HwDeviceExtension))) {
+          		if(!(tempbx & DriverMode)) {
+            		    if(SiS_BridgeInSlave(SiS_Pr)) {
+				tempbx |= SetSimuScanMode; /* TW: from BIOS 650/301/301LV/LVDS */
+            		    }
+                        }
+                    }
       		}
     	}
-    	if(SiS_IF_DEF_CH7005==1) {
-      		temp=SiS_GetReg1(SiS_P3d4,0x35);
-      		if(temp&TVOverScan) tempbx=tempbx|SetCHTVOverScan;
+
+    	if(!(tempbx & DisableCRT2Display)) {
+            if(tempbx & DriverMode) {
+                if(tempbx & SetSimuScanMode) {
+          	    if(!(modeflag & CRT2Mode)) {
+	                if( (HwDeviceExtension->jChipType >= SIS_315H) &&
+			       (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) ) {
+			     if(resinfo != 0x0a) {  /* TW: Inserted from 650/301 BIOS */
+			          tempbx |= SetInSlaveMode;
+            		          if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+              		 	     if(tempbx & SetCRT2ToTV) {
+                		         if(!(tempbx & SetNotSimuMode))
+					     SiS_Pr->SiS_SetFlag |= TVSimuMode;
+              			     }
+                                  }
+			     }                      /* TW: Inserted from 650/301 BIOS */
+		        } else {
+            		    tempbx |= SetInSlaveMode;
+            		    if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+              		        if(tempbx & SetCRT2ToTV) {
+                		    if(!(tempbx & SetNotSimuMode))
+					SiS_Pr->SiS_SetFlag |= TVSimuMode;
+              			}
+            		    }
+                        }
+	            }
+                }
+            } else {
+                tempbx |= SetInSlaveMode;
+        	if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+          	    if(tempbx & SetCRT2ToTV) {
+            		if(!(tempbx & SetNotSimuMode))
+			    SiS_Pr->SiS_SetFlag |= TVSimuMode;
+          	    }
+        	}
+      	    }
     	}
+	
+	if(SiS_Pr->SiS_CHOverScan) {
+    	   if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+      		temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x35);
+      		if((temp & TVOverScan) || (SiS_Pr->SiS_CHOverScan == 1) )
+		      tempbx |= SetCHTVOverScan;
+    	   }
+	   if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+      		temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x79);
+      		if( (temp & 0x80) || (SiS_Pr->SiS_CHOverScan == 1) )
+		      tempbx |= SetCHTVOverScan;
+    	   }
+	}
   }
-  /*add PALMN*/
-  if(SiS_IF_DEF_LVDS==0) {
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS==0) {
 #ifdef SIS300
      	if((HwDeviceExtension->jChipType==SIS_630)||
            (HwDeviceExtension->jChipType==SIS_730)) {
-           	if(!(OutputSelect&EnablePALMN))
-             		SiS_SetRegAND(SiS_P3d4,0x35,0x3F);
-           	if(tempbx&SetCRT2ToTV) {
-              		if(tempbx&SetPALTV) {
-                  		temp=SiS_GetReg1(SiS_P3d4,0x35);
-                  		temp=temp&0xC0;
-                  		if(temp==0x40)
-                    			tempbx=tempbx&(~SetPALTV);
+	   	if(ROMAddr && SiS_Pr->SiS_UseROM) {
+			OutputSelect = ROMAddr[0xfe];
+                }
+           	if(!(OutputSelect & EnablePALMN))
+             		SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x35,0x3F);
+           	if(tempbx & SetCRT2ToTV) {
+              		if(tempbx & SetPALTV) {
+                  		temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x35);
+				/* temp &= 0xC0;  */ /* TW: BIOS only tests 0x40, not 0x80 */
+                  		if(temp & 0x40)
+                    			tempbx &= (~SetPALTV);
              		}
           	}
       	}
 #endif
 #ifdef SIS315H
-     	if((HwDeviceExtension->jChipType == SIS_315H)||
-           (HwDeviceExtension->jChipType == SIS_315PRO)||
-           (HwDeviceExtension->jChipType == SIS_550)||   /* 05/02/01 ynlai for 550 */
-           (HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-           (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
-           (HwDeviceExtension->jChipType == SIS_650)) {
-		if(!(OutputSelect&EnablePALMN))
-        		SiS_SetRegAND(SiS_P3d4,0x38,0x3F);
-   		if(tempbx&SetCRT2ToTV) {
-    			if(tempbx&SetPALTV) {
-               			temp=SiS_GetReg1(SiS_P3d4,0x38);
-               			temp=temp&0xC0;
-               			if(temp==0x40)
-               				tempbx=tempbx&(~SetPALTV);
+     	if(HwDeviceExtension->jChipType >= SIS_315H) {
+	        if(ROMAddr && SiS_Pr->SiS_UseROM) {
+			OutputSelect = ROMAddr[0xf3];
+                }
+		if(!(OutputSelect & EnablePALMN))
+        		SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0x3F);
+   		if(tempbx & SetCRT2ToTV) {
+    			if(tempbx & SetPALTV) {
+               			temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+               			if(temp & 0x40)
+               				tempbx &= (~SetPALTV);
               		}
         	}
   	}
 #endif
- /*end add*/
   }
-  SiS_VBInfo=tempbx;
+
+  SiS_Pr->SiS_VBInfo=tempbx;
+
+#ifdef TWDEBUG
 #ifdef LINUX_KERNEL
-  printk(KERN_INFO "sisfb: (VBInfo = %x)\n", SiS_VBInfo);
+  printk(KERN_INFO "sisfb: (VBInfo= 0x%04x, SetFlag=0x%04x)\n", SiS_Pr->SiS_VBInfo, SiS_Pr->SiS_SetFlag);
 #endif
 #ifdef LINUX_XF86
-  xf86DrvMsg(0, X_INFO, "(init301.c: VBInfo = %x)\n", SiS_VBInfo);
+  xf86DrvMsg(0, X_PROBED, "(init301: VBInfo=0x%04x, SetFlag=0x%04x)\n", SiS_Pr->SiS_VBInfo, SiS_Pr->SiS_SetFlag);
+#endif
+#endif
+
+#if 0  /* TW: Incomplete! (But does not seem to be required) */
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+     /* TW: From A901/630+301B BIOS */
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+         if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x80)
+     }
+     if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+         if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x80)
+	     if( [si] == 3) ModeIdIndex = 0x3f2b;
+	 }
+     }
+     SiS_SetRegAND(SiS_Pr->SiS_P3d4, 0x31, 0xF7);
+     if(ModeNo == 0x13) bp+4 = 0x03;
+  } else {
+     /* From 650/301LVx BIOS: */
+     SiS_SetRegAND(SiS_Pr->SiS_P3d4, 0x31, 0xF7);
+     if(ModeNo == 0x13) bp+4 = 0x03;
+     else bp+4 = ModeNo;
+  }
 #endif
+
+  /* TW: 630/301B and 650/301 (not 301LV!) BIOSes do more here, but this seems for DOS mode */
+
 }
 
 void
-SiS_GetRAMDAC2DATA(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                   USHORT RefreshRateTableIndex)
+SiS_GetRAMDAC2DATA(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                   USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT tempax,tempbx,temp;
   USHORT temp1,temp2,modeflag=0,tempcx;
   USHORT StandTableIndex,CRT1Index;
   USHORT ResInfo,DisplayType;
-  SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr=NULL;
+  const  SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr = NULL;
+
+  SiS_Pr->SiS_RVBHCMAX  = 1;
+  SiS_Pr->SiS_RVBHCFACT = 1;
+
+  if(ModeNo <= 0x13){
+
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+    	StandTableIndex = SiS_GetModePtr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex);
+    	tempax = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[0];
+    	tempbx = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[6];
+    	temp1 = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[7];
 
-  SiS_RVBHCMAX=1;
-  SiS_RVBHCFACT=1;
-  if(ModeNo<=0x13){
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-    	StandTableIndex = SiS_GetModePtr(ROMAddr,ModeNo,ModeIdIndex);
-    	tempax = SiS_StandTable[StandTableIndex].CRTC[0];
-    	tempbx = SiS_StandTable[StandTableIndex].CRTC[6];
-    	temp1=SiS_StandTable[StandTableIndex].CRTC[7];
-  } else {
-    if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-        			&& (SiS_VBInfo&SetCRT2ToLCDA) ) {
-    	/*add crt1ptr*/
-    	temp=SiS_GetLVDSCRT1Ptr(ROMAddr,ModeNo,ModeIdIndex,
+  } else {
+
+     if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) ) {
+
+    	temp = SiS_GetLVDSCRT1Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
 			RefreshRateTableIndex,&ResInfo,&DisplayType);
-    	if(temp==0){
-    		return;
-    	}
+
+    	if(temp == 0)  return;
+
     	switch(DisplayType) {
-    		case 0 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1;		break;
-    		case 1 : LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1;          break;
-    		case 2 : LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1;         break;
-    		case 3 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1_H;         break;
-    		case 4 : LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1_H;        break;
-    		case 5 : LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1_H;       break;
-    		case 6 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2;           break;
-    		case 7 : LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2;          break;
-    		case 8 : LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2;         break;
-    		case 9 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2_H;         break;
-    		case 10: LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2_H;        break;
-    		case 11: LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2_H;       break;
-    		case 12: LVDSCRT1Ptr = SiS_CHTVCRT1UNTSC;               break;
-    		case 13: LVDSCRT1Ptr = SiS_CHTVCRT1ONTSC;               break;
-    		case 14: LVDSCRT1Ptr = SiS_CHTVCRT1UPAL;                break;
-    		case 15: LVDSCRT1Ptr = SiS_CHTVCRT1OPAL;                break;
-    		case 16: LVDSCRT1Ptr = SiS_LVDSCRT1320x480_1;           break;
-    	}
-    	temp1=(LVDSCRT1Ptr+ResInfo)->CR[0];
-    	temp2=(LVDSCRT1Ptr+ResInfo)->CR[14];
-    	tempax=(temp1&0xFF)|((temp2&0x03)<<8);
-    	tempbx=(LVDSCRT1Ptr+ResInfo)->CR[6];
-    	tempcx=(LVDSCRT1Ptr+ResInfo)->CR[13]<<8;
-    	tempcx = tempcx&0x0100;
+    		case 0 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1;		break;
+    		case 1 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1;          break;
+    		case 2 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1;         break;
+    		case 3 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1_H;         break;
+    		case 4 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1_H;        break;
+    		case 5 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1_H;       break;
+    		case 6 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2;           break;
+    		case 7 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2;          break;
+    		case 8 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2;         break;
+    		case 9 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2_H;         break;
+    		case 10: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2_H;        break;
+    		case 11: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2_H;       break;
+		case 12: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1;           break;
+		case 13: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H;         break;
+		case 14: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_1;         break;
+		case 15: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_1_H;       break;
+		case 16: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_2;         break;
+		case 17: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_2_H;       break;
+    		case 18: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UNTSC;               break;
+    		case 19: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1ONTSC;               break;
+    		case 20: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UPAL;                break;
+    		case 21: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1OPAL;                break;
+    		case 22: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1320x480_1;           break;
+		case 23: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_1;          break;
+    		case 24: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_1_H;        break;
+    		case 25: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_2;          break;
+    		case 26: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_2_H;        break;
+    		case 27: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_1;          break;
+    		case 28: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_1_H;        break;
+    		case 29: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_2;          break;
+    		case 30: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_2_H;        break;
+		case 36: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_1;         break;
+		case 37: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_1_H;       break;
+		case 38: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_2;         break;
+		case 39: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_2_H;       break;
+    	}
+    	temp1  = (LVDSCRT1Ptr+ResInfo)->CR[0];
+    	temp2  = (LVDSCRT1Ptr+ResInfo)->CR[14];
+    	tempax = (temp1 & 0xFF) | ((temp2 & 0x03) << 8);
+    	tempbx = (LVDSCRT1Ptr+ResInfo)->CR[6];
+    	tempcx = (LVDSCRT1Ptr+ResInfo)->CR[13]<<8;
+    	tempcx = tempcx & 0x0100;
     	tempcx = tempcx << 2;
     	tempbx = tempbx | tempcx;
-    	temp1=(LVDSCRT1Ptr+ResInfo)->CR[7];
-    	/*add 301b*/
+    	temp1  = (LVDSCRT1Ptr+ResInfo)->CR[7];
+
     } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-    	CRT1Index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
-    	CRT1Index=CRT1Index&0x3F;
-    	temp1 = (USHORT)SiS_CRT1Table[CRT1Index].CR[0];
-    	temp2 = (USHORT)SiS_CRT1Table[CRT1Index].CR[14];
-    	tempax=(temp1&0xFF)|((temp2&0x03)<<8);
-    	tempbx = (USHORT)SiS_CRT1Table[CRT1Index].CR[6];
-    	tempcx = (USHORT)SiS_CRT1Table[CRT1Index].CR[13]<<8;
-    	tempcx = tempcx&0x0100;
+
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    	CRT1Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+	if(HwDeviceExtension->jChipType < SIS_315H) {
+    	   CRT1Index &= 0x3F;
+	}
+    	temp1  = (USHORT)SiS_Pr->SiS_CRT1Table[CRT1Index].CR[0];
+    	temp2  = (USHORT)SiS_Pr->SiS_CRT1Table[CRT1Index].CR[14];
+    	tempax = (temp1 & 0xFF) | ((temp2 & 0x03) << 8);
+    	tempbx = (USHORT)SiS_Pr->SiS_CRT1Table[CRT1Index].CR[6];
+    	tempcx = (USHORT)SiS_Pr->SiS_CRT1Table[CRT1Index].CR[13]<<8;
+    	tempcx = tempcx & 0x0100;
     	tempcx = tempcx << 2;
     	tempbx = tempbx | tempcx;
-    	temp1 = (USHORT)SiS_CRT1Table[CRT1Index].CR[7];
-   }
+    	temp1  = (USHORT)SiS_Pr->SiS_CRT1Table[CRT1Index].CR[7];
+
+    }
+
   }
-  if(temp1&0x01) tempbx=tempbx|0x0100;
-  if(temp1&0x20) tempbx=tempbx|0x0200;
-  tempax=tempax+5;
-  if(modeflag&Charx8Dot) tempax=tempax*8;
-  else tempax=tempax*9;
 
-  SiS_VGAHT=tempax;
-  SiS_HT=tempax;
+  if(temp1 & 0x01) tempbx |= 0x0100;
+  if(temp1 & 0x20) tempbx |= 0x0200;
+  tempax += 5;
+
+  /* Charx8Dot is no more used (and assumed), so we set it */
+  modeflag |= Charx8Dot;
+
+  if(modeflag & Charx8Dot) tempax *= 8;
+  else                     tempax *= 9;
+
+  /* TW: From 650/301LVx 1.10.6s */
+  if(modeflag & HalfDCLK)  tempax <<= 1;
+
+  SiS_Pr->SiS_VGAHT = SiS_Pr->SiS_HT = tempax;
   tempbx++;
-  SiS_VGAVT=tempbx;
-  SiS_VT=tempbx;
+  SiS_Pr->SiS_VGAVT = SiS_Pr->SiS_VT = tempbx;
 }
 
 void
-SiS_UnLockCRT2(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
+SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
 {
-  if(HwDeviceExtension->jChipType >= SIS_315H) {
-    	SiS_SetRegANDOR(SiS_Part1Port,0x2f,0xFF,0x01);
-  } else {
-    	SiS_SetRegANDOR(SiS_Part1Port,0x24,0xFF,0x01);
-  }
+  if(HwDeviceExtension->jChipType >= SIS_315H)
+    	SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2f,0x01);
+  else
+    	SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x24,0x01);
 }
 
 void
-SiS_LockCRT2(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
+SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
 {
-  if(HwDeviceExtension->jChipType >= SIS_315H) {
-    	SiS_SetRegANDOR(SiS_Part1Port,0x2F,0xFE,0x00);
-  } else {
-     	SiS_SetRegANDOR(SiS_Part1Port,0x24,0xFE,0x00);
-  }
+  if(HwDeviceExtension->jChipType >= SIS_315H)
+    	SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2F,0xFE);
+  else
+     	SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x24,0xFE);
 }
 
 void
-SiS_EnableCRT2()
+SiS_EnableCRT2(SiS_Private *SiS_Pr)
 {
-  SiS_SetRegANDOR(SiS_P3c4,0x1E,0xFF,0x20);
+  SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
 }
 
+/* Checked against all BIOSes */
 void
-SiS_DisableBridge(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT  BaseAddr)
+SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
 {
-  USHORT temp1,tempah,temp;
+  USHORT tempah,pushax,temp=0;
+  UCHAR *ROMAddr = HwDeviceExtension->pjVirtualRomBase;
 
-  SiS_SetRegANDOR(SiS_P3c4,0x11,0xF7,0x08);
+  if (SiS_Pr->SiS_IF_DEF_LVDS == 0) {
 
-  /*SetPanelDelay(1); */
-  temp1=0x01;
-  if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)))  {  /*301b*/
-    	if((SiS_IsVAMode(BaseAddr)))
-       		temp1=0x00;			/*no disable vb*/
-  }
+      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {   /* ===== TW: For 30xB/LV ===== */
 
-  if(SiS_IF_DEF_LVDS==0) {
-   if(!(temp1)){              /*301b*/
-    SiS_SetRegANDOR(SiS_Part2Port,0x00,0x0DF,0x00);   /* disable VB */
-    SiS_DisplayOff();
-    if(HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */
-      SiS_SetRegOR(SiS_Part1Port,0x00,0x80);  /* FUNCTION CTRL | alan,BScreenOff */
-    }
-    SiS_SetRegANDOR(SiS_P3c4,0x32,0xDF,0x00);
-    
-    temp = SiS_GetReg1(SiS_Part1Port,0); 
-    SiS_SetRegOR(SiS_Part1Port,0x00,0x10);  /* FUNCTION CTRL | alan,BScreenOff */
-/*
-     if(HwDeviceExtension->jChipType >= SIS_315H)
-     {
-      	SiS_SetRegAND(SiS_Part1Port,0x2E,0x7F);
-     }
-*/
-     SiS_SetRegANDOR(SiS_P3c4,0x1E,0xDF,0x00);
-     SiS_SetReg1(SiS_Part1Port,0,temp);
-    }
-    else {
-    if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))  /*301b*/
-      {
-        if(!(SiS_Is301B(BaseAddr))) {
-          SiS_SetRegAND(SiS_P3c4,0x32,0xDF);
-          if((!(SiS_IsDualEdge(BaseAddr)))&&(!(SiS_IsVAMode(BaseAddr))))
-            tempah=0x7F;
-          else if((!(SiS_IsDualEdge(BaseAddr)))&&(SiS_IsVAMode(BaseAddr)))
-            tempah=0xBF;
-          else
-            tempah=0x3F;
-          SiS_SetRegAND(SiS_Part4Port,0x1F,tempah);
-        }
-      }
-    }
-  }
-  else { /* LVDS */
-    if(SiS_IF_DEF_CH7005==1) {
-      SiS_Backup7005 = SiS_GetCH7005(0x0e);
-      SiS_SetCH7005(0x090E);
-    }
-    SiS_DisplayOff();
-    SiS_SetRegANDOR(SiS_P3c4,0x32,0xDF,0x00);
-    SiS_SetRegANDOR(SiS_P3c4,0x1E,0xDF,0x00);
-    SiS_UnLockCRT2(HwDeviceExtension,BaseAddr);
-    SiS_SetRegANDOR(SiS_Part1Port,0x01,0xFF,0x80);
-    SiS_SetRegANDOR(SiS_Part1Port,0x02,0xFF,0x40);
-  }
-  /*SetPanelDelay(0);  */
-  SiS_SetRegANDOR(SiS_P3c4,0x11,0xFB,0x04);
-}
+        if(HwDeviceExtension->jChipType < SIS_315H) {
 
-void
-SiS_EnableBridge(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT  BaseAddr)
-{
-  USHORT temp,tempah;
+	   /* 300 series */
 
-  SiS_SetRegANDOR(SiS_P3c4,0x11,0xFB,0x00);
+	   if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwDeviceExtension))) {
+	      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF7,0x08);
+	      SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+	   }
+	   if(SiS_Is301B(SiS_Pr,BaseAddr)) {
+	      SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1f,0x3f);
+	      SiS_ShortDelay(SiS_Pr,1);
+	   }
+	   SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF);
+	   SiS_DisplayOff(SiS_Pr);
+	   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+	   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+	   SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension,BaseAddr);
+	   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x80);
+	   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40);
+	   if( (!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr))) ||
+	              (!(SiS_CR36BIOSWord23d(SiS_Pr,HwDeviceExtension))) ) {
+	      SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
+              SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xFB,0x04);
+	   }
 
-  /*SetPanelDelay(0);        */
-  if(SiS_IF_DEF_LVDS==0) {
-    if( (!(SiS_IsVAMode(BaseAddr))) &&
-        (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))) {
-    		SiS_SetRegANDOR(SiS_Part2Port,0x00,0x1F,0x20);
-    } else {
-      temp=SiS_GetReg1(SiS_P3c4,0x32);
-      temp=temp&0xDF;
-      if(SiS_BridgeInSlave()) {
-        tempah=SiS_GetReg1(SiS_P3d4,0x30);
-        if(!(tempah&SetCRT2ToRAMDAC)) {
-         temp=temp|0x20;
-        }
-      }
-      SiS_SetReg1(SiS_P3c4,0x32,temp);
-      SiS_SetRegANDOR(SiS_P3c4,0x1E,0xFF,0x20);
+        } else {
 
-      if(HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */
-        temp=SiS_GetReg1(SiS_Part1Port,0x2E);
-        if (!(temp&0x80))
-          SiS_SetRegOR(SiS_Part1Port,0x2E,0x80);          /* by alan,BVBDOENABLE=1 */
-      }
-
-      SiS_SetRegANDOR(SiS_Part2Port,0x00,0x1F,0x20);
-
-      if(HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */
-      	temp=SiS_GetReg1(SiS_Part1Port,0x2E);
-     	if (!(temp&0x80))
-            SiS_SetRegOR(SiS_Part1Port,0x2E,0x80);          /* by alan,BVBDOENABLE=1 */
-      }
-   
-      SiS_SetRegANDOR(SiS_Part2Port,0x00,0x1F,0x20);
-      SiS_VBLongWait();
-      SiS_DisplayOn();
-      SiS_VBLongWait();
-    }  
-  /*add301b*/
-    if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-      if(!(SiS_Is301B(BaseAddr))){  
-        temp=SiS_GetReg1(SiS_Part1Port,0x2E);
-        if(!(temp&0x80))
-           SiS_SetRegOR(SiS_Part1Port,0x2E,0x80);
-        if((!(SiS_IsDualEdge(BaseAddr)))&&(!(SiS_IsVAMode(BaseAddr))))
-           tempah=0x80;
-        else if((!(SiS_IsDualEdge(BaseAddr)))&&(SiS_IsVAMode(BaseAddr)))
-           tempah=0x40;
-        else
-           tempah=0xC0;
-        SiS_SetRegOR(SiS_Part4Port,0x1F,tempah);
-      }
-     }  
-  /*end 301b*/
-  } else {                /*LVDS*/
-    SiS_EnableCRT2();
-    SiS_DisplayOn();
-    SiS_UnLockCRT2(HwDeviceExtension, BaseAddr);
-    SiS_SetRegANDOR(SiS_Part1Port,0x02,0xBF,0x00);
-    if(SiS_BridgeInSlave()) {
-      	SiS_SetRegANDOR(SiS_Part1Port,0x01,0x1F,0x00);
-    } else {
-      	SiS_SetRegANDOR(SiS_Part1Port,0x01,0x1F,0x40);
-    }
-    if(SiS_IF_DEF_CH7005) {
-        if (SiS_Backup7005 != 0xff) {
-		SiS_SetCH7005(((SiS_Backup7005<<8)|0x0E));
-		SiS_Backup7005 = 0xff;
-	} else SiS_SetCH7005(0x0B0E);
-    }
-  }
-  /*SetPanelDelay(1);  */
-  SiS_SetRegANDOR(SiS_P3c4,0x11,0xF7,0x00);
-}
+	   /* 310 series */
 
-void
-SiS_SetPanelDelay(USHORT DelayTime)
-{
-  USHORT PanelID;
+#ifdef SIS650301NEW  /* From 650/301LVx 1.10.6s */
+	   if(!(SiS_IsM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	       tempah = 0xef;
+	       if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	           tempah = 0xf7;
+               }
+	       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x4c,tempah);
+	   }
 
-  PanelID=SiS_GetReg1(SiS_P3d4,0x36);
-  PanelID=PanelID>>4;
+	   SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
 
-  if(DelayTime==0) SiS_LCD_Wait_Time(SiS_PanelDelayTbl[PanelID].timer[0]);
-  else SiS_LCD_Wait_Time(SiS_PanelDelayTbl[PanelID].timer[1]);
-}
+	   if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	     	   SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFE,0x00);
+	   } else if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+		   SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFE,0x00);
+           }
 
-void
-SiS_LCD_Wait_Time(UCHAR DelayTime)
-{
-  USHORT i,j;
-  ULONG  temp,flag;
+	   SiS_SetReg3(SiS_Pr->SiS_P3c6,0x00);
 
-  flag=0;
-  for(i=0;i<DelayTime;i++) {
-    for(j=0;j<66;j++) {
-      temp=SiS_GetReg3(0x61);
-      temp=temp&0x10;
-      if(temp==flag) continue;
-      flag=temp;
-    }
-  }
-}
+           pushax = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x06);
 
-/*301b*/
-BOOLEAN
-SiS_Is301B(USHORT BaseAddr)
-{
-  USHORT flag;
+	   SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
 
-    flag=SiS_GetReg1(SiS_Part4Port,0x01);
-    if(flag>(0x0B0)) return(0); /*301b*/
-    else return(1);
- }
+           if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
 
-BOOLEAN
-SiS_IsDualEdge(USHORT BaseAddr)
-{
-#ifdef SIS315H
-    USHORT flag;
+	       SiS_DisplayOff(SiS_Pr);
+	       SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
+	       SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+	       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1E,0xDF);
 
-     flag=SiS_GetReg1(SiS_P3d4,0x38);
-      if(flag&EnableDualEdge)
-        return (0);
-      else
-#endif
-      	return(1);
-}
+	   } else {
 
-BOOLEAN
-SiS_IsVAMode(USHORT BaseAddr)
-{
-  USHORT flag;
-         flag=SiS_GetReg1(SiS_P3d4,0x38);
-#ifdef SIS315H
-      if((flag&EnableDualEdge)&&(flag&SetToLCDA))
-        return (0);
-      else
-#endif
-      	return(1);
- }
+              SiS_DisplayOff(SiS_Pr);
+	      SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
+	      SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
+	      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+	      temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00);
+              SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10);
+	      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+	      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x00,temp);
 
-BOOLEAN
-SiS_IsDisableCRT2(USHORT BaseAddr)
-{
-  USHORT flag;
+	   }
 
-  flag=SiS_GetReg1(SiS_P3d4,0x30);
-  if(flag&0x20) return(0); /*301b*/
-  else return(1);
-}
-/*end 301b*/
+	   tempah = 0x3f;
+	   if(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	      tempah = 0x7f;
+	      if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		  tempah = 0xbf;
+              }
+	   }
+	   SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,tempah);
 
-BOOLEAN
-SiS_BridgeIsOn(USHORT BaseAddr)
-{
-  USHORT flag;
+	   SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f);
 
-  if(SiS_IF_DEF_LVDS==1){
-    return(1);
-  }
-  else {
-    flag=SiS_GetReg1(SiS_Part4Port,0x00);
-      if((flag==1)||(flag==2)) return(1); /*301b*/
-    else return(0);
-  }
-}
+	   if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	      SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xdf);
+	   }
+
+	   if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	      if(!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr))) {
+	         if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		    SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFD,0x00);
+                 }
+              }
+	   }
 
+	   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x06,pushax);
 
-BOOLEAN
-SiS_BridgeIsEnable(USHORT BaseAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-  USHORT flag;
+#else	    /* TW: From 650/301LV BIOS */
 
-  if(SiS_BridgeIsOn(BaseAddr)==0) 
-  {
-    flag=SiS_GetReg1(SiS_Part1Port,0x0);
-    if(HwDeviceExtension->jChipType < SIS_315H) {
-      /* 300 series */
-      if(flag&0x0a0) return 1;
-      else	     return 0;
-    } else {
-      /* 310 series */
-      if(flag&0x050) return 1;
-      else           return 0;
-    }
-  }
-  return 0;
-}
+	   if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	     	   SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFE,0x00);
+		   SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+	   } else if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+		   SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFE,0x00);
+		   SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+           }
 
-BOOLEAN
-SiS_BridgeInSlave()
-{
-  USHORT flag1;
+           /* TW: 301B dependent code starts here in 650/301LV BIOS */
+	   if(SiS_Is301B(SiS_Pr,BaseAddr)) {
+	     tempah = 0x3f;
+             SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x1F,tempah);
+           }
 
-  flag1=SiS_GetReg1(SiS_P3d4,0x31);
-  if(flag1&(SetInSlaveMode>>8)) return 1;
-  else  return 0;
-}
+           SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF);
+	   SiS_DisplayOff(SiS_Pr);
 
-BOOLEAN
-SiS_GetLCDResInfo301(ULONG ROMAddr,USHORT SiS_P3d4,
-                     USHORT ModeNo,USHORT ModeIdIndex)
-{
-  USHORT temp,modeflag,resinfo=0;
 
-  SiS_LCDResInfo=0;
-  SiS_LCDTypeInfo=0;
-  SiS_LCDInfo=0;
+           SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
 
-  if (ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;  	/* si+St_ModeFlag  */
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-    	resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO; 	/*si+Ext_ResInfo*/
-  }
+           SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
 
-  if(!(SiS_VBInfo&(SetCRT2ToLCD|SetCRT2ToLCDA))){
-    	return 0;
-  }
-  if(!(SiS_VBInfo&(SetSimuScanMode|SwitchToCRT2))) {
-    	return 0;
-  }
-  temp=SiS_GetReg1(SiS_P3d4,0x36);
-  /*fstn*/
-  if(SiS_IF_DEF_FSTN){
-   	temp=0x27;
-   	SiS_SetReg1(SiS_P3d4,0x36,temp);
-  } 
-  SiS_LCDTypeInfo=temp>>4;
-  SiS_LCDResInfo=temp&0x0F;
-  if(SiS_IF_DEF_LVDS==0) {
-    	if(SiS_LCDResInfo<Panel1024x768) SiS_LCDResInfo=Panel1024x768;
-  } else {
-    	if(SiS_LCDResInfo<Panel800x600) SiS_LCDResInfo=Panel800x600;
-  }
-#if 0
-  /* TW: No 1600x1200 panels? Don't think so... */
-  if(SiS_LCDResInfo>Panel640x480) SiS_LCDResInfo=Panel1024x768;
+	   temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00);
+           SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10);
+	   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+	   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x00,temp);
+
+	   /* TW: Inserted from 650/301LV BIOS */
+	   if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	       if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	           if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		          SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
+			  SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFD,0x00);
+			  SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 4);
+                   } else if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+                          SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
+			  SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFD,0x00);
+			  SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 4);
+		   }
+	       }
+	    } else if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	       if(!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr))) {
+	            SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 2);
+		    SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFD,0x00);
+		    SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 4);
+               } else if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	           if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		          SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 2);
+			  SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFD,0x00);
+			  SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 4);
+                   } else if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+                          SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 2);
+			  SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFD,0x00);
+			  SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 4);
+		   }
+	       }
+	   } /* TW: 650/301LV end */
 #endif
-  if(SiS_LCDResInfo>Panel1600x1200) SiS_LCDResInfo=Panel1024x768;
-  /*fstn*/
-  if(SiS_IF_DEF_FSTN){
-       	SiS_LCDResInfo=Panel320x480;
-  }
-  temp=SiS_GetReg1(SiS_P3d4,0x37);
-  if(SiS_IF_DEF_FSTN){
-      	temp=0x04;
-      	SiS_SetReg1(SiS_P3d4,0x37,temp);
-  }
-  SiS_LCDInfo=temp;
 
-#ifdef LINUX_KERNEL
-  printk(KERN_INFO "sisfb: (LCDInfo = 0x%x LCDResInfo = 0x%x LCDTypeInfo = 0x%x)\n",
-                   SiS_LCDInfo, SiS_LCDResInfo, SiS_LCDTypeInfo);
-#endif
-#ifdef LINUX_XF86
-  xf86DrvMsg(0, X_INFO, "(init301.c: LCDInfo = 0x%x LCDResInfo = 0x%x LCDTypeInfo = 0x%x)\n",
-			SiS_LCDInfo, SiS_LCDResInfo, SiS_LCDTypeInfo);
-#endif
+	}
 
-  if(SiS_IF_DEF_LVDS==1){
-     if(modeflag&HalfDCLK){
-        if(SiS_IF_DEF_TRUMPION==0){
-            if(!(SiS_LCDInfo&LCDNonExpanding)){
-               if(ModeNo>0x13) {
-                  if(SiS_LCDResInfo==Panel1024x768){
-                      if(resinfo==4){                                /* 512x384  */
-                           SiS_SetFlag=SiS_SetFlag|EnableLVDSDDA;
-                      }
-                  } else {
-                      if(SiS_LCDResInfo==Panel800x600){
-                           if(resinfo==3){                             /*400x300  */
-                                SiS_SetFlag=SiS_SetFlag|EnableLVDSDDA;
-                           }
-                      }
-                  }
-               }
-           } else { /* NonExpanding */
-              SiS_SetFlag=SiS_SetFlag|EnableLVDSDDA;
-           }
-        } else { /* TRUMPION */
-          SiS_SetFlag=SiS_SetFlag|EnableLVDSDDA;
-        }
-     }
-  }
+      } else {     /* ============ TW: For 301 ================ */
 
-  if(SiS_VBInfo&SetInSlaveMode){
-    	if(SiS_VBInfo&SetNotSimuMode){
-      		SiS_SetFlag=SiS_SetFlag|LCDVESATiming;
-    	}
-  } else {
-    	SiS_SetFlag=SiS_SetFlag|LCDVESATiming;
-  }
-  return 1;
-}
+        if(HwDeviceExtension->jChipType < SIS_315H) {
+            if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) {
+                SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF0,0x0B);
+	        SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 1);
+	    }
+	}
 
-void
-SiS_PresetScratchregister(USHORT SiS_P3d4,PSIS_HW_DEVICE_INFO HwDeviceExtension)
-{
-  /*SiS_SetReg1(SiS_P3d4,0x30,0x21);  */
-  /*SiS_SetReg1(SiS_P3d4,0x31,0x41);  */
-  /*SiS_SetReg1(SiS_P3d4,0x32,0x28);  */
-  /*SiS_SetReg1(SiS_P3d4,0x33,0x22);  */
-  /*SiS_SetReg1(SiS_P3d4,0x35,0x43);  */
-  /*SiS_SetReg1(SiS_P3d4,0x36,0x01);  */
-  /*SiS_SetReg1(SiS_P3d4,0x37,0x00);  */
-}
+        SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xDF);           /* disable VB */
+        SiS_DisplayOff(SiS_Pr);
 
-void
-SiS_LongWait()
-{
-  USHORT i;
+        if(HwDeviceExtension->jChipType >= SIS_315H) {
+            SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
+	}
 
-  i=SiS_GetReg1(SiS_P3c4,0x1F);
-  if(!(i&0xC0)) {
+        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);                /* disable lock mode */
 
+	if(HwDeviceExtension->jChipType >= SIS_315H) {
+            temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00);
+            SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x10);
+	    SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
+	    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x00,temp);
+	} else {
+            SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);            /* disable CRT2 */
+	}
+
+      }
+
+  } else {     /* ============ TW: For LVDS =============*/
+
+    if(HwDeviceExtension->jChipType < SIS_315H) {
+
+	/* 300 series */
+
+	if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+#if 0	/* TW: Implemented this for power saving, but it's not worth
+         *     the problems
+	 */
+	    if(SiS_Pr->SiS_Backup70xx == 0xff) {
+		SiS_Pr->SiS_Backup70xx = SiS_GetCH700x(SiS_Pr,0x0e);
+	    }
+#endif
+	    SiS_SetCH700x(SiS_Pr,0x090E);
+	}
+
+	if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x11) & 0x08)) {
+
+	    if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x40)) {
+
+	        if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwDeviceExtension))) {
+
+                     SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+
+		     if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x06) & 0x1c)) {
+		         SiS_DisplayOff(SiS_Pr);
+	             }
+
+	             SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF7,0x08);
+	             SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+                }
+            }
+	}
+
+	SiS_DisplayOff(SiS_Pr);
+
+	SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+
+	SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+	SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension,BaseAddr);
+	SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x01,0x80);
+	SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x02,0x40);
+
+	if( (!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr))) ||
+	              (!(SiS_CR36BIOSWord23d(SiS_Pr,HwDeviceExtension))) ) {
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
+		SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xFB,0x04);
+	}
+
+    } else {
+
+	/* 310 series */
+
+	if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+		if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+			SiS_Chrontel701xBLOff(SiS_Pr);
+			SiS_Chrontel701xOff(SiS_Pr);
+		} else if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+			SiS_Chrontel701xBLOff(SiS_Pr);
+			SiS_Chrontel701xOff(SiS_Pr);
+		}
+
+		if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+			SiS_SetCH701x(SiS_Pr,0x0149);
+		} else if(SiS_IsTVOrYPbPr(SiS_Pr,HwDeviceExtension, BaseAddr))  {
+			SiS_SetCH701x(SiS_Pr,0x0149);
+		}
+	}
+
+	if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		SiS_DisplayOff(SiS_Pr);
+	} else if(!(SiS_IsTVOrYPbPr(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		SiS_DisplayOff(SiS_Pr);
+	}
+
+	if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
+	} else if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x00,0x80);
+	}
+
+	SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x32,0xDF);
+
+	if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+	} else if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1E,0xDF);
+	}
+
+	if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+		SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x1e,0xdf);
+	}
+
+	if(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+		SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xff);
+	} else {
+		SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x13,0xfb);
+	}
+
+	SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension, BaseAddr);
+
+	if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0xf7);
+	} else if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+		SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0xf7);
+	}
+
+#if 0  /* TW: BIOS code makes no sense */
+       if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+           if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	        if(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+		  /* Nothing there! */
+		}
+           }
+       }
+#endif
+
+    }  /* 310 series */
+
+  }  /* LVDS */
+
+}
+
+/* TW: Checked against all BIOSes */
+void
+SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+  USHORT temp=0,tempah,pushax,temp1;
+  UCHAR *ROMAddr = HwDeviceExtension->pjVirtualRomBase;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+
+    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {   /* TW: ====== For 301B et al  ====== */
+
+      if(HwDeviceExtension->jChipType < SIS_315H) {
+
+         /* 300 series */
+
+	 if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) {
+	    SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x11,0xFB);
+	    if(!(SiS_CR36BIOSWord23d(SiS_Pr,HwDeviceExtension))) {
+	       SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 0);
+	    }
+	    SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);   /* Enable CRT2 */
+/*	    DoSomeThingPCI_On(SiS_Pr) */
+            SiS_DisplayOn(SiS_Pr);
+	    SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension, BaseAddr);
+	    SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xBF);
+	    if(SiS_BridgeInSlave(SiS_Pr)) {
+      		SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x01,0x1F);
+      	    } else {
+      		SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0x1F,0x40);
+            }
+	    if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x40)) {
+	        if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16) & 0x10)) {
+		    if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwDeviceExtension))) {
+		        SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
+                    }
+		    SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+                    SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF7,0x00);
+                }
+	    }
+         } else {
+	   temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32) & 0xDF;             /* lock mode */
+           if(SiS_BridgeInSlave(SiS_Pr)) {
+              tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+              if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
+           }
+           SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
+	   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1F,0x20);        /* enable VB processor */
+	   if(SiS_Is301B(SiS_Pr,BaseAddr)) {
+              SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,0xC0);
+	      SiS_DisplayOn(SiS_Pr);
+	   } else {
+	      SiS_VBLongWait(SiS_Pr);
+	      SiS_DisplayOn(SiS_Pr);
+	      SiS_VBLongWait(SiS_Pr);
+	   }
+	 }
+
+      } else {
+
+         /* 310 series */
+
+#ifdef SIS650301NEW   /* TW: From 650/301LVx 1.10.6s */
+
+         if(!(SiS_IsM650or651(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	       tempah = 0x10;
+	       if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	           tempah = 0x08;
+               }
+	       SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x4c,tempah);
+	 }
+
+	 SiS_SetReg3(SiS_Pr->SiS_P3c6,0x00);
+
+	 SiS_DisplayOff(SiS_Pr);
+
+	 pushax = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x06);
+
+	 if( (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
+	     (SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) ) {
+             if(!(SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) {
+	        SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02);
+	     }
+	 }
+
+	 if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+             temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32) & 0xDF;
+	     if(SiS_BridgeInSlave(SiS_Pr)) {
+                tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+                if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
+             }
+             SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
+
+	     SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);                   /* enable CRT2 */
+	     SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 2);
+	 }
+
+	 if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	     SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1e,0x20);
+	 }
+
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1f,0x20);
+
+	 tempah = 0xc0;
+	 if(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	     tempah = 0x80;
+	     if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	        tempah = 0x40;
+             }
+	 }
+         SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,tempah);
+
+	 SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2e,0x80);
+
+	 if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	    if( (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
+	        ((SiS_CRT2IsLCD(SiS_Pr,BaseAddr))) ) {
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 3);
+                SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+		SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xfe,0x01);
+	    }
+	 }
+
+	 SiS_SetReg1(SiS_Pr->SiS_P3c4,0x06,pushax);
+	 SiS_DisplayOn(SiS_Pr);
+	 SiS_SetReg3(SiS_Pr->SiS_P3c6,0xff);
+
+	 if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	     SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
+	 }
+
+         SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
+	 SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x0c);
+	 SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x20);
+	 SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x31,0x05);
+	 SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x32,0x60);
+	 SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x33,0x00);
+	 SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
+	 SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x30,0x40);
+
+#else	 /* TW: From 650/301LV BIOS (different PanelDelay!) */
+
+	 if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	     SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xfd,0x02);
+	     SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 0);
+	 } else if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) {
+	     SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xfd,0x02);
+	     SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 0);
+	 }
+	 /* TW: --- end --- */
+
+         if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+            temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32) & 0xDF;
+	    if(SiS_BridgeInSlave(SiS_Pr)) {
+               tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+               if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
+            }
+            SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
+
+	    SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);                   /* enable CRT2 */
+
+/*          SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2E,0x7F);   */ 	/* TW: Not done in 650/301LV BIOS */
+            temp=SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2E);
+            if (!(temp & 0x80))
+                   SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);
+          }
+
+          SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1F,0x20);        /* enable VB processor */
+
+          if(SiS_Is301B(SiS_Pr,BaseAddr)) {
+
+             SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x1F,0xc0);
+
+             if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr)))   /* TW: "if" new from 650/301LV BIOS */
+	        SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7F);
+
+          } else {
+
+             SiS_VBLongWait(SiS_Pr);
+             SiS_DisplayOn(SiS_Pr);
+	     if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr)))  {  /* TW: "if" new from 650/301LV BIOS */
+	        SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7F);
+                SiS_VBLongWait(SiS_Pr);
+	     }
+
+          }
+
+	  /* TW: Entire section from 650/301LV BIOS */
+	  if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+	     if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+/*	        if (!(SiS_WeHaveBacklightCtrl(HwDeviceExtension, BaseAddr))) {  */ /* TW: BIOS code makes no sense */
+		   SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
+		   SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+		   SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFE,0x01);
+/*              }   */
+             } else if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) {
+/*	        if (!(SiS_WeHaveBacklightCtrl(HwDeviceExtension, BaseAddr))) {  */ /* TW: BIOS code makes no sense */
+		   SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
+		   SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+		   SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFE,0x01);
+/*              }   */
+	     }
+	  }
+
+#endif
+
+      }
+
+    } else {	/* ============  TW: For 301 ================ */
+
+       if(HwDeviceExtension->jChipType < SIS_315H) {
+            if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) {
+                SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF0,0x0B);
+	        SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 0);
+	    }
+       }
+
+       temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x32) & 0xDF;          /* lock mode */
+       if(SiS_BridgeInSlave(SiS_Pr)) {
+         tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+         if(!(tempah & SetCRT2ToRAMDAC))  temp |= 0x20;
+       }
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
+
+       SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1E,0x20);                  /* enable CRT2 */
+
+       if(HwDeviceExtension->jChipType >= SIS_315H) {
+         temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2E);
+         if(!(temp & 0x80))
+           SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);         /* BVBDOENABLE=1 */
+       }
+
+       SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x00,0x1F,0x20);     /* enable VB processor */
+
+       SiS_VBLongWait(SiS_Pr);
+       SiS_DisplayOn(SiS_Pr);
+       if(HwDeviceExtension->jChipType >= SIS_315H) {
+           SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
+       }
+       SiS_VBLongWait(SiS_Pr);
+
+       if(HwDeviceExtension->jChipType < SIS_315H) {
+            if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) {
+	        SiS_SetPanelDelay(SiS_Pr, ROMAddr, HwDeviceExtension, 1);
+                SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x11,0xF0,0x03);
+	    }
+       }
+
+    }
+
+  } else {   /* =================== TW: For LVDS ================== */
+
+    if(HwDeviceExtension->jChipType < SIS_315H) {
+
+      /* 300 series */
+
+      if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) {
+         SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x11,0xFB);
+	 if(!(SiS_CR36BIOSWord23d(SiS_Pr,HwDeviceExtension))) {
+	    SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 0);
+	 }
+      }
+
+      SiS_EnableCRT2(SiS_Pr);
+      SiS_DisplayOn(SiS_Pr);
+      SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension, BaseAddr);
+      SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x02,0xBF);
+      if(SiS_BridgeInSlave(SiS_Pr)) {
+      	SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x01,0x1F);
+      } else {
+      	SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x01,0x1F,0x40);
+      }
+
+      if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+        if(!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr))) {
+#if 0	/* TW: Implemented this for power saving, but it's not worth
+         *     the problems
+	 */
+           if(SiS_Pr->SiS_Backup70xx != 0xff) {
+		SiS_SetCH700x(SiS_Pr,((SiS_Pr->SiS_Backup70xx<<8)|0x0E));
+		SiS_Pr->SiS_Backup70xx = 0xff;
+	   } else
+#endif
+	        SiS_SetCH700x(SiS_Pr,0x0B0E);
+        }
+      }
+
+      if(SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) {
+          if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x40)) {
+              if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16) & 0x10)) {
+	          if(!(SiS_CR36BIOSWord23b(SiS_Pr,HwDeviceExtension))) {
+			SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
+        		SiS_SetPanelDelay(SiS_Pr,ROMAddr, HwDeviceExtension, 1);
+		  }
+		  SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+                  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x11,0xF7);
+              }
+	  }
+      }
+
+    } else {
+
+       /* 310 series */
+
+#if 0  /* BIOS code makes no sense */
+       if(SiS_IsVAMode()) {
+          if(SiS_IsLCDOrLCDA()) {
+	  }
+       }
+#endif
+
+       SiS_EnableCRT2(SiS_Pr);
+       SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension, BaseAddr);
+
+       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0xf7);
+
+       if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+          temp = SiS_GetCH701x(SiS_Pr,0x66);
+	  temp &= 0x20;
+	  SiS_Chrontel701xBLOff(SiS_Pr);
+       }
+
+       SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x2e,0x7f);
+
+       temp1 = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x2E);
+       if (!(temp1 & 0x80))
+           SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x2E,0x80);
+
+       if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+           if(temp) {
+	       SiS_Chrontel701xBLOn(SiS_Pr);
+	   }
+       }
+
+       if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+           SiS_SetRegOR(SiS_Pr->SiS_Part1Port,0x1E,0x20);
+       }
+
+       if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+           SiS_SetRegAND(SiS_Pr->SiS_Part1Port,0x00,0x7f);
+       }
+
+       if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+
+       		if(SiS_IsTVOrYPbPr(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+           		SiS_Chrontel701xOn(SiS_Pr,HwDeviceExtension, BaseAddr);
+         	}
+
+         	if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+           		SiS_ChrontelDoSomething1(SiS_Pr,HwDeviceExtension, BaseAddr);
+         	} else if(SiS_IsLCDOrLCDA(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+           		SiS_ChrontelDoSomething1(SiS_Pr,HwDeviceExtension, BaseAddr);
+        	}
+
+       }
+
+       if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+       	 	if(!(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+ 	   		if(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	            		SiS_Chrontel701xBLOn(SiS_Pr);
+	            		SiS_ChrontelDoSomething4(SiS_Pr,HwDeviceExtension, BaseAddr);
+           		} else if(SiS_IsLCDOrLCDA(SiS_Pr,HwDeviceExtension, BaseAddr))  {
+/*	      			if(!SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr)) {  */ /* TW: makes no sense */
+            				SiS_Chrontel701xBLOn(SiS_Pr);
+            				SiS_ChrontelDoSomething4(SiS_Pr,HwDeviceExtension, BaseAddr);
+/*            			}   */
+	   		}
+       		}
+       }
+
+    } /* 310 series */
+
+  }  /* LVDS */
+
+}
+
+void
+SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
+
+  /* TW: Switch on LCD backlight on SiS30x */
+  if( (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ||
+      (SiS_CRT2IsLCD(SiS_Pr,BaseAddr)) ) {
+    if(!(SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x26) & 0x02)) {
+	SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x02);
+	SiS_WaitVBRetrace(SiS_Pr,HwDeviceExtension);
+    }
+    if(!(SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x26) & 0x01)) {
+        SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x26,0x01);
+    }
+  }
+}
+
+void
+SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
+
+  /* TW: Switch off LCD backlight on SiS30x */
+  if( (!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) ||
+      (SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr)) ) {
+	 SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFE,0x00);
+  }
+
+  if(!(SiS_IsVAMode(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+      if(!(SiS_CRT2IsLCD(SiS_Pr,BaseAddr))) {
+          if(!(SiS_IsDualEdge(SiS_Pr,HwDeviceExtension, BaseAddr))) {
+  	      SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x26,0xFD,0x00);
+          }
+      }
+  }
+}
+
+BOOLEAN
+SiS_CR36BIOSWord23b(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT temp,temp1;
+  UCHAR *ROMAddr;
+
+  if((ROMAddr = (UCHAR *)HwDeviceExtension->pjVirtualRomBase) && SiS_Pr->SiS_UseROM) {
+     temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0xff;
+     temp >>= 4;
+     temp = 1 << temp;
+     temp1 = (ROMAddr[0x23c] << 8) | ROMAddr[0x23b];
+     if(temp1 & temp) return(1);
+     else return(0);
+  } else {
+     return(0);
+  }
+}
+
+BOOLEAN
+SiS_CR36BIOSWord23d(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT temp,temp1;
+  UCHAR *ROMAddr;
+
+  if((ROMAddr = (UCHAR *)HwDeviceExtension->pjVirtualRomBase) && SiS_Pr->SiS_UseROM) {
+     temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36) & 0xff;
+     temp >>= 4;
+     temp = 1 << temp;
+     temp1 = (ROMAddr[0x23e] << 8) | ROMAddr[0x23d];
+     if(temp1 & temp) return(1);
+     else return(0);
+  } else {
+     return(0);
+  }
+}
+
+void
+SiS_SetPanelDelay(SiS_Private *SiS_Pr, UCHAR *ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                  USHORT DelayTime)
+{
+  USHORT PanelID, DelayIndex, Delay, temp;
+
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+
+      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {			/* 300 series, LVDS */
+
+	  PanelID = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36);
+
+	  DelayIndex = PanelID >> 4;
+
+	  if((DelayTime >= 2) && ((PanelID & 0x0f) == 1))  {
+              Delay = 3;
+          } else {
+              if(DelayTime >= 2) DelayTime -= 2;
+
+              if(!(DelayTime & 0x01)) {
+       		  Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[0];
+              } else {
+       		  Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1];
+              }
+	      if((ROMAddr) && (SiS_Pr->SiS_UseROM)) {
+                  if(ROMAddr[0x220] & 0x40) {
+                      if(!(DelayTime & 0x01)) {
+	    	          Delay = (USHORT)ROMAddr[0x225];
+                      } else {
+	    	          Delay = (USHORT)ROMAddr[0x226];
+                      }
+                  }
+              }
+          }
+	  SiS_ShortDelay(SiS_Pr,Delay);
+
+      } else {							/* 300 series, 301(B) */
+
+	  PanelID = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36);
+	  temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x18);
+          if(!(temp & 0x10))  PanelID = 0x12;
+
+          DelayIndex = PanelID >> 4;
+
+	  if((DelayTime >= 2) && ((PanelID & 0x0f) == 1))  {
+              Delay = 3;
+          } else {
+              if(DelayTime >= 2) DelayTime -= 2;
+
+              if(!(DelayTime & 0x01)) {
+       		  Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[0];
+              } else {
+       		  Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1];
+              }
+	      if((ROMAddr) && (SiS_Pr->SiS_UseROM)) {
+                  if(ROMAddr[0x220] & 0x40) {
+                      if(!(DelayTime & 0x01)) {
+	    	          Delay = (USHORT)ROMAddr[0x225];
+                      } else {
+	    	          Delay = (USHORT)ROMAddr[0x226];
+                      }
+                  }
+              }
+          }
+	  SiS_ShortDelay(SiS_Pr,Delay);
+
+      }
+
+   } else {
+
+      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {			/* 310/325 series, LVDS */
+
+          /* TW: Not currently used */
+
+      } else {							/* 310/325 series, 301(B) */
+
+          PanelID = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36);
+	  DelayIndex = PanelID >> 4;
+          if(!(DelayTime & 0x01)) {
+       		Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[0];
+          } else {
+       		Delay = SiS_Pr->SiS_PanelDelayTbl[DelayIndex].timer[1];
+          }
+	  SiS_DDC2Delay(SiS_Pr, Delay * 4);
+
+      }
+
+   }
+
+}
+
+void
+SiS_LongDelay(SiS_Private *SiS_Pr, USHORT delay)
+{
+  while(delay--) {
+    SiS_GenericDelay(SiS_Pr,0x19df);
+  }
+}
+
+void
+SiS_ShortDelay(SiS_Private *SiS_Pr, USHORT delay)
+{
+  while(delay--) {
+      SiS_GenericDelay(SiS_Pr,0x42);
+  }
+}
+
+void
+SiS_GenericDelay(SiS_Private *SiS_Pr, USHORT delay)
+{
+  USHORT temp,flag;
+
+  flag = SiS_GetReg3(0x61) & 0x10;
+
+  while(delay) {
+      temp = SiS_GetReg3(0x61) & 0x10;
+      if(temp == flag) continue;
+      flag = temp;
+      delay--;
+  }
+}
+
+BOOLEAN
+SiS_Is301B(SiS_Private *SiS_Pr, USHORT BaseAddr)
+{
+  USHORT flag;
+
+  flag = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x01);
+  if(flag >= 0x0B0) return(1);
+  else return(0);
+}
+
+BOOLEAN
+SiS_CRT2IsLCD(SiS_Private *SiS_Pr, USHORT BaseAddr)
+{
+  USHORT flag;
+
+  flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+  if(flag & 0x20) return(1);
+  else return(0);
+}
+
+BOOLEAN
+SiS_IsDualEdge(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+#ifdef SIS315H
+  USHORT flag;
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+     if(flag & EnableDualEdge)  return(1);
+     else  return(0);
+  } else
+#endif
+     return(0);
+}
+
+BOOLEAN
+SiS_IsVAMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+#ifdef SIS315H
+  USHORT flag;
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+     if((flag & EnableDualEdge) && (flag & SetToLCDA))   return(1);
+#if 0 /* Not done in 650/301LVx 1.10.6s, but in 650/301LV */
+     else if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+       if(flag) return(1);
+       else     return(0);   			         
+     }
+#endif
+     else
+       return(0);
+  } else
+#endif
+     return(0);
+ }
+
+BOOLEAN
+SiS_WeHaveBacklightCtrl(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+#ifdef SIS315H
+  USHORT flag;
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x79);
+     if(flag & 0x10)  return(1);
+     else             return(0);
+  } else
+#endif
+     return(0);
+ }
+
+#if 0
+BOOLEAN
+SiS_Is315E(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+#ifdef SIS315H
+  USHORT flag;
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x5f);
+     if(flag & 0x10)  return(1);
+     else      	      return(0);
+  } else
+#endif
+     return(0);
+}
+#endif
+
+BOOLEAN
+SiS_IsM650or651(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+#ifdef SIS315H
+  USHORT flag;
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x5f);
+     flag &= 0xF0;
+     if((flag == 0xb0) || (flag == 0x90)) return 0;
+     else return 1;
+  } else
+#endif
+    return 1;
+}
+
+BOOLEAN
+SiS_IsYPbPr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+#ifdef SIS315H
+  USHORT flag;
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+     if(flag & 0x08)  return(1);
+     else      	      return(0);
+  } else
+#endif
+     return(0);
+}
+
+BOOLEAN
+SiS_IsTVOrYPbPr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+  USHORT flag;
+
+#ifdef SIS315H
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+     if(flag & SetCRT2ToTV) return(1);
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+     if(flag & 0x08)        return(1);
+     else                   return(0);
+  } else
+#endif
+  {
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+     if(flag & SetCRT2ToTV) return(1);
+  }
+  return(0);
+}
+
+BOOLEAN
+SiS_IsLCDOrLCDA(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+  USHORT flag;
+
+#ifdef SIS315H
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+     if(flag & SetCRT2ToLCD) return(1);
+     flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+     if(flag & SetToLCDA)    return(1);
+     else                    return(0);
+  } else
+#endif
+  {
+   flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+   if(flag & SetCRT2ToLCD)   return(1);
+  }
+  return(0);
+
+}
+
+BOOLEAN
+SiS_IsDisableCRT2(SiS_Private *SiS_Pr, USHORT BaseAddr)
+{
+  USHORT flag;
+
+  flag = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30);
+  if(flag & 0x20) return(0);
+  else            return(1);
+}
+
+BOOLEAN
+SiS_BridgeIsOn(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT flag;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+     return(0);   					/* TW: Changed from 1 to 0! */
+  } else {
+#if 0   /* TW: Commented for test on bridge-less systems */
+     if(HwDeviceExtension->jChipType >= SIS_315H) {    	/* TW: New (from 630/301B BIOS - not done there) */
+#endif
+        flag = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x00);
+        if((flag == 1) || (flag == 2)) return(0);       /* TW: Changed from 1 to 0! */
+        else return(1);                                 /* TW: Changed from 0 to 1! */
+#if 0
+     } else  return(0);					/* TW: New (from 630/301B BIOS - always return 0) */
+#endif
+  }
+}
+
+BOOLEAN
+SiS_BridgeIsEnable(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT flag;
+
+  if(!(SiS_BridgeIsOn(SiS_Pr,BaseAddr,HwDeviceExtension))) {
+    flag = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00);
+    if(HwDeviceExtension->jChipType < SIS_315H) {
+      /* 300 series (630/301B 2.04.5a) */
+      flag &= 0xa0;
+      if((flag == 0x80) || (flag == 0x20)) return 0;
+      else	                           return 1;
+    } else {
+      /* 310/325 series (650/301LVx 1.10.6s) */
+      flag &= 0x50;
+      if((flag == 0x40) || (flag == 0x10)) return 0;
+      else                                 return 1;
+    }
+  }
+  return 1;
+}
+
+BOOLEAN
+SiS_BridgeInSlave(SiS_Private *SiS_Pr)
+{
+  USHORT flag1;
+
+  flag1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31);
+  if(flag1 & (SetInSlaveMode >> 8)) return 1;
+  else return 0;
+}
+
+/* TW: New from 650/301LV(x) 1.10.6s BIOS */
+void
+SiS_SetHiVision(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT temp;
+
+  SiS_Pr->SiS_HiVision = 0;
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+#if 0   /* TW: Old */
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+           SiS_Pr->SiS_HiVision = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+	   SiS_Pr->SiS_HiVision &= 0x38;
+	   SiS_Pr->SiS_HiVision >>= 3;
+        }
+#endif  /* TW: New from 650/301LVx BIOS 1.10.6s */
+        temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+	if(temp & 0x40) {
+	    temp &= 0x30;
+	    switch(temp) {
+	      case 0x00: SiS_Pr->SiS_HiVision = 4; break;
+	      case 0x10: SiS_Pr->SiS_HiVision = 1; break;
+	      case 0x20: SiS_Pr->SiS_HiVision = 2; break;
+	      default:   SiS_Pr->SiS_HiVision = 3; break;
+	    }
+	}
+     }
+  }
+}
+
+/* TW: Checked against 630/LVDS 2.08, 650/LVDS and 650/301LV BIOS */
+BOOLEAN
+SiS_GetLCDResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
+                  USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT temp,modeflag,resinfo=0;
+  const unsigned char SiS300SeriesLCDRes[] =
+         { 0, 1, 2, 3, 7, 4, 5, 8,
+	   0, 0, 0, 0, 0, 0, 0, 0 };
+
+  SiS_Pr->SiS_LCDResInfo = 0;
+  SiS_Pr->SiS_LCDTypeInfo = 0;
+  SiS_Pr->SiS_LCDInfo = 0;
+
+  if (ModeNo<=0x13) {
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  } else {
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  }
+
+  if(!(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)))   return 0;
+
+  if(!(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2))) return 0;
+
+  temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36);
+
+  /* FSTN: Fake CR36 (TypeInfo 2, ResInfo SiS_Panel320x480) */
+  if(SiS_Pr->SiS_IF_DEF_FSTN){
+   	temp = 0x20 | SiS_Pr->SiS_Panel320x480;
+   	SiS_SetReg1(SiS_Pr->SiS_P3d4,0x36,temp);
+  }
+
+  SiS_Pr->SiS_LCDTypeInfo = temp >> 4;
+  temp &= 0x0f;
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+      /* TW: Translate 300 series LCDRes to 310/325 series for unified usage */
+      temp = SiS300SeriesLCDRes[temp];
+  }
+  SiS_Pr->SiS_LCDResInfo = temp;
+
+  if(SiS_Pr->SiS_IF_DEF_FSTN){
+       	SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_Panel320x480;
+  }
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+    	if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMin301)
+		SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_PanelMin301;
+  } else {
+    	if(SiS_Pr->SiS_LCDResInfo < SiS_Pr->SiS_PanelMinLVDS)
+		SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_PanelMinLVDS;
+  }
+
+  if(SiS_Pr->SiS_LCDResInfo > SiS_Pr->SiS_PanelMax)
+  	SiS_Pr->SiS_LCDResInfo = SiS_Pr->SiS_Panel1024x768;
+
+  temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);
+  if(SiS_Pr->SiS_IF_DEF_FSTN){
+        /* TW: Fake LVDS bridge for FSTN */
+      	temp = 0x04;
+      	SiS_SetReg1(SiS_Pr->SiS_P3d4,0x37,temp);
+  }
+  SiS_Pr->SiS_LCDInfo = temp;
+
+  /* TW: Inserted entire 315-block from 650/LVDS/301+LVx BIOSes */
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+         if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+	     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+		 if(ModeNo == 0x3a || ModeNo == 0x4d || ModeNo == 0x65) {
+		     SiS_Pr->SiS_LCDInfo |= LCDNonExpanding;
+		 }
+	     }
+	 }
+     }
+     if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x01) {
+         SiS_Pr->SiS_LCDInfo &= 0xFFEF;    
+	 SiS_Pr->SiS_LCDInfo |= LCDPass11;
+     }
+  } else {
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+        if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+           if(!(ROMAddr[0x235] & 0x02)) {
+	      SiS_Pr->SiS_LCDInfo &= 0xEF;
+	   }
+        }
+     } else {
+        if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+	   if((SiS_Pr->SiS_SetFlag & CRT2IsVGA) && ((ModeNo == 0x03) || (ModeNo == 0x10))) {
+               SiS_Pr->SiS_LCDInfo &= 0xEF;
+	   }
+	}
+     }
+  }
+
+#ifdef LINUX_KERNEL
+  printk(KERN_INFO "sisfb: (LCDInfo = 0x%x LCDResInfo = 0x%x LCDTypeInfo = 0x%x)\n",
+                   SiS_Pr->SiS_LCDInfo, SiS_Pr->SiS_LCDResInfo, SiS_Pr->SiS_LCDTypeInfo);
+#endif
+#ifdef LINUX_XF86
+  xf86DrvMsg(0, X_PROBED, "(init301: LCDInfo=0x%04x LCDResInfo=0x%02x LCDTypeInfo=0x%02x)\n",
+			SiS_Pr->SiS_LCDInfo, SiS_Pr->SiS_LCDResInfo, SiS_Pr->SiS_LCDTypeInfo);
+#endif
+
+  /* TW: With Trumpion, always Expanding */
+  if(SiS_Pr->SiS_IF_DEF_TRUMPION != 0){
+       SiS_Pr->SiS_LCDInfo &= (~LCDNonExpanding);
+  }
+
+  if(!((HwDeviceExtension->jChipType < SIS_315H) && (SiS_Pr->SiS_SetFlag & CRT2IsVGA))) {
+
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+	   if(ModeNo > 0x13) {
+	      if(!(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)) {
+                 if((resinfo == 7) || (resinfo == 3)) {
+                    SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+		 }
+              }
+           }
+        }
+	if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+	   SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+	}
+     }
+
+     if(modeflag & HalfDCLK) {
+        if(SiS_Pr->SiS_IF_DEF_TRUMPION == 0) {
+           if(!(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)) {
+	      if(!(((SiS_Pr->SiS_IF_DEF_LVDS == 1) || (HwDeviceExtension->jChipType < SIS_315H)) &&
+	                                      (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480))) {
+                 if(ModeNo > 0x13) {
+                    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+                       if(resinfo == 4) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;     /* 512x384  */
+                    } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) {
+                       if(resinfo == 3) SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;     /* 400x300  */
+                    }
+                 }
+	      } else SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+           } else SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+        } else SiS_Pr->SiS_SetFlag |= EnableLVDSDDA;
+     }
+
+  }
+
+  /* TW: wdr: if (VBInfo & LCD) && (VBInfo & (SetSimuScanMode | SwitchToCRT2)) { */
+  if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+    	if(SiS_Pr->SiS_VBInfo & SetNotSimuMode) {
+      		SiS_Pr->SiS_SetFlag |= LCDVESATiming;
+    	}
+  } else {
+    	SiS_Pr->SiS_SetFlag |= LCDVESATiming;
+  }
+
+  /* TW: Inserted from 650/301LVx BIOS 1.10.6s */
+  if(SiS_Pr->SiS_VBType & VB_SIS30xNEW) {
+      temp = 0x00;
+      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) temp = 0x04;
+      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) temp = 0x04;
+      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) temp = 0x04;
+      SiS_SetReg1(SiS_Pr->SiS_P3d4,0x39,temp);
+  } else if((HwDeviceExtension->jChipType > SIS_315H) && (SiS_Pr->SiS_IF_DEF_LVDS == 0)) {
+      SiS_SetReg1(SiS_Pr->SiS_P3d4,0x39,0x00);
+  }
+
+  return 1;
+}
+
+void
+SiS_PresetScratchregister(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  return;
+  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x30,0x21);  */
+  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x31,0x41);  */
+  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x32,0x28);  */
+  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x33,0x22);  */
+  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x35,0x43);  */
+  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x36,0x01);  */
+  /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x37,0x00);  */
+}
+
+void
+SiS_LongWait(SiS_Private *SiS_Pr)
+{
+  USHORT i;
+
+  i = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1F);
+
+  if(!(i & 0xC0)) {
+    for(i=0; i<0xFFFF; i++) {
+       if(!(SiS_GetReg2(SiS_Pr->SiS_P3da) & 0x08))
+         break;
+    }
     for(i=0; i<0xFFFF; i++) {
-       if(!(SiS_GetReg2(SiS_P3da) & 0x08))
+       if((SiS_GetReg2(SiS_Pr->SiS_P3da) & 0x08))
          break;
     }
-    for(i=0; i<0xFFFF; i++) {
-       if((SiS_GetReg2(SiS_P3da) & 0x08))
-         break;
+  }
+}
+
+void
+SiS_VBLongWait(SiS_Private *SiS_Pr)
+{
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) {
+    SiS_VBWait(SiS_Pr);
+  } else {
+    SiS_LongWait(SiS_Pr);
+  }
+  return;
+}
+
+void
+SiS_VBWait(SiS_Private *SiS_Pr)
+{
+  USHORT tempal,temp,i,j;
+
+  temp = 0;
+  for(i=0; i<3; i++) {
+    for(j=0; j<100; j++) {
+       tempal = SiS_GetReg2(SiS_Pr->SiS_P3da);
+       if(temp & 0x01) {
+          if((tempal & 0x08))  continue;
+          if(!(tempal & 0x08)) break;
+       } else {
+          if(!(tempal & 0x08)) continue;
+          if((tempal & 0x08))  break;
+       }
+    }
+    temp ^= 0x01;
+  }
+}
+
+void
+SiS_WaitVBRetrace(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        if(!(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x20)) return;
+     }
+     if(!(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x80)) {
+        SiS_WaitRetrace1(SiS_Pr,HwDeviceExtension);
+     } else {
+        SiS_WaitRetrace2(SiS_Pr,HwDeviceExtension);
+     }
+  } else {
+     if(!(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x40)) {
+        SiS_WaitRetrace1(SiS_Pr,HwDeviceExtension);
+     } else {
+        SiS_WaitRetrace2(SiS_Pr,HwDeviceExtension);
+     }
+  }
+}
+
+void
+SiS_WaitRetrace1(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT i,watchdog;
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1f) & 0xc0) return;
+     watchdog = 65535;
+     while( (SiS_GetReg2(SiS_Pr->SiS_P3da) & 0x08) && --watchdog);
+     watchdog = 65535;
+     while( (!(SiS_GetReg2(SiS_Pr->SiS_P3da) & 0x08)) && --watchdog);
+  } else {
+#if 0  /* TW: Not done in A901 BIOS */
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1f) & 0xc0) return;
+     }
+#endif
+     for(i=0; i<10; i++) {
+        watchdog = 65535;
+        while( (SiS_GetReg2(SiS_Pr->SiS_P3da) & 0x08) && --watchdog);
+	if(watchdog) break;
+     }
+     for(i=0; i<10; i++) {
+        watchdog = 65535;
+        while( (!(SiS_GetReg2(SiS_Pr->SiS_P3da) & 0x08)) && --watchdog);
+	if(watchdog) break;
+     }
+  }
+}
+
+void
+SiS_WaitRetraceDDC(SiS_Private *SiS_Pr)
+{
+  USHORT watchdog;
+
+  if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1f) & 0xc0) return;
+  watchdog = 65535;
+  while( (SiS_GetReg2(SiS_Pr->SiS_P3da) & 0x08) && --watchdog);
+  watchdog = 65535;
+  while( (!(SiS_GetReg2(SiS_Pr->SiS_P3da) & 0x08)) && --watchdog);
+}
+
+void
+SiS_WaitRetrace2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT i,watchdog,temp;
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     watchdog = 65535;
+     while( (SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x30) & 0x02) && --watchdog);
+     watchdog = 65535;
+     while( (!(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x30) & 0x02)) && --watchdog);
+  } else {
+     for(i=0; i<10; i++) {
+        watchdog = 65535;
+	while( (temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x25) & 0x02) && --watchdog);
+	if(watchdog) break;
+     }
+     for(i=0; i<10; i++) {
+        watchdog = 65535;
+	while( (!(temp = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x25) & 0x02)) && --watchdog);
+	if(watchdog) break;
+     }
+  }
+}
+
+/* =========== Set and Get register routines ========== */
+
+void
+SiS_SetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR)
+{
+  USHORT temp;
+
+  temp = SiS_GetReg1(Port,Index);     /* SiS_Pr->SiS_Part1Port index 02 */
+  temp = (temp & (DataAND)) | DataOR;
+  SiS_SetReg1(Port,Index,temp);
+}
+
+void
+SiS_SetRegAND(USHORT Port,USHORT Index,USHORT DataAND)
+{
+  USHORT temp;
+
+  temp = SiS_GetReg1(Port,Index);     /* SiS_Pr->SiS_Part1Port index 02 */
+  temp &= DataAND;
+  SiS_SetReg1(Port,Index,temp);
+}
+
+void SiS_SetRegOR(USHORT Port,USHORT Index,USHORT DataOR)
+{
+  USHORT temp;
+
+  temp = SiS_GetReg1(Port,Index);     /* SiS_Pr->SiS_Part1Port index 02 */
+  temp |= DataOR;
+  SiS_SetReg1(Port,Index,temp);
+}
+
+/* ========================================================= */
+
+/* TW: Set 301 TV Encoder (and some LCD relevant) registers */
+/* TW: Checked against 650/301LV, 650/301LVx and 630/301B (I+II) */
+void
+SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr, USHORT ModeNo,
+              USHORT ModeIdIndex,USHORT RefreshRateTableIndex,
+	      PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT      i, j, tempax, tempbx, tempcx, temp, temp1;
+  USHORT      push1, push2;
+  const       UCHAR *PhasePoint;
+  const       UCHAR *TimingPoint;
+  const       SiS_Part2PortTblStruct *CRT2Part2Ptr = NULL;
+  USHORT      modeflag, resinfo, crt2crtc, resindex, CRT2Index;
+  ULONG       longtemp, tempeax, tempebx, temp2, tempecx;
+  const UCHAR atable[] = {
+                 0xc3,0x9e,0xc3,0x9e,0x02,0x02,0x02,
+	         0xab,0x87,0xab,0x9e,0xe7,0x02,0x02
+  };
+
+  /* TW: Inserted from 650/301LV BIOS */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+     /* TW: Inserted from 650/301LVx 1.10.6s: (Is at end of SetGroup2!) */
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xfc,0x03);
+	   temp = 1;
+	   if(ModeNo<=0x13) temp = 3;
+	   SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x0b,temp);
+	}
+     }
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {    /* 650/301LV: (VB_SIS301LV | VB_SIS302LV)) */
+       if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+         if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+           if((ModeNo == 0x4a) || (ModeNo == 0x38)) {
+               SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1c,0xa7);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1d,0x07);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1e,0xf2);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1f,0x6e);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x20,0x17);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x21,0x8b);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x22,0x73);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x23,0x53);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x24,0x13);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x25,0x40);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x26,0x34);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x27,0xf4);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x28,0x63);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x29,0xbb);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2a,0xcc);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2b,0x7a);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2c,0x58);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2d,0xe4);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2e,0x73);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,0xda);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x30,0x13);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x43,0x72);
+           }
+         }
+       }
+     }
+     return;
+  }
+
+  if(ModeNo<=0x13) {
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
+    	resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+    	crt2crtc = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  } else {
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
+    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+    	crt2crtc = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+  }
+
+  tempcx = SiS_Pr->SiS_VBInfo;
+  tempax = (tempcx & 0x00FF) << 8;
+  tempbx = (tempcx & 0x00FF) | ((tempcx & 0x00FF) << 8);
+  tempbx &= 0x0410;
+  temp = (tempax & 0x0800) >> 8;
+  temp >>= 1;
+  temp |= (((tempbx & 0xFF00) >> 8) << 1);
+  temp |= ((tempbx & 0x00FF) >> 3);
+  temp ^= 0x0C;
+
+  PhasePoint  = SiS_Pr->SiS_PALPhase;
+  TimingPoint = SiS_Pr->SiS_PALTiming;
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {          /* PALPhase */
+    temp ^= 0x01;
+    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+      TimingPoint = SiS_Pr->SiS_HiTVSt2Timing;
+      if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+        if(modeflag & Charx8Dot) TimingPoint = SiS_Pr->SiS_HiTVSt1Timing;
+        else TimingPoint = SiS_Pr->SiS_HiTVTextTiming;
+      }
+    } else TimingPoint = SiS_Pr->SiS_HiTVExtTiming;
+  } else {
+#endif
+    if(SiS_Pr->SiS_VBInfo & SetPALTV){
+
+      TimingPoint = SiS_Pr->SiS_PALTiming;
+      PhasePoint  = SiS_Pr->SiS_PALPhase;
+
+      if( (SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS302B)) &&
+          ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+	    (SiS_Pr->SiS_SetFlag & TVSimuMode) ) ) {
+         PhasePoint = SiS_Pr->SiS_PALPhase2;
+      }
+
+    } else {
+
+        temp |= 0x10;
+	TimingPoint = SiS_Pr->SiS_NTSCTiming;
+	PhasePoint  = SiS_Pr->SiS_NTSCPhase;
+
+        if( (SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS302B)) &&
+	    ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+	      (SiS_Pr->SiS_SetFlag & TVSimuMode) ) ) {
+        	PhasePoint = SiS_Pr->SiS_NTSCPhase2;
+        }
+
+    }
+#ifdef oldHV
+  }
+#endif
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x00,temp);
+
+  temp = 0;
+  if((HwDeviceExtension->jChipType == SIS_630)||
+     (HwDeviceExtension->jChipType == SIS_730)) {
+     temp = 0x35;
+  }
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     temp = 0x38;
+  }
+  if(temp) {
+    if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+      if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x01) {
+          temp1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,temp);
+          if(temp1 & 0x40) {
+              	PhasePoint = SiS_Pr->SiS_PALMPhase;
+		if( (SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS302B)) &&
+		    ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+		      (SiS_Pr->SiS_SetFlag & TVSimuMode) ) ) {
+	           PhasePoint = SiS_Pr->SiS_PALMPhase2;
+		}
+	  }
+          if(temp1 & 0x80) {
+               	PhasePoint = SiS_Pr->SiS_PALNPhase;
+		if( (SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS302B)) &&
+		    ( (!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) ||
+		      (SiS_Pr->SiS_SetFlag & TVSimuMode) ) ) {
+	           PhasePoint = SiS_Pr->SiS_PALNPhase2;
+		}
+	  }
+      }
+    }
+  }
+
+#ifdef SIS315H
+  /* TW: Inserted from 650/301LV BIOS */
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {  /* 650/301LV : 301LV | 302LV */
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+           if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+              if((ModeNo == 0x4a) || (ModeNo == 0x38)) {
+	         PhasePoint = SiS_Pr->SiS_SpecialPhase;
+	      }
+           }
+        }
+     }
+  }
+#endif
+
+  for(i=0x31, j=0; i<=0x34; i++, j++){
+     SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,PhasePoint[j]);
+  }
+
+  for(i=0x01, j=0; i<=0x2D; i++, j++){
+     SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]);
+  }
+  for(i=0x39; i<=0x45; i++, j++){
+     SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,TimingPoint[j]);
+  }
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+    if(HwDeviceExtension->jChipType >= SIS_315H) {
+      if(!(SiS_Pr->SiS_ModeType & 0x07))
+        SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x3A,0x1F);
+    } else {
+      SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x3A,0x1F);
+    }
+  }
+
+  SiS_SetRegOR(SiS_Pr->SiS_Part2Port,0x0A,SiS_Pr->SiS_NewFlickerMode);
+
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x35,SiS_Pr->SiS_RY1COE);
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x36,SiS_Pr->SiS_RY2COE);
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x37,SiS_Pr->SiS_RY3COE);
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x38,SiS_Pr->SiS_RY4COE);
+
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) tempax = 950;
+  else {
+#endif
+    if(SiS_Pr->SiS_VBInfo & SetPALTV) tempax = 520;
+    else tempax = 440;
+#ifdef oldHV
+  }
+#endif
+
+  if( ( ( (!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) || (SiS_Pr->SiS_HiVision == 3) ) && (SiS_Pr->SiS_VDE <= tempax) ) ||
+      ( (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (SiS_Pr->SiS_HiVision != 3) &&
+        ( (SiS_Pr->SiS_VGAHDE == 1024) || ((SiS_Pr->SiS_VGAHDE != 1024) && (SiS_Pr->SiS_VDE <= tempax)) ) ) ) {
+
+     tempax -= SiS_Pr->SiS_VDE;
+     tempax >>= 2;
+     tempax = (tempax & 0x00FF) | ((tempax & 0x00FF) << 8);
+
+     temp = (tempax & 0xFF00) >> 8;
+     temp += (USHORT)TimingPoint[0];
+     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,temp);
+
+     temp = (tempax & 0xFF00) >> 8;
+     temp += (USHORT)TimingPoint[1];
+     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,temp);
+
+     if( (SiS_Pr->SiS_VBInfo & (SetCRT2ToTV - SetCRT2ToHiVisionTV)) &&
+        (SiS_Pr->SiS_HiVision != 3) &&
+        (SiS_Pr->SiS_VGAHDE >= 1024) ) {
+        if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+           SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x19);
+           SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x52);
+        } else {
+           if(HwDeviceExtension->jChipType >= SIS_315H) {
+             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x17);
+             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x1d);
+	   } else {
+             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x0b);
+             SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x11);
+	   }
+        }
+     }
+
+  }
+
+  tempcx = SiS_Pr->SiS_HT;
+
+  /* TW: Inserted from 650/301LVx 1.10.6s */
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+      if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) {
+      	   tempcx >>= 1;
+      }
+  }
+
+  tempcx--;
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        tempcx--;
+  }
+  temp = tempcx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1B,temp);
+  temp = (tempcx & 0xFF00) >> 8;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0xF0,temp);
+
+  tempcx++;
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        tempcx++;
+  }
+  tempcx >>= 1;
+
+  push1 = tempcx;
+
+  tempcx += 7;
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV)  tempcx -= 4;
+#endif
+  temp = (tempcx & 0x00FF) << 4;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x22,0x0F,temp);
+
+  tempbx = TimingPoint[j] | ((TimingPoint[j+1]) << 8);
+  tempbx += tempcx;
+
+  push2 = tempbx;
+
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x24,temp);
+  temp = ((tempbx & 0xFF00) >> 8) << 4;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0F,temp);
+
+  tempbx = push2;
+
+  tempbx += 8;
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+    tempbx -= 4;
+    tempcx = tempbx;
+  }
+#endif
+  temp = (tempbx & 0x00FF) << 4;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x29,0x0F,temp);
+
+  j += 2;
+  tempcx += ((TimingPoint[j] | ((TimingPoint[j+1]) << 8)));
+  temp = tempcx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x27,temp);
+  temp = ((tempcx & 0xFF00) >> 8) << 4;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x28,0x0F,temp);
+
+  tempcx += 8;
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV)  tempcx -= 4; 
+#endif
+  temp = (tempcx & 0xFF) << 4;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2A,0x0F,temp);
+
+  tempcx = push1;
+
+  j += 2;
+  tempcx -= (TimingPoint[j] | ((TimingPoint[j+1]) << 8));
+  temp = (tempcx & 0x00FF) << 4;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2D,0x0F,temp);
+
+  tempcx -= 11;
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) {
+    tempax = SiS_GetVGAHT2(SiS_Pr) - 1;
+    tempcx = tempax;
+  }
+  temp = tempcx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2E,temp);
+
+  tempbx = SiS_Pr->SiS_VDE;
+  if(SiS_Pr->SiS_VGAVDE == 360) tempbx = 746;
+  if(SiS_Pr->SiS_VGAVDE == 375) tempbx = 746;
+  if(SiS_Pr->SiS_VGAVDE == 405) tempbx = 853;
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+  	if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) tempbx >>= 1;
+  } else {
+	if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (!(SiS_Pr->SiS_HiVision & 0x03))) {
+	   tempbx >>= 1;
+	   if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+	      if(ModeNo <= 0x13) {
+	         if(crt2crtc == 1) {
+	            tempbx++;
+                 }
+	      }
+	   } else {
+              if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+	         if(crt2crtc == 4)   /* TW: BIOS calls GetRatePtrCRT2 here - does not make sense */
+                    if(SiS_Pr->SiS_ModeType <= 3) tempbx++;
+	      }
+	   }
+        }
+  }
+  tempbx -= 2;
+  temp = tempbx & 0x00FF;
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+      if(ModeNo == 0x2f) temp++;
+    }
+  }
+#endif
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2F,temp);
+
+  tempax = (tempcx & 0xFF00) | (tempax & 0x00FF);
+  tempbx = ((tempbx & 0xFF00) << 6) | (tempbx & 0x00FF);
+  tempax |= (tempbx & 0xFF00);
+#ifdef oldHV
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV)) {
+#endif
+    if(HwDeviceExtension->jChipType < SIS_315H) {
+      if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToSCART)) {		/* TW: New from 630/301B (II) BIOS */
+         tempax |= 0x1000;
+         if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToSVIDEO))  tempax |= 0x2000;
+      }
+    } else {
+      tempax |= 0x1000;
+      if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToSVIDEO))  tempax |= 0x2000;
+    }
+#ifdef oldHV
+  }
+#endif
+  temp = (tempax & 0xFF00) >> 8;
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x30,temp);
+
+  /* TW: Inserted from 650/301LVx 1.10.6s */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+     if( (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) ||
+         (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) ) {
+         SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x10,0x60);
+     }
+  }
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {      /* tv gatingno */
+    tempbx = SiS_Pr->SiS_VDE;
+    if((SiS_Pr->SiS_VBInfo & SetCRT2ToTV) && (!(SiS_Pr->SiS_HiVision & 0x03))) {
+         tempbx >>= 1;
+    }
+    tempbx -= 3;
+    tempbx &= 0x03ff;
+    temp = ((tempbx & 0xFF00) >> 8) << 5;
+    temp |= 0x18;
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x46,temp);
+    temp = tempbx & 0x00FF;
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x47,temp);
+    if(HwDeviceExtension->jChipType >= SIS_315H) {	/* TW: Inserted from 650/301LVx 1.10.6s */
+       tempax = 0;
+       if(SiS_Pr->SiS_HiVision & 0x07) {
+          if(SiS_Pr->SiS_HiVision & 0x04) tempax = 0x1000;
+          else if(SiS_Pr->SiS_HiVision & 0x01) tempax = 0x3000;
+	  else tempax = 0x5000;
+       }
+       temp = (tempax & 0xFF00) >> 8;
+       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x4d,temp);
+    }
+  }
+
+  tempbx &= 0x00FF;
+  if(!(modeflag & HalfDCLK)) {
+    tempcx = SiS_Pr->SiS_VGAHDE;
+    if(tempcx >= SiS_Pr->SiS_HDE){
+      tempbx |= 0x2000;
+      tempax &= 0x00FF;
+    }
+  }
+
+  tempcx = 0x0101;
+  if(SiS_Pr->SiS_VBInfo & (SetPALTV | SetCRT2ToTV)) {   /*301b- TW: BIOS BUG? */
+    if(!(SiS_Pr->SiS_HiVision & 0x03)) {
+      if(SiS_Pr->SiS_VGAHDE >= 1024) {
+        if(!(modeflag & HalfDCLK)) {   /* TW: This check not in 630/301B */
+          tempcx = 0x1920;
+          if(SiS_Pr->SiS_VGAHDE >= 1280) {
+            tempcx = 0x1420;
+            tempbx &= 0xDFFF;
+          }
+        }
+      }
+    }
+  }
+
+  if(!(tempbx & 0x2000)){
+
+    if(modeflag & HalfDCLK) {
+         tempcx = (tempcx & 0xFF00) | (((tempcx & 0x00FF) << 1) & 0xff);
+    }
+    push1 = tempbx;
+    tempeax = SiS_Pr->SiS_VGAHDE;
+    tempebx = (tempcx & 0xFF00) >> 8;
+    longtemp = tempeax * tempebx;
+    tempecx = tempcx & 0x00FF;
+    longtemp /= tempecx;
+    longtemp <<= 0x0d;
+    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+     	longtemp <<= 3;
+    }
+    tempecx = SiS_Pr->SiS_HDE;
+    temp2 = longtemp % tempecx;
+    tempeax = longtemp / tempecx;
+    if(temp2 != 0) tempeax++;
+    tempax = (USHORT)tempeax;
+    tempbx = push1;
+    tempcx = (tempcx & 0xff00) | (((tempax & 0xFF00) >> 8) >> 5);
+    tempbx |= (tempax & 0x1F00);
+    tempax = ((tempax & 0x00FF) << 8) | (tempax & 0x00FF);
+  }
+
+  temp = (tempax & 0xFF00) >> 8;
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x44,temp);
+  temp = (tempbx & 0xFF00) >> 8;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x45,0xC0,temp);
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+       temp = tempcx & 0x00FF;
+       if(tempbx & 0x2000) temp = 0;
+       temp |= 0x18;
+       SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x46,0xE0,temp);
+       if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+             tempbx = 0x0382;    /* TW: BIOS; Was 0x0364; */
+             tempcx = 0x007e;    /* TW: BIOS; Was 0x009c; */
+       } else {
+             tempbx = 0x0369;    /* TW: BIOS; Was 0x0346; */
+             tempcx = 0x0061;    /* TW: BIOS; Was 0x0078; */
+       }
+       temp = (tempbx & 0x00FF) ;
+       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x4B,temp);
+       temp = (tempcx & 0x00FF) ;
+       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x4C,temp);
+       tempbx &= 0x0300;
+       temp = (tempcx & 0xFF00) >> 8;
+       temp = (temp & 0x0003) << 2;
+       temp |= (tempbx >> 8);
+       if(HwDeviceExtension->jChipType < SIS_315H) {
+          SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x4D,temp);
+       } else {
+          SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x4D,0xF0,temp);
+       }
+
+       temp = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x43);
+       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x43,(USHORT)(temp - 3));
+  }
+
+  temp = 0;
+  if((HwDeviceExtension->jChipType == SIS_630)||
+     (HwDeviceExtension->jChipType == SIS_730)) {
+     temp = 0x35;
+  } else if(HwDeviceExtension->jChipType >= SIS_315H) {
+     temp = 0x38;
+  }
+  if(temp) {
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+          if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x01) {
+               if(SiS_GetReg1(SiS_Pr->SiS_P3d4,temp) & 0x40) {
+                     SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x00,0xEF);
+                     temp = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x01);
+                     SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,temp - 1);
+               }
+          }
+      }
+  }
+
+
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+    if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x0B,0x00);
+    }
+  }
+#endif
+
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)  return;
+  } else {
+     /* TW: !!! The following is a duplicate, done for LCDA as well (see above) */
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+       if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {    /* 650/301LV: (VB_SIS301LV | VB_SIS302LV)) */
+         if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+           if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+             if((ModeNo == 0x4a) || (ModeNo == 0x38)) {
+               SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1c,0xa7);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1d,0x07);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1e,0xf2);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1f,0x6e);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x20,0x17);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x21,0x8b);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x22,0x73);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x23,0x53);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x24,0x13);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x25,0x40);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x26,0x34);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x27,0xf4);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x28,0x63);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x29,0xbb);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2a,0xcc);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2b,0x7a);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2c,0x58);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2d,0xe4);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2e,0x73);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,0xda);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x30,0x13);
+	       SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x43,0x72);
+	     }
+           }
+         }
+       }
+       return;
+     }
+  }
+
+  /* TW: From here: Part2 LCD setup */
+
+  tempbx = SiS_Pr->SiS_HDE;
+  /* TW: Inserted from 650/301LVx 1.10.6s */
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+      if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) tempbx >>= 1;
+  }
+  tempbx--;			         /* RHACTE=HDE-1 */
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2C,temp);
+  temp = (tempbx & 0xFF00) >> 8;
+  temp <<= 4;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x2B,0x0F,temp);
+
+  temp = 0x01;
+  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+    if(SiS_Pr->SiS_ModeType == ModeEGA) {
+      if(SiS_Pr->SiS_VGAHDE >= 1024) {
+        temp = 0x02;
+	if(HwDeviceExtension->jChipType >= SIS_315H) {
+           if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
+             temp = 0x01;
+	   }
+	}
+      }
+    }
+  }
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x0B,temp);
+
+  tempbx = SiS_Pr->SiS_VDE;         		/* RTVACTEO=(VDE-1)&0xFF */
+  push1 = tempbx;
+
+  tempbx--;
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x03,temp);
+  temp = ((tempbx & 0xFF00) >> 8) & 0x07;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0C,0xF8,temp);
+
+  tempcx = SiS_Pr->SiS_VT;
+  push2 = tempcx;
+
+  tempcx--;
+  temp = tempcx & 0x00FF;  			 /* RVTVT=VT-1 */
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x19,temp);
+
+  temp = (tempcx & 0xFF00) >> 8;
+  temp <<= 5;
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp |= 0x10;
+    else {
+      if(SiS_Pr->SiS_LCDInfo & LCDSync)       /* TW: 630/301 BIOS checks this */
+         temp |= 0x10;
     }
+  } else {
+      /* TW: Inserted from 630/301LVx 1.10.6s */
+      if(SiS_Pr->SiS_LCDInfo & LCDRGB18Bit) {
+         if(SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x01) {
+      	    temp |= 0x10;
+	 }
+      }
+  }
+
+  /* 630/301 does not do all this */
+  if((SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+      if(HwDeviceExtension->jChipType >= SIS_315H) {
+        /* TW: Inserted from 650/301LVx 1.10.6s */
+        temp |= (SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37) >> 6);
+      } else {
+        tempbx = (tempbx & 0xFF00) | (SiS_Pr->SiS_LCDInfo & 0x0FF);
+        if(tempbx & LCDSync) {
+          tempbx &= (0xFF00 | LCDSyncBit);
+          tempbx = (tempbx & 0xFF00) | ((tempbx & 0x00FF) >> LCDSyncShift);
+          temp |= (tempbx & 0x00FF);
+        }
+      }
   }
+  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1A,temp);
+
+  SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x09,0xF0);
+  SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x0A,0xF0);
+
+  SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x17,0xFB);
+  SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x18,0xDF);
+
+  if(HwDeviceExtension->jChipType >= SIS_315H) {   /* ------------- 310 series ------------ */
+
+      /* TW: Inserted this entire section from 650/301LV(x) BIOS */
+
+      SiS_GetCRT2Part2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                         &CRT2Index,&resindex);
+
+      switch(CRT2Index) {
+        case Panel_1024x768      : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_1;  break;  /* "Normal" */
+        case Panel_1280x1024     : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1280x1024_1; break;
+	case Panel_1400x1050     : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1400x1050_1; break;
+	case Panel_1600x1200     : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1600x1200_1; break;
+        case Panel_1024x768 + 16 : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_2;  break;  /* Non-Expanding */
+        case Panel_1280x1024 + 16: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1280x1024_2; break;
+	case Panel_1400x1050 + 16: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1400x1050_2; break;
+	case Panel_1600x1200 + 16: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1600x1200_2; break;
+        case Panel_1024x768 + 32 : CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_3;  break;  /* VESA Timing */
+        case Panel_1280x1024 + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1280x1024_3; break;
+	case Panel_1400x1050 + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1400x1050_3; break;
+	case Panel_1600x1200 + 32: CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1600x1200_3; break;
+	default:                   CRT2Part2Ptr = SiS_Pr->SiS_CRT2Part2_1024x768_3;  break;
+      }
+
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,(CRT2Part2Ptr+resindex)->CR[0]);
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x02,0x80,(CRT2Part2Ptr+resindex)->CR[1]);
+      for(i = 2, j = 0x04; j <= 0x06; i++, j++ ) {
+        SiS_SetReg1(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]);
+      }
+      for(j = 0x1c; j <= 0x1d; i++, j++ ) {
+        SiS_SetReg1(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]);
+      }
+      for(j = 0x1f; j <= 0x21; i++, j++ ) {
+        SiS_SetReg1(SiS_Pr->SiS_Part2Port,j,(CRT2Part2Ptr+resindex)->CR[i]);
+      }
+      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x23,(CRT2Part2Ptr+resindex)->CR[10]);
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0x0f,(CRT2Part2Ptr+resindex)->CR[11]);
+
+      if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+        if(SiS_Pr->SiS_VGAVDE == 0x20d) {
+	  temp = 0xc3;
+	  if(SiS_Pr->SiS_ModeType <= ModeVGA) {
+	     temp++;
+	     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp += 2;
+	  }
+	  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,temp);
+	  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x30,0xb3);
+	}
+	if(SiS_Pr->SiS_VGAVDE == 0x1a4) {
+	  temp = 0x4d;
+	  if(SiS_Pr->SiS_ModeType <= ModeVGA) {
+	     temp++;
+	     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) temp++;
+	  }
+	  SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,temp);
+	}
+     }
+
+     /* TW: Inserted from 650/301LVx 1.10.6s: */
+     /* !!! This is a duplicate, done for LCDA as well - see above */
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+	   SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1a,0xfc,0x03);
+	   temp = 1;
+	   if(ModeNo<=0x13) temp = 3;
+	   SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x0b,temp);
+	}
+     }
+
+  } else {   /* ------------- 300 series ----------- */
+
+    tempcx++;
+    tempbx = 768;
+    if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1024x768) {
+      tempbx = 1024;
+      if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024) {
+         tempbx = 1200;
+         if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1600x1200) {
+            if(tempbx != SiS_Pr->SiS_VDE) {
+               tempbx = 960;
+            }
+         }
+      }
+    }
+    if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) {
+      tempbx = SiS_Pr->SiS_VDE - 1;
+      tempcx--;
+    }
+    tempax = 1;
+    if(!(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)) {
+      if(tempbx != SiS_Pr->SiS_VDE){
+        tempax = tempbx;
+        if(tempax < SiS_Pr->SiS_VDE) {
+          tempax = 0;
+          tempcx = 0;
+        } else {
+          tempax -= SiS_Pr->SiS_VDE;
+        }
+        tempax >>= 1;
+      }
+      tempcx -= tempax; /* lcdvdes */
+      tempbx -= tempax; /* lcdvdee */
+    } else {
+      tempax >>= 1;
+      tempcx -= tempax; /* lcdvdes */
+      tempbx -= tempax; /* lcdvdee */
+    }
+
+    temp = tempcx & 0x00FF;   				/* RVEQ1EQ=lcdvdes */
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x05,temp);
+    temp = tempbx & 0x00FF;   				/* RVEQ2EQ=lcdvdee */
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x06,temp);
+
+    temp = ((tempbx & 0xFF00) >> 8 ) << 3;
+    temp |= ((tempcx & 0xFF00) >> 8);
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,temp);
+
+    tempbx = push2;
+    tempax = push1;
+    tempcx = tempbx;
+    tempcx -= tempax;
+    tempcx >>= 4;
+    tempbx += tempax;
+    tempbx >>= 1;
+    if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)  tempbx -= 10;
+
+    temp = tempbx & 0x00FF;   				/* RTVACTEE=lcdvrs */
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x04,temp);
+
+    temp = ((tempbx & 0xFF00) >> 8) << 4;
+    tempbx += (tempcx + 1);
+    temp |= (tempbx & 0x000F);
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,temp);
+
+    /* TW: Code from 630/301B (I+II) BIOS */
+
+    if( ( ( (HwDeviceExtension->jChipType == SIS_630) ||
+            (HwDeviceExtension->jChipType == SIS_730) ) &&
+          (HwDeviceExtension->jChipRevision > 2) )  &&
+        (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) &&
+        (!(SiS_Pr->SiS_SetFlag & LCDVESATiming))  &&
+        (!(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)) ) {
+            if(ModeNo == 0x13) {
+              SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x04,0xB9);
+              SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x05,0xCC);
+              SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x06,0xA6);
+            } else {
+              if((crt2crtc & 0x3F) == 4) {
+                SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x2B);
+                SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x13);
+                SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x04,0xE5);
+                SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x05,0x08);
+                SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x06,0xE2);
+              }
+            }
+    }
+
+    /* TW: Inserted missing code from 630/301B BIOS: (II: 3258) */
+
+    if(SiS_Pr->SiS_LCDTypeInfo == 0x0c) {
+         crt2crtc &= 0x1f;
+         tempcx = 0;
+         if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) {
+           if (SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+              tempcx += 7;
+           }
+         }
+         tempcx += crt2crtc;
+         if (crt2crtc >= 4) {
+           SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x06,0xff);
+         }
+
+         if(!(SiS_Pr->SiS_VBInfo & SetNotSimuMode)) {
+           if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+             if(crt2crtc == 4) {
+                SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x01,0x28);
+             }
+           }
+         }
+         SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x02,0x18);
+         SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x04,atable[tempcx]);
+    }
+
+    tempcx = (SiS_Pr->SiS_HT - SiS_Pr->SiS_HDE) >> 2;     /* (HT-HDE)>>2     */
+    tempbx = SiS_Pr->SiS_HDE + 7;            		  /* lcdhdee         */
+    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+         tempbx += 2;
+    }
+    push1 = tempbx;
+    temp = tempbx & 0x00FF;    			          /* RHEQPLE=lcdhdee */
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x23,temp);
+    temp = (tempbx & 0xFF00) >> 8;
+    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x25,0xF0,temp);
+
+    temp = 7;
+    if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+         temp += 2;
+    }
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1F,temp);  	  /* RHBLKE=lcdhdes */
+
+    SiS_SetRegAND(SiS_Pr->SiS_Part2Port,0x20,0x0F);
+
+    tempbx += tempcx;
+    push2 = tempbx;
+    temp = tempbx & 0xFF;            		          /* RHBURSTS=lcdhrs */
+    if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+      if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) {
+        if(SiS_Pr->SiS_HDE == 1280)  temp = 0x47;
+      }
+    }
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x1C,temp);
+    temp = ((tempbx & 0xFF00) >> 8) << 4;
+    SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x1D,0x0F,temp);
+
+    tempbx = push2;
+    tempcx <<= 1;
+    tempbx += tempcx;
+    temp = tempbx & 0x00FF;            		          /* RHSYEXP2S=lcdhre */
+    SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x21,temp);
+
+    if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) {
+      if(SiS_Pr->SiS_VGAVDE == 525) {
+        if(SiS_Pr->SiS_ModeType <= ModeVGA)
+    	   temp=0xC6;
+        else
+       	   temp=0xC3;
+        SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,temp);
+        SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x30,0xB3);
+      } else if(SiS_Pr->SiS_VGAVDE == 420) {
+        if(SiS_Pr->SiS_ModeType <= ModeVGA)
+	   temp=0x4F;
+        else
+       	   temp=0x4D;   /* 650: 4e */
+        SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x2f,temp);
+      }
+    }
+
+  } /* HwDeviceExtension */
+}
+
+USHORT
+SiS_GetVGAHT2(SiS_Private *SiS_Pr)
+{
+  ULONG tempax,tempbx;
+
+  tempbx = ((SiS_Pr->SiS_VGAVT - SiS_Pr->SiS_VGAVDE) * SiS_Pr->SiS_RVBHCMAX) & 0xFFFF;
+  tempax = (SiS_Pr->SiS_VT - SiS_Pr->SiS_VDE) * SiS_Pr->SiS_RVBHCFACT;
+  tempax = (tempax * SiS_Pr->SiS_HT) / tempbx;
+  return((USHORT) tempax);
 }
 
+/* TW: Set 301 Macrovision(tm) registers */
+/* TW: Double-Checked against 650/301LV, 650/301LVx and 630/301B BIOS */
 void
-SiS_VBLongWait()
+SiS_SetGroup3(SiS_Private *SiS_Pr, USHORT  BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+              USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT tempal,temp,i,j;
+  USHORT temp;
+#ifdef oldHV
+  USHORT i;
+  const UCHAR  *tempdi;
+#endif
+  USHORT modeflag;
 
-  if(!(SiS_VBInfo&SetCRT2ToTV)) {
-    temp=0;
-    for(i=0;i<3;i++) {
-      for(j=0;j<100;j++) {
-        tempal=SiS_GetReg2(SiS_P3da);
-        if(temp&0x01) {        /* VBWaitMode2  */
-          if((tempal&0x08)) {
-            continue;
-          }
-          if(!(tempal&0x08)) {
-            break;
-          }
-        } else {                 /* VBWaitMode1  */
-          if(!(tempal&0x08)) {
-            continue;
-          }
-          if((tempal&0x08)) {
-            break;
+  /* TW: Inserted from 650/301LVx 1.10.6s */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) return;
+
+  if(ModeNo<=0x13)
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  else
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+
+  SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x00,0x00);
+
+  if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+    SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x13,0xFA);
+    SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x14,0xC8);
+  } else {
+    if(HwDeviceExtension->jChipType >= SIS_315H) {
+      SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x13,0xF5);
+      SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x14,0xB7);
+    } else {
+      SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x13,0xF6);
+      SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x14,0xBf);
+    }
+  }
+
+  temp = 0;
+  if((HwDeviceExtension->jChipType == SIS_630)||
+     (HwDeviceExtension->jChipType == SIS_730)) {
+     temp = 0x35;
+  } else if(HwDeviceExtension->jChipType >= SIS_315H) {
+     temp = 0x38;
+  }
+  if(temp) {
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+          if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x01) {
+              if(SiS_GetReg1(SiS_Pr->SiS_P3d4,temp) & 0x40){
+                  SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x13,0xFA);
+                  SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x14,0xC8);
+                  SiS_SetReg1(SiS_Pr->SiS_Part3Port,0x3D,0xA8);
+              }
           }
-        }
       }
-      temp=temp^0x01;
+  }
+
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+    tempdi = SiS_Pr->SiS_HiTVGroup3Data;
+    if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+      tempdi = SiS_Pr->SiS_HiTVGroup3Simu;
+      if(!(modeflag & Charx8Dot)) {
+        tempdi = SiS_Pr->SiS_HiTVGroup3Text;
+      }
+    }
+    for(i=0; i<=0x3E; i++){
+       SiS_SetReg1(SiS_Pr->SiS_Part3Port,i,tempdi[i]);
     }
-  } else {
-    SiS_LongWait();
   }
+#endif
+
   return;
 }
 
-BOOLEAN
-SiS_WaitVBRetrace(USHORT  BaseAddr)
+/* TW: Set 301 VGA2 registers */
+/* TW: Double-Checked against 650/301LV(x) and 630/301B BIOS */
+void
+SiS_SetGroup4(SiS_Private *SiS_Pr, USHORT  BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+              USHORT ModeIdIndex,USHORT RefreshRateTableIndex,
+	      PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT temp;
+  USHORT tempax,tempcx,tempbx,modeflag,temp,temp2;
+  ULONG tempebx,tempeax,templong;
 
-return 0;
+  if(ModeNo<=0x13)
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  else
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
-  temp=SiS_GetReg1(SiS_Part1Port,0x00); /* FUNCTION CTRL */
-  if(!(temp&0x80)){
-    return 0;
+  /* TW: From 650/301LVx 1.10.6s BIOS */
+  if(SiS_Pr->SiS_VBType & (VB_SIS30xLV | VB_SIS30xNEW)) {
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+          SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x24,0x0e);
+      }
   }
 
-  for(temp=0;temp==0;){
-     temp=SiS_GetReg1(SiS_Part1Port,0x25);
-     temp=temp&0x01;
-  }
-  for(;temp>0;){
-     temp=SiS_GetReg1(SiS_Part1Port,0x25);
-     temp=temp&0x01;
+  if(SiS_Pr->SiS_VBType & VB_SIS30xNEW) {
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+          SiS_SetRegAND(SiS_Pr->SiS_Part4Port,0x10,0x9f);
+      }
   }
-  return 1;
+
+  /* TW: From 650/301LV BIOS */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+  	/* TW: This is a duplicate; done at the end, too */
+	if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) {
+		SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c);
+	}
+	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x2a,0x00);
+	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
+	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
+   	return;
+  }
+
+  temp = SiS_Pr->SiS_RVBHCFACT;
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x13,temp);
+
+  tempbx = SiS_Pr->SiS_RVBHCMAX;
+  temp = tempbx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x14,temp);
+
+  temp2 = (((tempbx & 0xFF00) >> 8) << 7) & 0x00ff;
+
+  tempcx = SiS_Pr->SiS_VGAHT - 1;
+  temp = tempcx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x16,temp);
+
+  temp = (((tempcx & 0xFF00) >> 8) << 3) & 0x00ff;
+  temp2 |= temp;
+
+  tempcx = SiS_Pr->SiS_VGAVT - 1;
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV))  tempcx -= 5;
+
+  temp = tempcx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x17,temp);
+
+  temp = temp2 | ((tempcx & 0xFF00) >> 8);
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x15,temp);
+
+  tempcx = SiS_Pr->SiS_VBInfo;
+  tempbx = SiS_Pr->SiS_VGAHDE;
+  if(modeflag & HalfDCLK)  tempbx >>= 1;
+
+  /* TW: New for 650/301LV and 630/301B */
+  temp = 0xA0;
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+       temp = 0;
+       if(tempbx > 800) {
+          temp = 0xA0;
+          if(tempbx != 1024) {
+             temp = 0xC0;
+             if(tempbx != 1280) temp = 0;
+	  }
+       }
+  } else
+#endif
+    if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+      if(tempbx <= 800) {
+         temp = 0x80;
+	 if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD){
+            temp = 0;
+            if(tempbx > 800) temp = 0x60;
+         }
+      }
+  } else {
+      temp = 0x80;
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD){
+            temp = 0;
+            if(tempbx > 800) temp = 0x60;
+      }
+  }
+  if(SiS_Pr->SiS_HiVision & 0x03) {
+        temp = 0;
+	if(SiS_Pr->SiS_VGAHDE == 1024) temp = 0x20;
+  }
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+  	if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) temp = 0;
+  }
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301) {
+     if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1280x1024)
+        temp |= 0x0A;
+  }
+
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x0E,0x10,temp);
+
+  tempebx = SiS_Pr->SiS_VDE;
+
+#ifdef oldHV
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) {
+     if(!(temp & 0xE0)) tempebx >>=1;
+  }
+#endif
+
+  tempcx = SiS_Pr->SiS_RVBHRS;
+  temp = tempcx & 0x00FF;
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x18,temp);
+
+  tempeax = SiS_Pr->SiS_VGAVDE;
+  tempcx |= 0x4000;
+  if(tempeax <= tempebx){
+    tempcx ^= 0x4000;
+  } else {
+    tempeax -= tempebx;
+  }
+
+  templong = (tempeax * 256 * 1024) % tempebx;
+  tempeax = (tempeax * 256 * 1024) / tempebx;
+  tempebx = tempeax;
+  if(templong != 0) tempebx++;
+
+  temp = (USHORT)(tempebx & 0x000000FF);
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x1B,temp);
+  temp = (USHORT)((tempebx & 0x0000FF00) >> 8);
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x1A,temp);
+
+  tempbx = (USHORT)(tempebx >> 16);
+  temp = tempbx & 0x00FF;
+  temp <<= 4;
+  temp |= ((tempcx & 0xFF00) >> 8);
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x19,temp);
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+
+         SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x1C,0x28);
+	 tempbx = 0;
+         tempax = SiS_Pr->SiS_VGAHDE;
+         if(modeflag & HalfDCLK) tempax >>= 1;
+         if((SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) || (SiS_Pr->SiS_HiVision & 0x03)) {
+	     if(HwDeviceExtension->jChipType >= SIS_315H) {
+	         if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) tempax >>= 1;
+		 else if(tempax > 800) tempax -= 800;
+	     } else {
+                 if(tempax > 800) tempax -= 800;
+             }
+         }
+
+         if((SiS_Pr->SiS_VBInfo & (SetCRT2ToTV | SetPALTV)) && (!(SiS_Pr->SiS_HiVision & 0x03))) {
+           if(tempax > 800) {
+	      tempbx = 8;
+              if(tempax == 1024)
+	        tempax *= 25;
+              else
+	        tempax *= 20;
+
+	      temp = tempax % 32;
+	      tempax /= 32;
+	      tempax--;
+	      if (temp!=0) tempax++;
+           }
+         }
+	 tempax--;
+         temp = (tempax & 0xFF00) >> 8;
+         temp &= 0x03;
+	 SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x1D,tempax & 0x00FF);
+	 temp <<= 4;
+	 temp |= tempbx;
+	 SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x1E,temp);
+
+         temp = 0x0036;
+         if((SiS_Pr->SiS_VBInfo & (SetCRT2ToTV - SetCRT2ToHiVisionTV)) &&
+	                               (!(SiS_Pr->SiS_HiVision & 0x03))) {
+		temp |= 0x01;
+	        if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+	          if(!(SiS_Pr->SiS_SetFlag & TVSimuMode))
+  	                  temp &= 0xFE;
+		}
+         }
+         SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x1F,0xC0,temp);
+
+	 tempbx = SiS_Pr->SiS_HT;
+	 if(HwDeviceExtension->jChipType >= SIS_315H) {
+	 	if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) tempbx >>= 1;
+	 }
+         tempbx >>= 1;
+	 tempbx -= 2;
+         temp = ((tempbx & 0x0700) >> 8) << 3;
+         SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x21,0xC0,temp);
+         temp = tempbx & 0x00FF;
+         SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x22,temp);
+         if( (SiS_Pr->SiS_VBType & (VB_SIS30xLV | VB_SIS30xNEW)) &&
+	                        (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) ) {
+             SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x24,0x0e);
+	 }
+
+         /* TW: 650 BIOS does this for all bridge types - assumingly wrong */
+	 if(HwDeviceExtension->jChipType >= SIS_315H) {
+             /* TW: This is a duplicate; done for LCDA as well (see above) */
+	     if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x39) & 0x04) {
+		SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x27,0x2c);
+	     }
+	     SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x2a,0x00);
+	     SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
+	     SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
+         }
+
+  }  /* 301B */
+
+  SiS_SetCRT2VCLK(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,
+                  RefreshRateTableIndex,HwDeviceExtension);
 }
 
+/* TW: Double-Checked against 650/301LV(x) and 630/301B BIOS */
 void
-SiS_SetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR)
+SiS_SetCRT2VCLK(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                 USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT temp;
+  USHORT vclkindex;
+  USHORT tempah;
 
-  temp=SiS_GetReg1(Port,Index);     /* SiS_Part1Port index 02 */
-  temp=(temp&(DataAND))|DataOR;
-  SiS_SetReg1(Port,Index,temp);
+  vclkindex = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                              HwDeviceExtension);
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+   	tempah = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_A;
+   	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0A,tempah);
+   	tempah = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_B;
+   	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0B,tempah);
+	/* TW: New from 650/301LV, LVx BIOS */
+	if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {   /* 650/301LV: (VB_SIS301LV | VB_SIS302LV)) */
+           if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+	      if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+                 if((ModeNo == 0x4a) || (ModeNo == 0x38)) {
+		    SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0a,0x57);
+		    SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0b,0x46);
+		    SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x1f,0xf6);
+                 }
+              }
+           }
+	}
+  } else {	/* 650/301LVx does not do this anymore, jumps to SetRegs above - BUG? */
+   	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0A,0x01);
+   	tempah = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_B;
+   	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0B,tempah);
+   	tempah = SiS_Pr->SiS_VBVCLKData[vclkindex].Part4_A;
+   	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0A,tempah);
+  }
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x12,0x00);
+  tempah = 0x08;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
+    	tempah |= 0x20;
+  }
+  SiS_SetRegOR(SiS_Pr->SiS_Part4Port,0x12,tempah);
 }
 
-void
-SiS_SetRegAND(USHORT Port,USHORT Index,USHORT DataAND)
+/* TW: Double-checked against 650/LVDS (1.10.07), 630/301B/LVDS/LVDS+CH, 650/301LVx (1.10.6s) BIOS */
+USHORT
+SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT temp;
+  USHORT tempbx;
+#ifdef SIS300
+  const USHORT LCDXlat1VCLK300[4] = {VCLK65,   VCLK65,   VCLK65,   VCLK65};
+  const USHORT LCDXlat2VCLK300[4] = {VCLK108_2,VCLK108_2,VCLK108_2,VCLK108_2};
+  const USHORT LVDSXlat2VCLK300[4]= {VCLK65,   VCLK65,   VCLK65,   VCLK65};
+  const USHORT LVDSXlat3VCLK300[4]= {VCLK65,   VCLK65,   VCLK65,   VCLK65};
+#endif
+#ifdef SIS315H
+  const USHORT LCDXlat1VCLK310[4] = {VCLK65+2,   VCLK65+2,   VCLK65+2,   VCLK65+2};
+  const USHORT LCDXlat2VCLK310[4] = {VCLK108_2+5,VCLK108_2+5,VCLK108_2+5,VCLK108_2+5};
+  const USHORT LVDSXlat2VCLK310[4]= {VCLK65+2,   VCLK65+2,   VCLK65+2,   VCLK65+2};
+  const USHORT LVDSXlat3VCLK310[4]= {VCLK108_2+5,VCLK108_2+5,VCLK108_2+5,VCLK108_2+5};
+  			   /* {VCLK65+2,   VCLK65+2,   VCLK65+2,   VCLK65+2}; -  650/LVDS 1.10.07 */
+#endif
+  const USHORT LCDXlat0VCLK[4]    = {VCLK40, VCLK40, VCLK40, VCLK40};
+  const USHORT LVDSXlat1VCLK[4]   = {VCLK40, VCLK40, VCLK40, VCLK40};
+  USHORT CRT2Index,VCLKIndex=0;
+  USHORT modeflag,resinfo;
+  const UCHAR *CHTVVCLKPtr=NULL;
+  const USHORT *LCDXlatVCLK1 = NULL;
+  const USHORT *LCDXlatVCLK2 = NULL;
+  const USHORT *LVDSXlatVCLK2 = NULL;
+  const USHORT *LVDSXlatVCLK3 = NULL;
 
-  temp=SiS_GetReg1(Port,Index);     /* SiS_Part1Port index 02 */
-  temp=temp&DataAND;
-  SiS_SetReg1(Port,Index,temp);
+#ifdef SIS315H
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+		LCDXlatVCLK1 = LCDXlat1VCLK310;
+		LCDXlatVCLK2 = LCDXlat2VCLK310;
+		LVDSXlatVCLK2 = LVDSXlat2VCLK310;
+		LVDSXlatVCLK3 = LVDSXlat3VCLK310;
+  } else {
+#endif
+#ifdef SIS300
+		LCDXlatVCLK1 = LCDXlat1VCLK300;
+		LCDXlatVCLK2 = LCDXlat2VCLK300;
+		LVDSXlatVCLK2 = LVDSXlat2VCLK300;
+		LVDSXlatVCLK3 = LVDSXlat3VCLK300;
+#endif
+#ifdef SIS315H
+  }
+#endif
+
+  if(ModeNo<=0x13) {
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+    	resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+    	CRT2Index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  } else {
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+    	CRT2Index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+  }
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {    /* 301 */
+
+     if (SiS_Pr->SiS_SetFlag & ProgrammingCRT2) {
+
+        CRT2Index >>= 6;
+        if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)){      /*  LCD */
+            if(HwDeviceExtension->jChipType < SIS_315H) {
+	       /* TW: Inserted from 630/301B BIOS */
+	       if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600)
+	    		VCLKIndex = LCDXlat0VCLK[CRT2Index];
+	       else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)
+	    		VCLKIndex = LCDXlatVCLK1[CRT2Index];
+	       else
+	    		VCLKIndex = LCDXlatVCLK2[CRT2Index];
+	    } else {
+               /* TW: 650/301LV BIOS does not check expanding, 315 does  */
+	       if( (HwDeviceExtension->jChipType > SIS_315PRO) ||
+	           (!(SiS_Pr->SiS_LCDInfo & LCDNonExpanding)) ) {
+      	          if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x1024) {
+		     VCLKIndex = 0x19;
+		  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+		     VCLKIndex = 0x19;
+		  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
+		     VCLKIndex = 0x21;
+		  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+		     VCLKIndex = LCDXlatVCLK1[CRT2Index];
+                  } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1280x960) {
+		     VCLKIndex = 0x45;
+		     if(resinfo == 0x09) VCLKIndex++;
+	          } else {
+		     VCLKIndex = LCDXlatVCLK2[CRT2Index];
+      	          }
+	       } else {
+                   VCLKIndex = (UCHAR)SiS_GetReg2((USHORT)(SiS_Pr->SiS_P3ca+0x02));  /*  Port 3cch */
+         	   VCLKIndex = ((VCLKIndex >> 2) & 0x03);
+        	   if(ModeNo > 0x13) {
+          		VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+        	   }
+		   if(ModeNo <= 0x13) {  /* TW: Inserted from 315 BIOS */
+		      if(SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC == 1) VCLKIndex = 0x42;
+		   }
+		   if(VCLKIndex == 0) VCLKIndex = 0x41;
+		   if(VCLKIndex == 1) VCLKIndex = 0x43;
+		   if(VCLKIndex == 4) VCLKIndex = 0x44;
+	       }
+	    }
+        } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {                 /*  TV */
+        	if((SiS_Pr->SiS_IF_DEF_HiVision == 1) && (SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV)) {
+          		if(SiS_Pr->SiS_SetFlag & RPLLDIV2XO)  VCLKIndex = HiTVVCLKDIV2;
+     			else                                  VCLKIndex = HiTVVCLK;
+          		if(SiS_Pr->SiS_SetFlag & TVSimuMode) {
+            			if(modeflag & Charx8Dot)      VCLKIndex = HiTVSimuVCLK;
+            			else 			      VCLKIndex = HiTVTextVCLK;
+          		}
+        	} else {
+       			if(SiS_Pr->SiS_SetFlag & RPLLDIV2XO)  VCLKIndex = TVVCLKDIV2;
+            		else         		              VCLKIndex = TVVCLK;
+          	}
+		if(HwDeviceExtension->jChipType >= SIS_315H) {
+              		VCLKIndex += 25;
+  		}
+        } else {         					/* RAMDAC2 */
+        	VCLKIndex = (UCHAR)SiS_GetReg2((USHORT)(SiS_Pr->SiS_P3ca+0x02));
+        	VCLKIndex = ((VCLKIndex >> 2) & 0x03);
+        	if(ModeNo > 0x13) {
+          		VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+			if(HwDeviceExtension->jChipType < SIS_315H) {
+          			VCLKIndex &= 0x3f;
+				if( (HwDeviceExtension->jChipType == SIS_630) &&
+				    (HwDeviceExtension->jChipRevision >= 0x30)) {
+				     if(VCLKIndex == 0x14) VCLKIndex = 0x2e;
+				}
+			}
+        	}
+        }
+
+    } else {   /* If not programming CRT2 */
+
+        VCLKIndex = (UCHAR)SiS_GetReg2((USHORT)(SiS_Pr->SiS_P3ca+0x02));
+        VCLKIndex = ((VCLKIndex >> 2) & 0x03);
+        if(ModeNo > 0x13) {
+             VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+	     if(HwDeviceExtension->jChipType < SIS_315H) {
+                VCLKIndex &= 0x3f;
+		if( (HwDeviceExtension->jChipType != SIS_630) &&
+		    (HwDeviceExtension->jChipType != SIS_300) ) {
+		   if(VCLKIndex == 0x1b) VCLKIndex = 0x35;
+		}
+	     }
+        }
+    }
+
+  } else {       /*   LVDS  */
+
+    	VCLKIndex = CRT2Index;
+
+	if(SiS_Pr->SiS_SetFlag & ProgrammingCRT2) {  /* programming CRT2 */
+
+	   if( (SiS_Pr->SiS_IF_DEF_CH70xx != 0) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) ) {
+
+		VCLKIndex &= 0x1f;
+        	tempbx = 0;
+        	if(SiS_Pr->SiS_VBInfo & SetPALTV) tempbx += 2;
+        	if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx += 1;
+       		switch(tempbx) {
+          	   case 0: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUNTSC;  break;
+         	   case 1: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKONTSC;  break;
+                   case 2: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKUPAL;   break;
+                   case 3: CHTVVCLKPtr = SiS_Pr->SiS_CHTVVCLKOPAL;   break;
+        	}
+        	VCLKIndex = CHTVVCLKPtr[VCLKIndex];
+
+	   } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+
+	        VCLKIndex >>= 6;
+     		if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel800x600) ||
+		                   (SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel320x480))
+     			VCLKIndex = LVDSXlat1VCLK[VCLKIndex];
+     		else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768)
+     			VCLKIndex = LVDSXlatVCLK2[VCLKIndex];
+		else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600)
+                        VCLKIndex = LVDSXlatVCLK2[VCLKIndex];
+     		else    VCLKIndex = LVDSXlatVCLK3[VCLKIndex];
+
+	   } else {
+
+	        VCLKIndex = (UCHAR)SiS_GetReg2((USHORT)(SiS_Pr->SiS_P3ca+0x02));
+                VCLKIndex = ((VCLKIndex >> 2) & 0x03);
+                if(ModeNo > 0x13) {
+                     VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+		     if( (HwDeviceExtension->jChipType == SIS_630) &&
+                         (HwDeviceExtension->jChipRevision >= 0x30) ) {
+		         	if(VCLKIndex == 0x14) VCLKIndex = 0x2e;
+		     }
+	        }
+
+	   }
+
+	} else {  /* if not programming CRT2 */
+
+	   VCLKIndex = (UCHAR)SiS_GetReg2((USHORT)(SiS_Pr->SiS_P3ca+0x02));
+           VCLKIndex = ((VCLKIndex >> 2) & 0x03);
+           if(ModeNo > 0x13) {
+              VCLKIndex = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+              if(HwDeviceExtension->jChipType < SIS_315H) {
+	         if( (HwDeviceExtension->jChipType != SIS_630) &&
+		     (HwDeviceExtension->jChipType != SIS_300) ) {
+		        if(VCLKIndex == 0x1b) VCLKIndex = 0x35;
+	         }
+	      }
+	   }
+
+	}
+
+  }
+
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+    	VCLKIndex &= 0x3F;
+  }
+  return (VCLKIndex);
 }
 
-void SiS_SetRegOR(USHORT Port,USHORT Index,USHORT DataOR)
+/* TW: Set 301 Palette address port registers */
+/* TW: Checked against 650/301LV BIOS */
+void
+SiS_SetGroup5(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr,
+              UCHAR *ROMAddr, USHORT ModeNo, USHORT ModeIdIndex)
 {
-  USHORT temp;
 
-  temp=SiS_GetReg1(Port,Index);     /* SiS_Part1Port index 02 */
-  temp=temp|DataOR;
-  SiS_SetReg1(Port,Index,temp);
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)  return;
+
+  if(SiS_Pr->SiS_ModeType == ModeVGA){
+    if(!(SiS_Pr->SiS_VBInfo & (SetInSlaveMode | LoadDACFlag))){
+      SiS_EnableCRT2(SiS_Pr);
+      SiS_LoadDAC(SiS_Pr,HwDeviceExtension,ROMAddr,ModeNo,ModeIdIndex);
+    }
+  }
+  return;
 }
 
+/* TW: Checked against 650/LVDS and 630/301B BIOS */
 void
-SiS_SetGroup2(USHORT BaseAddr,ULONG ROMAddr, USHORT ModeNo,
-                   USHORT ModeIdIndex,USHORT RefreshRateTableIndex,
-		   PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_ModCRT1CRTC(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT i,j,tempax,tempbx,tempcx,temp,temp3;
-  USHORT push1,push2,temp1;
-  UCHAR *PhasePoint;
-  UCHAR *TimingPoint;
-  USHORT  modeflag,resinfo,crt2crtc,resindex,xres;
-  ULONG longtemp,tempeax,tempebx,temp2,tempecx;
-  USHORT  SiS_RY1COE=0,SiS_RY2COE=0,SiS_RY3COE=0,SiS_RY4COE=0;
-  USHORT  SiS_RY5COE=0,SiS_RY6COE=0,SiS_RY7COE=0;
+  USHORT temp,tempah,i,modeflag,j;
+  USHORT ResInfo,DisplayType;
+  const SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr=NULL;
 
-  if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-    	resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
-    	crt2crtc = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-    	resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-    	crt2crtc = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-  }
-
-  tempcx=SiS_VBInfo;
-  tempax=(tempcx&0x00FF)<<8;
-  tempbx=(tempcx&0x00FF)|((tempcx&0x00FF)<<8);
-  tempbx=tempbx&0x0410;
-  temp=(tempax&0x0800)>>8;
-  temp=temp>>1;
-  temp=temp|(((tempbx&0xFF00)>>8)<<1);
-  temp=temp|((tempbx&0x00FF)>>3);
-  temp=temp^0x0C;
-
-  PhasePoint = SiS_PALPhase;
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) {        /* PALPhase */
-    temp=temp^0x01;
-    if(SiS_VBInfo&SetInSlaveMode) {
-      TimingPoint = SiS_HiTVSt2Timing;
-      if(SiS_SetFlag&TVSimuMode) {
-        if(modeflag&Charx8Dot) TimingPoint = SiS_HiTVSt1Timing;
-        else TimingPoint = SiS_HiTVTextTiming;
-      }
-    } else TimingPoint = SiS_HiTVExtTiming;
-  } else {
-    if(SiS_VBInfo&SetPALTV){
-      if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-         PhasePoint = SiS_PALPhase2;              /* PALPhase */
-      else 
-         PhasePoint = SiS_PALPhase;  
-     
-         TimingPoint = SiS_PALTiming;
-    } else {
-        temp=temp|0x10;
-        if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-        	PhasePoint = SiS_NTSCPhase2;             /* PALPhase */
-        else
-        	PhasePoint = SiS_NTSCPhase;
-      
-        TimingPoint = SiS_NTSCTiming;
-    }
+  if(ModeNo <= 0x13) {
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  } else {
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
   }
-  SiS_SetReg1(SiS_Part2Port,0x00,temp);
 
-#ifdef SIS300
-  /*add PALMN*/
-  if((HwDeviceExtension->jChipType==SIS_630)||
-     (HwDeviceExtension->jChipType==SIS_730)) {
-     	if(SiS_VBInfo&SetCRT2ToTV) {
-             temp=SiS_GetReg1(SiS_P3d4,0x31);   
-             temp=temp&0x01; 
-             if(temp) {
-                  temp1=SiS_GetReg1(SiS_P3d4,0x35);        
-                  temp1=temp1&0x40; 
-                  if(temp1)
-                     	PhasePoint = SiS_PALMPhase;
-                  temp1=SiS_GetReg1(SiS_P3d4,0x35);        
-                  temp1=temp1&0x80;
-                  if(temp1)
-                     	PhasePoint = SiS_PALNPhase;
-             }
-        }
+  temp = SiS_GetLVDSCRT1Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                            &ResInfo,&DisplayType);
+
+  if(temp == 0) return;
+
+  /* TW: Inserted from 630/LVDS BIOS */
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+     if(SiS_Pr->SiS_SetFlag & CRT2IsVGA) return;
   }
-  /*end add*/
-#endif
 
-#ifdef SIS315H
-  /*add PALMN*/
-  if ( (HwDeviceExtension->jChipType==SIS_315H)||
-       (HwDeviceExtension->jChipType==SIS_315PRO)||
-       (HwDeviceExtension->jChipType==SIS_550) ||
-       (HwDeviceExtension->jChipType==SIS_640) ||
-       (HwDeviceExtension->jChipType==SIS_740) ||
-       (HwDeviceExtension->jChipType==SIS_650)) {
-           if(SiS_VBInfo&SetCRT2ToTV) {
-              temp=SiS_GetReg1(SiS_P3d4,0x31);
-              temp=temp&0x01;
-              if(temp) {
-                  temp1=SiS_GetReg1(SiS_P3d4,0x38);
-                  temp1=temp1&0x40;
-                  if(temp1)
-                     PhasePoint = SiS_PALMPhase;
-                  temp1=SiS_GetReg1(SiS_P3d4,0x38);
-                  temp1=temp1&0x80;
-                  if(temp1)
-                     PhasePoint = SiS_PALNPhase;
-              }
-           }
+  switch(DisplayType) {
+    case 0 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1;           break;
+    case 1 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1;          break;
+    case 2 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1;         break;
+    case 3 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1_H;         break;
+    case 4 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1_H;        break;
+    case 5 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1_H;       break;
+    case 6 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2;           break;
+    case 7 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2;          break;
+    case 8 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2;         break;
+    case 9 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2_H;         break;
+    case 10: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2_H;        break;
+    case 11: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2_H;       break;
+    case 12: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1;           break;
+    case 13: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H;         break;
+    case 14: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_1;         break;
+    case 15: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_1_H;       break;
+    case 16: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_2;         break;
+    case 17: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_2_H;       break;
+    case 18: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UNTSC;               break;
+    case 19: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1ONTSC;               break;
+    case 20: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UPAL;                break;
+    case 21: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1OPAL;                break;
+    case 22: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1320x480_1;           break; /* FSTN */
+    case 23: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_1;          break;
+    case 24: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_1_H;        break;
+    case 25: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_2;          break;
+    case 26: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x600_2_H;        break;
+    case 27: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_1;          break;
+    case 28: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_1_H;        break;
+    case 29: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_2;          break;
+    case 30: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11152x768_2_H;        break;
+    case 36: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_1;         break;
+    case 37: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_1_H;       break;
+    case 38: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_2;         break;
+    case 39: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11600x1200_2_H;       break;
   }
-  /*end add*/
-#endif
 
-  for(i=0x31,j=0;i<=0x34;i++,j++){
-     SiS_SetReg1(SiS_Part2Port,i,PhasePoint[j]);
+  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);                        /*unlock cr0-7  */
+
+  tempah = (LVDSCRT1Ptr+ResInfo)->CR[0];
+  SiS_SetReg1(SiS_Pr->SiS_P3d4,0x00,tempah);
+
+  for(i=0x02,j=1;i<=0x05;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
+  }
+  for(i=0x06,j=5;i<=0x07;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
+  }
+  for(i=0x10,j=7;i<=0x11;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
   }
-  for(i=0x01,j=0;i<=0x2D;i++,j++){
-     SiS_SetReg1(SiS_Part2Port,i,TimingPoint[j]);
+  for(i=0x15,j=9;i<=0x16;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
   }
-  for(i=0x39;i<=0x45;i++,j++){
-     SiS_SetReg1(SiS_Part2Port,i,TimingPoint[j]);      /* di->temp2[j] */
+  for(i=0x0A,j=11;i<=0x0C;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3c4,i,tempah);
   }
-  if(SiS_VBInfo&SetCRT2ToTV) {
-    SiS_SetRegANDOR(SiS_Part2Port,0x3A,0x1F,0x00);
+
+  tempah = (LVDSCRT1Ptr+ResInfo)->CR[14];
+  tempah &= 0xE0;
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0x1f,tempah);     	/* TW: Modfied (650/LVDS); Was SetReg(tempah) */
+
+  tempah = (LVDSCRT1Ptr+ResInfo)->CR[14];
+  tempah &= 0x01;
+  tempah <<= 5;
+  if(modeflag & DoubleScanMode){
+    	tempah |= 0x080;
+  }
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,~0x020,tempah);
+
+  /* TW: Inserted from 650/LVDS BIOS */
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+     if(modeflag & HalfDCLK)
+        SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);
   }
-  temp=SiS_NewFlickerMode;
-  SiS_SetRegANDOR(SiS_Part2Port,0x0A,0xFF,temp);
 
-  SiS_SetReg1(SiS_Part2Port,0x35,0x00); /*301b*/
-  SiS_SetReg1(SiS_Part2Port,0x36,0x00);
-  SiS_SetReg1(SiS_Part2Port,0x37,0x00);
-  SiS_SetReg1(SiS_Part2Port,0x38,SiS_RY1COE);
-  SiS_SetReg1(SiS_Part2Port,0x48,SiS_RY2COE);
-  SiS_SetReg1(SiS_Part2Port,0x49,SiS_RY3COE);
-  SiS_SetReg1(SiS_Part2Port,0x4a,SiS_RY4COE);
+  return;
+}
+
+#if 0 /* TW: Unused */
+/*301b*/
+void
+SiS_CHACRT1CRTC(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                USHORT RefreshRateTableIndex)
+{
+  USHORT temp,tempah,i,modeflag,j;
+  USHORT ResInfo,DisplayType;
+  SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr=NULL;
 
-  /*add to change 630+301b filter*/
-  resindex=SiS_GetResInfo(ROMAddr,ModeNo,ModeIdIndex);
   if(ModeNo<=0x13) {
-      xres=SiS_StResInfo[resindex].HTotal;
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
   } else {
-      xres=SiS_ModeResInfo[resindex].HTotal;                         /* xres->ax */
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
   }
-  if(xres==640){SiS_RY1COE=0xFF;SiS_RY2COE=0x03;SiS_RY3COE=0x02;SiS_RY4COE=0xF6;
-                         SiS_RY5COE=0xFC;SiS_RY6COE=0x27;SiS_RY7COE=0x46;}
-  if(xres==800){SiS_RY1COE=0x01;SiS_RY2COE=0x01;SiS_RY3COE=0xFC;SiS_RY4COE=0xF8;
-                         SiS_RY5COE=0x08;SiS_RY6COE=0x26;SiS_RY7COE=0x38;}                        
-  if(xres==1024){SiS_RY1COE=0xFF;SiS_RY2COE=0xFF;SiS_RY3COE=0xFC;SiS_RY4COE=0x00;
-                         SiS_RY5COE=0x0F;SiS_RY6COE=0x22;SiS_RY7COE=0x28;}
-  if(xres==720){SiS_RY1COE=0x01;SiS_RY2COE=0x02;SiS_RY3COE=0xFE;SiS_RY4COE=0xF7;
-                         SiS_RY5COE=0x03;SiS_RY6COE=0x27;SiS_RY7COE=0x3c;}
-  SiS_SetReg1(SiS_Part2Port,0x35,SiS_RY1COE); /*301b*/
-  SiS_SetReg1(SiS_Part2Port,0x36,SiS_RY2COE);
-  SiS_SetReg1(SiS_Part2Port,0x37,SiS_RY3COE);
-  SiS_SetReg1(SiS_Part2Port,0x38,SiS_RY4COE);
-  SiS_SetReg1(SiS_Part2Port,0x48,SiS_RY5COE);
-  SiS_SetReg1(SiS_Part2Port,0x49,SiS_RY6COE);
-  SiS_SetReg1(SiS_Part2Port,0x4a,SiS_RY7COE);
-  /*end add*/
 
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) tempax=950;
-  else {
-    if(SiS_VBInfo&SetPALTV) tempax=520;
-    else tempax=440;
+  temp=SiS_GetLVDSCRT1Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
+                       &ResInfo,&DisplayType);
+  if(temp==0){
+    return;
   }
-  if(SiS_VDE<=tempax) {
-    tempax=tempax-SiS_VDE;
-    tempax=tempax>>2;
-    tempax=(tempax&0x00FF)|((tempax&0x00FF)<<8);
-    push1=tempax;
-    temp=(tempax&0xFF00)>>8;
-    temp=temp+(USHORT)TimingPoint[0];
-    SiS_SetReg1(SiS_Part2Port,0x01,temp);
-    tempax=push1;
-    temp=(tempax&0xFF00)>>8;
-    temp=temp+TimingPoint[1];
-    SiS_SetReg1(SiS_Part2Port,0x02,temp);
-  }
-  /*301b*/
-  if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-        && (SiS_VBInfo&SetCRT2ToTV) && (SiS_VGAHDE==1024) ) {
-      if(SiS_VBInfo&SetPALTV) {
-       SiS_SetReg1(SiS_Part2Port,0x01,0x19);
-       SiS_SetReg1(SiS_Part2Port,0x02,0x52);
-      } else {
-       SiS_SetReg1(SiS_Part2Port,0x01,0x0B);
-       SiS_SetReg1(SiS_Part2Port,0x02,0x11);
-      } 
-    }
-    
-  tempcx=SiS_HT-1;
-  /*301b*/
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-     tempcx=tempcx-1;   
-  }
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part2Port,0x1B,temp);
-  temp=(tempcx&0xFF00)>>8;
-  SiS_SetRegANDOR(SiS_Part2Port,0x1D,~0x0F,temp);
-
-  tempcx=SiS_HT>>1;
-  push1=tempcx;                           /* push cx */
-  tempcx=tempcx+7;
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-    tempcx=tempcx-4;
-  }
-  temp=(tempcx&0x00FF);
-  temp=temp<<4;
-  SiS_SetRegANDOR(SiS_Part2Port,0x22,0x0F,temp);
-
-  tempbx=TimingPoint[j]|((TimingPoint[j+1])<<8);
-  tempbx=tempbx+tempcx;
-  push2=tempbx;
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part2Port,0x24,temp);
-  temp=(tempbx&0xFF00)>>8;
-  temp=temp<<4;
-  SiS_SetRegANDOR(SiS_Part2Port,0x25,0x0F,temp);
-
-  tempbx=push2;
-  tempbx=tempbx+8;
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-    tempbx=tempbx-4;
-    tempcx=tempbx;
-  }
-  temp=(tempbx&0x00FF)<<4;
-  SiS_SetRegANDOR(SiS_Part2Port,0x29,0x0F,temp);
-
-  j=j+2;
-  tempcx=tempcx+(TimingPoint[j]|((TimingPoint[j+1])<<8));
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part2Port,0x27,temp);
-  temp=((tempcx&0xFF00)>>8)<<4;
-  SiS_SetRegANDOR(SiS_Part2Port,0x28,0x0F,temp);
-
-  tempcx=tempcx+8;
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-    tempcx=tempcx-4;
-  }
-  temp=tempcx&0xFF;
-  temp=temp<<4;
-  SiS_SetRegANDOR(SiS_Part2Port,0x2A,0x0F,temp);
-
-  tempcx=push1;                                       /* pop cx */
-  j=j+2;
-  temp=TimingPoint[j]|((TimingPoint[j+1])<<8);
-  tempcx=tempcx-temp;
-  temp=tempcx&0x00FF;
-  temp=temp<<4;
-  SiS_SetRegANDOR(SiS_Part2Port,0x2D,0x0F,temp);
-
-  tempcx=tempcx-11;
-  if(!(SiS_VBInfo&SetCRT2ToTV)){
-    tempax=SiS_GetVGAHT2();
-    tempcx=tempax-1;
-  }
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part2Port,0x2E,temp);	/* TW: BIOS 0x48, here 0x3f @@@ */
-
-  tempbx=SiS_VDE;
-  if(SiS_VGAVDE==360) tempbx=746;
-  if(SiS_VGAVDE==375) tempbx=746;
-  if(SiS_VGAVDE==405) tempbx=853;
-  if(SiS_VBInfo&SetCRT2ToTV) {
-    tempbx=tempbx>>1;
-  }
-  tempbx=tempbx-2;
-  temp=tempbx&0x00FF;
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-    if(SiS_VBInfo&SetInSlaveMode) {
-      if(ModeNo==0x2f) temp=temp+1;
-    }
-  }
-  SiS_SetReg1(SiS_Part2Port,0x2F,temp);
-
-  temp=(tempcx&0xFF00)>>8;
-  temp=temp|(((tempbx&0xFF00)>>8)<<6);
-  if(!(SiS_VBInfo&SetCRT2ToHiVisionTV)) {
-    temp=temp|0x10;
-    if(!(SiS_VBInfo&SetCRT2ToSVIDEO)){
-      temp=temp|0x20;
-    }
-  }
-  SiS_SetReg1(SiS_Part2Port,0x30,temp);  /* TW: BIOS sets 0xb8, here (or somewhere else) 0xb5 */
-
-  /*301b*/
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {      /*tv gatingno*/
-    tempbx=SiS_VDE;
-    if(SiS_VBInfo&SetCRT2ToTV) {
-       tempbx=tempbx>>1;
-    }
-    temp=(((tempbx-3)&0x0300)>>8)<<5;
-    SiS_SetReg1(SiS_Part2Port,0x46,temp);
-    temp=(tempbx-3)&0x00FF;
-    SiS_SetReg1(SiS_Part2Port,0x47,temp);
-  }
-  /*end 301b*/
-
-  tempbx=tempbx&0x00FF;
-  if(!(modeflag&HalfDCLK)){
-    tempcx=SiS_VGAHDE;
-    if(tempcx>=SiS_HDE){
-      tempbx=tempbx|0x2000;
-      tempax=tempax&0x00FF;
-    }
-  }
-  tempcx=0x0101;
-
-  if(SiS_VBInfo&(SetCRT2ToHiVisionTV|SetCRT2ToTV)) { /*301b*/
-    if(SiS_VGAHDE>=1024) {
-      tempcx=0x1920;
-      if(SiS_VGAHDE>=1280) {
-        tempcx=0x1420;
-        tempbx=tempbx&0xDFFF;
-      }
-    }
-  }
-  if(!(tempbx&0x2000)){
-    if(modeflag&HalfDCLK){
-      tempcx=(tempcx&0xFF00)|((tempcx&0x00FF)<<1);
-    }
-    push1=tempbx;
-    tempeax=SiS_VGAHDE;
-    tempebx=(tempcx&0xFF00)>>8;
-    longtemp=tempeax*tempebx;
-    tempecx=tempcx&0x00FF;
-    longtemp=longtemp/tempecx;
-    /*301b*/
-    tempecx=8*1024;
-    if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-     	tempecx=tempecx*8;
-    }
-    longtemp=longtemp*tempecx;
-    tempecx=SiS_HDE;
-    temp2=longtemp%tempecx;
-    tempeax=longtemp/tempecx;
-    if(temp2!=0){
-      tempeax=tempeax+1;
-    }
-    tempax=(USHORT)tempeax;
-    /*301b*/
-    if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-     	tempcx=((tempax&0xFF00)>>5)>>8;
-    }
-    /*end 301b*/
-    tempbx=push1;
-    tempbx=(USHORT) ( ((tempeax&0x0000FF00)&0x1F00)|(tempbx&0x00FF) );
-    tempax=(USHORT) ( ((tempeax&0x000000FF)<<8)|(tempax&0x00FF) );
-    temp=(tempax&0xFF00)>>8;
-  } else {
-    temp=(tempax&0x00FF)>>8;
-  }
-  SiS_SetReg1(SiS_Part2Port,0x44,temp);
-  temp=(tempbx&0xFF00)>>8;
-  SiS_SetRegANDOR(SiS_Part2Port,0x45,~0x03F,temp);
-  /*301b*/
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-       if((tempcx&0x00FF)==0x01)
-    		tempcx=0x00;
-       SiS_SetRegANDOR(SiS_Part2Port,0x46,~0x007,tempcx);
-       SiS_SetRegOR(SiS_Part2Port,0x46,0x18);
-               if(SiS_VBInfo&SetPALTV) {
-                   tempbx=0x0364;
-                   tempcx=0x009c;
-               } else {
-                   tempbx=0x0346;
-                   tempcx=0x0078;
-               }
-       temp=(tempbx&0x00FF) ;
-       SiS_SetReg1(SiS_Part2Port,0x4B,temp);
-       temp=(tempcx&0x00FF) ;
-       SiS_SetReg1(SiS_Part2Port,0x4C,temp);
-       tempbx=(tempbx&0x0300);
-       temp=(tempcx&0xFF00)>>8 ;
-       temp=(temp&0x0003)<<2;
-       temp=temp|(tempbx>>8);
-       SiS_SetReg1(SiS_Part2Port,0x4D,temp);
 
-       temp=SiS_GetReg1(SiS_Part2Port,0x43); /*301b change */
-       SiS_SetReg1(SiS_Part2Port,0x43,(USHORT)(temp-3));
+  switch(DisplayType) {
+    case 0 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1;           break;
+    case 1 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1;          break;
+    case 2 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1;         break;
+    case 3 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_1_H;         break;
+    case 4 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_1_H;        break;
+    case 5 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_1_H;       break;
+    case 6 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2;           break;
+    case 7 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2;          break;
+    case 8 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2;         break;
+    case 9 : LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1800x600_2_H;         break;
+    case 10: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11024x768_2_H;        break;
+    case 11: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11280x1024_2_H;       break;
+    case 12: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1;           break;
+    case 13: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1XXXxXXX_1_H;         break;
+    case 14: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_1;         break;
+    case 15: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_1_H;       break;
+    case 16: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_2;         break;
+    case 17: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT11400x1050_2_H;       break;
+    case 18: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UNTSC;               break;
+    case 19: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1ONTSC;               break;
+    case 20: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1UPAL;                break;
+    case 21: LVDSCRT1Ptr = SiS_Pr->SiS_CHTVCRT1OPAL;                break;
+    case 22: LVDSCRT1Ptr = SiS_Pr->SiS_LVDSCRT1320x480_1;           break; /* FSTN */
   }
-  /*end 301b*/
 
-#ifdef SIS300
-  /*add PALMN*/
-  if((HwDeviceExtension->jChipType==SIS_630)||
-     (HwDeviceExtension->jChipType==SIS_730)) {
-          if(SiS_VBInfo&SetCRT2ToTV) {
-             temp=SiS_GetReg1(SiS_P3d4,0x31);
-             temp=temp&0x01;
-             if(temp) {
-                  temp1=SiS_GetReg1(SiS_P3d4,0x35);
-                  temp1=temp1&0x40;
-                  if(temp1){
-                           SiS_SetRegANDOR(SiS_Part2Port,0x00,0xEF,0x00);
-                           temp3=SiS_GetReg1(SiS_Part2Port,0x01);
-                           temp3=temp3-1;
-                           SiS_SetReg1(SiS_Part2Port,0x01,temp3);
-                  }
-             }
-          }
+  tempah=(UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x11);                        /*unlock cr0-7  */
+  tempah=tempah&0x7F;
+  SiS_SetReg1(SiS_Pr->SiS_P3d4,0x11,tempah);
+  tempah = (LVDSCRT1Ptr+ResInfo)->CR[0];
+  SiS_SetReg1(SiS_Pr->SiS_P3d4,0x0,tempah);
+  for(i=0x02,j=1;i<=0x05;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
+  }
+  for(i=0x06,j=5;i<=0x07;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
+  }
+  for(i=0x10,j=7;i<=0x11;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
+  }
+  for(i=0x15,j=9;i<=0x16;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
+  }
+
+  for(i=0x0A,j=11;i<=0x0C;i++,j++){
+    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
+    SiS_SetReg1(SiS_Pr->SiS_P3c4,i,tempah);
+  }
+
+  tempah = (LVDSCRT1Ptr+ResInfo)->CR[14];
+  tempah=tempah&0x0E0;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x0E,tempah);
+
+  tempah = (LVDSCRT1Ptr+ResInfo)->CR[14];
+  tempah=tempah&0x01;
+  tempah=tempah<<5;
+  if(modeflag&DoubleScanMode){
+    	tempah=tempah|0x080;
   }
-  /*end add*/
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,~0x020,tempah);
+  return;
+}
 #endif
 
-#ifdef SIS315H
-  /*add PALMN*/
-  if ( (HwDeviceExtension->jChipType==SIS_315H)||
-       (HwDeviceExtension->jChipType==SIS_315PRO)||
-       (HwDeviceExtension->jChipType==SIS_550) ||
-       (HwDeviceExtension->jChipType==SIS_640) ||
-       (HwDeviceExtension->jChipType==SIS_740) ||
-       (HwDeviceExtension->jChipType==SIS_650)) {
-        	if(SiS_VBInfo&SetCRT2ToTV) {
-             		temp=SiS_GetReg1(SiS_P3d4,0x31);
-            		temp=temp&0x01;
-              		if(temp) {
-                  		temp1=SiS_GetReg1(SiS_P3d4,0x38);
-                 		temp1=temp1&0x40;
-                   		if(temp1){
-                           		SiS_SetRegANDOR(SiS_Part2Port,0x00,0xEF,0x00);
-                           		temp3=SiS_GetReg1(SiS_Part2Port,0x01);
-                           		temp3=temp3-1;
-                           		SiS_SetReg1(SiS_Part2Port,0x01,temp3);
-                		}
-             		}
-          	}
+/* TW: Checked against 650/LVDS BIOS: modified for new panel resolutions */
+BOOLEAN
+SiS_GetLVDSCRT1Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+		   USHORT RefreshRateTableIndex,USHORT *ResInfo,
+		   USHORT *DisplayType)
+ {
+  USHORT tempbx,modeflag=0;
+  USHORT Flag,CRT2CRTC;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+      /* TW: Inserted from 650/LVDS BIOS */
+      if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+          if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) return 0;
+      }
   }
-  /*end add*/
-#endif
 
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-    if(!(SiS_VBInfo&SetInSlaveMode)) {
-      SiS_SetReg1(SiS_Part2Port,0x0B,0x00);
+  if(ModeNo <= 0x13) {
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+    	CRT2CRTC = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  } else {
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    	CRT2CRTC = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+  }
+
+  Flag = 1;
+  tempbx = 0;
+  if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+    if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) {
+      Flag = 0;
+      tempbx = 18;
+      if(SiS_Pr->SiS_VBInfo & SetPALTV) tempbx += 2;
+      if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) tempbx++;
     }
   }
-  if(SiS_VBInfo&SetCRT2ToTV){
-    return;
+  if(Flag) {
+    tempbx = SiS_Pr->SiS_LCDResInfo;
+    tempbx -= SiS_Pr->SiS_PanelMinLVDS;
+    if(SiS_Pr->SiS_LCDResInfo <= SiS_Pr->SiS_Panel1280x1024) {
+       if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx += 6;
+       if(modeflag & HalfDCLK) tempbx += 3;
+    } else {
+       if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+           tempbx = 14;
+	   if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx += 2;
+	   if(modeflag & HalfDCLK) tempbx++;
+       } else if(SiS_Pr->SiS_LCDInfo & LCDPass11) {
+           tempbx = 12;
+	   if(modeflag & HalfDCLK) tempbx++;
+       } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x600) {
+           tempbx = 23;
+	   if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx += 2;
+	   if(modeflag & HalfDCLK) tempbx++;
+       } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1152x768) {
+           tempbx = 27;
+	   if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx += 2;
+	   if(modeflag & HalfDCLK) tempbx++;
+       } else if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1600x1200) {
+           tempbx = 36;
+	   if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx += 2;
+	   if(modeflag & HalfDCLK) tempbx++;
+       }
+    }
   }
+  if(SiS_Pr->SiS_IF_DEF_FSTN){
+     if(SiS_Pr->SiS_LCDResInfo==SiS_Pr->SiS_Panel320x480){
+       tempbx=22;
+     }
+  }
+  *ResInfo = CRT2CRTC & 0x3F;
+  *DisplayType = tempbx;
+  return 1;
+}
 
-  /* TW: From here: LCD Part2 group */
+/* TW: Checked against 650/LVDS (1.10a, 1.10.07), 630/301B (I/II) and 630/LVDS BIOS */
+void
+SiS_SetCRT2ECLK(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo,USHORT ModeIdIndex,
+           USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT tempah,tempal,pushax;
+  USHORT vclkindex=0;
 
-  tempbx=SiS_HDE-1;         /* RHACTE=HDE-1 */
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part2Port,0x2C,temp);
-  temp=(tempbx&0xFF00)>>8;
-  temp=temp<<4;
-  SiS_SetRegANDOR(SiS_Part2Port,0x2B,0x0F,temp);
-  temp=0x01;
-  if(SiS_LCDResInfo==Panel1280x1024) {
-    if(SiS_ModeType==ModeEGA) {
-      if(SiS_VGAHDE>=1024) {
-        temp=0x02;
-        if (SiS_SetFlag&LCDVESATiming)
-          temp=0x01;
-      }
-    }
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD)) return;
+     }
   }
-  SiS_SetReg1(SiS_Part2Port,0x0B,temp);
 
-  tempbx=SiS_VDE;         /* RTVACTEO=(VDE-1)&0xFF */
-  push1=tempbx;
-  tempbx--;
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part2Port,0x03,temp);
-  temp=((tempbx&0xFF00)>>8)&0x07;
-  SiS_SetRegANDOR(SiS_Part2Port,0x0C,~0x07,temp);
-
-  tempcx=SiS_VT-1;
-  push2=tempcx+1;
-  temp=tempcx&0x00FF;   /* RVTVT=VT-1 */
-  SiS_SetReg1(SiS_Part2Port,0x19,temp);
-  temp=(tempcx&0xFF00)>>8;
-  temp=temp<<5;
-  if(SiS_LCDInfo&LCDRGB18Bit){
-    temp=temp|0x10;
-  }
-  if(SiS_VBInfo&SetCRT2ToLCD) {
-    tempbx=(tempbx&0xFF00)|(SiS_LCDInfo&0x0FF);
-    if(tempbx&LCDSync) {
-      tempbx=tempbx&LCDSyncBit;
-      tempbx=(tempbx&0xFF00)|((tempbx&0x00FF)>>LCDSyncShift);
-      temp=temp|(tempbx&0x00FF);
-    }
+  if((SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel640x480) || (SiS_Pr->SiS_IF_DEF_TRUMPION == 1)) {
+	SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
+        tempal = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+    	tempal &= 0x3F;
+	if(tempal == 2) RefreshRateTableIndex--;
+	vclkindex = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+                               RefreshRateTableIndex,HwDeviceExtension);
+	SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+  } else {
+        vclkindex = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+                               RefreshRateTableIndex,HwDeviceExtension);
   }
-  SiS_SetReg1(SiS_Part2Port,0x1A,temp);
 
-  tempcx++;
-  tempbx=768;
-  if(SiS_LCDResInfo!=Panel1024x768) {
-    tempbx=1024;
-    if(SiS_LCDResInfo!=Panel1280x1024) {
-         tempbx=1200;     /*301b */
-         if(SiS_LCDResInfo!=Panel1600x1200) {
-            if(tempbx!=SiS_VDE) {
-               tempbx=960;
-            }
-         }
-    }
+  tempal = 0x02B;
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+     if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) {
+    	tempal += 3;
+     }
   }
-  if(SiS_LCDInfo&LCDNonExpanding) {
-    tempbx=SiS_VDE;
-    tempbx--;
-    tempcx--;
-  }
-  tempax=1;
-  if(!(SiS_LCDInfo&LCDNonExpanding)) {
-    if(tempbx!=SiS_VDE){
-      tempax=tempbx;
-      if(tempax<SiS_VDE) {
-        tempax=0;
-        tempcx=0;
-      } else {
-        tempax=tempax-SiS_VDE;
-      }
-      tempax=tempax>>1;
-    }
-    tempcx=tempcx-tempax; /* lcdvdes */
-    tempbx=tempbx-tempax; /* lcdvdee */
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
+  pushax = tempal;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,0x20);
+  tempah = SiS_Pr->SiS_VCLKData[vclkindex].SR2B;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,tempal,tempah);
+  tempal++;
+  tempah = SiS_Pr->SiS_VCLKData[vclkindex].SR2C;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,tempal,tempah);
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,0x10);
+  tempal = pushax;
+  tempah = SiS_Pr->SiS_VCLKData[vclkindex].SR2B;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,tempal,tempah);
+  tempal++;
+  tempah = SiS_Pr->SiS_VCLKData[vclkindex].SR2C;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,tempal,tempah);
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,0x00);
+  tempal = pushax;
+  tempah = SiS_Pr->SiS_VCLKData[vclkindex].SR2B;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,tempal,tempah);
+  tempal++;
+  tempah = SiS_Pr->SiS_VCLKData[vclkindex].SR2C;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,tempal,tempah);
+  return;
+}
+
+#if 0  /* TW: Not used */
+void
+SiS_SetDefCRT2ExtRegs(SiS_Private *SiS_Pr, USHORT BaseAddr)
+{
+  USHORT  temp;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS==0) {
+    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x02,0x40);
+    SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x10,0x80);
+    temp=(UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
+    temp &= 0xC3;
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,0x35,temp);
   } else {
-    tempax=tempax>>1;
-    tempcx=tempcx-tempax; /* lcdvdes */
-    tempbx=tempbx-tempax; /* lcdvdee */
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,0x32,0x02);
+    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x02,0x00);
   }
+}
+#endif
 
-  temp=tempcx&0x00FF;   /* RVEQ1EQ=lcdvdes */
-  SiS_SetReg1(SiS_Part2Port,0x05,temp);
-  temp=tempbx&0x00FF;   /* RVEQ2EQ=lcdvdee */
-  SiS_SetReg1(SiS_Part2Port,0x06,temp);
+/* TW: Start of Chrontel 70xx functions ---------------------- */
 
-  /* TW new @@@ */
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-        /* TW: BIOS sets Part2 0x02 to 0x18. The old caluculation (in else statement)
-	 *     resulted in 0x13. Do it this way for 301B?
-	 */
-        temp=(((tempcx&0xFF00)>>8)<<3);   /* 0x325 & ff00 = 300 >> 8 = 3 << 3 = 0x18 */
-	SiS_SetReg1(SiS_Part2Port,0x02,temp);
-  } else {
-  /* TW end */
-  	temp=(tempbx&0xFF00)>>8;
-  	temp=temp<<3;
-  	temp=temp|((tempcx&0xFF00)>>8);
-  	SiS_SetReg1(SiS_Part2Port,0x02,temp);
-  }
-
-  tempbx=push2;  	/* SiS_VT = 0x326  - - - (TW DEBUG REMARKS)*/
-  tempax=push1;  	/* SiS_VDE = 0x300 */
-  tempcx=tempbx;
-  tempcx=tempcx-tempax; /* -> 0x26 */
-  tempcx=tempcx>>4;     /* -> 0x02 */
-  tempbx=tempbx+tempax; /* -> 0x626 */
-  tempbx=tempbx>>1;     /* -> 0x313 */
-  if(SiS_LCDInfo&LCDNonExpanding) {
-     tempbx=tempbx-10;
-  }
-  /* TW new @@@ */
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-  	/* TW: BIOS sets Part2 0x04 to 0x02. The old caluculation (in else statement)
-	 *     resulted in 0x13. Do it this way for 301B?
-	 */
-        temp=tempcx&0x00FF;
-	SiS_SetReg1(SiS_Part2Port,0x04,temp);
-  } else {
-  /* TW end */
-    	temp=tempbx&0x00FF;   		/* RTVACTEE=lcdvrs */
-  	SiS_SetReg1(SiS_Part2Port,0x04,temp);   /* TW: BIOS: 0x02, here 0x13 */
-  }
-
- temp=(tempbx&0xFF00)>>8;
- temp=temp<<4;
- tempbx=tempbx+tempcx+1;
- temp=temp|(tempbx&0x000F);
- SiS_SetReg1(SiS_Part2Port,0x01,temp);
-
- if(SiS_LCDResInfo==Panel1024x768) {
-   if(!(SiS_SetFlag&LCDVESATiming)) {
-     if(!(SiS_LCDInfo&LCDNonExpanding)) {
-       if(ModeNo==0x13) {
-         SiS_SetReg1(SiS_Part2Port,0x04,0xB9);
-         SiS_SetReg1(SiS_Part2Port,0x05,0xCC);
-         SiS_SetReg1(SiS_Part2Port,0x06,0xA6);
+/* Set-up the Chrontel Registers */
+void
+SiS_SetCHTVReg(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+               USHORT RefreshRateTableIndex)
+{
+  USHORT temp, tempbx, tempcl;
+  USHORT TVType, resindex;
+  const SiS_CHTVRegDataStruct *CHTVRegData = NULL;
+
+  if(ModeNo <= 0x13)
+    	tempcl = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  else
+    	tempcl = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+
+  TVType = 0;
+  if(SiS_Pr->SiS_VBInfo & SetPALTV) TVType += 2;
+  if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) TVType += 1;
+  switch(TVType) {
+    	case 0: CHTVRegData = SiS_Pr->SiS_CHTVReg_UNTSC; break;
+    	case 1: CHTVRegData = SiS_Pr->SiS_CHTVReg_ONTSC; break;
+    	case 2: CHTVRegData = SiS_Pr->SiS_CHTVReg_UPAL;  break;
+    	case 3: CHTVRegData = SiS_Pr->SiS_CHTVReg_OPAL;  break;
+  }
+  resindex = tempcl & 0x3F;
+
+  if(SiS_Pr->SiS_IF_DEF_CH70xx == 1) {
+
+     /* Chrontel 7005 */
+
+     /* TW: We don't support modes >800x600 */
+     if (resindex > 5) return;
+
+     if(SiS_Pr->SiS_VBInfo & SetPALTV) {
+    	SiS_SetCH700x(SiS_Pr,0x4304);   /* TW: 0x40=76uA (PAL); 0x03=15bit non-multi RGB*/
+    	SiS_SetCH700x(SiS_Pr,0x6909);	/* TW: Black level for PAL (105)*/
+     } else {
+    	SiS_SetCH700x(SiS_Pr,0x0304);   /* TW: upper nibble=71uA (NTSC), 0x03=15bit non-multi RGB*/
+    	SiS_SetCH700x(SiS_Pr,0x7109);	/* TW: Black level for NTSC (113)*/
+     }
+
+     temp = CHTVRegData[resindex].Reg[0];
+     tempbx=((temp&0x00FF)<<8)|0x00;	/* TW: Mode register */
+     SiS_SetCH700x(SiS_Pr,tempbx);
+     temp = CHTVRegData[resindex].Reg[1];
+     tempbx=((temp&0x00FF)<<8)|0x07;	/* TW: Start active video register */
+     SiS_SetCH700x(SiS_Pr,tempbx);
+     temp = CHTVRegData[resindex].Reg[2];
+     tempbx=((temp&0x00FF)<<8)|0x08;	/* TW: Position overflow register */
+     SiS_SetCH700x(SiS_Pr,tempbx);
+     temp = CHTVRegData[resindex].Reg[3];
+     tempbx=((temp&0x00FF)<<8)|0x0A;	/* TW: Horiz Position register */
+     SiS_SetCH700x(SiS_Pr,tempbx);
+     temp = CHTVRegData[resindex].Reg[4];
+     tempbx=((temp&0x00FF)<<8)|0x0B;	/* TW: Vertical Position register */
+     SiS_SetCH700x(SiS_Pr,tempbx);
+
+     /* TW: Set minimum flicker filter for Luma channel (SR1-0=00),
+                minimum text enhancement (S3-2=10),
+   	        maximum flicker filter for Chroma channel (S5-4=10)
+	        =00101000=0x28 (When reading, S1-0->S3-2, and S3-2->S1-0!)
+      */
+     SiS_SetCH700x(SiS_Pr,0x2801);
+
+     /* TW: Set video bandwidth
+            High bandwith Luma composite video filter(S0=1)
+            low bandwith Luma S-video filter (S2-1=00)
+	    disable peak filter in S-video channel (S3=0)
+	    high bandwidth Chroma Filter (S5-4=11)
+	    =00110001=0x31
+     */
+     SiS_SetCH700x(SiS_Pr,0xb103);       /* old: 3103 */
+
+     /* TW: Register 0x3D does not exist in non-macrovision register map
+            (Maybe this is a macrovision register?)
+      */
+     /* SiS_SetCH70xx(SiS_Pr,0x003D); */
+
+     /* TW: Register 0x10 only contains 1 writable bit (S0) for sensing,
+            all other bits a read-only. Macrovision?
+      */
+     SiS_SetCH70xxANDOR(SiS_Pr,0x0010,0x1F);
+
+     /* TW: Register 0x11 only contains 3 writable bits (S0-S2) for
+            contrast enhancement (set to 010 -> gain 2 Yout = 9/8*(Yin-57) )
+      */
+     SiS_SetCH70xxANDOR(SiS_Pr,0x0211,0xF8);
+
+     /* TW: Clear DSEN
+      */
+     SiS_SetCH70xxANDOR(SiS_Pr,0x001C,0xEF);
+
+     if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {		/* ---- NTSC ---- */
+       if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) {
+         if(resindex == 0x04) {   			/* 640x480 overscan: Mode 16 */
+      	   SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF);   	/* loop filter off */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE);      /* ACIV on, no need to set FSCI */
+         } else {
+           if(resindex == 0x05) {    			/* 800x600 overscan: Mode 23 */
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0118,0xF0);	/* 0x18-0x1f: FSCI 469,762,048 */
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0C19,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x001A,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x001B,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x001C,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x001D,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x001E,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x001F,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0120,0xEF);     /* Loop filter on for mode 23 */
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0021,0xFE);     /* ACIV off, need to set FSCI */
+           }
+         }
        } else {
-         temp=crt2crtc&0x3F;
-         if(temp==4) {
-           SiS_SetReg1(SiS_Part2Port,0x01,0x2B);
-           SiS_SetReg1(SiS_Part2Port,0x02,0x13);
-           SiS_SetReg1(SiS_Part2Port,0x04,0xE5);
-           SiS_SetReg1(SiS_Part2Port,0x05,0x08);
-           SiS_SetReg1(SiS_Part2Port,0x06,0xE2);
+         if(resindex == 0x04) {     			 /* ----- 640x480 underscan; Mode 17 */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); 	 /* loop filter off */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE);
+         } else {
+           if(resindex == 0x05) {   			 /* ----- 800x600 underscan: Mode 24 */
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0118,0xF0);     /* (FSCI was 0x1f1c71c7 - this is for mode 22) */
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0919,0xF0);	 /* FSCI for mode 24 is 428,554,851 */
+             SiS_SetCH70xxANDOR(SiS_Pr,0x081A,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0b1B,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x031C,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0a1D,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x061E,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x031F,0xF0);
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF);     /* loop filter off for mode 24 */
+             SiS_SetCH70xxANDOR(SiS_Pr,0x0021,0xFE);	 /* ACIV off, need to set FSCI */
+           }
          }
        }
+     } else {				/* ---- PAL ---- */
+           /* TW: We don't play around with FSCI in PAL mode */
+         if (resindex == 0x04) {
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); 	/* loop filter off */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE);      /* ACIV on */
+         } else {
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0020,0xEF); 	/* loop filter off */
+           SiS_SetCH70xxANDOR(SiS_Pr,0x0121,0xFE);      /* ACIV on */
+         }
      }
-   }
- }
 
- SiS_SetRegANDOR(SiS_Part2Port,0x09,0xF0,0x00);
- SiS_SetRegANDOR(SiS_Part2Port,0x0A,0xF0,0x00);
+  } else {
 
- tempcx=(SiS_HT-SiS_HDE)>>2;    		/* (HT-HDE)>>2     */
- tempbx=(SiS_HDE+7);            		/* lcdhdee         */
- /*301b*/
- if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-    tempbx=tempbx+2;
- }
- push1=tempbx;
- temp=tempbx&0x00FF;    			/* RHEQPLE=lcdhdee */
- SiS_SetReg1(SiS_Part2Port,0x23,temp);
- temp=(tempbx&0xFF00)>>8;
- SiS_SetRegANDOR(SiS_Part2Port,0x25,~0x0F,temp);
- /*301b*/
- temp=7;
- if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-    temp=temp+2;
- }
- SiS_SetReg1(SiS_Part2Port,0x1F,temp);  	/* RHBLKE=lcdhdes */
- SiS_SetRegANDOR(SiS_Part2Port,0x20,0x0F,0x00);
+     /* Chrontel 7019 */
 
- tempbx=tempbx+tempcx;
- push2=tempbx;
- temp=tempbx&0xFF;            			/* RHBURSTS=lcdhrs */
- if(SiS_LCDResInfo==Panel1280x1024) {
-   if(!(SiS_LCDInfo&LCDNonExpanding)) {
-     if(SiS_HDE==1280) {
-       temp=0x47;
-     }
-   }
- }
- SiS_SetReg1(SiS_Part2Port,0x1C,temp);
- temp=(tempbx&0xFF00)>>8;
- temp=temp<<4;
- SiS_SetRegANDOR(SiS_Part2Port,0x1D,~0x0F0,temp);
-
- tempbx=push2;
- tempcx=tempcx<<1;
- tempbx=tempbx+tempcx;
- temp=tempbx&0x00FF;            		/* RHSYEXP2S=lcdhre */
- SiS_SetReg1(SiS_Part2Port,0x21,temp);
-
- SiS_SetRegANDOR(SiS_Part2Port,0x17,0xFB,0x00);
- SiS_SetRegANDOR(SiS_Part2Port,0x18,0xDF,0x00);
-
- if(!(SiS_SetFlag&LCDVESATiming)) {
-   if(SiS_VGAVDE==525) {
-     if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))   /*301b*/
-    	temp=0xC6;
-     else
-       	temp=0xC4;
-     SiS_SetReg1(SiS_Part2Port,0x2f,temp);
-     SiS_SetReg1(SiS_Part2Port,0x30,0xB3);
-   }
-   if(SiS_VGAVDE==420) {
-     if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-    	temp=0x4F;
-     else
-       	temp=0x4E;
-     SiS_SetReg1(SiS_Part2Port,0x2f,temp);
-   }
- }
-}
+     /* TW: We don't support modes >1024x768 */
+     if (resindex > 6) return;
 
-USHORT
-SiS_GetVGAHT2()
-{
-  ULONG tempax,tempbx;
+     temp = CHTVRegData[resindex].Reg[0];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x00;
+     SiS_SetCH701x(SiS_Pr,tempbx);
 
-  tempbx=((SiS_VGAVT-SiS_VGAVDE)*SiS_RVBHCMAX)&0xFFFF;
-  tempax=(SiS_VT-SiS_VDE)*SiS_RVBHCFACT;
-  tempax=(tempax*SiS_HT)/tempbx;
-  return((USHORT) tempax);
+     temp = CHTVRegData[resindex].Reg[1];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x01;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[2];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x02;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[3];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x04;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[4];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x03;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[5];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x05;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[6];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x06;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[7];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x07;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[8];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x08;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[9];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x15;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[10];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x1f;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[11];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x0c;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[12];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x0d;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[13];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x0e;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[14];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x0f;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+     temp = CHTVRegData[resindex].Reg[15];
+     tempbx=((temp & 0x00FF) <<8 ) | 0x10;
+     SiS_SetCH701x(SiS_Pr,tempbx);
+
+  }
 }
 
 void
-SiS_SetGroup3(USHORT  BaseAddr,ULONG ROMAddr,USHORT ModeNo,
-              USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_SetCH701xForLCD(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
 {
-  USHORT i;
-  UCHAR *tempdi;
-  USHORT  modeflag,temp,temp1;
-
-  if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-  }
+  UCHAR regtable[]  = { 0x1c, 0x5f, 0x64, 0x6f, 0x70, 0x71,
+                        0x72, 0x73, 0x74, 0x76, 0x78, 0x7d };
+  UCHAR table28b4[] = { 0x60, 0x02, 0x00, 0x07, 0x40, 0xed,
+                        0xa3, 0xc8, 0xc7, 0xac, 0x60, 0x02 };
+  UCHAR table28c0[] = { 0x60, 0x03, 0x11, 0x00, 0x40, 0xef,
+                        0xad, 0xdb, 0xf6, 0xac, 0x60, 0x02 };
+  UCHAR *tableptr = NULL;
+  USHORT tempbh;
+  int i;
 
-  SiS_SetReg1(SiS_Part3Port,0x00,0x00);
-  if(SiS_VBInfo&SetPALTV) {
-    SiS_SetReg1(SiS_Part3Port,0x13,0xFA);
-    SiS_SetReg1(SiS_Part3Port,0x14,0xC8);
+  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+      tableptr = table28c0;
   } else {
-    SiS_SetReg1(SiS_Part3Port,0x13,0xF6);
-    SiS_SetReg1(SiS_Part3Port,0x14,0xBF);
+      tableptr = table28b4;
   }
-#ifdef SIS300
-  /*add PALMN*/
-  if((HwDeviceExtension->jChipType==SIS_630)||
-     (HwDeviceExtension->jChipType==SIS_730)) {
-           if(SiS_VBInfo&SetCRT2ToTV) {
-              temp=SiS_GetReg1(SiS_P3d4,0x31);
-              temp=temp&0x01;
-              if(temp) {
-                  temp1=SiS_GetReg1(SiS_P3d4,0x35);
-                  temp1=temp1&0x40;
-                   if(temp1){
-                          SiS_SetReg1(SiS_Part3Port,0x13,0xFA);
-                          SiS_SetReg1(SiS_Part3Port,0x14,0xC8);
-                          SiS_SetReg1(SiS_Part3Port,0x3D,0xA8);
-                }
-             }
-          } 
-      }	
-    /*end add*/
-#endif
-#ifdef SIS315H
-/*add PALMN*/
-  if ( (HwDeviceExtension->jChipType==SIS_315H)||
-       (HwDeviceExtension->jChipType==SIS_315PRO)||
-       (HwDeviceExtension->jChipType==SIS_550) ||
-       (HwDeviceExtension->jChipType==SIS_640) ||
-       (HwDeviceExtension->jChipType==SIS_740) ||
-       (HwDeviceExtension->jChipType==SIS_650)) {
-         if(SiS_VBInfo&SetCRT2ToTV) {
-             temp=SiS_GetReg1(SiS_P3d4,0x31);   
-             temp=temp&0x01; 
-              if(temp) {
-                  temp1=SiS_GetReg1(SiS_P3d4,0x38);        
-                  temp1=temp1&0x40; 
-                   if(temp1){
-                          SiS_SetReg1(SiS_Part3Port,0x13,0xFA); 
-                          SiS_SetReg1(SiS_Part3Port,0x14,0xC8); 
-                          SiS_SetReg1(SiS_Part3Port,0x3D,0xA8);
-                   }
-              }
-         }
+  tempbh = SiS_GetCH701x(SiS_Pr,0x74);
+  if((tempbh == 0xf6) || (tempbh == 0xc7)) {
+     tempbh = SiS_GetCH701x(SiS_Pr,0x73);
+     if(tempbh == 0xc8) {
+        if(SiS_Pr->SiS_LCDResInfo != SiS_Pr->SiS_Panel1400x1050) return;
+     } else if(tempbh == 0xdb) {
+        if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) return;
+     }
   }
- /*end add*/
-#endif
-  if(SiS_VBInfo&SetCRT2ToHiVisionTV) {
-    tempdi=SiS_HiTVGroup3Data;
-    if(SiS_SetFlag&TVSimuMode) {
-      tempdi=SiS_HiTVGroup3Simu;
-      if(!(modeflag&Charx8Dot)) {
-        tempdi=SiS_HiTVGroup3Text;
-      }
-    }
-    for(i=0;i<=0x3E;i++){
-       SiS_SetReg1(SiS_Part3Port,i,tempdi[i]);
-    }
+  for(i=0; i<0x0c; i++) {
+     SiS_SetCH701x(SiS_Pr,(tableptr[i] << 8) | regtable[i]);
   }
-  return;
+  SiS_Chrontel19f2(SiS_Pr);
+  tempbh = SiS_GetCH701x(SiS_Pr,0x1e);
+  tempbh |= 0xc0;
+  SiS_SetCH701x(SiS_Pr,(tempbh << 8) | 0x1e);	
 }
 
+/* TW: Chrontel 701x functions ================================= */
+
 void
-SiS_SetGroup4(USHORT  BaseAddr,ULONG ROMAddr,USHORT ModeNo,
-              USHORT ModeIdIndex,USHORT RefreshRateTableIndex,
-	      PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_Chrontel19f2(SiS_Private *SiS_Pr)
 {
-  USHORT tempax,tempcx,tempbx,modeflag,temp,temp2,push1;
-  ULONG tempebx,tempeax,templong;
+  UCHAR regtable[]  = { 0x67, 0x68, 0x69, 0x6a, 0x6b };
+  UCHAR table19e8[] = { 0x01, 0x02, 0x01, 0x01, 0x02 };
+  UCHAR table19ed[] = { 0x01, 0x02, 0x01, 0x01, 0x02 };
+  UCHAR *tableptr = NULL;
+  int i;
 
-  if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
+  if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+      tableptr = table19ed;
   } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
+      tableptr = table19e8;
   }
-  temp=SiS_RVBHCFACT;
-  SiS_SetReg1(SiS_Part4Port,0x13,temp);
 
-  tempbx=SiS_RVBHCMAX;
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_Part4Port,0x14,temp);
-  temp2=((tempbx&0xFF00)>>8)<<7;
-  
-  tempcx=SiS_VGAHT-1;
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part4Port,0x16,temp);
-  temp=((tempcx&0xFF00)>>8)<<3;
-  temp2=temp|temp2;
-
-  tempcx=SiS_VGAVT-1;
-  if(!(SiS_VBInfo&SetCRT2ToTV)){
-    tempcx=tempcx-5;
-  }
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part4Port,0x17,temp);
-  temp=temp2|((tempcx&0xFF00)>>8);
-  SiS_SetReg1(SiS_Part4Port,0x15,temp);
-
-  tempcx=SiS_VBInfo;
-  tempbx=SiS_VGAHDE;
-  if(modeflag&HalfDCLK){
-    tempbx=tempbx>>1;
-  }
-  if(tempcx&SetCRT2ToHiVisionTV) {
-       temp=0xA0;
-       if(tempbx!=1024) {
-           temp=0xC0;
-           if(tempbx!=1280) temp=0;
-       }
-  } else if((tempcx&SetCRT2ToTV)&&(SiS_VGAHDE==1024)) {       /*301b*/
-       temp=0xA0;
-  } else {
-       temp=0x80;
-       if(SiS_VBInfo&SetCRT2ToLCD){
-          temp=0;
-          if(tempbx>800) temp=0x60;
-       }
+  for(i=0; i<5; i++) {
+     SiS_SetCH701x(SiS_Pr,(tableptr[i] << 8) | regtable[i]);
   }
-  if(SiS_LCDResInfo!=Panel1280x1024) temp=temp|0x0A;
-  SiS_SetRegANDOR(SiS_Part4Port,0x0E,~0xEF,temp);
-
-  tempebx=SiS_VDE;
-  if(tempcx&SetCRT2ToHiVisionTV) {
-    /* if(!(tempax&0xE000)) tempbx=tempbx>>1; */
-    if(!(temp&0xE000)) tempbx=tempbx>>1;               /* alan ???? */
+}
 
-  }
+void
+SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr)
+{
+  USHORT temp;
 
-  tempcx=SiS_RVBHRS;
-  temp=tempcx&0x00FF;
-  SiS_SetReg1(SiS_Part4Port,0x18,temp);
-
-  tempebx=tempebx;
-  tempeax=SiS_VGAVDE;
-  tempcx=tempcx|0x04000;
-/*tempeax=tempeax-tempebx;  */
-  if(tempeax<=tempebx){
-    tempcx=((tempcx&0xFF00)^0x4000)|(tempcx&0x00ff);
-    tempeax=SiS_VGAVDE;
+  /* TW: Enable Chrontel 7019 LCD panel backlight */
+  if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+        temp = SiS_GetCH701x(SiS_Pr,0x66);
+        temp |= 0x20;
+	SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66);
   }
+}
 
-  else {
-    tempeax=tempeax-tempebx;
-  }
+void
+SiS_Chrontel701xOn(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
+{
+  USHORT temp;
 
-  push1=tempcx;
-  templong=(tempeax*256*1024)%tempebx;
-  tempeax=(tempeax*256*1024)/tempebx;
-  tempebx=tempeax;
-  if(templong!=0){
-    tempebx++;
-  }
-  tempcx=push1;
-  temp=(USHORT)(tempebx&0x000000FF);
-  SiS_SetReg1(SiS_Part4Port,0x1B,temp);
-  temp=(USHORT)((tempebx&0x0000FF00)>>8);
-  SiS_SetReg1(SiS_Part4Port,0x1A,temp);
-  tempbx=(USHORT) (tempebx>>16);
-  temp=tempbx&0x00FF;
-  temp=temp<<4;
-  temp=temp|((tempcx&0xFF00)>>8);
-  SiS_SetReg1(SiS_Part4Port,0x19,temp);
-
-  /*301b*/
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-         temp=0x0028;
-         SiS_SetReg1(SiS_Part4Port,0x1C,temp);
-         tempax=SiS_VGAHDE;
-          if(modeflag&HalfDCLK){
-           tempax=tempax>>1;
-           }
-          if(SiS_VBInfo&(SetCRT2ToLCD)) {
-             if(tempax>800)
-                tempax=tempax-800;
-          }
-          tempax=tempax-1;                
-                 
-         if(SiS_VBInfo&(SetCRT2ToTV|SetCRT2ToHiVisionTV)) {
-          if(SiS_VGAHDE>800)
-            {
-              if(SiS_VGAHDE==1024)
-                tempax=(tempax*25/32)-1;
-              else
-                  tempax=(tempax*20/32)-1;          
-            }
-         }
-         temp=(tempax&0xFF00)>>8;
-         temp=((temp&0x0003)<<4);
-         SiS_SetReg1(SiS_Part4Port,0x1E,temp);
-         temp=(tempax&0x00FF);
-         SiS_SetReg1(SiS_Part4Port,0x1D,temp);
-   
-         if(SiS_VBInfo&(SetCRT2ToTV|SetCRT2ToHiVisionTV)) {
-            if(SiS_VGAHDE>800){
-               SiS_SetRegOR(SiS_Part4Port,0x1E,0x08);
-            }
-         }
-         temp=0x0036;
-         if(SiS_VBInfo&SetCRT2ToTV) {
-             temp=temp|0x0001;
-         }
-         SiS_SetRegANDOR(SiS_Part4Port,0x1F,0x00C0,temp);
-         tempbx=(SiS_HT/2)-2;
-         temp=((tempbx&0x0700)>>8)<<3;
-         SiS_SetRegANDOR(SiS_Part4Port,0x21,0x00C0,temp);
-         temp=tempbx&0x00FF;
-         SiS_SetReg1(SiS_Part4Port,0x22,temp);
-         if( (SiS_VBType&(VB_SIS301LV|VB_SIS302LV)) && (SiS_VBInfo&SetCRT2ToLCD) ) {
-             SiS_SetReg1(SiS_Part4Port,0x24,0x0e);
-	 }
+  if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+     if(SiS_IsYPbPr(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+        temp = SiS_GetCH701x(SiS_Pr,0x01);
+	temp &= 0x3f;
+	temp |= 0x80;
+	SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x01);
+     }
+     SiS_SetCH701x(SiS_Pr,0x2049);   			/* TW: Enable TV path */
+     temp = SiS_GetCH701x(SiS_Pr,0x49);
+     if(SiS_IsYPbPr(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+        temp = SiS_GetCH701x(SiS_Pr,0x73);
+	temp |= 0x60;
+	SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x73);
+     }
+     temp = SiS_GetCH701x(SiS_Pr,0x47);
+     temp &= 0x7f;
+     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);
+     SiS_LongDelay(SiS_Pr,2);
+     temp = SiS_GetCH701x(SiS_Pr,0x47);
+     temp |= 0x80;
+     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);
   }
-  /*end 301b*/
-
-  SiS_SetCRT2VCLK(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwDeviceExtension);
 }
 
 void
-SiS_SetCRT2VCLK(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                 USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr)
 {
-  USHORT vclkindex;
-  USHORT tempah,temp1;
+  USHORT temp;
 
-  vclkindex = SiS_GetVCLK2Ptr(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwDeviceExtension);
-  /*301b*/
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-   	tempah = SiS_VBVCLKData[vclkindex].Part4_A;
-   	SiS_SetReg1(SiS_Part4Port,0x0A,tempah);
-   	tempah = SiS_VBVCLKData[vclkindex].Part4_B;
-   	SiS_SetReg1(SiS_Part4Port,0x0B,tempah);
-  } else {
-   	SiS_SetReg1(SiS_Part4Port,0x0A,0x01);
-   	tempah = SiS_VBVCLKData[vclkindex].Part4_B;
-   	SiS_SetReg1(SiS_Part4Port,0x0B,tempah);
-   	tempah = SiS_VBVCLKData[vclkindex].Part4_A;
-   	SiS_SetReg1(SiS_Part4Port,0x0A,tempah);
-  }
-  SiS_SetReg1(SiS_Part4Port,0x12,0x00);
-  tempah=0x08;
-  if(SiS_VBInfo&SetCRT2ToRAMDAC){
-    	tempah=tempah|0x020;
-  }
-  temp1=SiS_GetReg1(SiS_Part4Port,0x12);
-  tempah=tempah|temp1;
-  SiS_SetReg1(SiS_Part4Port,0x12,tempah);
+  /* TW: Disable Chrontel 7019 LCD panel backlight */
+  if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+        temp = SiS_GetCH701x(SiS_Pr,0x66);
+        temp &= 0xDF;
+	SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66);
+  }
 }
 
-USHORT
-SiS_GetVCLK2Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-        USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+void
+SiS_Chrontel701xOff(SiS_Private *SiS_Pr)
 {
-  USHORT tempbx;
-#ifdef SIS300
-  USHORT LCDXlat1VCLK300[4] = {VCLK65,VCLK65,VCLK65,VCLK65};
-  USHORT LCDXlat2VCLK300[4] = {VCLK108_2,VCLK108_2,VCLK108_2,VCLK108_2};
-  USHORT LVDSXlat2VCLK300[4]= {VCLK65,VCLK65,VCLK65,VCLK65};
-  USHORT LVDSXlat3VCLK300[4]= {VCLK65,VCLK65,VCLK65,VCLK65};
-#endif
-#ifdef SIS315H
-  USHORT LCDXlat1VCLK310[4] = {VCLK65+2,VCLK65+2,VCLK65+2,VCLK65+2};
-  USHORT LCDXlat2VCLK310[4] = {VCLK108_2+5,VCLK108_2+5,VCLK108_2+5,VCLK108_2+5};
-  USHORT LVDSXlat2VCLK310[4]= {VCLK65+2,VCLK65+2,VCLK65+2,VCLK65+2};
-  USHORT LVDSXlat3VCLK310[4]= {VCLK65+2,VCLK65+2,VCLK65+2,VCLK65+2};
-#endif
-  USHORT LVDSXlat1VCLK[4]   = {VCLK40,VCLK40,VCLK40,VCLK40};
-  USHORT CRT2Index,VCLKIndex;
-  USHORT modeflag,resinfo;
-  UCHAR *CHTVVCLKPtr=NULL;
-  USHORT *LCDXlatVCLK1=NULL;
-  USHORT *LCDXlatVCLK2=NULL;
-  USHORT *LVDSXlatVCLK2=NULL;
-  USHORT *LVDSXlatVCLK3=NULL;
+  USHORT temp;
 
-#ifdef SIS315H
-  if ( (HwDeviceExtension->jChipType==SIS_315H)||   
-       (HwDeviceExtension->jChipType==SIS_315PRO)||
-       (HwDeviceExtension->jChipType==SIS_550) ||
-       (HwDeviceExtension->jChipType==SIS_640) ||
-       (HwDeviceExtension->jChipType==SIS_740) ||
-       (HwDeviceExtension->jChipType==SIS_650)) {
-		LCDXlatVCLK1 = LCDXlat1VCLK310;
-		LCDXlatVCLK2 = LCDXlat2VCLK310;
-		LVDSXlatVCLK2 = LVDSXlat2VCLK310;
-		LVDSXlatVCLK3 = LVDSXlat3VCLK310;
-  } else {
-#endif
-#ifdef SIS300
-		LCDXlatVCLK1 = LCDXlat1VCLK300;
-		LCDXlatVCLK2 = LCDXlat2VCLK300;
-		LVDSXlatVCLK2 = LVDSXlat2VCLK300;
-		LVDSXlatVCLK3 = LVDSXlat3VCLK300;
-#endif
-#ifdef SIS315H
+  if(SiS_Pr->SiS_IF_DEF_CH70xx == 2) {
+        SiS_LongDelay(SiS_Pr,2);
+	/* TW: Complete power down of LVDS */
+	temp = SiS_GetCH701x(SiS_Pr,0x76);
+	temp &= 0xfc;
+	SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76);
+	SiS_SetCH701x(SiS_Pr,0x0066);
   }
-#endif
-
-  if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-    	resinfo = SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
-    	CRT2Index = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-    	resinfo = SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
-    	CRT2Index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-  }
-
-  if(SiS_IF_DEF_LVDS==0) {
-     CRT2Index = CRT2Index>>6;        /*  for LCD */
-     if((SiS_VBInfo&SetCRT2ToLCD)||(SiS_VBInfo&SetCRT2ToLCDA)){   /*301b*/
-      	if(SiS_LCDResInfo!=Panel1024x768){
-        	VCLKIndex = LCDXlatVCLK2[CRT2Index];
-      	} else {
-        	VCLKIndex = LCDXlatVCLK1[CRT2Index];
-      	}
-     } else {        /* for TV */
-      	if(SiS_VBInfo&SetCRT2ToTV) {
-        	if(SiS_IF_DEF_HiVision==1) {
-          		if(SiS_SetFlag&RPLLDIV2XO) {
-            			VCLKIndex=HiTVVCLKDIV2;
-            			if(HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */
-					/* VCLKIndex += 11;    for chip310  0x2E */
-              				VCLKIndex += 25;    /* for chip315  */
-            			}
-     			} else {
-            			VCLKIndex=HiTVVCLK;
-            			if(HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */
-					/*  VCLKIndex += 11;    for chip310  0x2E */
-              				VCLKIndex += 25;    /* for chip315  */
-            			}
-          		}
-          		if(SiS_SetFlag&TVSimuMode) {
-            			if(modeflag&Charx8Dot) {
-              				VCLKIndex=HiTVSimuVCLK;
-              					if(HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */
-							/*  VCLKIndex += 11;    for chip310  0x2E */
-              						VCLKIndex += 25;    /* for chip315  */
-              					}
-            			} else {
-              				VCLKIndex=HiTVTextVCLK;
-              				if(HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */
-						/*  VCLKIndex += 11;    for chip310  0x2E */
-              					VCLKIndex += 25;    /* for chip315  */
-              				}
-            			}
-          		}
-        	} else {
-          		if(SiS_VBInfo&SetCRT2ToTV) {
-            			if(SiS_SetFlag&RPLLDIV2XO) {
-              				VCLKIndex=TVVCLKDIV2;
-              					if(HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */
-							/* VCLKIndex += 11;    for chip310  0x2E */
-              						VCLKIndex += 25;    /* for chip315  */
-              					}
-            			} else {
-              				VCLKIndex=TVVCLK;
-              				if(HwDeviceExtension->jChipType >= SIS_315H) { /* 310 series */
-						/* VCLKIndex += 11;    for chip310  0x2E */
-              					VCLKIndex += 25;    /* for chip315  */
-              				}
-            			}
-          		}
-        	}
-      } else {    /* for CRT2 */
-        	VCLKIndex = (UCHAR)SiS_GetReg2((USHORT)(SiS_P3ca+0x02));      /*  Port 3cch */
-        	VCLKIndex =((VCLKIndex>>2)&0x03);
-        	if(ModeNo>0x13) {
-          		VCLKIndex =
-			    SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;    /* di+Ext_CRTVCLK */
-          		VCLKIndex = VCLKIndex&0x3f;
-        	}
-      }
-    }
-  } else {       /*   LVDS  */
-    	if(ModeNo<=0x13) VCLKIndex = CRT2Index;
-    	else VCLKIndex = CRT2Index;
-#ifdef LINUX_XF86
-	xf86DrvMsg(0, X_INFO, "CRT2Index = %d\n", CRT2Index);
-#endif
-	/* TW: This does not make sense: If CH7005 is there but CRT2 is set to
-	 *     LCD, VCLKindex is returned untouched...
-	 *     (Inserted SlaveMode check for 8bpp modes later)
-	 */
+}
 
-#if 1
-    	if((SiS_IF_DEF_CH7005==1) && (!(SiS_VBInfo&SetInSlaveMode))) {
-      		if(!(SiS_VBInfo&SetCRT2ToLCD)) {
-#else
+void
+SiS_ChrontelResetDB(SiS_Private *SiS_Pr)
+{
+     /* TW: Reset Chrontel 7019 datapath */
+     SiS_SetCH701x(SiS_Pr,0x1048);
+     SiS_LongDelay(SiS_Pr,1);
+     SiS_SetCH701x(SiS_Pr,0x1848);
+}
 
-/* 	TW: If we do it this way instead, some machines (MITAC) have problems 		*/
-	if((SiS_IF_DEF_CH7005==1) && (SiS_VBInfo&SetCRT2ToTV)) {
-#endif
+void
+SiS_ChrontelDoSomething4(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
+{
+     USHORT temp;
 
-        		VCLKIndex = VCLKIndex&0x1f;
-        		tempbx=0;
-        		if(SiS_VBInfo&SetPALTV) tempbx=tempbx+2;
-        		if(SiS_VBInfo&SetCHTVOverScan) tempbx=tempbx+1;
-       			switch(tempbx) {
-          			case 0: CHTVVCLKPtr=SiS_CHTVVCLKUNTSC;
-					break;
-          			case 1: CHTVVCLKPtr=SiS_CHTVVCLKONTSC;
-					break;
-          			case 2: CHTVVCLKPtr=SiS_CHTVVCLKUPAL;
-					break;
-          			case 3: CHTVVCLKPtr=SiS_CHTVVCLKOPAL;
-					break;
-        		}
-        		VCLKIndex=CHTVVCLKPtr[VCLKIndex];
-      		}  
-    	} else {
-     		VCLKIndex = VCLKIndex>>6;
-     		if((SiS_LCDResInfo==Panel800x600)||(SiS_LCDResInfo==Panel320x480))
-     			VCLKIndex = LVDSXlat1VCLK[VCLKIndex]; /*fstn*/
-     		else if(SiS_LCDResInfo==Panel1024x768)
-     			VCLKIndex = LVDSXlatVCLK2[VCLKIndex];
-     		else 	VCLKIndex = LVDSXlatVCLK3[VCLKIndex];
-    	}
-  }
-  if(HwDeviceExtension->jChipType < SIS_315H) { /* for300 serial*/
-    	VCLKIndex=VCLKIndex&0x3F;
-  }
-  return (VCLKIndex);
+     SiS_SetCH701x(SiS_Pr,0xaf76);
+     temp = SiS_GetCH701x(SiS_Pr,0x49);
+     temp &= 1;
+     if(temp != 1) {
+	temp = SiS_GetCH701x(SiS_Pr,0x47);
+	temp &= 0x70;
+	SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);
+	SiS_LongDelay(SiS_Pr,3);
+	temp = SiS_GetCH701x(SiS_Pr,0x47);
+	temp |= 0x80;
+	SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x47);
+     }
 }
 
 void
-SiS_SetGroup5(USHORT  BaseAddr,ULONG ROMAddr,USHORT ModeNo,
-              USHORT ModeIdIndex)
+SiS_ChrontelDoSomething3(SiS_Private *SiS_Pr, USHORT ModeNo,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                         USHORT BaseAddr)
 {
-  USHORT Pindex,Pdata;
+     USHORT temp,temp1;
 
-  Pindex=SiS_Part5Port;
-  Pdata=SiS_Part5Port+1;
-  if(SiS_ModeType==ModeVGA){
-    if(!(SiS_VBInfo&(SetInSlaveMode|LoadDACFlag|CRT2DisplayFlag))){
-      SiS_EnableCRT2();
-/*    LoadDAC2(ROMAddr,SiS_Part5Port,ModeNo,ModeIdIndex);  */
-    }
-  }
-  return;
+     temp1 = 0;
+     temp = SiS_GetCH701x(SiS_Pr,0x61);
+     if(temp < 2) {
+          temp++;
+	  SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x61);
+	  temp1 = 1;
+     }
+     SiS_SetCH701x(SiS_Pr,0xac76);
+     temp = SiS_GetCH701x(SiS_Pr,0x66);
+     temp |= 0x5f;
+     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66);
+     if(ModeNo > 0x13) {
+         if(SiS_WeHaveBacklightCtrl(SiS_Pr,HwDeviceExtension, BaseAddr)) {
+	    SiS_GenericDelay(SiS_Pr,0x3ff);
+	 } else {
+	    SiS_GenericDelay(SiS_Pr,0x2ff);
+	 }
+     } else {
+         if(!temp1)
+	    SiS_GenericDelay(SiS_Pr,0x2ff);
+     }
+     temp = SiS_GetCH701x(SiS_Pr,0x76);
+     temp |= 0x03;
+     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76);
+     temp = SiS_GetCH701x(SiS_Pr,0x66);
+     temp &= 0x7f;
+     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x66);
+     SiS_LongDelay(SiS_Pr,1);
 }
 
 void
-SiS_LoadDAC2(ULONG ROMAddr,USHORT SiS_Part5Port,
-             USHORT ModeNo,USHORT ModeIdIndex)
+SiS_ChrontelDoSomething2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr)
 {
-   USHORT data,data2;
-   USHORT time,i,j,k;
-   USHORT m,n,o;
-   USHORT si,di,bx,dl;
-   USHORT al,ah,dh;
-   USHORT *table=0;
-   USHORT Pindex,Pdata,modeflag;
+     USHORT temp,tempcl,tempch;
 
-  if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-  }
+     SiS_LongDelay(SiS_Pr, 1);
+     tempcl = 3;
+     tempch = 0;
 
-   Pindex=SiS_Part5Port;
-   Pdata=SiS_Part5Port+1;
-   data=modeflag&DACInfoFlag;
-   time=64;
-   if(data==0x00) table=SiS_MDA_DAC;
-   if(data==0x08) table=SiS_CGA_DAC;
-   if(data==0x10) table=SiS_EGA_DAC;
-   if(data==0x18) {
-     time=256;
-     table=SiS_VGA_DAC;
-   }
-   if(time==256) j=16;
-   else j=time;
+     do {
+       temp = SiS_GetCH701x(SiS_Pr,0x66);
+       temp &= 0x04;
+       if(temp == 0x04) break;
 
-   SiS_SetReg3(Pindex,0x00);
+       SiS_SetCH701xForLCD(SiS_Pr,HwDeviceExtension, BaseAddr);
 
-   for(i=0;i<j;i++) {
-      data=table[i];
-      for(k=0;k<3;k++) {
-        data2=0;
-        if(data&0x01) data2=0x2A;
-        if(data&0x02) data2=data2+0x15;
-        SiS_SetReg3(Pdata,data2);
-        data=data>>2;
-      }
-   }
+       if(tempcl == 0) {
+           if(tempch == 3) break;
+	   SiS_ChrontelResetDB(SiS_Pr);
+	   tempcl = 3;
+	   tempch++;
+       }
+       tempcl--;
+       temp = SiS_GetCH701x(SiS_Pr,0x76);
+       temp &= 0xfb;
+       SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76);
+       SiS_LongDelay(SiS_Pr,2);
+       temp = SiS_GetCH701x(SiS_Pr,0x76);
+       temp |= 0x04;
+       SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x76);
+       SiS_SetCH701x(SiS_Pr,0x6078);
+       SiS_LongDelay(SiS_Pr,2);
+    } while(0);
 
-   if(time==256) {
-      for(i=16;i<32;i++) {
-         data=table[i];
-         for(k=0;k<3;k++) SiS_SetReg3(Pdata,data);
-      }
-      si=32;
-      for(m=0;m<9;m++) {
-         di=si;
-         bx=si+0x04;
-         dl=0;
-         for(n=0;n<3;n++) {
-            for(o=0;o<5;o++) {
-              dh=table[si];
-              ah=table[di];
-              al=table[bx];
-              si++;
-              SiS_WriteDAC2(Pdata,dl,ah,al,dh);
-            }         /* for 5 */
-            si=si-2;
-            for(o=0;o<3;o++) {
-              dh=table[bx];
-              ah=table[di];
-              al=table[si];
-              si--;
-              SiS_WriteDAC2(Pdata,dl,ah,al,dh);
-            }         /* for 3 */
-            dl++;
-         }            /* for 3 */
-         si=si+5;
-      }               /* for 9 */
-   }
+    SiS_SetCH701x(SiS_Pr,0x0077);
 }
 
 void
-SiS_WriteDAC2(USHORT Pdata,USHORT dl, USHORT ah, USHORT al, USHORT dh)
+SiS_ChrontelDoSomething1(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                         USHORT BaseAddr)
 {
-  USHORT temp;
-  USHORT bh,bl;
-
-  bh=ah;
-  bl=al;
-  if(dl!=0) {
-    temp=bh;
-    bh=dh;
-    dh=temp;
-    if(dl==1) {
-       temp=bl;
-       bl=dh;
-       dh=temp;
-    }
-    else {
-       temp=bl;
-       bl=bh;
-       bh=temp;
-    }
-  }
-  SiS_SetReg3(Pdata,(USHORT)dh);
-  SiS_SetReg3(Pdata,(USHORT)bh);
-  SiS_SetReg3(Pdata,(USHORT)bl);
-}
+     USHORT temp;
 
-/* TW: Start of Chrontel 7005 functions ---------------------------- */
+     temp = SiS_GetCH701x(SiS_Pr,0x03);
+     temp |= 0x80;
+     temp &= 0xbf;
+     SiS_SetCH701x(SiS_Pr,(temp << 8) | 0x03);
 
-void
-SiS_SetCHTVReg(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-               USHORT RefreshRateTableIndex)
-{
-  USHORT temp,tempbx,tempcl;
-/*  USHORT CRT2CRTC; */
-  USHORT TVType,resindex;
-  SiS_CHTVRegDataStruct *CHTVRegData=NULL;
-
-  if(ModeNo<=0x13){
-    	tempcl = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-  }else{
-    	tempcl = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-  }
-  TVType = 0;
-  if(SiS_VBInfo&SetPALTV) TVType=TVType+2;
-  if(SiS_VBInfo&SetCHTVOverScan) TVType=TVType+1;
-  switch(TVType) {
-    	case 0: CHTVRegData = SiS_CHTVReg_UNTSC; break;
-    	case 1: CHTVRegData = SiS_CHTVReg_ONTSC; break;
-    	case 2: CHTVRegData = SiS_CHTVReg_UPAL;  break;
-    	case 3: CHTVRegData = SiS_CHTVReg_OPAL;  break;
-  }
-  resindex=tempcl&0x3F;
-
-  /* TW: We don't support modes >800x600 */
-  if (resindex > 5) return;
-
-  if(SiS_VBInfo&SetPALTV) {
-    	SiS_SetCH7005(0x4304);  /* TW: 0x40=76uA (PAL); 0x03=15bit non-multi RGB*/
-    	SiS_SetCH7005(0x6909);	/* TW: Black level for PAL (105)*/
-  } else {
-    	SiS_SetCH7005(0x0304);  /* TW: upper nibble=71uA (NTSC), 0x03=15bit non-multi RGB*/
-    	SiS_SetCH7005(0x7109);	/* TW: Black level for NTSC (113)*/
-  }
-
-  temp = CHTVRegData[resindex].Reg[0];
-  tempbx=((temp&0x00FF)<<8)|0x00;	/* TW: Mode register */
-  SiS_SetCH7005(tempbx);
-  temp = CHTVRegData[resindex].Reg[1];
-  tempbx=((temp&0x00FF)<<8)|0x07;	/* TW: Start active video register */
-  SiS_SetCH7005(tempbx);
-  temp = CHTVRegData[resindex].Reg[2];
-  tempbx=((temp&0x00FF)<<8)|0x08;	/* TW: Position overflow register */
-  SiS_SetCH7005(tempbx);
-  temp = CHTVRegData[resindex].Reg[3];
-  tempbx=((temp&0x00FF)<<8)|0x0A;	/* TW: Horiz Position register */
-  SiS_SetCH7005(tempbx);
-  temp = CHTVRegData[resindex].Reg[4];
-  tempbx=((temp&0x00FF)<<8)|0x0B;	/* TW: Vertical Position register */
-  SiS_SetCH7005(tempbx);
-
-  /* TW: Set minimum flicker filter for Luma channel (SR1-0=00),
-             minimum text enhancement (S3-2=10),
-	     maximum flicker filter for Chroma channel (S5-4=10)
-	     =00101000=0x28 (When reading, S1-0->S3-2, and S3-2->S1-0!)
-   */
-  SiS_SetCH7005(0x2801);
+     SiS_ChrontelResetDB(SiS_Pr);
 
-  /* TW: Set video bandwidth
-         High bandwith Luma composite video filter(S0=1)
-         low bandwith Luma S-video filter (S2-1=00)
-	 disable peak filter in S-video channel (S3=0)
-	 high bandwidth Chroma Filter (S5-4=11)
-	 =00110001=0x31
-  */
-  SiS_SetCH7005(0xb103);       /* old: 3103 */
+     SiS_ChrontelDoSomething2(SiS_Pr,HwDeviceExtension, BaseAddr);
 
-  /* TW: Register 0x3D does not exist in non-macrovision register map
-         (Maybe this is a macrovision register?)
-   */
-  /* SiS_SetCH7005(0x003D); */
+     temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x34);
+     SiS_ChrontelDoSomething3(SiS_Pr,temp, HwDeviceExtension, BaseAddr);
 
-  /* TW: Register 0x10 only contains 1 writable bit (S0) for sensing,
-         all other bits a read-only. Macrovision?
-   */
-  SiS_SetCHTVRegANDOR(0x0010,0x1F);
+     SiS_SetCH701x(SiS_Pr,0xaf76);
+}
 
-  /* TW: Register 0x11 only contains 3 writable bits (S0-S2) for
-         contrast enhancement (set to 010 -> gain 2 Yout = 9/8*(Yin-57) )
-   */
-  SiS_SetCHTVRegANDOR(0x0211,0xF8);
+/* TW: End of Chrontel 701x functions ==================================== */
 
-  /* TW: Clear DSEN
-   */
-  SiS_SetCHTVRegANDOR(0x001C,0xEF);
+/* TW: Generic Read/write routines for Chrontel ========================== */
 
-  if(!(SiS_VBInfo&SetPALTV)) {		/* ---- NTSC ---- */
-    tempcl=tempcl&0x3F;
-    if(SiS_VBInfo&SetCHTVOverScan) {
-      if(tempcl==0x04) {   			/* 640x480 overscan: Mode 16 */
-      	SiS_SetCHTVRegANDOR(0x0020,0xEF);   	/* loop filter off */
-        SiS_SetCHTVRegANDOR(0x0121,0xFE);       /* ACIV on, no need to set FSCI */
-      } else {
-        if(tempcl==0x05) {    			/* 800x600 overscan: Mode 23 */
-          SiS_SetCHTVRegANDOR(0x0118,0xF0);	/* 0x18-0x1f: FSCI 469,762,048 */
-          SiS_SetCHTVRegANDOR(0x0C19,0xF0);
-          SiS_SetCHTVRegANDOR(0x001A,0xF0);
-          SiS_SetCHTVRegANDOR(0x001B,0xF0);
-          SiS_SetCHTVRegANDOR(0x001C,0xF0);
-          SiS_SetCHTVRegANDOR(0x001D,0xF0);
-          SiS_SetCHTVRegANDOR(0x001E,0xF0);
-          SiS_SetCHTVRegANDOR(0x001F,0xF0);
-          SiS_SetCHTVRegANDOR(0x1020,0xEF);     /* Loop filter on for mode 23 */
-          SiS_SetCHTVRegANDOR(0x0021,0xFE);     /* ACIV off, need to set FSCI */
-        }
-      }
-    } else {
-      if(tempcl==0x04) {     			/* ----- 640x480 underscan; Mode 17 */
-        SiS_SetCHTVRegANDOR(0x0020,0xEF); 	/* loop filter off */
-        SiS_SetCHTVRegANDOR(0x0121,0xFE);
-      } else {
-        if(tempcl==0x05) {   			/* ----- 800x600 underscan: Mode 24 */
-          SiS_SetCHTVRegANDOR(0x0118,0xF0);     /* (FSCI was 0x1f1c71c7 - this is for mode 22) */
-          SiS_SetCHTVRegANDOR(0x0919,0xF0);	/* FSCI for mode 24 is 428,554,851 */
-          SiS_SetCHTVRegANDOR(0x081A,0xF0);
-          SiS_SetCHTVRegANDOR(0x0b1B,0xF0);
-          SiS_SetCHTVRegANDOR(0x031C,0xF0);
-          SiS_SetCHTVRegANDOR(0x0a1D,0xF0);
-          SiS_SetCHTVRegANDOR(0x061E,0xF0);
-          SiS_SetCHTVRegANDOR(0x031F,0xF0);
-          SiS_SetCHTVRegANDOR(0x0020,0xEF);     /* loop filter off for mode 24 */
-          SiS_SetCHTVRegANDOR(0x0021,0xFE);	/* ACIV off, need to set FSCI */
-        }
-      }
-    }
-  } else {				/* ---- PAL ---- */
-        /* TW: We don't play around with FSCI in PAL mode */
-      if (tempcl==0x04) {
-        SiS_SetCHTVRegANDOR(0x0020,0xEF); 	/* loop filter off */
-        SiS_SetCHTVRegANDOR(0x0121,0xFE);       /* ACIV on */
-      } else {
-        SiS_SetCHTVRegANDOR(0x0020,0xEF); 	/* loop filter off */
-        SiS_SetCHTVRegANDOR(0x0121,0xFE);       /* ACIV on */
-      }
-  }
+/* TW: The Chrontel is connected to the 630/730 via
+ * the 630/730's DDC/I2C port.
+ *
+ * On 630(S)T chipset, the index changed from 0x11 to 0x0a,
+ * possibly for working around the DDC problems
+ */
+
+void
+SiS_SetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx)
+{
+   if (SiS_Pr->SiS_IF_DEF_CH70xx == 1)
+      SiS_SetCH700x(SiS_Pr,tempbx);
+   else
+      SiS_SetCH701x(SiS_Pr,tempbx);
 }
 
+/* TW: Write to Chrontel 700x */
+/* Parameter is [Data (S15-S8) | Register no (S7-S0)] */
 void
-SiS_SetCHTVRegANDOR(USHORT tempax,USHORT tempbh)
+SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempbx)
 {
-  USHORT tempal,tempah,tempbl;
+  USHORT tempah,temp,i;
+
+  if(!(SiS_Pr->SiS_ChrontelInit)) {
+     SiS_Pr->SiS_DDC_Index = 0x11;		   /* TW: Bit 0 = SC;  Bit 1 = SD */
+     SiS_Pr->SiS_DDC_Data  = 0x02;                 /* Bitmask in IndexReg for Data */
+     SiS_Pr->SiS_DDC_Clk   = 0x01;                 /* Bitmask in IndexReg for Clk */
+     SiS_Pr->SiS_DDC_DataShift = 0x00;
+     SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;  	   /* TW: DAB (Device Address Byte) */
+  }
+
+  for(i=0;i<10;i++) {	/* TW: Do only 10 attempts to write */
+    /* SiS_SetSwitchDDC2(SiS_Pr); */
+    if(SiS_SetStart(SiS_Pr)) continue;		/* TW: Set start condition */
+    tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: Write DAB (S0=0=write) */
+    if(temp) continue;				/* TW:    (ERROR: no ack) */
+    tempah = tempbx & 0x00FF;			/* TW: Write RAB */
+    tempah |= 0x80;                             /* TW: (set bit 7, see datasheet) */
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);
+    if(temp) continue;				/* TW:    (ERROR: no ack) */
+    tempah = (tempbx & 0xFF00) >> 8;
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: Write data */
+    if(temp) continue;				/* TW:    (ERROR: no ack) */
+    if(SiS_SetStop(SiS_Pr)) continue;		/* TW: Set stop condition */
+    SiS_Pr->SiS_ChrontelInit = 1;
+    return;
+  }
 
-  tempal=tempax&0x00FF;
-  tempah=(tempax>>8)&0x00FF;
-  tempbl=SiS_GetCH7005(tempal);
-  tempbl=(((tempbl&tempbh)|tempah)<<8|tempal);  
-  SiS_SetCH7005(tempbl);
+  /* TW: For 630ST */
+  if(!(SiS_Pr->SiS_ChrontelInit)) {
+     SiS_Pr->SiS_DDC_Index = 0x0a;		/* TW: Bit 7 = SC;  Bit 6 = SD */
+     SiS_Pr->SiS_DDC_Data  = 0x80;              /* Bitmask in IndexReg for Data */
+     SiS_Pr->SiS_DDC_Clk   = 0x40;              /* Bitmask in IndexReg for Clk */
+     SiS_Pr->SiS_DDC_DataShift = 0x00;
+     SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;  	/* TW: DAB (Device Address Byte) */
+
+     for(i=0;i<10;i++) {	/* TW: Do only 10 attempts to write */
+       /* SiS_SetSwitchDDC2(SiS_Pr); */
+       if (SiS_SetStart(SiS_Pr)) continue;	/* TW: Set start condition */
+       tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+       temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: Write DAB (S0=0=write) */
+       if(temp) continue;			/* TW:    (ERROR: no ack) */
+       tempah = tempbx & 0x00FF;		/* TW: Write RAB */
+       tempah |= 0x80;                          /* TW: (set bit 7, see datasheet) */
+       temp = SiS_WriteDDC2Data(SiS_Pr,tempah);
+       if(temp) continue;			/* TW:    (ERROR: no ack) */
+       tempah = (tempbx & 0xFF00) >> 8;
+       temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: Write data */
+       if(temp) continue;			/* TW:    (ERROR: no ack) */
+       if(SiS_SetStop(SiS_Pr)) continue;	/* TW: Set stop condition */
+       SiS_Pr->SiS_ChrontelInit = 1;
+       return;
+    }
+  }
 }
 
-/* TW: Write to Chrontel 7005 */
+/* TW: Write to Chrontel 701x */
 /* Parameter is [Data (S15-S8) | Register no (S7-S0)] */
 void
-SiS_SetCH7005(USHORT tempbx)
+SiS_SetCH701x(SiS_Private *SiS_Pr, USHORT tempbx)
 {
   USHORT tempah,temp,i;
 
-  /* TW: This has to be relative to BaseAddr */
-  /* SiS_DDC_Port=0x3c4; */
-  SiS_DDC_Index=0x11;			/* TW: Bit 0 = SC;  Bit 1 = SD */
-  SiS_DDC_DataShift=0x00;
-  SiS_DDC_DeviceAddr=0xEA;  		/* TW: DAB (Device Address Byte) */
-
-  for(i=0;i<50;i++) {	/* TW: Do only 50 attempts to write */
-    SiS_SetSwitchDDC2();
-    SiS_SetStart();			/* TW: Set start condition */
-    tempah=SiS_DDC_DeviceAddr;
-    temp=SiS_WriteDDC2Data(tempah);	/* TW: Write DAB (S0=0=write) */
-    if(temp) continue;			/* TW:    (ERROR: no ack) */
-    tempah=tempbx&0x00FF;
-    temp=SiS_WriteDDC2Data(tempah);	/* TW: Write RAB */
-    if(temp) continue;			/* TW:    (ERROR: no ack) */
-    tempah=(tempbx&0xFF00)>>8;
-    temp=SiS_WriteDDC2Data(tempah);	/* TW: Write data */
-    if(temp) continue;			/* TW:    (ERROR: no ack) */
-    SiS_SetStop();			/* TW: Set stop condition */
+  SiS_Pr->SiS_DDC_Index = 0x11;			/* TW: Bit 0 = SC;  Bit 1 = SD */
+  SiS_Pr->SiS_DDC_Data  = 0x08;                 /* Bitmask in IndexReg for Data */
+  SiS_Pr->SiS_DDC_Clk   = 0x04;                 /* Bitmask in IndexReg for Clk */
+  SiS_Pr->SiS_DDC_DataShift = 0x00;
+  SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;  		/* TW: DAB (Device Address Byte) */
+
+  for(i=0;i<10;i++) {	/* TW: Do only 10 attempts to write */
+    if (SiS_SetStart(SiS_Pr)) continue;		/* TW: Set start condition */
+    tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: Write DAB (S0=0=write) */
+    if(temp) continue;				/* TW:    (ERROR: no ack) */
+    tempah = tempbx & 0x00FF;
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: Write RAB */
+    if(temp) continue;				/* TW:    (ERROR: no ack) */
+    tempah = (tempbx & 0xFF00) >> 8;
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: Write data */
+    if(temp) continue;				/* TW:    (ERROR: no ack) */
+    if(SiS_SetStop(SiS_Pr)) continue;		/* TW: Set stop condition */
     return;
   }
 }
 
+/* TW: Read from Chrontel 70xx */
+/* Parameter is [Register no (S7-S0)] */
+USHORT
+SiS_GetCH70xx(SiS_Private *SiS_Pr, USHORT tempbx)
+{
+   if (SiS_Pr->SiS_IF_DEF_CH70xx == 1)
+      return(SiS_GetCH700x(SiS_Pr,tempbx));
+   else
+      return(SiS_GetCH701x(SiS_Pr,tempbx));
+}
+
+/* TW: Read from Chrontel 700x */
+/* Parameter is [Register no (S7-S0)] */
 USHORT
-SiS_GetCH7005(USHORT tempbx)
+SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempbx)
 {
   USHORT tempah,temp,i;
 
-  /* TW: This has to be relative to BaseAddr, set by RegInit */
-  /* SiS_DDC_Port=0x3c4; */
-  SiS_DDC_Index=0x11;			/* TW: Bit 0 = SC;  Bit 1 = SD */
-  SiS_DDC_DataShift=0x00;
-  SiS_DDC_DeviceAddr=0xEA;		/* TW: DAB */
-  SiS_DDC_ReadAddr=tempbx;
-
-  for(i=0;i<50;i++) {	/* TW: Do only 50 attempts to write */
-    SiS_SetSwitchDDC2();
-    SiS_SetStart();			/* TW: Set start condition */
-    tempah=SiS_DDC_DeviceAddr;
-    temp=SiS_WriteDDC2Data(tempah);	/* TW: Write DAB (S0=0=write) */
-    if(temp) continue;			/* TW:        (ERROR: no ack) */
-    tempah=SiS_DDC_ReadAddr;		/* TW: Write RAB */
-    temp=SiS_WriteDDC2Data(tempah);
-    if(temp) continue;			/* TW:        (ERROR: no ack) */
-    SiS_SetStart();			/* TW: Re-start */
-    tempah=SiS_DDC_DeviceAddr;
-    tempah=tempah|0x01;
-    temp=SiS_WriteDDC2Data(tempah);	/* TW: DAB (S0=1=read) */
-    if(temp) continue;			/* TW:        (ERROR: no ack) */
-    tempah=SiS_ReadDDC2Data(tempah);	/* TW: Read byte */
-    SiS_SetStop();			/* TW: Stop condition */
+  if(!(SiS_Pr->SiS_ChrontelInit)) {
+     SiS_Pr->SiS_DDC_Index = 0x11;		/* TW: Bit 0 = SC;  Bit 1 = SD */
+     SiS_Pr->SiS_DDC_Data  = 0x02;              /* Bitmask in IndexReg for Data */
+     SiS_Pr->SiS_DDC_Clk   = 0x01;              /* Bitmask in IndexReg for Clk */
+     SiS_Pr->SiS_DDC_DataShift = 0x00;
+     SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;		/* TW: DAB */
+  }
+
+  SiS_Pr->SiS_DDC_ReadAddr = tempbx;
+
+  for(i=0;i<20;i++) {	/* TW: Do only 20 attempts to read */
+    /* SiS_SetSwitchDDC2(SiS_Pr); */
+    if(SiS_SetStart(SiS_Pr)) continue;		/* TW: Set start condition */
+    tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: Write DAB (S0=0=write) */
+    if(temp) continue;				/* TW:        (ERROR: no ack) */
+    tempah = SiS_Pr->SiS_DDC_ReadAddr | 0x80;	/* TW: Write RAB | 0x80 */
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);
+    if(temp) continue;				/* TW:        (ERROR: no ack) */
+    if (SiS_SetStart(SiS_Pr)) continue;		/* TW: Re-start */
+    tempah = SiS_Pr->SiS_DDC_DeviceAddr | 0x01; /* DAB | 0x01 = Read */
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: DAB (S0=1=read) */
+    if(temp) continue;				/* TW:        (ERROR: no ack) */
+    tempah = SiS_ReadDDC2Data(SiS_Pr,tempah);	/* TW: Read byte */
+    if (SiS_SetStop(SiS_Pr)) continue;		/* TW: Stop condition */
+    SiS_Pr->SiS_ChrontelInit = 1;
     return(tempah);
   }
-  return(tempah);
+
+  /* TW: For 630ST */
+  if(!SiS_Pr->SiS_ChrontelInit) {
+     SiS_Pr->SiS_DDC_Index = 0x0a;		/* TW: Bit 0 = SC;  Bit 1 = SD */
+     SiS_Pr->SiS_DDC_Data  = 0x80;              /* Bitmask in IndexReg for Data */
+     SiS_Pr->SiS_DDC_Clk   = 0x40;              /* Bitmask in IndexReg for Clk */
+     SiS_Pr->SiS_DDC_DataShift = 0x00;
+     SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;  	/* TW: DAB (Device Address Byte) */
+
+     for(i=0;i<20;i++) {	/* TW: Do only 20 attempts to read */
+       /* SiS_SetSwitchDDC2(SiS_Pr); */
+       if(SiS_SetStart(SiS_Pr)) continue;		/* TW: Set start condition */
+       tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+       temp = SiS_WriteDDC2Data(SiS_Pr,tempah);		/* TW: Write DAB (S0=0=write) */
+       if(temp) continue;				/* TW:        (ERROR: no ack) */
+       tempah = SiS_Pr->SiS_DDC_ReadAddr | 0x80;	/* TW: Write RAB | 0x80 */
+       temp = SiS_WriteDDC2Data(SiS_Pr,tempah);
+       if(temp) continue;				/* TW:        (ERROR: no ack) */
+       if (SiS_SetStart(SiS_Pr)) continue;		/* TW: Re-start */
+       tempah = SiS_Pr->SiS_DDC_DeviceAddr | 0x01; 	/* DAB | 0x01 = Read */
+       temp = SiS_WriteDDC2Data(SiS_Pr,tempah);		/* TW: DAB (S0=1=read) */
+       if(temp) continue;				/* TW:        (ERROR: no ack) */
+       tempah = SiS_ReadDDC2Data(SiS_Pr,tempah);	/* TW: Read byte */
+       if (SiS_SetStop(SiS_Pr)) continue;		/* TW: Stop condition */
+       SiS_Pr->SiS_ChrontelInit = 1;
+       return(tempah);
+     }
+  }
+  return(0xFFFF);
 }
 
-void
-SiS_SetSwitchDDC2(void)
+/* TW: Read from Chrontel 701x */
+/* Parameter is [Register no (S7-S0)] */
+USHORT
+SiS_GetCH701x(SiS_Private *SiS_Pr, USHORT tempbx)
 {
-  USHORT i;
+  USHORT tempah,temp,i;
 
-  SiS_SetSCLKHigh();
-  for(i=0;i<1000;i++) {
-    SiS_GetReg1(SiS_DDC_Port,0x05);
-  }
-  SiS_SetSCLKLow();
-  for(i=0;i<1000;i++) {
-    SiS_GetReg1(SiS_DDC_Port,0x05);
-  }
+  SiS_Pr->SiS_DDC_Index = 0x11;			/* TW: Bit 0 = SC;  Bit 1 = SD */
+  SiS_Pr->SiS_DDC_Data  = 0x08;                 /* Bitmask in IndexReg for Data */
+  SiS_Pr->SiS_DDC_Clk   = 0x04;                 /* Bitmask in IndexReg for Clk */
+  SiS_Pr->SiS_DDC_DataShift = 0x00;
+  SiS_Pr->SiS_DDC_DeviceAddr = 0xEA;		/* TW: DAB */
+  SiS_Pr->SiS_DDC_ReadAddr = tempbx;
+
+   for(i=0;i<20;i++) {	/* TW: Do only 20 attempts to read */
+    if(SiS_SetStart(SiS_Pr)) continue;		/* TW: Set start condition */
+    tempah = SiS_Pr->SiS_DDC_DeviceAddr;
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: Write DAB (S0=0=write) */
+    if(temp) continue;				/* TW:        (ERROR: no ack) */
+    tempah = SiS_Pr->SiS_DDC_ReadAddr;		/* TW: Write RAB */
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);
+    if(temp) continue;				/* TW:        (ERROR: no ack) */
+    if (SiS_SetStart(SiS_Pr)) continue;		/* TW: Re-start */
+    tempah = SiS_Pr->SiS_DDC_DeviceAddr | 0x01; /* DAB | 0x01 = Read */
+    temp = SiS_WriteDDC2Data(SiS_Pr,tempah);	/* TW: DAB (S0=1=read) */
+    if(temp) continue;				/* TW:        (ERROR: no ack) */
+    tempah = SiS_ReadDDC2Data(SiS_Pr,tempah);	/* TW: Read byte */
+    SiS_SetStop(SiS_Pr);			/* TW: Stop condition */
+    return(tempah);
+   }
+  return 0xFFFF;
 }
 
-/* TW: Set Chrontel 7005 start condition */
-/* TW: This is done by a SD high-to-low transition while SC is high */
-void
-SiS_SetStart(void)
+#ifdef LINUX_XF86
+/* TW: Our own DDC functions */
+USHORT
+SiS_InitDDCRegs(SiS_Private *SiS_Pr, SISPtr pSiS, USHORT adaptnum, USHORT DDCdatatype)
 {
-  SiS_SetSCLKLow();					  /* TW: (SC->low)  */
-  SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFD,0x02);  /* TW: SD->high */
-  SiS_SetSCLKHigh();					  /* TW: SC->high */
-  SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFD,0x00);  /* TW: SD->low = start condition */
-  SiS_SetSCLKHigh();					  /* TW: (SC->low) */
+     unsigned char ddcdtype[] = { 0xa0, 0xa0, 0xa0, 0xa2, 0xa6};
+     unsigned char flag, cr32;
+     USHORT        temp = 0, myadaptnum = adaptnum;
+
+     SiS_Pr->SiS_ChrontelInit = 0;   /* force re-detection! */
+
+     SiS_Pr->SiS_DDC_SecAddr = 0;
+     SiS_Pr->SiS_DDC_DeviceAddr = ddcdtype[DDCdatatype];
+     SiS_Pr->SiS_DDC_Port = SiS_Pr->SiS_P3c4;
+     SiS_Pr->SiS_DDC_Index = 0x11;
+     flag = 0xff;
+
+     cr32 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x32);
+
+     if(pSiS->VGAEngine == SIS_300_VGA) {		/* 300 series */
+
+        if(pSiS->VBFlags & VB_SISBRIDGE) {
+	   if(myadaptnum == 0) {
+	      if(!(cr32 & 0x20)) {
+	         myadaptnum = 2;
+		 if(!(cr32 & 0x10)) {
+		    myadaptnum = 1;
+		    if(!(cr32 & 0x08)) {
+		       myadaptnum = 0;
+		    }
+		 }
+              }
+	   }
+	}
+
+        if(myadaptnum != 0) {
+	   flag = 0;
+	   if(pSiS->VBFlags & VB_SISBRIDGE) {
+	      SiS_Pr->SiS_DDC_Port = SiS_Pr->SiS_Part4Port;
+              SiS_Pr->SiS_DDC_Index = 0x0f;
+	   }
+        }
+
+	if(cr32 & 0x80) {
+           if(myadaptnum >= 1) {
+	      if(!(cr32 & 0x08)) {
+	          myadaptnum = 1;
+		  if(!(cr32 & 0x10)) return 0xFFFF;
+              }
+	   }
+	}
+
+	temp = 4 - (myadaptnum * 2);
+	if(flag) temp = 0;
+
+	SiS_Pr->SiS_DDC_Data = 0x02 << temp;
+        SiS_Pr->SiS_DDC_Clk  = 0x01 << temp;
+
+     } else {						/* 310/325 series */
+
+        if(pSiS->VBFlags & (VB_30xLV|VB_30xLVX)) myadaptnum = 0;
+
+	if(pSiS->VBFlags & VB_SISBRIDGE) {
+	   if(myadaptnum == 0) {
+	      if(!(cr32 & 0x20)) {
+	         myadaptnum = 2;
+		 if(!(cr32 & 0x10)) {
+		    myadaptnum = 1;
+		    if(!(cr32 & 0x08)) {
+		       myadaptnum = 0;
+		    }
+		 }
+              }
+	   }
+	   if(myadaptnum == 2) {
+	      myadaptnum = 1;
+           }
+	}
+
+        if(myadaptnum == 1) {
+     	   flag = 0;
+	   if(pSiS->VBFlags & VB_SISBRIDGE) {
+	      SiS_Pr->SiS_DDC_Port = SiS_Pr->SiS_Part4Port;
+              SiS_Pr->SiS_DDC_Index = 0x0f;
+	   }
+        }
+
+        if(cr32 & 0x80) {
+           if(myadaptnum >= 1) {
+	      if(!(cr32 & 0x08)) {
+	         myadaptnum = 1;
+		 if(!(cr32 & 0x10)) return 0xFFFF;
+	      }
+	   }
+        }
+
+        temp = myadaptnum;
+        if(myadaptnum == 1) {
+           temp = 0;
+	   if(pSiS->VBFlags & VB_LVDS) flag = 0xff;
+        }
+
+	if(flag) temp = 0;
+
+        SiS_Pr->SiS_DDC_Data = 0x02 << temp;
+        SiS_Pr->SiS_DDC_Clk  = 0x01 << temp;
+
+    }
+    return 0;
 }
 
-/* TW: Set Chrontel 7005 stop condition */
-/* TW: This is done by a SD low-to-high transition while SC is high */
-void
-SiS_SetStop(void)
+USHORT
+SiS_WriteDABDDC(SiS_Private *SiS_Pr)
 {
-  SiS_SetSCLKLow();					  /* TW: (SC->low) */
-  SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFD,0x00);  /* TW: SD->low   */
-  SiS_SetSCLKHigh();					  /* TW: SC->high  */
-  SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFD,0x02);  /* TW: SD->high = stop condition */   
-  SiS_SetSCLKHigh();					  /* TW: (SC->high) */
+   SiS_SetStart(SiS_Pr);
+   if(SiS_WriteDDC2Data(SiS_Pr, SiS_Pr->SiS_DDC_DeviceAddr)) return 0xFFFF;
+   if(SiS_WriteDDC2Data(SiS_Pr, SiS_Pr->SiS_DDC_SecAddr)) return 0xFFFF;
+   return(0);
 }
 
-/* TW: Write 8 bits of data */
 USHORT
-SiS_WriteDDC2Data(USHORT tempax)
+SiS_PrepareReadDDC(SiS_Private *SiS_Pr)
 {
-  USHORT i,flag,temp;
-
-  flag=0x80;
-  for(i=0;i<8;i++) {
-    SiS_SetSCLKLow();					     /* TW: SC->low */
-    if(tempax&flag) {
-      SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFD,0x02); /* TW: Write bit (1) to SD */
-    } else {
-      SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFD,0x00); /* TW: Write bit (0) to SD */
-    }
-    SiS_SetSCLKHigh();					     /* TW: SC->high */
-    flag=flag>>1;
-  }
-  temp=SiS_CheckACK();					     /* TW: Check acknowledge */
-  return(temp);
+   SiS_SetStart(SiS_Pr);
+   if(SiS_WriteDDC2Data(SiS_Pr, (SiS_Pr->SiS_DDC_DeviceAddr | 0x01))) return 0xFFFF;
+   return(0);
 }
 
 USHORT
-SiS_ReadDDC2Data(USHORT tempax)
+SiS_PrepareDDC(SiS_Private *SiS_Pr)
 {
-  USHORT i,temp,getdata;
-
-  getdata=0;
-  for(i=0;i<8;i++) {
-    getdata=getdata<<1;
-    SiS_SetSCLKLow();
-    SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFD,0x02);
-    SiS_SetSCLKHigh();
-    temp=SiS_GetReg1(SiS_DDC_Port,SiS_DDC_Index);
-    if(temp&0x02) getdata=getdata|0x01;
-  }
-  return(getdata);
+   if(SiS_WriteDABDDC(SiS_Pr)) SiS_WriteDABDDC(SiS_Pr);
+   if(SiS_PrepareReadDDC(SiS_Pr)) return(SiS_PrepareReadDDC(SiS_Pr));
+   return(0);
 }
 
 void
-SiS_SetSCLKLow(void)
+SiS_SendACK(SiS_Private *SiS_Pr, USHORT yesno)
 {
-    USHORT temp;
-
-    SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFE,0x00);      /* SetSCLKLow()  */
-    do {
-      temp=SiS_GetReg1(SiS_DDC_Port,SiS_DDC_Index);
-    } while(temp&0x01);
-    SiS_DDC2Delay();
+   SiS_SetSCLKLow(SiS_Pr);
+   if(yesno) {
+      SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, SiS_Pr->SiS_DDC_Index,
+                      ~SiS_Pr->SiS_DDC_Data, SiS_Pr->SiS_DDC_Data);
+   } else {
+      SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port, SiS_Pr->SiS_DDC_Index,
+                      ~SiS_Pr->SiS_DDC_Data, 0);
+   }
+   SiS_SetSCLKHigh(SiS_Pr);
 }
 
-void
-SiS_SetSCLKHigh(void)
+USHORT
+SiS_DoProbeDDC(SiS_Private *SiS_Pr)
 {
-  USHORT temp;
+    unsigned char mask, value;
+    USHORT  temp, ret;
 
-  SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFE,0x01);      /* SetSCLKHigh()  */
-  do {
-    temp=SiS_GetReg1(SiS_DDC_Port,SiS_DDC_Index);
-  } while(!(temp&0x01));
-  SiS_DDC2Delay();
+    SiS_SetSwitchDDC2(SiS_Pr);
+    if(SiS_PrepareDDC(SiS_Pr)) {
+         SiS_SetStop(SiS_Pr);
+         return(0xFFFF);
+    }
+    mask = 0xf0;
+    value = 0x20;
+    if(SiS_Pr->SiS_DDC_DeviceAddr == 0xa0) {
+       temp = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0);
+       SiS_SendACK(SiS_Pr, 0);
+       if(temp == 0) {
+           mask = 0xff;
+	   value = 0xff;
+       }
+    }
+    temp = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0);
+    SiS_SendACK(SiS_Pr, 1);
+    temp &= mask;
+    if(temp == value) ret = 0;
+    else {
+       ret = 0xFFFF;
+       if(SiS_Pr->SiS_DDC_DeviceAddr == 0xa0) {
+           if(value == 0x30) ret = 0;
+       }
+    }
+    SiS_SetStop(SiS_Pr);
+    return(ret);
 }
 
-void
-SiS_DDC2Delay(void)
+USHORT
+SiS_ProbeDDC(SiS_Private *SiS_Pr)
 {
-  USHORT i;
+   USHORT flag;
 
-   for(i=0;i<DDC2DelayTime;i++) {
-    SiS_GetReg1(SiS_P3c4,0x05);
-  }
+   flag = 0x180;
+   SiS_Pr->SiS_DDC_DeviceAddr = 0xa0;
+   if(!(SiS_DoProbeDDC(SiS_Pr))) flag |= 0x02;
+   SiS_Pr->SiS_DDC_DeviceAddr = 0xa2;
+   if(!(SiS_DoProbeDDC(SiS_Pr))) flag |= 0x08;
+   SiS_Pr->SiS_DDC_DeviceAddr = 0xa6;
+   if(!(SiS_DoProbeDDC(SiS_Pr))) flag |= 0x10;
+   if(!(flag & 0x1a)) flag = 0;
+   return(flag);
 }
 
-/* TW: Check acknowledge */
-/* Returns 0 if ack ok, non-0 if ack not ok */
 USHORT
-SiS_CheckACK(void)
+SiS_ReadDDC(SiS_Private *SiS_Pr, SISPtr pSiS, USHORT DDCdatatype, unsigned char *buffer)
 {
-  USHORT tempah;
+   USHORT flag, length, i;
+   unsigned char chksum,gotcha;
 
-  SiS_SetSCLKLow();					  /* TW: (SC->low) */
-  SiS_SetRegANDOR(SiS_DDC_Port,SiS_DDC_Index,0xFD,0x02);  /* TW: (SD->high) */
-  SiS_SetSCLKHigh();					  /* TW: SC->high = clock impulse for ack */
-  tempah=SiS_GetReg1(SiS_DDC_Port,SiS_DDC_Index);	  /* TW: Read SD */
-  SiS_SetSCLKLow();					  /* TW: SC->low = end of clock impulse */
-  if(tempah&0x02) return(1);				  /* TW: Ack OK if bit = 0 */
-  else return(0);
+   if(DDCdatatype > 3) return 0xFFFF;  /* incomplete! */
+
+   flag = 0;
+   SiS_SetSwitchDDC2(SiS_Pr);
+   if(!(SiS_PrepareDDC(SiS_Pr))) {
+      length = 127;
+      if(DDCdatatype != 1) length = 255;
+      chksum = 0;
+      gotcha = 0;
+      for(i=0; i<length; i++) {
+         buffer[i] = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0);
+	 chksum += buffer[i];
+	 gotcha |= buffer[i];
+	 SiS_SendACK(SiS_Pr, 0);
+      }
+      buffer[i] = (unsigned char)SiS_ReadDDC2Data(SiS_Pr, 0);
+      chksum += buffer[i];
+      SiS_SendACK(SiS_Pr, 1);
+      if(gotcha) flag = (USHORT)chksum;
+      else flag = 0xFFFF;
+   } else {
+      flag = 0xFFFF;
+   }
+   SiS_SetStop(SiS_Pr);
+   return(flag);
 }
 
-/* TW: End of Chrontel 7005 functions ---------------------------- */
+/* TW: Our private DDC function
 
-void
-SiS_ModCRT1CRTC(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                USHORT RefreshRateTableIndex)
-{
-  USHORT temp,tempah,i,modeflag,j;
-  USHORT ResInfo,DisplayType;
-  SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr=NULL;
+   It complies somewhat with the corresponding VESA function
+   in arguments and return values.
 
-  if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-  }
+   Since this is probably called before the mode is changed,
+   we use our pre-detected pSiS-values instead of SiS_Pr as
+   regards chipset and video bridge type.
 
-  temp= SiS_GetLVDSCRT1Ptr(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
-                       &ResInfo,&DisplayType);
-  if(temp==0){
-    return;
-  }
+   Arguments:
+       adaptnum: 0=CRT1, 1=CRT2
+                 CRT2 DDC is not supported in some cases.
+       DDCdatatype: 0=Probe, 1=EDID, 2=VDIF(not supported), 3=?, 4=?(not supported)
+       buffer: ptr to 256 data bytes which will be filled with read data.
 
-  switch(DisplayType) {
-    case 0 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1;           break;
-    case 1 : LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1;          break;
-    case 2 : LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1;         break;
-    case 3 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1_H;         break;
-    case 4 : LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1_H;        break;
-    case 5 : LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1_H;       break;
-    case 6 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2;           break;
-    case 7 : LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2;          break;
-    case 8 : LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2;         break;
-    case 9 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2_H;         break;
-    case 10: LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2_H;        break;
-    case 11: LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2_H;       break;
-    case 12: LVDSCRT1Ptr = SiS_CHTVCRT1UNTSC;               break;
-    case 13: LVDSCRT1Ptr = SiS_CHTVCRT1ONTSC;               break;
-    case 14: LVDSCRT1Ptr = SiS_CHTVCRT1UPAL;                break;
-    case 15: LVDSCRT1Ptr = SiS_CHTVCRT1OPAL;                break;
-    case 16: LVDSCRT1Ptr = SiS_LVDSCRT1320x480_1;           break;
-  }
+   Returns 0xFFFF if error, otherwise
+       if DDCdatatype > 0:  Returns 0 if reading OK (included a correct checksum)
+       if DDCdatatype = 0:  Returns supported DDC modes
 
-  tempah=(UCHAR)SiS_GetReg1(SiS_P3d4,0x11);                        /*unlock cr0-7  */
-  tempah=tempah&0x7F;
-  SiS_SetReg1(SiS_P3d4,0x11,tempah);
-  tempah = (LVDSCRT1Ptr+ResInfo)->CR[0];
-  SiS_SetReg1(SiS_P3d4,0x0,tempah);
-  for(i=0x02,j=1;i<=0x05;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3d4,i,tempah);
-  }
-  for(i=0x06,j=5;i<=0x07;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3d4,i,tempah);
-  }
-  for(i=0x10,j=7;i<=0x11;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3d4,i,tempah);
-  }
-  for(i=0x15,j=9;i<=0x16;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3d4,i,tempah);
-  }
-  for(i=0x0A,j=11;i<=0x0C;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3c4,i,tempah);
-  }
+ */
+USHORT
+SiS_HandleDDC(SiS_Private *SiS_Pr, SISPtr pSiS, USHORT adaptnum,
+              USHORT DDCdatatype, unsigned char *buffer)
+{
+   if(DDCdatatype == 2) return 0xFFFF;
+   if(adaptnum > 2) return 0xFFFF;
+   if(pSiS->VGAEngine == SIS_300_VGA) {
+      if((adaptnum != 0) && (DDCdatatype != 0)) return 0xFFFF;
+   }
+   if((!(pSiS->VBFlags & VB_VIDEOBRIDGE)) && (adaptnum > 0)) return 0xFFFF;
+   if(SiS_InitDDCRegs(SiS_Pr, pSiS, adaptnum, DDCdatatype) == 0xFFFF) return 0xFFFF;
+   if(DDCdatatype == 0) {
+       return(SiS_ProbeDDC(SiS_Pr));
+   } else {
+       if(DDCdatatype > 4) return 0xFFFF;
+       return(SiS_ReadDDC(SiS_Pr, pSiS, DDCdatatype, buffer));
+   }
+}
 
-  tempah = (LVDSCRT1Ptr+ResInfo)->CR[14];
-  tempah=tempah&0x0E0;
-  SiS_SetReg1(SiS_P3c4,0x0E,tempah);
+/* TW: Generic I2C functions (compliant to i2c library) */
 
-  tempah = (LVDSCRT1Ptr+ResInfo)->CR[14];
-  tempah=tempah&0x01;
-  tempah=tempah<<5;
-  if(modeflag&DoubleScanMode){
-    	tempah=tempah|0x080;
-  }
-  SiS_SetRegANDOR(SiS_P3d4,0x09,~0x020,tempah);
-  return;
+#if 0
+USHORT
+SiS_I2C_GetByte(SiS_Private *SiS_Pr)
+{
+   return(SiS_ReadDDC2Data(SiS_Pr,0));
+}
+
+Bool
+SiS_I2C_PutByte(SiS_Private *SiS_Pr, USHORT data)
+{
+   if(SiS_WriteDDC2Data(SiS_Pr,data)) return FALSE;
+   return TRUE;
+}
+
+Bool
+SiS_I2C_Address(SiS_Private *SiS_Pr, USHORT addr)
+{
+   if(SiS_SetStart(SiS_Pr)) return FALSE;
+   if(SiS_WriteDDC2Data(SiS_Pr,addr)) return FALSE;
+   return TRUE;
 }
 
-/*301b*/
 void
-SiS_CHACRT1CRTC(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                USHORT RefreshRateTableIndex)
+SiS_I2C_Stop(SiS_Private *SiS_Pr)
 {
-  USHORT temp,tempah,i,modeflag,j;
-  USHORT ResInfo,DisplayType;
-  SiS_LVDSCRT1DataStruct *LVDSCRT1Ptr=NULL;
+   SiS_SetStop(SiS_Pr);
+}
+#endif
 
-  if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-  }
+#endif
 
-  temp= SiS_GetLVDSCRT1Ptr(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
-                       &ResInfo,&DisplayType);
-  if(temp==0){
-    return;
-  }
+void
+SiS_SetCH70xxANDOR(SiS_Private *SiS_Pr, USHORT tempax,USHORT tempbh)
+{
+  USHORT tempal,tempah,tempbl;
 
-  switch(DisplayType) {
-    case 0 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1;           break;
-    case 1 : LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1;          break;
-    case 2 : LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1;         break;
-    case 3 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_1_H;         break;
-    case 4 : LVDSCRT1Ptr = SiS_LVDSCRT11024x768_1_H;        break;
-    case 5 : LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_1_H;       break;
-    case 6 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2;           break;
-    case 7 : LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2;          break;
-    case 8 : LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2;         break;
-    case 9 : LVDSCRT1Ptr = SiS_LVDSCRT1800x600_2_H;         break;
-    case 10: LVDSCRT1Ptr = SiS_LVDSCRT11024x768_2_H;        break;
-    case 11: LVDSCRT1Ptr = SiS_LVDSCRT11280x1024_2_H;       break;
-    case 12: LVDSCRT1Ptr = SiS_CHTVCRT1UNTSC;               break;
-    case 13: LVDSCRT1Ptr = SiS_CHTVCRT1ONTSC;               break;
-    case 14: LVDSCRT1Ptr = SiS_CHTVCRT1UPAL;                break;
-    case 15: LVDSCRT1Ptr = SiS_CHTVCRT1OPAL;                break;
-  }
+  tempal = tempax & 0x00FF;
+  tempah =(tempax >> 8) & 0x00FF;
+  tempbl = SiS_GetCH70xx(SiS_Pr,tempal);
+  tempbl = (((tempbl & tempbh) | tempah) << 8 | tempal);
+  SiS_SetCH70xx(SiS_Pr,tempbl);
+}
 
-  tempah=(UCHAR)SiS_GetReg1(SiS_P3d4,0x11);                        /*unlock cr0-7  */
-  tempah=tempah&0x7F;
-  SiS_SetReg1(SiS_P3d4,0x11,tempah);
-  tempah = (LVDSCRT1Ptr+ResInfo)->CR[0];
-  SiS_SetReg1(SiS_P3d4,0x0,tempah);
-  for(i=0x02,j=1;i<=0x05;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3d4,i,tempah);
-  }
-  for(i=0x06,j=5;i<=0x07;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3d4,i,tempah);
-  }
-  for(i=0x10,j=7;i<=0x11;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3d4,i,tempah);
-  }
-  for(i=0x15,j=9;i<=0x16;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3d4,i,tempah);
-  }
+/* TW: Generic I2C functions for Chrontel --------- */
 
-  for(i=0x0A,j=11;i<=0x0C;i++,j++){
-    tempah = (LVDSCRT1Ptr+ResInfo)->CR[j];
-    SiS_SetReg1(SiS_P3c4,i,tempah);
-  }
+void
+SiS_SetSwitchDDC2(SiS_Private *SiS_Pr)
+{
+  SiS_SetSCLKHigh(SiS_Pr);
+  /* SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAY); */
+  SiS_WaitRetraceDDC(SiS_Pr);
 
-  tempah = (LVDSCRT1Ptr+ResInfo)->CR[14];
-  tempah=tempah&0x0E0;
-  SiS_SetReg1(SiS_P3c4,0x0E,tempah);
+  SiS_SetSCLKLow(SiS_Pr);
+  /* SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAY); */
+  SiS_WaitRetraceDDC(SiS_Pr);
+}
 
-  tempah = (LVDSCRT1Ptr+ResInfo)->CR[14];
-  tempah=tempah&0x01;
-  tempah=tempah<<5;
-  if(modeflag&DoubleScanMode){
-    	tempah=tempah|0x080;
-  }
-  SiS_SetRegANDOR(SiS_P3d4,0x09,~0x020,tempah);
-  return;
+/* TW: Set I2C start condition */
+/* TW: This is done by a SD high-to-low transition while SC is high */
+USHORT
+SiS_SetStart(SiS_Private *SiS_Pr)
+{
+  if(SiS_SetSCLKLow(SiS_Pr)) return 0xFFFF;			           /* TW: (SC->low)  */
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                  ~SiS_Pr->SiS_DDC_Data,SiS_Pr->SiS_DDC_Data);             /* TW: SD->high */
+  if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF;			           /* TW: SC->high */
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                  ~SiS_Pr->SiS_DDC_Data,0x00);                             /* TW: SD->low = start condition */
+  if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF;			           /* TW: (SC->low) */
+  return 0;
 }
-/*add for LCDA*/
 
-BOOLEAN
-SiS_GetLCDACRT1Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-		   USHORT RefreshRateTableIndex,USHORT *ResInfo,
-		   USHORT *DisplayType)
- {
-  USHORT tempbx=0,modeflag=0;
-  USHORT CRT2CRTC=0;
- /*301b*/
-  if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-                    &&(SiS_VBInfo&SetCRT2ToLCDA) ) {
-    	tempbx = SiS_LCDResInfo;
-    	tempbx -= Panel800x600;
-    	if(SiS_LCDInfo&LCDNonExpanding) tempbx +=6;
-#if 0   /* TW: That can't work - test modeflag BEFORE reading it? */
-    	if(modeflag&HalfDCLK) tempbx +=+3;
-#endif
-    	if(ModeNo<=0x13) {
-    		modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-    		CRT2CRTC = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-  	} else {
-    		modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-    		CRT2CRTC = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-  	}
-	/* TW: This belongs here I assume */
-	if(modeflag&HalfDCLK) tempbx +=+3;
-  }
-  *ResInfo = CRT2CRTC&0x3F;
-  *DisplayType = tempbx;
-  return 1;
+/* TW: Set I2C stop condition */
+/* TW: This is done by a SD low-to-high transition while SC is high */
+USHORT
+SiS_SetStop(SiS_Private *SiS_Pr)
+{
+  if(SiS_SetSCLKLow(SiS_Pr)) return 0xFFFF;			           /* TW: (SC->low) */
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                  ~SiS_Pr->SiS_DDC_Data,0x00);          		   /* TW: SD->low   */
+  if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF;			           /* TW: SC->high  */
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                  ~SiS_Pr->SiS_DDC_Data,SiS_Pr->SiS_DDC_Data);  	   /* TW: SD->high = stop condition */
+  if(SiS_SetSCLKHigh(SiS_Pr)) return 0xFFFF;			           /* TW: (SC->high) */
+  return 0;
 }
-/*end for 301b*/
 
-BOOLEAN
-SiS_GetLVDSCRT1Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-		USHORT RefreshRateTableIndex,USHORT *ResInfo,USHORT *DisplayType)
- {
-  USHORT tempbx,modeflag=0;
-  USHORT Flag,CRT2CRTC;
- 
-  if(ModeNo<=0x13) {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-    	CRT2CRTC = SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
-  } else {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-    	CRT2CRTC = SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-  }
-  if(!(SiS_VBInfo&SetInSlaveMode)){
-     return 0;
-  }
-  Flag=1;
-  tempbx=0;
-  if(SiS_IF_DEF_CH7005==1) {
-    if(!(SiS_VBInfo&SetCRT2ToLCD)) {
-      Flag=0;
-      tempbx =12;
-      if(SiS_VBInfo&SetPALTV) tempbx +=2;
-      if(SiS_VBInfo&SetCHTVOverScan) tempbx +=1;
+/* TW: Write 8 bits of data */
+USHORT
+SiS_WriteDDC2Data(SiS_Private *SiS_Pr, USHORT tempax)
+{
+  USHORT i,flag,temp;
+
+  flag=0x80;
+  for(i=0;i<8;i++) {
+    SiS_SetSCLKLow(SiS_Pr);				                      /* TW: SC->low */
+    if(tempax & flag) {
+      SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                      ~SiS_Pr->SiS_DDC_Data,SiS_Pr->SiS_DDC_Data);            /* TW: Write bit (1) to SD */
+    } else {
+      SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                      ~SiS_Pr->SiS_DDC_Data,0x00);                            /* TW: Write bit (0) to SD */
     }
+    SiS_SetSCLKHigh(SiS_Pr);				                      /* TW: SC->high */
+    flag >>= 1;
   }
-  if(Flag) {
-    tempbx =SiS_LCDResInfo;
-    tempbx -=Panel800x600;
-    if(SiS_LCDInfo&LCDNonExpanding) tempbx +=6;
-    if(modeflag&HalfDCLK) tempbx +=+3;
-  }
-  /*fstn*/
-   if(SiS_IF_DEF_FSTN){
-     if(SiS_LCDResInfo==Panel320x480){
-       tempbx=0x10;         /*not same with asmber code */
-     }
-   }
-  *ResInfo = CRT2CRTC&0x3F;
-  *DisplayType = tempbx;
-  return 1;
+  temp = SiS_CheckACK(SiS_Pr);				                      /* TW: Check acknowledge */
+  return(temp);
+}
+
+USHORT
+SiS_ReadDDC2Data(SiS_Private *SiS_Pr, USHORT tempax)
+{
+  USHORT i,temp,getdata;
+
+  getdata=0;
+  for(i=0; i<8; i++) {
+    getdata <<= 1;
+    SiS_SetSCLKLow(SiS_Pr);
+    SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                    ~SiS_Pr->SiS_DDC_Data,SiS_Pr->SiS_DDC_Data);
+    SiS_SetSCLKHigh(SiS_Pr);
+    temp = SiS_GetReg1(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index);
+    if(temp & SiS_Pr->SiS_DDC_Data) getdata |= 0x01;
+  }
+  return(getdata);
+}
+
+USHORT
+SiS_SetSCLKLow(SiS_Private *SiS_Pr)
+{
+  USHORT temp, watchdog=50000;
+
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                  ~SiS_Pr->SiS_DDC_Clk,0x00);      		/* SetSCLKLow()  */
+  do {
+    temp = SiS_GetReg1(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index);
+  } while((temp & SiS_Pr->SiS_DDC_Clk) && --watchdog);
+  if (!watchdog) return 0xFFFF;
+  SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT);
+  return 0;
 }
 
-void
-SiS_SetCRT2ECLK(ULONG ROMAddr, USHORT ModeNo,USHORT ModeIdIndex,
-           USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+USHORT
+SiS_SetSCLKHigh(SiS_Private *SiS_Pr)
 {
-  USHORT tempah,tempal;
-  USHORT P3cc=SiS_P3c9+3;
-  USHORT vclkindex=0;
+  USHORT temp,watchdog=50000;
 
-  if(SiS_IF_DEF_TRUMPION==0){  /*no trumpion  */
-    	tempal=SiS_GetReg2(P3cc);
-    	tempal=tempal&0x0C;
-    	vclkindex=SiS_GetVCLK2Ptr(ROMAddr,ModeNo,ModeIdIndex,
-                               RefreshRateTableIndex,HwDeviceExtension);
-  } else {  			/*trumpion  */
-    	SiS_SetFlag=SiS_SetFlag&(~ProgrammingCRT2);
-/*  	tempal=*((UCHAR *)(ROMAddr+SiS_RefIndex+0x03));     &di+Ext_CRTVCLK  */
-    	tempal=tempal&0x03F;
-    	if(tempal==0x02){ /*31.5MHz  */
-/*      	SiS_RefIndex=SiS_RefIndex-Ext2StructSize;   */
-    	}
-/*    	SiS_RefIndex=GetVCLKPtr(ROMAddr,ModeNo);  */
-    	SiS_SetFlag=SiS_SetFlag|ProgrammingCRT2;
-  }
-  tempal=0x02B;
-  if(!(SiS_VBInfo&SetInSlaveMode)){
-    	tempal=tempal+3;
-  }
-  SiS_SetReg1(SiS_P3c4,0x05,0x86);
-  tempah = SiS_VCLKData[vclkindex].SR2B;
-  SiS_SetReg1(SiS_P3c4,tempal,tempah);
-  tempal++;
-  tempah = SiS_VCLKData[vclkindex].SR2C;
-  SiS_SetReg1(SiS_P3c4,tempal,tempah);
-  tempal++;
-  SiS_SetReg1(SiS_P3c4,tempal,0x80);
-  return;
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                  ~SiS_Pr->SiS_DDC_Clk,SiS_Pr->SiS_DDC_Clk);  	/* SetSCLKHigh()  */
+  do {
+    temp = SiS_GetReg1(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index);
+  } while((!(temp & SiS_Pr->SiS_DDC_Clk)) && --watchdog);
+  if (!watchdog) return 0xFFFF;
+  SiS_DDC2Delay(SiS_Pr,SiS_I2CDELAYSHORT);
+  return 0;
 }
 
 void
-SiS_SetDefCRT2ExtRegs(USHORT BaseAddr)
+SiS_DDC2Delay(SiS_Private *SiS_Pr, USHORT delaytime)
 {
-  USHORT  temp;
+  USHORT i;
 
-  if(SiS_IF_DEF_LVDS==0) {
-    SiS_SetReg1(SiS_Part1Port,0x02,0x40);
-    SiS_SetReg1(SiS_Part4Port,0x10,0x80);
-    temp=(UCHAR)SiS_GetReg1(SiS_P3c4,0x16);
-    temp=temp&0xC3;
-    SiS_SetReg1(SiS_P3d4,0x35,temp);
-  }
-  else {
-    SiS_SetReg1(SiS_P3d4,0x32,0x02);
-    SiS_SetReg1(SiS_Part1Port,0x02,0x00);
+  for(i=0; i<delaytime; i++) {
+    SiS_GetReg1(SiS_Pr->SiS_P3c4,0x05);
   }
 }
 
+/* TW: Check I2C acknowledge */
+/* Returns 0 if ack ok, non-0 if ack not ok */
+USHORT
+SiS_CheckACK(SiS_Private *SiS_Pr)
+{
+  USHORT tempah;
+
+  SiS_SetSCLKLow(SiS_Pr);				           /* TW: (SC->low) */
+  SiS_SetRegANDOR(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index,
+                  ~SiS_Pr->SiS_DDC_Data,SiS_Pr->SiS_DDC_Data);     /* TW: (SD->high) */
+  SiS_SetSCLKHigh(SiS_Pr);				           /* TW: SC->high = clock impulse for ack */
+  tempah = SiS_GetReg1(SiS_Pr->SiS_DDC_Port,SiS_Pr->SiS_DDC_Index);/* TW: Read SD */
+  SiS_SetSCLKLow(SiS_Pr);				           /* TW: SC->low = end of clock impulse */
+  if(tempah & SiS_Pr->SiS_DDC_Data) return(1);			   /* TW: Ack OK if bit = 0 */
+  else return(0);
+}
+
+/* TW: End of I2C functions ----------------------- */
+
+
+/* =============== SiS 310/325 O.E.M. ================= */
+
 #ifdef SIS315H
-/*
-    for SIS310 O.E.M.
-*/
-/*
----------------------------------------------------------
-   LCDResInfo 1 : 800x600
-              2 : 1024x768
-              3 : 1280x1024
-              4 : 1280x960
-              5 : 640x480
-              6 : 1600x1200
-              7 : 1920x1440
-   VESA
-   non-VESA
-   non-Expanding
----------------------------------------------------------
-*/
+
 USHORT
-GetLCDPtrIndex (void)
+GetLCDPtrIndex(SiS_Private *SiS_Pr)
 {
-   USHORT index;
+  USHORT index;
 
-   index = (SiS_LCDResInfo & 0x0F)-1;
-   index *= 3;
-   if (SiS_LCDInfo&LCDNonExpanding)
-      index += 2;
-   else
-   {
-     if (!(SiS_LCDInfo&LCDVESATiming))
-       index++;
-   }
+  index = SiS_Pr->SiS_LCDResInfo & 0x0F;
+  index--;
+  index *= 3;
+  if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) index += 2;
+  else if(!(SiS_Pr->SiS_SetFlag & LCDVESATiming)) index++;
 
   return index;
- }
-
+}
 
 /*
 ---------------------------------------------------------
@@ -5238,573 +8806,608 @@
 ---------------------------------------------------------
 */
 USHORT
-GetTVPtrIndex(void)
+GetTVPtrIndex(SiS_Private *SiS_Pr)
 {
   USHORT index;
 
   index = 0;
-  if (SiS_VBInfo&SetPALTV)
-    index++;
-  if (SiS_VBInfo&SetCRT2ToHiVisionTV)  /* Hivision TV use PAL */
-    index++;
-  index *= 2;
+  if(SiS_Pr->SiS_VBInfo & SetPALTV) index++;
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) index++;  /* Hivision TV use PAL */
+
+  index <<= 1;
 
-  if ((SiS_VBInfo&SetInSlaveMode)&&(SiS_SetFlag&TVSimuMode))
+  if((SiS_Pr->SiS_VBInfo & SetInSlaveMode) && (SiS_Pr->SiS_SetFlag & TVSimuMode))
     index++;
 
   return index;
 }
 
+/* TW: Checked against 650/LVDS (1.10.07) and 650/301LVx (1.10.6s) BIOS (including data) */
 void
-SetDelayComp(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-             ULONG ROMAddr,USHORT ModeNo)
+SetDelayComp(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+             UCHAR *ROMAddr,USHORT ModeNo)
 {
-  USHORT Part1Port;
   USHORT delay,index;
 
-  if (SiS_VBInfo&SetCRT2ToRAMDAC)
-  {
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToRAMDAC) {
      delay = SiS310_CRT2DelayCompensation1;
-     if (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
+     if(SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS302B))
        delay = SiS310_CRT2DelayCompensation2;
-  }
-  else
-    if (SiS_VBInfo&SetCRT2ToLCD)
-    {
-       index = GetLCDPtrIndex();
-       delay = SiS310_LCDDelayCompensation1[index];
-       if (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-         delay = SiS310_LCDDelayCompensation2[index];
-    }
-    else
-    {
-       index = GetTVPtrIndex();
-       delay = SiS310_TVDelayCompensation1[index];
-       if (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-         delay = SiS310_TVDelayCompensation2[index];
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 1)
+       delay = SiS310_CRT2DelayCompensation3;
+  } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+     index = GetLCDPtrIndex(SiS_Pr);
+     delay = SiS310_LCDDelayCompensation1[index];
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
+       delay = SiS310_LCDDelayCompensation2[index];
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 1)
+       delay = SiS310_LCDDelayCompensation3[index];
+  } else {
+     index = GetTVPtrIndex(SiS_Pr);
+     delay = SiS310_TVDelayCompensation1[index];
+     if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
+       delay = SiS310_TVDelayCompensation2[index];
+     if(SiS_Pr->SiS_IF_DEF_LVDS == 1)
+       delay = SiS310_TVDelayCompensation3[index];
+  }
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+    if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+       SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0xF0,delay);
+    } else {
+       delay <<= 4;
+       SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2D,0x0F,delay);
     }
-  Part1Port=BaseAddr+SIS_CRT2_PORT_04;
-  SiS_SetRegANDOR(Part1Port,0x2D,~0x0F,delay);  /* index 2D D[3:0] */
+  } else {
+     SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2D,delay);  /* index 2D D[3:0] */
+  }
 }
 
-/*
-*/
+/* TW: Checked against 650/301LVx 1.10.6s BIOS (including data) */
 void
-SetAntiFlicker(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-               ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SetAntiFlicker(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+               UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT Part2Port;
   USHORT index,temp;
 
-  Part2Port=BaseAddr+SIS_CRT2_PORT_10;
-  temp = GetTVPtrIndex();
-  temp = (temp>>1);  /* 0: NTSC, 1 :PAL, 2:HiTV */
+  temp = GetTVPtrIndex(SiS_Pr);
+  temp >>= 1;  	  /* 0: NTSC, 1: PAL, 2: HiTV */
+
   if (ModeNo<=0x13)
-  {
-    index = SiS_SModeIDTable[ModeIdIndex].VB_StTVFlickerIndex;
-  }
+    index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVFlickerIndex;
   else
-  {
-    index = SiS_EModeIDTable[ModeIdIndex].VB_ExtTVFlickerIndex;
-  }
-  temp = SiS310_TVAntiFlick1[temp][index];
-  temp  <<= 4;
+    index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVFlickerIndex;
 
-  SiS_SetRegANDOR(Part2Port,0x0A,~0x70,temp);  /* index 0A D[6:4] */
+  temp = SiS310_TVAntiFlick1[temp][index];
+  temp <<= 4;
 
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0A,0x8f,temp);  /* index 0A D[6:4] */
 }
 
+/* TW: Checked against 650/301LVx 1.10.6s BIOS (including data) */
 void
-SetEdgeEnhance (PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-                ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SetEdgeEnhance(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+               UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT Part2Port;
   USHORT index,temp;
 
-  Part2Port=BaseAddr+SIS_CRT2_PORT_10;
-  temp = GetTVPtrIndex();
-  temp = (temp>>1);   /* 0: NTSC, 1 :PAL, 2:HiTV */
+  temp = GetTVPtrIndex(SiS_Pr);
+  temp >>= 1;              	/* 0: NTSC, 1: PAL, 2: HiTV */
+
   if (ModeNo<=0x13)
-  {
-    index = SiS_SModeIDTable[ModeIdIndex].VB_StTVEdgeIndex;   /* si+VB_StTVEdgeIndex */
-  }
+    index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVEdgeIndex;
   else
-  {
-    index = SiS_EModeIDTable[ModeIdIndex].VB_ExtTVEdgeIndex;  /* si+VB_ExtTVEdgeIndex */
-  }
-  temp = SiS310_TVEdge1[temp][index];
-  temp  <<= 5;
-
-  SiS_SetRegANDOR(Part2Port,0x3A,~0xE0,temp);  /* index 0A D[7:5] */
+    index = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVEdgeIndex;
 
+  temp = SiS310_TVEdge1[temp][index];
+  temp <<= 5;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x3A,0x1F,temp);  /* index 0A D[7:5] */
 }
 
+/* TW: Checked against 650/301LVx 1.10.6s BIOS (incl data) */
 void
-SetYFilter(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-           ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SetYFilter(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+           UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT Part2Port,temp1,temp2;
-  USHORT index,temp,i,index1;
-  UCHAR  OutputSelect=*pSiS_OutputSelect;
-  Part2Port=BaseAddr+SIS_CRT2_PORT_10;
-  temp = GetTVPtrIndex();
-  temp >>= 1;  /* 0: NTSC, 1 :PAL, 2:HiTV */
+  USHORT index, temp, i, j;
+  UCHAR  OutputSelect = *SiS_Pr->pSiS_OutputSelect;
 
-  if (ModeNo<=0x13)
-  {
-    index =  SiS_SModeIDTable[ModeIdIndex].VB_StTVYFilterIndex;
-  }
-  else
-  {
-    index =  SiS_EModeIDTable[ModeIdIndex].VB_ExtTVYFilterIndex;
+  temp = GetTVPtrIndex(SiS_Pr);
+  temp >>= 1;  			/* 0: NTSC, 1: PAL, 2: HiTV */
+
+  if (ModeNo<=0x13) {
+    index =  SiS_Pr->SiS_SModeIDTable[ModeIdIndex].VB_StTVYFilterIndex;
+  } else {
+    index =  SiS_Pr->SiS_EModeIDTable[ModeIdIndex].VB_ExtTVYFilterIndex;
   }
 
-  if (SiS_VBInfo&SetCRT2ToHiVisionTV)  /* Hivision TV use PAL */
-   temp = 0;
+  if(SiS_Pr->SiS_VBInfo&SetCRT2ToHiVisionTV)  temp = 1;  /* Hivision TV uses PAL */
 
-  /*301b*/
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-    for(i=0x35;i<=0x38;i++)
-   {
-     SiS_SetReg1(Part2Port,i,SiS310_TVYFilter2[temp][index][i-0x35]);
-   }
-   for(i=0x48;i<=0x4A;i++)
-   {
-     SiS_SetReg1(Part2Port,i,SiS310_TVYFilter2[temp][index][(i-0x48)+0x04]);
-   }
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+    for(i=0x35, j=0; i<=0x38; i++, j++) {
+       SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_TVYFilter2[temp][index][j]);
+    }
+    for(i=0x48; i<=0x4A; i++, j++) {
+       SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_TVYFilter2[temp][index][j]);
+    }
+  } else {
+    for(i=0x35, j=0; i<=0x38; i++, j++){
+       SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_TVYFilter1[temp][index][j]);
+    }
   }
-      /*end 301b*/
-  else{
-   for(i=0x35;i<=0x38;i++)
-   {
-     SiS_SetReg1(Part2Port,i,SiS310_TVYFilter1[temp][index][i-0x35]);
-   }
+  
+  if(ROMAddr && SiS_Pr->SiS_UseROM) {
+  	OutputSelect = ROMAddr[0xf3];
   }
-/*add PALMN*/
-    if(OutputSelect&EnablePALMN) {                  
-      index1=SiS_GetReg1(SiS_P3d4,0x31);
-      temp1=index1&0x01;
-      index1=SiS_GetReg1(SiS_P3d4,0x38);
-      temp2=index1&0xC0;
-      if(temp1){
-         if(temp2==0x40){
-              if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-                 for(i=0x35;i<=0x38;i++){
-                      SiS_SetReg1(Part2Port,i,SiS310_PALMFilter2[index][i-0x35]);
-                     }
-                 for(i=0x48;i<=0x4A;i++) {
-                       SiS_SetReg1(Part2Port,i,SiS310_PALMFilter2[index][(i-0x48)+0x04]);
-                     }
-                }
-              else{ 
-                 for(i=0x35;i<=0x38;i++)
-                 SiS_SetReg1(Part2Port,i,SiS310_PALMFilter[index][i-0x35]);
-                 } 
-             }
-         if(temp2==0x80){ 
-              if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-                 for(i=0x35;i<=0x38;i++){
-                      SiS_SetReg1(Part2Port,i,SiS310_PALNFilter2[index][i-0x35]);
-                     }
-                 for(i=0x48;i<=0x4A;i++) {
-                       SiS_SetReg1(Part2Port,i,SiS310_PALNFilter2[index][(i-0x48)+0x04]);
-                     }
+  if(OutputSelect & EnablePALMN) {
+      if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x01) {
+         temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+         temp &= (EnablePALMN | EnablePALN);
+         if(temp == EnablePALMN) {
+              if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+                 for(i=0x35, j=0; i<=0x38; i++, j++){
+                      SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_PALMFilter2[index][j]);
+                 }
+                 for(i=0x48; i<=0x4A; i++, j++) {
+                       SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_PALMFilter2[index][j]);
+                 }
+              } else {
+                 for(i=0x35, j=0; i<=0x38; i++, j++) {
+                       SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_PALMFilter[index][j]);
+                 }
+              }
+         }
+         if(temp == EnablePALN) {
+              if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+                 for(i=0x35, j=0; i<=0x38; i++, j++) {
+                      SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_PALNFilter2[index][j]);
+                 }
+                 for(i=0x48, j=0; i<=0x4A; i++, j++) {
+                       SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_PALNFilter2[index][j]);
+                 }
+             } else {
+                 for(i=0x35, j=0; i<=0x38; i++, j++)
+                       SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_PALNFilter[index][j]);
              }
-              else{
-                 for(i=0x35;i<=0x38;i++)
-                 SiS_SetReg1(Part2Port,i,SiS310_PALNFilter[index][i-0x35]);
-                }
-          }
+         }
       }
-    }
-    /*end PALMN*/
+  }
 }
 
+/* TW: Checked against 650/301LVx 1.10.6s BIOS (including data) */
 void
-SetPhaseIncr(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-             ULONG ROMAddr,USHORT ModeNo)
+SetPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+             UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT Part2Port;
-  USHORT index,temp,temp1,i;
+  USHORT index,temp,temp1,i,j,resinfo;
+
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToTV)) return;
 
-  Part2Port=BaseAddr+SIS_CRT2_PORT_10;
-  temp = GetTVPtrIndex();
-  /* 0: NTSC Graphics, 1: NTSC Text, 2 :PAL Graphics, 3 :PAL Text, 4:HiTV Graphics 5:HiTV Text */
+  temp1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);        /* if PALM/N not set */
+  temp1 &=  (EnablePALMN | EnablePALN);
+  if(temp1) return;
+
+
+  if (ModeNo<=0x13) {
+    resinfo =  SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+  } else {
+    resinfo =  SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  }
+
+  temp = GetTVPtrIndex(SiS_Pr);
+  /* 0: NTSC Graphics, 1: NTSC Text,    2:PAL Graphics,
+   * 3: PAL Text,      4: HiTV Graphics 5:HiTV Text
+   */
   index = temp % 2;
-  temp >>= 1;   /* 0: NTSC, 1 :PAL, 2:HiTV */
-  temp1=SiS_GetReg1(SiS_P3d4,0x38);        /*if PALMN Not Set*/
-  temp1=temp1&0xC0; 
-  if(!temp1){
-  	for(i=0x31;i<=0x34;i++)
-  	{
-    		if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-     			SiS_SetReg1(Part2Port,i,SiS310_TVPhaseIncr2[temp][index][i-0x31]);
-    		else
-     			SiS_SetReg1(Part2Port,i,SiS310_TVPhaseIncr1[temp][index][i-0x31]);
-  	}
+  temp >>= 1;          /* 0:NTSC, 1:PAL, 2:HiTV */
+
+  for(j=0, i=0x31; i<=0x34; i++, j++) {
+     if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV))
+	  SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_TVPhaseIncr1[temp][index][j]);
+     else if((!(SiS_Pr->SiS_VBInfo & SetInSlaveMode)) || (SiS_Pr->SiS_SetFlag & TVSimuMode))
+          SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_TVPhaseIncr2[temp][index][j]);
+     else
+          SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS310_TVPhaseIncr1[temp][index][j]);
+  }
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {    /* TW: 650/301LV: (VB_SIS301LV | VB_SIS302LV)) */
+     if(!(SiS_Pr->SiS_VBInfo & SetPALTV)) {
+        if(resinfo == 6) {
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x31,0x21);
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x32,0xf0);
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x33,0xf5);
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x34,0x7f);
+	} else if (resinfo == 7) {
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x31,0x21);
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x32,0xf0);
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x33,0xf5);
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x34,0x7f);
+	} else if (resinfo == 8) {
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x31,0x1e);
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x32,0x8b);
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x33,0xfb);
+	      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x34,0x7b);
+	}
+     }
   }
 }
 
 void
-SiS_OEM310Setting(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-                  ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SiS_OEM310Setting(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+                  UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-   SetDelayComp(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
-   if (SiS_VBInfo&SetCRT2ToTV) {
-       SetAntiFlicker(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
-       SetPhaseIncr(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
-       SetYFilter(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
-       SetEdgeEnhance(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+   SetDelayComp(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
+   /* TW: The TV funtions are not for LVDS */
+   if( (SiS_Pr->SiS_IF_DEF_LVDS == 0) && (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) ) {
+       SetAntiFlicker(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+       SetPhaseIncr(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+       SetYFilter(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+       if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) {
+          SetEdgeEnhance(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+       }
    }
 }
 
+/* TW: New from 650/301LVx 1.10.6s - clashes with OEMLCD() */
+void
+SiS_FinalizeLCD(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+                USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+  USHORT tempcl,tempch,tempbl,tempbh,tempbx,tempax,temp;
+  USHORT resinfo;
+
+  if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) return;
+
+  if(ModeNo<=0x13) {
+	resinfo = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ResInfo;
+  } else {
+    	resinfo = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_RESINFO;
+  }
+
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToLCDA)) {
+     if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+        SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x2a,0x00);
+	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x30,0x00);
+	SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x34,0x10);
+     }
+     tempch = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x36);
+     tempch &= 0xf0;
+     tempch >>= 4;
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+	   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x1f,0x76);
+	}
+     } else {
+        tempcl = tempbh = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x01);
+	tempcl &= 0x0f;
+	tempbh &= 0x70;
+	tempbh >>= 4;
+	tempbl = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x04);
+	tempbx = (tempbh << 8) | tempbl;
+	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1024x768) {
+	   if((resinfo == 8) || (!(SiS_Pr->SiS_LCDInfo & LCDNonExpanding))) {
+	      if(SiS_Pr->SiS_SetFlag & LCDVESATiming) {
+	      	tempbx = 770;
+	      } else {
+	        if(tempbx > 770) tempbx = 770;
+		if(SiS_Pr->SiS_VGAVDE < 600) {                   /* Shouldn't that be <=? */
+		   tempax = 768 - SiS_Pr->SiS_VGAVDE;
+		   tempax >>= 3;
+		   if(SiS_Pr->SiS_VGAVDE < 480)  tempax >>= 1;   /* Shouldn't that be <=? */
+		   tempbx -= tempax;
+		}
+	      }
+	   } else return;
+	}
+#if 0
+	if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+	}
+#endif
+	temp = tempbx & 0xff;
+	SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x04,temp);
+	temp = (tempbx & 0xff00) >> 8;
+	temp <<= 4;
+	temp |= tempcl;
+	SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,temp);
+     }
+  }
+}
+
+/* TW: New and checked from 650/301LV BIOS */
+/* This might clash with newer "FinalizeLCD()" function */
+void
+SiS_OEMLCD(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+                  UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+{
+   USHORT tempbx,tempah,tempbl,tempbh,tempcl;
+
+   if(!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) return;
+
+   if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+      SiS_UnLockCRT2(SiS_Pr,HwDeviceExtension,BaseAddr);
+      tempbh = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x1a);
+      tempbh &= 0x38;
+      tempbh >>= 3;
+      tempbl = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x18);
+      tempbx = (tempbh << 8) | tempbl;
+      if(SiS_Pr->SiS_LCDTypeInfo == 1)  tempbx -= 0x12;
+      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x18,tempbx & 0x00ff);
+      tempah = (tempbx & 0xff00) >> 8;
+      tempah &= 0x07;
+      tempah <<= 3;
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x1a,0xc7,tempah);
+      tempah = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x19);
+      tempah &= 0x0f;
+      if(SiS_Pr->SiS_LCDTypeInfo == 1)  tempah -= 2;
+      tempah &= 0x0f;
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x19,0xF0,tempah);
+      tempah = SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x14);
+      if(SiS_Pr->SiS_LCDTypeInfo == 1)  tempah++;
+      tempah -= 8;
+      SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x14,tempah);
+   } else if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+      tempcl = tempbh = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x01);
+      tempbh &= 0x70;
+      tempbh >>= 4;
+      tempbl = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x04);
+      tempbx = (tempbh << 8) | tempbl;
+      if(SiS_Pr->SiS_LCDTypeInfo == 1)  {
+           tempbx -= 0x1e;
+	   tempcl &= 0x0f;
+	   tempcl -= 4;
+	   tempcl &= 0x0f;
+      }
+      tempbl = tempbx & 0x00ff;
+      tempbh = (tempbx >> 8) & 0x00ff;
+      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x04,tempbl);
+      tempbh <<= 4;
+      tempbh |= tempcl;
+      SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x01,0x80,tempbh);
+   }
+}
 #endif
 
+
+/*  =================  SiS 300 O.E.M. ================== */
+
 #ifdef SIS300
-/*
-    for SIS300 O.E.M.
-*/
 
+#if 0   /* Not used */
 USHORT
-GetRevisionID(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+GetRevisionID(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-   ULONG temp1,base;
-   USHORT temp2=0; 
-   
+   ULONG temp1;
+#ifndef LINUX_XF86
+   ULONG base;
+#endif
+   USHORT temp2 = 0;
+
    if((HwDeviceExtension->jChipType==SIS_540)||
       (HwDeviceExtension->jChipType==SIS_630)||
       (HwDeviceExtension->jChipType==SIS_730)) {
-     	base=0x80000008;
+#ifndef LINUX_XF86
+     	base = 0x80000008;
      	OutPortLong(base,0xcf8);
-     	temp1=InPortLong(0xcfc);
-     	temp1=temp1&0x000000FF;
-     	temp2=(USHORT)(temp1);
+     	temp1 = InPortLong(0xcfc);
+#else
+	temp1=pciReadLong(0x00000000, 0x08);
+#endif
+     	temp1 &= 0x000000FF;
+     	temp2 = (USHORT)(temp1);
     	return temp2;
    }
    return 0;
 }
+#endif
 
+/* TW: Checked against 630/301B BIOS (incl data) */
 USHORT
-GetOEMTVPtr(void)
+GetOEMLCDPtr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, int Flag)
 {
-  USHORT index;
+  USHORT tempbx=0;
+  UCHAR customtable[] = {
+  	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+	0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
+  };
 
-  index = 0;
-  if (!(SiS_VBInfo&SetInSlaveMode))
-      	index=index+4;
-  
-  if (SiS_VBInfo&SetCRT2ToSCART){
-      	index=index+2;
+  if(Flag) {
+      if(customtable[SiS_Pr->SiS_LCDTypeInfo] == 0xFF) return 0xFFFF;
+  }
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+        tempbx = SiS_Pr->SiS_LCDTypeInfo << 2;
+	if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) tempbx += 2;
+	if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx++;
   } else {
-     	if (SiS_VBInfo&SetCRT2ToHiVisionTV)
-       		index=index+3;
-     	else {
-          	if(SiS_VBInfo&SetPALTV)
-          		index=index+1;
-        }
+  	tempbx = SiS_Pr->SiS_LCDTypeInfo;
+	if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx += 16;
   }
-  return index;
+  return tempbx;
 }
 
-/* TW: This is not for LVDS/Chrontel */
+/* TW: Checked against 630/301B and 630/LVDS BIOS (incl data) */
 void
-SetOEMTVDelay(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-              ULONG ROMAddr,USHORT ModeNo)
-{
-  USHORT Part1Port;
-  USHORT index,temp,ModeIdIndex;
-
-  Part1Port=BaseAddr+SIS_CRT2_PORT_04;
-  ModeIdIndex=SiS_SearchVBModeID(ROMAddr,ModeNo);
-  temp = GetOEMTVPtr();
-  index = SiS_VBModeIDTable[ModeIdIndex].VB_TVDelayIndex;
-  temp = SiS300_OEMTVDelay[temp][index];
-  temp=temp&0x3c;
-  SiS_SetRegANDOR(Part1Port,0x13,~0x3C,temp);  /* index 0A D[6:4] */
-}
-
-USHORT
-GetOEMLCDPtr(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SetOEMLCDDelay(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+               UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  /* USHORT temp,tempax; */
-  USHORT tempbx=0;
+  USHORT index,temp;
 
-  if(SiS_IF_DEF_LVDS==0) {
+  /* TW: The Panel Compensation Delay should be set according to tables
+   *     here. Unfortunately, the different BIOS versions don't case about
+   *     a uniform way using eg. ROM byte 0x220, but use different
+   *     hard coded delays (0x04, 0x20, 0x18) in SetGroup1(). So we can't
+   *     rely on the other OEM bits in 0x237, 0x238 here either.
+   *     ROMAddr > 0x233 is even used for code (!) in newer BIOSes!
+   */
 #if 0
-  	tempax=tempbx=SiS_LCDResInfo;
-      	tempbx=tempbx-Panel1024x768;
-     	if(!(SiS_SetFlag&LCDVESATiming)) {
-        	tempbx+=4;
-        	temp=GetRevisionID(HwDeviceExtension);
-        	if((HwDeviceExtension->jChipType == SIS_540)&&(temp<1))
-        		tempbx+=4;
-        	if((HwDeviceExtension->jChipType == SIS_630)&&(temp<3))
-        		tempbx+=4;
-       	}
-     	if((tempax==Panel1024x768)&&(SiS_LCDInfo&LCDNonExpanding)){
-        	tempbx=tempbx+3;
-       	}
+  if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+     if(!(ROMAddr[0x237] & 0x01)) return;
+     if(!(ROMAddr[0x237] & 0x02)) return;
+  }
 #endif
+  /* TW: We just check if a non-standard delay has been set; if not,
+   * we use our tables. Otherwise don't do anything here.
+   */
+  if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+     if(ROMAddr[0x220] & 0x80) return;
+  }
+  /* TW: We don't need to set this if the user select a custom pdc */
+  if(HwDeviceExtension->pdc) return;
 
-	/* TW: This is total bullshit. First, we calculate tempbx, now
-	 *     we overwrite it?! (Therefore commented code above)
-	 */
+  temp = GetOEMLCDPtr(SiS_Pr,HwDeviceExtension, 0);
 
-     	/*add OEMLCDPanelIDSupport*/
-        tempbx=SiS_LCDTypeInfo;
+  index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_LCDDelayIndex;
 
-#if 0   /* TW: Commented for DEBUG: */
-        tempbx=tempbx<<1;
-        if(!(SiS_SetFlag&LCDVESATiming))
-        	tempbx=tempbx+1;
-	tempbx*=2;
-	/* TW: The above code results in eg. 0xc * 2 * 2 = 48, but Delay2 table has
-	 *     only 32 entries. Thus, this can't work */
-#endif
-        /* TW: Don't think that 301(B) bridges need different LCD delay... */
-  	tempbx = SiS_LCDTypeInfo;
-	if(SiS_LCDInfo&LCDNonExpanding){
-      		tempbx=tempbx+16;
-	}
-  } else {  /* TW: Added LVDS code */
-  	tempbx = SiS_LCDTypeInfo;
-	if(SiS_LCDInfo&LCDNonExpanding){
-      		tempbx=tempbx+16;
-	}
+  if (SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+    	temp = SiS300_OEMLCDDelay2[temp][index];
+  } else {
+        temp = SiS300_OEMLCDDelay3[temp][index];
   }
-  return tempbx;
+  temp &= 0x3c;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp);  /* index 0A D[6:4] */
 }
 
-#if 0
-/* TW: Original code - can't work (eg. exceeds arrays by re-using temp,
-       writes to Part2(!)Port unlike TVDelay, etc...) */
-void
-SetOEMLCDDelay(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-               ULONG ROMAddr,USHORT ModeNo)
+/* TW: Checked against 630/301B 2.04.50 and 630/LVDS BIOS */
+USHORT
+GetOEMTVPtr(SiS_Private *SiS_Pr)
 {
-  USHORT Part2Port;
-  USHORT index,temp,ModeIdIndex;
-  Part2Port=BaseAddr+SIS_CRT2_PORT_10;
-  ModeIdIndex=SiS_SearchVBModeID(ROMAddr,ModeNo);
-  temp = GetOEMLCDPtr(HwDeviceExtension);
-  index = SiS_VBModeIDTable[ModeIdIndex].VB_LCDDelayIndex;
-  temp = SiS300_OEMLCDDelay1[temp][index];
-   /*add OEMLCDPanelIDSupport*/
-  temp = SiS300_OEMLCDDelay2[temp][index];
-  temp=temp&0x3c;
-  SiS_SetRegANDOR(Part2Port,0x13,~0x3C,temp);  /* index 0A D[6:4] */
+  USHORT index;
+
+  index = 0;
+  if(!(SiS_Pr->SiS_VBInfo & SetInSlaveMode))  index += 4;
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToSCART)  index += 2;
+     else if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) index += 3;
+     else if(SiS_Pr->SiS_VBInfo & SetPALTV)   index += 1;
+  } else {
+     if(SiS_Pr->SiS_VBInfo & SetCHTVOverScan) index += 2;
+     if(SiS_Pr->SiS_VBInfo & SetPALTV)        index += 1;
+  }
+  return index;
 }
-#endif
 
-/* TW: Although I assume that the code above does not work correctly,
- *     I won't change it for non-LVDS machines until someone tells me so.
- */
+/* TW: Checked against 630/301B 2.04.50 and 630/LVDS BIOS (incl data) */
 void
-SetOEMLCDDelay(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-               ULONG ROMAddr,USHORT ModeNo)
+SetOEMTVDelay(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+              UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT Part1Port, Part2Port;
-  USHORT index,temp,ModeIdIndex;
-
-  Part1Port=BaseAddr+SIS_CRT2_PORT_04;
-  Part2Port=BaseAddr+SIS_CRT2_PORT_10;
+  USHORT index,temp;
 
-  ModeIdIndex=SiS_SearchVBModeID(ROMAddr,ModeNo);
-  temp = GetOEMLCDPtr(HwDeviceExtension);
-  index = SiS_VBModeIDTable[ModeIdIndex].VB_LCDDelayIndex; /* TW: Always zero... */
-  if (SiS_IF_DEF_LVDS == 1) {
-  	/* TW: Added for LVDS: Assuming Part_1!!!_Port to be the correct one */
-    	temp = SiS300_OEMLCDDelay3[temp][index];
-	temp=temp&0x3c;
-  	SiS_SetRegANDOR(Part1Port,0x13,~0x3C,temp);  /* index 0A D[6:4] */
-  } else {
-        /* temp = SiS300_OEMLCDDelay1[temp][index];  */
-	/*  TW: This must be wrong: temp is eg. 48 and
-		thus exceeds array size of Delay2 table! */
-
-        /*add OEMLCDPanelIDSupport*/
-
-#if 0  /* TW: Commented for DEBUG */
-	temp = SiS300_OEMLCDDelay2[temp][index];
-	temp=temp&0x3c;
-  	SiS_SetRegANDOR(Part2Port,0x13,~0x3C,temp);  /* index 0A D[6:4] */
+#if 0  /* TW: Not used in newer BIOSes (2.04.5a) */
+  if((ROMAddr) && SiS_Pr->SiS_UseROM) {
+     if(!(ROMAddr[0x238] & 0x01)) return;
+     if(!(ROMAddr[0x238] & 0x02)) return;
+  }
 #endif
+  temp = GetOEMTVPtr(SiS_Pr);
 
-        /* TW: 301B reported not working. Maybe because of the above bullshit? */
-	/*     Do it like for LVDS now. 0x13 seems to be the LCD delay anyway */
-        temp = SiS300_OEMLCDDelay3[temp][index];
-	temp=temp&0x3c;
-  	SiS_SetRegANDOR(Part1Port,0x13,~0x3C,temp);  /* index 0A D[6:4] */
+  index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVDelayIndex;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+     temp = SiS300_OEMTVDelay301[temp][index];
+  } else {
+     temp = SiS300_OEMTVDelayLVDS[temp][index];
   }
+  temp &= 0x3c;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x13,~0x3C,temp);  /* index 0A D[6:4] */
 }
 
-/*
-*/
+/* TW: Checked against 630/301B 2.04.50 BIOS (incl data) */
 void
-SetOEMAntiFlicker(PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                  USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo)
+SetOEMAntiFlicker(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                  USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+		  USHORT ModeIdIndex)
 {
-  USHORT Part2Port;
   USHORT index,temp;
-  USHORT ModeIdIndex;
 
-  Part2Port=BaseAddr+SIS_CRT2_PORT_10;
-  ModeIdIndex=SiS_SearchVBModeID(ROMAddr,ModeNo);
-  temp = GetOEMTVPtr();
-  index = SiS_VBModeIDTable[ModeIdIndex].VB_TVFlickerIndex;
+  temp = GetOEMTVPtr(SiS_Pr);
+
+  index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVFlickerIndex;
+
   temp = SiS300_OEMTVFlicker[temp][index];
-  temp=temp&0x70;
-  SiS_SetRegANDOR(Part2Port,0x0A,~0x70,temp);  /* index 0A D[6:4] */
+  temp &= 0x70;
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part2Port,0x0A,0x8F,temp);  /* index 0A D[6:4] */
 }
 
+/* TW: Checked against 630/301B 2.04.50 BIOS (incl data) */
 void
-SetOEMPhaseIncr(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-                ULONG ROMAddr,USHORT ModeNo)
+SetOEMPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+                UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT Part2Port;
-  USHORT index,i,ModeIdIndex;
-
-  Part2Port=BaseAddr+SIS_CRT2_PORT_10;
-  /* temp = GetTVPtrIndex();*/
-  /* 0: NTSC Graphics, 1: NTSC Text, 2 :PAL Graphics, 3 :PAL Text, 4:HiTV Graphics 5:HiTV Text */
-  /* index = temp % 2;*/
-  /* temp >>= 1;   0: NTSC, 1 :PAL, 2:HiTV */
-  ModeIdIndex=SiS_SearchVBModeID(ROMAddr,ModeNo);
-  index = SiS_VBModeIDTable[ModeIdIndex].VB_TVPhaseIndex;
-  if (SiS_VBInfo&SetInSlaveMode){
-      if(SiS_VBInfo&SetPALTV){  
-         for(i=0x31;i<=0x34;i++)
-        	SiS_SetReg1(Part2Port,i,SiS300_StPALPhase[index][i-0x31]);
-      } else {
-          for(i=0x31;i<=0x34;i++)
-        	SiS_SetReg1(Part2Port,i,SiS300_StNTSCPhase[index][i-0x31]);
-      }
-      if(SiS_VBInfo&SetCRT2ToSCART){
-          for(i=0x31;i<=0x34;i++)
-        	SiS_SetReg1(Part2Port,i,SiS300_StSCARTPhase[index][i-0x31]);
-      }
-  } else {
-       if(SiS_VBInfo&SetPALTV){  
-          for(i=0x31;i<=0x34;i++)
-        	SiS_SetReg1(Part2Port,i,SiS300_ExtPALPhase[index][i-0x31]);
-       } else {
-          for(i=0x31;i<=0x34;i++)
-        	SiS_SetReg1(Part2Port,i,SiS300_ExtNTSCPhase[index][i-0x31]);
+  USHORT index,i,j,temp;
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToHiVisionTV) return;
+
+  temp = GetOEMTVPtr(SiS_Pr);
+
+  index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVPhaseIndex;
+
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+       for(i=0x31, j=0; i<=0x34; i++, j++) {
+          SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS300_Phase2[temp][index][j]);
        }
-       if(SiS_VBInfo&SetCRT2ToSCART){
-          for(i=0x31;i<=0x34;i++)
-        	SiS_SetReg1(Part2Port,i,SiS300_ExtSCARTPhase[index][i-0x31]);
+  } else {
+       for(i=0x31, j=0; i<=0x34; i++, j++) {
+          SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS300_Phase1[temp][index][j]);
        }
   }
 }
 
+/* TW: Checked against 630/301B 2.04.50 BIOS (incl data) */
 void
-SetOEMYFilter(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-              ULONG ROMAddr,USHORT ModeNo)
+SetOEMYFilter(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+              UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT Part2Port;
-  USHORT index,temp1,temp2,i,ModeIdIndex,index1;
-  Part2Port=BaseAddr+SIS_CRT2_PORT_10;
-    /*301b*/
-  ModeIdIndex=SiS_SearchVBModeID(ROMAddr,ModeNo);
-  index = SiS_VBModeIDTable[ModeIdIndex].VB_TVYFilterIndex;
-  if (SiS_VBInfo&SetInSlaveMode){
-      if(SiS_VBInfo&SetPALTV){  
-        	for(i=0x35;i<=0x38;i++)
-        		SiS_SetReg1(Part2Port,i,SiS300_StPALFilter[index][i-0x35]);
-      } else {
-         	 for(i=0x35;i<=0x38;i++)
-        		SiS_SetReg1(Part2Port,i,SiS300_StNTSCFilter[index][i-0x35]);
-      }
-  } else{
-      if(SiS_VBInfo&SetPALTV) {
-         for(i=0x35;i<=0x38;i++)
-        	SiS_SetReg1(Part2Port,i,SiS300_ExtPALFilter[index][i-0x35]);
-      } else{
-          for(i=0x35;i<=0x38;i++)
-        	SiS_SetReg1(Part2Port,i,SiS300_ExtNTSCFilter[index][i-0x35]);
-      }
-  }
+  USHORT index,temp,temp1,i,j;
 
-  if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-    if(SiS_VBInfo&SetPALTV){  
-    	for(i=0x35;i<=0x38;i++)
-    	{
-     		SiS_SetReg1(Part2Port,i,SiS300_PALFilter2[index][i-0x35]);
-    	}
-   	for(i=0x48;i<=0x4A;i++)
-    	{
-     		SiS_SetReg1(Part2Port,i,SiS300_PALFilter2[index][(i-0x48)+0x04]);
-    	}
-    } else {
-  	for(i=0x35;i<=0x38;i++)
-    	{
-     		SiS_SetReg1(Part2Port,i,SiS300_NTSCFilter2[index][i-0x35]);
-     	}
-   	for(i=0x48;i<=0x4A;i++)
-    	{
-     		SiS_SetReg1(Part2Port,i,SiS300_NTSCFilter2[index][(i-0x48)+0x04]);
-    	}
-    }
-  }
+  if(SiS_Pr->SiS_VBInfo & (SetCRT2ToSCART | SetCRT2ToHiVisionTV)) return;
 
-/*add PALMN*/
-  if((HwDeviceExtension->jChipType==SIS_630)||
-     (HwDeviceExtension->jChipType==SIS_730)) {
-      index1=SiS_GetReg1(SiS_P3d4,0x31);
-      temp1=index1&0x01;
-      index1=SiS_GetReg1(SiS_P3d4,0x35);
-      temp2=index1&0xC0;
-      if(temp1){
-         if(temp2==0x40){
-              if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-                 for(i=0x35;i<=0x38;i++){
-                      SiS_SetReg1(Part2Port,i,SiS300_PALMFilter2[index][i-0x35]);
-                 }
-                 for(i=0x48;i<=0x4A;i++) {
-                       SiS_SetReg1(Part2Port,i,SiS300_PALMFilter2[index][(i-0x48)+0x04]);
-                 }
-              } else {
-                 for(i=0x35;i<=0x38;i++)
-                 	SiS_SetReg1(Part2Port,i,SiS300_PALMFilter[index][i-0x35]);
-              }
-         }
-         if(temp2==0x80){ 
-              if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-                 for(i=0x35;i<=0x38;i++){
-                      SiS_SetReg1(Part2Port,i,SiS300_PALNFilter2[index][i-0x35]);
-                 }
-                 for(i=0x48;i<=0x4A;i++) {
-                       SiS_SetReg1(Part2Port,i,SiS300_PALNFilter2[index][(i-0x48)+0x04]);
-                 }
-             } else {
-                 for(i=0x35;i<=0x38;i++)
-                 	SiS_SetReg1(Part2Port,i,SiS300_PALNFilter[index][i-0x35]);
-             }
-          }
+  temp = GetOEMTVPtr(SiS_Pr);
+
+  index = SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].VB_TVYFilterIndex;
+
+  if(HwDeviceExtension->jChipType > SIS_300) {
+     if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x01) {
+       temp1 = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x35);
+       if(temp1 & (EnablePALMN | EnablePALN)) {
+          temp = 8;
+	  if(temp1 & EnablePALN) temp = 9;
+       }
+     }
+  }
+  if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      for(i=0x35, j=0; i<=0x38; i++, j++) {
+       	SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS300_Filter2[temp][index][j]);
       }
-   }
-  /*end PALMN*/
+      for(i=0x48; i<=0x4A; i++, j++) {
+     	SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS300_Filter2[temp][index][j]);
+      }
+  } else {
+      for(i=0x35, j=0; i<=0x38; i++, j++) {
+       	SiS_SetReg1(SiS_Pr->SiS_Part2Port,i,SiS300_Filter1[temp][index][j]);
+      }
+  }
 }
 
 void
-SiS_OEM300Setting(PSIS_HW_DEVICE_INFO HwDeviceExtension,
-		  USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo)
+SiS_OEM300Setting(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+		  USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo)
 {
-  if (SiS_VBInfo & SetCRT2ToLCD) {
-       SetOEMLCDDelay(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
-  }
-  if (SiS_VBInfo & SetCRT2ToTV) {
-       /* TW: (Added LVDS check) - done this way now because LVDS
-        * seems to be 1 for some of the SiS bridges as well
-	*/
-       if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-       						|| (SiS_IF_DEF_LVDS==0))  {
-	        SetOEMTVDelay(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
-       		SetOEMAntiFlicker(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
-    		/* SetOEMPhaseIncr(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);*/
-       		SetOEMYFilter(HwDeviceExtension,BaseAddr,ROMAddr,ModeNo);
+  USHORT ModeIdIndex;
+
+  ModeIdIndex = SiS_SearchVBModeID(SiS_Pr,ROMAddr,&ModeNo);
+  if(!(ModeIdIndex)) return;
+
+  if (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+       SetOEMLCDDelay(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+  }
+  if (SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+       SetOEMTVDelay(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+       if(SiS_Pr->SiS_IF_DEF_LVDS==0) {
+       		SetOEMAntiFlicker(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+    		SetOEMPhaseIncr(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
+       		SetOEMYFilter(SiS_Pr,HwDeviceExtension,BaseAddr,ROMAddr,ModeNo,ModeIdIndex);
        }
-    }
+  }
 }
 #endif
+
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/sis/init301.h linux.20pre10-ac2/drivers/video/sis/init301.h
--- linux.20pre10/drivers/video/sis/init301.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/sis/init301.h	2002-10-11 00:35:04.000000000 +0100
@@ -17,6 +17,7 @@
 
 #ifdef LINUX_XF86
 #include "xf86.h"
+#include "xf86Pci.h"
 #include "xf86PciInfo.h"
 #include "sis.h"
 #include "sis_regs.h"
@@ -35,202 +36,267 @@
 #include "dderror.h"
 #include "devioctl.h"
 #include "miniport.h"
-
 #include "ntddvdeo.h"
 #include "video.h"
 #include "sisv.h"
 #endif
 
-USHORT   SiS_SetFlag;
-USHORT   SiS_RVBHCFACT,SiS_RVBHCMAX,SiS_RVBHRS;
-USHORT   SiS_VGAVT,SiS_VGAHT;
-USHORT   SiS_VT,SiS_HT;
-USHORT   SiS_VGAVDE,SiS_VGAHDE;
-USHORT   SiS_VDE,SiS_HDE;
-USHORT   SiS_NewFlickerMode,SiS_RY1COE,SiS_RY2COE,SiS_RY3COE,SiS_RY4COE;
-USHORT   SiS_LCDHDES,SiS_LCDVDES;
-USHORT   SiS_DDC_Port;
-USHORT   SiS_DDC_Index;
-USHORT   SiS_DDC_DataShift;
-USHORT   SiS_DDC_DeviceAddr;
-USHORT   SiS_DDC_Flag;
-USHORT   SiS_DDC_ReadAddr;
-USHORT   SiS_DDC_Buffer;
-
-extern   USHORT   SiS_CRT1Mode;
-extern   USHORT   SiS_P3c4,SiS_P3d4;
-/*extern   USHORT      SiS_P3c0,SiS_P3ce,SiS_P3c2;*/
-extern   USHORT   SiS_P3ca;
-/*extern   USHORT      SiS_P3c6,SiS_P3c7,SiS_P3c8;*/
-extern   USHORT   SiS_P3c9;
-extern   USHORT   SiS_P3da;
-extern   USHORT   SiS_Part1Port,SiS_Part2Port;
-extern   USHORT   SiS_Part3Port,SiS_Part4Port,SiS_Part5Port;
-extern   USHORT   SiS_MDA_DAC[];
-extern   USHORT   SiS_CGA_DAC[];
-extern   USHORT   SiS_EGA_DAC[];
-extern   USHORT   SiS_VGA_DAC[];
-extern   USHORT   SiS_ModeType;
-extern   USHORT   SiS_SelectCRT2Rate;
-extern   USHORT   SiS_IF_DEF_LVDS;
-extern   USHORT   SiS_IF_DEF_TRUMPION;
-extern   USHORT   SiS_IF_DEF_CH7005;
-extern   USHORT   SiS_Backup7005;
-extern   USHORT   SiS_IF_DEF_HiVision;
-extern   USHORT   SiS_IF_DEF_DSTN;   /*add for dstn*/
-extern   USHORT   SiS_IF_DEF_FSTN;   /*add for fstn*/
-extern   USHORT   SiS_VBInfo;
-extern   USHORT   SiS_VBType;        /*301b*/
-extern   USHORT   SiS_VBExtInfo; /*301lv*/
-extern   USHORT   SiS_LCDResInfo;
-extern   USHORT   SiS_LCDTypeInfo;
-extern   USHORT   SiS_LCDInfo;
-extern   BOOLEAN  SiS_SearchVBModeID(ULONG, USHORT);
-extern   BOOLEAN  SiS_Is301B(USHORT BaseAddr);/*301b*/
-extern   BOOLEAN  SiS_IsDisableCRT2(USHORT BaseAddr);
-extern   BOOLEAN  SiS_IsVAMode(USHORT BaseAddr);
-extern   BOOLEAN  SiS_IsDualEdge(USHORT BaseAddr);
-/*end 301b*/
-
-void     SiS_SetDefCRT2ExtRegs(USHORT BaseAddr);
-USHORT   SiS_GetRatePtrCRT2(ULONG ROMAddr, USHORT ModeNo,USHORT ModeIdIndex);
-BOOLEAN  SiS_AdjustCRT2Rate(ULONG ROMAddr,USHORT ModeNo,USHORT MODEIdIndex,USHORT RefreshRateTableIndex,USHORT *i);
-void     SiS_SaveCRT2Info(USHORT ModeNo);
-void     SiS_GetCRT2Data(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-void     SiS_GetCRT2DataLVDS(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-void     SiS_GetCRT2PtrA(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex, USHORT *CRT2Index,USHORT *ResIndex);/*301b*/
-void     SiS_GetCRT2Data301(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-USHORT   SiS_GetResInfo(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-void     SiS_GetCRT2ResInfo(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-void     SiS_GetRAMDAC2DATA(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-void     SiS_GetCRT2Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,
-		USHORT *CRT2Index,USHORT *ResIndex);
-void     SiS_SetCRT2ModeRegs(USHORT BaseAddr,USHORT ModeNo,PSIS_HW_DEVICE_INFO );
-
-
-void     SiS_GetLVDSDesData(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-void     SiS_SetCRT2Offset(USHORT Part1Port,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-USHORT   SiS_GetOffset(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-USHORT   SiS_GetColorDepth(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-USHORT   SiS_GetVCLK(ULONG ROMAddr,USHORT ModeNo);
-USHORT   SiS_GetVCLKPtr(ULONG ROMAddr,USHORT ModeNo);
-USHORT   SiS_GetColorTh(ULONG ROMAddr);
-USHORT   SiS_GetMCLK(ULONG ROMAddr);
-USHORT   SiS_GetMCLKPtr(ULONG ROMAddr);
-USHORT   SiS_GetDRAMType(ULONG ROMAddr);
-USHORT   SiS_CalcDelayVB(void);
-extern USHORT   SiS_GetVCLK2Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_SetCRT2Sync(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT RefreshRateTableIndex);
+#if 0
+extern   const USHORT   SiS_MDA_DAC[];
+extern   const USHORT   SiS_CGA_DAC[];
+extern   const USHORT   SiS_EGA_DAC[];
+extern   const USHORT   SiS_VGA_DAC[];
+#endif
+
+extern   BOOLEAN  SiS_SearchVBModeID(SiS_Private *SiS_Pr, UCHAR *RomAddr, USHORT *);
+
+BOOLEAN  SiS_Is301B(SiS_Private *SiS_Pr, USHORT BaseAddr);
+BOOLEAN  SiS_IsM650or651(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+BOOLEAN  SiS_IsDisableCRT2(SiS_Private *SiS_Pr, USHORT BaseAddr);
+BOOLEAN  SiS_IsVAMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+BOOLEAN  SiS_IsDualEdge(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+BOOLEAN  SiS_CRT2IsLCD(SiS_Private *SiS_Pr, USHORT BaseAddr);
+void     SiS_SetDefCRT2ExtRegs(SiS_Private *SiS_Pr, USHORT BaseAddr);
+USHORT   SiS_GetRatePtrCRT2(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo,USHORT ModeIdIndex,
+                            PSIS_HW_DEVICE_INFO HwDeviceExtension);
+BOOLEAN  SiS_AdjustCRT2Rate(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT MODEIdIndex,
+                            USHORT RefreshRateTableIndex,USHORT *i,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SaveCRT2Info(SiS_Private *SiS_Pr, USHORT ModeNo);
+void     SiS_GetCRT2Data(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+		         USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_GetCRT2DataLVDS(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                             USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_GetCRT2PtrA(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                         USHORT RefreshRateTableIndex,USHORT *CRT2Index,USHORT *ResIndex);
+void     SiS_GetCRT2Part2Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+		             USHORT RefreshRateTableIndex,USHORT *CRT2Index, USHORT *ResIndex);
+void     SiS_GetCRT2Data301(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                            USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+USHORT   SiS_GetResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void     SiS_GetCRT2ResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                            PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_GetRAMDAC2DATA(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                            USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_GetCRT2Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                        USHORT RefreshRateTableIndex,USHORT *CRT2Index,USHORT *ResIndex,
+			PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetCRT2ModeRegs(SiS_Private *SiS_Pr, USHORT BaseAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                             PSIS_HW_DEVICE_INFO );
+void     SiS_SetHiVision(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_GetLVDSDesData(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+			    USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetCRT2Offset(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                           USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+USHORT   SiS_GetOffset(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                       USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+USHORT   SiS_GetColorDepth(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+USHORT   SiS_GetMCLK(SiS_Private *SiS_Pr, UCHAR *ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+USHORT   SiS_CalcDelayVB(SiS_Private *SiS_Pr);
+USHORT   SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                         USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetCRT2Sync(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+                         USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
 void     SiS_SetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR);
 void     SiS_SetRegOR(USHORT Port,USHORT Index,USHORT DataOR);
 void     SiS_SetRegAND(USHORT Port,USHORT Index,USHORT DataAND);
-USHORT   SiS_GetVGAHT2(void);
-void     SiS_SetGroup2(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_SetGroup3(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_SetGroup4(USHORT  BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_SetGroup5(USHORT  BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-void     SiS_SetCRT2VCLK(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_EnableCRT2(void);
-void     SiS_LoadDAC2(ULONG ROMAddr,USHORT Part5Port,USHORT ModeNo,USHORT ModeIdIndex);
-void     SiS_WriteDAC2(USHORT Pdata,USHORT dl, USHORT ah, USHORT al, USHORT dh);
-void     SiS_GetVBInfo301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-BOOLEAN  SiS_GetLCDResInfo(ULONG ROMAddr,USHORT P3d4,USHORT ModeNo,USHORT ModeIdIndex);
-BOOLEAN  SiS_BridgeIsOn(USHORT BaseAddr);
-BOOLEAN  SiS_BridgeIsEnable(USHORT BaseAddr,PSIS_HW_DEVICE_INFO );
-BOOLEAN  SiS_BridgeInSlave(void);
-/*void     SiS_PresetScratchregister(USHORT P3d4);*/
-void     SiS_PresetScratchregister(USHORT SiS_P3d4,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_SetTVSystem(VOID);
-void     SiS_LongWait(VOID);
-USHORT   SiS_GetQueueConfig(VOID);
-void     SiS_VBLongWait(VOID);
-USHORT   SiS_GetVCLKLen(ULONG ROMAddr);
-BOOLEAN  SiS_WaitVBRetrace(USHORT  BaseAddr);
-void     SiS_SetCRT2ECLK(ULONG ROMAddr, USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_GetLVDSDesPtr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,USHORT *PanelIndex,USHORT *ResIndex);
-void     SiS_GetLVDSDesPtrA(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,USHORT *PanelIndex,USHORT *ResIndex);/*301b*/
-void     SiS_SetTPData(VOID);
-void     SiS_ModCRT1CRTC(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-extern BOOLEAN  SiS_GetLVDSCRT1Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,
-		       USHORT *ResInfo,USHORT *DisplayType);
-void     SiS_SetCHTVReg(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-void     SiS_SetCHTVRegANDOR(USHORT tempax,USHORT tempbh);
-void     SiS_GetCHTVRegPtr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-void     SiS_SetCH7005(USHORT tempax);
-USHORT   SiS_GetCH7005(USHORT tempax);
-void     SiS_SetSwitchDDC2(void);
-void     SiS_SetStart(void);
-void     SiS_SetStop(void);
-void     SiS_DDC2Delay(void);
-void     SiS_SetSCLKLow(void);
-void     SiS_SetSCLKHigh(void);
-USHORT   SiS_ReadDDC2Data(USHORT tempax);
-USHORT   SiS_WriteDDC2Data(USHORT tempax);
-USHORT   SiS_CheckACK(void);
-void     SiS_OEM310Setting(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-void     SiS_OEM300Setting(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo);
-USHORT GetRevisionID(PSIS_HW_DEVICE_INFO HwDeviceExtension);
-
-BOOLEAN SiS_GetLCDResInfo301(ULONG ROMAddr,USHORT SiS_P3d4, USHORT ModeNo,USHORT ModeIdIndex);
-void    SiS_CHACRT1CRTC(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+USHORT   SiS_GetVGAHT2(SiS_Private *SiS_Pr);
+void     SiS_SetGroup2(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                       USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetGroup3(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                       PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetGroup4(SiS_Private *SiS_Pr, USHORT  BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                       USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetGroup5(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO, USHORT  BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+                       USHORT ModeIdIndex);
+void     SiS_FinalizeLCD(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                         PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetCRT2VCLK(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                         USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_EnableCRT2(SiS_Private *SiS_Pr);
+void     SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                       PSIS_HW_DEVICE_INFO HwDeviceExtension);
+BOOLEAN  SiS_BridgeIsOn(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO);
+BOOLEAN  SiS_BridgeIsEnable(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO);
+BOOLEAN  SiS_BridgeInSlave(SiS_Private *SiS_Pr);
+void     SiS_PresetScratchregister(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetTVSystem(SiS_Private *SiS_Pr);
+void     SiS_LongWait(SiS_Private *SiS_Pr);
+USHORT   SiS_GetQueueConfig(SiS_Private *SiS_Pr);
+void     SiS_VBLongWait(SiS_Private *SiS_Pr);
+USHORT   SiS_GetVCLKLen(SiS_Private *SiS_Pr, UCHAR *ROMAddr);
+void     SiS_WaitVBRetrace(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_WaitRetrace1(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_WaitRetrace2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_WaitRetraceDDC(SiS_Private *SiS_Pr);
+void     SiS_SetCRT2ECLK(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo,USHORT ModeIdIndex,
+                         USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_GetLVDSDesPtr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                           USHORT RefreshRateTableIndex,USHORT *PanelIndex,USHORT *ResIndex,
+			   PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_GetLVDSDesPtrA(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                            USHORT RefreshRateTableIndex,USHORT *PanelIndex,USHORT *ResIndex);
+void     SiS_SetTPData(SiS_Private *SiS_Pr);
+void     SiS_ModCRT1CRTC(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                         USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetCHTVReg(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
                         USHORT RefreshRateTableIndex);
-BOOLEAN SiS_GetLCDACRT1Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-		   USHORT RefreshRateTableIndex,USHORT *ResInfo,
-		   USHORT *DisplayType);
-USHORT  GetTVPtrIndex(void);
-USHORT 	GetLCDPtrIndex (void);
-void    SetDelayComp(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-             	ULONG ROMAddr,USHORT ModeNo);
-void    SetAntiFlicker(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-               	ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-void    SetEdgeEnhance (PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-                ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-void    SetYFilter(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-           	ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-void	SetPhaseIncr(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-             	ULONG ROMAddr,USHORT ModeNo);
-USHORT 	GetOEMLCDPtr(PSIS_HW_DEVICE_INFO HwDeviceExtension);
-USHORT 	GetOEMTVPtr(void);
-void	SetOEMTVDelay(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-              	ULONG ROMAddr,USHORT ModeNo);
-void	SetOEMLCDDelay(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-               	ULONG ROMAddr,USHORT ModeNo);
-void	SetOEMAntiFlicker(PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo);
-void  	SetOEMPhaseIncr(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-                ULONG ROMAddr,USHORT ModeNo);
-void	SetOEMYFilter(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
-              	ULONG ROMAddr,USHORT ModeNo);
+void     SiS_GetCHTVRegPtr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                           USHORT RefreshRateTableIndex);
+void     SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempax);
+USHORT   SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempax);
+void     SiS_SetCH701x(SiS_Private *SiS_Pr, USHORT tempax);
+USHORT   SiS_GetCH701x(SiS_Private *SiS_Pr, USHORT tempax);
+void     SiS_SetCH70xx(SiS_Private *SiS_Pr, USHORT tempax);
+USHORT   SiS_GetCH70xx(SiS_Private *SiS_Pr, USHORT tempax);
+#ifdef LINUX_XF86
+USHORT   SiS_I2C_GetByte(SiS_Private *SiS_Pr);
+Bool     SiS_I2C_PutByte(SiS_Private *SiS_Pr, USHORT data);
+Bool     SiS_I2C_Address(SiS_Private *SiS_Pr, USHORT addr);
+void     SiS_I2C_Stop(SiS_Private *SiS_Pr);
+#endif
+void     SiS_SetCH70xxANDOR(SiS_Private *SiS_Pr, USHORT tempax,USHORT tempbh);
+void     SiS_SetSwitchDDC2(SiS_Private *SiS_Pr);
+USHORT   SiS_SetStart(SiS_Private *SiS_Pr);
+USHORT   SiS_SetStop(SiS_Private *SiS_Pr);
+void     SiS_DDC2Delay(SiS_Private *SiS_Pr, USHORT delaytime);
+USHORT   SiS_SetSCLKLow(SiS_Private *SiS_Pr);
+USHORT   SiS_SetSCLKHigh(SiS_Private *SiS_Pr);
+USHORT   SiS_ReadDDC2Data(SiS_Private *SiS_Pr, USHORT tempax);
+USHORT   SiS_WriteDDC2Data(SiS_Private *SiS_Pr, USHORT tempax);
+USHORT   SiS_CheckACK(SiS_Private *SiS_Pr);
+#ifdef SIS315H
+void     SiS_OEM310Setting(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+                           UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void     SiS_OEMLCD(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+                    UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+USHORT 	 GetLCDPtrIndex(SiS_Private *SiS_Pr);
+USHORT   GetTVPtrIndex(SiS_Private *SiS_Pr);
+void     SetDelayComp(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+             	     UCHAR *ROMAddr,USHORT ModeNo);
+void     SetAntiFlicker(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+               	       UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void     SetEdgeEnhance(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+                       UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void     SetYFilter(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+           	   UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void	 SetPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+             	     UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+#endif
+#ifdef SIS300
+void     SiS_OEM300Setting(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+                           UCHAR *ROMAddr,USHORT ModeNo);
+USHORT 	 GetOEMLCDPtr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, int Flag);
+USHORT 	 GetOEMTVPtr(SiS_Private *SiS_Pr);
+void	 SetOEMTVDelay(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+              	      UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void	 SetOEMLCDDelay(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+               	       UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void	 SetOEMAntiFlicker(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                          USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void  	 SetOEMPhaseIncr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+                         UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void	 SetOEMYFilter(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr,
+               	       UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+#endif
+USHORT   GetRevisionID(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+BOOLEAN  SiS_LowModeStuff(SiS_Private *SiS_Pr, USHORT ModeNo,PSIS_HW_DEVICE_INFO HwDeviceExtension);
 
+BOOLEAN  SiS_GetLCDResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo, USHORT ModeIdIndex,
+                           PSIS_HW_DEVICE_INFO HwDeviceExtension);
+/* void    SiS_CHACRT1CRTC(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                        USHORT RefreshRateTableIndex); */
+
+BOOLEAN  SiS_SetCRT2Group301(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+                             PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetGroup1(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                       PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex);
+void     SiS_SetGroup1_LVDS(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                            PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex);
+void     SiS_SetGroup1_LCDA(SiS_Private *SiS_Pr, USHORT  BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                            PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex);
+void     SiS_SetGroup1_301(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                           PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex);
+#ifdef SIS300
+void     SiS_SetCRT2FIFO_300(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
+                             PSIS_HW_DEVICE_INFO HwDeviceExtension);
+#endif
+#ifdef SIS315H
+void     SiS_SetCRT2FIFO_310(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
+                             PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_CRT2AutoThreshold(SiS_Private *SiS_Pr, USHORT  BaseAddr);
+#endif
+BOOLEAN  SiS_GetLCDDDCInfo(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO,USHORT BaseAddr);
+void     SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO,USHORT BaseAddr);
+void     SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO,USHORT  BaseAddr);
+void     SiS_EnableBridge(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO,USHORT BaseAddr);
+void     SiS_SetPanelDelay(SiS_Private *SiS_Pr, UCHAR* ROMAddr,PSIS_HW_DEVICE_INFO,USHORT DelayTime);
+void     SiS_ShortDelay(SiS_Private *SiS_Pr, USHORT delay);
+void     SiS_LongDelay(SiS_Private *SiS_Pr, USHORT delay);
+void     SiS_GenericDelay(SiS_Private *SiS_Pr, USHORT delay);
+void     SiS_VBWait(SiS_Private *SiS_Pr);
+
+void     SiS_SiS30xBLOn(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SiS30xBLOff(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+
+/* TW: New functions (with mostly temporary names) */
+void     SiS_Chrontel701xBLOn(SiS_Private *SiS_Pr);
+void     SiS_Chrontel701xOn(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                            USHORT BaseAddr);
+void     SiS_Chrontel701xBLOff(SiS_Private *SiS_Pr);
+void     SiS_Chrontel701xOff(SiS_Private *SiS_Pr);
+void     SiS_ChrontelResetDB(SiS_Private *SiS_Pr);
+void     SiS_ChrontelDoSomething4(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+void     SiS_ChrontelDoSomething3(SiS_Private *SiS_Pr, USHORT ModeNo, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+void     SiS_ChrontelDoSomething2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+void     SiS_ChrontelDoSomething1(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+BOOLEAN  SiS_WeHaveBacklightCtrl(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+#if 0
+BOOLEAN  SiS_IsSomethingCR5F(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+#endif
+BOOLEAN  SiS_IsYPbPr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+BOOLEAN  SiS_IsTVOrYPbPr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+BOOLEAN  SiS_IsLCDOrLCDA(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+void     SiS_SetCH701xForLCD(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+void     SiS_Chrontel19f2(SiS_Private *SiS_Pr);
+BOOLEAN  SiS_CR36BIOSWord23b(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+BOOLEAN  SiS_CR36BIOSWord23d(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+BOOLEAN  SiS_IsSR13_CR30(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+/* TW end */
 
 extern   void     SiS_SetReg1(USHORT, USHORT, USHORT);
 extern   void     SiS_SetReg3(USHORT, USHORT);
 extern   UCHAR    SiS_GetReg1(USHORT, USHORT);
 extern   UCHAR    SiS_GetReg2(USHORT);
-extern   BOOLEAN  SiS_SearchModeID(ULONG ROMAddr, USHORT ModeNo,USHORT  *ModeIdIndex);
-extern   BOOLEAN  SiS_GetRatePtr(ULONG, USHORT);
+extern   BOOLEAN  SiS_SearchModeID(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT *ModeNo,USHORT *ModeIdIndex);
+extern   BOOLEAN  SiS_GetRatePtr(SiS_Private *SiS_Pr, ULONG, USHORT);
 extern   void     SiS_SetReg4(USHORT, ULONG);
 extern   ULONG    SiS_GetReg3(USHORT);
-extern   void     SiS_DisplayOff(void);
-extern   void     SiS_CRT2AutoThreshold(USHORT  BaseAddr);
-extern   void     SiS_DisplayOn(void);
-extern   UCHAR    SiS_GetModePtr(ULONG ROMAddr, USHORT ModeNo,USHORT ModeIdIndex);
-extern   UCHAR    SiS_Get310DRAMType(ULONG   ROMAddr);
-
-
-BOOLEAN  SiS_SetCRT2Group301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo, PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_SetGroup1(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex);
-void     SiS_SetGroup1_LVDS(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex);
-void     SiS_SetGroup1_LCDA(USHORT  BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex);/*301b*/
-void     SiS_SetGroup1_301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex);
-void     SiS_SetCRT2FIFO(USHORT Part1Port,ULONG ROMAddr,USHORT ModeNo, PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_SetCRT2FIFO2(USHORT Part1Port,ULONG ROMAddr,USHORT ModeNo, PSIS_HW_DEVICE_INFO HwDeviceExtension);
-BOOLEAN  SiS_GetLCDDDCInfo(PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_UnLockCRT2(PSIS_HW_DEVICE_INFO,USHORT BaseAddr);
-void     SiS_LockCRT2(PSIS_HW_DEVICE_INFO,USHORT BaseAddr);
-void     SiS_DisableBridge(PSIS_HW_DEVICE_INFO,USHORT  BaseAddr);
-void     SiS_EnableBridge(PSIS_HW_DEVICE_INFO,USHORT BaseAddr);
-void     SiS_SetPanelDelay(USHORT DelayTime);
-void     SiS_LCD_Wait_Time(UCHAR DelayTime);
+extern   void     SiS_DisplayOff(SiS_Private *SiS_Pr);
+extern   void     SiS_DisplayOn(SiS_Private *SiS_Pr);
+extern   UCHAR    SiS_GetModePtr(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo,USHORT ModeIdIndex);
+extern   BOOLEAN  SiS_GetLCDACRT1Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+		                     USHORT RefreshRateTableIndex,USHORT *ResInfo,USHORT *DisplayType);
+extern   BOOLEAN  SiS_GetLVDSCRT1Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                                     USHORT RefreshRateTableIndex,USHORT *ResInfo,USHORT *DisplayType);
+extern   void     SiS_LoadDAC(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO, UCHAR *ROMAddr,USHORT ModeNo,
+                              USHORT ModeIdIndex);
+#ifdef SIS315H
+extern   UCHAR    SiS_Get310DRAMType(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+#endif
+
+#ifdef LINUX_XF86
+/* DDC functions */
+USHORT   SiS_InitDDCRegs(SiS_Private *SiS_Pr, SISPtr pSiS, USHORT adaptnum, USHORT DDCdatatype);
+USHORT   SiS_WriteDABDDC(SiS_Private *SiS_Pr);
+USHORT   SiS_PrepareReadDDC(SiS_Private *SiS_Pr);
+USHORT   SiS_PrepareDDC(SiS_Private *SiS_Pr);
+void     SiS_SendACK(SiS_Private *SiS_Pr, USHORT yesno);
+USHORT   SiS_DoProbeDDC(SiS_Private *SiS_Pr);
+USHORT   SiS_ProbeDDC(SiS_Private *SiS_Pr);
+USHORT   SiS_ReadDDC(SiS_Private *SiS_Pr, SISPtr pSiS, USHORT DDCdatatype, unsigned char *buffer);
+USHORT   SiS_HandleDDC(SiS_Private *SiS_Pr, SISPtr pSiS, USHORT adaptnum,
+                       USHORT DDCdatatype, unsigned char *buffer);
+#endif
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/sis/init.c linux.20pre10-ac2/drivers/video/sis/init.c
--- linux.20pre10/drivers/video/sis/init.c	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/sis/init.c	2002-10-11 00:17:32.000000000 +0100
@@ -1,69 +1,69 @@
-/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/init.c,v 1.3 2000/12/02 01:16:16 dawes Exp $ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/init.c,v 1.3 2002/24/04 01:16:16 dawes Exp $ */
 /*
  * Mode switching code (CRT1 section) for SiS 300/540/630/730/315/550/650/740
- * (Universal module for Linux kernel framebuffer, XFree86 4.x)
+ * (Universal module for Linux kernel framebuffer and XFree86 4.x)
  *
- * Comments and changes marked with "TW" by Thomas Winischhofer <thomer@winischhofer.net>
+ * Assembler-To-C translation
+ * Parts Copyright 2002 by Thomas Winischhofer <thomas@winischhofer.net>
+ *
+ * Based on BIOS
+ *     1.10.07 (1.10a) for SiS650/LVDS+CH7019
+ *     1.07.1b for SiS650/301(B/LV)
+ *     2.04.50 (I) and 2.04.5c (II), 2.07a for SiS630/301(B)
+ *     2.02.3b, 2.03.02 and 2.04.5c for 630/LVDS/LVDS+CH7005
+ *     1.09b for 315/301(B)
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holder not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  The copyright holder makes no representations
+ * about the suitability of this software for any purpose.  It is provided
+ * "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
  *
- * (Version : V 0.80      [ynlai] 04/12/98)
  */
 
-/*
-#ifdef WINCE_HEADER
-*/
-/*
-#include "precomp.h"
-*/
-/*
-#endif
-*/
 #include "init.h"
 
-#ifdef TC
-#include <stdio.h>
-#include <string.h>
-#include <conio.h>
-#include <dos.h>
-#endif
-
-#ifdef WIN2000
-#include <miniport.h>
-#include "dderror.h"
-#include "devioctl.h"
-#include "miniport.h"
-#include "ntddvdeo.h"
-#include "video.h"
-#include "sisv.h"
-#include "tools.h"
-#endif
-
 #ifdef SIS300
 #include "300vtbl.h"
 #endif
+
 #ifdef SIS315H
 #include "310vtbl.h"
 #endif
 
 #ifdef LINUX_XF86
-BOOLEAN SiSBIOSSetMode(PSIS_HW_DEVICE_INFO HwDeviceExtension,
+BOOLEAN SiSBIOSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
                        ScrnInfoPtr pScrn, DisplayModePtr mode);
 #ifdef SISDUALHEAD /* TW: For dual head */
-BOOLEAN SiSBIOSSetModeCRT1(PSIS_HW_DEVICE_INFO HwDeviceExtension,
+BOOLEAN SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
                        ScrnInfoPtr pScrn, DisplayModePtr mode);
-BOOLEAN SiSBIOSSetModeCRT2(PSIS_HW_DEVICE_INFO HwDeviceExtension,
+BOOLEAN SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
                        ScrnInfoPtr pScrn, DisplayModePtr mode);
 #endif /* dual head */
 #endif /* linux_xf86 */
 
-#ifndef LINUX_XF86
-BOOLEAN SiSInit(PSIS_HW_DEVICE_INFO HwDeviceExtension);
+#ifdef LINUXBIOS
+BOOLEAN SiSInit(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
 #endif
 
 #ifdef LINUX_XF86
-BOOLEAN SiSSetMode(PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                   ScrnInfoPtr pScrn,USHORT ModeNo);
+BOOLEAN SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                   ScrnInfoPtr pScrn,USHORT ModeNo, BOOLEAN dosetpitch);
 #else
-BOOLEAN SiSSetMode(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo);
+BOOLEAN SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                   USHORT ModeNo);
 #endif
 
 #if defined(ALLOC_PRAGMA)
@@ -71,29 +71,31 @@
 #pragma alloc_text(PAGE,SiSInit)
 #endif
 
-void SiS_SetReg1(USHORT, USHORT, USHORT);
-void SiS_SetReg2(USHORT, USHORT, USHORT);
-void SiS_SetReg3(USHORT, USHORT);
-void SiS_SetReg4(USHORT, ULONG);
-UCHAR SiS_GetReg1(USHORT, USHORT);
-UCHAR SiS_GetReg2(USHORT);
-ULONG SiS_GetReg3(USHORT);
-void SiS_ClearDAC(ULONG);
-
 void DelaySeconds(int seconds);
-void DebugCode(UCHAR code);
+void DebugCode(SiS_Private *SiS_Pr, UCHAR code);
 
 #ifdef LINUX_XF86
 /* TW: Mode table for X driver */
-UShort  ModeIndex_640x480[]   = {0x2E, 0x44, 0x45, 0x62};
-UShort  ModeIndex_720x480[]   = {0x31, 0x33, 0x00, 0x35};
-UShort  ModeIndex_720x576[]   = {0x32, 0x34, 0x00, 0x36};
-UShort  ModeIndex_800x600[]   = {0x30, 0x47, 0x48, 0x63};
-UShort  ModeIndex_1024x768[]  = {0x38, 0x4A, 0x4B, 0x64};
-UShort  ModeIndex_1280x1024[] = {0x3A, 0x4D, 0x4E, 0x65};
-UShort  ModeIndex_1280x960[]  = {0x7C, 0x7D, 0x00, 0x7E};
-UShort  ModeIndex_1600x1200[] = {0x3C, 0x3D, 0x3E, 0x66};
-UShort  ModeIndex_1920x1440[] = {0x68, 0x69, 0x6A, 0x6B};
+const UShort  ModeIndex_320x480[]      = {0x5A, 0x5B, 0x00, 0x00};  /* DSTN/FSTN */
+const UShort  ModeIndex_512x384[]      = {0x52, 0x58, 0x00, 0x5c};
+const UShort  ModeIndex_640x480[]      = {0x2E, 0x44, 0x00, 0x62};
+const UShort  ModeIndex_720x480[]      = {0x31, 0x33, 0x00, 0x35};
+const UShort  ModeIndex_720x576[]      = {0x32, 0x34, 0x00, 0x36};
+const UShort  ModeIndex_800x480[]      = {0x70, 0x7a, 0x00, 0x76};  /* 310/325 series only */
+const UShort  ModeIndex_800x600[]      = {0x30, 0x47, 0x00, 0x63};
+const UShort  ModeIndex_1024x768[]     = {0x38, 0x4A, 0x00, 0x64};
+const UShort  ModeIndex_1024x576[]     = {0x71, 0x74, 0x00, 0x77};  /* 310/325 series only */
+const UShort  ModeIndex_1024x600[]     = {0x20, 0x21, 0x00, 0x22};  /* 300 series only */
+const UShort  ModeIndex_1280x1024[]    = {0x3A, 0x4D, 0x00, 0x65};
+const UShort  ModeIndex_300_1280x960[] = {0x6e, 0x6f, 0x00, 0x7b};
+const UShort  ModeIndex_310_1280x960[] = {0x7C, 0x7D, 0x00, 0x7E};
+const UShort  ModeIndex_1152x768[]     = {0x23, 0x24, 0x00, 0x25};  /* 300 series only */
+const UShort  ModeIndex_1280x768[]     = {0x23, 0x24, 0x00, 0x25};  /* 310/325 series only */
+const UShort  ModeIndex_1280x720[]     = {0x79, 0x75, 0x00, 0x78};  /* 310/325 series only */
+const UShort  ModeIndex_1400x1050[]    = {0x26, 0x27, 0x00, 0x28};  /* 310/325 series only */
+const UShort  ModeIndex_1600x1200[]    = {0x3C, 0x3D, 0x00, 0x66};
+const UShort  ModeIndex_1920x1440[]    = {0x68, 0x69, 0x00, 0x6B};
+const UShort  ModeIndex_2048x1536[]    = {0x6c, 0x6d, 0x00, 0x6e};  /* 310/325 series only */
 #endif
 
 void
@@ -104,8 +106,7 @@
   int j;
 #endif
 
-  for (i=0;i<seconds;i++)
-  {
+  for (i=0;i<seconds;i++) {
 #ifdef TC
     delay(1000);
 #endif
@@ -124,359 +125,524 @@
 }
 
 void
-DebugCode(UCHAR code)
+DebugCode(SiS_Private *SiS_Pr, UCHAR code)
 {
-  OutPortByte ( 0x80, code);
-  /*OutPortByte ( 0x300, code);*/
+  OutPortByte(0x80, code);
   DelaySeconds(0x3);
 }
 
 #ifdef SIS300
 void
-InitTo300Pointer(void)
+InitTo300Pointer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-   SiS_SModeIDTable = (SiS_StStruct *) SiS300_SModeIDTable;
-   SiS_VBModeIDTable = (SiS_VBModeStruct *) SiS300_VBModeIDTable;	/*add for 300 oem util*/
-   SiS_StandTable = (SiS_StandTableStruct *) SiS300_StandTable;
-   SiS_EModeIDTable = (SiS_ExtStruct *) SiS300_EModeIDTable;
-   SiS_RefIndex = (SiS_Ext2Struct *) SiS300_RefIndex;
-   SiS_CRT1Table = (SiS_CRT1TableStruct *) SiS300_CRT1Table;
-   SiS_MCLKData = (SiS_MCLKDataStruct *) SiS300_MCLKData;
-   SiS_ECLKData = (SiS_ECLKDataStruct *) SiS300_ECLKData;
-   SiS_VCLKData = (SiS_VCLKDataStruct *) SiS300_VCLKData;
-   SiS_VBVCLKData = (SiS_VBVCLKDataStruct *) SiS300_VCLKData;
-   SiS_ScreenOffset = SiS300_ScreenOffset;
-   SiS_StResInfo = (SiS_StResInfoStruct *) SiS300_StResInfo;
-   SiS_ModeResInfo = (SiS_ModeResInfoStruct *) SiS300_ModeResInfo;
-
-   pSiS_OutputSelect = &SiS300_OutputSelect;
-   pSiS_SoftSetting = &SiS300_SoftSetting;
-   pSiS_SR07 = &SiS300_SR07;
-   SiS_SR15 = SiS300_SR15;
-   SiS_CR40 = SiS300_CR40;
-   SiS_CR49 = SiS300_CR49;
-   pSiS_SR1F = &SiS300_SR1F;
-   pSiS_SR21 = &SiS300_SR21;
-   pSiS_SR22 = &SiS300_SR22;
-   pSiS_SR23 = &SiS300_SR23;
-   pSiS_SR24 = &SiS300_SR24;
-   SiS_SR25 = SiS300_SR25;
-   pSiS_SR31 = &SiS300_SR31;
-   pSiS_SR32 = &SiS300_SR32;
-   pSiS_SR33 = &SiS300_SR33;
-   pSiS_CRT2Data_1_2 = &SiS300_CRT2Data_1_2;
-   pSiS_CRT2Data_4_D = &SiS300_CRT2Data_4_D;
-   pSiS_CRT2Data_4_E = &SiS300_CRT2Data_4_E;
-   pSiS_CRT2Data_4_10 = &SiS300_CRT2Data_4_10;
-   pSiS_RGBSenseData = &SiS300_RGBSenseData;
-   pSiS_VideoSenseData = &SiS300_VideoSenseData;
-   pSiS_YCSenseData = &SiS300_YCSenseData;
-   pSiS_RGBSenseData2 = &SiS300_RGBSenseData2;
-   pSiS_VideoSenseData2 = &SiS300_VideoSenseData2;
-   pSiS_YCSenseData2 = &SiS300_YCSenseData2;
-
-   SiS_NTSCPhase = SiS300_NTSCPhase;
-   SiS_PALPhase = SiS300_PALPhase;
-   SiS_NTSCPhase2 = SiS300_NTSCPhase2;
-   SiS_PALPhase2 = SiS300_PALPhase2;
-   SiS_PALMPhase = SiS300_PALMPhase;  /*add for PALMN*/
-   SiS_PALNPhase = SiS300_PALNPhase;
-   
-   SiS_StLCD1024x768Data = (SiS_LCDDataStruct *) SiS300_StLCD1024x768Data;
-   SiS_ExtLCD1024x768Data = (SiS_LCDDataStruct *) SiS300_ExtLCD1024x768Data;
-   SiS_St2LCD1024x768Data = (SiS_LCDDataStruct *) SiS300_St2LCD1024x768Data;
-   SiS_StLCD1280x1024Data = (SiS_LCDDataStruct *) SiS300_StLCD1280x1024Data;
-   SiS_ExtLCD1280x1024Data = (SiS_LCDDataStruct *) SiS300_ExtLCD1280x1024Data;
-   SiS_St2LCD1280x1024Data = (SiS_LCDDataStruct *) SiS300_St2LCD1280x1024Data;
-   SiS_NoScaleData = (SiS_LCDDataStruct *) SiS300_NoScaleData;
-   SiS_LCD1280x960Data = (SiS_LCDDataStruct *) SiS300_LCD1280x960Data;
-   SiS_StPALData = (SiS_TVDataStruct *) SiS300_StPALData;
-   SiS_ExtPALData = (SiS_TVDataStruct *) SiS300_ExtPALData;
-   SiS_StNTSCData = (SiS_TVDataStruct *) SiS300_StNTSCData;
-   SiS_ExtNTSCData = (SiS_TVDataStruct *) SiS300_ExtNTSCData;
-   SiS_St1HiTVData = (SiS_TVDataStruct *) SiS300_St1HiTVData;
-   SiS_St2HiTVData = (SiS_TVDataStruct *) SiS300_St2HiTVData;
-   SiS_ExtHiTVData = (SiS_TVDataStruct *) SiS300_ExtHiTVData;
-   SiS_NTSCTiming = SiS300_NTSCTiming;
-   SiS_PALTiming = SiS300_PALTiming;
-   SiS_HiTVSt1Timing = SiS300_HiTVSt1Timing;
-   SiS_HiTVSt2Timing = SiS300_HiTVSt2Timing;
-   SiS_HiTVTextTiming = SiS300_HiTVTextTiming;
-   SiS_HiTVGroup3Data = SiS300_HiTVGroup3Data;
-   SiS_HiTVGroup3Simu = SiS300_HiTVGroup3Simu;
-   SiS_HiTVGroup3Text = SiS300_HiTVGroup3Text;
-
-   SiS_PanelDelayTbl = (SiS_PanelDelayTblStruct *) SiS300_PanelDelayTbl;
-   SiS_LVDS800x600Data_1 = (SiS_LVDSDataStruct *) SiS300_LVDS800x600Data_1;
-   SiS_LVDS800x600Data_2 = (SiS_LVDSDataStruct *) SiS300_LVDS800x600Data_2;
-   SiS_LVDS1024x768Data_1 = (SiS_LVDSDataStruct *) SiS300_LVDS1024x768Data_1;
-   SiS_LVDS1024x768Data_2 = (SiS_LVDSDataStruct *) SiS300_LVDS1024x768Data_2;
-   SiS_LVDS1280x1024Data_1 = (SiS_LVDSDataStruct *) SiS300_LVDS1280x1024Data_1;
-   SiS_LVDS1280x1024Data_2 = (SiS_LVDSDataStruct *) SiS300_LVDS1280x1024Data_2;
-   SiS_LVDS640x480Data_1 = (SiS_LVDSDataStruct *) SiS300_LVDS640x480Data_1;
-   SiS_CHTVUNTSCData = (SiS_LVDSDataStruct *) SiS300_CHTVUNTSCData;
-   SiS_CHTVONTSCData = (SiS_LVDSDataStruct *) SiS300_CHTVONTSCData;
-   SiS_CHTVUPALData = (SiS_LVDSDataStruct *) SiS300_CHTVUPALData;
-   SiS_CHTVOPALData = (SiS_LVDSDataStruct *) SiS300_CHTVOPALData;
-   SiS_PanelType00_1 = (SiS_LVDSDesStruct *) SiS300_PanelType00_1;
-   SiS_PanelType01_1 = (SiS_LVDSDesStruct *) SiS300_PanelType01_1;
-   SiS_PanelType02_1 = (SiS_LVDSDesStruct *) SiS300_PanelType02_1;
-   SiS_PanelType03_1 = (SiS_LVDSDesStruct *) SiS300_PanelType03_1;
-   SiS_PanelType04_1 = (SiS_LVDSDesStruct *) SiS300_PanelType04_1;
-   SiS_PanelType05_1 = (SiS_LVDSDesStruct *) SiS300_PanelType05_1;
-   SiS_PanelType06_1 = (SiS_LVDSDesStruct *) SiS300_PanelType06_1;
-   SiS_PanelType07_1 = (SiS_LVDSDesStruct *) SiS300_PanelType07_1;
-   SiS_PanelType08_1 = (SiS_LVDSDesStruct *) SiS300_PanelType08_1;
-   SiS_PanelType09_1 = (SiS_LVDSDesStruct *) SiS300_PanelType09_1;
-   SiS_PanelType0a_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0a_1;
-   SiS_PanelType0b_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0b_1;
-   SiS_PanelType0c_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0c_1;
-   SiS_PanelType0d_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0d_1;
-   SiS_PanelType0e_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0e_1;
-   SiS_PanelType0f_1 = (SiS_LVDSDesStruct *) SiS300_PanelType0f_1;
-   SiS_PanelType00_2 = (SiS_LVDSDesStruct *) SiS300_PanelType00_2;
-   SiS_PanelType01_2 = (SiS_LVDSDesStruct *) SiS300_PanelType01_2;
-   SiS_PanelType02_2 = (SiS_LVDSDesStruct *) SiS300_PanelType02_2;
-   SiS_PanelType03_2 = (SiS_LVDSDesStruct *) SiS300_PanelType03_2;
-   SiS_PanelType04_2 = (SiS_LVDSDesStruct *) SiS300_PanelType04_2;
-   SiS_PanelType05_2 = (SiS_LVDSDesStruct *) SiS300_PanelType05_2;
-   SiS_PanelType06_2 = (SiS_LVDSDesStruct *) SiS300_PanelType06_2;
-   SiS_PanelType07_2 = (SiS_LVDSDesStruct *) SiS300_PanelType07_2;
-   SiS_PanelType08_2 = (SiS_LVDSDesStruct *) SiS300_PanelType08_2;
-   SiS_PanelType09_2 = (SiS_LVDSDesStruct *) SiS300_PanelType09_2;
-   SiS_PanelType0a_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0a_2;
-   SiS_PanelType0b_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0b_2;
-   SiS_PanelType0c_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0c_2;
-   SiS_PanelType0d_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0d_2;
-   SiS_PanelType0e_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0e_2;
-   SiS_PanelType0f_2 = (SiS_LVDSDesStruct *) SiS300_PanelType0f_2;
-   SiS_CHTVUNTSCDesData = (SiS_LVDSDesStruct *) SiS300_CHTVUNTSCDesData;
-   SiS_CHTVONTSCDesData = (SiS_LVDSDesStruct *) SiS300_CHTVONTSCDesData;
-   SiS_CHTVUPALDesData = (SiS_LVDSDesStruct *) SiS300_CHTVUPALDesData;
-   SiS_CHTVOPALDesData = (SiS_LVDSDesStruct *) SiS300_CHTVOPALDesData;
-   SiS_LVDSCRT1800x600_1 = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT1800x600_1;
-   SiS_LVDSCRT11024x768_1 = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11024x768_1;
-   SiS_LVDSCRT11280x1024_1 = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11280x1024_1;
-   SiS_LVDSCRT1800x600_1_H = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT1800x600_1_H;
-   SiS_LVDSCRT11024x768_1_H = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11024x768_1_H;
-   SiS_LVDSCRT11280x1024_1_H = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11280x1024_1_H;
-   SiS_LVDSCRT1800x600_2 = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT1800x600_2;
-   SiS_LVDSCRT11024x768_2 = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11024x768_2;
-   SiS_LVDSCRT11280x1024_2 = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11280x1024_2;
-   SiS_LVDSCRT1800x600_2_H = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT1800x600_2_H;
-   SiS_LVDSCRT11024x768_2_H = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11024x768_2_H;
-   SiS_LVDSCRT11280x1024_2_H = (SiS_LVDSCRT1DataStruct *) SiS300_LVDSCRT11280x1024_2_H;
-   SiS_CHTVCRT1UNTSC = (SiS_LVDSCRT1DataStruct *) SiS300_CHTVCRT1UNTSC;
-   SiS_CHTVCRT1ONTSC = (SiS_LVDSCRT1DataStruct *) SiS300_CHTVCRT1ONTSC;
-   SiS_CHTVCRT1UPAL = (SiS_LVDSCRT1DataStruct *) SiS300_CHTVCRT1UPAL;
-   SiS_CHTVCRT1OPAL = (SiS_LVDSCRT1DataStruct *) SiS300_CHTVCRT1OPAL;
-   SiS_CHTVReg_UNTSC = (SiS_CHTVRegDataStruct *) SiS300_CHTVReg_UNTSC;
-   SiS_CHTVReg_ONTSC = (SiS_CHTVRegDataStruct *) SiS300_CHTVReg_ONTSC;
-   SiS_CHTVReg_UPAL = (SiS_CHTVRegDataStruct *) SiS300_CHTVReg_UPAL;
-   SiS_CHTVReg_OPAL = (SiS_CHTVRegDataStruct *) SiS300_CHTVReg_OPAL;
-   SiS_CHTVVCLKUNTSC = SiS300_CHTVVCLKUNTSC;
-   SiS_CHTVVCLKONTSC = SiS300_CHTVVCLKONTSC;
-   SiS_CHTVVCLKUPAL = SiS300_CHTVVCLKUPAL;
-   SiS_CHTVVCLKOPAL = SiS300_CHTVVCLKOPAL;
-   /* 300 customization related */
+   SiS_Pr->SiS_SModeIDTable  = (SiS_StStruct *)SiS300_SModeIDTable;
+   SiS_Pr->SiS_VBModeIDTable = (SiS_VBModeStruct *)SiS300_VBModeIDTable;
+   SiS_Pr->SiS_StandTable    = (SiS_StandTableStruct *)SiS300_StandTable;
+   SiS_Pr->SiS_EModeIDTable  = (SiS_ExtStruct *)SiS300_EModeIDTable;
+   SiS_Pr->SiS_RefIndex      = (SiS_Ext2Struct *)SiS300_RefIndex;
+   SiS_Pr->SiS_CRT1Table     = (SiS_CRT1TableStruct *)SiS300_CRT1Table;
+   if(HwDeviceExtension->jChipType == SIS_300) {
+      SiS_Pr->SiS_MCLKData_0    = (SiS_MCLKDataStruct *)SiS300_MCLKData_300; /* 300 */
+   } else {
+      SiS_Pr->SiS_MCLKData_0    = (SiS_MCLKDataStruct *)SiS300_MCLKData_630; /* 630 */
+   }
+   SiS_Pr->SiS_ECLKData      = (SiS_ECLKDataStruct *)SiS300_ECLKData;
+   SiS_Pr->SiS_VCLKData      = (SiS_VCLKDataStruct *)SiS300_VCLKData;
+   SiS_Pr->SiS_VBVCLKData    = (SiS_VBVCLKDataStruct *)SiS300_VCLKData;
+   SiS_Pr->SiS_ScreenOffset  = SiS300_ScreenOffset;
+   SiS_Pr->SiS_StResInfo     = (SiS_StResInfoStruct *)SiS300_StResInfo;
+   SiS_Pr->SiS_ModeResInfo   = (SiS_ModeResInfoStruct *)SiS300_ModeResInfo;
+
+   SiS_Pr->pSiS_OutputSelect = &SiS300_OutputSelect;
+   SiS_Pr->pSiS_SoftSetting  = &SiS300_SoftSetting;
+
+   SiS_Pr->SiS_SR15  = SiS300_SR15;
+
+#ifndef LINUX_XF86
+   SiS_Pr->pSiS_SR07 = &SiS300_SR07;
+   SiS_Pr->SiS_CR40  = SiS300_CR40;
+   SiS_Pr->SiS_CR49  = SiS300_CR49;
+   SiS_Pr->pSiS_SR1F = &SiS300_SR1F;
+   SiS_Pr->pSiS_SR21 = &SiS300_SR21;
+   SiS_Pr->pSiS_SR22 = &SiS300_SR22;
+   SiS_Pr->pSiS_SR23 = &SiS300_SR23;
+   SiS_Pr->pSiS_SR24 = &SiS300_SR24;
+   SiS_Pr->SiS_SR25  = SiS300_SR25;
+   SiS_Pr->pSiS_SR31 = &SiS300_SR31;
+   SiS_Pr->pSiS_SR32 = &SiS300_SR32;
+   SiS_Pr->pSiS_SR33 = &SiS300_SR33;
+   SiS_Pr->pSiS_CRT2Data_1_2  = &SiS300_CRT2Data_1_2;
+   SiS_Pr->pSiS_CRT2Data_4_D  = &SiS300_CRT2Data_4_D;
+   SiS_Pr->pSiS_CRT2Data_4_E  = &SiS300_CRT2Data_4_E;
+   SiS_Pr->pSiS_CRT2Data_4_10 = &SiS300_CRT2Data_4_10;
+   SiS_Pr->pSiS_RGBSenseData    = &SiS300_RGBSenseData;
+   SiS_Pr->pSiS_VideoSenseData  = &SiS300_VideoSenseData;
+   SiS_Pr->pSiS_YCSenseData     = &SiS300_YCSenseData;
+   SiS_Pr->pSiS_RGBSenseData2   = &SiS300_RGBSenseData2;
+   SiS_Pr->pSiS_VideoSenseData2 = &SiS300_VideoSenseData2;
+   SiS_Pr->pSiS_YCSenseData2    = &SiS300_YCSenseData2;
+#endif
+
+   SiS_Pr->SiS_NTSCPhase  = SiS300_NTSCPhase;
+   SiS_Pr->SiS_PALPhase   = SiS300_PALPhase;
+   SiS_Pr->SiS_NTSCPhase2 = SiS300_NTSCPhase2;
+   SiS_Pr->SiS_PALPhase2  = SiS300_PALPhase2;
+   SiS_Pr->SiS_PALMPhase  = SiS300_PALMPhase;
+   SiS_Pr->SiS_PALNPhase  = SiS300_PALNPhase;
+   SiS_Pr->SiS_PALMPhase2 = SiS300_PALMPhase2;
+   SiS_Pr->SiS_PALNPhase2 = SiS300_PALNPhase2;
+
+   SiS_Pr->SiS_StLCD1024x768Data    = (SiS_LCDDataStruct *)SiS300_StLCD1024x768Data;
+   SiS_Pr->SiS_ExtLCD1024x768Data   = (SiS_LCDDataStruct *)SiS300_ExtLCD1024x768Data;
+   SiS_Pr->SiS_St2LCD1024x768Data   = (SiS_LCDDataStruct *)SiS300_St2LCD1024x768Data;
+   SiS_Pr->SiS_StLCD1280x1024Data   = (SiS_LCDDataStruct *)SiS300_StLCD1280x1024Data;
+   SiS_Pr->SiS_ExtLCD1280x1024Data  = (SiS_LCDDataStruct *)SiS300_ExtLCD1280x1024Data;
+   SiS_Pr->SiS_St2LCD1280x1024Data  = (SiS_LCDDataStruct *)SiS300_St2LCD1280x1024Data;
+   SiS_Pr->SiS_NoScaleData1024x768  = (SiS_LCDDataStruct *)SiS300_NoScaleData1024x768;
+   SiS_Pr->SiS_NoScaleData1280x1024 = (SiS_LCDDataStruct *)SiS300_NoScaleData1280x1024;
+   SiS_Pr->SiS_LCD1280x960Data      = (SiS_LCDDataStruct *)SiS300_LCD1280x960Data;
+   SiS_Pr->SiS_ExtLCD1400x1050Data  = (SiS_LCDDataStruct *)SiS300_ExtLCD1400x1050Data;
+   SiS_Pr->SiS_ExtLCD1600x1200Data  = (SiS_LCDDataStruct *)SiS300_ExtLCD1600x1200Data;
+   SiS_Pr->SiS_StLCD1400x1050Data   = (SiS_LCDDataStruct *)SiS300_StLCD1400x1050Data;
+   SiS_Pr->SiS_StLCD1600x1200Data   = (SiS_LCDDataStruct *)SiS300_StLCD1600x1200Data;
+   SiS_Pr->SiS_NoScaleData1400x1050 = (SiS_LCDDataStruct *)SiS300_NoScaleData1400x1050;
+   SiS_Pr->SiS_NoScaleData1600x1200 = (SiS_LCDDataStruct *)SiS300_NoScaleData1600x1200;
+
+   SiS_Pr->SiS_StPALData   = (SiS_TVDataStruct *)SiS300_StPALData;
+   SiS_Pr->SiS_ExtPALData  = (SiS_TVDataStruct *)SiS300_ExtPALData;
+   SiS_Pr->SiS_StNTSCData  = (SiS_TVDataStruct *)SiS300_StNTSCData;
+   SiS_Pr->SiS_ExtNTSCData = (SiS_TVDataStruct *)SiS300_ExtNTSCData;
+#ifdef oldHV
+   SiS_Pr->SiS_St1HiTVData = (SiS_TVDataStruct *)SiS300_St1HiTVData;
+   SiS_Pr->SiS_St2HiTVData = (SiS_TVDataStruct *)SiS300_St2HiTVData;
+   SiS_Pr->SiS_ExtHiTVData = (SiS_TVDataStruct *)SiS300_ExtHiTVData;
+#endif
+
+   SiS_Pr->SiS_NTSCTiming     = SiS300_NTSCTiming;
+   SiS_Pr->SiS_PALTiming      = SiS300_PALTiming;
+#ifdef oldHV
+   SiS_Pr->SiS_HiTVSt1Timing  = SiS300_HiTVSt1Timing;
+   SiS_Pr->SiS_HiTVSt2Timing  = SiS300_HiTVSt2Timing;
+   SiS_Pr->SiS_HiTVTextTiming = SiS300_HiTVTextTiming;
+   SiS_Pr->SiS_HiTVGroup3Data = SiS300_HiTVGroup3Data;
+   SiS_Pr->SiS_HiTVGroup3Simu = SiS300_HiTVGroup3Simu;
+   SiS_Pr->SiS_HiTVGroup3Text = SiS300_HiTVGroup3Text;
+#endif
+
+   SiS_Pr->SiS_PanelDelayTbl     = (SiS_PanelDelayTblStruct *)SiS300_PanelDelayTbl;
+   SiS_Pr->SiS_PanelDelayTblLVDS = (SiS_PanelDelayTblStruct *)SiS300_PanelDelayTblLVDS;
+
+   SiS_Pr->SiS_LVDS800x600Data_1   = (SiS_LVDSDataStruct *)SiS300_LVDS800x600Data_1;
+   SiS_Pr->SiS_LVDS800x600Data_2   = (SiS_LVDSDataStruct *)SiS300_LVDS800x600Data_2;
+   SiS_Pr->SiS_LVDS1024x768Data_1  = (SiS_LVDSDataStruct *)SiS300_LVDS1024x768Data_1;
+   SiS_Pr->SiS_LVDS1024x768Data_2  = (SiS_LVDSDataStruct *)SiS300_LVDS1024x768Data_2;
+   SiS_Pr->SiS_LVDS1280x1024Data_1 = (SiS_LVDSDataStruct *)SiS300_LVDS1280x1024Data_1;
+   SiS_Pr->SiS_LVDS1280x1024Data_2 = (SiS_LVDSDataStruct *)SiS300_LVDS1280x1024Data_2;
+   SiS_Pr->SiS_LVDS1280x960Data_1  = (SiS_LVDSDataStruct *)SiS300_LVDS1280x1024Data_1;
+   SiS_Pr->SiS_LVDS1280x960Data_2  = (SiS_LVDSDataStruct *)SiS300_LVDS1280x1024Data_2;
+   SiS_Pr->SiS_LVDS1400x1050Data_1 = (SiS_LVDSDataStruct *)SiS300_LVDS1400x1050Data_1;
+   SiS_Pr->SiS_LVDS1400x1050Data_2 = (SiS_LVDSDataStruct *)SiS300_LVDS1400x1050Data_2;
+   SiS_Pr->SiS_LVDS1024x600Data_1  = (SiS_LVDSDataStruct *)SiS300_LVDS1024x600Data_1;
+   SiS_Pr->SiS_LVDS1024x600Data_2  = (SiS_LVDSDataStruct *)SiS300_LVDS1024x600Data_2;
+   SiS_Pr->SiS_LVDS1152x768Data_1  = (SiS_LVDSDataStruct *)SiS300_LVDS1152x768Data_1;
+   SiS_Pr->SiS_LVDS1152x768Data_2  = (SiS_LVDSDataStruct *)SiS300_LVDS1152x768Data_2;
+   SiS_Pr->SiS_LVDSXXXxXXXData_1   = (SiS_LVDSDataStruct *)SiS300_LVDSXXXxXXXData_1;
+   SiS_Pr->SiS_LVDS320x480Data_1   = (SiS_LVDSDataStruct *)SiS300_LVDS320x480Data_1;
+   SiS_Pr->SiS_LVDS640x480Data_1   = (SiS_LVDSDataStruct *)SiS300_LVDS640x480Data_1;
+   SiS_Pr->SiS_LCDA1400x1050Data_1 = (SiS_LVDSDataStruct *)SiS300_LCDA1400x1050Data_1;
+   SiS_Pr->SiS_LCDA1400x1050Data_2 = (SiS_LVDSDataStruct *)SiS300_LCDA1400x1050Data_2;
+   SiS_Pr->SiS_LCDA1600x1200Data_1 = (SiS_LVDSDataStruct *)SiS300_LCDA1600x1200Data_1;
+   SiS_Pr->SiS_LCDA1600x1200Data_2 = (SiS_LVDSDataStruct *)SiS300_LCDA1600x1200Data_2;
+   SiS_Pr->SiS_CHTVUNTSCData = (SiS_LVDSDataStruct *)SiS300_CHTVUNTSCData;
+   SiS_Pr->SiS_CHTVONTSCData = (SiS_LVDSDataStruct *)SiS300_CHTVONTSCData;
+   SiS_Pr->SiS_CHTVUPALData  = (SiS_LVDSDataStruct *)SiS300_CHTVUPALData;
+   SiS_Pr->SiS_CHTVOPALData  = (SiS_LVDSDataStruct *)SiS300_CHTVOPALData;
+   SiS_Pr->SiS_PanelType00_1 = (SiS_LVDSDesStruct *)SiS300_PanelType00_1;
+   SiS_Pr->SiS_PanelType01_1 = (SiS_LVDSDesStruct *)SiS300_PanelType01_1;
+   SiS_Pr->SiS_PanelType02_1 = (SiS_LVDSDesStruct *)SiS300_PanelType02_1;
+   SiS_Pr->SiS_PanelType03_1 = (SiS_LVDSDesStruct *)SiS300_PanelType03_1;
+   SiS_Pr->SiS_PanelType04_1 = (SiS_LVDSDesStruct *)SiS300_PanelType04_1;
+   SiS_Pr->SiS_PanelType05_1 = (SiS_LVDSDesStruct *)SiS300_PanelType05_1;
+   SiS_Pr->SiS_PanelType06_1 = (SiS_LVDSDesStruct *)SiS300_PanelType06_1;
+   SiS_Pr->SiS_PanelType07_1 = (SiS_LVDSDesStruct *)SiS300_PanelType07_1;
+   SiS_Pr->SiS_PanelType08_1 = (SiS_LVDSDesStruct *)SiS300_PanelType08_1;
+   SiS_Pr->SiS_PanelType09_1 = (SiS_LVDSDesStruct *)SiS300_PanelType09_1;
+   SiS_Pr->SiS_PanelType0a_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0a_1;
+   SiS_Pr->SiS_PanelType0b_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0b_1;
+   SiS_Pr->SiS_PanelType0c_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0c_1;
+   SiS_Pr->SiS_PanelType0d_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0d_1;
+   SiS_Pr->SiS_PanelType0e_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0e_1;
+   SiS_Pr->SiS_PanelType0f_1 = (SiS_LVDSDesStruct *)SiS300_PanelType0f_1;
+   SiS_Pr->SiS_PanelType00_2 = (SiS_LVDSDesStruct *)SiS300_PanelType00_2;
+   SiS_Pr->SiS_PanelType01_2 = (SiS_LVDSDesStruct *)SiS300_PanelType01_2;
+   SiS_Pr->SiS_PanelType02_2 = (SiS_LVDSDesStruct *)SiS300_PanelType02_2;
+   SiS_Pr->SiS_PanelType03_2 = (SiS_LVDSDesStruct *)SiS300_PanelType03_2;
+   SiS_Pr->SiS_PanelType04_2 = (SiS_LVDSDesStruct *)SiS300_PanelType04_2;
+   SiS_Pr->SiS_PanelType05_2 = (SiS_LVDSDesStruct *)SiS300_PanelType05_2;
+   SiS_Pr->SiS_PanelType06_2 = (SiS_LVDSDesStruct *)SiS300_PanelType06_2;
+   SiS_Pr->SiS_PanelType07_2 = (SiS_LVDSDesStruct *)SiS300_PanelType07_2;
+   SiS_Pr->SiS_PanelType08_2 = (SiS_LVDSDesStruct *)SiS300_PanelType08_2;
+   SiS_Pr->SiS_PanelType09_2 = (SiS_LVDSDesStruct *)SiS300_PanelType09_2;
+   SiS_Pr->SiS_PanelType0a_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0a_2;
+   SiS_Pr->SiS_PanelType0b_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0b_2;
+   SiS_Pr->SiS_PanelType0c_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0c_2;
+   SiS_Pr->SiS_PanelType0d_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0d_2;
+   SiS_Pr->SiS_PanelType0e_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0e_2;
+   SiS_Pr->SiS_PanelType0f_2 = (SiS_LVDSDesStruct *)SiS300_PanelType0f_2;
+   SiS_Pr->SiS_CHTVUNTSCDesData = (SiS_LVDSDesStruct *)SiS300_CHTVUNTSCDesData;
+   SiS_Pr->SiS_CHTVONTSCDesData = (SiS_LVDSDesStruct *)SiS300_CHTVONTSCDesData;
+   SiS_Pr->SiS_CHTVUPALDesData  = (SiS_LVDSDesStruct *)SiS300_CHTVUPALDesData;
+   SiS_Pr->SiS_CHTVOPALDesData  = (SiS_LVDSDesStruct *)SiS300_CHTVOPALDesData;
+   SiS_Pr->SiS_LVDSCRT1800x600_1     = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_1;
+   SiS_Pr->SiS_LVDSCRT11024x768_1    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_1;
+   SiS_Pr->SiS_LVDSCRT11280x1024_1   = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_1;
+   SiS_Pr->SiS_LVDSCRT11024x600_1    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x600_1;
+   SiS_Pr->SiS_LVDSCRT11152x768_1    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11152x768_1;
+   SiS_Pr->SiS_LVDSCRT1800x600_1_H   = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_1_H;
+   SiS_Pr->SiS_LVDSCRT11024x768_1_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_1_H;
+   SiS_Pr->SiS_LVDSCRT11280x1024_1_H = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_1_H;
+   SiS_Pr->SiS_LVDSCRT11024x600_1_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x600_1_H;
+   SiS_Pr->SiS_LVDSCRT11152x768_1_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11152x768_1_H;
+   SiS_Pr->SiS_LVDSCRT1800x600_2     = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_2;
+   SiS_Pr->SiS_LVDSCRT11024x768_2    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_2;
+   SiS_Pr->SiS_LVDSCRT11280x1024_2   = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_2;
+   SiS_Pr->SiS_LVDSCRT11024x600_2    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x600_2;
+   SiS_Pr->SiS_LVDSCRT11152x768_2    = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11152x768_2;
+   SiS_Pr->SiS_LVDSCRT1800x600_2_H   = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT1800x600_2_H;
+   SiS_Pr->SiS_LVDSCRT11024x768_2_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x768_2_H;
+   SiS_Pr->SiS_LVDSCRT11280x1024_2_H = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11280x1024_2_H;
+   SiS_Pr->SiS_LVDSCRT11024x600_2_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11024x600_2_H;
+   SiS_Pr->SiS_LVDSCRT11152x768_2_H  = (SiS_LVDSCRT1DataStruct *)SiS300_LVDSCRT11152x768_2_H;
+   SiS_Pr->SiS_CHTVCRT1UNTSC = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1UNTSC;
+   SiS_Pr->SiS_CHTVCRT1ONTSC = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1ONTSC;
+   SiS_Pr->SiS_CHTVCRT1UPAL  = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1UPAL;
+   SiS_Pr->SiS_CHTVCRT1OPAL  = (SiS_LVDSCRT1DataStruct *)SiS300_CHTVCRT1OPAL;
+   SiS_Pr->SiS_CHTVReg_UNTSC = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_UNTSC;
+   SiS_Pr->SiS_CHTVReg_ONTSC = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_ONTSC;
+   SiS_Pr->SiS_CHTVReg_UPAL  = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_UPAL;
+   SiS_Pr->SiS_CHTVReg_OPAL  = (SiS_CHTVRegDataStruct *)SiS300_CHTVReg_OPAL;
+   SiS_Pr->SiS_CHTVVCLKUNTSC = SiS300_CHTVVCLKUNTSC;
+   SiS_Pr->SiS_CHTVVCLKONTSC = SiS300_CHTVVCLKONTSC;
+   SiS_Pr->SiS_CHTVVCLKUPAL  = SiS300_CHTVVCLKUPAL;
+   SiS_Pr->SiS_CHTVVCLKOPAL  = SiS300_CHTVVCLKOPAL;
+
+   /* TW: LCDResInfo will on 300 series be translated to 310/325 series definitions */
+   SiS_Pr->SiS_Panel320x480   = Panel_320x480;
+   SiS_Pr->SiS_Panel640x480   = Panel_640x480;
+   SiS_Pr->SiS_Panel800x600   = Panel_800x600;
+   SiS_Pr->SiS_Panel1024x768  = Panel_1024x768;
+   SiS_Pr->SiS_Panel1280x1024 = Panel_1280x1024;
+   SiS_Pr->SiS_Panel1280x960  = Panel_1280x960;
+   SiS_Pr->SiS_Panel1024x600  = Panel_1024x600;
+   SiS_Pr->SiS_Panel1152x768  = Panel_1152x768;
+   SiS_Pr->SiS_Panel1600x1200 = 16;  		/* TW: Something illegal */
+   SiS_Pr->SiS_Panel1400x1050 = 16;  		/* TW: Something illegal */
+   SiS_Pr->SiS_Panel1152x864  = 16;   		/* TW: Something illegal */
+   SiS_Pr->SiS_Panel1280x768  = 16;   		/* TW: Something illegal */
+   SiS_Pr->SiS_PanelMax       = Panel_320x480;     /* TW: highest value */
+   SiS_Pr->SiS_PanelMinLVDS   = Panel_800x600;     /* TW: Lowest value LVDS */
+   SiS_Pr->SiS_PanelMin301    = Panel_1024x768;    /* TW: lowest value 301 */
 }
 #endif
 
 #ifdef SIS315H
 void
-InitTo310Pointer(void)
-{
-   SiS_SModeIDTable = (SiS_StStruct *) SiS310_SModeIDTable;
-   SiS_StandTable = (SiS_StandTableStruct *) SiS310_StandTable;
-   SiS_EModeIDTable = (SiS_ExtStruct *) SiS310_EModeIDTable;
-   SiS_RefIndex = (SiS_Ext2Struct *) SiS310_RefIndex;
-   SiS_CRT1Table = (SiS_CRT1TableStruct *) SiS310_CRT1Table;
-   SiS_MCLKData = (SiS_MCLKDataStruct *) SiS310_MCLKData;
-   SiS_ECLKData = (SiS_ECLKDataStruct *) SiS310_ECLKData;
-   SiS_VCLKData = (SiS_VCLKDataStruct *) SiS310_VCLKData;
-   SiS_VBVCLKData = (SiS_VBVCLKDataStruct *) SiS310_VBVCLKData;
-   SiS_ScreenOffset = SiS310_ScreenOffset;
-   SiS_StResInfo = (SiS_StResInfoStruct *) SiS310_StResInfo;
-   SiS_ModeResInfo = (SiS_ModeResInfoStruct *) SiS310_ModeResInfo;
-
-   pSiS_OutputSelect = &SiS310_OutputSelect;
-   pSiS_SoftSetting = &SiS310_SoftSetting;
-   pSiS_SR07 = &SiS310_SR07;
-   SiS_SR15 = SiS310_SR15;
-   SiS_CR40 = SiS310_CR40;
-   SiS_CR49 = SiS310_CR49;
-   pSiS_SR1F = &SiS310_SR1F;
-   pSiS_SR21 = &SiS310_SR21;
-   pSiS_SR22 = &SiS310_SR22;
-   pSiS_SR23 = &SiS310_SR23;
-   pSiS_SR24 = &SiS310_SR24;
-   SiS_SR25 = SiS310_SR25;
-   pSiS_SR31 = &SiS310_SR31;
-   pSiS_SR32 = &SiS310_SR32;
-   pSiS_SR33 = &SiS310_SR33;
-   pSiS_CRT2Data_1_2 = &SiS310_CRT2Data_1_2;
-   pSiS_CRT2Data_4_D = &SiS310_CRT2Data_4_D;
-   pSiS_CRT2Data_4_E = &SiS310_CRT2Data_4_E;
-   pSiS_CRT2Data_4_10 = &SiS310_CRT2Data_4_10;
-   pSiS_RGBSenseData = &SiS310_RGBSenseData;
-   pSiS_VideoSenseData = &SiS310_VideoSenseData;
-   pSiS_YCSenseData = &SiS310_YCSenseData;
-   pSiS_RGBSenseData2 = &SiS310_RGBSenseData2;
-   pSiS_VideoSenseData2 = &SiS310_VideoSenseData2;
-   pSiS_YCSenseData2 = &SiS310_YCSenseData2;
-   SiS_NTSCPhase = SiS310_NTSCPhase;
-   SiS_PALPhase = SiS310_PALPhase;
-   SiS_NTSCPhase2 = SiS310_NTSCPhase2;
-   SiS_PALPhase2 = SiS310_PALPhase2;
-   SiS_PALMPhase = SiS310_PALMPhase;  /*add for PALMN*/
-   SiS_PALNPhase = SiS310_PALNPhase;
-
-   SiS_StLCD1024x768Data = (SiS_LCDDataStruct *) SiS310_StLCD1024x768Data;
-   SiS_ExtLCD1024x768Data = (SiS_LCDDataStruct *) SiS310_ExtLCD1024x768Data;
-   SiS_St2LCD1024x768Data = (SiS_LCDDataStruct *) SiS310_St2LCD1024x768Data;
-   SiS_StLCD1280x1024Data = (SiS_LCDDataStruct *) SiS310_StLCD1280x1024Data;
-   SiS_ExtLCD1280x1024Data = (SiS_LCDDataStruct *) SiS310_ExtLCD1280x1024Data;
-   SiS_St2LCD1280x1024Data = (SiS_LCDDataStruct *) SiS310_St2LCD1280x1024Data;
-   SiS_NoScaleData = (SiS_LCDDataStruct *) SiS310_NoScaleData;
-   SiS_LCD1280x960Data = (SiS_LCDDataStruct *) SiS310_LCD1280x960Data;
-   SiS_StPALData = (SiS_TVDataStruct *) SiS310_StPALData;
-   SiS_ExtPALData = (SiS_TVDataStruct *) SiS310_ExtPALData;
-   SiS_StNTSCData = (SiS_TVDataStruct *) SiS310_StNTSCData;
-   SiS_ExtNTSCData = (SiS_TVDataStruct *) SiS310_ExtNTSCData;
-   SiS_St1HiTVData = (SiS_TVDataStruct *) SiS310_St1HiTVData;
-   SiS_St2HiTVData = (SiS_TVDataStruct *) SiS310_St2HiTVData;
-   SiS_ExtHiTVData = (SiS_TVDataStruct *) SiS310_ExtHiTVData;
-   SiS_NTSCTiming = SiS310_NTSCTiming;
-   SiS_PALTiming = SiS310_PALTiming;
-   SiS_HiTVSt1Timing = SiS310_HiTVSt1Timing;
-   SiS_HiTVSt2Timing = SiS310_HiTVSt2Timing;
-   SiS_HiTVTextTiming = SiS310_HiTVTextTiming;
-   SiS_HiTVGroup3Data = SiS310_HiTVGroup3Data;
-   SiS_HiTVGroup3Simu = SiS310_HiTVGroup3Simu;
-   SiS_HiTVGroup3Text = SiS310_HiTVGroup3Text;
-
-   SiS_PanelDelayTbl = (SiS_PanelDelayTblStruct *) SiS310_PanelDelayTbl;
-   SiS_LVDS320x480Data_1 = (SiS_LVDSDataStruct *) SiS310_LVDS320x480Data_1;
-   SiS_LVDS800x600Data_1 = (SiS_LVDSDataStruct *) SiS310_LVDS800x600Data_1;
-   SiS_LVDS800x600Data_2 = (SiS_LVDSDataStruct *) SiS310_LVDS800x600Data_2;
-   SiS_LVDS1024x768Data_1 = (SiS_LVDSDataStruct *) SiS310_LVDS1024x768Data_1;
-   SiS_LVDS1024x768Data_2 = (SiS_LVDSDataStruct *) SiS310_LVDS1024x768Data_2;
-   SiS_LVDS1280x1024Data_1 = (SiS_LVDSDataStruct *) SiS310_LVDS1280x1024Data_1;
-   SiS_LVDS1280x1024Data_2 = (SiS_LVDSDataStruct *) SiS310_LVDS1280x1024Data_2;
-   SiS_LVDS640x480Data_1 = (SiS_LVDSDataStruct *) SiS310_LVDS640x480Data_1;
-   SiS_CHTVUNTSCData = (SiS_LVDSDataStruct *) SiS310_CHTVUNTSCData;
-   SiS_CHTVONTSCData = (SiS_LVDSDataStruct *) SiS310_CHTVONTSCData;
-   SiS_CHTVUPALData = (SiS_LVDSDataStruct *) SiS310_CHTVUPALData;
-   SiS_CHTVOPALData = (SiS_LVDSDataStruct *) SiS310_CHTVOPALData;
-   SiS_PanelType00_1 = (SiS_LVDSDesStruct *) SiS310_PanelType00_1;
-   SiS_PanelType01_1 = (SiS_LVDSDesStruct *) SiS310_PanelType01_1;
-   SiS_PanelType02_1 = (SiS_LVDSDesStruct *) SiS310_PanelType02_1;
-   SiS_PanelType03_1 = (SiS_LVDSDesStruct *) SiS310_PanelType03_1;
-   SiS_PanelType04_1 = (SiS_LVDSDesStruct *) SiS310_PanelType04_1;
-   SiS_PanelType05_1 = (SiS_LVDSDesStruct *) SiS310_PanelType05_1;
-   SiS_PanelType06_1 = (SiS_LVDSDesStruct *) SiS310_PanelType06_1;
-   SiS_PanelType07_1 = (SiS_LVDSDesStruct *) SiS310_PanelType07_1;
-   SiS_PanelType08_1 = (SiS_LVDSDesStruct *) SiS310_PanelType08_1;
-   SiS_PanelType09_1 = (SiS_LVDSDesStruct *) SiS310_PanelType09_1;
-   SiS_PanelType0a_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0a_1;
-   SiS_PanelType0b_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0b_1;
-   SiS_PanelType0c_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0c_1;
-   SiS_PanelType0d_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0d_1;
-   SiS_PanelType0e_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0e_1;
-   SiS_PanelType0f_1 = (SiS_LVDSDesStruct *) SiS310_PanelType0f_1;
-   SiS_PanelType00_2 = (SiS_LVDSDesStruct *) SiS310_PanelType00_2;
-   SiS_PanelType01_2 = (SiS_LVDSDesStruct *) SiS310_PanelType01_2;
-   SiS_PanelType02_2 = (SiS_LVDSDesStruct *) SiS310_PanelType02_2;
-   SiS_PanelType03_2 = (SiS_LVDSDesStruct *) SiS310_PanelType03_2;
-   SiS_PanelType04_2 = (SiS_LVDSDesStruct *) SiS310_PanelType04_2;
-   SiS_PanelType05_2 = (SiS_LVDSDesStruct *) SiS310_PanelType05_2;
-   SiS_PanelType06_2 = (SiS_LVDSDesStruct *) SiS310_PanelType06_2;
-   SiS_PanelType07_2 = (SiS_LVDSDesStruct *) SiS310_PanelType07_2;
-   SiS_PanelType08_2 = (SiS_LVDSDesStruct *) SiS310_PanelType08_2;
-   SiS_PanelType09_2 = (SiS_LVDSDesStruct *) SiS310_PanelType09_2;
-   SiS_PanelType0a_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0a_2;
-   SiS_PanelType0b_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0b_2;
-   SiS_PanelType0c_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0c_2;
-   SiS_PanelType0d_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0d_2;
-   SiS_PanelType0e_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0e_2;
-   SiS_PanelType0f_2 = (SiS_LVDSDesStruct *) SiS310_PanelType0f_2;
-   /*301b*/
-   LVDS1024x768Des_1= (SiS_LVDSDesStruct *) SiS310_PanelType1076_1;
-   LVDS1280x1024Des_1= (SiS_LVDSDesStruct *)SiS310_PanelType1210_1;
-   LVDS1280x960Des_1= (SiS_LVDSDesStruct *)SiS310_PanelType1296_1 ;
-   LVDS1024x768Des_2= (SiS_LVDSDesStruct *) SiS310_PanelType1076_2;
-   LVDS1280x1024Des_2= (SiS_LVDSDesStruct *) SiS310_PanelType1210_2;
-   LVDS1280x960Des_2= (SiS_LVDSDesStruct *) SiS310_PanelType1296_2;
-   /*end 301b*/
-   
-   SiS_CHTVUNTSCDesData = (SiS_LVDSDesStruct *) SiS310_CHTVUNTSCDesData;
-   SiS_CHTVONTSCDesData = (SiS_LVDSDesStruct *) SiS310_CHTVONTSCDesData;
-   SiS_CHTVUPALDesData = (SiS_LVDSDesStruct *) SiS310_CHTVUPALDesData;
-   SiS_CHTVOPALDesData = (SiS_LVDSDesStruct *) SiS310_CHTVOPALDesData;
-   SiS_LVDSCRT1800x600_1 = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT1800x600_1;
-   SiS_LVDSCRT11024x768_1 = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11024x768_1;
-   SiS_LVDSCRT11280x1024_1 = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11280x1024_1;
-   SiS_LVDSCRT1800x600_1_H = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT1800x600_1_H;
-   SiS_LVDSCRT11024x768_1_H = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11024x768_1_H;
-   SiS_LVDSCRT11280x1024_1_H = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11280x1024_1_H;
-   SiS_LVDSCRT1800x600_2 = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT1800x600_2;
-   SiS_LVDSCRT11024x768_2 = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11024x768_2;
-   SiS_LVDSCRT11280x1024_2 = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11280x1024_2;
-   SiS_LVDSCRT1800x600_2_H = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT1800x600_2_H;
-   SiS_LVDSCRT11024x768_2_H = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11024x768_2_H;
-   SiS_LVDSCRT11280x1024_2_H = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT11280x1024_2_H;
-   SiS_LVDSCRT1320x480_1 = (SiS_LVDSCRT1DataStruct *) SiS310_LVDSCRT1320x480_1;   /*fstn*/
-   SiS_CHTVCRT1UNTSC = (SiS_LVDSCRT1DataStruct *) SiS310_CHTVCRT1UNTSC;
-   SiS_CHTVCRT1ONTSC = (SiS_LVDSCRT1DataStruct *) SiS310_CHTVCRT1ONTSC;
-   SiS_CHTVCRT1UPAL = (SiS_LVDSCRT1DataStruct *) SiS310_CHTVCRT1UPAL;
-   SiS_CHTVCRT1OPAL = (SiS_LVDSCRT1DataStruct *) SiS310_CHTVCRT1OPAL;
-   SiS_CHTVReg_UNTSC = (SiS_CHTVRegDataStruct *) SiS310_CHTVReg_UNTSC;
-   SiS_CHTVReg_ONTSC = (SiS_CHTVRegDataStruct *) SiS310_CHTVReg_ONTSC;
-   SiS_CHTVReg_UPAL = (SiS_CHTVRegDataStruct *) SiS310_CHTVReg_UPAL;
-   SiS_CHTVReg_OPAL = (SiS_CHTVRegDataStruct *) SiS310_CHTVReg_OPAL;
-   /*add for LCDA*/
-   SiS_LCDACRT1800x600_1 = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT1800x600_1;
-   SiS_LCDACRT11024x768_1 = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11024x768_1;
-   SiS_LCDACRT11280x1024_1 = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11280x1024_1;
-   SiS_LCDACRT1800x600_1_H = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT1800x600_1_H;
-   SiS_LCDACRT11024x768_1_H = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11024x768_1_H;
-   SiS_LCDACRT11280x1024_1_H = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11280x1024_1_H;
-   SiS_LCDACRT1800x600_2 = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT1800x600_2;
-   SiS_LCDACRT11024x768_2 = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11024x768_2;
-   SiS_LCDACRT11280x1024_2 = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11280x1024_2;
-   SiS_LCDACRT1800x600_2_H = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT1800x600_2_H;
-   SiS_LCDACRT11024x768_2_H = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11024x768_2_H;
-   SiS_LCDACRT11280x1024_2_H = (SiS_LCDACRT1DataStruct *) SiS310_LCDACRT11280x1024_2_H;
-   /*end for 301b*/
-
-   SiS_CHTVVCLKUNTSC = SiS310_CHTVVCLKUNTSC;
-   SiS_CHTVVCLKONTSC = SiS310_CHTVVCLKONTSC;
-   SiS_CHTVVCLKUPAL = SiS310_CHTVVCLKUPAL;
-   SiS_CHTVVCLKOPAL = SiS310_CHTVVCLKOPAL;
-   /* 310 customization related */
+InitTo310Pointer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+   SiS_Pr->SiS_SModeIDTable  = (SiS_StStruct *)SiS310_SModeIDTable;
+   SiS_Pr->SiS_StandTable    = (SiS_StandTableStruct *)SiS310_StandTable;
+   SiS_Pr->SiS_EModeIDTable  = (SiS_ExtStruct *)SiS310_EModeIDTable;
+   SiS_Pr->SiS_RefIndex      = (SiS_Ext2Struct *)SiS310_RefIndex;
+   SiS_Pr->SiS_CRT1Table     = (SiS_CRT1TableStruct *)SiS310_CRT1Table;
+   /* TW: MCLK is different */
+   if(HwDeviceExtension->jChipType > SIS_315PRO) {
+      SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_650;  /* 550, 650 */
+   } else {
+      SiS_Pr->SiS_MCLKData_0 = (SiS_MCLKDataStruct *)SiS310_MCLKData_0_315;  /* 315 */
+   }
+   SiS_Pr->SiS_MCLKData_1    = (SiS_MCLKDataStruct *)SiS310_MCLKData_1;
+   SiS_Pr->SiS_ECLKData      = (SiS_ECLKDataStruct *)SiS310_ECLKData;
+   SiS_Pr->SiS_VCLKData      = (SiS_VCLKDataStruct *)SiS310_VCLKData;
+   SiS_Pr->SiS_VBVCLKData    = (SiS_VBVCLKDataStruct *)SiS310_VBVCLKData;
+   SiS_Pr->SiS_ScreenOffset  = SiS310_ScreenOffset;
+   SiS_Pr->SiS_StResInfo     = (SiS_StResInfoStruct *)SiS310_StResInfo;
+   SiS_Pr->SiS_ModeResInfo   = (SiS_ModeResInfoStruct *)SiS310_ModeResInfo;
+
+   SiS_Pr->pSiS_OutputSelect = &SiS310_OutputSelect;
+   SiS_Pr->pSiS_SoftSetting  = &SiS310_SoftSetting;
+
+   SiS_Pr->SiS_SR15  = SiS310_SR15;
+
+#ifndef LINUX_XF86
+   SiS_Pr->pSiS_SR07 = &SiS310_SR07;
+   SiS_Pr->SiS_CR40  = SiS310_CR40;
+   SiS_Pr->SiS_CR49  = SiS310_CR49;
+   SiS_Pr->pSiS_SR1F = &SiS310_SR1F;
+   SiS_Pr->pSiS_SR21 = &SiS310_SR21;
+   SiS_Pr->pSiS_SR22 = &SiS310_SR22;
+   SiS_Pr->pSiS_SR23 = &SiS310_SR23;
+   SiS_Pr->pSiS_SR24 = &SiS310_SR24;
+   SiS_Pr->SiS_SR25  = SiS310_SR25;
+   SiS_Pr->pSiS_SR31 = &SiS310_SR31;
+   SiS_Pr->pSiS_SR32 = &SiS310_SR32;
+   SiS_Pr->pSiS_SR33 = &SiS310_SR33;
+   SiS_Pr->pSiS_CRT2Data_1_2  = &SiS310_CRT2Data_1_2;
+   SiS_Pr->pSiS_CRT2Data_4_D  = &SiS310_CRT2Data_4_D;
+   SiS_Pr->pSiS_CRT2Data_4_E  = &SiS310_CRT2Data_4_E;
+   SiS_Pr->pSiS_CRT2Data_4_10 = &SiS310_CRT2Data_4_10;
+   SiS_Pr->pSiS_RGBSenseData    = &SiS310_RGBSenseData;
+   SiS_Pr->pSiS_VideoSenseData  = &SiS310_VideoSenseData;
+   SiS_Pr->pSiS_YCSenseData     = &SiS310_YCSenseData;
+   SiS_Pr->pSiS_RGBSenseData2   = &SiS310_RGBSenseData2;
+   SiS_Pr->pSiS_VideoSenseData2 = &SiS310_VideoSenseData2;
+   SiS_Pr->pSiS_YCSenseData2    = &SiS310_YCSenseData2;
+#endif
+
+   SiS_Pr->SiS_NTSCPhase    = SiS310_NTSCPhase;
+   SiS_Pr->SiS_PALPhase     = SiS310_PALPhase;
+   SiS_Pr->SiS_NTSCPhase2   = SiS310_NTSCPhase2;
+   SiS_Pr->SiS_PALPhase2    = SiS310_PALPhase2;
+   SiS_Pr->SiS_PALMPhase    = SiS310_PALMPhase;
+   SiS_Pr->SiS_PALNPhase    = SiS310_PALNPhase;
+   SiS_Pr->SiS_PALMPhase2   = SiS310_PALMPhase2;
+   SiS_Pr->SiS_PALNPhase2   = SiS310_PALNPhase2;
+   SiS_Pr->SiS_SpecialPhase = SiS310_SpecialPhase;
+
+   SiS_Pr->SiS_StLCD1024x768Data    = (SiS_LCDDataStruct *)SiS310_StLCD1024x768Data;
+   SiS_Pr->SiS_ExtLCD1024x768Data   = (SiS_LCDDataStruct *)SiS310_ExtLCD1024x768Data;
+   SiS_Pr->SiS_St2LCD1024x768Data   = (SiS_LCDDataStruct *)SiS310_St2LCD1024x768Data;
+   SiS_Pr->SiS_StLCD1280x1024Data   = (SiS_LCDDataStruct *)SiS310_StLCD1280x1024Data;
+   SiS_Pr->SiS_ExtLCD1280x1024Data  = (SiS_LCDDataStruct *)SiS310_ExtLCD1280x1024Data;
+   SiS_Pr->SiS_St2LCD1280x1024Data  = (SiS_LCDDataStruct *)SiS310_St2LCD1280x1024Data;
+   SiS_Pr->SiS_NoScaleData1024x768  = (SiS_LCDDataStruct *)SiS310_NoScaleData1024x768;
+   SiS_Pr->SiS_NoScaleData1280x1024 = (SiS_LCDDataStruct *)SiS310_NoScaleData1280x1024;
+   SiS_Pr->SiS_LCD1280x960Data      = (SiS_LCDDataStruct *)SiS310_LCD1280x960Data;
+   SiS_Pr->SiS_ExtLCD1400x1050Data  = (SiS_LCDDataStruct *)SiS310_ExtLCD1400x1050Data;
+   SiS_Pr->SiS_ExtLCD1600x1200Data  = (SiS_LCDDataStruct *)SiS310_ExtLCD1600x1200Data;
+   SiS_Pr->SiS_StLCD1400x1050Data   = (SiS_LCDDataStruct *)SiS310_StLCD1400x1050Data;
+   SiS_Pr->SiS_StLCD1600x1200Data   = (SiS_LCDDataStruct *)SiS310_StLCD1600x1200Data;
+   SiS_Pr->SiS_NoScaleData1400x1050 = (SiS_LCDDataStruct *)SiS310_NoScaleData1400x1050;
+   SiS_Pr->SiS_NoScaleData1600x1200 = (SiS_LCDDataStruct *)SiS310_NoScaleData1600x1200;
+
+   SiS_Pr->SiS_StPALData   = (SiS_TVDataStruct *)SiS310_StPALData;
+   SiS_Pr->SiS_ExtPALData  = (SiS_TVDataStruct *)SiS310_ExtPALData;
+   SiS_Pr->SiS_StNTSCData  = (SiS_TVDataStruct *)SiS310_StNTSCData;
+   SiS_Pr->SiS_ExtNTSCData = (SiS_TVDataStruct *)SiS310_ExtNTSCData;
+#ifdef oldHV
+   SiS_Pr->SiS_St1HiTVData = (SiS_TVDataStruct *)SiS310_St1HiTVData;
+   SiS_Pr->SiS_St2HiTVData = (SiS_TVDataStruct *)SiS310_St2HiTVData;
+   SiS_Pr->SiS_ExtHiTVData = (SiS_TVDataStruct *)SiS310_ExtHiTVData;
+#endif
+
+   SiS_Pr->SiS_NTSCTiming     = SiS310_NTSCTiming;
+   SiS_Pr->SiS_PALTiming      = SiS310_PALTiming;
+#ifdef oldHV
+   SiS_Pr->SiS_HiTVSt1Timing  = SiS310_HiTVSt1Timing;
+   SiS_Pr->SiS_HiTVSt2Timing  = SiS310_HiTVSt2Timing;
+   SiS_Pr->SiS_HiTVTextTiming = SiS310_HiTVTextTiming;
+   SiS_Pr->SiS_HiTVExtTiming  = SiS310_HiTVExtTiming;
+   SiS_Pr->SiS_HiTVGroup3Data = SiS310_HiTVGroup3Data;
+   SiS_Pr->SiS_HiTVGroup3Simu = SiS310_HiTVGroup3Simu;
+   SiS_Pr->SiS_HiTVGroup3Text = SiS310_HiTVGroup3Text;
+#endif
+
+   SiS_Pr->SiS_PanelDelayTbl = (SiS_PanelDelayTblStruct *)SiS310_PanelDelayTbl;
+   SiS_Pr->SiS_PanelDelayTblLVDS = (SiS_PanelDelayTblStruct *)SiS310_PanelDelayTblLVDS;
+
+   SiS_Pr->SiS_LVDS800x600Data_1   = (SiS_LVDSDataStruct *)SiS310_LVDS800x600Data_1;
+   SiS_Pr->SiS_LVDS800x600Data_2   = (SiS_LVDSDataStruct *)SiS310_LVDS800x600Data_2;
+   SiS_Pr->SiS_LVDS1024x768Data_1  = (SiS_LVDSDataStruct *)SiS310_LVDS1024x768Data_1;
+   SiS_Pr->SiS_LVDS1024x768Data_2  = (SiS_LVDSDataStruct *)SiS310_LVDS1024x768Data_2;
+   SiS_Pr->SiS_LVDS1280x1024Data_1 = (SiS_LVDSDataStruct *)SiS310_LVDS1280x1024Data_1;
+   SiS_Pr->SiS_LVDS1280x1024Data_2 = (SiS_LVDSDataStruct *)SiS310_LVDS1280x1024Data_2;
+   SiS_Pr->SiS_LVDS1280x960Data_1  = (SiS_LVDSDataStruct *)SiS310_LVDS1280x960Data_1;
+   SiS_Pr->SiS_LVDS1280x960Data_2  = (SiS_LVDSDataStruct *)SiS310_LVDS1280x960Data_2;
+   SiS_Pr->SiS_LVDS1400x1050Data_1 = (SiS_LVDSDataStruct *)SiS310_LVDS1400x1050Data_1;
+   SiS_Pr->SiS_LVDS1400x1050Data_2 = (SiS_LVDSDataStruct *)SiS310_LVDS1400x1050Data_2;
+   SiS_Pr->SiS_LVDS1024x600Data_1  = (SiS_LVDSDataStruct *)SiS310_LVDS1024x600Data_1;
+   SiS_Pr->SiS_LVDS1024x600Data_2  = (SiS_LVDSDataStruct *)SiS310_LVDS1024x600Data_2;
+   SiS_Pr->SiS_LVDS1152x768Data_1  = (SiS_LVDSDataStruct *)SiS310_LVDS1152x768Data_1;
+   SiS_Pr->SiS_LVDS1152x768Data_2  = (SiS_LVDSDataStruct *)SiS310_LVDS1152x768Data_2;
+   SiS_Pr->SiS_LVDSXXXxXXXData_1   = (SiS_LVDSDataStruct *)SiS310_LVDSXXXxXXXData_1;
+   SiS_Pr->SiS_LVDS320x480Data_1   = (SiS_LVDSDataStruct *)SiS310_LVDS320x480Data_1;
+   SiS_Pr->SiS_LVDS640x480Data_1   = (SiS_LVDSDataStruct *)SiS310_LVDS640x480Data_1;
+   SiS_Pr->SiS_LCDA1400x1050Data_1  = (SiS_LVDSDataStruct *)SiS310_LCDA1400x1050Data_1;
+   SiS_Pr->SiS_LCDA1400x1050Data_2  = (SiS_LVDSDataStruct *)SiS310_LCDA1400x1050Data_2;
+   SiS_Pr->SiS_LCDA1600x1200Data_1  = (SiS_LVDSDataStruct *)SiS310_LCDA1600x1200Data_1;
+   SiS_Pr->SiS_LCDA1600x1200Data_2  = (SiS_LVDSDataStruct *)SiS310_LCDA1600x1200Data_2;
+   SiS_Pr->SiS_CHTVUNTSCData = (SiS_LVDSDataStruct *)SiS310_CHTVUNTSCData;
+   SiS_Pr->SiS_CHTVONTSCData = (SiS_LVDSDataStruct *)SiS310_CHTVONTSCData;
+   SiS_Pr->SiS_CHTVUPALData  = (SiS_LVDSDataStruct *)SiS310_CHTVUPALData;
+   SiS_Pr->SiS_CHTVOPALData  = (SiS_LVDSDataStruct *)SiS310_CHTVOPALData;
+   SiS_Pr->SiS_PanelType00_1 = (SiS_LVDSDesStruct *)SiS310_PanelType00_1;
+   SiS_Pr->SiS_PanelType01_1 = (SiS_LVDSDesStruct *)SiS310_PanelType01_1;
+   SiS_Pr->SiS_PanelType02_1 = (SiS_LVDSDesStruct *)SiS310_PanelType02_1;
+   SiS_Pr->SiS_PanelType03_1 = (SiS_LVDSDesStruct *)SiS310_PanelType03_1;
+   SiS_Pr->SiS_PanelType04_1 = (SiS_LVDSDesStruct *)SiS310_PanelType04_1;
+   SiS_Pr->SiS_PanelType05_1 = (SiS_LVDSDesStruct *)SiS310_PanelType05_1;
+   SiS_Pr->SiS_PanelType06_1 = (SiS_LVDSDesStruct *)SiS310_PanelType06_1;
+   SiS_Pr->SiS_PanelType07_1 = (SiS_LVDSDesStruct *)SiS310_PanelType07_1;
+   SiS_Pr->SiS_PanelType08_1 = (SiS_LVDSDesStruct *)SiS310_PanelType08_1;
+   SiS_Pr->SiS_PanelType09_1 = (SiS_LVDSDesStruct *)SiS310_PanelType09_1;
+   SiS_Pr->SiS_PanelType0a_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0a_1;
+   SiS_Pr->SiS_PanelType0b_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0b_1;
+   SiS_Pr->SiS_PanelType0c_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0c_1;
+   SiS_Pr->SiS_PanelType0d_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0d_1;
+   SiS_Pr->SiS_PanelType0e_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0e_1;
+   SiS_Pr->SiS_PanelType0f_1 = (SiS_LVDSDesStruct *)SiS310_PanelType0f_1;
+   SiS_Pr->SiS_PanelType00_2 = (SiS_LVDSDesStruct *)SiS310_PanelType00_2;
+   SiS_Pr->SiS_PanelType01_2 = (SiS_LVDSDesStruct *)SiS310_PanelType01_2;
+   SiS_Pr->SiS_PanelType02_2 = (SiS_LVDSDesStruct *)SiS310_PanelType02_2;
+   SiS_Pr->SiS_PanelType03_2 = (SiS_LVDSDesStruct *)SiS310_PanelType03_2;
+   SiS_Pr->SiS_PanelType04_2 = (SiS_LVDSDesStruct *)SiS310_PanelType04_2;
+   SiS_Pr->SiS_PanelType05_2 = (SiS_LVDSDesStruct *)SiS310_PanelType05_2;
+   SiS_Pr->SiS_PanelType06_2 = (SiS_LVDSDesStruct *)SiS310_PanelType06_2;
+   SiS_Pr->SiS_PanelType07_2 = (SiS_LVDSDesStruct *)SiS310_PanelType07_2;
+   SiS_Pr->SiS_PanelType08_2 = (SiS_LVDSDesStruct *)SiS310_PanelType08_2;
+   SiS_Pr->SiS_PanelType09_2 = (SiS_LVDSDesStruct *)SiS310_PanelType09_2;
+   SiS_Pr->SiS_PanelType0a_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0a_2;
+   SiS_Pr->SiS_PanelType0b_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0b_2;
+   SiS_Pr->SiS_PanelType0c_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0c_2;
+   SiS_Pr->SiS_PanelType0d_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0d_2;
+   SiS_Pr->SiS_PanelType0e_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0e_2;
+   SiS_Pr->SiS_PanelType0f_2 = (SiS_LVDSDesStruct *)SiS310_PanelType0f_2;
+
+   SiS_Pr->LVDS1024x768Des_1  = (SiS_LVDSDesStruct *)SiS310_PanelType1076_1;
+   SiS_Pr->LVDS1280x1024Des_1 = (SiS_LVDSDesStruct *)SiS310_PanelType1210_1;
+   SiS_Pr->LVDS1400x1050Des_1 = (SiS_LVDSDesStruct *)SiS310_PanelType1296_1 ;
+   SiS_Pr->LVDS1600x1200Des_1 = (SiS_LVDSDesStruct *)SiS310_PanelType1600_1 ;
+   SiS_Pr->LVDS1024x768Des_2  = (SiS_LVDSDesStruct *)SiS310_PanelType1076_2;
+   SiS_Pr->LVDS1280x1024Des_2 = (SiS_LVDSDesStruct *)SiS310_PanelType1210_2;
+   SiS_Pr->LVDS1400x1050Des_2 = (SiS_LVDSDesStruct *)SiS310_PanelType1296_2;
+   SiS_Pr->LVDS1600x1200Des_2 = (SiS_LVDSDesStruct *)SiS310_PanelType1600_2 ;
+
+   /* TW: New from 650/301LV BIOS */
+   SiS_Pr->SiS_CRT2Part2_1024x768_1  = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1024x768_1;
+   SiS_Pr->SiS_CRT2Part2_1280x1024_1 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1280x1024_1;
+   SiS_Pr->SiS_CRT2Part2_1400x1050_1 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1400x1050_1;
+   SiS_Pr->SiS_CRT2Part2_1600x1200_1 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1600x1200_1;
+   SiS_Pr->SiS_CRT2Part2_1024x768_2  = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1024x768_2;
+   SiS_Pr->SiS_CRT2Part2_1280x1024_2 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1280x1024_2;
+   SiS_Pr->SiS_CRT2Part2_1400x1050_2 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1400x1050_2;
+   SiS_Pr->SiS_CRT2Part2_1600x1200_2 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1600x1200_2;
+   SiS_Pr->SiS_CRT2Part2_1024x768_3  = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1024x768_3;
+   SiS_Pr->SiS_CRT2Part2_1280x1024_3 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1280x1024_3;
+   SiS_Pr->SiS_CRT2Part2_1400x1050_3 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1400x1050_3;
+   SiS_Pr->SiS_CRT2Part2_1600x1200_3 = (SiS_Part2PortTblStruct *)SiS310_CRT2Part2_1600x1200_3;
+
+   SiS_Pr->SiS_CHTVUNTSCDesData = (SiS_LVDSDesStruct *)SiS310_CHTVUNTSCDesData;
+   SiS_Pr->SiS_CHTVONTSCDesData = (SiS_LVDSDesStruct *)SiS310_CHTVONTSCDesData;
+   SiS_Pr->SiS_CHTVUPALDesData  = (SiS_LVDSDesStruct *)SiS310_CHTVUPALDesData;
+   SiS_Pr->SiS_CHTVOPALDesData  = (SiS_LVDSDesStruct *)SiS310_CHTVOPALDesData;
+
+   SiS_Pr->SiS_LVDSCRT1800x600_1     = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_1;
+   SiS_Pr->SiS_LVDSCRT11024x768_1    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_1;
+   SiS_Pr->SiS_LVDSCRT11280x1024_1   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_1;
+   SiS_Pr->SiS_LVDSCRT11400x1050_1   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_1;
+   SiS_Pr->SiS_LVDSCRT11024x600_1    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x600_1;
+   SiS_Pr->SiS_LVDSCRT11152x768_1    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11152x768_1;
+   SiS_Pr->SiS_LVDSCRT11600x1200_1   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_1;
+   SiS_Pr->SiS_LVDSCRT1800x600_1_H   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_1_H;
+   SiS_Pr->SiS_LVDSCRT11024x768_1_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_1_H;
+   SiS_Pr->SiS_LVDSCRT11280x1024_1_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_1_H;
+   SiS_Pr->SiS_LVDSCRT11400x1050_1_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_1_H;
+   SiS_Pr->SiS_LVDSCRT11024x600_1_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x600_1_H;
+   SiS_Pr->SiS_LVDSCRT11152x768_1_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11152x768_1_H;
+   SiS_Pr->SiS_LVDSCRT11600x1200_1_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_1_H;
+   SiS_Pr->SiS_LVDSCRT1800x600_2     = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_2;
+   SiS_Pr->SiS_LVDSCRT11024x768_2    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_2;
+   SiS_Pr->SiS_LVDSCRT11280x1024_2   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_2;
+   SiS_Pr->SiS_LVDSCRT11400x1050_2   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_2;
+   SiS_Pr->SiS_LVDSCRT11024x600_2    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x600_2;
+   SiS_Pr->SiS_LVDSCRT11152x768_2    = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11152x768_2;
+   SiS_Pr->SiS_LVDSCRT11600x1200_2   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_2;
+   SiS_Pr->SiS_LVDSCRT1800x600_2_H   = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1800x600_2_H;
+   SiS_Pr->SiS_LVDSCRT11024x768_2_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x768_2_H;
+   SiS_Pr->SiS_LVDSCRT11280x1024_2_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11280x1024_2_H;
+   SiS_Pr->SiS_LVDSCRT11400x1050_2_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11400x1050_2_H;
+   SiS_Pr->SiS_LVDSCRT11024x600_2_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11024x600_2_H;
+   SiS_Pr->SiS_LVDSCRT11152x768_2_H  = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11152x768_2_H;
+   SiS_Pr->SiS_LVDSCRT11600x1200_2_H = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT11600x1200_2_H;
+   SiS_Pr->SiS_LVDSCRT1XXXxXXX_1     = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1XXXxXXX_1;
+   SiS_Pr->SiS_LVDSCRT1320x480_1     = (SiS_LVDSCRT1DataStruct *)SiS310_LVDSCRT1320x480_1;
+   SiS_Pr->SiS_CHTVCRT1UNTSC = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1UNTSC;
+   SiS_Pr->SiS_CHTVCRT1ONTSC = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1ONTSC;
+   SiS_Pr->SiS_CHTVCRT1UPAL  = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1UPAL;
+   SiS_Pr->SiS_CHTVCRT1OPAL  = (SiS_LVDSCRT1DataStruct *)SiS310_CHTVCRT1OPAL;
+   SiS_Pr->SiS_CHTVReg_UNTSC = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_UNTSC;
+   SiS_Pr->SiS_CHTVReg_ONTSC = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_ONTSC;
+   SiS_Pr->SiS_CHTVReg_UPAL  = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_UPAL;
+   SiS_Pr->SiS_CHTVReg_OPAL  = (SiS_CHTVRegDataStruct *)SiS310_CHTVReg_OPAL;
+   SiS_Pr->SiS_LCDACRT1800x600_1     = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT1800x600_1;
+   SiS_Pr->SiS_LCDACRT11024x768_1    = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_1;
+   SiS_Pr->SiS_LCDACRT11280x1024_1   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_1;
+   SiS_Pr->SiS_LCDACRT11400x1050_1   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_1;
+   SiS_Pr->SiS_LCDACRT11600x1200_1   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_1;
+   SiS_Pr->SiS_LCDACRT1800x600_1_H   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT1800x600_1_H;
+   SiS_Pr->SiS_LCDACRT11024x768_1_H  = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_1_H;
+   SiS_Pr->SiS_LCDACRT11280x1024_1_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_1_H;
+   SiS_Pr->SiS_LCDACRT11400x1050_1_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_1_H;
+   SiS_Pr->SiS_LCDACRT11600x1200_1_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_1_H;
+   SiS_Pr->SiS_LCDACRT1800x600_2     = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT1800x600_2;
+   SiS_Pr->SiS_LCDACRT11024x768_2    = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_2;
+   SiS_Pr->SiS_LCDACRT11280x1024_2   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_2;
+   SiS_Pr->SiS_LCDACRT11400x1050_2   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_2;
+   SiS_Pr->SiS_LCDACRT11600x1200_2   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_2;
+   SiS_Pr->SiS_LCDACRT1800x600_2_H   = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT1800x600_2_H;
+   SiS_Pr->SiS_LCDACRT11024x768_2_H  = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11024x768_2_H;
+   SiS_Pr->SiS_LCDACRT11280x1024_2_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11280x1024_2_H;
+   SiS_Pr->SiS_LCDACRT11400x1050_2_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11400x1050_2_H;
+   SiS_Pr->SiS_LCDACRT11600x1200_2_H = (SiS_LCDACRT1DataStruct *)SiS310_LCDACRT11600x1200_2_H;
+   SiS_Pr->SiS_CHTVVCLKUNTSC = SiS310_CHTVVCLKUNTSC;
+   SiS_Pr->SiS_CHTVVCLKONTSC = SiS310_CHTVVCLKONTSC;
+   SiS_Pr->SiS_CHTVVCLKUPAL  = SiS310_CHTVVCLKUPAL;
+   SiS_Pr->SiS_CHTVVCLKOPAL  = SiS310_CHTVVCLKOPAL;
+
+   SiS_Pr->SiS_Panel320x480   = Panel_320x480;
+   SiS_Pr->SiS_Panel640x480   = Panel_640x480;
+   SiS_Pr->SiS_Panel800x600   = Panel_800x600;
+   SiS_Pr->SiS_Panel1024x768  = Panel_1024x768;
+   SiS_Pr->SiS_Panel1280x1024 = Panel_1280x1024;
+   SiS_Pr->SiS_Panel1280x960  = Panel_1280x960;
+   SiS_Pr->SiS_Panel1600x1200 = Panel_1600x1200;
+   SiS_Pr->SiS_Panel1400x1050 = Panel_1400x1050;
+   SiS_Pr->SiS_Panel1152x768  = Panel_1152x768;
+   SiS_Pr->SiS_Panel1152x864  = Panel_1152x864;
+   SiS_Pr->SiS_Panel1280x768  = Panel_1280x768;
+   SiS_Pr->SiS_Panel1024x600  = Panel_1024x600;
+   SiS_Pr->SiS_PanelMax       = Panel_320x480;    /* TW: highest value */
+   SiS_Pr->SiS_PanelMinLVDS   = Panel_800x600;    /* TW: lowest value LVDS/LCDA */
+   SiS_Pr->SiS_PanelMin301    = Panel_1024x768;   /* TW: lowest value 301 */
 }
 #endif
 
-#ifndef LINUX_XF86
+#ifdef LINUXBIOS
 /* -------------- SiSInit -----------------*/
+/* TW: I degraded this for LINUXBIOS only, because we
+ *     don't need this otherwise
+ */
 BOOLEAN
-SiSInit(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiSInit(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-   ULONG   ROMAddr  = (ULONG)HwDeviceExtension->pjVirtualRomBase;
+   UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
    ULONG   FBAddr   = (ULONG)HwDeviceExtension->pjVideoMemoryAddress;
    USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
-   UCHAR   i,temp=0;
+   UCHAR   i, temp=0;
    UCHAR   SR11;
 #ifdef LINUX_KERNEL
    UCHAR   temp1;
    ULONG   base;
 #endif
-   UCHAR   SR12=0,SR13=0,SR14=0,SR16=0,SR17=0,SR18=0,SR19=0,SR1A=0;
-
+   UCHAR   SR13=0, SR14=0, SR16=0
+   UCHAR   SR17=0, SR19=0, SR1A=0;
+#ifdef SIS300
+   UCHAR   SR18=0, SR12=0;
+#endif
 #ifdef SIS315H
-   UCHAR   CR37=0,CR38=0,CR79=0,CR7A=0,CR7B=0,CR7C=0;
-   UCHAR   SR1B=0,SR15=0;
-   PSIS_DSReg  pSR;
+   UCHAR   CR37=0, CR38=0, CR79=0,
+   UCHAR   CR7A=0, CR7B=0, CR7C=0;
+   UCHAR   SR1B=0, SR15=0;
+   PSIS_DSReg pSR;
    ULONG   Temp;
 #endif
    UCHAR   VBIOSVersion[5];
@@ -484,118 +650,115 @@
    if(FBAddr==0)    return (FALSE);
    if(BaseAddr==0)  return (FALSE);
 
-   SiS_SetReg3((USHORT)(BaseAddr+0x12),  0x67);  /* 3c2 <- 67 ,ynlai */
+   SiS_SetReg3((USHORT)(BaseAddr+0x12),  0x67);  /* Misc */
 
 #ifdef SIS315H
-   /*if(HwDeviceExtension->jChipType > SIS_315H)*/
    if(HwDeviceExtension->jChipType > SIS_315PRO) {
      if(!HwDeviceExtension->bIntegratedMMEnabled)
-     	return (FALSE);  /* alan  */
+     	return (FALSE);
    }
 #endif
 
    SiS_MemoryCopy(VBIOSVersion,HwDeviceExtension->szVBIOSVer,4);
-   VBIOSVersion[4]= 0x0;
-   /* 09/07/99 modify by domao */
+   VBIOSVersion[4]= 0x00;
 
+   SiSDetermineROMUsage(SiS_Pr, HwDeviceExtension, ROMAddr);
+
+   /* TW: Init pointers */
 #ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_315H)||
-      (HwDeviceExtension->jChipType == SIS_315PRO)||
-      (HwDeviceExtension->jChipType == SIS_550)||   /* 05/02/01 ynlai for 550 */
-      (HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_650))    /* 09/03/01 chiawen for 650 */
-     InitTo310Pointer();
+   if((HwDeviceExtension->jChipType == SIS_315H) ||
+      (HwDeviceExtension->jChipType == SIS_315PRO) ||
+      (HwDeviceExtension->jChipType == SIS_550) ||
+      (HwDeviceExtension->jChipType == SIS_640) ||
+      (HwDeviceExtension->jChipType == SIS_740) ||
+      (HwDeviceExtension->jChipType == SIS_650))
+     InitTo310Pointer(SiS_Pr, HwDeviceExtension);
 #endif
 
 #ifdef SIS300
-   if ((HwDeviceExtension->jChipType == SIS_540)||
-       (HwDeviceExtension->jChipType == SIS_630)||
-       (HwDeviceExtension->jChipType == SIS_730)||
-       (HwDeviceExtension->jChipType == SIS_300))
-     InitTo300Pointer();
+   if((HwDeviceExtension->jChipType == SIS_540) ||
+      (HwDeviceExtension->jChipType == SIS_630) ||
+      (HwDeviceExtension->jChipType == SIS_730) ||
+      (HwDeviceExtension->jChipType == SIS_300))
+     InitTo300Pointer(SiS_Pr, HwDeviceExtension);
 #endif
 
-   /* TW: Set SiS Register globals */
-   SiSRegInit(BaseAddr);
+   /* TW: Set SiS Register definitions */
+   SiSRegInit(SiS_Pr, BaseAddr);
 
-   /* TW: Determine LVDS/CH7005/TRUMPION */
-   SiS_Set_LVDS_TRUMPION(HwDeviceExtension);
+   /* TW: Determine LVDS/CH70xx/TRUMPION */
+   SiS_Set_LVDS_TRUMPION(SiS_Pr, HwDeviceExtension);
 
-   SiS_SetReg1(SiS_P3c4,0x05,0x86);                     /* 1.Openkey - unlock registers */
+   /* TW: Unlock registers */
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
 
 #ifdef LINUX_KERNEL
 
-#ifdef SIS300                                         	/* add to set SR14*/
-   if((HwDeviceExtension->jChipType==SIS_540)||
-      (HwDeviceExtension->jChipType==SIS_630)||
+#ifdef SIS300                                         	/* Set SR14 */
+   if((HwDeviceExtension->jChipType==SIS_540) ||
+      (HwDeviceExtension->jChipType==SIS_630) ||
       (HwDeviceExtension->jChipType==SIS_730)) {
      base=0x80000060;
      OutPortLong(base,0xcf8);
-     temp1=InPortLong(0xcfc);
-     temp1=temp1>>(16+8+4);
-     temp1=temp1&(0x07);
-     temp1=temp1+1;
-     temp1=1<<temp1;
-     SR14=temp1-1;
-     base=0x80000064;
+     temp1 = InPortLong(0xcfc);
+     temp1 >>= (16+8+4);
+     temp1 &= 0x07;
+     temp1++;
+     temp1 = 1 << temp1;
+     SR14 = temp1 - 1;
+     base = 0x80000064;
      OutPortLong(base,0xcf8);
-     temp1=InPortLong(0xcfc);
-     temp1=temp1&(0x00000020);
-     if(temp1)
-      	SR14=(0x10000000)|SR14;
-     else
-      	SR14=(0x01000000)|SR14;
+     temp1 = InPortLong(0xcfc);
+     temp1 &= 0x00000020;
+     if(temp1) 	SR14 |= 0x80;
+     else      	SR14 |= 0x40;
    }
 #endif
 
-#ifdef SIS315H                                         /* add to set SR14*/
+#ifdef SIS315H                                          /* Set SR14 */
    if(HwDeviceExtension->jChipType==SIS_550) {
-     base=0x80000060;
+     base = 0x80000060;
      OutPortLong(base,0xcf8);
-     temp1=InPortLong(0xcfc);
-     temp1=temp1>>(16+8+4);
-     temp1=temp1&(0x07);
-     temp1=temp1+1;
-     temp1=1<<temp1;
-     SR14=temp1-1;
-     base=0x80000064;
+     temp1 = InPortLong(0xcfc);
+     temp1 >>= (16+8+4);
+     temp1 &= 0x07;
+     temp1++;
+     temp1 = 1 << temp1;
+     SR14 = temp1 - 1;
+     base = 0x80000064;
      OutPortLong(base,0xcf8);
-     temp1=InPortLong(0xcfc);
-     temp1=temp1&(0x00000020);
-     if(temp1)
-      SR14=(0x10000000)|SR14;
-     else
-      SR14=(0x01000000)|SR14;
+     temp1 = InPortLong(0xcfc);
+     temp1 &= 0x00000020;
+     if(temp1)  SR14 |= 0x80;
+     else       SR14 |= 0x40;
    }
 
-   if((HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_650)) {  /* 09/03/01 chiawen for 650 */
-     base=0x80000064;
+   if((HwDeviceExtension->jChipType == SIS_640) ||      /* Set SR14 */
+      (HwDeviceExtension->jChipType == SIS_740) ||
+      (HwDeviceExtension->jChipType == SIS_650)) {
+     base = 0x80000064;
      OutPortLong(base,0xcf8);
      temp1=InPortLong(0xcfc);
-     temp1=temp>>4;
-     temp1=temp1&(0x07);
-     if(temp1 > 2 ) {
+     temp1 >>= 4;
+     temp1 &= 0x07;
+     if(temp1 > 2) {
        temp = temp1;
        switch(temp) {
-        case 3: temp1=0x07;  break;
-        case 4: temp1=0x0F;  break;
-        case 5: temp1=0x1F;  break;
-        case 6: temp1=0x05;  break;
-        case 7: temp1=0x17;  break;
+        case 3: temp1 = 0x07;  break;
+        case 4: temp1 = 0x0F;  break;
+        case 5: temp1 = 0x1F;  break;
+        case 6: temp1 = 0x05;  break;
+        case 7: temp1 = 0x17;  break;
         case 8: break;
         case 9: break;
        }
      }
-     SR14=temp1;
-     base=0x8000007C;
+     SR14 = temp1;
+     base = 0x8000007C;
      OutPortLong(base,0xcf8);
-     temp1=InPortLong(0xcfc);
-     temp1=temp1&(0x00000020);
-     if(temp1)
-       SR14=(0x10000000)|SR14;
+     temp1 = InPortLong(0xcfc);
+     temp1 &= 0x00000020;
+     if(temp1)  SR14 |= 0x80;
    }
 #endif
 
@@ -605,25 +768,25 @@
    if((HwDeviceExtension->jChipType == SIS_540)||
       (HwDeviceExtension->jChipType == SIS_630)||
       (HwDeviceExtension->jChipType == SIS_730)) {
-     SR12 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x12);
-     SR13 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x13);
-     SR14 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x14);
-     SR16 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x16);
-     SR17 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x17);
-     SR18 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x18);
-     SR19 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x19);
-     SR1A = (UCHAR)SiS_GetReg1(SiS_P3c4,0x1A);
+     SR12 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x12);
+     SR13 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13);
+     SR14 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+     SR16 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
+     SR17 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17);
+     SR18 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x18);
+     SR19 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x19);
+     SR1A = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1A);
    } else if(HwDeviceExtension->jChipType == SIS_300){
-     SR13 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x13);
-     SR14 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x14);
+     SR13 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13);
+     SR14 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
    }
 #endif
 #ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_550)||
-      (HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_650)) {  /* 09/03/01 chiawen for 650 */
-     SR19 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x19);
+   if((HwDeviceExtension->jChipType == SIS_550) ||
+      (HwDeviceExtension->jChipType == SIS_640) ||
+      (HwDeviceExtension->jChipType == SIS_740) ||
+      (HwDeviceExtension->jChipType == SIS_650)) {
+     SR19 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x19);
      SR19 = (SR19)||0x01;  /* TW: ??? || ??? */
      if(SR19==0x00) {
      	SR13 = 0x22;
@@ -640,399 +803,411 @@
      	CR7B = 0x00;
      	CR7C = 0x00;
      } else {
-     	SR13 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x13);
-     	SR14 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x14);
-     	SR15 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x15);
-     	SR16 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x16);
-     	SR17 = (UCHAR)SiS_GetReg1(SiS_P3c4,0x17);
-     	SR1A = (UCHAR)SiS_GetReg1(SiS_P3c4,0x1A);
-     	SR1B = (UCHAR)SiS_GetReg1(SiS_P3c4,0x1B);
-     	CR37 = 0x02;/*(UCHAR)SiS_GetReg1(SiS_P3d4,0x37);*/
-     	CR38 = (UCHAR)SiS_GetReg1(SiS_P3d4,0x38);
-     	CR79 = (UCHAR)SiS_GetReg1(SiS_P3d4,0x79);
-     	CR7A = (UCHAR)SiS_GetReg1(SiS_P3d4,0x7A);
-     	CR7B = (UCHAR)SiS_GetReg1(SiS_P3d4,0x7B);
-     	CR7C = (UCHAR)SiS_GetReg1(SiS_P3d4,0x7C);
+     	SR13 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13);
+     	SR14 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+     	SR15 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x15);
+     	SR16 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
+     	SR17 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17);
+     	SR1A = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1A);
+     	SR1B = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1B);
+     	CR37 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);  /* TW: Was 0x02 - why? */
+     	CR38 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x38);
+     	CR79 = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x79);
+     	CR7A = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x7A);
+     	CR7B = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x7B);
+     	CR7C = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x7C);
      }
    }
 #endif
 
-/* ResetExtReg begin: Reset extended registers */
-
-   for(i=0x06;i< 0x20;i++) SiS_SetReg1(SiS_P3c4,i,0);   /* 2.Reset Extended register */
-   for(i=0x21;i<=0x27;i++) SiS_SetReg1(SiS_P3c4,i,0);   /*   Reset Extended register */
-   for(i=0x31;i<=0x3D;i++) SiS_SetReg1(SiS_P3c4,i,0);
+   /* Reset extended registers */
+
+   for(i=0x06; i< 0x20; i++) SiS_SetReg1(SiS_Pr->SiS_P3c4,i,0);
+   for(i=0x21; i<=0x27; i++) SiS_SetReg1(SiS_Pr->SiS_P3c4,i,0);
+   for(i=0x31; i<=0x3D; i++) SiS_SetReg1(SiS_Pr->SiS_P3c4,i,0);
 
 #ifdef SIS300
-   if((HwDeviceExtension->jChipType == SIS_540)||
-      (HwDeviceExtension->jChipType == SIS_630)||
-      (HwDeviceExtension->jChipType == SIS_730)||
+   if((HwDeviceExtension->jChipType == SIS_540) ||
+      (HwDeviceExtension->jChipType == SIS_630) ||
+      (HwDeviceExtension->jChipType == SIS_730) ||
       (HwDeviceExtension->jChipType == SIS_300)) {
-     	for(i=0x38;i<=0x3F;i++) SiS_SetReg1(SiS_P3d4,i,0);
+     	for(i=0x38; i<=0x3F; i++) SiS_SetReg1(SiS_Pr->SiS_P3d4,i,0);
    }
 #endif
 
 #ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_315H)||
-      (HwDeviceExtension->jChipType == SIS_315PRO)||
-      (HwDeviceExtension->jChipType == SIS_550)||   /* 05/02/01 ynlai for 550 */
-      (HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
+   if((HwDeviceExtension->jChipType == SIS_315H) ||
+      (HwDeviceExtension->jChipType == SIS_315PRO) ||
+      (HwDeviceExtension->jChipType == SIS_550) ||
+      (HwDeviceExtension->jChipType == SIS_640) ||
+      (HwDeviceExtension->jChipType == SIS_740) ||
       (HwDeviceExtension->jChipType == SIS_650)) {
-   	for(i=0x12;i<=0x1B;i++) SiS_SetReg1(SiS_P3c4,i,0);
-   	for(i=0x79;i<=0x7C;i++) SiS_SetReg1(SiS_P3d4,i,0);
+   	for(i=0x12; i<=0x1B; i++) SiS_SetReg1(SiS_Pr->SiS_P3c4,i,0);
+   	for(i=0x79; i<=0x7C; i++) SiS_SetReg1(SiS_Pr->SiS_P3d4,i,0);
    }
 #endif
-/* ResetExtReg end */
+
+   /* Restore Extended Registers */
 
 #ifdef SIS300
-   if((HwDeviceExtension->jChipType == SIS_540)||
-      (HwDeviceExtension->jChipType == SIS_630)||
+   if((HwDeviceExtension->jChipType == SIS_540) ||
+      (HwDeviceExtension->jChipType == SIS_630) ||
       (HwDeviceExtension->jChipType == SIS_730)) {
-     SiS_SetReg1(SiS_P3c4,0x12,SR12);
-     SiS_SetReg1(SiS_P3c4,0x13,SR13);
-     SiS_SetReg1(SiS_P3c4,0x14,SR14);
-     SiS_SetReg1(SiS_P3c4,0x16,SR16);
-     SiS_SetReg1(SiS_P3c4,0x17,SR17);
-     SiS_SetReg1(SiS_P3c4,0x18,SR18);
-     SiS_SetReg1(SiS_P3c4,0x19,SR19);
-     SiS_SetReg1(SiS_P3c4,0x1A,SR1A);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x12,SR12);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,SR13);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,SR14);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,SR16);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x17,SR17);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x18,SR18);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x19,SR19);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1A,SR1A);
    }
 #endif
 
 #ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_550)||
-      (HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_650)) {  /* 09/03/01 chiawen for 650 */
-     SiS_SetReg1(SiS_P3c4,0x13,SR13);
-     SiS_SetReg1(SiS_P3c4,0x14,SR14);
-     SiS_SetReg1(SiS_P3c4,0x15,SR15);
-     SiS_SetReg1(SiS_P3c4,0x16,SR16);
-     SiS_SetReg1(SiS_P3c4,0x17,SR17);
-     SiS_SetReg1(SiS_P3c4,0x19,SR19);
-     SiS_SetReg1(SiS_P3c4,0x1A,SR1A);
-     SiS_SetReg1(SiS_P3c4,0x1B,SR1B);
-     SiS_SetReg1(SiS_P3d4,0x37,CR37);
-     SiS_SetReg1(SiS_P3d4,0x38,CR38);
-     SiS_SetReg1(SiS_P3d4,0x79,CR79);
-     SiS_SetReg1(SiS_P3d4,0x7A,CR7A);
-     SiS_SetReg1(SiS_P3d4,0x7B,CR7B);
-     SiS_SetReg1(SiS_P3d4,0x7C,CR7C);
+   if((HwDeviceExtension->jChipType == SIS_550) ||
+      (HwDeviceExtension->jChipType == SIS_640) ||
+      (HwDeviceExtension->jChipType == SIS_740) ||
+      (HwDeviceExtension->jChipType == SIS_650)) {
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,SR13);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,SR14);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x15,SR15);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,SR16);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x17,SR17);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x19,SR19);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1A,SR1A);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1B,SR1B);
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x37,CR37);
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x38,CR38);
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x79,CR79);
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x7A,CR7A);
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x7B,CR7B);
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x7C,CR7C);
    }
 #endif
 
 #ifdef SIS300
-   if((HwDeviceExtension->jChipType==SIS_540)||
-      (HwDeviceExtension->jChipType==SIS_630)||
+   if((HwDeviceExtension->jChipType==SIS_540) ||
+      (HwDeviceExtension->jChipType==SIS_630) ||
       (HwDeviceExtension->jChipType==SIS_730)) {
-     	temp=(UCHAR)SR1A;
+     	temp = (UCHAR)SR1A & 0x03;
    } else if(HwDeviceExtension->jChipType==SIS_300) {
         /* TW: Nothing */
-   } else
+   }
 #endif
-   {
-      	if((*pSiS_SoftSetting&SoftDRAMType)==0){
-          	temp=(UCHAR)SiS_GetReg1(SiS_P3c4,0x3A);
+#ifdef SIS315H
+   if((HwDeviceExtension->jChipType == SIS_315H )||
+      (HwDeviceExtension->jChipType == SIS_315PRO)) {
+      	if((*SiS_Pr->pSiS_SoftSetting & SoftDRAMType) == 0){
+          	temp = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3A) & 0x03;
+        }
+   }
+   if((HwDeviceExtension->jChipType == SIS_550) ||
+      (HwDeviceExtension->jChipType == SIS_640) ||
+      (HwDeviceExtension->jChipType == SIS_740) ||
+      (HwDeviceExtension->jChipType == SIS_650)) {
+        if((*SiS_Pr->pSiS_SoftSetting & SoftDRAMType) == 0){
+          	temp = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x07;
         }
    }
+#endif
 
-   SiS_RAMType=temp&0x03;
-   SiS_SetMemoryClock(ROMAddr);
+   SiS_Pr->SiS_RAMType = temp;
+   SiS_SetMemoryClock(SiS_Pr, ROMAddr, HwDeviceExtension);
 
-/* SetDefExt1Regs begin: Set default register contents */
+   /* Set default register contents */
 
-   SiS_SetReg1(SiS_P3c4,0x07,*pSiS_SR07); 		/* DAC speed */
-   if((HwDeviceExtension->jChipType != SIS_540)&&
-      (HwDeviceExtension->jChipType != SIS_630)&&
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x07,*SiS_Pr->pSiS_SR07); 		/* DAC speed */
+
+   if((HwDeviceExtension->jChipType != SIS_540) &&
+      (HwDeviceExtension->jChipType != SIS_630) &&
       (HwDeviceExtension->jChipType != SIS_730)){
      	for(i=0x15;i<0x1C;i++) {
-       		SiS_SetReg1(SiS_P3c4,i,SiS_SR15[i-0x15][SiS_RAMType]);
+       	    SiS_SetReg1(SiS_Pr->SiS_P3c4,i,SiS_Pr->SiS_SR15[i-0x15][SiS_Pr->SiS_RAMType]);
      	}
    }
 
 #ifdef SIS315H
-   if ((HwDeviceExtension->jChipType == SIS_315H )||
+   if ((HwDeviceExtension->jChipType == SIS_315H ) ||
        (HwDeviceExtension->jChipType == SIS_315PRO)) {
      	for(i=0x40;i<=0x44;i++) {
-       		SiS_SetReg1(SiS_P3d4,i,SiS_CR40[i-0x40][SiS_RAMType]);
+       	    SiS_SetReg1(SiS_Pr->SiS_P3d4,i,SiS_Pr->SiS_CR40[i-0x40][SiS_Pr->SiS_RAMType]);
      	}
-     	SiS_SetReg1(SiS_P3d4,0x48,0x23);
-     	SiS_SetReg1(SiS_P3d4,0x49,SiS_CR49[0]);
-    	/* /SiS_SetReg1(SiS_P3c4,0x25,SiS_SR25[0]);  */
+     	SiS_SetReg1(SiS_Pr->SiS_P3d4,0x48,0x23);
+     	SiS_SetReg1(SiS_Pr->SiS_P3d4,0x49,SiS_Pr->SiS_CR49[0]);
+    /*  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x25,SiS_Pr->SiS_SR25[0]);  */
    }
 #endif
 
-   SiS_SetReg1(SiS_P3c4,0x1F,*pSiS_SR1F); 	/* DAC pedestal */
-   /*SiS_SetReg1(SiS_P3c4,0x20,0x20);*/
-   SiS_SetReg1(SiS_P3c4,0x20,0xA0); /* alan, 2001/6/26 Frame buffer can read/write*/
-   SiS_SetReg1(SiS_P3c4,0x23,*pSiS_SR23);
-   SiS_SetReg1(SiS_P3c4,0x24,*pSiS_SR24);
-   SiS_SetReg1(SiS_P3c4,0x25,SiS_SR25[0]);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1F,*SiS_Pr->pSiS_SR1F); 	/* DAC pedestal */
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x20,0xA0);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x23,*SiS_Pr->pSiS_SR23);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x24,*SiS_Pr->pSiS_SR24);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x25,SiS_Pr->SiS_SR25[0]);
 
 #ifdef SIS300
-   if(HwDeviceExtension->jChipType==SIS_300) {
-     	SiS_SetReg1(SiS_P3c4,0x21,0x84);
-     	SiS_SetReg1(SiS_P3c4,0x22,0x00);
+   if(HwDeviceExtension->jChipType == SIS_300) {
+     	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x21,0x84);
+     	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x22,0x00);
    }
 #endif
 
-   SR11=0x0F;
-   SiS_SetReg1(SiS_P3c4,0x11,SR11);	/* Power Management */
+   SR11 = 0x0F;
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x11,SR11);		/* Power Management & DDC port */
 
-   SiS_UnLockCRT2(HwDeviceExtension, BaseAddr);
-   SiS_SetReg1(SiS_Part1Port,0x00,0x00);
-   SiS_SetReg1(SiS_Part1Port,0x02,*pSiS_CRT2Data_1_2);
+   SiS_UnLockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x00,0x00);
+   SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x02,*SiS_Pr->pSiS_CRT2Data_1_2);
 
-#ifdef SIS315H                            /* 05/02/01 ynlai  for sis550 */
+#ifdef SIS315H
    if((HwDeviceExtension->jChipType == SIS_315H) ||
       (HwDeviceExtension->jChipType == SIS_315PRO) ||
-      (HwDeviceExtension->jChipType == SIS_550)||
-      (HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_650))    /* 09/03/01 chiawen for 650 */
-     	SiS_SetReg1(SiS_Part1Port,0x2E,0x08); /* use VB */
+      (HwDeviceExtension->jChipType == SIS_550) ||
+      (HwDeviceExtension->jChipType == SIS_640) ||
+      (HwDeviceExtension->jChipType == SIS_740) ||
+      (HwDeviceExtension->jChipType == SIS_650))
+     	SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x2E,0x08);    /* use VB */
 #endif
 
-   temp=*pSiS_SR32;
-   if(!SiS_BridgeIsOn(BaseAddr)) {
-     	temp=temp&0xEF;
+   temp = *SiS_Pr->pSiS_SR32;
+   if(SiS_BridgeIsOn(SiS_Pr, BaseAddr)) {
+     	temp &= 0xEF;
    }
-   SiS_SetReg1(SiS_P3c4,0x32,temp);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,temp);
 
 #ifdef SIS315H
-   if ((HwDeviceExtension->jChipType == SIS_315H) ||
-       (HwDeviceExtension->jChipType == SIS_315PRO)) {
-     HwDeviceExtension->pQueryVGAConfigSpace(HwDeviceExtension,0x50,0,&Temp);  /* Get */
+   if((HwDeviceExtension->jChipType == SIS_315H) ||
+      (HwDeviceExtension->jChipType == SIS_315PRO)) {
+     HwDeviceExtension->pQueryVGAConfigSpace(HwDeviceExtension,0x50,0,&Temp);
      Temp >>= 20;
      Temp &= 0xF;
-     if (Temp!=1) {
-     	SiS_SetReg1(SiS_P3c4,0x25,SiS_SR25[1]);
-     	SiS_SetReg1(SiS_P3d4,0x49,SiS_CR49[1]);
+     if (Temp != 1) {
+     	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x25,SiS_Pr->SiS_SR25[1]);
+     	SiS_SetReg1(SiS_Pr->SiS_P3d4,0x49,SiS_Pr->SiS_CR49[1]);
      }
 
-     SiS_SetReg1(SiS_P3c4,0x27,0x1F);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x27,0x1F);
 
-     SiS_SetReg1(SiS_P3c4,0x31,*pSiS_SR31);
-     SiS_SetReg1(SiS_P3c4,0x32,*pSiS_SR32);
-     SiS_SetReg1(SiS_P3c4,0x33,*pSiS_SR33);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,*SiS_Pr->pSiS_SR31);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x32,*SiS_Pr->pSiS_SR32);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x33,*SiS_Pr->pSiS_SR33);
    }
 #endif
 
-   if (SiS_BridgeIsOn(BaseAddr)==1) {
-     	if(SiS_IF_DEF_LVDS==0) {
-       		SiS_SetReg1(SiS_Part2Port,0x00,0x1C);
-       		SiS_SetReg1(SiS_Part4Port,0x0D,*pSiS_CRT2Data_4_D);
-       		SiS_SetReg1(SiS_Part4Port,0x0E,*pSiS_CRT2Data_4_E);
-       		SiS_SetReg1(SiS_Part4Port,0x10,*pSiS_CRT2Data_4_10);
-       		SiS_SetReg1(SiS_Part4Port,0x0F,0x3F);
+   if (SiS_BridgeIsOn(SiS_Pr, BaseAddr) == 0) {
+     	if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+       		SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x00,0x1C);
+       		SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0D,*SiS_Pr->pSiS_CRT2Data_4_D);
+       		SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0E,*SiS_Pr->pSiS_CRT2Data_4_E);
+       		SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x10,*SiS_Pr->pSiS_CRT2Data_4_10);
+       		SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x0F,0x3F);
      	}
-     	SiS_LockCRT2(HwDeviceExtension, BaseAddr);
+     	SiS_LockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
    }
-   SiS_SetReg1(SiS_P3d4,0x83,0x00);
-/*   SetDefExt1Regs end */
+   SiS_SetReg1(SiS_Pr->SiS_P3d4,0x83,0x00);
 
 #ifdef SIS315H
-   if ((HwDeviceExtension->jChipType==SIS_315H)||
-       (HwDeviceExtension->jChipType==SIS_315PRO)) { /* 05/02/01 ynlai */
+   if ((HwDeviceExtension->jChipType==SIS_315H) ||
+       (HwDeviceExtension->jChipType==SIS_315PRO)) {
        	if (HwDeviceExtension->bSkipDramSizing==TRUE) {
-         	SiS_SetDRAMModeRegister(ROMAddr);
+         	SiS_SetDRAMModeRegister(SiS_Pr, ROMAddr,HwDeviceExtension);
          	pSR = HwDeviceExtension->pSR;
          	if (pSR!=NULL) {
            		while (pSR->jIdx!=0xFF) {
-             			SiS_SetReg1(SiS_P3c4,pSR->jIdx,pSR->jVal);
+             			SiS_SetReg1(SiS_Pr->SiS_P3c4,pSR->jIdx,pSR->jVal);
              			pSR++;
            		}
          	}
-       } else SiS_SetDRAMSize_310(HwDeviceExtension);
+       } else SiS_SetDRAMSize_310(SiS_Pr, HwDeviceExtension);
    }
 #endif
 
 #ifdef SIS315H
-   if((HwDeviceExtension->jChipType==SIS_550)){ /* 05/02/01 ynlai For SiS 550 */
+   if((HwDeviceExtension->jChipType==SIS_550)){
        /* SetDRAMConfig begin */
-/*     SiS_SetReg1(SiS_P3c4,0x12,SR12);
-       SiS_SetReg1(SiS_P3c4,0x13,SR13);
-       SiS_SetReg1(SiS_P3c4,0x14,SR14);
-       SiS_SetReg1(SiS_P3c4,0x16,SR16);
-       SiS_SetReg1(SiS_P3c4,0x17,SR17);
-       SiS_SetReg1(SiS_P3c4,0x18,SR18);
-       SiS_SetReg1(SiS_P3c4,0x19,SR19);
-       SiS_SetReg1(SiS_P3c4,0x1A,SR1A);   */
+/*     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x12,SR12);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,SR13);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,SR14);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,SR16);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x17,SR17);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x18,SR18);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x19,SR19);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1A,SR1A);   */
        /* SetDRAMConfig end */
    }
 #endif
 
 #ifdef SIS300
-   if( HwDeviceExtension->jChipType==SIS_300) {       /* For SiS 300 Chip  */
-       	if (HwDeviceExtension->bSkipDramSizing==TRUE) {
-/*       	SiS_SetDRAMModeRegister(ROMAddr);
+   if(HwDeviceExtension->jChipType == SIS_300) {
+       	if (HwDeviceExtension->bSkipDramSizing == TRUE) {
+/*       	SiS_SetDRAMModeRegister(ROMAddr,HwDeviceExtension);
          	temp = (HwDeviceExtension->pSR)->jVal;
-         	SiS_SetReg1(SiS_P3c4,0x13,temp);
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,temp);
          	temp = (HwDeviceExtension->pSR)->jVal;
-         	SiS_SetReg1(SiS_P3c4,0x14,temp);   */
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,temp);   */
        } else {
 #ifdef TC
-         	SiS_SetReg1(SiS_P3c4,0x13,SR13);
-         	SiS_SetReg1(SiS_P3c4,0x14,SR14);
-         	SiS_SetRegANDOR(SiS_P3c4,0x15,0xFF,0x04);
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,SR13);
+         	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,SR14);
+         	SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x15,0xFF,0x04);
 #else
-         	SiS_SetDRAMSize_300(HwDeviceExtension);
-         	SiS_SetDRAMSize_300(HwDeviceExtension);
+         	SiS_SetDRAMSize_300(SiS_Pr, HwDeviceExtension);
+         	SiS_SetDRAMSize_300(SiS_Pr, HwDeviceExtension);
 #endif
        }
    }
-   if((HwDeviceExtension->jChipType==SIS_540)||       /* For SiS 630/540/730 Chip  */
+   if((HwDeviceExtension->jChipType==SIS_540)||
       (HwDeviceExtension->jChipType==SIS_630)||
-      (HwDeviceExtension->jChipType==SIS_730)){
-       	/* SetDRAMConfig begin */
+      (HwDeviceExtension->jChipType==SIS_730)) {
 #if 0
-     	SiS_SetReg1(SiS_P3c4,0x12,SR12);
-       	SiS_SetReg1(SiS_P3c4,0x13,SR13);
-       	SiS_SetReg1(SiS_P3c4,0x14,SR14);
-       	SiS_SetReg1(SiS_P3c4,0x16,SR16);
-       	SiS_SetReg1(SiS_P3c4,0x17,SR17);
-       	SiS_SetReg1(SiS_P3c4,0x18,SR18);
-       	SiS_SetReg1(SiS_P3c4,0x19,SR19);
-       	SiS_SetReg1(SiS_P3c4,0x1A,SR1A);
+     	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x12,SR12);
+       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,SR13);
+       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,SR14);
+       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,SR16);
+       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x17,SR17);
+       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x18,SR18);
+       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x19,SR19);
+       	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1A,SR1A);
 #endif
-       	/* SetDRAMConfig end */
    }
 /* SetDRAMSize end */
 #endif /* SIS300 */
 
-/*   SetDefExt2Regs begin  */
+   /* Set default Ext2Regs */
 #if 0
    AGP=1;
-   temp=(UCHAR)SiS_GetReg1(SiS_P3c4,0x3A);
-   temp=temp&0x30;
-   if(temp==0x30) AGP=0;
-   if(AGP==0) *pSiS_SR21=*pSiS_SR21&0xEF;
-   SiS_SetReg1(SiS_P3c4,0x21,*pSiS_SR21);
-   if(AGP==1) *pSiS_SR22=*pSiS_SR22&0x20;
-   SiS_SetReg1(SiS_P3c4,0x22,*pSiS_SR22);
-#endif
-   SiS_SetReg1(SiS_P3c4,0x21,*pSiS_SR21);
-   SiS_SetReg1(SiS_P3c4,0x22,*pSiS_SR22);
-/*   SetDefExt2Regs end  */
+   temp=(UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3A);
+   temp &= 0x30;
+   if(temp == 0x30) AGP=0;
+   if(AGP == 0) *SiS_Pr->pSiS_SR21 &= 0xEF;
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x21,*SiS_Pr->pSiS_SR21);
+   if(AGP == 1) *SiS_Pr->pSiS_SR22 &= 0x20;
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x22,*SiS_Pr->pSiS_SR22);
+#endif
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x21,*SiS_Pr->pSiS_SR21);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x22,*SiS_Pr->pSiS_SR22);
 
 #if 0
-   SiS_SetReg3(SiS_P3c6,0xff);
-   SiS_ClearDAC(SiS_P3c8);        /* [ynlai] 05/22/01 */
+   SiS_SetReg3(SiS_Pr->SiS_P3c6,0xff);
+   SiS_ClearDAC(SiS_Pr, SiS_Pr->SiS_P3c8);
 #endif
 
-   SiS_DetectMonitor(HwDeviceExtension,BaseAddr);
-   SiS_GetSenseStatus(HwDeviceExtension,ROMAddr);      /* sense CRT2 */
+#ifdef LINUXBIOS   /* TW: This is not needed for our purposes */
+   SiS_DetectMonitor(SiS_Pr, HwDeviceExtension,BaseAddr);    /* Sense CRT1 */
+   SiS_GetSenseStatus(SiS_Pr, HwDeviceExtension,ROMAddr);    /* Sense CRT2 */
+#endif
 
    return(TRUE);
 }
 
 void
-SiS_Set_LVDS_TRUMPION(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_Set_LVDS_TRUMPION(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT temp=0;
+  USHORT temp = 0;
 
 #ifdef SiS300
-  if ((HwDeviceExtension->jChipType == SIS_540)||
-      (HwDeviceExtension->jChipType == SIS_630)||
-      (HwDeviceExtension->jChipType == SIS_730)) {
+  if((HwDeviceExtension->jChipType == SIS_540) ||
+     (HwDeviceExtension->jChipType == SIS_630) ||
+     (HwDeviceExtension->jChipType == SIS_730)) {
         /* TW: Read POWER_ON_TRAP and copy to CR37 */
-    	temp = (UCHAR)SiS_GetReg1(SiS_P3c4,0x1A);
-    	temp=(temp&0xE0)>>4;
-   	SiS_SetRegANDOR(SiS_P3d4,0x37,0xF1,temp);
-   }
+    	temp = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1A);
+    	temp = (temp & 0xE0) >> 4;
+   	SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,0xF1,temp);
+  }
+#endif
+#ifdef SIS315H
+  if((HwDeviceExtension->jChipType == SIS_640) ||
+     (HwDeviceExtension->jChipType == SIS_740) ||
+     (HwDeviceExtension->jChipType == SIS_650)) {
+#if 0 /* TW: This is not required */
+        /* TW: Read POWER_ON_TRAP and copy to CR37 */
+    	temp = (UCHAR)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1A);
+    	temp = (temp & 0xE0) >> 4;
+   	SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,0xF1,temp);
+#endif
+  }
 #endif
 
-   /* Set globals SiS_IF_DEF... */
-   SiSSetLVDSetc(HwDeviceExtension, 0);
+   SiSSetLVDSetc(SiS_Pr, HwDeviceExtension, 0);
 }
 
-/* ===============  for 300 dram sizing begin  =============== */
+/* ===============  SiS 300 dram sizing begin  =============== */
 #ifdef SIS300
 void
-SiS_SetDRAMSize_300(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_SetDRAMSize_300(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-   /*ULONG   ROMAddr  = (ULONG)HwDeviceExtension->pjVirtualRomBase;*/
-   ULONG   FBAddr   = (ULONG)HwDeviceExtension->pjVideoMemoryAddress;
-   /*USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;*/
-   USHORT  SR13,SR14=0,buswidth,Done;
-   SHORT   i,j,k;
+   ULONG   FBAddr = (ULONG)HwDeviceExtension->pjVideoMemoryAddress;
+   USHORT  SR13, SR14=0, buswidth, Done;
+   SHORT   i, j, k;
    USHORT  data, TotalCapacity, PhysicalAdrOtherPage=0;
    ULONG   Addr;
    UCHAR   temp;
-
-   int PseudoRankCapacity,PseudoTotalCapacity,PseudoAdrPinCount;
-   int RankCapacity,AdrPinCount,BankNumHigh,BankNumMid,MB2Bank;
-   /*int PageCapacity,PhysicalAdrHigh,PhysicalAdrHalfPage,PhysicalAdrAnotherPage;*/
-   int PageCapacity,PhysicalAdrHigh,PhysicalAdrHalfPage;
-
-   SiSSetMode(HwDeviceExtension,0x2e);
-
-   data=SiS_GetReg1(SiS_P3c4,0x1);
-   data=data|0x20;
-   SiS_SetReg1(SiS_P3c4,0x01,data);                    /* Turn OFF Display  */
-
-   SiS_SetReg1(SiS_P3c4,0x13,0x00);
-   SiS_SetReg1(SiS_P3c4,0x14,0xBF);
-   buswidth=SiS_ChkBUSWidth_300(FBAddr);
-
-   MB2Bank=16;
-   Done=0;
-   for(i=6;i>=0;i--) {
-      if(Done==1) break;
-      PseudoRankCapacity=1<<i;
-      for(j=4;j>=1;j--) {
-         if(Done==1) break;
-         PseudoTotalCapacity=PseudoRankCapacity*j;
-         PseudoAdrPinCount=15-j;
+   int     PseudoRankCapacity, PseudoTotalCapacity, PseudoAdrPinCount;
+   int     RankCapacity, AdrPinCount, BankNumHigh, BankNumMid, MB2Bank;
+   int     PageCapacity, PhysicalAdrHigh, PhysicalAdrHalfPage;
+
+   SiSSetMode(SiS_Pr, HwDeviceExtension, 0x2e);
+
+   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x20);        /* Turn OFF Display  */
+
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,0x00);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,0xBF);
+
+   buswidth = SiS_ChkBUSWidth_300(SiS_Pr, FBAddr);
+
+   MB2Bank = 16;
+   Done = 0;
+   for(i=6; i>=0; i--) {
+      if(Done == 1) break;
+      PseudoRankCapacity = 1 << i;
+      for(j=4; j>=1; j--) {
+         if(Done == 1) break;
+         PseudoTotalCapacity = PseudoRankCapacity * j;
+         PseudoAdrPinCount = 15 - j;
          if(PseudoTotalCapacity <= 64) {
-            for(k=0;k<=16;k++) {
-               if(Done==1) break;
-               RankCapacity=buswidth*SiS_DRAMType[k][3];
-               AdrPinCount=SiS_DRAMType[k][2]+SiS_DRAMType[k][0];
-               if(RankCapacity==PseudoRankCapacity)
-                 if(AdrPinCount<=PseudoAdrPinCount) {
-                    if(j==3) {             /* Rank No */
-                       BankNumHigh=RankCapacity*MB2Bank*3-1;
-                       BankNumMid=RankCapacity*MB2Bank*1-1;
+            for(k=0; k<=16; k++) {
+               if(Done == 1) break;
+               RankCapacity = buswidth * SiS_DRAMType[k][3];
+               AdrPinCount = SiS_DRAMType[k][2] + SiS_DRAMType[k][0];
+               if(RankCapacity == PseudoRankCapacity)
+                 if(AdrPinCount <= PseudoAdrPinCount) {
+                    if(j == 3) {             /* Rank No */
+                       BankNumHigh = RankCapacity * MB2Bank * 3 - 1;
+                       BankNumMid = RankCapacity * MB2Bank * 1 - 1;
+                    } else {
+                       BankNumHigh = RankCapacity * MB2Bank * j - 1;
+                       BankNumMid = RankCapacity * MB2Bank * j / 2 - 1;
                     }
-                    else {
-                       BankNumHigh=RankCapacity*MB2Bank*j-1;
-                       BankNumMid=RankCapacity*MB2Bank*j/2-1;
-                    }
-                    PageCapacity=(1<<SiS_DRAMType[k][1])*buswidth*4;
-                    PhysicalAdrHigh =BankNumHigh;
-                    PhysicalAdrHalfPage=(PageCapacity/2+PhysicalAdrHigh)%PageCapacity;
-                    PhysicalAdrOtherPage=PageCapacity*SiS_DRAMType[k][2]+PhysicalAdrHigh;
+                    PageCapacity = (1 << SiS_DRAMType[k][1]) * buswidth * 4;
+                    PhysicalAdrHigh = BankNumHigh;
+                    PhysicalAdrHalfPage = (PageCapacity / 2 + PhysicalAdrHigh) % PageCapacity;
+                    PhysicalAdrOtherPage = PageCapacity * SiS_DRAMType[k][2] + PhysicalAdrHigh;
                     /* Write data */
-                    /*Test */
-                    temp=(UCHAR)SiS_GetReg1(SiS_P3c4,0x15);
-                    SiS_SetReg1(SiS_P3c4,0x15,(USHORT)(temp&0xFB));
-
-                    temp=(UCHAR)SiS_GetReg1(SiS_P3c4,0x15);
-                    SiS_SetReg1(SiS_P3c4,0x15,(USHORT)(temp|0x04));
-                    /*Test */
-                    TotalCapacity=SiS_DRAMType[k][3]*buswidth;
-                    SR13=SiS_DRAMType[k][4];
-                    if(buswidth==4) SR14=(TotalCapacity-1)|0x80;
-                    if(buswidth==2) SR14=(TotalCapacity-1)|0x40;
-                    if(buswidth==1) SR14=(TotalCapacity-1)|0x00;
-                    SiS_SetReg1(SiS_P3c4,0x13,SR13);
-                    SiS_SetReg1(SiS_P3c4,0x14,SR14);
-
-                    Addr=FBAddr+(BankNumHigh)*64*1024+PhysicalAdrHigh;
-                    *((USHORT *)(Addr)) = (USHORT) PhysicalAdrHigh;
-                    Addr=FBAddr+(BankNumMid)*64*1024+PhysicalAdrHigh;
-                    *((USHORT *)(Addr)) = (USHORT) BankNumMid;
-                    Addr=FBAddr+(BankNumHigh)*64*1024+PhysicalAdrHalfPage;
-                    *((USHORT *)(Addr)) = (USHORT) PhysicalAdrHalfPage;
-                    Addr=FBAddr+(BankNumHigh)*64*1024+PhysicalAdrOtherPage;
-                    *((USHORT *)(Addr))=PhysicalAdrOtherPage;
+                    /*Test*/
+                    SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x15,0xFB);
+                    SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x15,0x04);
+                    /*/Test*/
+                    TotalCapacity = SiS_DRAMType[k][3] * buswidth;
+                    SR13 = SiS_DRAMType[k][4];
+                    if(buswidth == 4) SR14 = (TotalCapacity - 1) | 0x80;
+                    if(buswidth == 2) SR14 = (TotalCapacity - 1) | 0x40;
+                    if(buswidth == 1) SR14 = (TotalCapacity - 1) | 0x00;
+                    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,SR13);
+                    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,SR14);
+
+                    Addr = FBAddr + (BankNumHigh) * 64 * 1024 + PhysicalAdrHigh;
+                    *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHigh;
+                    Addr = FBAddr + (BankNumMid) * 64 * 1024 + PhysicalAdrHigh;
+                    *((USHORT *)(Addr)) = (USHORT)BankNumMid;
+                    Addr = FBAddr + (BankNumHigh) * 64 * 1024 + PhysicalAdrHalfPage;
+                    *((USHORT *)(Addr)) = (USHORT)PhysicalAdrHalfPage;
+                    Addr = FBAddr + (BankNumHigh) * 64 * 1024 + PhysicalAdrOtherPage;
+                    *((USHORT *)(Addr)) = PhysicalAdrOtherPage;
 
                     /* Read data */
-                    Addr=FBAddr+(BankNumHigh)*64*1024+PhysicalAdrHigh;
-                    data=*((USHORT *)(Addr));
-                    if(data==PhysicalAdrHigh) Done=1;
+                    Addr = FBAddr + (BankNumHigh) * 64 * 1024 + PhysicalAdrHigh;
+                    data = *((USHORT *)(Addr));
+                    if(data == PhysicalAdrHigh) Done = 1;
                  }  /* if struct */
             }  /* for loop (k) */
          }  /* if struct */
@@ -1041,168 +1216,149 @@
 }
 
 USHORT
-SiS_ChkBUSWidth_300(ULONG FBAddress)
+SiS_ChkBUSWidth_300(SiS_Private *SiS_Pr, ULONG FBAddress)
 {
-   /*USHORT  data;*/
    PULONG  pVideoMemory;
 
-   pVideoMemory = (PULONG) FBAddress;
+   pVideoMemory = (PULONG)FBAddress;
 
    pVideoMemory[0] = 0x01234567L;
    pVideoMemory[1] = 0x456789ABL;
    pVideoMemory[2] = 0x89ABCDEFL;
    pVideoMemory[3] = 0xCDEF0123L;
-   if (pVideoMemory[3]==0xCDEF0123L) { /*ChannelA128Bit */
+   if (pVideoMemory[3]==0xCDEF0123L) {  /* Channel A 128bit */
      return(4);
    }
-   if (pVideoMemory[1]==0x456789ABL) {  /*ChannelB64Bit */
+   if (pVideoMemory[1]==0x456789ABL) {  /* Channel B 64bit */
      return(2);
    }
    return(1);
 }
 #endif
+/* ===============  SiS 300 dram sizing end    =============== */
 
-/* ===============  for 300 dram sizing end    =============== */
-
-/* ===============  310 dram sizing begin ==================== */
+/* ============  SiS 310/325 dram sizing begin  ============== */
 #ifdef SIS315H
 
 /* TW: Moved Get310DRAMType further down */
 
 void
-SiS_Delay15us(ULONG ulMicrsoSec)
+SiS_Delay15us(SiS_Private *SiS_Pr, ULONG ulMicrsoSec)
 {
 }
 
 void
-SiS_SDR_MRS(void)
+SiS_SDR_MRS(SiS_Private *SiS_Pr, )
 {
    USHORT  data;
 
-   data=SiS_GetReg1(SiS_P3c4,0x16);
-   data=data & 0x3F;          /*/ SR16 D7=0,D6=0 */
-   SiS_SetReg1(SiS_P3c4,0x16,data);   /*/ enable mode register set(MRS) low */
-   SiS_Delay15us(0x100);
-   data=data | 0x80;          /*/ SR16 D7=1,D6=0 */
-   SiS_SetReg1(SiS_P3c4,0x16,data);   /*/ enable mode register set(MRS) high */
-   SiS_Delay15us(0x100);
+   data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
+   data &= 0x3F;          		        /* SR16 D7=0, D6=0 */
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,data);   	/* enable mode register set(MRS) low */
+   SiS_Delay15us(SiS_Pr, 0x100);
+   data |= 0x80;          		        /* SR16 D7=1, D6=0 */
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,data);   	/* enable mode register set(MRS) high */
+   SiS_Delay15us(SiS_Pr, 0x100);
 }
 
 void
-SiS_DDR_MRS(void)
+SiS_DDR_MRS(SiS_Private *SiS_Pr)
 {
    USHORT  data;
 
    /* SR16 <- 1F,DF,2F,AF */
 
    /* enable DLL of DDR SD/SGRAM , SR16 D4=1 */
-   data=SiS_GetReg1(SiS_P3c4,0x16);
+   data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
    data &= 0x0F;
    data |= 0x10;
-   SiS_SetReg1(SiS_P3c4,0x16,data);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,data);
 
-   if (!(SiS_SR15[1][SiS_RAMType] & 0x10))
-   {
+   if (!(SiS_Pr->SiS_SR15[1][SiS_Pr->SiS_RAMType] & 0x10))
      data &= 0x0F;
-   }
+
    /* SR16 D7=1,D6=1 */
    data |= 0xC0;
-   SiS_SetReg1(SiS_P3c4,0x16,data);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,data);
    
    /* SR16 D7=1,D6=0,D5=1,D4=0 */
    data &= 0x0F;
    data |= 0x20;
-   SiS_SetReg1(SiS_P3c4,0x16,data);
-   if (!(SiS_SR15[1][SiS_RAMType] & 0x10)) {
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,data);
+   if (!(SiS_Pr->SiS_SR15[1][SiS_Pr->SiS_RAMType] & 0x10))
      data &= 0x0F;
-   }
+
    /* SR16 D7=1 */
    data |= 0x80;
-   SiS_SetReg1(SiS_P3c4,0x16,data);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,data);
 }
 
 void
-SiS_SetDRAMModeRegister(ULONG ROMAddr)
+SiS_SetDRAMModeRegister(SiS_Private *SiS_Pr, UCHAR *ROMAddr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-
-    if (SiS_Get310DRAMType(ROMAddr)<2) {
-      SiS_SDR_MRS();
-    } else {
-      /* SR16 <- 0F,CF,0F,8F */
-      SiS_DDR_MRS();
-    }
+    if (SiS_Get310DRAMType(ROMAddr,HwDeviceExtension) < 2)
+        SiS_SDR_MRS(SiS_Pr);
+    else
+        /* SR16 <- 0F,CF,0F,8F */
+        SiS_DDR_MRS(SiS_Pr);
 }
 
 void
-SiS_DisableRefresh(void)
+SiS_DisableRefresh(SiS_Private *SiS_Pr)
 {
-   USHORT  data;
-
-   data=SiS_GetReg1(SiS_P3c4,0x17);
-   data &= 0xF8;
-   SiS_SetReg1(SiS_P3c4,0x17,data);
-
-   data=SiS_GetReg1(SiS_P3c4,0x19);
-   data |= 0x03;
-   SiS_SetReg1(SiS_P3c4,0x19,data);
-
+   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x17,0xF8);
+   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x19,0x03);
 }
 
 void
-SiS_EnableRefresh(ULONG ROMAddr)
+SiS_EnableRefresh(SiS_Private *SiS_Pr, UCHAR *ROMAddr)
 {
-   SiS_SetReg1(SiS_P3c4,0x17,SiS_SR15[2][SiS_RAMType]);  /* SR17 */
-   SiS_SetReg1(SiS_P3c4,0x19,SiS_SR15[4][SiS_RAMType]);  /* SR19 */
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x17,SiS_Pr->SiS_SR15[2][SiS_Pr->SiS_RAMType]);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x19,SiS_Pr->SiS_SR15[4][SiS_Pr->SiS_RAMType]);
 }
 
 void
-SiS_DisableChannelInterleaving(int index,USHORT SiS_DDRDRAM_TYPE[][5])
+SiS_DisableChannelInterleaving(SiS_Private *SiS_Pr, int index,
+                               USHORT SiS_DDRDRAM_TYPE[][5])
 {
    USHORT  data;
 
-   data=SiS_GetReg1(SiS_P3c4,0x15);
+   data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x15);
    data &= 0x1F;
    switch (SiS_DDRDRAM_TYPE[index][3])
    {
-     case 64: data |= 0;
-              break;
-     case 32: data |= 0x20;
-              break;
-     case 16: data |= 0x40;
-              break;
-     case 4:  data |= 0x60;
-              break;
+     case 64: data |= 0; 	break;
+     case 32: data |= 0x20;	break;
+     case 16: data |= 0x40;     break;
+     case 4:  data |= 0x60;     break;
    }
-   SiS_SetReg1(SiS_P3c4,0x15,data);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x15,data);
 }
 
 void
-SiS_SetDRAMSizingType(int index,USHORT DRAMTYPE_TABLE[][5])
+SiS_SetDRAMSizingType(SiS_Private *SiS_Pr, int index, USHORT DRAMTYPE_TABLE[][5])
 {
-   USHORT  data;
-
-   data = DRAMTYPE_TABLE[index][4];
-   SiS_SetReg1(SiS_P3c4,0x13,data);
-
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,DRAMTYPE_TABLE[index][4]);
    /* should delay 50 ns */
 }
 
 void
-SiS_CheckBusWidth_310(ULONG ROMAddress,ULONG FBAddress)
+SiS_CheckBusWidth_310(SiS_Private *SiS_Pr, UCHAR *ROMAddress,ULONG FBAddress,
+                      PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
    USHORT  data;
    PULONG volatile pVideoMemory;
 
-   pVideoMemory = (PULONG) FBAddress;
-   if (SiS_Get310DRAMType(ROMAddress)<2) {
+   pVideoMemory = (PULONG)FBAddress;
+   if(SiS_Get310DRAMType(ROMAddress,HwDeviceExtension) < 2) {
 
-     SiS_SetReg1(SiS_P3c4,0x13,0x00);
-     SiS_SetReg1(SiS_P3c4,0x14,0x12);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,0x00);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,0x12);
      /* should delay */
-     SiS_SDR_MRS();
+     SiS_SDR_MRS(SiS_Pr);
 
-     SiS_ChannelAB = 0;
-     SiS_DataBusWidth = 128;
+     SiS_Pr->SiS_ChannelAB = 0;
+     SiS_Pr->SiS_DataBusWidth = 128;
      pVideoMemory[0] = 0x01234567L;
      pVideoMemory[1] = 0x456789ABL;
      pVideoMemory[2] = 0x89ABCDEFL;
@@ -1212,31 +1368,31 @@
      pVideoMemory[6] = 0xFFFFFFFFL;
      pVideoMemory[7] = 0xFFFFFFFFL;
      if ((pVideoMemory[3]!=0xCDEF0123L) || (pVideoMemory[2] != 0x89ABCDEFL)) {
-       /*ChannelA64Bit */
-       SiS_DataBusWidth = 64;
-       SiS_ChannelAB = 0;
-       data=SiS_GetReg1(SiS_P3c4,0x14);
-       SiS_SetReg1(SiS_P3c4,  0x14, (USHORT) (data & 0xFD));
+       /*Channel A 64Bit */
+       SiS_Pr->SiS_DataBusWidth = 64;
+       SiS_Pr->SiS_ChannelAB = 0;
+       data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,(USHORT)(data & 0xFD));
      }
 
      if ((pVideoMemory[1]!=0x456789ABL) || (pVideoMemory[0] != 0x01234567L)) {
-       /*ChannelB64Bit */
-       SiS_DataBusWidth = 64;
-       SiS_ChannelAB = 1;
-       data=SiS_GetReg1(SiS_P3c4,0x14);
-       SiS_SetReg1(SiS_P3c4,0x14,(USHORT)((data&0xFD)|0x01));
+       /*Channel B 64Bit */
+       SiS_Pr->SiS_DataBusWidth = 64;
+       SiS_Pr->SiS_ChannelAB = 1;
+       data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,(USHORT)((data&0xFD)|0x01));
      }
      return;
 
    } else {
      /* DDR Dual channel */
-     SiS_SetReg1(SiS_P3c4,0x13,0x00);
-     SiS_SetReg1(SiS_P3c4,0x14,0x02); /* Channel A, 64bit */
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x13,0x00);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,0x02); /* Channel A, 64bit */
      /* should delay */
-     SiS_DDR_MRS();
+     SiS_DDR_MRS(SiS_Pr);
 
-     SiS_ChannelAB = 0;
-     SiS_DataBusWidth = 64;
+     SiS_Pr->SiS_ChannelAB = 0;
+     SiS_Pr->SiS_DataBusWidth = 64;
      pVideoMemory[0] = 0x01234567L;
      pVideoMemory[1] = 0x456789ABL;
      pVideoMemory[2] = 0x89ABCDEFL;
@@ -1254,17 +1410,17 @@
      } else {
        if (pVideoMemory[0] == 0x01234567L) {
          /* Channel A 32bit */
-         SiS_DataBusWidth = 32;
-         SiS_SetReg1(SiS_P3c4,0x14,0x00);
+         SiS_Pr->SiS_DataBusWidth = 32;
+         SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,0x00);
          return;
        }
      }
 
-     SiS_SetReg1(SiS_P3c4,0x14,0x03); /* Channel B, 64bit */
-     SiS_DDR_MRS();
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,0x03); /* Channel B, 64bit */
+     SiS_DDR_MRS(SiS_Pr);
 
-     SiS_ChannelAB = 1;
-     SiS_DataBusWidth = 64;
+     SiS_Pr->SiS_ChannelAB = 1;
+     SiS_Pr->SiS_DataBusWidth = 64;
      pVideoMemory[0] = 0x01234567L;
      pVideoMemory[1] = 0x456789ABL;
      pVideoMemory[2] = 0x89ABCDEFL;
@@ -1284,8 +1440,8 @@
      } else {
        if (pVideoMemory[0] == 0x01234567L) {
          /* Channel B 32 */
-         SiS_DataBusWidth = 32;
-         SiS_SetReg1(SiS_P3c4,0x14,0x01);
+         SiS_Pr->SiS_DataBusWidth = 32;
+         SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,0x01);
        } else {
          /* error */
        }
@@ -1294,7 +1450,7 @@
 }
 
 int
-SiS_SetRank(int index,UCHAR RankNo,UCHAR SiS_ChannelAB,USHORT DRAMTYPE_TABLE[][5])
+SiS_SetRank(SiS_Private *SiS_Pr, int index,UCHAR RankNo,USHORT DRAMTYPE_TABLE[][5])
 {
   USHORT  data;
   int RankSize;
@@ -1302,68 +1458,66 @@
   if ((RankNo==2)&&(DRAMTYPE_TABLE[index][0]==2))
          return 0;
 
-  RankSize = DRAMTYPE_TABLE[index][3]/2 * SiS_DataBusWidth/32;
+  RankSize = DRAMTYPE_TABLE[index][3]/2 * SiS_Pr->SiS_DataBusWidth / 32;
 
-  if (RankNo*RankSize<=128) {
+  if (RankNo * RankSize <= 128) {
     data = 0;
-    while ((RankSize>>=1)>0) {
-      data+=0x10;
+    while((RankSize >>= 1) > 0) {
+      data += 0x10;
     }
-    data |= (RankNo-1)<<2;
-    data |= (SiS_DataBusWidth/64)&2;
-    data |= SiS_ChannelAB;
-    SiS_SetReg1(SiS_P3c4,0x14,data);
+    data |= (RankNo - 1) << 2;
+    data |= (SiS_Pr->SiS_DataBusWidth / 64) & 2;
+    data |= SiS_Pr->SiS_ChannelAB;
+    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,data);
     /* should delay */
-    SiS_SDR_MRS();
+    SiS_SDR_MRS(SiS_Pr);
     return 1;
   } else
     return 0;
 }
 
 int
-SiS_SetDDRChannel(int index,UCHAR ChannelNo,UCHAR SiS_ChannelAB,
+SiS_SetDDRChannel(SiS_Private *SiS_Pr, int index,UCHAR ChannelNo,
                   USHORT DRAMTYPE_TABLE[][5])
 {
   USHORT  data;
   int RankSize;
 
-  RankSize = DRAMTYPE_TABLE[index][3]/2 * SiS_DataBusWidth/32;
+  RankSize = DRAMTYPE_TABLE[index][3]/2 * SiS_Pr->SiS_DataBusWidth / 32;
   /* RankSize = DRAMTYPE_TABLE[index][3]; */
-  if (ChannelNo*RankSize<=128) {
+  if (ChannelNo * RankSize <= 128) {
     data = 0;
-    while ((RankSize>>=1)>0) {
-      data+=0x10;
+    while((RankSize >>= 1) > 0) {
+      data += 0x10;
     }
-    if (ChannelNo==2)
-      data |= 0x0C;
-
-    data |= (SiS_DataBusWidth/32)&2;
-    data |= SiS_ChannelAB;
-    SiS_SetReg1(SiS_P3c4,0x14,data);
+    if(ChannelNo == 2) data |= 0x0C;
+    data |= (SiS_Pr->SiS_DataBusWidth / 32) & 2;
+    data |= SiS_Pr->SiS_ChannelAB;
+    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,data);
     /* should delay */
-    SiS_DDR_MRS();
+    SiS_DDR_MRS(SiS_Pr);
     return 1;
   } else
     return 0;
 }
 
 int
-SiS_CheckColumn(int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
+SiS_CheckColumn(SiS_Private *SiS_Pr, int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
 {
   int i;
   ULONG Increment,Position;
 
-  /*Increment = 1<<(DRAMTYPE_TABLE[index][2] + SiS_DataBusWidth / 64 + 1); */
-  Increment = 1<<(10 + SiS_DataBusWidth / 64);
+  /*Increment = 1<<(DRAMTYPE_TABLE[index][2] + SiS_Pr->SiS_DataBusWidth / 64 + 1); */
+  Increment = 1 << (10 + SiS_Pr->SiS_DataBusWidth / 64);
 
   for (i=0,Position=0;i<2;i++) {
-         *((PULONG)(FBAddress+Position))=Position;
+         *((PULONG)(FBAddress + Position)) = Position;
          Position += Increment;
   }
 
   for (i=0,Position=0;i<2;i++) {
 /*    if (FBAddress[Position]!=Position) */
-         if ( (*(PULONG) (FBAddress + Position)) !=Position)
+         if((*(PULONG)(FBAddress + Position)) != Position)
                 return 0;
          Position += Increment;
   }
@@ -1371,21 +1525,21 @@
 }
 
 int
-SiS_CheckBanks(int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
+SiS_CheckBanks(SiS_Private *SiS_Pr, int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
 {
   int i;
   ULONG Increment,Position;
-  Increment = 1<<(DRAMTYPE_TABLE[index][2] + SiS_DataBusWidth / 64 + 2);
+  Increment = 1 << (DRAMTYPE_TABLE[index][2] + SiS_Pr->SiS_DataBusWidth / 64 + 2);
 
   for (i=0,Position=0;i<4;i++) {
 /*    FBAddress[Position]=Position; */
-    *((PULONG)(FBAddress+Position))=Position;
+    *((PULONG)(FBAddress + Position)) = Position;
     Position += Increment;
   }
 
   for (i=0,Position=0;i<4;i++) {
 /*    if (FBAddress[Position]!=Position) */
-    if ( (*(PULONG) (FBAddress + Position)) !=Position)
+    if((*(PULONG)(FBAddress + Position)) != Position)
       return 0;
     Position += Increment;
   }
@@ -1393,12 +1547,12 @@
 }
 
 int
-SiS_CheckRank(int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
+SiS_CheckRank(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
 {
   int i;
   ULONG Increment,Position;
   Increment = 1<<(DRAMTYPE_TABLE[index][2] + DRAMTYPE_TABLE[index][1] +
-                  DRAMTYPE_TABLE[index][0] + SiS_DataBusWidth / 64 + RankNo);
+                  DRAMTYPE_TABLE[index][0] + SiS_Pr->SiS_DataBusWidth / 64 + RankNo);
 
   for (i=0,Position=0;i<2;i++) {
 /*    FBAddress[Position]=Position; */
@@ -1418,88 +1572,91 @@
 }
 
 int
-SiS_CheckDDRRank(int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
+SiS_CheckDDRRank(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
 {
   ULONG Increment,Position;
   USHORT  data;
-  
+
   Increment = 1<<(DRAMTYPE_TABLE[index][2] + DRAMTYPE_TABLE[index][1] +
-                  DRAMTYPE_TABLE[index][0] + SiS_DataBusWidth / 64 + RankNo);
+                  DRAMTYPE_TABLE[index][0] + SiS_Pr->SiS_DataBusWidth / 64 + RankNo);
 
   Increment += Increment/2;
-  
+
   Position =0;
-  *((PULONG)(FBAddress+Position+0))=0x01234567;
-  *((PULONG)(FBAddress+Position+1))=0x456789AB;
-  *((PULONG)(FBAddress+Position+2))=0x55555555;
-  *((PULONG)(FBAddress+Position+3))=0x55555555;
-  *((PULONG)(FBAddress+Position+4))=0xAAAAAAAA;
-  *((PULONG)(FBAddress+Position+5))=0xAAAAAAAA;
+  *((PULONG)(FBAddress+Position + 0)) = 0x01234567;
+  *((PULONG)(FBAddress+Position + 1)) = 0x456789AB;
+  *((PULONG)(FBAddress+Position + 2)) = 0x55555555;
+  *((PULONG)(FBAddress+Position + 3)) = 0x55555555;
+  *((PULONG)(FBAddress+Position + 4)) = 0xAAAAAAAA;
+  *((PULONG)(FBAddress+Position + 5)) = 0xAAAAAAAA;
 
-  if ( (*(PULONG) (FBAddress + 1))==0x456789AB)
+  if ( (*(PULONG) (FBAddress + 1)) == 0x456789AB)
     return 1;
 
-  if ( (*(PULONG) (FBAddress + 0))==0x01234567)
+  if ( (*(PULONG) (FBAddress + 0)) == 0x01234567)
     return 0;
 
-  data=SiS_GetReg1(SiS_P3c4,0x14);
+  data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
   data &= 0xF3;
   data |= 0x08;
-  SiS_SetReg1(SiS_P3c4,0x14,data);
-  data=SiS_GetReg1(SiS_P3c4,0x15);
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x14,data);
+  data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x15);
   data += 0x20;
-  SiS_SetReg1(SiS_P3c4,0x15,data);
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x15,data);
 
   return 1;
 }
 
 int
-SiS_CheckRanks(int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
+SiS_CheckRanks(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
 {
   int r;
 
   for (r=RankNo;r>=1;r--) {
-    if (!SiS_CheckRank(r,index,DRAMTYPE_TABLE,FBAddress))
+    if (!SiS_CheckRank(SiS_Pr, r, index, DRAMTYPE_TABLE, FBAddress))
       return 0;
   }
-  if (!SiS_CheckBanks(index,DRAMTYPE_TABLE,FBAddress))
+  if (!SiS_CheckBanks(SiS_Pr, index, DRAMTYPE_TABLE, FBAddress))
     return 0;
 
-  if (!SiS_CheckColumn(index,DRAMTYPE_TABLE,FBAddress))
+  if (!SiS_CheckColumn(SiS_Pr, index, DRAMTYPE_TABLE, FBAddress))
     return 0;
+
   return 1;
 }
 
 int
-SiS_CheckDDRRanks(int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress)
+SiS_CheckDDRRanks(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],
+                  ULONG FBAddress)
 {
   int r;
 
   for (r=RankNo;r>=1;r--) {
-    if (!SiS_CheckDDRRank(r,index,DRAMTYPE_TABLE,FBAddress))
+    if (!SiS_CheckDDRRank(SiS_Pr, r,index,DRAMTYPE_TABLE,FBAddress))
       return 0;
   }
-  if (!SiS_CheckBanks(index,DRAMTYPE_TABLE,FBAddress))
+  if (!SiS_CheckBanks(SiS_Pr, index,DRAMTYPE_TABLE,FBAddress))
     return 0;
 
-  if (!SiS_CheckColumn(index,DRAMTYPE_TABLE,FBAddress))
+  if (!SiS_CheckColumn(SiS_Pr, index,DRAMTYPE_TABLE,FBAddress))
     return 0;
+
   return 1;
 }
 
 int
-SiS_SDRSizing(ULONG FBAddress)
+SiS_SDRSizing(SiS_Private *SiS_Pr, ULONG FBAddress)
 {
   int    i;
   UCHAR  j;
 
   for (i=0;i<13;i++) {
-    SiS_SetDRAMSizingType(i, SiS_SDRDRAM_TYPE);
+    SiS_SetDRAMSizingType(SiS_Pr, i, SiS_SDRDRAM_TYPE);
     for (j=2;j>0;j--) {
-      if (!SiS_SetRank(i,(UCHAR) j, SiS_ChannelAB,SiS_SDRDRAM_TYPE))
+      if (!SiS_SetRank(SiS_Pr, i,(UCHAR) j, SiS_SDRDRAM_TYPE))
         continue;
       else {
-        if (SiS_CheckRanks(j,i,SiS_SDRDRAM_TYPE, FBAddress))
+        if (SiS_CheckRanks(SiS_Pr, j,i,SiS_SDRDRAM_TYPE, FBAddress))
           return 1;
       }
     }
@@ -1508,21 +1665,21 @@
 }
 
 int
-SiS_DDRSizing(ULONG FBAddress)
+SiS_DDRSizing(SiS_Private *SiS_Pr, ULONG FBAddress)
 {
 
   int    i;
   UCHAR  j;
 
-  for (i=0;i<4;i++){
-    SiS_SetDRAMSizingType(i,SiS_DDRDRAM_TYPE);
-    SiS_DisableChannelInterleaving(i,SiS_DDRDRAM_TYPE);
-    for (j=2;j>0;j--) {
-      SiS_SetDDRChannel(i, j, SiS_ChannelAB, SiS_DDRDRAM_TYPE);
-      if (!SiS_SetRank(i,(UCHAR) j, SiS_ChannelAB,SiS_DDRDRAM_TYPE))
+  for (i=0; i<4; i++){
+    SiS_SetDRAMSizingType(SiS_Pr, i, SiS_DDRDRAM_TYPE);
+    SiS_DisableChannelInterleaving(SiS_Pr, i, SiS_DDRDRAM_TYPE);
+    for (j=2; j>0; j--) {
+      SiS_SetDDRChannel(SiS_Pr, i, j, SiS_DDRDRAM_TYPE);
+      if (!SiS_SetRank(SiS_Pr, i, (UCHAR) j, SiS_DDRDRAM_TYPE))
         continue;
       else {
-        if (SiS_CheckDDRRanks(j,i,SiS_DDRDRAM_TYPE, FBAddress))
+        if (SiS_CheckDDRRanks(SiS_Pr, j, i, SiS_DDRDRAM_TYPE, FBAddress))
           return 1;
       }
     }
@@ -1534,32 +1691,31 @@
  check if read cache pointer is correct
 */
 void
-SiS_VerifyMclk(ULONG FBAddr)
+SiS_VerifyMclk(SiS_Private *SiS_Pr, ULONG FBAddr)
 {
    PUCHAR  pVideoMemory = (PUCHAR) FBAddr;
-   UCHAR i,j;
-   USHORT Temp,SR21;
+   UCHAR   i, j;
+   USHORT  Temp,SR21;
 
+   pVideoMemory[0] = 0xaa;  /* alan */
+   pVideoMemory[16] = 0x55; /* note: PCI read cache is off */
 
-   pVideoMemory[0]=0xaa; /* alan */
-   pVideoMemory[16]=0x55; /* note: PCI read cache is off */
-
-   if ((pVideoMemory[0]!=0xaa)||(pVideoMemory[16]!=0x55)) {
-     for (i=0,j=16;i<2;i++,j+=16)  {
-       SR21 = SiS_GetReg1(SiS_P3c4, 0x21);
-       Temp = SR21 & 0xFB;     /* disable PCI post write buffer empty gating */
-       SiS_SetReg1(SiS_P3c4, 0x21, Temp);
-
-       Temp = SiS_GetReg1(SiS_P3c4, 0x3C);
-       Temp = Temp | 0x01;                 /*MCLK reset */
-       SiS_SetReg1(SiS_P3c4, 0x3C, Temp);
-       Temp = SiS_GetReg1(SiS_P3c4, 0x3C);
-       Temp = Temp & 0xFE;                 /* MCLK normal operation */
-       SiS_SetReg1(SiS_P3c4, 0x3C, Temp);
-       SiS_SetReg1(SiS_P3c4, 0x21, SR21);
+   if((pVideoMemory[0] != 0xaa) || (pVideoMemory[16] != 0x55)) {
+     for (i=0,j=16; i<2; i++,j+=16)  {
+       SR21 = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x21);
+       Temp = SR21 & 0xFB;           /* disable PCI post write buffer empty gating */
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x21,Temp);
+
+       Temp = SiS_GetReg1(SiS_Pr->SiS_P3c4, 0x3C);
+       Temp |= 0x01;                 /* MCLK reset */
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x3C,Temp);
+       Temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3C);
+       Temp &= 0xFE;                 /* MCLK normal operation */
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x3C,Temp);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x21,SR21);
 
        pVideoMemory[16+j] = j;
-       if (pVideoMemory[16+j]==j)  {
+       if(pVideoMemory[16+j] == j) {
          pVideoMemory[j] = j;
          break;
        }
@@ -1569,113 +1725,107 @@
 
 /* TW: Is this a 315E? */
 int
-Is315E(void)
+Is315E(SiS_Private *SiS_Pr)
 {
    USHORT  data;
-  	
-   data=SiS_GetReg1(SiS_P3d4,0x5F);
-   if (data&0x10) return 1;
+
+   data = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x5F);
+   if(data & 0x10) return 1;
    else return 0;
 }
 
 /* TW: For 315 only */
 void
-SiS_SetDRAMSize_310(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_SetDRAMSize_310(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-   ULONG   ROMAddr  = (ULONG)HwDeviceExtension->pjVirtualRomBase;
+   UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
    ULONG   FBAddr   = (ULONG)HwDeviceExtension->pjVideoMemoryAddress;
-   /*USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;*/
    USHORT  data;
 
 #ifdef SIS301	/* TW: SIS301 ??? */
-   /*SiS_SetReg1(SiS_P3d4,0x30,0x40);   */
+   /*SiS_SetReg1(SiS_Pr->SiS_P3d4,0x30,0x40);   */
 #endif
 #ifdef SIS302   /* TW: SIS302 ??? */
-   SiS_SetReg1(SiS_P3d4,0x30,0x4D);  /* alan,should change value */
-   SiS_SetReg1(SiS_P3d4,0x31,0xc0);  /* alan,should change value */
-   SiS_SetReg1(SiS_P3d4,0x34,0x3F);  /* alan,should change value */
+   SiS_SetReg1(SiS_Pr->SiS_P3d4,0x30,0x4D);  /* alan,should change value */
+   SiS_SetReg1(SiS_Pr->SiS_P3d4,0x31,0xc0);  /* alan,should change value */
+   SiS_SetReg1(SiS_Pr->SiS_P3d4,0x34,0x3F);  /* alan,should change value */
 #endif
 
-   SiSSetMode(HwDeviceExtension,0x2e);
+   SiSSetMode(SiS_Pr, HwDeviceExtension, 0x2e);
 
-   data=SiS_GetReg1(SiS_P3c4,0x21);
-   SiS_SetReg1(SiS_P3c4,0x21,(USHORT) (data&0xDF));      /* disable read cache */
+   data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x21);
+   SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x21,0xDF);                 /* disable read cache */
 
-   data=SiS_GetReg1(SiS_P3c4,0x1);
-   data=data|0x20;
-   SiS_SetReg1(SiS_P3c4,0x01,data);                    /* Turn OFF Display */
+   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x20);                  /* Turn OFF Display */
 
-   data=SiS_GetReg1(SiS_P3c4,0x16);
-   SiS_SetReg1(SiS_P3c4,0x16,(USHORT) (data|0x0F));      /* assume lowest speed DRAM */
+   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x16,0x0F);                  /* assume lowest speed DRAM */
 
-   SiS_SetDRAMModeRegister(ROMAddr);
-   SiS_DisableRefresh();
-   SiS_CheckBusWidth_310(ROMAddr,FBAddr);
+   SiS_SetDRAMModeRegister(SiS_Pr, ROMAddr, HwDeviceExtension);
+   SiS_DisableRefresh(SiS_Pr);
+   SiS_CheckBusWidth_310(SiS_Pr, ROMAddr, FBAddr, HwDeviceExtension);
 
-   SiS_VerifyMclk(FBAddr); /* alan 2000/7/3 */
+   SiS_VerifyMclk(SiS_Pr, FBAddr);
 
-   if (SiS_Get310DRAMType(ROMAddr)<2) {
-     SiS_SDRSizing(FBAddr);
-   } else {
-     SiS_DDRSizing(FBAddr);
-   }
-   
-   if (Is315E()) {
-     data=SiS_GetReg1(SiS_P3c4,0x14);
-     if ((data&0x0C)==0x0C) /* dual channel */
-     {
-     	if ((data&0xF0)>0x40)
+   if(SiS_Get310DRAMType(SiS_Pr, ROMAddr, HwDeviceExtension) < 2)
+     SiS_SDRSizing(SiS_Pr, FBAddr);
+   else
+     SiS_DDRSizing(SiS_Pr, FBAddr);
+
+   if(Is315E(SiS_Pr)) {
+     data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+     if((data & 0x0C) == 0x0C) { 	/* dual channel */
+     	if((data & 0xF0) > 0x40)
      	  data = (data & 0x0F) | 0x40;
-     } else { /* single channel */
-     	if ((data&0xF0)>0x50)
+     } else { 				/* single channel */
+     	if((data & 0xF0) > 0x50)
      	  data = (data & 0x0F) | 0x50;
      }
    }
-   
-   SiS_SetReg1(SiS_P3c4,0x16,SiS_SR15[1][SiS_RAMType]);  /* restore SR16 */
 
-   SiS_EnableRefresh(ROMAddr);
-   data=SiS_GetReg1(SiS_P3c4,0x21);
-   SiS_SetReg1(SiS_P3c4,0x21,(USHORT) (data|0x20));      /* enable read cache */
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x16,SiS_Pr->SiS_SR15[1][SiS_Pr->SiS_RAMType]);  /* restore SR16 */
+
+   SiS_EnableRefresh(SiS_Pr, ROMAddr);
+   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x21,0x20);      	/* enable read cache */
 }
 #endif
 
 void
-SiS_SetMemoryClock(ULONG ROMAddr)
+SiS_SetMemoryClock(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-   SiS_SetReg1(SiS_P3c4,0x28,SiS_MCLKData[SiS_RAMType].SR28);
-   SiS_SetReg1(SiS_P3c4,0x29,SiS_MCLKData[SiS_RAMType].SR29);
-   SiS_SetReg1(SiS_P3c4,0x2A,SiS_MCLKData[SiS_RAMType].SR2A);
-   SiS_SetReg1(SiS_P3c4,0x2E,SiS_ECLKData[SiS_RAMType].SR2E);
-   SiS_SetReg1(SiS_P3c4,0x2F,SiS_ECLKData[SiS_RAMType].SR2F);
-   SiS_SetReg1(SiS_P3c4,0x30,SiS_ECLKData[SiS_RAMType].SR30);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x28,SiS_Pr->SiS_MCLKData_0[SiS_Pr->SiS_RAMType].SR28);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x29,SiS_Pr->SiS_MCLKData_0[SiS_Pr->SiS_RAMType].SR29);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2A,SiS_Pr->SiS_MCLKData_0[SiS_Pr->SiS_RAMType].SR2A);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2E,SiS_Pr->SiS_ECLKData[SiS_Pr->SiS_RAMType].SR2E);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2F,SiS_Pr->SiS_ECLKData[SiS_Pr->SiS_RAMType].SR2F);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x30,SiS_Pr->SiS_ECLKData[SiS_Pr->SiS_RAMType].SR30);
 
 #ifdef SIS315H
-   if (Is315E()) {
-     SiS_SetReg1(SiS_P3c4,0x28,0x3B); /* 143 */
-     SiS_SetReg1(SiS_P3c4,0x29,0x22);
-     SiS_SetReg1(SiS_P3c4,0x2E,0x3B); /* 143 */
-     SiS_SetReg1(SiS_P3c4,0x2F,0x22);
+   if (Is315E(SiS_Pr)) {
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x28,0x3B); /* 143 */
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x29,0x22);
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2E,0x3B); /* 143 */
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2F,0x22);
    }
 #endif
 }
 
-#endif /* ifndef LINUX_XF86 */
+#endif /* ifdef LINUXBIOS */
 
 #ifdef SIS315H
 UCHAR
-SiS_Get310DRAMType(ULONG   ROMAddr)
+SiS_Get310DRAMType(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
    UCHAR   data;
 
-   /*
-   index=SiS_GetReg1(SiS_P3c4,0x1A);
-   index=index&07;
-   */
-   if (*pSiS_SoftSetting&SoftDRAMType)
-     data = *pSiS_SoftSetting & 0x03;
-   else
-     data=SiS_GetReg1(SiS_P3c4,0x3a) & 0x03;
+   if(*SiS_Pr->pSiS_SoftSetting & SoftDRAMType) {
+     data = *SiS_Pr->pSiS_SoftSetting & 0x03;
+   } else {
+     if(HwDeviceExtension->jChipType > SIS_315PRO) {
+        data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x13) & 0x07;
+     } else {	/* TW: 315 */
+        data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3a) & 0x03;
+     }
+   }
 
    return data;
 }
@@ -1685,31 +1835,31 @@
 
 /* ----------------------------------------- */
 
-void SiSRegInit(USHORT BaseAddr)
+void SiSRegInit(SiS_Private *SiS_Pr, USHORT BaseAddr)
 {
-   SiS_P3c4=BaseAddr+0x14;
-   SiS_P3d4=BaseAddr+0x24;
-   SiS_P3c0=BaseAddr+0x10;
-   SiS_P3ce=BaseAddr+0x1e;
-   SiS_P3c2=BaseAddr+0x12;
-   SiS_P3ca=BaseAddr+0x1a;
-   SiS_P3c6=BaseAddr+0x16;
-   SiS_P3c7=BaseAddr+0x17;
-   SiS_P3c8=BaseAddr+0x18;
-   SiS_P3c9=BaseAddr+0x19;
-   SiS_P3da=BaseAddr+0x2A;
-   SiS_Part1Port=BaseAddr+SIS_CRT2_PORT_04;
-   SiS_Part2Port=BaseAddr+SIS_CRT2_PORT_10;
-   SiS_Part3Port=BaseAddr+SIS_CRT2_PORT_12;
-   SiS_Part4Port=BaseAddr+SIS_CRT2_PORT_14;
-   SiS_Part5Port=BaseAddr+SIS_CRT2_PORT_14+2;
-   SiS_DDC_Port=BaseAddr+0x14;  /* 0x3c4; */
+   SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
+   SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
+   SiS_Pr->SiS_P3c0 = BaseAddr + 0x10;
+   SiS_Pr->SiS_P3ce = BaseAddr + 0x1e;
+   SiS_Pr->SiS_P3c2 = BaseAddr + 0x12;
+   SiS_Pr->SiS_P3ca = BaseAddr + 0x1a;
+   SiS_Pr->SiS_P3c6 = BaseAddr + 0x16;
+   SiS_Pr->SiS_P3c7 = BaseAddr + 0x17;
+   SiS_Pr->SiS_P3c8 = BaseAddr + 0x18;
+   SiS_Pr->SiS_P3c9 = BaseAddr + 0x19;
+   SiS_Pr->SiS_P3da = BaseAddr + 0x2A;
+   SiS_Pr->SiS_Part1Port = BaseAddr + SIS_CRT2_PORT_04;   /* Digital video interface registers (LCD) */
+   SiS_Pr->SiS_Part2Port = BaseAddr + SIS_CRT2_PORT_10;   /* 301 TV Encoder registers */
+   SiS_Pr->SiS_Part3Port = BaseAddr + SIS_CRT2_PORT_12;   /* 301 Macrovision registers */
+   SiS_Pr->SiS_Part4Port = BaseAddr + SIS_CRT2_PORT_14;   /* 301 VGA2 (and LCD) registers */
+   SiS_Pr->SiS_Part5Port = BaseAddr + SIS_CRT2_PORT_14+2; /* 301 palette address port registers */
+   SiS_Pr->SiS_DDC_Port = BaseAddr + 0x14;                /* DDC Port ( = P3C4, SR11/0A) */
 }
 
 void
-SiSInitPCIetc(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiSInitPCIetc(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-#ifdef LINUX_XF86
+/* #ifdef LINUX_XF86 */
    if ((HwDeviceExtension->jChipType == SIS_540)||
        (HwDeviceExtension->jChipType == SIS_630)||
        (HwDeviceExtension->jChipType == SIS_730)||
@@ -1718,9 +1868,9 @@
 		  - PCI IO ENABLE  (0x20)
 		  - MMIO ENABLE (0x1)
   	*/
-       SiS_SetReg1(SiS_P3c4,0x20,0xa1);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x20,0xa1);
        /* TW: Enable 2D (0x42) & 3D accelerator (0x18) */
-       SiS_SetReg1(SiS_P3c4,0x1E,0x5A);
+       SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x1E,0xFF,0x5A);
    }
    if((HwDeviceExtension->jChipType == SIS_315H)||
       (HwDeviceExtension->jChipType == SIS_315PRO)||
@@ -1729,106 +1879,144 @@
       (HwDeviceExtension->jChipType == SIS_740)||
       (HwDeviceExtension->jChipType == SIS_650)) {
       /* TW: This seems to be done the same way on these chipsets */
-      SiS_SetReg1(SiS_P3c4,0x20,0xa1);
-      SiS_SetReg1(SiS_P3c4,0x1E,0x5A);
+      SiS_SetReg1(SiS_Pr->SiS_P3c4,0x20,0xa1);
+      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x1E,0xFF,0x5A);
    }
-#endif
+/* #endif */
 }
 
 void
-SiSSetLVDSetc(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo)
+SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo)
 {
    ULONG   temp;
 
-   SiS_IF_DEF_LVDS=0;
-   SiS_IF_DEF_CH7005=0;
-   SiS_IF_DEF_HiVision=0;
-   SiS_IF_DEF_DSTN=0;
-   SiS_IF_DEF_FSTN=0;
-   if((ModeNo==0x5a)||(ModeNo==0x5b)) {
-   	SiS_IF_DEF_DSTN=1;   /* for 550 dstn */
-   	SiS_IF_DEF_FSTN=1;   /* for fstn */
+   SiS_Pr->SiS_IF_DEF_LVDS = 0;
+   SiS_Pr->SiS_IF_DEF_TRUMPION = 0;
+   SiS_Pr->SiS_IF_DEF_CH70xx = 0;
+   SiS_Pr->SiS_IF_DEF_HiVision = 0;
+   SiS_Pr->SiS_IF_DEF_DSTN = 0;
+   SiS_Pr->SiS_IF_DEF_FSTN = 0;
+
+   SiS_Pr->SiS_ChrontelInit = 0;
+
+   if((ModeNo == 0x5a) || (ModeNo == 0x5b)) {
+   	SiS_Pr->SiS_IF_DEF_DSTN = 1;   /* for 550 dstn */
+   	SiS_Pr->SiS_IF_DEF_FSTN = 1;   /* for fstn */
    }
-   if((HwDeviceExtension->jChipType == SIS_540)||
-      (HwDeviceExtension->jChipType == SIS_630)||
-      (HwDeviceExtension->jChipType == SIS_730)||
-      (HwDeviceExtension->jChipType == SIS_550)||
-      (HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_650))    /* 09/03/01 chiawen for 650 */
+
+#ifdef SIS300
+   if((HwDeviceExtension->jChipType == SIS_540) ||
+      (HwDeviceExtension->jChipType == SIS_630) ||
+      (HwDeviceExtension->jChipType == SIS_730))
     {
-      	if (SiS_IF_DEF_FSTN) {                               /*fstn setCR37=0x04;*/
-        	SiS_SetReg1(SiS_P3d4,0x37,0x04);
-      	}
-      	temp=SiS_GetReg1(SiS_P3d4,0x37);
-      	temp=(temp&0x0E)>>1;
-      	if((temp==0)||(temp==1)) {   /* for 301 */
-        	SiS_IF_DEF_LVDS=0;
-        	SiS_IF_DEF_CH7005=0;
-        	SiS_IF_DEF_TRUMPION=0;
-      	}
-      	if((temp>=2)&&(temp<=5)) SiS_IF_DEF_LVDS=1;
-      	if(temp==3) SiS_IF_DEF_TRUMPION=1;
-      	if((temp==4)||(temp==5)) {
-		/* TW: Save power status */
-		SiS_Backup7005 = SiS_GetCH7005(0x0e);
-		SiS_IF_DEF_CH7005=1;
+        /* TW: Check for SiS30x first */
+        temp = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x00);
+	if((temp == 1) || (temp == 2)) return;
+      	temp = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);
+      	temp = (temp & 0x0E) >> 1;
+      	if((temp >= 2) && (temp <= 5)) SiS_Pr->SiS_IF_DEF_LVDS = 1;
+      	if(temp == 3)   SiS_Pr->SiS_IF_DEF_TRUMPION = 1;
+      	if((temp == 4) || (temp == 5)) {
+		/* TW: Save power status (and error check) */
+		SiS_Pr->SiS_Backup70xx = SiS_GetCH700x(SiS_Pr, 0x0e);
+		SiS_Pr->SiS_IF_DEF_CH70xx = 1;
         }
    }
+#endif
+#ifdef SIS315H
+   if((HwDeviceExtension->jChipType == SIS_550) ||
+      (HwDeviceExtension->jChipType == SIS_640) ||
+      (HwDeviceExtension->jChipType == SIS_740) ||
+      (HwDeviceExtension->jChipType == SIS_650))
+    {
+        /* TW: CR37 is different on 310/325 series */
+        if (SiS_Pr->SiS_IF_DEF_FSTN)                       /* fstn: set CR37=0x04 */
+             SiS_SetReg1(SiS_Pr->SiS_P3d4,0x37,0x04);      /* (fake LVDS bridge) */
+
+	temp=SiS_GetReg1(SiS_Pr->SiS_P3d4,0x37);
+      	temp = (temp & 0x0E) >> 1;
+      	if((temp >= 2) && (temp <= 3)) SiS_Pr->SiS_IF_DEF_LVDS = 1;
+      	if(temp == 3)  {
+			SiS_Pr->SiS_IF_DEF_CH70xx = 2;
+        }
+	/* SiS_Pr->SiS_IF_DEF_HiVision = 1; */
+    }
+#endif
 }
 
 void
-SiSInitPtr(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiSInitPtr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
 #ifdef SIS315H
-   if((HwDeviceExtension->jChipType == SIS_315H)||  /* 05/02/01 ynlai for sis550 */
-      (HwDeviceExtension->jChipType == SIS_315PRO)||
-      (HwDeviceExtension->jChipType == SIS_550)||
-      (HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
-      (HwDeviceExtension->jChipType == SIS_650))    /* 09/03/01 chiawen for 650 */
-     InitTo310Pointer();
+   if((HwDeviceExtension->jChipType == SIS_315H) ||
+      (HwDeviceExtension->jChipType == SIS_315PRO) ||
+      (HwDeviceExtension->jChipType == SIS_550) ||
+      (HwDeviceExtension->jChipType == SIS_640) ||
+      (HwDeviceExtension->jChipType == SIS_740) ||
+      (HwDeviceExtension->jChipType == SIS_650))
+     InitTo310Pointer(SiS_Pr, HwDeviceExtension);
 #endif
 
 #ifdef SIS300
-   if ((HwDeviceExtension->jChipType == SIS_540)||
-       (HwDeviceExtension->jChipType == SIS_630)||
-       (HwDeviceExtension->jChipType == SIS_730)||
+   if ((HwDeviceExtension->jChipType == SIS_540) ||
+       (HwDeviceExtension->jChipType == SIS_630) ||
+       (HwDeviceExtension->jChipType == SIS_730) ||
        (HwDeviceExtension->jChipType == SIS_300))
-     InitTo300Pointer();
+     InitTo300Pointer(SiS_Pr, HwDeviceExtension);
 #endif
 }
 
+void
+SiSDetermineROMUsage(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, UCHAR *ROMAddr)
+{
+   if((ROMAddr) && (HwDeviceExtension->UseROM)) {
+     if((ROMAddr[0x00] != 0x55) || (ROMAddr[0x01] != 0xAA)) {
+        SiS_Pr->SiS_UseROM = FALSE;
+     } else if(HwDeviceExtension->jChipType < SIS_315H) {
+        /* TW: We don't use the ROM image if BIOS version < 2.0.0 as
+         *     such old BIOSes don't have the needed data at the
+	 *     expected locations
+	 */
+        if(ROMAddr[0x06] < '2')  SiS_Pr->SiS_UseROM = FALSE;
+	else                     SiS_Pr->SiS_UseROM = TRUE;
+     } else {
+        /* TW: TODO: Check this for 310/325 series */
+	SiS_Pr->SiS_UseROM = TRUE;
+     }
+   } else SiS_Pr->SiS_UseROM = FALSE;
+
+}
+
 /*
  	=========================================
- 	======== SiS SetMode Function  ==========
+ 	======== SiS SetMode Functions ==========
  	=========================================
 */
 #ifdef LINUX_XF86
 /* TW: This is used for non-Dual-Head mode from X */
 BOOLEAN
-SiSBIOSSetMode(PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn,
+SiSBIOSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn,
                DisplayModePtr mode)
 {
    UShort  ModeNo=0;
 
    ModeNo = SiS_CalcModeIndex(pScrn, mode);
-   if (!ModeNo) return FALSE;
+   if(!ModeNo) return FALSE;
 
-   xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Setting mode 0x%x\n", ModeNo);
+   xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting mode 0x%x\n", ModeNo);
 
-   return(SiSSetMode(HwDeviceExtension, pScrn, ModeNo));
+   return(SiSSetMode(SiS_Pr, HwDeviceExtension, pScrn, ModeNo, TRUE));
 }
 
 #ifdef SISDUALHEAD
 /* TW: Set CRT1 mode (used for dual head) */
 BOOLEAN
-SiSBIOSSetModeCRT1(PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn,
+SiSBIOSSetModeCRT1(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn,
                DisplayModePtr mode)
 {
    ULONG   temp;
-   USHORT  ModeIdIndex,KeepLockReg;
-   ULONG   ROMAddr  = (ULONG)HwDeviceExtension->pjVirtualRomBase;
+   USHORT  ModeIdIndex;
+   UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
    USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
    SISPtr  pSiS = SISPTR(pScrn);
    SISEntPtr pSiSEnt = pSiS->entityPrivate;
@@ -1836,139 +2024,190 @@
    UShort  ModeNo=0;
 
    ModeNo = SiS_CalcModeIndex(pScrn, mode);
-   if (!ModeNo) return FALSE;
+   if(!ModeNo) return FALSE;
+
+   xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting mode 0x%x on CRT1\n", ModeNo);
 
-   xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Setting mode 0x%x on CRT1\n", ModeNo);
+   SiSInitPtr(SiS_Pr, HwDeviceExtension);
 
-   SiSInitPtr(HwDeviceExtension);
+   SiSRegInit(SiS_Pr, BaseAddr);
 
-   SiSRegInit(BaseAddr);
+   SiS_Pr->SiS_VGAINFO = SiS_GetSetMMIOReg(pScrn, 0x489, 0xff);
 
-   SiSInitPCIetc(HwDeviceExtension);
+   SiSInitPCIetc(SiS_Pr, HwDeviceExtension);
 
-   SiSSetLVDSetc(HwDeviceExtension, ModeNo);
+   SiSSetLVDSetc(SiS_Pr, HwDeviceExtension, ModeNo);
+
+   SiSDetermineROMUsage(SiS_Pr, HwDeviceExtension, ROMAddr);
 
    /* TW: We don't clear the buffer under X */
-   flag_clearbuffer=0;
+   SiS_Pr->SiS_flag_clearbuffer=0;
+
+   /* 1.Openkey */
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
 
-   /* SiS_PresetScratchregister(SiS_P3d4,HwDeviceExtension);  */      		/* add for CRT2  */
-   KeepLockReg = SiS_GetReg1(SiS_P3c4,0x05);
-   SiS_SetReg1(SiS_P3c4,0x05,0x86);                             		/* 1.Openkey */
+   SiS_UnLockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
 
-   temp = SiS_SearchModeID(ROMAddr,ModeNo,&ModeIdIndex);        		/* 2.Get ModeID Table  */
-   if(temp==0)  return(0);
+   /* 2.Get ModeID Table  */
+   temp = SiS_SearchModeID(SiS_Pr, ROMAddr,&ModeNo,&ModeIdIndex);
+   if(temp == 0)  return(0);
 
    /* TW: Determine VBType (301,301B,301LV,302B,302LV) */
-   SiS_GetVBType(BaseAddr);
+   SiS_GetVBType(SiS_Pr, BaseAddr,HwDeviceExtension);
 
-   SiS_GetVBInfo301(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);   	/*add for CRT2 */
-   SiS_GetLCDResInfo301(ROMAddr,SiS_P3d4,ModeNo,ModeIdIndex);   		/*add for CRT2 */
+   /* TW: Get VB information (connectors, connected devices) */
+   SiS_GetVBInfo(SiS_Pr, BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+   SiS_SetHiVision(SiS_Pr, BaseAddr,HwDeviceExtension);
+   SiS_GetLCDResInfo(SiS_Pr, ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
 
-   SiS_SetCRT1Group(ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex);
+   /* TW: I am not sure the flag's name is correct */
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+      if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
+          if(ModeNo != 0x10)  SiS_Pr->SiS_SetFlag |= CRT2IsVGA;
+      }
+   }
+
+   /* TW: Set mode on CRT1 */
+   SiS_SetCRT1Group(SiS_Pr, ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex,BaseAddr);
 
    pSiSEnt->CRT1ModeNo = ModeNo;
    pSiSEnt->CRT1DMode = mode;
 
    /* TW: SetPitch: Adapt to virtual size & position */
-   SiS_SetPitchCRT1(pScrn, BaseAddr);
+   if(ModeNo > 0x13) {
+      SiS_SetPitchCRT1(SiS_Pr, pScrn, BaseAddr);
+   }
 
    /* We have to reset CRT2 if changing mode on CRT1 */
-   if (pSiSEnt->CRT2ModeNo != -1) {
-        xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "(Re-)Setting mode 0x%x on CRT2\n",
+   if(pSiSEnt->CRT2ModeNo != -1) {
+        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "(Re-)Setting mode 0x%x on CRT2\n",
 				pSiSEnt->CRT2ModeNo);
-	SiSBIOSSetModeCRT2(HwDeviceExtension, pSiSEnt->pScrn_1,
+	SiSBIOSSetModeCRT2(SiS_Pr, HwDeviceExtension, pSiSEnt->pScrn_1,
 				pSiSEnt->CRT2DMode);
    }
 
-   /* Backup/Set ModeNo in MMIO */
-   /* SiS_GetSetModeID(pScrn,ModeNo); */
+   if((HwDeviceExtension->jChipType > SIS_315PRO) && (SiS_Pr->SiS_IF_DEF_LVDS == 0)) {
+      /* TW: *** For 650 only! *** */
+      SiS_HandleCRT1(SiS_Pr);
+   }
+
+   SiS_DisplayOn(SiS_Pr);
+   SiS_SetReg3(SiS_Pr->SiS_P3c6,0xFF);
 
-   if(KeepLockReg==0xA1) SiS_SetReg1(SiS_P3c4,0x05,0x86); /* 05/02/01 ynlai */
-   else SiS_SetReg1(SiS_P3c4,0x05,0x00);
+   if((HwDeviceExtension->jChipType >= SIS_315H) && (SiS_Pr->SiS_IF_DEF_LVDS == 0)) {
+      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+          SiS_Handle301B_1400x1050(SiS_Pr, ModeNo);
+      }
+   }
+
+   /* Backup/Set ModeNo in MMIO */
+   SiS_GetSetModeID(pScrn,ModeNo);
 
    return TRUE;
 }
 
 /* TW: Set CRT2 mode (used for dual head) */
 BOOLEAN
-SiSBIOSSetModeCRT2(PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn,
+SiSBIOSSetModeCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, ScrnInfoPtr pScrn,
                DisplayModePtr mode)
 {
    ULONG   temp;
-   USHORT  ModeIdIndex,KeepLockReg;
-   ULONG   ROMAddr  = (ULONG)HwDeviceExtension->pjVirtualRomBase;
+   USHORT  ModeIdIndex;
+   UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
    USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
-   UShort  ModeNo=0;
-   SISPtr  pSiS = SISPTR(pScrn);
+   UShort  ModeNo   = 0;
+   SISPtr  pSiS     = SISPTR(pScrn);
    SISEntPtr pSiSEnt = pSiS->entityPrivate;
 
    ModeNo = SiS_CalcModeIndex(pScrn, mode);
-   if (!ModeNo) return FALSE;
+   if(!ModeNo) return FALSE;
 
-   SiSInitPtr(HwDeviceExtension);
+   SiSInitPtr(SiS_Pr, HwDeviceExtension);
 
-   SiSRegInit(BaseAddr);
+   SiSRegInit(SiS_Pr, BaseAddr);
 
-   SiSInitPCIetc(HwDeviceExtension);
+   SiS_Pr->SiS_VGAINFO = SiS_GetSetMMIOReg(pScrn, 0x489, 0xff);
 
-   SiSSetLVDSetc(HwDeviceExtension, ModeNo);
+   SiSInitPCIetc(SiS_Pr, HwDeviceExtension);
+
+   SiSSetLVDSetc(SiS_Pr, HwDeviceExtension, ModeNo);
+
+   SiSDetermineROMUsage(SiS_Pr, HwDeviceExtension, ROMAddr);
 
    /* TW: We don't clear the buffer under X */
-   flag_clearbuffer=0;
+   SiS_Pr->SiS_flag_clearbuffer=0;
 
    /* TW: Save ModeNo so we can set it from within SetMode for CRT1 */
    pSiSEnt->CRT2ModeNo = ModeNo;
    pSiSEnt->CRT2DMode = mode;
 
    /* TW: We can't set CRT2 mode before CRT1 mode is set */
-   if (pSiSEnt->CRT1ModeNo == -1) {
-   	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+   if(pSiSEnt->CRT1ModeNo == -1) {
+   	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 		"Setting CRT2 mode delayed until after setting CRT1 mode\n");
    	return TRUE;
    }
 
-   xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Setting mode 0x%x on CRT2\n", ModeNo);
+   xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting mode 0x%x on CRT2\n", ModeNo);
 
-   /* SiS_PresetScratchregister(SiS_P3d4,HwDeviceExtension);      */  		/* add for CRT2  */
-   KeepLockReg = SiS_GetReg1(SiS_P3c4,0x05);
-   SiS_SetReg1(SiS_P3c4,0x05,0x86);                             		/* 1.Openkey */
+   /* 1.Openkey */
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
 
-   temp = SiS_SearchModeID(ROMAddr,ModeNo,&ModeIdIndex);        		/* 2.Get ModeID Table  */
-   if(temp==0)  return(0);
+   SiS_UnLockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
+
+   /* 2.Get ModeID */
+   temp = SiS_SearchModeID(SiS_Pr, ROMAddr,&ModeNo,&ModeIdIndex);
+   if(temp == 0)  return(0);
 
    /* TW: Determine VBType (301,301B,301LV,302B,302LV) */
-   SiS_GetVBType(BaseAddr);
+   SiS_GetVBType(SiS_Pr, BaseAddr,HwDeviceExtension);
+
+   /* TW: Get VB information (connectors, connected devices) */
+   SiS_GetVBInfo(SiS_Pr, BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+   SiS_SetHiVision(SiS_Pr, BaseAddr,HwDeviceExtension);
+   SiS_GetLCDResInfo(SiS_Pr, ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
 
-   SiS_GetVBInfo301(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);   	/*add for CRT2 */
-   SiS_GetLCDResInfo301(ROMAddr,SiS_P3d4,ModeNo,ModeIdIndex);   		/*add for CRT2 */
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+      if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
+          /* TW: I am not sure the flag's name is correct */
+          if(ModeNo != 0x10)  SiS_Pr->SiS_SetFlag |= CRT2IsVGA;
+      }
+   }
 
+   /* Set mode on CRT2 */
    switch (HwDeviceExtension->ujVBChipID) {
      case VB_CHIP_301:
-     case VB_CHIP_301B:    /*for Linux & WinCE to open*/
-        SiS_SetCRT2Group301(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);         /*add for CRT2 */
-        break;
+     case VB_CHIP_301B:
+     case VB_CHIP_301LV:
+     case VB_CHIP_301LVX:
      case VB_CHIP_302:
-        SiS_SetCRT2Group301(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
+     case VB_CHIP_302B:
+     case VB_CHIP_302LV:
+     case VB_CHIP_302LVX:
+        SiS_SetCRT2Group301(SiS_Pr, BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
         break;
      case VB_CHIP_303:
-/*      SetCRT2Group302(BaseAddr,ROMAddr,ModeNo, HwDeviceExtension);            add for CRT2   */
         break;
-     case VB_CHIP_UNKNOWN:                                                                                                 /*add for lvds ch7005*/
-        temp=SiS_GetReg1(SiS_P3d4,0x37);
-        if(temp&(ExtChipLVDS|ExtChipTrumpion|ExtChipCH7005)){
-             	SiS_SetCRT2Group301(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
-        }
+     case VB_CHIP_UNKNOWN:
+        if (SiS_Pr->SiS_IF_DEF_LVDS == 1 || SiS_Pr->SiS_IF_DEF_CH70xx == 1 ||
+	                                               SiS_Pr->SiS_IF_DEF_TRUMPION != 0)
+             	SiS_SetCRT2Group301(SiS_Pr,BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
         break;
    }
 
-   /* TW: SetPitch: Adapt to virtual size & position */
-   SiS_SetPitchCRT2(pScrn, BaseAddr);
+   SiS_DisplayOn(SiS_Pr);
+   SiS_SetReg3(SiS_Pr->SiS_P3c6,0xFF);
 
-   /* Backup/Set ModeNo in MMIO */
-   /* SiS_GetSetModeID(pScrn,ModeNo); */
+   if((HwDeviceExtension->jChipType >= SIS_315H) && (SiS_Pr->SiS_IF_DEF_LVDS == 0)) {
+      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+          SiS_Handle301B_1400x1050(SiS_Pr, ModeNo);
+      }
+   }
 
-   if(KeepLockReg==0xA1) SiS_SetReg1(SiS_P3c4,0x05,0x86); /* 05/02/01 ynlai */
-   else SiS_SetReg1(SiS_P3c4,0x05,0x00);
+   /* TW: SetPitch: Adapt to virtual size & position */
+   if(ModeNo > 0x13) {
+       SiS_SetPitchCRT2(SiS_Pr, pScrn, BaseAddr);
+   }
 
    return TRUE;
 }
@@ -1978,1440 +2217,1662 @@
 #ifdef LINUX_XF86
 /* TW: We need pScrn for setting the pitch correctly */
 BOOLEAN
-SiSSetMode(PSIS_HW_DEVICE_INFO HwDeviceExtension,ScrnInfoPtr pScrn,USHORT ModeNo)
+SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,ScrnInfoPtr pScrn,USHORT ModeNo, BOOLEAN dosetpitch)
 #else
 BOOLEAN
-SiSSetMode(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo)
+SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo)
 #endif
 {
    ULONG   temp;
    USHORT  ModeIdIndex,KeepLockReg;
-   ULONG   ROMAddr  = (ULONG)HwDeviceExtension->pjVirtualRomBase;
+   UCHAR  *ROMAddr  = HwDeviceExtension->pjVirtualRomBase;
    USHORT  BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
 
-   SiSInitPtr(HwDeviceExtension);
+   SiSInitPtr(SiS_Pr, HwDeviceExtension);
+
+   SiSRegInit(SiS_Pr, BaseAddr);
 
-   SiSRegInit(BaseAddr);
+#ifdef LINUX_XF86
+   if(pScrn) SiS_Pr->SiS_VGAINFO = SiS_GetSetMMIOReg(pScrn, 0x489, 0xff);
+   else
+#endif
+         SiS_Pr->SiS_VGAINFO = 0x11;
+
+   SiSInitPCIetc(SiS_Pr, HwDeviceExtension);
 
-   SiSInitPCIetc(HwDeviceExtension);
+   SiSSetLVDSetc(SiS_Pr, HwDeviceExtension, ModeNo);
 
-   SiSSetLVDSetc(HwDeviceExtension, ModeNo);
+   SiSDetermineROMUsage(SiS_Pr, HwDeviceExtension, ROMAddr);
+
+   /* TW: Shift the clear-buffer-bit away */
+   ModeNo = ((ModeNo & 0x80) << 8) | (ModeNo & 0x7f);
 
 #ifdef LINUX_XF86
-   /* TW: We don't clear the buffer under X */
-   ModeNo |= 0x80;
+   /* TW: We never clear the buffer in X */
+   ModeNo |= 0x8000;
 #endif
 
-   if(ModeNo&0x80) {
-     	ModeNo=ModeNo&0x7F;
-     	flag_clearbuffer=0;
+   if(ModeNo & 0x8000) {
+     	ModeNo &= 0x007F;
+     	SiS_Pr->SiS_flag_clearbuffer = 0;
    } else {
-     	flag_clearbuffer=1;
+     	SiS_Pr->SiS_flag_clearbuffer = 1;
    }
 
-   SiS_PresetScratchregister(SiS_P3d4,HwDeviceExtension);       		/* add for CRT2  */
-   KeepLockReg = SiS_GetReg1(SiS_P3c4,0x05);
-   SiS_SetReg1(SiS_P3c4,0x05,0x86);                             		/* 1.Openkey */
+   /* 1.Openkey */
+   KeepLockReg = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x05);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
 
-   temp = SiS_SearchModeID(ROMAddr,ModeNo,&ModeIdIndex);        		/* 2.Get ModeID Table  */
-   if(temp==0)  return(0);
+   SiS_UnLockCRT2(SiS_Pr, HwDeviceExtension, BaseAddr);
+
+   /* 2.Get ModeID Table  */
+   temp = SiS_SearchModeID(SiS_Pr,ROMAddr,&ModeNo,&ModeIdIndex);
+   if(temp == 0) return(0);
 
    /* TW: Determine VBType (301,301B,301LV,302B,302LV) */
-   SiS_GetVBType(BaseAddr);
+   SiS_GetVBType(SiS_Pr,BaseAddr,HwDeviceExtension);
+
+   /* TW: Init/restore some VB registers */
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+         if(ROMAddr && SiS_Pr->SiS_UseROM) {
+           temp = ROMAddr[VB310Data_1_2_Offset];
+	   temp |= 0x40;
+           SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x02,temp);
+	   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x32,0x10);
+         }
+      }
+   }
 
-   SiS_GetVBInfo301(BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);   	/*add for CRT2 */
-   SiS_GetLCDResInfo301(ROMAddr,SiS_P3d4,ModeNo,ModeIdIndex);   		/*add for CRT2 */
+   /* TW: Get VB information (connectors, connected devices) */
+   SiS_GetVBInfo(SiS_Pr,BaseAddr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+   SiS_SetHiVision(SiS_Pr,BaseAddr,HwDeviceExtension);
+   SiS_GetLCDResInfo(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+
+   /* 3. Check memory size */
+   temp = SiS_CheckMemorySize(SiS_Pr,ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex);
+   if(!temp) return(0);
+
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+      if(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x17) & 0x08)  {
+          /* TW: I am not sure the flag's name is correct */
+          if(ModeNo != 0x10)  SiS_Pr->SiS_SetFlag |= CRT2IsVGA;
+      }
+   }
 
-   temp=SiS_CheckMemorySize(ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex);    	/*3.Check memory size */
-   if(temp==0) return(0);
-   if(SiS_VBInfo&(SetSimuScanMode|SetCRT2ToLCDA)) {				/*301b*/
-   	SiS_SetCRT1Group(ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex);
+   /* TW: Set mode on CRT1 */
+   if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SetCRT2ToLCDA)) {
+   	SiS_SetCRT1Group(SiS_Pr,ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex,BaseAddr);
    } else {
-     if(!(SiS_VBInfo&SwitchToCRT2)) {
-       	SiS_SetCRT1Group(ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex);
+     if(!(SiS_Pr->SiS_VBInfo & SwitchToCRT2)) {
+       	SiS_SetCRT1Group(SiS_Pr,ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex,BaseAddr);
      }
    }
 
-   if(SiS_VBInfo&(SetSimuScanMode|SwitchToCRT2|SetCRT2ToLCDA)) {		/*301b*/
+   /* TW: Set mode on CRT2 */
+   if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2 | SetCRT2ToLCDA)) {
      switch (HwDeviceExtension->ujVBChipID) {
      case VB_CHIP_301:
-     case VB_CHIP_301B:    /*for Linux & WinCE to open*/
-        SiS_SetCRT2Group301(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);        /*add for CRT2 */
-        break;
+     case VB_CHIP_301B:
+     case VB_CHIP_301LV:
+     case VB_CHIP_301LVX:
      case VB_CHIP_302:
-        SiS_SetCRT2Group301(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
+     case VB_CHIP_302B:
+     case VB_CHIP_302LV:
+     case VB_CHIP_302LVX:
+        SiS_SetCRT2Group301(SiS_Pr,BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
         break;
      case VB_CHIP_303:
-/*      SetCRT2Group302(BaseAddr,ROMAddr,ModeNo, HwDeviceExtension);             add for CRT2   */
         break;
-     case VB_CHIP_UNKNOWN:                                                                                                 /*add for lvds ch7005*/
-        temp=SiS_GetReg1(SiS_P3d4,0x37);
-        if(temp&(ExtChipLVDS|ExtChipTrumpion|ExtChipCH7005)){
-             	SiS_SetCRT2Group301(BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
-        }
+     case VB_CHIP_UNKNOWN:
+	if(SiS_Pr->SiS_IF_DEF_LVDS == 1   ||
+	   SiS_Pr->SiS_IF_DEF_CH70xx != 0 ||
+	   SiS_Pr->SiS_IF_DEF_TRUMPION != 0)
+             	SiS_SetCRT2Group301(SiS_Pr,BaseAddr,ROMAddr,ModeNo,HwDeviceExtension);
         break;
      }
    }
 
+
+   if((HwDeviceExtension->jChipType > SIS_315PRO) && (SiS_Pr->SiS_IF_DEF_LVDS == 0)) {
+      /* TW: For 650 only! */
+      SiS_HandleCRT1(SiS_Pr);
+   }
+
+   SiS_DisplayOn(SiS_Pr);
+   SiS_SetReg3(SiS_Pr->SiS_P3c6,0xFF);
+
+   if((HwDeviceExtension->jChipType >= SIS_315H) && (SiS_Pr->SiS_IF_DEF_LVDS == 0)) {
+      if(SiS_Pr->SiS_LCDResInfo == SiS_Pr->SiS_Panel1400x1050) {
+          SiS_Handle301B_1400x1050(SiS_Pr, ModeNo);
+      }
+   }
+
 #ifdef LINUX_XF86
-   /* TW: SetPitch: Adapt to virtual size & position */
-   SiS_SetPitch(pScrn, BaseAddr);
-   /* Backup/Set ModeNo in MMIO */
-   SiS_GetSetModeID(pScrn,ModeNo);
+   if(pScrn) {
+      /* TW: SetPitch: Adapt to virtual size & position */
+      if((ModeNo > 0x13) && (dosetpitch)) {
+         SiS_SetPitch(SiS_Pr, pScrn, BaseAddr);
+      }
+
+      /* Backup/Set ModeNo in MMIO */
+      SiS_GetSetModeID(pScrn, ModeNo);
+   }
 #endif
 
 #ifndef LINUX_XF86  /* TW: We never lock registers in XF86 */
-   if(KeepLockReg==0xA1) SiS_SetReg1(SiS_P3c4,0x05,0x86);
-   else SiS_SetReg1(SiS_P3c4,0x05,0x00);
+   if(KeepLockReg == 0xA1) SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x86);
+   else SiS_SetReg1(SiS_Pr->SiS_P3c4,0x05,0x00);
 #endif
 
    return TRUE;
 }
 
 void
-SetEnableDstn()		/* TW: Called from sis_main.c */
+SetEnableDstn(SiS_Private *SiS_Pr)	/* TW: Called from sis_main.c */
 {
-   SiS_IF_DEF_DSTN=1;   /*for 550 dstn*/
+   /* For 550 dstn */
+   SiS_Pr->SiS_IF_DEF_DSTN = 1;
 }
 
 void
-SiS_SetCRT1Group(ULONG ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                 USHORT ModeNo,USHORT ModeIdIndex)
+SiS_HandleCRT1(SiS_Private *SiS_Pr)
 {
-  USHORT  StandTableIndex,RefreshRateTableIndex;
-  USHORT  temp;
+  /* TW: Do this on 650 only! */
 
-  /*SiS_SetReg1(SiS_P3d4,0x34,ModeNo);*/
-  SiS_CRT1Mode = ModeNo;
-  /* set CR34->CRT1 ModeNo for CRT2 FIFO */
-  StandTableIndex = SiS_GetModePtr(ROMAddr,ModeNo,ModeIdIndex); /* 4.GetModePtr  */
-  SiS_SetSeqRegs(ROMAddr,StandTableIndex);                      /* 5.SetSeqRegs  */
-  SiS_SetMiscRegs(ROMAddr,StandTableIndex);                     /* 6.SetMiscRegs */
-  SiS_SetCRTCRegs(ROMAddr,HwDeviceExtension,StandTableIndex);   /* 7.SetCRTCRegs */
-  SiS_SetATTRegs(ROMAddr,StandTableIndex);                      /* 8.SetATTRegs  */
-  SiS_SetGRCRegs(ROMAddr,StandTableIndex);                      /* 9.SetGRCRegs  */
-  SiS_ClearExt1Regs();                                          /* 10.Clear Ext1Regs */
-  temp=~ProgrammingCRT2;                                        /* 11.GetRatePtr  */
-  SiS_SetFlag=SiS_SetFlag&temp;
-  SiS_SelectCRT2Rate=0;
+  /* TW: No, we don't do this at all. There is a new
+   * CRT1-is-connected-at-boot-time logic in the 650, which
+   * confuses our own. So just clear the bit and skip the rest.
+   */
 
-#ifdef LINUX_XF86
-  xf86DrvMsg(0, X_INFO, "VBType = %x, LVDS=%d, VBInfo=%x\n",
-                    SiS_VBType, SiS_IF_DEF_LVDS, SiS_VBInfo);
+  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x63,0xbf);
+
+#if 0
+  if(!(SiS_GetReg1(SiS_Pr->SiS_P3c4,0x15) & 0x01))
+     SiS_SetRegOR(SiS_Pr->SiS_P3d4,0x63,0x40);
+  }
 #endif
+}
 
-  /*301b*/
-  if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))) {
-      if(SiS_VBInfo&SetCRT2ToLCDA) {
-	 SiS_SetFlag=SiS_SetFlag|ProgrammingCRT2;
-      }
+void
+SiS_Handle301B_1400x1050(SiS_Private *SiS_Pr, USHORT ModeNo)
+{
+  if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x30) & SetCRT2ToLCD) {
+     if(ModeNo <= 0x13) {
+        if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & (SetNotSimuMode >> 8)) {
+	   SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x38,0xFC);
+	}
+     }
   }
-  /*end 301b*/
+}
 
-  RefreshRateTableIndex=SiS_GetRatePtrCRT2(ROMAddr,ModeNo,ModeIdIndex);   /* 11.GetRatePtr */
+void
+SiS_SetCRT1Group(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                 USHORT ModeNo,USHORT ModeIdIndex,USHORT BaseAddr)
+{
+  USHORT  StandTableIndex,RefreshRateTableIndex;
 
-  if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))) {
-      if(!(SiS_VBInfo&SetCRT2ToLCDA)) {
-	 SiS_SetFlag=SiS_SetFlag&(~ProgrammingCRT2);
-      }
+  SiS_Pr->SiS_CRT1Mode = ModeNo;
+  StandTableIndex = SiS_GetModePtr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex);
+  if(SiS_LowModeStuff(SiS_Pr,ModeNo,HwDeviceExtension)) {
+    if(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2)) {
+       SiS_DisableBridge(SiS_Pr,HwDeviceExtension,BaseAddr);
+    }
   }
 
-  if (RefreshRateTableIndex!=0xFFFF) {
-    SiS_SetSync(ROMAddr,RefreshRateTableIndex);                          /* 12.SetSync */
-    SiS_SetCRT1CRTC(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex);   /* 13.SetCRT1CRTC  */
-    SiS_SetCRT1Offset(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwDeviceExtension);   /* 14.SetCRT1Offset */
-    SiS_SetCRT1VCLK(ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension,RefreshRateTableIndex);     /* 15.SetCRT1VCLK  */
+  SiS_SetSeqRegs(SiS_Pr,ROMAddr,StandTableIndex);
+  SiS_SetMiscRegs(SiS_Pr,ROMAddr,StandTableIndex);
+  SiS_SetCRTCRegs(SiS_Pr,ROMAddr,HwDeviceExtension,StandTableIndex);
+  SiS_SetATTRegs(SiS_Pr,ROMAddr,StandTableIndex,ModeNo,HwDeviceExtension);
+  SiS_SetGRCRegs(SiS_Pr,ROMAddr,StandTableIndex);
+  SiS_ClearExt1Regs(SiS_Pr,HwDeviceExtension);
+  SiS_ResetCRT1VCLK(SiS_Pr,ROMAddr,HwDeviceExtension);
+
+  SiS_Pr->SiS_SelectCRT2Rate = 0;
+  SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
+
+#ifdef LINUX_XF86
+  xf86DrvMsg(0, X_PROBED, "(init: VBType=0x%04x, VBInfo=0x%04x)\n",
+                    SiS_Pr->SiS_VBType, SiS_Pr->SiS_VBInfo);
+#endif
+
+  if(SiS_Pr->SiS_VBInfo & SetSimuScanMode) {
+     if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+        SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+     }
+  }
+
+  if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+	SiS_Pr->SiS_SetFlag |= ProgrammingCRT2;
+  }
+
+  RefreshRateTableIndex = SiS_GetRatePtrCRT2(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
+
+  if(!(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+	SiS_Pr->SiS_SetFlag &= (~ProgrammingCRT2);
   }
+
+  if (RefreshRateTableIndex != 0xFFFF) {
+    	SiS_SetSync(SiS_Pr,ROMAddr,RefreshRateTableIndex);
+    	SiS_SetCRT1CRTC(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwDeviceExtension);
+    	SiS_SetCRT1Offset(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,HwDeviceExtension);
+    	SiS_SetCRT1VCLK(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension,RefreshRateTableIndex);
+  }
+
 #ifdef SIS300
+  if(HwDeviceExtension->jChipType == SIS_300){
+     	SiS_SetCRT1FIFO_300(SiS_Pr,ROMAddr,ModeNo,HwDeviceExtension,RefreshRateTableIndex);
+  }
   if((HwDeviceExtension->jChipType == SIS_630)||
+     (HwDeviceExtension->jChipType == SIS_730)||
      (HwDeviceExtension->jChipType == SIS_540)) {
-     	SiS_SetCRT1FIFO2(ROMAddr,ModeNo,HwDeviceExtension,RefreshRateTableIndex);
+     	SiS_SetCRT1FIFO_630(SiS_Pr,ROMAddr,ModeNo,HwDeviceExtension,RefreshRateTableIndex);
   }
 #endif
 #ifdef SIS315H
   if(HwDeviceExtension->jChipType >= SIS_315H) {
-     	SiS_SetCRT1FIFO(ROMAddr,ModeNo,HwDeviceExtension);
+     	SiS_SetCRT1FIFO_310(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,HwDeviceExtension);
   }
 #endif
-  SiS_SetCRT1ModeRegs(ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex,RefreshRateTableIndex);
-  SiS_SetVCLKState(ROMAddr,HwDeviceExtension,ModeNo,RefreshRateTableIndex);
-#ifdef SIS315H
-  if(HwDeviceExtension->jChipType > SIS_315H) {
-    if (RefreshRateTableIndex!=0xFFFF)
-      	SiS_SetInterlace(ROMAddr,ModeNo,RefreshRateTableIndex);
+
+  SiS_SetCRT1ModeRegs(SiS_Pr,ROMAddr,HwDeviceExtension,ModeNo,ModeIdIndex,RefreshRateTableIndex);
+
+  SiS_LoadDAC(SiS_Pr,HwDeviceExtension,ROMAddr,ModeNo,ModeIdIndex);
+
+#ifndef LINUX_XF86
+  if(SiS_Pr->SiS_flag_clearbuffer) {
+        SiS_ClearBuffer(SiS_Pr,HwDeviceExtension,ModeNo);
   }
 #endif
-  SiS_LoadDAC(ROMAddr,ModeNo,ModeIdIndex);
-  if(flag_clearbuffer) SiS_ClearBuffer(HwDeviceExtension,ModeNo);
 
-  if(!(SiS_VBInfo&(SetSimuScanMode|SwitchToCRT2|SetCRT2ToLCDA))) {   /*301b*/
-    SiS_LongWait();
-    SiS_DisplayOn();
+  if(!(SiS_Pr->SiS_VBInfo & (SetSimuScanMode | SwitchToCRT2 | SetCRT2ToLCDA))) {
+        SiS_LongWait(SiS_Pr);
+        SiS_DisplayOn(SiS_Pr);
   }
 }
 
 #ifdef LINUX_XF86
 void
-SiS_SetPitch(ScrnInfoPtr pScrn, UShort BaseAddr)
+SiS_SetPitch(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, UShort BaseAddr)
 {
    SISPtr pSiS = SISPTR(pScrn);
 
-   if (pSiS->VBFlags & DISPTYPE_DISP1) {
-   	SiS_SetPitchCRT1(pScrn, BaseAddr);
+   /* TW: We need to set pitch for CRT1 if bridge is in SlaveMode, too */
+   if( (pSiS->VBFlags & DISPTYPE_DISP1) ||
+       ( (pSiS->VBFlags & VB_VIDEOBRIDGE) &&
+         ( ((pSiS->VGAEngine == SIS_300_VGA) && (SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0xa0) == 0x20) ||
+           ((pSiS->VGAEngine == SIS_315_VGA) && (SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x00) & 0x50) == 0x10) ) ) ) {
+   	SiS_SetPitchCRT1(SiS_Pr, pScrn, BaseAddr);
    }
    if (pSiS->VBFlags & DISPTYPE_DISP2) {
-   	SiS_SetPitchCRT2(pScrn, BaseAddr);
+   	SiS_SetPitchCRT2(SiS_Pr, pScrn, BaseAddr);
    }
 }
 
 void
-SiS_SetPitchCRT1(ScrnInfoPtr pScrn, UShort BaseAddr)
+SiS_SetPitchCRT1(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, UShort BaseAddr)
 {
     SISPtr pSiS = SISPTR(pScrn);
     ULong  HDisplay,temp;
 
-    HDisplay = pSiS->scrnOffset / 8;
-    SiS_SetReg1(SiS_P3d4, 0x13, (HDisplay & 0xFF));
-    temp = (SiS_GetReg1(SiS_P3c4, 0x0E) & 0xF0) | (HDisplay>>8);
-    SiS_SetReg1(SiS_P3c4, 0x0E, temp);
+    HDisplay = pSiS->scrnPitch / 8;
+    SiS_SetReg1(SiS_Pr->SiS_P3d4, 0x13, (HDisplay & 0xFF));
+    temp = (SiS_GetReg1(SiS_Pr->SiS_P3c4, 0x0E) & 0xF0) | (HDisplay>>8);
+    SiS_SetReg1(SiS_Pr->SiS_P3c4, 0x0E, temp);
 }
 
 void
-SiS_SetPitchCRT2(ScrnInfoPtr pScrn, UShort BaseAddr)
+SiS_SetPitchCRT2(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, UShort BaseAddr)
 {
     SISPtr pSiS = SISPTR(pScrn);
     ULong  HDisplay,temp;
 
-    HDisplay = pSiS->scrnOffset / 8;
-    SiS_SetReg1(SiS_Part1Port, 0x24, 1);
-    SiS_SetReg1(SiS_Part1Port, 0x07, HDisplay);
-    temp = (SiS_GetReg1(SiS_Part1Port, 0x09) & 0xF0) | (HDisplay>>8);
-    SiS_SetReg1(SiS_Part1Port, 0x09, temp);
+    HDisplay = pSiS->scrnPitch / 8;
+
+    /* Unlock CRT2 */
+    if (pSiS->VGAEngine == SIS_315_VGA)
+        SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x2F, 0xFF, 0x01);
+    else
+        SiS_SetRegANDOR(SiS_Pr->SiS_Part1Port,0x24, 0xFF, 0x01);
+
+    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x07, (HDisplay & 0xFF));
+    temp = (SiS_GetReg1(SiS_Pr->SiS_Part1Port,0x09) & 0xF0) | ((HDisplay >> 8) & 0xFF);
+    SiS_SetReg1(SiS_Pr->SiS_Part1Port,0x09, temp);
 }
 #endif
 
+/* TW: Checked against 650/301 and 630/301B BIOS */
+/* TW: Re-written for 650/301LVx 1.10.6s BIOS */
 void
-SiS_GetVBType(USHORT BaseAddr)
+SiS_GetVBType(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT flag;
+  USHORT flag=0, rev=0, nolcd=0;
+
+  SiS_Pr->SiS_VBType = 0;
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1) return;
+
+  flag = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x00);
+
+  /* TW: Illegal values not welcome... */
+  if(flag > 10) return;
+
+  rev = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x01);
 
-  flag=SiS_GetReg1(SiS_Part4Port,0x00);
-  /* TW: On pure LVDS, Part4 is not assigned and returns 0xff */
-  if (flag >= 4) return;
-  /* TW end */
   if (flag >= 2) {
-  	flag=SiS_GetReg1(SiS_Part4Port,0x01);
-        if(flag>=0xB0){
-            	SiS_VBType=VB_SIS302B;
-            	if(flag>=0xD0)
-               		SiS_VBType=VB_SIS302LV;
+        SiS_Pr->SiS_VBType = VB_SIS302B;
+  } else if (flag == 1) {
+        SiS_Pr->SiS_VBType = VB_SIS301;
+        if(rev >= 0xB0) {
+            	SiS_Pr->SiS_VBType = VB_SIS301B;
+		if(HwDeviceExtension->jChipType >= SIS_315H) {
+    		    nolcd = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x23);
+                    if(!(nolcd & 0x02))
+       	                SiS_Pr->SiS_VBType |= VB_NoLCD;
+		}
         }
-  } else {
-        flag=SiS_GetReg1(SiS_Part4Port,0x01);
-        if(flag>=0xB0){
-            	SiS_VBType=VB_SIS301B;
-            	if(flag>=0xD0)
-               		SiS_VBType=VB_SIS301LV;
-        } else
-            SiS_VBType=VB_SIS301;
-  }
-  flag=SiS_GetReg1(SiS_Part4Port,0x23);       /*301dlvds*/
-  if(!(flag&0x02))
-      	SiS_VBType=SiS_VBType|VB_NoLCD;
+  }
+  if(SiS_Pr->SiS_VBType & (VB_SIS301B | VB_SIS302B)) {
+        if(rev >= 0xD0) {
+	        SiS_Pr->SiS_VBType &= ~(VB_SIS301B | VB_SIS302B);
+          	SiS_Pr->SiS_VBType |= VB_SIS30xLV;
+		SiS_Pr->SiS_VBType &= ~(VB_NoLCD);
+		if(rev >= 0xE0) {
+		    SiS_Pr->SiS_VBType &= ~(VB_SIS30xLV);
+		    SiS_Pr->SiS_VBType |= VB_SIS30xNEW;
+		}
+        }
+  }
 }
 
-/* win2000 MM adapter not support standard mode  */
+/* TW: Checked against 650/301LVx 1.10.6s */
 BOOLEAN
-SiS_SearchModeID(ULONG ROMAddr, USHORT ModeNo,USHORT  *ModeIdIndex)
+SiS_SearchModeID(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT *ModeNo,USHORT *ModeIdIndex)
 {
-#ifndef LINUX_XF86
-   PUCHAR VGA_INFO="\0x11";
-#endif
-   
-   if (ModeNo<=5) ModeNo |= 1;
-   if (ModeNo<=0x13) {
-     /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(SiS_SModeIDTable)/sizeof(SiS_StStruct);(*ModeIdIndex)++) */
-     for (*ModeIdIndex=0;;(*ModeIdIndex)++)
-     {
-       if (SiS_SModeIDTable[*ModeIdIndex].St_ModeID==ModeNo) break;
-       if (SiS_SModeIDTable[*ModeIdIndex].St_ModeID==0xFF)  return FALSE;
-     }
-#ifndef LINUX_XF86
-#ifdef TC
-     VGA_INFO = (PUCHAR) MK_FP(0,0x489);
-#endif
-     if (ModeNo==0x07) {
-        if ((*VGA_INFO&0x10)!=0) (*ModeIdIndex)++; /* 400 lines */
-        /* else 350 lines */
-     }
-     if (ModeNo<=3) {
-       if ((*VGA_INFO&0x80)==0) {
-         (*ModeIdIndex)++;
-         if ((*VGA_INFO&0x10)!=0)
-           (*ModeIdIndex)++;; /* 400 lines  */
+   UCHAR VGAINFO = SiS_Pr->SiS_VGAINFO;
+
+   if(*ModeNo <= 0x13) {
+
+      if((*ModeNo) <= 5) (*ModeNo) |= 1;
+
+      for (*ModeIdIndex=0;;(*ModeIdIndex)++) {
+         if (SiS_Pr->SiS_SModeIDTable[*ModeIdIndex].St_ModeID == (*ModeNo)) break;
+         if (SiS_Pr->SiS_SModeIDTable[*ModeIdIndex].St_ModeID == 0xFF)   return FALSE;
+      }
+
+      if(*ModeNo == 0x07) {
+          if(VGAINFO & 0x10) (*ModeIdIndex)++;   /* 400 lines */
+          /* else 350 lines */
+      }
+      if(*ModeNo <= 3) {
+         if(!(VGAINFO & 0x80)) (*ModeIdIndex)++;
+         if(VGAINFO & 0x10)    (*ModeIdIndex)++; /* 400 lines  */
          /* else 350 lines  */
-       }
-       /* else 200 lines  */
-     }
-#endif  /* NOT X86 */
-   }
-   else 
-   {
-     /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(SiS_EModeIDTable)/sizeof(SiS_ExtStruct);(*ModeIdIndex)++) */
-     for (*ModeIdIndex=0;;(*ModeIdIndex)++)
-     {
-       if (SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID==ModeNo) break;
-       if (SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID==0xFF) return FALSE;
-     }
+      }
+      /* else 200 lines  */
+
+   } else {
+
+      for (*ModeIdIndex=0;;(*ModeIdIndex)++) {
+         if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo)) break;
+         if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)   return FALSE;
+      }
+
    }
    return TRUE;
 }
 
-/*add for 300 oem util for search VBModeID*/
+/* For SiS 300 oem util: Search VBModeID */
 BOOLEAN
-SiS_SearchVBModeID(ULONG ROMAddr, USHORT ModeNo)
+SiS_SearchVBModeID(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT *ModeNo)
 {
    USHORT ModeIdIndex;
-#ifdef TC
-   PUCHAR VGA_INFO;
-#endif
-   
-   if (ModeNo<=5) ModeNo |= 1;
-    /* for (ModeIdIndex=0;ModeIdIndex<sizeof(SiS_SModeIDTable)/sizeof(SiS_StStruct);(*ModeIdIndex)++) */
-     for (ModeIdIndex=0;;(ModeIdIndex)++)
-     {
-       if (SiS_VBModeIDTable[ModeIdIndex].ModeID==ModeNo) break;
-       if (SiS_VBModeIDTable[ModeIdIndex].ModeID==0xFF)  return FALSE;
-     }
-#ifdef TC
-     VGA_INFO = (PUCHAR) MK_FP(0,0x489);
-     if (ModeNo==0x07) {
-	if ((*VGA_INFO&0x10)!=0) (ModeIdIndex)++; /* 400 lines */
-	/* else 350 lines */
-     }
-     if (ModeNo<=3) {
-       if ((*VGA_INFO&0x80)==0) {
-	 (ModeIdIndex)++;
-         if ((*VGA_INFO&0x10)!=0)
-	   (ModeIdIndex)++;; /* 400 lines  */
-	 /* else 350 lines  */
-       }
-       /* else 200 lines  */
-     }
-#endif
-  return ((BOOLEAN)ModeIdIndex);
+   UCHAR VGAINFO = SiS_Pr->SiS_VGAINFO;
+
+   if(*ModeNo <= 5) *ModeNo |= 1;
+
+   for(ModeIdIndex=0; ; ModeIdIndex++) {
+       if (SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].ModeID == *ModeNo) break;
+       if (SiS_Pr->SiS_VBModeIDTable[ModeIdIndex].ModeID == 0xFF)   return FALSE;
+   }
+
+   if(*ModeNo != 0x07) {
+        if(*ModeNo > 0x03) return ((BOOLEAN)ModeIdIndex);
+	if(VGAINFO & 0x80) return ((BOOLEAN)ModeIdIndex);
+	ModeIdIndex++;
+   }
+   if(VGAINFO & 0x10) ModeIdIndex++;   /* 400 lines */
+	                               /* else 350 lines */
+   return ((BOOLEAN)ModeIdIndex);
 }
-/*end oem util */
 
+/* TW: Checked against 630/301B, 315 1.09 and 650/301LVx 1.10.6s BIOS */
+/* TW: Modified */
 BOOLEAN
-SiS_CheckMemorySize(ULONG ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+SiS_CheckMemorySize(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
                     USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT memorysize,modeflag,temp;
-
-  if((HwDeviceExtension->jChipType == SIS_550)||   /* 05/02/01 ynlai for sis550 */
-     (HwDeviceExtension->jChipType == SIS_640)||   /* 08/20/01 chiawen for 640/740 */
-     (HwDeviceExtension->jChipType == SIS_740)||   /* 09/03/01 chiawen for 640/740 */
-     (HwDeviceExtension->jChipType == SIS_650))    /* 09/03/01 chiawen for 650 */
-    return(TRUE);
+  USHORT memorysize,modeflag;
+  ULONG  temp;
 
   if (ModeNo<=0x13) {
-    modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+      modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
   } else {
-    modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+      modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
   }
 
-/*  ModeType=modeflag&ModeInfoFlag;                           	   Get mode type  */
-
-  memorysize=modeflag&MemoryInfoFlag;
-  memorysize=memorysize>MemorySizeShift;
-  memorysize++;                                        		/* Get memory size */
+  memorysize = modeflag & MemoryInfoFlag;
+  memorysize >>= MemorySizeShift;			/* Get required memory size */
+  memorysize++;
 
-  temp=SiS_GetReg1(SiS_P3c4,0x14);                             	/* Get DRAM Size    */
-  if((HwDeviceExtension->jChipType == SIS_315H)||
-     (HwDeviceExtension->jChipType == SIS_315PRO)) {
-    temp= 1 << ((temp&0x0F0)>>4);				/* 315 */
-    if ((temp&0x0c)==0x08) { /* DDR asymetric */
-      temp += temp/2;
-    } else {
-      if ((temp&0x0c)!=0) temp <<= 1;
-    }
-  } else { 							/* 300, 540, 630, 730 */
-    temp=temp&0x3F;
-    temp++;
-  }
+  temp = GetDRAMSize(SiS_Pr, HwDeviceExtension);       	/* Get adapter memory size */
+  temp /= (1024*1024);   				/* (in MB) */
 
-  if(temp<memorysize) return(FALSE);
+  if(temp < memorysize) return(FALSE);
   else return(TRUE);
 }
 
 UCHAR
-SiS_GetModePtr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SiS_GetModePtr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
    UCHAR index;
 
    if(ModeNo<=0x13) {
-     	index = SiS_SModeIDTable[ModeIdIndex].St_StTableIndex;
+     	index = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_StTableIndex;
    } else {
-     	if(SiS_ModeType <= 0x02) index=0x1B;    /* 02 -> ModeEGA  */
+     	if(SiS_Pr->SiS_ModeType <= 0x02) index=0x1B;    /* 02 -> ModeEGA  */
      	else index=0x0F;
    }
-   return index;       /* Get SiS_StandTable index  */
+   return index;
 }
 
+/* TW: Checked against 300, 650/LVDS (1.10.07, 1.10a) and 650/301LV BIOS */
 void
-SiS_SetSeqRegs(ULONG ROMAddr,USHORT StandTableIndex)
+SiS_SetSeqRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex)
 {
    UCHAR SRdata;
    USHORT i;
 
-   SiS_SetReg1(SiS_P3c4,0x00,0x03);           /* Set SR0  */
-   SRdata=SiS_StandTable[StandTableIndex].SR[0];
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x00,0x03);           	/* Set SR0  */
 
-   if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-      	if(SiS_VBInfo&SetCRT2ToLCDA) {
-        	SRdata=SRdata|0x01;
+   SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0];
+
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      	if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+        	SRdata |= 0x01;
         }
    }
-
-   if(SiS_IF_DEF_LVDS==1) {
-     if(SiS_IF_DEF_CH7005==1) {
-       if(SiS_VBInfo&SetCRT2ToTV) {
-         if(SiS_VBInfo&SetInSlaveMode) {
-           SRdata=SRdata|0x01;        					/* 8 dot clock  */
+   if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+     if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+       if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+         if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+           SRdata |= 0x01;        			/* 8 dot clock  */
          }
        }
      }
-     if(SiS_VBInfo&SetCRT2ToLCD) {
-       if(SiS_VBInfo&SetInSlaveMode) {
-         SRdata=SRdata|0x01;          					/* 8 dot clock  */
+     if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+       if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+         SRdata |= 0x01;          			/* 8 dot clock  */
        }
      }
    }
 
-   SRdata=SRdata|0x20;                					/* screen off  */
-   SiS_SetReg1(SiS_P3c4,0x01,SRdata);         				/* Set SR1 */
+   SRdata |= 0x20;                			/* screen off  */
+
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x01,SRdata);
+
    for(i=02;i<=04;i++) {
-     	SRdata=SiS_StandTable[StandTableIndex].SR[i-1];   		/* Get SR2,3,4 from file */
-     	SiS_SetReg1(SiS_P3c4,i,SRdata);                       		/* Set SR2 3 4 */
+       	SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1];
+     	SiS_SetReg1(SiS_Pr->SiS_P3c4,i,SRdata);
    }
 }
 
+/* Checked against 300, 650/301LVx 1.10.6s and 650/LVDS 1.10.07 BIOS */
 void
-SiS_SetMiscRegs(ULONG ROMAddr,USHORT StandTableIndex)
+SiS_SetMiscRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex)
 {
    UCHAR Miscdata;
 
-   Miscdata = SiS_StandTable[StandTableIndex].MISC;    /* Get Misc from file */
-   if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))) {
-      if(SiS_VBInfo&SetCRT2ToLCDA) {
-        Miscdata=Miscdata|0x0C;
+   Miscdata = SiS_Pr->SiS_StandTable[StandTableIndex].MISC;
+
+   if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) {
+        Miscdata |= 0x0C;
       }
     }
-   SiS_SetReg3(SiS_P3c2,Miscdata);                         /* Set Misc(3c2) */
+
+   SiS_SetReg3(SiS_Pr->SiS_P3c2,Miscdata);
 }
 
+/* Checked against 300, 650/LVDS (1.10.07) and 650/301LVx (1.10.6s) BIOS (630 code still there!) */
 void
-SiS_SetCRTCRegs(ULONG ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+SiS_SetCRTCRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
                 USHORT StandTableIndex)
 {
   UCHAR CRTCdata;
   USHORT i;
 
-  CRTCdata=(UCHAR)SiS_GetReg1(SiS_P3d4,0x11);
-  CRTCdata=CRTCdata&0x7f;
-  SiS_SetReg1(SiS_P3d4,0x11,CRTCdata);                     /* Unlock CRTC */
+  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);                       /* Unlock CRTC */
 
   for(i=0;i<=0x18;i++) {
-     CRTCdata=SiS_StandTable[StandTableIndex].CRTC[i];     /* Get CRTC from file */
-     SiS_SetReg1(SiS_P3d4,i,CRTCdata);                     /* Set CRTC(3d4) */
+     CRTCdata=SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,i,CRTCdata);                     /* Set CRTC(3d4) */
   }
-  if((HwDeviceExtension->jChipType==SIS_630)&&
-     (HwDeviceExtension->jChipRevision==0x30)) {           /* for 630S0 */
-    if(SiS_VBInfo&SetInSlaveMode) {
-      if(SiS_VBInfo&(SetCRT2ToLCD|SetCRT2ToTV)) {
-        SiS_SetReg1(SiS_P3d4,0x18,0xFE);
+  if( ( (HwDeviceExtension->jChipType == SIS_630) ||
+        (HwDeviceExtension->jChipType == SIS_730) )  &&
+      (HwDeviceExtension->jChipRevision >= 0x30) ) {       	   /* for 630S0 */
+    if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+      if(SiS_Pr->SiS_VBInfo & (SetCRT2ToLCD | SetCRT2ToTV)) {
+        SiS_SetReg1(SiS_Pr->SiS_P3d4,0x18,0xFE);
       }
     }
   }
 }
 
+/* TW: Checked against 300, 650/LVDS (1.10.07), 650/301LVx (1.10.6s) and 630/301B BIOS */
 void
-SiS_SetATTRegs(ULONG ROMAddr,USHORT StandTableIndex)
+SiS_SetATTRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex,USHORT ModeNo,
+               PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
    UCHAR ARdata;
    USHORT i;
 
    for(i=0;i<=0x13;i++) {
-    ARdata = SiS_StandTable[StandTableIndex].ATTR[i];     /* Get AR for file  */
-    if(SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV)) {
-      if(SiS_VBInfo&SetCRT2ToLCDA) {
-         if(i==0x13) ARdata=0;
+    ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
+#if 0
+    if((i <= 0x0f) || (i == 0x11)) {
+        if(ds:489 & 0x08) {
+	   continue;
+        }
+    }
+#endif
+    if(i == 0x13) {
+      if(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) {
+        if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)  ARdata=0;
+      }
+      if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+        if(SiS_Pr->SiS_IF_DEF_CH70xx != 0) {
+          if(SiS_Pr->SiS_VBInfo & SetCRT2ToTV) {
+            if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) ARdata=0;
+          }
+        }
+      }
+      if(SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) {
+        if(HwDeviceExtension->jChipType >= SIS_315H) {
+	  /* TW: From 650/LVDS 1.10.07, 1.10a; 650/301LVx 1.10.6s */
+	  ARdata = 0;
+	} else {
+          if(SiS_Pr->SiS_VBInfo & SetInSlaveMode) {
+	     ARdata=0;
+          }
+	}
       }
     }
-    if (SiS_IF_DEF_LVDS==1) {                             /*for LVDS  */
-       if(SiS_IF_DEF_CH7005==1) {
-         if(SiS_VBInfo&SetCRT2ToTV) {
-           if(SiS_VBInfo&SetInSlaveMode) {
-             if(i==0x13) ARdata=0;
-           }
-         }
-       }
-       if(SiS_VBInfo&SetCRT2ToLCD) {
-         if(SiS_VBInfo&SetInSlaveMode) {
-           if(SiS_LCDInfo&LCDNonExpanding) {
-             if(i==0x13) ARdata=0;
-           }
-         }
-       }
-     }
-     SiS_GetReg2(SiS_P3da);                              /* reset 3da  */
-     SiS_SetReg3(SiS_P3c0,i);                            /* set index  */
-     SiS_SetReg3(SiS_P3c0,ARdata);                       /* set data   */
+    SiS_GetReg2(SiS_Pr->SiS_P3da);                              /* reset 3da  */
+    SiS_SetReg3(SiS_Pr->SiS_P3c0,i);                            /* set index  */
+    SiS_SetReg3(SiS_Pr->SiS_P3c0,ARdata);                       /* set data   */
    }
-   SiS_GetReg2(SiS_P3da);                                /* reset 3da  */
-   SiS_SetReg3(SiS_P3c0,0x14);                           /* set index  */
-   SiS_SetReg3(SiS_P3c0,0x00);                           /* set data   */
+   SiS_GetReg2(SiS_Pr->SiS_P3da);                               /* reset 3da  */
+   SiS_SetReg3(SiS_Pr->SiS_P3c0,0x14);                          /* set index  */
+   SiS_SetReg3(SiS_Pr->SiS_P3c0,0x00);                          /* set data   */
 
-   SiS_GetReg2(SiS_P3da);                                /* Enable Attribute  */
-   SiS_SetReg3(SiS_P3c0,0x20);
+   SiS_GetReg2(SiS_Pr->SiS_P3da);                               /* Enable Attribute  */
+   SiS_SetReg3(SiS_Pr->SiS_P3c0,0x20);
 }
 
+/* TW: Checked against 300, 650/LVDS (1.10.07, 1.10a) and 650/301LV BIOS */
 void
-SiS_SetGRCRegs(ULONG ROMAddr,USHORT StandTableIndex)
+SiS_SetGRCRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex)
 {
    UCHAR GRdata;
    USHORT i;
 
    for(i=0;i<=0x08;i++) {
-     GRdata = SiS_StandTable[StandTableIndex].GRC[i]; 	  /* Get GR from file */
-     SiS_SetReg1(SiS_P3ce,i,GRdata);                      /* Set GR(3ce) */
+     GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i]; 	  	/* Get GR from file */
+     SiS_SetReg1(SiS_Pr->SiS_P3ce,i,GRdata);                    /* Set GR(3ce) */
    }
 
-   if(SiS_ModeType>ModeVGA) {
-     GRdata=(UCHAR)SiS_GetReg1(SiS_P3ce,0x05);
-     GRdata=GRdata&0xBF;                                  /* 256 color disable */
-     SiS_SetReg1(SiS_P3ce,0x05,GRdata);
+   if(SiS_Pr->SiS_ModeType > ModeVGA) {
+     SiS_SetRegAND(SiS_Pr->SiS_P3ce,0x05,0xBF);			/* 256 color disable */
    }
 }
 
+/* TW: Checked against 650/LVDS (1.10.07, 1.10a), 650/301LVx (1.10.6s) and 630/301B BIOS */
 void
-SiS_ClearExt1Regs()
+SiS_ClearExt1Regs(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT i;
 
-  for(i=0x0A;i<=0x0E;i++) SiS_SetReg1(SiS_P3c4,i,0x00);      /* Clear SR0A-SR0E */
+  for(i=0x0A;i<=0x0E;i++) SiS_SetReg1(SiS_Pr->SiS_P3c4,i,0x00);      /* Clear SR0A-SR0E */
+
+  /* TW: New from 650/LVDS/301LV BIOSes: */
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+     SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x37,0xFE);
+  }
 }
 
+/* TW: Checked against 300, 650/LVDS (1.10.07) and 650/301LV BIOS */
 void
-SiS_SetSync(ULONG ROMAddr,USHORT RefreshRateTableIndex)
+SiS_SetSync(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT RefreshRateTableIndex)
 {
   USHORT sync;
   USHORT temp;
 
-  sync = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag >> 8;  /* di+0x00 */
+  sync = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag >> 8;
 
-  sync=sync&0xC0;
-  temp=0x2F;
-  temp=temp|sync;
-  SiS_SetReg3(SiS_P3c2,temp);                                 /* Set Misc(3c2) */
+  sync &= 0xC0;
+  temp = 0x2F | sync;
+  SiS_SetReg3(SiS_Pr->SiS_P3c2,temp);                                 /* Set Misc(3c2) */
 }
 
+/* TW: Checked against 300, 650/LVDS (1.10.07) and 650/301LVx (1.10.6s) BIOS */
 void
-SiS_SetCRT1CRTC(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                USHORT RefreshRateTableIndex)
+SiS_SetCRT1CRTC(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                USHORT RefreshRateTableIndex,
+		PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   UCHAR  index;
-  UCHAR  data;
-  USHORT temp,tempah,i,modeflag,j;
+  USHORT tempah,i,modeflag,j;
+#ifdef SIS315H
+  USHORT temp;
   USHORT ResInfo,DisplayType;
-  SiS_LCDACRT1DataStruct *LCDACRT1Ptr=NULL;
+  const SiS_LCDACRT1DataStruct *LCDACRT1Ptr = NULL;
+#endif
+
+  SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x11,0x7f);		/*unlock cr0-7  */
+
+  if(ModeNo<=0x13) {
+        modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  } else {
+        modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  }
+
+  if((SiS_Pr->SiS_IF_DEF_LVDS == 0) && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)) {
+
+#ifdef SIS315H
+
+     /* LCDA */
+
+     temp = SiS_GetLCDACRT1Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+                       RefreshRateTableIndex,&ResInfo,&DisplayType);
 
-  if((SiS_VBType&VB_SIS302B)&&(SiS_VBInfo&SetCRT2ToLCDA)
-  	&& (SiS_IF_DEF_LVDS==0) ) { /* TW: Added LVDS check */
-     /*add crt1ptr*/
-     if(ModeNo<=0x13) {
-       modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;      /* si+St_ResInfo */
-     } else {
-       modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;     /* si+Ext_ResInfo */
-     }
-     temp= SiS_GetLCDACRT1Ptr(ROMAddr,ModeNo,ModeIdIndex,RefreshRateTableIndex,
-                       &ResInfo,&DisplayType);
-  
      switch(DisplayType) {
-      case 0 : LCDACRT1Ptr = SiS_LCDACRT1800x600_1;           break;
-      case 1 : LCDACRT1Ptr = SiS_LCDACRT11024x768_1;          break;
-      case 2 : LCDACRT1Ptr = SiS_LCDACRT11280x1024_1;         break;
-      case 3 : LCDACRT1Ptr = SiS_LCDACRT1800x600_1_H;         break;
-      case 4 : LCDACRT1Ptr = SiS_LCDACRT11024x768_1_H;        break;
-      case 5 : LCDACRT1Ptr = SiS_LCDACRT11280x1024_1_H;       break;
-      case 6 : LCDACRT1Ptr = SiS_LCDACRT1800x600_2;           break;
-      case 7 : LCDACRT1Ptr = SiS_LCDACRT11024x768_2;          break;
-      case 8 : LCDACRT1Ptr = SiS_LCDACRT11280x1024_2;         break;
-      case 9 : LCDACRT1Ptr = SiS_LCDACRT1800x600_2_H;         break;
-      case 10: LCDACRT1Ptr = SiS_LCDACRT11024x768_2_H;        break;
-      case 11: LCDACRT1Ptr = SiS_LCDACRT11280x1024_2_H;       break;
-      /*case 12: LCDACRT1Ptr = SiS_CHTVCRT1UNTSC;             break;
-      case 13: LCDACRT1Ptr = SiS_CHTVCRT1ONTSC;               break;
-      case 14: LCDACRT1Ptr = SiS_CHTVCRT1UPAL;                break;
-      case 15: LCDACRT1Ptr = SiS_CHTVCRT1OPAL;                break;*/
-     }
-
-     tempah=(UCHAR)SiS_GetReg1(SiS_P3d4,0x11);                        /*unlock cr0-7  */
-     tempah=tempah&0x7F;
-     SiS_SetReg1(SiS_P3d4,0x11,tempah);
+      case Panel_800x600       : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT1800x600_1;           break;
+      case Panel_1024x768      : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_1;          break;
+      case Panel_1280x1024     : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_1;         break;
+      case Panel_1400x1050     : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_1;         break;
+      case Panel_1600x1200     : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_1;         break;
+      case Panel_800x600 + 16  : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT1800x600_1_H;         break;
+      case Panel_1024x768 + 16 : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_1_H;        break;
+      case Panel_1280x1024 + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_1_H;       break;
+      case Panel_1400x1050 + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_1_H;       break;
+      case Panel_1600x1200 + 16: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_1_H;       break;
+      case Panel_800x600 + 32  : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT1800x600_2;           break;
+      case Panel_1024x768 + 32 : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_2;          break;
+      case Panel_1280x1024 + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_2;         break;
+      case Panel_1400x1050 + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_2;         break;
+      case Panel_1600x1200 + 32: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_2;         break;
+      case Panel_800x600 + 48  : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT1800x600_2_H;         break;
+      case Panel_1024x768 + 48 : LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_2_H;        break;
+      case Panel_1280x1024 + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11280x1024_2_H;       break;
+      case Panel_1400x1050 + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11400x1050_2_H;       break;
+      case Panel_1600x1200 + 48: LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11600x1200_2_H;       break;
+      default:                   LCDACRT1Ptr = SiS_Pr->SiS_LCDACRT11024x768_1;          break;
+     }
+
      tempah = (LCDACRT1Ptr+ResInfo)->CR[0];
-     SiS_SetReg1(SiS_P3d4,0x0,tempah);
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x00,tempah);
      for(i=0x01,j=1;i<=0x07;i++,j++){
        tempah = (LCDACRT1Ptr+ResInfo)->CR[j];
-       SiS_SetReg1(SiS_P3d4,i,tempah);
+       SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
      }
-     /* for(i=0x06,j=5;i<=0x07;i++,j++){
-       tempah = (LCDACRT1Ptr+ResInfo)->CR[j];
-       SiS_SetReg1(SiS_P3d4,i,tempah);
-     }*/
      for(i=0x10,j=8;i<=0x12;i++,j++){
        tempah = (LCDACRT1Ptr+ResInfo)->CR[j];
-       SiS_SetReg1(SiS_P3d4,i,tempah);
+       SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
      }
      for(i=0x15,j=11;i<=0x16;i++,j++){
        tempah =(LCDACRT1Ptr+ResInfo)->CR[j];
-       SiS_SetReg1(SiS_P3d4,i,tempah);
+       SiS_SetReg1(SiS_Pr->SiS_P3d4,i,tempah);
      }
      for(i=0x0A,j=13;i<=0x0C;i++,j++){
        tempah = (LCDACRT1Ptr+ResInfo)->CR[j];
-       SiS_SetReg1(SiS_P3c4,i,tempah);
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,i,tempah);
      }
-  
+
      tempah = (LCDACRT1Ptr+ResInfo)->CR[16];
-     tempah=tempah&0x0E0;
-     SiS_SetReg1(SiS_P3c4,0x0E,tempah);
-  
+     tempah &= 0x0E0;
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x0E,tempah);
+
      tempah = (LCDACRT1Ptr+ResInfo)->CR[16];
-     tempah=tempah&0x01;
-     tempah=tempah<<5;
-     if(modeflag&DoubleScanMode){
-       tempah=tempah|0x080;
-     }
-     SiS_SetRegANDOR(SiS_P3d4,0x09,~0x020,tempah);
-     if(SiS_ModeType>0x03) SiS_SetReg1(SiS_P3d4,0x14,0x4F);
-  /*end 301b*/
-  }
-  else {  /* LVDS */
-     index=SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;  		/* Get index */
-     index=index&0x3F;
-
-     if(SiS_IF_DEF_FSTN) {						/*fstn*/
-        index=index&0x7F;	/* TW: First AND it with 3F, now with 7F ??? */
-     }
-     data=(UCHAR)SiS_GetReg1(SiS_P3d4,0x11);
-     data=data&0x7F;
-     SiS_SetReg1(SiS_P3d4,0x11,data);                             	/* Unlock CRTC */
+     tempah &= 0x01;
+     tempah <<= 5;
+     if(modeflag & DoubleScanMode)  tempah |= 0x080;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,~0x020,tempah);
+
+#endif
+
+  } else {
+
+     /* LVDS, 301, 301B, 301LV, 302LV, ... (non-LCDA) */
+
+     index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;  	/* Get index */
+     if(HwDeviceExtension->jChipType < SIS_315H) {
+        index &= 0x3F;
+     }
 
      for(i=0,j=0;i<=07;i++,j++) {
-       data=SiS_CRT1Table[index].CR[i];
-       SiS_SetReg1(SiS_P3d4,j,data);
+       tempah=SiS_Pr->SiS_CRT1Table[index].CR[i];
+       SiS_SetReg1(SiS_Pr->SiS_P3d4,j,tempah);
      }
      for(j=0x10;i<=10;i++,j++) {
-       data=SiS_CRT1Table[index].CR[i];
-       SiS_SetReg1(SiS_P3d4,j,data);
+       tempah=SiS_Pr->SiS_CRT1Table[index].CR[i];
+       SiS_SetReg1(SiS_Pr->SiS_P3d4,j,tempah);
      }
      for(j=0x15;i<=12;i++,j++) {
-       data=SiS_CRT1Table[index].CR[i];
-       SiS_SetReg1(SiS_P3d4,j,data);
+       tempah=SiS_Pr->SiS_CRT1Table[index].CR[i];
+       SiS_SetReg1(SiS_Pr->SiS_P3d4,j,tempah);
      }
      for(j=0x0A;i<=15;i++,j++) {
-       data=SiS_CRT1Table[index].CR[i];
-       SiS_SetReg1(SiS_P3c4,j,data);
+       tempah=SiS_Pr->SiS_CRT1Table[index].CR[i];
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,j,tempah);
      }
 
-     data=SiS_CRT1Table[index].CR[16];
-     data=data&0xE0;
-     SiS_SetReg1(SiS_P3c4,0x0E,data);
+     tempah = SiS_Pr->SiS_CRT1Table[index].CR[16];
+     tempah &= 0xE0;
+     SiS_SetReg1(SiS_Pr->SiS_P3c4,0x0E,tempah);
 
-     data=(UCHAR)SiS_GetReg1(SiS_P3d4,0x09);
-     data=data&0xDF;                                      /* clear CR9 D[5] */
-     i=SiS_CRT1Table[index].CR[16];
-     i=i&0x01;
-     i=i<<5;
-     data=data|i;
+     tempah = SiS_Pr->SiS_CRT1Table[index].CR[16];
+     tempah &= 0x01;
+     tempah <<= 5;
+     if(modeflag & DoubleScanMode)  tempah |= 0x80;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x09,0xDF,tempah);
 
-     if (ModeNo<=0x13)
-       i = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
-     else
-       i = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  }
 
-     i=i&DoubleScanMode;
-     if(i) data=data|0x80;
-     SiS_SetReg1(SiS_P3d4,0x09,data);
+  if(SiS_Pr->SiS_ModeType > ModeVGA) SiS_SetReg1(SiS_Pr->SiS_P3d4,0x14,0x4F);
+}
 
-     if(SiS_ModeType>0x03) SiS_SetReg1(SiS_P3d4,0x14,0x4F);
+BOOLEAN
+SiS_GetLCDACRT1Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+		   USHORT RefreshRateTableIndex,USHORT *ResInfo,
+		   USHORT *DisplayType)
+ {
+  USHORT tempbx=0,modeflag=0;
+  USHORT CRT2CRTC=0;
+
+  if(ModeNo<=0x13) {
+  	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+  	CRT2CRTC = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+  } else {
+  	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  	CRT2CRTC = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
   }
+
+  tempbx = SiS_Pr->SiS_LCDResInfo;
+
+  if(SiS_Pr->SiS_LCDInfo & LCDNonExpanding) tempbx += 32;
+  if(modeflag & HalfDCLK)                   tempbx += 16;
+
+  *ResInfo = CRT2CRTC & 0x3F;
+  *DisplayType = tempbx;
+
+  return 1;
 }
 
-/* TW: Set offset ("pitch") - overruled by SetPitch in XF86 */
+/* TW: Set offset and pitch - partly overruled by SetPitch() in XF86 */
+/* TW: Checked against 650/LVDS (1.10.07), 650/301LV and 315 BIOS */
 void
-SiS_SetCRT1Offset(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+SiS_SetCRT1Offset(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
                   USHORT RefreshRateTableIndex,
 		  PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-   USHORT temp,ah,al;
-   USHORT temp2,i;
-   USHORT DisplayUnit;
+   USHORT temp, DisplayUnit, infoflag;
+
+   infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+
+   DisplayUnit = SiS_GetOffset(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+                     RefreshRateTableIndex,HwDeviceExtension);
+
+   temp = (DisplayUnit >> 8) & 0x0f;
+   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0E,0xF0,temp);
 
-   /* Alan */
-   temp = SiS_EModeIDTable[ModeIdIndex].Ext_ModeInfo;
+   temp = DisplayUnit & 0xFF;
+   SiS_SetReg1(SiS_Pr->SiS_P3d4,0x13,temp);
+
+   if(infoflag & InterlaceMode) DisplayUnit >>= 1;
+
+   DisplayUnit <<= 5;
+   temp = (DisplayUnit & 0xff00) >> 8;
+   if (DisplayUnit & 0xff) temp++;
+   temp++;
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x10,temp);
+}
+
+/* TW: New from 650/LVDS 1.10.07, 630/301B and 630/LVDS BIOS */
+void
+SiS_ResetCRT1VCLK(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+{
+   USHORT index;
+
+   /* TW: We only need to do this if Panel Link is to be
+    *     initialized, thus on 630/LVDS/301B, and 650/LVDS
+    */
    if(HwDeviceExtension->jChipType >= SIS_315H) {
-     temp=temp>>8;         /* sis310 */
+       if (SiS_Pr->SiS_IF_DEF_LVDS == 0)  return;
    } else {
-     temp=temp>>4;         /* sis300 */
+       if( (SiS_Pr->SiS_IF_DEF_LVDS == 0) &&
+           (!(SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)) ) {
+	   return;
+      }
    }
-   temp=SiS_ScreenOffset[temp];
 
-   if((ModeNo>=0x7C)&&(ModeNo<=0x7E)) {
-     /* TW: 1280x960 */
-     temp=0x6B;  /* TW: Why? Offset for 1280 is normally 0x50! */
-     temp2=ModeNo-0x7C;
-     /* TW: SiS_ModeType-ModeEGA (below) is 1,3 or 5, not 0,1,or 2 */
-     temp2=(temp2*2)+1; /* TW: Maybe this is more correct? */
-   }
-   else {
-     temp2 = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
-     temp2=temp2&InterlaceMode;
-     if(temp2) temp=temp<<1;
-     temp2=SiS_ModeType-ModeEGA;
-   }
-
-   switch (temp2) {
-     case 0 : temp2=1; break;
-     case 1 : temp2=2; break;
-     case 2 : temp2=4; break;
-     case 3 : temp2=4; break;
-     case 4 : temp2=6; break;
-     case 5 : temp2=8; break;
-   }
-   temp=temp*temp2;
-   DisplayUnit=temp;
-
-   temp2=temp;
-   temp=temp>>8;                                         /* ah */
-   temp=temp&0x0F;
-   i=SiS_GetReg1(SiS_P3c4,0x0E);
-   i=i&0xF0;
-   i=i|temp;
-   SiS_SetReg1(SiS_P3c4,0x0E,i);
-
-   temp=(UCHAR)temp2;
-   temp=temp&0xFF;                                        /* al */
-   SiS_SetReg1(SiS_P3d4,0x13,temp);
-
-   temp2 = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
-   temp2=temp2&InterlaceMode;
-   if(temp2) DisplayUnit>>=1;
-
-   DisplayUnit=DisplayUnit<<5;
-   ah=(DisplayUnit&0xff00)>>8;
-   al=DisplayUnit&0x00ff;
-   if(al==0) ah=ah+1;
-   else ah=ah+2;
-   SiS_SetReg1(SiS_P3c4,0x10,ah);
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+   	SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xCF,0x20);
+   } else {
+   	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,0x20);
+   }
+   index = 1;
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[index].SR2B);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[index].SR2C);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2D,0x80);
+   if(HwDeviceExtension->jChipType >= SIS_315H) {
+   	SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x31,0xcf,0x10);
+   } else {
+   	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,0x10);
+   }
+   index = 0;
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[index].SR2B);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[index].SR2C);
+   SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2D,0x80);
 }
 
+/* TW: Checked against 300, 650/LVDS, 650/301LVx, 315, 630/301B, 630/LVDS BIOS */
 void
-SiS_SetCRT1VCLK(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+SiS_SetCRT1VCLK(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
                 PSIS_HW_DEVICE_INFO HwDeviceExtension,
 		USHORT RefreshRateTableIndex)
 {
-  UCHAR  index,data;
-  USHORT vclkindex;
-
-  /* TW: Now I'm confused. Is IF_DEF_LVDS 1 even for 301B/302B/301LV/302lV?
-   *     This functions could make one believe that LVDS is 0 for these. But
-   *     in this case SetGroup1_LVDS doesn't make sense (see init301.c)
-   *     So my conclusion is that LVDS = 1 for some of the SiS bridges as
-   *     well, i just don't know which ones...
-   */
+  USHORT  index;
 
-  if(SiS_IF_DEF_LVDS==1) {
+  index = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+	                  RefreshRateTableIndex,HwDeviceExtension);
 
-        /* TW: Do this if IF_DEF_LVDS is 1 */
+  if( (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV)
+                       && (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA) ){
 
-    	index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+    	SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xCF);
 
-    	/*if(HwDeviceExtension->jChipType < SIS_315H) { */
-    	index=index&0x3F;
-    	/*}*/
-    	data = SiS_GetReg1(SiS_P3c4,0x31) & 0xCF;
-	SiS_SetReg1(SiS_P3c4,0x31,data);
-	/* SiS_SetReg1(SiS_P3c4,0x31,0x00); 	     */                 /* for300 */
-
-    	SiS_SetReg1(SiS_P3c4,0x2B,SiS_VCLKData[index].SR2B);
-    	SiS_SetReg1(SiS_P3c4,0x2C,SiS_VCLKData[index].SR2C);
-	
-    	if(HwDeviceExtension->jChipType < SIS_315H)
-      		SiS_SetReg1(SiS_P3c4,0x2D,0x80);                        /* for300 series */
-   	else
-      		SiS_SetReg1(SiS_P3c4,0x2D,0x01);                        /* for310 series */
-  }
-
-  else if( (SiS_VBType&(VB_SIS301B|VB_SIS302B|VB_SIS301LV|VB_SIS302LV))
-               && (SiS_VBInfo&SetCRT2ToLCDA)
-	       && (SiS_IF_DEF_LVDS==0) ){  /* TW: I did NOT include this here */
+    	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VBVCLKData[index].Part4_A);
+    	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VBVCLKData[index].Part4_B);
 
-        /* TW: Do this if bridge type is 301B/302B/301LV/302LV
-	 *     (This can only be called if LVDS is 0...)
-	 */
-	 
-    	vclkindex = SiS_GetVCLK2Ptr(ROMAddr,ModeNo,ModeIdIndex,
-	                     RefreshRateTableIndex,HwDeviceExtension);
-    	data = SiS_GetReg1(SiS_P3c4,0x31) & 0xCF;
-    	SiS_SetReg1(SiS_P3c4,0x31,data);
-
-    	data = SiS_VBVCLKData[vclkindex].Part4_A;
-    	SiS_SetReg1(SiS_P3c4,0x2B,data);
-    	data = SiS_VBVCLKData[vclkindex].Part4_B;
-    	SiS_SetReg1(SiS_P3c4,0x2C,data);
-
-    	if(HwDeviceExtension->jChipType < SIS_315H)
-    		SiS_SetReg1(SiS_P3c4,0x2D,0x80);                        /* for300 series */
-    	else
-    		SiS_SetReg1(SiS_P3c4,0x2D,0x01);
-  }
-  else {
-
-	/* TW: Do this if LVDS is 0 and the brigde type is NOT
-	 *     301B/302B/301LV/302LV. This leaves only 301...
-	 *     (or 301B/.. if not LCDA)
-	 */
+    	if(HwDeviceExtension->jChipType >= SIS_315H) {
+		SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2D,0x01);
+   	} else {
+    		SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2D,0x80);
+    	}
 
-    	index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
-    	/*if(HwDeviceExtension->jChipType < SIS_315H) { */
-    	index=index&0x3F;
-    	/*}*/
-    	data = SiS_GetReg1(SiS_P3c4,0x31) & 0xCF;
-	SiS_SetReg1(SiS_P3c4,0x31,data);
-	/*SiS_SetReg1(SiS_P3c4,0x31,0x00); */                       	/* for300 */
+  } else {
 
-    	SiS_SetReg1(SiS_P3c4,0x2B,SiS_VCLKData[index].SR2B);
-    	SiS_SetReg1(SiS_P3c4,0x2C,SiS_VCLKData[index].SR2C);
-    	if(HwDeviceExtension->jChipType < SIS_315H)
-      		SiS_SetReg1(SiS_P3c4,0x2D,0x80);                        /* for300 series */
-    	else
-      		SiS_SetReg1(SiS_P3c4,0x2D,0x01);                        /* for310 series */
+	if(HwDeviceExtension->jChipType >= SIS_315H) {
+	    SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x31,0xCF);
+	} else {
+	    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x31,0x00);
+	}
+
+    	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2B,SiS_Pr->SiS_VCLKData[index].SR2B);
+    	SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2C,SiS_Pr->SiS_VCLKData[index].SR2C);
+
+    	if(HwDeviceExtension->jChipType >= SIS_315H) {
+	    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2D,0x01);
+	} else {
+      	    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x2D,0x80);
+        }
   }
 }
 
+#if 0  /* TW: Not used */
 void
-SiS_IsLowResolution(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SiS_IsLowResolution(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
-  USHORT data;
   USHORT ModeFlag;
 
-  data = SiS_GetReg1(SiS_P3c4,0x0F);
-  data = data&0x7F;
-  SiS_SetReg1(SiS_P3c4,0x0F,data);
+  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0F,0x7F);
 
-  if (ModeNo>0x13) {
-    ModeFlag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+  if(ModeNo > 0x13) {
+    ModeFlag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
     if ((ModeFlag & HalfDCLK) && (ModeFlag & DoubleScanMode)) {
-      data = SiS_GetReg1(SiS_P3c4,0x0F);
-      data = data|0x80;
-      SiS_SetReg1(SiS_P3c4,0x0F,data);
-      data = SiS_GetReg1(SiS_P3c4,0x01);
-      data = data&0xF7;
-      SiS_SetReg1(SiS_P3c4,0x01,data);
+      SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0F,0x80);
+      SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x01,0xF7);
     }
   }
 }
+#endif
 
+/* TW: Checked against 300, 630/LVDS, 650/LVDS and 315 BIOS */
 void
-SiS_SetCRT1ModeRegs(ULONG ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+SiS_SetCRT1ModeRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
                     USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex)
 {
   USHORT data,data2,data3;
   USHORT infoflag=0,modeflag;
   USHORT resindex,xres;
 
-  if (ModeNo>0x13) {
-    	modeflag = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-    	infoflag = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+  if(ModeNo > 0x13) {
+    	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    	infoflag = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
   } else {
-    	modeflag = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;    /* si+St_ModeFlag */
+    	modeflag = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
   }
 
-  SiS_SetRegANDOR(SiS_P3c4,0x1F,0x3F,0x00); 	/* DAC pedestal */
+  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1F,0x3F); 		/* DAC pedestal */
 
-  if(ModeNo>0x13) data=infoflag;
-  else data=0;
-  data2=SiS_GetReg1(SiS_P3c4,0x06) & 0xC0;  /* TW: Preserve Xv display mode!!! */
-  if(ModeNo>0x13) {
-    if(SiS_ModeType>0x02) {
-       data2=data2|0x02;
-       data3=SiS_ModeType-ModeVGA;
-       data3=data3<<2;
-       data2=data2|data3;
-    }
-  }
-  data=data&InterlaceMode;
-  if(data) data2=data2|0x20;
-  SiS_SetReg1(SiS_P3c4,0x06,data2);
-
-  if((HwDeviceExtension->jChipType==SIS_630)||
-     (HwDeviceExtension->jChipType==SIS_540)||
-     (HwDeviceExtension->jChipType==SIS_730)) {
-    resindex=SiS_GetResInfo(ROMAddr,ModeNo,ModeIdIndex);
-    if(ModeNo<=0x13)
-      	xres=SiS_StResInfo[resindex].HTotal;
-    else
-      	xres=SiS_ModeResInfo[resindex].HTotal;                         /* xres->ax */
-    data=0x0000;
-    if(infoflag&InterlaceMode) {
-      if(xres==1024) data=0x0035;
-      if(xres==1280) data=0x0048;
-    }
-    data2=data&0x00FF;
-    SiS_SetRegANDOR(SiS_P3d4,0x19,0xFF,data2);
-    data2=(data&0xFF00)>>8;
-    SiS_SetRegANDOR(SiS_P3d4,0x19,0xFC,data2);
-  }
-
-  if(modeflag&HalfDCLK) {
-    SiS_SetRegANDOR(SiS_P3c4,0x01,0xFF,0x01);
-  }
-
-  if((HwDeviceExtension->jChipType==SIS_630)||
-     (HwDeviceExtension->jChipType==SIS_540)||
-     (HwDeviceExtension->jChipType==SIS_730)){
-     /* TW: This was missing here for modes > 1024x768: */
-    if(modeflag&LineCompareOff) {
-      SiS_SetRegANDOR(SiS_P3c4,0x0F,0xF7,0x08);
-    } else {
-      SiS_SetRegANDOR(SiS_P3c4,0x0F,0xF7,0x00);
+  if(ModeNo > 0x13) data = infoflag;
+  else data = 0;
+
+  data2 = 0;
+  if(ModeNo > 0x13) {
+    if(SiS_Pr->SiS_ModeType > 0x02) {
+       data2 |= 0x02;
+       data3 = (SiS_Pr->SiS_ModeType - ModeVGA) << 2;
+       data2 |= data3;
     }
+  }
+  if(data & InterlaceMode) data2 |= 0x20;
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x06,0xC0, data2);
+
+  resindex = SiS_GetResInfo(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex);
+  if(ModeNo <= 0x13) {
+      	xres = SiS_Pr->SiS_StResInfo[resindex].HTotal;
   } else {
-    if(modeflag&LineCompareOff) {
-      SiS_SetRegANDOR(SiS_P3c4,0x0F,0xF7,0x08);
-    } else {
-      SiS_SetRegANDOR(SiS_P3c4,0x0F,0xF7,0x00);
-    }
+      	xres = SiS_Pr->SiS_ModeResInfo[resindex].HTotal;
+  }
+
+  if(HwDeviceExtension->jChipType != SIS_300) {
+     data = 0x0000;
+     if(infoflag & InterlaceMode) {
+        if(xres == 1024) data = 0x0035;
+        else data = 0x0048;
+     }
+     data2 = data & 0x00FF;
+     SiS_SetReg1(SiS_Pr->SiS_P3d4,0x19,data2);
+     data2 = (data & 0xFF00) >> 8;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x1a,0xFC,data2);
+  }
+
+  if(modeflag & HalfDCLK) {
+     SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x01,0x08);
+  }
+
+  if(HwDeviceExtension->jChipType == SIS_300) {
+     if(modeflag & LineCompareOff) {
+        SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0F,0x08);
+     } else {
+        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0F,0xF7);
+     }
+  } else if(HwDeviceExtension->jChipType < SIS_315H) {
+     if(modeflag & LineCompareOff) {
+        SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,0x08);
+     } else {
+        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0F,0xB7);
+     }
+     /* 630 BIOS does something for mode 0x12 here */
+  } else {
+     if(modeflag & LineCompareOff) {
+        SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xB7,0x08);
+     } else {
+        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x0F,0xB7);
+     }
+  }
+
+  if(HwDeviceExtension->jChipType != SIS_300) {
+     if(SiS_Pr->SiS_ModeType == ModeEGA) {
+        if(ModeNo > 0x13) {
+  	   SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x0F,0x40);
+        }
+     }
   }
 
-  data=0x60;
-  if(SiS_ModeType!=ModeText) {
-      data=data^0x60;
-      if(SiS_ModeType!=ModeEGA) {
-        data=data^0xA0;
+#ifdef SIS315H
+  /* TW: 315 BIOS sets SR17 at this point */
+  if(HwDeviceExtension->jChipType == SIS_315PRO) {
+      data = SiS_Get310DRAMType(SiS_Pr,ROMAddr,HwDeviceExtension);
+      data = SiS_Pr->SiS_SR15[2][data];
+      if(SiS_Pr->SiS_ModeType == ModeText) {
+          data &= 0xc7;
+      } else {
+          data2 = SiS_GetOffset(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+                                RefreshRateTableIndex,HwDeviceExtension);
+	  data2 >>= 1;
+	  if(infoflag & InterlaceMode) data2 >>= 1;
+	  data3 = SiS_GetColorDepth(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex);
+	  data3 >>= 1;
+	  if(data3 == 0) data3++;
+	  data2 /= data3;
+	  if(data2 >= 0x50) {
+	      data &= 0x0f;
+	      data |= 0x50;
+	  }
+      }
+      SiS_SetReg1(SiS_Pr->SiS_P3c4,0x17,data);
+  }
+#endif
+
+  data = 0x60;
+  if(SiS_Pr->SiS_ModeType != ModeText) {
+      data ^= 0x60;
+      if(SiS_Pr->SiS_ModeType != ModeEGA) {
+        data ^= 0xA0;
       }
   }
-  SiS_SetRegANDOR(SiS_P3c4,0x21,0x1F,data);
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x21,0x1F,data);
+
+  SiS_SetVCLKState(SiS_Pr,ROMAddr,HwDeviceExtension,ModeNo,RefreshRateTableIndex,ModeIdIndex);
+
+#ifdef SIS315H
+  if(HwDeviceExtension->jChipType >= SIS_315H) {
+    if(SiS_GetReg1(SiS_Pr->SiS_P3d4,0x31) & 0x40) {
+        SiS_SetReg1(SiS_Pr->SiS_P3d4,0x52,0x2c);
+    } else {
+        SiS_SetReg1(SiS_Pr->SiS_P3d4,0x52,0x6c);
+    }
+  }
+#endif
 }
 
+/* TW: Checked against 300, 315, 650/LVDS, 650/301LVx, 630/301B and 630/LVDS BIOS */
 void
-SiS_SetVCLKState(ULONG ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                 USHORT ModeNo,USHORT RefreshRateTableIndex)
+SiS_SetVCLKState(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                 USHORT ModeNo,USHORT RefreshRateTableIndex,
+                 USHORT ModeIdIndex)
 {
-   USHORT data,data2=0;
-   USHORT VCLK;
-   UCHAR  index=0;
+  USHORT data, data2=0;
+  USHORT VCLK, index=0;
 
-  if (ModeNo<=0x13) VCLK=0;
+  if (ModeNo <= 0x13) VCLK = 0;
   else {
-    index = SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
-    /*if(HwDeviceExtension->jChipType < SIS_315H) { */
-    index=index&0x3F;
-    /*}*/
-    VCLK = SiS_VCLKData[index].CLOCK;
+     index = SiS_GetVCLK2Ptr(SiS_Pr,ROMAddr,ModeNo,ModeIdIndex,
+	               RefreshRateTableIndex,HwDeviceExtension);
+     VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
   }
 
-  if(HwDeviceExtension->jChipType < SIS_315H) {
-    data2=0x00;
-    if(VCLK>150) data2=data2|0x80;
-    SiS_SetRegANDOR(SiS_P3c4,0x07,0x7B,data2); 	/* DAC speed */
-
-    data2=0x00;
-    if(VCLK>=150) data2=data2|0x08;       	/* VCLK > 150 */
-    SiS_SetRegANDOR(SiS_P3c4,0x32,0xF7,data2);
-  } else { /* 310 series */
-    data=SiS_GetReg1(SiS_P3c4,0x32);
-    data=data&0xf3;
-    if(VCLK>=200) data=data|0x0c;         	/* VCLK > 200 */
-    SiS_SetReg1(SiS_P3c4,0x32,data);
-    data=SiS_GetReg1(SiS_P3c4,0x1F);	  	/* DAC pedestal */
+  if(HwDeviceExtension->jChipType < SIS_315H) {		/* 300 series */
+
+    data2 = 0x00;
+    if(VCLK > 150) data2 |= 0x80;
+    SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0x7B,data2); 	/* DAC speed */
+
+    data2 = 0x00;
+    if(VCLK >= 150) data2 |= 0x08;       	/* VCLK > 150 */
+    SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xF7,data2);
+
+  } else { 						/* 310/325 series */
+
+    data = 0;
+    if(VCLK >= 166) data |= 0x0c;         	/* TW: Was 200; is 166 in 650 and 315 BIOSes */
+    SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x32,0xf3,data);
+
+    if(VCLK >= 166) {				/* TW: Was 200, is 166 in 650 and 315 BIOSes */
+       SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x1f,0xe7);
+    }
+#if 0 /* Not done in 315 and 650/301LV/LVDS BIOSes: */
+    data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1F);	  	/* DAC pedestal */
     data &= 0xE7;
     if(VCLK<200) data |= 0x10;
-    SiS_SetReg1(SiS_P3c4,0x1F,data);	  	/* DAC pedestal */
+    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1F,data);	  	/* DAC pedestal */
+#endif
   }
 
-  if(VCLK<135) data2=0x03;
-  if((VCLK>=135)&&(VCLK<160)) data2=0x02;
-  if((VCLK>=160)&&(VCLK<260)) data2=0x01;
-  if(VCLK>260) data2=0x00;
+  data2 = 0x03;
+  if((VCLK >= 135) && (VCLK < 160)) data2 = 0x02;
+  if((VCLK >= 160) && (VCLK < 260)) data2 = 0x01;
+  if(VCLK >= 260) data2 = 0x00;
   /* disable 24bit palette RAM gamma correction  */
-  if(HwDeviceExtension->jChipType==SIS_540) {
-    	if((VCLK==203)||(VCLK<234)) data2=0x02;
+  if(HwDeviceExtension->jChipType == SIS_540) {
+    	if((VCLK == 203) || (VCLK < 234)) data2 = 0x02;
+  }
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xFC,data2);  	/* DAC speed */
+  } else {
+      if(HwDeviceExtension->jChipType > SIS_315PRO) {
+         /* TW: This "if" is done in 650/LVDS/301LV BIOSes; Not in 315 BIOS */
+         if(ModeNo > 0x13) data2 &= 0xfc;
+      }
+      SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x07,0xF8,data2);  	/* DAC speed */
   }
-  SiS_SetRegANDOR(SiS_P3c4,0x07,0xFC,data2);  	/* DAC speed */
 }
 
+/* TW: Checked against 650/301LVx 1.10.6s, 315, 630/301B BIOS */
 void
-SiS_LoadDAC(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
+SiS_LoadDAC(SiS_Private *SiS_Pr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+            UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex)
 {
    USHORT data,data2;
    USHORT time,i,j,k;
    USHORT m,n,o;
    USHORT si,di,bx,dl;
    USHORT al,ah,dh;
-   USHORT *table=NULL;
+   USHORT DACAddr, DACData, shiftflag;
+   const USHORT *table = NULL;
+#if 0
+   USHORT tempah,tempch,tempcl,tempdh,tempal,tempbx;
+#endif
 
    if (ModeNo<=0x13)
-        data = SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
+        data = SiS_Pr->SiS_SModeIDTable[ModeIdIndex].St_ModeFlag;
    else
-        data = SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+        data = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
-   data=data&DACInfoFlag;
-   time=64;
-   if(data==0x00) table=SiS_MDA_DAC;
-   if(data==0x08) table=SiS_CGA_DAC;
-   if(data==0x10) table=SiS_EGA_DAC;
-   if(data==0x18) {
-     time=256;
-     table=SiS_VGA_DAC;
-   }
-   if(time==256) j=16;
-   else j=time;
-
-   SiS_SetReg3(SiS_P3c6,0xFF);
-   SiS_SetReg3(SiS_P3c8,0x00);
-
-   for(i=0;i<j;i++) {
-      data=table[i];
-      for(k=0;k<3;k++) {
-        data2=0;
-        if(data&0x01) data2=0x2A;
-        if(data&0x02) data2=data2+0x15;
-        SiS_SetReg3(SiS_P3c9,data2);
-        data=data>>2;
-      }
-   }
+#if 0
+   if(!(ds:489 & 0x08)) {
+#endif
 
-   if(time==256) {
-      for(i=16;i<32;i++) {
-         data=table[i];
-         for(k=0;k<3;k++) SiS_SetReg3(SiS_P3c9,data);
-      }
-      si=32;
-      for(m=0;m<9;m++) {
-         di=si;
-         bx=si+0x04;
-         dl=0;
-         for(n=0;n<3;n++) {
-            for(o=0;o<5;o++) {
-              dh=table[si];
-              ah=table[di];
-              al=table[bx];
-              si++;
-              SiS_WriteDAC(dl,ah,al,dh);
-            }         /* for 5 */
-            si=si-2;
-            for(o=0;o<3;o++) {
-              dh=table[bx];
-              ah=table[di];
-              al=table[si];
-              si--;
-              SiS_WriteDAC(dl,ah,al,dh);
-            }         /* for 3 */
-            dl++;
-         }            /* for 3 */
-         si=si+5;
-      }               /* for 9 */
-   }
+	data &= DACInfoFlag;
+	time = 64;
+	if(data == 0x00) table = SiS_MDA_DAC;
+	if(data == 0x08) table = SiS_CGA_DAC;
+	if(data == 0x10) table = SiS_EGA_DAC;
+	if(data == 0x18) {
+	   time = 256;
+	   table = SiS_VGA_DAC;
+	}
+	if(time == 256) j = 16;
+	else            j = time;
+
+	if( ( (HwDeviceExtension->jChipType < SIS_315H) &&         /* 630/301B */
+	      (SiS_Pr->SiS_VBType & VB_SIS301BLV302BLV) &&
+	      (SiS_Pr->SiS_VBInfo & SetCRT2ToLCD) )         ||
+	    (SiS_Pr->SiS_VBInfo & SetCRT2ToLCDA)            ||     /* LCDA */
+	    (!(SiS_Pr->SiS_SetFlag & ProgrammingCRT2)) ) {         /* Programming CRT1 */
+	   DACAddr = SiS_Pr->SiS_P3c8;
+	   DACData = SiS_Pr->SiS_P3c9;
+	   shiftflag = 0;
+	   SiS_SetReg3(SiS_Pr->SiS_P3c6,0xFF);
+	} else {
+	   shiftflag = 1;
+	   DACAddr = SiS_Pr->SiS_Part5Port;
+	   DACData = SiS_Pr->SiS_Part5Port + 1;
+	}
+
+	SiS_SetReg3(DACAddr,0x00);
+
+	for(i=0; i<j; i++) {
+	   data = table[i];
+	   for(k=0; k<3; k++) {
+		data2 = 0;
+		if(data & 0x01) data2 = 0x2A;
+		if(data & 0x02) data2 += 0x15;
+		if(shiftflag) data2 <<= 2;
+		SiS_SetReg3(DACData,data2);
+		data >>= 2;
+	   }
+	}
+
+	if(time == 256) {
+	   for(i = 16; i < 32; i++) {
+		data = table[i];
+		if(shiftflag) data <<= 2;
+		for(k=0; k<3; k++) SiS_SetReg3(DACData,data);
+	   }
+	   si = 32;
+	   for(m = 0; m < 9; m++) {
+	      di = si;
+	      bx = si + 4;
+	      dl = 0;
+	      for(n = 0; n < 3; n++) {
+		 for(o = 0; o < 5; o++) {
+		    dh = table[si];
+		    ah = table[di];
+		    al = table[bx];
+		    si++;
+		    SiS_WriteDAC(SiS_Pr,DACData,shiftflag,dl,ah,al,dh);
+		 }
+		 si -= 2;
+		 for(o = 0; o < 3; o++) {
+		    dh = table[bx];
+		    ah = table[di];
+		    al = table[si];
+		    si--;
+		    SiS_WriteDAC(SiS_Pr,DACData,shiftflag,dl,ah,al,dh);
+		 }
+		 dl++;
+	      }            /* for n < 3 */
+	      si += 5;
+	   }               /* for m < 9 */
+	}
+#if 0
+    }  /* ds:489 & 0x08 */
+#endif
+
+#if 0
+    if((!(ds:489 & 0x08)) && (ds:489 & 0x06)) {
+           tempbx = 0;
+	   for(i=0; i< 256; i++) {
+               SiS_SetReg3(SiS_Pr->SiS_P3c8-1,tempbx);    	/* 7f87 */
+               tempah = SiS_GetReg3(SiS_Pr->SiS_P3c8+1);  	/* 7f83 */
+	       tempch = SiS_GetReg3(SiS_Pr->SiS_P3c8+1);
+	       tempcl = SiS_GetReg3(SiS_Pr->SiS_P3c8+1);
+	       tempdh = tempah;
+	       tempal = 0x4d * tempdh;          	/* 7fb8 */
+	       tempbx += tempal;
+	       tempal = 0x97 * tempch;
+	       tempbx += tempal;
+	       tempal = 0x1c * tempcl;
+	       tempbx += tempal;
+	       if((tempbx & 0x00ff) > 0x80) tempbx += 0x100;
+	       tempdh = (tempbx & 0x00ff) >> 8;
+	       tempch = tempdh;
+	       tempcl = tempdh;
+	       SiS_SetReg3(SiS_Pr->SiS_P3c8,(tempbx & 0xff));  	/* 7f7c */
+	       SiS_SetReg3(SiS_Pr->SiS_P3c8+1,tempdh);          /* 7f92 */
+	       SiS_SetReg3(SiS_Pr->SiS_P3c8+1,tempch);
+	       SiS_SetReg3(SiS_Pr->SiS_P3c8+1,tempcl);
+           }
+    }
+#endif
 }
 
 void
-SiS_WriteDAC(USHORT dl, USHORT ah, USHORT al, USHORT dh)
+SiS_WriteDAC(SiS_Private *SiS_Pr, USHORT DACData, USHORT shiftflag,
+             USHORT dl, USHORT ah, USHORT al, USHORT dh)
 {
   USHORT temp;
   USHORT bh,bl;
 
-  bh=ah;
-  bl=al;
-  if(dl!=0) {
-    temp=bh;
-    bh=dh;
-    dh=temp;
-    if(dl==1) {
-       temp=bl;
-       bl=dh;
-       dh=temp;
+  bh = ah;
+  bl = al;
+  if(dl != 0) {
+    temp = bh;
+    bh = dh;
+    dh = temp;
+    if(dl == 1) {
+       temp = bl;
+       bl = dh;
+       dh = temp;
     } else {
-       temp=bl;
-       bl=bh;
-       bh=temp;
+       temp = bl;
+       bl = bh;
+       bh = temp;
     }
   }
-  SiS_SetReg3(SiS_P3c9,(USHORT)dh);
-  SiS_SetReg3(SiS_P3c9,(USHORT)bh);
-  SiS_SetReg3(SiS_P3c9,(USHORT)bl);
+  if(shiftflag) {
+     dh <<= 2;
+     bh <<= 2;
+     bl <<= 2;
+  }
+  SiS_SetReg3(DACData,(USHORT)dh);
+  SiS_SetReg3(DACData,(USHORT)bh);
+  SiS_SetReg3(DACData,(USHORT)bl);
 }
 
 ULONG
-GetDRAMSize(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+GetDRAMSize(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  ULONG   AdapterMemorySize=0;
+  ULONG   AdapterMemorySize = 0;
 #ifdef SIS315H
   USHORT  counter;
 #endif
-  
+
 #ifdef SIS315H
-  if ((HwDeviceExtension->jChipType == SIS_315H)||
+  if ((HwDeviceExtension->jChipType == SIS_315H) ||
       (HwDeviceExtension->jChipType == SIS_315PRO)) {
-    	counter = SiS_GetReg1(SiS_P3c4,0x14)&0xF0; 	/*get memory size*/
-    	counter >>= 4;
-    	AdapterMemorySize= 1 << counter;
-    	AdapterMemorySize *= 1024*1024;
-  } else {
-    	if ((HwDeviceExtension->jChipType == SIS_550)||
-            (HwDeviceExtension->jChipType == SIS_640)||
-            (HwDeviceExtension->jChipType == SIS_740)||
+    	counter = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+	AdapterMemorySize = 1 << ((counter & 0xF0) >> 4);
+	counter >>= 2;
+	counter &= 0x03;
+	if(counter == 0x02) {
+		AdapterMemorySize += (AdapterMemorySize / 2);      /* DDR asymetric */
+	} else if(counter != 0) {
+		AdapterMemorySize <<= 1;                           /* SINGLE_CHANNEL_2_RANK or DUAL_CHANNEL_1_RANK */
+	}
+	AdapterMemorySize *= (1024*1024);
+
+  } else if((HwDeviceExtension->jChipType == SIS_550) ||
+            (HwDeviceExtension->jChipType == SIS_640) ||
+            (HwDeviceExtension->jChipType == SIS_740) ||
             (HwDeviceExtension->jChipType == SIS_650)) {
-      		counter = SiS_GetReg1(SiS_P3c4,0x14)&0x3F; /*get memory size*/
+      		counter = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14) & 0x3F;
       		counter++;
       		AdapterMemorySize = counter * 4;
-      		AdapterMemorySize *= 1024*1024;
-		/* TW: FIXME: Some 550 BIOSes don't set up SR14 correctly. We
-		 * will have to read PCI configuration for a correct memory
-		 * size. (However, this is checked in framebuffer driver;
-		 * X does not use this function but if it ever will, this will
-		 * become an issue.)
-		 */
-    	}
+      		AdapterMemorySize *= (1024*1024);
   }
 #endif
 
 #ifdef SIS300
-  if ((HwDeviceExtension->jChipType==SIS_300)||
-      (HwDeviceExtension->jChipType==SIS_540)||
-      (HwDeviceExtension->jChipType==SIS_630)||
+  if ((HwDeviceExtension->jChipType==SIS_300) ||
+      (HwDeviceExtension->jChipType==SIS_540) ||
+      (HwDeviceExtension->jChipType==SIS_630) ||
       (HwDeviceExtension->jChipType==SIS_730)) {
-      	AdapterMemorySize = SiS_GetReg1(SiS_P3c4,0x14); /*get memory size*/
-      	AdapterMemorySize = AdapterMemorySize&0x3F;
+      	AdapterMemorySize = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14) & 0x3F;
       	AdapterMemorySize++;
-      	AdapterMemorySize *= 1024*1024;
+      	AdapterMemorySize *= (1024*1024);
   }
 #endif
 
   return AdapterMemorySize;
 }
 
+#ifndef LINUX_XF86
 void
-SiS_ClearBuffer(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo)
+SiS_ClearBuffer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo)
 {
   PVOID   VideoMemoryAddress = (PVOID)HwDeviceExtension->pjVideoMemoryAddress;
   ULONG   AdapterMemorySize  = (ULONG)HwDeviceExtension->ulVideoMemorySize;
   PUSHORT pBuffer;
   int i;
 
-  if (SiS_ModeType>=ModeEGA) {
-    if (ModeNo>0x13) {
-      AdapterMemorySize=GetDRAMSize(HwDeviceExtension);
+  if (SiS_Pr->SiS_ModeType>=ModeEGA) {
+    if(ModeNo > 0x13) {
+      AdapterMemorySize = GetDRAMSize(SiS_Pr, HwDeviceExtension);
       SiS_SetMemory(VideoMemoryAddress,AdapterMemorySize,0);
     } else {
       pBuffer = VideoMemoryAddress;
-      for (i=0;i<0x4000;i++)
-        pBuffer[i]=0x0000;
+      for(i=0; i<0x4000; i++)
+         pBuffer[i] = 0x0000;
     }
   } else {
     pBuffer = VideoMemoryAddress;
-    if (SiS_ModeType<ModeCGA) {
-      for (i=0;i<0x4000;i++)
-        pBuffer[i]=0x0720;
+    if (SiS_Pr->SiS_ModeType < ModeCGA) {
+      for(i=0; i<0x4000; i++)
+         pBuffer[i] = 0x0720;
     } else {
       SiS_SetMemory(VideoMemoryAddress,0x8000,0);
     }
   }
 }
+#endif
 
 void
-SiS_DisplayOn(void)
+SiS_DisplayOn(SiS_Private *SiS_Pr)
 {
-   SiS_SetRegANDOR(SiS_P3c4,0x01,0xDF,0x00);
+   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x01,0xDF,0x00);
 }
 
 void
-SiS_DisplayOff(void)
+SiS_DisplayOff(SiS_Private *SiS_Pr)
 {
-   SiS_SetRegANDOR(SiS_P3c4,0x01,0xDF,0x20);
+   SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x01,0xDF,0x20);
 }
 
 
 /* ========================================== */
 /*  SR CRTC GR */
 void
-SiS_SetReg1(
-   USHORT  port,
-   USHORT  index,
-   USHORT  data
-   )
+SiS_SetReg1(USHORT port, USHORT index, USHORT data)
 {
    OutPortByte(port,index);
    OutPortByte(port+1,data);
-   
-   /*
-   _asm
-   {
-         mov      dx, port                      
-         mov      ax, index                     
-         mov      bx, data                      
-         out      dx, al
-         mov      ax, bx
-         inc      dx
-         out      dx, al
-   }
-   */
-
 }
 
 /* ========================================== */
 /*  AR(3C0) */
 void
-SiS_SetReg2(
-   USHORT  port,
-   USHORT  index,
-   USHORT  data
-   )
+SiS_SetReg2(SiS_Private *SiS_Pr, USHORT port, USHORT index, USHORT data)
 {
-
    InPortByte(port+0x3da-0x3c0);
-   OutPortByte(SiS_P3c0,index);
-   OutPortByte(SiS_P3c0,data);
-   OutPortByte(SiS_P3c0,0x20);
-
-   /*
-   _asm
-   {
-         mov      dx, port                      
-         mov      cx, index                     
-         mov      bx, data                      
-
-         add      dx, 3dah-3c0h
-         in       al, dx
-
-         mov      ax, cx
-         mov      dx, 3c0h
-         out      dx, al
-         mov      ax, bx
-         out      dx, al
-
-         mov      ax, 20h
-         out      dx, al
-   }
-   */
-
+   OutPortByte(SiS_Pr->SiS_P3c0,index);
+   OutPortByte(SiS_Pr->SiS_P3c0,data);
+   OutPortByte(SiS_Pr->SiS_P3c0,0x20);
 }
 
-/* ========================================== */
 void
-SiS_SetReg3(
-   USHORT  port,
-   USHORT  data
-   )
+SiS_SetReg3(USHORT port, USHORT data)
 {
-
    OutPortByte(port,data);
-   
-   /*
-   _asm
-   {
-         mov      dx, port                      
-         mov      ax, data                      
-         out      dx, al
-
-   }
-   */
-
 }
 
-/* ========================================== */
 void
-SiS_SetReg4(
-   USHORT  port,
-   ULONG   data
-   )
+SiS_SetReg4(USHORT port, ULONG data)
 {
-
    OutPortLong(port,data);
-
-   /*
-   _asm
-   {
-         mov      dx, port                      ;; port
-         mov      eax, data                      ;; data
-         out      dx, eax
-
-   }
-   */
 }
 
-/* ========================================= */
-UCHAR
-SiS_GetReg1(
-   USHORT  port,
-   USHORT  index
-   )
+UCHAR SiS_GetReg1(USHORT port, USHORT index)
 {
    UCHAR   data;
 
-
    OutPortByte(port,index);
    data = InPortByte(port+1);
 
-   /*
-   _asm
-   {
-         mov      dx, port                      ;; port
-         mov      ax, index                     ;; index
-
-         out      dx, al
-         mov      ax, bx
-         inc      dx
-         xor      eax, eax
-         in       al, dx
-         mov      data, al
-   }
-   */
    return(data);
 }
-/* ========================================== */
+
 UCHAR
-SiS_GetReg2(
-   USHORT  port
-   )
+SiS_GetReg2(USHORT port)
 {
    UCHAR   data;
 
    data= InPortByte(port);
 
-   /*
-   _asm
-   {
-         mov      dx, port                      ;; port
-         xor      eax, eax
-         in       al, dx
-         mov      data, al
-   }
-   */
    return(data);
 }
 
-/* ========================================== */
 ULONG
-SiS_GetReg3(
-   USHORT  port
-   )
+SiS_GetReg3(USHORT port)
 {
    ULONG   data;
 
-
    data = InPortLong(port);
 
-   /*
-   _asm
-   {
-         mov      dx, port                      ;; port
-         xor      eax, eax
-         in       eax, dx
-         mov      data, eax
-   }
-   */
    return(data);
 }
 
-/* ========================================== */
 void
-SiS_ClearDAC(ULONG   port)
+SiS_ClearDAC(SiS_Private *SiS_Pr, ULONG port)
 {
    int i;
 
    OutPortByte(port, 0);
    port++;
-   for (i=0;i<256*3;i++) {
+   for (i=0; i < (256 * 3); i++) {
       OutPortByte(port, 0);
    }
 
 }
-/* ========================================== */
 
+#if 0  /* TW: Unused */
 void
-SiS_SetInterlace(ULONG ROMAddr, USHORT ModeNo,USHORT RefreshRateTableIndex)
+SiS_SetInterlace(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT RefreshRateTableIndex)
 {
   ULONG Temp;
   USHORT data,Temp2;
 
   if (ModeNo<=0x13) return;
-  Temp = (ULONG)SiS_GetReg1(SiS_P3d4, 0x01);
+
+  Temp = (ULONG)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x01);
   Temp++;
-  Temp=Temp*8;
+  Temp <<= 3;
 
-  if(Temp==1024) data=0x0035;
-  else if(Temp==1280) data=0x0048;
-  else data=0x0000;
+  if(Temp == 1024) data = 0x0035;
+  else if(Temp == 1280) data = 0x0048;
+  else data = 0x0000;
 
-  Temp2 = SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+  Temp2 = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
   Temp2 &= InterlaceMode;
   if(Temp2 == 0) data=0x0000;
 
-  SiS_SetReg1(SiS_P3d4,0x19,data);
+  SiS_SetReg1(SiS_Pr->SiS_P3d4,0x19,data);
 
-  Temp = (ULONG)SiS_GetReg1(SiS_P3d4, 0x1A);
-  Temp2= (USHORT)(Temp & 0xFC);
-  SiS_SetReg1(SiS_P3d4,0x1A,(USHORT)Temp);
+  Temp = (ULONG)SiS_GetReg1(SiS_Pr->SiS_P3d4,0x1A);
+  Temp = (USHORT)(Temp & 0xFC);
+  SiS_SetReg1(SiS_Pr->SiS_P3d4,0x1A,(USHORT)Temp);
 
-  Temp = (ULONG)SiS_GetReg1(SiS_P3c4, 0x0f);
-  Temp2= (USHORT)Temp & 0xBF;
-  if(ModeNo==0x37) Temp2=Temp2|0x40;
-  SiS_SetReg1(SiS_P3d4,0x1A,(USHORT)Temp2);
+  Temp = (ULONG)SiS_GetReg1(SiS_Pr->SiS_P3c4,0x0f);
+  Temp2 = (USHORT)Temp & 0xBF;
+  if(ModeNo==0x37) Temp2 |= 0x40;
+  SiS_SetReg1(SiS_Pr->SiS_P3d4,0x1A,(USHORT)Temp2);
 }
+#endif
 
+/* TW: Checked against 650/LVDS (1.10.07), 650/301LVx (1.10.6s) and 315 BIOS */
+#ifdef SIS315H
 void
-SiS_SetCRT1FIFO(ULONG ROMAddr,USHORT ModeNo,PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_SetCRT1FIFO_310(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT  data;
+  USHORT modeflag;
+
+  SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x3D,0xFE);  /* disable auto-threshold */
 
-  data=SiS_GetReg1(SiS_P3c4,0x3D);
-  data &= 0xfe;
-  SiS_SetReg1(SiS_P3c4,0x3D,data);  /* diable auto-threshold */
-  if (ModeNo>0x13) {
-    SiS_SetReg1(SiS_P3c4,0x08,0x34);
-    data=SiS_GetReg1(SiS_P3c4,0x09);
-    data &= 0xF0;
-    SiS_SetReg1(SiS_P3c4,0x09,data);
-
-    data=SiS_GetReg1(SiS_P3c4,0x3D);
-    data |= 0x01;
-    SiS_SetReg1(SiS_P3c4,0x3D,data);
+  if(ModeNo > 0x13) {
+    modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+    if( (!(modeflag & DoubleScanMode)) || (!(modeflag & HalfDCLK))) {
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x08,0x34);
+       SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
+       SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x3D,0x01);
+    } else {
+       SiS_SetReg1(SiS_Pr->SiS_P3c4,0x08,0xAE);
+       SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
+    }
   } else {
-    SiS_SetReg1(SiS_P3c4,0x08,0xAE);
-    data=SiS_GetReg1(SiS_P3c4,0x09);
-    data &= 0xF0;
-    SiS_SetReg1(SiS_P3c4,0x09,data);
+    SiS_SetReg1(SiS_Pr->SiS_P3c4,0x08,0xAE);
+    SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x09,0xF0);
   }
 }
+#endif
+
+#ifdef SIS300
+void
+SiS_SetCRT1FIFO_300(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                    USHORT RefreshRateTableIndex)
+{
+  USHORT  ThresholdLow = 0;
+  USHORT  index, VCLK, MCLK, colorth=0;
+  USHORT  tempah, temp;
+
+  if(ModeNo > 0x13) {
+
+     index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+     index &= 0x3F;
+     VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;             /* Get VCLK  */
+
+     switch (SiS_Pr->SiS_ModeType - ModeEGA) {     /* Get half colordepth */
+        case 0 : colorth = 1; break;
+        case 1 : colorth = 1; break;
+        case 2 : colorth = 2; break;
+        case 3 : colorth = 2; break;
+        case 4 : colorth = 3; break;
+        case 5 : colorth = 4; break;
+     }
+
+     index = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3A);
+     index &= 0x07;
+     MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK;           /* Get MCLK  */
+
+     tempah = SiS_GetReg1(SiS_Pr->SiS_P3d4,0x35);
+     tempah &= 0xc3;
+     SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3c,tempah);
+
+     do {
+        ThresholdLow = SiS_CalcDelay(SiS_Pr, ROMAddr, VCLK, colorth, MCLK);
+        ThresholdLow++;
+        if(ThresholdLow < 0x13) break;
+        SiS_SetRegAND(SiS_Pr->SiS_P3c4,0x16,0xfc);
+        ThresholdLow = 0x13;
+        tempah = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
+        tempah >>= 6;
+        if(!(tempah)) break;
+        tempah--;
+        tempah <<= 6;
+        SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x16,0x3f,tempah);
+     } while(0);
+
+  } else ThresholdLow = 2;
+
+  /* Write CRT/CPU threshold low, CRT/Engine threshold high */
+  temp = (ThresholdLow << 4) | 0x0f;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x08,temp);
+
+  temp = (ThresholdLow & 0x10) << 1;
+  if(ModeNo > 0x13) temp |= 0x40;
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0f,0x9f,temp);
+
+  /* What is this? */
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x3B,0x09);
+
+  /* Write CRT/CPU threshold high */
+  temp = ThresholdLow + 3;
+  if(temp > 0x0f) temp = 0x0f;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x09,temp);
+}
+
+USHORT
+SiS_CalcDelay(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT VCLK, USHORT colordepth, USHORT MCLK)
+{
+  USHORT tempax, tempbx;
+
+  tempbx = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 0);
+  tempax = SiS_DoCalcDelay(SiS_Pr, MCLK, VCLK, colordepth, 1);
+  if(tempax < 4) tempax = 4;
+  tempax -= 4;
+  if(tempbx < tempax) tempbx = tempax;
+  return(tempbx);
+}
+
+USHORT
+SiS_DoCalcDelay(SiS_Private *SiS_Pr, USHORT MCLK, USHORT VCLK, USHORT colordepth, USHORT key)
+{
+  const UCHAR ThLowA[]   = { 61, 3,52, 5,68, 7,100,11,
+                             43, 3,42, 5,54, 7, 78,11,
+                             34, 3,37, 5,47, 7, 67,11 };
+
+  const UCHAR ThLowB[]   = { 81, 4,72, 6,88, 8,120,12,
+                             55, 4,54, 6,66, 8, 90,12,
+                             42, 4,45, 6,55, 8, 75,12 };
+
+  const UCHAR ThTiming[] = {  1, 2, 2, 3, 0, 1,  1, 2 };
+
+  USHORT tempah, tempal, tempcl, tempbx, temp;
+  ULONG  longtemp;
+
+  tempah = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x18);
+  tempah &= 0x62;
+  tempah >>= 1;
+  tempal = tempah;
+  tempah >>= 3;
+  tempal |= tempah;
+  tempal &= 0x07;
+  tempcl = ThTiming[tempal];
+  tempbx = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
+  tempbx >>= 6;
+  tempah = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+  tempah >>= 4;
+  tempah &= 0x0c;
+  tempbx |= tempah;
+  tempbx <<= 1;
+  if(key == 0) {
+     tempal = ThLowA[tempbx + 1];
+     tempal *= tempcl;
+     tempal += ThLowA[tempbx];
+  } else {
+     tempal = ThLowB[tempbx + 1];
+     tempal *= tempcl;
+     tempal += ThLowB[tempbx];
+  }
+  longtemp = tempal * VCLK * colordepth;
+  temp = longtemp % (MCLK * 16);
+  longtemp /= (MCLK * 16);
+  if(temp) longtemp++;
+  return((USHORT)longtemp);
+}
 
+#if 0  /* TW: Old fragment, unused */
 USHORT
-SiS_CalcDelay(ULONG ROMAddr,USHORT key)
+SiS_CalcDelay(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT key)
 {
   USHORT data,data2,temp0,temp1;
   UCHAR   ThLowA[]=   {61,3,52,5,68,7,100,11,
                        43,3,42,5,54,7, 78,11,
                        34,3,37,5,47,7, 67,11};
+
   UCHAR   ThLowB[]=   {81,4,72,6,88,8,120,12,
                        55,4,54,6,66,8, 90,12,
                        42,4,45,6,55,8, 75,12};
+
   UCHAR   ThTiming[]= {1,2,2,3,0,1,1,2};
 
-  data=SiS_GetReg1(SiS_P3c4,0x16);
+  data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x16);
   data=data>>6;
-  data2=SiS_GetReg1(SiS_P3c4,0x14);
+  data2=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
   data2=(data2>>4)&0x0C;
   data=data|data2;
   data=data<1;
@@ -3424,7 +3885,7 @@
   }
 
   data2=0;
-  data=SiS_GetReg1(SiS_P3c4,0x18);
+  data=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x18);
   if(data&0x02) data2=data2|0x01;
   if(data&0x20) data2=data2|0x02;
   if(data&0x40) data2=data2|0x04;
@@ -3432,97 +3893,110 @@
   data=temp1*ThTiming[data2]+temp0;
   return(data);
 }
+#endif
 
 void
-SiS_SetCRT1FIFO2(ULONG ROMAddr,USHORT ModeNo,PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                 USHORT RefreshRateTableIndex)
+SiS_SetCRT1FIFO_630(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                    USHORT RefreshRateTableIndex)
 {
-  USHORT  i,index,data,VCLK,data2,MCLK,colorth=0;
-  ULONG   B,eax,ah,bl;
+  USHORT  i,index,data,VCLK,MCLK,colorth=0;
+  ULONG   B,eax,bl,data2;
   USHORT  ThresholdLow=0;
-  UCHAR   FQBQData[]= { 0x01,0x21,0x41,0x61,0x81,  /* TW: in BIOS at 0xf85 - identical */
+  UCHAR   FQBQData[]= { 0x01,0x21,0x41,0x61,0x81,
                         0x31,0x51,0x71,0x91,0xb1,
                         0x00,0x20,0x40,0x60,0x80,
                         0x30,0x50,0x70,0x90,0xb0,0xFF};
 
-  if(ModeNo>=0x13) {
-    index=SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
-    if(HwDeviceExtension->jChipType < SIS_315H) { /* for300 series */
-      index=index&0x3F;
-    }
-    VCLK=SiS_VCLKData[index].CLOCK;           /* Get VCLK  */
-    index=SiS_GetReg1(SiS_P3c4,0x1A);
-    index=index&07;
-    MCLK=SiS_MCLKData[index].CLOCK;           /* Get MCLK  */
-
-    data2=SiS_ModeType-0x02;
-      switch (data2) {
-        case 0 : colorth=1; break;  /* 1 */
-        case 1 : colorth=1; break;  /* 2 */
-        case 2 : colorth=2; break;  /* 4 */
-        case 3 : colorth=2; break;  /* 4 */
-        case 4 : colorth=3; break;  /* 6 */
-        case 5 : colorth=4; break;  /* 8 */
-      }
+  i=0;
+  if(ModeNo >= 0x13) {
+    index = SiS_Pr->SiS_RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+    index &= 0x3F;
+    VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;             /* Get VCLK  */
+
+    index = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1A);
+    index &= 0x07;
+    MCLK = SiS_Pr->SiS_MCLKData_0[index].CLOCK;           /* Get MCLK  */
+
+    data2 = SiS_Pr->SiS_ModeType - ModeEGA;	  /* Get half colordepth */
+    switch (data2) {
+        case 0 : colorth = 1; break;
+        case 1 : colorth = 1; break;
+        case 2 : colorth = 2; break;
+        case 3 : colorth = 2; break;
+        case 4 : colorth = 3; break;
+        case 5 : colorth = 4; break;
+    }
 
-    i=0;
     do{
-       B=(SiS_CalcDelay2(ROMAddr,FQBQData[i])*VCLK*colorth);
+       B = SiS_CalcDelay2(SiS_Pr, ROMAddr, FQBQData[i]) * VCLK * colorth;
+       bl = B / (MCLK * 16);
 
-       bl=B/(16*MCLK);
        if (B==bl*16*MCLK) {
-         bl=bl+1;
+         bl = bl + 1;
        } else {
-         bl=bl+2;  /* TW: was +1 */
+         bl = bl + 2;
        }
 
-       if(bl>0x13) {
-          if(FQBQData[i+1]==0xFF) {
-             ThresholdLow=0x13;
+       if(bl > 0x13) {
+          if(FQBQData[i+1] == 0xFF) {
+             ThresholdLow = 0x13;
              break;
           }
           i++;
        } else {
-          ThresholdLow=bl;
+          ThresholdLow = bl;
           break;
        }
-    } while(FQBQData[i]!=0xFF);
+    } while(FQBQData[i] != 0xFF);
   }
   else {
-    ThresholdLow=0x02;
+    ThresholdLow = 0x02;
   }
 
-  data2=FQBQData[i];
-  data2=(data2&0xf0)>>4;
-  data2=data2<<24;
+  /* Write foreground and background queue */
+  data2 = FQBQData[i];
+  data2 = (data2 & 0xf0)>>4;
+  data2 <<= 24;
 
+#ifndef LINUX_XF86
   SiS_SetReg4(0xcf8,0x80000050);
-  eax=SiS_GetReg3(0xcfc);
-  eax=eax&0xf0ffffff;
-  eax=eax|data2;
+  eax = SiS_GetReg3(0xcfc);
+  eax &= 0xf0ffffff;
+  eax |= data2;
   SiS_SetReg4(0xcfc,eax);
+#else
+  /* We use pci functions X offers. We use pcitag 0, because
+   * we want to read/write to the host bridge (which is always
+   * 00:00.0 on 630, 730 and 540), not the VGA device.
+   */
+  eax = pciReadLong(0x00000000, 0x50);
+  eax &= 0xf0ffffff;
+  eax |= data2;
+  pciWriteLong(0x00000000, 0x50, eax);
+#endif
+
+  /* TODO: write GUI grant timer (PCI config 0xA3) */
+
+  /* Write CRT/CPU threshold low, CRT/Engine threshold high */
+  data = ((ThresholdLow & 0x0f) << 4) | 0x0f;
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x08,data);
+
+  data = (ThresholdLow & 0x10) << 1;
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x0F,0xDF,data);
+
+  /* What is this? */
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x3B,0x09);
 
-  ah=ThresholdLow;
-  ah=ah<<4;
-  ah=ah|0x0f;
-  SiS_SetReg1(SiS_P3c4,0x08,ah);
-
-  data=ThresholdLow;
-  data=data&0x10;
-  data=data<<1;
-  SiS_SetRegANDOR(SiS_P3c4,0x0F,0xDF,data);
-
-  SiS_SetReg1(SiS_P3c4,0x3B,0x09);
-
-  data=ThresholdLow+3;
-  if(data>0x0f) data=0x0f;
-  SiS_SetRegANDOR(SiS_P3c4,0x09,0x80,data);
+  /* Write CRT/CPU threshold high (gap = 3) */
+  data = ThresholdLow + 3;
+  if(data > 0x0f) data = 0x0f;
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3c4,0x09,0x80,data);
 }
 
 USHORT
-SiS_CalcDelay2(ULONG ROMAddr,UCHAR key)
+SiS_CalcDelay2(SiS_Private *SiS_Pr, UCHAR *ROMAddr,UCHAR key)
 {
-  USHORT data,index;	   /* TW: in BIOS at 0x1029 - identical */
+  USHORT data,index;
   UCHAR  LatencyFactor[] ={ 97, 88, 86, 79, 77, 00,       /*; 64  bit    BQ=2   */
                             00, 87, 85, 78, 76, 54,       /*; 64  bit    BQ=1   */
                             97, 88, 86, 79, 77, 00,       /*; 128 bit    BQ=2   */
@@ -3532,174 +4006,246 @@
                             86, 77, 75, 68, 66, 00,       /*; 128 bit    BQ=2   */
                             00, 68, 66, 59, 57, 37};      /*; 128 bit    BQ=1   */
 
-  index=(key&0xE0)>>5;
-  if(key&0x10) index=index+6;
-  if(!(key&0x01)) index=index+24;
-  data=SiS_GetReg1(SiS_P3c4,0x14);
-  if(data&0x0080) index=index+12;
+  index = (key & 0xE0) >> 5;
+  if(key & 0x10) index +=6;
+  if(!(key & 0x01)) index += 24;
+  data = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x14);
+  if(data & 0x0080) index += 12;
 
-  data=LatencyFactor[index];
+  data = LatencyFactor[index];
   return(data);
 }
+#endif
 
-void
-SiS_CRT2AutoThreshold(USHORT  BaseAddr)
+/* =============== Autodetection ================ */
+/*             I N C O M P L E T E                */
+
+BOOLEAN
+SiS_GetPanelID(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-  USHORT  temp1;
-  USHORT  Part1Port;
-  Part1Port=BaseAddr+SIS_CRT2_PORT_04;
-  temp1=SiS_GetReg1(SiS_Part1Port,0x01);
-  temp1 |= 0x40;
-  SiS_SetReg1(SiS_Part1Port,0x01,temp1);
+  const USHORT PanelTypeTable300[16] = {
+      0xc101, 0xc117, 0x0121, 0xc135, 0xc142, 0xc152, 0xc162, 0xc072,
+      0xc181, 0xc192, 0xc1a1, 0xc1b6, 0xc1c2, 0xc0d2, 0xc1e2, 0xc1f2
+  };
+  const USHORT PanelTypeTable31030x[16] = {
+      0xc102, 0xc112, 0x0122, 0xc132, 0xc142, 0xc152, 0xc169, 0xc179,
+      0x0189, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+  };
+  const USHORT PanelTypeTable310LVDS[16] = {
+      0xc111, 0xc122, 0xc133, 0xc144, 0xc155, 0xc166, 0xc177, 0xc188,
+      0xc199, 0xc0aa, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+  };
+  USHORT tempax,tempbx,tempah,temp;
+
+  if(HwDeviceExtension->jChipType < SIS_315H) {
+
+    tempax = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x18);
+    tempbx = tempax & 0x0F;
+    if(!(tempax & 0x10)){
+      if(SiS_Pr->SiS_IF_DEF_LVDS == 1){
+        tempbx = 0;
+        temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x38);
+        if(temp & 0x40) tempbx |= 0x08;
+        if(temp & 0x20) tempbx |= 0x02;
+        if(temp & 0x01) tempbx |= 0x01;
+        temp = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x39);
+        if(temp & 0x80) tempbx |= 0x04;
+      } else {
+        return 0;
+      }
+    }
+    tempbx = PanelTypeTable300[tempbx];
+    tempbx |= LCDSync;
+    temp = tempbx & 0x00FF;
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,0x36,temp);
+    temp = (tempbx & 0xFF00) >> 8;
+    SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),temp);
+
+  } else {
+
+    tempax = tempah = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1a);
+    tempax &= 0x1e;
+    tempax >>= 1;
+    if(SiS_Pr->SiS_IF_DEF_LVDS == 1) {
+       if(tempax == 0) {
+           /* TODO: Include HUGE detection routine
+	            (Probably not worth bothering)
+	    */
+           return 0;
+       }
+       temp = tempax & 0xff;
+       tempax--;
+       tempbx = PanelTypeTable310LVDS[tempax];
+    } else {
+       tempbx = PanelTypeTable31030x[tempax];
+       temp = tempbx & 0xff;
+    }
+    SiS_SetReg1(SiS_Pr->SiS_P3d4,0x36,temp);
+    tempbx = (tempbx & 0xff00) >> 8;
+    temp = tempbx & 0xc1;
+    SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),temp);
+    if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+       temp = tempbx & 0x04;
+       SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x39,0xfb,temp);
+    }
+
+  }
+  return 1;
 }
 
-/* =============  ynlai ============== */
+
+#ifdef LINUXBIOS
+
 void
-SiS_DetectMonitor(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
+SiS_DetectMonitor(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr)
 {
-  UCHAR  DAC_TEST_PARMS[]={0x0F,0x0F,0x0F};
-  UCHAR  DAC_CLR_PARMS[]={0x00,0x00,0x00};
+  UCHAR  DAC_TEST_PARMS[] = {0x0F,0x0F,0x0F};
+  UCHAR  DAC_CLR_PARMS[]  = {0x00,0x00,0x00};
   USHORT SR1F;
 
-  SR1F=SiS_GetReg1(SiS_P3c4,0x1F);		/* DAC pedestal */
-  SiS_SetRegANDOR(SiS_P3c4,0x1F,0xFF,0x04);
-  if(SiS_IF_DEF_LVDS==0) {
-    if(SiS_BridgeIsOn(BaseAddr)) {
-      SiS_SetReg1(SiS_P3d4,0x30,0x41);
+  SR1F = SiS_GetReg1(SiS_Pr->SiS_P3c4,0x1F);		/* backup DAC pedestal */
+  SiS_SetRegOR(SiS_Pr->SiS_P3c4,0x1F,0x04);
+
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 0) {
+    if(!(SiS_BridgeIsOn(SiS_Pr, BaseAddr))) {
+      SiS_SetReg1(SiS_Pr->SiS_P3d4,0x30,0x41);
     }
   }
-  /*SiSSetMode(HwDeviceExtension,0x03);  */ /* ynlai InitMode */
 
-#ifdef LINUX_XF86
-  SiSSetMode(HwDeviceExtension,NULL,0x2E); 
-#else
-  SiSSetMode(HwDeviceExtension,0x2E);   /* alan */
-#endif
-  SiS_SetReg3(SiS_P3c6,0xff);
-  SiS_ClearDAC(SiS_P3c8);
-  SiS_LongWait();
-  SiS_LongWait();
-  SiS_SetRegANDOR(SiS_P3d4,0x32,0xDF,0x00);
-  if(SiS_TestMonitorType(DAC_TEST_PARMS[0],DAC_TEST_PARMS[1],DAC_TEST_PARMS[2])) {
-    SiS_SetRegANDOR(SiS_P3d4,0x32,0xDF,0x20);
-  }
-  if(SiS_TestMonitorType(DAC_TEST_PARMS[0],DAC_TEST_PARMS[1],DAC_TEST_PARMS[2])) {
-    SiS_SetRegANDOR(SiS_P3d4,0x32,0xDF,0x20);
+  SiSSetMode(SiS_Pr,HwDeviceExtension,0x2E);
+  if(HwDeviceExtension->jChipType > SIS_315PRO) {
+     /* TW: On 650 only - enable CRT1 */
+     SiS_SetRegAND(SiS_Pr->SiS_P3d4,0x63,0xbf);
+  }
+  SiS_SetReg3(SiS_Pr->SiS_P3c6,0xff);
+  SiS_ClearDAC(SiS_Pr, SiS_Pr->SiS_P3c8);
+  SiS_LongWait(SiS_Pr);
+  SiS_LongWait(SiS_Pr);
+  SiS_LongWait(SiS_Pr);
+  SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x32,0xDF,0x00);
+  if(SiS_TestMonitorType(SiS_Pr, DAC_TEST_PARMS[0],DAC_TEST_PARMS[1],DAC_TEST_PARMS[2])) {
+    SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x32,0xDF,0x20);
+  } else if(SiS_TestMonitorType(SiS_Pr, DAC_TEST_PARMS[0],DAC_TEST_PARMS[1],DAC_TEST_PARMS[2])) {
+    SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x32,0xDF,0x20);
   }
-  SiS_TestMonitorType(DAC_CLR_PARMS[0],DAC_CLR_PARMS[1],DAC_CLR_PARMS[2]);
-  SiS_SetReg1(SiS_P3c4,0x1F,SR1F);
+  SiS_TestMonitorType(SiS_Pr, DAC_CLR_PARMS[0],DAC_CLR_PARMS[1],DAC_CLR_PARMS[2]);
+
+  SiS_SetReg1(SiS_Pr->SiS_P3c4,0x1F,SR1F);
 }
 
 USHORT
-SiS_TestMonitorType(UCHAR R_DAC,UCHAR G_DAC,UCHAR B_DAC)
+SiS_TestMonitorType(SiS_Private *SiS_Pr, UCHAR R_DAC,UCHAR G_DAC,UCHAR B_DAC)
 {
    USHORT temp,tempbx;
 
-   tempbx=R_DAC*0x4d+G_DAC*0x97+B_DAC*0x1c;
-   if(tempbx>0x80) tempbx=tempbx+0x100;
-   tempbx = (tempbx&0xFF00)>>8;
+   tempbx = R_DAC * 0x4d + G_DAC * 0x97 + B_DAC * 0x1c;
+   if((tempbx & 0x00ff) > 0x80) tempbx += 0x100;
+   tempbx = (tempbx & 0xFF00) >> 8;
    R_DAC = (UCHAR) tempbx;
    G_DAC = (UCHAR) tempbx;
    B_DAC = (UCHAR) tempbx;
 
-   SiS_SetReg3(SiS_P3c8,0x00);
-   SiS_SetReg3(SiS_P3c9,R_DAC);
-   SiS_SetReg3(SiS_P3c9,G_DAC);
-   SiS_SetReg3(SiS_P3c9,B_DAC);
-   SiS_LongWait();
-   temp=SiS_GetReg2(SiS_P3c2);
-   if(temp&0x10) return(1);
+   SiS_SetReg3(SiS_Pr->SiS_P3c8,0x00);
+   SiS_SetReg3(SiS_Pr->SiS_P3c9,R_DAC);
+   SiS_SetReg3(SiS_Pr->SiS_P3c9,G_DAC);
+   SiS_SetReg3(SiS_Pr->SiS_P3c9,B_DAC);
+   SiS_LongWait(SiS_Pr);
+   temp=SiS_GetReg2(SiS_Pr->SiS_P3c2);
+   if(temp & 0x10) return(1);
    else return(0);
 }
 
-/* ---- test ----- */
 void
-SiS_GetSenseStatus(PSIS_HW_DEVICE_INFO HwDeviceExtension,ULONG ROMAddr)
+SiS_GetSenseStatus(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,UCHAR *ROMAddr)
 {
   USHORT tempax=0,tempbx,tempcx,temp;
-  USHORT P2reg0=0,SenseModeNo=0,OutputSelect=*pSiS_OutputSelect;
+  USHORT P2reg0=0,SenseModeNo=0,OutputSelect=*SiS_Pr->pSiS_OutputSelect;
   USHORT ModeIdIndex,i;
   USHORT BaseAddr = (USHORT)HwDeviceExtension->ulIOAddress;
 
-  if(SiS_IF_DEF_LVDS==1){
-    SiS_GetPanelID();
+  if(SiS_Pr->SiS_IF_DEF_LVDS == 1){
+    SiS_GetPanelID(SiS_Pr);
     temp=LCDSense;
-    temp=temp|SiS_SenseCHTV();
+    temp=temp|SiS_SenseCHTV(SiS_Pr);
     tempbx=~(LCDSense|AVIDEOSense|SVIDEOSense);
-    SiS_SetRegANDOR(SiS_P3d4,0x32,tempbx,temp);
+    SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x32,tempbx,temp);
   } else {       /* for 301 */
-    if(SiS_IF_DEF_HiVision==1) {  /* for HiVision */
-      tempax=SiS_GetReg1(SiS_P3c4,0x38);
+    if(SiS_Pr->SiS_IF_DEF_HiVision==1) {  /* for HiVision */
+      tempax=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x38);
       temp=tempax&0x01;
-      tempax=SiS_GetReg1(SiS_P3c4,0x3A);
+      tempax=SiS_GetReg1(SiS_Pr->SiS_P3c4,0x3A);
       temp=temp|(tempax&0x02);
-      SiS_SetRegANDOR(SiS_P3d4,0x32,0xA0,temp);
+      SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x32,0xA0,temp);
     } else {
-      if(SiS_BridgeIsOn(BaseAddr)) {
-        P2reg0 = SiS_GetReg1(SiS_Part2Port,0x00);
-        if(!SiS_BridgeIsEnable(BaseAddr,HwDeviceExtension)) {
+      if(SiS_BridgeIsOn(SiS_Pr, BaseAddr)==0) {    /* TW: Inserted "==0" */
+        P2reg0 = SiS_GetReg1(SiS_Pr->SiS_Part2Port,0x00);
+        if(!(SiS_BridgeIsEnable(SiS_Pr, BaseAddr,HwDeviceExtension))) {
           SenseModeNo=0x2e;
-          temp = SiS_SearchModeID(ROMAddr,SenseModeNo,&ModeIdIndex);
-          SiS_SetFlag = 0x00;
-          SiS_ModeType = ModeVGA;
-          SiS_VBInfo = SetCRT2ToRAMDAC |LoadDACFlag |SetInSlaveMode;
-          SiS_SetCRT2Group301(BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension);
+          temp = SiS_SearchModeID(SiS_Pr, ROMAddr,&SenseModeNo,&ModeIdIndex);
+          SiS_Pr->SiS_SetFlag = 0x00;
+          SiS_Pr->SiS_ModeType = ModeVGA;
+          SiS_Pr->SiS_VBInfo = SetCRT2ToRAMDAC |LoadDACFlag |SetInSlaveMode;
+          SiS_SetCRT2Group301(SiS_Pr, BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension);
           for(i=0;i<20;i++) {
-            SiS_LongWait();
+            SiS_LongWait(SiS_Pr);
           }
         }
-        SiS_SetReg1(SiS_Part2Port,0x00,0x1c);
+        SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x00,0x1c);
         tempax=0;
-        tempbx=*pSiS_RGBSenseData;
-        /*301b*/
-	if(!(SiS_Is301B(BaseAddr))){
-                tempbx=*pSiS_RGBSenseData2;
+        tempbx=*SiS_Pr->pSiS_RGBSenseData;
+	if(SiS_Is301B(SiS_Pr, BaseAddr)){
+                tempbx=*SiS_Pr->pSiS_RGBSenseData2;
         }
-        /*end 301b*/	
         tempcx=0x0E08;
-        if(SiS_Sense(SiS_Part4Port,tempbx,tempcx)){
-          if(SiS_Sense(SiS_Part4Port,tempbx,tempcx)){
+        if(SiS_Sense(SiS_Pr, tempbx,tempcx)){
+          if(SiS_Sense(SiS_Pr, tempbx,tempcx)){
             tempax=tempax|Monitor2Sense;
           }
         }
-
-        tempbx=*pSiS_YCSenseData;
-         /*301b*/
-        if(!(SiS_Is301B(BaseAddr))){
-               tempbx=*pSiS_YCSenseData2;  
+        tempbx=*SiS_Pr->pSiS_YCSenseData;
+        if(SiS_Is301B(SiS_Pr, BaseAddr)){
+               tempbx=*SiS_Pr->pSiS_YCSenseData2;
         }
-        /*301b*/
         tempcx=0x0604;
-        if(SiS_Sense(SiS_Part4Port,tempbx,tempcx)){
-          if(SiS_Sense(SiS_Part4Port,tempbx,tempcx)){
+        if(SiS_Sense(SiS_Pr, tempbx,tempcx)){
+          if(SiS_Sense(SiS_Pr,tempbx,tempcx)){
             tempax=tempax|SVIDEOSense;
           }
         }
 
-        if(OutputSelect&BoardTVType){
-          tempbx=*pSiS_VideoSenseData;
-        /*301b*/
-        if(!(SiS_Is301B(BaseAddr))){
-             tempbx=*pSiS_VideoSenseData2;
+	if(ROMAddr && SiS_Pr->SiS_UseROM) {
+#ifdef SIS300
+	   if((HwDeviceExtension->jChipType==SIS_630)||
+              (HwDeviceExtension->jChipType==SIS_730)) {
+		OutputSelect = ROMAddr[0xfe];
+	   }
+#endif
+#ifdef SIS315H
+	   if(HwDeviceExtension->jChipType >= SIS_315H) {
+	        OutputSelect = ROMAddr[0xf3];
+	   }
+#endif
         }
-        /*end 301b*/
+        if(OutputSelect&BoardTVType){
+          tempbx=*SiS_Pr->pSiS_VideoSenseData;
+          if(SiS_Is301B(SiS_Pr, BaseAddr)){
+             tempbx=*SiS_Pr->pSiS_VideoSenseData2;
+          }
           tempcx=0x0804;
-          if(SiS_Sense(SiS_Part4Port,tempbx,tempcx)){
-            if(SiS_Sense(SiS_Part4Port,tempbx,tempcx)){
+          if(SiS_Sense(SiS_Pr, tempbx,tempcx)){
+            if(SiS_Sense(SiS_Pr, tempbx,tempcx)){
               tempax=tempax|AVIDEOSense;
             }
           }
         } else {
           if(!(tempax&SVIDEOSense)){
-            tempbx=*pSiS_VideoSenseData;
-            /*301b*/
-            if(!(SiS_Is301B(BaseAddr))){
-              tempbx=*pSiS_VideoSenseData2;
+            tempbx=*SiS_Pr->pSiS_VideoSenseData;
+            if(SiS_Is301B(SiS_Pr, BaseAddr)){
+              tempbx=*SiS_Pr->pSiS_VideoSenseData2;
             }
-            /*end 301b*/
             tempcx=0x0804;
-            if(SiS_Sense(SiS_Part4Port,tempbx,tempcx)){
-              if(SiS_Sense(SiS_Part4Port,tempbx,tempcx)){
+            if(SiS_Sense(SiS_Pr,tempbx,tempcx)){
+              if(SiS_Sense(SiS_Pr, tempbx,tempcx)){
                 tempax=tempax|AVIDEOSense;
               }
             }
@@ -3707,61 +4253,60 @@
         }
       }
 
-      if(SiS_SenseLCD(HwDeviceExtension)){
+      if(SiS_SenseLCD(SiS_Pr, HwDeviceExtension)){
         tempax=tempax|LCDSense;
       }
 
       tempbx=0;
       tempcx=0;
-      SiS_Sense(SiS_Part4Port,tempbx,tempcx);
-  
-      if((SiS_VBType&VB_SIS301LV)||(SiS_VBType&VB_SIS302LV)){
-         tempax=tempax&0x00ef;   				/* 301lv to disable CRT2*/
+      SiS_Sense(SiS_Pr, tempbx,tempcx);
+
+      if(SiS_Pr->SiS_VBType & (VB_SIS30xLV|VB_SIS30xLVX)){   /* TW: prev. 301LV|302LV */
+         tempax &= 0x00ef;   /* 301lv to disable CRT2*/
       }
-      SiS_SetRegANDOR(SiS_P3d4,0x32,~0xDF,tempax);
-      SiS_SetReg1(SiS_Part2Port,0x00,P2reg0);
+      SiS_SetRegANDOR(SiS_Pr->SiS_P3d4,0x32,~0xDF,tempax);
+      SiS_SetReg1(SiS_Pr->SiS_Part2Port,0x00,P2reg0);
       if(!(P2reg0&0x20)) {
-        SiS_VBInfo = DisableCRT2Display;
-        SiS_SetCRT2Group301(BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension);
+        SiS_Pr->SiS_VBInfo = DisableCRT2Display;
+        SiS_SetCRT2Group301(SiS_Pr,BaseAddr,ROMAddr,SenseModeNo,HwDeviceExtension);
       }
     }
   }
 }
 
 BOOLEAN
-SiS_Sense(USHORT Part4Port,USHORT tempbx,USHORT tempcx)
+SiS_Sense(SiS_Private *SiS_Pr, USHORT tempbx,USHORT tempcx)
 {
   USHORT temp,i,tempch;
 
-  temp=tempbx&0xFF;
-  SiS_SetReg1(SiS_Part4Port,0x11,temp);
-  temp=(tempbx&0xFF00)>>8;
-  temp=temp|(tempcx&0x00FF);
-  SiS_SetRegANDOR(SiS_Part4Port,0x10,~0x1F,temp);
-
-  for(i=0;i<10;i++) SiS_LongWait();
-
-  tempch=(tempcx&0x7F00)>>8;      /*   ynlai [05/22/2001]  */
-  temp=SiS_GetReg1(SiS_Part4Port,0x03);
-  temp=temp^(0x0E);
-  temp=temp&tempch;               /*   ynlai [05/22/2001]  */
+  temp = tempbx & 0xFF;
+  SiS_SetReg1(SiS_Pr->SiS_Part4Port,0x11,temp);
+  temp = (tempbx & 0xFF00) >> 8;
+  temp |= (tempcx & 0x00FF);
+  SiS_SetRegANDOR(SiS_Pr->SiS_Part4Port,0x10,~0x1F,temp);
+
+  for(i=0; i<10; i++) SiS_LongWait(SiS_Pr);
+
+  tempch = (tempcx & 0x7F00) >> 8;
+  temp = SiS_GetReg1(SiS_Pr->SiS_Part4Port,0x03);
+  temp ^= 0x0E;
+  temp &= tempch;
   if(temp>0) return 1;
   else return 0;
 }
 
 USHORT
-SiS_SenseLCD(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_SenseLCD(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
-/*  USHORT SoftSetting; */
   USHORT temp;
 
-  temp=SiS_GetPanelID();
-  if(!temp)  temp=SiS_GetLCDDDCInfo(HwDeviceExtension);
+  temp=SiS_GetPanelID(SiS_Pr);
+  if(!temp)  temp=SiS_GetLCDDDCInfo(SiS_Pr, HwDeviceExtension);
   return(temp);
 }
 
 BOOLEAN
-SiS_GetLCDDDCInfo(PSIS_HW_DEVICE_INFO HwDeviceExtension)
+SiS_GetLCDDDCInfo(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension)
 {
   USHORT temp;
   /*add lcd sense*/
@@ -3769,79 +4314,32 @@
     	return 0;
   else{
      	temp=(USHORT)HwDeviceExtension->ulCRT2LCDType;
-     	SiS_SetReg1(SiS_P3d4,0x36,temp);
+     	SiS_SetReg1(SiS_Pr->SiS_P3d4,0x36,temp);
   	return 1;
   }
 }
 
-BOOLEAN
-SiS_GetPanelID(void)
-{
-  USHORT PanelTypeTable[16]={ SyncNN | PanelRGB18Bit | Panel800x600  | _PanelType00,
-                              SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType01,
-                              SyncPP | PanelRGB18Bit | Panel800x600  | _PanelType02,
-                              SyncNN | PanelRGB18Bit | Panel640x480  | _PanelType03,
-                              SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType04,
-                              SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType05,
-                              SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType06,
-                              SyncNN | PanelRGB24Bit | Panel1024x768 | _PanelType07,
-                              SyncNN | PanelRGB18Bit | Panel800x600  | _PanelType08,
-                              SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType09,
-                              SyncNN | PanelRGB18Bit | Panel800x600  | _PanelType0A,
-                              SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0B,
-                              SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0C,
-                              SyncNN | PanelRGB24Bit | Panel1024x768 | _PanelType0D,
-                              SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0E,
-                              SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0F
-                              };
-  USHORT tempax,tempbx,temp;
-/*  USHORT return_flag; */
-
-  tempax=SiS_GetReg1(SiS_P3c4,0x18);
-  tempbx=tempax&0x0F;
-  if(!(tempax&0x10)){
-    if(SiS_IF_DEF_LVDS==1){
-      tempbx=0;
-      temp=SiS_GetReg1(SiS_P3c4,0x38);
-      if(temp&0x40) tempbx=tempbx|0x08;
-      if(temp&0x20) tempbx=tempbx|0x02;
-      if(temp&0x01) tempbx=tempbx|0x01;
-      temp=SiS_GetReg1(SiS_P3c4,0x39);
-      if(temp&0x80) tempbx=tempbx|0x04;
-    }else{
-      return 0;
-    }
-  }
-
-  tempbx=tempbx<<1;
-  tempbx=PanelTypeTable[tempbx];
-  tempbx=tempbx|LCDSync;
-  temp=tempbx&0x00FF;
-  SiS_SetReg1(SiS_P3d4,0x36,temp);
-  temp=(tempbx&0xFF00)>>8;
-  SiS_SetRegANDOR(SiS_P3d4,0x37,~(LCDSyncBit|LCDRGB18Bit),temp);
-  return 1;
-}
-
 USHORT
-SiS_SenseCHTV(void)
+SiS_SenseCHTV(SiS_Private *SiS_Pr)
 {
   USHORT temp,push0e,status;
 
   status=0;
-  push0e=SiS_GetCH7005(0x0e);
-  push0e=(push0e<<8)|0x0e;
-  SiS_SetCH7005(0x0b0e);
-  SiS_SetCH7005(0x0110);
-  SiS_SetCH7005(0x0010);
-  temp=SiS_GetCH7005(0x10);
-  if(temp&0x08) status=status|SVIDEOSense;
-  if(temp&0x02) status=status|AVIDEOSense;
-  SiS_SetCH7005(push0e);
+  push0e = SiS_GetCH700x(SiS_Pr, 0x0e);
+  push0e = (push0e << 8) | 0x0e;
+  SiS_SetCH700x(SiS_Pr, 0x0b0e);
+  SiS_SetCH700x(SiS_Pr, 0x0110);
+  SiS_SetCH700x(SiS_Pr, 0x0010);
+  temp = SiS_GetCH700x(SiS_Pr, 0x10);
+  if(temp & 0x08) status |= SVIDEOSense;
+  if(temp & 0x02) status |= AVIDEOSense;
+  SiS_SetCH700x(SiS_Pr, push0e);
   return(status);
 }
+#endif /* LINUXBIOS */
+
+/*  ================ for TC only =================  */
 
-/*  ================for TC only =================  */
 #ifdef TC
 
 int
@@ -3940,74 +4438,418 @@
     /*ModeNo=0x4A; *//* 1024x768x 16bpp */
     /*ModeNo=0x47;*/ /* 800x600x 16bpp */
   }
- /* SiSInit(&HwDeviceExtension);*/
-#ifdef LINUX_XF86
-  SiSSetMode(&HwDeviceExtension,NULL, ModeNo);
-#else
-  SiSSetMode(&HwDeviceExtension,ModeNo);
-#endif
+ /* SiSInit(SiS_Pr, &HwDeviceExtension);*/
+  SiSSetMode(SiS_Pr, &HwDeviceExtension, ModeNo);
 }
-#endif /* TC */
+#endif /* TC END */
+
+/* ================ LINUX XFREE86 ====================== */
+
+/* Helper functions */
 
-/* TW: New for Linux XF86 */
 #ifdef LINUX_XF86
 USHORT
 SiS_CalcModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode)
 {
-   UShort i = (pScrn->bitsPerPixel+7)/8 - 1;
+   SISPtr pSiS = SISPTR(pScrn);
+   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;
    UShort ModeIndex = 0;
+
    switch(mode->HDisplay)
    {
+     case 320:
+          if(mode->VDisplay == 480) {
+                ModeIndex = ModeIndex_320x480[i];
+	  }
+          break;
+     case 512:
+          if(mode->VDisplay == 384) {
+             ModeIndex = ModeIndex_512x384[i];
+	  }
+          break;
      case 640:
-          ModeIndex = ModeIndex_640x480[i];
+          if(mode->VDisplay == 480) {
+             ModeIndex = ModeIndex_640x480[i];
+	  }
           break;
      case 720:
-          if(mode->VDisplay == 480)
-            ModeIndex = ModeIndex_720x480[i];
-          else
-            ModeIndex = ModeIndex_720x576[i];
+          if(mode->VDisplay == 480) {
+                ModeIndex = ModeIndex_720x480[i];
+          } else if(mode->VDisplay == 576) {
+                ModeIndex = ModeIndex_720x576[i];
+          }
           break;
      case 800:
-          ModeIndex = ModeIndex_800x600[i];
+	  if(mode->VDisplay == 600) {
+             ModeIndex = ModeIndex_800x600[i];
+	  } else if(pSiS->VGAEngine == SIS_315_VGA) {
+	     if(mode->VDisplay == 480) {
+	           ModeIndex = ModeIndex_800x480[i];
+             }
+	  }
           break;
      case 1024:
-          ModeIndex = ModeIndex_1024x768[i];
+          if(mode->VDisplay == 768) {
+	        ModeIndex = ModeIndex_1024x768[i];
+	  } else if(pSiS->VGAEngine == SIS_315_VGA) {
+	     if(mode->VDisplay == 576) {
+	        ModeIndex = ModeIndex_1024x576[i];
+             }
+	  } else if(pSiS->VGAEngine == SIS_300_VGA) {
+	     if(mode->VDisplay == 600) {
+	        ModeIndex = ModeIndex_1024x600[i];
+             }
+	  }
           break;
+     case 1152:
+          if(pSiS->VGAEngine == SIS_300_VGA) {
+	     if(mode->VDisplay == 768) {
+	        ModeIndex = ModeIndex_1152x768[i];
+             }
+	  }
+	  break;
      case 1280:
-          if(mode->VDisplay == 960)
-            ModeIndex = ModeIndex_1280x960[i];
-          else
-            ModeIndex = ModeIndex_1280x1024[i];
+          if(mode->VDisplay == 960) {
+             if(pSiS->VGAEngine == SIS_300_VGA) {
+	        ModeIndex = ModeIndex_300_1280x960[i];
+             } else {
+                ModeIndex = ModeIndex_310_1280x960[i];
+             }
+	  } else if (mode->VDisplay == 1024) {
+	     ModeIndex = ModeIndex_1280x1024[i];
+	  } else if(pSiS->VGAEngine == SIS_315_VGA) {
+	     if (mode->VDisplay == 768) {
+	        ModeIndex = ModeIndex_1280x768[i];
+	     } else if (mode->VDisplay == 720) {
+	        ModeIndex = ModeIndex_1280x720[i];
+             }
+	  }
+          break;
+     case 1400:
+          if(pSiS->VGAEngine == SIS_315_VGA) {
+	     if(mode->VDisplay == 1050) {
+	        ModeIndex = ModeIndex_1400x1050[i];
+             }
+	  }
           break;
      case 1600:
-          ModeIndex = ModeIndex_1600x1200[i];
+          if(mode->VDisplay == 1200) {
+             ModeIndex = ModeIndex_1600x1200[i];
+	  }
           break;
      case 1920:
-          ModeIndex = ModeIndex_1920x1440[i];
+          if(mode->VDisplay == 1440) {
+             ModeIndex = ModeIndex_1920x1440[i];
+	  }
+          break;
+     case 2048:
+          if(pSiS->VGAEngine == SIS_315_VGA) {
+	     if(mode->VDisplay == 1536) {
+	         ModeIndex = ModeIndex_2048x1536[i];
+             }
+	  }
           break;
    }
 
    return(ModeIndex);
 }
 
+USHORT
+SiS_CheckCalcModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode, int VBFlags)
+{
+   SISPtr pSiS = SISPTR(pScrn);
+   UShort i = (pSiS->CurrentLayout.bitsPerPixel+7)/8 - 1;    
+   UShort ModeIndex = 0;
+
+   if(VBFlags & CRT2_LCD) {
+
+      if( (mode->HDisplay <= pSiS->LCDwidth) &&
+          (mode->VDisplay <= pSiS->LCDheight) ) {
+
+        if(VBFlags & VB_LVDS) {        		/* LCD on LVDS */
+
+          switch(mode->HDisplay)
+  	  {
+	  case 512:
+		if(mode->VDisplay == 384) {
+		   ModeIndex = ModeIndex_512x384[i];
+		}
+		break;
+	  case 640:
+		if(mode->VDisplay == 480) {
+		   ModeIndex = ModeIndex_640x480[i];
+		}
+		break;
+	  case 800:
+		if(mode->VDisplay == 600) {
+		   ModeIndex = ModeIndex_800x600[i];
+		}
+		break;
+	  case 1024:
+		if(mode->VDisplay == 768) {
+		   ModeIndex = ModeIndex_1024x768[i];
+		} else if(pSiS->VGAEngine == SIS_300_VGA) {
+		   if(mode->VDisplay == 600) {
+		      ModeIndex = ModeIndex_1024x600[i];
+		   }
+		}
+		break;
+	  case 1152:
+		if(pSiS->VGAEngine == SIS_300_VGA) {
+		   if(mode->VDisplay == 768) {
+			ModeIndex = ModeIndex_1152x768[i];
+		   }
+		}
+		break;
+	  case 1280:
+		if(mode->VDisplay == 1024) {
+		   ModeIndex = ModeIndex_1280x1024[i];
+		} else if(pSiS->VGAEngine == SIS_315_VGA) {
+		   if(mode->VDisplay == 768) {
+		      ModeIndex = ModeIndex_1280x768[i];
+		   }
+		}
+		break;
+	  case 1400:
+	        if(mode->VDisplay == 1050) {
+		   if(pSiS->VGAEngine == SIS_315_VGA) {
+		      ModeIndex = ModeIndex_1400x1050[i];
+		   }
+		}
+		break;
+          }
+
+        } else {                       	 	/* LCD on 301(B) */
+
+          switch(mode->HDisplay)
+	  {
+	  case 512:
+		if(mode->VDisplay == 384) {
+		   ModeIndex = ModeIndex_512x384[i];
+		}
+		break;
+	  case 640:
+		if(mode->VDisplay == 480) {
+		   ModeIndex = ModeIndex_640x480[i];
+		}
+		break;
+	  case 800:
+		if(mode->VDisplay == 600) {
+		   ModeIndex = ModeIndex_800x600[i];
+		}
+		break;
+	  case 1024:
+		if(mode->VDisplay == 768) {
+		   ModeIndex = ModeIndex_1024x768[i];
+		} /* else if(pSiS->VGAEngine == SIS_300_VGA) {  --  not supported on 301(B) --
+		   if(mode->VDisplay == 600) {
+			ModeIndex = ModeIndex_1024x600[i];
+		   }
+		} */
+		break;
+	  case 1152:  /* not supported on 301(B) */
+#if 0
+		if(pSiS->VGAEngine == SIS_300_VGA) {
+		   if(mode->VDisplay == 768) {
+			ModeIndex = ModeIndex_1152x768[i];
+		   }
+		}
+#endif
+		break;
+	  case 1280:
+		if(mode->VDisplay == 960) {
+		   if(pSiS->VGAEngine == SIS_300_VGA) {
+		      ModeIndex = ModeIndex_300_1280x960[i];
+		   } else {
+		      ModeIndex = ModeIndex_310_1280x960[i];
+		   }
+                } else if (mode->VDisplay == 1024) {
+	             ModeIndex = ModeIndex_1280x1024[i];
+	        }
+	  case 1600:
+		if(mode->VDisplay == 1200) {
+		   ModeIndex = ModeIndex_1600x1200[i];
+		}
+		break;
+	  }
+
+        }
+
+      }
+
+   } else if(VBFlags & CRT2_TV) {
+
+      if(VBFlags & VB_CHRONTEL) {		/* TV on Chrontel */
+
+        switch(mode->HDisplay)
+	{
+      	case 512:
+		if(mode->VDisplay == 384) {
+		   ModeIndex = ModeIndex_512x384[i];
+		}
+		break;
+	case 640:
+		if(mode->VDisplay == 480) {
+		   ModeIndex = ModeIndex_640x480[i];
+		}
+		break;
+	case 800:
+		if(mode->VDisplay == 600) {
+		   ModeIndex = ModeIndex_800x600[i];
+		}
+		break;
+	case 1024:
+		if(mode->VDisplay == 768) {
+		   if(pSiS->VGAEngine == SIS_315_VGA) {
+		      ModeIndex = ModeIndex_1024x768[i];
+		   }
+		}
+		break;
+        }
+
+      } else {				    /* TV on 301(B) */
+
+        switch(mode->HDisplay)
+	{
+      	case 512:
+		if(mode->VDisplay == 384) {
+		   ModeIndex = ModeIndex_512x384[i];
+		}
+		break;
+	case 640:
+		if(mode->VDisplay == 480) {
+		   ModeIndex = ModeIndex_640x480[i];
+		}
+		break;
+	case 720:
+                if(mode->VDisplay == 480) {
+                   ModeIndex = ModeIndex_720x480[i];
+                } else if(mode->VDisplay == 576) {
+                   ModeIndex = ModeIndex_720x576[i];
+                }
+                break;
+	case 800:
+		if(mode->VDisplay == 600) {
+		   ModeIndex = ModeIndex_800x600[i];
+		}
+		break;
+	case 1024:
+		if(mode->VDisplay == 768) {
+		   if(VBFlags & (VB_301B|VB_302B|VB_30xLV|VB_30xLVX)) {
+		      ModeIndex = ModeIndex_1024x768[i];
+		   }
+		}
+		break;
+        }
+
+      }
+
+   } else if(VBFlags & CRT2_VGA) {		/* CRT2 is VGA2 */
+
+	switch(mode->HDisplay)
+	{
+	case 512:
+		if(mode->VDisplay == 384) {
+		    ModeIndex = ModeIndex_512x384[i];
+		}
+		break;
+	case 640:
+		if(mode->VDisplay == 480) {
+		   ModeIndex = ModeIndex_640x480[i];
+		}
+		break;
+	case 800:
+		if(mode->VDisplay == 600) {
+		   ModeIndex = ModeIndex_800x600[i];
+		} else if(pSiS->VGAEngine == SIS_315_VGA) {
+		   if(mode->VDisplay == 480) {
+			ModeIndex = ModeIndex_800x480[i];
+		   }
+		}
+		break;
+	case 1024:
+		if(mode->VDisplay == 768) {
+			ModeIndex = ModeIndex_1024x768[i];
+		} else if(pSiS->VGAEngine == SIS_315_VGA) {
+		   if(mode->VDisplay == 576) {
+			ModeIndex = ModeIndex_1024x576[i];
+		   }
+		}
+		break;
+	case 1152:
+		if(pSiS->VGAEngine == SIS_300_VGA) {
+		   if(mode->VDisplay == 768) {
+			ModeIndex = ModeIndex_1152x768[i];
+		   }
+		}
+		break;
+	case 1280:
+		if (mode->VDisplay == 1024) {
+		   ModeIndex = ModeIndex_1280x1024[i];
+		} else if(pSiS->VGAEngine == SIS_315_VGA) {
+		   if (mode->VDisplay == 768) {
+			ModeIndex = ModeIndex_1280x768[i];
+		   } else if (mode->VDisplay == 720) {
+			ModeIndex = ModeIndex_1280x720[i];
+		   }
+		}
+		break;
+	case 1400:
+		if(pSiS->VGAEngine == SIS_315_VGA) {
+		   ModeIndex = ModeIndex_1400x1050[i];
+		}
+		break;
+	}
+
+   } else {				/* CRT1 only, no CRT2 */
+
+       ModeIndex = SiS_CalcModeIndex(pScrn, mode);
+
+   }
+
+   return(ModeIndex);
+}
+
 #define MODEID_OFF 0x449
 
 unsigned char
 SiS_GetSetModeID(ScrnInfoPtr pScrn, unsigned char id)
 {
+    return(SiS_GetSetMMIOReg(pScrn, MODEID_OFF, id));
+}
+
+unsigned char
+SiS_GetSetMMIOReg(ScrnInfoPtr pScrn, USHORT offset, unsigned char value)
+{
     unsigned char ret;
+    unsigned char *base;
+    SISPtr pSiS = SISPTR(pScrn);
+    BOOLEAN mapped;
 
-    unsigned char* base = xf86MapVidMem(pScrn->scrnIndex,
-					VIDMEM_MMIO, 0, 0x2000);
-    ret = *(base + MODEID_OFF);
-
-    /* id != 0xff means: set mode */
-    if (id != 0xff)
-	*(base + MODEID_OFF) = id;
-    xf86UnMapVidMem(pScrn->scrnIndex,base,0x2000);
+    if(pSiS->IOBase) {
+    	base = (unsigned char *)pSiS->IOBase;
+	mapped = FALSE;
+    } else {
+        base = xf86MapVidMem(pScrn->scrnIndex, VIDMEM_MMIO, 0, 0x2000);
+	if(!base) {
+	     xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+	          "(init.c: Could not MMIO area!)\n");
+	     return 0;
+	}
+	mapped = TRUE;
+    }
+
+    ret = *(base + offset);
+
+    /* value != 0xff means: set register */
+    if (value != 0xff)
+	*(base + offset) = value;
+
+    if(mapped) xf86UnMapVidMem(pScrn->scrnIndex, base, 0x2000);
 
     return ret;
 }
+
 #endif
 
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/sis/initdef.h linux.20pre10-ac2/drivers/video/sis/initdef.h
--- linux.20pre10/drivers/video/sis/initdef.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/sis/initdef.h	2002-10-11 00:17:32.000000000 +0100
@@ -1,6 +1,5 @@
 /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sis/initdef.h,v 1.4 2000/12/02 01:16:17 dawes Exp $ */
 
-/* Comments and changes marked with "TW" by Thomas Winischhofer <thomas@winischhofer.net> */
 
 #ifndef _INITDEF_
 #define _INITDEF_
@@ -10,22 +9,20 @@
 #define SiS630                  0x6300
 #define SiS730                  0x6300
 
-/*301b*/
-/* VBType */
+/* SiS_VBType */
 #define VB_SIS301	      	0x0001
 #define VB_SIS301B        	0x0002
 #define VB_SIS302B        	0x0004
-#define VB_SIS301LV     	0x0008 /*301lv*/
-#define VB_SIS302LV     	0x0010
+#define VB_SIS30xLV     	0x0008
+#define VB_SIS30xNEW     	0x0010
 #define VB_NoLCD        	0x8000
-/*end 301b*/
+#define VB_SIS301BLV302BLV      (VB_SIS301B|VB_SIS302B|VB_SIS30xLV|VB_SIS30xNEW)
 
 #define CRT1Len                 17
 #define LVDSCRT1Len             15
 #define CHTVRegDataLen          5
 
-#define ModeInfoFlag            0x07
-#define IsTextMode              0x07
+/* SiS_ModeType */
 #define ModeText                0x00
 #define ModeCGA                 0x01
 #define ModeEGA                 0x02
@@ -35,10 +32,14 @@
 #define Mode24Bpp               0x06
 #define Mode32Bpp               0x07
 
+#define ModeInfoFlag            0x07
+#define IsTextMode              0x07
+
 #define DACInfoFlag             0x18
 #define MemoryInfoFlag          0x1E0
 #define MemorySizeShift         0x05
 
+/* modeflag */
 #define Charx8Dot               0x0200
 #define LineCompareOff          0x0400
 #define CRT2Mode                0x0800
@@ -69,7 +70,7 @@
 #define ECLKindex4              0x0400
 
 /* VBInfo */
-#define SetSimuScanMode         0x0001
+#define SetSimuScanMode         0x0001   /* CR 30 */
 #define SwitchToCRT2            0x0002
 #define SetCRT2ToTV             0x009C
 #define SetCRT2ToAVIDEO         0x0004
@@ -78,30 +79,93 @@
 #define SetCRT2ToLCD            0x0020
 #define SetCRT2ToRAMDAC         0x0040
 #define SetCRT2ToHiVisionTV     0x0080
-#define SetNTSCTV               0x0000
+#define SetNTSCTV               0x0000   /* CR 31 */
 #define SetPALTV                0x0100
 #define SetInSlaveMode          0x0200
 #define SetNotSimuMode          0x0400
 #define SetNotSimuTVMode        0x0400
 #define SetDispDevSwitch        0x0800
 #define LoadDACFlag             0x1000
+#define SetCHTVOverScan  	0x1000  /* TW: Re-defined (from 0x8000) */
 #define DisableCRT2Display      0x2000
+#define CRT2DisplayFlag         0x2000
 #define DriverMode              0x4000
-#define HotKeySwitch            0x8000
-#define SetCHTVOverScan  	0x8000
-#define SetCRT2ToLCDA           0x8000/*301b*/
+#define HotKeySwitch            0x8000  /* TW: ? */
+#define SetCRT2ToLCDA           0x8000
+
 #define PanelRGB18Bit           0x0100
 #define PanelRGB24Bit           0x0000
 
-#define TVOverScan              0x10
+#define TVOverScan              0x10    /* Bit in CR35 (300 series only) */
 #define TVOverScanShift         4
 #define ClearBufferFlag         0x20
-#define EnableDualEdge 		0x01		/*301b*/	
-#define SetToLCDA		0x02
+
+/* CR32 (Newer 630, and 310/325 series)
+
+   [0]   VB connected with CVBS
+   [1]   VB connected with SVHS
+   [2]   VB connected with SCART
+   [3]   VB connected with LCD
+   [4]   VB connected with CRT2 (secondary VGA)
+   [5]   CRT1 monitor is connected
+   [6]   VB connected with Hi-Vision TV
+   [7]   VB connected with DVI combo connector
+
+
+   CR37
+
+   [0]   Set 24/18 bit (0/1) RGB to LVDS/TMDS transmitter (set by BIOS)
+   [3:1] External chip
+         300 series:
+	    001   SiS301 (never seen)
+	    010   LVDS
+	    011   LVDS + Tumpion Zurac
+	    100   LVDS + Chrontel 7005
+	    110   Chrontel 7005
+	  310/325 series
+	    001   SiS30x (never seen)
+	    010   LVDS
+	    011   LVDS + Chrontel 7019
+	  All other combinations reserved
+   [4]    LVDS: Expanding(0)/Non-expanding(1) LCD display
+          30x:  SiS30x(0)/LCD monitor(1) scaling display
+   [5]    LCD polarity select
+          0: VESA DMT Standard
+	  1: EDID 2.x defined
+   [6]    LCD horizontal polarity select
+          0: High active
+	  1: Low active
+   [7]    LCD vertical polarity select
+          0: High active
+	  1: Low active
+*/
+
+#define EnableDualEdge 		0x01   /* CR38 (310/325 series) */
+/* #define PAL_NTSC             0x01      (only on 315PRO) */
+#define SetToLCDA		0x02   /* TW: LCD channel A (302B and 650+LVDS only) */
+#define EnableLVDSHiVision      0x08   /* TW: Only on 650/LVDS systems */
+#define SetYPbPr                0x10   /* TW: YPbPr color format */
+#define EnablePALMN             0x40
+#define EnablePALN              0x80
+
+/* CR79 (310/325 series only)
+   [3-0] Notify driver
+         0001 Mode Switch event (set by BIOS)
+	 0010 Epansion On/Off event
+	 0011 TV UnderScan/OverScan event
+	 0100 Set Brightness event
+	 0101 Set Contrast event
+	 0110 Set Mute event
+	 0111 Set Volume Up/Down event
+   [4]   Enable Backlight Control by BIOS/driver (set by driver)
+   [5]   PAL/NTSC (set by BIOS)
+   [6]   Expansion On/Off (set by BIOS)
+   [7]   TV UnderScan/OverScan (set by BIOS)
+*/
+
 
 #define SetSCARTOutput          0x01
 #define BoardTVType             0x02
-#define EnablePALMN             0x40
 
 /* SetFlag */
 #define ProgrammingCRT2         0x01
@@ -112,41 +176,69 @@
 #define SetDispDevSwitchFlag    0x20
 #define CheckWinDos             0x40
 #define SetJDOSMode             0x80
+#define CRT2IsVGA	        0x80  /* TW: Not sure about this name... */
 
 /* LCDResInfo */
-#define Panel800x600            0x01
-#define Panel1024x768           0x02
-#define Panel1280x1024          0x03
-#define Panel1280x960           0x04
-#define Panel640x480            0x05
-#define Panel1600x1200          0x06 /*301b*/
-#define Panel320x480            0x07 /*fstn*/
+#define Panel300_800x600        0x01	/* CR36 */
+#define Panel300_1024x768       0x02
+#define Panel300_1280x1024      0x03
+#define Panel300_1280x960       0x04
+#define Panel300_640x480        0x05
+#define Panel300_1024x600       0x06
+#define Panel300_1152x768       0x07
+#define Panel300_320x480        0x08 	/* fstn - TW: This is fake, can be any */
+
+#define Panel310_800x600        0x01
+#define Panel310_1024x768       0x02
+#define Panel310_1280x1024      0x03
+#define Panel310_640x480        0x04
+#define Panel310_1024x600       0x05
+#define Panel310_1152x864       0x06
+#define Panel310_1280x960       0x07
+#define Panel310_1152x768       0x08	/* TW: LVDS only */
+#define Panel310_1400x1050      0x09
+#define Panel310_1280x768       0x0a    /* TW: LVDS only */
+#define Panel310_1600x1200      0x0b
+#define Panel310_320x480        0x0c    /* fstn - TW: This is fake, can be any */
+
+#define Panel_800x600           0x01	/* Unified values */
+#define Panel_1024x768          0x02
+#define Panel_1280x1024         0x03
+#define Panel_640x480           0x04
+#define Panel_1024x600          0x05
+#define Panel_1152x864          0x06
+#define Panel_1280x960          0x07
+#define Panel_1152x768          0x08	/* TW: LVDS only */
+#define Panel_1400x1050         0x09
+#define Panel_1280x768          0x0a    /* TW: LVDS only */
+#define Panel_1600x1200         0x0b
+#define Panel_320x480           0x0c    /* fstn - TW: This is fake, can be any */
 
 #define ExtChipType             0x0e
 #define ExtChip301              0x02
 #define ExtChipLVDS             0x04
 #define ExtChipTrumpion         0x06
 #define ExtChipCH7005           0x08
-#define ExtChipMitacTV          0x0a
+#define ExtChipMitacTV          0x0a            /* TW: Incorrect, 0x0a = Chrontel 7005 only */
+
+#define IsM650                  0x80   		/* TW: CR5F */
 
 /* LCDInfo */
 #define LCDRGB18Bit             0x01
+#define LCDNonExpandingShift    0x04
 #define LCDNonExpanding         0x10
-
-#define LCDNonExpandingShift    4
 #define LCDSync                 0x20
+#define LCDPass11              0x100 
 #define LCDSyncBit              0xe0
 #define LCDSyncShift            6
 
-#define DDC2DelayTime           300     
-
-#define CRT2DisplayFlag         0x2000
 #define LCDDataLen              8
 #define HiTVDataLen             12
 #define TVDataLen               16
 #define SetPALTV                0x0100
-#define HalfDCLK                0x1000
+#define HalfDCLK                0x1000  /* modeflag */
 #define NTSCHT                  1716
+#define NTSC2HT                 1920
 #define NTSCVT                  525
 #define PALHT                   1728
 #define PALVT                   625
@@ -159,25 +251,23 @@
 
 #define VCLKStartFreq           25
 #define SoftDramType            0x80
-#define VCLK40                  0x04
-#define VCLK65                  0x09
-#define VCLK108_2               0x14
-#define LCDRGB18Bit             0x01
+
+#define VCLK40                  0x04   /* Index in VCLKData array */
+#define VCLK65                  0x09   /* Index in VCLKData array */
+#define VCLK108_2               0x14   /* Index in VCLKData array */
+#define TVVCLKDIV2              0x21   /* Indices in (VB)VCLKData arrays */
+#define TVVCLK                  0x22
+#define HiTVVCLKDIV2            0x23
+#define HiTVVCLK                0x24
+#define HiTVSimuVCLK            0x25
+#define HiTVTextVCLK            0x26
+
 #define LoadDACFlag             0x1000
 #define AfterLockCRT2           0x4000
 #define SetCRT2ToAVIDEO         0x0004
 #define SetCRT2ToSCART          0x0010
 #define Ext2StructSize          5
 
-#define TVVCLKDIV2              0x021
-#define TVVCLK                  0x022
-
-#define HiTVVCLKDIV2            0x023
-#define HiTVVCLK                0x024
-#define HiTVSimuVCLK            0x025
-#define HiTVTextVCLK            0x026
-#define SwitchToCRT2            0x0002
-#define LCDVESATiming           0x08
 #define SetSCARTOutput          0x01
 #define AVIDEOSense             0x01
 #define SVIDEOSense             0x02
@@ -190,14 +280,13 @@
 #define HotPlugFunction         0x08
 #define StStructSize            0x06
 
-#define SIS_CRT2_PORT_04        0x04 - 0x030
+#define SIS_CRT2_PORT_04        0x04 - 0x30
 #define SIS_CRT2_PORT_10        0x10 - 0x30
 #define SIS_CRT2_PORT_12        0x12 - 0x30
 #define SIS_CRT2_PORT_14        0x14 - 0x30
 
-#define LCDNonExpanding         0x10
 #define ADR_CRT2PtrData         0x20E
-#define offset_Zurac            0x210
+#define offset_Zurac            0x210   /* TW: Trumpion Zurac data pointer */
 #define ADR_LVDSDesPtrData      0x212
 #define ADR_LVDSCRT1DataPtr     0x214
 #define ADR_CHTVVCLKPtr         0x216
@@ -235,7 +324,7 @@
 #define _PanelType0F             0x78
 
 #define PRIMARY_VGA       	0     /* 1: SiS is primary vga 0:SiS is secondary vga */
-#define BIOSIDCodeAddr          0x235
+#define BIOSIDCodeAddr          0x235  /* TW: Offsets to ptrs in BIOS image */
 #define OEMUtilIDCodeAddr       0x237
 #define VBModeIDTableAddr       0x239
 #define OEMTVPtrAddr            0x241
@@ -276,9 +365,11 @@
 
 #define OEMLCDPanelIDSupport    0x0080
 
-/* =============================================================
-   			for 310
-============================================================== */
+/*
+  =============================================================
+   			for 310/325 series
+  =============================================================
+*/
 #define SoftDRAMType        0x80
 #define SoftSetting_OFFSET  0x52
 #define SR07_OFFSET  0x7C
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/sis/init.h linux.20pre10-ac2/drivers/video/sis/init.h
--- linux.20pre10/drivers/video/sis/init.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/sis/init.h	2002-10-11 00:35:04.000000000 +0100
@@ -16,6 +16,7 @@
 
 #ifdef LINUX_XF86
 #include "xf86.h"
+#include "xf86Pci.h"
 #include "xf86PciInfo.h"
 #include "xf86_OSproc.h"
 #include "sis.h"
@@ -35,246 +36,273 @@
 #include "dderror.h"
 #include "devioctl.h"
 #include "miniport.h"
-
 #include "ntddvdeo.h"
 #include "video.h"
 #include "sisv.h"
+#include "tools.h"
 #endif
 
-USHORT SiS_DRAMType[17][5]={{0x0C,0x0A,0x02,0x40,0x39},{0x0D,0x0A,0x01,0x40,0x48},
-                     {0x0C,0x09,0x02,0x20,0x35},{0x0D,0x09,0x01,0x20,0x44},
-                     {0x0C,0x08,0x02,0x10,0x31},{0x0D,0x08,0x01,0x10,0x40},
-                     {0x0C,0x0A,0x01,0x20,0x34},{0x0C,0x09,0x01,0x08,0x32},
-                     {0x0B,0x08,0x02,0x08,0x21},{0x0C,0x08,0x01,0x08,0x30},
-                     {0x0A,0x08,0x02,0x04,0x11},{0x0B,0x0A,0x01,0x10,0x28},
-                     {0x09,0x08,0x02,0x02,0x01},{0x0B,0x09,0x01,0x08,0x24},
-                     {0x0B,0x08,0x01,0x04,0x20},{0x0A,0x08,0x01,0x02,0x10},
-                     {0x09,0x08,0x01,0x01,0x00}};
+const USHORT SiS_DRAMType[17][5]={
+	{0x0C,0x0A,0x02,0x40,0x39},
+	{0x0D,0x0A,0x01,0x40,0x48},
+	{0x0C,0x09,0x02,0x20,0x35},
+	{0x0D,0x09,0x01,0x20,0x44},
+	{0x0C,0x08,0x02,0x10,0x31},
+	{0x0D,0x08,0x01,0x10,0x40},
+	{0x0C,0x0A,0x01,0x20,0x34},
+	{0x0C,0x09,0x01,0x08,0x32},
+	{0x0B,0x08,0x02,0x08,0x21},
+	{0x0C,0x08,0x01,0x08,0x30},
+	{0x0A,0x08,0x02,0x04,0x11},
+	{0x0B,0x0A,0x01,0x10,0x28},
+	{0x09,0x08,0x02,0x02,0x01},
+	{0x0B,0x09,0x01,0x08,0x24},
+	{0x0B,0x08,0x01,0x04,0x20},
+	{0x0A,0x08,0x01,0x02,0x10},
+	{0x09,0x08,0x01,0x01,0x00}
+};
 
-USHORT SiS_SDRDRAM_TYPE[13][5]=
+const USHORT SiS_SDRDRAM_TYPE[13][5] =
 {
-{ 2,12, 9,64,0x35},
-{ 1,13, 9,64,0x44},
-{ 2,12, 8,32,0x31},
-{ 2,11, 9,32,0x25},
-{ 1,12, 9,32,0x34},
-{ 1,13, 8,32,0x40},
-{ 2,11, 8,16,0x21},
-{ 1,12, 8,16,0x30},
-{ 1,11, 9,16,0x24},
-{ 1,11, 8, 8,0x20},
-{ 2, 9, 8, 4,0x01},
-{ 1,10, 8, 4,0x10},
-{ 1, 9, 8, 2,0x00}
+	{ 2,12, 9,64,0x35},
+	{ 1,13, 9,64,0x44},
+	{ 2,12, 8,32,0x31},
+	{ 2,11, 9,32,0x25},
+	{ 1,12, 9,32,0x34},
+	{ 1,13, 8,32,0x40},
+	{ 2,11, 8,16,0x21},
+	{ 1,12, 8,16,0x30},
+	{ 1,11, 9,16,0x24},
+	{ 1,11, 8, 8,0x20},
+	{ 2, 9, 8, 4,0x01},
+	{ 1,10, 8, 4,0x10},
+	{ 1, 9, 8, 2,0x00}
 };
 
-USHORT SiS_DDRDRAM_TYPE[4][5]=
+const USHORT SiS_DDRDRAM_TYPE[4][5] =
 {
-{ 2,12, 9,64,0x35},
-{ 2,12, 8,32,0x31},
-{ 2,11, 8,16,0x21},
-{ 2, 9, 8, 4,0x01}
+	{ 2,12, 9,64,0x35},
+	{ 2,12, 8,32,0x31},
+	{ 2,11, 8,16,0x21},
+	{ 2, 9, 8, 4,0x01}
 };
 
-UCHAR SiS_ChannelAB,SiS_DataBusWidth;
+const USHORT SiS_MDA_DAC[] =
+{
+	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+        0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
+        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+        0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F
+};
 
+const USHORT SiS_CGA_DAC[] =
+{
+        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+};
 
-USHORT SiS_MDA_DAC[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-               0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-               0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
-               0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-               0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-               0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-               0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F};
-
-USHORT SiS_CGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-               0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-               0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-               0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-               0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-               0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-               0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-               0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F};
-
-USHORT SiS_EGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15,
-               0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35,
-               0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D,
-               0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D,
-               0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17,
-               0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37,
-               0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F,
-               0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F};
-
-USHORT SiS_VGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-               0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-               0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18,
-               0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F,
-
-               0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F,
-               0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00,
-               0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18,
-               0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04,
-               0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10,
-               0x0B,0x0C,0x0D,0x0F,0x10};
-
-USHORT      SiS_P3c4,SiS_P3d4,SiS_P3c0,SiS_P3ce,SiS_P3c2;
-USHORT      SiS_P3ca,SiS_P3c6,SiS_P3c7,SiS_P3c8,SiS_P3c9,SiS_P3da;
-USHORT      SiS_Part1Port,SiS_Part2Port;
-USHORT      SiS_Part3Port,SiS_Part4Port,SiS_Part5Port;
-USHORT      SiS_CRT1Mode;
-
-USHORT   flag_clearbuffer;         /*0: no clear frame buffer 1:clear frame buffer  */
-int      SiS_RAMType;              /*int      ModeIDOffset,StandTable,CRT1Table,ScreenOffset,REFIndex;*/
-USHORT   SiS_ModeType;
-USHORT   SiS_IF_DEF_LVDS,SiS_IF_DEF_TRUMPION,SiS_IF_DEF_DSTN,SiS_IF_DEF_FSTN;    /*add for dstn*/
-USHORT   SiS_IF_DEF_CH7005,SiS_IF_DEF_HiVision;
-USHORT	 SiS_Backup7005=0xff;	/* TW: Backup for power-status */
-USHORT   SiS_VBInfo,SiS_LCDResInfo,SiS_LCDTypeInfo,SiS_LCDInfo, SiS_VBType;/*301b*/
-USHORT   SiS_VBExtInfo;  /*301lv*/
-USHORT   SiS_SelectCRT2Rate;
-
-extern   USHORT   SiS_SetFlag;
-extern   USHORT   SiS_DDC_Port;
-
-void     SiS_SetMemoryClock(ULONG ROMAddr);
-void     SiS_SetDRAMModeRegister(ULONG   ROMAddr);
-void     SiS_SetDRAMSize_310(PSIS_HW_DEVICE_INFO);
-void     SiS_SetDRAMSize_300(PSIS_HW_DEVICE_INFO HwDeviceExtension);
-USHORT   SiS_ChkBUSWidth_300(ULONG FBAddress);
-UCHAR    SiS_Get310DRAMType(ULONG   ROMAddr);
-
-BOOLEAN SiS_SearchVBModeID(ULONG ROMAddr, USHORT ModeNo);
-void SiS_IsLowResolution(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-ULONG GetDRAMSize(PSIS_HW_DEVICE_INFO HwDeviceExtension);
+const USHORT SiS_EGA_DAC[] =
+{
+        0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15,
+        0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35,
+        0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D,
+        0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D,
+        0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17,
+        0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37,
+        0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F,
+        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+};
+
+const USHORT SiS_VGA_DAC[] =
+{
+	0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+	0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+	0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18,
+	0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F,
+	0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F,
+	0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00,
+	0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18,
+	0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04,
+	0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10,
+	0x0B,0x0C,0x0D,0x0F,0x10
+};
+
+void     SiS_SetReg1(USHORT, USHORT, USHORT);
+void     SiS_SetReg2(SiS_Private *, USHORT, USHORT, USHORT);
+void     SiS_SetReg3(USHORT, USHORT);
+void     SiS_SetReg4(USHORT, ULONG);
+UCHAR    SiS_GetReg1(USHORT, USHORT);
+UCHAR    SiS_GetReg2(USHORT);
+ULONG    SiS_GetReg3(USHORT);
+void     SiS_ClearDAC(SiS_Private *SiS_Pr, ULONG);
+void     SiS_SetMemoryClock(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetDRAMModeRegister(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+BOOLEAN  SiS_SearchVBModeID(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT *ModeNo);
+void     SiS_IsLowResolution(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+ULONG    GetDRAMSize(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
 
 #ifdef SIS300
-void InitTo300Pointer(void);
-#endif
-#ifdef SIS315H
-void InitTo310Pointer(void);
+void     InitTo300Pointer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetDRAMSize_300(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+USHORT   SiS_ChkBUSWidth_300(SiS_Private *SiS_Pr, ULONG FBAddress);
 #endif
 
 #ifdef SIS315H
-void SiS_DDR_MRS(void);
-void SiS_SDR_MRS(void);
-void SiS_DisableRefresh(void);
-void SiS_EnableRefresh(ULONG ROMAddr);
-void SiS_DisableChannelInterleaving(int index,USHORT SiS_DDRDRAM_TYPE[][5]);
-void SiS_SetDRAMSizingType(int index,USHORT DRAMTYPE_TABLE[][5]);
-void SiS_CheckBusWidth_310(ULONG ROMAddress,ULONG FBAddress);
-int  SiS_SetRank(int index,UCHAR RankNo,UCHAR SiS_ChannelAB,USHORT DRAMTYPE_TABLE[][5]);
-int  SiS_SetDDRChannel(int index,UCHAR ChannelNo,UCHAR SiS_ChannelAB,USHORT DRAMTYPE_TABLE[][5]);
-int  SiS_CheckColumn(int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
-int  SiS_CheckBanks(int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
-int  SiS_CheckRank(int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
-int  SiS_CheckDDRRank(int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
-int  SiS_CheckRanks(int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
-int  SiS_CheckDDRRanks(int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
-int  SiS_SDRSizing(ULONG FBAddress);
-int  SiS_DDRSizing(ULONG FBAddress);
-int  Is315E(void);
-void SiS_VerifyMclk(ULONG FBAddr);
+void     InitTo310Pointer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+UCHAR    SiS_Get310DRAMType(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_DDR_MRS(SiS_Private *SiS_Pr);
+void     SiS_SDR_MRS(SiS_Private *SiS_Pr);
+void     SiS_DisableRefresh(SiS_Private *SiS_Pr);
+void     SiS_EnableRefresh(SiS_Private *SiS_Pr, UCHAR *ROMAddr);
+void     SiS_SetDRAMSize_310(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO);
+void     SiS_DisableChannelInterleaving(SiS_Private *SiS_Pr, int index,USHORT SiS_DDRDRAM_TYPE[][5]);
+void     SiS_SetDRAMSizingType(SiS_Private *SiS_Pr, int index,USHORT DRAMTYPE_TABLE[][5]);
+void     SiS_CheckBusWidth_310(SiS_Private *SiS_Pr, UCHAR *ROMAddress,ULONG FBAddress,
+                               PSIS_HW_DEVICE_INFO HwDeviceExtension);
+int      SiS_SetRank(SiS_Private *SiS_Pr, int index,UCHAR RankNo,USHORT DRAMTYPE_TABLE[][5]);
+int      SiS_SetDDRChannel(SiS_Private *SiS_Pr, int index,UCHAR ChannelNo,
+                           USHORT DRAMTYPE_TABLE[][5]);
+int      SiS_CheckColumn(SiS_Private *SiS_Pr, int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
+int      SiS_CheckBanks(SiS_Private *SiS_Pr, int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
+int      SiS_CheckRank(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
+int      SiS_CheckDDRRank(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
+int      SiS_CheckRanks(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
+int      SiS_CheckDDRRanks(SiS_Private *SiS_Pr, int RankNo,int index,USHORT DRAMTYPE_TABLE[][5],ULONG FBAddress);
+int      SiS_SDRSizing(SiS_Private *SiS_Pr, ULONG FBAddress);
+int      SiS_DDRSizing(SiS_Private *SiS_Pr, ULONG FBAddress);
+int      Is315E(SiS_Private *SiS_Pr);
+void     SiS_VerifyMclk(SiS_Private *SiS_Pr, ULONG FBAddr);
 #endif
 
-/*int    init300(int,int,int);  */
-/*extern      "C"    int     ChkBUSWidth(int);  */
-/*int    setmode(int,int,int,int);  */
-extern void SetEnableDstn(void);
-void     SiS_Delay15us(ULONG);
-BOOLEAN  SiS_SearchModeID(ULONG ROMAddr, USHORT ModeNo,USHORT  *ModeIdIndex);
-BOOLEAN  SiS_CheckMemorySize(ULONG ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+void     SiS_HandleCRT1(SiS_Private *SiS_Pr);
+void     SiS_Handle301B_1400x1050(SiS_Private *SiS_Pr, USHORT ModeNo);
+void     SetEnableDstn(SiS_Private *SiS_Pr);
+void     SiS_Delay15us(SiS_Private *SiS_Pr);
+BOOLEAN  SiS_SearchModeID(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT *ModeNo,USHORT *ModeIdIndex);
+BOOLEAN  SiS_CheckMemorySize(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
                              USHORT ModeNo,USHORT ModeIdIndex);
-UCHAR    SiS_GetModePtr(ULONG ROMAddr, USHORT ModeNo,USHORT ModeIdIndex);
-void     SiS_SetSeqRegs(ULONG,USHORT StandTableIndex);
-void     SiS_SetMiscRegs(ULONG,USHORT StandTableIndex);
-void     SiS_SetCRTCRegs(ULONG,PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT StandTableIndex);
-void     SiS_SetATTRegs(ULONG,USHORT StandTableIndex);
-void     SiS_SetGRCRegs(ULONG,USHORT StandTableIndex);
-void     SiS_ClearExt1Regs(void);
-void     SiS_SetSync(ULONG ROMAddr,USHORT RefreshRateTableIndex);
-void     SiS_SetCRT1CRTC(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-void     SiS_SetCRT1VCLK(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO,
+UCHAR    SiS_GetModePtr(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo,USHORT ModeIdIndex);
+void     SiS_SetSeqRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex);
+void     SiS_SetMiscRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex);
+void     SiS_SetCRTCRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                         USHORT StandTableIndex);
+void     SiS_SetATTRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex,USHORT ModeNo,
+                        PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetGRCRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT StandTableIndex);
+void     SiS_ClearExt1Regs(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetSync(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT RefreshRateTableIndex);
+void     SiS_SetCRT1CRTC(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                         USHORT RefreshRateTableIndex,
+			 PSIS_HW_DEVICE_INFO HwDeviceExtension);
+BOOLEAN  SiS_GetLCDACRT1Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                            USHORT RefreshRateTableIndex,USHORT *ResInfo,USHORT *DisplayType);
+void     SiS_ResetCRT1VCLK(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetCRT1VCLK(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO,
                          USHORT RefreshRateTableIndex);
-void     SiS_SetVCLKState(ULONG ROMAddr,PSIS_HW_DEVICE_INFO, USHORT ModeNo,USHORT RefreshRateTableIndex);
-void     SiS_LoadDAC(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-void     SiS_DisplayOn(void);
-void 	 SiS_DisplayOff(void);
-void     SiS_SetCRT1ModeRegs(ULONG ROMAddr,PSIS_HW_DEVICE_INFO,USHORT ModeNo,
+void     SiS_SetVCLKState(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO, USHORT ModeNo,
+                          USHORT RefreshRateTableIndex, USHORT ModeIdIndex);
+void     SiS_LoadDAC(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+void     SiS_WriteDAC(SiS_Private *SiS_Pr, USHORT, USHORT, USHORT, USHORT, USHORT, USHORT);
+void     SiS_DisplayOn(SiS_Private *SiS_Pr);
+void 	 SiS_DisplayOff(SiS_Private *SiS_Pr);
+void     SiS_SetCRT1ModeRegs(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO,USHORT ModeNo,
                              USHORT ModeIdIndex,USHORT RefreshRateTableIndex);
-void     SiS_WriteDAC(USHORT, USHORT, USHORT, USHORT);
-void     SiS_GetVBType(USHORT BaseAddr);/*301b*/
-USHORT   SiS_ChkBUSWidth(ULONG);
-USHORT   SiS_GetModeIDLength(ULONG, USHORT);
-USHORT   SiS_GetRefindexLength(ULONG, USHORT);
-void     SiS_SetInterlace(ULONG ROMAddr,USHORT ModeNo,USHORT RefreshRateTableIndex);
-USHORT   SiS_CalcDelay2(ULONG ,UCHAR);
-USHORT   SiS_CalcDelay(ULONG ,USHORT);
-void     SiS_Set_LVDS_TRUMPION(PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiS_SetCRT1Offset(ULONG,USHORT,USHORT,USHORT,PSIS_HW_DEVICE_INFO);
-void     SiS_SetCRT1FIFO(ULONG,USHORT,PSIS_HW_DEVICE_INFO);
-void     SiS_SetCRT1FIFO2(ULONG,USHORT ModeNo,PSIS_HW_DEVICE_INFO,USHORT RefreshRateTableIndex);
-void     SiS_CRT2AutoThreshold(USHORT  BaseAddr);
-void     SiS_ClearBuffer(PSIS_HW_DEVICE_INFO,USHORT ModeNo);
-void     SiS_SetCRT1Group(ULONG ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                          USHORT ModeNo,USHORT ModeIdIndex);
-void     SiS_DetectMonitor(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr);
-void     SiS_GetSenseStatus(PSIS_HW_DEVICE_INFO HwDeviceExtension,ULONG ROMAddr);
-USHORT   SiS_TestMonitorType(UCHAR R_DAC,UCHAR G_DAC,UCHAR B_DAC);
-USHORT   SiS_SenseCHTV(VOID);
-BOOLEAN  SiS_Sense(USHORT Part4Port,USHORT tempbx,USHORT tempcx);
-BOOLEAN  SiS_GetPanelID(VOID);
-BOOLEAN  SiS_GetLCDDDCInfo(PSIS_HW_DEVICE_INFO);
-USHORT   SiS_SenseLCD(PSIS_HW_DEVICE_INFO);
-void     SiSRegInit(USHORT BaseAddr);
-void     SiSInitPtr(PSIS_HW_DEVICE_INFO HwDeviceExtension);
-void     SiSSetLVDSetc(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo);
-void     SiSInitPCIetc(PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_GetVBType(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO);
+USHORT   SiS_ChkBUSWidth(SiS_Private *SiS_Pr, UCHAR *ROMAddr);
+USHORT   SiS_GetModeIDLength(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT);
+USHORT   SiS_GetRefindexLength(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT);
+void     SiS_SetInterlace(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT RefreshRateTableIndex);
+void     SiS_Set_LVDS_TRUMPION(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiS_SetCRT1Offset(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT,USHORT,USHORT,PSIS_HW_DEVICE_INFO);
+#ifdef SIS315H
+void     SiS_SetCRT1FIFO_310(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT,USHORT,PSIS_HW_DEVICE_INFO);
+#endif
+#ifdef SIS300
+void     SiS_SetCRT1FIFO_300(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,PSIS_HW_DEVICE_INFO,
+                             USHORT RefreshRateTableIndex);
+void     SiS_SetCRT1FIFO_630(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,PSIS_HW_DEVICE_INFO,
+                             USHORT RefreshRateTableIndex);
+USHORT   SiS_CalcDelay(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT VCLK,
+                       USHORT colordepth, USHORT MCLK);
+USHORT   SiS_DoCalcDelay(SiS_Private *SiS_Pr, USHORT MCLK, USHORT VCLK, USHORT colordepth, USHORT key);
+USHORT   SiS_CalcDelay2(SiS_Private *SiS_Pr, UCHAR *ROMAddr, UCHAR);
+#endif
+void     SiS_ClearBuffer(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO,USHORT ModeNo);
+void     SiS_SetCRT1Group(SiS_Private *SiS_Pr, UCHAR *ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension,
+                          USHORT ModeNo,USHORT ModeIdIndex,USHORT BaseAddr);
+void     SiS_DetectMonitor(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr);
+void     SiS_GetSenseStatus(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,UCHAR *ROMAddr);
+USHORT   SiS_TestMonitorType(SiS_Private *SiS_Pr, UCHAR R_DAC,UCHAR G_DAC,UCHAR B_DAC);
+USHORT   SiS_SenseCHTV(SiS_Private *SiS_Pr);
+BOOLEAN  SiS_Sense(SiS_Private *SiS_Pr, USHORT tempbx,USHORT tempcx);
+BOOLEAN  SiS_GetPanelID(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO);
+BOOLEAN  SiS_GetLCDDDCInfo(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO);
+USHORT   SiS_SenseLCD(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO);
+void     SiSRegInit(SiS_Private *SiS_Pr, USHORT BaseAddr);
+void     SiSInitPtr(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiSSetLVDSetc(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo);
+void     SiSInitPCIetc(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+void     SiSDetermineROMUsage(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, UCHAR *ROMAddr);
 
 #ifdef LINUX_XF86
 USHORT  	SiS_CalcModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode);
-void    	SiS_SetPitch(ScrnInfoPtr pScrn, UShort BaseAddr);
-void    	SiS_SetPitchCRT1(ScrnInfoPtr pScrn, UShort BaseAddr);
-void    	SiS_SetPitchCRT2(ScrnInfoPtr pScrn, UShort BaseAddr);
+USHORT  	SiS_CheckCalcModeIndex(ScrnInfoPtr pScrn, DisplayModePtr mode, int VBFlags);
+void    	SiS_SetPitch(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, UShort BaseAddr);
+void    	SiS_SetPitchCRT1(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, UShort BaseAddr);
+void    	SiS_SetPitchCRT2(SiS_Private *SiS_Pr, ScrnInfoPtr pScrn, UShort BaseAddr);
 unsigned char 	SiS_GetSetModeID(ScrnInfoPtr pScrn, unsigned char id);
+unsigned char 	SiS_GetSetMMIOReg(ScrnInfoPtr pScrn, USHORT offset, unsigned char value);
 #endif
 
-extern BOOLEAN   SiS_SetCRT2Group301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
+extern USHORT    SiS_GetOffset(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+                       USHORT RefreshRateTableIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+extern USHORT    SiS_GetColorDepth(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+extern void      SiS_DisableBridge(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+extern BOOLEAN   SiS_SetCRT2Group301(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
                                      PSIS_HW_DEVICE_INFO HwDeviceExtension);
-extern void      SiS_PresetScratchregister(USHORT SiS_P3d4,
+extern void      SiS_PresetScratchregister(SiS_Private *SiS_Pr, USHORT SiS_P3d4,
                                            PSIS_HW_DEVICE_INFO HwDeviceExtension);
-extern void      SiS_UnLockCRT2(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr);
-extern void      SiS_LockCRT2(PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr);
-extern BOOLEAN   SiS_BridgeIsOn(USHORT BaseAddr);
-extern BOOLEAN   SiS_BridgeIsEnable(USHORT BaseAddr,PSIS_HW_DEVICE_INFO );
-extern void      SiS_SetTVSystem301(VOID);
-extern BOOLEAN   SiS_GetLCDDDCInfo301(PSIS_HW_DEVICE_INFO HwDeviceExtension);
-extern BOOLEAN   SiS_GetSenseStatus301(PSIS_HW_DEVICE_INFO HwDeviceExtension,
-                                       USHORT BaseAddr,ULONG ROMAddr);
-extern USHORT    SiS_GetVCLKLen(ULONG ROMAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-extern BOOLEAN   SiS_SetCRT2Group302(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
-                                     PSIS_HW_DEVICE_INFO HwDeviceExtension);
-extern void      SiS_GetVBInfo301(USHORT BaseAddr,ULONG ROMAddr,USHORT ModeNo,
-                                  USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
-extern BOOLEAN   SiS_GetLCDResInfo301(ULONG ROMAddr,USHORT P3d4,USHORT ModeNo,
-                                      USHORT ModeIdIndex);
-/* extern USHORT  SiS_VBInfo,LCDResInfo,LCDTypeInfo,LCDInfo; */  /* TW: redundant */
-extern USHORT    SiS_GetRatePtrCRT2(ULONG ROMAddr, USHORT ModeNo,USHORT ModeIdIndex);
-extern void      SiS_LongWait(VOID);
+extern void      SiS_UnLockCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr);
+extern void      SiS_LockCRT2(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension,USHORT BaseAddr);
+extern BOOLEAN   SiS_BridgeIsOn(SiS_Private *SiS_Pr, USHORT BaseAddr);
+extern BOOLEAN   SiS_BridgeIsEnable(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO );
+extern void      SiS_GetVBInfo(SiS_Private *SiS_Pr, USHORT BaseAddr,UCHAR *ROMAddr,USHORT ModeNo,
+                               USHORT ModeIdIndex,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+extern BOOLEAN   SiS_GetLCDResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,
+                                   USHORT ModeIdIndex, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+extern void      SiS_SetHiVision(SiS_Private *SiS_Pr, USHORT BaseAddr,PSIS_HW_DEVICE_INFO HwDeviceExtension);
+extern USHORT    SiS_GetRatePtrCRT2(SiS_Private *SiS_Pr, UCHAR *ROMAddr, USHORT ModeNo,USHORT ModeIdIndex,
+                                    PSIS_HW_DEVICE_INFO HwDeviceExtension);
+extern void      SiS_LongWait(SiS_Private *SiS_Pr);
+extern void      SiS_SetRegOR(USHORT Port,USHORT Index,USHORT DataOR);
+extern void      SiS_SetRegAND(USHORT Port,USHORT Index,USHORT DataAND);
 extern void      SiS_SetRegANDOR(USHORT Port,USHORT Index,USHORT DataAND,USHORT DataOR);
-extern USHORT    SiS_GetResInfo(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
-extern void      SiS_SetCH7005(USHORT tempax);
-extern USHORT    SiS_GetCH7005(USHORT tempax);
-extern BOOLEAN   SiS_GetLVDSCRT1Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
-                                    USHORT RefreshRateTableIndex,
-		                    USHORT *ResInfo,USHORT *DisplayType);
-extern BOOLEAN   SiS_GetLCDACRT1Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+extern USHORT    SiS_GetResInfo(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex);
+extern void      SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempax);
+extern USHORT    SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempax);
+extern void      SiS_SetCH701x(SiS_Private *SiS_Pr, USHORT tempax);
+extern USHORT    SiS_GetCH701x(SiS_Private *SiS_Pr, USHORT tempax);
+extern void      SiS_SetCH70xx(SiS_Private *SiS_Pr, USHORT tempax);
+extern USHORT    SiS_GetCH70xx(SiS_Private *SiS_Pr, USHORT tempax);
+extern BOOLEAN   SiS_GetLVDSCRT1Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
                                     USHORT RefreshRateTableIndex,
 		                    USHORT *ResInfo,USHORT *DisplayType);
-extern USHORT    SiS_GetVCLK2Ptr(ULONG ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
+extern USHORT    SiS_GetVCLK2Ptr(SiS_Private *SiS_Pr, UCHAR *ROMAddr,USHORT ModeNo,USHORT ModeIdIndex,
                                  USHORT RefreshRateTableIndex,
 				 PSIS_HW_DEVICE_INFO HwDeviceExtension);
-extern BOOLEAN   SiS_Is301B(USHORT BaseAddr);/*301b*/
+extern BOOLEAN   SiS_Is301B(SiS_Private *SiS_Pr, USHORT BaseAddr);
+extern BOOLEAN   SiS_IsM650(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT BaseAddr);
+extern BOOLEAN   SiS_LowModeStuff(SiS_Private *SiS_Pr, USHORT ModeNo,PSIS_HW_DEVICE_INFO HwDeviceExtension);
 
 #endif
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/sis/Makefile linux.20pre10-ac2/drivers/video/sis/Makefile
--- linux.20pre10/drivers/video/sis/Makefile	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/sis/Makefile	2002-10-11 00:17:32.000000000 +0100
@@ -6,7 +6,7 @@
 
 export-objs := sis_main.o
 
-obj-y  := sis_main.o init.o init301.o
+obj-y  := sis_main.o init.o init301.o sis_accel.o
 obj-m  := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/sis/oem300.h linux.20pre10-ac2/drivers/video/sis/oem300.h
--- linux.20pre10/drivers/video/sis/oem300.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/sis/oem300.h	2002-10-11 00:17:32.000000000 +0100
@@ -1,5 +1,8 @@
 
-UCHAR SiS300_OEMTVDelay[8][4]={
+/* OEM Data for 300 series */
+
+const UCHAR SiS300_OEMTVDelay301[8][4] =
+{
 	{0x08,0x08,0x08,0x08},
 	{0x08,0x08,0x08,0x08},
 	{0x08,0x08,0x08,0x08},
@@ -10,7 +13,20 @@
 	{0x20,0x20,0x20,0x20}
 };
 
-UCHAR SiS300_OEMTVFlicker[8][4]={
+const UCHAR SiS300_OEMTVDelayLVDS[8][4] =
+{
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20}
+};
+
+const UCHAR SiS300_OEMTVFlicker[8][4] =
+{
 	{0x00,0x00,0x00,0x00},
 	{0x00,0x00,0x00,0x00},
 	{0x00,0x00,0x00,0x00},
@@ -21,7 +37,8 @@
 	{0x00,0x00,0x00,0x00}
 };
 
-UCHAR SiS300_OEMLCDDelay1[12][4]={
+#if 0   /* TW: Not used */
+const UCHAR SiS300_OEMLCDDelay1[12][4]={
 	{0x2c,0x2c,0x2c,0x2c},
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
@@ -35,9 +52,43 @@
 	{0x20,0x20,0x20,0x20},
 	{0x24,0x24,0x24,0x24}
 };
+#endif
 
-
-UCHAR SiS300_OEMLCDDelay2[32][4]={
+/* TW: From 630/301B BIOS */
+const UCHAR SiS300_OEMLCDDelay2[64][4] =		 /* for 301/301b/302b/301LV/302LV */
+{
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
+	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
@@ -73,7 +124,7 @@
 };
 
 /* TW: Added for LVDS */
-UCHAR SiS300_OEMLCDDelay3[32][4]={
+const UCHAR SiS300_OEMLCDDelay3[32][4] = {	/* For LVDS */
 	{0x20,0x20,0x20,0x20},  /* --- Expanding panels */
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
@@ -86,7 +137,7 @@
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
-	{0x04,0x04,0x04,0x04},		/* Clevo 2202, Mitac (PanelType 12)*/
+	{0x04,0x04,0x04,0x04},		/* Clevo 2202 (PanelType 12); Mitac needs 0x20! */
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},  	/* Uniwill N241S2 (PanelType 14)*/
 	{0x20,0x20,0x20,0x20},
@@ -102,146 +153,152 @@
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
-	{0x20,0x20,0x20,0x20},
+	{0x04,0x04,0x04,0x04},          /* Gericom 2200C (PanelType 28) */
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20},
 	{0x20,0x20,0x20,0x20}
 };
 
-/*
-UCHAR SiS300_StNTSCDelay[]={0x08,0x08,0x08,0x08,0xff};
-UCHAR SiS300_StPALDelay[]={0x08,0x08,0x08,0x08,0xff};
-UCHAR SiS300_StSCARTDelay[]={0x08,0x08,0x08,0x08,0xff};
-UCHAR SiS300_StHiTVDelay[]={0x2c,0x2c,0x2c,0x2c,0xff};
-UCHAR SiS300_ExtNTSCDelay[]={0x08,0x08,0x08,0x08,0xff};
-UCHAR SiS300_ExtPALDelay[]={0x08,0x08,0x08,0x08,0xff};
-UCHAR SiS300_ExtSCARTDelay[]={0x08,0x08,0x08,0x08,0xff};
-UCHAR SiS300_ExtHiTVDelay[]={0x20,0x20,0x20,0x20,0xff};
-UCHAR SiS300_StNTSCFlicker[]={0x00,0x00,0x00,0x00,0xff};
-UCHAR SiS300_StPALFlicker[]={0x00,0x00,0x00,0x00,0xff};
-UCHAR SiS300_StSCARTFlicker[]={0x00,0x00,0x00,0x00,0xff};
-UCHAR SiS300_StHiTVFlicker[]={0x00,0x00,0x00,0x00,0xff};
-UCHAR SiS300_ExtNTSCFlicker[]={0x00,0x00,0x00,0x00,0xff};
-UCHAR SiS300_ExtPALFlicker[]={0x00,0x00,0x00,0x00,0xff};
-UCHAR SiS300_ExtSCARTFlicker[]={0x00,0x00,0x00,0x00,0xff};
-UCHAR SiS300_ExtHiTVFlicker[]={0x00,0x00,0x00,0x00,0xff};
-*/
-
-#if 0
-//typedef struct _SiS_OEMTVPhasestruct  {
-//UCHAR Index[4];
-//} SiS_OEMTVPhasestruct;
-//SiS_OEMTVPhasestruct
-#endif
-
-UCHAR SiS300_StNTSCPhase[6][4]={
+const UCHAR SiS300_Phase1[8][6][4] =
+{
+    {
 	{0x21,0xed,0x00,0x08},
 	{0x21,0xed,0x8a,0x08},
 	{0x21,0xed,0x8a,0x08},
 	{0x21,0xed,0x8a,0x08},
 	{0x21,0xed,0x8a,0x08},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVPhasestruct
-#endif
-
-UCHAR SiS300_StPALPhase[6][4]={
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
+	{0xff,0xff,0xff,0xff}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVPhasestruct
-#endif
-
-UCHAR SiS300_StSCARTPhase[6][4]={
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
+	{0xff,0xff,0xff,0xff}
+    },
+    {
+        {0x21,0xed,0x00,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0xff,0xff,0xff,0xff}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVPhasestruct
-#endif
-
-UCHAR SiS300_StHiTVPhase[6][4]={
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
+	{0xff,0xff,0xff,0xff}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0xff,0xff,0xff,0xff}
+    }
 };
 
-#if 0
-//SiS_OEMTVPhasestruct
-#endif
 
-UCHAR SiS300_ExtNTSCPhase[6][4]={
-	{0x21,0xed,0x00,0x08},
+const UCHAR SiS300_Phase2[8][6][4] =
+{
+    {
+        {0x21,0xed,0x00,0x08},
 	{0x21,0xed,0x8a,0x08},
 	{0x21,0xed,0x8a,0x08},
 	{0x21,0xed,0x8a,0x08},
 	{0x21,0xed,0x8a,0x08},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVPhasestruct
-#endif
-
-UCHAR SiS300_ExtPALPhase[6][4]={
+    },
+    {
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVPhasestruct
-#endif
-
-UCHAR SiS300_ExtSCARTPhase[6][4]={
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
+	{0xff,0xff,0xff,0xff}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVPhasestruct
-#endif
-
-UCHAR SiS300_ExtHiTVPhase[6][4]={
+    },
+    {
+        {0x21,0xed,0x00,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0x21,0xed,0x8a,0x08},
+	{0xff,0xff,0xff,0xff}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0xff,0xff,0xff,0xff}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
+	{0xff,0xff,0xff,0xff}
+    },
+    {
+        {0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0x2a,0x05,0xd3,0x00},
 	{0xff,0xff,0xff,0xff}
+    }
 };
 
-#if 0
-//typedef struct _SiS_OEMTVFilterstruct{
-//UCHAR Index[4];
-//} SiS_OEMTVFilterstruct;
-//SiS_OEMTVFilterstruct
-#endif
-
-UCHAR SiS300_StNTSCFilter[17][4]={
+const UCHAR SiS300_Filter1[10][17][4] =
+{
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xeb,0x04,0x10,0x18},
@@ -259,13 +316,8 @@
 	{0xeb,0x04,0x25,0x18},
 	{0xeb,0x04,0x25,0x18},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVFilterstruct
-#endif
-
-UCHAR SiS300_StPALFilter[17][4]={
+    },
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xf1,0xf7,0x10,0x32},
@@ -283,13 +335,8 @@
 	{0xf1,0xf7,0x1f,0x32},
 	{0xf1,0xf7,0x1f,0x32},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVFilterstruct
-#endif
-
-UCHAR SiS300_StSCARTFilter[17][4]={
+    },
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xf1,0xf7,0x10,0x32},
@@ -307,13 +354,8 @@
 	{0xf1,0xf7,0x1f,0x32},
 	{0xf1,0xf7,0x1f,0x32},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVFilterstruct
-#endif
-
-UCHAR SiS300_StHiTVFilter[17][4]={
+    },
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xf1,0xf7,0x10,0x32},
@@ -331,13 +373,8 @@
 	{0xf1,0xf7,0x1f,0x32},
 	{0xf1,0xf7,0x1f,0x32},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVFilterstruct
-#endif
-
-UCHAR SiS300_ExtNTSCFilter[17][4]={
+    },
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xeb,0x04,0x10,0x18},
@@ -355,13 +392,8 @@
 	{0xeb,0x04,0x25,0x18},
 	{0xeb,0x04,0x25,0x18},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVFilterstruct
-#endif
-
-UCHAR SiS300_ExtPALFilter[17][4]={
+    },
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xf1,0xf7,0x10,0x32},
@@ -379,13 +411,8 @@
 	{0xf1,0xf7,0x1f,0x32},
 	{0xf1,0xf7,0x1f,0x32},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVFilterstruct
-#endif
-
-UCHAR SiS300_ExtSCARTFilter[17][4]={
+    },
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xf1,0xf7,0x10,0x32},
@@ -403,13 +430,8 @@
 	{0xf1,0xf7,0x1f,0x32},
 	{0xf1,0xf7,0x1f,0x32},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//SiS_OEMTVFilterstruct
-#endif
-
-UCHAR SiS300_ExtHiTVFilter[17][4]={
+    },
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xf1,0xf7,0x10,0x32},
@@ -427,44 +449,8 @@
 	{0xf1,0xf7,0x1f,0x32},
 	{0xf1,0xf7,0x1f,0x32},
 	{0xff,0xff,0xff,0xff}
-};
-
-#if 0
-//typedef struct _SiS_OEMTVFilter2struct{
-//UCHAR Index[7];
-//} SiS_OEMTVFilter2struct;
-//SiS_OEMTVFilter2struct
-#endif
-
-UCHAR SiS300_NTSCFilter2[9][7]={
-	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
-	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
-};
-
-#if 0
-//SiS_OEMTVFilter2struct
-#endif
-
-UCHAR SiS300_PALFilter2[9][7]={
-	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
-	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
-};
-
-UCHAR SiS300_PALMFilter[17][4]={
+    },
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xeb,0x04,0x10,0x18},
@@ -482,9 +468,8 @@
 	{0xeb,0x04,0x25,0x18},
 	{0xeb,0x04,0x25,0x18},
 	{0xff,0xff,0xff,0xff}
-};
-
-UCHAR SiS300_PALNFilter[17][4]={
+    },
+    {
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xeb,0x04,0x10,0x18},
@@ -502,10 +487,12 @@
 	{0xeb,0x04,0x25,0x18},
 	{0xeb,0x04,0x25,0x18},
 	{0xff,0xff,0xff,0xff}
+    },
 };
 
-
-UCHAR SiS300_PALMFilter2[9][7]={
+const UCHAR SiS300_Filter2[10][9][7] =
+{
+    {
 	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
 	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
 	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
@@ -515,9 +502,96 @@
 	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
 	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
 	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
-};
-
-UCHAR SiS300_PALNFilter2[9][7]={
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    },
+    {
 	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
 	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
 	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
@@ -527,5 +601,6 @@
 	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
 	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
 	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+    }
 };
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/sis/oem310.h linux.20pre10-ac2/drivers/video/sis/oem310.h
--- linux.20pre10/drivers/video/sis/oem310.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/sis/oem310.h	2002-10-11 00:17:32.000000000 +0100
@@ -1,92 +1,181 @@
 
-UCHAR SiS310_CRT2DelayCompensation1=0x4; /* 301A */
-UCHAR SiS310_LCDDelayCompensation1[]=
-		{0x0,0x0,0x0,0xb,0xb,0xb,0x8,0x8,0x8,0x8,0x8,0x8,
-		 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0};
-UCHAR SiS310_TVDelayCompensation1[]={0x2,0x2,0x2,0x2,0x8,0xb};
-UCHAR SiS310_CRT2DelayCompensation2=0xC; /* 301B */
-UCHAR SiS310_LCDDelayCompensation2[]=
-		{0x0,0x0,0x0,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x8,
-		 0x8,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0};
-UCHAR SiS310_TVDelayCompensation2[]={0x3,0x3,0x3,0x3,0x8,0xb};
-UCHAR SiS310_TVAntiFlick1[3][2]={{0x4,0x0},{0x4,0x8},{0x0,0x0}};
-
-UCHAR SiS310_TVEdge1[3][2]={{0x0,0x4},{0x0,0x4},{0x0,0x0}};
-
-UCHAR SiS310_TVYFilter1[3][8][4]=
-{
- {
-  {0x0,0xf4,0x10,0x38},
-  {0x0,0xf4,0x10,0x38},
-  {0xeb,0x4,0x25,0x18},
-  {0xf7,0x6,0x19,0x14},
-  {0x0,0xf4,0x10,0x38},
-  {0xeb,0x4,0x25,0x18},
-  {0xee,0xc,0x22,0x8},
-  {0xeb,0x15,0x25,0xf6}
- },
- {
-  {0x0,0xf4,0x10,0x38},
-  {0x0,0xf4,0x10,0x38},
-  {0xf1,0xf7,0x1f,0x32},
-  {0xf3,0x0,0x1d,0x20},
-  {0x0,0xf4,0x10,0x38},
-  {0xf1,0xf7,0x1f,0x32},
-  {0xf3,0x0,0x1d,0x20},
-  {0xfc,0xfb,0x14,0x2a}
- },
- {
-  {0x0,0x0,0x0,0x0},
-  {0x0,0xf4,0x10,0x38},
-  {0x0,0xf4,0x10,0x38},
-  {0xeb,0x4,0x25,0x18},
-  {0xf7,0x6,0x19,0x14},
-  {0x0,0xf4,0x10,0x38},
-  {0xeb,0x4,0x25,0x18},
-  {0xee,0xc,0x22,0x8}
+/* OEM Data for 310/325 series */
+
+const UCHAR SiS310_CRT2DelayCompensation1 = 0x04; /* 301A */
+
+const UCHAR SiS310_LCDDelayCompensation1[] =
+{
+		 0x00,0x00,0x00,    /*   800x600 */
+		 0x0b,0x0b,0x0b,    /*  1024x768 */
+		 0x08,0x08,0x08,    /* 1280x1024 */
+		 0x00,0x00,0x00,    /*   640x480 (unknown) */
+		 0x00,0x00,0x00,    /*  1024x600 (unknown) */
+		 0x00,0x00,0x00,    /*  1152x864 (unknown) */
+		 0x08,0x08,0x08,    /*  1280x960 (guessed) */
+		 0x00,0x00,0x00,    /*  1152x768 (unknown) */
+		 0x08,0x08,0x08,    /* 1400x1050 */
+		 0x08,0x08,0x08,    /*  1280x768  (guessed) */
+		 0x00,0x00,0x00,    /* 1600x1200 */
+		 0x00,0x00,0x00,    /*   320x480 (unknown) */
+		 0x00,0x00,0x00,
+		 0x00,0x00,0x00,
+		 0x00,0x00,0x00
+};
+
+const UCHAR SiS310_TVDelayCompensation1[] =
+{
+		  0x02,0x02,    /* NTSC Enhanced, Standard */
+                  0x02,0x02,    /* PAL */
+		  0x08,0x0b     /* HiVision */
+};
+
+const UCHAR SiS310_CRT2DelayCompensation2 = 0x00;   /* TW: From 650/301LV BIOS; was 0x0C; */      /* 301B */
+
+UCHAR SiS310_LCDDelayCompensation2[] =
+{
+		  0x01,0x01,0x01,    /*   800x600 */
+		  0x01,0x01,0x01,    /*  1024x768 */
+		  0x01,0x01,0x01,    /* 1280x1024 */
+                  0x01,0x01,0x01,    /*   640x480 (unknown) */
+		  0x01,0x01,0x01,    /*  1024x600 (unknown) */
+		  0x01,0x01,0x01,    /*  1152x864 (unknown) */
+		  0x01,0x01,0x01,    /*  1280x960 (guessed) */
+		  0x01,0x01,0x01,    /*  1152x768 (unknown) */
+		  0x01,0x01,0x01,    /* 1400x1050 */
+		  0x08,0x08,0x08,    /*  1280x768  (guessed) */
+		  0x01,0x01,0x01,    /* 1600x1200 */
+		  0x02,0x02,0x02,
+		  0x02,0x02,0x02,
+		  0x02,0x02,0x02,
+		  0x02,0x02,0x02
+};
+
+const UCHAR SiS310_TVDelayCompensation2[] =
+{
+		  0x03,0x03,        /* TW: From 650/301LVx 1.10.6s BIOS */
+		  0x03,0x03,
+		  0x03,0x03
+#if 0
+		  0x03,0x03,        /* NTSC Enhanced, Standard */
+                  0x03,0x03,        /* PAL */
+		  0x08,0x0b         /* HiVision */
+#endif
+};
+
+const UCHAR SiS310_CRT2DelayCompensation3 = 0x00;   /* LVDS */
+
+const UCHAR SiS310_LCDDelayCompensation3[] =
+{
+                   0x00,0x00,0x00,    /*   800x600 */
+		   0x00,0x00,0x00,    /*  1024x768 */
+		   0x00,0x00,0x00,    /* 1280x1024 */
+		   0x00,0x00,0x00,    /*   640x480 (unknown) */
+		   0x00,0x00,0x00,    /*  1024x600 (unknown) */
+		   0x00,0x00,0x00,    /*  1152x864 (unknown) */
+		   0x00,0x00,0x00,    /*  1280x960 (guessed) */
+		   0x00,0x00,0x00,    /*  1152x768 (unknown) */
+		   0x00,0x00,0x00,    /* 1400x1050 */
+		   0x00,0x00,0x00,    /*  1280x768  (guessed) */
+		   0x00,0x00,0x00,    /* 1600x1200 */
+		   0x00,0x00,0x00,
+		   0x00,0x00,0x00,
+		   0x00,0x00,0x00,
+		   0x00,0x00,0x00
+};
+
+const UCHAR SiS310_TVDelayCompensation3[] =
+{
+		   0x0a,0x0a,
+		   0x0a,0x0a,
+		   0x0a,0x0a
+};
+
+const UCHAR SiS310_TVAntiFlick1[3][2] =
+{
+            {0x4,0x0},
+	    {0x4,0x8},
+	    {0x0,0x0}
+};
+
+const UCHAR SiS310_TVEdge1[3][2] =
+{
+            {0x0,0x4},
+	    {0x0,0x4},
+	    {0x0,0x0}
+};
+
+const UCHAR SiS310_TVYFilter1[3][8][4] =
+{
+ {
+	{0x00,0xf4,0x10,0x38},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x25,0x18},
+	{0xf1,0x04,0x1f,0x18},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x25,0x18},
+	{0xee,0x0c,0x22,0x08},
+	{0xeb,0x15,0x25,0xf6}
+ },
+ {
+	{0x00,0xf4,0x10,0x38},
+	{0x00,0xf4,0x10,0x38},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf3,0x00,0x1d,0x20},
+	{0x00,0xf4,0x10,0x38},
+	{0xf1,0xf7,0x1f,0x32},
+	{0xf3,0x00,0x1d,0x20},
+	{0xfc,0xfb,0x14,0x2a}
+ },
+ {
+	{0x00,0x00,0x00,0x00},
+	{0x00,0xf4,0x10,0x38},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x25,0x18},
+	{0xf7,0x06,0x19,0x14},
+	{0x00,0xf4,0x10,0x38},
+	{0xeb,0x04,0x25,0x18},
+	{0xee,0x0c,0x22,0x08}
  }
 };
-/*301b*/
-UCHAR SiS310_TVYFilter2[3][9][7]=
+
+const UCHAR SiS310_TVYFilter2[3][9][7] =
 {
  {
-  {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-  {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-  {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-  {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-  {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-  {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-  {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-  {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
-  {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
- },
- {
-  {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-  {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-  {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-  {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-  {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-  {0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
-  {0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
-  {0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
-  {0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
- },
- {
-  
-  {0x0,0x0,0x0,0xF4,0xFF,0x1C,0x22},
-  {0x0,0x0,0x0,0xF4,0xFF,0x1C,0x22},
-  {0x0,0x0,0x0,0xF4,0xFF,0x1C,0x22},
-  {0x0,0x0,0x0,0xF4,0xFF,0x1C,0x22},
-  {0x0,0x0,0x0,0xF4,0xFF,0x1C,0x22},
-  {0x0,0x0,0x0,0xF4,0xFF,0x1C,0x22},
-  {0x0,0x0,0x0,0xF4,0xFF,0x1C,0x22},
-  {0x0,0x0,0x0,0xF4,0xFF,0x1C,0x22}
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+ },
+ {
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
+	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
+	{0x01,0x01,0xFC,0xF8,0x08,0x26,0x38},
+	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
+ },
+ {
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22},
+	{0x00,0x00,0x00,0xF4,0xFF,0x1C,0x22}
  }
 };
-/*end 301b*/
 
-/*add PALMN*/
-UCHAR SiS310_PALMFilter[17][4]={
+const UCHAR SiS310_PALMFilter[17][4] =
+{
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xeb,0x04,0x10,0x18},
@@ -106,7 +195,8 @@
 	{0xff,0xff,0xff,0xff}
 };
 
-UCHAR SiS310_PALNFilter[17][4]={
+const UCHAR SiS310_PALNFilter[17][4] =
+{
 	{0x00,0xf4,0x10,0x38},
 	{0x00,0xf4,0x10,0x38},
 	{0xeb,0x04,0x10,0x18},
@@ -127,7 +217,8 @@
 };
 
 
-UCHAR SiS310_PALMFilter2[9][7]={
+const UCHAR SiS310_PALMFilter2[9][7] =
+{
 	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
 	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
 	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
@@ -139,7 +230,8 @@
 	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
 };
 
-UCHAR SiS310_PALNFilter2[9][7]={
+const UCHAR SiS310_PALNFilter2[9][7] =
+{
 	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
 	{0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C},
 	{0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46},
@@ -151,35 +243,37 @@
 	{0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28}
 };
 
-/*end PALMN*/
-UCHAR SiS310_TVPhaseIncr1[3][2][4]=
+const UCHAR SiS310_TVPhaseIncr1[3][2][4]=
 {
  {
-  {0x21,0xed,0x8a,0x8},
-  {0x21,0xed,0x8a,0x8}
+	{0x21,0xed,0xba,0x08},
+	{0x21,0xed,0xba,0x08}
  },
  {
-  {0x2a,0x5,0xd3,0x0},
-  {0x2a,0x5,0xd3,0x0}
+	{0x2a,0x05,0xe3,0x00},
+	{0x2a,0x05,0xe3,0x00}
  },
  {
-  {0x2a,0x5,0xd3,0x0},
-  {0x2a,0x5,0xd3,0x0}
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00}
  }
 };
 
-UCHAR SiS310_TVPhaseIncr2[3][2][4]=
+const UCHAR SiS310_TVPhaseIncr2[3][2][4]=
 {
  {
-  {0x21,0xF0,0x7b,0xd6},
-  {0x21,0xF0,0x7b,0xd6}
+	{0x1e,0x8b,0xda,0xa7},   /* {0x21,0xF1,0x37,0x56}, - new (1.10.6s) */
+	{0x1e,0x8b,0xda,0xa7}    /* {0x21,0xF1,0x37,0x56} */
  },
  {
-  {0x2a,0x09,0x86,0xe9},
-  {0x2a,0x09,0x86,0xe9}
+	{0x2a,0x0a,0x41,0xe9},   /* {0x2a,0x09,0x86,0xe9}, */
+	{0x2a,0x0a,0x41,0xe9}    /* {0x2a,0x09,0x86,0xe9} */
  },
  {
-  {0x2a,0x5,0xd3,0x0},
-  {0x2a,0x5,0xd3,0x0}
+	{0x2a,0x05,0xd3,0x00},
+	{0x2a,0x05,0xd3,0x00}
  }
 };
+
+
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/sis/osdef.h linux.20pre10-ac2/drivers/video/sis/osdef.h
--- linux.20pre10/drivers/video/sis/osdef.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/sis/osdef.h	2002-10-11 00:17:32.000000000 +0100
@@ -7,6 +7,7 @@
 /**********************************************************************/
 #ifdef LINUX_KERNEL
 	#include <linux/config.h>
+	#include <linux/version.h>
 	#ifdef CONFIG_FB_SIS_300
  		#define SIS300
 	#endif
@@ -14,6 +15,12 @@
 	#ifdef CONFIG_FB_SIS_315
 		#define SIS315H
 	#endif
+	#if 1
+		#define SISFBACCEL	/* Include 2D acceleration */
+	#endif
+	#if 1
+		#define SISFB_PAN	/* Include Y-Panning code */
+	#endif
 #else
 /*	#define SIS300*/
 	#define SIS315H
@@ -122,6 +129,10 @@
 #define InPortLong(p)    inl((CARD16)(p))
 #endif
 
+/**********************************************************************/
+/*  LINUX KERNEL                                                      */
+/**********************************************************************/
+
 #ifdef LINUX_KERNEL
 #define OutPortByte(p,v) outb((u8)(v),(u16)(p))
 #define OutPortWord(p,v) outw((u16)(v),(u16)(p))
@@ -146,7 +157,7 @@
 
 
 /**********************************************************************/
-/*  WIN CE                                                          */
+/*  WIN CE                                                            */
 /**********************************************************************/
 
 #ifdef WINCE_HEADER
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/sis/sis_accel.c linux.20pre10-ac2/drivers/video/sis/sis_accel.c
--- linux.20pre10/drivers/video/sis/sis_accel.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/sis/sis_accel.c	2002-10-11 00:17:32.000000000 +0100
@@ -0,0 +1,508 @@
+/*
+ * SiS 300/630/730/540/315/550/650/740 frame buffer driver
+ * for Linux kernels 2.4.x and 2.5.x
+ *
+ * 2D acceleration part
+ *
+ * Based on the X driver's sis300_accel.c which is
+ *     Copyright Xavier Ducoin <x.ducoin@lectra.com>
+ *     Copyright 2002 by Thomas Winischhofer, Vienna, Austria
+ * and sis310_accel.c which is
+ *     Copyright 2002 by Thomas Winischhofer, Vienna, Austria
+ *
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ *			(see http://www.winischhofer.net/
+ *			for more information and updates)
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vt_kern.h>
+#include <linux/capability.h>
+#include <linux/fs.h>
+#include <linux/agp_backend.h>
+
+#include <linux/types.h>
+#include <linux/sisfb.h>
+
+#include <asm/io.h>
+#include <asm/mtrr.h>
+
+#include <video/fbcon.h>
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+#endif
+
+#include "osdef.h"
+#include "vgatypes.h"
+#include "vstruct.h"
+#include "sis_accel.h"
+#include "sis.h"
+
+extern struct     video_info ivideo;
+extern VGA_ENGINE sisvga_engine;
+
+static const int sisALUConv[] =
+{
+    0x00,       /* dest = 0;            0,      GXclear,        0 */
+    0x88,       /* dest &= src;         DSa,    GXand,          0x1 */
+    0x44,       /* dest = src & ~dest;  SDna,   GXandReverse,   0x2 */
+    0xCC,       /* dest = src;          S,      GXcopy,         0x3 */
+    0x22,       /* dest &= ~src;        DSna,   GXandInverted,  0x4 */
+    0xAA,       /* dest = dest;         D,      GXnoop,         0x5 */
+    0x66,       /* dest = ^src;         DSx,    GXxor,          0x6 */
+    0xEE,       /* dest |= src;         DSo,    GXor,           0x7 */
+    0x11,       /* dest = ~src & ~dest; DSon,   GXnor,          0x8 */
+    0x99,       /* dest ^= ~src ;       DSxn,   GXequiv,        0x9 */
+    0x55,       /* dest = ~dest;        Dn,     GXInvert,       0xA */
+    0xDD,       /* dest = src|~dest ;   SDno,   GXorReverse,    0xB */
+    0x33,       /* dest = ~src;         Sn,     GXcopyInverted, 0xC */
+    0xBB,       /* dest |= ~src;        DSno,   GXorInverted,   0xD */
+    0x77,       /* dest = ~src|~dest;   DSan,   GXnand,         0xE */
+    0xFF,       /* dest = 0xFF;         1,      GXset,          0xF */
+};
+/* same ROP but with Pattern as Source */
+static const int sisPatALUConv[] =
+{
+    0x00,       /* dest = 0;            0,      GXclear,        0 */
+    0xA0,       /* dest &= src;         DPa,    GXand,          0x1 */
+    0x50,       /* dest = src & ~dest;  PDna,   GXandReverse,   0x2 */
+    0xF0,       /* dest = src;          P,      GXcopy,         0x3 */
+    0x0A,       /* dest &= ~src;        DPna,   GXandInverted,  0x4 */
+    0xAA,       /* dest = dest;         D,      GXnoop,         0x5 */
+    0x5A,       /* dest = ^src;         DPx,    GXxor,          0x6 */
+    0xFA,       /* dest |= src;         DPo,    GXor,           0x7 */
+    0x05,       /* dest = ~src & ~dest; DPon,   GXnor,          0x8 */
+    0xA5,       /* dest ^= ~src ;       DPxn,   GXequiv,        0x9 */
+    0x55,       /* dest = ~dest;        Dn,     GXInvert,       0xA */
+    0xF5,       /* dest = src|~dest ;   PDno,   GXorReverse,    0xB */
+    0x0F,       /* dest = ~src;         Pn,     GXcopyInverted, 0xC */
+    0xAF,       /* dest |= ~src;        DPno,   GXorInverted,   0xD */
+    0x5F,       /* dest = ~src|~dest;   DPan,   GXnand,         0xE */
+    0xFF,       /* dest = 0xFF;         1,      GXset,          0xF */
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+static const unsigned char myrops[] = {
+   	3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
+   };
+#endif
+
+/* 300 series */
+
+static void
+SiS300Sync(void)
+{
+	SiS300Idle
+}
+
+static void
+SiS310Sync(void)
+{
+	SiS310Idle
+}
+
+static void
+SiS300SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
+                                unsigned int planemask, int trans_color)
+{
+	SiS300SetupDSTColorDepth(ivideo.DstColor);
+	SiS300SetupSRCPitch(ivideo.video_linelength)
+	SiS300SetupDSTRect(ivideo.video_linelength, -1)
+
+	if(trans_color != -1) {
+		SiS300SetupROP(0x0A)
+		SiS300SetupSRCTrans(trans_color)
+		SiS300SetupCMDFlag(TRANSPARENT_BITBLT)
+	} else {
+	        SiS300SetupROP(sisALUConv[rop])
+	}
+	if(xdir > 0) {
+		SiS300SetupCMDFlag(X_INC)
+	}
+	if(ydir > 0) {
+		SiS300SetupCMDFlag(Y_INC)
+	}
+}
+
+static void
+SiS300SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y,
+                                int width, int height)
+{
+	long srcbase, dstbase;
+
+	srcbase = dstbase = 0;
+	if (src_y >= 2048) {
+		srcbase = ivideo.video_linelength * src_y;
+		src_y = 0;
+	}
+	if (dst_y >= 2048) {
+		dstbase = ivideo.video_linelength * dst_y;
+		dst_y = 0;
+	}
+
+	SiS300SetupSRCBase(srcbase);
+	SiS300SetupDSTBase(dstbase);
+
+	if(!(ivideo.CommandReg & X_INC))  {
+		src_x += width-1;
+		dst_x += width-1;
+	}
+	if(!(ivideo.CommandReg & Y_INC))  {
+		src_y += height-1;
+		dst_y += height-1;
+	}
+	SiS300SetupRect(width, height)
+	SiS300SetupSRCXY(src_x, src_y)
+	SiS300SetupDSTXY(dst_x, dst_y)
+	SiS300DoCMD
+}
+
+static void
+SiS300SetupForSolidFill(int color, int rop, unsigned int planemask)
+{
+	SiS300SetupPATFG(color)
+	SiS300SetupDSTRect(ivideo.video_linelength, -1)
+	SiS300SetupDSTColorDepth(ivideo.DstColor);
+	SiS300SetupROP(sisPatALUConv[rop])
+	SiS300SetupCMDFlag(PATFG)
+}
+
+static void
+SiS300SubsequentSolidFillRect(int x, int y, int w, int h)
+{
+	long dstbase;
+
+	dstbase = 0;
+	if(y >= 2048) {
+		dstbase = ivideo.video_linelength * y;
+		y = 0;
+	}
+	SiS300SetupDSTBase(dstbase)
+	SiS300SetupDSTXY(x,y)
+	SiS300SetupRect(w,h)
+	SiS300SetupCMDFlag(X_INC | Y_INC | BITBLT)
+	SiS300DoCMD
+}
+
+/* 310/325 series ------------------------------------------------ */
+
+static void
+SiS310SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
+                                unsigned int planemask, int trans_color)
+{
+	SiS310SetupDSTColorDepth(ivideo.DstColor);
+	SiS310SetupSRCPitch(ivideo.video_linelength)
+	SiS310SetupDSTRect(ivideo.video_linelength, -1)
+	if (trans_color != -1) {
+		SiS310SetupROP(0x0A)
+		SiS310SetupSRCTrans(trans_color)
+		SiS310SetupCMDFlag(TRANSPARENT_BITBLT)
+	} else {
+	        SiS310SetupROP(sisALUConv[rop])
+		/* Set command - not needed, both 0 */
+		/* SiSSetupCMDFlag(BITBLT | SRCVIDEO) */
+	}
+	SiS310SetupCMDFlag(ivideo.SiS310_AccelDepth)
+	/* TW: The 310/325 series is smart enough to know the direction */
+}
+
+static void
+SiS310SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y,
+                                int width, int height)
+{
+	long srcbase, dstbase;
+
+	srcbase = dstbase = 0;
+	if (src_y >= 2048) {
+		srcbase = ivideo.video_linelength * src_y;
+		src_y = 0;
+	}
+	if (dst_y >= 2048) {
+		dstbase = ivideo.video_linelength * dst_y;
+		dst_y = 0;
+	}
+
+	SiS310SetupSRCBase(srcbase);
+	SiS310SetupDSTBase(dstbase);
+	SiS310SetupRect(width, height)
+	SiS310SetupSRCXY(src_x, src_y)
+	SiS310SetupDSTXY(dst_x, dst_y)
+	SiS310DoCMD
+}
+
+static void
+SiS310SetupForSolidFill(int color, int rop, unsigned int planemask)
+{
+	SiS310SetupPATFG(color)
+	SiS310SetupDSTRect(ivideo.video_linelength, -1)
+	SiS310SetupDSTColorDepth(ivideo.DstColor);
+	SiS310SetupROP(sisPatALUConv[rop])
+	SiS310SetupCMDFlag(PATFG | ivideo.SiS310_AccelDepth)
+}
+
+static void
+SiS310SubsequentSolidFillRect(int x, int y, int w, int h)
+{
+	long dstbase;
+
+	dstbase = 0;
+	if(y >= 2048) {
+		dstbase = ivideo.video_linelength * y;
+		y = 0;
+	}
+	SiS310SetupDSTBase(dstbase)
+	SiS310SetupDSTXY(x,y)
+	SiS310SetupRect(w,h)
+	SiS310SetupCMDFlag(BITBLT)
+	SiS310DoCMD
+}
+
+/* --------------------------------------------------------------------- */
+
+/* The exported routines */
+
+int sisfb_initaccel(void)
+{
+#ifdef SISFB_USE_SPINLOCKS
+    spin_lock_init(&ivideo.lockaccel);
+#endif
+    return(0);
+}
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)  /* --- KERNEL 2.5.34 and later --- */
+
+void fbcon_sis_fillrect(struct fb_info *info, struct fb_fillrect *rect)
+{
+   CRITFLAGS
+
+   TWDEBUG("Inside sis_fillrect");
+   if(!rect->width || !rect->height)
+   	return;
+
+   if(!sisfb_accel) {
+        cfb_fillrect(info, rect);
+	return;
+   }
+
+   if(sisvga_engine == SIS_300_VGA) {
+	   CRITBEGIN
+	   SiS300SetupForSolidFill(rect->color, myrops[rect->rop], 0);
+	   SiS300SubsequentSolidFillRect(rect->dx, rect->dy, rect->width, rect->height);
+	   CRITEND
+	   SiS300Sync();
+   } else {
+	   CRITBEGIN
+	   SiS310SetupForSolidFill(rect->color, myrops[rect->rop], 0);
+	   SiS310SubsequentSolidFillRect(rect->dx, rect->dy, rect->width, rect->height);
+	   CRITEND
+	   SiS310Sync();
+   }
+
+}
+
+void fbcon_sis_copyarea(struct fb_info *info, struct fb_copyarea *area)
+{
+   int xdir, ydir;
+   CRITFLAGS
+
+   TWDEBUG("Inside sis_copyarea");
+   if(!sisfb_accel) {
+   	cfb_copyarea(info, area);
+	return;
+   }
+
+   if(!area->width || !area->height)
+   	return;
+
+   if(area->sx < area->dx) xdir = 0;
+   else                    xdir = 1;
+   if(area->sy < area->dy) ydir = 0;
+   else                    ydir = 1;
+
+   if(sisvga_engine == SIS_300_VGA) {
+      CRITBEGIN
+      SiS300SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
+      SiS300SubsequentScreenToScreenCopy(area->sx, area->sy, area->dx, area->dy, area->width, area->height);
+      CRITEND
+      SiS300Sync();
+   } else {
+      CRITBEGIN
+      SiS310SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
+      SiS310SubsequentScreenToScreenCopy(area->sx, area->sy, area->dx, area->dy, area->width, area->height);
+      CRITEND
+      SiS310Sync();
+   }
+}
+
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)  /* ------ KERNEL <2.5.34 ------ */
+
+void fbcon_sis_bmove(struct display *p, int srcy, int srcx,
+			    int dsty, int dstx, int height, int width)
+{
+        int xdir, ydir;
+	CRITFLAGS
+
+	srcx *= fontwidth(p);
+	srcy *= fontheight(p);
+	dstx *= fontwidth(p);
+	dsty *= fontheight(p);
+	width *= fontwidth(p);
+	height *= fontheight(p);
+
+
+	if(srcx < dstx) xdir = 0;
+	else            xdir = 1;
+	if(srcy < dsty) ydir = 0;
+	else            ydir = 1;
+
+	if(sisvga_engine == SIS_300_VGA) {
+	   CRITBEGIN
+	   SiS300SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
+	   SiS300SubsequentScreenToScreenCopy(srcx, srcy, dstx, dsty, width, height);
+	   CRITEND
+	   SiS300Sync();
+	} else {
+	   CRITBEGIN
+	   SiS310SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
+	   SiS310SubsequentScreenToScreenCopy(srcx, srcy, dstx, dsty, width, height);
+	   CRITEND
+	   SiS310Sync();
+	}
+}
+
+
+static void fbcon_sis_clear(struct vc_data *conp, struct display *p,
+			int srcy, int srcx, int height, int width, int color)
+{
+	CRITFLAGS
+
+	srcx *= fontwidth(p);
+	srcy *= fontheight(p);
+	width *= fontwidth(p);
+	height *= fontheight(p);
+
+	if(sisvga_engine == SIS_300_VGA) {
+	   CRITBEGIN
+	   SiS300SetupForSolidFill(color, 3, 0);
+	   SiS300SubsequentSolidFillRect(srcx, srcy, width, height);
+	   CRITEND
+	   SiS300Sync();
+	} else {
+	   CRITBEGIN
+	   SiS310SetupForSolidFill(color, 3, 0);
+	   SiS310SubsequentSolidFillRect(srcx, srcy, width, height);
+	   CRITEND
+	   SiS310Sync();
+	}
+}
+
+void fbcon_sis_clear8(struct vc_data *conp, struct display *p,
+			int srcy, int srcx, int height, int width)
+{
+	u32 bgx;
+
+	bgx = attr_bgcol_ec(p, conp);
+	fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx);
+}
+
+void fbcon_sis_clear16(struct vc_data *conp, struct display *p,
+			int srcy, int srcx, int height, int width)
+{
+	u32 bgx;
+
+	bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+	fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx);
+}
+
+void fbcon_sis_clear32(struct vc_data *conp, struct display *p,
+			int srcy, int srcx, int height, int width)
+{
+	u32 bgx;
+
+	bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+	fbcon_sis_clear(conp, p, srcy, srcx, height, width, bgx);
+}
+
+void fbcon_sis_revc(struct display *p, int srcx, int srcy)
+{
+	CRITFLAGS
+
+	srcx *= fontwidth(p);
+	srcy *= fontheight(p);
+
+	if(sisvga_engine == SIS_300_VGA) {
+	   CRITBEGIN
+	   SiS300SetupForSolidFill(0, 0x0a, 0);
+	   SiS300SubsequentSolidFillRect(srcx, srcy, fontwidth(p), fontheight(p));
+	   CRITEND
+	   SiS300Sync();
+	} else {
+	   CRITBEGIN
+	   SiS310SetupForSolidFill(0, 0x0a, 0);
+	   SiS310SubsequentSolidFillRect(srcx, srcy, fontwidth(p), fontheight(p));
+	   CRITEND
+	   SiS310Sync();
+	}
+}
+
+#ifdef FBCON_HAS_CFB8
+struct display_switch fbcon_sis8 = {
+	setup:			fbcon_cfb8_setup,
+	bmove:			fbcon_sis_bmove,
+	clear:			fbcon_sis_clear8,
+	putc:			fbcon_cfb8_putc,
+	putcs:			fbcon_cfb8_putcs,
+	revc:			fbcon_cfb8_revc,
+	clear_margins:		fbcon_cfb8_clear_margins,
+	fontwidthmask:		FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+#ifdef FBCON_HAS_CFB16
+struct display_switch fbcon_sis16 = {
+	setup:			fbcon_cfb16_setup,
+	bmove:			fbcon_sis_bmove,
+	clear:			fbcon_sis_clear16,
+	putc:			fbcon_cfb16_putc,
+	putcs:			fbcon_cfb16_putcs,
+	revc:			fbcon_sis_revc,
+	clear_margins:		fbcon_cfb16_clear_margins,
+	fontwidthmask:		FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+#ifdef FBCON_HAS_CFB32
+struct display_switch fbcon_sis32 = {
+	setup:			fbcon_cfb32_setup,
+	bmove:			fbcon_sis_bmove,
+	clear:			fbcon_sis_clear32,
+	putc:			fbcon_cfb32_putc,
+	putcs:			fbcon_cfb32_putcs,
+	revc:			fbcon_sis_revc,
+	clear_margins:		fbcon_cfb32_clear_margins,
+	fontwidthmask:		FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+
+#endif /* KERNEL VERSION */
+
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/sis/sis_accel.h linux.20pre10-ac2/drivers/video/sis/sis_accel.h
--- linux.20pre10/drivers/video/sis/sis_accel.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/sis/sis_accel.h	2002-10-11 00:17:32.000000000 +0100
@@ -0,0 +1,508 @@
+/*
+ * SiS 300/630/730/540/315/550/650/740 frame buffer driver
+ * for Linux kernels 2.4.x and 2.5.x
+ *
+ * 2D acceleration part
+ *
+ * Based on the X driver's sis300_accel.h which is
+ *     Copyright Xavier Ducoin <x.ducoin@lectra.com>
+ *     Copyright 2002 by Thomas Winischhofer, Vienna, Austria
+ * and sis310_accel.h which is
+ *     Copyright 2002 by Thomas Winischhofer, Vienna, Austria
+ *
+ * Author:   Thomas Winischhofer <thomas@winischhofer.net>:
+ *			(see http://www.winischhofer.net/
+ *			for more information and updates)
+ */
+
+#ifndef _SISFB_ACCEL_H
+#define _SISFB_ACCEL_H
+
+/* Guard accelerator accesses with spin_lock_irqsave? Works well without. */
+#undef SISFB_USE_SPINLOCKS
+
+#ifdef SISFB_USE_SPINLOCKS
+#include <linux/spinlock.h>
+#define CRITBEGIN  spin_lock_irqsave(&ivideo.lockaccel), critflags);
+#define CRITEND	   spin_unlock_irqrestore(&ivideo.lockaccel), critflags);
+#define CRITFLAGS  unsigned long critflags;
+#else
+#define CRITBEGIN
+#define CRITEND
+#define CRITFLAGS
+#endif
+
+/* Definitions for the SIS engine communication. */
+
+#define PATREGSIZE      384  /* Pattern register size. 384 bytes @ 0x8300 */
+#define BR(x)   (0x8200 | (x) << 2)
+#define PBR(x)  (0x8300 | (x) << 2)
+
+/* SiS300 engine commands */
+#define BITBLT                  0x00000000  /* Blit */
+#define COLOREXP                0x00000001  /* Color expand */
+#define ENCOLOREXP              0x00000002  /* Enhanced color expand */
+#define MULTIPLE_SCANLINE       0x00000003  /* ? */
+#define LINE                    0x00000004  /* Draw line */
+#define TRAPAZOID_FILL          0x00000005  /* Fill trapezoid */
+#define TRANSPARENT_BITBLT      0x00000006  /* Transparent Blit */
+
+/* Additional engine commands for 310/325 */
+#define ALPHA_BLEND		0x00000007  /* Alpha blend ? */
+#define A3D_FUNCTION		0x00000008  /* 3D command ? */
+#define	CLEAR_Z_BUFFER		0x00000009  /* ? */
+#define GRADIENT_FILL		0x0000000A  /* Gradient fill */
+#define STRETCH_BITBLT		0x0000000B  /* Stretched Blit */
+
+/* source select */
+#define SRCVIDEO                0x00000000  /* source is video RAM */
+#define SRCSYSTEM               0x00000010  /* source is system memory */
+#define SRCCPUBLITBUF           SRCSYSTEM   /* source is CPU-driven BitBuffer (for color expand) */
+#define SRCAGP                  0x00000020  /* source is AGP memory (?) */
+
+/* Pattern flags */
+#define PATFG                   0x00000000  /* foreground color */
+#define PATPATREG               0x00000040  /* pattern in pattern buffer (0x8300) */
+#define PATMONO                 0x00000080  /* mono pattern */
+
+/* blitting direction (300 series only) */
+#define X_INC                   0x00010000
+#define X_DEC                   0x00000000
+#define Y_INC                   0x00020000
+#define Y_DEC                   0x00000000
+
+/* Clipping flags */
+#define NOCLIP                  0x00000000
+#define NOMERGECLIP             0x04000000
+#define CLIPENABLE              0x00040000
+#define CLIPWITHOUTMERGE        0x04040000
+
+/* Transparency */
+#define OPAQUE                  0x00000000
+#define TRANSPARENT             0x00100000
+
+/* ? */
+#define DSTAGP                  0x02000000
+#define DSTVIDEO                0x02000000
+
+/* Line */
+#define LINE_STYLE              0x00800000
+#define NO_RESET_COUNTER        0x00400000
+#define NO_LAST_PIXEL           0x00200000
+
+/* Subfunctions for Color/Enhanced Color Expansion (310/325 only) */
+#define COLOR_TO_MONO		0x00100000
+#define AA_TEXT			0x00200000
+
+/* Some general registers for 310/325 series */
+#define SRC_ADDR		0x8200
+#define SRC_PITCH		0x8204
+#define AGP_BASE		0x8206 /* color-depth dependent value */
+#define SRC_Y			0x8208
+#define SRC_X			0x820A
+#define DST_Y			0x820C
+#define DST_X			0x820E
+#define DST_ADDR		0x8210
+#define DST_PITCH		0x8214
+#define DST_HEIGHT		0x8216
+#define RECT_WIDTH		0x8218
+#define RECT_HEIGHT		0x821A
+#define PAT_FGCOLOR		0x821C
+#define PAT_BGCOLOR		0x8220
+#define SRC_FGCOLOR		0x8224
+#define SRC_BGCOLOR		0x8228
+#define MONO_MASK		0x822C
+#define LEFT_CLIP		0x8234
+#define TOP_CLIP		0x8236
+#define RIGHT_CLIP		0x8238
+#define BOTTOM_CLIP		0x823A
+#define COMMAND_READY		0x823C
+#define FIRE_TRIGGER      	0x8240
+
+#define PATTERN_REG		0x8300  /* 384 bytes pattern buffer */
+
+/* Line registers */
+#define LINE_X0			SRC_Y
+#define LINE_X1			DST_Y
+#define LINE_Y0			SRC_X
+#define LINE_Y1			DST_X
+#define LINE_COUNT		RECT_WIDTH
+#define LINE_STYLE_PERIOD	RECT_HEIGHT
+#define LINE_STYLE_0		MONO_MASK
+#define LINE_STYLE_1		0x8230
+#define LINE_XN			PATTERN_REG
+#define LINE_YN			PATTERN_REG+2
+
+/* Transparent bitblit registers */
+#define TRANS_DST_KEY_HIGH	PAT_FGCOLOR
+#define TRANS_DST_KEY_LOW	PAT_BGCOLOR
+#define TRANS_SRC_KEY_HIGH	SRC_FGCOLOR
+#define TRANS_SRC_KEY_LOW	SRC_BGCOLOR
+
+/* Queue */
+#define Q_BASE_ADDR		0x85C0  /* Base address of software queue (?) */
+#define Q_WRITE_PTR		0x85C4  /* Current write pointer (?) */
+#define Q_READ_PTR		0x85C8  /* Current read pointer (?) */
+#define Q_STATUS		0x85CC  /* queue status */
+
+
+#define MMIO_IN8(base, offset) \
+	*(volatile u8 *)(((u8*)(base)) + (offset))
+#define MMIO_IN16(base, offset) \
+	*(volatile u16 *)(void *)(((u8*)(base)) + (offset))
+#define MMIO_IN32(base, offset) \
+	*(volatile u32 *)(void *)(((u8*)(base)) + (offset))
+#define MMIO_OUT8(base, offset, val) \
+	*(volatile u8 *)(((u8*)(base)) + (offset)) = (val)
+#define MMIO_OUT16(base, offset, val) \
+	*(volatile u16 *)(void *)(((u8*)(base)) + (offset)) = (val)
+#define MMIO_OUT32(base, offset, val) \
+	*(volatile u32 *)(void *)(((u8*)(base)) + (offset)) = (val)
+
+/* ------------- SiS 300 series -------------- */
+
+/* Macros to do useful things with the SIS BitBLT engine */
+
+/* BR(16) (0x8420):
+
+   bit 31 2D engine: 1 is idle,
+   bit 30 3D engine: 1 is idle,
+   bit 29 Command queue: 1 is empty
+
+   bits 28:24: Current CPU driven BitBlt buffer stage bit[4:0]
+
+   bits 15:0:  Current command queue length
+
+*/
+
+/* TW: BR(16)+2 = 0x8242 */
+
+int     CmdQueLen;
+
+#define SiS300Idle \
+  { \
+  while( (MMIO_IN16(ivideo.mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \
+  while( (MMIO_IN16(ivideo.mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \
+  while( (MMIO_IN16(ivideo.mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \
+  CmdQueLen=MMIO_IN16(ivideo.mmio_vbase, 0x8240); \
+  }
+/* TW: (do three times, because 2D engine seems quite unsure about whether or not it's idle) */
+
+#define SiS300SetupSRCBase(base) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(0), base);\
+                CmdQueLen --;
+
+#define SiS300SetupSRCPitch(pitch) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT16(ivideo.mmio_vbase, BR(1), pitch);\
+                CmdQueLen --;
+
+#define SiS300SetupSRCXY(x,y) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(2), (x)<<16 | (y) );\
+                CmdQueLen --;
+
+#define SiS300SetupDSTBase(base) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(4), base);\
+                CmdQueLen --;
+
+#define SiS300SetupDSTXY(x,y) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(3), (x)<<16 | (y) );\
+                CmdQueLen --;
+
+#define SiS300SetupDSTRect(x,y) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(5), (y)<<16 | (x) );\
+                CmdQueLen --;
+
+#define SiS300SetupDSTColorDepth(bpp) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT16(ivideo.mmio_vbase, BR(1)+2, bpp);\
+                CmdQueLen --;
+
+#define SiS300SetupRect(w,h) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(6), (h)<<16 | (w) );\
+                CmdQueLen --;
+
+#define SiS300SetupPATFG(color) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(7), color);\
+                CmdQueLen --;
+
+#define SiS300SetupPATBG(color) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(8), color);\
+                CmdQueLen --;
+
+#define SiS300SetupSRCFG(color) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(9), color);\
+                CmdQueLen --;
+
+#define SiS300SetupSRCBG(color) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(10), color);\
+                CmdQueLen --;
+
+/* 0x8224 src colorkey high */
+/* 0x8228 src colorkey low */
+/* 0x821c dest colorkey high */
+/* 0x8220 dest colorkey low */
+#define SiS300SetupSRCTrans(color) \
+                if (CmdQueLen <= 1)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, 0x8224, color);\
+		MMIO_OUT32(ivideo.mmio_vbase, 0x8228, color);\
+		CmdQueLen -= 2;
+
+#define SiS300SetupDSTTrans(color) \
+		if (CmdQueLen <= 1)  SiS300Idle;\
+		MMIO_OUT32(ivideo.mmio_vbase, 0x821C, color); \
+		MMIO_OUT32(ivideo.mmio_vbase, 0x8220, color); \
+                CmdQueLen -= 2;
+
+#define SiS300SetupMONOPAT(p0,p1) \
+                if (CmdQueLen <= 1)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(11), p0);\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(12), p1);\
+                CmdQueLen -= 2;
+
+#define SiS300SetupClipLT(left,top) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(13), ((left) & 0xFFFF) | (top)<<16 );\
+                CmdQueLen--;
+
+#define SiS300SetupClipRB(right,bottom) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(14), ((right) & 0xFFFF) | (bottom)<<16 );\
+                CmdQueLen--;
+
+/* General */
+#define SiS300SetupROP(rop) \
+                ivideo.CommandReg = (rop) << 8;
+
+#define SiS300SetupCMDFlag(flags) \
+                ivideo.CommandReg |= (flags);
+
+#define SiS300DoCMD \
+                if (CmdQueLen <= 1)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(15), ivideo.CommandReg); \
+                MMIO_OUT32(ivideo.mmio_vbase, BR(16), 0);\
+                CmdQueLen -= 2;
+
+/* Line */
+#define SiS300SetupX0Y0(x,y) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(2), (y)<<16 | (x) );\
+                CmdQueLen--;
+
+#define SiS300SetupX1Y1(x,y) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(3), (y)<<16 | (x) );\
+                CmdQueLen--;
+
+#define SiS300SetupLineCount(c) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT16(ivideo.mmio_vbase, BR(6), c);\
+                CmdQueLen--;
+
+#define SiS300SetupStylePeriod(p) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT16(ivideo.mmio_vbase, BR(6)+2, p);\
+                CmdQueLen--;
+
+#define SiS300SetupStyleLow(ls) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(11), ls);\
+                CmdQueLen--;
+
+#define SiS300SetupStyleHigh(ls) \
+                if (CmdQueLen <= 0)  SiS300Idle;\
+                MMIO_OUT32(ivideo.mmio_vbase, BR(12), ls);\
+                CmdQueLen--;
+
+
+
+/* ----------- SiS 310/325 series --------------- */
+
+/* Q_STATUS:
+   bit 31 = 1: All engines idle and all queues empty
+   bit 30 = 1: Hardware Queue (=HW CQ, 2D queue, 3D queue) empty
+   bit 29 = 1: 2D engine is idle
+   bit 28 = 1: 3D engine is idle
+   bit 27 = 1: HW command queue empty
+   bit 26 = 1: 2D queue empty
+   bit 25 = 1: 3D queue empty
+   bit 24 = 1: SW command queue empty
+   bits 23:16: 2D counter 3
+   bits 15:8:  2D counter 2
+   bits 7:0:   2D counter 1
+
+   Where is the command queue length (current amount of commands the queue
+   can accept) on the 310/325 series? (The current implementation is taken
+   from 300 series and certainly wrong...)
+*/
+
+/* TW: FIXME: CmdQueLen is... where....? */
+#define SiS310Idle \
+  { \
+  while( (MMIO_IN16(ivideo.mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \
+  while( (MMIO_IN16(ivideo.mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \
+  CmdQueLen=MMIO_IN16(ivideo.mmio_vbase, Q_STATUS); \
+  }
+
+#define SiS310SetupSRCBase(base) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, SRC_ADDR, base);\
+      CmdQueLen--;
+
+#define SiS310SetupSRCPitch(pitch) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT16(ivideo.mmio_vbase, SRC_PITCH, pitch);\
+      CmdQueLen--;
+
+#define SiS310SetupSRCXY(x,y) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, SRC_Y, (x)<<16 | (y) );\
+      CmdQueLen--;
+
+#define SiS310SetupDSTBase(base) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, DST_ADDR, base);\
+      CmdQueLen--;
+
+#define SiS310SetupDSTXY(x,y) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, DST_Y, (x)<<16 | (y) );\
+      CmdQueLen--;
+
+#define SiS310SetupDSTRect(x,y) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, DST_PITCH, (y)<<16 | (x) );\
+      CmdQueLen--;
+
+#define SiS310SetupDSTColorDepth(bpp) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT16(ivideo.mmio_vbase, AGP_BASE, bpp);\
+      CmdQueLen--;
+
+#define SiS310SetupRect(w,h) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, RECT_WIDTH, (h)<<16 | (w) );\
+      CmdQueLen--;
+
+#define SiS310SetupPATFG(color) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, PAT_FGCOLOR, color);\
+      CmdQueLen--;
+
+#define SiS310SetupPATBG(color) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, PAT_BGCOLOR, color);\
+      CmdQueLen--;
+
+#define SiS310SetupSRCFG(color) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, SRC_FGCOLOR, color);\
+      CmdQueLen--;
+
+#define SiS310SetupSRCBG(color) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, SRC_BGCOLOR, color);\
+      CmdQueLen--;
+
+#define SiS310SetupSRCTrans(color) \
+      if (CmdQueLen <= 1)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, TRANS_SRC_KEY_HIGH, color);\
+      MMIO_OUT32(ivideo.mmio_vbase, TRANS_SRC_KEY_LOW, color);\
+      CmdQueLen -= 2;
+
+#define SiS310SetupDSTTrans(color) \
+      if (CmdQueLen <= 1)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, TRANS_DST_KEY_HIGH, color); \
+      MMIO_OUT32(ivideo.mmio_vbase, TRANS_DST_KEY_LOW, color); \
+      CmdQueLen -= 2;
+
+#define SiS310SetupMONOPAT(p0,p1) \
+      if (CmdQueLen <= 1)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, MONO_MASK, p0);\
+      MMIO_OUT32(ivideo.mmio_vbase, MONO_MASK+4, p1);\
+      CmdQueLen -= 2;
+
+#define SiS310SetupClipLT(left,top) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, LEFT_CLIP, ((left) & 0xFFFF) | (top)<<16 );\
+      CmdQueLen--;
+
+#define SiS310SetupClipRB(right,bottom) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, RIGHT_CLIP, ((right) & 0xFFFF) | (bottom)<<16 );\
+      CmdQueLen--;
+
+#define SiS310SetupROP(rop) \
+      ivideo.CommandReg = (rop) << 8;
+
+#define SiS310SetupCMDFlag(flags) \
+      ivideo.CommandReg |= (flags);
+
+#define SiS310DoCMD \
+      if (CmdQueLen <= 1)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, COMMAND_READY, ivideo.CommandReg); \
+      MMIO_OUT32(ivideo.mmio_vbase, FIRE_TRIGGER, 0); \
+      CmdQueLen -= 2;
+
+#define SiS310SetupX0Y0(x,y) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, LINE_X0, (y)<<16 | (x) );\
+      CmdQueLen--;
+
+#define SiS310SetupX1Y1(x,y) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, LINE_X1, (y)<<16 | (x) );\
+      CmdQueLen--;
+
+#define SiS310SetupLineCount(c) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT16(ivideo.mmio_vbase, LINE_COUNT, c);\
+      CmdQueLen--;
+
+#define SiS310SetupStylePeriod(p) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT16(ivideo.mmio_vbase, LINE_STYLE_PERIOD, p);\
+      CmdQueLen--;
+
+#define SiS310SetupStyleLow(ls) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, LINE_STYLE_0, ls);\
+      CmdQueLen--;
+
+#define SiS310SetupStyleHigh(ls) \
+      if (CmdQueLen <= 0)  SiS310Idle;\
+      MMIO_OUT32(ivideo.mmio_vbase, LINE_STYLE_1, ls);\
+      CmdQueLen--;
+
+int  sisfb_initaccel(void);
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+void fbcon_sis_bmove(struct display *p, int srcy, int srcx, int dsty,
+                     int dstx, int height, int width);
+void fbcon_sis_revc(struct display *p, int srcy, int srcx);
+void fbcon_sis_clear8(struct vc_data *conp, struct display *p, int srcy,
+                      int srcx, int height, int width);
+void fbcon_sis_clear16(struct vc_data *conp, struct display *p, int srcy,
+                       int srcx, int height, int width);
+void fbcon_sis_clear32(struct vc_data *conp, struct display *p, int srcy,
+                       int srcx, int height, int width);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+extern int sisfb_accel;
+void fbcon_sis_fillrect(struct fb_info *info, struct fb_fillrect *rect);
+void fbcon_sis_copyarea(struct fb_info *info, struct fb_copyarea *area);
+extern void cfb_fillrect(struct fb_info *info, struct fb_fillrect *rect);
+extern void cfb_copyarea(struct fb_info *info, struct fb_copyarea *area);
+#endif
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/sis/sis.h linux.20pre10-ac2/drivers/video/sis/sis.h
--- linux.20pre10/drivers/video/sis/sis.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/sis/sis.h	2002-10-11 00:17:32.000000000 +0100
@@ -0,0 +1,10 @@
+#ifndef _SIS_H
+#define _SIS_H
+
+#if 1
+#define TWDEBUG(x)
+#else
+#define TWDEBUG(x) printk(KERN_INFO x "\n");
+#endif
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/sis/sis_main.c linux.20pre10-ac2/drivers/video/sis/sis_main.c
--- linux.20pre10/drivers/video/sis/sis_main.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/sis/sis_main.c	2002-10-11 00:17:32.000000000 +0100
@@ -8,11 +8,16 @@
  * Authors:   	SiS (www.sis.com.tw)
  *		(Various others)
  *		Thomas Winischhofer <thomas@winischhofer.net>:
- *			- many fixes and enhancements for 630 & 310 series,
- *			- extended bridge handling, TV output for Chrontel
+ *			- many fixes and enhancements for all chipset series,
+ *			- extended bridge handling, TV output for Chrontel 7005
+ *                      - 650/LVDS support (for LCD panels up to 1400x1050)
+ *                      - 650/Chrontel 7019 support
+ *                      - 301B/301LV(x)/302B/302LV(x) LCD and TV support
  *			- memory queue handling enhancements,
- *			- everything marked with "TW"
- *			(see http://www.winischhofer.net/linuxsis630.shtml
+ *                      - 2D acceleration and y-panning,
+ *                      - portation to 2.5 API (yet incomplete)
+ *			- everything marked with "TW" and more
+ *			(see http://www.winischhofer.net/
  *			for more information and updates)
  */
 
@@ -36,6 +41,11 @@
 #include <linux/capability.h>
 #include <linux/fs.h>
 #include <linux/agp_backend.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,33)
+#include <linux/spinlock.h>
+#endif
+
+#include "osdef.h"
 
 #include <linux/types.h>
 #include <linux/sisfb.h>
@@ -49,68 +59,52 @@
 #include <video/fbcon-cfb24.h>
 #include <video/fbcon-cfb32.h>
 
-#include "osdef.h"
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+#include "../fbcon-accel.h"
+#endif
+
 #include "vgatypes.h"
 #include "sis_main.h"
+#include "sis.h"
 //#ifdef LINUXBIOS
 //#include "bios.h"
 //#endif
 
 /* -------------------- Macro definitions ---------------------------- */
-// #define SISFBDEBUG
-#undef SISFBDEBUG /* TW */
+#undef SISFBDEBUG /* TW: no debugging */
+
 #ifdef SISFBDEBUG
 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
 #else
 #define DPRINTK(fmt, args...)
 #endif
 
-#define vgawb(reg,data) \
-           (outb(data, ivideo.vga_base+reg))
-#define vgaww(reg,data) \
-           (outw(data, ivideo.vga_base+reg))
-#define vgawl(reg,data) \
-           (outl(data, ivideo.vga_base+reg))
-#define vgarb(reg)      \
-           (inb(ivideo.vga_base+reg))
-
-/* --------------- Hardware Access Routines -------------------------- */
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+#ifdef SISFBACCEL
+#ifdef FBCON_HAS_CFB8
+extern struct display_switch fbcon_sis8;
+#endif
+#ifdef FBCON_HAS_CFB16
+extern struct display_switch fbcon_sis16;
+#endif
+#ifdef FBCON_HAS_CFB32
+extern struct display_switch fbcon_sis32;
+#endif
+#endif
+#endif
 
-void sisfb_set_reg1(u16 port, u16 index, u16 data)
-{
-	outb((u8) (index & 0xff), port);
-	port++;
-	outb((u8) (data & 0xff), port);
-}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+/* TEMP */
+void my_cfb_imageblit(struct fb_info *info, struct fb_image *image);
+#endif
 
-void sisfb_set_reg3(u16 port, u16 data)
-{
-	outb((u8) (data & 0xff), port);
-}
+/* --------------- Hardware Access Routines -------------------------- */
 
 void sisfb_set_reg4(u16 port, unsigned long data)
 {
 	outl((u32) (data & 0xffffffff), port);
 }
 
-u8 sisfb_get_reg1(u16 port, u16 index)
-{
-	u8 data;
-
-	outb((u8) (index & 0xff), port);
-	port += 1;
-	data = inb(port);
-	return (data);
-}
-
-u8 sisfb_get_reg2(u16 port)
-{
-	u8 data;
-
-	data = inb(port);
-	return (data);
-}
-
 u32 sisfb_get_reg3(u16 port)
 {
 	u32 data;
@@ -119,25 +113,7 @@
 	return (data);
 }
 
-// Eden Chen
-//void sisfb_clear_DAC(u16 port)
-//{
-//	int i,j;
-//
-//	vgawb(DAC_ADR, 0x00);
-//	for(i=0; i<256; i++)
-//		for(j=0; j<3; j++)
-//			vgawb(DAC_DATA, 0);
-//}
-
-//void sisfb_clear_buffer(PHW_DEVICE_EXTENSION psishw_ext)
-//{
-//	memset((char *) ivideo.video_vbase, 0,
-//		video_linelength * ivideo.video_height);
-//}
-// ~Eden Chen
-
-/* --------------- Interface to BIOS code ---------------------------- */
+/* -------------------- Interface to BIOS code -------------------- */
 
 BOOLEAN
 sisfb_query_VGA_config_space(PSIS_HW_DEVICE_INFO psishw_ext,
@@ -178,7 +154,7 @@
 	return TRUE;
 }
 
-BOOLEAN sisfb_query_north_bridge_space(PSIS_HW_DEVICE_INFO psishw_ext, 
+BOOLEAN sisfb_query_north_bridge_space(PSIS_HW_DEVICE_INFO psishw_ext,
 	unsigned long offset, unsigned long set, unsigned long *value)
 {
 	static struct pci_dev *pdev = NULL;
@@ -233,10 +209,13 @@
 	return TRUE;
 }
 
-/* -------------------- Export functions ----------------------------- */
+/* -------------------- Exported functions ----------------------------- */
 
-static void sis_get_glyph(SIS_GLYINFO *gly)
+static void sis_get_glyph(struct fb_info *info, SIS_GLYINFO *gly)
 {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#define currcon info->currcon
+#endif
 	struct display *p = &fb_display[currcon];
 	u16 c;
 	u8 *cdat;
@@ -244,7 +223,7 @@
 	u8 *gbuf = gly->gmask;
 	int size;
 
-
+	TWDEBUG("Inside get_glyph");
 	gly->fontheight = fontheight(p);
 	gly->fontwidth = fontwidth(p);
 	widthb = (fontwidth(p) + 7) / 8;
@@ -258,10 +237,15 @@
 	size = fontheight(p) * widthb;
 	memcpy(gbuf, cdat, size);
 	gly->ngmask = size;
+	TWDEBUG("End of get_glyph");
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#undef currcon 
+#endif
 }
 
 void sis_dispinfo(struct ap_data *rec)
 {
+        TWDEBUG("Inside dispinfo");
 	rec->minfo.bpp    = ivideo.video_bpp;
 	rec->minfo.xres   = ivideo.video_width;
 	rec->minfo.yres   = ivideo.video_height;
@@ -278,125 +262,175 @@
 	rec->TV_type      = ivideo.TV_type; 
 	rec->TV_plug      = ivideo.TV_plug; 
 	rec->chip         = ivideo.chip;
+	TWDEBUG("End of dispinfo");
 }
 
 /* ------------------ Internal Routines ------------------------------ */
 
 static void sisfb_search_mode(const char *name)
 {
-	int i = 0;
+	int i = 0, j = 0;
 
-	if (name == NULL)
+	if(name == NULL)
 		return;
 
-	while (sisbios_mode[i].mode_no != 0) {
+	while(sisbios_mode[i].mode_no != 0) {
 		if (!strcmp(name, sisbios_mode[i].name)) {
 			sisfb_mode_idx = i;
+			j = 1;
 			break;
 		}
 		i++;
 	}
-	if (sisfb_mode_idx < 0)
-		printk(KERN_INFO "sisfb: Invalid mode '%s'\n", name);
+	if(!j) printk(KERN_INFO "sisfb: Invalid mode '%s'\n", name);
 }
 
-static void sisfb_validate_mode(void)
+static void sisfb_search_vesamode(unsigned int vesamode)
 {
-	switch (ivideo.disp_state & DISPTYPE_DISP2) {
-	case DISPTYPE_LCD:
-	    switch (sishw_ext.ulCRT2LCDType) {
-		case LCD_1024x768:
-			if (sisbios_mode[sisfb_mode_idx].xres > 1024)
-				sisfb_mode_idx = -1;
-			break;
-		case LCD_1280x1024:
-		case LCD_1280x960:
-			if (sisbios_mode[sisfb_mode_idx].xres > 1280)
-				sisfb_mode_idx = -1;
-			break;
-		case LCD_2048x1536:
-			if (sisbios_mode[sisfb_mode_idx].xres > 2048)
-				sisfb_mode_idx = -1;
-			break;
-		case LCD_1920x1440:
-			if (sisbios_mode[sisfb_mode_idx].xres > 1920)
-				sisfb_mode_idx = -1;
-			break;
-		case LCD_1600x1200:
-			if (sisbios_mode[sisfb_mode_idx].xres > 1600)
-				sisfb_mode_idx = -1;
-			break;
-		case LCD_800x600:
-			if (sisbios_mode[sisfb_mode_idx].xres > 800)
-				sisfb_mode_idx = -1;
-			break;
-		case LCD_640x480:
-			if (sisbios_mode[sisfb_mode_idx].xres > 640)
-				sisfb_mode_idx = -1;
-			break;
-		case LCD_320x480:	/* TW: FSTN */
-			if (sisbios_mode[sisfb_mode_idx].xres > 320)
-				sisfb_mode_idx = -1;
+	int i = 0, j = 0;
+
+	if(vesamode == 0) {
+		sisfb_mode_idx = MODE_INDEX_NONE;
+		return;
+	}
+
+	vesamode &= 0x1dff;  /* Clean VESA mode number from other flags */
+
+	while(sisbios_mode[i].mode_no != 0) {
+		if( (sisbios_mode[i].vesa_mode_no_1 == vesamode) ||
+		    (sisbios_mode[i].vesa_mode_no_2 == vesamode) ) {
+			sisfb_mode_idx = i;
+			j = 1;
 			break;
-		default:
-			sisfb_mode_idx = -1;
 		}
-		if (sisbios_mode[sisfb_mode_idx].xres == 720)
-			sisfb_mode_idx = -1;
+		i++;
+	}
+	if(!j) printk(KERN_INFO "sisfb: Invalid VESA mode 0x%x'\n", vesamode);
+}
+
+static int sisfb_validate_mode(int myindex)
+{
+   u16 xres, yres;
+
+#ifdef CONFIG_FB_SIS_300
+   if(sisvga_engine == SIS_300_VGA) {
+       if(!(sisbios_mode[sisfb_mode_idx].chipset & MD_SIS300)) {
+           return(-1);
+       }
+   }
+#endif
+#ifdef CONFIG_FB_SIS_315
+   if(sisvga_engine == SIS_315_VGA) {
+       if(!(sisbios_mode[myindex].chipset & MD_SIS315)) {
+	   return(-1);
+       }
+   }
+#endif
+
+   switch (ivideo.disp_state & DISPTYPE_DISP2) {
+     case DISPTYPE_LCD:
+	switch (sishw_ext.ulCRT2LCDType) {
+	case LCD_1024x768:
+	 	xres = 1024; yres =  768;  break;
+	case LCD_1280x1024:
+		xres = 1280; yres = 1024;  break;
+	case LCD_1280x960:
+	        xres = 1280; yres =  960;  break;
+	case LCD_2048x1536:
+		xres = 2048; yres = 1536;  break;
+	case LCD_1920x1440:
+		xres = 1920; yres = 1440;  break;
+	case LCD_1600x1200:
+		xres = 1600; yres = 1200;  break;
+	case LCD_800x600:
+		xres =  800; yres =  600;  break;
+	case LCD_640x480:
+		xres =  640; yres =  480;  break;
+	case LCD_320x480:				/* TW: FSTN */
+		xres =  320; yres =  480;  break;
+        case LCD_1024x600:
+		xres = 1024; yres =  600;  break;
+	case LCD_1152x864:
+		xres = 1152; yres =  864;  break;
+	case LCD_1152x768:
+		xres = 1152; yres =  768;  break;
+	case LCD_1280x768:
+		xres = 1280; yres =  768;  break;
+	case LCD_1400x1050:
+		xres = 1400; yres = 1050;  break;
+	default:
+	        xres =    0; yres =    0;  break;
+	}
+	if(sisbios_mode[myindex].xres > xres) {
+	        return(-1);
+	}
+        if(sisbios_mode[myindex].yres > yres) {
+	        return(-1);
+	}
+	if (sisbios_mode[myindex].xres == 720) {
+		return(-1);
+	}
+	break;
+     case DISPTYPE_TV:
+	switch (sisbios_mode[myindex].xres) {
+	case 512:
+	case 640:
+	case 800:
 		break;
-	case DISPTYPE_TV:
-	    switch (sisbios_mode[sisfb_mode_idx].xres) {
-		case 800:
-		case 640:
-			break;
-		case 720:
-			if (ivideo.TV_type == TVMODE_NTSC) {
-				if (sisbios_mode[sisfb_mode_idx].yres != 480)
-					sisfb_mode_idx = -1;
-			} else if (ivideo.TV_type == TVMODE_PAL) {
-				if (sisbios_mode[sisfb_mode_idx].yres != 576)
-					sisfb_mode_idx = -1;
-			}
-			/* TW: LVDS/CHRONTEL only supports 640 and 800 */
-			if (ivideo.hasVB == HASVB_LVDS_CHRONTEL ||
-						ivideo.hasVB == HASVB_CHRONTEL)
-					sisfb_mode_idx = -1;
-			break;
-		case 1024:
-			if (ivideo.TV_type == TVMODE_NTSC) {
-				if(sisbios_mode[sisfb_mode_idx].bpp == 32)
-				       sisfb_mode_idx = -1; /* TW; was -= 1 */
-				       /* TW: Should this mean a switch-back to
-				        *     16bpp or simply 'illegal mode'?
-					*/
-			}
-			/* TW: LVDS/CHRONTEL only supports 640 and 800 */
-			if (ivideo.hasVB == HASVB_LVDS_CHRONTEL ||
-						ivideo.hasVB == HASVB_CHRONTEL)
-					sisfb_mode_idx = -1;
-			break;
-		default:
-			sisfb_mode_idx = -1;
+	case 720:
+		if (ivideo.TV_type == TVMODE_NTSC) {
+			if (sisbios_mode[myindex].yres != 480) {
+				return(-1);
+			}
+		} else if (ivideo.TV_type == TVMODE_PAL) {
+			if (sisbios_mode[myindex].yres != 576) {
+				return(-1);
+			}
+		}
+		/* TW: LVDS/CHRONTEL does not support 720 */
+		if (ivideo.hasVB == HASVB_LVDS_CHRONTEL ||
+					ivideo.hasVB == HASVB_CHRONTEL) {
+				return(-1);
+		}
+		break;
+	case 1024:
+		if (ivideo.TV_type == TVMODE_NTSC) {
+			if(sisbios_mode[myindex].bpp == 32) {
+			       return(-1);
+			}
+		}
+		/* TW: LVDS/CHRONTEL only supports < 800 (1024 on 650/Ch7019)*/
+		if (ivideo.hasVB == HASVB_LVDS_CHRONTEL ||
+					ivideo.hasVB == HASVB_CHRONTEL) {
+		    if(ivideo.chip < SIS_315H) {
+				return(-1);
+		    }
 		}
 		break;
+	default:
+		return(-1);
 	}
+	break;
+     }
+     return(myindex);
 }
 
 static void sisfb_search_crt2type(const char *name)
 {
 	int i = 0;
 
-	if (name == NULL)
+	if(name == NULL)
 		return;
 
-	while (sis_crt2type[i].type_no != -1) {
+	while(sis_crt2type[i].type_no != -1) {
 		if (!strcmp(name, sis_crt2type[i].name)) {
 			sisfb_crt2type = sis_crt2type[i].type_no;
+			sisfb_tvplug = sis_crt2type[i].tvplug_no;
 			break;
 		}
 		i++;
 	}
-	if (sisfb_crt2type < 0)
+	if(sisfb_crt2type < 0)
 		printk(KERN_INFO "sisfb: Invalid CRT2 type: %s\n", name);
 }
 
@@ -404,7 +438,7 @@
 {
 	int i = 0;
 
-	if (name == NULL)
+	if(name == NULL)
 		return;
 
 	while (sis_queuemode[i].type_no != -1) {
@@ -459,50 +493,51 @@
 	}
 }
 
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
 static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green, unsigned *blue,
 			 unsigned *transp, struct fb_info *fb_info)
 {
-	if (regno >= video_cmap_len)
+	if (regno >= ivideo.video_cmap_len)
 		return 1;
 
-	*red = palette[regno].red;
-	*green = palette[regno].green;
-	*blue = palette[regno].blue;
+	*red = sis_palette[regno].red;
+	*green = sis_palette[regno].green;
+	*blue = sis_palette[regno].blue;
 	*transp = 0;
 	return 0;
 }
+#endif
 
-static int sis_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
-			 unsigned transp, struct fb_info *fb_info)
+static int sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
+                           unsigned transp, struct fb_info *fb_info)
 {
-	if (regno >= video_cmap_len)
+	if (regno >= ivideo.video_cmap_len)
 		return 1;
 
-	palette[regno].red = red;
-	palette[regno].green = green;
-	palette[regno].blue = blue;
+	sis_palette[regno].red = red;
+	sis_palette[regno].green = green;
+	sis_palette[regno].blue = blue;
 
 	switch (ivideo.video_bpp) {
 #ifdef FBCON_HAS_CFB8
 	case 8:
-		vgawb(DAC_ADR, regno);
-		vgawb(DAC_DATA, red >> 10);
-		vgawb(DAC_DATA, green >> 10);
-		vgawb(DAC_DATA, blue >> 10);
+	        outSISREG(SISDACA, regno);
+		outSISREG(SISDACD, (red >> 10));
+		outSISREG(SISDACD, (green >> 10));
+		outSISREG(SISDACD, (blue >> 10));
 		if (ivideo.disp_state & DISPTYPE_DISP2) {
-		 	vgawb(DAC2_ADR,  regno);
-			vgawb(DAC2_DATA, red >> 8);
-			vgawb(DAC2_DATA, green >> 8);
-			vgawb(DAC2_DATA, blue >> 8);
+		        outSISREG(SISDAC2A, regno);
+			outSISREG(SISDAC2D, (red >> 8));
+			outSISREG(SISDAC2D, (green >> 8));
+			outSISREG(SISDAC2D, (blue >> 8));
 		}
 		break;
 #endif
 #ifdef FBCON_HAS_CFB16
 	case 15:
 	case 16:
-		fbcon_cmap.cfb16[regno] =
-		    ((red & 0xf800)) |
-		    ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
+		sis_fbcon_cmap.cfb16[regno] =
+		    ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
 		break;
 #endif
 #ifdef FBCON_HAS_CFB24
@@ -510,8 +545,7 @@
 		red >>= 8;
 		green >>= 8;
 		blue >>= 8;
-		fbcon_cmap.cfb24[regno] =
-		    (red << 16) | (green << 8) | (blue);
+		sis_fbcon_cmap.cfb24[regno] = (red << 16) | (green << 8) | (blue);
 		break;
 #endif
 #ifdef FBCON_HAS_CFB32
@@ -519,8 +553,7 @@
 		red >>= 8;
 		green >>= 8;
 		blue >>= 8;
-		fbcon_cmap.cfb32[regno] =
-		    (red << 16) | (green << 8) | (blue);
+		sis_fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | (blue);
 		break;
 #endif
 	}
@@ -540,22 +573,24 @@
 	int found_mode = 0;
 	int old_mode;
 
-	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
+	TWDEBUG("Inside do_set_var");
+
+	if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
 		vtotal = var->upper_margin + var->yres + var->lower_margin +
 		         var->vsync_len;   /* TW */
 		vtotal <<= 1;
-	} else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
 		vtotal = var->upper_margin + var->yres + var->lower_margin +
 		         var->vsync_len;   /* TW */
 		vtotal <<= 2;
-	} else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
 		vtotal = var->upper_margin + (var->yres/2) + var->lower_margin +
 		         var->vsync_len;   /* TW */
 		/* var->yres <<= 1; */ /* TW */
 	} else 	vtotal = var->upper_margin + var->yres + var->lower_margin +
 		         var->vsync_len;
 
-	if (!(htotal) || !(vtotal)) {
+	if(!(htotal) || !(vtotal)) {
 		DPRINTK("sisfb: Invalid 'var' information\n");
 		return -EINVAL;
 	}
@@ -564,17 +599,20 @@
 	hrate = drate / htotal;
 	ivideo.refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
 
-	DPRINTK("sisfb: Change mode to %dx%dx%d-%dMHz\n",
+	/* TW: Calculation wrong for 1024x600 - force it to 60Hz */
+	if((var->xres == 1024) && (var->yres == 600)) ivideo.refresh_rate = 60;
+
+	printk("sisfb: Change mode to %dx%dx%d-%dHz\n",
 		var->xres,var->yres,var->bits_per_pixel,ivideo.refresh_rate);
 
 	old_mode = sisfb_mode_idx;
 	sisfb_mode_idx = 0;
 
-	while ((sisbios_mode[sisfb_mode_idx].mode_no != 0)
-	       && (sisbios_mode[sisfb_mode_idx].xres <= var->xres)) {
-		if ((sisbios_mode[sisfb_mode_idx].xres == var->xres)
-		    && (sisbios_mode[sisfb_mode_idx].yres == var->yres)
-		    && (sisbios_mode[sisfb_mode_idx].bpp == var->bits_per_pixel)) {
+	while( (sisbios_mode[sisfb_mode_idx].mode_no != 0) &&
+	       (sisbios_mode[sisfb_mode_idx].xres <= var->xres) ) {
+		if( (sisbios_mode[sisfb_mode_idx].xres == var->xres) &&
+		    (sisbios_mode[sisfb_mode_idx].yres == var->yres) &&
+		    (sisbios_mode[sisfb_mode_idx].bpp == var->bits_per_pixel)) {
 			sisfb_mode_no = sisbios_mode[sisfb_mode_idx].mode_no;
 			found_mode = 1;
 			break;
@@ -582,66 +620,97 @@
 		sisfb_mode_idx++;
 	}
 
-	if (found_mode)
-		sisfb_validate_mode();
+	if(found_mode)
+		sisfb_mode_idx = sisfb_validate_mode(sisfb_mode_idx);
 	else
 		sisfb_mode_idx = -1;
 
-       	if (sisfb_mode_idx < 0) {
-		DPRINTK("sisfb: sisfb does not support mode %dx%d-%d\n", var->xres,
+       	if(sisfb_mode_idx < 0) {
+		printk("sisfb: Mode %dx%dx%d not supported\n", var->xres,
 		       var->yres, var->bits_per_pixel);
 		sisfb_mode_idx = old_mode;
 		return -EINVAL;
 	}
 
-	if (sisfb_search_refresh_rate(ivideo.refresh_rate) == 0) {
+	if(sisfb_search_refresh_rate(ivideo.refresh_rate) == 0) {
 		sisfb_rate_idx = sisbios_mode[sisfb_mode_idx].rate_idx;
 		ivideo.refresh_rate = 60;
 	}
 
-	if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
-
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+	if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
+#else
+	if(isactive) {
+#endif
 		sisfb_pre_setmode();
 
-		if (SiSSetMode(&sishw_ext, sisfb_mode_no) == 0) {
-			DPRINTK("sisfb: Setting mode[0x%x]: failed\n", sisfb_mode_no);
-			return -1;
+		if(SiSSetMode(&SiS_Pr, &sishw_ext, sisfb_mode_no) == 0) {
+			printk("sisfb: Setting mode[0x%x] failed\n", sisfb_mode_no);
+			return -EINVAL;
 		}
 
-		vgawb(SEQ_ADR, IND_SIS_PASSWORD);
-		vgawb(SEQ_DATA, SIS_PASSWORD);
+		outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
 
 		sisfb_post_setmode();
 
-		DPRINTK("sisfb: Set new mode: %dx%dx%d-%d \n", sisbios_mode[sisfb_mode_idx].xres,
-			sisbios_mode[sisfb_mode_idx].yres, sisbios_mode[sisfb_mode_idx].bpp,
+		DPRINTK("sisfb: Set new mode: %dx%dx%d-%d \n",
+			sisbios_mode[sisfb_mode_idx].xres,
+			sisbios_mode[sisfb_mode_idx].yres,
+			sisbios_mode[sisfb_mode_idx].bpp,
 			ivideo.refresh_rate);
 
 		ivideo.video_bpp = sisbios_mode[sisfb_mode_idx].bpp;
 		ivideo.video_vwidth = ivideo.video_width = sisbios_mode[sisfb_mode_idx].xres;
 		ivideo.video_vheight = ivideo.video_height = sisbios_mode[sisfb_mode_idx].yres;
 		ivideo.org_x = ivideo.org_y = 0;
-		video_linelength =
-		    ivideo.video_width * (ivideo.video_bpp >> 3);
+		ivideo.video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
+		switch(ivideo.video_bpp) {
+        	case 8:
+            		ivideo.DstColor = 0x0000;
+	    		ivideo.SiS310_AccelDepth = 0x00000000;
+			ivideo.video_cmap_len = 256;
+            		break;
+        	case 16:
+            		ivideo.DstColor = 0x8000;
+            		ivideo.SiS310_AccelDepth = 0x00010000;
+			ivideo.video_cmap_len = 16;
+            		break;
+        	case 32:
+            		ivideo.DstColor = 0xC000;
+	    		ivideo.SiS310_AccelDepth = 0x00020000;
+			ivideo.video_cmap_len = 16;
+            		break;
+		default:
+			ivideo.video_cmap_len = 16;
+		        printk(KERN_ERR "sisfb: Unsupported accel depth %d", ivideo.video_bpp);
+			break;
+    		}
 	}
+	TWDEBUG("End of do_set_var");
 	return 0;
 }
 
-static void sisfb_set_disp(int con, struct fb_var_screeninfo *var)
+/* ------ Internal functions only for 2.4 series ------- */
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+static void sisfb_set_disp(int con, struct fb_var_screeninfo *var,
+                           struct fb_info *info)
 {
 	struct fb_fix_screeninfo fix;
+	long   flags;
 	struct display *display;
 	struct display_switch *sw;
-	u32 flags;
 
-	if (con >= 0)
+	if(con >= 0)
 		display = &fb_display[con];
 	else
-		display = &disp;	
+		display = &sis_disp;
 
 	sisfb_get_fix(&fix, con, 0);
 
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,23)
 	display->screen_base = ivideo.video_vbase;
+#endif
 	display->visual = fix.visual;
 	display->type = fix.type;
 	display->type_aux = fix.type_aux;
@@ -654,29 +723,42 @@
 	display->var = *var;
 
 	save_flags(flags);
+
 	switch (ivideo.video_bpp) {
 #ifdef FBCON_HAS_CFB8
 	   case 8:
+#ifdef SISFBACCEL
+		sw = sisfb_accel ? &fbcon_sis8 : &fbcon_cfb8;
+#else
 		sw = &fbcon_cfb8;
+#endif
 		break;
 #endif
 #ifdef FBCON_HAS_CFB16
 	   case 15:
 	   case 16:
+#ifdef SISFBACCEL
+		sw = sisfb_accel ? &fbcon_sis16 : &fbcon_cfb16;
+#else
 		sw = &fbcon_cfb16;
-		display->dispsw_data = fbcon_cmap.cfb16;
+#endif
+		display->dispsw_data = sis_fbcon_cmap.cfb16;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB24
 	   case 24:
 		sw = &fbcon_cfb24;
-		display->dispsw_data = fbcon_cmap.cfb24;
+		display->dispsw_data = sis_fbcon_cmap.cfb24;
 		break;
 #endif
 #ifdef FBCON_HAS_CFB32
 	   case 32:
+#ifdef SISFBACCEL
+		sw = sisfb_accel ? &fbcon_sis32 : &fbcon_cfb32;
+#else
 		sw = &fbcon_cfb32;
-		display->dispsw_data = fbcon_cmap.cfb32;
+#endif
+		display->dispsw_data = sis_fbcon_cmap.cfb32;
 		break;
 #endif
 	   default:
@@ -687,138 +769,987 @@
 	display->dispsw = &sisfb_sw;
 	restore_flags(flags);
 
+#ifdef SISFB_PAN
+        if(sisfb_ypan) {
+  	    /* display->scrollmode = SCROLL_YPAN; - not defined */
+	} else {
+	    display->scrollmode = SCROLL_YREDRAW;
+	    sisfb_sw.bmove = fbcon_redraw_bmove;
+	}
+#else
 	display->scrollmode = SCROLL_YREDRAW;
 	sisfb_sw.bmove = fbcon_redraw_bmove;
+#endif
 }
 
 static void sisfb_do_install_cmap(int con, struct fb_info *info)
 {
-	if (con != currcon)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+	if (con != info->currcon)
 		return;
 
-	if (fb_display[con].cmap.len)
-		fb_set_cmap(&fb_display[con].cmap, 1, sis_setcolreg, info);
-	else
-		fb_set_cmap(fb_default_cmap(video_cmap_len), 1,
-			    sis_setcolreg, info);
+        if (fb_display[con].cmap.len)
+                fb_set_cmap(&fb_display[con].cmap, 1, info);
+        else
+		fb_set_cmap(fb_default_cmap(ivideo.video_cmap_len), 1, info);
+#else
+        if (con != currcon)
+		return;
+
+        if (fb_display[con].cmap.len)
+		fb_set_cmap(&fb_display[con].cmap, 1, sisfb_setcolreg, info);
+        else
+		fb_set_cmap(fb_default_cmap(ivideo.video_cmap_len), 1,
+			    sisfb_setcolreg, info);
+#endif
 }
+#endif
 
+/* ------ functions for all series ------ */
 
-/* --------------- Chip-dependent Routines --------------------------- */
+#ifdef SISFB_PAN
+static void sisfb_pan_var(struct fb_var_screeninfo *var)
+{
+	unsigned int base;
 
-#ifdef CONFIG_FB_SIS_300 /* for SiS 300/630/540/730 */
-static int sisfb_get_dram_size_300(void)
+	TWDEBUG("Inside pan_var");
+
+        base = var->yoffset * var->xres_virtual + var->xoffset;
+
+        /* calculate base bpp dep. */
+        switch(var->bits_per_pixel) {
+        case 16:
+        	base >>= 1;
+        	break;
+	case 32:
+            	break;
+	case 8:
+        default:
+        	base >>= 2;
+            	break;
+        }
+	
+	outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
+
+        outSISIDXREG(SISCR, 0x0D, base & 0xFF);
+	outSISIDXREG(SISCR, 0x0C, (base >> 8) & 0xFF);
+	outSISIDXREG(SISSR, 0x0D, (base >> 16) & 0xFF);
+	if(sisvga_engine == SIS_315_VGA) {
+		setSISIDXREG(SISSR, 0x37, 0xFE, (base >> 24) & 0x01);
+	}
+        if(ivideo.disp_state & DISPTYPE_DISP2) {
+		orSISIDXREG(SISPART1, sisfb_CRT2_write_enable, 0x01);
+        	outSISIDXREG(SISPART1, 0x06, (base & 0xFF));
+        	outSISIDXREG(SISPART1, 0x05, ((base >> 8) & 0xFF));
+        	outSISIDXREG(SISPART1, 0x04, ((base >> 16) & 0xFF));
+		if(sisvga_engine == SIS_315_VGA) {
+			setSISIDXREG(SISPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
+		}
+        }
+	TWDEBUG("End of pan_var");
+}
+#endif
+
+static void sisfb_crtc_to_var(struct fb_var_screeninfo *var)
 {
-	struct pci_dev *pdev = NULL;
-	int pdev_valid = 0;
-	u8  pci_data, reg;
-	u16 nbridge_id;
+	u16 VRE, VBE, VRS, VBS, VDE, VT;
+	u16 HRE, HBE, HRS, HBS, HDE, HT;
+	u8  sr_data, cr_data, cr_data2, cr_data3, mr_data;
+	int A, B, C, D, E, F, temp;
+	double hrate, drate;
 
-	switch (ivideo.chip) {
-	   case SIS_540:
-		nbridge_id = PCI_DEVICE_ID_SI_540;
-		break;
-	   case SIS_630:
-		nbridge_id = PCI_DEVICE_ID_SI_630;
+	TWDEBUG("Inside crtc_to_var");
+	inSISIDXREG(SISSR, IND_SIS_COLOR_MODE, sr_data);
+
+	if (sr_data & SIS_INTERLACED_MODE)
+		var->vmode = FB_VMODE_INTERLACED;
+	else
+		var->vmode = FB_VMODE_NONINTERLACED;
+
+	switch ((sr_data & 0x1C) >> 2) {
+	   case SIS_8BPP_COLOR_MODE:
+		var->bits_per_pixel = 8;
 		break;
-	   case SIS_730:
-		nbridge_id = PCI_DEVICE_ID_SI_730;
+	   case SIS_16BPP_COLOR_MODE:
+		var->bits_per_pixel = 16;
 		break;
-	   default:
-		nbridge_id = 0;
+	   case SIS_32BPP_COLOR_MODE:
+		var->bits_per_pixel = 32;
 		break;
 	}
 
-	if (nbridge_id == 0) {  /* 300 */
-		vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
-		ivideo.video_size =
-		        ((unsigned int) ((vgarb(SEQ_DATA) & SIS_DRAM_SIZE_MASK) + 1) << 20);
-	} else {		/* 540, 630, 730 */
-		pci_for_each_dev(pdev) {
-			if ((pdev->vendor == PCI_VENDOR_ID_SI) 
-				&& (pdev->device == nbridge_id)) {
-				pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data);
-				pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
-				ivideo.video_size = (unsigned int)(1 << (pci_data+21));
-				pdev_valid = 1;
-	
-				reg = SIS_DATA_BUS_64 << 6;
-				vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
-				switch (pci_data) {
-				   case BRI_DRAM_SIZE_2MB:
-					reg |= SIS_DRAM_SIZE_2MB;
-					break;
-				   case BRI_DRAM_SIZE_4MB:
-					reg |= SIS_DRAM_SIZE_4MB;
-					break;
-				   case BRI_DRAM_SIZE_8MB:
-					reg |= SIS_DRAM_SIZE_8MB;
-					break;
-				   case BRI_DRAM_SIZE_16MB:
-					reg |= SIS_DRAM_SIZE_16MB;
-					break;
-				   case BRI_DRAM_SIZE_32MB:
-					reg |= SIS_DRAM_SIZE_32MB;
-					break;
-				   case BRI_DRAM_SIZE_64MB:
-					reg |= SIS_DRAM_SIZE_64MB;
-					break;
-				}
-				vgawb(SEQ_DATA, reg);
-				break;
-			}  
-		}   
-	
-		if (!pdev_valid)
-			return -1;
+	switch (var->bits_per_pixel) {
+	   case 8:
+		var->red.length = 6;
+		var->green.length = 6;
+		var->blue.length = 6;
+		ivideo.video_cmap_len = 256;
+		break;
+	   case 16:
+		var->red.offset = 11;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 6;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		ivideo.video_cmap_len = 16;
+		break;
+	   case 24:
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		ivideo.video_cmap_len = 16;
+		break;
+	   case 32:
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		ivideo.video_cmap_len = 16;
+		break;
 	}
-	return 0;
-}
 
-static void sisfb_detect_VB_connect_300()
-{
-	u8 sr16, sr17, cr32, temp;
+	inSISIDXREG(SISSR, 0x0A, sr_data);
 
-	vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_17);
-	sr17 = vgarb(SEQ_DATA);
-	vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR32);
-	cr32 = vgarb(CRTC_DATA);
+        inSISIDXREG(SISCR, 0x06, cr_data);
 
-	ivideo.TV_plug = ivideo.TV_type = 0;
-	if ((sr17 & 0x0F) && (ivideo.chip != SIS_300)) {
-		if ((sr17 & 0x01) && !sisfb_crt1off)
-			sisfb_crt1off = 0;
-		else {
-			if (sr17 & 0x0E)
-				sisfb_crt1off = 1;
-			else
-				sisfb_crt1off = 0;
-		}
+        inSISIDXREG(SISCR, 0x07, cr_data2);
 
-		if (sisfb_crt2type != -1)
-			/* TW: override detected CRT2 type */
-			ivideo.disp_state = sisfb_crt2type;
-		else if (sr17 & 0x08 )
-			ivideo.disp_state = DISPTYPE_CRT2;
-		else if (sr17 & 0x02)
-			ivideo.disp_state = DISPTYPE_LCD;
-		else if (sr17 & 0x04)
-			ivideo.disp_state = DISPTYPE_TV;
-		else
-			ivideo.disp_state = 0;
+	VT = (cr_data & 0xFF) | ((u16) (cr_data2 & 0x01) << 8) |
+	     ((u16) (cr_data2 & 0x20) << 4) | ((u16) (sr_data & 0x01) << 10);
+	A = VT + 2;
 
-		if (sr17 & 0x20)
-			ivideo.TV_plug = TVPLUG_SVIDEO;
-		else if (sr17 & 0x10)
-			ivideo.TV_plug = TVPLUG_COMPOSITE;
+	inSISIDXREG(SISCR, 0x12, cr_data);
+
+	VDE = (cr_data & 0xff) | ((u16) (cr_data2 & 0x02) << 7) |
+	      ((u16) (cr_data2 & 0x40) << 3) | ((u16) (sr_data & 0x02) << 9);
+	E = VDE + 1;
+
+	inSISIDXREG(SISCR, 0x10, cr_data);
+
+	VRS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x04) << 6) |
+	      ((u16) (cr_data2 & 0x80) << 2) | ((u16) (sr_data & 0x08) << 7);
+	F = VRS + 1 - E;
+
+	inSISIDXREG(SISCR, 0x15, cr_data);
+
+	inSISIDXREG(SISCR, 0x09, cr_data3);
+
+	VBS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x08) << 5) |
+	      ((u16) (cr_data3 & 0x20) << 4) | ((u16) (sr_data & 0x04) << 8);
+
+	inSISIDXREG(SISCR, 0x16, cr_data);
+
+	VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4);
+	temp = VBE - ((E - 1) & 511);
+	B = (temp > 0) ? temp : (temp + 512);
+
+	inSISIDXREG(SISCR, 0x11, cr_data);
+
+	VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
+	temp = VRE - ((E + F - 1) & 31);
+	C = (temp > 0) ? temp : (temp + 32);
+
+	D = B - F - C;
+
+
+        var->yres = E;
+#ifndef SISFB_PAN
+	var->yres_virtual = E;
+#endif
+	/* TW: We have to report the physical dimension to the console! */
+	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+		var->yres <<= 1;
+#ifndef SISFB_PAN
+		var->yres_virtual <<= 1;
+#endif
+	}
+	/* TW end */
+	var->upper_margin = D;
+	var->lower_margin = F;
+	var->vsync_len = C;
+
+	inSISIDXREG(SISSR, 0x0b, sr_data);
+
+	inSISIDXREG(SISCR, 0x00, cr_data);
+
+	HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8);
+	A = HT + 5;
+
+	inSISIDXREG(SISCR, 0x01, cr_data);
+
+	HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6);
+	E = HDE + 1;
+
+	inSISIDXREG(SISCR, 0x04, cr_data);
+
+	HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2);
+	F = HRS - E - 3;
+
+	inSISIDXREG(SISCR, 0x02, cr_data);
+
+	HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4);
+
+	inSISIDXREG(SISSR, 0x0c, sr_data);
+
+	inSISIDXREG(SISCR, 0x03, cr_data);
+
+	inSISIDXREG(SISCR, 0x15, cr_data2);
+
+	HBE = (cr_data & 0x1f) | ((u16) (cr_data2 & 0x80) >> 2) |
+	      ((u16) (sr_data & 0x03) << 6);
+	HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
+
+	temp = HBE - ((E - 1) & 255);
+	B = (temp > 0) ? temp : (temp + 256);
+
+	temp = HRE - ((E + F + 3) & 63);
+	C = (temp > 0) ? temp : (temp + 64);
+
+	D = B - F - C;
+
+	var->xres = var->xres_virtual = E * 8;
+	var->left_margin = D * 8;
+	var->right_margin = F * 8;
+	var->hsync_len = C * 8;
+
+	var->activate = FB_ACTIVATE_NOW;
+
+	var->sync = 0;
+
+	mr_data = inSISREG(SISMISCR);
+#if 0
+	mr_data = vgarb(0x1C);
+#endif
+	if (mr_data & 0x80)
+		var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
+	else
+		var->sync |= FB_SYNC_VERT_HIGH_ACT;
+
+	if (mr_data & 0x40)
+		var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
+	else
+		var->sync |= FB_SYNC_HOR_HIGH_ACT;
+
+	VT += 2;
+	VT <<= 1;
+	HT = (HT + 5) * 8;
+
+	hrate = (double) ivideo.refresh_rate * (double) VT / 2;
+	drate = hrate * HT;
+	var->pixclock = (u32) (1E12 / drate);
+
+#ifdef SISFB_PAN
+	if(sisfb_ypan) {
+	    var->yres_virtual = ivideo.heapstart / (var->xres * (var->bits_per_pixel >> 3));
+	    if(var->yres_virtual <= var->yres) {
+	        var->yres_virtual = var->yres;
+	    }
+	} else
+#endif
+	   var->yres_virtual = var->yres;
+
+        TWDEBUG("end of crtc_to_var");
+}
+
+/* ------------------ Public Routines -------------------------------- */
+
+/* -------- functions only for for 2.4 series ------- */
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info)
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#define currcon info->currcon
+#endif
+	int err;
+	unsigned int cols, rows;
+
+	fb_display[con].var.activate = FB_ACTIVATE_NOW;
+        if(sisfb_do_set_var(var, con == currcon, info)) {
+		sisfb_crtc_to_var(var);
+		return -EINVAL;
+	}
+
+	sisfb_crtc_to_var(var);
+
+	sisfb_set_disp(con, var, info);
+
+	if(info->changevar)
+		(*info->changevar) (con);
+
+	if((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0)))
+		return err;
+
+	sisfb_do_install_cmap(con, info);
+
+	cols = sisbios_mode[sisfb_mode_idx].cols;
+	rows = sisbios_mode[sisfb_mode_idx].rows;
+	vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
+
+	return 0;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#undef currcon
+#endif
+}
+
+static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info)
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#define currcon info->currcon
+#endif
+        if (con == currcon)
+		return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
+
+	else if (fb_display[con].cmap.len)
+		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+	else
+		fb_copy_cmap(fb_default_cmap(ivideo.video_cmap_len), cmap, kspc ? 0 : 2);
+
+	return 0;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#undef currcon
+#endif
+}
+
+static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info)
+{
+	int err;
+
+	if (!fb_display[con].cmap.len) {
+		err = fb_alloc_cmap(&fb_display[con].cmap, ivideo.video_cmap_len, 0);
+		if (err)
+			return err;
+	}
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+	if (con == info->currcon)
+		return fb_set_cmap(cmap, kspc, info);
+#else
+        if (con == currcon)
+		return fb_set_cmap(cmap, kspc, sisfb_setcolreg, info);
+#endif
+	else
+		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
+	return 0;
+}
+#endif
+
+/* -------- functions only for 2.5 series ------- */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+static int sisfb_set_par(struct fb_info *info)
+{
+	int err;
+
+	TWDEBUG("inside set_par\n");
+        if((err = sisfb_do_set_var(&info->var, 1, info)))
+		return err;
+
+	sisfb_get_fix(&info->fix, info->currcon, info);
+
+	TWDEBUG("end of set_par");
+	return 0;
+}
+
+static int sisfb_check_var(struct fb_var_screeninfo *var,
+                            struct fb_info *info)
+{
+	unsigned int htotal =
+		var->left_margin + var->xres + var->right_margin +
+		var->hsync_len;
+	unsigned int vtotal = 0;
+	double drate = 0, hrate = 0;
+	int found_mode = 0;
+	int refresh_rate, search_idx;
+
+	TWDEBUG("Inside check_var");
+
+	if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
+		vtotal = var->upper_margin + var->yres + var->lower_margin +
+		         var->vsync_len;   /* TW */
+		vtotal <<= 1;
+	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+		vtotal = var->upper_margin + var->yres + var->lower_margin +
+		         var->vsync_len;   /* TW */
+		vtotal <<= 2;
+	} else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+		vtotal = var->upper_margin + (var->yres/2) + var->lower_margin +
+		         var->vsync_len;   /* TW */
+		/* var->yres <<= 1; */ /* TW */
+	} else 	vtotal = var->upper_margin + var->yres + var->lower_margin +
+		         var->vsync_len;
+
+	if(!(htotal) || !(vtotal)) {
+		SISFAIL("sisfb: no valid timing data");
+	}
+
+	drate = 1E12 / var->pixclock;
+	hrate = drate / htotal;
+	refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
+
+	/* TW: Calculation wrong for 1024x600 - force it to 60Hz */
+	if((var->xres == 1024) && (var->yres == 600)) refresh_rate = 60;
+
+	search_idx = 0;
+	while( (sisbios_mode[search_idx].mode_no != 0) &&
+	       (sisbios_mode[search_idx].xres <= var->xres) ) {
+		if( (sisbios_mode[search_idx].xres == var->xres) &&
+		    (sisbios_mode[search_idx].yres == var->yres) &&
+		    (sisbios_mode[search_idx].bpp == var->bits_per_pixel)) {
+			found_mode = 1;
+			break;
+		}
+		search_idx++;
+	}
+
+	/* TW: TODO: Check the refresh rate */
+
+	if(found_mode)
+		search_idx = sisfb_validate_mode(search_idx);
+	else
+		SISFAIL("sisfb: no valid mode");
+
+       	if(sisfb_mode_idx < 0) {
+		SISFAIL("sisfb: mode not supported");
+	}
+
+	/* TW: Horiz-panning not supported */
+	if(var->xres != var->xres_virtual)
+		var->xres_virtual = var->xres;
+
+	if(!sisfb_ypan) {
+		if(var->yres != var->yres_virtual)
+			var->yres_virtual = var->yres;
+	} else {
+	   /* TW: Now patch yres_virtual if we use panning */
+	   /* *** May I do this? *** */
+	   var->yres_virtual = ivideo.heapstart / (var->xres * (var->bits_per_pixel >> 3));
+	    if(var->yres_virtual <= var->yres) {
+	    	/* TW: Paranoia check */
+	        var->yres_virtual = var->yres;
+	    }
+	}
+	TWDEBUG("end of check_var");
+	return 0;
+}
+#endif
+
+/* -------- functions for all series ------- */
+
+static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			 struct fb_info *info)
+{
+	TWDEBUG("inside get_fix");
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+
+	strcpy(fix->id, sis_fb_info.modename);
+
+	fix->smem_start = ivideo.video_base;
+
+        /* TW */
+        if((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
+	    if (ivideo.video_size > 0x1000000) {
+	        fix->smem_len = 0xc00000;
+	    } else if (ivideo.video_size > 0x800000)
+		fix->smem_len = 0x800000;
+	    else
+		fix->smem_len = 0x400000;
+        } else
+		fix->smem_len = sisfb_mem * 1024;
+
+	fix->type        = video_type;
+	fix->type_aux    = 0;
+	if(ivideo.video_bpp == 8)
+		fix->visual = FB_VISUAL_PSEUDOCOLOR;
+	else
+		fix->visual = FB_VISUAL_TRUECOLOR;
+	fix->xpanstep    = 0;
+#ifdef SISFB_PAN
+        if(sisfb_ypan) 	 fix->ypanstep = 1;
+#endif
+	fix->ywrapstep   = 0;
+	fix->line_length = ivideo.video_linelength;
+	fix->mmio_start  = ivideo.mmio_base;
+	fix->mmio_len    = sisfb_mmio_size;
+	fix->accel       = FB_ACCEL_SIS_GLAMOUR;
+	fix->reserved[0] = ivideo.video_size & 0xFFFF;
+	fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF;
+	fix->reserved[2] = sisfb_caps;
+	TWDEBUG("end of get_fix");
+	return 0;
+}
+
+static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *info)
+{
+	TWDEBUG("inside get_var");
+	if(con == -1)
+		memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
+	else
+		*var = fb_display[con].var;
+
+	/* JennyLee 2001126: for FSTN */
+	if (var->xres == 320 && var->yres == 480)
+		var->yres = 240;
+	/* ~JennyLee */
+	TWDEBUG("end of get_var");
+	return 0;
+}
+
+#ifdef SISFB_PAN
+static int sisfb_pan_display(struct fb_var_screeninfo *var, int con,
+		struct fb_info* info)
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#define currcon info->currcon
+#endif
+	TWDEBUG("inside pan_display");
+	if (var->vmode & FB_VMODE_YWRAP) {
+		if (var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset)
+			return -EINVAL;
+	} else {
+		if (var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual ||
+		    var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)
+			return -EINVAL;
+	}
+
+        if (con == currcon)
+		sisfb_pan_var(var);
+
+	fb_display[con].var.xoffset = var->xoffset;
+	fb_display[con].var.yoffset = var->yoffset;
+	if (var->vmode & FB_VMODE_YWRAP)
+		fb_display[con].var.vmode |= FB_VMODE_YWRAP;
+	else
+		fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
+
+	TWDEBUG("end of pan_display");
+	return 0;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#undef currcon
+#endif
+}
+#endif
+
+static int sisfb_ioctl(struct inode *inode, struct file *file,
+		       unsigned int cmd, unsigned long arg, int con,
+		       struct fb_info *info)
+{
+	TWDEBUG("inside ioctl");
+	switch (cmd) {
+	   case FBIO_ALLOC:
+		if (!capable(CAP_SYS_RAWIO))
+			return -EPERM;
+		sis_malloc((struct sis_memreq *) arg);
+		break;
+	   case FBIO_FREE:
+		if (!capable(CAP_SYS_RAWIO))
+			return -EPERM;
+		sis_free(*(unsigned long *) arg);
+		break;
+	   case FBIOGET_GLYPH:
+                sis_get_glyph(info,(SIS_GLYINFO *) arg);
+		break;
+	   case FBIOGET_HWCINFO:
+		{
+			unsigned long *hwc_offset = (unsigned long *) arg;
+
+			if (sisfb_caps & HW_CURSOR_CAP)
+				*hwc_offset = sisfb_hwcursor_vbase -
+				    (unsigned long) ivideo.video_vbase;
+			else
+				*hwc_offset = 0;
+
+			break;
+		}
+	   case FBIOPUT_MODEINFO:
+		{
+			struct mode_info *x = (struct mode_info *)arg;
+
+			ivideo.video_bpp        = x->bpp;
+			ivideo.video_width      = x->xres;
+			ivideo.video_height     = x->yres;
+			ivideo.video_vwidth     = x->v_xres;
+			ivideo.video_vheight    = x->v_yres;
+			ivideo.org_x            = x->org_x;
+			ivideo.org_y            = x->org_y;
+			ivideo.refresh_rate     = x->vrate;
+			ivideo.video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
+			switch(ivideo.video_bpp) {
+        		case 8:
+            			ivideo.DstColor = 0x0000;
+	    			ivideo.SiS310_AccelDepth = 0x00000000;
+				ivideo.video_cmap_len = 256;
+            			break;
+        		case 16:
+            			ivideo.DstColor = 0x8000;
+            			ivideo.SiS310_AccelDepth = 0x00010000;
+				ivideo.video_cmap_len = 16;
+            			break;
+        		case 32:
+            			ivideo.DstColor = 0xC000;
+	    			ivideo.SiS310_AccelDepth = 0x00020000;
+				ivideo.video_cmap_len = 16;
+            			break;
+			default:
+				ivideo.video_cmap_len = 16;
+		       	 	printk(KERN_ERR "sisfb: Unsupported accel depth %d", ivideo.video_bpp);
+				break;
+    			}
+
+			break;
+		}
+	   case FBIOGET_DISPINFO:
+		sis_dispinfo((struct ap_data *)arg);
+		break;
+	   case SISFB_GET_INFO:  /* TW: New for communication with X driver */
+	        {
+			sisfb_info *x = (sisfb_info *)arg;
+
+			x->sisfb_id = SISFB_ID;
+			x->sisfb_version = VER_MAJOR;
+			x->sisfb_revision = VER_MINOR;
+			x->sisfb_patchlevel = VER_LEVEL;
+			x->chip_id = ivideo.chip_id;
+			x->memory = ivideo.video_size / 1024;
+			x->heapstart = ivideo.heapstart / 1024;
+			x->fbvidmode = sisfb_mode_no;
+			x->sisfb_caps = sisfb_caps;
+			x->sisfb_tqlen = 512; /* yet unused */
+	                break;
+		}
+	   default:
+		return -EINVAL;
+	}
+	TWDEBUG("end of ioctl");
+	return 0;
+
+}
+
+static int sisfb_mmap(struct fb_info *info, struct file *file,
+		      struct vm_area_struct *vma)
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#define currcon info->currcon
+#endif
+	struct fb_var_screeninfo var;
+	unsigned long start;
+	unsigned long off;
+	u32 len;
+
+	TWDEBUG("inside mmap");
+	if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT))  return -EINVAL;
+
+	off = vma->vm_pgoff << PAGE_SHIFT;
+
+	start = (unsigned long) ivideo.video_base;
+	len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);
+
+	if (off >= len) {
+		off -= len;
+		sisfb_get_var(&var, currcon, info);
+		if(var.accel_flags) return -EINVAL;
+
+		start = (unsigned long) ivideo.mmio_base;
+		len = PAGE_ALIGN((start & ~PAGE_MASK) + sisfb_mmio_size);
+	}
+
+	start &= PAGE_MASK;
+	if((vma->vm_end - vma->vm_start + off) > len)	return -EINVAL;
+
+	off += start;
+	vma->vm_pgoff = off >> PAGE_SHIFT;
+
+#if defined(__i386__) || defined(__x86_64__)
+	if (boot_cpu_data.x86 > 3)
+		pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,
+				vma->vm_page_prot))
+#else	/* TW: 2.5 API */
+	if (io_remap_page_range(vma, vma->vm_start, off, vma->vm_end - vma->vm_start,
+				vma->vm_page_prot))
+#endif
+		return -EAGAIN;
+
+        TWDEBUG("end of mmap");
+	return 0;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#undef currcon
+#endif
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+static struct fb_ops sisfb_ops = {
+	.owner        =	THIS_MODULE,
+	.fb_set_var   =	gen_set_var,
+	.fb_get_cmap  =	gen_get_cmap,
+	.fb_set_cmap  =	gen_set_cmap,
+
+	.fb_check_var = sisfb_check_var,
+	.fb_set_par   = sisfb_set_par,
+        .fb_setcolreg = sisfb_setcolreg,
+        .fb_blank     = sisfb_blank,
+#ifdef SISFB_PAN
+        .fb_pan_display = sisfb_pan_display,
+#endif
+        .fb_fillrect  = fbcon_sis_fillrect,
+	.fb_copyarea  = fbcon_sis_copyarea,
+	.fb_imageblit = my_cfb_imageblit,
+	.fb_ioctl     =	sisfb_ioctl,
+	.fb_mmap      =	sisfb_mmap,
+};
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+static struct fb_ops sisfb_ops = {
+	owner:		THIS_MODULE,
+	fb_get_fix:	sisfb_get_fix,
+	fb_get_var:	sisfb_get_var,
+	fb_set_var:	sisfb_set_var,
+	fb_get_cmap:	sisfb_get_cmap,
+	fb_set_cmap:	sisfb_set_cmap,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+        fb_setcolreg:   sisfb_setcolreg,
+        fb_blank:       sisfb_blank,
+#endif
+#ifdef SISFB_PAN
+        fb_pan_display:	sisfb_pan_display,
+#endif
+	fb_ioctl:	sisfb_ioctl,
+	fb_mmap:	sisfb_mmap,
+};
+#endif
+
+/* ------------ Interface to the low level console driver -------------*/
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)	/* --------- for 2.4 series --------- */
+static int sisfb_update_var(int con, struct fb_info *info)
+{
+#ifdef SISFB_PAN
+        sisfb_pan_var(&fb_display[con].var);
+#endif
+	return 0;
+}
+
+static int sisfb_switch(int con, struct fb_info *info)
+{
+	int cols, rows;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#define currcon info->currcon
+#endif
+
+        if(fb_display[currcon].cmap.len)
+		fb_get_cmap(&fb_display[currcon].cmap, 1, sis_getcolreg, info);
+
+	fb_display[con].var.activate = FB_ACTIVATE_NOW;
+
+	if(!memcmp(&fb_display[con].var, &fb_display[currcon].var,
+	                           sizeof(struct fb_var_screeninfo))) {
+		currcon = con;
+		return 1;
+	}
+
+	currcon = con;
+
+	sisfb_do_set_var(&fb_display[con].var, 1, info);
+
+	sisfb_set_disp(con, &fb_display[con].var, info);
+
+	sisfb_do_install_cmap(con, info);
+
+	cols = sisbios_mode[sisfb_mode_idx].cols;
+	rows = sisbios_mode[sisfb_mode_idx].rows;
+	vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
+
+	sisfb_update_var(con, info);
+
+	return 1;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+#undef currcon
+#endif
+}
+
+static void sisfb_blank(int blank, struct fb_info *info)
+{
+	u8 reg;
+
+	inSISIDXREG(SISCR, 0x17, reg);
+
+	if(blank > 0)
+		reg &= 0x7f;
+	else
+		reg |= 0x80;
+
+	outSISIDXREG(SISCR, 0x17, reg);
+}
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)	/* ---------- for 2.5 series -------- */
+static int sisfb_blank(int blank, struct fb_info *info)
+{
+	u8 reg;
+
+	inSISIDXREG(SISCR, 0x17, reg);
+
+	if(blank > 0)
+		reg &= 0x7f;
+	else
+		reg |= 0x80;
+
+	outSISIDXREG(SISCR, 0x17, reg);
+        return(0);
+}
+#endif
+
+/* --------------- Chip-dependent Routines --------------------------- */
+
+#ifdef CONFIG_FB_SIS_300 /* for SiS 300/630/540/730 */
+
+static int sisfb_get_dram_size_300(void)
+{
+	struct pci_dev *pdev = NULL;
+	int pdev_valid = 0;
+	u8  pci_data, reg;
+	u16 nbridge_id;
+
+	switch (ivideo.chip) {
+	   case SIS_540:
+		nbridge_id = PCI_DEVICE_ID_SI_540;
+		break;
+	   case SIS_630:
+		nbridge_id = PCI_DEVICE_ID_SI_630;
+		break;
+	   case SIS_730:
+		nbridge_id = PCI_DEVICE_ID_SI_730;
+		break;
+	   default:
+		nbridge_id = 0;
+		break;
+	}
+
+	if (nbridge_id == 0) {  /* 300 */
+
+	        inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE,reg);
+		ivideo.video_size =
+		        ((unsigned int) ((reg & SIS_DRAM_SIZE_MASK) + 1) << 20);
+
+	} else {		/* 540, 630, 730 */
+
+		pci_for_each_dev(pdev) {
+
+			if ((pdev->vendor == PCI_VENDOR_ID_SI) 
+				       && (pdev->device == nbridge_id)) {
+				pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data);
+				pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
+				ivideo.video_size = (unsigned int)(1 << (pci_data+21));
+				pdev_valid = 1;
+	
+				reg = SIS_DATA_BUS_64 << 6;
+				switch (pci_data) {
+				   case BRI_DRAM_SIZE_2MB:
+					reg |= SIS_DRAM_SIZE_2MB;
+					break;
+				   case BRI_DRAM_SIZE_4MB:
+					reg |= SIS_DRAM_SIZE_4MB;
+					break;
+				   case BRI_DRAM_SIZE_8MB:
+					reg |= SIS_DRAM_SIZE_8MB;
+					break;
+				   case BRI_DRAM_SIZE_16MB:
+					reg |= SIS_DRAM_SIZE_16MB;
+					break;
+				   case BRI_DRAM_SIZE_32MB:
+					reg |= SIS_DRAM_SIZE_32MB;
+					break;
+				   case BRI_DRAM_SIZE_64MB:
+					reg |= SIS_DRAM_SIZE_64MB;
+					break;
+				}
+				outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+				break;
+			}  
+		}   
+	
+		if (!pdev_valid)  return -1;
+	}
+	return 0;
+}
+
+static void sisfb_detect_VB_connect_300()
+{
+	u8 sr16, sr17, cr32, temp;
+
+	ivideo.TV_plug = ivideo.TV_type = 0;
+
+        switch(ivideo.hasVB) {
+	  case HASVB_LVDS_CHRONTEL:
+	  case HASVB_CHRONTEL:
+	     SiS_SenseCh();
+	     break;
+	  case HASVB_301:
+	  case HASVB_302:
+	     SiS_Sense30x();
+	     break;
+	}
+
+	inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_17, sr17);
+        inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR32, cr32);
+
+	if ((sr17 & 0x0F) && (ivideo.chip != SIS_300)) {
+
+		if ((sr17 & 0x01) && !sisfb_crt1off)
+			sisfb_crt1off = 0;
+		else {
+			if (sr17 & 0x0E)
+				sisfb_crt1off = 1;
+			else
+				sisfb_crt1off = 0;
+		}
+
+		if (sisfb_crt2type != -1)
+			/* TW: override detected CRT2 type */
+			ivideo.disp_state = sisfb_crt2type;
+		else if (sr17 & 0x08 )
+			ivideo.disp_state = DISPTYPE_CRT2;
+		else if (sr17 & 0x02)
+			ivideo.disp_state = DISPTYPE_LCD;
+		else if (sr17 & 0x04)
+			ivideo.disp_state = DISPTYPE_TV;
+		else
+			ivideo.disp_state = 0;
+
+		if(sisfb_tvplug != -1)
+			/* PR/TW: override detected TV type */
+			ivideo.TV_plug = sisfb_tvplug;
+		else if (sr17 & 0x20)
+			ivideo.TV_plug = TVPLUG_SVIDEO;
+		else if (sr17 & 0x10)
+			ivideo.TV_plug = TVPLUG_COMPOSITE;
+
+		inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_16, sr16);
+		if (sr16 & 0x20)
+			ivideo.TV_type = TVMODE_PAL;
+		else
+			ivideo.TV_type = TVMODE_NTSC;
 
-		vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_16);
-		sr16 = vgarb(SEQ_DATA);
-		if (sr16 & 0x20)
-			ivideo.TV_type = TVMODE_PAL;
-		else
-			ivideo.TV_type = TVMODE_NTSC;
 	} else {
+
 		if ((cr32 & SIS_CRT1) && !sisfb_crt1off)
 			sisfb_crt1off = 0;
 		else {
@@ -840,11 +1771,16 @@
 		else
 			ivideo.disp_state = 0;
 
-		/* TW: Detect TV plug & type anyway */
-		if (cr32 & SIS_VB_HIVISION) {
+		/* TW: Detect TV plug & type */
+		if(sisfb_tvplug != -1)
+			/* PR/TW: override with option */
+		        ivideo.TV_plug = sisfb_tvplug;
+#ifdef oldHV
+		else if (cr32 & SIS_VB_HIVISION) {
 			ivideo.TV_type = TVMODE_HIVISION;
 			ivideo.TV_plug = TVPLUG_SVIDEO;
 		}
+#endif
 		else if (cr32 & SIS_VB_SVIDEO)
 			ivideo.TV_plug = TVPLUG_SVIDEO;
 		else if (cr32 & SIS_VB_COMPOSITE)
@@ -853,34 +1789,19 @@
 			ivideo.TV_plug = TVPLUG_SCART;
 
 		if (ivideo.TV_type == 0) {
-			// Eden Chen
-			//temp = *((u8 *)(sishw_ext.VirtualRomBase+0x52));
-			//if (temp&0x40) {
-			//	temp=*((u8 *)(sishw_ext.VirtualRomBase+0x53));
-				//} else {
-			vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP);
-			temp = vgarb(SEQ_DATA);
-			//}
-			// ~Eden Chen
+		        inSISIDXREG(SISSR, IND_SIS_POWER_ON_TRAP, temp);
 			if (temp & 0x01)
 				ivideo.TV_type = TVMODE_PAL;
 			else
 				ivideo.TV_type = TVMODE_NTSC;
 		}
+
 	}
 
 	/* TW: Copy forceCRT1 option to CRT1off if option is given */
     	if (sisfb_forcecrt1 != -1) {
-		vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_17);
-    		sr17 = vgarb(SEQ_DATA);
-    		if (sisfb_forcecrt1) {
-			sisfb_crt1off=0;
-			sr17 |= 0x80;
-		} else {
-			sisfb_crt1off=1;
-			sr17 &= ~0x80;
-		}
-		vgawb(SEQ_DATA, sr17);
+    		if(sisfb_forcecrt1) sisfb_crt1off = 0;
+		else                sisfb_crt1off = 1;
     	}
 }
 
@@ -888,11 +1809,9 @@
 {
 	u8 reg;
 
-	if (ivideo.chip != SIS_300) {
-		if (!sisfb_has_VB_300()) {
-			vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR37);
-			reg = vgarb(CRTC_DATA);
-
+	if(ivideo.chip != SIS_300) {
+		if(!sisfb_has_VB_300()) {
+		        inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR37, reg);
 			switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) {
 			   case SIS_EXTERNAL_CHIP_SIS301:
 				ivideo.hasVB = HASVB_301;
@@ -916,22 +1835,13 @@
 	} else {
 		sisfb_has_VB_300();
 	}
-	//sishw_ext.hasVB = ivideo.hasVB;
 }
 
 static int sisfb_has_VB_300(void)
 {
-	// Eden Chen
-	//u8 sr38, sr39, vb_chipid;
 	u8 vb_chipid;
 
-	//vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP);
-	//sr38 = vgarb(SEQ_DATA);
-	//vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP2);
-	//sr39 = vgarb(SEQ_DATA);
-	vgawb(VB_PART4_ADR, 0x0);
-	vb_chipid = vgarb(VB_PART4_DATA);
-        
+	inSISIDXREG(SISPART4, 0x00, vb_chipid);
 	switch (vb_chipid) {
 	   case 0x01:
 		ivideo.hasVB = HASVB_301;
@@ -948,31 +1858,13 @@
 	}
 	return TRUE;
 
-	//if (
-	//	( (ivideo.chip == SIS_300) && (sr38 & 0x20) )
-	//	||
-	//	( (ivideo.chip == SIS_540) && (sr38 & 0x20) && (!(sr39 & 0x80)) )
-	//	||
-	//	( (ivideo.chip == SIS_630 ) && (sr38 & 0x20) && (!(sr39 & 0x80)) && 
-	//		((ivideo.revision_id & 0xf0) < 0x30) && (vb_chipid == 1) ) 
-	//	||
-	//	( (ivideo.chip == SIS_630 ) && ((ivideo.revision_id & 0xf0) >= 0x30) && 
-	//		(vb_chipid == 1) ) 
-	//	||
-	//	( (ivideo.chip == SIS_730) && (vb_chipid == 1) ) /* 730 */
-	//) {
-	//	ivideo.hasVB = HASVB_301;
-	//	return TRUE;
-	//} else {
-	//	ivideo.hasVB = HASVB_NONE;
-	//	return FALSE;
-	//}
-
-	// ~Eden Chen
 }
+
 #endif  /* CONFIG_FB_SIS_300 */
 
-#ifdef CONFIG_FB_SIS_315    /* for SiS 315H/315PRO/550/650/740 */
+
+#ifdef CONFIG_FB_SIS_315    /* for SiS 315/550/650/740 */
+
 static int sisfb_get_dram_size_315(void)
 {
 	struct pci_dev *pdev = NULL;
@@ -981,25 +1873,24 @@
 	u8  reg = 0;
 
 	if (ivideo.chip == SIS_550 || ivideo.chip == SIS_650) {
+
 #ifdef LINUXBIOS
+
 		pci_for_each_dev(pdev) {
+
 			if ( (pdev->vendor == PCI_VENDOR_ID_SI)
-				&& ( (pdev->device == PCI_DEVICE_ID_SI_550)
-				  || (pdev->device == PCI_DEVICE_ID_SI_650))) {
+				&& ( (pdev->device == PCI_DEVICE_ID_SI_550) ||
+				     (pdev->device == PCI_DEVICE_ID_SI_650))) {
 				pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS,
 				                     &pci_data);
 				pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
-				ivideo.video_size =
-				    (unsigned int)(1 << (pci_data+21));
+				ivideo.video_size = (unsigned int)(1 << (pci_data + 21));
 				pdev_valid = 1;
 
 				/* TW: Initialize SR14 "by hand" */
-				vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
-				reg = vgarb(SEQ_DATA) & 0xC0;
-
+				inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+				reg &= 0xC0;
 				switch (pci_data) {
-				//case BRI_DRAM_SIZE_2MB:
-				//	reg |= (SIS315_DRAM_SIZE_2MB << 4); break;
 				   case BRI_DRAM_SIZE_4MB:
 					reg |= SIS550_DRAM_SIZE_4MB;
 					break;
@@ -1015,22 +1906,20 @@
 				   case BRI_DRAM_SIZE_64MB:
 					reg |= SIS550_DRAM_SIZE_64MB;
 					break;
-				   /* case BRI_DRAM_SIZE_128MB:
-					reg |= (SIS315_DRAM_SIZE_128MB << 4); break; */
 				}
 
-			        /* TODO : set Dual channel and bus width bits here */
+			        /* TODO: set Dual channel and bus width bits here */
 
-				vgawb(SEQ_DATA, reg);
+				outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
 				break;
 			}  
 		}
 	
-		if (!pdev_valid)
-			return -1;
+		if (!pdev_valid)  return -1;
+
 #else
-		vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
-		reg = vgarb(SEQ_DATA);
+
+                inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
 		switch (reg & SIS550_DRAM_SIZE_MASK) {
 		   case SIS550_DRAM_SIZE_4MB:
 			ivideo.video_size = 0x400000;   break;
@@ -1053,26 +1942,26 @@
 		   default:
 		        /* TW: Some 550 BIOSes don't seem to initialize SR14 correctly (if at all),
 			 *     do it the hard way ourselves in this case. Unfortunately, we don't
-			 *     support 24, 48, 96 and other "odd" amounts here. I don't know if
-			 *     this work-around is required for 650/740 as well, but do it in case
-			 *     for now.
+			 *     support 24, 48, 96 and other "odd" amounts here.
 			 */
 		        printk(KERN_INFO
 			       "sisfb: Warning: Could not determine memory size, "
 			       "now reading from PCI config\n");
 			pdev_valid = 0;
+
 			pci_for_each_dev(pdev) {
+
 			   if ( (pdev->vendor == PCI_VENDOR_ID_SI)
-			         && (    (pdev->device == PCI_DEVICE_ID_SI_550)
-				      || (pdev->device == PCI_DEVICE_ID_SI_650) ) ) {
+			         && (pdev->device == PCI_DEVICE_ID_SI_550) ) {
+
 				pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS,
 				                     &pci_data);
 				pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4;
 				ivideo.video_size = (unsigned int)(1 << (pci_data+21));
 				pdev_valid = 1;
 				/* TW: Initialize SR14=IND_SIS_DRAM_SIZE */
-				vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
-				reg = vgarb(SEQ_DATA) & 0xC0;
+				inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
+				reg &= 0xC0;
 				switch (pci_data) {
 				   case BRI_DRAM_SIZE_4MB:
 					reg |= SIS550_DRAM_SIZE_4MB;  break;
@@ -1084,13 +1973,11 @@
 					reg |= SIS550_DRAM_SIZE_32MB; break;
 				   case BRI_DRAM_SIZE_64MB:
 					reg |= SIS550_DRAM_SIZE_64MB; break;
-				   /* case BRI_DRAM_SIZE_128MB:
-					reg |= (SIS315_DRAM_SIZE_128MB << 4); break; */
 				   default:
 				   	printk(KERN_INFO "sisfb: Unable to determine memory size, giving up.\n");
 					return -1;
 				}
-				vgawb(SEQ_DATA, reg);
+				outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
 			   }
 			}
 			if (!pdev_valid) {
@@ -1101,9 +1988,10 @@
 		}
 #endif
 		return 0;
+
 	} else {	/* 315 */
-		vgawb(SEQ_ADR, IND_SIS_DRAM_SIZE);
-		reg = vgarb(SEQ_DATA);
+
+	        inSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg);
 		switch ((reg & SIS315_DRAM_SIZE_MASK) >> 4) {
 		   case SIS315_DRAM_SIZE_2MB:
 			ivideo.video_size = 0x200000;
@@ -1141,7 +2029,7 @@
 		ivideo.video_size <<= 1;
 		break;
 	   case SIS315_ASYM_DDR:		/* TW: DDR asymentric */
-		ivideo.video_size += ivideo.video_size/2;
+		ivideo.video_size += (ivideo.video_size/2);
 		break;
 	}
 
@@ -1150,12 +2038,23 @@
 
 static void sisfb_detect_VB_connect_315(void)
 {
-	u8 sr17, cr32, temp;
-
-	vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR32);
-	cr32 = vgarb(CRTC_DATA);
+	u8 cr32, temp=0;
 
 	ivideo.TV_plug = ivideo.TV_type = 0;
+
+        switch(ivideo.hasVB) {
+	  case HASVB_LVDS_CHRONTEL:
+	  case HASVB_CHRONTEL:
+	     SiS_SenseCh();
+	     break;
+	  case HASVB_301:
+	  case HASVB_302:
+	     SiS_Sense30x();
+	     break;
+	}
+
+	inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR32, cr32);
+
 	if ((cr32 & SIS_CRT1) && !sisfb_crt1off)
 		sisfb_crt1off = 0;
 	else {
@@ -1177,37 +2076,46 @@
 	else
 		ivideo.disp_state = 0;
 
-	if (cr32 & SIS_VB_HIVISION) {
+	if(sisfb_tvplug != -1)
+		/* PR/TW: Override with option */
+	        ivideo.TV_plug = sisfb_tvplug;
+#ifdef oldHV
+	else if (cr32 & SIS_VB_HIVISION) {
 		ivideo.TV_type = TVMODE_HIVISION;
 		ivideo.TV_plug = TVPLUG_SVIDEO;
-	} else if (cr32 & SIS_VB_SVIDEO)
+	}
+#endif
+	else if (cr32 & SIS_VB_SVIDEO)
 		ivideo.TV_plug = TVPLUG_SVIDEO;
 	else if (cr32 & SIS_VB_COMPOSITE)
 		ivideo.TV_plug = TVPLUG_COMPOSITE;
 	else if (cr32 & SIS_VB_SCART)
 		ivideo.TV_plug = TVPLUG_SCART;
 
-	if (ivideo.TV_type == 0) {
-		vgawb(SEQ_ADR, IND_SIS_POWER_ON_TRAP);
-		temp = vgarb(SEQ_DATA);
-		if (temp & 0x01)
+	if(ivideo.TV_type == 0) {
+	    /* TW: PAL/NTSC changed for 650 */
+	    if(ivideo.chip <= SIS_315PRO) {
+
+                inSISIDXREG(SISCR, 0x38, temp);
+		if(temp & 0x10)
+			ivideo.TV_type = TVMODE_PAL;
+		else
+			ivideo.TV_type = TVMODE_NTSC;
+
+	    } else {
+
+	        inSISIDXREG(SISCR, 0x79, temp);
+		if(temp & 0x20)
 			ivideo.TV_type = TVMODE_PAL;
 		else
 			ivideo.TV_type = TVMODE_NTSC;
+	    }
 	}
 
 	/* TW: Copy forceCRT1 option to CRT1off if option is given */
     	if (sisfb_forcecrt1 != -1) {
-		vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_17);
-    		sr17 = vgarb(SEQ_DATA);
-    		if (sisfb_forcecrt1) {
-			sisfb_crt1off=0;
-			sr17 |= 0x80;
-		} else {
-			sisfb_crt1off=1;
-			sr17 &= ~0x80;
-		}
-		vgawb(SEQ_DATA, sr17);
+    		if (sisfb_forcecrt1) sisfb_crt1off = 0;
+		else   	             sisfb_crt1off = 1;
     	}
 }
 
@@ -1215,44 +2123,31 @@
 {
 	u8 reg;
 
-	/* 550 has LVDS-like FSTN bridge (?) */
-	if (ivideo.chip == SIS_550) {
 		if (!sisfb_has_VB_315()) {
-			vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR37);
-			reg = vgarb(CRTC_DATA);
-
+		        inSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR37, reg);
+			/* TW: CR37 changed on 310/325 series */
 			switch ((reg & SIS_EXTERNAL_CHIP_MASK) >> 1) {
 			   case SIS_EXTERNAL_CHIP_SIS301:
 				ivideo.hasVB = HASVB_301;
 				break;
-			   case SIS_EXTERNAL_CHIP_LVDS:
+			   case SIS310_EXTERNAL_CHIP_LVDS:
 				ivideo.hasVB = HASVB_LVDS;
 				break;
-			   case SIS_EXTERNAL_CHIP_TRUMPION:
-				ivideo.hasVB = HASVB_TRUMPION;
-				break;
-			   case SIS_EXTERNAL_CHIP_LVDS_CHRONTEL:
+			   case SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL:
 				ivideo.hasVB = HASVB_LVDS_CHRONTEL;
 				break;
-			   case SIS_EXTERNAL_CHIP_CHRONTEL:
-				ivideo.hasVB = HASVB_CHRONTEL;
-				break;
 			   default:
 				break;
 			}
 		}
-	} else {
-		sisfb_has_VB_315();
-	}
 }
 
+
 static int sisfb_has_VB_315(void)
 {
 	u8 vb_chipid;
 
-	vgawb(VB_PART4_ADR, 0x0);
-	vb_chipid = vgarb(VB_PART4_DATA);
-
+	inSISIDXREG(SISPART4, 0x00, vb_chipid);
 	switch (vb_chipid) {
 	   case 0x01:
 		ivideo.hasVB = HASVB_301;
@@ -1267,12 +2162,204 @@
 		ivideo.hasVB = HASVB_NONE;
 		return FALSE;
 	}
-	// Eden Chen
-	//sishw_ext.hasVB = ivideo.hasVB;
-	// ~Eden Chen
-	return TRUE;
+	return TRUE;
+}
+
+#endif   /* CONFIG_FB_SIS_315 */
+
+/* -------------- Sensing routines --------------- */
+
+/* TW: Determine and detect attached devices on SiS30x */
+int
+SISDoSense(int tempbl, int tempbh, int tempcl, int tempch)
+{
+    int temp,i;
+
+    outSISIDXREG(SISPART4,0x11,tempbl);
+    temp = tempbh | tempcl;
+    setSISIDXREG(SISPART4,0x10,0xe0,temp);
+    for(i=0; i<10; i++) SiS_LongWait(&SiS_Pr);
+    tempch &= 0x7f;
+    inSISIDXREG(SISPART4,0x03,temp);
+    temp ^= 0x0e;
+    temp &= tempch;
+    return(temp);
+}
+
+void
+SiS_Sense30x(void)
+{
+  u8 backupP4_0d;
+  u8 testsvhs_tempbl, testsvhs_tempbh;
+  u8 testsvhs_tempcl, testsvhs_tempch;
+  u8 testcvbs_tempbl, testcvbs_tempbh;
+  u8 testcvbs_tempcl, testcvbs_tempch;
+  int myflag, result;
+
+  inSISIDXREG(SISPART4,0x0d,backupP4_0d);
+  outSISIDXREG(SISPART4,0x0d,(backupP4_0d | 0x04));
+
+  if(sisvga_engine == SIS_300_VGA) {
+
+        testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xb9;
+	testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xb3;
+	if((sishw_ext.ujVBChipID != VB_CHIP_301) &&
+	   (sishw_ext.ujVBChipID != VB_CHIP_302) ) {
+	   testsvhs_tempbh = 0x01; testsvhs_tempbl = 0x6b;
+	   testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x74;
+	}
+	inSISIDXREG(SISPART4,0x01,myflag);
+	if(myflag & 0x04) {
+	   testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xdd;
+	   testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xee;
+	}
+	testsvhs_tempch = 0x06;	testsvhs_tempcl = 0x04;
+	testcvbs_tempch = 0x08; testcvbs_tempcl = 0x04;
+
+  } else if((ivideo.chip == SIS_315) ||
+    	    (ivideo.chip == SIS_315H) ||
+	    (ivideo.chip == SIS_315PRO)) {
+
+        testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xb9;
+	testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xb3;
+	if((sishw_ext.ujVBChipID != VB_CHIP_301) &&
+	   (sishw_ext.ujVBChipID != VB_CHIP_302) ) {
+	      testsvhs_tempbh = 0x01; testsvhs_tempbl = 0x6b;
+	      testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x74;
+	}
+	inSISIDXREG(SISPART4,0x01,myflag);
+	if(myflag & 0x04) {
+	   testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xdd;
+	   testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xee;
+	}
+	testsvhs_tempch = 0x06;	testsvhs_tempcl = 0x04;
+	testcvbs_tempch = 0x08; testcvbs_tempcl = 0x04;
+
+    } else {
+
+        testsvhs_tempbh = 0x02; testsvhs_tempbl = 0x00;
+	testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x00;
+
+	testsvhs_tempch = 0x04;	testsvhs_tempcl = 0x08;
+	testcvbs_tempch = 0x08; testcvbs_tempcl = 0x08;
+
+    }
+
+    result = SISDoSense(testsvhs_tempbl, testsvhs_tempbh,
+                        testsvhs_tempcl, testsvhs_tempch);
+    if(result) {
+        printk(KERN_INFO "sisfb: Detected TV connected to SVHS output\n");
+        /* TW: So we can be sure that there IS a SVHS output */
+	ivideo.TV_plug = TVPLUG_SVIDEO;
+	orSISIDXREG(SISCR, 0x32, 0x02);
+    }
+
+    if(!result) {
+        result = SISDoSense(testcvbs_tempbl, testcvbs_tempbh,
+	                    testcvbs_tempcl, testcvbs_tempch);
+	if(result) {
+	    printk(KERN_INFO "sisfb: Detected TV connected to CVBS output\n");
+	    /* TW: So we can be sure that there IS a CVBS output */
+	    ivideo.TV_plug = TVPLUG_COMPOSITE;
+	    orSISIDXREG(SISCR, 0x32, 0x01);
+	}
+    }
+    SISDoSense(0, 0, 0, 0);
+
+    outSISIDXREG(SISPART4,0x0d,backupP4_0d);
+}
+
+/* TW: Determine and detect attached TV's on Chrontel */
+void
+SiS_SenseCh(void)
+{
+
+   u8 temp1;
+#ifdef CONFIG_FB_SIS_315
+   u8 temp2;
+#endif
+
+   if(ivideo.chip < SIS_315H) {
+
+#ifdef CONFIG_FB_SIS_300
+       SiS_Pr.SiS_IF_DEF_CH70xx = 1;		/* TW: Chrontel 7005 */
+       temp1 = SiS_GetCH700x(&SiS_Pr, 0x25);
+       if ((temp1 >= 50) && (temp1 <= 100)) {
+	   /* TW: Read power status */
+	   temp1 = SiS_GetCH700x(&SiS_Pr, 0x0e);
+	   if((temp1 & 0x03) != 0x03) {
+     	        /* TW: Power all outputs */
+		SiS_SetCH70xxANDOR(&SiS_Pr, 0x030E,0xF8);
+	   }
+	   /* TW: Sense connected TV devices */
+	   SiS_SetCH700x(&SiS_Pr, 0x0110);
+	   SiS_SetCH700x(&SiS_Pr, 0x0010);
+	   temp1 = SiS_GetCH700x(&SiS_Pr, 0x10);
+	   if(!(temp1 & 0x08)) {
+		printk(KERN_INFO
+		   "sisfb: Chrontel: Detected TV connected to SVHS output\n");
+		/* TW: So we can be sure that there IS a SVHS output */
+		ivideo.TV_plug = TVPLUG_SVIDEO;
+		orSISIDXREG(SISCR, 0x32, 0x02);
+	   } else if (!(temp1 & 0x02)) {
+		printk(KERN_INFO
+		   "sisfb: Chrontel: Detected TV connected to CVBS output\n");
+		/* TW: So we can be sure that there IS a CVBS output */
+		ivideo.TV_plug = TVPLUG_COMPOSITE;
+		orSISIDXREG(SISCR, 0x32, 0x01);
+	   } else {
+ 		SiS_SetCH70xxANDOR(&SiS_Pr, 0x010E,0xF8);
+	   }
+       } else if(temp1 == 0) {
+	  SiS_SetCH70xxANDOR(&SiS_Pr, 0x010E,0xF8);
+       }
+#endif
+
+   } else {
+
+#ifdef CONFIG_FB_SIS_315
+	SiS_Pr.SiS_IF_DEF_CH70xx = 2;		/* TW: Chrontel 7019 */
+        temp1 = SiS_GetCH701x(&SiS_Pr, 0x49);
+	SiS_SetCH701x(&SiS_Pr, 0x2049);
+	SiS_DDC2Delay(&SiS_Pr, 0x96);
+	temp2 = SiS_GetCH701x(&SiS_Pr, 0x20);
+	temp2 |= 0x01;
+	SiS_SetCH701x(&SiS_Pr, (temp2 << 8) | 0x20);
+	SiS_DDC2Delay(&SiS_Pr, 0x96);
+	temp2 ^= 0x01;
+	SiS_SetCH701x(&SiS_Pr, (temp2 << 8) | 0x20);
+	SiS_DDC2Delay(&SiS_Pr, 0x96);
+	temp2 = SiS_GetCH701x(&SiS_Pr, 0x20);
+	SiS_SetCH701x(&SiS_Pr, (temp1 << 8) | 0x49);
+        temp1 = 0;
+	if(temp2 & 0x02) temp1 |= 0x01;
+	if(temp2 & 0x10) temp1 |= 0x01;
+	if(temp2 & 0x04) temp1 |= 0x02;
+	if( (temp1 & 0x01) && (temp1 & 0x02) ) temp1 = 0x04;
+	switch(temp1) {
+	case 0x01:
+	     printk(KERN_INFO
+		"sisfb: Chrontel: Detected TV connected to CVBS output\n");
+	     ivideo.TV_plug = TVPLUG_COMPOSITE;
+	     orSISIDXREG(SISCR, 0x32, 0x01);
+             break;
+	case 0x02:
+	     printk(KERN_INFO
+		"sisfb: Chrontel: Detected TV connected to SVHS output\n");
+	     ivideo.TV_plug = TVPLUG_SVIDEO;
+	     orSISIDXREG(SISCR, 0x32, 0x02);
+             break;
+	case 0x04:
+	     /* TW: This should not happen */
+	     printk(KERN_INFO
+		"sisfb: Chrontel: Detected TV connected to SCART output!?\n");
+             break;
+	}
+#endif
+
+   }
 }
-#endif   /* CONFIG_FB_SIS_315 */
+
 
 /* --------------------- Heap Routines ------------------------------- */
 
@@ -1293,40 +2380,41 @@
 	u32            agp_phys;
 #endif
 #endif
-/* TW: If more than 8MB videoRAM detected, let our heap start at 8MB. If
- *     there is less RAM available, let it start at 4MB. This can be overruled
- *     by mem parameter.
+/* TW: The heap start is either set manually using the "mem" parameter, or
+ *     defaults as follows:
+ *     -) If more than 16MB videoRAM available, let our heap start at 12MB.
+ *     -) If more than  8MB videoRAM available, let our heap start at  8MB.
+ *     -) If 4MB or less is available, let it start at 4MB.
  *     This is for avoiding a clash with X driver which uses the beginning
  *     of the videoRAM. To limit size of X framebuffer, use Option MaxXFBMem
  *     in XF86Config-4.
  *     The heap start can also be specified by parameter "mem" when starting the sisfb
  *     driver. sisfb mem=1024 lets heap starts at 1MB, etc.
  */
-      /*karl:10/01/2001*/
-      if ((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
-	if (ivideo.video_size > 0x800000) {
-		sisfb_heap_start =
-		    (unsigned long) ivideo.video_vbase + 0x800000;
-		printk(KERN_INFO "sisfb: Memory heap starting at 8192K\n");
+     if ((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
+        if (ivideo.video_size > 0x1000000) {
+	        ivideo.heapstart = 0xc00000;
+	} else if (ivideo.video_size > 0x800000) {
+	        ivideo.heapstart = 0x800000;
 	} else {
-		sisfb_heap_start =
-		    (unsigned long) ivideo.video_vbase + 0x400000;
-		printk(KERN_INFO "sisfb: Memory heap starting at 4096K\n");
+		ivideo.heapstart = 0x400000;
 	}
      } else {
-   	   sisfb_heap_start =
-	       (unsigned long) (ivideo.video_vbase + (sisfb_mem * 1024));
-	   printk(KERN_INFO "sisfb: Memory heap starting at %dK\n", sisfb_mem);
+           ivideo.heapstart = sisfb_mem * 1024;
      }
+     sisfb_heap_start =
+	       (unsigned long) (ivideo.video_vbase + ivideo.heapstart);
+     printk(KERN_INFO "sisfb: Memory heap starting at %dK\n",
+     					(int)(ivideo.heapstart / 1024));
 
      sisfb_heap_end = (unsigned long) ivideo.video_vbase + ivideo.video_size;
      sisfb_heap_size = sisfb_heap_end - sisfb_heap_start;
 
 #ifdef CONFIG_FB_SIS_315
      if (sisvga_engine == SIS_315_VGA) {
-        /* TW: Now initlalize the 310 series' command queue mode.
-	 * On 310, there are three queue modes available which
-	 *     are chosen by setting bits 7:5 in SR26:
+        /* TW: Now initialize the 310 series' command queue mode.
+	 * On 310/325, there are three queue modes available which
+	 * are chosen by setting bits 7:5 in SR26:
 	 * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep
 	 *    track of the queue, the FIFO, command parsing and so
 	 *    on. This is the one comparable to the 300 series.
@@ -1387,7 +2475,7 @@
 		}
 	}
 #else
-	agp_enabled= 0;
+	agp_enabled = 0;
 #endif
 
 	/* TW: Now select the queue mode */
@@ -1422,26 +2510,22 @@
 	switch (cmd_type) {
 	   case AGP_CMD_QUEUE:
 #ifndef AGPOFF
-		DPRINTK("sisfb: AGP buffer base:0x%lx, offset:0x%x, size: %dK\n",
+		DPRINTK("sisfb: AGP buffer base = 0x%lx, offset = 0x%x, size = %dK\n",
 			agp_info->aper_base, agp->physical, agp_size/1024);
 
 		agp_phys = agp_info->aper_base + agp->physical;
 
-		vgawb(CRTC_ADR, IND_SIS_AGP_IO_PAD);
-		vgawb(CRTC_DATA, 0);
-		vgawb(CRTC_DATA, SIS_AGP_2X);
+		outSISIDXREG(SISCR,  IND_SIS_AGP_IO_PAD, 0);
+		outSISIDXREG(SISCR,  IND_SIS_AGP_IO_PAD, SIS_AGP_2X);
 
-		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_THRESHOLD);
-		vgawb(SEQ_DATA, COMMAND_QUEUE_THRESHOLD);
+                outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
 
-		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);
-		vgawb(SEQ_DATA, SIS_CMD_QUEUE_RESET);
+		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
 
 		*write_port = *read_port;
 
 		temp |= SIS_AGP_CMDQUEUE_ENABLE;
-		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);
-		vgawb(SEQ_DATA, temp);
+		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
 
 		*cmdq_baseport = agp_phys;
 
@@ -1453,17 +2537,14 @@
 		sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
 		sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;
 
-		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_THRESHOLD);
-		vgawb(SEQ_DATA, COMMAND_QUEUE_THRESHOLD);
+		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
 
-		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);
-		vgawb(SEQ_DATA, SIS_CMD_QUEUE_RESET);
+		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
 
 		*write_port = *read_port;
 
 		temp |= SIS_VRAM_CMDQUEUE_ENABLE;
-		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);
-		vgawb(SEQ_DATA, temp);
+		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
 
 		*cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE;
 
@@ -1481,23 +2562,19 @@
 	   	sisfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
 		sisfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;
 
-		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_THRESHOLD);
-		vgawb(SEQ_DATA, COMMAND_QUEUE_THRESHOLD);
-
-		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);
-		vgawb(SEQ_DATA, SIS_CMD_QUEUE_RESET);
+		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
+		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, SIS_CMD_QUEUE_RESET);
 
 		*write_port = *read_port;
 
-		/* TW: Set Auto_Correction bit; this works in sisfb lite,
-		 * so why not.
-		 */
+		/* TW: Set Auto_Correction bit */
 		temp |= (SIS_MMIO_CMD_ENABLE | SIS_CMD_AUTO_CORR);
-		vgawb(SEQ_ADR, IND_SIS_CMDQUEUE_SET);
-		vgawb(SEQ_DATA, temp);
+		outSISIDXREG(SISSR, IND_SIS_CMDQUEUE_SET, temp);
 
 		*cmdq_baseport = ivideo.video_size - COMMAND_QUEUE_AREA_SIZE;
 
+		sisfb_caps |= MMIO_CMD_QUEUE_CAP;
+
 		DPRINTK("sisfb: MMIO Cmd Queue offset = 0x%lx, size is %dK\n",
 			*cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024);
 		break;
@@ -1515,15 +2592,16 @@
 
 		tqueue_pos = (ivideo.video_size -
 		       TURBO_QUEUE_AREA_SIZE) / (64 * 1024);
+
 		temp = (u8) (tqueue_pos & 0xff);
-		vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_SET);
-		tq_state = vgarb(SEQ_DATA);
+
+		inSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
 		tq_state |= 0xf0;
 		tq_state &= 0xfc;
 		tq_state |= (u8) (tqueue_pos >> 8);
-		vgawb(SEQ_DATA, tq_state);
-		vgawb(SEQ_ADR, IND_SIS_TURBOQUEUE_ADR);
-		vgawb(SEQ_DATA, temp);
+		outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_SET, tq_state);
+
+		outSISIDXREG(SISSR, IND_SIS_TURBOQUEUE_ADR, temp);
 
 		sisfb_caps |= TURBO_QUEUE_CAP;
 
@@ -1534,1075 +2612,506 @@
 	    }
      }
 #endif
-        /* TW: Now reserve memory for the HWCursor. It is always located at the very
-               top of the videoRAM, right below the TB memory area (if used). */
-	if (sisfb_heap_size >= sisfb_hwcursor_size) {
+     /* TW: Now reserve memory for the HWCursor. It is always located at the very
+            top of the videoRAM, right below the TB memory area (if used). */
+     if (sisfb_heap_size >= sisfb_hwcursor_size) {
 		sisfb_heap_end -= sisfb_hwcursor_size;
 		sisfb_heap_size -= sisfb_hwcursor_size;
-		sisfb_hwcursor_vbase = sisfb_heap_end;
-
-		sisfb_caps |= HW_CURSOR_CAP;
-
-		DPRINTK("sisfb: Hardware Cursor start at 0x%lx, size is %dK\n",
-			sisfb_heap_end, sisfb_hwcursor_size/1024);
-	}
-
-	sisfb_heap.poha_chain = NULL;
-	sisfb_heap.poh_freelist = NULL;
-
-	poh = sisfb_poh_new_node();
-
-	if (poh == NULL)
-		return 1;
-	
-	poh->poh_next = &sisfb_heap.oh_free;
-	poh->poh_prev = &sisfb_heap.oh_free;
-	poh->size = sisfb_heap_end - sisfb_heap_start + 1;
-	poh->offset = sisfb_heap_start - (unsigned long) ivideo.video_vbase;
-
-	DPRINTK("sisfb: Heap start:0x%p, end:0x%p, len=%dk\n",
-		(char *) sisfb_heap_start, (char *) sisfb_heap_end,
-		(unsigned int) poh->size / 1024);
-
-	DPRINTK("sisfb: First Node offset:0x%x, size:%dk\n",
-		(unsigned int) poh->offset, (unsigned int) poh->size / 1024);
-	
-	sisfb_heap.oh_free.poh_next = poh;
-	sisfb_heap.oh_free.poh_prev = poh;
-	sisfb_heap.oh_free.size = 0;
-	sisfb_heap.max_freesize = poh->size;
-
-	sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used;
-	sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used;
-	sisfb_heap.oh_used.size = SENTINEL;
-
-	return 0;
-}
-
-static SIS_OH *sisfb_poh_new_node(void)
-{
-	int i;
-	unsigned long cOhs;
-	SIS_OHALLOC *poha;
-	SIS_OH *poh;
-
-	if (sisfb_heap.poh_freelist == NULL) {
-		poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL);
-
-		poha->poha_next = sisfb_heap.poha_chain;
-		sisfb_heap.poha_chain = poha;
-
-		cOhs =
-		    (OH_ALLOC_SIZE -
-		     sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
-
-		poh = &poha->aoh[0];
-		for (i = cOhs - 1; i != 0; i--) {
-			poh->poh_next = poh + 1;
-			poh = poh + 1;
-		}
-
-		poh->poh_next = NULL;
-		sisfb_heap.poh_freelist = &poha->aoh[0];
-	}
-
-	poh = sisfb_heap.poh_freelist;
-	sisfb_heap.poh_freelist = poh->poh_next;
-
-	return (poh);
-}
-
-static SIS_OH *sisfb_poh_allocate(unsigned long size)
-{
-	SIS_OH *pohThis;
-	SIS_OH *pohRoot;
-	int bAllocated = 0;
-
-	if (size > sisfb_heap.max_freesize) {
-		DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
-			(unsigned int) size / 1024);
-		return (NULL);
-	}
-
-	pohThis = sisfb_heap.oh_free.poh_next;
-
-	while (pohThis != &sisfb_heap.oh_free) {
-		if (size <= pohThis->size) {
-			bAllocated = 1;
-			break;
-		}
-		pohThis = pohThis->poh_next;
-	}
-
-	if (!bAllocated) {
-		DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
-			(unsigned int) size / 1024);
-		return (NULL);
-	}
-
-	if (size == pohThis->size) {
-		pohRoot = pohThis;
-		sisfb_delete_node(pohThis);
-	} else {
-		pohRoot = sisfb_poh_new_node();
-
-		if (pohRoot == NULL) {
-			return (NULL);
-		}
-
-		pohRoot->offset = pohThis->offset;
-		pohRoot->size = size;
-
-		pohThis->offset += size;
-		pohThis->size -= size;
-	}
-
-	sisfb_heap.max_freesize -= size;
-
-	pohThis = &sisfb_heap.oh_used;
-	sisfb_insert_node(pohThis, pohRoot);
-
-	return (pohRoot);
-}
-
-static void sisfb_delete_node(SIS_OH *poh)
-{
-	SIS_OH *poh_prev;
-	SIS_OH *poh_next;
-
-
-	poh_prev = poh->poh_prev;
-	poh_next = poh->poh_next;
-
-	poh_prev->poh_next = poh_next;
-	poh_next->poh_prev = poh_prev;
-
-	return;
-}
-
-static void sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
-{
-	SIS_OH *pohTemp;
-
-	pohTemp = pohList->poh_next;
-
-	pohList->poh_next = poh;
-	pohTemp->poh_prev = poh;
-
-	poh->poh_prev = pohList;
-	poh->poh_next = pohTemp;
-}
-
-static SIS_OH *sisfb_poh_free(unsigned long base)
-{
-	SIS_OH *pohThis;
-	SIS_OH *poh_freed;
-	SIS_OH *poh_prev;
-	SIS_OH *poh_next;
-	unsigned long ulUpper;
-	unsigned long ulLower;
-	int foundNode = 0;
-
-	poh_freed = sisfb_heap.oh_used.poh_next;
-
-	while (poh_freed != &sisfb_heap.oh_used) {
-		if (poh_freed->offset == base) {
-			foundNode = 1;
-			break;
-		}
-
-		poh_freed = poh_freed->poh_next;
-	}
-
-	if (!foundNode)
-		return (NULL);
-
-	sisfb_heap.max_freesize += poh_freed->size;
-
-	poh_prev = poh_next = NULL;
-	ulUpper = poh_freed->offset + poh_freed->size;
-	ulLower = poh_freed->offset;
-
-	pohThis = sisfb_heap.oh_free.poh_next;
-
-	while (pohThis != &sisfb_heap.oh_free) {
-		if (pohThis->offset == ulUpper) {
-			poh_next = pohThis;
-		}
-			else if ((pohThis->offset + pohThis->size) ==
-				 ulLower) {
-			poh_prev = pohThis;
-		}
-		pohThis = pohThis->poh_next;
-	}
-
-	sisfb_delete_node(poh_freed);
-
-	if (poh_prev && poh_next) {
-		poh_prev->size += (poh_freed->size + poh_next->size);
-		sisfb_delete_node(poh_next);
-		sisfb_free_node(poh_freed);
-		sisfb_free_node(poh_next);
-		return (poh_prev);
-	}
-
-	if (poh_prev) {
-		poh_prev->size += poh_freed->size;
-		sisfb_free_node(poh_freed);
-		return (poh_prev);
-	}
-
-	if (poh_next) {
-		poh_next->size += poh_freed->size;
-		poh_next->offset = poh_freed->offset;
-		sisfb_free_node(poh_freed);
-		return (poh_next);
-	}
-
-	sisfb_insert_node(&sisfb_heap.oh_free, poh_freed);
-
-	return (poh_freed);
-}
-
-static void sisfb_free_node(SIS_OH *poh)
-{
-	if (poh == NULL) {
-		return;
-	}
-
-	poh->poh_next = sisfb_heap.poh_freelist;
-	sisfb_heap.poh_freelist = poh;
-
-	return;
-}
-
-void sis_malloc(struct sis_memreq *req)
-{
-	SIS_OH *poh;
-
-	poh = sisfb_poh_allocate(req->size);
-
-	if (poh == NULL) {
-		req->offset = 0;
-		req->size = 0;
-		DPRINTK("sisfb: Video RAM allocation failed\n");
-	} else {
-		DPRINTK("sisfb: Video RAM allocation succeeded: 0x%p\n",
-			(char *) (poh->offset +
-				  (unsigned long) ivideo.video_vbase));
-
-		req->offset = poh->offset;
-		req->size = poh->size;
-	}
-
-}
-
-void sis_free(unsigned long base)
-{
-	SIS_OH *poh;
-
-	poh = sisfb_poh_free(base);
-
-	if (poh == NULL) {
-		DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
-			(unsigned int) base);
-	}
-}
-
-/* ------------------ SetMode Routines ------------------------------- */
-
-static void sisfb_pre_setmode(void)
-{
-	u8 cr30 = 0, cr31 = 0;
+		sisfb_hwcursor_vbase = sisfb_heap_end;
 
-	vgawb(CRTC_ADR, 0x31);
-	cr31 = vgarb(CRTC_DATA) & ~0x60;
+		sisfb_caps |= HW_CURSOR_CAP;
 
-	switch (ivideo.disp_state & DISPTYPE_DISP2) {
-	   case DISPTYPE_CRT2:
-		printk(KERN_INFO "sisfb: CRT2 type is VGA\n");
-		cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
-		cr31 |= SIS_DRIVER_MODE;
-		break;
-	   case DISPTYPE_LCD:
-		printk(KERN_INFO "sisfb: CRT2 type is LCD\n");
-		cr30  = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
-		cr31 |= SIS_DRIVER_MODE;
-		break;
-	   case DISPTYPE_TV:
-		printk(KERN_INFO "sisfb: CRT2 type is TV\n");
-		if (ivideo.TV_type == TVMODE_HIVISION)
-			cr30 = (SIS_VB_OUTPUT_HIVISION | SIS_SIMULTANEOUS_VIEW_ENABLE);
-		else if (ivideo.TV_plug == TVPLUG_SVIDEO)
-			cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
-		else if (ivideo.TV_plug == TVPLUG_COMPOSITE)
-			cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
-		else if (ivideo.TV_plug == TVPLUG_SCART)
-			cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
-		cr31 |= SIS_DRIVER_MODE;
-		cr31 &= ~0x04; /* TW: No Slavemode by default  */
-                /*karl*/
-	        if (sisfb_tvmode == 1 || ivideo.TV_type == TVMODE_PAL)
-			cr31 |= 0x1;
-                if (sisfb_tvmode == 2 || ivideo.TV_type == TVMODE_NTSC)
-                        cr31 &= ~0x1;
-		break;
-	   default:	/* CRT2 disable */
-		printk(KERN_INFO "sisfb: CRT2 is disabled\n");
-		cr30 = 0x00;
-		cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
-	}
+		DPRINTK("sisfb: Hardware Cursor start at 0x%lx, size is %dK\n",
+			sisfb_heap_end, sisfb_hwcursor_size/1024);
+     }
 
-	vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR30);
-	vgawb(CRTC_DATA, cr30);
-	vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR31);
-	vgawb(CRTC_DATA, cr31);
-	/* printk(KERN_INFO "sisfb: 0x30=%x 0x31=%x\n", cr30, cr31); */
-	vgawb(CRTC_ADR, IND_SIS_SCRATCH_REG_CR33);
-/*
-	if (ivideo.disp_state & DISPTYPE_CRT2) {
-		sisfb_rate_idx &= 0x0F;
-		sisfb_rate_idx |= (sisfb_rate_idx << 4);
-		vgawb(CRTC_DATA, sisfb_rate_idx);
-	} else {
-		vgawb(CRTC_DATA, sisfb_rate_idx & 0x0F);
-	}
-*/
-	vgawb(CRTC_DATA, sisfb_rate_idx & 0x0F);
-}
+     sisfb_heap.poha_chain = NULL;
+     sisfb_heap.poh_freelist = NULL;
 
-static void sisfb_post_setmode(void)
-{
-	u8 reg;
+     poh = sisfb_poh_new_node();
 
-	vgawb(CRTC_ADR, 0x17);
-	reg = vgarb(CRTC_DATA);
+     if(poh == NULL)  return 1;
+	
+     poh->poh_next = &sisfb_heap.oh_free;
+     poh->poh_prev = &sisfb_heap.oh_free;
+     poh->size = sisfb_heap_end - sisfb_heap_start + 1;
+     poh->offset = sisfb_heap_start - (unsigned long) ivideo.video_vbase;
 
-	if ((ivideo.hasVB == HASVB_LVDS) || (ivideo.hasVB == HASVB_LVDS_CHRONTEL))
-		if (ivideo.video_bpp == 8)   
-			sisfb_crt1off = 0;
+     DPRINTK("sisfb: Heap start:0x%p, end:0x%p, len=%dk\n",
+		(char *) sisfb_heap_start, (char *) sisfb_heap_end,
+		(unsigned int) poh->size / 1024);
 
-	if (sisfb_crt1off)	  
-		reg &= ~0x80;
-	else 	      
-		reg |= 0x80;
-	vgawb(CRTC_DATA, reg);
-	
-	vgawb(SEQ_ADR, IND_SIS_RAMDAC_CONTROL);
-	reg = vgarb(SEQ_DATA);
-	reg &= ~0x04;
-	vgawb(SEQ_DATA, reg);
-
-	if ((ivideo.disp_state & DISPTYPE_TV) && (ivideo.hasVB == HASVB_301)) {
-		/*karl*/
-		vgawb(VB_PART4_ADR,0x01);
-		reg = vgarb(VB_PART4_DATA);
-		
-	   if ((reg != 0xB1) && (reg != 0xB0)) /*301B Revision ID*/
-           {	
-		// Eden Chen
-		switch (ivideo.video_width) {
-		   case 320:
-			filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 4 : 12;
-			break;
-		   case 640:
-			filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 5 : 13;
-			break;
-		   case 720:
-			filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 6 : 14;
-			break;
-		   case 800:
-			filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 7 : 15;
-			break;
-		   default:
-			filter = -1;
-			break;
-		}
-		// ~Eden Chen
+     DPRINTK("sisfb: First Node offset:0x%x, size:%dk\n",
+		(unsigned int) poh->offset, (unsigned int) poh->size / 1024);
 
-		// Eden Chen
-		//vgawb(VB_PART1_ADR,  0x24);
-		vgawb(VB_PART1_ADR,  sisfb_CRT2_write_enable);
-		// ~Eden Chen
-		vgawb(VB_PART1_DATA, 0x1);
-		
-		// Eden Chen for Debug
-/*
-		if (ivideo.chip == SIS_550 || ivideo.chip == SIS_650) {
-			vgawb(VB_PART1_ADR,  0x2D);
-			vgawb(VB_PART1_DATA, 0x11);
-
-			if (sisfb_mode_no == 0x63) {
-				vgawb(VB_PART2_ADR,  0x15);
-				vgawb(VB_PART2_DATA, 0x0A);
-				vgawb(VB_PART2_ADR,  0x28);
-				vgawb(VB_PART2_DATA, 0x62);
-				vgawb(VB_PART2_ADR,  0x2D);
-				vgawb(VB_PART2_DATA, 0xF8);
-				vgawb(VB_PART2_ADR,  0x2E);
-				vgawb(VB_PART2_DATA, 0x14);
-				vgawb(VB_PART2_ADR,  0x33);
-				vgawb(VB_PART2_DATA, 0x8A);
-
-				vgawb(VB_PART2_ADR,  0x35);
-				vgawb(VB_PART2_DATA, 0xF4);
-				vgawb(VB_PART2_ADR,  0x36);
-				vgawb(VB_PART2_DATA, 0x10);
-				vgawb(VB_PART2_ADR,  0x37);
-				vgawb(VB_PART2_DATA, 0x1C);
-				vgawb(VB_PART2_ADR,  0x38);
-				vgawb(VB_PART2_DATA, 0x00);
-				vgawb(VB_PART2_ADR,  0x44);
-				vgawb(VB_PART2_DATA, 0x29);
-				vgawb(VB_PART2_ADR,  0x45);
-				vgawb(VB_PART2_DATA, 0x54);
-
-				vgawb(VB_PART4_ADR,  0x0D);
-				vgawb(VB_PART4_DATA, 0x0F);
-				vgawb(VB_PART4_ADR,  0x0F);
-				vgawb(VB_PART4_DATA, 0x0F);
-				vgawb(VB_PART4_ADR,  0x10);
-				vgawb(VB_PART4_DATA, 0x83);
-				vgawb(VB_PART4_ADR,  0x11);
-				vgawb(VB_PART4_DATA, 0xFF);
-				vgawb(VB_PART4_ADR,  0x18);
-				vgawb(VB_PART4_DATA, 0x20);
-				vgawb(VB_PART4_ADR,  0x19);
-				vgawb(VB_PART4_DATA, 0x52);
-			}
-		}
-*/
-		// ~Eden Chen
+     sisfb_heap.oh_free.poh_next = poh;
+     sisfb_heap.oh_free.poh_prev = poh;
+     sisfb_heap.oh_free.size = 0;
+     sisfb_heap.max_freesize = poh->size;
+
+     sisfb_heap.oh_used.poh_next = &sisfb_heap.oh_used;
+     sisfb_heap.oh_used.poh_prev = &sisfb_heap.oh_used;
+     sisfb_heap.oh_used.size = SENTINEL;
 
-		if (ivideo.TV_type == TVMODE_NTSC) {
-			vgawb(VB_PART2_ADR, 0x3A);
-			reg = vgarb(VB_PART2_DATA);
-			reg &= 0x1F;
-			vgawb(VB_PART2_DATA, reg);
+     return 0;
+}
 
-			if (ivideo.TV_plug == TVPLUG_SVIDEO) {
-				vgawb(VB_PART2_ADR, 0x30);
-				reg = vgarb(VB_PART2_DATA);
-				reg &= 0xDF;
-				vgawb(VB_PART2_DATA, reg);
-			} else if (ivideo.TV_plug == TVPLUG_COMPOSITE) {
-				vgawb(VB_PART2_ADR, 0x30);
-				reg = vgarb(VB_PART2_DATA);
-				reg |= 0x20;
-				vgawb(VB_PART2_DATA, reg);
+static SIS_OH *sisfb_poh_new_node(void)
+{
+	int           i;
+	unsigned long cOhs;
+	SIS_OHALLOC   *poha;
+	SIS_OH        *poh;
 
-				switch (ivideo.video_width) {
-				case 640:
-					vgawb(VB_PART2_ADR,  0x35);
-					vgawb(VB_PART2_DATA, 0xEB);
-					vgawb(VB_PART2_ADR,  0x36);
-					vgawb(VB_PART2_DATA, 0x04);
-					vgawb(VB_PART2_ADR,  0x37);
-					vgawb(VB_PART2_DATA, 0x25);
-					vgawb(VB_PART2_ADR,  0x38);
-					vgawb(VB_PART2_DATA, 0x18);
-					break;
-				case 720:
-					vgawb(VB_PART2_ADR,  0x35);
-					vgawb(VB_PART2_DATA, 0xEE);
-					vgawb(VB_PART2_ADR,  0x36);
-					vgawb(VB_PART2_DATA, 0x0C);
-					vgawb(VB_PART2_ADR,  0x37);
-					vgawb(VB_PART2_DATA, 0x22);
-					vgawb(VB_PART2_ADR,  0x38);
-					vgawb(VB_PART2_DATA, 0x08);
-					break;
-				case 800:
-					vgawb(VB_PART2_ADR,  0x35);
-					vgawb(VB_PART2_DATA, 0xEB);
-					vgawb(VB_PART2_ADR,  0x36);
-					vgawb(VB_PART2_DATA, 0x15);
-					vgawb(VB_PART2_ADR,  0x37);
-					vgawb(VB_PART2_DATA, 0x25);
-					vgawb(VB_PART2_ADR,  0x38);
-					vgawb(VB_PART2_DATA, 0xF6);
-					break;
-				}
-			}
-		} else if (ivideo.TV_type == TVMODE_PAL) {
-			vgawb(VB_PART2_ADR, 0x3A);
-			reg = vgarb(VB_PART2_DATA);
-			reg &= 0x1F;
-			vgawb(VB_PART2_DATA, reg);
+	if (sisfb_heap.poh_freelist == NULL) {
+		poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL);
+		if(!poha) return NULL;
 
-			if (ivideo.TV_plug == TVPLUG_SVIDEO) {
-				vgawb(VB_PART2_ADR, 0x30);
-				reg = vgarb(VB_PART2_DATA);
-				reg &= 0xDF;
-				vgawb(VB_PART2_DATA, reg);
-			} else if (ivideo.TV_plug == TVPLUG_COMPOSITE) {
-				vgawb(VB_PART2_ADR, 0x30);
-				reg = vgarb(VB_PART2_DATA);
-				reg |= 0x20;
-				vgawb(VB_PART2_DATA, reg);
+		poha->poha_next = sisfb_heap.poha_chain;
+		sisfb_heap.poha_chain = poha;
 
-				switch (ivideo.video_width) {
-				case 640:
-					vgawb(VB_PART2_ADR,  0x35);
-					vgawb(VB_PART2_DATA, 0xF1);
-					vgawb(VB_PART2_ADR,  0x36);
-					vgawb(VB_PART2_DATA, 0xF7);
-					vgawb(VB_PART2_ADR,  0x37);
-					vgawb(VB_PART2_DATA, 0x1F);
-					vgawb(VB_PART2_ADR,  0x38);
-					vgawb(VB_PART2_DATA, 0x32);
-					break;
-				case 720:
-					vgawb(VB_PART2_ADR,  0x35);
-					vgawb(VB_PART2_DATA, 0xF3);
-					vgawb(VB_PART2_ADR,  0x36);
-					vgawb(VB_PART2_DATA, 0x00);
-					vgawb(VB_PART2_ADR,  0x37);
-					vgawb(VB_PART2_DATA, 0x1D);
-					vgawb(VB_PART2_ADR,  0x38);
-					vgawb(VB_PART2_DATA, 0x20);
-					break;
-				case 800:
-					vgawb(VB_PART2_ADR,  0x35);
-					vgawb(VB_PART2_DATA, 0xFC);
-					vgawb(VB_PART2_ADR,  0x36);
-					vgawb(VB_PART2_DATA, 0xFB);
-					vgawb(VB_PART2_ADR,  0x37);
-					vgawb(VB_PART2_DATA, 0x14);
-					vgawb(VB_PART2_ADR,  0x38);
-					vgawb(VB_PART2_DATA, 0x2A);
-					break;
-				}
-			}
-		}
+		cOhs = (OH_ALLOC_SIZE - sizeof(SIS_OHALLOC)) / sizeof(SIS_OH) + 1;
 
-		// Eden 
-		if ((filter >= 0) && (filter <=7)) {
-			DPRINTK("FilterTable[%d]-%d: %02x %02x %02x %02x\n", filter_tb, filter, 
-				sis_TV_filter[filter_tb].filter[filter][0],
-				sis_TV_filter[filter_tb].filter[filter][1],
-				sis_TV_filter[filter_tb].filter[filter][2],
-				sis_TV_filter[filter_tb].filter[filter][3]
-			);
-			vgawb(VB_PART2_ADR,  0x35);
-			vgawb(VB_PART2_DATA, sis_TV_filter[filter_tb].filter[filter][0]);
-			vgawb(VB_PART2_ADR,  0x36);
-			vgawb(VB_PART2_DATA, sis_TV_filter[filter_tb].filter[filter][1]);
-			vgawb(VB_PART2_ADR,  0x37);
-			vgawb(VB_PART2_DATA, sis_TV_filter[filter_tb].filter[filter][2]);
-			vgawb(VB_PART2_ADR,  0x38);
-			vgawb(VB_PART2_DATA, sis_TV_filter[filter_tb].filter[filter][3]);
+		poh = &poha->aoh[0];
+		for (i = cOhs - 1; i != 0; i--) {
+			poh->poh_next = poh + 1;
+			poh = poh + 1;
 		}
-		// ~Eden 
-	     } /*karl:endif (reg != 0xB1)*/
-	  
+
+		poh->poh_next = NULL;
+		sisfb_heap.poh_freelist = &poha->aoh[0];
 	}
 
+	poh = sisfb_heap.poh_freelist;
+	sisfb_heap.poh_freelist = poh->poh_next;
+
+	return (poh);
 }
 
-static void sisfb_crtc_to_var(struct fb_var_screeninfo *var)
+static SIS_OH *sisfb_poh_allocate(unsigned long size)
 {
-	u16 VRE, VBE, VRS, VBS, VDE, VT;
-	u16 HRE, HBE, HRS, HBS, HDE, HT;
-	u8  sr_data, cr_data, cr_data2, cr_data3, mr_data;
-	int A, B, C, D, E, F, temp;
-	double hrate, drate;
+	SIS_OH *pohThis;
+	SIS_OH *pohRoot;
+	int     bAllocated = 0;
 
-	vgawb(SEQ_ADR, IND_SIS_COLOR_MODE);
-	sr_data = vgarb(SEQ_DATA);
+	if (size > sisfb_heap.max_freesize) {
+		DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
+			(unsigned int) size / 1024);
+		return (NULL);
+	}
 
-	if (sr_data & SIS_INTERLACED_MODE)
-		var->vmode = FB_VMODE_INTERLACED;
-	else
-		var->vmode = FB_VMODE_NONINTERLACED;
+	pohThis = sisfb_heap.oh_free.poh_next;
 
-	switch ((sr_data & 0x1C) >> 2) {
-	   case SIS_8BPP_COLOR_MODE:
-		var->bits_per_pixel = 8;
-		break;
-	   case SIS_16BPP_COLOR_MODE:
-		var->bits_per_pixel = 16;
-		break;
-	   case SIS_32BPP_COLOR_MODE:
-		var->bits_per_pixel = 32;
-		break;
+	while (pohThis != &sisfb_heap.oh_free) {
+		if (size <= pohThis->size) {
+			bAllocated = 1;
+			break;
+		}
+		pohThis = pohThis->poh_next;
 	}
 
-	switch (var->bits_per_pixel) {
-	   case 8:
-		var->red.length = 6;
-		var->green.length = 6;
-		var->blue.length = 6;
-		video_cmap_len = 256;
-		break;
-	   case 16:
-		var->red.offset = 11;
-		var->red.length = 5;
-		var->green.offset = 5;
-		var->green.length = 6;
-		var->blue.offset = 0;
-		var->blue.length = 5;
-		var->transp.offset = 0;
-		var->transp.length = 0;
-		video_cmap_len = 16;
-		break;
-	   case 24:
-		var->red.offset = 16;
-		var->red.length = 8;
-		var->green.offset = 8;
-		var->green.length = 8;
-		var->blue.offset = 0;
-		var->blue.length = 8;
-		var->transp.offset = 0;
-		var->transp.length = 0;
-		video_cmap_len = 16;
-		break;
-	   case 32:
-		var->red.offset = 16;
-		var->red.length = 8;
-		var->green.offset = 8;
-		var->green.length = 8;
-		var->blue.offset = 0;
-		var->blue.length = 8;
-		var->transp.offset = 24;
-		var->transp.length = 8;
-		video_cmap_len = 16;
-		break;
+	if (!bAllocated) {
+		DPRINTK("sisfb: Can't allocate %dk size on offscreen\n",
+			(unsigned int) size / 1024);
+		return (NULL);
 	}
 
-	vgawb(SEQ_ADR, 0xA);
-	sr_data = vgarb(SEQ_DATA);
+	if (size == pohThis->size) {
+		pohRoot = pohThis;
+		sisfb_delete_node(pohThis);
+	} else {
+		pohRoot = sisfb_poh_new_node();
 
-	vgawb(CRTC_ADR, 0x6);
-	cr_data = vgarb(CRTC_DATA);
-	vgawb(CRTC_ADR, 0x7);
-	cr_data2 = vgarb(CRTC_DATA);
-	VT = (cr_data & 0xFF) | ((u16) (cr_data2 & 0x01) << 8) |
-	     ((u16) (cr_data2 & 0x20) << 4) | ((u16) (sr_data & 0x01) <<
-					      10);
-	A = VT + 2;
+		if (pohRoot == NULL) {
+			return (NULL);
+		}
 
-	vgawb(CRTC_ADR, 0x12);
-	cr_data = vgarb(CRTC_DATA);
-	VDE = (cr_data & 0xff) | ((u16) (cr_data2 & 0x02) << 7) |
-	      ((u16) (cr_data2 & 0x40) << 3) | ((u16) (sr_data & 0x02) << 9);
-	E = VDE + 1;
+		pohRoot->offset = pohThis->offset;
+		pohRoot->size = size;
 
-	vgawb(CRTC_ADR, 0x10);
-	cr_data = vgarb(CRTC_DATA);
-	VRS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x04) << 6) |
-	      ((u16) (cr_data2 & 0x80) << 2) | ((u16) (sr_data & 0x08) << 7);
-	F = VRS + 1 - E;
+		pohThis->offset += size;
+		pohThis->size -= size;
+	}
 
-	vgawb(CRTC_ADR, 0x15);
-	cr_data = vgarb(CRTC_DATA);
-	vgawb(CRTC_ADR, 0x9);
-	cr_data3 = vgarb(CRTC_DATA);
-	VBS = (cr_data & 0xff) | ((u16) (cr_data2 & 0x08) << 5) |
-	      ((u16) (cr_data3 & 0x20) << 4) | ((u16) (sr_data & 0x04) << 8);
+	sisfb_heap.max_freesize -= size;
 
-	vgawb(CRTC_ADR, 0x16);
-	cr_data = vgarb(CRTC_DATA);
-	VBE = (cr_data & 0xff) | ((u16) (sr_data & 0x10) << 4);
-	temp = VBE - ((E - 1) & 511);
-	B = (temp > 0) ? temp : (temp + 512);
+	pohThis = &sisfb_heap.oh_used;
+	sisfb_insert_node(pohThis, pohRoot);
 
-	vgawb(CRTC_ADR, 0x11);
-	cr_data = vgarb(CRTC_DATA);
-	VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
-	temp = VRE - ((E + F - 1) & 31);
-	C = (temp > 0) ? temp : (temp + 32);
+	return (pohRoot);
+}
 
-	D = B - F - C;
+static void sisfb_delete_node(SIS_OH *poh)
+{
+	SIS_OH *poh_prev;
+	SIS_OH *poh_next;
 
-	var->yres = var->yres_virtual = E;
-	/* TW: We have to report the physical dimension to the console! */
-	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
-		var->yres <<= 1;
-		var->yres_virtual <<=1;
-	}
-	/* TW end */
-	var->upper_margin = D;
-	var->lower_margin = F;
-	var->vsync_len = C;
+	poh_prev = poh->poh_prev;
+	poh_next = poh->poh_next;
 
-	vgawb(SEQ_ADR, 0xb);
-	sr_data = vgarb(SEQ_DATA);
+	poh_prev->poh_next = poh_next;
+	poh_next->poh_prev = poh_prev;
 
-	vgawb(CRTC_ADR, 0x0);
-	cr_data = vgarb(CRTC_DATA);
-	HT = (cr_data & 0xff) | ((u16) (sr_data & 0x03) << 8);
-	A = HT + 5;
+}
 
-	vgawb(CRTC_ADR, 0x1);
-	cr_data = vgarb(CRTC_DATA);
-	HDE = (cr_data & 0xff) | ((u16) (sr_data & 0x0C) << 6);
-	E = HDE + 1;
+static void sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh)
+{
+	SIS_OH *pohTemp;
 
-	vgawb(CRTC_ADR, 0x4);
-	cr_data = vgarb(CRTC_DATA);
-	HRS = (cr_data & 0xff) | ((u16) (sr_data & 0xC0) << 2);
-	F = HRS - E - 3;
+	pohTemp = pohList->poh_next;
 
-	vgawb(CRTC_ADR, 0x2);
-	cr_data = vgarb(CRTC_DATA);
-	HBS = (cr_data & 0xff) | ((u16) (sr_data & 0x30) << 4);
+	pohList->poh_next = poh;
+	pohTemp->poh_prev = poh;
 
-	vgawb(SEQ_ADR, 0xc);
-	sr_data = vgarb(SEQ_DATA);
-	vgawb(CRTC_ADR, 0x3);
-	cr_data = vgarb(CRTC_DATA);
-	vgawb(CRTC_ADR, 0x5);
-	cr_data2 = vgarb(CRTC_DATA);
-	HBE = (cr_data & 0x1f) | ((u16) (cr_data2 & 0x80) >> 2) |
-	      ((u16) (sr_data & 0x03) << 6);
-	HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
+	poh->poh_prev = pohList;
+	poh->poh_next = pohTemp;
+}
 
-	temp = HBE - ((E - 1) & 255);
-	B = (temp > 0) ? temp : (temp + 256);
+static SIS_OH *sisfb_poh_free(unsigned long base)
+{
+	SIS_OH *pohThis;
+	SIS_OH *poh_freed;
+	SIS_OH *poh_prev;
+	SIS_OH *poh_next;
+	unsigned long ulUpper;
+	unsigned long ulLower;
+	int foundNode = 0;
 
-	temp = HRE - ((E + F + 3) & 63);
-	C = (temp > 0) ? temp : (temp + 64);
+	poh_freed = sisfb_heap.oh_used.poh_next;
 
-	D = B - F - C;
+	while(poh_freed != &sisfb_heap.oh_used) {
+		if(poh_freed->offset == base) {
+			foundNode = 1;
+			break;
+		}
 
-	var->xres = var->xres_virtual = E * 8;
-	var->left_margin = D * 8;
-	var->right_margin = F * 8;
-	var->hsync_len = C * 8;
+		poh_freed = poh_freed->poh_next;
+	}
 
-	var->activate = FB_ACTIVATE_NOW;
+	if (!foundNode)  return (NULL);
 
-	var->sync = 0;
+	sisfb_heap.max_freesize += poh_freed->size;
 
-	mr_data = vgarb(0x1C);
-	if (mr_data & 0x80)
-		var->sync &= ~FB_SYNC_VERT_HIGH_ACT;
-	else
-		var->sync |= FB_SYNC_VERT_HIGH_ACT;
+	poh_prev = poh_next = NULL;
+	ulUpper = poh_freed->offset + poh_freed->size;
+	ulLower = poh_freed->offset;
 
-	if (mr_data & 0x40)
-		var->sync &= ~FB_SYNC_HOR_HIGH_ACT;
-	else
-		var->sync |= FB_SYNC_HOR_HIGH_ACT;
+	pohThis = sisfb_heap.oh_free.poh_next;
 
-	VT += 2;
-	VT <<= 1;
-	HT = (HT + 5) * 8;
+	while (pohThis != &sisfb_heap.oh_free) {
+		if (pohThis->offset == ulUpper) {
+			poh_next = pohThis;
+		}
+			else if ((pohThis->offset + pohThis->size) ==
+				 ulLower) {
+			poh_prev = pohThis;
+		}
+		pohThis = pohThis->poh_next;
+	}
 
-	hrate = (double) ivideo.refresh_rate * (double) VT / 2;
-	drate = hrate * HT;
-	var->pixclock = (u32) (1E12 / drate);
-}
+	sisfb_delete_node(poh_freed);
 
-/* ------------------ Public Routines -------------------------------- */
+	if (poh_prev && poh_next) {
+		poh_prev->size += (poh_freed->size + poh_next->size);
+		sisfb_delete_node(poh_next);
+		sisfb_free_node(poh_freed);
+		sisfb_free_node(poh_next);
+		return (poh_prev);
+	}
 
-static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info)
-{
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-	strcpy(fix->id, fb_info.modename);
+	if (poh_prev) {
+		poh_prev->size += poh_freed->size;
+		sisfb_free_node(poh_freed);
+		return (poh_prev);
+	}
 
-	fix->smem_start = ivideo.video_base;
-        
-        /*karl:10/01/2001*/ /* TW */
-        if ((!sisfb_mem) || (sisfb_mem > (ivideo.video_size/1024))) {
-	    if (ivideo.video_size > 0x800000)
-		fix->smem_len = 0x800000;
-	    else
-		fix->smem_len = 0x400000;
-        } else
-		fix->smem_len = sisfb_mem * 1024;
+	if (poh_next) {
+		poh_next->size += poh_freed->size;
+		poh_next->offset = poh_freed->offset;
+		sisfb_free_node(poh_freed);
+		return (poh_next);
+	}
 
-	fix->type = video_type;
-	fix->type_aux = 0;
-	if (ivideo.video_bpp == 8)
-		fix->visual = FB_VISUAL_PSEUDOCOLOR;
-	else
-		fix->visual = FB_VISUAL_TRUECOLOR;
-	fix->xpanstep = 0;
-	fix->ypanstep = 0;
-	fix->ywrapstep = 0;
-	fix->line_length = video_linelength;
-	fix->mmio_start = ivideo.mmio_base;
-	fix->mmio_len = sisfb_mmio_size;
-	fix->accel = FB_ACCEL_SIS_GLAMOUR;
-	fix->reserved[0] = ivideo.video_size & 0xFFFF;
-	fix->reserved[1] = (ivideo.video_size >> 16) & 0xFFFF;
-	fix->reserved[2] = sisfb_caps;	
+	sisfb_insert_node(&sisfb_heap.oh_free, poh_freed);
 
-	return 0;
+	return (poh_freed);
 }
 
-static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
+static void sisfb_free_node(SIS_OH *poh)
 {
-	if (con == -1)
-		memcpy(var, &default_var, sizeof(struct fb_var_screeninfo));
-	else
-		*var = fb_display[con].var;
+	if(poh == NULL) return;
 
-	/* JennyLee 2001126: for FSTN */
-	if (var->xres == 320 && var->yres == 480)
-		var->yres = 240;
-	/* ~JennyLee */
+	poh->poh_next = sisfb_heap.poh_freelist;
+	sisfb_heap.poh_freelist = poh;
 
-	return 0;
 }
 
-static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
+void sis_malloc(struct sis_memreq *req)
 {
-	int err;
-	unsigned int cols, rows;
-
-	fb_display[con].var.activate = FB_ACTIVATE_NOW;
-	if (sisfb_do_set_var(var, con == currcon, info)) {
-		sisfb_crtc_to_var(var);	
-		return -EINVAL;
-	}
-	
-	sisfb_crtc_to_var(var);
-	
-	sisfb_set_disp(con, var);
+	SIS_OH *poh;
 
-	if (info->changevar)
-		(*info->changevar) (con);
+	poh = sisfb_poh_allocate(req->size);
 
-	if ((err = fb_alloc_cmap(&fb_display[con].cmap, 0, 0)))
-		return err;
+	if(poh == NULL) {
+		req->offset = 0;
+		req->size = 0;
+		DPRINTK("sisfb: Video RAM allocation failed\n");
+	} else {
+		DPRINTK("sisfb: Video RAM allocation succeeded: 0x%p\n",
+			(char *) (poh->offset + (unsigned long) ivideo.video_vbase));
 
-	sisfb_do_install_cmap(con, info);
-	
-	cols = sisbios_mode[sisfb_mode_idx].cols;
-	rows = sisbios_mode[sisfb_mode_idx].rows;
-	vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
+		req->offset = poh->offset;
+		req->size = poh->size;
+	}
 
-	return 0;
 }
 
-static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info)
+void sis_free(unsigned long base)
 {
-	if (con == currcon)
-		return fb_get_cmap(cmap, kspc, sis_getcolreg, info);
-	else if (fb_display[con].cmap.len)	
-		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-	else
-		fb_copy_cmap(fb_default_cmap(video_cmap_len), cmap, kspc ? 0 : 2);
-
-	return 0;
-}
+	SIS_OH *poh;
 
-static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info)
-{
-	int err;
+	poh = sisfb_poh_free(base);
 
-	if (!fb_display[con].cmap.len) {	
-		err = fb_alloc_cmap(&fb_display[con].cmap, video_cmap_len, 0);
-		if (err)
-			return err;
+	if(poh == NULL) {
+		DPRINTK("sisfb: sisfb_poh_free() failed at base 0x%x\n",
+			(unsigned int) base);
 	}
-	if (con == currcon)	
-		return fb_set_cmap(cmap, kspc, sis_setcolreg, info);
-	else
-		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
-	return 0;
 }
 
-static int sisfb_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, unsigned long arg, int con,
-		       struct fb_info *info)
+/* ------------------ SetMode Routines ------------------------------- */
+
+static void sisfb_pre_setmode(void)
 {
-	switch (cmd) {
-	   case FBIO_ALLOC:
-		if (!capable(CAP_SYS_RAWIO))
-			return -EPERM;
-		sis_malloc((struct sis_memreq *) arg);
-		break;
-	   case FBIO_FREE:
-		if (!capable(CAP_SYS_RAWIO))
-			return -EPERM;
-		sis_free(*(unsigned long *) arg);
+	u8 cr30 = 0, cr31 = 0;
+
+	inSISIDXREG(SISCR, 0x31, cr31);
+	cr31 &= ~0x60;
+
+	switch (ivideo.disp_state & DISPTYPE_DISP2) {
+	   case DISPTYPE_CRT2:
+		printk(KERN_INFO "sisfb: CRT2 type is VGA\n");
+		cr30 = (SIS_VB_OUTPUT_CRT2 | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		cr31 |= SIS_DRIVER_MODE;
 		break;
-	   case FBIOGET_GLYPH:
-		sis_get_glyph((SIS_GLYINFO *) arg);
+	   case DISPTYPE_LCD:
+		printk(KERN_INFO "sisfb: CRT2 type is LCD\n");
+		cr30  = (SIS_VB_OUTPUT_LCD | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		cr31 |= SIS_DRIVER_MODE;
 		break;
-	   case FBIOGET_HWCINFO:
-		{
-			unsigned long *hwc_offset = (unsigned long *) arg;
-
-			if (sisfb_caps & HW_CURSOR_CAP)
-				*hwc_offset = sisfb_hwcursor_vbase -
-				    (unsigned long) ivideo.video_vbase;
-			else
-				*hwc_offset = 0;
+	   case DISPTYPE_TV:
+		printk(KERN_INFO "sisfb: CRT2 type is TV\n");
+		if (ivideo.TV_type == TVMODE_HIVISION)
+			cr30 = (SIS_VB_OUTPUT_HIVISION | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		else if (ivideo.TV_plug == TVPLUG_SVIDEO)
+			cr30 = (SIS_VB_OUTPUT_SVIDEO | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		else if (ivideo.TV_plug == TVPLUG_COMPOSITE)
+			cr30 = (SIS_VB_OUTPUT_COMPOSITE | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		else if (ivideo.TV_plug == TVPLUG_SCART)
+			cr30 = (SIS_VB_OUTPUT_SCART | SIS_SIMULTANEOUS_VIEW_ENABLE);
+		cr31 |= SIS_DRIVER_MODE;
 
-			break;
-		}
-	   case FBIOPUT_MODEINFO:
-		{
-			struct mode_info *x = (struct mode_info *)arg;
-			
-			ivideo.video_bpp      = x->bpp;
-			ivideo.video_width    = x->xres;
-			ivideo.video_height   = x->yres;
-			ivideo.video_vwidth   = x->v_xres;
-			ivideo.video_vheight  = x->v_yres;
-			ivideo.org_x          = x->org_x;
-			ivideo.org_y          = x->org_y;
-			ivideo.refresh_rate   = x->vrate;
-			
-			break;
-		}
-	   case FBIOGET_DISPINFO:
-		sis_dispinfo((struct ap_data *)arg);
+	        if (sisfb_tvmode == 1 || ivideo.TV_type == TVMODE_PAL)
+			cr31 |= 0x01;
+                else   /* if (sisfb_tvmode == 2 || ivideo.TV_type == TVMODE_NTSC) - nonsense */
+                        cr31 &= ~0x01;
 		break;
-	   default:
-		return -EINVAL;
+	   default:	/* CRT2 disable */
+		printk(KERN_INFO "sisfb: CRT2 is disabled\n");
+		cr30 = 0x00;
+		cr31 |= (SIS_DRIVER_MODE | SIS_VB_OUTPUT_DISABLE);
 	}
-	return 0;
+
+	outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR30, cr30);
+	outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR31, cr31);
+
+        outSISIDXREG(SISCR, IND_SIS_SCRATCH_REG_CR33, (sisfb_rate_idx & 0x0F));
 
 }
 
-static int sisfb_mmap(struct fb_info *info, struct file *file,
-		      struct vm_area_struct *vma)
+static void sisfb_post_setmode(void)
 {
-	struct fb_var_screeninfo var;
-	unsigned long start;
-	unsigned long off;
-	u32 len;
+	u8 reg;
+	BOOLEAN doit = TRUE;
+
+	/* TW: We can't switch off CRT1 on LVDS/Chrontel in 8bpp Modes */
+	if ((ivideo.hasVB == HASVB_LVDS) || (ivideo.hasVB == HASVB_LVDS_CHRONTEL)) {
+		if (ivideo.video_bpp == 8) {
+			doit = FALSE;
+		}
+	}
+
+	/* TW: We can't switch off CRT1 on 630+301B in 8bpp Modes */
+	if ( (sishw_ext.ujVBChipID == VB_CHIP_301B) && (sisvga_engine == SIS_300_VGA) &&
+	     (ivideo.disp_state & DISPTYPE_LCD) ) {
+	        if (ivideo.video_bpp == 8) {
+			doit = FALSE;
+	        }
+	}
+
+	/* TW: We can't switch off CRT1 if bridge is in slave mode */
+	if(ivideo.hasVB != HASVB_NONE) {
+		inSISIDXREG(SISPART1, 0x00, reg);
+		if(sisvga_engine == SIS_300_VGA) {
+			if((reg & 0xa0) == 0x20) {
+				doit = FALSE;
+			}
+		}
+		if(sisvga_engine == SIS_315_VGA) {
+			if((reg & 0x50) == 0x10) {
+				doit = FALSE;
+			}
+		}
+	} else sisfb_crt1off = 0;
 
-	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
-		return -EINVAL;
-	off = vma->vm_pgoff << PAGE_SHIFT;
-	
-	start = (unsigned long) ivideo.video_base;
-	len = PAGE_ALIGN((start & ~PAGE_MASK) + ivideo.video_size);
+	inSISIDXREG(SISCR, 0x17, reg);
+	if((sisfb_crt1off) && (doit))
+		reg &= ~0x80;
+	else 	      
+		reg |= 0x80;
+	outSISIDXREG(SISCR, 0x17, reg);
 
-	if (off >= len) {
-		off -= len;
-		sisfb_get_var(&var, currcon, info);
-		if (var.accel_flags)
-			return -EINVAL;
-		start = (unsigned long) ivideo.mmio_base;
-		len = PAGE_ALIGN((start & ~PAGE_MASK) + sisfb_mmio_size);
-	}
+        andSISIDXREG(SISSR, IND_SIS_RAMDAC_CONTROL, ~0x04);
 
-	start &= PAGE_MASK;
-	if ((vma->vm_end - vma->vm_start + off) > len)
-		return -EINVAL;
-	off += start;
-	vma->vm_pgoff = off >> PAGE_SHIFT;
+	if((ivideo.disp_state & DISPTYPE_TV) && (ivideo.hasVB == HASVB_301)) {
 
-#if defined(__i386__)
-	if (boot_cpu_data.x86 > 3)
-		pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	if (io_remap_page_range(vma->vm_start, off, vma->vm_end - vma->vm_start,
-				vma->vm_page_prot))
-#else	/* TW: 2.5 API */
-	if (io_remap_page_range(vma, vma->vm_start, off, vma->vm_end - vma->vm_start,
-				vma->vm_page_prot))
-#endif
-		return -EAGAIN;
-	return 0;
+	   inSISIDXREG(SISPART4, 0x01, reg);
 
-}
+	   if(reg < 0xB0) {        	/* Set filter for SiS301 */
 
-static struct fb_ops sisfb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	sisfb_get_fix,
-	fb_get_var:	sisfb_get_var,
-	fb_set_var:	sisfb_set_var,
-	fb_get_cmap:	sisfb_get_cmap,
-	fb_set_cmap:	sisfb_set_cmap,
-	fb_ioctl:	sisfb_ioctl,
-	fb_mmap:	sisfb_mmap,
-};
+		switch (ivideo.video_width) {
+		   case 320:
+			filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 4 : 12;
+			break;
+		   case 640:
+			filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 5 : 13;
+			break;
+		   case 720:
+			filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 6 : 14;
+			break;
+		   case 800:
+			filter_tb = (ivideo.TV_type == TVMODE_NTSC) ? 7 : 15;
+			break;
+		   default:
+			filter = -1;
+			break;
+		}
 
-/* ------------ Interface to the low level console driver -------------*/
+		orSISIDXREG(SISPART1, sisfb_CRT2_write_enable, 0x01);
 
-static int sisfb_update_var(int con, struct fb_info *info)
-{
-	return 0;
-}
+		if(ivideo.TV_type == TVMODE_NTSC) {
 
-static int sisfb_switch(int con, struct fb_info *info)
-{
-	int cols, rows;
+		        andSISIDXREG(SISPART2, 0x3a, 0x1f);
 
-	if (fb_display[currcon].cmap.len)
-		fb_get_cmap(&fb_display[currcon].cmap, 1, sis_getcolreg, info);
+			if (ivideo.TV_plug == TVPLUG_SVIDEO) {
 
-	fb_display[con].var.activate = FB_ACTIVATE_NOW;
+			        andSISIDXREG(SISPART2, 0x30, 0xdf);
 
-	if (!memcmp(&fb_display[con].var, &fb_display[currcon].var,
-	                           sizeof(struct fb_var_screeninfo))) {
-		currcon = con;
-		return 1;
-	}
+			} else if (ivideo.TV_plug == TVPLUG_COMPOSITE) {
 
-	currcon = con;
+			        orSISIDXREG(SISPART2, 0x30, 0x20);
 
-	sisfb_do_set_var(&fb_display[con].var, 1, info);
+				switch (ivideo.video_width) {
+				case 640:
+				        outSISIDXREG(SISPART2, 0x35, 0xEB);
+					outSISIDXREG(SISPART2, 0x36, 0x04);
+					outSISIDXREG(SISPART2, 0x37, 0x25);
+					outSISIDXREG(SISPART2, 0x38, 0x18);
+					break;
+				case 720:
+					outSISIDXREG(SISPART2, 0x35, 0xEE);
+					outSISIDXREG(SISPART2, 0x36, 0x0C);
+					outSISIDXREG(SISPART2, 0x37, 0x22);
+					outSISIDXREG(SISPART2, 0x38, 0x08);
+					break;
+				case 800:
+					outSISIDXREG(SISPART2, 0x35, 0xEB);
+					outSISIDXREG(SISPART2, 0x36, 0x15);
+					outSISIDXREG(SISPART2, 0x37, 0x25);
+					outSISIDXREG(SISPART2, 0x38, 0xF6);
+					break;
+				}
+			}
 
-	sisfb_set_disp(con, &fb_display[con].var);
-	
-	sisfb_do_install_cmap(con, info);
+		} else if(ivideo.TV_type == TVMODE_PAL) {
 
-	cols = sisbios_mode[sisfb_mode_idx].cols;
-	rows = sisbios_mode[sisfb_mode_idx].rows;
-	vc_resize_con(rows, cols, fb_display[con].conp->vc_num);
+			andSISIDXREG(SISPART2, 0x3A, 0x1F);
 
-	sisfb_update_var(con, info);
+			if (ivideo.TV_plug == TVPLUG_SVIDEO) {
 
-	return 1;
-}
+			        andSISIDXREG(SISPART2, 0x30, 0xDF);
 
-static void sisfb_blank(int blank, struct fb_info *info)
-{
-	u8 reg;
+			} else if (ivideo.TV_plug == TVPLUG_COMPOSITE) {
 
-	vgawb(CRTC_ADR, 0x17);
-	reg = vgarb(CRTC_DATA);
+			        orSISIDXREG(SISPART2, 0x30, 0x20);
 
-	if (blank > 0)		
-		reg &= 0x7f;
-	else			
-		reg |= 0x80;
+				switch (ivideo.video_width) {
+				case 640:
+					outSISIDXREG(SISPART2, 0x35, 0xF1);
+					outSISIDXREG(SISPART2, 0x36, 0xF7);
+					outSISIDXREG(SISPART2, 0x37, 0x1F);
+					outSISIDXREG(SISPART2, 0x38, 0x32);
+					break;
+				case 720:
+					outSISIDXREG(SISPART2, 0x35, 0xF3);
+					outSISIDXREG(SISPART2, 0x36, 0x00);
+					outSISIDXREG(SISPART2, 0x37, 0x1D);
+					outSISIDXREG(SISPART2, 0x38, 0x20);
+					break;
+				case 800:
+					outSISIDXREG(SISPART2, 0x35, 0xFC);
+					outSISIDXREG(SISPART2, 0x36, 0xFB);
+					outSISIDXREG(SISPART2, 0x37, 0x14);
+					outSISIDXREG(SISPART2, 0x38, 0x2A);
+					break;
+				}
+			}
+		}
+
+		if ((filter >= 0) && (filter <=7)) {
+			DPRINTK("FilterTable[%d]-%d: %02x %02x %02x %02x\n", filter_tb, filter, 
+				sis_TV_filter[filter_tb].filter[filter][0],
+				sis_TV_filter[filter_tb].filter[filter][1],
+				sis_TV_filter[filter_tb].filter[filter][2],
+				sis_TV_filter[filter_tb].filter[filter][3]
+			);
+			outSISIDXREG(SISPART2, 0x35, (sis_TV_filter[filter_tb].filter[filter][0]));
+			outSISIDXREG(SISPART2, 0x36, (sis_TV_filter[filter_tb].filter[filter][1]));
+			outSISIDXREG(SISPART2, 0x37, (sis_TV_filter[filter_tb].filter[filter][2]));
+			outSISIDXREG(SISPART2, 0x38, (sis_TV_filter[filter_tb].filter[filter][3]));
+		}
+
+	     }
+	  
+	}
 
-	vgawb(CRTC_ADR, 0x17);
-	vgawb(CRTC_DATA, reg);
 }
 
+#ifndef MODULE
 int sisfb_setup(char *options)
 {
 	char *this_opt;
 
-	fb_info.fontname[0] = '\0';
+	sis_fb_info.fontname[0] = '\0';
 	ivideo.refresh_rate = 0;
 
+        printk(KERN_INFO "sisfb: Options %s\n", options);
+
 	if (!options || !*options)
 		return 0;
 
-#if 0	/* TW (Alex Tribble): Change for 2.5 series */
-	for (this_opt = strtok(options, ","); this_opt;
-	     this_opt = strtok(NULL, ",")) {
-#endif
-	while((this_opt = strsep(&options, ","))) {
-		if (!*this_opt)
-			continue;
+	while((this_opt = strsep(&options, ",")) != NULL) {
+
+		if (!*this_opt)	continue;
 
 		if (!strcmp(this_opt, "inverse")) {
 			sisfb_inverse = 1;
-			fb_invert_cmaps();
+			/* fb_invert_cmaps(); */
 		} else if (!strncmp(this_opt, "font:", 5)) {
-			strcpy(fb_info.fontname, this_opt + 5);
+			strcpy(sis_fb_info.fontname, this_opt + 5);
 		} else if (!strncmp(this_opt, "mode:", 5)) {
 			sisfb_search_mode(this_opt + 5);
+		} else if (!strncmp(this_opt, "vesa:", 5)) {
+			sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0));
 		} else if (!strncmp(this_opt, "vrate:", 6)) {
 			ivideo.refresh_rate =
 			    simple_strtoul(this_opt + 6, NULL, 0);
@@ -2619,42 +3128,60 @@
 			sisfb_search_crt2type(this_opt + 14);
 		} else if (!strncmp(this_opt, "forcecrt1:", 10)) {
 			sisfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
-                  /*karl*/
                 } else if (!strncmp(this_opt, "tvmode:",7)) {
                         if (!strncmp(this_opt + 7, "pal",3))
                          	sisfb_tvmode = 1;
                         if (!strncmp(this_opt + 7, "ntsc",4))
                          	sisfb_tvmode = 2;
-                }
-                 /*karl:10/01/2001*/ 
-                else if (!strncmp(this_opt, "mem:",4)) {
+                } else if (!strncmp(this_opt, "tvstandard:",11)) {
+                        if (!strncmp(this_opt + 11, "pal",3))
+                         	sisfb_tvmode = 1;
+                        else if (!strncmp(this_opt + 11, "ntsc",4))
+                         	sisfb_tvmode = 2;
+                }else if (!strncmp(this_opt, "mem:",4)) {
 		        sisfb_mem = simple_strtoul(this_opt + 4, NULL, 0);
-                }
-		/* JennyLee 20011211 */
-		else if (!strncmp(this_opt, "dstn:", 5)) {
-			enable_dstn = simple_strtoul(this_opt + 5, NULL, 0);
-		}
-		/* ~JennyLee 20011211 */
-		else if (!strncmp(this_opt, "queuemode:", 10)) {
+                } else if (!strncmp(this_opt, "dstn", 4)) {
+			enable_dstn = 1;
+			/* TW: DSTN overrules forcecrt2type */
+			sisfb_crt2type = DISPTYPE_LCD;
+		} else if (!strncmp(this_opt, "queuemode:", 10)) {
 			sisfb_search_queuemode(this_opt + 10);
+		} else if (!strncmp(this_opt, "pdc:", 4)) {
+		        sisfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
+		        if(sisfb_pdc & ~0x3c) {
+			   printk(KERN_INFO "sisfb: Illegal pdc parameter\n");
+			   sisfb_pdc = 0;
+		        }
+		} else if (!strncmp(this_opt, "noaccel", 7)) {
+			sisfb_accel = 0;
+		} else if (!strncmp(this_opt, "noypan", 6)) {
+		        sisfb_ypan = 0;
+		} else {
+			printk(KERN_INFO "sisfb: Invalid parameter %s\n", this_opt);
 		}
 
-		else
-			printk(KERN_INFO "sisfb: Invalid parameter %s\n", this_opt);
+		/* TW: Acceleration only with MMIO mode */
+		if((sisfb_queuemode != -1) && (sisfb_queuemode != MMIO_CMD)) {
+			sisfb_ypan = 0;
+			sisfb_accel = 0;
+		}
+		/* TW: Panning only with acceleration */
+		if(sisfb_accel == 0) sisfb_ypan = 0;
+
 	}
 	return 0;
 }
+#endif
 
 int __init sisfb_init(void)
 {
 	struct pci_dev *pdev = NULL;
 	struct board *b;
 	int pdev_valid = 0;
-	//unsigned long rom_vbase;
+	/* unsigned long rom_vbase;  */
 	u32 reg32;
 	u16 reg16;
 	u8  reg;
-	int temp1, temp2;
 
 	outb(0x77, 0x80);
 
@@ -2670,25 +3197,24 @@
 	if (sisfb_off)
 		return -ENXIO;
 
-//	printk("20011213:enable_dstn=%d \n", enable_dstn);
 	if (enable_dstn)
-		SetEnableDstn();
+		SetEnableDstn(&SiS_Pr);
+
+	memset(&sis_fb_info, 0, sizeof(sis_fb_info));
+	memset(&sis_disp, 0, sizeof(sis_disp));
 
 	pci_for_each_dev(pdev) {
 		for (b = sisdev_list; b->vendor; b++) {
 			if ((b->vendor == pdev->vendor)
 			    && (b->device == pdev->device)) {
 				pdev_valid = 1;
-				strcpy(fb_info.modename, b->name);
+				strcpy(sis_fb_info.modename, b->name);
 				ivideo.chip_id = pdev->device;
 				pci_read_config_byte(pdev, PCI_REVISION_ID,
 				                     &ivideo.revision_id);
 				pci_read_config_word(pdev, PCI_COMMAND, &reg16);
-				// Eden Chen
-				//sishw_ext.uRevisionID = ivideo.revision_id;
 				sishw_ext.jChipRevision = ivideo.revision_id;
-				// ~Eden Chen
-				sisvga_enabled = reg16 & 0x1;
+				sisvga_enabled = reg16 & 0x01;
 				break;
 			}
 		}
@@ -2700,7 +3226,6 @@
 	if (!pdev_valid)
 		return -ENODEV;
 
-// Eden Chen
 	switch (ivideo.chip_id) {
 	   case PCI_DEVICE_ID_SI_300:
 		ivideo.chip = SIS_300;
@@ -2712,9 +3237,9 @@
 		{
 			sisfb_set_reg4(0xCF8, 0x80000000);
 			reg32 = sisfb_get_reg3(0xCFC);
-			if (reg32 == 0x07301039) {
+			if(reg32 == 0x07301039) {
 				ivideo.chip = SIS_730;
-				strcpy(fb_info.modename, "SIS 730");
+				strcpy(sis_fb_info.modename, "SIS 730");
 			} else
 				ivideo.chip = SIS_630;
 
@@ -2760,31 +3285,28 @@
 		sisfb_CRT2_write_enable = IND_SIS_CRT2_WRITE_ENABLE_315;
 		break;
 	}
-	// Eden Chen
-	//sishw_ext.jChipID = ivideo.chip;
 	sishw_ext.jChipType = ivideo.chip;
-	// for Debug
+
+	/* for Debug */
 	if ((sishw_ext.jChipType == SIS_315PRO) 
 	   || (sishw_ext.jChipType == SIS_315) )
 		sishw_ext.jChipType = SIS_315H;
-	// ~Eden Chen
 
-	DPRINTK("%s is used as %s device(VGA Engine %d).\n", 
-		fb_info.modename, sisvga_enabled ? "primary" : "secondary", sisvga_engine);
+	DPRINTK("%s is used as %s device (VGA Engine %d).\n",
+		sis_fb_info.modename, sisvga_enabled ? "primary" : "secondary", sisvga_engine);
 
 	ivideo.video_base = pci_resource_start(pdev, 0);
 	ivideo.mmio_base = pci_resource_start(pdev, 1);
-	// Eden Chen
-	//sishw_ext.IOAddress = (unsigned short) ivideo.vga_base 
-	//	= pci_resource_start(pdev, 2) + 0x30;
-	sishw_ext.ulIOAddress = (unsigned short) ivideo.vga_base
-		= pci_resource_start(pdev, 2) + 0x30;
-	// ~Eden Chen
+	sishw_ext.ulIOAddress = (unsigned short) ivideo.vga_base =
+	    (unsigned short) SiS_Pr.RelIO = pci_resource_start(pdev, 2) + 0x30;
 
 	sisfb_mmio_size =  pci_resource_len(pdev, 1);
 
-	if (!sisvga_enabled)
+	if(!sisvga_enabled) {
 		if (pci_enable_device(pdev))   return -EIO;
+	}
+
+	SiSRegInit(&SiS_Pr, (USHORT)sishw_ext.ulIOAddress);
 
 // Eden Eden
 //#ifdef LINUXBIOS
@@ -2799,37 +3321,30 @@
 //	}
 //#endif
 // ~Eden Chen
-	
-	vgawb(SEQ_ADR, IND_SIS_PASSWORD);
-	vgawb(SEQ_DATA, SIS_PASSWORD);
+
+        outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
 
 #ifdef LINUXBIOS
+
 #ifdef CONFIG_FB_SIS_300
 	if (sisvga_engine == SIS_300_VGA) {
-		vgawb(SEQ_ADR, 0x28);
-		vgawb(SEQ_DATA, 0x37);
+	        outSISIDXREG(SISSR, 0x28, 0x37);
 
-		vgawb(SEQ_ADR, 0x29);
-		vgawb(SEQ_DATA, 0x61);
+                outSISIDXREG(SISSR, 0x29, 0x61);
 
-		vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_1A);
-		reg = vgarb(SEQ_DATA);
-		reg |= SIS_SCRATCH_REG_1A_MASK;
-		vgawb(SEQ_DATA, reg);
+                orSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_1A, SIS_SCRATCH_REG_1A_MASK);
 	}
 #endif
 #ifdef CONFIG_FB_SIS_315
 	if (ivideo.chip == SIS_550 || ivideo.chip == SIS_650) {
-		vgawb(SEQ_ADR,  0x28);
-		vgawb(SEQ_DATA, 0x5A);
+	        outSISIDXREG(SISSR, 0x28, 0x5a);
 
-		vgawb(SEQ_ADR,  0x29);
-		vgawb(SEQ_DATA, 0x64);
+                outSISIDXREG(SISSR, 0x29, 0x64);
 
-		vgawb(CRTC_ADR,  0x3A);
-		vgawb(CRTC_DATA, 0x00);
+                outSISIDXREG(SISCR, 0x3a, 0x00);
 	}
 #endif
+
 #endif /* LinuxBIOS */
 
 	if (sisvga_engine == SIS_315_VGA) {
@@ -2840,16 +3355,7 @@
 			break;
 		   case SIS_550:
 		   case SIS_650:
-			// Eden Chen
-			//vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_1A);
-			//reg = vgarb(SEQ_DATA);
-			//if (reg & SIS_SCRATCH_REG_1A_MASK)
-			//	sishw_ext.bIntegratedMMEnabled = TRUE;
-			//else
-			//	sishw_ext.bIntegratedMMEnabled = FALSE;
-			//for Debug
 			sishw_ext.bIntegratedMMEnabled = TRUE;
-			// ~Eden Chen
 			break;
 		   default:
 			break;
@@ -2858,8 +3364,7 @@
 		if (ivideo.chip == SIS_300) {
 			sishw_ext.bIntegratedMMEnabled = TRUE;
 		} else {
-			vgawb(SEQ_ADR, IND_SIS_SCRATCH_REG_1A);
-			reg = vgarb(SEQ_DATA);
+		        inSISIDXREG(SISSR, IND_SIS_SCRATCH_REG_1A, reg);
 			if (reg & SIS_SCRATCH_REG_1A_MASK)
 				sishw_ext.bIntegratedMMEnabled = TRUE;
 			else
@@ -2867,7 +3372,6 @@
 		}
 	}
 
-	// Eden Chen
 	sishw_ext.pDevice = NULL;
 	sishw_ext.pjVirtualRomBase = NULL;
 	sishw_ext.pjCustomizedROMImage = NULL;
@@ -2876,34 +3380,38 @@
 	sishw_ext.pQueryNorthBridgeSpace = &sisfb_query_north_bridge_space;
 	strcpy(sishw_ext.szVBIOSVer, "0.84");
 
+	/* TW: Mode numbers for 1280x960 are different for 300 and 310/325 series */
+	if(sisvga_engine == SIS_300_VGA) {
+		sisbios_mode[MODEINDEX_1280x960].mode_no = 0x6e;
+		sisbios_mode[MODEINDEX_1280x960+1].mode_no = 0x6f;
+		sisbios_mode[MODEINDEX_1280x960+2].mode_no = 0x7b;
+		sisbios_mode[MODEINDEX_1280x960+3].mode_no = 0x7b;
+	}
+
 	sishw_ext.pSR = vmalloc(sizeof(SIS_DSReg) * SR_BUFFER_SIZE);
 	if (sishw_ext.pSR == NULL) {
-		printk(KERN_INFO "sisfb: Fatal error: Allocating SRReg space failed.\n");
+		printk(KERN_ERR "sisfb: Fatal error: Allocating SRReg space failed.\n");
 		return -ENODEV;
 	}
 	sishw_ext.pSR[0].jIdx = sishw_ext.pSR[0].jVal = 0xFF;
 
 	sishw_ext.pCR = vmalloc(sizeof(SIS_DSReg) * CR_BUFFER_SIZE);
 	if (sishw_ext.pCR == NULL) {
-		vfree(sishw_ext.pSR);
-		printk(KERN_INFO "sisfb: Fatal error: Allocating CRReg space failed.\n");
+	        vfree(sishw_ext.pSR);
+		printk(KERN_ERR "sisfb: Fatal error: Allocating CRReg space failed.\n");
 		return -ENODEV;
 	}
 	sishw_ext.pCR[0].jIdx = sishw_ext.pCR[0].jVal = 0xFF;
-	// ~Eden Chen
 
 #ifdef CONFIG_FB_SIS_300
-	if (sisvga_engine == SIS_300_VGA) {
-		if (!sisvga_enabled) {
-			// Eden Chen
-			sishw_ext.pjVideoMemoryAddress 
+	if(sisvga_engine == SIS_300_VGA) {
+		if(!sisvga_enabled) {
+			sishw_ext.pjVideoMemoryAddress
 				= ioremap(ivideo.video_base, 0x2000000);
 			if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {   /* TW: for mode "none" */
-				//SiSInit300(&sishw_ext);
-				SiSInit(&sishw_ext);
-				vgawb(SEQ_ADR, IND_SIS_PASSWORD);
-				vgawb(SEQ_DATA, SIS_PASSWORD);
-				// ~Eden Chen
+			        /* TW: SiSInit now for LinuxBIOS only */
+				/* SiSInit(&SiS_Pr, &sishw_ext);  */
+				outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
 			}
 		}
 #ifdef LINUXBIOS
@@ -2911,20 +3419,18 @@
 			sishw_ext.pjVideoMemoryAddress
 				= ioremap(ivideo.video_base, 0x2000000);
 			if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {   /* TW: for mode "none" */
-				SiSInit(&sishw_ext);
-				vgawb(SEQ_ADR, IND_SIS_PASSWORD);
-				vgawb(SEQ_DATA, SIS_PASSWORD);
+				SiSInit(&SiS_Pr, &sishw_ext);
+				outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
 			}
 		}
-		if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {   /* TW: for mode "none" */
-			vgawb(SEQ_ADR, 0x7);
-			reg = vgarb(SEQ_DATA);
-			reg |= 0x10;
-			vgawb(SEQ_DATA, reg);
+		if((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {   /* TW: for mode "none" */
+		        orSISIDXREG(SISSR, 0x07, 0x10);
 		}
 #endif
-		if (sisfb_get_dram_size_300()) {
-			printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size\n");
+		if(sisfb_get_dram_size_300()) {
+		        vfree(sishw_ext.pSR);
+			vfree(sishw_ext.pCR);
+			printk(KERN_ERR "sisfb: Fatal error: Unable to determine RAM size\n");
 			return -ENODEV;
 		}
 	}
@@ -2939,19 +3445,17 @@
 			sishw_ext.pjVideoMemoryAddress 
 				= ioremap(ivideo.video_base, 0x8000000);
 			if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {   /* TW: for mode "none" */
-				SiSInit(&sishw_ext);
+			        /* TW: SISInit is now for LINUXBIOS only */
+				/* SiSInit(&SiS_Pr, &sishw_ext); */
 
-				vgawb(SEQ_ADR, IND_SIS_PASSWORD);
-				vgawb(SEQ_DATA, SIS_PASSWORD);
+				outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
 
 				sishw_ext.bSkipDramSizing = TRUE;
-				vgawb(SEQ_ADR, 0x13);
 				sishw_ext.pSR[0].jIdx = 0x13;
-				sishw_ext.pSR[0].jVal = vgarb(SEQ_DATA);
-				vgawb(SEQ_ADR, 0x14);
 				sishw_ext.pSR[1].jIdx = 0x14;
-				sishw_ext.pSR[1].jVal = vgarb(SEQ_DATA);
 				sishw_ext.pSR[2].jIdx = 0xFF;
+				inSISIDXREG(SISSR, 0x13, sishw_ext.pSR[0].jVal);
+				inSISIDXREG(SISSR, 0x14, sishw_ext.pSR[1].jVal);
 				sishw_ext.pSR[2].jVal = 0xFF;
 			}
 		}
@@ -2960,51 +3464,51 @@
 			sishw_ext.pjVideoMemoryAddress
 				= ioremap(ivideo.video_base, 0x8000000);
 			if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {   /* TW: for mode "none" */
-				SiSInit(&sishw_ext);
-				vgawb(SEQ_ADR, IND_SIS_PASSWORD);
-				vgawb(SEQ_DATA, SIS_PASSWORD);
+
+				SiSInit(&SiS_Pr, &sishw_ext);
+
+				outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
 
 				sishw_ext.bSkipDramSizing = TRUE;
-				vgawb(SEQ_ADR, 0x13);
 				sishw_ext.pSR[0].jIdx = 0x13;
-				sishw_ext.pSR[0].jVal = vgarb(SEQ_DATA);
-				vgawb(SEQ_ADR, 0x14);
 				sishw_ext.pSR[1].jIdx = 0x14;
-				sishw_ext.pSR[1].jVal = vgarb(SEQ_DATA);
 				sishw_ext.pSR[2].jIdx = 0xFF;
+				inSISIDXREG(SISSR, 0x13, sishw_ext.pSR[0].jVal);
+				inSISIDXREG(SISSR, 0x14, sishw_ext.pSR[1].jVal);
 				sishw_ext.pSR[2].jVal = 0xFF;
 			}
 		}
 #endif
 		if (sisfb_get_dram_size_315()) {
+			vfree(sishw_ext.pSR);
+			vfree(sishw_ext.pCR);
 			printk(KERN_INFO "sisfb: Fatal error: Unable to determine RAM size.\n");
 			return -ENODEV;
 		}
 	}
 #endif
+
 	if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {   /* TW: for mode "none" */
-		//Eden Chen
-		vgawb(SEQ_ADR, IND_SIS_PCI_ADDRESS_SET);
-		reg = vgarb(SEQ_DATA);
-		reg |= SIS_PCI_ADDR_ENABLE;    	/* Enable PCI_LINEAR_ADDRESSING */
-		reg |= SIS_MEM_MAP_IO_ENABLE;  	/* Enable MMIO_ENABLE */
-		vgawb(SEQ_DATA, reg);
-
-		vgawb(SEQ_ADR, IND_SIS_MODULE_ENABLE);
-		reg = vgarb(SEQ_DATA);
-		reg |= SIS_ENABLE_2D;		/* Enable 2D accelerator engine */
-		vgawb(SEQ_DATA, reg);
-		//~Eden Chen
+
+	        /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE  */
+	        orSISIDXREG(SISSR, IND_SIS_PCI_ADDRESS_SET, (SIS_PCI_ADDR_ENABLE | SIS_MEM_MAP_IO_ENABLE));
+
+                /* Enable 2D accelerator engine */
+	        orSISIDXREG(SISSR, IND_SIS_MODULE_ENABLE, SIS_ENABLE_2D);
+
 	}
 
-	// Eden Chen
 	sishw_ext.ulVideoMemorySize = ivideo.video_size;
-	// ~Eden Chen
-	
-	printk("Video base at %08lx, for %08lx\n", ivideo.video_base, ivideo.video_size);
-	
+
+	if(sisfb_pdc) {
+	    sishw_ext.pdc = sisfb_pdc;
+	} else {
+	    sishw_ext.pdc = 0;
+	}
+
 	if (!request_mem_region(ivideo.video_base, ivideo.video_size, "sisfb FB")) {
 		printk(KERN_ERR "sisfb: Fatal error: Unable to reserve frame buffer memory\n");
+		printk(KERN_ERR "sisfb: Is there another framebuffer driver active?\n");
 		vfree(sishw_ext.pSR);
 		vfree(sishw_ext.pCR);
 		return -ENODEV;
@@ -3012,78 +3516,78 @@
 
 	if (!request_mem_region(ivideo.mmio_base, sisfb_mmio_size, "sisfb MMIO")) {
 		printk(KERN_ERR "sisfb: Fatal error: Unable to reserve MMIO region\n");
+		release_mem_region(ivideo.video_base, ivideo.video_size);
 		vfree(sishw_ext.pSR);
 		vfree(sishw_ext.pCR);
-		release_mem_region(ivideo.video_base, ivideo.video_size);
 		return -ENODEV;
 	}
-	// Eden Chen
-	//sishw_ext.VirtualVideoMemoryAddress = ivideo.video_vbase 
-	sishw_ext.pjVideoMemoryAddress = ivideo.video_vbase 
+
+	sishw_ext.pjVideoMemoryAddress = ivideo.video_vbase
 		= ioremap(ivideo.video_base, ivideo.video_size);
-	// Eden Chen
 	ivideo.mmio_vbase = ioremap(ivideo.mmio_base, sisfb_mmio_size);
 
-	printk(KERN_INFO
-	       "sisfb: Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
+	printk(KERN_INFO "sisfb: Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
 	       ivideo.video_base, ivideo.video_vbase,
 	       ivideo.video_size / 1024);
 
-	printk(KERN_INFO
-	       "sisfb: MMIO at 0x%lx, mapped to 0x%p, size %ldk\n",
+	printk(KERN_INFO "sisfb: MMIO at 0x%lx, mapped to 0x%p, size %ldk\n",
 	       ivideo.mmio_base, ivideo.mmio_vbase,
 	       sisfb_mmio_size / 1024);
 
+	if(sisfb_heap_init()) {
+		printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
+	}
+
+	ivideo.mtrr = (unsigned int) 0;
+
 	if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {   /* TW: for mode "none" */
 
 #ifdef CONFIG_FB_SIS_300
 		if (sisvga_engine == SIS_300_VGA) {
 			sisfb_get_VB_type_300();
-			if (ivideo.hasVB != HASVB_NONE) {
-				sisfb_detect_VB_connect_300();
-			}
 		}
 #endif
 
 #ifdef CONFIG_FB_SIS_315
 		if (sisvga_engine == SIS_315_VGA) {
 			sisfb_get_VB_type_315();
-			if (ivideo.hasVB != HASVB_NONE) {
-				sisfb_detect_VB_connect_315();
-			}
 		}
 #endif
 
-		// Eden Chen
 		sishw_ext.ujVBChipID = VB_CHIP_UNKNOWN;
 		sishw_ext.usExternalChip = 0;
 
 		switch (ivideo.hasVB) {
 
 		case HASVB_301:
-			/*karl*/
-			vgawb(VB_PART4_ADR,0x01);
-			reg = vgarb(VB_PART4_DATA);
-			if (reg >= 0xD0) {
-				sishw_ext.ujVBChipID = VB_CHIP_301B;
-				printk(KERN_INFO "sisfb: SiS301LV bridge detected\n");
+		        inSISIDXREG(SISPART4, 0x01, reg);
+			if (reg >= 0xE0) {
+				sishw_ext.ujVBChipID = VB_CHIP_301LVX;
+				printk(KERN_INFO "sisfb: SiS301LVX bridge detected (revision 0x%02x)\n",reg);
+	  		} else if (reg >= 0xD0) {
+				sishw_ext.ujVBChipID = VB_CHIP_301LV;
+				printk(KERN_INFO "sisfb: SiS301LV bridge detected (revision 0x%02x)\n",reg);
 	  		} else if (reg >= 0xB0) {
 				sishw_ext.ujVBChipID = VB_CHIP_301B;
-				printk(KERN_INFO "sisfb: SiS301B bridge detected\n");
+				printk(KERN_INFO "sisfb: SiS301B bridge detected (revision 0x%02x\n",reg);
 			} else {
 				sishw_ext.ujVBChipID = VB_CHIP_301;
 				printk(KERN_INFO "sisfb: SiS301 bridge detected\n");
 			}
 			break;
 		case HASVB_302:
-			vgawb(VB_PART4_ADR,0x01);
-			reg = vgarb(VB_PART4_DATA);
-			sishw_ext.ujVBChipID = VB_CHIP_302;
-			if (reg >= 0xD0) {
-				printk(KERN_INFO "sisfb: SiS302LV bridge detected\n");
+		        inSISIDXREG(SISPART4, 0x01, reg);
+			if (reg >= 0xE0) {
+				sishw_ext.ujVBChipID = VB_CHIP_302LVX;
+				printk(KERN_INFO "sisfb: SiS302LVX bridge detected (revision 0x%02x)\n",reg);
+	  		} else if (reg >= 0xD0) {
+				sishw_ext.ujVBChipID = VB_CHIP_302LV;
+				printk(KERN_INFO "sisfb: SiS302LV bridge detected (revision 0x%02x)\n",reg);
 	  		} else if (reg >= 0xB0) {
-				printk(KERN_INFO "sisfb: SiS302B bridge detected\n");
+			        sishw_ext.ujVBChipID = VB_CHIP_302B;
+				printk(KERN_INFO "sisfb: SiS302B bridge detected (revision 0x%02x)\n",reg);
 			} else {
+			        sishw_ext.ujVBChipID = VB_CHIP_302;
 				printk(KERN_INFO "sisfb: SiS302 bridge detected\n");
 			}
 			break;
@@ -3093,108 +3597,64 @@
 			break;
 		case HASVB_LVDS:
 			sishw_ext.usExternalChip = 0x1;
-			printk(KERN_INFO "sisfb: LVDS bridge detected\n");
+			printk(KERN_INFO "sisfb: LVDS transmitter detected\n");
 			break;
 		case HASVB_TRUMPION:
 			sishw_ext.usExternalChip = 0x2;
-			printk(KERN_INFO "sisfb: TRUMPION TV converter detected\n");
+			printk(KERN_INFO "sisfb: Trumpion Zurac LVDS scaler detected\n");
 			break;
 		case HASVB_CHRONTEL:
 			sishw_ext.usExternalChip = 0x4;
-			printk(KERN_INFO "sisfb: Chrontel TV converter detected\n");
+			printk(KERN_INFO "sisfb: Chrontel TV encoder detected\n");
 			break;
 		case HASVB_LVDS_CHRONTEL:
 			sishw_ext.usExternalChip = 0x5;
-			printk(KERN_INFO "sisfb: LVDS bridge and Chrontel TV converter detected\n");
+			printk(KERN_INFO "sisfb: LVDS transmitter and Chrontel TV encoder detected\n");
 			break;
 		default:
 			printk(KERN_INFO "sisfb: No or unknown bridge type detected\n");
 			break;
 		}
-		// ~Eden Chen
 
-		/* TW: Determine and detect attached TV's on Chrontel */
-		if (sishw_ext.usExternalChip == 0x04 || sishw_ext.usExternalChip == 0x05) {
-		    SiSRegInit(sishw_ext.ulIOAddress);
-		    temp1=SiS_GetCH7005(0x25);
-		    if ((temp1 >= 50) && (temp1 <= 100)) {
-	    		/* TW: Read power status */
-	    		temp1 = SiS_GetCH7005(0x0e);
-	    		if ((temp1&0x03)!=0x03) {
-		        	/* TW: Power all outputs */
-	        		SiS_SetCHTVRegANDOR(0x030E,0xF8);
-	    		}
-			/* TW: Sense connected TV devices */
-	    		SiS_SetCH7005(0x0110);
-	    		SiS_SetCH7005(0x0010);
-	    		temp1 = SiS_GetCH7005(0x10);
-	    		if (!(temp1 & 0x08)) {
-				/* TW: So we can be sure that there IS a SVHS output */
-				printk(KERN_INFO
-				   "sisfb: Chrontel: Detected TV connected to SVHS output\n");
-				ivideo.TV_plug = TVPLUG_SVIDEO;
-				vgawb(CRTC_ADR, 0x32);
-				temp2 = vgarb(CRTC_DATA) | 0x02;
-				vgawb(CRTC_DATA, temp2);
-			} else if (!(temp1 & 0x02)) {
-				/* TW: So we can be sure that there IS a CVBS output */
-				printk(KERN_INFO
-				   "sisfb: Chrontel: Detected TV connected to CVBS output\n");
-				ivideo.TV_plug = TVPLUG_COMPOSITE;
-				vgawb(CRTC_ADR, 0x32);
-				temp2 = vgarb(CRTC_DATA) | 0x01;
-				vgawb(CRTC_DATA, temp2);
-	    		} else {
-		    		SiS_SetCHTVRegANDOR(0x010E,0xF8);
-	    		}
-		    } else if (temp1==0) {
-	    		        SiS_SetCHTVRegANDOR(0x010E,0xF8);
-	    	    }
-	    	}
+		if (ivideo.hasVB != HASVB_NONE) {
+#ifdef CONFIG_FB_SIS_300
+		      if (sisvga_engine == SIS_300_VGA) {
+				sisfb_detect_VB_connect_300();
+                      }
+#endif
+#ifdef CONFIG_FB_SIS_315
+		      if (sisvga_engine == SIS_315_VGA) {
+				sisfb_detect_VB_connect_315();
+                      }
+#endif
+		}
 
 		if (ivideo.disp_state & DISPTYPE_DISP2) {
 			if (sisfb_crt1off)
 				ivideo.disp_state |= DISPMODE_SINGLE;
 			else
 				ivideo.disp_state |= (DISPMODE_MIRROR | DISPTYPE_CRT1);
-		} else
+		} else {
 			ivideo.disp_state = DISPMODE_SINGLE | DISPTYPE_CRT1;
+		}
 
 		if (ivideo.disp_state & DISPTYPE_LCD) {
-			vgawb(CRTC_ADR, IND_SIS_LCD_PANEL);
-			reg = vgarb(CRTC_DATA);
-			// Eden Chen
-			switch (reg) {
-			   case SIS_LCD_PANEL_800X600:
-				sishw_ext.ulCRT2LCDType = LCD_800x600;
-				break;
-			   case SIS_LCD_PANEL_1024X768:
-				sishw_ext.ulCRT2LCDType = LCD_1024x768;
-				break;
-			   case SIS_LCD_PANEL_1280X1024:
-				sishw_ext.ulCRT2LCDType = LCD_1280x1024;
-				break;
-			   case SIS_LCD_PANEL_640X480:
-				sishw_ext.ulCRT2LCDType = LCD_640x480;
-				break;
-			   case SIS_LCD_PANEL_1280X960:
-				sishw_ext.ulCRT2LCDType = LCD_1280x960;
-				break;
-			   case SIS_LCD_PANEL_1600x1200: /* TW */
-				sishw_ext.ulCRT2LCDType = LCD_1600x1200;
-				break;
-			   case SIS_LCD_PANEL_320x480:   /* TW: FSTN */
-				sishw_ext.ulCRT2LCDType = LCD_320x480;
-				break;
-			   default:
-				sishw_ext.ulCRT2LCDType = LCD_1024x768;
-				break;
+		    if (!enable_dstn) {
+		        inSISIDXREG(SISCR, IND_SIS_LCD_PANEL, reg);
+			reg &= 0x0f;
+			if (sisvga_engine == SIS_300_VGA) {
+			    sishw_ext.ulCRT2LCDType = sis300paneltype[reg];
+			} else {
+			    sishw_ext.ulCRT2LCDType = sis310paneltype[reg];
 			}
-			// ~Eden Chen
+		    } else {
+		        /* TW: FSTN/DSTN */
+			sishw_ext.ulCRT2LCDType = LCD_320x480;
+		    }
 		}
 
 		if (sisfb_mode_idx >= 0)
-			sisfb_validate_mode();
+			sisfb_mode_idx = sisfb_validate_mode(sisfb_mode_idx);
 
 		if (sisfb_mode_idx < 0) {
 			switch (ivideo.disp_state & DISPTYPE_DISP2) {
@@ -3224,196 +3684,404 @@
 		ivideo.video_vwidth = ivideo.video_width = sisbios_mode[sisfb_mode_idx].xres;
 		ivideo.video_vheight = ivideo.video_height = sisbios_mode[sisfb_mode_idx].yres;
 		ivideo.org_x = ivideo.org_y = 0;
-		video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
+		ivideo.video_linelength = ivideo.video_width * (ivideo.video_bpp >> 3);
+		switch(ivideo.video_bpp) {
+        	case 8:
+            		ivideo.DstColor = 0x0000;
+	    		ivideo.SiS310_AccelDepth = 0x00000000;
+			ivideo.video_cmap_len = 256;
+            		break;
+        	case 16:
+            		ivideo.DstColor = 0x8000;
+            		ivideo.SiS310_AccelDepth = 0x00010000;
+			ivideo.video_cmap_len = 16;
+            		break;
+        	case 32:
+            		ivideo.DstColor = 0xC000;
+	    		ivideo.SiS310_AccelDepth = 0x00020000;
+			ivideo.video_cmap_len = 16;
+            		break;
+		default:
+			ivideo.video_cmap_len = 16;
+		        printk(KERN_INFO "sisfb: Unsupported accel depth %d", ivideo.video_bpp);
+			sisfb_accel = 0;
+			break;
+    		}
 
-		printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz), linelength=%d\n",
+		printk(KERN_INFO "sisfb: Mode is %dx%dx%d (%dHz)\n",
 	       		ivideo.video_width, ivideo.video_height, ivideo.video_bpp,
-			ivideo.refresh_rate, video_linelength);
-
-		// Eden Chen
-		// Check interface correction  For Debug
-		DPRINTK("VM Adr=0x%p\n", sishw_ext.pjVideoMemoryAddress);
-		DPRINTK("VM Size=%ldK\n", sishw_ext.ulVideoMemorySize/1024);
-		DPRINTK("IO Adr=0x%lx\n", sishw_ext.ulIOAddress);
-		DPRINTK("Chip=%d\n", sishw_ext.jChipType);
-		DPRINTK("ChipRevision=%d\n", sishw_ext.jChipRevision);
-		DPRINTK("VBChip=%d\n", sishw_ext.ujVBChipID);
-		DPRINTK("ExtVB=%d\n", sishw_ext.usExternalChip);
-		DPRINTK("LCD=%ld\n", sishw_ext.ulCRT2LCDType);
-		DPRINTK("bIntegratedMMEnabled=%d\n", sishw_ext.bIntegratedMMEnabled);
-		// ~Eden Chen
+			ivideo.refresh_rate);
 
 		sisfb_pre_setmode();
 
-		if (SiSSetMode(&sishw_ext, sisfb_mode_no) == 0) {
-			DPRINTK("set mode[0x%x]: failed\n", sisfb_mode_no);
+		if (SiSSetMode(&SiS_Pr, &sishw_ext, sisfb_mode_no) == 0) {
+			printk("sisfb: Setting mode[0x%x] failed, using default mode\n", sisfb_mode_no);
 			return -1;
 		}
 
-		vgawb(SEQ_ADR, IND_SIS_PASSWORD);
-		vgawb(SEQ_DATA, SIS_PASSWORD);
+		outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
 
 		sisfb_post_setmode();
 
 		sisfb_crtc_to_var(&default_var);
 
-		fb_info.changevar = NULL;
+		if(sisfb_accel) {
+		   sisfb_initaccel();
+		}
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)	/* ---- 2.4 series init ---- */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,23)
+		sis_fb_info.screen_base = ivideo.video_vbase;
+		sis_fb_info.currcon = -1;
+#endif
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-		fb_info.node = -1;
+		sis_fb_info.node = -1;
 #else
-		fb_info.node = NODEV;
+		sis_fb_info.node = NODEV;
+#endif
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,23)
+		sis_fb_info.blank = &sisfb_blank;
 #endif
-		fb_info.fbops = &sisfb_ops;
-		fb_info.disp = &disp;
-		fb_info.switch_con = &sisfb_switch;
-		fb_info.updatevar = &sisfb_update_var;
-		fb_info.blank = &sisfb_blank;
-		fb_info.flags = FBINFO_FLAG_DEFAULT;
+		sis_fb_info.fbops = &sisfb_ops;
+		sis_fb_info.switch_con = &sisfb_switch;
+		sis_fb_info.updatevar = &sisfb_update_var;
+		sis_fb_info.changevar = NULL;
+		sis_fb_info.disp = &sis_disp;
+		sis_fb_info.flags = FBINFO_FLAG_DEFAULT;
 
-		sisfb_set_disp(-1, &default_var);
+		sisfb_set_disp(-1, &default_var, &sis_fb_info);
+#endif
 
-	} /* TW: if mode = "none" */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)	/* ---- 2.5 series init ---- */
+		sis_fb_info.screen_base = ivideo.video_vbase;
+		sis_fb_info.node = NODEV;
+		sis_fb_info.fbops = &sisfb_ops;
+		sisfb_get_fix(&sis_fb_info.fix, -1, &sis_fb_info);
+		sis_fb_info.pseudo_palette = pseudo_palette;
+		sis_fb_info.flags = FBINFO_FLAG_DEFAULT;
+
+		sis_fb_info.changevar = NULL;
+		sis_fb_info.currcon = -1;
+		sis_fb_info.disp = &sis_disp;
+		sis_fb_info.switch_con = gen_switch;
+		sis_fb_info.updatevar = gen_update_var;
 
-	if (sisfb_heap_init()) {
-		printk(KERN_WARNING "sisfb: Failed to initialize offscreen memory heap\n");
-	}
+		fb_alloc_cmap(&sis_fb_info.cmap, 256, 0);
 
-        ivideo.mtrr = (unsigned int) 0;
-	if ((sisbios_mode[sisfb_mode_idx].mode_no) != 0xFF) {   /* TW: for mode "none" */
-         	/*H.C.*/
+		sis_fb_info.var = default_var;
+#endif
+
+#ifdef CONFIG_MTRR
 		ivideo.mtrr = mtrr_add((unsigned int) ivideo.video_base,
 				(unsigned int) ivideo.video_size,
 				MTRR_TYPE_WRCOMB, 1);
-      		/*
-			if (ivideo.mtrr >= 0) {
-           		printk(KERN_INFO "Succeed to turn on Write-Combining on VideoMemory %08XH, Size: %08XH\n",
-					ivideo.video_base, ivideo.video_size);
-      			} else	{
-           		printk(KERN_INFO "Fail to turn on Write-Combining on Video Memory 0x%08X, Size: 0x%08X\n",
-					ivideo.video_base, ivideo.video_size);
-      			}
-        	*/
-		vc_resize_con(1, 1, 0);
+		if(ivideo.mtrr) {
+			printk(KERN_INFO "sisfb: Added MTRRs\n");
+		}
+#endif
 
-		if (register_framebuffer(&fb_info) < 0)
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+		vc_resize_con(1, 1, 0);
+#endif
+		TWDEBUG("Before calling register_framebuffer");
+		if(register_framebuffer(&sis_fb_info) < 0)
 			return -EINVAL;
 
+		printk(KERN_INFO "sisfb: Installed SISFB_GET_INFO ioctl (%x)\n", SISFB_GET_INFO);
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+		printk(KERN_INFO "sisfb: 2D acceleration is %s, scrolling mode %s\n",
+		     sisfb_accel ? "enabled" : "disabled",
+		     sisfb_ypan  ? "ypan" : "redraw");
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+		printk(KERN_INFO "sisfb: 2D acceleration is %s\n",
+		     sisfb_accel ? "enabled" : "disabled");
+#endif
+
 		printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%02d\n",
-	       		GET_FB_IDX(fb_info.node), fb_info.modename, VER_MAJOR, VER_MINOR,
+	       		GET_FB_IDX(sis_fb_info.node), sis_fb_info.modename, VER_MAJOR, VER_MINOR,
 	       		VER_LEVEL);
 
+
 	}	/* TW: if mode = "none" */
 	return 0;
 }
 
+/* ------------------------------------------------------------------------------ */
+
+/* TW: As long as the generic framebuffer parts don't work as modules, we use
+   our own stuff here. I can't debug a fb driver if I need to compile the driver
+   into the kernel. It simply drives me nuts.
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,33)
+
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <asm/types.h>
+
+#include <video/fbcon.h>
+
+void my_cfb_imageblit(struct fb_info *p, struct fb_image *image)
+{
+	int pad, ppw;
+	int x2, y2, n, i, j, k, l = 7;
+	unsigned long tmp = ~0 << (BITS_PER_LONG - p->var.bits_per_pixel);
+	unsigned long fgx, bgx, fgcolor, bgcolor, eorx;
+	unsigned long end_mask;
+	unsigned long *dst = NULL;
+	u8 *dst1;
+	u8 *src;
+
+	/*
+	 * We could use hardware clipping but on many cards you get around hardware
+	 * clipping by writing to framebuffer directly like we are doing here.
+	 */
+	x2 = image->dx + image->width;
+	y2 = image->dy + image->height;
+	image->dx = image->dx > 0 ? image->dx : 0;
+	image->dy = image->dy > 0 ? image->dy : 0;
+	x2 = x2 < p->var.xres_virtual ? x2 : p->var.xres_virtual;
+	y2 = y2 < p->var.yres_virtual ? y2 : p->var.yres_virtual;
+	image->width  = x2 - image->dx;
+	image->height = y2 - image->dy;
+
+	dst1 = p->screen_base + image->dy * p->fix.line_length +
+		((image->dx * p->var.bits_per_pixel) >> 3);
+
+	ppw = BITS_PER_LONG/p->var.bits_per_pixel;
+
+	src = image->data;
+
+	if (image->depth == 1) {
+
+		if (p->fix.visual == FB_VISUAL_TRUECOLOR) {
+			fgx = fgcolor = ((u32 *)(p->pseudo_palette))[image->fg_color];
+			bgx = bgcolor = ((u32 *)(p->pseudo_palette))[image->bg_color];
+		} else {
+			fgx = fgcolor = image->fg_color;
+			bgx = bgcolor = image->bg_color;
+		}
+
+		for (i = 0; i < ppw-1; i++) {
+			fgx <<= p->var.bits_per_pixel;
+			bgx <<= p->var.bits_per_pixel;
+			fgx |= fgcolor;
+			bgx |= bgcolor;
+		}
+		eorx = fgx ^ bgx;
+		n = ((image->width + 7) >> 3);
+		pad = (n << 3) - image->width;
+		n = image->width % ppw;
+
+		for (i = 0; i < image->height; i++) {
+			dst = (unsigned long *) dst1;
+
+			for (j = image->width/ppw; j > 0; j--) {
+				end_mask = 0;
+
+				for (k = ppw; k > 0; k--) {
+					if (test_bit(l, (unsigned long *) src))
+						end_mask |= (tmp >> (p->var.bits_per_pixel*(k-1)));
+					l--;
+					if (l < 0) { l = 7; src++; }
+				}
+				fb_writel((end_mask & eorx)^bgx, dst);
+				dst++;
+			}
+
+			if (n) {
+				end_mask = 0;
+				for (j = n; j > 0; j--) {
+					if (test_bit(l, (unsigned long *) src))
+						end_mask |= (tmp >> (p->var.bits_per_pixel*(j-1)));
+					l--;
+					if (l < 0) { l = 7; src++; }
+				}
+				fb_writel((end_mask & eorx)^bgx, dst);
+				dst++;
+			}
+			l -= pad;
+			dst1 += p->fix.line_length;
+		}
+	} else {
+		/* Draw the penguin */
+		n = ((image->width * p->var.bits_per_pixel) >> 3);
+		end_mask = 0;
+	}
+}
+#endif
+/* -------------------------------------------------------------------------------- */
+
+
 #ifdef MODULE
 
-static char *mode = NULL;
+static char         *mode = NULL;
+static int          vesa = -1;
 static unsigned int rate = 0;
 static unsigned int crt1off = 1;
 static unsigned int mem = 0;
 static unsigned int dstn = 0;
-static char *forcecrt2type = NULL;
-static int forcecrt1 = -1;
-static char *queuemode = NULL;
+static char         *forcecrt2type = NULL;
+static int          forcecrt1 = -1;
+static char         *queuemode = NULL;
+static int          pdc = 0;
+static int          noaccel = -1;
+static int          noypan  = -1;
+static int          inverse = 0;
 
 MODULE_DESCRIPTION("SiS 300/540/630/730/315/550/650/740 framebuffer driver");
-MODULE_LICENSE("GPL");    /* TW (Code is officially open says SiS) */
-MODULE_AUTHOR("Various; SiS; Some parts by Thomas Winischhofer <thomas@winischhofer.net>");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Various; SiS; Thomas Winischhofer <thomas@winischhofer.net>");
 
 MODULE_PARM(mode, "s");
 MODULE_PARM_DESC(mode,
-       "Selects the desired display mode in the format [X]x[Y]x[Depth], eg. 800x600x16 "
-       "(default: none; this leaves the console untouched and the driver will only do "
-       "the video memory management for eg. DRM/DRI)");
+       "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
+         "800x600x16 (default: none if sisfb is a module; this leaves the\n"
+	 "console untouched and the driver will only do the video memory\n"
+	 "management for eg. DRM/DRI; 800x600x8 if sisfb is in the kernel)");
+
+MODULE_PARM(vesa, "i");
+MODULE_PARM_DESC(vesa,
+       "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
+         "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
+	 "and the driver will only do the video memory management for eg. DRM/DRI;\n"
+	 "0x0103 if sisfb is in the kernel)");
 
 MODULE_PARM(rate, "i");
 MODULE_PARM_DESC(rate,
-	"Selects the desired vertical refresh rate for CRT1 (external VGA) in Hz. "
+	"\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
 	"(default: 60)");
 
 MODULE_PARM(crt1off,   "i");
 MODULE_PARM_DESC(crt1off,
-	"If this option is set, the driver will switch off CRT1 (external VGA). "
 	"(Deprecated, please use forcecrt1)");
 
 MODULE_PARM(filter, "i");
 MODULE_PARM_DESC(filter,
-	"Selects TV flicker filter type (only for SiS30x video bridges). "
-	"(Possible values 0-7, default: [no filter])");
+	"\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
+	  "(Possible values 0-7, default: [no filter])");
 
 MODULE_PARM(dstn,   "i"); /* JennyLee 20011211 */
 MODULE_PARM_DESC(dstn,
-	"Selects DSTN display mode (1=ON, 0=OFF) (default: 0)");
+	"\nSelects DSTN/FSTN display mode for SiS550. This sets CRT2 type to LCD and\n"
+	  "overrides forcecrt2type setting. (1=ON, 0=OFF) (default: 0)");
 
 MODULE_PARM(queuemode,   "s");
 MODULE_PARM_DESC(queuemode,
-	"Selects the queue mode on 315/550/650/740. Possible choices are AGP, VRAM "
-	"or MMIO. AGP is only available if the kernel has AGP support. "
-	"The queue mode is important to programs using the 2D/3D accelerator of "
-	"the SiS chip. The modes require a totally different way of programming "
-	"the engines. On 300/540/630/730, this option is ignored. (default: MMIO)");
+	"\nSelects the queue mode on 315/550/650/740. Possible choices are AGP, VRAM or\n"
+  	  "MMIO. AGP is only available if the kernel has AGP support. The queue mode is\n"
+	  "important to programs using the 2D/3D accelerator of the SiS chip. The modes\n"
+	  "require a totally different way of programming the engines. If any mode than\n"
+	  "MMIO is selected, sisfb will disable its own 2D acceleration. On\n"
+	  "300/540/630/730, this option is ignored. (default: MMIO)");
 
 /* TW: "Import" the options from the X driver */
 MODULE_PARM(mem,    "i");
 MODULE_PARM_DESC(mem,
-	"Determines the beginning of the video memory heap in KB. This heap is used for "
-	"video RAM management for eg. DRM/DRI. The default depends on the amount of video "
-	"memory available. If 8MB of video RAM or less is available, "
-	"the heap starts at 4096KB, otherwise at 8192KB. The value is to be specified "
-	"without 'KB' and should match MaxXFBMem setting for XFree 4.x (x>=2). "
-	"See http://www.winischhofer.net/linuxsis630.shtml for a closer description.");
+	"\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
+	  "for video RAM management for eg. DRM/DRI. The default depends on the amount\n"
+	  "of video RAM available. If 8MB of video RAM or less is available, the heap\n"
+	  "starts at 4096KB, if between 8 and 16MB are available at 8192KB, otherwise\n"
+	  "at 12288KB. The value is to be specified without 'KB' and should match\n"
+	  "the MaxXFBMem setting for XFree 4.x (x>=2).");
 
 MODULE_PARM(forcecrt2type, "s");
 MODULE_PARM_DESC(forcecrt2type,
-	"If this option is omitted, the driver autodetects CRT2 output devices, such as LCD, "
-	"TV or secondary VGA (in this order; so if eg. an LCD is there, it will be used regardless "
-	"of a connected TV set). With this option, this autodetection can be overridden. "
-	"Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2 and makes it "
-	"possible to use higher resolutions on CRT1 than eg. your LCD panel supports. TV "
-	"selects TV output (only resolutions 640x480 and 800x600 are supported for TV!). "
-	"VGA refers to _secondary_ VGA which is unlikely to be available; the VGA plug found "
-	"on most machines is CRT1. (default: [autodetected])");
+	"\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
+	  "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
+	  "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
+	  "On systems with a 301(B) bridge, parameters SVIDEO, COMPOSITE or SCART can be\n"
+	  "used instead of TV to override the TV detection. (default: [autodetected])");
 
 MODULE_PARM(forcecrt1, "i");
 MODULE_PARM_DESC(forcecrt1,
-	"Normally, the driver autodetects whether or not CRT1 (external VGA) is connected. "
-	"With this option, the detection can be overridden (1=CRT1 ON, 0=CRT1 off) "
-	"(default: [autodetected])");
+	"\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
+	  "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
+	  " 0=CRT1 off) (default: [autodetected])");
+
+MODULE_PARM(pdc, "i");
+MODULE_PARM_DESC(pdc,
+        "\n(300 series only) This is for manually selecting the LCD panel delay\n"
+	  "compensation. The driver should detect this correctly in most cases; however,\n"
+	  "sometimes this is not possible. If you see 'small waves' on the LCD, try\n"
+	  "setting this to 4, 32 or 24. If the problem persists, try other values\n"
+	  "between 4 and 60 in steps of 4. (default: [autodetected])");
+
+MODULE_PARM(noaccel, "i");
+MODULE_PARM_DESC(noaccel,
+        "\nIf set to anything other than 0, 2D acceleration and y-panning will be\n"
+	"disabled. (default: 0)");
+
+MODULE_PARM(noypan, "i");
+MODULE_PARM_DESC(noypan,
+        "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
+	"will be performed by redrawing the screen. This required 2D acceleration, so\n"
+	"if the option noaccel is set, y-panning will be disabled. (default: 0)");
+
+MODULE_PARM(inverse, "i");
+MODULE_PARM_DESC(inverse,
+        "\nSetting this to anything but 0 should invert the display colors, but this\n"
+	"does not seem to work. (default: 0)");
 
 int init_module(void)
 {
-	if (mode)
+	if(mode)
 		sisfb_search_mode(mode);
-	else  /* TW: set mode=none if no mode parameter is given */
+	else if(vesa != -1)
+		sisfb_search_vesamode(vesa);
+	else  /* TW: set mode=none if no mode is given - we do this only if we are a module */
 		sisfb_mode_idx = MODE_INDEX_NONE;
 
 	ivideo.refresh_rate = rate;
 
-	if (forcecrt2type)
+	if(forcecrt2type)
 		sisfb_search_crt2type(forcecrt2type);
 
-	if (crt1off == 0)
+	if(crt1off == 0)
 		sisfb_crt1off = 1;
 	else
 		sisfb_crt1off = 0;
 
 	sisfb_forcecrt1 = forcecrt1;
-	if (forcecrt1 == 1)
+	if(forcecrt1 == 1)
 		sisfb_crt1off = 0;
-	else if (forcecrt1 == 0)
+	else if(forcecrt1 == 0)
 		sisfb_crt1off = 1;
 
-	if (mem)
-		sisfb_mem = mem;
+	if(noaccel == 1)      sisfb_accel = 0;
+	else if(noaccel == 0) sisfb_accel = 1;
 
-	enable_dstn = dstn; /* JennyLee 20011211 */
+	if(noypan == 1)       sisfb_ypan = 0;
+	else if(noypan == 0)  sisfb_ypan = 1;
 
-	if (queuemode)
-		sisfb_search_queuemode(queuemode);
+	/* TW: Panning only with acceleration */
+	if(sisfb_accel == 0)  sisfb_ypan = 0;
 
-	if(sisfb_init()<0)
-		return -ENODEV;
+	if(inverse)           sisfb_inverse = 1;
+
+	if(mem)		      sisfb_mem = mem;
+
+	enable_dstn = dstn;
+
+	/* TW: DSTN overrules forcecrt2type */
+	if (enable_dstn)      sisfb_crt2type = DISPTYPE_LCD;
+
+	if (queuemode)        sisfb_search_queuemode(queuemode);
+	/* TW: If other queuemode than MMIO, disable 2D accel any ypan */
+	if((sisfb_queuemode != -1) && (sisfb_queuemode != MMIO_CMD)) {
+	        sisfb_accel = 0;
+		sisfb_ypan = 0;
+	}
+
+        if(pdc) {
+	   if(!(pdc & ~0x3c)) {
+	        sisfb_pdc = pdc & 0x3c;
+	   }
+	}
+
+	if(sisfb_init() < 0) return -ENODEV;
 
 	return 0;
 }
@@ -3423,14 +4091,17 @@
 	/* TW: Release mem regions */
 	release_mem_region(ivideo.video_base, ivideo.video_size);
 	release_mem_region(ivideo.mmio_base, sisfb_mmio_size);
+#ifdef CONFIG_MTRR
 	/* TW: Release MTRR region */
-	if (ivideo.mtrr) mtrr_del(ivideo.mtrr, 
+	if(ivideo.mtrr) mtrr_del(ivideo.mtrr,
 			      (unsigned int)ivideo.video_base,
 	                      (unsigned int)ivideo.video_size);
+#endif
 	/* Unregister the framebuffer */
-	unregister_framebuffer(&fb_info);
+	unregister_framebuffer(&sis_fb_info);
 	printk(KERN_INFO "sisfb: Module unloaded\n");
 }
+
 #endif
 
 EXPORT_SYMBOL(sis_malloc);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/sis/sis_main.h linux.20pre10-ac2/drivers/video/sis/sis_main.h
--- linux.20pre10/drivers/video/sis/sis_main.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/sis/sis_main.h	2002-10-11 00:17:32.000000000 +0100
@@ -1,16 +1,22 @@
 #ifndef _SISFB_MAIN
 #define _SISFB_MAIN
 
-/* Comments and changes marked with "TW" by Thomas Winischhofer <tw@webit.com> */
+/* Comments and changes marked with "TW" by Thomas Winischhofer <thomas@winischhofer.net> */
+
+#include "vstruct.h"
 
 /* ------------------- Constant Definitions ------------------------- */
 
-#undef LINUXBIOS   /* turn on when use LINUXBIOS */
+#undef LINUXBIOS   /* turn this on when compiling for LINUXBIOS */
 #define AGPOFF     /* default is turn off AGP */
 
+#define SISFAIL(x) do { printk(x "\n"); return -EINVAL; } while(0)
+
 #define VER_MAJOR                 1
-#define VER_MINOR                 3
-#define VER_LEVEL                 13 
+#define VER_MINOR                 5
+#define VER_LEVEL                 7
+
+#include "sis.h"
 
 /* TW: To be included in pci_ids.h */
 #ifndef PCI_DEVICE_ID_SI_650_VGA
@@ -21,17 +27,13 @@
 #endif
 /* TW end */
 
-#define DEFAULT_MODE              3
-#define DEFAULT_LCDMODE           12
-#define DEFAULT_TVMODE            12
-#define MODE_INDEX_NONE           0 /* TW: index for mode=none */
-
 #define MAX_ROM_SCAN              0x10000
 
-#define TURBO_QUEUE_CAP           0x80
-#define HW_CURSOR_CAP             0x40
-#define AGP_CMD_QUEUE_CAP         0x80
-#define VM_CMD_QUEUE_CAP          0x20
+#define HW_CURSOR_CAP             0x80
+#define TURBO_QUEUE_CAP           0x40
+#define AGP_CMD_QUEUE_CAP         0x20
+#define VM_CMD_QUEUE_CAP          0x10
+#define MMIO_CMD_QUEUE_CAP        0x08
 
 /* For 300 series */
 #ifdef CONFIG_FB_SIS_300
@@ -68,6 +70,19 @@
 #define VB_PART4_ADR              (0x14-0x30)
 #define VB_PART4_DATA             (0x15-0x30)
 
+#define SISSR			  SiS_Pr.SiS_P3c4
+#define SISCR                     SiS_Pr.SiS_P3d4
+#define SISDACA                   SiS_Pr.SiS_P3c8
+#define SISDACD                   SiS_Pr.SiS_P3c9
+#define SISPART1                  SiS_Pr.SiS_Part1Port
+#define SISPART2                  SiS_Pr.SiS_Part2Port
+#define SISPART3                  SiS_Pr.SiS_Part3Port
+#define SISPART4                  SiS_Pr.SiS_Part4Port
+#define SISPART5                  SiS_Pr.SiS_Part5Port
+#define SISDAC2A                  SISPART5
+#define SISDAC2D                  (SISPART5 + 1)
+#define SISMISCR                  (SiS_Pr.RelIO + 0x1c)
+
 #define IND_SIS_PASSWORD          0x05  /* SRs */
 #define IND_SIS_COLOR_MODE        0x06
 #define IND_SIS_RAMDAC_CONTROL    0x07
@@ -92,16 +107,14 @@
 #define IND_SIS_SCRATCH_REG_CR37  0x37
 #define IND_SIS_AGP_IO_PAD        0x48
 
-#define IND_BRI_DRAM_STATUS       0x63 /* PCI memory size offset */
+#define IND_BRI_DRAM_STATUS       0x63 /* PCI config memory size offset */
 
 #define MMIO_QUEUE_PHYBASE        0x85C0
 #define MMIO_QUEUE_WRITEPORT      0x85C4
 #define MMIO_QUEUE_READPORT       0x85C8
 
-/* Eden Chen; TW */
 #define IND_SIS_CRT2_WRITE_ENABLE_300 0x24
 #define IND_SIS_CRT2_WRITE_ENABLE_315 0x2F
-/* ~Eden Chen; TW */
 
 #define SIS_PASSWORD              0x86  /* SR05 */
 #define SIS_INTERLACED_MODE       0x20  /* SR06 */
@@ -109,7 +122,7 @@
 #define SIS_15BPP_COLOR_MODE      0x1 
 #define SIS_16BPP_COLOR_MODE      0x2 
 #define SIS_32BPP_COLOR_MODE      0x4 
-#define SIS_DRAM_SIZE_MASK        0x3F  /* SR14 */
+#define SIS_DRAM_SIZE_MASK        0x3F  /* 300/630/730 SR14 */
 #define SIS_DRAM_SIZE_1MB         0x00
 #define SIS_DRAM_SIZE_2MB         0x01
 #define SIS_DRAM_SIZE_4MB         0x03
@@ -122,7 +135,7 @@
 #define SIS_DATA_BUS_64           0x01
 #define SIS_DATA_BUS_128          0x02
 
-#define SIS315_DRAM_SIZE_MASK     0xF0  /* 315/640?/740? SR14 */
+#define SIS315_DRAM_SIZE_MASK     0xF0  /* 315 SR14 */
 #define SIS315_DRAM_SIZE_2MB      0x01
 #define SIS315_DRAM_SIZE_4MB      0x02
 #define SIS315_DRAM_SIZE_8MB      0x03
@@ -139,7 +152,7 @@
 #define SIS315_ASYM_DDR		  	0x02
 #define SIS315_DUAL_CHANNEL_1_RANK    	0x3
 
-#define SIS550_DRAM_SIZE_MASK     0x3F  /* 550/650 SR14 */
+#define SIS550_DRAM_SIZE_MASK     0x3F  /* 550/650/740 SR14 */
 #define SIS550_DRAM_SIZE_4MB      0x00
 #define SIS550_DRAM_SIZE_8MB      0x01
 #define SIS550_DRAM_SIZE_16MB     0x03
@@ -157,7 +170,7 @@
 #define SIS_MEM_MAP_IO_ENABLE     0x01  /* SR20 */
 #define SIS_PCI_ADDR_ENABLE       0x80
 
-#define SIS_AGP_CMDQUEUE_ENABLE   0x80  /* 315 SR26 */
+#define SIS_AGP_CMDQUEUE_ENABLE   0x80  /* 315/650/740 SR26 */
 #define SIS_VRAM_CMDQUEUE_ENABLE  0x40
 #define SIS_MMIO_CMD_ENABLE       0x20
 #define SIS_CMD_QUEUE_SIZE_512k   0x00
@@ -175,8 +188,10 @@
 #define SIS_VB_OUTPUT_LCD         0x20
 #define SIS_VB_OUTPUT_CRT2        0x40
 #define SIS_VB_OUTPUT_HIVISION    0x80
+
 #define SIS_VB_OUTPUT_DISABLE     0x20  /* CR31 */
 #define SIS_DRIVER_MODE           0x40
+
 #define SIS_VB_COMPOSITE          0x01  /* CR32 */
 #define SIS_VB_SVIDEO             0x02
 #define SIS_VB_SCART              0x04
@@ -185,23 +200,21 @@
 #define SIS_CRT1                  0x20
 #define SIS_VB_HIVISION           0x40
 #define SIS_VB_DVI                0x80
-#define SIS_VB_TV                 (SIS_VB_COMPOSITE | SIS_VB_SVIDEO | SIS_VB_SCART | SIS_VB_HIVISION)
-#define SIS_LCD_PANEL_800X600     0x1   /* CR36 */
-#define SIS_LCD_PANEL_1024X768    0x2
-#define SIS_LCD_PANEL_1280X1024   0x3
-#define SIS_LCD_PANEL_1280X960    0x4
-#define SIS_LCD_PANEL_640X480     0x5
-#define SIS_LCD_PANEL_1600x1200   0x6  /* TW */
-#define SIS_LCD_PANEL_320x480	  0x7  /* TW: FSTN */
-#define SIS_EXTERNAL_CHIP_MASK    0x0E  /* CR37 */
-#define SIS_EXTERNAL_CHIP_SIS301        0x01
-#define SIS_EXTERNAL_CHIP_LVDS          0x02  
-#define SIS_EXTERNAL_CHIP_TRUMPION      0x03
-#define SIS_EXTERNAL_CHIP_LVDS_CHRONTEL 0x04
-#define SIS_EXTERNAL_CHIP_CHRONTEL      0x05
+#define SIS_VB_TV                 (SIS_VB_COMPOSITE | SIS_VB_SVIDEO | \
+                                   SIS_VB_SCART | SIS_VB_HIVISION)
+
+#define SIS_EXTERNAL_CHIP_MASK    	   0x0E  /* CR37 */
+#define SIS_EXTERNAL_CHIP_SIS301           0x01  /* in CR37 << 1 ! */
+#define SIS_EXTERNAL_CHIP_LVDS             0x02  /* in CR37 << 1 ! */
+#define SIS_EXTERNAL_CHIP_TRUMPION         0x03  /* in CR37 << 1 ! */
+#define SIS_EXTERNAL_CHIP_LVDS_CHRONTEL    0x04  /* in CR37 << 1 ! */
+#define SIS_EXTERNAL_CHIP_CHRONTEL         0x05  /* in CR37 << 1 ! */
+#define SIS310_EXTERNAL_CHIP_LVDS          0x02  /* in CR37 << 1 ! */
+#define SIS310_EXTERNAL_CHIP_LVDS_CHRONTEL 0x03  /* in CR37 << 1 ! */
+
 #define SIS_AGP_2X                0x20  /* CR48 */
 
-#define BRI_DRAM_SIZE_MASK        0x70  /* PCI bridge */
+#define BRI_DRAM_SIZE_MASK        0x70  /* PCI bridge config data */
 #define BRI_DRAM_SIZE_2MB         0x00
 #define BRI_DRAM_SIZE_4MB         0x01
 #define BRI_DRAM_SIZE_8MB         0x02
@@ -209,44 +222,99 @@
 #define BRI_DRAM_SIZE_32MB        0x04
 #define BRI_DRAM_SIZE_64MB        0x05
 
-// Eden Chen
 #define HW_DEVICE_EXTENSION	  SIS_HW_DEVICE_INFO
 #define PHW_DEVICE_EXTENSION      PSIS_HW_DEVICE_INFO
 
 #define SR_BUFFER_SIZE            5
 #define CR_BUFFER_SIZE            5
-// ~Eden Chen
 
-int enable_dstn = 0;
+/* Useful macros */
+#define inSISREG(base)          inb(base)
+#define outSISREG(base,val)     outb(val,base)
+#define orSISREG(base,val)      do { \
+                                  unsigned char __Temp = inb(base); \
+                                  outSISREG(base, __Temp | (val)); \
+                                } while (0)
+#define andSISREG(base,val)     do { \
+                                  unsigned char __Temp = inb(base); \
+                                  outSISREG(base, __Temp & (val)); \
+                                } while (0)
+#define inSISIDXREG(base,idx,var)   do { \
+                                      outb(idx,base); var=inb((base)+1); \
+                                    } while (0)
+#define outSISIDXREG(base,idx,val)  do { \
+                                      outb(idx,base); outb((val),(base)+1); \
+                                    } while (0)
+#define orSISIDXREG(base,idx,val)   do { \
+                                      unsigned char __Temp; \
+                                      outb(idx,base);   \
+                                      __Temp = inb((base)+1)|(val); \
+                                      outSISIDXREG(base,idx,__Temp); \
+                                    } while (0)
+#define andSISIDXREG(base,idx,and)  do { \
+                                      unsigned char __Temp; \
+                                      outb(idx,base);   \
+                                      __Temp = inb((base)+1)&(and); \
+                                      outSISIDXREG(base,idx,__Temp); \
+                                    } while (0)
+#define setSISIDXREG(base,idx,and,or)   do { \
+                                          unsigned char __Temp; \
+                                          outb(idx,base);   \
+                                          __Temp = (inb((base)+1)&(and))|(or); \
+                                          outSISIDXREG(base,idx,__Temp); \
+                                        } while (0)
 
 /* ------------------- Global Variables ----------------------------- */
 
 /* Fbcon variables */
-static struct fb_info fb_info;
-static struct display disp;
-static int video_type = FB_TYPE_PACKED_PIXELS;
-static int video_linelength;
-static int video_cmap_len;
+static struct fb_info sis_fb_info;
+
+static struct display sis_disp;
+
+static int    video_type = FB_TYPE_PACKED_PIXELS;
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
 static struct display_switch sisfb_sw;
+#endif
+
 static struct fb_var_screeninfo default_var = {
-	0, 0, 0, 0,
-	0, 0,
-	0,
-	0,
-	{0, 8, 0},
-	{0, 8, 0},
-	{0, 8, 0},
-	{0, 0, 0},
-	0,
-	FB_ACTIVATE_NOW, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0,
-	0,
-	FB_VMODE_NONINTERLACED,
-	{0, 0, 0, 0, 0, 0}
+	xres:           0,
+	yres:           0,
+	xres_virtual:   0,
+	yres_virtual:   0,
+	xoffset:        0,
+	yoffset:        0,
+	bits_per_pixel: 0,
+	grayscale:      0,
+	red:            {0, 8, 0},
+	green:          {0, 8, 0},
+	blue:           {0, 8, 0},
+	transp:         {0, 0, 0},
+	nonstd:         0,
+	activate:       FB_ACTIVATE_NOW,
+	height:         -1,
+	width:          -1,
+	accel_flags:    0,
+	pixclock:       0,
+	left_margin:    0,
+	right_margin:   0,
+	upper_margin:   0,
+	lower_margin:   0,
+	hsync_len:      0,
+	vsync_len:      0,
+	sync:           0,
+	vmode:          FB_VMODE_NONINTERLACED,
+	reserved:       {0, 0, 0, 0, 0, 0}
 };
 
 static struct {
 	u16 blue, green, red, pad;
-} palette[256];
+} sis_palette[256];
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+static u32 pseudo_palette[17];
+#endif
+
 static union {
 #ifdef FBCON_HAS_CFB16
 	u16 cfb16[16];
@@ -257,7 +325,7 @@
 #ifdef FBCON_HAS_CFB32
 	u32 cfb32[16];
 #endif
-} fbcon_cmap;
+} sis_fbcon_cmap;
 
 /* display status */
 static int sisfb_off = 0;
@@ -265,45 +333,50 @@
 static int sisfb_forcecrt1 = -1;
 static int sisfb_inverse = 0;
 static int sisvga_enabled = 0;
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,23)
 static int currcon = 0;
-/*karl*/
+#endif
+
+/* global flags */
 static int sisfb_tvmode = 0;
 static int sisfb_mem = 0;
+static int sisfb_pdc = 0;
+static int enable_dstn = 0;
+static int sisfb_accel = -1;
+static int sisfb_ypan = -1;
 
-static enum _VGA_ENGINE {
-	UNKNOWN_VGA = 0,
-	SIS_300_VGA,
-	SIS_315_VGA,
-} sisvga_engine = UNKNOWN_VGA;
+VGA_ENGINE sisvga_engine = UNKNOWN_VGA;
 
-/* TW: These are to adapted to VGA_ENGINE type */
+/* TW: These are to adapted according to VGA_ENGINE type */
 static int sisfb_hwcursor_size = 0;
 static int sisfb_CRT2_write_enable = 0;
 
-/* mode-related variables */
-int sisfb_mode_idx = MODE_INDEX_NONE;  /* (TW) was -1 */
-u8  sisfb_mode_no = 0;
-u8  sisfb_rate_idx = 0;
-
-int sisfb_crt2type = -1;	/* TW: CRT2 type (for overriding autodetection) */
+int sisfb_crt2type  = -1;	/* TW: CRT2 type (for overriding autodetection) */
+int sisfb_tvplug    = -1;	/* PR: Tv plug type (for overriding autodetection) */
 
-int sisfb_queuemode = -1; 	/* TW: Use MMIO queue mode by default (310 series only) */
+int sisfb_queuemode = -1; 	/* TW: Use MMIO queue mode by default (310/325 series only) */
 
-/* data for sis components*/
+/* data for sis components */
 struct video_info ivideo;
 
-// Eden Chen
+/* TW: For ioctl SISFB_GET_INFO */
+sisfb_info sisfbinfo;
+
+/* TW: Hardware extension; contains data on hardware */
 HW_DEVICE_EXTENSION sishw_ext = {
-	NULL, NULL, NULL, NULL,
+	NULL, NULL, FALSE, NULL, NULL,
 	0, 0, 0, 0, 0, 0, 0, 0, 0,
 	NULL, NULL, NULL, NULL,
-	{0, 0, 0, 0}
+	{0, 0, 0, 0},
+	0
 };
-// ~Eden Chen
+
+/* TW: SiS private structure */
+SiS_Private  SiS_Pr;
 
 /* card parameters */
 static unsigned long sisfb_mmio_size = 0;
-static u8 sisfb_caps = 0;
+static u8            sisfb_caps = 0;
 
 typedef enum _SIS_CMDTYPE {
 	MMIO_CMD = 0,
@@ -317,118 +390,203 @@
 	const char *name;
 } sisdev_list[] = {
 	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_300,     "SIS 300"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, "SIS 540"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, "SIS 630"},
+	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_540_VGA, "SIS 540 VGA"},
+	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630_VGA, "SIS 630/730 VGA"},
 	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315H,    "SIS 315H"},
 	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315,     "SIS 315"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315PRO,  "SIS 315Pro"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_550_VGA, "SIS 550"},
-	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650_VGA, "SIS 650 VGA"},
+	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_315PRO,  "SIS 315PRO"},
+	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_550_VGA, "SIS 550 VGA"},
+	{PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650_VGA, "SIS 650/M650/651/740 VGA"},
 	{0, 0, NULL}
 };
 
+#define MD_SIS300 1
+#define MD_SIS315 2
+
 /* mode table */
-static const struct _sisbios_mode {
+/* NOT const - will be patched for 1280x960 mode number chaos reasons */
+struct _sisbios_mode {
 	char name[15];
 	u8 mode_no;
+	u16 vesa_mode_no_1;  /* "SiS defined" VESA mode number */
+	u16 vesa_mode_no_2;  /* Real VESA mode numbers */
 	u16 xres;
 	u16 yres;
 	u16 bpp;
 	u16 rate_idx;
 	u16 cols;
 	u16 rows;
+	u8  chipset;
 } sisbios_mode[] = {
-	{"none", 0xFF, 0, 0, 0, 0, 0, 0}, 		    /* TW: for mode "none" */
-	{"320x240x16",   0x56,  320,  240, 16, 1,  40, 15},
-	{"320x480x8",    0x5A,  320,  480,  8, 1,  40, 30},
-	{"320x480x16",   0x5B,  320,  480, 16, 1,  40, 30},
-	{"640x480x8",    0x2E,  640,  480,  8, 1,  80, 30},
-	{"640x480x16",   0x44,  640,  480, 16, 1,  80, 30},
-	{"640x480x24",   0x62,  640,  480, 32, 1,  80, 30}, /* TW: That's for people who mix up color- and fb depth */
-	{"640x480x32",   0x62,  640,  480, 32, 1,  80, 30},
-	{"720x480x8",    0x31,  720,  480,  8, 1,  90, 30},
-	{"720x480x16",   0x33,  720,  480, 16, 1,  90, 30},
-	{"720x480x24",   0x35,  720,  480, 32, 1,  90, 30}, /* TW */
-	{"720x480x32",   0x35,  720,  480, 32, 1,  90, 30},
-	{"720x576x8",    0x32,  720,  576,  8, 1,  90, 36},
-	{"720x576x16",   0x34,  720,  576, 16, 1,  90, 36},
-	{"720x576x24",   0x36,  720,  576, 32, 1,  90, 36}, /* TW */
-	{"720x576x32",   0x36,  720,  576, 32, 1,  90, 36},
-	{"800x600x8",    0x30,  800,  600,  8, 2, 100, 37},
-	{"800x600x16",   0x47,  800,  600, 16, 2, 100, 37},
-	{"800x600x24",   0x63,  800,  600, 32, 2, 100, 37}, /* TW */
-	{"800x600x32",   0x63,  800,  600, 32, 2, 100, 37},
-	{"1024x768x8",   0x38, 1024,  768,  8, 2, 128, 48},
-	{"1024x768x16",  0x4A, 1024,  768, 16, 2, 128, 48},
-	{"1024x768x24",  0x64, 1024,  768, 32, 2, 128, 48}, /* TW */
-	{"1024x768x32",  0x64, 1024,  768, 32, 2, 128, 48},
-	{"1280x960x8",   0x7C, 1280,  960,  8, 1, 160, 60}, /* TW */
-	{"1280x960x16",  0x7D, 1280,  960, 16, 1, 160, 60}, /* TW */
-	{"1280x960x24",  0x7E, 1280,  960, 32, 1, 160, 60}, /* TW */
-	{"1280x960x32",  0x7E, 1280,  960, 32, 1, 160, 60}, /* TW */
-	{"1280x1024x8",  0x3A, 1280, 1024,  8, 2, 160, 64},
-	{"1280x1024x16", 0x4D, 1280, 1024, 16, 2, 160, 64},
-	{"1280x1024x24", 0x65, 1280, 1024, 32, 2, 160, 64}, /* TW */
-	{"1280x1024x32", 0x65, 1280, 1024, 32, 2, 160, 64},
-	{"1600x1200x8",  0x3C, 1600, 1200,  8, 1, 200, 75},
-	{"1600x1200x16", 0x3D, 1600, 1200, 16, 1, 200, 75},
-	{"1600x1200x24", 0x66, 1600, 1200, 32, 1, 200, 75}, /* TW */
-	{"1600x1200x32", 0x66, 1600, 1200, 32, 1, 200, 75},
-	{"1920x1440x8",  0x68, 1920, 1440,  8, 1, 240, 75},
-	{"1920x1440x16", 0x69, 1920, 1440, 16, 1, 240, 75},
-	{"1920x1440x24", 0x6B, 1920, 1440, 32, 1, 240, 75}, /* TW */
-	{"1920x1440x32", 0x6B, 1920, 1440, 32, 1, 240, 75},
-	{"\0", 0x00, 0, 0, 0, 0, 0, 0}
+#define MODE_INDEX_NONE           0  /* TW: index for mode=none */
+	{"none",         0xFF, 0x0000, 0x0000,    0,    0,  0, 0,   0,  0, MD_SIS300|MD_SIS315},  /* TW: for mode "none" */
+	{"320x240x16",   0x56, 0x0000, 0x0000,  320,  240, 16, 1,  40, 15,           MD_SIS315},
+	{"320x480x8",    0x5A, 0x0000, 0x0000,  320,  480,  8, 1,  40, 30,           MD_SIS315},  /* TW: FSTN */
+	{"320x480x16",   0x5B, 0x0000, 0x0000,  320,  480, 16, 1,  40, 30,           MD_SIS315},  /* TW: FSTN */
+	{"640x480x8",    0x2E, 0x0101, 0x0101,  640,  480,  8, 1,  80, 30, MD_SIS300|MD_SIS315},
+	{"640x480x16",   0x44, 0x0111, 0x0111,  640,  480, 16, 1,  80, 30, MD_SIS300|MD_SIS315},
+	{"640x480x24",   0x62, 0x013a, 0x0112,  640,  480, 32, 1,  80, 30, MD_SIS300|MD_SIS315},  /* TW: That's for people who mix up color- and fb depth */
+	{"640x480x32",   0x62, 0x013a, 0x0112,  640,  480, 32, 1,  80, 30, MD_SIS300|MD_SIS315},
+	{"720x480x8",    0x31, 0x0000, 0x0000,  720,  480,  8, 1,  90, 30, MD_SIS300|MD_SIS315},
+	{"720x480x16",   0x33, 0x0000, 0x0000,  720,  480, 16, 1,  90, 30, MD_SIS300|MD_SIS315},
+	{"720x480x24",   0x35, 0x0000, 0x0000,  720,  480, 32, 1,  90, 30, MD_SIS300|MD_SIS315},
+	{"720x480x32",   0x35, 0x0000, 0x0000,  720,  480, 32, 1,  90, 30, MD_SIS300|MD_SIS315},
+	{"720x576x8",    0x32, 0x0000, 0x0000,  720,  576,  8, 1,  90, 36, MD_SIS300|MD_SIS315},
+	{"720x576x16",   0x34, 0x0000, 0x0000,  720,  576, 16, 1,  90, 36, MD_SIS300|MD_SIS315},
+	{"720x576x24",   0x36, 0x0000, 0x0000,  720,  576, 32, 1,  90, 36, MD_SIS300|MD_SIS315},
+	{"720x576x32",   0x36, 0x0000, 0x0000,  720,  576, 32, 1,  90, 36, MD_SIS300|MD_SIS315},
+	{"800x480x8",    0x70, 0x0000, 0x0000,  800,  480,  8, 1, 100, 30,           MD_SIS315},  /* TW: 310/325 series only */
+	{"800x480x16",   0x7a, 0x0000, 0x0000,  800,  480, 16, 1, 100, 30,           MD_SIS315},
+	{"800x480x24",   0x76, 0x0000, 0x0000,  800,  480, 32, 1, 100, 30,           MD_SIS315},
+	{"800x480x32",   0x76, 0x0000, 0x0000,  800,  480, 32, 1, 100, 30,           MD_SIS315},
+#define DEFAULT_MODE              20 /* TW: index for 800x600x8 */
+#define DEFAULT_LCDMODE           20 /* TW: index for 800x600x8 */
+#define DEFAULT_TVMODE            20 /* TW: index for 800x600x8 */
+	{"800x600x8",    0x30, 0x0103, 0x0103,  800,  600,  8, 2, 100, 37, MD_SIS300|MD_SIS315},
+	{"800x600x16",   0x47, 0x0114, 0x0114,  800,  600, 16, 2, 100, 37, MD_SIS300|MD_SIS315},
+	{"800x600x24",   0x63, 0x013b, 0x0115,  800,  600, 32, 2, 100, 37, MD_SIS300|MD_SIS315},
+	{"800x600x32",   0x63, 0x013b, 0x0115,  800,  600, 32, 2, 100, 37, MD_SIS300|MD_SIS315},
+	{"1024x576x8",   0x71, 0x0000, 0x0000, 1024,  576,  8, 1, 128, 36,           MD_SIS315},  /* TW: 310/325 series only */
+	{"1024x576x16",  0x74, 0x0000, 0x0000, 1024,  576, 16, 1, 128, 36,           MD_SIS315},
+	{"1024x576x24",  0x77, 0x0000, 0x0000, 1024,  576, 32, 1, 128, 36,           MD_SIS315},
+	{"1024x576x32",  0x77, 0x0000, 0x0000, 1024,  576, 32, 1, 128, 36,           MD_SIS315},
+	{"1024x600x8",   0x20, 0x0000, 0x0000, 1024,  600,  8, 1, 128, 37, MD_SIS300          },  /* TW: 300 series only */
+	{"1024x600x16",  0x21, 0x0000, 0x0000, 1024,  600, 16, 1, 128, 37, MD_SIS300          },
+	{"1024x600x24",  0x22, 0x0000, 0x0000, 1024,  600, 32, 1, 128, 37, MD_SIS300          },
+	{"1024x600x32",  0x22, 0x0000, 0x0000, 1024,  600, 32, 1, 128, 37, MD_SIS300          },
+	{"1024x768x8",   0x38, 0x0105, 0x0105, 1024,  768,  8, 2, 128, 48, MD_SIS300          },
+	{"1024x768x16",  0x4A, 0x0117, 0x0117, 1024,  768, 16, 2, 128, 48, MD_SIS300          },
+	{"1024x768x24",  0x64, 0x013c, 0x0118, 1024,  768, 32, 2, 128, 48, MD_SIS300          },
+	{"1024x768x32",  0x64, 0x013c, 0x0118, 1024,  768, 32, 2, 128, 48, MD_SIS300          },
+	{"1152x768x8",   0x23, 0x0000, 0x0000, 1152,  768,  8, 1, 144, 48, MD_SIS300          },  /* TW: 300 series only */
+	{"1152x768x16",  0x24, 0x0000, 0x0000, 1152,  768, 16, 1, 144, 48, MD_SIS300          },
+	{"1152x768x24",  0x25, 0x0000, 0x0000, 1152,  768, 32, 1, 144, 48, MD_SIS300          },
+	{"1152x768x32",  0x25, 0x0000, 0x0000, 1152,  768, 32, 1, 144, 48, MD_SIS300          },
+	{"1280x720x8",   0x79, 0x0000, 0x0000, 1280,  720,  8, 1, 160, 45,           MD_SIS315},  /* TW: 310/325 series only */
+	{"1280x720x16",  0x75, 0x0000, 0x0000, 1280,  720, 16, 1, 160, 45,           MD_SIS315},
+	{"1280x720x24",  0x78, 0x0000, 0x0000, 1280,  720, 32, 1, 160, 45,           MD_SIS315},
+	{"1280x720x32",  0x78, 0x0000, 0x0000, 1280,  720, 32, 1, 160, 45,           MD_SIS315},
+	{"1280x768x8",   0x23, 0x0000, 0x0000, 1280,  768,  8, 1, 160, 48,           MD_SIS315},  /* TW: 310/325 series only */
+	{"1280x768x16",  0x24, 0x0000, 0x0000, 1280,  768, 16, 1, 160, 48,           MD_SIS315},
+	{"1280x768x24",  0x25, 0x0000, 0x0000, 1280,  768, 32, 1, 160, 48,           MD_SIS315},
+	{"1280x768x32",  0x25, 0x0000, 0x0000, 1280,  768, 32, 1, 160, 48,           MD_SIS315},
+#define MODEINDEX_1280x960 48
+	{"1280x960x8",   0x7C, 0x0000, 0x0000, 1280,  960,  8, 1, 160, 60, MD_SIS300|MD_SIS315},  /* TW: Modenumbers being patched */
+	{"1280x960x16",  0x7D, 0x0000, 0x0000, 1280,  960, 16, 1, 160, 60, MD_SIS300|MD_SIS315},
+	{"1280x960x24",  0x7E, 0x0000, 0x0000, 1280,  960, 32, 1, 160, 60, MD_SIS300|MD_SIS315},
+	{"1280x960x32",  0x7E, 0x0000, 0x0000, 1280,  960, 32, 1, 160, 60, MD_SIS300|MD_SIS315},
+	{"1280x1024x8",  0x3A, 0x0107, 0x0107, 1280, 1024,  8, 2, 160, 64, MD_SIS300|MD_SIS315},
+	{"1280x1024x16", 0x4D, 0x011a, 0x011a, 1280, 1024, 16, 2, 160, 64, MD_SIS300|MD_SIS315},
+	{"1280x1024x24", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 2, 160, 64, MD_SIS300|MD_SIS315},
+	{"1280x1024x32", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 2, 160, 64, MD_SIS300|MD_SIS315},
+	{"1400x1050x8",  0x26, 0x0000, 0x0000, 1400, 1050,  8, 1, 175, 65,           MD_SIS315},  /* TW: 310/325 series only */
+	{"1400x1050x16", 0x27, 0x0000, 0x0000, 1400, 1050, 16, 1, 175, 65,           MD_SIS315},
+	{"1400x1050x24", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65,           MD_SIS315},
+	{"1400x1050x32", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65,           MD_SIS315},
+	{"1600x1200x8",  0x3C, 0x0130, 0x011c, 1600, 1200,  8, 1, 200, 75, MD_SIS300|MD_SIS315},
+	{"1600x1200x16", 0x3D, 0x0131, 0x011e, 1600, 1200, 16, 1, 200, 75, MD_SIS300|MD_SIS315},
+	{"1600x1200x24", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315},
+	{"1600x1200x32", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_SIS300|MD_SIS315},
+	{"1920x1440x8",  0x68, 0x013f, 0x0000, 1920, 1440,  8, 1, 240, 75, MD_SIS300|MD_SIS315},
+	{"1920x1440x16", 0x69, 0x0140, 0x0000, 1920, 1440, 16, 1, 240, 75, MD_SIS300|MD_SIS315},
+	{"1920x1440x24", 0x6B, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315},
+	{"1920x1440x32", 0x6B, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_SIS300|MD_SIS315},
+	{"2048x1536x8",  0x6c, 0x0000, 0x0000, 2048, 1536,  8, 1, 256, 96,           MD_SIS315},  /* TW: 310/325 series only */
+	{"2048x1536x16", 0x6d, 0x0000, 0x0000, 2048, 1536, 16, 1, 256, 96,           MD_SIS315},
+	{"2048x1536x24", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96,           MD_SIS315},
+	{"2048x1536x32", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96,           MD_SIS315},
+	{"\0", 0x00, 0, 0, 0, 0, 0, 0, 0}
 };
 
+/* mode-related variables */
+#ifdef MODULE
+int sisfb_mode_idx = MODE_INDEX_NONE;  /* Don't use a mode by default if we are a module */
+#else
+int sisfb_mode_idx = -1;               /* Use a default mode if we are inside the kernel */
+#endif
+u8  sisfb_mode_no  = 0;
+u8  sisfb_rate_idx = 0;
+
+/* TW: CR36 evaluation */
+const USHORT sis300paneltype[] =
+    { LCD_UNKNOWN,   LCD_800x600,  LCD_1024x768,  LCD_1280x1024,
+      LCD_1280x960,  LCD_640x480,  LCD_1024x600,  LCD_1152x768,
+      LCD_320x480,   LCD_1024x768, LCD_1024x768,  LCD_1024x768,
+      LCD_1024x768,  LCD_1024x768, LCD_1024x768,  LCD_1024x768 };
+
+const USHORT sis310paneltype[] =
+    { LCD_UNKNOWN,   LCD_800x600,  LCD_1024x768,  LCD_1280x1024,
+      LCD_640x480,   LCD_1024x600, LCD_1152x864,  LCD_1280x960,
+      LCD_1152x768,  LCD_1400x1050,LCD_1280x768,  LCD_1600x1200,
+      LCD_320x480,   LCD_1024x768, LCD_1024x768,  LCD_1024x768 };
+
 static const struct _sis_crt2type {
-	char name[6];
+	char name[10];
 	int type_no;
+	int tvplug_no;
 } sis_crt2type[] = {
-	{"NONE", 0},
-	{"LCD",  DISPTYPE_LCD},
-	{"TV",   DISPTYPE_TV},
-	{"VGA",  DISPTYPE_CRT2},
-	{"none", 0},	/* TW: make it fool-proof */
-	{"lcd",  DISPTYPE_LCD},
-	{"tv",   DISPTYPE_TV},
-	{"vga",  DISPTYPE_CRT2},
-	{"\0",  -1}
+	{"NONE", 	0, 		-1},
+	{"LCD",  	DISPTYPE_LCD, 	-1},
+	{"TV",   	DISPTYPE_TV, 	-1},
+	{"VGA",  	DISPTYPE_CRT2, 	-1},
+	{"SVIDEO", 	DISPTYPE_TV, 	TVPLUG_SVIDEO},
+	{"COMPOSITE", 	DISPTYPE_TV, 	TVPLUG_COMPOSITE},
+	{"SCART", 	DISPTYPE_TV, 	TVPLUG_SCART},
+	{"none", 	0, 		-1},
+	{"lcd",  	DISPTYPE_LCD, 	-1},
+	{"tv",   	DISPTYPE_TV, 	-1},
+	{"vga",  	DISPTYPE_CRT2, 	-1},
+	{"svideo", 	DISPTYPE_TV, 	TVPLUG_SVIDEO},
+	{"composite", 	DISPTYPE_TV, 	TVPLUG_COMPOSITE},
+	{"scart", 	DISPTYPE_TV, 	TVPLUG_SCART},
+	{"\0",  	-1, 		-1}
 };
 
+/* Queue mode selection for 310 series */
 static const struct _sis_queuemode {
 	char name[6];
 	int type_no;
 } sis_queuemode[] = {
-	{"AGP",  AGP_CMD_QUEUE},
-	{"VRAM", VM_CMD_QUEUE},
-	{"MMIO", MMIO_CMD},
-	{"agp",  AGP_CMD_QUEUE},
-	{"vram", VM_CMD_QUEUE},
-	{"mmio", MMIO_CMD},
-	{"\0",  -1}
+	{"AGP",  	AGP_CMD_QUEUE},
+	{"VRAM", 	VM_CMD_QUEUE},
+	{"MMIO", 	MMIO_CMD},
+	{"agp",  	AGP_CMD_QUEUE},
+	{"vram", 	VM_CMD_QUEUE},
+	{"mmio", 	MMIO_CMD},
+	{"\0",   	-1}
 };
 
-static struct _sis_vrate {
+static const struct _sis_vrate {
 	u16 idx;
 	u16 xres;
 	u16 yres;
 	u16 refresh;
 } sisfb_vrate[] = {
-	{1,  640,  480,  60}, {2,  640, 480,  72}, {3,  640, 480,  75}, {4,  640, 480,  85},
-	{5,  640,  480, 100}, {6,  640, 480, 120}, {7,  640, 480, 160}, {8,  640, 480, 200},
-	{1,  720,  480,  60},
-	{1,  720,  576,  50},
-	{1,  800,  600,  56}, {2,  800, 600,  60}, {3,  800, 600,  72}, {4,  800, 600,  75},
-	{5,  800,  600,  85}, {6,  800, 600, 100}, {7,  800, 600, 120}, {8,  800, 600, 160},
-	{1, 1024,  768,  43}, {2, 1024, 768,  60}, {3, 1024, 768,  70}, {4, 1024, 768,  75},
-	{5, 1024,  768,  85}, {6, 1024, 768, 100}, {7, 1024, 768, 120},
-	{1, 1280, 1024,  43}, {2, 1280, 1024, 60}, {3, 1280, 1024, 75}, {4, 1280, 1024, 85},
-	/* TW: Values for 1280x960 guessed */
-	{1, 1280,  960,  43},  /* {1, 1280,  960, 60}, */
-	{1, 1600, 1200,  60}, {2, 1600, 1200, 65}, {3, 1600, 1200, 70}, {4, 1600, 1200, 75},
-	{5, 1600, 1200,  85},
-	{1, 1920, 1440,  60},
+	{1,  640,  480, 60}, {2,  640,  480,  72}, {3, 640,   480,  75}, {4,  640, 480,  85},
+	{5,  640,  480,100}, {6,  640,  480, 120}, {7, 640,   480, 160}, {8,  640, 480, 200},
+	{1,  720,  480, 60},
+	{1,  720,  576, 58},
+	{1,  800,  480, 60}, {2,  800,  480,  75}, {3, 800,   480,  85},
+	{1,  800,  600, 56}, {2,  800,  600,  60}, {3, 800,   600,  72}, {4,  800, 600,  75},
+	{5,  800,  600, 85}, {6,  800,  600, 100}, {7, 800,   600, 120}, {8,  800, 600, 160},
+	{1, 1024,  768, 43}, {2, 1024,  768,  60}, {3, 1024,  768,  70}, {4, 1024, 768,  75},
+	{5, 1024,  768, 85}, {6, 1024,  768, 100}, {7, 1024,  768, 120},
+	{1, 1024,  576, 60}, {2, 1024,  576,  65}, {3, 1024,  576,  75},
+	{1, 1024,  600, 60},
+	{1, 1152,  768, 60},
+	{1, 1280,  720, 60}, {2, 1280,  720,  75}, {3, 1280,  720,  85},
+	{1, 1280,  768, 60},
+	{1, 1280, 1024, 43}, {2, 1280, 1024,  60}, {3, 1280, 1024,  75}, {4, 1280, 1024,  85},
+	{1, 1280,  960, 60},
+	{1, 1400, 1050, 60},
+	{1, 1600, 1200, 60}, {2, 1600, 1200,  65}, {3, 1600, 1200,  70}, {4, 1600, 1200,  75},
+	{5, 1600, 1200, 85}, {6, 1600, 1200, 100}, {7, 1600, 1200, 120},
+	/* TW: Clock values for 1920x1440 guessed (except for the first one) */
+	{1, 1920, 1440, 60}, {2, 1920, 1440,  70}, {3, 1920, 1440,  75}, {4, 1920, 1440,  85},
+	{5, 1920, 1440,100}, {6, 1920, 1440, 120},
+	/* TW: Clock values for 2048x1536 guessed */
+	{1, 2048, 1536, 60}, {2, 2048, 1536,  70}, {3, 2048, 1536,  75}, {4, 2048, 1536,  85},
+	{5, 2048, 1536,100},
 	{0, 0, 0, 0}
 };
 
@@ -466,10 +624,10 @@
 static unsigned long sisfb_heap_start;
 static unsigned long sisfb_heap_end;
 static unsigned long sisfb_heap_size;
-static SIS_HEAP sisfb_heap;
+static SIS_HEAP      sisfb_heap;
 
 // Eden Chen
-static struct _sis_TV_filter {
+static const struct _sis_TV_filter {
 	u8 filter[9][4];
 } sis_TV_filter[] = {
 	{ {{0x00,0x00,0x00,0x40},  /* NTSCFilter_0 */
@@ -618,115 +776,134 @@
 	   {0xFF,0xFF,0xFF,0xFF} }}
 };
 
-static int filter = -1;
+static int           filter = -1;
 static unsigned char filter_tb;
 //~Eden Chen
 
-/* ---------------------- Routine Prototype ------------------------- */
+/* ---------------------- Routine prototypes ------------------------- */
 
 /* Interface used by the world */
-int sisfb_setup(char *options);
-static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info);
-static int sisfb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
-static int sisfb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
-static int sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info);
-static int sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info);
-static int sisfb_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, unsigned long arg, int con,
-		       struct fb_info *info);
+#ifndef MODULE
+int             sisfb_setup(char *options);
+#endif
+
+static int      sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			struct fb_info *info);
+static int      sisfb_get_var(struct fb_var_screeninfo *var, int con,
+			struct fb_info *info);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+static int      sisfb_set_par(struct fb_info *info);
+#endif
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+static int      sisfb_set_var(struct fb_var_screeninfo *var, int con,
+			struct fb_info *info);
+static int      sisfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			struct fb_info *info);
+static int      sisfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			struct fb_info *info);
+#endif
+static int      sisfb_ioctl(struct inode *inode, struct file *file,
+		       	unsigned int cmd, unsigned long arg, int con,
+		       	struct fb_info *info);
 
 /* Interface to the low level console driver */
-int sisfb_init(void);
-static int sisfb_update_var(int con, struct fb_info *info);
-static int sisfb_switch(int con, struct fb_info *info);
-static void sisfb_blank(int blank, struct fb_info *info);
+int             sisfb_init(void);
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+static int      sisfb_update_var(int con, struct fb_info *info);
+static int      sisfb_switch(int con, struct fb_info *info);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+static int      sisfb_blank(int blank, struct fb_info *info);
+#else
+static void     sisfb_blank(int blank, struct fb_info *info);
+#endif
 
 /* hardware access routines */
-void sisfb_set_reg1(u16 port, u16 index, u16 data);
-void sisfb_set_reg3(u16 port, u16 data);
-void sisfb_set_reg4(u16 port, unsigned long data);
-u8   sisfb_get_reg1(u16 port, u16 index);
-u8   sisfb_get_reg2(u16 port);
-u32  sisfb_get_reg3(u16 port);
-// Eden Chen
-//void sisfb_clear_DAC(u16 port);
-//void sisfb_clear_buffer(PHW_DEVICE_EXTENSION psishw_ext);
-// ~Eden Chen
+void            sisfb_set_reg4(u16 port, unsigned long data);
+u32             sisfb_get_reg3(u16 port);
+
+/* 2D accelerator functions */
+extern int      sisfb_initaccel(void);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+extern void     fbcon_sis_fillrect(struct fb_info *info, struct fb_fillrect *rect);
+extern void     fbcon_sis_copyarea(struct fb_info *info, struct fb_copyarea *area);
+extern void     cfb_imageblit(struct fb_info *info, struct fb_image *image);
+#endif
 
 /* Internal routines */
-static void sisfb_search_mode(const char *name);
-static void sisfb_validate_mode(void);
-static u8   sisfb_search_refresh_rate(unsigned int rate);
-static int  sis_getcolreg(unsigned regno, unsigned *red, unsigned *green,
-			 unsigned *blue, unsigned *transp,
-			 struct fb_info *fb_info);
-static int  sis_setcolreg(unsigned regno, unsigned red, unsigned green,
-			 unsigned blue, unsigned transp,
-			 struct fb_info *fb_info);
-static int  sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
-		      struct fb_info *info);
-static void sisfb_set_disp(int con, struct fb_var_screeninfo *var);
-static void sisfb_do_install_cmap(int con, struct fb_info *info);
+static void     sisfb_search_mode(const char *name);
+static int      sisfb_validate_mode(int modeindex);
+static u8       sisfb_search_refresh_rate(unsigned int rate);
+static int      sisfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			unsigned blue, unsigned transp,
+			struct fb_info *fb_info);
+static int      sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
+		      	struct fb_info *info);
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+static void     sisfb_set_disp(int con, struct fb_var_screeninfo *var, struct fb_info *info);
+static int      sis_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+			unsigned *blue, unsigned *transp,
+			struct fb_info *fb_info);
+static void     sisfb_do_install_cmap(int con, struct fb_info *info);
+#endif
+static void     sisfb_pre_setmode(void);
+static void     sisfb_post_setmode(void);
+static void     sisfb_crtc_to_var(struct fb_var_screeninfo *var);
 
-/* Chip-dependent Routines */
+/* Chipset-dependent Routines */
 #ifdef CONFIG_FB_SIS_300
-static int sisfb_get_dram_size_300(void);
-//extern BOOLEAN SiSInit300(PHW_DEVICE_EXTENSION HwDeviceExtension);
-static void sisfb_detect_VB_connect_300(void);
-static void sisfb_get_VB_type_300(void);
-static int sisfb_has_VB_300(void);
-//extern BOOLEAN SiSSetMode(PHW_DEVICE_EXTENSION HwDeviceExtension,USHORT ModeNo);
+static int      sisfb_get_dram_size_300(void);
+static void     sisfb_detect_VB_connect_300(void);
+static void     sisfb_get_VB_type_300(void);
+static int      sisfb_has_VB_300(void);
 #endif
 #ifdef CONFIG_FB_SIS_315
-static int sisfb_get_dram_size_315(void);
-//extern BOOLEAN SiSInit310(PHW_DEVICE_EXTENSION HwDeviceExtension);
-static void sisfb_detect_VB_connect_315(void);
-static void sisfb_get_VB_type_315(void);
-static int sisfb_has_VB_315(void);
-//extern BOOLEAN SiSSetMode310(PHW_DEVICE_EXTENSION HwDeviceExtension, USHORT ModeNo);
+static int      sisfb_get_dram_size_315(void);
+static void     sisfb_detect_VB_connect_315(void);
+static void     sisfb_get_VB_type_315(void);
+static int      sisfb_has_VB_315(void);
 #endif
 
-/* SetMode routines */
-
-// Eden Chen
-extern BOOLEAN SiSSetMode(PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT ModeNo);
-extern BOOLEAN SiSInit(PSIS_HW_DEVICE_INFO HwDeviceExtension);
-extern void SetEnableDstn(void);
-// ~Eden Chen
-
-extern void 	SiSRegInit(USHORT BaseAddr);
-extern USHORT 	SiS_GetCH7005(USHORT tempbx);
-extern void 	SiS_SetCH7005(USHORT tempbx);
-extern void     SiS_SetCHTVRegANDOR(USHORT tempax,USHORT tempbh);
-
-static void sisfb_pre_setmode(void);
-static void sisfb_post_setmode(void);
-static void sisfb_crtc_to_var(struct fb_var_screeninfo *var);
+/* TW: Sensing routines */
+void            SiS_Sense30x(void);
+int             SISDoSense(int tempbl, int tempbh, int tempcl, int tempch);
+void            SiS_SenseCh(void);
+
+/* Routines from init.c/init301.c */
+extern void 	SiSRegInit(SiS_Private *SiS_Pr, USHORT BaseAddr);
+extern BOOLEAN  SiSInit(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension);
+extern BOOLEAN  SiSSetMode(SiS_Private *SiS_Pr, PSIS_HW_DEVICE_INFO HwDeviceExtension, USHORT ModeNo);
+extern void     SetEnableDstn(SiS_Private *SiS_Pr);
+extern void     SiS_LongWait(SiS_Private *SiS_Pr);
+
+/* TW: Chrontel TV functions */
+extern USHORT 	SiS_GetCH700x(SiS_Private *SiS_Pr, USHORT tempbx);
+extern void 	SiS_SetCH700x(SiS_Private *SiS_Pr, USHORT tempbx);
+extern USHORT 	SiS_GetCH701x(SiS_Private *SiS_Pr, USHORT tempbx);
+extern void 	SiS_SetCH701x(SiS_Private *SiS_Pr, USHORT tempbx);
+extern void     SiS_SetCH70xxANDOR(SiS_Private *SiS_Pr, USHORT tempax,USHORT tempbh);
+extern void     SiS_DDC2Delay(SiS_Private *SiS_Pr, USHORT delaytime);
 
 /* Export functions  */
-static void sis_get_glyph(SIS_GLYINFO *gly);
-void sis_dispinfo(struct ap_data *rec);
-void sis_malloc(struct sis_memreq *req);
-void sis_free(unsigned long base);
+static void     sis_get_glyph(struct fb_info *info, SIS_GLYINFO *gly);
+void            sis_dispinfo(struct ap_data *rec);
+void            sis_malloc(struct sis_memreq *req);
+void            sis_free(unsigned long base);
 
 /* heap routines */
-static int sisfb_heap_init(void);
-static SIS_OH *sisfb_poh_new_node(void);
-static SIS_OH *sisfb_poh_allocate(unsigned long size);
-static void sisfb_delete_node(SIS_OH *poh);
-static void sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh);
-static SIS_OH *sisfb_poh_free(unsigned long base);
-static void sisfb_free_node(SIS_OH *poh);
+static int      sisfb_heap_init(void);
+static SIS_OH   *sisfb_poh_new_node(void);
+static SIS_OH   *sisfb_poh_allocate(unsigned long size);
+static void     sisfb_delete_node(SIS_OH *poh);
+static void     sisfb_insert_node(SIS_OH *pohList, SIS_OH *poh);
+static SIS_OH   *sisfb_poh_free(unsigned long base);
+static void     sisfb_free_node(SIS_OH *poh);
 
 /* routines to access PCI configuration space */
-BOOLEAN sisfb_query_VGA_config_space(PSIS_HW_DEVICE_INFO psishw_ext, 
-	unsigned long offset, unsigned long set, unsigned long *value);
-BOOLEAN sisfb_query_north_bridge_space(PSIS_HW_DEVICE_INFO psishw_ext, 
-	unsigned long offset, unsigned long set, unsigned long *value);
+BOOLEAN         sisfb_query_VGA_config_space(PSIS_HW_DEVICE_INFO psishw_ext,
+	          	unsigned long offset, unsigned long set, unsigned long *value);
+BOOLEAN         sisfb_query_north_bridge_space(PSIS_HW_DEVICE_INFO psishw_ext,
+	         	unsigned long offset, unsigned long set, unsigned long *value);
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/sis/vgatypes.h linux.20pre10-ac2/drivers/video/sis/vgatypes.h
--- linux.20pre10/drivers/video/sis/vgatypes.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/sis/vgatypes.h	2002-10-11 00:17:32.000000000 +0100
@@ -1,12 +1,18 @@
 #ifndef _VGATYPES_
 #define _VGATYPES_
 
+#ifdef LINUX_XF86
+#include "xf86Pci.h"
+#endif
+
+#ifdef LINUX_KERNEL  /* TW: We don't want the X driver to depend on kernel source */
+#include <linux/ioctl.h>
+#endif
 
 #ifndef TC
 #define far
 #endif
 
-
 #ifndef FALSE
 #define FALSE   0
 #endif
@@ -19,7 +25,7 @@
 #define NULL    0
 #endif
 
-#ifndef CHAR 
+#ifndef CHAR
 typedef char CHAR;
 #endif
 
@@ -43,7 +49,6 @@
 typedef unsigned long ULONG;
 #endif
 
-
 #ifndef PUCHAR
 typedef UCHAR far *PUCHAR;
 #endif
@@ -77,7 +82,7 @@
 #define VBIOS_VER_MAX_LENGTH         4
 #endif
 
-#ifndef LINUX_KERNEL
+#ifndef LINUX_KERNEL   /* For kernel, this is defined in sisfb.h */
 #ifndef WIN2000
 #ifndef SIS_CHIP_TYPE
 typedef enum _SIS_CHIP_TYPE {
@@ -109,13 +114,13 @@
 typedef enum _SIS_VB_CHIP_TYPE {
     VB_CHIP_Legacy = 0,
     VB_CHIP_301,
-    VB_CHIP_301B,
-    VB_CHIP_301BLCD,
-    VB_CHIP_301BTV,
+    VB_CHIP_301B,      
+    VB_CHIP_301LV,
+    VB_CHIP_301LVX,
     VB_CHIP_302,
     VB_CHIP_302B,
-    VB_CHIP_302BLCD,
-    VB_CHIP_302BTV, 
+    VB_CHIP_302LV,
+    VB_CHIP_302LVX,
     VB_CHIP_303,
     VB_CHIP_UNKNOWN, /* other video bridge or no video bridge */
     MAX_VB_CHIP
@@ -135,13 +140,18 @@
     LCD_1600x1200,
     LCD_1920x1440,
     LCD_2048x1536,
-    LCD_320x480,    /* TW: FSTN */
+    LCD_320x480,       /* TW: FSTN */
+    LCD_1400x1050,
+    LCD_1152x864,
+    LCD_1152x768,
+    LCD_1280x768,
+    LCD_1024x600,
     LCD_UNKNOWN
 } SIS_LCD_TYPE;
 #endif
 #endif
 
-#ifndef WIN2000 /* mark by Paul ,Move definition to sisv.h*/
+#ifndef WIN2000 /* mark by Paul, Move definition to sisv.h*/
 #ifndef PSIS_DSReg
 typedef struct _SIS_DSReg
 {
@@ -158,15 +168,15 @@
 
 
 struct _SIS_HW_DEVICE_INFO
-{   
+{
     PVOID  pDevice;              /* The pointer to the physical device data structure
                                     in each OS or NULL for unused. */
-    UCHAR  *pjVirtualRomBase;    /* Only for NT, NULL for WinCE & Linux. */
-                                 /* base virtual address of VBIOS ROM Space */
+    UCHAR  *pjVirtualRomBase;    /* base virtual address of VBIOS ROM Space */
                                  /* or base virtual address of ROM image file. */
                                  /* if NULL, then read from pjROMImage; */
                                  /* Note:ROM image file is the file of VBIOS ROM */
 
+    BOOLEAN UseROM;		 /* TW: Use the ROM image if provided */
  
     UCHAR  *pjCustomizedROMImage;/* base virtual address of ROM image file. */
                                  /* wincE:ROM image file is the file for OEM */
@@ -201,6 +211,7 @@
                                  /*             011:Trumpion LVDS Scaling Chip */
                                  /*             100:LVDS(LCD-out)+Chrontel 7005 */
                                  /*             101:Single Chrontel 7005 */
+				 /* TW: This has changed on 310/325 series! */
 
     ULONG  ulCRT2LCDType;        /* defined in the data structure type */
                                  /* "SIS_LCD_TYPE" */
@@ -217,7 +228,7 @@
                                  /* end data :(idx, val) =  (FF, FF) */
                                  /* Note : restore cR registers if  */
                                  /* bSkipDramSizing = TRUE */
-    
+
     PSIS_QUERYSPACE  pQueryVGAConfigSpace; /* Get/Set VGA Configuration  */
                                            /* space */
  
@@ -226,9 +237,48 @@
 
     UCHAR  szVBIOSVer[VBIOS_VER_MAX_LENGTH];
 
+    UCHAR  pdc;			/* TW: PanelDelayCompensation */
+
+#ifdef LINUX_XF86
+    PCITAG PciTag;		/* PCI Tag for Linux XF86 */
+#endif
+};
+#endif
+#endif 
+
+
+/* TW: Addtional IOCTL for communication sisfb <> X driver        */
+/*     If changing this, sisfb.h must also be changed (for sisfb) */
+
+#ifdef LINUX_XF86  /* We don't want the X driver to depend on the kernel source */
+
+/* TW: ioctl for identifying and giving some info (esp. memory heap start) */
+#define SISFB_GET_INFO    0x80046ef8  /* Wow, what a terrible hack... */
+
+/* TW: Structure argument for SISFB_GET_INFO ioctl  */
+typedef struct _SISFB_INFO sisfb_info, *psisfb_info;
+
+struct _SISFB_INFO {
+	unsigned long sisfb_id;         /* for identifying sisfb */
+#ifndef SISFB_ID
+#define SISFB_ID	  0x53495346    /* Identify myself with 'SISF' */
+#endif
+ 	int    chip_id;			/* PCI ID of detected chip */
+	int    memory;			/* video memory in KB which sisfb manages */
+	int    heapstart;               /* heap start (= sisfb "mem" argument) in KB */
+	unsigned char fbvidmode;	/* current sisfb mode */
+
+	unsigned char sisfb_version;
+	unsigned char sisfb_revision;
+	unsigned char sisfb_patchlevel;
+
+	unsigned char sisfb_caps;	/* sisfb's capabilities */
+
+	int    sisfb_tqlen;		/* turbo queue length (in KB) */
+
+	char reserved[249]; 		/* for future use */
 };
 #endif
-#endif/*~ mark by Paul ,Move definition to sisv.h*/
 
 #ifndef WIN2000
 #ifndef WINCE_HEADER
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/drivers/video/sis/vstruct.h linux.20pre10-ac2/drivers/video/sis/vstruct.h
--- linux.20pre10/drivers/video/sis/vstruct.h	2002-10-09 21:36:53.000000000 +0100
+++ linux.20pre10-ac2/drivers/video/sis/vstruct.h	2002-10-11 00:17:32.000000000 +0100
@@ -4,344 +4,516 @@
 #define EXTERN extern
 #endif /* _INIT_ */
 
+#ifndef _VSTRUCT_
+#define _VSTRUCT_
+
 typedef struct _SiS_PanelDelayTblStruct
 {
- UCHAR timer[2];
+ 	UCHAR timer[2];
 } SiS_PanelDelayTblStruct;
 
 typedef struct _SiS_LCDDataStruct
 {
- USHORT RVBHCMAX;
- USHORT RVBHCFACT;
- USHORT VGAHT;
- USHORT VGAVT;
- USHORT LCDHT;
- USHORT LCDVT;
+	USHORT RVBHCMAX;
+	USHORT RVBHCFACT;
+	USHORT VGAHT;
+	USHORT VGAVT;
+	USHORT LCDHT;
+	USHORT LCDVT;
 } SiS_LCDDataStruct;
 
 typedef struct _SiS_TVDataStruct
 {
- USHORT RVBHCMAX;
- USHORT RVBHCFACT;
- USHORT VGAHT;
- USHORT VGAVT;
- USHORT TVHDE;
- USHORT TVVDE;
- USHORT RVBHRS;
- UCHAR FlickerMode;
- USHORT HALFRVBHRS;
- UCHAR RY1COE;
- UCHAR RY2COE;
- UCHAR RY3COE;
- UCHAR RY4COE;
+	USHORT RVBHCMAX;
+	USHORT RVBHCFACT;
+	USHORT VGAHT;
+	USHORT VGAVT;
+	USHORT TVHDE;
+	USHORT TVVDE;
+	USHORT RVBHRS;
+	UCHAR  FlickerMode;
+	USHORT HALFRVBHRS;
+	UCHAR  RY1COE;
+	UCHAR  RY2COE;
+	UCHAR  RY3COE;
+	UCHAR  RY4COE;
 } SiS_TVDataStruct;
 
 typedef struct _SiS_LVDSDataStruct
 {
- USHORT VGAHT;
- USHORT VGAVT;
- USHORT LCDHT;
- USHORT LCDVT;
+	USHORT VGAHT;
+	USHORT VGAVT;
+	USHORT LCDHT;
+	USHORT LCDVT;
 } SiS_LVDSDataStruct;
 
 typedef struct _SiS_LVDSDesStruct
 {
- USHORT LCDHDES;
- USHORT LCDVDES;
+	USHORT LCDHDES;
+	USHORT LCDVDES;
 } SiS_LVDSDesStruct;
 
 typedef struct _SiS_LVDSCRT1DataStruct
 {
- UCHAR CR[15];
+	UCHAR  CR[15];
 } SiS_LVDSCRT1DataStruct;
 
 /*add for LCDA*/
 typedef struct _SiS_LCDACRT1DataStruct
 {
- UCHAR CR[17];
+	UCHAR  CR[17];
 } SiS_LCDACRT1DataStruct;
 
 typedef struct _SiS_CHTVRegDataStruct
 {
- UCHAR Reg[5];
+	UCHAR  Reg[16];
 } SiS_CHTVRegDataStruct;
 
 typedef struct _SiS_StStruct
 {
- UCHAR St_ModeID;
- USHORT St_ModeFlag;
- UCHAR St_StTableIndex;
- UCHAR St_CRT2CRTC;
- UCHAR St_ResInfo;
- UCHAR VB_StTVFlickerIndex;
- UCHAR VB_StTVEdgeIndex;
- UCHAR VB_StTVYFilterIndex;
+	UCHAR  St_ModeID;
+	USHORT St_ModeFlag;
+	UCHAR  St_StTableIndex;
+	UCHAR  St_CRT2CRTC;
+	UCHAR  St_ResInfo;
+	UCHAR  VB_StTVFlickerIndex;
+	UCHAR  VB_StTVEdgeIndex;
+	UCHAR  VB_StTVYFilterIndex;
 } SiS_StStruct;
 
 typedef struct _SiS_VBModeStruct
 {
-UCHAR  ModeID;
-UCHAR  VB_TVDelayIndex;
-UCHAR  VB_TVFlickerIndex;
-UCHAR  VB_TVPhaseIndex;
-UCHAR  VB_TVYFilterIndex;
-UCHAR  VB_LCDDelayIndex;
-UCHAR  _VB_LCDHIndex;
-UCHAR  _VB_LCDVIndex;
+	UCHAR  ModeID;
+	UCHAR  VB_TVDelayIndex;
+	UCHAR  VB_TVFlickerIndex;
+	UCHAR  VB_TVPhaseIndex;
+	UCHAR  VB_TVYFilterIndex;
+	UCHAR  VB_LCDDelayIndex;
+	UCHAR  _VB_LCDHIndex;
+	UCHAR  _VB_LCDVIndex;
 } SiS_VBModeStruct;
 
 typedef struct _SiS_StandTableStruct
 {
- UCHAR CRT_COLS;
- UCHAR ROWS;
- UCHAR CHAR_HEIGHT;
- USHORT CRT_LEN;
- UCHAR SR[4];
- UCHAR MISC;
- UCHAR CRTC[0x19];
- UCHAR ATTR[0x14];
- UCHAR GRC[9];
+	UCHAR  CRT_COLS;
+	UCHAR  ROWS;
+	UCHAR  CHAR_HEIGHT;
+	USHORT CRT_LEN;
+	UCHAR  SR[4];
+	UCHAR  MISC;
+	UCHAR  CRTC[0x19];
+	UCHAR  ATTR[0x14];
+	UCHAR  GRC[9];
 } SiS_StandTableStruct;
 
 typedef struct _SiS_ExtStruct
 {
- UCHAR Ext_ModeID;
- USHORT Ext_ModeFlag;
- USHORT Ext_ModeInfo;
- USHORT Ext_Point;
- USHORT Ext_VESAID;
- UCHAR Ext_VESAMEMSize;
- UCHAR Ext_RESINFO;
- UCHAR VB_ExtTVFlickerIndex;
- UCHAR VB_ExtTVEdgeIndex;
- UCHAR VB_ExtTVYFilterIndex;
- UCHAR REFindex;
+	UCHAR  Ext_ModeID;
+	USHORT Ext_ModeFlag;
+	USHORT Ext_ModeInfo;
+	USHORT Ext_Point;
+	USHORT Ext_VESAID;
+	UCHAR  Ext_VESAMEMSize;
+	UCHAR  Ext_RESINFO;
+	UCHAR  VB_ExtTVFlickerIndex;
+	UCHAR  VB_ExtTVEdgeIndex;
+	UCHAR  VB_ExtTVYFilterIndex;
+	UCHAR  REFindex;
 } SiS_ExtStruct;
 
 typedef struct _SiS_Ext2Struct
 {
- USHORT Ext_InfoFlag;
- UCHAR Ext_CRT1CRTC;
- UCHAR Ext_CRTVCLK;
- UCHAR Ext_CRT2CRTC;
- UCHAR  ModeID;
- USHORT XRes;
- USHORT YRes;
- USHORT ROM_OFFSET;
+	USHORT Ext_InfoFlag;
+	UCHAR  Ext_CRT1CRTC;
+	UCHAR  Ext_CRTVCLK;
+	UCHAR  Ext_CRT2CRTC;
+	UCHAR  ModeID;
+	USHORT XRes;
+	USHORT YRes;
+	USHORT ROM_OFFSET;
 } SiS_Ext2Struct;
 
+typedef struct _SiS_Part2PortTblStruct
+{
+ 	UCHAR  CR[12];
+} SiS_Part2PortTblStruct;
+
 typedef struct _SiS_CRT1TableStruct
 {
- UCHAR CR[17];
+	UCHAR  CR[17];
 } SiS_CRT1TableStruct;
 
 typedef struct _SiS_MCLKDataStruct
 {
- UCHAR SR28,SR29,SR2A;
- USHORT CLOCK;
+	UCHAR  SR28,SR29,SR2A;
+	USHORT CLOCK;
 } SiS_MCLKDataStruct;
 
 typedef struct _SiS_ECLKDataStruct
 {
- UCHAR SR2E,SR2F,SR30;
- USHORT CLOCK;
+	UCHAR  SR2E,SR2F,SR30;
+	USHORT CLOCK;
 } SiS_ECLKDataStruct;
 
 typedef struct _SiS_VCLKDataStruct
 {
- UCHAR SR2B,SR2C;
- USHORT CLOCK;
+	UCHAR  SR2B,SR2C;
+	USHORT CLOCK;
 } SiS_VCLKDataStruct;
 
 typedef struct _SiS_VBVCLKDataStruct
 {
- UCHAR Part4_A,Part4_B;
- USHORT CLOCK;
+	UCHAR  Part4_A,Part4_B;
+	USHORT CLOCK;
 } SiS_VBVCLKDataStruct;
 
 typedef struct _SiS_StResInfoStruct
 {
- USHORT HTotal;
- USHORT VTotal;
+	USHORT HTotal;
+	USHORT VTotal;
 } SiS_StResInfoStruct;
 
 typedef struct _SiS_ModeResInfoStruct
 {
- USHORT HTotal;
- USHORT VTotal;
- UCHAR  XChar;
- UCHAR  YChar;
+	USHORT HTotal;
+	USHORT VTotal;
+	UCHAR  XChar;
+	UCHAR  YChar;
 } SiS_ModeResInfoStruct;
 
-EXTERN SiS_StStruct *SiS_SModeIDTable;
-EXTERN SiS_StandTableStruct *SiS_StandTable;
-EXTERN SiS_ExtStruct  *SiS_EModeIDTable;
-EXTERN SiS_Ext2Struct  *SiS_RefIndex;
-EXTERN SiS_VBModeStruct *SiS_VBModeIDTable;
-EXTERN SiS_CRT1TableStruct  *SiS_CRT1Table;
-EXTERN SiS_MCLKDataStruct  *SiS_MCLKData;
-EXTERN SiS_ECLKDataStruct  *SiS_ECLKData;
-EXTERN SiS_VCLKDataStruct  *SiS_VCLKData;
-EXTERN SiS_VBVCLKDataStruct  *SiS_VBVCLKData;
-EXTERN SiS_StResInfoStruct  *SiS_StResInfo;
-EXTERN SiS_ModeResInfoStruct  *SiS_ModeResInfo;
-EXTERN UCHAR *SiS_ScreenOffset;
-
-EXTERN UCHAR *pSiS_OutputSelect;
-EXTERN UCHAR *pSiS_SoftSetting;
-EXTERN UCHAR *pSiS_SR07;
-
 typedef UCHAR DRAM4Type[4];
-EXTERN DRAM4Type *SiS_SR15; /* pointer : point to array */
-EXTERN DRAM4Type *SiS_CR40; /* pointer : point to array */
-EXTERN UCHAR *SiS_CR49;
-EXTERN UCHAR *SiS_SR25;
-
-EXTERN UCHAR *pSiS_SR1F;
-EXTERN UCHAR *pSiS_SR21;
-EXTERN UCHAR *pSiS_SR22;
-EXTERN UCHAR *pSiS_SR23;
-EXTERN UCHAR *pSiS_SR24;
-EXTERN UCHAR *pSiS_SR31;
-EXTERN UCHAR *pSiS_SR32;
-EXTERN UCHAR *pSiS_SR33;
-EXTERN UCHAR *pSiS_CRT2Data_1_2;
-EXTERN UCHAR *pSiS_CRT2Data_4_D;
-EXTERN UCHAR *pSiS_CRT2Data_4_E;
-EXTERN UCHAR *pSiS_CRT2Data_4_10;
-EXTERN USHORT *pSiS_RGBSenseData;
-EXTERN USHORT *pSiS_VideoSenseData;
-EXTERN USHORT *pSiS_YCSenseData;
-EXTERN USHORT *pSiS_RGBSenseData2; /*301b*/
-EXTERN USHORT *pSiS_VideoSenseData2;
-EXTERN USHORT *pSiS_YCSenseData2;
-
-EXTERN UCHAR *SiS_NTSCPhase;
-EXTERN UCHAR *SiS_PALPhase;
-EXTERN UCHAR *SiS_NTSCPhase2;
-EXTERN UCHAR *SiS_PALPhase2;
-EXTERN UCHAR *SiS_PALMPhase;
-EXTERN UCHAR *SiS_PALNPhase;
-EXTERN SiS_LCDDataStruct  *SiS_StLCD1024x768Data;
-EXTERN SiS_LCDDataStruct  *SiS_ExtLCD1024x768Data;
-EXTERN SiS_LCDDataStruct  *SiS_St2LCD1024x768Data;
-EXTERN SiS_LCDDataStruct  *SiS_StLCD1280x1024Data;
-EXTERN SiS_LCDDataStruct  *SiS_ExtLCD1280x1024Data;
-EXTERN SiS_LCDDataStruct  *SiS_St2LCD1280x1024Data;
-EXTERN SiS_LCDDataStruct  *SiS_NoScaleData;
-EXTERN SiS_LCDDataStruct  *SiS_LCD1280x960Data;
-EXTERN SiS_TVDataStruct   *SiS_StPALData;
-EXTERN SiS_TVDataStruct   *SiS_ExtPALData;
-EXTERN SiS_TVDataStruct   *SiS_StNTSCData;
-EXTERN SiS_TVDataStruct   *SiS_ExtNTSCData;
-EXTERN SiS_TVDataStruct   *SiS_St1HiTVData;
-EXTERN SiS_TVDataStruct   *SiS_St2HiTVData;
-EXTERN SiS_TVDataStruct   *SiS_ExtHiTVData;
-EXTERN UCHAR *SiS_NTSCTiming;
-EXTERN UCHAR *SiS_PALTiming;
-EXTERN UCHAR *SiS_HiTVExtTiming;
-EXTERN UCHAR *SiS_HiTVSt1Timing;
-EXTERN UCHAR *SiS_HiTVSt2Timing;
-EXTERN UCHAR *SiS_HiTVTextTiming;
-EXTERN UCHAR *SiS_HiTVGroup3Data;
-EXTERN UCHAR *SiS_HiTVGroup3Simu;
-EXTERN UCHAR *SiS_HiTVGroup3Text;
-
-EXTERN SiS_PanelDelayTblStruct *SiS_PanelDelayTbl;
-EXTERN SiS_LVDSDataStruct  *SiS_LVDS800x600Data_1;
-EXTERN SiS_LVDSDataStruct  *SiS_LVDS800x600Data_2;
-EXTERN SiS_LVDSDataStruct  *SiS_LVDS1024x768Data_1;
-EXTERN SiS_LVDSDataStruct  *SiS_LVDS1024x768Data_2;
-EXTERN SiS_LVDSDataStruct  *SiS_LVDS1280x1024Data_1;
-EXTERN SiS_LVDSDataStruct  *SiS_LVDS1280x1024Data_2;
-EXTERN SiS_LVDSDataStruct  *SiS_LVDS640x480Data_1;
-EXTERN SiS_LVDSDataStruct  *SiS_LVDS320x480Data_1;  /*fstn*/
-EXTERN SiS_LVDSDataStruct  *SiS_CHTVUNTSCData;
-EXTERN SiS_LVDSDataStruct  *SiS_CHTVONTSCData;
-EXTERN SiS_LVDSDataStruct  *SiS_CHTVUPALData;
-EXTERN SiS_LVDSDataStruct  *SiS_CHTVOPALData;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType00_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType01_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType02_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType03_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType04_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType05_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType06_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType07_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType08_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType09_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0a_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0b_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0c_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0d_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0e_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0f_1;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType00_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType01_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType02_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType03_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType04_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType05_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType06_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType07_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType08_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType09_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0a_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0b_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0c_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0d_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0e_2;
-EXTERN SiS_LVDSDesStruct  *SiS_PanelType0f_2;
-/*301b*/
-EXTERN SiS_LVDSDesStruct  *LVDS1024x768Des_1;
-EXTERN SiS_LVDSDesStruct  *LVDS1280x1024Des_1;
-EXTERN SiS_LVDSDesStruct  *LVDS1280x960Des_1;
-EXTERN SiS_LVDSDesStruct  *LVDS1024x768Des_2;
-EXTERN SiS_LVDSDesStruct  *LVDS1280x1024Des_2;
-EXTERN SiS_LVDSDesStruct  *LVDS1280x960Des_2;
-/*end 301b*/
-EXTERN SiS_LVDSDesStruct  *SiS_CHTVUNTSCDesData;
-EXTERN SiS_LVDSDesStruct  *SiS_CHTVONTSCDesData;
-EXTERN SiS_LVDSDesStruct  *SiS_CHTVUPALDesData;
-EXTERN SiS_LVDSDesStruct  *SiS_CHTVOPALDesData;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_1;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_1;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_1;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_1_H;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_1_H;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_1_H;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_2;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_2;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_2;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_2_H;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_2_H;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_2_H;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1UNTSC;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1ONTSC;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1UPAL;
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1OPAL;
-/*fstn*/
-EXTERN SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1320x480_1;
-/*add for  LCDA*/
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT1800x600_1;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_1;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_1;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT1800x600_1_H;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_1_H;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_1_H;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT1800x600_2;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_2;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_2;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT1800x600_2_H;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_2_H;
-EXTERN SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_2_H;
-/*end 301b*/
-
-EXTERN SiS_CHTVRegDataStruct *SiS_CHTVReg_UNTSC;
-EXTERN SiS_CHTVRegDataStruct *SiS_CHTVReg_ONTSC;
-EXTERN SiS_CHTVRegDataStruct *SiS_CHTVReg_UPAL;
-EXTERN SiS_CHTVRegDataStruct *SiS_CHTVReg_OPAL;
-EXTERN UCHAR *SiS_CHTVVCLKUNTSC;
-EXTERN UCHAR *SiS_CHTVVCLKONTSC;
-EXTERN UCHAR *SiS_CHTVVCLKUPAL;
-EXTERN UCHAR *SiS_CHTVVCLKOPAL;
+
+typedef struct _SiS_Private
+{
+#ifdef LINUX_KERNEL
+        USHORT RelIO;
+#endif
+	USHORT SiS_P3c4;
+	USHORT SiS_P3d4;
+	USHORT SiS_P3c0;
+	USHORT SiS_P3ce;
+	USHORT SiS_P3c2;
+	USHORT SiS_P3ca;
+	USHORT SiS_P3c6;
+	USHORT SiS_P3c7;
+	USHORT SiS_P3c8;
+	USHORT SiS_P3c9;
+	USHORT SiS_P3da;
+	USHORT SiS_Part1Port;
+	USHORT SiS_Part2Port;
+	USHORT SiS_Part3Port;
+	USHORT SiS_Part4Port;
+	USHORT SiS_Part5Port;
+	USHORT SiS_IF_DEF_LVDS;
+	USHORT SiS_IF_DEF_TRUMPION;
+	USHORT SiS_IF_DEF_DSTN;
+	USHORT SiS_IF_DEF_FSTN;
+	USHORT SiS_IF_DEF_CH70xx;
+	USHORT SiS_IF_DEF_HiVision;
+	UCHAR  SiS_VGAINFO;
+	BOOLEAN SiS_UseROM;
+	int    SiS_CHOverScan;
+	USHORT SiS_Backup70xx;
+	USHORT SiS_CRT1Mode;
+	USHORT SiS_flag_clearbuffer;
+	int    SiS_RAMType;
+	UCHAR  SiS_ChannelAB;
+	UCHAR  SiS_DataBusWidth;
+	USHORT SiS_ModeType;
+	USHORT SiS_VBInfo;
+	USHORT SiS_LCDResInfo;
+	USHORT SiS_LCDTypeInfo;
+	USHORT SiS_LCDInfo;
+	USHORT SiS_VBType;
+	USHORT SiS_VBExtInfo;
+	USHORT SiS_HiVision;
+	USHORT SiS_SelectCRT2Rate;
+	USHORT SiS_SetFlag;
+	USHORT SiS_RVBHCFACT;
+	USHORT SiS_RVBHCMAX;
+	USHORT SiS_RVBHRS;
+	USHORT SiS_VGAVT;
+	USHORT SiS_VGAHT;
+	USHORT SiS_VT;
+	USHORT SiS_HT;
+	USHORT SiS_VGAVDE;
+	USHORT SiS_VGAHDE;
+	USHORT SiS_VDE;
+	USHORT SiS_HDE;
+	USHORT SiS_NewFlickerMode;
+	USHORT SiS_RY1COE;
+	USHORT SiS_RY2COE;
+	USHORT SiS_RY3COE;
+	USHORT SiS_RY4COE;
+	USHORT SiS_LCDHDES;
+	USHORT SiS_LCDVDES;
+	USHORT SiS_DDC_Port;
+	USHORT SiS_DDC_Index;
+	USHORT SiS_DDC_Data;
+	USHORT SiS_DDC_Clk;
+	USHORT SiS_DDC_DataShift;
+	USHORT SiS_DDC_DeviceAddr;
+	USHORT SiS_DDC_ReadAddr;
+	USHORT SiS_DDC_SecAddr;
+	USHORT SiS_Panel800x600;
+	USHORT SiS_Panel1024x768;
+	USHORT SiS_Panel1280x1024;
+	USHORT SiS_Panel1600x1200;
+	USHORT SiS_Panel1280x960;
+	USHORT SiS_Panel1400x1050;
+	USHORT SiS_Panel320x480;
+	USHORT SiS_Panel1152x768;
+	USHORT SiS_Panel1280x768;
+	USHORT SiS_Panel1024x600;
+	USHORT SiS_Panel640x480;
+	USHORT SiS_Panel1152x864;
+	USHORT SiS_PanelMax;
+	USHORT SiS_PanelMinLVDS;
+	USHORT SiS_PanelMin301;
+	USHORT SiS_ChrontelInit;
+	
+	/* Pointers: */
+	const SiS_StStruct          *SiS_SModeIDTable;
+	const SiS_StandTableStruct  *SiS_StandTable;
+	const SiS_ExtStruct         *SiS_EModeIDTable;
+	const SiS_Ext2Struct        *SiS_RefIndex;
+	const SiS_VBModeStruct      *SiS_VBModeIDTable;
+	const SiS_CRT1TableStruct   *SiS_CRT1Table;
+	const SiS_MCLKDataStruct    *SiS_MCLKData_0;
+	const SiS_MCLKDataStruct    *SiS_MCLKData_1;
+	const SiS_ECLKDataStruct    *SiS_ECLKData;
+	const SiS_VCLKDataStruct    *SiS_VCLKData;
+	const SiS_VBVCLKDataStruct  *SiS_VBVCLKData;
+	const SiS_StResInfoStruct   *SiS_StResInfo;
+	const SiS_ModeResInfoStruct *SiS_ModeResInfo;
+	const UCHAR                 *SiS_ScreenOffset;
+
+	const UCHAR                 *pSiS_OutputSelect;
+	const UCHAR                 *pSiS_SoftSetting;
+
+	const DRAM4Type *SiS_SR15; /* pointer : point to array */
+#ifndef LINUX_XF86
+	UCHAR *pSiS_SR07;
+	const DRAM4Type *SiS_CR40; /* pointer : point to array */
+	UCHAR *SiS_CR49;
+	UCHAR *SiS_SR25;
+	UCHAR *pSiS_SR1F;
+	UCHAR *pSiS_SR21;
+	UCHAR *pSiS_SR22;
+	UCHAR *pSiS_SR23;
+	UCHAR *pSiS_SR24;
+	UCHAR *pSiS_SR31;
+	UCHAR *pSiS_SR32;
+	UCHAR *pSiS_SR33;
+	UCHAR *pSiS_CRT2Data_1_2;
+	UCHAR *pSiS_CRT2Data_4_D;
+	UCHAR *pSiS_CRT2Data_4_E;
+	UCHAR *pSiS_CRT2Data_4_10;
+	const USHORT *pSiS_RGBSenseData;
+	const USHORT *pSiS_VideoSenseData;
+	const USHORT *pSiS_YCSenseData;
+	const USHORT *pSiS_RGBSenseData2; /*301b*/
+	const USHORT *pSiS_VideoSenseData2;
+	const USHORT *pSiS_YCSenseData2;
+#endif
+	const UCHAR *SiS_NTSCPhase;
+	const UCHAR *SiS_PALPhase;
+	const UCHAR *SiS_NTSCPhase2;
+	const UCHAR *SiS_PALPhase2;
+	const UCHAR *SiS_PALMPhase;
+	const UCHAR *SiS_PALNPhase;
+	const UCHAR *SiS_PALMPhase2;
+	const UCHAR *SiS_PALNPhase2;
+	const UCHAR *SiS_SpecialPhase;
+	const SiS_LCDDataStruct  *SiS_StLCD1024x768Data;
+	const SiS_LCDDataStruct  *SiS_ExtLCD1024x768Data;
+	const SiS_LCDDataStruct  *SiS_St2LCD1024x768Data;
+	const SiS_LCDDataStruct  *SiS_StLCD1280x1024Data;
+	const SiS_LCDDataStruct  *SiS_ExtLCD1280x1024Data;
+	const SiS_LCDDataStruct  *SiS_St2LCD1280x1024Data;
+	const SiS_LCDDataStruct  *SiS_NoScaleData1024x768;
+	const SiS_LCDDataStruct  *SiS_NoScaleData1280x1024;
+	const SiS_LCDDataStruct  *SiS_LCD1280x960Data;
+	const SiS_LCDDataStruct  *SiS_NoScaleData1400x1050;
+	const SiS_LCDDataStruct  *SiS_NoScaleData1600x1200;
+	const SiS_LCDDataStruct  *SiS_StLCD1400x1050Data;
+	const SiS_LCDDataStruct  *SiS_StLCD1600x1200Data;
+	const SiS_LCDDataStruct  *SiS_ExtLCD1400x1050Data;
+	const SiS_LCDDataStruct  *SiS_ExtLCD1600x1200Data;
+	const SiS_TVDataStruct   *SiS_StPALData;
+	const SiS_TVDataStruct   *SiS_ExtPALData;
+	const SiS_TVDataStruct   *SiS_StNTSCData;
+	const SiS_TVDataStruct   *SiS_ExtNTSCData;
+#ifdef oldHV
+	const SiS_TVDataStruct   *SiS_St1HiTVData;
+	const SiS_TVDataStruct   *SiS_St2HiTVData;
+	const SiS_TVDataStruct   *SiS_ExtHiTVData;
+#endif
+	const UCHAR *SiS_NTSCTiming;
+	const UCHAR *SiS_PALTiming;
+#ifdef oldHV
+	const UCHAR *SiS_HiTVExtTiming;
+	const UCHAR *SiS_HiTVSt1Timing;
+	const UCHAR *SiS_HiTVSt2Timing;
+	const UCHAR *SiS_HiTVTextTiming;
+	const UCHAR *SiS_HiTVGroup3Data;
+	const UCHAR *SiS_HiTVGroup3Simu;
+	const UCHAR *SiS_HiTVGroup3Text;
+#endif
+	const SiS_PanelDelayTblStruct *SiS_PanelDelayTbl;
+	const SiS_PanelDelayTblStruct *SiS_PanelDelayTblLVDS;
+	const SiS_LVDSDataStruct  *SiS_LVDS800x600Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS800x600Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1024x768Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1024x768Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1280x1024Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1280x1024Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1280x960Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1280x960Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1400x1050Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1400x1050Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1024x600Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1024x600Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS1152x768Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS1152x768Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDS640x480Data_1;
+	const SiS_LVDSDataStruct  *SiS_LVDS320x480Data_1;
+	const SiS_LVDSDataStruct  *SiS_LCDA1400x1050Data_1;
+	const SiS_LVDSDataStruct  *SiS_LCDA1400x1050Data_2;
+	const SiS_LVDSDataStruct  *SiS_LCDA1600x1200Data_1;
+	const SiS_LVDSDataStruct  *SiS_LCDA1600x1200Data_2;
+	const SiS_LVDSDataStruct  *SiS_LVDSXXXxXXXData_1;
+	const SiS_LVDSDataStruct  *SiS_CHTVUNTSCData;
+	const SiS_LVDSDataStruct  *SiS_CHTVONTSCData;
+	const SiS_LVDSDataStruct  *SiS_CHTVUPALData;
+	const SiS_LVDSDataStruct  *SiS_CHTVOPALData;
+	const SiS_LVDSDesStruct  *SiS_PanelType00_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType01_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType02_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType03_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType04_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType05_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType06_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType07_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType08_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType09_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType0a_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType0b_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType0c_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType0d_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType0e_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType0f_1;
+	const SiS_LVDSDesStruct  *SiS_PanelType00_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType01_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType02_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType03_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType04_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType05_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType06_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType07_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType08_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType09_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType0a_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType0b_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType0c_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType0d_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType0e_2;
+	const SiS_LVDSDesStruct  *SiS_PanelType0f_2;
+
+	const SiS_LVDSDesStruct  *LVDS1024x768Des_1;
+	const SiS_LVDSDesStruct  *LVDS1280x1024Des_1;
+	const SiS_LVDSDesStruct  *LVDS1400x1050Des_1;
+	const SiS_LVDSDesStruct  *LVDS1600x1200Des_1;
+	const SiS_LVDSDesStruct  *LVDS1024x768Des_2;
+	const SiS_LVDSDesStruct  *LVDS1280x1024Des_2;
+	const SiS_LVDSDesStruct  *LVDS1400x1050Des_2;
+	const SiS_LVDSDesStruct  *LVDS1600x1200Des_2;
+
+	const SiS_LVDSDesStruct  *SiS_CHTVUNTSCDesData;
+	const SiS_LVDSDesStruct  *SiS_CHTVONTSCDesData;
+	const SiS_LVDSDesStruct  *SiS_CHTVUPALDesData;
+	const SiS_LVDSDesStruct  *SiS_CHTVOPALDesData;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11400x1050_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x600_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11152x768_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11600x1200_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11400x1050_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x600_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11152x768_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11600x1200_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11400x1050_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x600_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11152x768_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11600x1200_2;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1800x600_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x768_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11280x1024_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11400x1050_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11024x600_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11152x768_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT11600x1200_2_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1XXXxXXX_1;
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1XXXxXXX_1_H;
+	const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1UNTSC;
+	const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1ONTSC;
+	const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1UPAL;
+	const SiS_LVDSCRT1DataStruct  *SiS_CHTVCRT1OPAL;
+
+	const SiS_LVDSCRT1DataStruct  *SiS_LVDSCRT1320x480_1;
+
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT1800x600_1;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_1;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_1;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11400x1050_1;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11600x1200_1;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT1800x600_1_H;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_1_H;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_1_H;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11400x1050_1_H;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11600x1200_1_H;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT1800x600_2;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_2;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_2;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11400x1050_2;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11600x1200_2;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT1800x600_2_H;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11024x768_2_H;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11280x1024_2_H;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11400x1050_2_H;
+	const SiS_LCDACRT1DataStruct  *SiS_LCDACRT11600x1200_2_H;
+
+	/* TW: New for 650/301LV */
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_1;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_1;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1400x1050_1;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1600x1200_1;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_2;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_2;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1400x1050_2;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1600x1200_2;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1024x768_3;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1280x1024_3;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1400x1050_3;
+	const SiS_Part2PortTblStruct *SiS_CRT2Part2_1600x1200_3;
+
+	const SiS_CHTVRegDataStruct *SiS_CHTVReg_UNTSC;
+	const SiS_CHTVRegDataStruct *SiS_CHTVReg_ONTSC;
+	const SiS_CHTVRegDataStruct *SiS_CHTVReg_UPAL;
+	const SiS_CHTVRegDataStruct *SiS_CHTVReg_OPAL;
+	const UCHAR *SiS_CHTVVCLKUNTSC;
+	const UCHAR *SiS_CHTVVCLKONTSC;
+	const UCHAR *SiS_CHTVVCLKUPAL;
+	const UCHAR *SiS_CHTVVCLKOPAL;
+} SiS_Private;
+
+#endif
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/befs/attribute.c linux.20pre10-ac2/fs/befs/attribute.c
--- linux.20pre10/fs/befs/attribute.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/befs/attribute.c	2002-09-01 13:21:01.000000000 +0100
@@ -12,7 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 
-#include "befs_fs.h"
+#include "befs.h"
 #include "endian.h"
 
 #define SD_DATA(sd)\
@@ -27,7 +27,6 @@
 
 befs_small_data *find_small_data(struct super_block *sb, befs_inode * inode,
 				 const char *name);
-
 int
  read_small_data(struct super_block *sb, befs_inode * inode,
 		 befs_small_data * sdata, void *buf, size_t bufsize);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/befs/befs_fs.h linux.20pre10-ac2/fs/befs/befs_fs.h
--- linux.20pre10/fs/befs/befs_fs.h	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/befs/befs_fs.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,200 +0,0 @@
-/*
- * befs_fs.h
- *
- * Copyright (C) 2001-2002 Will Dyson <will_dyson@pobox.com>
- * Copyright (C) 1999 Makoto Kato (m_kato@ga2.so-net.ne.jp)
- */
-
-#ifndef _LINUX_BEFS_FS
-#define _LINUX_BEFS_FS
-
-#include "befs_fs_types.h"
-#include "compatibility.h"
-
-/* used in debug.c */
-#define BEFS_VERSION "0.9.2"
-
-typedef __u64 befs_blocknr_t;
-typedef __u32 vfs_blocknr_t;
-
-/*
- * BeFS in memory structures
- */
-
-typedef struct befs_mount_options {
-	gid_t gid;
-	uid_t uid;
-	int use_gid;
-	int use_uid;
-	int debug;
-	char *iocharset;
-} befs_mount_options;
-
-typedef struct befs_sb_info {
-	__u32 magic1;
-	__u32 block_size;
-	__u32 block_shift;
-	__u32 byte_order;
-	befs_off_t num_blocks;
-	befs_off_t used_blocks;
-	__u32 inode_size;
-	__u32 magic2;
-
-	/* Allocation group information */
-	__u32 blocks_per_ag;
-	__u32 ag_shift;
-	__u32 num_ags;
-
-	/* jornal log entry */
-	befs_block_run log_blocks;
-	befs_off_t log_start;
-	befs_off_t log_end;
-
-	befs_inode_addr root_dir;
-	befs_inode_addr indices;
-	__u32 magic3;
-
-	befs_mount_options mount_opts;
-	struct nls_table *nls;
-
-} befs_sb_info;
-
-typedef struct befs_inode_info {
-	__u32 i_flags;
-	__u32 i_type;
-
-	befs_inode_addr i_inode_num;
-	befs_inode_addr i_parent;
-	befs_inode_addr i_attribute;
-
-	union {
-		befs_data_stream ds;
-		char symlink[BEFS_SYMLINK_LEN];
-	} i_data;
-
-} befs_inode_info;
-
-enum befs_err {
-	BEFS_OK,
-	BEFS_ERR,
-	BEFS_BAD_INODE,
-	BEFS_BT_END,
-	BEFS_BT_EMPTY,
-	BEFS_BT_MATCH,
-	BEFS_BT_PARMATCH,
-	BEFS_BT_NOT_FOUND
-};
-
-/****************************/
-/* io.c */
-struct buffer_head *befs_bread_iaddr(struct super_block *sb,
-				     befs_inode_addr iaddr);
-
-struct buffer_head *befs_bread(struct super_block *sb, befs_blocknr_t block);
-/****************************/
-
-/****************************/
-/* datastream.c */
-struct buffer_head *befs_read_datastream(struct super_block *sb,
-					 befs_data_stream * ds, befs_off_t pos,
-					 uint * off);
-
-int befs_fblock2brun(struct super_block *sb, befs_data_stream * data,
-		     befs_blocknr_t fblock, befs_block_run * run);
-
-size_t befs_read_lsymlink(struct super_block *sb, befs_data_stream * data,
-			  void *buff, befs_off_t len);
-
-befs_blocknr_t befs_count_blocks(struct super_block *sb, befs_data_stream * ds);
-
-extern const befs_inode_addr BAD_IADDR;
-/****************************/
-
-/****************************/
-/* debug.c */
-void befs_error(const struct super_block *sb, const char *fmt, ...);
-void befs_warning(const struct super_block *sb, const char *fmt, ...);
-void befs_debug(const struct super_block *sb, const char *fmt, ...);
-
-void befs_dump_super_block(const struct super_block *sb, befs_super_block *);
-void befs_dump_inode(const struct super_block *sb, befs_inode *);
-void befs_dump_index_entry(const struct super_block *sb, befs_btree_super *);
-void befs_dump_index_node(const struct super_block *sb, befs_btree_nodehead *);
-void befs_dump_inode_addr(const struct super_block *sb, befs_inode_addr);
-/****************************/
-
-/****************************/
-/* btree.c */
-int befs_btree_find(struct super_block *sb, befs_data_stream * ds,
-		    const char *key, befs_off_t * value);
-
-int befs_btree_read(struct super_block *sb, befs_data_stream * ds,
-		    loff_t key_no, size_t bufsize, char *keybuf,
-		    size_t * keysize, befs_off_t * value);
-/****************************/
-
-/****************************/
-/* super.c */
-int befs_load_sb(struct super_block *sb, befs_super_block * disk_sb);
-int befs_check_sb(struct super_block *sb);
-/****************************/
-
-/****************************/
-/* inode.c */
-int befs_check_inode(struct super_block *sb, befs_inode * raw_inode,
-		     befs_blocknr_t inode);
-/****************************/
-
-/* Gets a pointer to the private portion of the super_block
- * structure from the public part
- */
-static inline befs_sb_info *
-BEFS_SB(const struct super_block *super)
-{
-	return (befs_sb_info *) super->u.generic_sbp;
-}
-
-static inline befs_inode_info *
-BEFS_I(const struct inode *inode)
-{
-	return (befs_inode_info *) inode->u.generic_ip;
-}
-
-static inline befs_blocknr_t
-iaddr2blockno(struct super_block *sb, befs_inode_addr * iaddr)
-{
-	return ((iaddr->allocation_group << BEFS_SB(sb)->ag_shift) +
-		iaddr->start);
-}
-
-static inline befs_inode_addr
-blockno2iaddr(struct super_block *sb, befs_blocknr_t blockno)
-{
-	befs_inode_addr iaddr;
-	iaddr.allocation_group = blockno >> BEFS_SB(sb)->ag_shift;
-	iaddr.start =
-	    blockno - (iaddr.allocation_group << BEFS_SB(sb)->ag_shift);
-	iaddr.len = 1;
-
-	return iaddr;
-}
-
-static inline unsigned int
-befs_iaddrs_per_block(struct super_block *sb)
-{
-	return BEFS_SB(sb)->block_size / sizeof (befs_inode_addr);
-}
-
-static inline int
-befs_iaddr_is_empty(befs_inode_addr * iaddr)
-{
-	return (!iaddr->allocation_group) && (!iaddr->start) && (!iaddr->len);
-}
-
-static inline size_t
-befs_brun_size(struct super_block *sb, befs_block_run run)
-{
-	return BEFS_SB(sb)->block_size * run.len;
-}
-
-#endif				/* _LINUX_BEFS_FS */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/befs/befs_fs_types.h linux.20pre10-ac2/fs/befs/befs_fs_types.h
--- linux.20pre10/fs/befs/befs_fs_types.h	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/befs/befs_fs_types.h	2002-09-18 14:26:33.000000000 +0100
@@ -45,15 +45,17 @@
  */
 
 enum super_flags {
+	BEFS_BYTESEX_BE,
+	BEFS_BYTESEX_LE,
 	BEFS_CLEAN = 0x434c454e,
 	BEFS_DIRTY = 0x44495254,
-	BEFS_BYTESEX_BE = 0x45474942,
-	BEFS_BYTESEX_LE = 0x42494745,
 	BEFS_SUPER_MAGIC1 = 0x42465331,	/* BFS1 */
 	BEFS_SUPER_MAGIC2 = 0xdd121031,
 	BEFS_SUPER_MAGIC3 = 0x15b6830e,
 };
 
+#define BEFS_BYTEORDER_NATIVE 0x42494745
+
 #define BEFS_SUPER_MAGIC BEFS_SUPER_MAGIC1
 
 /*
@@ -77,15 +79,15 @@
  * On-Disk datastructures of BeFS
  */
 
-typedef __u64 befs_off_t;
-typedef __u64 befs_time_t;
+typedef u64 befs_off_t;
+typedef u64 befs_time_t;
 typedef void befs_binode_etc;
 
 /* Block runs */
 typedef struct {
-	__u32 allocation_group;
-	__u16 start;
-	__u16 len;
+	u32 allocation_group;
+	u16 start;
+	u16 len;
 } PACKED befs_block_run;
 
 typedef befs_block_run befs_inode_addr;
@@ -95,29 +97,29 @@
  */
 typedef struct {
 	char name[B_OS_NAME_LENGTH];
-	__u32 magic1;
-	__u32 fs_byte_order;
+	u32 magic1;
+	u32 fs_byte_order;
 
-	__u32 block_size;
-	__u32 block_shift;
+	u32 block_size;
+	u32 block_shift;
 
 	befs_off_t num_blocks;
 	befs_off_t used_blocks;
 
-	__u32 inode_size;
+	u32 inode_size;
 
-	__u32 magic2;
-	__u32 blocks_per_ag;
-	__u32 ag_shift;
-	__u32 num_ags;
+	u32 magic2;
+	u32 blocks_per_ag;
+	u32 ag_shift;
+	u32 num_ags;
 
-	__u32 flags;
+	u32 flags;
 
 	befs_block_run log_blocks;
 	befs_off_t log_start;
 	befs_off_t log_end;
 
-	__u32 magic3;
+	u32 magic3;
 	befs_inode_addr root_dir;
 	befs_inode_addr indices;
 
@@ -139,35 +141,35 @@
 
 /* Attribute */
 typedef struct {
-	__u32 type;
-	__u16 name_size;
-	__u16 data_size;
+	u32 type;
+	u16 name_size;
+	u16 data_size;
 	char name[1];
 } PACKED befs_small_data;
 
 /* Inode structure */
 typedef struct {
-	__u32 magic1;
+	u32 magic1;
 	befs_inode_addr inode_num;
-	__u32 uid;
-	__u32 gid;
-	__u32 mode;
-	__u32 flags;
+	u32 uid;
+	u32 gid;
+	u32 mode;
+	u32 flags;
 	befs_time_t create_time;
 	befs_time_t last_modified_time;
 	befs_inode_addr parent;
 	befs_inode_addr attributes;
-	__u32 type;
+	u32 type;
 
-	__u32 inode_size;
-	__u32 etc;		/* not use */
+	u32 inode_size;
+	u32 etc;		/* not use */
 
 	union {
 		befs_data_stream datastream;
 		char symlink[BEFS_SYMLINK_LEN];
 	} data;
 
-	__u32 pad[4];		/* not use */
+	u32 pad[4];		/* not use */
 	befs_small_data small_data[1];
 } PACKED befs_inode;
 
@@ -188,10 +190,10 @@
 };
 
 typedef struct {
-	__u32 magic;
-	__u32 node_size;
-	__u32 max_depth;
-	__u32 data_type;
+	u32 magic;
+	u32 node_size;
+	u32 max_depth;
+	u32 data_type;
 	befs_off_t root_node_ptr;
 	befs_off_t free_node_ptr;
 	befs_off_t max_size;
@@ -204,8 +206,8 @@
 	befs_off_t left;
 	befs_off_t right;
 	befs_off_t overflow;
-	__u16 all_key_count;
-	__u16 all_key_length;
+	u16 all_key_count;
+	u16 all_key_length;
 } PACKED befs_btree_nodehead;
 
 #endif				/* _LINUX_BEFS_FS_TYPES */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/befs/befs.h linux.20pre10-ac2/fs/befs/befs.h
--- linux.20pre10/fs/befs/befs.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/fs/befs/befs.h	2002-09-18 14:26:33.000000000 +0100
@@ -0,0 +1,152 @@
+/*
+ * befs_fs.h
+ *
+ * Copyright (C) 2001-2002 Will Dyson <will_dyson@pobox.com>
+ * Copyright (C) 1999 Makoto Kato (m_kato@ga2.so-net.ne.jp)
+ */
+
+#ifndef _LINUX_BEFS_H
+#define _LINUX_BEFS_H
+
+#include "befs_fs_types.h"
+
+/* used in debug.c */
+#define BEFS_VERSION "0.9.3"
+
+typedef u64 befs_blocknr_t;
+typedef u32 vfs_blocknr_t;
+
+/*
+ * BeFS in memory structures
+ */
+
+typedef struct befs_mount_options {
+	gid_t gid;
+	uid_t uid;
+	int use_gid;
+	int use_uid;
+	int debug;
+	char *iocharset;
+} befs_mount_options;
+
+typedef struct befs_sb_info {
+	u32 magic1;
+	u32 block_size;
+	u32 block_shift;
+	int byte_order;
+	befs_off_t num_blocks;
+	befs_off_t used_blocks;
+	u32 inode_size;
+	u32 magic2;
+
+	/* Allocation group information */
+	u32 blocks_per_ag;
+	u32 ag_shift;
+	u32 num_ags;
+
+	/* jornal log entry */
+	befs_block_run log_blocks;
+	befs_off_t log_start;
+	befs_off_t log_end;
+
+	befs_inode_addr root_dir;
+	befs_inode_addr indices;
+	u32 magic3;
+
+	befs_mount_options mount_opts;
+	struct nls_table *nls;
+
+} befs_sb_info;
+
+typedef struct befs_inode_info {
+	u32 i_flags;
+	u32 i_type;
+
+	befs_inode_addr i_inode_num;
+	befs_inode_addr i_parent;
+	befs_inode_addr i_attribute;
+
+	union {
+		befs_data_stream ds;
+		char symlink[BEFS_SYMLINK_LEN];
+	} i_data;
+
+} befs_inode_info;
+
+enum befs_err {
+	BEFS_OK,
+	BEFS_ERR,
+	BEFS_BAD_INODE,
+	BEFS_BT_END,
+	BEFS_BT_EMPTY,
+	BEFS_BT_MATCH,
+	BEFS_BT_PARMATCH,
+	BEFS_BT_NOT_FOUND
+};
+
+/****************************/
+/* debug.c */
+void befs_error(const struct super_block *sb, const char *fmt, ...);
+void befs_warning(const struct super_block *sb, const char *fmt, ...);
+void befs_debug(const struct super_block *sb, const char *fmt, ...);
+
+void befs_dump_super_block(const struct super_block *sb, befs_super_block *);
+void befs_dump_inode(const struct super_block *sb, befs_inode *);
+void befs_dump_index_entry(const struct super_block *sb, befs_btree_super *);
+void befs_dump_index_node(const struct super_block *sb, befs_btree_nodehead *);
+void befs_dump_inode_addr(const struct super_block *sb, befs_inode_addr);
+/****************************/
+
+/* Gets a pointer to the private portion of the super_block
+ * structure from the public part
+ */
+static inline befs_sb_info *
+BEFS_SB(const struct super_block *super)
+{
+	return (befs_sb_info *) super->u.generic_sbp;
+}
+
+static inline befs_inode_info *
+BEFS_I(const struct inode *inode)
+{
+	return (befs_inode_info *) inode->u.generic_ip;
+}
+
+static inline befs_blocknr_t
+iaddr2blockno(struct super_block *sb, befs_inode_addr * iaddr)
+{
+	return ((iaddr->allocation_group << BEFS_SB(sb)->ag_shift) +
+		iaddr->start);
+}
+
+static inline befs_inode_addr
+blockno2iaddr(struct super_block *sb, befs_blocknr_t blockno)
+{
+	befs_inode_addr iaddr;
+	iaddr.allocation_group = blockno >> BEFS_SB(sb)->ag_shift;
+	iaddr.start =
+	    blockno - (iaddr.allocation_group << BEFS_SB(sb)->ag_shift);
+	iaddr.len = 1;
+
+	return iaddr;
+}
+
+static inline unsigned int
+befs_iaddrs_per_block(struct super_block *sb)
+{
+	return BEFS_SB(sb)->block_size / sizeof (befs_inode_addr);
+}
+
+static inline int
+befs_iaddr_is_empty(befs_inode_addr * iaddr)
+{
+	return (!iaddr->allocation_group) && (!iaddr->start) && (!iaddr->len);
+}
+
+static inline size_t
+befs_brun_size(struct super_block *sb, befs_block_run run)
+{
+	return BEFS_SB(sb)->block_size * run.len;
+}
+
+#endif				/* _LINUX_BEFS_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/befs/btree.c linux.20pre10-ac2/fs/befs/btree.c
--- linux.20pre10/fs/befs/btree.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/befs/btree.c	2002-09-01 13:21:01.000000000 +0100
@@ -26,7 +26,9 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 
-#include "befs_fs.h"
+#include "befs.h"
+#include "btree.h"
+#include "datastream.h"
 #include "endian.h"
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/befs/btree.h linux.20pre10-ac2/fs/befs/btree.h
--- linux.20pre10/fs/befs/btree.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/fs/befs/btree.h	2002-09-01 13:21:01.000000000 +0100
@@ -0,0 +1,11 @@
+/*
+ * btree.h
+ * 
+ */
+
+int befs_btree_find(struct super_block *sb, befs_data_stream * ds,
+		    const char *key, befs_off_t * value);
+
+int befs_btree_read(struct super_block *sb, befs_data_stream * ds,
+		    loff_t key_no, size_t bufsize, char *keybuf,
+		    size_t * keysize, befs_off_t * value);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/befs/compatibility.h linux.20pre10-ac2/fs/befs/compatibility.h
--- linux.20pre10/fs/befs/compatibility.h	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/befs/compatibility.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,26 +0,0 @@
-/*
- * linux/fs/befs/compatiblity.h
- *
- * Copyright (C) 2001 Will Dyson <will_dyson@pobox.com>
- *   AKA <will@cs.earlham.edu>
- *
- * This file trys to take care of differences between
- * kernel versions
- */
-
-#include <linux/version.h>
-
-/* New interfaces in 2.4.10 */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
-
-#define min_t(type,x,y) \
-({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
-
-#define max_t(type,x,y) \
-({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
-
-#define vsnprintf(buf, n, fmt, args) vsprintf(buf, fmt, args)
-
-#define MODULE_LICENSE(x)
-
-#endif				/* LINUX_VERSION_CODE */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/befs/datastream.c linux.20pre10-ac2/fs/befs/datastream.c
--- linux.20pre10/fs/befs/datastream.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/befs/datastream.c	2002-09-01 13:21:01.000000000 +0100
@@ -15,7 +15,9 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 
-#include "befs_fs.h"
+#include "befs.h"
+#include "datastream.h"
+#include "io.h"
 #include "endian.h"
 
 const befs_inode_addr BAD_IADDR = { 0, 0, 0 };
@@ -466,8 +468,7 @@
 	}
 
 	dbl_indir_block = befs_bread(sb,
-				     iaddr2blockno(sb,
-						   &data->double_indirect) +
+				     iaddr2blockno(sb, &data->double_indirect) +
 				     dbl_which_block);
 	if (dbl_indir_block == NULL) {
 		befs_error(sb, "befs_read_brun_dblindirect() couldn't read the "
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/befs/datastream.h linux.20pre10-ac2/fs/befs/datastream.h
--- linux.20pre10/fs/befs/datastream.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/fs/befs/datastream.h	2002-09-01 13:21:01.000000000 +0100
@@ -0,0 +1,18 @@
+/*
+ * datastream.h
+ *
+ */
+
+struct buffer_head *befs_read_datastream(struct super_block *sb,
+					 befs_data_stream * ds, befs_off_t pos,
+					 uint * off);
+
+int befs_fblock2brun(struct super_block *sb, befs_data_stream * data,
+		     befs_blocknr_t fblock, befs_block_run * run);
+
+size_t befs_read_lsymlink(struct super_block *sb, befs_data_stream * data,
+			  void *buff, befs_off_t len);
+
+befs_blocknr_t befs_count_blocks(struct super_block *sb, befs_data_stream * ds);
+
+extern const befs_inode_addr BAD_IADDR;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/befs/debug.c linux.20pre10-ac2/fs/befs/debug.c
--- linux.20pre10/fs/befs/debug.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/befs/debug.c	2002-09-01 13:21:01.000000000 +0100
@@ -20,7 +20,7 @@
 
 #endif				/* __KERNEL__ */
 
-#include "befs_fs.h"
+#include "befs.h"
 #include "endian.h"
 
 #define ERRBUFSIZE 1024
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/befs/endian.h linux.20pre10-ac2/fs/befs/endian.h
--- linux.20pre10/fs/befs/endian.h	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/befs/endian.h	2002-09-01 13:21:01.000000000 +0100
@@ -10,7 +10,6 @@
 #define LINUX_BEFS_ENDIAN
 
 #include <linux/byteorder/generic.h>
-#include "befs_fs.h"
 
 static inline u64
 fs64_to_cpu(const struct super_block *sb, u64 n)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/befs/inode.c linux.20pre10-ac2/fs/befs/inode.c
--- linux.20pre10/fs/befs/inode.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/befs/inode.c	2002-09-01 13:21:01.000000000 +0100
@@ -6,7 +6,8 @@
 
 #include <linux/fs.h>
 
-#include "befs_fs.h"
+#include "befs.h"
+#include "inode.h"
 #include "endian.h"
 
 /*
@@ -18,9 +19,9 @@
 befs_check_inode(struct super_block *sb, befs_inode * raw_inode,
 		 befs_blocknr_t inode)
 {
-	__u32 magic1 = fs32_to_cpu(sb, raw_inode->magic1);
+	u32 magic1 = fs32_to_cpu(sb, raw_inode->magic1);
 	befs_inode_addr ino_num = fsrun_to_cpu(sb, raw_inode->inode_num);
-	__u32 flags = fs32_to_cpu(sb, raw_inode->flags);
+	u32 flags = fs32_to_cpu(sb, raw_inode->flags);
 
 	/* check magic header. */
 	if (magic1 != BEFS_INODE_MAGIC1) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/befs/inode.h linux.20pre10-ac2/fs/befs/inode.h
--- linux.20pre10/fs/befs/inode.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/fs/befs/inode.h	2002-09-01 13:21:01.000000000 +0100
@@ -0,0 +1,7 @@
+/*
+ * inode.h
+ * 
+ */
+
+int befs_check_inode(struct super_block *sb, befs_inode * raw_inode,
+		     befs_blocknr_t inode);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/befs/io.c linux.20pre10-ac2/fs/befs/io.c
--- linux.20pre10/fs/befs/io.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/befs/io.c	2002-09-01 13:21:01.000000000 +0100
@@ -13,7 +13,8 @@
 
 #include <linux/fs.h>
 
-#include "befs_fs.h"
+#include "befs.h"
+#include "io.h"
 
 /*
  * Converts befs notion of disk addr to a disk offset and uses
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/befs/io.h linux.20pre10-ac2/fs/befs/io.h
--- linux.20pre10/fs/befs/io.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/fs/befs/io.h	2002-09-01 13:21:01.000000000 +0100
@@ -0,0 +1,8 @@
+/*
+ * io.h
+ */
+
+struct buffer_head *befs_bread_iaddr(struct super_block *sb,
+				     befs_inode_addr iaddr);
+
+struct buffer_head *befs_bread(struct super_block *sb, befs_blocknr_t block);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/befs/linuxvfs.c linux.20pre10-ac2/fs/befs/linuxvfs.c
--- linux.20pre10/fs/befs/linuxvfs.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/befs/linuxvfs.c	2002-09-01 13:21:01.000000000 +0100
@@ -15,7 +15,12 @@
 #include <linux/string.h>
 #include <linux/nls.h>
 
-#include "befs_fs.h"
+#include "befs.h"
+#include "btree.h"
+#include "inode.h"
+#include "datastream.h"
+#include "super.h"
+#include "io.h"
 #include "endian.h"
 
 EXPORT_NO_SYMBOLS;
@@ -35,42 +40,55 @@
 static void befs_clear_inode(struct inode *ino);
 static int befs_init_inodecache(void);
 static void befs_destroy_inodecache(void);
+
 static int befs_readlink(struct dentry *, char *, int);
 static int befs_follow_link(struct dentry *, struct nameidata *nd);
+
 static int befs_utf2nls(struct super_block *sb, const char *in, int in_len,
 			char **out, int *out_len);
 static int befs_nls2utf(struct super_block *sb, const char *in, int in_len,
 			char **out, int *out_len);
+
 static void befs_put_super(struct super_block *);
 static struct super_block *befs_read_super(struct super_block *, void *, int);
 static int befs_remount(struct super_block *, int *, char *);
 static int befs_statfs(struct super_block *, struct statfs *);
 static int parse_options(char *, befs_mount_options *);
 
+static ssize_t befs_listxattr(struct dentry *dentry, char *buffer, size_t size);
+static ssize_t befs_getxattr(struct dentry *dentry, const char *name,
+			     void *buffer, size_t size);
+static int befs_setxattr(struct dentry *dentry, const char *name, void *value,
+			 size_t size, int flags);
+static int befs_removexattr(struct dentry *dentry, const char *name);
+
+/* slab cache for befs_inode_info objects */
+static kmem_cache_t *befs_inode_cachep;
+
 static const struct super_operations befs_sops = {
 	read_inode:befs_read_inode,	/* initialize & read inode */
 	clear_inode:befs_clear_inode,	/* uninit inode */
 	put_super:befs_put_super,	/* uninit super */
 	statfs:befs_statfs,	/* statfs */
-	remount_fs:befs_remount	/* remount_fs */
+	remount_fs:befs_remount,
 };
 
-/* slab cache for befs_inode_info objects */
-static kmem_cache_t *befs_inode_cachep;
-
 struct file_operations befs_dir_operations = {
-	read:generic_read_dir,	/* read */
-	readdir:befs_readdir,	/* readdir */
+	read:generic_read_dir,
+	readdir:befs_readdir,
 };
 
 struct inode_operations befs_dir_inode_operations = {
-	lookup:befs_lookup,	/* lookup */
+	lookup:befs_lookup,
 };
 
 struct file_operations befs_file_operations = {
 	llseek:default_llseek,
-	read:generic_file_read,	/* read */
-	mmap:generic_file_mmap,	/* mmap */
+	read:generic_file_read,
+	mmap:generic_file_mmap,
+};
+
+struct inode_operations befs_file_inode_operations = {
 };
 
 struct address_space_operations befs_aops = {
@@ -80,8 +98,8 @@
 };
 
 static struct inode_operations befs_symlink_inode_operations = {
-	readlink:befs_readlink,	/* readlink */
-	follow_link:befs_follow_link	/* follow_link */
+	readlink:befs_readlink,
+	follow_link:befs_follow_link,
 };
 
 /* 
@@ -353,12 +371,7 @@
 	    (time_t) (fs64_to_cpu(sb, raw_inode->last_modified_time) >> 16);
 	inode->i_ctime = inode->i_mtime;
 	inode->i_atime = inode->i_mtime;
-
-/* Bloody hell, Linus. Why add this in a stable series? */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,9)
 	inode->i_blkbits = befs_sb->block_shift;
-#endif
-
 	inode->i_blksize = befs_sb->block_size;
 
 	befs_ino->i_inode_num = fsrun_to_cpu(sb, raw_inode->inode_num);
@@ -387,6 +400,7 @@
 
 	if (S_ISREG(inode->i_mode)) {
 		inode->i_fop = &befs_file_operations;
+		inode->i_op = &befs_file_inode_operations;
 	} else if (S_ISDIR(inode->i_mode)) {
 		inode->i_op = &befs_dir_inode_operations;
 		inode->i_fop = &befs_dir_operations;
@@ -539,7 +553,7 @@
 	wchar_t uni;
 	int unilen, utflen;
 	char *result;
-	int maxlen = in_len; /* The utf8->nls conversion cant make more chars */
+	int maxlen = in_len;	/* The utf8->nls conversion cant make more chars */
 
 	befs_debug(sb, "---> utf2nls()");
 
@@ -661,6 +675,37 @@
 	return -EILSEQ;
 }
 
+/****Xattr****/
+
+static ssize_t
+befs_listxattr(struct dentry *dentry, char *buffer, size_t size)
+{
+	printk(KERN_ERR "befs_listxattr called\n");
+	return 0;
+}
+
+static ssize_t
+befs_getxattr(struct dentry *dentry, const char *name,
+	      void *buffer, size_t size)
+{
+	return 0;
+}
+
+static int
+befs_setxattr(struct dentry *dentry, const char *name,
+	      void *value, size_t size, int flags)
+{
+	return 0;
+}
+
+static int
+befs_removexattr(struct dentry *dentry, const char *name)
+{
+	return 0;
+}
+
+/****Superblock****/
+
 static int
 parse_options(char *options, befs_mount_options * opts)
 {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/befs/super.c linux.20pre10-ac2/fs/befs/super.c
--- linux.20pre10/fs/befs/super.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/befs/super.c	2002-09-01 13:21:01.000000000 +0100
@@ -9,7 +9,8 @@
 
 #include <linux/fs.h>
 
-#include "befs_fs.h"
+#include "befs.h"
+#include "super.h"
 #include "endian.h"
 
 /**
@@ -25,8 +26,11 @@
 {
 	befs_sb_info *befs_sb = BEFS_SB(sb);
 
-	/* byte_order is special, no byte-swap */
-	befs_sb->byte_order = disk_sb->fs_byte_order;
+	/* Check the byte order of the filesystem */
+	if (le32_to_cpu(disk_sb->fs_byte_order) == BEFS_BYTEORDER_NATIVE)
+		befs_sb->byte_order = BEFS_BYTESEX_LE;
+	else if (be32_to_cpu(disk_sb->fs_byte_order) == BEFS_BYTEORDER_NATIVE)
+		befs_sb->byte_order = BEFS_BYTESEX_BE;
 
 	befs_sb->magic1 = fs32_to_cpu(sb, disk_sb->magic1);
 	befs_sb->magic2 = fs32_to_cpu(sb, disk_sb->magic2);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/befs/super.h linux.20pre10-ac2/fs/befs/super.h
--- linux.20pre10/fs/befs/super.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/fs/befs/super.h	2002-09-01 13:21:01.000000000 +0100
@@ -0,0 +1,7 @@
+/*
+ * super.h
+ */
+
+int befs_load_sb(struct super_block *sb, befs_super_block * disk_sb);
+
+int befs_check_sb(struct super_block *sb);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/befs/TODO linux.20pre10-ac2/fs/befs/TODO
--- linux.20pre10/fs/befs/TODO	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/befs/TODO	2002-09-01 13:21:01.000000000 +0100
@@ -3,14 +3,9 @@
 
 * Convert comments to the Kernel-Doc format.
 
-* Befs_fs.h has gotten big and messy. No reason not to break it up into 
-	smaller peices.
-
 * See if Alexander Viro's option parser made it into the kernel tree. 
 	Use that if we can. (include/linux/parser.h)
 
 * See if we really need separate types for on-disk and in-memory 
 	representations of the superblock and inode.
 
-* We need a wrapper around the kernel's disk cache stuff. Then it would be 
-	easy to slip in stuff like using the pagecache.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/binfmt_elf.c linux.20pre10-ac2/fs/binfmt_elf.c
--- linux.20pre10/fs/binfmt_elf.c	2002-10-09 21:36:35.000000000 +0100
+++ linux.20pre10-ac2/fs/binfmt_elf.c	2002-08-06 15:41:51.000000000 +0100
@@ -1143,7 +1143,7 @@
 	psinfo.pr_state = i;
 	psinfo.pr_sname = (i < 0 || i > 5) ? '.' : "RSDZTD"[i];
 	psinfo.pr_zomb = psinfo.pr_sname == 'Z';
-	psinfo.pr_nice = current->nice;
+	psinfo.pr_nice = task_nice(current);
 	psinfo.pr_flag = current->flags;
 	psinfo.pr_uid = NEW_TO_OLD_UID(current->uid);
 	psinfo.pr_gid = NEW_TO_OLD_GID(current->gid);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/block_dev.c linux.20pre10-ac2/fs/block_dev.c
--- linux.20pre10/fs/block_dev.c	2002-10-09 21:36:35.000000000 +0100
+++ linux.20pre10-ac2/fs/block_dev.c	2002-10-11 00:22:21.000000000 +0100
@@ -131,8 +131,9 @@
 	return 0;
 }
 
-static int blkdev_direct_IO(int rw, struct inode * inode, struct kiobuf * iobuf, unsigned long blocknr, int blocksize)
+static int blkdev_direct_IO(int rw, struct file * filp, struct kiobuf * iobuf, unsigned long blocknr, int blocksize)
 {
+	struct inode * inode = filp->f_dentry->d_inode->i_mapping->host;
 	return generic_direct_IO(rw, inode, iobuf, blocknr, blocksize, blkdev_get_block);
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/buffer.c linux.20pre10-ac2/fs/buffer.c
--- linux.20pre10/fs/buffer.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/buffer.c	2002-08-23 01:06:46.000000000 +0100
@@ -47,6 +47,7 @@
 #include <linux/highmem.h>
 #include <linux/module.h>
 #include <linux/completion.h>
+#include <linux/mm_inline.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -323,7 +324,7 @@
 
 	lock_kernel();
 	sync_inodes_sb(sb);
-	DQUOT_SYNC(dev);
+	DQUOT_SYNC_SB(sb);
 	lock_super(sb);
 	if (sb->s_dirt && sb->s_op && sb->s_op->write_super)
 		sb->s_op->write_super(sb);
@@ -345,7 +346,7 @@
 
 	lock_kernel();
 	sync_inodes(dev);
-	DQUOT_SYNC(dev);
+	DQUOT_SYNC_DEV(dev);
 	sync_supers(dev);
 	unlock_kernel();
 
@@ -586,9 +587,10 @@
 void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
 {
 	spin_lock(&lru_list_lock);
-	if (bh->b_inode)
+	if (buffer_inode(bh))
 		list_del(&bh->b_inode_buffers);
-	bh->b_inode = inode;
+	else
+		set_buffer_inode(bh);
 	list_add(&bh->b_inode_buffers, &inode->i_dirty_buffers);
 	spin_unlock(&lru_list_lock);
 }
@@ -596,9 +598,10 @@
 void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode)
 {
 	spin_lock(&lru_list_lock);
-	if (bh->b_inode)
+	if (buffer_inode(bh))
 		list_del(&bh->b_inode_buffers);
-	bh->b_inode = inode;
+	else
+		set_buffer_inode(bh);
 	list_add(&bh->b_inode_buffers, &inode->i_dirty_data_buffers);
 	spin_unlock(&lru_list_lock);
 }
@@ -607,13 +610,13 @@
    remove_inode_queue functions.  */
 static void __remove_inode_queue(struct buffer_head *bh)
 {
-	bh->b_inode = NULL;
+	clear_buffer_inode(bh);
 	list_del(&bh->b_inode_buffers);
 }
 
 static inline void remove_inode_queue(struct buffer_head *bh)
 {
-	if (bh->b_inode)
+	if (buffer_inode(bh))
 		__remove_inode_queue(bh);
 }
 
@@ -695,13 +698,13 @@
 			/* All buffers in the lru lists are mapped */
 			if (!buffer_mapped(bh))
 				BUG();
-			if (buffer_dirty(bh))
+			if (buffer_dirty(bh) && destroy_dirty_buffers)
 				printk("invalidate: dirty buffer\n");
 			if (!atomic_read(&bh->b_count)) {
 				if (destroy_dirty_buffers || !buffer_dirty(bh)) {
 					remove_inode_queue(bh);
 				}
-			} else
+			} else if (!bdev->bd_openers)
 				printk("invalidate: busy buffer\n");
 
 			write_unlock(&hash_table_lock);
@@ -731,8 +734,9 @@
 {
 	balance_dirty();
 	wakeup_bdflush();
-	try_to_free_pages(GFP_NOIO);
+	try_to_free_pages(GFP_NOFS);
 	run_task_queue(&tq_disk);
+	__set_current_state(TASK_RUNNING);
 	yield();
 }
 
@@ -741,6 +745,7 @@
 	bh->b_list = BUF_CLEAN;
 	bh->b_end_io = handler;
 	bh->b_private = private;
+	bh->b_journal_head = NULL;
 }
 
 static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
@@ -838,9 +843,9 @@
 		bh = BH_ENTRY(list->next);
 		list_del(&bh->b_inode_buffers);
 		if (!buffer_dirty(bh) && !buffer_locked(bh))
-			bh->b_inode = NULL;
+			clear_buffer_inode(bh);
 		else {
-			bh->b_inode = &tmp;
+			set_buffer_inode(bh);
 			list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers);
 			if (buffer_dirty(bh)) {
 				get_bh(bh);
@@ -953,10 +958,8 @@
 		struct buffer_head * bh;
 
 		bh = get_hash_table(dev, block, size);
-		if (bh) {
-			touch_buffer(bh);
+		if (bh)
 			return bh;
-		}
 
 		if (!grow_buffers(dev, block, size))
 			free_more_memory();
@@ -1119,6 +1122,7 @@
 	struct buffer_head * bh;
 
 	bh = getblk(dev, block, size);
+	touch_buffer(bh);
 	if (buffer_uptodate(bh))
 		return bh;
 	ll_rw_block(READ, 1, &bh);
@@ -1134,7 +1138,7 @@
  */
 static void __put_unused_buffer_head(struct buffer_head * bh)
 {
-	if (bh->b_inode)
+	if (buffer_inode(bh))
 		BUG();
 	if (nr_unused_buffer_heads >= MAX_UNUSED_BUFFERS) {
 		kmem_cache_free(bh_cachep, bh);
@@ -1990,12 +1994,7 @@
 	flush_dcache_page(page);
 	kunmap(page);
 
-	if (!atomic_set_buffer_dirty(bh)) {
-		__mark_dirty(bh);
-		buffer_insert_inode_data_queue(bh, inode);
-		balance_dirty();
-	}
-
+	__mark_buffer_dirty(bh);
 	err = 0;
 
 unlock:
@@ -2175,11 +2174,10 @@
 	err = 0;
 
 	for (i = nr; --i >= 0; ) {
-		iosize += size;
 		tmp = bh[i];
-		if (buffer_locked(tmp)) {
+		if (buffer_locked(tmp))
 			wait_on_buffer(tmp);
-		}
+		iosize += tmp->b_size;
 		
 		if (!buffer_uptodate(tmp)) {
 			/* We are traversing bh'es in reverse order so
@@ -2221,6 +2219,7 @@
 	struct kiobuf *	iobuf = NULL;
 	struct page *	map;
 	struct buffer_head *tmp, **bhs = NULL;
+	int		iosize = size;
 
 	if (!nr)
 		return 0;
@@ -2257,7 +2256,7 @@
 			}
 			
 			while (length > 0) {
-				blocknr = b[bufind++];
+				blocknr = b[bufind];
 				if (blocknr == -1UL) {
 					if (rw == READ) {
 						/* there was an hole in the filesystem */
@@ -2270,9 +2269,15 @@
 					} else
 						BUG();
 				}
+				if (iobuf->dovary && (offset == 0)) {
+					iosize = RAWIO_BLOCKSIZE;
+					if (iosize > length)
+						iosize = length;
+				}
+				bufind += (iosize/size);
 				tmp = bhs[bhind++];
 
-				tmp->b_size = size;
+				tmp->b_size = iosize;
 				set_bh_page(tmp, map, offset);
 				tmp->b_this_page = tmp;
 
@@ -2288,7 +2293,10 @@
 					set_bit(BH_Uptodate, &tmp->b_state);
 
 				atomic_inc(&iobuf->io_count);
-				submit_bh(rw, tmp);
+				if (iobuf->dovary)
+					submit_bh_blknr(rw, tmp);
+				else
+					submit_bh(rw, tmp);
 				/* 
 				 * Wait for IO if we have got too much 
 				 */
@@ -2303,8 +2311,8 @@
 				}
 
 			skip_block:
-				length -= size;
-				offset += size;
+				length -= iosize;
+				offset += iosize;
 
 				if (offset >= PAGE_SIZE) {
 					offset = 0;
@@ -2535,63 +2543,23 @@
 	return 1;
 }
 
-/*
- * The first time the VM inspects a page which has locked buffers, it
- * will just mark it as needing waiting upon on the scan of the page LRU.
- * BH_Wait_IO is used for this.
- *
- * The second time the VM visits the page, if it still has locked
- * buffers, it is time to start writing them out.  (BH_Wait_IO was set).
- *
- * The third time the VM visits the page, if the I/O hasn't completed
- * then it's time to wait upon writeout.  BH_Lock and BH_Launder are
- * used for this.
- *
- * There is also the case of buffers which were locked by someone else
- * - write(2) callers, bdflush, etc.  There can be a huge number of these
- * and we don't want to just skip them all and fail the page allocation. 
- * We want to be able to wait on these buffers as well.
- *
- * The BH_Launder bit is set in submit_bh() to indicate that I/O is
- * underway against the buffer, doesn't matter who started it - we know
- * that the buffer will eventually come unlocked, and so it's safe to
- * wait on it.
- *
- * The caller holds the page lock and the caller will free this page
- * into current->local_page, so by waiting on the page's buffers the
- * caller is guaranteed to obtain this page.
- *
- * sync_page_buffers() will sort-of return true if all the buffers
- * against this page are freeable, so try_to_free_buffers() should
- * try to free the page's buffers a second time.  This is a bit
- * broken for blocksize < PAGE_CACHE_SIZE, but not very importantly.
- */
-static int sync_page_buffers(struct buffer_head *head)
+static void sync_page_buffers(struct buffer_head *head)
 {
 	struct buffer_head * bh = head;
-	int tryagain = 1;
 
 	do {
 		if (!buffer_dirty(bh) && !buffer_locked(bh))
 			continue;
 
 		/* Don't start IO first time around.. */
-		if (!test_and_set_bit(BH_Wait_IO, &bh->b_state)) {
-			tryagain = 0;
+		if (!test_and_set_bit(BH_Wait_IO, &bh->b_state))
 			continue;
-		}
 
-		/* Second time through we start actively writing out.. */
-		if (test_and_set_bit(BH_Lock, &bh->b_state)) {
-			if (unlikely(!buffer_launder(bh))) {
-				tryagain = 0;
-				continue;
-			}
-			wait_on_buffer(bh);
-			tryagain = 1;
+		/* If we cannot lock the buffer just skip it. */
+		if (test_and_set_bit(BH_Lock, &bh->b_state))
 			continue;
-		}
 
+		/* Second time through we start actively writing out.. */
 		if (!atomic_set_buffer_clean(bh)) {
 			unlock_buffer(bh);
 			continue;
@@ -2601,10 +2569,9 @@
 		get_bh(bh);
 		bh->b_end_io = end_buffer_io_sync;
 		submit_bh(WRITE, bh);
-		tryagain = 0;
 	} while ((bh = bh->b_this_page) != head);
 
-	return tryagain;
+	return;
 }
 
 /*
@@ -2628,7 +2595,6 @@
 {
 	struct buffer_head * tmp, * bh = page->buffers;
 
-cleaned_buffers_try_again:
 	spin_lock(&lru_list_lock);
 	write_lock(&hash_table_lock);
 	tmp = bh;
@@ -2671,15 +2637,9 @@
 	write_unlock(&hash_table_lock);
 	spin_unlock(&lru_list_lock);
 	gfp_mask = pf_gfp_mask(gfp_mask);
-	if (gfp_mask & __GFP_IO) {
-		if ((gfp_mask & __GFP_HIGHIO) || !PageHighMem(page)) {
-			if (sync_page_buffers(bh)) {
-				/* no IO or waiting next time */
-				gfp_mask = 0;
-				goto cleaned_buffers_try_again;
-			}
-		}
-	}
+	if ((gfp_mask & __GFP_IO) &&
+			((gfp_mask & __GFP_HIGHIO) || !PageHighMem(page)))
+		sync_page_buffers(bh);
 	if (balance_dirty_state() >= 0)
 		wakeup_bdflush();
 	return 0;
@@ -2775,7 +2735,7 @@
 		hash_table = (struct buffer_head **)
 		    __get_free_pages(GFP_ATOMIC, order);
 	} while (hash_table == NULL && --order > 0);
-	printk("Buffer-cache hash table entries: %d (order: %d, %ld bytes)\n",
+	printk(KERN_INFO "Buffer cache hash table entries: %d (order: %d, %ld bytes)\n",
 	       nr_hash, order, (PAGE_SIZE << order));
 
 	if (!hash_table)
@@ -2944,8 +2904,10 @@
 				break;
 			ndirty -= NRSYNC;
 		}
-		if (ndirty > 0 || bdflush_stop())
+		if (ndirty > 0 || bdflush_stop()) {
+			run_task_queue(&tq_disk);
 			interruptible_sleep_on(&bdflush_wait);
+		}
 	}
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/Config.in linux.20pre10-ac2/fs/Config.in
--- linux.20pre10/fs/Config.in	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/Config.in	2002-10-11 00:22:21.000000000 +0100
@@ -5,6 +5,14 @@
 comment 'File systems'
 
 bool 'Quota support' CONFIG_QUOTA
+dep_tristate '  Old quota format support' CONFIG_QFMT_V1 $CONFIG_QUOTA
+dep_tristate '  VFS v0 quota format support' CONFIG_QFMT_V2 $CONFIG_QUOTA
+dep_mbool '  Compatible quota interfaces' CONFIG_QIFACE_COMPAT $CONFIG_QUOTA
+if [ "$CONFIG_QUOTA" = "y" -a "$CONFIG_QIFACE_COMPAT" = "y" ]; then
+   choice '    Compatible quota interfaces' \
+	"Original	CONFIG_QIFACE_V1 \
+	 VFSv0		CONFIG_QIFACE_V2" Original
+fi
 tristate 'Kernel automounter support' CONFIG_AUTOFS_FS
 tristate 'Kernel automounter version 4 support (also supports v3)' CONFIG_AUTOFS4_FS
 
@@ -102,6 +110,7 @@
    dep_tristate 'InterMezzo file system support (replicating fs) (EXPERIMENTAL)' CONFIG_INTERMEZZO_FS $CONFIG_INET $CONFIG_EXPERIMENTAL
    dep_tristate 'NFS file system support' CONFIG_NFS_FS $CONFIG_INET
    dep_mbool '  Provide NFSv3 client support' CONFIG_NFS_V3 $CONFIG_NFS_FS
+   dep_mbool '  Allow direct I/O on NFS files (EXPERIMENTAL)' CONFIG_NFS_DIRECTIO $CONFIG_NFS_FS $CONFIG_EXPERIMENTAL
    dep_bool '  Root file system on NFS' CONFIG_ROOT_NFS $CONFIG_NFS_FS $CONFIG_IP_PNP
 
    dep_tristate 'NFS server support' CONFIG_NFSD $CONFIG_INET
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/dquot.c linux.20pre10-ac2/fs/dquot.c
--- linux.20pre10/fs/dquot.c	2002-10-09 21:36:35.000000000 +0100
+++ linux.20pre10-ac2/fs/dquot.c	2002-08-06 15:41:51.000000000 +0100
@@ -35,7 +35,7 @@
  *		Jan Kara, <jack@suse.cz>, sponsored by SuSE CR, 10-11/99
  *
  *		Used struct list_head instead of own list struct
- *		Invalidation of dquots with dq_count > 0 no longer possible
+ *		Invalidation of referenced dquots is no longer possible
  *		Improved free_dquots list management
  *		Quota and i_blocks are now updated in one place to avoid races
  *		Warnings are now delayed so we won't block in critical section
@@ -45,6 +45,10 @@
  *		Added dynamic quota structure allocation
  *		Jan Kara <jack@suse.cz> 12/2000
  *
+ *		Rewritten quota interface. Implemented new quota format and
+ *		formats registering.
+ *		Jan Kara, <jack@suse.cz>, 2001,2002
+ *
  * (C) Copyright 1994 - 1997 Marco van Wieringen 
  */
 
@@ -59,20 +63,53 @@
 #include <linux/tty.h>
 #include <linux/file.h>
 #include <linux/slab.h>
+#include <linux/sysctl.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
 
 #include <asm/uaccess.h>
 
-#define __DQUOT_VERSION__	"dquot_6.4.0"
+static char *quotatypes[] = INITQFNAMES;
+static struct quota_format_type *quota_formats;	/* List of registered formats */
 
-int nr_dquots, nr_free_dquots;
+int register_quota_format(struct quota_format_type *fmt)
+{
+	lock_kernel();
+	fmt->qf_next = quota_formats;
+	quota_formats = fmt;
+	unlock_kernel();
+	return 0;
+}
 
-static char *quotatypes[] = INITQFNAMES;
+void unregister_quota_format(struct quota_format_type *fmt)
+{
+	struct quota_format_type **actqf;
 
-static inline struct quota_mount_options *sb_dqopt(struct super_block *sb)
+	lock_kernel();
+	for (actqf = &quota_formats; *actqf && *actqf != fmt; actqf = &(*actqf)->qf_next);
+	if (*actqf)
+		*actqf = (*actqf)->qf_next;
+	unlock_kernel();
+}
+
+static struct quota_format_type *find_quota_format(int id)
 {
-	return &sb->s_dquot;
+	struct quota_format_type *actqf;
+
+	lock_kernel();
+	for (actqf = quota_formats; actqf && actqf->qf_fmt_id != id; actqf = actqf->qf_next);
+	if (actqf && !try_inc_mod_count(actqf->qf_owner))
+		actqf = NULL;
+	unlock_kernel();
+	return actqf;
+}
+
+static void put_quota_format(struct quota_format_type *fmt)
+{
+	if (fmt->qf_owner)
+		__MOD_DEC_USE_COUNT(fmt->qf_owner);
 }
 
 /*
@@ -85,11 +122,11 @@
  * list is used for the sync and invalidate operations, which must look
  * at every dquot.
  *
- * Unused dquots (dq_count == 0) are added to the free_dquots list when
- * freed, and this list is searched whenever we need an available dquot.
- * Dquots are removed from the list as soon as they are used again, and
- * nr_free_dquots gives the number of dquots on the list. When dquot is
- * invalidated it's completely released from memory.
+ * Unused dquots (dq_count == 0) are added to the free_dquots list when freed,
+ * and this list is searched whenever we need an available dquot.  Dquots are
+ * removed from the list as soon as they are used again, and
+ * dqstats.free_dquots gives the number of dquots on the list. When
+ * dquot is invalidated it's completely released from memory.
  *
  * Dquots with a specific identity (device, type and id) are placed on
  * one of the dquot_hash[] hash chains. The provides an efficient search
@@ -115,35 +152,39 @@
 static LIST_HEAD(free_dquots);
 static struct list_head dquot_hash[NR_DQHASH];
 
-static struct dqstats dqstats;
+struct dqstats dqstats;
 
 static void dqput(struct dquot *);
 static struct dquot *dqduplicate(struct dquot *);
 
-static inline char is_enabled(struct quota_mount_options *dqopt, short type)
+static inline void get_dquot_ref(struct dquot *dquot)
 {
-	switch (type) {
-		case USRQUOTA:
-			return((dqopt->flags & DQUOT_USR_ENABLED) != 0);
-		case GRPQUOTA:
-			return((dqopt->flags & DQUOT_GRP_ENABLED) != 0);
-	}
-	return(0);
+	dquot->dq_count++;
+}
+
+static inline void put_dquot_ref(struct dquot *dquot)
+{
+	dquot->dq_count--;
+}
+
+static inline void get_dquot_dup_ref(struct dquot *dquot)
+{
+	dquot->dq_dup_ref++;
 }
 
-static inline char sb_has_quota_enabled(struct super_block *sb, short type)
+static inline void put_dquot_dup_ref(struct dquot *dquot)
 {
-	return is_enabled(sb_dqopt(sb), type);
+	dquot->dq_dup_ref--;
 }
 
-static inline int const hashfn(kdev_t dev, unsigned int id, short type)
+static inline int const hashfn(struct super_block *sb, unsigned int id, int type)
 {
-	return((HASHDEV(dev) ^ id) * (MAXQUOTAS - type)) % NR_DQHASH;
+	return((((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type)) % NR_DQHASH;
 }
 
 static inline void insert_dquot_hash(struct dquot *dquot)
 {
-	struct list_head *head = dquot_hash + hashfn(dquot->dq_dev, dquot->dq_id, dquot->dq_type);
+	struct list_head *head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id, dquot->dq_type);
 	list_add(&dquot->dq_hash, head);
 }
 
@@ -153,14 +194,14 @@
 	INIT_LIST_HEAD(&dquot->dq_hash);
 }
 
-static inline struct dquot *find_dquot(unsigned int hashent, kdev_t dev, unsigned int id, short type)
+static inline struct dquot *find_dquot(unsigned int hashent, struct super_block *sb, unsigned int id, int type)
 {
 	struct list_head *head;
 	struct dquot *dquot;
 
 	for (head = dquot_hash[hashent].next; head != dquot_hash+hashent; head = head->next) {
 		dquot = list_entry(head, struct dquot, dq_hash);
-		if (dquot->dq_dev == dev && dquot->dq_id == id && dquot->dq_type == type)
+		if (dquot->dq_sb == sb && dquot->dq_id == id && dquot->dq_type == type)
 			return dquot;
 	}
 	return NODQUOT;
@@ -170,14 +211,14 @@
 static inline void put_dquot_head(struct dquot *dquot)
 {
 	list_add(&dquot->dq_free, &free_dquots);
-	nr_free_dquots++;
+	dqstats.free_dquots++;
 }
 
 /* Add a dquot to the tail of the free list */
 static inline void put_dquot_last(struct dquot *dquot)
 {
 	list_add(&dquot->dq_free, free_dquots.prev);
-	nr_free_dquots++;
+	dqstats.free_dquots++;
 }
 
 /* Move dquot to the head of free list (it must be already on it) */
@@ -193,7 +234,7 @@
 		return;
 	list_del(&dquot->dq_free);
 	INIT_LIST_HEAD(&dquot->dq_free);
-	nr_free_dquots--;
+	dqstats.free_dquots--;
 }
 
 static inline void put_inuse(struct dquot *dquot)
@@ -201,12 +242,12 @@
 	/* We add to the back of inuse list so we don't have to restart
 	 * when traversing this list and we block */
 	list_add(&dquot->dq_inuse, inuse_list.prev);
-	nr_dquots++;
+	dqstats.allocated_dquots++;
 }
 
 static inline void remove_inuse(struct dquot *dquot)
 {
-	nr_dquots--;
+	dqstats.allocated_dquots--;
 	list_del(&dquot->dq_inuse);
 }
 
@@ -243,6 +284,7 @@
 	wake_up(&dquot->dq_wait_lock);
 }
 
+/* Wait for dquot to be unused */
 static void __wait_dquot_unused(struct dquot *dquot)
 {
 	DECLARE_WAITQUEUE(wait, current);
@@ -258,85 +300,56 @@
 	current->state = TASK_RUNNING;
 }
 
-/*
- *	We don't have to be afraid of deadlocks as we never have quotas on quota files...
- */
-static void write_dquot(struct dquot *dquot)
+/* Wait for all duplicated dquot references to be dropped */
+static void __wait_dup_drop(struct dquot *dquot)
 {
-	short type = dquot->dq_type;
-	struct file *filp;
-	mm_segment_t fs;
-	loff_t offset;
-	ssize_t ret;
-	struct semaphore *sem = &dquot->dq_sb->s_dquot.dqio_sem;
-	struct dqblk dqbuf;
-
-	down(sem);
-	filp = dquot->dq_sb->s_dquot.files[type];
-	offset = dqoff(dquot->dq_id);
-	fs = get_fs();
-	set_fs(KERNEL_DS);
+	DECLARE_WAITQUEUE(wait, current);
 
-	/*
-	 * Note: clear the DQ_MOD flag unconditionally,
-	 * so we don't loop forever on failure.
-	 */
-	memcpy(&dqbuf, &dquot->dq_dqb, sizeof(struct dqblk));
-	dquot->dq_flags &= ~DQ_MOD;
-	ret = 0;
-	if (filp)
-		ret = filp->f_op->write(filp, (char *)&dqbuf, 
-					sizeof(struct dqblk), &offset);
-	if (ret != sizeof(struct dqblk))
-		printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
-			kdevname(dquot->dq_dev));
-
-	set_fs(fs);
-	up(sem);
-	dqstats.writes++;
-}
-
-static void read_dquot(struct dquot *dquot)
-{
-	short type = dquot->dq_type;
-	struct file *filp;
-	mm_segment_t fs;
-	loff_t offset;
+	add_wait_queue(&dquot->dq_wait_free, &wait);
+repeat:
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	if (dquot->dq_dup_ref) {
+		schedule();
+		goto repeat;
+	}
+	remove_wait_queue(&dquot->dq_wait_free, &wait);
+	current->state = TASK_RUNNING;
+}
 
-	filp = dquot->dq_sb->s_dquot.files[type];
-	if (filp == (struct file *)NULL)
-		return;
+static int read_dqblk(struct dquot *dquot)
+{
+	int ret;
+	struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
 
 	lock_dquot(dquot);
-	if (!dquot->dq_sb)	/* Invalidated quota? */
-		goto out_lock;
-	/* Now we are sure filp is valid - the dquot isn't invalidated */
-	down(&dquot->dq_sb->s_dquot.dqio_sem);
-	offset = dqoff(dquot->dq_id);
-	fs = get_fs();
-	set_fs(KERNEL_DS);
-	filp->f_op->read(filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk), &offset);
-	up(&dquot->dq_sb->s_dquot.dqio_sem);
-	set_fs(fs);
-
-	if (dquot->dq_bhardlimit == 0 && dquot->dq_bsoftlimit == 0 &&
-	    dquot->dq_ihardlimit == 0 && dquot->dq_isoftlimit == 0)
-		dquot->dq_flags |= DQ_FAKE;
-	dqstats.reads++;
-out_lock:
+	down(&dqopt->dqio_sem);
+	ret = dqopt->ops[dquot->dq_type]->read_dqblk(dquot);
+	up(&dqopt->dqio_sem);
 	unlock_dquot(dquot);
+	return ret;
+}
+
+static int commit_dqblk(struct dquot *dquot)
+{
+	int ret;
+	struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
+
+	down(&dqopt->dqio_sem);
+	ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot);
+	up(&dqopt->dqio_sem);
+	return ret;
 }
 
 /* Invalidate all dquots on the list, wait for all users. Note that this function is called
  * after quota is disabled so no new quota might be created. As we only insert to the end of
  * inuse list, we don't have to restart searching... */
-static void invalidate_dquots(struct super_block *sb, short type)
+static void invalidate_dquots(struct super_block *sb, int type)
 {
 	struct dquot *dquot;
 	struct list_head *head;
 
 restart:
-	for (head = inuse_list.next; head != &inuse_list; head = head->next) {
+	list_for_each(head, &inuse_list) {
 		dquot = list_entry(head, struct dquot, dq_inuse);
 		if (dquot->dq_sb != sb)
 			continue;
@@ -359,37 +372,107 @@
 	}
 }
 
-int sync_dquots(kdev_t dev, short type)
+static int vfs_quota_sync(struct super_block *sb, int type)
 {
 	struct list_head *head;
 	struct dquot *dquot;
+	struct quota_info *dqopt = sb_dqopt(sb);
+	int cnt;
 
-	lock_kernel();
 restart:
-	for (head = inuse_list.next; head != &inuse_list; head = head->next) {
+	list_for_each(head, &inuse_list) {
 		dquot = list_entry(head, struct dquot, dq_inuse);
-		if (dev && dquot->dq_dev != dev)
+		if (sb && dquot->dq_sb != sb)
 			continue;
                 if (type != -1 && dquot->dq_type != type)
 			continue;
 		if (!dquot->dq_sb)	/* Invalidated? */
 			continue;
-		if (!(dquot->dq_flags & (DQ_MOD | DQ_LOCKED)))
+		if (!dquot_dirty(dquot) && !(dquot->dq_flags & DQ_LOCKED))
 			continue;
-		/* Raise use count so quota won't be invalidated. We can't use dqduplicate() as it does too many tests */
-		dquot->dq_count++;
+		/* Get reference to quota so it won't be invalidated. get_dquot_ref()
+		 * is enough since if dquot is locked/modified it can't be
+		 * on the free list */
+		get_dquot_ref(dquot);
 		if (dquot->dq_flags & DQ_LOCKED)
 			wait_on_dquot(dquot);
-		if (dquot->dq_flags & DQ_MOD)
-			write_dquot(dquot);
+		if (dquot_dirty(dquot))
+			commit_dqblk(dquot);
 		dqput(dquot);
 		goto restart;
 	}
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+		if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt))
+			dqopt->info[cnt].dqi_flags &= ~DQF_ANY_DQUOT_DIRTY;
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+		if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt) && info_dirty(&dqopt->info[cnt]))
+			dqopt->ops[cnt]->write_file_info(sb, cnt);
 	dqstats.syncs++;
-	unlock_kernel();
+
 	return 0;
 }
 
+static struct super_block *get_super_to_sync(int type)
+{
+	struct list_head *head;
+	int cnt, dirty;
+
+restart:
+	spin_lock(&sb_lock);
+	list_for_each(head, &super_blocks) {
+		struct super_block *sb = list_entry(head, struct super_block, s_list);
+
+		for (cnt = 0, dirty = 0; cnt < MAXQUOTAS; cnt++)
+			if ((type == cnt || type == -1) && sb_has_quota_enabled(sb, cnt)
+			    && sb_dqopt(sb)->info[cnt].dqi_flags & DQF_ANY_DQUOT_DIRTY)
+				dirty = 1;
+		if (!dirty)
+			continue;
+		sb->s_count++;
+		spin_unlock(&sb_lock);
+		down_read(&sb->s_umount);
+		if (!sb->s_root) {
+			drop_super(sb);
+			goto restart;
+		}
+		return sb;
+	}
+	spin_unlock(&sb_lock);
+	return NULL;
+}
+
+void sync_dquots_dev(kdev_t dev, int type)
+{
+	struct super_block *sb;
+
+	if (dev) {
+		if ((sb = get_super(dev))) {
+			lock_kernel();
+			if (sb->s_qcop->quota_sync)
+				sb->s_qcop->quota_sync(sb, type);
+			unlock_kernel();
+			drop_super(sb);
+		}
+	}
+	else {
+		while ((sb = get_super_to_sync(type))) {
+			lock_kernel();
+			if (sb->s_qcop->quota_sync)
+				sb->s_qcop->quota_sync(sb, type);
+			unlock_kernel();
+			drop_super(sb);
+		}
+	}
+}
+
+void sync_dquots_sb(struct super_block *sb, int type)
+{
+	lock_kernel();
+	if (sb->s_qcop->quota_sync)
+		sb->s_qcop->quota_sync(sb, type);
+	unlock_kernel();
+}
+
 /* Free unused dquots from cache */
 static void prune_dqcache(int count)
 {
@@ -408,19 +491,38 @@
 	}
 }
 
+/*
+ * This is called from kswapd when we think we need some
+ * more memory, but aren't really sure how much. So we
+ * carefully try to free a _bit_ of our dqcache, but not
+ * too much.
+ *
+ * Priority:
+ *   1 - very urgent: shrink everything
+ *   ...
+ *   6 - base-level: try to shrink a bit.
+ */
+
 int shrink_dqcache_memory(int priority, unsigned int gfp_mask)
 {
+	int count = 0;
+
 	lock_kernel();
-	prune_dqcache(nr_free_dquots / (priority + 1));
+	count = dqstats.free_dquots / priority;
+	prune_dqcache(count);
 	unlock_kernel();
 	return kmem_cache_shrink(dquot_cachep);
 }
 
-/* NOTE: If you change this function please check whether dqput_blocks() works right... */
+/*
+ * Put reference to dquot
+ * NOTE: If you change this function please check whether dqput_blocks() works right...
+ */
 static void dqput(struct dquot *dquot)
 {
 	if (!dquot)
 		return;
+#ifdef __DQUOT_PARANOIA
 	if (!dquot->dq_count) {
 		printk("VFS: dqput: trying to free free dquot\n");
 		printk("VFS: device %s, dquot of %s %d\n",
@@ -428,33 +530,38 @@
 			dquot->dq_id);
 		return;
 	}
+#endif
 
 	dqstats.drops++;
 we_slept:
+	if (dquot->dq_dup_ref && dquot->dq_count - dquot->dq_dup_ref <= 1) {	/* Last unduplicated reference? */
+		__wait_dup_drop(dquot);
+		goto we_slept;
+	}
 	if (dquot->dq_count > 1) {
 		/* We have more than one user... We can simply decrement use count */
-		dquot->dq_count--;
+		put_dquot_ref(dquot);
 		return;
 	}
-	if (dquot->dq_flags & DQ_MOD) {
-		write_dquot(dquot);
+	if (dquot_dirty(dquot)) {
+		commit_dqblk(dquot);
 		goto we_slept;
 	}
 
 	/* sanity check */
 	if (!list_empty(&dquot->dq_free)) {
 		printk(KERN_ERR "dqput: dquot already on free list??\n");
-		dquot->dq_count--;	/* J.K. Just decrementing use count seems safer... */
+		put_dquot_ref(dquot);
 		return;
 	}
-	dquot->dq_count--;
+	put_dquot_ref(dquot);
 	/* If dquot is going to be invalidated invalidate_dquots() is going to free it so */
 	if (!(dquot->dq_flags & DQ_INVAL))
 		put_dquot_last(dquot);	/* Place at end of LRU free queue */
 	wake_up(&dquot->dq_wait_free);
 }
 
-static struct dquot *get_empty_dquot(void)
+static struct dquot *get_empty_dquot(struct super_block *sb, int type)
 {
 	struct dquot *dquot;
 
@@ -468,6 +575,9 @@
 	INIT_LIST_HEAD(&dquot->dq_free);
 	INIT_LIST_HEAD(&dquot->dq_inuse);
 	INIT_LIST_HEAD(&dquot->dq_hash);
+	dquot->dq_sb = sb;
+	dquot->dq_dev = sb->s_dev;
+	dquot->dq_type = type;
 	dquot->dq_count = 1;
 	/* all dquots go on the inuse_list */
 	put_inuse(dquot);
@@ -475,11 +585,11 @@
 	return dquot;
 }
 
-static struct dquot *dqget(struct super_block *sb, unsigned int id, short type)
+static struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
 {
-	unsigned int hashent = hashfn(sb->s_dev, id, type);
+	unsigned int hashent = hashfn(sb, id, type);
 	struct dquot *dquot, *empty = NODQUOT;
-	struct quota_mount_options *dqopt = sb_dqopt(sb);
+	struct quota_info *dqopt = sb_dqopt(sb);
 
 we_slept:
         if (!is_enabled(dqopt, type)) {
@@ -488,23 +598,21 @@
                 return NODQUOT;
 	}
 
-	if ((dquot = find_dquot(hashent, sb->s_dev, id, type)) == NODQUOT) {
+	if ((dquot = find_dquot(hashent, sb, id, type)) == NODQUOT) {
 		if (empty == NODQUOT) {
-			if ((empty = get_empty_dquot()) == NODQUOT)
+			if ((empty = get_empty_dquot(sb, type)) == NODQUOT)
 				schedule();	/* Try to wait for a moment... */
 			goto we_slept;
 		}
 		dquot = empty;
-        	dquot->dq_id = id;
-        	dquot->dq_type = type;
-        	dquot->dq_dev = sb->s_dev;
-        	dquot->dq_sb = sb;
+		dquot->dq_id = id;
 		/* hash it first so it can be found */
 		insert_dquot_hash(dquot);
-        	read_dquot(dquot);
+		read_dqblk(dquot);
 	} else {
-		if (!dquot->dq_count++)
+		if (!dquot->dq_count)
 			remove_free_dquot(dquot);
+		get_dquot_ref(dquot);
 		dqstats.cache_hits++;
 		wait_on_dquot(dquot);
 		if (empty)
@@ -516,30 +624,47 @@
 		dqput(dquot);
 		return NODQUOT;
 	}
-	dquot->dq_referenced++;
+	++dquot->dq_referenced;
 	dqstats.lookups++;
 
 	return dquot;
 }
 
+/* Duplicate reference to dquot got from inode */
 static struct dquot *dqduplicate(struct dquot *dquot)
 {
 	if (dquot == NODQUOT)
 		return NODQUOT;
-	dquot->dq_count++;
+	get_dquot_ref(dquot);
 	if (!dquot->dq_sb) {
 		printk(KERN_ERR "VFS: dqduplicate(): Invalidated quota to be duplicated!\n");
-		dquot->dq_count--;
+		put_dquot_ref(dquot);
 		return NODQUOT;
 	}
 	if (dquot->dq_flags & DQ_LOCKED)
 		printk(KERN_ERR "VFS: dqduplicate(): Locked quota to be duplicated!\n");
+	get_dquot_dup_ref(dquot);
 	dquot->dq_referenced++;
 	dqstats.lookups++;
+
 	return dquot;
 }
 
-static int dqinit_needed(struct inode *inode, short type)
+/* Put duplicated reference */
+static void dqputduplicate(struct dquot *dquot)
+{
+	if (!dquot->dq_dup_ref) {
+		printk(KERN_ERR "VFS: dqputduplicate(): Duplicated dquot put without duplicate reference.\n");
+		return;
+	}
+	put_dquot_dup_ref(dquot);
+	if (!dquot->dq_dup_ref)
+		wake_up(&dquot->dq_wait_free);
+	put_dquot_ref(dquot);
+	dqstats.drops++;
+}
+
+static int dqinit_needed(struct inode *inode, int type)
 {
 	int cnt;
 
@@ -553,16 +678,13 @@
 	return 0;
 }
 
-static void add_dquot_ref(struct super_block *sb, short type)
+static void add_dquot_ref(struct super_block *sb, int type)
 {
 	struct list_head *p;
 
-	if (!sb->dq_op)
-		return;	/* nothing to do */
-
 restart:
 	file_list_lock();
-	for (p = sb->s_files.next; p != &sb->s_files; p = p->next) {
+	list_for_each(p, &sb->s_files) {
 		struct file *filp = list_entry(p, struct file, f_list);
 		struct inode *inode = filp->f_dentry->d_inode;
 		if (filp->f_mode & FMODE_WRITE && dqinit_needed(inode, type)) {
@@ -582,13 +704,15 @@
 /* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */
 static inline int dqput_blocks(struct dquot *dquot)
 {
-	if (dquot->dq_count == 1)
+	if (dquot->dq_dup_ref && dquot->dq_count - dquot->dq_dup_ref <= 1)
+		return 1;
+	if (dquot->dq_count <= 1 && dquot->dq_flags & DQ_MOD)
 		return 1;
 	return 0;
 }
 
 /* Remove references to dquots from inode - add dquot to list for freeing if needed */
-int remove_inode_dquot_ref(struct inode *inode, short type, struct list_head *tofree_head)
+int remove_inode_dquot_ref(struct inode *inode, int type, struct list_head *tofree_head)
 {
 	struct dquot *dquot = inode->i_dquot[type];
 	int cnt;
@@ -635,38 +759,38 @@
 
 static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number)
 {
-	dquot->dq_curinodes += number;
-	dquot->dq_flags |= DQ_MOD;
+	dquot->dq_dqb.dqb_curinodes += number;
+	mark_dquot_dirty(dquot);
 }
 
-static inline void dquot_incr_blocks(struct dquot *dquot, unsigned long number)
+static inline void dquot_incr_space(struct dquot *dquot, qsize_t number)
 {
-	dquot->dq_curblocks += number;
-	dquot->dq_flags |= DQ_MOD;
+	dquot->dq_dqb.dqb_curspace += number;
+	mark_dquot_dirty(dquot);
 }
 
 static inline void dquot_decr_inodes(struct dquot *dquot, unsigned long number)
 {
-	if (dquot->dq_curinodes > number)
-		dquot->dq_curinodes -= number;
+	if (dquot->dq_dqb.dqb_curinodes > number)
+		dquot->dq_dqb.dqb_curinodes -= number;
 	else
-		dquot->dq_curinodes = 0;
-	if (dquot->dq_curinodes < dquot->dq_isoftlimit)
-		dquot->dq_itime = (time_t) 0;
+		dquot->dq_dqb.dqb_curinodes = 0;
+	if (dquot->dq_dqb.dqb_curinodes < dquot->dq_dqb.dqb_isoftlimit)
+		dquot->dq_dqb.dqb_itime = (time_t) 0;
 	dquot->dq_flags &= ~DQ_INODES;
-	dquot->dq_flags |= DQ_MOD;
+	mark_dquot_dirty(dquot);
 }
 
-static inline void dquot_decr_blocks(struct dquot *dquot, unsigned long number)
+static inline void dquot_decr_space(struct dquot *dquot, qsize_t number)
 {
-	if (dquot->dq_curblocks > number)
-		dquot->dq_curblocks -= number;
+	if (dquot->dq_dqb.dqb_curspace > number)
+		dquot->dq_dqb.dqb_curspace -= number;
 	else
-		dquot->dq_curblocks = 0;
-	if (dquot->dq_curblocks < dquot->dq_bsoftlimit)
-		dquot->dq_btime = (time_t) 0;
+		dquot->dq_dqb.dqb_curspace = 0;
+	if (toqb(dquot->dq_dqb.dqb_curspace) < dquot->dq_dqb.dqb_bsoftlimit)
+		dquot->dq_dqb.dqb_btime = (time_t) 0;
 	dquot->dq_flags &= ~DQ_BLKS;
-	dquot->dq_flags |= DQ_MOD;
+	mark_dquot_dirty(dquot);
 }
 
 static inline int need_print_warning(struct dquot *dquot, int flag)
@@ -739,7 +863,10 @@
 
 static inline char ignore_hardlimit(struct dquot *dquot)
 {
-	return capable(CAP_SYS_RESOURCE) && !dquot->dq_sb->s_dquot.rsquash[dquot->dq_type];
+	struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
+
+	return capable(CAP_SYS_RESOURCE) &&
+	    (info->dqi_format->qf_fmt_id != QFMT_VFS_OLD || !(info->dqi_flags & V1_DQF_RSQUASH));
 }
 
 static int check_idq(struct dquot *dquot, ulong inodes, char *warntype)
@@ -748,60 +875,60 @@
 	if (inodes <= 0 || dquot->dq_flags & DQ_FAKE)
 		return QUOTA_OK;
 
-	if (dquot->dq_ihardlimit &&
-	   (dquot->dq_curinodes + inodes) > dquot->dq_ihardlimit &&
+	if (dquot->dq_dqb.dqb_ihardlimit &&
+	   (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_ihardlimit &&
             !ignore_hardlimit(dquot)) {
 		*warntype = IHARDWARN;
 		return NO_QUOTA;
 	}
 
-	if (dquot->dq_isoftlimit &&
-	   (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit &&
-	    dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime &&
+	if (dquot->dq_dqb.dqb_isoftlimit &&
+	   (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit &&
+	    dquot->dq_dqb.dqb_itime && CURRENT_TIME >= dquot->dq_dqb.dqb_itime &&
             !ignore_hardlimit(dquot)) {
 		*warntype = ISOFTLONGWARN;
 		return NO_QUOTA;
 	}
 
-	if (dquot->dq_isoftlimit &&
-	   (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit &&
-	    dquot->dq_itime == 0) {
+	if (dquot->dq_dqb.dqb_isoftlimit &&
+	   (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit &&
+	    dquot->dq_dqb.dqb_itime == 0) {
 		*warntype = ISOFTWARN;
-		dquot->dq_itime = CURRENT_TIME + dquot->dq_sb->s_dquot.inode_expire[dquot->dq_type];
+		dquot->dq_dqb.dqb_itime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
 	}
 
 	return QUOTA_OK;
 }
 
-static int check_bdq(struct dquot *dquot, ulong blocks, char prealloc, char *warntype)
+static int check_bdq(struct dquot *dquot, qsize_t space, int prealloc, char *warntype)
 {
 	*warntype = 0;
-	if (blocks <= 0 || dquot->dq_flags & DQ_FAKE)
+	if (space <= 0 || dquot->dq_flags & DQ_FAKE)
 		return QUOTA_OK;
 
-	if (dquot->dq_bhardlimit &&
-	   (dquot->dq_curblocks + blocks) > dquot->dq_bhardlimit &&
+	if (dquot->dq_dqb.dqb_bhardlimit &&
+	   toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bhardlimit &&
             !ignore_hardlimit(dquot)) {
 		if (!prealloc)
 			*warntype = BHARDWARN;
 		return NO_QUOTA;
 	}
 
-	if (dquot->dq_bsoftlimit &&
-	   (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit &&
-	    dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime &&
+	if (dquot->dq_dqb.dqb_bsoftlimit &&
+	   toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bsoftlimit &&
+	    dquot->dq_dqb.dqb_btime && CURRENT_TIME >= dquot->dq_dqb.dqb_btime &&
             !ignore_hardlimit(dquot)) {
 		if (!prealloc)
 			*warntype = BSOFTLONGWARN;
 		return NO_QUOTA;
 	}
 
-	if (dquot->dq_bsoftlimit &&
-	   (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit &&
-	    dquot->dq_btime == 0) {
+	if (dquot->dq_dqb.dqb_bsoftlimit &&
+	   toqb(dquot->dq_dqb.dqb_curspace + space) > dquot->dq_dqb.dqb_bsoftlimit &&
+	    dquot->dq_dqb.dqb_btime == 0) {
 		if (!prealloc) {
 			*warntype = BSOFTWARN;
-			dquot->dq_btime = CURRENT_TIME + dquot->dq_sb->s_dquot.block_expire[dquot->dq_type];
+			dquot->dq_dqb.dqb_btime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace;
 		}
 		else
 			/*
@@ -815,148 +942,15 @@
 }
 
 /*
- * Initialize a dquot-struct with new quota info. This is used by the
- * system call interface functions.
- */ 
-static int set_dqblk(struct super_block *sb, int id, short type, int flags, struct dqblk *dqblk)
-{
-	struct dquot *dquot;
-	int error = -EFAULT;
-	struct dqblk dq_dqblk;
-
-	if (copy_from_user(&dq_dqblk, dqblk, sizeof(struct dqblk)))
-		return error;
-
-	if (sb && (dquot = dqget(sb, id, type)) != NODQUOT) {
-		/* We can't block while changing quota structure... */
-		if (id > 0 && ((flags & SET_QUOTA) || (flags & SET_QLIMIT))) {
-			dquot->dq_bhardlimit = dq_dqblk.dqb_bhardlimit;
-			dquot->dq_bsoftlimit = dq_dqblk.dqb_bsoftlimit;
-			dquot->dq_ihardlimit = dq_dqblk.dqb_ihardlimit;
-			dquot->dq_isoftlimit = dq_dqblk.dqb_isoftlimit;
-		}
-
-		if ((flags & SET_QUOTA) || (flags & SET_USE)) {
-			if (dquot->dq_isoftlimit &&
-			    dquot->dq_curinodes < dquot->dq_isoftlimit &&
-			    dq_dqblk.dqb_curinodes >= dquot->dq_isoftlimit)
-				dquot->dq_itime = CURRENT_TIME + dquot->dq_sb->s_dquot.inode_expire[type];
-			dquot->dq_curinodes = dq_dqblk.dqb_curinodes;
-			if (dquot->dq_curinodes < dquot->dq_isoftlimit)
-				dquot->dq_flags &= ~DQ_INODES;
-			if (dquot->dq_bsoftlimit &&
-			    dquot->dq_curblocks < dquot->dq_bsoftlimit &&
-			    dq_dqblk.dqb_curblocks >= dquot->dq_bsoftlimit)
-				dquot->dq_btime = CURRENT_TIME + dquot->dq_sb->s_dquot.block_expire[type];
-			dquot->dq_curblocks = dq_dqblk.dqb_curblocks;
-			if (dquot->dq_curblocks < dquot->dq_bsoftlimit)
-				dquot->dq_flags &= ~DQ_BLKS;
-		}
-
-		if (id == 0) {
-			dquot->dq_sb->s_dquot.block_expire[type] = dquot->dq_btime = dq_dqblk.dqb_btime;
-			dquot->dq_sb->s_dquot.inode_expire[type] = dquot->dq_itime = dq_dqblk.dqb_itime;
-		}
-
-		if (dq_dqblk.dqb_bhardlimit == 0 && dq_dqblk.dqb_bsoftlimit == 0 &&
-		    dq_dqblk.dqb_ihardlimit == 0 && dq_dqblk.dqb_isoftlimit == 0)
-			dquot->dq_flags |= DQ_FAKE;
-		else
-			dquot->dq_flags &= ~DQ_FAKE;
-
-		dquot->dq_flags |= DQ_MOD;
-		dqput(dquot);
-	}
-	return 0;
-}
-
-static int get_quota(struct super_block *sb, int id, short type, struct dqblk *dqblk)
-{
-	struct dquot *dquot;
-	struct dqblk data;
-	int error = -ESRCH;
-
-	if (!sb || !sb_has_quota_enabled(sb, type))
-		goto out;
-	dquot = dqget(sb, id, type);
-	if (dquot == NODQUOT)
-		goto out;
-
-	memcpy(&data, &dquot->dq_dqb, sizeof(struct dqblk));        /* We copy data to preserve them from changing */
-	dqput(dquot);
-	error = -EFAULT;
-	if (dqblk && !copy_to_user(dqblk, &data, sizeof(struct dqblk)))
-		error = 0;
-out:
-	return error;
-}
-
-static int get_stats(caddr_t addr)
-{
-	int error = -EFAULT;
-	struct dqstats stats;
-
-	dqstats.allocated_dquots = nr_dquots;
-	dqstats.free_dquots = nr_free_dquots;
-
-	/* make a copy, in case we page-fault in user space */
-	memcpy(&stats, &dqstats, sizeof(struct dqstats));
-	if (!copy_to_user(addr, &stats, sizeof(struct dqstats)))
-		error = 0;
-	return error;
-}
-
-static int quota_root_squash(struct super_block *sb, short type, int *addr)
-{
-	int new_value, error;
-
-	if (!sb)
-		return(-ENODEV);
-
-	error = -EFAULT;
-	if (!copy_from_user(&new_value, addr, sizeof(int))) {
-		sb_dqopt(sb)->rsquash[type] = new_value;
-		error = 0;
-	}
-	return error;
-}
-
-#if 0	/* We are not going to support filesystems without i_blocks... */
-/*
- * This is a simple algorithm that calculates the size of a file in blocks.
- * This is only used on filesystems that do not have an i_blocks count.
- */
-static u_long isize_to_blocks(loff_t isize, size_t blksize_bits)
-{
-	u_long blocks;
-	u_long indirect;
-
-	if (!blksize_bits)
-		blksize_bits = BLOCK_SIZE_BITS;
-	blocks = (isize >> blksize_bits) + ((isize & ~((1 << blksize_bits)-1)) ? 1 : 0);
-	if (blocks > 10) {
-		indirect = ((blocks - 11) >> 8) + 1; /* single indirect blocks */
-		if (blocks > (10 + 256)) {
-			indirect += ((blocks - 267) >> 16) + 1; /* double indirect blocks */
-			if (blocks > (10 + 256 + (256 << 8)))
-				indirect++; /* triple indirect blocks */
-		}
-		blocks += indirect;
-	}
-	return blocks;
-}
-#endif
-
-/*
  * Externally referenced functions through dquot_operations in inode.
  *
  * Note: this is a blocking operation.
  */
-void dquot_initialize(struct inode *inode, short type)
+void dquot_initialize(struct inode *inode, int type)
 {
 	struct dquot *dquot[MAXQUOTAS];
 	unsigned int id = 0;
-	short cnt;
+	int cnt;
 
 	if (IS_NOQUOTA(inode))
 		return;
@@ -1002,7 +996,7 @@
 void dquot_drop(struct inode *inode)
 {
 	struct dquot *dquot;
-	short cnt;
+	int cnt;
 
 	inode->i_flags &= ~S_QUOTA;
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
@@ -1017,7 +1011,7 @@
 /*
  * This operation can block, but only after everything is updated
  */
-int dquot_alloc_block(struct inode *inode, unsigned long number, char warn)
+int dquot_alloc_space(struct inode *inode, qsize_t number, int warn)
 {
 	int cnt, ret = NO_QUOTA;
 	struct dquot *dquot[MAXQUOTAS];
@@ -1038,16 +1032,16 @@
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		if (dquot[cnt] == NODQUOT)
 			continue;
-		dquot_incr_blocks(dquot[cnt], number);
+		dquot_incr_space(dquot[cnt], number);
 	}
-	inode->i_blocks += number << (BLOCK_SIZE_BITS - 9);
+	inode_add_bytes(inode, number);
 	/* NOBLOCK End */
 	ret = QUOTA_OK;
 warn_put_all:
 	flush_warnings(dquot, warntype);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
 		if (dquot[cnt] != NODQUOT)
-			dqput(dquot[cnt]);
+			dqputduplicate(dquot[cnt]);
 	return ret;
 }
 
@@ -1084,16 +1078,16 @@
 	flush_warnings(dquot, warntype);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
 		if (dquot[cnt] != NODQUOT)
-			dqput(dquot[cnt]);
+			dqputduplicate(dquot[cnt]);
 	return ret;
 }
 
 /*
  * This is a non-blocking operation.
  */
-void dquot_free_block(struct inode *inode, unsigned long number)
+void dquot_free_space(struct inode *inode, qsize_t number)
 {
-	unsigned short cnt;
+	unsigned int cnt;
 	struct dquot *dquot;
 
 	/* NOBLOCK Start */
@@ -1101,10 +1095,10 @@
 		dquot = dqduplicate(inode->i_dquot[cnt]);
 		if (dquot == NODQUOT)
 			continue;
-		dquot_decr_blocks(dquot, number);
-		dqput(dquot);
+		dquot_decr_space(dquot, number);
+		dqputduplicate(dquot);
 	}
-	inode->i_blocks -= number << (BLOCK_SIZE_BITS - 9);
+	inode_sub_bytes(inode, number);
 	/* NOBLOCK End */
 }
 
@@ -1113,7 +1107,7 @@
  */
 void dquot_free_inode(const struct inode *inode, unsigned long number)
 {
-	unsigned short cnt;
+	unsigned int cnt;
 	struct dquot *dquot;
 
 	/* NOBLOCK Start */
@@ -1122,7 +1116,7 @@
 		if (dquot == NODQUOT)
 			continue;
 		dquot_decr_inodes(dquot, number);
-		dqput(dquot);
+		dqputduplicate(dquot);
 	}
 	/* NOBLOCK End */
 }
@@ -1134,7 +1128,7 @@
  */
 int dquot_transfer(struct inode *inode, struct iattr *iattr)
 {
-	unsigned long blocks;
+	qsize_t space;
 	struct dquot *transfer_from[MAXQUOTAS];
 	struct dquot *transfer_to[MAXQUOTAS];
 	int cnt, ret = NO_QUOTA, chuid = (iattr->ia_valid & ATTR_UID) && inode->i_uid != iattr->ia_uid,
@@ -1164,7 +1158,7 @@
 		}
 	}
 	/* NOBLOCK START: From now on we shouldn't block */
-	blocks = (inode->i_blocks >> 1);
+	space = inode_get_bytes(inode);
 	/* Build the transfer_from list and check the limits */
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
 		/* The second test can fail when quotaoff is in progress... */
@@ -1174,7 +1168,7 @@
 		if (transfer_from[cnt] == NODQUOT)	/* Can happen on quotafiles (quota isn't initialized on them)... */
 			continue;
 		if (check_idq(transfer_to[cnt], 1, warntype+cnt) == NO_QUOTA ||
-		    check_bdq(transfer_to[cnt], blocks, 0, warntype+cnt) == NO_QUOTA)
+		    check_bdq(transfer_to[cnt], space, 0, warntype+cnt) == NO_QUOTA)
 			goto warn_put_all;
 	}
 
@@ -1189,10 +1183,10 @@
 			continue;
 
 		dquot_decr_inodes(transfer_from[cnt], 1);
-		dquot_decr_blocks(transfer_from[cnt], blocks);
+		dquot_decr_space(transfer_from[cnt], space);
 
 		dquot_incr_inodes(transfer_to[cnt], 1);
-		dquot_incr_blocks(transfer_to[cnt], blocks);
+		dquot_incr_space(transfer_to[cnt], space);
 
 		if (inode->i_dquot[cnt] == NODQUOT)
 			BUG();
@@ -1208,39 +1202,29 @@
 warn_put_all:
 	flush_warnings(transfer_to, warntype);
 	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		/* First we must put duplicate - otherwise we might deadlock */
 		if (transfer_to[cnt] != NODQUOT)
-			dqput(transfer_to[cnt]);
+			dqputduplicate(transfer_to[cnt]);
 		if (transfer_from[cnt] != NODQUOT)
 			dqput(transfer_from[cnt]);
 	}
 	return ret;
 }
 
-static int __init dquot_init(void)
-{
-	int i;
-
-	for (i = 0; i < NR_DQHASH; i++)
-		INIT_LIST_HEAD(dquot_hash + i);
-	printk(KERN_NOTICE "VFS: Diskquotas version %s initialized\n", __DQUOT_VERSION__);
-	return 0;
-}
-__initcall(dquot_init);
-
 /*
  * Definitions of diskquota operations.
  */
 struct dquot_operations dquot_operations = {
-	dquot_initialize,		/* mandatory */
-	dquot_drop,			/* mandatory */
-	dquot_alloc_block,
-	dquot_alloc_inode,
-	dquot_free_block,
-	dquot_free_inode,
-	dquot_transfer
+	initialize:	dquot_initialize,		/* mandatory */
+	drop:		dquot_drop,			/* mandatory */
+	alloc_space:	dquot_alloc_space,
+	alloc_inode:	dquot_alloc_inode,
+	free_space:	dquot_free_space,
+	free_inode:	dquot_free_inode,
+	transfer:	dquot_transfer
 };
 
-static inline void set_enable_flags(struct quota_mount_options *dqopt, short type)
+static inline void set_enable_flags(struct quota_info *dqopt, int type)
 {
 	switch (type) {
 		case USRQUOTA:
@@ -1252,7 +1236,7 @@
 	}
 }
 
-static inline void reset_enable_flags(struct quota_mount_options *dqopt, short type)
+static inline void reset_enable_flags(struct quota_info *dqopt, int type)
 {
 	switch (type) {
 		case USRQUOTA:
@@ -1265,16 +1249,15 @@
 }
 
 /* Function in inode.c - remove pointers to dquots in icache */
-extern void remove_dquot_ref(struct super_block *, short);
+extern void remove_dquot_ref(struct super_block *, int);
 
 /*
  * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
  */
-int quota_off(struct super_block *sb, short type)
+int vfs_quota_off(struct super_block *sb, int type)
 {
-	struct file *filp;
-	short cnt;
-	struct quota_mount_options *dqopt = sb_dqopt(sb);
+	int cnt;
+	struct quota_info *dqopt = sb_dqopt(sb);
 
 	lock_kernel();
 	if (!sb)
@@ -1292,51 +1275,48 @@
 		/* Note: these are blocking operations */
 		remove_dquot_ref(sb, cnt);
 		invalidate_dquots(sb, cnt);
+		if (info_dirty(&dqopt->info[cnt]))
+			dqopt->ops[cnt]->write_file_info(sb, cnt);
+		if (dqopt->ops[cnt]->free_file_info)
+			dqopt->ops[cnt]->free_file_info(sb, cnt);
+		put_quota_format(dqopt->info[cnt].dqi_format);
 
-		filp = dqopt->files[cnt];
+		fput(dqopt->files[cnt]);
 		dqopt->files[cnt] = (struct file *)NULL;
-		dqopt->inode_expire[cnt] = 0;
-		dqopt->block_expire[cnt] = 0;
-		fput(filp);
-	}	
+		dqopt->info[cnt].dqi_flags = 0;
+		dqopt->info[cnt].dqi_igrace = 0;
+		dqopt->info[cnt].dqi_bgrace = 0;
+		dqopt->ops[cnt] = NULL;
+	}
 	up(&dqopt->dqoff_sem);
 out:
 	unlock_kernel();
 	return 0;
 }
 
-static inline int check_quotafile_size(loff_t size)
-{
-	ulong blocks = size >> BLOCK_SIZE_BITS;
-	size_t off = size & (BLOCK_SIZE - 1);
-
-	return !(((blocks % sizeof(struct dqblk)) * BLOCK_SIZE + off % sizeof(struct dqblk)) % sizeof(struct dqblk));
-}
-
-static int quota_on(struct super_block *sb, short type, char *path)
+int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path)
 {
-	struct file *f;
+	struct file *f = NULL;
 	struct inode *inode;
-	struct dquot *dquot;
-	struct quota_mount_options *dqopt = sb_dqopt(sb);
-	char *tmp;
+	struct quota_info *dqopt = sb_dqopt(sb);
+	struct quota_format_type *fmt = find_quota_format(format_id);
 	int error;
 
-	if (is_enabled(dqopt, type))
-		return -EBUSY;
+	if (!fmt)
+		return -ESRCH;
+	if (is_enabled(dqopt, type)) {
+		error = -EBUSY;
+		goto out_fmt;
+	}
 
 	down(&dqopt->dqoff_sem);
-	tmp = getname(path);
-	error = PTR_ERR(tmp);
-	if (IS_ERR(tmp))
-		goto out_lock;
 
-	f = filp_open(tmp, O_RDWR, 0600);
-	putname(tmp);
+	f = filp_open(path, O_RDWR, 0600);
 
 	error = PTR_ERR(f);
 	if (IS_ERR(f))
 		goto out_lock;
+	dqopt->files[type] = f;
 	error = -EIO;
 	if (!f->f_op || !f->f_op->read || !f->f_op->write)
 		goto out_f;
@@ -1345,134 +1325,197 @@
 	if (!S_ISREG(inode->i_mode))
 		goto out_f;
 	error = -EINVAL;
-	if (inode->i_size == 0 || !check_quotafile_size(inode->i_size))
+	if (!fmt->qf_ops->check_quota_file(sb, type))
 		goto out_f;
 	/* We don't want quota on quota files */
 	dquot_drop(inode);
 	inode->i_flags |= S_NOQUOTA;
 
-	dqopt->files[type] = f;
-	sb->dq_op = &dquot_operations;
+	dqopt->ops[type] = fmt->qf_ops;
+	dqopt->info[type].dqi_format = fmt;
+	if ((error = dqopt->ops[type]->read_file_info(sb, type)) < 0)
+		goto out_f;
 	set_enable_flags(dqopt, type);
 
-	dquot = dqget(sb, 0, type);
-	dqopt->inode_expire[type] = (dquot != NODQUOT) ? dquot->dq_itime : MAX_IQ_TIME;
-	dqopt->block_expire[type] = (dquot != NODQUOT) ? dquot->dq_btime : MAX_DQ_TIME;
-	dqput(dquot);
-
 	add_dquot_ref(sb, type);
 
 	up(&dqopt->dqoff_sem);
 	return 0;
 
 out_f:
-	filp_close(f, NULL);
+	if (f)
+		filp_close(f, NULL);
+	dqopt->files[type] = NULL;
 out_lock:
 	up(&dqopt->dqoff_sem);
+out_fmt:
+	put_quota_format(fmt);
 
 	return error; 
 }
 
-/*
- * This is the system call interface. This communicates with
- * the user-level programs. Currently this only supports diskquota
- * calls. Maybe we need to add the process quotas etc. in the future,
- * but we probably should use rlimits for that.
- */
-asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
+/* Generic routine for getting common part of quota structure */
+static void do_get_dqblk(struct dquot *dquot, struct if_dqblk *di)
 {
-	int cmds = 0, type = 0, flags = 0;
-	kdev_t dev;
-	struct super_block *sb = NULL;
-	int ret = -EINVAL;
+	struct mem_dqblk *dm = &dquot->dq_dqb;
 
-	lock_kernel();
-	cmds = cmd >> SUBCMDSHIFT;
-	type = cmd & SUBCMDMASK;
+	di->dqb_bhardlimit = dm->dqb_bhardlimit;
+	di->dqb_bsoftlimit = dm->dqb_bsoftlimit;
+	di->dqb_curspace = dm->dqb_curspace;
+	di->dqb_ihardlimit = dm->dqb_ihardlimit;
+	di->dqb_isoftlimit = dm->dqb_isoftlimit;
+	di->dqb_curinodes = dm->dqb_curinodes;
+	di->dqb_btime = dm->dqb_btime;
+	di->dqb_itime = dm->dqb_itime;
+	di->dqb_valid = QIF_ALL;
+}
 
-	if ((u_int) type >= MAXQUOTAS)
-		goto out;
-	if (id & ~0xFFFF)
-		goto out;
+int vfs_get_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di)
+{
+	struct dquot *dquot = dqget(sb, id, type);
 
-	ret = -EPERM;
-	switch (cmds) {
-		case Q_SYNC:
-		case Q_GETSTATS:
-			break;
-		case Q_GETQUOTA:
-			if (((type == USRQUOTA && current->euid != id) ||
-			     (type == GRPQUOTA && !in_egroup_p(id))) &&
-			    !capable(CAP_SYS_ADMIN))
-				goto out;
-			break;
-		default:
-			if (!capable(CAP_SYS_ADMIN))
-				goto out;
-	}
-
-	ret = -EINVAL;
-	dev = NODEV;
-	if (special != NULL || (cmds != Q_SYNC && cmds != Q_GETSTATS)) {
-		mode_t mode;
-		struct nameidata nd;
-
-		ret = user_path_walk(special, &nd);
-		if (ret)
-			goto out;
-
-		dev = nd.dentry->d_inode->i_rdev;
-		mode = nd.dentry->d_inode->i_mode;
-		path_release(&nd);
-
-		ret = -ENOTBLK;
-		if (!S_ISBLK(mode))
-			goto out;
-		ret = -ENODEV;
-		sb = get_super(dev);
-		if (!sb)
-			goto out;
-	}
-
-	ret = -EINVAL;
-	switch (cmds) {
-		case Q_QUOTAON:
-			ret = quota_on(sb, type, (char *) addr);
-			goto out;
-		case Q_QUOTAOFF:
-			ret = quota_off(sb, type);
-			goto out;
-		case Q_GETQUOTA:
-			ret = get_quota(sb, id, type, (struct dqblk *) addr);
-			goto out;
-		case Q_SETQUOTA:
-			flags |= SET_QUOTA;
-			break;
-		case Q_SETUSE:
-			flags |= SET_USE;
-			break;
-		case Q_SETQLIM:
-			flags |= SET_QLIMIT;
-			break;
-		case Q_SYNC:
-			ret = sync_dquots(dev, type);
-			goto out;
-		case Q_GETSTATS:
-			ret = get_stats(addr);
-			goto out;
-		case Q_RSQUASH:
-			ret = quota_root_squash(sb, type, (int *) addr);
-			goto out;
-		default:
-			goto out;
-	}
-
-	ret = -NODEV;
-	if (sb && sb_has_quota_enabled(sb, type))
-		ret = set_dqblk(sb, id, type, flags, (struct dqblk *) addr);
-out:
-	if (sb)
-		drop_super(sb);
-	unlock_kernel();
-	return ret;
+	if (!dquot)
+		return -EINVAL;
+	do_get_dqblk(dquot, di);
+	dqput(dquot);
+	return 0;
+}
+
+/* Generic routine for setting common part of quota structure */
+static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
+{
+	struct mem_dqblk *dm = &dquot->dq_dqb;
+	int check_blim = 0, check_ilim = 0;
+
+	if (di->dqb_valid & QIF_SPACE) {
+		dm->dqb_curspace = di->dqb_curspace;
+		check_blim = 1;
+	}
+	if (di->dqb_valid & QIF_BLIMITS) {
+		dm->dqb_bsoftlimit = di->dqb_bsoftlimit;
+		dm->dqb_bhardlimit = di->dqb_bhardlimit;
+		check_blim = 1;
+	}
+	if (di->dqb_valid & QIF_INODES) {
+		dm->dqb_curinodes = di->dqb_curinodes;
+		check_ilim = 1;
+	}
+	if (di->dqb_valid & QIF_ILIMITS) {
+		dm->dqb_isoftlimit = di->dqb_isoftlimit;
+		dm->dqb_ihardlimit = di->dqb_ihardlimit;
+		check_ilim = 1;
+	}
+	if (di->dqb_valid & QIF_BTIME)
+		dm->dqb_btime = di->dqb_btime;
+	if (di->dqb_valid & QIF_ITIME)
+		dm->dqb_itime = di->dqb_itime;
+
+	if (check_blim) {
+		if (!dm->dqb_bsoftlimit || toqb(dm->dqb_curspace) < dm->dqb_bsoftlimit) {
+			dm->dqb_btime = 0;
+			dquot->dq_flags &= ~DQ_BLKS;
+		}
+		else if (!(di->dqb_valid & QIF_BTIME))	/* Set grace only if user hasn't provided his own... */
+			dm->dqb_btime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace;
+	}
+	if (check_ilim) {
+		if (!dm->dqb_isoftlimit || dm->dqb_curinodes < dm->dqb_isoftlimit) {
+			dm->dqb_itime = 0;
+			dquot->dq_flags &= ~DQ_INODES;
+		}
+		else if (!(di->dqb_valid & QIF_ITIME))	/* Set grace only if user hasn't provided his own... */
+			dm->dqb_itime = CURRENT_TIME + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
+	}
+	if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit || dm->dqb_isoftlimit)
+		dquot->dq_flags &= ~DQ_FAKE;
+	else
+		dquot->dq_flags |= DQ_FAKE;
+	dquot->dq_flags |= DQ_MOD;
+}
+
+int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di)
+{
+	struct dquot *dquot = dqget(sb, id, type);
+
+	if (!dquot)
+		return -EINVAL;
+	do_set_dqblk(dquot, di);
+	dqput(dquot);
+	return 0;
+}
+
+/* Generic routine for getting common part of quota file information */
+int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
+{
+	struct mem_dqinfo *mi = sb_dqopt(sb)->info + type;
+
+	ii->dqi_bgrace = mi->dqi_bgrace;
+	ii->dqi_igrace = mi->dqi_igrace;
+	ii->dqi_flags = mi->dqi_flags & DQF_MASK;
+	ii->dqi_valid = IIF_ALL;
+	return 0;
+}
+
+/* Generic routine for setting common part of quota file information */
+int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii)
+{
+	struct mem_dqinfo *mi = sb_dqopt(sb)->info + type;
+
+	if (ii->dqi_valid & IIF_BGRACE)
+		mi->dqi_bgrace = ii->dqi_bgrace;
+	if (ii->dqi_valid & IIF_IGRACE)
+		mi->dqi_igrace = ii->dqi_igrace;
+	if (ii->dqi_valid & IIF_FLAGS)
+		mi->dqi_flags = (mi->dqi_flags & ~DQF_MASK) | (ii->dqi_flags & DQF_MASK);
+	mark_info_dirty(mi);
+	return 0;
+}
+
+struct quotactl_ops vfs_quotactl_ops = {
+	quota_on:	vfs_quota_on,
+	quota_off:	vfs_quota_off,
+	quota_sync:	vfs_quota_sync,
+	get_info:	vfs_get_dqinfo,
+	set_info:	vfs_set_dqinfo,
+	get_dqblk:	vfs_get_dqblk,
+	set_dqblk:	vfs_set_dqblk
+};
+
+static ctl_table fs_dqstats_table[] = {
+	{FS_DQ_LOOKUPS, "lookups", &dqstats.lookups, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_DROPS, "drops", &dqstats.drops, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_READS, "reads", &dqstats.reads, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_WRITES, "writes", &dqstats.writes, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_CACHE_HITS, "cache_hits", &dqstats.cache_hits, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_ALLOCATED, "allocated_dquots", &dqstats.allocated_dquots, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_FREE, "free_dquots", &dqstats.free_dquots, sizeof(int), 0444, NULL, &proc_dointvec},
+	{FS_DQ_SYNCS, "syncs", &dqstats.syncs, sizeof(int), 0444, NULL, &proc_dointvec},
+	{},
+};
+
+static ctl_table fs_table[] = {
+	{FS_DQSTATS, "quota", NULL, 0, 0555, fs_dqstats_table},
+	{},
+};
+
+static ctl_table sys_table[] = {
+	{CTL_FS, "fs", NULL, 0, 0555, fs_table},
+	{},
+};
+
+static int __init dquot_init(void)
+{
+	int i;
+
+	register_sysctl_table(sys_table, 0);
+	for (i = 0; i < NR_DQHASH; i++)
+		INIT_LIST_HEAD(dquot_hash + i);
+	printk(KERN_NOTICE "VFS: Disk quotas v%s\n", __DQUOT_VERSION__);
+
+	return 0;
 }
+__initcall(dquot_init);
+
+EXPORT_SYMBOL(register_quota_format);
+EXPORT_SYMBOL(unregister_quota_format);
+EXPORT_SYMBOL(dqstats);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/exec.c linux.20pre10-ac2/fs/exec.c
--- linux.20pre10/fs/exec.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/exec.c	2002-09-29 21:21:32.000000000 +0100
@@ -35,6 +35,8 @@
 #include <linux/highmem.h>
 #include <linux/spinlock.h>
 #include <linux/personality.h>
+#include <linux/swap.h>
+#include <linux/utsname.h>
 #define __NO_VERSION__
 #include <linux/module.h>
 
@@ -47,6 +49,8 @@
 #endif
 
 int core_uses_pid;
+char core_pattern[65] = "core";
+/* The maximal length of core_pattern is also specified in sysctl.c */ 
 
 static struct linux_binfmt *formats;
 static rwlock_t binfmt_lock = RW_LOCK_UNLOCKED;
@@ -300,6 +304,7 @@
 	flush_dcache_page(page);
 	flush_page_to_ram(page);
 	set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY))));
+	page_add_rmap(page, pte);
 	tsk->mm->rss++;
 	spin_unlock(&tsk->mm->page_table_lock);
 
@@ -329,6 +334,12 @@
 	if (!mpnt) 
 		return -ENOMEM; 
 	
+	if (!vm_enough_memory((STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT))
+	{
+		kmem_cache_free(vm_area_cachep, mpnt);
+		return -ENOMEM;
+	}
+
 	down_write(&current->mm->mmap_sem);
 	{
 		mpnt->vm_mm = current->mm;
@@ -953,10 +964,126 @@
 		__MOD_DEC_USE_COUNT(old->module);
 }
 
+#define CORENAME_MAX_SIZE 64
+
+/* format_corename will inspect the pattern parameter, and output a
+ * name into corename, which must have space for at least
+ * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator.
+ */
+void format_corename(char *corename, const char *pattern, long signr)
+{
+	const char *pat_ptr = pattern;
+	char *out_ptr = corename;
+	char *const out_end = corename + CORENAME_MAX_SIZE;
+	int rc;
+	int pid_in_pattern = 0;
+
+	/* Repeat as long as we have more pattern to process and more output
+	   space */
+	while (*pat_ptr) {
+		if (*pat_ptr != '%') {
+			if (out_ptr == out_end)
+				goto out;
+			*out_ptr++ = *pat_ptr++;
+		} else {
+			switch (*++pat_ptr) {
+			case 0:
+				goto out;
+			/* Double percent, output one percent */
+			case '%':
+				if (out_ptr == out_end)
+					goto out;
+				*out_ptr++ = '%';
+				break;
+			/* pid */
+			case 'p':
+				pid_in_pattern = 1;
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%d", current->pid);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			/* uid */
+			case 'u':
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%d", current->uid);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			/* gid */
+			case 'g':
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%d", current->gid);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			/* signal that caused the coredump */
+			case 's':
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%ld", signr);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			/* UNIX time of coredump */
+			case 't': {
+				struct timeval tv;
+				do_gettimeofday(&tv);
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%ld", tv.tv_sec);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			}
+			/* hostname */
+			case 'h':
+				down_read(&uts_sem);
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%s", system_utsname.nodename);
+				up_read(&uts_sem);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			/* executable */
+			case 'e':
+				rc = snprintf(out_ptr, out_end - out_ptr,
+					      "%s", current->comm);
+				if (rc > out_end - out_ptr)
+					goto out;
+				out_ptr += rc;
+				break;
+			default:
+				break;
+			}
+			++pat_ptr;
+		}
+	}
+	/* Backward compatibility with core_uses_pid:
+	 *
+	 * If core_pattern does not include a %p (as is the default)
+	 * and core_uses_pid is set, then .%pid will be appended to
+	 * the filename */
+	if (!pid_in_pattern
+            && (core_uses_pid || atomic_read(&current->mm->mm_users) != 1)) {
+		rc = snprintf(out_ptr, out_end - out_ptr,
+			      ".%d", current->pid);
+		if (rc > out_end - out_ptr)
+			goto out;
+		out_ptr += rc;
+	}
+      out:
+	*out_ptr = 0;
+}
+
 int do_coredump(long signr, struct pt_regs * regs)
 {
 	struct linux_binfmt * binfmt;
-	char corename[6+sizeof(current->comm)+10];
+	char corename[CORENAME_MAX_SIZE + 1];
 	struct file * file;
 	struct inode * inode;
 	int retval = 0;
@@ -971,9 +1098,7 @@
 	if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump)
 		goto fail;
 
-	memcpy(corename,"core", 5); /* include trailing \0 */
- 	if (core_uses_pid || atomic_read(&current->mm->mm_users) != 1)
- 		sprintf(&corename[4], ".%d", current->pid);
+ 	format_corename(corename, core_pattern, signr);
 	file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW, 0600);
 	if (IS_ERR(file))
 		goto fail;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/ext2/balloc.c linux.20pre10-ac2/fs/ext2/balloc.c
--- linux.20pre10/fs/ext2/balloc.c	2002-10-09 21:36:35.000000000 +0100
+++ linux.20pre10-ac2/fs/ext2/balloc.c	2002-08-06 15:41:51.000000000 +0100
@@ -269,7 +269,8 @@
 	}
 	lock_super (sb);
 	es = sb->u.ext2_sb.s_es;
-	if (block < le32_to_cpu(es->s_first_data_block) || 
+	if (block < le32_to_cpu(es->s_first_data_block) ||
+	    block + count < block ||
 	    (block + count) > le32_to_cpu(es->s_blocks_count)) {
 		ext2_error (sb, "ext2_free_blocks",
 			    "Freeing blocks not in datazone - "
@@ -302,22 +303,20 @@
 	if (!gdp)
 		goto error_return;
 
-	if (in_range (le32_to_cpu(gdp->bg_block_bitmap), block, count) ||
-	    in_range (le32_to_cpu(gdp->bg_inode_bitmap), block, count) ||
-	    in_range (block, le32_to_cpu(gdp->bg_inode_table),
-		      sb->u.ext2_sb.s_itb_per_group) ||
-	    in_range (block + count - 1, le32_to_cpu(gdp->bg_inode_table),
-		      sb->u.ext2_sb.s_itb_per_group))
-		ext2_error (sb, "ext2_free_blocks",
-			    "Freeing blocks in system zones - "
-			    "Block = %lu, count = %lu",
-			    block, count);
+	for (i = 0; i < count; i++, block++) {
+		if (block == le32_to_cpu(gdp->bg_block_bitmap) ||
+		    block == le32_to_cpu(gdp->bg_inode_bitmap) ||
+		    in_range(block, le32_to_cpu(gdp->bg_inode_table),
+			     EXT2_SB(sb)->s_itb_per_group)) {
+			ext2_error(sb, __FUNCTION__,
+				   "Freeing block in system zone - block = %lu",
+				   block);
+			continue;
+		}
 
-	for (i = 0; i < count; i++) {
 		if (!ext2_clear_bit (bit + i, bh->b_data))
-			ext2_error (sb, "ext2_free_blocks",
-				      "bit already cleared for block %lu",
-				      block + i);
+			ext2_error(sb, __FUNCTION__,
+				   "bit already cleared for block %lu", block);
 		else {
 			DQUOT_FREE_BLOCK(inode, 1);
 			gdp->bg_free_blocks_count =
@@ -336,7 +335,6 @@
 		wait_on_buffer (bh);
 	}
 	if (overflow) {
-		block += count;
 		count = overflow;
 		goto do_more;
 	}
@@ -521,9 +519,14 @@
 	    tmp == le32_to_cpu(gdp->bg_inode_bitmap) ||
 	    in_range (tmp, le32_to_cpu(gdp->bg_inode_table),
 		      sb->u.ext2_sb.s_itb_per_group))
+	{
 		ext2_error (sb, "ext2_new_block",
-			    "Allocating block in system zone - "
-			    "block = %u", tmp);
+			    "Allocating block in system zone - block = %u",
+			    tmp);
+		ext2_set_bit(j, bh->b_data);
+		DQUOT_FREE_BLOCK(inode, 1);
+		goto repeat;
+	}
 
 	if (ext2_set_bit (j, bh->b_data)) {
 		ext2_warning (sb, "ext2_new_block",
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/ext2/inode.c linux.20pre10-ac2/fs/ext2/inode.c
--- linux.20pre10/fs/ext2/inode.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/ext2/inode.c	2002-10-11 00:22:21.000000000 +0100
@@ -583,8 +583,9 @@
 {
 	return generic_block_bmap(mapping,block,ext2_get_block);
 }
-static int ext2_direct_IO(int rw, struct inode * inode, struct kiobuf * iobuf, unsigned long blocknr, int blocksize)
+static int ext2_direct_IO(int rw, struct file * filp, struct kiobuf * iobuf, unsigned long blocknr, int blocksize)
 {
+	struct inode * inode = filp->f_dentry->d_inode->i_mapping->host;
 	return generic_direct_IO(rw, inode, iobuf, blocknr, blocksize, ext2_get_block);
 }
 struct address_space_operations ext2_aops = {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/inode.c linux.20pre10-ac2/fs/inode.c
--- linux.20pre10/fs/inode.c	2002-10-09 21:36:35.000000000 +0100
+++ linux.20pre10-ac2/fs/inode.c	2002-09-12 13:48:46.000000000 +0100
@@ -777,11 +777,13 @@
 	atomic_set(&inode->i_writecount, 0);
 	inode->i_size = 0;
 	inode->i_blocks = 0;
+	inode->i_bytes = 0;
 	inode->i_generation = 0;
 	memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
 	inode->i_pipe = NULL;
 	inode->i_bdev = NULL;
 	inode->i_cdev = NULL;
+	inode->i_rdev = 0;
 	inode->i_data.a_ops = &empty_aops;
 	inode->i_data.host = inode;
 	inode->i_data.gfp_mask = GFP_HIGHUSER;
@@ -1203,9 +1205,9 @@
 
 /* Functions back in dquot.c */
 void put_dquot_list(struct list_head *);
-int remove_inode_dquot_ref(struct inode *, short, struct list_head *);
+int remove_inode_dquot_ref(struct inode *, int, struct list_head *);
 
-void remove_dquot_ref(struct super_block *sb, short type)
+void remove_dquot_ref(struct super_block *sb, int type)
 {
 	struct inode *inode;
 	struct list_head *act_head;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/cache.c linux.20pre10-ac2/fs/intermezzo/cache.c
--- linux.20pre10/fs/intermezzo/cache.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/cache.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,10 +1,23 @@
-/*
- *
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
  *  Copyright (C) 2000 Stelias Computing, Inc.
  *  Copyright (C) 2000 Red Hat, Inc.
  *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #define __NO_VERSION__
@@ -27,7 +40,6 @@
 #include <linux/init.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
 
 /*
@@ -38,6 +50,8 @@
    The methods for the cache are set up in methods.
 */
 
+extern kmem_cache_t * presto_dentry_slab;
+
 /* the intent of this hash is to have collision chains of length 1 */
 #define CACHES_BITS 8
 #define CACHES_SIZE (1 << CACHES_BITS)
@@ -56,7 +70,7 @@
         cache->cache_dev = dev;
 }
 
-inline void presto_init_cache_hash(void)
+inline void presto_cache_init_hash(void)
 {
         int i;
         for ( i = 0; i < CACHES_SIZE; i++ ) {
@@ -65,7 +79,7 @@
 }
 
 /* map a device to a cache */
-struct presto_cache *presto_find_cache(kdev_t dev)
+struct presto_cache *presto_cache_find(kdev_t dev)
 {
         struct presto_cache *cache;
         struct list_head *lh, *tmp;
@@ -85,85 +99,19 @@
 struct presto_cache *presto_get_cache(struct inode *inode)
 {
         struct presto_cache *cache;
-
+        ENTRY;
         /* find the correct presto_cache here, based on the device */
-        cache = presto_find_cache(inode->i_dev);
+        cache = presto_cache_find(inode->i_dev);
         if ( !cache ) {
-                printk("WARNING: no presto cache for dev %x, ino %ld\n",
+                CERROR("WARNING: no presto cache for dev %x, ino %ld\n",
                        inode->i_dev, inode->i_ino);
                 EXIT;
                 return NULL;
         }
+        EXIT;
         return cache;
 }
 
-
-/* list cache mount points for ioctl's or /proc/fs/intermezzo/mounts */
-int presto_sprint_mounts(char *buf, int buflen, int minor)
-{
-        int len = 0;
-        int i;
-        struct list_head *head, *tmp;
-        struct presto_cache *cache;
-
-        buf[0] = '\0';
-        for (i=0 ; i<CACHES_SIZE ; i++) {
-                head = tmp = &presto_caches[i];
-                while ( (tmp = tmp->next) != head ) {
-                        cache = list_entry(tmp, struct presto_cache,
-                                            cache_chain);
-                        if ( !cache->cache_root_fileset || !cache->cache_mtpt)
-                                continue;
-                        if ((minor != -1) &&
-                            (cache->cache_psdev->uc_minor != minor))
-                                continue;
-                        if ( strlen(cache->cache_root_fileset) +
-                             strlen(cache->cache_mtpt) + 
-                             strlen(cache->cache_psdev->uc_devname) +
-                             4 > buflen - len)
-                                break;
-                        len += sprintf(buf + len, "%s %s %s\n",
-                                       cache->cache_root_fileset,
-                                       cache->cache_mtpt,
-                                       cache->cache_psdev->uc_devname);
-                }
-        }
-
-        buf[buflen-1] = '\0';
-        CDEBUG(D_SUPER, "%s\n", buf);
-        return len;
-}
-
-#ifdef CONFIG_KREINT
-/* get mount point by volname
-       Arthur Ma, 2000.12.25
- */
-int presto_get_mount (char *buf, int buflen, char *volname)
-{
-        int i;
-        struct list_head *head, *tmp;
-        struct presto_cache *cache = NULL;
-        char *path = "";
-
-        buf[0] = '\0';
-        for (i=0 ; i<CACHES_SIZE ; i++) {
-                head = tmp = &presto_caches[i];
-                while ( (tmp = tmp->next) != head ) {
-                        cache = list_entry(tmp, struct presto_cache,
-                                            cache_chain);
-                        if ( !cache->cache_root_fileset || !cache->cache_mtpt)
-                                continue;
-                        if ( strcmp(cache->cache_root_fileset, volname) == 0)
-                                break;
-                }
-        }
-        if (cache != NULL)
-                path = cache->cache_mtpt;
-        strncpy (buf, path, buflen);
-        return strlen (buf);
-}
-#endif
-
 /* another debugging routine: check fs is InterMezzo fs */
 int presto_ispresto(struct inode *inode)
 {
@@ -178,23 +126,21 @@
 }
 
 /* setup a cache structure when we need one */
-struct presto_cache *presto_init_cache(void)
+struct presto_cache *presto_cache_init(void)
 {
         struct presto_cache *cache;
 
-        /* make a presto_cache structure for the hash */
-        PRESTO_ALLOC(cache, struct presto_cache *, sizeof(struct presto_cache));
+        PRESTO_ALLOC(cache, sizeof(struct presto_cache));
         if ( cache ) {
                 memset(cache, 0, sizeof(struct presto_cache));
                 INIT_LIST_HEAD(&cache->cache_chain);
                 INIT_LIST_HEAD(&cache->cache_fset_list);
+                cache->cache_lock = SPIN_LOCK_UNLOCKED;
+                cache->cache_reserved = 0; 
         }
-	cache->cache_lock = SPIN_LOCK_UNLOCKED;
-	cache->cache_reserved = 0; 
         return cache;
 }
 
-
 /* free a cache structure and all of the memory it is pointing to */
 inline void presto_free_cache(struct presto_cache *cache)
 {
@@ -202,12 +148,12 @@
                 return;
 
         list_del(&cache->cache_chain);
-        if (cache->cache_mtpt)
-                PRESTO_FREE(cache->cache_mtpt, strlen(cache->cache_mtpt) + 1);
-        if (cache->cache_type)
-                PRESTO_FREE(cache->cache_type, strlen(cache->cache_type) + 1);
-        if (cache->cache_root_fileset)
-                PRESTO_FREE(cache->cache_root_fileset, strlen(cache->cache_root_fileset) + 1);
+        if (cache->cache_sb && cache->cache_sb->s_root &&
+                        presto_d2d(cache->cache_sb->s_root)) {
+                kmem_cache_free(presto_dentry_slab, 
+                                presto_d2d(cache->cache_sb->s_root));
+                cache->cache_sb->s_root->d_fsdata = NULL;
+        }
 
         PRESTO_FREE(cache, sizeof(struct presto_cache));
 }
@@ -216,41 +162,43 @@
 {
         struct filter_fs *filter; 
         loff_t avail; 
-	struct super_block *sb = cache->cache_sb;
+        struct super_block *sb = cache->cache_sb;
         filter = cache->cache_filter;
-	if (!filter ) {
-		EXIT;
-		return 0; 
-	}
-	if (!filter->o_trops ) {
-		EXIT;
-		return 0; 
-	}
-	if (!filter->o_trops->tr_avail ) {
-		EXIT;
-		return 0; 
-	}
+        if (!filter ) {
+                EXIT;
+                return 0; 
+        }
+        if (!filter->o_trops ) {
+                EXIT;
+                return 0; 
+        }
+        if (!filter->o_trops->tr_avail ) {
+                EXIT;
+                return 0; 
+        }
+
+        spin_lock(&cache->cache_lock);
         avail = filter->o_trops->tr_avail(cache, sb); 
         CDEBUG(D_SUPER, "ESC::%ld +++> %ld \n", (long) cache->cache_reserved,
-	         (long) (cache->cache_reserved + req)); 
+                 (long) (cache->cache_reserved + req)); 
         CDEBUG(D_SUPER, "ESC::Avail::%ld \n", (long) avail);
-	spin_lock(&cache->cache_lock);
         if (req + cache->cache_reserved > avail) {
-		spin_unlock(&cache->cache_lock);
+                spin_unlock(&cache->cache_lock);
                 EXIT;
                 return -ENOSPC;
         }
-	cache->cache_reserved += req; 
-	spin_unlock(&cache->cache_lock);
+        cache->cache_reserved += req; 
+        spin_unlock(&cache->cache_lock);
 
+        EXIT;
         return 0;
 }
 
 void presto_release_space(struct presto_cache *cache, loff_t req)
 {
         CDEBUG(D_SUPER, "ESC::%ld ---> %ld \n", (long) cache->cache_reserved,
-	         (long) (cache->cache_reserved - req)); 
-	spin_lock(&cache->cache_lock);
-	cache->cache_reserved -= req; 
-	spin_unlock(&cache->cache_lock);
+                 (long) (cache->cache_reserved - req)); 
+        spin_lock(&cache->cache_lock);
+        cache->cache_reserved -= req; 
+        spin_unlock(&cache->cache_lock);
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/dcache.c linux.20pre10-ac2/fs/intermezzo/dcache.c
--- linux.20pre10/fs/intermezzo/dcache.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/dcache.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,10 +1,34 @@
-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Original version: Copyright (C) 1996 P. Braam and M. Callahan
+ *  Rewritten for Linux 2.1. Copyright (C) 1997 Carnegie Mellon University
+ *  d_fsdata and NFS compatiblity fixes Copyright (C) 2001 Tacit Networks, Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
  * Directory operations for InterMezzo filesystem
- * Original version: (C) 1996 P. Braam and M. Callahan
- * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University
+ */
+
+/* inode dentry alias list walking code adapted from linux/fs/dcache.c
  *
- * Stelias encourages users to contribute improvements to
- * the InterMezzo project. Contact Peter Braam (coda@stelias.com).
+ * fs/dcache.c
+ *
+ * (C) 1997 Thomas Schoebel-Theuer,
+ * with heavy changes by Linus Torvalds
  */
 
 #define __NO_VERSION__
@@ -15,48 +39,307 @@
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/locks.h>
+#include <linux/slab.h>
 #include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
+#include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
 
 #include <linux/intermezzo_fs.h>
 
-static int presto_dentry_revalidate(struct dentry *de, int );
-
+static kmem_cache_t * presto_dentry_slab;
 
 /* called when a cache lookup succeeds */
-static int presto_dentry_revalidate(struct dentry *de, int flag)
+static int presto_d_revalidate(struct dentry *de, int flag)
 {
-	struct inode *inode = de->d_inode;
-	ENTRY;
-	if (!inode) {
-		EXIT;
-		return 1;
-	}
-	if (is_bad_inode(inode)) {
-		EXIT;
-		return 0;
-	}
-
-	if ( S_ISDIR(inode->i_mode) ) {
-		EXIT;
-		return (presto_chk(de, PRESTO_DATA) &&
-			(presto_chk(de, PRESTO_ATTR)));
-	} else {
-		EXIT;
-		return presto_chk(de, PRESTO_ATTR);
-	}
+        struct inode *inode = de->d_inode;
+        struct presto_file_set * root_fset;
+
+        ENTRY;
+        if (!inode) {
+                EXIT;
+                return 0;
+        }
+
+        if (is_bad_inode(inode)) {
+                EXIT;
+                return 0;
+        }
+
+        if (!presto_d2d(de)) {
+                presto_set_dd(de);
+        }
+
+        if (!presto_d2d(de)) {
+                EXIT;
+                return 0;
+        }
+
+        root_fset = presto_d2d(de->d_inode->i_sb->s_root)->dd_fset;
+        if (root_fset->fset_flags & FSET_FLAT_BRANCH && 
+            (presto_d2d(de)->dd_fset != root_fset )) {
+                presto_d2d(de)->dd_fset = root_fset;
+        }
+
+        EXIT;
+        return 1;
+
+#if 0
+        /* The following is needed for metadata on demand. */
+        if ( S_ISDIR(inode->i_mode) ) {
+                EXIT;
+                return (presto_chk(de, PRESTO_DATA) &&
+                        (presto_chk(de, PRESTO_ATTR)));
+        } else {
+                EXIT;
+                return presto_chk(de, PRESTO_ATTR);
+        }
+#endif
 }
 
-static void presto_dentry_iput(struct dentry *dentry, struct inode *inode)
+static void presto_d_release(struct dentry *dentry)
 {
-	dentry->d_time = 0;
-	iput(inode);
+        if (!presto_d2d(dentry)) {
+                /* This can happen for dentries from NFSd */
+                return;
+        }
+        presto_d2d(dentry)->dd_count--;
+
+        if (!presto_d2d(dentry)->dd_count) {
+                kmem_cache_free(presto_dentry_slab, presto_d2d(dentry));
+                dentry->d_fsdata = NULL;
+        }
 }
 
 struct dentry_operations presto_dentry_ops = 
 {
-	d_revalidate: presto_dentry_revalidate,
-        d_iput: presto_dentry_iput
+        .d_revalidate =  presto_d_revalidate,
+        .d_release = presto_d_release
 };
 
+static inline int presto_is_dentry_ROOT (struct dentry *dentry)
+{
+        return(dentry_name_cmp(dentry,"ROOT") &&
+               !dentry_name_cmp(dentry->d_parent,".intermezzo"));
+}
+
+static struct presto_file_set* presto_try_find_fset(struct dentry* dentry,
+                int *is_under_d_intermezzo)
+{
+        struct dentry* temp_dentry;
+        struct presto_dentry_data *d_data;
+        int found_root=0;
+
+        ENTRY;
+        CDEBUG(D_FSDATA, "finding fileset for %p:%s\n", dentry, 
+                        dentry->d_name.name);
+
+        *is_under_d_intermezzo = 0;
+
+        /* walk up through the branch to get the fileset */
+        /* The dentry we are passed presumably does not have the correct
+         * fset information. However, we still want to start walking up
+         * the branch from this dentry to get our found_root and 
+         * is_under_d_intermezzo decisions correct
+         */
+        for (temp_dentry = dentry ; ; temp_dentry = temp_dentry->d_parent) {
+                CDEBUG(D_FSDATA, "--->dentry %p:%*s\n", temp_dentry, 
+                        temp_dentry->d_name.len,temp_dentry->d_name.name);
+                if (presto_is_dentry_ROOT(temp_dentry))
+                        found_root = 1;
+                if (!found_root &&
+                    dentry_name_cmp(temp_dentry, ".intermezzo")) {
+                        *is_under_d_intermezzo = 1;
+                }
+                d_data = presto_d2d(temp_dentry);
+                if (d_data) {
+                        /* If we found a "ROOT" dentry while walking up the
+                         * branch, we will journal regardless of whether
+                         * we are under .intermezzo or not.
+                         * If we are already under d_intermezzo don't reverse
+                         * the decision here...even if we found a "ROOT"
+                         * dentry above .intermezzo (if we were ever to
+                         * modify the directory structure).
+                         */
+                        if (!*is_under_d_intermezzo)  
+                                *is_under_d_intermezzo = !found_root &&
+                                  (d_data->dd_flags & PRESTO_DONT_JOURNAL);
+                        EXIT;
+                        return d_data->dd_fset;
+                }
+                if (temp_dentry->d_parent == temp_dentry) {
+                        break;
+                }
+        }
+        EXIT;
+        return NULL;
+}
+
+/* Only call this function on positive dentries */
+static struct presto_dentry_data* presto_try_find_alias_with_dd (
+                  struct dentry* dentry)
+{
+        struct inode *inode=dentry->d_inode;
+        struct list_head *head, *next, *tmp;
+        struct dentry *tmp_dentry;
+
+        /* Search through the alias list for dentries with d_fsdata */
+        spin_lock(&dcache_lock);
+        head = &inode->i_dentry;
+        next = inode->i_dentry.next;
+        while (next != head) {
+                tmp = next;
+                next = tmp->next;
+                tmp_dentry = list_entry(tmp, struct dentry, d_alias);
+                if (!presto_d2d(tmp_dentry)) {
+                        spin_unlock(&dcache_lock);
+                        return presto_d2d(tmp_dentry);
+                }
+        }
+        spin_unlock(&dcache_lock);
+        return NULL;
+}
+
+/* Only call this function on positive dentries */
+static void presto_set_alias_dd (struct dentry *dentry, 
+                struct presto_dentry_data* dd)
+{
+        struct inode *inode=dentry->d_inode;
+        struct list_head *head, *next, *tmp;
+        struct dentry *tmp_dentry;
+
+        /* Set d_fsdata for this dentry */
+        dd->dd_count++;
+        dentry->d_fsdata = dd;
+
+        /* Now set d_fsdata for all dentries in the alias list. */
+        spin_lock(&dcache_lock);
+        head = &inode->i_dentry;
+        next = inode->i_dentry.next;
+        while (next != head) {
+                tmp = next;
+                next = tmp->next;
+                tmp_dentry = list_entry(tmp, struct dentry, d_alias);
+                if (!presto_d2d(tmp_dentry)) {
+                        dd->dd_count++;
+                        tmp_dentry->d_fsdata = dd;
+                }
+        }
+        spin_unlock(&dcache_lock);
+        return;
+}
+
+inline struct presto_dentry_data *izo_alloc_ddata(void)
+{
+        struct presto_dentry_data *dd;
+
+        dd = kmem_cache_alloc(presto_dentry_slab, SLAB_KERNEL);
+        if (dd == NULL) {
+                CERROR("IZO: out of memory trying to allocate presto_dentry_data\n");
+                return NULL;
+        }
+        memset(dd, 0, sizeof(*dd));
+        dd->dd_count = 1;
+
+        return dd;
+}
+
+/* This uses the BKL! */
+int presto_set_dd(struct dentry * dentry)
+{
+        struct presto_file_set *fset;
+        struct presto_dentry_data *dd;
+        int is_under_d_izo;
+        int error=0;
+
+        ENTRY;
+
+        if (!dentry)
+                BUG();
+
+        lock_kernel();
+
+        /* Did we lose a race? */
+        if (dentry->d_fsdata) {
+                CERROR("dentry %p already has d_fsdata set\n", dentry);
+                if (dentry->d_inode)
+                        CERROR("    inode: %ld\n", dentry->d_inode->i_ino);
+                EXIT;
+                goto out_unlock;
+        }
+
+        if (dentry->d_inode != NULL) {
+                /* NFSd runs find_fh_dentry which instantiates disconnected
+                 * dentries which are then connected without a lookup(). 
+                 * So it is possible to have connected dentries that do not 
+                 * have d_fsdata set. So we walk the list trying to find 
+                 * an alias which has its d_fsdata set and then use that 
+                 * for all the other dentries  as well. 
+                 * - SHP,Vinny. 
+                 */
+
+                /* If there is an alias with d_fsdata use it. */
+                if ((dd = presto_try_find_alias_with_dd (dentry))) {
+                        presto_set_alias_dd (dentry, dd);
+                        EXIT;
+                        goto out_unlock;
+                }
+        } else {
+                /* Negative dentry */
+                CDEBUG(D_FSDATA,"negative dentry %p: %*s\n", dentry, 
+                                dentry->d_name.len, dentry->d_name.name);
+        }
+
+        /* No pre-existing d_fsdata, we need to construct one.
+         * First, we must walk up the tree to find the fileset 
+         * If a fileset can't be found, we leave a null fsdata
+         * and return EROFS to indicate that we can't journal
+         * updates. 
+         */
+        fset = presto_try_find_fset (dentry, &is_under_d_izo);
+        if (!fset) { 
+#ifdef PRESTO_NO_NFS
+                CERROR("No fileset for dentry %p: %*s\n", dentry,
+                                dentry->d_name.len, dentry->d_name.name);
+#endif
+                error = -EROFS;
+                EXIT;
+                goto out_unlock;
+        }
+
+        dentry->d_fsdata = izo_alloc_ddata();
+        if (!presto_d2d(dentry)) {
+                CERROR ("InterMezzo: out of memory allocating d_fsdata\n");
+                error = -ENOMEM;
+                goto out_unlock;
+        }
+        presto_d2d(dentry)->dd_fset = fset;
+        if (is_under_d_izo)
+                presto_d2d(dentry)->dd_flags |= PRESTO_DONT_JOURNAL;
+        EXIT;
+
+out_unlock:    
+        CDEBUG(D_FSDATA,"presto_set_dd dentry %p: %*s, d_fsdata %p\n", 
+                        dentry, dentry->d_name.len, dentry->d_name.name, 
+                        dentry->d_fsdata);
+        unlock_kernel();
+        return error; 
+}
+
+int presto_init_ddata_cache(void)
+{
+        ENTRY;
+        presto_dentry_slab =
+                kmem_cache_create("presto_cache",
+                                  sizeof(struct presto_dentry_data), 0,
+                                  SLAB_HWCACHE_ALIGN, NULL,
+                                  NULL);
+        EXIT;
+        return (presto_dentry_slab != NULL);
+}
+
+void presto_cleanup_ddata_cache(void)
+{
+        kmem_cache_destroy(presto_dentry_slab);
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/dir.c linux.20pre10-ac2/fs/intermezzo/dir.c
--- linux.20pre10/fs/intermezzo/dir.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/dir.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,14 +1,27 @@
-/*
- *
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
  *  Copyright (C) 2000 Stelias Computing, Inc.
  *  Copyright (C) 2000 Red Hat, Inc.
  *  Copyright (C) 2000 Tacitus Systems
  *  Copyright (C) 2000 Peter J. Braam
  *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-
 #include <stdarg.h>
 
 #include <asm/bitops.h>
@@ -31,39 +44,38 @@
 #include <linux/module.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
 
 static inline void presto_relock_sem(struct inode *dir) 
 {
-	/* the lock from sys_mkdir / lookup_create */
-	down(&dir->i_sem);
-	/* the rest is done by the do_{create,mkdir, ...} */
+        /* the lock from sys_mkdir / lookup_create */
+        down(&dir->i_sem);
+        /* the rest is done by the do_{create,mkdir, ...} */
 }
 
 static inline void presto_relock_other(struct inode *dir) 
 {
-	/* vfs_mkdir locks */
+        /* vfs_mkdir locks */
         down(&dir->i_zombie);
-	lock_kernel(); 
+        lock_kernel(); 
 }
 
 static inline void presto_fulllock(struct inode *dir) 
 {
-	/* the lock from sys_mkdir / lookup_create */
-	down(&dir->i_sem);
-	/* vfs_mkdir locks */
+        /* the lock from sys_mkdir / lookup_create */
+        down(&dir->i_sem);
+        /* vfs_mkdir locks */
         down(&dir->i_zombie);
-	lock_kernel(); 
+        lock_kernel(); 
 }
 
 static inline void presto_unlock(struct inode *dir) 
 {
-	/* vfs_mkdir locks */
-	unlock_kernel(); 
+        /* vfs_mkdir locks */
+        unlock_kernel(); 
         up(&dir->i_zombie);
-	/* the lock from sys_mkdir / lookup_create */
-	up(&dir->i_sem);
+        /* the lock from sys_mkdir / lookup_create */
+        up(&dir->i_sem);
 }
 
 
@@ -71,116 +83,83 @@
  * these are initialized in super.c
  */
 extern int presto_permission(struct inode *inode, int mask);
-int presto_ilookup_uid = 0;
-
-extern int presto_prep(struct dentry *, struct presto_cache **,
-                       struct presto_file_set **);
+static int izo_authorized_uid = 0;
 
-static int dentry2id(struct dentry *dentry, ino_t *id, unsigned int *generation)
+int izo_dentry_is_ilookup(struct dentry *dentry, ino_t *id,
+                          unsigned int *generation)
 {
-        char *tmpname;
+        char tmpname[64];
         char *next;
-        int error = 0;
 
         ENTRY;
-        if (dentry->d_name.len > EXT2_NAME_LEN) {
-                EXIT;
-                return -ENAMETOOLONG;
-        }
-
         /* prefix is 7 characters: '...ino:' */
-        if ( dentry->d_name.len < 7 ||
+        if ( dentry->d_name.len < 7 || dentry->d_name.len > 64 ||
              memcmp(dentry->d_name.name, PRESTO_ILOOKUP_MAGIC, 7) != 0 ) {
                 EXIT;
-                return 1;
-        }
-
-        PRESTO_ALLOC(tmpname, char *, dentry->d_name.len - 7 + 1);
-        if ( !tmpname ) {
-                EXIT;
-                return -ENOMEM;
+                return 0;
         }
 
         memcpy(tmpname, dentry->d_name.name + 7, dentry->d_name.len - 7);
-        *(tmpname + dentry->d_name.len) = '\0';
+        *(tmpname + dentry->d_name.len - 7) = '\0';
 
-        /* name is of the form <inode number>:<generation> */
-        *id = simple_strtoul(tmpname, &next, 0);
+        /* name is of the form ...ino:<inode number>:<generation> */
+        *id = simple_strtoul(tmpname, &next, 16);
         if ( *next == PRESTO_ILOOKUP_SEP ) {
-                *generation = simple_strtoul(next + 1, 0, 0);
-                CDEBUG(D_INODE, "INO to find = %s\n", tmpname);
-                CDEBUG(D_INODE, "Id = %lx (%lu), generation %x (%d)\n",
-                       *id, *id, *generation, *generation);
-        } else
-                error = 1;
-
-        PRESTO_FREE(tmpname, dentry->d_name.len - 7 + 1);
-        EXIT;
-        return error;
+                *generation = simple_strtoul(next + 1, 0, 16);
+                CDEBUG(D_INODE, "ino string: %s, Id = %lx (%lu), "
+                       "generation %x (%d)\n",
+                       tmpname, *id, *id, *generation, *generation);
+                EXIT;
+                return 1;
+        } else {
+                EXIT;
+                return 0;
+        }
 }
 
-static int presto_opendir_upcall(int minor, struct dentry *de, 
-                          struct dentry *root, int async)
+struct dentry *presto_tmpfs_ilookup(struct inode *dir, 
+                                    struct dentry *dentry,
+                                    ino_t ino, 
+                                    unsigned int generation)
 {
-        int rc;
-        char *path, *buffer;
-        int pathlen;
-
-        PRESTO_ALLOC(buffer, char *, PAGE_SIZE);
-        if ( !buffer ) {
-                printk("PRESTO: out of memory!\n");
-                return ENOMEM;
-        }
-        path = presto_path(de, root, buffer, PAGE_SIZE);
-        pathlen = MYPATHLEN(buffer, path);
-        CDEBUG(D_INODE, "path: %*s, len %d\n", pathlen, path, pathlen);
-        rc = lento_opendir(minor, pathlen, path, async);
-        PRESTO_FREE(buffer, PAGE_SIZE);
-        return rc;
+        return dentry; 
 }
 
+
 inline int presto_can_ilookup(void)
 {
-        return (current->euid == presto_ilookup_uid ||
+        return (current->euid == izo_authorized_uid ||
                 capable(CAP_DAC_READ_SEARCH));
 }
 
-struct dentry *presto_ilookup(struct inode *dir, struct dentry *dentry,
-                            ino_t ino, unsigned int generation)
+struct dentry *presto_iget_ilookup(struct inode *dir, 
+                                          struct dentry *dentry,
+                                          ino_t ino, 
+                                          unsigned int generation)
 {
         struct inode *inode;
         int error;
 
         ENTRY;
 
-        /* if we can't ilookup, forbid anything with this name to
-         * avoid any security issues/name clashes.
-         */
         if ( !presto_can_ilookup() ) {
-                CDEBUG(D_CACHE, "ilookup denied: euid %u, ilookup_uid %u\n",
-                       current->euid, presto_ilookup_uid);
-                EXIT;
+                CERROR("ilookup denied: euid %u, authorized_uid %u\n",
+                       current->euid, izo_authorized_uid);
                 return ERR_PTR(-EPERM);
         }
+        error = -ENOENT;
         inode = iget(dir->i_sb, ino);
-        if (!inode || !inode->i_nlink || is_bad_inode(inode)) {
-                CDEBUG(D_PIOCTL, "fatal: invalid inode %ld (%s).\n",
-                       ino, inode ? inode->i_nlink ? "bad inode" :
-                       "no links" : "NULL");
-                error = -ENOENT;
-                EXIT;
+        if (!inode) { 
+                CERROR("fatal: NULL inode ino %lu\n", ino); 
+                goto cleanup_iput;
+        }
+        if (is_bad_inode(inode) || inode->i_nlink == 0) {
+                CERROR("fatal: bad inode ino %lu, links %d\n", ino, inode->i_nlink); 
                 goto cleanup_iput;
         }
-
-        /* We need to make sure we have the right inode (by checking the
-         * generation) so we don't write into the wrong file (old inode was
-         * deleted and then a new one was created with the same number).
-         */
         if (inode->i_generation != generation) {
-                CDEBUG(D_PIOCTL, "fatal: bad generation %u (want %u)\n",
+                CERROR("fatal: bad generation %u (want %u)\n",
                        inode->i_generation, generation);
-                error = -ENOENT;
-                EXIT;
                 goto cleanup_iput;
         }
 
@@ -196,73 +175,164 @@
         return ERR_PTR(error);
 }
 
+struct dentry *presto_add_ilookup_dentry(struct dentry *parent,
+                                         struct dentry *real)
+{
+        struct inode *inode = real->d_inode;
+        struct dentry *de;
+        char buf[32];
+        char *ptr = buf;
+        struct dentry *inodir;
+        struct presto_dentry_data *dd;
+
+        inodir = lookup_one_len("..iopen..", parent,  strlen("..iopen..")); 
+        if (!inodir || IS_ERR(inodir) || !inodir->d_inode ) { 
+                CERROR("%s: bad ..iopen.. lookup\n", __FUNCTION__); 
+                return NULL; 
+        }
+        inodir->d_inode->i_op = &presto_dir_iops;
+
+        snprintf(ptr, 32, "...ino:%lx:%x", inode->i_ino, inode->i_generation);
+
+        de = lookup_one_len(ptr, inodir,  strlen(ptr)); 
+        if (!de || IS_ERR(de)) {
+                CERROR("%s: bad ...ino lookup %ld\n", 
+                       __FUNCTION__, PTR_ERR(de)); 
+                dput(inodir);
+                return NULL; 
+        }
+
+        dd = presto_d2d(real);
+        if (!dd) 
+                BUG();
+
+        /* already exists */
+        if (de->d_inode)
+                BUG();
+#if 0 
+                if (de->d_inode != inode ) { 
+                        CERROR("XX de->d_inode %ld, inode %ld\n", 
+                               de->d_inode->i_ino, inode->i_ino); 
+                        BUG();
+                }
+                if (dd->dd_inodentry) { 
+                        CERROR("inodentry exists %ld \n", inode->i_ino);
+                        BUG();
+                }
+                dput(inodir);
+                return de;
+        }
+#endif 
+
+        if (presto_d2d(de)) 
+                BUG();
+
+        atomic_inc(&inode->i_count);
+        de->d_op = &presto_dentry_ops;
+        d_add(de, inode);
+        if (!de->d_op)
+                CERROR("DD: no ops dentry %p, dd %p\n", de, dd);
+        dd->dd_inodentry = de;
+        dd->dd_count++;
+        de->d_fsdata = dd;
+
+        dput(inodir);
+        return de;
+}
 
 struct dentry *presto_lookup(struct inode * dir, struct dentry *dentry)
 {
         int rc = 0;
         struct dentry *de;
         struct presto_cache *cache;
-        struct presto_file_set *fset;
-        int error; 
         int minor;
         ino_t ino;
         unsigned int generation;
+        struct inode_operations *iops;
+        int is_ilookup = 0;
 
         ENTRY;
-        error = presto_prep(dentry->d_parent, &cache, &fset);
-        if ( error  ) {
+        cache = presto_get_cache(dir);
+        if (cache == NULL) {
+                CERROR("InterMezzo BUG: no cache in presto_lookup "
+                       "(dir ino: %ld)!\n", dir->i_ino);
                 EXIT;
-                return ERR_PTR(error);
+                return NULL;
         }
         minor = presto_c2m(cache);
 
-        CDEBUG(D_CACHE, "dir ino: %ld, name: %*s\n",
-               dir->i_ino, dentry->d_name.len, dentry->d_name.name);
-        if ( ISLENTO(minor) )
-                CDEBUG(D_CACHE, "We are lento\n");
-
-        rc = dentry2id(dentry, &ino, &generation);
-        CDEBUG(D_CACHE, "dentry2id returned %d\n", rc);
-        if ( rc < 0 ) {
-                EXIT;
-                goto exit;
+        iops = filter_c2cdiops(cache->cache_filter);
+        if (!iops || !iops->lookup) {
+                CERROR("InterMezzo BUG: filesystem has no lookup\n");
+                EXIT;
+                return NULL;
         }
 
-        if ( rc == 0 ) {
-                de = presto_ilookup(dir, dentry, ino, generation);
-        } else {
-                struct inode_operations *iops = filter_c2cdiops(cache->cache_filter);
-                rc = 0;
-                /* recursively do a cache lookup in dir */
-                if (iops && iops->lookup) 
+
+        CDEBUG(D_CACHE, "dentry %p, dir ino: %ld, name: %*s, islento: %d\n",
+               dentry, dir->i_ino, dentry->d_name.len, dentry->d_name.name,
+               ISLENTO(minor));
+
+        if (dentry->d_fsdata)
+                CERROR("DD -- BAD dentry %p has data\n", dentry);
+                       
+        dentry->d_fsdata = NULL;
+#if 0
+        if (ext2_check_for_iopen(dir, dentry))
+                de = NULL;
+        else {
+#endif
+                if ( izo_dentry_is_ilookup(dentry, &ino, &generation) ) { 
+                        de = cache->cache_filter->o_trops->tr_ilookup
+                                (dir, dentry, ino, generation);
+                        is_ilookup = 1;
+                } else
                         de = iops->lookup(dir, dentry);
-                else {
-                        printk("filesystem has no lookup\n");
-                        EXIT;
-                        goto exit;
-                }
+#if 0
         }
-        /* XXX this needs some work to handle returning de if we get it */
-        filter_setup_dentry_ops(cache->cache_filter, 
+#endif
+
+        if ( IS_ERR(de) ) {
+                CERROR("dentry lookup error %ld\n", PTR_ERR(de));
+                return de;
+        }
+
+        /* some file systems have no read_inode: set methods here */
+        if (dentry->d_inode)
+                presto_set_ops(dentry->d_inode, cache->cache_filter);
+
+        filter_setup_dentry_ops(cache->cache_filter,
                                 dentry->d_op, &presto_dentry_ops);
         dentry->d_op = filter_c2udops(cache->cache_filter);
-        if ( IS_ERR(de) ) {
-                rc = PTR_ERR(de);
-                CDEBUG(D_CACHE, "dentry lookup error %d\n", rc);
-                EXIT;
-                goto exit;
+
+        /* In lookup we will tolerate EROFS return codes from presto_set_dd
+         * to placate NFS. EROFS indicates that a fileset was not found but
+         * we should still be able to continue through a lookup.
+         * Anything else is a hard error and must be returned to VFS. */
+        if (!is_ilookup)
+                rc = presto_set_dd(dentry);
+        if (rc && rc != -EROFS) {
+                CERROR("presto_set_dd failed (dir %ld, name %*s): %d\n",
+                       dir->i_ino, dentry->d_name.len, dentry->d_name.name, rc);
+                return ERR_PTR(rc);
         }
 
-        /* some file systems set the methods in lookup, not in
-           read_inode, as a result we should set the methods here 
-           as well as in read_inode 
-        */
-	if (dentry->d_inode) {
-		presto_set_ops(dentry->d_inode, cache->cache_filter); 
-	}
         EXIT;
-exit:
-        return ERR_PTR(rc);
+        return NULL;
+}
+
+static inline int presto_check_set_fsdata (struct dentry *de)
+{
+        if (presto_d2d(de) == NULL) {
+#ifdef PRESTO_NO_NFS
+                CERROR("dentry without fsdata: %p: %*s\n", de, 
+                                de->d_name.len, de->d_name.name);
+                BUG();
+#endif
+                return presto_set_dd (de);
+        }
+
+        return 0;
 }
 
 int presto_setattr(struct dentry *de, struct iattr *iattr)
@@ -273,6 +343,7 @@
         struct lento_vfs_context info = { 0, 0, 0 };
 
         ENTRY;
+
         error = presto_prep(de, &cache, &fset);
         if ( error ) {
                 EXIT;
@@ -295,7 +366,7 @@
 
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
         error = presto_do_setattr(fset, de, iattr, &info);
         presto_put_permit(de->d_inode);
         return error;
@@ -310,23 +381,32 @@
 
 int presto_prep(struct dentry *dentry, struct presto_cache **cache,
                 struct presto_file_set **fset)
-{
+{       
+        int rc;
+
+        /* NFS might pass us dentries which have not gone through lookup.
+         * Test and set d_fsdata for such dentries
+         */
+        rc = presto_check_set_fsdata (dentry);
+        if (rc) return rc;
+
         *fset = presto_fset(dentry);
-        if ( !*fset ) {
-                CDEBUG(D_INODE, "No file set for dentry at %p\n", dentry);
+        if ( *fset == NULL ) {
+                CERROR("No file set for dentry at %p: %*s\n", dentry,
+                                dentry->d_name.len, dentry->d_name.name);
                 return -EROFS;
         }
 
         *cache = (*fset)->fset_cache;
-        if ( !*cache ) {
-                printk("PRESTO: BAD, BAD: cannot find cache\n");
+        if ( *cache == NULL ) {
+                CERROR("PRESTO: BAD, BAD: cannot find cache\n");
                 return -EBADF;
         }
 
         CDEBUG(D_PIOCTL, "---> cache flags %x, fset flags %x\n",
               (*cache)->cache_flags, (*fset)->fset_flags);
         if( presto_is_read_only(*fset) ) {
-                printk("PRESTO: cannot modify read-only fileset, minor %d.\n",
+                CERROR("PRESTO: cannot modify read-only fileset, minor %d.\n",
                        presto_c2m(*cache));
                 return -EROFS;
         }
@@ -342,12 +422,18 @@
         struct presto_file_set *fset;
 
         ENTRY;
+        error = presto_check_set_fsdata(dentry);
+        if ( error ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(dentry->d_parent, &cache, &fset);
         if ( error ) {
                 EXIT;
                 return error;
         }
-	presto_unlock(dir);
+        presto_unlock(dir);
 
         /* Does blocking and non-blocking behavious need to be 
            checked for.  Without blocking (return 1), the permit
@@ -360,12 +446,13 @@
         }
 
         presto_relock_sem(dir);
-	parent = dentry->d_parent; 
+        parent = dentry->d_parent; 
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
         error = presto_do_create(fset, parent, dentry, mode, &info);
+
         presto_relock_other(dir);
         presto_put_permit(dir);
         EXIT;
@@ -388,6 +475,12 @@
                 return error;
         }
 
+        error = presto_check_set_fsdata(new_dentry);
+        if ( error ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(new_dentry->d_parent, &new_cache, &new_fset);
         if ( error ) {
                 EXIT;
@@ -412,15 +505,25 @@
                 return -EROFS;
         }
 
-	presto_relock_sem(dir);
+        presto_relock_sem(dir);
         parent = new_dentry->d_parent;
 
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
         error = presto_do_link(fset, old_dentry, parent,
                                new_dentry, &info);
+
+#if 0
+        /* XXX for links this is not right */
+        if (cache->cache_filter->o_trops->tr_add_ilookup ) { 
+                struct dentry *d;
+                d = cache->cache_filter->o_trops->tr_add_ilookup
+                        (dir->i_sb->s_root, new_dentry, 1); 
+        }
+#endif 
+
         presto_relock_other(dir);
         presto_put_permit(dir);
         presto_put_permit(old_dentry->d_inode);
@@ -437,13 +540,19 @@
 
         ENTRY;
 
+        error = presto_check_set_fsdata(dentry);
+        if ( error  ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(dentry->d_parent, &cache, &fset);
         if ( error  ) {
                 EXIT;
                 return error;
         }
 
-	presto_unlock(dir); 
+        presto_unlock(dir); 
 
         if ( presto_get_permit(dir) < 0 ) {
                 EXIT;
@@ -454,17 +563,18 @@
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
 
-	presto_relock_sem(dir); 
-	parent = dentry->d_parent;
+        presto_relock_sem(dir); 
+        parent = dentry->d_parent;
         error = presto_do_mkdir(fset, parent, dentry, mode, &info);
-	presto_relock_other(dir); 
+        presto_relock_other(dir); 
         presto_put_permit(dir);
         return error;
 }
 
 
+
 static int presto_symlink(struct inode *dir, struct dentry *dentry,
                    const char *name)
 {
@@ -475,6 +585,12 @@
         struct lento_vfs_context info;
 
         ENTRY;
+        error = presto_check_set_fsdata(dentry);
+        if ( error ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(dentry->d_parent, &cache, &fset);
         if ( error ) {
                 EXIT;
@@ -484,16 +600,16 @@
         presto_unlock(dir);
         if ( presto_get_permit(dir) < 0 ) {
                 EXIT;
-		presto_fulllock(dir);
+                presto_fulllock(dir);
                 return -EROFS;
         }
 
-	presto_relock_sem(dir);
+        presto_relock_sem(dir);
         parent = dentry->d_parent;
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
         error = presto_do_symlink(fset, parent, dentry, name, &info);
         presto_relock_other(dir);
         presto_put_permit(dir);
@@ -509,6 +625,12 @@
         struct lento_vfs_context info;
 
         ENTRY;
+        error = presto_check_set_fsdata(dentry);
+        if ( error ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(dentry->d_parent, &cache, &fset);
         if ( error  ) {
                 EXIT;
@@ -518,17 +640,19 @@
         presto_unlock(dir);
         if ( presto_get_permit(dir) < 0 ) {
                 EXIT;
-		presto_fulllock(dir);
+                presto_fulllock(dir);
                 return -EROFS;
         }
 
-	presto_relock_sem(dir);
+        presto_relock_sem(dir);
         parent = dentry->d_parent;
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
+
         error = presto_do_unlink(fset, parent, dentry, &info);
+
         presto_relock_other(dir);
         presto_put_permit(dir);
         return error;
@@ -544,6 +668,13 @@
 
         ENTRY;
         CDEBUG(D_FILE, "prepping presto\n");
+        error = presto_check_set_fsdata(dentry);
+
+        if ( error ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(dentry->d_parent, &cache, &fset);
         if ( error ) {
                 EXIT;
@@ -554,32 +685,32 @@
         /* We need to dget() before the dput in double_unlock, to ensure we
          * still have dentry references.  double_lock doesn't do dget for us.
          */
-	unlock_kernel();
-	if (d_unhashed(dentry))
-		d_rehash(dentry);
+        unlock_kernel();
+        if (d_unhashed(dentry))
+                d_rehash(dentry);
         double_up(&dir->i_zombie, &dentry->d_inode->i_zombie);
         double_up(&dir->i_sem, &dentry->d_inode->i_sem);
 
         CDEBUG(D_FILE, "getting permit\n");
         if ( presto_get_permit(parent->d_inode) < 0 ) {
                 EXIT;
-		double_down(&dir->i_sem, &dentry->d_inode->i_sem);
-		double_down(&dir->i_zombie, &dentry->d_inode->i_zombie);
-		
-		lock_kernel();
+                double_down(&dir->i_sem, &dentry->d_inode->i_sem);
+                double_down(&dir->i_zombie, &dentry->d_inode->i_zombie);
+                
+                lock_kernel();
                 return -EROFS;
         }
         CDEBUG(D_FILE, "locking\n");
 
-	double_down(&dir->i_sem, &dentry->d_inode->i_sem);
-	parent = dentry->d_parent;
+        double_down(&dir->i_sem, &dentry->d_inode->i_sem);
+        parent = dentry->d_parent;
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
         error = presto_do_rmdir(fset, parent, dentry, &info);
         presto_put_permit(parent->d_inode);
-	lock_kernel();
+        lock_kernel();
         EXIT;
         return error;
 }
@@ -593,6 +724,12 @@
         struct lento_vfs_context info;
 
         ENTRY;
+        error = presto_check_set_fsdata(dentry);
+        if ( error ) {
+                EXIT;
+                return error;
+        }
+
         error = presto_prep(dentry->d_parent, &cache, &fset);
         if ( error  ) {
                 EXIT;
@@ -605,13 +742,13 @@
                 presto_fulllock(dir);
                 return -EROFS;
         }
-	
-	presto_relock_sem(dir);
+        
+        presto_relock_sem(dir);
         parent = dentry->d_parent;
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
+        info.flags |= LENTO_FL_IGNORE_TIME;
         error = presto_do_mknod(fset, parent, dentry, mode, rdev, &info);
         presto_relock_other(dir);
         presto_put_permit(dir);
@@ -620,80 +757,81 @@
 }
 
 inline void presto_triple_unlock(struct inode *old_dir, struct inode *new_dir, 
-				 struct dentry *old_dentry, 
-				 struct dentry *new_dentry, int triple)
+                                 struct dentry *old_dentry, 
+                                 struct dentry *new_dentry, int triple)
 {
-	/* rename_dir case */ 
-	if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
-		if (triple) {			
-			triple_up(&old_dir->i_zombie,
-				  &new_dir->i_zombie,
-				  &new_dentry->d_inode->i_zombie);
-		} else { 
-			double_up(&old_dir->i_zombie,
-				  &new_dir->i_zombie);
-		}
-		up(&old_dir->i_sb->s_vfs_rename_sem);
-	} else /* this case is rename_other */
-		double_up(&old_dir->i_zombie, &new_dir->i_zombie);
-	/* done by do_rename */
-	unlock_kernel();
-	double_up(&old_dir->i_sem, &new_dir->i_sem);
+        /* rename_dir case */ 
+        if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
+                if (triple) {                   
+                        triple_up(&old_dir->i_zombie,
+                                  &new_dir->i_zombie,
+                                  &new_dentry->d_inode->i_zombie);
+                } else { 
+                        double_up(&old_dir->i_zombie,
+                                  &new_dir->i_zombie);
+                }
+                up(&old_dir->i_sb->s_vfs_rename_sem);
+        } else /* this case is rename_other */
+                double_up(&old_dir->i_zombie, &new_dir->i_zombie);
+        /* done by do_rename */
+        unlock_kernel();
+        double_up(&old_dir->i_sem, &new_dir->i_sem);
 }
 
 inline void presto_triple_fulllock(struct inode *old_dir, 
-				   struct inode *new_dir, 
-				   struct dentry *old_dentry, 
-				   struct dentry *new_dentry, int triple)
-{
-	/* done by do_rename */
-	double_down(&old_dir->i_sem, &new_dir->i_sem);
-	lock_kernel();
-	/* rename_dir case */ 
-	if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
-		down(&old_dir->i_sb->s_vfs_rename_sem);
-		if (triple) {			
-			triple_down(&old_dir->i_zombie,
-				  &new_dir->i_zombie,
-				  &new_dentry->d_inode->i_zombie);
-		} else { 
-			double_down(&old_dir->i_zombie,
-				  &new_dir->i_zombie);
-		}
-	} else /* this case is rename_other */
-		double_down(&old_dir->i_zombie, &new_dir->i_zombie);
+                                   struct inode *new_dir, 
+                                   struct dentry *old_dentry, 
+                                   struct dentry *new_dentry, int triple)
+{
+        /* done by do_rename */
+        double_down(&old_dir->i_sem, &new_dir->i_sem);
+        lock_kernel();
+        /* rename_dir case */ 
+        if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
+                down(&old_dir->i_sb->s_vfs_rename_sem);
+                if (triple) {                   
+                        triple_down(&old_dir->i_zombie,
+                                  &new_dir->i_zombie,
+                                  &new_dentry->d_inode->i_zombie);
+                } else { 
+                        double_down(&old_dir->i_zombie,
+                                  &new_dir->i_zombie);
+                }
+        } else /* this case is rename_other */
+                double_down(&old_dir->i_zombie, &new_dir->i_zombie);
 }
 
 inline void presto_triple_relock_sem(struct inode *old_dir, 
-				   struct inode *new_dir, 
-				   struct dentry *old_dentry, 
-				   struct dentry *new_dentry, int triple)
-{
-	/* done by do_rename */
-	double_down(&old_dir->i_sem, &new_dir->i_sem);
-	lock_kernel();
+                                   struct inode *new_dir, 
+                                   struct dentry *old_dentry, 
+                                   struct dentry *new_dentry, int triple)
+{
+        /* done by do_rename */
+        double_down(&old_dir->i_sem, &new_dir->i_sem);
+        lock_kernel();
 }
 
 inline void presto_triple_relock_other(struct inode *old_dir, 
-				   struct inode *new_dir, 
-				   struct dentry *old_dentry, 
-				   struct dentry *new_dentry, int triple)
-{
-	/* rename_dir case */ 
-	if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
-		down(&old_dir->i_sb->s_vfs_rename_sem);
-		if (triple) {			
-			triple_down(&old_dir->i_zombie,
-				  &new_dir->i_zombie,
-				  &new_dentry->d_inode->i_zombie);
-		} else { 
-			double_down(&old_dir->i_zombie,
-				  &new_dir->i_zombie);
-		}
-	} else /* this case is rename_other */
-		double_down(&old_dir->i_zombie, &new_dir->i_zombie);
+                                   struct inode *new_dir, 
+                                   struct dentry *old_dentry, 
+                                   struct dentry *new_dentry, int triple)
+{
+        /* rename_dir case */ 
+        if (S_ISDIR(old_dentry->d_inode->i_mode)) { 
+                down(&old_dir->i_sb->s_vfs_rename_sem);
+                if (triple) {                   
+                        triple_down(&old_dir->i_zombie,
+                                  &new_dir->i_zombie,
+                                  &new_dentry->d_inode->i_zombie);
+                } else { 
+                        double_down(&old_dir->i_zombie,
+                                  &new_dir->i_zombie);
+                }
+        } else /* this case is rename_other */
+                double_down(&old_dir->i_zombie, &new_dir->i_zombie);
 }
 
+
 // XXX this can be optimized: renamtes across filesets only require 
 //     multiple KML records, but can locally be executed normally. 
 int presto_rename(struct inode *old_dir, struct dentry *old_dentry,
@@ -713,7 +851,6 @@
                 EXIT;
                 return error;
         }
-
         error = presto_prep(new_parent, &new_cache, &new_fset);
         if ( error ) {
                 EXIT;
@@ -732,27 +869,27 @@
         triple = (S_ISDIR(old_dentry->d_inode->i_mode) && new_dentry->d_inode)?
                 1:0;
 
-	presto_triple_unlock(old_dir, new_dir, old_dentry, new_dentry, triple); 
+        presto_triple_unlock(old_dir, new_dir, old_dentry, new_dentry, triple); 
 
         if ( presto_get_permit(old_dir) < 0 ) {
                 EXIT;
-		presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple); 
+                presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple); 
                 return -EROFS;
         }
         if ( presto_get_permit(new_dir) < 0 ) {
                 EXIT;
-		presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple); 
+                presto_triple_fulllock(old_dir, new_dir, old_dentry, new_dentry, triple); 
                 return -EROFS;
         }
 
-	presto_triple_relock_sem(old_dir, new_dir, old_dentry, new_dentry, triple); 
+        presto_triple_relock_sem(old_dir, new_dir, old_dentry, new_dentry, triple); 
         memset(&info, 0, sizeof(info));
         if (!ISLENTO(presto_c2m(cache)))
                 info.flags = LENTO_FL_KML;
-	info.flags |= LENTO_FL_IGNORE_TIME;
-        error = presto_do_rename(fset, old_parent, old_dentry, new_parent,
-                                 new_dentry, &info);
-	presto_triple_relock_other(old_dir, new_dir, old_dentry, new_dentry, triple); 
+        info.flags |= LENTO_FL_IGNORE_TIME;
+        error = do_rename(fset, old_parent, old_dentry, new_parent,
+                          new_dentry, &info);
+        presto_triple_relock_other(old_dir, new_dir, old_dentry, new_dentry, triple); 
 
         presto_put_permit(new_dir);
         presto_put_permit(old_dir);
@@ -812,72 +949,467 @@
 }
 
 
-static int presto_dir_open(struct inode *inode, struct file *file)
+int presto_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg)
 {
-        int rc = 0;
-        struct dentry *de = file->f_dentry;
-        struct file_operations *fops;
-        struct presto_cache *cache;
-        struct presto_file_set *fset;
-        int minor;
-        int error; 
+        char buf[1024];
+        struct izo_ioctl_data *data = NULL;
+        struct presto_dentry_data *dd;
+        int rc;
 
         ENTRY;
 
-        error = presto_prep(file->f_dentry, &cache, &fset);
-        if ( error  ) {
+        /* Try the filesystem's ioctl first, and return if it succeeded. */
+        dd = presto_d2d(file->f_dentry); 
+        if (dd && dd->dd_fset) { 
+                int (*cache_ioctl)(struct inode *, struct file *, unsigned int, unsigned long ) = filter_c2cdfops(dd->dd_fset->fset_cache->cache_filter)->ioctl;
+                rc = -ENOTTY;
+                if (cache_ioctl)
+                        rc = cache_ioctl(inode, file, cmd, arg);
+                if (rc != -ENOTTY) {
+                        EXIT;
+                        return rc;
+                }
+        }
+
+        if (current->euid != 0 && current->euid != izo_authorized_uid) {
                 EXIT;
-                make_bad_inode(inode);
-                return error;
+                return -EPERM;
         }
-        minor = presto_c2m(cache);
 
-        CDEBUG(D_CACHE, "minor %d, DATA_OK: %d, ino: %ld\n",
-               minor, presto_chk(de, PRESTO_DATA), inode->i_ino);
+        memset(buf, 0, sizeof(buf));
+        
+        if (izo_ioctl_getdata(buf, buf + 1024, (void *)arg)) { 
+                CERROR("intermezzo ioctl: data error\n");
+                return -EINVAL;
+        }
+        data = (struct izo_ioctl_data *)buf;
+        
+        switch(cmd) {
+        case IZO_IOC_REINTKML: { 
+                int rc;
+                int cperr;
+                rc = kml_reint_rec(file, data);
+
+                EXIT;
+                cperr = copy_to_user((char *)arg, data, sizeof(*data));
+                if (cperr) { 
+                        CERROR("WARNING: cperr %d\n", cperr); 
+                        rc = -EFAULT;
+                }
+                return rc;
+        }
+
+        case IZO_IOC_GET_RCVD: {
+                struct izo_rcvd_rec rec;
+                struct presto_file_set *fset;
+                int rc;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                rc = izo_rcvd_get(&rec, fset, data->ioc_uuid);
+                if (rc < 0) {
+                        EXIT;
+                        return rc;
+                }
+
+                EXIT;
+                return copy_to_user((char *)arg, &rec, sizeof(rec))? -EFAULT : 0;
+        }
+
+        case IZO_IOC_REPSTATUS: {
+                __u64 client_kmlsize;
+                struct izo_rcvd_rec *lr_client;
+                struct izo_rcvd_rec rec;
+                struct presto_file_set *fset;
+                int minor;
+                int rc;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                client_kmlsize = data->ioc_kmlsize;
+                lr_client =  (struct izo_rcvd_rec *) data->ioc_pbuf1;
+
+                rc = izo_repstatus(fset, client_kmlsize, 
+                                       lr_client, &rec);
+                if (rc < 0) {
+                        EXIT;
+                        return rc;
+                }
+
+                EXIT;
+                return copy_to_user((char *)arg, &rec, sizeof(rec))? -EFAULT : 0;
+        }
+
+        case IZO_IOC_GET_CHANNEL: {
+                struct presto_file_set *fset;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                
+                data->ioc_dev = fset->fset_cache->cache_psdev->uc_minor;
+                CDEBUG(D_PSDEV, "CHANNEL %d\n", data->ioc_dev); 
+                EXIT;
+                return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0;
+        }
+
+        case IZO_IOC_SET_IOCTL_UID:
+                izo_authorized_uid = data->ioc_uid;
+                EXIT;
+                return 0;
+
+        case IZO_IOC_SET_PID:
+                rc = izo_psdev_setpid(data->ioc_dev);
+                EXIT;
+                return rc;
+
+        case IZO_IOC_SET_CHANNEL:
+                rc = izo_psdev_setchannel(file, data->ioc_dev);
+                EXIT;
+                return rc;
+
+        case IZO_IOC_GET_KML_SIZE: {
+                struct presto_file_set *fset;
+                __u64 kmlsize;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+
+                kmlsize = presto_kml_offset(fset) + fset->fset_kml_logical_off;
+
+                EXIT;
+                return copy_to_user((char *)arg, &kmlsize, sizeof(kmlsize))?-EFAULT : 0;
+        }
+
+        case IZO_IOC_PURGE_FILE_DATA: {
+                struct presto_file_set *fset;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+
+                rc = izo_purge_file(fset, data->ioc_inlbuf1);
+                EXIT;
+                return rc;
+        }
+
+        case IZO_IOC_GET_FILEID: {
+                rc = izo_get_fileid(file, data);
+                EXIT;
+                if (rc)
+                        return rc;
+                return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0;
+        }
+
+        case IZO_IOC_SET_FILEID: {
+                rc = izo_set_fileid(file, data);
+                EXIT;
+                if (rc)
+                        return rc;
+                return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT  : 0;
+        }
+
+        case IZO_IOC_ADJUST_LML: { 
+                struct lento_vfs_context *info; 
+                info = (struct lento_vfs_context *)data->ioc_inlbuf1;
+                rc = presto_adjust_lml(file, info); 
+                EXIT;
+                return rc;
+        }
+
+        case IZO_IOC_CONNECT: {
+                struct presto_file_set *fset;
+                int minor;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                rc = izo_upc_connect(minor, data->ioc_ino,
+                                     data->ioc_generation, data->ioc_uuid,
+                                     data->ioc_flags);
+                EXIT;
+                return rc;
+        }
+
+        case IZO_IOC_GO_FETCH_KML: {
+                struct presto_file_set *fset;
+                int minor;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                rc = izo_upc_go_fetch_kml(minor, fset->fset_name,
+                                          data->ioc_uuid, data->ioc_kmlsize);
+                EXIT;
+                return rc;
+        }
+
+        case IZO_IOC_REVOKE_PERMIT:
+                if (data->ioc_flags)
+                        rc = izo_revoke_permit(file->f_dentry, data->ioc_uuid);
+                else
+                        rc = izo_revoke_permit(file->f_dentry, NULL);
+                EXIT;
+                return rc;
+
+        case IZO_IOC_CLEAR_FSET:
+                rc = izo_clear_fsetroot(file->f_dentry);
+                EXIT;
+                return rc;
+
+        case IZO_IOC_CLEAR_ALL_FSETS: { 
+                struct presto_file_set *fset;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+
+                rc = izo_clear_all_fsetroots(fset->fset_cache);
+                EXIT;
+                return rc;
+        }
+
+        case IZO_IOC_SET_FSET:
+                /*
+                 * Mark this dentry as being a fileset root.
+                 */
+                rc = presto_set_fsetroot_from_ioc(file->f_dentry, 
+                                                  data->ioc_inlbuf1,
+                                                  data->ioc_flags);
+                EXIT;
+                return rc;
+
+
+        case IZO_IOC_MARK: {
+                int res = 0;  /* resulting flags - returned to user */
+                int error;
+
+                CDEBUG(D_DOWNCALL, "mark inode: %ld, and: %x, or: %x, what %d\n",
+                       file->f_dentry->d_inode->i_ino, data->ioc_and_flag,
+                       data->ioc_or_flag, data->ioc_mark_what);
+
+                switch (data->ioc_mark_what) {
+                case MARK_DENTRY:               
+                        error = izo_mark_dentry(file->f_dentry,
+                                                   data->ioc_and_flag,
+                                                   data->ioc_or_flag, &res);
+                        break;
+                case MARK_FSET:
+                        error = izo_mark_fset(file->f_dentry,
+                                                 data->ioc_and_flag,
+                                                 data->ioc_or_flag, &res);
+                        break;
+                case MARK_CACHE:
+                        error = izo_mark_cache(file->f_dentry,
+                                                  data->ioc_and_flag,
+                                                  data->ioc_or_flag, &res);
+                        break;
+                case MARK_GETFL: {
+                        int fflags, cflags;
+                        data->ioc_and_flag = 0xffffffff;
+                        data->ioc_or_flag = 0; 
+                        error = izo_mark_dentry(file->f_dentry,
+                                                   data->ioc_and_flag,
+                                                   data->ioc_or_flag, &res);
+                        if (error) 
+                                break;
+                        error = izo_mark_fset(file->f_dentry,
+                                                 data->ioc_and_flag,
+                                                 data->ioc_or_flag, &fflags);
+                        if (error) 
+                                break;
+                        error = izo_mark_cache(file->f_dentry,
+                                                  data->ioc_and_flag,
+                                                  data->ioc_or_flag,
+                                                  &cflags);
+
+                        if (error) 
+                                break;
+                        data->ioc_and_flag = fflags;
+                        data->ioc_or_flag = cflags;
+                        break;
+                }
+                default:
+                        error = -EINVAL;
+                }
+
+                if (error) { 
+                        EXIT;
+                        return error;
+                }
+                data->ioc_mark_what = res;
+                CDEBUG(D_DOWNCALL, "mark inode: %ld, and: %x, or: %x, what %x\n",
+                       file->f_dentry->d_inode->i_ino, data->ioc_and_flag,
+                       data->ioc_or_flag, data->ioc_mark_what);
+
+                EXIT;
+                return copy_to_user((char *)arg, data, sizeof(*data))? -EFAULT : 0;
+        }
+#if 0
+        case IZO_IOC_CLIENT_MAKE_BRANCH: {
+                struct presto_file_set *fset;
+                int minor;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                rc = izo_upc_client_make_branch(minor, fset->fset_name,
+                                                data->ioc_inlbuf1,
+                                                data->ioc_inlbuf2);
+                EXIT;
+                return rc;
+        }
+#endif
+        case IZO_IOC_SERVER_MAKE_BRANCH: {
+                struct presto_file_set *fset;
+                int minor;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                izo_upc_server_make_branch(minor, data->ioc_inlbuf1);
+                EXIT;
+                return 0;
+        }
+        case IZO_IOC_SET_KMLSIZE: {
+                struct presto_file_set *fset;
+                int minor;
+                struct izo_rcvd_rec rec;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
+
+                rc = izo_upc_set_kmlsize(minor, fset->fset_name, data->ioc_uuid,
+                                         data->ioc_kmlsize);
+
+                if (rc != 0) {
+                        EXIT;
+                        return rc;
+                }
+
+                rc = izo_rcvd_get(&rec, fset, data->ioc_uuid);
+                if (rc == -EINVAL) {
+                        /* We don't know anything about this uuid yet; no
+                         * worries. */
+                        memset(&rec, 0, sizeof(rec));
+                } else if (rc <= 0) {
+                        CERROR("InterMezzo: error reading last_rcvd: %d\n", rc);
+                        EXIT;
+                        return rc;
+                }
+                rec.lr_remote_offset = data->ioc_kmlsize;
+                rc = izo_rcvd_write(fset, &rec);
+                if (rc <= 0) {
+                        CERROR("InterMezzo: error writing last_rcvd: %d\n", rc);
+                        EXIT;
+                        return rc;
+                }
+                EXIT;
+                return rc;
+        }
+        case IZO_IOC_BRANCH_UNDO: {
+                struct presto_file_set *fset;
+                int minor;
 
-        if ( ISLENTO(minor) )
-                goto cache;
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
 
-        if ( !presto_chk(de, PRESTO_DATA) ) {
-                CDEBUG(D_CACHE, "doing lento_opendir\n");
-                rc = presto_opendir_upcall(minor, file->f_dentry, fset->fset_mtpt, SYNCHRONOUS);
+                rc = izo_upc_branch_undo(minor, fset->fset_name,
+                                         data->ioc_inlbuf1);
+                EXIT;
+                return rc;
         }
+        case IZO_IOC_BRANCH_REDO: {
+                struct presto_file_set *fset;
+                int minor;
+
+                fset = presto_fset(file->f_dentry);
+                if (fset == NULL) {
+                        EXIT;
+                        return -ENODEV;
+                }
+                minor = presto_f2m(fset);
 
-        if ( rc ) {
-                printk("presto_dir_open: DATA_OK: %d, ino: %ld, error %d\n",
-                       presto_chk(de, PRESTO_DATA), inode->i_ino, rc);
-                return rc ;
+                rc = izo_upc_branch_redo(minor, fset->fset_name,
+                                         data->ioc_inlbuf1);
+                EXIT;
+                return rc;
         }
 
- cache:
-        fops = filter_c2cdfops(cache->cache_filter);
-        if ( fops->open ) {
-                rc = fops->open(inode, file);
+        case TCGETS:
+                EXIT;
+                return -EINVAL;
+
+        default:
+                EXIT;
+                return -EINVAL;
+                
         }
-        presto_set(de, PRESTO_DATA | PRESTO_ATTR);
-        CDEBUG(D_CACHE, "returns %d, data %d, attr %d\n", rc,
-               presto_chk(de, PRESTO_DATA), presto_chk(de, PRESTO_ATTR));
+        EXIT;
         return 0;
 }
 
 struct file_operations presto_dir_fops = {
-        open: presto_dir_open
+        .ioctl =  presto_ioctl
 };
 
 struct inode_operations presto_dir_iops = {
-        create: presto_create,
-        lookup: presto_lookup,
-        link:   presto_link,
-        unlink: presto_unlink,
-        symlink:        presto_symlink,
-        mkdir:  presto_mkdir,
-        rmdir:  presto_rmdir,
-        mknod:  presto_mknod,
-        rename: presto_rename,
-        permission:     presto_permission,
-        setattr:        presto_setattr,
+        .create       = presto_create,
+        .lookup       = presto_lookup,
+        .link         = presto_link,
+        .unlink       = presto_unlink,
+        .symlink      = presto_symlink,
+        .mkdir        = presto_mkdir,
+        .rmdir        = presto_rmdir,
+        .mknod        = presto_mknod,
+        .rename       = presto_rename,
+        .permission   = presto_permission,
+        .setattr      = presto_setattr,
 #ifdef CONFIG_FS_EXT_ATTR
-	set_ext_attr:	presto_set_ext_attr,
+        .set_ext_attr = presto_set_ext_attr,
 #endif
-
 };
+
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/ext_attr.c linux.20pre10-ac2/fs/intermezzo/ext_attr.c
--- linux.20pre10/fs/intermezzo/ext_attr.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/ext_attr.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,10 +1,25 @@
-/* 
- * Extended attribute handling for presto.
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ * 
+ *  Copyright (C) 2001 Tacit Networks, Inc.
+ *    Author: Shirish H. Phatak <shirish@tacitnetworks.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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.
  *
- * Copyright (C) 2001. All rights reserved.
- * Shirish H. Phatak
- * Tacit Networks, Inc.
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
+ * Extended attribute handling for presto.
  */
 
 #define __NO_VERSION__
@@ -32,10 +47,7 @@
 #include <linux/smp_lock.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
-
 
 #ifdef CONFIG_FS_EXT_ATTR
 #include <linux/ext_attr.h>
@@ -43,9 +55,6 @@
 extern inline void presto_debug_fail_blkdev(struct presto_file_set *fset,
                                             unsigned long value);
 
-extern int presto_prep(struct dentry *, struct presto_cache **,
-                       struct presto_file_set **);
-
 
 /* VFS interface */
 /* XXX! Fixme test for user defined attributes */
@@ -77,7 +86,7 @@
          * we do a reverse mapping from inode to the first dentry 
          */
         if (list_empty(&inode->i_dentry)) {
-                printk("No alias for inode %d\n", (int) inode->i_ino);
+                CERROR("No alias for inode %d\n", (int) inode->i_ino);
                 EXIT;
                 return -EINVAL;
         }
@@ -101,12 +110,13 @@
             * (works for ext3)
             */
             if (flags & EXT_ATTR_FLAG_USER) {
-                PRESTO_ALLOC(buf, char *, buffer_len);
+                PRESTO_ALLOC(buf, buffer_len);
                 if (!buf) {
-                        printk("InterMezzo: out of memory!!!\n");
+                        CERROR("InterMezzo: out of memory!!!\n");
                         return -ENOMEM;
                 }
-                if (copy_from_user(buf, buffer, buffer_len))
+                error = copy_from_user(buf, buffer, buffer_len);
+                if (error) 
                         return -EFAULT;
             } else 
                 buf = buffer;
@@ -174,7 +184,7 @@
         fset = presto_fset(dentry);
         error = -EINVAL;
         if ( !fset ) {
-                printk("No fileset!\n");
+                CERROR("No fileset!\n");
                 EXIT;
                 goto exit_dentry;
         }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/file.c linux.20pre10-ac2/fs/intermezzo/file.c
--- linux.20pre10/fs/intermezzo/file.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/file.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,22 +1,34 @@
-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
  *  Copyright (C) 2000 Stelias Computing, Inc.
  *  Copyright (C) 2000 Red Hat, Inc.
  *  Copyright (C) 2000 TurboLinux, Inc.
  *  Copyright (C) 2000 Los Alamos National Laboratory.
- *  Copyright (C) 2000 Tacitus Systems
+ *  Copyright (C) 2000, 2001 Tacit Networks, Inc.
  *  Copyright (C) 2000 Peter J. Braam
  *  Copyright (C) 2001 Mountain View Data, Inc. 
  *  Copyright (C) 2001 Cluster File Systems, Inc. 
  *
- *  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 file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
+ *  This file manages file I/O
+ * 
  */
 
-
 #include <stdarg.h>
 
 #include <asm/bitops.h>
@@ -39,71 +51,126 @@
 #include <linux/module.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_kml.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
 #include <linux/fsfilter.h>
 /*
  * these are initialized in super.c
  */
 extern int presto_permission(struct inode *inode, int mask);
-extern int presto_opendir_upcall(int minor, struct dentry *de, int async);
-
-extern int presto_prep(struct dentry *, struct presto_cache **,
-                       struct presto_file_set **);
 
 
-#if 0
 static int presto_open_upcall(int minor, struct dentry *de)
 {
         int rc;
         char *path, *buffer;
+        struct presto_file_set *fset;
         int pathlen;
+        struct lento_vfs_context info;
+        struct presto_dentry_data *dd = presto_d2d(de);
 
-        PRESTO_ALLOC(buffer, char *, PAGE_SIZE);
+        PRESTO_ALLOC(buffer, PAGE_SIZE);
         if ( !buffer ) {
-                printk("PRESTO: out of memory!\n");
-                return ENOMEM;
+                CERROR("PRESTO: out of memory!\n");
+                return -ENOMEM;
         }
-        path = presto_path(de, buffer, PAGE_SIZE);
+        fset = presto_fset(de);
+        path = presto_path(de, fset->fset_dentry, buffer, PAGE_SIZE);
         pathlen = MYPATHLEN(buffer, path);
-        rc = lento_open(minor, pathlen, path);
+        
+        CDEBUG(D_FILE, "de %p, dd %p\n", de, dd);
+        if (dd->remote_ino == 0) {
+                rc = presto_get_fileid(minor, fset, de);
+        }
+        memset (&info, 0, sizeof(info));
+        if (dd->remote_ino > 0) {
+                info.remote_ino = dd->remote_ino;
+                info.remote_generation = dd->remote_generation;
+        } else
+                CERROR("get_fileid failed %d, ino: %Lx, fetching by name\n", rc,
+                       dd->remote_ino);
+
+        rc = izo_upc_open(minor, pathlen, path, fset->fset_name, &info);
         PRESTO_FREE(buffer, PAGE_SIZE);
         return rc;
 }
-#endif
 
+static inline int open_check_dod(struct file *file,
+                                 struct presto_file_set *fset)
+{
+        int gen, is_iopen = 0, minor;
+        struct presto_cache *cache = fset->fset_cache;
+        ino_t inum;
+
+        minor = presto_c2m(cache);
+
+        if ( ISLENTO(minor) ) {
+                CDEBUG(D_CACHE, "is lento, not doing DOD.\n");
+                return 0;
+        }
+
+        /* Files are only ever opened by inode during backfetches, when by
+         * definition we have the authoritative copy of the data.  No DOD. */
+        is_iopen = izo_dentry_is_ilookup(file->f_dentry, &inum, &gen);
+
+        if (is_iopen) {
+                CDEBUG(D_CACHE, "doing iopen, not doing DOD.\n");
+                return 0;
+        }
+
+        if (!(fset->fset_flags & FSET_DATA_ON_DEMAND)) {
+                CDEBUG(D_CACHE, "fileset not on demand.\n");
+                return 0;
+        }
+                
+        if (file->f_flags & O_TRUNC) {
+                CDEBUG(D_CACHE, "fileset dod: O_TRUNC.\n");
+                return 0;
+        }
+                
+        if (presto_chk(file->f_dentry, PRESTO_DONT_JOURNAL)) {
+                CDEBUG(D_CACHE, "file under .intermezzo, not doing DOD\n");
+                return 0;
+        }
+
+        if (presto_chk(file->f_dentry, PRESTO_DATA)) {
+                CDEBUG(D_CACHE, "PRESTO_DATA is set, not doing DOD.\n");
+                return 0;
+        }
+
+        if (cache->cache_filter->o_trops->tr_all_data(file->f_dentry->d_inode)) {
+                CDEBUG(D_CACHE, "file not sparse, not doing DOD.\n");
+                return 0;
+        }
+
+        return 1;
+}
 
 static int presto_file_open(struct inode *inode, struct file *file)
 {
         int rc = 0;
         struct file_operations *fops;
         struct presto_cache *cache;
+        struct presto_file_set *fset;
         struct presto_file_data *fdata;
         int writable = (file->f_flags & (O_RDWR | O_WRONLY));
-        int minor;
-        int i;
+        int minor, i;
 
         ENTRY;
 
-        cache = presto_get_cache(inode);
-        if ( !cache ) {
-                printk("PRESTO: BAD, BAD: cannot find cache\n");
+        if (presto_prep(file->f_dentry, &cache, &fset) < 0) {
                 EXIT;
                 return -EBADF;
         }
 
         minor = presto_c2m(cache);
 
-        CDEBUG(D_CACHE, "presto_file_open: DATA_OK: %d, ino: %ld\n",
-               presto_chk(file->f_dentry, PRESTO_DATA), inode->i_ino);
-
-        if ( ISLENTO(minor) )
-                goto cache;
-
-        if ( file->f_flags & O_RDWR || file->f_flags & O_WRONLY) {
-                CDEBUG(D_CACHE, "presto_file_open: calling presto_get_permit\n");
-                /* lock needed to protect permit_count manipulations -SHP */
+        CDEBUG(D_CACHE, "DATA_OK: %d, ino: %ld, islento: %d\n",
+               presto_chk(file->f_dentry, PRESTO_DATA), inode->i_ino,
+               ISLENTO(minor));
+
+        if ( !ISLENTO(minor) && (file->f_flags & O_RDWR ||
+                                 file->f_flags & O_WRONLY)) {
+                CDEBUG(D_CACHE, "calling presto_get_permit\n");
                 if ( presto_get_permit(inode) < 0 ) {
                         EXIT;
                         return -EROFS;
@@ -111,71 +178,97 @@
                 presto_put_permit(inode);
         }
 
-        /* XXX name space synchronization here for data/streaming on demand?*/
-        /* XXX Lento can make us wait here for backfetches to complete */
-#if 0
-        if ( !presto_chk(file->f_dentry, PRESTO_DATA) ||
-             !presto_has_all_data(file->f_dentry->d_inode) ) {
-                CDEBUG(D_CACHE, "presto_file_open: presto_open_upcall\n");
+        if (open_check_dod(file, fset)) {
+                CDEBUG(D_CACHE, "presto_open_upcall\n");
+                CDEBUG(D_CACHE, "dentry: %p setting DATA, ATTR\n", file->f_dentry);
+                presto_set(file->f_dentry, PRESTO_ATTR | PRESTO_DATA);
                 rc = presto_open_upcall(minor, file->f_dentry);
+                if (rc) {
+                        EXIT;
+                        CERROR("%s: returning error %d\n", __FUNCTION__, rc);
+                        return rc;
+                }
+
+        }
+
+        /* file was truncated upon open: do not refetch */
+        if (file->f_flags & O_TRUNC) { 
+                CDEBUG(D_CACHE, "setting DATA, ATTR\n");
+                presto_set(file->f_dentry, PRESTO_ATTR | PRESTO_DATA);
         }
 
-#endif
-        rc = 0;
- cache:
         fops = filter_c2cffops(cache->cache_filter);
         if ( fops->open ) {
-                CDEBUG(D_CACHE, "presto_file_open: calling fs open\n");
+                CDEBUG(D_CACHE, "calling fs open\n");
                 rc = fops->open(inode, file);
-        }
-        if (rc) {
-            EXIT;
-            return rc;
-        }
 
-        CDEBUG(D_CACHE, "presto_file_open: setting DATA, ATTR\n");
-        if( ISLENTO(minor) )
-            presto_set(file->f_dentry, PRESTO_ATTR );
-        else
-                presto_set(file->f_dentry, PRESTO_ATTR | PRESTO_DATA);
+                if (rc) {
+                        EXIT;
+                        return rc;
+                }
+        }
 
-        if (writable) { 
-                PRESTO_ALLOC(fdata, struct presto_file_data *, sizeof(*fdata));
+        if (writable) {
+                PRESTO_ALLOC(fdata, sizeof(*fdata));
                 if (!fdata) {
                         EXIT;
                         return -ENOMEM;
                 }
-                /* we believe that on open the kernel lock
-                   assures that only one process will do this allocation */ 
+                /* LOCK: XXX check that the kernel lock protects this alloc */
                 fdata->fd_do_lml = 0;
+                fdata->fd_bytes_written = 0;
                 fdata->fd_fsuid = current->fsuid;
                 fdata->fd_fsgid = current->fsgid;
                 fdata->fd_mode = file->f_dentry->d_inode->i_mode;
+                fdata->fd_uid = file->f_dentry->d_inode->i_uid;
+                fdata->fd_gid = file->f_dentry->d_inode->i_gid;
                 fdata->fd_ngroups = current->ngroups;
-                for (i=0 ; i<current->ngroups ; i++)
-                        fdata->fd_groups[i] = current->groups[i]; 
-                fdata->fd_bytes_written = 0; /*when open,written data is zero*/ 
-                file->private_data = fdata; 
+                for (i=0 ; i < current->ngroups ; i++)
+                        fdata->fd_groups[i] = current->groups[i];
+                if (!ISLENTO(minor)) 
+                        fdata->fd_info.flags = LENTO_FL_KML; 
+                else { 
+                        /* this is for the case of DOD, 
+                           reint_close will adjust flags if needed */
+                        fdata->fd_info.flags = 0;
+                }
+
+                presto_getversion(&fdata->fd_version, inode);
+                file->private_data = fdata;
         } else {
                 file->private_data = NULL;
         }
 
+        EXIT;
         return 0;
 }
 
+int presto_adjust_lml(struct file *file, struct lento_vfs_context *info)
+{
+        struct presto_file_data *fdata = 
+                (struct presto_file_data *) file->private_data;
+
+        if (!fdata) { 
+                EXIT;
+                return -EINVAL;
+        }
+                
+        memcpy(&fdata->fd_info, info, sizeof(*info));
+        EXIT;
+        return 0; 
+}
+
+
 static int presto_file_release(struct inode *inode, struct file *file)
 {
-        struct rec_info rec;
         int rc;
-        int writable = (file->f_flags & (O_RDWR | O_WRONLY));
         struct file_operations *fops;
         struct presto_cache *cache;
         struct presto_file_set *fset;
-        void *handle; 
         struct presto_file_data *fdata = 
                 (struct presto_file_data *)file->private_data;
-
         ENTRY;
+
         rc = presto_prep(file->f_dentry, &cache, &fset);
         if ( rc ) {
                 EXIT;
@@ -183,96 +276,40 @@
         }
 
         fops = filter_c2cffops(cache->cache_filter);
-        rc = fops->release(inode, file);
+        if (fops && fops->release)
+                rc = fops->release(inode, file);
 
-        CDEBUG(D_CACHE, "islento = %d (minor %d), writable = %d, rc %d, data %p\n",
+        CDEBUG(D_CACHE, "islento = %d (minor %d), rc %d, data %p\n",
                ISLENTO(cache->cache_psdev->uc_minor), 
-               cache->cache_psdev->uc_minor, 
-               writable, rc, fdata);
-
-        if (fdata && fdata->fd_do_lml) { 
-                CDEBUG(D_CACHE, "LML at %lld\n", fdata->fd_lml_offset); 
-        }
-
-        /* don't journal close if file couldn't have been written to */
-        /*    if (!ISLENTO(cache->cache_prestominor) && !rc && writable) {*/
-        if (fdata && fdata->fd_do_lml && 
-            !rc && writable && (! ISLENTO(cache->cache_psdev->uc_minor))) {
-                struct presto_version new_ver;
-
-                presto_getversion(&new_ver, inode);
+               cache->cache_psdev->uc_minor, rc, fdata);
 
+        /* this file was modified: ignore close errors, write KML */
+        if (fdata && fdata->fd_do_lml) {
                 /* XXX: remove when lento gets file granularity cd */
-                /* Lock needed to protect permit_count manipulations -SHP */
                 if ( presto_get_permit(inode) < 0 ) {
                         EXIT;
                         return -EROFS;
                 }
-                CDEBUG(D_CACHE, "presto_file_release: writing journal\n");
         
-                rc = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
-                if (rc) { 
-                        presto_put_permit(inode); 
-                        EXIT; 
-                        return rc;
-                }
-                handle = presto_trans_start(fset, file->f_dentry->d_inode, 
-                                            PRESTO_OP_RELEASE);
-                if ( IS_ERR(handle) ) {
-                        printk("presto_release: no space for transaction\n");
-                        presto_put_permit(inode);
-                        return -ENOSPC;
-                }
-                rc = presto_journal_close(&rec, fset, file, file->f_dentry, 
-                                          &new_ver);
-                if (rc) { 
-                        printk("presto_close: cannot journal close\n");
-                        /* XXX oops here to get this bug */ 
-                        *(int *)0 = 1;
-                        presto_put_permit(inode);
-                        return -ENOSPC;
-                }
-                presto_trans_commit(fset, handle); 
-
-                /* cancel the LML record */ 
-                handle = presto_trans_start
-                        (fset, inode, PRESTO_OP_WRITE);
-                if ( IS_ERR(handle) ) {
-                        printk("presto_release: no space for clear\n");
-                        presto_put_permit(inode);
-                        return -ENOSPC;
-                }
-                rc = presto_clear_lml_close(fset,
-                                            fdata->fd_lml_offset); 
-                if (rc < 0 ) { 
-                        /* XXX oops here to get this bug */ 
-                        *(int *)0 = 1;
-                        presto_put_permit(inode);
-                        printk("presto_close: cannot journal close\n");
-                        return -ENOSPC;
-                }
-                presto_trans_commit(fset, handle); 
-                presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
-
-                presto_truncate_lml(fset);
-
+                fdata->fd_info.updated_time = file->f_dentry->d_inode->i_mtime;
+                rc = presto_do_close(fset, file); 
                 presto_put_permit(inode);
         }
 
         if (!rc && fdata) {
                 PRESTO_FREE(fdata, sizeof(*fdata));
+                file->private_data = NULL; 
         }
-        file->private_data = NULL; 
         
         EXIT;
         return rc;
 }
 
-
-
-static void presto_apply_write_policy(struct file *file, struct presto_file_set *fset, loff_t res)
+static void presto_apply_write_policy(struct file *file,
+                                      struct presto_file_set *fset, loff_t res)
 {
-        struct presto_file_data *fdata = (struct presto_file_data *)file->private_data;
+        struct presto_file_data *fdata =
+                (struct presto_file_data *)file->private_data;
         struct presto_cache *cache = fset->fset_cache;
         struct presto_version new_file_ver;
         int error;
@@ -285,40 +322,44 @@
          journaling in a thread, add more options etc.)
         */ 
  
-         if (  (fset->fset_flags & FSET_JCLOSE_ON_WRITE)
-                 && (!ISLENTO(cache->cache_psdev->uc_minor)))  {
-                 fdata->fd_bytes_written += res;
+        if ((fset->fset_flags & FSET_JCLOSE_ON_WRITE) &&
+            (!ISLENTO(cache->cache_psdev->uc_minor))) {
+                fdata->fd_bytes_written += res;
  
-                 if (fdata->fd_bytes_written >= fset->fset_file_maxio) {
-                         presto_getversion(&new_file_ver, file->f_dentry->d_inode);
+                if (fdata->fd_bytes_written >= fset->fset_file_maxio) {
+                        presto_getversion(&new_file_ver,
+                                          file->f_dentry->d_inode);
                         /* This is really heavy weight and should be fixed
                            ASAP. At most we should be recording the number
                            of bytes written and not locking the kernel, 
                            wait for permits, etc, on the write path. SHP
                         */
                         lock_kernel();
-                         if ( presto_get_permit(file->f_dentry->d_inode) < 0 ) {
-                                 EXIT;
-                                 /* we must be disconnected, not to worry */
+                        if ( presto_get_permit(file->f_dentry->d_inode) < 0 ) {
+                                EXIT;
+                                /* we must be disconnected, not to worry */
+                                unlock_kernel();
                                 return; 
-                         }
-                         error = presto_journal_close
-                                (&rec, fset, file, file->f_dentry, &new_file_ver);
-                         presto_put_permit(file->f_dentry->d_inode);
+                        }
+                        error = presto_journal_close(&rec, fset, file,
+                                                     file->f_dentry,
+                                                     &fdata->fd_version,
+                                                     &new_file_ver);
+                        presto_put_permit(file->f_dentry->d_inode);
                         unlock_kernel();
-                         if ( error ) {
-                                 printk("presto_close: cannot journal close\n");
-                                 /* XXX these errors are really bad */
+                        if ( error ) {
+                                CERROR("presto_close: cannot journal close\n");
+                                /* XXX these errors are really bad */
                                 /* panic(); */
-                                 return;
-                         }
-                             fdata->fd_bytes_written = 0;
-                     } 
+                                return;
+                        }
+                        fdata->fd_bytes_written = 0;
+                }
         }
 }
 
-static ssize_t presto_file_write(struct file *file, const char *buf, size_t size, 
-                          loff_t *off)
+static ssize_t presto_file_write(struct file *file, const char *buf,
+                                 size_t size, loff_t *off)
 {
         struct rec_info rec;
         int error;
@@ -344,83 +385,155 @@
                 << file->f_dentry->d_inode->i_sb->s_blocksize_bits);
 
         error = presto_reserve_space(fset->fset_cache, res_size); 
-        CDEBUG(D_INODE, "Reserved %Ld for %Zd\n", res_size, size); 
+        CDEBUG(D_INODE, "Reserved %Ld for %d\n", res_size, size); 
         if ( error ) { 
                 EXIT;
                 return -ENOSPC;
         }
 
-        /* XXX lock something here */
-        CDEBUG(D_INODE, "islento %d, minor: %d\n", ISLENTO(cache->cache_psdev->uc_minor),
+        CDEBUG(D_INODE, "islento %d, minor: %d\n", 
+               ISLENTO(cache->cache_psdev->uc_minor),
                cache->cache_psdev->uc_minor); 
+
+        /* 
+         *  XXX this lock should become a per inode lock when 
+         *  Vinny's changes are in; we could just use i_sem.
+         */
         read_lock(&fset->fset_lml.fd_lock); 
         fdata = (struct presto_file_data *)file->private_data;
-        do_lml_here = (!ISLENTO(cache->cache_psdev->uc_minor)) &&
-                size && (fdata->fd_do_lml == 0);
+        do_lml_here = size && (fdata->fd_do_lml == 0) &&
+                !presto_chk(file->f_dentry, PRESTO_DONT_JOURNAL);
 
         if (do_lml_here)
                 fdata->fd_do_lml = 1;
         read_unlock(&fset->fset_lml.fd_lock); 
 
-        /* XXX we have two choices:
-           - we do the transaction for the LML record BEFORE any write
-           transaction starts - that has the benefit that no other
-           short write can complete without the record being there. 
-           The disadvantage is that even if no write happens we get 
-           the LML record. 
-           - we bundle the transaction with this write.  In that case
-           we may not have an LML record is a short write goes through
-           before this one (can that actually happen?).
+        /* XXX 
+           There might be a bug here.  We need to make 
+           absolutely sure that the ext3_file_write commits 
+           after our transaction that writes the LML record.
+           Nesting the file write helps if new blocks are allocated. 
         */
         res = 0;
         if (do_lml_here) {
+                struct presto_version file_version;
                 /* handle different space reqs from file system below! */
                 handle = presto_trans_start(fset, file->f_dentry->d_inode, 
-                                            PRESTO_OP_WRITE);
+                                            KML_OPCODE_WRITE);
                 if ( IS_ERR(handle) ) {
                         presto_release_space(fset->fset_cache, res_size); 
-                        printk("presto_write: no space for transaction\n");
+                        CERROR("presto_write: no space for transaction\n");
                         return -ENOSPC;
                 }
-                res = presto_journal_write(&rec, fset, file);
+
+                presto_getversion(&file_version, file->f_dentry->d_inode); 
+                res = presto_write_lml_close(&rec, fset, file, 
+                                             fdata->fd_info.remote_ino, 
+                                             fdata->fd_info.remote_generation, 
+                                             &fdata->fd_info.remote_version, 
+                                             &file_version);
                 fdata->fd_lml_offset = rec.offset;
                 if ( res ) {
-                        /* XXX oops here to get this bug */ 
-                        /* *(int *)0 = 1; */
+                        CERROR("intermezzo: PANIC failed to write LML\n");
+                        *(int *)0 = 1;
                         EXIT;
                         goto exit_write;
                 }
-                
                 presto_trans_commit(fset, handle);
         }
 
         fops = filter_c2cffops(cache->cache_filter);
         res = fops->write(file, buf, size, off);
         if ( res != size ) {
-                CDEBUG(D_FILE, "file write returns short write: size %Zd, res %Zd\n", size, res); 
+                CDEBUG(D_FILE, "file write returns short write: size %d, res %d\n", size, res); 
         }
 
         if ( (res > 0) && fdata ) 
                  presto_apply_write_policy(file, fset, res);
-  
+
  exit_write:
         presto_release_space(fset->fset_cache, res_size); 
         return res;
 }
 
 struct file_operations presto_file_fops = {
-        write:   presto_file_write,
-        open:    presto_file_open,
-        release: presto_file_release
+        .write   = presto_file_write,
+        .open    = presto_file_open,
+        .release = presto_file_release,
+        .ioctl   = presto_ioctl
 };
 
 struct inode_operations presto_file_iops = {
-        permission: presto_permission,
-	setattr: presto_setattr,
+        .permission   = presto_permission,
+        .setattr      = presto_setattr,
 #ifdef CONFIG_FS_EXT_ATTR
-	set_ext_attr: presto_set_ext_attr,
+        .set_ext_attr = presto_set_ext_attr,
 #endif
 };
 
+/* FIXME: I bet we want to add a lock here and in presto_file_open. */
+int izo_purge_file(struct presto_file_set *fset, char *file)
+{
+#if 0
+        void *handle = NULL;
+        char *path = NULL;
+        struct nameidata nd;
+        struct dentry *dentry;
+        int rc = 0, len;
+        loff_t oldsize;
+
+        /* FIXME: not mtpt it's gone */
+        len = strlen(fset->fset_cache->cache_mtpt) + strlen(file) + 1;
+        PRESTO_ALLOC(path, len + 1);
+        if (path == NULL)
+                return -1;
+
+        sprintf(path, "%s/%s", fset->fset_cache->cache_mtpt, file);
+        rc = izo_lookup_file(fset, path, &nd);
+        if (rc)
+                goto error;
+        dentry = nd.dentry;
+
+        /* FIXME: take a lock here */
+
+        if (dentry->d_inode->i_atime > CURRENT_TIME - 5) {
+                /* We lost the race; this file was accessed while we were doing
+                 * ioctls and lookups and whatnot. */
+                rc = -EBUSY;
+                goto error_unlock;
+        }
+
+        /* FIXME: Check if this file is open. */
+
+        handle = presto_trans_start(fset, dentry->d_inode, KML_OPCODE_TRUNC);
+        if (IS_ERR(handle)) {
+                rc = -ENOMEM;
+                goto error_unlock;
+        }
+
+        /* FIXME: Write LML record */
+
+        oldsize = dentry->d_inode->i_size;
+        rc = izo_do_truncate(fset, dentry, 0, oldsize);
+        if (rc != 0)
+                goto error_clear;
+        rc = izo_do_truncate(fset, dentry, oldsize, 0);
+        if (rc != 0)
+                goto error_clear;
 
+ error_clear:
+        /* FIXME: clear LML record */
 
+ error_unlock:
+        /* FIXME: release the lock here */
+
+ error:
+        if (handle != NULL && !IS_ERR(handle))
+                presto_trans_commit(fset, handle);
+        if (path != NULL)
+                PRESTO_FREE(path, len + 1);
+        return rc;
+#else
+        return 0;
+#endif
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/fileset.c linux.20pre10-ac2/fs/intermezzo/fileset.c
--- linux.20pre10/fs/intermezzo/fileset.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/fileset.c	2002-10-10 23:24:51.000000000 +0100
@@ -0,0 +1,675 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Managing filesets
+ *
+ */
+
+#define __NO_VERSION__
+#include <stdarg.h>
+
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <linux/intermezzo_fs.h>
+#include <linux/intermezzo_psdev.h>
+
+static inline struct presto_file_set *presto_dentry2fset(struct dentry *dentry)
+{
+        if (presto_d2d(dentry) == NULL) {
+                EXIT;
+                return NULL;
+        }
+        return presto_d2d(dentry)->dd_fset;
+}
+
+/* find the fileset dentry for this dentry */
+struct presto_file_set *presto_fset(struct dentry *de)
+{
+        struct dentry *fsde;
+        ENTRY;
+        if ( !de->d_inode ) {
+                /* FIXME: is this ok to be NULL? */
+                CDEBUG(D_INODE,"presto_fset: warning %*s has NULL inode.\n",
+                de->d_name.len, de->d_name.name);
+        }
+        for (fsde = de;; fsde = fsde->d_parent) {
+                if ( presto_dentry2fset(fsde) ) {
+                        EXIT;
+                        return presto_dentry2fset(fsde);
+                }
+                if (fsde->d_parent == fsde)
+                        break;
+        }
+        EXIT;
+        return NULL;
+}
+
+int presto_get_lastrecno(char *path, off_t *recno)
+{
+        struct nameidata nd; 
+        struct presto_file_set *fset;
+        struct dentry *dentry;
+        int error;
+        ENTRY;
+
+        error = presto_walk(path, &nd);
+        if (error) {
+                EXIT;
+                return error;
+        }
+
+        dentry = nd.dentry;
+
+        error = -ENXIO;
+        if ( !presto_ispresto(dentry->d_inode) ) {
+                EXIT;
+                goto kml_out;
+        }
+
+        error = -EINVAL;
+        if ( ! presto_dentry2fset(dentry)) {
+                EXIT;
+                goto kml_out;
+        }
+
+        fset = presto_dentry2fset(dentry);
+        if (!fset) {
+                EXIT;
+                goto kml_out;
+        }
+        error = 0;
+        *recno = fset->fset_kml.fd_recno;
+
+ kml_out:
+        path_release(&nd);
+        return error;
+}
+
+static char * _izo_make_path(char *fsetname, char *name)
+{
+        char *path = NULL;
+        int len;
+
+        len = strlen("/.intermezzo/") + strlen(fsetname) 
+                + 1 + strlen(name) + 1;
+
+        PRESTO_ALLOC(path, len);
+        if (path == NULL)
+                return NULL;
+
+        sprintf(path, "/.intermezzo/%s/%s", fsetname, name);
+
+        return path;
+}
+
+char * izo_make_path(struct presto_file_set *fset, char *name)
+{
+        return _izo_make_path(fset->fset_name, name);
+}
+
+static struct file *_izo_fset_open(char *fsetname, char *name, int flags, int mode) 
+{
+        char *path;
+        struct file *f;
+        int error;
+        ENTRY;
+
+        path = _izo_make_path(fsetname, name);
+        if (path == NULL) {
+                EXIT;
+                return ERR_PTR(-ENOMEM);
+        }
+
+        CDEBUG(D_INODE, "opening file %s\n", path);
+        f = filp_open(path, flags, mode);
+        error = PTR_ERR(f);
+        if (IS_ERR(f)) {
+                CDEBUG(D_INODE, "Error %d\n", error);
+        }
+
+        PRESTO_FREE(path, strlen(path));
+
+        EXIT;
+        return f;
+
+}
+
+struct file *izo_fset_open(struct presto_file_set *fset, char *name, int flags, int mode) 
+{
+        return _izo_fset_open(fset->fset_name, name, flags, mode);
+}
+
+
+
+/*
+ *  note: this routine "pins" a dentry for a fileset root
+ */
+int presto_set_fsetroot(struct dentry *ioctl_dentry, char *fsetname,
+                        unsigned int flags)
+{
+        struct presto_file_set *fset = NULL;
+        struct presto_cache *cache;
+        int error;
+        struct file  *fset_root;
+        struct dentry *dentry;
+
+        ENTRY;
+
+        fset_root = _izo_fset_open(fsetname, "ROOT",  O_RDONLY, 000);
+        if (IS_ERR(fset_root)) {
+                CERROR("Can't open %s/ROOT\n", fsetname);
+                EXIT;
+                error = PTR_ERR(fset_root);
+                goto out;
+        }
+        dentry = dget(fset_root->f_dentry);
+        filp_close(fset_root, NULL);
+
+        dentry->d_inode->i_op = ioctl_dentry->d_inode->i_op;
+        dentry->d_inode->i_fop = ioctl_dentry->d_inode->i_fop;
+        dentry->d_op = ioctl_dentry->d_op;
+        fset = presto_dentry2fset(dentry);
+        if (fset && (fset->fset_dentry == dentry) ) { 
+                CERROR("Fsetroot already set (inode %ld)\n",
+                       dentry->d_inode->i_ino);
+                /* XXX: ignore because clear_fsetroot is broken  */
+#if 0
+                dput(dentry);
+                EXIT;
+                error = -EEXIST;
+                goto out;
+#endif
+        }
+
+        cache = presto_get_cache(dentry->d_inode);
+        if (!cache) { 
+                CERROR("No cache found for inode %ld\n",
+                       dentry->d_inode->i_ino);
+                EXIT;
+                error = -ENODEV;
+                goto out_free;
+        }
+
+        PRESTO_ALLOC(fset, sizeof(*fset));
+        if ( !fset ) {
+                CERROR("No memory allocating fset for %s\n", fsetname);
+                EXIT;
+                error = -ENOMEM;
+                goto out_free;
+        }
+        CDEBUG(D_INODE, "fset at %p\n", fset);
+
+        CDEBUG(D_INODE, "InterMezzo: fsetroot: inode %ld, fileset name %s\n",
+               dentry->d_inode->i_ino, fsetname);
+
+        fset->fset_mnt = mntget(current->fs->pwdmnt); 
+        fset->fset_cache = cache;
+        fset->fset_dentry = dentry; 
+        fset->fset_name = strdup(fsetname);
+        fset->fset_chunkbits = CHUNK_BITS;
+        fset->fset_flags = flags;
+        fset->fset_file_maxio = FSET_DEFAULT_MAX_FILEIO; 
+        fset->fset_permit_lock = SPIN_LOCK_UNLOCKED;
+        PRESTO_ALLOC(fset->fset_reint_buf, 64 * 1024);
+        if (fset->fset_reint_buf == NULL) {
+                EXIT;
+                error = -ENOMEM;
+                goto out_free;
+        }
+        init_waitqueue_head(&fset->fset_permit_queue);
+
+        if (presto_d2d(dentry) == NULL) { 
+                dentry->d_fsdata = izo_alloc_ddata();
+        }
+        if (presto_d2d(dentry) == NULL) {
+                CERROR("InterMezzo: %s: no memory\n", __FUNCTION__);
+                EXIT;
+                error = -ENOMEM;
+                goto out_free;
+        }
+        presto_d2d(dentry)->dd_fset = fset;
+        list_add(&fset->fset_list, &cache->cache_fset_list);
+
+        error = izo_init_kml_file(fset, &fset->fset_kml);
+        if ( error ) {
+                EXIT;
+                CDEBUG(D_JOURNAL, "Error init_kml %d\n", error);
+                goto out_list_del;
+        }
+
+        error = izo_init_lml_file(fset, &fset->fset_lml);
+        if ( error ) {
+                int rc;
+                EXIT;
+                rc = izo_log_close(&fset->fset_kml);
+                CDEBUG(D_JOURNAL, "Error init_lml %d, cleanup %d\n", error, rc);
+                goto out_list_del;
+        }
+
+        /* init_last_rcvd_file could trigger a presto_file_write(), which
+         * requires that the lml structure be initialized. -phil */
+        error = izo_init_last_rcvd_file(fset, &fset->fset_rcvd);
+        if ( error ) {
+                int rc;
+                EXIT;
+                rc = izo_log_close(&fset->fset_kml);
+                rc = izo_log_close(&fset->fset_lml);
+                CDEBUG(D_JOURNAL, "Error init_lastrcvd %d, cleanup %d\n", error, rc);
+                goto out_list_del;
+        }
+
+        CDEBUG(D_PIOCTL, "-------> fset at %p, dentry at %p, mtpt %p,"
+               "fset %s, cache %p, presto_d2d(dentry)->dd_fset %p\n",
+               fset, dentry, fset->fset_dentry, fset->fset_name, cache,
+               presto_d2d(dentry)->dd_fset);
+
+        EXIT;
+        return 0;
+
+ out_list_del:
+        list_del(&fset->fset_list);
+        presto_d2d(dentry)->dd_fset = NULL;
+ out_free:
+        if (fset) {
+                mntput(fset->fset_mnt); 
+                if (fset->fset_reint_buf != NULL)
+                        PRESTO_FREE(fset->fset_reint_buf, 64 * 1024);
+                PRESTO_FREE(fset, sizeof(*fset));
+        }
+        dput(dentry); 
+ out:
+        return error;
+}
+
+static int izo_cleanup_fset(struct presto_file_set *fset)
+{
+        int error;
+        struct presto_cache *cache;
+
+        ENTRY;
+
+        CERROR("Cleaning up fset %s\n", fset->fset_name);
+
+        error = izo_log_close(&fset->fset_kml);
+        if (error)
+                CERROR("InterMezzo: Closing kml for fset %s: %d\n",
+                       fset->fset_name, error);
+        error = izo_log_close(&fset->fset_lml);
+        if (error)
+                CERROR("InterMezzo: Closing lml for fset %s: %d\n",
+                       fset->fset_name, error);
+        error = izo_log_close(&fset->fset_rcvd);
+        if (error)
+                CERROR("InterMezzo: Closing last_rcvd for fset %s: %d\n",
+                       fset->fset_name, error);
+
+        cache = fset->fset_cache;
+
+        list_del(&fset->fset_list);
+
+        presto_d2d(fset->fset_dentry)->dd_fset = NULL;
+        dput(fset->fset_dentry);
+        mntput(fset->fset_mnt);
+
+        PRESTO_FREE(fset->fset_name, strlen(fset->fset_name) + 1);
+        PRESTO_FREE(fset->fset_reint_buf, 64 * 1024);
+        PRESTO_FREE(fset, sizeof(*fset));
+        EXIT;
+        return error;
+}
+
+int izo_clear_fsetroot(struct dentry *dentry)
+{
+        struct presto_file_set *fset;
+
+        ENTRY;
+
+        fset = presto_dentry2fset(dentry);
+        if (!fset) {
+                EXIT;
+                return -EINVAL;
+        }
+
+        izo_cleanup_fset(fset);
+        EXIT;
+        return 0;
+}
+
+int izo_clear_all_fsetroots(struct presto_cache *cache)
+{
+        struct presto_file_set *fset;
+        struct list_head *tmp,*tmpnext;
+        int error;
+ 
+        error = 0;
+        tmp = &cache->cache_fset_list;
+        tmpnext = tmp->next;
+        while ( tmpnext != &cache->cache_fset_list) {
+                tmp = tmpnext;
+                tmpnext = tmp->next;
+                fset = list_entry(tmp, struct presto_file_set, fset_list);
+
+                error = izo_cleanup_fset(fset);
+                if (error)
+                        break;
+        }
+        return error;
+}
+
+static struct vfsmount *izo_alloc_vfsmnt(void)
+{
+        struct vfsmount *mnt;
+        PRESTO_ALLOC(mnt, sizeof(*mnt));
+        if (mnt) {
+                memset(mnt, 0, sizeof(struct vfsmount));
+                atomic_set(&mnt->mnt_count,1);
+                INIT_LIST_HEAD(&mnt->mnt_hash);
+                INIT_LIST_HEAD(&mnt->mnt_child);
+                INIT_LIST_HEAD(&mnt->mnt_mounts);
+                INIT_LIST_HEAD(&mnt->mnt_list);
+        }
+        return mnt;
+}
+
+
+static void izo_setup_ctxt(struct dentry *root, struct vfsmount *mnt,
+                           struct run_ctxt *save) 
+{
+        struct run_ctxt new;
+
+        mnt->mnt_root = root;
+        mnt->mnt_sb = root->d_inode->i_sb;
+        unlock_super(mnt->mnt_sb);
+
+        new.rootmnt = mnt;
+        new.root = root;
+        new.pwdmnt = mnt;
+        new.pwd = root;
+        new.fsuid = 0;
+        new.fsgid = 0;
+        new.fs = get_fs(); 
+        /* XXX where can we get the groups from? */
+        new.ngroups = 0;
+
+        push_ctxt(save, &new); 
+}
+
+static void izo_cleanup_ctxt(struct vfsmount *mnt, struct run_ctxt *save) 
+{
+        lock_super(mnt->mnt_sb);
+        pop_ctxt(save); 
+}
+
+static int izo_simple_mkdir(struct dentry *dir, char *name, int mode)
+{
+        struct dentry *dchild; 
+        int err;
+        ENTRY;
+        
+        dchild = lookup_one_len(name, dir, strlen(name));
+        if (IS_ERR(dchild)) { 
+                EXIT;
+                return PTR_ERR(dchild); 
+        }
+
+        if (dchild->d_inode) { 
+                dput(dchild);
+                EXIT;
+                return -EEXIST;
+        }
+
+        err = vfs_mkdir(dir->d_inode, dchild, mode);
+        dput(dchild);
+        
+        EXIT;
+        return err;
+}
+
+static int izo_simple_symlink(struct dentry *dir, char *name, char *tgt)
+{
+        struct dentry *dchild; 
+        int err;
+        ENTRY;
+        
+        dchild = lookup_one_len(name, dir, strlen(name));
+        if (IS_ERR(dchild)) { 
+                EXIT;
+                return PTR_ERR(dchild); 
+        }
+
+        if (dchild->d_inode) { 
+                dput(dchild);
+                EXIT;
+                return -EEXIST;
+        }
+
+        err = vfs_symlink(dir->d_inode, dchild, tgt);
+        dput(dchild);
+        
+        EXIT;
+        return err;
+}
+
+/*
+ * run set_fsetroot in chroot environment
+ */
+int presto_set_fsetroot_from_ioc(struct dentry *root, char *fsetname,
+                                 unsigned int flags)
+{
+        int rc;
+        struct presto_cache *cache;
+        struct vfsmount *mnt;
+        struct run_ctxt save;
+
+        if (root != root->d_inode->i_sb->s_root) {
+                CERROR ("IOC_SET_FSET must be called on mount point\n");
+                return -ENODEV;
+        }
+
+        cache = presto_get_cache(root->d_inode);
+        mnt = cache->cache_vfsmount;
+        if (!mnt) { 
+                EXIT;
+                return -ENOMEM;
+        }
+        
+        izo_setup_ctxt(root, mnt, &save); 
+        rc = presto_set_fsetroot(root, fsetname, flags);
+        izo_cleanup_ctxt(mnt, &save);
+        return rc;
+}
+
+/* XXX: this function should detect if fsetname is already in use for
+   the cache under root
+*/ 
+int izo_prepare_fileset(struct dentry *root, char *fsetname) 
+{
+        int err;
+        struct dentry *dotizo = NULL, *fsetdir = NULL, *dotiopen = NULL; 
+        struct presto_cache *cache;
+        struct vfsmount *mnt;
+        struct run_ctxt save;
+
+        cache = presto_get_cache(root->d_inode);
+        mnt = cache->cache_vfsmount = izo_alloc_vfsmnt();
+        if (!mnt) { 
+                EXIT;
+                return -ENOMEM;
+        }
+        
+        if (!fsetname) 
+                fsetname = "rootfset"; 
+
+        izo_setup_ctxt(root, mnt, &save); 
+
+        err = izo_simple_mkdir(root, ".intermezzo", 0755);
+        CDEBUG(D_CACHE, "mkdir on .intermezzo err %d\n", err); 
+
+        err = izo_simple_mkdir(root, "..iopen..", 0755);
+        CDEBUG(D_CACHE, "mkdir on ..iopen.. err %d\n", err); 
+
+        dotiopen = lookup_one_len("..iopen..", root, strlen("..iopen.."));
+        if (IS_ERR(dotiopen)) { 
+                EXIT;
+                goto out;
+        }
+        dotiopen->d_inode->i_op = &presto_dir_iops;
+        dput(dotiopen);
+
+
+        dotizo = lookup_one_len(".intermezzo", root, strlen(".intermezzo"));
+        if (IS_ERR(dotizo)) { 
+                EXIT;
+                goto out;
+        }
+
+
+        err = izo_simple_mkdir(dotizo, fsetname, 0755);
+        CDEBUG(D_CACHE, "mkdir err %d\n", err); 
+
+        /* XXX find the dentry of the root of the fileset (root for now) */ 
+        fsetdir = lookup_one_len(fsetname, dotizo, strlen(fsetname));
+        if (IS_ERR(fsetdir)) { 
+                EXIT;
+                goto out;
+        }
+
+        err = izo_simple_symlink(fsetdir, "ROOT", "../.."); 
+
+        /* XXX read flags from flags file */ 
+        err =  presto_set_fsetroot(root, fsetname, 0); 
+        CDEBUG(D_CACHE, "set_fsetroot err %d\n", err); 
+
+ out:
+        if (dotizo && !IS_ERR(dotizo)) 
+                dput(dotizo); 
+        if (fsetdir && !IS_ERR(fsetdir)) 
+                dput(fsetdir); 
+        izo_cleanup_ctxt(mnt, &save);
+        return err; 
+}
+
+int izo_set_fileid(struct file *dir, struct izo_ioctl_data *data)
+{
+        int rc = 0;
+        struct presto_cache *cache;
+        struct vfsmount *mnt;
+        struct run_ctxt save;
+        struct nameidata nd;
+        struct dentry *dentry;
+        struct presto_dentry_data *dd;
+        struct dentry *root;
+        char *buf = NULL; 
+
+        ENTRY;
+
+
+        root = dir->f_dentry;
+
+        /* actually, needs to be called on ROOT of fset, not mount point  
+        if (root != root->d_inode->i_sb->s_root) {
+                CERROR ("IOC_SET_FSET must be called on mount point\n");
+                return -ENODEV;
+        }
+        */
+
+        cache = presto_get_cache(root->d_inode);
+        mnt = cache->cache_vfsmount;
+        if (!mnt) { 
+                EXIT;
+                return -ENOMEM;
+        }
+        
+        izo_setup_ctxt(root, mnt, &save); 
+        
+        PRESTO_ALLOC(buf, data->ioc_plen1);
+        if (!buf) { 
+                rc = -ENOMEM;
+                EXIT;
+                goto out;
+        }
+        if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) { 
+                rc =  -EFAULT;
+                EXIT;
+                goto out;
+        }
+
+        rc = presto_walk(buf, &nd);
+        if (rc) {
+                CERROR("Unable to open: %s\n", buf);
+                EXIT;
+                goto out;
+        }
+        dentry = nd.dentry;
+        if (!dentry) {
+                CERROR("no dentry!\n");
+                rc =  -EINVAL;
+                EXIT;
+                goto out_close;
+        }
+        dd = presto_d2d(dentry);
+        if (!dd) {
+                CERROR("no dentry_data!\n");
+                rc = -EINVAL;
+                EXIT;
+                goto out_close;
+        }
+
+        CDEBUG(D_FILE,"de:%p dd:%p\n", dentry, dd);
+
+        if (dd->remote_ino != 0) {
+                CERROR("remote_ino already set? %Lx:%Lx\n", dd->remote_ino,
+                       dd->remote_generation);
+                rc = 0;
+                EXIT;
+                goto out_close;
+        }
+
+
+        CDEBUG(D_FILE,"setting %p %p, %s to %Lx:%Lx\n", dentry, dd, 
+               buf, data->ioc_ino,
+               data->ioc_generation);
+        dd->remote_ino = data->ioc_ino;
+        dd->remote_generation = data->ioc_generation;
+
+        EXIT;
+ out_close:
+        path_release(&nd);
+ out:
+        if (buf)
+                PRESTO_FREE(buf, data->ioc_plen1);
+        izo_cleanup_ctxt(mnt, &save);
+        return rc;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/inode.c linux.20pre10-ac2/fs/intermezzo/inode.c
--- linux.20pre10/fs/intermezzo/inode.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/inode.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,11 +1,27 @@
-/*
- * Super block/filesystem wide operations
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk> and
+ *    Michael Callahan <callahan@maths.ox.ac.uk>
+ *  Copyright (C) 1999 Carnegie Mellon University
+ *    Rewritten for Linux 2.1.  Peter Braam <braam@cs.cmu.edu>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
  *
- * Copryright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk> and
- * Michael Callahan <callahan@maths.ox.ac.uk>
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
  *
- * Rewritten for Linux 2.1.  Peter Braam <braam@cs.cmu.edu>
- * Copyright (C) Carnegie Mellon University
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Super block/filesystem wide operations
  */
 
 #define __NO_VERSION__
@@ -32,57 +48,45 @@
 #include <asm/segment.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
 
-extern int presto_remount(struct super_block *, int *, char *);
-
-int presto_excluded_gid = PRESTO_EXCL_GID;
-
-extern int presto_prep(struct dentry *, struct presto_cache **,
-                              struct presto_file_set **);
 extern void presto_free_cache(struct presto_cache *);
 
-
 void presto_set_ops(struct inode *inode, struct  filter_fs *filter)
 {
-	ENTRY; 
+        ENTRY; 
+
         if (!inode || is_bad_inode(inode))
                 return;
-	if (inode->i_gid == presto_excluded_gid ) { 
-		EXIT;
-                CDEBUG(D_INODE, "excluded methods for %ld at %p, %p\n",
-                       inode->i_ino, inode->i_op, inode->i_fop);
-		return; 
-	}
+
         if (S_ISREG(inode->i_mode)) {
                 if ( !filter_c2cfiops(filter) ) {
                        filter_setup_file_ops(filter, 
-					     inode, &presto_file_iops,
-					     &presto_file_fops);
+                                             inode, &presto_file_iops,
+                                             &presto_file_fops);
                 }
-		inode->i_op = filter_c2ufiops(filter);
-		inode->i_fop = filter_c2uffops(filter);
+                inode->i_op = filter_c2ufiops(filter);
+                inode->i_fop = filter_c2uffops(filter);
                 CDEBUG(D_INODE, "set file methods for %ld to %p\n",
                        inode->i_ino, inode->i_op);
         } else if (S_ISDIR(inode->i_mode)) {
-		inode->i_op = filter_c2udiops(filter);
-		inode->i_fop = filter_c2udfops(filter);
-                CDEBUG(D_INODE, "set dir methods for %ld to %p lookup %p\n",
-                       inode->i_ino, inode->i_op, inode->i_op->lookup);
+                inode->i_op = filter_c2udiops(filter);
+                inode->i_fop = filter_c2udfops(filter);
+                CDEBUG(D_INODE, "set dir methods for %ld to %p ioctl %p\n",
+                       inode->i_ino, inode->i_op, inode->i_fop->ioctl);
         } else if (S_ISLNK(inode->i_mode)) {
                 if ( !filter_c2csiops(filter)) {
                         filter_setup_symlink_ops(filter, 
                                                  inode,
                                                  &presto_sym_iops, 
-						 &presto_sym_fops);
+                                                 &presto_sym_fops);
                 }
-		inode->i_op = filter_c2usiops(filter);
-		inode->i_fop = filter_c2usfops(filter);
+                inode->i_op = filter_c2usiops(filter);
+                inode->i_fop = filter_c2usfops(filter);
                 CDEBUG(D_INODE, "set link methods for %ld to %p\n",
                        inode->i_ino, inode->i_op);
         }
-	EXIT;
+        EXIT;
 }
 
 void presto_read_inode(struct inode *inode)
@@ -91,7 +95,7 @@
 
         cache = presto_get_cache(inode);
         if ( !cache ) {
-                printk("PRESTO: BAD, BAD: cannot find cache\n");
+                CERROR("PRESTO: BAD, BAD: cannot find cache\n");
                 make_bad_inode(inode);
                 return ;
         }
@@ -99,37 +103,52 @@
         filter_c2csops(cache->cache_filter)->read_inode(inode);
 
         CDEBUG(D_INODE, "presto_read_inode: ino %ld, gid %d\n", 
-	       inode->i_ino, inode->i_gid);
-
-	//        if (inode->i_gid == presto_excluded_gid)
-        //       return;
+               inode->i_ino, inode->i_gid);
 
-	presto_set_ops(inode, cache->cache_filter); 
+        presto_set_ops(inode, cache->cache_filter); 
         /* XXX handle special inodes here or not - probably not? */
 }
 
-void presto_put_super(struct super_block *sb)
+static void presto_put_super(struct super_block *sb)
 {
         struct presto_cache *cache;
-        struct upc_comm *psdev;
+        struct upc_channel *channel;
         struct super_operations *sops;
         struct list_head *lh;
+        int err;
 
-	ENTRY;
-        cache = presto_find_cache(sb->s_dev);
+        ENTRY;
+        cache = presto_cache_find(sb->s_dev);
         if (!cache) {
-		EXIT;
+                EXIT;
                 goto exit;
-	}
-        psdev = &upc_comms[presto_c2m(cache)];
-
+        }
+        channel = &izo_channels[presto_c2m(cache)];
         sops = filter_c2csops(cache->cache_filter);
+        err = izo_clear_all_fsetroots(cache); 
+        if (err) { 
+                CERROR("%s: err %d\n", __FUNCTION__, err);
+        }
+        PRESTO_FREE(cache->cache_vfsmount, sizeof(struct vfsmount));
+
+        /* look at kill_super - fsync_super is not exported GRRR but 
+           probably not needed */ 
+        unlock_super(sb);
+        shrink_dcache_parent(cache->cache_root); 
+        dput(cache->cache_root); 
+        //fsync_super(sb); 
+        lock_super(sb);
+
+        if (sops->write_super)
+                sops->write_super(sb); 
+
         if (sops->put_super)
                 sops->put_super(sb);
 
         /* free any remaining async upcalls when the filesystem is unmounted */
-        lh = psdev->uc_pending.next;
-        while ( lh != &psdev->uc_pending) {
+        spin_lock(&channel->uc_lock);
+        lh = channel->uc_pending.next;
+        while ( lh != &channel->uc_pending) {
                 struct upc_req *req;
                 req = list_entry(lh, struct upc_req, rq_chain);
 
@@ -141,6 +160,8 @@
                 PRESTO_FREE(req->rq_data, req->rq_bufsize);
                 PRESTO_FREE(req, sizeof(struct upc_req));
         }
+        list_del(&cache->cache_channel_list); 
+        spin_unlock(&channel->uc_lock);
 
         presto_free_cache(cache);
 
@@ -151,18 +172,16 @@
         return ;
 }
 
+struct super_operations presto_super_ops = {
+        .read_inode    = presto_read_inode,
+        .put_super     = presto_put_super,
+};
+
 
 /* symlinks can be chowned */
 struct inode_operations presto_sym_iops = {
-	setattr:	presto_setattr
+        .setattr       = presto_setattr
 };
 
 /* NULL for now */
 struct file_operations presto_sym_fops; 
-
-struct super_operations presto_super_ops = {
-        read_inode:     presto_read_inode,
-        put_super:      presto_put_super,
-        remount_fs:     presto_remount
-};
-MODULE_LICENSE("GPL");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/journal.c linux.20pre10-ac2/fs/intermezzo/journal.c
--- linux.20pre10/fs/intermezzo/journal.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/journal.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,13 +1,32 @@
-/*
- * Intermezzo. (C) 1998 Peter J. Braam
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam
+ *  Copyright (C) 2001 Cluster File Systems, Inc. 
+ *  Copyright (C) 2001 Tacit Networks, Inc. <phil@off.net>
+ *
+ *  Support for journalling extended attributes
+ *  Copyright (C) 2001 Shirish H. Phatak, Tacit Networks, Inc.
+ * 
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
  *
- * Support for journalling extended attributes
- * (C) 2001 Shirish H. Phatak, Tacit Networks, Inc.
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
@@ -19,15 +38,25 @@
 #include <linux/string.h>
 #include <linux/smp_lock.h>
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 
-static int presto_log(struct presto_file_set *fset, struct rec_info *rec,
-                      const char *buf, size_t size,
-                      const char *string1, int len1, 
-                      const char *string2, int len2,
-                      const char *string3, int len3);
+struct presto_reservation_data {
+        unsigned int ri_recno;
+        loff_t ri_offset;
+        loff_t ri_size;
+        struct list_head ri_list;
+};
+
+/* 
+ *  Locking Semantics
+ * 
+ * write lock in struct presto_log_fd: 
+ *  - name: fd_lock
+ *  - required for: accessing any field in a presto_log_fd 
+ *  - may not be held across I/O
+ *  - 
+ *  
+ */
 
 /*
  *  reserve record space and/or atomically request state of the log
@@ -57,22 +86,25 @@
 
         fd->fd_recno++;
         
-        /* this move the fd_offset back after truncation */ 
+        /* this moves the fd_offset back after truncation */ 
         if ( list_empty(&fd->fd_reservations) && 
              !chunked_record) { 
                 fd->fd_offset = fd->fd_file->f_dentry->d_inode->i_size;
         }
 
         rec->offset = fd->fd_offset;
-        rec->recno = fd->fd_recno;
+        if (rec->is_kml)
+                rec->offset += fset->fset_kml_logical_off;
 
-        fd->fd_offset += rec->size;
+        rec->recno = fd->fd_recno;
 
         /* add the reservation data to the end of the list */
-        list_add(&rd->ri_list, fd->fd_reservations.prev);
-        rd->ri_offset = rec->offset;
+        rd->ri_offset = fd->fd_offset;
         rd->ri_size = rec->size;
         rd->ri_recno = rec->recno; 
+        list_add(&rd->ri_list, fd->fd_reservations.prev);
+
+        fd->fd_offset += rec->size;
 
         write_unlock(&fd->fd_lock); 
 
@@ -87,61 +119,92 @@
         write_unlock(&fd->fd_lock);
 }
 
-static int presto_do_truncate(struct presto_file_set *fset, 
-                              struct dentry *dentry, loff_t length, 
-                              loff_t size_check)
+/* XXX should we ask for do_truncate to be exported? */
+int izo_do_truncate(struct presto_file_set *fset, struct dentry *dentry,
+                    loff_t length,  loff_t size_check)
 {
         struct inode *inode = dentry->d_inode;
-        struct inode_operations *op; 
         int error;
         struct iattr newattrs;
 
         ENTRY;
 
-        /* Not pretty: "inode->i_size" shouldn't really be "loff_t". */
-        if ((off_t) length < 0)
+        if (length < 0) {
+                EXIT;
                 return -EINVAL;
+        }
 
-        fs_down(&inode->i_sem);
+        down(&inode->i_sem);
         lock_kernel();
         
         if (size_check != inode->i_size) { 
                 unlock_kernel();
-                fs_up(&inode->i_sem);
+                up(&inode->i_sem);
                 EXIT;
                 return -EALREADY; 
         }
 
         newattrs.ia_size = length;
         newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
-        op = filter_c2cfiops(fset->fset_cache->cache_filter);
 
-        if (op != NULL && op->setattr != NULL)
-                error = op->setattr(dentry, &newattrs);
+        if (inode->i_op && inode->i_op->setattr)
+                error = inode->i_op->setattr(dentry, &newattrs);
         else {
                 inode_setattr(dentry->d_inode, &newattrs);
-                /* Some filesystems, e.g. ext2 and older versions of ext3
-                   legitimately do not have a <fs>_setattr method. -SHP
-                */
-                /*
-                printk ("Warning:: int presto_do_truncate(xxx), op->setattr == NULL");
-		error = -EOPNOTSUPP; 
-		*/
-		error = 0;
+                error = 0;
         }
+
         unlock_kernel();
-        fs_up(&inode->i_sem);
+        up(&inode->i_sem);
         EXIT;
         return error;
 }
 
+static void presto_kml_truncate(struct presto_file_set *fset)
+{
+        int rc;
+        ENTRY;
+
+        write_lock(&fset->fset_kml.fd_lock);
+        if (fset->fset_kml.fd_truncating == 1 ) {
+                write_unlock(&fset->fset_kml.fd_lock);
+                EXIT;
+                return;
+        }
+
+        fset->fset_kml.fd_truncating = 1;
+        write_unlock(&fset->fset_kml.fd_lock);
+
+        CERROR("islento: %d, count: %d\n",
+               ISLENTO(presto_i2m(fset->fset_dentry->d_inode)),
+               fset->fset_permit_count);
+
+        rc = izo_upc_kml_truncate(fset->fset_cache->cache_psdev->uc_minor,
+                                fset->fset_lento_off, fset->fset_lento_recno,
+                                fset->fset_name);
+
+        /* Userspace is the only permitholder now, and will retain an exclusive
+         * hold on the permit until KML truncation completes. */
+        /* FIXME: double check this code path now that the precise semantics of
+         * fset->fset_permit_count have changed. */
+
+        if (rc != 0) {
+                write_lock(&fset->fset_kml.fd_lock);
+                fset->fset_kml.fd_truncating = 0;
+                write_unlock(&fset->fset_kml.fd_lock);
+        }
+
+        EXIT;
+}
 
 void *presto_trans_start(struct presto_file_set *fset, struct inode *inode,
                          int op)
 {
         ENTRY;
-        if ( !fset->fset_cache->cache_filter->o_trops )
+        if ( !fset->fset_cache->cache_filter->o_trops ) {
+                EXIT;
                 return NULL;
+        }
         EXIT;
         return fset->fset_cache->cache_filter->o_trops->tr_start
                 (fset, inode, op);
@@ -150,28 +213,39 @@
 void presto_trans_commit(struct presto_file_set *fset, void *handle)
 {
         ENTRY;
-        if (!fset->fset_cache->cache_filter->o_trops )
+        if (!fset->fset_cache->cache_filter->o_trops ) {
+                EXIT;
                 return;
-        EXIT;
-        return fset->fset_cache->cache_filter->o_trops->tr_commit(fset, handle);
+        }
+
+        fset->fset_cache->cache_filter->o_trops->tr_commit(fset, handle);
 
+        /* Check to see if the KML needs truncated. */
+        if (fset->kml_truncate_size > 0 &&
+            !fset->fset_kml.fd_truncating &&
+            fset->fset_kml.fd_offset > fset->kml_truncate_size) {
+                CDEBUG(D_JOURNAL, "kml size: %lu; truncating\n",
+                       (unsigned long)fset->fset_kml.fd_offset);
+                presto_kml_truncate(fset);
+        }
+        EXIT;
 }
 
 inline int presto_no_journal(struct presto_file_set *fset)
 {
         int minor = fset->fset_cache->cache_psdev->uc_minor;
-        return upc_comms[minor].uc_no_journal;
+        return izo_channels[minor].uc_no_journal;
 }
 
 #define size_round(x)  (((x)+3) & ~0x3)
 
 #define BUFF_FREE(buf) PRESTO_FREE(buf, PAGE_SIZE)
-#define BUFF_ALLOC(newbuf, oldbuf)                      \
-        PRESTO_ALLOC(newbuf, char *, PAGE_SIZE);        \
-        if ( !newbuf ) {                                \
-                if (oldbuf)                             \
-                        BUFF_FREE(oldbuf);              \
-                return -ENOMEM;                         \
+#define BUFF_ALLOC(newbuf, oldbuf)              \
+        PRESTO_ALLOC(newbuf, PAGE_SIZE);        \
+        if ( !newbuf ) {                        \
+                if (oldbuf)                     \
+                        BUFF_FREE(oldbuf);      \
+                return -ENOMEM;                 \
         }
 
 /*
@@ -234,38 +308,40 @@
                                        __u32 ngroups, gid_t *groups,
                                        __u32 fsuid, __u32 fsgid)
 {
-        struct big_journal_prefix p;
+        struct kml_prefix_hdr p;
+        u32 loggroups[NGROUPS_MAX];
+
         int i; 
 
         p.len = cpu_to_le32(rec->size);
-        p.version = PRESTO_KML_MAJOR_VERSION | PRESTO_KML_MINOR_VERSION;
+        p.version = KML_MAJOR_VERSION | KML_MINOR_VERSION;
         p.pid = cpu_to_le32(current->pid);
-        p.uid = cpu_to_le32(current->uid);
+        p.auid = cpu_to_le32(current->uid);
         p.fsuid = cpu_to_le32(fsuid);
         p.fsgid = cpu_to_le32(fsgid);
         p.ngroups = cpu_to_le32(ngroups);
         p.opcode = cpu_to_le32(opcode);
         for (i=0 ; i < ngroups ; i++)
-                p.groups[i] = cpu_to_le32((__u32) groups[i]);
+                loggroups[i] = cpu_to_le32((__u32) groups[i]);
 
-        buf = logit(buf, &p, sizeof(struct journal_prefix) + 
-                    sizeof(__u32) * ngroups);
+        buf = logit(buf, &p, sizeof(struct kml_prefix_hdr));
+        buf = logit(buf, &loggroups, sizeof(__u32) * ngroups);
         return buf;
 }
 
 static inline char *
 journal_log_prefix(char *buf, int opcode, struct rec_info *rec)
 {
-	__u32 groups[NGROUPS_MAX]; 
-	int i; 
+        __u32 groups[NGROUPS_MAX]; 
+        int i; 
 
-	/* convert 16 bit gid's to 32 bit gid's */
-	for (i=0; i<current->ngroups; i++) 
-		groups[i] = (__u32) current->groups[i];
-	
+        /* convert 16 bit gid's to 32 bit gid's */
+        for (i=0; i<current->ngroups; i++) 
+                groups[i] = (__u32) current->groups[i];
+        
         return journal_log_prefix_with_groups_and_ids(buf, opcode, rec,
                                                       (__u32)current->ngroups,
-						      groups,
+                                                      groups,
                                                       (__u32)current->fsuid,
                                                       (__u32)current->fsgid);
 }
@@ -280,83 +356,86 @@
                                                       (__u32)current->fsgid);
 }
 
-static inline char *log_version(char *buf, struct dentry *dentry)
+static inline char *log_dentry_version(char *buf, struct dentry *dentry)
 {
         struct presto_version version;
 
         presto_getversion(&version, dentry->d_inode);
+        
+        version.pv_mtime = HTON__u64(version.pv_mtime);
+        version.pv_ctime = HTON__u64(version.pv_ctime);
+        version.pv_size = HTON__u64(version.pv_size);
 
         return logit(buf, &version, sizeof(version));
 }
 
+static inline char *log_version(char *buf, struct presto_version *pv)
+{
+        struct presto_version version;
+
+        memcpy(&version, pv, sizeof(version));
+        
+        version.pv_mtime = HTON__u64(version.pv_mtime);
+        version.pv_ctime = HTON__u64(version.pv_ctime);
+        version.pv_size = HTON__u64(version.pv_size);
+
+        return logit(buf, &version, sizeof(version));
+}
+
+static inline char *log_rollback(char *buf, struct izo_rollback_data *rb)
+{
+        struct izo_rollback_data rollback;
+
+        memcpy(&rollback, rb, sizeof(rollback));
+        
+        rollback.rb_mode = HTON__u32(rollback.rb_mode);
+        rollback.rb_rdev = HTON__u32(rollback.rb_rdev);
+        rollback.rb_uid = HTON__u64(rollback.rb_uid);
+        rollback.rb_gid = HTON__u64(rollback.rb_gid);
+
+        return logit(buf, &rollback, sizeof(rollback));
+}
+
 static inline char *journal_log_suffix(char *buf, char *log,
                                        struct presto_file_set *fset,
                                        struct dentry *dentry,
                                        struct rec_info *rec)
 {
-        struct journal_suffix s;
-        struct journal_prefix *p = (struct journal_prefix *)log;
+        struct kml_suffix s;
+        struct kml_prefix_hdr *p = (struct kml_prefix_hdr *)log;
 
 #if 0
-	/* XXX needs to be done after reservation, 
-	   disable ths until version 1.2 */
+        /* XXX needs to be done after reservation, 
+           disable ths until version 1.2 */
         if ( dentry ) { 
-                s.prevrec = cpu_to_le32(rec->offset - dentry->d_time);
-                dentry->d_time = (unsigned long) rec->offset;
+                s.prevrec = cpu_to_le32(rec->offset - 
+                                        presto_d2d(dentry)->dd_kml_offset);
+                presto_d2d(dentry)->dd_kml_offset = rec->offset;
         } else { 
                 s.prevrec = -1;
         }
 #endif
-	s.prevrec = 0; 
+        s.prevrec = 0; 
 
         /* record number needs to be filled in after reservation 
            s.recno = cpu_to_le32(rec->recno); */ 
         s.time = cpu_to_le32(CURRENT_TIME);
-        s.len = cpu_to_le32(p->len);
+        s.len = p->len;
         return logit(buf, &s, sizeof(s));
 }
 
-int presto_close_journal_file(struct presto_file_set *fset)
+int izo_log_close(struct presto_log_fd *logfd)
 {
         int rc = 0;
-        int rc2 = 0;
-        int rc3 = 0;
 
-        ENTRY;
-        if ( fset->fset_kml.fd_file) {
-                rc =filp_close(fset->fset_kml.fd_file, 0);
-                fset->fset_kml.fd_file = NULL;
-        } else {
-                printk("hehehehe no filp\n");
-        }
-        if ( rc ) {
-                printk("presto: close files: kml filp won't close %d\n", rc);
-        }
-
-        if ( fset->fset_last_rcvd) {
-                rc2 = filp_close(fset->fset_last_rcvd, 0);
-                fset->fset_last_rcvd = NULL;
-        } else {
-                printk("hehehehe no filp\n");
-        }
-
-        if ( rc2 ) {
-                if ( !rc )
-                        rc = rc2;
-                printk("presto: close files: last_rcvd filp won't close %d\n", rc2);
-        }
+        if (logfd->fd_file) {
+                rc = filp_close(logfd->fd_file, 0);
+                logfd->fd_file = NULL;
+        } else
+                CERROR("InterMezzo: %s: no filp\n", __FUNCTION__);
+        if (rc != 0)
+                CERROR("InterMezzo: close files: filp won't close: %d\n", rc);
 
-        if ( fset->fset_lml.fd_file) {
-                rc3 = filp_close(fset->fset_lml.fd_file, 0);
-                fset->fset_lml.fd_file = NULL;
-        } else {
-                printk("hehehehe no filp\n");
-        }
-        if ( rc3 ) {
-                if ( (!rc) && (!rc2) )
-                        rc = rc3;
-                printk("presto: close files: lml filp won't close %d\n", rc3);
-        }
         return rc;
 }
 
@@ -391,7 +470,7 @@
         set_fs(get_ds());
         rc = file->f_op->write(file, str, len, off);
         if (rc != len) {
-                printk("presto_fwrite: wrote %d bytes instead of "
+                CERROR("presto_fwrite: wrote %d bytes instead of "
                        "%d at %ld\n", rc, len, (long)*off);
                 rc = -EIO; 
         }
@@ -406,10 +485,9 @@
         mm_segment_t old_fs;
         ENTRY;
 
-        if ( len > 512 ) {
-                printk("presto_fread: read at %Ld for %d bytes, ino %ld\n",
+        if (len > 512)
+                CERROR("presto_fread: read at %Ld for %d bytes, ino %ld\n",
                        *off, len, file->f_dentry->d_inode->i_ino); 
-        }
 
         rc = -EINVAL;
         if ( !off ) {
@@ -436,21 +514,47 @@
         set_fs(get_ds());
         rc = file->f_op->read(file, str, len, off);
         if (rc != len) {
-                printk("presto_fread: read %d bytes instead of "
-                       "%d at %ld\n", rc, len, (long)*off);
+                CDEBUG(D_FILE, "presto_fread: read %d bytes instead of "
+                       "%d at %Ld\n", rc, len, *off);
                 rc = -EIO; 
         }
         set_fs(old_fs);
+        EXIT;
         return rc;
 }
 
+loff_t presto_kml_offset(struct presto_file_set *fset)
+{
+        unsigned int kml_recno;
+        struct presto_log_fd *fd = &fset->fset_kml;
+        loff_t  offset;
+        ENTRY;
+
+        write_lock(&fd->fd_lock); 
+
+        /* Determine the largest valid offset, i.e. up until the first
+         * reservation held on the file. */
+        if ( !list_empty(&fd->fd_reservations) ) {
+                struct presto_reservation_data *rd;
+                rd = list_entry(fd->fd_reservations.next, 
+                                struct presto_reservation_data, 
+                                ri_list);
+                offset = rd->ri_offset;
+                kml_recno = rd->ri_recno;
+        } else {
+                offset = fd->fd_file->f_dentry->d_inode->i_size;
+                kml_recno = fset->fset_kml.fd_recno; 
+        }
+        write_unlock(&fd->fd_lock); 
+        return offset; 
+}
 
 static int presto_kml_dispatch(struct presto_file_set *fset)
 {
         int rc = 0;
         unsigned int kml_recno;
         struct presto_log_fd *fd = &fset->fset_kml;
-        loff_t  offset;
+        loff_t offset;
         ENTRY;
 
         write_lock(&fd->fd_lock); 
@@ -470,18 +574,27 @@
         }
 
         if ( kml_recno < fset->fset_lento_recno ) {
-                printk("presto_kml_dispatch: smoke is coming\n"); 
+                CERROR("presto_kml_dispatch: smoke is coming\n"); 
                 write_unlock(&fd->fd_lock);
+                EXIT;
                 return 0; 
         } else if ( kml_recno == fset->fset_lento_recno ) {
                 write_unlock(&fd->fd_lock);
                 EXIT;
                 return 0; 
+                /* XXX add a further "if" here to delay the KML upcall */ 
+#if 0
+        } else if ( kml_recno < fset->fset_lento_recno + 100) {
+                write_unlock(&fd->fd_lock);
+                EXIT;
+                return 0;
+#endif
         }
         CDEBUG(D_PIOCTL, "fset: %s\n", fset->fset_name);
-        rc = lento_kml(fset->fset_cache->cache_psdev->uc_minor,
+
+        rc = izo_upc_kml(fset->fset_cache->cache_psdev->uc_minor,
                        fset->fset_lento_off, fset->fset_lento_recno,
-                       offset, kml_recno, strlen(fset->fset_name),
+                       offset + fset->fset_kml_logical_off, kml_recno,
                        fset->fset_name);
 
         if ( rc ) {
@@ -497,6 +610,256 @@
         return 0;
 }
 
+int izo_lookup_file(struct presto_file_set *fset, char *path,
+                    struct nameidata *nd)
+{
+        int error = 0;
+
+        CDEBUG(D_CACHE, "looking up: %s\n", path);
+
+        if (path_init(path, LOOKUP_PARENT, nd))
+                error = path_walk(path, nd);
+        if (error) {
+                EXIT;
+                return error;
+        }
+
+        return 0;
+}
+
+/* FIXME: this function is a mess of locking and error handling.  There's got to
+ * be a better way. */
+static int do_truncate_rename(struct presto_file_set *fset, char *oldname,
+                              char *newname)
+{
+        struct dentry *old_dentry, *new_dentry;
+        struct nameidata oldnd, newnd;
+        char *oldpath, *newpath;
+        int error;
+
+        ENTRY;
+
+        oldpath = izo_make_path(fset, oldname);
+        if (oldpath == NULL) {
+                EXIT;
+                return -ENOENT;
+        }
+
+        newpath = izo_make_path(fset, newname);
+        if (newpath == NULL) {
+                error = -ENOENT;
+                EXIT;
+                goto exit;
+        }
+
+        if ((error = izo_lookup_file(fset, oldpath, &oldnd)) != 0) {
+                EXIT;
+                goto exit1;
+        }
+
+        if ((error = izo_lookup_file(fset, newpath, &newnd)) != 0) {
+                EXIT;
+                goto exit2;
+        }
+
+        double_lock(newnd.dentry, oldnd.dentry);
+        old_dentry = lookup_hash(&oldnd.last, oldnd.dentry);
+        error = PTR_ERR(old_dentry);
+        if (IS_ERR(old_dentry)) {
+                EXIT;
+                goto exit3;
+        }
+        error = -ENOENT;
+        if (!old_dentry->d_inode) {
+                EXIT;
+                goto exit4;
+        }
+        new_dentry = lookup_hash(&newnd.last, newnd.dentry);
+        error = PTR_ERR(new_dentry);
+        if (IS_ERR(new_dentry)) {
+                EXIT;
+                goto exit4;
+        }
+
+        {
+        extern int presto_rename(struct inode *old_dir,struct dentry *old_dentry,
+                                struct inode *new_dir,struct dentry *new_dentry);
+        error = presto_rename(old_dentry->d_parent->d_inode, old_dentry,
+                              new_dentry->d_parent->d_inode, new_dentry);
+        }
+
+        dput(new_dentry);
+        EXIT;
+ exit4:
+        dput(old_dentry);
+ exit3:
+        double_up(&newnd.dentry->d_inode->i_sem, &oldnd.dentry->d_inode->i_sem);
+        path_release(&newnd);
+ exit2:
+        path_release(&oldnd);
+ exit1:
+        PRESTO_FREE(newpath, strlen(newpath) + 1);
+ exit:
+        PRESTO_FREE(oldpath, strlen(oldpath) + 1);
+        return error;
+}
+
+/* This function is called with the fset->fset_kml.fd_lock held */
+int presto_finish_kml_truncate(struct presto_file_set *fset,
+                               unsigned long int offset)
+{
+        struct lento_vfs_context info;
+        void *handle;
+        struct file *f;
+        struct dentry *dentry;
+        int error = 0, len;
+        struct nameidata nd;
+        char *kmlpath = NULL, *smlpath = NULL;
+        ENTRY;
+
+        if (offset == 0) {
+                /* Lento couldn't do what it needed to; abort the truncation. */
+                fset->fset_kml.fd_truncating = 0;
+                EXIT;
+                return 0;
+        }
+
+        /* someone is about to write to the end of the KML; try again later. */
+        if ( !list_empty(&fset->fset_kml.fd_reservations) ) {
+                EXIT;
+                return -EAGAIN;
+        }
+
+        f = presto_copy_kml_tail(fset, offset);
+        if (IS_ERR(f)) {
+                EXIT;
+                return PTR_ERR(f);
+        }                        
+
+        /* In a single transaction:
+         *
+         *   - unlink 'kml'
+         *   - rename 'kml_tmp' to 'kml'
+         *   - unlink 'sml'
+         *   - rename 'sml_tmp' to 'sml'
+         *   - rewrite the first record of last_rcvd with the new kml
+         *     offset.
+         */
+        handle = presto_trans_start(fset, fset->fset_dentry->d_inode,
+                                    KML_OPCODE_KML_TRUNC);
+        if (IS_ERR(handle)) {
+                presto_release_space(fset->fset_cache, PRESTO_REQLOW);
+                CERROR("ERROR: presto_finish_kml_truncate: no space for transaction\n");
+                EXIT;
+                return -ENOMEM;
+        }
+
+        memset(&info, 0, sizeof(info));
+        info.flags = LENTO_FL_IGNORE_TIME;
+
+        kmlpath = izo_make_path(fset, "kml");
+        if (kmlpath == NULL) {
+                error = -ENOMEM;
+                CERROR("make_path failed: ENOMEM\n");
+                EXIT;
+                goto exit_commit;
+        }
+
+        if ((error = izo_lookup_file(fset, kmlpath, &nd)) != 0) {
+                CERROR("izo_lookup_file(kml) failed: %d.\n", error);
+                EXIT;
+                goto exit_commit;
+        }
+        down(&nd.dentry->d_inode->i_sem);
+        dentry = lookup_hash(&nd.last, nd.dentry);
+        error = PTR_ERR(dentry);
+        if (IS_ERR(dentry)) {
+                up(&nd.dentry->d_inode->i_sem);
+                path_release(&nd);
+                CERROR("lookup_hash failed\n");
+                EXIT;
+                goto exit_commit;
+        }
+        error = presto_do_unlink(fset, dentry->d_parent, dentry, &info);
+        dput(dentry);
+        up(&nd.dentry->d_inode->i_sem);
+        path_release(&nd);
+
+        if (error != 0) {
+                CERROR("presto_do_unlink(kml) failed: %d.\n", error);
+                EXIT;
+                goto exit_commit;
+        }
+
+        smlpath = izo_make_path(fset, "sml");
+        if (smlpath == NULL) {
+                error = -ENOMEM;
+                CERROR("make_path() failed: ENOMEM\n");
+                EXIT;
+                goto exit_commit;
+        }
+
+        if ((error = izo_lookup_file(fset, smlpath, &nd)) != 0) {
+                CERROR("izo_lookup_file(sml) failed: %d.\n", error);
+                EXIT;
+                goto exit_commit;
+        }
+        down(&nd.dentry->d_inode->i_sem);
+        dentry = lookup_hash(&nd.last, nd.dentry);
+        error = PTR_ERR(dentry);
+        if (IS_ERR(dentry)) {
+                up(&nd.dentry->d_inode->i_sem);
+                path_release(&nd);
+                CERROR("lookup_hash failed\n");
+                EXIT;
+                goto exit_commit;
+        }
+        error = presto_do_unlink(fset, dentry->d_parent, dentry, &info);
+        dput(dentry);
+        up(&nd.dentry->d_inode->i_sem);
+        path_release(&nd);
+
+        if (error != 0) {
+                CERROR("presto_do_unlink(sml) failed: %d.\n", error);
+                EXIT;
+                goto exit_commit;
+        }
+
+        error = do_truncate_rename(fset, "kml_tmp", "kml");
+        if (error != 0)
+                CERROR("do_truncate_rename(kml_tmp, kml) failed: %d\n", error);
+        error = do_truncate_rename(fset, "sml_tmp", "sml");
+        if (error != 0)
+                CERROR("do_truncate_rename(sml_tmp, sml) failed: %d\n", error);
+
+        /* Write a new 'last_rcvd' record with the new KML offset */
+        fset->fset_kml_logical_off += offset;
+        CDEBUG(D_CACHE, "new kml_logical_offset: %Lu\n",
+               fset->fset_kml_logical_off);
+        if (presto_write_kml_logical_offset(fset) != 0) {
+                CERROR("presto_write_kml_logical_offset failed\n");
+        }
+
+        presto_trans_commit(fset, handle);
+
+        /* Everything was successful, so swap the KML file descriptors */
+        filp_close(fset->fset_kml.fd_file, NULL);
+        fset->fset_kml.fd_file = f;
+        fset->fset_kml.fd_offset -= offset;
+        fset->fset_kml.fd_truncating = 0;
+
+        EXIT;
+        return 0;
+
+ exit_commit:
+        presto_trans_commit(fset, handle);
+        len = strlen("/.intermezzo/") + strlen(fset->fset_name) +strlen("sml");
+        if (kmlpath != NULL)
+                PRESTO_FREE(kmlpath, len);
+        if (smlpath != NULL)
+                PRESTO_FREE(smlpath, len);
+        return error;
+}
 
 /* structure of an extended log record:
 
@@ -513,10 +876,10 @@
         size_t prefix_size; 
         int rc;
 
-        prefix_size = size - sizeof(struct journal_suffix);
+        prefix_size = size - sizeof(struct kml_suffix);
         rc = presto_fwrite(f, buf, prefix_size, off);
         if ( rc != prefix_size ) {
-                printk("Write error!\n");
+                CERROR("Write error!\n");
                 EXIT;
                 return -EIO;
         }
@@ -524,7 +887,7 @@
         if  ( string1  && len1 ) {
                 rc = presto_fwrite(f, string1, len1, off);
                 if ( rc != len1 ) {
-                        printk("Write error!\n");
+                        CERROR("Write error!\n");
                         EXIT;
                         return -EIO;
                 }
@@ -533,7 +896,7 @@
         if  ( string2 && len2 ) {
                 rc = presto_fwrite(f, string2, len2, off);
                 if ( rc != len2 ) {
-                        printk("Write error!\n");
+                        CERROR("Write error!\n");
                         EXIT;
                         return -EIO;
                 }
@@ -542,16 +905,16 @@
         if  ( string3 && len3 ) {
                 rc = presto_fwrite(f, string3, len3, off);
                 if ( rc != len3 ) {
-                        printk("Write error!\n");
+                        CERROR("Write error!\n");
                         EXIT;
                         return -EIO;
                 }
         }
 
         rc = presto_fwrite(f, buf + prefix_size,
-                           sizeof(struct journal_suffix), off);
-        if ( rc != sizeof(struct journal_suffix) ) {
-                printk("Write error!\n");
+                           sizeof(struct kml_suffix), off);
+        if ( rc != sizeof(struct kml_suffix) ) {
+                CERROR("Write error!\n");
                 EXIT;
                 return -EIO;
         }
@@ -561,18 +924,20 @@
 
 /*
  * rec->size must be valid prior to calling this function.
+ *
+ * had to export this for branch_reinter in kml_reint.c 
  */
-static int presto_log(struct presto_file_set *fset, struct rec_info *rec,
-                      const char *buf, size_t size,
-                      const char *string1, int len1, 
-                      const char *string2, int len2,
-                      const char *string3, int len3)
+int presto_log(struct presto_file_set *fset, struct rec_info *rec,
+               const char *buf, size_t size,
+               const char *string1, int len1, 
+               const char *string2, int len2,
+               const char *string3, int len3)
 {
         int rc;
         struct presto_reservation_data rd;
         loff_t offset;
         struct presto_log_fd *fd;
-        struct journal_suffix *s;
+        struct kml_suffix *s;
         int prefix_size; 
 
         ENTRY;
@@ -590,17 +955,26 @@
         }
 
         presto_reserve_record(fset, fd, rec, &rd);
-        offset = rec->offset;
+
+        if (rec->is_kml) {
+                if (rec->offset < fset->fset_kml_logical_off) {
+                        CERROR("record with pre-trunc offset.  tell phil.\n");
+                        BUG();
+                }
+                offset = rec->offset - fset->fset_kml_logical_off;
+        } else {
+                offset = rec->offset;
+        }
 
         /* now we know the record number */ 
-        prefix_size = size - sizeof(struct journal_suffix);
-        s = (struct journal_suffix *) (buf + prefix_size); 
-        s->recno =  cpu_to_le32(rec->recno); 
+        prefix_size = size - sizeof(struct kml_suffix);
+        s = (struct kml_suffix *) (buf + prefix_size); 
+        s->recno = cpu_to_le32(rec->recno); 
 
         rc = presto_write_record(fd->fd_file, &offset, buf, size, 
                                  string1, len1, string2, len2, string3, len3); 
         if (rc) {
-                printk("presto: error writing record to %s\n",
+                CERROR("presto: error writing record to %s\n",
                         rec->is_kml ? "KML" : "LML"); 
                 return rc;
         }
@@ -616,7 +990,7 @@
 static int presto_last_record(struct presto_log_fd *fd, loff_t *size, 
                              loff_t *tail_offset, __u32 *recno, loff_t tail)
 {
-        struct journal_suffix suffix;
+        struct kml_suffix suffix;
         int rc;
         loff_t zeroes;
 
@@ -624,7 +998,7 @@
         *tail_offset = 0;
         *size = 0;
         
-        if (tail < sizeof(struct journal_prefix) + sizeof(suffix)) {
+        if (tail < sizeof(struct kml_prefix_hdr) + sizeof(suffix)) {
                 EXIT;
                 return 0;
         }
@@ -644,18 +1018,18 @@
         }
 
         /* zeroes at the begining of file. this is needed to prevent
-	   presto_fread errors  -SHP
-	*/
+           presto_fread errors  -SHP
+        */
         if (zeroes <= 0) return 0;
                        
-        zeroes -= sizeof(suffix);
+        zeroes -= sizeof(suffix) + sizeof(int);
         rc = presto_fread(fd->fd_file, (char *)&suffix, sizeof(suffix), &zeroes);
         if ( rc != sizeof(suffix) ) {
                 EXIT;
                 return rc;
         }
         if ( suffix.len > 500 ) {
-                printk("PRESTO: Warning long record tail at %ld, rec tail_offset at %ld (size %d)\n", 
+                CERROR("InterMezzo: Warning long record tail at %ld, rec tail_offset at %ld (size %d)\n", 
                         (long) zeroes, (long)*tail_offset, suffix.len); 
         }
 
@@ -665,213 +1039,259 @@
         return 0;
 }
 
-static int presto_kml_last_recno(struct presto_file_set *fset)
+static int izo_kml_last_recno(struct presto_log_fd *logfd)
 {
         int rc; 
         loff_t size;
         loff_t tail_offset;
         int recno;
-        loff_t tail = fset->fset_kml.fd_file->f_dentry->d_inode->i_size;
+        loff_t tail = logfd->fd_file->f_dentry->d_inode->i_size;
 
-        if ((rc = presto_last_record(&fset->fset_kml, &size, 
-                                        &tail_offset, &recno, tail)) ) {
+        rc = presto_last_record(logfd, &size, &tail_offset, &recno, tail);
+        if (rc != 0) {
                 EXIT;
                 return rc;
         }
 
-        fset->fset_kml.fd_offset = tail_offset;
-        fset->fset_kml.fd_recno = recno;
+        logfd->fd_offset = tail_offset;
+        logfd->fd_recno = recno;
         CDEBUG(D_JOURNAL, "setting fset_kml->fd_recno to %d, offset  %Ld\n",
                recno, tail_offset); 
         EXIT;
         return 0;
 }
 
-static struct file *presto_log_open(struct presto_file_set *fset, char *name, int flags)
+struct file *izo_log_open(struct presto_file_set *fset, char *name, int flags)
 {
         struct presto_cache *cache = fset->fset_cache;
         struct file *f;
         int error;
-        int mtpt_len, path_len;
-        char *path;
         ENTRY;
 
-        mtpt_len = strlen(cache->cache_mtpt);
-        path_len = mtpt_len + strlen("/.intermezzo/") +
-                strlen(fset->fset_name) + strlen(name);
-
-        error = -ENOMEM;
-        PRESTO_ALLOC(path, char *, path_len + 1);
-        if ( !path ) {
-                EXIT;
-                return ERR_PTR(-ENOMEM);
-        }
-
-        sprintf(path, "%s/.intermezzo/%s/%s", cache->cache_mtpt,
-                fset->fset_name, name);
-        CDEBUG(D_INODE, "opening file %s\n", path);
-
-        f = filp_open(path, flags, 0);
+        f = izo_fset_open(fset, name, flags, 0644);
         error = PTR_ERR(f);
         if (IS_ERR(f)) {
-                CDEBUG(D_INODE, "Error %d\n", error);
                 EXIT;
-                goto out_free;
+                return f;
         }
 
         error = -EINVAL;
         if ( cache != presto_get_cache(f->f_dentry->d_inode) ) {
-                printk("PRESTO: %s cache does not match fset cache!\n", name);
+                CERROR("InterMezzo: %s cache does not match fset cache!\n",name);
                 fset->fset_kml.fd_file = NULL;
                 filp_close(f, NULL);
-                goto out_free;
+                f = NULL;
+                EXIT;
+                return f;
         }
 
         if (cache->cache_filter &&  cache->cache_filter->o_trops &&
-	    cache->cache_filter->o_trops->tr_journal_data) {
-		CDEBUG(D_INODE, "\n");
+            cache->cache_filter->o_trops->tr_journal_data) {
                 cache->cache_filter->o_trops->tr_journal_data
                         (f->f_dentry->d_inode);
         } else {
-                printk("WARNING: InterMezzo no file data logging!\n"); 
+                CERROR("InterMezzo WARNING: no file data logging!\n"); 
         }
 
- out_free:
-        PRESTO_FREE(path, path_len + 1);
-
         EXIT;
+
         return f;
 }
 
-int presto_init_kml_file(struct presto_file_set *fset)
+int izo_init_kml_file(struct presto_file_set *fset, struct presto_log_fd *logfd)
 {
         int error = 0;
         struct file *f;
 
         ENTRY;
-        if (fset->fset_kml.fd_file) {
+        if (logfd->fd_file) {
                 CDEBUG(D_INODE, "fset already has KML open\n");
                 EXIT;
                 return 0;
         }
 
-        fset->fset_kml.fd_lock = RW_LOCK_UNLOCKED;
-        INIT_LIST_HEAD(&fset->fset_kml.fd_reservations); 
-        f = presto_log_open(fset, "kml",  O_RDWR | O_CREAT);
-        if ( IS_ERR(f) ) {
+        logfd->fd_lock = RW_LOCK_UNLOCKED;
+        INIT_LIST_HEAD(&logfd->fd_reservations); 
+        f = izo_log_open(fset, "kml",  O_RDWR | O_CREAT);
+        if (IS_ERR(f)) {
                 error = PTR_ERR(f);
                 return error;
         }
 
-        fset->fset_kml.fd_file = f;
-        error = presto_kml_last_recno(fset);
+        logfd->fd_file = f;
+        error = izo_kml_last_recno(logfd);
 
-        if ( error ) {
-                EXIT;
-                fset->fset_kml.fd_file = NULL;
+        if (error) {
+                logfd->fd_file = NULL;
                 filp_close(f, NULL);
-                printk("presto: IO error in KML of fset %s\n", 
+                CERROR("InterMezzo: IO error in KML of fset %s\n",
                        fset->fset_name);
+                EXIT;
+                return error;
         }
-        fset->fset_lento_off = fset->fset_kml.fd_offset;
-        fset->fset_lento_recno = fset->fset_kml.fd_recno;
+        fset->fset_lento_off = logfd->fd_offset;
+        fset->fset_lento_recno = logfd->fd_recno;
 
         EXIT;
         return error;
 }
 
-
-int presto_init_last_rcvd_file(struct presto_file_set *fset)
+int izo_init_last_rcvd_file(struct presto_file_set *fset, struct presto_log_fd *logfd)
 {
         int error = 0;
         struct file *f;
+        struct rec_info recinfo;
 
         ENTRY;
-        if (fset->fset_last_rcvd) {
+        if (logfd->fd_file != NULL) {
                 CDEBUG(D_INODE, "fset already has last_rcvd open\n");
                 EXIT;
                 return 0;
         }
 
-        f = presto_log_open(fset, "last_rcvd", O_RDWR | O_CREAT);
-        if ( IS_ERR(f) ) {
+        logfd->fd_lock = RW_LOCK_UNLOCKED;
+        INIT_LIST_HEAD(&logfd->fd_reservations); 
+        f = izo_log_open(fset, "last_rcvd", O_RDWR | O_CREAT);
+        if (IS_ERR(f)) {
                 error = PTR_ERR(f);
                 return error;
         }
 
-        fset->fset_last_rcvd = f;
+        logfd->fd_file = f;
+        logfd->fd_offset = f->f_dentry->d_inode->i_size;
+
+        error = izo_rep_cache_init(fset);
+
+        if (presto_read_kml_logical_offset(&recinfo, fset) == 0) {
+                fset->fset_kml_logical_off = recinfo.offset;
+        } else {
+                /* The 'last_rcvd' file doesn't contain a kml offset record,
+                 * probably because we just created 'last_rcvd'.  Write one. */
+                fset->fset_kml_logical_off = 0;
+                presto_write_kml_logical_offset(fset);
+        }
 
         EXIT;
         return error;
 }
 
-int presto_init_lml_file(struct presto_file_set *fset)
+int izo_init_lml_file(struct presto_file_set *fset, struct presto_log_fd *logfd)
 {
         int error = 0;
         struct file *f;
 
         ENTRY;
-        if (fset->fset_lml.fd_file) {
+        if (logfd->fd_file) {
                 CDEBUG(D_INODE, "fset already has lml open\n");
                 EXIT;
                 return 0;
         }
 
-        fset->fset_lml.fd_lock = RW_LOCK_UNLOCKED;
-        INIT_LIST_HEAD(&fset->fset_lml.fd_reservations); 
-        f = presto_log_open(fset, "lml", O_RDWR | O_CREAT);
-        if ( IS_ERR(f) ) {
+        logfd->fd_lock = RW_LOCK_UNLOCKED;
+        INIT_LIST_HEAD(&logfd->fd_reservations); 
+        f = izo_log_open(fset, "lml", O_RDWR | O_CREAT);
+        if (IS_ERR(f)) {
                 error = PTR_ERR(f);
                 return error;
         }
 
-        fset->fset_lml.fd_file = f;
-        fset->fset_lml.fd_offset = 
-                fset->fset_lml.fd_file->f_dentry->d_inode->i_size;
+        logfd->fd_file = f;
+        logfd->fd_offset = f->f_dentry->d_inode->i_size;
 
         EXIT;
         return error;
 }
 
-/* Write the last_rcvd values to the last)_rcvd file */
-int presto_write_last_rcvd(struct rec_info *recinfo,
-                           struct presto_file_set *fset,
-                           struct lento_vfs_context *info)
-{
-        int ret;
-        loff_t off = info->slot_offset;
-        struct {
-                __u32 remote_recno;
-                __u64 remote_offset;
-                __u32 local_recno;
-                __u64 local_offset;
-        } rcvd_rec;
-
-        rcvd_rec.remote_recno = cpu_to_le32(info->recno);
-        rcvd_rec.remote_offset = cpu_to_le64(info->kml_offset);
-        rcvd_rec.local_recno = cpu_to_le32(recinfo->recno);
-        rcvd_rec.local_offset = cpu_to_le64(recinfo->offset + recinfo->size);
+/* Get the KML-offset record from the last_rcvd file */
+int presto_read_kml_logical_offset(struct rec_info *recinfo,
+                                   struct presto_file_set *fset)
+{
+        loff_t off;
+        struct izo_rcvd_rec rec;
+        char uuid[16] = {0};
+
+        off = izo_rcvd_get(&rec, fset, uuid);
+        if (off < 0)
+                return -1;
 
-        ret = presto_fwrite(fset->fset_last_rcvd, (char *)(&rcvd_rec),
-                            sizeof(rcvd_rec), &off);
+        recinfo->offset = rec.lr_local_offset;
+        return 0;
+}
 
-        if (ret == sizeof(rcvd_rec))
-                ret = 0;
+int presto_write_kml_logical_offset(struct presto_file_set *fset)
+{
+        loff_t rc;
+        struct izo_rcvd_rec rec;
+        char uuid[16] = {0};
+
+        rc = izo_rcvd_get(&rec, fset, uuid);
+        if (rc < 0)
+                memset(&rec, 0, sizeof(rec));
+
+        rec.lr_local_offset =
+                cpu_to_le64(fset->fset_kml_logical_off);
 
-        return ret;
+        return izo_rcvd_write(fset, &rec);
 }
 
+struct file * presto_copy_kml_tail(struct presto_file_set *fset,
+                                   unsigned long int start)
+{
+        struct file *f;
+        int len;
+        loff_t read_off, write_off, bytes;
+
+        ENTRY;
+
+        /* Copy the tail of 'kml' to 'kml_tmp' */
+        f = izo_log_open(fset, "kml_tmp", O_RDWR);
+        if (IS_ERR(f)) {
+                EXIT;
+                return f;
+        }
+
+        write_off = 0;
+        read_off = start;
+        bytes = fset->fset_kml.fd_offset - start;
+        while (bytes > 0) {
+                char buf[4096];
+                int toread;
+
+                if (bytes > sizeof(buf))
+                        toread = sizeof(buf);
+                else
+                        toread = bytes;
+
+                len = presto_fread(fset->fset_kml.fd_file, buf, toread,
+                                   &read_off);
+                if (len <= 0)
+                        break;
+
+                if (presto_fwrite(f, buf, len, &write_off) != len) {
+                        filp_close(f, NULL);
+                        EXIT;
+                        return ERR_PTR(-EIO);
+                }
+
+                bytes -= len;
+        }
+
+        EXIT;
+        return f;
+}
+
+
 /* LML records here */
-/* this writes the LML records for close, in conjunction with the KML  */
+/* this writes an LML record to the LML file (rec->is_kml =0)  */
 int presto_write_lml_close(struct rec_info *rec,
                            struct presto_file_set *fset, 
                            struct file *file,
                            __u64 remote_ino,
-                           __u32 remote_generation,
-                           __u32 remote_version,
+                           __u64 remote_generation,
+                           struct presto_version *remote_version,
                            struct presto_version *new_file_ver)
 {
-        int opcode = PRESTO_OP_CLOSE;
+        int opcode = KML_OPCODE_CLOSE;
         char *buffer;
         struct dentry *dentry = file->f_dentry; 
         __u64 ino;
@@ -890,7 +1310,7 @@
           EXIT;
           return 0;
         }
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
@@ -899,28 +1319,27 @@
         ino = cpu_to_le64(dentry->d_inode->i_ino);
         generation = cpu_to_le32(dentry->d_inode->i_generation);
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + sizeof(*new_file_ver) +
+                sizeof(struct kml_prefix_hdr) + sizeof(*new_file_ver) +
                 sizeof(ino) + sizeof(generation) + sizeof(pathlen) +
                 sizeof(remote_ino) + sizeof(remote_generation) + 
                 sizeof(remote_version) + sizeof(rec->offset) +
-                sizeof(struct journal_suffix);
-
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+                sizeof(struct kml_suffix);
 
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
+        
         rec->is_kml = 0;
         rec->size = size + size_round(le32_to_cpu(pathlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, new_file_ver, sizeof(*new_file_ver));
+        logrecord = log_version(logrecord, new_file_ver);
         logrecord = logit(logrecord, &ino, sizeof(ino));
         logrecord = logit(logrecord, &generation, sizeof(generation));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
         logrecord = logit(logrecord, &remote_ino, sizeof(remote_ino));
         logrecord = logit(logrecord, &remote_generation,
                           sizeof(remote_generation));
-        logrecord = logit(logrecord, &remote_version, sizeof(remote_version));
+        logrecord = log_version(logrecord, remote_version);
         logrecord = logit(logrecord, &rec->offset, sizeof(rec->offset));
         logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec);
 
@@ -934,28 +1353,6 @@
         return error;
 }
 
-int presto_journal_write(struct rec_info *rec,
-                         struct presto_file_set *fset, 
-                         struct file *file)
-{
-        struct presto_version file_version;
-        int rc;
-        ENTRY;
-
-        presto_getversion(&file_version, file->f_dentry->d_inode); 
-        /* append this record */
-        rc = presto_write_lml_close
-                (rec, 
-                 fset, 
-                 file,
-                 0, /* remote_ino */
-                 0, /* remote_generation */
-                 0, /* remote_version */
-                 &file_version);
-        EXIT;
-        return rc;
-}
-
 /* 
  * Check if the given record is at the end of the file. If it is, truncate
  * the lml to the record's offset, removing it. Repeat on prior record,
@@ -969,7 +1366,7 @@
         loff_t lml_last_recsize;
         loff_t local_offset;
         int recno;
-        struct journal_prefix prefix;
+        struct kml_prefix_hdr prefix;
         struct inode *inode = fset->fset_lml.fd_file->f_dentry->d_inode;
         void *handle;
         int rc;
@@ -1004,33 +1401,33 @@
           beginning of the file. -SHP
        */
        if (lml_last_recsize != 0) {
-       		local_offset = lml_last_rec - lml_last_recsize;
-       		rc = presto_fread(fset->fset_lml.fd_file, (char *)&prefix,  
-                          		sizeof(prefix), &local_offset); 
-        	if (rc != sizeof(prefix)) {
-                	EXIT;
-                	goto tr_out;
-        	}
+                local_offset = lml_last_rec - lml_last_recsize;
+                rc = presto_fread(fset->fset_lml.fd_file, (char *)&prefix,  
+                                        sizeof(prefix), &local_offset); 
+                if (rc != sizeof(prefix)) {
+                        EXIT;
+                        goto tr_out;
+                }
        
-        	if ( prefix.opcode != PRESTO_OP_NOOP ) {
-                	EXIT;
-                	rc = 0;
+                if ( prefix.opcode != KML_OPCODE_NOOP ) {
+                        EXIT;
+                        rc = 0;
                         /* We may have zeroes at the end of the file, should
-			   we clear them out? -SHP
+                           we clear them out? -SHP
                         */
-                	goto tr_out;
-        	}
-	} else 
-	 	lml_last_rec=0;
+                        goto tr_out;
+                }
+        } else 
+                lml_last_rec=0;
 
-        handle = presto_trans_start(fset, inode, PRESTO_OP_TRUNC);
-        if ( !handle ) {
+        handle = presto_trans_start(fset, inode, KML_OPCODE_TRUNC);
+        if ( IS_ERR(handle) ) {
                 EXIT;
                 rc = -ENOMEM;
                 goto tr_out;
         }
 
-        rc = presto_do_truncate(fset, fset->fset_lml.fd_file->f_dentry, 
+        rc = izo_do_truncate(fset, fset->fset_lml.fd_file->f_dentry, 
                                 lml_last_rec - lml_last_recsize, lml_tail);
         presto_trans_commit(fset, handle); 
         if ( rc == 0 ) {
@@ -1048,25 +1445,21 @@
 
 int presto_truncate_lml(struct presto_file_set *fset)
 {
-
         int rc; 
         ENTRY;
         
         while ( (rc = presto_truncate_lml_tail(fset)) > 0);
         if ( rc < 0 && rc != -EALREADY) {
-                printk("truncate_lml error %d\n", rc); 
+                CERROR("truncate_lml error %d\n", rc); 
         }
         EXIT;
         return rc;
 }
 
-
-
-int presto_clear_lml_close(struct presto_file_set *fset, 
-                           loff_t  lml_offset)
+int presto_clear_lml_close(struct presto_file_set *fset, loff_t lml_offset)
 {
         int rc;
-        struct journal_prefix record;
+        struct kml_prefix_hdr record;
         loff_t offset = lml_offset;
 
         ENTRY;
@@ -1076,20 +1469,20 @@
                 return 0;
         }
 
-        CDEBUG(D_JOURNAL, "reading prefix: off %ld, size %Zd\n", 
+        CDEBUG(D_JOURNAL, "reading prefix: off %ld, size %d\n", 
                (long)lml_offset, sizeof(record));
         rc = presto_fread(fset->fset_lml.fd_file, (char *)&record,
                           sizeof(record), &offset);
 
         if ( rc != sizeof(record) ) {
-                printk("presto: clear_lml io error %d\n", rc); 
+                CERROR("presto: clear_lml io error %d\n", rc); 
                 EXIT;
                 return -EIO;
         }
 
         /* overwrite the prefix */ 
         CDEBUG(D_JOURNAL, "overwriting prefix: off %ld\n", (long)lml_offset);
-        record.opcode = PRESTO_OP_NOOP;
+        record.opcode = KML_OPCODE_NOOP;
         offset = lml_offset;
         /* note: this does just a single transaction in the cache */
         rc = presto_fwrite(fset->fset_lml.fd_file, (char *)(&record), 
@@ -1107,22 +1500,16 @@
 
 /* now a journal function for every operation */
 
-int presto_journal_setattr(struct rec_info *rec, 
-                           struct presto_file_set *fset, 
-                           struct dentry *dentry,
-                           struct presto_version *old_ver, struct iattr *iattr)
+int presto_journal_setattr(struct rec_info *rec, struct presto_file_set *fset,
+                           struct dentry *dentry, struct presto_version *old_ver,
+                           struct izo_rollback_data *rb, struct iattr *iattr)
 {
-        int opcode = PRESTO_OP_SETATTR;
-        char *buffer;
-        char *path;
-        __u32 pathlen;
-        int size;
-        char *logrecord;
-        char record[292];
+        int opcode = KML_OPCODE_SETATTR;
+        char *buffer, *path, *logrecord, record[316];
         struct dentry *root;
-        __u32 uid, gid, mode, valid, flags;
+        __u32 uid, gid, mode, valid, flags, pathlen;
         __u64 fsize, mtime, ctime;
-        int error;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1130,25 +1517,26 @@
                 return 0;
         }
 
-        if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) ) {
+        if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) 
+            || ((dentry->d_parent != dentry) && list_empty(&dentry->d_hash))) {
                 EXIT;
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + sizeof(*old_ver) +
+                sizeof(struct kml_prefix_hdr) + sizeof(*old_ver) +
                 sizeof(valid) + sizeof(mode) + sizeof(uid) + sizeof(gid) +
                 sizeof(fsize) + sizeof(mtime) + sizeof(ctime) + sizeof(flags) +
-                sizeof(pathlen) + sizeof(struct journal_suffix);
+                sizeof(pathlen) + sizeof(*rb) + sizeof(struct kml_suffix);
+
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
         /* Only journal one kind of mtime, and not atime at all.  Also don't
          * journal bogus data in iattr, to make the journal more compressible.
          */
@@ -1169,7 +1557,7 @@
         rec->size = size + size_round(le32_to_cpu(pathlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, old_ver, sizeof(*old_ver));
+        logrecord = log_version(logrecord, old_ver);
         logrecord = logit(logrecord, &valid, sizeof(valid));
         logrecord = logit(logrecord, &mode, sizeof(mode));
         logrecord = logit(logrecord, &uid, sizeof(uid));
@@ -1178,6 +1566,7 @@
         logrecord = logit(logrecord, &mtime, sizeof(mtime));
         logrecord = logit(logrecord, &ctime, sizeof(ctime));
         logrecord = logit(logrecord, &flags, sizeof(flags));
+        logrecord = log_rollback(logrecord, rb);
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
         logrecord = journal_log_suffix(logrecord, record, fset, dentry, rec);
 
@@ -1190,21 +1579,69 @@
         return error;
 }
 
+int presto_get_fileid(int minor, struct presto_file_set *fset,
+                      struct dentry *dentry)
+{
+        int opcode = KML_OPCODE_GET_FILEID;
+        struct rec_info rec;
+        char *buffer, *path, *logrecord, record[4096]; /*include path*/
+        struct dentry *root;
+        __u32 uid, gid, pathlen;
+        int error, size;
+        struct kml_suffix *suffix;
+
+        ENTRY;
+
+        root = fset->fset_dentry;
+
+        uid = cpu_to_le32(dentry->d_inode->i_uid);
+        gid = cpu_to_le32(dentry->d_inode->i_gid);
+        BUFF_ALLOC(buffer, NULL);
+        path = presto_path(dentry, root, buffer, PAGE_SIZE);
+        pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
+        size =  sizeof(__u32) * current->ngroups + 
+                sizeof(struct kml_prefix_hdr) + sizeof(pathlen) +
+                size_round(le32_to_cpu(pathlen)) +
+                sizeof(struct kml_suffix);
+
+        CDEBUG(D_FILE, "kml size: %d\n", size);
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
+
+        memset(&rec, 0, sizeof(rec));
+        rec.is_kml = 1;
+        rec.size = size;
+
+        logrecord = journal_log_prefix(record, opcode, &rec);
+        logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
+        logrecord = logit(logrecord, path, size_round(le32_to_cpu(pathlen)));
+        suffix = (struct kml_suffix *)logrecord;
+        logrecord = journal_log_suffix(logrecord, record, fset, dentry, &rec);
+        /* journal_log_suffix expects journal_log to set this */
+        suffix->recno = 0;
+
+        CDEBUG(D_FILE, "actual kml size: %d\n", logrecord - record);
+        CDEBUG(D_FILE, "get fileid: uid %d, gid %d, path: %s\n", uid, gid,path);
+
+        error = izo_upc_get_fileid(minor, size, record, 
+                                   size_round(le32_to_cpu(pathlen)), path,
+                                   fset->fset_name);
+
+        BUFF_FREE(buffer);
+        EXIT;
+        return error;
+}
+
 int presto_journal_create(struct rec_info *rec, struct presto_file_set *fset,
                           struct dentry *dentry,
                           struct presto_version *tgt_dir_ver,
                           struct presto_version *new_file_ver, int mode)
 {
-        int opcode = PRESTO_OP_CREATE;
-        char *buffer;
-        char *path;
-        __u32 pathlen;
-        int size;
-        char *logrecord;
-        char record[292];
+        int opcode = KML_OPCODE_CREATE;
+        char *buffer, *path, *logrecord, record[292];
         struct dentry *root;
-        __u32 uid, gid, lmode;
-        int error;
+        __u32 uid, gid, lmode, pathlen;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1212,7 +1649,7 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         uid = cpu_to_le32(dentry->d_inode->i_uid);
         gid = cpu_to_le32(dentry->d_inode->i_gid);
@@ -1222,21 +1659,20 @@
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(lmode) + sizeof(uid) + sizeof(gid) + sizeof(pathlen) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, dentry->d_parent);
-        logrecord = logit(logrecord, new_file_ver, sizeof(*new_file_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, dentry->d_parent);
+        logrecord = log_version(logrecord, new_file_ver);
         logrecord = logit(logrecord, &lmode, sizeof(lmode));
         logrecord = logit(logrecord, &uid, sizeof(uid));
         logrecord = logit(logrecord, &gid, sizeof(gid));
@@ -1252,22 +1688,17 @@
         return error;
 }
 
-int presto_journal_symlink(struct rec_info *rec, struct presto_file_set *fset, struct dentry *dentry,
-                           const char *target,
+int presto_journal_symlink(struct rec_info *rec, struct presto_file_set *fset,
+                           struct dentry *dentry, const char *target,
                            struct presto_version *tgt_dir_ver,
                            struct presto_version *new_link_ver)
 {
-        int opcode = PRESTO_OP_SYMLINK;
-        char *buffer;
-        char *path;
-        __u32 pathlen;
-        int size;
-        char *logrecord;
-        char record[292];
-        __u32 targetlen = cpu_to_le32(strlen(target));
+        int opcode = KML_OPCODE_SYMLINK;
+        char *buffer, *path, *logrecord, record[292];
         struct dentry *root;
-        __u32 uid, gid;
-        int error;
+        __u32 uid, gid, pathlen;
+        __u32 targetlen = cpu_to_le32(strlen(target));
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1275,7 +1706,7 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         uid = cpu_to_le32(dentry->d_inode->i_uid);
         gid = cpu_to_le32(dentry->d_inode->i_gid);
@@ -1284,22 +1715,21 @@
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(uid) + sizeof(gid) + sizeof(pathlen) +
-                sizeof(targetlen) + sizeof(struct journal_suffix);
+                sizeof(targetlen) + sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen)) +
                 size_round(le32_to_cpu(targetlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, dentry->d_parent);
-        logrecord = logit(logrecord, new_link_ver, sizeof(*new_link_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, dentry->d_parent);
+        logrecord = log_version(logrecord, new_link_ver);
         logrecord = logit(logrecord, &uid, sizeof(uid));
         logrecord = logit(logrecord, &gid, sizeof(gid));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
@@ -1316,20 +1746,16 @@
         return error;
 }
 
-int presto_journal_mkdir(struct rec_info *rec, struct presto_file_set *fset, struct dentry *dentry,
+int presto_journal_mkdir(struct rec_info *rec, struct presto_file_set *fset,
+                         struct dentry *dentry,
                          struct presto_version *tgt_dir_ver,
                          struct presto_version *new_dir_ver, int mode)
 {
-        int opcode = PRESTO_OP_MKDIR;
-        char *buffer;
-        char *path;
-        __u32 pathlen;
-        int size;
-        char *logrecord;
-        char record[292];
+        int opcode = KML_OPCODE_MKDIR;
+        char *buffer, *path, *logrecord, record[292];
         struct dentry *root;
-        __u32 uid, gid, lmode;
-        int error;
+        __u32 uid, gid, lmode, pathlen;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1337,7 +1763,7 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         uid = cpu_to_le32(dentry->d_inode->i_uid);
         gid = cpu_to_le32(dentry->d_inode->i_gid);
@@ -1347,21 +1773,20 @@
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size = sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(lmode) + sizeof(uid) + sizeof(gid) + sizeof(pathlen) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen));
         logrecord = journal_log_prefix(record, opcode, rec);
 
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, dentry->d_parent);
-        logrecord = logit(logrecord, new_dir_ver, sizeof(*new_dir_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, dentry->d_parent);
+        logrecord = log_version(logrecord, new_dir_ver);
         logrecord = logit(logrecord, &lmode, sizeof(lmode));
         logrecord = logit(logrecord, &uid, sizeof(uid));
         logrecord = logit(logrecord, &gid, sizeof(gid));
@@ -1381,18 +1806,14 @@
 int
 presto_journal_rmdir(struct rec_info *rec, struct presto_file_set *fset,
                      struct dentry *dir, struct presto_version *tgt_dir_ver,
-                     struct presto_version *old_dir_ver, int len,
-                     const char *name)
+                     struct presto_version *old_dir_ver,
+                     struct izo_rollback_data *rb, int len, const char *name)
 {
-        int opcode = PRESTO_OP_RMDIR;
-        char *buffer;
-        char *path;
+        int opcode = KML_OPCODE_RMDIR;
+        char *buffer, *path, *logrecord, record[316];
         __u32 pathlen, llen;
-        int size;
-        char *logrecord;
-        char record[292];
         struct dentry *root;
-        int error;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1400,19 +1821,19 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         llen = cpu_to_le32(len);
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dir, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
-                sizeof(pathlen) + sizeof(llen) + sizeof(struct journal_suffix);
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(pathlen) + sizeof(llen) + sizeof(*rb) +
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         CDEBUG(D_JOURNAL, "path: %s (%d), name: %s (%d), size %d\n",
                path, pathlen, name, len, size);
@@ -1422,9 +1843,10 @@
                 size_round(len);
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, dir);
-        logrecord = logit(logrecord, old_dir_ver, sizeof(*old_dir_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, dir);
+        logrecord = log_version(logrecord, old_dir_ver);
+        logrecord = logit(logrecord, rb, sizeof(*rb));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
         logrecord = logit(logrecord, &llen, sizeof(llen));
         logrecord = journal_log_suffix(logrecord, record, fset, dir, rec);
@@ -1445,16 +1867,11 @@
                      struct presto_version *new_node_ver, int mode,
                      int dmajor, int dminor )
 {
-        int opcode = PRESTO_OP_MKNOD;
-        char *buffer;
-        char *path;
-        __u32 pathlen;
-        int size;
-        char *logrecord;
-        char record[292];
+        int opcode = KML_OPCODE_MKNOD;
+        char *buffer, *path, *logrecord, record[292];
         struct dentry *root;
-        __u32 uid, gid, lmode, lmajor, lminor;
-        int error;
+        __u32 uid, gid, lmode, lmajor, lminor, pathlen;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1462,7 +1879,7 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         uid = cpu_to_le32(dentry->d_inode->i_uid);
         gid = cpu_to_le32(dentry->d_inode->i_gid);
@@ -1474,22 +1891,21 @@
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size = sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(lmode) + sizeof(uid) + sizeof(gid) + sizeof(lmajor) +
                 sizeof(lminor) + sizeof(pathlen) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, dentry->d_parent);
-        logrecord = logit(logrecord, new_node_ver, sizeof(*new_node_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, dentry->d_parent);
+        logrecord = log_version(logrecord, new_node_ver);
         logrecord = logit(logrecord, &lmode, sizeof(lmode));
         logrecord = logit(logrecord, &uid, sizeof(uid));
         logrecord = logit(logrecord, &gid, sizeof(gid));
@@ -1513,15 +1929,11 @@
                     struct presto_version *tgt_dir_ver,
                     struct presto_version *new_link_ver)
 {
-        int opcode = PRESTO_OP_LINK;
-        char *buffer, *srcbuffer;
-        char *path, *srcpath;
+        int opcode = KML_OPCODE_LINK;
+        char *buffer, *srcbuffer, *path, *srcpath, *logrecord, record[292];
         __u32 pathlen, srcpathlen;
-        int size;
-        char *logrecord;
-        char record[292];
         struct dentry *root;
-        int error;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1529,7 +1941,7 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         BUFF_ALLOC(srcbuffer, NULL);
         srcpath = presto_path(src, root, srcbuffer, PAGE_SIZE);
@@ -1539,22 +1951,21 @@
         path = presto_path(tgt, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(srcpathlen) + sizeof(pathlen) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen)) + 
                 size_round(le32_to_cpu(srcpathlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, tgt->d_parent);
-        logrecord = logit(logrecord, new_link_ver, sizeof(*new_link_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, tgt->d_parent);
+        logrecord = log_version(logrecord, new_link_ver);
         logrecord = logit(logrecord, &srcpathlen, sizeof(srcpathlen));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
         logrecord = journal_log_suffix(logrecord, record, fset, tgt, rec);
@@ -1571,20 +1982,16 @@
 }
 
 
-int presto_journal_rename(struct rec_info *rec, struct presto_file_set *fset, struct dentry *src,
-                          struct dentry *tgt,
+int presto_journal_rename(struct rec_info *rec, struct presto_file_set *fset,
+                          struct dentry *src, struct dentry *tgt,
                           struct presto_version *src_dir_ver,
                           struct presto_version *tgt_dir_ver)
 {
-        int opcode = PRESTO_OP_RENAME;
-        char *buffer, *srcbuffer;
-        char *path, *srcpath;
+        int opcode = KML_OPCODE_RENAME;
+        char *buffer, *srcbuffer, *path, *srcpath, *logrecord, record[292];
         __u32 pathlen, srcpathlen;
-        int size;
-        char *logrecord;
-        char record[292];
         struct dentry *root;
-        int error;
+        int error, size;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1592,7 +1999,7 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         BUFF_ALLOC(srcbuffer, NULL);
         srcpath = presto_path(src, root, srcbuffer, PAGE_SIZE);
@@ -1602,23 +2009,22 @@
         path = presto_path(tgt, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 4 * sizeof(*src_dir_ver) +
+                sizeof(struct kml_prefix_hdr) + 4 * sizeof(*src_dir_ver) +
                 sizeof(srcpathlen) + sizeof(pathlen) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen)) + 
                 size_round(le32_to_cpu(srcpathlen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, src_dir_ver, sizeof(*src_dir_ver));
-        logrecord = log_version(logrecord, src->d_parent);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, tgt->d_parent);
+        logrecord = log_version(logrecord, src_dir_ver);
+        logrecord = log_dentry_version(logrecord, src->d_parent);
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, tgt->d_parent);
         logrecord = logit(logrecord, &srcpathlen, sizeof(srcpathlen));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
         logrecord = journal_log_suffix(logrecord, record, fset, tgt, rec);
@@ -1634,21 +2040,18 @@
         return error;
 }
 
-
-int presto_journal_unlink(struct rec_info *rec, struct presto_file_set *fset, struct dentry *dir,
-                          struct presto_version *tgt_dir_ver,
-                          struct presto_version *old_file_ver, int len,
-                          const char *name)
-{
-        int opcode = PRESTO_OP_UNLINK;
-        char *buffer;
-        char *path;
+int presto_journal_unlink(struct rec_info *rec, struct presto_file_set *fset,
+                          struct dentry *dir, struct presto_version *tgt_dir_ver,
+                          struct presto_version *old_file_ver,
+                          struct izo_rollback_data *rb, struct dentry *dentry,
+                          char *old_target, int old_targetlen)
+{
+        int opcode = KML_OPCODE_UNLINK;
+        char *buffer, *path, *logrecord, record[316];
+        const char *name;
         __u32 pathlen, llen;
-        int size;
-        char *logrecord;
-        char record[292];
         struct dentry *root;
-        int error;
+        int error, size, len;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1656,35 +2059,41 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
+
+        name = dentry->d_name.name;
+        len = dentry->d_name.len;
 
         llen = cpu_to_le32(len);
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dir, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
-        size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 3 * sizeof(*tgt_dir_ver) +
-                sizeof(pathlen) + sizeof(llen) + sizeof(struct journal_suffix);
+        size = sizeof(__u32) * current->ngroups + 
+                sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
+                sizeof(pathlen) + sizeof(llen) + sizeof(*rb) +
+                sizeof(old_targetlen) + sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
-        rec->size = size + size_round(le32_to_cpu(pathlen)) + size_round(len);
+        rec->size = size + size_round(le32_to_cpu(pathlen)) + size_round(len) +
+                size_round(old_targetlen);
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, tgt_dir_ver, sizeof(*tgt_dir_ver));
-        logrecord = log_version(logrecord, dir);
-        logrecord = logit(logrecord, old_file_ver, sizeof(*old_file_ver));
+        logrecord = log_version(logrecord, tgt_dir_ver);
+        logrecord = log_dentry_version(logrecord, dir);
+        logrecord = log_version(logrecord, old_file_ver);
+        logrecord = log_rollback(logrecord, rb);
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
         logrecord = logit(logrecord, &llen, sizeof(llen));
+        logrecord = logit(logrecord, &old_targetlen, sizeof(old_targetlen));
         logrecord = journal_log_suffix(logrecord, record, fset, dir, rec);
 
         error = presto_log(fset, rec, record, size,
                            path, size_round(le32_to_cpu(pathlen)),
-                           name, size_round(len), 
-                           NULL, 0);
+                           name, size_round(len),
+                           old_target, size_round(old_targetlen));
 
         BUFF_FREE(buffer);
         EXIT;
@@ -1694,20 +2103,16 @@
 int
 presto_journal_close(struct rec_info *rec, struct presto_file_set *fset,
                      struct file *file, struct dentry *dentry,
-		     struct presto_version *new_file_ver)
+                     struct presto_version *old_file_ver,
+                     struct presto_version *new_file_ver)
 {
-        int opcode = PRESTO_OP_CLOSE;
+        int opcode = KML_OPCODE_CLOSE;
         struct presto_file_data *fd;
-        char *buffer;
-        char *path;
-        __u64 ino;
-        __u32 pathlen;
-        __u32 generation;
-        int size;
-        char *logrecord;
-        char record[292];
+        char *buffer, *path, *logrecord, record[316];
         struct dentry *root;
-        int error;
+        int error, size, i;
+        __u32 pathlen, generation;
+        __u64 ino;
         __u32 open_fsuid;
         __u32 open_fsgid;
         __u32 open_ngroups;
@@ -1715,7 +2120,6 @@
         __u32 open_mode;
         __u32 open_uid;
         __u32 open_gid;
-        int i;
 
         ENTRY;
 
@@ -1724,18 +2128,19 @@
                 return 0;
         }
 
-        if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) ) {
+        if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) 
+            || ((dentry->d_parent != dentry) && list_empty(&dentry->d_hash))) {
                 EXIT;
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         fd = (struct presto_file_data *)file->private_data;
         if (fd) {
                 open_ngroups = fd->fd_ngroups;
                 for (i = 0; i < fd->fd_ngroups; i++)
-			open_groups[i] = (__u32) fd->fd_groups[i];
+                        open_groups[i] = (__u32) fd->fd_groups[i];
                 open_mode = fd->fd_mode;
                 open_uid = fd->fd_uid;
                 open_gid = fd->fd_gid;
@@ -1744,7 +2149,7 @@
         } else {
                 open_ngroups = current->ngroups;
                 for (i=0; i<current->ngroups; i++)
-			open_groups[i] =  (__u32) current->groups[i]; 
+                        open_groups[i] =  (__u32) current->groups[i]; 
                 open_mode = dentry->d_inode->i_mode;
                 open_uid = dentry->d_inode->i_uid;
                 open_gid = dentry->d_inode->i_gid;
@@ -1758,13 +2163,12 @@
         generation = cpu_to_le32(dentry->d_inode->i_generation);
         size =  sizeof(__u32) * open_ngroups +
                 sizeof(open_mode) + sizeof(open_uid) + sizeof(open_gid) +
-                sizeof(struct journal_prefix) + sizeof(*new_file_ver) +
-                sizeof(ino) + sizeof(generation) + sizeof(pathlen) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_prefix_hdr) + sizeof(*old_file_ver) +
+                sizeof(*new_file_ver) + sizeof(ino) + sizeof(generation) +
+                sizeof(pathlen) + sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen));
@@ -1775,7 +2179,8 @@
         logrecord = logit(logrecord, &open_mode, sizeof(open_mode));
         logrecord = logit(logrecord, &open_uid, sizeof(open_uid));
         logrecord = logit(logrecord, &open_gid, sizeof(open_gid));
-        logrecord = logit(logrecord, new_file_ver, sizeof(*new_file_ver));
+        logrecord = log_version(logrecord, old_file_ver);
+        logrecord = log_version(logrecord, new_file_ver);
         logrecord = logit(logrecord, &ino, sizeof(ino));
         logrecord = logit(logrecord, &generation, sizeof(generation));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
@@ -1796,12 +2201,10 @@
                          __u64 ino,     __u32 generation, 
                          struct presto_version *new_file_ver)
 {
-        int opcode = PRESTO_OP_CLOSE;
-        int size;
-        char *logrecord;
-        char record[292];
+        int opcode = KML_OPCODE_CLOSE;
+        char *logrecord, record[292];
         struct dentry *root;
-        int error;
+        int error, size;
 
         ENTRY;
 
@@ -1810,24 +2213,23 @@
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         size =  sizeof(__u32) * ngroups + 
-                sizeof(struct journal_prefix) + sizeof(*new_file_ver) +
+                sizeof(struct kml_prefix_hdr) + sizeof(*new_file_ver) +
                 sizeof(ino) + sizeof(generation) + 
                 sizeof(le32_to_cpu(pathlen)) +
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         rec->size = size + size_round(le32_to_cpu(pathlen));
 
         logrecord = journal_log_prefix_with_groups(record, opcode, rec,
                                                    ngroups, groups);
-        logrecord = logit(logrecord, new_file_ver, sizeof(*new_file_ver));
+        logrecord = log_version(logrecord, new_file_ver);
         logrecord = logit(logrecord, &ino, sizeof(ino));
         logrecord = logit(logrecord, &generation, sizeof(generation));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
@@ -1862,7 +2264,7 @@
                 __u64 lml_offset;
         } close_rec; 
         struct file *file = fset->fset_lml.fd_file;
-        struct journal_prefix prefix;
+        struct kml_prefix_hdr prefix;
         int rc = 0;
         ENTRY;
 
@@ -1878,11 +2280,11 @@
                           sizeof(prefix), &read_offset);
         if ( rc != sizeof(prefix) ) {
                 EXIT;
-                printk("presto_complete_lml: ioerror - 1, tell Peter\n");
+                CERROR("presto_complete_lml: ioerror - 1, tell Peter\n");
                 return -EIO;
         }
 
-        if ( prefix.opcode == PRESTO_OP_NOOP ) {
+        if ( prefix.opcode == KML_OPCODE_NOOP ) {
                 lml_offset += prefix.len; 
                 goto again; 
         }
@@ -1891,7 +2293,7 @@
                           prefix.ngroups * sizeof(__u32), &read_offset); 
         if ( rc != prefix.ngroups * sizeof(__u32) ) {
                 EXIT;
-                printk("presto_complete_lml: ioerror - 2, tell Peter\n");
+                CERROR("presto_complete_lml: ioerror - 2, tell Peter\n");
                 return -EIO;
         }
 
@@ -1899,7 +2301,7 @@
                           sizeof(close_rec), &read_offset); 
         if ( rc != sizeof(close_rec) ) {
                 EXIT;
-                printk("presto_complete_lml: ioerror - 3, tell Peter\n");
+                CERROR("presto_complete_lml: ioerror - 3, tell Peter\n");
                 return -EIO;
         }
 
@@ -1914,20 +2316,20 @@
                           le32_to_cpu(close_rec.pathlen), &read_offset); 
         if ( rc != le32_to_cpu(close_rec.pathlen) ) {
                 EXIT;
-                printk("presto_complete_lml: ioerror - 4, tell Peter\n");
+                CERROR("presto_complete_lml: ioerror - 4, tell Peter\n");
                 return -EIO;
         }
         
         handle = presto_trans_start(fset, file->f_dentry->d_inode, 
-                                    PRESTO_OP_RELEASE);
-        if ( !handle ) {
+                                    KML_OPCODE_RELEASE);
+        if ( IS_ERR(handle) ) {
                 EXIT;
                 return -ENOMEM; 
         }
 
         rc = presto_clear_lml_close(fset, lml_offset); 
         if ( rc ) {
-                printk("error during clearing: %d\n", rc);
+                CERROR("error during clearing: %d\n", rc);
                 presto_trans_commit(fset, handle);
                 EXIT; 
                 return rc; 
@@ -1938,7 +2340,7 @@
                                   close_rec.ino, close_rec.generation,
                                   &close_rec.new_file_ver); 
         if ( rc ) {
-                printk("error during rewrite close: %d\n", rc);
+                CERROR("error during rewrite close: %d\n", rc);
                 presto_trans_commit(fset, handle);
                 EXIT; 
                 return rc; 
@@ -1946,7 +2348,7 @@
 
         presto_trans_commit(fset, handle); 
         if ( rc ) { 
-                printk("error during truncation: %d\n", rc);
+                CERROR("error during truncation: %d\n", rc);
                 EXIT; 
                 return rc;
         }
@@ -1973,20 +2375,14 @@
                                  int flags) 
 { 
         int opcode = (buffer == NULL) ? 
-                     PRESTO_OP_DELEXTATTR : 
-                     PRESTO_OP_SETEXTATTR ;
-        char *temp;
-        char *path;
-        __u32 pathlen;
-        int size;
-        char *logrecord;
-        char record[292];
+                     KML_OPCODE_DELEXTATTR : 
+                     KML_OPCODE_SETEXTATTR ;
+        char *temp, *path, *logrecord, record[292];
         struct dentry *root;
-        int error;
+        int error, size;
         __u32 namelen=cpu_to_le32(strnlen(name,PRESTO_EXT_ATTR_NAME_MAX));
         __u32 buflen=(buffer != NULL)? cpu_to_le32(buffer_len): cpu_to_le32(0);
-        __u32 mode;
-
+        __u32 mode, pathlen;
 
         ENTRY;
         if ( presto_no_journal(fset) ) {
@@ -1994,12 +2390,13 @@
                 return 0;
         }
 
-        if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) ) {
+        if (!dentry->d_inode || (dentry->d_inode->i_nlink == 0) 
+            || ((dentry->d_parent != dentry) && list_empty(&dentry->d_hash))) {
                 EXIT;
                 return 0;
         }
 
-        root = fset->fset_mtpt;
+        root = fset->fset_dentry;
 
         BUFF_ALLOC(temp, NULL);
         path = presto_path(dentry, root, temp, PAGE_SIZE);
@@ -2013,15 +2410,14 @@
         mode=cpu_to_le32(dentry->d_inode->i_mode);
 
         size =  sizeof(__u32) * current->ngroups + 
-                sizeof(struct journal_prefix) + 
+                sizeof(struct kml_prefix_hdr) + 
                 2 * sizeof(struct presto_version) +
                 sizeof(flags) + sizeof(mode) + sizeof(namelen) + 
                 sizeof(buflen) + sizeof(pathlen) + 
-                sizeof(struct journal_suffix);
+                sizeof(struct kml_suffix);
 
-        if ( size > sizeof(record) ) {
-                printk("PRESTO: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
-        }
+        if ( size > sizeof(record) )
+                CERROR("InterMezzo: BUFFER OVERFLOW in %s!\n", __FUNCTION__);
 
         rec->is_kml = 1;
         /* Make space for a path, a attr name and value*/
@@ -2036,8 +2432,8 @@
                     size_round(le32_to_cpu(buflen));
 
         logrecord = journal_log_prefix(record, opcode, rec);
-        logrecord = logit(logrecord, ver, sizeof(*ver));
-        logrecord = log_version(logrecord, dentry);
+        logrecord = log_version(logrecord, ver);
+        logrecord = log_dentry_version(logrecord, dentry);
         logrecord = logit(logrecord, &flags, sizeof(flags));
         logrecord = logit(logrecord, &mode, sizeof(flags));
         logrecord = logit(logrecord, &pathlen, sizeof(pathlen));
@@ -2055,4 +2451,3 @@
         return error;
 }
 #endif
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/journal_ext2.c linux.20pre10-ac2/fs/intermezzo/journal_ext2.c
--- linux.20pre10/fs/intermezzo/journal_ext2.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/journal_ext2.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,6 +1,22 @@
-
-/*
- * Intermezzo. (C) 1998 Peter J. Braam
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/types.h>
@@ -18,9 +34,7 @@
 #include <linux/ext2_fs.h> 
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 
 #if defined(CONFIG_EXT2_FS)
 
@@ -48,7 +62,7 @@
                 return ERR_PTR(-ENOSPC);
         }
         
-        if (  (op != PRESTO_OP_UNLINK && op != PRESTO_OP_RMDIR)
+        if (  (op != KML_OPCODE_UNLINK && op != KML_OPCODE_RMDIR)
               && avail_kmlblocks < 6 ) {
                 return ERR_PTR(-ENOSPC);
         }            
@@ -57,10 +71,17 @@
 
 static void presto_e2_trans_commit(struct presto_file_set *fset, void *handle)
 {
-  do {} while (0);
+        do {} while (0);
+}
+
+static int presto_e2_has_all_data(struct inode *inode)
+{
+        BUG();
+        return 0;
 }
 
 struct journal_ops presto_ext2_journal_ops = {
+        tr_all_data: presto_e2_has_all_data,
         tr_avail: presto_e2_freespace,
         tr_start: presto_e2_trans_start,
         tr_commit: presto_e2_trans_commit,
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/journal_ext3.c linux.20pre10-ac2/fs/intermezzo/journal_ext3.c
--- linux.20pre10/fs/intermezzo/journal_ext3.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/journal_ext3.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,10 +1,27 @@
-
-/*
- * Intermezzo. (C) 1998 Peter J. Braam
- * Intermezzo. (C) 2000 Red Hat, Inc.
- * Intermezzo. (C) 2000 Los Alamos National Laboratory
- * Intermezzo. (C) 2000 TurboLinux, Inc.
- * Intermezzo. (C) 2001 Mountain View Data, Inc.
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
+ *  Copyright (C) 2000 Red Hat, Inc.
+ *  Copyright (C) 2000 Los Alamos National Laboratory
+ *  Copyright (C) 2000 TurboLinux, Inc.
+ *  Copyright (C) 2001 Mountain View Data, Inc.
+ *  Copyright (C) 2001 Tacit Networks, Inc. <phil@off.net>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/types.h>
@@ -28,9 +45,7 @@
 #endif
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 
 #if defined(CONFIG_EXT3_FS) || defined (CONFIG_EXT3_FS_MODULE)
 
@@ -85,7 +100,7 @@
                 return ERR_PTR(-ENOSPC);
         }
         
-        if (  (op != PRESTO_OP_UNLINK && op != PRESTO_OP_RMDIR)
+        if (  (op != KML_OPCODE_UNLINK && op != KML_OPCODE_RMDIR)
               && avail_kmlblocks < 6 ) {
                 return ERR_PTR(-ENOSPC);
         }            
@@ -107,52 +122,71 @@
            and operations involving the LML records 
         */
         switch (op) {
-        case PRESTO_OP_TRUNC:
+        case KML_OPCODE_TRUNC:
                 jblocks = one_path_blks + extra_name_blks + trunc_blks
                         + EXT3_DELETE_TRANS_BLOCKS; 
                 break;
-        case PRESTO_OP_RELEASE:
+        case KML_OPCODE_KML_TRUNC:
+                /* Hopefully this is a little better, but I'm still mostly
+                 * guessing here. */
+                /* unlink 1 */
+                jblocks = extra_name_blks + trunc_blks +
+                        EXT3_DELETE_TRANS_BLOCKS + 2; 
+
+                /* unlink 2 */
+                jblocks += extra_name_blks + trunc_blks +
+                        EXT3_DELETE_TRANS_BLOCKS + 2; 
+
+                /* rename 1 */
+                jblocks += 2 * extra_path_blks + trunc_blks + 
+                        2 * EXT3_DATA_TRANS_BLOCKS + 2 + 3;
+
+                /* rename 2 */
+                jblocks += 2 * extra_path_blks + trunc_blks + 
+                        2 * EXT3_DATA_TRANS_BLOCKS + 2 + 3;
+                break;
+        case KML_OPCODE_RELEASE:
                 /* 
                 jblocks = one_path_blks + lml_blks + 2*trunc_blks; 
                 */
                 jblocks = one_path_blks; 
                 break;
-        case PRESTO_OP_SETATTR:
+        case KML_OPCODE_SETATTR:
                 jblocks = one_path_blks + trunc_blks + 1 ; 
                 break;
-        case PRESTO_OP_CREATE:
+        case KML_OPCODE_CREATE:
                 jblocks = one_path_blks + trunc_blks 
                         + EXT3_DATA_TRANS_BLOCKS + 3 + 2; 
                 break;
-        case PRESTO_OP_LINK:
+        case KML_OPCODE_LINK:
                 jblocks = one_path_blks + trunc_blks 
                         + EXT3_DATA_TRANS_BLOCKS + 2; 
                 break;
-        case PRESTO_OP_UNLINK:
+        case KML_OPCODE_UNLINK:
                 jblocks = one_path_blks + extra_name_blks + trunc_blks
                         + EXT3_DELETE_TRANS_BLOCKS + 2; 
                 break;
-        case PRESTO_OP_SYMLINK:
+        case KML_OPCODE_SYMLINK:
                 jblocks = one_path_blks + extra_path_blks + trunc_blks
                         + EXT3_DATA_TRANS_BLOCKS + 5; 
                 break;
-        case PRESTO_OP_MKDIR:
+        case KML_OPCODE_MKDIR:
                 jblocks = one_path_blks + trunc_blks
                         + EXT3_DATA_TRANS_BLOCKS + 4 + 2;
                 break;
-        case PRESTO_OP_RMDIR:
+        case KML_OPCODE_RMDIR:
                 jblocks = one_path_blks + extra_name_blks + trunc_blks
                         + EXT3_DELETE_TRANS_BLOCKS + 1; 
                 break;
-        case PRESTO_OP_MKNOD:
+        case KML_OPCODE_MKNOD:
                 jblocks = one_path_blks + trunc_blks + 
                         EXT3_DATA_TRANS_BLOCKS + 3 + 2;
                 break;
-        case PRESTO_OP_RENAME:
+        case KML_OPCODE_RENAME:
                 jblocks = one_path_blks + extra_path_blks + trunc_blks + 
                         2 * EXT3_DATA_TRANS_BLOCKS + 2 + 3;
                 break;
-        case PRESTO_OP_WRITE:
+        case KML_OPCODE_WRITE:
                 jblocks = one_path_blks; 
                 /*  add this when we can wrap our transaction with 
                     that of ext3_file_write (ordered writes)
@@ -164,7 +198,8 @@
                 return NULL;
         }
 
-        CDEBUG(D_JOURNAL, "creating journal handle (%d blocks)\n", jblocks);
+        CDEBUG(D_JOURNAL, "creating journal handle (%d blocks) for op %d\n",
+               jblocks, op);
         /* journal_start/stop does not do its own locking while updating
          * the handle/transaction information. Hence we create our own
          * critical section to protect these calls. -SHP
@@ -175,7 +210,7 @@
         return handle;
 }
 
-void presto_e3_trans_commit(struct presto_file_set *fset, void *handle)
+static void presto_e3_trans_commit(struct presto_file_set *fset, void *handle)
 {
         if ( presto_no_journal(fset) || !handle)
                 return;
@@ -186,7 +221,7 @@
         unlock_kernel();
 }
 
-void presto_e3_journal_file_data(struct inode *inode)
+static void presto_e3_journal_file_data(struct inode *inode)
 {
 #ifdef EXT3_JOURNAL_DATA_FL
         inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL;
@@ -195,11 +230,56 @@
 #endif
 }
 
+/* The logic here is a slightly modified version of ext3/inode.c:block_to_path
+ */
+static int presto_e3_has_all_data(struct inode *inode)
+{
+        int ptrs = EXT3_ADDR_PER_BLOCK(inode->i_sb);
+        int ptrs_bits = EXT3_ADDR_PER_BLOCK_BITS(inode->i_sb);
+        const long direct_blocks = EXT3_NDIR_BLOCKS,
+                indirect_blocks = ptrs,
+                double_blocks = (1 << (ptrs_bits * 2));
+        long block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
+                inode->i_sb->s_blocksize_bits;
+
+        ENTRY;
+
+        if (inode->i_size == 0) {
+                EXIT;
+                return 1;
+        }
+
+        if (block < direct_blocks) {
+                /* No indirect blocks, no problem. */
+        } else if (block < indirect_blocks + direct_blocks) {
+                block++;
+        } else if (block < double_blocks + indirect_blocks + direct_blocks) {
+                block += 2;
+        } else if (((block - double_blocks - indirect_blocks - direct_blocks)
+                    >> (ptrs_bits * 2)) < ptrs) {
+                block += 3;
+        }
+
+        block *= (inode->i_sb->s_blocksize / 512);
+
+        CDEBUG(D_CACHE, "Need %ld blocks, have %ld.\n", block, inode->i_blocks);
+
+        if (block > inode->i_blocks) {
+                EXIT;
+                return 0;
+        }
+
+        EXIT;
+        return 1;
+}
+
 struct journal_ops presto_ext3_journal_ops = {
-        tr_avail: presto_e3_freespace,
-        tr_start:  presto_e3_trans_start,
-        tr_commit: presto_e3_trans_commit,
-        tr_journal_data: presto_e3_journal_file_data
+        .tr_all_data     = presto_e3_has_all_data,
+        .tr_avail        = presto_e3_freespace,
+        .tr_start        =  presto_e3_trans_start,
+        .tr_commit       = presto_e3_trans_commit,
+        .tr_journal_data = presto_e3_journal_file_data,
+        .tr_ilookup      = presto_iget_ilookup
 };
 
 #endif /* CONFIG_EXT3_FS */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/journal_obdfs.c linux.20pre10-ac2/fs/intermezzo/journal_obdfs.c
--- linux.20pre10/fs/intermezzo/journal_obdfs.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/journal_obdfs.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,10 +1,26 @@
-
-/*
- * Intermezzo. (C) 1998 Peter J. Braam
- * Intermezzo. (C) 2000 Red Hat, Inc.
- * Intermezzo. (C) 2000 Los Alamos National Laboratory
- * Intermezzo. (C) 2000 TurboLinux, Inc.
- * Intermezzo. (C) 2001 Mountain View Data, Inc.
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
+ *  Copyright (C) 2000 Red Hat, Inc.
+ *  Copyright (C) 2000 Los Alamos National Laboratory
+ *  Copyright (C) 2000 TurboLinux, Inc.
+ *  Copyright (C) 2001 Mountain View Data, Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/types.h>
@@ -25,9 +41,7 @@
 #endif
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 
 #ifdef CONFIG_OBDFS_FS
 
@@ -171,10 +185,10 @@
 }
 
 struct journal_ops presto_obdfs_journal_ops = {
-        tr_avail: presto_obdfs_freespace,
-        tr_start:  presto_obdfs_trans_start,
-        tr_commit: presto_obdfs_trans_commit,
-        tr_journal_data: presto_obdfs_journal_file_data
+        .tr_avail        = presto_obdfs_freespace,
+        .tr_start        =  presto_obdfs_trans_start,
+        .tr_commit       = presto_obdfs_trans_commit,
+        .tr_journal_data = presto_obdfs_journal_file_data
 };
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/journal_reiserfs.c linux.20pre10-ac2/fs/intermezzo/journal_reiserfs.c
--- linux.20pre10/fs/intermezzo/journal_reiserfs.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/journal_reiserfs.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,10 +1,26 @@
-
-/*
- * Intermezzo. (C) 1998 Peter J. Braam
- * Intermezzo. (C) 2000 Red Hat, Inc.
- * Intermezzo. (C) 2000 Los Alamos National Laboratory
- * Intermezzo. (C) 2000 TurboLinux, Inc.
- * Intermezzo. (C) 2001 Mountain View Data, Inc.
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
+ *  Copyright (C) 2000 Red Hat, Inc.
+ *  Copyright (C) 2000 Los Alamos National Laboratory
+ *  Copyright (C) 2000 TurboLinux, Inc.
+ *  Copyright (C) 2001 Mountain View Data, Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #include <linux/types.h>
@@ -28,9 +44,8 @@
 #endif
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
+
 #if defined(CONFIG_REISERFS_FS) || defined(CONFIG_REISERFS_FS_MODULE)
 
 
@@ -54,9 +69,9 @@
         __u32 avail_kmlblocks;
 	struct reiserfs_transaction_handle *th ;
 
-	PRESTO_ALLOC(th, struct reiserfs_transaction_handle *, sizeof(*th));
+	PRESTO_ALLOC(th, sizeof(*th));
 	if (!th) { 
-		printk("presto: No memory for trans handle\n");
+		CERROR("presto: No memory for trans handle\n");
 		return NULL;
 	}
 
@@ -83,23 +98,24 @@
         CDEBUG(D_JOURNAL, "creating journal handle (%d blocks)\n", jblocks);
 
 	lock_kernel();
-	//journal_begin(th, inode->i_sb, jblocks);
+	journal_begin(th, inode->i_sb, jblocks);
 	unlock_kernel();
 	return th; 
 }
 
-void presto_reiserfs_trans_commit(struct presto_file_set *fset, void *handle)
+static void presto_reiserfs_trans_commit(struct presto_file_set *fset,
+                                         void *handle)
 {
 	int jblocks;
 	jblocks = 3 + JOURNAL_PER_BALANCE_CNT * 4;
 	
 	lock_kernel();
-	//journal_end(handle, fset->fset_cache->cache_sb, jblocks);
+	journal_end(handle, fset->fset_cache->cache_sb, jblocks);
 	unlock_kernel();
 	PRESTO_FREE(handle, sizeof(struct reiserfs_transaction_handle));
 }
 
-void presto_reiserfs_journal_file_data(struct inode *inode)
+static void presto_reiserfs_journal_file_data(struct inode *inode)
 {
 #ifdef EXT3_JOURNAL_DATA_FL
         inode->u.ext3_i.i_flags |= EXT3_JOURNAL_DATA_FL;
@@ -108,11 +124,18 @@
 #endif
 }
 
+static int presto_reiserfs_has_all_data(struct inode *inode)
+{
+        BUG();
+        return 0;
+}
+
 struct journal_ops presto_reiserfs_journal_ops = {
-        tr_avail: presto_reiserfs_freespace,
-        tr_start:  presto_reiserfs_trans_start,
-        tr_commit: presto_reiserfs_trans_commit,
-        tr_journal_data: presto_reiserfs_journal_file_data
+        .tr_all_data     = presto_reiserfs_has_all_data,
+        .tr_avail        = presto_reiserfs_freespace,
+        .tr_start        = presto_reiserfs_trans_start,
+        .tr_commit       = presto_reiserfs_trans_commit,
+        .tr_journal_data = presto_reiserfs_journal_file_data
 };
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/journal_tmpfs.c linux.20pre10-ac2/fs/intermezzo/journal_tmpfs.c
--- linux.20pre10/fs/intermezzo/journal_tmpfs.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/journal_tmpfs.c	2002-10-10 23:24:51.000000000 +0100
@@ -0,0 +1,109 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
+ *  Copyright (C) 2000 Red Hat, Inc.
+ *  Copyright (C) 2000 Los Alamos National Laboratory
+ *  Copyright (C) 2000 TurboLinux, Inc.
+ *  Copyright (C) 2001 Mountain View Data, Inc.
+ *  Copyright (C) 2001 Tacit Networks, Inc. <phil@off.net>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/param.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/locks.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+#include <linux/string.h>
+#include <linux/smp_lock.h>
+#if defined(CONFIG_TMPFS)
+#include <linux/jbd.h>
+#if defined(CONFIG_EXT3)
+#include <linux/ext3_fs.h>
+#include <linux/ext3_jbd.h>
+#endif
+#endif
+
+#include <linux/intermezzo_fs.h>
+#include <linux/intermezzo_psdev.h>
+
+#if defined(CONFIG_TMPFS)
+
+/* space requirements: 
+   presto_do_truncate: 
+        used to truncate the KML forward to next fset->chunksize boundary
+          - zero partial block
+          - update inode
+   presto_write_record: 
+        write header (< one block) 
+        write one path (< MAX_PATHLEN) 
+        possibly write another path (< MAX_PATHLEN)
+        write suffix (< one block) 
+   presto_update_last_rcvd
+        write one block
+*/
+
+static loff_t presto_tmpfs_freespace(struct presto_cache *cache,
+                                         struct super_block *sb)
+{
+        return (1<<30);
+}
+
+/* start the filesystem journal operations */
+static void *presto_tmpfs_trans_start(struct presto_file_set *fset, 
+                                   struct inode *inode, 
+                                   int op)
+{
+        return (void *)1; 
+}
+
+static void presto_tmpfs_trans_commit(struct presto_file_set *fset, void *handle)
+{
+        return;
+}
+
+static void presto_tmpfs_journal_file_data(struct inode *inode)
+{
+        return; 
+}
+
+/* The logic here is a slightly modified version of ext3/inode.c:block_to_path
+ */
+static int presto_tmpfs_has_all_data(struct inode *inode)
+{
+        return 0;
+}
+
+struct journal_ops presto_tmpfs_journal_ops = {
+        tr_all_data: presto_tmpfs_has_all_data,
+        tr_avail: presto_tmpfs_freespace,
+        tr_start:  presto_tmpfs_trans_start,
+        tr_commit: presto_tmpfs_trans_commit,
+        tr_journal_data: presto_tmpfs_journal_file_data,
+        tr_ilookup: presto_tmpfs_ilookup,
+        tr_add_ilookup: presto_add_ilookup_dentry
+};
+
+#endif /* CONFIG_EXT3_FS */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/journal_xfs.c linux.20pre10-ac2/fs/intermezzo/journal_xfs.c
--- linux.20pre10/fs/intermezzo/journal_xfs.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/journal_xfs.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,7 +1,23 @@
-
-/*
- *  * Intermezzo. (C) 1998 Peter J. Braam
- *   */
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
 
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -15,13 +31,13 @@
 #include <asm/segment.h>
 #include <asm/uaccess.h>
 #include <linux/string.h>
+#if 0
+/* XFS Support not there yet */
 #ifdef CONFIG_FS_XFS
 #include <linux/xfs_fs.h>
 #endif
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 #include <linux/intermezzo_journal.h>
 
 #if 0
@@ -120,18 +136,27 @@
 	xfs_trans_stop(handle);
 }
 
-void presto_xfs_journal_file_data(struct inode *inode)
+static void presto_xfs_journal_file_data(struct inode *inode)
 {
         return; 
 }
 
+static int presto_xfs_has_all_data(struct inode *inode)
+{
+        BUG();
+        return 0;
+}
+
 struct journal_ops presto_xfs_journal_ops = {
-        tr_avail: presto_xfs_freespace,
-        tr_start:  presto_xfs_trans_start,
-        tr_commit: presto_xfs_trans_commit,
-        tr_journal_data: presto_xfs_journal_file_data
+        .tr_all_data     = presto_xfs_has_all_data,
+        .tr_avail        = presto_xfs_freespace,
+        .tr_start        = presto_xfs_trans_start,
+        .tr_commit       = presto_xfs_trans_commit,
+        .tr_journal_data = presto_xfs_journal_file_data
 };
 
-#endif /* CONFIG_XFS_FS */
+#endif
 
 
+#endif /* CONFIG_XFS_FS */
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/kml.c linux.20pre10-ac2/fs/intermezzo/kml.c
--- linux.20pre10/fs/intermezzo/kml.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/kml.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,214 +0,0 @@
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <asm/uaccess.h>
-
-#include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
-#include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
-
-static struct presto_file_set * kml_getfset (char *path)
-{
-        return presto_path2fileset(path);
-}
-
-/* Send the KML buffer and related volume info into kernel */
-int begin_kml_reint (struct file *file, unsigned long arg)
-{
-        struct {
-                char *volname;
-                unsigned int namelen;  
-                char *recbuf;
-                unsigned int reclen;     /* int   newpos; */
-        } input;
-        struct kml_fsdata *kml_fsdata = NULL;
-        struct presto_file_set *fset = NULL;
-        char   *path;
-        int    error;
-
-        ENTRY;
-        /* allocate buffer & copy it to kernel space */
-        if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                EXIT;
-                return -EFAULT;
-        }
-
-	if (input.namelen > PATH_MAX)
-	{
-		EXIT;
-		return -EINVAL;
-	}
-		
-        if (input.reclen > kml_fsdata->kml_maxsize)
-                return -ENOMEM; /* we'll find solution to this in the future */
-
-        PRESTO_ALLOC(path, char *, input.namelen + 1);
-        if ( !path ) {
-                EXIT;
-                return -ENOMEM;
-        }
-        if (copy_from_user(path, input.volname, input.namelen)) {
-                PRESTO_FREE(path, input.namelen + 1);
-                EXIT;
-                return -EFAULT;
-        }
-        path[input.namelen] = '\0';
-        fset = kml_getfset (path);
-        PRESTO_FREE(path, input.namelen + 1);
-
-        kml_fsdata = FSET_GET_KMLDATA(fset);
-        /* read the buf from user memory here */
-        if (copy_from_user(kml_fsdata->kml_buf, input.recbuf, input.reclen)) {
-                EXIT;
-                return -EFAULT;
-        }
-        kml_fsdata->kml_len = input.reclen;
-
-        decode_kmlrec (&kml_fsdata->kml_reint_cache,
-                        kml_fsdata->kml_buf, kml_fsdata->kml_len);
-
-        kml_fsdata->kml_reint_current = kml_fsdata->kml_reint_cache.next;
-        kml_fsdata->kml_reintpos = 0;
-        kml_fsdata->kml_count = 0;
-        return 0;
-}
-
-/* DO_KML_REINT  */
-int do_kml_reint (struct file *file, unsigned long arg)
-{
-        struct {
-                char *volname;
-                unsigned int namelen;  
-                char *path;
-                unsigned int pathlen;
-                int recno;
-                int offset;
-                int len;
-                int generation;
-                __u64 ino;
-        } input;
-        int error;
-        char   *path;
-        struct kml_rec *close_rec;
-        struct kml_fsdata *kml_fsdata;
-        struct presto_file_set *fset;
-
-        ENTRY;
-        if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                EXIT;
-                return -EFAULT;
-        }
-        
-        if(input.namelen > PATH_MAX || input.pathlen > PATH_MAX)
-        {
-        	EXIT;
-        	return -EFAULT;
-        }
-        
-        PRESTO_ALLOC(path, char *, input.namelen + 1);
-        if ( !path ) {
-                EXIT;
-                return -ENOMEM;
-        }
-        if (copy_from_user(path, input.volname, input.namelen)) {
-                PRESTO_FREE(path, input.namelen + 1);
-                EXIT;
-                return -EFAULT;
-        }
-        path[input.namelen] = '\0';
-        fset = kml_getfset (path);
-        PRESTO_FREE(path, input.namelen + 1);
-
-        kml_fsdata = FSET_GET_KMLDATA(fset);
-
-        error = kml_reintbuf(kml_fsdata, 
-                fset->fset_mtpt->d_name.name, 
-                &close_rec);
-
-        if (error == KML_CLOSE_BACKFETCH && close_rec != NULL) {
-                struct kml_close *close = &close_rec->rec_kml.close;
-                input.ino = close->ino;
-                input.generation = close->generation;
-                if (strlen (close->path) + 1 < input.pathlen) {
-                        strcpy (input.path, close->path);
-                        input.pathlen = strlen (close->path) + 1;
-                        input.recno = close_rec->rec_tail.recno;
-                        input.offset = close_rec->rec_kml_offset;
-                        input.len = close_rec->rec_size;
-                        input.generation = close->generation;
-                        input.ino = close->ino;
-                }
-                else {
-                        CDEBUG(D_KML, "KML_DO_REINT::no space to save:%d < %d",
-                                strlen (close->path) + 1, input.pathlen);
-                        error = -ENOMEM;
-                }
-                if (copy_to_user((char *)arg, &input, sizeof (input)))
-			return -EFAULT;
-        }
-        return error;
-}
-
-/* END_KML_REINT */
-int end_kml_reint (struct file *file, unsigned long arg)
-{
-        /* Free KML buffer and related volume info */
-        struct {
-                char *volname;
-                unsigned int namelen;  
-#if 0
-                int   count; 
-                int   newpos; 
-#endif
-        } input;
-        struct presto_file_set *fset = NULL;
-        struct kml_fsdata *kml_fsdata = NULL;
-        int error;
-        char *path;
-
-        ENTRY;
-        if (copy_from_user(&input, (char *)arg, sizeof(input))) { 
-               EXIT;
-               return -EFAULT;
-        }
-
-	if (input.namelen > PATH_MAX)
-	{
-		EXIT;
-		return -EFAULT;
-	}
-	
-        PRESTO_ALLOC(path, char *, input.namelen + 1);
-        if ( !path ) {
-                EXIT;
-                return -ENOMEM;
-        }
-        if (copy_from_user(path, input.volname, input.namelen)) {
-        if ( error ) {
-                PRESTO_FREE(path, input.namelen + 1);
-                EXIT;
-                return -EFAULT;
-        }
-        path[input.namelen] = '\0';
-        fset = kml_getfset (path);
-        PRESTO_FREE(path, input.namelen + 1);
-
-        kml_fsdata = FSET_GET_KMLDATA(fset);
-        delete_kmlrec (&kml_fsdata->kml_reint_cache);
-
-        /* kml reint support */
-        kml_fsdata->kml_reint_current = NULL;
-        kml_fsdata->kml_len = 0;
-        kml_fsdata->kml_reintpos = 0;
-        kml_fsdata->kml_count = 0;
-#if 0
-        input.newpos = kml_upc->newpos;
-        input.count = kml_upc->count;
-        if (copy_to_user((char *)arg, &input, sizeof (input)))
-		return -EFAULT;
-#endif
-        return error;
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/kml_decode.c linux.20pre10-ac2/fs/intermezzo/kml_decode.c
--- linux.20pre10/fs/intermezzo/kml_decode.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/kml_decode.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,1017 +0,0 @@
-/*
- * KML Decoding
- *
- * Copryright (C) 1996 Arthur Ma <arthur.ma@mountainviewdata.com> 
- *
- * Copyright (C) 2001 Mountainview Data, Inc.
- */
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/mm.h>
-#include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_kml.h>
-
-static int size_round (int val);
-static int unpack_create (struct kml_create *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_open (struct kml_open *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_symlink (struct kml_symlink *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_mknod (struct kml_mknod *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_link (struct kml_link *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_rename (struct kml_rename *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_unlink (struct kml_unlink *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_rmdir (struct kml_rmdir *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_setattr (struct kml_setattr *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_close (struct kml_close *rec, char *buf,
-                                int pos, int *rec_offs);
-static int unpack_mkdir (struct kml_mkdir *rec, char *buf,
-                                int pos, int *rec_offs);
-
-#if 0
-static int unpack_endmark (struct kml_endmark *rec, char *buf,
-                                int pos, int *rec_offs);
-static void print_kml_endmark (struct kml_endmark *rec);
-#endif
-
-static int kml_unpack (char *kml_buf, int rec_size, int kml_offset,
-                        struct kml_rec **newrec);
-static char *kml_version (struct presto_version *ver);
-static void print_kml_prefix (struct big_journal_prefix *head);
-static void print_kml_create (struct kml_create *rec);
-static void print_kml_mkdir (struct kml_mkdir *rec);
-static void print_kml_unlink (struct kml_unlink *rec);
-static void print_kml_rmdir (struct kml_rmdir *rec);
-static void print_kml_close (struct kml_close *rec);
-static void print_kml_symlink (struct kml_symlink *rec);
-static void print_kml_rename (struct kml_rename *rec);
-static void print_kml_setattr (struct kml_setattr *rec);
-static void print_kml_link (struct kml_link *rec);
-static void print_kml_mknod (struct kml_mknod *rec);
-static void print_kml_open (struct kml_open *rec);
-static void print_kml_suffix (struct journal_suffix *tail);
-static char *readrec (char *recbuf, int reclen, int pos, int *size);
-
-#define  KML_PREFIX_WORDS           8
-static int kml_unpack (char *kml_buf, int rec_size, int kml_offset, 
-                        struct kml_rec **newrec)
-{
-        struct kml_rec  *rec;
-        char            *p;
-        int             pos, rec_offs;
-        int             error;
-
-        ENTRY;
-        if (rec_size < sizeof (struct journal_prefix) +
-                       sizeof (struct journal_suffix))
-                return -EBADF;
-
-        PRESTO_ALLOC(rec, struct kml_rec *, sizeof (struct kml_rec));
-        if (rec == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-        rec->rec_kml_offset = kml_offset;
-        rec->rec_size = rec_size;
-        p = kml_buf;
-        p = dlogit (&rec->rec_head, p, KML_PREFIX_WORDS * sizeof (int));
-        p = dlogit (&rec->rec_head.groups, p, 
-                        sizeof (int) * rec->rec_head.ngroups);
-
-        pos = sizeof (struct journal_prefix) + 
-                        sizeof (int) * rec->rec_head.ngroups;
-        switch (rec->rec_head.opcode)
-        {
-                case KML_CREATE:
-                        error = unpack_create (&rec->rec_kml.create, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_MKDIR:
-                        error = unpack_mkdir (&rec->rec_kml.mkdir, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_UNLINK:
-                        error = unpack_unlink (&rec->rec_kml.unlink, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_RMDIR:
-                        error = unpack_rmdir (&rec->rec_kml.rmdir, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_CLOSE:
-                        error = unpack_close (&rec->rec_kml.close, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_SYMLINK:
-                        error = unpack_symlink (&rec->rec_kml.symlink, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_RENAME:
-                        error = unpack_rename (&rec->rec_kml.rename, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_SETATTR:
-                        error = unpack_setattr (&rec->rec_kml.setattr, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_LINK:
-                        error = unpack_link (&rec->rec_kml.link, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_OPEN:
-                        error = unpack_open (&rec->rec_kml.open, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-                case KML_MKNOD:
-                        error = unpack_mknod (&rec->rec_kml.mknod, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-#if 0
-                case KML_ENDMARK:
-                        error = unpack_endmark (&rec->rec_kml.endmark, 
-                                        kml_buf, pos, &rec_offs);
-                        break;
-#endif
-                default:
-                        CDEBUG (D_KML, "wrong opcode::%u\n", 
-                                        rec->rec_head.opcode);
-                        EXIT;
-                        return -EINVAL;
-        } 
-        if (error) {
-                PRESTO_FREE (rec, sizeof (struct kml_rec));
-                return -EINVAL;
-        }
-        p = kml_buf + rec_offs;
-        p = dlogit (&rec->rec_tail, p, sizeof (struct journal_suffix));
-        memset (&rec->kml_optimize, 0, sizeof (struct kml_optimize));
-        *newrec = rec;
-        EXIT;
-        return 0;
-}
-
-static int size_round (int val)
-{
-        return (val + 3) & (~0x3);
-}
-
-static int unpack_create (struct kml_create *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 88;
-        int pathlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->mode, p, sizeof (int));
-        p = dlogit (&rec->uid, p, sizeof (int));
-        p = dlogit (&rec->gid, p, sizeof (int));
-        p = dlogit (&pathlen, p, sizeof (int));
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->path = q;
-
-        *rec_offs = pos + unpack_size + size_round(pathlen);
-        EXIT;
-        return 0;
-}
-
-static int unpack_open (struct kml_open *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        *rec_offs = pos;
-        return 0;
-}
-
-static int unpack_symlink (struct kml_symlink *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 88;
-        int pathlen, targetlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->uid, p, sizeof (int));
-        p = dlogit (&rec->gid, p, sizeof (int));
-        p = dlogit (&pathlen, p, sizeof (int));
-        p = dlogit (&targetlen, p, sizeof (int));
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->sourcepath = q;
-
-        PRESTO_ALLOC(q, char *, targetlen + 1);
-        if (q == NULL) {
-                PRESTO_FREE (rec->sourcepath, pathlen + 1);
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, targetlen);
-        q[targetlen] = '\0';
-        rec->targetpath = q;
-
-        *rec_offs = pos + unpack_size + size_round(pathlen) +
-                        size_round(targetlen);
-        EXIT;
-        return 0;
-}
-
-static int unpack_mknod (struct kml_mknod *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 96;
-        int pathlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->mode, p, sizeof (int));
-        p = dlogit (&rec->uid, p, sizeof (int));
-        p = dlogit (&rec->gid, p, sizeof (int));
-        p = dlogit (&rec->major, p, sizeof (int));
-        p = dlogit (&rec->minor, p, sizeof (int));
-        p = dlogit (&pathlen, p, sizeof (int));
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->path = q;
-
-        *rec_offs = pos + unpack_size + size_round(pathlen);
-        EXIT;
-        return 0;
-}
-
-static int unpack_link (struct kml_link *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 80;
-        int pathlen, targetlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version));
-        p = dlogit (&pathlen, p, sizeof (int));
-        p = dlogit (&targetlen, p, sizeof (int));
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->sourcepath = q;
-        p += size_round (pathlen);
-
-        PRESTO_ALLOC(q, char *, targetlen + 1);
-        if (q == NULL) {
-                PRESTO_FREE (rec->sourcepath, pathlen + 1);
-                EXIT;
-                return -ENOMEM;
-        }
-        memcpy (q, p, targetlen);
-        q[targetlen] = '\0';
-        rec->targetpath = q;
-
-        *rec_offs = pos + unpack_size + size_round(pathlen) +
-                        size_round(targetlen);
-        EXIT;
-        return 0;
-}
-
-static int unpack_rename (struct kml_rename *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 104;
-        int pathlen, targetlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->old_objectv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_tgtv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->old_tgtv, p, sizeof (struct presto_version));
-        p = dlogit (&pathlen, p, sizeof (int));
-        p = dlogit (&targetlen, p, sizeof (int));
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->sourcepath = q;
-        p += size_round (pathlen);
-
-        PRESTO_ALLOC(q, char *, targetlen + 1);
-        if (q == NULL) {
-                PRESTO_FREE (rec->sourcepath, pathlen + 1);
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, targetlen);
-        q[targetlen] = '\0';
-        rec->targetpath = q;
-
-        *rec_offs = pos + unpack_size + size_round(pathlen) +
-                        size_round(targetlen);
-        EXIT;
-        return 0;
-}
-
-static int unpack_unlink (struct kml_unlink *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 80;
-        int pathlen, targetlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->old_tgtv, p, sizeof (struct presto_version));
-        p = dlogit (&pathlen, p, sizeof (int));
-        p = dlogit (&targetlen, p, sizeof (int));
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->path = q;
-        p += size_round (pathlen);
-
-        PRESTO_ALLOC(q, char *, targetlen + 1);
-        if (q == NULL) {
-                PRESTO_FREE (rec->path, pathlen + 1);
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, targetlen);
-        q[targetlen] = '\0';
-        rec->name = q;
-
-        /* fix the presto_journal_unlink problem */
-        *rec_offs = pos + unpack_size + size_round(pathlen) +
-                        size_round(targetlen);
-        EXIT;
-        return 0;
-}
-
-static int unpack_rmdir (struct kml_rmdir *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 80;
-        int pathlen, targetlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->old_tgtv, p, sizeof (struct presto_version));
-        p = dlogit (&pathlen, p, sizeof (int));
-        p = dlogit (&targetlen, p, sizeof (int));
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->path = q;
-        p += size_round (pathlen);
-
-        PRESTO_ALLOC(q, char *, targetlen + 1);
-        if (q == NULL) {
-                PRESTO_FREE (rec->path, pathlen + 1);
-                EXIT;
-                return -ENOMEM;
-        }
-        memcpy (q, p, targetlen);
-        q[targetlen] = '\0';
-        rec->name = q;
-
-        *rec_offs = pos + unpack_size + size_round(pathlen) +
-                        size_round(targetlen);
-        EXIT;
-        return 0;
-}
-
-static int unpack_setattr (struct kml_setattr *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 72;
-        struct kml_attr {
-                __u64   size, mtime, ctime;
-        } objattr;
-        int     valid, mode, uid, gid, flags;
-        int pathlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->old_objectv, p, sizeof (struct presto_version));
-        p = dlogit (&valid, p, sizeof (int));
-        p = dlogit (&mode, p, sizeof (int));
-        p = dlogit (&uid, p, sizeof (int));
-        p = dlogit (&gid, p, sizeof (int));
-        p = dlogit (&objattr, p, sizeof (struct kml_attr));
-        p = dlogit (&flags, p, sizeof (int));
-        p = dlogit (&pathlen, p, sizeof (int));
-
-        rec->iattr.ia_valid = valid;
-        rec->iattr.ia_mode = mode;
-        rec->iattr.ia_uid = uid;
-        rec->iattr.ia_gid = gid;
-        rec->iattr.ia_size = objattr.size;
-        rec->iattr.ia_mtime = objattr.mtime;
-        rec->iattr.ia_ctime = objattr.ctime;
-        rec->iattr.ia_atime = 0;
-        rec->iattr.ia_attr_flags = flags;
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->path = q;
-        p += pathlen;
-
-        *rec_offs = pos + unpack_size + size_round(pathlen);
-        EXIT;
-        return 0;
-}
-
-static int unpack_close (struct kml_close *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 52;
-        int pathlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->open_mode, p, sizeof (int));
-        p = dlogit (&rec->open_uid, p, sizeof (int));
-        p = dlogit (&rec->open_gid, p, sizeof (int));
-        p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->ino, p, sizeof (__u64));
-        p = dlogit (&rec->generation, p, sizeof (int));
-        p = dlogit (&pathlen, p, sizeof (int));
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->path = q;
-        p += pathlen;
-
-        *rec_offs = pos + unpack_size + size_round(pathlen);
-        EXIT;
-        return 0;
-}
-
-static int unpack_mkdir (struct kml_mkdir *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p, *q;
-        int unpack_size = 88;
-        int pathlen;
-
-        ENTRY;
-        p = buf + pos;
-        p = dlogit (&rec->old_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_parentv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->new_objectv, p, sizeof (struct presto_version));
-        p = dlogit (&rec->mode, p, sizeof (int));
-        p = dlogit (&rec->uid, p, sizeof (int));
-        p = dlogit (&rec->gid, p, sizeof (int));
-        p = dlogit (&pathlen, p, sizeof (int));
-
-        PRESTO_ALLOC(q, char *, pathlen + 1);
-        if (q == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        memcpy (q, p, pathlen);
-        q[pathlen] = '\0';
-        rec->path = q;
-        p += pathlen;
-
-        *rec_offs = pos + unpack_size + size_round(pathlen);
-        EXIT;
-        return 0;
-}
-
-#if 0
-static int unpack_endmark (struct kml_endmark *rec, char *buf, 
-                                int pos, int *rec_offs)
-{
-        char *p;
-        p = buf + pos;
-        p = dlogit (&rec->total, p, sizeof (int));
-
-        PRESTO_ALLOC (rec->kop, struct kml_kop_node *, 
-                        sizeof (struct kml_kop_node) * rec->total);
-        if (rec->kop == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-
-        p = dlogit (rec->kop, p, sizeof (struct kml_kop_node) * rec->total);
-
-        *rec_offs = pos + sizeof (int) + sizeof (struct kml_kop_node) * rec->total;
-        return 0;
-}
-#endif
-
-static char *kml_version (struct presto_version *ver)
-{
-        static char buf[256];
-        sprintf (buf, "mt::%lld, ct::%lld, size::%lld",
-                ver->pv_mtime, ver->pv_ctime, ver->pv_size); 
-        return buf;
-}
-
-static void print_kml_prefix (struct big_journal_prefix *head)
-{
-        int i;
-
-        CDEBUG (D_KML, " === KML PREFIX\n");
-        CDEBUG (D_KML, "     len        = %u\n", head->len);
-        CDEBUG (D_KML, "     version    = %u\n", head->version);
-        CDEBUG (D_KML, "     pid        = %u\n", head->pid);
-        CDEBUG (D_KML, "     uid        = %u\n", head->uid);
-        CDEBUG (D_KML, "     fsuid      = %u\n", head->fsuid);
-        CDEBUG (D_KML, "     fsgid      = %u\n", head->fsgid);
-        CDEBUG (D_KML, "     opcode     = %u\n", head->opcode);
-        CDEBUG (D_KML, "     ngroup     = %u",  head->ngroups);
-        for (i = 0; i < head->ngroups; i++)
-                CDEBUG (D_KML, "%u  ",  head->groups[i]);
-        CDEBUG (D_KML, "\n");
-}
-
-static void print_kml_create (struct kml_create *rec)
-{
-        CDEBUG (D_KML, " === CREATE\n");
-        CDEBUG (D_KML, "     path::%s\n", rec->path);
-        CDEBUG (D_KML, "     new_objv::%s\n", kml_version (&rec->new_objectv));
-        CDEBUG (D_KML, "     old_parv::%s\n", kml_version (&rec->old_parentv));
-        CDEBUG (D_KML, "     new_parv::%s\n", kml_version (&rec->new_parentv));
-        CDEBUG (D_KML, "     mode::%o\n", rec->mode);
-        CDEBUG (D_KML, "     uid::%d\n", rec->uid);
-        CDEBUG (D_KML, "     gid::%d\n", rec->gid);
-}
-
-static void print_kml_mkdir (struct kml_mkdir *rec)
-{
-        CDEBUG (D_KML, " === MKDIR\n");
-        CDEBUG (D_KML, "     path::%s\n", rec->path);
-        CDEBUG (D_KML, "     new_objv::%s\n", kml_version (&rec->new_objectv));
-        CDEBUG (D_KML, "     old_parv::%s\n", kml_version (&rec->old_parentv));
-        CDEBUG (D_KML, "     new_parv::%s\n", kml_version (&rec->new_parentv));
-        CDEBUG (D_KML, "     mode::%o\n", rec->mode);
-        CDEBUG (D_KML, "     uid::%d\n", rec->uid);
-        CDEBUG (D_KML, "     gid::%d\n", rec->gid);
-}
-
-static void print_kml_unlink (struct kml_unlink *rec)
-{
-        CDEBUG (D_KML, " === UNLINK\n");
-        CDEBUG (D_KML, "     path::%s/%s\n", rec->path, rec->name);
-        CDEBUG (D_KML, "     old_tgtv::%s\n", kml_version (&rec->old_tgtv));
-        CDEBUG (D_KML, "     old_parv::%s\n", kml_version (&rec->old_parentv));
-        CDEBUG (D_KML, "     new_parv::%s\n", kml_version (&rec->new_parentv));
-}
-
-static void print_kml_rmdir (struct kml_rmdir *rec)
-{
-        CDEBUG (D_KML, " === RMDIR\n");
-        CDEBUG (D_KML, "     path::%s/%s\n", rec->path, rec->name);
-        CDEBUG (D_KML, "     old_tgtv::%s\n", kml_version (&rec->old_tgtv));
-        CDEBUG (D_KML, "     old_parv::%s\n", kml_version (&rec->old_parentv));
-        CDEBUG (D_KML, "     new_parv::%s\n", kml_version (&rec->new_parentv));
-}
-
-static void print_kml_close (struct kml_close *rec)
-{
-        CDEBUG (D_KML, " === CLOSE\n");
-        CDEBUG (D_KML, "     mode::%o\n", rec->open_mode);
-        CDEBUG (D_KML, "     uid::%d\n", rec->open_uid);
-        CDEBUG (D_KML, "     gid::%d\n", rec->open_gid);
-        CDEBUG (D_KML, "     path::%s\n", rec->path);
-        CDEBUG (D_KML, "     new_objv::%s\n", kml_version (&rec->new_objectv));
-        CDEBUG (D_KML, "     ino::%lld\n", rec->ino);
-        CDEBUG (D_KML, "     gen::%u\n", rec->generation);
-}
-
-static void print_kml_symlink (struct kml_symlink *rec)
-{
-        CDEBUG (D_KML, " === SYMLINK\n");
-        CDEBUG (D_KML, "     s-path::%s\n", rec->sourcepath);
-        CDEBUG (D_KML, "     t-path::%s\n", rec->targetpath);
-        CDEBUG (D_KML, "     old_parv::%s\n", kml_version (&rec->old_parentv));
-        CDEBUG (D_KML, "     new_parv::%s\n", kml_version (&rec->new_parentv));
-        CDEBUG (D_KML, "     new_objv::%s\n", kml_version (&rec->new_objectv));
-        CDEBUG (D_KML, "     uid::%d\n", rec->uid);
-        CDEBUG (D_KML, "     gid::%d\n", rec->gid);
-}
-
-static void print_kml_rename (struct kml_rename *rec)
-{
-        CDEBUG (D_KML, " === RENAME\n");
-        CDEBUG (D_KML, "     s-path::%s\n", rec->sourcepath);
-        CDEBUG (D_KML, "     t-path::%s\n", rec->targetpath);
-        CDEBUG (D_KML, "     old_tgtv::%s\n", kml_version (&rec->old_tgtv));
-        CDEBUG (D_KML, "     new_tgtv::%s\n", kml_version (&rec->new_tgtv));
-        CDEBUG (D_KML, "     new_objv::%s\n", kml_version (&rec->new_objectv));
-        CDEBUG (D_KML, "     old_objv::%s\n", kml_version (&rec->old_objectv));
-}
-
-static void print_kml_setattr (struct kml_setattr *rec)
-{
-        CDEBUG (D_KML, " === SETATTR\n");
-        CDEBUG (D_KML, "     path::%s\n", rec->path);
-        CDEBUG (D_KML, "     old_objv::%s\n", kml_version (&rec->old_objectv));
-        CDEBUG (D_KML, "     valid::0x%x\n", rec->iattr.ia_valid);
-        CDEBUG (D_KML, "     mode::%o\n", rec->iattr.ia_mode);
-        CDEBUG (D_KML, "     uid::%d\n", rec->iattr.ia_uid);
-        CDEBUG (D_KML, "     gid::%d\n", rec->iattr.ia_gid);
-        CDEBUG (D_KML, "     size::%u\n", (u32) rec->iattr.ia_size);
-        CDEBUG (D_KML, "     mtime::%u\n", (u32) rec->iattr.ia_mtime);
-        CDEBUG (D_KML, "     ctime::%u\n", (u32) rec->iattr.ia_ctime);
-        CDEBUG (D_KML, "     flags::%u\n", (u32) rec->iattr.ia_attr_flags);
-}
-
-static void print_kml_link (struct kml_link *rec)
-{
-        CDEBUG (D_KML, " === LINK\n");
-        CDEBUG (D_KML, "     path::%s ==> %s\n", rec->sourcepath, rec->targetpath);
-        CDEBUG (D_KML, "     old_parv::%s\n", kml_version (&rec->old_parentv));
-        CDEBUG (D_KML, "     new_obj::%s\n", kml_version (&rec->new_objectv));
-        CDEBUG (D_KML, "     new_parv::%s\n", kml_version (&rec->new_parentv));
-}
-
-static void print_kml_mknod (struct kml_mknod *rec)
-{
-        CDEBUG (D_KML, " === MKNOD\n");
-        CDEBUG (D_KML, "     path::%s\n", rec->path);
-        CDEBUG (D_KML, "     new_obj::%s\n", kml_version (&rec->new_objectv));
-        CDEBUG (D_KML, "     old_parv::%s\n", kml_version (&rec->old_parentv));
-        CDEBUG (D_KML, "     new_parv::%s\n", kml_version (&rec->new_parentv));
-        CDEBUG (D_KML, "     mode::%o\n", rec->mode);
-        CDEBUG (D_KML, "     uid::%d\n", rec->uid);
-        CDEBUG (D_KML, "     gid::%d\n", rec->gid);
-        CDEBUG (D_KML, "     major::%d\n", rec->major);
-        CDEBUG (D_KML, "     minor::%d\n", rec->minor);
-}
-
-static void print_kml_open (struct kml_open *rec)
-{
-        CDEBUG (D_KML, " === OPEN\n");
-}
-
-#if 0
-static void print_kml_endmark (struct kml_endmark *rec)
-{
-        int i;
-        CDEBUG (D_KML, " === ENDMARK\n");
-        CDEBUG (D_KML, "     total::%u\n", rec->total);
-        for (i = 0; i < rec->total; i++)
-        {       
-                CDEBUG (D_KML, "         recno=%ld::flag=%ld,op=%ld, i_ino=%ld, \
-                        i_nlink=%ld\n", (long) rec->kop[i].kml_recno, 
-                        (long) rec->kop[i].kml_flag, (long) rec->kop[i].kml_op, 
-                        (long) rec->kop[i].i_ino, (long) rec->kop[i].i_nlink);
-        }
-}
-#endif
-
-static void print_kml_optimize (struct kml_optimize  *rec)
-{
-        CDEBUG (D_KML, " === OPTIMIZE\n");
-        if (rec->kml_flag == KML_REC_DELETE)
-                CDEBUG (D_KML, "     kml_flag::deleted\n");
-        else
-                CDEBUG (D_KML, "     kml_flag::exist\n");
-        CDEBUG (D_KML, "     kml_op::%u\n", rec->kml_op);
-        CDEBUG (D_KML, "     i_nlink::%d\n", rec->i_nlink);
-        CDEBUG (D_KML, "     i_ino::%u\n", rec->i_ino);
-}
-
-static void print_kml_suffix (struct journal_suffix *tail)
-{
-        CDEBUG (D_KML, " === KML SUFFIX\n");
-        CDEBUG (D_KML, "     prevrec::%ld\n", tail->prevrec);
-        CDEBUG (D_KML, "     recno::%ld\n", (long) tail->recno);
-        CDEBUG (D_KML, "     time::%d\n", tail->time);
-        CDEBUG (D_KML, "     len::%d\n", tail->len);
-}
-
-void kml_printrec (struct kml_rec *rec, int kml_printop)
-{
-        if (kml_printop & PRINT_KML_PREFIX)
-                print_kml_prefix (&rec->rec_head);
-        if (kml_printop & PRINT_KML_REC) 
-        { 
-                switch (rec->rec_head.opcode)
-                {
-                        case KML_CREATE:
-                                print_kml_create (&rec->rec_kml.create);
-                                break;
-                        case KML_MKDIR:
-                                print_kml_mkdir (&rec->rec_kml.mkdir);
-                                break;
-                        case KML_UNLINK:
-                                print_kml_unlink (&rec->rec_kml.unlink);
-                                break;
-                        case KML_RMDIR:
-                                print_kml_rmdir (&rec->rec_kml.rmdir);
-                                break;
-                        case KML_CLOSE:
-                                print_kml_close (&rec->rec_kml.close);
-                                break;
-                        case KML_SYMLINK:
-                                print_kml_symlink (&rec->rec_kml.symlink);
-                                break;
-                        case KML_RENAME:
-                                print_kml_rename (&rec->rec_kml.rename);
-                                break;
-                        case KML_SETATTR:
-                                print_kml_setattr (&rec->rec_kml.setattr);
-                                break;
-                        case KML_LINK:
-                                print_kml_link (&rec->rec_kml.link);
-                                break;
-                        case KML_OPEN:
-                                print_kml_open (&rec->rec_kml.open);
-                                break;
-                        case KML_MKNOD:
-                                print_kml_mknod (&rec->rec_kml.mknod);
-                                break;
-#if 0
-                        case KML_ENDMARK:
-                                print_kml_endmark (&rec->rec_kml.endmark);
-#endif
-                                break;
-                        default:
-                                CDEBUG (D_KML, " === BAD RECORD, opcode=%u\n",
-                                        rec->rec_head.opcode);
-                                break;
-                }
-        }
-        if (kml_printop & PRINT_KML_SUFFIX)
-                print_kml_suffix (&rec->rec_tail);
-        if (kml_printop & PRINT_KML_OPTIMIZE)
-                print_kml_optimize (&rec->kml_optimize);
-}
-
-void kml_freerec (struct kml_rec *rec)
-{
-        char *sourcepath = NULL,
-             *targetpath = NULL;
-        switch (rec->rec_head.opcode)
-        {
-                case KML_CREATE:
-                        sourcepath = rec->rec_kml.create.path;
-                        break;
-                case KML_MKDIR:
-                        sourcepath = rec->rec_kml.create.path;
-                        break;
-                case KML_UNLINK:
-                        sourcepath = rec->rec_kml.unlink.path;
-                        targetpath = rec->rec_kml.unlink.name;
-                        break;
-                case KML_RMDIR:
-                        sourcepath = rec->rec_kml.rmdir.path;
-                        targetpath = rec->rec_kml.rmdir.name;
-                        break;
-                case KML_CLOSE:
-                        sourcepath = rec->rec_kml.close.path;
-                        break;
-                case KML_SYMLINK:
-                        sourcepath = rec->rec_kml.symlink.sourcepath;
-                        targetpath = rec->rec_kml.symlink.targetpath;
-                        break;
-                case KML_RENAME:
-                        sourcepath = rec->rec_kml.rename.sourcepath;
-                        targetpath = rec->rec_kml.rename.targetpath;
-                        break;
-                case KML_SETATTR:
-                        sourcepath = rec->rec_kml.setattr.path;
-                        break;
-                case KML_LINK:
-                        sourcepath = rec->rec_kml.link.sourcepath;
-                        targetpath = rec->rec_kml.link.targetpath;
-                        break;
-                case KML_OPEN:
-                        break;
-                case KML_MKNOD:
-                        sourcepath = rec->rec_kml.mknod.path;
-                        break;
-#if 0
-                case KML_ENDMARK:
-                        PRESTO_FREE (rec->rec_kml.endmark.kop, sizeof (int) + 
-                                sizeof (struct kml_kop_node) * 
-                                rec->rec_kml.endmark.total);
-#endif
-                        break;
-                default:
-                        break;
-        }
-        if (sourcepath != NULL)
-                PRESTO_FREE (sourcepath, strlen (sourcepath) + 1);
-        if (targetpath != NULL)
-                PRESTO_FREE (targetpath, strlen (targetpath) + 1);
-}
-
-char *readrec (char *recbuf, int reclen, int pos, int *size)
-{
-        char *p = recbuf + pos;
-        *size = *((int *) p);
-        if (*size > (reclen - pos))
-            return NULL;
-        return p; 
-}
-
-int kml_decoderec (char *buf, int pos, int buflen, int *size, 
-                        struct kml_rec **newrec)
-{
-        char *tmp;
-        int  error;
-        tmp = readrec (buf, buflen, pos, size);
-        if (tmp == NULL)
-                return -EBADF;
-        error = kml_unpack (tmp, *size, pos, newrec); 
-        return error;
-}
-
-#if 0
-static void fill_kmlrec_optimize (struct list_head *head, 
-                struct kml_rec *optrec)
-{
-        struct kml_rec *kmlrec;
-        struct list_head *tmp;
-        struct kml_endmark *km;
-        struct kml_optimize *ko;
-        int    n;
-
-        if (optrec->rec_kml.endmark.total == 0)
-                return;
-        n = optrec->rec_kml.endmark.total - 1;
-        tmp = head->prev;
-        km = &optrec->rec_kml.endmark;
-        while ( n >= 0 && tmp != head ) 
-        {
-                kmlrec = list_entry(tmp, struct kml_rec,
-                        kml_optimize.kml_chains);
-                tmp = tmp->prev;
-                if (kmlrec->rec_tail.recno == km->kop[n].kml_recno) 
-                {
-                        ko = &kmlrec->kml_optimize;
-                        ko->kml_flag = km->kop[n].kml_flag;
-                        ko->kml_op   = km->kop[n].kml_op;
-                        ko->i_nlink  = km->kop[n].i_nlink;
-                        ko->i_ino    = km->kop[n].i_ino;
-                        n --;
-                }
-        }
-        if (n != -1)
-                CDEBUG (D_KML, "Yeah!!!, KML optimize error, recno=%d, n=%d\n",
-                        optrec->rec_tail.recno, n);     
-}
-#endif
-
-int decode_kmlrec (struct list_head *head, char *kml_buf, int buflen)
-{
-        struct kml_rec *rec;
-        int    pos = 0, size;
-        int    err;
-        while (pos < buflen) {
-                err = kml_decoderec (kml_buf, pos, buflen, &size, &rec);
-                if (err != 0)
-                        break;
-#if 0
-                if (rec->rec_head.opcode == KML_ENDMARK) {
-                        fill_kmlrec_optimize (head, rec);
-                        mark_rec_deleted (rec);
-                }
-#endif
-                list_add_tail (&rec->kml_optimize.kml_chains, head);
-                pos += size;
-        }
-        return err;
-}
-
-int delete_kmlrec (struct list_head *head)
-{
-        struct kml_rec *rec;
-        struct list_head *tmp;
-
-        if (list_empty(head))
-                return 0;
-        tmp = head->next;
-        while ( tmp != head ) {
-                rec = list_entry(tmp, struct kml_rec, 
-                        kml_optimize.kml_chains);
-                tmp = tmp->next;
-                kml_freerec (rec);
-        }
-        INIT_LIST_HEAD(head);
-        return 0;
-}
-
-int print_allkmlrec (struct list_head *head, int printop)
-{
-        struct kml_rec *rec;
-        struct list_head *tmp;
-
-        if (list_empty(head))
-                return 0;
-        tmp = head->next;
-        while ( tmp != head ) {
-                rec = list_entry(tmp, struct kml_rec,
-                        kml_optimize.kml_chains);
-                tmp = tmp->next;
-#if 0
-                if (printop & PRINT_KML_EXIST) {
-                        if (is_deleted_node (rec))
-                                continue;
-                }
-                else if (printop & PRINT_KML_DELETE) {
-                        if (! is_deleted_node (rec))
-                                continue;
-                }
-#endif
-                kml_printrec (rec, printop);
-        }
-        INIT_LIST_HEAD(head);
-        return 0;
-}
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/kml_reint.c linux.20pre10-ac2/fs/intermezzo/kml_reint.c
--- linux.20pre10/fs/intermezzo/kml_reint.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/kml_reint.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,9 +1,25 @@
-/*
- * KML REINT
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
- * Copryright (C) 1996 Arthur Ma <arthur.ma@mountainviewdata.com>
+ *  Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Reintegration of KML records
  *
- * Copyright (C) 2000 Mountainview Data, Inc.
  */
 
 #define __NO_VERSION__
@@ -19,393 +35,596 @@
 #include <asm/pgtable.h>
 #include <asm/mmu_context.h>
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_kml.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_upcall.h>
-
-static void kmlreint_pre_secure (struct kml_rec *rec);
-static void kmlreint_post_secure (struct kml_rec *rec);
 
-static void kmlreint_pre_secure (struct kml_rec *rec)
+static void kmlreint_pre_secure(struct kml_rec *rec, struct file *dir,
+                                struct run_ctxt *saved)
 {
-        if (current->fsuid != current->uid)
-                CDEBUG (D_KML, "reint_kmlreint_pre_secure: cannot setfsuid\n");
-        if (current->fsgid != current->gid)
-                CDEBUG (D_KML, "reint_kmlreint_pre_secure: cannot setfsgid\n");
-        current->fsuid = rec->rec_head.uid;
-        current->fsgid = rec->rec_head.fsgid;
+        struct run_ctxt ctxt; 
+        struct presto_dentry_data *dd = presto_d2d(dir->f_dentry);
+        int i;
+
+        ctxt.fsuid = rec->prefix.hdr->fsuid;
+        ctxt.fsgid = rec->prefix.hdr->fsgid;
+        ctxt.fs = KERNEL_DS; 
+        ctxt.pwd = dd->dd_fset->fset_dentry;
+        ctxt.pwdmnt = dd->dd_fset->fset_mnt;
+
+        ctxt.root = ctxt.pwd;
+        ctxt.rootmnt = ctxt.pwdmnt;
+        if (rec->prefix.hdr->ngroups > 0) {
+                ctxt.ngroups = rec->prefix.hdr->ngroups;
+                for (i = 0; i< ctxt.ngroups; i++) 
+                        ctxt.groups[i] = rec->prefix.groups[i];
+        } else
+                ctxt.ngroups = 0;
+
+        push_ctxt(saved, &ctxt);
+}
+
+
+/* Append two strings in a less-retarded fashion. */
+static char * path_join(char *p1, int p1len, char *p2, int p2len)
+{
+        int size = p1len + p2len + 2; /* possibly one extra /, one NULL */
+        char *path;
+
+        path = kmalloc(size, GFP_KERNEL);
+        if (path == NULL)
+                return NULL;
+
+        memcpy(path, p1, p1len);
+        if (path[p1len - 1] != '/') {
+                path[p1len] = '/';
+                p1len++;
+        }
+        memcpy(path + p1len, p2, p2len);
+        path[p1len + p2len] = '\0';
+
+        return path;
 }
 
-static void kmlreint_post_secure (struct kml_rec *rec)
+static inline int kml_recno_equal(struct kml_rec *rec,
+                                  struct presto_file_set *fset)
 {
-        current->fsuid = current->uid; 
-        current->fsgid = current->gid;
-        /* current->egid = current->gid; */ 
-        /* ????????????? */
+        return (rec->suffix->recno == fset->fset_lento_recno + 1);
 }
 
-static int reint_create (int slot_offset, struct kml_rec *rec)
+static inline int version_equal(struct presto_version *a, struct inode *inode)
 {
-        struct  lento_vfs_context info;
-        struct  kml_create *create = &rec->rec_kml.create;
-        mm_segment_t old_fs;
-        int     error;
+        if (a == NULL)
+                return 1;
+
+        if (inode == NULL) {
+                CERROR("InterMezzo: NULL inode in version_equal()\n");
+                return 0;
+        }
+
+        if (inode->i_mtime == a->pv_mtime &&
+            (S_ISDIR(inode->i_mode) || inode->i_size == a->pv_size))
+                return 1;
 
+        return 0;
+}
+
+static int reint_close(struct kml_rec *rec, struct file *file,
+                       struct lento_vfs_context *given_info)
+{
+        struct run_ctxt saved_ctxt;
+        int error;
+        struct presto_file_set *fset;
+        struct lento_vfs_context info; 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0; 
+        memcpy(&info, given_info, sizeof(*given_info));
 
-        CDEBUG (D_KML, "=====REINT_CREATE::%s\n", create->path);
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_create(create->path, create->mode, &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
+
+        CDEBUG (D_KML, "=====REINT_CLOSE::%s\n", rec->path);
+
+        fset = presto_fset(file->f_dentry);
+        if (fset->fset_flags & FSET_DATA_ON_DEMAND) {
+                struct iattr iattr;
+
+                iattr.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_SIZE;
+                iattr.ia_mtime = (time_t)rec->new_objectv->pv_mtime;
+                iattr.ia_ctime = (time_t)rec->new_objectv->pv_ctime;
+                iattr.ia_size = (time_t)rec->new_objectv->pv_size;
+
+                /* no kml record, but update last rcvd */
+                /* save fileid in dentry for later backfetch */
+                info.flags |= LENTO_FL_EXPECT | LENTO_FL_SET_DDFILEID;
+                info.remote_ino = rec->ino;
+                info.remote_generation = rec->generation;
+                info.flags &= ~LENTO_FL_KML;
+                kmlreint_pre_secure(rec, file, &saved_ctxt);
+                error = lento_setattr(rec->path, &iattr, &info);
+                pop_ctxt(&saved_ctxt);
+
+                presto_d2d(file->f_dentry)->dd_flags &= ~PRESTO_DATA;
+        } else {
+                int minor = presto_f2m(fset);
+
+                info.updated_time = rec->new_objectv->pv_mtime;
+                memcpy(&info.remote_version, rec->old_objectv, 
+                       sizeof(*rec->old_objectv));
+                info.remote_ino = rec->ino;
+                info.remote_generation = rec->generation;
+                error = izo_upc_backfetch(minor, rec->path, fset->fset_name,
+                                          &info);
+                if (error) {
+                        CERROR("backfetch error %d\n", error);
+                        /* if file doesn't exist anymore,  then ignore the CLOSE
+                         * and just update the last_rcvd.
+                         */
+                        if (error == ENOENT) {
+                                CDEBUG(D_KML, "manually updating remote offset uuid %s"
+                                       "recno %d offset %Lu\n", info.uuid, info.recno, info.kml_offset);
+                                error = izo_rcvd_upd_remote(fset, info.uuid, info.recno, info.kml_offset);
+                                if(error)
+                                        CERROR("izo_rcvd_upd_remote error %d\n", error);
+
+                        } 
+                }
+                        
+                /* propagate error to avoid further reint */
+        }
 
         EXIT;
         return error;
 }
 
-static int reint_open (int slot_offset, struct kml_rec *rec)
+static int reint_create(struct kml_rec *rec, struct file *dir,
+                        struct lento_vfs_context *info)
 {
-        return 0;
+        struct run_ctxt saved_ctxt;
+        int     error;        ENTRY;
+
+        CDEBUG (D_KML, "=====REINT_CREATE::%s\n", rec->path);
+        info->updated_time = rec->new_objectv->pv_ctime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_create(rec->path, rec->mode, info);
+        pop_ctxt(&saved_ctxt); 
+
+        EXIT;
+        return error;
 }
 
-static int reint_mkdir (int slot_offset, struct kml_rec *rec)
+static int reint_link(struct kml_rec *rec, struct file *dir,
+                      struct lento_vfs_context *info)
 {
-        struct  lento_vfs_context info;
-        struct  kml_mkdir *mkdir = &rec->rec_kml.mkdir;
-        mm_segment_t old_fs;
+        struct run_ctxt saved_ctxt;
         int     error;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0; 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_mkdir (mkdir->path, mkdir->mode, &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
+        CDEBUG (D_KML, "=====REINT_LINK::%s -> %s\n", rec->path, rec->target);
+        info->updated_time = rec->new_objectv->pv_mtime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_link(rec->path, rec->target, info);
+        pop_ctxt(&saved_ctxt); 
 
         EXIT;
         return error;
 }
 
-static int reint_rmdir (int slot_offset, struct kml_rec *rec)
+static int reint_mkdir(struct kml_rec *rec, struct file *dir,
+                       struct lento_vfs_context *info)
 {
-        struct  kml_rmdir  *rmdir = &rec->rec_kml.rmdir;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
-        char *name;
-        int error;
+        struct run_ctxt saved_ctxt;
+        int     error;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
-        name = bdup_printf ("%s/%s", rmdir->path, rmdir->name);
-        if (name == NULL)
-        {
-                kmlreint_post_secure (rec);
-                EXIT;
-                return -ENOMEM;
-        }
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0;
 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_rmdir (name, &info);
-        set_fs (old_fs);
+        CDEBUG (D_KML, "=====REINT_MKDIR::%s\n", rec->path);
+        info->updated_time = rec->new_objectv->pv_ctime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_mkdir(rec->path, rec->mode, info);
+        pop_ctxt(&saved_ctxt); 
+
+        EXIT;
+        return error;
+}
+
+static int reint_mknod(struct kml_rec *rec, struct file *dir,
+                       struct lento_vfs_context *info)
+{
+        struct run_ctxt saved_ctxt;
+        int     error, dev;
+
+        ENTRY;
+
+        CDEBUG (D_KML, "=====REINT_MKNOD::%s\n", rec->path);
+        info->updated_time = rec->new_objectv->pv_ctime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+
+        dev = rec->rdev ?: MKDEV(rec->major, rec->minor);
+
+        error = lento_mknod(rec->path, rec->mode, dev, info);
+        pop_ctxt(&saved_ctxt); 
 
-        PRESTO_FREE (name, strlen (name) + 1);
-        kmlreint_post_secure (rec);
         EXIT;
         return error;
 }
 
-static int reint_link (int slot_offset, struct kml_rec *rec)
+
+static int reint_noop(struct kml_rec *rec, struct file *dir,
+                      struct lento_vfs_context *info)
+{
+        return 0;
+}
+
+static int reint_rename(struct kml_rec *rec, struct file *dir,
+                        struct lento_vfs_context *info)
 {
-        struct  kml_link *link = &rec->rec_kml.link;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
+        struct run_ctxt saved_ctxt;
         int     error;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0; 
+        CDEBUG (D_KML, "=====REINT_RENAME::%s -> %s\n", rec->path, rec->target);
+        info->updated_time = rec->new_objectv->pv_mtime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_rename(rec->path, rec->target, info);
+        pop_ctxt(&saved_ctxt); 
 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_link (link->sourcepath, link->targetpath, &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
         EXIT;
         return error;
 }
 
-static int reint_unlink (int slot_offset, struct kml_rec *rec)
+static int reint_rmdir(struct kml_rec *rec, struct file *dir,
+                       struct lento_vfs_context *info)
 {
-        struct  kml_unlink *unlink = &rec->rec_kml.unlink;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
+        struct run_ctxt saved_ctxt;
         int     error;
-        char   *name;
+        char *path;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
-        name = bdup_printf ("%s/%s", unlink->path, unlink->name);
-        if (name == NULL)
-        {
-                kmlreint_post_secure (rec);
+
+        path = path_join(rec->path, rec->pathlen - 1, rec->target, rec->targetlen);
+        if (path == NULL) {
                 EXIT;
                 return -ENOMEM;
         }
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0;
 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_unlink (name, &info);
-        set_fs (old_fs);
-        PRESTO_FREE (name, strlen (name));
-        kmlreint_post_secure (rec);
+        CDEBUG (D_KML, "=====REINT_RMDIR::%s\n", path);
+        info->updated_time = rec->new_parentv->pv_mtime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_rmdir(path, info);
+        pop_ctxt(&saved_ctxt); 
 
+        kfree(path);
         EXIT;
         return error;
 }
 
-static int reint_symlink (int slot_offset, struct kml_rec *rec)
+static int reint_setattr(struct kml_rec *rec, struct file *dir,
+                         struct lento_vfs_context *info)
 {
-        struct  kml_symlink *symlink = &rec->rec_kml.symlink;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
+        struct run_ctxt saved_ctxt;
+        struct iattr iattr;
         int     error;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0; 
+        iattr.ia_valid = rec->valid;
+        iattr.ia_mode  = (umode_t)rec->mode;
+        iattr.ia_uid   = (uid_t)rec->uid;
+        iattr.ia_gid   = (gid_t)rec->gid;
+        iattr.ia_size  = (off_t)rec->size;
+        iattr.ia_ctime = (time_t)rec->ctime;
+        iattr.ia_mtime = (time_t)rec->mtime;
+        iattr.ia_atime = iattr.ia_mtime; /* We don't track atimes. */
+        iattr.ia_attr_flags = rec->flags;
+
+        CDEBUG (D_KML, "=====REINT_SETATTR::%s (%d)\n", rec->path, rec->valid);
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_setattr(rec->path, &iattr, info);
+        pop_ctxt(&saved_ctxt); 
 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_symlink (symlink->targetpath, 
-                        symlink->sourcepath, &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
         EXIT;
         return error;
 }
 
-static int reint_rename (int slot_offset, struct kml_rec *rec)
+static int reint_symlink(struct kml_rec *rec, struct file *dir,
+                         struct lento_vfs_context *info)
 {
-        struct  kml_rename *rename = &rec->rec_kml.rename;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
+        struct run_ctxt saved_ctxt;
         int     error;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0;
-
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_rename (rename->sourcepath, rename->targetpath, &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
+        CDEBUG (D_KML, "=====REINT_SYMLINK::%s -> %s\n", rec->path, rec->target);
+        info->updated_time = rec->new_objectv->pv_ctime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_symlink(rec->target, rec->path, info);
+        pop_ctxt(&saved_ctxt); 
 
         EXIT;
         return error;
 }
 
-static int reint_setattr (int slot_offset, struct kml_rec *rec)
+static int reint_unlink(struct kml_rec *rec, struct file *dir,
+                        struct lento_vfs_context *info)
 {
-        struct  kml_setattr *setattr = &rec->rec_kml.setattr;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
+        struct run_ctxt saved_ctxt;
         int     error;
+        char *path;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = setattr->iattr.ia_attr_flags;
+        path = path_join(rec->path, rec->pathlen - 1, rec->target, rec->targetlen);
+        if (path == NULL) {
+                EXIT;
+                return -ENOMEM;
+        }
+
+        CDEBUG (D_KML, "=====REINT_UNLINK::%s\n", path);
+        info->updated_time = rec->new_parentv->pv_mtime;
+        kmlreint_pre_secure(rec, dir, &saved_ctxt);
+        error = lento_unlink(path, info);
+        pop_ctxt(&saved_ctxt); 
 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_setattr (setattr->path, &setattr->iattr, &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
+        kfree(path);
         EXIT;
         return error;
 }
 
-static int reint_mknod (int slot_offset, struct kml_rec *rec)
+static int branch_reint_rename(struct presto_file_set *fset, struct kml_rec *rec, 
+                   struct file *dir, struct lento_vfs_context *info,
+                   char * kml_data, __u64 kml_size)
 {
-        struct  kml_mknod *mknod = &rec->rec_kml.mknod;
-        struct  lento_vfs_context info;
-        mm_segment_t old_fs;
         int     error;
 
         ENTRY;
-        kmlreint_pre_secure (rec);
 
-        info.slot_offset = slot_offset;
-        info.recno = rec->rec_tail.recno;
-        info.kml_offset = rec->rec_kml_offset;
-        info.flags = 0;
+        error = reint_rename(rec, dir, info);
+        if (error == -ENOENT) {
+                /* normal reint failed because path was not found */
+                struct rec_info rec;
+                
+                CDEBUG(D_KML, "saving branch rename kml\n");
+                rec.is_kml = 1;
+                rec.size = kml_size;
+                error = presto_log(fset, &rec, kml_data, kml_size,
+                           NULL, 0, NULL, 0,  NULL, 0);
+                if (error == 0)
+                        error = presto_write_last_rcvd(&rec, fset, info);
+        }
 
-        old_fs = get_fs();
-        set_fs (get_ds());
-        error = lento_mknod (mknod->path, mknod->mode, 
-                MKDEV(mknod->major, mknod->minor), &info);
-        set_fs (old_fs);
-        kmlreint_post_secure (rec);
         EXIT;
         return error;
 }
 
-int kml_reint (char *mtpt, int slot_offset, struct kml_rec *rec)
+int branch_reinter(struct presto_file_set *fset, struct kml_rec *rec, 
+                   struct file *dir, struct lento_vfs_context *info,
+                   char * kml_data, __u64 kml_size)
 {
         int error = 0;
-        switch (rec->rec_head.opcode)
-        {
-                case KML_CREATE:
-                        error = reint_create (slot_offset, rec);
-                        break;
-                case KML_OPEN:
-                        error = reint_open (slot_offset, rec);
-                        break;
-                case KML_CLOSE:
-                        /* error = reint_close (slot_offset, rec);
-                           force the system to return to lento */
-                        error = KML_CLOSE_BACKFETCH;
-                        break;
-                case KML_MKDIR:
-                        error = reint_mkdir (slot_offset, rec);
-                        break;
-                case KML_RMDIR:
-                        error = reint_rmdir (slot_offset, rec);
-                        break;
-                case KML_UNLINK:
-                        error = reint_unlink (slot_offset, rec);
-                        break;
-                case KML_LINK:
-                        error =  reint_link (slot_offset, rec);
-                        break;
-                case KML_SYMLINK:
-                        error = reint_symlink (slot_offset, rec);
-                        break;
-                case KML_RENAME:
-                        error = reint_rename (slot_offset, rec);
-                        break;
-                case KML_SETATTR:
-                        error =  reint_setattr (slot_offset, rec);
-                        break;
-                case KML_MKNOD:
-                        error = reint_mknod (slot_offset, rec);
-                        break;
-                default:
-                        CDEBUG (D_KML, "wrong opcode::%d\n", rec->rec_head.opcode);
-                        return -EBADF;
-        }
-        if (error != 0 && error != KML_CLOSE_BACKFETCH)
-                CDEBUG (D_KML, "KML_ERROR::error = %d\n", error);
+        int op = rec->prefix.hdr->opcode;
+
+        if (op == KML_OPCODE_CLOSE) {
+                /* regular close and backfetch */
+                error = reint_close(rec, dir, info);
+        } else if  (op == KML_OPCODE_RENAME) {
+                /* rename only if name already exists  */
+                error = branch_reint_rename(fset, rec, dir, info,
+                                            kml_data, kml_size);
+        } else {
+                /* just rewrite kml into branch/kml and update last_rcvd */
+                struct rec_info rec;
+                
+                CDEBUG(D_KML, "Saving branch kml\n");
+                rec.is_kml = 1;
+                rec.size = kml_size;
+                error = presto_log(fset, &rec, kml_data, kml_size,
+                           NULL, 0, NULL, 0,  NULL, 0);
+                if (error == 0)
+                        error = presto_write_last_rcvd(&rec, fset, info);
+        }
+                
         return error;
 }
 
-/* return the old mtpt */
-/*
-struct fs_struct {
-        atomic_t count;
-        int umask;
-        struct dentry * root, * pwd;
+typedef int (*reinter_t)(struct kml_rec *rec, struct file *basedir,
+                         struct lento_vfs_context *info);
+
+static reinter_t presto_reinters[KML_OPCODE_NUM] =
+{
+        [KML_OPCODE_CLOSE] = reint_close,
+        [KML_OPCODE_CREATE] = reint_create,
+        [KML_OPCODE_LINK] = reint_link,
+        [KML_OPCODE_MKDIR] = reint_mkdir,
+        [KML_OPCODE_MKNOD] = reint_mknod,
+        [KML_OPCODE_NOOP] = reint_noop,
+        [KML_OPCODE_RENAME] = reint_rename,
+        [KML_OPCODE_RMDIR] = reint_rmdir,
+        [KML_OPCODE_SETATTR] = reint_setattr,
+        [KML_OPCODE_SYMLINK] = reint_symlink,
+        [KML_OPCODE_UNLINK] = reint_unlink,
 };
-*/
-static int do_set_fs_root (struct dentry *newroot, 
-                                        struct dentry **old_root)
-{
-        struct dentry *de = current->fs->root;
-        current->fs->root = newroot;
-	if (old_root != (struct dentry **) NULL)
-        	*old_root = de;
-        return 0;
+
+static inline reinter_t get_reinter(int op)
+{
+        if (op < 0 || op >= sizeof(presto_reinters) / sizeof(reinter_t)) 
+                return NULL; 
+        else 
+                return  presto_reinters[op];
 }
 
-static int set_system_mtpt (char *mtpt, struct dentry **old_root)
+int kml_reint_rec(struct file *dir, struct izo_ioctl_data *data)
 {
-	struct nameidata nd;
-        struct dentry *dentry;
-	int error;
-
-	if (path_init(pathname, LOOKUP_PARENT, &nd))
-		error = path_walk(mtpt, &nd);
-        if (error) {
-                CDEBUG (D_KML, "Yean!!!!::Can't find mtpt::%s\n", mtpt);
+        char *ptr;
+        char *end;
+        struct kml_rec rec;
+        int error = 0;
+        struct lento_vfs_context info;
+        struct presto_cache *cache;
+        struct presto_file_set *fset;
+        struct presto_dentry_data *dd = presto_d2d(dir->f_dentry);
+        int op;
+        reinter_t reinter;
+
+        struct izo_rcvd_rec lr_rec;
+        int off;
+
+        ENTRY;
+
+        error = presto_prep(dir->f_dentry, &cache, &fset);
+        if ( error  ) {
+                CERROR("intermezzo: Reintegration on invalid file\n");
                 return error;
-	}
+        }
+
+        if (!dd || !dd->dd_fset || dd->dd_fset->fset_dentry != dir->f_dentry) { 
+                CERROR("intermezzo: reintegration on non-fset root (ino %ld)\n",
+                       dir->f_dentry->d_inode->i_ino);
+                    
+                return -EINVAL;
+        }
+
+        if (data->ioc_plen1 > 64 * 1024) {
+                EXIT;
+                return -ENOSPC;
+        }
+
+        ptr = fset->fset_reint_buf;
+        end = ptr + data->ioc_plen1;
+
+        if (copy_from_user(ptr, data->ioc_pbuf1, data->ioc_plen1)) { 
+                EXIT;
+                error = -EFAULT;
+                goto out;
+        }
+
+        error = kml_unpack(&rec, &ptr, end);
+        if (error) { 
+                EXIT;
+                error = -EFAULT;
+                goto out;
+        }
+
+        off = izo_rcvd_get(&lr_rec, fset, data->ioc_uuid);
+        if (off < 0) {
+                CERROR("No last_rcvd record, setting to 0\n");
+                memset(&lr_rec, 0, sizeof(lr_rec));
+        }
+ 
+        data->ioc_kmlsize = ptr - fset->fset_reint_buf;
 
-        dentry = nd.dentry;
-        error = do_set_fs_root (dentry, old_root);
-        path_release (&nd);
+        if (rec.suffix->recno != lr_rec.lr_remote_recno + 1) {
+                CERROR("KML record number %Lu expected, not %d\n",
+                       lr_rec.lr_remote_recno + 1,
+                       rec.suffix->recno);
+
+#if 0
+                if (!version_check(&rec, dd->dd_fset, &info)) {
+                        /* FIXME: do an upcall to resolve conflicts */
+                        CERROR("intermezzo: would be a conflict!\n");
+                        error = -EINVAL;
+                        EXIT;
+                        goto out;
+                }
+#endif
+        }
+
+        op = rec.prefix.hdr->opcode;
+
+        reinter = get_reinter(op);
+        if (!reinter) { 
+                CERROR("%s: Unrecognized KML opcode %d\n", __FUNCTION__, op);
+                error = -EINVAL;
+                EXIT;
+                goto out;
+        }
+
+        info.kml_offset = data->ioc_offset + data->ioc_kmlsize;
+        info.recno = rec.suffix->recno;
+        info.flags = LENTO_FL_EXPECT;
+        if (data->ioc_flags)
+                info.flags |= LENTO_FL_KML;
+
+        memcpy(info.uuid, data->ioc_uuid, sizeof(info.uuid));
+
+        if (fset->fset_flags & FSET_IS_BRANCH && data->ioc_flags)
+                error = branch_reinter(fset, &rec, dir, &info, fset->fset_reint_buf,
+                                       data->ioc_kmlsize);
+        else 
+                error = reinter(&rec, dir, &info);
+ out: 
+        EXIT;
         return error;
 }
 
-int kml_reintbuf (struct  kml_fsdata *kml_fsdata,
-                  char *mtpt, struct kml_rec **close_rec)
+int izo_get_fileid(struct file *dir, struct izo_ioctl_data *data)
 {
-        struct kml_rec *rec = NULL;
-        struct list_head *head, *tmp;
-        struct dentry *old_root;
-        int    error = 0;
-
-        head = &kml_fsdata->kml_reint_cache;
-        if (list_empty(head))
-                return 0;
+        char *buf = NULL; 
+        char *ptr;
+        char *end;
+        struct kml_rec rec;
+        struct file *file;
+        struct presto_cache *cache;
+        struct presto_file_set *fset;
+        struct presto_dentry_data *dd = presto_d2d(dir->f_dentry);
+        struct run_ctxt saved_ctxt;
+        int     error;
 
-        if (kml_fsdata->kml_reint_current == NULL ||
-            kml_fsdata->kml_reint_current == head->next)
-                return 0;
+        ENTRY;
 
-        error = set_system_mtpt (mtpt, &old_root);
-        if (error)
+        error = presto_prep(dir->f_dentry, &cache, &fset);
+        if ( error  ) {
+                CERROR("intermezzo: Reintegration on invalid file\n");
                 return error;
+        }
+
+        if (!dd || !dd->dd_fset || dd->dd_fset->fset_dentry != dir->f_dentry) { 
+                CERROR("intermezzo: reintegration on non-fset root (ino %ld)\n",
+                       dir->f_dentry->d_inode->i_ino);
+                    
+                return -EINVAL;
+        }
+
+
+        PRESTO_ALLOC(buf, data->ioc_plen1);
+        if (!buf) { 
+                EXIT;
+                return -ENOMEM;
+        }
+        ptr = buf;
+        end = buf + data->ioc_plen1;
+
+        if (copy_from_user(buf, data->ioc_pbuf1, data->ioc_plen1)) { 
+                EXIT;
+                PRESTO_FREE(buf, data->ioc_plen1);
+                return -EFAULT;
+        }
 
-        tmp = head->next;
-        while (error == 0 &&  tmp != head ) {
-                rec = list_entry(tmp, struct kml_rec, kml_optimize.kml_chains);
-                error = kml_reint (mtpt, rec->rec_kml_offset, rec);
-                tmp = tmp->next;
+        error = kml_unpack(&rec, &ptr, end);
+        if (error) { 
+                EXIT;
+                PRESTO_FREE(buf, data->ioc_plen1);
+                return -EFAULT;
         }
 
-        do_set_fs_root (old_root, NULL);
-
-        if (error == KML_CLOSE_BACKFETCH)
-                *close_rec = rec;
-        kml_fsdata->kml_reint_current = tmp;
+        kmlreint_pre_secure(&rec, dir, &saved_ctxt);
+
+        file = filp_open(rec.path, O_RDONLY, 0);
+        if (!file || IS_ERR(file)) { 
+                error = PTR_ERR(file);
+                goto out;
+        }
+        data->ioc_ino = file->f_dentry->d_inode->i_ino;
+        data->ioc_generation = file->f_dentry->d_inode->i_generation; 
+        filp_close(file, 0); 
+
+        CDEBUG(D_FILE, "%s ino %Lx, gen %Lx\n", rec.path, 
+               data->ioc_ino, data->ioc_generation);
+
+ out:
+        if (buf) 
+                PRESTO_FREE(buf, data->ioc_plen1);
+        pop_ctxt(&saved_ctxt); 
+        EXIT;
         return error;
 }
 
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/kml_setup.c linux.20pre10-ac2/fs/intermezzo/kml_setup.c
--- linux.20pre10/fs/intermezzo/kml_setup.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/kml_setup.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,59 +0,0 @@
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#define __NO_VERSION__
-#include <linux/module.h>
-#include <asm/uaccess.h>
-
-#include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
-#include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
-
-int kml_init (struct presto_file_set *fset)
-{
-        struct kml_fsdata *data;
-
-        ENTRY;
-        PRESTO_ALLOC (data, struct kml_fsdata *, sizeof (struct kml_fsdata));
-        if (data == NULL) {
-                EXIT;
-                return -ENOMEM;
-        }
-        INIT_LIST_HEAD (&data->kml_reint_cache);
-        INIT_LIST_HEAD (&data->kml_kop_cache);
-
-        PRESTO_ALLOC (data->kml_buf, char *, KML_REINT_MAXBUF);
-        if (data->kml_buf == NULL) {
-                PRESTO_FREE (data, sizeof (struct kml_fsdata));
-                EXIT;
-                return -ENOMEM;
-        }
-
-        data->kml_maxsize = KML_REINT_MAXBUF;
-        data->kml_len = 0;
-        data->kml_reintpos = 0;
-        data->kml_count = 0;
-        fset->fset_kmldata = data;
-        EXIT;
-        return 0;
-}
-
-int kml_cleanup (struct presto_file_set *fset)
-{
-        struct kml_fsdata *data = fset->fset_kmldata;
-
-        if (data == NULL)
-                return 0;
-
-        fset->fset_kmldata = NULL;
-#if 0
-        kml_sop_cleanup (&data->kml_reint_cache);
-        kml_kop_cleanup (&data->kml_kop_cache);
-#endif
-        PRESTO_FREE (data->kml_buf, KML_REINT_MAXBUF);
-        PRESTO_FREE (data, sizeof (struct kml_fsdata));
-        return 0;
-}
-
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/kml_unpack.c linux.20pre10-ac2/fs/intermezzo/kml_unpack.c
--- linux.20pre10/fs/intermezzo/kml_unpack.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/kml_unpack.c	2002-10-10 23:24:51.000000000 +0100
@@ -0,0 +1,708 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Unpacking of KML records
+ *
+ */
+
+#ifdef __KERNEL__
+#  include <linux/module.h>
+#  include <linux/errno.h>
+#  include <linux/kernel.h>
+#  include <linux/major.h>
+#  include <linux/sched.h>
+#  include <linux/lp.h>
+#  include <linux/slab.h>
+#  include <linux/ioport.h>
+#  include <linux/fcntl.h>
+#  include <linux/delay.h>
+#  include <linux/skbuff.h>
+#  include <linux/proc_fs.h>
+#  include <linux/vmalloc.h>
+#  include <linux/fs.h>
+#  include <linux/poll.h>
+#  include <linux/init.h>
+#  include <linux/list.h>
+#  include <linux/stat.h>
+#  include <asm/io.h>
+#  include <asm/segment.h>
+#  include <asm/system.h>
+#  include <asm/poll.h>
+#  include <asm/uaccess.h>
+#else
+#  include <time.h>
+#  include <stdio.h>
+#  include <string.h>
+#  include <stdlib.h>
+#  include <errno.h>
+#  include <sys/stat.h>
+#  include <glib.h>
+#endif
+
+#include <linux/intermezzo_lib.h>
+#include <linux/intermezzo_idl.h>
+#include <linux/intermezzo_fs.h>
+
+int kml_unpack_version(struct presto_version **ver, char **buf, char *end) 
+{
+	char *ptr = *buf;
+        struct presto_version *pv;
+
+	UNLOGP(*ver, struct presto_version, ptr, end);
+        pv = *ver;
+        pv->pv_mtime   = NTOH__u64(pv->pv_mtime);
+        pv->pv_ctime   = NTOH__u64(pv->pv_ctime);
+        pv->pv_size    = NTOH__u64(pv->pv_size);
+
+	*buf = ptr;
+
+        return 0;
+}
+
+
+static int kml_unpack_noop(struct kml_rec *rec, char **buf, char *end)
+{
+	return 0;
+}
+
+ 
+static int kml_unpack_get_fileid(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+
+	*buf = ptr;
+	return 0;
+}
+
+static int kml_unpack_create(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->mode, __u32, ptr, end);
+	LUNLOGV(rec->uid, __u32, ptr, end);
+	LUNLOGV(rec->gid, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+ 
+static int kml_unpack_mkdir(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->mode, __u32, ptr, end);
+	LUNLOGV(rec->uid, __u32, ptr, end);
+	LUNLOGV(rec->gid, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_unlink(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+        LUNLOGV(rec->old_mode, __u32, ptr, end);
+        LUNLOGV(rec->old_rdev, __u32, ptr, end);
+        LUNLOGV(rec->old_uid, __u64, ptr, end);
+        LUNLOGV(rec->old_gid, __u64, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+        LUNLOGV(rec->old_targetlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
+        UNLOGL(rec->old_target, char, rec->old_targetlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_rmdir(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+        LUNLOGV(rec->old_mode, __u32, ptr, end);
+        LUNLOGV(rec->old_rdev, __u32, ptr, end);
+        LUNLOGV(rec->old_uid, __u64, ptr, end);
+        LUNLOGV(rec->old_gid, __u64, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_close(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	LUNLOGV(rec->mode, __u32, ptr, end);  // used for open_mode
+	LUNLOGV(rec->uid, __u32, ptr, end);   // used for open_uid
+	LUNLOGV(rec->gid, __u32, ptr, end);   // used for open_gid
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->ino, __u64, ptr, end);
+	LUNLOGV(rec->generation, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_symlink(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->uid, __u32, ptr, end);
+	LUNLOGV(rec->gid, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_rename(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_setattr(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+	LUNLOGV(rec->valid, __u32, ptr, end);
+	LUNLOGV(rec->mode, __u32, ptr, end);
+	LUNLOGV(rec->uid, __u32, ptr, end);
+	LUNLOGV(rec->gid, __u32, ptr, end);
+	LUNLOGV(rec->size, __u64, ptr, end);
+	LUNLOGV(rec->mtime, __u64, ptr, end);
+	LUNLOGV(rec->ctime, __u64, ptr, end);
+	LUNLOGV(rec->flags, __u32, ptr, end);
+        LUNLOGV(rec->old_mode, __u32, ptr, end);
+        LUNLOGV(rec->old_rdev, __u32, ptr, end);
+        LUNLOGV(rec->old_uid, __u64, ptr, end);
+        LUNLOGV(rec->old_gid, __u64, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_link(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+static int kml_unpack_mknod(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_parentv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->mode, __u32, ptr, end);
+	LUNLOGV(rec->uid, __u32, ptr, end);
+	LUNLOGV(rec->gid, __u32, ptr, end);
+	LUNLOGV(rec->major, __u32, ptr, end);
+	LUNLOGV(rec->minor, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_write(struct kml_rec *rec, char **buf, char *end)
+{
+	printf("NOT IMPLEMENTED");
+	return 0;
+}
+
+
+static int kml_unpack_release(struct kml_rec *rec, char **buf, char *end)
+{
+	printf("NOT IMPLEMENTED");
+	return 0;
+}
+
+
+static int kml_unpack_trunc(struct kml_rec *rec, char **buf, char *end)
+{
+	printf("NOT IMPLEMENTED");
+	return 0;
+}
+
+
+static int kml_unpack_setextattr(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->flags, __u32, ptr, end);
+	LUNLOGV(rec->mode, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->namelen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+        UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->name, char, rec->namelen, ptr, end);
+	UNLOGL(rec->target, char, rec->targetlen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+
+static int kml_unpack_delextattr(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+
+	kml_unpack_version(&rec->old_objectv, &ptr, end);
+	kml_unpack_version(&rec->new_objectv, &ptr, end);
+	LUNLOGV(rec->flags, __u32, ptr, end);
+	LUNLOGV(rec->mode, __u32, ptr, end);
+	LUNLOGV(rec->pathlen, __u32, ptr, end);
+	LUNLOGV(rec->namelen, __u32, ptr, end);
+	LUNLOGV(rec->targetlen, __u32, ptr, end);
+	UNLOGL(rec->path, char, rec->pathlen, ptr, end);
+	UNLOGL(rec->name, char, rec->namelen, ptr, end);
+
+	*buf = ptr;
+
+	return 0;
+}
+
+static int kml_unpack_open(struct kml_rec *rec, char **buf, char *end)
+{
+	printf("NOT IMPLEMENTED");
+	return 0;
+}
+
+static int kml_unpack_kml_trunc(struct kml_rec *rec, char **buf, char *end)
+{
+
+	printf("NOT IMPLEMENTED");
+	return 0;
+}
+
+
+typedef int (*unpacker)(struct kml_rec *rec, char **buf, char *end);
+
+static unpacker unpackers[KML_OPCODE_NUM] = 
+{
+	[KML_OPCODE_NOOP] = kml_unpack_noop,
+	[KML_OPCODE_CREATE] = kml_unpack_create, 
+	[KML_OPCODE_MKDIR] = kml_unpack_mkdir,
+	[KML_OPCODE_UNLINK] = kml_unpack_unlink,
+	[KML_OPCODE_RMDIR] = kml_unpack_rmdir,
+	[KML_OPCODE_CLOSE] = kml_unpack_close,
+	[KML_OPCODE_SYMLINK] = kml_unpack_symlink,
+	[KML_OPCODE_RENAME] = kml_unpack_rename,
+	[KML_OPCODE_SETATTR] = kml_unpack_setattr,
+	[KML_OPCODE_LINK] = kml_unpack_link,
+	[KML_OPCODE_OPEN] = kml_unpack_open,
+	[KML_OPCODE_MKNOD] = kml_unpack_mknod,
+	[KML_OPCODE_WRITE] = kml_unpack_write,
+	[KML_OPCODE_RELEASE] = kml_unpack_release,
+	[KML_OPCODE_TRUNC] = kml_unpack_trunc,
+	[KML_OPCODE_SETEXTATTR] = kml_unpack_setextattr,
+	[KML_OPCODE_DELEXTATTR] = kml_unpack_delextattr,
+	[KML_OPCODE_KML_TRUNC] = kml_unpack_kml_trunc,
+	[KML_OPCODE_GET_FILEID] = kml_unpack_get_fileid
+};
+
+int kml_unpack_prefix(struct kml_rec *rec, char **buf, char *end) 
+{
+	char *ptr = *buf;
+        int n;
+
+        UNLOGP(rec->prefix.hdr, struct kml_prefix_hdr, ptr, end);
+        rec->prefix.hdr->len     = NTOH__u32(rec->prefix.hdr->len);
+        rec->prefix.hdr->version = NTOH__u32(rec->prefix.hdr->version);
+        rec->prefix.hdr->pid     = NTOH__u32(rec->prefix.hdr->pid);
+        rec->prefix.hdr->auid    = NTOH__u32(rec->prefix.hdr->auid);
+        rec->prefix.hdr->fsuid   = NTOH__u32(rec->prefix.hdr->fsuid);
+        rec->prefix.hdr->fsgid   = NTOH__u32(rec->prefix.hdr->fsgid);
+        rec->prefix.hdr->opcode  = NTOH__u32(rec->prefix.hdr->opcode);
+        rec->prefix.hdr->ngroups = NTOH__u32(rec->prefix.hdr->ngroups);
+
+	UNLOGL(rec->prefix.groups, __u32, rec->prefix.hdr->ngroups, ptr, end);
+        for (n = 0; n < rec->prefix.hdr->ngroups; n++) {
+                rec->prefix.groups[n] = NTOH__u32(rec->prefix.groups[n]);
+        }
+
+	*buf = ptr;
+
+        return 0;
+}
+
+int kml_unpack_suffix(struct kml_rec *rec, char **buf, char *end) 
+{
+	char *ptr = *buf;
+
+	UNLOGP(rec->suffix, struct kml_suffix, ptr, end);
+        rec->suffix->prevrec   = NTOH__u32(rec->suffix->prevrec);
+        rec->suffix->recno    = NTOH__u32(rec->suffix->recno);
+        rec->suffix->time     = NTOH__u32(rec->suffix->time);
+        rec->suffix->len      = NTOH__u32(rec->suffix->len);
+
+	*buf = ptr;
+
+        return 0;
+}
+
+int kml_unpack(struct kml_rec *rec, char **buf, char *end)
+{
+	char *ptr = *buf;
+	int err; 
+
+        if (((unsigned long)ptr % 4) != 0) {
+                printf("InterMezzo: %s: record misaligned.\n", __FUNCTION__);
+                return -EINVAL;
+        }
+
+        while (ptr < end) { 
+                __u32 *i = (__u32 *)ptr;
+                if (*i)
+                        break;
+                ptr += sizeof(*i);
+        }
+	*buf = ptr;
+
+	memset(rec, 0, sizeof(*rec));
+
+        err = kml_unpack_prefix(rec, &ptr, end);
+	if (err) {
+                printf("InterMezzo: %s: unpack_prefix failed: %d\n",
+                       __FUNCTION__, err);
+		return err;
+        }
+
+        if (rec->prefix.hdr->opcode < 0  ||
+            rec->prefix.hdr->opcode >= KML_OPCODE_NUM) {
+                printf("InterMezzo: %s: invalid opcode (%d)\n",
+                       __FUNCTION__, rec->prefix.hdr->opcode);
+		return -EINVAL;
+        }
+	err = unpackers[rec->prefix.hdr->opcode](rec, &ptr, end);
+	if (err) {
+                printf("InterMezzo: %s: unpacker failed: %d\n",
+                       __FUNCTION__, err);
+		return err;
+        }
+
+        err = kml_unpack_suffix(rec, &ptr, end);
+	if (err) {
+                printf("InterMezzo: %s: unpack_suffix failed: %d\n",
+                       __FUNCTION__, err);
+		return err;
+        }
+
+
+	if (rec->prefix.hdr->len != rec->suffix->len) {
+                printf("InterMezzo: %s: lengths don't match\n",
+                       __FUNCTION__);
+		return -EINVAL;
+        }
+        if ((rec->prefix.hdr->len % 4) != 0) {
+                printf("InterMezzo: %s: record length not a "
+                       "multiple of 4.\n", __FUNCTION__);
+                return -EINVAL;
+        }
+        if (ptr - *buf != rec->prefix.hdr->len) {
+                printf("InterMezzo: %s: unpacking error\n",
+                       __FUNCTION__);
+                return -EINVAL;
+        }
+        while (ptr < end) { 
+                __u32 *i = (__u32 *)ptr;
+                if (*i)
+                        break;
+                ptr += sizeof(*i);
+        }
+	*buf = ptr;
+	return 0;
+}
+
+
+#ifndef __KERNEL__
+#define STR(ptr) ((ptr))? (ptr) : ""
+
+#define OPNAME(n) [KML_OPCODE_##n] = #n
+static char *opnames[KML_OPCODE_NUM] = {
+	OPNAME(NOOP),
+	OPNAME(CREATE),
+	OPNAME(MKDIR), 
+	OPNAME(UNLINK),
+	OPNAME(RMDIR),
+	OPNAME(CLOSE),
+	OPNAME(SYMLINK),
+	OPNAME(RENAME),
+	OPNAME(SETATTR),
+	OPNAME(LINK),
+	OPNAME(OPEN),
+	OPNAME(MKNOD),
+	OPNAME(WRITE),
+	OPNAME(RELEASE),
+	OPNAME(TRUNC),
+	OPNAME(SETEXTATTR),
+	OPNAME(DELEXTATTR),
+	OPNAME(KML_TRUNC),
+	OPNAME(GET_FILEID)
+};
+#undef OPNAME
+
+static char *print_opname(int op)
+{
+	if (op < 0 || op >= sizeof (opnames) / sizeof (*opnames))
+		return NULL;
+	return opnames[op];
+}
+
+
+static char *print_time(__u64 i)
+{
+	char buf[128];
+	
+	memset(buf, 0, 128);
+
+#ifndef __KERNEL__
+	strftime(buf, 128, "%Y/%m/%d %H:%M:%S", gmtime((time_t *)&i));
+#else
+	sprintf(buf, "%Ld\n", i);
+#endif
+
+	return strdup(buf);
+}
+
+static char *print_version(struct presto_version *ver)
+{
+	char ver_buf[128];
+	char *mtime;
+	char *ctime;
+
+	if (!ver || ver->pv_ctime == 0) {
+		return strdup("");
+	} 
+	mtime = print_time(ver->pv_mtime);
+	ctime = print_time(ver->pv_ctime);
+	sprintf(ver_buf, "mtime %s, ctime %s, len %lld", 
+		mtime, ctime, ver->pv_size);
+	free(mtime);
+	free(ctime);
+	return strdup(ver_buf);
+}
+
+
+char *kml_print_rec(struct kml_rec *rec, int brief)
+{
+	char *str;
+	char *nov, *oov, *ntv, *otv, *npv, *opv;
+	char *rectime, *mtime, *ctime;
+
+        if (brief) {
+		str = g_strdup_printf(" %08d %7s %*s %*s", 
+                                      rec->suffix->recno,
+                                      print_opname (rec->prefix.hdr->opcode),
+                                      rec->pathlen, STR(rec->path),
+                                      rec->targetlen, STR(rec->target));
+                
+		return str;
+	}
+
+	rectime = print_time(rec->suffix->time);
+	mtime = print_time(rec->mtime);
+	ctime = print_time(rec->ctime);
+
+	nov = print_version(rec->new_objectv);
+	oov = print_version(rec->old_objectv);
+	ntv = print_version(rec->new_targetv);
+	otv = print_version(rec->old_targetv);
+	npv = print_version(rec->new_parentv);
+	opv = print_version(rec->old_parentv);
+
+	str = g_strdup_printf("\n -- Record:\n"
+		"    Recno     %d\n"
+		"    KML off   %lld\n" 
+		"    Version   %d\n" 
+		"    Len       %d\n"
+		"    Suf len   %d\n"
+		"    Time      %s\n"
+		"    Opcode    %d\n"
+		"    Op        %s\n"
+		"    Pid       %d\n"
+		"    AUid      %d\n"
+		"    Fsuid     %d\n" 
+		"    Fsgid     %d\n"
+		"    Prevrec   %d\n" 
+		"    Ngroups   %d\n"
+		//"    Groups    @{$self->{groups}}\n" 
+		" -- Path:\n"
+		"    Inode     %d\n"
+		"    Gen num   %u\n"
+                "    Old mode  %o\n"
+                "    Old rdev  %x\n"
+                "    Old uid   %llu\n"
+                "    Old gid   %llu\n"
+		"    Path      %*s\n"
+		//"    Open_mode %o\n",
+		"    Pathlen   %d\n"
+		"    Tgt       %*s\n"
+		"    Tgtlen    %d\n" 
+		"    Old Tgt   %*s\n"
+		"    Old Tgtln %d\n" 
+		" -- Attr:\n"
+		"    Valid     %x\n"
+		"    mode %o, uid %d, gid %d, size %lld, mtime %s, ctime %s rdev %x (%d:%d)\n"
+		" -- Versions:\n"
+		"    New object %s\n"
+		"    Old object %s\n"
+		"    New target %s\n"
+		"    Old target %s\n"
+		"    New parent %s\n"
+		"    Old parent %s\n", 
+		
+		rec->suffix->recno, 
+		rec->offset, 
+		rec->prefix.hdr->version, 
+		rec->prefix.hdr->len, 
+		rec->suffix->len, 
+		rectime,
+		rec->prefix.hdr->opcode, 
+		print_opname (rec->prefix.hdr->opcode),
+		rec->prefix.hdr->pid,
+		rec->prefix.hdr->auid,
+		rec->prefix.hdr->fsuid,
+		rec->prefix.hdr->fsgid,
+		rec->suffix->prevrec,
+		rec->prefix.hdr->ngroups,
+		rec->ino,
+		rec->generation,
+                rec->old_mode,
+                rec->old_rdev,
+                rec->old_uid,
+                rec->old_gid,
+		rec->pathlen,
+		STR(rec->path),
+		rec->pathlen,
+		rec->targetlen,
+		STR(rec->target),
+		rec->targetlen,
+		rec->old_targetlen,
+		STR(rec->old_target),
+		rec->old_targetlen,
+		
+		rec->valid, 
+		rec->mode,
+		rec->uid,
+		rec->gid,
+		rec->size,
+		mtime,
+		ctime,
+		rec->rdev, rec->major, rec->minor,
+		nov, oov, ntv, otv, npv, opv);
+		
+	free(nov);
+	free(oov);
+	free(ntv);
+	free(otv);
+	free(npv);
+	free(opv);
+
+	free(rectime); 
+	free(ctime);
+	free(mtime);
+
+	return str;
+}
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/kml_utils.c linux.20pre10-ac2/fs/intermezzo/kml_utils.c
--- linux.20pre10/fs/intermezzo/kml_utils.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/kml_utils.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,44 +0,0 @@
-#include <linux/list.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_kml.h>
-
-
-// dlogit -- oppsite to logit ()
-//         return the sbuf + size;
-char *dlogit (void *tbuf, const void *sbuf, int size)
-{
-        char *ptr = (char *)sbuf;
-        memcpy(tbuf, ptr, size);
-        ptr += size;
-        return ptr;
-}
-
-static spinlock_t kml_lock = SPIN_LOCK_UNLOCKED;
-static char  buf[1024];
-char * bdup_printf (char *format, ...)
-{
-        va_list args;
-        int  i;
-        char *path;
-        long flags;
-
-        spin_lock_irqsave(&kml_lock, flags);
-        va_start(args, format);
-        i = vsprintf(buf, format, args); /* hopefully i < sizeof(buf) */
-        va_end(args);
-
-        PRESTO_ALLOC (path, char *, i + 1);
-        if (path == NULL)
-                return NULL;
-        strcpy (path, buf);
-
-        spin_unlock_irqrestore(&kml_lock, flags);
-        return path;
-}
-
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/Makefile linux.20pre10-ac2/fs/intermezzo/Makefile
--- linux.20pre10/fs/intermezzo/Makefile	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/Makefile	2002-10-11 01:10:53.000000000 +0100
@@ -4,8 +4,11 @@
 
 O_TARGET := intermezzo.o
 
-obj-y :=  journal_reiserfs.o cache.o  journal.o presto.o vfs.o psdev.o upcall.o methods.o sysctl.o dcache.o  dir.o  super.o journal_ext2.o journal_ext3.o journal_xfs.o  inode.o  file.o journal_obdfs.o
-
+obj-y :=  cache.o dcache.o dir.o ext_attr.o file.o fileset.o inode.o \
+	  journal.o journal_ext2.o journal_ext3.o journal_obdfs.o \
+          journal_reiserfs.o journal_tmpfs.o journal_xfs.o kml_reint.o \
+          kml_unpack.o methods.o presto.o psdev.o replicator.o super.o \
+          sysctl.o upcall.o vfs.o
 
 obj-m := $(O_TARGET)
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/methods.c linux.20pre10-ac2/fs/intermezzo/methods.c
--- linux.20pre10/fs/intermezzo/methods.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/methods.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,5 +1,5 @@
-/*
- *
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
  *  Copyright (C) 2000 Stelias Computing, Inc.
  *  Copyright (C) 2000 Red Hat, Inc.
@@ -7,6 +7,22 @@
  *
  *  Extended Attribute Support
  *  Copyright (C) 2001 Shirish H. Phatak, Tacit Networks, Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
  */
 
 #include <stdarg.h>
@@ -150,6 +166,16 @@
                 FDEBUG(D_SUPER, "ops at %p\n", ops);
         }
 
+        if ( strlen(cache_type) == strlen("tmpfs") &&
+             memcmp(cache_type, "tmpfs", strlen("tmpfs")) == 0 ) {
+#if defined(CONFIG_TMPFS)
+                ops->o_trops = &presto_tmpfs_journal_ops;
+#else
+                ops->o_trops = NULL;
+#endif
+                FDEBUG(D_SUPER, "ops at %p\n", ops);
+        }
+
         if ( strlen(cache_type) == strlen("reiserfs") &&
              memcmp(cache_type, "reiserfs", strlen("reiserfs")) == 0 ) {
 #if 0
@@ -164,7 +190,7 @@
         if ( strlen(cache_type) == strlen("xfs") &&
              memcmp(cache_type, "xfs", strlen("xfs")) == 0 ) {
 #if 0
-                //#if defined(CONFIG_XFS_FS) || defined (CONFIG_XFS_FS_MODULE)
+/*#if defined(CONFIG_XFS_FS) || defined (CONFIG_XFS_FS_MODULE) */
                 ops->o_trops = &presto_xfs_journal_ops;
 #else
                 ops->o_trops = NULL;
@@ -207,6 +233,13 @@
                 ops = &filter_oppar[FILTER_FS_EXT3];
                 FDEBUG(D_SUPER, "ops at %p\n", ops);
         }
+
+        if ( strlen(cache_type) == strlen("tmpfs") &&
+             memcmp(cache_type, "tmpfs", strlen("tmpfs")) == 0 ) {
+                ops = &filter_oppar[FILTER_FS_TMPFS];
+                FDEBUG(D_SUPER, "ops at %p\n", ops);
+        }
+
         if ( strlen(cache_type) == strlen("reiserfs") &&
              memcmp(cache_type, "reiserfs", strlen("reiserfs")) == 0 ) {
                 ops = &filter_oppar[FILTER_FS_REISERFS];
@@ -219,7 +252,7 @@
         }
 
         if (ops == NULL) {
-                printk("prepare to die: unrecognized cache type for Filter\n");
+                CERROR("prepare to die: unrecognized cache type for Filter\n");
         }
         return ops;
         FEXIT;
@@ -343,7 +376,7 @@
         memcpy(filter_c2udfops(cache), cache_fops, sizeof(*cache_fops));
 
         /* unconditional filtering operations */
-        filter_c2udfops(cache)->open = filter_fops->open;
+        filter_c2udfops(cache)->ioctl = filter_fops->ioctl;
 
         FEXIT;
 }
@@ -374,7 +407,7 @@
         memcpy(pr_iops, cache_iops, sizeof(*cache_iops));
 
         /* copy dir fops */
-        printk("*** cache file ops at %p\n", cache_fops);
+        CERROR("*** cache file ops at %p\n", cache_fops);
         memcpy(filter_c2uffops(cache), cache_fops, sizeof(*cache_fops));
 
         /* assign */
@@ -383,6 +416,8 @@
                 pr_iops->setattr = filter_iops->setattr;
         if (cache_iops->getattr)
                 pr_iops->getattr = filter_iops->getattr;
+        /* XXX Should this be conditional rmr ? */
+        pr_iops->permission = filter_iops->permission;
 #ifdef CONFIG_FS_EXT_ATTR
     	/* For now we assume that posix acls are handled through extended
 	* attributes. If this is not the case, we must explicitly trap and 
@@ -397,6 +432,7 @@
         filter_c2uffops(cache)->open = filter_fops->open;
         filter_c2uffops(cache)->release = filter_fops->release;
         filter_c2uffops(cache)->write = filter_fops->write;
+        filter_c2uffops(cache)->ioctl = filter_fops->ioctl;
 
         FEXIT;
 }
@@ -455,7 +491,7 @@
                filter_dop, sizeof(*filter_dop));
         
         if (cache_dop &&  cache_dop != filter_dop && cache_dop->d_revalidate){
-                printk("WARNING: filter overriding revalidation!\n");
+                CERROR("WARNING: filter overriding revalidation!\n");
         }
         return;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/presto.c linux.20pre10-ac2/fs/intermezzo/presto.c
--- linux.20pre10/fs/intermezzo/presto.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/presto.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,12 +1,26 @@
-/*
- * intermezzo.c
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
- * This file implements basic routines supporting the semantics
+ *  Author: Peter J. Braam <braam@clusterfs.com>
+ *  Copyright (C) 1998 Stelias Computing Inc
+ *  Copyright (C) 1999 Red Hat Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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.
  *
- * Author: Peter J. Braam  <braam@cs.cmu.edu>
- * Copyright (C) 1998 Stelias Computing Inc
- * Copyright (C) 1999 Red Hat Inc.
+ *   You should have received a copy of the GNU General Public License
+ *   along with InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
+ * This file implements basic routines supporting the semantics
  */
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -23,13 +37,7 @@
 #include <linux/smp_lock.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
-
-extern int presto_init_last_rcvd_file(struct presto_file_set *);
-extern int presto_init_lml_file(struct presto_file_set *);
-extern int presto_init_kml_file(struct presto_file_set *);
 
 int presto_walk(const char *name, struct nameidata *nd)
 {
@@ -37,7 +45,7 @@
         /* we do not follow symlinks to support symlink operations 
            correctly. The vfs should always hand us resolved dentries
            so we should not be required to use LOOKUP_FOLLOW. At the
-	   reintegrating end, lento again should be working with the 
+           reintegrating end, lento again should be working with the 
            resolved pathname and not the symlink. SHP
            XXX: This code implies that direct symlinks do not work. SHP
         */
@@ -51,17 +59,6 @@
 }
 
 
-static inline int presto_dentry_is_fsetroot(struct dentry *dentry)
-{
-        return ((long) dentry->d_fsdata) & PRESTO_FSETROOT;
-}
-
-static inline struct presto_file_set *presto_dentry2fset(struct dentry *dentry)
-{
-        return (struct presto_file_set *)
-                (((long) dentry->d_fsdata) - PRESTO_FSETROOT);
-}
-
 /* find the presto minor device for this inode */
 int presto_i2m(struct inode *inode)
 {
@@ -70,7 +67,7 @@
         cache = presto_get_cache(inode);
         CDEBUG(D_PSDEV, "\n");
         if ( !cache ) {
-                printk("PRESTO: BAD: cannot find cache for dev %d, ino %ld\n",
+                CERROR("PRESTO: BAD: cannot find cache for dev %d, ino %ld\n",
                        inode->i_dev, inode->i_ino);
                 EXIT;
                 return -1;
@@ -91,48 +88,6 @@
 
 }
 
-int presto_has_all_data(struct inode *inode)
-{
-        ENTRY;
-
-        if ( (inode->i_size >> inode->i_sb->s_blocksize_bits) >
-             inode->i_blocks) {
-                EXIT;
-                return 0;
-        }
-        EXIT;
-        return 1;
-
-}
-
-/* find the fileset dentry for this dentry */
-struct presto_file_set *presto_fset(struct dentry *de)
-{
-        struct dentry *fsde;
-        ENTRY;
-        fsde = de;
-        for ( ; ; ) {
-                if ( presto_dentry_is_fsetroot(fsde) ) {
-                        EXIT;
-                        return presto_dentry2fset(fsde);
-                }
-                /* are we at the cache "/" ?? */
-                if ( fsde->d_parent == fsde ) {
-                        if ( !de->d_inode ) {
-                                printk("Warning %*s has no fileset inode.\n",
-                                       de->d_name.len, de->d_name.name);
-                        }
-                        /* better to return a BAD thing */
-                        EXIT;
-                        return NULL;
-                }
-                fsde = fsde->d_parent;
-        }
-        /* not reached */
-        EXIT;
-        return NULL;
-}
-
 /* XXX check this out */
 struct presto_file_set *presto_path2fileset(const char *name)
 {
@@ -168,7 +123,7 @@
 
         ENTRY;
         minor = presto_i2m(dentry->d_inode);
-        if ( upc_comms[minor].uc_no_filter ) {
+        if ( izo_channels[minor].uc_no_filter ) {
                 EXIT;
                 return ~0;
         }
@@ -178,41 +133,30 @@
              (flag == PRESTO_ATTR || flag == PRESTO_DATA) &&
              (fset->fset_flags & FSET_INSYNC) ) {
                 CDEBUG(D_INODE, "fset in sync (ino %ld)!\n",
-                       fset->fset_mtpt->d_inode->i_ino);
+                       fset->fset_dentry->d_inode->i_ino);
                 EXIT;
                 return 1;
         }
 
-        /* if it is a fsetroot, it's stored in the fset_flags */
-        if ( fset && presto_dentry_is_fsetroot(dentry) ) {
-                EXIT;
-                return fset->fset_data & flag;
-        }
-
         EXIT;
-        return ((int)(long)dentry->d_fsdata & flag);
+        return (presto_d2d(dentry)->dd_flags & flag);
 }
 
 /* set a bit in the dentry flags */
 void presto_set(struct dentry *dentry, int flag)
 {
-
+        ENTRY;
         if ( dentry->d_inode ) {
                 CDEBUG(D_INODE, "SET ino %ld, flag %x\n",
                        dentry->d_inode->i_ino, flag);
         }
-
-        if ( presto_dentry_is_fsetroot(dentry)) {
-                struct presto_file_set *fset = presto_dentry2fset(dentry);
-                if (fset) {
-                        fset->fset_data |= flag;
-                        CDEBUG(D_INODE, "Setting fset->fset_data: now %x\n",
-                               fset->fset_data);
-                }
-        } else {
-                CDEBUG(D_INODE, "Setting dentry->d_fsdata\n");
-                ((int)(long)dentry->d_fsdata) |= flag;
+        if ( presto_d2d(dentry) == NULL) {
+                CERROR("dentry without d_fsdata in presto_set: %p: %*s", dentry,
+                                dentry->d_name.len, dentry->d_name.name);
+                BUG();
         }
+        presto_d2d(dentry)->dd_flags |= flag;
+        EXIT;
 }
 
 /* given a path: complete the closes on the fset */
@@ -224,7 +168,6 @@
         struct presto_file_set *fset;
         ENTRY;
 
-
         error = presto_walk(path, &nd);
         if (error) {
                 EXIT;
@@ -242,7 +185,7 @@
         fset = presto_fset(dentry);
         error = -EINVAL;
         if ( !fset ) {
-                printk("No fileset!\n");
+                CERROR("No fileset!\n");
                 EXIT;
                 goto out_complete;
         }
@@ -256,108 +199,7 @@
         return error;
 }       
 
-/* set the fset recno and offset to a given value */ 
-int lento_reset_fset(char *path, __u64 offset, __u32 recno)
-{
-        struct nameidata nd;
-        struct dentry *dentry;
-        int error;
-        struct presto_file_set *fset;
-        ENTRY;
-
-
-        error = presto_walk(path, &nd);
-        if (error)
-                return error;
-
-        dentry = nd.dentry;
-
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
-                EXIT;
-                goto out_complete;
-        }
-        
-        fset = presto_fset(dentry);
-        error = -EINVAL;
-        if ( !fset ) {
-                printk("No fileset!\n");
-                EXIT;
-                goto out_complete;
-        }
-
-        write_lock(&fset->fset_kml.fd_lock);
-        fset->fset_kml.fd_recno = recno;
-        fset->fset_kml.fd_offset = offset;
-        read_lock(&fset->fset_kml.fd_lock);
-        
-        EXIT;
- out_complete:
-        path_release(&nd);
-        return error;
-}       
-
-
-
-/* given a path, write an LML record for it - thus must have root's 
-   group array settings, since lento is doing this 
-*/ 
-int lento_write_lml(char *path,
-                     __u64 remote_ino, 
-                     __u32 remote_generation,
-                     __u32 remote_version,
-                     struct presto_version *remote_file_version)
-{
-        struct nameidata nd; 
-        struct rec_info rec;
-        struct dentry *dentry;
-        struct file file;
-        int error;
-        struct presto_file_set *fset;
-        ENTRY;
-
-        error = presto_walk(path, &nd);
-        if (error) {
-                EXIT;
-                return error;
-        }
-        dentry = nd.dentry;
-
-        file.f_dentry = dentry;
-        file.private_data = NULL;
-
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
-                EXIT;
-                goto out_lml;
-        }
-        
-        fset = presto_fset(dentry);
-        error = -EINVAL;
-        if ( !fset ) {
-                printk("No fileset!\n");
-                EXIT;
-                goto out_lml;
-        }
-
-        
-        /* setting offset to -1 appends */
-        rec.offset = -1;
-        /* this only requires a transaction below which is automatic */
-        error = presto_write_lml_close(&rec, 
-                                       fset,
-                                       &file, 
-                                       remote_ino,
-                                       remote_generation,
-                                       remote_version,
-                                       remote_file_version);
-        
-        EXIT;
- out_lml:
-        path_release(&nd);
-        return error;
-}       
-
+#if 0
 /* given a path: write a close record and cancel an LML record, finally
    call truncate LML.  Lento is doing this so it goes in with uid/gid's 
    root. 
@@ -396,14 +238,14 @@
 
         error=-EINVAL;
         if (fset==NULL) {
-                printk("No fileset!\n");
+                CERROR("No fileset!\n");
                 EXIT;
                 goto out_cancel_lml;
         }
         
         /* this only requires a transaction below which is automatic */
         handle = presto_trans_start(fset, dentry->d_inode, PRESTO_OP_RELEASE); 
-        if ( !handle ) {
+        if ( IS_ERR(handle) ) {
                 error = -ENOMEM; 
                 EXIT; 
                 goto out_cancel_lml; 
@@ -435,7 +277,7 @@
 
         if (info->flags & LENTO_FL_WRITE_EXPECT) {
                 error = presto_write_last_rcvd(&rec, fset, info); 
-                if ( error ) {
+                if ( error < 0 ) {
                         EXIT; 
                         presto_trans_commit(fset, handle);
                         goto out_cancel_lml;
@@ -454,148 +296,101 @@
         path_release(&nd); 
         return error;
 }       
+#endif 
 
-
-/* given a path, operate on the flags in its dentry.  Used by downcalls */
-int presto_mark_dentry(const char *name, int and_flag, int or_flag, 
+/* given a dentry, operate on the flags in its dentry.  Used by downcalls */
+int izo_mark_dentry(struct dentry *dentry, int and_flag, int or_flag, 
                        int *res)
 {
-        struct nameidata nd;
-        struct dentry *dentry;
-        int error;
-
-        CDEBUG(D_INODE, "name: %s, and flag %x, or flag %x\n",
-               name, and_flag, or_flag);
-
-        error = presto_walk(name, &nd);
-        if (error)
-                return error;
-        dentry = nd.dentry;
-        CDEBUG(D_INODE, "dentry at %p, d_fsdata %p\n", dentry, dentry->d_fsdata);
+        int error = 0;
 
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) )
-                goto out;
-
-        error = 0;
-        if ( presto_dentry_is_fsetroot(dentry) ) {
-                struct presto_file_set *fset = presto_dentry2fset(dentry);
-                CDEBUG(D_INODE, "Setting fset fset_data: fset %p\n", fset);
-                if ( fset ) {
-                        fset->fset_data &= and_flag;
-                        fset->fset_data |= or_flag;
-                        if (res) {
-                                *res = fset->fset_data;
-                        }
-                }
-                CDEBUG(D_INODE, "fset %p, flags %x data %x\n", 
-                       fset, fset->fset_flags, fset->fset_data);
-        } else {
-                ((int)(long)dentry->d_fsdata) &= and_flag;
-                ((int)(long)dentry->d_fsdata) |= or_flag;
-                if (res) 
-                        *res = (int)(long)dentry->d_fsdata;
+        if (presto_d2d(dentry) == NULL) {
+                CERROR("InterMezzo: no ddata for inode %ld in %s\n",
+                       dentry->d_inode->i_ino, __FUNCTION__);
+                return -EINVAL;
         }
 
-        /* indicate if we were the only users while changing the flag */
-        if ( atomic_read(&dentry->d_count) > 1 )
-                error = -EBUSY;
+        CDEBUG(D_INODE, "inode: %ld, and flag %x, or flag %x, dd_flags %x\n",
+               dentry->d_inode->i_ino, and_flag, or_flag,
+               presto_d2d(dentry)->dd_flags);
+
+        presto_d2d(dentry)->dd_flags &= and_flag;
+        presto_d2d(dentry)->dd_flags |= or_flag;
+        if (res) 
+                *res = presto_d2d(dentry)->dd_flags;
 
-out:
-        path_release(&nd);
         return error;
 }
 
 /* given a path, operate on the flags in its cache.  Used by mark_ioctl */
-int presto_mark_cache(const char *name, int and_flag, int or_flag, 
-                      int *res)
+int izo_mark_cache(struct dentry *dentry, int and_flag, int or_flag, 
+                   int *res)
 {
-        struct nameidata nd;
-        struct dentry *dentry;
         struct presto_cache *cache;
-        int error;
-
-        CDEBUG(D_INODE,
-               "presto_mark_cache :: name: %s, and flag %x, or flag %x\n",
-               name, and_flag, or_flag);
 
-        error = presto_walk(name, &nd);
-        if (error)
-                return error;
+        if (presto_d2d(dentry) == NULL) {
+                CERROR("InterMezzo: no ddata for inode %ld in %s\n",
+                       dentry->d_inode->i_ino, __FUNCTION__);
+                return -EINVAL;
+        }
 
-        dentry = nd.dentry;
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) )
-                goto out;
+        CDEBUG(D_INODE, "inode: %ld, and flag %x, or flag %x, dd_flags %x\n",
+               dentry->d_inode->i_ino, and_flag, or_flag,
+               presto_d2d(dentry)->dd_flags);
 
-        error = -EBADF;
         cache = presto_get_cache(dentry->d_inode);
         if ( !cache ) {
-                printk("PRESTO: BAD: cannot find cache in presto_mark_cache\n");
-                make_bad_inode(dentry->d_inode);
-                goto out;
+                CERROR("PRESTO: BAD: cannot find cache in izo_mark_cache\n");
+                return -EBADF;
         }
-        error = 0;
+
         ((int)cache->cache_flags) &= and_flag;
         ((int)cache->cache_flags) |= or_flag;
-        if (res) {
+        if (res)
                 *res = (int)cache->cache_flags;
-        }
 
-out:
-        path_release(&nd);
-        return error;
+        return 0;
 }
 
-int presto_mark_fset_dentry(struct dentry *dentry, int and_flag, int or_flag, 
-                     int * res)
+int presto_set_max_kml_size(const char *path, unsigned long max_size)
 {
-        int error;
         struct presto_file_set *fset;
 
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) )
-                return error;
+        ENTRY;
+
+        fset = presto_path2fileset(path);
+        if (IS_ERR(fset)) {
+                EXIT;
+                return PTR_ERR(fset);
+        }
+
+        fset->kml_truncate_size = max_size;
+        CDEBUG(D_CACHE, "KML truncate size set to %lu bytes for fset %s.\n",
+               max_size, path);
+
+        EXIT;
+        return 0;
+}
 
-        error = -EBADF;
+int izo_mark_fset(struct dentry *dentry, int and_flag, int or_flag, 
+                  int * res)
+{
+        struct presto_file_set *fset;
+        
         fset = presto_fset(dentry);
         if ( !fset ) {
-                printk("PRESTO: BAD: cannot find cache in presto_mark_cache\n");
+                CERROR("PRESTO: BAD: cannot find cache in izo_mark_cache\n");
                 make_bad_inode(dentry->d_inode);
-                return error;
+                return -EBADF;
         }
-        error = 0;
         ((int)fset->fset_flags) &= and_flag;
         ((int)fset->fset_flags) |= or_flag;
-        if (res) { 
+        if (res)
                 *res = (int)fset->fset_flags;
-        }
-
-        return error;
-}
-
-/* given a path, operate on the flags in its cache.  Used by mark_ioctl */
-inline int presto_mark_fset(const char *name, int and_flag, int or_flag, 
-                     int * res)
-{
-        struct nameidata nd;
-        struct dentry *dentry;
-        int error;
-        ENTRY;
 
-        error = presto_walk(name, &nd);
-        if (error)
-                return error;
-
-
-        dentry = nd.dentry;
-        error = presto_mark_fset_dentry(dentry, and_flag, or_flag, res);
-
-        path_release(&nd);
-        return error;
+        return 0;
 }
 
-
 /* talk to Lento about the permit */
 static int presto_permit_upcall(struct dentry *dentry)
 {
@@ -606,8 +401,12 @@
         int fsetnamelen;
         struct presto_file_set *fset = NULL;
 
-        if ( (minor = presto_i2m(dentry->d_inode)) < 0)
+        ENTRY;
+
+        if ( (minor = presto_i2m(dentry->d_inode)) < 0) {
+                EXIT;
                 return -EINVAL;
+        }
 
         fset = presto_fset(dentry);
         if (!fset) {
@@ -617,22 +416,26 @@
         
         if ( !presto_lento_up(minor) ) {
                 if ( fset->fset_flags & FSET_STEAL_PERMIT ) {
+                        EXIT;
                         return 0;
                 } else {
+                        EXIT;
                         return -ENOTCONN;
                 }
         }
 
-        PRESTO_ALLOC(buffer, char *, PAGE_SIZE);
+        PRESTO_ALLOC(buffer, PAGE_SIZE);
         if ( !buffer ) {
-                printk("PRESTO: out of memory!\n");
+                CERROR("PRESTO: out of memory!\n");
+                EXIT;
                 return -ENOMEM;
         }
-        path = presto_path(dentry, fset->fset_mtpt, buffer, PAGE_SIZE);
+        path = presto_path(dentry, fset->fset_dentry, buffer, PAGE_SIZE);
         pathlen = MYPATHLEN(buffer, path);
         fsetnamelen = strlen(fset->fset_name); 
-        rc = lento_permit(minor, pathlen, fsetnamelen, path, fset->fset_name);
+        rc = izo_upc_permit(minor, dentry, pathlen, path, fset->fset_name);
         PRESTO_FREE(buffer, PAGE_SIZE);
+        EXIT;
         return rc;
 }
 
@@ -641,13 +444,16 @@
  *  - if 0 is returned the permit was already in the kernel -- or --
  *    Lento gave us the permit without reintegration
  *  - lento returns the number of records it reintegrated 
+ *
+ * Note that if this fileset has branches, a permit will -never- to a normal
+ * process for writing in the data area (ie, outside of .intermezzo)
  */
 int presto_get_permit(struct inode * inode)
 {
         struct dentry *de;
         struct presto_file_set *fset;
         int minor = presto_i2m(inode);
-        int rc;
+        int rc = 0;
 
         ENTRY;
         if (minor < 0) {
@@ -657,47 +463,101 @@
 
         if ( ISLENTO(minor) ) {
                 EXIT;
-                return -EINVAL;
+                return 0;
         }
 
         if (list_empty(&inode->i_dentry)) {
-                printk("No alias for inode %d\n", (int) inode->i_ino);
+                CERROR("No alias for inode %d\n", (int) inode->i_ino);
                 EXIT;
                 return -EINVAL;
         }
 
         de = list_entry(inode->i_dentry.next, struct dentry, d_alias);
 
+        if (presto_chk(de, PRESTO_DONT_JOURNAL)) {
+                EXIT;
+                return 0;
+        }
+
         fset = presto_fset(de);
         if ( !fset ) {
-                printk("Presto: no fileset in presto_get_permit!\n");
+                CERROR("Presto: no fileset in presto_get_permit!\n");
                 EXIT;
                 return -EINVAL;
         }
 
+        if (fset->fset_flags & FSET_HAS_BRANCHES) {
+                EXIT;
+                return -EROFS;
+        }
+
+        spin_lock(&fset->fset_permit_lock);
         if (fset->fset_flags & FSET_HASPERMIT) {
-                lock_kernel();
                 fset->fset_permit_count++;
                 CDEBUG(D_INODE, "permit count now %d, inode %lx\n", 
                        fset->fset_permit_count, inode->i_ino);
-                unlock_kernel();
+                spin_unlock(&fset->fset_permit_lock);
                 EXIT;
                 return 0;
+        }
+
+        /* Allow reintegration to proceed without locks -SHP */
+        fset->fset_permit_upcall_count++;
+        if (fset->fset_permit_upcall_count == 1) {
+                spin_unlock(&fset->fset_permit_lock);
+                rc = presto_permit_upcall(fset->fset_dentry);
+                spin_lock(&fset->fset_permit_lock);
+                fset->fset_permit_upcall_count--;
+                if (rc == 0) {
+                        izo_mark_fset(fset->fset_dentry, ~0, FSET_HASPERMIT,
+                                      NULL);
+                        fset->fset_permit_count++;
+                } else if (rc == ENOTCONN) {
+                        CERROR("InterMezzo: disconnected operation. stealing permit.\n");
+                        izo_mark_fset(fset->fset_dentry, ~0, FSET_HASPERMIT,
+                                      NULL);
+                        fset->fset_permit_count++;
+                        /* set a disconnected flag here to stop upcalls */
+                        rc = 0;
+                } else {
+                        CERROR("InterMezzo: presto_permit_upcall failed: %d\n", rc);
+                        rc = -EROFS;
+                        /* go to sleep here and try again? */
+                }
+                wake_up_interruptible(&fset->fset_permit_queue);
         } else {
-		/* Allow reintegration to proceed without locks -SHP */
-                rc = presto_permit_upcall(fset->fset_mtpt);
-                lock_kernel();
-                if ( !rc ) { 
-                	presto_mark_fset_dentry
-				(fset->fset_mtpt, ~0, FSET_HASPERMIT, NULL);
-                	fset->fset_permit_count++;
+                /* Someone is already doing an upcall; go to sleep. */
+                DECLARE_WAITQUEUE(wait, current);
+
+                spin_unlock(&fset->fset_permit_lock);
+                add_wait_queue(&fset->fset_permit_queue, &wait);
+                while (1) {
+                        set_current_state(TASK_INTERRUPTIBLE);
+
+                        spin_lock(&fset->fset_permit_lock);
+                        if (fset->fset_permit_upcall_count == 0)
+                                break;
+                        spin_unlock(&fset->fset_permit_lock);
+
+                        if (signal_pending(current)) {
+                                remove_wait_queue(&fset->fset_permit_queue,
+                                                  &wait);
+                                return -ERESTARTSYS;
+                        }
+                        schedule();
                 }
-                CDEBUG(D_INODE, "permit count now %d, ino %lx (likely 1), rc %d\n", 
-        		fset->fset_permit_count, inode->i_ino, rc);
-                unlock_kernel();
-                EXIT;
-                return rc;
+                remove_wait_queue(&fset->fset_permit_queue, &wait);
+                /* We've been woken up: do we have the permit? */
+                if (fset->fset_flags & FSET_HASPERMIT)
+                        /* FIXME: Is this the right thing? */
+                        rc = -EAGAIN;
         }
+
+        CDEBUG(D_INODE, "permit count now %d, ino %ld (likely 1), "
+               "rc %d\n", fset->fset_permit_count, inode->i_ino, rc);
+        spin_unlock(&fset->fset_permit_lock);
+        EXIT;
+        return rc;
 }
 
 int presto_put_permit(struct inode * inode)
@@ -714,11 +574,11 @@
 
         if ( ISLENTO(minor) ) {
                 EXIT;
-                return -1;
+                return 0;
         }
 
         if (list_empty(&inode->i_dentry)) {
-                printk("No alias for inode %d\n", (int) inode->i_ino);
+                CERROR("No alias for inode %d\n", (int) inode->i_ino);
                 EXIT;
                 return -1;
         }
@@ -727,436 +587,143 @@
 
         fset = presto_fset(de);
         if ( !fset ) {
-                printk("Presto: no fileset in presto_get_permit!\n");
+                CERROR("InterMezzo: no fileset in %s!\n", __FUNCTION__);
                 EXIT;
                 return -1;
         }
 
-        lock_kernel();
+        if (presto_chk(de, PRESTO_DONT_JOURNAL)) {
+                EXIT;
+                return 0;
+        }
+
+        spin_lock(&fset->fset_permit_lock);
         if (fset->fset_flags & FSET_HASPERMIT) {
-                if (fset->fset_permit_count > 0) fset->fset_permit_count--;
-                else printk("Put permit while permit count is 0, inode %lx!\n",
-                                inode->i_ino); 
+                if (fset->fset_permit_count > 0)
+                        fset->fset_permit_count--;
+                else
+                        CERROR("Put permit while permit count is 0, "
+                               "inode %ld!\n", inode->i_ino); 
         } else {
-        	fset->fset_permit_count=0;
-        	printk("Put permit while no permit, inode %lx, flags %x!\n", 
-               		inode->i_ino, fset->fset_flags);
+                fset->fset_permit_count = 0;
+                CERROR("InterMezzo: put permit while no permit, inode %ld, "
+                       "flags %x!\n", inode->i_ino, fset->fset_flags);
         }
 
-        CDEBUG(D_INODE, "permit count now %d, inode %lx\n", 
-        		fset->fset_permit_count, inode->i_ino);
+        CDEBUG(D_INODE, "permit count now %d, inode %ld\n",
+               fset->fset_permit_count, inode->i_ino);
 
         if (fset->fset_flags & FSET_PERMIT_WAITING &&
-                    fset->fset_permit_count == 0) {
-                CDEBUG(D_INODE, "permit count now 0, ino %lx, notify Lento\n", 
+            fset->fset_permit_count == 0) {
+                CDEBUG(D_INODE, "permit count now 0, ino %ld, wake sleepers\n",
                        inode->i_ino);
-                presto_mark_fset_dentry(fset->fset_mtpt, ~FSET_PERMIT_WAITING, 0, NULL);
-                presto_mark_fset_dentry(fset->fset_mtpt, ~FSET_HASPERMIT, 0, NULL);
-                lento_release_permit(fset->fset_cache->cache_psdev->uc_minor,
-                                     fset->fset_permit_cookie);
-                fset->fset_permit_cookie = 0; 
+                wake_up_interruptible(&fset->fset_permit_queue);
         }
-        unlock_kernel();
+        spin_unlock(&fset->fset_permit_lock);
 
         EXIT;
         return 0;
 }
 
-
 void presto_getversion(struct presto_version * presto_version,
                        struct inode * inode)
 {
-        presto_version->pv_mtime = cpu_to_le64((__u64)inode->i_mtime);
-        presto_version->pv_ctime = cpu_to_le64((__u64)inode->i_ctime);
-        presto_version->pv_size = cpu_to_le64((__u64)inode->i_size);
-}
-
-/*
- *  note: this routine "pins" a dentry for a fileset root
- */
-int presto_set_fsetroot(char *path, char *fsetname, unsigned int fsetid,
-                        unsigned int flags)
-{
-        struct presto_file_set *fset;
-        struct presto_file_set *fset2;
-        struct dentry *dentry;
-        struct presto_cache *cache;
-        int error;
-
-        ENTRY;
-
-        PRESTO_ALLOC(fset, struct presto_file_set *, sizeof(*fset));
-        error = -ENOMEM;
-        if ( !fset ) {
-                printk(KERN_ERR "No memory allocating fset for %s\n", fsetname);
-                EXIT;
-                return -ENOMEM;
-        }
-        CDEBUG(D_INODE, "fset at %p\n", fset);
-
-        printk("presto: fsetroot: path %s, fileset name %s\n", path, fsetname);
-        error = presto_walk(path, &fset->fset_nd);
-        CDEBUG(D_INODE, "\n");
-        if (error) {
-                EXIT;
-                goto out_free;
-        }
-        dentry = fset->fset_nd.dentry;
-        CDEBUG(D_INODE, "\n");
-
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
-                EXIT;
-                goto out_dput;
-        }
-
-        CDEBUG(D_INODE, "\n");
-        cache = presto_get_cache(dentry->d_inode);
-        if (!cache) {
-                printk(KERN_ERR "No cache found for %s\n", path);
-                EXIT;
-                goto out_dput;
-        }
-
-        CDEBUG(D_INODE, "\n");
-        error = -EINVAL;
-        if ( !cache->cache_mtpt) {
-                printk(KERN_ERR "Presto - no mountpoint: fsetroot fails!\n");
-                EXIT;
-                goto out_dput;
-        }
-        CDEBUG(D_INODE, "\n");
-
-        if (!cache->cache_root_fileset)  {
-                printk(KERN_ERR "Presto - no file set: fsetroot fails!\n");
-                EXIT;
-                goto out_dput;
-        }
-
-        error = -EEXIST;
-        CDEBUG(D_INODE, "\n");
-        fset2 = presto_fset(dentry);
-        if (fset2 && (fset2->fset_mtpt == dentry) ) { 
-                printk(KERN_ERR "Fsetroot already set (path %s)\n", path);
-                EXIT;
-                goto out_dput;
-        }
-
-        fset->fset_cache = cache;
-        fset->fset_mtpt = dentry;
-        fset->fset_name = fsetname;
-        fset->fset_chunkbits = CHUNK_BITS;
-        fset->fset_flags = flags;
-	fset->fset_file_maxio = FSET_DEFAULT_MAX_FILEIO; 
-
-        dentry->d_fsdata = (void *) ( ((long)fset) + PRESTO_FSETROOT );
-        list_add(&fset->fset_list, &cache->cache_fset_list);
-
-        error = presto_init_kml_file(fset);
-        if ( error ) {
-                EXIT;
-                CDEBUG(D_JOURNAL, "Error init_kml %d\n", error);
-                goto out_list_del;
-        }
-
-        error = presto_init_last_rcvd_file(fset);
-        if ( error ) {
-                int rc;
-                EXIT;
-                rc = presto_close_journal_file(fset);
-                CDEBUG(D_JOURNAL, "Error init_lastrcvd %d, cleanup %d\n", error, rc);
-                goto out_list_del;
-        }
-
-        error = presto_init_lml_file(fset);
-        if ( error ) {
-                int rc;
-                EXIT;
-                rc = presto_close_journal_file(fset);
-                CDEBUG(D_JOURNAL, "Error init_lml %d, cleanup %d\n", error, rc);
-                goto out_list_del;
-        }
-
-#ifdef  CONFIG_KREINT
-        /* initialize kml reint buffer */
-        error = kml_init (fset); 
-        if ( error ) {
-                int rc;
-                EXIT;
-                rc = presto_close_journal_file(fset);
-                CDEBUG(D_JOURNAL, "Error init kml reint %d, cleanup %d\n", 
-                                error, rc);
-                goto out_list_del;
-        }
-#endif
-        if ( dentry->d_inode == dentry->d_inode->i_sb->s_root->d_inode) {
-                cache->cache_flags |= CACHE_FSETROOT_SET;
-        }
-
-        CDEBUG(D_PIOCTL, "-------> fset at %p, dentry at %p, mtpt %p, fset %s, cache %p, d_fsdata %p\n",
-               fset, dentry, fset->fset_mtpt, fset->fset_name, cache, dentry->d_fsdata);
-
-        EXIT;
-        return 0;
-
- out_list_del:
-        list_del(&fset->fset_list);
-        dentry->d_fsdata = 0;
- out_dput:
-        path_release(&fset->fset_nd); 
- out_free:
-        PRESTO_FREE(fset, sizeof(*fset));
-        return error;
+        presto_version->pv_mtime = (__u64)inode->i_mtime;
+        presto_version->pv_ctime = (__u64)inode->i_ctime;
+        presto_version->pv_size  = (__u64)inode->i_size;
 }
 
-int presto_get_kmlsize(char *path, size_t *size)
-{
-        struct nameidata nd;
-        struct presto_file_set *fset;
-        struct dentry *dentry;
-        int error;
-
-        ENTRY;
-        error = presto_walk(path, &nd);
-        if (error) {
-                EXIT;
-                return error;
-        }
-        dentry = nd.dentry;
-
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
-                EXIT;
-                goto kml_out;
-        }
-
-        error = -EINVAL;
-        if ( ! presto_dentry_is_fsetroot(dentry)) {
-                EXIT;
-                goto kml_out;
-        }
-
-        fset = presto_dentry2fset(dentry);
-        if (!fset) {
-                EXIT;
-                goto kml_out;
-        }
-        error = 0;
-        *size = fset->fset_kml.fd_offset;
 
- kml_out:
-        path_release(&nd);
-        return error;
-}
-
-int presto_clear_fsetroot(char *path)
+/* If uuid is non-null, it is the uuid of the peer that's making the revocation
+ * request.  If it is null, this request was made locally, without external
+ * pressure to give up the permit.  This most often occurs when a client
+ * starts up.
+ *
+ * FIXME: this function needs to be refactored slightly once we start handling
+ * multiple clients.
+ */
+int izo_revoke_permit(struct dentry *dentry, __u8 uuid[16])
 {
-        struct nameidata nd;
-        struct presto_file_set *fset;
-        struct dentry *dentry;
-        struct presto_cache *cache;
-        int error;
+        struct presto_file_set *fset; 
+        DECLARE_WAITQUEUE(wait, current);
+        int minor, rc;
 
         ENTRY;
-        error = presto_walk(path, &nd);
-        if (error) {
-                EXIT;
-                return error;
-        }
-        dentry = nd.dentry;
-
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
-                EXIT;
-                goto put_out;
-        }
-
-        error = -EINVAL;
-        if ( ! presto_dentry_is_fsetroot(dentry)) {
-                EXIT;
-                goto put_out;
-        }
 
-        fset = presto_dentry2fset(dentry);
-        if (!fset) {
+        minor = presto_i2m(dentry->d_inode);
+        if (minor < 0) {
                 EXIT;
-                goto put_out;
+                return -ENODEV;
         }
 
-#ifdef  CONFIG_KREINT
-        error = kml_cleanup (fset);
-        if ( error ) {
-                printk("InterMezzo: Closing kml for fset %s: %d\n",
-                       fset->fset_name, error);
-        }
-#endif
-
-        error = presto_close_journal_file(fset);
-        if ( error ) {
-                printk("InterMezzo: Closing journal for fset %s: %d\n",
-                       fset->fset_name, error);
-        }
-        cache = fset->fset_cache;
-        cache->cache_flags &= ~CACHE_FSETROOT_SET;
-
-        list_del(&fset->fset_list);
-        dentry->d_fsdata = 0;
-        path_release(&fset->fset_nd);
-        fset->fset_mtpt = NULL;
-        PRESTO_FREE(fset->fset_name, strlen(fset->fset_name) + 1);
-        PRESTO_FREE(fset, sizeof(*fset));
-        EXIT;
-
-put_out:
-        path_release(&nd); /* for our lookup */
-        return error;
-}
-
-int presto_clear_all_fsetroots(char *path)
-{
-        struct nameidata nd;
-        struct presto_file_set *fset;
-        struct dentry *dentry;
-        struct presto_cache *cache;
-        int error;
-        struct list_head *tmp,*tmpnext;
-
-
-        ENTRY;
-        error = presto_walk(path, &nd);
-        if (error) {
+        fset = presto_fset(dentry);
+        if (fset == NULL) {
                 EXIT;
-                return error;
+                return -ENODEV;
         }
-        dentry = nd.dentry;
 
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
+        spin_lock(&fset->fset_permit_lock);
+        if (fset->fset_flags & FSET_PERMIT_WAITING) {
+                CERROR("InterMezzo: Two processes are waiting on the same permit--this not yet supported!  Aborting this particular permit request...\n");
                 EXIT;
-                goto put_out;
+                spin_unlock(&fset->fset_permit_lock);
+                return -EINVAL;
         }
 
-        error = -EINVAL;
-        if ( ! presto_dentry_is_fsetroot(dentry)) {
-                EXIT;
-                goto put_out;
-        }
+        if (fset->fset_permit_count == 0)
+                goto got_permit;
 
-        fset = presto_dentry2fset(dentry);
-        if (!fset) {
+        /* Something is still using this permit.  Mark that we're waiting for it
+         * and go to sleep. */
+        rc = izo_mark_fset(dentry, ~0, FSET_PERMIT_WAITING, NULL);
+        spin_unlock(&fset->fset_permit_lock);
+        if (rc < 0) {
                 EXIT;
-                goto put_out;
+                return rc;
         }
 
-        cache = fset->fset_cache;
-        cache = fset->fset_cache;
-        cache->cache_flags &= ~CACHE_FSETROOT_SET;
-
-        tmp = &cache->cache_fset_list;
-        tmpnext = tmp->next;
-        while ( tmpnext != &cache->cache_fset_list) {
-		tmp=tmpnext;
-                tmpnext=tmp->next;
-                fset = list_entry(tmp, struct presto_file_set, fset_list);
-
-                
-                error = presto_close_journal_file(fset);
-                if ( error ) {
-                        printk("InterMezzo: Closing journal for fset %s: %d\n",
-                               fset->fset_name, error);
+        add_wait_queue(&fset->fset_permit_queue, &wait);
+        while (1) {
+                set_current_state(TASK_INTERRUPTIBLE);
+
+                spin_lock(&fset->fset_permit_lock);
+                if (fset->fset_permit_count == 0)
+                        break;
+                spin_unlock(&fset->fset_permit_lock);
+
+                if (signal_pending(current)) {
+                        /* FIXME: there must be a better thing to return... */
+                        remove_wait_queue(&fset->fset_permit_queue, &wait);
+                        EXIT;
+                        return -ERESTARTSYS;
                 }
-                list_del(&fset->fset_list);
-                fset->fset_mtpt->d_fsdata = 0;
-                path_release(&fset->fset_nd);
-                fset->fset_mtpt = NULL;
-                PRESTO_FREE(fset->fset_name, strlen(fset->fset_name) +1);
-                PRESTO_FREE(fset, sizeof(*fset));
-        }
-
-        EXIT;
- put_out:
-        path_release(&nd); /* for our lookup */
-        return error;
-}
-
-
-int presto_get_lastrecno(char *path, off_t *recno)
-{
-        struct nameidata nd; 
-        struct presto_file_set *fset;
-        struct dentry *dentry;
-        int error;
-        ENTRY;
-
-        error = presto_walk(path, &nd);
-        if (error) {
-                EXIT;
-                return error;
-        }
-
-        dentry = nd.dentry;
-
-        error = -ENXIO;
-        if ( !presto_ispresto(dentry->d_inode) ) {
-                EXIT;
-                goto kml_out;
-        }
 
-        error = -EINVAL;
-        if ( ! presto_dentry_is_fsetroot(dentry)) {
-                EXIT;
-                goto kml_out;
-        }
+                /* FIXME: maybe there should be a timeout here. */
 
-        fset = presto_dentry2fset(dentry);
-        if (!fset) {
-                EXIT;
-                goto kml_out;
+                schedule();
         }
-        error = 0;
-        *recno = fset->fset_kml.fd_recno;
-
- kml_out:
-        path_release(&nd);
-        return error;
-}
-
-/* 
-   if *cookie != 0, lento must wait for this cookie
-   before releasing the permit, operations are in progress. 
-*/ 
-int presto_permit_downcall( const char * path, int *cookie )
-{
-        int result;
-        struct presto_file_set *fset; 
 
-        fset = presto_path2fileset(path);
-        if (IS_ERR(fset)) { 
-                EXIT;
-                return PTR_ERR(fset);
-        }
+        remove_wait_queue(&fset->fset_permit_queue, &wait);
+ got_permit:
+        /* By this point fset->fset_permit_count is zero and we're holding the
+         * lock. */
+        CDEBUG(D_CACHE, "InterMezzo: releasing permit inode %ld\n",
+               dentry->d_inode->i_ino);
 
-	lock_kernel();
-        if (fset->fset_permit_count != 0) {
-                /* is there are previous cookie? */
-                if (fset->fset_permit_cookie == 0) {
-                        CDEBUG(D_CACHE, "presto installing cookie 0x%x, %s\n",
-                               *cookie, path);
-                        fset->fset_permit_cookie = *cookie;
-                } else {
-                        *cookie = fset->fset_permit_cookie;
-                        CDEBUG(D_CACHE, "presto has cookie 0x%x, %s\n",
-                               *cookie, path);
+        if (uuid != NULL) {
+                rc = izo_upc_revoke_permit(minor, fset->fset_name, uuid);
+                if (rc < 0) {
+                        spin_unlock(&fset->fset_permit_lock);
+                        EXIT;
+                        return rc;
                 }
-                result = presto_mark_fset(path, 0, FSET_PERMIT_WAITING, NULL);
-        } else {
-                *cookie = 0;
-                CDEBUG(D_CACHE, "presto releasing permit %s\n", path);
-                result = presto_mark_fset(path, ~FSET_HASPERMIT, 0, NULL);
         }
-	unlock_kernel();
 
-        return result;
+        izo_mark_fset(fset->fset_dentry, ~FSET_PERMIT_WAITING, 0, NULL);
+        izo_mark_fset(fset->fset_dentry, ~FSET_HASPERMIT, 0, NULL);
+        spin_unlock(&fset->fset_permit_lock);
+        EXIT;
+        return 0;
 }
 
 inline int presto_is_read_only(struct presto_file_set * fset)
@@ -1171,4 +738,3 @@
         mask= (ISLENTO(minor)? CACHE_LENTO_RO : CACHE_CLIENT_RO);
         return  ((cache->cache_flags & mask)? 1 : 0);
 }
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/psdev.c linux.20pre10-ac2/fs/intermezzo/psdev.c
--- linux.20pre10/fs/intermezzo/psdev.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/psdev.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,4 +1,6 @@
-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
  *              An implementation of a loadable kernel mode driver providing
  *              multiple kernel/user space bidirectional communications links.
  *
@@ -6,8 +8,7 @@
  *
  *              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.
+ *              version 2 as published by the Free Software Foundation.
  *
  *              Adapted to become the Linux 2.0 Coda pseudo device
  *              Peter  Braam  <braam@maths.ox.ac.uk>
@@ -22,12 +23,8 @@
  *              Copyright (c) 2000 Tacitus Systems, Inc.
  *              Copyright (c) 2001 Cluster File Systems, Inc.
  *
- *		Extended attribute support
- *		Copyright (c) 2001 Shirish. H. Phatak
- *		Copyright (c) 2001 Tacit Networks, Inc.
  */
 
-
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -42,20 +39,20 @@
 #include <linux/proc_fs.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
+#include <linux/file.h>
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/list.h>
+#include <linux/devfs_fs_kernel.h>
 #include <asm/io.h>
-#include <asm/ioctls.h>
 #include <asm/segment.h>
 #include <asm/system.h>
 #include <asm/poll.h>
 #include <asm/uaccess.h>
+#include <linux/miscdevice.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 
 
 #ifdef PRESTO_DEVEL
@@ -67,120 +64,178 @@
 #endif
 
 /* Like inode.c (presto_sym_iops), the initializer is just to prevent
-   upc_comms from appearing as a COMMON symbol (and therefore
-   interfering with other modules that use the same variable name. */
-struct upc_comm upc_comms[MAX_PRESTODEV] = {{0}};
+   izo_channels from appearing as a COMMON symbol (and therefore
+   interfering with other modules that use the same variable name). */
+struct upc_channel izo_channels[MAX_CHANNEL] = {{0}};
 
-/*
- * Device operations: map file to upcall structure
- */
-static inline struct upc_comm *presto_psdev_f2u(struct file *file)
+int izo_psdev_get_free_channel(void)
 {
-        int minor;
+        int i, result = -1;
+        
+        for (i = 0 ; i < MAX_CHANNEL ; i++ ) {
+                if (list_empty(&(izo_channels[i].uc_cache_list))) { 
+                    result = i;
+                    break;
+                }
+        }
+        return result;
+}
 
-        if ( MAJOR(file->f_dentry->d_inode->i_rdev) != PRESTO_PSDEV_MAJOR ) {
-                EXIT;
-                return NULL;
+
+int izo_psdev_setpid(int minor)
+{
+        struct upc_channel *channel; 
+        if (minor < 0 || minor >= MAX_CHANNEL) { 
+                return -EINVAL;
         }
 
-        minor = MINOR(file->f_dentry->d_inode->i_rdev);
-        if ( minor < 0 || minor >= MAX_PRESTODEV ) {
-                EXIT;
-                return NULL;
+        channel = &(izo_channels[minor]); 
+        /*
+         * This ioctl is performed by each Lento that starts up
+         * and wants to do further communication with presto.
+         */
+        CDEBUG(D_PSDEV, "Setting current pid to %d channel %d\n", 
+               current->pid, minor);
+        channel->uc_pid = current->pid;
+        spin_lock(&channel->uc_lock); 
+        if ( !list_empty(&channel->uc_processing) ) {
+                struct list_head *lh;
+                struct upc_req *req;
+                CERROR("WARNING: setpid & processing not empty!\n");
+                lh = &channel->uc_processing;
+                while ( (lh = lh->next) != &channel->uc_processing) {
+                        req = list_entry(lh, struct upc_req, rq_chain);
+                        /* freeing of req and data is done by the sleeper */
+                        wake_up(&req->rq_sleep);
+                }
+        }
+        if ( !list_empty(&channel->uc_processing) ) {
+                CERROR("BAD: FAILDED TO CLEAN PROCESSING LIST!\n");
+        }
+        spin_unlock(&channel->uc_lock); 
+        EXIT;
+        return 0;
+}
+
+int izo_psdev_setchannel(struct file *file, int fd)
+{
+
+        struct file *psdev_file = fget(fd); 
+        struct presto_cache *cache = presto_get_cache(file->f_dentry->d_inode);
+
+        if (!psdev_file) { 
+                CERROR("%s: no psdev_file!\n", __FUNCTION__);
+                return -EINVAL;
         }
 
-        return &(upc_comms[minor]);
+        if (!cache) { 
+                CERROR("%s: no cache!\n", __FUNCTION__);
+                fput(psdev_file); 
+                return -EINVAL;
+        } 
+
+        if (psdev_file->private_data) { 
+                CERROR("%s: channel already set!\n", __FUNCTION__);
+                fput(psdev_file); 
+                return -EINVAL;
+        }
+
+        psdev_file->private_data = cache->cache_psdev;
+        fput(psdev_file); 
+        EXIT; 
+        return 0; 
 }
 
 inline int presto_lento_up(int minor) 
 {
-        return upc_comms[minor].uc_pid;
+        return izo_channels[minor].uc_pid;
 }
 
-
 static unsigned int presto_psdev_poll(struct file *file, poll_table * wait)
-{
-        struct upc_comm *upccom;
+ {
+        struct upc_channel *channel = (struct upc_channel *)file->private_data;
         unsigned int mask = POLLOUT | POLLWRNORM;
-        /* ENTRY; this will flood you */
 
-        if ( ! (upccom = presto_psdev_f2u(file)) ) {
-                kdev_t dev = file->f_dentry->d_inode->i_rdev;
-                printk("InterMezzo: %s, bad device %s\n",
-                       __FUNCTION__, kdevname(dev));
+        /* ENTRY; this will flood you */
+        if ( ! channel ) { 
+                CERROR("%s: bad psdev file\n", __FUNCTION__);
+                return -EBADF;
         }
 
-        poll_wait(file, &(upccom->uc_waitq), wait);
+        poll_wait(file, &(channel->uc_waitq), wait);
 
-        if (!list_empty(&upccom->uc_pending)) {
+        spin_lock(&channel->uc_lock);
+        if (!list_empty(&channel->uc_pending)) {
                 CDEBUG(D_PSDEV, "Non-empty pending list.\n");
                 mask |= POLLIN | POLLRDNORM;
         }
+        spin_unlock(&channel->uc_lock);
 
         /* EXIT; will flood you */
         return mask;
 }
 
-
-
 /*
  *      Receive a message written by Lento to the psdev
  */
 static ssize_t presto_psdev_write(struct file *file, const char *buf,
                                   size_t count, loff_t *off)
 {
-        struct upc_comm *upccom;
+        struct upc_channel *channel = (struct upc_channel *)file->private_data;
         struct upc_req *req = NULL;
         struct upc_req *tmp;
         struct list_head *lh;
-        struct lento_down_hdr hdr;
+        struct izo_upcall_resp hdr;
+        int error;
 
-        if ( ! (upccom = presto_psdev_f2u(file)) ) {
-                kdev_t dev = file->f_dentry->d_inode->i_rdev;
-                printk("InterMezzo: %s, bad device %s\n",
-                       __FUNCTION__, kdevname(dev));
+        if ( ! channel ) { 
+                CERROR("%s: bad psdev file\n", __FUNCTION__);
+                return -EBADF;
         }
 
         /* Peek at the opcode, uniquefier */
         if ( count < sizeof(hdr) ) {
-              printk("presto_psdev_write: Lento didn't write full hdr.\n");
+              CERROR("presto_psdev_write: Lento didn't write full hdr.\n");
                 return -EINVAL;
         }
 
-        if (copy_from_user(&hdr, buf, sizeof(hdr)))
+        error = copy_from_user(&hdr, buf, sizeof(hdr));
+        if ( error )
                 return -EFAULT;
 
         CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%d,%d)\n",
                current->pid, hdr.opcode, hdr.unique);
 
+        spin_lock(&channel->uc_lock); 
         /* Look for the message on the processing queue. */
-        lh  = &upccom->uc_processing;
-        while ( (lh = lh->next) != &upccom->uc_processing ) {
+        lh  = &channel->uc_processing;
+        while ( (lh = lh->next) != &channel->uc_processing ) {
                 tmp = list_entry(lh, struct upc_req , rq_chain);
                 if (tmp->rq_unique == hdr.unique) {
                         req = tmp;
-                      /* unlink here: keeps search length minimal */
-                        list_del(&req->rq_chain);
-                      INIT_LIST_HEAD(&req->rq_chain);
+                        /* unlink here: keeps search length minimal */
+                        list_del_init(&req->rq_chain);
                         CDEBUG(D_PSDEV,"Eureka opc %d uniq %d!\n",
                                hdr.opcode, hdr.unique);
                         break;
                 }
         }
+        spin_unlock(&channel->uc_lock); 
         if (!req) {
-                printk("psdev_write: msg (%d, %d) not found\n",
+                CERROR("psdev_write: msg (%d, %d) not found\n",
                        hdr.opcode, hdr.unique);
                 return(-ESRCH);
         }
 
         /* move data into response buffer. */
         if (req->rq_bufsize < count) {
-                printk("psdev_write: too much cnt: %d, cnt: %Zd, "
+                CERROR("psdev_write: too much cnt: %d, cnt: %d, "
                        "opc: %d, uniq: %d.\n",
                        req->rq_bufsize, count, hdr.opcode, hdr.unique);
                 count = req->rq_bufsize; /* don't have more space! */
         }
-        if (copy_from_user(req->rq_data, buf, count))
+        error = copy_from_user(req->rq_data, buf, count);
+        if ( error )
                 return -EFAULT;
 
         /* adjust outsize: good upcalls can be aware of this */
@@ -197,40 +252,43 @@
 static ssize_t presto_psdev_read(struct file * file, char * buf,
                                  size_t count, loff_t *off)
 {
-        struct upc_comm *upccom;
+        struct upc_channel *channel = (struct upc_channel *)file->private_data;
         struct upc_req *req;
         int result = count;
 
-        if ( ! (upccom = presto_psdev_f2u(file)) ) {
-                kdev_t dev = file->f_dentry->d_inode->i_rdev;
-                printk("InterMezzo: %s, bad device %s\n",
-                       __FUNCTION__, kdevname(dev));
+        if ( ! channel ) { 
+                CERROR("%s: bad psdev file\n", __FUNCTION__);
+                return -EBADF;
         }
 
-        CDEBUG(D_PSDEV, "count %Zd\n", count);
-        if (list_empty(&(upccom->uc_pending))) {
+        spin_lock(&channel->uc_lock); 
+        if (list_empty(&(channel->uc_pending))) {
                 CDEBUG(D_UPCALL, "Empty pending list in read, not good\n");
+                spin_unlock(&channel->uc_lock); 
                 return -EINVAL;
         }
-
-        req = list_entry((upccom->uc_pending.next), struct upc_req, rq_chain);
+        req = list_entry((channel->uc_pending.next), struct upc_req, rq_chain);
         list_del(&(req->rq_chain));
-      if (! (req->rq_flags & REQ_ASYNC) ) {
-              list_add(&(req->rq_chain), upccom->uc_processing.prev);
-      }
-      req->rq_flags |= REQ_READ;
+        if (! (req->rq_flags & REQ_ASYNC) ) {
+                list_add(&(req->rq_chain), channel->uc_processing.prev);
+        }
+        spin_unlock(&channel->uc_lock); 
+
+        req->rq_flags |= REQ_READ;
 
         /* Move the input args into userspace */
+        CDEBUG(D_PSDEV, "\n");
         if (req->rq_bufsize <= count) {
                 result = req->rq_bufsize;
         }
 
         if (count < req->rq_bufsize) {
-                printk ("psdev_read: buffer too small, read %Zd of %d bytes\n",
+                CERROR ("psdev_read: buffer too small, read %d of %d bytes\n",
                         count, req->rq_bufsize);
         }
 
         if ( copy_to_user(buf, req->rq_data, result) ) {
+                BUG();
                 return -EFAULT;
         }
 
@@ -246,1059 +304,16 @@
         return result;
 }
 
-static int presto_psdev_ioctl(struct inode *inode, struct file *file,
-                              unsigned int cmd, unsigned long arg)
-{
-        struct upc_comm *upccom;
-        /* XXX is this rdev or dev? */
-        kdev_t dev = inode->i_rdev;
-
-        ENTRY;
-        upccom = presto_psdev_f2u(file);
-        if ( !upccom) {
-                printk("InterMezzo: %s, bad device %s\n",
-                       __FUNCTION__, kdevname(dev));
-                EXIT;
-                return -ENODEV;
-        }
-
-        switch(cmd) {
-
-        case TCGETS:
-                return -EINVAL;
-
-        case PRESTO_GETMOUNT: {
-                /* return all the mounts for this device.  */
-                int minor = 0;
-                int len, outlen;
-                struct readmount readmount;
-                struct readmount *user_readmount = (struct readmount *) arg;
-                char * tmp;
-                int error = 0;
-
-                if (copy_from_user(&readmount, (void *)arg, sizeof(readmount)))
-                {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                len = readmount.io_len;
-                minor = MINOR(dev);
-                PRESTO_ALLOC(tmp, char *, len);
-                if (!tmp) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-
-                outlen = presto_sprint_mounts(tmp, len, minor);
-                CDEBUG(D_PSDEV, "presto_sprint_mounts returns %d bytes\n",
-                                outlen);
-
-                /* as this came out on 1/3/2000, it could NEVER work.
-                 * So fix it ... RGM
-                 * I mean, let's let the compiler do a little work ...
-                 * gcc suggested the extra ()
-                 */
-                if (copy_to_user(readmount.io_string, tmp, outlen)) {
-                        CDEBUG(D_PSDEV, "Copy_to_user string 0x%p failed\n",
-                               readmount.io_string);
-			error = -EFAULT;
-                }
-                if (!error && copy_to_user(&(user_readmount->io_len),
-                                           &outlen, sizeof(int))) {
-                        CDEBUG(D_PSDEV, "Copy_to_user len @0x%p failed\n",
-                               &(user_readmount->io_len));
-			error = -EFAULT;
-                }
-
-                PRESTO_FREE(tmp, len);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_SETPID: {
-                /*
-                 * This ioctl is performed by each Lento that starts up
-                 * and wants to do further communication with presto.
-                 */
-                CDEBUG(D_PSDEV, "Setting current pid to %d\n", current->pid);
-                upccom->uc_pid = current->pid;
-                if ( !list_empty(&upccom->uc_processing) ) {
-                        struct list_head *lh;
-                        struct upc_req *req;
-                        printk("WARNING: setpid & processing not empty!\n");
-                        lh = &upccom->uc_processing;
-                        while ( (lh = lh->next) != &upccom->uc_processing) {
-                                req = list_entry(lh, struct upc_req, rq_chain);
-                                /* freeing of req and data is done by the sleeper */
-                                wake_up(&req->rq_sleep);
-                        }
-                }
-                if ( !list_empty(&upccom->uc_processing) ) {
-                        printk("BAD: FAILDED TO CLEAN PROCESSING LIST!\n");
-                }
-                EXIT;
-                return 0;
-        }
-
-        case PRESTO_CLEAR_FSETROOT: {
-                /*
-                 * Close KML files.
-                 */
-                int error;
-                int saved_pid = upccom->uc_pid;
-                char *path;
-                struct {
-                        char *path;
-                        unsigned int path_len;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-                
-                if(input.path_len > PATH_MAX)
-                {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                PRESTO_ALLOC(path, char *, input.path_len + 1);
-                if ( !path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(path, input.path, input.path_len)) {
-                        PRESTO_FREE(path, input.path_len + 1);
-                        EXIT;
-                        return -EFAULT;
-                }
-                path[input.path_len] = '\0';
-                CDEBUG(D_PSDEV, "clear_fsetroot: path %s\n", path);
-
-                upccom->uc_pid = current->pid;
-                error = presto_clear_fsetroot(path);
-                upccom->uc_pid = saved_pid;
-                PRESTO_FREE(path, input.path_len + 1);
-                EXIT;
-                return error;
-        }
-
-
-        case PRESTO_CLEAR_ALL_FSETROOTS: {
-                /*
-                 * Close KML files.
-                 */
-                int error;
-                int saved_pid = upccom->uc_pid;
-                char *path;
-                struct {
-                        char *path;
-                        unsigned int path_len;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-                
-                if(input.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                PRESTO_ALLOC(path, char *, input.path_len + 1);
-                if ( !path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(path, input.path, input.path_len)) {
-                        PRESTO_FREE(path, input.path_len + 1);
-                        EXIT;
-                        return -EFAULT;
-                }
-                path[input.path_len] = '\0';
-                CDEBUG(D_PSDEV, "clear_all_fsetroot: path %s\n", path);
-
-                upccom->uc_pid = current->pid;
-                error = presto_clear_all_fsetroots(path);
-                upccom->uc_pid = saved_pid;
-                PRESTO_FREE(path, input.path_len + 1);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_GET_KMLSIZE: {
-                int error;
-                int saved_pid = upccom->uc_pid;
-                char *path;
-                size_t size = 0;
-                struct {
-                        __u64 size;
-                        char *path;
-                        unsigned int path_len;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                if(input.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                PRESTO_ALLOC(path, char *, input.path_len + 1);
-                if ( !path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(path, input.path, input.path_len)) {
-                        PRESTO_FREE(path, input.path_len + 1);
-                        EXIT;
-                        return -EFAULT;
-                }
-                path[input.path_len] = '\0';
-                CDEBUG(D_PSDEV, "get_kmlsize: len %d path %s\n", 
-                       input.path_len, path);
-
-                upccom->uc_pid = current->pid;
-                error = presto_get_kmlsize(path, &size);
-                PRESTO_FREE(path, input.path_len + 1);
-                if (error) {
-                        EXIT;
-                        return error;
-                }
-                input.size = size;
-                upccom->uc_pid = saved_pid;
-
-                CDEBUG(D_PSDEV, "get_kmlsize: size = %Zd\n", size);
-
-                EXIT;
-                if (copy_to_user((char *)arg, &input, sizeof(input)))
-			return -EFAULT;
-		return 0;
-        }
-
-        case PRESTO_GET_RECNO: {
-                int error;
-                int saved_pid = upccom->uc_pid;
-                char *path;
-                off_t recno = 0;
-                struct {
-                        __u64 recno;
-                        char *path;
-                        unsigned int path_len;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                if(input.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                PRESTO_ALLOC(path, char *, input.path_len + 1);
-                if ( !path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(path, input.path, input.path_len)) {
-                        PRESTO_FREE(path, input.path_len + 1);
-                        EXIT;
-                        return -EFAULT;
-                }
-                path[input.path_len] = '\0';
-                CDEBUG(D_PSDEV, "get_recno: len %d path %s\n", 
-                       input.path_len, path);
-
-                upccom->uc_pid = current->pid;
-                error = presto_get_lastrecno(path, &recno);
-                PRESTO_FREE(path, input.path_len + 1);
-                if (error) {
-                        EXIT;
-                        return error;
-                }
-                input.recno = recno;
-                upccom->uc_pid = saved_pid;
-
-                CDEBUG(D_PSDEV, "get_recno: recno = %d\n", (int) recno);
-
-                EXIT;
-                if (copy_to_user((char *)arg, &input, sizeof(input)))
-			return -EFAULT;
-		return 0;
-        }
-
-        case PRESTO_SET_FSETROOT: {
-                /*
-                 * Save information about the cache, and initialize "special"
-                 * cache files (KML, etc).
-                 */
-                int error;
-                int saved_pid = upccom->uc_pid;
-                char *fsetname;
-                char *path;
-                struct {
-                        char *path;
-                        unsigned int path_len;
-                        char *name;
-                        unsigned int name_len;
-                        int   id;
-                        int   flags;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                if(input.name_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                if(input.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-                
-                PRESTO_ALLOC(path, char *, input.path_len + 1);
-                if ( !path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(path, input.path, input.path_len)) {
-                        EXIT;
-			error = -EFAULT;
-                        goto exit_free_path;
-                }
-                path[input.path_len] = '\0';
-
-                PRESTO_ALLOC(fsetname, char *, input.name_len + 1);
-                if ( !fsetname ) {
-                        error = -ENOMEM;
-                        EXIT;
-                        goto exit_free_path;
-                }
-                if (copy_from_user(fsetname, input.name, input.name_len)) {
-                        EXIT;
-			error = -EFAULT;
-                        goto exit_free_fsetname;
-                }
-                fsetname[input.name_len] = '\0';
-
-                CDEBUG(D_PSDEV,
-                       "set_fsetroot: path %s name %s, id %d, flags %x\n",
-                       path, fsetname, input.id, input.flags);
-                upccom->uc_pid = current->pid;
-                error = presto_set_fsetroot(path, fsetname, input.id,input.flags);
-                upccom->uc_pid = saved_pid;
-                if ( error ) {
-                        EXIT;
-                        goto exit_free_fsetname;
-                }
-                /* fsetname is kept in the fset, so don't free it now */
-                PRESTO_FREE(path, input.path_len + 1);
-                EXIT;
-                return 0;
-
-        exit_free_fsetname:
-                PRESTO_FREE(fsetname, input.name_len + 1);
-        exit_free_path:
-                PRESTO_FREE(path, input.path_len + 1);
-                return error;
-        }
-
-        case PRESTO_CLOSE_JOURNALF: {
-                int saved_pid = upccom->uc_pid;
-                int error;
-
-                CDEBUG(D_SUPER, "HELLO\n");
-
-                /* pretend we are lento: we should lock something */
-                upccom->uc_pid = current->pid;
-                error = presto_close_journal_file(NULL);
-                CDEBUG(D_PSDEV, "error is %d\n", error);
-                upccom->uc_pid = saved_pid;
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_GETOPT:
-        case PRESTO_SETOPT: {
-                /* return all the mounts for this device.  */
-                int dosetopt(int, struct psdev_opt *);
-                int dogetopt(int, struct psdev_opt *);
-                int minor = 0;
-                struct psdev_opt kopt;
-                int error = 0;
-                struct psdev_opt *user_opt = (struct psdev_opt *) arg;
-
-                if (copy_from_user(&kopt, (void *)arg, sizeof(kopt))) {
-                        printk("psdev: can't copyin %Zd bytes from %p to %p\n",
-                               sizeof(kopt), (struct kopt *) arg, &kopt);
-                        EXIT;
-                        return -EFAULT;
-                }
-                minor = MINOR(dev);
-                if (cmd == PRESTO_SETOPT)
-                        error = dosetopt(minor, &kopt);
-
-                if ( error ) {
-                        CDEBUG(D_PSDEV,
-                               "dosetopt failed minor %d, opt %d, val %d\n",
-                               minor, kopt.optname, kopt.optval);
-                        EXIT;
-                        return error;
-                }
-
-                error = dogetopt(minor, &kopt);
-
-                if ( error ) {
-                        CDEBUG(D_PSDEV,
-                               "dogetopt failed minor %d, opt %d, val %d\n",
-                               minor, kopt.optname, kopt.optval);
-                        EXIT;
-                        return error;
-                }
-
-                if (copy_to_user(user_opt, &kopt, sizeof(kopt))) {
-                        CDEBUG(D_PSDEV, "Copy_to_user opt 0x%p failed\n",
-                               user_opt);
-                        EXIT;
-                        return -EFAULT;
-                }
-                CDEBUG(D_PSDEV, "dosetopt minor %d, opt %d, val %d return %d\n",
-                         minor, kopt.optname, kopt.optval, error);
-                EXIT;
-                return 0;
-        }
-
-        case PRESTO_VFS_SETATTR: {
-                int error;
-                struct lento_input_attr input;
-                struct iattr iattr;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-                iattr.ia_valid = input.valid;
-                iattr.ia_mode  = (umode_t)input.mode;
-                iattr.ia_uid   = (uid_t)input.uid;
-                iattr.ia_gid   = (gid_t)input.gid;
-                iattr.ia_size  = (off_t)input.size;
-                iattr.ia_atime = (time_t)input.atime;
-                iattr.ia_mtime = (time_t)input.mtime;
-                iattr.ia_ctime = (time_t)input.ctime;
-                iattr.ia_attr_flags = input.attr_flags;
-
-                error = lento_setattr(input.name, &iattr, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_CREATE: {
-                int error;
-                struct lento_input_mode input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_create(input.name, input.mode, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_LINK: {
-                int error;
-                struct lento_input_old_new input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_link(input.oldname, input.newname, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_UNLINK: {
-                int error;
-                struct lento_input input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_unlink(input.name, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_SYMLINK: {
-                int error;
-                struct lento_input_old_new input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_symlink(input.oldname, input.newname,&input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_MKDIR: {
-                int error;
-                struct lento_input_mode input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_mkdir(input.name, input.mode, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_RMDIR: {
-                int error;
-                struct lento_input input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_rmdir(input.name, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_MKNOD: {
-                int error;
-                struct lento_input_dev input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_mknod(input.name, input.mode,
-                                    MKDEV(input.major,input.minor),&input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_VFS_RENAME: {
-                int error;
-                struct lento_input_old_new input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                error = lento_rename(input.oldname, input.newname, &input.info);
-                EXIT;
-                return error;
-        }
-
-#ifdef CONFIG_FS_EXT_ATTR
-        /* IOCTL to create/modify an extended attribute */
-        case PRESTO_VFS_SETEXTATTR: {
-                int error;
-                struct lento_input_ext_attr input;
-                char *name;
-                char *buffer;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                    EXIT;
-                    return -EFAULT;
-                }
-
-                /* Now setup the input parameters */
-                PRESTO_ALLOC(name, char *, input.name_len+1);
-                /* We need null terminated strings for attr names */
-                name[input.name_len] = '\0';
-                if (copy_from_user(name, input.name, input.name_len)) {
-                    EXIT;
-                    PRESTO_FREE(name,input.name_len+1);
-                    return -EFAULT;
-                }
-
-                PRESTO_ALLOC(buffer, char *, input.buffer_len+1);
-                if (copy_from_user(buffer, input.buffer, input.buffer_len)) {
-                    EXIT;
-                    PRESTO_FREE(name,input.name_len+1);
-                    PRESTO_FREE(buffer,input.buffer_len+1);
-                    return -EFAULT;
-                }
-                /* Make null terminated for easy printing */
-                buffer[input.buffer_len]='\0';
- 
-                CDEBUG(D_PSDEV," setextattr params: name %s, valuelen %d,"
-                       " value %s, attr flags %x, mode %o, slot offset %d,"
-                       " recno %d, kml offset %lu, flags %x, time %d\n", 
-                       name, input.buffer_len, buffer, input.flags, input.mode,
-                       input.info.slot_offset, input.info.recno,
-                       (unsigned long) input.info.kml_offset, input.info.flags,
-                       input.info.updated_time);
-
-                error=lento_set_ext_attr
-                      (input.path,name,buffer,input.buffer_len,
-                       input.flags, input.mode, &input.info);
-
-                PRESTO_FREE(name,input.name_len+1);
-                PRESTO_FREE(buffer,input.buffer_len+1);
-                EXIT;
-                return error;
-        }
-
-        /* IOCTL to delete an extended attribute */
-        case PRESTO_VFS_DELEXTATTR: {
-                int error;
-                struct lento_input_ext_attr input;
-                char *name;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                    EXIT;
-                    return -EFAULT;
-                }
-
-                /* Now setup the input parameters */
-                PRESTO_ALLOC(name, char *, input.name_len+1);
-                /* We need null terminated strings for attr names */
-                name[input.name_len] = '\0';
-                if (copy_from_user(name, input.name, input.name_len)) {
-                    EXIT;
-                    PRESTO_FREE(name,input.name_len+1);
-                    return -EFAULT;
-                }
-
-                CDEBUG(D_PSDEV," delextattr params: name %s,"
-                       " attr flags %x, mode %o, slot offset %d, recno %d,"
-                       " kml offset %lu, flags %x, time %d\n", 
-                       name, input.flags, input.mode,
-                       input.info.slot_offset, input.info.recno,
-                       (unsigned long) input.info.kml_offset, input.info.flags,
-                       input.info.updated_time);
-
-                error=lento_set_ext_attr
-                      (input.path,name,NULL,0,input.flags,
-                       input.mode,&input.info);
-                PRESTO_FREE(name,input.name_len+1);
-                EXIT;
-                return error;
-        }
-#endif
-
-        case PRESTO_VFS_IOPEN: {
-                struct lento_input_iopen input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                input.fd = lento_iopen(input.name, (ino_t)input.ino,
-                                       input.generation, input.flags);
-                CDEBUG(D_PIOCTL, "lento_iopen file descriptor: %d\n", input.fd);
-                if (input.fd < 0) {
-                        EXIT;
-                        return input.fd;
-                }
-                EXIT;
-                if (copy_to_user((char *)arg, &input, sizeof(input)))
-			return -EFAULT;
-		return 0;
-        }
-
-        case PRESTO_VFS_CLOSE: {
-                int error;
-                struct lento_input_close input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                CDEBUG(D_PIOCTL, "lento_close file descriptor: %d\n", input.fd);
-                error = lento_close(input.fd, &input.info);
-                EXIT;
-                return error;
-        }
-
-        case PRESTO_BACKFETCH_LML: {
-                char *user_path;
-                struct lml_arg {
-                        char *path;
-                        __u32 path_len;
-                        __u64 remote_ino;
-                        __u32 remote_generation;
-                        __u32 remote_version;
-                        struct presto_version remote_file_version;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                if(input.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                user_path = input.path;
-
-                PRESTO_ALLOC(input.path, char *, input.path_len + 1);
-                if ( !input.path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(input.path, user_path, input.path_len)) {
-                        EXIT;
-                        PRESTO_FREE(input.path, input.path_len + 1);
-                        return -EFAULT;
-                }
-                input.path[input.path_len] = '\0';
-
-                CDEBUG(D_DOWNCALL, "lml name: %s\n", input.path);
-                
-                return lento_write_lml(input.path, 
-                                       input.remote_ino, 
-                                       input.remote_generation,
-                                       input.remote_version,
-                                       &input.remote_file_version); 
-
-        }
-                
-
-        case PRESTO_CANCEL_LML: {
-                char *user_path;
-                struct lml_arg {
-                        char *path;
-                        __u64 lml_offset; 
-                        __u32 path_len;
-                        __u64 remote_ino;
-                        __u32 remote_generation;
-                        __u32 remote_version;
-                        struct lento_vfs_context info;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                if(input.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                user_path = input.path;
-
-                PRESTO_ALLOC(input.path, char *, input.path_len + 1);
-                if ( !input.path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(input.path, user_path, input.path_len)) {
-                        EXIT;
-                        PRESTO_FREE(input.path, input.path_len + 1);
-                        return -EFAULT;
-                }
-                input.path[input.path_len] = '\0';
-
-                CDEBUG(D_DOWNCALL, "lml name: %s\n", input.path);
-                
-                return lento_cancel_lml(input.path, 
-                                        input.lml_offset, 
-                                        input.remote_ino, 
-                                        input.remote_generation,
-                                        input.remote_version,
-                                        &input.info); 
-
-        }
-
-        case PRESTO_COMPLETE_CLOSES: {
-                char *user_path;
-                int error;
-                struct lml_arg {
-                        char *path;
-                        __u32 path_len;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                if(input.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                user_path = input.path;
-
-                PRESTO_ALLOC(input.path, char *, input.path_len + 1);
-                if ( !input.path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(input.path, user_path, input.path_len)) {
-                        EXIT;
-                        PRESTO_FREE(input.path, input.path_len + 1);
-                        return -EFAULT;
-                }
-                input.path[input.path_len] = '\0';
-
-                CDEBUG(D_DOWNCALL, "lml name: %s\n", input.path);
-                
-                error = lento_complete_closes(input.path);
-                PRESTO_FREE(input.path, input.path_len + 1);
-                return error;
-        }
-
-        case PRESTO_RESET_FSET: {
-                char *user_path;
-                struct lml_arg {
-                        char *path;
-                        __u32 path_len;
-                        __u64 offset;
-                        __u32 recno;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                if(input.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                user_path = input.path;
-
-                PRESTO_ALLOC(input.path, char *, input.path_len + 1);
-                if ( !input.path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(input.path, user_path, input.path_len)) {
-                        EXIT;
-                        PRESTO_FREE(input.path, input.path_len + 1);
-                        return -EFAULT;
-                }
-                input.path[input.path_len] = '\0';
-
-                CDEBUG(D_DOWNCALL, "lml name: %s\n", input.path);
-                
-                return lento_reset_fset(input.path, input.offset, input.recno); 
-
-        }
-                
-
-        case PRESTO_MARK: {
-                char *user_path;
-                int res = 0;  /* resulting flags - returned to user */
-                int error;
-                struct {
-                        int  mark_what;
-                        int  and_flag;
-                        int  or_flag;
-                        unsigned int path_len;
-                        char *path;
-                } input;
-
-                if (copy_from_user(&input, (char *)arg, sizeof(input))) {
-                        EXIT;
-                        return -EFAULT;
-                }
-
-                if(input.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-
-                user_path = input.path;
-
-                PRESTO_ALLOC(input.path, char *, input.path_len + 1);
-                if ( !input.path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(input.path, user_path, input.path_len)) {
-                        EXIT;
-                        PRESTO_FREE(input.path, input.path_len + 1);
-                        return -EFAULT;
-                }
-                input.path[input.path_len] = '\0';
-
-                CDEBUG(D_DOWNCALL, "mark name: %s, and: %x, or: %x, what %d\n",
-                       input.path, input.and_flag, input.or_flag, 
-                       input.mark_what);
-
-                switch (input.mark_what) {
-                case MARK_DENTRY:               
-                        error = presto_mark_dentry(input.path,
-                                                   input.and_flag,
-                                                   input.or_flag, &res);
-                        break;
-                case MARK_FSET:
-                        error = presto_mark_fset(input.path,
-                                                   input.and_flag,
-                                                   input.or_flag, &res);
-                        break;
-                case MARK_CACHE:
-                        error = presto_mark_cache(input.path,
-                                                   input.and_flag,
-                                                   input.or_flag, &res);
-                        break;
-                case MARK_GETFL: {
-                        int fflags, cflags;
-                        input.and_flag = 0xffffffff;
-                        input.or_flag = 0; 
-                        error = presto_mark_dentry(input.path,
-                                                   input.and_flag,
-                                                   input.or_flag, &res);
-                        if (error) 
-                                break;
-                        error = presto_mark_fset(input.path,
-                                                   input.and_flag,
-                                                   input.or_flag, &fflags);
-                        if (error) 
-                                break;
-                        error = presto_mark_cache(input.path,
-                                                   input.and_flag,
-                                                   input.or_flag, &cflags);
-
-                        if (error) 
-                                break;
-                        input.and_flag = fflags;
-                        input.or_flag = cflags;
-                	break;
-                }
-                default:
-                        error = -EINVAL;
-                }
-
-                PRESTO_FREE(input.path, input.path_len + 1);
-                if (error == -EBUSY) {
-                        input.and_flag = error;
-                        error = 0;
-                }
-                if (error) { 
-                        EXIT;
-                        return error;
-                }
-                /* return the correct cookie to wait for */
-                input.mark_what = res;
-                if (copy_to_user((char *)arg, &input, sizeof(input)))
-			return -EFAULT;
-		return 0;
-        }
-
-#ifdef  CONFIG_KREINT
-        case PRESTO_REINT_BEGIN:
-                return begin_kml_reint (file, arg);
-        case PRESTO_DO_REINT:
-                return do_kml_reint (file, arg);
-        case PRESTO_REINT_END:
-                return end_kml_reint (file, arg);
-#endif
-
-        case PRESTO_RELEASE_PERMIT: {
-                int error;
-                char *user_path;
-                struct {
-                        int  cookie;
-                        unsigned int path_len;
-                        char *path;
-                } permit;
-                
-                if (copy_from_user(&permit, (char *)arg, sizeof(permit))) {
-                        EXIT;
-                        return -EFAULT;
-		}
-
-                if(permit.path_len > PATH_MAX) {
-                	EXIT;
-                	return -EINVAL;
-                }
-                user_path = permit.path;
-                
-                PRESTO_ALLOC(permit.path, char *, permit.path_len + 1);
-                if ( !permit.path ) {
-                        EXIT;
-                        return -ENOMEM;
-                }
-                if (copy_from_user(permit.path, user_path, permit.path_len)) {
-                        EXIT;
-                        PRESTO_FREE(permit.path, permit.path_len + 1);
-                        return -EFAULT;
-                }
-                permit.path[permit.path_len] = '\0';
-                
-                CDEBUG(D_DOWNCALL, "release permit: %s, in cookie=%d\n",
-                       permit.path, permit.cookie);
-                error = presto_permit_downcall(permit.path, &permit.cookie);
-                
-                PRESTO_FREE(permit.path, permit.path_len + 1);
-                if (error) {
-                        EXIT;
-                        return error;
-                }
-                /* return the correct cookie to wait for */
-                if (copy_to_user((char *)arg, &permit, sizeof(permit)))
-			return -EFAULT;
-		return 0;
-        }
-        
-        default:
-                CDEBUG(D_PSDEV, "bad ioctl 0x%x, \n", cmd);
-                CDEBUG(D_PSDEV, "valid are 0x%Zx - 0x%Zx, 0x%Zx - 0x%Zx \n",
-                        PRESTO_GETMOUNT, PRESTO_GET_KMLSIZE,
-                        PRESTO_VFS_SETATTR, PRESTO_VFS_IOPEN);
-                EXIT;
-        }
-
-        return -EINVAL;
-}
-
 
 static int presto_psdev_open(struct inode * inode, struct file * file)
 {
-         struct upc_comm *upccom;
-         ENTRY;
+        ENTRY;
 
-         if ( ! (upccom = presto_psdev_f2u(file)) ) {
-                 kdev_t dev = file->f_dentry->d_inode->i_rdev;
-                 printk("InterMezzo: %s, bad device %s\n",
-                        __FUNCTION__, kdevname(dev));
-                 EXIT;
-                 return -EINVAL;
-         }
+        file->private_data = NULL;  
 
         MOD_INC_USE_COUNT;
 
-        CDEBUG(D_PSDEV, "Psdev_open: uc_pid: %d, caller: %d, flags: %d\n",
-               upccom->uc_pid, current->pid, file->f_flags);
+        CDEBUG(D_PSDEV, "Psdev_open: caller: %d, flags: %d\n", current->pid, file->f_flags);
 
         EXIT;
         return 0;
@@ -1308,32 +323,25 @@
 
 static int presto_psdev_release(struct inode * inode, struct file * file)
 {
-        struct upc_comm *upccom;
+        struct upc_channel *channel = (struct upc_channel *)file->private_data;
         struct upc_req *req;
         struct list_head *lh;
         ENTRY;
 
-
-        if ( ! (upccom = presto_psdev_f2u(file)) ) {
-                kdev_t dev = file->f_dentry->d_inode->i_rdev;
-                printk("InterMezzo: %s, bad device %s\n",
-                       __FUNCTION__, kdevname(dev));
-        }
-
-        if ( upccom->uc_pid != current->pid ) {
-                printk("psdev_release: Not lento.\n");
-                MOD_DEC_USE_COUNT;
-                return 0;
+        if ( ! channel ) { 
+                CERROR("%s: bad psdev file\n", __FUNCTION__);
+                return -EBADF;
         }
 
         MOD_DEC_USE_COUNT;
         CDEBUG(D_PSDEV, "Lento: pid %d\n", current->pid);
-        upccom->uc_pid = 0;
+        channel->uc_pid = 0;
 
         /* Wake up clients so they can return. */
         CDEBUG(D_PSDEV, "Wake up clients sleeping for pending.\n");
-        lh = &upccom->uc_pending;
-        while ( (lh = lh->next) != &upccom->uc_pending) {
+        spin_lock(&channel->uc_lock); 
+        lh = &channel->uc_pending;
+        while ( (lh = lh->next) != &channel->uc_pending) {
                 req = list_entry(lh, struct upc_req, rq_chain);
 
                 /* Async requests stay around for a new lento */
@@ -1346,13 +354,14 @@
         }
 
         CDEBUG(D_PSDEV, "Wake up clients sleeping for processing\n");
-        lh = &upccom->uc_processing;
-        while ( (lh = lh->next) != &upccom->uc_processing) {
+        lh = &channel->uc_processing;
+        while ( (lh = lh->next) != &channel->uc_processing) {
                 req = list_entry(lh, struct upc_req, rq_chain);
                 /* freeing of req and data is done by the sleeper */
                 req->rq_flags |= REQ_DEAD; 
                 wake_up(&req->rq_sleep);
         }
+        spin_unlock(&channel->uc_lock); 
         CDEBUG(D_PSDEV, "Done.\n");
 
         EXIT;
@@ -1360,57 +369,46 @@
 }
 
 static struct file_operations presto_psdev_fops = {
-        read:    presto_psdev_read,
-        write:   presto_psdev_write,
-        poll:    presto_psdev_poll,
-        ioctl:   presto_psdev_ioctl,
-        open:    presto_psdev_open,
-        release: presto_psdev_release
+        .read    = presto_psdev_read,
+        .write   = presto_psdev_write,
+        .poll    = presto_psdev_poll,
+        .open    = presto_psdev_open,
+        .release = presto_psdev_release
 };
 
+/* modules setup */
+static struct miscdevice intermezzo_psdev = {
+        INTERMEZZO_MINOR,
+        "intermezzo",
+        &presto_psdev_fops
+};
 
 int  presto_psdev_init(void)
 {
         int i;
+        int err; 
 
-#ifdef PRESTO_DEVEL
-        if (register_chrdev(PRESTO_PSDEV_MAJOR, "intermezzo_psdev_devel",
-                           &presto_psdev_fops)) {
-                printk(KERN_ERR "presto_psdev: unable to get major %d\n",
-                       PRESTO_PSDEV_MAJOR);
+        if ( (err = misc_register(&intermezzo_psdev)) ) { 
+                CERROR("%s: cannot register %d err %d\n", 
+                       __FUNCTION__, INTERMEZZO_MINOR, err);
                 return -EIO;
         }
-#else
-        if (register_chrdev(PRESTO_PSDEV_MAJOR, "intermezzo_psdev",
-                           &presto_psdev_fops)) {
-                printk("presto_psdev: unable to get major %d\n",
-                       PRESTO_PSDEV_MAJOR);
-                return -EIO;
-        }
-#endif
 
-        memset(&upc_comms, 0, sizeof(upc_comms));
-        for ( i = 0 ; i < MAX_PRESTODEV ; i++ ) {
-                char *name;
-                struct upc_comm *psdev = &upc_comms[i];
-                INIT_LIST_HEAD(&psdev->uc_pending);
-                INIT_LIST_HEAD(&psdev->uc_processing);
-                INIT_LIST_HEAD(&psdev->uc_cache_list);
-                init_waitqueue_head(&psdev->uc_waitq);
-                psdev->uc_hard = 0;
-                psdev->uc_no_filter = 0;
-                psdev->uc_no_journal = 0;
-                psdev->uc_no_upcall = 0;
-                psdev->uc_timeout = 30;
-                psdev->uc_errorval = 0;
-                psdev->uc_minor = i;
-                PRESTO_ALLOC(name, char *, strlen(PRESTO_PSDEV_NAME "256")+1);
-                if (!name) { 
-                        printk("Unable to allocate memory for device name\n");
-                        continue;
-                }
-                sprintf(name, PRESTO_PSDEV_NAME "%d", i); 
-                psdev->uc_devname = name;
+        memset(&izo_channels, 0, sizeof(izo_channels));
+        for ( i = 0 ; i < MAX_CHANNEL ; i++ ) {
+                struct upc_channel *channel = &(izo_channels[i]);
+                INIT_LIST_HEAD(&channel->uc_pending);
+                INIT_LIST_HEAD(&channel->uc_processing);
+                INIT_LIST_HEAD(&channel->uc_cache_list);
+                init_waitqueue_head(&channel->uc_waitq);
+                channel->uc_lock = SPIN_LOCK_UNLOCKED;
+                channel->uc_hard = 0;
+                channel->uc_no_filter = 0;
+                channel->uc_no_journal = 0;
+                channel->uc_no_upcall = 0;
+                channel->uc_timeout = 30;
+                channel->uc_errorval = 0;
+                channel->uc_minor = i;
         }
         return 0;
 }
@@ -1419,25 +417,24 @@
 {
         int i;
 
-        for ( i = 0 ; i < MAX_PRESTODEV ; i++ ) {
-                struct upc_comm *psdev = &upc_comms[i];
+        misc_deregister(&intermezzo_psdev);
+
+        for ( i = 0 ; i < MAX_CHANNEL ; i++ ) {
+                struct upc_channel *channel = &(izo_channels[i]);
                 struct list_head *lh;
 
-                if ( ! list_empty(&psdev->uc_pending)) { 
-                        printk("Weird, tell Peter: module cleanup and pending list not empty dev %d\n", i);
-                }
-                if ( ! list_empty(&psdev->uc_processing)) { 
-                        printk("Weird, tell Peter: module cleanup and processing list not empty dev %d\n", i);
+                spin_lock(&channel->uc_lock); 
+                if ( ! list_empty(&channel->uc_pending)) { 
+                        CERROR("Weird, tell Peter: module cleanup and pending list not empty dev %d\n", i);
                 }
-                if ( ! list_empty(&psdev->uc_cache_list)) { 
-                        printk("Weird, tell Peter: module cleanup and cache listnot empty dev %d\n", i);
+                if ( ! list_empty(&channel->uc_processing)) { 
+                        CERROR("Weird, tell Peter: module cleanup and processing list not empty dev %d\n", i);
                 }
-                if (psdev->uc_devname) {
-                        PRESTO_FREE(psdev->uc_devname,
-                                    strlen(PRESTO_PSDEV_NAME "256")+1);
+                if ( ! list_empty(&channel->uc_cache_list)) { 
+                        CERROR("Weird, tell Peter: module cleanup and cache listnot empty dev %d\n", i);
                 }
-                lh = psdev->uc_pending.next;
-                while ( lh != &psdev->uc_pending) {
+                lh = channel->uc_pending.next;
+                while ( lh != &channel->uc_pending) {
                         struct upc_req *req;
 
                         req = list_entry(lh, struct upc_req, rq_chain);
@@ -1453,22 +450,23 @@
                                 wake_up(&req->rq_sleep);
                         }
                 }
-                lh = &psdev->uc_processing;
-                while ( (lh = lh->next) != &psdev->uc_processing ) {
+                lh = &channel->uc_processing;
+                while ( (lh = lh->next) != &channel->uc_processing ) {
                         struct upc_req *req;
                         req = list_entry(lh, struct upc_req, rq_chain);
                         list_del(&(req->rq_chain));
                         req->rq_flags |= REQ_DEAD; 
                         wake_up(&req->rq_sleep);
                 }
+                spin_unlock(&channel->uc_lock); 
         }
 }
 
 /*
  * lento_upcall and lento_downcall routines
  */
-static inline unsigned long lento_waitfor_upcall(struct upc_req *req,
-                                                 int minor)
+static inline unsigned long lento_waitfor_upcall
+            (struct upc_channel *channel, struct upc_req *req, int minor)
 {
         DECLARE_WAITQUEUE(wait, current);
         unsigned long posttime;
@@ -1477,16 +475,17 @@
 
         add_wait_queue(&req->rq_sleep, &wait);
         for (;;) {
-                if ( upc_comms[minor].uc_hard == 0 )
-                        current->state = TASK_INTERRUPTIBLE;
+                if ( izo_channels[minor].uc_hard == 0 )
+                        set_current_state(TASK_INTERRUPTIBLE);
                 else
-                        current->state = TASK_UNINTERRUPTIBLE;
+                        set_current_state(TASK_UNINTERRUPTIBLE);
 
                 /* got a reply */
                 if ( req->rq_flags & (REQ_WRITE | REQ_DEAD) )
                         break;
 
-                if ( !upc_comms[minor].uc_hard && signal_pending(current) ) {
+                /* these cases only apply when TASK_INTERRUPTIBLE */ 
+                if ( !izo_channels[minor].uc_hard && signal_pending(current) ) {
                         /* if this process really wants to die, let it go */
                         if (sigismember(&(current->pending.signal), SIGKILL)||
                             sigismember(&(current->pending.signal), SIGINT) )
@@ -1494,21 +493,21 @@
                         /* signal is present: after timeout always return
                            really smart idea, probably useless ... */
                         if ( time_after(jiffies, req->rq_posttime +
-                             upc_comms[minor].uc_timeout * HZ) )
+                             izo_channels[minor].uc_timeout * HZ) )
                                 break;
                 }
                 schedule();
-
         }
-      list_del(&req->rq_chain); 
-      INIT_LIST_HEAD(&req->rq_chain); 
+
+        spin_lock(&channel->uc_lock);
+        list_del_init(&req->rq_chain); 
+        spin_unlock(&channel->uc_lock);
         remove_wait_queue(&req->rq_sleep, &wait);
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
 
         CDEBUG(D_SPECIAL, "posttime: %ld, returned: %ld\n",
                posttime, jiffies-posttime);
         return  (jiffies - posttime);
-
 }
 
 /*
@@ -1524,31 +523,30 @@
  * is read (in presto_psdev_read), when the filesystem is unmounted, or
  * when the module is unloaded.
  */
-int lento_upcall(int minor, int bufsize, int *rep_size, union up_args *buffer,
-                 int async, struct upc_req *rq)
+int izo_upc_upcall(int minor, int *size, struct izo_upcall_hdr *buffer, 
+                   int async)
 {
         unsigned long runtime;
-        struct upc_comm *upc_commp;
-        union down_args *out;
+        struct upc_channel *channel;
+        struct izo_upcall_resp *out;
         struct upc_req *req;
         int error = 0;
 
         ENTRY;
-        upc_commp = &(upc_comms[minor]);
+        channel = &(izo_channels[minor]);
 
-        if (upc_commp->uc_no_upcall) {
+        if (channel->uc_no_upcall) {
                 EXIT;
                 goto exit_buf;
         }
-        if (!upc_commp->uc_pid && !async) {
+        if (!channel->uc_pid && !async) {
                 EXIT;
                 error = -ENXIO;
                 goto exit_buf;
         }
 
         /* Format the request message. */
-        CDEBUG(D_UPCALL, "buffer at %p, size %d\n", buffer, bufsize);
-        PRESTO_ALLOC(req, struct upc_req *, sizeof(struct upc_req));
+        PRESTO_ALLOC(req, sizeof(struct upc_req));
         if ( !req ) {
                 EXIT;
                 error = -ENOMEM;
@@ -1556,29 +554,29 @@
         }
         req->rq_data = (void *)buffer;
         req->rq_flags = 0;
-        req->rq_bufsize = bufsize;
+        req->rq_bufsize = *size;
         req->rq_rep_size = 0;
-        req->rq_opcode = ((union up_args *)buffer)->uh.opcode;
-        req->rq_unique = ++upc_commp->uc_seq;
+        req->rq_opcode = buffer->u_opc;
+        req->rq_unique = ++channel->uc_seq;
         init_waitqueue_head(&req->rq_sleep);
 
         /* Fill in the common input args. */
-        ((union up_args *)buffer)->uh.unique = req->rq_unique;
+        buffer->u_uniq = req->rq_unique;
+        buffer->u_async = async;
+
+        spin_lock(&channel->uc_lock); 
         /* Append msg to pending queue and poke Lento. */
-        list_add(&req->rq_chain, upc_commp->uc_pending.prev);
+        list_add(&req->rq_chain, channel->uc_pending.prev);
+        spin_unlock(&channel->uc_lock); 
         CDEBUG(D_UPCALL,
                "Proc %d waking Lento %d for(opc,uniq) =(%d,%d) msg at %p.\n",
-               current->pid, upc_commp->uc_pid, req->rq_opcode,
+               current->pid, channel->uc_pid, req->rq_opcode,
                req->rq_unique, req);
-
-        wake_up_interruptible(&upc_commp->uc_waitq);
+        wake_up_interruptible(&channel->uc_waitq);
 
         if ( async ) {
-                req->rq_flags = REQ_ASYNC;
-                if( rq != NULL ) {
-                        *rq = *req; /* struct copying */
-                }
                 /* req, rq_data are freed in presto_psdev_read for async */
+                req->rq_flags = REQ_ASYNC;
                 EXIT;
                 return 0;
         }
@@ -1593,29 +591,29 @@
          * ENODEV.  */
 
         /* Go to sleep.  Wake up on signals only after the timeout. */
-        runtime = lento_waitfor_upcall(req, minor);
+        runtime = lento_waitfor_upcall(channel, req, minor);
 
         CDEBUG(D_TIMING, "opc: %d time: %ld uniq: %d size: %d\n",
                req->rq_opcode, jiffies - req->rq_posttime,
                req->rq_unique, req->rq_rep_size);
         CDEBUG(D_UPCALL,
-               "..process %d woken up by Lento for req at 0x%p, data at %p\n",
-               current->pid, req, req->rq_data);
+               "..process %d woken up by Lento for req at 0x%x, data at %x\n",
+               current->pid, (int)req, (int)req->rq_data);
 
-        if (upc_commp->uc_pid) {      /* i.e. Lento is still alive */
+        if (channel->uc_pid) {      /* i.e. Lento is still alive */
           /* Op went through, interrupt or not we go on */
             if (req->rq_flags & REQ_WRITE) {
-                    out = (union down_args *)req->rq_data;
+                    out = (struct izo_upcall_resp *)req->rq_data;
                     /* here we map positive Lento errors to kernel errors */
-                    if ( out->dh.result < 0 ) {
-                            printk("Tell Peter: Lento returns negative error %d, for oc %d!\n",
-                                   out->dh.result, out->dh.opcode);
-                          out->dh.result = EINVAL;
+                    if ( out->result < 0 ) {
+                            CERROR("Tell Peter: Lento returns negative error %d, for oc %d!\n",
+                                   out->result, out->opcode);
+                          out->result = EINVAL;
                     }
-                    error = -out->dh.result;
+                    error = -out->result;
                     CDEBUG(D_UPCALL, "upcall: (u,o,r) (%d, %d, %d) out at %p\n",
-                           out->dh.unique, out->dh.opcode, out->dh.result, out);
-                    *rep_size = req->rq_rep_size;
+                           out->unique, out->opcode, out->result, out);
+                    *size = req->rq_rep_size;
                     EXIT;
                     goto exit_req;
             }
@@ -1632,53 +630,16 @@
 
             /* interrupted after Lento did its read, send signal */
             if ( (req->rq_flags & REQ_READ) && signal_pending(current) ) {
-                    union up_args *sigargs;
-                    struct upc_req *sigreq;
-
-                    CDEBUG(D_UPCALL,"Sending for: op = %d.%d, flags = %x\n",
+                    CDEBUG(D_UPCALL,"Interrupt after read: op = %d.%d, flags = %x\n",
                            req->rq_opcode, req->rq_unique, req->rq_flags);
 
                     error = -EINTR;
-
-                    /* req, rq_data are freed in presto_psdev_read for async */
-                    PRESTO_ALLOC(sigreq, struct upc_req *,
-                                 sizeof (struct upc_req));
-                    if (!sigreq) {
-                            error = -ENOMEM;
-                            EXIT;
-                            goto exit_req;
-                    }
-                    PRESTO_ALLOC((sigreq->rq_data), char *,
-                                 sizeof(struct lento_up_hdr));
-                    if (!(sigreq->rq_data)) {
-                            PRESTO_FREE(sigreq, sizeof (struct upc_req));
-                            error = -ENOMEM;
-                            EXIT;
-                            goto exit_req;
-                    }
-
-                    sigargs = (union up_args *)sigreq->rq_data;
-                    sigargs->uh.opcode = LENTO_SIGNAL;
-                    sigargs->uh.unique = req->rq_unique;
-
-                    sigreq->rq_flags = REQ_ASYNC;
-                    sigreq->rq_opcode = sigargs->uh.opcode;
-                    sigreq->rq_unique = sigargs->uh.unique;
-                    sigreq->rq_bufsize = sizeof(struct lento_up_hdr);
-                    sigreq->rq_rep_size = 0;
-                    CDEBUG(D_UPCALL,
-                           "presto_upcall: enqueing signal msg (%d, %d)\n",
-                           sigreq->rq_opcode, sigreq->rq_unique);
-
-                    /* insert at head of queue! */
-                    list_add(&sigreq->rq_chain, &upc_commp->uc_pending);
-                    wake_up_interruptible(&upc_commp->uc_waitq);
             } else {
-                  printk("Lento: Strange interruption - tell Peter.\n");
+                  CERROR("Lento: Strange interruption - tell Peter.\n");
                     error = -EINTR;
             }
-        } else {        /* If lento died i.e. !UC_OPEN(upc_commp) */
-                printk("presto_upcall: Lento dead on (op,un) (%d.%d) flags %d\n",
+        } else {        /* If lento died i.e. !UC_OPEN(channel) */
+                CERROR("lento_upcall: Lento dead on (op,un) (%d.%d) flags %d\n",
                        req->rq_opcode, req->rq_unique, req->rq_flags);
                 error = -ENODEV;
         }
@@ -1686,8 +647,5 @@
 exit_req:
         PRESTO_FREE(req, sizeof(struct upc_req));
 exit_buf:
-        PRESTO_FREE(buffer, bufsize);
         return error;
 }
-
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/replicator.c linux.20pre10-ac2/fs/intermezzo/replicator.c
--- linux.20pre10/fs/intermezzo/replicator.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/replicator.c	2002-10-10 23:24:51.000000000 +0100
@@ -0,0 +1,291 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
+ * Copyright (C) 2001 Tacit Networks, Inc. <phil@off.net>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Manage RCVD records for clients in the kernel
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <stdarg.h>
+#include <asm/uaccess.h>
+
+#include <linux/errno.h>
+
+#include <linux/intermezzo_fs.h>
+
+/*
+ * this file contains a hash table of replicators/clients for a
+ * fileset. It allows fast lookup and update of reintegration status
+ */
+
+struct izo_offset_rec {
+	struct list_head or_list;
+	char             or_uuid[16];
+	loff_t           or_offset;
+};
+
+#define RCACHE_BITS 8
+#define RCACHE_SIZE (1 << RCACHE_BITS)
+#define RCACHE_MASK (RCACHE_SIZE - 1)
+
+static struct list_head *
+izo_rep_cache(void)
+{
+	int i;
+	struct list_head *cache;
+	PRESTO_ALLOC(cache, sizeof(struct list_head) * RCACHE_SIZE);
+	if (cache == NULL) {
+		CERROR("intermezzo-fatal: no memory for replicator cache\n");
+                return NULL;
+	}
+	memset(cache, 0, sizeof(struct list_head) * RCACHE_SIZE);
+	for (i = 0; i < RCACHE_SIZE; i++)
+		INIT_LIST_HEAD(&cache[i]);
+
+	return cache;
+}
+
+static struct list_head *
+izo_rep_hash(struct list_head *cache, char *uuid)
+{
+        return &cache[(RCACHE_MASK & uuid[1])];
+}
+
+static void
+izo_rep_cache_clean(struct presto_file_set *fset)
+{
+	int i;
+	struct list_head *bucket;
+	struct list_head *tmp;
+
+        if (fset->fset_clients == NULL)
+		return;
+        for (i = 0; i < RCACHE_SIZE; i++) {
+		tmp = bucket = &fset->fset_clients[i];
+
+		tmp = tmp->next;
+                while (tmp != bucket) {
+			struct izo_offset_rec *offrec;
+			tmp = tmp->next;
+			list_del(tmp);
+			offrec = list_entry(tmp, struct izo_offset_rec,
+					    or_list);
+			PRESTO_FREE(offrec, sizeof(struct izo_offset_rec));
+		}
+	}
+}
+
+struct izo_offset_rec *
+izo_rep_cache_find(struct presto_file_set *fset, char *uuid)
+{
+	struct list_head *buck = izo_rep_hash(fset->fset_clients, uuid);
+	struct list_head *tmp = buck;
+        struct izo_offset_rec *rec = NULL;
+
+        while ( (tmp = tmp->next) != buck ) {
+		rec = list_entry(tmp, struct izo_offset_rec, or_list);
+                if ( memcmp(rec->or_uuid, uuid, sizeof(rec->or_uuid)) == 0 )
+			return rec;
+	}
+
+	return NULL;
+}
+
+static int
+izo_rep_cache_add(struct presto_file_set *fset, struct izo_rcvd_rec *rec,
+                  loff_t offset)
+{
+        struct izo_offset_rec *offrec;
+
+        if (izo_rep_cache_find(fset, rec->lr_uuid)) {
+                CERROR("izo: duplicate client entry %s off %Ld\n",
+                       fset->fset_name, offset);
+                return -EINVAL;
+        }
+
+        PRESTO_ALLOC(offrec, sizeof(*offrec));
+        if (offrec == NULL) {
+                CERROR("izo: cannot allocate offrec\n");
+                return -ENOMEM;
+        }
+
+        memcpy(offrec->or_uuid, rec->lr_uuid, sizeof(rec->lr_uuid));
+        offrec->or_offset = offset;
+
+        list_add(&offrec->or_list,
+                 izo_rep_hash(fset->fset_clients, rec->lr_uuid));
+        return 0;
+}
+
+int
+izo_rep_cache_init(struct presto_file_set *fset)
+{
+	struct izo_rcvd_rec rec;
+        loff_t offset = 0, last_offset = 0;
+
+	fset->fset_clients = izo_rep_cache();
+        if (fset->fset_clients == NULL) {
+		CERROR("Error initializing client cache\n");
+		return -ENOMEM;
+	}
+
+        while ( presto_fread(fset->fset_rcvd.fd_file, (char *)&rec,
+                             sizeof(rec), &offset) == sizeof(rec) ) {
+                int rc;
+
+                if ((rc = izo_rep_cache_add(fset, &rec, last_offset)) < 0) {
+			izo_rep_cache_clean(fset);
+			return rc;
+		}
+
+                last_offset = offset;
+	}
+
+	return 0;
+}
+
+/*
+ * Return local last_rcvd record for the client. Update or create 
+ * if necessary.
+ *
+ * XXX: After this call, any -EINVAL from izo_rcvd_get is a real error.
+ */
+int
+izo_repstatus(struct presto_file_set *fset,  __u64 client_kmlsize, 
+              struct izo_rcvd_rec *lr_client, struct izo_rcvd_rec *lr_server)
+{
+        int rc;
+        rc = izo_rcvd_get(lr_server, fset, lr_client->lr_uuid);
+        if (rc < 0 && rc != -EINVAL) {
+                return rc;
+        }
+
+        /* client is new or has been reset. */
+        if (rc < 0 || (client_kmlsize == 0 && lr_client->lr_remote_offset == 0)) {
+                memset(lr_server, 0, sizeof(*lr_server));
+                memcpy(lr_server->lr_uuid, lr_client->lr_uuid, sizeof(lr_server->lr_uuid));
+                rc = izo_rcvd_write(fset, lr_server);
+                if (rc < 0)
+                        return rc;
+        }
+
+        /* update intersync */
+        rc = izo_upc_repstatus(presto_f2m(fset), fset->fset_name, lr_server);
+        return rc;
+}
+
+loff_t
+izo_rcvd_get(struct izo_rcvd_rec *rec, struct presto_file_set *fset, char *uuid)
+{
+        struct izo_offset_rec *offrec;
+        struct izo_rcvd_rec tmprec;
+        loff_t offset;
+
+        offrec = izo_rep_cache_find(fset, uuid);
+        if (offrec == NULL) {
+                CDEBUG(D_SPECIAL, "izo_get_rcvd: uuid not in hash.\n");
+                return -EINVAL;
+        }
+        offset = offrec->or_offset;
+
+        if (rec == NULL)
+                return offset;
+
+        if (presto_fread(fset->fset_rcvd.fd_file, (char *)&tmprec,
+                         sizeof(tmprec), &offset) != sizeof(tmprec)) {
+                CERROR("izo_get_rcvd: Unable to read from last_rcvd file offset "
+                       "%Lu\n", offset);
+                return -EIO;
+        }
+
+        memcpy(rec->lr_uuid, tmprec.lr_uuid, sizeof(tmprec.lr_uuid));
+        rec->lr_remote_recno = le64_to_cpu(tmprec.lr_remote_recno);
+        rec->lr_remote_offset = le64_to_cpu(tmprec.lr_remote_offset);
+        rec->lr_local_recno = le64_to_cpu(tmprec.lr_local_recno);
+        rec->lr_local_offset = le64_to_cpu(tmprec.lr_local_offset);
+        rec->lr_last_ctime = le64_to_cpu(tmprec.lr_last_ctime);
+
+        return offrec->or_offset;
+}
+
+/* Try to lookup the UUID in the hash.  Insert it if it isn't found.  Write the
+ * data to the file.
+ *
+ * Returns the offset of the beginning of the record in the last_rcvd file. */
+loff_t
+izo_rcvd_write(struct presto_file_set *fset, struct izo_rcvd_rec *rec)
+{
+        struct izo_offset_rec *offrec;
+        loff_t offset, rc;
+
+        ENTRY;
+
+        offrec = izo_rep_cache_find(fset, rec->lr_uuid);
+        if (offrec == NULL) {
+                /* I don't think it should be possible for an entry to be not in
+                 * the hash table without also having an invalid offset, but we
+                 * handle it gracefully regardless. */
+                write_lock(&fset->fset_rcvd.fd_lock);
+                offset = fset->fset_rcvd.fd_offset;
+                fset->fset_rcvd.fd_offset += sizeof(*rec);
+                write_unlock(&fset->fset_rcvd.fd_lock);
+
+                rc = izo_rep_cache_add(fset, rec, offset);
+                if (rc < 0) {
+                        EXIT;
+                        return rc;
+                }
+        } else
+                offset = offrec->or_offset;
+        
+
+        rc = presto_fwrite(fset->fset_rcvd.fd_file, (char *)rec, sizeof(*rec),
+                           &offset);
+        if (rc == sizeof(*rec))
+                /* presto_fwrite() advances 'offset' */
+                rc = offset - sizeof(*rec);
+
+        EXIT;
+        return rc;
+}
+
+loff_t
+izo_rcvd_upd_remote(struct presto_file_set *fset, char * uuid,  __u64 remote_recno, 
+                    __u64 remote_offset)
+{
+        struct izo_rcvd_rec rec;
+        
+        loff_t rc;
+
+        ENTRY;
+        rc = izo_rcvd_get(&rec, fset, uuid);
+        if (rc < 0)
+                return rc;
+        rec.lr_remote_recno = remote_recno;
+        rec.lr_remote_offset = remote_offset;
+
+        rc = izo_rcvd_write(fset, &rec);
+        EXIT;
+        if (rc < 0)
+                return rc;
+        return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/super.c linux.20pre10-ac2/fs/intermezzo/super.c
--- linux.20pre10/fs/intermezzo/super.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/super.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,13 +1,30 @@
-/*
- *  presto's super.c
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
- *  Copyright (C) 1998 Peter J. Braam
+ *  Copyright (C) 1998 Peter J. Braam <braam@clusterfs.com>
  *  Copyright (C) 2000 Stelias Computing, Inc.
  *  Copyright (C) 2000 Red Hat, Inc.
  *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
+ *  presto's super.c
  */
 
+static char rcsid[] __attribute ((unused)) = "$Id: super.c,v 1.41 2002/10/03 03:50:49 rread Exp $";
+#define INTERMEZZO_VERSION "$Revision: 1.41 $"
 
 #include <stdarg.h>
 
@@ -26,11 +43,11 @@
 #include <linux/locks.h>
 #include <linux/blkdev.h>
 #include <linux/init.h>
+#include <linux/devfs_fs_kernel.h>
 #define __NO_VERSION__
 #include <linux/module.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
 
 #ifdef PRESTO_DEBUG
@@ -38,23 +55,8 @@
 long presto_kmemory = 0;
 #endif
 
-extern struct presto_cache *presto_init_cache(void);
-extern inline void presto_cache_add(struct presto_cache *cache, kdev_t dev);
-extern inline void presto_init_cache_hash(void);
-
-int presto_remount(struct super_block *, int *, char *);
-extern ssize_t presto_file_write(struct file *file, const char *buf, 
-                                 size_t size, loff_t *off);
-
-/*
- *  Reading the super block.
- *
- *
- *
- */
-
 /* returns an allocated string, copied out from data if opt is found */
-static char *read_opt(const char *opt, char *data)
+static char *opt_read(const char *opt, char *data)
 {
         char *value;
         char *retval;
@@ -67,9 +69,9 @@
                 return NULL;
 
         value++;
-        PRESTO_ALLOC(retval, char *, strlen(value) + 1);
+        PRESTO_ALLOC(retval, strlen(value) + 1);
         if ( !retval ) {
-                printk("InterMezzo: Out of memory!\n");
+                CERROR("InterMezzo: Out of memory!\n");
                 return NULL;
         }
 
@@ -78,21 +80,30 @@
         return retval;
 }
 
-static void store_opt(char **dst, char *opt, char *defval)
+static void opt_store(char **dst, char *opt)
 {
-        if (dst) {
-                if (*dst) { 
-                        PRESTO_FREE(*dst, strlen(*dst) + 1);
-                }
-                *dst = opt;
-        } else {
-                printk("presto: store_opt, error dst == NULL\n"); 
-        }
+        if (!dst) 
+                CERROR("intermezzo: store_opt, error dst == NULL\n"); 
+
+        if (*dst)
+                PRESTO_FREE(*dst, strlen(*dst) + 1);
+        *dst = opt;
+}
 
+static void opt_set_default(char **dst, char *defval)
+{
+        if (!dst) 
+                CERROR("intermezzo: store_opt, error dst == NULL\n"); 
 
-        if (!opt && defval) {
+        if (*dst)
+                PRESTO_FREE(*dst, strlen(*dst) + 1);
+        if (defval) {
                 char *def_alloced; 
-                PRESTO_ALLOC(def_alloced, char *, strlen(defval)+1);
+                PRESTO_ALLOC(def_alloced, strlen(defval)+1);
+                if (!def_alloced) {
+                        CERROR("InterMezzo: Out of memory!\n");
+                        return ;
+                }
                 strcpy(def_alloced, defval);
                 *dst = def_alloced; 
         }
@@ -105,19 +116,23 @@
  * to the read_super operation of the cache).  The return value will
  * be a pointer to the end of the cache_data.
  */
-static char *presto_options(char *options, char *cache_data,
+static char *presto_options(struct super_block *sb, 
+                            char *options, char *cache_data,
                             char **cache_type, char **fileset,
-                            char **prestodev,  char **mtpt)
+                            char **channel)
 {
         char *this_char;
         char *cache_data_end = cache_data;
 
+        /* set the defaults */ 
+        if (strcmp(sb->s_type->name, "intermezzo") == 0)
+            opt_set_default(cache_type, "ext3"); 
+        else 
+            opt_set_default(cache_type, "tmpfs"); 
+            
         if (!options || !cache_data)
                 return cache_data_end;
 
-        /* set the defaults */ 
-        store_opt(cache_type, NULL, "ext3"); 
-        store_opt(prestodev, NULL, PRESTO_PSDEV_NAME "0"); 
 
         CDEBUG(D_SUPER, "parsing options\n");
         for (this_char = strtok (options, ",");
@@ -126,119 +141,80 @@
                 char *opt;
                 CDEBUG(D_SUPER, "this_char %s\n", this_char);
 
-                if ( (opt = read_opt("fileset", this_char)) ) {
-                        store_opt(fileset, opt, NULL);
+                if ( (opt = opt_read("fileset", this_char)) ) {
+                        opt_store(fileset, opt);
                         continue;
                 }
-                if ( (opt = read_opt("cache_type", this_char)) ) {
-                        store_opt(cache_type, opt, "ext3");
+                if ( (opt = opt_read("cache_type", this_char)) ) {
+                        opt_store(cache_type, opt);
                         continue;
                 }
-                if ( (opt = read_opt("mtpt", this_char)) ) {
-                        store_opt(mtpt, opt, NULL);
-                        continue;
-                }
-                if ( (opt = read_opt("prestodev", this_char)) ) {
-                        store_opt(prestodev, opt, PRESTO_PSDEV_NAME);
+                if ( (opt = opt_read("channel", this_char)) ) {
+                        opt_store(channel, opt);
                         continue;
                 }
 
-                cache_data_end += sprintf(cache_data_end, "%s%s",
-                                          cache_data_end != cache_data ? ",":"",
-                                          this_char);
+                cache_data_end += 
+                        sprintf(cache_data_end, "%s%s",
+                                cache_data_end != cache_data ? ",":"", 
+                                this_char);
         }
 
         return cache_data_end;
 }
 
-/*
-    map a /dev/intermezzoX path to a minor:
-    used to validate mount options passed to InterMezzo
- */
-static int presto_get_minor(char *dev_path, int *minor)
+static int presto_set_channel(struct presto_cache *cache, char *channel)
 {
-        struct nameidata nd;
-        struct dentry *dentry;
-        kdev_t devno = 0;
-        int error; 
+        int minor; 
+
         ENTRY;
+        if (!channel) {
+                minor = izo_psdev_get_free_channel();
+        } else {
+                minor = simple_strtoul(channel, NULL, 0); 
+        }
+        if (minor < 0 || minor >= MAX_CHANNEL) { 
+                CERROR("all channels in use or channel too large %d\n", 
+                       minor);
+                return -EINVAL;
+        }
+        
+        cache->cache_psdev = &(izo_channels[minor]);
+        list_add(&cache->cache_channel_list, 
+                 &cache->cache_psdev->uc_cache_list); 
 
-        /* Special case for root filesystem - use minor 0 always. */
-        if ( current->pid == 1 ) {
-                *minor = 0;
-                return 0;
-        }
-
-        error = presto_walk(dev_path, &nd);
-        if (error) {
-		EXIT;
-                return error;
-	}
-        dentry = nd.dentry;
-
-	error = -ENODEV;
-        if (!dentry->d_inode) { 
-		EXIT;
-		goto out;
-	}
-
-        if (!S_ISCHR(dentry->d_inode->i_mode)) {
-		EXIT;
-		goto out;
-	}
-
-        devno = dentry->d_inode->i_rdev;
-        if ( MAJOR(devno) != PRESTO_PSDEV_MAJOR ) { 
-		EXIT;
-		goto out;
-	}
-
-        if ( MINOR(devno) >= MAX_PRESTODEV ) {
-		EXIT;
-		goto out;
-	}
-
-	EXIT;
- out:
-        *minor = MINOR(devno);
-        path_release(&nd);
-        return 0;
+        EXIT;
+        return minor;
 }
 
-/* We always need to remove the presto options before passing to bottom FS */
-struct super_block * presto_read_super(struct super_block * presto_sb,
+/* We always need to remove the presto options before passing 
+   mount options to cache FS */
+struct super_block * presto_read_super(struct super_block * sb,
                                        void * data, int silent)
 {
-        struct super_block *mysb = NULL;
         struct file_system_type *fstype;
         struct presto_cache *cache = NULL;
         char *cache_data = NULL;
         char *cache_data_end;
         char *cache_type = NULL;
         char *fileset = NULL;
-        char *presto_mtpt = NULL;
-        char *prestodev = NULL;
-        struct filter_fs *ops;
-        int minor;
-        struct upc_comm *psdev;
+        char *channel = NULL;
+        int err; 
+        unsigned int minor;
 
         ENTRY;
-        CDEBUG(D_MALLOC, "before parsing: kmem %ld, vmem %ld\n",
-               presto_kmemory, presto_vmemory);
 
         /* reserve space for the cache's data */
-        PRESTO_ALLOC(cache_data, void *, PAGE_SIZE);
+        PRESTO_ALLOC(cache_data, PAGE_SIZE);
         if ( !cache_data ) {
-                printk("presto_read_super: Cannot allocate data page.\n");
+                CERROR("presto_read_super: Cannot allocate data page.\n");
                 EXIT;
                 goto out_err;
         }
 
-        CDEBUG(D_SUPER, "mount opts: %s\n", data ? (char *)data : "(none)");
-
         /* read and validate options */
-        cache_data_end = presto_options(data, cache_data, &cache_type, &fileset,
-                                        &prestodev, &presto_mtpt);
+        cache_data_end = presto_options(sb, data, cache_data, &cache_type, 
+                                        &fileset, &channel);
 
         /* was there anything for the cache filesystem in the data? */
         if (cache_data_end == cache_data) {
@@ -249,112 +225,87 @@
                        cache_data);
         }
 
-        /* prepare the communication channel */
-        if ( presto_get_minor(prestodev, &minor) ) {
-                /* if (!silent) */
-                printk("InterMezzo: %s not a valid presto dev\n", prestodev);
-                EXIT;
-                goto out_err;
-        }
-        psdev = &upc_comms[minor];
-        CDEBUG(D_SUPER, "\n");
-        psdev->uc_no_filter = 1;
-
-        CDEBUG(D_SUPER, "presto minor is %d\n", minor);
-
         /* set up the cache */
-        cache = presto_init_cache();
+        cache = presto_cache_init();
         if ( !cache ) {
-                printk("presto_read_super: failure allocating cache.\n");
+                CERROR("presto_read_super: failure allocating cache.\n");
                 EXIT;
                 goto out_err;
         }
-
-        /* no options were passed: likely we are "/" readonly */
-        if ( !presto_mtpt || !fileset ) {
-                cache->cache_flags |= CACHE_LENTO_RO | CACHE_CLIENT_RO;
-        }
-        cache->cache_psdev = psdev;
-        /* no options were passed: likely we are "/" readonly */
-        /* before the journaling infrastructure can work, these
-           need to be set; that happens in presto_remount */
-        if ( !presto_mtpt || !fileset ) {
-                if (!presto_mtpt) 
-                        printk("No mountpoint marking cache RO\n");
-                if (!fileset) 
-                        printk("No fileset marking cache RO\n");
-                cache->cache_flags |= CACHE_LENTO_RO | CACHE_CLIENT_RO;
-        }
-
-        cache->cache_mtpt = presto_mtpt;
-        cache->cache_root_fileset = fileset;
         cache->cache_type = cache_type;
 
-        printk("Presto: type=%s, vol=%s, dev=%s (minor %d), mtpt %s, flags %x\n",
-               cache_type, fileset ? fileset : "NULL", prestodev, minor,
-               presto_mtpt ? presto_mtpt : "NULL", cache->cache_flags);
+        /* link cache to channel */ 
+        minor = presto_set_channel(cache, channel);
+        if (minor < 0) { 
+                EXIT;
+                goto out_err;
+        }
 
+        CDEBUG(D_SUPER, "Presto: type=%s, fset=%s, dev= %d, flags %x\n",
+               cache_type, fileset?fileset:"NULL", minor, cache->cache_flags);
 
         MOD_INC_USE_COUNT;
-        fstype = get_fs_type(cache_type);
 
+        /* get the filter for the cache */
+        fstype = get_fs_type(cache_type);
         cache->cache_filter = filter_get_filter_fs((const char *)cache_type); 
         if ( !fstype || !cache->cache_filter) {
-                printk("Presto: unrecognized fs type or cache type\n");
+                CERROR("Presto: unrecognized fs type or cache type\n");
                 MOD_DEC_USE_COUNT;
                 EXIT;
                 goto out_err;
         }
-        mysb = fstype->read_super(presto_sb, cache_data, silent);
+
+        /* can we in fact mount the cache */ 
+        if ((fstype->fs_flags & FS_REQUIRES_DEV) && !sb->s_bdev) {
+                CERROR("filesystem \"%s\" requires a valid block device\n",
+                                cache_type);
+                MOD_DEC_USE_COUNT;
+                EXIT;
+                goto out_err;
+        }
+
+        sb = fstype->read_super(sb, cache_data, silent);
+
         /* this might have been freed above */
         if (cache_data) {
                 PRESTO_FREE(cache_data, PAGE_SIZE);
                 cache_data = NULL;
         }
-        if ( !mysb ) {
-                /* if (!silent) */
-                printk("InterMezzo: cache mount failure.\n");
+
+        if ( !sb ) {
+                CERROR("InterMezzo: cache mount failure.\n");
                 MOD_DEC_USE_COUNT;
                 EXIT;
                 goto out_err;
         }
 
-	
-	cache->cache_sb = mysb;
-        ops = filter_get_filter_fs(cache_type);
-
-        filter_setup_journal_ops(cache->cache_filter, cache->cache_type); 
+        cache->cache_sb = sb;
+        cache->cache_root = dget(sb->s_root);
 
         /* we now know the dev of the cache: hash the cache */
-        presto_cache_add(cache, mysb->s_dev);
+        presto_cache_add(cache, sb->s_dev);
+        err = izo_prepare_fileset(sb->s_root, fileset); 
 
-        /* make sure we have our own super operations: mysb
+        filter_setup_journal_ops(cache->cache_filter, cache->cache_type); 
+
+        /* make sure we have our own super operations: sb
            still contains the cache operations */
-        filter_setup_super_ops(cache->cache_filter, mysb->s_op, 
+        filter_setup_super_ops(cache->cache_filter, sb->s_op, 
                                &presto_super_ops);
-        mysb->s_op = filter_c2usops(cache->cache_filter);
+        sb->s_op = filter_c2usops(cache->cache_filter);
 
-        /* now get our own directory operations */
-        if ( mysb->s_root && mysb->s_root->d_inode ) {
-                CDEBUG(D_SUPER, "\n");
-                filter_setup_dir_ops(cache->cache_filter, 
-                                     mysb->s_root->d_inode,
-                                     &presto_dir_iops, &presto_dir_fops);
-                mysb->s_root->d_inode->i_op = filter_c2udiops(cache->cache_filter);
-                CDEBUG(D_SUPER, "lookup at %p\n", 
-                       mysb->s_root->d_inode->i_op->lookup);
-                filter_setup_dentry_ops(cache->cache_filter, 
-                                        mysb->s_root->d_op, 
-                                        &presto_dentry_ops);
-                presto_sb->s_root->d_op = filter_c2udops(cache->cache_filter);
-                cache->cache_mtde = mysb->s_root;
-        }
-
-        CDEBUG(D_MALLOC, "after mounting: kmem %ld, vmem %ld\n",
-               presto_kmemory, presto_vmemory);
+        /* get izo directory operations: sb->s_root->d_inode exists now */
+        filter_setup_dir_ops(cache->cache_filter, sb->s_root->d_inode,
+                             &presto_dir_iops, &presto_dir_fops);
+        filter_setup_dentry_ops(cache->cache_filter, sb->s_root->d_op, 
+                                &presto_dentry_ops);
+        sb->s_root->d_inode->i_op = filter_c2udiops(cache->cache_filter);
+        sb->s_root->d_inode->i_fop = filter_c2udfops(cache->cache_filter);
+        sb->s_root->d_op = filter_c2udops(cache->cache_filter);
 
         EXIT;
-        return mysb;
+        return sb;
 
  out_err:
         CDEBUG(D_SUPER, "out_err called\n");
@@ -364,10 +315,8 @@
                 PRESTO_FREE(cache_data, PAGE_SIZE);
         if (fileset)
                 PRESTO_FREE(fileset, strlen(fileset) + 1);
-        if (presto_mtpt)
-                PRESTO_FREE(presto_mtpt, strlen(presto_mtpt) + 1);
-        if (prestodev)
-                PRESTO_FREE(prestodev, strlen(prestodev) + 1);
+        if (channel)
+                PRESTO_FREE(channel, strlen(channel) + 1);
         if (cache_type)
                 PRESTO_FREE(cache_type, strlen(cache_type) + 1);
 
@@ -376,152 +325,78 @@
         return NULL;
 }
 
-int presto_remount(struct super_block * sb, int *flags, char *data)
-{
-        char *cache_data = NULL;
-        char *cache_data_end;
-        char **type;
-        char **fileset;
-        char **mtpt;
-        char **prestodev;
-        struct super_operations *sops;
-        struct presto_cache *cache = NULL;
-        int err = 0;
-
-        ENTRY;
-        CDEBUG(D_MALLOC, "before remount: kmem %ld, vmem %ld\n",
-               presto_kmemory, presto_vmemory);
-        CDEBUG(D_SUPER, "remount opts: %s\n", data ? (char *)data : "(none)");
-        if (data) {
-                /* reserve space for the cache's data */
-                PRESTO_ALLOC(cache_data, void *, PAGE_SIZE);
-                if ( !cache_data ) {
-                        err = -ENOMEM;
-                        EXIT;
-                        goto out_err;
-                }
-        }
-
-        cache = presto_find_cache(sb->s_dev);
-        if (!cache) {
-                printk( "%s: cannot find cache on remount\n", __FUNCTION__);
-                err = -ENODEV;
-                EXIT;
-                goto out_err;
-        }
-
-        /* If an option has not yet been set, we allow it to be set on
-         * remount.  If an option already has a value, we pass NULL for
-         * the option pointer, which means that the InterMezzo option
-         * will be parsed but discarded.
-         */
-        type = cache->cache_type ? NULL : &cache->cache_type;
-        fileset = cache->cache_root_fileset ? NULL : &cache->cache_root_fileset;
-        prestodev = cache->cache_psdev ? NULL : &cache->cache_psdev->uc_devname;
-        mtpt = cache->cache_mtpt ? NULL : &cache->cache_mtpt;
-        cache_data_end = presto_options(data, cache_data, type, fileset,
-                                        prestodev, mtpt);
 
-        if (cache_data) {
-                if (cache_data_end == cache_data) {
-                        PRESTO_FREE(cache_data, PAGE_SIZE);
-                        cache_data = NULL;
-                } else {
-                        CDEBUG(D_SUPER, "cache_data at %p is: %s\n", cache_data,
-                               cache_data);
-                }
-        }
-
-        if (cache->cache_root_fileset && cache->cache_mtpt) {
-                cache->cache_flags &= ~(CACHE_LENTO_RO|CACHE_CLIENT_RO);
-        }
-
-        sops = filter_c2csops(cache->cache_filter);
-        if (sops->remount_fs) {
-                err = sops->remount_fs(sb, flags, cache_data);
-        }
 
-        CDEBUG(D_MALLOC, "after remount: kmem %ld, vmem %ld\n",
-               presto_kmemory, presto_vmemory);
-        EXIT;
-out_err:
-        if (cache_data)
-                PRESTO_FREE(cache_data, PAGE_SIZE);
-        return err;
-}
-
-struct file_system_type presto_fs_type = {
 #ifdef PRESTO_DEVEL
-        "izofs",
+static DECLARE_FSTYPE(presto_fs_type, "izo", presto_read_super, FS_REQUIRES_DEV);
+static DECLARE_FSTYPE(vpresto_fs_type, "vintermezzo", presto_read_super, FS_LITTER);
 #else 
-        "intermezzo",
+static DECLARE_FSTYPE(vpresto_fs_type, "vintermezzo", presto_read_super, FS_LITTER);
+static DECLARE_FSTYPE(presto_fs_type, "intermezzo", presto_read_super, FS_REQUIRES_DEV);
 #endif
-        FS_REQUIRES_DEV, /* can use Ibaskets when ext2 does */
-        presto_read_super,
-        NULL
-};
 
 
-int /* __init */ init_intermezzo_fs(void)
+
+int __init init_intermezzo_fs(void)
 {
         int status;
 
-        printk(KERN_INFO "InterMezzo Kernel/Lento communications, "
-               "v1.04, braam@inter-mezzo.org\n");
+        printk(KERN_INFO "InterMezzo Kernel/Intersync communications " INTERMEZZO_VERSION
+               " info@clusterfs.com\n");
 
         status = presto_psdev_init();
         if ( status ) {
-                printk("Problem (%d) in init_intermezzo_psdev\n", status);
+                CERROR("Problem (%d) in init_intermezzo_psdev\n", status);
                 return status;
         }
 
         status = init_intermezzo_sysctl();
         if (status) {
-                printk("presto: failed in init_intermezzo_sysctl!\n");
+                CERROR("presto: failed in init_intermezzo_sysctl!\n");
         }
 
-        presto_init_cache_hash();
+        presto_cache_init_hash();
+
+        if (!presto_init_ddata_cache()) {
+                CERROR("presto out of memory!\n");
+                return -ENOMEM;
+        }
 
         status = register_filesystem(&presto_fs_type);
         if (status) {
-                printk("presto: failed in register_filesystem!\n");
+                CERROR("presto: failed in register_filesystem!\n");
+        }
+        status = register_filesystem(&vpresto_fs_type);
+        if (status) {
+                CERROR("vpresto: failed in register_filesystem!\n");
         }
         return status;
 }
 
-
-#ifdef MODULE
-MODULE_AUTHOR("Peter J. Braam <braam@inter-mezzo.org>");
-MODULE_DESCRIPTION("InterMezzo Kernel/Lento communications, v1.0.5.1");
-
-int init_module(void)
-{
-        return init_intermezzo_fs();
-}
-
-
-void cleanup_module(void)
+void __exit exit_intermezzo_fs(void)
 {
         int err;
 
         ENTRY;
 
         if ( (err = unregister_filesystem(&presto_fs_type)) != 0 ) {
-                printk("presto: failed to unregister filesystem\n");
+                CERROR("presto: failed to unregister filesystem\n");
+        }
+        if ( (err = unregister_filesystem(&vpresto_fs_type)) != 0 ) {
+                CERROR("vpresto: failed to unregister filesystem\n");
         }
 
         presto_psdev_cleanup();
         cleanup_intermezzo_sysctl();
-
-
-#ifdef PRESTO_DEVEL
-        unregister_chrdev(PRESTO_PSDEV_MAJOR, "intermezzo_psdev_devel");
-#else 
-        unregister_chrdev(PRESTO_PSDEV_MAJOR, "intermezzo_psdev");
-#endif
-        CDEBUG(D_MALLOC, "after cleanup: kmem %ld, vmem %ld\n",
+        presto_cleanup_ddata_cache();
+        CERROR("after cleanup: kmem %ld, vmem %ld\n",
                presto_kmemory, presto_vmemory);
 }
 
-#endif
 
+MODULE_AUTHOR("Cluster Filesystems Inc. <info@clusterfs.com>");
+MODULE_DESCRIPTION("InterMezzo Kernel/Intersync communications " INTERMEZZO_VERSION);
+MODULE_LICENSE("GPL");
+
+module_init(init_intermezzo_fs)
+module_exit(exit_intermezzo_fs)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/sysctl.c linux.20pre10-ac2/fs/intermezzo/sysctl.c
--- linux.20pre10/fs/intermezzo/sysctl.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/sysctl.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,4 +1,23 @@
-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 1999 Peter J. Braam <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
  *  Sysctrl entries for Intermezzo!
  */
 
@@ -24,7 +43,6 @@
 
 #include <linux/intermezzo_fs.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_upcall.h>
 
 /* /proc entries */
 
@@ -36,8 +54,6 @@
 	int len=0;
 
 	/* this works as long as we are below 1024 characters! */
-	len += presto_sprint_mounts(buffer, length, -1);
-
 	*start = buffer + offset;
 	len -= offset;
 
@@ -67,30 +83,27 @@
 #define PSDEV_NO_UPCALL    7      /* controls lento_upcall */
 #define PSDEV_ERRORVAL     8      /* controls presto_debug_fail_blkdev */
 #define PSDEV_EXCL_GID     9      /* which GID is ignored by presto */
-#define PSDEV_ILOOKUP_UID 10      /* which UID bypasses file access perms */
 #define PSDEV_BYTES_TO_CLOSE 11   /* bytes to write before close */
 
 /* These are global presto control options */
-#define PRESTO_PRIMARY_CTLCNT 4
-static struct ctl_table presto_table[ PRESTO_PRIMARY_CTLCNT + MAX_PRESTODEV + 1] =
+#define PRESTO_PRIMARY_CTLCNT 2
+static struct ctl_table presto_table[ PRESTO_PRIMARY_CTLCNT + MAX_CHANNEL + 1] =
 {
 	{PSDEV_DEBUG, "debug", &presto_debug, sizeof(int), 0644, NULL, &proc_dointvec},
 	{PSDEV_TRACE, "trace", &presto_print_entry, sizeof(int), 0644, NULL, &proc_dointvec},
-	{PSDEV_EXCL_GID, "presto_excluded_gid", &presto_excluded_gid, sizeof(int), 0644, NULL, &proc_dointvec},
-	{PSDEV_ILOOKUP_UID, "presto_ilookup_uid", &presto_ilookup_uid, sizeof(int), 0644, NULL, &proc_dointvec},
 };
 
 /*
  * Intalling the sysctl entries: strategy
  * - have templates for each /proc/sys/intermezzo/ entry
  *   such an entry exists for each /dev/presto
- *    (proto_prestodev_entry)
+ *    (proto_channel_entry)
  * - have a template for the contents of such directories
  *    (proto_psdev_table)
  * - have the master table (presto_table)
  *
  * When installing, malloc, memcpy and fix up the pointers to point to
- * the appropriate constants in upc_comms[your_minor]
+ * the appropriate constants in izo_channels[your_minor]
  */
 
 static ctl_table proto_psdev_table[] = {
@@ -99,15 +112,13 @@
 	{PSDEV_NO_JOURNAL, "no_journal", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
 	{PSDEV_NO_UPCALL, "no_upcall", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
 	{PSDEV_TIMEOUT, "timeout", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
-	{PSDEV_TRACE, "trace", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
-	{PSDEV_DEBUG, "debug", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
 #ifdef PRESTO_DEBUG
 	{PSDEV_ERRORVAL, "errorval", NULL, sizeof(int), 0644, NULL, &proc_dointvec},
 #endif
 	{ 0 }
 };
 
-static ctl_table proto_prestodev_entry = {
+static ctl_table proto_channel_entry = {
 	PSDEV_INTERMEZZO, 0,  NULL, 0, 0555, 0,
 };
 
@@ -124,6 +135,7 @@
 /* we made these separate as setting may in future be more restricted
  * than getting
  */
+#ifdef RON_MINNICH
 int dosetopt(int minor, struct psdev_opt *opt)
 {
 	int retval = 0;
@@ -134,23 +146,23 @@
 	switch(opt->optname) {
 
 	case PSDEV_TIMEOUT:
-		upc_comms[minor].uc_timeout = newval;
+		izo_channels[minor].uc_timeout = newval;
 		break;
 
 	case PSDEV_HARD:
-		upc_comms[minor].uc_hard = newval;
+		izo_channels[minor].uc_hard = newval;
 		break;
 
 	case PSDEV_NO_FILTER:
-		upc_comms[minor].uc_no_filter = newval;
+		izo_channels[minor].uc_no_filter = newval;
 		break;
 
 	case PSDEV_NO_JOURNAL:
-		upc_comms[minor].uc_no_journal = newval;
+		izo_channels[minor].uc_no_journal = newval;
 		break;
 
 	case PSDEV_NO_UPCALL:
-		upc_comms[minor].uc_no_upcall = newval;
+		izo_channels[minor].uc_no_upcall = newval;
 		break;
 
 #ifdef PRESTO_DEBUG
@@ -161,17 +173,17 @@
 		 * allow setting the underlying device read-only for the
 		 * current presto cache.
 		 */
-		int errorval = upc_comms[minor].uc_errorval;
+		int errorval = izo_channels[minor].uc_errorval;
 		if (errorval < 0) {
 			if (newval == 0)
 				set_device_ro(-errorval, 0);
 			else
-				printk("device %s already read only\n",
+				CERROR("device %s already read only\n",
 				       kdevname(-errorval));
 		} else {
 			if (newval < 0)
 				set_device_ro(-newval, 1);
-			upc_comms[minor].uc_errorval = newval;
+			izo_channels[minor].uc_errorval = newval;
 			CDEBUG(D_PSDEV, "setting errorval to %d\n", newval);
 		}
 
@@ -203,32 +215,32 @@
 	switch(opt->optname) {
 
 	case PSDEV_TIMEOUT:
-		opt->optval = upc_comms[minor].uc_timeout;
+		opt->optval = izo_channels[minor].uc_timeout;
 		break;
 
 	case PSDEV_HARD:
-		opt->optval = upc_comms[minor].uc_hard;
+		opt->optval = izo_channels[minor].uc_hard;
 		break;
 
 	case PSDEV_NO_FILTER:
-		opt->optval = upc_comms[minor].uc_no_filter;
+		opt->optval = izo_channels[minor].uc_no_filter;
 		break;
 
 	case PSDEV_NO_JOURNAL:
-		opt->optval = upc_comms[minor].uc_no_journal;
+		opt->optval = izo_channels[minor].uc_no_journal;
 		break;
 
 	case PSDEV_NO_UPCALL:
-		opt->optval = upc_comms[minor].uc_no_upcall;
+		opt->optval = izo_channels[minor].uc_no_upcall;
 		break;
 
 #ifdef PSDEV_DEBUG
 	case PSDEV_ERRORVAL: {
-		int errorval = upc_comms[minor].uc_errorval;
+		int errorval = izo_channels[minor].uc_errorval;
 		if (errorval < 0 && is_read_only(-errorval))
-			printk(KERN_INFO "device %s has been set read-only\n",
+			CERROR("device %s has been set read-only\n",
 			       kdevname(-errorval));
-		opt->optval = upc_comms[minor].uc_errorval;
+		opt->optval = izo_channels[minor].uc_errorval;
 		break;
 	}
 #endif
@@ -247,29 +259,26 @@
 	EXIT;
 	return retval;
 }
+#endif
 
 
-
+/* allocate the tables for the presto devices. We need
+ * sizeof(proto_channel_table)/sizeof(proto_channel_table[0])
+ * entries for each dev
+ */
 int /* __init */ init_intermezzo_sysctl(void)
 {
 	int i;
-	extern struct upc_comm upc_comms[MAX_PRESTODEV];
-
-	/* allocate the tables for the presto devices. We need
-	 * sizeof(proto_prestodev_table)/sizeof(proto_prestodev_table[0])
-	 * entries for each dev
-	 */
-	int total_dev = MAX_PRESTODEV;
+	int total_dev = MAX_CHANNEL;
 	int entries_per_dev = sizeof(proto_psdev_table) /
 		sizeof(proto_psdev_table[0]);
 	int total_entries = entries_per_dev * total_dev;
 	ctl_table *dev_ctl_table;
 
-	PRESTO_ALLOC(dev_ctl_table, ctl_table *,
-		     sizeof(ctl_table) * total_entries);
+	PRESTO_ALLOC(dev_ctl_table, sizeof(ctl_table) * total_entries);
 
 	if (! dev_ctl_table) {
-		printk("WARNING: presto couldn't allocate dev_ctl_table\n");
+		CERROR("WARNING: presto couldn't allocate dev_ctl_table\n");
 		EXIT;
 		return -ENOMEM;
 	}
@@ -286,14 +295,14 @@
 		/* entries for the individual "files" in this "directory" */
 		ctl_table *psdev_entries = &dev_ctl_table[i * entries_per_dev];
 		/* init the psdev and psdev_entries with the prototypes */
-		*psdev = proto_prestodev_entry;
+		*psdev = proto_channel_entry;
 		memcpy(psdev_entries, proto_psdev_table,
 		       sizeof(proto_psdev_table));
 		/* now specialize them ... */
 		/* the psdev has to point to psdev_entries, and fix the number */
 		psdev->ctl_name = psdev->ctl_name + i + 1; /* sorry */
 
-		psdev->procname = kmalloc(32, GFP_KERNEL);
+		PRESTO_ALLOC((void*)psdev->procname, PROCNAME_SIZE);
 		if (!psdev->procname) {
 			PRESTO_FREE(dev_ctl_table,
 				    sizeof(ctl_table) * total_entries);
@@ -304,15 +313,13 @@
 		psdev->child = psdev_entries;
 
 		/* now for each psdev entry ... */
-		psdev_entries[0].data = &(upc_comms[i].uc_hard);
-		psdev_entries[1].data = &(upc_comms[i].uc_no_filter);
-		psdev_entries[2].data = &(upc_comms[i].uc_no_journal);
-		psdev_entries[3].data = &(upc_comms[i].uc_no_upcall);
-		psdev_entries[4].data = &(upc_comms[i].uc_timeout);
-		psdev_entries[5].data = &presto_print_entry;
-		psdev_entries[6].data = &presto_debug;
+		psdev_entries[0].data = &(izo_channels[i].uc_hard);
+		psdev_entries[1].data = &(izo_channels[i].uc_no_filter);
+		psdev_entries[2].data = &(izo_channels[i].uc_no_journal);
+		psdev_entries[3].data = &(izo_channels[i].uc_no_upcall);
+		psdev_entries[4].data = &(izo_channels[i].uc_timeout);
 #ifdef PRESTO_DEBUG
-		psdev_entries[7].data = &(upc_comms[i].uc_errorval);
+		psdev_entries[5].data = &(izo_channels[i].uc_errorval);
 #endif
 	}
 
@@ -331,8 +338,9 @@
 	return 0;
 }
 
-void cleanup_intermezzo_sysctl() {
-	int total_dev = MAX_PRESTODEV;
+void cleanup_intermezzo_sysctl(void)
+{
+	int total_dev = MAX_CHANNEL;
 	int entries_per_dev = sizeof(proto_psdev_table) /
 		sizeof(proto_psdev_table[0]);
 	int total_entries = entries_per_dev * total_dev;
@@ -346,7 +354,7 @@
 	for(i = 0; i < total_dev; i++) {
 		/* entry for this /proc/sys/intermezzo/intermezzo"i" */
 		ctl_table *psdev = &presto_table[i + PRESTO_PRIMARY_CTLCNT];
-		kfree(psdev->procname);
+		PRESTO_FREE(psdev->procname, PROCNAME_SIZE);
 	}
 	/* presto_table[PRESTO_PRIMARY_CTLCNT].child points to the
 	 * dev_ctl_table previously allocated in init_intermezzo_psdev()
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/upcall.c linux.20pre10-ac2/fs/intermezzo/upcall.c
--- linux.20pre10/fs/intermezzo/upcall.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/upcall.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,22 +1,28 @@
-/*
- * Mostly platform independent upcall operations to Venus:
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * Copyright (C) 2001, 2002 Cluster File Systems, Inc. <braam@clusterfs.com>
+ * Copyright (C) 2001 Tacit Networks, Inc. <phil@off.net>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Mostly platform independent upcall operations to a cache manager:
  *  -- upcalls
  *  -- upcall routines
  *
- * Linux 2.0 version
- * Copyright (C) 1996 Peter J. Braam <braam@cs.cmu.edu>,
- * Michael Callahan <callahan@maths.ox.ac.uk>
- *
- * Redone for Linux 2.1
- * Copyright (C) 1997 Carnegie Mellon University
- *
- * Carnegie Mellon University encourages users of this code to contribute
- * improvements to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
- *
- * Much cleaned up for InterMezzo
- * Copyright (C) 1998 Peter J. Braam <braam@cs.cmu.edu>,
- * Copyright (C) 1999 Carnegie Mellon University
- *
  */
 
 #include <asm/system.h>
@@ -39,210 +45,513 @@
 #include <linux/vmalloc.h>
 #include <asm/segment.h>
 
+#include <linux/intermezzo_lib.h>
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
 
+#include <linux/intermezzo_idl.h>
+
 /*
-  At present: four upcalls
-  - opendir: fetch a directory (synchronous & asynchronous)
-  - open: fetch file (synchronous)
-  - journal: send a journal page (asynchronous)
-  - permit: get a permit (synchronous)
+  At present:
+  -- Asynchronous calls:
+   - kml:            give a "more" kml indication to userland
+   - kml_truncate:   initiate KML truncation
+   - release_permit: kernel is done with permit
+  -- Synchronous
+   - open:           fetch file
+   - permit:         get a permit
 
-  Errors returned here are positive.
+  Errors returned by user level code are positive
 
  */
 
+static struct izo_upcall_hdr *upc_pack(__u32 opcode, int pathlen, char *path,
+                                       char *fsetname, int reclen, char *rec,
+                                       int *size)
+{
+        struct izo_upcall_hdr *hdr;
+        char *ptr;
+        ENTRY;
 
-#define INSIZE(tag) sizeof(struct lento_ ## tag ## _in)
-#define OUTSIZE(tag) sizeof(struct lento_ ## tag ## _out)
-#define SIZE(tag)  ( (INSIZE(tag)>OUTSIZE(tag)) ? INSIZE(tag) : OUTSIZE(tag) )
-
-#define UPARG(op)\
-do {\
-        PRESTO_ALLOC(inp, union up_args *, insize);\
-        if ( !inp ) { return -ENOMEM; }\
-        outp = (union down_args *) (inp);\
-        inp->uh.opcode = (op);\
-        inp->uh.pid = current->pid;\
-        inp->uh.uid = current->fsuid;\
-        outsize = insize;\
-} while (0)
-
-#define BUFF_ALLOC(buffer)                              \
-        PRESTO_ALLOC(buffer, char *, PAGE_SIZE);        \
-        if ( !buffer ) {                                \
-                printk("PRESTO: out of memory!\n");     \
-                return -ENOMEM;                         \
+        *size = sizeof(struct izo_upcall_hdr);
+        if ( fsetname ) {
+                *size += round_strlen(fsetname);
+        }
+        if ( path ) { 
+                *size += round_strlen(path);
         }
+        if ( rec ) { 
+                *size += size_round(reclen);
+        }
+        PRESTO_ALLOC(hdr, *size);
+        if (!hdr) { 
+                CERROR("intermezzo upcall: out of memory (opc %d)\n", opcode);
+                EXIT;
+                return NULL;
+        }
+        memset(hdr, 0, *size);
+
+        ptr = (char *)hdr + sizeof(*hdr);
+
+        /* XXX do we need fsuid ? */
+        hdr->u_len = *size;
+        hdr->u_version = IZO_UPC_VERSION;
+        hdr->u_opc = opcode;
+        hdr->u_pid = current->pid;
+        hdr->u_uid = current->fsuid;
+
+        if (path) { 
+                /*XXX Robert: please review what len to pass in for 
+                  NUL terminated strings */
+                hdr->u_pathlen = strlen(path);
+                LOGL0(path, hdr->u_pathlen, ptr);
+        }
+        if (fsetname) { 
+                hdr->u_fsetlen = strlen(fsetname);
+                LOGL0(fsetname, strlen(fsetname), ptr);
+        }
+        if (rec) { 
+                hdr->u_reclen = reclen;
+                LOGL(rec, reclen, ptr);
+        }
+        
+        EXIT;
+        return hdr;
+}
 
 /* the upcalls */
-int lento_kml(int minor, unsigned int offset, unsigned int first_recno,
-              unsigned int length, unsigned int last_recno, int namelen,
-              char *fsetname)
-{
-        union up_args *inp;
-        union down_args *outp;
-        int insize, outsize, error;
+int izo_upc_kml(int minor, __u64 offset, __u32 first_recno, __u64 length, __u32 last_recno, char *fsetname)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+
         ENTRY;
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return 0;
+        }
+
+        hdr = upc_pack(IZO_UPC_KML, 0, NULL, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        hdr->u_offset = offset;
+        hdr->u_first_recno = first_recno;
+        hdr->u_length = length;
+        hdr->u_last_recno = last_recno;
+
+        CDEBUG(D_UPCALL, "KML: fileset %s, offset %Lu, length %Lu, "
+               "first %u, last %d; minor %d\n",
+               fsetname, hdr->u_offset, hdr->u_length, hdr->u_first_recno,
+               hdr->u_last_recno, minor);
+
+        error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS);
+
+        EXIT;
+        return -error;
+}
+
+int izo_upc_kml_truncate(int minor, __u64 length, __u32 last_recno, char *fsetname)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
 
+        ENTRY;
         if (!presto_lento_up(minor)) {
                 EXIT;
                 return 0;
         }
 
-        insize = SIZE(kml) + namelen + 1;
-        UPARG(LENTO_KML);
-        inp->lento_kml.namelen = namelen;
-        memcpy(inp->lento_kml.fsetname, fsetname, namelen);
-        inp->lento_kml.fsetname[namelen] = '\0';
-        inp->lento_kml.offset = offset;
-        inp->lento_kml.first_recno = first_recno;
-        inp->lento_kml.length = length;
-        inp->lento_kml.last_recno = last_recno;
-
-        CDEBUG(D_UPCALL, "KML: fileset %s, offset %d, length %d, "
-               "first %d, last %d; minor %d\n",
-               inp->lento_kml.fsetname,
-               inp->lento_kml.offset,
-               inp->lento_kml.length,
-               inp->lento_kml.first_recno,
-               inp->lento_kml.last_recno, minor);
+        hdr = upc_pack(IZO_UPC_KML_TRUNC, 0, NULL, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        hdr->u_length = length;
+        hdr->u_last_recno = last_recno;
+
+        CDEBUG(D_UPCALL, "KML TRUNCATE: fileset %s, length %Lu, "
+               "last recno %d, minor %d\n",
+               fsetname, hdr->u_length, hdr->u_last_recno, minor);
 
-        error = lento_upcall(minor, insize, &outsize, inp,
-                             ASYNCHRONOUS, NULL);
+        error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS);
 
         EXIT;
         return error;
 }
 
-int lento_release_permit( int minor, int mycookie )
+int izo_upc_open(int minor, __u32 pathlen, char *path, char *fsetname, struct lento_vfs_context *info)
 {
-        union up_args *inp;
-        union down_args *outp;
-        int insize, outsize, error;
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
         ENTRY;
 
         if (!presto_lento_up(minor)) {
                 EXIT;
-                return 0;
+                return -EIO;
         }
 
-        insize= SIZE(response_cookie);
-        UPARG(LENTO_COOKIE);
-        inp->lento_response_cookie.cookie= mycookie;
+        hdr = upc_pack(IZO_UPC_OPEN, pathlen, path, fsetname, 
+                       sizeof(*info), (char*)info, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
 
-        CDEBUG(D_UPCALL, "cookie %d\n", mycookie);
+        CDEBUG(D_UPCALL, "path %s\n", path);
 
-        error = lento_upcall(minor, insize, &outsize, inp,
-                             ASYNCHRONOUS, NULL);
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
 
         EXIT;
-        return error;
+        return -error;
 }
 
-int lento_opendir(int minor, int pathlen, char *path, int async)
+int izo_upc_get_fileid(int minor, __u32 reclen, char *rec, 
+                       __u32 pathlen, char *path, char *fsetname)
 {
-        union up_args *inp;
-        union down_args *outp;
-        int insize, outsize, error;
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
         ENTRY;
 
-        insize = SIZE(opendir) + pathlen + 1;
-        UPARG(LENTO_OPENDIR);
-        inp->lento_opendir.async = async;
-        inp->lento_opendir.pathlen = pathlen;
-        memcpy(inp->lento_opendir.path, path, pathlen);
-        inp->lento_opendir.path[pathlen] = '\0';
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
+
+        hdr = upc_pack(IZO_UPC_GET_FILEID, pathlen, path, fsetname, reclen, rec, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
 
-        CDEBUG(D_UPCALL, "path %s\n", inp->lento_opendir.path);
+        CDEBUG(D_UPCALL, "path %s\n", path);
 
-        if (async) {
-                error = lento_upcall(minor, insize, &outsize, inp,
-                                     ASYNCHRONOUS, NULL);
-                return 0;
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
+
+        EXIT;
+        return -error;
+}
+
+int izo_upc_backfetch(int minor, char *path, char *fsetname, struct lento_vfs_context *info)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
+
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
         }
 
-        error = lento_upcall(minor, insize, &outsize, inp,
-                             SYNCHRONOUS, NULL);
-        if (error && error != EISFSETROOT) {
-                printk("lento_opendir: error %d\n", error);
+        hdr = upc_pack(IZO_UPC_BACKFETCH, strlen(path), path, fsetname, 
+                       sizeof(*info), (char *)info, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
         }
 
+        /* This is currently synchronous, kml_reint_record blocks */
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
+
         EXIT;
-        return error;
+        return -error;
 }
 
-int lento_open(int minor, int pathlen, char *path)
+int izo_upc_permit(int minor, struct dentry *dentry, __u32 pathlen, char *path,
+                   char *fsetname)
 {
-        union up_args *inp;
-        union down_args *outp;
-        int insize, outsize, error;
-
-	ENTRY;
-	insize = SIZE(open) + pathlen + 1;
-	UPARG(LENTO_OPEN);
-	inp->lento_open.pathlen = pathlen;
-	memcpy(inp->lento_open.path, path, pathlen);
-	inp->lento_open.path[pathlen] = '\0';
-
-	CDEBUG(D_UPCALL, "path %s\n", inp->lento_open.path);
-
-	error = lento_upcall(minor, insize, &outsize, inp,
-			     SYNCHRONOUS, NULL);
-	if (error) {
-	        printk("lento_open: error %d\n", error);
-	}
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+
+        ENTRY;
+
+        hdr = upc_pack(IZO_UPC_PERMIT, pathlen, path, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        CDEBUG(D_UPCALL, "Permit minor %d path %s\n", minor, path);
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+
+        if (error == -EROFS) {
+                int err;
+                CERROR("InterMezzo: ERROR - requested permit for read-only "
+                       "fileset.\n   Setting \"%s\" read-only!\n", path);
+                err = izo_mark_cache(dentry, 0xFFFFFFFF, CACHE_CLIENT_RO, NULL);
+                if (err)
+                        CERROR("InterMezzo ERROR: mark_cache %d\n", err);
+        } else if (error) {
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
+        }
 
         EXIT;
         return error;
 }
 
+/* This is a ping-pong upcall handled on the server when a client (uuid)
+ * requests the permit for itself. */
+int izo_upc_revoke_permit(int minor, char *fsetname, __u8 uuid[16])
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+
+        ENTRY;
+
+        hdr = upc_pack(IZO_UPC_REVOKE_PERMIT, 0, NULL, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
 
-int lento_permit(int minor, int pathlen, int fsetnamelen, char *path, char *fsetname)
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+
+        if (error)
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
+
+        EXIT;
+        return -error;
+}
+
+int izo_upc_go_fetch_kml(int minor, char *fsetname, __u8 uuid[16],
+                         __u64 kmlsize)
 {
-        union up_args *inp;
-        union down_args *outp;
-        int insize, outsize, error;
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
         ENTRY;
 
-        insize = SIZE(permit) + pathlen + 1 + fsetnamelen + 1;
-        UPARG(LENTO_PERMIT);
-        inp->lento_permit.pathlen = pathlen;
-        inp->lento_permit.fsetnamelen = fsetnamelen;
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
+
+        hdr = upc_pack(IZO_UPC_GO_FETCH_KML, 0, NULL, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        hdr->u_offset = kmlsize;
+        memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
+
+        error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS);
+        if (error)
+                CERROR("%s: error %d\n", __FUNCTION__, error);
 
-        memcpy(inp->lento_permit.path, path, pathlen);
-        inp->lento_permit.path[pathlen] = '\0';
+        EXIT;
+        return -error;
+}
 
-	memcpy(&(inp->lento_permit.path[pathlen+1]), fsetname, fsetnamelen); 
-        inp->lento_permit.path[fsetnamelen + 1 + pathlen] = '\0';
+int izo_upc_connect(int minor, __u64 ip_address, __u64 port, __u8 uuid[16],
+                    int client_flag)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
 
-        CDEBUG(D_UPCALL, "Permit minor %d path %s\n", minor,
-               inp->lento_permit.path);
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
 
-        error = lento_upcall(minor, insize, &outsize, inp,
-                             SYNCHRONOUS, NULL);
+        hdr = upc_pack(IZO_UPC_CONNECT, 0, NULL, NULL, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        hdr->u_offset = ip_address;
+        hdr->u_length = port;
+        memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
+        hdr->u_first_recno = client_flag;
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
         if (error) {
-                if( error == -EROFS ) {
-                        int err;
-                        printk("lento_permit: ERROR - requested permit for "
-                               "read-only fileset.\n"
-                               "   Setting \"%s\" read-only!\n",
-                               path);
-                        err= presto_mark_cache(path, 0xFFFFFFFF, 
-                                               CACHE_CLIENT_RO, NULL);
-                        if( err ) {
-                                printk("ERROR : mark_cache %d\n", err);
-                        }
-                }
-                else {
-                        printk("lento_permit: error %d\n", error);
-                }
+                CERROR("%s: error %d\n", __FUNCTION__, error);
         }
 
         EXIT;
+        return -error;
+}
+
+int izo_upc_set_kmlsize(int minor, char *fsetname, __u8 uuid[16], __u64 kmlsize)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
+
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
+
+        hdr = upc_pack(IZO_UPC_SET_KMLSIZE, 0, NULL, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        memcpy(hdr->u_uuid, uuid, sizeof(hdr->u_uuid));
+        hdr->u_length = kmlsize;
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("%s: error %d\n", __FUNCTION__, error);
+
+        EXIT;
+        return -error;
+}
+
+int izo_upc_repstatus(int minor,  char * fsetname, struct izo_rcvd_rec *lr_server)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
+
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
+
+        hdr = upc_pack(IZO_UPC_REPSTATUS, 0, NULL, fsetname, 
+                       sizeof(*lr_server), (char*)lr_server, 
+                       &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("%s: error %d\n", __FUNCTION__, error);
+
+        EXIT;
+        return -error;
+}
+
+
+#if 0
+int izo_upc_client_make_branch(int minor, char *fsetname, char *tagname,
+                               char *branchname)
+{
+        int size, error;
+        struct izo_upcall_hdr *hdr;
+        int pathlen;
+        char *path;
+        ENTRY;
+
+        hdr = upc_pack(IZO_UPC_CLIENT_MAKE_BRANCH, strlen(tagname), tagname,
+                       fsetname, strlen(branchname) + 1, branchname, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                error = -PTR_ERR(hdr);
+                goto error;
+        }
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: error %d\n", error);
 
+ error:
+        PRESTO_FREE(path, pathlen);
+        EXIT;
         return error;
 }
+#endif
+
+int izo_upc_server_make_branch(int minor, char *fsetname)
+{
+        int size, error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
 
+        hdr = upc_pack(IZO_UPC_SERVER_MAKE_BRANCH, 0, NULL, fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                error = -PTR_ERR(hdr);
+                goto error;
+        }
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: error %d\n", error);
+
+ error:
+        EXIT;
+        return -error;
+}
+
+int izo_upc_branch_undo(int minor, char *fsetname, char *branchname)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
+
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
+
+        hdr = upc_pack(IZO_UPC_BRANCH_UNDO, strlen(branchname), branchname,
+                       fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
+
+        EXIT;
+        return -error;
+}
+
+int izo_upc_branch_redo(int minor, char *fsetname, char *branchname)
+{
+        int size;
+        int error;
+        struct izo_upcall_hdr *hdr;
+        ENTRY;
+
+        if (!presto_lento_up(minor)) {
+                EXIT;
+                return -EIO;
+        }
+
+        hdr = upc_pack(IZO_UPC_BRANCH_REDO, strlen(branchname) + 1, branchname,
+                       fsetname, 0, NULL, &size);
+        if (!hdr || IS_ERR(hdr)) {
+                EXIT;
+                return -PTR_ERR(hdr);
+        }
+
+        error = izo_upc_upcall(minor, &size, hdr, SYNCHRONOUS);
+        if (error)
+                CERROR("InterMezzo: %s: error %d\n", __FUNCTION__, error);
+
+        EXIT;
+        return -error;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/intermezzo/vfs.c linux.20pre10-ac2/fs/intermezzo/vfs.c
--- linux.20pre10/fs/intermezzo/vfs.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/intermezzo/vfs.c	2002-10-10 23:24:51.000000000 +0100
@@ -1,4 +1,25 @@
-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 2001, 2002 Cluster File Systems, Inc.
+ *  Copyright (C) 2000 Stelias Computing, Inc.
+ *  Copyright (C) 2000 Red Hat, Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
  * vfs.c
  *
  * This file implements kernel downcalls from lento.
@@ -48,20 +69,50 @@
 #include <linux/blk.h>
 
 #include <linux/intermezzo_fs.h>
-#include <linux/intermezzo_upcall.h>
 #include <linux/intermezzo_psdev.h>
-#include <linux/intermezzo_kml.h>
 
 #ifdef CONFIG_FS_EXT_ATTR
-#include <linux/ext_attr.h>
+# include <linux/ext_attr.h>
 
-#ifdef CONFIG_FS_POSIX_ACL
-#include <linux/posix_acl.h>
-#endif
+# ifdef CONFIG_FS_POSIX_ACL
+#  include <linux/posix_acl.h>
+# endif
 #endif
 
 extern struct inode_operations presto_sym_iops;
 
+/* Write the last_rcvd values to the last_rcvd file.  We don't know what the
+ * UUID or last_ctime values are, so we have to read from the file first
+ * (sigh). 
+ * exported for branch_reinter in kml_reint.c*/
+int presto_write_last_rcvd(struct rec_info *recinfo,
+                           struct presto_file_set *fset,
+                           struct lento_vfs_context *info)
+{
+        int rc;
+        struct izo_rcvd_rec rcvd_rec;
+
+        ENTRY;
+
+        memset(&rcvd_rec, 0, sizeof(rcvd_rec));
+        memcpy(rcvd_rec.lr_uuid, info->uuid, sizeof(rcvd_rec.lr_uuid));
+        rcvd_rec.lr_remote_recno = HTON__u64(info->recno);
+        rcvd_rec.lr_remote_offset = HTON__u64(info->kml_offset);
+        rcvd_rec.lr_local_recno = HTON__u64(recinfo->recno);
+        rcvd_rec.lr_local_offset = HTON__u64(recinfo->offset + recinfo->size);
+
+        rc = izo_rcvd_write(fset, &rcvd_rec);
+        if (rc < 0) {
+                /* izo_rcvd_write returns negative errors and non-negative
+                 * offsets */
+                CERROR("InterMezzo: izo_rcvd_write failed: %d\n", rc);
+                EXIT;
+                return rc;
+        }
+        EXIT;
+        return 0;
+}
+
 /*
  * It's inline, so penalty for filesystems that don't use sticky bit is
  * minimal.
@@ -130,13 +181,13 @@
                                      unsigned long value)
 {
         int minor = presto_f2m(fset);
-        int errorval = upc_comms[minor].uc_errorval;
-        kdev_t dev = fset->fset_mtpt->d_inode->i_dev;
+        int errorval = izo_channels[minor].uc_errorval;
+        kdev_t dev = fset->fset_dentry->d_inode->i_dev;
 
         if (errorval && errorval == (long)value && !is_read_only(dev)) {
                 CDEBUG(D_SUPER, "setting device %s read only\n", kdevname(dev));
                 BLKDEV_FAIL(dev, 1);
-                upc_comms[minor].uc_errorval = -dev;
+                izo_channels[minor].uc_errorval = -dev;
         }
 }
 #else
@@ -144,20 +195,22 @@
 #endif
 
 
-static inline int presto_do_kml(struct lento_vfs_context *info, struct inode* inode)
+static inline int presto_do_kml(struct lento_vfs_context *info,
+                                struct dentry *dentry)
 {
-        if ( ! (info->flags & LENTO_FL_KML) ) 
+        if ( ! (info->flags & LENTO_FL_KML) )
                 return 0;
-        if ( inode->i_gid == presto_excluded_gid ) 
+        if ( presto_chk(dentry, PRESTO_DONT_JOURNAL) )
                 return 0;
         return 1;
 }
 
-static inline int presto_do_expect(struct lento_vfs_context *info, struct inode *inode)
+static inline int presto_do_rcvd(struct lento_vfs_context *info,
+                                 struct dentry *dentry)
 {
         if ( ! (info->flags & LENTO_FL_EXPECT) ) 
                 return 0;
-        if ( inode->i_gid == presto_excluded_gid ) 
+        if ( presto_chk(dentry, PRESTO_DONT_JOURNAL) )
                 return 0;
         return 1;
 }
@@ -166,12 +219,15 @@
 /* XXX fixme: this should not fail, all these dentries are in memory
    when _we_ call this */
 int presto_settime(struct presto_file_set *fset, 
-                   struct dentry *dentry, 
+                   struct dentry *newobj,
+                   struct dentry *parent,
+                   struct dentry *target,
                    struct lento_vfs_context *ctx, 
                    int valid)
 {
-        int error; 
-        struct inode *inode = dentry->d_inode;
+        int error = 0;
+        struct dentry *dentry;
+        struct inode *inode;
         struct inode_operations *iops;
         struct iattr iattr;
 
@@ -180,39 +236,128 @@
                 EXIT;
                 return 0;
         }
+
         iattr.ia_ctime = ctx->updated_time;
         iattr.ia_mtime = ctx->updated_time;
         iattr.ia_valid = valid;
 
-        error = -EROFS;
-        if (IS_RDONLY(inode)) {
-                EXIT;
-                return -EROFS;
+        while (1) {
+                if (parent && ctx->flags & LENTO_FL_TOUCH_PARENT) {
+                        dentry = parent;
+                        parent = NULL;
+                } else if (newobj && ctx->flags & LENTO_FL_TOUCH_NEWOBJ) {
+                        dentry = newobj;
+                        newobj = NULL;
+                } else if (target) {
+                        dentry = target;
+                        target = NULL;
+                } else
+                        break;
+
+                inode = dentry->d_inode;
+
+                error = -EROFS;
+                if (IS_RDONLY(inode)) {
+                        EXIT;
+                        return -EROFS;
+                }
+
+                if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
+                        EXIT;
+                        return -EPERM;
+                }
+
+                error = -EPERM;
+                iops = filter_c2cdiops(fset->fset_cache->cache_filter); 
+                if (!iops) { 
+                        EXIT;
+                        return error;
+                }
+
+                if (iops->setattr != NULL)
+                        error = iops->setattr(dentry, &iattr);
+                else {
+                        error = 0;
+                        inode_setattr(dentry->d_inode, &iattr);
+                }
         }
+        EXIT;
+        return error;
+}
 
-        if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
+void izo_get_rollback_data(struct inode *inode, struct izo_rollback_data *rb)
+{
+        rb->rb_mode = (__u32)inode->i_mode;
+        rb->rb_rdev = (__u32)inode->i_rdev;
+        rb->rb_uid  = (__u64)inode->i_uid;
+        rb->rb_gid  = (__u64)inode->i_gid;
+}
+
+
+int presto_do_close(struct presto_file_set *fset, struct file *file)
+{
+        struct rec_info rec;
+        int rc = -ENOSPC; 
+        void *handle;
+        struct inode *inode = file->f_dentry->d_inode;
+        struct presto_file_data *fdata = 
+                (struct presto_file_data *)file->private_data;
+
+        ENTRY;
+        presto_getversion(&fdata->fd_info.remote_version, inode);
+
+        rc = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
+        if (rc) { 
                 EXIT;
-                return -EPERM;
+                return rc;
         }
 
-        error = -EPERM;
-        iops = filter_c2cdiops(fset->fset_cache->cache_filter); 
-        if (!iops) {
-                EXIT;
-                return error;
+        handle = presto_trans_start(fset, file->f_dentry->d_inode, 
+                                            KML_OPCODE_RELEASE);
+        if ( IS_ERR(handle) ) {
+                CERROR("presto_release: no space for transaction\n");
+                return rc;
         }
 
-        if (iops->setattr != NULL)
-                error = iops->setattr(dentry, &iattr);
-        else {
-		error = 0;
-                inode_setattr(dentry->d_inode, &iattr);
-	}
+        if (fdata->fd_info.flags & LENTO_FL_KML) 
+                rc = presto_journal_close(&rec, fset, file, file->f_dentry,
+                                          &fdata->fd_version, 
+                                          &fdata->fd_info.remote_version);
+        if (rc) { 
+                CERROR("presto_close: cannot journal close\n");
+                goto out;
+        }
+
+        if (fdata->fd_info.flags & LENTO_FL_EXPECT) 
+                rc = presto_write_last_rcvd(&rec, fset, &fdata->fd_info);
+
+        if (rc) { 
+                CERROR("presto_close: cannot journal last_rcvd\n");
+                goto out;
+        }
+        presto_trans_commit(fset, handle); 
+        
+        /* cancel the LML record */ 
+        handle = presto_trans_start(fset, inode, KML_OPCODE_WRITE);
+        if ( IS_ERR(handle) ) {
+                CERROR("presto_release: no space for clear\n");
+                return -ENOSPC;
+        }
+
+        rc = presto_clear_lml_close(fset, fdata->fd_lml_offset); 
+        if (rc < 0 ) { 
+                CERROR("presto_close: cannot journal close\n");
+                goto out;
+        }
+        presto_truncate_lml(fset);
+
+ out:
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+        presto_trans_commit(fset, handle); 
         EXIT;
-        return error;
+        return rc;
 }
 
-
 int presto_do_setattr(struct presto_file_set *fset, struct dentry *dentry,
                       struct iattr *iattr, struct lento_vfs_context *info)
 {
@@ -221,8 +366,9 @@
         struct inode_operations *iops;
         int error;
         struct presto_version old_ver, new_ver;
+        struct izo_rollback_data rb;
         void *handle;
-	off_t old_size=inode->i_size;
+        loff_t old_size=inode->i_size;
 
         ENTRY;
         error = -EROFS;
@@ -237,33 +383,34 @@
         }
 
         presto_getversion(&old_ver, dentry->d_inode);
+        izo_get_rollback_data(dentry->d_inode, &rb);
         error = -EPERM;
         iops = filter_c2cdiops(fset->fset_cache->cache_filter); 
-        if (!iops &&
-            !iops->setattr) {
+
+        error = presto_reserve_space(fset->fset_cache, 2*PRESTO_REQHIGH); 
+        if (error) {
                 EXIT;
                 return error;
         }
 
-	error = presto_reserve_space(fset->fset_cache, 2*PRESTO_REQHIGH); 
-	if (error) {
-		EXIT;
-		return error;
-	}
-
-	if  (iattr->ia_valid & ATTR_SIZE) { 
-		handle = presto_trans_start(fset, dentry->d_inode, PRESTO_OP_TRUNC);
-	} else {
-		handle = presto_trans_start(fset, dentry->d_inode, PRESTO_OP_SETATTR);
-	}
+        if  (iattr->ia_valid & ATTR_SIZE) {
+                if (izo_mark_dentry(dentry, ~PRESTO_DATA, 0, NULL) != 0)
+                        CERROR("izo_mark_dentry(inode %ld, ~PRESTO_DATA) "
+                               "failed\n", dentry->d_inode->i_ino);
+                handle = presto_trans_start(fset, dentry->d_inode,
+                                            KML_OPCODE_TRUNC);
+        } else {
+                handle = presto_trans_start(fset, dentry->d_inode,
+                                            KML_OPCODE_SETATTR);
+        }
 
         if ( IS_ERR(handle) ) {
-                printk("presto_do_setattr: no space for transaction\n");
-		presto_release_space(fset->fset_cache, 2*PRESTO_REQHIGH); 
+                CERROR("presto_do_setattr: no space for transaction\n");
+                presto_release_space(fset->fset_cache, 2*PRESTO_REQHIGH); 
                 return -ENOSPC;
         }
 
-        if (dentry->d_inode && iops->setattr) {
+        if (dentry->d_inode && iops && iops->setattr) {
                 error = iops->setattr(dentry, iattr);
         } else {
                 error = inode_change_ok(dentry->d_inode, iattr);
@@ -271,41 +418,43 @@
                         inode_setattr(inode, iattr);
         }
 
-	if (!error && (iattr->ia_valid & ATTR_SIZE))
-		vmtruncate(inode, iattr->ia_size);
+        if (!error && (iattr->ia_valid & ATTR_SIZE))
+                vmtruncate(inode, iattr->ia_size);
 
         if (error) {
                 EXIT;
                 goto exit;
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SETATTR | 0x10);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SETATTR | 0x10);
 
-        if ( presto_do_kml(info, dentry->d_inode) ) {
+        if ( presto_do_kml(info, dentry) ) {
                 if ((iattr->ia_valid & ATTR_SIZE) && (old_size != inode->i_size)) {
-                	struct file file;
-                	/* Journal a close whenever we see a potential truncate
-                 	* At the receiving end, lento should explicitly remove
-                 	* ATTR_SIZE from the list of valid attributes */
-                	presto_getversion(&new_ver, inode);
-                	file.private_data = NULL;
-                	file.f_dentry = dentry;
-                	error=presto_journal_close(&rec, fset, &file, dentry, &new_ver);
-            	}
+                        struct file file;
+                        /* Journal a close whenever we see a potential truncate
+                        * At the receiving end, lento should explicitly remove
+                        * ATTR_SIZE from the list of valid attributes */
+                        presto_getversion(&new_ver, inode);
+                        file.private_data = NULL;
+                        file.f_dentry = dentry;
+                        error = presto_journal_close(&rec, fset, &file, dentry,
+                                                     &old_ver, &new_ver);
+                }
 
-		if (!error)
-                	error = presto_journal_setattr(&rec, fset, dentry, &old_ver, iattr);
+                if (!error)
+                        error = presto_journal_setattr(&rec, fset, dentry,
+                                                       &old_ver, &rb, iattr);
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SETATTR | 0x20);
-        if ( presto_do_expect(info, dentry->d_inode) )
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SETATTR | 0x20);
+        if ( presto_do_rcvd(info, dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SETATTR | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SETATTR | 0x30);
 
         EXIT;
 exit:
-	presto_release_space(fset->fset_cache, 2*PRESTO_REQHIGH); 
+        presto_release_space(fset->fset_cache, 2*PRESTO_REQHIGH); 
         presto_trans_commit(fset, handle);
         return error;
 }
@@ -342,7 +491,7 @@
         fset = presto_fset(dentry);
         error = -EINVAL;
         if ( !fset ) {
-                printk("No fileset!\n");
+                CERROR("No fileset!\n");
                 EXIT;
                 goto exit_lock;
         }
@@ -378,6 +527,14 @@
 
         error = presto_do_setattr(fset, dentry, iattr, info);
 
+        if (info->flags & LENTO_FL_SET_DDFILEID) {
+                struct presto_dentry_data *dd = presto_d2d(dentry);
+                if (dd) {
+                        dd->remote_ino = info->remote_ino;
+                        dd->remote_generation = info->remote_generation;
+                }
+        }
+
 #ifdef CONFIG_FS_POSIX_ACL
         /* restore the inode_operations if we changed them*/
         if (iattr->ia_valid & ATTR_MODE) 
@@ -408,12 +565,12 @@
         mode |= S_IFREG;
 
         down(&dir->d_inode->i_zombie);
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
-	if (error) {
-		EXIT;
-        	up(&dir->d_inode->i_zombie);
-		return error;
-	}
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
+        if (error) {
+                EXIT;
+                up(&dir->d_inode->i_zombie);
+                return error;
+        }
 
         error = may_create(dir->d_inode, dentry);
         if (error) {
@@ -429,13 +586,13 @@
         }
 
         presto_getversion(&tgt_dir_ver, dir->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_CREATE);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_CREATE);
         if ( IS_ERR(handle) ) {
                 EXIT;
-		presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
-                printk("presto_do_create: no space for transaction\n");
+                presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+                CERROR("presto_do_create: no space for transaction\n");
                 error=-ENOSPC;
-		goto exit_pre_lock;
+                goto exit_pre_lock;
         }
         DQUOT_INIT(dir->d_inode);
         lock_kernel();
@@ -445,21 +602,11 @@
                 goto exit_lock;
         }
 
-        if (dentry->d_inode && 
-            dentry->d_inode->i_gid != presto_excluded_gid) {
+        if (dentry->d_inode) {
                 struct presto_cache *cache = fset->fset_cache;
                 /* was this already done? */
-                if ( !filter_c2cfiops(cache->cache_filter) )
-                        filter_setup_file_ops(cache->cache_filter, 
-                                              dentry->d_inode,
-                                              &presto_file_iops,
-                                              &presto_file_fops);
-
-                /* make the new inode ours */
-                dentry->d_inode->i_op = 
-                        filter_c2ufiops(cache->cache_filter);
-                dentry->d_inode->i_fop = 
-                        filter_c2uffops(cache->cache_filter);
+                presto_set_ops(dentry->d_inode, cache->cache_filter);
+
                 filter_setup_dentry_ops(cache->cache_filter, 
                                         dentry->d_op, 
                                         &presto_dentry_ops);
@@ -473,37 +620,44 @@
                 }
         }
 
-        error = presto_settime(fset, dir, info, ATTR_CTIME | ATTR_MTIME);
-        if (error) { 
-                EXIT;
-                goto exit_lock;
-        }
-        error = presto_settime(fset, dentry, info, ATTR_CTIME | ATTR_MTIME);
+        info->flags |= LENTO_FL_TOUCH_PARENT;
+        error = presto_settime(fset, NULL, dir, dentry,
+                               info, ATTR_CTIME | ATTR_MTIME);
         if (error) { 
                 EXIT;
                 goto exit_lock;
         }
 
+        presto_debug_fail_blkdev(fset, KML_OPCODE_CREATE | 0x10);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_CREATE | 0x10);
-        presto_getversion(&new_file_ver, dentry->d_inode);
-        if ( presto_do_kml(info, dentry->d_inode) )
+        if ( presto_do_kml(info, dentry) ) { 
+                presto_getversion(&new_file_ver, dentry->d_inode);
                 error = presto_journal_create(&rec, fset, dentry, &tgt_dir_ver,
-                                              &new_file_ver,
+                                              &new_file_ver, 
                                               dentry->d_inode->i_mode);
+        }
+
+        presto_debug_fail_blkdev(fset, KML_OPCODE_CREATE | 0x20);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_CREATE | 0x20);
-        if ( presto_do_expect(info, dentry->d_inode) )
+        if ( presto_do_rcvd(info, dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_CREATE | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_CREATE | 0x30);
+
+        /* add inode dentry */
+        if (fset->fset_cache->cache_filter->o_trops->tr_add_ilookup ) { 
+                struct dentry *d;
+                d = fset->fset_cache->cache_filter->o_trops->tr_add_ilookup
+                        (dir->d_inode->i_sb->s_root, dentry);
+        }
+
         EXIT;
 
  exit_lock:
         unlock_kernel();
         presto_trans_commit(fset, handle);
  exit_pre_lock:
-	presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
         up(&dir->d_inode->i_zombie);
         return error;
 }
@@ -551,9 +705,9 @@
         if (path_init(pathname,  LOOKUP_PARENT, &nd))
                 error = path_walk(pathname, &nd);
         if (error) {
-		EXIT;
+                EXIT;
                 goto exit;
-	}
+        }
         dentry = lookup_create(&nd, 0);
         error = PTR_ERR(dentry);
         if (IS_ERR(dentry)) {
@@ -564,7 +718,7 @@
         fset = presto_fset(dentry);
         error = -EINVAL;
         if ( !fset ) {
-                printk("No fileset!\n");
+                CERROR("No fileset!\n");
                 EXIT;
                 goto exit_lock;
         }
@@ -575,7 +729,7 @@
 
  exit_lock:
         path_release (&nd);
-	dput(dentry); 
+        dput(dentry); 
         up(&dentry->d_parent->d_inode->i_sem);
         putname(pathname);
 exit:
@@ -595,12 +749,12 @@
         void *handle;
 
         down(&dir->d_inode->i_zombie);
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
-	if (error) {
-		EXIT;
-        	up(&dir->d_inode->i_zombie);
-		return error;
-	}
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
+        if (error) {
+                EXIT;
+                up(&dir->d_inode->i_zombie);
+                return error;
+        }
         error = -ENOENT;
         inode = old_dentry->d_inode;
         if (!inode)
@@ -631,10 +785,10 @@
 
 
         presto_getversion(&tgt_dir_ver, dir->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_LINK);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_LINK);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
-                printk("presto_do_link: no space for transaction\n");
+                presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+                CERROR("presto_do_link: no space for transaction\n");
                 return -ENOSPC;
         }
 
@@ -647,32 +801,37 @@
                 goto exit_lock;
         }
 
-        error = presto_settime(fset, dir, info, ATTR_CTIME | ATTR_MTIME);
-        if (error) { 
-                EXIT;
-                goto exit_lock;
-        }
-        error = presto_settime(fset, new_dentry, info, ATTR_CTIME);
+        /* link dd data to that of existing dentry */
+        old_dentry->d_op->d_release(new_dentry); 
+        if (!presto_d2d(old_dentry)) 
+                BUG();
+        presto_d2d(old_dentry)->dd_count++;
+
+        new_dentry->d_fsdata = presto_d2d(old_dentry);
+
+        info->flags |= LENTO_FL_TOUCH_PARENT;
+        error = presto_settime(fset, NULL, dir, new_dentry,
+                               info, ATTR_CTIME);
         if (error) { 
                 EXIT;
                 goto exit_lock;
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_LINK | 0x10);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_LINK | 0x10);
         presto_getversion(&new_link_ver, new_dentry->d_inode);
-        if ( presto_do_kml(info, old_dentry->d_inode) )
+        if ( presto_do_kml(info, old_dentry) )
                 error = presto_journal_link(&rec, fset, old_dentry, new_dentry,
                                             &tgt_dir_ver, &new_link_ver);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_LINK | 0x20);
-        if ( presto_do_expect(info, old_dentry->d_inode) )
+        presto_debug_fail_blkdev(fset, KML_OPCODE_LINK | 0x20);
+        if ( presto_do_rcvd(info, old_dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_LINK | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_LINK | 0x30);
         EXIT;
         presto_trans_commit(fset, handle);
 exit_lock:
-	presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
         up(&dir->d_inode->i_zombie);
         return error;
 }
@@ -714,7 +873,7 @@
                         fset = presto_fset(new_dentry);
                         error = -EINVAL;
                         if ( !fset ) {
-                                printk("No fileset!\n");
+                                CERROR("No fileset!\n");
                                 EXIT;
                                 goto out2;
                         }
@@ -736,17 +895,17 @@
         return error;
 }
 
-
 int presto_do_unlink(struct presto_file_set *fset, struct dentry *dir,
                      struct dentry *dentry, struct lento_vfs_context *info)
 {
         struct rec_info rec;
-        int error;
         struct inode_operations *iops;
         struct presto_version tgt_dir_ver, old_file_ver;
+        struct izo_rollback_data rb;
         void *handle;
-        int do_kml = 0, do_expect =0;
-	int linkno = 0;
+        int do_kml = 0, do_rcvd = 0, linkno = 0, error, old_targetlen = 0;
+        char *old_target = NULL;
+
         ENTRY;
         down(&dir->d_inode->i_zombie);
         error = may_delete(dir->d_inode, dentry, 0);
@@ -764,19 +923,34 @@
                 return error;
         }
 
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQLOW); 
-	if (error) {
-		EXIT;
-        	up(&dir->d_inode->i_zombie);
-		return error;
-	}
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQLOW); 
+        if (error) {
+                EXIT;
+                up(&dir->d_inode->i_zombie);
+                return error;
+        }
+
+
+        if (presto_d2d(dentry)) { 
+                struct presto_dentry_data *dd = presto_d2d(dentry); 
+                struct dentry *de = dd->dd_inodentry;
+                if (de && dentry->d_inode->i_nlink == 1) { 
+                        dd->dd_count--;
+                        dd->dd_inodentry = NULL; 
+                        de->d_fsdata = NULL; 
+                        atomic_dec(&de->d_inode->i_count); 
+                        de->d_inode = NULL;
+                        dput(de); 
+                }
+        }
 
         presto_getversion(&tgt_dir_ver, dir->d_inode);
         presto_getversion(&old_file_ver, dentry->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_UNLINK);
+        izo_get_rollback_data(dentry->d_inode, &rb);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_UNLINK);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, PRESTO_REQLOW); 
-                printk("ERROR: presto_do_unlink: no space for transaction. Tell Peter.\n");
+                presto_release_space(fset->fset_cache, PRESTO_REQLOW); 
+                CERROR("ERROR: presto_do_unlink: no space for transaction. Tell Peter.\n");
                 up(&dir->d_inode->i_zombie);
                 return -ENOSPC;
         }
@@ -785,12 +959,45 @@
                 error = -EBUSY;
         else {
                 lock_kernel();
-		linkno = dentry->d_inode->i_nlink;
-		if (linkno > 1) {
-			dget(dentry);
-		}
-                do_kml = presto_do_kml(info, dir->d_inode);
-                do_expect = presto_do_expect(info, dir->d_inode);
+                linkno = dentry->d_inode->i_nlink;
+                if (linkno > 1) {
+                        dget(dentry);
+                }
+
+                if (S_ISLNK(dentry->d_inode->i_mode)) {
+                        mm_segment_t old_fs;
+                        struct inode_operations *riops;
+                        riops = filter_c2csiops(fset->fset_cache->cache_filter);
+
+                        PRESTO_ALLOC(old_target, PATH_MAX);
+                        if (old_target == NULL) {
+                                error = -ENOMEM;
+                                EXIT;
+                                goto exit;
+                        }
+
+                        old_fs = get_fs();
+                        set_fs(get_ds());
+
+                        if (riops->readlink == NULL)
+                                CERROR("InterMezzo %s: no readlink iops.\n",
+                                       __FUNCTION__);
+                        else
+                                old_targetlen =
+                                        riops->readlink(dentry, old_target,
+                                                        PATH_MAX);
+                        if (old_targetlen < 0) {
+                                CERROR("InterMezzo: readlink failed: %ld\n",
+                                       PTR_ERR(old_target));
+                                PRESTO_FREE(old_target, PATH_MAX);
+                                old_target = NULL;
+                                old_targetlen = 0;
+                        }
+                        set_fs(old_fs);
+                }
+
+                do_kml = presto_do_kml(info, dir);
+                do_rcvd = presto_do_rcvd(info, dir);
                 error = iops->unlink(dir->d_inode, dentry);
                 unlock_kernel();
                 if (!error)
@@ -798,7 +1005,9 @@
         }
 
         if (linkno > 1) { 
-                error = presto_settime(fset, dentry, info, ATTR_CTIME);
+                /* FIXME: Combine this with the next call? */
+                error = presto_settime(fset, NULL, NULL, dentry,
+                                       info, ATTR_CTIME);
                 dput(dentry); 
                 if (error) { 
                         EXIT;
@@ -806,7 +1015,8 @@
                 }
         }
 
-        error = presto_settime(fset, dir, info, ATTR_CTIME | ATTR_MTIME);
+        error = presto_settime(fset, NULL, NULL, dir,
+                               info, ATTR_CTIME | ATTR_MTIME);
         if (error) { 
                 EXIT;
                 goto exit;
@@ -818,22 +1028,22 @@
                 goto exit;
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_UNLINK | 0x10);
-        if ( do_kml ) { 
+        presto_debug_fail_blkdev(fset, KML_OPCODE_UNLINK | 0x10);
+        if ( do_kml )
                 error = presto_journal_unlink(&rec, fset, dir, &tgt_dir_ver,
-                                              &old_file_ver,
-                                              dentry->d_name.len,
-                                              dentry->d_name.name);
-	}
-        presto_debug_fail_blkdev(fset, PRESTO_OP_UNLINK | 0x20);
-        if ( do_expect ) { 
+                                              &old_file_ver, &rb, dentry,
+                                              old_target, old_targetlen);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_UNLINK | 0x20);
+        if ( do_rcvd ) { 
                 error = presto_write_last_rcvd(&rec, fset, info);
-	}
-        presto_debug_fail_blkdev(fset, PRESTO_OP_UNLINK | 0x30);
+        }
+        presto_debug_fail_blkdev(fset, KML_OPCODE_UNLINK | 0x30);
         EXIT;
 exit:
-	presto_release_space(fset->fset_cache, PRESTO_REQLOW); 
+        presto_release_space(fset->fset_cache, PRESTO_REQLOW); 
         presto_trans_commit(fset, handle);
+        if (old_target != NULL)
+                PRESTO_FREE(old_target, PATH_MAX);
         return error;
 }
 
@@ -866,7 +1076,7 @@
                 fset = presto_fset(dentry);
                 error = -EINVAL;
                 if ( !fset ) {
-                        printk("No fileset!\n");
+                        CERROR("No fileset!\n");
                         EXIT;
                         goto exit2;
                 }
@@ -904,13 +1114,13 @@
 
         ENTRY;
         down(&dir->d_inode->i_zombie);
-	/* record + max path len + space to free */ 
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
-	if (error) {
-		EXIT;
-        	up(&dir->d_inode->i_zombie);
-		return error;
-	}
+        /* record + max path len + space to free */ 
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
+        if (error) {
+                EXIT;
+                up(&dir->d_inode->i_zombie);
+                return error;
+        }
 
         error = may_create(dir->d_inode, dentry);
         if (error) {
@@ -926,11 +1136,12 @@
         }
 
         presto_getversion(&tgt_dir_ver, dir->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_SYMLINK);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_SYMLINK);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
-                printk("ERROR: presto_do_symlink: no space for transaction. Tell Peter.\n"); 
+                presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
+                CERROR("ERROR: presto_do_symlink: no space for transaction. Tell Peter.\n"); 
                 EXIT;
+                up(&dir->d_inode->i_zombie);
                 return -ENOSPC;
         }
         DQUOT_INIT(dir->d_inode);
@@ -941,19 +1152,11 @@
                 goto exit;
         }
 
-        if (dentry->d_inode &&
-            dentry->d_inode->i_gid != presto_excluded_gid) {
+        if (dentry->d_inode) {
                 struct presto_cache *cache = fset->fset_cache;
                 
-                /* was this already done? */
-                if ( !filter_c2csiops(cache->cache_filter) )
-                        filter_setup_symlink_ops(cache->cache_filter, 
-                                                 dentry->d_inode,
-                                                 &presto_sym_iops,
-                                                 NULL);
+                presto_set_ops(dentry->d_inode, cache->cache_filter);
 
-                /* make the new inode ours */
-                dentry->d_inode->i_op = filter_c2usiops(cache->cache_filter);
                 filter_setup_dentry_ops(cache->cache_filter, dentry->d_op, 
                                         &presto_dentry_ops);
                 dentry->d_op = filter_c2udops(cache->cache_filter);
@@ -965,34 +1168,31 @@
                 }
         }
 
-        error = presto_settime(fset, dir, info, ATTR_CTIME | ATTR_MTIME);
-        if (error) { 
-                EXIT;
-                goto exit;
-        }
-        error = presto_settime(fset, dentry, info, ATTR_CTIME | ATTR_MTIME);
+        info->flags |= LENTO_FL_TOUCH_PARENT;
+        error = presto_settime(fset, NULL, dir, dentry,
+                               info, ATTR_CTIME | ATTR_MTIME);
         if (error) { 
                 EXIT;
                 goto exit;
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SYMLINK | 0x10);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SYMLINK | 0x10);
         presto_getversion(&new_link_ver, dentry->d_inode);
-        if ( presto_do_kml(info, dentry->d_inode) )
+        if ( presto_do_kml(info, dentry) )
                 error = presto_journal_symlink(&rec, fset, dentry, oldname,
                                                &tgt_dir_ver, &new_link_ver);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SYMLINK | 0x20);
-        if ( presto_do_expect(info, dentry->d_inode) )
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SYMLINK | 0x20);
+        if ( presto_do_rcvd(info, dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SYMLINK | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SYMLINK | 0x30);
         EXIT;
 exit:
         unlock_kernel();
         presto_trans_commit(fset, handle);
  exit_lock:
-	presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
         up(&dir->d_inode->i_zombie);
         return error;
 }
@@ -1033,7 +1233,7 @@
         dentry = lookup_create(&nd, 0);
         error = PTR_ERR(dentry);
         if (IS_ERR(dentry)) {
-        	path_release(&nd);
+                path_release(&nd);
                 EXIT;
                 goto exit_to;
         }
@@ -1041,8 +1241,8 @@
         fset = presto_fset(dentry);
         error = -EINVAL;
         if ( !fset ) {
-                printk("No fileset!\n");
-        	path_release(&nd);
+                CERROR("No fileset!\n");
+                path_release(&nd);
                 EXIT;
                 goto exit_lock;
         }
@@ -1073,11 +1273,12 @@
 
         ENTRY;
         down(&dir->d_inode->i_zombie);
-	/* one journal record + directory block + room for removals*/ 
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
-	if (error) { 
+
+        /* one journal record + directory block + room for removals*/ 
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
+        if (error) { 
                 EXIT;
-        	up(&dir->d_inode->i_zombie);
+                up(&dir->d_inode->i_zombie);
                 return error;
         }
 
@@ -1095,10 +1296,10 @@
 
         error = -ENOSPC;
         presto_getversion(&tgt_dir_ver, dir->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_MKDIR);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_MKDIR);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
-                printk("presto_do_mkdir: no space for transaction\n");
+                presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
+                CERROR("presto_do_mkdir: no space for transaction\n");
                 goto exit_lock;
         }
 
@@ -1111,11 +1312,11 @@
                 goto exit;
         }
 
-        if ( dentry->d_inode && !error && 
-             dentry->d_inode->i_gid != presto_excluded_gid) {
+        if ( dentry->d_inode && !error) {
                 struct presto_cache *cache = fset->fset_cache;
-                /* make it ours */
-                dentry->d_inode->i_op = filter_c2udiops(cache->cache_filter);
+
+                presto_set_ops(dentry->d_inode, cache->cache_filter);
+
                 filter_setup_dentry_ops(cache->cache_filter, 
                                         dentry->d_op, 
                                         &presto_dentry_ops);
@@ -1128,35 +1329,32 @@
                 }
         }
 
-        error = presto_settime(fset, dir, info, ATTR_CTIME | ATTR_MTIME);
-        if (error) { 
-                EXIT;
-                goto exit;
-        }
-        error = presto_settime(fset, dentry, info, ATTR_CTIME | ATTR_MTIME);
+        info->flags |= LENTO_FL_TOUCH_PARENT;
+        error = presto_settime(fset, NULL, dir, dentry,
+                             info, ATTR_CTIME | ATTR_MTIME);
         if (error) { 
                 EXIT;
                 goto exit;
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_MKDIR | 0x10);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_MKDIR | 0x10);
         presto_getversion(&new_dir_ver, dentry->d_inode);
-        if ( presto_do_kml(info, dentry->d_inode) )
+        if ( presto_do_kml(info, dir) )
                 error = presto_journal_mkdir(&rec, fset, dentry, &tgt_dir_ver,
-                                             &new_dir_ver,
+                                             &new_dir_ver, 
                                              dentry->d_inode->i_mode);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_MKDIR | 0x20);
-        if ( presto_do_expect(info, dentry->d_inode) )
+        presto_debug_fail_blkdev(fset, KML_OPCODE_MKDIR | 0x20);
+        if ( presto_do_rcvd(info, dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_MKDIR | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_MKDIR | 0x30);
         EXIT;
 exit:
         unlock_kernel();
         presto_trans_commit(fset, handle);
  exit_lock:
-	presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH + 4096); 
         up(&dir->d_inode->i_zombie);
         return error;
 }
@@ -1193,8 +1391,8 @@
         if (!IS_ERR(dentry)) {
                 fset = presto_fset(dentry);
                 error = -EINVAL;
-                if ( !fset ) {
-                        printk("No fileset!\n");
+                if (!fset) {
+                        CERROR("No fileset!\n");
                         EXIT;
                         goto out_dput;
                 }
@@ -1202,14 +1400,14 @@
                 error = presto_do_mkdir(fset, nd.dentry, dentry, 
                                         mode & S_IALLUGO, info);
 out_dput:
-		dput(dentry);
+                dput(dentry);
         }
-	up(&nd.dentry->d_inode->i_sem);
-	path_release(&nd);
+        up(&nd.dentry->d_inode->i_sem);
+        path_release(&nd);
 out_name:
         EXIT;
         putname(pathname);
-	CDEBUG(D_PIOCTL, "error: %d\n", error);
+        CDEBUG(D_PIOCTL, "error: %d\n", error);
         return error;
 }
 
@@ -1232,10 +1430,11 @@
         struct rec_info rec;
         int error;
         struct presto_version tgt_dir_ver, old_dir_ver;
+        struct izo_rollback_data rb;
         struct inode_operations *iops;
         void *handle;
-        int do_kml, do_expect;
-	int size;
+        int do_kml, do_rcvd;
+        int size;
 
         ENTRY;
         error = may_delete(dir->d_inode, dentry, 1);
@@ -1249,64 +1448,67 @@
                 return error;
         }
 
-	size = PRESTO_REQHIGH - dentry->d_inode->i_size; 
-	error = presto_reserve_space(fset->fset_cache, size); 
-	if (error) { 
-		EXIT;
-		return error;
-	}
+        size = PRESTO_REQHIGH - dentry->d_inode->i_size; 
+        error = presto_reserve_space(fset->fset_cache, size); 
+        if (error) { 
+                EXIT;
+                return error;
+        }
 
         presto_getversion(&tgt_dir_ver, dir->d_inode);
         presto_getversion(&old_dir_ver, dentry->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_RMDIR);
+        izo_get_rollback_data(dentry->d_inode, &rb);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_RMDIR);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, size); 
-                printk("ERROR: presto_do_rmdir: no space for transaction. Tell Peter.\n");
+                presto_release_space(fset->fset_cache, size); 
+                CERROR("ERROR: presto_do_rmdir: no space for transaction. Tell Peter.\n");
                 return -ENOSPC;
         }
 
         DQUOT_INIT(dir->d_inode);
 
-        do_kml = presto_do_kml(info, dir->d_inode);
-        do_expect = presto_do_expect(info, dir->d_inode);
+        do_kml = presto_do_kml(info, dir);
+        do_rcvd = presto_do_rcvd(info, dir);
 
         double_down(&dir->d_inode->i_zombie, &dentry->d_inode->i_zombie);
         d_unhash(dentry);
         if (IS_DEADDIR(dir->d_inode))
                 error = -ENOENT;
-        else if (d_mountpoint(dentry))
+        else if (d_mountpoint(dentry)) {
+                CERROR("foo: d_mountpoint(dentry): ino %ld\n",
+                       dentry->d_inode->i_ino);
                 error = -EBUSY;
-        else {
+        } else {
                 lock_kernel();
                 error = iops->rmdir(dir->d_inode, dentry);
                 unlock_kernel();
                 if (!error) {
                         dentry->d_inode->i_flags |= S_DEAD;
-			error = presto_settime(fset, dir, info, 
-					       ATTR_CTIME | ATTR_MTIME);
-		}
+                        error = presto_settime(fset, NULL, NULL, dir, info,
+                                               ATTR_CTIME | ATTR_MTIME);
+                }
         }
         double_up(&dir->d_inode->i_zombie, &dentry->d_inode->i_zombie);
         if (!error)
                 d_delete(dentry);
         dput(dentry);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_RMDIR | 0x10);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_RMDIR | 0x10);
         if ( !error && do_kml )
                 error = presto_journal_rmdir(&rec, fset, dir, &tgt_dir_ver,
-                                             &old_dir_ver,
+                                             &old_dir_ver, &rb,
                                              dentry->d_name.len,
                                              dentry->d_name.name);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_RMDIR | 0x20);
-        if ( !error && do_expect ) 
+        presto_debug_fail_blkdev(fset, KML_OPCODE_RMDIR | 0x20);
+        if ( !error && do_rcvd ) 
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_RMDIR | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_RMDIR | 0x30);
         EXIT;
 
         presto_trans_commit(fset, handle);
-	presto_release_space(fset->fset_cache, size); 
+        presto_release_space(fset->fset_cache, size); 
         return error;
 }
 
@@ -1320,21 +1522,27 @@
 
         ENTRY;
         name = getname(pathname);
-        if(IS_ERR(name))
+        if(IS_ERR(name)) {
+                EXIT;
                 return PTR_ERR(name);
+        }
 
         if (path_init(name, LOOKUP_PARENT, &nd))
                 error = path_walk(name, &nd);
-        if (error)
+        if (error) {
+                EXIT;
                 goto exit;
-
+        }
         switch(nd.last_type) {
-                case LAST_DOTDOT:
-                        error = -ENOTEMPTY;
-                        goto exit1;
-                case LAST_ROOT: case LAST_DOT:
-                        error = -EBUSY;
-                        goto exit1;
+        case LAST_DOTDOT:
+                error = -ENOTEMPTY;
+                EXIT;
+                goto exit1;
+        case LAST_ROOT:
+        case LAST_DOT:
+                error = -EBUSY;
+                EXIT;
+                goto exit1;
         }
         down(&nd.dentry->d_inode->i_sem);
         dentry = lookup_hash(&nd.last, nd.dentry);
@@ -1343,7 +1551,7 @@
                 fset = presto_fset(dentry);
                 error = -EINVAL;
                 if ( !fset ) {
-                        printk("No fileset!\n");
+                        CERROR("No fileset!\n");
                         EXIT;
                         goto exit_put;
                 }
@@ -1353,11 +1561,10 @@
         }
         up(&nd.dentry->d_inode->i_sem);
 exit1:
-        EXIT;
         path_release(&nd);
 exit:
-        EXIT;
         putname(name);
+        EXIT;
         return error;
 }
 
@@ -1374,13 +1581,13 @@
         ENTRY;
 
         down(&dir->d_inode->i_zombie);
-	/* one KML entry */ 
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
-	if (error) {
-		EXIT;
-        	up(&dir->d_inode->i_zombie);
-		return error;
-	}
+        /* one KML entry */ 
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
+        if (error) {
+                EXIT;
+                up(&dir->d_inode->i_zombie);
+                return error;
+        }
 
         if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD)) {
                 EXIT;
@@ -1405,10 +1612,10 @@
         
         error = -ENOSPC;
         presto_getversion(&tgt_dir_ver, dir->d_inode);
-        handle = presto_trans_start(fset, dir->d_inode, PRESTO_OP_MKNOD);
+        handle = presto_trans_start(fset, dir->d_inode, KML_OPCODE_MKNOD);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
-                printk("presto_do_mknod: no space for transaction\n");
+                presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+                CERROR("presto_do_mknod: no space for transaction\n");
                 goto exit_lock2;
         }
 
@@ -1417,11 +1624,11 @@
                 EXIT;
                 goto exit_commit;
         }
-        if ( dentry->d_inode &&
-             dentry->d_inode->i_gid != presto_excluded_gid) {
+        if ( dentry->d_inode) {
                 struct presto_cache *cache = fset->fset_cache;
-                /* make it ours */
-                dentry->d_inode->i_op = filter_c2udiops(cache->cache_filter);
+
+                presto_set_ops(dentry->d_inode, cache->cache_filter);
+
                 filter_setup_dentry_ops(cache->cache_filter, dentry->d_op, 
                                         &presto_dentry_ops);
                 dentry->d_op = filter_c2udops(cache->cache_filter);
@@ -1434,35 +1641,37 @@
                 }
         }
 
-        error = presto_settime(fset, dir, info, ATTR_MTIME);
+        error = presto_settime(fset, NULL, NULL, dir,
+                               info, ATTR_MTIME);
         if (error) { 
                 EXIT;
         }
-        error = presto_settime(fset, dentry, info, ATTR_CTIME | ATTR_MTIME);
+        error = presto_settime(fset, NULL, NULL, dentry,
+                               info, ATTR_CTIME | ATTR_MTIME);
         if (error) { 
                 EXIT;
         }
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_MKNOD | 0x10);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_MKNOD | 0x10);
         presto_getversion(&new_node_ver, dentry->d_inode);
-        if ( presto_do_kml(info, dentry->d_inode) )
+        if ( presto_do_kml(info, dentry) )
                 error = presto_journal_mknod(&rec, fset, dentry, &tgt_dir_ver,
-                                             &new_node_ver,
+                                             &new_node_ver, 
                                              dentry->d_inode->i_mode,
                                              MAJOR(dev), MINOR(dev) );
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_MKNOD | 0x20);
-        if ( presto_do_expect(info, dentry->d_inode) ) 
+        presto_debug_fail_blkdev(fset, KML_OPCODE_MKNOD | 0x20);
+        if ( presto_do_rcvd(info, dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_MKNOD | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_MKNOD | 0x30);
         EXIT;
  exit_commit:
         presto_trans_commit(fset, handle);
  exit_lock2:
         unlock_kernel();
  exit_lock:
-	presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
         up(&dir->d_inode->i_zombie);
         return error;
 }
@@ -1494,7 +1703,7 @@
                 fset = presto_fset(dentry);
                 error = -EINVAL;
                 if ( !fset ) {
-                        printk("No fileset!\n");
+                        CERROR("No fileset!\n");
                         EXIT;
                         goto exit_put;
                 }
@@ -1523,7 +1732,7 @@
         return error;
 }
 
-static int do_rename(struct presto_file_set *fset,
+int do_rename(struct presto_file_set *fset,
                      struct dentry *old_parent, struct dentry *old_dentry,
                      struct dentry *new_parent, struct dentry *new_dentry,
                      struct lento_vfs_context *info)
@@ -1533,7 +1742,7 @@
         struct inode_operations *iops;
         struct presto_version src_dir_ver, tgt_dir_ver;
         void *handle;
-	int new_inode_unlink = 0;
+        int new_inode_unlink = 0;
         struct inode *old_dir = old_parent->d_inode;
         struct inode *new_dir = new_parent->d_inode;
 
@@ -1548,15 +1757,15 @@
                 return error;
         }
 
-	error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
-	if (error) {
-		EXIT;
-		return error;
-	}
-        handle = presto_trans_start(fset, old_dir, PRESTO_OP_RENAME);
+        error = presto_reserve_space(fset->fset_cache, PRESTO_REQHIGH); 
+        if (error) {
+                EXIT;
+                return error;
+        }
+        handle = presto_trans_start(fset, old_dir, KML_OPCODE_RENAME);
         if ( IS_ERR(handle) ) {
-		presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
-                printk("presto_do_rename: no space for transaction\n");
+                presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+                CERROR("presto_do_rename: no space for transaction\n");
                 return -ENOSPC;
         }
         if (new_dentry->d_inode && new_dentry->d_inode->i_nlink > 1) { 
@@ -1572,19 +1781,17 @@
         }
 
         if (new_inode_unlink) { 
-                error = presto_settime(fset, old_dentry, info, ATTR_CTIME);
+                error = presto_settime(fset, NULL, NULL, old_dentry,
+                                       info, ATTR_CTIME);
                 dput(old_dentry); 
                 if (error) { 
                         EXIT;
                         goto exit;
                 }
         }
-        error = presto_settime(fset, old_parent, info, ATTR_CTIME | ATTR_MTIME);
-        if (error) { 
-                EXIT;
-                goto exit;
-        }
-        error = presto_settime(fset, new_parent, info, ATTR_CTIME | ATTR_MTIME);
+        info->flags |= LENTO_FL_TOUCH_PARENT;
+        error = presto_settime(fset, NULL, new_parent, old_parent,
+                               info, ATTR_CTIME | ATTR_MTIME);
         if (error) { 
                 EXIT;
                 goto exit;
@@ -1593,21 +1800,22 @@
         /* XXX make a distinction between cross file set
          * and intra file set renames here
          */
-        presto_debug_fail_blkdev(fset, PRESTO_OP_RENAME | 0x10);
-        if ( presto_do_kml(info, old_dir) )
-                error = presto_journal_rename(&rec, fset, old_dentry, new_dentry,
+        presto_debug_fail_blkdev(fset, KML_OPCODE_RENAME | 0x10);
+        if ( presto_do_kml(info, old_dentry) )
+                error = presto_journal_rename(&rec, fset, old_dentry,
+                                              new_dentry,
                                               &src_dir_ver, &tgt_dir_ver);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_RENAME | 0x20);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_RENAME | 0x20);
 
-        if ( presto_do_expect(info, new_dir) ) 
+        if ( presto_do_rcvd(info, old_dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_RENAME | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_RENAME | 0x30);
         EXIT;
 exit:
         presto_trans_commit(fset, handle);
-	presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
+        presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
         return error;
 }
 
@@ -1729,7 +1937,7 @@
                 error = -EBUSY;
         else
                 error = do_rename(fset, old_parent, old_dentry,
-                                         new_parent, new_dentry, info);
+                                  new_parent, new_dentry, info);
         double_up(&old_dir->i_zombie, &new_dir->i_zombie);
         if (error)
                 return error;
@@ -1802,7 +2010,7 @@
         fset = presto_fset(old_dentry);
         error = -EINVAL;
         if ( !fset ) {
-                printk("No fileset!\n");
+                CERROR("No fileset!\n");
                 EXIT;
                 goto exit4;
         }
@@ -1852,7 +2060,7 @@
         if (!IS_ERR(to)) {
                 error = lento_do_rename(from,to, info);
                 putname(to);
-        }
+        } 
         putname(from);
         return error;
 }
@@ -1879,7 +2087,7 @@
         fset = presto_fset(dentry);
         error = -EINVAL;
         if (!fset) {
-                printk("No fileset for %*s!\n",
+                CERROR("No fileset for %*s!\n",
                        dentry->d_name.len, dentry->d_name.name);
                 EXIT;
                 dput(dentry);
@@ -1890,7 +2098,7 @@
         sprintf(name, "%s%#lx%c%#x",
                 PRESTO_ILOOKUP_MAGIC, ino, PRESTO_ILOOKUP_SEP, generation);
         CDEBUG(D_PIOCTL, "opening %ld by number (as %s)\n", ino, name);
-        return lookup_one_len(name, fset->fset_mtpt, strlen(name));
+        return lookup_one_len(name, fset->fset_dentry, strlen(name));
 }
 
 static struct file *presto_filp_dopen(struct dentry *dentry, int flags)
@@ -1914,8 +2122,7 @@
                 error = get_write_access(inode);
                 if (error) {
                         CDEBUG(D_PIOCTL, "error getting write access\n");
-                        EXIT;
-                        goto cleanup_file;
+                        EXIT;                        goto cleanup_file;
                 }
         }
 
@@ -1969,8 +2176,8 @@
          * just turn off the flag and ignore it.
          */
         if (flags & O_CREAT) {
-                printk(KERN_WARNING "%s: create file by inode number (%ld) not allowed\n",
-                	__FUNCTION__, ino);
+                CERROR("%s: create file by inode number (%ld) not allowed\n",
+                       __FUNCTION__, ino);
                 EXIT;
                 return -EACCES;
         }
@@ -1986,6 +2193,7 @@
         error = presto_walk(tmp, &nd);
         if ( error && error != -ENOENT ) {
                 EXIT;
+                unlock_kernel();
                 return error;
         } 
         if (error == -ENOENT)
@@ -2000,7 +2208,7 @@
                 slash = strrchr(tmp, '/');
                 if (slash && slash != tmp) {
                         *slash = '\0';
-			path_release(&nd);
+                        path_release(&nd);
                         goto again;
                 }
                 /* we should never get here... */
@@ -2052,7 +2260,7 @@
         EXIT;
 exit:
         unlock_kernel();
-	path_release(&nd);
+        path_release(&nd);
         putname(tmp);
         return fd;
 
@@ -2061,72 +2269,6 @@
         goto exit;
 }
 
-int lento_close(unsigned int fd, struct lento_vfs_context *info)
-{
-        struct rec_info rec;
-        int error;
-        struct file * filp;
-        struct dentry *dentry;
-        int do_kml, do_expect;
-
-        ENTRY;
-        lock_kernel();
-
-        error = -EBADF;
-        filp = fcheck(fd);
-        if (filp) {
-
-                struct files_struct * files = current->files;
-                dentry = filp->f_dentry;
-                dget(dentry);
-                do_kml = presto_do_kml(info, dentry->d_inode);
-                do_expect = presto_do_expect(info, dentry->d_inode);
-                files->fd[fd] = NULL;
-                put_unused_fd(fd);
-                FD_CLR(fd, files->close_on_exec);
-                error = filp_close(filp, files);
-        } else {
-                EXIT;
-                return error;
-        }
-
-        if (error) {
-                EXIT;
-                goto exit;
-        }
-
-        if ( do_kml ) { 
-                struct presto_file_set *fset;
-                struct presto_version new_file_ver;
-
-                fset = presto_fset(dentry);
-                error = -EINVAL;
-                if (!fset) {
-                        printk("No fileset for %*s!\n",
-                               dentry->d_name.len, dentry->d_name.name);
-                        EXIT;
-                        goto exit;
-                }
-                presto_getversion(&new_file_ver, dentry->d_inode);
-                error = presto_journal_close(&rec, fset, filp, dentry, 
-					     &new_file_ver);
-                if ( error ) {
-                        printk("presto: close error %d!\n", error);
-                        EXIT;
-                        goto exit;
-                }
-                if ( do_expect ) 
-
-                        error = presto_write_last_rcvd(&rec, fset, info);
-        }
-
-        EXIT;
-exit:
-        dput(dentry);
-        unlock_kernel();
-        return error;
-}
-
 #ifdef CONFIG_FS_EXT_ATTR
 
 #ifdef CONFIG_FS_POSIX_ACL
@@ -2254,9 +2396,9 @@
         }
 
         
-        handle = presto_trans_start(fset,dentry->d_inode,PRESTO_OP_SETEXTATTR);
+        handle = presto_trans_start(fset,dentry->d_inode,KML_OPCODE_SETEXTATTR);
         if ( IS_ERR(handle) ) {
-                printk("presto_do_set_ext_attr: no space for transaction\n");
+                CERROR("presto_do_set_ext_attr: no space for transaction\n");
                 presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
                 return -ENOSPC;
         }
@@ -2285,15 +2427,15 @@
 #endif
 
         /* Reset ctime. Only inode change time (ctime) is affected */
-        error = presto_settime(fset, dentry, info, ATTR_CTIME);
+        error = presto_settime(fset, NULL, NULL, dentry, info, ATTR_CTIME);
         if (error) { 
                 EXIT;
                 goto exit;
         }
 
         if (flags & EXT_ATTR_FLAG_USER) {
-                printk(" USER flag passed to presto_do_set_ext_attr!\n");
-                *(int *)0 = 1;
+                CERROR(" USER flag passed to presto_do_set_ext_attr!\n");
+                BUG();
         }
 
         /* We are here, so set_ext_attr succeeded. We no longer need to keep
@@ -2302,17 +2444,17 @@
          */
         flags &= ~(EXT_ATTR_FLAG_EXISTS | EXT_ATTR_FLAG_CREATE);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SETEXTATTR | 0x10);
-        if ( presto_do_kml(info, dentry->d_inode) )
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SETEXTATTR | 0x10);
+        if ( presto_do_kml(info, dentry) )
                 error = presto_journal_set_ext_attr
                         (&rec, fset, dentry, &ver, name, buffer, 
                          buffer_len, flags);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SETEXTATTR | 0x20);
-        if ( presto_do_expect(info, dentry->d_inode) )
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SETEXTATTR | 0x20);
+        if ( presto_do_rcvd(info, dentry) )
                 error = presto_write_last_rcvd(&rec, fset, info);
 
-        presto_debug_fail_blkdev(fset, PRESTO_OP_SETEXTATTR | 0x30);
+        presto_debug_fail_blkdev(fset, KML_OPCODE_SETEXTATTR | 0x30);
         EXIT;
 exit:
         presto_release_space(fset->fset_cache, PRESTO_REQHIGH); 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/ioctl.c linux.20pre10-ac2/fs/ioctl.c
--- linux.20pre10/fs/ioctl.c	2002-10-09 21:36:35.000000000 +0100
+++ linux.20pre10-ac2/fs/ioctl.c	2002-08-06 15:41:51.000000000 +0100
@@ -101,6 +101,16 @@
 				filp->f_flags &= ~FASYNC;
 			break;
 
+		case FIOQSIZE:
+			if (S_ISDIR(filp->f_dentry->d_inode->i_mode) ||
+			    S_ISREG(filp->f_dentry->d_inode->i_mode) ||
+			    S_ISLNK(filp->f_dentry->d_inode->i_mode)) {
+				loff_t res = inode_get_bytes(filp->f_dentry->d_inode);
+				error = copy_to_user((loff_t *)arg, &res, sizeof(res)) ? -EFAULT : 0;
+			}
+			else
+				error = -ENOTTY;
+			break;
 		default:
 			error = -ENOTTY;
 			if (S_ISREG(filp->f_dentry->d_inode->i_mode))
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/jbd/commit.c linux.20pre10-ac2/fs/jbd/commit.c
--- linux.20pre10/fs/jbd/commit.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/jbd/commit.c	2002-09-29 20:19:54.000000000 +0100
@@ -704,13 +704,25 @@
 			JBUFFER_TRACE(jh, "refile for checkpoint writeback");
 			__journal_refile_buffer(jh);
 		} else {
+			struct page *page = bh->b_page;
+			
 			J_ASSERT_BH(bh, !buffer_dirty(bh));
 			J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
 			__journal_unfile_buffer(jh);
 			jh->b_transaction = 0;
 			__journal_remove_journal_head(bh);
-			__brelse(bh);
+
+			if (TryLockPage(page)) {	
+				__brelse(bh);
+			} else {
+				__brelse(bh);
+				page_cache_get(page);
+				try_to_free_buffers(page, 0);
+				unlock_page(page);
+				page_cache_release(page);
+			}
 		}
+		
 		spin_unlock(&journal_datalist_lock);
 	}
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/jbd/journal.c linux.20pre10-ac2/fs/jbd/journal.c
--- linux.20pre10/fs/jbd/journal.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/jbd/journal.c	2002-09-29 20:24:28.000000000 +0100
@@ -730,14 +730,21 @@
  * need to set up all of the mapping information to tell the journaling
  * system where the journal blocks are.
  *
- * journal_init_dev creates a journal which maps a fixed contiguous
- * range of blocks on an arbitrary block device.
- *
- * journal_init_inode creates a journal which maps an on-disk inode as
- * the journal.  The inode must exist already, must support bmap() and
- * must have all data blocks preallocated.
  */
 
+ /**
+  *  journal_t * journal_init_dev() - creates an initialises a journal structure
+  *  @kdev: Block device on which to create the journal
+  *  @fs_dev: Device which hold journalled filesystem for this journal.
+  *  @start: Block nr Start of journal.
+  *  @len:  Lenght of the journal in blocks.
+  *  @blocksize: blocksize of journalling device
+  *  @returns: a newly created journal_t *
+  *  
+  *  journal_init_dev creates a journal which maps a fixed contiguous
+  *  range of blocks on an arbitrary block device.
+  * 
+  */
 journal_t * journal_init_dev(kdev_t dev, kdev_t fs_dev,
 			int start, int len, int blocksize)
 {
@@ -760,7 +767,15 @@
 
 	return journal;
 }
-
+ 
+/** 
+ *  journal_t * journal_init_inode () - creates a journal which maps to a inode.
+ *  @inode: An inode to create the journal in
+ *  
+ * journal_init_inode creates a journal which maps an on-disk inode as
+ * the journal.  The inode must exist already, must support bmap() and
+ * must have all data blocks preallocated.
+ */
 journal_t * journal_init_inode (struct inode *inode)
 {
 	struct buffer_head *bh;
@@ -850,12 +865,15 @@
 	return 0;
 }
 
-/*
+/** 
+ * int journal_create() - Initialise the new journal file
+ * @journal: Journal to create. This structure must have been initialised
+ * 
  * Given a journal_t structure which tells us which disk blocks we can
  * use, create a new journal superblock and initialise all of the
- * journal fields from scratch.  */
-
-int journal_create (journal_t *journal)
+ * journal fields from scratch.  
+ **/
+int journal_create(journal_t *journal)
 {
 	unsigned long blocknr;
 	struct buffer_head *bh;
@@ -916,11 +934,14 @@
 	return journal_reset(journal);
 }
 
-/*
+/** 
+ * void journal_update_superblock() - Update journal sb on disk.
+ * @journal: The journal to update.
+ * @wait: Set to '0' if you don't want to wait for IO completion.
+ *
  * Update a journal's dynamic superblock fields and write it to disk,
  * optionally waiting for the IO to complete.
-*/
-
+ */
 void journal_update_superblock(journal_t *journal, int wait)
 {
 	journal_superblock_t *sb = journal->j_superblock;
@@ -1036,12 +1057,14 @@
 }
 
 
-/*
+/**
+ * int journal_load() - Read journal from disk.
+ * @journal: Journal to act on.
+ * 
  * Given a journal_t structure which tells us which disk blocks contain
  * a journal, read the journal from disk to initialise the in-memory
  * structures.
  */
-
 int journal_load(journal_t *journal)
 {
 	int err;
@@ -1086,11 +1109,13 @@
 	return -EIO;
 }
 
-/*
+/**
+ * void journal_destroy() - Release a journal_t structure.
+ * @journal: Journal to act on.
+* 
  * Release a journal_t structure once it is no longer in use by the
  * journaled object.
  */
-
 void journal_destroy (journal_t *journal)
 {
 	/* Wait for the commit thread to wake up and die. */
@@ -1128,8 +1153,12 @@
 }
 
 
-/* Published API: Check whether the journal uses all of a given set of
- * features.  Return true (non-zero) if it does. */
+/**
+ *int journal_check_used_features () - Check if features specified are used.
+ * 
+ * Check whether the journal uses all of a given set of
+ * features.  Return true (non-zero) if it does. 
+ **/
 
 int journal_check_used_features (journal_t *journal, unsigned long compat,
 				 unsigned long ro, unsigned long incompat)
@@ -1151,7 +1180,10 @@
 	return 0;
 }
 
-/* Published API: Check whether the journaling code supports the use of
+/**
+ * int journal_check_available_features() - Check feature set in journalling layer
+ * 
+ * Check whether the journaling code supports the use of
  * all of a given set of features on this journal.  Return true
  * (non-zero) if it can. */
 
@@ -1180,8 +1212,13 @@
 	return 0;
 }
 
-/* Published API: Mark a given journal feature as present on the
- * superblock.  Returns true if the requested features could be set. */
+/**
+ * int journal_set_features () - Mark a given journal feature in the superblock
+ *
+ * Mark a given journal feature as present on the
+ * superblock.  Returns true if the requested features could be set. 
+ *
+ */
 
 int journal_set_features (journal_t *journal, unsigned long compat,
 			  unsigned long ro, unsigned long incompat)
@@ -1207,12 +1244,12 @@
 }
 
 
-/*
- * Published API:
+/**
+ * int journal_update_format () - Update on-disk journal structure.
+ *
  * Given an initialised but unloaded journal struct, poke about in the
  * on-disk structure to update it to the most recent supported version.
  */
-
 int journal_update_format (journal_t *journal)
 {
 	journal_superblock_t *sb;
@@ -1262,7 +1299,10 @@
 }
 
 
-/*
+/**
+ * int journal_flush () - Flush journal
+ * @journal: Journal to act on.
+ * 
  * Flush all data for a given journal to disk and empty the journal.
  * Filesystems can use this when remounting readonly to ensure that
  * recovery does not need to happen on remount.
@@ -1316,12 +1356,16 @@
 	return err;
 }
 
-/*
+/**
+ * int journal_wipe() - Wipe journal contents
+ * @journal: Journal to act on.
+ * @write: flag (see below)
+ * 
  * Wipe out all of the contents of a journal, safely.  This will produce
  * a warning if the journal contains any valid recovery information.
  * Must be called between journal_init_*() and journal_load().
  *
- * If (write) is non-zero, then we wipe out the journal on disk; otherwise
+ * If 'write' is non-zero, then we wipe out the journal on disk; otherwise
  * we merely suppress recovery.
  */
 
@@ -1370,43 +1414,11 @@
 }
 
 /*
- * journal_abort: perform a complete, immediate shutdown of the ENTIRE
- * journal (not of a single transaction).  This operation cannot be
- * undone without closing and reopening the journal.
- *
- * The journal_abort function is intended to support higher level error
- * recovery mechanisms such as the ext2/ext3 remount-readonly error
- * mode.
- *
- * Journal abort has very specific semantics.  Any existing dirty,
- * unjournaled buffers in the main filesystem will still be written to
- * disk by bdflush, but the journaling mechanism will be suspended
- * immediately and no further transaction commits will be honoured.
+ * Journal abort has very specific semantics, which we describe
+ * for journal abort. 
  *
- * Any dirty, journaled buffers will be written back to disk without
- * hitting the journal.  Atomicity cannot be guaranteed on an aborted
- * filesystem, but we _do_ attempt to leave as much data as possible
- * behind for fsck to use for cleanup.
- *
- * Any attempt to get a new transaction handle on a journal which is in
- * ABORT state will just result in an -EROFS error return.  A
- * journal_stop on an existing handle will return -EIO if we have
- * entered abort state during the update.
- *
- * Recursive transactions are not disturbed by journal abort until the
- * final journal_stop, which will receive the -EIO error.
- *
- * Finally, the journal_abort call allows the caller to supply an errno
- * which will be recored (if possible) in the journal superblock.  This
- * allows a client to record failure conditions in the middle of a
- * transaction without having to complete the transaction to record the
- * failure to disk.  ext3_error, for example, now uses this
- * functionality.
- *
- * Errors which originate from within the journaling layer will NOT
- * supply an errno; a null errno implies that absolutely no further
- * writes are done to the journal (unless there are any already in
- * progress).
+ * Two internal function, which provide abort to te jbd layer
+ * itself are here.
  */
 
 /* Quick version for internal journal use (doesn't lock the journal).
@@ -1444,7 +1456,52 @@
 		journal_update_superblock(journal, 1);
 }
 
-/* Full version for external use */
+/**
+ * void journal_abort () - Shutdown the journal immediately.
+ * @journal: the journal to shutdown.
+ * @errno:   an error number to record in the journal indicating
+ *           the reason for the shutdown.
+ *
+ * Perform a complete, immediate shutdown of the ENTIRE
+ * journal (not of a single transaction).  This operation cannot be
+ * undone without closing and reopening the journal.
+ *           
+ * The journal_abort function is intended to support higher level error
+ * recovery mechanisms such as the ext2/ext3 remount-readonly error
+ * mode.
+ *
+ * Journal abort has very specific semantics.  Any existing dirty,
+ * unjournaled buffers in the main filesystem will still be written to
+ * disk by bdflush, but the journaling mechanism will be suspended
+ * immediately and no further transaction commits will be honoured.
+ *
+ * Any dirty, journaled buffers will be written back to disk without
+ * hitting the journal.  Atomicity cannot be guaranteed on an aborted
+ * filesystem, but we _do_ attempt to leave as much data as possible
+ * behind for fsck to use for cleanup.
+ *
+ * Any attempt to get a new transaction handle on a journal which is in
+ * ABORT state will just result in an -EROFS error return.  A
+ * journal_stop on an existing handle will return -EIO if we have
+ * entered abort state during the update.
+ *
+ * Recursive transactions are not disturbed by journal abort until the
+ * final journal_stop, which will receive the -EIO error.
+ *
+ * Finally, the journal_abort call allows the caller to supply an errno
+ * which will be recorded (if possible) in the journal superblock.  This
+ * allows a client to record failure conditions in the middle of a
+ * transaction without having to complete the transaction to record the
+ * failure to disk.  ext3_error, for example, now uses this
+ * functionality.
+ *
+ * Errors which originate from within the journaling layer will NOT
+ * supply an errno; a null errno implies that absolutely no further
+ * writes are done to the journal (unless there are any already in
+ * progress).
+ * 
+ */
+
 void journal_abort (journal_t *journal, int errno)
 {
 	lock_journal(journal);
@@ -1452,6 +1509,17 @@
 	unlock_journal(journal);
 }
 
+/** 
+ * int journal_errno () - returns the journal's error state.
+ * @journal: journal to examine.
+ *
+ * This is the errno numbet set with journal_abort(), the last
+ * time the journal was mounted - if the journal was stopped
+ * without calling abort this will be 0.
+ *
+ * If the journal has been aborted on this mount time -EROFS will
+ * be returned.
+ */
 int journal_errno (journal_t *journal)
 {
 	int err;
@@ -1465,6 +1533,14 @@
 	return err;
 }
 
+
+
+/** 
+ * int journal_clear_err () - clears the journal's error state
+ *
+ * An error must be cleared or Acked to take a FS out of readonly
+ * mode.
+ */
 int journal_clear_err (journal_t *journal)
 {
 	int err = 0;
@@ -1478,6 +1554,13 @@
 	return err;
 }
 
+
+/** 
+ * void journal_ack_err() - Ack journal err.
+ *
+ * An error must be cleared or Acked to take a FS out of readonly
+ * mode.
+ */
 void journal_ack_err (journal_t *journal)
 {
 	lock_journal(journal);
@@ -1664,8 +1747,8 @@
  *
  * Whenever a buffer has an attached journal_head, its ->b_state:BH_JBD bit
  * is set.  This bit is tested in core kernel code where we need to take
- * JBD-specific actions.  Testing the zeroness of ->b_private is not reliable
- * there.
+ * JBD-specific actions.  Testing the zeroness of ->b_journal_head is not
+ * reliable there.
  *
  * When a buffer has its BH_JBD bit set, its ->b_count is elevated by one.
  *
@@ -1720,9 +1803,9 @@
 
 		if (buffer_jbd(bh)) {
 			/* Someone did it for us! */
-			J_ASSERT_BH(bh, bh->b_private != NULL);
+			J_ASSERT_BH(bh, bh->b_journal_head != NULL);
 			journal_free_journal_head(jh);
-			jh = bh->b_private;
+			jh = bh->b_journal_head;
 		} else {
 			/*
 			 * We actually don't need jh_splice_lock when
@@ -1730,7 +1813,7 @@
 			 */
 			spin_lock(&jh_splice_lock);
 			set_bit(BH_JBD, &bh->b_state);
-			bh->b_private = jh;
+			bh->b_journal_head = jh;
 			jh->b_bh = bh;
 			atomic_inc(&bh->b_count);
 			spin_unlock(&jh_splice_lock);
@@ -1739,7 +1822,7 @@
 	}
 	jh->b_jcount++;
 	spin_unlock(&journal_datalist_lock);
-	return bh->b_private;
+	return bh->b_journal_head;
 }
 
 /*
@@ -1772,7 +1855,7 @@
 			J_ASSERT_BH(bh, jh2bh(jh) == bh);
 			BUFFER_TRACE(bh, "remove journal_head");
 			spin_lock(&jh_splice_lock);
-			bh->b_private = NULL;
+			bh->b_journal_head = NULL;
 			jh->b_bh = NULL;	/* debug, really */
 			clear_bit(BH_JBD, &bh->b_state);
 			__brelse(bh);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/jbd/recovery.c linux.20pre10-ac2/fs/jbd/recovery.c
--- linux.20pre10/fs/jbd/recovery.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/jbd/recovery.c	2002-09-29 20:24:36.000000000 +0100
@@ -207,20 +207,22 @@
 		var -= ((journal)->j_last - (journal)->j_first);	\
 } while (0)
 
-/*
- * journal_recover
- *
+/**
+ * int journal_recover(journal_t *journal) - recovers a on-disk journal
+ * @journal: the journal to recover
+ * 
  * The primary function for recovering the log contents when mounting a
  * journaled device.  
- * 
+ */
+int journal_recover(journal_t *journal)
+{
+/*
  * Recovery is done in three passes.  In the first pass, we look for the
  * end of the log.  In the second, we assemble the list of revoke
  * blocks.  In the third and final pass, we replay any un-revoked blocks
  * in the log.  
  */
 
-int journal_recover(journal_t *journal)
-{
 	int			err;
 	journal_superblock_t *	sb;
 
@@ -264,20 +266,23 @@
 	return err;
 }
 
-/*
- * journal_skip_recovery
- *
+/**
+ * int journal_skip_recovery() - Start journal and wipe exiting records 
+ * @journal: journal to startup
+ * 
  * Locate any valid recovery information from the journal and set up the
  * journal structures in memory to ignore it (presumably because the
  * caller has evidence that it is out of date).  
- *
+ * This function does'nt appear to be exorted..
+ */
+int journal_skip_recovery(journal_t *journal)
+{
+/*
  * We perform one pass over the journal to allow us to tell the user how
  * much recovery information is being erased, and to let us initialise
  * the journal transaction sequence numbers to the next unused ID. 
  */
 
-int journal_skip_recovery(journal_t *journal)
-{
 	int			err;
 	journal_superblock_t *	sb;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/jbd/transaction.c linux.20pre10-ac2/fs/jbd/transaction.c
--- linux.20pre10/fs/jbd/transaction.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/jbd/transaction.c	2002-09-29 20:24:41.000000000 +0100
@@ -223,19 +223,20 @@
 	return handle;
 }
 
-/*
- * Obtain a new handle.  
+/**
+ * handle_t *journal_start() - Obtain a new handle.  
+ * @journal: Journal to start transaction on.
+ * @nblocks: number of block buffer we might modify
  *
  * We make sure that the transaction can guarantee at least nblocks of
  * modified buffers in the log.  We block until the log can guarantee
  * that much space.  
  *
- * This function is visible to journal users (like ext2fs), so is not
+ * This function is visible to journal users (like ext3fs), so is not
  * called with the journal already locked.
  *
  * Return a pointer to a newly allocated handle, or NULL on failure
  */
-
 handle_t *journal_start(journal_t *journal, int nblocks)
 {
 	handle_t *handle = journal_current_handle();
@@ -325,7 +326,11 @@
 	return ret;
 }
 
-/*
+/**
+ * handle_t *journal_try_start() - Don't block, but try and get a handle
+ * @journal: Journal to start transaction on.
+ * @nblocks: number of block buffer we might modify
+ * 
  * Try to start a handle, but non-blockingly.  If we weren't able
  * to, return an ERR_PTR value.
  */
@@ -369,16 +374,18 @@
 	return handle;
 }
 
-/*
- * journal_extend: extend buffer credits.
- *
+/**
+ * int journal_extend() - extend buffer credits.
+ * @handle:  handle to 'extend'
+ * @nblocks: nr blocks to try to extend by.
+ * 
  * Some transactions, such as large extends and truncates, can be done
  * atomically all at once or in several stages.  The operation requests
  * a credit for a number of buffer modications in advance, but can
  * extend its credit if it needs more.  
  *
  * journal_extend tries to give the running handle more buffer credits.
- * It does not guarantee that allocation: this is a best-effort only.
+ * It does not guarantee that allocation - this is a best-effort only.
  * The calling process MUST be able to deal cleanly with a failure to
  * extend here.
  *
@@ -387,7 +394,6 @@
  * return code < 0 implies an error
  * return code > 0 implies normal transaction-full status.
  */
-
 int journal_extend (handle_t *handle, int nblocks)
 {
 	transaction_t *transaction = handle->h_transaction;
@@ -436,8 +442,12 @@
 }
 
 
-/*
- * journal_restart: restart a handle for a multi-transaction filesystem
+/**
+ * int journal_restart() - restart a handle .
+ * @handle:  handle to restart
+ * @nblocks: nr credits requested
+ * 
+ * Restart a handle for a multi-transaction filesystem
  * operation.
  *
  * If the journal_extend() call above fails to grant new buffer credits
@@ -479,8 +489,9 @@
 }
 
 
-/* 
- * Barrier operation: establish a transaction barrier. 
+/**
+ * void journal_lock_updates () - establish a transaction barrier.
+ * @journal:  Journal to establish a barrier on.
  *
  * This locks out any further updates from being started, and blocks
  * until all existing updates have completed, returning only once the
@@ -488,7 +499,6 @@
  *
  * The journal lock should not be held on entry.
  */
-
 void journal_lock_updates (journal_t *journal)
 {
 	lock_journal(journal);
@@ -516,12 +526,14 @@
 	down(&journal->j_barrier);
 }
 
-/*
+/**
+ * void journal_unlock_updates (journal_t* journal) - release barrier
+ * @journal:  Journal to release the barrier on.
+ * 
  * Release a transaction barrier obtained with journal_lock_updates().
  *
  * Should be called without the journal lock held.
  */
-
 void journal_unlock_updates (journal_t *journal)
 {
 	lock_journal(journal);
@@ -535,23 +547,14 @@
 }
 
 /*
- * journal_get_write_access: notify intent to modify a buffer for metadata
- * (not data) update.
- *
- * If the buffer is already part of the current transaction, then there
- * is nothing we need to do.  If it is already part of a prior
+ * if the buffer is already part of the current transaction, then there
+ * is nothing we need to do.  if it is already part of a prior
  * transaction which we are still committing to disk, then we need to
  * make sure that we do not overwrite the old copy: we do copy-out to
- * preserve the copy going to disk.  We also account the buffer against
+ * preserve the copy going to disk.  we also account the buffer against
  * the handle's metadata buffer credits (unless the buffer is already
  * part of the transaction, that is).
- *
- * Returns an error code or 0 on success.
- *
- * In full data journalling mode the buffer may be of type BJ_AsyncData,
- * because we're write()ing a buffer which is also part of a shared mapping.
  */
-
 static int
 do_get_write_access(handle_t *handle, struct journal_head *jh, int force_copy) 
 {
@@ -756,6 +759,17 @@
 	return error;
 }
 
+/**
+ * int journal_get_write_access() - notify intent to modify a buffer for metadata (not data) update.
+ * @handle: transaction to add buffer modifications to
+ * @bh:     bh to be used for metadata writes
+ *
+ * Returns an error code or 0 on success.
+ *
+ * In full data journalling mode the buffer may be of type BJ_AsyncData,
+ * because we're write()ing a buffer which is also part of a shared mapping.
+ */
+
 int journal_get_write_access (handle_t *handle, struct buffer_head *bh) 
 {
 	transaction_t *transaction = handle->h_transaction;
@@ -786,6 +800,13 @@
  * There is no lock ranking violation: it was a newly created,
  * unlocked buffer beforehand. */
 
+/**
+ * int journal_get_create_access () - notify intent to use newly created bh
+ * @handle: ransaction to new buffer to
+ * @bh: new buffer.
+ *
+ * Call this if you create a new bh.
+ */
 int journal_get_create_access (handle_t *handle, struct buffer_head *bh) 
 {
 	transaction_t *transaction = handle->h_transaction;
@@ -847,13 +868,14 @@
 
 
 
-/*
- * journal_get_undo_access: Notify intent to modify metadata with non-
- * rewindable consequences
- *
+/**
+ * int journal_get_undo_access() -  Notify intent to modify metadata with non-rewindable consequences
+ * @handle: transaction
+ * @bh: buffer to undo
+ * 
  * Sometimes there is a need to distinguish between metadata which has
  * been committed to disk and that which has not.  The ext3fs code uses
- * this for freeing and allocating space: we have to make sure that we
+ * this for freeing and allocating space, we have to make sure that we
  * do not reuse freed space until the deallocation has been committed,
  * since if we overwrote that space we would make the delete
  * un-rewindable in case of a crash.
@@ -865,13 +887,12 @@
  * as we know that the buffer has definitely been committed to disk.
  * 
  * We never need to know which transaction the committed data is part
- * of: buffers touched here are guaranteed to be dirtied later and so
+ * of, buffers touched here are guaranteed to be dirtied later and so
  * will be committed to a new transaction in due course, at which point
  * we can discard the old committed data pointer.
  *
  * Returns error number or 0 on success.  
  */
-
 int journal_get_undo_access (handle_t *handle, struct buffer_head *bh)
 {
 	journal_t *journal = handle->h_transaction->t_journal;
@@ -913,10 +934,12 @@
 	return err;
 }
 
-/* 
- * journal_dirty_data: mark a buffer as containing dirty data which
- * needs to be flushed before we can commit the current transaction.  
- *
+/** 
+ * int journal_dirty_data() -  mark a buffer as containing dirty data which needs to be flushed before we can commit the current transaction.  
+ * @handle: transaction
+ * @bh: bufferhead to mark
+ * @async: flag
+ * 
  * The buffer is placed on the transaction's data list and is marked as
  * belonging to the transaction.
  *
@@ -925,7 +948,10 @@
  * t_async_datalist.
  * 
  * Returns error number or 0 on success.  
- *
+ */
+int journal_dirty_data (handle_t *handle, struct buffer_head *bh, int async)
+{
+/*
  * journal_dirty_data() can be called via page_launder->ext3_writepage
  * by kswapd.  So it cannot block.  Happily, there's nothing here
  * which needs lock_journal if `async' is set.
@@ -934,9 +960,6 @@
  * between BJ_AsyncData and BJ_SyncData according to who tried to
  * change its state last.
  */
-
-int journal_dirty_data (handle_t *handle, struct buffer_head *bh, int async)
-{
 	journal_t *journal = handle->h_transaction->t_journal;
 	int need_brelse = 0;
 	int wanted_jlist = async ? BJ_AsyncData : BJ_SyncData;
@@ -1079,24 +1102,28 @@
 	return 0;
 }
 
-/* 
- * journal_dirty_metadata: mark a buffer as containing dirty metadata
- * which needs to be journaled as part of the current transaction.
+/** 
+ * int journal_dirty_metadata() -  mark a buffer as containing dirty metadata
+ * @handle: transaction to add buffer to.
+ * @bh: buffer to mark 
+ * 
+ * mark dirty metadata which needs to be journaled as part of the current transaction.
  *
  * The buffer is placed on the transaction's metadata list and is marked
  * as belonging to the transaction.  
  *
+ * Returns error number or 0 on success.  
+ */
+int journal_dirty_metadata (handle_t *handle, struct buffer_head *bh)
+{
+/*
  * Special care needs to be taken if the buffer already belongs to the
  * current committing transaction (in which case we should have frozen
  * data present for that commit).  In that case, we don't relink the
  * buffer: that only gets done when the old transaction finally
  * completes its commit.
  * 
- * Returns error number or 0 on success.  
  */
-
-int journal_dirty_metadata (handle_t *handle, struct buffer_head *bh)
-{
 	transaction_t *transaction = handle->h_transaction;
 	journal_t *journal = transaction->t_journal;
 	struct journal_head *jh = bh2jh(bh);
@@ -1182,9 +1209,12 @@
 }
 #endif
 
-/* 
- * journal_forget: bforget() for potentially-journaled buffers.  We can
- * only do the bforget if there are no commits pending against the
+/** 
+ * void journal_forget() - bforget() for potentially-journaled buffers.
+ * @handle: transaction handle
+ * @bh:     bh to 'forget'
+ *
+ * We can only do the bforget if there are no commits pending against the
  * buffer.  If the buffer is dirty in the current running transaction we
  * can safely unlink it. 
  *
@@ -1196,7 +1226,6 @@
  * Allow this call even if the handle has aborted --- it may be part of
  * the caller's cleanup after an abort.
  */
-
 void journal_forget (handle_t *handle, struct buffer_head *bh)
 {
 	transaction_t *transaction = handle->h_transaction;
@@ -1357,7 +1386,10 @@
 	jcb->jcb_func = func;
 }
 
-/*
+/**
+ * int journal_stop() - complete a transaction
+ * @handle: tranaction to complete.
+ * 
  * All done for a particular handle.
  *
  * There is not much action needed here.  We just return any remaining
@@ -1370,7 +1402,6 @@
  * return -EIO if a journal_abort has been executed since the
  * transaction began.
  */
-
 int journal_stop(handle_t *handle)
 {
 	transaction_t *transaction = handle->h_transaction;
@@ -1408,6 +1439,7 @@
 	if (handle->h_sync) {
 		do {
 			old_handle_count = transaction->t_handle_count;
+			set_current_state(TASK_RUNNING);
 			yield();
 		} while (old_handle_count != transaction->t_handle_count);
 	}
@@ -1455,8 +1487,10 @@
 	return err;
 }
 
-/*
- * For synchronous operations: force any uncommitted trasnactions
+/**int journal_force_commit() - force any uncommitted transactions
+ * @journal: journal to force
+ *
+ * For synchronous operations: force any uncommitted transactions
  * to disk.  May seem kludgy, but it reuses all the handle batching
  * code in a very simple manner.
  */
@@ -1660,6 +1694,26 @@
 	return 0;
 }
 
+
+/** 
+ * int journal_try_to_free_buffers() - try to free page buffers.
+ * @journal: journal for operation
+ * @page: to try and free
+ * @gfp_mask: 'IO' mode for try_to_free_buffers()
+ *
+ * 
+ * For all the buffers on this page,
+ * if they are fully written out ordered data, move them onto BUF_CLEAN
+ * so try_to_free_buffers() can reap them.
+ * 
+ * This function returns non-zero if we wish try_to_free_buffers()
+ * to be called. We do this if the page is releasable by try_to_free_buffers().
+ * We also do it if the page has locked or dirty buffers and the caller wants
+ * us to perform sync or async writeout.
+ */
+int journal_try_to_free_buffers(journal_t *journal, 
+				struct page *page, int gfp_mask)
+{
 /*
  * journal_try_to_free_buffers().  For all the buffers on this page,
  * if they are fully written out ordered data, move them onto BUF_CLEAN
@@ -1684,14 +1738,7 @@
  * cannot happen because we never reallocate freed data as metadata
  * while the data is part of a transaction.  Yes?
  *
- * This function returns non-zero if we wish try_to_free_buffers()
- * to be called. We do this is the page is releasable by try_to_free_buffers().
- * We also do it if the page has locked or dirty buffers and the caller wants
- * us to perform sync or async writeout.
  */
-int journal_try_to_free_buffers(journal_t *journal, 
-				struct page *page, int gfp_mask)
-{
 	struct buffer_head *bh;
 	struct buffer_head *tmp;
 	int locked_or_dirty = 0;
@@ -1903,8 +1950,15 @@
 	return may_free;
 }
 
-/*
- * Return non-zero if the page's buffers were successfully reaped
+/** 
+ * int journal_flushpage() 
+ * @journal: journal to use for flush... 
+ * @page:    page to flush
+ * @offset:  length of page to flush.
+ *
+ * Reap page buffers containing data after offset in page.
+ *
+ * Return non-zero if the page's buffers were successfully reaped.
  */
 int journal_flushpage(journal_t *journal, 
 		      struct page *page, 
@@ -1944,8 +1998,17 @@
 	unlock_journal(journal);
 
 	if (!offset) {
-		if (!may_free || !try_to_free_buffers(page, 0))
+		if (!may_free || !try_to_free_buffers(page, 0)) {
+			if (!offset) {
+				/* We are still using the page, but only
+                                   because a transaction is pinning the
+                                   page.  Once it commits, we want to
+                                   encourage the page to be reaped as
+                                   quickly as possible. */
+				ClearPageReferenced(page);
+			}
 			return 0;
+		}
 		J_ASSERT(page->buffers == NULL);
 	}
 	return 1;
@@ -1976,6 +2039,10 @@
 	 * with __jbd_unexpected_dirty_buffer()'s handling of dirty
 	 * state. */
 
+	/* The following list of buffer states needs to be consistent
+	 * with __jbd_unexpected_dirty_buffer()'s handling of dirty
+	 * state. */
+
 	if (jlist == BJ_Metadata || jlist == BJ_Reserved || 
 	    jlist == BJ_Shadow || jlist == BJ_Forget) {
 		if (atomic_set_buffer_clean(jh2bh(jh)) ||
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/jffs2/background.c linux.20pre10-ac2/fs/jffs2/background.c
--- linux.20pre10/fs/jffs2/background.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/jffs2/background.c	2002-08-06 15:41:51.000000000 +0100
@@ -106,9 +106,6 @@
 
         sprintf(current->comm, "jffs2_gcd_mtd%d", c->mtd->index);
 
-	/* FIXME in the 2.2 backport */
-	current->nice = 10;
-
 	for (;;) {
 		spin_lock_irq(&current->sigmask_lock);
 		siginitsetinv (&current->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/jfs/inode.c linux.20pre10-ac2/fs/jfs/inode.c
--- linux.20pre10/fs/jfs/inode.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/jfs/inode.c	2002-10-11 00:22:21.000000000 +0100
@@ -323,9 +323,10 @@
 	return generic_block_bmap(mapping, block, jfs_get_block);
 }
 
-static int jfs_direct_IO(int rw, struct inode *inode, struct kiobuf *iobuf,
+static int jfs_direct_IO(int rw, struct file *filp, struct kiobuf *iobuf,
 			 unsigned long blocknr, int blocksize)
 {
+	struct inode * inode = filp->f_dentry->d_inode->i_mapping->host;
 	return generic_direct_IO(rw, inode, iobuf, blocknr,
 				 blocksize, jfs_get_block);
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/lockd/svclock.c linux.20pre10-ac2/fs/lockd/svclock.c
--- linux.20pre10/fs/lockd/svclock.c	2002-10-09 21:36:35.000000000 +0100
+++ linux.20pre10-ac2/fs/lockd/svclock.c	2002-08-06 15:41:51.000000000 +0100
@@ -62,8 +62,8 @@
 		nlmsvc_remove_block(block);
 	bp = &nlm_blocked;
 	if (when != NLM_NEVER) {
-		if ((when += jiffies) == NLM_NEVER)
-			when ++;
+		if ((when += jiffies) > NLM_NEVER)
+			when = NLM_NEVER;
 		while ((b = *bp) && time_before_eq(b->b_when,when))
 			bp = &b->b_next;
 	} else
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/lockd/svcproc.c linux.20pre10-ac2/fs/lockd/svcproc.c
--- linux.20pre10/fs/lockd/svcproc.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/lockd/svcproc.c	2002-08-06 15:41:51.000000000 +0100
@@ -345,6 +345,15 @@
 	return stat;
 }
 
+static int
+nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp,
+						void           *resp)
+{
+	dprintk("lockd: GRANTED_RES   called\n");
+	nlmsvc_grant_reply(&argp->cookie, argp->status);
+	return 0;
+}
+
 /*
  * SHARE: create a DOS share or alter existing share.
  */
@@ -545,14 +554,12 @@
 #define nlmsvc_decode_lockres	nlmsvc_decode_void
 #define nlmsvc_decode_unlockres	nlmsvc_decode_void
 #define nlmsvc_decode_cancelres	nlmsvc_decode_void
-#define nlmsvc_decode_grantedres	nlmsvc_decode_void
 
 #define nlmsvc_proc_none	nlmsvc_proc_null
 #define nlmsvc_proc_test_res	nlmsvc_proc_null
 #define nlmsvc_proc_lock_res	nlmsvc_proc_null
 #define nlmsvc_proc_cancel_res	nlmsvc_proc_null
 #define nlmsvc_proc_unlock_res	nlmsvc_proc_null
-#define nlmsvc_proc_granted_res	nlmsvc_proc_null
 
 struct nlm_void			{ int dummy; };
 
@@ -589,7 +596,7 @@
   PROC(lock_res,	lockres,	norep,		res,	void, 1),
   PROC(cancel_res,	cancelres,	norep,		res,	void, 1),
   PROC(unlock_res,	unlockres,	norep,		res,	void, 1),
-  PROC(granted_res,	grantedres,	norep,		res,	void, 1),
+  PROC(granted_res,	res,		norep,		res,	void, 1),
   /* statd callback */
   PROC(sm_notify,	reboot,		void,		reboot,	void, 1),
   PROC(none,		void,		void,		void,	void, 1),
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/locks.c linux.20pre10-ac2/fs/locks.c
--- linux.20pre10/fs/locks.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/locks.c	2002-08-25 16:00:46.000000000 +0100
@@ -274,9 +274,18 @@
 		return -EINVAL;
 	}
 
-	if (((start += l->l_start) < 0) || (l->l_len < 0))
+	/* POSIX-1996 leaves the case l->l_len < 0 undefined;
+	   POSIX-2001 defines it. */
+	start += l->l_start;
+	if (l->l_len < 0) {
+		end = start - 1;
+		start += l->l_len;
+	} else {
+		end = start + l->l_len - 1;
+	}
+
+	if (start < 0)
 		return -EINVAL;
-	end = start + l->l_len - 1;
 	if (l->l_len > 0 && end < 0)
 		return -EOVERFLOW;
 	fl->fl_start = start;	/* we record the absolute position */
@@ -926,8 +935,11 @@
 				goto next_lock;
 			/* If the next lock in the list has entirely bigger
 			 * addresses than the new one, insert the lock here.
+			 *
+			 * be careful if fl_end == OFFSET_MAX --okir
 			 */
-			if (fl->fl_start > caller->fl_end + 1)
+			if (fl->fl_start > caller->fl_end + 1
+			 && caller->fl_end != OFFSET_MAX)
 				break;
 
 			/* If we come here, the new and old lock are of the
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/Makefile linux.20pre10-ac2/fs/Makefile
--- linux.20pre10/fs/Makefile	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/Makefile	2002-09-14 22:01:44.000000000 +0100
@@ -7,20 +7,19 @@
 
 O_TARGET := fs.o
 
-export-objs :=	filesystems.o open.o dcache.o buffer.o
+export-objs :=	filesystems.o open.o dcache.o buffer.o dquot.o
 mod-subdirs :=	nls
 
 obj-y :=	open.o read_write.o devices.o file_table.o buffer.o \
 		super.o block_dev.o char_dev.o stat.o exec.o pipe.o namei.o \
 		fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \
 		dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \
-		filesystems.o namespace.o seq_file.o xattr.o
+		filesystems.o namespace.o seq_file.o quota.o xattr.o
 
-ifeq ($(CONFIG_QUOTA),y)
-obj-y += dquot.o
-else
-obj-y += noquot.o
-endif
+
+obj-$(CONFIG_QUOTA)		+= dquot.o
+obj-$(CONFIG_QFMT_V1)		+= quota_v1.o
+obj-$(CONFIG_QFMT_V2)		+= quota_v2.o
 
 subdir-$(CONFIG_PROC_FS)	+= proc
 subdir-y			+= partitions
@@ -71,6 +70,7 @@
 
 
 obj-$(CONFIG_BINFMT_AOUT)	+= binfmt_aout.o
+obj-$(CONFIG_BINFMT_SOM)	+= binfmt_som.o
 obj-$(CONFIG_BINFMT_EM86)	+= binfmt_em86.o
 obj-$(CONFIG_BINFMT_MISC)	+= binfmt_misc.o
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/namespace.c linux.20pre10-ac2/fs/namespace.c
--- linux.20pre10/fs/namespace.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/namespace.c	2002-08-29 23:09:34.000000000 +0100
@@ -1023,15 +1023,10 @@
 	if (!mnt_cache)
 		panic("Cannot create vfsmount cache");
 
-	mempages >>= (16 - PAGE_SHIFT);
-	mempages *= sizeof(struct list_head);
-	for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++)
-		;
-
-	do {
-		mount_hashtable = (struct list_head *)
-			__get_free_pages(GFP_ATOMIC, order);
-	} while (mount_hashtable == NULL && --order >= 0);
+	/* using single pointer list heads would save half of the hash table. */
+	order = 0; 
+	mount_hashtable = (struct list_head *)
+		__get_free_pages(GFP_ATOMIC, order);
 
 	if (!mount_hashtable)
 		panic("Failed to allocate mount hash table\n");
@@ -1055,8 +1050,9 @@
 	nr_hash = 1UL << hash_bits;
 	hash_mask = nr_hash-1;
 
-	printk("Mount-cache hash table entries: %d (order: %ld, %ld bytes)\n",
-			nr_hash, order, (PAGE_SIZE << order));
+	printk(KERN_INFO "Mount cache hash table entries: %d"
+		" (order: %ld, %ld bytes)\n",
+		nr_hash, order, (PAGE_SIZE << order));
 
 	/* And initialize the newly allocated array */
 	d = mount_hashtable;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/nfs/direct.c linux.20pre10-ac2/fs/nfs/direct.c
--- linux.20pre10/fs/nfs/direct.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/fs/nfs/direct.c	2002-10-11 00:22:21.000000000 +0100
@@ -0,0 +1,374 @@
+/*
+ * linux/fs/nfs/direct.c
+ *
+ * High-performance direct I/O for the NFS client
+ *
+ * When an application requests uncached I/O, all read and write requests
+ * are made directly to the server; data stored or fetched via these
+ * requests is not cached in the Linux page cache.  The client does not
+ * correct unaligned requests from applications.  All requested bytes are
+ * held on permanent storage before a direct write system call returns to
+ * an application.  Applications that manage their own data caching, such
+ * as databases, make very good use of direct I/O on local file systems.
+ *
+ * Solaris implements an uncached I/O facility called directio() that
+ * is used for backups and sequential I/O to very large files.  Solaris
+ * also supports uncaching whole NFS partitions with "-o forcedirectio,"
+ * an undocumented mount option.
+ *
+ * Note that I/O to read in executables (e.g. kernel_read) cannot use
+ * direct (kiobuf) reads because there is no vma backing the passed-in
+ * data buffer.
+ *
+ * Designed by Jeff Kimmel, Chuck Lever, and Trond Myklebust.
+ *
+ * Initial implementation:	12/2001 by Chuck Lever <cel@netapp.com>
+ *
+ * TODO:
+ *
+ * 1.  Use concurrent asynchronous network requests rather than
+ *     serialized synchronous network requests for normal (non-sync)
+ *     direct I/O.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/file.h>
+#include <linux/errno.h>
+#include <linux/nfs_fs.h>
+#include <linux/smp_lock.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/iobuf.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#define NFSDBG_FACILITY		(NFSDBG_PAGECACHE | NFSDBG_VFS)
+#define VERF_SIZE		(2 * sizeof(__u32))
+
+static /* inline */ int
+nfs_direct_read_rpc(struct file *file, struct nfs_readargs *arg)
+{
+	int result;
+	struct inode * inode = file->f_dentry->d_inode;
+	struct nfs_fattr fattr;
+        struct rpc_message msg;
+        struct nfs_readres res = { &fattr, arg->count, 0 };
+
+#ifdef CONFIG_NFS_V3
+	msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ?
+						NFS3PROC_READ : NFSPROC_READ;
+#else
+	msg.rpc_proc = NFSPROC_READ;
+#endif
+	msg.rpc_argp = arg;
+        msg.rpc_resp = &res;
+
+	lock_kernel();
+        msg.rpc_cred = nfs_file_cred(file);
+        fattr.valid = 0;
+        result = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
+	nfs_refresh_inode(inode, &fattr);
+	unlock_kernel();
+
+	return result;
+}
+
+static /* inline */ int
+nfs_direct_write_rpc(struct file *file, struct nfs_writeargs *arg,
+	struct nfs_writeverf *verf)
+{
+	int result;
+	struct inode *inode = file->f_dentry->d_inode;
+	struct nfs_fattr fattr;
+        struct rpc_message msg;
+        struct nfs_writeres res = { &fattr, verf, 0 };
+
+#ifdef CONFIG_NFS_V3
+	msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ?
+						NFS3PROC_WRITE : NFSPROC_WRITE;
+#else
+	msg.rpc_proc = NFSPROC_WRITE;
+#endif
+	msg.rpc_argp = arg;
+        msg.rpc_resp = &res;
+
+	lock_kernel();
+	msg.rpc_cred = get_rpccred(nfs_file_cred(file));
+	fattr.valid = 0;
+        result = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
+	nfs_write_attributes(inode, &fattr);
+	put_rpccred(msg.rpc_cred);
+	unlock_kernel();
+
+#ifdef CONFIG_NFS_V3
+	if (NFS_PROTO(inode)->version == 3) {
+		if (result > 0) {
+			if ((arg->stable == NFS_FILE_SYNC) &&
+			    (verf->committed != NFS_FILE_SYNC)) {
+				printk(KERN_ERR __FUNCTION__
+				": server didn't sync stable write request\n");
+				return -EIO;
+			}
+
+			if (result != arg->count) {
+				printk(KERN_INFO __FUNCTION__
+					": short write, count=%u, result=%d\n",
+							arg->count, result);
+			}
+		}
+		return result;
+	} else {
+#endif
+        	verf->committed = NFS_FILE_SYNC; /* NFSv2 always syncs data */
+		if (result == 0)
+			return arg->count;
+		return result;
+#ifdef CONFIG_NFS_V3
+	}
+#endif
+}
+
+#ifdef CONFIG_NFS_V3
+static /* inline */ int
+nfs_direct_commit_rpc(struct inode *inode, loff_t offset, size_t count,
+	struct nfs_writeverf *verf)
+{
+	int result;
+	struct nfs_fattr fattr;
+	struct nfs_writeargs	arg = { NFS_FH(inode), offset, count, 0, 0,
+					NULL };
+	struct nfs_writeres	res = { &fattr, verf, 0 };
+	struct rpc_message	msg = { NFS3PROC_COMMIT, &arg, &res, NULL };
+
+	fattr.valid = 0;
+
+	lock_kernel();
+	result = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
+	nfs_write_attributes(inode, &fattr);
+	unlock_kernel();
+
+	return result;
+}
+#else
+static inline int
+nfs_direct_commit_rpc(struct inode *inode, loff_t offset, size_t count,
+	struct nfs_writeverf *verf)
+{
+	return 0;
+}
+#endif
+
+/*
+ * Walk through the iobuf and create an iovec for each "rsize" bytes.
+ */
+static int
+nfs_direct_read(struct file *file, struct kiobuf *iobuf, loff_t offset,
+	size_t count)
+{
+	int curpage, total;
+	struct inode *inode = file->f_dentry->d_inode;
+	int rsize = NFS_SERVER(inode)->rsize;
+	struct page **src = iobuf->maplist,
+		    **end = iobuf->maplist + iobuf->nr_pages;
+	struct page *pages[NFS_READ_MAXIOV];
+	struct nfs_readargs args = { NFS_FH(inode),
+				     offset,
+				     0,
+				     iobuf->offset,
+				     pages };
+
+	total = 0;
+	curpage = 0;
+        while (count) {
+		int request, result;
+		struct page **dst = pages;
+
+                request = count;
+                if (count > rsize)
+                        request = rsize;
+		args.count = request;
+
+		do {
+			if (!*src)
+				return -EFAULT;
+
+			*dst++ = *src;
+			/* zero after the first iov */
+			if (request < PAGE_SIZE)
+				break;
+			request -= PAGE_SIZE;
+			src++;
+		} while (request != 0 && src != end);
+
+                result = nfs_direct_read_rpc(file, &args);
+
+                if (result < 0) {
+			if (result == -EISDIR)
+				total = -EINVAL;
+			else
+                        	total = result;
+                        break;
+                }
+
+                total += result;
+                if (result < args.count)   /* NFSv2ism */
+                        break;
+                count -= result;
+		args.offset += result;
+		args.pgbase += result;
+	        args.pgbase &= ~PAGE_MASK;
+        };
+	return total;
+}
+
+/*
+ * Walk through the iobuf and create an iovec for each "wsize" bytes.
+ * If only one network write is necessary, or if the O_SYNC flag or
+ * 'sync' mount option are present, or if this is a V2 inode, use
+ * FILE_SYNC.  Otherwise, use UNSTABLE and finish with a COMMIT.
+ *
+ * The mechanics of this function are much the same as nfs_direct_read,
+ * with the added complexity of committing unstable writes.
+ */
+static int
+nfs_direct_write(struct file *file, struct kiobuf *iobuf,
+	loff_t offset, size_t count)
+{
+	int curpage, total;
+	int need_commit = 0;
+	loff_t save_offset = offset;
+	struct inode *inode = file->f_dentry->d_inode;
+	int wsize = NFS_SERVER(inode)->wsize;
+	struct nfs_writeverf first_verf, ret_verf;
+	struct page *pages[NFS_WRITE_MAXIOV];
+        struct nfs_writeargs args = { NFS_FH(inode), 0, 0, NFS_FILE_SYNC, 0, pages };
+
+#ifdef CONFIG_NFS_V3
+	if ((NFS_PROTO(inode)->version == 3) && (count > wsize) &&
+							(!IS_SYNC(inode)))
+		args.stable = NFS_UNSTABLE;
+#endif
+
+retry:
+	total = 0;
+	curpage = 0;
+        while (count) {
+		int request, result;
+		struct page **dest = pages;
+
+                request = count;
+                if (count > wsize)
+                        request = wsize;
+		args.count = request;
+		args.offset = offset;
+		args.pgbase = (iobuf->offset + total) & ~PAGE_MASK;
+
+		do {
+			struct page *page = iobuf->maplist[curpage];
+
+			if (!page)
+				return -EFAULT;
+
+			*dest++ = page;
+			/* zero after the first iov */
+			if (request > PAGE_SIZE)
+				break;
+			request -= PAGE_SIZE;
+			curpage++;
+		} while (request != 0 && curpage < iobuf->nr_pages);
+
+                result = nfs_direct_write_rpc(file, &args, &ret_verf);
+
+                if (result < 0) {
+                        total = result;
+                        break;
+                }
+
+		if (!total)
+			memcpy(&first_verf.verifier, &ret_verf.verifier,
+								VERF_SIZE);
+		if (ret_verf.committed != NFS_FILE_SYNC) {
+			need_commit = 1;
+			if (memcmp(&first_verf.verifier, &ret_verf.verifier,
+								VERF_SIZE))
+				goto print_retry;
+		}
+
+                total += result;
+                count -= result;
+                offset += result;
+        };
+
+	/*
+	 * Commit data written so far, even in the event of an error
+	 */
+	if (need_commit) {
+		if (nfs_direct_commit_rpc(inode, save_offset,
+					iobuf->length - count, &ret_verf))
+			goto print_retry;
+		if (memcmp(&first_verf.verifier, &ret_verf.verifier,
+								VERF_SIZE))
+			goto print_retry;
+	}
+
+	return total;
+
+print_retry:
+	printk(KERN_INFO __FUNCTION__
+		": detected server restart; retrying with FILE_SYNC\n");
+	args.stable = NFS_FILE_SYNC;
+	offset = save_offset;
+	count = iobuf->length;
+	goto retry;
+}
+
+/*
+ * Read or write data, moving the data directly to/from the
+ * application's buffer without caching in the page cache.
+ *
+ * Rules for direct I/O
+ *
+ * 1.  block size = 512 bytes or more
+ * 2.  file byte offset is block aligned
+ * 3.  byte count is a multiple of block size
+ * 4.  user buffer is not aligned
+ * 5.  user buffer is faulted in and pinned
+ *
+ * These are verified before we get here.
+ */
+int
+nfs_direct_IO(int rw, struct file *file, struct kiobuf *iobuf,
+	unsigned long blocknr, int blocksize)
+{
+	int result = -EINVAL;
+	size_t count = iobuf->length;
+	struct dentry *dentry = file->f_dentry;
+	struct inode *inode = dentry->d_inode;
+	loff_t offset = blocknr << inode->i_blkbits;
+
+	switch (rw) {
+	case READ:
+		dfprintk(VFS,
+			"NFS: direct_IO(READ) (%s/%s) off/cnt(%Lu/%d)\n",
+				dentry->d_parent->d_name.name,
+					dentry->d_name.name, offset, count);
+
+		result = nfs_direct_read(file, iobuf, offset, count);
+		break;
+	case WRITE:
+		dfprintk(VFS,
+			"NFS: direct_IO(WRITE) (%s/%s) off/cnt(%Lu/%d)\n",
+				dentry->d_parent->d_name.name,
+					dentry->d_name.name, offset, count);
+
+		result = nfs_direct_write(file, iobuf, offset, count);
+		break;
+	default:
+		break;
+	}
+
+	dfprintk(VFS, "NFS: direct_IO result = %d\n", result);
+	return result;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/nfs/file.c linux.20pre10-ac2/fs/nfs/file.c
--- linux.20pre10/fs/nfs/file.c	2002-10-09 21:36:35.000000000 +0100
+++ linux.20pre10-ac2/fs/nfs/file.c	2002-10-11 00:22:21.000000000 +0100
@@ -16,6 +16,7 @@
  *  nfs regular file handling functions
  */
 
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -199,6 +200,9 @@
 	sync_page: nfs_sync_page,
 	writepage: nfs_writepage,
 	prepare_write: nfs_prepare_write,
+#ifdef CONFIG_NFS_DIRECTIO
+	direct_IO: nfs_direct_IO,
+#endif
 	commit_write: nfs_commit_write
 };
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/nfs/Makefile linux.20pre10-ac2/fs/nfs/Makefile
--- linux.20pre10/fs/nfs/Makefile	2002-10-09 21:36:35.000000000 +0100
+++ linux.20pre10-ac2/fs/nfs/Makefile	2002-10-11 00:22:21.000000000 +0100
@@ -14,6 +14,7 @@
 
 obj-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o      
 obj-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o
+obj-$(CONFIG_NFS_DIRECTIO) += direct.o
 
 obj-m   := $(O_TARGET)
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/nfs/write.c linux.20pre10-ac2/fs/nfs/write.c
--- linux.20pre10/fs/nfs/write.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/nfs/write.c	2002-10-11 00:22:21.000000000 +0100
@@ -123,23 +123,6 @@
 }
 
 /*
- * This function will be used to simulate weak cache consistency
- * under NFSv2 when the NFSv3 attribute patch is included.
- * For the moment, we just call nfs_refresh_inode().
- */
-static __inline__ int
-nfs_write_attributes(struct inode *inode, struct nfs_fattr *fattr)
-{
-	if ((fattr->valid & NFS_ATTR_FATTR) && !(fattr->valid & NFS_ATTR_WCC)) {
-		fattr->pre_size  = NFS_CACHE_ISIZE(inode);
-		fattr->pre_mtime = NFS_CACHE_MTIME(inode);
-		fattr->pre_ctime = NFS_CACHE_CTIME(inode);
-		fattr->valid |= NFS_ATTR_WCC;
-	}
-	return nfs_refresh_inode(inode, fattr);
-}
-
-/*
  * Write a page synchronously.
  * Offset is the data offset within the page.
  */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/noquot.c linux.20pre10-ac2/fs/noquot.c
--- linux.20pre10/fs/noquot.c	2002-10-09 21:36:35.000000000 +0100
+++ linux.20pre10-ac2/fs/noquot.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,15 +0,0 @@
-/* noquot.c: Quota stubs necessary for when quotas are not
- *           compiled into the kernel.
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-
-int nr_dquots, nr_free_dquots;
-int max_dquots;
-
-asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
-{
-	return(-ENOSYS);
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/partitions/sun.c linux.20pre10-ac2/fs/partitions/sun.c
--- linux.20pre10/fs/partitions/sun.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/partitions/sun.c	2002-09-29 20:14:17.000000000 +0100
@@ -32,7 +32,7 @@
 	kdev_t dev = to_kdev_t(bdev->bd_dev);
 	struct sun_disklabel {
 		unsigned char info[128];   /* Informative text string */
-		unsigned char spare0[14];
+		unsigned char sparc0[14];
 		struct sun_info {
 			unsigned char spare1;
 			unsigned char id;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/proc/array.c linux.20pre10-ac2/fs/proc/array.c
--- linux.20pre10/fs/proc/array.c	2002-10-09 21:36:35.000000000 +0100
+++ linux.20pre10-ac2/fs/proc/array.c	2002-09-29 20:46:36.000000000 +0100
@@ -338,16 +338,15 @@
 
 	/* scale priority and nice values from timeslices to -20..20 */
 	/* to make it look like a "normal" Unix priority/nice value  */
-	priority = task->counter;
-	priority = 20 - (priority * 10 + DEF_COUNTER / 2) / DEF_COUNTER;
-	nice = task->nice;
+	priority = task_prio(task);
+	nice = task_nice(task);
 
 	read_lock(&tasklist_lock);
 	ppid = task->pid ? task->p_opptr->pid : 0;
 	read_unlock(&tasklist_lock);
 	res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
 %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
-%lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
+%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu\n",
 		task->pid,
 		task->comm,
 		state,
@@ -390,7 +389,9 @@
 		task->nswap,
 		task->cnswap,
 		task->exit_signal,
-		task->processor);
+		task_cpu(task),
+		task->rt_priority,
+		task->policy);
 	if(mm)
 		mmput(mm);
 	return res;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/proc/proc_misc.c linux.20pre10-ac2/fs/proc/proc_misc.c
--- linux.20pre10/fs/proc/proc_misc.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/proc/proc_misc.c	2002-08-13 14:43:44.000000000 +0100
@@ -36,6 +36,7 @@
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 #include <linux/seq_file.h>
+#include <linux/mm_inline.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -106,11 +107,11 @@
 	a = avenrun[0] + (FIXED_1/200);
 	b = avenrun[1] + (FIXED_1/200);
 	c = avenrun[2] + (FIXED_1/200);
-	len = sprintf(page,"%d.%02d %d.%02d %d.%02d %d/%d %d\n",
+	len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n",
 		LOAD_INT(a), LOAD_FRAC(a),
 		LOAD_INT(b), LOAD_FRAC(b),
 		LOAD_INT(c), LOAD_FRAC(c),
-		nr_running, nr_threads, last_pid);
+		nr_running(), nr_threads, last_pid);
 	return proc_calc_metrics(page, start, off, count, eof, len);
 }
 
@@ -122,7 +123,7 @@
 	int len;
 
 	uptime = jiffies;
-	idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime;
+	idle = init_task.times.tms_utime + init_task.times.tms_stime;
 
 	/* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
 	   that would overflow about every five days at HZ == 100.
@@ -155,7 +156,11 @@
 	struct sysinfo i;
 	int len;
 	int pg_size ;
+	int committed;
 
+	/* FIXME: needs to be in headers */
+	extern atomic_t vm_committed_space;
+	
 /*
  * display in kilobytes.
  */
@@ -164,6 +169,7 @@
 	si_meminfo(&i);
 	si_swapinfo(&i);
 	pg_size = atomic_read(&page_cache_size) - i.bufferram ;
+	committed = atomic_read(&vm_committed_space);
 
 	len = sprintf(page, "        total:    used:    free:  shared: buffers:  cached:\n"
 		"Mem:  %8Lu %8Lu %8Lu %8Lu %8Lu %8Lu\n"
@@ -185,13 +191,16 @@
 		"Cached:       %8lu kB\n"
 		"SwapCached:   %8lu kB\n"
 		"Active:       %8u kB\n"
-		"Inactive:     %8u kB\n"
+		"Inact_dirty:  %8u kB\n"
+		"Inact_clean:  %8u kB\n"
+		"Inact_target: %8u kB\n"
 		"HighTotal:    %8lu kB\n"
 		"HighFree:     %8lu kB\n"
 		"LowTotal:     %8lu kB\n"
 		"LowFree:      %8lu kB\n"
 		"SwapTotal:    %8lu kB\n"
-		"SwapFree:     %8lu kB\n",
+		"SwapFree:     %8lu kB\n"
+		"Committed_AS: %8u kB\n",
 		K(i.totalram),
 		K(i.freeram),
 		K(i.sharedram),
@@ -199,13 +208,16 @@
 		K(pg_size - swapper_space.nrpages),
 		K(swapper_space.nrpages),
 		K(nr_active_pages),
-		K(nr_inactive_pages),
+		K(nr_inactive_dirty_pages),
+		K(nr_inactive_clean_pages),
+		K(inactive_target()),
 		K(i.totalhigh),
 		K(i.freehigh),
 		K(i.totalram-i.totalhigh),
 		K(i.freeram-i.freehigh),
 		K(i.totalswap),
-		K(i.freeswap));
+		K(i.freeswap),
+		K(committed));
 
 	return proc_calc_metrics(page, start, off, count, eof, len);
 #undef B
@@ -370,11 +382,11 @@
 		}
 	}
 
-	proc_sprintf(page, &off, &len,
-		"\nctxt %u\n"
+	len += sprintf(page + len,
+		"\nctxt %lu\n"
 		"btime %lu\n"
 		"processes %lu\n",
-		kstat.context_swtch,
+		nr_context_switches(),
 		xtime.tv_sec - jif / HZ,
 		total_forks);
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/quota.c linux.20pre10-ac2/fs/quota.c
--- linux.20pre10/fs/quota.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/fs/quota.c	2002-08-06 15:41:51.000000000 +0100
@@ -0,0 +1,656 @@
+/*
+ * Quota code necessary even when VFS quota support is not compiled
+ * into the kernel.  The interesting stuff is over in dquot.c, here
+ * we have symbols for initial quotactl(2) handling, the sysctl(2)
+ * variables, etc - things needed even when quota support disabled.
+ */
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <asm/current.h>
+#include <asm/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/smp_lock.h>
+#ifdef CONFIG_QIFACE_COMPAT
+#include <linux/quotacompat.h>
+#endif
+
+
+int nr_dquots, nr_free_dquots;
+
+/* Check validity of quotactl */
+static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
+{
+	if (type >= MAXQUOTAS)
+		return -EINVAL;
+	/* Is operation supported? */
+	if (!sb->s_qcop)
+		return -ENOSYS;
+
+	switch (cmd) {
+		case Q_GETFMT:
+			break;
+		case Q_QUOTAON:
+			if (!sb->s_qcop->quota_on)
+				return -ENOSYS;
+			break;
+		case Q_QUOTAOFF:
+			if (!sb->s_qcop->quota_off)
+				return -ENOSYS;
+			break;
+		case Q_SETINFO:
+			if (!sb->s_qcop->set_info)
+				return -ENOSYS;
+			break;
+		case Q_GETINFO:
+			if (!sb->s_qcop->get_info)
+				return -ENOSYS;
+			break;
+		case Q_SETQUOTA:
+			if (!sb->s_qcop->set_dqblk)
+				return -ENOSYS;
+			break;
+		case Q_GETQUOTA:
+			if (!sb->s_qcop->get_dqblk)
+				return -ENOSYS;
+			break;
+		case Q_SYNC:
+			if (!sb->s_qcop->quota_sync)
+				return -ENOSYS;
+			break;
+		case Q_XQUOTAON:
+		case Q_XQUOTAOFF:
+		case Q_XQUOTARM:
+			if (!sb->s_qcop->set_xstate)
+				return -ENOSYS;
+			break;
+		case Q_XGETQSTAT:
+			if (!sb->s_qcop->get_xstate)
+				return -ENOSYS;
+			break;
+		case Q_XSETQLIM:
+			if (!sb->s_qcop->set_xquota)
+				return -ENOSYS;
+			break;
+		case Q_XGETQUOTA:
+			if (!sb->s_qcop->get_xquota)
+				return -ENOSYS;
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	/* Is quota turned on for commands which need it? */
+	switch (cmd) {
+		case Q_GETFMT:
+		case Q_GETINFO:
+		case Q_QUOTAOFF:
+		case Q_SETINFO:
+		case Q_SETQUOTA:
+		case Q_GETQUOTA:
+			if (!sb_has_quota_enabled(sb, type))
+				return -ESRCH;
+	}
+	/* Check privileges */
+	if (cmd == Q_GETQUOTA || cmd == Q_XGETQUOTA) {
+		if (((type == USRQUOTA && current->euid != id) ||
+		     (type == GRPQUOTA && !in_egroup_p(id))) &&
+		    !capable(CAP_SYS_ADMIN))
+			return -EPERM;
+	}
+	else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO && cmd != Q_XGETQSTAT)
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+	return 0;
+}
+
+/* Resolve device pathname to superblock */
+static struct super_block *resolve_dev(const char *path)
+{
+	int ret;
+	mode_t mode;
+	struct nameidata nd;
+	kdev_t dev;
+	struct super_block *sb;
+
+	ret = user_path_walk(path, &nd);
+	if (ret)
+		goto out;
+
+	dev = nd.dentry->d_inode->i_rdev;
+	mode = nd.dentry->d_inode->i_mode;
+	path_release(&nd);
+
+	ret = -ENOTBLK;
+	if (!S_ISBLK(mode))
+		goto out;
+	ret = -ENODEV;
+	sb = get_super(dev);
+	if (!sb)
+		goto out;
+	return sb;
+out:
+	return ERR_PTR(ret);
+}
+
+/* Copy parameters and call proper function */
+static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, caddr_t addr)
+{
+	int ret;
+
+	switch (cmd) {
+		case Q_QUOTAON: {
+			char *pathname;
+
+			if (IS_ERR(pathname = getname(addr)))
+				return PTR_ERR(pathname);
+			ret = sb->s_qcop->quota_on(sb, type, id, pathname);
+			putname(pathname);
+			return ret;
+		}
+		case Q_QUOTAOFF:
+			return sb->s_qcop->quota_off(sb, type);
+
+		case Q_GETFMT: {
+			__u32 fmt;
+
+			fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id;
+			if (copy_to_user(addr, &fmt, sizeof(fmt)))
+				return -EFAULT;
+			return 0;
+		}
+		case Q_GETINFO: {
+			struct if_dqinfo info;
+
+			if ((ret = sb->s_qcop->get_info(sb, type, &info)))
+				return ret;
+			if (copy_to_user(addr, &info, sizeof(info)))
+				return -EFAULT;
+			return 0;
+		}
+		case Q_SETINFO: {
+			struct if_dqinfo info;
+
+			if (copy_from_user(&info, addr, sizeof(info)))
+				return -EFAULT;
+			return sb->s_qcop->set_info(sb, type, &info);
+		}
+		case Q_GETQUOTA: {
+			struct if_dqblk idq;
+
+			if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)))
+				return ret;
+			if (copy_to_user(addr, &idq, sizeof(idq)))
+				return -EFAULT;
+			return 0;
+		}
+		case Q_SETQUOTA: {
+			struct if_dqblk idq;
+
+			if (copy_from_user(&idq, addr, sizeof(idq)))
+				return -EFAULT;
+			return sb->s_qcop->set_dqblk(sb, type, id, &idq);
+		}
+		case Q_SYNC:
+			return sb->s_qcop->quota_sync(sb, type);
+
+		case Q_XQUOTAON:
+		case Q_XQUOTAOFF:
+		case Q_XQUOTARM: {
+			__u32 flags;
+
+			if (copy_from_user(&flags, addr, sizeof(flags)))
+				return -EFAULT;
+			return sb->s_qcop->set_xstate(sb, flags, cmd);
+		}
+		case Q_XGETQSTAT: {
+			struct fs_quota_stat fqs;
+		
+			if ((ret = sb->s_qcop->get_xstate(sb, &fqs)))
+				return ret;
+			if (copy_to_user(addr, &fqs, sizeof(fqs)))
+				return -EFAULT;
+			return 0;
+		}
+		case Q_XSETQLIM: {
+			struct fs_disk_quota fdq;
+
+			if (copy_from_user(&fdq, addr, sizeof(fdq)))
+				return -EFAULT;
+		       return sb->s_qcop->set_xquota(sb, type, id, &fdq);
+		}
+		case Q_XGETQUOTA: {
+			struct fs_disk_quota fdq;
+
+			if ((ret = sb->s_qcop->get_xquota(sb, type, id, &fdq)))
+				return ret;
+			if (copy_to_user(addr, &fdq, sizeof(fdq)))
+				return -EFAULT;
+			return 0;
+		}
+		/* We never reach here unless validity check is broken */
+		default:
+			BUG();
+	}
+	return 0;
+}
+
+#ifdef CONFIG_QIFACE_COMPAT
+static int check_compat_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
+{
+	if (type >= MAXQUOTAS)
+		return -EINVAL;
+	/* Is operation supported? */
+	/* sb==NULL for GETSTATS calls */
+	if (sb && !sb->s_qcop)
+		return -ENOSYS;
+
+	switch (cmd) {
+		case Q_COMP_QUOTAON:
+			if (!sb->s_qcop->quota_on)
+				return -ENOSYS;
+			break;
+		case Q_COMP_QUOTAOFF:
+			if (!sb->s_qcop->quota_off)
+				return -ENOSYS;
+			break;
+		case Q_COMP_SYNC:
+			if (!sb->s_qcop->quota_sync)
+				return -ENOSYS;
+		break;
+#ifdef CONFIG_QIFACE_V2
+		case Q_V2_SETFLAGS:
+		case Q_V2_SETGRACE:
+		case Q_V2_SETINFO:
+			if (!sb->s_qcop->set_info)
+				return -ENOSYS;
+			break;
+		case Q_V2_GETINFO:
+			if (!sb->s_qcop->get_info)
+				return -ENOSYS;
+			break;
+		case Q_V2_SETQLIM:
+		case Q_V2_SETUSE:
+		case Q_V2_SETQUOTA:
+			if (!sb->s_qcop->set_dqblk)
+				return -ENOSYS;
+			break;
+		case Q_V2_GETQUOTA:
+			if (!sb->s_qcop->get_dqblk)
+				return -ENOSYS;
+			break;
+		case Q_V2_GETSTATS:
+			return 0;	/* GETSTATS need no other checks */
+#endif
+#ifdef CONFIG_QIFACE_V1
+		case Q_V1_SETQLIM:
+		case Q_V1_SETUSE:
+		case Q_V1_SETQUOTA:
+			if (!sb->s_qcop->set_dqblk)
+				return -ENOSYS;
+			break;
+		case Q_V1_GETQUOTA:
+			if (!sb->s_qcop->get_dqblk)
+				return -ENOSYS;
+			break;
+		case Q_V1_RSQUASH:
+			if (!sb->s_qcop->set_info)
+				return -ENOSYS;
+			break;
+		case Q_V1_GETSTATS:
+			return 0;	/* GETSTATS need no other checks */
+#endif
+		default:
+			return -EINVAL;
+	}
+
+	/* Is quota turned on for commands which need it? */
+	switch (cmd) {
+		case Q_V2_SETFLAGS:
+		case Q_V2_SETGRACE:
+		case Q_V2_SETINFO:
+		case Q_V2_GETINFO:
+		case Q_COMP_QUOTAOFF:
+		case Q_V1_RSQUASH:
+		case Q_V1_SETQUOTA:
+		case Q_V1_SETQLIM:
+		case Q_V1_SETUSE:
+		case Q_V2_SETQUOTA:
+		/* Q_V2_SETQLIM: collision with Q_V1_SETQLIM */
+		case Q_V2_SETUSE:
+		case Q_V1_GETQUOTA:
+		case Q_V2_GETQUOTA:
+			if (!sb_has_quota_enabled(sb, type))
+				return -ESRCH;
+	}
+#ifdef CONFIG_QIFACE_V1
+	if (cmd != Q_COMP_QUOTAON && cmd != Q_COMP_QUOTAOFF && cmd != Q_COMP_SYNC && sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id != QFMT_VFS_OLD)
+#else
+	if (cmd != Q_COMP_QUOTAON && cmd != Q_COMP_QUOTAOFF && cmd != Q_COMP_SYNC && sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id != QFMT_VFS_V0)
+#endif
+		return -ESRCH;
+
+	/* Check privileges */
+	if (cmd == Q_V1_GETQUOTA || cmd == Q_V2_GETQUOTA) {
+		if (((type == USRQUOTA && current->euid != id) ||
+		     (type == GRPQUOTA && !in_egroup_p(id))) &&
+		    !capable(CAP_SYS_ADMIN))
+			return -EPERM;
+	}
+	else if (cmd != Q_V1_GETSTATS && cmd != Q_V2_GETSTATS && cmd != Q_V2_GETINFO && cmd != Q_COMP_SYNC)
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+	return 0;
+}
+
+#ifdef CONFIG_QIFACE_V1
+static int v1_set_rsquash(struct super_block *sb, int type, int flag)
+{
+	struct if_dqinfo info;
+
+	info.dqi_valid = IIF_FLAGS;
+	info.dqi_flags = flag ? V1_DQF_RSQUASH : 0;
+	return sb->s_qcop->set_info(sb, type, &info);
+}
+
+static int v1_get_dqblk(struct super_block *sb, int type, qid_t id, struct v1c_mem_dqblk *mdq)
+{
+	struct if_dqblk idq;
+	int ret;
+
+	if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)) < 0)
+		return ret;
+	mdq->dqb_ihardlimit = idq.dqb_ihardlimit;
+	mdq->dqb_isoftlimit = idq.dqb_isoftlimit;
+	mdq->dqb_curinodes = idq.dqb_curinodes;
+	mdq->dqb_bhardlimit = idq.dqb_bhardlimit;
+	mdq->dqb_bsoftlimit = idq.dqb_bsoftlimit;
+	mdq->dqb_curblocks = toqb(idq.dqb_curspace);
+	mdq->dqb_itime = idq.dqb_itime;
+	mdq->dqb_btime = idq.dqb_btime;
+	if (id == 0) {	/* Times for id 0 are in fact grace times */
+		struct if_dqinfo info;
+
+		if ((ret = sb->s_qcop->get_info(sb, type, &info)) < 0)
+			return ret;
+		mdq->dqb_btime = info.dqi_bgrace;
+		mdq->dqb_itime = info.dqi_igrace;
+	}
+	return 0;
+}
+
+static int v1_set_dqblk(struct super_block *sb, int type, int cmd, qid_t id, struct v1c_mem_dqblk *mdq)
+{
+	struct if_dqblk idq;
+	int ret;
+
+	idq.dqb_valid = 0;
+	if (cmd == Q_V1_SETQUOTA || cmd == Q_V1_SETQLIM) {
+		idq.dqb_ihardlimit = mdq->dqb_ihardlimit;
+		idq.dqb_isoftlimit = mdq->dqb_isoftlimit;
+		idq.dqb_bhardlimit = mdq->dqb_bhardlimit;
+		idq.dqb_bsoftlimit = mdq->dqb_bsoftlimit;
+		idq.dqb_valid |= QIF_LIMITS;
+	}
+	if (cmd == Q_V1_SETQUOTA || cmd == Q_V1_SETUSE) {
+		idq.dqb_curinodes = mdq->dqb_curinodes;
+		idq.dqb_curspace = ((qsize_t)mdq->dqb_curblocks) << QUOTABLOCK_BITS;
+		idq.dqb_valid |= QIF_USAGE;
+	}
+	ret = sb->s_qcop->set_dqblk(sb, type, id, &idq);
+	if (!ret && id == 0 && cmd == Q_V1_SETQUOTA) {	/* Times for id 0 are in fact grace times */
+		struct if_dqinfo info;
+
+		info.dqi_bgrace = mdq->dqb_btime;
+		info.dqi_igrace = mdq->dqb_itime;
+		info.dqi_valid = IIF_BGRACE | IIF_IGRACE;
+		ret = sb->s_qcop->set_info(sb, type, &info);
+	}
+	return ret;
+}
+
+static void v1_get_stats(struct v1c_dqstats *dst)
+{
+	memcpy(dst, &dqstats, sizeof(dqstats));
+}
+#endif
+
+#ifdef CONFIG_QIFACE_V2
+static int v2_get_info(struct super_block *sb, int type, struct v2c_mem_dqinfo *oinfo)
+{
+	struct if_dqinfo info;
+	int ret;
+
+	if ((ret = sb->s_qcop->get_info(sb, type, &info)) < 0)
+		return ret;
+	oinfo->dqi_bgrace = info.dqi_bgrace;
+	oinfo->dqi_igrace = info.dqi_igrace;
+	oinfo->dqi_flags = info.dqi_flags;
+	oinfo->dqi_blocks = sb_dqopt(sb)->info[type].u.v2_i.dqi_blocks;
+	oinfo->dqi_free_blk = sb_dqopt(sb)->info[type].u.v2_i.dqi_free_blk;
+	oinfo->dqi_free_entry = sb_dqopt(sb)->info[type].u.v2_i.dqi_free_entry;
+	return 0;
+}
+
+static int v2_set_info(struct super_block *sb, int type, int cmd, struct v2c_mem_dqinfo *oinfo)
+{
+	struct if_dqinfo info;
+
+	info.dqi_valid = 0;
+	if (cmd == Q_V2_SETGRACE || cmd == Q_V2_SETINFO) {
+		info.dqi_bgrace = oinfo->dqi_bgrace;
+		info.dqi_igrace = oinfo->dqi_igrace;
+		info.dqi_valid |= IIF_BGRACE | IIF_IGRACE;
+	}
+	if (cmd == Q_V2_SETFLAGS || cmd == Q_V2_SETINFO) {
+		info.dqi_flags = oinfo->dqi_flags;
+		info.dqi_valid |= IIF_FLAGS;
+	}
+	/* We don't simulate deadly effects of setting other parameters ;-) */
+	return sb->s_qcop->set_info(sb, type, &info);
+}
+
+static int v2_get_dqblk(struct super_block *sb, int type, qid_t id, struct v2c_mem_dqblk *mdq)
+{
+	struct if_dqblk idq;
+	int ret;
+
+	if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)) < 0)
+		return ret;
+	mdq->dqb_ihardlimit = idq.dqb_ihardlimit;
+	mdq->dqb_isoftlimit = idq.dqb_isoftlimit;
+	mdq->dqb_curinodes = idq.dqb_curinodes;
+	mdq->dqb_bhardlimit = idq.dqb_bhardlimit;
+	mdq->dqb_bsoftlimit = idq.dqb_bsoftlimit;
+	mdq->dqb_curspace = idq.dqb_curspace;
+	mdq->dqb_itime = idq.dqb_itime;
+	mdq->dqb_btime = idq.dqb_btime;
+	return 0;
+}
+
+static int v2_set_dqblk(struct super_block *sb, int type, int cmd, qid_t id, struct v2c_mem_dqblk *mdq)
+{
+	struct if_dqblk idq;
+
+	idq.dqb_valid = 0;
+	if (cmd == Q_V2_SETQUOTA || cmd == Q_V2_SETQLIM) {
+		idq.dqb_ihardlimit = mdq->dqb_ihardlimit;
+		idq.dqb_isoftlimit = mdq->dqb_isoftlimit;
+		idq.dqb_bhardlimit = mdq->dqb_bhardlimit;
+		idq.dqb_bsoftlimit = mdq->dqb_bsoftlimit;
+		idq.dqb_valid |= QIF_LIMITS;
+	}
+	if (cmd == Q_V2_SETQUOTA || cmd == Q_V2_SETUSE) {
+		idq.dqb_curinodes = mdq->dqb_curinodes;
+		idq.dqb_curspace = mdq->dqb_curspace;
+		idq.dqb_valid |= QIF_USAGE;
+	}
+	return sb->s_qcop->set_dqblk(sb, type, id, &idq);
+}
+
+static void v2_get_stats(struct v2c_dqstats *dst)
+{
+	memcpy(dst, &dqstats, sizeof(dqstats));
+	dst->version = __DQUOT_NUM_VERSION__;
+}
+#endif
+
+/* Handle requests to old interface */
+static int do_compat_quotactl(struct super_block *sb, int type, int cmd, qid_t id, caddr_t addr)
+{
+	int ret;
+
+	switch (cmd) {
+		case Q_COMP_QUOTAON: {
+			char *pathname;
+
+			if (IS_ERR(pathname = getname(addr)))
+				return PTR_ERR(pathname);
+#ifdef CONFIG_QIFACE_V1
+			ret = sb->s_qcop->quota_on(sb, type, QFMT_VFS_OLD, pathname);
+#else
+			ret = sb->s_qcop->quota_on(sb, type, QFMT_VFS_V0, pathname);
+#endif
+			putname(pathname);
+			return ret;
+		}
+		case Q_COMP_QUOTAOFF:
+			return sb->s_qcop->quota_off(sb, type);
+		case Q_COMP_SYNC:
+			return sb->s_qcop->quota_sync(sb, type);
+#ifdef CONFIG_QIFACE_V1
+		case Q_V1_RSQUASH: {
+			int flag;
+
+			if (copy_from_user(&flag, addr, sizeof(flag)))
+				return -EFAULT;
+			return v1_set_rsquash(sb, type, flag);
+		}
+		case Q_V1_GETQUOTA: {
+			struct v1c_mem_dqblk mdq;
+
+			if ((ret = v1_get_dqblk(sb, type, id, &mdq)))
+				return ret;
+			if (copy_to_user(addr, &mdq, sizeof(mdq)))
+				return -EFAULT;
+			return 0;
+		}
+		case Q_V1_SETQLIM:
+		case Q_V1_SETUSE:
+		case Q_V1_SETQUOTA: {
+			struct v1c_mem_dqblk mdq;
+
+			if (copy_from_user(&mdq, addr, sizeof(mdq)))
+				return -EFAULT;
+			return v1_set_dqblk(sb, type, cmd, id, &mdq);
+		}
+		case Q_V1_GETSTATS: {
+			struct v1c_dqstats dst;
+
+			v1_get_stats(&dst);
+			if (copy_to_user(addr, &dst, sizeof(dst)))
+				return -EFAULT;
+			return 0;
+		}
+#endif
+#ifdef CONFIG_QIFACE_V2
+		case Q_V2_GETINFO: {
+			struct v2c_mem_dqinfo info;
+
+			if ((ret = v2_get_info(sb, type, &info)))
+				return ret;
+			if (copy_to_user(addr, &info, sizeof(info)))
+				return -EFAULT;
+			return 0;
+		}
+		case Q_V2_SETFLAGS:
+		case Q_V2_SETGRACE:
+		case Q_V2_SETINFO: {
+			struct v2c_mem_dqinfo info;
+
+			if (copy_from_user(&info, addr, sizeof(info)))
+				return -EFAULT;
+			
+			return v2_set_info(sb, type, cmd, &info);
+		}
+		case Q_V2_GETQUOTA: {
+			struct v2c_mem_dqblk mdq;
+
+			if ((ret = v2_get_dqblk(sb, type, id, &mdq)))
+				return ret;
+			if (copy_to_user(addr, &mdq, sizeof(mdq)))
+				return -EFAULT;
+			return 0;
+		}
+		case Q_V2_SETUSE:
+		case Q_V2_SETQLIM:
+		case Q_V2_SETQUOTA: {
+			struct v2c_mem_dqblk mdq;
+
+			if (copy_from_user(&mdq, addr, sizeof(mdq)))
+				return -EFAULT;
+			return v2_set_dqblk(sb, type, cmd, id, &mdq);
+		}
+		case Q_V2_GETSTATS: {
+			struct v2c_dqstats dst;
+
+			v2_get_stats(&dst);
+			if (copy_to_user(addr, &dst, sizeof(dst)))
+				return -EFAULT;
+			return 0;
+		}
+#endif
+	}
+	BUG();
+	return 0;
+}
+#endif
+
+/* Macros for short-circuiting the compatibility tests */
+#define NEW_COMMAND(c) ((c) & (0x80 << 16))
+#define XQM_COMMAND(c) (((c) & ('X' << 8)) == ('X' << 8))
+
+/*
+ * This is the system call interface. This communicates with
+ * the user-level programs. Currently this only supports diskquota
+ * calls. Maybe we need to add the process quotas etc. in the future,
+ * but we probably should use rlimits for that.
+ */
+asmlinkage long sys_quotactl(unsigned int cmd, const char *special, qid_t id, caddr_t addr)
+{
+	uint cmds, type;
+	struct super_block *sb = NULL;
+	int ret = -EINVAL;
+
+	lock_kernel();
+	cmds = cmd >> SUBCMDSHIFT;
+	type = cmd & SUBCMDMASK;
+
+#ifdef CONFIG_QIFACE_COMPAT
+	if (cmds != Q_V1_GETSTATS && cmds != Q_V2_GETSTATS && IS_ERR(sb = resolve_dev(special))) {
+		ret = PTR_ERR(sb);
+		sb = NULL;
+		goto out;
+	}
+	if (!NEW_COMMAND(cmds) && !XQM_COMMAND(cmds)) {
+		if ((ret = check_compat_quotactl_valid(sb, type, cmds, id)) < 0)
+			goto out;
+		ret = do_compat_quotactl(sb, type, cmds, id, addr);
+		goto out;
+	}
+#else
+	if (IS_ERR(sb = resolve_dev(special))) {
+		ret = PTR_ERR(sb);
+		sb = NULL;
+		goto out;
+	}
+#endif
+	if ((ret = check_quotactl_valid(sb, type, cmds, id)) < 0)
+		goto out;
+	ret = do_quotactl(sb, type, cmds, id, addr);
+out:
+	if (sb)
+		drop_super(sb);
+	unlock_kernel();
+	return ret;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/quota_v1.c linux.20pre10-ac2/fs/quota_v1.c
--- linux.20pre10/fs/quota_v1.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/fs/quota_v1.c	2002-08-06 15:41:51.000000000 +0100
@@ -0,0 +1,239 @@
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/quota.h>
+#include <linux/dqblk_v1.h>
+#include <linux/quotaio_v1.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+
+static void v1_disk2mem_dqblk(struct mem_dqblk *m, struct v1_disk_dqblk *d)
+{
+	m->dqb_ihardlimit = d->dqb_ihardlimit;
+	m->dqb_isoftlimit = d->dqb_isoftlimit;
+	m->dqb_curinodes = d->dqb_curinodes;
+	m->dqb_bhardlimit = d->dqb_bhardlimit;
+	m->dqb_bsoftlimit = d->dqb_bsoftlimit;
+	m->dqb_curspace = d->dqb_curblocks << QUOTABLOCK_BITS;
+	m->dqb_itime = d->dqb_itime;
+	m->dqb_btime = d->dqb_btime;
+}
+
+static void v1_mem2disk_dqblk(struct v1_disk_dqblk *d, struct mem_dqblk *m)
+{
+	d->dqb_ihardlimit = m->dqb_ihardlimit;
+	d->dqb_isoftlimit = m->dqb_isoftlimit;
+	d->dqb_curinodes = m->dqb_curinodes;
+	d->dqb_bhardlimit = m->dqb_bhardlimit;
+	d->dqb_bsoftlimit = m->dqb_bsoftlimit;
+	d->dqb_curblocks = toqb(m->dqb_curspace);
+	d->dqb_itime = m->dqb_itime;
+	d->dqb_btime = m->dqb_btime;
+}
+
+static int v1_read_dqblk(struct dquot *dquot)
+{
+	int type = dquot->dq_type;
+	struct file *filp;
+	mm_segment_t fs;
+	loff_t offset;
+	struct v1_disk_dqblk dqblk;
+
+	filp = sb_dqopt(dquot->dq_sb)->files[type];
+	if (filp == (struct file *)NULL)
+		return -EINVAL;
+
+	/* Now we are sure filp is valid */
+	offset = v1_dqoff(dquot->dq_id);
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	filp->f_op->read(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset);
+	set_fs(fs);
+
+	v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk);
+	if (dquot->dq_dqb.dqb_bhardlimit == 0 && dquot->dq_dqb.dqb_bsoftlimit == 0 &&
+	    dquot->dq_dqb.dqb_ihardlimit == 0 && dquot->dq_dqb.dqb_isoftlimit == 0)
+		dquot->dq_flags |= DQ_FAKE;
+	dqstats.reads++;
+	return 0;
+}
+
+static int v1_commit_dqblk(struct dquot *dquot)
+{
+	short type = dquot->dq_type;
+	struct file *filp;
+	mm_segment_t fs;
+	loff_t offset;
+	ssize_t ret;
+	struct v1_disk_dqblk dqblk;
+
+	filp = sb_dqopt(dquot->dq_sb)->files[type];
+	offset = v1_dqoff(dquot->dq_id);
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	/*
+	 * Note: clear the DQ_MOD flag unconditionally,
+	 * so we don't loop forever on failure.
+	 */
+	v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb);
+	dquot->dq_flags &= ~DQ_MOD;
+	if (dquot->dq_id == 0) {
+		dqblk.dqb_btime = sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace;
+		dqblk.dqb_itime = sb_dqopt(dquot->dq_sb)->info[type].dqi_igrace;
+	}
+	ret = 0;
+	if (filp)
+		ret = filp->f_op->write(filp, (char *)&dqblk,
+					sizeof(struct v1_disk_dqblk), &offset);
+	if (ret != sizeof(struct v1_disk_dqblk)) {
+		printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
+			kdevname(dquot->dq_dev));
+		if (ret >= 0)
+			ret = -EIO;
+		goto out;
+	}
+	ret = 0;
+
+out:
+	set_fs(fs);
+	dqstats.writes++;
+	return ret;
+}
+
+/* Magics of new quota format */
+#define V2_INITQMAGICS {\
+	0xd9c01f11,     /* USRQUOTA */\
+	0xd9c01927      /* GRPQUOTA */\
+}
+
+/* Header of new quota format */
+struct v2_disk_dqheader {
+	__u32 dqh_magic;        /* Magic number identifying file */
+	__u32 dqh_version;      /* File version */
+};
+
+static int v1_check_quota_file(struct super_block *sb, int type)
+{
+	struct file *f = sb_dqopt(sb)->files[type];
+	struct inode *inode = f->f_dentry->d_inode;
+	ulong blocks;
+	size_t off; 
+	struct v2_disk_dqheader dqhead;
+	mm_segment_t fs;
+	ssize_t size;
+	loff_t offset = 0;
+	static const uint quota_magics[] = V2_INITQMAGICS;
+
+	if (!inode->i_size)
+		return 0;
+	blocks = inode->i_size >> BLOCK_SIZE_BITS;
+	off = inode->i_size & (BLOCK_SIZE - 1);
+	if ((blocks % sizeof(struct v1_disk_dqblk) * BLOCK_SIZE + off) % sizeof(struct v1_disk_dqblk))
+		return 0;
+	/* Doublecheck whether we didn't get file with new format - with old quotactl() this could happen */
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	size = f->f_op->read(f, (char *)&dqhead, sizeof(struct v2_disk_dqheader), &offset);
+	set_fs(fs);
+	if (size != sizeof(struct v2_disk_dqheader))
+		return 1;	/* Probably not new format */
+	if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type])
+		return 1;	/* Definitely not new format */
+	printk(KERN_INFO "VFS: %s: Refusing to turn on old quota format on given file. It probably contains newer quota format.\n", kdevname(sb->s_dev));
+        return 0;		/* Seems like a new format file -> refuse it */
+}
+
+static int v1_read_file_info(struct super_block *sb, int type)
+{
+	struct quota_info *dqopt = sb_dqopt(sb);
+	mm_segment_t fs;
+	loff_t offset;
+	struct file *filp = dqopt->files[type];
+	struct v1_disk_dqblk dqblk;
+	int ret;
+
+	down(&dqopt->dqio_sem);
+	offset = v1_dqoff(0);
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	if ((ret = filp->f_op->read(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset)) != sizeof(struct v1_disk_dqblk)) {
+		if (ret >= 0)
+			ret = -EIO;
+		goto out;
+	}
+	ret = 0;
+	dqopt->info[type].dqi_igrace = dqblk.dqb_itime ? dqblk.dqb_itime : MAX_IQ_TIME;
+	dqopt->info[type].dqi_bgrace = dqblk.dqb_btime ? dqblk.dqb_btime : MAX_DQ_TIME;
+out:
+	up(&dqopt->dqio_sem);
+	set_fs(fs);
+	return ret;
+}
+
+static int v1_write_file_info(struct super_block *sb, int type)
+{
+	struct quota_info *dqopt = sb_dqopt(sb);
+	mm_segment_t fs;
+	struct file *filp = dqopt->files[type];
+	struct v1_disk_dqblk dqblk;
+	loff_t offset;
+	int ret;
+
+	down(&dqopt->dqio_sem);
+	dqopt->info[type].dqi_flags &= ~DQF_INFO_DIRTY;
+	offset = v1_dqoff(0);
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	if ((ret = filp->f_op->read(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset)) != sizeof(struct v1_disk_dqblk)) {
+		if (ret >= 0)
+			ret = -EIO;
+		goto out;
+	}
+	dqblk.dqb_itime = dqopt->info[type].dqi_igrace;
+	dqblk.dqb_btime = dqopt->info[type].dqi_bgrace;
+	offset = v1_dqoff(0);
+	ret = filp->f_op->write(filp, (char *)&dqblk, sizeof(struct v1_disk_dqblk), &offset);
+	if (ret == sizeof(struct v1_disk_dqblk))
+		ret = 0;
+	else if (ret > 0)
+		ret = -EIO;
+out:
+	up(&dqopt->dqio_sem);
+	set_fs(fs);
+	return ret;
+}
+
+static struct quota_format_ops v1_format_ops = {
+	check_quota_file:	v1_check_quota_file,
+	read_file_info:		v1_read_file_info,
+	write_file_info:	v1_write_file_info,
+	free_file_info:		NULL,
+	read_dqblk:		v1_read_dqblk,
+	commit_dqblk:		v1_commit_dqblk,
+};
+
+static struct quota_format_type v1_quota_format = {
+	qf_fmt_id:	QFMT_VFS_OLD,
+	qf_ops:		&v1_format_ops,
+	qf_owner:	THIS_MODULE
+};
+
+static int __init init_v1_quota_format(void)
+{
+        return register_quota_format(&v1_quota_format);
+}
+
+static void __exit exit_v1_quota_format(void)
+{
+        unregister_quota_format(&v1_quota_format);
+}
+
+EXPORT_NO_SYMBOLS;
+
+module_init(init_v1_quota_format);
+module_exit(exit_v1_quota_format);
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/quota_v2.c linux.20pre10-ac2/fs/quota_v2.c
--- linux.20pre10/fs/quota_v2.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/fs/quota_v2.c	2002-08-06 15:41:51.000000000 +0100
@@ -0,0 +1,690 @@
+/*
+ *	vfsv0 quota IO operations on file
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/dqblk_v2.h>
+#include <linux/quotaio_v2.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#define __QUOTA_V2_PARANOIA
+
+typedef char *dqbuf_t;
+
+#define GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff)
+#define GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)buf)+sizeof(struct v2_disk_dqdbheader)))
+
+/* Check whether given file is really vfsv0 quotafile */
+static int v2_check_quota_file(struct super_block *sb, int type)
+{
+	struct v2_disk_dqheader dqhead;
+	struct file *f = sb_dqopt(sb)->files[type];
+	mm_segment_t fs;
+	ssize_t size;
+	loff_t offset = 0;
+	static const uint quota_magics[] = V2_INITQMAGICS;
+	static const uint quota_versions[] = V2_INITQVERSIONS;
+ 
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	size = f->f_op->read(f, (char *)&dqhead, sizeof(struct v2_disk_dqheader), &offset);
+	set_fs(fs);
+	if (size != sizeof(struct v2_disk_dqheader))
+		return 0;
+	if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
+	    le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
+		return 0;
+	return 1;
+}
+
+/* Read information header from quota file */
+static int v2_read_file_info(struct super_block *sb, int type)
+{
+	mm_segment_t fs;
+	struct v2_disk_dqinfo dinfo;
+	struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
+	struct file *f = sb_dqopt(sb)->files[type];
+	ssize_t size;
+	loff_t offset = V2_DQINFOOFF;
+
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	size = f->f_op->read(f, (char *)&dinfo, sizeof(struct v2_disk_dqinfo), &offset);
+	set_fs(fs);
+	if (size != sizeof(struct v2_disk_dqinfo)) {
+		printk(KERN_WARNING "Can't read info structure on device %s.\n",
+			kdevname(f->f_dentry->d_sb->s_dev));
+		return -1;
+	}
+	info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
+	info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
+	info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
+	info->u.v2_i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
+	info->u.v2_i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
+	info->u.v2_i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
+	return 0;
+}
+
+/* Write information header to quota file */
+static int v2_write_file_info(struct super_block *sb, int type)
+{
+	mm_segment_t fs;
+	struct v2_disk_dqinfo dinfo;
+	struct mem_dqinfo *info = sb_dqopt(sb)->info+type;
+	struct file *f = sb_dqopt(sb)->files[type];
+	ssize_t size;
+	loff_t offset = V2_DQINFOOFF;
+
+	info->dqi_flags &= ~DQF_INFO_DIRTY;
+	dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
+	dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
+	dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
+	dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.dqi_blocks);
+	dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.dqi_free_blk);
+	dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.dqi_free_entry);
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	size = f->f_op->write(f, (char *)&dinfo, sizeof(struct v2_disk_dqinfo), &offset);
+	set_fs(fs);
+	if (size != sizeof(struct v2_disk_dqinfo)) {
+		printk(KERN_WARNING "Can't write info structure on device %s.\n",
+			kdevname(f->f_dentry->d_sb->s_dev));
+		return -1;
+	}
+	return 0;
+}
+
+static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d)
+{
+	m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
+	m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
+	m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
+	m->dqb_itime = le64_to_cpu(d->dqb_itime);
+	m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit);
+	m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit);
+	m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
+	m->dqb_btime = le64_to_cpu(d->dqb_btime);
+}
+
+static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
+{
+	d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
+	d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
+	d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
+	d->dqb_itime = cpu_to_le64(m->dqb_itime);
+	d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit);
+	d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit);
+	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
+	d->dqb_btime = cpu_to_le64(m->dqb_btime);
+	d->dqb_id = cpu_to_le32(id);
+}
+
+static dqbuf_t getdqbuf(void)
+{
+	dqbuf_t buf = kmalloc(V2_DQBLKSIZE, GFP_KERNEL);
+	if (!buf)
+		printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n");
+	return buf;
+}
+
+static inline void freedqbuf(dqbuf_t buf)
+{
+	kfree(buf);
+}
+
+static ssize_t read_blk(struct file *filp, uint blk, dqbuf_t buf)
+{
+	mm_segment_t fs;
+	ssize_t ret;
+	loff_t offset = blk<<V2_DQBLKSIZE_BITS;
+
+	memset(buf, 0, V2_DQBLKSIZE);
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = filp->f_op->read(filp, (char *)buf, V2_DQBLKSIZE, &offset);
+	set_fs(fs);
+	return ret;
+}
+
+static ssize_t write_blk(struct file *filp, uint blk, dqbuf_t buf)
+{
+	mm_segment_t fs;
+	ssize_t ret;
+	loff_t offset = blk<<V2_DQBLKSIZE_BITS;
+
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = filp->f_op->write(filp, (char *)buf, V2_DQBLKSIZE, &offset);
+	set_fs(fs);
+	return ret;
+
+}
+
+/* Remove empty block from list and return it */
+static int get_free_dqblk(struct file *filp, struct mem_dqinfo *info)
+{
+	dqbuf_t buf = getdqbuf();
+	struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
+	int ret, blk;
+
+	if (!buf)
+		return -ENOMEM;
+	if (info->u.v2_i.dqi_free_blk) {
+		blk = info->u.v2_i.dqi_free_blk;
+		if ((ret = read_blk(filp, blk, buf)) < 0)
+			goto out_buf;
+		info->u.v2_i.dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
+	}
+	else {
+		memset(buf, 0, V2_DQBLKSIZE);
+		if ((ret = write_blk(filp, info->u.v2_i.dqi_blocks, buf)) < 0)	/* Assure block allocation... */
+			goto out_buf;
+		blk = info->u.v2_i.dqi_blocks++;
+	}
+	mark_info_dirty(info);
+	ret = blk;
+out_buf:
+	freedqbuf(buf);
+	return ret;
+}
+
+/* Insert empty block to the list */
+static int put_free_dqblk(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk)
+{
+	struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
+	int err;
+
+	dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_blk);
+	dh->dqdh_prev_free = cpu_to_le32(0);
+	dh->dqdh_entries = cpu_to_le16(0);
+	info->u.v2_i.dqi_free_blk = blk;
+	mark_info_dirty(info);
+	if ((err = write_blk(filp, blk, buf)) < 0)	/* Some strange block. We had better leave it... */
+		return err;
+	return 0;
+}
+
+/* Remove given block from the list of blocks with free entries */
+static int remove_free_dqentry(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk)
+{
+	dqbuf_t tmpbuf = getdqbuf();
+	struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
+	uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free);
+	int err;
+
+	if (!tmpbuf)
+		return -ENOMEM;
+	if (nextblk) {
+		if ((err = read_blk(filp, nextblk, tmpbuf)) < 0)
+			goto out_buf;
+		((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free;
+		if ((err = write_blk(filp, nextblk, tmpbuf)) < 0)
+			goto out_buf;
+	}
+	if (prevblk) {
+		if ((err = read_blk(filp, prevblk, tmpbuf)) < 0)
+			goto out_buf;
+		((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free;
+		if ((err = write_blk(filp, prevblk, tmpbuf)) < 0)
+			goto out_buf;
+	}
+	else {
+		info->u.v2_i.dqi_free_entry = nextblk;
+		mark_info_dirty(info);
+	}
+	freedqbuf(tmpbuf);
+	dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
+	if (write_blk(filp, blk, buf) < 0)	/* No matter whether write succeeds block is out of list */
+		printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk);
+	return 0;
+out_buf:
+	freedqbuf(tmpbuf);
+	return err;
+}
+
+/* Insert given block to the beginning of list with free entries */
+static int insert_free_dqentry(struct file *filp, struct mem_dqinfo *info, dqbuf_t buf, uint blk)
+{
+	dqbuf_t tmpbuf = getdqbuf();
+	struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
+	int err;
+
+	if (!tmpbuf)
+		return -ENOMEM;
+	dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_entry);
+	dh->dqdh_prev_free = cpu_to_le32(0);
+	if ((err = write_blk(filp, blk, buf)) < 0)
+		goto out_buf;
+	if (info->u.v2_i.dqi_free_entry) {
+		if ((err = read_blk(filp, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
+			goto out_buf;
+		((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk);
+		if ((err = write_blk(filp, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
+			goto out_buf;
+	}
+	freedqbuf(tmpbuf);
+	info->u.v2_i.dqi_free_entry = blk;
+	mark_info_dirty(info);
+	return 0;
+out_buf:
+	freedqbuf(tmpbuf);
+	return err;
+}
+
+/* Find space for dquot */
+static uint find_free_dqentry(struct dquot *dquot, int *err)
+{
+	struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
+	struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info+dquot->dq_type;
+	uint blk, i;
+	struct v2_disk_dqdbheader *dh;
+	struct v2_disk_dqblk *ddquot;
+	struct v2_disk_dqblk fakedquot;
+	dqbuf_t buf;
+
+	*err = 0;
+	if (!(buf = getdqbuf())) {
+		*err = -ENOMEM;
+		return 0;
+	}
+	dh = (struct v2_disk_dqdbheader *)buf;
+	ddquot = GETENTRIES(buf);
+	if (info->u.v2_i.dqi_free_entry) {
+		blk = info->u.v2_i.dqi_free_entry;
+		if ((*err = read_blk(filp, blk, buf)) < 0)
+			goto out_buf;
+	}
+	else {
+		blk = get_free_dqblk(filp, info);
+		if ((int)blk < 0) {
+			*err = blk;
+			return 0;
+		}
+		memset(buf, 0, V2_DQBLKSIZE);
+		info->u.v2_i.dqi_free_entry = blk;	/* This is enough as block is already zeroed and entry list is empty... */
+		mark_info_dirty(info);
+	}
+	if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK)	/* Block will be full? */
+		if ((*err = remove_free_dqentry(filp, info, buf, blk)) < 0) {
+			printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
+			goto out_buf;
+		}
+	dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)+1);
+	memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
+	/* Find free structure in block */
+	for (i = 0; i < V2_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)); i++);
+#ifdef __QUOTA_V2_PARANOIA
+	if (i == V2_DQSTRINBLK) {
+		printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
+		*err = -EIO;
+		goto out_buf;
+	}
+#endif
+	if ((*err = write_blk(filp, blk, buf)) < 0) {
+		printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk);
+		goto out_buf;
+	}
+	dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+sizeof(struct v2_disk_dqdbheader)+i*sizeof(struct v2_disk_dqblk);
+	freedqbuf(buf);
+	return blk;
+out_buf:
+	freedqbuf(buf);
+	return 0;
+}
+
+/* Insert reference to structure into the trie */
+static int do_insert_tree(struct dquot *dquot, uint *treeblk, int depth)
+{
+	struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
+	struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type;
+	dqbuf_t buf;
+	int ret = 0, newson = 0, newact = 0;
+	u32 *ref;
+	uint newblk;
+
+	if (!(buf = getdqbuf()))
+		return -ENOMEM;
+	if (!*treeblk) {
+		ret = get_free_dqblk(filp, info);
+		if (ret < 0)
+			goto out_buf;
+		*treeblk = ret;
+		memset(buf, 0, V2_DQBLKSIZE);
+		newact = 1;
+	}
+	else {
+		if ((ret = read_blk(filp, *treeblk, buf)) < 0) {
+			printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk);
+			goto out_buf;
+		}
+	}
+	ref = (u32 *)buf;
+	newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
+	if (!newblk)
+		newson = 1;
+	if (depth == V2_DQTREEDEPTH-1) {
+#ifdef __QUOTA_V2_PARANOIA
+		if (newblk) {
+			printk(KERN_ERR "VFS: Inserting already present quota entry (block %u).\n", ref[GETIDINDEX(dquot->dq_id, depth)]);
+			ret = -EIO;
+			goto out_buf;
+		}
+#endif
+		newblk = find_free_dqentry(dquot, &ret);
+	}
+	else
+		ret = do_insert_tree(dquot, &newblk, depth+1);
+	if (newson && ret >= 0) {
+		ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk);
+		ret = write_blk(filp, *treeblk, buf);
+	}
+	else if (newact && ret < 0)
+		put_free_dqblk(filp, info, buf, *treeblk);
+out_buf:
+	freedqbuf(buf);
+	return ret;
+}
+
+/* Wrapper for inserting quota structure into tree */
+static inline int dq_insert_tree(struct dquot *dquot)
+{
+	int tmp = V2_DQTREEOFF;
+	return do_insert_tree(dquot, &tmp, 0);
+}
+
+/*
+ *	We don't have to be afraid of deadlocks as we never have quotas on quota files...
+ */
+static int v2_write_dquot(struct dquot *dquot)
+{
+	int type = dquot->dq_type;
+	struct file *filp;
+	mm_segment_t fs;
+	loff_t offset;
+	ssize_t ret;
+	struct v2_disk_dqblk ddquot;
+
+	if (!dquot->dq_off)
+		if ((ret = dq_insert_tree(dquot)) < 0) {
+			printk(KERN_ERR "VFS: Error %d occured while creating quota.\n", ret);
+			return ret;
+		}
+	filp = sb_dqopt(dquot->dq_sb)->files[type];
+	offset = dquot->dq_off;
+	mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
+	fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = filp->f_op->write(filp, (char *)&ddquot, sizeof(struct v2_disk_dqblk), &offset);
+	set_fs(fs);
+	if (ret != sizeof(struct v2_disk_dqblk)) {
+		printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", kdevname(dquot->dq_dev));
+		if (ret >= 0)
+			ret = -ENOSPC;
+	}
+	else
+		ret = 0;
+	dqstats.writes++;
+	return ret;
+}
+
+/* Free dquot entry in data block */
+static int free_dqentry(struct dquot *dquot, uint blk)
+{
+	struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
+	struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type;
+	struct v2_disk_dqdbheader *dh;
+	dqbuf_t buf = getdqbuf();
+	int ret = 0;
+
+	if (!buf)
+		return -ENOMEM;
+	if (dquot->dq_off >> V2_DQBLKSIZE_BITS != blk) {
+		printk(KERN_ERR "VFS: Quota structure has offset to other block (%u) than it should (%u).\n", blk, (uint)(dquot->dq_off >> V2_DQBLKSIZE_BITS));
+		goto out_buf;
+	}
+	if ((ret = read_blk(filp, blk, buf)) < 0) {
+		printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
+		goto out_buf;
+	}
+	dh = (struct v2_disk_dqdbheader *)buf;
+	dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)-1);
+	if (!le16_to_cpu(dh->dqdh_entries)) {	/* Block got free? */
+		if ((ret = remove_free_dqentry(filp, info, buf, blk)) < 0 ||
+		    (ret = put_free_dqblk(filp, info, buf, blk)) < 0) {
+			printk(KERN_ERR "VFS: Can't move quota data block (%u) to free list.\n", blk);
+			goto out_buf;
+		}
+	}
+	else {
+		memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0, sizeof(struct v2_disk_dqblk));
+		if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
+			/* Insert will write block itself */
+			if ((ret = insert_free_dqentry(filp, info, buf, blk)) < 0) {
+				printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
+				goto out_buf;
+			}
+		}
+		else
+			if ((ret = write_blk(filp, blk, buf)) < 0) {
+				printk(KERN_ERR "VFS: Can't write quota data block %u\n", blk);
+				goto out_buf;
+			}
+	}
+	dquot->dq_off = 0;	/* Quota is now unattached */
+out_buf:
+	freedqbuf(buf);
+	return ret;
+}
+
+/* Remove reference to dquot from tree */
+static int remove_tree(struct dquot *dquot, uint *blk, int depth)
+{
+	struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
+	struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type;
+	dqbuf_t buf = getdqbuf();
+	int ret = 0;
+	uint newblk;
+	u32 *ref = (u32 *)buf;
+	
+	if (!buf)
+		return -ENOMEM;
+	if ((ret = read_blk(filp, *blk, buf)) < 0) {
+		printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
+		goto out_buf;
+	}
+	newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
+	if (depth == V2_DQTREEDEPTH-1) {
+		ret = free_dqentry(dquot, newblk);
+		newblk = 0;
+	}
+	else
+		ret = remove_tree(dquot, &newblk, depth+1);
+	if (ret >= 0 && !newblk) {
+		int i;
+		ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
+		for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++);	/* Block got empty? */
+		if (i == V2_DQBLKSIZE) {
+			put_free_dqblk(filp, info, buf, *blk);
+			*blk = 0;
+		}
+		else
+			if ((ret = write_blk(filp, *blk, buf)) < 0)
+				printk(KERN_ERR "VFS: Can't write quota tree block %u.\n", *blk);
+	}
+out_buf:
+	freedqbuf(buf);
+	return ret;	
+}
+
+/* Delete dquot from tree */
+static int v2_delete_dquot(struct dquot *dquot)
+{
+	uint tmp = V2_DQTREEOFF;
+
+	if (!dquot->dq_off)	/* Even not allocated? */
+		return 0;
+	return remove_tree(dquot, &tmp, 0);
+}
+
+/* Find entry in block */
+static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
+{
+	struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
+	dqbuf_t buf = getdqbuf();
+	loff_t ret = 0;
+	int i;
+	struct v2_disk_dqblk *ddquot = GETENTRIES(buf);
+
+	if (!buf)
+		return -ENOMEM;
+	if ((ret = read_blk(filp, blk, buf)) < 0) {
+		printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
+		goto out_buf;
+	}
+	if (dquot->dq_id)
+		for (i = 0; i < V2_DQSTRINBLK && le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
+	else {	/* ID 0 as a bit more complicated searching... */
+		struct v2_disk_dqblk fakedquot;
+
+		memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
+		for (i = 0; i < V2_DQSTRINBLK; i++)
+			if (!le32_to_cpu(ddquot[i].dqb_id) && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))
+				break;
+	}
+	if (i == V2_DQSTRINBLK) {
+		printk(KERN_ERR "VFS: Quota for id %u referenced but not present.\n", dquot->dq_id);
+		ret = -EIO;
+		goto out_buf;
+	}
+	else
+		ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
+out_buf:
+	freedqbuf(buf);
+	return ret;
+}
+
+/* Find entry for given id in the tree */
+static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth)
+{
+	struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
+	dqbuf_t buf = getdqbuf();
+	loff_t ret = 0;
+	u32 *ref = (u32 *)buf;
+
+	if (!buf)
+		return -ENOMEM;
+	if ((ret = read_blk(filp, blk, buf)) < 0) {
+		printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
+		goto out_buf;
+	}
+	ret = 0;
+	blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
+	if (!blk)	/* No reference? */
+		goto out_buf;
+	if (depth < V2_DQTREEDEPTH-1)
+		ret = find_tree_dqentry(dquot, blk, depth+1);
+	else
+		ret = find_block_dqentry(dquot, blk);
+out_buf:
+	freedqbuf(buf);
+	return ret;
+}
+
+/* Find entry for given id in the tree - wrapper function */
+static inline loff_t find_dqentry(struct dquot *dquot)
+{
+	return find_tree_dqentry(dquot, V2_DQTREEOFF, 0);
+}
+
+static int v2_read_dquot(struct dquot *dquot)
+{
+	int type = dquot->dq_type;
+	struct file *filp;
+	mm_segment_t fs;
+	loff_t offset;
+	struct v2_disk_dqblk ddquot;
+	int ret = 0;
+
+	filp = sb_dqopt(dquot->dq_sb)->files[type];
+
+#ifdef __QUOTA_V2_PARANOIA
+	if (!filp || !dquot->dq_sb) {	/* Invalidated quota? */
+		printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
+		return -EIO;
+	}
+#endif
+	offset = find_dqentry(dquot);
+	if (offset <= 0) {	/* Entry not present? */
+		if (offset < 0)
+			printk(KERN_ERR "VFS: Can't read quota structure for id %u.\n", dquot->dq_id);
+		dquot->dq_off = 0;
+		dquot->dq_flags |= DQ_FAKE;
+		memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
+		ret = offset;
+	}
+	else {
+		dquot->dq_off = offset;
+		fs = get_fs();
+		set_fs(KERNEL_DS);
+		if ((ret = filp->f_op->read(filp, (char *)&ddquot, sizeof(struct v2_disk_dqblk), &offset)) != sizeof(struct v2_disk_dqblk)) {
+			if (ret >= 0)
+				ret = -EIO;
+			printk(KERN_ERR "VFS: Error while reading quota structure for id %u.\n", dquot->dq_id);
+			memset(&ddquot, 0, sizeof(struct v2_disk_dqblk));
+		}
+		else
+			ret = 0;
+		set_fs(fs);
+		disk2memdqb(&dquot->dq_dqb, &ddquot);
+	}
+	dqstats.reads++;
+	return ret;
+}
+
+/* Commit changes of dquot to disk - it might also mean deleting it when quota became fake one and user has no blocks... */
+static int v2_commit_dquot(struct dquot *dquot)
+{
+	/* We clear the flag everytime so we don't loop when there was an IO error... */
+	dquot->dq_flags &= ~DQ_MOD;
+	if (dquot->dq_flags & DQ_FAKE && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace))
+		return v2_delete_dquot(dquot);
+	else
+		return v2_write_dquot(dquot);
+}
+
+static struct quota_format_ops v2_format_ops = {
+	check_quota_file:	v2_check_quota_file,
+	read_file_info:		v2_read_file_info,
+	write_file_info:	v2_write_file_info,
+	free_file_info:		NULL,
+	read_dqblk:		v2_read_dquot,
+	commit_dqblk:		v2_commit_dquot,
+};
+
+static struct quota_format_type v2_quota_format = {
+	qf_fmt_id:	QFMT_VFS_V0,
+	qf_ops:		&v2_format_ops,
+	qf_owner:	THIS_MODULE
+};
+
+static int __init init_v2_quota_format(void)
+{
+	return register_quota_format(&v2_quota_format);
+}
+
+static void __exit exit_v2_quota_format(void)
+{
+	unregister_quota_format(&v2_quota_format);
+}
+
+EXPORT_NO_SYMBOLS;
+
+module_init(init_v2_quota_format);
+module_exit(exit_v2_quota_format);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/ramfs/inode.c linux.20pre10-ac2/fs/ramfs/inode.c
--- linux.20pre10/fs/ramfs/inode.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/fs/ramfs/inode.c	2002-08-06 15:41:51.000000000 +0100
@@ -29,8 +29,18 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/locks.h>
+#include <linux/highmem.h>
+#include <linux/slab.h>
 
 #include <asm/uaccess.h>
+#include <linux/spinlock.h>
+
+#if PAGE_CACHE_SIZE % 1024
+#error Oh no, PAGE_CACHE_SIZE is not divisible by 1k! I cannot cope.
+#endif
+
+#define IBLOCKS_PER_PAGE  (PAGE_CACHE_SIZE / 512)
+#define K_PER_PAGE (PAGE_CACHE_SIZE / 1024)
 
 /* some random number */
 #define RAMFS_MAGIC	0x858458f6
@@ -40,8 +50,176 @@
 static struct file_operations ramfs_file_operations;
 static struct inode_operations ramfs_dir_inode_operations;
 
+/*
+ * ramfs super-block data in memory
+ */
+struct ramfs_sb_info {
+	/* Prevent races accessing the used block
+	 * counts. Conceptually, this could probably be a semaphore,
+	 * but the only thing we do while holding the lock is
+	 * arithmetic, so there's no point */
+	spinlock_t ramfs_lock;
+
+	/* It is important that at least the free counts below be
+	   signed.  free_XXX may become negative if a limit is changed
+	   downwards (by a remount) below the current usage. */	  
+
+	/* maximum number of pages in a file */
+	long max_file_pages;
+
+	/* max total number of data pages */
+	long max_pages;
+	/* free_pages = max_pages - total number of pages currently in use */
+	long free_pages;
+	
+	/* max number of inodes */
+	long max_inodes;
+	/* free_inodes = max_inodes - total number of inodes currently in use */
+	long free_inodes;
+
+	/* max number of dentries */
+	long max_dentries;
+	/* free_dentries = max_dentries - total number of dentries in use */
+	long free_dentries;
+};
+
+#define RAMFS_SB(sb) ((struct ramfs_sb_info *)((sb)->u.generic_sbp))
+
+/*
+ * Resource limit helper functions
+ */
+
+static inline void lock_rsb(struct ramfs_sb_info *rsb)
+{
+	spin_lock(&(rsb->ramfs_lock));
+}
+
+static inline void unlock_rsb(struct ramfs_sb_info *rsb)
+{
+	spin_unlock(&(rsb->ramfs_lock));
+}
+
+/* Decrements the free inode count and returns true, or returns false
+ * if there are no free inodes */
+static int ramfs_alloc_inode(struct super_block *sb)
+{
+	struct ramfs_sb_info *rsb = RAMFS_SB(sb);
+	int ret = 1;
+
+	lock_rsb(rsb);
+	if (!rsb->max_inodes || rsb->free_inodes > 0)
+		rsb->free_inodes--;
+	else
+		ret = 0;
+	unlock_rsb(rsb);
+	
+	return ret;
+}
+
+/* Increments the free inode count */
+static void ramfs_dealloc_inode(struct super_block *sb)
+{
+	struct ramfs_sb_info *rsb = RAMFS_SB(sb);
+	
+	lock_rsb(rsb);
+	rsb->free_inodes++;
+	unlock_rsb(rsb);
+}
+
+/* Decrements the free dentry count and returns true, or returns false
+ * if there are no free dentries */
+static int ramfs_alloc_dentry(struct super_block *sb)
+{
+	struct ramfs_sb_info *rsb = RAMFS_SB(sb);
+	int ret = 1;
+
+	lock_rsb(rsb);
+	if (!rsb->max_dentries || rsb->free_dentries > 0)
+		rsb->free_dentries--;
+	else
+		ret = 0;
+	unlock_rsb(rsb);
+	
+	return ret;
+}
+
+/* Increments the free dentry count */
+static void ramfs_dealloc_dentry(struct super_block *sb)
+{
+	struct ramfs_sb_info *rsb = RAMFS_SB(sb);
+	
+	lock_rsb(rsb);
+	rsb->free_dentries++;
+	unlock_rsb(rsb);
+}
+
+/* If the given page can be added to the give inode for ramfs, return
+ * true and update the filesystem's free page count and the inode's
+ * i_blocks field. Always returns true if the file is already used by
+ * ramfs (ie. PageDirty(page) is true)  */
+int ramfs_alloc_page(struct inode *inode, struct page *page)
+{
+	struct ramfs_sb_info *rsb = RAMFS_SB(inode->i_sb);
+	int ret = 1;
+
+	if (PageDirty(page)) /* It's already been allocated */
+		return 1;
+
+	lock_rsb(rsb);
+		
+	if ( (rsb->free_pages > 0) &&
+	     ( !rsb->max_file_pages ||
+	       (inode->i_data.nrpages <= rsb->max_file_pages) ) ) {
+		inode->i_blocks += IBLOCKS_PER_PAGE;
+		rsb->free_pages--;
+		SetPageDirty(page);
+	} else {
+		ClearPageUptodate(page);
+		ret = 0;
+	}
+	
+	unlock_rsb(rsb);
+
+	return ret;
+}
+
+void ramfs_dealloc_page(struct inode *inode, struct page *page)
+{
+	struct ramfs_sb_info *rsb = RAMFS_SB(inode->i_sb);
+
+	if (! PageDirty(page)) /* The page was never allocated 
+				  this can happen if it was only read */
+		return;
+
+	lock_rsb(rsb);
+
+	ClearPageDirty(page);
+	
+	rsb->free_pages++;
+	inode->i_blocks -= IBLOCKS_PER_PAGE;
+	
+	if (rsb->free_pages > rsb->max_pages) {
+		printk(KERN_ERR "ramfs: Error in page allocation, free_pages (%ld) > max_pages (%ld)\n", rsb->free_pages, rsb->max_pages);
+	}
+
+	unlock_rsb(rsb);
+}
+
+
+
 static int ramfs_statfs(struct super_block *sb, struct statfs *buf)
 {
+	struct ramfs_sb_info *rsb = RAMFS_SB(sb);
+
+	lock_rsb(rsb);
+	buf->f_blocks = rsb->max_pages;
+	buf->f_files = rsb->max_inodes;
+
+	buf->f_bfree = rsb->free_pages;
+	buf->f_bavail = buf->f_bfree;
+	buf->f_ffree = rsb->free_inodes;
+	unlock_rsb(rsb);
+
 	buf->f_type = RAMFS_MAGIC;
 	buf->f_bsize = PAGE_CACHE_SIZE;
 	buf->f_namelen = 255;
@@ -74,9 +252,26 @@
 	return 0;
 }
 
+static int ramfs_writepage(struct page *page)
+{
+	struct inode *inode = (struct inode *)page->mapping->host;
+
+	if (! ramfs_alloc_page(inode, page))
+		return -ENOSPC;
+
+	return 0;
+}
+
 static int ramfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
 {
-	void *addr = kmap(page);
+	struct inode *inode = (struct inode *)page->mapping->host;
+	void *addr;
+
+	if (! ramfs_alloc_page(inode, page)) {
+		return -ENOSPC;
+	}
+
+	addr = (void *) kmap(page);
 	if (!Page_Uptodate(page)) {
 		memset(addr, 0, PAGE_CACHE_SIZE);
 		flush_dcache_page(page);
@@ -97,9 +292,21 @@
 	return 0;
 }
 
+static void ramfs_removepage(struct page *page)
+{
+	struct inode *inode = (struct inode *)page->mapping->host;
+
+	ramfs_dealloc_page(inode, page);
+}
+
 struct inode *ramfs_get_inode(struct super_block *sb, int mode, int dev)
 {
-	struct inode * inode = new_inode(sb);
+	struct inode * inode;
+
+	if (! ramfs_alloc_inode(sb))
+		return NULL;
+
+	inode = new_inode(sb);
 
 	if (inode) {
 		inode->i_mode = mode;
@@ -125,23 +332,35 @@
 			inode->i_op = &page_symlink_inode_operations;
 			break;
 		}
-	}
+	} else
+		ramfs_dealloc_inode(sb);
+
 	return inode;
 }
 
 /*
- * File creation. Allocate an inode, and we're done..
+ * File creation. Allocate an inode, update free inode and dentry counts
+ * and we're done..
  */
 static int ramfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev)
 {
-	struct inode * inode = ramfs_get_inode(dir->i_sb, mode, dev);
+	struct super_block *sb = dir->i_sb;
+	struct inode * inode;
 	int error = -ENOSPC;
 
+	if (! ramfs_alloc_dentry(sb))
+		return error;
+
+	inode = ramfs_get_inode(dir->i_sb, mode, dev);
+
 	if (inode) {
 		d_instantiate(dentry, inode);
 		dget(dentry);		/* Extra count - pin the dentry in core */
 		error = 0;
+	} else {
+		ramfs_dealloc_dentry(sb);
 	}
+
 	return error;
 }
 
@@ -160,11 +379,15 @@
  */
 static int ramfs_link(struct dentry *old_dentry, struct inode * dir, struct dentry * dentry)
 {
+	struct super_block *sb = dir->i_sb;
 	struct inode *inode = old_dentry->d_inode;
 
 	if (S_ISDIR(inode->i_mode))
 		return -EPERM;
 
+	if (! ramfs_alloc_dentry(sb))
+		return -ENOSPC;
+
 	inode->i_nlink++;
 	atomic_inc(&inode->i_count);	/* New dentry reference */
 	dget(dentry);		/* Extra pinning count for the created dentry */
@@ -211,6 +434,7 @@
  */
 static int ramfs_unlink(struct inode * dir, struct dentry *dentry)
 {
+	struct super_block *sb = dir->i_sb;
 	int retval = -ENOTEMPTY;
 
 	if (ramfs_empty(dentry)) {
@@ -218,6 +442,9 @@
 
 		inode->i_nlink--;
 		dput(dentry);			/* Undo the count from "create" - this does all the work */
+
+		ramfs_dealloc_dentry(sb);
+
 		retval = 0;
 	}
 	return retval;
@@ -233,6 +460,8 @@
  */
 static int ramfs_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir,struct dentry *new_dentry)
 {
+	struct super_block *sb = new_dir->i_sb;
+
 	int error = -ENOTEMPTY;
 
 	if (ramfs_empty(new_dentry)) {
@@ -240,6 +469,7 @@
 		if (inode) {
 			inode->i_nlink--;
 			dput(new_dentry);
+			ramfs_dealloc_dentry(sb);
 		}
 		error = 0;
 	}
@@ -264,11 +494,173 @@
 	return 0;
 }
 
+static void ramfs_delete_inode(struct inode *inode)
+{
+	ramfs_dealloc_inode(inode->i_sb);
+
+	clear_inode(inode);
+}
+
+static void ramfs_put_super(struct super_block *sb)
+{
+	kfree(sb->u.generic_sbp);
+}
+
+struct ramfs_params {
+	long pages;
+	long filepages;
+	long inodes;
+	long dentries;
+};
+
+static int parse_options(char * options, struct ramfs_params *p)
+{
+	char save = 0, *savep = NULL, *optname, *value;
+
+	p->pages = -1;
+	p->filepages = -1;
+	p->inodes = -1;
+	p->dentries = -1;
+
+	for (optname = strtok(options,","); optname;
+		     optname = strtok(NULL,",")) {
+	if ((value = strchr(optname,'=')) != NULL) {
+			save = *value;
+			savep = value;
+			*value++ = 0;
+		}
+
+		if (!strcmp(optname, "maxfilesize") && value) {
+			p->filepages = simple_strtoul(value, &value, 0)
+				/ K_PER_PAGE;
+			if (*value)
+				return -EINVAL;
+		} else if (!strcmp(optname, "maxsize") && value) {
+			p->pages = simple_strtoul(value, &value, 0)
+				/ K_PER_PAGE;
+			if (*value)
+				return -EINVAL;
+		} else if (!strcmp(optname, "maxinodes") && value) {
+			p->inodes = simple_strtoul(value, &value, 0);
+			if (*value)
+				return -EINVAL;
+ 		} else if (!strcmp(optname, "maxdentries") && value) {
+			p->dentries = simple_strtoul(value, &value, 0);
+			if (*value)
+				return -EINVAL;
+		}
+
+		if (optname != options)
+			*(optname-1) = ',';
+		if (value)
+			*savep = save;
+	}
+
+	return 0;
+}
+
+static void init_limits(struct ramfs_sb_info *rsb, struct ramfs_params *p)
+{
+	struct sysinfo si;
+
+	si_meminfo(&si);
+
+	/* By default we set the limits to be:
+	       - Allow this ramfs to take up to half of all available RAM
+	       - No limit on filesize (except no file may be bigger that
+	         the total max size, obviously)
+	       - dentries limited to one per 4k of data space
+	       - No limit to the number of inodes (except that there
+	         are never more inodes than dentries).
+	*/
+	rsb->max_pages = (si.totalram / 2);
+
+	if (p->pages >= 0)
+		rsb->max_pages = p->pages;
+
+	rsb->max_file_pages = 0;
+	if (p->filepages >= 0)
+ 		rsb->max_file_pages = p->filepages;
+
+	rsb->max_dentries = rsb->max_pages * K_PER_PAGE / 4;
+ 	if (p->dentries >= 0)
+		rsb->max_dentries = p->dentries;
+
+	rsb->max_inodes = 0;
+ 	if (p->inodes >= 0)
+		rsb->max_inodes = p->inodes;
+
+	rsb->free_pages = rsb->max_pages;
+	rsb->free_inodes = rsb->max_inodes;
+	rsb->free_dentries = rsb->max_dentries;
+
+	return;
+}
+
+/* reset_limits is called during a remount to change the usage limits.
+
+   This will suceed, even if the new limits are lower than current
+   usage. This is the intended behaviour - new allocations will fail
+   until usage falls below the new limit */
+static void reset_limits(struct ramfs_sb_info *rsb, struct ramfs_params *p)
+{
+	lock_rsb(rsb);
+
+	if (p->pages >= 0) {
+		int used_pages = rsb->max_pages - rsb->free_pages;
+
+		rsb->max_pages = p->pages;
+		rsb->free_pages = rsb->max_pages - used_pages;
+	}
+
+	if (p->filepages >= 0) {
+		rsb->max_file_pages = p->filepages;
+ 	}
+	
+
+	if (p->dentries >= 0) {
+		int used_dentries = rsb->max_dentries - rsb->free_dentries;
+
+		rsb->max_dentries = p->dentries;
+		rsb->free_dentries = rsb->max_dentries - used_dentries;
+	}
+
+	if (p->inodes >= 0) {
+		int used_inodes = rsb->max_inodes - rsb->free_inodes;
+
+		rsb->max_inodes = p->inodes;
+		rsb->free_inodes = rsb->max_inodes - used_inodes;
+	}
+
+	unlock_rsb(rsb);
+}
+
+static int ramfs_remount(struct super_block * sb, int * flags, char * data)
+{
+	struct ramfs_params params;
+	struct ramfs_sb_info * rsb = RAMFS_SB(sb);
+
+	if (parse_options((char *)data, &params) != 0)
+		return -EINVAL;
+
+	reset_limits(rsb, &params);
+
+ 	printk(KERN_DEBUG "ramfs: remounted with options: %s\n", 
+	       data ? (char *)data : "<defaults>" );
+	printk(KERN_DEBUG "ramfs: max_pages=%ld max_file_pages=%ld \
+max_inodes=%ld max_dentries=%ld\n",
+	       rsb->max_pages, rsb->max_file_pages,
+	       rsb->max_inodes, rsb->max_dentries);
+
+	return 0;
+}
+ 
 static struct address_space_operations ramfs_aops = {
 	readpage:	ramfs_readpage,
-	writepage:	fail_writepage,
+	writepage:	ramfs_writepage,
 	prepare_write:	ramfs_prepare_write,
-	commit_write:	ramfs_commit_write
+	commit_write:	ramfs_commit_write,
+	removepage:	ramfs_removepage,
 };
 
 static struct file_operations ramfs_file_operations = {
@@ -293,17 +685,37 @@
 static struct super_operations ramfs_ops = {
 	statfs:		ramfs_statfs,
 	put_inode:	force_delete,
+	delete_inode:	ramfs_delete_inode,
+	put_super:      ramfs_put_super,
+	remount_fs:     ramfs_remount,
 };
 
+/*
+ * Initialisation
+ */
+
 static struct super_block *ramfs_read_super(struct super_block * sb, void * data, int silent)
 {
 	struct inode * inode;
 	struct dentry * root;
+	struct ramfs_sb_info * rsb;
+	struct ramfs_params params;
 
 	sb->s_blocksize = PAGE_CACHE_SIZE;
 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
 	sb->s_magic = RAMFS_MAGIC;
 	sb->s_op = &ramfs_ops;
+
+	sb->u.generic_sbp = kmalloc(sizeof(struct ramfs_sb_info), GFP_KERNEL);
+	rsb = RAMFS_SB(sb);
+
+	spin_lock_init(&rsb->ramfs_lock);
+
+	if (parse_options((char *)data, &params) != 0)
+		return NULL;
+
+	init_limits(rsb, &params);
+
 	inode = ramfs_get_inode(sb, S_IFDIR | 0755, 0);
 	if (!inode)
 		return NULL;
@@ -314,6 +726,13 @@
 		return NULL;
 	}
 	sb->s_root = root;
+
+	printk(KERN_DEBUG "ramfs: mounted with options: %s\n", 
+	       data ? (char *)data : "<defaults>" );
+	printk(KERN_DEBUG "ramfs: max_pages=%ld max_file_pages=%ld \
+max_inodes=%ld max_dentries=%ld\n",
+	       rsb->max_pages, rsb->max_file_pages,
+	       rsb->max_inodes, rsb->max_dentries);
 	return sb;
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/read_write.c linux.20pre10-ac2/fs/read_write.c
--- linux.20pre10/fs/read_write.c	2002-10-09 21:36:35.000000000 +0100
+++ linux.20pre10-ac2/fs/read_write.c	2002-09-29 20:34:20.000000000 +0100
@@ -218,7 +218,7 @@
 	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 *);
 
-	ssize_t tot_len;
+	size_t tot_len;
 	struct iovec iovstack[UIO_FASTIOV];
 	struct iovec *iov=iovstack;
 	ssize_t ret, i;
@@ -259,12 +259,19 @@
 	tot_len = 0;
 	ret = -EINVAL;
 	for (i = 0 ; i < count ; i++) {
-		ssize_t tmp = tot_len;
 		ssize_t len = (ssize_t) iov[i].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 */
+		/* We must do this work unsigned - signed overflow is
+		   undefined and gcc 3.2 now uses that fact sometimes... 
+		   
+		   FIXME: put in a proper limits.h for each platform */
+#if BITS_PER_LONG==64
+		if (tot_len > 0x7FFFFFFFFFFFFFFFUL)
+#else
+		if (tot_len > 0x7FFFFFFFUL)
+#endif		
 			goto out;
 	}
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/reiserfs/buffer2.c linux.20pre10-ac2/fs/reiserfs/buffer2.c
--- linux.20pre10/fs/reiserfs/buffer2.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/reiserfs/buffer2.c	2002-08-13 14:43:51.000000000 +0100
@@ -51,11 +51,11 @@
 struct buffer_head  * reiserfs_bread (struct super_block *super, int n_block, int n_size) 
 {
     struct buffer_head  *result;
-    PROC_EXP( unsigned int ctx_switches = kstat.context_swtch );
+    PROC_EXP( unsigned int ctx_switches = nr_context_switches(); );
 
     result = bread (super -> s_dev, n_block, n_size);
     PROC_INFO_INC( super, breads );
-    PROC_EXP( if( kstat.context_swtch != ctx_switches ) 
+    PROC_EXP( if( nr_context_switches() != ctx_switches ) 
 	      PROC_INFO_INC( super, bread_miss ) );
     return result;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/reiserfs/inode.c linux.20pre10-ac2/fs/reiserfs/inode.c
--- linux.20pre10/fs/reiserfs/inode.c	2002-10-09 21:44:48.000000000 +0100
+++ linux.20pre10-ac2/fs/reiserfs/inode.c	2002-10-11 00:22:21.000000000 +0100
@@ -2119,10 +2119,11 @@
 	}
 }
 
-static int reiserfs_direct_io(int rw, struct inode *inode, 
+static int reiserfs_direct_io(int rw, struct file *filp, 
                               struct kiobuf *iobuf, unsigned long blocknr,
 			      int blocksize) 
 {
+    struct inode * inode = filp->f_dentry->d_inode->i_mapping->host;
     return generic_direct_IO(rw, inode, iobuf, blocknr, blocksize,
                              reiserfs_get_block_direct_io) ;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/fs/super.c linux.20pre10-ac2/fs/super.c
--- linux.20pre10/fs/super.c	2002-10-09 21:44:49.000000000 +0100
+++ linux.20pre10-ac2/fs/super.c	2002-08-06 15:41:51.000000000 +0100
@@ -27,6 +27,7 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/major.h>
 #include <linux/acct.h>
+#include <linux/quotaops.h>
 
 #include <asm/uaccess.h>
 
@@ -279,6 +280,8 @@
 		sema_init(&s->s_dquot.dqio_sem, 1);
 		sema_init(&s->s_dquot.dqoff_sem, 1);
 		s->s_maxbytes = MAX_NON_LFS;
+		s->dq_op = sb_dquot_ops;
+		s->s_qcop = sb_quotactl_ops;
 	}
 	return s;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-alpha/bitops.h linux.20pre10-ac2/include/asm-alpha/bitops.h
--- linux.20pre10/include/asm-alpha/bitops.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-alpha/bitops.h	2002-08-06 15:41:52.000000000 +0100
@@ -3,6 +3,7 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <asm/compiler.h>
 
 /*
  * Copyright 1994, Linus Torvalds.
@@ -74,6 +75,17 @@
  * WARNING: non atomic version.
  */
 static __inline__ void
+__clear_bit(unsigned long nr, volatile void * addr)
+{
+	int *m = ((int *) addr) + (nr >> 5);
+
+	*m &= ~(1 << (nr & 31));
+}
+
+/*
+ * WARNING: non atomic version.
+ */
+static __inline__ void
 __change_bit(unsigned long nr, volatile void * addr)
 {
 	int *m = ((int *) addr) + (nr >> 5);
@@ -264,6 +276,28 @@
 #endif
 }
 
+/*
+ * __ffs = Find First set bit in word.  Undefined if no set bit exists.
+ */
+static inline unsigned long __ffs(unsigned long word)
+{
+#if defined(__alpha_cix__) && defined(__alpha_fix__)
+	/* Whee.  EV67 can calculate it directly.  */
+	unsigned long result;
+	__asm__("cttz %1,%0" : "=r"(result) : "r"(word));
+	return result;
+#else
+	unsigned long bits, qofs, bofs;
+
+	__asm__("cmpbge $31,%1,%0" : "=r"(bits) : "r"(word));
+	qofs = ffz_b(bits);
+	bits = __kernel_extbl(word, qofs);
+	bofs = ffz_b(~bits);
+
+	return qofs*8 + bofs;
+#endif
+}
+
 #ifdef __KERNEL__
 
 /*
@@ -365,13 +399,77 @@
 }
 
 /*
- * The optimizer actually does good code for this case..
+ * Find next one bit in a bitmap reasonably efficiently.
+ */
+static inline unsigned long
+find_next_bit(void * addr, unsigned long size, unsigned long offset)
+{
+	unsigned long * p = ((unsigned long *) addr) + (offset >> 6);
+	unsigned long result = offset & ~63UL;
+	unsigned long tmp;
+
+	if (offset >= size)
+		return size;
+	size -= result;
+	offset &= 63UL;
+	if (offset) {
+		tmp = *(p++);
+		tmp &= ~0UL << offset;
+		if (size < 64)
+			goto found_first;
+		if (tmp)
+			goto found_middle;
+		size -= 64;
+		result += 64;
+	}
+	while (size & ~63UL) {
+		if ((tmp = *(p++)))
+			goto found_middle;
+		result += 64;
+		size -= 64;
+	}
+	if (!size)
+		return result;
+	tmp = *p;
+found_first:
+	tmp &= ~0UL >> (64 - size);
+	if (!tmp)
+		return result + size;
+found_middle:
+	return result + __ffs(tmp);
+}
+
+/*
+ * The optimizer actually does good code for this case.
  */
 #define find_first_zero_bit(addr, size) \
 	find_next_zero_bit((addr), (size), 0)
+#define find_first_bit(addr, size) \
+	find_next_bit((addr), (size), 0)
 
 #ifdef __KERNEL__
 
+/*
+ * Every architecture must define this function. It's the fastest
+ * way of searching a 140-bit bitmap where the first 100 bits are
+ * unlikely to be set. It's guaranteed that at least one of the 140
+ * bits is set.
+ */
+static inline unsigned long
+sched_find_first_bit(unsigned long b[3])
+{
+	unsigned long b0 = b[0], b1 = b[1], b2 = b[2];
+	unsigned long ofs;
+
+	ofs = (b1 ? 64 : 128);
+	b1 = (b1 ? b1 : b2);
+	ofs = (b0 ? 0 : ofs);
+	b0 = (b0 ? b0 : b1);
+
+	return __ffs(b0) + ofs;
+}
+
+
 #define ext2_set_bit                 __test_and_set_bit
 #define ext2_clear_bit               __test_and_clear_bit
 #define ext2_test_bit                test_bit
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-alpha/hdreg.h linux.20pre10-ac2/include/asm-alpha/hdreg.h
--- linux.20pre10/include/asm-alpha/hdreg.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-alpha/hdreg.h	2002-09-06 00:50:04.000000000 +0100
@@ -7,6 +7,7 @@
 #ifndef __ASMalpha_HDREG_H
 #define __ASMalpha_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+//typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMalpha_HDREG_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-alpha/ide.h linux.20pre10-ac2/include/asm-alpha/ide.h
--- linux.20pre10/include/asm-alpha/ide.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-alpha/ide.h	2002-08-15 16:45:33.000000000 +0100
@@ -19,8 +19,6 @@
 #define MAX_HWIFS	4
 #endif
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
@@ -82,43 +80,6 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		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 */
-	} b;
-} control_t;
-
-#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 /* __ASMalpha_IDE_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-alpha/ioctls.h linux.20pre10-ac2/include/asm-alpha/ioctls.h
--- linux.20pre10/include/asm-alpha/ioctls.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-alpha/ioctls.h	2002-09-30 17:40:13.000000000 +0100
@@ -9,6 +9,7 @@
 #define FIONBIO		_IOW('f', 126, int)
 #define FIONREAD	_IOR('f', 127, int)
 #define TIOCINQ		FIONREAD
+#define FIOQSIZE	_IOR('f', 128, loff_t)
 
 #define TIOCGETP	_IOR('t', 8, struct sgttyb)
 #define TIOCSETP	_IOW('t', 9, struct sgttyb)
@@ -65,6 +66,8 @@
 # define TIOCM_OUT2	0x4000
 # define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 #define TIOCGSOFTCAR	0x5419
 #define TIOCSSOFTCAR	0x541A
 #define TIOCLINUX	0x541C
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-alpha/pgtable.h linux.20pre10-ac2/include/asm-alpha/pgtable.h
--- linux.20pre10/include/asm-alpha/pgtable.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-alpha/pgtable.h	2002-08-06 15:41:52.000000000 +0100
@@ -213,8 +213,8 @@
 	pte_t pte;								\
 	unsigned long pfn;							\
 										\
-	pfn = ((unsigned long)((page)-page_zone(page)->zone_mem_map)) << 32;	\
-	pfn += page_zone(page)->zone_start_paddr << (32-PAGE_SHIFT);		\
+	pfn = ((unsigned long)((page)-(page)->zone->zone_mem_map)) << 32;	\
+	pfn += (page)->zone->zone_start_paddr << (32-PAGE_SHIFT);		\
 	pte_val(pte) = pfn | pgprot_val(pgprot);				\
 										\
 	pte;									\
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-alpha/rmap.h linux.20pre10-ac2/include/asm-alpha/rmap.h
--- linux.20pre10/include/asm-alpha/rmap.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/asm-alpha/rmap.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,7 @@
+#ifndef _ALPHA_RMAP_H
+#define _ALPHA_RMAP_H
+
+/* nothing to see, move along */
+#include <asm-generic/rmap.h>
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-alpha/smp.h linux.20pre10-ac2/include/asm-alpha/smp.h
--- linux.20pre10/include/asm-alpha/smp.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-alpha/smp.h	2002-08-06 15:41:52.000000000 +0100
@@ -55,7 +55,7 @@
 #define cpu_logical_map(cpu)  __cpu_logical_map[cpu]
 
 #define hard_smp_processor_id()	__hard_smp_processor_id()
-#define smp_processor_id()	(current->processor)
+#define smp_processor_id()	(current->cpu)
 
 extern unsigned long cpu_present_mask;
 #define cpu_online_map cpu_present_mask
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-alpha/system.h linux.20pre10-ac2/include/asm-alpha/system.h
--- linux.20pre10/include/asm-alpha/system.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-alpha/system.h	2002-08-06 15:41:52.000000000 +0100
@@ -309,9 +309,11 @@
 #define __sti()			do { barrier(); setipl(IPL_MIN); } while(0)
 #define __save_flags(flags)	((flags) = rdps())
 #define __save_and_cli(flags)	do { (flags) = swpipl(IPL_MAX); barrier(); } while(0)
+#define __save_and_sti(flags)	do { (flags) = swpipl(IPL_MIN); barrier(); } while(0)
 #define __restore_flags(flags)	do { barrier(); setipl(flags); barrier(); } while(0)
 
 #define local_irq_save(flags)		__save_and_cli(flags)
+#define local_irq_set(flags)		__save_and_sti(flags)
 #define local_irq_restore(flags)	__restore_flags(flags)
 #define local_irq_disable()		__cli()
 #define local_irq_enable()		__sti()
@@ -320,8 +322,6 @@
 
 extern int global_irq_holder;
 
-#define save_and_cli(flags)     (save_flags(flags), cli())
-
 extern void __global_cli(void);
 extern void __global_sti(void);
 extern unsigned long __global_save_flags(void);
@@ -331,6 +331,8 @@
 #define sti()                   __global_sti()
 #define save_flags(flags)	((flags) = __global_save_flags())
 #define restore_flags(flags)    __global_restore_flags(flags)
+#define save_and_cli(flags)	(save_flags(flags), cli())
+#define save_and_sti(flags)	(save_flags(flags), sti())
 
 #else /* CONFIG_SMP */
 
@@ -338,6 +340,7 @@
 #define sti()			__sti()
 #define save_flags(flags)	__save_flags(flags)
 #define save_and_cli(flags)	__save_and_cli(flags)
+#define save_and_sti(flags)	__save_and_sti(flags)
 #define restore_flags(flags)	__restore_flags(flags)
 
 #endif /* CONFIG_SMP */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-arm/arch-cl7500/system.h linux.20pre10-ac2/include/asm-arm/arch-cl7500/system.h
--- linux.20pre10/include/asm-arm/arch-cl7500/system.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-arm/arch-cl7500/system.h	2002-08-06 15:41:52.000000000 +0100
@@ -18,6 +18,6 @@
 	do {					\
 		iomd_writeb(0, IOMD_ROMCR0);	\
 		cpu_reset(0);			\
-	} while (0);
+	} while (0)
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-arm/arch-sa1100/keyboard.h linux.20pre10-ac2/include/asm-arm/arch-sa1100/keyboard.h
--- linux.20pre10/include/asm-arm/arch-sa1100/keyboard.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-arm/arch-sa1100/keyboard.h	2002-08-06 15:41:52.000000000 +0100
@@ -10,8 +10,8 @@
 #include <asm/mach-types.h>
 #include <asm/arch/assabet.h>
 
-#define kbd_disable_irq()	do { } while(0);
-#define kbd_enable_irq()	do { } while(0);
+#define kbd_disable_irq()	do { } while(0)
+#define kbd_enable_irq()	do { } while(0)
 
 extern int sa1111_kbd_init_hw(void);
 extern void gc_kbd_init_hw(void);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-arm/hdreg.h linux.20pre10-ac2/include/asm-arm/hdreg.h
--- linux.20pre10/include/asm-arm/hdreg.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-arm/hdreg.h	2002-09-06 00:50:04.000000000 +0100
@@ -7,7 +7,8 @@
 #ifndef __ASMARM_HDREG_H
 #define __ASMARM_HDREG_H
 
-typedef unsigned int ide_ioreg_t;
+//typedef unsigned int ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMARM_HDREG_H */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-arm/ide.h linux.20pre10-ac2/include/asm-arm/ide.h
--- linux.20pre10/include/asm-arm/ide.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-arm/ide.h	2002-08-15 16:45:55.000000000 +0100
@@ -17,47 +17,8 @@
 #define MAX_HWIFS	4
 #endif
 
-#define ide__sti()	__sti()
-
 #include <asm/arch/ide.h>
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		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 */
-	} b;
-} control_t;
-
-#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)
-
 /*
  * We always use the new IDE port registering,
  * so these are fixed here.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-arm/page.h linux.20pre10-ac2/include/asm-arm/page.h
--- linux.20pre10/include/asm-arm/page.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-arm/page.h	2002-08-06 15:41:52.000000000 +0100
@@ -106,6 +106,9 @@
 #define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
 #endif
 
+#define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
+				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
 #endif
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-arm/proc-armo/system.h linux.20pre10-ac2/include/asm-arm/proc-armo/system.h
--- linux.20pre10/include/asm-arm/proc-armo/system.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-arm/proc-armo/system.h	2002-08-06 15:41:52.000000000 +0100
@@ -127,4 +127,6 @@
 	  : "memory");					\
 	} while (0)
 
+#define __save_and_sti(x)	({__save_flags(x);__sti();})
+
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-arm/proc-armv/rmap.h linux.20pre10-ac2/include/asm-arm/proc-armv/rmap.h
--- linux.20pre10/include/asm-arm/proc-armv/rmap.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/asm-arm/proc-armv/rmap.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,72 @@
+#ifndef _ARMV_RMAP_H
+#define _ARMV_RMAP_H
+/*
+ * linux/include/asm-arm/proc-armv/rmap.h
+ *
+ * Architecture dependant parts of the reverse mapping code,
+ *
+ * We use the struct page of the page table page to find a pointer
+ * to an array of two 'struct arm_rmap_info's, one for each of the
+ * two page tables in each page.
+ * 
+ * - rmi->mm points to the process' mm_struct
+ * - rmi->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
+ */
+#include <linux/mm.h>
+
+struct arm_rmap_info {
+	struct mm_struct *mm;
+	unsigned long index;
+};
+
+static inline void pgtable_add_rmap(pte_t * ptep, struct mm_struct * mm, unsigned long address)
+{
+	struct page * page = virt_to_page(ptep);
+	struct arm_rmap_info *rmi = (void *)page->mapping;
+
+	if (((unsigned long)ptep)&2048)
+		rmi++;
+
+	rmi->mm = mm;
+	rmi->index = address & ~((PTRS_PER_PTE * PAGE_SIZE) - 1);
+}
+
+static inline void pgtable_remove_rmap(pte_t * ptep)
+{
+	struct page * page = virt_to_page(ptep);
+	struct arm_rmap_info *rmi = (void *)page->mapping;
+
+	if (((unsigned long)ptep)&2048)
+		rmi++;
+
+	rmi->mm = NULL;
+	rmi->index = 0;
+}
+
+static inline struct mm_struct * ptep_to_mm(pte_t * ptep)
+{
+	struct page * page = virt_to_page(ptep);
+	struct arm_rmap_info *rmi = (void *)page->mapping;
+
+	if (((unsigned long)ptep)&2048)
+		rmi++;
+
+	return rmi->mm;
+}
+
+static inline unsigned long ptep_to_address(pte_t * ptep)
+{
+	struct page * page = virt_to_page(ptep);
+	struct arm_rmap_info *rmi = (void *)page->mapping;
+	unsigned long low_bits;
+
+	if (((unsigned long)ptep)&2048)
+		rmi++;
+
+	low_bits = ((unsigned long)ptep & ~PAGE_MASK) * PTRS_PER_PTE;
+	return rmi->index + low_bits;
+}
+
+#endif /* _ARMV_RMAP_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-arm/proc-armv/system.h linux.20pre10-ac2/include/asm-arm/proc-armv/system.h
--- linux.20pre10/include/asm-arm/proc-armv/system.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-arm/proc-armv/system.h	2002-08-06 15:41:52.000000000 +0100
@@ -141,6 +141,8 @@
 	: "r" (x)						\
 	: "memory")
 
+#define __save_and_sti(x)	({__save_flags(x);__sti();})
+
 #if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110)
 /*
  * On the StrongARM, "swp" is terminally broken since it bypasses the
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-arm/rmap.h linux.20pre10-ac2/include/asm-arm/rmap.h
--- linux.20pre10/include/asm-arm/rmap.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/asm-arm/rmap.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,6 @@
+#ifndef _ARM_RMAP_H
+#define _ARM_RMAP_H
+
+#include <asm/proc/rmap.h>
+
+#endif /* _ARM_RMAP_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-arm/system.h linux.20pre10-ac2/include/asm-arm/system.h
--- linux.20pre10/include/asm-arm/system.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-arm/system.h	2002-08-06 15:41:52.000000000 +0100
@@ -58,6 +58,7 @@
 
 /* For spinlocks etc */
 #define local_irq_save(x)	__save_flags_cli(x)
+#define local_irq_set(x)	__save_and_sti(x)
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -82,6 +83,8 @@
 #define save_flags(x)		__save_flags(x)
 #define restore_flags(x)	__restore_flags(x)
 #define save_flags_cli(x)	__save_flags_cli(x)
+#define save_and_cli(x)		__save_flags_cli(x)
+#define save_and_sti(x)		__save_flags_sti(x)
 
 #endif /* CONFIG_SMP */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-cris/ide.h linux.20pre10-ac2/include/asm-cris/ide.h
--- linux.20pre10/include/asm-cris/ide.h	2002-10-09 21:36:39.000000000 +0100
+++ linux.20pre10-ac2/include/asm-cris/ide.h	2002-09-01 17:51:25.000000000 +0100
@@ -22,8 +22,6 @@
 
 #define MAX_HWIFS	4
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	/* all IDE busses share the same IRQ, number 4.
@@ -88,67 +86,11 @@
 	}
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all                    : 8;    /* all of the bits together */
-	struct {
-		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 */
-	} b;
-} control_t;
-
 /* some configuration options we don't need */
 
 #undef SUPPORT_VLB_SYNC
 #define SUPPORT_VLB_SYNC 0
 
-#undef SUPPORT_SLOW_DATA_PORTS
-#define SUPPORT_SLOW_DATA_PORTS	0
-
-/* request and free a normal interrupt */
-
-#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))
-
-/* ide-probe.c calls ide_request_region and stuff on the io_ports defined,
- * but since they are not actually memory-mapped in the ETRAX driver, we don't
- * do anything.
- */
-
-#define ide_check_region(from,extent)		(0)
-#define ide_request_region(from,extent,name)	do {} while(0)
-#define ide_release_region(from,extent)		do {} while(0)
-
-/*
- * 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)
-
-/* the drive addressing is done through a controller register on the Etrax CPU */
-void OUT_BYTE(unsigned char data, ide_ioreg_t reg);
-unsigned char IN_BYTE(ide_ioreg_t reg);
-
-/* this tells ide.h not to define the standard macros */
-#define HAVE_ARCH_OUT_BYTE
-#define HAVE_ARCH_IN_BYTE
-
 #endif /* __KERNEL__ */
 
 #endif /* __ASMCRIS_IDE_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-cris/ioctls.h linux.20pre10-ac2/include/asm-cris/ioctls.h
--- linux.20pre10/include/asm-cris/ioctls.h	2002-10-09 21:36:39.000000000 +0100
+++ linux.20pre10-ac2/include/asm-cris/ioctls.h	2002-08-06 15:41:52.000000000 +0100
@@ -69,6 +69,7 @@
 #define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
 #define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
 #define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+#define FIOQSIZE	0x5460
 
 #define TIOCSERSETRS485 0x5460  /* enable rs-485 */
 #define TIOCSERWRRS485  0x5461  /* write rs-485 */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-cris/rmap.h linux.20pre10-ac2/include/asm-cris/rmap.h
--- linux.20pre10/include/asm-cris/rmap.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/asm-cris/rmap.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,7 @@
+#ifndef _CRIS_RMAP_H
+#define _CRIS_RMAP_H
+
+/* nothing to see, move along :) */
+#include <asm-generic/rmap.h>
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-cris/system.h linux.20pre10-ac2/include/asm-cris/system.h
--- linux.20pre10/include/asm-cris/system.h	2002-10-09 21:36:39.000000000 +0100
+++ linux.20pre10-ac2/include/asm-cris/system.h	2002-08-06 15:41:52.000000000 +0100
@@ -69,6 +69,7 @@
 
 /* For spinlocks etc */
 #define local_irq_save(x) __asm__ __volatile__ ("move $ccr,%0\n\tdi" : "=rm" (x) : : "memory"); 
+#define local_irq_set(x) __asm__ __volatile__ ("move $ccr,%0\n\tei" : "=rm" (x) : : "memory");
 #define local_irq_restore(x) restore_flags(x)
 
 #define local_irq_disable()  cli()
@@ -80,7 +81,8 @@
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
-#define save_and_cli(x) do { __save_flags(x); cli(); } while(0)
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0)
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0)
 
 static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
 {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-cris/termios.h linux.20pre10-ac2/include/asm-cris/termios.h
--- linux.20pre10/include/asm-cris/termios.h	2002-10-09 21:36:39.000000000 +0100
+++ linux.20pre10-ac2/include/asm-cris/termios.h	2002-09-30 17:40:35.000000000 +0100
@@ -38,6 +38,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 
 /* line disciplines */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-cris/uaccess.h linux.20pre10-ac2/include/asm-cris/uaccess.h
--- linux.20pre10/include/asm-cris/uaccess.h	2002-10-09 21:36:39.000000000 +0100
+++ linux.20pre10-ac2/include/asm-cris/uaccess.h	2002-10-11 15:59:10.000000000 +0100
@@ -147,25 +147,6 @@
 #define __put_user(x,ptr) \
   __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
 
-/*
- * The "xxx_ret" versions return constant specified in third argument, if
- * something bad happens. These macros can be optimized for the
- * case of just returning from the function xxx_ret is used.
- */
-
-#define put_user_ret(x,ptr,ret) \
-	do { if (put_user(x,ptr)) return ret; } while (0)
-
-#define get_user_ret(x,ptr,ret) \
-	do { if (get_user(x,ptr)) return ret; } while (0)
-
-#define __put_user_ret(x,ptr,ret) \
-	do { if (__put_user(x,ptr)) return ret; } while (0)
-
-#define __get_user_ret(x,ptr,ret) \
-	do { if (__get_user(x,ptr)) return ret; } while (0)
-
-
 extern long __put_user_bad(void);
 
 #define __put_user_nocheck(x,ptr,size)			\
@@ -1017,11 +998,6 @@
  __constant_copy_to_user(to, from, n) :		\
  __generic_copy_to_user(to, from, n))
 
-#define copy_to_user_ret(to,from,n,retval) \
-	do { if (copy_to_user(to,from,n)) return retval; } while (0)
-#define copy_from_user_ret(to,from,n,retval) \
-	do { if (copy_from_user(to,from,n)) return retval; } while (0)
-
 /* We let the __ versions of copy_from/to_user inline, because they're often
  * used in fast paths and have only a small space overhead.
  */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-generic/bitops.h linux.20pre10-ac2/include/asm-generic/bitops.h
--- linux.20pre10/include/asm-generic/bitops.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-generic/bitops.h	2002-08-06 15:41:52.000000000 +0100
@@ -51,6 +51,12 @@
 	return ((mask & *addr) != 0);
 }
 
+/*
+ * fls: find last bit set.
+ */
+
+#define fls(x) generic_fls(x)
+
 #ifdef __KERNEL__
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-generic/rmap.h linux.20pre10-ac2/include/asm-generic/rmap.h
--- linux.20pre10/include/asm-generic/rmap.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/asm-generic/rmap.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,57 @@
+#ifndef _GENERIC_RMAP_H
+#define _GENERIC_RMAP_H
+/*
+ * linux/include/asm-generic/rmap.h
+ *
+ * Architecture dependant parts of the reverse mapping code,
+ * this version should work for most architectures with a
+ * 'normal' page table layout.
+ *
+ * We use the struct page of the page table page to find out
+ * the process and full address of a page table entry:
+ * - page->mapping points to the process' mm_struct
+ * - 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
+ */
+#include <linux/mm.h>
+
+static inline void pgtable_add_rmap(pte_t * ptep, struct mm_struct * mm, unsigned long address)
+{
+	struct page * page = virt_to_page(ptep);
+#ifdef BROKEN_PPC_PTE_ALLOC_ONE
+	/* OK, so PPC calls pte_alloc() before mem_map[] is setup ... ;( */
+	extern int mem_init_done;
+
+	if (!mem_init_done)
+		return;
+#endif
+	page->mapping = (void *)mm;
+	page->index = address & ~((PTRS_PER_PTE * PAGE_SIZE) - 1);
+}
+
+static inline void pgtable_remove_rmap(pte_t * ptep)
+{
+	struct page * page = virt_to_page(ptep);
+
+	page->mapping = NULL;
+	page->index = 0;
+}
+
+static inline struct mm_struct * ptep_to_mm(pte_t * ptep)
+{
+	struct page * page = virt_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);
+	unsigned long low_bits;
+
+	low_bits = ((unsigned long)ptep & ~PAGE_MASK) * PTRS_PER_PTE;
+	return page->index + low_bits;
+}
+
+#endif /* _GENERIC_RMAP_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-generic/xor.h linux.20pre10-ac2/include/asm-generic/xor.h
--- linux.20pre10/include/asm-generic/xor.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-generic/xor.h	2002-08-06 15:41:52.000000000 +0100
@@ -13,6 +13,8 @@
  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <asm/processor.h>
+
 static void
 xor_8regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
 {
@@ -299,6 +301,364 @@
 	} while (--lines > 0);
 }
 
+static void
+xor_8regs_p_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+	long lines = bytes / (sizeof (long)) / 8;
+	prefetchw(p1);
+	prefetch(p2);
+
+	do {
+		prefetchw(p1+8);
+		prefetch(p2+8);
+		p1[0] ^= p2[0];
+		p1[1] ^= p2[1];
+		p1[2] ^= p2[2];
+		p1[3] ^= p2[3];
+		p1[4] ^= p2[4];
+		p1[5] ^= p2[5];
+		p1[6] ^= p2[6];
+		p1[7] ^= p2[7];
+		p1 += 8;
+		p2 += 8;
+	} while (--lines > 0);
+}
+
+static void
+xor_8regs_p_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	    unsigned long *p3)
+{
+	long lines = bytes / (sizeof (long)) / 8;
+	prefetchw(p1);
+	prefetch(p2);
+	prefetch(p3);
+
+	do {
+		prefetchw(p1+8);
+		prefetch(p2+8);
+		prefetch(p3+8);
+		p1[0] ^= p2[0] ^ p3[0];
+		p1[1] ^= p2[1] ^ p3[1];
+		p1[2] ^= p2[2] ^ p3[2];
+		p1[3] ^= p2[3] ^ p3[3];
+		p1[4] ^= p2[4] ^ p3[4];
+		p1[5] ^= p2[5] ^ p3[5];
+		p1[6] ^= p2[6] ^ p3[6];
+		p1[7] ^= p2[7] ^ p3[7];
+		p1 += 8;
+		p2 += 8;
+		p3 += 8;
+	} while (--lines > 0);
+}
+
+static void
+xor_8regs_p_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	    unsigned long *p3, unsigned long *p4)
+{
+	long lines = bytes / (sizeof (long)) / 8;
+
+	prefetchw(p1);
+	prefetch(p2);
+	prefetch(p3);
+	prefetch(p4);
+
+	do {
+		prefetchw(p1+8);
+		prefetch(p2+8);
+		prefetch(p3+8);
+		prefetch(p4+8);
+
+		p1[0] ^= p2[0] ^ p3[0] ^ p4[0];
+		p1[1] ^= p2[1] ^ p3[1] ^ p4[1];
+		p1[2] ^= p2[2] ^ p3[2] ^ p4[2];
+		p1[3] ^= p2[3] ^ p3[3] ^ p4[3];
+		p1[4] ^= p2[4] ^ p3[4] ^ p4[4];
+		p1[5] ^= p2[5] ^ p3[5] ^ p4[5];
+		p1[6] ^= p2[6] ^ p3[6] ^ p4[6];
+		p1[7] ^= p2[7] ^ p3[7] ^ p4[7];
+		p1 += 8;
+		p2 += 8;
+		p3 += 8;
+		p4 += 8;
+	} while (--lines > 0);
+}
+
+static void
+xor_8regs_p_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	    unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+	long lines = bytes / (sizeof (long)) / 8;
+
+	prefetchw(p1);
+	prefetch(p2);
+	prefetch(p3);
+	prefetch(p4);
+	prefetch(p5);
+
+	do {
+		prefetchw(p1+8);
+		prefetch(p2+8);
+		prefetch(p3+8);
+		prefetch(p4+8);
+		prefetch(p5+8);
+
+		p1[0] ^= p2[0] ^ p3[0] ^ p4[0] ^ p5[0];
+		p1[1] ^= p2[1] ^ p3[1] ^ p4[1] ^ p5[1];
+		p1[2] ^= p2[2] ^ p3[2] ^ p4[2] ^ p5[2];
+		p1[3] ^= p2[3] ^ p3[3] ^ p4[3] ^ p5[3];
+		p1[4] ^= p2[4] ^ p3[4] ^ p4[4] ^ p5[4];
+		p1[5] ^= p2[5] ^ p3[5] ^ p4[5] ^ p5[5];
+		p1[6] ^= p2[6] ^ p3[6] ^ p4[6] ^ p5[6];
+		p1[7] ^= p2[7] ^ p3[7] ^ p4[7] ^ p5[7];
+		p1 += 8;
+		p2 += 8;
+		p3 += 8;
+		p4 += 8;
+		p5 += 8;
+	} while (--lines > 0);
+}
+
+static void
+xor_32regs_p_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+	long lines = bytes / (sizeof (long)) / 8;
+
+	prefetchw(p1);
+	prefetch(p2);
+
+	do {
+		register long d0, d1, d2, d3, d4, d5, d6, d7;
+
+		prefetchw(p1+8);
+		prefetch(p2+8);
+
+		d0 = p1[0];	/* Pull the stuff into registers	*/
+		d1 = p1[1];	/*  ... in bursts, if possible.		*/
+		d2 = p1[2];
+		d3 = p1[3];
+		d4 = p1[4];
+		d5 = p1[5];
+		d6 = p1[6];
+		d7 = p1[7];
+		d0 ^= p2[0];
+		d1 ^= p2[1];
+		d2 ^= p2[2];
+		d3 ^= p2[3];
+		d4 ^= p2[4];
+		d5 ^= p2[5];
+		d6 ^= p2[6];
+		d7 ^= p2[7];
+		p1[0] = d0;	/* Store the result (in burts)		*/
+		p1[1] = d1;
+		p1[2] = d2;
+		p1[3] = d3;
+		p1[4] = d4;
+		p1[5] = d5;
+		p1[6] = d6;
+		p1[7] = d7;
+		p1 += 8;
+		p2 += 8;
+	} while (--lines > 0);
+}
+
+static void
+xor_32regs_p_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	    unsigned long *p3)
+{
+	long lines = bytes / (sizeof (long)) / 8;
+
+	prefetchw(p1);
+	prefetch(p2);
+	prefetch(p3);
+
+	do {
+		register long d0, d1, d2, d3, d4, d5, d6, d7;
+
+		prefetchw(p1+8);
+		prefetch(p2+8);
+		prefetch(p3+8);
+
+		d0 = p1[0];	/* Pull the stuff into registers	*/
+		d1 = p1[1];	/*  ... in bursts, if possible.		*/
+		d2 = p1[2];
+		d3 = p1[3];
+		d4 = p1[4];
+		d5 = p1[5];
+		d6 = p1[6];
+		d7 = p1[7];
+		d0 ^= p2[0];
+		d1 ^= p2[1];
+		d2 ^= p2[2];
+		d3 ^= p2[3];
+		d4 ^= p2[4];
+		d5 ^= p2[5];
+		d6 ^= p2[6];
+		d7 ^= p2[7];
+		d0 ^= p3[0];
+		d1 ^= p3[1];
+		d2 ^= p3[2];
+		d3 ^= p3[3];
+		d4 ^= p3[4];
+		d5 ^= p3[5];
+		d6 ^= p3[6];
+		d7 ^= p3[7];
+		p1[0] = d0;	/* Store the result (in burts)		*/
+		p1[1] = d1;
+		p1[2] = d2;
+		p1[3] = d3;
+		p1[4] = d4;
+		p1[5] = d5;
+		p1[6] = d6;
+		p1[7] = d7;
+		p1 += 8;
+		p2 += 8;
+		p3 += 8;
+	} while (--lines > 0);
+}
+
+static void
+xor_32regs_p_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	    unsigned long *p3, unsigned long *p4)
+{
+	long lines = bytes / (sizeof (long)) / 8;
+
+	prefetchw(p1);
+	prefetch(p2);
+	prefetch(p3);
+	prefetch(p4);
+
+	do {
+		register long d0, d1, d2, d3, d4, d5, d6, d7;
+
+		prefetchw(p1+8);
+		prefetch(p2+8);
+		prefetch(p3+8);
+		prefetch(p4+8);
+
+		d0 = p1[0];	/* Pull the stuff into registers	*/
+		d1 = p1[1];	/*  ... in bursts, if possible.		*/
+		d2 = p1[2];
+		d3 = p1[3];
+		d4 = p1[4];
+		d5 = p1[5];
+		d6 = p1[6];
+		d7 = p1[7];
+		d0 ^= p2[0];
+		d1 ^= p2[1];
+		d2 ^= p2[2];
+		d3 ^= p2[3];
+		d4 ^= p2[4];
+		d5 ^= p2[5];
+		d6 ^= p2[6];
+		d7 ^= p2[7];
+		d0 ^= p3[0];
+		d1 ^= p3[1];
+		d2 ^= p3[2];
+		d3 ^= p3[3];
+		d4 ^= p3[4];
+		d5 ^= p3[5];
+		d6 ^= p3[6];
+		d7 ^= p3[7];
+		d0 ^= p4[0];
+		d1 ^= p4[1];
+		d2 ^= p4[2];
+		d3 ^= p4[3];
+		d4 ^= p4[4];
+		d5 ^= p4[5];
+		d6 ^= p4[6];
+		d7 ^= p4[7];
+		p1[0] = d0;	/* Store the result (in burts)		*/
+		p1[1] = d1;
+		p1[2] = d2;
+		p1[3] = d3;
+		p1[4] = d4;
+		p1[5] = d5;
+		p1[6] = d6;
+		p1[7] = d7;
+		p1 += 8;
+		p2 += 8;
+		p3 += 8;
+		p4 += 8;
+	} while (--lines > 0);
+}
+
+static void
+xor_32regs_p_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	    unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+	long lines = bytes / (sizeof (long)) / 8;
+
+	prefetchw(p1);
+	prefetch(p2);
+	prefetch(p3);
+	prefetch(p4);
+	prefetch(p5);
+
+	do {
+		register long d0, d1, d2, d3, d4, d5, d6, d7;
+
+		prefetchw(p1+8);
+		prefetch(p2+8);
+		prefetch(p3+8);
+		prefetch(p4+8);
+		prefetch(p5+8);
+
+		d0 = p1[0];	/* Pull the stuff into registers	*/
+		d1 = p1[1];	/*  ... in bursts, if possible.		*/
+		d2 = p1[2];
+		d3 = p1[3];
+		d4 = p1[4];
+		d5 = p1[5];
+		d6 = p1[6];
+		d7 = p1[7];
+		d0 ^= p2[0];
+		d1 ^= p2[1];
+		d2 ^= p2[2];
+		d3 ^= p2[3];
+		d4 ^= p2[4];
+		d5 ^= p2[5];
+		d6 ^= p2[6];
+		d7 ^= p2[7];
+		d0 ^= p3[0];
+		d1 ^= p3[1];
+		d2 ^= p3[2];
+		d3 ^= p3[3];
+		d4 ^= p3[4];
+		d5 ^= p3[5];
+		d6 ^= p3[6];
+		d7 ^= p3[7];
+		d0 ^= p4[0];
+		d1 ^= p4[1];
+		d2 ^= p4[2];
+		d3 ^= p4[3];
+		d4 ^= p4[4];
+		d5 ^= p4[5];
+		d6 ^= p4[6];
+		d7 ^= p4[7];
+		d0 ^= p5[0];
+		d1 ^= p5[1];
+		d2 ^= p5[2];
+		d3 ^= p5[3];
+		d4 ^= p5[4];
+		d5 ^= p5[5];
+		d6 ^= p5[6];
+		d7 ^= p5[7];
+		p1[0] = d0;	/* Store the result (in burts)		*/
+		p1[1] = d1;
+		p1[2] = d2;
+		p1[3] = d3;
+		p1[4] = d4;
+		p1[5] = d5;
+		p1[6] = d6;
+		p1[7] = d7;
+		p1 += 8;
+		p2 += 8;
+		p3 += 8;
+		p4 += 8;
+		p5 += 8;
+	} while (--lines > 0);
+}
+
 static struct xor_block_template xor_block_8regs = {
 	name: "8regs",
 	do_2: xor_8regs_2,
@@ -315,8 +675,26 @@
 	do_5: xor_32regs_5,
 };
 
+static struct xor_block_template xor_block_8regs_p = {
+	name: "8regs_prefetch",
+	do_2: xor_8regs_p_2,
+	do_3: xor_8regs_p_3,
+	do_4: xor_8regs_p_4,
+	do_5: xor_8regs_p_5,
+};
+
+static struct xor_block_template xor_block_32regs_p = {
+	name: "32regs_prefetch",
+	do_2: xor_32regs_p_2,
+	do_3: xor_32regs_p_3,
+	do_4: xor_32regs_p_4,
+	do_5: xor_32regs_p_5,
+};
+
 #define XOR_TRY_TEMPLATES			\
 	do {					\
 		xor_speed(&xor_block_8regs);	\
+		xor_speed(&xor_block_8regs_p);	\
 		xor_speed(&xor_block_32regs);	\
+		xor_speed(&xor_block_32regs_p);	\
 	} while (0)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/apicdef.h linux.20pre10-ac2/include/asm-i386/apicdef.h
--- linux.20pre10/include/asm-i386/apicdef.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/apicdef.h	2002-09-18 14:26:33.000000000 +0100
@@ -11,8 +11,10 @@
 #define		APIC_DEFAULT_PHYS_BASE	0xfee00000
  
 #define		APIC_ID		0x20
-#define			APIC_ID_MASK		(0x0F<<24)
-#define			GET_APIC_ID(x)		(((x)>>24)&0x0F)
+#define			APIC_ID_MASK		(0xFF<<24)
+#define			GET_APIC_ID(x)		(((x)>>24)&0xFF)
+#define				XAPIC_VER_LOW	0x14	/* Version num range */
+#define				XAPIC_VER_HIGH	0x1F
 #define		APIC_LVR	0x30
 #define			APIC_LVR_MASK		0xFF00FF
 #define			GET_APIC_VERSION(x)	((x)&0xFF)
@@ -32,6 +34,8 @@
 #define			SET_APIC_LOGICAL_ID(x)	(((x)<<24))
 #define			APIC_ALL_CPUS		0xFF
 #define		APIC_DFR	0xE0
+#define			APIC_DFR_CLUSTER	0x0FFFFFFFul	/* Clustered */
+#define			APIC_DFR_FLAT		0xFFFFFFFFul	/* Flat mode */
 #define		APIC_SPIV	0xF0
 #define			APIC_SPIV_FOCUS_DISABLED	(1<<9)
 #define			APIC_SPIV_APIC_ENABLED		(1<<8)
@@ -57,6 +61,7 @@
 #define			APIC_INT_LEVELTRIG	0x08000
 #define			APIC_INT_ASSERT		0x04000
 #define			APIC_ICR_BUSY		0x01000
+#define			APIC_DEST_PHYSICAL	0x00000
 #define			APIC_DEST_LOGICAL	0x00800
 #define			APIC_DM_FIXED		0x00000
 #define			APIC_DM_LOWEST		0x00100
@@ -107,7 +112,14 @@
 
 #define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
 
-#define MAX_IO_APICS 8
+#ifdef CONFIG_MULTIQUAD
+#define MAX_IO_APICS	32
+#else
+#define MAX_IO_APICS	8
+#endif
+
+#define		APIC_BROADCAST_ID_XAPIC		0xFF
+#define 	APIC_BROADCAST_ID_APIC		0x0F
 
 /*
  * the local APIC register structure, memory mapped. Not terribly well
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/apic.h linux.20pre10-ac2/include/asm-i386/apic.h
--- linux.20pre10/include/asm-i386/apic.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/apic.h	2002-10-09 22:15:47.000000000 +0100
@@ -85,7 +85,6 @@
 extern struct pm_dev *apic_pm_register(pm_dev_t, unsigned long, pm_callback);
 extern void apic_pm_unregister(struct pm_dev*);
 
-extern unsigned int apic_timer_irqs [NR_CPUS];
 extern int check_nmi_watchdog (void);
 
 extern unsigned int nmi_watchdog;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/bitops.h linux.20pre10-ac2/include/asm-i386/bitops.h
--- linux.20pre10/include/asm-i386/bitops.h	2002-10-09 21:44:49.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/bitops.h	2002-09-18 14:26:33.000000000 +0100
@@ -6,6 +6,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/compiler.h>
 
 /*
  * These have to be done with inline assembly: that way the bit-setting
@@ -75,6 +76,14 @@
 		:"=m" (ADDR)
 		:"Ir" (nr));
 }
+
+static __inline__ void __clear_bit(int nr, volatile void * addr)
+{
+	__asm__ __volatile__(
+		"btrl %1,%0"
+		:"=m" (ADDR)
+		:"Ir" (nr));
+}
 #define smp_mb__before_clear_bit()	barrier()
 #define smp_mb__after_clear_bit()	barrier()
 
@@ -284,6 +293,34 @@
 }
 
 /**
+ * find_first_bit - find the first set bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum size to search
+ *
+ * Returns the bit-number of the first set bit, not the number of the byte
+ * containing a bit.
+ */
+static __inline__ int find_first_bit(void * addr, unsigned size)
+{
+	int d0, d1;
+	int res;
+
+	/* This looks at memory. Mark it volatile to tell gcc not to move it around */
+	__asm__ __volatile__(
+		"xorl %%eax,%%eax\n\t"
+		"repe; scasl\n\t"
+		"jz 1f\n\t"
+		"leal -4(%%edi),%%edi\n\t"
+		"bsfl (%%edi),%%eax\n"
+		"1:\tsubl %%ebx,%%edi\n\t"
+		"shll $3,%%edi\n\t"
+		"addl %%edi,%%eax"
+		:"=a" (res), "=&c" (d0), "=&D" (d1)
+		:"1" ((size + 31) >> 5), "2" (addr), "b" (addr));
+	return res;
+}
+
+/**
  * find_next_zero_bit - find the first zero bit in a memory region
  * @addr: The address to base the search on
  * @offset: The bitnumber to start searching at
@@ -296,7 +333,7 @@
 	
 	if (bit) {
 		/*
-		 * Look for zero in first byte
+		 * Look for zero in the first 32 bits.
 		 */
 		__asm__("bsfl %1,%0\n\t"
 			"jne 1f\n\t"
@@ -317,6 +354,39 @@
 }
 
 /**
+ * find_next_bit - find the first set bit in a memory region
+ * @addr: The address to base the search on
+ * @offset: The bitnumber to start searching at
+ * @size: The maximum size to search
+ */
+static __inline__ int find_next_bit (void * addr, int size, int offset)
+{
+	unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
+	int set = 0, bit = offset & 31, res;
+	
+	if (bit) {
+		/*
+		 * Look for nonzero in the first 32 bits:
+		 */
+		__asm__("bsfl %1,%0\n\t"
+			"jne 1f\n\t"
+			"movl $32, %0\n"
+			"1:"
+			: "=r" (set)
+			: "r" (*p >> bit));
+		if (set < (32 - bit))
+			return set + offset;
+		set = 32 - bit;
+		p++;
+	}
+	/*
+	 * No set bit yet, search remaining full words for a bit
+	 */
+	res = find_first_bit (p, size - 32 * (p - (unsigned long *) addr));
+	return (offset + set + res);
+}
+
+/**
  * ffz - find first zero in word.
  * @word: The word to search
  *
@@ -330,8 +400,47 @@
 	return word;
 }
 
+/**
+ * __ffs - find first bit in word.
+ * @word: The word to search
+ *
+ * Undefined if no bit exists, so code should check against 0 first.
+ */
+static __inline__ unsigned long __ffs(unsigned long word)
+{
+	__asm__("bsfl %1,%0"
+		:"=r" (word)
+		:"rm" (word));
+	return word;
+}
+
+/*
+ * fls: find last bit set.
+ */
+
+#define fls(x) generic_fls(x)
+
 #ifdef __KERNEL__
 
+/*
+ * Every architecture must define this function. It's the fastest
+ * way of searching a 140-bit bitmap where the first 100 bits are
+ * unlikely to be set. It's guaranteed that at least one of the 140
+ * bits is cleared.
+ */
+static inline int _sched_find_first_bit(unsigned long *b)
+{
+	if (unlikely(b[0]))
+		return __ffs(b[0]);
+	if (unlikely(b[1]))
+		return __ffs(b[1]) + 32;
+	if (unlikely(b[2]))
+		return __ffs(b[2]) + 64;
+	if (b[3])
+		return __ffs(b[3]) + 96;
+	return __ffs(b[4]) + 128;
+}
+
 /**
  * ffs - find first bit set
  * @x: the word to search
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/desc.h linux.20pre10-ac2/include/asm-i386/desc.h
--- linux.20pre10/include/asm-i386/desc.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/desc.h	2002-08-26 14:24:47.000000000 +0100
@@ -18,23 +18,31 @@
  *   9 - APM BIOS support
  *  10 - APM BIOS support
  *  11 - APM BIOS support
+ *  12 - PNPBIOS support
+ *  13 - PNPBIOS support
+ *  14 - PNPBIOS support
+ *  15 - PNPBIOS support
+ *  16 - PNPBIOS support
+ *  17 - not used
+ *  18 - not used
+ *  19 - not used
  *
  * The TSS+LDT descriptors are spread out a bit so that every CPU
  * has an exclusive cacheline for the per-CPU TSS and LDT:
  *
- *  12 - CPU#0 TSS                          <-- new cacheline 
- *  13 - CPU#0 LDT
- *  14 - not used 
- *  15 - not used 
- *  16 - CPU#1 TSS                          <-- new cacheline 
- *  17 - CPU#1 LDT
- *  18 - not used 
- *  19 - not used 
+ *  20 - CPU#0 TSS                          <-- new cacheline 
+ *  21 - CPU#0 LDT
+ *  22 - not used 
+ *  23 - not used 
+ *  24 - CPU#1 TSS                          <-- new cacheline 
+ *  25 - CPU#1 LDT
+ *  26 - not used 
+ *  27 - not used 
  *  ... NR_CPUS per-CPU TSS+LDT's if on SMP
  *
  * Entry into gdt where to find first TSS.
  */
-#define __FIRST_TSS_ENTRY 12
+#define __FIRST_TSS_ENTRY 20
 #define __FIRST_LDT_ENTRY (__FIRST_TSS_ENTRY+1)
 
 #define __TSS(n) (((n)<<2) + __FIRST_TSS_ENTRY)
@@ -79,13 +87,13 @@
 /*
  * load one particular LDT into the current CPU
  */
-static inline void load_LDT (struct mm_struct *mm)
+static inline void load_LDT (mm_context_t *pc)
 {
 	int cpu = smp_processor_id();
-	void *segments = mm->context.segments;
-	int count = LDT_ENTRIES;
+	void *segments = pc->ldt;
+	int count = pc->size;
 
-	if (!segments) {
+	if (!count) {
 		segments = &default_ldt[0];
 		count = 5;
 	}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/hardirq.h linux.20pre10-ac2/include/asm-i386/hardirq.h
--- linux.20pre10/include/asm-i386/hardirq.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/hardirq.h	2002-10-09 22:15:47.000000000 +0100
@@ -12,7 +12,11 @@
 	unsigned int __local_bh_count;
 	unsigned int __syscall_count;
 	struct task_struct * __ksoftirqd_task; /* waitqueue is too large */
+	unsigned long idle_timestamp;
 	unsigned int __nmi_count;	/* arch dependent */
+#if CONFIG_X86_LOCAL_APIC 	
+	unsigned int apic_timer_irqs;	/* arch dependent */
+#endif
 } ____cacheline_aligned irq_cpustat_t;
 
 #include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/hdreg.h linux.20pre10-ac2/include/asm-i386/hdreg.h
--- linux.20pre10/include/asm-i386/hdreg.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/hdreg.h	2002-08-15 16:46:17.000000000 +0100
@@ -7,6 +7,7 @@
 #ifndef __ASMi386_HDREG_H
 #define __ASMi386_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+//typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMi386_HDREG_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/ide.h linux.20pre10-ac2/include/asm-i386/ide.h
--- linux.20pre10/include/asm-i386/ide.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/ide.h	2002-09-18 14:26:33.000000000 +0100
@@ -23,8 +23,6 @@
 # endif
 #endif
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
@@ -79,6 +77,7 @@
 	int index;
 
 	for(index = 0; index < MAX_HWIFS; index++) {
+		memset(&hw, 0, sizeof hw);
 		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
 		hw.irq = ide_default_irq(ide_default_io_base(index));
 		ide_register_hw(&hw, NULL);
@@ -86,43 +85,6 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		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 */
-	} b;
-} control_t;
-
-#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 -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/io_apic.h linux.20pre10-ac2/include/asm-i386/io_apic.h
--- linux.20pre10/include/asm-i386/io_apic.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/io_apic.h	2002-09-18 14:26:33.000000000 +0100
@@ -97,7 +97,7 @@
 extern int mp_irq_entries;
 
 /* MP IRQ source entries */
-extern struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
+extern struct mpc_config_intsrc *mp_irqs;
 
 /* non-0 if default (table-less) MP configuration */
 extern int mpc_default_type;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/ioctls.h linux.20pre10-ac2/include/asm-i386/ioctls.h
--- linux.20pre10/include/asm-i386/ioctls.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/ioctls.h	2002-08-06 15:41:52.000000000 +0100
@@ -67,6 +67,7 @@
 #define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
 #define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
 #define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+#define FIOQSIZE	0x5460
 
 /* Used for packet mode */
 #define TIOCPKT_DATA		 0
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/mmu_context.h linux.20pre10-ac2/include/asm-i386/mmu_context.h
--- linux.20pre10/include/asm-i386/mmu_context.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/mmu_context.h	2002-10-09 22:15:47.000000000 +0100
@@ -7,10 +7,12 @@
 #include <asm/pgalloc.h>
 
 /*
- * possibly do the LDT unload here?
+ * hooks to add arch specific data into the mm struct.
+ * Note that destroy_context is called even if init_new_context
+ * fails.
  */
-#define destroy_context(mm)		do { } while(0)
-#define init_new_context(tsk,mm)	0
+int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
+void destroy_context(struct mm_struct *mm);
 
 #ifdef CONFIG_SMP
 
@@ -27,22 +29,21 @@
 
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu)
 {
-	if (prev != next) {
+	if (likely(prev != next)) {
 		/* stop flush ipis for the previous mm */
 		clear_bit(cpu, &prev->cpu_vm_mask);
-		/*
-		 * Re-load LDT if necessary
-		 */
-		if (prev->context.segments != next->context.segments)
-			load_LDT(next);
 #ifdef CONFIG_SMP
 		cpu_tlbstate[cpu].state = TLBSTATE_OK;
 		cpu_tlbstate[cpu].active_mm = next;
 #endif
 		set_bit(cpu, &next->cpu_vm_mask);
-		set_bit(cpu, &next->context.cpuvalid);
 		/* Re-load page tables */
 		load_cr3(next->pgd);
+	 	/* load_LDT, if either the previous or next thread
+		 * has a non-default LDT.
+		 */
+		if (unlikely(next->context.size+prev->context.size))
+			load_LDT(&next->context);
 	}
 #ifdef CONFIG_SMP
 	else {
@@ -54,9 +55,8 @@
 			 * tlb flush IPI delivery. We must reload %cr3.
 			 */
 			load_cr3(next->pgd);
+			load_LDT(&next->context);
 		}
-		if (!test_and_set_bit(cpu, &next->context.cpuvalid))
-			load_LDT(next);
 	}
 #endif
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/mmu.h linux.20pre10-ac2/include/asm-i386/mmu.h
--- linux.20pre10/include/asm-i386/mmu.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/mmu.h	2002-08-26 14:24:47.000000000 +0100
@@ -4,10 +4,13 @@
 /*
  * The i386 doesn't have a mmu context, but
  * we put the segment information here.
+ *
+ * cpu_vm_mask is used to optimize ldt flushing.
  */
 typedef struct { 
-	void *segments;
-	unsigned long cpuvalid;
+	int size;
+	struct semaphore sem;
+	void *	ldt;
 } mm_context_t;
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/mpspec.h linux.20pre10-ac2/include/asm-i386/mpspec.h
--- linux.20pre10/include/asm-i386/mpspec.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/mpspec.h	2002-09-18 14:26:33.000000000 +0100
@@ -14,7 +14,8 @@
 #define SMP_MAGIC_IDENT	(('_'<<24)|('P'<<16)|('M'<<8)|'_')
 
 /*
- * a maximum of 16 APICs with the current APIC ID architecture.
+ * a maximum of 16 APICs with the classic APIC ID architecture.
+ * xAPICs can have up to 256.  SAPICs have 16 ID bits.
  */
 #ifdef CONFIG_MULTIQUAD
 #define MAX_APICS 256
@@ -184,11 +185,7 @@
  *	7	2 CPU MCA+PCI
  */
 
-#ifdef CONFIG_MULTIQUAD
-#define MAX_IRQ_SOURCES 512
-#else /* !CONFIG_MULTIQUAD */
 #define MAX_IRQ_SOURCES 256
-#endif /* CONFIG_MULTIQUAD */
 
 #define MAX_MP_BUSSES 32
 enum mp_bustype {
@@ -197,24 +194,23 @@
 	MP_BUS_PCI,
 	MP_BUS_MCA
 };
-extern int mp_bus_id_to_type [MAX_MP_BUSSES];
-extern int mp_bus_id_to_node [MAX_MP_BUSSES];
-extern int mp_bus_id_to_local [MAX_MP_BUSSES];
+extern int *mp_bus_id_to_type;
+extern int *mp_bus_id_to_node;
+extern int *mp_bus_id_to_local;
+extern int *mp_bus_id_to_pci_bus;
 extern int quad_local_to_mp_bus_id [NR_CPUS/4][4];
-extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
 
 extern unsigned int boot_cpu_physical_apicid;
+extern unsigned int boot_cpu_logical_apicid;
 extern unsigned long phys_cpu_present_map;
 extern int smp_found_config;
 extern void find_smp_config (void);
 extern void get_smp_config (void);
 extern int nr_ioapics;
 extern int apic_version [MAX_APICS];
-extern int mp_bus_id_to_type [MAX_MP_BUSSES];
 extern int mp_irq_entries;
-extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES];
+extern struct mpc_config_intsrc *mp_irqs;
 extern int mpc_default_type;
-extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES];
 extern int mp_current_pci_id;
 extern unsigned long mp_lapic_addr;
 extern int pic_mode;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/msr.h linux.20pre10-ac2/include/asm-i386/msr.h
--- linux.20pre10/include/asm-i386/msr.h	2002-10-09 21:44:49.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/msr.h	2002-10-10 23:54:36.000000000 +0100
@@ -114,5 +114,7 @@
 /* Transmeta defined MSRs */
 #define MSR_TMTA_LONGRUN_CTRL		0x80868010
 #define MSR_TMTA_LONGRUN_FLAGS		0x80868011
+#define MSR_TMTA_LRTI_READOUT		0x80868018
+#define MSR_TMTA_LRTI_VOLT_MHZ		0x8086801a
 
 #endif /* __ASM_MSR_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/pci.h linux.20pre10-ac2/include/asm-i386/pci.h
--- linux.20pre10/include/asm-i386/pci.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/pci.h	2002-10-11 00:35:04.000000000 +0100
@@ -103,7 +103,9 @@
 	if (direction == PCI_DMA_NONE)
 		out_of_line_bug();
 
-	return (dma_addr_t)(page - mem_map) * PAGE_SIZE + offset;
+	return ((dma_addr_t)(page - mem_map) *
+		(dma_addr_t) PAGE_SIZE +
+		(dma_addr_t) offset);
 }
 
 static inline void pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address,
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/pgalloc.h linux.20pre10-ac2/include/asm-i386/pgalloc.h
--- linux.20pre10/include/asm-i386/pgalloc.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/pgalloc.h	2002-10-09 22:15:47.000000000 +0100
@@ -224,7 +224,7 @@
 {
 	struct mm_struct *active_mm;
 	int state;
-};
+} ____cacheline_aligned;
 extern struct tlb_state cpu_tlbstate[NR_CPUS];
 
 #endif /* CONFIG_SMP */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/processor.h linux.20pre10-ac2/include/asm-i386/processor.h
--- linux.20pre10/include/asm-i386/processor.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/processor.h	2002-09-29 20:34:20.000000000 +0100
@@ -96,7 +96,13 @@
 
 extern void identify_cpu(struct cpuinfo_x86 *);
 extern void print_cpu_info(struct cpuinfo_x86 *);
-extern void dodgy_tsc(void);
+extern int select_tsc(void);
+
+#define TSC_NONE	0	/* No TSC available, fall back to PIT */
+#define TSC_CPU		1	/* Use processor TSC */
+#define TSC_VISWS	2	/* VISWS hardware */
+#define TSC_CYCLONE	3	/* IBM cyclone timer */
+#define TSC_HPET	4	/* Intel/AMD HPET */
 
 /*
  * EFLAGS bits
@@ -435,9 +441,12 @@
  */
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
-/* Copy and release all segment info associated with a VM */
-extern void copy_segments(struct task_struct *p, struct mm_struct * mm);
-extern void release_segments(struct mm_struct * mm);
+/* Copy and release all segment info associated with a VM
+ * Unusable due to lack of error handling, use {init_new,destroy}_context
+ * instead.
+ */
+static inline void copy_segments(struct task_struct *p, struct mm_struct * mm) { }
+static inline void release_segments(struct mm_struct * mm) { }
 
 /*
  * Return saved PC of a blocked thread.
@@ -510,4 +519,10 @@
 
 #endif
 
+/* We have an SMP load balancer */
+
+/* If you are seeing weird crashes please retest with this commented out */
+
+// #define ARCH_HAS_SMP_BALANCE
+
 #endif /* __ASM_I386_PROCESSOR_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/rmap.h linux.20pre10-ac2/include/asm-i386/rmap.h
--- linux.20pre10/include/asm-i386/rmap.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/rmap.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,7 @@
+#ifndef _I386_RMAP_H
+#define _I386_RMAP_H
+
+/* nothing to see, move along */
+#include <asm-generic/rmap.h>
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/smp_balance.h linux.20pre10-ac2/include/asm-i386/smp_balance.h
--- linux.20pre10/include/asm-i386/smp_balance.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/smp_balance.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,43 @@
+#ifndef _ASM_SMP_BALANCE_H
+#define _ASM_SMP_BALANCE_H
+
+/*
+ * Find any idle processor package (i.e. both virtual processors are idle)
+ */
+
+static inline int find_idle_package(int this_cpu)
+{
+	int i = this_cpu + 1;
+
+	if (i == smp_num_cpus)
+		i = 0;
+
+	while (i != this_cpu) {
+		int physical, sibling;
+		physical = cpu_logical_map(i);
+		sibling = cpu_sibling_map[physical];
+
+		if (i++ == smp_num_cpus)
+			i = 0;
+		if (idle_cpu(physical) && idle_cpu(sibling))
+			return physical;
+	}
+	return -1;                      /* not found */
+}
+
+static inline int arch_load_balance(int this_cpu, int idle)
+{
+	/* Special hack for hyperthreading */
+       if (smp_num_siblings > 1 && idle && !idle_cpu(cpu_sibling_map[this_cpu])) {
+               int found;
+               struct runqueue *rq_target;
+
+               if ((found = find_idle_package(this_cpu)) >= 0 ) {
+                       rq_target = cpu_rq(found);
+                       resched_task(rq_target->idle);
+                       return 1;
+               }
+       }
+       return 0;
+}
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/smpboot.h linux.20pre10-ac2/include/asm-i386/smpboot.h
--- linux.20pre10/include/asm-i386/smpboot.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/smpboot.h	2002-10-09 22:15:47.000000000 +0100
@@ -1,62 +1,55 @@
 #ifndef __ASM_SMPBOOT_H
 #define __ASM_SMPBOOT_H
 
-#ifndef clustered_apic_mode
- #ifdef CONFIG_MULTIQUAD
-  #define clustered_apic_mode (1)
- #else /* !CONFIG_MULTIQUAD */
-  #define clustered_apic_mode (0)
- #endif /* CONFIG_MULTIQUAD */
-#endif 
- 
-#ifdef CONFIG_MULTIQUAD
- #define TRAMPOLINE_LOW phys_to_virt(0x8)
- #define TRAMPOLINE_HIGH phys_to_virt(0xa)
-#else /* !CONFIG_MULTIQUAD */
- #define TRAMPOLINE_LOW phys_to_virt(0x467)
- #define TRAMPOLINE_HIGH phys_to_virt(0x469)
-#endif /* CONFIG_MULTIQUAD */
-
-#ifdef CONFIG_MULTIQUAD
- #define boot_cpu_apicid boot_cpu_logical_apicid
-#else /* !CONFIG_MULTIQUAD */
- #define boot_cpu_apicid boot_cpu_physical_apicid
-#endif /* CONFIG_MULTIQUAD */
+#ifndef __ASM_SMP_H
+#include "asm/smp.h"
+#endif
+
+#define TRAMPOLINE_LOW phys_to_virt(clustered_apic_logical?0x8:0x467)
+#define TRAMPOLINE_HIGH phys_to_virt(clustered_apic_logical?0xa:0x469)
+
+extern unsigned char raw_phys_apicid[NR_CPUS];
 
 /*
- * How to map from the cpu_present_map
+ * To build the logical APIC ID for each CPU we have three cases:
+ *  1) Normal flat mode:  use a bitmap of the CPU numbers
+ *  2) Logical multi-quad (NUMA-Q):  do nothing, the BIOS has set it up
+ *  3) Physical multi-quad (xAPIC clusters):  convert the Intel standard
+ *	physical APIC ID to a cluster nibble/cpu bitmap nibble
+ *
+ ***	mps_cpu (index number):   0,  1,  2,  3,  4,  5,  6,  7,  8,  9, ... 
+ ***  CPUs have xAPIC phys IDs:  00, 01, 02, 03, 10, 11, 12, 13, 20, 21, ... 
+ ***		its logical ID:  01, 02, 04, 08, 11, 12, 14, 18, 21, 22, ... 
  */
-#ifdef CONFIG_MULTIQUAD
- #define cpu_present_to_apicid(mps_cpu) ( ((mps_cpu/4)*16) + (1<<(mps_cpu%4)) )
-#else /* !CONFIG_MULTIQUAD */
- #define cpu_present_to_apicid(apicid) (apicid)
-#endif /* CONFIG_MULTIQUAD */
+ 
+#define physical_to_logical_apicid(phys_apic) ( (1ul << ((phys_apic) & 0x3)) | ((phys_apic) & APIC_DEST_CLUSTER_MASK) )
+
+static inline int cpu_present_to_apicid(int mps_cpu)
+{
+	if(clustered_apic_logical)
+		return (mps_cpu/4)*16 + (1<<(mps_cpu%4));
+	if(clustered_apic_physical)
+		return raw_phys_apicid[mps_cpu];
+	return 1 << mps_cpu;
+}
+
+static inline unsigned long apicid_to_phys_cpu_present(int apicid)
+{
+	if(clustered_apic_mode)
+		return 1UL << (((apicid >> 4) << 2) + (apicid & 0x3));
+	return 1UL << apicid;
+}
 
 /*
  * Mappings between logical cpu number and logical / physical apicid
- * The first four macros are trivial, but it keeps the abstraction consistent
+ * The first two macros are trivial, but it keeps the abstraction consistent
  */
-extern volatile int logical_apicid_2_cpu[];
-extern volatile int cpu_2_logical_apicid[];
-extern volatile int physical_apicid_2_cpu[];
-extern volatile int cpu_2_physical_apicid[];
-
-#define logical_apicid_to_cpu(apicid) logical_apicid_2_cpu[apicid]
-#define cpu_to_logical_apicid(cpu) cpu_2_logical_apicid[cpu]
-#define physical_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid]
-#define cpu_to_physical_apicid(cpu) cpu_2_physical_apicid[cpu]
-#ifdef CONFIG_MULTIQUAD			/* use logical IDs to bootstrap */
-#define boot_apicid_to_cpu(apicid) logical_apicid_2_cpu[apicid]
-#define cpu_to_boot_apicid(cpu) cpu_2_logical_apicid[cpu]
-#else /* !CONFIG_MULTIQUAD */		/* use physical IDs to bootstrap */
-#define boot_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid]
-#define cpu_to_boot_apicid(cpu) cpu_2_physical_apicid[cpu]
-#endif /* CONFIG_MULTIQUAD */
-
-
-#ifdef CONFIG_MULTIQUAD
-#else /* !CONFIG_MULTIQUAD */
-#endif /* CONFIG_MULTIQUAD */
+
+extern volatile u8 cpu_2_logical_apicid[];
+extern volatile u8 cpu_2_physical_apicid[];
+
+#define cpu_to_logical_apicid(cpu) (int)cpu_2_logical_apicid[cpu]
+#define cpu_to_physical_apicid(cpu) (int)cpu_2_physical_apicid[cpu]
 
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/smp.h linux.20pre10-ac2/include/asm-i386/smp.h
--- linux.20pre10/include/asm-i386/smp.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/smp.h	2002-10-09 22:15:47.000000000 +0100
@@ -22,37 +22,54 @@
 #endif
 #endif
 
-#ifdef CONFIG_SMP
+#ifdef CONFIG_X86_LOCAL_APIC
 # ifdef CONFIG_MULTIQUAD
-#  define TARGET_CPUS 0xf     /* all CPUs in *THIS* quad */
-#  define INT_DELIVERY_MODE 0     /* physical delivery on LOCAL quad */
+#define		TARGET_CPUS			(__target_cpus())
+#define		INT_DEST_ADDR_MODE		(int_dest_addr_mode)
+#define		INT_DELIVERY_MODE		(int_delivery_mode)
 # else
-#  define TARGET_CPUS cpu_online_map
-#  define INT_DELIVERY_MODE 1     /* logical delivery broadcast to all procs */
+#define		TARGET_CPUS			cpu_online_map
+#define		INT_DEST_ADDR_MODE		APIC_DEST_LOGICAL	/* logical delivery */
+#define		INT_DELIVERY_MODE		(dest_LowestPrio)
 # endif
 #else
-# define INT_DELIVERY_MODE 1     /* logical delivery */
-# define TARGET_CPUS 0x01
+#define		clustered_apic_mode		(0)
+#define		apic_broadcast_id		(0x0Fu)
+#define		esr_disable			(0)
+#define		logical_cpu_present_map		(1)
+#define		TARGET_CPUS			0x01
+#define		INT_DEST_ADDR_MODE		0x800u	/* logical delivery */
+#define 	INT_DELIVERY_MODE		(1)	/* dest_LowestPrio */
 #endif
 
-#ifndef clustered_apic_mode
- #ifdef CONFIG_MULTIQUAD
-  #define clustered_apic_mode (1)
-  #define esr_disable (1)
- #else /* !CONFIG_MULTIQUAD */
-  #define clustered_apic_mode (0)
-  #define esr_disable (0)
- #endif /* CONFIG_MULTIQUAD */
-#endif 
+#define APIC_DEST_CLUSTER_MASK	0xF0u	/* Destination masks */
+#define APIC_DEST_CPUS_MASK	0x0Fu	/* when clustered.   */
+
+#define CLUSTERED_APIC_LOGICAL	0x01
+#define CLUSTERED_APIC_PHYSICAL	0x02
+#define clustered_apic_logical	(clustered_apic_mode & CLUSTERED_APIC_LOGICAL)
+#define clustered_apic_physical	(clustered_apic_mode & CLUSTERED_APIC_PHYSICAL)
 
-#ifdef CONFIG_SMP
 #ifndef __ASSEMBLY__
 
+#ifdef CONFIG_X86_LOCAL_APIC
+
+extern unsigned char clustered_apic_mode;
+extern unsigned char esr_disable;
+extern unsigned char int_delivery_mode;
+extern unsigned int int_dest_addr_mode;
+extern unsigned int apic_broadcast_id;
+
+#endif
+
+#ifdef CONFIG_SMP
+
 /*
  * Private routines/data
  */
  
 extern void smp_alloc_memory(void);
+extern unsigned long logical_cpu_present_map;
 extern unsigned long phys_cpu_present_map;
 extern unsigned long cpu_online_map;
 extern volatile unsigned long smp_invalidate_needed;
@@ -63,6 +80,7 @@
 extern void smp_flush_tlb(void);
 extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
 extern void smp_send_reschedule(int cpu);
+extern void smp_send_reschedule_all(void);
 extern void smp_invalidate_rcv(void);		/* Process an NMI */
 extern void (*mtrr_hook) (void);
 extern void zap_low_mappings (void);
@@ -81,11 +99,14 @@
 	return cpu;
 }
 
+#define cpu_online(cpu) (cpu_online_map & (1<<(cpu)))
+
 /*
  * Some lowlevel functions might want to know about
  * the real APIC ID <-> CPU # mapping.
  */
 #define MAX_APICID 256
+#define BAD_APICID 0xFFu
 extern volatile int cpu_to_physical_apicid[NR_CPUS];
 extern volatile int physical_apicid_to_cpu[MAX_APICID];
 extern volatile int cpu_to_logical_apicid[NR_CPUS];
@@ -104,7 +125,7 @@
  * so this is correct in the x86 case.
  */
 
-#define smp_processor_id() (current->processor)
+#define smp_processor_id() (current->cpu)
 
 static __inline int hard_smp_processor_id(void)
 {
@@ -118,21 +139,8 @@
 	return GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR));
 }
 
+#endif
 #endif /* !__ASSEMBLY__ */
 
 #define NO_PROC_ID		0xFF		/* No processor magic marker */
-
-/*
- *	This magic constant controls our willingness to transfer
- *	a process across CPUs. Such a transfer incurs misses on the L1
- *	cache, and on a P6 or P5 with multiple L2 caches L2 hits. My
- *	gut feeling is this will vary by board in value. For a board
- *	with separate L2 cache it probably depends also on the RSS, and
- *	for a board with shared L2 cache it ought to decay fast as other
- *	processes are run.
- */
- 
-#define PROC_CHANGE_PENALTY	15		/* Schedule penalty */
-
-#endif
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/spinlock.h linux.20pre10-ac2/include/asm-i386/spinlock.h
--- linux.20pre10/include/asm-i386/spinlock.h	2002-10-09 21:44:49.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/spinlock.h	2002-09-18 14:26:33.000000000 +0100
@@ -49,7 +49,7 @@
  * We make no fairness assumptions. They have a cost.
  */
 
-#define spin_is_locked(x)	(*(volatile signed char *)(&(x)->lock) <= 0)
+#define spin_is_locked(x)	(*(volatile char *)(&(x)->lock) <= 0)
 #define spin_unlock_wait(x)	do { barrier(); } while(spin_is_locked(x))
 
 #define spin_lock_string \
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-i386/system.h linux.20pre10-ac2/include/asm-i386/system.h
--- linux.20pre10/include/asm-i386/system.h	2002-10-09 21:44:49.000000000 +0100
+++ linux.20pre10-ac2/include/asm-i386/system.h	2002-09-18 14:26:33.000000000 +0100
@@ -12,25 +12,22 @@
 struct task_struct;	/* one of the stranger aspects of C forward declarations.. */
 extern void FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next));
 
-#define prepare_to_switch()	do { } while(0)
 #define switch_to(prev,next,last) do {					\
 	asm volatile("pushl %%esi\n\t"					\
 		     "pushl %%edi\n\t"					\
 		     "pushl %%ebp\n\t"					\
 		     "movl %%esp,%0\n\t"	/* save ESP */		\
-		     "movl %3,%%esp\n\t"	/* restore ESP */	\
+		     "movl %2,%%esp\n\t"	/* restore ESP */	\
 		     "movl $1f,%1\n\t"		/* save EIP */		\
-		     "pushl %4\n\t"		/* restore EIP */	\
+		     "pushl %3\n\t"		/* restore EIP */	\
 		     "jmp __switch_to\n"				\
 		     "1:\t"						\
 		     "popl %%ebp\n\t"					\
 		     "popl %%edi\n\t"					\
 		     "popl %%esi\n\t"					\
-		     :"=m" (prev->thread.esp),"=m" (prev->thread.eip),	\
-		      "=b" (last)					\
+		     :"=m" (prev->thread.esp),"=m" (prev->thread.eip)	\
 		     :"m" (next->thread.esp),"m" (next->thread.eip),	\
-		      "a" (prev), "d" (next),				\
-		      "b" (prev));					\
+		      "a" (prev), "d" (next));				\
 } while (0)
 
 #define _set_base(addr,base) do { unsigned long __pr; \
@@ -322,8 +319,18 @@
 /* used in the idle loop; sti takes one instruction cycle to complete */
 #define safe_halt()		__asm__ __volatile__("sti; hlt": : :"memory")
 
+#define __save_and_cli(x)	do { __save_flags(x); __cli(); } while(0);
+#define __save_and_sti(x)	do { __save_flags(x); __sti(); } while(0);
+
 /* For spinlocks etc */
+#if 0
 #define local_irq_save(x)	__asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
+#define local_irq_set(x)	__asm__ __volatile__("pushfl ; popl %0 ; sti":"=g" (x): /* no input */ :"memory")
+#else
+#define local_irq_save(x)	__save_and_cli(x)
+#define local_irq_set(x)	__save_and_sti(x)
+#endif
+
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -338,6 +345,8 @@
 #define sti() __global_sti()
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0);
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
 
 #else
 
@@ -345,6 +354,8 @@
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
+#define save_and_cli(x) __save_and_cli(x)
+#define save_and_sti(x) __save_and_sti(x)
 
 #endif
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-ia64/hdreg.h linux.20pre10-ac2/include/asm-ia64/hdreg.h
--- linux.20pre10/include/asm-ia64/hdreg.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-ia64/hdreg.h	2002-08-15 16:46:26.000000000 +0100
@@ -7,6 +7,7 @@
 #ifndef __ASM_IA64_HDREG_H
 #define __ASM_IA64_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+//typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASM_IA64_HDREG_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-ia64/ide.h linux.20pre10-ac2/include/asm-ia64/ide.h
--- linux.20pre10/include/asm-ia64/ide.h	2002-10-09 21:44:49.000000000 +0100
+++ linux.20pre10-ac2/include/asm-ia64/ide.h	2002-09-14 22:35:36.000000000 +0100
@@ -25,8 +25,6 @@
 # endif
 #endif
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
@@ -88,43 +86,6 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		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 */
-	} b;
-} control_t;
-
-#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 /* __ASM_IA64_IDE_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-ia64/ioctls.h linux.20pre10-ac2/include/asm-ia64/ioctls.h
--- linux.20pre10/include/asm-ia64/ioctls.h	2002-10-09 21:44:49.000000000 +0100
+++ linux.20pre10-ac2/include/asm-ia64/ioctls.h	2002-09-14 22:35:54.000000000 +0100
@@ -72,6 +72,7 @@
 #define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
 #define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
 #define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+#define FIOQSIZE	0x5460
 
 /* Used for packet mode */
 #define TIOCPKT_DATA		 0
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-ia64/io.h linux.20pre10-ac2/include/asm-ia64/io.h
--- linux.20pre10/include/asm-ia64/io.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-ia64/io.h	2002-08-30 00:03:09.000000000 +0100
@@ -272,18 +272,18 @@
 #define __outw		platform_outw
 #define __outl		platform_outl
 
-#define inb		__inb
-#define inw		__inw
-#define inl		__inl
-#define insb		__insb
-#define insw		__insw
-#define insl		__insl
-#define outb		__outb
-#define outw		__outw
-#define outl		__outl
-#define outsb		__outsb
-#define outsw		__outsw
-#define outsl		__outsl
+#define inb(a)		__inb(a)
+#define inw(a)		__inw(a)
+#define inl(a)		__inl(a)
+#define insb(a,b,c)	__insb(a,b,c)
+#define insw(a,b,c)	__insw(a,b,c)
+#define insl(a,b,c)	__insl(a,b,c)
+#define outb(a,b)	__outb(a,b)
+#define outw(a,b)	__outw(a,b)
+#define outl(a,b)	__outl(a,b)
+#define outsb(a,b,c)	__outsb(a,b,c)
+#define outsw(a,b,c)	__outsw(a,b,c)
+#define outsl(a,b,c)	__outsl(a,b,c)
 
 /*
  * The address passed to these functions are ioremap()ped already.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-ia64/rmap.h linux.20pre10-ac2/include/asm-ia64/rmap.h
--- linux.20pre10/include/asm-ia64/rmap.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/asm-ia64/rmap.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,7 @@
+#ifndef _IA64_RMAP_H
+#define _IA64_RMAP_H
+
+/* nothing to see, move along */
+#include <asm-generic/rmap.h>
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-ia64/system.h linux.20pre10-ac2/include/asm-ia64/system.h
--- linux.20pre10/include/asm-ia64/system.h	2002-10-09 21:44:49.000000000 +0100
+++ linux.20pre10-ac2/include/asm-ia64/system.h	2002-09-14 22:36:29.000000000 +0100
@@ -171,6 +171,15 @@
 						      : "p6", "p7", "memory")
 #endif /* !CONFIG_IA64_DEBUG_IRQ */
 
+#error andre hedrick screwed this up please help unscrew in order to clean up
+/*
+ * __save_and_sti(x) == __save_flags(x); ide__sti();
+ *                      __save_flags(x); __sti();
+ *
+ * local_irq_set(x) == __save_and_sti(x)
+ */
+
+
 #define local_irq_enable()	__asm__ __volatile__ (";; ssm psr.i;; srlz.d" ::: "memory")
 
 #define __cli()			local_irq_disable ()
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-ia64/termios.h linux.20pre10-ac2/include/asm-ia64/termios.h
--- linux.20pre10/include/asm-ia64/termios.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-ia64/termios.h	2002-09-30 17:41:00.000000000 +0100
@@ -44,6 +44,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 
 /* line disciplines */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-m68k/hdreg.h linux.20pre10-ac2/include/asm-m68k/hdreg.h
--- linux.20pre10/include/asm-m68k/hdreg.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-m68k/hdreg.h	2002-09-06 00:50:04.000000000 +0100
@@ -9,5 +9,6 @@
 
 typedef unsigned int   q40ide_ioreg_t;
 typedef unsigned char * ide_ioreg_t;
+//typedef unsigned long ide_ioreg_t;
 
 #endif /* _M68K_HDREG_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-m68k/ide.h linux.20pre10-ac2/include/asm-m68k/ide.h
--- linux.20pre10/include/asm-m68k/ide.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-m68k/ide.h	2002-08-19 23:44:26.000000000 +0100
@@ -50,6 +50,9 @@
 #define MAX_HWIFS	4	/* same as the other archs */
 #endif
 
+/*
+ * FIXME: IOPS struct calls needed for taskfile.
+ */
 
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
@@ -80,29 +83,6 @@
 {
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		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 or 1 */
-		unsigned head		: 4;	/* always zeros here */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-		unsigned reserved456	: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned bit0		: 1;
-	} b;
-} control_t;
-
 static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
 			unsigned long flags, const char *device, void *dev_id)
 {
@@ -190,22 +170,26 @@
 
 #define ADDR_TRANS_B(_addr_) (_addr_)
 #define ADDR_TRANS_W(_addr_) (_addr_)
+#define ADDR_TRANS_L(_addr_) (_addr_)
 
 #else
 
 #define ADDR_TRANS_B(_addr_) (MACH_IS_Q40 ? ((unsigned char *)Q40_ISA_IO_B(_addr_)) : (_addr_))
 #define ADDR_TRANS_W(_addr_) (MACH_IS_Q40 ? ((unsigned char *)Q40_ISA_IO_W(_addr_)) : (_addr_))
+#define ADDR_TRANS_L(_addr_) (MACH_IS_Q40 ? ((unsigned char *)Q40_ISA_IO_L(_addr_)) : (_addr_))
 #endif
 
-#define HAVE_ARCH_OUT_BYTE
+#define HAVE_ARCH_OUT_BYTE 1
 
 #define OUT_BYTE(v,p)	out_8(ADDR_TRANS_B((p)), (v))
 #define OUT_WORD(v,p)	out_be16(ADDR_TRANS_W((p)), (v))
+#define OUT_LONG(v,p)	out_be32(ADDR_TRANS_L((p)), (v))
 
-#define HAVE_ARCH_IN_BYTE
+#define HAVE_ARCH_IN_BYTE 1
 
 #define IN_BYTE(p)	in_8(ADDR_TRANS_B((p)))
 #define IN_WORD(p)	in_be16(ADDR_TRANS_W((p)))
+#define IN_LONG(p)	in_be32(ADDR_TRANS_L((p)))
 
 #define insw(port, buf, nr) raw_insw(ADDR_TRANS_W(port), buf, nr)
 #define outsw(port, buf, nr) raw_outsw(ADDR_TRANS_W(port), buf, nr)
@@ -227,19 +211,6 @@
 #endif /* CONFIG_ATARI || CONFIG_Q40 */
 
 
-#define T_CHAR          (0x0000)        /* char:  don't touch  */
-#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
-#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
-#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
-
-#define T_MASK_TYPE     (0xc000)
-#define T_MASK_COUNT    (0x3fff)
-
-#define D_CHAR(cnt)     (T_CHAR  | (cnt))
-#define D_SHORT(cnt)    (T_SHORT | (cnt))
-#define D_INT(cnt)      (T_INT   | (cnt))
-#define D_TEXT(cnt)     (T_TEXT  | (cnt))
-
 /* Q40 and Atari have byteswapped IDE bus and since many interesting
  * values in the identification string are text, chars and words they
  * happened to be almost correct without swapping.. However *_capacity 
@@ -248,83 +219,11 @@
 #define M68K_IDE_SWAPW  (MACH_IS_Q40 || MACH_IS_ATARI)
 #endif
 
-#if defined(CONFIG_AMIGA) || defined (CONFIG_MAC) || defined(M68K_IDE_SWAPW)
-static u_short driveid_types[] = {
-	D_SHORT(10),	/* config - vendor2 */
-	D_TEXT(20),	/* serial_no */
-	D_SHORT(3),	/* buf_type, buf_size - ecc_bytes */
-	D_TEXT(48),	/* fw_rev - model */
-	D_CHAR(2),	/* max_multsect - vendor3 */
-	D_SHORT(1),	/* dword_io */
-	D_CHAR(2),	/* vendor4 - capability */
-	D_SHORT(1),	/* reserved50 */
-	D_CHAR(4),	/* vendor5 - tDMA */
-	D_SHORT(4),	/* field_valid - cur_sectors */
-	D_INT(1),	/* cur_capacity */
-	D_CHAR(2),	/* multsect - multsect_valid */
-	D_INT(1),	/* lba_capacity */
-	D_SHORT(194)	/* dma_1word - reserved */
-};
-
-#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
-#endif /* CONFIG_AMIGA */
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-#if defined(CONFIG_AMIGA) || defined (CONFIG_MAC) || defined(M68K_IDE_SWAPW)
-   u_char *p = (u_char *)id;
-   int i, j, cnt;
-   u_char t;
-
-   if (!MACH_IS_AMIGA && !MACH_IS_MAC && !MACH_IS_Q40 && !MACH_IS_ATARI)
-   	return;
-#ifdef M68K_IDE_SWAPW
-   if (M68K_IDE_SWAPW)    /* fix bus byteorder first */
-      for (i=0; i < 512; i+=2) {
-	 t = p[i]; p[i] = p[i+1]; p[i+1] = t; 
-      }
-#endif
-   for (i = 0; i < num_driveid_types; i++) {
-      cnt = driveid_types[i] & T_MASK_COUNT;
-      switch (driveid_types[i] & T_MASK_TYPE) {
-         case T_CHAR:
-            p += cnt;
-            break;
-         case T_SHORT:
-            for (j = 0; j < cnt; j++) {
-	       t = p[0];
-	       p[0] = p[1];
-	       p[1] = t;
-               p += 2;
-            }
-            break;
-         case T_INT:
-            for (j = 0; j < cnt; j++) {
-	       t = p[0];
-	       p[0] = p[3];
-	       p[3] = t;
-	       t = p[1];
-	       p[1] = p[2];
-	       p[2] = t;
-               p += 4;
-            }
-            break;
-         case T_TEXT:
-            for (j = 0; j < cnt; j += 2) {
-	       t = p[0];
-	       p[0] = p[1];
-	       p[1] = t;
-               p += 2;
-            }
-            break;
-      }
-   }
-#endif /* CONFIG_AMIGA */
-}
+#ifdef CONFIG_ATARI
+#define IDE_ARCH_LOCK 1
 
 static __inline__ void ide_release_lock (int *ide_lock)
 {
-#ifdef CONFIG_ATARI
 	if (MACH_IS_ATARI) {
 		if (*ide_lock == 0) {
 			printk("ide_release_lock: bug\n");
@@ -333,12 +232,10 @@
 		*ide_lock = 0;
 		stdma_release();
 	}
-#endif /* CONFIG_ATARI */
 }
 
 static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *, struct pt_regs *), void *data)
 {
-#ifdef CONFIG_ATARI
 	if (MACH_IS_ATARI) {
 		if (*ide_lock == 0) {
 			if (in_interrupt() > 0)
@@ -347,39 +244,8 @@
 			*ide_lock = 1;
 		}
 	}
-#endif /* CONFIG_ATARI */
 }
-
-#define ide_ack_intr(hwif)	((hwif)->hw.ack_intr ? (hwif)->hw.ack_intr(hwif) : 1)
-
-/*
- * On the Atari, we sometimes can't enable interrupts:
- */
-
-/* MSch: changed sti() to STI() wherever possible in ide.c; moved STI() def. 
- * to asm/ide.h 
- */
-/* The Atari interrupt structure strictly requires that the IPL isn't lowered
- * uncontrolled in an interrupt handler. In the concrete case, the IDE
- * interrupt is already a slow int, so the irq is already disabled at the time
- * the handler is called, and the IPL has been lowered to the minimum value
- * possible. To avoid going below that, STI() checks for being called inside
- * an interrupt, and in that case it does nothing. Hope that is reasonable and
- * works. (Roman)
- */
-#ifdef MACH_ATARI_ONLY
-#define	ide__sti()					\
-    do {						\
-	if (!in_interrupt()) __sti();			\
-    } while(0)
-#elif defined(CONFIG_ATARI)
-#define	ide__sti()						\
-    do {							\
-	if (!MACH_IS_ATARI || !in_interrupt()) sti();		\
-    } while(0)
-#else /* !defined(CONFIG_ATARI) */
-#define	ide__sti()	__sti()
-#endif
+#endif /* CONFIG_ATARI */
 
 #endif /* __KERNEL__ */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-m68k/ioctls.h linux.20pre10-ac2/include/asm-m68k/ioctls.h
--- linux.20pre10/include/asm-m68k/ioctls.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-m68k/ioctls.h	2002-08-06 15:41:52.000000000 +0100
@@ -65,6 +65,7 @@
 
 #define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
 #define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+#define FIOQSIZE	0x545E
 
 /* Used for packet mode */
 #define TIOCPKT_DATA		 0
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-m68k/rmap.h linux.20pre10-ac2/include/asm-m68k/rmap.h
--- linux.20pre10/include/asm-m68k/rmap.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/asm-m68k/rmap.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,7 @@
+#ifndef _M86K_RMAP_H
+#define _M86K_RMAP_H
+
+/* nothing to see, move along */
+#include <asm-generic/rmap.h>
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-m68k/system.h linux.20pre10-ac2/include/asm-m68k/system.h
--- linux.20pre10/include/asm-m68k/system.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-m68k/system.h	2002-08-06 15:41:52.000000000 +0100
@@ -47,7 +47,6 @@
   (last) = _last; \
 }
 
-
 /* interrupt control.. */
 #if 0
 #define __sti() asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory")
@@ -64,6 +63,7 @@
 
 /* For spinlocks etc */
 #define local_irq_save(x)	({ __save_flags(x); __cli(); })
+#define local_irq_set(x)	({ __save_flags(x); __sti(); })
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -72,7 +72,8 @@
 #define sti()			__sti()
 #define save_flags(x)		__save_flags(x)
 #define restore_flags(x)	__restore_flags(x)
-#define save_and_cli(flags)   do { save_flags(flags); cli(); } while(0)
+#define save_and_cli(x)		do { save_flags(x); cli(); } while(0)
+#define save_and_set(x)		do { save_flags(x); sti(); } while(0)
 
 /*
  * Force strict CPU ordering.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-m68k/termios.h linux.20pre10-ac2/include/asm-m68k/termios.h
--- linux.20pre10/include/asm-m68k/termios.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-m68k/termios.h	2002-09-30 17:41:19.000000000 +0100
@@ -47,6 +47,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 
 /* line disciplines */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-mips/ide.h linux.20pre10-ac2/include/asm-mips/ide.h
--- linux.20pre10/include/asm-mips/ide.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-mips/ide.h	2002-08-15 16:46:37.000000000 +0100
@@ -24,21 +24,11 @@
 # endif
 #endif
 
-#define ide__sti()	__sti()
-
 struct ide_ops {
 	int (*ide_default_irq)(ide_ioreg_t base);
 	ide_ioreg_t (*ide_default_io_base)(int index);
 	void (*ide_init_hwif_ports)(hw_regs_t *hw, ide_ioreg_t data_port,
 	                            ide_ioreg_t ctrl_port, int *irq);
-	int (*ide_request_irq)(unsigned int irq, void (*handler)(int, void *,
-	                       struct pt_regs *), unsigned long flags,
-	                       const char *device, void *dev_id);
-	void (*ide_free_irq)(unsigned int irq, void *dev_id);
-	int (*ide_check_region) (ide_ioreg_t from, unsigned int extent);
-	void (*ide_request_region)(ide_ioreg_t from, unsigned int extent,
-	                        const char *name);
-	void (*ide_release_region)(ide_ioreg_t from, unsigned int extent);
 };
 
 extern struct ide_ops *ide_ops;
@@ -73,74 +63,6 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-#ifdef __MIPSEB__
-		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 or 1 */
-		unsigned head		: 4;	/* always zeros here */
-#else
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-#endif
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-#ifdef __MIPSEB__
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-		unsigned reserved456	: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned bit0		: 1;
-#else
-		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 */
-#endif
-	} b;
-} control_t;
-
-static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int,void *, struct pt_regs *),
-			unsigned long flags, const char *device, void *dev_id)
-{
-	return ide_ops->ide_request_irq(irq, handler, flags, device, dev_id);
-}
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
-	ide_ops->ide_free_irq(irq, dev_id);
-}
-
-static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
-{
-	return ide_ops->ide_check_region(from, extent);
-}
-
-static __inline__ void ide_request_region(ide_ioreg_t from,
-                                          unsigned int extent, const char *name)
-{
-	ide_ops->ide_request_region(from, extent, name);
-}
-
-static __inline__ void ide_release_region(ide_ioreg_t from,
-                                          unsigned int extent)
-{
-	ide_ops->ide_release_region(from, extent);
-}
-
 #undef  SUPPORT_VLB_SYNC
 #define SUPPORT_VLB_SYNC 0
 
@@ -197,94 +119,8 @@
 	}
 }
 
-#define T_CHAR          (0x0000)        /* char:  don't touch  */
-#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
-#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
-#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
-
-#define T_MASK_TYPE     (0xc000)
-#define T_MASK_COUNT    (0x3fff)
-
-#define D_CHAR(cnt)     (T_CHAR  | (cnt))
-#define D_SHORT(cnt)    (T_SHORT | (cnt))
-#define D_INT(cnt)      (T_INT   | (cnt))
-#define D_TEXT(cnt)     (T_TEXT  | (cnt))
-
-static u_short driveid_types[] = {
-	D_SHORT(10),	/* config - vendor2 */
-	D_TEXT(20),	/* serial_no */
-	D_SHORT(3),	/* buf_type - ecc_bytes */
-	D_TEXT(48),	/* fw_rev - model */
-	D_CHAR(2),	/* max_multsect - vendor3 */
-	D_SHORT(1),	/* dword_io */
-	D_CHAR(2),	/* vendor4 - capability */
-	D_SHORT(1),	/* reserved50 */
-	D_CHAR(4),	/* vendor5 - tDMA */
-	D_SHORT(4),	/* field_valid - cur_sectors */
-	D_INT(1),	/* cur_capacity */
-	D_CHAR(2),	/* multsect - multsect_valid */
-	D_INT(1),	/* lba_capacity */
-	D_SHORT(194)	/* dma_1word - reservedyy */
-};
-
-#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-	u_char *p = (u_char *)id;
-	int i, j, cnt;
-	u_char t;
-
-	for (i = 0; i < num_driveid_types; i++) {
-		cnt = driveid_types[i] & T_MASK_COUNT;
-		switch (driveid_types[i] & T_MASK_TYPE) {
-		case T_CHAR:
-			p += cnt;
-			break;
-		case T_SHORT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		case T_INT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[3];
-				p[3] = t;
-				t = p[1];
-				p[1] = p[2];
-				p[2] = t;
-				p += 4;
-			}
-			break;
-		case T_TEXT:
-			for (j = 0; j < cnt; j += 2) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		};
-	}
-}
-
-#else /* defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)  */
-
-#define ide_fix_driveid(id)		do {} while (0)
-
 #endif
 
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
 #endif /* __KERNEL__ */
 
 #endif /* __ASM_IDE_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-mips/rmap.h linux.20pre10-ac2/include/asm-mips/rmap.h
--- linux.20pre10/include/asm-mips/rmap.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/asm-mips/rmap.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,7 @@
+#ifndef _MIPS_RMAP_H
+#define _MIPS_RMAP_H
+
+/* nothing to see, move along */
+#include <asm-generic/rmap.h>
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-mips/sibyte/swarm_ide.h linux.20pre10-ac2/include/asm-mips/sibyte/swarm_ide.h
--- linux.20pre10/include/asm-mips/sibyte/swarm_ide.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/asm-mips/sibyte/swarm_ide.h	2002-09-14 22:39:11.000000000 +0100
@@ -25,8 +25,23 @@
 #define SWARM_IDE_REG(pcaddr) (SWARM_IDE_BASE + ((pcaddr)<<5))
 #define SWARM_IDE_INT         (K_INT_GPIO_4)
 
-extern ide_ideproc_t swarm_ideproc;
 
+#ifdef __IDE_SWARM_C
+static inline void swarm_outb (u8 val, unsigned long port)
+{
+	*(volatile u8 *)(mips_io_port_base + (port)) = val;
+}
+
+static inline void swarm_outw (u16 val, unsigned long port)
+{
+	*(volatile u16 *)(mips_io_port_base + (port)) = val;
+}
+
+static inline void swarm_outl (u32 val, unsigned long port)
+{
+	*(volatile u32 *)(mips_io_port_base + (port)) = val;
+}
+#else /* !__IDE_SWARM_C */
 #define swarm_outb(val,port)							\
 do {									\
 	*(volatile u8 *)(mips_io_port_base + (port)) = val;	\
@@ -41,6 +56,7 @@
 do {									\
 	*(volatile u32 *)(mips_io_port_base + (port)) = val;\
 } while(0)
+#endif /* __IDE_SWARM_C */
 
 static inline unsigned char swarm_inb(unsigned long port)
 {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-mips/system.h linux.20pre10-ac2/include/asm-mips/system.h
--- linux.20pre10/include/asm-mips/system.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/asm-mips/system.h	2002-09-14 22:39:11.000000000 +0100
@@ -114,6 +114,8 @@
 	: /* no inputs */						\
 	: "memory")
 
+#define __save_and_sti(x)	do { __save_flags(x); __sti(); } while(0);
+
 __asm__(".macro\t__restore_flags flags\n\t"
 	".set\tnoreorder\n\t"
 	".set\tnoat\n\t"
@@ -152,6 +154,7 @@
 #  define save_flags(x) do { x = __global_save_flags(); } while (0)
 #  define restore_flags(x) __global_restore_flags(x)
 #  define save_and_cli(x) do { save_flags(x); cli(); } while(0)
+#  define save_and_sti(x) do { save_flags(x); sti(); } while(0)
 
 #else /* Single processor */
 
@@ -160,11 +163,13 @@
 #  define save_flags(x) __save_flags(x)
 #  define save_and_cli(x) __save_and_cli(x)
 #  define restore_flags(x) __restore_flags(x)
+#  define save_and_sti(x) __save_and_sti(x)
 
 #endif /* SMP */
 
 /* For spinlocks etc */
 #define local_irq_save(x)	__save_and_cli(x)
+#define local_irq_set(x)	__save_and_sti(x)
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-mips/termios.h linux.20pre10-ac2/include/asm-mips/termios.h
--- linux.20pre10/include/asm-mips/termios.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-mips/termios.h	2002-09-30 17:41:31.000000000 +0100
@@ -84,6 +84,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* line disciplines */
 #define N_TTY		0
 #define N_SLIP		1
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-mips64/ide.h linux.20pre10-ac2/include/asm-mips64/ide.h
--- linux.20pre10/include/asm-mips64/ide.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/asm-mips64/ide.h	2002-09-14 22:39:26.000000000 +0100
@@ -28,21 +28,11 @@
 # endif
 #endif
 
-#define ide__sti()	__sti()
-
 struct ide_ops {
 	int (*ide_default_irq)(ide_ioreg_t base);
 	ide_ioreg_t (*ide_default_io_base)(int index);
 	void (*ide_init_hwif_ports)(hw_regs_t *hw, ide_ioreg_t data_port,
 	                            ide_ioreg_t ctrl_port, int *irq);
-	int (*ide_request_irq)(unsigned int irq, void (*handler)(int, void *,
-	                       struct pt_regs *), unsigned long flags,
-	                       const char *device, void *dev_id);
-	void (*ide_free_irq)(unsigned int irq, void *dev_id);
-	int (*ide_check_region) (ide_ioreg_t from, unsigned int extent);
-	void (*ide_request_region)(ide_ioreg_t from, unsigned int extent,
-	                        const char *name);
-	void (*ide_release_region)(ide_ioreg_t from, unsigned int extent);
 };
 
 extern struct ide_ops *ide_ops;
@@ -77,215 +67,50 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-#ifdef __MIPSEB__
-		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 or 1 */
-		unsigned head           : 4;    /* always zeros here */
-#else
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-#endif
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-#ifdef __MIPSEB__
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-		unsigned reserved456	: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned bit0		: 1;
-#else
-		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 */
-#endif
-	} b;
-} control_t;
-
-static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int,void *, struct pt_regs *),
-			unsigned long flags, const char *device, void *dev_id)
-{
-	return ide_ops->ide_request_irq(irq, handler, flags, device, dev_id);
-}
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
-	ide_ops->ide_free_irq(irq, dev_id);
-}
-
-static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
-{
-	return ide_ops->ide_check_region(from, extent);
-}
-
-static __inline__ void ide_request_region(ide_ioreg_t from,
-                                          unsigned int extent, const char *name)
-{
-	ide_ops->ide_request_region(from, extent, name);
-}
-
-static __inline__ void ide_release_region(ide_ioreg_t from,
-                                          unsigned int extent)
-{
-	ide_ops->ide_release_region(from, extent);
-}
-
-
 #if defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)
 
-/* get rid of defs from io.h - ide has its private and conflicting versions */
-#ifdef insw
-#undef insw
-#endif
-#ifdef outsw
-#undef outsw
-#endif
 #ifdef insl
 #undef insl
 #endif
 #ifdef outsl
 #undef outsl
 #endif
-
-#define insw(port, addr, count) ide_insw(port, addr, count)
-#define insl(port, addr, count) ide_insl(port, addr, count)
-#define outsw(port, addr, count) ide_outsw(port, addr, count)
-#define outsl(port, addr, count) ide_outsl(port, addr, count)
-
-static inline void ide_insw(unsigned long port, void *addr, unsigned int count)
-{
-       while (count--) {
-               *(u16 *)addr = *(volatile u16 *)(mips_io_port_base + port);
-               addr += 2;
-       }
-}
-
-static inline void ide_outsw(unsigned long port, void *addr, unsigned int count)
-{
-       while (count--) {
-               *(volatile u16 *)(mips_io_port_base + (port)) = *(u16 *)addr;
-               addr += 2;
-       }
-}
-
-static inline void ide_insl(unsigned long port, void *addr, unsigned int count)
-{
-       while (count--) {
-               *(u32 *)addr = *(volatile u32 *)(mips_io_port_base + port);
-               addr += 4;
-       }
-}
-
-static inline void ide_outsl(unsigned long port, void *addr, unsigned int count)
-{
-       while (count--) {
-               *(volatile u32 *)(mips_io_port_base + (port)) = *(u32 *)addr;
-               addr += 4;
-       }
-}
-
-#define T_CHAR          (0x0000)        /* char:  don't touch  */
-#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
-#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
-#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
-
-#define T_MASK_TYPE     (0xc000)
-#define T_MASK_COUNT    (0x3fff)
-
-#define D_CHAR(cnt)     (T_CHAR  | (cnt))
-#define D_SHORT(cnt)    (T_SHORT | (cnt))
-#define D_INT(cnt)      (T_INT   | (cnt))
-#define D_TEXT(cnt)     (T_TEXT  | (cnt))
-
-static u_short driveid_types[] = {
-	D_SHORT(10),	/* config - vendor2 */
-	D_TEXT(20),	/* serial_no */
-	D_SHORT(3),	/* buf_type - ecc_bytes */
-	D_TEXT(48),	/* fw_rev - model */
-	D_CHAR(2),	/* max_multsect - vendor3 */
-	D_SHORT(1),	/* dword_io */
-	D_CHAR(2),	/* vendor4 - capability */
-	D_SHORT(1),	/* reserved50 */
-	D_CHAR(4),	/* vendor5 - tDMA */
-	D_SHORT(4),	/* field_valid - cur_sectors */
-	D_INT(1),	/* cur_capacity */
-	D_CHAR(2),	/* multsect - multsect_valid */
-	D_INT(1),	/* lba_capacity */
-	D_SHORT(194)	/* dma_1word - reservedyy */
-};
-
-#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-	u_char *p = (u_char *)id;
-	int i, j, cnt;
-	u_char t;
-
-	for (i = 0; i < num_driveid_types; i++) {
-		cnt = driveid_types[i] & T_MASK_COUNT;
-		switch (driveid_types[i] & T_MASK_TYPE) {
-		case T_CHAR:
-			p += cnt;
-			break;
-		case T_SHORT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		case T_INT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[3];
-				p[3] = t;
-				t = p[1];
-				p[1] = p[2];
-				p[2] = t;
-				p += 4;
-			}
-			break;
-		case T_TEXT:
-			for (j = 0; j < cnt; j += 2) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		};
-	}
-}
-
-#else /* defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)  */
-
-#define ide_fix_driveid(id)		do {} while (0)
-
+#ifdef insw
+#undef insw
 #endif
+#ifdef outsw
+#undef outsw
+#endif
+
+#define insw(p,a,c)							\
+do {									\
+	unsigned short *ptr = (unsigned short *)(a);			\
+	unsigned int i = (c);						\
+	while (i--)							\
+		*ptr++ = inw(p);					\
+} while (0)
+#define insl(p,a,c)							\
+do {									\
+	unsigned long *ptr = (unsigned long *)(a);			\
+	unsigned int i = (c);						\
+	while (i--)							\
+		*ptr++ = inl(p);					\
+} while (0)
+#define outsw(p,a,c)							\
+do {									\
+	unsigned short *ptr = (unsigned short *)(a);			\
+	unsigned int i = (c);						\
+	while (i--)							\
+		outw(*ptr++, (p));					\
+} while (0)
+#define outsl(p,a,c) {							\
+	unsigned long *ptr = (unsigned long *)(a);			\
+	unsigned int i = (c);						\
+	while (i--)							\
+		outl(*ptr++, (p));					\
+} while (0)
 
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
+#endif /* defined(CONFIG_SWAP_IO_SPACE) && defined(__MIPSEB__)  */
 
 #endif /* __KERNEL__ */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-mips64/rmap.h linux.20pre10-ac2/include/asm-mips64/rmap.h
--- linux.20pre10/include/asm-mips64/rmap.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/asm-mips64/rmap.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,7 @@
+#ifndef _MIPS64_RMAP_H
+#define _MIPS64_RMAP_H
+
+/* nothing to see, move along */
+#include <asm-generic/rmap.h>
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-mips64/sibyte/swarm_ide.h linux.20pre10-ac2/include/asm-mips64/sibyte/swarm_ide.h
--- linux.20pre10/include/asm-mips64/sibyte/swarm_ide.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/asm-mips64/sibyte/swarm_ide.h	2002-09-14 22:40:06.000000000 +0100
@@ -25,8 +25,22 @@
 #define SWARM_IDE_REG(pcaddr) (SWARM_IDE_BASE + ((pcaddr)<<5))
 #define SWARM_IDE_INT         (K_INT_GPIO_4)
 
-extern ide_ideproc_t swarm_ideproc;
+#ifdef __IDE_SWARM_C
+static inline void swarm_outb (u8 val, unsigned long port)
+{
+	*(volatile u8 *)(mips_io_port_base + (port)) = val;
+}
+
+static inline void swarm_outw (u16 val, unsigned long port)
+{
+	*(volatile u16 *)(mips_io_port_base + (port)) = val;
+}
 
+static inline void swarm_outl (u32 val, unsigned long port)
+{
+	*(volatile u32 *)(mips_io_port_base + (port)) = val;
+}
+#else /* !__IDE_SWARM_C */
 #define swarm_outb(val,port)							\
 do {									\
 	*(volatile u8 *)(mips_io_port_base + (port)) = val;	\
@@ -41,6 +55,7 @@
 do {									\
 	*(volatile u32 *)(mips_io_port_base + (port)) = val;\
 } while(0)
+#endif /* __IDE_SWARM_C */
 
 static inline unsigned char swarm_inb(unsigned long port)
 {
@@ -57,7 +72,6 @@
 	return (*(volatile u32 *)(mips_io_port_base + port));
 }
 
-
 static inline void swarm_outsb(unsigned long port, void *addr, unsigned int count)
 {
 	while (count--) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-mips64/system.h linux.20pre10-ac2/include/asm-mips64/system.h
--- linux.20pre10/include/asm-mips64/system.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/asm-mips64/system.h	2002-09-14 22:40:26.000000000 +0100
@@ -109,6 +109,8 @@
 	: /* no inputs */						\
 	: "memory")
 
+#define __save_and_sti(x)       do { __save_flags(x); __sti(); } while(0);
+
 __asm__(".macro\t__restore_flags flags\n\t"
 	".set\tnoreorder\n\t"
 	".set\tnoat\n\t"
@@ -147,6 +149,7 @@
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
 #define save_and_cli(x) do { save_flags(x); cli(); } while(0)
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0)
 
 #else
 
@@ -155,11 +158,13 @@
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
 #define save_and_cli(x) __save_and_cli(x)
+#define save_and_sti(x) __save_and_sti(x)
 
 #endif /* CONFIG_SMP */
 
 /* For spinlocks etc */
 #define local_irq_save(x)	__save_and_cli(x)
+#define local_irq_set(x)	__save_and_sti(x)
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-mips64/termios.h linux.20pre10-ac2/include/asm-mips64/termios.h
--- linux.20pre10/include/asm-mips64/termios.h	2002-10-09 21:36:39.000000000 +0100
+++ linux.20pre10-ac2/include/asm-mips64/termios.h	2002-09-30 17:41:40.000000000 +0100
@@ -85,6 +85,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* line disciplines */
 #define N_TTY		0
 #define N_SLIP		1
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-parisc/hdreg.h linux.20pre10-ac2/include/asm-parisc/hdreg.h
--- linux.20pre10/include/asm-parisc/hdreg.h	2002-10-09 21:36:39.000000000 +0100
+++ linux.20pre10-ac2/include/asm-parisc/hdreg.h	2002-09-06 00:50:04.000000000 +0100
@@ -1,6 +1,7 @@
 #ifndef _ASM_HDREG_H
 #define _ASM_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+//typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-parisc/ide.h linux.20pre10-ac2/include/asm-parisc/ide.h
--- linux.20pre10/include/asm-parisc/ide.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/asm-parisc/ide.h	2002-08-15 16:46:55.000000000 +0100
@@ -78,94 +78,6 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-#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))
-
-#define T_CHAR          (0x0000)        /* char:  don't touch  */
-#define T_SHORT         (0x4000)        /* short: 12 -> 21     */
-#define T_INT           (0x8000)        /* int:   1234 -> 4321 */
-#define T_TEXT          (0xc000)        /* text:  12 -> 21     */
-
-#define T_MASK_TYPE     (0xc000)
-#define T_MASK_COUNT    (0x3fff)
-
-#define D_CHAR(cnt)     (T_CHAR  | (cnt))
-#define D_SHORT(cnt)    (T_SHORT | (cnt))
-#define D_INT(cnt)      (T_INT   | (cnt))
-#define D_TEXT(cnt)     (T_TEXT  | (cnt))
-
-static u_short driveid_types[] = {
-	D_SHORT(10),	/* config - vendor2 */
-	D_TEXT(20),	/* serial_no */
-	D_SHORT(3),	/* buf_type - ecc_bytes */
-	D_TEXT(48),	/* fw_rev - model */
-	D_CHAR(2),	/* max_multsect - vendor3 */
-	D_SHORT(1),	/* dword_io */
-	D_CHAR(2),	/* vendor4 - capability */
-	D_SHORT(1),	/* reserved50 */
-	D_CHAR(4),	/* vendor5 - tDMA */
-	D_SHORT(4),	/* field_valid - cur_sectors */
-	D_INT(1),	/* cur_capacity */
-	D_CHAR(2),	/* multsect - multsect_valid */
-	D_INT(1),	/* lba_capacity */
-	D_SHORT(194)	/* dma_1word - reservedyy */
-};
-
-#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))
-
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-	u_char *p = (u_char *)id;
-	int i, j, cnt;
-	u_char t;
-
-	for (i = 0; i < num_driveid_types; i++) {
-		cnt = driveid_types[i] & T_MASK_COUNT;
-		switch (driveid_types[i] & T_MASK_TYPE) {
-		case T_CHAR:
-			p += cnt;
-			break;
-		case T_SHORT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		case T_INT:
-			for (j = 0; j < cnt; j++) {
-				t = p[0];
-				p[0] = p[3];
-				p[3] = t;
-				t = p[1];
-				p[1] = p[2];
-				p[2] = t;
-				p += 4;
-			}
-			break;
-		case T_TEXT:
-			for (j = 0; j < cnt; j += 2) {
-				t = p[0];
-				p[0] = p[1];
-				p[1] = t;
-				p += 2;
-			}
-			break;
-		};
-	}
-}
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
 #endif /* __KERNEL__ */
 
 #endif /* __ASM_PARISC_IDE_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-parisc/processor.h linux.20pre10-ac2/include/asm-parisc/processor.h
--- linux.20pre10/include/asm-parisc/processor.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/asm-parisc/processor.h	2002-09-18 12:28:20.000000000 +0100
@@ -9,6 +9,7 @@
 #define __ASM_PARISC_PROCESSOR_H
 
 #ifndef __ASSEMBLY__
+#include <linux/config.h>
 #include <linux/threads.h>
 
 #include <asm/hardware.h>
@@ -17,6 +18,9 @@
 #include <asm/ptrace.h>
 #include <asm/types.h>
 #include <asm/system.h>
+#ifdef CONFIG_SMP
+#include <asm/spinlock_t.h>
+#endif
 #endif /* __ASSEMBLY__ */
 
 /*
@@ -71,7 +75,6 @@
 */
 struct cpuinfo_parisc {
 
-	struct irq_region *region;
 	unsigned long it_value;     /* Interval Timer value at last timer Intr */
 	unsigned long it_delta;     /* Interval Timer delta (tic_10ms / HZ * 100) */
 	unsigned long irq_count;    /* number of IRQ's since boot */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-ppc/bitops.h linux.20pre10-ac2/include/asm-ppc/bitops.h
--- linux.20pre10/include/asm-ppc/bitops.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-ppc/bitops.h	2002-08-26 14:23:02.000000000 +0100
@@ -10,6 +10,7 @@
 #define _PPC_BITOPS_H
 
 #include <linux/config.h>
+#include <linux/compiler.h>
 #include <asm/byteorder.h>
 
 /*
@@ -239,6 +240,11 @@
 
 #ifdef __KERNEL__
 
+static inline int __ffs(unsigned long x)
+{
+	return __ilog2(x & -x);
+}
+
 /*
  * ffs: find first bit set. This is defined the same way as
  * the libc and compiler builtin ffs routines, therefore
@@ -250,6 +256,18 @@
 }
 
 /*
+ * fls: find last (most-significant) bit set.
+ * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
+ */
+static __inline__ int fls(unsigned int x)
+{
+	int lz;
+
+	asm ("cntlzw %0,%1" : "=r" (lz) : "r" (x));
+	return 32 - lz;
+}
+
+/*
  * hweightN: returns the hamming weight (i.e. the number
  * of bits set) of a N-bit word
  */
@@ -261,6 +279,23 @@
 #endif /* __KERNEL__ */
 
 /*
+ * Find the first bit set in a 140-bit bitmap.
+ * The first 100 bits are unlikely to be set.
+ */
+static inline int _sched_find_first_bit(unsigned long *b)
+{
+	if (unlikely(b[0]))
+		return __ffs(b[0]);
+	if (unlikely(b[1]))
+		return __ffs(b[1]) + 32;
+	if (unlikely(b[2]))
+		return __ffs(b[2]) + 64;
+	if (b[3])
+		return __ffs(b[3]) + 96;
+	return __ffs(b[4]) + 128;
+}
+
+/*
  * This implementation of find_{first,next}_zero_bit was stolen from
  * Linus' asm-alpha/bitops.h.
  */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-ppc/hdreg.h linux.20pre10-ac2/include/asm-ppc/hdreg.h
--- linux.20pre10/include/asm-ppc/hdreg.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-ppc/hdreg.h	2002-09-06 00:50:04.000000000 +0100
@@ -14,7 +14,8 @@
 #ifndef __ASMPPC_HDREG_H
 #define __ASMPPC_HDREG_H
 
-typedef unsigned int ide_ioreg_t;
+//typedef unsigned int ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMPPC_HDREG_H */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-ppc/hw_irq.h linux.20pre10-ac2/include/asm-ppc/hw_irq.h
--- linux.20pre10/include/asm-ppc/hw_irq.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/asm-ppc/hw_irq.h	2002-08-13 14:46:37.000000000 +0100
@@ -21,6 +21,7 @@
 
 #define __save_flags(flags) __save_flags_ptr((unsigned long *)&flags)
 #define __save_and_cli(flags) ({__save_flags(flags);__cli();})
+#define __save_and_sti(flags) ({__save_flags(flags);__sti();})
 
 extern void do_lost_interrupts(unsigned long);
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-ppc/ide.h linux.20pre10-ac2/include/asm-ppc/ide.h
--- linux.20pre10/include/asm-ppc/ide.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-ppc/ide.h	2002-08-15 16:47:03.000000000 +0100
@@ -30,17 +30,9 @@
 #include <linux/ioport.h>
 #include <asm/io.h>
 
-extern void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
-
 struct ide_machdep_calls {
         int         (*default_irq)(ide_ioreg_t base);
         ide_ioreg_t (*default_io_base)(int index);
-        int         (*ide_check_region)(ide_ioreg_t from, unsigned int extent);
-        void        (*ide_request_region)(ide_ioreg_t from,
-                                      unsigned int extent,
-                                      const char *name);
-        void        (*ide_release_region)(ide_ioreg_t from,
-                                      unsigned int extent);
         void        (*ide_init_hwif)(hw_regs_t *hw,
                                      ide_ioreg_t data_port,
                                      ide_ioreg_t ctrl_port,
@@ -49,16 +41,11 @@
 
 extern struct ide_machdep_calls ppc_ide_md;
 
-void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
-#define ide_fix_driveid(id)	ppc_generic_ide_fix_driveid((id))
-
 #undef	SUPPORT_SLOW_DATA_PORTS
 #define	SUPPORT_SLOW_DATA_PORTS	0
 #undef	SUPPORT_VLB_SYNC
 #define SUPPORT_VLB_SYNC	0
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	if (ppc_ide_md.default_irq)
@@ -99,67 +86,13 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
-{
-	if (ppc_ide_md.ide_check_region)
-		return ppc_ide_md.ide_check_region(from, extent);
-	return 0;
-}
-
-static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
-{
-	if (ppc_ide_md.ide_request_region)
-		ppc_ide_md.ide_request_region(from, extent, name);
-}
-
-static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
-{
-	if (ppc_ide_md.ide_release_region)
-		ppc_ide_md.ide_release_region(from, extent);
-}
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		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 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned HOB		: 1;	/* 48-bit address ordering */
-		unsigned reserved456	: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned SRST		: 1;	/* host soft reset bit */
-		unsigned nIEN		: 1;	/* device INTRQ to host */
-		unsigned bit0		: 1;
-	} b;
-} control_t;
-
-#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
-
 /*
  * 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_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1)
-#else
-#define ide_ack_intr(hwif)		(1)
+#define IDE_ARCH_ACK_INTR 1
 #endif
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
 #endif /* __KERNEL__ */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-ppc/rmap.h linux.20pre10-ac2/include/asm-ppc/rmap.h
--- linux.20pre10/include/asm-ppc/rmap.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/asm-ppc/rmap.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,9 @@
+#ifndef _PPC_RMAP_H
+#define _PPC_RMAP_H
+
+/* PPC calls pte_alloc() before mem_map[] is setup ... */
+#define BROKEN_PPC_PTE_ALLOC_ONE
+
+#include <asm-generic/rmap.h>
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-ppc/rwsem.h linux.20pre10-ac2/include/asm-ppc/rwsem.h
--- linux.20pre10/include/asm-ppc/rwsem.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/asm-ppc/rwsem.h	2002-09-14 21:56:24.000000000 +0100
@@ -91,6 +91,20 @@
 	return 0;
 }
 
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+	int tmp;
+
+	while ((tmp = sem->count) >= 0) {
+		if (tmp == cmpxchg(&sem->count, tmp,
+				   tmp + RWSEM_ACTIVE_READ_BIAS)) {
+			smp_wmb();
+			return 1;
+		}
+	}
+	return 0;
+}
+
 /*
  * lock for writing
  */
@@ -116,6 +130,16 @@
 	return tmp == RWSEM_UNLOCKED_VALUE;
 }
 
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+	int tmp;
+
+	tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
+		      RWSEM_ACTIVE_WRITE_BIAS);
+	smp_wmb();
+	return tmp == RWSEM_UNLOCKED_VALUE;
+}
+
 /*
  * unlock after reading
  */
@@ -148,6 +172,7 @@
 	atomic_add(delta, (atomic_t *)(&sem->count));
 }
 
+
 /*
  * implement exchange and add functionality
  */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-ppc/system.h linux.20pre10-ac2/include/asm-ppc/system.h
--- linux.20pre10/include/asm-ppc/system.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-ppc/system.h	2002-08-06 15:41:52.000000000 +0100
@@ -105,6 +105,7 @@
 #define save_flags(flags)	__save_flags(flags)
 #define restore_flags(flags)	__restore_flags(flags)
 #define save_and_cli(flags)	__save_and_cli(flags)
+#define save_and_sti(flags)	__save_and_sti(flags)
 
 #else /* CONFIG_SMP */
 
@@ -117,11 +118,15 @@
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
 
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0);
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
+
 #endif /* !CONFIG_SMP */
 
 #define local_irq_disable()		__cli()
 #define local_irq_enable()		__sti()
 #define local_irq_save(flags)		__save_and_cli(flags)
+#define local_irq_set(flags)		__save_and_sti(flags)
 #define local_irq_restore(flags)	__restore_flags(flags)
 
 static __inline__ unsigned long
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-ppc64/hw_irq.h linux.20pre10-ac2/include/asm-ppc64/hw_irq.h
--- linux.20pre10/include/asm-ppc64/hw_irq.h	2002-10-09 21:36:39.000000000 +0100
+++ linux.20pre10-ac2/include/asm-ppc64/hw_irq.h	2002-08-06 15:41:55.000000000 +0100
@@ -31,6 +31,7 @@
 #define __save_flags(flags)	((flags) = __no_use_save_flags())
 #define __restore_flags(flags)	__no_use_restore_flags((unsigned long)flags)
 #define __save_and_cli(flags)	({__save_flags(flags);__cli();})
+#define __save_and_sti(flags)	({__save_flags(flags);__sti();})
 
 #else
 
@@ -63,6 +64,7 @@
 }
 
 #define __save_and_cli(flags)          __do_save_and_cli(&flags)
+#define __save_and_sti(flags)		({__save_flags(flags);__sti();})
 
 #endif /* CONFIG_PPC_ISERIES */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-ppc64/ide.h linux.20pre10-ac2/include/asm-ppc64/ide.h
--- linux.20pre10/include/asm-ppc64/ide.h	2002-10-09 21:36:39.000000000 +0100
+++ linux.20pre10-ac2/include/asm-ppc64/ide.h	2002-08-15 16:47:13.000000000 +0100
@@ -22,8 +22,6 @@
 #define MAX_HWIFS	4
 #endif
 
-#define ide__sti()	__sti()
-
 void ppc64_ide_fix_driveid(struct hd_driveid *id);
 #define ide_fix_driveid(id)	ppc64_ide_fix_driveid((id))
 
@@ -53,30 +51,6 @@
 {
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-	} select_t;
-
-#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_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
 #endif /* __KERNEL__ */
 
 #endif /* __ASMPPC64_IDE_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-ppc64/system.h linux.20pre10-ac2/include/asm-ppc64/system.h
--- linux.20pre10/include/asm-ppc64/system.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/asm-ppc64/system.h	2002-08-29 18:57:06.000000000 +0100
@@ -90,6 +90,7 @@
 #define save_flags(flags)	__save_flags(flags)
 #define restore_flags(flags)	__restore_flags(flags)
 #define save_and_cli(flags)	__save_and_cli(flags)
+#define save_and_sti(flags)	__save_and_sti(flags)
 
 #else /* CONFIG_SMP */
 
@@ -102,11 +103,15 @@
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
 
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0);
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
+
 #endif /* !CONFIG_SMP */
 
 #define local_irq_disable()		__cli()
 #define local_irq_enable()		__sti()
 #define local_irq_save(flags)		__save_and_cli(flags)
+#define local_irq_set(flags)		__save_and_sti(flags)
 #define local_irq_restore(flags)	__restore_flags(flags)
 
 static __inline__ int __is_processor(unsigned long pv)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-ppc64/termios.h linux.20pre10-ac2/include/asm-ppc64/termios.h
--- linux.20pre10/include/asm-ppc64/termios.h	2002-10-09 21:36:39.000000000 +0100
+++ linux.20pre10-ac2/include/asm-ppc64/termios.h	2002-09-30 17:42:23.000000000 +0100
@@ -192,6 +192,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 #define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-s390/ide.h linux.20pre10-ac2/include/asm-s390/ide.h
--- linux.20pre10/include/asm-s390/ide.h	2002-10-09 21:36:39.000000000 +0100
+++ linux.20pre10-ac2/include/asm-s390/ide.h	2002-08-15 16:47:13.000000000 +0100
@@ -15,45 +15,6 @@
 #define MAX_HWIFS	0
 #endif
 
-#define ide__sti()	do {} while (0)
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		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 */
-	} b;
-} control_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	do {} while (0)
-#define ide_free_irq(irq,dev_id)		do {} while (0)
-#define ide_check_region(from,extent)		do {} while (0)
-#define ide_request_region(from,extent,name)	do {} while (0)
-#define ide_release_region(from,extent)		do {} while (0)
-
-/*
- * 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)
-
 /*
  * We always use the new IDE port registering,
  * so these are fixed here.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-s390/rmap.h linux.20pre10-ac2/include/asm-s390/rmap.h
--- linux.20pre10/include/asm-s390/rmap.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/asm-s390/rmap.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,7 @@
+#ifndef _S390_RMAP_H
+#define _S390_RMAP_H
+
+/* nothing to see, move along */
+#include <asm-generic/rmap.h>
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-s390/system.h linux.20pre10-ac2/include/asm-s390/system.h
--- linux.20pre10/include/asm-s390/system.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/asm-s390/system.h	2002-08-13 14:46:55.000000000 +0100
@@ -206,8 +206,12 @@
                 : "cc", "0", "1", "2"); \
         })
 
+#define __save_and_cli(x)	do { __save_flags(x); __cli(); } while(0);
+#define __save_and_sti(x)	do { __save_flags(x); __sti(); } while(0);
+
 /* For spinlocks etc */
 #define local_irq_save(x)	((x) = __cli())
+#define local_irq_set(x)	__save_and_sti(x)
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -223,6 +227,8 @@
 #define sti() __global_sti()
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0);
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
 
 extern void smp_ctl_set_bit(int cr, int bit);
 extern void smp_ctl_clear_bit(int cr, int bit);
@@ -235,6 +241,8 @@
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
+#define save_and_cli(x) __save_and_cli(x)
+#define save_and_sti(x) __save_and_sti(x)
 
 #define ctl_set_bit(cr, bit) __ctl_set_bit(cr, bit)
 #define ctl_clear_bit(cr, bit) __ctl_clear_bit(cr, bit)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-s390x/ide.h linux.20pre10-ac2/include/asm-s390x/ide.h
--- linux.20pre10/include/asm-s390x/ide.h	2002-10-09 21:36:39.000000000 +0100
+++ linux.20pre10-ac2/include/asm-s390x/ide.h	2002-08-15 16:47:13.000000000 +0100
@@ -15,45 +15,6 @@
 #define MAX_HWIFS	0
 #endif
 
-#define ide__sti()	do {} while (0)
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		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 */
-	} b;
-} control_t;
-
-#define ide_request_irq(irq,hand,flg,dev,id)	do {} while (0)
-#define ide_free_irq(irq,dev_id)		do {} while (0)
-#define ide_check_region(from,extent)		do {} while (0)
-#define ide_request_region(from,extent,name)	do {} while (0)
-#define ide_release_region(from,extent)		do {} while (0)
-
-/*
- * 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)
-
 /*
  * We always use the new IDE port registering,
  * so these are fixed here.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-s390x/rmap.h linux.20pre10-ac2/include/asm-s390x/rmap.h
--- linux.20pre10/include/asm-s390x/rmap.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/asm-s390x/rmap.h	2002-08-06 15:41:55.000000000 +0100
@@ -0,0 +1,7 @@
+#ifndef _S390X_RMAP_H
+#define _S390X_RMAP_H
+
+/* nothing to see, move along */
+#include <asm-generic/rmap.h>
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-s390x/system.h linux.20pre10-ac2/include/asm-s390x/system.h
--- linux.20pre10/include/asm-s390x/system.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/asm-s390x/system.h	2002-08-13 14:46:55.000000000 +0100
@@ -216,8 +216,13 @@
                 : "cc", "0", "1", "2"); \
         })
 
+
+#define __save_and_cli(x)       do { __save_flags(x); __cli(); } while(0);
+#define __save_and_sti(x)       do { __save_flags(x); __sti(); } while(0);
+
 /* For spinlocks etc */
 #define local_irq_save(x)	((x) = __cli())
+#define local_irq_set(x)	__save_and_sti(x)
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -233,6 +238,8 @@
 #define sti() __global_sti()
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0);
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
 
 extern void smp_ctl_set_bit(int cr, int bit);
 extern void smp_ctl_clear_bit(int cr, int bit);
@@ -245,6 +252,8 @@
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
+#define save_and_cli(x) __save_and_cli(x)
+#define save_and_sti(x) __save_and_sti(x)
 
 #define ctl_set_bit(cr, bit) __ctl_set_bit(cr, bit)
 #define ctl_clear_bit(cr, bit) __ctl_clear_bit(cr, bit)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-sh/hdreg.h linux.20pre10-ac2/include/asm-sh/hdreg.h
--- linux.20pre10/include/asm-sh/hdreg.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-sh/hdreg.h	2002-09-06 00:50:04.000000000 +0100
@@ -7,6 +7,7 @@
 #ifndef __ASM_SH_HDREG_H
 #define __ASM_SH_HDREG_H
 
-typedef unsigned int ide_ioreg_t;
+//typedef unsigned int ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASM_SH_HDREG_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-sh/ide.h linux.20pre10-ac2/include/asm-sh/ide.h
--- linux.20pre10/include/asm-sh/ide.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-sh/ide.h	2002-08-15 16:47:21.000000000 +0100
@@ -22,8 +22,6 @@
 #define MAX_HWIFS	2
 #endif
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq_hp600(ide_ioreg_t base)
 {
 	switch (base) {
@@ -107,43 +105,6 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		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 */
-	} b;
-} control_t;
-
-#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 /* __ASM_SH_IDE_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-sh/ioctls.h linux.20pre10-ac2/include/asm-sh/ioctls.h
--- linux.20pre10/include/asm-sh/ioctls.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-sh/ioctls.h	2002-08-06 15:41:52.000000000 +0100
@@ -9,6 +9,7 @@
 #define FIONBIO		_IOW('f', 126, int)
 #define FIONREAD	_IOR('f', 127, int)
 #define TIOCINQ		FIONREAD
+#define FIOQSIZE	_IOR('f', 128, loff_t)
 
 #define TCGETS		0x5401
 #define TCSETS		0x5402
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-sh/rmap.h linux.20pre10-ac2/include/asm-sh/rmap.h
--- linux.20pre10/include/asm-sh/rmap.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/asm-sh/rmap.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,7 @@
+#ifndef _SH_RMAP_H
+#define _SH_RMAP_H
+
+/* nothing to see, move along */
+#include <asm-generic/rmap.h>
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-sh/system.h linux.20pre10-ac2/include/asm-sh/system.h
--- linux.20pre10/include/asm-sh/system.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-sh/system.h	2002-08-06 15:41:52.000000000 +0100
@@ -215,8 +215,11 @@
 		: "=&r" (__dummy));			\
 } while (0)
 
+#define __save_and_sti(x)       do { __save_flags(x); __sti(); } while(0);
+
 /* For spinlocks etc */
 #define local_irq_save(x)	x = __save_and_cli()
+#define local_irq_set(x)	__save_and_sti(x)
 #define local_irq_restore(x)	__restore_flags(x)
 #define local_irq_disable()	__cli()
 #define local_irq_enable()	__sti()
@@ -231,13 +234,14 @@
 #define sti() __global_sti()
 #define save_flags(x) ((x)=__global_save_flags())
 #define restore_flags(x) __global_restore_flags(x)
-
+#define save_and_sti(x) do { save_flags(x); sti(); } while(0);
 #else
 
 #define cli() __cli()
 #define sti() __sti()
 #define save_flags(x) __save_flags(x)
 #define save_and_cli(x) x = __save_and_cli()
+#define save_and_sti(x) __save_and_sti(x)
 #define restore_flags(x) __restore_flags(x)
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-sh/termios.h linux.20pre10-ac2/include/asm-sh/termios.h
--- linux.20pre10/include/asm-sh/termios.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-sh/termios.h	2002-09-30 17:42:36.000000000 +0100
@@ -37,6 +37,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 
 /* line disciplines */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-sparc/elf.h linux.20pre10-ac2/include/asm-sparc/elf.h
--- linux.20pre10/include/asm-sparc/elf.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-sparc/elf.h	2002-08-06 15:41:52.000000000 +0100
@@ -41,7 +41,7 @@
 	dest[34] = src->npc;				\
 	dest[35] = src->y;				\
 	dest[36] = dest[37] = 0; /* XXX */		\
-} while(0);
+} while(0)
 
 typedef struct {
 	union {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-sparc/ide.h linux.20pre10-ac2/include/asm-sparc/ide.h
--- linux.20pre10/include/asm-sparc/ide.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-sparc/ide.h	2002-08-15 16:47:28.000000000 +0100
@@ -20,8 +20,6 @@
 #undef  MAX_HWIFS
 #define MAX_HWIFS	2
 
-#define	ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	return 0;
@@ -73,56 +71,6 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned int		all	: 8;	/* all of the bits together */
-	struct {
-		unsigned int	bit7	: 1;
-		unsigned int	lba	: 1;
-		unsigned int	bit5	: 1;
-		unsigned int	unit	: 1;
-		unsigned int	head	: 4;
-	} b;
-} select_t;
-
-typedef union {
-	unsigned int all		: 8;	/* all of the bits together */
-	struct {
-		unsigned int HOB	: 1;	/* 48-bit address ordering */
-		unsigned int reserved456: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned int SRST	: 1;	/* host soft reset bit */
-		unsigned int nIEN	: 1;	/* device INTRQ to host */
-		unsigned int bit0	: 1;
-	} b;
-} control_t;
-
-static __inline__ int ide_request_irq(unsigned int irq,
-				      void (*handler)(int, void *, struct pt_regs *),
-				      unsigned long flags, const char *name, void *devid)
-{
-	return request_irq(irq, handler, SA_SHIRQ, name, devid);
-}
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
-	free_irq(irq, dev_id);
-}
-
-static __inline__ int ide_check_region(ide_ioreg_t base, unsigned int size)
-{
-	/* We leave these empty because pcic.c calls sparc_alloc_io() */
-	return 0;
-}
-
-static __inline__ void ide_request_region(ide_ioreg_t base, unsigned int size,
-					  const char *name)
-{
-}
-
-static __inline__ void ide_release_region(ide_ioreg_t base, unsigned int size)
-{
-}
-
 #undef  SUPPORT_SLOW_DATA_PORTS
 #define SUPPORT_SLOW_DATA_PORTS 0
 
@@ -215,103 +163,6 @@
 	/* __flush_dcache_range((unsigned long)src, end); */ /* P3 see hme */
 }
 
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-	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->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);
-}
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-/* #define ide_ack_intr(hwif)	((hwif)->hw.ack_intr ? (hwif)->hw.ack_intr(hwif) : 1) */
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
 #endif /* __KERNEL__ */
 
 #endif /* _SPARC_IDE_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-sparc/ioctls.h linux.20pre10-ac2/include/asm-sparc/ioctls.h
--- linux.20pre10/include/asm-sparc/ioctls.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-sparc/ioctls.h	2002-08-06 15:41:52.000000000 +0100
@@ -86,6 +86,7 @@
 #define FIONBIO		_IOW('f', 126, int)
 #define FIONREAD	_IOR('f', 127, int)
 #define TIOCINQ		FIONREAD
+#define FIOQSIZE	_IOR('f', 128, loff_t)
 
 /* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it
  * someday.  This is completely bogus, I know...
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-sparc/rmap.h linux.20pre10-ac2/include/asm-sparc/rmap.h
--- linux.20pre10/include/asm-sparc/rmap.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/asm-sparc/rmap.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,7 @@
+#ifndef _SPARC_RMAP_H
+#define _SPARC_RMAP_H
+
+/* nothing to see, move along */
+#include <asm-generic/rmap.h>
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-sparc/system.h linux.20pre10-ac2/include/asm-sparc/system.h
--- linux.20pre10/include/asm-sparc/system.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-sparc/system.h	2002-08-06 15:41:52.000000000 +0100
@@ -241,20 +241,21 @@
 	return retval;
 }
 
+#define __save_and_sti(flags)	do { __save_flags(flags); __sti(); } while(0);
+
 #define __save_flags(flags)	((flags) = getipl())
 #define __save_and_cli(flags)	((flags) = read_psr_and_cli())
 #define __restore_flags(flags)	setipl((flags))
 #define local_irq_disable()		__cli()
 #define local_irq_enable()		__sti()
 #define local_irq_save(flags)		__save_and_cli(flags)
+#define local_irq_set(flags)		__save_and_sti(flags)
 #define local_irq_restore(flags)	__restore_flags(flags)
 
 #ifdef CONFIG_SMP
 
 extern unsigned char global_irq_holder;
 
-#define save_and_cli(flags)   do { save_flags(flags); cli(); } while(0)
-
 extern void __global_cli(void);
 extern void __global_sti(void);
 extern unsigned long __global_save_flags(void);
@@ -263,6 +264,7 @@
 #define sti()			__global_sti()
 #define save_flags(flags)	((flags)=__global_save_flags())
 #define restore_flags(flags)	__global_restore_flags(flags)
+#define save_and_sti(flags)	do { save_flags(flags); sti(); } while(0);
 
 #else
 
@@ -271,6 +273,7 @@
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
 #define save_and_cli(x) __save_and_cli(x)
+#define save_and_sti(x) __save_and_sti(x)
 
 #endif
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-sparc/termbits.h linux.20pre10-ac2/include/asm-sparc/termbits.h
--- linux.20pre10/include/asm-sparc/termbits.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/asm-sparc/termbits.h	2002-09-30 17:43:15.000000000 +0100
@@ -210,6 +210,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 #define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-sparc64/ide.h linux.20pre10-ac2/include/asm-sparc64/ide.h
--- linux.20pre10/include/asm-sparc64/ide.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-sparc64/ide.h	2002-08-15 16:47:36.000000000 +0100
@@ -20,8 +20,6 @@
 #undef  MAX_HWIFS
 #define MAX_HWIFS	2
 
-#define	ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	return 0;
@@ -69,57 +67,6 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned int		all	: 8;	/* all of the bits together */
-	struct {
-		unsigned int	bit7	: 1;
-		unsigned int	lba	: 1;
-		unsigned int	bit5	: 1;
-		unsigned int	unit	: 1;
-		unsigned int	head	: 4;
-	} b;
-} select_t;
-
-typedef union {
-	unsigned int all		: 8;	/* all of the bits together */
-	struct {
-		unsigned int HOB	: 1;	/* 48-bit address ordering */
-		unsigned int reserved456: 3;
-		unsigned bit3		: 1;	/* ATA-2 thingy */
-		unsigned int SRST	: 1;	/* host soft reset bit */
-		unsigned int nIEN	: 1;	/* device INTRQ to host */
-		unsigned int bit0	: 1;
-	} b;
-} control_t;
-
-static __inline__ int ide_request_irq(unsigned int irq,
-				      void (*handler)(int, void *, struct pt_regs *),
-				      unsigned long flags, const char *name, void *devid)
-{
-	return request_irq(irq, handler, SA_SHIRQ, name, devid);
-}
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
-	free_irq(irq, dev_id);
-}
-
-static __inline__ int ide_check_region(ide_ioreg_t base, unsigned int size)
-{
-	return check_region(base, size);
-}
-
-static __inline__ void ide_request_region(ide_ioreg_t base, unsigned int size,
-					  const char *name)
-{
-	request_region(base, size, name);
-}
-
-static __inline__ void ide_release_region(ide_ioreg_t base, unsigned int size)
-{
-	release_region(base, size);
-}
-
 #undef  SUPPORT_SLOW_DATA_PORTS
 #define SUPPORT_SLOW_DATA_PORTS 0
 
@@ -232,102 +179,6 @@
 #endif
 }
 
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
-{
-	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->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);
-}
-
-/*
- * The following are not needed for the non-m68k ports
- */
-#define ide_ack_intr(hwif)		(1)
-#define ide_release_lock(lock)		do {} while (0)
-#define ide_get_lock(lock, hdlr, data)	do {} while (0)
-
 #endif /* __KERNEL__ */
 
 #endif /* _SPARC64_IDE_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-sparc64/ioctls.h linux.20pre10-ac2/include/asm-sparc64/ioctls.h
--- linux.20pre10/include/asm-sparc64/ioctls.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-sparc64/ioctls.h	2002-08-06 15:41:52.000000000 +0100
@@ -87,6 +87,7 @@
 #define FIONBIO		_IOW('f', 126, int)
 #define FIONREAD	_IOR('f', 127, int)
 #define TIOCINQ		FIONREAD
+#define FIOQSIZE	_IOR('f', 128, loff_t)
 
 /* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it
  * someday.  This is completely bogus, I know...
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-sparc64/rmap.h linux.20pre10-ac2/include/asm-sparc64/rmap.h
--- linux.20pre10/include/asm-sparc64/rmap.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/asm-sparc64/rmap.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,7 @@
+#ifndef _SPARC64_RMAP_H
+#define _SPARC64_RMAP_H
+
+/* nothing to see, move along */
+#include <asm-generic/rmap.h>
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-sparc64/system.h linux.20pre10-ac2/include/asm-sparc64/system.h
--- linux.20pre10/include/asm-sparc64/system.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-sparc64/system.h	2002-08-06 15:41:52.000000000 +0100
@@ -65,9 +65,13 @@
 #define __save_flags(flags)		((flags) = getipl())
 #define __save_and_cli(flags)		((flags) = read_pil_and_cli())
 #define __restore_flags(flags)		setipl((flags))
+
+#define __save_and_sti(flags)		({ __save_flags(flags); __sti(); })
+
 #define local_irq_disable()		__cli()
 #define local_irq_enable()		__sti()
 #define local_irq_save(flags)		__save_and_cli(flags)
+#define local_irq_set(flags)		__save_and_sti(flags)
 #define local_irq_restore(flags)	__restore_flags(flags)
 
 #ifndef CONFIG_SMP
@@ -76,6 +80,7 @@
 #define save_flags(x) __save_flags(x)
 #define restore_flags(x) __restore_flags(x)
 #define save_and_cli(x) __save_and_cli(x)
+#define save_and_sti(x) __save_and_sti(x)
 #else
 
 #ifndef __ASSEMBLY__
@@ -90,6 +95,7 @@
 #define save_flags(x)		((x) = __global_save_flags())
 #define restore_flags(flags)	__global_restore_flags(flags)
 #define save_and_cli(flags)	do { save_flags(flags); cli(); } while(0)
+#define save_and_sti(flags)	do { save_flags(flags); sti(); } while(0)
 
 #endif
 
@@ -143,7 +149,11 @@
 
 #define flush_user_windows flushw_user
 #define flush_register_windows flushw_all
-#define prepare_to_switch flushw_all
+
+#define prepare_arch_schedule(prev)		task_lock(prev)
+#define finish_arch_schedule(prev)		task_unlock(prev)
+#define prepare_arch_switch(rq)			do { spin_unlock(&(rq)->lock); flushw_all(); }
+#define finish_arch_switch(rq)			__sti()
 
 #ifndef CONFIG_DEBUG_SPINLOCK
 #define CHECK_LOCKS(PREV)	do { } while(0)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-sparc64/termbits.h linux.20pre10-ac2/include/asm-sparc64/termbits.h
--- linux.20pre10/include/asm-sparc64/termbits.h	2002-10-09 21:36:38.000000000 +0100
+++ linux.20pre10-ac2/include/asm-sparc64/termbits.h	2002-09-30 17:43:28.000000000 +0100
@@ -211,6 +211,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 #define TIOCSER_TEMT    0x01	/* Transmitter physically empty */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-x86_64/hdreg.h linux.20pre10-ac2/include/asm-x86_64/hdreg.h
--- linux.20pre10/include/asm-x86_64/hdreg.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/asm-x86_64/hdreg.h	2002-09-26 22:17:44.000000000 +0100
@@ -7,6 +7,7 @@
 #ifndef __ASMx86_64_HDREG_H
 #define __ASMx86_64_HDREG_H
 
-typedef unsigned short ide_ioreg_t;
+//typedef unsigned short ide_ioreg_t;
+typedef unsigned long ide_ioreg_t;
 
 #endif /* __ASMx86_64_HDREG_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-x86_64/ide.h linux.20pre10-ac2/include/asm-x86_64/ide.h
--- linux.20pre10/include/asm-x86_64/ide.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/asm-x86_64/ide.h	2002-09-26 22:17:44.000000000 +0100
@@ -5,7 +5,7 @@
  */
 
 /*
- *  This file contains the x86_64 architecture specific IDE code.
+ *  This file contains the i386 architecture specific IDE code.
  */
 
 #ifndef __ASMx86_64_IDE_H
@@ -23,8 +23,6 @@
 # endif
 #endif
 
-#define ide__sti()	__sti()
-
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
 	switch (base) {
@@ -86,43 +84,6 @@
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 }
 
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		unsigned head		: 4;	/* always zeros here */
-		unsigned unit		: 1;	/* drive select number, 0 or 1 */
-		unsigned bit5		: 1;	/* always 1 */
-		unsigned lba		: 1;	/* using LBA instead of CHS */
-		unsigned bit7		: 1;	/* always 1 */
-	} b;
-} select_t;
-
-typedef union {
-	unsigned all			: 8;	/* all of the bits together */
-	struct {
-		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 */
-	} b;
-} control_t;
-
-#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 /* __ASMx86_64_IDE_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/asm-x86_64/termios.h linux.20pre10-ac2/include/asm-x86_64/termios.h
--- linux.20pre10/include/asm-x86_64/termios.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/asm-x86_64/termios.h	2002-09-30 17:43:42.000000000 +0100
@@ -37,6 +37,8 @@
 #define TIOCM_OUT2	0x4000
 #define TIOCM_LOOP	0x8000
 
+#define TIOCM_MODEM_BITS       TIOCM_OUT2      /* IRDA support */
+
 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 
 /* line disciplines */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/acct.h linux.20pre10-ac2/include/linux/acct.h
--- linux.20pre10/include/linux/acct.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/acct.h	2002-09-18 14:26:34.000000000 +0100
@@ -56,7 +56,9 @@
 	comp_t		ac_swaps;		/* Accounting Number of Swaps */
 	__u32		ac_exitcode;		/* Accounting Exitcode */
 	char		ac_comm[ACCT_COMM + 1];	/* Accounting Command Name */
-	char		ac_pad[10];		/* Accounting Padding Bytes */
+	char		ac_pad[2];		/* Accounting Padding Bytes */
+	__u32		ac_uid32;		/* 32 bit UID */
+	__u32		ac_gid32;		/* 32 bit GID */
 };
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/binfmts.h linux.20pre10-ac2/include/linux/binfmts.h
--- linux.20pre10/include/linux/binfmts.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/binfmts.h	2002-10-11 00:35:04.000000000 +0100
@@ -16,6 +16,8 @@
 
 #ifdef __KERNEL__
 
+struct file;
+
 /*
  * This structure is used to hold the arguments that are used when loading binaries.
  */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/bitops.h linux.20pre10-ac2/include/linux/bitops.h
--- linux.20pre10/include/linux/bitops.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/bitops.h	2002-09-18 14:26:33.000000000 +0100
@@ -1,6 +1,6 @@
 #ifndef _LINUX_BITOPS_H
 #define _LINUX_BITOPS_H
-
+#include <asm/bitops.h>
 
 /*
  * ffs: find first bit set. This is defined the same way as
@@ -38,6 +38,47 @@
 }
 
 /*
+ * fls: find last bit set.
+ */
+
+extern __inline__ int generic_fls(int x)
+{
+	int r = 32;
+
+	if (!x)
+		return 0;
+	if (!(x & 0xffff0000)) {
+		x <<= 16;
+		r -= 16;
+	}
+	if (!(x & 0xff000000)) {
+		x <<= 8;
+		r -= 8;
+	}
+	if (!(x & 0xf0000000)) {
+		x <<= 4;
+		r -= 4;
+	}
+	if (!(x & 0xc0000000)) {
+		x <<= 2;
+		r -= 2;
+	}
+	if (!(x & 0x80000000)) {
+		x <<= 1;
+		r -= 1;
+	}
+	return r;
+}
+
+extern __inline__ int get_bitmask_order(unsigned int count)
+{
+	int order;
+	
+	order = fls(count);
+	return order;	/* We could be slightly more clever with -1 here... */
+}
+
+/*
  * hweightN: returns the hamming weight (i.e. the number
  * of bits set) of a N-bit word
  */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/blkcdb.h linux.20pre10-ac2/include/linux/blkcdb.h
--- linux.20pre10/include/linux/blkcdb.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/linux/blkcdb.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,101 @@
+/*
+ * 2.5 Command Descriptor Block (CDB) Block Pre-Handler.
+ *
+ * Copyright (C) 2001 Andre Hedrick <andre@linux-ide.org>
+ *
+ * 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.
+ *
+ * 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 Licens
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-
+ */
+
+#ifndef _LINUX_BLKCDB_H
+#define _LINUX_BLKCDB_H
+
+typedef struct cdb_list {
+#if 0
+        unsigned char cdb_0;
+        unsigned char cdb_1;
+        unsigned char cdb_2;
+        unsigned char cdb_3;
+        unsigned char cdb_4;
+        unsigned char cdb_5;
+        unsigned char cdb_6;
+        unsigned char cdb_7;
+        unsigned char cdb_8;
+        unsigned char cdb_9;
+        unsigned char cdb_10;
+        unsigned char cdb_11;
+        unsigned char cdb_12;
+        unsigned char cdb_13;
+        unsigned char cdb_14;
+        unsigned char cdb_15;
+#else
+        unsigned char cdb_regs[16];
+#endif
+} cdb_list_t;
+
+#if 0
+
+typedef cdb_list_t * (queue_proc) (kdev_t dev);
+
+request_queue_t *ide_get_queue (kdev_t dev)
+{
+        ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[MAJOR(dev)].data;
+
+        return &hwif->drives[DEVICE_NR(dev) & 1].queue;
+}
+
+static request_queue_t *sd_find_queue(kdev_t dev)
+{
+        Scsi_Disk *dpnt;
+        int target;
+        target = DEVICE_NR(dev);
+
+        dpnt = &rscsi_disks[target];
+        if (!dpnt)
+                return NULL;    /* No such device */
+        return &dpnt->device->request_queue;
+}
+
+prebuilder:             NULL,
+block_device_operations
+struct block_device {
+
+void do_ide_request(request_queue_t *q)
+
+ide_do_request
+
+typedef cdb_list_t (request_cdb_proc) (request_queue_t *q);
+
+typedef cdb_list_t (request_cdb_proc) (request_queue_t *q);
+typedef void (request_fn_proc) (request_queue_t *q);
+
+srb
+
+switch (SCpnt->request.cmd)
+SCpnt->cmnd[0] = WRITE_6/READ_6;
+SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
+			((SCpnt->lun << 5) & 0xe0) : 0;
+SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
+SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff;
+SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff;
+SCpnt->cmnd[5] = (unsigned char) block & 0xff;
+SCpnt->cmnd[6] = 0;
+SCpnt->cmnd[7] = (unsigned char) (this_count >> 8) & 0xff;
+SCpnt->cmnd[8] = (unsigned char) this_count & 0xff;
+SCpnt->cmnd[9] = 0;
+
+#endif
+
+#endif /* _LINUX_BLKCDB_H */
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/blkdev.h linux.20pre10-ac2/include/linux/blkdev.h
--- linux.20pre10/include/linux/blkdev.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/linux/blkdev.h	2002-10-11 00:35:04.000000000 +0100
@@ -140,6 +140,22 @@
 	wait_queue_head_t	wait_for_requests[2];
 };
 
+#define blk_queue_plugged(q)	(q)->plugged
+#define blk_fs_request(rq)	((rq)->cmd == READ || (rq)->cmd == WRITE)
+#define blk_queue_empty(q)	list_empty(&(q)->queue_head)
+
+extern inline int rq_data_dir(struct request *rq)
+{
+	if (rq->cmd == READ)
+		return READ;
+	else if (rq->cmd == WRITE)
+		return WRITE;
+	else {
+		BUG();
+		return -1; /* ahem */
+	}
+}
+
 extern unsigned long blk_max_low_pfn, blk_max_pfn;
 
 #define BLK_BOUNCE_HIGH		(blk_max_low_pfn << PAGE_SHIFT)
@@ -225,6 +241,8 @@
 
 extern int * max_segments[MAX_BLKDEV];
 
+extern char * blkdev_varyio[MAX_BLKDEV];
+
 #define MAX_SEGMENTS 128
 #define MAX_SECTORS 255
 
@@ -278,4 +296,12 @@
 	return retval;
 }
 
+static inline int get_blkdev_varyio(int major, int minor)
+{
+	int retval = 0;
+	if (blkdev_varyio[major]) {
+		retval = blkdev_varyio[major][minor];	
+	}
+	return retval;
+}
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/brlock.h linux.20pre10-ac2/include/linux/brlock.h
--- linux.20pre10/include/linux/brlock.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/linux/brlock.h	2002-09-26 22:46:50.000000000 +0100
@@ -28,13 +28,15 @@
  * load-locked/store-conditional cpus (ALPHA/MIPS/PPC) and
  * compare-and-swap cpus (Sparc64).  So we control which
  * implementation to use with a __BRLOCK_USE_ATOMICS define. -DaveM
+ *
+ * Added BR_LLC_LOCK for use in net/core/ext8022.c -acme
  */
 
 /* Register bigreader lock indices here. */
 enum brlock_indices {
 	BR_GLOBALIRQ_LOCK,
 	BR_NETPROTO_LOCK,
-
+	BR_LLC_LOCK,
 	__BR_END
 };
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/console.h linux.20pre10-ac2/include/linux/console.h
--- linux.20pre10/include/linux/console.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/console.h	2002-09-26 22:46:50.000000000 +0100
@@ -90,6 +90,7 @@
 #define CON_PRINTBUFFER	(1)
 #define CON_CONSDEV	(2) /* Last on the command line */
 #define CON_ENABLED	(4)
+#define CON_BOOT	(8) /* Only used for initial boot */
 
 struct console
 {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/cpufreq.h linux.20pre10-ac2/include/linux/cpufreq.h
--- linux.20pre10/include/linux/cpufreq.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/linux/cpufreq.h	2002-10-10 23:54:36.000000000 +0100
@@ -0,0 +1,247 @@
+/*
+ *  linux/include/linux/cpufreq.h
+ *
+ *  Copyright (C) 2001 Russell King
+ *            (C) 2002 Dominik Brodowski <linux@brodo.de>
+ *            
+ *
+ * $Id: cpufreq.h,v 1.27 2002/10/08 14:54:23 db Exp $
+ *
+ * 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.
+ */
+#ifndef _LINUX_CPUFREQ_H
+#define _LINUX_CPUFREQ_H
+
+#include <linux/config.h>
+#include <linux/notifier.h>
+#include <linux/threads.h>
+
+
+/*********************************************************************
+ *                     CPUFREQ NOTIFIER INTERFACE                    *
+ *********************************************************************/
+
+int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
+int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
+
+#define CPUFREQ_TRANSITION_NOTIFIER     (0)
+#define CPUFREQ_POLICY_NOTIFIER         (1)
+
+#define CPUFREQ_ALL_CPUS        ((NR_CPUS))
+
+
+/********************** cpufreq policy notifiers *********************/
+
+#define CPUFREQ_POLICY_POWERSAVE        (1)
+#define CPUFREQ_POLICY_PERFORMANCE      (2)
+
+/* values here are CPU kHz so that hardware which doesn't run with some
+ * frequencies can complain without having to guess what per cent / per
+ * mille means. */
+struct cpufreq_policy {
+	unsigned int            cpu;    /* cpu nr or CPUFREQ_ALL_CPUS */
+	unsigned int            min;    /* in kHz */
+	unsigned int            max;    /* in kHz */
+        unsigned int            policy; /* see above */
+	unsigned int            max_cpu_freq; /* for information */
+};
+
+#define CPUFREQ_ADJUST          (0)
+#define CPUFREQ_INCOMPATIBLE    (1)
+#define CPUFREQ_NOTIFY          (2)
+
+
+/******************** cpufreq transition notifiers *******************/
+
+#define CPUFREQ_PRECHANGE	(0)
+#define CPUFREQ_POSTCHANGE	(1)
+
+struct cpufreq_freqs {
+	unsigned int cpu;      /* cpu nr or CPUFREQ_ALL_CPUS */
+	unsigned int old;
+	unsigned int new;
+};
+
+
+/**
+ * cpufreq_scale - "old * mult / div" calculation for large values (32-bit-arch safe)
+ * @old:   old value
+ * @div:   divisor
+ * @mult:  multiplier
+ *
+ * Needed for loops_per_jiffy and similar calculations.  We do it 
+ * this way to avoid math overflow on 32-bit machines.  This will
+ * become architecture dependent once high-resolution-timer is
+ * merged (or any other thing that introduces sc_math.h).
+ *
+ *    new = old * mult / div
+ */
+static inline unsigned long cpufreq_scale(unsigned long old, u_int div, u_int mult)
+{
+	unsigned long val, carry;
+
+	mult /= 100;
+	div  /= 100;
+        val   = (old / div) * mult;
+        carry = old % div;
+	carry = carry * mult / div;
+
+	return carry + val;
+};
+
+
+/*********************************************************************
+ *                      DYNAMIC CPUFREQ INTERFACE                    *
+ *********************************************************************/
+#ifdef CONFIG_CPU_FREQ_DYNAMIC
+/* TBD */
+#endif /* CONFIG_CPU_FREQ_DYNAMIC */
+
+
+/*********************************************************************
+ *                      CPUFREQ DRIVER INTERFACE                     *
+ *********************************************************************/
+
+typedef void (*cpufreq_policy_t)          (struct cpufreq_policy *policy);
+
+struct cpufreq_driver {
+	/* needed by all drivers */
+	cpufreq_policy_t        verify;
+	cpufreq_policy_t        setpolicy;
+	struct cpufreq_policy   *policy;
+#ifdef CONFIG_CPU_FREQ_DYNAMIC
+	/* TBD */
+#endif
+	/* 2.4. compatible API */
+#ifdef CONFIG_CPU_FREQ_24_API
+	unsigned int            cpu_min_freq;
+	unsigned int            cpu_cur_freq[NR_CPUS];
+#endif
+};
+
+int cpufreq_register(struct cpufreq_driver *driver_data);
+int cpufreq_unregister(void);
+
+void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state);
+
+
+static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned int min, unsigned int max) 
+{
+	if (policy->min < min)
+		policy->min = min;
+	if (policy->max < min)
+		policy->max = min;
+	if (policy->min > max)
+		policy->min = max;
+	if (policy->max > max)
+		policy->max = max;
+	if (policy->min > policy->max)
+		policy->min = policy->max;
+	return;
+}
+
+/*********************************************************************
+ *                        CPUFREQ 2.6. INTERFACE                     *
+ *********************************************************************/
+int cpufreq_set_policy(struct cpufreq_policy *policy);
+int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
+
+#ifdef CONFIG_PM
+int cpufreq_restore(void);
+#endif
+
+
+#ifdef CONFIG_CPU_FREQ_24_API
+/*********************************************************************
+ *                        CPUFREQ 2.4. INTERFACE                     *
+ *********************************************************************/
+int cpufreq_setmax(unsigned int cpu);
+int cpufreq_set(unsigned int kHz, unsigned int cpu);
+unsigned int cpufreq_get(unsigned int cpu);
+
+/* /proc/sys/cpu */
+enum {
+	CPU_NR   = 1,           /* compatibilty reasons */
+	CPU_NR_0 = 1,
+	CPU_NR_1 = 2,
+	CPU_NR_2 = 3,
+	CPU_NR_3 = 4,
+	CPU_NR_4 = 5,
+	CPU_NR_5 = 6,
+	CPU_NR_6 = 7,
+	CPU_NR_7 = 8,
+	CPU_NR_8 = 9,
+	CPU_NR_9 = 10,
+	CPU_NR_10 = 11,
+	CPU_NR_11 = 12,
+	CPU_NR_12 = 13,
+	CPU_NR_13 = 14,
+	CPU_NR_14 = 15,
+	CPU_NR_15 = 16,
+	CPU_NR_16 = 17,
+	CPU_NR_17 = 18,
+	CPU_NR_18 = 19,
+	CPU_NR_19 = 20,
+	CPU_NR_20 = 21,
+	CPU_NR_21 = 22,
+	CPU_NR_22 = 23,
+	CPU_NR_23 = 24,
+	CPU_NR_24 = 25,
+	CPU_NR_25 = 26,
+	CPU_NR_26 = 27,
+	CPU_NR_27 = 28,
+	CPU_NR_28 = 29,
+	CPU_NR_29 = 30,
+	CPU_NR_30 = 31,
+	CPU_NR_31 = 32,
+};
+
+/* /proc/sys/cpu/{0,1,...,(NR_CPUS-1)} */
+enum {
+	CPU_NR_FREQ_MAX = 1,
+	CPU_NR_FREQ_MIN = 2,
+	CPU_NR_FREQ = 3,
+};
+
+#define CTL_CPU_VARS_SPEED_MAX { \
+                ctl_name: CPU_NR_FREQ_MAX, \
+                data: &cpu_max_freq, \
+                procname: "speed-max", \
+                maxlen:	sizeof(cpu_max_freq),\
+                mode: 0444, \
+                proc_handler: proc_dointvec, }
+
+#define CTL_CPU_VARS_SPEED_MIN { \
+                ctl_name: CPU_NR_FREQ_MIN, \
+                data: &cpu_min_freq, \
+                procname: "speed-min", \
+                maxlen:	sizeof(cpu_min_freq),\
+                mode: 0444, \
+                proc_handler: proc_dointvec, }
+
+#define CTL_CPU_VARS_SPEED(cpunr) { \
+                ctl_name: CPU_NR_FREQ, \
+                procname: "speed", \
+                mode: 0644, \
+                proc_handler: cpufreq_procctl, \
+                strategy: cpufreq_sysctl, \
+                extra1: (void*) (cpunr), }
+
+#define CTL_TABLE_CPU_VARS(cpunr) static ctl_table ctl_cpu_vars_##cpunr[] = {\
+                CTL_CPU_VARS_SPEED_MAX, \
+                CTL_CPU_VARS_SPEED_MIN, \
+                CTL_CPU_VARS_SPEED(cpunr),  \
+                { ctl_name: 0, }, }
+
+/* the ctl_table entry for each CPU */
+#define CPU_ENUM(s) { \
+                ctl_name: (CPU_NR + s), \
+                procname: #s, \
+                mode: 0555, \
+                child: ctl_cpu_vars_##s }
+
+#endif /* CONFIG_CPU_FREQ_24_API */
+
+#endif /* _LINUX_CPUFREQ_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/dcache.h linux.20pre10-ac2/include/linux/dcache.h
--- linux.20pre10/include/linux/dcache.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/linux/dcache.h	2002-09-18 14:26:33.000000000 +0100
@@ -62,7 +62,8 @@
 	return end_name_hash(hash);
 }
 
-#define DNAME_INLINE_LEN 16
+/* XXX: check good value for 64bit */ 
+#define DNAME_INLINE_LEN 32
 
 struct dentry {
 	atomic_t d_count;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/device-mapper.h linux.20pre10-ac2/include/linux/device-mapper.h
--- linux.20pre10/include/linux/device-mapper.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/linux/device-mapper.h	2002-08-12 22:46:07.000000000 +0100
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+ * This file is released under the LGPL.
+ */
+
+#ifndef _LINUX_DEVICE_MAPPER_H
+#define _LINUX_DEVICE_MAPPER_H
+
+#define DM_DIR "mapper"	/* Slashes not supported */
+#define DM_MAX_TYPE_NAME 16
+#define DM_NAME_LEN 128
+#define DM_UUID_LEN 129
+
+#ifdef __KERNEL__
+
+struct dm_table;
+struct dm_dev;
+typedef unsigned long offset_t;
+
+typedef enum { STATUSTYPE_INFO, STATUSTYPE_TABLE } status_type_t;
+
+/*
+ * Prototypes for functions for a target
+ */
+typedef int (*dm_ctr_fn) (struct dm_table *t, offset_t b, offset_t l,
+			  int argc, char **argv, void **context);
+typedef void (*dm_dtr_fn) (struct dm_table *t, void *c);
+typedef int (*dm_map_fn) (struct buffer_head *bh, int rw, void *context);
+typedef int (*dm_err_fn) (struct buffer_head *bh, int rw, void *context);
+typedef int (*dm_status_fn) (status_type_t status_type, char *result,
+			     int maxlen, void *context);
+
+void dm_error(const char *message);
+
+/*
+ * Constructors should call these functions to ensure destination devices
+ * are opened/closed correctly
+ */
+int dm_table_get_device(struct dm_table *t, const char *path,
+			offset_t start, offset_t len,
+			int mode, struct dm_dev **result);
+void dm_table_put_device(struct dm_table *table, struct dm_dev *d);
+
+/*
+ * Information about a target type
+ */
+struct target_type {
+	const char *name;
+	struct module *module;
+	dm_ctr_fn ctr;
+	dm_dtr_fn dtr;
+	dm_map_fn map;
+	dm_err_fn err;
+	dm_status_fn status;
+};
+
+int dm_register_target(struct target_type *t);
+int dm_unregister_target(struct target_type *t);
+
+#endif				/* __KERNEL__ */
+
+#endif				/* _LINUX_DEVICE_MAPPER_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/dm-ioctl.h linux.20pre10-ac2/include/linux/dm-ioctl.h
--- linux.20pre10/include/linux/dm-ioctl.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/linux/dm-ioctl.h	2002-09-18 14:26:34.000000000 +0100
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+ * This file is released under the LGPL.
+ */
+
+#ifndef _LINUX_DM_IOCTL_H
+#define _LINUX_DM_IOCTL_H
+
+#include <linux/device-mapper.h>
+#include <linux/types.h>
+
+/*
+ * Implements a traditional ioctl interface to the device mapper.
+ */
+
+/*
+ * All ioctl arguments consist of a single chunk of memory, with
+ * this structure at the start.  If a uuid is specified any
+ * lookup (eg. for a DM_INFO) will be done on that, *not* the
+ * name.
+ */
+struct dm_ioctl {
+	/*
+	 * The version number is made up of three parts:
+	 * major - no backward or forward compatibility,
+	 * minor - only backwards compatible,
+	 * patch - both backwards and forwards compatible.
+	 *
+	 * All clients of the ioctl interface should fill in the
+	 * version number of the interface that they were
+	 * compiled with.
+	 *
+	 * All recognised ioctl commands (ie. those that don't
+	 * return -ENOTTY) fill out this field, even if the
+	 * command failed.
+	 */
+	uint32_t version[3];	/* in/out */
+	uint32_t data_size;	/* total size of data passed in
+				 * including this struct */
+
+	uint32_t data_start;	/* offset to start of data
+				 * relative to start of this struct */
+
+	uint32_t target_count;	/* in/out */
+	uint32_t open_count;	/* out */
+	uint32_t flags;		/* in/out */
+
+	__kernel_dev_t dev;	/* in/out */
+
+	char name[DM_NAME_LEN];	/* device name */
+	char uuid[DM_UUID_LEN];	/* unique identifier for
+				 * the block device */
+};
+
+/*
+ * Used to specify tables.  These structures appear after the
+ * dm_ioctl.
+ */
+struct dm_target_spec {
+	int32_t status;		/* used when reading from kernel only */
+	uint64_t sector_start;
+	uint32_t length;
+
+	/*
+	 * Offset in bytes (from the start of this struct) to
+	 * next target_spec.
+	 */
+	uint32_t next;
+
+	char target_type[DM_MAX_TYPE_NAME];
+
+	/*
+	 * Parameter string starts immediately after this object.
+	 * Be careful to add padding after string to ensure correct
+	 * alignment of subsequent dm_target_spec.
+	 */
+};
+
+/*
+ * Used to retrieve the target dependencies.
+ */
+struct dm_target_deps {
+	uint32_t count;
+
+	__kernel_dev_t dev[0];	/* out */
+};
+
+/*
+ * If you change this make sure you make the corresponding change
+ * to dm-ioctl.c:lookup_ioctl()
+ */
+enum {
+	/* Top level cmds */
+	DM_VERSION_CMD = 0,
+	DM_REMOVE_ALL_CMD,
+
+	/* device level cmds */
+	DM_DEV_CREATE_CMD,
+	DM_DEV_REMOVE_CMD,
+	DM_DEV_RELOAD_CMD,
+	DM_DEV_RENAME_CMD,
+	DM_DEV_SUSPEND_CMD,
+	DM_DEV_DEPS_CMD,
+	DM_DEV_STATUS_CMD,
+
+	/* target level cmds */
+	DM_TARGET_STATUS_CMD,
+	DM_TARGET_WAIT_CMD
+};
+
+#define DM_IOCTL 0xfd
+
+#define DM_VERSION       _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl)
+#define DM_REMOVE_ALL    _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl)
+
+#define DM_DEV_CREATE    _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl)
+#define DM_DEV_REMOVE    _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl)
+#define DM_DEV_RELOAD    _IOWR(DM_IOCTL, DM_DEV_RELOAD_CMD, struct dm_ioctl)
+#define DM_DEV_SUSPEND   _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl)
+#define DM_DEV_RENAME    _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl)
+#define DM_DEV_DEPS      _IOWR(DM_IOCTL, DM_DEV_DEPS_CMD, struct dm_ioctl)
+#define DM_DEV_STATUS    _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl)
+
+#define DM_TARGET_STATUS _IOWR(DM_IOCTL, DM_TARGET_STATUS_CMD, struct dm_ioctl)
+#define DM_TARGET_WAIT   _IOWR(DM_IOCTL, DM_TARGET_WAIT_CMD, struct dm_ioctl)
+
+#define DM_VERSION_MAJOR	1
+#define DM_VERSION_MINOR	0
+#define DM_VERSION_PATCHLEVEL	3
+#define DM_VERSION_EXTRA	"-ioctl-bk (2002-08-5)"
+
+/* Status bits */
+#define DM_READONLY_FLAG	0x00000001
+#define DM_SUSPEND_FLAG		0x00000002
+#define DM_EXISTS_FLAG		0x00000004
+#define DM_PERSISTENT_DEV_FLAG	0x00000008
+
+/*
+ * Flag passed into ioctl STATUS command to get table information
+ * rather than current status.
+ */
+#define DM_STATUS_TABLE_FLAG	0x00000010
+
+#endif				/* _LINUX_DM_IOCTL_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/dqblk_v1.h linux.20pre10-ac2/include/linux/dqblk_v1.h
--- linux.20pre10/include/linux/dqblk_v1.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/linux/dqblk_v1.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,18 @@
+/*
+ *	File with in-memory structures of old quota format
+ */
+
+#ifndef _LINUX_DQBLK_V1_H
+#define _LINUX_DQBLK_V1_H
+
+/* Id of quota format */
+#define QFMT_VFS_OLD 1
+
+/* Root squash turned on */
+#define V1_DQF_RSQUASH 1
+
+/* Special information about quotafile */
+struct v1_mem_dqinfo {
+};
+
+#endif	/* _LINUX_DQBLK_V1_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/dqblk_v2.h linux.20pre10-ac2/include/linux/dqblk_v2.h
--- linux.20pre10/include/linux/dqblk_v2.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/linux/dqblk_v2.h	2002-09-18 14:26:33.000000000 +0100
@@ -0,0 +1,20 @@
+/*
+ *	Definitions of structures for vfsv0 quota format
+ */
+
+#ifndef _LINUX_DQBLK_V2_H
+#define _LINUX_DQBLK_V2_H
+
+#include <linux/types.h>
+
+/* id numbers of quota format */
+#define QFMT_VFS_V0 2
+
+/* Inmemory copy of version specific information */
+struct v2_mem_dqinfo {
+	unsigned int dqi_blocks;
+	unsigned int dqi_free_blk;
+	unsigned int dqi_free_entry;
+};
+
+#endif /* _LINUX_DQBLK_V2_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/dqblk_xfs.h linux.20pre10-ac2/include/linux/dqblk_xfs.h
--- linux.20pre10/include/linux/dqblk_xfs.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/linux/dqblk_xfs.h	2002-09-18 14:26:33.000000000 +0100
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 1995-2001 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ * USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef _LINUX_DQBLK_XFS_H
+#define _LINUX_DQBLK_XFS_H
+
+#include <linux/types.h>
+
+/*
+ * Disk quota - quotactl(2) commands for the XFS Quota Manager (XQM).
+ */
+
+#define XQM_CMD(x)	(('X'<<8)+(x))	/* note: forms first QCMD argument */
+#define Q_XQUOTAON	XQM_CMD(0x1)	/* enable accounting/enforcement */
+#define Q_XQUOTAOFF	XQM_CMD(0x2)	/* disable accounting/enforcement */
+#define Q_XGETQUOTA	XQM_CMD(0x3)	/* get disk limits and usage */
+#define Q_XSETQLIM	XQM_CMD(0x4)	/* set disk limits */
+#define Q_XGETQSTAT	XQM_CMD(0x5)	/* get quota subsystem status */
+#define Q_XQUOTARM	XQM_CMD(0x6)	/* free disk space used by dquots */
+
+/*
+ * fs_disk_quota structure:
+ *
+ * This contains the current quota information regarding a user/proj/group.
+ * It is 64-bit aligned, and all the blk units are in BBs (Basic Blocks) of
+ * 512 bytes.
+ */
+#define FS_DQUOT_VERSION	1	/* fs_disk_quota.d_version */
+typedef struct fs_disk_quota {
+	__s8		d_version;	/* version of this structure */
+	__s8		d_flags;	/* XFS_{USER,PROJ,GROUP}_QUOTA */
+	__u16		d_fieldmask;	/* field specifier */
+	__u32		d_id;		/* user, project, or group ID */
+	__u64		d_blk_hardlimit;/* absolute limit on disk blks */
+	__u64		d_blk_softlimit;/* preferred limit on disk blks */
+	__u64		d_ino_hardlimit;/* maximum # allocated inodes */
+	__u64		d_ino_softlimit;/* preferred inode limit */
+	__u64		d_bcount;	/* # disk blocks owned by the user */
+	__u64		d_icount;	/* # inodes owned by the user */
+	__s32		d_itimer;	/* zero if within inode limits */
+					/* if not, we refuse service */
+	__s32		d_btimer;	/* similar to above; for disk blocks */
+	__u16	  	d_iwarns;       /* # warnings issued wrt num inodes */
+	__u16	  	d_bwarns;       /* # warnings issued wrt disk blocks */
+	__s32		d_padding2;	/* padding2 - for future use */
+	__u64		d_rtb_hardlimit;/* absolute limit on realtime blks */
+	__u64		d_rtb_softlimit;/* preferred limit on RT disk blks */
+	__u64		d_rtbcount;	/* # realtime blocks owned */
+	__s32		d_rtbtimer;	/* similar to above; for RT disk blks */
+	__u16	  	d_rtbwarns;     /* # warnings issued wrt RT disk blks */
+	__s16		d_padding3;	/* padding3 - for future use */	
+	char		d_padding4[8];	/* yet more padding */
+} fs_disk_quota_t;
+
+/*
+ * These fields are sent to Q_XSETQLIM to specify fields that need to change.
+ */
+#define FS_DQ_ISOFT	(1<<0)
+#define FS_DQ_IHARD	(1<<1)
+#define FS_DQ_BSOFT	(1<<2)
+#define FS_DQ_BHARD 	(1<<3)
+#define FS_DQ_RTBSOFT	(1<<4)
+#define FS_DQ_RTBHARD	(1<<5)
+#define FS_DQ_LIMIT_MASK	(FS_DQ_ISOFT | FS_DQ_IHARD | FS_DQ_BSOFT | \
+				 FS_DQ_BHARD | FS_DQ_RTBSOFT | FS_DQ_RTBHARD)
+/*
+ * These timers can only be set in super user's dquot. For others, timers are
+ * automatically started and stopped. Superusers timer values set the limits
+ * for the rest.  In case these values are zero, the DQ_{F,B}TIMELIMIT values
+ * defined below are used. 
+ * These values also apply only to the d_fieldmask field for Q_XSETQLIM.
+ */
+#define FS_DQ_BTIMER	(1<<6)
+#define FS_DQ_ITIMER	(1<<7)
+#define FS_DQ_RTBTIMER 	(1<<8)
+#define FS_DQ_TIMER_MASK	(FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER)
+
+/*
+ * The following constants define the default amount of time given a user
+ * before the soft limits are treated as hard limits (usually resulting
+ * in an allocation failure).  These may be modified by the quotactl(2)
+ * system call with the Q_XSETQLIM command.
+ */
+#define	DQ_FTIMELIMIT	(7 * 24*60*60)		/* 1 week */
+#define	DQ_BTIMELIMIT	(7 * 24*60*60)		/* 1 week */
+
+/*
+ * Various flags related to quotactl(2).  Only relevant to XFS filesystems.
+ */
+#define XFS_QUOTA_UDQ_ACCT	(1<<0)  /* user quota accounting */
+#define XFS_QUOTA_UDQ_ENFD	(1<<1)  /* user quota limits enforcement */
+#define XFS_QUOTA_GDQ_ACCT	(1<<2)  /* group quota accounting */
+#define XFS_QUOTA_GDQ_ENFD	(1<<3)  /* group quota limits enforcement */
+
+#define XFS_USER_QUOTA		(1<<0)	/* user quota type */
+#define XFS_PROJ_QUOTA		(1<<1)	/* (IRIX) project quota type */
+#define XFS_GROUP_QUOTA		(1<<2)	/* group quota type */
+
+/*
+ * fs_quota_stat is the struct returned in Q_XGETQSTAT for a given file system.
+ * Provides a centralized way to get meta infomation about the quota subsystem.
+ * eg. space taken up for user and group quotas, number of dquots currently
+ * incore.
+ */
+#define FS_QSTAT_VERSION	1	/* fs_quota_stat.qs_version */
+
+/*
+ * Some basic infomation about 'quota files'.
+ */
+typedef struct fs_qfilestat {
+	__u64		qfs_ino;	/* inode number */
+	__u64		qfs_nblks;	/* number of BBs 512-byte-blks */
+	__u32		qfs_nextents;	/* number of extents */
+} fs_qfilestat_t;
+
+typedef struct fs_quota_stat {
+	__s8		qs_version;	/* version number for future changes */
+	__u16		qs_flags;	/* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
+	__s8		qs_pad;		/* unused */
+	fs_qfilestat_t	qs_uquota;	/* user quota storage information */
+	fs_qfilestat_t	qs_gquota;	/* group quota storage information */
+	__u32		qs_incoredqs;	/* number of dquots incore */
+	__s32		qs_btimelimit;  /* limit for blks timer */	
+	__s32		qs_itimelimit;  /* limit for inodes timer */	
+	__s32		qs_rtbtimelimit;/* limit for rt blks timer */	
+	__u16		qs_bwarnlimit;	/* limit for num warnings */
+	__u16		qs_iwarnlimit;	/* limit for num warnings */
+} fs_quota_stat_t;
+
+#endif	/* _LINUX_DQBLK_XFS_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/fsfilter.h linux.20pre10-ac2/include/linux/fsfilter.h
--- linux.20pre10/include/linux/fsfilter.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/linux/fsfilter.h	2002-10-10 23:26:12.000000000 +0100
@@ -1,3 +1,7 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ */
+
 #ifndef __FILTER_H_
 #define __FILTER_H_ 1
 
@@ -59,12 +63,13 @@
         struct snapshot_ops *o_snops;
 };
 
-#define FILTER_FS_TYPES 5
+#define FILTER_FS_TYPES 6
 #define FILTER_FS_EXT2 0
 #define FILTER_FS_EXT3 1
 #define FILTER_FS_REISERFS 2
 #define FILTER_FS_XFS 3
 #define FILTER_FS_OBDFS 4
+#define FILTER_FS_TMPFS 5
 extern struct filter_fs filter_oppar[FILTER_FS_TYPES];
 
 struct filter_fs *filter_get_filter_fs(const char *cache_type);
@@ -96,7 +101,7 @@
 #define PRESTO_DEBUG
 #ifdef PRESTO_DEBUG
 /* debugging masks */
-#define D_SUPER     1   /* print results returned by Venus */
+#define D_SUPER     1  
 #define D_INODE     2   /* print entry and exit into procedure */
 #define D_FILE      4
 #define D_CACHE     8   /* cache debugging */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/fs.h linux.20pre10-ac2/include/linux/fs.h
--- linux.20pre10/include/linux/fs.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/linux/fs.h	2002-10-11 00:22:45.000000000 +0100
@@ -206,7 +206,7 @@
 extern void buffer_init(unsigned long);
 extern void inode_init(unsigned long);
 extern void mnt_init(unsigned long);
-extern void files_init(unsigned long mempages);
+extern void files_init(unsigned long);
 
 /* bh state bits */
 enum bh_state_bits {
@@ -220,6 +220,7 @@
 	BH_Wait_IO,	/* 1 if we should write out this buffer */
 	BH_Launder,	/* 1 if we can throttle on this buffer */
 	BH_JBD,		/* 1 if it has an attached journal_head */
+	BH_Inode,	/* 1 if it is attached to i_dirty[_data]_buffers */
 
 	BH_PrivateStart,/* not a state bit, but the first bit available
 			 * for private allocation by other entities
@@ -262,11 +263,10 @@
 	struct page *b_page;		/* the page this bh is mapped to */
 	void (*b_end_io)(struct buffer_head *bh, int uptodate); /* I/O completion */
  	void *b_private;		/* reserved for b_end_io */
-
+ 	void *b_journal_head;		/* ext3 journal_heads */
 	unsigned long b_rsector;	/* Real buffer location on disk */
 	wait_queue_head_t b_wait;
 
-	struct inode *	     b_inode;
 	struct list_head     b_inode_buffers;	/* doubly linked list of inode dirty buffers */
 };
 
@@ -395,7 +395,8 @@
 	int (*flushpage) (struct page *, unsigned long);
 	int (*releasepage) (struct page *, int);
 #define KERNEL_HAS_O_DIRECT /* this is for modules out of the kernel */
-	int (*direct_IO)(int, struct inode *, struct kiobuf *, unsigned long, int);
+	int (*direct_IO)(int, struct file *, struct kiobuf *, unsigned long, int);
+	void (*removepage)(struct page *); /* called when page gets removed from the inode */
 };
 
 struct address_space {
@@ -454,6 +455,7 @@
 	unsigned long		i_blksize;
 	unsigned long		i_blocks;
 	unsigned long		i_version;
+	unsigned short		i_bytes;
 	struct semaphore	i_sem;
 	struct semaphore	i_zombie;
 	struct inode_operations	*i_op;
@@ -514,6 +516,39 @@
 	} u;
 };
 
+static inline void inode_add_bytes(struct inode *inode, loff_t bytes)
+{
+	inode->i_blocks += bytes >> 9;
+	bytes &= 511;
+	inode->i_bytes += bytes;
+	if (inode->i_bytes >= 512) {
+		inode->i_blocks++;
+		inode->i_bytes -= 512;
+	}
+}
+
+static inline void inode_sub_bytes(struct inode *inode, loff_t bytes)
+{
+	inode->i_blocks -= bytes >> 9;
+	bytes &= 511;
+	if (inode->i_bytes < bytes) {
+		inode->i_blocks--;
+		inode->i_bytes += 512;
+	}
+	inode->i_bytes -= bytes;
+}
+
+static inline loff_t inode_get_bytes(struct inode *inode)
+{
+	return (((loff_t)inode->i_blocks) << 9) + inode->i_bytes;
+}
+
+static inline void inode_set_bytes(struct inode *inode, loff_t bytes)
+{
+	inode->i_blocks = bytes >> 9;
+	inode->i_bytes = bytes & 511;
+}
+
 struct fown_struct {
 	int pid;		/* pid or -pgrp where SIGIO should be sent */
 	uid_t uid, euid;	/* uid/euid of process setting the owner */
@@ -659,20 +694,6 @@
 	int last_type;
 };
 
-#define DQUOT_USR_ENABLED	0x01		/* User diskquotas enabled */
-#define DQUOT_GRP_ENABLED	0x02		/* Group diskquotas enabled */
-
-struct quota_mount_options
-{
-	unsigned int flags;			/* Flags for diskquotas on this device */
-	struct semaphore dqio_sem;		/* lock device while I/O in progress */
-	struct semaphore dqoff_sem;		/* serialize quota_off() and quota_on() on device */
-	struct file *files[MAXQUOTAS];		/* fp's to quotafiles */
-	time_t inode_expire[MAXQUOTAS];		/* expiretime for inode-quota */
-	time_t block_expire[MAXQUOTAS];		/* expiretime for block-quota */
-	char rsquash[MAXQUOTAS];		/* for quotas threat root as any other user */
-};
-
 /*
  *	Umount options
  */
@@ -720,6 +741,7 @@
 	struct file_system_type	*s_type;
 	struct super_operations	*s_op;
 	struct dquot_operations	*dq_op;
+	struct quotactl_ops	*s_qcop;
 	unsigned long		s_flags;
 	unsigned long		s_magic;
 	struct dentry		*s_root;
@@ -734,7 +756,7 @@
 
 	struct block_device	*s_bdev;
 	struct list_head	s_instances;
-	struct quota_mount_options s_dquot;	/* Diskquota specific options */
+ 	struct quota_info s_dquot;	/* Diskquota specific options */
 
 	union {
 		struct minix_sb_info	minix_sb;
@@ -954,16 +976,6 @@
 	__mark_inode_dirty(inode, I_DIRTY_PAGES);
 }
 
-struct dquot_operations {
-	void (*initialize) (struct inode *, short);
-	void (*drop) (struct inode *);
-	int (*alloc_block) (struct inode *, unsigned long, char);
-	int (*alloc_inode) (const struct inode *, unsigned long);
-	void (*free_block) (struct inode *, unsigned long);
-	void (*free_inode) (const struct inode *, unsigned long);
-	int (*transfer) (struct inode *, struct iattr *);
-};
-
 struct file_system_type {
 	const char *name;
 	int fs_flags;
@@ -1186,6 +1198,21 @@
 		clear_bit(BH_Async, &bh->b_state);
 }
 
+static inline void set_buffer_inode(struct buffer_head *bh)
+{
+	set_bit(BH_Inode, &bh->b_state);
+}
+
+static inline void clear_buffer_inode(struct buffer_head *bh)
+{
+	clear_bit(BH_Inode, &bh->b_state);
+}
+
+static inline int buffer_inode(struct buffer_head *bh)
+{
+	return test_bit(BH_Inode, &bh->b_state);
+}
+
 /*
  * If an error happens during the make_request, this function
  * has to be recalled. It marks the buffer as clean and not
@@ -1377,6 +1404,7 @@
 extern struct buffer_head * getblk(kdev_t, int, int);
 extern void ll_rw_block(int, int, struct buffer_head * bh[]);
 extern void submit_bh(int, struct buffer_head *);
+extern void submit_bh_blknr(int, struct buffer_head *);
 extern int is_read_only(kdev_t);
 extern void __brelse(struct buffer_head *);
 static inline void brelse(struct buffer_head *buf)
@@ -1474,8 +1502,6 @@
 	}
 	return 0;
 }
-unsigned long generate_cluster(kdev_t, int b[], int);
-unsigned long generate_cluster_swab32(kdev_t, int b[], int);
 extern kdev_t ROOT_DEV;
 extern char root_device_name[];
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/hdreg.h linux.20pre10-ac2/include/linux/hdreg.h
--- linux.20pre10/include/linux/hdreg.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/hdreg.h	2002-09-30 17:01:32.000000000 +0100
@@ -34,6 +34,7 @@
 #define ECC_STAT		0x04	/* Corrected error */
 #define DRQ_STAT		0x08
 #define SEEK_STAT		0x10
+#define SRV_STAT		0x10
 #define WRERR_STAT		0x20
 #define READY_STAT		0x40
 #define BUSY_STAT		0x80
@@ -49,6 +50,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
  *	HDIO_DRIVE_CMD, HDIO_DRIVE_TASK, and HDIO_DRIVE_TASKFILE
@@ -61,6 +69,8 @@
 typedef unsigned char task_ioreg_t;
 #endif
 
+typedef unsigned long sata_ioreg_t;
+
 #define HDIO_DRIVE_CMD_HDR_SIZE		4*sizeof(task_ioreg_t)
 #define HDIO_DRIVE_TASK_HDR_SIZE	8*sizeof(task_ioreg_t)
 #define HDIO_DRIVE_HOB_HDR_SIZE		8*sizeof(task_ioreg_t)
@@ -131,8 +141,8 @@
  */
 #define IDE_TASKFILE_STD_OUT_FLAGS	0xFE
 #define IDE_TASKFILE_STD_IN_FLAGS	0xFE
-#define IDE_HOB_STD_OUT_FLAGS		0xC0
-#define IDE_HOB_STD_IN_FLAGS		0xC0
+#define IDE_HOB_STD_OUT_FLAGS		0x3C
+#define IDE_HOB_STD_IN_FLAGS		0x3C
 
 typedef struct ide_task_request_s {
 	task_ioreg_t	io_ports[8];
@@ -177,37 +187,82 @@
 
 /* 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
-#define WIN_RESTORE			0x10
+/*
+ *	0x09->0x0F Reserved
+ */
+#define WIN_RECAL			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
@@ -218,10 +273,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
@@ -233,6 +293,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
@@ -270,7 +332,7 @@
 #define SMART_HCYL_PASS			0xC2
 		
 /* WIN_SETFEATURES sub-commands */
-
+#define SETFEATURES_EN_8BIT	0x01	/* Enable 8-Bit Transfers */
 #define SETFEATURES_EN_WCACHE	0x02	/* Enable write cache */
 #define SETFEATURES_XFER	0x03	/* Set transfer mode */
 #	define XFER_UDMA_7	0x47	/* 0100|0111 */
@@ -295,22 +357,33 @@
 #	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 */
+#define SETFEATURES_RW_LONG	0x44	/* Set Lenght of VS bytes */
+#define SETFEATURES_SET_CACHE	0x54	/* Set Cache segments to SC Reg. Val */
 #define SETFEATURES_DIS_RLA	0x55	/* Disable read look-ahead feature */
 #define SETFEATURES_EN_RI	0x5D	/* Enable release interrupt */
 #define SETFEATURES_EN_SI	0x5E	/* Enable SERVICE interrupt */
 #define SETFEATURES_DIS_RPOD	0x66	/* Disable reverting to power on defaults */
+#define SETFEATURES_DIS_ECC	0x77	/* Disable ECC byte count */
+#define SETFEATURES_DIS_8BIT	0x81	/* Disable 8-Bit Transfers */
 #define SETFEATURES_DIS_WCACHE	0x82	/* Disable write cache */
 #define SETFEATURES_EN_DEFECT	0x84	/* Enable Defect Management */
 #define SETFEATURES_DIS_APM	0x85	/* Disable advanced power management */
+#define SETFEATURES_EN_ECC	0x88	/* Enable ECC byte count */
 #define SETFEATURES_EN_MSN	0x95	/* Enable Media Status Notification */
+#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 */
 
@@ -341,6 +414,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 */
@@ -389,6 +465,9 @@
 #define HDIO_GETGEO_BIG		0x0330	/* */
 #define HDIO_GETGEO_BIG_RAW	0x0331	/* */
 
+#define HDIO_SET_IDE_SCSI	0x0338
+#define HDIO_SET_SCSI_IDE	0x0339
+
 #define __NEW_HD_DRIVE_ID
 /* structure returned by HDIO_GET_IDENTITY,
  * as per ANSI NCITS ATA6 rev.1b spec
@@ -501,7 +580,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
@@ -548,19 +630,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:
@@ -574,18 +659,17 @@
 					 *  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 */
-#if 0
-	unsigned short	words100_103[4]	;/* reserved words 100-103 */
-#else
+	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 */
-#endif
 	unsigned short	words104_125[22];/* reserved words 104-125 */
 	unsigned short	last_lun;	/* (word 126) */
 	unsigned short	word127;	/* (word 127) Feature Set
@@ -654,7 +738,7 @@
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 int ide_register(int io_port, int ctl_port, int irq);
-void ide_unregister(unsigned int);
+int ide_unregister(unsigned int);
 #endif /* CONFIG_BLK_DEV_IDE || CONFIG_BLK_DEV_IDE_MODULE */
 
 #endif  /* __KERNEL__ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/ide.h linux.20pre10-ac2/include/linux/ide.h
--- linux.20pre10/include/linux/ide.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/linux/ide.h	2002-10-11 00:35:04.000000000 +0100
@@ -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,7 +14,37 @@
 #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/highmem.h>
+#include <linux/pci.h>
+#include <asm/byteorder.h>
+#include <asm/system.h>
 #include <asm/hdreg.h>
+#include <asm/io.h>
+
+#define CLASSIC_BUILTINS_METHOD				1
+//#undef CLASSIC_BUILTINS_METHOD
+#define HWIF_PROBE_CLASSIC_METHOD			1
+//#undef HWIF_PROBE_CLASSIC_METHOD
+
+#ifdef CLASSIC_BUILTINS_METHOD
+#  undef FAKE_CLASSIC_ATTACH_METHOD
+#  undef DIRECT_HWIF_PROBE_ATTACH_METHOD
+#else /* ! CLASSIC_BUILTINS_METHOD */
+#  ifdef HWIF_PROBE_CLASSIC_METHOD
+#    undef FAKE_CLASSIC_ATTACH_METHOD
+#    undef DIRECT_HWIF_PROBE_ATTACH_METHOD
+#  else /* ! HWIF_PROBE_CLASSIC_METHOD */
+//#    define FAKE_CLASSIC_ATTACH_METHOD			1
+#    undef FAKE_CLASSIC_ATTACH_METHOD
+#    ifdef FAKE_CLASSIC_ATTACH_METHOD
+#      undef DIRECT_HWIF_PROBE_ATTACH_METHOD
+#    else /* ! FAKE_CLASSIC_ATTACH_METHOD */
+#      define DIRECT_HWIF_PROBE_ATTACH_METHOD		1
+#    endif /* FAKE_CLASSIC_ATTACH_METHOD */
+#  endif /* HWIF_PROBE_CLASSIC_METHOD */
+#endif /* CLASSIC_BUILTINS_METHOD */
 
 /*
  * This is the multiple IDE interface driver, as evolved from hd.c.
@@ -160,9 +190,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)
@@ -170,6 +197,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))
+
 /*
  * Some more useful definitions
  */
@@ -178,21 +242,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:
  */
@@ -207,39 +262,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;		\
@@ -267,9 +289,24 @@
 		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 (*OUTSW)(u32 port, void *addr, u32 count);
+	void (*OUTSL)(u32 port, void *addr, u32 count);
+
+	u8  (*INB)(u32 port);
+	u16 (*INW)(u32 port);
+	u32 (*INL)(u32 port);
+	void (*INSW)(u32 port, void *addr, u32 count);
+	void (*INSL)(u32 port, void *addr, u32 count);
+} ide_io_ops_t;
+
 /*
  * Structure to hold all information about the location of this port
  */
@@ -280,6 +317,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;
 
 /*
@@ -296,34 +338,26 @@
 			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>
 
-/*
- * If the arch-dependant ide.h did not declare/define any OUT_BYTE
- * or IN_BYTE functions, we make some defaults here.
- */
-
-#ifndef HAVE_ARCH_OUT_BYTE
-#ifdef REALLY_FAST_IO
-#define OUT_BYTE(b,p)          outb((b),(p))
-#define OUT_WORD(w,p)          outw((w),(p))
+/* 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 OUT_BYTE(b,p)          outb_p((b),(p))
-#define OUT_WORD(w,p)          outw_p((w),(p))
-#endif
+# define ide_ack_intr(hwif) (1)
 #endif
 
-#ifndef HAVE_ARCH_IN_BYTE
-#ifdef REALLY_FAST_IO
-#define IN_BYTE(p)             (byte)inb(p)
-#define IN_WORD(p)             (short)inw(p)
-#else
-#define IN_BYTE(p)             (byte)inb_p(p)
-#define IN_WORD(p)             (short)inw_p(p)
-#endif
-#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 */
 
 /*
  * Now for the data we need to maintain per-drive:  ide_drive_t
@@ -336,235 +370,638 @@
 #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 {
-		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 reserved	: 4;	/* unused */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		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;
+		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;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		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 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;
+} 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;
+	struct {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+		unsigned bit0		: 1;
+		unsigned nIEN		: 1;
+		unsigned SRST		: 1;
+		unsigned bit3		: 1;
+		unsigned reserved456	: 3;
+		unsigned HOB		: 1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+		unsigned HOB		: 1;
+		unsigned reserved456	: 3;
+		unsigned bit3		: 1;
+		unsigned SRST		: 1;
+		unsigned nIEN		: 1;
+		unsigned bit0		: 1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	} b;
+} 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 */
+
+	wait_queue_head_t wqueue;	/* used to wait for drive in open() */
+	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 hd_struct	*part;	/* drive partition table */
+	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 busy		: 1;	/* currently doing revalidate_disk() */
 	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 nobios		: 1;	/* do not probe bios for drive */
 	unsigned revalidate	: 1;	/* request revalidation */
-	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 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;	/* : 2; 0=28-bit, 1=48-bit, 2=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 */
+	unsigned dead		: 1;	/* 1=dead, no new attachments */
+	unsigned addressing;		/*      : 3;
+					 *  0=28-bit
+					 *  1=48-bit
+					 *  2=48-bit doing 28-bit
+					 *  3=64-bit
+					 */
+
+	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 */
-	void		  *hwif;	/* actually (ide_hwif_t *) */
-	wait_queue_head_t wqueue;	/* used to wait for drive in open() */
-	struct hd_driveid *id;		/* drive model identification info */
-	struct hd_struct  *part;	/* drive partition table */
-	char		name[4];	/* drive name, such as "hda" */
-	void 		*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 */
-	void		*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 */
 } 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_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 *);
+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;
 
 /*
- * 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.
+ * mapping stuff, prepare for highmem...
  *
+ * temporarily mapping a (possible) highmem bio for PIO transfer
  */
-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);
+#define ide_rq_offset(rq) \
+	(((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
 
-/*
- * 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);
+extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags)
+{
+	return bh_kmap_irq(rq->bh, flags) + ide_rq_offset(rq);
+}
 
-/*
- * ide soft-power support
- */
-typedef int (ide_busproc_t) (ide_drive_t *, int);
+extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags)
+{
+	bh_kunmap_irq(buffer, flags);
+}
 
 #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)
-#endif /* CONFIG_BLK_DEV_IDEPCI */
+struct ide_pci_device_s;
 
 typedef struct hwif_s {
-	struct hwif_s	*next;		/* for linked-list in ide_hwgroup_t */
-	void		*hwgroup;	/* actually (ide_hwgroup_t *) */
-	ide_ioreg_t	io_ports[IDE_NR_PORTS];	/* task file registers */
+	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 *) */
+	struct proc_dir_entry *proc;	/* /proc/ide/ directory entry */
+	struct gendisk *gd;		/* gendisk structure */
+
+	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 */
-	struct gendisk	*gd;		/* gendisk structure */
-	ide_tuneproc_t	*tuneproc;	/* routine to tune PIO mode for drives */
-	ide_speedproc_t	*speedproc;	/* routine to retune DMA modes for drives */
-	ide_selectproc_t *selectproc;	/* tweaks hardware to select drive */
-	ide_resetproc_t	*resetproc;	/* routine to reset controller after a disk reset */
-	ide_intrproc_t	*intrproc;	/* special interrupt handling for shared pci interrupts */
-	ide_maskproc_t	*maskproc;	/* special host masking for drive selection */
-	ide_quirkproc_t	*quirkproc;	/* check host's drive quirk list */
-	ide_rw_proc_t	*rwproc;	/* adjust timing based upon rq->cmd direction */
-	ide_ideproc_t   *ideproc;       /* CPU-polled transfer routine */
-	ide_dmaproc_t	*dmaproc;	/* dma read/write/abort routine */
-	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.. */
+
+	struct pci_dev  *pci_dev;	/* for pci chipsets */
+	struct ide_pci_device_s	*cds;	/* chipset device struct */
+
+#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 (*OUTSW)(u32 port, void *addr, u32 count);
+	void (*OUTSL)(u32 port, void *addr, u32 count);
+
+	u8  (*INB)(u32 port);
+	u16 (*INW)(u32 port);
+	u32 (*INL)(u32 port);
+	void (*INSW)(u32 port, void *addr, u32 count);
+	void (*INSL)(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_highio  : 1; /* don't trust pci dma mask, 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 */
-	ide_busproc_t	*busproc;	/* driver soft-power interface */
-	byte		bus_state;	/* power state of the IDE bus */
 } ide_hwif_t;
 
 /*
@@ -572,7 +1009,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;
 
 /*
@@ -581,24 +1018,39 @@
 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 */
-	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 */
+		/* 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;
+
+		/* for pci chipsets */
+	struct pci_dev *pci_dev;
+		/* chipset device struct */
+	struct ide_pci_device_s *cds;
+
+		/* 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 */
@@ -651,14 +1103,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;
 
@@ -686,51 +1138,39 @@
  */
 #define IDE_SUBDRIVER_VERSION	1
 
-typedef int		(ide_cleanup_proc)(ide_drive_t *);
-typedef int		(ide_standby_proc)(ide_drive_t *);
-typedef int		(ide_flushcache_proc)(ide_drive_t *);
-typedef ide_startstop_t	(ide_do_request_proc)(ide_drive_t *, struct request *, unsigned long);
-typedef void		(ide_end_request_proc)(byte, ide_hwgroup_t *);
-typedef int		(ide_ioctl_proc)(ide_drive_t *, struct inode *, struct file *, unsigned int, unsigned long);
-typedef int		(ide_open_proc)(struct inode *, struct file *, ide_drive_t *);
-typedef void		(ide_release_proc)(struct inode *, struct file *, ide_drive_t *);
-typedef int		(ide_check_media_change_proc)(ide_drive_t *);
-typedef void		(ide_revalidate_proc)(ide_drive_t *);
-typedef void		(ide_pre_reset_proc)(ide_drive_t *);
-typedef unsigned long	(ide_capacity_proc)(ide_drive_t *);
-typedef ide_startstop_t	(ide_special_proc)(ide_drive_t *);
-typedef void		(ide_setting_proc)(ide_drive_t *);
-typedef int		(ide_reinit_proc)(ide_drive_t *);
-typedef void		(ata_prebuilder_proc)(ide_drive_t *);
-typedef void		(atapi_prebuilder_proc)(ide_drive_t *);
-
 typedef struct ide_driver_s {
 	const char			*name;
 	const char			*version;
-	byte				media;
+	u8				media;
 	unsigned busy			: 1;
 	unsigned supports_dma		: 1;
 	unsigned supports_dsc_overlap	: 1;
-	ide_cleanup_proc		*cleanup;
-	ide_standby_proc		*standby;
-	ide_flushcache_proc		*flushcache;
-	ide_do_request_proc		*do_request;
-	ide_end_request_proc		*end_request;
-	ide_ioctl_proc			*ioctl;
-	ide_open_proc			*open;
-	ide_release_proc		*release;
-	ide_check_media_change_proc	*media_change;
-	ide_revalidate_proc		*revalidate;
-	ide_pre_reset_proc		*pre_reset;
-	ide_capacity_proc		*capacity;
-	ide_special_proc		*special;
-	ide_proc_entry_t		*proc;
-	ide_reinit_proc			*reinit;
-	ata_prebuilder_proc		*ata_prebuilder;
-	atapi_prebuilder_proc		*atapi_prebuilder;
+	int		(*cleanup)(ide_drive_t *);
+	int		(*shutdown)(ide_drive_t *);
+	int		(*standby)(ide_drive_t *);
+	int		(*suspend)(ide_drive_t *);
+	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);
+	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 *);
+	int		(*media_change)(ide_drive_t *);
+	void		(*revalidate)(ide_drive_t *);
+	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		(*init)(void);
+	int		(*attach)(ide_drive_t *);
+	void		(*ata_prebuilder)(ide_drive_t *);
+	void		(*atapi_prebuilder)(ide_drive_t *);
 } ide_driver_t;
 
-#define DRIVER(drive)		((ide_driver_t *)((drive)->driver))
+#define DRIVER(drive)		((drive)->driver)
 
 /*
  * IDE modules.
@@ -748,6 +1188,53 @@
 	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;
+
+#if 0
+typedef enum {
+	IDE_MEDIA_FLOPPY	= ide_floppy,
+	IDE_MEDIA_TAPE		= ide_tape,
+	IDE_MEDIA_CDROM		= ide_cdrom,
+	IDE_MEDIA_OPTICAL	= ide_optical,
+	IDE_MEDIA_DISK		= ide_disk,
+	IDE_MEDIA_SCSI		= ide_scsi,
+} ide_media_type;
+
+struct ide_media {
+	ide_media_type type;
+	char name[4];
+	atomic_t refcount;	/* Maybe this should be a struct module*
+				   with MOD_INC instead */
+	struct list_head devices;
+};
+
+struct {
+	struct ide_media floppy;
+	struct ide_media tape;
+	struct ide_media cdrom;
+	struct ide_media optical;
+	struct ide_media disk;
+	struct ide_media scsi;
+} ide_medias;
+
+void __init init_media(void)
+{
+	memset(&ide_medias, 0, sizeof(ide_medias));
+
+	ide_medias.floppy.type	= IDE_MEDIA_FLOPPY;
+	ide_medias.tape.type	= IDE_MEDIA_TAPE;
+	ide_medias.cdrom.type	= IDE_MEDIA_CDROM;
+	ide_medias.optical.type	= IDE_MEDIA_OPTICAL;
+	ide_medias.disk.type	= IDE_MEDIA_DISK;
+	ide_medias.scsi.type	= IDE_MEDIA_SCSI;
+};
+#endif
+
 /*
  * ide_hwifs[] is the master data structure used to keep track
  * of just about everything in ide.c.  Whenever possible, routines
@@ -758,8 +1245,16 @@
  */
 #ifndef _IDE_C
 extern	ide_hwif_t	ide_hwifs[];		/* master data repository */
+extern	ide_module_t	*ide_chipsets;
 extern	ide_module_t	*ide_modules;
 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;
 
@@ -768,56 +1263,50 @@
  */
 #define IDE_DRIVER		/* Toggle some magic bits in blk.h */
 #define LOCAL_END_REQUEST	/* Don't generate end_request in blk.h */
+//#define DEVICE_NR(device)	(MINOR(device) >> PARTN_BITS)
 #include <linux/blk.h>
 
-void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup);
-
-/*
- * This is used for (nearly) all data transfers from/to the IDE interface
- * FIXME for 2.5, to a pointer pass verses memcpy........
- */
-void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
-void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount);
-
-/*
- * This is used for (nearly) all ATAPI data transfers from/to the IDE interface
- * FIXME for 2.5, to a pointer pass verses memcpy........
- */
-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);
-
-int drive_is_ready (ide_drive_t *drive);
+extern int ide_end_request(ide_drive_t *, int /* uptodate */);
 
 /*
  * 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 *, ide_handler_t *, unsigned int, ide_expiry_t *);
 
 /*
  * 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);
+extern u8 ide_dump_status(ide_drive_t *, const char *, u8);
 
 /*
  * 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);
+extern ide_startstop_t ide_error(ide_drive_t *, const char *, u8);
 
 /*
  * 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".
@@ -826,43 +1315,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);
-
-int ide_wait_noerr (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 *);
+
+extern void ide_revalidate_drive(ide_drive_t *);
 
 /*
  * 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.
  */
-ide_startstop_t restart_request (ide_drive_t *);
+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 *);
 
 /*
  * "action" parameter type for ide_do_drive_cmd() below.
@@ -875,21 +1365,6 @@
 } ide_action_t;
 
 /*
- * temporarily mapping a (possible) highmem bio
- */
-#define ide_rq_offset(rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
-
-extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags)
-{
-	return bh_kmap_irq(rq->bh, flags) + ide_rq_offset(rq);
-}
-
-extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags)
-{
-	bh_kunmap_irq(buffer, flags);
-}
-
-/*
  * This function issues a special IDE device request
  * onto the request queue.
  *
@@ -914,23 +1389,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;
@@ -940,71 +1427,147 @@
 	ide_pre_handler_t	*prehandler;
 	ide_handler_t		*handler;
 	ide_post_handler_t	*posthandler;
-	void			*special;	/* valid_t generally */
 	struct request		*rq;		/* copy of request */
-	unsigned long		block;		/* copy of block */
+	void			*special;	/* valid_t generally */
 } 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;
 	ide_handler_t		*handler;
-	void			*special;
 	struct request		*rq;		/* copy of request */
-	unsigned long		block;		/* copy of block */
+	void			*special;
 } pkt_task_t;
 
-/*
- * taskfile io for disks for now...
- */
-ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task);
+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);
+
+extern int drive_is_ready(ide_drive_t *);
+extern int wait_for_ready(ide_drive_t *, int /* timeout */);
 
 /*
- * Builds request from ide_ioctl
+ * taskfile io for disks for now...and builds request from ide_ioctl
  */
-void do_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler);
+extern ide_startstop_t do_rw_taskfile(ide_drive_t *, ide_task_t *);
+
+/* (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 *);
 
-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 task_mulout_intr (ide_drive_t *drive);
-void ide_init_drive_taskfile (struct request *rq);
+extern int ide_raw_taskfile(ide_drive_t *, ide_task_t *, u8 *);
 
-int ide_wait_taskfile (ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, byte *buf);
+extern ide_pre_handler_t * ide_pre_handler_parser(struct hd_drive_task_hdr *, struct hd_drive_hob_hdr *);
 
-int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *cmd, byte *buf);
+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_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);
 /* 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_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);
+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
@@ -1012,107 +1575,169 @@
  * 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);
-
-/*
- * ide_multwrite() transfers a block of up to mcount sectors of data
- * to a drive as part of a disk multwrite operation.
- */
-int ide_multwrite (ide_drive_t *drive, unsigned int mcount);
+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 *, unsigned long);
 
 /*
  * 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 *);
 
-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 ide_reinit_drive (ide_drive_t *drive);
+extern int ide_attach_drive(ide_drive_t *);
+
+extern int ideprobe_init(void);
+extern int idedisk_attach(ide_drive_t *);
+extern int idedisk_init(void);
+extern int ide_cdrom_attach(ide_drive_t *);
+extern int ide_cdrom_init(void);
+extern int idetape_attach(ide_drive_t *);
+extern int idetape_init(void);
+extern int idefloppy_attach(ide_drive_t *);
+extern int idefloppy_init(void);
+extern int idescsi_attach(ide_drive_t *);
+extern int idescsi_init(void);
+
+extern void ide_scan_pcibus(int scan_direction) __init;
+extern int ide_pci_register_driver(struct pci_driver *driver);
+extern void ide_pci_unregister_driver(struct pci_driver *driver);
+
+extern void default_hwif_iops(ide_hwif_t *);
+extern void default_hwif_mmiops(ide_hwif_t *);
+extern void default_hwif_transport(ide_hwif_t *);
+
+
+extern int ide_register_module(ide_module_t *module);
+extern void ide_unregister_module(ide_module_t *module);
+extern ide_drive_t *ide_scan_devices(u8, const char *, ide_driver_t *, int);
+extern int ide_register_subdriver(ide_drive_t *, ide_driver_t *, int /* ver */);
+extern int ide_unregister_subdriver(ide_drive_t *);
+extern int ide_replace_subdriver(ide_drive_t *, const char * /* driver*/);
+
+#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;
 
-#ifdef _IDE_C
-#ifdef CONFIG_BLK_DEV_IDE
-int ideprobe_init (void);
-#endif /* CONFIG_BLK_DEV_IDE */
-#ifdef CONFIG_BLK_DEV_IDEDISK
-int idedisk_reinit (ide_drive_t *drive);
-int idedisk_init (void);
-#endif /* CONFIG_BLK_DEV_IDEDISK */
-#ifdef CONFIG_BLK_DEV_IDECD
-int ide_cdrom_reinit (ide_drive_t *drive);
-int ide_cdrom_init (void);
-#endif /* CONFIG_BLK_DEV_IDECD */
-#ifdef CONFIG_BLK_DEV_IDETAPE
-int idetape_reinit (ide_drive_t *drive);
-int idetape_init (void);
-#endif /* CONFIG_BLK_DEV_IDETAPE */
-#ifdef CONFIG_BLK_DEV_IDEFLOPPY
-int idefloppy_reinit (ide_drive_t *drive);
-int idefloppy_init (void);
-#endif /* CONFIG_BLK_DEV_IDEFLOPPY */
-#ifdef CONFIG_BLK_DEV_IDESCSI
-int idescsi_reinit (ide_drive_t *drive);
-int idescsi_init (void);
-#endif /* CONFIG_BLK_DEV_IDESCSI */
-#endif /* _IDE_C */
-
-int ide_register_module (ide_module_t *module);
-void ide_unregister_module (ide_module_t *module);
-ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n);
-int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version);
-int ide_unregister_subdriver (ide_drive_t *drive);
-int ide_replace_subdriver(ide_drive_t *drive, const char *driver);
+void ide_pci_register_host_proc(ide_pci_host_proc_t *);
+#endif /* CONFIG_PROC_FS */
 
-#ifdef CONFIG_BLK_DEV_IDEPCI
 #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 */
 
-unsigned long ide_find_free_region (unsigned short size) __init;
-void ide_scan_pcibus (int scan_direction) __init;
-#endif
-#ifdef CONFIG_BLK_DEV_IDEDMA
+#define NODMA 0
+#define NOAUTODMA 1
+#define AUTODMA 2
+#define EOL 255
+
+typedef struct ide_pci_enablebit_s {
+	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 {
+	u16			vendor;
+	u16			device;
+	char			*name;
+	void			(*init_setup)(struct pci_dev *, struct ide_pci_device_s *);
+	unsigned int		(*init_chipset)(struct pci_dev *, const char *);
+	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];
+	u8			bootable;
+	unsigned int		extra;
+	struct ide_pci_device_s	*next;
+} ide_pci_device_t;
+
+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 *);
+
 #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
+extern int ide_build_dmatable(ide_drive_t *, struct request *, int);
+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 *);
+
+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 *);
+
+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;
+}
+
+/* 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);
 
-void hwif_unregister (ide_hwif_t *hwif);
+#define ide_lock		(io_request_lock)
+#define DRIVE_LOCK(drive)       ((drive)->queue.queue_lock)
 
-void export_ide_init_queue (ide_drive_t *drive);
-byte export_probe_for_drive (ide_drive_t *drive);
 
 #endif /* _IDE_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/intermezzo_fs.h linux.20pre10-ac2/include/linux/intermezzo_fs.h
--- linux.20pre10/include/linux/intermezzo_fs.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/linux/intermezzo_fs.h	2002-10-11 00:35:04.000000000 +0100
@@ -1,211 +1,358 @@
-/*
- *
- *  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.
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
  *
+ *  Copyright (C) 2001, 2002 Cluster File Systems, Inc.
+ *  Copyright (C) 2001 Tacitus Systems, Inc.
  *  Copyright (C) 2000 Stelias Computing, Inc.
  *  Copyright (C) 2000 Red Hat, Inc.
  *  Copyright (C) 2000 TurboLinux, Inc.
  *  Copyright (C) 2000 Los Alamos National Laboratory.
- *  Copyright (C) 2001 Tacitus Systems, Inc.
- *  Copyright (C) 2001 Cluster File Systems, Inc. 
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
 #ifndef __INTERMEZZO_FS_H_
 #define __INTERMEZZO_FS_H_ 1
 
+#include <linux/intermezzo_lib.h>
+#include <linux/intermezzo_idl.h>
+
+
 #ifdef __KERNEL__
-#include <linux/smp.h>
-#include <linux/fsfilter.h>
+typedef __u8 uuid_t[16];
+#else
+# include <uuid/uuid.h>
+#endif
+
+struct lento_vfs_context {
+        __u64 kml_offset;
+        __u64 updated_time;
+        __u64 remote_ino;
+        __u64 remote_generation;
+        __u32 slot_offset;
+        __u32 recno;
+        __u32 flags;
+        uuid_t uuid;
+        struct presto_version remote_version;
+};
+
+static inline int izo_ioctl_is_invalid(struct izo_ioctl_data *data);
+
+#ifdef __KERNEL__
+# include <linux/smp.h>
+# include <linux/fsfilter.h>
+# include <linux/slab.h>
+# include <linux/vmalloc.h>
+# include <linux/smp_lock.h>
 
 /* fixups for fs.h */
-#ifndef fs_down
-#define fs_down(sem) down(sem)
-#endif
+# ifndef fs_down
+#  define fs_down(sem) down(sem)
+# endif
+
+# ifndef fs_up
+#  define fs_up(sem) up(sem)
+# endif
+
+# define KML_IDLE                        0
+# define KML_DECODE                      1
+# define KML_OPTIMIZE                    2
+# define KML_REINT                       3
+
+# define KML_OPEN_REINT                  0x0100
+# define KML_REINT_BEGIN                 0x0200
+# define KML_BACKFETCH                   0x0400
+# define KML_REINT_END                   0x0800
+# define KML_CLOSE_REINT                 0x1000
+# define KML_REINT_MAXBUF                (64 * 1024)
 
-#ifndef fs_up
-#define fs_up(sem) up(sem)
-#endif
+# define CACHE_CLIENT_RO       0x4
+# define CACHE_LENTO_RO        0x8
 
-/* We will be more tolerant than the default ea patch with attr name sizes and
- * the size of value. If these come via VFS from the default ea patches, the
- * corresponding character strings will be truncated anyway. During journalling- * we journal length for both name and value. See journal_set_ext_attr.
- */
-#define PRESTO_EXT_ATTR_NAME_MAX 128
-#define PRESTO_EXT_ATTR_VALUE_MAX 8192
+/* global variables */
+extern int presto_debug;
+extern int presto_print_entry;
+extern long presto_kmemory;
+extern long presto_vmemory;
 
-#define KML_IDLE                        0
-#define KML_DECODE                      1
-#define KML_OPTIMIZE                    2
-#define KML_REINT                       3
-
-#define KML_OPEN_REINT                  0x0100
-#define KML_REINT_BEGIN                 0x0200
-#define KML_BACKFETCH                   0x0400
-#define KML_REINT_END                   0x0800
-#define KML_CLOSE_REINT                 0x1000
-#define FSET_GET_KMLDATA(fset)          fset->fset_kmldata
-#define KML_REINT_MAXBUF              	(64 * 1024)
-
-struct  kml_fsdata
-{
-        int                kml_state;
-
-        /* kml optimize support */
-        struct list_head   kml_kop_cache;
-
-        /* kml reint support */
-        int                kml_reint_state;
-        struct list_head   kml_reint_cache;
-        struct list_head  *kml_reint_current;
-        int                kml_maxsize;  /* max buffer */
-        int                kml_len;
-        char *             kml_buf;
-        loff_t             kml_reintpos;
-        int                kml_count;
-};
+# define PRESTO_DEBUG
+# ifdef PRESTO_DEBUG
+/* debugging masks */
+#  define D_SUPER       1
+#  define D_INODE       2
+#  define D_FILE        4
+#  define D_CACHE       8  /* cache debugging */
+#  define D_MALLOC     16  /* print malloc, de-alloc information */
+#  define D_JOURNAL    32
+#  define D_UPCALL     64  /* up and downcall debugging */
+#  define D_PSDEV     128
+#  define D_PIOCTL    256
+#  define D_SPECIAL   512
+#  define D_TIMING   1024
+#  define D_DOWNCALL 2048
+#  define D_KML      4096
+#  define D_FSDATA   8192
 
-/* super.c */
-struct presto_cache *presto_find_cache(kdev_t dev) ;
-extern struct file_system_type presto_fs_type;
-extern int init_intermezzo_fs(void);
+#  define CDEBUG(mask, format, a...)                                    \
+        do {                                                            \
+                if (presto_debug & mask) {                              \
+                        printk("(%s:%s,l. %d %d): " format, __FILE__,   \
+                               __FUNCTION__, __LINE__, current->pid     \
+                               , ## a);                                 \
+                }                                                       \
+        } while (0)
 
-#define CACHE_TYPE_LENGTH       16
+#define CERROR(format, a...)                                            \
+do {                                                                    \
+        printk("(%s:%s,l. %d %d): " format, __FILE__, __FUNCTION__,     \
+               __LINE__, current->pid , ## a);                          \
+} while (0)
 
-int presto_ispresto(struct inode *);
+#  define ENTRY                                                         \
+        if (presto_print_entry)                                         \
+                printk("Process %d entered %s\n", current->pid, __FUNCTION__)
+
+#  define EXIT                                                          \
+        if (presto_print_entry)                                         \
+                printk("Process %d leaving %s at %d\n", current->pid,   \
+                       __FUNCTION__, __LINE__)
+
+#  define presto_kmem_inc(ptr, size) presto_kmemory += (size)
+#  define presto_kmem_dec(ptr, size) presto_kmemory -= (size)
+#  define presto_vmem_inc(ptr, size) presto_vmemory += (size)
+#  define presto_vmem_dec(ptr, size) presto_vmemory -= (size)
+# else /* !PRESTO_DEBUG */
+#  define CDEBUG(mask, format, a...) do {} while (0)
+#  define ENTRY do {} while (0)
+#  define EXIT do {} while (0)
+#  define presto_kmem_inc(ptr, size) do {} while (0)
+#  define presto_kmem_dec(ptr, size) do {} while (0)
+#  define presto_vmem_inc(ptr, size) do {} while (0)
+#  define presto_vmem_dec(ptr, size) do {} while (0)
+# endif /* PRESTO_DEBUG */
+
+
+struct run_ctxt {
+        struct vfsmount *pwdmnt;
+        struct dentry   *pwd;
+        struct vfsmount *rootmnt;
+        struct dentry   *root;
+        uid_t            fsuid;
+        gid_t            fsgid;
+        mm_segment_t     fs;
+	int              ngroups;
+	gid_t	         groups[NGROUPS];
+
+};
 
-#define CACHE_CLIENT_RO       0x4
-#define CACHE_LENTO_RO        0x8
-#define CACHE_FSETROOT_SET     0x10
+static inline void push_ctxt(struct run_ctxt *save, struct run_ctxt *new)
+{
+        int i;
+        save->fs = get_fs();
+        save->pwd = dget(current->fs->pwd);
+        save->pwdmnt = mntget(current->fs->pwdmnt);
+        save->fsgid = current->fsgid;
+        save->fsuid = current->fsuid;
+        save->root = current->fs->root;
+        save->rootmnt = current->fs->rootmnt;
+        save->ngroups = current->ngroups;
+        for (i = 0; i< current->ngroups; i++) 
+                save->groups[i] = current->groups[i];
+
+        set_fs(new->fs);
+        lock_kernel();
+        set_fs_pwd(current->fs, new->pwdmnt, new->pwd);
+        if (new->root)
+                set_fs_root(current->fs, new->rootmnt, new->root);
+        unlock_kernel();
+        current->fsuid = new->fsuid;
+        current->fsgid = new->fsgid;
+        if (new->ngroups > 0) {
+                current->ngroups = new->ngroups;
+                for (i = 0; i< new->ngroups; i++) 
+                        current->groups[i] = new->groups[i];
+        }
+        
+}
+
+static inline void pop_ctxt(struct run_ctxt *saved)
+{
+        int i;
 
+        set_fs(saved->fs);
+        lock_kernel();
+        set_fs_pwd(current->fs, saved->pwdmnt, saved->pwd);
+        if (saved->root)
+                set_fs_root(current->fs, saved->rootmnt, saved->root);
+        unlock_kernel();
+        current->fsuid = saved->fsuid;
+        current->fsgid = saved->fsgid;
+        current->ngroups = saved->ngroups;
+        for (i = 0; i< saved->ngroups; i++) 
+                current->groups[i] = saved->groups[i];
+
+        mntput(saved->pwdmnt);
+        dput(saved->pwd);
+}
+
+static inline struct presto_dentry_data *presto_d2d(struct dentry *dentry)
+{
+        return (struct presto_dentry_data *)(dentry->d_fsdata);
+}
 
 struct presto_cache {
-        spinlock_t         cache_lock; 
-	loff_t             cache_reserved;
-        struct list_head cache_chain; /* for the dev/cache hash */
+        spinlock_t          cache_lock;
+        loff_t              cache_reserved;
+        struct  vfsmount   *cache_vfsmount;
+        struct super_block *cache_sb;
+        struct  dentry     *cache_root;
+        struct list_head    cache_chain; /* for the dev/cache hash */
 
         int   cache_flags;
-        char *cache_root_fileset;  /* fileset mounted on cache "/"  */
 
         kdev_t cache_dev;            /* underlying block device */
-	struct super_block *cache_sb;
-        struct dentry *cache_mtde;  /* unix mtpt of cache XXX NOT VALID XXX */
-        char *cache_mtpt;           /*  again */
 
         char *cache_type;            /* filesystem type of cache */
         struct filter_fs *cache_filter;
 
-        struct upc_comm *cache_psdev;  /* points to /dev/intermezzo? we use */
-        struct list_head cache_psdev_chain; 
-
+        struct upc_channel *cache_psdev;  /* points to channel used */
+        struct list_head cache_channel_list; 
         struct list_head cache_fset_list; /* filesets mounted in cache */
 };
 
-
-
-
-/* file sets */
-#define CHUNK_BITS  16
-
 struct presto_log_fd {
-        rwlock_t         fd_lock; 
-        loff_t           fd_offset;  /* offset where next record should go */ 
+        rwlock_t         fd_lock;
+        loff_t           fd_offset;  /* offset where next record should go */
         struct file    *fd_file;
         int             fd_truncating;
-        unsigned int   fd_recno;   /* last recno written */ 
+        unsigned int   fd_recno;   /* last recno written */
         struct list_head  fd_reservations;
 };
 
+/* file sets */
+# define CHUNK_BITS  16
+
 struct presto_file_set {
         struct list_head fset_list;
         struct presto_log_fd fset_kml;
         struct presto_log_fd fset_lml;
-        struct file *fset_last_rcvd;
-        struct dentry *fset_mtpt;
-        struct nameidata fset_nd; 
+        struct presto_log_fd fset_rcvd;
+        struct list_head *fset_clients;  /* cache of clients */
+        struct dentry *fset_dentry;
+        struct vfsmount *fset_mnt;
         struct presto_cache *fset_cache;
 
         unsigned int fset_lento_recno;  /* last recno mentioned to lento */
         loff_t fset_lento_off;    /* last offset mentioned to lento */
+        loff_t fset_kml_logical_off; /* logical offset of kml file byte 0 */
         char * fset_name;
 
         int fset_flags;
+        int fset_chunkbits;
+        char *fset_reint_buf; /* temporary buffer holds kml during reint */
+
+        spinlock_t fset_permit_lock;
         int fset_permit_count;
-        int fset_permit_cookie;
-        int fset_chunkbits; 
-        int fset_data; /* replaces the dentry d_data field for fsetroots */
-	struct  kml_fsdata *fset_kmldata;
-	loff_t  fset_file_maxio;  /* writing more than this causes a close */ 
+        int fset_permit_upcall_count;
+        /* This queue is used both for processes waiting for the kernel to give
+         * up the permit as well as processes waiting for the kernel to be given
+         * the permit, depending on the state of FSET_HASPERMIT. */
+        wait_queue_head_t fset_permit_queue;
+
+        loff_t  fset_file_maxio;  /* writing more than this causes a close */
+        unsigned long int kml_truncate_size;
 };
 
 /* This is the default number of bytes written before a close is recorded*/
 #define FSET_DEFAULT_MAX_FILEIO (1024<<10)
 
+struct dentry *presto_tmpfs_ilookup(struct inode *dir, struct dentry *dentry, 
+                                    ino_t ino, unsigned int generation);
+struct dentry *presto_iget_ilookup(struct inode *dir, struct dentry *dentry, 
+                                    ino_t ino, unsigned int generation);
+struct dentry *presto_add_ilookup_dentry(struct dentry *parent,
+                                         struct dentry *real);
+
 struct journal_ops {
+        int (*tr_all_data)(struct inode *);
         loff_t (*tr_avail)(struct presto_cache *fset, struct super_block *);
         void *(*tr_start)(struct presto_file_set *, struct inode *, int op);
         void (*tr_commit)(struct presto_file_set *, void *handle);
         void (*tr_journal_data)(struct inode *);
+        struct dentry *(*tr_ilookup)(struct inode *dir, struct dentry *dentry, ino_t ino, unsigned int generation);
+        struct dentry *(*tr_add_ilookup)(struct dentry *parent, struct dentry *real);
 };
 
-
 extern struct journal_ops presto_ext2_journal_ops;
 extern struct journal_ops presto_ext3_journal_ops;
+extern struct journal_ops presto_tmpfs_journal_ops;
 extern struct journal_ops presto_xfs_journal_ops;
 extern struct journal_ops presto_reiserfs_journal_ops;
 extern struct journal_ops presto_obdfs_journal_ops;
-struct lento_vfs_context {
-        __u32 slot_offset;
-        __u32 recno;
-        __u64 kml_offset;
-        __u32 flags;
-        __u32 updated_time;
-};
-
 
-#define LENTO_FL_KML            0x0001
-#define LENTO_FL_EXPECT         0x0002
-#define LENTO_FL_VFSCHECK       0x0004
-#define LENTO_FL_JUSTLOG        0x0008
-#define LENTO_FL_WRITE_KML      0x0010
-#define LENTO_FL_CANCEL_LML     0x0020
-#define LENTO_FL_WRITE_EXPECT   0x0040
-#define LENTO_FL_IGNORE_TIME    0x0080
+# define LENTO_FL_KML            0x0001
+# define LENTO_FL_EXPECT         0x0002
+# define LENTO_FL_VFSCHECK       0x0004
+# define LENTO_FL_JUSTLOG        0x0008
+# define LENTO_FL_WRITE_KML      0x0010
+# define LENTO_FL_CANCEL_LML     0x0020
+# define LENTO_FL_WRITE_EXPECT   0x0040
+# define LENTO_FL_IGNORE_TIME    0x0080
+# define LENTO_FL_TOUCH_PARENT   0x0100
+# define LENTO_FL_TOUCH_NEWOBJ   0x0200
+# define LENTO_FL_SET_DDFILEID   0x0400
 
-struct presto_cache *presto_get_cache(struct inode *inode) ;
+struct presto_cache *presto_get_cache(struct inode *inode);
 int presto_sprint_mounts(char *buf, int buflen, int minor);
 struct presto_file_set *presto_fset(struct dentry *de);
 int presto_journal(struct dentry *dentry, char *buf, size_t size);
 int presto_fwrite(struct file *file, const char *str, int len, loff_t *off);
+int presto_ispresto(struct inode *);
+
+/* super.c */
+extern struct file_system_type presto_fs_type;
+extern int init_intermezzo_fs(void);
+
+/* fileset.c */
+extern int izo_prepare_fileset(struct dentry *root, char *fsetname);
+char * izo_make_path(struct presto_file_set *fset, char *name);
+struct file *izo_fset_open(struct presto_file_set *fset, char *name, int flags, int mode);
 
 /* psdev.c */
+int izo_psdev_get_free_channel(void);
 int presto_psdev_init(void);
+int izo_psdev_setpid(int minor);
 extern void presto_psdev_cleanup(void);
 inline int presto_lento_up(int minor);
+int izo_psdev_setchannel(struct file *file, int fd);
 
 /* inode.c */
 extern struct super_operations presto_super_ops;
-extern int presto_excluded_gid; 
-#define PRESTO_EXCL_GID 4711
 void presto_set_ops(struct inode *inode, struct  filter_fs *filter);
-void presto_read_inode(struct inode *inode);
-void presto_put_super(struct super_block *);
-
-/* journal.c */
-void presto_trans_commit(struct presto_file_set *fset, void *handle);
-void *presto_trans_start(struct presto_file_set *fset, struct inode *inode,
-                           int op);
 
 /* dcache.c */
-void presto_frob_dop(struct dentry *de) ;
-char * presto_path(struct dentry *dentry, struct dentry *root,
-                   char *buffer, int buflen);
+void presto_frob_dop(struct dentry *de);
+char *presto_path(struct dentry *dentry, struct dentry *root,
+                  char *buffer, int buflen);
+inline struct presto_dentry_data *izo_alloc_ddata(void);
+int presto_set_dd(struct dentry *);
+int presto_init_ddata_cache(void);
+void presto_cleanup_ddata_cache(void);
 extern struct dentry_operations presto_dentry_ops;
 
-
-
 /* dir.c */
 extern struct inode_operations presto_dir_iops;
 extern struct inode_operations presto_file_iops;
@@ -214,97 +361,103 @@
 extern struct file_operations presto_file_fops;
 extern struct file_operations presto_sym_fops;
 int presto_setattr(struct dentry *de, struct iattr *iattr);
-extern int presto_ilookup_uid; 
-#define PRESTO_ILOOKUP_MAGIC "...ino:"
-#define PRESTO_ILOOKUP_SEP ':'
-
+int presto_settime(struct presto_file_set *fset, struct dentry *newobj,
+                   struct dentry *parent, struct dentry *target,
+                   struct lento_vfs_context *ctx, int valid);
+int presto_ioctl(struct inode *inode, struct file *file,
+                 unsigned int cmd, unsigned long arg);
+
+extern int presto_ilookup_uid;
+# define PRESTO_ILOOKUP_MAGIC "...ino:"
+# define PRESTO_ILOOKUP_SEP ':'
+int izo_dentry_is_ilookup(struct dentry *, ino_t *id, unsigned int *generation);
 struct dentry *presto_lookup(struct inode * dir, struct dentry *dentry);
 
-/* file.c */
-struct presto_reservation_data {
-        unsigned int ri_recno; 
-        loff_t ri_offset;
-        loff_t ri_size;
-        struct list_head ri_list;
+struct presto_dentry_data {
+        int dd_count; /* how mnay dentries are using this dentry */
+        struct presto_file_set *dd_fset;
+        struct dentry *dd_inodentry; 
+        loff_t dd_kml_offset;
+        int dd_flags;
+        __u64 remote_ino;
+        __u64 remote_generation;
 };
 
-
-struct presto_file_data { 
+struct presto_file_data {
         int fd_do_lml;
         loff_t fd_lml_offset;
-        uid_t fd_fsuid;
-        gid_t fd_fsgid;
+        size_t fd_bytes_written;
+        /* authorization related data of file at open time */
         uid_t fd_uid;
         gid_t fd_gid;
         mode_t fd_mode;
+        /* identification data of calling process */
+        uid_t fd_fsuid;
+        gid_t fd_fsgid;
         int fd_ngroups;
-        size_t fd_bytes_written; /* Number of bytes written so far on this fd*/
         gid_t fd_groups[NGROUPS_MAX];
+        /* information how to complete the close operation */
+        struct lento_vfs_context fd_info;
+        struct presto_version fd_version;
 };
 
-
 /* presto.c and Lento::Downcall */
-struct presto_version {
-        __u64 pv_mtime;
-        __u64 pv_ctime;
-        __u64 pv_size;
-};
+
 int presto_walk(const char *name, struct nameidata *nd);
-int presto_clear_fsetroot(char *path);
-int presto_clear_all_fsetroots(char *path);
-int  presto_get_kmlsize(char *path, size_t *size);
-int  presto_get_lastrecno(char *path, off_t *size);
-int presto_set_fsetroot(char *path, char *fsetname, unsigned int fsetid,
+int izo_clear_fsetroot(struct dentry *dentry);
+int izo_clear_all_fsetroots(struct presto_cache *cache);
+int presto_get_kmlsize(char *path, __u64 *size);
+int presto_get_lastrecno(char *path, off_t *size);
+int presto_set_fsetroot(struct dentry *dentry, char *fsetname,
                        unsigned int flags);
-int presto_has_all_data(struct inode *inode);
+int presto_set_fsetroot_from_ioc(struct dentry *dentry, char *fsetname,
+                                 unsigned int flags);
 inline int presto_is_read_only(struct presto_file_set *);
 int presto_truncate_lml(struct presto_file_set *fset);
 int lento_write_lml(char *path,
-                     __u64 remote_ino, 
+                     __u64 remote_ino,
                      __u32 remote_generation,
                      __u32 remote_version,
                     struct presto_version *remote_file_version);
-int lento_reset_fset(char *path, __u64 offset, __u32 recno);
 int lento_complete_closes(char *path);
-int lento_cancel_lml(char *path,
-                     __u64 lml_offset, 
-                     __u64 remote_ino, 
-                     __u32 remote_generation,
-                     __u32 remote_version, 
-                     struct lento_vfs_context *info);
 inline int presto_f2m(struct presto_file_set *fset);
-
+int presto_prep(struct dentry *, struct presto_cache **,
+                       struct presto_file_set **);
 /* cache.c */
+extern struct presto_cache *presto_cache_init(void);
+extern inline void presto_cache_add(struct presto_cache *cache, kdev_t dev);
+extern inline void presto_cache_init_hash(void);
+
+struct presto_cache *presto_cache_find(kdev_t dev);
+
 #define PRESTO_REQLOW  (3 * 4096)
 #define PRESTO_REQHIGH (6 * 4096)
 void presto_release_space(struct presto_cache *cache, loff_t req);
 int presto_reserve_space(struct presto_cache *cache, loff_t req);
 
-/* NOTE: PRESTO_FSETROOT MUST be 0x1:
-   - if this bit is set dentry->d_fsdata points to a file_set
-   - the address of the file_set if d_fsdata - 1
-*/
-
-#define PRESTO_FSETROOT         0x00000001 /* dentry is fileset root */
 #define PRESTO_DATA             0x00000002 /* cached data is valid */
 #define PRESTO_ATTR             0x00000004 /* attributes cached */
-
-#define EISFSETROOT             0x2001
-
+#define PRESTO_DONT_JOURNAL     0x00000008 /* things like .intermezzo/ */
 
 struct presto_file_set *presto_path2fileset(const char *name);
-int presto_permit_downcall(const char *path, int *cookie);
+int izo_revoke_permit(struct dentry *, uuid_t uuid);
 int presto_chk(struct dentry *dentry, int flag);
 void presto_set(struct dentry *dentry, int flag);
 int presto_get_permit(struct inode *inode);
 int presto_put_permit(struct inode *inode);
-int presto_mark_dentry(const char *path, int and, int or, int *res);
-int presto_mark_cache(const char *path, int and_bits, int or_bits, int *);
-int presto_mark_fset(const char *path, int and_bits, int or_bits, int *);
+int presto_set_max_kml_size(const char *path, unsigned long max_size);
+int izo_mark_dentry(struct dentry *dentry, int and, int or, int *res);
+int izo_mark_cache(struct dentry *dentry, int and_bits, int or_bits, int *);
+int izo_mark_fset(struct dentry *dentry, int and_bits, int or_bits, int *);
 void presto_getversion(struct presto_version *pv, struct inode *inode);
 int presto_i2m(struct inode *inode);
 int presto_c2m(struct presto_cache *cache);
 
+
+/* file.c */
+int izo_purge_file(struct presto_file_set *fset, char *file);
+int presto_adjust_lml(struct file *file, struct lento_vfs_context *info);
+
 /* journal.c */
 struct rec_info {
         loff_t offset;
@@ -312,21 +465,47 @@
         int recno;
         int is_kml;
 };
+
 void presto_trans_commit(struct presto_file_set *fset, void *handle);
 void *presto_trans_start(struct presto_file_set *fset, struct inode *inode,
-                           int op);
-int presto_clear_lml_close(struct presto_file_set *fset, 
+                         int op);
+int presto_fread(struct file *file, char *str, int len, loff_t *off);
+int presto_clear_lml_close(struct presto_file_set *fset,
                            loff_t  lml_offset);
-int presto_write_lml_close(struct rec_info *rec,
-                           struct presto_file_set *fset, 
-                           struct file *file,
-                           __u64 remote_ino,
-                           __u32 remote_generation,
-                           __u32 remote_version,
-                           struct presto_version *new_file_ver);
-int presto_complete_lml(struct presto_file_set *fset); 
+int presto_complete_lml(struct presto_file_set *fset);
+int presto_read_kml_logical_offset(struct rec_info *recinfo,
+                                   struct presto_file_set *fset);
+int presto_write_kml_logical_offset(struct presto_file_set *fset);
+struct file *presto_copy_kml_tail(struct presto_file_set *fset,
+                                  unsigned long int start);
+int presto_finish_kml_truncate(struct presto_file_set *fset,
+                               unsigned long int offset);
+int izo_lookup_file(struct presto_file_set *fset, char *path,
+                    struct nameidata *nd);
+int izo_do_truncate(struct presto_file_set *fset, struct dentry *dentry,
+                    loff_t length,  loff_t size_check);
+int izo_log_close(struct presto_log_fd *logfd);
+struct file *izo_log_open(struct presto_file_set *fset, char *name, int flags);
+int izo_init_kml_file(struct presto_file_set *, struct presto_log_fd *);
+int izo_init_lml_file(struct presto_file_set *, struct presto_log_fd *);
+int izo_init_last_rcvd_file(struct presto_file_set *, struct presto_log_fd *);
 
 /* vfs.c */
+
+/* Extra data needed in the KML for rollback operations; this structure is
+ * passed around during the KML-writing process. */
+struct izo_rollback_data {
+        __u32 rb_mode;
+        __u32 rb_rdev;
+        __u64 rb_uid;
+        __u64 rb_gid;
+};
+
+int presto_write_last_rcvd(struct rec_info *recinfo,
+                           struct presto_file_set *fset,
+                           struct lento_vfs_context *info);
+void izo_get_rollback_data(struct inode *inode, struct izo_rollback_data *rb);
+int presto_do_close(struct presto_file_set *fset, struct file *file);
 int presto_do_setattr(struct presto_file_set *fset, struct dentry *dentry,
                       struct iattr *iattr, struct lento_vfs_context *info);
 int presto_do_create(struct presto_file_set *fset, struct dentry *dir,
@@ -348,9 +527,11 @@
 int presto_do_mknod(struct presto_file_set *fset, struct dentry *dir,
                     struct dentry *dentry, int mode, dev_t dev,
                     struct lento_vfs_context *info);
-int presto_do_rename(struct presto_file_set *fset, struct dentry *old_dir,
-                     struct dentry *old_dentry, struct dentry *new_dir,
-                     struct dentry *new_dentry, struct lento_vfs_context *info);
+int do_rename(struct presto_file_set *fset, struct dentry *old_dir,
+              struct dentry *old_dentry, struct dentry *new_dir,
+              struct dentry *new_dentry, struct lento_vfs_context *info);
+int presto_do_statfs (struct presto_file_set *fset,
+                      struct statfs * buf);
 
 int lento_setattr(const char *name, struct iattr *iattr,
                   struct lento_vfs_context *info);
@@ -367,8 +548,6 @@
 int lento_rename(const char *oldname, const char *newname,
                  struct lento_vfs_context *info);
 int lento_iopen(const char *name, ino_t ino, unsigned int generation,int flags);
-int lento_close(unsigned int fd, struct lento_vfs_context *info);
-
 
 /* journal.c */
 
@@ -376,12 +555,16 @@
 
 __inline__ int presto_no_journal(struct presto_file_set *fset);
 int journal_fetch(int minor);
-int presto_journal_write(struct rec_info *rec, struct presto_file_set *fset,
-                         struct file *file);
+int presto_log(struct presto_file_set *fset, struct rec_info *rec,
+               const char *buf, size_t size,
+               const char *string1, int len1, 
+               const char *string2, int len2,
+               const char *string3, int len3);
+int presto_get_fileid(int minor, struct presto_file_set *fset,
+                      struct dentry *dentry);
 int presto_journal_setattr(struct rec_info *rec, struct presto_file_set *fset,
-                           struct dentry *dentry,
-                           struct presto_version *old_ver,
-                           struct iattr *iattr);
+                           struct dentry *dentry, struct presto_version *old_ver,
+                           struct izo_rollback_data *, struct iattr *iattr);
 int presto_journal_create(struct rec_info *rec, struct presto_file_set *fset,
                           struct dentry *dentry,
                           struct presto_version *tgt_dir_ver,
@@ -391,10 +574,11 @@
                         struct presto_version *tgt_dir_ver,
                         struct presto_version *new_link_ver);
 int presto_journal_unlink(struct rec_info *rec, struct presto_file_set *fset,
-                          struct dentry *dentry,
+                          struct dentry *dir,
                           struct presto_version *tgt_dir_ver,
-                          struct presto_version *old_file_ver, int len,
-                          const char *name);
+                          struct presto_version *old_file_ver,
+                          struct izo_rollback_data *, struct dentry *dentry,
+                          char *old_target, int old_targetlen);
 int presto_journal_symlink(struct rec_info *rec, struct presto_file_set *fset,
                            struct dentry *dentry, const char *target,
                            struct presto_version *tgt_dir_ver,
@@ -406,8 +590,8 @@
 int presto_journal_rmdir(struct rec_info *rec, struct presto_file_set *fset,
                          struct dentry *dentry,
                          struct presto_version *tgt_dir_ver,
-                         struct presto_version *old_dir_ver, int len,
-                         const char *name);
+                         struct presto_version *old_dir_ver,
+                         struct izo_rollback_data *, int len, const char *name);
 int presto_journal_mknod(struct rec_info *rec, struct presto_file_set *fset,
                          struct dentry *dentry,
                          struct presto_version *tgt_dir_ver,
@@ -417,302 +601,324 @@
                           struct dentry *src, struct dentry *tgt,
                           struct presto_version *src_dir_ver,
                           struct presto_version *tgt_dir_ver);
-int presto_journal_open(struct rec_info *rec, struct presto_file_set *fset,
-                        struct dentry *dentry, struct presto_version *old_ver);
-int presto_journal_close(struct rec_info *rec, struct presto_file_set *fset,
-                         struct file *file, 
-			 struct dentry *dentry, 
-			 struct presto_version *new_ver);
-int presto_close_journal_file(struct presto_file_set *fset);
+int presto_journal_open(struct rec_info *, struct presto_file_set *,
+                        struct dentry *, struct presto_version *old_ver);
+int presto_journal_close(struct rec_info *rec, struct presto_file_set *,
+                         struct file *, struct dentry *,
+                         struct presto_version *old_file_ver,
+                         struct presto_version *new_file_ver);
+int presto_write_lml_close(struct rec_info *rec,
+                           struct presto_file_set *fset, 
+                           struct file *file,
+                           __u64 remote_ino,
+                           __u64 remote_generation,
+                           struct presto_version *remote_version,
+                           struct presto_version *new_file_ver);
 void presto_log_op(void *data, int len);
-int presto_write_last_rcvd(struct rec_info *recinfo,
-                           struct presto_file_set *fset,
-                           struct lento_vfs_context *info);
-
-/* journal_ext3.c */
-struct ext3_journal_data {
-        struct file *jd_file;
-};
-extern struct ext3_journal_data e3jd;
-
-
+loff_t presto_kml_offset(struct presto_file_set *fset);
 
+/* upcall.c */
+#define SYNCHRONOUS 0
+#define ASYNCHRONOUS 1
+/* asynchronous calls */
+int izo_upc_kml(int minor, __u64 offset, __u32 first_recno, __u64 length,
+                __u32 last_recno, char *fsetname);
+int izo_upc_kml_truncate(int minor, __u64 length, __u32 last_recno,
+                         char *fsetname);
+int izo_upc_go_fetch_kml(int minor, char *fsetname, uuid_t uuid, __u64 kmlsize);
+int izo_upc_backfetch(int minor, char *path, char *fileset, 
+                      struct lento_vfs_context *);
+
+/* synchronous calls */
+int izo_upc_get_fileid(int minor, __u32 reclen, char *rec, 
+                       __u32 pathlen, char *path, char *fsetname);
+int izo_upc_permit(int minor, struct dentry *, __u32 pathlen, char *path,
+                   char *fset);
+int izo_upc_open(int minor, __u32 pathlen, char *path, char *fsetname, 
+                 struct lento_vfs_context *info);
+int izo_upc_connect(int minor, __u64 ip_address, __u64 port, __u8 uuid[16],
+                    int client_flag);
+int izo_upc_revoke_permit(int minor, char *fsetname, uuid_t uuid);
+int izo_upc_set_kmlsize(int minor, char *fsetname, uuid_t uuid, __u64 kmlsize);
+int izo_upc_client_make_branch(int minor, char *fsetname);
+int izo_upc_server_make_branch(int minor, char *fsetname);
+int izo_upc_branch_undo(int minor, char *fsetname, char *branchname);
+int izo_upc_branch_redo(int minor, char *fsetname, char *branchname);
+int izo_upc_repstatus(int minor,  char * fsetname, struct izo_rcvd_rec *lr_server);
+
+/* general mechanism */
+int izo_upc_upcall(int minor, int *size, struct izo_upcall_hdr *, int async);
+
+/* replicator.c */
+int izo_repstatus(struct presto_file_set *fset, __u64 client_kmlsize, 
+                  struct izo_rcvd_rec *lr_client, struct izo_rcvd_rec *lr_server);
+int izo_rep_cache_init(struct presto_file_set *);
+loff_t izo_rcvd_get(struct izo_rcvd_rec *, struct presto_file_set *, char *uuid);
+loff_t izo_rcvd_write(struct presto_file_set *, struct izo_rcvd_rec *);
+loff_t izo_rcvd_upd_remote(struct presto_file_set *fset, char * uuid,  __u64 remote_recno,
+                           __u64 remote_offset);
 
 /* sysctl.c */
 int init_intermezzo_sysctl(void);
 void cleanup_intermezzo_sysctl(void);
 
 /* ext_attr.c */
-#ifdef CONFIG_FS_EXT_ATTR
-/* XXX: Borrowed from vfs.c. Once the ea patch is into CVS 
- * move this prototype -SHP
- */
-int presto_do_set_ext_attr(struct presto_file_set *fset,
-                           struct dentry *dentry,
-                           const char *name, void *buffer,
-                           size_t buffer_len, int flags, mode_t *mode,
-                           struct lento_vfs_context *info);
-int presto_set_ext_attr(struct inode *inode,
-                        const char *name, void *buffer,
-                        size_t buffer_len, int flags);
-int lento_set_ext_attr(const char *path, const char *name,
-                       void *buffer, size_t buffer_len, int flags,
-                       mode_t mode, struct lento_vfs_context *info);
-/* XXX: Borrowed from journal.c. Once the ea patch is into CVS 
- * move this prototype -SHP
+/* We will be more tolerant than the default ea patch with attr name sizes and
+ * the size of value. If these come via VFS from the default ea patches, the
+ * corresponding character strings will be truncated anyway. During journalling- * we journal length for both name and value. See journal_set_ext_attr.
  */
-int presto_journal_set_ext_attr (struct rec_info *rec,
-                                 struct presto_file_set *fset,
-                                 struct dentry *dentry,
-                                 struct presto_version *ver, const char *name,
-                                 const char *buffer, int buffer_len,
-                                 int flags);
-#endif
-
-
-/* global variables */
-extern int presto_debug;
-extern int presto_print_entry;
-
-#define PRESTO_DEBUG
-#ifdef PRESTO_DEBUG
-/* debugging masks */
-#define D_SUPER     1   /* print results returned by Venus */
-#define D_INODE     2   /* print entry and exit into procedure */
-#define D_FILE      4
-#define D_CACHE     8   /* cache debugging */
-#define D_MALLOC    16  /* print malloc, de-alloc information */
-#define D_JOURNAL   32
-#define D_UPCALL    64  /* up and downcall debugging */
-#define D_PSDEV    128
-#define D_PIOCTL   256
-#define D_SPECIAL  512
-#define D_TIMING  1024
-#define D_DOWNCALL 2048
-#define D_KML      4096
-
-#define CDEBUG(mask, format, a...)                                      \
-        do {                                                            \
-                if (presto_debug & mask) {                              \
-                        printk("(%s:%s,l. %d %d): ", __FILE__, __FUNCTION__, __LINE__, current->pid);   \
-                        printk(format, ##a); }                          \
-        } while (0)
-
-#define ENTRY                                                           \
-        if(presto_print_entry)                                          \
-                printk("Process %d entered %s\n", current->pid, __FUNCTION__)
-
-#define EXIT                                                            \
-        if(presto_print_entry)                                          \
-                printk("Process %d leaving %s at %d\n", current->pid,   \
-                       __FUNCTION__,__LINE__)
-
-extern long presto_kmemory;
-extern long presto_vmemory;
-
-#define presto_kmem_inc(ptr, size) presto_kmemory += (size)
-#define presto_kmem_dec(ptr, size) presto_kmemory -= (size)
-#define presto_vmem_inc(ptr, size) presto_vmemory += (size)
-#define presto_vmem_dec(ptr, size) presto_vmemory -= (size)
-#else /* !PRESTO_DEBUG */
-#define CDEBUG(mask, format, a...) do {} while (0)
-#define ENTRY do {} while (0)
-#define EXIT do {} while (0)
-#define presto_kmem_inc(ptr, size) do {} while (0)
-#define presto_kmem_dec(ptr, size) do {} while (0)
-#define presto_vmem_inc(ptr, size) do {} while (0)
-#define presto_vmem_dec(ptr, size) do {} while (0)
-#endif /* PRESTO_DEBUG */
-
+#define PRESTO_EXT_ATTR_NAME_MAX 128
+#define PRESTO_EXT_ATTR_VALUE_MAX 8192
 
-#define PRESTO_ALLOC(ptr, cast, size)                                   \
+#define PRESTO_ALLOC(ptr, size)                                         \
 do {                                                                    \
-    if (size <= 4096) {                                                 \
-        ptr = (cast)kmalloc((unsigned long) size, GFP_KERNEL);          \
-        CDEBUG(D_MALLOC, "kmalloced: %ld at %p.\n", (long)size, ptr);   \
-        presto_kmem_inc(ptr, size);                                     \
-    } else {                                                            \
-        ptr = (cast)vmalloc((unsigned long) size);                      \
-        CDEBUG(D_MALLOC, "vmalloced: %ld at %p.\n", (long)size, ptr);   \
-        presto_vmem_inc(ptr, size);                                     \
-    }                                                                   \
-    if ((ptr) == 0)                                                     \
-        printk("PRESTO: out of memory at %s:%d\n", __FILE__, __LINE__); \
-    else                                                                \
-        memset( ptr, 0, size );                                         \
+        long s = (size);                                                \
+        (ptr) = kmalloc(s, GFP_KERNEL);                                 \
+        if ((ptr) == NULL)                                              \
+                CERROR("IZO: out of memory at %s:%d (trying to "        \
+                       "allocate %ld)\n", __FILE__, __LINE__, s);       \
+        else {                                                          \
+                presto_kmem_inc((ptr), s);                              \
+                memset((ptr), 0, s);                                    \
+        }                                                               \
+        CDEBUG(D_MALLOC, "kmalloced: %ld at %p (tot %ld).\n",           \
+               s, (ptr), presto_kmemory);                               \
 } while (0)
 
-
-
-#define PRESTO_FREE(ptr,size)                                           \
+#define PRESTO_FREE(ptr, size)                                          \
 do {                                                                    \
-    if (!ptr) {                                                         \
-        printk("PRESTO: free NULL pointer (%ld bytes) at %s:%d\n",      \
-               (long)size, __FILE__, __LINE__);                         \
-        break;                                                          \
-    }                                                                   \
-    if (size <= 4096) {                                                 \
-        CDEBUG(D_MALLOC, "kfreed: %ld at %p.\n", (long)size, ptr);      \
-        presto_kmem_dec(ptr, size);                                     \
-        kfree((ptr));                                         \
-    } else {                                                            \
-        CDEBUG(D_MALLOC, "vfreed: %ld at %p.\n", (long)size, ptr);      \
-        presto_vmem_dec(ptr, size);                                     \
-        vfree((ptr));                                                   \
-    }                                                                   \
+        long s = (size);                                                \
+        if ((ptr) == NULL) {                                            \
+                CERROR("IZO: free NULL pointer (%ld bytes) at "         \
+                       "%s:%d\n", s, __FILE__, __LINE__);               \
+                break;                                                  \
+        }                                                               \
+        kfree(ptr);                                                     \
+        CDEBUG(D_MALLOC, "kfreed: %ld at %p (tot %ld).\n",              \
+               s, (ptr), presto_kmemory);                               \
+        presto_kmem_dec((ptr), s);                                      \
 } while (0)
 
-#define MYPATHLEN(buffer,path) (buffer + PAGE_SIZE - path - 1)
-
-#else /* __KERNEL__ */
-#include <asm/types.h>
-#include <sys/ioctl.h>
-struct lento_vfs_context {
-        __u32 slot_offset;
-        __u32 recno;
-        __u64 kml_offset;
-        __u32 flags;
-        __u32 updated_time;
-};
-#endif /* __KERNEL__*/
-
-
-/* marking flags for fsets */
-#define FSET_CLIENT_RO 0x00000001
-#define FSET_LENTO_RO  0x00000002
-#define FSET_HASPERMIT  0x00000004 /* we have a permit to WB */
-#define FSET_INSYNC     0x00000008 /* this fileset is in sync */
-#define FSET_PERMIT_WAITING 0x00000010 /* Lento is waiting for permit */
-#define FSET_STEAL_PERMIT 0x00000020 /* take permit if Lento is dead */
-#define FSET_JCLOSE_ON_WRITE 0x00000040 /* Journal closes on writes */
-
-
-/* what to mark indicator (ioctl parameter) */ 
-#define MARK_DENTRY   101
-#define MARK_FSET     102
-#define MARK_CACHE    103
-#define MARK_GETFL    104
+static inline int dentry_name_cmp(struct dentry *dentry, char *name)
+{
+        return (strlen(name) == dentry->d_name.len &&
+                memcmp(name, dentry->d_name.name, dentry->d_name.len) == 0);
+}
 
+static inline char *strdup(char *str)
+{
+        char *tmp;
+        tmp = kmalloc(strlen(str) + 1, GFP_KERNEL);
+        if (tmp)
+                memcpy(tmp, str, strlen(str) + 1);
+               
+        return tmp;
+}
 
+/* buffer MUST be at least the size of izo_ioctl_hdr */
+static inline int izo_ioctl_getdata(char *buf, char *end, void *arg)
+{
+        struct izo_ioctl_hdr *hdr;
+        struct izo_ioctl_data *data;
+        int err;
+        ENTRY;
+
+        hdr = (struct izo_ioctl_hdr *)buf;
+        data = (struct izo_ioctl_data *)buf;
+
+        err = copy_from_user(buf, (void *)arg, sizeof(*hdr));
+        if ( err ) {
+                EXIT;
+                return err;
+        }
+
+        if (hdr->ioc_version != IZO_IOCTL_VERSION) {
+                CERROR("IZO: version mismatch kernel vs application\n");
+                return -EINVAL;
+        }
+
+        if (hdr->ioc_len + buf >= end) {
+                CERROR("IZO: user buffer exceeds kernel buffer\n");
+                return -EINVAL;
+        }
+
+        if (hdr->ioc_len < sizeof(struct izo_ioctl_data)) {
+                CERROR("IZO: user buffer too small for ioctl\n");
+                return -EINVAL;
+        }
+
+        err = copy_from_user(buf, (void *)arg, hdr->ioc_len);
+        if ( err ) {
+                EXIT;
+                return err;
+        }
+
+        if (izo_ioctl_is_invalid(data)) {
+                CERROR("IZO: ioctl not correctly formatted\n");
+                return -EINVAL;
+        }
+
+        if (data->ioc_inllen1) {
+                data->ioc_inlbuf1 = &data->ioc_bulk[0];
+        }
+
+        if (data->ioc_inllen2) {
+                data->ioc_inlbuf2 = &data->ioc_bulk[0] +
+                        size_round(data->ioc_inllen1);
+        }
+
+        EXIT;
+        return 0;
+}
+
+# define MYPATHLEN(buffer, path) ((buffer) + PAGE_SIZE - (path))
+
+# define free kfree
+# define malloc(a) kmalloc(a, GFP_KERNEL)
+# define printf printk
+int kml_reint_rec(struct file *dir, struct izo_ioctl_data *data);
+int izo_get_fileid(struct file *dir, struct izo_ioctl_data *data);
+int izo_set_fileid(struct file *dir, struct izo_ioctl_data *data);
 
-struct readmount {
-        int io_len;  /* this is IN & OUT: true length of str is returned */
-        char *io_string;
-};
+#else /* __KERNEL__ */
+# include <stdlib.h>
+# include <stdio.h>
+# include <sys/types.h>
+# include <sys/ioctl.h>
+# include <string.h>
+
+# define printk printf
+# ifndef CERROR
+#   define CERROR printf
+# endif
+# define kmalloc(a,b) malloc(a)
+
+void init_fsreintdata (void);
+int kml_fsreint(struct kml_rec *rec, char *basedir);
+int kml_iocreint(__u32 size, char *ptr, __u32 offset, int dird,
+                 uuid_t uuid, __u32 generate_kml);
 
-/* modeled after setsockopt */
-/* so if you have no /proc, oh well. */
-/* for now it's all ints. We may grow this later for non-ints. */
-struct psdev_opt {
-        int optname;
-        int optval;
-};
+static inline int izo_ioctl_packlen(struct izo_ioctl_data *data);
 
-struct lento_input {
-        char *name;
-        struct lento_vfs_context info;
-};
+static inline void izo_ioctl_init(struct izo_ioctl_data *data)
+{
+        memset(data, 0, sizeof(*data));
+        data->ioc_len = sizeof(*data);
+        data->ioc_version = IZO_IOCTL_VERSION;
+}
 
-struct lento_input_attr {
-        char *name;
-#if BITS_PER_LONG < 64
-        __u32 dummy;    /* XXX on 64-bit platforms, this is not needed */
-#endif
-        __u32 valid;
-        __u32 mode;
-        __u32 uid;
-        __u32 gid;
-        __u64 size;
-        __s64 atime;
-        __s64 mtime;
-        __s64 ctime;
-        __u32 attr_flags;
-        struct lento_vfs_context info;
-};
+static inline int
+izo_ioctl_pack(struct izo_ioctl_data *data, char **pbuf, int max)
+{
+        char *ptr;
+        struct izo_ioctl_data *overlay;
+        data->ioc_len = izo_ioctl_packlen(data);
+        data->ioc_version = IZO_IOCTL_VERSION;
+
+        if (*pbuf && izo_ioctl_packlen(data) > max)
+                return 1;
+        if (*pbuf == NULL)
+                *pbuf = malloc(data->ioc_len);
+        if (*pbuf == NULL)
+                return 1;
+        overlay = (struct izo_ioctl_data *)*pbuf;
+        memcpy(*pbuf, data, sizeof(*data));
+
+        ptr = overlay->ioc_bulk;
+        if (data->ioc_inlbuf1)
+                LOGL(data->ioc_inlbuf1, data->ioc_inllen1, ptr);
+        if (data->ioc_inlbuf2)
+                LOGL(data->ioc_inlbuf2, data->ioc_inllen2, ptr);
+        if (izo_ioctl_is_invalid(overlay))
+                return 1;
 
-struct lento_input_mode {
-        char *name;
-        __u32 mode;
-        struct lento_vfs_context info;
-};
+        return 0;
+}
 
-struct lento_input_old_new {
-        char *oldname;
-        char *newname;
-        struct lento_vfs_context info;
-};
+#endif /* __KERNEL__*/
 
-struct lento_input_dev {
-        char *name;
-        __u32 mode;
-        __u32 major;
-        __u32 minor;
-        struct lento_vfs_context info;
-};
+#define IZO_ERROR_NAME 1
+#define IZO_ERROR_UPDATE 2
+#define IZO_ERROR_DELETE 3
+#define IZO_ERROR_RENAME 4
 
-struct lento_input_iopen {
-        char *name;
-#if BITS_PER_LONG < 64
-        __u32 dummy;    /* XXX on 64-bit platforms, this is not needed */
+static inline char *izo_error(int err)
+{
+#ifndef __KERNEL__
+        if (err <= 0)
+                return strerror(-err);
 #endif
-        __u64 ino;
-        __u32 generation;
-        __u32 flags;
-        __s32 fd;
-};
+        switch (err) {
+        case IZO_ERROR_NAME:
+                return "InterMezzo name/name conflict";
+        case IZO_ERROR_UPDATE:
+                return "InterMezzo update/update conflict";
+        case IZO_ERROR_DELETE:
+                return "InterMezzo update/delete conflict";
+        case IZO_ERROR_RENAME:
+                return "InterMezzo rename/rename conflict";
+        }
+        return "Unknown InterMezzo error";
+}
 
-struct lento_input_close {
-        __u32 fd;
-        struct lento_vfs_context info;
-};
-
-/* XXX: check for alignment */
-struct lento_input_ext_attr {
-        char  *path;
-        char  *name;
-        __u32 name_len;
-        char  *buffer;
-        __u32 buffer_len;
-        __u32 flags;
-        __u32 mode;
-        struct lento_vfs_context info;
-};
+static inline int izo_ioctl_packlen(struct izo_ioctl_data *data)
+{
+        int len = sizeof(struct izo_ioctl_data);
+        len += size_round(data->ioc_inllen1);
+        len += size_round(data->ioc_inllen2);
+        return len;
+}
 
-/* XXX should PRESTO_GET_* actually be of type _IOR, since we are reading? */
-#define PRESTO_GETMOUNT         _IOW ('p',0x03, struct readmount *)
-#define PRESTO_SETPID           _IOW ('p',0x04, struct readmount *)
-#define PRESTO_CLOSE_JOURNALF   _IOW ('p',0x06, struct readmount *)
-#define PRESTO_SET_FSETROOT     _IOW ('p',0x07, struct readmount *)
-#define PRESTO_CLEAR_FSETROOT   _IOW ('p',0x08, struct readmount *)
-#define PRESTO_SETOPT           _IOW ('p',0x09, struct psdev_opt *)
-#define PRESTO_GETOPT           _IOW ('p',0x0a, struct psdev_opt *)
-#define PRESTO_GET_KMLSIZE      _IOW ('p',0x0b, struct psdev_opt *)
-#define PRESTO_GET_RECNO        _IOW ('p',0x0c, struct psdev_opt *)
-#define PRESTO_VFS_SETATTR      _IOW ('p',0x10, struct lento_input_attr *)
-#define PRESTO_VFS_CREATE       _IOW ('p',0x11, struct lento_input_mode *)
-#define PRESTO_VFS_LINK         _IOW ('p',0x12, struct lento_input_old_new *)
-#define PRESTO_VFS_UNLINK       _IOW ('p',0x13, struct lento_input *)
-#define PRESTO_VFS_SYMLINK      _IOW ('p',0x14, struct lento_input_old_new *)
-#define PRESTO_VFS_MKDIR        _IOW ('p',0x15, struct lento_input_mode *)
-#define PRESTO_VFS_RMDIR        _IOW ('p',0x16, struct lento_input *)
-#define PRESTO_VFS_MKNOD        _IOW ('p',0x17, struct lento_input_dev *)
-#define PRESTO_VFS_RENAME       _IOW ('p',0x18, struct lento_input_old_new *)
-#define PRESTO_VFS_CLOSE        _IOW ('p',0x1a, struct lento_input_close *)
-#define PRESTO_VFS_IOPEN        _IOW ('p',0x1b, struct lento_input_iopen *)
-#define PRESTO_VFS_SETEXTATTR   _IOW ('p',0x1c, struct lento_input_ext_attr *)
-#define PRESTO_VFS_DELEXTATTR   _IOW ('p',0x1d, struct lento_input_ext_attr *)
-
-#define PRESTO_MARK             _IOW ('p',0x20, struct lento_input_open *)
-#define PRESTO_RELEASE_PERMIT   _IOW ('p',0x21, struct lento_input_open *)
-#define PRESTO_CLEAR_ALL_FSETROOTS  _IOW ('p',0x22, struct readmount *)
-#define PRESTO_BACKFETCH_LML    _IOW ('p',0x23, struct readmount *)
-#define PRESTO_REINT            _IOW ('p',0x24, struct readmount *)
-#define PRESTO_CANCEL_LML       _IOW ('p',0x25, struct readmount *)
-#define PRESTO_RESET_FSET       _IOW ('p',0x26, struct readmount *)
-#define PRESTO_COMPLETE_CLOSES  _IOW ('p',0x27, struct readmount *)
-
-#define PRESTO_REINT_BEGIN      _IOW ('p',0x30, struct readmount *)
-#define PRESTO_DO_REINT         _IOW ('p',0x31, struct readmount *)
-#define PRESTO_REINT_END        _IOW ('p',0x32, struct readmount *)
+static inline int izo_ioctl_is_invalid(struct izo_ioctl_data *data)
+{
+        if (data->ioc_len > (1<<30)) {
+                CERROR("IZO ioctl: ioc_len larger than 1<<30\n");
+                return 1;
+        }
+        if (data->ioc_inllen1 > (1<<30)) {
+                CERROR("IZO ioctl: ioc_inllen1 larger than 1<<30\n");
+                return 1;
+        }
+        if (data->ioc_inllen2 > (1<<30)) {
+                CERROR("IZO ioctl: ioc_inllen2 larger than 1<<30\n");
+                return 1;
+        }
+        if (data->ioc_inlbuf1 && !data->ioc_inllen1) {
+                CERROR("IZO ioctl: inlbuf1 pointer but 0 length\n");
+                return 1;
+        }
+        if (data->ioc_inlbuf2 && !data->ioc_inllen2) {
+                CERROR("IZO ioctl: inlbuf2 pointer but 0 length\n");
+                return 1;
+        }
+        if (data->ioc_pbuf1 && !data->ioc_plen1) {
+                CERROR("IZO ioctl: pbuf1 pointer but 0 length\n");
+                return 1;
+        }
+        if (data->ioc_pbuf2 && !data->ioc_plen2) {
+                CERROR("IZO ioctl: pbuf2 pointer but 0 length\n");
+                return 1;
+        }
+        if (izo_ioctl_packlen(data) != data->ioc_len ) {
+                CERROR("IZO ioctl: packlen exceeds ioc_len\n");
+                return 1;
+        }
+        if (data->ioc_inllen1 &&
+            data->ioc_bulk[data->ioc_inllen1 - 1] != '\0') {
+                CERROR("IZO ioctl: inlbuf1 not 0 terminated\n");
+                return 1;
+        }
+        if (data->ioc_inllen2 &&
+            data->ioc_bulk[size_round(data->ioc_inllen1) + data->ioc_inllen2
+                           - 1] != '\0') {
+                CERROR("IZO ioctl: inlbuf2 not 0 terminated\n");
+                return 1;
+        }
+        return 0;
+}
+
+/* kml_unpack.c */
+char *kml_print_rec(struct kml_rec *rec, int brief);
+int kml_unpack(struct kml_rec *rec, char **buf, char *end);
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/intermezzo_idl.h linux.20pre10-ac2/include/linux/intermezzo_idl.h
--- linux.20pre10/include/linux/intermezzo_idl.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/linux/intermezzo_idl.h	2002-10-10 23:26:12.000000000 +0100
@@ -0,0 +1,300 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 2001, 2002 Cluster File Systems, Inc.
+ *  Copyright (C) 2001 Tacit Networks, Inc.
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __INTERMEZZO_IDL_H__
+#define __INTERMEZZO_IDL_H__
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/* this file contains all data structures used in InterMezzo's interfaces:
+ * - upcalls
+ * - ioctl's
+ * - KML records
+ * - RCVD records
+ * - rpc's
+ */ 
+
+/* UPCALL */
+#define INTERMEZZO_MINOR 248   
+
+
+#define IZO_UPC_VERSION 0x00010002
+#define IZO_UPC_PERMIT        1
+#define IZO_UPC_CONNECT       2
+#define IZO_UPC_GO_FETCH_KML  3
+#define IZO_UPC_OPEN          4
+#define IZO_UPC_REVOKE_PERMIT 5
+#define IZO_UPC_KML           6
+#define IZO_UPC_BACKFETCH     7
+#define IZO_UPC_KML_TRUNC     8
+#define IZO_UPC_SET_KMLSIZE   9
+#define IZO_UPC_BRANCH_UNDO   10
+#define IZO_UPC_BRANCH_REDO   11
+#define IZO_UPC_GET_FILEID    12
+#define IZO_UPC_CLIENT_MAKE_BRANCH    13
+#define IZO_UPC_SERVER_MAKE_BRANCH    14
+#define IZO_UPC_REPSTATUS    15
+
+#define IZO_UPC_LARGEST_OPCODE 15
+
+struct izo_upcall_hdr {
+        __u32 u_len;
+        __u32 u_version;
+        __u32 u_opc;
+        __u32 u_uniq;
+        __u32 u_pid;
+        __u32 u_uid;
+        __u32 u_pathlen;
+        __u32 u_fsetlen;
+        __u64 u_offset;
+        __u64 u_length;
+        __u32 u_first_recno;
+        __u32 u_last_recno;
+        __u32 u_async;
+        __u32 u_reclen;
+        __u8  u_uuid[16];
+};
+
+/* This structure _must_ sit at the beginning of the buffer */
+struct izo_upcall_resp {
+        __u32 opcode;
+        __u32 unique;    
+        __u32 result;
+};
+
+
+/* IOCTL */
+
+#define IZO_IOCTL_VERSION 0x00010003
+
+/* maximum size supported for ioc_pbuf1 */
+#define KML_MAX_BUF (64*1024)
+
+struct izo_ioctl_hdr { 
+        __u32  ioc_len;
+        __u32  ioc_version;
+};
+
+struct izo_ioctl_data {
+        __u32 ioc_len;
+        __u32 ioc_version;
+        __u32 ioc_izodev;
+        __u32 ioc_kmlrecno;
+        __u64 ioc_kmlsize;
+        __u32 ioc_flags;
+        __s32 ioc_inofd;
+        __u64 ioc_ino;
+        __u64 ioc_generation;
+        __u32 ioc_mark_what;
+        __u32 ioc_and_flag;
+        __u32 ioc_or_flag;
+        __u32 ioc_dev;
+        __u32 ioc_offset;
+        __u32 ioc_slot;
+        __u64 ioc_uid;
+        __u8  ioc_uuid[16];
+
+        __u32 ioc_inllen1;   /* path */
+        char *ioc_inlbuf1;
+        __u32 ioc_inllen2;   /* fileset */
+        char *ioc_inlbuf2;
+
+        __u32 ioc_plen1;     /* buffers in user space (KML) */
+        char *ioc_pbuf1;
+        __u32 ioc_plen2;     /* buffers in user space (KML) */
+        char *ioc_pbuf2;
+
+        char  ioc_bulk[0];
+};
+
+#define IZO_IOC_DEVICE          _IOW ('p',0x50, void *)
+#define IZO_IOC_REINTKML        _IOW ('p',0x51, void *)
+#define IZO_IOC_GET_RCVD        _IOW ('p',0x52, void *)
+#define IZO_IOC_SET_IOCTL_UID   _IOW ('p',0x53, void *)
+#define IZO_IOC_GET_KML_SIZE    _IOW ('p',0x54, void *)
+#define IZO_IOC_PURGE_FILE_DATA _IOW ('p',0x55, void *)
+#define IZO_IOC_CONNECT         _IOW ('p',0x56, void *)
+#define IZO_IOC_GO_FETCH_KML    _IOW ('p',0x57, void *)
+#define IZO_IOC_MARK            _IOW ('p',0x58, void *)
+#define IZO_IOC_CLEAR_FSET      _IOW ('p',0x59, void *)
+#define IZO_IOC_CLEAR_ALL_FSETS _IOW ('p',0x60, void *)
+#define IZO_IOC_SET_FSET        _IOW ('p',0x61, void *)
+#define IZO_IOC_REVOKE_PERMIT   _IOW ('p',0x62, void *)
+#define IZO_IOC_SET_KMLSIZE     _IOW ('p',0x63, void *)
+#define IZO_IOC_CLIENT_MAKE_BRANCH _IOW ('p',0x64, void *)
+#define IZO_IOC_SERVER_MAKE_BRANCH _IOW ('p',0x65, void *)
+#define IZO_IOC_BRANCH_UNDO    _IOW ('p',0x66, void *)
+#define IZO_IOC_BRANCH_REDO    _IOW ('p',0x67, void *)
+#define IZO_IOC_SET_PID        _IOW ('p',0x68, void *)
+#define IZO_IOC_SET_CHANNEL    _IOW ('p',0x69, void *)
+#define IZO_IOC_GET_CHANNEL    _IOW ('p',0x70, void *)
+#define IZO_IOC_GET_FILEID    _IOW ('p',0x71, void *)
+#define IZO_IOC_ADJUST_LML    _IOW ('p',0x72, void *)
+#define IZO_IOC_SET_FILEID    _IOW ('p',0x73, void *)
+#define IZO_IOC_REPSTATUS    _IOW ('p',0x74, void *)
+
+/* marking flags for fsets */
+#define FSET_CLIENT_RO        0x00000001
+#define FSET_LENTO_RO         0x00000002
+#define FSET_HASPERMIT        0x00000004 /* we have a permit to WB */
+#define FSET_INSYNC           0x00000008 /* this fileset is in sync */
+#define FSET_PERMIT_WAITING   0x00000010 /* Lento is waiting for permit */
+#define FSET_STEAL_PERMIT     0x00000020 /* take permit if Lento is dead */
+#define FSET_JCLOSE_ON_WRITE  0x00000040 /* Journal closes on writes */
+#define FSET_DATA_ON_DEMAND   0x00000080 /* update data on file_open() */
+#define FSET_PERMIT_EXCLUSIVE 0x00000100 /* only one permitholder allowed */
+#define FSET_HAS_BRANCHES     0x00000200 /* this fileset contains branches */
+#define FSET_IS_BRANCH        0x00000400 /* this fileset is a branch */
+#define FSET_FLAT_BRANCH      0x00000800 /* this fileset is ROOT with branches */
+
+/* what to mark indicator (ioctl parameter) */
+#define MARK_DENTRY   101
+#define MARK_FSET     102
+#define MARK_CACHE    103
+#define MARK_GETFL    104
+
+/* KML */
+
+#define KML_MAJOR_VERSION 0x00010000
+#define KML_MINOR_VERSION 0x00000002
+#define KML_OPCODE_NOOP          0
+#define KML_OPCODE_CREATE        1
+#define KML_OPCODE_MKDIR         2
+#define KML_OPCODE_UNLINK        3
+#define KML_OPCODE_RMDIR         4
+#define KML_OPCODE_CLOSE         5
+#define KML_OPCODE_SYMLINK       6
+#define KML_OPCODE_RENAME        7
+#define KML_OPCODE_SETATTR       8
+#define KML_OPCODE_LINK          9
+#define KML_OPCODE_OPEN          10
+#define KML_OPCODE_MKNOD         11
+#define KML_OPCODE_WRITE         12
+#define KML_OPCODE_RELEASE       13
+#define KML_OPCODE_TRUNC         14
+#define KML_OPCODE_SETEXTATTR    15
+#define KML_OPCODE_DELEXTATTR    16
+#define KML_OPCODE_KML_TRUNC     17
+#define KML_OPCODE_GET_FILEID    18
+#define KML_OPCODE_NUM           19
+/* new stuff */
+struct presto_version {
+        __u64 pv_mtime;
+        __u64 pv_ctime;
+        __u64 pv_size;
+};
+
+struct kml_prefix_hdr {
+        __u32                    len;
+        __u32                    version;
+        __u32                    pid;
+        __u32                    auid;
+        __u32                    fsuid;
+        __u32                    fsgid;
+        __u32                    opcode;
+        __u32                    ngroups;
+};
+
+struct kml_prefix { 
+        struct kml_prefix_hdr    *hdr;
+        __u32                    *groups;
+};
+
+struct kml_suffix { 
+        __u32                    prevrec;
+        __u32                    recno;
+        __u32                    time;
+        __u32                    len;
+};
+
+struct kml_rec {
+        char                   *buf;
+        struct kml_prefix       prefix;
+        __u64                   offset;
+        char                   *path;
+        int                     pathlen;
+        char                   *name;
+        int                     namelen;
+        char                   *target;
+        int                     targetlen;
+        struct presto_version  *old_objectv;
+        struct presto_version  *new_objectv;
+        struct presto_version  *old_parentv;
+        struct presto_version  *new_parentv;
+        struct presto_version  *old_targetv;
+        struct presto_version  *new_targetv;
+        __u32                   valid;
+        __u32                   mode;
+        __u32                   uid;
+        __u32                   gid;
+        __u64                   size;
+        __u32                   mtime;
+        __u32                   ctime;
+        __u32                   flags;
+        __u32                   ino;
+        __u32                   rdev;
+        __u32                   major;
+        __u32                   minor;
+        __u32                   generation;
+        __u32                   old_mode;
+        __u32                   old_rdev;
+        __u64                   old_uid;
+        __u64                   old_gid;
+        char                   *old_target;
+        int                     old_targetlen;
+        struct kml_suffix      *suffix;
+};
+
+
+/* RCVD */ 
+
+/* izo_rcvd_rec fills the .intermezzo/fset/last_rcvd file and provides data about
+ * our view of reintegration offsets for a given peer.
+ *
+ * The only exception is the last_rcvd record which has a UUID consisting of all
+ * zeroes; this record's lr_local_offset field is the logical byte offset of our
+ * KML, which is updated when KML truncation takes place.  All other fields are
+ * reserved. */
+
+/* XXX - document how clean shutdowns are recorded */
+
+struct izo_rcvd_rec { 
+        __u8    lr_uuid[16];       /* which peer? */
+        __u64   lr_remote_recno;   /* last confirmed remote recno  */
+        __u64   lr_remote_offset;  /* last confirmed remote offset */
+        __u64   lr_local_recno;    /* last locally reinted recno   */
+        __u64   lr_local_offset;   /* last locally reinted offset  */
+        __u64   lr_last_ctime;     /* the largest ctime that has reintegrated */
+};
+
+/* Cache purge database
+ *
+ * Each DB entry is this structure followed by the path name, no trailing NUL. */
+struct izo_purge_entry {
+        __u64 p_atime;
+        __u32 p_pathlen;
+};
+
+/* RPC */
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/intermezzo_lib.h linux.20pre10-ac2/include/linux/intermezzo_lib.h
--- linux.20pre10/include/linux/intermezzo_lib.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/linux/intermezzo_lib.h	2002-10-10 23:26:12.000000000 +0100
@@ -0,0 +1,168 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
+ *
+ *   This file is part of InterMezzo, http://www.inter-mezzo.org.
+ *
+ *   InterMezzo is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   InterMezzo 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 InterMezzo; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Data structures unpacking/packing macros & inlines
+ *
+ */
+
+#ifndef _INTERMEZZO_LIB_H
+#define _INTERMEZZO_LIB_H
+
+#ifdef __KERNEL__
+# include <linux/types.h>
+#else
+# include <string.h>
+# include <sys/types.h>
+#endif
+
+#undef MIN
+#define MIN(a,b) (((a)<(b)) ? (a): (b))
+#undef MAX
+#define MAX(a,b) (((a)>(b)) ? (a): (b))
+#define MKSTR(ptr) ((ptr))? (ptr) : ""
+
+static inline int size_round (int val)
+{
+	return (val + 3) & (~0x3);
+}
+
+static inline int size_round0(int val)
+{
+        if (!val) 
+                return 0;
+	return (val + 1 + 3) & (~0x3);
+}
+
+static inline size_t round_strlen(char *fset)
+{
+	return size_round(strlen(fset) + 1);
+}
+
+#ifdef __KERNEL__
+# define NTOH__u32(var) le32_to_cpu(var)
+# define NTOH__u64(var) le64_to_cpu(var)
+# define HTON__u32(var) cpu_to_le32(var)
+# define HTON__u64(var) cpu_to_le64(var)
+#else
+# include <glib.h>
+# define NTOH__u32(var) GUINT32_FROM_LE(var)
+# define NTOH__u64(var) GUINT64_FROM_LE(var)
+# define HTON__u32(var) GUINT32_TO_LE(var)
+# define HTON__u64(var) GUINT64_TO_LE(var)
+#endif
+
+/* 
+ * copy sizeof(type) bytes from pointer to var and move ptr forward.
+ * return EFAULT if pointer goes beyond end
+ */
+#define UNLOGV(var,type,ptr,end)                \
+do {                                            \
+        var = *(type *)ptr;                     \
+        ptr += sizeof(type);                    \
+        if (ptr > end )                         \
+                return -EFAULT;                 \
+} while (0)
+
+/* the following two macros convert to little endian */
+/* type MUST be __u32 or __u64 */
+#define LUNLOGV(var,type,ptr,end)               \
+do {                                            \
+        var = NTOH##type(*(type *)ptr);         \
+        ptr += sizeof(type);                    \
+        if (ptr > end )                         \
+                return -EFAULT;                 \
+} while (0)
+
+/* now log values */
+#define LOGV(var,type,ptr)                      \
+do {                                            \
+        *((type *)ptr) = var;                   \
+        ptr += sizeof(type);                    \
+} while (0)
+
+/* and in network order */
+#define LLOGV(var,type,ptr)                     \
+do {                                            \
+        *((type *)ptr) = HTON##type(var);       \
+        ptr += sizeof(type);                    \
+} while (0)
+
+
+/* 
+ * set var to point at (type *)ptr, move ptr forward with sizeof(type)
+ * return from function with EFAULT if ptr goes beyond end
+ */
+#define UNLOGP(var,type,ptr,end)                \
+do {                                            \
+        var = (type *)ptr;                      \
+        ptr += sizeof(type);                    \
+        if (ptr > end )                         \
+                return -EFAULT;                 \
+} while (0)
+
+#define LOGP(var,type,ptr)                      \
+do {                                            \
+        memcpy(ptr, var, sizeof(type));         \
+        ptr += sizeof(type);                    \
+} while (0)
+
+/* 
+ * set var to point at (char *)ptr, move ptr forward by size_round(len);
+ * return from function with EFAULT if ptr goes beyond end
+ */
+#define UNLOGL(var,type,len,ptr,end)                    \
+do {                                                    \
+        if (len == 0)                                   \
+                var = (type *)0;                        \
+        else {                                          \
+                var = (type *)ptr;                      \
+                ptr += size_round(len * sizeof(type));  \
+        }                                               \
+        if (ptr > end )                                 \
+                return -EFAULT;                         \
+} while (0)
+
+#define UNLOGL0(var,type,len,ptr,end)                           \
+do {                                                            \
+        UNLOGL(var,type,len+1,ptr,end);                         \
+        if ( *((char *)ptr - size_round(len+1) + len) != '\0')  \
+                        return -EFAULT;                         \
+} while (0)
+
+#define LOGL(var,len,ptr)                               \
+do {                                                    \
+        size_t __fill = size_round(len);                \
+        /* Prevent data leakage. */                     \
+        if (__fill > 0)                                 \
+                memset((char *)ptr, 0, __fill);         \
+        memcpy((char *)ptr, (const char *)var, len);    \
+        ptr += __fill;                                  \
+} while (0)
+
+#define LOGL0(var,len,ptr)                              \
+do {                                                    \
+        if (!len) break;                                \
+        memcpy((char *)ptr, (const char *)var, len);    \
+        *((char *)(ptr) + len) = 0;                     \
+        ptr += size_round(len + 1);                     \
+} while (0)
+
+#endif /* _INTERMEZZO_LIB_H */
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/intermezzo_psdev.h linux.20pre10-ac2/include/linux/intermezzo_psdev.h
--- linux.20pre10/include/linux/intermezzo_psdev.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/linux/intermezzo_psdev.h	2002-10-11 00:35:04.000000000 +0100
@@ -1,57 +1,42 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ */
+
 #ifndef __PRESTO_PSDEV_H
 #define __PRESTO_PSDEV_H
 
-#ifdef PRESTO_DEVEL
-# define PRESTO_FS_NAME "izofs"
-# define PRESTO_PSDEV_NAME "/dev/izo"
-# define PRESTO_PSDEV_MAJOR 186
-#else
-# define PRESTO_FS_NAME "InterMezzo"
-# define PRESTO_PSDEV_NAME "/dev/intermezzo"
-# define PRESTO_PSDEV_MAJOR 185
-#endif
-
-#define MAX_PRESTODEV 16
-
+#define MAX_CHANNEL 16
+#define PROCNAME_SIZE 32
+#include <linux/locks.h>
+#include <linux/smp_lock.h>
 #include <linux/version.h>
 
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
-#define wait_queue_head_t  struct wait_queue *
-#define DECLARE_WAITQUEUE(name,task) \
-        struct wait_queue name = { task, NULL }
-#define init_waitqueue_head(arg) 
-#else
-#ifndef __initfunc
-#define __initfunc(arg) arg
-#endif
-#endif
-
-
-/* represents state of a /dev/presto */
+/* represents state of an instance reached with /dev/intermezzo */
 /* communication pending & processing queues */
-struct upc_comm {
+struct upc_channel {
         unsigned int         uc_seq;
-        wait_queue_head_t    uc_waitq;     /* Lento wait queue */
-        struct list_head    uc_pending;
-        struct list_head    uc_processing;
-        int                  uc_pid;       /* Lento's pid */
-        int                  uc_hard; /* allows signals during upcalls */
+        wait_queue_head_t    uc_waitq;    /* Lento wait queue */
+        struct list_head     uc_pending;
+        struct list_head     uc_processing;
+        spinlock_t            uc_lock;
+        int                  uc_pid;      /* Lento's pid */
+        int                  uc_hard;     /* allows signals during upcalls */
         int                  uc_no_filter;
         int                  uc_no_journal;
         int                  uc_no_upcall;
-        int                  uc_timeout; /* . sec: signals will dequeue upc */
+        int                  uc_timeout;  /* . sec: signals will dequeue upc */
         long                 uc_errorval; /* for testing I/O failures */
         struct list_head     uc_cache_list;
-        int                   uc_minor;
-        char *                uc_devname;
+        int                  uc_minor;
 };
 
-#define ISLENTO(minor) (current->pid == upc_comms[minor].uc_pid \
-                || current->p_pptr->pid == upc_comms[minor].uc_pid)
+#define ISLENTO(minor) (current->pid == izo_channels[minor].uc_pid \
+                || current->p_pptr->pid == izo_channels[minor].uc_pid \
+                || current->p_pptr->p_pptr->pid == izo_channels[minor].uc_pid)
 
-extern struct upc_comm upc_comms[MAX_PRESTODEV];
+extern struct upc_channel izo_channels[MAX_CHANNEL];
 
-/* messages between presto filesystem in kernel and Venus */
+/* message types between presto filesystem in kernel */
 #define REQ_READ   1
 #define REQ_WRITE  2
 #define REQ_ASYNC  4
@@ -60,10 +45,10 @@
 struct upc_req {
         struct list_head   rq_chain;
         caddr_t            rq_data;
-        u_short            rq_flags;
-        u_short            rq_bufsize;
-        u_short            rq_rep_size;
-        u_short            rq_opcode;  /* copied from data to save lookup */
+        int                rq_flags;
+        int                rq_bufsize;
+        int                rq_rep_size;
+        int                rq_opcode;  /* copied from data to save lookup */
         int                rq_unique;
         wait_queue_head_t  rq_sleep;   /* process' wait queue */
         unsigned long      rq_posttime;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/interrupt.h linux.20pre10-ac2/include/linux/interrupt.h
--- linux.20pre10/include/linux/interrupt.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/interrupt.h	2002-10-09 22:15:47.000000000 +0100
@@ -10,6 +10,7 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 #include <asm/ptrace.h>
+#include <asm/system.h>
 
 struct irqaction {
 	void (*handler)(int, void *, struct pt_regs *);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/iobuf.h linux.20pre10-ac2/include/linux/iobuf.h
--- linux.20pre10/include/linux/iobuf.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/linux/iobuf.h	2002-10-11 00:35:04.000000000 +0100
@@ -28,6 +28,8 @@
 #define KIO_STATIC_PAGES	(KIO_MAX_ATOMIC_IO / (PAGE_SIZE >> 10) + 1)
 #define KIO_MAX_SECTORS		(KIO_MAX_ATOMIC_IO * 2)
 
+#define RAWIO_BLOCKSIZE		4096
+
 /* The main kiobuf struct used for all our IO! */
 
 struct kiobuf 
@@ -37,7 +39,9 @@
 	int		offset;		/* Offset to start of valid data */
 	int		length;		/* Number of valid bytes of data */
 
-	unsigned int	locked : 1;	/* If set, pages has been locked */
+	unsigned int	locked : 1,	/* If set, pages has been locked */
+			dovary : 1;	/* If set, do variable size IO */
+
 
 	struct page **  maplist;
 	struct buffer_head ** bh;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/jbd.h linux.20pre10-ac2/include/linux/jbd.h
--- linux.20pre10/include/linux/jbd.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/linux/jbd.h	2002-10-11 00:35:04.000000000 +0100
@@ -70,7 +70,38 @@
 #define JFS_MIN_JOURNAL_BLOCKS 1024
 
 #ifdef __KERNEL__
+
+/**
+ * typedef handle_t - The handle_t type represents a single atomic update being performed by some process.
+ *
+ * All filesystem modifications made by the process go
+ * through this handle.  Recursive operations (such as quota operations)
+ * are gathered into a single update.
+ *
+ * The buffer credits field is used to account for journaled buffers
+ * being modified by the running process.  To ensure that there is
+ * enough log space for all outstanding operations, we need to limit the
+ * number of outstanding buffers possible at any time.  When the
+ * operation completes, any buffer credits not used are credited back to
+ * the transaction, so that at all times we know how many buffers the
+ * outstanding updates on a transaction might possibly touch. 
+ * 
+ * This is an opaque datatype.
+ **/
 typedef struct handle_s		handle_t;	/* Atomic operation type */
+
+
+/**
+ * typedef journal_t - The journal_t maintains all of the journaling state information for a single filesystem.
+ *
+ * journal_t is linked to from the fs superblock structure.
+ * 
+ * We use the journal_t to keep track of all outstanding transaction
+ * activity on the filesystem, and to manage the state of the log
+ * writing process.
+ *
+ * This is an opaque datatype.
+ **/
 typedef struct journal_s	journal_t;	/* Journal control structure */
 #endif
 
@@ -254,7 +285,7 @@
 
 static inline struct journal_head *bh2jh(struct buffer_head *bh)
 {
-	return bh->b_private;
+	return bh->b_journal_head;
 }
 
 #define HAVE_JOURNAL_CALLBACK_STATUS
@@ -266,7 +297,8 @@
 
 struct jbd_revoke_table_s;
 
-/* The handle_t type represents a single atomic update being performed
+/**
+ * The handle_t type represents a single atomic update being performed
  * by some process.  All filesystem modifications made by the process go
  * through this handle.  Recursive operations (such as quota operations)
  * are gathered into a single update.
@@ -277,7 +309,21 @@
  * number of outstanding buffers possible at any time.  When the
  * operation completes, any buffer credits not used are credited back to
  * the transaction, so that at all times we know how many buffers the
- * outstanding updates on a transaction might possibly touch. */
+ * outstanding updates on a transaction might possibly touch. 
+ *
+ * struct handle_s - The handle_s type is the concrete type associated with handle_t.
+ * @h_transaction: Which compound transaction is this update a part of?
+ * @h_buffer_credits: Number of remaining buffers we are allowed to dirty.
+ * @h_ref: Reference count on this handle
+ * @h_err: Field for caller's use to track errors through large fs operations
+ * @h_sync: flag for sync-on-close
+ * @h_jdata: flag to force data journaling
+ * @h_aborted: flag indicating fatal error on handle
+ **/
+
+/* Docbook can't yet cope with the bit fields, but will leave the documentation
+ * in so it can be fixed later. 
+ */
 
 struct handle_s 
 {
@@ -290,8 +336,8 @@
 	/* Reference count on this handle */
 	int			h_ref;
 
-	/* Field for caller's use to track errors through large fs
-	   operations */
+	/* Field for caller's use to track errors through large fs */
+	/* operations */
 	int			h_err;
 
 	/* List of application registered callbacks for this handle.
@@ -373,7 +419,7 @@
 	 */
 	struct journal_head *	t_async_datalist;
 	
-	/* Doubly-linked circular list of all forget buffers (superseded
+	/* Doubly-linked circular list of all forget buffers (superceded
            buffers which we can un-checkpoint once this transaction
            commits) */
 	struct journal_head *	t_forget;
@@ -425,21 +471,58 @@
 	struct list_head	t_jcb;
 };
 
-
-/* The journal_t maintains all of the journaling state information for a
- * single filesystem.  It is linked to from the fs superblock structure.
- * 
- * We use the journal_t to keep track of all outstanding transaction
- * activity on the filesystem, and to manage the state of the log
- * writing process. */
+/**
+ * struct journal_s - The journal_s type is the concrete type associated with journal_t.
+ * @j_flags:  General journaling state flags
+ * @j_errno:  Is there an outstanding uncleared error on the journal (from a prior abort)? 
+ * @j_sb_buffer: First part of superblock buffer
+ * @j_superblock: Second part of superblock buffer
+ * @j_format_version: Version of the superblock format
+ * @j_barrier_count:  Number of processes waiting to create a barrier lock
+ * @j_barrier: The barrier lock itself
+ * @j_running_transaction: The current running transaction..
+ * @j_committing_transaction: the transaction we are pushing to disk
+ * @j_checkpoint_transactions: a linked circular list of all transactions waiting for checkpointing
+ * @j_wait_transaction_locked: Wait queue for waiting for a locked transaction to start committing, or for a barrier lock to be released
+ * @j_wait_logspace: Wait queue for waiting for checkpointing to complete
+ * @j_wait_done_commit: Wait queue for waiting for commit to complete 
+ * @j_wait_checkpoint:  Wait queue to trigger checkpointing
+ * @j_wait_commit: Wait queue to trigger commit
+ * @j_wait_updates: Wait queue to wait for updates to complete
+ * @j_checkpoint_sem: Semaphore for locking against concurrent checkpoints
+ * @j_sem: The main journal lock, used by lock_journal() 
+ * @j_head: Journal head - identifies the first unused block in the journal
+ * @j_tail: Journal tail - identifies the oldest still-used block in the journal.
+ * @j_free: Journal free - how many free blocks are there in the journal?
+ * @j_first: The block number of the first usable block 
+ * @j_last: The block number one beyond the last usable block
+ * @j_dev: Device where we store the journal
+ * @j_blocksize: blocksize for the location where we store the journal.
+ * @j_blk_offset: starting block offset for into the device where we store the journal
+ * @j_fs_dev: Device which holds the client fs.  For internal journal this will be equal to j_dev
+ * @j_maxlen: Total maximum capacity of the journal region on disk.
+ * @j_inode: Optional inode where we store the journal.  If present, all  journal block numbers are mapped into this inode via bmap().
+ * @j_tail_sequence:  Sequence number of the oldest transaction in the log 
+ * @j_transaction_sequence: Sequence number of the next transaction to grant
+ * @j_commit_sequence: Sequence number of the most recently committed transaction
+ * @j_commit_request: Sequence number of the most recent transaction wanting commit 
+ * @j_uuid: Uuid of client object.
+ * @j_task: Pointer to the current commit thread for this journal
+ * @j_max_transaction_buffers:  Maximum number of metadata buffers to allow in a single compound commit transaction
+ * @j_commit_interval: What is the maximum transaction lifetime before we begin a commit?
+ * @j_commit_timer:  The timer used to wakeup the commit thread
+ * @j_commit_timer_active: Timer flag
+ * @j_all_journals:  Link all journals together - system-wide 
+ * @j_revoke: The revoke table - maintains the list of revoked blocks in the current transaction.
+ **/
 
 struct journal_s
 {
 	/* General journaling state flags */
 	unsigned long		j_flags;
 
-	/* Is there an outstanding uncleared error on the journal (from
-	 * a prior abort)? */
+	/* Is there an outstanding uncleared error on the journal (from */
+	/* a prior abort)? */
 	int			j_errno;
 	
 	/* The superblock buffer */
@@ -461,13 +544,13 @@
 	/* ... the transaction we are pushing to disk ... */
 	transaction_t *		j_committing_transaction;
 	
-	/* ... and a linked circular list of all transactions waiting
-	 * for checkpointing. */
+	/* ... and a linked circular list of all transactions waiting */
+	/* for checkpointing. */
 	/* Protected by journal_datalist_lock */
 	transaction_t *		j_checkpoint_transactions;
 
-	/* Wait queue for waiting for a locked transaction to start
-           committing, or for a barrier lock to be released */
+	/* Wait queue for waiting for a locked transaction to start */
+        /*  committing, or for a barrier lock to be released */
 	wait_queue_head_t	j_wait_transaction_locked;
 	
 	/* Wait queue for waiting for checkpointing to complete */
@@ -494,33 +577,33 @@
 	/* Journal head: identifies the first unused block in the journal. */
 	unsigned long		j_head;
 	
-	/* Journal tail: identifies the oldest still-used block in the
-	 * journal. */
+	/* Journal tail: identifies the oldest still-used block in the */
+	/* journal. */
 	unsigned long		j_tail;
 
 	/* Journal free: how many free blocks are there in the journal? */
 	unsigned long		j_free;
 
-	/* Journal start and end: the block numbers of the first usable
-	 * block and one beyond the last usable block in the journal. */
+	/* Journal start and end: the block numbers of the first usable */
+	/* block and one beyond the last usable block in the journal. */
 	unsigned long		j_first, j_last;
 
-	/* Device, blocksize and starting block offset for the location
-	 * where we store the journal. */
+	/* Device, blocksize and starting block offset for the location */
+	/* where we store the journal. */
 	kdev_t			j_dev;
 	int			j_blocksize;
 	unsigned int		j_blk_offset;
 
-	/* Device which holds the client fs.  For internal journal this
-	 * will be equal to j_dev. */
+	/* Device which holds the client fs.  For internal journal this */
+	/* will be equal to j_dev. */
 	kdev_t			j_fs_dev;
 
 	/* Total maximum capacity of the journal region on disk. */
 	unsigned int		j_maxlen;
 
-	/* Optional inode where we store the journal.  If present, all
-	 * journal block numbers are mapped into this inode via
-	 * bmap(). */
+	/* Optional inode where we store the journal.  If present, all */
+	/* journal block numbers are mapped into this inode via */
+	/* bmap(). */
 	struct inode *		j_inode;
 
 	/* Sequence number of the oldest transaction in the log */
@@ -532,23 +615,23 @@
 	/* Sequence number of the most recent transaction wanting commit */
 	tid_t			j_commit_request;
 
-	/* Journal uuid: identifies the object (filesystem, LVM volume
-	 * etc) backed by this journal.  This will eventually be
-	 * replaced by an array of uuids, allowing us to index multiple
-	 * devices within a single journal and to perform atomic updates
-	 * across them.  */
+	/* Journal uuid: identifies the object (filesystem, LVM volume   */
+	/* etc) backed by this journal.  This will eventually be         */
+	/* replaced by an array of uuids, allowing us to index multiple  */
+	/* devices within a single journal and to perform atomic updates */
+	/* across them.  */
 
 	__u8			j_uuid[16];
 
 	/* Pointer to the current commit thread for this journal */
 	struct task_struct *	j_task;
 
-	/* Maximum number of metadata buffers to allow in a single
-	 * compound commit transaction */
+	/* Maximum number of metadata buffers to allow in a single */
+	/* compound commit transaction */
 	int			j_max_transaction_buffers;
 
-	/* What is the maximum transaction lifetime before we begin a
-	 * commit? */
+	/* What is the maximum transaction lifetime before we begin a */
+	/* commit? */
 	unsigned long		j_commit_interval;
 
 	/* The timer used to wakeup the commit thread: */
@@ -558,8 +641,8 @@
 	/* Link all journals together - system-wide */
 	struct list_head	j_all_journals;
 
-	/* The revoke table: maintains the list of revoked blocks in the
-           current transaction. */
+	/* The revoke table: maintains the list of revoked blocks in the */
+        /*  current transaction. */
 	struct jbd_revoke_table_s *j_revoke;
 };
 
@@ -825,7 +908,7 @@
 #define BJ_SyncData	1	/* Normal data: flush before commit */
 #define BJ_AsyncData	2	/* writepage data: wait on it before commit */
 #define BJ_Metadata	3	/* Normal journaled metadata */
-#define BJ_Forget	4	/* Buffer superseded by this transaction */
+#define BJ_Forget	4	/* Buffer superceded by this transaction */
 #define BJ_IO		5	/* Buffer is for temporary IO use */
 #define BJ_Shadow	6	/* Buffer contents being shadowed to the log */
 #define BJ_LogCtl	7	/* Buffer contains log descriptors */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/kd.h linux.20pre10-ac2/include/linux/kd.h
--- linux.20pre10/include/linux/kd.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/kd.h	2002-09-18 14:26:33.000000000 +0100
@@ -132,6 +132,19 @@
 
 #define KDSIGACCEPT	0x4B4E	/* accept kbd generated signals */
 
+struct hwclk_time {
+	unsigned	sec;	/* 0..59 */
+	unsigned	min;	/* 0..59 */
+	unsigned	hour;	/* 0..23 */
+	unsigned	day;	/* 1..31 */
+	unsigned	mon;	/* 0..11 */
+	unsigned	year;	/* 70... */
+	int		wday;	/* 0..6, 0 is Sunday, -1 means unknown/don't set */
+};
+
+#define KDGHWCLK        0x4B50	/* get hardware clock */
+#define KDSHWCLK        0x4B51  /* set hardware clock */
+
 struct kbd_repeat {
 	int delay;	/* in msec; <= 0: don't change */
 	int rate;	/* in msec; <= 0: don't change */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/kernel_stat.h linux.20pre10-ac2/include/linux/kernel_stat.h
--- linux.20pre10/include/linux/kernel_stat.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/linux/kernel_stat.h	2002-10-09 22:15:47.000000000 +0100
@@ -27,11 +27,10 @@
 	unsigned int pgpgin, pgpgout;
 	unsigned int pswpin, pswpout;
 #if defined (__hppa__) 
-	unsigned int irqs[NR_IRQ_REGS][IRQ_PER_REGION];
+	unsigned int irqs[NR_CPUS][NR_IRQ_REGS][IRQ_PER_REGION];
 #elif !defined(CONFIG_ARCH_S390)
 	unsigned int irqs[NR_CPUS][NR_IRQS];
 #endif
-	unsigned int context_swtch;
 };
 
 extern struct kernel_stat kstat;
@@ -44,7 +43,12 @@
  */
 static inline int kstat_irqs (int irq)
 {
-	return kstat.irqs[IRQ_REGION(irq)][IRQ_OFFSET(irq)];
+	int i, sum=0; 
+
+	for (i = 0 ; i < smp_num_cpus ; i++)
+		sum += kstat.irqs[i][IRQ_REGION(irq)][IRQ_OFFSET(irq)];
+ 
+	return sum;
 }
 #elif !defined(CONFIG_ARCH_S390)
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/llc.h linux.20pre10-ac2/include/linux/llc.h
--- linux.20pre10/include/linux/llc.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/linux/llc.h	2002-09-18 14:26:34.000000000 +0100
@@ -0,0 +1,102 @@
+#ifndef __LINUX_LLC_H
+#define __LINUX_LLC_H
+/*
+ * IEEE 802.2 User Interface SAPs for Linux, data structures and indicators.
+ *
+ * Copyright (c) 2001 by Jay Schulist <jschlst@samba.org>
+ *
+ * This program can be redistributed or modified under the terms of the
+ * GNU General Public License as published by the Free Software Foundation.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#define __LLC_SOCK_SIZE__ 28	/* sizeof(sockaddr_llc), word align. */
+struct sockaddr_llc {
+	sa_family_t     sllc_family;	/* AF_LLC */
+	sa_family_t	sllc_arphrd;	/* ARPHRD_ETHER */
+	unsigned char   sllc_test;
+	unsigned char   sllc_xid;
+	unsigned char	sllc_ua;	/* UA data, only for SOCK_STREAM. */
+	unsigned char   sllc_dsap;
+	unsigned char   sllc_ssap;
+	unsigned char   sllc_dmac[IFHWADDRLEN];
+	unsigned char   sllc_smac[IFHWADDRLEN];
+	unsigned char   sllc_mmac[IFHWADDRLEN];
+	unsigned char   __pad[__LLC_SOCK_SIZE__ - sizeof(sa_family_t) * 2 -
+			      sizeof(unsigned char) * 5 - IFHWADDRLEN * 3];
+};
+
+/* sockopt definitions. */
+enum llc_sockopts {
+	LLC_OPT_UNKNOWN = 0,
+	LLC_OPT_RETRY,		/* max retrans attempts. */
+	LLC_OPT_SIZE,		/* max PDU size (octets). */
+	LLC_OPT_ACK_TMR_EXP,	/* ack expire time (secs). */
+	LLC_OPT_P_TMR_EXP,	/* pf cycle expire time (secs). */
+	LLC_OPT_REJ_TMR_EXP,	/* rej sent expire time (secs). */
+	LLC_OPT_BUSY_TMR_EXP,	/* busy state expire time (secs). */
+	LLC_OPT_TX_WIN,		/* tx window size. */
+	LLC_OPT_RX_WIN,		/* rx window size. */
+	LLC_OPT_MAX
+};
+
+#define LLC_OPT_MAX_RETRY	 100
+#define LLC_OPT_MAX_SIZE	4196
+#define LLC_OPT_MAX_WIN		 127
+#define LLC_OPT_MAX_ACK_TMR_EXP	  60
+#define LLC_OPT_MAX_P_TMR_EXP	  60
+#define LLC_OPT_MAX_REJ_TMR_EXP	  60
+#define LLC_OPT_MAX_BUSY_TMR_EXP  60
+
+/* LLC SAP types. */
+#define LLC_SAP_NULL	0x00		/* NULL SAP. 			*/
+#define LLC_SAP_LLC	0x02		/* LLC Sublayer Managment. 	*/
+#define LLC_SAP_SNA	0x04		/* SNA Path Control. 		*/
+#define LLC_SAP_PNM	0x0E		/* Proway Network Managment.	*/	
+#define LLC_SAP_IP	0x06		/* TCP/IP. 			*/
+#define LLC_SAP_BSPAN	0x42		/* Bridge Spanning Tree Proto	*/
+#define LLC_SAP_MMS	0x4E		/* Manufacturing Message Srv.	*/
+#define LLC_SAP_8208	0x7E		/* ISO 8208			*/
+#define LLC_SAP_3COM	0x80		/* 3COM. 			*/
+#define LLC_SAP_PRO	0x8E		/* Proway Active Station List	*/
+#define LLC_SAP_SNAP	0xAA		/* SNAP. 			*/
+#define LLC_SAP_BANYAN	0xBC		/* Banyan. 			*/
+#define LLC_SAP_IPX	0xE0		/* IPX/SPX. 			*/
+#define LLC_SAP_NETBEUI	0xF0		/* NetBEUI. 			*/
+#define LLC_SAP_LANMGR	0xF4		/* LanManager. 			*/
+#define LLC_SAP_IMPL	0xF8		/* IMPL				*/
+#define LLC_SAP_DISC	0xFC		/* Discovery			*/
+#define LLC_SAP_OSI	0xFE		/* OSI Network Layers. 		*/
+#define LLC_SAP_LAR	0xDC		/* LAN Address Resolution 	*/
+#define LLC_SAP_RM	0xD4		/* Resource Management 		*/
+#define LLC_SAP_GLOBAL	0xFF		/* Global SAP. 			*/
+
+#ifdef __KERNEL__
+#define LLC_SAP_DYN_START	0xC0
+#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.destruct_hook)
+#define llc_ui_skb_cb(__skb) ((struct sockaddr_llc *)&((__skb)->cb[0]))
+
+#ifdef CONFIG_LLC_UI
+extern int llc_ui_init(void);
+extern void llc_ui_exit(void);
+#else
+#define llc_ui_init()
+#define llc_ui_exit()
+#endif
+#endif /* __KERNEL__ */
+#endif /* __LINUX_LLC_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/lockd/lockd.h linux.20pre10-ac2/include/linux/lockd/lockd.h
--- linux.20pre10/include/linux/lockd/lockd.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/lockd/lockd.h	2002-10-11 00:35:04.000000000 +0100
@@ -89,8 +89,11 @@
 /*
  * This is a server block (i.e. a lock requested by some client which
  * couldn't be granted because of a conflicting lock).
+ *
+ * XXX: Beware of signedness errors. b_when is passed as a signed long
+ * into time_before_eq et al. --okir
  */
-#define NLM_NEVER		(~(unsigned long) 0)
+#define NLM_NEVER		(0x7FFFFFF)
 struct nlm_block {
 	struct nlm_block *	b_next;		/* linked list (all blocks) */
 	struct nlm_block *	b_fnext;	/* linked list (per file) */
@@ -161,6 +164,7 @@
 u32		  nlmsvc_testlock(struct nlm_file *, struct nlm_lock *,
 					struct nlm_lock *);
 u32		  nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *);
+void		  nlmsvc_grant_reply(struct nlm_cookie *, u32);
 unsigned long	  nlmsvc_retry_blocked(void);
 int		  nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *,
 					int action);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/malloc.h linux.20pre10-ac2/include/linux/malloc.h
--- linux.20pre10/include/linux/malloc.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/malloc.h	2002-10-11 00:35:04.000000000 +0100
@@ -1,7 +1,7 @@
 #ifndef _LINUX_MALLOC_H
 #define _LINUX_MALLOC_H
 
-#warning linux/malloc.h is deprecated, use linux/slab.h instead.
+#error linux/malloc.h is deprecated, use linux/slab.h instead.
 
 #include <linux/slab.h>
 #endif /* _LINUX_MALLOC_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/matroxfb.h linux.20pre10-ac2/include/linux/matroxfb.h
--- linux.20pre10/include/linux/matroxfb.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/linux/matroxfb.h	2002-09-18 14:26:34.000000000 +0100
@@ -30,5 +30,51 @@
 /* which outputs exist on this framebuffer */
 #define MATROXFB_GET_ALL_OUTPUTS	_IOR('n',0xFB,sizeof(__u32))
 
+struct matroxfb_queryctrl {
+  __u32 id;			/* ID for control */
+  char name[32];		/* A suggested label for this control */
+  int minimum;			/* Minimum value */
+  int maximum;			/* Maximum value */
+  unsigned int step;            /* The increment between values of an integer
+				   control that are distinct on the hardware */
+  int default_value;		/* Driver default value */
+  __u32 type;			/* Control type. */
+  __u32 flags;			/* Control flags */
+  __u32 category;               /* Control category code, useful for 
+				   separating controls by function */
+  char group[32];               /* A suggested label string for the 
+				   control group */
+  __u32 reserved[2];
+};
+
+enum matroxfb_ctrl_type {
+  MATROXFB_CTRL_TYPE_INTEGER=0,	/* An integer-valued control */
+  MATROXFB_CTRL_TYPE_BOOLEAN,	/* A boolean-valued control */
+  MATROXFB_CTRL_TYPE_MENU,	/* The control has a menu of choices */
+  MATROXFB_CTRL_TYPE_BUTTON /* A button which performs an action when clicked */
+};
+
+enum matroxfb_ctrl_id {
+  MATROXFB_CID_BRIGHTNESS=0x00980900,
+  MATROXFB_CID_CONTRAST,
+  MATROXFB_CID_SATURATION,
+  MATROXFB_CID_HUE,
+  MATROXFB_CID_GAMMA	 =0x00980910,
+  MATROXFB_CID_TESTOUT	 =0x08000000,
+  MATROXFB_CID_DEFLICKER,
+  MATROXFB_CID_LAST
+};
+  
+
+#define MATROXFB_TVOQUERYCTRL	_IOWR('V',36,struct matroxfb_queryctrl)
+   
+struct matroxfb_control {
+  __u32 id;			/* A driver-defined ID */
+  int value;			/* The current value, or new value */
+};
+
+#define MATROXFB_G_TVOCTRL	_IOWR('V',27,struct matroxfb_control)
+#define MATROXFB_S_TVOCTRL	_IOW ('V',28,struct matroxfb_control)
+
 #endif
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/mempool.h linux.20pre10-ac2/include/linux/mempool.h
--- linux.20pre10/include/linux/mempool.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/linux/mempool.h	2002-10-09 22:15:47.000000000 +0100
@@ -0,0 +1,31 @@
+/*
+ * memory buffer pool support
+ */
+#ifndef _LINUX_MEMPOOL_H
+#define _LINUX_MEMPOOL_H
+
+#include <linux/list.h>
+#include <linux/wait.h>
+
+struct mempool_s;
+typedef struct mempool_s mempool_t;
+
+typedef void * (mempool_alloc_t)(int gfp_mask, void *pool_data);
+typedef void (mempool_free_t)(void *element, void *pool_data);
+
+extern mempool_t * mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
+				 mempool_free_t *free_fn, void *pool_data);
+extern int mempool_resize(mempool_t *pool, int new_min_nr, int gfp_mask);
+extern void mempool_destroy(mempool_t *pool);
+extern void * mempool_alloc(mempool_t *pool, int gfp_mask);
+extern void mempool_free(void *element, mempool_t *pool);
+
+/*
+ * A mempool_alloc_t and mempool_free_t that get the memory from
+ * a slab that is passed in through pool_data.
+ */
+void *mempool_alloc_slab(int gfp_mask, void *pool_data);
+void mempool_free_slab(void *element, void *pool_data);
+
+
+#endif /* _LINUX_MEMPOOL_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/miscdevice.h linux.20pre10-ac2/include/linux/miscdevice.h
--- linux.20pre10/include/linux/miscdevice.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/miscdevice.h	2002-10-11 00:35:04.000000000 +0100
@@ -3,38 +3,39 @@
 
 #include <linux/devfs_fs_kernel.h>
 
-#define BUSMOUSE_MINOR 0
-#define PSMOUSE_MINOR  1
-#define MS_BUSMOUSE_MINOR 2
-#define ATIXL_BUSMOUSE_MINOR 3
-#define AMIGAMOUSE_MINOR 4
-#define ATARIMOUSE_MINOR 5
-#define SUN_MOUSE_MINOR 6
-#define APOLLO_MOUSE_MINOR 7
-#define PC110PAD_MINOR 9
-#define ADB_MOUSE_MINOR 10
-#define MK712_MINOR 15			/* MK712 touch screen */
+#define BUSMOUSE_MINOR		0
+#define PSMOUSE_MINOR		1
+#define MS_BUSMOUSE_MINOR	2
+#define ATIXL_BUSMOUSE_MINOR	3
+#define AMIGAMOUSE_MINOR	4
+#define ATARIMOUSE_MINOR	5
+#define SUN_MOUSE_MINOR		6
+#define APOLLO_MOUSE_MINOR	7
+#define PC110PAD_MINOR		9
+#define ADB_MOUSE_MINOR		10
+#define MK712_MINOR 		15	/* MK712 touch screen */
+#define SYNTH_MINOR    		25
 #define WATCHDOG_MINOR		130	/* Watchdog timer     */
 #define TEMP_MINOR		131	/* Temperature Sensor */
-#define RTC_MINOR 135
+#define RTC_MINOR		135
 #define EFI_RTC_MINOR		136	/* EFI Time services */
-#define SUN_OPENPROM_MINOR 139
-#define NVRAM_MINOR 144
-#define I2O_MINOR 166
+#define SUN_OPENPROM_MINOR	139
+#define NVRAM_MINOR		144
+#define I2O_MINOR		166
 #define MICROCODE_MINOR		184
-#define MWAVE_MINOR	219		/* ACP/Mwave Modem */
-#define MPT_MINOR	220
-#define MISC_DYNAMIC_MINOR 255
-
-#define SGI_GRAPHICS_MINOR   146
-#define SGI_OPENGL_MINOR     147
-#define SGI_GFX_MINOR        148
-#define SGI_STREAMS_MOUSE    149
-#define SGI_STREAMS_KEYBOARD 150
+#define MWAVE_MINOR		219	/* ACP/Mwave Modem */
+#define MPT_MINOR		220
+#define MISC_DYNAMIC_MINOR	255
+
+#define SGI_GRAPHICS_MINOR	146
+#define SGI_OPENGL_MINOR	147
+#define SGI_GFX_MINOR		148
+#define SGI_STREAMS_MOUSE	149
+#define SGI_STREAMS_KEYBOARD	150
 /* drivers/sgi/char/usema.c */
-#define SGI_USEMACLONE	     151
+#define SGI_USEMACLONE	    	151
 
-#define TUN_MINOR	     200
+#define TUN_MINOR	     	200
 
 extern int misc_init(void);
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/mman.h linux.20pre10-ac2/include/linux/mman.h
--- linux.20pre10/include/linux/mman.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/mman.h	2002-08-06 15:41:52.000000000 +0100
@@ -6,4 +6,8 @@
 #define MREMAP_MAYMOVE	1
 #define MREMAP_FIXED	2
 
+extern int vm_enough_memory(long pages);
+extern void vm_unacct_memory(long pages);
+extern void vm_validate_enough(char *x);
+
 #endif /* _LINUX_MMAN_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/mm.h linux.20pre10-ac2/include/linux/mm.h
--- linux.20pre10/include/linux/mm.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/mm.h	2002-10-11 00:35:04.000000000 +0100
@@ -18,9 +18,6 @@
 extern unsigned long num_mappedpages;
 extern void * high_memory;
 extern int page_cluster;
-/* The inactive_clean lists are per zone. */
-extern struct list_head active_list;
-extern struct list_head inactive_list;
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -104,7 +101,13 @@
 #define VM_DONTEXPAND	0x00040000	/* Cannot expand with mremap() */
 #define VM_RESERVED	0x00080000	/* Don't unmap it from swap_out */
 
-#define VM_STACK_FLAGS	0x00000177
+#define VM_ACCOUNT	0x00100000	/* Memory is a vm accounted object */
+
+#ifdef ARCH_STACK_GROWSUP
+#define VM_STACK_FLAGS	(VM_DATA_DEFAULT_FLAGS|VM_GROWSUP|VM_ACCOUNT)
+#else
+#define VM_STACK_FLAGS	(VM_DATA_DEFAULT_FLAGS|VM_GROWSDOWN|VM_ACCOUNT)
+#endif
 
 #define VM_READHINTMASK			(VM_SEQ_READ | VM_RAND_READ)
 #define VM_ClearReadHint(v)		(v)->vm_flags &= ~VM_READHINTMASK
@@ -122,7 +125,6 @@
  */
 extern pgprot_t protection_map[16];
 
-
 /*
  * These are the virtual MM functions - opening of an area, closing and
  * unmapping it (needed to keep files on disk up-to-date etc), pointer
@@ -134,6 +136,9 @@
 	struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int unused);
 };
 
+/* forward declaration; pte_chain is meant to be internal to rmap.c */
+struct pte_chain;
+
 /*
  * Each physical page in the system has a struct page associated with
  * it to keep track of whatever it is we are using the page for at the
@@ -151,7 +156,11 @@
  */
 typedef struct page {
 	struct list_head list;		/* ->mapping has some page lists. */
-	struct address_space *mapping;	/* The inode (or ...) we belong to. */
+	struct address_space *mapping;	/* The inode (or ...) we belong to.
+					 * protected by PG_locked and the
+					 * pagecache_lock. Hold one to read,
+					 * both to write.
+					 */
 	unsigned long index;		/* Our offset within mapping. */
 	struct page *next_hash;		/* Next page sharing our hash bucket in
 					   the pagecache hash table. */
@@ -160,6 +169,10 @@
 					   updated asynchronously */
 	struct list_head lru;		/* Pageout list, eg. active_list;
 					   protected by pagemap_lru_lock !! */
+	unsigned char age;		/* Page aging counter. */
+	struct pte_chain * pte_chain;	/* Reverse pte mapping pointer.
+					 * protected by PG_chainlock
+					 */ 
 	struct page **pprev_hash;	/* Complement to *next_hash. */
 	struct buffer_head * buffers;	/* Buffer maps us to a disk block. */
 
@@ -176,7 +189,7 @@
 #if defined(CONFIG_HIGHMEM) || defined(WANT_PAGE_VIRTUAL)
 	void *virtual;			/* Kernel virtual address (NULL if
 					   not kmapped, ie. highmem) */
-#endif /* CONFIG_HIGMEM || WANT_PAGE_VIRTUAL */
+#endif /* CONFIG_HIGHMEM || CONFIG_SPARC64 */
 } mem_map_t;
 
 /*
@@ -287,9 +300,9 @@
 #define PG_referenced		 2
 #define PG_uptodate		 3
 #define PG_dirty		 4
-#define PG_unused		 5
-#define PG_lru			 6
-#define PG_active		 7
+#define PG_inactive_clean	 5
+#define PG_active		 6
+#define PG_inactive_dirty	 7
 #define PG_slab			 8
 #define PG_skip			10
 #define PG_highmem		11
@@ -297,6 +310,10 @@
 #define PG_arch_1		13
 #define PG_reserved		14
 #define PG_launder		15	/* written out by VM pressure.. */
+#define PG_chainlock		16	/* lock bit for ->pte_chain */
+#define PG_lru			17
+/* Don't you dare to use high bits, they seem to be used for something else! */
+
 
 /* Make it prettier to test the above... */
 #define UnlockPage(page)	unlock_page(page)
@@ -316,6 +333,29 @@
 #define ClearPageLaunder(page)	clear_bit(PG_launder, &(page)->flags)
 
 /*
+ * inlines for acquisition and release of PG_chainlock
+ */
+static inline void pte_chain_lock(struct page *page)
+{
+	/*
+	 * Assuming the lock is uncontended, this never enters
+	 * the body of the outer loop. If it is contended, then
+	 * within the inner loop a non-atomic test is used to
+	 * busywait with less bus contention for a good time to
+	 * attempt to acquire the lock bit.
+	 */
+	while (test_and_set_bit(PG_chainlock, &page->flags)) {
+		while (test_bit(PG_chainlock, &page->flags))
+			cpu_relax();
+	}
+}
+
+static inline void pte_chain_unlock(struct page *page)
+{
+	clear_bit(PG_chainlock, &page->flags);
+}
+
+/*
  * The zone field is never updated after free_area_init_core()
  * sets it, so none of the operations on it need to be atomic.
  */
@@ -343,7 +383,6 @@
  * The same is true for page_address() in arch-dependent code.
  */
 #if defined(CONFIG_HIGHMEM) || defined(WANT_PAGE_VIRTUAL)
-
 #define set_page_address(page, address)			\
 	do {						\
 		(page)->virtual = (address);		\
@@ -357,6 +396,7 @@
  * Permanent address of a page. Obviously must never be
  * called on a highmem page.
  */
+
 #if defined(CONFIG_HIGHMEM) || defined(WANT_PAGE_VIRTUAL)
 
 #define page_address(page) ((page)->virtual)
@@ -392,10 +432,16 @@
 #define PageActive(page)	test_bit(PG_active, &(page)->flags)
 #define SetPageActive(page)	set_bit(PG_active, &(page)->flags)
 #define ClearPageActive(page)	clear_bit(PG_active, &(page)->flags)
+#define TestandSetPageActive(page)	test_and_set_bit(PG_active, &(page)->flags)
+#define TestandClearPageActive(page)	test_and_clear_bit(PG_active, &(page)->flags)
 
-#define PageLRU(page)		test_bit(PG_lru, &(page)->flags)
-#define TestSetPageLRU(page)	test_and_set_bit(PG_lru, &(page)->flags)
-#define TestClearPageLRU(page)	test_and_clear_bit(PG_lru, &(page)->flags)
+#define PageInactiveDirty(page)	test_bit(PG_inactive_dirty, &(page)->flags)
+#define SetPageInactiveDirty(page)	set_bit(PG_inactive_dirty, &(page)->flags)
+#define ClearPageInactiveDirty(page)	clear_bit(PG_inactive_dirty, &(page)->flags)
+
+#define PageInactiveClean(page)	test_bit(PG_inactive_clean, &(page)->flags)
+#define SetPageInactiveClean(page)	set_bit(PG_inactive_clean, &(page)->flags)
+#define ClearPageInactiveClean(page)	clear_bit(PG_inactive_clean, &(page)->flags)
 
 #ifdef CONFIG_HIGHMEM
 #define PageHighMem(page)		test_bit(PG_highmem, &(page)->flags)
@@ -406,6 +452,11 @@
 #define SetPageReserved(page)		set_bit(PG_reserved, &(page)->flags)
 #define ClearPageReserved(page)		clear_bit(PG_reserved, &(page)->flags)
 
+#define PageLRU(page)	 	test_bit(PG_lru, &(page)->flags)
+#define SetPageLRU(page)	set_bit(PG_lru, &(page)->flags)
+#define ClearPageLRU(page)	clear_bit(PG_lru, &(page)->flags)
+
+ 
 /*
  * Error return values for the *_nopage functions
  */
@@ -460,6 +511,7 @@
 #define __free_page(page) __free_pages((page), 0)
 #define free_page(addr) free_pages((addr),0)
 
+extern void FASTCALL(fixup_freespace(struct zone_struct *, int));
 extern void show_free_areas(void);
 extern void show_free_areas_node(pg_data_t *pgdat);
 
@@ -556,7 +608,7 @@
 	return ret;
 }
 
-extern int do_munmap(struct mm_struct *, unsigned long, size_t);
+extern int do_munmap(struct mm_struct *, unsigned long, size_t, int acct);
 
 extern unsigned long do_brk(unsigned long, unsigned long);
 
@@ -623,34 +675,9 @@
 
 	return gfp_mask;
 }
-	
-/* vma is the first one with  address < vma->vm_end,
- * and even  address < vma->vm_start. Have to extend vma. */
-static inline int expand_stack(struct vm_area_struct * vma, unsigned long address)
-{
-	unsigned long grow;
 
-	/*
-	 * vma->vm_start/vm_end cannot change under us because the caller is required
-	 * to hold the mmap_sem in write mode. We need to get the spinlock only
-	 * before relocating the vma range ourself.
-	 */
-	address &= PAGE_MASK;
- 	spin_lock(&vma->vm_mm->page_table_lock);
-	grow = (vma->vm_start - address) >> PAGE_SHIFT;
-	if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur ||
-	    ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) {
-		spin_unlock(&vma->vm_mm->page_table_lock);
-		return -ENOMEM;
-	}
-	vma->vm_start = address;
-	vma->vm_pgoff -= grow;
-	vma->vm_mm->total_vm += grow;
-	if (vma->vm_flags & VM_LOCKED)
-		vma->vm_mm->locked_vm += grow;
-	spin_unlock(&vma->vm_mm->page_table_lock);
-	return 0;
-}
+/* Do stack extension */	
+extern  int expand_stack(struct vm_area_struct * vma, unsigned long address);
 
 /* Look up the first VMA which satisfies  addr < vm_end,  NULL if none. */
 extern struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/mm_inline.h linux.20pre10-ac2/include/linux/mm_inline.h
--- linux.20pre10/include/linux/mm_inline.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/linux/mm_inline.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,274 @@
+#ifndef _LINUX_MM_INLINE_H
+#define _LINUX_MM_INLINE_H
+
+#include <linux/mm.h>
+
+/*
+ * These inline functions tend to need bits and pieces of all the
+ * other VM include files, meaning they cannot be defined inside
+ * one of the other VM include files.
+ *
+ * The include file mess really needs to be cleaned up...
+ */
+
+static inline void add_page_to_active_list(struct page * page)
+{
+	struct zone_struct * zone = page_zone(page);
+	DEBUG_LRU_PAGE(page);
+	SetPageActive(page);
+	list_add(&page->lru, &zone->active_list);
+	zone->active_pages++;
+	nr_active_pages++;
+}
+
+static inline void add_page_to_inactive_dirty_list(struct page * page)
+{
+	struct zone_struct * zone = page_zone(page);
+	DEBUG_LRU_PAGE(page);
+	SetPageInactiveDirty(page);
+	list_add(&page->lru, &zone->inactive_dirty_list);
+	zone->inactive_dirty_pages++;
+	nr_inactive_dirty_pages++;
+}
+
+static inline void add_page_to_inactive_clean_list(struct page * page)
+{
+	struct zone_struct * zone = page_zone(page);
+	DEBUG_LRU_PAGE(page);
+	SetPageInactiveClean(page);
+	list_add(&page->lru, &zone->inactive_clean_list);
+	zone->inactive_clean_pages++;
+	nr_inactive_clean_pages++;
+}
+
+static inline void del_page_from_active_list(struct page * page)
+{
+	struct zone_struct * zone = page_zone(page);
+	list_del(&page->lru);
+	ClearPageActive(page);
+	nr_active_pages--;
+	zone->active_pages--;
+	DEBUG_LRU_PAGE(page);
+}
+
+static inline void del_page_from_inactive_dirty_list(struct page * page)
+{
+	struct zone_struct * zone = page_zone(page);
+	list_del(&page->lru);
+	ClearPageInactiveDirty(page);
+	nr_inactive_dirty_pages--;
+	zone->inactive_dirty_pages--;
+	DEBUG_LRU_PAGE(page);
+}
+
+static inline void del_page_from_inactive_clean_list(struct page * page)
+{
+	struct zone_struct * zone = page_zone(page);
+	list_del(&page->lru);
+	ClearPageInactiveClean(page);
+	zone->inactive_clean_pages--;
+	nr_inactive_clean_pages--;
+	DEBUG_LRU_PAGE(page);
+}
+
+/*
+ * Inline functions to control some balancing in the VM.
+ *
+ * Note that we do both global and per-zone balancing, with
+ * most of the balancing done globally.
+ */
+#define	PLENTY_FACTOR	2
+#define	ALL_ZONES	NULL
+#define	ANY_ZONE	(struct zone_struct *)(~0UL)
+#define INACTIVE_FACTOR	5
+
+#define	VM_MIN	0
+#define	VM_LOW	1
+#define	VM_HIGH	2
+#define VM_PLENTY 3
+static inline int zone_free_limit(struct zone_struct * zone, int limit)
+{
+	int free, target, delta;
+
+	/* This is really nasty, but GCC should completely optimise it away. */
+	if (limit == VM_MIN)
+		target = zone->pages_min;
+	else if (limit == VM_LOW)
+		target = zone->pages_low;
+	else if (limit == VM_HIGH)
+		target = zone->pages_high;
+	else
+		target = zone->pages_high * PLENTY_FACTOR;
+
+	free = zone->free_pages + zone->inactive_clean_pages;
+	delta = target - free;
+
+	return delta;
+}
+
+static inline int free_limit(struct zone_struct * zone, int limit)
+{
+	int shortage = 0, local;
+
+	if (zone == ALL_ZONES) {
+		for_each_zone(zone)
+			shortage += zone_free_limit(zone, limit);
+	} else if (zone == ANY_ZONE) {
+		for_each_zone(zone) {
+			local = zone_free_limit(zone, limit);
+			shortage += max(local, 0);
+		}
+	} else {
+		shortage = zone_free_limit(zone, limit);
+	}
+
+	return shortage;
+}
+
+/**
+ * free_min - test for critically low amount of free pages
+ * @zone: zone to test, ALL_ZONES to test memory globally
+ *
+ * Returns a positive value if we have a serious shortage of free and
+ * clean pages, zero or negative if there is no serious shortage.
+ */
+static inline int free_min(struct zone_struct * zone)
+{
+	return free_limit(zone, VM_MIN);
+}
+
+/**
+ * free_low - test for low amount of free pages
+ * @zone: zone to test, ALL_ZONES to test memory globally
+ *
+ * Returns a positive value if we have a shortage of free and
+ * clean pages, zero or negative if there is no shortage.
+ */
+static inline int free_low(struct zone_struct * zone)
+{
+	return free_limit(zone, VM_LOW);
+}
+
+/**
+ * free_high - test if amount of free pages is less than ideal
+ * @zone: zone to test, ALL_ZONES to test memory globally
+ *
+ * Returns a positive value if the number of free and clean
+ * pages is below kswapd's target, zero or negative if we
+ * have more than enough free and clean pages.
+ */
+static inline int free_high(struct zone_struct * zone)
+{
+	return free_limit(zone, VM_HIGH);
+}
+
+/**
+ * free_plenty - test if enough pages are freed
+ * @zone: zone to test, ALL_ZONES to test memory globally
+ *
+ * Returns a positive value if the number of free + clean pages
+ * in a zone is not yet excessive and kswapd is still allowed to
+ * free pages here, a negative value if kswapd should leave the
+ * zone alone.
+ */
+static inline int free_plenty(struct zone_struct * zone)
+{
+	return free_limit(zone, VM_PLENTY);
+}
+
+/*
+ * The inactive page target is the free target + 20% of (active + inactive)
+ * pages. 
+ */
+static inline int zone_inactive_limit(struct zone_struct * zone, int limit)
+{
+	int inactive, target, inactive_base;
+
+	inactive_base = zone->active_pages + zone->inactive_dirty_pages;
+	inactive_base /= INACTIVE_FACTOR;
+
+	/* GCC should optimise this away completely. */
+	if (limit == VM_MIN)
+		target = zone->pages_high + inactive_base / 2;
+	else if (limit == VM_LOW)
+		target = zone->pages_high + inactive_base;
+	else
+		target = zone->pages_high + inactive_base * 2;
+
+	inactive = zone->free_pages + zone->inactive_clean_pages;
+	inactive += zone->inactive_dirty_pages;
+
+	return target - inactive;
+}
+
+static inline int inactive_limit(struct zone_struct * zone, int limit)
+{
+	int shortage = 0, local;
+
+	if (zone == ALL_ZONES) {
+		for_each_zone(zone)
+			shortage += zone_inactive_limit(zone, limit);
+	} else if (zone == ANY_ZONE) {
+		for_each_zone(zone) {
+			local = zone_inactive_limit(zone, limit);
+			shortage += max(local, 0);
+		}
+	} else {
+		shortage = zone_inactive_limit(zone, limit);
+	}
+
+	return shortage;
+}
+
+/**
+ * inactive_min - test for serious shortage of (free + inactive clean) pages
+ * @zone: zone to test, ALL_ZONES for global testing
+ *
+ * Returns the shortage as a positive number, a negative number
+ * if we have no serious shortage of (free + inactive clean) pages
+ */
+static inline int inactive_min(struct zone_struct * zone)
+{
+	return inactive_limit(zone, VM_MIN);
+}
+
+/**
+ * inactive_low - test for shortage of (free + inactive clean) pages
+ * @zone: zone to test, ALL_ZONES for global testing
+ *
+ * Returns the shortage as a positive number, a negative number
+ * if we have no shortage of (free + inactive clean) pages
+ */
+static inline int inactive_low(struct zone_struct * zone)
+{
+	return inactive_limit(zone, VM_LOW);
+}
+
+/**
+ * inactive_high - less than ideal amount of (free + inactive) pages
+ * @zone: zone to test, ALL_ZONES for global testing
+ *
+ * Returns the shortage as a positive number, a negative number
+ * if we have more than enough (free + inactive) pages
+ */
+static inline int inactive_high(struct zone_struct * zone)
+{
+	return inactive_limit(zone, VM_HIGH);
+}
+
+/*
+ * inactive_target - number of inactive pages we ought to have.
+ */
+static inline int inactive_target(void)
+{
+	int target;
+
+	target = nr_active_pages + nr_inactive_dirty_pages
+			+ nr_inactive_clean_pages;
+
+	target /= INACTIVE_FACTOR;
+
+	return target;
+}
+
+#endif /* _LINUX_MM_INLINE_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/mmzone.h linux.20pre10-ac2/include/linux/mmzone.h
--- linux.20pre10/include/linux/mmzone.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/linux/mmzone.h	2002-10-09 22:15:47.000000000 +0100
@@ -25,6 +25,15 @@
 } free_area_t;
 
 struct pglist_data;
+struct pte_chain;
+
+#define MAX_CHUNKS_PER_NODE 8
+
+#define MAX_PER_CPU_PAGES 512
+typedef struct per_cpu_pages_s {
+	int			nr_pages, max_nr_pages;
+	struct list_head	head;
+} __attribute__((aligned(L1_CACHE_BYTES))) per_cpu_t;
 
 /*
  * On machines where it is needed (eg PCs) we divide physical memory
@@ -38,21 +47,30 @@
 	/*
 	 * Commonly accessed fields:
 	 */
+	per_cpu_t		cpu_pages[NR_CPUS];
 	spinlock_t		lock;
 	unsigned long		free_pages;
-	unsigned long		pages_min, pages_low, pages_high;
+	unsigned long		active_pages;
+	unsigned long		inactive_dirty_pages;
+	unsigned long		inactive_clean_pages;
+	unsigned long		pages_min, pages_low, pages_high, pages_plenty;
 	int			need_balance;
 
 	/*
 	 * free areas of different sizes
 	 */
+	struct list_head	active_list;
+	struct list_head	inactive_dirty_list;
+	struct list_head	inactive_clean_list;
 	free_area_t		free_area[MAX_ORDER];
+	spinlock_t		pte_chain_freelist_lock;
+	struct pte_chain	*pte_chain_freelist;
 
 	/*
-	 * wait_table		-- the array holding the hash table
-	 * wait_table_size	-- the size of the hash table array
-	 * wait_table_shift	-- wait_table_size
-	 * 				== BITS_PER_LONG (1 << wait_table_bits)
+	 * wait_table           -- the array holding the hash table
+	 * wait_table_size      -- the size of the hash table array
+	 * wait_table_shift     -- wait_table_size
+	 *                             == BITS_PER_LONG (1 << wait_table_bits)
 	 *
 	 * The purpose of all these is to keep track of the people
 	 * waiting for a page to become available and make them
@@ -143,9 +161,6 @@
 extern int numnodes;
 extern pg_data_t *pgdat_list;
 
-#define memclass(pgzone, classzone)	(((pgzone)->zone_pgdat == (classzone)->zone_pgdat) \
-			&& ((pgzone) <= (classzone)))
-
 /*
  * The following two are not meant for general usage. They are here as
  * prototypes for the discontig memory code.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/msdos_fs.h linux.20pre10-ac2/include/linux/msdos_fs.h
--- linux.20pre10/include/linux/msdos_fs.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/msdos_fs.h	2002-10-11 00:35:04.000000000 +0100
@@ -70,9 +70,9 @@
 
 #define MSDOS_FAT12 4084 /* maximum number of clusters in a 12 bit FAT */
 
-#define EOF_FAT12 0xFF8		/* standard EOF */
-#define EOF_FAT16 0xFFF8
-#define EOF_FAT32 0xFFFFFF8
+#define EOF_FAT12 0xFFF		/* standard EOF */
+#define EOF_FAT16 0xFFFF
+#define EOF_FAT32 0xFFFFFFF
 #define EOF_FAT(s) (MSDOS_SB(s)->fat_bits == 32 ? EOF_FAT32 : \
 	MSDOS_SB(s)->fat_bits == 16 ? EOF_FAT16 : EOF_FAT12)
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/nfs_fs.h linux.20pre10-ac2/include/linux/nfs_fs.h
--- linux.20pre10/include/linux/nfs_fs.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/nfs_fs.h	2002-10-11 00:35:04.000000000 +0100
@@ -270,6 +270,11 @@
 extern int  nfs_scan_lru_read_timeout(struct nfs_server *, struct list_head *);
 
 /*
+ * linux/fs/nfs/direct.c
+ */
+extern int  nfs_direct_IO(int, struct file *, struct kiobuf *, unsigned long, int);
+
+/*
  * linux/fs/mount_clnt.c
  * (Used only by nfsroot module)
  */
@@ -298,6 +303,23 @@
 	return __nfs_refresh_inode(inode,fattr);
 }
 
+/*
+ * This function will be used to simulate weak cache consistency
+ * under NFSv2 when the NFSv3 attribute patch is included.
+ * For the moment, we just call nfs_refresh_inode().
+ */
+static __inline__ int
+nfs_write_attributes(struct inode *inode, struct nfs_fattr *fattr)
+{
+	if ((fattr->valid & NFS_ATTR_FATTR) && !(fattr->valid & NFS_ATTR_WCC)) {
+		fattr->pre_size  = NFS_CACHE_ISIZE(inode);
+		fattr->pre_mtime = NFS_CACHE_MTIME(inode);
+		fattr->pre_ctime = NFS_CACHE_CTIME(inode);
+		fattr->valid |= NFS_ATTR_WCC;
+	}
+	return nfs_refresh_inode(inode, fattr);
+}
+
 static inline loff_t
 nfs_size_to_loff_t(__u64 size)
 {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/nfs_xdr.h linux.20pre10-ac2/include/linux/nfs_xdr.h
--- linux.20pre10/include/linux/nfs_xdr.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/linux/nfs_xdr.h	2002-10-11 00:22:21.000000000 +0100
@@ -59,7 +59,7 @@
 /* Arguments to the read call.
  * Note that NFS_READ_MAXIOV must be <= (MAX_IOVEC-2) from sunrpc/xprt.h
  */
-#define NFS_READ_MAXIOV 8
+#define NFS_READ_MAXIOV		(9)
 
 struct nfs_readargs {
 	struct nfs_fh *		fh;
@@ -78,7 +78,7 @@
 /* Arguments to the write call.
  * Note that NFS_WRITE_MAXIOV must be <= (MAX_IOVEC-2) from sunrpc/xprt.h
  */
-#define NFS_WRITE_MAXIOV        8
+#define NFS_WRITE_MAXIOV	(9)
 struct nfs_writeargs {
 	struct nfs_fh *		fh;
 	__u64			offset;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/pci_ids.h linux.20pre10-ac2/include/linux/pci_ids.h
--- linux.20pre10/include/linux/pci_ids.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/linux/pci_ids.h	2002-10-10 23:56:47.000000000 +0100
@@ -288,6 +288,12 @@
 #define PCI_DEVICE_ID_NS_87560_USB	0x0012
 #define PCI_DEVICE_ID_NS_83815		0x0020
 #define PCI_DEVICE_ID_NS_83820		0x0022
+#define PCI_DEVICE_ID_NS_SCx200_BRIDGE	0x0500
+#define PCI_DEVICE_ID_NS_SCx200_SMI	0x0501
+#define PCI_DEVICE_ID_NS_SCx200_IDE	0x0502
+#define PCI_DEVICE_ID_NS_SCx200_AUDIO	0x0503
+#define PCI_DEVICE_ID_NS_SCx200_VIDEO	0x0504
+#define PCI_DEVICE_ID_NS_SCx200_XBUS	0x0505
 #define PCI_DEVICE_ID_NS_87410		0xd001
 
 #define PCI_VENDOR_ID_TSENG		0x100c
@@ -387,11 +393,17 @@
 #define PCI_DEVICE_ID_AMD_VIPER_7411	0x7411
 #define PCI_DEVICE_ID_AMD_VIPER_7413	0x7413
 #define PCI_DEVICE_ID_AMD_VIPER_7414	0x7414
-#define PCI_DEVICE_ID_AMD_VIPER_7440	0x7440
-#define PCI_DEVICE_ID_AMD_VIPER_7441	0x7441
-#define PCI_DEVICE_ID_AMD_VIPER_7443	0x7443
-#define PCI_DEVICE_ID_AMD_VIPER_7448	0x7448
-#define PCI_DEVICE_ID_AMD_VIPER_7449	0x7449
+#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_AC97    0x746d
 
@@ -477,19 +489,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
@@ -739,7 +760,9 @@
 #define PCI_DEVICE_ID_CMD_648		0x0648
 #define PCI_DEVICE_ID_CMD_649		0x0649
 #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
@@ -884,6 +907,7 @@
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA	0x0152
 #define PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO	0x0153
 #define PCI_DEVICE_ID_NVIDIA_IGEFORCE2		0x01a0
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE		0x01bc
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3		0x0200
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1		0x0201
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2		0x0202
@@ -985,6 +1009,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
@@ -1123,6 +1148,7 @@
 #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_CSB6USB 0x0221
@@ -1567,6 +1593,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
@@ -1628,7 +1657,11 @@
 #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_82815_MC	0x1130
+
 #define PCI_DEVICE_ID_INTEL_82559ER	0x1209
 #define PCI_DEVICE_ID_INTEL_82092AA_0	0x1221
 #define PCI_DEVICE_ID_INTEL_82092AA_1	0x1222
@@ -1684,9 +1717,9 @@
 #define PCI_DEVICE_ID_INTEL_82801E_2	0x2452
 #define PCI_DEVICE_ID_INTEL_82801E_3	0x2453
 #define PCI_DEVICE_ID_INTEL_82801E_9	0x2459
-#define PCI_DEVICE_ID_INTEL_82801E_11	0x245b
-#define PCI_DEVICE_ID_INTEL_82801E_13	0x245d
-#define PCI_DEVICE_ID_INTEL_82801E_14	0x245e
+#define PCI_DEVICE_ID_INTEL_82801E_11	0x245B
+#define PCI_DEVICE_ID_INTEL_82801E_14	0x245D
+#define PCI_DEVICE_ID_INTEL_82801E_15	0x245E
 #define PCI_DEVICE_ID_INTEL_82801CA_0	0x2480
 #define PCI_DEVICE_ID_INTEL_82801CA_2	0x2482
 #define PCI_DEVICE_ID_INTEL_82801CA_3	0x2483
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/pc_keyb.h linux.20pre10-ac2/include/linux/pc_keyb.h
--- linux.20pre10/include/linux/pc_keyb.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/pc_keyb.h	2002-08-06 15:41:52.000000000 +0100
@@ -128,3 +128,6 @@
 	struct fasync_struct *fasync;
 	unsigned char buf[AUX_BUF_SIZE];
 };
+
+extern void pckbd_blink (char);
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/pnpbios.h linux.20pre10-ac2/include/linux/pnpbios.h
--- linux.20pre10/include/linux/pnpbios.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/linux/pnpbios.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,212 @@
+/*
+ * Include file for the interface to a PnP BIOS
+ *
+ * Original BIOS code (C) 1998 Christian Schmidt (chr.schmidt@tu-bs.de)
+ * PnP handler parts (c) 1998 Tom Lees <tom@lpsg.demon.co.uk>
+ * Minor reorganizations by David Hinds <dhinds@zen.stanford.edu>
+ *
+ * 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, 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
+ */
+
+#ifndef _LINUX_PNPBIOS_H
+#define _LINUX_PNPBIOS_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/pci.h>
+
+/*
+ * Status codes (warnings and errors)
+ */
+#define PNP_SUCCESS                     0x00
+#define PNP_NOT_SET_STATICALLY          0x7f
+#define PNP_UNKNOWN_FUNCTION            0x81
+#define PNP_FUNCTION_NOT_SUPPORTED      0x82
+#define PNP_INVALID_HANDLE              0x83
+#define PNP_BAD_PARAMETER               0x84
+#define PNP_SET_FAILED                  0x85
+#define PNP_EVENTS_NOT_PENDING          0x86
+#define PNP_SYSTEM_NOT_DOCKED           0x87
+#define PNP_NO_ISA_PNP_CARDS            0x88
+#define PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES 0x89
+#define PNP_CONFIG_CHANGE_FAILED_NO_BATTERY 0x8a
+#define PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT 0x8b
+#define PNP_BUFFER_TOO_SMALL            0x8c
+#define PNP_USE_ESCD_SUPPORT            0x8d
+#define PNP_MESSAGE_NOT_SUPPORTED       0x8e
+#define PNP_HARDWARE_ERROR              0x8f
+
+#define ESCD_SUCCESS                    0x00
+#define ESCD_IO_ERROR_READING           0x55
+#define ESCD_INVALID                    0x56
+#define ESCD_BUFFER_TOO_SMALL           0x59
+#define ESCD_NVRAM_TOO_SMALL            0x5a
+#define ESCD_FUNCTION_NOT_SUPPORTED     0x81
+
+/*
+ * Events that can be received by "get event"
+ */
+#define PNPEV_ABOUT_TO_CHANGE_CONFIG	0x0001
+#define PNPEV_DOCK_CHANGED		0x0002
+#define PNPEV_SYSTEM_DEVICE_CHANGED	0x0003
+#define PNPEV_CONFIG_CHANGED_FAILED	0x0004
+#define PNPEV_UNKNOWN_SYSTEM_EVENT	0xffff
+/* 0x8000 through 0xfffe are OEM defined */
+
+/*
+ * Messages that should be sent through "send message"
+ */
+#define PNPMSG_OK			0x00
+#define PNPMSG_ABORT			0x01
+#define PNPMSG_UNDOCK_DEFAULT_ACTION	0x40
+#define PNPMSG_POWER_OFF		0x41
+#define PNPMSG_PNP_OS_ACTIVE		0x42
+#define PNPMSG_PNP_OS_INACTIVE		0x43
+/* 0x8000 through 0xffff are OEM defined */
+
+#pragma pack(1)
+struct pnp_dev_node_info {
+	__u16	no_nodes;
+	__u16	max_node_size;
+};
+struct pnp_docking_station_info {
+	__u32	location_id;
+	__u32	serial;
+	__u16	capabilities;
+};
+struct pnp_isa_config_struc {
+	__u8	revision;
+	__u8	no_csns;
+	__u16	isa_rd_data_port;
+	__u16	reserved;
+};
+struct escd_info_struc {
+	__u16	min_escd_write_size;
+	__u16	escd_size;
+	__u32	nv_storage_base;
+};
+struct pnp_bios_node {
+	__u16	size;
+	__u8	handle;
+	__u32	eisa_id;
+	__u8	type_code[3];
+	__u16	flags;
+	__u8	data[0];
+};
+#pragma pack()
+
+struct pnpbios_device_id
+{
+	char id[8];
+	unsigned long driver_data;
+};
+
+struct pnpbios_driver {
+	struct list_head node;
+	char *name;
+	const struct pnpbios_device_id *id_table;	/* NULL if wants all devices */
+	int  (*probe)  (struct pci_dev *dev, const struct pnpbios_device_id *id);	/* New device inserted */
+	void (*remove) (struct pci_dev *dev);		/* Device removed, either due to hotplug remove or module remove */
+};
+
+#ifdef CONFIG_PNPBIOS
+
+/* exported */
+extern int  pnpbios_register_driver(struct pnpbios_driver *drv);
+extern void pnpbios_unregister_driver(struct pnpbios_driver *drv);
+
+/* non-exported */
+#define pnpbios_for_each_dev(dev) \
+	for(dev = pnpbios_dev_g(pnpbios_devices.next); dev != pnpbios_dev_g(&pnpbios_devices); dev = pnpbios_dev_g(dev->global_list.next))
+
+
+#define pnpbios_dev_g(n) list_entry(n, struct pci_dev, global_list)
+
+static __inline struct pnpbios_driver *pnpbios_dev_driver(const struct pci_dev *dev)
+{
+	return (struct pnpbios_driver *)dev->driver;
+}
+
+extern int  pnpbios_dont_use_current_config;
+extern void *pnpbios_kmalloc(size_t size, int f);
+extern int pnpbios_init (void);
+extern int pnpbios_proc_init (void);
+extern void pnpbios_proc_exit (void);
+
+extern int pnp_bios_dev_node_info (struct pnp_dev_node_info *data);
+extern int pnp_bios_get_dev_node (u8 *nodenum, char config, struct pnp_bios_node *data);
+extern int pnp_bios_set_dev_node (u8 nodenum, char config, struct pnp_bios_node *data);
+extern int pnp_bios_get_stat_res (char *info);
+extern int pnp_bios_isapnp_config (struct pnp_isa_config_struc *data);
+extern int pnp_bios_escd_info (struct escd_info_struc *data);
+extern int pnp_bios_read_escd (char *data, u32 nvram_base);
+#if needed
+extern int pnp_bios_get_event (u16 *message);
+extern int pnp_bios_send_message (u16 message);
+extern int pnp_bios_set_stat_res (char *info);
+extern int pnp_bios_apm_id_table (char *table, u16 *size);
+extern int pnp_bios_write_escd (char *data, u32 nvram_base);
+#endif
+
+/*
+ * a helper function which helps ensure correct pnpbios_driver
+ * setup and cleanup for commonly-encountered hotplug/modular cases
+ *
+ * This MUST stay in a header, as it checks for -DMODULE
+ */
+ 
+static inline int pnpbios_module_init(struct pnpbios_driver *drv)
+{
+	int rc = pnpbios_register_driver (drv);
+
+	if (rc > 0)
+		return 0;
+
+	/* iff CONFIG_HOTPLUG and built into kernel, we should
+	 * leave the driver around for future hotplug events.
+	 * For the module case, a hotplug daemon of some sort
+	 * should load a module in response to an insert event. */
+#if defined(CONFIG_HOTPLUG) && !defined(MODULE)
+	if (rc == 0)
+		return 0;
+#else
+	if (rc == 0)
+		rc = -ENODEV;		
+#endif
+
+	/* if we get here, we need to clean up pci driver instance
+	 * and return some sort of error */
+	pnpbios_unregister_driver (drv);
+	
+	return rc;
+}
+
+#else /* CONFIG_PNPBIOS */
+
+static __inline__ int pnpbios_register_driver(struct pnpbios_driver *drv)
+{
+	return 0;
+}
+
+static __inline__ void pnpbios_unregister_driver(struct pnpbios_driver *drv)
+{
+	return;
+}
+
+#endif /* CONFIG_PNPBIOS */
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_PNPBIOS_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/quotacompat.h linux.20pre10-ac2/include/linux/quotacompat.h
--- linux.20pre10/include/linux/quotacompat.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/linux/quotacompat.h	2002-09-18 14:26:34.000000000 +0100
@@ -0,0 +1,86 @@
+/*
+ *	Definition of symbols used for backward compatible interface
+ */
+
+#ifndef _LINUX_QUOTACOMPAT_
+#define _LINUX_QUOTACOMPAT_
+
+#include <linux/types.h>
+#include <linux/quota.h>
+
+struct v1c_mem_dqblk {
+	__u32 dqb_bhardlimit;	/* absolute limit on disk blks alloc */
+	__u32 dqb_bsoftlimit;	/* preferred limit on disk blks */
+	__u32 dqb_curblocks;	/* current block count */
+	__u32 dqb_ihardlimit;	/* maximum # allocated inodes */
+	__u32 dqb_isoftlimit;	/* preferred inode limit */
+	__u32 dqb_curinodes;	/* current # allocated inodes */
+	time_t dqb_btime;	/* time limit for excessive disk use */
+	time_t dqb_itime;	/* time limit for excessive files */
+};
+
+struct v1c_dqstats {
+	__u32 lookups;
+	__u32 drops;
+	__u32 reads;
+	__u32 writes;
+	__u32 cache_hits;
+	__u32 allocated_dquots;
+	__u32 free_dquots;
+	__u32 syncs;
+};
+
+struct v2c_mem_dqblk {
+	unsigned int dqb_ihardlimit;
+	unsigned int dqb_isoftlimit;
+	unsigned int dqb_curinodes;
+	unsigned int dqb_bhardlimit;
+	unsigned int dqb_bsoftlimit;
+	qsize_t dqb_curspace;
+	__kernel_time_t dqb_btime;
+	__kernel_time_t dqb_itime;
+};
+
+struct v2c_mem_dqinfo {
+	unsigned int dqi_bgrace;
+	unsigned int dqi_igrace;
+	unsigned int dqi_flags;
+	unsigned int dqi_blocks;
+	unsigned int dqi_free_blk;
+	unsigned int dqi_free_entry;
+};
+
+struct v2c_dqstats {
+	__u32 lookups;
+	__u32 drops;
+	__u32 reads;
+	__u32 writes;
+	__u32 cache_hits;
+	__u32 allocated_dquots;
+	__u32 free_dquots;
+	__u32 syncs;
+	__u32 version;
+};
+
+#define Q_COMP_QUOTAON  0x0100	/* enable quotas */
+#define Q_COMP_QUOTAOFF 0x0200	/* disable quotas */
+#define Q_COMP_SYNC     0x0600	/* sync disk copy of a filesystems quotas */
+
+#define Q_V1_GETQUOTA 0x0300	/* get limits and usage */
+#define Q_V1_SETQUOTA 0x0400	/* set limits and usage */
+#define Q_V1_SETUSE   0x0500	/* set usage */
+#define Q_V1_SETQLIM  0x0700	/* set limits */
+#define Q_V1_GETSTATS 0x0800	/* get collected stats */
+#define Q_V1_RSQUASH  0x1000	/* set root_squash option */
+
+#define Q_V2_SETQLIM  0x0700	/* set limits */
+#define Q_V2_GETINFO  0x0900	/* get info about quotas - graces, flags... */
+#define Q_V2_SETINFO  0x0A00	/* set info about quotas */
+#define Q_V2_SETGRACE 0x0B00	/* set inode and block grace */
+#define Q_V2_SETFLAGS 0x0C00	/* set flags for quota */
+#define Q_V2_GETQUOTA 0x0D00	/* get limits and usage */
+#define Q_V2_SETQUOTA 0x0E00	/* set limits and usage */
+#define Q_V2_SETUSE   0x0F00	/* set usage */
+#define Q_V2_GETSTATS 0x1100	/* get collected stats */
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/quota.h linux.20pre10-ac2/include/linux/quota.h
--- linux.20pre10/include/linux/quota.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/quota.h	2002-09-18 14:26:33.000000000 +0100
@@ -40,30 +40,22 @@
 #define _LINUX_QUOTA_
 
 #include <linux/errno.h>
+#include <linux/types.h>
 
-/*
- * Convert diskblocks to blocks and the other way around.
- */
-#define dbtob(num) (num << BLOCK_SIZE_BITS)
-#define btodb(num) (num >> BLOCK_SIZE_BITS)
+#define __DQUOT_VERSION__	"dquot_6.5.1"
+#define __DQUOT_NUM_VERSION__	6*10000+5*100+1
 
-/*
- * Convert count of filesystem blocks to diskquota blocks, meant
- * for filesystems where i_blksize != BLOCK_SIZE
- */
-#define fs_to_dq_blocks(num, blksize) (((num) * (blksize)) / BLOCK_SIZE)
+typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
+typedef __u64 qsize_t;          /* Type in which we store sizes */
 
-/*
- * Definitions for disk quotas imposed on the average user
- * (big brother finally hits Linux).
- *
- * The following constants define the amount of time given a user
- * before the soft limits are treated as hard limits (usually resulting
- * in an allocation failure). The timer is started when the user crosses
- * their soft limit, it is reset when they go below their soft limit.
- */
-#define MAX_IQ_TIME  604800	/* (7*24*60*60) 1 week */
-#define MAX_DQ_TIME  604800	/* (7*24*60*60) 1 week */
+/* Size of blocks in which are counted size limits */
+#define QUOTABLOCK_BITS 10
+#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS)
+
+/* Conversion routines from and to quota blocks */
+#define qb2kb(x) ((x) << (QUOTABLOCK_BITS-10))
+#define kb2qb(x) ((x) >> (QUOTABLOCK_BITS-10))
+#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS)
 
 #define MAXQUOTAS 2
 #define USRQUOTA  0		/* element used for user quotas */
@@ -78,9 +70,6 @@
 	"undefined", \
 };
 
-#define QUOTAFILENAME "quota"
-#define QUOTAGROUP "staff"
-
 /*
  * Command definitions for the 'quotactl' system call.
  * The commands are broken into a main command defined below
@@ -91,61 +80,122 @@
 #define SUBCMDSHIFT 8
 #define QCMD(cmd, type)  (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))
 
-#define Q_QUOTAON  0x0100	/* enable quotas */
-#define Q_QUOTAOFF 0x0200	/* disable quotas */
-#define Q_GETQUOTA 0x0300	/* get limits and usage */
-#define Q_SETQUOTA 0x0400	/* set limits and usage */
-#define Q_SETUSE   0x0500	/* set usage */
-#define Q_SYNC     0x0600	/* sync disk copy of a filesystems quotas */
-#define Q_SETQLIM  0x0700	/* set limits */
-#define Q_GETSTATS 0x0800	/* get collected stats */
-#define Q_RSQUASH  0x1000	/* set root_squash option */
-
-/*
- * The following structure defines the format of the disk quota file
- * (as it appears on disk) - the file is an array of these structures
- * indexed by user or group number.
+#define Q_SYNC     0x800001	/* sync disk copy of a filesystems quotas */
+#define Q_QUOTAON  0x800002	/* turn quotas on */
+#define Q_QUOTAOFF 0x800003	/* turn quotas off */
+#define Q_GETFMT   0x800004	/* get quota format used on given filesystem */
+#define Q_GETINFO  0x800005	/* get information about quota files */
+#define Q_SETINFO  0x800006	/* set information about quota files */
+#define Q_GETQUOTA 0x800007	/* get user quota structure */
+#define Q_SETQUOTA 0x800008	/* set user quota structure */
+
+/*
+ * Quota structure used for communication with userspace via quotactl
+ * Following flags are used to specify which fields are valid
  */
-struct dqblk {
+#define QIF_BLIMITS	1
+#define QIF_SPACE	2
+#define QIF_ILIMITS	4
+#define QIF_INODES	8
+#define QIF_BTIME	16
+#define QIF_ITIME	32
+#define QIF_LIMITS	(QIF_BLIMITS | QIF_ILIMITS)
+#define QIF_USAGE	(QIF_SPACE | QIF_INODES)
+#define QIF_TIMES	(QIF_BTIME | QIF_ITIME)
+#define QIF_ALL		(QIF_LIMITS | QIF_USAGE | QIF_TIMES)
+
+struct if_dqblk {
+	__u64 dqb_bhardlimit;
+	__u64 dqb_bsoftlimit;
+	__u64 dqb_curspace;
+	__u64 dqb_ihardlimit;
+	__u64 dqb_isoftlimit;
+	__u64 dqb_curinodes;
+	__u64 dqb_btime;
+	__u64 dqb_itime;
+	__u32 dqb_valid;
+};
+
+/*
+ * Structure used for setting quota information about file via quotactl
+ * Following flags are used to specify which fields are valid
+ */
+#define IIF_BGRACE	1
+#define IIF_IGRACE	2
+#define IIF_FLAGS	4
+#define IIF_ALL		(IIF_BGRACE | IIF_IGRACE | IIF_FLAGS)
+
+struct if_dqinfo {
+	__u64 dqi_bgrace;
+	__u64 dqi_igrace;
+	__u32 dqi_flags;
+	__u32 dqi_valid;
+};
+
+#ifdef __KERNEL__
+
+#include <linux/dqblk_xfs.h>
+#include <linux/dqblk_v1.h>
+#include <linux/dqblk_v2.h>
+
+/*
+ * Data for one user/group kept in memory
+ */
+struct mem_dqblk {
 	__u32 dqb_bhardlimit;	/* absolute limit on disk blks alloc */
 	__u32 dqb_bsoftlimit;	/* preferred limit on disk blks */
-	__u32 dqb_curblocks;	/* current block count */
+	qsize_t dqb_curspace;	/* current used space */
 	__u32 dqb_ihardlimit;	/* absolute limit on allocated inodes */
 	__u32 dqb_isoftlimit;	/* preferred inode limit */
 	__u32 dqb_curinodes;	/* current # allocated inodes */
-	time_t dqb_btime;		/* time limit for excessive disk use */
-	time_t dqb_itime;		/* time limit for excessive inode use */
+	time_t dqb_btime;	/* time limit for excessive disk use */
+	time_t dqb_itime;	/* time limit for excessive inode use */
 };
 
 /*
- * Shorthand notation.
+ * Data for one quotafile kept in memory
  */
-#define	dq_bhardlimit	dq_dqb.dqb_bhardlimit
-#define	dq_bsoftlimit	dq_dqb.dqb_bsoftlimit
-#define	dq_curblocks	dq_dqb.dqb_curblocks
-#define	dq_ihardlimit	dq_dqb.dqb_ihardlimit
-#define	dq_isoftlimit	dq_dqb.dqb_isoftlimit
-#define	dq_curinodes	dq_dqb.dqb_curinodes
-#define	dq_btime	dq_dqb.dqb_btime
-#define	dq_itime	dq_dqb.dqb_itime
+struct quota_format_type;
+
+struct mem_dqinfo {
+	struct quota_format_type *dqi_format;
+	int dqi_flags;
+	unsigned int dqi_bgrace;
+	unsigned int dqi_igrace;
+	union {
+		struct v1_mem_dqinfo v1_i;
+		struct v2_mem_dqinfo v2_i;
+	} u;
+};
+
+#define DQF_MASK 0xffff		/* Mask for format specific flags */
+#define DQF_INFO_DIRTY 0x10000  /* Is info dirty? */
+#define DQF_ANY_DQUOT_DIRTY 0x20000	/* Is any dquot dirty? */
 
-#define dqoff(UID)      ((loff_t)((UID) * sizeof (struct dqblk)))
+extern inline void mark_info_dirty(struct mem_dqinfo *info)
+{
+	info->dqi_flags |= DQF_INFO_DIRTY;
+}
+
+#define info_dirty(info) ((info)->dqi_flags & DQF_INFO_DIRTY)
+
+#define info_any_dirty(info) ((info)->dqi_flags & DQF_INFO_DIRTY ||\
+			      (info)->dqi_flags & DQF_ANY_DQUOT_DIRTY)
+
+#define sb_dqopt(sb) (&(sb)->s_dquot)
 
 struct dqstats {
-	__u32 lookups;
-	__u32 drops;
-	__u32 reads;
-	__u32 writes;
-	__u32 cache_hits;
-	__u32 allocated_dquots;
-	__u32 free_dquots;
-	__u32 syncs;
+	int lookups;
+	int drops;
+	int reads;
+	int writes;
+	int cache_hits;
+	int allocated_dquots;
+	int free_dquots;
+	int syncs;
 };
 
-#ifdef __KERNEL__
-
-extern int nr_dquots, nr_free_dquots;
-extern int dquot_root_squash;
+extern struct dqstats dqstats;
 
 #define NR_DQHASH 43            /* Just an arbitrary number */
 
@@ -162,37 +212,113 @@
 	struct list_head dq_free;	/* Free list element */
 	wait_queue_head_t dq_wait_lock;	/* Pointer to waitqueue on dquot lock */
 	wait_queue_head_t dq_wait_free;	/* Pointer to waitqueue for quota to be unused */
-	int dq_count;			/* Reference count */
+	int dq_count;			/* Use count */
+	int dq_dup_ref;			/* Number of duplicated refences */
 
 	/* fields after this point are cleared when invalidating */
 	struct super_block *dq_sb;	/* superblock this applies to */
 	unsigned int dq_id;		/* ID this applies to (uid, gid) */
 	kdev_t dq_dev;			/* Device this applies to */
+	loff_t dq_off;			/* Offset of dquot on disk */
 	short dq_type;			/* Type of quota */
 	short dq_flags;			/* See DQ_* */
 	unsigned long dq_referenced;	/* Number of times this dquot was 
 					   referenced during its lifetime */
-	struct dqblk dq_dqb;		/* Diskquota usage */
+	struct mem_dqblk dq_dqb;	/* Diskquota usage */
 };
 
 #define NODQUOT (struct dquot *)NULL
 
-/*
- * Flags used for set_dqblk.
- */
-#define SET_QUOTA         0x02
-#define SET_USE           0x04
-#define SET_QLIMIT        0x08
-
 #define QUOTA_OK          0
 #define NO_QUOTA          1
 
+/* Operations which must be implemented by each quota format */
+struct quota_format_ops {
+	int (*check_quota_file)(struct super_block *sb, int type);	/* Detect whether file is in our format */
+	int (*read_file_info)(struct super_block *sb, int type);	/* Read main info about file - called on quotaon() */
+	int (*write_file_info)(struct super_block *sb, int type);	/* Write main info about file */
+	int (*free_file_info)(struct super_block *sb, int type);	/* Called on quotaoff() */
+	int (*read_dqblk)(struct dquot *dquot);		/* Read structure for one user */
+	int (*commit_dqblk)(struct dquot *dquot);	/* Write (or delete) structure for one user */
+};
+
+/* Operations working with dquots */
+struct dquot_operations {
+	void (*initialize) (struct inode *, int);
+	void (*drop) (struct inode *);
+	int (*alloc_space) (struct inode *, qsize_t, int);
+	int (*alloc_inode) (const struct inode *, unsigned long);
+	void (*free_space) (struct inode *, qsize_t);
+	void (*free_inode) (const struct inode *, unsigned long);
+	int (*transfer) (struct inode *, struct iattr *);
+};
+
+/* Operations handling requests from userspace */
+struct quotactl_ops {
+	int (*quota_on)(struct super_block *, int, int, char *);
+	int (*quota_off)(struct super_block *, int);
+	int (*quota_sync)(struct super_block *, int);
+	int (*get_info)(struct super_block *, int, struct if_dqinfo *);
+	int (*set_info)(struct super_block *, int, struct if_dqinfo *);
+	int (*get_dqblk)(struct super_block *, int, qid_t, struct if_dqblk *);
+	int (*set_dqblk)(struct super_block *, int, qid_t, struct if_dqblk *);
+	int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
+	int (*set_xstate)(struct super_block *, unsigned int, int);
+	int (*get_xquota)(struct super_block *, int, qid_t, struct fs_disk_quota *);
+	int (*set_xquota)(struct super_block *, int, qid_t, struct fs_disk_quota *);
+};
+
+struct quota_format_type {
+	int qf_fmt_id;	/* Quota format id */
+	struct quota_format_ops *qf_ops;	/* Operations of format */
+	struct module *qf_owner;		/* Module implementing quota format */
+	struct quota_format_type *qf_next;
+};
+
+#define DQUOT_USR_ENABLED	0x01		/* User diskquotas enabled */
+#define DQUOT_GRP_ENABLED	0x02		/* Group diskquotas enabled */
+
+struct quota_info {
+	unsigned int flags;			/* Flags for diskquotas on this device */
+	struct semaphore dqio_sem;		/* lock device while I/O in progress */
+	struct semaphore dqoff_sem;		/* serialize quota_off() and quota_on() on device */
+	struct file *files[MAXQUOTAS];		/* fp's to quotafiles */
+	struct mem_dqinfo info[MAXQUOTAS];	/* Information for each quota type */
+	struct quota_format_ops *ops[MAXQUOTAS];	/* Operations for each type */
+};
+
+/* Inline would be better but we need to dereference super_block which is not defined yet */
+#define mark_dquot_dirty(dquot) do {\
+	dquot->dq_flags |= DQ_MOD;\
+	sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_flags |= DQF_ANY_DQUOT_DIRTY;\
+} while (0)
+
+#define dquot_dirty(dquot) ((dquot)->dq_flags & DQ_MOD)
+
+static inline int is_enabled(struct quota_info *dqopt, int type)
+{
+	switch (type) {
+		case USRQUOTA:
+			return dqopt->flags & DQUOT_USR_ENABLED;
+		case GRPQUOTA:
+			return dqopt->flags & DQUOT_GRP_ENABLED;
+	}
+	return 0;
+}
+
+#define sb_any_quota_enabled(sb) (is_enabled(sb_dqopt(sb), USRQUOTA) | is_enabled(sb_dqopt(sb), GRPQUOTA))
+
+#define sb_has_quota_enabled(sb, type) (is_enabled(sb_dqopt(sb), type))
+
+int register_quota_format(struct quota_format_type *fmt);
+void unregister_quota_format(struct quota_format_type *fmt);
+
 #else
 
 # /* nodep */ include <sys/cdefs.h>
 
 __BEGIN_DECLS
-long quotactl __P ((int, const char *, int, caddr_t));
+long quotactl __P ((unsigned int, const char *, int, caddr_t));
 __END_DECLS
 
 #endif /* __KERNEL__ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/quotaio_v1.h linux.20pre10-ac2/include/linux/quotaio_v1.h
--- linux.20pre10/include/linux/quotaio_v1.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/linux/quotaio_v1.h	2002-09-18 14:26:34.000000000 +0100
@@ -0,0 +1,33 @@
+#ifndef _LINUX_QUOTAIO_V1_H
+#define _LINUX_QUOTAIO_V1_H
+
+#include <linux/types.h>
+
+/*
+ * The following constants define the amount of time given a user
+ * before the soft limits are treated as hard limits (usually resulting
+ * in an allocation failure). The timer is started when the user crosses
+ * their soft limit, it is reset when they go below their soft limit.
+ */
+#define MAX_IQ_TIME  604800	/* (7*24*60*60) 1 week */
+#define MAX_DQ_TIME  604800	/* (7*24*60*60) 1 week */
+
+/*
+ * The following structure defines the format of the disk quota file
+ * (as it appears on disk) - the file is an array of these structures
+ * indexed by user or group number.
+ */
+struct v1_disk_dqblk {
+	__u32 dqb_bhardlimit;	/* absolute limit on disk blks alloc */
+	__u32 dqb_bsoftlimit;	/* preferred limit on disk blks */
+	__u32 dqb_curblocks;	/* current block count */
+	__u32 dqb_ihardlimit;	/* absolute limit on allocated inodes */
+	__u32 dqb_isoftlimit;	/* preferred inode limit */
+	__u32 dqb_curinodes;	/* current # allocated inodes */
+	time_t dqb_btime;	/* time limit for excessive disk use */
+	time_t dqb_itime;	/* time limit for excessive inode use */
+};
+
+#define v1_dqoff(UID)      ((loff_t)((UID) * sizeof (struct v1_disk_dqblk)))
+
+#endif	/* _LINUX_QUOTAIO_V1_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/quotaio_v2.h linux.20pre10-ac2/include/linux/quotaio_v2.h
--- linux.20pre10/include/linux/quotaio_v2.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/linux/quotaio_v2.h	2002-09-18 14:26:34.000000000 +0100
@@ -0,0 +1,79 @@
+/*
+ *	Definitions of structures for vfsv0 quota format
+ */
+
+#ifndef _LINUX_QUOTAIO_V2_H
+#define _LINUX_QUOTAIO_V2_H
+
+#include <linux/types.h>
+#include <linux/quota.h>
+
+/*
+ * Definitions of magics and versions of current quota files
+ */
+#define V2_INITQMAGICS {\
+	0xd9c01f11,	/* USRQUOTA */\
+	0xd9c01927	/* GRPQUOTA */\
+}
+
+#define V2_INITQVERSIONS {\
+	0,		/* USRQUOTA */\
+	0		/* GRPQUOTA */\
+}
+
+/*
+ * The following structure defines the format of the disk quota file
+ * (as it appears on disk) - the file is a radix tree whose leaves point
+ * to blocks of these structures.
+ */
+struct v2_disk_dqblk {
+	__u32 dqb_id;		/* id this quota applies to */
+	__u32 dqb_ihardlimit;	/* absolute limit on allocated inodes */
+	__u32 dqb_isoftlimit;	/* preferred inode limit */
+	__u32 dqb_curinodes;	/* current # allocated inodes */
+	__u32 dqb_bhardlimit;	/* absolute limit on disk space (in QUOTABLOCK_SIZE) */
+	__u32 dqb_bsoftlimit;	/* preferred limit on disk space (in QUOTABLOCK_SIZE) */
+	__u64 dqb_curspace;	/* current space occupied (in bytes) */
+	__u64 dqb_btime;	/* time limit for excessive disk use */
+	__u64 dqb_itime;	/* time limit for excessive inode use */
+};
+
+/*
+ * Here are header structures as written on disk and their in-memory copies
+ */
+/* First generic header */
+struct v2_disk_dqheader {
+	__u32 dqh_magic;	/* Magic number identifying file */
+	__u32 dqh_version;	/* File version */
+};
+
+/* Header with type and version specific information */
+struct v2_disk_dqinfo {
+	__u32 dqi_bgrace;	/* Time before block soft limit becomes hard limit */
+	__u32 dqi_igrace;	/* Time before inode soft limit becomes hard limit */
+	__u32 dqi_flags;	/* Flags for quotafile (DQF_*) */
+	__u32 dqi_blocks;	/* Number of blocks in file */
+	__u32 dqi_free_blk;	/* Number of first free block in the list */
+	__u32 dqi_free_entry;	/* Number of block with at least one free entry */
+};
+
+/*
+ *  Structure of header of block with quota structures. It is padded to 16 bytes so
+ *  there will be space for exactly 18 quota-entries in a block
+ */
+struct v2_disk_dqdbheader {
+	__u32 dqdh_next_free;	/* Number of next block with free entry */
+	__u32 dqdh_prev_free;	/* Number of previous block with free entry */
+	__u16 dqdh_entries;	/* Number of valid entries in block */
+	__u16 dqdh_pad1;
+	__u32 dqdh_pad2;
+};
+
+#define V2_DQINFOOFF	sizeof(struct v2_disk_dqheader)	/* Offset of info header in file */
+#define V2_DQBLKSIZE_BITS	10
+#define V2_DQBLKSIZE	(1 << V2_DQBLKSIZE_BITS)	/* Size of block with quota structures */
+#define V2_DQTREEOFF	1		/* Offset of tree in file in blocks */
+#define V2_DQTREEDEPTH	4		/* Depth of quota tree */
+#define V2_DQSTRINBLK	((V2_DQBLKSIZE - sizeof(struct v2_disk_dqdbheader)) / sizeof(struct v2_disk_dqblk))	/* Number of entries in one blocks */
+
+#endif /* _LINUX_QUOTAIO_V2_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/quotaops.h linux.20pre10-ac2/include/linux/quotaops.h
--- linux.20pre10/include/linux/quotaops.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/quotaops.h	2002-10-11 00:35:04.000000000 +0100
@@ -20,15 +20,16 @@
 /*
  * declaration of quota_function calls in kernel.
  */
-extern void dquot_initialize(struct inode *inode, short type);
+extern void sync_dquots_dev(kdev_t dev, int type);
+extern void sync_dquots_sb(struct super_block *sb, int type);
+
+extern void dquot_initialize(struct inode *inode, int type);
 extern void dquot_drop(struct inode *inode);
-extern int  quota_off(struct super_block *sb, short type);
-extern int  sync_dquots(kdev_t dev, short type);
 
-extern int  dquot_alloc_block(struct inode *inode, unsigned long number, char prealloc);
+extern int  dquot_alloc_space(struct inode *inode, qsize_t number, int prealloc);
 extern int  dquot_alloc_inode(const struct inode *inode, unsigned long number);
 
-extern void dquot_free_block(struct inode *inode, unsigned long number);
+extern void dquot_free_space(struct inode *inode, qsize_t number);
 extern void dquot_free_inode(const struct inode *inode, unsigned long number);
 
 extern int  dquot_transfer(struct inode *inode, struct iattr *iattr);
@@ -36,11 +37,15 @@
 /*
  * Operations supported for diskquotas.
  */
-#define sb_any_quota_enabled(sb) ((sb)->s_dquot.flags & (DQUOT_USR_ENABLED | DQUOT_GRP_ENABLED))
+extern struct dquot_operations dquot_operations;
+extern struct quotactl_ops vfs_quotactl_ops;
+
+#define sb_dquot_ops (&dquot_operations)
+#define sb_quotactl_ops (&vfs_quotactl_ops)
 
 static __inline__ void DQUOT_INIT(struct inode *inode)
 {
-	if (!inode->i_sb)
+ 	if (!inode->i_sb)
 		out_of_line_bug();
 	lock_kernel();
 	if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode))
@@ -59,50 +64,50 @@
 	unlock_kernel();
 }
 
-static __inline__ int DQUOT_PREALLOC_BLOCK_NODIRTY(struct inode *inode, int nr)
+static __inline__ int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
 {
 	lock_kernel();
 	if (sb_any_quota_enabled(inode->i_sb)) {
-		/* Number of used blocks is updated in alloc_block() */
-		if (inode->i_sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, inode->i_sb->s_blocksize), 1) == NO_QUOTA) {
+		/* Used space is updated in alloc_space() */
+		if (inode->i_sb->dq_op->alloc_space(inode, nr, 1) == NO_QUOTA) {
 			unlock_kernel();
 			return 1;
 		}
 	}
 	else
-		inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9);
+		inode_add_bytes(inode, nr);
 	unlock_kernel();
 	return 0;
 }
 
-static __inline__ int DQUOT_PREALLOC_BLOCK(struct inode *inode, int nr)
+static __inline__ int DQUOT_PREALLOC_SPACE(struct inode *inode, qsize_t nr)
 {
 	int ret;
-        if (!(ret =  DQUOT_PREALLOC_BLOCK_NODIRTY(inode, nr)))
+        if (!(ret =  DQUOT_PREALLOC_SPACE_NODIRTY(inode, nr)))
 		mark_inode_dirty(inode);
 	return ret;
 }
 
-static __inline__ int DQUOT_ALLOC_BLOCK_NODIRTY(struct inode *inode, int nr)
+static __inline__ int DQUOT_ALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
 {
 	lock_kernel();
 	if (sb_any_quota_enabled(inode->i_sb)) {
-		/* Number of used blocks is updated in alloc_block() */
-		if (inode->i_sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, inode->i_sb->s_blocksize), 0) == NO_QUOTA) {
+		/* Used space is updated in alloc_space() */
+		if (inode->i_sb->dq_op->alloc_space(inode, nr, 0) == NO_QUOTA) {
 			unlock_kernel();
 			return 1;
 		}
 	}
 	else
-		inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9);
+		inode_add_bytes(inode, nr);
 	unlock_kernel();
 	return 0;
 }
 
-static __inline__ int DQUOT_ALLOC_BLOCK(struct inode *inode, int nr)
+static __inline__ int DQUOT_ALLOC_SPACE(struct inode *inode, qsize_t nr)
 {
 	int ret;
-	if (!(ret = DQUOT_ALLOC_BLOCK_NODIRTY(inode, nr)))
+	if (!(ret = DQUOT_ALLOC_SPACE_NODIRTY(inode, nr)))
 		mark_inode_dirty(inode);
 	return ret;
 }
@@ -121,19 +126,19 @@
 	return 0;
 }
 
-static __inline__ void DQUOT_FREE_BLOCK_NODIRTY(struct inode *inode, int nr)
+static __inline__ void DQUOT_FREE_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
 {
 	lock_kernel();
 	if (sb_any_quota_enabled(inode->i_sb))
-		inode->i_sb->dq_op->free_block(inode, fs_to_dq_blocks(nr, inode->i_sb->s_blocksize));
+		inode->i_sb->dq_op->free_space(inode, nr);
 	else
-		inode->i_blocks -= nr << (inode->i_sb->s_blocksize_bits - 9);
+		inode_sub_bytes(inode, nr);
 	unlock_kernel();
 }
 
-static __inline__ void DQUOT_FREE_BLOCK(struct inode *inode, int nr)
+static __inline__ void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr)
 {
-	DQUOT_FREE_BLOCK_NODIRTY(inode, nr);
+	DQUOT_FREE_SPACE_NODIRTY(inode, nr);
 	mark_inode_dirty(inode);
 }
 
@@ -159,63 +164,85 @@
 	return 0;
 }
 
-#define DQUOT_SYNC(dev)	sync_dquots(dev, -1)
-#define DQUOT_OFF(sb)	quota_off(sb, -1)
+#define DQUOT_SYNC_DEV(dev)	sync_dquots_dev(dev, -1)
+#define DQUOT_SYNC_SB(sb)	sync_dquots_sb(sb, -1)
+
+static __inline__ int DQUOT_OFF(struct super_block *sb)
+{
+	int ret = -ENOSYS;
+
+	lock_kernel();
+	if (sb->s_qcop && sb->s_qcop->quota_off)
+		ret = sb->s_qcop->quota_off(sb, -1);
+	unlock_kernel();
+	return ret;
+}
 
 #else
 
 /*
  * NO-OP when quota not configured.
  */
+#define sb_dquot_ops				(NULL)
+#define sb_quotactl_ops				(NULL)
 #define DQUOT_INIT(inode)			do { } while(0)
 #define DQUOT_DROP(inode)			do { } while(0)
 #define DQUOT_ALLOC_INODE(inode)		(0)
 #define DQUOT_FREE_INODE(inode)			do { } while(0)
-#define DQUOT_SYNC(dev)				do { } while(0)
+#define DQUOT_SYNC_DEV(dev)			do { } while(0)
+#define DQUOT_SYNC_SB(sb)			do { } while(0)
 #define DQUOT_OFF(sb)				do { } while(0)
 #define DQUOT_TRANSFER(inode, iattr)		(0)
-extern __inline__ int DQUOT_PREALLOC_BLOCK_NODIRTY(struct inode *inode, int nr)
+extern __inline__ int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
 {
 	lock_kernel();
-	inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9);
+	inode_add_bytes(inode, nr);
 	unlock_kernel();
 	return 0;
 }
 
-extern __inline__ int DQUOT_PREALLOC_BLOCK(struct inode *inode, int nr)
+extern __inline__ int DQUOT_PREALLOC_SPACE(struct inode *inode, qsize_t nr)
 {
-	DQUOT_PREALLOC_BLOCK_NODIRTY(inode, nr);
+	DQUOT_PREALLOC_SPACE_NODIRTY(inode, nr);
 	mark_inode_dirty(inode);
 	return 0;
 }
 
-extern __inline__ int DQUOT_ALLOC_BLOCK_NODIRTY(struct inode *inode, int nr)
+extern __inline__ int DQUOT_ALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
 {
 	lock_kernel();
-	inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9);
+	inode_add_bytes(inode, nr);
 	unlock_kernel();
 	return 0;
 }
 
-extern __inline__ int DQUOT_ALLOC_BLOCK(struct inode *inode, int nr)
+extern __inline__ int DQUOT_ALLOC_SPACE(struct inode *inode, qsize_t nr)
 {
-	DQUOT_ALLOC_BLOCK_NODIRTY(inode, nr);
+	DQUOT_ALLOC_SPACE_NODIRTY(inode, nr);
 	mark_inode_dirty(inode);
 	return 0;
 }
 
-extern __inline__ void DQUOT_FREE_BLOCK_NODIRTY(struct inode *inode, int nr)
+extern __inline__ void DQUOT_FREE_SPACE_NODIRTY(struct inode *inode, qsize_t nr)
 {
 	lock_kernel();
-	inode->i_blocks -= nr << (inode->i_sb->s_blocksize_bits - 9);
+	inode_sub_bytes(inode, nr);
 	unlock_kernel();
 }
 
-extern __inline__ void DQUOT_FREE_BLOCK(struct inode *inode, int nr)
+extern __inline__ void DQUOT_FREE_SPACE(struct inode *inode, qsize_t nr)
 {
-	DQUOT_FREE_BLOCK_NODIRTY(inode, nr);
+	DQUOT_FREE_SPACE_NODIRTY(inode, nr);
 	mark_inode_dirty(inode);
 }	
 
 #endif /* CONFIG_QUOTA */
+
+#define DQUOT_PREALLOC_BLOCK_NODIRTY(inode, nr)	DQUOT_PREALLOC_SPACE_NODIRTY(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits)
+#define DQUOT_PREALLOC_BLOCK(inode, nr)	DQUOT_PREALLOC_SPACE(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits)
+#define DQUOT_ALLOC_BLOCK_NODIRTY(inode, nr) DQUOT_ALLOC_SPACE_NODIRTY(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits)
+#define DQUOT_ALLOC_BLOCK(inode, nr) DQUOT_ALLOC_SPACE(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits)
+#define DQUOT_FREE_BLOCK_NODIRTY(inode, nr) DQUOT_FREE_SPACE_NODIRTY(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits)
+#define DQUOT_FREE_BLOCK(inode, nr) DQUOT_FREE_SPACE(inode, ((qsize_t)(nr)) << (inode)->i_sb->s_blocksize_bits)
+
 #endif /* _LINUX_QUOTAOPS_ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/sched.h linux.20pre10-ac2/include/linux/sched.h
--- linux.20pre10/include/linux/sched.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/linux/sched.h	2002-10-11 00:35:04.000000000 +0100
@@ -73,16 +73,16 @@
 #define CT_TO_SECS(x)	((x) / HZ)
 #define CT_TO_USECS(x)	(((x) % HZ) * 1000000/HZ)
 
-extern int nr_running, nr_threads;
+extern int nr_threads;
 extern int last_pid;
+extern unsigned long nr_running(void);
+extern unsigned long nr_uninterruptible(void);
 
 #include <linux/fs.h>
 #include <linux/time.h>
 #include <linux/param.h>
 #include <linux/resource.h>
-#ifdef __KERNEL__
 #include <linux/timer.h>
-#endif
 
 #include <asm/processor.h>
 
@@ -119,12 +119,6 @@
 #define SCHED_FIFO		1
 #define SCHED_RR		2
 
-/*
- * This is an additional bit set when we want to
- * yield the CPU for one re-schedule..
- */
-#define SCHED_YIELD		0x10
-
 struct sched_param {
 	int sched_priority;
 };
@@ -142,17 +136,23 @@
  * a separate lock).
  */
 extern rwlock_t tasklist_lock;
-extern spinlock_t runqueue_lock;
 extern spinlock_t mmlist_lock;
 
+typedef struct task_struct task_t;
+
 extern void sched_init(void);
-extern void init_idle(void);
+extern void init_idle(task_t *idle, int cpu);
+extern int idle_cpu(int cpu);
 extern void show_state(void);
 extern void cpu_init (void);
 extern void trap_init(void);
 extern void update_process_times(int user);
-extern void update_one_process(struct task_struct *p, unsigned long user,
+extern void update_one_process(task_t *p, unsigned long user,
 			       unsigned long system, int cpu);
+extern void scheduler_tick(int user_tick, int system);
+extern void migration_init(void);
+extern unsigned long cache_decay_ticks;
+extern int set_user(uid_t new_ruid, int dumpclear);
 
 #define	MAX_SCHEDULE_TIMEOUT	LONG_MAX
 extern signed long FASTCALL(schedule_timeout(signed long timeout));
@@ -164,6 +164,36 @@
 extern int current_is_keventd(void);
 
 /*
+ * Priority of a process goes from 0..MAX_PRIO-1, valid RT
+ * priority is 0..MAX_RT_PRIO-1, and SCHED_OTHER tasks are
+ * in the range MAX_RT_PRIO..MAX_PRIO-1. Priority values
+ * are inverted: lower p->prio value means higher priority.
+ *
+ * The MAX_RT_USER_PRIO value allows the actual maximum
+ * RT priority to be separate from the value exported to
+ * user-space.  This allows kernel threads to set their
+ * priority to a value higher than any user task. Note:
+ * MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO.
+ */
+
+#define MAX_USER_RT_PRIO	100
+#define MAX_RT_PRIO		MAX_USER_RT_PRIO
+
+#define MAX_PRIO		(MAX_RT_PRIO + 40)
+
+/*
+ * The maximum RT priority is configurable.  If the resulting
+ * bitmap is 160-bits , we can use a hand-coded routine which
+ * is optimal.  Otherwise, we fall back on a generic routine for
+ * finding the first set bit from an arbitrarily-sized bitmap.
+ */
+#if MAX_PRIO < 160 && MAX_PRIO > 127
+#define sched_find_first_bit(map)	_sched_find_first_bit(map)
+#else
+#define sched_find_first_bit(map)	find_first_bit(map, MAX_PRIO)
+#endif
+
+/*
  * The default fd array needs to be at least BITS_PER_LONG,
  * as this is the granularity returned by copy_fdset().
  */
@@ -229,7 +259,7 @@
 	unsigned long rss, total_vm, locked_vm;
 	unsigned long def_flags;
 	unsigned long cpu_vm_mask;
-	unsigned long swap_address;
+	unsigned long rlimit_rss;
 
 	unsigned dumpable:1;
 
@@ -248,6 +278,7 @@
 	mmap_sem:	__RWSEM_INITIALIZER(name.mmap_sem), \
 	page_table_lock: SPIN_LOCK_UNLOCKED, 		\
 	mmlist:		LIST_HEAD_INIT(name.mmlist),	\
+	rlimit_rss:	RLIM_INFINITY,			\
 }
 
 struct signal_struct {
@@ -284,6 +315,8 @@
 extern struct user_struct root_user;
 #define INIT_USER (&root_user)
 
+typedef struct prio_array prio_array_t;
+
 struct task_struct {
 	/*
 	 * offsets of these are hardcoded elsewhere - touch with care
@@ -301,36 +334,25 @@
 
 	int lock_depth;		/* Lock depth */
 
-/*
- * offset 32 begins here on 32-bit platforms. We keep
- * all fields in a single cacheline that are needed for
- * the goodness() loop in schedule().
- */
-	long counter;
-	long nice;
-	unsigned long policy;
-	struct mm_struct *mm;
-	int processor;
 	/*
-	 * cpus_runnable is ~0 if the process is not running on any
-	 * CPU. It's (1 << cpu) if it's running on a CPU. This mask
-	 * is updated under the runqueue lock.
-	 *
-	 * To determine whether a process might run on a CPU, this
-	 * mask is AND-ed with cpus_allowed.
-	 */
-	unsigned long cpus_runnable, cpus_allowed;
-	/*
-	 * (only the 'next' pointer fits into the cacheline, but
-	 * that's just fine.)
+	 * offset 32 begins here on 32-bit platforms.
 	 */
+	unsigned int cpu;
+	int prio, static_prio;
 	struct list_head run_list;
-	unsigned long sleep_time;
+	prio_array_t *array;
+
+	unsigned long sleep_avg;
+	unsigned long sleep_timestamp;
+
+	unsigned long policy;
+	unsigned long cpus_allowed;
+	unsigned int time_slice;
+
+	task_t *next_task, *prev_task;
+
+	struct mm_struct *mm, *active_mm;
 
-	struct task_struct *next_task, *prev_task;
-	struct mm_struct *active_mm;
-	struct list_head local_pages;
-	unsigned int allocation_order, nr_local_pages;
 
 /* task state */
 	struct linux_binfmt *binfmt;
@@ -351,12 +373,12 @@
 	 * older sibling, respectively.  (p->father can be replaced with 
 	 * p->p_pptr->pid)
 	 */
-	struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
+	task_t *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
 	struct list_head thread_group;
 
 	/* PID hash table linkage. */
-	struct task_struct *pidhash_next;
-	struct task_struct **pidhash_pprev;
+	task_t *pidhash_next;
+	task_t **pidhash_pprev;
 
 	wait_queue_head_t wait_chldexit;	/* for wait4() */
 	struct completion *vfork_done;		/* for vfork() */
@@ -454,10 +476,16 @@
  */
 #define _STK_LIM	(8*1024*1024)
 
-#define DEF_COUNTER	(10*HZ/100)	/* 100 ms time slice */
-#define MAX_COUNTER	(20*HZ/100)
-#define DEF_NICE	(0)
+#if CONFIG_SMP
+extern void set_cpus_allowed(task_t *p, unsigned long new_mask);
+#else
+#define set_cpus_allowed(p, new_mask)	do { } while (0)
+#endif
 
+extern void set_user_nice(task_t *p, long nice);
+extern int task_prio(task_t *p);
+extern int task_nice(task_t *p);
+extern int idle_cpu(int cpu);
 extern void yield(void);
 
 /*
@@ -477,14 +505,14 @@
     addr_limit:		KERNEL_DS,					\
     exec_domain:	&default_exec_domain,				\
     lock_depth:		-1,						\
-    counter:		DEF_COUNTER,					\
-    nice:		DEF_NICE,					\
+    prio:		MAX_PRIO-20,					\
+    static_prio:	MAX_PRIO-20,					\
     policy:		SCHED_OTHER,					\
+    cpus_allowed:	-1,						\
     mm:			NULL,						\
     active_mm:		&init_mm,					\
-    cpus_runnable:	-1,						\
-    cpus_allowed:	-1,						\
     run_list:		LIST_HEAD_INIT(tsk.run_list),			\
+    time_slice:		HZ,						\
     next_task:		&tsk,						\
     prev_task:		&tsk,						\
     p_opptr:		&tsk,						\
@@ -518,24 +546,24 @@
 #endif
 
 union task_union {
-	struct task_struct task;
+	task_t task;
 	unsigned long stack[INIT_TASK_SIZE/sizeof(long)];
 };
 
 extern union task_union init_task_union;
 
 extern struct   mm_struct init_mm;
-extern struct task_struct *init_tasks[NR_CPUS];
+extern task_t *init_tasks[NR_CPUS];
 
 /* PID hashing. (shouldnt this be dynamic?) */
 #define PIDHASH_SZ (4096 >> 2)
-extern struct task_struct *pidhash[PIDHASH_SZ];
+extern task_t *pidhash[PIDHASH_SZ];
 
 #define pid_hashfn(x)	((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
 
-static inline void hash_pid(struct task_struct *p)
+static inline void hash_pid(task_t *p)
 {
-	struct task_struct **htable = &pidhash[pid_hashfn(p->pid)];
+	task_t **htable = &pidhash[pid_hashfn(p->pid)];
 
 	if((p->pidhash_next = *htable) != NULL)
 		(*htable)->pidhash_pprev = &p->pidhash_next;
@@ -543,16 +571,16 @@
 	p->pidhash_pprev = htable;
 }
 
-static inline void unhash_pid(struct task_struct *p)
+static inline void unhash_pid(task_t *p)
 {
 	if(p->pidhash_next)
 		p->pidhash_next->pidhash_pprev = p->pidhash_pprev;
 	*p->pidhash_pprev = p->pidhash_next;
 }
 
-static inline struct task_struct *find_task_by_pid(int pid)
+static inline task_t *find_task_by_pid(int pid)
 {
-	struct task_struct *p, **htable = &pidhash[pid_hashfn(pid)];
+	task_t *p, **htable = &pidhash[pid_hashfn(pid)];
 
 	for(p = *htable; p && p->pid != pid; p = p->pidhash_next)
 		;
@@ -560,19 +588,6 @@
 	return p;
 }
 
-#define task_has_cpu(tsk) ((tsk)->cpus_runnable != ~0UL)
-
-static inline void task_set_cpu(struct task_struct *tsk, unsigned int cpu)
-{
-	tsk->processor = cpu;
-	tsk->cpus_runnable = 1UL << cpu;
-}
-
-static inline void task_release_cpu(struct task_struct *tsk)
-{
-	tsk->cpus_runnable = ~0UL;
-}
-
 /* per-UID process charging. */
 extern struct user_struct * alloc_uid(uid_t);
 extern void free_uid(struct user_struct *);
@@ -599,47 +614,51 @@
 extern void FASTCALL(interruptible_sleep_on(wait_queue_head_t *q));
 extern long FASTCALL(interruptible_sleep_on_timeout(wait_queue_head_t *q,
 						    signed long timeout));
-extern int FASTCALL(wake_up_process(struct task_struct * tsk));
+extern int FASTCALL(wake_up_process(task_t * tsk));
+extern void FASTCALL(wake_up_forked_process(task_t * tsk));
+extern void FASTCALL(sched_exit(task_t * p));
 
 #define wake_up(x)			__wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1)
 #define wake_up_nr(x, nr)		__wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, nr)
 #define wake_up_all(x)			__wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 0)
-#define wake_up_sync(x)			__wake_up_sync((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1)
-#define wake_up_sync_nr(x, nr)		__wake_up_sync((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, nr)
 #define wake_up_interruptible(x)	__wake_up((x),TASK_INTERRUPTIBLE, 1)
 #define wake_up_interruptible_nr(x, nr)	__wake_up((x),TASK_INTERRUPTIBLE, nr)
 #define wake_up_interruptible_all(x)	__wake_up((x),TASK_INTERRUPTIBLE, 0)
-#define wake_up_interruptible_sync(x)	__wake_up_sync((x),TASK_INTERRUPTIBLE, 1)
-#define wake_up_interruptible_sync_nr(x, nr) __wake_up_sync((x),TASK_INTERRUPTIBLE,  nr)
+#ifdef CONFIG_SMP
+#define wake_up_interruptible_sync(x)   __wake_up_sync((x),TASK_INTERRUPTIBLE, 1)
+#else
+#define wake_up_interruptible_sync(x)   __wake_up((x),TASK_INTERRUPTIBLE, 1)
+#endif
+
 asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru);
 
 extern int in_group_p(gid_t);
 extern int in_egroup_p(gid_t);
 
 extern void proc_caches_init(void);
-extern void flush_signals(struct task_struct *);
-extern void flush_signal_handlers(struct task_struct *);
+extern void flush_signals(task_t *);
+extern void flush_signal_handlers(task_t *);
 extern void sig_exit(int, int, struct siginfo *);
 extern int dequeue_signal(sigset_t *, siginfo_t *);
 extern void block_all_signals(int (*notifier)(void *priv), void *priv,
 			      sigset_t *mask);
 extern void unblock_all_signals(void);
-extern int send_sig_info(int, struct siginfo *, struct task_struct *);
-extern int force_sig_info(int, struct siginfo *, struct task_struct *);
+extern int send_sig_info(int, struct siginfo *, task_t *);
+extern int force_sig_info(int, struct siginfo *, task_t *);
 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);
-extern void notify_parent(struct task_struct *, int);
-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 void notify_parent(task_t *, int);
+extern void do_notify_parent(task_t *, int);
+extern void force_sig(int, task_t *);
+extern int send_sig(int, task_t *, int);
 extern int kill_pg(pid_t, int, int);
 extern int kill_sl(pid_t, int, int);
 extern int kill_proc(pid_t, int, int);
 extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *);
 extern int do_sigaltstack(const stack_t *, stack_t *, unsigned long);
 
-static inline int signal_pending(struct task_struct *p)
+static inline int signal_pending(task_t *p)
 {
 	return (p->sigpending != 0);
 }
@@ -678,7 +697,7 @@
    This is required every time the blocked sigset_t changes.
    All callers should have t->sigmask_lock.  */
 
-static inline void recalc_sigpending(struct task_struct *t)
+static inline void recalc_sigpending(task_t *t)
 {
 	t->sigpending = has_pending_signals(&t->pending.signal, &t->blocked);
 }
@@ -785,16 +804,17 @@
 extern int expand_fdset(struct files_struct *, int nr);
 extern void free_fdset(fd_set *, int);
 
-extern int  copy_thread(int, unsigned long, unsigned long, unsigned long, struct task_struct *, struct pt_regs *);
+extern int  copy_thread(int, unsigned long, unsigned long, unsigned long, task_t *, struct pt_regs *);
 extern void flush_thread(void);
 extern void exit_thread(void);
 
-extern void exit_mm(struct task_struct *);
-extern void exit_files(struct task_struct *);
-extern void exit_sighand(struct task_struct *);
+extern void exit_mm(task_t *);
+extern void exit_files(task_t *);
+extern void exit_sighand(task_t *);
 
 extern void reparent_to_init(void);
 extern void daemonize(void);
+extern task_t *child_reaper;
 
 extern int do_execve(char *, char **, char **, struct pt_regs *);
 extern int do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long);
@@ -803,6 +823,9 @@
 extern void FASTCALL(add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait));
 extern void FASTCALL(remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait));
 
+extern void wait_task_inactive(task_t * p);
+extern void kick_if_running(task_t * p);
+
 #define __wait_event(wq, condition) 					\
 do {									\
 	wait_queue_t __wait;						\
@@ -884,27 +907,12 @@
 	for (task = next_thread(current) ; task != current ; task = next_thread(task))
 
 #define next_thread(p) \
-	list_entry((p)->thread_group.next, struct task_struct, thread_group)
+	list_entry((p)->thread_group.next, task_t, thread_group)
 
 #define thread_group_leader(p)	(p->pid == p->tgid)
 
-static inline void del_from_runqueue(struct task_struct * p)
-{
-	nr_running--;
-	p->sleep_time = jiffies;
-	list_del(&p->run_list);
-	p->run_list.next = NULL;
-}
-
-static inline int task_on_runqueue(struct task_struct *p)
+static inline void unhash_process(task_t *p)
 {
-	return (p->run_list.next != NULL);
-}
-
-static inline void unhash_process(struct task_struct *p)
-{
-	if (task_on_runqueue(p))
-		out_of_line_bug();
 	write_lock_irq(&tasklist_lock);
 	nr_threads--;
 	unhash_pid(p);
@@ -914,12 +922,12 @@
 }
 
 /* Protects ->fs, ->files, ->mm, and synchronises with wait4().  Nests inside tasklist_lock */
-static inline void task_lock(struct task_struct *p)
+static inline void task_lock(task_t *p)
 {
 	spin_lock(&p->alloc_lock);
 }
 
-static inline void task_unlock(struct task_struct *p)
+static inline void task_unlock(task_t *p)
 {
 	spin_unlock(&p->alloc_lock);
 }
@@ -943,9 +951,29 @@
 	return res;
 }
 
+static inline void set_need_resched(void)
+{
+	current->need_resched = 1;
+}
+
+static inline void clear_need_resched(void)
+{
+	current->need_resched = 0;
+}
+
+static inline void set_tsk_need_resched(struct task_struct *tsk)
+{
+	tsk->need_resched = 1;
+}
+
+static inline void clear_tsk_need_resched(struct task_struct *tsk)
+{
+	tsk->need_resched = 0;
+}
+
 static inline int need_resched(void)
 {
-	return (unlikely(current->need_resched));
+	return unlikely(current->need_resched);
 }
 
 extern void __cond_resched(void);
@@ -955,5 +983,34 @@
 		__cond_resched();
 }
 
+/*
+ * Wrappers for p->cpu access. No-op on UP.
+ */
+#ifdef CONFIG_SMP
+
+static inline unsigned int task_cpu(struct task_struct *p)
+{
+	return p->cpu;
+}
+
+static inline void set_task_cpu(struct task_struct *p, unsigned int cpu)
+{
+	p->cpu = cpu;
+}
+
+#else
+
+static inline unsigned int task_cpu(struct task_struct *p)
+{
+	return 0;
+}
+
+static inline void set_task_cpu(struct task_struct *p, unsigned int cpu)
+{
+}
+
+#endif /* CONFIG_SMP */
+
 #endif /* __KERNEL__ */
+
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/scx200_gpio.h linux.20pre10-ac2/include/linux/scx200_gpio.h
--- linux.20pre10/include/linux/scx200_gpio.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/linux/scx200_gpio.h	2002-10-10 23:56:47.000000000 +0100
@@ -0,0 +1,98 @@
+#include <linux/spinlock.h>
+
+u32 scx200_gpio_configure(int index, u32 set, u32 clear);
+void scx200_gpio_dump(unsigned index);
+
+extern unsigned scx200_gpio_base;
+extern spinlock_t scx200_gpio_lock;
+extern long scx200_gpio_shadow[2];
+
+#define scx200_gpio_present() (scx200_gpio_base!=0)
+
+/* Definitions to make sure I do the same thing in all functions */
+#define __SCx200_GPIO_BANK unsigned bank = index>>5
+#define __SCx200_GPIO_IOADDR unsigned short ioaddr = scx200_gpio_base+0x10*bank
+#define __SCx200_GPIO_SHADOW long *shadow = scx200_gpio_shadow+bank
+#define __SCx200_GPIO_INDEX index &= 31
+
+#define __SCx200_GPIO_OUT __asm__ __volatile__("outsl":"=mS" (shadow):"d" (ioaddr), "0" (shadow))
+
+/* returns the value of the GPIO pin */
+
+static inline int scx200_gpio_get(int index) {
+	__SCx200_GPIO_BANK;
+	__SCx200_GPIO_IOADDR + 0x04;
+	__SCx200_GPIO_INDEX;
+		
+	return (inl(ioaddr) & (1<<index)) ? 1 : 0;
+}
+
+/* return the value driven on the GPIO signal (the value that will be
+   driven if the GPIO is configured as an output, it might not be the
+   state of the GPIO right now if the GPIO is configured as an input) */
+
+static inline int scx200_gpio_current(int index) {
+        __SCx200_GPIO_BANK;
+	__SCx200_GPIO_INDEX;
+		
+	return (scx200_gpio_shadow[bank] & (1<<index)) ? 1 : 0;
+}
+
+/* drive the GPIO signal high */
+
+static inline void scx200_gpio_set_high(int index) {
+	__SCx200_GPIO_BANK;
+	__SCx200_GPIO_IOADDR;
+	__SCx200_GPIO_SHADOW;
+	__SCx200_GPIO_INDEX;
+	set_bit(index, shadow);
+	__SCx200_GPIO_OUT;
+}
+
+/* drive the GPIO signal low */
+
+static inline void scx200_gpio_set_low(int index) {
+	__SCx200_GPIO_BANK;
+	__SCx200_GPIO_IOADDR;
+	__SCx200_GPIO_SHADOW;
+	__SCx200_GPIO_INDEX;
+	clear_bit(index, shadow);
+	__SCx200_GPIO_OUT;
+}
+
+/* drive the GPIO signal to state */
+
+static inline void scx200_gpio_set(int index, int state) {
+	__SCx200_GPIO_BANK;
+	__SCx200_GPIO_IOADDR;
+	__SCx200_GPIO_SHADOW;
+	__SCx200_GPIO_INDEX;
+	if (state)
+		set_bit(index, shadow);
+	else
+		clear_bit(index, shadow);
+	__SCx200_GPIO_OUT;
+}
+
+/* toggle the GPIO signal */
+static inline void scx200_gpio_change(int index) {
+	__SCx200_GPIO_BANK;
+	__SCx200_GPIO_IOADDR;
+	__SCx200_GPIO_SHADOW;
+	__SCx200_GPIO_INDEX;
+	change_bit(index, shadow);
+	__SCx200_GPIO_OUT;
+}
+
+#undef __SCx200_GPIO_BANK
+#undef __SCx200_GPIO_IOADDR
+#undef __SCx200_GPIO_SHADOW
+#undef __SCx200_GPIO_INDEX
+#undef __SCx200_GPIO_OUT
+
+/*
+    Local variables:
+        compile-command: "make -C ../.. bzImage modules"
+        c-basic-offset: 8
+    End:
+*/
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/scx200.h linux.20pre10-ac2/include/linux/scx200.h
--- linux.20pre10/include/linux/scx200.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/linux/scx200.h	2002-10-10 23:56:47.000000000 +0100
@@ -0,0 +1,56 @@
+/* linux/include/linux/scx200.h
+
+   Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+
+   Defines for the National Semiconductor SCx200 Processors
+*/
+
+/* Interesting stuff for the National Semiconductor SCx200 CPU */
+
+/* F0 PCI Header/Bridge Configuration Registers */
+#define SCx200_DOCCS_BASE 0x78	/* DOCCS Base Address Register */
+#define SCx200_DOCCS_CTRL 0x7c	/* DOCCS Control Register */
+
+/* GPIO Register Block */
+#define SCx200_GPIO_SIZE 0x2c	/* Size of GPIO register block */
+
+/* General Configuration Block */
+#define SCx200_CB_BASE 0x9000	/* Base fixed at 0x9000 according to errata */
+
+/* Watchdog Timer */
+#define SCx200_WDT_OFFSET 0x00	/* offset within configuration block */
+#define SCx200_WDT_SIZE 0x05	/* size */
+
+#define SCx200_WDT_WDTO 0x00	/* Time-Out Register */
+#define SCx200_WDT_WDCNFG 0x02	/* Configuration Register */
+#define SCx200_WDT_WDSTS 0x04	/* Status Register */
+#define SCx200_WDT_WDSTS_WDOVF (1<<0) /* Overflow bit */
+
+/* High Resolution Timer */
+#define SCx200_TIMER_OFFSET 0x08
+#define SCx200_TIMER_SIZE 0x05
+
+/* Clock Generators */
+#define SCx200_CLOCKGEN_OFFSET 0x10
+#define SCx200_CLOCKGEN_SIZE 0x10
+
+/* Pin Multiplexing and Miscellaneous Configuration Registers */
+#define SCx200_MISC_OFFSET 0x30
+#define SCx200_MISC_SIZE 0x10
+
+#define SCx200_PMR 0x30		/* Pin Multiplexing Register */
+#define SCx200_MCR 0x34		/* Miscellaneous Configuration Register */
+#define SCx200_INTSEL 0x38	/* Interrupt Selection Register */
+#define SCx200_IID 0x3c		/* IA On a Chip Identification Number Reg */
+#define SCx200_REV 0x3d		/* Revision Register */
+#define SCx200_CBA 0x3e		/* Configuration Base Address Register */
+
+/* Verify that the configuration block really is there */
+#define scx200_cb_probe(base) (inw((base) + SCx200_CBA) == (base))
+
+/*
+    Local variables:
+        compile-command: "make -C ../.. bzImage modules"
+        c-basic-offset: 8
+    End:
+*/
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/serialP.h linux.20pre10-ac2/include/linux/serialP.h
--- linux.20pre10/include/linux/serialP.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/serialP.h	2002-10-09 22:15:47.000000000 +0100
@@ -83,6 +83,7 @@
 	long			pgrp; /* pgrp of opening process */
  	struct circ_buf		xmit;
  	spinlock_t		xmit_lock;
+ 	spinlock_t		irq_spinlock;
 	u8			*iomem_base;
 	u16			iomem_reg_shift;
 	int			io_type;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/sisfb.h linux.20pre10-ac2/include/linux/sisfb.h
--- linux.20pre10/include/linux/sisfb.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/linux/sisfb.h	2002-10-11 00:17:46.000000000 +0100
@@ -1,6 +1,11 @@
 #ifndef _LINUX_SISFB
 #define _LINUX_SISFB
 
+#include <linux/spinlock.h>
+
+#include <asm/ioctl.h>
+#include <asm/types.h>
+
 #define DISPTYPE_CRT1       0x00000008L
 #define DISPTYPE_CRT2       0x00000004L
 #define DISPTYPE_LCD        0x00000002L
@@ -20,7 +25,7 @@
 #define HASVB_303       	0x40
 #define HASVB_CHRONTEL  	0x80
 
-/* Never change the order of the following enum */
+/* TW: *Never* change the order of the following enum */
 typedef enum _SIS_CHIP_TYPE {
 	SIS_VGALegacy = 0,
 	SIS_300,
@@ -38,6 +43,12 @@
 	MAX_SIS_CHIP
 } SIS_CHIP_TYPE;
 
+typedef enum _VGA_ENGINE {
+	UNKNOWN_VGA = 0,
+	SIS_300_VGA,
+	SIS_315_VGA,
+} VGA_ENGINE;
+
 typedef enum _TVTYPE {
 	TVMODE_NTSC = 0,
 	TVMODE_PAL,
@@ -83,22 +94,25 @@
 };
 
 struct video_info {
-	int    chip_id;
+	int           chip_id;
 	unsigned int  video_size;
 	unsigned long video_base;
-	char  *video_vbase;
+	char  *       video_vbase;
 	unsigned long mmio_base;
-	char  *mmio_vbase; 
+	char  *       mmio_vbase;
 	unsigned long vga_base;
 	unsigned long mtrr;
+	unsigned long heapstart;
 
 	int    video_bpp;
+	int    video_cmap_len;
 	int    video_width;
 	int    video_height;
 	int    video_vwidth;
 	int    video_vheight;
 	int    org_x;
 	int    org_y;
+	int    video_linelength;
 	unsigned int refresh_rate;
 
 	unsigned long disp_state;
@@ -109,9 +123,46 @@
 	SIS_CHIP_TYPE chip;
 	unsigned char revision_id;
 
+        unsigned short DstColor;		/* TW: For 2d acceleration */
+	unsigned long  SiS310_AccelDepth;
+	unsigned long  CommandReg;
+
+	spinlock_t     lockaccel;
+
 	char reserved[256];
 };
 
+
+/* TW: Addtional IOCTL for communication sisfb <> X driver                 */
+/*     If changing this, vgatypes.h must also be changed (for X driver)    */
+
+/* TW: ioctl for identifying and giving some info (esp. memory heap start) */
+#define SISFB_GET_INFO	  _IOR('n',0xF8,sizeof(__u32))
+
+/* TW: Structure argument for SISFB_GET_INFO ioctl  */
+typedef struct _SISFB_INFO sisfb_info, *psisfb_info;
+
+struct _SISFB_INFO {
+	unsigned long sisfb_id;         /* for identifying sisfb */
+#ifndef SISFB_ID
+#define SISFB_ID	  0x53495346    /* Identify myself with 'SISF' */
+#endif
+ 	int    chip_id;			/* PCI ID of detected chip */
+	int    memory;			/* video memory in KB which sisfb manages */
+	int    heapstart;               /* heap start (= sisfb "mem" argument) in KB */
+	unsigned char fbvidmode;	/* current sisfb mode */
+	
+	unsigned char sisfb_version;
+	unsigned char sisfb_revision;
+	unsigned char sisfb_patchlevel;
+
+	unsigned char sisfb_caps;	/* Sisfb capabilities */
+
+	int    sisfb_tqlen;		/* turbo queue length (in KB) */
+
+	char reserved[249]; 		/* for future use */
+};
+
 #ifdef __KERNEL__
 extern struct video_info ivideo;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/smp_balance.h linux.20pre10-ac2/include/linux/smp_balance.h
--- linux.20pre10/include/linux/smp_balance.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/linux/smp_balance.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,10 @@
+#ifndef _LINUX_SMP_BALANCE_H
+#define _LINUX_SMP_BALANCE_H
+
+#ifdef ARCH_HAS_SMP_BALANCE
+#include <asm/smp_balance.h>
+#else
+#define arch_load_balance(x,y)		0
+#endif
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/smp.h linux.20pre10-ac2/include/linux/smp.h
--- linux.20pre10/include/linux/smp.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/smp.h	2002-10-09 22:15:47.000000000 +0100
@@ -84,8 +84,16 @@
 #define kernel_lock()
 #define cpu_logical_map(cpu)			0
 #define cpu_number_map(cpu)			0
+#define cpu_online(cpu)				({ cpu; 1; })
 #define smp_call_function(func,info,retry,wait)	({ 0; })
 #define cpu_online_map				1
-
+static inline void smp_send_reschedule(int cpu) { }
+static inline void smp_send_reschedule_all(void) { }
 #endif
+
+/*
+ * Common definitions:
+ */
+#define cpu()					smp_processor_id()
+
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/swap.h linux.20pre10-ac2/include/linux/swap.h
--- linux.20pre10/include/linux/swap.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/linux/swap.h	2002-10-09 21:52:07.000000000 +0100
@@ -86,13 +86,12 @@
 extern unsigned int nr_free_pages(void);
 extern unsigned int nr_free_buffer_pages(void);
 extern int nr_active_pages;
-extern int nr_inactive_pages;
+extern int nr_inactive_dirty_pages;
+extern int nr_inactive_clean_pages;
 extern atomic_t page_cache_size;
 extern atomic_t buffermem_pages;
-
 extern spinlock_cacheline_t pagecache_lock_cacheline;
 #define pagecache_lock (pagecache_lock_cacheline.lock)
-
 extern void __remove_inode_page(struct page *);
 
 /* Incomplete types for prototype declarations: */
@@ -102,32 +101,50 @@
 
 struct zone_t;
 
+/* linux/mm/rmap.c */
+extern int FASTCALL(page_referenced(struct page *));
+extern void FASTCALL(page_add_rmap(struct page *, pte_t *));
+extern void FASTCALL(page_remove_rmap(struct page *, pte_t *));
+extern int FASTCALL(try_to_unmap(struct page *));
+extern int FASTCALL(page_over_rsslimit(struct page *));
+
+/* return values of try_to_unmap */
+#define	SWAP_SUCCESS	0
+#define	SWAP_AGAIN	1
+#define	SWAP_FAIL	2
+#define	SWAP_ERROR	3
+
 /* linux/mm/swap.c */
 extern void FASTCALL(lru_cache_add(struct page *));
 extern void FASTCALL(__lru_cache_del(struct page *));
 extern void FASTCALL(lru_cache_del(struct page *));
 
 extern void FASTCALL(activate_page(struct page *));
+extern void FASTCALL(activate_page_nolock(struct page *));
+extern void FASTCALL(deactivate_page(struct page *));
+extern void FASTCALL(deactivate_page_nolock(struct page *));
+extern void FASTCALL(drop_page(struct page *));
 
 extern void swap_setup(void);
 
 /* linux/mm/vmscan.c */
 extern wait_queue_head_t kswapd_wait;
-extern int FASTCALL(try_to_free_pages_zone(zone_t *, unsigned int));
-extern int FASTCALL(try_to_free_pages(unsigned int));
+extern struct page * FASTCALL(reclaim_page(zone_t *));
+extern int FASTCALL(try_to_free_pages(unsigned int gfp_mask));
+extern void wakeup_kswapd(unsigned int);
+extern void rss_free_pages(unsigned int);
 
 /* linux/mm/page_io.c */
 extern void rw_swap_page(int, struct page *);
 extern void rw_swap_page_nolock(int, swp_entry_t, char *);
 
-/* linux/mm/page_alloc.c */
-
 /* linux/mm/swap_state.c */
 #define SWAP_CACHE_INFO
 #ifdef SWAP_CACHE_INFO
 extern void show_swap_cache_info(void);
 #endif
 extern int add_to_swap_cache(struct page *, swp_entry_t);
+extern int add_to_swap(struct page *);
 extern void __delete_from_swap_cache(struct page *page);
 extern void delete_from_swap_cache(struct page *page);
 extern void free_page_and_swap_cache(struct page *page);
@@ -165,43 +182,26 @@
 extern void FASTCALL(mark_page_accessed(struct page *));
 
 /*
+ * Page aging defines. These seem to work great in FreeBSD,
+ * no need to reinvent the wheel.
+ */
+#define PAGE_AGE_START 5
+#define PAGE_AGE_ADV 3
+#define PAGE_AGE_DECL 1
+#define PAGE_AGE_MAX 64
+
+/*
  * List add/del helper macros. These must be called
  * with the pagemap_lru_lock held!
  */
 #define DEBUG_LRU_PAGE(page)			\
 do {						\
-	if (!PageLRU(page))			\
-		BUG();				\
 	if (PageActive(page))			\
 		BUG();				\
-} while (0)
-
-#define add_page_to_active_list(page)		\
-do {						\
-	DEBUG_LRU_PAGE(page);			\
-	SetPageActive(page);			\
-	list_add(&(page)->lru, &active_list);	\
-	nr_active_pages++;			\
-} while (0)
-
-#define add_page_to_inactive_list(page)		\
-do {						\
-	DEBUG_LRU_PAGE(page);			\
-	list_add(&(page)->lru, &inactive_list);	\
-	nr_inactive_pages++;			\
-} while (0)
-
-#define del_page_from_active_list(page)		\
-do {						\
-	list_del(&(page)->lru);			\
-	ClearPageActive(page);			\
-	nr_active_pages--;			\
-} while (0)
-
-#define del_page_from_inactive_list(page)	\
-do {						\
-	list_del(&(page)->lru);			\
-	nr_inactive_pages--;			\
+	if (PageInactiveDirty(page))		\
+		BUG();				\
+	if (PageInactiveClean(page))		\
+		BUG();				\
 } while (0)
 
 extern spinlock_t swaplock;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/sysctl.h linux.20pre10-ac2/include/linux/sysctl.h
--- linux.20pre10/include/linux/sysctl.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/linux/sysctl.h	2002-10-09 22:15:47.000000000 +0100
@@ -124,6 +124,7 @@
 	KERN_CORE_USES_PID=52,		/* int: use core or core.%pid */
 	KERN_TAINTED=53,	/* int: various kernel tainted flags */
 	KERN_CADPID=54,		/* int: PID of the process to notify on CAD */
+ 	KERN_CORE_PATTERN=55,	/* string: pattern for core-files */
 };
 
 
@@ -536,7 +537,7 @@
 	FS_STATINODE=2,
 	FS_MAXINODE=3,	/* int:maximum number of inodes that can be allocated */
 	FS_NRDQUOT=4,	/* int:current number of allocated dquots */
-	FS_MAXDQUOT=5,	/* int:maximum number of dquots that can be allocated */
+	/* was FS_MAXDQUOT */
 	FS_NRFILE=6,	/* int:current number of allocated filedescriptors */
 	FS_MAXFILE=7,	/* int:maximum number of filedescriptors that can be allocated */
 	FS_DENTRY=8,
@@ -547,6 +548,19 @@
 	FS_LEASES=13,	/* int: leases enabled */
 	FS_DIR_NOTIFY=14,	/* int: directory notification enabled */
 	FS_LEASE_TIME=15,	/* int: maximum time to wait for a lease break */
+	FS_DQSTATS=16,	/* dir: disc quota usage statistics */
+};
+
+/* /proc/sys/fs/quota/ */
+enum {
+	FS_DQ_LOOKUPS = 1,
+	FS_DQ_DROPS = 2,
+	FS_DQ_READS = 3,
+	FS_DQ_WRITES = 4,
+	FS_DQ_CACHE_HITS = 5,
+	FS_DQ_ALLOCATED = 6,
+	FS_DQ_FREE = 7,
+	FS_DQ_SYNCS = 8,
 };
 
 /* CTL_DEBUG names: */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/usbdevice_fs.h linux.20pre10-ac2/include/linux/usbdevice_fs.h
--- linux.20pre10/include/linux/usbdevice_fs.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/linux/usbdevice_fs.h	2002-10-09 22:15:47.000000000 +0100
@@ -142,6 +142,8 @@
 #define USBDEVFS_HUB_PORTINFO      _IOR('U', 19, struct usbdevfs_hub_portinfo)
 #define USBDEVFS_RESET             _IO('U', 20)
 #define USBDEVFS_CLEAR_HALT        _IOR('U', 21, unsigned int)
+#define USBDEVFS_DISCONNECT        _IO('U', 22)
+#define USBDEVFS_CONNECT           _IO('U', 23)
 
 /* --------------------------------------------------------------------- */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/usb.h linux.20pre10-ac2/include/linux/usb.h
--- linux.20pre10/include/linux/usb.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/linux/usb.h	2002-10-11 00:35:04.000000000 +0100
@@ -865,6 +865,7 @@
 	struct usb_device *children[USB_MAXCHILDREN];
 };
 
+extern int usb_ifnum_to_ifpos(struct usb_device *dev, unsigned ifnum);
 extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum);
 extern struct usb_endpoint_descriptor *usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum);
 
@@ -873,6 +874,7 @@
 extern void usb_scan_devices(void);
 
 /* used these for multi-interface device registration */
+extern int usb_find_interface_driver_for_ifnum(struct usb_device *dev, unsigned ifnum);
 extern void usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void* priv);
 extern int usb_interface_claimed(struct usb_interface *iface);
 extern void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/vmalloc.h linux.20pre10-ac2/include/linux/vmalloc.h
--- linux.20pre10/include/linux/vmalloc.h	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/include/linux/vmalloc.h	2002-10-11 00:35:04.000000000 +0100
@@ -26,6 +26,7 @@
 extern void vmfree_area_pages(unsigned long address, unsigned long size);
 extern int vmalloc_area_pages(unsigned long address, unsigned long size,
                               int gfp_mask, pgprot_t prot);
+extern void *vcalloc(unsigned long nmemb, unsigned long elem_size);
 
 /*
  *	Allocate any pages
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/linux/wait.h linux.20pre10-ac2/include/linux/wait.h
--- linux.20pre10/include/linux/wait.h	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/include/linux/wait.h	2002-10-09 22:15:47.000000000 +0100
@@ -58,6 +58,7 @@
 # define wq_read_unlock read_unlock
 # define wq_write_lock_irq write_lock_irq
 # define wq_write_lock_irqsave write_lock_irqsave
+# define wq_write_unlock_irq write_unlock_irq
 # define wq_write_unlock_irqrestore write_unlock_irqrestore
 # define wq_write_unlock write_unlock
 #else
@@ -70,6 +71,7 @@
 # define wq_read_unlock_irqrestore spin_unlock_irqrestore
 # define wq_write_lock_irq spin_lock_irq
 # define wq_write_lock_irqsave spin_lock_irqsave
+# define wq_write_unlock_irq spin_unlock_irq
 # define wq_write_unlock_irqrestore spin_unlock_irqrestore
 # define wq_write_unlock spin_unlock
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/net/datalink.h linux.20pre10-ac2/include/net/datalink.h
--- linux.20pre10/include/net/datalink.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/net/datalink.h	2002-08-06 15:41:52.000000000 +0100
@@ -2,15 +2,24 @@
 #define _NET_INET_DATALINK_H_
 
 struct datalink_proto {
-	unsigned short	type_len;
-	unsigned char	type[8];
-	const char	*string_name;
-	unsigned short	header_length;
-	int	(*rcvfunc)(struct sk_buff *, struct net_device *, 
-				struct packet_type *);
-	void	(*datalink_header)(struct datalink_proto *, struct sk_buff *,
-					unsigned char *);
-	struct datalink_proto	*next;
+        unsigned short  type_len;
+        unsigned char   type[8];
+        const char      *string_name;
+
+        union {
+                struct llc_pinfo *llc;
+        } ll_pinfo;
+
+	struct llc_sc_info *llc_sc;
+	struct sock *sock;
+
+        unsigned short  header_length;
+
+        int     (*rcvfunc)(struct sk_buff *, struct net_device *,
+                                struct packet_type *);
+        void    (*datalink_header)(struct datalink_proto *, struct sk_buff *,
+                                        unsigned char *);
+        struct datalink_proto   *next;
 };
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/net/llc_actn.h linux.20pre10-ac2/include/net/llc_actn.h
--- linux.20pre10/include/net/llc_actn.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/net/llc_actn.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,48 @@
+#ifndef LLC_ACTN_H
+#define LLC_ACTN_H
+/*
+ * Copyright (c) 1997 by Procom Technology,Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+/* Station component state transition actions */
+#define LLC_STATION_AC_START_ACK_TMR		1
+#define LLC_STATION_AC_SET_RETRY_CNT_0		2
+#define LLC_STATION_AC_INC_RETRY_CNT_BY_1	3
+#define LLC_STATION_AC_SET_XID_R_CNT_0		4
+#define LLC_STATION_AC_INC_XID_R_CNT_BY_1	5
+#define LLC_STATION_AC_SEND_NULL_DSAP_XID_C	6
+#define LLC_STATION_AC_SEND_XID_R		7
+#define LLC_STATION_AC_SEND_TEST_R		8
+#define LLC_STATION_AC_REPORT_STATUS		9
+
+/* All station state event action functions look like this */
+typedef int (*llc_station_action_t)(struct llc_station *station,
+				    struct llc_station_state_ev *ev);
+extern int llc_station_ac_start_ack_timer(struct llc_station *station,
+					  struct llc_station_state_ev *ev);
+extern int llc_station_ac_set_retry_cnt_0(struct llc_station *station,
+					  struct llc_station_state_ev *ev);
+extern int llc_station_ac_inc_retry_cnt_by_1(struct llc_station *station,
+					     struct llc_station_state_ev *ev);
+extern int llc_station_ac_set_xid_r_cnt_0(struct llc_station *station,
+					  struct llc_station_state_ev *ev);
+extern int llc_station_ac_inc_xid_r_cnt_by_1(struct llc_station *station,
+					     struct llc_station_state_ev *ev);
+extern int llc_station_ac_send_null_dsap_xid_c(struct llc_station *station,
+					       struct llc_station_state_ev *ev);
+extern int llc_station_ac_send_xid_r(struct llc_station *station,
+				     struct llc_station_state_ev *ev);
+extern int llc_station_ac_send_test_r(struct llc_station *station,
+				      struct llc_station_state_ev *ev);
+extern int llc_station_ac_report_status(struct llc_station *station,
+					struct llc_station_state_ev *ev);
+extern int llc_station_ac_report_status(struct llc_station *station,
+					struct llc_station_state_ev *ev);
+#endif /* LLC_ACTN_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/net/llc_c_ac.h linux.20pre10-ac2/include/net/llc_c_ac.h
--- linux.20pre10/include/net/llc_c_ac.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/net/llc_c_ac.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,254 @@
+#ifndef LLC_C_AC_H
+#define LLC_C_AC_H
+/*
+ * Copyright (c) 1997 by Procom Technology,Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+/* Connection component state transition actions */
+/*
+ * Connection state transition actions
+ * (Fb = F bit; Pb = P bit; Xb = X bit)
+ */
+#define LLC_CONN_AC_CLR_REMOTE_BUSY			 1
+#define LLC_CONN_AC_CONN_IND				 2
+#define LLC_CONN_AC_CONN_CONFIRM			 3
+#define LLC_CONN_AC_DATA_IND				 4
+#define LLC_CONN_AC_DISC_IND				 5
+#define LLC_CONN_AC_RESET_IND				 6
+#define LLC_CONN_AC_RESET_CONFIRM			 7
+#define LLC_CONN_AC_REPORT_STATUS			 8
+#define LLC_CONN_AC_CLR_REMOTE_BUSY_IF_Fb_EQ_1		 9
+#define LLC_CONN_AC_STOP_REJ_TMR_IF_DATA_FLAG_EQ_2	10
+#define LLC_CONN_AC_SEND_DISC_CMD_Pb_SET_X		11
+#define LLC_CONN_AC_SEND_DM_RSP_Fb_SET_Pb		12
+#define LLC_CONN_AC_SEND_DM_RSP_Fb_SET_1		13
+#define LLC_CONN_AC_SEND_DM_RSP_Fb_SET_F_FLAG		14
+#define LLC_CONN_AC_SEND_FRMR_RSP_Fb_SET_X		15
+#define LLC_CONN_AC_RESEND_FRMR_RSP_Fb_SET_0		16
+#define LLC_CONN_AC_RESEND_FRMR_RSP_Fb_SET_Pb		17
+#define LLC_CONN_AC_SEND_I_CMD_Pb_SET_1			18
+#define LLC_CONN_AC_RESEND_I_CMD_Pb_SET_1		19
+#define LLC_CONN_AC_RESEND_I_CMD_Pb_SET_1_OR_SEND_RR	20
+#define LLC_CONN_AC_SEND_I_XXX_Xb_SET_0			21
+#define LLC_CONN_AC_RESEND_I_XXX_Xb_SET_0		22
+#define LLC_CONN_AC_RESEND_I_XXX_Xb_SET_0_OR_SEND_RR	23
+#define LLC_CONN_AC_RESEND_I_RSP_Fb_SET_1		24
+#define LLC_CONN_AC_SEND_REJ_CMD_Pb_SET_1		25
+#define LLC_CONN_AC_SEND_REJ_RSP_Fb_SET_1		26
+#define LLC_CONN_AC_SEND_REJ_XXX_Xb_SET_0		27
+#define LLC_CONN_AC_SEND_RNR_CMD_Pb_SET_1		28
+#define LLC_CONN_AC_SEND_RNR_RSP_Fb_SET_1		29
+#define LLC_CONN_AC_SEND_RNR_XXX_Xb_SET_0		30
+#define LLC_CONN_AC_SET_REMOTE_BUSY			31
+#define LLC_CONN_AC_OPTIONAL_SEND_RNR_XXX_Xb_SET_0	32
+#define LLC_CONN_AC_SEND_RR_CMD_Pb_SET_1		33
+#define LLC_CONN_AC_SEND_ACK_CMD_Pb_SET_1		34
+#define LLC_CONN_AC_SEND_RR_RSP_Fb_SET_1		35
+#define LLC_CONN_AC_SEND_ACK_RSP_Fb_SET_1		36
+#define LLC_CONN_AC_SEND_RR_XXX_Xb_SET_0		37
+#define LLC_CONN_AC_SEND_ACK_XXX_Xb_SET_0		38
+#define LLC_CONN_AC_SEND_SABME_CMD_Pb_SET_X		39
+#define LLC_CONN_AC_SEND_UA_RSP_Fb_SET_Pb		40
+#define LLC_CONN_AC_SEND_UA_RSP_Fb_SET_F_FLAG		41
+#define LLC_CONN_AC_S_FLAG_SET_0			42
+#define LLC_CONN_AC_S_FLAG_SET_1			43
+#define LLC_CONN_AC_START_P_TMR				44
+#define LLC_CONN_AC_START_ACK_TMR			45
+#define LLC_CONN_AC_START_REJ_TMR			46
+#define LLC_CONN_AC_START_ACK_TMR_IF_NOT_RUNNING	47
+#define LLC_CONN_AC_STOP_ACK_TMR			48
+#define LLC_CONN_AC_STOP_P_TMR				49
+#define LLC_CONN_AC_STOP_REJ_TMR			50
+#define LLC_CONN_AC_STOP_ALL_TMRS			51
+#define LLC_CONN_AC_STOP_OTHER_TMRS			52
+#define LLC_CONN_AC_UPDATE_Nr_RECEIVED			53
+#define LLC_CONN_AC_UPDATE_P_FLAG			54
+#define LLC_CONN_AC_DATA_FLAG_SET_2			55
+#define LLC_CONN_AC_DATA_FLAG_SET_0			56
+#define LLC_CONN_AC_DATA_FLAG_SET_1			57
+#define LLC_CONN_AC_DATA_FLAG_SET_1_IF_DATA_FLAG_EQ_0	58
+#define LLC_CONN_AC_P_FLAG_SET_0			59
+#define LLC_CONN_AC_P_FLAG_SET_P			60
+#define LLC_CONN_AC_REMOTE_BUSY_SET_0			61
+#define LLC_CONN_AC_RETRY_CNT_SET_0			62
+#define LLC_CONN_AC_RETRY_CNT_INC_BY_1			63
+#define LLC_CONN_AC_Vr_SET_0				64
+#define LLC_CONN_AC_Vr_INC_BY_1				65
+#define LLC_CONN_AC_Vs_SET_0				66
+#define LLC_CONN_AC_Vs_SET_Nr				67
+#define LLC_CONN_AC_F_FLAG_SET_P			68
+#define LLC_CONN_AC_STOP_SENDACK_TMR			70
+#define LLC_CONN_AC_START_SENDACK_TMR_IF_NOT_RUNNING	71
+
+typedef int (*llc_conn_action_t)(struct sock *sk, struct llc_conn_state_ev *ev);
+
+extern int llc_conn_ac_clear_remote_busy(struct sock *sk,
+					 struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_conn_ind(struct sock *sk, struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_conn_confirm(struct sock* sk, struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_data_ind(struct sock* sk, struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_disc_ind(struct sock* sk, struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_rst_ind(struct sock* sk, struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_rst_confirm(struct sock* sk,
+				     struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_report_status(struct sock* sk,
+				     struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_clear_remote_busy_if_f_eq_1(struct sock* sk,
+						  struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2(struct sock* sk,
+						  struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_disc_cmd_p_set_x(struct sock* sk,
+					     struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_dm_rsp_f_set_p(struct sock* sk,
+					   struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_dm_rsp_f_set_1(struct sock* sk,
+					   struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_dm_rsp_f_set_f_flag(struct sock* sk,
+						struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_frmr_rsp_f_set_x(struct sock* sk,
+					     struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_resend_frmr_rsp_f_set_0(struct sock* sk,
+					       struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_resend_frmr_rsp_f_set_p(struct sock* sk,
+					       struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_i_cmd_p_set_1(struct sock* sk,
+					  struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_i_cmd_p_set_0(struct sock* sk,
+					  struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_resend_i_cmd_p_set_1(struct sock* sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_resend_i_cmd_p_set_1_or_send_rr(struct sock* sk,
+						  struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_i_xxx_x_set_0(struct sock* sk,
+					  struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_resend_i_xxx_x_set_0(struct sock* sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr(struct sock* sk,
+						  struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_resend_i_rsp_f_set_1(struct sock* sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_rej_cmd_p_set_1(struct sock* sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_rej_rsp_f_set_1(struct sock* sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_rej_xxx_x_set_0(struct sock* sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_rnr_cmd_p_set_1(struct sock* sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_rnr_rsp_f_set_1(struct sock* sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_rnr_xxx_x_set_0(struct sock* sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_set_remote_busy(struct sock* sk,
+				       struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_opt_send_rnr_xxx_x_set_0(struct sock* sk,
+						struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_rr_cmd_p_set_1(struct sock* sk,
+					   struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_ack_cmd_p_set_1(struct sock* sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_rr_rsp_f_set_1(struct sock* sk,
+					   struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_ack_rsp_f_set_1(struct sock* sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_rr_xxx_x_set_0(struct sock* sk,
+					   struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_ack_xxx_x_set_0(struct sock* sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_sabme_cmd_p_set_x(struct sock* sk,
+					      struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_ua_rsp_f_set_f_flag(struct sock* sk,
+						struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_ua_rsp_f_set_p(struct sock* sk,
+					   struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_set_s_flag_0(struct sock* sk,
+				    struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_set_s_flag_1(struct sock* sk,
+				    struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_start_p_timer(struct sock* sk,
+				     struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_start_ack_timer(struct sock* sk,
+				       struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_start_rej_timer(struct sock* sk,
+				       struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_start_ack_tmr_if_not_running(struct sock* sk,
+						  struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_stop_ack_timer(struct sock* sk,
+				      struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_stop_p_timer(struct sock* sk,
+				    struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_stop_rej_timer(struct sock* sk,
+				      struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_stop_all_timers(struct sock* sk,
+				       struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_stop_other_timers(struct sock* sk,
+					 struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_upd_nr_received(struct sock* sk,
+				       struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_inc_tx_win_size(struct sock* sk,
+				       struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_dec_tx_win_size(struct sock* sk,
+				       struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_upd_p_flag(struct sock* sk,
+				     struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_set_data_flag_2(struct sock* sk,
+				       struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_set_data_flag_0(struct sock* sk,
+				       struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_set_data_flag_1(struct sock* sk,
+				       struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_set_data_flag_1_if_data_flag_eq_0(struct sock* sk,
+						  struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_set_p_flag_0(struct sock* sk,
+				    struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_set_p_flag_1(struct sock* sk,
+				    struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_set_remote_busy_0(struct sock* sk,
+					struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_set_retry_cnt_0(struct sock* sk,
+					struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_set_cause_flag_0(struct sock* sk,
+					struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_set_cause_flag_1(struct sock* sk,
+					struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_inc_retry_cnt_by_1(struct sock* sk,
+					  struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_set_vr_0(struct sock* sk, struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_inc_vr_by_1(struct sock* sk,
+				   struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_set_vs_0(struct sock* sk, struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_set_vs_nr(struct sock* sk, struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_rst_vs(struct sock* sk, struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_upd_vs(struct sock* sk, struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_set_f_flag_p(struct sock* sk,
+				    struct llc_conn_state_ev *ev);
+extern int llc_conn_disc(struct sock* sk, struct llc_conn_state_ev *ev);
+extern int llc_conn_reset(struct sock* sk, struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_disc_confirm(struct sock* sk, struct llc_conn_state_ev *ev);
+extern u8 llc_circular_between(u8 a, u8 b, u8 c);
+extern int llc_conn_ac_send_ack_if_needed(struct sock* sk,
+					  struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_inc_npta_value(struct sock* sk,
+				      struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_adjust_npta_by_rr(struct sock* sk,
+					 struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_adjust_npta_by_rnr(struct sock* sk,
+					  struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_rst_sendack_flag(struct sock* sk,
+					struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_rr_rsp_f_set_ackpf(struct sock* sk,
+					       struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock* sk,
+					      struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_i_rsp_as_ack(struct sock* sk,
+					 struct llc_conn_state_ev *ev);
+extern int llc_conn_ac_send_i_as_ack(struct sock* sk,
+				     struct llc_conn_state_ev *ev);
+#endif /* LLC_C_AC_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/net/llc_c_ev.h linux.20pre10-ac2/include/net/llc_c_ev.h
--- linux.20pre10/include/net/llc_c_ev.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/net/llc_c_ev.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,323 @@
+#ifndef LLC_C_EV_H
+#define LLC_C_EV_H
+/*
+ * Copyright (c) 1997 by Procom Technology,Inc.
+ *		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+/* Connection component state transition event qualifiers */
+/* Types of events (possible values in 'ev->type') */
+#define LLC_CONN_EV_TYPE_SIMPLE		 1
+#define LLC_CONN_EV_TYPE_CONDITION	 2
+#define LLC_CONN_EV_TYPE_PRIM		 3
+#define LLC_CONN_EV_TYPE_PDU		 4	/* command/response PDU */
+#define LLC_CONN_EV_TYPE_ACK_TMR	 5
+#define LLC_CONN_EV_TYPE_P_TMR		 6
+#define LLC_CONN_EV_TYPE_REJ_TMR	 7
+#define LLC_CONN_EV_TYPE_BUSY_TMR	 8
+#define LLC_CONN_EV_TYPE_RPT_STATUS	 9
+#define LLC_CONN_EV_TYPE_SENDACK_TMR	10
+
+#define NBR_CONN_EV		   5
+/* Connection events which cause state transitions when fully qualified */
+
+#define LLC_CONN_EV_CONN_REQ				 1
+#define LLC_CONN_EV_CONN_RESP				 2
+#define LLC_CONN_EV_DATA_REQ				 3
+#define LLC_CONN_EV_DISC_REQ				 4
+#define LLC_CONN_EV_RESET_REQ				 5
+#define LLC_CONN_EV_RESET_RESP				 6
+#define LLC_CONN_EV_LOCAL_BUSY_DETECTED			 7
+#define LLC_CONN_EV_LOCAL_BUSY_CLEARED			 8
+#define LLC_CONN_EV_RX_BAD_PDU				 9
+#define LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X		10
+#define LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X		11
+#define LLC_CONN_EV_RX_FRMR_RSP_Fbit_SET_X		12
+#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_X			13
+#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_X_UNEXPD_Ns	14
+#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_X_INVAL_Ns	15
+#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_X			16
+#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_X_UNEXPD_Ns	17
+#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_X_INVAL_Ns	18
+#define LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_X		19
+#define LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_X		20
+#define LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_X		21
+#define LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_X		22
+#define LLC_CONN_EV_RX_RR_CMD_Pbit_SET_X		23
+#define LLC_CONN_EV_RX_RR_RSP_Fbit_SET_X		24
+#define LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X		25
+#define LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X		26
+#define LLC_CONN_EV_RX_XXX_CMD_Pbit_SET_X		27
+#define LLC_CONN_EV_RX_XXX_RSP_Fbit_SET_X		28
+#define LLC_CONN_EV_RX_XXX_YYY				29
+#define LLC_CONN_EV_RX_ZZZ_CMD_Pbit_SET_X_INVAL_Nr	30
+#define LLC_CONN_EV_RX_ZZZ_RSP_Fbit_SET_X_INVAL_Nr	31
+#define LLC_CONN_EV_P_TMR_EXP				32
+#define LLC_CONN_EV_ACK_TMR_EXP				33
+#define LLC_CONN_EV_REJ_TMR_EXP				34
+#define LLC_CONN_EV_BUSY_TMR_EXP			35
+#define LLC_CONN_EV_RX_XXX_CMD_Pbit_SET_1		36
+#define LLC_CONN_EV_RX_XXX_CMD_Pbit_SET_0		37
+#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns	38
+#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns	39
+#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_1_UNEXPD_Ns	40
+#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns	41
+#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_0			42
+#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_0			43
+#define LLC_CONN_EV_RX_I_CMD_Pbit_SET_1			44
+#define LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0		45
+#define LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0		46
+#define LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1		47
+#define LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1		48
+#define LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0		49
+#define LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0		50
+#define LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1		51
+#define LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1		52
+#define LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0		53
+#define LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0		54
+#define LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1		55
+#define LLC_CONN_EV_RX_I_RSP_Fbit_SET_1			56
+#define LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_1		57
+#define LLC_CONN_EV_RX_XXX_RSP_Fbit_SET_1		58
+#define LLC_CONN_EV_TX_BUFF_FULL			59
+
+#define LLC_CONN_EV_INIT_P_F_CYCLE			100
+/*
+ * Connection event qualifiers; for some events a certain combination of
+ * these qualifiers must be TRUE before event recognized valid for state;
+ * these constants act as indexes into the Event Qualifier function
+ * table
+ */
+#define LLC_CONN_EV_QFY_DATA_FLAG_EQ_1		 1
+#define LLC_CONN_EV_QFY_DATA_FLAG_EQ_0		 2
+#define LLC_CONN_EV_QFY_DATA_FLAG_EQ_2		 3
+#define LLC_CONN_EV_QFY_P_FLAG_EQ_1		 4
+#define LLC_CONN_EV_QFY_P_FLAG_EQ_0		 5
+#define LLC_CONN_EV_QFY_P_FLAG_EQ_Fbit		 6
+#define LLC_CONN_EV_QFY_REMOTE_BUSY_EQ_0	 7
+#define LLC_CONN_EV_QFY_RETRY_CNT_LT_N2		 8
+#define LLC_CONN_EV_QFY_RETRY_CNT_GTE_N2	 9
+#define LLC_CONN_EV_QFY_S_FLAG_EQ_1		10
+#define LLC_CONN_EV_QFY_S_FLAG_EQ_0		11
+#define LLC_CONN_EV_QFY_INIT_P_F_CYCLE		12
+
+/* Event data interface; what is sent in an event package */
+/* Event LLC_CONN_EV_TYPE_SIMPLE interface */
+struct llc_conn_ev_simple_if {
+	u8 ev;
+};
+
+/* Event LLC_CONN_EV_TYPE_PRIM interface */
+struct llc_conn_ev_prim_if {
+	u8			  prim;  /* connect, disconnect, reset, ... */
+	u8			  type;  /* request, indicate, response, conf */
+	struct llc_prim_if_block *data;
+};
+
+/* Event LLC_CONN_EV_TYPE_PDU interface */
+struct llc_conn_ev_pdu_if {
+	u8		ev;
+	u8		reason;
+	struct sk_buff *skb;
+};
+
+/* 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;
+};
+
+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 {
+	u8			  type;
+	u8			  status;
+	u8			  flag;
+	struct llc_prim_if_block *ind_prim;
+	struct llc_prim_if_block *cfm_prim;
+	union llc_conn_ev_if	  data;
+};
+
+typedef int (*llc_conn_ev_t)(struct sock *sk, struct llc_conn_state_ev *ev);
+typedef int (*llc_conn_ev_qfyr_t)(struct sock *sk,
+				  struct llc_conn_state_ev *ev);
+
+extern int llc_conn_ev_conn_req(struct sock *sk, struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_conn_resp(struct sock *sk, struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_data_req(struct sock *sk, struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_disc_req(struct sock *sk, struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rst_req(struct sock *sk, struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rst_resp(struct sock *sk, struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_local_busy_detected(struct sock *sk,
+					   struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_local_busy_cleared(struct sock *sk,
+					  struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_bad_pdu(struct sock *sk,
+				  struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_disc_cmd_pbit_set_x(struct sock *sk,
+					      struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_dm_rsp_fbit_set_x(struct sock *sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_frmr_rsp_fbit_set_x(struct sock *sk,
+					      struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_i_cmd_pbit_set_x_inval_ns(struct sock *sk,
+						  struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_i_rsp_fbit_set_x(struct sock *sk,
+					   struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_i_rsp_fbit_set_x_unexpd_ns(struct sock *sk,
+						  struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_i_rsp_fbit_set_x_inval_ns(struct sock *sk,
+						  struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_rej_rsp_fbit_set_x(struct sock *sk,
+					     struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_sabme_cmd_pbit_set_x(struct sock *sk,
+					       struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_ua_rsp_fbit_set_x(struct sock *sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_xxx_cmd_pbit_set_x(struct sock *sk,
+					     struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_xxx_rsp_fbit_set_x(struct sock *sk,
+					     struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_xxx_yyy(struct sock *sk,
+				  struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_zzz_cmd_pbit_set_x_inval_nr(struct sock *sk,
+						  struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_zzz_rsp_fbit_set_x_inval_nr(struct sock *sk,
+						  struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_p_tmr_exp(struct sock *sk,
+				   struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_ack_tmr_exp(struct sock *sk,
+				   struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rej_tmr_exp(struct sock *sk,
+				   struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_busy_tmr_exp(struct sock *sk,
+				    struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_any_tmr_exp(struct sock *sk,
+				   struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_sendack_tmr_exp(struct sock *sk,
+				       struct llc_conn_state_ev *ev);
+/* NOT_USED functions and their variations */
+extern int llc_conn_ev_rx_xxx_cmd_pbit_set_1(struct sock *sk,
+					     struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_xxx_cmd_pbit_set_0(struct sock *sk,
+					     struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_xxx_rsp_fbit_set_1(struct sock *sk,
+					     struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns(struct sock *sk,
+						  struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns(struct sock *sk,
+						  struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_i_cmd_pbit_set_0(struct sock *sk,
+					   struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_i_cmd_pbit_set_1(struct sock *sk,
+					   struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns(struct sock *sk,
+						  struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns(struct sock *sk,
+						  struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_i_rsp_fbit_set_0(struct sock *sk,
+					   struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_i_rsp_fbit_set_1(struct sock *sk,
+					   struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_rr_cmd_pbit_set_0(struct sock *sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_rr_cmd_pbit_set_1(struct sock *sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_rr_rsp_fbit_set_0(struct sock *sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_rr_rsp_fbit_set_1(struct sock *sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_rnr_cmd_pbit_set_0(struct sock *sk,
+					     struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_rnr_cmd_pbit_set_1(struct sock *sk,
+					     struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_rnr_rsp_fbit_set_0(struct sock *sk,
+					     struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_rnr_rsp_fbit_set_1(struct sock *sk,
+					     struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_rej_cmd_pbit_set_0(struct sock *sk,
+					     struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_rej_cmd_pbit_set_1(struct sock *sk,
+					     struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_rej_rsp_fbit_set_0(struct sock *sk,
+					     struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_rej_rsp_fbit_set_1(struct sock *sk,
+					     struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_rx_any_frame(struct sock *sk,
+				    struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_tx_buffer_full(struct sock *sk,
+				      struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_init_p_f_cycle(struct sock *sk,
+				      struct llc_conn_state_ev *ev);
+
+/* Available connection action qualifiers */
+extern int llc_conn_ev_qlfy_data_flag_eq_1(struct sock *sk,
+					   struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_data_flag_eq_0(struct sock *sk,
+					   struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_data_flag_eq_2(struct sock *sk,
+					   struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_p_flag_eq_1(struct sock *sk,
+					struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_last_frame_eq_1(struct sock *sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_last_frame_eq_0(struct sock *sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_p_flag_eq_0(struct sock *sk,
+					struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_p_flag_eq_f(struct sock *sk,
+					struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_remote_busy_eq_0(struct sock *sk,
+					     struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_remote_busy_eq_1(struct sock *sk,
+					     struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_retry_cnt_lt_n2(struct sock *sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_retry_cnt_gte_n2(struct sock *sk,
+					     struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_s_flag_eq_1(struct sock *sk,
+					struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_s_flag_eq_0(struct sock *sk,
+					struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_cause_flag_eq_1(struct sock *sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_cause_flag_eq_0(struct sock *sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_init_p_f_cycle(struct sock *sk,
+					   struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_set_status_conn(struct sock *sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_set_status_disc(struct sock *sk,
+					    struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_set_status_failed(struct sock *sk,
+					      struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_set_status_impossible(struct sock *sk,
+						  struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_set_status_remote_busy(struct sock *sk,
+						  struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_set_status_received(struct sock *sk,
+						struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_set_status_refuse(struct sock *sk,
+					      struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_set_status_conflict(struct sock *sk,
+						struct llc_conn_state_ev *ev);
+extern int llc_conn_ev_qlfy_set_status_rst_done(struct sock *sk,
+						struct llc_conn_state_ev *ev);
+#endif /* LLC_C_EV_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/net/llc_conn.h linux.20pre10-ac2/include/net/llc_conn.h
--- linux.20pre10/include/net/llc_conn.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/net/llc_conn.h	2002-10-09 22:15:47.000000000 +0100
@@ -0,0 +1,155 @@
+#ifndef LLC_CONN_H
+#define LLC_CONN_H
+/*
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/timer.h>
+#include <net/llc_if.h>
+
+#undef DEBUG_LLC_CONN_ALLOC
+
+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 */
+	u8		    state;		/* state of connection */
+	struct llc_sap	   *sap;		/* pointer to parent SAP */
+	struct llc_addr	    laddr;		/* lsap/mac pair */
+	struct llc_addr	    daddr;		/* dsap/mac pair */
+	struct net_device  *dev;		/* device to send to remote */
+	u8		    retry_count;	/* number of retries */
+	u8		    ack_must_be_send;
+	u8		    first_pdu_Ns;
+	u8		    npta;
+	struct llc_timer    ack_timer;
+	struct llc_timer    pf_cycle_timer;
+	struct llc_timer    rej_sent_timer;
+	struct llc_timer    busy_state_timer;	/* ind busy clr at remote LLC */
+	u8		    vS;			/* seq# next in-seq I-PDU tx'd*/
+	u8		    vR;			/* seq# next in-seq I-PDU rx'd*/
+	u32		    n2;			/* max nbr re-tx's for timeout*/
+	u32		    n1;			/* max nbr octets in I PDU */
+	u8		    k;			/* tx window size; max = 127 */
+	u8		    rw;			/* rx window size; max = 127 */
+	u8		    p_flag;		/* state flags */
+	u8		    f_flag;
+	u8		    s_flag;
+	u8		    data_flag;
+	u8		    remote_busy_flag;
+	u8		    cause_flag;
+	struct sk_buff_head pdu_unack_q;	/* PUDs sent/waiting ack */
+	u16		    link;		/* network layer link number */
+	u8		    X;			/* a temporary variable */
+	u8		    ack_pf;		/* this flag indicates what is
+						   the P-bit of acknowledge */
+	u8		    failed_data_req; /* recognize that already exist a
+						failed llc_data_req_handler
+						(tx_buffer_full or unacceptable
+						state */
+	u8		    dec_step;
+	u8		    inc_cntr;
+	u8		    dec_cntr;
+	u8		    connect_step;
+	u8		    last_nr;	   /* NR of last pdu recieved */
+	u32		    rx_pdu_hdr;	   /* used for saving header of last pdu
+					      received and caused sending FRMR.
+					      Used for resending FRMR */
+#ifdef DEBUG_LLC_CONN_ALLOC
+	char *f_alloc,	/* function that allocated this connection */
+	     *f_free;	/* function that freed this connection */
+	int l_alloc,	/* line that allocated this connection */
+	    l_free;	/* line that freed this connection */
+#endif
+};
+
+#define llc_sk(__sk) ((struct llc_opt *)(__sk)->protinfo.destruct_hook)
+
+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 void llc_sock_reset(struct sock *sk);
+extern int llc_sock_init(struct sock *sk);
+
+/* Access to a connection */
+extern struct llc_conn_state_ev *llc_conn_alloc_ev(struct sock *sk);
+extern int llc_conn_send_ev(struct sock *sk, struct llc_conn_state_ev *ev);
+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,
+			     struct llc_conn_state_ev *ev);
+extern void llc_conn_free_ev(struct llc_conn_state_ev *ev);
+extern void llc_conn_resend_i_pdu_as_cmd(struct sock *sk, u8 nr,
+					 u8 first_p_bit);
+extern void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr,
+					 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 u8 llc_data_accept_state(u8 state);
+extern void llc_build_offset_table(void);
+#endif /* LLC_CONN_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/net/llc_c_st.h linux.20pre10-ac2/include/net/llc_c_st.h
--- linux.20pre10/include/net/llc_c_st.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/net/llc_c_st.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,48 @@
+#ifndef LLC_C_ST_H
+#define LLC_C_ST_H
+/*
+ * Copyright (c) 1997 by Procom Technology,Inc.
+ *		2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+/* Connection component state management */
+/* connection states */
+#define LLC_CONN_OUT_OF_SVC		 0	/* prior to allocation */
+ 
+#define LLC_CONN_STATE_ADM		 1	/* disc, initial state */
+#define LLC_CONN_STATE_SETUP		 2	/* disconnected state */
+#define LLC_CONN_STATE_NORMAL		 3	/* connected state */
+#define LLC_CONN_STATE_BUSY		 4	/* connected state */
+#define LLC_CONN_STATE_REJ		 5	/* connected state */
+#define LLC_CONN_STATE_AWAIT		 6	/* connected state */
+#define LLC_CONN_STATE_AWAIT_BUSY	 7	/* connected state */
+#define LLC_CONN_STATE_AWAIT_REJ	 8	/* connected state */
+#define LLC_CONN_STATE_D_CONN		 9	/* disconnected state */
+#define LLC_CONN_STATE_RESET		10	/* disconnected state */
+#define LLC_CONN_STATE_ERROR		11	/* disconnected state */
+#define LLC_CONN_STATE_TEMP		12	/* disconnected state */
+
+#define NBR_CONN_STATES			12	/* size of state table */
+#define NO_STATE_CHANGE			100
+
+/* 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;
+};
+
+struct llc_conn_state {
+   u8 current_state;
+   struct llc_conn_state_trans **transitions;
+};
+
+extern struct llc_conn_state llc_conn_state_table[];
+#endif /* LLC_C_ST_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/net/llc_evnt.h linux.20pre10-ac2/include/net/llc_evnt.h
--- linux.20pre10/include/net/llc_evnt.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/net/llc_evnt.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,93 @@
+#ifndef LLC_EVNT_H
+#define LLC_EVNT_H
+/*
+ * Copyright (c) 1997 by Procom Technology,Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+/* Station component state transition events */
+/* Types of events (possible values in 'ev->type') */
+#define LLC_STATION_EV_TYPE_SIMPLE	1
+#define LLC_STATION_EV_TYPE_CONDITION	2
+#define LLC_STATION_EV_TYPE_PRIM	3
+#define LLC_STATION_EV_TYPE_PDU		4       /* command/response PDU */
+#define LLC_STATION_EV_TYPE_ACK_TMR	5
+#define LLC_STATION_EV_TYPE_RPT_STATUS	6
+
+/* Events */
+#define LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK		1
+#define LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK		2
+#define LLC_STATION_EV_ACK_TMR_EXP_LT_RETRY_CNT_MAX_RETRY	3
+#define LLC_STATION_EV_ACK_TMR_EXP_EQ_RETRY_CNT_MAX_RETRY	4
+#define LLC_STATION_EV_RX_NULL_DSAP_XID_C			5
+#define LLC_STATION_EV_RX_NULL_DSAP_0_XID_R_XID_R_CNT_EQ	6
+#define LLC_STATION_EV_RX_NULL_DSAP_1_XID_R_XID_R_CNT_EQ	7
+#define LLC_STATION_EV_RX_NULL_DSAP_TEST_C			8
+#define LLC_STATION_EV_DISABLE_REQ				9
+
+/* Interfaces for various types of supported events */
+struct llc_stat_ev_simple_if {
+	u8 ev;
+};
+
+struct llc_stat_ev_prim_if {
+	u8 prim; /* connect, disconnect, reset, ... */
+	u8 type; /* request, indicate, response, confirm */
+};
+
+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;
+	union llc_stat_ev_if data;
+	struct list_head	node; /* node in station->ev_q.list */
+};
+
+typedef int (*llc_station_ev_t)(struct llc_station *station,
+				struct llc_station_state_ev *ev);
+
+extern int llc_stat_ev_enable_with_dup_addr_check(struct llc_station *station,
+					       struct llc_station_state_ev *ev);
+extern int llc_stat_ev_enable_without_dup_addr_check(struct llc_station *station,
+					       struct llc_station_state_ev *ev);
+extern int llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry(struct llc_station *
+									station,
+					       struct llc_station_state_ev *ev);
+extern int llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry(struct llc_station *station,
+					       struct llc_station_state_ev *ev);
+extern int llc_stat_ev_rx_null_dsap_xid_c(struct llc_station *station,
+					  struct llc_station_state_ev *ev);
+extern int llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq(struct llc_station *station,
+					       struct llc_station_state_ev *ev);
+extern int llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq(struct llc_station *station,
+					       struct llc_station_state_ev *ev);
+extern int llc_stat_ev_rx_null_dsap_test_c(struct llc_station *station,
+					   struct llc_station_state_ev *ev);
+extern int llc_stat_ev_disable_req(struct llc_station *station,
+				       struct llc_station_state_ev *ev);
+#endif /* LLC_EVNT_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/net/llc_if.h linux.20pre10-ac2/include/net/llc_if.h
--- linux.20pre10/include/net/llc_if.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/net/llc_if.h	2002-09-18 14:26:34.000000000 +0100
@@ -0,0 +1,155 @@
+#ifndef LLC_IF_H
+#define LLC_IF_H
+/*
+ * Copyright (c) 1997 by Procom Technology,Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+/* Defines LLC interface to network layer */
+/* Available primitives */
+#include <linux/if.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_DISABLE_PRIM	6
+#define LLC_XID_PRIM		7
+#define LLC_TEST_PRIM		8
+#define LLC_SAP_ACTIVATION      9
+#define LLC_SAP_DEACTIVATION   10
+
+#define LLC_NBR_PRIMITIVES     11
+
+#define LLC_IND			1
+#define LLC_CONFIRM		2
+
+/* Primitive type */
+#define LLC_PRIM_TYPE_REQ	1
+#define LLC_PRIM_TYPE_IND	2
+#define LLC_PRIM_TYPE_RESP	3
+#define LLC_PRIM_TYPE_CONFIRM	4
+
+/* Reset reasons, remote entity or local LLC */
+#define LLC_RESET_REASON_REMOTE	1
+#define LLC_RESET_REASON_LOCAL	2
+
+/* Disconnect reasons */
+#define LLC_DISC_REASON_RX_DM_RSP_PDU	0
+#define LLC_DISC_REASON_RX_DISC_CMD_PDU	1
+#define LLC_DISC_REASON_ACK_TMR_EXP	2
+
+/* Confirm reasons */
+#define LLC_STATUS_CONN		0 /* connect confirm & reset confirm */
+#define LLC_STATUS_DISC		1 /* connect confirm & reset confirm */
+#define LLC_STATUS_FAILED	2 /* connect confirm & reset confirm */
+#define LLC_STATUS_IMPOSSIBLE	3 /* connect confirm */
+#define LLC_STATUS_RECEIVED	4 /* data conn */
+#define LLC_STATUS_REMOTE_BUSY	5 /* data conn */
+#define LLC_STATUS_REFUSE	6 /* data conn */
+#define LLC_STATUS_CONFLICT	7 /* disconnect conn */
+#define LLC_STATUS_RESET_DONE	8 /*  */
+
+/* Structures and types */
+/* SAP/MAC Address pair */
+struct llc_addr {
+	u8 lsap;
+	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;
+	struct llc_addr	daddr;
+	u8		pri;
+	struct sk_buff *skb;		/* pointer to frame */
+	u8		lfb;		/* largest frame bit (TR) */
+};
+
+struct llc_prim_xid {
+	struct llc_addr saddr;
+	struct llc_addr daddr;
+	u8		pri;
+	struct sk_buff *skb;
+};
+
+struct llc_prim_test {
+	struct llc_addr	saddr;
+	struct llc_addr	daddr;
+	u8		pri;
+	struct sk_buff *skb;		/* pointer to frame */
+};
+
+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;
+};
+
+struct llc_sap;
+
+/* Information block passed with all called primitives */
+struct llc_prim_if_block {
+	struct llc_sap	      *sap;
+	u8		       prim;
+	union llc_u_prim_data *data;
+};
+typedef int (*llc_prim_call_t)(struct llc_prim_if_block *prim_if);
+
+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);
+#endif /* LLC_IF_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/net/llc_mac.h linux.20pre10-ac2/include/net/llc_mac.h
--- linux.20pre10/include/net/llc_mac.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/net/llc_mac.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,23 @@
+#ifndef LLC_MAC_H
+#define LLC_MAC_H
+/*
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+/* 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 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);
+#endif /* LLC_MAC_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/net/llc_main.h linux.20pre10-ac2/include/net/llc_main.h
--- linux.20pre10/include/net/llc_main.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/net/llc_main.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,68 @@
+#ifndef LLC_MAIN_H
+#define LLC_MAIN_H
+/*
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#define LLC_EVENT		 1
+#define LLC_PACKET		 2
+#define LLC_TYPE_1		 1
+#define LLC_TYPE_2		 2
+#define LLC_P_TIME		 2
+#define LLC_ACK_TIME		 3
+#define LLC_REJ_TIME		 3
+#define LLC_BUSY_TIME		 3
+#define LLC_SENDACK_TIME	50
+#define LLC_DEST_INVALID	 0	/* Invalid LLC PDU type */
+#define LLC_DEST_SAP		 1	/* Type 1 goes here */
+#define LLC_DEST_CONN		 2	/* Type 2 goes here */
+
+/* LLC Layer global default parameters */
+
+#define LLC_GLOBAL_DEFAULT_MAX_NBR_SAPS		4
+#define LLC_GLOBAL_DEFAULT_MAX_NBR_CONNS	64
+
+extern struct llc_prim_if_block llc_ind_prim, llc_cfm_prim;
+
+/* LLC station component (SAP and connection resource manager) */
+/* Station component; one per adapter */
+struct llc_station {
+	u8     state;			/* state of station */
+	u8     xid_r_count;		/* XID response PDU counter */
+	struct timer_list ack_timer;
+	u8     ack_tmr_running;		/* 1 or 0 */
+	u8     retry_count;
+	u8     maximum_retry;
+	u8     mac_sa[6];		/* MAC source address */
+	struct {
+		spinlock_t	 lock;
+		struct list_head list;
+	} sap_list;			/* list of related SAPs */
+	struct {
+		spinlock_t	 lock;
+		struct list_head list;
+	} ev_q;				/* events entering state mach. */
+	struct sk_buff_head mac_pdu_q;	/* PDUs ready to send to MAC */
+};
+struct llc_station_state_ev;
+
+extern struct llc_sap *llc_sap_alloc(void);
+extern void llc_sap_save(struct llc_sap *sap);
+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 struct llc_station_state_ev *
+			     llc_station_alloc_ev(struct llc_station *station);
+extern void llc_station_send_ev(struct llc_station *station,
+				struct llc_station_state_ev *ev);
+extern void llc_station_send_pdu(struct llc_station *station,
+				 struct sk_buff *skb);
+extern struct sk_buff *llc_alloc_frame(void);
+#endif /* LLC_MAIN_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/net/llc_pdu.h linux.20pre10-ac2/include/net/llc_pdu.h
--- linux.20pre10/include/net/llc_pdu.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/net/llc_pdu.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,255 @@
+#ifndef LLC_PDU_H
+#define LLC_PDU_H
+/*
+ * Copyright (c) 1997 by Procom Technology,Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+/* LLC PDU structure */
+/* Lengths of frame formats */
+#define LLC_PDU_LEN_I	4       /* header and 2 control bytes */
+#define LLC_PDU_LEN_S	4
+#define LLC_PDU_LEN_U	3       /* header and 1 control byte */
+/* Known SAP addresses */
+#define LLC_GLOBAL_SAP	0xFF
+#define LLC_NULL_SAP	0x00	/* not network-layer visible */
+#define LLC_MGMT_INDIV	0x02	/* station LLC mgmt indiv addr */
+#define LLC_MGMT_GRP	0x03	/* station LLC mgmt group addr */
+#define LLC_RDE_SAP	0xA6	/* route ... */
+
+/* SAP field bit masks */
+#define LLC_ISO_RESERVED_SAP	0x02
+#define LLC_SAP_GROUP_DSAP	0x01
+#define LLC_SAP_RESP_SSAP	0x01
+
+/* Group/individual DSAP indicator is DSAP field */
+#define LLC_PDU_GROUP_DSAP_MASK    0x01
+#define LLC_PDU_IS_GROUP_DSAP(pdu)      \
+	((pdu->dsap & LLC_PDU_GROUP_DSAP_MASK) ? 0 : 1)
+#define LLC_PDU_IS_INDIV_DSAP(pdu)      \
+	(!(pdu->dsap & LLC_PDU_GROUP_DSAP_MASK) ? 0 : 1)
+
+/* Command/response PDU indicator in SSAP field */
+#define LLC_PDU_CMD_RSP_MASK	0x01
+#define LLC_PDU_CMD		0
+#define LLC_PDU_RSP		1
+#define LLC_PDU_IS_CMD(pdu)    ((pdu->ssap & LLC_PDU_RSP) ? 1 : 0)
+#define LLC_PDU_IS_RSP(pdu)    ((pdu->ssap & LLC_PDU_RSP) ? 0 : 1)
+
+/* Get PDU type from 2 lowest-order bits of control field first byte */
+#define LLC_PDU_TYPE_I_MASK    0x01	/* 16-bit control field */
+#define LLC_PDU_TYPE_S_MASK    0x03
+#define LLC_PDU_TYPE_U_MASK    0x03	/* 8-bit control field */
+#define LLC_PDU_TYPE_MASK      0x03
+
+#define LLC_PDU_TYPE_I	0	/* first bit */
+#define LLC_PDU_TYPE_S	1	/* first two bits */
+#define LLC_PDU_TYPE_U	3	/* first two bits */
+
+#define LLC_PDU_TYPE_IS_I(pdu) \
+	((!(pdu->ctrl_1 & LLC_PDU_TYPE_I_MASK)) ? 0 : 1)
+
+#define LLC_PDU_TYPE_IS_U(pdu) \
+	(((pdu->ctrl_1 & LLC_PDU_TYPE_U_MASK) == LLC_PDU_TYPE_U) ? 0 : 1)
+
+#define LLC_PDU_TYPE_IS_S(pdu) \
+	(((pdu->ctrl_1 & LLC_PDU_TYPE_S_MASK) == LLC_PDU_TYPE_S) ? 0 : 1)
+
+/* U-format PDU control field masks */
+#define LLC_U_PF_BIT_MASK      0x10	/* P/F bit mask */
+#define LLC_U_PF_IS_1(pdu)     ((pdu->ctrl_1 & LLC_U_PF_BIT_MASK) ? 0 : 1)
+#define LLC_U_PF_IS_0(pdu)     ((!(pdu->ctrl_1 & LLC_U_PF_BIT_MASK)) ? 0 : 1)
+
+#define LLC_U_PDU_CMD_MASK     0xEC	/* cmd/rsp mask */
+#define LLC_U_PDU_CMD(pdu)     (pdu->ctrl_1 & LLC_U_PDU_CMD_MASK)
+#define LLC_U_PDU_RSP(pdu)     (pdu->ctrl_1 & LLC_U_PDU_CMD_MASK)
+
+#define LLC_1_PDU_CMD_UI       0x00	/* Type 1 cmds/rsps */
+#define LLC_1_PDU_CMD_XID      0xAC
+#define LLC_1_PDU_CMD_TEST     0xE0
+
+#define LLC_2_PDU_CMD_SABME    0x6C	/* Type 2 cmds/rsps */
+#define LLC_2_PDU_CMD_DISC     0x40
+#define LLC_2_PDU_RSP_UA       0x60
+#define LLC_2_PDU_RSP_DM       0x0C
+#define LLC_2_PDU_RSP_FRMR     0x84
+
+/* Type 1 operations */
+
+/* XID information field bit masks */
+
+/* LLC format identifier (byte 1) */
+#define LLC_XID_FMT_ID		0x81	/* first byte must be this */
+
+/* LLC types/classes identifier (byte 2) */
+#define LLC_XID_CLASS_ZEROS_MASK	0xE0	/* these must be zeros */
+#define LLC_XID_CLASS_MASK		0x1F	/* AND with byte to get below */
+
+#define LLC_XID_NULL_CLASS_1	0x01	/* if NULL LSAP...use these */
+#define LLC_XID_NULL_CLASS_2	0x03
+#define LLC_XID_NULL_CLASS_3	0x05
+#define LLC_XID_NULL_CLASS_4	0x07
+
+#define LLC_XID_NNULL_TYPE_1	0x01	/* if non-NULL LSAP...use these */
+#define LLC_XID_NNULL_TYPE_2	0x02
+#define LLC_XID_NNULL_TYPE_3	0x04
+#define LLC_XID_NNULL_TYPE_1_2	0x03
+#define LLC_XID_NNULL_TYPE_1_3	0x05
+#define LLC_XID_NNULL_TYPE_2_3	0x06
+#define LLC_XID_NNULL_ALL		0x07
+
+/* Sender Receive Window (byte 3) */
+#define LLC_XID_RW_MASK	0xFE	/* AND with value to get below */
+
+#define LLC_XID_MIN_RW	0x02	/* lowest-order bit always zero */
+
+/* Type 2 operations */
+
+#define LLC_2_SEQ_NBR_MODULO   ((u8) 128)
+
+/* I-PDU masks ('ctrl' is I-PDU control word) */
+#define LLC_I_GET_NS(pdu)     (u8)((pdu->ctrl_1 & 0xFE) >> 1)
+#define LLC_I_GET_NR(pdu)     (u8)((pdu->ctrl_2 & 0xFE) >> 1)
+
+#define LLC_I_PF_BIT_MASK      0x01
+
+#define LLC_I_PF_IS_0(pdu)     ((!(pdu->ctrl_2 & LLC_I_PF_BIT_MASK)) ? 0 : 1)
+#define LLC_I_PF_IS_1(pdu)     ((pdu->ctrl_2 & LLC_I_PF_BIT_MASK) ? 0 : 1)
+
+/* S-PDU supervisory commands and responses */
+
+#define LLC_S_PDU_CMD_MASK     0x0C
+#define LLC_S_PDU_CMD(pdu)     (pdu->ctrl_1 & LLC_S_PDU_CMD_MASK)
+#define LLC_S_PDU_RSP(pdu)     (pdu->ctrl_1 & LLC_S_PDU_CMD_MASK)
+
+#define LLC_2_PDU_CMD_RR       0x00	/* rx ready cmd */
+#define LLC_2_PDU_RSP_RR       0x00	/* rx ready rsp */
+#define LLC_2_PDU_CMD_REJ      0x08	/* reject PDU cmd */
+#define LLC_2_PDU_RSP_REJ      0x08	/* reject PDU rsp */
+#define LLC_2_PDU_CMD_RNR      0x04	/* rx not ready cmd */
+#define LLC_2_PDU_RSP_RNR      0x04	/* rx not ready rsp */
+
+#define LLC_S_PF_BIT_MASK      0x01
+#define LLC_S_PF_IS_0(pdu)     ((!(pdu->ctrl_2 & LLC_S_PF_BIT_MASK)) ? 0 : 1)
+#define LLC_S_PF_IS_1(pdu)     ((pdu->ctrl_2 & LLC_S_PF_BIT_MASK) ? 0 : 1)
+
+#define PDU_SUPV_GET_Nr(pdu)   ((pdu->ctrl_2 & 0xFE) >> 1)
+#define PDU_GET_NEXT_Vr(sn)    (++sn & ~LLC_2_SEQ_NBR_MODULO)
+
+/* FRMR information field macros */
+
+#define FRMR_INFO_LENGTH       5	/* 5 bytes of information */
+
+/*
+ * info is pointer to FRMR info field structure; 'rej_ctrl' is byte pointer
+ * (if U-PDU) or word pointer to rejected PDU control field
+ */
+#define FRMR_INFO_SET_REJ_CNTRL(info,rej_ctrl) \
+	info->rej_pdu_ctrl = ((*((u8 *) rej_ctrl) & \
+				LLC_PDU_TYPE_U) != LLC_PDU_TYPE_U ? \
+				(u16)*((u16 *) rej_ctrl) : \
+				(((u16) *((u8 *) rej_ctrl)) & 0x00FF))
+
+/*
+ * Info is pointer to FRMR info field structure; 'vs' is a byte containing
+ * send state variable value in low-order 7 bits (insure the lowest-order
+ * bit remains zero (0))
+ */
+#define FRMR_INFO_SET_Vs(info,vs) (info->curr_ssv = (((u8) vs) << 1))
+#define FRMR_INFO_SET_Vr(info,vr) (info->curr_rsv = (((u8) vr) << 1))
+
+/*
+ * Info is pointer to FRMR info field structure; 'cr' is a byte containing
+ * the C/R bit value in the low-order bit
+ */
+#define FRMR_INFO_SET_C_R_BIT(info, cr)  (info->curr_rsv |= (((u8) cr) & 0x01))
+
+/*
+ * In the remaining five macros, 'info' is pointer to FRMR info field
+ * structure; 'ind' is a byte containing the bit value to set in the
+ * lowest-order bit)
+ */
+#define FRMR_INFO_SET_INVALID_PDU_CTRL_IND(info, ind) \
+       (info->ind_bits = ((info->ind_bits & 0xFE) | (((u8) ind) & 0x01)))
+
+#define FRMR_INFO_SET_INVALID_PDU_INFO_IND(info, ind) \
+       (info->ind_bits = ( (info->ind_bits & 0xFD) | (((u8) ind) & 0x02)))
+
+#define FRMR_INFO_SET_PDU_INFO_2LONG_IND(info, ind) \
+       (info->ind_bits = ( (info->ind_bits & 0xFB) | (((u8) ind) & 0x04)))
+
+#define FRMR_INFO_SET_PDU_INVALID_Nr_IND(info, ind) \
+       (info->ind_bits = ( (info->ind_bits & 0xF7) | (((u8) ind) & 0x08)))
+
+#define FRMR_INFO_SET_PDU_INVALID_Ns_IND(info, ind) \
+       (info->ind_bits = ( (info->ind_bits & 0xEF) | (((u8) ind) & 0x10)))
+
+/* Sequence-numbered PDU format (4 bytes in length) */
+typedef struct llc_pdu_sn {
+	u8 dsap;
+	u8 ssap;
+	u8 ctrl_1;
+	u8 ctrl_2;
+} llc_pdu_sn_t;
+
+/* Un-numbered PDU format (3 bytes in length) */
+typedef struct llc_pdu_un {
+	u8 dsap;
+	u8 ssap;
+	u8 ctrl_1;
+} llc_pdu_un_t;
+
+/* LLC Type 1 XID command/response information fields format */
+typedef struct llc_xid_info {
+	u8 fmt_id;	/* always 0x18 for LLC */
+	u8 type;	/* different if NULL/non-NULL LSAP */
+	u8 rw;		/* sender receive window */
+} llc_xid_info_t;
+
+/* LLC Type 2 FRMR response information field format */
+typedef struct llc_frmr_info {
+	u16 rej_pdu_ctrl;	/* bits 1-8 if U-PDU */
+	u8  curr_ssv;		/* current send state variable val */
+	u8  curr_rsv;		/* current receive state variable */
+	u8  ind_bits;		/* indicator bits set with macro */
+} llc_frmr_info_t;
+
+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_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,
+				   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, llc_pdu_sn_t *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);
+#endif /* LLC_PDU_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/net/llc_s_ac.h linux.20pre10-ac2/include/net/llc_s_ac.h
--- linux.20pre10/include/net/llc_s_ac.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/net/llc_s_ac.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,47 @@
+#ifndef LLC_S_AC_H
+#define LLC_S_AC_H
+/*
+ * Copyright (c) 1997 by Procom Technology,Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+/* SAP component actions */
+#define SAP_ACT_UNITDATA_IND	1
+#define SAP_ACT_SEND_UI		2
+#define SAP_ACT_SEND_XID_C	3
+#define SAP_ACT_SEND_XID_R	4
+#define SAP_ACT_SEND_TEST_C	5
+#define SAP_ACT_SEND_TEST_R	6
+#define SAP_ACT_REPORT_STATUS	7
+#define SAP_ACT_XID_IND		8
+#define SAP_ACT_TEST_IND	9
+
+/* All action functions must look like this */
+typedef int (*llc_sap_action_t)(struct llc_sap *sap,
+				struct llc_sap_state_ev *ev);
+
+extern int llc_sap_action_unitdata_ind(struct llc_sap *sap,
+				       struct llc_sap_state_ev *ev);
+extern int llc_sap_action_send_ui(struct llc_sap *sap,
+				  struct llc_sap_state_ev *ev);
+extern int llc_sap_action_send_xid_c(struct llc_sap *sap,
+				     struct llc_sap_state_ev *ev);
+extern int llc_sap_action_send_xid_r(struct llc_sap *sap,
+				     struct llc_sap_state_ev *ev);
+extern int llc_sap_action_send_test_c(struct llc_sap *sap,
+				      struct llc_sap_state_ev *ev);
+extern int llc_sap_action_send_test_r(struct llc_sap *sap,
+				      struct llc_sap_state_ev *ev);
+extern int llc_sap_action_report_status(struct llc_sap *sap,
+					struct llc_sap_state_ev *ev);
+extern int llc_sap_action_xid_ind(struct llc_sap *sap,
+				  struct llc_sap_state_ev *ev);
+extern int llc_sap_action_test_ind(struct llc_sap *sap,
+				   struct llc_sap_state_ev *ev);
+#endif /* LLC_S_AC_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/net/llc_sap.h linux.20pre10-ac2/include/net/llc_sap.h
--- linux.20pre10/include/net/llc_sap.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/net/llc_sap.h	2002-10-11 00:35:04.000000000 +0100
@@ -0,0 +1,42 @@
+#ifndef LLC_SAP_H
+#define LLC_SAP_H
+/*
+ * Copyright (c) 1997 by Procom Technology,Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/skbuff.h>
+/* Defines the SAP component */
+struct llc_sap {
+	u8		    state;
+	struct llc_station *parent_station;
+	u8		    p_bit;		/* only lowest-order bit used */
+	u8		    f_bit;		/* only lowest-order bit used */
+	llc_prim_call_t	    req;		/* provided by LLC layer */
+	llc_prim_call_t	    resp;		/* provided by LLC layer */
+	llc_prim_call_t	    ind;		/* provided by network layer */
+	llc_prim_call_t	    conf;		/* provided by network layer */
+	struct llc_addr	    laddr;		/* SAP value in this 'lsap' */
+	struct list_head    node;		/* entry in station sap_list */
+	struct {
+		spinlock_t	 lock;
+		struct list_head list;
+	} sk_list; /* LLC sockets this one manages */
+	struct sk_buff_head mac_pdu_q;		/* PDUs ready to send to MAC */
+};
+struct llc_sap_state_ev;
+
+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 llc_sap_state_ev *ev);
+extern void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb,
+			    struct llc_sap_state_ev *ev);
+extern void llc_sap_send_pdu(struct llc_sap *sap, struct sk_buff *skb);
+extern struct llc_sap_state_ev *llc_sap_alloc_ev(struct llc_sap *sap);
+#endif /* LLC_SAP_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/net/llc_s_ev.h linux.20pre10-ac2/include/net/llc_s_ev.h
--- linux.20pre10/include/net/llc_s_ev.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/net/llc_s_ev.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,101 @@
+#ifndef LLC_S_EV_H
+#define LLC_S_EV_H
+/*
+ * Copyright (c) 1997 by Procom Technology,Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+/* Defines SAP component events */
+/* Types of events (possible values in 'ev->type') */
+#define LLC_SAP_EV_TYPE_SIMPLE		1
+#define LLC_SAP_EV_TYPE_CONDITION	2
+#define LLC_SAP_EV_TYPE_PRIM		3
+#define LLC_SAP_EV_TYPE_PDU		4   /* command/response PDU */
+#define LLC_SAP_EV_TYPE_ACK_TMR		5
+#define LLC_SAP_EV_TYPE_RPT_STATUS	6
+
+#define LLC_SAP_EV_ACTIVATION_REQ	 1
+#define LLC_SAP_EV_RX_UI		 2
+#define LLC_SAP_EV_UNITDATA_REQ		 3
+#define LLC_SAP_EV_XID_REQ		 4
+#define LLC_SAP_EV_RX_XID_C		 5
+#define LLC_SAP_EV_RX_XID_R		 6
+#define LLC_SAP_EV_TEST_REQ		 7
+#define LLC_SAP_EV_RX_TEST_C		 8
+#define LLC_SAP_EV_RX_TEST_R		 9
+#define LLC_SAP_EV_DEACTIVATION_REQ	10
+
+/* Interfaces for various types of supported events */
+struct llc_sap_ev_simple_if {
+	u8 ev;
+};
+
+struct llc_prim_if_block;
+
+struct llc_sap_ev_prim_if {
+	u8			  prim; /* connect, disconnect, reset, ... */
+	u8			  type; /* request, indicate, response, conf */
+	struct llc_prim_if_block *data;
+};
+
+struct llc_sap_ev_pdu_if {
+	u8		   ev;
+	u8		   reason;
+	struct sk_buff *skb;
+};
+
+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;
+
+struct llc_sap_state_ev {
+	u8			  type;
+	u8			  ind_cfm_flag;
+	struct llc_prim_if_block *prim;
+	union llc_sap_ev_if	  data;
+};
+
+struct llc_sap;
+
+typedef int (*llc_sap_ev_t)(struct llc_sap *sap, struct llc_sap_state_ev *ev);
+
+extern int llc_sap_ev_activation_req(struct llc_sap *sap,
+				     struct llc_sap_state_ev *ev);
+extern int llc_sap_ev_rx_ui(struct llc_sap *sap, struct llc_sap_state_ev *ev);
+extern int llc_sap_ev_unitdata_req(struct llc_sap *sap,
+				   struct llc_sap_state_ev *ev);
+extern int llc_sap_ev_xid_req(struct llc_sap *sap,
+			      struct llc_sap_state_ev *ev);
+extern int llc_sap_ev_rx_xid_c(struct llc_sap *sap,
+			       struct llc_sap_state_ev *ev);
+extern int llc_sap_ev_rx_xid_r(struct llc_sap *sap,
+			       struct llc_sap_state_ev *ev);
+extern int llc_sap_ev_test_req(struct llc_sap *sap,
+			       struct llc_sap_state_ev *ev);
+extern int llc_sap_ev_rx_test_c(struct llc_sap *sap,
+				struct llc_sap_state_ev *ev);
+extern int llc_sap_ev_rx_test_r(struct llc_sap *sap,
+				struct llc_sap_state_ev *ev);
+extern int llc_sap_ev_deactivation_req(struct llc_sap *sap,
+				       struct llc_sap_state_ev *ev);
+#endif /* LLC_S_EV_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/net/llc_s_st.h linux.20pre10-ac2/include/net/llc_s_st.h
--- linux.20pre10/include/net/llc_s_st.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/net/llc_s_st.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,34 @@
+#ifndef LLC_S_ST_H
+#define LLC_S_ST_H
+/*
+ * Copyright (c) 1997 by Procom Technology,Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+/* Defines SAP component states */
+
+#define LLC_SAP_STATE_INACTIVE	1
+#define LLC_SAP_STATE_ACTIVE	2
+#define LLC_NBR_SAP_STATES	2       /* size of state table */
+/* structures and types */
+/* SAP state table structure */
+struct llc_sap_state_trans {
+	llc_sap_ev_t	  ev;
+	u8		  next_state;
+	llc_sap_action_t *ev_actions;
+};
+
+struct llc_sap_state {
+    u8				 curr_state;
+    struct llc_sap_state_trans **transitions;
+};
+
+/* only access to SAP state table */
+extern struct llc_sap_state llc_sap_state_table[LLC_NBR_SAP_STATES];
+#endif /* LLC_S_ST_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/net/llc_stat.h linux.20pre10-ac2/include/net/llc_stat.h
--- linux.20pre10/include/net/llc_stat.h	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/include/net/llc_stat.h	2002-08-06 15:41:52.000000000 +0100
@@ -0,0 +1,35 @@
+#ifndef LLC_STAT_H
+#define LLC_STAT_H
+/*
+ * Copyright (c) 1997 by Procom Technology,Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+/* Station component state table */
+/* Station component states */
+#define LLC_STATION_STATE_DOWN		1	/* initial state */
+#define LLC_STATION_STATE_DUP_ADDR_CHK	2
+#define LLC_STATION_STATE_UP		3
+
+#define LLC_NBR_STATION_STATES		3	/* size of state table */
+
+/* Station component state table structure */
+struct llc_station_state_trans {
+	llc_station_ev_t ev;
+	u8 next_state;
+	llc_station_action_t *ev_actions;
+};
+
+struct llc_station_state {
+	u8 curr_state;
+	struct llc_station_state_trans **transitions;
+};
+
+extern struct llc_station_state llc_station_state_table[LLC_NBR_STATION_STATES];
+#endif /* LLC_STAT_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/include/net/p8022.h linux.20pre10-ac2/include/net/p8022.h
--- linux.20pre10/include/net/p8022.h	2002-10-09 21:36:37.000000000 +0100
+++ linux.20pre10-ac2/include/net/p8022.h	2002-08-06 15:41:52.000000000 +0100
@@ -1,7 +1,9 @@
 #ifndef _NET_P8022_H
 #define _NET_P8022_H
-
-extern struct datalink_proto *register_8022_client(unsigned char type, int (*rcvfunc)(struct sk_buff *, struct net_device *, struct packet_type *));
+extern struct datalink_proto *register_8022_client(unsigned char type,
+						   int (*rcvfunc)
+						   	(struct sk_buff *,
+							 struct net_device *,
+							 struct packet_type *));
 extern void unregister_8022_client(unsigned char type);
-
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/init/do_mounts.c linux.20pre10-ac2/init/do_mounts.c
--- linux.20pre10/init/do_mounts.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/init/do_mounts.c	2002-10-07 21:40:06.000000000 +0100
@@ -164,7 +164,6 @@
 	{ "dasdg", (DASD_MAJOR << MINORBITS) + (6 << 2) },
 	{ "dasdh", (DASD_MAJOR << MINORBITS) + (7 << 2) },
 #endif
-#if defined(CONFIG_BLK_CPQ_DA) || defined(CONFIG_BLK_CPQ_DA_MODULE)
 	{ "ida/c0d0p",0x4800 },
 	{ "ida/c0d1p",0x4810 },
 	{ "ida/c0d2p",0x4820 },
@@ -181,15 +180,6 @@
 	{ "ida/c0d13p",0x48D0 },
 	{ "ida/c0d14p",0x48E0 },
 	{ "ida/c0d15p",0x48F0 },
-	{ "ida/c1d0p",0x4900 },
-	{ "ida/c2d0p",0x4A00 },
-	{ "ida/c3d0p",0x4B00 },
-	{ "ida/c4d0p",0x4C00 },
-	{ "ida/c5d0p",0x4D00 },
-	{ "ida/c6d0p",0x4E00 },
-	{ "ida/c7d0p",0x4F00 }, 
-#endif
-#if defined(CONFIG_BLK_CPQ_CISS_DA) || defined(CONFIG_BLK_CPQ_CISS_DA_MODULE)
 	{ "cciss/c0d0p",0x6800 },
 	{ "cciss/c0d1p",0x6810 },
 	{ "cciss/c0d2p",0x6820 },
@@ -206,14 +196,6 @@
 	{ "cciss/c0d13p",0x68D0 },
 	{ "cciss/c0d14p",0x68E0 },
 	{ "cciss/c0d15p",0x68F0 },
-	{ "cciss/c1d0p",0x6900 },
-	{ "cciss/c2d0p",0x6A00 },
-	{ "cciss/c3d0p",0x6B00 },
-	{ "cciss/c4d0p",0x6C00 },
-	{ "cciss/c5d0p",0x6D00 },
-	{ "cciss/c6d0p",0x6E00 },
-	{ "cciss/c7d0p",0x6F00 },
-#endif
 	{ "ataraid/d0p",0x7200 },
 	{ "ataraid/d1p",0x7210 },
 	{ "ataraid/d2p",0x7220 },
@@ -230,6 +212,24 @@
 	{ "ataraid/d13p",0x72D0 },
 	{ "ataraid/d14p",0x72E0 },
 	{ "ataraid/d15p",0x72F0 },
+        { "rd/c0d0p",0x3000 },
+        { "rd/c0d0p1",0x3001 },
+        { "rd/c0d0p2",0x3002 },
+        { "rd/c0d0p3",0x3003 },
+        { "rd/c0d0p4",0x3004 },
+        { "rd/c0d0p5",0x3005 },
+        { "rd/c0d0p6",0x3006 },
+        { "rd/c0d0p7",0x3007 },
+        { "rd/c0d0p8",0x3008 },
+        { "rd/c0d1p",0x3008 },
+        { "rd/c0d1p1",0x3009 },
+        { "rd/c0d1p2",0x300a },
+        { "rd/c0d1p3",0x300b },
+        { "rd/c0d1p4",0x300c },
+        { "rd/c0d1p5",0x300d },
+        { "rd/c0d1p6",0x300e },
+        { "rd/c0d1p7",0x300f },
+        { "rd/c0d1p8",0x3010 },
 	{ "nftla", 0x5d00 },
 	{ "nftlb", 0x5d10 },
 	{ "nftlc", 0x5d20 },
@@ -886,6 +886,8 @@
 	mount_devfs_fs ();
 }
 
+#ifdef CONFIG_BLK_DEV_RAM
+
 #if defined(BUILD_CRAMDISK) && defined(CONFIG_BLK_DEV_RAM)
 
 /*
@@ -1032,3 +1034,4 @@
 }
 
 #endif  /* BUILD_CRAMDISK && CONFIG_BLK_DEV_RAM */
+#endif  /* CONFIG_BLK_DEV_RAM */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/init/main.c linux.20pre10-ac2/init/main.c
--- linux.20pre10/init/main.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/init/main.c	2002-09-29 21:11:31.000000000 +0100
@@ -60,6 +60,10 @@
 #include <linux/isapnp.h>
 #endif
 
+#ifdef CONFIG_PNPBIOS
+#include <linux/pnpbios.h>
+#endif
+
 #ifdef CONFIG_IRDA
 extern int irda_proto_init(void);
 extern int irda_device_init(void);
@@ -106,6 +110,10 @@
 #if defined(CONFIG_SYSVIPC)
 extern void ipc_init(void);
 #endif
+ 
+#ifdef CONFIG_PARISC
+extern void parisc_init(void);
+#endif
 
 /*
  * Boot command-line arguments
@@ -288,8 +296,6 @@
 extern void setup_arch(char **);
 extern void cpu_idle(void);
 
-unsigned long wait_init_idle;
-
 #ifndef CONFIG_SMP
 
 #ifdef CONFIG_X86_LOCAL_APIC
@@ -298,34 +304,24 @@
 	APIC_init_uniprocessor();
 }
 #else
-#define smp_init()	do { } while (0)
+#define smp_init()      do { } while (0)
 #endif
 
 #else
 
-
 /* Called by boot processor to activate the rest. */
 static void __init smp_init(void)
 {
 	/* Get other processors into their bootup holding patterns. */
 	smp_boot_cpus();
-	wait_init_idle = cpu_online_map;
-	clear_bit(current->processor, &wait_init_idle); /* Don't wait on me! */
 
 	smp_threads_ready=1;
 	smp_commence();
-
-	/* Wait for the other cpus to set up their idle processes */
-	printk("Waiting on wait_init_idle (map = 0x%lx)\n", wait_init_idle);
-	while (wait_init_idle) {
-		cpu_relax();
-		barrier();
-	}
-	printk("All processors have done init_idle\n");
 }
 
 #endif
 
+
 /*
  * We need to finalize in a non-__init function or else race conditions
  * between the root thread and the init thread may cause start_kernel to
@@ -337,9 +333,8 @@
 {
 	kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGNAL);
 	unlock_kernel();
-	current->need_resched = 1;
- 	cpu_idle();
-} 
+	cpu_idle();
+}
 
 /*
  *	Activate the first processor.
@@ -420,18 +415,25 @@
 #ifdef CONFIG_PROC_FS
 	proc_root_init();
 #endif
+#ifdef CONFIG_PARISC
+	parisc_init();
+#endif
 #if defined(CONFIG_SYSVIPC)
 	ipc_init();
 #endif
 	check_bugs();
+
 	printk("POSIX conformance testing by UNIFIX\n");
 
-	/* 
-	 *	We count on the initial thread going ok 
-	 *	Like idlers init is an unlocked kernel thread, which will
-	 *	make syscalls (and thus be locked).
+	init_idle(current, smp_processor_id());
+	/*
+	 *      We count on the initial thread going ok
+	 *      Like idlers init is an unlocked kernel thread, which will
+	 *      make syscalls (and thus be locked).
 	 */
 	smp_init();
+
+	/* Do the rest non-__init'ed, we're now alive */
 	rest_init();
 }
 
@@ -460,6 +462,10 @@
  */
 static void __init do_basic_setup(void)
 {
+	/* Start the per-CPU migration threads */
+#if CONFIG_SMP
+	migration_init();
+#endif
 
 	/*
 	 * Tell the world that we're going to be the grim
@@ -519,6 +525,9 @@
 #ifdef CONFIG_ISAPNP
 	isapnp_init();
 #endif
+#ifdef CONFIG_PNPBIOS
+	pnpbios_init();
+#endif
 #ifdef CONFIG_TC
 	tc_init();
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/ipc/shm.c linux.20pre10-ac2/ipc/shm.c
--- linux.20pre10/ipc/shm.c	2002-10-09 21:36:43.000000000 +0100
+++ linux.20pre10-ac2/ipc/shm.c	2002-08-06 15:42:06.000000000 +0100
@@ -680,7 +680,7 @@
 		shmdnext = shmd->vm_next;
 		if (shmd->vm_ops == &shm_vm_ops
 		    && shmd->vm_start - (shmd->vm_pgoff << PAGE_SHIFT) == (ulong) shmaddr) {
-			do_munmap(mm, shmd->vm_start, shmd->vm_end - shmd->vm_start);
+			do_munmap(mm, shmd->vm_start, shmd->vm_end - shmd->vm_start, 1);
 			retval = 0;
 		}
 	}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/kernel/acct.c linux.20pre10-ac2/kernel/acct.c
--- linux.20pre10/kernel/acct.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/kernel/acct.c	2002-08-06 15:41:51.000000000 +0100
@@ -53,6 +53,7 @@
 #include <linux/acct.h>
 #include <linux/smp_lock.h>
 #include <linux/file.h>
+#include <linux/highuid.h>
 #include <linux/tty.h>
 
 #include <asm/uaccess.h>
@@ -299,8 +300,10 @@
 	ac.ac_etime = encode_comp_t(jiffies - current->start_time);
 	ac.ac_utime = encode_comp_t(current->times.tms_utime);
 	ac.ac_stime = encode_comp_t(current->times.tms_stime);
-	ac.ac_uid = current->uid;
-	ac.ac_gid = current->gid;
+	ac.ac_uid = fs_high2lowuid(current->uid);
+	ac.ac_gid = fs_high2lowgid(current->gid);
+	ac.ac_uid32 = current->uid;
+	ac.ac_gid32 = current->gid;
 	ac.ac_tty = (current->tty) ? kdev_t_to_nr(current->tty->device) : 0;
 
 	ac.ac_flag = 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/kernel/capability.c linux.20pre10-ac2/kernel/capability.c
--- linux.20pre10/kernel/capability.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/kernel/capability.c	2002-08-06 15:41:51.000000000 +0100
@@ -8,6 +8,8 @@
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 
+unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */
+
 kernel_cap_t cap_bset = CAP_INIT_EFF_SET;
 
 /* Note: never hold tasklist_lock while spinning for this one */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/kernel/cpufreq.c linux.20pre10-ac2/kernel/cpufreq.c
--- linux.20pre10/kernel/cpufreq.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/kernel/cpufreq.c	2002-10-10 23:54:37.000000000 +0100
@@ -0,0 +1,1092 @@
+/*
+ *  linux/kernel/cpufreq.c
+ *
+ *  Copyright (C) 2001 Russell King
+ *            (C) 2002 Dominik Brodowski <linux@brodo.de>
+ *
+ *  $Id: cpufreq.c,v 1.45 2002/10/08 14:54:23 db Exp $
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/notifier.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/ctype.h>
+#include <linux/proc_fs.h>
+
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_CPU_FREQ_24_API
+#include <linux/sysctl.h>
+#endif
+
+
+/**
+ * The "cpufreq driver" - the arch- or hardware-dependend low
+ * level driver of CPUFreq support, and its locking mutex. 
+ * cpu_max_freq is in kHz.
+ */
+static struct cpufreq_driver   	*cpufreq_driver;
+static DECLARE_MUTEX            (cpufreq_driver_sem);
+
+
+/**
+ * Two notifier lists: the "policy" list is involved in the 
+ * validation process for a new CPU frequency policy; the 
+ * "transition" list for kernel code that needs to handle
+ * changes to devices when the CPU clock speed changes.
+ * The mutex locks both lists. If both cpufreq_driver_sem
+ * and cpufreq_notifier_sem need to be hold, get cpufreq_driver_sem
+ * first.
+ */
+static struct notifier_block    *cpufreq_policy_notifier_list;
+static struct notifier_block    *cpufreq_transition_notifier_list;
+static DECLARE_MUTEX            (cpufreq_notifier_sem);
+
+
+/**
+ * The cpufreq default policy. Can be set by a "cpufreq=..." command
+ * line option.
+ */
+static struct cpufreq_policy default_policy = {
+	.cpu    = CPUFREQ_ALL_CPUS,
+	.min    = 0,
+	.max    = 0,
+	.policy = 0,
+};
+
+
+#ifdef CONFIG_CPU_FREQ_24_API
+/**
+ * A few values needed by the 2.4.-compatible API
+ */
+static unsigned int     cpu_max_freq;
+static unsigned int     cpu_min_freq;
+static unsigned int     cpu_cur_freq[NR_CPUS];
+#endif
+
+
+
+/*********************************************************************
+ *                              2.6. API                             *
+ *********************************************************************/
+
+/**
+ * cpufreq_parse_policy - parse a policy string
+ * @input_string: the string to parse.
+ * @policy: the policy written inside input_string
+ *
+ * This function parses a "policy string" - something the user echo'es into
+ * /proc/cpufreq or gives as boot parameter - into a struct cpufreq_policy.
+ * If there are invalid/missing entries, they are replaced with current
+ * cpufreq policy.
+ */
+static int cpufreq_parse_policy(char input_string[42], struct cpufreq_policy *policy)
+{
+	unsigned int            min = 0;
+	unsigned int            max = 0;
+	unsigned int            cpu = 0;
+	char			policy_string[42] = {'\0'};
+	struct cpufreq_policy   current_policy;
+	unsigned int            result = -EFAULT;
+	unsigned int            i = 0;
+
+	if (!policy)
+		return -EINVAL;
+
+	policy->min = 0;
+	policy->max = 0;
+	policy->policy = 0;
+	policy->cpu = CPUFREQ_ALL_CPUS;
+
+	if (sscanf(input_string, "%d:%d:%d:%s", &cpu, &min, &max, policy_string) == 4) 
+	{
+		policy->min = min;
+		policy->max = max;
+		policy->cpu = cpu;
+		result = 0;
+		goto scan_policy;
+	}
+	if (sscanf(input_string, "%d%%%d%%%d%%%s", &cpu, &min, &max, policy_string) == 4)
+	{
+		if (!cpufreq_get_policy(&current_policy, cpu)) {
+			policy->min = (min * current_policy.max_cpu_freq) / 100;
+			policy->max = (max * current_policy.max_cpu_freq) / 100;
+			policy->cpu = cpu;
+			result = 0;
+			goto scan_policy;
+		}
+	}
+
+	if (sscanf(input_string, "%d:%d:%s", &min, &max, policy_string) == 3) 
+	{
+		policy->min = min;
+		policy->max = max;
+		result = 0;
+		goto scan_policy;
+	}
+
+	if (sscanf(input_string, "%d%%%d%%%s", &min, &max, policy_string) == 3)
+	{
+		if (!cpufreq_get_policy(&current_policy, cpu)) {
+			policy->min = (min * current_policy.max_cpu_freq) / 100;
+			policy->max = (max * current_policy.max_cpu_freq) / 100;
+			result = 0;
+			goto scan_policy;
+		}
+	}
+
+	return -EINVAL;
+
+scan_policy:
+
+	for (i=0;i<sizeof(policy_string);i++){
+		if (policy_string[i]=='\0')
+			break;
+		policy_string[i] = tolower(policy_string[i]);
+	}
+
+	if (!strncmp(policy_string, "powersave", 6) ||  
+            !strncmp(policy_string, "eco", 3) ||       
+	    !strncmp(policy_string, "batter", 6) ||
+	    !strncmp(policy_string, "low", 3)) 
+	{
+		result = 0;
+		policy->policy = CPUFREQ_POLICY_POWERSAVE;
+	}
+	else if (!strncmp(policy_string, "performance",6) ||
+	    !strncmp(policy_string, "high",4) ||
+	    !strncmp(policy_string, "full",4))
+	{
+		result = 0;
+		policy->policy = CPUFREQ_POLICY_PERFORMANCE;
+	}
+	else if (!cpufreq_get_policy(&current_policy, policy->cpu))
+	{
+		policy->policy = current_policy.policy;
+	}
+	else
+	{
+		policy->policy = 0;
+	}
+
+	return result;
+}
+
+
+/*
+ * cpufreq command line parameter.  Must be hard values (kHz)
+ *  cpufreq=1000000:2000000:PERFORMANCE   
+ * to set the default CPUFreq policy.
+ */
+static int __init cpufreq_setup(char *str)
+{
+	cpufreq_parse_policy(str, &default_policy);
+	default_policy.cpu = CPUFREQ_ALL_CPUS;
+	return 1;
+}
+__setup("cpufreq=", cpufreq_setup);
+
+
+#ifdef CONFIG_PROC_FS
+
+/**
+ * cpufreq_proc_read - read /proc/cpufreq
+ *
+ * This function prints out the current cpufreq policy.
+ */
+static int cpufreq_proc_read (
+	char			*page,
+	char			**start,
+	off_t			off,
+	int 			count,
+	int 			*eof,
+	void			*data)
+{
+	char			*p = page;
+	int			len = 0;
+	struct cpufreq_policy   policy;
+	unsigned int            min_pctg = 0;
+	unsigned int            max_pctg = 0;
+	unsigned int            i = 0;
+
+	if (off != 0)
+		goto end;
+
+	p += sprintf(p, "          minimum CPU frequency  -  maximum CPU frequency  -  policy\n");
+	for (i=0;i<NR_CPUS;i++) {
+		if (!cpu_online(i))
+			continue;
+
+		cpufreq_get_policy(&policy, i);
+		min_pctg = (policy.min * 100) / policy.max_cpu_freq;
+		max_pctg = (policy.max * 100) / policy.max_cpu_freq;
+
+		p += sprintf(p, "CPU%3d    %9d kHz (%3d %%)  -  %9d kHz (%3d %%)  -  ",
+			     i , policy.min, min_pctg, policy.max, max_pctg);
+		switch (policy.policy) {
+		case CPUFREQ_POLICY_POWERSAVE:
+			p += sprintf(p, "powersave\n");
+			break;
+		case CPUFREQ_POLICY_PERFORMANCE:
+			p += sprintf(p, "performance\n");
+			break;
+		default:
+			p += sprintf(p, "INVALID\n");
+			break;
+		}
+	}
+end:
+	len = (p - page);
+	if (len <= off+count) 
+		*eof = 1;
+	*start = page + off;
+	len -= off;
+	if (len>count) 
+		len = count;
+	if (len<0) 
+		len = 0;
+
+	return len;
+}
+
+
+/**
+ * cpufreq_proc_write - handles writing into /proc/cpufreq
+ *
+ * This function calls the parsing script and then sets the policy
+ * accordingly.
+ */
+static int cpufreq_proc_write (
+        struct file		*file,
+        const char		*buffer,
+        unsigned long		count,
+        void			*data)
+{
+	int                     result = 0;
+	char			proc_string[42] = {'\0'};
+	struct cpufreq_policy   policy;
+
+
+	if ((count > sizeof(proc_string) - 1))
+		return -EINVAL;
+	
+	if (copy_from_user(proc_string, buffer, count))
+		return -EFAULT;
+	
+	proc_string[count] = '\0';
+
+	result = cpufreq_parse_policy(proc_string, &policy);
+	if (result)
+		return -EFAULT;
+
+	cpufreq_set_policy(&policy);
+
+	return count;
+}
+
+
+/**
+ * cpufreq_proc_init - add "cpufreq" to the /proc root directory
+ *
+ * This function adds "cpufreq" to the /proc root directory.
+ */
+static unsigned int cpufreq_proc_init (void)
+{
+	struct proc_dir_entry *entry = NULL;
+
+        /* are these acceptable values? */
+	entry = create_proc_entry("cpufreq", S_IFREG|S_IRUGO|S_IWUSR, 
+				  &proc_root);
+
+	if (!entry) {
+		printk(KERN_ERR "unable to create /proc/cpufreq entry\n");
+		return -EIO;
+	} else {
+		entry->read_proc = cpufreq_proc_read;
+		entry->write_proc = cpufreq_proc_write;
+	}
+
+	return 0;
+}
+
+
+/**
+ * cpufreq_proc_exit - removes "cpufreq" from the /proc root directory.
+ *
+ * This function removes "cpufreq" from the /proc root directory.
+ */
+static void cpufreq_proc_exit (void)
+{
+	remove_proc_entry("cpufreq", &proc_root);
+	return;
+}
+#endif /* CONFIG_PROC_FS */
+
+
+
+/*********************************************************************
+ *                        2.4. COMPATIBLE API                        *
+ *********************************************************************/
+
+#ifdef CONFIG_CPU_FREQ_24_API
+/** 
+ * cpufreq_set - set the CPU frequency
+ * @freq: target frequency in kHz
+ * @cpu: CPU for which the frequency is to be set
+ *
+ * Sets the CPU frequency to freq.
+ */
+int cpufreq_set(unsigned int freq, unsigned int cpu)
+{
+	struct cpufreq_policy policy;
+	down(&cpufreq_driver_sem);
+	if (!cpufreq_driver || !cpu_max_freq) {
+		up(&cpufreq_driver_sem);
+		return -EINVAL;
+	}
+
+	policy.min = freq;
+	policy.max = freq;
+	policy.policy = CPUFREQ_POLICY_POWERSAVE;
+	policy.cpu = cpu;
+	
+	up(&cpufreq_driver_sem);
+
+	return cpufreq_set_policy(&policy);
+}
+EXPORT_SYMBOL_GPL(cpufreq_set);
+
+
+/** 
+ * cpufreq_setmax - set the CPU to the maximum frequency
+ * @cpu - affected cpu;
+ *
+ * Sets the CPU frequency to the maximum frequency supported by
+ * this CPU.
+ */
+int cpufreq_setmax(unsigned int cpu)
+{
+	if (!cpu_online(cpu) && (cpu != CPUFREQ_ALL_CPUS))
+		return -EINVAL;
+	return cpufreq_set(cpu_max_freq, cpu);
+}
+EXPORT_SYMBOL_GPL(cpufreq_setmax);
+
+
+/** 
+ * cpufreq_get - get the current CPU frequency (in kHz)
+ * @cpu: CPU number - currently without effect.
+ *
+ * Get the CPU current (static) CPU frequency
+ */
+unsigned int cpufreq_get(unsigned int cpu)
+{
+	if (!cpu_online(cpu))
+		return -EINVAL;
+	return cpu_cur_freq[cpu];
+}
+EXPORT_SYMBOL(cpufreq_get);
+
+
+#ifdef CONFIG_SYSCTL
+
+
+/*********************** cpufreq_sysctl interface ********************/
+static int
+cpufreq_procctl(ctl_table *ctl, int write, struct file *filp,
+		void *buffer, size_t *lenp)
+{
+	char buf[16], *p;
+	int cpu = (int) ctl->extra1;
+	int len, left = *lenp;
+
+	if (!left || (filp->f_pos && !write) || !cpu_online(cpu)) {
+		*lenp = 0;
+		return 0;
+	}
+
+	if (write) {
+		unsigned int freq;
+
+		len = left;
+		if (left > sizeof(buf))
+			left = sizeof(buf);
+		if (copy_from_user(buf, buffer, left))
+			return -EFAULT;
+		buf[sizeof(buf) - 1] = '\0';
+
+		freq = simple_strtoul(buf, &p, 0);
+		cpufreq_set(freq, cpu);
+	} else {
+		len = sprintf(buf, "%d\n", cpufreq_get(cpu));
+		if (len > left)
+			len = left;
+		if (copy_to_user(buffer, buf, len))
+			return -EFAULT;
+	}
+
+	*lenp = len;
+	filp->f_pos += len;
+	return 0;
+}
+
+static int
+cpufreq_sysctl(ctl_table *table, int *name, int nlen,
+	       void *oldval, size_t *oldlenp,
+	       void *newval, size_t newlen, void **context)
+{
+	int cpu = (int) table->extra1;
+
+	if (!cpu_online(cpu))
+		return -EINVAL;
+
+	if (oldval && oldlenp) {
+		size_t oldlen;
+
+		if (get_user(oldlen, oldlenp))
+			return -EFAULT;
+
+		if (oldlen != sizeof(unsigned int))
+			return -EINVAL;
+
+		if (put_user(cpufreq_get(cpu), (unsigned int *)oldval) ||
+		    put_user(sizeof(unsigned int), oldlenp))
+			return -EFAULT;
+	}
+	if (newval && newlen) {
+		unsigned int freq;
+
+		if (newlen != sizeof(unsigned int))
+			return -EINVAL;
+
+		if (get_user(freq, (unsigned int *)newval))
+			return -EFAULT;
+
+		cpufreq_set(freq, cpu);
+	}
+	return 1;
+}
+
+/* ctl_table ctl_cpu_vars_{0,1,...,(NR_CPUS-1)} */
+/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */
+        CTL_TABLE_CPU_VARS(0);
+#if NR_CPUS > 1
+	CTL_TABLE_CPU_VARS(1);
+#endif
+#if NR_CPUS > 2
+	CTL_TABLE_CPU_VARS(2);
+#endif
+#if NR_CPUS > 3
+	CTL_TABLE_CPU_VARS(3);
+#endif
+#if NR_CPUS > 4
+	CTL_TABLE_CPU_VARS(4);
+#endif
+#if NR_CPUS > 5
+	CTL_TABLE_CPU_VARS(5);
+#endif
+#if NR_CPUS > 6
+	CTL_TABLE_CPU_VARS(6);
+#endif
+#if NR_CPUS > 7
+	CTL_TABLE_CPU_VARS(7);
+#endif
+#if NR_CPUS > 8
+	CTL_TABLE_CPU_VARS(8);
+#endif
+#if NR_CPUS > 9
+	CTL_TABLE_CPU_VARS(9);
+#endif
+#if NR_CPUS > 10
+	CTL_TABLE_CPU_VARS(10);
+#endif
+#if NR_CPUS > 11
+	CTL_TABLE_CPU_VARS(11);
+#endif
+#if NR_CPUS > 12
+	CTL_TABLE_CPU_VARS(12);
+#endif
+#if NR_CPUS > 13
+	CTL_TABLE_CPU_VARS(13);
+#endif
+#if NR_CPUS > 14
+	CTL_TABLE_CPU_VARS(14);
+#endif
+#if NR_CPUS > 15
+	CTL_TABLE_CPU_VARS(15);
+#endif
+#if NR_CPUS > 16
+	CTL_TABLE_CPU_VARS(16);
+#endif
+#if NR_CPUS > 17
+	CTL_TABLE_CPU_VARS(17);
+#endif
+#if NR_CPUS > 18
+	CTL_TABLE_CPU_VARS(18);
+#endif
+#if NR_CPUS > 19
+	CTL_TABLE_CPU_VARS(19);
+#endif
+#if NR_CPUS > 20
+	CTL_TABLE_CPU_VARS(20);
+#endif
+#if NR_CPUS > 21
+	CTL_TABLE_CPU_VARS(21);
+#endif
+#if NR_CPUS > 22
+	CTL_TABLE_CPU_VARS(22);
+#endif
+#if NR_CPUS > 23
+	CTL_TABLE_CPU_VARS(23);
+#endif
+#if NR_CPUS > 24
+	CTL_TABLE_CPU_VARS(24);
+#endif
+#if NR_CPUS > 25
+	CTL_TABLE_CPU_VARS(25);
+#endif
+#if NR_CPUS > 26
+	CTL_TABLE_CPU_VARS(26);
+#endif
+#if NR_CPUS > 27
+	CTL_TABLE_CPU_VARS(27);
+#endif
+#if NR_CPUS > 28
+	CTL_TABLE_CPU_VARS(28);
+#endif
+#if NR_CPUS > 29
+	CTL_TABLE_CPU_VARS(29);
+#endif
+#if NR_CPUS > 30
+	CTL_TABLE_CPU_VARS(30);
+#endif
+#if NR_CPUS > 31
+	CTL_TABLE_CPU_VARS(31);
+#endif
+#if NR_CPUS > 32
+#error please extend CPU enumeration
+#endif
+
+/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */
+static ctl_table ctl_cpu_table[NR_CPUS + 1] = {
+	CPU_ENUM(0),
+#if NR_CPUS > 1
+	CPU_ENUM(1),
+#endif
+#if NR_CPUS > 2
+	CPU_ENUM(2),
+#endif
+#if NR_CPUS > 3
+	CPU_ENUM(3),
+#endif
+#if NR_CPUS > 4
+	CPU_ENUM(4),
+#endif
+#if NR_CPUS > 5
+	CPU_ENUM(5),
+#endif
+#if NR_CPUS > 6
+	CPU_ENUM(6),
+#endif
+#if NR_CPUS > 7
+	CPU_ENUM(7),
+#endif
+#if NR_CPUS > 8
+	CPU_ENUM(8),
+#endif
+#if NR_CPUS > 9
+	CPU_ENUM(9),
+#endif
+#if NR_CPUS > 10
+	CPU_ENUM(10),
+#endif
+#if NR_CPUS > 11
+	CPU_ENUM(11),
+#endif
+#if NR_CPUS > 12
+	CPU_ENUM(12),
+#endif
+#if NR_CPUS > 13
+	CPU_ENUM(13),
+#endif
+#if NR_CPUS > 14
+	CPU_ENUM(14),
+#endif
+#if NR_CPUS > 15
+	CPU_ENUM(15),
+#endif
+#if NR_CPUS > 16
+	CPU_ENUM(16),
+#endif
+#if NR_CPUS > 17
+	CPU_ENUM(17),
+#endif
+#if NR_CPUS > 18
+	CPU_ENUM(18),
+#endif
+#if NR_CPUS > 19
+	CPU_ENUM(19),
+#endif
+#if NR_CPUS > 20
+	CPU_ENUM(20),
+#endif
+#if NR_CPUS > 21
+	CPU_ENUM(21),
+#endif
+#if NR_CPUS > 22
+	CPU_ENUM(22),
+#endif
+#if NR_CPUS > 23
+	CPU_ENUM(23),
+#endif
+#if NR_CPUS > 24
+	CPU_ENUM(24),
+#endif
+#if NR_CPUS > 25
+	CPU_ENUM(25),
+#endif
+#if NR_CPUS > 26
+	CPU_ENUM(26),
+#endif
+#if NR_CPUS > 27
+	CPU_ENUM(27),
+#endif
+#if NR_CPUS > 28
+	CPU_ENUM(28),
+#endif
+#if NR_CPUS > 29
+	CPU_ENUM(29),
+#endif
+#if NR_CPUS > 30
+	CPU_ENUM(30),
+#endif
+#if NR_CPUS > 31
+	CPU_ENUM(31),
+#endif
+#if NR_CPUS > 32
+#error please extend CPU enumeration
+#endif
+	{
+		ctl_name:	0,
+	}
+};
+
+static ctl_table ctl_cpu[2] = {
+	{
+		ctl_name:	CTL_CPU,
+		procname:	"cpu",
+		mode:		0555,
+		child:		ctl_cpu_table,
+	},
+	{
+		ctl_name:	0,
+	}
+};
+
+struct ctl_table_header *cpufreq_sysctl_table;
+
+static inline void cpufreq_sysctl_init(void)
+{
+	cpufreq_sysctl_table = register_sysctl_table(ctl_cpu, 0);
+}
+
+static inline void cpufreq_sysctl_exit(void)
+{
+	unregister_sysctl_table(cpufreq_sysctl_table);
+}
+
+#else
+#define cpufreq_sysctl_init()
+#define cpufreq_sysctl_exit()
+#endif /* CONFIG_SYSCTL */
+#endif /* CONFIG_CPU_FREQ_24_API */
+
+
+
+/*********************************************************************
+ *                     NOTIFIER LISTS INTERFACE                      *
+ *********************************************************************/
+
+/**
+ *	cpufreq_register_notifier - register a driver with cpufreq
+ *	@nb: notifier function to register
+ *      @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER
+ *
+ *	Add a driver to one of two lists: either a list of drivers that 
+ *      are notified about clock rate changes (once before and once after
+ *      the transition), or a list of drivers that are notified about
+ *      changes in cpufreq policy.
+ *
+ *	This function may sleep, and has the same return conditions as
+ *	notifier_chain_register.
+ */
+int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list)
+{
+	int ret;
+
+	down(&cpufreq_notifier_sem);
+	switch (list) {
+	case CPUFREQ_TRANSITION_NOTIFIER:
+		ret = notifier_chain_register(&cpufreq_transition_notifier_list, nb);
+		break;
+	case CPUFREQ_POLICY_NOTIFIER:
+		ret = notifier_chain_register(&cpufreq_policy_notifier_list, nb);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	up(&cpufreq_notifier_sem);
+
+	return ret;
+}
+EXPORT_SYMBOL(cpufreq_register_notifier);
+
+
+/**
+ *	cpufreq_unregister_notifier - unregister a driver with cpufreq
+ *	@nb: notifier block to be unregistered
+ *      @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER
+ *
+ *	Remove a driver from the CPU frequency notifier list.
+ *
+ *	This function may sleep, and has the same return conditions as
+ *	notifier_chain_unregister.
+ */
+int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list)
+{
+	int ret;
+
+	down(&cpufreq_notifier_sem);
+	switch (list) {
+	case CPUFREQ_TRANSITION_NOTIFIER:
+		ret = notifier_chain_unregister(&cpufreq_transition_notifier_list, nb);
+		break;
+	case CPUFREQ_POLICY_NOTIFIER:
+		ret = notifier_chain_unregister(&cpufreq_policy_notifier_list, nb);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	up(&cpufreq_notifier_sem);
+
+	return ret;
+}
+EXPORT_SYMBOL(cpufreq_unregister_notifier);
+
+
+
+/*********************************************************************
+ *                          POLICY INTERFACE                         *
+ *********************************************************************/
+
+/**
+ * cpufreq_get_policy - get the current cpufreq_policy
+ * @policy: struct cpufreq_policy into which the current cpufreq_policy is written
+ *
+ * Reads the current cpufreq policy.
+ */
+int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu)
+{
+	down(&cpufreq_driver_sem);
+	if (!cpufreq_driver  || !policy || 
+	    (cpu >= NR_CPUS) || (!cpu_online(cpu))) {
+		up(&cpufreq_driver_sem);
+		return -EINVAL;
+	}
+	
+	policy->min    = cpufreq_driver->policy[cpu].min;
+	policy->max    = cpufreq_driver->policy[cpu].max;
+	policy->policy = cpufreq_driver->policy[cpu].policy;
+	policy->max_cpu_freq = cpufreq_driver->policy[0].max_cpu_freq;
+	policy->cpu    = cpu;
+
+	up(&cpufreq_driver_sem);
+
+	return 0;
+}
+
+
+/**
+ *	cpufreq_set_policy - set a new CPUFreq policy
+ *	@policy: policy to be set.
+ *
+ *	Sets a new CPU frequency and voltage scaling policy.
+ */
+int cpufreq_set_policy(struct cpufreq_policy *policy)
+{
+	unsigned int i;
+
+	down(&cpufreq_driver_sem);
+	if (!cpufreq_driver || !cpufreq_driver->verify || 
+	    !cpufreq_driver->setpolicy || !policy ||
+	    (policy->cpu > NR_CPUS)) {
+		up(&cpufreq_driver_sem);
+		return -EINVAL;
+	}
+
+	down(&cpufreq_notifier_sem);
+
+	policy->max_cpu_freq = cpufreq_driver->policy[0].max_cpu_freq;
+
+	/* verify the cpu speed can be set within this limit */
+	cpufreq_driver->verify(policy);
+
+	/* adjust if neccessary - all reasons */
+	notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_ADJUST,
+			    policy);
+
+	/* adjust if neccessary - hardware incompatibility*/
+	notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_INCOMPATIBLE,
+			    policy);
+
+	/* verify the cpu speed can be set within this limit,
+	   which might be different to the first one */
+	cpufreq_driver->verify(policy);
+
+	/* notification of the new policy */
+	notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_NOTIFY,
+			    policy);
+
+	up(&cpufreq_notifier_sem);
+
+	if (policy->cpu == CPUFREQ_ALL_CPUS) {
+		for (i=0;i<NR_CPUS;i++) {
+			cpufreq_driver->policy[i].min    = policy->min;
+			cpufreq_driver->policy[i].max    = policy->max;
+			cpufreq_driver->policy[i].policy = policy->policy;
+		} 
+	} else {
+		cpufreq_driver->policy[policy->cpu].min    = policy->min;
+		cpufreq_driver->policy[policy->cpu].max    = policy->max;
+		cpufreq_driver->policy[policy->cpu].policy = policy->policy;
+	}
+
+#ifdef CONFIG_CPU_FREQ_24_API
+	if (policy->cpu == CPUFREQ_ALL_CPUS) {
+		for (i=0;i<NR_CPUS;i++)
+			cpu_cur_freq[i] = policy->max;
+	} else
+		cpu_cur_freq[policy->cpu] = policy->max;
+#endif
+
+	cpufreq_driver->setpolicy(policy);
+	
+	up(&cpufreq_driver_sem);
+
+	return 0;
+}
+EXPORT_SYMBOL(cpufreq_set_policy);
+
+
+
+/*********************************************************************
+ *                    DYNAMIC CPUFREQ SWITCHING                      *
+ *********************************************************************/
+#ifdef CONFIG_CPU_FREQ_DYNAMIC
+/* TBD */
+#endif /* CONFIG_CPU_FREQ_DYNAMIC */
+
+
+
+/*********************************************************************
+ *            EXTERNALLY AFFECTING FREQUENCY CHANGES                 *
+ *********************************************************************/
+
+/**
+ * adjust_jiffies - adjust the system "loops_per_jiffy"
+ *
+ * This function alters the system "loops_per_jiffy" for the clock
+ * speed change. Note that loops_per_jiffy is only updated if all
+ * CPUs are affected - else there is a need for per-CPU loops_per_jiffy
+ * values which are provided by various architectures. 
+ */
+static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
+{
+	if ((val == CPUFREQ_PRECHANGE  && ci->old < ci->new) ||
+	    (val == CPUFREQ_POSTCHANGE && ci->old > ci->new))
+		if (ci->cpu == CPUFREQ_ALL_CPUS)
+			loops_per_jiffy = cpufreq_scale(loops_per_jiffy, ci->old, ci->new);
+}
+
+
+/**
+ * cpufreq_notify_transition - call notifier chain and adjust_jiffies on frequency transition
+ *
+ * This function calls the transition notifiers and the "adjust_jiffies" function. It is called
+ * twice on all CPU frequency changes that have external effects. 
+ */
+void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
+{
+	down(&cpufreq_notifier_sem);
+	switch (state) {
+	case CPUFREQ_PRECHANGE:
+		notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs);
+		adjust_jiffies(CPUFREQ_PRECHANGE, freqs);		
+		break;
+	case CPUFREQ_POSTCHANGE:
+		adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
+		notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs);
+#ifdef CONFIG_CPU_FREQ_24_API
+		if (freqs->cpu == CPUFREQ_ALL_CPUS) {
+			for (i=0;i<NR_CPUS;i++)
+				cpu_cur_freq[i] = freqs->new;
+		} else
+			cpu_cur_freq[freqs->cpu] = freqs->new;
+#endif
+		break;
+	}
+	up(&cpufreq_notifier_sem);
+}
+EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
+
+
+
+/*********************************************************************
+ *               REGISTER / UNREGISTER CPUFREQ DRIVER                *
+ *********************************************************************/
+
+/**
+ * cpufreq_register - register a CPU Frequency driver
+ * @driver_data: A struct cpufreq_driver containing the values submitted by the CPU Frequency driver.
+ *
+ *   Registers a CPU Frequency driver to this core code. This code 
+ * returns zero on success, -EBUSY when another driver got here first
+ * (and isn't unregistered in the meantime). 
+ *
+ */
+int cpufreq_register(struct cpufreq_driver *driver_data)
+{
+	unsigned int            ret;
+
+	if (cpufreq_driver)
+		return -EBUSY;
+	
+	if (!driver_data || !driver_data->verify || 
+	    !driver_data->setpolicy)
+		return -EINVAL;
+
+	down(&cpufreq_driver_sem);
+	cpufreq_driver        = driver_data;
+	
+	if (!default_policy.policy)
+		default_policy.policy = driver_data->policy[0].policy;
+	if (!default_policy.min)
+		default_policy.min = driver_data->policy[0].min;
+	if (!default_policy.max)
+		default_policy.max = driver_data->policy[0].max;
+	default_policy.cpu = CPUFREQ_ALL_CPUS;
+
+	up(&cpufreq_driver_sem);
+
+	ret = cpufreq_set_policy(&default_policy);
+
+	cpufreq_proc_init();
+
+#ifdef CONFIG_CPU_FREQ_24_API
+	down(&cpufreq_driver_sem);
+	cpu_min_freq          = driver_data->cpu_min_freq;
+	cpu_max_freq          = driver_data->policy[0].max_cpu_freq;
+	{
+		unsigned int i;
+		for (i=0; i<NR_CPUS; i++) {
+			cpu_cur_freq[i] = driver_data->cpu_cur_freq[i];
+		}
+	}
+	up(&cpufreq_driver_sem);
+
+	cpufreq_sysctl_init();
+#endif
+	if (ret) {
+		down(&cpufreq_driver_sem);
+		cpufreq_driver = NULL;
+		up(&cpufreq_driver_sem);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(cpufreq_register);
+
+
+/**
+ * cpufreq_unregister - unregister the current CPUFreq driver
+ *
+ *    Unregister the current CPUFreq driver. Only call this if you have 
+ * the right to do so, i.e. if you have succeeded in initialising before!
+ * Returns zero if successful, and -EINVAL if the cpufreq_driver is
+ * currently not initialised.
+ */
+int cpufreq_unregister(void)
+{
+	down(&cpufreq_driver_sem);
+
+	if (!cpufreq_driver) {
+		up(&cpufreq_driver_sem);
+		return -EINVAL;
+	}
+
+	cpufreq_driver = NULL;
+
+	up(&cpufreq_driver_sem);
+
+	cpufreq_proc_exit();
+
+#ifdef CONFIG_CPU_FREQ_24_API
+	cpufreq_sysctl_exit();
+#endif
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cpufreq_unregister);
+
+
+#ifdef CONFIG_PM
+/**
+ *	cpufreq_restore - restore the CPU clock frequency after resume
+ *
+ *	Restore the CPU clock frequency so that our idea of the current
+ *	frequency reflects the actual hardware.
+ */
+int cpufreq_restore(void)
+{
+	struct cpufreq_policy policy;
+	unsigned int i;
+
+	if (in_interrupt())
+		panic("cpufreq_restore() called from interrupt context!");
+
+	for (i=0;i<NR_CPUS;i++) {
+		if (!cpu_online(i))
+			continue;
+
+		down(&cpufreq_driver_sem);
+		if (!cpufreq_driver) {
+			up(&cpufreq_driver_sem);
+			return 0;
+		}
+	
+		policy.min    = cpufreq_driver->policy[i].min;
+		policy.max    = cpufreq_driver->policy[i].max;
+		policy.policy = cpufreq_driver->policy[i].policy;
+		policy.cpu    = i;
+		up(&cpufreq_driver_sem);
+
+		cpufreq_set_policy(&policy);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cpufreq_restore);
+#else
+#define cpufreq_restore()
+#endif /* CONFIG_PM */
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/kernel/exit.c linux.20pre10-ac2/kernel/exit.c
--- linux.20pre10/kernel/exit.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/kernel/exit.c	2002-10-09 21:52:07.000000000 +0100
@@ -28,49 +28,22 @@
 
 static void release_task(struct task_struct * p)
 {
-	if (p != current) {
+	if (p == current)
+		BUG();
 #ifdef CONFIG_SMP
-		/*
-		 * Wait to make sure the process isn't on the
-		 * runqueue (active on some other CPU still)
-		 */
-		for (;;) {
-			task_lock(p);
-			if (!task_has_cpu(p))
-				break;
-			task_unlock(p);
-			do {
-				cpu_relax();
-				barrier();
-			} while (task_has_cpu(p));
-		}
-		task_unlock(p);
+	wait_task_inactive(p);
 #endif
-		atomic_dec(&p->user->processes);
-		free_uid(p->user);
-		unhash_process(p);
-
-		release_thread(p);
-		current->cmin_flt += p->min_flt + p->cmin_flt;
-		current->cmaj_flt += p->maj_flt + p->cmaj_flt;
-		current->cnswap += p->nswap + p->cnswap;
-		/*
-		 * Potentially available timeslices are retrieved
-		 * here - this way the parent does not get penalized
-		 * for creating too many processes.
-		 *
-		 * (this cannot be used to artificially 'generate'
-		 * timeslices, because any timeslice recovered here
-		 * was given away by the parent in the first place.)
-		 */
-		current->counter += p->counter;
-		if (current->counter >= MAX_COUNTER)
-			current->counter = MAX_COUNTER;
-		p->pid = 0;
-		free_task_struct(p);
-	} else {
-		printk("task releasing itself\n");
-	}
+	atomic_dec(&p->user->processes);
+	free_uid(p->user);
+	unhash_process(p);
+
+	release_thread(p);
+	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);
+	p->pid = 0;
+	free_task_struct(p);
 }
 
 /*
@@ -150,6 +123,79 @@
 	return retval;
 }
 
+/**
+ * reparent_to_init() - Reparent the calling kernel thread to the init task.
+ *
+ * If a kernel thread is launched as a result of a system call, or if
+ * it ever exits, it should generally reparent itself to init so that
+ * it is correctly cleaned up on exit.
+ *
+ * The various task state such as scheduling policy and priority may have
+ * been inherited from a user process, so we reset them to sane values here.
+ *
+ * NOTE that reparent_to_init() gives the caller full capabilities.
+ */
+void reparent_to_init(void)
+{
+	write_lock_irq(&tasklist_lock);
+
+	/* Reparent to init */
+	REMOVE_LINKS(current);
+	current->p_pptr = child_reaper;
+	current->p_opptr = child_reaper;
+	SET_LINKS(current);
+
+	/* Set the exit signal to SIGCHLD so we signal init on exit */
+	current->exit_signal = SIGCHLD;
+
+	current->ptrace = 0;
+	if ((current->policy == SCHED_OTHER) && (task_nice(current) < 0))
+		set_user_nice(current, 0);
+	/* cpus_allowed? */
+	/* rt_priority? */
+	/* signals? */
+	current->cap_effective = CAP_INIT_EFF_SET;
+	current->cap_inheritable = CAP_INIT_INH_SET;
+	current->cap_permitted = CAP_FULL_SET;
+	current->keep_capabilities = 0;
+	memcpy(current->rlim, init_task.rlim, sizeof(*(current->rlim)));
+	current->user = INIT_USER;
+
+	write_unlock_irq(&tasklist_lock);
+}
+
+/*
+ *	Put all the gunge required to become a kernel thread without
+ *	attached user resources in one place where it belongs.
+ */
+
+void daemonize(void)
+{
+	struct fs_struct *fs;
+
+
+	/*
+	 * If we were started as result of loading a module, close all of the
+	 * user space pages.  We don't need them, and if we didn't close them
+	 * they would be locked into memory.
+	 */
+	exit_mm(current);
+
+	current->session = 1;
+	current->pgrp = 1;
+	current->tty = NULL;
+
+	/* Become as one with the init task */
+
+	exit_fs(current);	/* current->fs->count--; */
+	fs = init_task.fs;
+	current->fs = fs;
+	atomic_inc(&fs->count);
+ 	exit_files(current);
+	current->files = init_task.files;
+	atomic_inc(&current->files->count);
+}
+
 /*
  * When we die, we re-parent all our children.
  * Try to give them to another thread in our thread
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/kernel/fork.c linux.20pre10-ac2/kernel/fork.c
--- linux.20pre10/kernel/fork.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/kernel/fork.c	2002-09-18 12:58:44.000000000 +0100
@@ -22,6 +22,7 @@
 #include <linux/namespace.h>
 #include <linux/personality.h>
 #include <linux/compiler.h>
+#include <linux/mman.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -30,7 +31,6 @@
 
 /* The idle threads do not count.. */
 int nr_threads;
-int nr_running;
 
 int max_threads;
 unsigned long total_forks;	/* Handle normal Linux uptimes. */
@@ -38,6 +38,8 @@
 
 struct task_struct *pidhash[PIDHASH_SZ];
 
+rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED;  /* outer */
+
 void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
 {
 	unsigned long flags;
@@ -143,6 +145,7 @@
 {
 	struct vm_area_struct * mpnt, *tmp, **pprev;
 	int retval;
+	unsigned long charge = 0;
 
 	flush_cache_mm(current->mm);
 	mm->locked_vm = 0;
@@ -151,7 +154,6 @@
 	mm->map_count = 0;
 	mm->rss = 0;
 	mm->cpu_vm_mask = 0;
-	mm->swap_address = 0;
 	pprev = &mm->mmap;
 
 	/*
@@ -171,6 +173,12 @@
 		retval = -ENOMEM;
 		if(mpnt->vm_flags & VM_DONTCOPY)
 			continue;
+		if(mpnt->vm_flags & VM_ACCOUNT) {
+			unsigned int len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
+			if(!vm_enough_memory(len))
+				goto fail_nomem;
+			charge += len;
+		}
 		tmp = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 		if (!tmp)
 			goto fail_nomem;
@@ -214,10 +222,12 @@
 	}
 	retval = 0;
 	build_mmap_rb(mm);
-
-fail_nomem:
+out:
 	flush_tlb_mm(current->mm);
 	return retval;
+fail_nomem:
+	vm_unacct_memory(charge);
+	goto out;
 }
 
 spinlock_t mmlist_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED;
@@ -275,9 +285,6 @@
 void mmput(struct mm_struct *mm)
 {
 	if (atomic_dec_and_lock(&mm->mm_users, &mmlist_lock)) {
-		extern struct mm_struct *swap_mm;
-		if (swap_mm == mm)
-			swap_mm = list_entry(mm->mmlist.next, struct mm_struct, mmlist);
 		list_del(&mm->mmlist);
 		mmlist_nr--;
 		spin_unlock(&mmlist_lock);
@@ -578,6 +585,7 @@
 	    struct pt_regs *regs, unsigned long stack_size)
 {
 	int retval;
+	unsigned long flags;
 	struct task_struct *p;
 	struct completion vfork;
 
@@ -638,8 +646,7 @@
 	if (p->pid == 0 && current->pid != 0)
 		goto bad_fork_cleanup;
 
-	p->run_list.next = NULL;
-	p->run_list.prev = NULL;
+	INIT_LIST_HEAD(&p->run_list);
 
 	p->p_cptr = NULL;
 	init_waitqueue_head(&p->wait_chldexit);
@@ -665,19 +672,18 @@
 #ifdef CONFIG_SMP
 	{
 		int i;
-		p->cpus_runnable = ~0UL;
-		p->processor = current->processor;
+
 		/* ?? should we just memset this ?? */
 		for(i = 0; i < smp_num_cpus; i++)
-			p->per_cpu_utime[i] = p->per_cpu_stime[i] = 0;
+			p->per_cpu_utime[cpu_logical_map(i)] =
+				p->per_cpu_stime[cpu_logical_map(i)] = 0;
 		spin_lock_init(&p->sigmask_lock);
 	}
 #endif
+	p->array = NULL;
 	p->lock_depth = -1;		/* -1 = no lock */
 	p->start_time = jiffies;
 
-	INIT_LIST_HEAD(&p->local_pages);
-
 	retval = -ENOMEM;
 	/* copy all the process information */
 	if (copy_files(clone_flags, p))
@@ -706,15 +712,27 @@
 	p->pdeath_signal = 0;
 
 	/*
-	 * "share" dynamic priority between parent and child, thus the
-	 * total amount of dynamic priorities in the system doesn't change,
-	 * more scheduling fairness. This is only important in the first
-	 * timeslice, on the long run the scheduling behaviour is unchanged.
-	 */
-	p->counter = (current->counter + 1) >> 1;
-	current->counter >>= 1;
-	if (!current->counter)
-		current->need_resched = 1;
+	 * Share the timeslice between parent and child, thus the
+	 * total amount of pending timeslices in the system doesnt change,
+	 * resulting in more scheduling fairness.
+	 */
+	__save_flags(flags);
+	__cli();
+	if (!current->time_slice)
+		BUG();
+	p->time_slice = (current->time_slice + 1) >> 1;
+	current->time_slice >>= 1;
+	if (!current->time_slice) {
+		/*
+		 * This case is rare, it happens when the parent has only
+		 * a single jiffy left from its timeslice. Taking the
+		 * runqueue lock is not a problem.
+		 */
+		current->time_slice = 1;
+		scheduler_tick(0,0);
+	}
+	p->sleep_timestamp = jiffies;
+	__restore_flags(flags);
 
 	/*
 	 * Ok, add it to the run-queues and make it
@@ -750,11 +768,16 @@
 
 	if (p->ptrace & PT_PTRACED)
 		send_sig(SIGSTOP, p, 1);
-
-	wake_up_process(p);		/* do this last */
+	wake_up_forked_process(p);	/* do this last */
 	++total_forks;
 	if (clone_flags & CLONE_VFORK)
 		wait_for_completion(&vfork);
+	else
+		/*
+		 * Let the child process run first, to avoid most of the
+		 * COW overhead when the child exec()s afterwards.
+		 */
+		current->need_resched = 1;
 
 fork_out:
 	return retval;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/kernel/kmod.c linux.20pre10-ac2/kernel/kmod.c
--- linux.20pre10/kernel/kmod.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/kernel/kmod.c	2002-08-06 15:41:51.000000000 +0100
@@ -119,15 +119,8 @@
 		if (curtask->files->fd[i]) close(i);
 	}
 
-	/* Drop the "current user" thing */
-	{
-		struct user_struct *user = curtask->user;
-		curtask->user = INIT_USER;
-		atomic_inc(&INIT_USER->__count);
-		atomic_inc(&INIT_USER->processes);
-		atomic_dec(&user->processes);
-		free_uid(user);
-	}
+	/* Become root */
+	set_user(0, 0);
 
 	/* Give kmod all effective privileges.. */
 	curtask->euid = curtask->fsuid = 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/kernel/ksyms.c linux.20pre10-ac2/kernel/ksyms.c
--- linux.20pre10/kernel/ksyms.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/kernel/ksyms.c	2002-09-29 21:19:20.000000000 +0100
@@ -11,6 +11,7 @@
 
 #include <linux/config.h>
 #include <linux/slab.h>
+#include <linux/smp.h>
 #include <linux/module.h>
 #include <linux/blkdev.h>
 #include <linux/cdrom.h>
@@ -110,6 +111,7 @@
 EXPORT_SYMBOL(kfree);
 EXPORT_SYMBOL(vfree);
 EXPORT_SYMBOL(__vmalloc);
+EXPORT_SYMBOL(vcalloc);
 EXPORT_SYMBOL(vmalloc_to_page);
 EXPORT_SYMBOL(mem_map);
 EXPORT_SYMBOL(remap_page_range);
@@ -324,6 +326,7 @@
 EXPORT_SYMBOL(refile_buffer);
 EXPORT_SYMBOL(max_sectors);
 EXPORT_SYMBOL(max_readahead);
+EXPORT_SYMBOL(blkdev_varyio);
 
 /* tty routines */
 EXPORT_SYMBOL(tty_hangup);
@@ -443,7 +446,9 @@
 /* process management */
 EXPORT_SYMBOL(complete_and_exit);
 EXPORT_SYMBOL(__wake_up);
-EXPORT_SYMBOL(__wake_up_sync);
+#if CONFIG_SMP
+EXPORT_SYMBOL_GPL(__wake_up_sync); /* internal use only */
+#endif
 EXPORT_SYMBOL(wake_up_process);
 EXPORT_SYMBOL(sleep_on);
 EXPORT_SYMBOL(sleep_on_timeout);
@@ -453,6 +458,12 @@
 EXPORT_SYMBOL(schedule_timeout);
 EXPORT_SYMBOL(yield);
 EXPORT_SYMBOL(__cond_resched);
+EXPORT_SYMBOL(set_user_nice);
+EXPORT_SYMBOL(task_nice);
+EXPORT_SYMBOL_GPL(idle_cpu);
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL_GPL(set_cpus_allowed);
+#endif
 EXPORT_SYMBOL(jiffies);
 EXPORT_SYMBOL(xtime);
 EXPORT_SYMBOL(do_gettimeofday);
@@ -464,6 +475,7 @@
 
 EXPORT_SYMBOL(kstat);
 EXPORT_SYMBOL(nr_running);
+EXPORT_SYMBOL(nr_context_switches);
 
 /* misc */
 EXPORT_SYMBOL(panic);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/kernel/Makefile linux.20pre10-ac2/kernel/Makefile
--- linux.20pre10/kernel/Makefile	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/kernel/Makefile	2002-08-11 21:27:21.000000000 +0100
@@ -9,7 +9,7 @@
 
 O_TARGET := kernel.o
 
-export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o printk.o
+export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o printk.o cpufreq.o
 
 obj-y     = sched.o dma.o fork.o exec_domain.o panic.o printk.o \
 	    module.o exit.o itimer.o info.o time.o softirq.o resource.o \
@@ -19,6 +19,8 @@
 obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += ksyms.o
 obj-$(CONFIG_PM) += pm.o
+obj-$(CONFIG_CPU_FREQ) += cpufreq.o
+obj-$(CONFIG_IKCONFIG) += configs.o
 
 ifneq ($(CONFIG_IA64),y)
 # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
@@ -26,7 +28,21 @@
 # me.  I suspect most platforms don't need this, but until we know that for sure
 # I turn this off for IA-64 only.  Andreas Schwab says it's also needed on m68k
 # to get a correct value for the wait-channel (WCHAN in ps). --davidm
+#
+# Some gcc's are building so that O(1) scheduler is triple faulting if we 
+# build -O2. (Turns out to be a CPU issue. Update your microcode if you hit it)
+#
 CFLAGS_sched.o := $(PROFILING) -fno-omit-frame-pointer
 endif
 
 include $(TOPDIR)/Rules.make
+
+configs.o: $(TOPDIR)/scripts/mkconfigs configs.c
+	$(CC) $(CFLAGS) $(CFLAGS_KERNEL) -DEXPORT_SYMTAB -c -o configs.o configs.c
+
+$(TOPDIR)/scripts/mkconfigs: $(TOPDIR)/scripts/mkconfigs.c
+	$(HOSTCC) $(HOSTCFLAGS) -o $(TOPDIR)/scripts/mkconfigs $(TOPDIR)/scripts/mkconfigs.c
+
+configs.c: $(TOPDIR)/.config $(TOPDIR)/scripts/mkconfigs
+	$(TOPDIR)/scripts/mkconfigs $(TOPDIR)/.config configs.c
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/kernel/module.c linux.20pre10-ac2/kernel/module.c
--- linux.20pre10/kernel/module.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/kernel/module.c	2002-08-06 15:41:51.000000000 +0100
@@ -303,7 +303,7 @@
 		error = namelen;
 		goto err0;
 	}
-	if (size < sizeof(struct module)+namelen) {
+	if (size < sizeof(struct module)+namelen+1) {
 		error = -EINVAL;
 		goto err1;
 	}
@@ -482,10 +482,10 @@
 		error = n_namelen;
 		goto err2;
 	}
-	if (namelen != n_namelen || strcmp(n_name, mod_tmp.name) != 0) {
+	if (namelen != n_namelen || strcmp(n_name, name_tmp) != 0) {
 		printk(KERN_ERR "init_module: changed module name to "
 				"`%s' from `%s'\n",
-		       n_name, mod_tmp.name);
+		       n_name, name_tmp);
 		goto err3;
 	}
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/kernel/panic.c linux.20pre10-ac2/kernel/panic.c
--- linux.20pre10/kernel/panic.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/kernel/panic.c	2002-09-29 20:34:20.000000000 +0100
@@ -16,6 +16,8 @@
 #include <linux/init.h>
 #include <linux/sysrq.h>
 #include <linux/interrupt.h>
+#include <linux/vt_kern.h>
+#include <linux/pc_keyb.h>
 
 asmlinkage void sys_sync(void);	/* it's really int */
 
@@ -28,9 +30,155 @@
 	panic_timeout = simple_strtoul(str, NULL, 0);
 	return 1;
 }
-
 __setup("panic=", panic_setup);
 
+
+#if (defined(CONFIG_X86) && defined(CONFIG_VT)) || defined(CONFIG_PC_KEYB)
+#define do_blink(x) pckbd_blink(x)
+#else
+#define do_blink(x) 0
+#endif
+
+#ifdef CONFIG_PANIC_MORSE
+
+static int blink_setting = 1;
+
+static const unsigned char morsetable[] = {
+	0122, 0, 0310, 0, 0, 0163,			/* "#$%&' */
+	055, 0155, 0, 0, 0163, 0141, 0152, 0051, 	/* ()*+,-./ */
+	077, 076, 074, 070, 060, 040, 041, 043, 047, 057, /* 0-9 */
+	0107, 0125, 0, 0061, 0, 0114, 0, 		/* :;<=>?@ */
+	006, 021, 025, 011, 002, 024, 013, 020, 004,	/* A-I */
+	036, 015, 022, 007, 005, 017, 026, 033, 012,	/* J-R */
+	010, 003, 014, 030, 016, 031, 035, 023,		/* S-Z */
+	0, 0, 0, 0, 0154				/* [\]^_ */
+};
+
+__inline__ unsigned char tomorse(char c) {
+	if (c >= 'a' && c <= 'z')
+		c = c - 'a' + 'A';
+	if (c >= '"' && c <= '_') {
+		return morsetable[c - '"'];
+	} else
+		return 0;
+}
+
+
+#define DITLEN (HZ / 5)
+#define DAHLEN 3 * DITLEN
+#define SPACELEN 7 * DITLEN
+
+#define FREQ 844
+
+/* Tell the user who may be running in X and not see the console that we have 
+   panic'ed. This is to distingush panics from "real" lockups. 
+   Could in theory send the panic message as morse, but that is left as an
+   exercise for the reader.  
+   And now it's done! LED and speaker morse code by Andrew Rodland 
+   <arodland@noln.com>, with improvements based on suggestions from
+   linux@horizon.com and a host of others.
+*/ 
+
+void panic_blink(char *buf)
+{ 
+	static unsigned long next_jiffie = 0;
+	static char * bufpos = 0;
+	static unsigned char morse = 0;
+	static char state = 1;
+	
+	if (!blink_setting) 
+		return;
+
+	if (!buf)
+		buf="Panic lost?";
+
+
+	if (bufpos && time_after (next_jiffie, jiffies)) {
+		return; /* Waiting for something. */
+	}
+
+	if (state) { /* Coming off of a blink. */
+		if (blink_setting & 0x01)
+			do_blink(0);
+
+		state = 0;
+
+		if(morse > 1) { /* Not done yet, just a one-dit pause. */
+			next_jiffie = jiffies + DITLEN;
+		} else { /* Get a new char, and figure out how much space. */
+			
+			if(!bufpos)
+				bufpos = (char *)buf; /* First time through */
+
+			if(!*bufpos) {
+				bufpos = (char *)buf; /* Repeating */
+				next_jiffie = jiffies + SPACELEN;
+			} else {
+				/* Inter-letter space */
+				next_jiffie = jiffies + DAHLEN; 
+			}
+
+			if (! (morse = tomorse(*bufpos) )) {
+				next_jiffie = jiffies + SPACELEN;
+				state = 1; /* And get us back here */
+			}
+			bufpos ++;
+		}
+	} else { /* Starting a new blink. We have valid code in morse. */
+		int len;
+
+		len = (morse & 001) ? DAHLEN : DITLEN;
+
+		if (blink_setting & 0x02)
+			kd_mksound(FREQ, len);
+		
+		next_jiffie = jiffies + len;
+
+		if (blink_setting & 0x01)
+			do_blink(1);
+		state = 1;
+		morse >>= 1;
+	}
+}  
+
+#else /* CONFIG_PANIC_MORSE */
+
+static int blink_setting = HZ / 2; /* Over here, it's jiffies between blinks. */
+
+/* This is the "original" 2.4-ac panic_blink, rewritten to use my
+ * sorta-arch-independent do_blink stuff.
+ */
+void panic_blink(char *buf) {
+	static char state = 0;
+	static unsigned long next_jiffie = 0;
+
+	if (!blink_setting)
+		return;
+
+	if (jiffies >= next_jiffie) {
+		state ^= 1;
+		do_blink(state);
+		next_jiffie = jiffies + blink_setting;
+	}
+
+	return;
+}
+
+#endif /* CONFIG_PANIC_MORSE */
+
+static int __init panicblink_setup(char *str)
+{
+    int par;
+    if (get_option(&str,&par)) 
+	    blink_setting = par;
+    return 1;
+}
+
+/* panicblink=0 disables the blinking as it caused problems with some console
+   switches. */
+__setup("panicblink=", panicblink_setup);
+
+
 /**
  *	panic - halt the system
  *	@fmt: The text string to print
@@ -96,10 +244,7 @@
 #endif
 	sti();
 	for(;;) {
-#if defined(CONFIG_X86) && defined(CONFIG_VT) 
-		extern void panic_blink(void);
-		panic_blink(); 
-#endif
+		panic_blink(buf); 
 		CHECK_EMERGENCY_SYNC
 	}
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/kernel/printk.c linux.20pre10-ac2/kernel/printk.c
--- linux.20pre10/kernel/printk.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/kernel/printk.c	2002-08-07 14:37:11.000000000 +0100
@@ -26,6 +26,7 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>			/* For in_interrupt() */
 #include <linux/config.h>
+#include <linux/delay.h>
 
 #include <asm/uaccess.h>
 
@@ -529,6 +530,7 @@
 	if (must_wake_klogd && !oops_in_progress)
 		wake_up_interruptible(&log_wait);
 }
+EXPORT_SYMBOL(release_console_sem);
 
 /** console_conditional_schedule - yield the CPU if required
  *
@@ -556,7 +558,14 @@
 {
 	struct console *c;
 
-	acquire_console_sem();
+	/*
+	 * Try to get the console semaphore. If someone else owns it
+	 * we have to return without unblanking because console_unblank
+	 * may be called in interrupt context.
+	 */
+	if (down_trylock(&console_sem) != 0)
+		return;
+	console_may_schedule = 0;
 	for (c = console_drivers; c != NULL; c = c->next)
 		if ((c->flags & CON_ENABLED) && c->unblank)
 			c->unblank();
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/kernel/ptrace.c linux.20pre10-ac2/kernel/ptrace.c
--- linux.20pre10/kernel/ptrace.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/kernel/ptrace.c	2002-08-06 15:41:51.000000000 +0100
@@ -31,20 +31,7 @@
 		if (child->state != TASK_STOPPED)
 			return -ESRCH;
 #ifdef CONFIG_SMP
-		/* Make sure the child gets off its CPU.. */
-		for (;;) {
-			task_lock(child);
-			if (!task_has_cpu(child))
-				break;
-			task_unlock(child);
-			do {
-				if (child->state != TASK_STOPPED)
-					return -ESRCH;
-				barrier();
-				cpu_relax();
-			} while (task_has_cpu(child));
-		}
-		task_unlock(child);
+		wait_task_inactive(child);
 #endif		
 	}
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/kernel/sched.c linux.20pre10-ac2/kernel/sched.c
--- linux.20pre10/kernel/sched.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/kernel/sched.c	2002-10-09 22:18:03.000000000 +0100
@@ -1,760 +1,1052 @@
 /*
- *  linux/kernel/sched.c
+ *  kernel/sched.c
  *
  *  Kernel scheduler and related syscalls
  *
- *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 1991-2002  Linus Torvalds
  *
  *  1996-12-23  Modified by Dave Grothe to fix bugs in semaphores and
  *              make semaphores SMP safe
  *  1998-11-19	Implemented schedule_timeout() and related stuff
  *		by Andrea Arcangeli
- *  1998-12-28  Implemented better SMP scheduling by Ingo Molnar
+ *  2002-01-04	New ultra-scalable O(1) scheduler by Ingo Molnar:
+ *  		hybrid priority-list and round-robin design with
+ *  		an array-switch method of distributing timeslices
+ *  		and per-CPU runqueues.  Additional code by Davide
+ *  		Libenzi, Robert Love, and Rusty Russell.
  */
 
-/*
- * 'sched.c' is the main kernel file. It contains scheduling primitives
- * (sleep_on, wakeup, schedule etc) as well as a number of simple system
- * call functions (type getpid()), which just extract a field from
- * current-task
- */
-
-#include <linux/config.h>
 #include <linux/mm.h>
+#include <linux/nmi.h>
 #include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/highmem.h>
 #include <linux/smp_lock.h>
-#include <linux/nmi.h>
+#include <asm/mmu_context.h>
 #include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
 #include <linux/completion.h>
-#include <linux/prefetch.h>
-#include <linux/compiler.h>
+#include <linux/kernel_stat.h>
 
-#include <asm/uaccess.h>
-#include <asm/mmu_context.h>
+/*
+ * Convert user-nice values [ -20 ... 0 ... 19 ]
+ * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],
+ * and back.
+ */
+#define NICE_TO_PRIO(nice)	(MAX_RT_PRIO + (nice) + 20)
+#define PRIO_TO_NICE(prio)	((prio) - MAX_RT_PRIO - 20)
+#define TASK_NICE(p)		PRIO_TO_NICE((p)->static_prio)
 
-extern void timer_bh(void);
-extern void tqueue_bh(void);
-extern void immediate_bh(void);
+/*
+ * 'User priority' is the nice value converted to something we
+ * can work with better when scaling various scheduler parameters,
+ * it's a [ 0 ... 39 ] range.
+ */
+#define USER_PRIO(p)		((p)-MAX_RT_PRIO)
+#define TASK_USER_PRIO(p)	USER_PRIO((p)->static_prio)
+#define MAX_USER_PRIO		(USER_PRIO(MAX_PRIO))
 
 /*
- * scheduler variables
+ * These are the 'tuning knobs' of the scheduler:
+ *
+ * Minimum timeslice is 10 msecs, default timeslice is 150 msecs,
+ * maximum timeslice is 300 msecs. Timeslices get refilled after
+ * they expire.
  */
+#define MIN_TIMESLICE		( 10 * HZ / 1000)
+#define MAX_TIMESLICE		(300 * HZ / 1000)
+#define CHILD_PENALTY		95
+#define PARENT_PENALTY		100
+#define EXIT_WEIGHT		3
+#define PRIO_BONUS_RATIO	25
+#define INTERACTIVE_DELTA	2
+#define MAX_SLEEP_AVG		(2*HZ)
+#define STARVATION_LIMIT	(2*HZ)
+
+/*
+ * If a task is 'interactive' then we reinsert it in the active
+ * array after it has expired its current timeslice. (it will not
+ * continue to run immediately, it will still roundrobin with
+ * other interactive tasks.)
+ *
+ * This part scales the interactivity limit depending on niceness.
+ *
+ * We scale it linearly, offset by the INTERACTIVE_DELTA delta.
+ * Here are a few examples of different nice levels:
+ *
+ *  TASK_INTERACTIVE(-20): [1,1,1,1,1,1,1,1,1,0,0]
+ *  TASK_INTERACTIVE(-10): [1,1,1,1,1,1,1,0,0,0,0]
+ *  TASK_INTERACTIVE(  0): [1,1,1,1,0,0,0,0,0,0,0]
+ *  TASK_INTERACTIVE( 10): [1,1,0,0,0,0,0,0,0,0,0]
+ *  TASK_INTERACTIVE( 19): [0,0,0,0,0,0,0,0,0,0,0]
+ *
+ * (the X axis represents the possible -5 ... 0 ... +5 dynamic
+ *  priority range a task can explore, a value of '1' means the
+ *  task is rated interactive.)
+ *
+ * Ie. nice +19 tasks can never get 'interactive' enough to be
+ * reinserted into the active array. And only heavily CPU-hog nice -20
+ * tasks will be expired. Default nice 0 tasks are somewhere between,
+ * it takes some effort for them to get interactive, but it's not
+ * too hard.
+ */
+
+#define SCALE(v1,v1_max,v2_max) \
+	(v1) * (v2_max) / (v1_max)
 
-unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */
+#define DELTA(p) \
+	(SCALE(TASK_NICE(p), 40, MAX_USER_PRIO*PRIO_BONUS_RATIO/100) + \
+		INTERACTIVE_DELTA)
 
-extern void mem_use(void);
+#define TASK_INTERACTIVE(p) \
+	((p)->prio <= (p)->static_prio - DELTA(p))
 
 /*
- * Scheduling quanta.
+ * BASE_TIMESLICE scales user-nice values [ -20 ... 19 ]
+ * to time slice values.
  *
- * NOTE! The unix "nice" value influences how long a process
- * gets. The nice value ranges from -20 to +19, where a -20
- * is a "high-priority" task, and a "+10" is a low-priority
- * task.
+ * The higher a thread's priority, the bigger timeslices
+ * it gets during one round of execution. But even the lowest
+ * priority thread gets MIN_TIMESLICE worth of execution time.
  *
- * We want the time-slice to be around 50ms or so, so this
- * calculation depends on the value of HZ.
+ * task_timeslice() is the interface that is used by the scheduler.
  */
-#if HZ < 200
-#define TICK_SCALE(x)	((x) >> 2)
-#elif HZ < 400
-#define TICK_SCALE(x)	((x) >> 1)
-#elif HZ < 800
-#define TICK_SCALE(x)	(x)
-#elif HZ < 1600
-#define TICK_SCALE(x)	((x) << 1)
-#else
-#define TICK_SCALE(x)	((x) << 2)
-#endif
-
-#define NICE_TO_TICKS(nice)	(TICK_SCALE(20-(nice))+1)
+#define BASE_TIMESLICE(p) (MIN_TIMESLICE + \
+	((MAX_TIMESLICE - MIN_TIMESLICE) * \
+	 (MAX_PRIO-1-(p)->static_prio)/(MAX_USER_PRIO - 1)))
 
+static inline unsigned int task_timeslice(task_t *p)
+{
+	return BASE_TIMESLICE(p);
+}
 
 /*
- *	Init task must be ok at boot for the ix86 as we will check its signals
- *	via the SMP irq return path.
+ * These are the runqueue data structures:
  */
- 
-struct task_struct * init_tasks[NR_CPUS] = {&init_task, };
+
+#define BITMAP_SIZE ((((MAX_PRIO+1+7)/8)+sizeof(long)-1)/sizeof(long))
+
+typedef struct runqueue runqueue_t;
+
+struct prio_array {
+	int nr_active;
+	unsigned long bitmap[BITMAP_SIZE];
+	struct list_head queue[MAX_PRIO];
+};
 
 /*
- * The tasklist_lock protects the linked list of processes.
+ * This is the main, per-CPU runqueue data structure.
  *
- * The runqueue_lock locks the parts that actually access
- * and change the run-queues, and have to be interrupt-safe.
- *
- * If both locks are to be concurrently held, the runqueue_lock
- * nests inside the tasklist_lock.
- *
- * task->alloc_lock nests inside tasklist_lock.
+ * Locking rule: those places that want to lock multiple runqueues
+ * (such as the load balancing or the process migration code), lock
+ * acquire operations must be ordered by ascending &runqueue.
  */
-spinlock_t runqueue_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED;  /* inner */
-rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED;	/* outer */
+struct runqueue {
+	spinlock_t lock;
+	unsigned long nr_running, nr_switches, expired_timestamp,
+			nr_uninterruptible;
+	task_t *curr, *idle;
+	prio_array_t *active, *expired, arrays[2];
+	int prev_nr_running[NR_CPUS];
+	task_t *migration_thread;
+	struct list_head migration_queue;
+} ____cacheline_aligned;
+
+static struct runqueue runqueues[NR_CPUS] __cacheline_aligned;
+
+#define cpu_rq(cpu)		(runqueues + (cpu))
+#define this_rq()		cpu_rq(smp_processor_id())
+#define task_rq(p)		cpu_rq(task_cpu(p))
+#define cpu_curr(cpu)		(cpu_rq(cpu)->curr)
+#define rt_task(p)		((p)->prio < MAX_RT_PRIO)
+
+/*
+ * Default context-switch locking:
+ */
+#ifndef prepare_arch_schedule
+# define prepare_arch_schedule(prev)	do { } while(0)
+# define finish_arch_schedule(prev)	do { } while(0)
+# define prepare_arch_switch(rq)	do { } while(0)
+# define finish_arch_switch(rq)		spin_unlock_irq(&(rq)->lock)
+#endif
 
-static LIST_HEAD(runqueue_head);
 
 /*
- * We align per-CPU scheduling data on cacheline boundaries,
- * to prevent cacheline ping-pong.
+ * task_rq_lock - lock the runqueue a given task resides on and disable
+ * interrupts.  Note the ordering: we can safely lookup the task_rq without
+ * explicitly disabling preemption.
  */
-static union {
-	struct schedule_data {
-		struct task_struct * curr;
-		cycles_t last_schedule;
-	} schedule_data;
-	char __pad [SMP_CACHE_BYTES];
-} aligned_data [NR_CPUS] __cacheline_aligned = { {{&init_task,0}}};
+static inline runqueue_t *task_rq_lock(task_t *p, unsigned long *flags)
+{
+	struct runqueue *rq;
 
-#define cpu_curr(cpu) aligned_data[(cpu)].schedule_data.curr
-#define last_schedule(cpu) aligned_data[(cpu)].schedule_data.last_schedule
+repeat_lock_task:
+	local_irq_save(*flags);
+	rq = task_rq(p);
+	spin_lock(&rq->lock);
+	if (unlikely(rq != task_rq(p))) {
+		spin_unlock_irqrestore(&rq->lock, *flags);
+		goto repeat_lock_task;
+	}
+	return rq;
+}
 
-struct kernel_stat kstat;
-extern struct task_struct *child_reaper;
+static inline void task_rq_unlock(runqueue_t *rq, unsigned long *flags)
+{
+	spin_unlock_irqrestore(&rq->lock, *flags);
+}
 
-#ifdef CONFIG_SMP
+/*
+ * rq_lock - lock a given runqueue and disable interrupts.
+ */
+static inline runqueue_t *this_rq_lock(void)
+{
+	runqueue_t *rq;
 
-#define idle_task(cpu) (init_tasks[cpu_number_map(cpu)])
-#define can_schedule(p,cpu) \
-	((p)->cpus_runnable & (p)->cpus_allowed & (1 << cpu))
+	local_irq_disable();
+	rq = this_rq();
+	spin_lock(&rq->lock);
 
-#else
+	return rq;
+}
 
-#define idle_task(cpu) (&init_task)
-#define can_schedule(p,cpu) (1)
+static inline void rq_unlock(runqueue_t *rq)
+{
+	spin_unlock_irq(&rq->lock);
+}
 
-#endif
+/*
+ * Adding/removing a task to/from a priority array:
+ */
+static inline void dequeue_task(struct task_struct *p, prio_array_t *array)
+{
+	array->nr_active--;
+	list_del(&p->run_list);
+	if (list_empty(array->queue + p->prio))
+		__clear_bit(p->prio, array->bitmap);
+}
 
-void scheduling_functions_start_here(void) { }
+static inline void enqueue_task(struct task_struct *p, prio_array_t *array)
+{
+	list_add_tail(&p->run_list, array->queue + p->prio);
+	__set_bit(p->prio, array->bitmap);
+	array->nr_active++;
+	p->array = array;
+}
 
 /*
- * This is the function that decides how desirable a process is..
- * You can weigh different processes against each other depending
- * on what CPU they've run on lately etc to try to handle cache
- * and TLB miss penalties.
+ * effective_prio - return the priority that is based on the static
+ * priority but is modified by bonuses/penalties.
+ *
+ * We scale the actual sleep average [0 .... MAX_SLEEP_AVG]
+ * into the -5 ... 0 ... +5 bonus/penalty range.
+ *
+ * We use 25% of the full 0...39 priority range so that:
+ *
+ * 1) nice +19 interactive tasks do not preempt nice 0 CPU hogs.
+ * 2) nice -20 CPU hogs do not get preempted by nice 0 tasks.
  *
- * Return values:
- *	 -1000: never select this
- *	     0: out of time, recalculate counters (but it might still be
- *		selected)
- *	   +ve: "goodness" value (the larger, the better)
- *	 +1000: realtime process, select this.
+ * Both properties are important to certain workloads.
  */
-
-static inline int goodness(struct task_struct * p, int this_cpu, struct mm_struct *this_mm)
+static inline int effective_prio(task_t *p)
 {
-	int weight;
+	int bonus, prio;
 
-	/*
-	 * select the current process after every other
-	 * runnable process, but before the idle thread.
-	 * Also, dont trigger a counter recalculation.
-	 */
-	weight = -1;
-	if (p->policy & SCHED_YIELD)
-		goto out;
+	bonus = MAX_USER_PRIO*PRIO_BONUS_RATIO*p->sleep_avg/MAX_SLEEP_AVG/100 -
+			MAX_USER_PRIO*PRIO_BONUS_RATIO/100/2;
 
-	/*
-	 * Non-RT process - normal case first.
-	 */
-	if (p->policy == SCHED_OTHER) {
+	prio = p->static_prio - bonus;
+	if (prio < MAX_RT_PRIO)
+		prio = MAX_RT_PRIO;
+	if (prio > MAX_PRIO-1)
+		prio = MAX_PRIO-1;
+	return prio;
+}
+
+/*
+ * activate_task - move a task to the runqueue.
+ *
+ * Also update all the scheduling statistics stuff. (sleep average
+ * calculation, priority modifiers, etc.)
+ */
+static inline void activate_task(task_t *p, runqueue_t *rq)
+{
+	unsigned long sleep_time = jiffies - p->sleep_timestamp;
+	prio_array_t *array = rq->active;
+
+	if (!rt_task(p) && sleep_time) {
 		/*
-		 * Give the process a first-approximation goodness value
-		 * according to the number of clock-ticks it has left.
-		 *
-		 * Don't do any other calculations if the time slice is
-		 * over..
+		 * This code gives a bonus to interactive tasks. We update
+		 * an 'average sleep time' value here, based on
+		 * sleep_timestamp. The more time a task spends sleeping,
+		 * the higher the average gets - and the higher the priority
+		 * boost gets as well.
 		 */
-		weight = p->counter;
-		if (!weight)
-			goto out;
-			
-#ifdef CONFIG_SMP
-		/* Give a largish advantage to the same processor...   */
-		/* (this is equivalent to penalizing other processors) */
-		if (p->processor == this_cpu)
-			weight += PROC_CHANGE_PENALTY;
-#endif
-
-		/* .. and a slight advantage to the current MM */
-		if (p->mm == this_mm || !p->mm)
-			weight += 1;
-		weight += 20 - p->nice;
-		goto out;
+		p->sleep_avg += sleep_time;
+		if (p->sleep_avg > MAX_SLEEP_AVG)
+			p->sleep_avg = MAX_SLEEP_AVG;
+		p->prio = effective_prio(p);
 	}
-
-	/*
-	 * Realtime process, select the first one on the
-	 * runqueue (taking priorities within processes
-	 * into account).
-	 */
-	weight = 1000 + p->rt_priority;
-out:
-	return weight;
+	enqueue_task(p, array);
+	rq->nr_running++;
 }
 
 /*
- * the 'goodness value' of replacing a process on a given CPU.
- * positive value means 'replace', zero or negative means 'dont'.
+ * deactivate_task - remove a task from the runqueue.
  */
-static inline int preemption_goodness(struct task_struct * prev, struct task_struct * p, int cpu)
+static inline void deactivate_task(struct task_struct *p, runqueue_t *rq)
 {
-	return goodness(p, cpu, prev->active_mm) - goodness(prev, cpu, prev->active_mm);
+	rq->nr_running--;
+	if (p->state == TASK_UNINTERRUPTIBLE)
+		rq->nr_uninterruptible++;
+	dequeue_task(p, p->array);
+	p->array = NULL;
 }
 
 /*
- * This is ugly, but reschedule_idle() is very timing-critical.
- * We are called with the runqueue spinlock held and we must
- * not claim the tasklist_lock.
+ * resched_task - mark a task 'to be rescheduled now'.
+ *
+ * On UP this means the setting of the need_resched flag, on SMP it
+ * might also involve a cross-CPU call to trigger the scheduler on
+ * the target CPU.
  */
-static FASTCALL(void reschedule_idle(struct task_struct * p));
-
-static void reschedule_idle(struct task_struct * p)
+static inline void resched_task(task_t *p)
 {
 #ifdef CONFIG_SMP
-	int this_cpu = smp_processor_id();
-	struct task_struct *tsk, *target_tsk;
-	int cpu, best_cpu, i, max_prio;
-	cycles_t oldest_idle;
-
-	/*
-	 * shortcut if the woken up task's last CPU is
-	 * idle now.
-	 */
-	best_cpu = p->processor;
-	if (can_schedule(p, best_cpu)) {
-		tsk = idle_task(best_cpu);
-		if (cpu_curr(best_cpu) == tsk) {
-			int need_resched;
-send_now_idle:
-			/*
-			 * If need_resched == -1 then we can skip sending
-			 * the IPI altogether, tsk->need_resched is
-			 * actively watched by the idle thread.
-			 */
-			need_resched = tsk->need_resched;
-			tsk->need_resched = 1;
-			if ((best_cpu != this_cpu) && !need_resched)
-				smp_send_reschedule(best_cpu);
-			return;
-		}
-	}
-
-	/*
-	 * We know that the preferred CPU has a cache-affine current
-	 * process, lets try to find a new idle CPU for the woken-up
-	 * process. Select the least recently active idle CPU. (that
-	 * one will have the least active cache context.) Also find
-	 * the executing process which has the least priority.
-	 */
-	oldest_idle = (cycles_t) -1;
-	target_tsk = NULL;
-	max_prio = 0;
-
-	for (i = 0; i < smp_num_cpus; i++) {
-		cpu = cpu_logical_map(i);
-		if (!can_schedule(p, cpu))
-			continue;
-		tsk = cpu_curr(cpu);
-		/*
-		 * We use the first available idle CPU. This creates
-		 * a priority list between idle CPUs, but this is not
-		 * a problem.
-		 */
-		if (tsk == idle_task(cpu)) {
-#if defined(__i386__) && defined(CONFIG_SMP)
-                        /*
-			 * Check if two siblings are idle in the same
-			 * physical package. Use them if found.
-			 */
-			if (smp_num_siblings == 2) {
-				if (cpu_curr(cpu_sibling_map[cpu]) == 
-			            idle_task(cpu_sibling_map[cpu])) {
-					oldest_idle = last_schedule(cpu);
-					target_tsk = tsk;
-					break;
-				}
-				
-                        }
-#endif		
-			if (last_schedule(cpu) < oldest_idle) {
-				oldest_idle = last_schedule(cpu);
-				target_tsk = tsk;
-			}
-		} else {
-			if (oldest_idle == -1ULL) {
-				int prio = preemption_goodness(tsk, p, cpu);
-
-				if (prio > max_prio) {
-					max_prio = prio;
-					target_tsk = tsk;
-				}
-			}
-		}
-	}
-	tsk = target_tsk;
-	if (tsk) {
-		if (oldest_idle != -1ULL) {
-			best_cpu = tsk->processor;
-			goto send_now_idle;
-		}
-		tsk->need_resched = 1;
-		if (tsk->processor != this_cpu)
-			smp_send_reschedule(tsk->processor);
-	}
-	return;
-		
+	int need_resched;
 
-#else /* UP */
-	int this_cpu = smp_processor_id();
-	struct task_struct *tsk;
-
-	tsk = cpu_curr(this_cpu);
-	if (preemption_goodness(tsk, p, this_cpu) > 0)
-		tsk->need_resched = 1;
+	need_resched = p->need_resched;
+	wmb();
+	set_tsk_need_resched(p);
+	if (!need_resched && (task_cpu(p) != smp_processor_id()))
+		smp_send_reschedule(task_cpu(p));
+#else
+	set_tsk_need_resched(p);
 #endif
 }
 
+#ifdef CONFIG_SMP
+
 /*
- * Careful!
+ * wait_task_inactive - wait for a thread to unschedule.
  *
- * This has to add the process to the _end_ of the 
- * run-queue, not the beginning. The goodness value will
- * determine whether this process will run next. This is
- * important to get SCHED_FIFO and SCHED_RR right, where
- * a process that is either pre-empted or its time slice
- * has expired, should be moved to the tail of the run 
- * queue for its priority - Bhavesh Davda
+ * The caller must ensure that the task *will* unschedule sometime soon,
+ * else this function might spin for a *long* time.
  */
-static inline void add_to_runqueue(struct task_struct * p)
+void wait_task_inactive(task_t * p)
 {
-	list_add_tail(&p->run_list, &runqueue_head);
-	nr_running++;
+	unsigned long flags;
+	runqueue_t *rq;
+
+repeat:
+	rq = task_rq(p);
+	if (unlikely(rq->curr == p)) {
+		cpu_relax();
+		goto repeat;
+	}
+	rq = task_rq_lock(p, &flags);
+	if (unlikely(rq->curr == p)) {
+		task_rq_unlock(rq, &flags);
+		goto repeat;
+	}
+	task_rq_unlock(rq, &flags);
 }
 
-static inline void move_last_runqueue(struct task_struct * p)
+/*
+ * kick_if_running - kick the remote CPU if the task is running currently.
+ *
+ * This code is used by the signal code to signal tasks
+ * which are in user-mode, as quickly as possible.
+ *
+ * (Note that we do this lockless - if the task does anything
+ * while the message is in flight then it will notice the
+ * sigpending condition anyway.)
+ */
+void kick_if_running(task_t * p)
 {
-	list_del(&p->run_list);
-	list_add_tail(&p->run_list, &runqueue_head);
+	if (p == task_rq(p)->curr)
+		resched_task(p);
 }
+#endif
 
-/*
- * Wake up a process. Put it on the run-queue if it's not
- * already there.  The "current" process is always on the
- * run-queue (except when the actual re-schedule is in
- * progress), and as such you're allowed to do the simpler
- * "current->state = TASK_RUNNING" to mark yourself runnable
- * without the overhead of this.
+/***
+ * try_to_wake_up - wake up a thread
+ * @p: the to-be-woken-up thread
+ * @sync: do a synchronous wakeup?
+ *
+ * Put it on the run-queue if it's not already there. The "current"
+ * thread is always on the run-queue (except when the actual
+ * re-schedule is in progress), and as such you're allowed to do
+ * the simpler "current->state = TASK_RUNNING" to mark yourself
+ * runnable without the overhead of this.
+ *
+ * returns failure only if the task is already active.
  */
-static inline int try_to_wake_up(struct task_struct * p, int synchronous)
+static int try_to_wake_up(task_t * p, int sync)
 {
 	unsigned long flags;
 	int success = 0;
+	long old_state;
+	runqueue_t *rq;
 
-	/*
-	 * We want the common case fall through straight, thus the goto.
-	 */
-	spin_lock_irqsave(&runqueue_lock, flags);
+repeat_lock_task:
+	rq = task_rq_lock(p, &flags);
+	old_state = p->state;
+	if (!p->array) {
+		/*
+		 * Fast-migrate the task if it's not running or runnable
+		 * currently. Do not violate hard affinity.
+		 */
+		if (unlikely(sync && (rq->curr != p) &&
+			(task_cpu(p) != smp_processor_id()) &&
+			(p->cpus_allowed & (1UL << smp_processor_id())))) {
+
+			set_task_cpu(p, smp_processor_id());
+			task_rq_unlock(rq, &flags);
+			goto repeat_lock_task;
+		}
+		if (old_state == TASK_UNINTERRUPTIBLE)
+			rq->nr_uninterruptible--;
+		activate_task(p, rq);
+		if (p->prio < rq->curr->prio)
+			resched_task(rq->curr);
+		success = 1;
+	}
 	p->state = TASK_RUNNING;
-	if (task_on_runqueue(p))
-		goto out;
-	add_to_runqueue(p);
-	if (!synchronous || !(p->cpus_allowed & (1 << smp_processor_id())))
-		reschedule_idle(p);
-	success = 1;
-out:
-	spin_unlock_irqrestore(&runqueue_lock, flags);
+	task_rq_unlock(rq, &flags);
+
 	return success;
 }
 
-inline int wake_up_process(struct task_struct * p)
+int wake_up_process(task_t * p)
 {
 	return try_to_wake_up(p, 0);
 }
 
-static void process_timeout(unsigned long __data)
+/*
+ * wake_up_forked_process - wake up a freshly forked process.
+ *
+ * This function will do some initial scheduler statistics housekeeping
+ * that must be done for every newly created process.
+ */
+void wake_up_forked_process(task_t * p)
 {
-	struct task_struct * p = (struct task_struct *) __data;
+	runqueue_t *rq = this_rq_lock();
 
-	wake_up_process(p);
+	p->state = TASK_RUNNING;
+	if (!rt_task(p)) {
+		/*
+		 * We decrease the sleep average of forking parents
+		 * and children as well, to keep max-interactive tasks
+		 * from forking tasks that are max-interactive.
+		 */
+		current->sleep_avg = current->sleep_avg * PARENT_PENALTY / 100;
+		p->sleep_avg = p->sleep_avg * CHILD_PENALTY / 100;
+		p->prio = effective_prio(p);
+	}
+	set_task_cpu(p, smp_processor_id());
+	activate_task(p, rq);
+
+	rq_unlock(rq);
+}
+
+/*
+ * Potentially available exiting-child timeslices are
+ * retrieved here - this way the parent does not get
+ * penalized for creating too many threads.
+ *
+ * (this cannot be used to 'generate' timeslices
+ * artificially, because any timeslice recovered here
+ * was given away by the parent in the first place.)
+ */
+void sched_exit(task_t * p)
+{
+	__cli();
+	current->time_slice += p->time_slice;
+	if (unlikely(current->time_slice > MAX_TIMESLICE))
+		current->time_slice = MAX_TIMESLICE;
+	__sti();
+	/*
+	 * 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 +
+			p->sleep_avg) / (EXIT_WEIGHT + 1);
 }
 
 /**
- * schedule_timeout - sleep until timeout
- * @timeout: timeout value in jiffies
- *
- * Make the current task sleep until @timeout jiffies have
- * elapsed. The routine will return immediately unless
- * the current task state has been set (see set_current_state()).
+ * schedule_tail - first thing a freshly forked thread must call.
  *
- * You can set the task state as follows -
- *
- * %TASK_UNINTERRUPTIBLE - at least @timeout jiffies are guaranteed to
- * pass before the routine returns. The routine will return 0
- *
- * %TASK_INTERRUPTIBLE - the routine may return early if a signal is
- * delivered to the current task. In this case the remaining time
- * in jiffies will be returned, or 0 if the timer expired in time
- *
- * The current task state is guaranteed to be TASK_RUNNING when this 
- * routine returns.
- *
- * Specifying a @timeout value of %MAX_SCHEDULE_TIMEOUT will schedule
- * the CPU away without a bound on the timeout. In this case the return
- * value will be %MAX_SCHEDULE_TIMEOUT.
- *
- * In all cases the return value is guaranteed to be non-negative.
+ * @prev: the thread we just switched away from.
  */
-signed long schedule_timeout(signed long timeout)
+#if CONFIG_SMP
+asmlinkage void schedule_tail(task_t *prev)
 {
-	struct timer_list timer;
-	unsigned long expire;
-
-	switch (timeout)
-	{
-	case MAX_SCHEDULE_TIMEOUT:
-		/*
-		 * These two special cases are useful to be comfortable
-		 * in the caller. Nothing more. We could take
-		 * MAX_SCHEDULE_TIMEOUT from one of the negative value
-		 * but I' d like to return a valid offset (>=0) to allow
-		 * the caller to do everything it want with the retval.
-		 */
-		schedule();
-		goto out;
-	default:
-		/*
-		 * Another bit of PARANOID. Note that the retval will be
-		 * 0 since no piece of kernel is supposed to do a check
-		 * for a negative retval of schedule_timeout() (since it
-		 * should never happens anyway). You just have the printk()
-		 * that will tell you if something is gone wrong and where.
-		 */
-		if (timeout < 0)
-		{
-			printk(KERN_ERR "schedule_timeout: wrong timeout "
-			       "value %lx from %p\n", timeout,
-			       __builtin_return_address(0));
-			current->state = TASK_RUNNING;
-			goto out;
-		}
-	}
+	finish_arch_switch(this_rq());
+	finish_arch_schedule(prev);
+}
+#endif
 
-	expire = timeout + jiffies;
+/*
+ * context_switch - switch to the new MM and the new
+ * thread's register state.
+ */
+static inline task_t * context_switch(task_t *prev, task_t *next)
+{
+	struct mm_struct *mm = next->mm;
+	struct mm_struct *oldmm = prev->active_mm;
 
-	init_timer(&timer);
-	timer.expires = expire;
-	timer.data = (unsigned long) current;
-	timer.function = process_timeout;
+	if (unlikely(!mm)) {
+		next->active_mm = oldmm;
+		atomic_inc(&oldmm->mm_count);
+		enter_lazy_tlb(oldmm, next, smp_processor_id());
+	} else
+		switch_mm(oldmm, mm, next, smp_processor_id());
 
-	add_timer(&timer);
-	schedule();
-	del_timer_sync(&timer);
+	if (unlikely(!prev->mm)) {
+		prev->active_mm = NULL;
+		mmdrop(oldmm);
+	}
 
-	timeout = expire - jiffies;
+	/* Here we just switch the register state and the stack. */
+	switch_to(prev, next, prev);
 
- out:
-	return timeout < 0 ? 0 : timeout;
+	return prev;
 }
 
 /*
- * schedule_tail() is getting called from the fork return path. This
- * cleans up all remaining scheduler things, without impacting the
- * common case.
+ * nr_running, nr_uninterruptible and nr_context_switches:
+ *
+ * externally visible scheduler statistics: current number of runnable
+ * threads, current number of uninterruptible-sleeping threads, total
+ * number of context switches performed since bootup.
  */
-static inline void __schedule_tail(struct task_struct *prev)
+unsigned long nr_running(void)
 {
-#ifdef CONFIG_SMP
-	int policy;
-
-	/*
-	 * prev->policy can be written from here only before `prev'
-	 * can be scheduled (before setting prev->cpus_runnable to ~0UL).
-	 * Of course it must also be read before allowing prev
-	 * to be rescheduled, but since the write depends on the read
-	 * to complete, wmb() is enough. (the spin_lock() acquired
-	 * before setting cpus_runnable is not enough because the spin_lock()
-	 * common code semantics allows code outside the critical section
-	 * to enter inside the critical section)
-	 */
-	policy = prev->policy;
-	prev->policy = policy & ~SCHED_YIELD;
-	wmb();
+	unsigned long i, sum = 0;
 
-	/*
-	 * fast path falls through. We have to clear cpus_runnable before
-	 * checking prev->state to avoid a wakeup race. Protect against
-	 * the task exiting early.
-	 */
-	task_lock(prev);
-	task_release_cpu(prev);
-	mb();
-	if (prev->state == TASK_RUNNING)
-		goto needs_resched;
+	for (i = 0; i < smp_num_cpus; i++)
+		sum += cpu_rq(cpu_logical_map(i))->nr_running;
 
-out_unlock:
-	task_unlock(prev);	/* Synchronise here with release_task() if prev is TASK_ZOMBIE */
-	return;
+	return sum;
+}
 
-	/*
-	 * Slow path - we 'push' the previous process and
-	 * reschedule_idle() will attempt to find a new
-	 * processor for it. (but it might preempt the
-	 * current process as well.) We must take the runqueue
-	 * lock and re-check prev->state to be correct. It might
-	 * still happen that this process has a preemption
-	 * 'in progress' already - but this is not a problem and
-	 * might happen in other circumstances as well.
-	 */
-needs_resched:
-	{
-		unsigned long flags;
+unsigned long nr_uninterruptible(void)
+{
+	unsigned long i, sum = 0;
 
-		/*
-		 * Avoid taking the runqueue lock in cases where
-		 * no preemption-check is necessery:
-		 */
-		if ((prev == idle_task(smp_processor_id())) ||
-						(policy & SCHED_YIELD))
-			goto out_unlock;
+	for (i = 0; i < smp_num_cpus; i++)
+		sum += cpu_rq(cpu_logical_map(i))->nr_uninterruptible;
 
-		spin_lock_irqsave(&runqueue_lock, flags);
-		if ((prev->state == TASK_RUNNING) && !task_has_cpu(prev))
-			reschedule_idle(prev);
-		spin_unlock_irqrestore(&runqueue_lock, flags);
-		goto out_unlock;
-	}
-#else
-	prev->policy &= ~SCHED_YIELD;
-#endif /* CONFIG_SMP */
+	return sum;
 }
 
-asmlinkage void schedule_tail(struct task_struct *prev)
+unsigned long nr_context_switches(void)
 {
-	__schedule_tail(prev);
+	unsigned long i, sum = 0;
+
+	for (i = 0; i < smp_num_cpus; i++)
+		sum += cpu_rq(cpu_logical_map(i))->nr_switches;
+
+	return sum;
 }
 
 /*
- *  'schedule()' is the scheduler function. It's a very simple and nice
- * scheduler: it's not perfect, but certainly works for most things.
- *
- * The goto is "interesting".
+ * double_rq_lock - safely lock two runqueues
  *
- *   NOTE!!  Task 0 is the 'idle' task, which gets called when no other
- * tasks can run. It can not be killed, and it cannot sleep. The 'state'
- * information in task[0] is never used.
+ * Note this does not disable interrupts like task_rq_lock,
+ * you need to do so manually before calling.
  */
-asmlinkage void schedule(void)
+static inline void double_rq_lock(runqueue_t *rq1, runqueue_t *rq2)
 {
-	struct schedule_data * sched_data;
-	struct task_struct *prev, *next, *p;
-	struct list_head *tmp;
-	int this_cpu, c;
-
-
-	spin_lock_prefetch(&runqueue_lock);
+	if (rq1 == rq2)
+		spin_lock(&rq1->lock);
+	else {
+		if (rq1 < rq2) {
+			spin_lock(&rq1->lock);
+			spin_lock(&rq2->lock);
+		} else {
+			spin_lock(&rq2->lock);
+			spin_lock(&rq1->lock);
+		}
+	}
+}
 
-	BUG_ON(!current->active_mm);
-need_resched_back:
-	prev = current;
-	this_cpu = prev->processor;
+/*
+ * double_rq_unlock - safely unlock two runqueues
+ *
+ * Note this does not restore interrupts like task_rq_unlock,
+ * you need to do so manually after calling.
+ */
+static inline void double_rq_unlock(runqueue_t *rq1, runqueue_t *rq2)
+{
+	spin_unlock(&rq1->lock);
+	if (rq1 != rq2)
+		spin_unlock(&rq2->lock);
+}
 
-	if (unlikely(in_interrupt())) {
-		printk("Scheduling in interrupt\n");
-		BUG();
+#if CONFIG_SMP
+/*
+ * double_lock_balance - lock the busiest runqueue
+ *
+ * this_rq is locked already. Recalculate nr_running if we have to
+ * drop the runqueue lock.
+ */
+static inline unsigned int double_lock_balance(runqueue_t *this_rq,
+	runqueue_t *busiest, int this_cpu, int idle, unsigned int nr_running)
+{
+	if (unlikely(!spin_trylock(&busiest->lock))) {
+		if (busiest < this_rq) {
+			spin_unlock(&this_rq->lock);
+			spin_lock(&busiest->lock);
+			spin_lock(&this_rq->lock);
+			/* Need to recalculate nr_running */
+			if (idle || (this_rq->nr_running > this_rq->prev_nr_running[this_cpu]))
+				nr_running = this_rq->nr_running;
+			else
+				nr_running = this_rq->prev_nr_running[this_cpu];
+		} else
+			spin_lock(&busiest->lock);
 	}
+	return nr_running;
+}
 
-	release_kernel_lock(prev, this_cpu);
+#include <linux/smp_balance.h>
 
+/*
+ * Current runqueue is empty, or rebalance tick: if there is an
+ * inbalance (current runqueue is too short) then pull from
+ * busiest runqueue(s).
+ *
+ * We call this with the current runqueue locked,
+ * irqs disabled.
+ */
+static void load_balance(runqueue_t *this_rq, int idle)
+{
+	int imbalance, nr_running, load, max_load,
+		idx, i, this_cpu = smp_processor_id();
+	task_t *next = this_rq->idle, *tmp;
+	runqueue_t *busiest, *rq_src;
+	prio_array_t *array;
+	struct list_head *head, *curr;
+
+	/*
+	 * Handle platform specific balancing operations, such as 
+	 * hyperthreading.
+	 */
+	 
+	if(arch_load_balance(this_cpu, idle))
+		return;
+		
 	/*
-	 * 'sched_data' is protected by the fact that we can run
-	 * only one process per CPU.
+	 * We search all runqueues to find the most busy one.
+	 * We do this lockless to reduce cache-bouncing overhead,
+	 * we re-check the 'best' source CPU later on again, with
+	 * the lock held.
+	 *
+	 * We fend off statistical fluctuations in runqueue lengths by
+	 * saving the runqueue length during the previous load-balancing
+	 * operation and using the smaller one the current and saved lengths.
+	 * If a runqueue is long enough for a longer amount of time then
+	 * we recognize it and pull tasks from it.
+	 *
+	 * The 'current runqueue length' is a statistical maximum variable,
+	 * for that one we take the longer one - to avoid fluctuations in
+	 * the other direction. So for a load-balance to happen it needs
+	 * stable long runqueue on the target CPU and stable short runqueue
+	 * on the local runqueue.
+	 *
+	 * We make an exception if this CPU is about to become idle - in
+	 * that case we are less picky about moving a task across CPUs and
+	 * take what can be taken.
 	 */
-	sched_data = & aligned_data[this_cpu].schedule_data;
+	if (idle || (this_rq->nr_running > this_rq->prev_nr_running[this_cpu]))
+		nr_running = this_rq->nr_running;
+	else
+		nr_running = this_rq->prev_nr_running[this_cpu];
 
-	spin_lock_irq(&runqueue_lock);
+	busiest = NULL;
+	max_load = 1;
+	for (i = 0; i < smp_num_cpus; i++) {
+		int logical = cpu_logical_map(i);
 
-	/* move an exhausted RR process to be last.. */
-	if (unlikely(prev->policy == SCHED_RR))
-		if (!prev->counter) {
-			prev->counter = NICE_TO_TICKS(prev->nice);
-			move_last_runqueue(prev);
+		rq_src = cpu_rq(logical);
+		if (idle || (rq_src->nr_running < this_rq->prev_nr_running[logical]))
+			load = rq_src->nr_running;
+		else
+			load = this_rq->prev_nr_running[logical];
+		this_rq->prev_nr_running[logical] = rq_src->nr_running;
+
+		if ((load > max_load) && (rq_src != this_rq)) {
+			busiest = rq_src;
+			max_load = load;
 		}
-
-	switch (prev->state) {
-		case TASK_INTERRUPTIBLE:
-			if (signal_pending(prev)) {
-				prev->state = TASK_RUNNING;
-				break;
-			}
-		default:
-			del_from_runqueue(prev);
-		case TASK_RUNNING:;
 	}
-	prev->need_resched = 0;
 
+	if (likely(!busiest))
+		return;
+
+	imbalance = (max_load - nr_running) / 2;
+
+	/* It needs an at least ~25% imbalance to trigger balancing. */
+	if (!idle && (imbalance < (max_load + 3)/4))
+		return;
+
+	nr_running = double_lock_balance(this_rq, busiest, this_cpu, idle, nr_running);
 	/*
-	 * this is the scheduler proper:
+	 * Make sure nothing changed since we checked the
+	 * runqueue length.
 	 */
+	if (busiest->nr_running <= nr_running + 1)
+		goto out_unlock;
 
-repeat_schedule:
 	/*
-	 * Default process to select..
+	 * We first consider expired tasks. Those will likely not be
+	 * executed in the near future, and they are most likely to
+	 * be cache-cold, thus switching CPUs has the least effect
+	 * on them.
 	 */
-	next = idle_task(this_cpu);
-	c = -1000;
-	list_for_each(tmp, &runqueue_head) {
-		p = list_entry(tmp, struct task_struct, run_list);
-		if (can_schedule(p, this_cpu)) {
-			int weight = goodness(p, this_cpu, prev->active_mm);
-			if (weight > c)
-				c = weight, next = p;
+	if (busiest->expired->nr_active)
+		array = busiest->expired;
+	else
+		array = busiest->active;
+
+new_array:
+	/* Start searching at priority 0: */
+	idx = 0;
+skip_bitmap:
+	if (!idx)
+		idx = sched_find_first_bit(array->bitmap);
+	else
+		idx = find_next_bit(array->bitmap, MAX_PRIO, idx);
+	if (idx == MAX_PRIO) {
+		if (array == busiest->expired) {
+			array = busiest->active;
+			goto new_array;
 		}
+		goto out_unlock;
 	}
 
-	/* Do we need to re-calculate counters? */
-	if (unlikely(!c)) {
-		struct task_struct *p;
-
-		spin_unlock_irq(&runqueue_lock);
-		read_lock(&tasklist_lock);
-		for_each_task(p)
-			p->counter = (p->counter >> 1) + NICE_TO_TICKS(p->nice);
-		read_unlock(&tasklist_lock);
-		spin_lock_irq(&runqueue_lock);
-		goto repeat_schedule;
+	head = array->queue + idx;
+	curr = head->prev;
+skip_queue:
+	tmp = list_entry(curr, task_t, run_list);
+
+	/*
+	 * We do not migrate tasks that are:
+	 * 1) running (obviously), or
+	 * 2) cannot be migrated to this CPU due to cpus_allowed, or
+	 * 3) are cache-hot on their current CPU.
+	 */
+
+#define CAN_MIGRATE_TASK(p,rq,this_cpu)					\
+	((jiffies - (p)->sleep_timestamp > cache_decay_ticks) &&	\
+		((p) != (rq)->curr) &&					\
+			((p)->cpus_allowed & (1UL << (this_cpu))))
+
+	if (!CAN_MIGRATE_TASK(tmp, busiest, this_cpu)) {
+		curr = curr->next;
+		if (curr != head)
+			goto skip_queue;
+		idx++;
+		goto skip_bitmap;
+	}
+	next = tmp;
+	/*
+	 * take the task out of the other runqueue and
+	 * put it into this one:
+	 */
+	dequeue_task(next, array);
+	busiest->nr_running--;
+	set_task_cpu(next, this_cpu);
+	this_rq->nr_running++;
+	enqueue_task(next, this_rq->active);
+	if (next->prio < current->prio)
+		set_need_resched();
+	if (!idle && --imbalance) {
+		if (array == busiest->expired) {
+			array = busiest->active;
+			goto new_array;
+		}
 	}
+out_unlock:
+	spin_unlock(&busiest->lock);
+}
 
-	/*
-	 * from this point on nothing can prevent us from
-	 * switching to the next task, save this fact in
-	 * sched_data.
-	 */
-	sched_data->curr = next;
-	task_set_cpu(next, this_cpu);
-	spin_unlock_irq(&runqueue_lock);
+/*
+ * One of the idle_cpu_tick() and busy_cpu_tick() functions will
+ * get called every timer tick, on every CPU. Our balancing action
+ * frequency and balancing agressivity depends on whether the CPU is
+ * idle or not.
+ *
+ * busy-rebalance every 250 msecs. idle-rebalance every 1 msec. (or on
+ * systems with HZ=100, every 10 msecs.)
+ */
+#define BUSY_REBALANCE_TICK (HZ/4 ?: 1)
+#define IDLE_REBALANCE_TICK (HZ/1000 ?: 1)
 
-	if (unlikely(prev == next)) {
-		/* We won't go through the normal tail, so do this by hand */
-		prev->policy &= ~SCHED_YIELD;
-		goto same_process;
-	}
+static inline void idle_tick(void)
+{
+	if (jiffies % IDLE_REBALANCE_TICK)
+		return;
+	spin_lock(&this_rq()->lock);
+	load_balance(this_rq(), 1);
+	spin_unlock(&this_rq()->lock);
+}
 
-#ifdef CONFIG_SMP
- 	/*
- 	 * maintain the per-process 'last schedule' value.
- 	 * (this has to be recalculated even if we reschedule to
- 	 * the same process) Currently this is only used on SMP,
-	 * and it's approximate, so we do not have to maintain
-	 * it while holding the runqueue spinlock.
- 	 */
- 	sched_data->last_schedule = get_cycles();
+#endif
 
-	/*
-	 * We drop the scheduler lock early (it's a global spinlock),
-	 * thus we have to lock the previous process from getting
-	 * rescheduled during switch_to().
-	 */
+/*
+ * We place interactive tasks back into the active array, if possible.
+ *
+ * To guarantee that this does not starve expired tasks we ignore the
+ * interactivity of a task if the first expired task had to wait more
+ * than a 'reasonable' amount of time. This deadline timeout is
+ * load-dependent, as the frequency of array switched decreases with
+ * increasing number of running tasks:
+ */
+#define EXPIRED_STARVING(rq) \
+		((rq)->expired_timestamp && \
+		(jiffies - (rq)->expired_timestamp >= \
+			STARVATION_LIMIT * ((rq)->nr_running) + 1))
 
-#endif /* CONFIG_SMP */
+/*
+ * This function gets called by the timer code, with HZ frequency.
+ * We call it with interrupts disabled.
+ */
+void scheduler_tick(int user_tick, int system)
+{
+	int cpu = smp_processor_id();
+	runqueue_t *rq = this_rq();
+	task_t *p = current;
 
-	kstat.context_swtch++;
-	/*
-	 * there are 3 processes which are affected by a context switch:
-	 *
-	 * prev == .... ==> (last => next)
-	 *
-	 * It's the 'much more previous' 'prev' that is on next's stack,
-	 * but prev is set to (the just run) 'last' process by switch_to().
-	 * This might sound slightly confusing but makes tons of sense.
-	 */
-	prepare_to_switch();
-	{
-		struct mm_struct *mm = next->mm;
-		struct mm_struct *oldmm = prev->active_mm;
-		if (!mm) {
-			BUG_ON(next->active_mm);
-			next->active_mm = oldmm;
-			atomic_inc(&oldmm->mm_count);
-			enter_lazy_tlb(oldmm, next, this_cpu);
-		} else {
-			BUG_ON(next->active_mm != mm);
-			switch_mm(oldmm, mm, next, this_cpu);
+	if (p == rq->idle) {
+		if (local_bh_count(cpu) || local_irq_count(cpu) > 1)
+			kstat.per_cpu_system[cpu] += system;
+#if CONFIG_SMP
+		idle_tick();
+#endif
+		return;
+	}
+	if (TASK_NICE(p) > 0)
+		kstat.per_cpu_nice[cpu] += user_tick;
+	else
+		kstat.per_cpu_user[cpu] += user_tick;
+	kstat.per_cpu_system[cpu] += system;
+
+	/* Task might have expired already, but not scheduled off yet */
+	if (p->array != rq->active) {
+		set_tsk_need_resched(p);
+		return;
+	}
+	spin_lock(&rq->lock);
+	if (unlikely(rt_task(p))) {
+		/*
+		 * RR tasks need a special form of timeslice management.
+		 * FIFO tasks have no timeslices.
+		 */
+		if ((p->policy == SCHED_RR) && !--p->time_slice) {
+			p->time_slice = task_timeslice(p);
+			set_tsk_need_resched(p);
+
+			/* put it at the end of the queue: */
+			dequeue_task(p, rq->active);
+			enqueue_task(p, rq->active);
 		}
+		goto out;
+	}
+	/*
+	 * The task was running during this tick - update the
+	 * time slice counter and the sleep average. Note: we
+	 * do not update a process's priority until it either
+	 * goes to sleep or uses up its timeslice. This makes
+	 * it possible for interactive tasks to use up their
+	 * timeslices at their highest priority levels.
+	 */
+	if (p->sleep_avg)
+		p->sleep_avg--;
+	if (!--p->time_slice) {
+		dequeue_task(p, rq->active);
+		set_tsk_need_resched(p);
+		p->prio = effective_prio(p);
+		p->time_slice = task_timeslice(p);
+
+		if (!TASK_INTERACTIVE(p) || EXPIRED_STARVING(rq)) {
+			if (!rq->expired_timestamp)
+				rq->expired_timestamp = jiffies;
+			enqueue_task(p, rq->expired);
+		} else
+			enqueue_task(p, rq->active);
+	}
+out:
+#if CONFIG_SMP
+	if (!(jiffies % BUSY_REBALANCE_TICK))
+		load_balance(rq, 0);
+#endif
+	spin_unlock(&rq->lock);
+}
+
+void scheduling_functions_start_here(void) { }
+
+/*
+ * schedule() is the main scheduler function.
+ */
+asmlinkage void schedule(void)
+{
+	task_t *prev, *next;
+	runqueue_t *rq;
+	prio_array_t *array;
+	struct list_head *queue;
+	int idx;
+
+	if (unlikely(in_interrupt()))
+		BUG();
+
+need_resched:
+	prev = current;
+	rq = this_rq();
+
+	release_kernel_lock(prev, smp_processor_id());
+	prepare_arch_schedule(prev);
+	prev->sleep_timestamp = jiffies;
+	spin_lock_irq(&rq->lock);
 
-		if (!prev->mm) {
-			prev->active_mm = NULL;
-			mmdrop(oldmm);
+	switch (prev->state) {
+	case TASK_INTERRUPTIBLE:
+		if (unlikely(signal_pending(prev))) {
+			prev->state = TASK_RUNNING;
+			break;
 		}
+	default:
+		deactivate_task(prev, rq);
+	case TASK_RUNNING:
+		;
+	}
+#if CONFIG_SMP
+pick_next_task:
+#endif
+	if (unlikely(!rq->nr_running)) {
+#if CONFIG_SMP
+		load_balance(rq, 1);
+		if (rq->nr_running)
+			goto pick_next_task;
+#endif
+		next = rq->idle;
+		rq->expired_timestamp = 0;
+		goto switch_tasks;
 	}
 
-	/*
-	 * This just switches the register state and the
-	 * stack.
-	 */
-	switch_to(prev, next, prev);
-	__schedule_tail(prev);
+	array = rq->active;
+	if (unlikely(!array->nr_active)) {
+		/*
+		 * Switch the active and expired arrays.
+		 */
+		rq->active = rq->expired;
+		rq->expired = array;
+		array = rq->active;
+		rq->expired_timestamp = 0;
+	}
+
+	idx = sched_find_first_bit(array->bitmap);
+	queue = array->queue + idx;
+	next = list_entry(queue->next, task_t, run_list);
+
+switch_tasks:
+	prefetch(next);
+	clear_tsk_need_resched(prev);
+
+	if (likely(prev != next)) {
+		rq->nr_switches++;
+		rq->curr = next;
+	
+		prepare_arch_switch(rq);
+		prev = context_switch(prev, next);
+		barrier();
+		rq = this_rq();
+		finish_arch_switch(rq);
+	} else
+		spin_unlock_irq(&rq->lock);
+	finish_arch_schedule(prev);
 
-same_process:
 	reacquire_kernel_lock(current);
-	if (current->need_resched)
-		goto need_resched_back;
-	return;
+	if (need_resched())
+		goto need_resched;
 }
 
 /*
- * The core wakeup function.  Non-exclusive wakeups (nr_exclusive == 0) just wake everything
- * up.  If it's an exclusive wakeup (nr_exclusive == small +ve number) then we wake all the
- * non-exclusive tasks and one exclusive task.
+ * The core wakeup function.  Non-exclusive wakeups (nr_exclusive == 0) just
+ * wake everything up.  If it's an exclusive wakeup (nr_exclusive == small +ve
+ * number) then we wake all the non-exclusive tasks and one exclusive task.
  *
  * There are circumstances in which we can try to wake a task which has already
- * started to run but is not in state TASK_RUNNING.  try_to_wake_up() returns zero
- * in this (rare) case, and we handle it by contonuing to scan the queue.
+ * started to run but is not in state TASK_RUNNING.  try_to_wake_up() returns
+ * zero in this (rare) case, and we handle it by continuing to scan the queue.
  */
-static inline void __wake_up_common (wait_queue_head_t *q, unsigned int mode,
-			 	     int nr_exclusive, const int sync)
+static inline void __wake_up_common(wait_queue_head_t *q, unsigned int mode, int nr_exclusive, int sync)
 {
 	struct list_head *tmp;
-	struct task_struct *p;
-
-	CHECK_MAGIC_WQHEAD(q);
-	WQ_CHECK_LIST_HEAD(&q->task_list);
-	
-	list_for_each(tmp,&q->task_list) {
-		unsigned int state;
-                wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list);
+	unsigned int state;
+	wait_queue_t *curr;
+	task_t *p;
 
-		CHECK_MAGIC(curr->__magic);
+	list_for_each(tmp, &q->task_list) {
+		curr = list_entry(tmp, wait_queue_t, task_list);
 		p = curr->task;
 		state = p->state;
-		if (state & mode) {
-			WQ_NOTE_WAKER(curr);
-			if (try_to_wake_up(p, sync) && (curr->flags&WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
+		if ((state & mode) && try_to_wake_up(p, sync) &&
+			((curr->flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive))
 				break;
-		}
 	}
 }
 
-void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr)
+/**
+ * __wake_up - wake up threads blocked on a waitqueue.
+ * @q: the waitqueue
+ * @mode: which threads
+ * @nr_exclusive: how many wake-one or wake-many threads to wake up
+ */
+void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr_exclusive)
 {
-	if (q) {
-		unsigned long flags;
-		wq_read_lock_irqsave(&q->lock, flags);
-		__wake_up_common(q, mode, nr, 0);
-		wq_read_unlock_irqrestore(&q->lock, flags);
-	}
+	unsigned long flags;
+
+	if (unlikely(!q))
+		return;
+
+	spin_lock_irqsave(&q->lock, flags);
+	__wake_up_common(q, mode, nr_exclusive, 0);
+	spin_unlock_irqrestore(&q->lock, flags);
 }
 
-void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr)
+#if CONFIG_SMP
+
+/**
+ * __wake_up - sync- wake up threads blocked on a waitqueue.
+ * @q: the waitqueue
+ * @mode: which threads
+ * @nr_exclusive: how many wake-one or wake-many threads to wake up
+ *
+ * The sync wakeup differs that the waker knows that it will schedule
+ * away soon, so while the target thread will be woken up, it will not
+ * be migrated to another CPU - ie. the two threads are 'synchronized'
+ * with each other. This can prevent needless bouncing between CPUs.
+ */
+void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive)
 {
-	if (q) {
-		unsigned long flags;
-		wq_read_lock_irqsave(&q->lock, flags);
-		__wake_up_common(q, mode, nr, 1);
-		wq_read_unlock_irqrestore(&q->lock, flags);
-	}
+	unsigned long flags;
+
+	if (unlikely(!q))
+		return;
+
+	spin_lock_irqsave(&q->lock, flags);
+	if (likely(nr_exclusive))
+		__wake_up_common(q, mode, nr_exclusive, 1);
+	else
+		__wake_up_common(q, mode, nr_exclusive, 0);
+	spin_unlock_irqrestore(&q->lock, flags);
 }
 
+#endif
+ 
 void complete(struct completion *x)
 {
 	unsigned long flags;
@@ -790,15 +1082,15 @@
 	wait_queue_t wait;			\
 	init_waitqueue_entry(&wait, current);
 
-#define	SLEEP_ON_HEAD					\
-	wq_write_lock_irqsave(&q->lock,flags);		\
+#define SLEEP_ON_HEAD					\
+	spin_lock_irqsave(&q->lock,flags);		\
 	__add_wait_queue(q, &wait);			\
-	wq_write_unlock(&q->lock);
+	spin_unlock(&q->lock);
 
 #define	SLEEP_ON_TAIL						\
-	wq_write_lock_irq(&q->lock);				\
+	spin_lock_irq(&q->lock);				\
 	__remove_wait_queue(q, &wait);				\
-	wq_write_unlock_irqrestore(&q->lock,flags);
+	spin_unlock_irqrestore(&q->lock, flags);
 
 void interruptible_sleep_on(wait_queue_head_t *q)
 {
@@ -850,17 +1142,53 @@
 
 void scheduling_functions_end_here(void) { }
 
+void set_user_nice(task_t *p, long nice)
+{
+	unsigned long flags;
+	prio_array_t *array;
+	runqueue_t *rq;
+
+	if (TASK_NICE(p) == nice || nice < -20 || nice > 19)
+		return;
+	/*
+	 * We have to be careful, if called from sys_setpriority(),
+	 * the task might be in the middle of scheduling on another CPU.
+	 */
+	rq = task_rq_lock(p, &flags);
+	if (rt_task(p)) {
+		p->static_prio = NICE_TO_PRIO(nice);
+		goto out_unlock;
+	}
+	array = p->array;
+	if (array)
+		dequeue_task(p, array);
+	p->static_prio = NICE_TO_PRIO(nice);
+	p->prio = NICE_TO_PRIO(nice);
+	if (array) {
+		enqueue_task(p, array);
+		/*
+		 * If the task is running and lowered its priority,
+		 * or increased its priority then reschedule its CPU:
+		 */
+		if ((NICE_TO_PRIO(nice) < p->static_prio) || (p == rq->curr))
+			resched_task(rq->curr);
+	}
+out_unlock:
+	task_rq_unlock(rq, &flags);
+}
+
 #ifndef __alpha__
 
-/*
- * This has been replaced by sys_setpriority.  Maybe it should be
- * moved into the arch dependent tree for those ports that require
- * it for backward compatibility?
+/**
+ * sys_nice - change the priority of the current process.
+ * @increment: priority increment
+ *
+ * sys_setpriority is a more generic, but much slower function that
+ * does similar things.
  */
-
 asmlinkage long sys_nice(int increment)
 {
-	long newprio;
+	long nice;
 
 	/*
 	 *	Setpriority might change our priority at the same moment.
@@ -876,34 +1204,69 @@
 	if (increment > 40)
 		increment = 40;
 
-	newprio = current->nice + increment;
-	if (newprio < -20)
-		newprio = -20;
-	if (newprio > 19)
-		newprio = 19;
-	current->nice = newprio;
+	nice = PRIO_TO_NICE(current->static_prio) + increment;
+	if (nice < -20)
+		nice = -20;
+	if (nice > 19)
+		nice = 19;
+	set_user_nice(current, nice);
 	return 0;
 }
 
 #endif
 
-static inline struct task_struct *find_process_by_pid(pid_t pid)
+/**
+ * task_prio - return the priority value of a given task.
+ * @p: the task in question.
+ *
+ * This is the priority value as seen by users in /proc.
+ * RT tasks are offset by -200. Normal tasks are centered
+ * around 0, value goes from -16 to +15.
+ */
+int task_prio(task_t *p)
+{
+	return p->prio - MAX_USER_RT_PRIO;
+}
+
+/**
+ * task_nice - return the nice value of a given task.
+ * @p: the task in question.
+ */
+int task_nice(task_t *p)
+{
+	return TASK_NICE(p);
+}
+
+/**
+ * idle_cpu - is a given cpu idle currently?
+ * @cpu: the processor in question.
+ */
+inline int idle_cpu(int cpu)
 {
-	struct task_struct *tsk = current;
+	return cpu_curr(cpu) == cpu_rq(cpu)->idle;
+}
 
-	if (pid)
-		tsk = find_task_by_pid(pid);
-	return tsk;
+/**
+ * find_process_by_pid - find a process with a matching PID value.
+ * @pid: the pid in question.
+ */
+static inline task_t *find_process_by_pid(pid_t pid)
+{
+	return pid ? find_task_by_pid(pid) : current;
 }
 
-static int setscheduler(pid_t pid, int policy, 
-			struct sched_param *param)
+/*
+ * setscheduler - change the scheduling policy and/or RT priority of a thread.
+ */
+static int setscheduler(pid_t pid, int policy, struct sched_param *param)
 {
 	struct sched_param lp;
-	struct task_struct *p;
-	int retval;
+	int retval = -EINVAL;
+	prio_array_t *array;
+	unsigned long flags;
+	runqueue_t *rq;
+	task_t *p;
 
-	retval = -EINVAL;
 	if (!param || pid < 0)
 		goto out_nounlock;
 
@@ -915,14 +1278,19 @@
 	 * We play safe to avoid deadlocks.
 	 */
 	read_lock_irq(&tasklist_lock);
-	spin_lock(&runqueue_lock);
 
 	p = find_process_by_pid(pid);
 
 	retval = -ESRCH;
 	if (!p)
-		goto out_unlock;
-			
+		goto out_unlock_tasklist;
+
+	/*
+	 * To be able to change p->policy safely, the apropriate
+	 * runqueue lock must be held.
+	 */
+	rq = task_rq_lock(p, &flags);
+
 	if (policy < 0)
 		policy = p->policy;
 	else {
@@ -931,56 +1299,78 @@
 				policy != SCHED_OTHER)
 			goto out_unlock;
 	}
-	
+
 	/*
-	 * Valid priorities for SCHED_FIFO and SCHED_RR are 1..99, valid
-	 * priority for SCHED_OTHER is 0.
+	 * Valid priorities for SCHED_FIFO and SCHED_RR are
+	 * 1..MAX_USER_RT_PRIO-1, valid priority for SCHED_OTHER is 0.
 	 */
 	retval = -EINVAL;
-	if (lp.sched_priority < 0 || lp.sched_priority > 99)
+	if (lp.sched_priority < 0 || lp.sched_priority > MAX_USER_RT_PRIO-1)
 		goto out_unlock;
 	if ((policy == SCHED_OTHER) != (lp.sched_priority == 0))
 		goto out_unlock;
 
 	retval = -EPERM;
-	if ((policy == SCHED_FIFO || policy == SCHED_RR) && 
+	if ((policy == SCHED_FIFO || policy == SCHED_RR) &&
 	    !capable(CAP_SYS_NICE))
 		goto out_unlock;
 	if ((current->euid != p->euid) && (current->euid != p->uid) &&
 	    !capable(CAP_SYS_NICE))
 		goto out_unlock;
 
+	array = p->array;
+	if (array)
+		deactivate_task(p, task_rq(p));
 	retval = 0;
 	p->policy = policy;
 	p->rt_priority = lp.sched_priority;
-
-	current->need_resched = 1;
+	if (policy != SCHED_OTHER)
+		p->prio = MAX_USER_RT_PRIO-1 - p->rt_priority;
+	else
+		p->prio = p->static_prio;
+	if (array)
+		activate_task(p, task_rq(p));
 
 out_unlock:
-	spin_unlock(&runqueue_lock);
+	task_rq_unlock(rq, &flags);
+out_unlock_tasklist:
 	read_unlock_irq(&tasklist_lock);
 
 out_nounlock:
 	return retval;
 }
 
-asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, 
+/**
+ * sys_sched_setscheduler - set/change the scheduler policy and RT priority
+ * @pid: the pid in question.
+ * @policy: new policy
+ * @param: structure containing the new RT priority.
+ */
+asmlinkage long sys_sched_setscheduler(pid_t pid, int policy,
 				      struct sched_param *param)
 {
 	return setscheduler(pid, policy, param);
 }
 
+/**
+ * sys_sched_setparam - set/change the RT priority of a thread
+ * @pid: the pid in question.
+ * @param: structure containing the new RT priority.
+ */
 asmlinkage long sys_sched_setparam(pid_t pid, struct sched_param *param)
 {
 	return setscheduler(pid, -1, param);
 }
 
+/**
+ * sys_sched_getscheduler - get the policy (scheduling class) of a thread
+ * @pid: the pid in question.
+ */
 asmlinkage long sys_sched_getscheduler(pid_t pid)
 {
-	struct task_struct *p;
-	int retval;
+	int retval = -EINVAL;
+	task_t *p;
 
-	retval = -EINVAL;
 	if (pid < 0)
 		goto out_nounlock;
 
@@ -988,20 +1378,24 @@
 	read_lock(&tasklist_lock);
 	p = find_process_by_pid(pid);
 	if (p)
-		retval = p->policy & ~SCHED_YIELD;
+		retval = p->policy;
 	read_unlock(&tasklist_lock);
 
 out_nounlock:
 	return retval;
 }
 
+/**
+ * sys_sched_getparam - get the RT priority of a thread
+ * @pid: the pid in question.
+ * @param: sched_param structure containing the RT priority.
+ */
 asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param *param)
 {
-	struct task_struct *p;
 	struct sched_param lp;
-	int retval;
+	int retval = -EINVAL;
+	task_t *p;
 
-	retval = -EINVAL;
 	if (!param || pid < 0)
 		goto out_nounlock;
 
@@ -1026,44 +1420,125 @@
 	return retval;
 }
 
-asmlinkage long sys_sched_yield(void)
+/**
+ * sys_sched_setaffinity - set the cpu affinity of a process
+ * @pid: pid of the process
+ * @len: length in bytes of the bitmask pointed to by user_mask_ptr
+ * @user_mask_ptr: user-space pointer to the new cpu mask
+ */
+asmlinkage int sys_sched_setaffinity(pid_t pid, unsigned int len,
+				      unsigned long *user_mask_ptr)
 {
+	unsigned long new_mask;
+	int retval;
+	task_t *p;
+
+	if (len < sizeof(new_mask))
+		return -EINVAL;
+
+	if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask)))
+		return -EFAULT;
+
+	new_mask &= cpu_online_map;
+	if (!new_mask)
+		return -EINVAL;
+
+	read_lock(&tasklist_lock);
+
+	p = find_process_by_pid(pid);
+	if (!p) {
+		read_unlock(&tasklist_lock);
+		return -ESRCH;
+	}
+
 	/*
-	 * Trick. sched_yield() first counts the number of truly 
-	 * 'pending' runnable processes, then returns if it's
-	 * only the current processes. (This test does not have
-	 * to be atomic.) In threaded applications this optimization
-	 * gets triggered quite often.
+	 * It is not safe to call set_cpus_allowed with the
+	 * tasklist_lock held.  We will bump the task_struct's
+	 * usage count and then drop tasklist_lock.
 	 */
+	get_task_struct(p);
+	read_unlock(&tasklist_lock);
 
-	int nr_pending = nr_running;
+	retval = -EPERM;
+	if ((current->euid != p->euid) && (current->euid != p->uid) &&
+			!capable(CAP_SYS_NICE))
+		goto out_unlock;
 
-#if CONFIG_SMP
-	int i;
+	retval = 0;
+	set_cpus_allowed(p, new_mask);
 
-	// Subtract non-idle processes running on other CPUs.
-	for (i = 0; i < smp_num_cpus; i++) {
-		int cpu = cpu_logical_map(i);
-		if (aligned_data[cpu].schedule_data.curr != idle_task(cpu))
-			nr_pending--;
-	}
-#else
-	// on UP this process is on the runqueue as well
-	nr_pending--;
-#endif
-	if (nr_pending) {
-		/*
-		 * This process can only be rescheduled by us,
-		 * so this is safe without any locking.
-		 */
-		if (current->policy == SCHED_OTHER)
-			current->policy |= SCHED_YIELD;
-		current->need_resched = 1;
-
-		spin_lock_irq(&runqueue_lock);
-		move_last_runqueue(current);
-		spin_unlock_irq(&runqueue_lock);
+out_unlock:
+	free_task_struct(p);
+	return retval;
+}
+
+/**
+ * sys_sched_getaffinity - get the cpu affinity of a process
+ * @pid: pid of the process
+ * @len: length in bytes of the bitmask pointed to by user_mask_ptr
+ * @user_mask_ptr: user-space pointer to hold the current cpu mask
+ */
+asmlinkage int sys_sched_getaffinity(pid_t pid, unsigned int len,
+				      unsigned long *user_mask_ptr)
+{
+	unsigned int real_len;
+	unsigned long mask;
+	int retval;
+	task_t *p;
+
+	real_len = sizeof(mask);
+	if (len < real_len)
+		return -EINVAL;
+
+	read_lock(&tasklist_lock);
+
+	retval = -ESRCH;
+	p = find_process_by_pid(pid);
+	if (!p)
+		goto out_unlock;
+
+	retval = 0;
+	mask = p->cpus_allowed & cpu_online_map;
+
+out_unlock:
+	read_unlock(&tasklist_lock);
+	if (retval)
+		return retval;
+	if (copy_to_user(user_mask_ptr, &mask, real_len))
+		return -EFAULT;
+	return real_len;
+}
+
+/**
+ * sys_sched_yield - yield the current processor to other threads.
+ *
+ * this function yields the current CPU by moving the calling thread
+ * to the expired array. If there are no other threads running on this
+ * CPU then this function will return.
+ */
+asmlinkage long sys_sched_yield(void)
+{
+	runqueue_t *rq = this_rq_lock();
+	prio_array_t *array = current->array;
+
+	/*
+	 * We implement yielding by moving the task into the expired
+	 * queue.
+	 *
+	 * (special rule: RT tasks will just roundrobin in the active
+	 *  array.)
+	 */
+	if (likely(!rt_task(current))) {
+		dequeue_task(current, array);
+		enqueue_task(current, rq->expired);
+	} else {
+		list_del(&current->run_list);
+		list_add_tail(&current->run_list, array->queue + current->prio);
 	}
+	spin_unlock(&rq->lock);
+
+	schedule();
+
 	return 0;
 }
 
@@ -1077,15 +1552,29 @@
 {
 	set_current_state(TASK_RUNNING);
 	sys_sched_yield();
-	schedule();
 }
 
+/**
+ * _cond_resched	-	conditionally reschedule
+ *
+ * Helper function called if cond_resched inline decides we have
+ * exceeded the timeslice at this point. We give up the processor
+ * having made sure we will get it back
+ */
+ 
 void __cond_resched(void)
 {
 	set_current_state(TASK_RUNNING);
 	schedule();
 }
 
+/**
+ * sys_sched_get_priority_max - return maximum RT priority.
+ * @policy: scheduling class.
+ *
+ * this syscall returns the maximum rt_priority that can be used
+ * by a given scheduling class.
+ */
 asmlinkage long sys_sched_get_priority_max(int policy)
 {
 	int ret = -EINVAL;
@@ -1093,7 +1582,7 @@
 	switch (policy) {
 	case SCHED_FIFO:
 	case SCHED_RR:
-		ret = 99;
+		ret = MAX_USER_RT_PRIO-1;
 		break;
 	case SCHED_OTHER:
 		ret = 0;
@@ -1102,6 +1591,13 @@
 	return ret;
 }
 
+/**
+ * sys_sched_get_priority_min - return minimum RT priority.
+ * @policy: scheduling class.
+ *
+ * this syscall returns the minimum rt_priority that can be used
+ * by a given scheduling class.
+ */
 asmlinkage long sys_sched_get_priority_min(int policy)
 {
 	int ret = -EINVAL;
@@ -1117,11 +1613,19 @@
 	return ret;
 }
 
+/**
+ * sys_sched_rr_get_interval - return the default timeslice of a process.
+ * @pid: pid of the process.
+ * @interval: userspace pointer to the timeslice value.
+ *
+ * this syscall writes the default timeslice value of a given process
+ * into the user-space timespec buffer. A value of '0' means infinity.
+ */
 asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval)
 {
-	struct timespec t;
-	struct task_struct *p;
 	int retval = -EINVAL;
+	struct timespec t;
+	task_t *p;
 
 	if (pid < 0)
 		goto out_nounlock;
@@ -1130,8 +1634,8 @@
 	read_lock(&tasklist_lock);
 	p = find_process_by_pid(pid);
 	if (p)
-		jiffies_to_timespec(p->policy & SCHED_FIFO ? 0 : NICE_TO_TICKS(p->nice),
-				    &t);
+		jiffies_to_timespec(p->policy & SCHED_FIFO ?
+					 0 : task_timeslice(p), &t);
 	read_unlock(&tasklist_lock);
 	if (p)
 		retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0;
@@ -1139,14 +1643,14 @@
 	return retval;
 }
 
-static void show_task(struct task_struct * p)
+static void show_task(task_t * p)
 {
 	unsigned long free = 0;
 	int state;
 	static const char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" };
 
 	printk("%-13.13s ", p->comm);
-	state = p->state ? ffz(~p->state) + 1 : 0;
+	state = p->state ? __ffs(p->state) + 1 : 0;
 	if (((unsigned) state) < sizeof(stat_nam)/sizeof(char *))
 		printk(stat_nam[state]);
 	else
@@ -1187,7 +1691,7 @@
 		printk(" (NOTLB)\n");
 
 	{
-		extern void show_trace_task(struct task_struct *tsk);
+		extern void show_trace_task(task_t *tsk);
 		show_trace_task(p);
 	}
 }
@@ -1209,7 +1713,7 @@
 
 void show_state(void)
 {
-	struct task_struct *p;
+	task_t *p;
 
 #if (BITS_PER_LONG == 32)
 	printk("\n"
@@ -1232,128 +1736,241 @@
 	read_unlock(&tasklist_lock);
 }
 
-/**
- * reparent_to_init() - Reparent the calling kernel thread to the init task.
- *
- * If a kernel thread is launched as a result of a system call, or if
- * it ever exits, it should generally reparent itself to init so that
- * it is correctly cleaned up on exit.
- *
- * The various task state such as scheduling policy and priority may have
- * been inherited fro a user process, so we reset them to sane values here.
- *
- * NOTE that reparent_to_init() gives the caller full capabilities.
- */
-void reparent_to_init(void)
+void __init init_idle(task_t *idle, int cpu)
 {
-	struct task_struct *this_task = current;
+	runqueue_t *idle_rq = cpu_rq(cpu), *rq = cpu_rq(task_cpu(idle));
+	unsigned long flags;
+
+	__save_flags(flags);
+	__cli();
+	double_rq_lock(idle_rq, rq);
+
+	idle_rq->curr = idle_rq->idle = idle;
+	deactivate_task(idle, rq);
+	idle->array = NULL;
+	idle->prio = MAX_PRIO;
+	idle->state = TASK_RUNNING;
+	set_task_cpu(idle, cpu);
+	double_rq_unlock(idle_rq, rq);
+	set_tsk_need_resched(idle);
+	__restore_flags(flags);
+}
 
-	write_lock_irq(&tasklist_lock);
+extern void init_timervecs(void);
+extern void timer_bh(void);
+extern void tqueue_bh(void);
+extern void immediate_bh(void);
 
-	/* Reparent to init */
-	REMOVE_LINKS(this_task);
-	this_task->p_pptr = child_reaper;
-	this_task->p_opptr = child_reaper;
-	SET_LINKS(this_task);
+void __init sched_init(void)
+{
+	runqueue_t *rq;
+	int i, j, k;
 
-	/* Set the exit signal to SIGCHLD so we signal init on exit */
-	this_task->exit_signal = SIGCHLD;
+	for (i = 0; i < NR_CPUS; i++) {
+		prio_array_t *array;
 
-	/* We also take the runqueue_lock while altering task fields
-	 * which affect scheduling decisions */
-	spin_lock(&runqueue_lock);
+		rq = cpu_rq(i);
+		rq->active = rq->arrays;
+		rq->expired = rq->arrays + 1;
+		spin_lock_init(&rq->lock);
+		INIT_LIST_HEAD(&rq->migration_queue);
+
+		for (j = 0; j < 2; j++) {
+			array = rq->arrays + j;
+			for (k = 0; k < MAX_PRIO; k++) {
+				INIT_LIST_HEAD(array->queue + k);
+				__clear_bit(k, array->bitmap);
+			}
+			// delimiter for bitsearch
+			__set_bit(MAX_PRIO, array->bitmap);
+		}
+	}
+	/*
+	 * We have to do a little magic to get the first
+	 * process right in SMP mode.
+	 */
+	rq = this_rq();
+	rq->curr = current;
+	rq->idle = current;
+	wake_up_process(current);
 
-	this_task->ptrace = 0;
-	this_task->nice = DEF_NICE;
-	this_task->policy = SCHED_OTHER;
-	/* cpus_allowed? */
-	/* rt_priority? */
-	/* signals? */
-	this_task->cap_effective = CAP_INIT_EFF_SET;
-	this_task->cap_inheritable = CAP_INIT_INH_SET;
-	this_task->cap_permitted = CAP_FULL_SET;
-	this_task->keep_capabilities = 0;
-	memcpy(this_task->rlim, init_task.rlim, sizeof(*(this_task->rlim)));
-	this_task->user = INIT_USER;
+	init_timervecs();
+	init_bh(TIMER_BH, timer_bh);
+	init_bh(TQUEUE_BH, tqueue_bh);
+	init_bh(IMMEDIATE_BH, immediate_bh);
 
-	spin_unlock(&runqueue_lock);
-	write_unlock_irq(&tasklist_lock);
+	/*
+	 * The boot idle thread does lazy MMU switching as well:
+	 */
+	atomic_inc(&init_mm.mm_count);
+	enter_lazy_tlb(&init_mm, current, smp_processor_id());
 }
 
+#if CONFIG_SMP
+
 /*
- *	Put all the gunge required to become a kernel thread without
- *	attached user resources in one place where it belongs.
+ * This is how migration works:
+ *
+ * 1) we queue a migration_req_t structure in the source CPU's
+ *    runqueue and wake up that CPU's migration thread.
+ * 2) we down() the locked semaphore => thread blocks.
+ * 3) migration thread wakes up (implicitly it forces the migrated
+ *    thread off the CPU)
+ * 4) it gets the migration request and checks whether the migrated
+ *    task is still in the wrong runqueue.
+ * 5) if it's in the wrong runqueue then the migration thread removes
+ *    it and puts it into the right queue.
+ * 6) migration thread up()s the semaphore.
+ * 7) we wake up and the migration is done.
  */
 
-void daemonize(void)
+typedef struct {
+	struct list_head list;
+	task_t *task;
+	struct semaphore sem;
+} migration_req_t;
+
+/*
+ * Change a given task's CPU affinity. Migrate the process to a
+ * proper CPU and schedule it away if the CPU it's executing on
+ * is removed from the allowed bitmask.
+ *
+ * NOTE: the caller must have a valid reference to the task, the
+ * task must not exit() & deallocate itself prematurely.  The
+ * call is not atomic; no spinlocks may be held.
+ */
+void set_cpus_allowed(task_t *p, unsigned long new_mask)
 {
-	struct fs_struct *fs;
+	unsigned long flags;
+	migration_req_t req;
+	runqueue_t *rq;
 
+	new_mask &= cpu_online_map;
+	if (!new_mask)
+		BUG();
 
+	rq = task_rq_lock(p, &flags);
+	p->cpus_allowed = new_mask;
 	/*
-	 * If we were started as result of loading a module, close all of the
-	 * user space pages.  We don't need them, and if we didn't close them
-	 * they would be locked into memory.
+	 * Can the task run on the task's current CPU? If not then
+	 * migrate the process off to a proper CPU.
 	 */
-	exit_mm(current);
-
-	current->session = 1;
-	current->pgrp = 1;
-	current->tty = NULL;
-
-	/* Become as one with the init task */
+	if (new_mask & (1UL << task_cpu(p))) {
+		task_rq_unlock(rq, &flags);
+		goto out;
+	}
+	/*
+	 * If the task is not on a runqueue (and not running), then
+	 * it is sufficient to simply update the task's cpu field.
+	 */
+	if (!p->array && (p != rq->curr)) {
+		set_task_cpu(p, __ffs(p->cpus_allowed));
+		task_rq_unlock(rq, &flags);
+		goto out;
+	}
+	init_MUTEX_LOCKED(&req.sem);
+	req.task = p;
+	list_add(&req.list, &rq->migration_queue);
+	task_rq_unlock(rq, &flags);
+	wake_up_process(rq->migration_thread);
 
-	exit_fs(current);	/* current->fs->count--; */
-	fs = init_task.fs;
-	current->fs = fs;
-	atomic_inc(&fs->count);
- 	exit_files(current);
-	current->files = init_task.files;
-	atomic_inc(&current->files->count);
+	down(&req.sem);
+out:
+	;
 }
 
-extern unsigned long wait_init_idle;
-
-void __init init_idle(void)
+/*
+ * migration_thread - this is a highprio system thread that performs
+ * thread migration by 'pulling' threads into the target runqueue.
+ */
+static int migration_thread(void * bind_cpu)
 {
-	struct schedule_data * sched_data;
-	sched_data = &aligned_data[smp_processor_id()].schedule_data;
+	struct sched_param param = { sched_priority: MAX_RT_PRIO-1 };
+	int cpu = cpu_logical_map((int) (long) bind_cpu);
+	runqueue_t *rq;
+	int ret;
+
+	daemonize();
+	sigfillset(&current->blocked);
+	set_fs(KERNEL_DS);
+	/*
+	 * The first migration thread is started on CPU #0. This one can
+	 * migrate the other migration threads to their destination CPUs.
+	 */
+	if (cpu != 0) {
+		while (!cpu_rq(cpu_logical_map(0))->migration_thread)
+			yield();
+		set_cpus_allowed(current, 1UL << cpu);
+	}
+	printk("migration_task %d on cpu=%d\n", cpu, smp_processor_id());
+	ret = setscheduler(0, SCHED_FIFO, &param);
+
+	rq = this_rq();
+	rq->migration_thread = current;
+
+	sprintf(current->comm, "migration_CPU%d", smp_processor_id());
+
+	for (;;) {
+		runqueue_t *rq_src, *rq_dest;
+		struct list_head *head;
+		int cpu_src, cpu_dest;
+		migration_req_t *req;
+		unsigned long flags;
+		task_t *p;
+
+		spin_lock_irqsave(&rq->lock, flags);
+		head = &rq->migration_queue;
+		current->state = TASK_INTERRUPTIBLE;
+		if (list_empty(head)) {
+			spin_unlock_irqrestore(&rq->lock, flags);
+			schedule();
+			continue;
+		}
+		req = list_entry(head->next, migration_req_t, list);
+		list_del_init(head->next);
+		spin_unlock_irqrestore(&rq->lock, flags);
+
+		p = req->task;
+		cpu_dest = __ffs(p->cpus_allowed);
+		rq_dest = cpu_rq(cpu_dest);
+repeat:
+		cpu_src = task_cpu(p);
+		rq_src = cpu_rq(cpu_src);
+
+		local_irq_save(flags);
+		double_rq_lock(rq_src, rq_dest);
+		if (task_cpu(p) != cpu_src) {
+			double_rq_unlock(rq_src, rq_dest);
+			local_irq_restore(flags);
+			goto repeat;
+		}
+		if (rq_src == rq) {
+			set_task_cpu(p, cpu_dest);
+			if (p->array) {
+				deactivate_task(p, rq_src);
+				activate_task(p, rq_dest);
+			}
+		}
+		double_rq_unlock(rq_src, rq_dest);
+		local_irq_restore(flags);
 
-	if (current != &init_task && task_on_runqueue(current)) {
-		printk("UGH! (%d:%d) was on the runqueue, removing.\n",
-			smp_processor_id(), current->pid);
-		del_from_runqueue(current);
+		up(&req->sem);
 	}
-	sched_data->curr = current;
-	sched_data->last_schedule = get_cycles();
-	clear_bit(current->processor, &wait_init_idle);
 }
 
-extern void init_timervecs (void);
-
-void __init sched_init(void)
+void __init migration_init(void)
 {
-	/*
-	 * We have to do a little magic to get the first
-	 * process right in SMP mode.
-	 */
-	int cpu = smp_processor_id();
-	int nr;
-
-	init_task.processor = cpu;
-
-	for(nr = 0; nr < PIDHASH_SZ; nr++)
-		pidhash[nr] = NULL;
-
-	init_timervecs();
+	int cpu;
 
-	init_bh(TIMER_BH, timer_bh);
-	init_bh(TQUEUE_BH, tqueue_bh);
-	init_bh(IMMEDIATE_BH, immediate_bh);
+	current->cpus_allowed = 1UL << cpu_logical_map(0);
+	for (cpu = 0; cpu < smp_num_cpus; cpu++)
+		if (kernel_thread(migration_thread, (void *) (long) cpu,
+				CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0)
+			BUG();
+	current->cpus_allowed = -1L;
 
-	/*
-	 * The boot idle thread does lazy MMU switching as well:
-	 */
-	atomic_inc(&init_mm.mm_count);
-	enter_lazy_tlb(&init_mm, current, cpu);
+	for (cpu = 0; cpu < smp_num_cpus; cpu++)
+		while (!cpu_rq(cpu_logical_map(cpu))->migration_thread)
+			schedule_timeout(2);
 }
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/kernel/signal.c linux.20pre10-ac2/kernel/signal.c
--- linux.20pre10/kernel/signal.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/kernel/signal.c	2002-08-06 15:41:51.000000000 +0100
@@ -492,7 +492,7 @@
  * No need to set need_resched since signal event passing
  * goes through ->blocked
  */
-static inline void signal_wake_up(struct task_struct *t)
+inline void signal_wake_up(struct task_struct *t)
 {
 	t->sigpending = 1;
 
@@ -507,12 +507,9 @@
 	 * process of changing - but no harm is done by that
 	 * other than doing an extra (lightweight) IPI interrupt.
 	 */
-	spin_lock(&runqueue_lock);
-	if (task_has_cpu(t) && t->processor != smp_processor_id())
-		smp_send_reschedule(t->processor);
-	spin_unlock(&runqueue_lock);
-#endif /* CONFIG_SMP */
-
+	if ((t->state == TASK_RUNNING) && (t->cpu != cpu()))
+		kick_if_running(t);
+#endif
 	if (t->state & TASK_INTERRUPTIBLE) {
 		wake_up_process(t);
 		return;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/kernel/softirq.c linux.20pre10-ac2/kernel/softirq.c
--- linux.20pre10/kernel/softirq.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/kernel/softirq.c	2002-08-29 18:58:57.000000000 +0100
@@ -259,9 +259,9 @@
 
 	while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
 		current->state = TASK_RUNNING;
-		do {
+		do
 			yield();
-		} while (test_bit(TASKLET_STATE_SCHED, &t->state));
+		while (test_bit(TASKLET_STATE_SCHED, &t->state));
 	}
 	tasklet_unlock_wait(t);
 	clear_bit(TASKLET_STATE_SCHED, &t->state);
@@ -364,13 +364,13 @@
 	int cpu = cpu_logical_map(bind_cpu);
 
 	daemonize();
-	current->nice = 19;
+	set_user_nice(current, 19);
 	sigfillset(&current->blocked);
 
 	/* Migrate to the right CPU */
-	current->cpus_allowed = 1UL << cpu;
-	while (smp_processor_id() != cpu)
-		schedule();
+	set_cpus_allowed(current, 1UL << cpu);
+	if (cpu() != cpu)
+		BUG();
 
 	sprintf(current->comm, "ksoftirqd_CPU%d", bind_cpu);
 
@@ -395,7 +395,7 @@
 	}
 }
 
-static __init int spawn_ksoftirqd(void)
+__init int spawn_ksoftirqd(void)
 {
 	int cpu;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/kernel/sys.c linux.20pre10-ac2/kernel/sys.c
--- linux.20pre10/kernel/sys.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/kernel/sys.c	2002-08-06 15:41:51.000000000 +0100
@@ -4,6 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/utsname.h>
@@ -220,10 +221,10 @@
 		}
 		if (error == -ESRCH)
 			error = 0;
-		if (niceval < p->nice && !capable(CAP_SYS_NICE))
+		if (niceval < task_nice(p) && !capable(CAP_SYS_NICE))
 			error = -EACCES;
 		else
-			p->nice = niceval;
+			set_user_nice(p, niceval);
 	}
 	read_unlock(&tasklist_lock);
 
@@ -249,7 +250,7 @@
 		long niceval;
 		if (!proc_sel(p, which, who))
 			continue;
-		niceval = 20 - p->nice;
+		niceval = 20 - task_nice(p);
 		if (niceval > retval)
 			retval = niceval;
 	}
@@ -490,9 +491,10 @@
 	}
 }
 
-static int set_user(uid_t new_ruid, int dumpclear)
+int set_user(uid_t new_ruid, int dumpclear)
 {
 	struct user_struct *new_user, *old_user;
+	struct task_struct *this_task = current;
 
 	/* What if a process setreuid()'s and this brings the
 	 * new uid over his NPROC rlimit?  We can check this now
@@ -502,17 +504,16 @@
 	new_user = alloc_uid(new_ruid);
 	if (!new_user)
 		return -EAGAIN;
-	old_user = current->user;
-	atomic_dec(&old_user->processes);
+	old_user = this_task->user;
 	atomic_inc(&new_user->processes);
+	atomic_dec(&old_user->processes);
 
-	if(dumpclear)
-	{
-		current->mm->dumpable = 0;
+	if (dumpclear && this_task->mm) {
+		this_task->mm->dumpable = 0;
 		wmb();
 	}
-	current->uid = new_ruid;
-	current->user = new_user;
+	this_task->uid = new_ruid;
+	this_task->user = new_user;
 	free_uid(old_user);
 	return 0;
 }
@@ -1128,6 +1129,12 @@
 	if (resource == RLIMIT_NOFILE) {
 		if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN)
 			return -EPERM;
+	} else if (resource == RLIMIT_RSS && current->mm) {
+		/* rlimit is specified in bytes, convert to pages */
+		unsigned long pages = RLIM_INFINITY;
+		if (new_rlim.rlim_cur != RLIM_INFINITY)
+			pages = new_rlim.rlim_cur >> PAGE_SHIFT;
+		current->mm->rlimit_rss = pages;
 	}
 	*old_rlim = new_rlim;
 	return 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/kernel/sysctl.c linux.20pre10-ac2/kernel/sysctl.c
--- linux.20pre10/kernel/sysctl.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/kernel/sysctl.c	2002-09-29 20:36:44.000000000 +0100
@@ -49,6 +49,7 @@
 extern int max_queued_signals;
 extern int sysrq_enabled;
 extern int core_uses_pid;
+extern char core_pattern[];
 extern int cad_pid;
 
 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
@@ -171,6 +172,8 @@
 	 0644, NULL, &proc_dointvec},
 	{KERN_CORE_USES_PID, "core_uses_pid", &core_uses_pid, sizeof(int),
 	 0644, NULL, &proc_dointvec},
+	{KERN_CORE_PATTERN, "core_pattern", core_pattern, 64,
+	 0644, NULL, &proc_dostring, &sysctl_string},
 	{KERN_TAINTED, "tainted", &tainted, sizeof(int),
 	 0644, NULL, &proc_dointvec},
 	{KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t),
@@ -271,12 +274,12 @@
 	 &pgt_cache_water, 2*sizeof(int), 0644, NULL, &proc_dointvec},
 	{VM_PAGE_CLUSTER, "page-cluster", 
 	 &page_cluster, sizeof(int), 0644, NULL, &proc_dointvec},
+	{VM_MAX_MAP_COUNT, "max_map_count",
+	 &max_map_count, sizeof(int), 0644, NULL, &proc_dointvec},
 	{VM_MIN_READAHEAD, "min-readahead",
 	&vm_min_readahead,sizeof(int), 0644, NULL, &proc_dointvec},
 	{VM_MAX_READAHEAD, "max-readahead",
 	&vm_max_readahead,sizeof(int), 0644, NULL, &proc_dointvec},
-	{VM_MAX_MAP_COUNT, "max_map_count",
-	 &max_map_count, sizeof(int), 0644, NULL, &proc_dointvec},
 	{0}
 };
 
@@ -293,8 +296,6 @@
 	 0444, NULL, &proc_dointvec},
 	{FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int),
 	 0644, NULL, &proc_dointvec},
-	{FS_NRDQUOT, "dquot-nr", &nr_dquots, 2*sizeof(int),
-	 0444, NULL, &proc_dointvec},
 	{FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
 	 0444, NULL, &proc_dointvec},
 	{FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL,
@@ -320,6 +321,7 @@
 	{0}
 };  
 
+
 extern void init_irq_proc (void);
 
 void __init sysctl_init(void)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/kernel/timer.c linux.20pre10-ac2/kernel/timer.c
--- linux.20pre10/kernel/timer.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/kernel/timer.c	2002-10-09 21:52:22.000000000 +0100
@@ -25,6 +25,8 @@
 
 #include <asm/uaccess.h>
 
+struct kernel_stat kstat;
+
 /*
  * Timekeeping variables
  */
@@ -598,25 +600,7 @@
 	int cpu = smp_processor_id(), system = user_tick ^ 1;
 
 	update_one_process(p, user_tick, system, cpu);
-	if (p->pid) {
-		if (--p->counter <= 0) {
-			p->counter = 0;
-			/*
-			 * SCHED_FIFO is priority preemption, so this is 
-			 * not the place to decide whether to reschedule a
-			 * SCHED_FIFO task or not - Bhavesh Davda
-			 */
-			if (p->policy != SCHED_FIFO) {
-				p->need_resched = 1;
-			}
-		}
-		if (p->nice > 0)
-			kstat.per_cpu_nice[cpu] += user_tick;
-		else
-			kstat.per_cpu_user[cpu] += user_tick;
-		kstat.per_cpu_system[cpu] += system;
-	} else if (local_bh_count(cpu) || local_irq_count(cpu) > 1)
-		kstat.per_cpu_system[cpu] += system;
+	scheduler_tick(user_tick, system);
 }
 
 /*
@@ -624,17 +608,7 @@
  */
 static unsigned long count_active_tasks(void)
 {
-	struct task_struct *p;
-	unsigned long nr = 0;
-
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
-		if ((p->state == TASK_RUNNING ||
-		     (p->state & TASK_UNINTERRUPTIBLE)))
-			nr += FIXED_1;
-	}
-	read_unlock(&tasklist_lock);
-	return nr;
+        return (nr_running() + nr_uninterruptible()) * FIXED_1;
 }
 
 /*
@@ -827,6 +801,89 @@
 
 #endif
 
+static void process_timeout(unsigned long __data)
+{
+	wake_up_process((task_t *)__data);
+}
+
+/**
+ * schedule_timeout - sleep until timeout
+ * @timeout: timeout value in jiffies
+ *
+ * Make the current task sleep until @timeout jiffies have
+ * elapsed. The routine will return immediately unless
+ * the current task state has been set (see set_current_state()).
+ *
+ * You can set the task state as follows -
+ *
+ * %TASK_UNINTERRUPTIBLE - at least @timeout jiffies are guaranteed to
+ * pass before the routine returns. The routine will return 0
+ *
+ * %TASK_INTERRUPTIBLE - the routine may return early if a signal is
+ * delivered to the current task. In this case the remaining time
+ * in jiffies will be returned, or 0 if the timer expired in time
+ *
+ * The current task state is guaranteed to be TASK_RUNNING when this 
+ * routine returns.
+ *
+ * Specifying a @timeout value of %MAX_SCHEDULE_TIMEOUT will schedule
+ * the CPU away without a bound on the timeout. In this case the return
+ * value will be %MAX_SCHEDULE_TIMEOUT.
+ *
+ * In all cases the return value is guaranteed to be non-negative.
+ */
+signed long schedule_timeout(signed long timeout)
+{
+	struct timer_list timer;
+	unsigned long expire;
+
+	switch (timeout)
+	{
+	case MAX_SCHEDULE_TIMEOUT:
+		/*
+		 * These two special cases are useful to be comfortable
+		 * in the caller. Nothing more. We could take
+		 * MAX_SCHEDULE_TIMEOUT from one of the negative value
+		 * but I' d like to return a valid offset (>=0) to allow
+		 * the caller to do everything it want with the retval.
+		 */
+		schedule();
+		goto out;
+	default:
+		/*
+		 * Another bit of PARANOID. Note that the retval will be
+		 * 0 since no piece of kernel is supposed to do a check
+		 * for a negative retval of schedule_timeout() (since it
+		 * should never happens anyway). You just have the printk()
+		 * that will tell you if something is gone wrong and where.
+		 */
+		if (timeout < 0)
+		{
+			printk(KERN_ERR "schedule_timeout: wrong timeout "
+			       "value %lx from %p\n", timeout,
+			       __builtin_return_address(0));
+			current->state = TASK_RUNNING;
+			goto out;
+		}
+	}
+
+	expire = timeout + jiffies;
+
+	init_timer(&timer);
+	timer.expires = expire;
+	timer.data = (unsigned long) current;
+	timer.function = process_timeout;
+
+	add_timer(&timer);
+	schedule();
+	del_timer_sync(&timer);
+
+	timeout = expire - jiffies;
+
+ out:
+	return timeout < 0 ? 0 : timeout;
+}
+
 /* Thread ID - the internal kernel "pid" */
 asmlinkage long sys_gettid(void)
 {
@@ -873,4 +930,3 @@
 	}
 	return 0;
 }
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/MAINTAINERS linux.20pre10-ac2/MAINTAINERS
--- linux.20pre10/MAINTAINERS	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/MAINTAINERS	2002-10-10 23:56:47.000000000 +0100
@@ -154,6 +154,14 @@
 W:	http://www.ibm.com/linux/ltc/
 S:	Supported
 
+AACRAID SCSI RAID DRIVER
+P:	Adaptec OEM Raid Solutions
+M:	linux-aacraid-devel@dell.com
+L:	linux-aacraid-devel@dell.com
+L:	linux-aacraid-announce@dell.com
+W:	http://domsch.com/linux
+S:	Supported
+
 ACPI
 P:	Andy Grover
 M:	andrew.grover@intel.com
@@ -245,7 +253,7 @@
 BEFS FILE SYSTEM
 P:	Will Dyson
 M:	will@cs.earlham.edu
-W:	http://cs.earlham.edu/~will/software/linux/kernel/BeFS.html
+W:	http://befs-driver.sourceforge.net/
 S:	Maintained
 
 BERKSHIRE PRODUCTS PC WATCHDOG DRIVER
@@ -286,13 +294,6 @@
 W:	http://bytesex.org/bttv/
 S:	Maintained
 
-BUSLOGIC SCSI DRIVER
-P:	Leonard N. Zubkoff
-M:	Leonard N. Zubkoff <lnz@dandelion.com>
-L:	linux-scsi@vger.kernel.org
-W:	http://www.dandelion.com/Linux/
-S:	Maintained
-
 CIRRUS LOGIC GENERIC FBDEV DRIVER
 P:	Jeff Garzik
 M:	jgarzik@mandrakesoft.com
@@ -439,6 +440,13 @@
 W:	http://www.debian.org/~dz/i8k/
 S:	Maintained
 
+DEVICE-MAPPER
+P:	Joe Thornber
+M:	thornber@sistina.com
+L:	dm@uk.sistina.com
+W:	http://www.sistina.com/lvm
+S:	Maintained
+
 DEVICE NUMBER REGISTRY
 P:	H. Peter Anvin
 M:	hpa@zytor.com
@@ -948,6 +956,11 @@
 L:	linuxppc-dev@lists.linuxppc.org
 S:	Maintained
 
+LLC (802.2)
+P:	Arnaldo Carvalho de Melo
+M:	acme@conectiva.com.br
+S:	Maintained
+
 LINUX FOR 64BIT POWERPC
 P:	David Engebretsen
 M:	engebret@us.ibm.com
@@ -1145,6 +1158,14 @@
 W:	http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
 S:	Maintained
 
+NINJA SCSI-32Bi/UDE PCI/CARDBUS SCSI HOST ADAPTER DRIVER
+P:	GOTO Masanori
+M:	gotom@debian.or.jp
+P:	YOKOTA Hiroshi
+M:	yokota@netlab.is.tsukuba.ac.jp
+W:	http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
+S:	Maintained
+
 NON-IDE/NON-SCSI CDROM DRIVERS [GENERAL] (come on, crew - mark your responsibility)
 P:	Eberhard Moenkeberg
 M:	emoenke@gwdg.de
@@ -1277,6 +1298,13 @@
 W:	http://www.realitydiluted.com/projects/nino
 S:	Maintained
 
+PHILIPS NINO PALM PC
+P:	Steven Hill
+M:	sjhill@realitydiluted.com
+L:	linux-mips@oss.sgi.com
+W:	http://www.realitydiluted.com/projects/nino
+S:	Maintained
+
 PNP SUPPORT
 P:	Tom Lees
 M:	tom@lpsg.demon.co.uk
@@ -1307,17 +1335,6 @@
 W:	http://www.pnd-pc.demon.co.uk/promise/
 S:	Maintained
 
-PROMISE PDC202XX IDE CONTROLLER DRIVER
-P:	Hank Yang
-M:	support@promise.com.tw [TAIWAN]
-P:	Jordan Rhody
-M:	support@promise.com [U.S.A]
-P:	Jack Hu
-M:	support-china@promise.com [CHINA]
-W:	http://www.promise.com/support/linux_eng.asp
-W:	http://www.promise.com.tw/support/linux_eng.asp
-S:	Maintained
-
 QNX4 FILESYSTEM
 P:	Anders Larsen
 M:	al@alarsen.net
@@ -1430,6 +1447,12 @@
 L:	linux-scsi@vger.kernel.org
 S:	Maintained
 
+SCx200 CPU SUPPORT
+P:	Christer Weinigel
+M:	christer@weinigel.se
+W:	http://www.weinigel.se
+S:	Supported
+
 SGI VISUAL WORKSTATION 320 AND 540
 P:	Bent Hagemark
 M:	bh@sgi.com
@@ -1557,6 +1580,25 @@
 M:	hch@infradead.org
 S:	Maintained
 
+TI PARALLEL LINK CABLE DRIVER
+P:     Romain Lievin
+M:     roms@lpg.ticalc.org
+S:     Maintained
+
+TI GRAPH LINK USB (SilverLink) CABLE DRIVER
+P:      Romain Lievin
+M:      roms@lpg.ticalc.org
+P:      Julien Blache
+M:      jb@technologeek.org
+S:      Maintained
+
+TIEMAN VOYAGER USB BRAILLE DISPLAY DRIVER
+P:	Stephane Dalton
+M:	sdalton@videotron.ca
+P:	Stphane Doyon
+M:	s.doyon@videotron.ca
+S:	Maintained
+
 TI GRAPH LINK USB (SilverLink) CABLE DRIVER
 P:      Romain Lievin
 M:      roms@lpg.ticalc.org
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/Makefile linux.20pre10-ac2/Makefile
--- linux.20pre10/Makefile	2002-10-09 21:44:46.000000000 +0100
+++ linux.20pre10-ac2/Makefile	2002-10-09 21:52:27.000000000 +0100
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 20
-EXTRAVERSION = -pre10
+EXTRAVERSION = -pre10-ac1
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
@@ -40,10 +40,11 @@
 MODFLAGS	= -DMODULE
 CFLAGS_KERNEL	=
 PERL		= perl
+AWK		= awk
 
 export	VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION KERNELRELEASE ARCH \
 	CONFIG_SHELL TOPDIR HPATH HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \
-	CPP AR NM STRIP OBJCOPY OBJDUMP MAKE MAKEFILES GENKSYMS MODFLAGS PERL
+	CPP AR NM STRIP OBJCOPY OBJDUMP MAKE MAKEFILES GENKSYMS MODFLAGS PERL AWK
 
 all:	do-it-all
 
@@ -172,7 +173,7 @@
 DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a
 DRIVERS-$(CONFIG_PPC32) += drivers/macintosh/macintosh.o
 DRIVERS-$(CONFIG_MAC) += drivers/macintosh/macintosh.o
-DRIVERS-$(CONFIG_ISAPNP) += drivers/pnp/pnp.o
+DRIVERS-$(CONFIG_PNP) += drivers/pnp/pnp.o
 DRIVERS-$(CONFIG_SGI_IP22) += drivers/sgi/sgi.a
 DRIVERS-$(CONFIG_VT) += drivers/video/video.o
 DRIVERS-$(CONFIG_PARIDE) += drivers/block/paride/paride.a
@@ -199,6 +200,7 @@
 	kernel/ksyms.lst include/linux/compile.h \
 	vmlinux System.map \
 	.tmp* \
+	scripts/mkconfigs kernel/configs.c kernel/configs.o \
 	drivers/char/consolemap_deftbl.c drivers/video/promcon_tbl.c \
 	drivers/char/conmakehash \
 	drivers/char/drm/*-mod.c \
@@ -226,6 +228,7 @@
 # files removed with 'make mrproper'
 MRPROPER_FILES = \
 	include/linux/autoconf.h include/linux/version.h \
+	tmp* \
 	drivers/net/hamradio/soundmodem/sm_tbl_{afsk1200,afsk2666,fsk9600}.h \
 	drivers/net/hamradio/soundmodem/sm_tbl_{hapn4800,psk4800}.h \
 	drivers/net/hamradio/soundmodem/sm_tbl_{afsk2400_7,afsk2400_8}.h \
@@ -243,6 +246,7 @@
 	include/asm \
 	.hdepend scripts/mkdep scripts/split-include scripts/docproc \
 	$(TOPDIR)/include/linux/modversions.h \
+	scripts/mkconfigs kernel/configs.c kernel/configs.o \
 	kernel.spec
 
 # directories removed with 'make mrproper'
@@ -316,7 +320,7 @@
 
 linuxsubdirs: $(patsubst %, _dir_%, $(SUBDIRS))
 
-$(patsubst %, _dir_%, $(SUBDIRS)) : dummy include/linux/version.h include/config/MARKER
+$(patsubst %, _dir_%, $(SUBDIRS)) : dummy include/linux/version.h tmp_include_depends
 	$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C $(patsubst _dir_%, %, $@)
 
 $(TOPDIR)/include/linux/version.h: include/linux/version.h
@@ -356,13 +360,13 @@
 
 comma	:= ,
 
-init/version.o: init/version.c include/linux/compile.h include/config/MARKER
+init/version.o: init/version.c include/linux/compile.h tmp_include_depends
 	$(CC) $(CFLAGS) $(CFLAGS_KERNEL) -DUTS_MACHINE='"$(ARCH)"' -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o init/version.o init/version.c
 
-init/main.o: init/main.c include/config/MARKER
+init/main.o: init/main.c tmp_include_depends
 	$(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o $@ $<
 
-init/do_mounts.o: init/do_mounts.c include/config/MARKER
+init/do_mounts.o: init/do_mounts.c tmp_include_depends
 	$(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o $@ $<
 
 fs lib mm ipc kernel drivers net: dummy
@@ -389,7 +393,7 @@
 modules: $(patsubst %, _mod_%, $(SUBDIRS))
 
 .PHONY: $(patsubst %, _mod_%, $(SUBDIRS))
-$(patsubst %, _mod_%, $(SUBDIRS)) : include/linux/version.h include/config/MARKER
+$(patsubst %, _mod_%, $(SUBDIRS)) : include/linux/version.h tmp_include_depends
 	$(MAKE) -C $(patsubst _mod_%, %, $@) CFLAGS="$(CFLAGS) $(MODFLAGS)" MAKING_MODULES=1 modules
 
 .PHONY: modules_install
@@ -494,6 +498,13 @@
 ifdef CONFIG_MODVERSIONS
 	$(MAKE) update-modverfile
 endif
+	(find $(TOPDIR) \( -name .depend -o -name .hdepend \) -print | xargs $(AWK) -f scripts/include_deps) > tmp_include_depends
+	sed -ne 's/^\([^ ].*\):.*/  \1 \\/p' tmp_include_depends > tmp_include_depends_1
+	(echo ""; echo "all: \\"; cat tmp_include_depends_1; echo "") >> tmp_include_depends
+	rm tmp_include_depends_1
+
+tmp_include_depends: include/config/MARKER dummy
+	$(MAKE) -r -f tmp_include_depends all
 
 ifdef CONFIG_MODVERSIONS
 MODVERFILE := $(TOPDIR)/include/linux/modversions.h
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/bootmem.c linux.20pre10-ac2/mm/bootmem.c
--- linux.20pre10/mm/bootmem.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/mm/bootmem.c	2002-08-13 14:56:20.000000000 +0100
@@ -325,7 +325,7 @@
 
 void * __init __alloc_bootmem (unsigned long size, unsigned long align, unsigned long goal)
 {
-	pg_data_t *pgdat;
+	pg_data_t *pgdat = pgdat_list;
 	void *ptr;
 
 	for_each_pgdat(pgdat)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/filemap.c linux.20pre10-ac2/mm/filemap.c
--- linux.20pre10/mm/filemap.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/mm/filemap.c	2002-10-11 00:22:21.000000000 +0100
@@ -22,6 +22,7 @@
 #include <linux/swapctl.h>
 #include <linux/init.h>
 #include <linux/mm.h>
+#include <linux/mm_inline.h>
 #include <linux/iobuf.h>
 
 #include <asm/pgalloc.h>
@@ -95,6 +96,9 @@
 {
 	struct address_space * mapping = page->mapping;
 
+	if (mapping->a_ops->removepage)
+		mapping->a_ops->removepage(page);
+	
 	mapping->nrpages--;
 	list_del(&page->list);
 	page->mapping = NULL;
@@ -154,14 +158,11 @@
 
 		if (mapping) {
 			spin_lock(&pagecache_lock);
-			mapping = page->mapping;
-			if (mapping) {	/* may have been truncated */
-				list_del(&page->list);
-				list_add(&page->list, &mapping->dirty_pages);
-			}
+			list_del(&page->list);
+			list_add(&page->list, &mapping->dirty_pages);
 			spin_unlock(&pagecache_lock);
 
-			if (mapping && mapping->host)
+			if (mapping->host)
 				mark_inode_dirty_pages(mapping->host);
 		}
 	}
@@ -236,6 +237,10 @@
 
 static void truncate_complete_page(struct page *page)
 {
+	/* Page has already been removed from processes, by vmtruncate()  */
+	if (page->pte_chain)
+		BUG();
+
 	/* Leave it on the LRU if it gets converted into anonymous buffers */
 	if (!page->buffers || do_flushpage(page, 0))
 		lru_cache_del(page);
@@ -808,6 +813,7 @@
 	return &wait[hash];
 }
 
+
 /* 
  * Wait for a page to get unlocked.
  *
@@ -1029,7 +1035,54 @@
 }
 
 /*
- * Same as grab_cache_page, but do not wait if the page is unavailable.
+ * We combine this with read-ahead to deactivate pages when we
+ * think there's sequential IO going on. Note that this is
+ * harmless since we don't actually evict the pages from memory
+ * but just move them to the inactive list.
+ *
+ * TODO:
+ * - make the readahead code smarter
+ * - move readahead to the VMA level so we can do the same
+ *   trick with mmap()
+ *
+ * Rik van Riel, 2000
+ */
+static void drop_behind(struct file * file, unsigned long index)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	struct address_space *mapping = inode->i_mapping;
+	struct page *page;
+	unsigned long start;
+
+	/* Nothing to drop-behind if we're on the first page. */
+	if (!index)
+		return;
+
+	if (index > file->f_rawin)
+		start = index - file->f_rawin;
+	else
+		start = 0;
+
+	/*
+	 * Go backwards from index-1 and drop all pages in the
+	 * readahead window. Since the readahead window may have
+	 * been increased since the last time we were called, we
+	 * stop when the page isn't there.
+	 */
+	spin_lock(&pagemap_lru_lock);
+	while (--index >= start) {
+		struct page **hash = page_hash(mapping, index);
+		spin_lock(&pagecache_lock);
+		page = __find_page_nolock(mapping, index, *hash);
+		spin_unlock(&pagecache_lock);
+		if (!page || !PageActive(page))
+			break;
+		drop_page(page);
+	}
+	spin_unlock(&pagemap_lru_lock);
+}
+
+/* Same as grab_cache_page, but do not wait if the page is unavailable.
  * This is intended for speculative data generators, where the data can
  * be regenerated if the page couldn't be grabbed.  This routine should
  * be safe to call while holding the lock for another page.
@@ -1299,6 +1352,12 @@
 		if (filp->f_ramax > max_readahead)
 			filp->f_ramax = max_readahead;
 
+		/*
+		 * Move the pages that have already been passed
+		 * to the inactive list.
+		 */
+		drop_behind(filp, index);
+
 #ifdef PROFILE_READAHEAD
 		profile_readahead((reada_ok == 2), filp);
 #endif
@@ -1310,16 +1369,23 @@
 /*
  * Mark a page as having seen activity.
  *
- * If it was already so marked, move it to the active queue and drop
- * the referenced bit.  Otherwise, just mark it for future action..
+ * We immediately reclaim the inactive clean pages because those are
+ * counted as freeable.  We don't modify the inactive dirty ones because
+ * we're never sure if those are freeable anyway.
  */
 void mark_page_accessed(struct page *page)
 {
-	if (!PageActive(page) && PageReferenced(page)) {
+	/* Mark the page referenced, AFTER checking for previous usage.. */
+	SetPageReferenced(page);
+
+	if (unlikely(PageInactiveClean(page))) {
+		struct zone_struct *zone = page_zone(page);
+		int free = zone->free_pages + zone->inactive_clean_pages;
+
 		activate_page(page);
-		ClearPageReferenced(page);
-	} else
-		SetPageReferenced(page);
+		if (free < zone->pages_low)
+			wakeup_kswapd(GFP_NOIO);
+	}
 }
 
 /*
@@ -1599,7 +1665,7 @@
 		if (retval)
 			break;
 
-		retval = mapping->a_ops->direct_IO(rw, inode, iobuf, (offset+progress) >> blocksize_bits, blocksize);
+		retval = mapping->a_ops->direct_IO(rw, filp, iobuf, (offset+progress) >> blocksize_bits, blocksize);
 
 		if (rw == READ && retval > 0)
 			mark_dirty_kiobuf(iobuf, retval);
@@ -1833,7 +1899,7 @@
 		nr = max;
 
 	/* And limit it to a sane percentage of the inactive list.. */
-	max = nr_inactive_pages / 2;
+	max = nr_inactive_clean_pages / 2;
 	if (nr > max)
 		nr = max;
 
@@ -2974,13 +3040,16 @@
 	 * Check whether we've reached the file size limit.
 	 */
 	err = -EFBIG;
-	
+
 	if (!S_ISBLK(inode->i_mode) && limit != RLIM_INFINITY) {
 		if (pos >= limit) {
 			send_sig(SIGXFSZ, current, 0);
 			goto out;
 		}
-		if (pos > 0xFFFFFFFFULL || count > limit - (u32)pos) {
+		/* Fix this up when we got to rlimit64 */
+		if (pos > 0xFFFFFFFFULL)
+			count = 0;
+		else if(count > limit - (u32)pos) {
 			/* send_sig(SIGXFSZ, current, 0); */
 			count = limit - (u32)pos;
 		}
@@ -3054,6 +3123,7 @@
 		unsigned long index, offset;
 		long page_fault;
 		char *kaddr;
+		int deactivate = 1;
 
 		/*
 		 * Try to find the page in the cache. If it isn't there,
@@ -3062,8 +3132,10 @@
 		offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
 		index = pos >> PAGE_CACHE_SHIFT;
 		bytes = PAGE_CACHE_SIZE - offset;
-		if (bytes > count)
+		if (bytes > count) {
 			bytes = count;
+			deactivate = 0;
+		}
 
 		/*
 		 * Bring in the user page that we will copy from _first_.
@@ -3107,8 +3179,11 @@
 unlock:
 		kunmap(page);
 		/* Mark it unlocked again and drop the page.. */
-		SetPageReferenced(page);
 		UnlockPage(page);
+		if (deactivate)
+			deactivate_page(page);
+		else
+			mark_page_accessed(page);
 		page_cache_release(page);
 
 		if (status < 0)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/highmem.c linux.20pre10-ac2/mm/highmem.c
--- linux.20pre10/mm/highmem.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/mm/highmem.c	2002-08-21 22:52:56.000000000 +0100
@@ -355,6 +355,7 @@
 	/* we need to wait I/O completion */
 	run_task_queue(&tq_disk);
 
+	__set_current_state(TASK_RUNNING);
 	yield();
 	goto repeat_alloc;
 }
@@ -391,6 +392,7 @@
 	/* we need to wait I/O completion */
 	run_task_queue(&tq_disk);
 
+	__set_current_state(TASK_RUNNING);
 	yield();
 	goto repeat_alloc;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/Makefile linux.20pre10-ac2/mm/Makefile
--- linux.20pre10/mm/Makefile	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/mm/Makefile	2002-08-12 17:01:07.000000000 +0100
@@ -9,12 +9,12 @@
 
 O_TARGET := mm.o
 
-export-objs := shmem.o filemap.o memory.o page_alloc.o
+export-objs := shmem.o filemap.o memory.o page_alloc.o mempool.o
 
 obj-y	 := memory.o mmap.o filemap.o mprotect.o mlock.o mremap.o \
 	    vmalloc.o slab.o bootmem.o swap.o vmscan.o page_io.o \
 	    page_alloc.o swap_state.o swapfile.o numa.o oom_kill.o \
-	    shmem.o
+	    shmem.o rmap.o mempool.o
 
 obj-$(CONFIG_HIGHMEM) += highmem.o
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/memory.c linux.20pre10-ac2/mm/memory.c
--- linux.20pre10/mm/memory.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/mm/memory.c	2002-09-29 20:03:17.000000000 +0100
@@ -34,6 +34,21 @@
  *
  * 16.07.99  -  Support of BIGMEM added by Gerhard Wichert, Siemens AG
  *		(Gerhard.Wichert@pdb.siemens.de)
+ * 26.02.2002 - Added address space accounting <alan@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.
+ *
+ *  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/mm.h>
@@ -44,9 +59,11 @@
 #include <linux/iobuf.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
+#include <linux/mm_inline.h>
 #include <linux/module.h>
 
 #include <asm/pgalloc.h>
+#include <asm/rmap.h>
 #include <asm/uaccess.h>
 #include <asm/tlb.h>
 
@@ -103,6 +120,7 @@
 	}
 	pte = pte_offset(dir, 0);
 	pmd_clear(dir);
+	pgtable_remove_rmap(pte);
 	pte_free(pte);
 }
 
@@ -240,9 +258,11 @@
 
 				if (pte_none(pte))
 					goto cont_copy_pte_range_noset;
+				/* pte contains position in swap, so copy. */
 				if (!pte_present(pte)) {
 					swap_duplicate(pte_to_swp_entry(pte));
-					goto cont_copy_pte_range;
+					set_pte(dst_pte, pte);
+					goto cont_copy_pte_range_noset;
 				}
 				ptepage = pte_page(pte);
 				if ((!VALID_PAGE(ptepage)) || 
@@ -250,7 +270,7 @@
 					goto cont_copy_pte_range;
 
 				/* If it's a COW mapping, write protect it both in the parent and the child */
-				if (cow && pte_write(pte)) {
+				if (cow) {
 					ptep_set_wrprotect(src_pte);
 					pte = *src_pte;
 				}
@@ -263,6 +283,7 @@
 				dst->rss++;
 
 cont_copy_pte_range:		set_pte(dst_pte, pte);
+				page_add_rmap(ptepage, dst_pte);
 cont_copy_pte_range_noset:	address += PAGE_SIZE;
 				if (address >= end)
 					goto out_unlock;
@@ -318,8 +339,10 @@
 			continue;
 		if (pte_present(pte)) {
 			struct page *page = pte_page(pte);
-			if (VALID_PAGE(page) && !PageReserved(page))
+			if (VALID_PAGE(page) && !PageReserved(page)) {
 				freed ++;
+				page_remove_rmap(page, ptep);
+			}
 			/* This will eventually call __free_pte on the pte. */
 			tlb_remove_page(tlb, ptep, address + offset);
 		} else {
@@ -357,49 +380,65 @@
 	return freed;
 }
 
-/*
- * remove user pages in a given range.
+#define ZAP_BLOCK_SIZE	(256 * PAGE_SIZE)
+
+/**
+ * zap_page_range - remove user pages in a given range
+ * @mm: mm_struct containing the applicable pages
+ * @address: starting address of pages to zap
+ * @size: number of bytes to zap
  */
 void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size)
 {
 	mmu_gather_t *tlb;
 	pgd_t * dir;
-	unsigned long start = address, end = address + size;
-	int freed = 0;
-
-	dir = pgd_offset(mm, address);
-
+	unsigned long start, end, addr, block;
+	int freed;
+ 
 	/*
-	 * This is a long-lived spinlock. That's fine.
-	 * There's no contention, because the page table
-	 * lock only protects against kswapd anyway, and
-	 * even if kswapd happened to be looking at this
-	 * process we _want_ it to get stuck.
+	 * Break the work up into blocks of ZAP_BLOCK_SIZE pages:
+	 * this decreases lock-hold time for the page_table_lock
+	 * dramatically, which could otherwise be held for a very
+	 * long time.  This decreases lock contention and increases
+	 * periods of preemptibility.
 	 */
-	if (address >= end)
-		BUG();
-	spin_lock(&mm->page_table_lock);
-	flush_cache_range(mm, address, end);
-	tlb = tlb_gather_mmu(mm);
+	while (size) {
+		if (size > ZAP_BLOCK_SIZE)
+			block = ZAP_BLOCK_SIZE;
+		else
+			block = size;
+
+		freed = 0;
+		start = addr = address;
+		end = address + block;
+		dir = pgd_offset(mm, address);
 
-	do {
-		freed += zap_pmd_range(tlb, dir, address, end - address);
-		address = (address + PGDIR_SIZE) & PGDIR_MASK;
-		dir++;
-	} while (address && (address < end));
+		BUG_ON(address >= end);
 
-	/* this will flush any remaining tlb entries */
-	tlb_finish_mmu(tlb, start, end);
+		spin_lock(&mm->page_table_lock);
+		flush_cache_range(mm, start, end);
+		tlb = tlb_gather_mmu(mm);
 
-	/*
-	 * Update rss for the mm_struct (not necessarily current->mm)
-	 * Notice that rss is an unsigned long.
-	 */
-	if (mm->rss > freed)
-		mm->rss -= freed;
-	else
-		mm->rss = 0;
-	spin_unlock(&mm->page_table_lock);
+		do {
+			freed += zap_pmd_range(tlb, dir, addr, end - addr);
+			addr = (addr + PGDIR_SIZE) & PGDIR_MASK;
+			dir++;
+		} while (addr && (addr < end));
+
+		/* this will flush any remaining tlb entries */
+		tlb_finish_mmu(tlb, start, end);
+
+		/* Update rss for the mm_struct (need not be current->mm) */
+		if (mm->rss > freed)
+			mm->rss -= freed;
+		else
+			mm->rss = 0;
+
+		spin_unlock(&mm->page_table_lock);
+
+		address += block;
+		size -= block;
+	}
 }
 
 /*
@@ -984,7 +1023,9 @@
 	if (pte_same(*page_table, pte)) {
 		if (PageReserved(old_page))
 			++mm->rss;
+		page_remove_rmap(old_page, page_table);
 		break_cow(vma, new_page, address, page_table);
+		page_add_rmap(new_page, page_table);
 		lru_cache_add(new_page);
 
 		/* Free the old page.. */
@@ -1097,6 +1138,10 @@
 	struct page *new_page;
 	unsigned long offset;
 
+	/* Low on free memory ?  Don't make things worse. */
+	if (free_low(ALL_ZONES) < 0)
+		return;
+
 	/*
 	 * Get the number of handles we should do readahead io to.
 	 */
@@ -1176,6 +1221,7 @@
 	flush_page_to_ram(page);
 	flush_icache_page(vma, page);
 	set_pte(page_table, pte);
+	page_add_rmap(page, page_table);
 
 	/* No need to invalidate - it was non-present before */
 	update_mmu_cache(vma, address, pte);
@@ -1191,14 +1237,13 @@
 static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma, pte_t *page_table, int write_access, unsigned long addr)
 {
 	pte_t entry;
+	struct page * page = ZERO_PAGE(addr);
 
 	/* Read-only mapping of ZERO_PAGE. */
 	entry = pte_wrprotect(mk_pte(ZERO_PAGE(addr), vma->vm_page_prot));
 
 	/* ..except if it's a write access */
 	if (write_access) {
-		struct page *page;
-
 		/* Allocate our own private page. */
 		spin_unlock(&mm->page_table_lock);
 
@@ -1217,10 +1262,10 @@
 		flush_page_to_ram(page);
 		entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
 		lru_cache_add(page);
-		mark_page_accessed(page);
 	}
 
 	set_pte(page_table, entry);
+	page_add_rmap(page, page_table); /* ignores ZERO_PAGE */
 
 	/* No need to invalidate - it was non-present before */
 	update_mmu_cache(vma, addr, entry);
@@ -1275,6 +1320,8 @@
 		new_page = page;
 	}
 
+	mark_page_accessed(new_page);
+
 	spin_lock(&mm->page_table_lock);
 	/*
 	 * This silly early PAGE_DIRTY setting removes a race
@@ -1295,6 +1342,7 @@
 		if (write_access)
 			entry = pte_mkwrite(pte_mkdirty(entry));
 		set_pte(page_table, entry);
+		page_add_rmap(new_page, page_table);
 	} else {
 		/* One of our sibling threads was faster, back out. */
 		page_cache_release(new_page);
@@ -1371,6 +1419,14 @@
 	current->state = TASK_RUNNING;
 	pgd = pgd_offset(mm, address);
 
+	/* 
+	 * If we are over our RSS limit and the system needs memory,
+	 * we will free memory for the non-hogs and slow down a bit.
+	 */
+	if (mm->rlimit_rss && mm->rss > mm->rlimit_rss &&
+					free_high(ALL_ZONES) > 0)
+		rss_free_pages(GFP_HIGHUSER);
+
 	/*
 	 * We need the page table lock to synchronize with kswapd
 	 * and the SMP-safe atomic PTE updates.
@@ -1452,6 +1508,7 @@
 				goto out;
 			}
 		}
+		pgtable_add_rmap(new, mm, address);
 		pmd_populate(mm, pmd, new);
 	}
 out:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/mempool.c linux.20pre10-ac2/mm/mempool.c
--- linux.20pre10/mm/mempool.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/mm/mempool.c	2002-08-15 13:15:22.000000000 +0100
@@ -0,0 +1,299 @@
+/*
+ *  linux/mm/mempool.c
+ *
+ *  memory buffer pool support. Such pools are mostly used
+ *  for guaranteed, deadlock-free memory allocations during
+ *  extreme VM load.
+ *
+ *  started by Ingo Molnar, Copyright (C) 2001
+ */
+
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/mempool.h>
+
+struct mempool_s {
+	spinlock_t lock;
+	int min_nr;		/* nr of elements at *elements */
+	int curr_nr;		/* Current nr of elements at *elements */
+	void **elements;
+
+	void *pool_data;
+	mempool_alloc_t *alloc;
+	mempool_free_t *free;
+	wait_queue_head_t wait;
+};
+
+static void add_element(mempool_t *pool, void *element)
+{
+	BUG_ON(pool->curr_nr >= pool->min_nr);
+	pool->elements[pool->curr_nr++] = element;
+}
+
+static void *remove_element(mempool_t *pool)
+{
+	BUG_ON(pool->curr_nr <= 0);
+	return pool->elements[--pool->curr_nr];
+}
+
+static void free_pool(mempool_t *pool)
+{
+	while (pool->curr_nr) {
+		void *element = remove_element(pool);
+		pool->free(element, pool->pool_data);
+	}
+	kfree(pool->elements);
+	kfree(pool);
+}
+
+/**
+ * mempool_create - create a memory pool
+ * @min_nr:    the minimum number of elements guaranteed to be
+ *             allocated for this pool.
+ * @alloc_fn:  user-defined element-allocation function.
+ * @free_fn:   user-defined element-freeing function.
+ * @pool_data: optional private data available to the user-defined functions.
+ *
+ * this function creates and allocates a guaranteed size, preallocated
+ * memory pool. The pool can be used from the mempool_alloc and mempool_free
+ * functions. This function might sleep. Both the alloc_fn() and the free_fn()
+ * functions might sleep - as long as the mempool_alloc function is not called
+ * from IRQ contexts.
+ */
+mempool_t * mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
+				mempool_free_t *free_fn, void *pool_data)
+{
+	mempool_t *pool;
+
+	pool = kmalloc(sizeof(*pool), GFP_KERNEL);
+	if (!pool)
+		return NULL;
+	memset(pool, 0, sizeof(*pool));
+	pool->elements = kmalloc(min_nr * sizeof(void *), GFP_KERNEL);
+	if (!pool->elements) {
+		kfree(pool);
+		return NULL;
+	}
+	spin_lock_init(&pool->lock);
+	pool->min_nr = min_nr;
+	pool->pool_data = pool_data;
+	init_waitqueue_head(&pool->wait);
+	pool->alloc = alloc_fn;
+	pool->free = free_fn;
+
+	/*
+	 * First pre-allocate the guaranteed number of buffers.
+	 */
+	while (pool->curr_nr < pool->min_nr) {
+		void *element;
+
+		element = pool->alloc(GFP_KERNEL, pool->pool_data);
+		if (unlikely(!element)) {
+			free_pool(pool);
+			return NULL;
+		}
+		add_element(pool, element);
+	}
+	return pool;
+}
+
+/**
+ * mempool_resize - resize an existing memory pool
+ * @pool:       pointer to the memory pool which was allocated via
+ *              mempool_create().
+ * @new_min_nr: the new minimum number of elements guaranteed to be
+ *              allocated for this pool.
+ * @gfp_mask:   the usual allocation bitmask.
+ *
+ * This function shrinks/grows the pool. In the case of growing,
+ * it cannot be guaranteed that the pool will be grown to the new
+ * size immediately, but new mempool_free() calls will refill it.
+ *
+ * Note, the caller must guarantee that no mempool_destroy is called
+ * while this function is running. mempool_alloc() & mempool_free()
+ * might be called (eg. from IRQ contexts) while this function executes.
+ */
+int mempool_resize(mempool_t *pool, int new_min_nr, int gfp_mask)
+{
+	void *element;
+	void **new_elements;
+	unsigned long flags;
+
+	BUG_ON(new_min_nr <= 0);
+
+	spin_lock_irqsave(&pool->lock, flags);
+	if (new_min_nr < pool->min_nr) {
+		while (pool->curr_nr > new_min_nr) {
+			element = remove_element(pool);
+			spin_unlock_irqrestore(&pool->lock, flags);
+			pool->free(element, pool->pool_data);
+			spin_lock_irqsave(&pool->lock, flags);
+		}
+		pool->min_nr = new_min_nr;
+		goto out_unlock;
+	}
+	spin_unlock_irqrestore(&pool->lock, flags);
+
+	/* Grow the pool */
+	new_elements = kmalloc(new_min_nr * sizeof(*new_elements), gfp_mask);
+	if (!new_elements)
+		return -ENOMEM;
+
+	spin_lock_irqsave(&pool->lock, flags);
+	memcpy(new_elements, pool->elements,
+			pool->curr_nr * sizeof(*new_elements));
+	kfree(pool->elements);
+	pool->elements = new_elements;
+	pool->min_nr = new_min_nr;
+
+	while (pool->curr_nr < pool->min_nr) {
+		spin_unlock_irqrestore(&pool->lock, flags);
+		element = pool->alloc(gfp_mask, pool->pool_data);
+		if (!element)
+			goto out;
+		spin_lock_irqsave(&pool->lock, flags);
+		if (pool->curr_nr < pool->min_nr)
+			add_element(pool, element);
+		else
+			kfree(element);		/* Raced */
+	}
+out_unlock:
+	spin_unlock_irqrestore(&pool->lock, flags);
+out:
+	return 0;
+}
+
+/**
+ * mempool_destroy - deallocate a memory pool
+ * @pool:      pointer to the memory pool which was allocated via
+ *             mempool_create().
+ *
+ * this function only sleeps if the free_fn() function sleeps. The caller
+ * has to guarantee that all elements have been returned to the pool (ie:
+ * freed) prior to calling mempool_destroy().
+ */
+void mempool_destroy(mempool_t *pool)
+{
+	if (pool->curr_nr != pool->min_nr)
+		BUG();		/* There were outstanding elements */
+	free_pool(pool);
+}
+
+/**
+ * mempool_alloc - allocate an element from a specific memory pool
+ * @pool:      pointer to the memory pool which was allocated via
+ *             mempool_create().
+ * @gfp_mask:  the usual allocation bitmask.
+ *
+ * this function only sleeps if the alloc_fn function sleeps or
+ * returns NULL. Note that due to preallocation, this function
+ * *never* fails when called from process contexts. (it might
+ * fail if called from an IRQ context.)
+ */
+void * mempool_alloc(mempool_t *pool, int gfp_mask)
+{
+	void *element;
+	unsigned long flags;
+	int curr_nr;
+	DECLARE_WAITQUEUE(wait, current);
+	int gfp_nowait = gfp_mask & ~(__GFP_WAIT | __GFP_IO);
+
+repeat_alloc:
+	element = pool->alloc(gfp_nowait, pool->pool_data);
+	if (likely(element != NULL))
+		return element;
+
+	/*
+	 * If the pool is less than 50% full then try harder
+	 * to allocate an element:
+	 */
+	if ((gfp_mask != gfp_nowait) && (pool->curr_nr <= pool->min_nr/2)) {
+		element = pool->alloc(gfp_mask, pool->pool_data);
+		if (likely(element != NULL))
+			return element;
+	}
+
+	/*
+	 * Kick the VM at this point.
+	 */
+	wakeup_bdflush();
+
+	spin_lock_irqsave(&pool->lock, flags);
+	if (likely(pool->curr_nr)) {
+		element = remove_element(pool);
+		spin_unlock_irqrestore(&pool->lock, flags);
+		return element;
+	}
+	spin_unlock_irqrestore(&pool->lock, flags);
+
+	/* We must not sleep in the GFP_ATOMIC case */
+	if (gfp_mask == gfp_nowait)
+		return NULL;
+
+	run_task_queue(&tq_disk);
+
+	add_wait_queue_exclusive(&pool->wait, &wait);
+	set_task_state(current, TASK_UNINTERRUPTIBLE);
+
+	spin_lock_irqsave(&pool->lock, flags);
+	curr_nr = pool->curr_nr;
+	spin_unlock_irqrestore(&pool->lock, flags);
+
+	if (!curr_nr)
+		schedule();
+
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&pool->wait, &wait);
+
+	goto repeat_alloc;
+}
+
+/**
+ * mempool_free - return an element to the pool.
+ * @element:   pool element pointer.
+ * @pool:      pointer to the memory pool which was allocated via
+ *             mempool_create().
+ *
+ * this function only sleeps if the free_fn() function sleeps.
+ */
+void mempool_free(void *element, mempool_t *pool)
+{
+	unsigned long flags;
+
+	if (pool->curr_nr < pool->min_nr) {
+		spin_lock_irqsave(&pool->lock, flags);
+		if (pool->curr_nr < pool->min_nr) {
+			add_element(pool, element);
+			spin_unlock_irqrestore(&pool->lock, flags);
+			wake_up(&pool->wait);
+			return;
+		}
+		spin_unlock_irqrestore(&pool->lock, flags);
+	}
+	pool->free(element, pool->pool_data);
+}
+
+/*
+ * A commonly used alloc and free fn.
+ */
+void *mempool_alloc_slab(int gfp_mask, void *pool_data)
+{
+	kmem_cache_t *mem = (kmem_cache_t *) pool_data;
+	return kmem_cache_alloc(mem, gfp_mask);
+}
+
+void mempool_free_slab(void *element, void *pool_data)
+{
+	kmem_cache_t *mem = (kmem_cache_t *) pool_data;
+	kmem_cache_free(mem, element);
+}
+
+
+EXPORT_SYMBOL(mempool_create);
+EXPORT_SYMBOL(mempool_resize);
+EXPORT_SYMBOL(mempool_destroy);
+EXPORT_SYMBOL(mempool_alloc);
+EXPORT_SYMBOL(mempool_free);
+EXPORT_SYMBOL(mempool_alloc_slab);
+EXPORT_SYMBOL(mempool_free_slab);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/mlock.c linux.20pre10-ac2/mm/mlock.c
--- linux.20pre10/mm/mlock.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/mm/mlock.c	2002-08-06 15:41:52.000000000 +0100
@@ -198,6 +198,7 @@
 	unsigned long lock_limit;
 	int error = -ENOMEM;
 
+	vm_validate_enough("entering sys_mlock");
 	down_write(&current->mm->mmap_sem);
 	len = PAGE_ALIGN(len + (start & ~PAGE_MASK));
 	start &= PAGE_MASK;
@@ -220,6 +221,7 @@
 	error = do_mlock(start, len, 1);
 out:
 	up_write(&current->mm->mmap_sem);
+	vm_validate_enough("exiting sys_mlock");
 	return error;
 }
 
@@ -227,11 +229,13 @@
 {
 	int ret;
 
+	vm_validate_enough("entering sys_munlock");
 	down_write(&current->mm->mmap_sem);
 	len = PAGE_ALIGN(len + (start & ~PAGE_MASK));
 	start &= PAGE_MASK;
 	ret = do_mlock(start, len, 0);
 	up_write(&current->mm->mmap_sem);
+	vm_validate_enough("exiting sys_munlock");
 	return ret;
 }
 
@@ -268,6 +272,8 @@
 	unsigned long lock_limit;
 	int ret = -EINVAL;
 
+	vm_validate_enough("entering sys_mlockall");
+
 	down_write(&current->mm->mmap_sem);
 	if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE)))
 		goto out;
@@ -287,15 +293,18 @@
 	ret = do_mlockall(flags);
 out:
 	up_write(&current->mm->mmap_sem);
+	vm_validate_enough("exiting sys_mlockall");
 	return ret;
 }
 
 asmlinkage long sys_munlockall(void)
 {
 	int ret;
+	vm_validate_enough("entering sys_munlockall");
 
 	down_write(&current->mm->mmap_sem);
 	ret = do_mlockall(0);
 	up_write(&current->mm->mmap_sem);
+	vm_validate_enough("exiting sys_munlockall");
 	return ret;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/mmap.c linux.20pre10-ac2/mm/mmap.c
--- linux.20pre10/mm/mmap.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/mm/mmap.c	2002-09-18 12:56:55.000000000 +0100
@@ -1,8 +1,25 @@
 /*
  *	linux/mm/mmap.c
- *
  * Written by obz.
+ *
+ *  Address space accounting code	<alan@redhat.com>
+ *  (c) Copyright 2002 Red Hat Inc, All Rights Reserved
+ *
+ *  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/slab.h>
 #include <linux/shm.h>
 #include <linux/mman.h>
@@ -46,6 +63,7 @@
 
 int sysctl_overcommit_memory;
 int max_map_count = DEFAULT_MAX_MAP_COUNT;
+atomic_t vm_committed_space = ATOMIC_INIT(0);
 
 /* Check that a process has enough memory to allocate a
  * new virtual mapping.
@@ -55,42 +73,109 @@
 	/* Stupid algorithm to decide if we have enough memory: while
 	 * simple, it hopefully works in most obvious cases.. Easy to
 	 * fool it, but this should catch most mistakes.
-	 */
-	/* 23/11/98 NJC: Somewhat less stupid version of algorithm,
+	 *
+	 * 23/11/98 NJC: Somewhat less stupid version of algorithm,
 	 * which tries to do "TheRightThing".  Instead of using half of
 	 * (buffers+cache), use the minimum values.  Allow an extra 2%
 	 * of num_physpages for safety margin.
+	 *
+	 * 2002/02/26 Alan Cox: Added two new modes that do real accounting
 	 */
+	unsigned long free, allowed;
+	struct sysinfo i;
 
-	unsigned long free;
+	atomic_add(pages, &vm_committed_space);
 	
         /* Sometimes we want to use more memory than we have. */
-	if (sysctl_overcommit_memory)
-	    return 1;
+	if (sysctl_overcommit_memory == 1)
+		return 1;
+		
+	if (sysctl_overcommit_memory == 0)
+	{
+		/* The page cache contains buffer pages these days.. */
+		free = atomic_read(&page_cache_size);
+		free += nr_free_pages();
+		free += nr_swap_pages;
+	
+		/*
+		 * This double-counts: the nrpages are both in the page-cache
+		 * and in the swapper space. At the same time, this compensates
+		 * for the swap-space over-allocation (ie "nr_swap_pages" being
+		 * too small.
+		 */
+		free += swapper_space.nrpages;
+	
+		/*
+		 * The code below doesn't account for free space in the inode
+		 * and dentry slab cache, slab cache fragmentation, inodes and
+		 * dentries which will become freeable under VM load, etc.
+		 * Lets just hope all these (complex) factors balance out...
+		 */
+		free += (dentry_stat.nr_unused * sizeof(struct dentry)) >> PAGE_SHIFT;
+		free += (inodes_stat.nr_unused * sizeof(struct inode)) >> PAGE_SHIFT;
+	
+		if(free > pages)
+			return 1;
+		atomic_sub(pages, &vm_committed_space);
+		return 0;
+	}
+	allowed = total_swap_pages;
+	
+	if(sysctl_overcommit_memory == 2)
+	{
+		/* FIXME - need to add arch hooks to get the bits we need
+		   without the higher overhead crap */
+		si_meminfo(&i);	
+		allowed += i.totalram >> 1;
+	}
+	if(atomic_read(&vm_committed_space) < allowed)
+		return 1;
+	atomic_sub(pages, &vm_committed_space);
+	return 0;
+	
+}
 
-	/* The page cache contains buffer pages these days.. */
-	free = atomic_read(&page_cache_size);
-	free += nr_free_pages();
-	free += nr_swap_pages;
+void vm_unacct_memory(long pages)
+{	
+	atomic_sub(pages, &vm_committed_space);
+}
 
-	/*
-	 * This double-counts: the nrpages are both in the page-cache
-	 * and in the swapper space. At the same time, this compensates
-	 * for the swap-space over-allocation (ie "nr_swap_pages" being
-	 * too small.
-	 */
-	free += swapper_space.nrpages;
+/*
+ *	Don't even bother telling me the locking is wrong - its a test
+ *	routine and uniprocessor is quite sufficient..
+ *
+ *	To enable this debugging you must tweak the #if below, and build
+ *	with no SYS5 shared memory (thats not validated yet) and non SMP
+ */
 
-	/*
-	 * The code below doesn't account for free space in the inode
-	 * and dentry slab cache, slab cache fragmentation, inodes and
-	 * dentries which will become freeable under VM load, etc.
-	 * Lets just hope all these (complex) factors balance out...
-	 */
-	free += (dentry_stat.nr_unused * sizeof(struct dentry)) >> PAGE_SHIFT;
-	free += (inodes_stat.nr_unused * sizeof(struct inode)) >> PAGE_SHIFT;
+void vm_validate_enough(char *x)
+{
+#if 0
+	unsigned long count = 0UL;
+	struct mm_struct *mm;
+	struct vm_area_struct *vma;
+	struct list_head *mmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&mmlist_lock, flags);
 
-	return free > pages;
+	list_for_each(mmp, &init_mm.mmlist)
+	{
+		mm = list_entry(mmp, struct mm_struct, mmlist);
+		for(vma = mm->mmap; vma!=NULL; vma=vma->vm_next)
+		{
+			if(vma->vm_flags & VM_ACCOUNT)
+				count += (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+		}
+	}	
+	if(count != atomic_read(&vm_committed_space))
+	{
+		printk("MM crappo accounting %s: %lu %ld.\n",
+			x, count, atomic_read(&vm_committed_space));
+		atomic_set(&vm_committed_space, count);
+	}
+	spin_unlock_irqrestore(&mmlist_lock, flags);
+#endif
 }
 
 /* Remove one vm structure from the inode's i_mapping address space. */
@@ -161,12 +246,13 @@
 
 	/* Always allow shrinking brk. */
 	if (brk <= mm->brk) {
-		if (!do_munmap(mm, newbrk, oldbrk-newbrk))
+		if (!do_munmap(mm, newbrk, oldbrk-newbrk, 1))
 			goto set_brk;
 		goto out;
 	}
 
 	/* Check against rlimit.. */
+	/* FIXME: - this seems to be checked in do_brk.. */
 	rlim = current->rlim[RLIMIT_DATA].rlim_cur;
 	if (rlim < RLIM_INFINITY && brk - mm->start_data > rlim)
 		goto out;
@@ -175,10 +261,6 @@
 	if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))
 		goto out;
 
-	/* Check if we have enough memory.. */
-	if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT))
-		goto out;
-
 	/* Ok, looks good - let it rip. */
 	if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk)
 		goto out;
@@ -390,6 +472,12 @@
 	return 0;
 }
 
+
+/*
+ *	NOTE: in this function we rely on TASK_SIZE being lower than
+ *	SIZE_MAX-PAGE_SIZE at least. I'm pretty sure that it is.
+ */
+
 unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned long len,
 	unsigned long prot, unsigned long flags, unsigned long pgoff)
 {
@@ -399,16 +487,20 @@
 	int correct_wcount = 0;
 	int error;
 	rb_node_t ** rb_link, * rb_parent;
+	unsigned long charged = 0;
 
+	vm_validate_enough("entering do_mmap_pgoff");
 	if (file && (!file->f_op || !file->f_op->mmap))
 		return -ENODEV;
 
-	if ((len = PAGE_ALIGN(len)) == 0)
+	if (!len)
 		return addr;
 
 	if (len > TASK_SIZE)
 		return -EINVAL;
 
+	len = PAGE_ALIGN(len);  /* This cannot be zero now */
+
 	/* offset overflow? */
 	if ((pgoff + (len >> PAGE_SHIFT)) < pgoff)
 		return -EINVAL;
@@ -482,7 +574,7 @@
 munmap_back:
 	vma = find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent);
 	if (vma && vma->vm_start < addr + len) {
-		if (do_munmap(mm, addr, len))
+		if (do_munmap(mm, addr, len, 1))
 			return -ENOMEM;
 		goto munmap_back;
 	}
@@ -492,11 +584,15 @@
 	    > current->rlim[RLIMIT_AS].rlim_cur)
 		return -ENOMEM;
 
-	/* Private writable mapping? Check memory availability.. */
-	if ((vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE &&
-	    !(flags & MAP_NORESERVE)				 &&
-	    !vm_enough_memory(len >> PAGE_SHIFT))
-		return -ENOMEM;
+	if (!(flags & MAP_NORESERVE) || sysctl_overcommit_memory > 1) {
+		if ((vm_flags & (VM_SHARED|VM_WRITE)) == VM_WRITE) {
+			/* Private writable mapping: check memory availability */
+			charged = len >> PAGE_SHIFT;
+			if (!vm_enough_memory(charged))
+				return -ENOMEM;
+			vm_flags |= VM_ACCOUNT;
+		}
+	}
 
 	/* Can we just expand an old anonymous mapping? */
 	if (!file && !(vm_flags & VM_SHARED) && rb_parent)
@@ -508,8 +604,9 @@
 	 * not unmapped, but the maps are removed from the list.
 	 */
 	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+	error = -ENOMEM;
 	if (!vma)
-		return -ENOMEM;
+		goto unacct_error;
 
 	vma->vm_mm = mm;
 	vma->vm_start = addr;
@@ -561,8 +658,7 @@
 		 * to update the tree pointers.
 		 */
 		addr = vma->vm_start;
-		stale_vma = find_vma_prepare(mm, addr, &prev,
-						&rb_link, &rb_parent);
+		stale_vma = find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent);
 		/*
 		 * Make sure the lowlevel driver did its job right.
 		 */
@@ -583,6 +679,7 @@
 		mm->locked_vm += len >> PAGE_SHIFT;
 		make_pages_present(addr, addr + len);
 	}
+	vm_validate_enough("out from do_mmap_pgoff");
 	return addr;
 
 unmap_and_free_vma:
@@ -595,6 +692,10 @@
 	zap_page_range(mm, vma->vm_start, vma->vm_end - vma->vm_start);
 free_vma:
 	kmem_cache_free(vm_area_cachep, vma);
+unacct_error:
+	if(charged)
+		vm_unacct_memory(charged);
+	vm_validate_enough("error path from do_mmap_pgoff");
 	return error;
 }
 
@@ -737,6 +838,96 @@
 	return NULL;
 }
 
+/* vma is the first one with  address < vma->vm_end,
+ * and even  address < vma->vm_start. Have to extend vma. */
+ 
+#ifdef ARCH_STACK_GROWSUP
+static inline int expand_stack(struct vm_area_struct * vma, unsigned long address)
+{
+	unsigned long grow;
+
+	if (!(vma->vm_flags & VM_GROWSUP))
+		return -EFAULT;
+
+	vm_validate_enough("entering expand_stack");
+
+	/*
+	 * vma->vm_start/vm_end cannot change under us because the caller is required
+	 * to hold the mmap_sem in write mode. We need to get the spinlock only
+	 * before relocating the vma range ourself.
+	 */
+ 	spin_lock(&vma->vm_mm->page_table_lock);
+
+	address += 4 + PAGE_SIZE - 1;
+	address &= PAGE_MASK;
+	grow = (address - vma->vm_end) >> PAGE_SHIFT;
+	
+	/* Overcommit.. */
+	if(!vm_enough_memory(grow)) {
+		spin_unlock(&vma->vm_mm->page_table_lock);
+		return -ENOMEM;
+	}
+	
+	if (address - vma->vm_start > current->rlim[RLIMIT_STACK].rlim_cur ||
+	    ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur)
+	{
+		spin_unlock(&vma->vm_mm->page_table_lock);
+		vm_unacct_memory(grow);
+		vm_validate_enough("exiting expand_stack - FAIL");
+		return -ENOMEM;
+	}
+	vma->vm_end = address;
+	vma->vm_mm->total_vm += grow;
+	if (vma->vm_flags & VM_LOCKED)
+		vma->vm_mm->locked_vm += grow;
+	vm_validate_enough("exiting expand_stack");
+	return 0;
+}
+#else
+
+int expand_stack(struct vm_area_struct * vma, unsigned long address)
+{
+	unsigned long grow;
+
+	if (!(vma->vm_flags & VM_GROWSDOWN))
+		return -EFAULT;
+
+	vm_validate_enough("entering expand_stack");
+
+	/*
+	 * vma->vm_start/vm_end cannot change under us because the caller is required
+	 * to hold the mmap_sem in write mode. We need to get the spinlock only
+	 * before relocating the vma range ourself.
+	 */
+	address &= PAGE_MASK;
+ 	spin_lock(&vma->vm_mm->page_table_lock);
+	grow = (vma->vm_start - address) >> PAGE_SHIFT;
+
+	/* Overcommit.. */
+	if(!vm_enough_memory(grow)) {
+		spin_unlock(&vma->vm_mm->page_table_lock);
+		return -ENOMEM;
+	}
+	
+	if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur ||
+	    ((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->rlim[RLIMIT_AS].rlim_cur) {
+		spin_unlock(&vma->vm_mm->page_table_lock);
+		vm_unacct_memory(grow);
+		vm_validate_enough("exiting expand_stack - FAIL");
+		return -ENOMEM;
+	}
+	vma->vm_start = address;
+	vma->vm_pgoff -= grow;
+	vma->vm_mm->total_vm += grow;
+	if (vma->vm_flags & VM_LOCKED)
+		vma->vm_mm->locked_vm += grow;
+	spin_unlock(&vma->vm_mm->page_table_lock);
+	vm_validate_enough("exiting expand_stack");
+	return 0;
+}
+
+#endif
+
 struct vm_area_struct * find_extend_vma(struct mm_struct * mm, unsigned long addr)
 {
 	struct vm_area_struct * vma;
@@ -784,7 +975,7 @@
  */
 static struct vm_area_struct * unmap_fixup(struct mm_struct *mm, 
 	struct vm_area_struct *area, unsigned long addr, size_t len, 
-	struct vm_area_struct *extra)
+	struct vm_area_struct *extra, int acct)
 {
 	struct vm_area_struct *mpnt;
 	unsigned long end = addr + len;
@@ -792,6 +983,8 @@
 	area->vm_mm->total_vm -= len >> PAGE_SHIFT;
 	if (area->vm_flags & VM_LOCKED)
 		area->vm_mm->locked_vm -= len >> PAGE_SHIFT;
+	if (acct && (area->vm_flags & VM_ACCOUNT))
+		vm_unacct_memory(len >> PAGE_SHIFT);
 
 	/* Unmapping the whole area. */
 	if (addr == area->vm_start && end == area->vm_end) {
@@ -802,7 +995,7 @@
 		kmem_cache_free(vm_area_cachep, area);
 		return extra;
 	}
-
+	
 	/* Work out to one of the ends. */
 	if (end == area->vm_end) {
 		/*
@@ -916,10 +1109,12 @@
  * work.  This now handles partial unmappings.
  * Jeremy Fitzhardine <jeremy@sw.oz.au>
  */
-int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
+int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len, int acct)
 {
 	struct vm_area_struct *mpnt, *prev, **npp, *free, *extra;
 
+	if(acct) vm_validate_enough("entering do_munmap");
+
 	if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr)
 		return -EINVAL;
 
@@ -986,6 +1181,7 @@
 		    (file = mpnt->vm_file) != NULL) {
 			atomic_dec(&file->f_dentry->d_inode->i_writecount);
 		}
+
 		remove_shared_vm_struct(mpnt);
 		mm->map_count--;
 
@@ -994,7 +1190,7 @@
 		/*
 		 * Fix the mapping, and free the old area if it wasn't reused.
 		 */
-		extra = unmap_fixup(mm, mpnt, st, size, extra);
+		extra = unmap_fixup(mm, mpnt, st, size, extra, acct);
 		if (file)
 			atomic_inc(&file->f_dentry->d_inode->i_writecount);
 	}
@@ -1005,6 +1201,7 @@
 		kmem_cache_free(vm_area_cachep, extra);
 
 	free_pgtables(mm, prev, addr, addr+len);
+	if(acct) vm_validate_enough("exit -ok- do_munmap");
 
 	return 0;
 }
@@ -1015,7 +1212,7 @@
 	struct mm_struct *mm = current->mm;
 
 	down_write(&mm->mmap_sem);
-	ret = do_munmap(mm, addr, len);
+	ret = do_munmap(mm, addr, len, 1);
 	up_write(&mm->mmap_sem);
 	return ret;
 }
@@ -1032,6 +1229,9 @@
 	unsigned long flags;
 	rb_node_t ** rb_link, * rb_parent;
 
+	vm_validate_enough("entering do_brk");
+
+
 	len = PAGE_ALIGN(len);
 	if (!len)
 		return addr;
@@ -1052,7 +1252,7 @@
  munmap_back:
 	vma = find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent);
 	if (vma && vma->vm_start < addr + len) {
-		if (do_munmap(mm, addr, len))
+		if (do_munmap(mm, addr, len, 1))
 			return -ENOMEM;
 		goto munmap_back;
 	}
@@ -1068,7 +1268,7 @@
 	if (!vm_enough_memory(len >> PAGE_SHIFT))
 		return -ENOMEM;
 
-	flags = VM_DATA_DEFAULT_FLAGS | mm->def_flags;
+	flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags; 
 
 	/* Can we just expand an old anonymous mapping? */
 	if (rb_parent && vma_merge(mm, prev, rb_parent, addr, addr + len, flags))
@@ -1079,8 +1279,11 @@
 	 */
 	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (!vma)
+	{
+		/* We accounted this address space - undo it */
+		vm_unacct_memory(len >> PAGE_SHIFT);
 		return -ENOMEM;
-
+	}
 	vma->vm_mm = mm;
 	vma->vm_start = addr;
 	vma->vm_end = addr + len;
@@ -1099,6 +1302,9 @@
 		mm->locked_vm += len >> PAGE_SHIFT;
 		make_pages_present(addr, addr + len);
 	}
+
+	vm_validate_enough("exiting do_brk");
+
 	return addr;
 }
 
@@ -1140,6 +1346,10 @@
 		unsigned long end = mpnt->vm_end;
 		unsigned long size = end - start;
 
+		/* If the VMA has been charged for, account for its removal */
+		if (mpnt->vm_flags & VM_ACCOUNT)
+			vm_unacct_memory(size >> PAGE_SHIFT);
+	
 		if (mpnt->vm_ops) {
 			if (mpnt->vm_ops->close)
 				mpnt->vm_ops->close(mpnt);
@@ -1159,6 +1369,9 @@
 		BUG();
 
 	clear_page_tables(mm, FIRST_USER_PGD_NR, USER_PTRS_PER_PGD);
+
+	vm_validate_enough("exiting exit_mmap");
+
 }
 
 /* Insert vm structure into process list sorted by address
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/mprotect.c linux.20pre10-ac2/mm/mprotect.c
--- linux.20pre10/mm/mprotect.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/mm/mprotect.c	2002-09-18 12:57:34.000000000 +0100
@@ -2,6 +2,23 @@
  *	linux/mm/mprotect.c
  *
  *  (C) Copyright 1994 Linus Torvalds
+ *
+ *  Address space accounting code	<alan@redhat.com>
+ *  (c) Copyright 2002 Red Hat Inc, All Rights Reserved
+ *
+ *  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/slab.h>
 #include <linux/smp_lock.h>
@@ -241,11 +258,28 @@
 {
 	pgprot_t newprot;
 	int error;
+	unsigned long charged = 0;
 
 	if (newflags == vma->vm_flags) {
 		*pprev = vma;
 		return 0;
 	}
+
+	/*
+	 * If we make a private mapping writable we increase our commit;
+	 * but (without finer accounting) cannot reduce our commit if we
+	 * make it unwritable again.
+	 *
+	 * FIXME? We haven't defined a VM_NORESERVE flag, so mprotecting
+	 * a MAP_NORESERVE private mapping to writable will now reserve.
+	 */
+	if ((newflags & VM_WRITE) &&
+	    !(vma->vm_flags & (VM_ACCOUNT|VM_WRITE|VM_SHARED))) {
+		charged = (end - start) >> PAGE_SHIFT;
+		if (!vm_enough_memory(charged))
+			return -ENOMEM;
+		newflags |= VM_ACCOUNT;
+	}
 	newprot = protection_map[newflags & 0xf];
 	if (start == vma->vm_start) {
 		if (end == vma->vm_end)
@@ -256,10 +290,10 @@
 		error = mprotect_fixup_end(vma, pprev, start, newflags, newprot);
 	else
 		error = mprotect_fixup_middle(vma, pprev, start, end, newflags, newprot);
-
-	if (error)
+	if (error) {
+		vm_unacct_memory(charged);
 		return error;
-
+	}
 	change_protection(start, end, newprot);
 	return 0;
 }
@@ -270,6 +304,8 @@
 	struct vm_area_struct * vma, * next, * prev;
 	int error = -EINVAL;
 
+	vm_validate_enough("entering mprotect");
+
 	if (start & ~PAGE_MASK)
 		return -EINVAL;
 	len = PAGE_ALIGN(len);
@@ -333,5 +369,6 @@
 	}
 out:
 	up_write(&current->mm->mmap_sem);
+	vm_validate_enough("exiting mprotect");
 	return error;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/mremap.c linux.20pre10-ac2/mm/mremap.c
--- linux.20pre10/mm/mremap.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/mm/mremap.c	2002-09-18 12:56:20.000000000 +0100
@@ -2,6 +2,23 @@
  *	linux/mm/remap.c
  *
  *	(C) Copyright 1996 Linus Torvalds
+ *
+ *	Address space accounting code	<alan@redhat.com>
+ *	(c) Copyright 2002 Red Hat Inc, All Rights Reserved
+ *
+ *  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/slab.h>
@@ -13,8 +30,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgalloc.h>
 
-extern int vm_enough_memory(long pages);
-
 static inline pte_t *get_one_pte(struct mm_struct *mm, unsigned long addr)
 {
 	pgd_t * pgd;
@@ -61,8 +76,14 @@
 {
 	int error = 0;
 	pte_t pte;
+	struct page * page = NULL;
+
+	if (pte_present(*src))
+		page = pte_page(*src);
 
 	if (!pte_none(*src)) {
+		if (page)
+			page_remove_rmap(page, src);
 		pte = ptep_get_and_clear(src);
 		if (!dst) {
 			/* No dest?  We must put it back. */
@@ -70,6 +91,8 @@
 			error++;
 		}
 		set_pte(dst, pte);
+		if (page)
+			page_add_rmap(page, dst);
 	}
 	return error;
 }
@@ -130,6 +153,7 @@
 	struct vm_area_struct * new_vma, * next, * prev;
 	int allocated_vma;
 
+
 	new_vma = NULL;
 	next = find_vma_prev(mm, new_addr, &prev);
 	if (next) {
@@ -189,7 +213,8 @@
 				new_vma->vm_ops->open(new_vma);
 			insert_vm_struct(current->mm, new_vma);
 		}
-		do_munmap(current->mm, addr, old_len);
+		/* The old VMA has been accounted for, don't double account */
+		do_munmap(current->mm, addr, old_len, 0);
 		current->mm->total_vm += new_len >> PAGE_SHIFT;
 		if (new_vma->vm_flags & VM_LOCKED) {
 			current->mm->locked_vm += new_len >> PAGE_SHIFT;
@@ -217,6 +242,7 @@
 {
 	struct vm_area_struct *vma;
 	unsigned long ret = -EINVAL;
+	unsigned long charged = 0;
 
 	if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE))
 		goto out;
@@ -246,16 +272,17 @@
 		if ((addr <= new_addr) && (addr+old_len) > new_addr)
 			goto out;
 
-		do_munmap(current->mm, new_addr, new_len);
+		do_munmap(current->mm, new_addr, new_len, 1);
 	}
 
 	/*
 	 * Always allow a shrinking remap: that just unmaps
 	 * the unnecessary pages..
+	 * do_munmap does all the needed commit accounting
 	 */
 	ret = addr;
 	if (old_len >= new_len) {
-		do_munmap(current->mm, addr+new_len, old_len - new_len);
+		do_munmap(current->mm, addr+new_len, old_len - new_len, 1);
 		if (!(flags & MREMAP_FIXED) || (new_addr == addr))
 			goto out;
 	}
@@ -285,11 +312,12 @@
 	if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len)
 	    > current->rlim[RLIMIT_AS].rlim_cur)
 		goto out;
-	/* Private writable mapping? Check memory availability.. */
-	if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE &&
-	    !(flags & MAP_NORESERVE)				 &&
-	    !vm_enough_memory((new_len - old_len) >> PAGE_SHIFT))
-		goto out;
+
+	if (vma->vm_flags & VM_ACCOUNT) {
+		charged = (new_len - old_len) >> PAGE_SHIFT;
+		if(!vm_enough_memory(charged))
+			goto out_nc;
+	}
 
 	/* old_len exactly to the end of the area..
 	 * And we're not relocating the area.
@@ -313,6 +341,7 @@
 						   addr + new_len);
 			}
 			ret = addr;
+			vm_validate_enough("mremap path1");
 			goto out;
 		}
 	}
@@ -336,6 +365,12 @@
 		ret = move_vma(vma, addr, old_len, new_len, new_addr);
 	}
 out:
+	if(ret & ~PAGE_MASK)
+	{
+		vm_unacct_memory(charged);
+		vm_validate_enough("mremap error path");
+	}
+out_nc:
 	return ret;
 }
 
@@ -345,8 +380,10 @@
 {
 	unsigned long ret;
 
+	vm_validate_enough("entry to mremap");
 	down_write(&current->mm->mmap_sem);
 	ret = do_mremap(addr, old_len, new_len, flags, new_addr);
 	up_write(&current->mm->mmap_sem);
+	vm_validate_enough("exit from mremap");
 	return ret;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/oom_kill.c linux.20pre10-ac2/mm/oom_kill.c
--- linux.20pre10/mm/oom_kill.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/mm/oom_kill.c	2002-09-29 20:03:17.000000000 +0100
@@ -82,7 +82,7 @@
 	 * Niced processes are most likely less important, so double
 	 * their badness points.
 	 */
-	if (p->nice > 0)
+	if (task_nice(p) > 0)
 		points *= 2;
 
 	/*
@@ -146,7 +146,7 @@
 	 * all the memory it needs. That way it should be able to
 	 * exit() and clear out its resources quickly...
 	 */
-	p->counter = 5 * HZ;
+	p->time_slice = HZ;
 	p->flags |= PF_MEMALLOC | PF_MEMDIE;
 
 	/* This process has hardware access, be more careful. */
@@ -168,6 +168,7 @@
 static void oom_kill(void)
 {
 	struct task_struct *p, *q;
+	extern wait_queue_head_t kswapd_done;
 
 	read_lock(&tasklist_lock);
 	p = select_bad_process();
@@ -183,6 +184,9 @@
 	}
 	read_unlock(&tasklist_lock);
 
+	/* Chances are by this time our victim is sleeping on kswapd. */
+	wake_up(&kswapd_done);
+
 	/*
 	 * Make kswapd go out of the way, so "p" has a good chance of
 	 * killing itself before someone else gets the chance to ask
@@ -200,12 +204,6 @@
 	static unsigned long first, last, count, lastkill;
 	unsigned long now, since;
 
-	/*
-	 * Enough swap space left?  Not OOM.
-	 */
-	if (nr_swap_pages > 0)
-		return;
-
 	now = jiffies;
 	since = now - last;
 	last = now;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/page_alloc.c linux.20pre10-ac2/mm/page_alloc.c
--- linux.20pre10/mm/page_alloc.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/mm/page_alloc.c	2002-09-29 20:03:17.000000000 +0100
@@ -10,6 +10,7 @@
  *  Reshaped it to be a zoned allocator, Ingo Molnar, Red Hat, 1999
  *  Discontiguous memory support, Kanoj Sarcar, SGI, Nov 1999
  *  Zone balancing, Kanoj Sarcar, SGI, Jan 2000
+ *  Per-CPU page pool, Ingo Molnar, Red Hat, 2001, 2002
  */
 
 #include <linux/config.h>
@@ -21,16 +22,16 @@
 #include <linux/bootmem.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/mm_inline.h>
+#include <linux/smp.h>
 
 int nr_swap_pages;
 int nr_active_pages;
-int nr_inactive_pages;
-LIST_HEAD(inactive_list);
-LIST_HEAD(active_list);
+int nr_inactive_dirty_pages;
+int nr_inactive_clean_pages;
 pg_data_t *pgdat_list;
 
 /*
- *
  * The zone_table array is used to look up the address of the
  * struct zone corresponding to a given zone number (ZONE_DMA,
  * ZONE_NORMAL, or ZONE_HIGHMEM).
@@ -42,13 +43,15 @@
 static int zone_balance_ratio[MAX_NR_ZONES] __initdata = { 128, 128, 128, };
 static int zone_balance_min[MAX_NR_ZONES] __initdata = { 20 , 20, 20, };
 static int zone_balance_max[MAX_NR_ZONES] __initdata = { 255 , 255, 255, };
+static int zone_extrafree_ratio[MAX_NR_ZONES] __initdata = { 128, 512, 0, };
+static int zone_extrafree_max[MAX_NR_ZONES] __initdata = { 1024 , 1024, 0, };
 
 /*
  * Temporary debugging check.
  */
 #define BAD_RANGE(zone, page)						\
 (									\
-	(((page) - mem_map) >= ((zone)->zone_start_mapnr+(zone)->size))	\
+	(((page) - mem_map) >= ((zone)->zone_start_mapnr+(zone)->size)) \
 	|| (((page) - mem_map) < (zone)->zone_start_mapnr)		\
 	|| ((zone) != page_zone(page))					\
 )
@@ -84,34 +87,47 @@
 	unsigned long index, page_idx, mask, flags;
 	free_area_t *area;
 	struct page *base;
+	per_cpu_t *per_cpu;
 	zone_t *zone;
 
-	/*
-	 * Yes, think what happens when other parts of the kernel take 
+	/* Yes, think what happens when other parts of the kernel take 
 	 * a reference to a page in order to pin it for io. -ben
 	 */
-	if (PageLRU(page)) {
-		if (unlikely(in_interrupt()))
-			BUG();
+	if (PageLRU(page))
 		lru_cache_del(page);
-	}
 
+	/*
+	 * This late check is safe because reserved pages do not
+	 * have a valid page->count. This trick avoids overhead
+	 * in __free_pages().
+	 */
+	if (PageReserved(page))
+		return;
 	if (page->buffers)
 		BUG();
-	if (page->mapping)
+	if (page->mapping) {
+		printk(KERN_CRIT "Page has mapping still set. This is a serious situation. However if you \n");
+		printk(KERN_CRIT "are using the NVidia binary only module please report this bug to \n");
+		printk(KERN_CRIT "NVidia and not to the linux kernel mailinglist.\n");
 		BUG();
+	}
 	if (!VALID_PAGE(page))
 		BUG();
+	if (PageSwapCache(page))
+		BUG();
 	if (PageLocked(page))
 		BUG();
 	if (PageActive(page))
 		BUG();
+	if (PageInactiveDirty(page))
+		BUG();
+	if (PageInactiveClean(page))
+		BUG();
+	if (page->pte_chain)
+		BUG();
 	page->flags &= ~((1<<PG_referenced) | (1<<PG_dirty));
-
-	if (current->flags & PF_FREE_PAGES)
-		goto local_freelist;
- back_local_freelist:
-
+	page->age = PAGE_AGE_START;
+	
 	zone = page_zone(page);
 
 	mask = (~0UL) << order;
@@ -123,7 +139,18 @@
 
 	area = zone->free_area + order;
 
-	spin_lock_irqsave(&zone->lock, flags);
+	per_cpu = zone->cpu_pages + smp_processor_id();
+
+	__save_flags(flags);
+	__cli();
+	if (!order && (per_cpu->nr_pages < per_cpu->max_nr_pages) && (free_high(zone) <= 0)) {
+		list_add(&page->list, &per_cpu->head);
+		per_cpu->nr_pages++;
+		__restore_flags(flags);
+		return;
+	}
+
+	spin_lock(&zone->lock);
 
 	zone->free_pages -= mask;
 
@@ -140,7 +167,7 @@
 		/*
 		 * Move the buddy up one level.
 		 * This code is taking advantage of the identity:
-		 * 	-mask = 1+~mask
+		 *	-mask = 1+~mask
 		 */
 		buddy1 = base + (page_idx ^ -mask);
 		buddy2 = base + page_idx;
@@ -158,17 +185,6 @@
 	list_add(&(base + page_idx)->list, &area->free_list);
 
 	spin_unlock_irqrestore(&zone->lock, flags);
-	return;
-
- local_freelist:
-	if (current->nr_local_pages)
-		goto back_local_freelist;
-	if (in_interrupt())
-		goto back_local_freelist;		
-
-	list_add(&page->list, &current->local_pages);
-	page->index = order;
-	current->nr_local_pages++;
 }
 
 #define MARK_USED(index, order, area) \
@@ -198,13 +214,32 @@
 static FASTCALL(struct page * rmqueue(zone_t *zone, unsigned int order));
 static struct page * rmqueue(zone_t *zone, unsigned int order)
 {
+	per_cpu_t *per_cpu = zone->cpu_pages + smp_processor_id();
 	free_area_t * area = zone->free_area + order;
 	unsigned int curr_order = order;
 	struct list_head *head, *curr;
 	unsigned long flags;
 	struct page *page;
+	int threshold = 0;
+
+	if (!(current->flags & PF_MEMALLOC))
+		 threshold = (per_cpu->max_nr_pages / 8);
+	__save_flags(flags);
+	__cli();
 
-	spin_lock_irqsave(&zone->lock, flags);
+	if (!order && (per_cpu->nr_pages>threshold)) {
+		if (unlikely(list_empty(&per_cpu->head)))
+			BUG();
+		page = list_entry(per_cpu->head.next, struct page, list);
+		list_del(&page->list);
+		per_cpu->nr_pages--;
+		__restore_flags(flags);
+ 
+		set_page_count(page, 1);
+		return page;
+	}
+ 
+ 	spin_lock(&zone->lock);
 	do {
 		head = &area->free_list;
 		curr = head->next;
@@ -227,10 +262,7 @@
 			set_page_count(page, 1);
 			if (BAD_RANGE(zone,page))
 				BUG();
-			if (PageLRU(page))
-				BUG();
-			if (PageActive(page))
-				BUG();
+			DEBUG_LRU_PAGE(page);
 			return page;	
 		}
 		curr_order++;
@@ -249,76 +281,83 @@
 }
 #endif
 
-static struct page * FASTCALL(balance_classzone(zone_t *, unsigned int, unsigned int, int *));
-static struct page * balance_classzone(zone_t * classzone, unsigned int gfp_mask, unsigned int order, int * freed)
+/*
+ * If we are able to directly reclaim pages, we move pages from the
+ * inactive_clean list onto the free list until the zone has enough
+ * free pages or until the inactive_clean pages are exhausted.
+ * If we cannot do this work ourselves, call kswapd.
+ */
+void FASTCALL(fixup_freespace(zone_t * zone, int direct_reclaim));
+void fixup_freespace(zone_t * zone, int direct_reclaim)
+{
+	if (direct_reclaim) {
+		struct page * page;
+		do {
+			if ((page = reclaim_page(zone)))
+				__free_pages_ok(page, 0);
+		} while (page && zone->free_pages <= zone->pages_min);
+	} else
+		wakeup_kswapd(GFP_ATOMIC);
+}
+
+#define PAGES_KERNEL	0
+#define PAGES_MIN	1
+#define PAGES_LOW	2
+#define PAGES_HIGH	3
+
+/*
+ * This function does the dirty work for __alloc_pages
+ * and is separated out to keep the code size smaller.
+ * (suggested by Davem at 1:30 AM, typed by Rik at 6 AM)
+ */
+static struct page * __alloc_pages_limit(zonelist_t *zonelist,
+			unsigned long order, int limit, int direct_reclaim)
 {
-	struct page * page = NULL;
-	int __freed = 0;
+	zone_t **zone = zonelist->zones;
+	unsigned long water_mark = 0;
 
-	if (!(gfp_mask & __GFP_WAIT))
-		goto out;
-	if (in_interrupt())
-		BUG();
-
-	current->allocation_order = order;
-	current->flags |= PF_MEMALLOC | PF_FREE_PAGES;
-
-	__freed = try_to_free_pages_zone(classzone, gfp_mask);
-
-	current->flags &= ~(PF_MEMALLOC | PF_FREE_PAGES);
-
-	if (current->nr_local_pages) {
-		struct list_head * entry, * local_pages;
-		struct page * tmp;
-		int nr_pages;
-
-		local_pages = &current->local_pages;
-
-		if (likely(__freed)) {
-			/* pick from the last inserted so we're lifo */
-			entry = local_pages->next;
-			do {
-				tmp = list_entry(entry, struct page, list);
-				if (tmp->index == order && memclass(page_zone(tmp), classzone)) {
-					list_del(entry);
-					current->nr_local_pages--;
-					set_page_count(tmp, 1);
-					page = tmp;
-
-					if (page->buffers)
-						BUG();
-					if (page->mapping)
-						BUG();
-					if (!VALID_PAGE(page))
-						BUG();
-					if (PageLocked(page))
-						BUG();
-					if (PageLRU(page))
-						BUG();
-					if (PageActive(page))
-						BUG();
-					if (PageDirty(page))
-						BUG();
+	for (;;) {
+		zone_t *z = *(zone++);
 
-					break;
-				}
-			} while ((entry = entry->next) != local_pages);
+		if (!z)
+			break;
+		if (!z->size)
+			BUG();
+
+		/*
+		 * We allocate if the number of (free + inactive_clean)
+		 * pages is above the watermark.
+		 */
+		switch (limit) {
+			case PAGES_KERNEL:
+				water_mark = z->pages_min / 2;
+				break;
+			case PAGES_MIN:
+				water_mark = z->pages_min;
+				break;
+			case PAGES_LOW:
+				water_mark = z->pages_low;
+				break;
+			default:
+			case PAGES_HIGH:
+				water_mark = z->pages_high;
 		}
 
-		nr_pages = current->nr_local_pages;
-		/* free in reverse order so that the global order will be lifo */
-		while ((entry = local_pages->prev) != local_pages) {
-			list_del(entry);
-			tmp = list_entry(entry, struct page, list);
-			__free_pages_ok(tmp, tmp->index);
-			if (!nr_pages--)
-				BUG();
+		if (z->free_pages + z->inactive_clean_pages >= water_mark) {
+			struct page *page = NULL;
+			/* If possible, reclaim a page directly. */
+			if (direct_reclaim)
+				page = reclaim_page(z);
+			/* If that fails, fall back to rmqueue. */
+			if (!page)
+				page = rmqueue(z, order);
+			if (page)
+				return page;
 		}
-		current->nr_local_pages = 0;
 	}
- out:
-	*freed = __freed;
-	return page;
+
+	/* Found nothing. */
+	return NULL;
 }
 
 /*
@@ -326,100 +365,247 @@
  */
 struct page * __alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_t *zonelist)
 {
-	unsigned long min;
-	zone_t **zone, * classzone;
+	zone_t **zone;
+	int min, direct_reclaim = 0;
 	struct page * page;
-	int freed;
 
+	/*
+	 * (If anyone calls gfp from interrupts nonatomically then it
+	 * will sooner or later tripped up by a schedule().)
+	 *
+	 * We fall back to lower-level zones if allocation
+	 * in a higher zone fails.
+	 */
+
+	/*
+	 * Can we take pages directly from the inactive_clean
+	 * list?
+	 */
+	if (order == 0 && (gfp_mask & __GFP_WAIT))
+		direct_reclaim = 1;
+
+try_again:
+	/*
+	 * First, see if we have any zones with lots of free memory.
+	 *
+	 * We allocate free memory first because it doesn't contain
+	 * any data we would want to cache.
+	 */
 	zone = zonelist->zones;
-	classzone = *zone;
-	if (classzone == NULL)
-		return NULL;
 	min = 1UL << order;
 	for (;;) {
 		zone_t *z = *(zone++);
 		if (!z)
 			break;
+		if (!z->size)
+			BUG();
 
-		min += z->pages_low;
+		min += z->pages_min;
 		if (z->free_pages > min) {
 			page = rmqueue(z, order);
 			if (page)
 				return page;
-		}
+		} else if (z->free_pages < z->pages_min)
+			fixup_freespace(z, direct_reclaim);
+	}
+
+	/*
+	 * Next, try to allocate a page from a zone with a HIGH
+	 * amount of (free + inactive_clean) pages.
+	 *
+	 * If there is a lot of activity, inactive_target
+	 * will be high and we'll have a good chance of
+	 * finding a page using the HIGH limit.
+	 */
+	page = __alloc_pages_limit(zonelist, order, PAGES_HIGH, direct_reclaim);
+	if (page)
+		return page;
+
+	/*
+	 * Then try to allocate a page from a zone with more
+	 * than zone->pages_low of (free + inactive_clean) pages.
+	 *
+	 * When the working set is very large and VM activity
+	 * is low, we're most likely to have our allocation
+	 * succeed here.
+	 */
+	page = __alloc_pages_limit(zonelist, order, PAGES_LOW, direct_reclaim);
+	if (page)
+		return page;
+
+	/*
+	 * OK, none of the zones on our zonelist has lots
+	 * of pages free.
+	 *
+	 * We wake up kswapd, in the hope that kswapd will
+	 * resolve this situation before memory gets tight.
+	 *
+	 * We'll also help a bit trying to free pages, this
+	 * way statistics will make sure really fast allocators
+	 * are slowed down more than slow allocators and other
+	 * programs in the system shouldn't be impacted as much
+	 * by the hogs.
+	 */
+	wakeup_kswapd(gfp_mask);
+
+	/*
+	 * After waking up kswapd, we try to allocate a page
+	 * from any zone which isn't critical yet.
+	 *
+	 * Kswapd should, in most situations, bring the situation
+	 * back to normal in no time.
+	 */
+	page = __alloc_pages_limit(zonelist, order, PAGES_MIN, direct_reclaim);
+	if (page)
+		return page;
+
+	/*
+	 * Kernel allocations can eat a few emergency pages.
+	 * We should be able to run without this, find out why
+	 * the SCSI layer isn't happy ...
+	 */
+	if (gfp_mask & __GFP_HIGH) {
+		page = __alloc_pages_limit(zonelist, order, PAGES_KERNEL, direct_reclaim);
+		if (page)
+			return page;
 	}
 
-	classzone->need_balance = 1;
-	mb();
-	if (waitqueue_active(&kswapd_wait))
-		wake_up_interruptible(&kswapd_wait);
+	/*
+	 * Oh well, we didn't succeed.
+	 */
+	if (!(current->flags & PF_MEMALLOC)) {
+		/*
+		 * Are we dealing with a higher order allocation?
+		 *
+		 * If so, try to defragment some memory.
+		 */
+		if (order > 0 && (gfp_mask & __GFP_WAIT))
+			goto defragment;
+
+		/*
+		 * If we arrive here, we are really tight on memory.
+		 * Since kswapd didn't succeed in freeing pages for us,
+		 * we need to help it.
+		 *
+		 * Single page allocs loop until the allocation succeeds.
+		 * Multi-page allocs can fail due to memory fragmentation;
+		 * in that case we bail out to prevent infinite loops and
+		 * hanging device drivers ...
+		 *
+		 * Another issue are GFP_NOFS allocations; because they
+		 * do not have __GFP_FS set it's possible we cannot make
+		 * any progress freeing pages, in that case it's better
+		 * to give up than to deadlock the kernel looping here.
+		 *
+		 * NFS: we must yield the CPU (to rpciod) to avoid deadlock.
+		 */
+		if (gfp_mask & __GFP_WAIT) {
+			__set_current_state(TASK_RUNNING);
+			yield();
+			if (!order || free_high(ALL_ZONES) >= 0) {
+				int progress = try_to_free_pages(gfp_mask);
+				if (progress || (gfp_mask & __GFP_FS))
+					goto try_again;
+				/*
+				 * Fail if no progress was made and the
+				 * allocation may not be able to block on IO.
+				 */
+				return NULL;
+			}
+		}
+	}
 
+	/*
+	 * Final phase: allocate anything we can!
+	 *
+	 * Higher order allocations, GFP_ATOMIC allocations and
+	 * recursive allocations (PF_MEMALLOC) end up here.
+	 *
+	 * Only recursive allocations can use the very last pages
+	 * in the system, otherwise it would be just too easy to
+	 * deadlock the system...
+	 */
 	zone = zonelist->zones;
 	min = 1UL << order;
 	for (;;) {
-		unsigned long local_min;
 		zone_t *z = *(zone++);
+		struct page * page = NULL;
 		if (!z)
 			break;
 
-		local_min = z->pages_min;
-		if (!(gfp_mask & __GFP_WAIT))
-			local_min >>= 2;
-		min += local_min;
-		if (z->free_pages > min) {
+		/*
+		 * SUBTLE: direct_reclaim is only possible if the task
+		 * becomes PF_MEMALLOC while looping above. This will
+		 * happen when the OOM killer selects this task for
+		 * death.
+		 */
+		if (direct_reclaim) {
+			page = reclaim_page(z);
+			if (page)
+				return page;
+		}
+
+		/* XXX: is pages_min/4 a good amount to reserve for this? */
+		min += z->pages_min / 4;
+		if (z->free_pages > min || ((current->flags & PF_MEMALLOC) && !in_interrupt())) {
 			page = rmqueue(z, order);
 			if (page)
 				return page;
 		}
 	}
+	goto out_failed;
 
-	/* here we're in the low on memory slow path */
 
-rebalance:
-	if (current->flags & (PF_MEMALLOC | PF_MEMDIE)) {
+	/*
+	 * Naive "defragmentation" for higher-order allocations. First we
+	 * free the inactive_clean pages to see if we can allocate our
+	 * allocation, then we call page_launder() to clean some dirty
+	 * pages, and last we try once more.
+	 *
+	 * We might want to turn this into something which defragments
+	 * memory based on physical page, simply by looking for unmapped
+	 * pages next to pages on the free list...
+	 */
+defragment:
+	{
+		int freed = 0;
+defragment_again:
 		zone = zonelist->zones;
 		for (;;) {
 			zone_t *z = *(zone++);
 			if (!z)
 				break;
-
-			page = rmqueue(z, order);
-			if (page)
-				return page;
+			if (!z->size)
+				continue;
+			while (z->inactive_clean_pages) {
+				struct page * page;
+				/* Move one page to the free list. */
+				page = reclaim_page(z);
+				if (!page)
+					break;
+				__free_page(page);
+				/* Try if the allocation succeeds. */
+				page = rmqueue(z, order);
+				if (page)
+					return page;
+			}
 		}
-		return NULL;
-	}
-
-	/* Atomic allocations - we can't balance anything */
-	if (!(gfp_mask & __GFP_WAIT))
-		return NULL;
-
-	page = balance_classzone(classzone, gfp_mask, order, &freed);
-	if (page)
-		return page;
-
-	zone = zonelist->zones;
-	min = 1UL << order;
-	for (;;) {
-		zone_t *z = *(zone++);
-		if (!z)
-			break;
 
-		min += z->pages_min;
-		if (z->free_pages > min) {
-			page = rmqueue(z, order);
-			if (page)
-				return page;
+		/* XXX: do real defragmentation instead of calling launder ? */
+		if (!freed & !(current->flags & PF_MEMALLOC)) {
+			freed = 1;
+			current->flags |= PF_MEMALLOC;
+			try_to_free_pages(gfp_mask);
+			current->flags &= ~PF_MEMALLOC;
+			goto defragment_again;
 		}
 	}
 
-	/* Don't let big-order allocations loop */
-	if (order > 3)
-		return NULL;
-
-	/* Yield for kswapd, and try again */
-	yield();
-	goto rebalance;
+
+out_failed:
+	/* No luck.. */
+//	printk(KERN_ERR "__alloc_pages: %lu-order allocation failed.\n", order);
+	return NULL;
 }
 
 /*
@@ -450,7 +636,7 @@
 
 void __free_pages(struct page *page, unsigned int order)
 {
-	if (!PageReserved(page) && put_page_testzero(page))
+	if (put_page_testzero(page))
 		__free_pages_ok(page, order);
 }
 
@@ -465,12 +651,13 @@
  */
 unsigned int nr_free_pages (void)
 {
-	unsigned int sum = 0;
+	unsigned int sum;
 	zone_t *zone;
 
+	sum = 0;
 	for_each_zone(zone)
 		sum += zone->free_pages;
-
+	
 	return sum;
 }
 
@@ -488,11 +675,11 @@
 		zone_t *zone;
 
 		for (zone = *zonep++; zone; zone = *zonep++) {
-			unsigned long size = zone->size;
-			unsigned long high = zone->pages_high;
-			if (size > high)
-				sum += size - high;
+			sum += zone->free_pages;
+			sum += zone->inactive_clean_pages;
+			sum += zone->inactive_dirty_pages;
 		}
+
 	}
 
 	return sum;
@@ -543,10 +730,15 @@
 		tmpdat = tmpdat->node_next;
 	}
 
-	printk("( Active: %d, inactive: %d, free: %d )\n",
-	       nr_active_pages,
-	       nr_inactive_pages,
-	       nr_free_pages());
+	printk("Free pages:      %6dkB (%6dkB HighMem)\n",
+		nr_free_pages() << (PAGE_SHIFT-10),
+		nr_free_highpages() << (PAGE_SHIFT-10));
+
+	printk("( Active: %d, inactive_dirty: %d, inactive_clean: %d, free: %d )\n",
+		nr_active_pages,
+		nr_inactive_dirty_pages,
+		nr_inactive_clean_pages,
+		nr_free_pages());
 
 	for (type = 0; type < MAX_NR_ZONES; type++) {
 		struct list_head *head, *curr;
@@ -681,6 +873,7 @@
  *   - mark all memory queues empty
  *   - clear the memory bitmaps
  */
+extern unsigned int kswapd_minfree;
 void __init free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap,
 	unsigned long *zones_size, unsigned long zone_start_paddr, 
 	unsigned long *zholes_size, struct page *lmem_map)
@@ -726,8 +919,9 @@
 
 	offset = lmem_map - mem_map;	
 	for (j = 0; j < MAX_NR_ZONES; j++) {
+		int k;
 		zone_t *zone = pgdat->node_zones + j;
-		unsigned long mask;
+		unsigned long mask, extrafree = 0;
 		unsigned long size, realsize;
 
 		zone_table[nid * MAX_NR_ZONES + j] = zone;
@@ -738,16 +932,40 @@
 		printk("zone(%lu): %lu pages.\n", j, size);
 		zone->size = size;
 		zone->name = zone_names[j];
+
+		for (k = 0; k < NR_CPUS; k++) {
+			per_cpu_t *per_cpu = zone->cpu_pages + k;
+
+			INIT_LIST_HEAD(&per_cpu->head);
+			per_cpu->nr_pages = 0;
+			per_cpu->max_nr_pages = realsize / smp_num_cpus / 128;
+			if (per_cpu->max_nr_pages > MAX_PER_CPU_PAGES)
+				per_cpu->max_nr_pages = MAX_PER_CPU_PAGES;
+			else if (!per_cpu->max_nr_pages)
+				per_cpu->max_nr_pages = 1;
+		}
 		zone->lock = SPIN_LOCK_UNLOCKED;
 		zone->zone_pgdat = pgdat;
 		zone->free_pages = 0;
+		zone->inactive_clean_pages = 0;
+		zone->inactive_dirty_pages = 0;
 		zone->need_balance = 0;
+		zone->pte_chain_freelist = NULL;
+		INIT_LIST_HEAD(&zone->active_list);
+		INIT_LIST_HEAD(&zone->inactive_dirty_list);
+		INIT_LIST_HEAD(&zone->inactive_clean_list);
+		spin_lock_init(&zone->pte_chain_freelist_lock);
+
 		if (!size)
 			continue;
 
 		/*
-		 * The per-page waitqueue mechanism uses hashed waitqueues
-		 * per zone.
+		 * The per-page waitqueue mechanism requires hash tables
+		 * whose buckets are waitqueues. These hash tables are
+		 * per-zone, and dynamically sized according to the size
+		 * of the zone so as to maintain a good ratio of waiters
+		 * to hash table buckets. Right here we just allocate
+		 * and initialize them for later use (in filemap.c)
 		 */
 		zone->wait_table_size = wait_table_size(size);
 		zone->wait_table_shift =
@@ -761,15 +979,22 @@
 
 		pgdat->nr_zones = j+1;
 
+		/*
+		 * On large memory machines we keep extra memory
+		 * free for kernel allocations.
+		 */
+		if (zone_extrafree_ratio[j])
+			extrafree = min_t(int, (realtotalpages / zone_extrafree_ratio[j]), zone_extrafree_max[j]);
+		if (extrafree < zone_balance_max[j])
+			extrafree = 0;
+
 		mask = (realsize / zone_balance_ratio[j]);
 		if (mask < zone_balance_min[j])
 			mask = zone_balance_min[j];
-		else if (mask > zone_balance_max[j])
-			mask = zone_balance_max[j];
-		zone->pages_min = mask;
-		zone->pages_low = mask*2;
-		zone->pages_high = mask*3;
-
+		zone->pages_min = extrafree + min(mask, (unsigned long)zone_balance_max[j]);
+		zone->pages_low = extrafree + mask*2;
+		zone->pages_high = extrafree + mask*3;
+		zone->pages_plenty = extrafree + mask*6;
 		zone->zone_mem_map = mem_map + offset;
 		zone->zone_start_mapnr = offset;
 		zone->zone_start_paddr = zone_start_paddr;
@@ -777,6 +1002,8 @@
 		if ((zone_start_paddr >> PAGE_SHIFT) & (zone_required_alignment-1))
 			printk("BUG: wrong zone alignment, it will crash\n");
 
+		kswapd_minfree += zone->pages_min;
+
 		/*
 		 * Initially all pages are reserved - free ones are freed
 		 * up by free_all_bootmem() once the early boot process is
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/page_io.c linux.20pre10-ac2/mm/page_io.c
--- linux.20pre10/mm/page_io.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/mm/page_io.c	2002-08-13 14:57:05.000000000 +0100
@@ -72,6 +72,11 @@
 
  	/* block_size == PAGE_SIZE/zones_used */
  	brw_page(rw, page, dev, zones, block_size);
+
+ 	/* Note! For consistency we do all of the logic,
+ 	 * decrementing the page count, and unlocking the page in the
+ 	 * swap lock map - in the IO completion handler.
+ 	 */
 	return 1;
 }
 
@@ -82,6 +87,7 @@
  *  - it's marked as being swap-cache
  *  - it's associated with the swap inode
  */
+
 void rw_swap_page(int rw, struct page *page)
 {
 	swp_entry_t entry;
@@ -92,6 +98,8 @@
 		PAGE_BUG(page);
 	if (!PageSwapCache(page))
 		PAGE_BUG(page);
+	if (page->mapping != &swapper_space)
+		PAGE_BUG(page);
 	if (!rw_swap_page_base(rw, entry, page))
 		UnlockPage(page);
 }
@@ -107,6 +115,8 @@
 	
 	if (!PageLocked(page))
 		PAGE_BUG(page);
+	if (PageSwapCache(page))
+		PAGE_BUG(page);
 	if (page->mapping)
 		PAGE_BUG(page);
 	/* needs sync_page to wait I/O completation */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/rmap.c linux.20pre10-ac2/mm/rmap.c
--- linux.20pre10/mm/rmap.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/mm/rmap.c	2002-09-29 20:03:17.000000000 +0100
@@ -0,0 +1,433 @@
+/*
+ * mm/rmap.c - physical to virtual reverse mappings
+ *
+ * Copyright 2001, Rik van Riel <riel@conectiva.com.br>
+ * Released under the General Public License (GPL).
+ *
+ *
+ * Simple, low overhead pte-based reverse mapping scheme.
+ * This is kept modular because we may want to experiment
+ * with object-based reverse mapping schemes. Please try
+ * to keep this thing as modular as possible.
+ */
+
+/*
+ * Locking:
+ * - the page->pte_chain is protected by the PG_chainlock bit,
+ *   which nests within the pagemap_lru_lock, then the
+ *   mm->page_table_lock, and then the page lock.
+ * - because swapout locking is opposite to the locking order
+ *   in the page fault path, the swapout path uses trylocks
+ *   on the mm->page_table_lock
+ */
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+
+#include <asm/pgalloc.h>
+#include <asm/rmap.h>
+#include <asm/smplock.h>
+
+/* #define DEBUG_RMAP */
+
+/*
+ * Shared pages have a chain of pte_chain structures, used to locate
+ * all the mappings to this page. We only need a pointer to the pte
+ * 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.
+ */
+struct pte_chain {
+	struct pte_chain * next;
+	pte_t * ptep;
+};
+
+static inline struct pte_chain * pte_chain_alloc(zone_t *);
+static inline void pte_chain_free(struct pte_chain *, struct pte_chain *,
+		struct page *, zone_t *);
+static void alloc_new_pte_chains(zone_t *);
+
+/**
+ * page_referenced - test if the page was referenced
+ * @page: the page to test
+ *
+ * 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.
+ */
+int page_referenced(struct page * page)
+{
+	struct pte_chain * pc;
+	int referenced = 0;
+
+	if (PageTestandClearReferenced(page))
+		referenced++;
+
+	/* 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++;
+	}
+
+	return referenced;
+}
+
+/**
+ * page_add_rmap - add reverse mapping entry to a page
+ * @page: the page to add the mapping to
+ * @ptep: the page table entry mapping this page
+ *
+ * Add a new pte reverse mapping to a page.
+ * The caller needs to hold the mm->page_table_lock.
+ */
+void page_add_rmap(struct page * page, pte_t * ptep)
+{
+	struct pte_chain * pte_chain;
+
+#ifdef DEBUG_RMAP
+	if (!page || !ptep)
+		BUG();
+	if (!pte_present(*ptep))
+		BUG();
+	if (!ptep_to_mm(ptep))
+		BUG();
+#endif
+
+	if (!VALID_PAGE(page) || PageReserved(page))
+		return;
+
+#ifdef DEBUG_RMAP
+	pte_chain_lock(page);
+	{
+		struct pte_chain * pc;
+		for (pc = page->pte_chain; pc; pc = pc->next) {
+			if (pc->ptep == ptep)
+				BUG();
+		}
+	}
+	pte_chain_unlock(page);
+#endif
+
+	pte_chain = pte_chain_alloc(page_zone(page));
+
+	pte_chain_lock(page);
+
+	/* Hook up the pte_chain to the page. */
+	pte_chain->ptep = ptep;
+	pte_chain->next = page->pte_chain;
+	page->pte_chain = pte_chain;
+
+	pte_chain_unlock(page);
+}
+
+/**
+ * page_remove_rmap - take down reverse mapping to a page
+ * @page: page to remove mapping from
+ * @ptep: page table entry to remove
+ *
+ * Removes the reverse mapping from the pte_chain of the page,
+ * after that the caller can clear the page table entry and free
+ * the page.
+ * Caller needs to hold the mm->page_table_lock.
+ */
+void page_remove_rmap(struct page * page, pte_t * ptep)
+{
+	struct pte_chain * pc, * prev_pc = NULL;
+	zone_t *zone;
+
+	if (!page || !ptep)
+		BUG();
+	if (!VALID_PAGE(page) || PageReserved(page))
+		return;
+
+	zone = page_zone(page);
+
+	pte_chain_lock(page);
+	for (pc = page->pte_chain; pc; prev_pc = pc, pc = pc->next) {
+		if (pc->ptep == ptep) {
+			pte_chain_free(pc, prev_pc, page, zone);
+			goto out;
+		}
+	}
+#ifdef DEBUG_RMAP
+	/* Not found. This should NEVER happen! */
+	printk(KERN_ERR "page_remove_rmap: pte_chain %p not present.\n", ptep);
+	printk(KERN_ERR "page_remove_rmap: only found: ");
+	for (pc = page->pte_chain; pc; pc = pc->next)
+		printk("%p ", pc->ptep);
+	printk("\n");
+	printk(KERN_ERR "page_remove_rmap: driver cleared PG_reserved ?\n");
+#endif
+
+out:
+	pte_chain_unlock(page);
+	return;
+			
+}
+
+/**
+ * try_to_unmap_one - worker function for try_to_unmap
+ * @page: page to unmap
+ * @ptep: page table entry to unmap from page
+ *
+ * Internal helper function for try_to_unmap, called for each page
+ * table entry mapping a page. Because locking order here is opposite
+ * to the locking order used by the page fault path, we use trylocks.
+ * Locking:
+ *	pagemap_lru_lock		page_launder()
+ *	    page lock			page_launder(), trylock
+ *		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)
+{
+	unsigned long address = ptep_to_address(ptep);
+	struct mm_struct * mm = ptep_to_mm(ptep);
+	struct vm_area_struct * vma;
+	pte_t pte;
+	int ret;
+
+	if (!mm)
+		BUG();
+
+	/*
+	 * We need the page_table_lock to protect us from page faults,
+	 * munmap, fork, etc...
+	 */
+	if (!spin_trylock(&mm->page_table_lock))
+		return SWAP_AGAIN;
+
+	/* During mremap, it's possible pages are not in a VMA. */
+	vma = find_vma(mm, address);
+	if (!vma) {
+		ret = SWAP_FAIL;
+		goto out_unlock;
+	}
+
+	/* The page is mlock()d, we cannot swap it out. */
+	if (vma->vm_flags & VM_LOCKED) {
+		ret = SWAP_FAIL;
+		goto out_unlock;
+	}
+
+	/* Nuke the page table entry. */
+	pte = ptep_get_and_clear(ptep);
+	flush_tlb_page(vma, address);
+	flush_cache_page(vma, address);
+
+	/* Store the swap location in the pte. See handle_pte_fault() ... */
+	if (PageSwapCache(page)) {
+		swp_entry_t entry;
+		entry.val = page->index;
+		swap_duplicate(entry);
+		set_pte(ptep, swp_entry_to_pte(entry));
+	}
+
+	/* Move the dirty bit to the physical page now the pte is gone. */
+	if (pte_dirty(pte))
+		set_page_dirty(page);
+
+	mm->rss--;
+	page_cache_release(page);
+	ret = SWAP_SUCCESS;
+
+out_unlock:
+	spin_unlock(&mm->page_table_lock);
+	return ret;
+}
+
+/**
+ * try_to_unmap - try to remove all page table mappings to a page
+ * @page: the page to get unmapped
+ *
+ * Tries to remove all the page table entries which are mapping this
+ * page, used in the pageout path.  Caller must hold pagemap_lru_lock
+ * and the page lock.  Return values are:
+ *
+ * SWAP_SUCCESS	- we succeeded in removing all mappings
+ * SWAP_AGAIN	- we missed a trylock, try again later
+ * SWAP_FAIL	- the page is unswappable
+ * SWAP_ERROR	- an error occurred
+ */
+int try_to_unmap(struct page * page)
+{
+	struct pte_chain * pc, * next_pc, * prev_pc = NULL;
+	zone_t *zone = page_zone(page);
+	int ret = SWAP_SUCCESS;
+
+	/* This page should not be on the pageout lists. */
+	if (!VALID_PAGE(page) || PageReserved(page))
+		BUG();
+	if (!PageLocked(page))
+		BUG();
+	/* We need backing store to swap out a page. */
+	if (!page->mapping)
+		BUG();
+
+	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, zone);
+				break;
+			case SWAP_AGAIN:
+				/* Skip this pte, remembering status. */
+				prev_pc = pc;
+				ret = SWAP_AGAIN;
+				continue;
+			case SWAP_FAIL:
+				return SWAP_FAIL;
+			case SWAP_ERROR:
+				return SWAP_ERROR;
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * page_over_rsslimit - test if the page is over its RSS limit
+ * @page - page to test
+ *
+ * This function returns true if the process owning this page
+ * is over its RSS (resident set size) limit.  For shared pages
+ * we penalise it only if all processes using it are over their
+ * rss limits.
+ * The caller needs to hold the page's pte_chain_lock.
+ */
+int page_over_rsslimit(struct page * page)
+{
+	struct pte_chain * pte_chain = page->pte_chain;
+	struct mm_struct * mm;
+	pte_t * ptep;
+
+	/* No process is using the page. */
+	if (!pte_chain)
+		return 0;
+
+	do {
+		ptep = pte_chain->ptep;
+		mm = ptep_to_mm(ptep);
+
+		/*
+		 * If the process is under its RSS limit, stop
+		 * scanning and don't penalise the page.
+		 */
+		if(!mm->rlimit_rss || mm->rss <= mm->rlimit_rss)
+			return 0;
+		
+		pte_chain = pte_chain->next;
+	} while (pte_chain);
+
+	return 1;
+}
+
+/**
+ ** No more VM stuff below this comment, only pte_chain helper
+ ** functions.
+ **/
+
+static inline void pte_chain_push(zone_t * zone,
+		struct pte_chain * pte_chain)
+{
+	pte_chain->ptep = NULL;
+	pte_chain->next = zone->pte_chain_freelist;
+	zone->pte_chain_freelist = pte_chain;
+}
+
+static inline struct pte_chain * pte_chain_pop(zone_t * zone)
+{
+	struct pte_chain *pte_chain;
+
+	pte_chain = zone->pte_chain_freelist;
+	zone->pte_chain_freelist = pte_chain->next;
+	pte_chain->next = NULL;
+
+	return pte_chain;
+}
+
+/**
+ * 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)
+ * @zone: memory zone to free pte chain in
+ *
+ * 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,
+		zone_t * zone)
+{
+	if (prev_pte_chain)
+		prev_pte_chain->next = pte_chain->next;
+	else if (page)
+		page->pte_chain = pte_chain->next;
+
+	spin_lock(&zone->pte_chain_freelist_lock);
+	pte_chain_push(zone, pte_chain);
+	spin_unlock(&zone->pte_chain_freelist_lock);
+}
+
+/**
+ * pte_chain_alloc - allocate a pte_chain struct
+ * @zone: memory zone to allocate pte_chain for
+ *
+ * Returns a pointer to a fresh pte_chain structure. Allocates new
+ * pte_chain structures as required.
+ * Caller needs to hold the page's pte_chain_lock.
+ */
+static inline struct pte_chain * pte_chain_alloc(zone_t * zone)
+{
+	struct pte_chain * pte_chain;
+
+	spin_lock(&zone->pte_chain_freelist_lock);
+
+	/* Allocate new pte_chain structs as needed. */
+	if (!zone->pte_chain_freelist)
+		alloc_new_pte_chains(zone);
+
+	/* Grab the first pte_chain from the freelist. */
+	pte_chain = pte_chain_pop(zone);
+
+	spin_unlock(&zone->pte_chain_freelist_lock);
+
+	return pte_chain;
+}
+
+/**
+ * alloc_new_pte_chains - convert a free page to pte_chain structures
+ * @zone: memory zone to allocate pte_chains for
+ *
+ * Grabs a free page and converts it to pte_chain structures. We really
+ * should pre-allocate these earlier in the pagefault path or come up
+ * with some other trick.
+ *
+ * Note that we cannot use the slab cache because the pte_chain structure
+ * is way smaller than the minimum size of a slab cache allocation.
+ * Caller needs to hold the zone->pte_chain_freelist_lock
+ */
+static void alloc_new_pte_chains(zone_t *zone)
+{
+	struct pte_chain * pte_chain = (void *) get_zeroed_page(GFP_ATOMIC);
+	int i = PAGE_SIZE / sizeof(struct pte_chain);
+
+	if (pte_chain) {
+		for (; i-- > 0; pte_chain++)
+			pte_chain_push(zone, pte_chain);
+	} else {
+		/* Yeah yeah, I'll fix the pte_chain allocation ... */
+		panic("Fix pte_chain allocation!\n");
+	}
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/shmem.c linux.20pre10-ac2/mm/shmem.c
--- linux.20pre10/mm/shmem.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/mm/shmem.c	2002-09-18 21:49:58.000000000 +0100
@@ -5,8 +5,25 @@
  *		 2000 Transmeta Corp.
  *		 2000-2001 Christoph Rohland
  *		 2000-2001 SAP AG
+ *		 2002 Red Hat Inc.
+ * TODO:
+ *	Accounting needs verification
+ *	We need to verify all the security fixes from generic_file_write are
+ *		now there
  * 
- * This file is released under the GPL.
+ *  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
  */
 
 /*
@@ -21,6 +38,8 @@
 #include <linux/devfs_fs_kernel.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
+#include <linux/mm_inline.h>
+#include <linux/mman.h>
 #include <linux/file.h>
 #include <linux/swap.h>
 #include <linux/pagemap.h>
@@ -54,43 +73,25 @@
 
 LIST_HEAD (shmem_inodes);
 static spinlock_t shmem_ilock = SPIN_LOCK_UNLOCKED;
-atomic_t shmem_nrpages = ATOMIC_INIT(0); /* Not used right now */
+atomic_t shmem_nrpages = ATOMIC_INIT(0);
 
 static struct page *shmem_getpage_locked(struct shmem_inode_info *, struct inode *, unsigned long);
 
-/*
- * shmem_recalc_inode - recalculate the size of an inode
- *
- * @inode: inode to recalc
- * @swap:  additional swap pages freed externally
- *
- * We have to calculate the free blocks since the mm can drop pages
- * behind our back
- *
- * But we know that normally
- * inodes->i_blocks/BLOCKS_PER_PAGE == 
- * 			inode->i_mapping->nrpages + info->swapped
- *
- * So the mm freed 
- * inodes->i_blocks/BLOCKS_PER_PAGE - 
- * 			(inode->i_mapping->nrpages + info->swapped)
- *
- * It has to be called with the spinlock held.
- */
-
-static void shmem_recalc_inode(struct inode * inode)
+static void shmem_removepage(struct page *page)
 {
-	unsigned long freed;
+	struct inode * inode;
+	struct shmem_sb_info * sbinfo;
 
-	freed = (inode->i_blocks/BLOCKS_PER_PAGE) -
-		(inode->i_mapping->nrpages + SHMEM_I(inode)->swapped);
-	if (freed){
-		struct shmem_sb_info * sbinfo = SHMEM_SB(inode->i_sb);
-		inode->i_blocks -= freed*BLOCKS_PER_PAGE;
-		spin_lock (&sbinfo->stat_lock);
-		sbinfo->free_blocks += freed;
-		spin_unlock (&sbinfo->stat_lock);
-	}
+	atomic_dec(&shmem_nrpages);
+	if (PageLaunder(page))
+		return;
+
+	inode = page->mapping->host;
+	sbinfo = SHMEM_SB(inode->i_sb);
+	inode->i_blocks -= BLOCKS_PER_PAGE;
+	spin_lock (&sbinfo->stat_lock);
+	sbinfo->free_blocks++;
+	spin_unlock (&sbinfo->stat_lock);
 }
 
 /*
@@ -320,6 +321,7 @@
 	unsigned long partial;
 	unsigned long freed = 0;
 	struct shmem_inode_info * info = SHMEM_I(inode);
+	struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
 
 	down(&info->sem);
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
@@ -352,11 +354,41 @@
 		freed += shmem_truncate_indirect(info, index);
 
 	info->swapped -= freed;
-	shmem_recalc_inode(inode);
+	inode->i_blocks -= freed*BLOCKS_PER_PAGE;
 	spin_unlock (&info->lock);
+	spin_lock (&sbinfo->stat_lock);
+	sbinfo->free_blocks += freed;
+	spin_unlock (&sbinfo->stat_lock);
 	up(&info->sem);
 }
 
+static int shmem_notify_change(struct dentry * dentry, struct iattr *attr)
+{
+	struct inode *inode = dentry->d_inode;
+	long change = 0;
+	int error;
+
+	if ((attr->ia_valid & ATTR_SIZE) && (attr->ia_size <= SHMEM_MAX_BYTES)) {
+		/*
+	 	 * Account swap file usage based on new file size,
+		 * but just let vmtruncate fail on out-of-range sizes.
+	 	 */
+		change = VM_ACCT(attr->ia_size) - VM_ACCT(inode->i_size);
+		if (change > 0) {
+			if (!vm_enough_memory(change))
+				return -ENOMEM;
+		} else
+			vm_unacct_memory(-change);
+
+	}
+	error = inode_change_ok(inode, attr);
+	if (!error)
+		error = inode_setattr(inode, attr);
+	if (error && change)
+		vm_unacct_memory(change);
+	return error;
+}
+
 static void shmem_delete_inode(struct inode * inode)
 {
 	struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
@@ -365,6 +397,7 @@
 		spin_lock (&shmem_ilock);
 		list_del (&SHMEM_I(inode)->list);
 		spin_unlock (&shmem_ilock);
+		vm_unacct_memory(VM_ACCT(inode->i_size));
 		inode->i_size = 0;
 		shmem_truncate (inode);
 	}
@@ -419,6 +452,7 @@
 	swap_free(entry);
 	ptr[offset] = (swp_entry_t) {0};
 	delete_from_swap_cache(page);
+	atomic_inc(&shmem_nrpages);
 	add_to_page_cache(page, info->inode->i_mapping, offset + idx);
 	SetPageDirty(page);
 	SetPageUptodate(page);
@@ -484,7 +518,6 @@
 	entry = shmem_swp_entry(info, index, 0);
 	if (IS_ERR(entry))	/* this had been allocated on page allocation */
 		BUG();
-	shmem_recalc_inode(inode);
 	if (entry->val)
 		BUG();
 
@@ -498,6 +531,7 @@
 		 * Raced with "speculative" read_swap_cache_async.
 		 * Add page back to page cache, unref swap, try again.
 		 */
+		atomic_inc(&shmem_nrpages);
 		add_to_page_cache_locked(page, mapping, index);
 		spin_unlock(&info->lock);
 		swap_free(swap);
@@ -555,7 +589,6 @@
 		return page;
 	}
 	
-	shmem_recalc_inode(inode);
 	if (entry->val) {
 		unsigned long flags;
 
@@ -621,6 +654,7 @@
 
 	/* We have the page */
 	SetPageUptodate(page);
+	atomic_inc(&shmem_nrpages);
 	return page;
 no_space:
 	spin_unlock (&sbinfo->stat_lock);
@@ -780,6 +814,13 @@
 static struct inode_operations shmem_symlink_inode_operations;
 static struct inode_operations shmem_symlink_inline_operations;
 
+/*
+ *	This is a copy of generic_file_write slightly modified. It would
+ *	help no end if it were kept remotely up to date with the
+ *	generic_file_write changes. I don't alas see a good way to merge
+ *	it back and use the generic one -- Alan
+ */
+ 
 static ssize_t
 shmem_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
 {
@@ -791,6 +832,7 @@
 	unsigned long	written;
 	long		status;
 	int		err;
+	loff_t		maxpos;
 
 	if ((ssize_t) count < 0)
 		return -EINVAL;
@@ -803,12 +845,12 @@
 	pos = *ppos;
 	err = -EINVAL;
 	if (pos < 0)
-		goto out;
+		goto out_nc;
 
 	err = file->f_error;
 	if (err) {
 		file->f_error = 0;
-		goto out;
+		goto out_nc;
 	}
 
 	written = 0;
@@ -816,6 +858,18 @@
 	if (file->f_flags & O_APPEND)
 		pos = inode->i_size;
 
+	maxpos = inode->i_size;
+
+	if (pos + count > inode->i_size) {
+		maxpos = pos + count;
+		if (maxpos > SHMEM_MAX_BYTES)
+			maxpos = SHMEM_MAX_BYTES;
+		if (!vm_enough_memory(VM_ACCT(maxpos) - VM_ACCT(inode->i_size))) {
+			err = -ENOMEM;
+			goto out_nc;
+		}
+	}
+
 	/*
 	 * Check whether we've reached the file size limit.
 	 */
@@ -825,21 +879,77 @@
 			send_sig(SIGXFSZ, current, 0);
 			goto out;
 		}
-		if (count > limit - pos) {
+		if (pos > 0xFFFFFFFFULL || count > limit - (u32)pos) {
+			/* send_sig(SIGXFSZ, current, 0); */
+			count = limit - (u32)pos;
+		}
+	}
+
+	/*
+	 *	LFS rule 
+	 */
+	if ( pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) {
+		if (pos >= MAX_NON_LFS) {
 			send_sig(SIGXFSZ, current, 0);
-			count = limit - pos;
+			goto out;
+		}
+		if (count > MAX_NON_LFS - (u32)pos) {
+			/* send_sig(SIGXFSZ, current, 0); */
+			count = MAX_NON_LFS - (u32)pos;
 		}
 	}
 
-	status	= 0;
-	if (count) {
-		remove_suid(inode);
-		inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+	/*
+	 *	Are we about to exceed the fs block limit ?
+	 *
+	 *	If we have written data it becomes a short write
+	 *	If we have exceeded without writing data we send
+	 *	a signal and give them an EFBIG.
+	 *
+	 *	Linus frestrict idea will clean these up nicely..
+	 */
+	 
+	if (!S_ISBLK(inode->i_mode)) {
+		if (pos >= inode->i_sb->s_maxbytes)
+		{
+			if (count || pos > inode->i_sb->s_maxbytes) {
+				send_sig(SIGXFSZ, current, 0);
+				err = -EFBIG;
+				goto out;
+			}
+			/* zero-length writes at ->s_maxbytes are OK */
+		}
+
+		if (pos + count > inode->i_sb->s_maxbytes)
+			count = inode->i_sb->s_maxbytes - pos;
+	} else {
+		if (is_read_only(inode->i_rdev)) {
+			err = -EPERM;
+			goto out;
+		}
+		if (pos >= inode->i_size) {
+			if (count || pos > inode->i_size) {
+				err = -ENOSPC;
+				goto out;
+			}
+		}
+
+		if (pos + count > inode->i_size)
+			count = inode->i_size - pos;
 	}
 
+	err = 0;
+	if (count == 0)
+		goto out;
+	status	= 0;
+
+	remove_suid(inode);
+	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+
 	while (count) {
 		unsigned long bytes, index, offset;
 		char *kaddr;
+		int deactivate = 1;
 
 		/*
 		 * Try to find the page in the cache. If it isn't there,
@@ -850,6 +960,7 @@
 		bytes = PAGE_CACHE_SIZE - offset;
 		if (bytes > count) {
 			bytes = count;
+			deactivate = 0;
 		}
 
 		/*
@@ -878,7 +989,7 @@
 		}
 
 		kaddr = kmap(page);
-		status = copy_from_user(kaddr+offset, buf, bytes);
+		status = __copy_from_user(kaddr+offset, buf, bytes);
 		kunmap(page);
 		if (status)
 			goto fail_write;
@@ -896,6 +1007,10 @@
 unlock:
 		/* Mark it unlocked again and drop the page.. */
 		UnlockPage(page);
+		if (deactivate)
+			deactivate_page(page);
+		else
+			mark_page_accessed(page);
 		page_cache_release(page);
 
 		if (status < 0)
@@ -905,6 +1020,10 @@
 
 	err = written ? written : status;
 out:
+	/* Short writes give back address space */
+	if (inode->i_size != maxpos)
+		vm_unacct_memory(VM_ACCT(maxpos) - VM_ACCT(inode->i_size));
+out_nc:
 	up(&inode->i_sem);
 	return err;
 fail_write:
@@ -1177,10 +1296,15 @@
 		memcpy(info, symname, len);
 		inode->i_op = &shmem_symlink_inline_operations;
 	} else {
+		if (!vm_enough_memory(VM_ACCT(1))) {
+			iput(inode);
+			return -ENOMEM;
+		}
 		down(&info->sem);
 		page = shmem_getpage_locked(info, inode, 0);
 		if (IS_ERR(page)) {
 			up(&info->sem);
+			vm_unacct_memory(VM_ACCT(1));
 			iput(inode);
 			return PTR_ERR(page);
 		}
@@ -1383,6 +1507,7 @@
 
 
 static struct address_space_operations shmem_aops = {
+	removepage:	shmem_removepage,
 	writepage:	shmem_writepage,
 };
 
@@ -1397,6 +1522,7 @@
 
 static struct inode_operations shmem_inode_operations = {
 	truncate:	shmem_truncate,
+	setattr:	shmem_notify_change,
 };
 
 static struct inode_operations shmem_dir_inode_operations = {
@@ -1492,7 +1618,6 @@
 	struct inode * inode;
 	struct dentry *dentry, *root;
 	struct qstr this;
-	int vm_enough_memory(long pages);
 
 	if (size > SHMEM_MAX_BYTES)
 		return ERR_PTR(-EINVAL);
@@ -1500,13 +1625,14 @@
 	if (!vm_enough_memory(VM_ACCT(size)))
 		return ERR_PTR(-ENOMEM);
 
+	error = -ENOMEM;
 	this.name = name;
 	this.len = strlen(name);
 	this.hash = 0; /* will go */
 	root = shm_mnt->mnt_root;
 	dentry = d_alloc(root, &this);
 	if (!dentry)
-		return ERR_PTR(-ENOMEM);
+		goto put_memory;
 
 	error = -ENFILE;
 	file = get_empty_filp();
@@ -1531,6 +1657,8 @@
 	put_filp(file);
 put_dentry:
 	dput (dentry);
+put_memory:
+	vm_unacct_memory(VM_ACCT(size));
 	return ERR_PTR(error);	
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/swap.c linux.20pre10-ac2/mm/swap.c
--- linux.20pre10/mm/swap.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/mm/swap.c	2002-08-06 15:41:52.000000000 +0100
@@ -15,10 +15,10 @@
 
 #include <linux/mm.h>
 #include <linux/kernel_stat.h>
-#include <linux/swap.h>
 #include <linux/swapctl.h>
 #include <linux/pagemap.h>
 #include <linux/init.h>
+#include <linux/mm_inline.h>
 
 #include <asm/dma.h>
 #include <asm/uaccess.h> /* for copy_to/from_user */
@@ -33,15 +33,97 @@
 	8,	/* do swap I/O in clusters of this size */
 };
 
+/**
+ * (de)activate_page - move pages from/to active and inactive lists
+ * @page: the page we want to move
+ * @nolock - are we already holding the pagemap_lru_lock?
+ *
+ * Deactivate_page will move an active page to the right
+ * inactive list, while activate_page will move a page back
+ * from one of the inactive lists to the active list. If
+ * called on a page which is not on any of the lists, the
+ * page is left alone.
+ */
+void deactivate_page_nolock(struct page * page)
+{
+	/*
+	 * Don't touch it if it's not on the active list.
+	 * (some pages aren't on any list at all)
+	 */
+	ClearPageReferenced(page);
+	page->age = 0;
+	if (PageActive(page)) {
+		del_page_from_active_list(page);
+		add_page_to_inactive_dirty_list(page);
+	}
+}	
+
+void deactivate_page(struct page * page)
+{
+	spin_lock(&pagemap_lru_lock);
+	deactivate_page_nolock(page);
+	spin_unlock(&pagemap_lru_lock);
+}
+
+/**
+ * drop_page - like deactivate_page, but try inactive_clean list
+ * @page: the page to drop
+ *
+ * Try to move a page to the inactive_clean list, this succeeds if the
+ * page is clean and not in use by anybody. If the page cannot be placed
+ * on the inactive_clean list it is placed on the inactive_dirty list
+ * instead.
+ *
+ * Note: this function gets called with the pagemap_lru_lock held.
+ */
+void drop_page(struct page * page)
+{
+	if (!TryLockPage(page)) {
+		if (page->mapping && page->buffers) {
+			page_cache_get(page);
+			spin_unlock(&pagemap_lru_lock);
+			try_to_release_page(page, GFP_NOIO);
+			spin_lock(&pagemap_lru_lock);
+			page_cache_release(page);
+		}
+		UnlockPage(page);
+	}
+
+	/* Make sure the page really is reclaimable. */
+	pte_chain_lock(page);
+	if (!page->mapping || PageDirty(page) || page->pte_chain ||
+			page->buffers || page_count(page) > 1)
+		deactivate_page_nolock(page);
+
+	else if (page_count(page) == 1) {
+		ClearPageReferenced(page);
+		page->age = 0;
+		if (PageActive(page)) {
+			del_page_from_active_list(page);
+			add_page_to_inactive_clean_list(page);
+		} else if (PageInactiveDirty(page)) {
+			del_page_from_inactive_dirty_list(page);
+			add_page_to_inactive_clean_list(page);
+		}
+	}
+	pte_chain_unlock(page);
+}
+
 /*
  * Move an inactive page to the active list.
  */
-static inline void activate_page_nolock(struct page * page)
+void activate_page_nolock(struct page * page)
 {
-	if (PageLRU(page) && !PageActive(page)) {
-		del_page_from_inactive_list(page);
+	if (PageInactiveDirty(page)) {
+		del_page_from_inactive_dirty_list(page);
+		add_page_to_active_list(page);
+	} else if (PageInactiveClean(page)) {
+		del_page_from_inactive_clean_list(page);
 		add_page_to_active_list(page);
 	}
+
+	/* Make sure the page gets a fair chance at staying active. */
+	page->age = max((int)page->age, PAGE_AGE_START);
 }
 
 void activate_page(struct page * page)
@@ -59,8 +141,8 @@
 {
 	if (!PageLRU(page)) {
 		spin_lock(&pagemap_lru_lock);
-		if (!TestSetPageLRU(page))
-			add_page_to_inactive_list(page);
+		SetPageLRU(page);
+		add_page_to_active_list(page);
 		spin_unlock(&pagemap_lru_lock);
 	}
 }
@@ -74,13 +156,14 @@
  */
 void __lru_cache_del(struct page * page)
 {
-	if (TestClearPageLRU(page)) {
-		if (PageActive(page)) {
-			del_page_from_active_list(page);
-		} else {
-			del_page_from_inactive_list(page);
-		}
+	if (PageActive(page)) {
+		del_page_from_active_list(page);
+	} else if (PageInactiveDirty(page)) {
+		del_page_from_inactive_dirty_list(page);
+	} else if (PageInactiveClean(page)) {
+		del_page_from_inactive_clean_list(page);
 	}
+	ClearPageLRU(page);
 }
 
 /**
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/swapfile.c linux.20pre10-ac2/mm/swapfile.c
--- linux.20pre10/mm/swapfile.c	2002-10-09 21:36:36.000000000 +0100
+++ linux.20pre10-ac2/mm/swapfile.c	2002-08-06 15:41:52.000000000 +0100
@@ -373,6 +373,7 @@
 		return;
 	get_page(page);
 	set_pte(dir, pte_mkold(mk_pte(page, vma->vm_page_prot)));
+	page_add_rmap(page, dir);
 	swap_free(entry);
 	++vma->vm_mm->rss;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/swap_state.c linux.20pre10-ac2/mm/swap_state.c
--- linux.20pre10/mm/swap_state.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/mm/swap_state.c	2002-08-15 02:28:34.000000000 +0100
@@ -89,6 +89,40 @@
 	return 0;
 }
 
+/**
+ * add_to_swap - allocate swap space for a page
+ * @page: page we want to move to swap
+ *
+ * Allocate swap space for the page and add the page to the
+ * swap cache.  Caller needs to hold the page lock.
+ */
+int add_to_swap(struct page * page)
+{
+	swp_entry_t entry;
+
+	if (!PageLocked(page))
+		BUG();
+
+	for (;;) {
+		entry = get_swap_page();
+		if (!entry.val)
+			return 0;
+		/*
+		 * Add it to the swap cache and mark it dirty
+		 * (adding to the page cache will clear the dirty
+		 * and uptodate bits, so we need to do it again)
+		 */
+		if (add_to_swap_cache(page, entry) == 0) {
+			SetPageUptodate(page);
+			set_page_dirty(page);
+			swap_free(entry);
+			return 1;
+		}
+		/* Raced with "speculative" read_swap_cache_async */
+		swap_free(entry);
+	}
+}
+
 /*
  * This must be called only on pages that have
  * been verified to be in the swap cache.
@@ -118,7 +152,7 @@
 		BUG();
 
 	if (unlikely(!block_flushpage(page, 0)))
-		BUG();	/* an anonymous page cannot have page->buffers set */
+		PAGE_BUG(page);	/* an anonymous page cannot have page->buffers set */
 
 	entry.val = page->index;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/vmalloc.c linux.20pre10-ac2/mm/vmalloc.c
--- linux.20pre10/mm/vmalloc.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/mm/vmalloc.c	2002-09-30 21:09:14.000000000 +0100
@@ -176,9 +176,13 @@
 	area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
 	if (!area)
 		return NULL;
+
 	size += PAGE_SIZE;
-	if(!size)
+	if (!size) {
+		kfree (area);
 		return NULL;
+	}
+
 	addr = VMALLOC_START;
 	write_lock(&vmlist_lock);
 	for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
@@ -323,3 +327,22 @@
 	read_unlock(&vmlist_lock);
 	return buf - buf_start;
 }
+
+void *vcalloc(unsigned long nmemb, unsigned long elem_size)
+{
+	unsigned long size;
+	void *addr;
+
+	/*
+	 * Check that we're not going to overflow.
+	 */
+	if (nmemb > (ULONG_MAX / elem_size))
+		return NULL;
+
+	size = nmemb * elem_size;
+	addr = vmalloc(size);
+	if (addr)
+		memset(addr, 0, size);
+
+	return addr;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/mm/vmscan.c linux.20pre10-ac2/mm/vmscan.c
--- linux.20pre10/mm/vmscan.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/mm/vmscan.c	2002-09-29 20:03:17.000000000 +0100
@@ -23,9 +23,12 @@
 #include <linux/init.h>
 #include <linux/highmem.h>
 #include <linux/file.h>
+#include <linux/mm_inline.h>
 
 #include <asm/pgalloc.h>
 
+static void refill_freelist(void);
+static void wakeup_memwaiters(void);
 /*
  * The "priority" of VM scanning is how much of the queues we
  * will scan in one go. A value of 6 for DEF_PRIORITY implies
@@ -34,368 +37,322 @@
  */
 #define DEF_PRIORITY (6)
 
-/*
- * The swap-out function returns 1 if it successfully
- * scanned all the pages it was asked to (`count').
- * It returns zero if it couldn't do anything,
- *
- * rss may decrease because pages are shared, but this
- * doesn't count as having freed a page.
- */
+static inline void age_page_up(struct page *page)
+{
+	page->age = min((int) (page->age + PAGE_AGE_ADV), PAGE_AGE_MAX); 
+}
 
-/* mm->page_table_lock is held. mmap_sem is not held */
-static inline int try_to_swap_out(struct mm_struct * mm, struct vm_area_struct* vma, unsigned long address, pte_t * page_table, struct page *page, zone_t * classzone)
+static inline void age_page_down(struct page *page)
 {
-	pte_t pte;
-	swp_entry_t entry;
+	page->age -= min(PAGE_AGE_DECL, (int)page->age);
+}
 
-	/* Don't look at this pte if it's been accessed recently. */
-	if ((vma->vm_flags & VM_LOCKED) || ptep_test_and_clear_young(page_table)) {
-		mark_page_accessed(page);
-		return 0;
-	}
+/* Must be called with page's pte_chain_lock held. */
+static inline int page_mapping_inuse(struct page * page)
+{
+	struct address_space * mapping = page->mapping;
 
-	/* Don't bother unmapping pages that are active */
-	if (PageActive(page))
-		return 0;
+	/* Page is in somebody's page tables. */
+	if (page->pte_chain)
+		return 1;
 
-	/* Don't bother replenishing zones not under pressure.. */
-	if (!memclass(page_zone(page), classzone))
+	/* XXX: does this happen ? */
+	if (!mapping)
 		return 0;
 
-	if (TryLockPage(page))
-		return 0;
+	/* File is mmaped by somebody. */
+	if (mapping->i_mmap || mapping->i_mmap_shared)
+		return 1;
 
-	/* From this point on, the odds are that we're going to
-	 * nuke this pte, so read and clear the pte.  This hook
-	 * is needed on CPUs which update the accessed and dirty
-	 * bits in hardware.
-	 */
-	flush_cache_page(vma, address);
-	pte = ptep_get_and_clear(page_table);
-	flush_tlb_page(vma, address);
+	return 0;
+}
 
-	if (pte_dirty(pte))
-		set_page_dirty(page);
+/**
+ * reclaim_page - reclaims one page from the inactive_clean list
+ * @zone: reclaim a page from this zone
+ *
+ * The pages on the inactive_clean can be instantly reclaimed.
+ * The tests look impressive, but most of the time we'll grab
+ * the first page of the list and exit successfully.
+ */
+struct page * reclaim_page(zone_t * zone)
+{
+	struct page * page = NULL;
+	struct list_head * page_lru;
+	swp_entry_t entry = {0};
+	int maxscan;
 
 	/*
-	 * Is the page already in the swap cache? If so, then
-	 * we can just drop our reference to it without doing
-	 * any IO - it's already up-to-date on disk.
+	 * We need to hold the pagecache_lock around all tests to make sure
+	 * reclaim_page() cannot race with find_get_page() and friends.
 	 */
-	if (PageSwapCache(page)) {
-		entry.val = page->index;
-		swap_duplicate(entry);
-set_swap_pte:
-		set_pte(page_table, swp_entry_to_pte(entry));
-drop_pte:
-		mm->rss--;
-		UnlockPage(page);
-		{
-			int freeable = page_count(page) - !!page->buffers <= 2;
-			page_cache_release(page);
-			return freeable;
+	spin_lock(&pagemap_lru_lock);
+	spin_lock(&pagecache_lock);
+	maxscan = zone->inactive_clean_pages;
+	while (maxscan-- && !list_empty(&zone->inactive_clean_list)) {
+		page_lru = zone->inactive_clean_list.prev;
+		page = list_entry(page_lru, struct page, lru);
+
+		/* Wrong page on list?! (list corruption, should not happen) */
+		if (unlikely(!PageInactiveClean(page))) {
+			printk("VM: reclaim_page, wrong page on list.\n");
+			list_del(page_lru);
+			page_zone(page)->inactive_clean_pages--;
+			continue;
 		}
-	}
-
-	/*
-	 * Is it a clean page? Then it must be recoverable
-	 * by just paging it in again, and we can just drop
-	 * it..  or if it's dirty but has backing store,
-	 * just mark the page dirty and drop it.
-	 *
-	 * However, this won't actually free any real
-	 * memory, as the page will just be in the page cache
-	 * somewhere, and as such we should just continue
-	 * our scan.
-	 *
-	 * Basically, this just makes it possible for us to do
-	 * some real work in the future in "refill_inactive()".
-	 */
-	if (page->mapping)
-		goto drop_pte;
-	if (!PageDirty(page))
-		goto drop_pte;
-
-	/*
-	 * Anonymous buffercache pages can be left behind by
-	 * concurrent truncate and pagefault.
-	 */
-	if (page->buffers)
-		goto preserve;
 
-	/*
-	 * This is a dirty, swappable page.  First of all,
-	 * get a suitable swap entry for it, and make sure
-	 * we have the swap cache set up to associate the
-	 * page with that swap entry.
-	 */
-	for (;;) {
-		entry = get_swap_page();
-		if (!entry.val)
-			break;
-		/* Add it to the swap cache and mark it dirty
-		 * (adding to the page cache will clear the dirty
-		 * and uptodate bits, so we need to do it again)
-		 */
-		if (add_to_swap_cache(page, entry) == 0) {
-			SetPageUptodate(page);
-			set_page_dirty(page);
-			goto set_swap_pte;
+		/* Page is being freed */
+		if (unlikely(page_count(page)) == 0) {
+			list_del(page_lru);
+			list_add(page_lru, &zone->inactive_clean_list);
+			continue;
 		}
-		/* Raced with "speculative" read_swap_cache_async */
-		swap_free(entry);
-	}
 
-	/* No swap space left */
-preserve:
-	set_pte(page_table, pte);
-	UnlockPage(page);
-	return 0;
-}
-
-/* mm->page_table_lock is held. mmap_sem is not held */
-static inline int swap_out_pmd(struct mm_struct * mm, struct vm_area_struct * vma, pmd_t *dir, unsigned long address, unsigned long end, int count, zone_t * classzone)
-{
-	pte_t * pte;
-	unsigned long pmd_end;
-
-	if (pmd_none(*dir))
-		return count;
-	if (pmd_bad(*dir)) {
-		pmd_ERROR(*dir);
-		pmd_clear(dir);
-		return count;
-	}
-	
-	pte = pte_offset(dir, address);
-	
-	pmd_end = (address + PMD_SIZE) & PMD_MASK;
-	if (end > pmd_end)
-		end = pmd_end;
+		/* Page cannot be reclaimed ?  Move to inactive_dirty list. */
+		pte_chain_lock(page);
+		if (unlikely(page->pte_chain || page->buffers ||
+				PageReferenced(page) || PageDirty(page) ||
+				page_count(page) > 1 || TryLockPage(page))) {
+			del_page_from_inactive_clean_list(page);
+			add_page_to_inactive_dirty_list(page);
+			pte_chain_unlock(page);
+			continue;
+		}
 
-	do {
-		if (pte_present(*pte)) {
-			struct page *page = pte_page(*pte);
+		/*
+		 * From here until reaching either the bottom of the loop
+		 * or found_page: the pte_chain_lock is held.
+		 */
 
-			if (VALID_PAGE(page) && !PageReserved(page)) {
-				count -= try_to_swap_out(mm, vma, address, pte, page, classzone);
-				if (!count) {
-					address += PAGE_SIZE;
-					break;
-				}
-			}
+		/* OK, remove the page from the caches. */
+                if (PageSwapCache(page)) {
+			entry.val = page->index;
+			__delete_from_swap_cache(page);
+			goto found_page;
 		}
-		address += PAGE_SIZE;
-		pte++;
-	} while (address && (address < end));
-	mm->swap_address = address;
-	return count;
-}
 
-/* mm->page_table_lock is held. mmap_sem is not held */
-static inline int swap_out_pgd(struct mm_struct * mm, struct vm_area_struct * vma, pgd_t *dir, unsigned long address, unsigned long end, int count, zone_t * classzone)
-{
-	pmd_t * pmd;
-	unsigned long pgd_end;
+		if (page->mapping) {
+			__remove_inode_page(page);
+			goto found_page;
+		}
 
-	if (pgd_none(*dir))
-		return count;
-	if (pgd_bad(*dir)) {
-		pgd_ERROR(*dir);
-		pgd_clear(dir);
-		return count;
+		/* We should never ever get here. */
+		printk(KERN_ERR "VM: reclaim_page, found unknown page\n");
+		list_del(page_lru);
+		zone->inactive_clean_pages--;
+		pte_chain_unlock(page);
+		UnlockPage(page);
 	}
+	spin_unlock(&pagecache_lock);
+	spin_unlock(&pagemap_lru_lock);
+	return NULL;
 
-	pmd = pmd_offset(dir, address);
-
-	pgd_end = (address + PGDIR_SIZE) & PGDIR_MASK;	
-	if (pgd_end && (end > pgd_end))
-		end = pgd_end;
-	
-	do {
-		count = swap_out_pmd(mm, vma, pmd, address, end, count, classzone);
-		if (!count)
-			break;
-		address = (address + PMD_SIZE) & PMD_MASK;
-		pmd++;
-	} while (address && (address < end));
-	return count;
-}
-
-/* mm->page_table_lock is held. mmap_sem is not held */
-static inline int swap_out_vma(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long address, int count, zone_t * classzone)
-{
-	pgd_t *pgdir;
-	unsigned long end;
-
-	/* Don't swap out areas which are reserved */
-	if (vma->vm_flags & VM_RESERVED)
-		return count;
-
-	pgdir = pgd_offset(mm, address);
 
-	end = vma->vm_end;
-	BUG_ON(address >= end);
-	do {
-		count = swap_out_pgd(mm, vma, pgdir, address, end, count, classzone);
-		if (!count)
-			break;
-		address = (address + PGDIR_SIZE) & PGDIR_MASK;
-		pgdir++;
-	} while (address && (address < end));
-	return count;
+found_page:
+	__lru_cache_del(page);
+	pte_chain_unlock(page);
+	spin_unlock(&pagecache_lock);
+	spin_unlock(&pagemap_lru_lock);
+	if (entry.val)
+		swap_free(entry);
+	UnlockPage(page);
+	page->age = PAGE_AGE_START;
+	if (page_count(page) != 1)
+		printk("VM: reclaim_page, found page with count %d!\n",
+				page_count(page));
+	return page;
 }
 
-/* Placeholder for swap_out(): may be updated by fork.c:mmput() */
-struct mm_struct *swap_mm = &init_mm;
-
-/*
- * Returns remaining count of pages to be swapped out by followup call.
+/**
+ * page_dirty - do we need to write the data out to disk
+ * @page: page to test
+ *
+ * Returns true if the page contains data which needs to
+ * be written to disk.  Doesn't test the page tables (yet?).
  */
-static inline int swap_out_mm(struct mm_struct * mm, int count, int * mmcounter, zone_t * classzone)
+static inline int page_dirty(struct page *page)
 {
-	unsigned long address;
-	struct vm_area_struct* vma;
+	struct buffer_head *tmp, *bh;
 
-	/*
-	 * Find the proper vm-area after freezing the vma chain 
-	 * and ptes.
-	 */
-	spin_lock(&mm->page_table_lock);
-	address = mm->swap_address;
-	if (address == TASK_SIZE || swap_mm != mm) {
-		/* We raced: don't count this mm but try again */
-		++*mmcounter;
-		goto out_unlock;
-	}
-	vma = find_vma(mm, address);
-	if (vma) {
-		if (address < vma->vm_start)
-			address = vma->vm_start;
-
-		for (;;) {
-			count = swap_out_vma(mm, vma, address, count, classzone);
-			vma = vma->vm_next;
-			if (!vma)
-				break;
-			if (!count)
-				goto out_unlock;
-			address = vma->vm_start;
-		}
-	}
-	/* Indicate that we reached the end of address space */
-	mm->swap_address = TASK_SIZE;
+	if (PageDirty(page))
+		return 1;
 
-out_unlock:
-	spin_unlock(&mm->page_table_lock);
-	return count;
-}
+	if (page->mapping && !page->buffers)
+		return 0;
 
-static int FASTCALL(swap_out(unsigned int priority, unsigned int gfp_mask, zone_t * classzone));
-static int swap_out(unsigned int priority, unsigned int gfp_mask, zone_t * classzone)
-{
-	int counter, nr_pages = SWAP_CLUSTER_MAX;
-	struct mm_struct *mm;
+	tmp = bh = page->buffers;
 
-	counter = mmlist_nr;
 	do {
-		if (unlikely(current->need_resched)) {
-			__set_current_state(TASK_RUNNING);
-			schedule();
-		}
-
-		spin_lock(&mmlist_lock);
-		mm = swap_mm;
-		while (mm->swap_address == TASK_SIZE || mm == &init_mm) {
-			mm->swap_address = 0;
-			mm = list_entry(mm->mmlist.next, struct mm_struct, mmlist);
-			if (mm == swap_mm)
-				goto empty;
-			swap_mm = mm;
-		}
-
-		/* Make sure the mm doesn't disappear when we drop the lock.. */
-		atomic_inc(&mm->mm_users);
-		spin_unlock(&mmlist_lock);
-
-		nr_pages = swap_out_mm(mm, nr_pages, &counter, classzone);
-
-		mmput(mm);
-
-		if (!nr_pages)
+		if (tmp->b_state & ((1<<BH_Dirty) | (1<<BH_Lock)))
 			return 1;
-	} while (--counter >= 0);
-
-	return 0;
+		tmp = tmp->b_this_page;
+	} while (tmp != bh);
 
-empty:
-	spin_unlock(&mmlist_lock);
 	return 0;
 }
 
-static int FASTCALL(shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask, int priority));
-static int shrink_cache(int nr_pages, zone_t * classzone, unsigned int gfp_mask, int priority)
+/**
+ * page_launder_zone - clean dirty inactive pages, move to inactive_clean list
+ * @zone: zone to free pages in
+ * @gfp_mask: what operations we are allowed to do
+ * @full_flush: full-out page flushing, if we couldn't get enough clean pages
+ *
+ * This function is called when we are low on free / inactive_clean
+ * pages, its purpose is to refill the free/clean list as efficiently
+ * as possible.
+ *
+ * This means we do writes asynchronously as long as possible and will
+ * only sleep on IO when we don't have another option. Since writeouts
+ * cause disk seeks and make read IO slower, we skip writes alltogether
+ * when the amount of dirty pages is small.
+ *
+ * This code is heavily inspired by the FreeBSD source code. Thanks
+ * go out to Matthew Dillon.
+ */
+int page_launder_zone(zone_t * zone, int gfp_mask, int full_flush)
 {
-	struct list_head * entry;
-	int max_scan = nr_inactive_pages / priority;
-	int max_mapped = min((nr_pages << (10 - priority)), max_scan / 10);
+	int maxscan, cleaned_pages, target, maxlaunder, iopages;
+	struct list_head * entry, * next;
 
+	target = max(free_plenty(zone), zone->pages_min);
+	cleaned_pages = iopages = 0;
+
+	/* If we can get away with it, only flush 2 MB worth of dirty pages */
+	if (full_flush)
+		maxlaunder = 1000000;
+	else {
+		maxlaunder = min_t(int, 512, zone->inactive_dirty_pages / 4);
+		maxlaunder = max(maxlaunder, free_plenty(zone) * 4);
+	}
+	
+	/* The main launder loop. */
 	spin_lock(&pagemap_lru_lock);
-	while (--max_scan >= 0 && (entry = inactive_list.prev) != &inactive_list) {
+rescan:
+	maxscan = zone->inactive_dirty_pages;
+	entry = zone->inactive_dirty_list.prev;
+	next = entry->prev;
+	while (maxscan-- && !list_empty(&zone->inactive_dirty_list) &&
+			next != &zone->inactive_dirty_list) {
 		struct page * page;
-
-		if (unlikely(current->need_resched)) {
+		
+		/* Low latency reschedule point */
+		if (current->need_resched) {
 			spin_unlock(&pagemap_lru_lock);
-			__set_current_state(TASK_RUNNING);
 			schedule();
 			spin_lock(&pagemap_lru_lock);
 			continue;
 		}
 
+		entry = next;
+		next = entry->prev;
 		page = list_entry(entry, struct page, lru);
 
-		BUG_ON(!PageLRU(page));
-		BUG_ON(PageActive(page));
+		/* This page was removed while we looked the other way. */
+		if (!PageInactiveDirty(page))
+			goto rescan;
+
+		if (cleaned_pages > target)
+			break;
 
-		list_del(entry);
-		list_add(entry, &inactive_list);
+		/* Stop doing IO if we've laundered too many pages already. */
+		if (maxlaunder < 0)
+			gfp_mask &= ~(__GFP_IO|__GFP_FS);
+
+		/* Wrong page on list?! (list corruption, should not happen) */
+		if (!PageInactiveDirty(page)) {
+			printk("VM: page_launder, wrong page on list.\n");
+			list_del(entry);
+			nr_inactive_dirty_pages--;
+			page_zone(page)->inactive_dirty_pages--;
+			continue;
+		}
 
 		/*
-		 * Zero page counts can happen because we unlink the pages
-		 * _after_ decrementing the usage count..
+		 * Page is being freed, don't worry about it.
 		 */
-		if (unlikely(!page_count(page)))
+		if (unlikely(page_count(page)) == 0)
 			continue;
 
-		if (!memclass(page_zone(page), classzone))
+		/*
+		 * The page is locked. IO in progress?
+		 * Acquire PG_locked early in order to safely
+		 * access page->mapping.
+		 */
+		if (unlikely(TryLockPage(page))) {
+			iopages++;
 			continue;
+		}
 
-		/* Racy check to avoid trylocking when not worthwhile */
-		if (!page->buffers && (page_count(page) != 1 || !page->mapping))
-			goto page_mapped;
+		/*
+		 * The page is in active use or really unfreeable. Move to
+		 * the active list and adjust the page age if needed.
+		 */
+		pte_chain_lock(page);
+		if (page_referenced(page) && page_mapping_inuse(page) &&
+				!page_over_rsslimit(page)) {
+			del_page_from_inactive_dirty_list(page);
+			add_page_to_active_list(page);
+			page->age = max((int)page->age, PAGE_AGE_START);
+			pte_chain_unlock(page);
+			UnlockPage(page);
+			continue;
+		}
 
 		/*
-		 * The page is locked. IO in progress?
-		 * Move it to the back of the list.
+		 * Anonymous process memory without backing store. Try to
+		 * allocate it some swap space here.
+		 *
+		 * XXX: implement swap clustering ?
 		 */
-		if (unlikely(TryLockPage(page))) {
-			if (PageLaunder(page) && (gfp_mask & __GFP_FS)) {
-				page_cache_get(page);
-				spin_unlock(&pagemap_lru_lock);
-				wait_on_page(page);
+		if (page->pte_chain && !page->mapping && !page->buffers) {
+			/* Don't bother if we can't swap it out now. */
+			if (maxlaunder < 0) {
+				pte_chain_unlock(page);
+				UnlockPage(page);
+				list_del(entry);
+				list_add(entry, &zone->inactive_dirty_list);
+				continue;
+			}
+			page_cache_get(page);
+			pte_chain_unlock(page);
+			spin_unlock(&pagemap_lru_lock);
+			if (!add_to_swap(page)) {
+				activate_page(page);
+				UnlockPage(page);
 				page_cache_release(page);
 				spin_lock(&pagemap_lru_lock);
+				continue;
+			}
+			page_cache_release(page);
+			spin_lock(&pagemap_lru_lock);
+			pte_chain_lock(page);
+		}
+
+		/*
+		 * The page is mapped into the page tables of one or more
+		 * processes. Try to unmap it here.
+		 */
+		if (page->pte_chain && page->mapping) {
+			switch (try_to_unmap(page)) {
+				case SWAP_ERROR:
+				case SWAP_FAIL:
+					goto page_active;
+				case SWAP_AGAIN:
+					pte_chain_unlock(page);
+					UnlockPage(page);
+					continue;
+				case SWAP_SUCCESS:
+					; /* try to free the page below */
 			}
-			continue;
 		}
+		pte_chain_unlock(page);
 
-		if (PageDirty(page) && is_page_cache_freeable(page) && page->mapping) {
+		if (PageDirty(page) && page->mapping) {
 			/*
 			 * It is not critical here to write it only if
 			 * the page is unmapped beause any direct writer
 			 * like O_DIRECT would set the PG_dirty bitflag
-			 * on the phisical page after having successfully
+			 * on the physical page after having successfully
 			 * pinned it and after the I/O to the page is finished,
 			 * so the direct writes to the page cannot get lost.
 			 */
@@ -409,10 +366,17 @@
 				spin_unlock(&pagemap_lru_lock);
 
 				writepage(page);
+				maxlaunder--;
+				iopages++;
 				page_cache_release(page);
 
 				spin_lock(&pagemap_lru_lock);
 				continue;
+			} else {
+				UnlockPage(page);
+				list_del(entry);
+				list_add(entry, &zone->inactive_dirty_list);
+				continue;
 			}
 		}
 
@@ -422,11 +386,11 @@
 		 * the page as well.
 		 */
 		if (page->buffers) {
-			spin_unlock(&pagemap_lru_lock);
-
-			/* avoid to free a locked page */
+			/* To avoid freeing our page before we're done. */
 			page_cache_get(page);
 
+			spin_unlock(&pagemap_lru_lock);
+
 			if (try_to_release_page(page, gfp_mask)) {
 				if (!page->mapping) {
 					/*
@@ -442,266 +406,324 @@
 					/* effectively free the page here */
 					page_cache_release(page);
 
-					if (--nr_pages)
-						continue;
-					break;
+					cleaned_pages++;
+					continue;
 				} else {
 					/*
-					 * The page is still in pagecache so undo the stuff
-					 * before the try_to_release_page since we've not
-					 * finished and we can now try the next step.
+					 * We freed the buffers but may have
+					 * slept; undo the stuff we did before
+					 * try_to_release_page and fall through
+					 * to the next step.
+					 * But only if the page is still on the inact. dirty 
+					 * list.
 					 */
-					page_cache_release(page);
 
 					spin_lock(&pagemap_lru_lock);
+					/* Check if the page was removed from the list
+					 * while we looked the other way. 
+					 */
+					if (!PageInactiveDirty(page)) {
+						page_cache_release(page);
+						continue;
+					}
+					page_cache_release(page);
 				}
 			} else {
 				/* failed to drop the buffers so stop here */
 				UnlockPage(page);
 				page_cache_release(page);
+				maxlaunder--;
+				iopages++;
 
 				spin_lock(&pagemap_lru_lock);
 				continue;
 			}
 		}
 
-		spin_lock(&pagecache_lock);
 
 		/*
-		 * this is the non-racy check for busy page.
+		 * If the page is really freeable now, move it to the
+		 * inactive_clean list.
+		 *
+		 * We re-test everything since the page could have been
+		 * used by somebody else while we waited on IO above.
+		 * This test is not safe from races, but only the one
+		 * in reclaim_page() needs to be.
 		 */
-		if (!page->mapping || !is_page_cache_freeable(page)) {
-			spin_unlock(&pagecache_lock);
+		pte_chain_lock(page);
+		if (page->mapping && !PageDirty(page) && !page->pte_chain &&
+				page_count(page) == 1) {
+			del_page_from_inactive_dirty_list(page);
+			add_page_to_inactive_clean_list(page);
+			pte_chain_unlock(page);
 			UnlockPage(page);
-page_mapped:
-			if (--max_mapped >= 0)
-				continue;
-
+			cleaned_pages++;
+		} else {
 			/*
-			 * Alert! We've found too many mapped pages on the
-			 * inactive list, so we start swapping out now!
+			 * OK, we don't know what to do with the page.
+			 * It's no use keeping it here, so we move it to
+			 * the active list.
 			 */
-			spin_unlock(&pagemap_lru_lock);
-			swap_out(priority, gfp_mask, classzone);
-			return nr_pages;
-		}
-
-		/*
-		 * It is critical to check PageDirty _after_ we made sure
-		 * the page is freeable* so not in use by anybody.
-		 */
-		if (PageDirty(page)) {
-			spin_unlock(&pagecache_lock);
+page_active:
+			del_page_from_inactive_dirty_list(page);
+			add_page_to_active_list(page);
+			pte_chain_unlock(page);
 			UnlockPage(page);
-			continue;
 		}
-
-		/* point of no return */
-		if (likely(!PageSwapCache(page))) {
-			__remove_inode_page(page);
-			spin_unlock(&pagecache_lock);
-		} else {
-			swp_entry_t swap;
-			swap.val = page->index;
-			__delete_from_swap_cache(page);
-			spin_unlock(&pagecache_lock);
-			swap_free(swap);
-		}
-
-		__lru_cache_del(page);
-		UnlockPage(page);
-
-		/* effectively free the page here */
-		page_cache_release(page);
-
-		if (--nr_pages)
-			continue;
-		break;
 	}
 	spin_unlock(&pagemap_lru_lock);
 
-	return nr_pages;
+	/* Return the number of pages moved to the inactive_clean list. */
+	return cleaned_pages + iopages;
 }
 
-/*
- * This moves pages from the active list to
- * the inactive list.
+/**
+ * page_launder - clean dirty inactive pages, move to inactive_clean list
+ * @gfp_mask: what operations we are allowed to do
  *
- * We move them the other way when we see the
- * reference bit on the page.
+ * This function iterates over all zones and calls page_launder_zone(),
+ * balancing still needs to be added...
  */
-static void refill_inactive(int nr_pages)
+int page_launder(int gfp_mask)
 {
-	struct list_head * entry;
+	struct zone_struct * zone;
+	int freed = 0;
 
-	spin_lock(&pagemap_lru_lock);
-	entry = active_list.prev;
-	while (nr_pages && entry != &active_list) {
-		struct page * page;
-
-		page = list_entry(entry, struct page, lru);
-		entry = entry->prev;
-		if (PageTestandClearReferenced(page)) {
-			list_del(&page->lru);
-			list_add(&page->lru, &active_list);
-			continue;
+	/* Global balancing while we have a global shortage. */
+	if (free_high(ALL_ZONES) >= 0)
+		for_each_zone(zone)
+			if (free_plenty(zone) >= 0)
+				freed += page_launder_zone(zone, gfp_mask, 0);
+	
+	/* Clean up the remaining zones with a serious shortage, if any. */
+	for_each_zone(zone)
+		if (free_low(zone) >= 0) {
+			int fullflush = free_min(zone) > 0;
+			freed += page_launder_zone(zone, gfp_mask, fullflush);
 		}
 
-		nr_pages--;
-
-		del_page_from_active_list(page);
-		add_page_to_inactive_list(page);
-		SetPageReferenced(page);
-	}
-	spin_unlock(&pagemap_lru_lock);
+	return freed;
 }
 
-static int FASTCALL(shrink_caches(zone_t * classzone, int priority, unsigned int gfp_mask, int nr_pages));
-static int shrink_caches(zone_t * classzone, int priority, unsigned int gfp_mask, int nr_pages)
+/**
+ * refill_inactive_zone - scan the active list and find pages to deactivate
+ * @priority: how much are we allowed to scan
+ *
+ * This function will scan a portion of the active list of a zone to find
+ * unused pages, those pages will then be moved to the inactive list.
+ */
+int refill_inactive_zone(struct zone_struct * zone, int priority)
 {
-	int chunk_size = nr_pages;
-	unsigned long ratio;
+	int maxscan = zone->active_pages >> priority;
+	int target = inactive_high(zone);
+	struct list_head * page_lru;
+	int nr_deactivated = 0;
+	struct page * page;
 
-	nr_pages -= kmem_cache_reap(gfp_mask);
-	if (nr_pages <= 0)
-		return 0;
-
-	nr_pages = chunk_size;
-	/* try to keep the active list 2/3 of the size of the cache */
-	ratio = (unsigned long) nr_pages * nr_active_pages / ((nr_inactive_pages + 1) * 2);
-	refill_inactive(ratio);
+	/* Take the lock while messing with the list... */
+	spin_lock(&pagemap_lru_lock);
+	while (maxscan-- && !list_empty(&zone->active_list)) {
+		page_lru = zone->active_list.prev;
+		page = list_entry(page_lru, struct page, lru);
+
+		/* Wrong page on list?! (list corruption, should not happen) */
+		if (unlikely(!PageActive(page))) {
+			printk("VM: refill_inactive, wrong page on list.\n");
+			list_del(page_lru);
+			nr_active_pages--;
+			continue;
+		}
+		
+		/* Needed to follow page->mapping */
+		if (TryLockPage(page)) {
+			list_del(page_lru);
+			list_add(page_lru, &zone->active_list);
+			continue;
+		}
 
-	nr_pages = shrink_cache(nr_pages, classzone, gfp_mask, priority);
-	if (nr_pages <= 0)
-		return 0;
+		/*
+		 * If the object the page is in is not in use we don't
+		 * bother with page aging.  If the page is touched again
+		 * while on the inactive_clean list it'll be reactivated.
+		 * From here until the end of the current iteration
+		 * both PG_locked and the pte_chain_lock are held.
+		 */
+		pte_chain_lock(page);
+		if (!page_mapping_inuse(page)) {
+			pte_chain_unlock(page);
+			UnlockPage(page);
+			drop_page(page);
+			continue;
+		}
 
-	shrink_dcache_memory(priority, gfp_mask);
-	shrink_icache_memory(priority, gfp_mask);
-#ifdef CONFIG_QUOTA
-	shrink_dqcache_memory(DEF_PRIORITY, gfp_mask);
-#endif
+		/*
+		 * Do aging on the pages.
+		 */
+		if (page_referenced(page)) {
+			age_page_up(page);
+		} else {
+			age_page_down(page);
+		}
 
-	return nr_pages;
-}
+		/* 
+		 * If the page age is 'hot' and the process using the
+		 * page doesn't exceed its RSS limit we keep the page.
+		 * Otherwise we move it to the inactive_dirty list.
+		 */
+		if (page->age && !page_over_rsslimit(page)) {
+			list_del(page_lru);
+			list_add(page_lru, &zone->active_list);
+		} else {
+			deactivate_page_nolock(page);
+			if (++nr_deactivated > target) {
+				pte_chain_unlock(page);
+				UnlockPage(page);
+				goto done;
+			}
+		}
+		pte_chain_unlock(page);
+		UnlockPage(page);
 
-int try_to_free_pages_zone(zone_t *classzone, unsigned int gfp_mask)
-{
-	int priority = DEF_PRIORITY;
-	int nr_pages = SWAP_CLUSTER_MAX;
+		/* Low latency reschedule point */
+		if (current->need_resched) {
+			spin_unlock(&pagemap_lru_lock);
+			schedule();
+			spin_lock(&pagemap_lru_lock);
+		}
+	}
 
-	gfp_mask = pf_gfp_mask(gfp_mask);
-	do {
-		nr_pages = shrink_caches(classzone, priority, gfp_mask, nr_pages);
-		if (nr_pages <= 0)
-			return 1;
-	} while (--priority);
+done:
+	spin_unlock(&pagemap_lru_lock);
 
-	/*
-	 * Hmm.. Cache shrink failed - time to kill something?
-	 * Mhwahahhaha! This is the part I really like. Giggle.
-	 */
-	out_of_memory();
-	return 0;
+	return nr_deactivated;
 }
 
-int try_to_free_pages(unsigned int gfp_mask)
+/**
+ * refill_inactive - checks all zones and refills the inactive list as needed
+ *
+ * This function tries to balance page eviction from all zones by aging
+ * the pages from each zone in the same ratio until the global inactive
+ * shortage is resolved. After that it does one last "clean-up" scan to
+ * fix up local inactive shortages.
+ */
+int refill_inactive(void)
 {
-	pg_data_t *pgdat;
-	zonelist_t *zonelist;
-	unsigned long pf_free_pages;
-	int error = 0;
+	int maxtry = 1 << DEF_PRIORITY;
+	zone_t * zone;
+	int ret = 0;
 
-	pf_free_pages = current->flags & PF_FREE_PAGES;
-	current->flags &= ~PF_FREE_PAGES;
+	/* Global balancing while we have a global shortage. */
+	while (maxtry-- && inactive_low(ALL_ZONES) >= 0) {
+		for_each_zone(zone) {
+			if (inactive_high(zone) >= 0)
+				ret += refill_inactive_zone(zone, DEF_PRIORITY);
+		}
+	}
 
-	for_each_pgdat(pgdat) {
-		zonelist = pgdat->node_zonelists + (gfp_mask & GFP_ZONEMASK);
-		error |= try_to_free_pages_zone(zonelist->zones[0], gfp_mask);
+	/* Local balancing for zones which really need it. */
+	for_each_zone(zone) {
+		if (inactive_min(zone) >= 0)
+			ret += refill_inactive_zone(zone, 0);
 	}
 
-	current->flags |= pf_free_pages;
-	return error;
+	return ret;
 }
 
-DECLARE_WAIT_QUEUE_HEAD(kswapd_wait);
-
-static int check_classzone_need_balance(zone_t * classzone)
+/**
+ * background_aging - slow background aging of zones
+ * @priority: priority at which to scan
+ *
+ * When the VM load is low or nonexistant, this function is
+ * called once a second to "sort" the pages in the VM. This
+ * way we know which pages to evict once a load spike happens.
+ * The effects of this function are very slow, the CPU usage
+ * should be minimal to nonexistant under most loads.
+ */
+static inline void background_aging(int priority)
 {
-	zone_t * first_classzone;
+	struct zone_struct * zone;
 
-	first_classzone = classzone->zone_pgdat->node_zones;
-	while (classzone >= first_classzone) {
-		if (classzone->free_pages > classzone->pages_high)
-			return 0;
-		classzone--;
-	}
-	return 1;
+	for_each_zone(zone)
+		if (inactive_high(zone) > 0)
+			refill_inactive_zone(zone, priority);
 }
 
-static int kswapd_balance_pgdat(pg_data_t * pgdat)
+/*
+ * Worker function for kswapd and try_to_free_pages, we get
+ * called whenever there is a shortage of free/inactive_clean
+ * pages.
+ *
+ * This function will also move pages to the inactive list,
+ * if needed.
+ */
+static int do_try_to_free_pages(unsigned int gfp_mask)
 {
-	int need_more_balance = 0, i;
-	zone_t * zone;
+	int ret = 0;
 
-	for (i = pgdat->nr_zones-1; i >= 0; i--) {
-		zone = pgdat->node_zones + i;
-		if (unlikely(current->need_resched))
-			schedule();
-		if (!zone->need_balance)
-			continue;
-		if (!try_to_free_pages_zone(zone, GFP_KSWAPD)) {
-			zone->need_balance = 0;
-			__set_current_state(TASK_INTERRUPTIBLE);
-			schedule_timeout(HZ);
-			continue;
-		}
-		if (check_classzone_need_balance(zone))
-			need_more_balance = 1;
-		else
-			zone->need_balance = 0;
-	}
+	/*
+	 * Eat memory from filesystem page cache, buffer cache,
+	 * dentry, inode and filesystem quota caches.
+	 */
+	ret += page_launder(gfp_mask);
+	ret += shrink_dcache_memory(DEF_PRIORITY, gfp_mask);
+	ret += shrink_icache_memory(1, gfp_mask);
+#ifdef CONFIG_QUOTA
+	ret += shrink_dqcache_memory(DEF_PRIORITY, gfp_mask);
+#endif
 
-	return need_more_balance;
-}
+	/*
+	 * Move pages from the active list to the inactive list.
+	 */
+	refill_inactive();
 
-static void kswapd_balance(void)
-{
-	int need_more_balance;
-	pg_data_t * pgdat;
+	/* 	
+	 * Reclaim unused slab cache memory.
+	 */
+	ret += kmem_cache_reap(gfp_mask);
 
-	do {
-		need_more_balance = 0;
+	refill_freelist();
+
+	/* Start IO when needed. */
+	if (free_plenty(ALL_ZONES) > 0 || free_low(ANY_ZONE) > 0)
+		run_task_queue(&tq_disk);
+
+	/*
+	 * Hmm.. Cache shrink failed - time to kill something?
+	 * Mhwahahhaha! This is the part I really like. Giggle.
+	 */
+	if (!ret && free_min(ANY_ZONE) > 0)
+		out_of_memory();
 
-		for_each_pgdat(pgdat)
-			need_more_balance |= kswapd_balance_pgdat(pgdat);
-	} while (need_more_balance);
+	return ret;
 }
 
-static int kswapd_can_sleep_pgdat(pg_data_t * pgdat)
+/**
+ * refill_freelist - move inactive_clean pages to free list if needed
+ *
+ * Move some pages from the inactive_clean lists to the free
+ * lists so atomic allocations have pages to work from. This
+ * function really only does something when we don't have a 
+ * userspace load on __alloc_pages().
+ *
+ * We refill the freelist in a bump from pages_min to pages_min * 2
+ * in order to give the buddy allocator something to play with.
+ */
+static void refill_freelist(void)
 {
+	struct page * page;
 	zone_t * zone;
-	int i;
 
-	for (i = pgdat->nr_zones-1; i >= 0; i--) {
-		zone = pgdat->node_zones + i;
-		if (!zone->need_balance)
+	for_each_zone(zone) {
+		if (!zone->size || zone->free_pages >= zone->pages_min)
 			continue;
-		return 0;
-	}
-
-	return 1;
-}
-
-static int kswapd_can_sleep(void)
-{
-	pg_data_t * pgdat;
 
-	for_each_pgdat(pgdat) {
-		if (!kswapd_can_sleep_pgdat(pgdat))
-			return 0;
+		while (zone->free_pages < zone->pages_min * 2) {
+			page = reclaim_page(zone);
+			if (!page)
+				break;
+			__free_page(page);
+		}
 	}
-
-	return 1;
 }
 
 /*
@@ -720,7 +742,6 @@
 int kswapd(void *unused)
 {
 	struct task_struct *tsk = current;
-	DECLARE_WAITQUEUE(wait, tsk);
 
 	daemonize();
 	strcpy(tsk->comm, "kswapd");
@@ -744,24 +765,155 @@
 	 * Kswapd main loop.
 	 */
 	for (;;) {
-		__set_current_state(TASK_INTERRUPTIBLE);
-		add_wait_queue(&kswapd_wait, &wait);
+		static long recalc = 0;
 
-		mb();
-		if (kswapd_can_sleep())
-			schedule();
+		/*
+		 * We try to rebalance the VM either when we have a
+		 * global shortage of free pages or when one particular
+		 * zone is very short on free pages.
+		 */
+		if (free_high(ALL_ZONES) >= 0 || free_low(ANY_ZONE) > 0)
+			do_try_to_free_pages(GFP_KSWAPD);
+
+		refill_freelist();
+
+		/* Once a second ... */
+		if (time_after(jiffies, recalc + HZ)) {
+			recalc = jiffies;
+
+			/* Do background page aging. */
+			background_aging(DEF_PRIORITY);
+		}
 
-		__set_current_state(TASK_RUNNING);
+		wakeup_memwaiters();
+	}
+}
+
+static int kswapd_overloaded;
+unsigned int kswapd_minfree; /* initialized in mm/page_alloc.c */
+DECLARE_WAIT_QUEUE_HEAD(kswapd_wait);
+DECLARE_WAIT_QUEUE_HEAD(kswapd_done);
+
+/**
+ * wakeup_kswapd - wake up the pageout daemon
+ * gfp_mask: page freeing flags
+ *
+ * This function wakes up kswapd and can, under heavy VM pressure,
+ * put the calling task to sleep temporarily.
+ */
+void wakeup_kswapd(unsigned int gfp_mask)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	/* If we're in the memory freeing business ourself, don't sleep
+	 * but just wake kswapd and go back to businesss.
+	 */
+	if (current->flags & PF_MEMALLOC) {
+		wake_up_interruptible(&kswapd_wait);
+		return;
+	}
+
+	/* We need all of kswapd's GFP flags, otherwise we can't sleep on it.
+	 * We still wake kswapd of course.
+	 */
+	if ((gfp_mask & GFP_KSWAPD) != GFP_KSWAPD) {
+		wake_up_interruptible(&kswapd_wait);
+		return;
+	}
+	
+	add_wait_queue(&kswapd_done, &wait);
+        set_current_state(TASK_UNINTERRUPTIBLE);
+        
+        /* Wake kswapd .... */
+        wake_up_interruptible(&kswapd_wait);
+        
+        /* ... and check if we need to wait on it */
+	if ((free_low(ALL_ZONES) > (kswapd_minfree / 2)) && !kswapd_overloaded)
+		schedule();
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&kswapd_done, &wait);
+}
+
+static void wakeup_memwaiters(void)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	        
+	add_wait_queue(&kswapd_wait, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+
+	/* Don't let the processes waiting on memory get stuck, ever. */
+	wake_up(&kswapd_done);
+
+	/* Enough free RAM, we can easily keep up with memory demand. */
+	if (free_high(ALL_ZONES) <= 0) {
+		schedule_timeout(HZ);
 		remove_wait_queue(&kswapd_wait, &wait);
+		return;
+	}
+	remove_wait_queue(&kswapd_wait, &wait);
 
-		/*
-		 * If we actually get into a low-memory situation,
-		 * the processes needing more memory will wake us
-		 * up on a more timely basis.
-		 */
-		kswapd_balance();
-		run_task_queue(&tq_disk);
+	/* OK, the VM is very loaded. Sleep instead of using all CPU. */
+	kswapd_overloaded = 1;
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ / 4);
+	kswapd_overloaded = 0;
+	return;
+}
+
+/**
+ * try_to_free_pages - run the pageout code ourselves
+ * gfp_mask: mask of things the pageout code is allowed to do
+ *
+ * When the load on the system gets higher, it can happen
+ * that kswapd no longer manages to keep enough memory
+ * free. In those cases user programs allocating memory
+ * will call try_to_free_pages() and help the pageout code.
+ * This has the effects of freeing memory and slowing down
+ * the largest memory hogs a bit.
+ */
+int try_to_free_pages(unsigned int gfp_mask)
+{
+	int ret = 1;
+
+	gfp_mask = pf_gfp_mask(gfp_mask);
+	if (gfp_mask & __GFP_WAIT) {
+		current->flags |= PF_MEMALLOC;
+		ret = do_try_to_free_pages(gfp_mask);
+		current->flags &= ~PF_MEMALLOC;
 	}
+
+	return ret;
+}
+
+/**
+ * rss_free_pages - run part of the pageout code and slow down a bit
+ * @gfp_mask: mask of things the pageout code is allowed to do
+ *
+ * This function is called when a task is over its RSS limit and
+ * has a page fault.  It's goal is to free some memory so non-hogs
+ * can run faster and slow down itself when needed so it won't eat
+ * the memory non-hogs can use.
+ */
+void rss_free_pages(unsigned int gfp_mask)
+{
+	long pause = 0;
+
+	if (current->flags & PF_MEMALLOC)
+		return;
+
+	current->flags |= PF_MEMALLOC;
+
+	do {
+		page_launder(gfp_mask);
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(pause);
+		set_current_state(TASK_RUNNING);
+		pause++;
+	} while (free_high(ALL_ZONES) >= 0);
+
+	current->flags &= ~PF_MEMALLOC;
+	return;
 }
 
 static int __init kswapd_init(void)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/802/p8022.c linux.20pre10-ac2/net/802/p8022.c
--- linux.20pre10/net/802/p8022.c	2002-10-09 21:36:39.000000000 +0100
+++ linux.20pre10-ac2/net/802/p8022.c	2002-08-06 15:41:56.000000000 +0100
@@ -11,11 +11,10 @@
  *		matches. The control byte is ignored and handling of such items
  *		is up to the routine passed the frame.
  *
- *		Unlike the 802.3 datalink we have a list of 802.2 entries as there
- *		are multiple protocols to demux. The list is currently short (3 or
- *		4 entries at most). The current demux assumes this.
+ *		Unlike the 802.3 datalink we have a list of 802.2 entries as
+ *		there are multiple protocols to demux. The list is currently
+ *		short (3 or 4 entries at most). The current demux assumes this.
  */
-
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
@@ -25,8 +24,13 @@
 #include <linux/init.h>
 #include <net/p8022.h>
 
-static struct datalink_proto *p8022_list = NULL;
+extern void llc_register_sap(unsigned char sap,
+			       int (*rcvfunc)(struct sk_buff *,
+					      struct net_device *,
+					       struct packet_type *));
+extern void llc_unregister_sap(unsigned char sap);
 
+static struct datalink_proto *p8022_list;
 /*
  *	We don't handle the loopback SAP stuff, the extended
  *	802.2 command set, multicast SAP identifiers and non UI
@@ -34,91 +38,68 @@
  *	IP and Appletalk phase 2. See the llc_* routines for
  *	support libraries if your protocol needs these.
  */
-
 static struct datalink_proto *find_8022_client(unsigned char type)
 {
-	struct datalink_proto	*proto;
-
-	for (proto = p8022_list;
-		((proto != NULL) && (*(proto->type) != type));
-		proto = proto->next)
-		;
+	struct datalink_proto *proto = p8022_list;
 
+	while (proto && *(proto->type) != type)
+		proto = proto->next;
 	return proto;
 }
 
-int p8022_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
+int p8022_rcv(struct sk_buff *skb, struct net_device *dev,
+	      struct packet_type *pt)
 {
-	struct datalink_proto	*proto;
+	struct datalink_proto *proto;
+	int rc = 0;
 
 	proto = find_8022_client(*(skb->h.raw));
-	if (proto != NULL) 
-	{
-		skb->h.raw += 3;
-		skb->nh.raw += 3;
-		skb_pull(skb,3);
-		return proto->rcvfunc(skb, dev, pt);
+	if (!proto) {
+		skb->sk = NULL;
+		kfree_skb(skb);
+		goto out;
 	}
-
-	skb->sk = NULL;
-	kfree_skb(skb);
-	return 0;
+	skb->h.raw += 3;
+	skb->nh.raw += 3;
+	skb_pull(skb, 3);
+	rc = proto->rcvfunc(skb, dev, pt);
+out:	return rc;
 }
 
 static void p8022_datalink_header(struct datalink_proto *dl,
-		struct sk_buff *skb, unsigned char *dest_node)
+				  struct sk_buff *skb, unsigned char *dest_node)
 {
-	struct net_device	*dev = skb->dev;
-	unsigned char	*rawp;
+	struct net_device *dev = skb->dev;
+	unsigned char *rawp = skb_push(skb, 3);
 
-	rawp = skb_push(skb,3);
 	*rawp++ = dl->type[0];
 	*rawp++ = dl->type[0];
-	*rawp = 0x03;	/* UI */
+	*rawp	= 0x03;	/* UI */
 	dev->hard_header(skb, dev, ETH_P_802_3, dest_node, NULL, skb->len);
 }
 
-static struct packet_type p8022_packet_type =
-{
-	0,	/* MUTTER ntohs(ETH_P_8022),*/
-	NULL,		/* All devices */
-	p8022_rcv,
-	NULL,
-	NULL,
-};
-
-EXPORT_SYMBOL(register_8022_client);
-EXPORT_SYMBOL(unregister_8022_client);
-
-static int __init p8022_init(void)
-{
-	p8022_packet_type.type=htons(ETH_P_802_2);
-	dev_add_pack(&p8022_packet_type);
-	return 0;
-}
-
-module_init(p8022_init);
-
-struct datalink_proto *register_8022_client(unsigned char type, int (*rcvfunc)(struct sk_buff *, struct net_device *, struct packet_type *))
-{
-	struct datalink_proto	*proto;
-
-	if (find_8022_client(type) != NULL)
-		return NULL;
-
-	proto = (struct datalink_proto *) kmalloc(sizeof(*proto), GFP_ATOMIC);
-	if (proto != NULL) {
-		proto->type[0] = type;
-		proto->type_len = 1;
-		proto->rcvfunc = rcvfunc;
-		proto->header_length = 3;
-		proto->datalink_header = p8022_datalink_header;
-		proto->string_name = "802.2";
-		proto->next = p8022_list;
-		p8022_list = proto;
+struct datalink_proto *register_8022_client(unsigned char type,
+					    int (*rcvfunc)(struct sk_buff *,
+						    	   struct net_device *,
+							  struct packet_type *))
+{
+	struct datalink_proto *proto = NULL;
+
+	if (find_8022_client(type))
+		goto out;
+	proto = kmalloc(sizeof(*proto), GFP_ATOMIC);
+	if (proto) {
+		proto->type[0]		= type;
+		proto->type_len		= 1;
+		proto->rcvfunc		= rcvfunc;
+		proto->header_length	= 3;
+		proto->datalink_header	= p8022_datalink_header;
+		proto->string_name	= "802.2";
+		proto->next		= p8022_list;
+		p8022_list		= proto;
+		llc_register_sap(type, p8022_rcv);
 	}
-
-	return proto;
+out:	return proto;
 }
 
 void unregister_8022_client(unsigned char type)
@@ -128,17 +109,18 @@
 
 	save_flags(flags);
 	cli();
-
-	while ((tmp = *clients) != NULL)
-	{
+	while (*clients) {
+		tmp = *clients;
 		if (tmp->type[0] == type) {
 			*clients = tmp->next;
 			kfree(tmp);
+			llc_unregister_sap(type);
 			break;
-		} else {
-			clients = &tmp->next;
 		}
+		clients = &tmp->next;
 	}
-
 	restore_flags(flags);
 }
+
+EXPORT_SYMBOL(register_8022_client);
+EXPORT_SYMBOL(unregister_8022_client);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/bluetooth/bnep/core.c linux.20pre10-ac2/net/bluetooth/bnep/core.c
--- linux.20pre10/net/bluetooth/bnep/core.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/net/bluetooth/bnep/core.c	2002-08-06 15:42:06.000000000 +0100
@@ -458,8 +458,6 @@
         sigfillset(&current->blocked);
 	flush_signals(current);
 
-	current->nice = -15;
-
         set_fs(KERNEL_DS);
 
 	init_waitqueue_entry(&wait, current);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/Config.in linux.20pre10-ac2/net/Config.in
--- linux.20pre10/net/Config.in	2002-10-09 21:36:39.000000000 +0100
+++ linux.20pre10-ac2/net/Config.in	2002-08-06 15:41:56.000000000 +0100
@@ -68,11 +68,12 @@
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
    tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
-   bool '802.2 LLC (EXPERIMENTAL)' CONFIG_LLC
+   tristate 'ANSI/IEEE 802.2 Data link layer protocol' CONFIG_LLC
+   if [ "$CONFIG_LLC" != "n" ]; then
+	# When NETBEUI is added the following line will be a tristate
+	define_bool CONFIG_LLC_UI y
+   fi
    bool 'Frame Diverter (EXPERIMENTAL)' CONFIG_NET_DIVERT
-#   if [ "$CONFIG_LLC" = "y" ]; then
-#      bool '  Netbeui (EXPERIMENTAL)' CONFIG_NETBEUI
-#   fi
    if [ "$CONFIG_INET" = "y" ]; then
       tristate 'Acorn Econet/AUN protocols (EXPERIMENTAL)' CONFIG_ECONET
       if [ "$CONFIG_ECONET" != "n" ]; then
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/core/ext8022.c linux.20pre10-ac2/net/core/ext8022.c
--- linux.20pre10/net/core/ext8022.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/net/core/ext8022.c	2002-08-06 15:41:56.000000000 +0100
@@ -0,0 +1,76 @@
+/*
+ * (ext8022.c)
+ * 
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/brlock.h>
+
+typedef int (*func_type)(struct sk_buff *skb, struct net_device *dev,
+			 struct packet_type *pt);
+static int llc_rcv(struct sk_buff *skb, struct net_device *dev,
+		   struct packet_type *);
+
+static func_type llc_sap_table[128];
+static int llc_users;
+
+static struct packet_type llc_packet_type = {
+	type:	__constant_htons(ETH_P_802_2),
+	func:	llc_rcv,
+};
+static struct packet_type llc_tr_packet_type = {
+	type:	__constant_htons(ETH_P_TR_802_2),
+	func:	llc_rcv,
+};
+
+static int llc_rcv(struct sk_buff *skb, struct net_device *dev,
+		   struct packet_type *pt)
+{
+ 	unsigned char n = (*(skb->h.raw)) >> 1;
+
+	br_read_lock(BR_LLC_LOCK);
+	if (llc_sap_table[n])
+            llc_sap_table[n](skb, dev, pt);
+        else
+            kfree_skb(skb);
+	br_read_unlock(BR_LLC_LOCK);
+        return 0;
+}
+
+void llc_register_sap(unsigned char sap, func_type rcvfunc)
+{
+	sap >>= 1;
+	br_write_lock_bh(BR_LLC_LOCK);
+	llc_sap_table[sap] = rcvfunc;            
+	if (!llc_users) {
+		dev_add_pack(&llc_packet_type);
+		dev_add_pack(&llc_tr_packet_type);
+        }
+	llc_users++;
+	br_write_unlock_bh(BR_LLC_LOCK);
+}
+
+void llc_unregister_sap(unsigned char sap)
+{
+	sap >>= 1;
+	br_write_lock_bh(BR_LLC_LOCK);
+        llc_sap_table[sap] = NULL;
+	if (!--llc_users) {
+		dev_remove_pack(&llc_packet_type);
+		dev_remove_pack(&llc_tr_packet_type);
+        } 
+	br_write_unlock_bh(BR_LLC_LOCK);
+}
+
+EXPORT_SYMBOL(llc_register_sap);
+EXPORT_SYMBOL(llc_unregister_sap);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/core/Makefile linux.20pre10-ac2/net/core/Makefile
--- linux.20pre10/net/core/Makefile	2002-10-09 21:36:39.000000000 +0100
+++ linux.20pre10-ac2/net/core/Makefile	2002-08-06 15:41:56.000000000 +0100
@@ -9,7 +9,7 @@
 
 O_TARGET := core.o
 
-export-objs := netfilter.o profile.o
+export-objs := ext8022.o netfilter.o profile.o
 
 obj-y := sock.o skbuff.o iovec.o datagram.o scm.o
 
@@ -23,6 +23,10 @@
 
 obj-$(CONFIG_NET) += dev.o dev_mcast.o dst.o neighbour.o rtnetlink.o utils.o
 
+ifneq ($(CONFIG_LLC),n)
+obj-y += ext8022.o
+endif
+
 obj-$(CONFIG_NETFILTER) += netfilter.o
 obj-$(CONFIG_NET_DIVERT) += dv.o
 obj-$(CONFIG_NET_PROFILE) += profile.o
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/llc/llc_actn.c linux.20pre10-ac2/net/llc/llc_actn.c
--- linux.20pre10/net/llc/llc_actn.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/net/llc/llc_actn.c	2002-08-06 15:42:06.000000000 +0100
@@ -0,0 +1,147 @@
+/*
+ * llc_actn.c - Implementation of actions of station component of LLC
+ *
+ * Description :
+ *   Functions in this module are implementation of station component actions.
+ *   Details of actions can be found in IEEE-802.2 standard document.
+ *   All functions have one station and one event as input argument. All of
+ *   them return 0 On success and 1 otherwise.
+ *
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/netdevice.h>
+#include <net/llc_if.h>
+#include <net/llc_main.h>
+#include <net/llc_evnt.h>
+#include <net/llc_pdu.h>
+#include <net/llc_mac.h>
+
+static void llc_station_ack_tmr_callback(unsigned long timeout_data);
+
+int llc_station_ac_start_ack_timer(struct llc_station *station,
+				   struct llc_station_state_ev *ev)
+{
+	del_timer(&station->ack_timer);
+	station->ack_timer.expires  = jiffies + LLC_ACK_TIME * HZ;
+	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;
+}
+
+int llc_station_ac_set_retry_cnt_0(struct llc_station *station,
+				   struct llc_station_state_ev *ev)
+{
+	station->retry_count = 0;
+	return 0;
+}
+
+int llc_station_ac_inc_retry_cnt_by_1(struct llc_station *station,
+				      struct llc_station_state_ev *ev)
+{
+	station->retry_count++;
+	return 0;
+}
+
+int llc_station_ac_set_xid_r_cnt_0(struct llc_station *station,
+				   struct llc_station_state_ev *ev)
+{
+	station->xid_r_count = 0;
+	return 0;
+}
+
+int llc_station_ac_inc_xid_r_cnt_by_1(struct llc_station *station,
+				      struct llc_station_state_ev *ev)
+{
+	station->xid_r_count++;
+	return 0;
+}
+
+int llc_station_ac_send_null_dsap_xid_c(struct llc_station *station,
+					struct llc_station_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (!skb)
+		goto out;
+	rc = 0;
+	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, 0, 0, LLC_PDU_CMD);
+	llc_pdu_init_as_xid_cmd(skb, LLC_XID_NULL_CLASS_2, 127);
+	lan_hdrs_init(skb, station->mac_sa, station->mac_sa);
+	llc_station_send_pdu(station, skb);
+out:	return rc;
+}
+
+int llc_station_ac_send_xid_r(struct llc_station *station,
+			      struct llc_station_state_ev *ev)
+{
+	u8 mac_da[ETH_ALEN], dsap;
+	int rc = 1;
+	struct sk_buff *ev_skb;
+	struct sk_buff* skb = llc_alloc_frame();
+
+	if (!skb)
+		goto out;
+	rc = 0;
+	ev_skb = ev->data.pdu.skb;
+	skb->dev = ev_skb->dev;
+	llc_pdu_decode_sa(ev_skb, mac_da);
+	llc_pdu_decode_ssap(ev_skb, &dsap);
+	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
+	llc_pdu_init_as_xid_rsp(skb, LLC_XID_NULL_CLASS_2, 127);
+	lan_hdrs_init(skb, station->mac_sa, mac_da);
+	llc_station_send_pdu(station, skb);
+out:	return rc;
+}
+
+int llc_station_ac_send_test_r(struct llc_station *station,
+			       struct llc_station_state_ev *ev)
+{
+	u8 mac_da[ETH_ALEN], dsap;
+	int rc = 1;
+	struct sk_buff *ev_skb;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (!skb)
+		goto out;
+	rc = 0;
+	ev_skb = ev->data.pdu.skb;
+	skb->dev = ev_skb->dev;
+	llc_pdu_decode_sa(ev_skb, mac_da);
+	llc_pdu_decode_ssap(ev_skb, &dsap);
+	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
+       	llc_pdu_init_as_test_rsp(skb, ev_skb);
+	lan_hdrs_init(skb, station->mac_sa, mac_da);
+	llc_station_send_pdu(station, skb);
+out:	return rc;
+}
+
+int llc_station_ac_report_status(struct llc_station *station,
+				 struct llc_station_state_ev *ev)
+{
+	return 0;
+}
+
+static void llc_station_ack_tmr_callback(unsigned long timeout_data)
+{
+	struct llc_station *station = (struct llc_station *)timeout_data;
+	struct llc_station_state_ev *ev;
+
+	station->ack_tmr_running = 0;
+	ev = llc_station_alloc_ev(station);
+	if (ev) {
+		ev->type = LLC_STATION_EV_TYPE_ACK_TMR;
+		ev->data.tmr.timer_specific = NULL;
+		llc_station_send_ev(station, ev);
+	}
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/llc/llc_c_ac.c linux.20pre10-ac2/net/llc/llc_c_ac.c
--- linux.20pre10/net/llc/llc_c_ac.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/net/llc/llc_c_ac.c	2002-08-06 15:42:06.000000000 +0100
@@ -0,0 +1,1645 @@
+/*
+ * llc_c_ac.c - actions performed during connection state transition.
+ *
+ * Description:
+ *   Functions in this module are implementation of connection component actions
+ *   Details of actions can be found in IEEE-802.2 standard document.
+ *   All functions have one connection and one event as input argument. All of
+ *   them return 0 On success and 1 otherwise.
+ *
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/netdevice.h>
+#include <net/llc_conn.h>
+#include <net/llc_sap.h>
+#include <net/sock.h>
+#include <net/llc_main.h>
+#include <net/llc_c_ev.h>
+#include <net/llc_c_ac.h>
+#include <net/llc_c_st.h>
+#include <net/llc_pdu.h>
+#include <net/llc_mac.h>
+
+static void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data);
+static void llc_conn_ack_tmr_cb(unsigned long timeout_data);
+static void llc_conn_rej_tmr_cb(unsigned long timeout_data);
+static void llc_conn_busy_tmr_cb(unsigned long timeout_data);
+static int llc_conn_ac_inc_vs_by_1(struct sock *sk,
+				   struct llc_conn_state_ev *ev);
+static void llc_process_tmr_ev(struct sock *sk, struct llc_conn_state_ev *ev);
+static int llc_conn_ac_data_confirm(struct sock *sk,
+				    struct llc_conn_state_ev *ev);
+
+#define INCORRECT 0
+
+int llc_conn_ac_clear_remote_busy(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	struct llc_opt *llc = llc_sk(sk);
+
+	if (llc->remote_busy_flag) {
+		u8 nr;
+		llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+		llc->remote_busy_flag = 0;
+		del_timer(&llc->busy_state_timer.timer);
+		llc->busy_state_timer.running = 0;
+		nr = LLC_I_GET_NR(rx_pdu);
+		llc_conn_resend_i_pdu_as_cmd(sk, nr, 0);
+	}
+	return 0;
+}
+
+int llc_conn_ac_conn_ind(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = ev->data.pdu.skb;
+	union llc_u_prim_data *prim_data = llc_ind_prim.data;
+	struct llc_prim_if_block *prim = &llc_ind_prim;
+	struct llc_sap *sap;
+	struct llc_opt *llc = llc_sk(sk);
+
+	llc_pdu_decode_dsap(skb, &prim_data->conn.daddr.lsap);
+	sap = llc_sap_find(prim_data->conn.daddr.lsap);
+	if (sap) {
+		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;
+		rc = 0;
+	}
+	return rc;
+}
+
+int llc_conn_ac_conn_confirm(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	union llc_u_prim_data *prim_data = llc_cfm_prim.data;
+	struct sk_buff *skb = ev->data.pdu.skb;
+	/* FIXME: wtf, this is global, so the whole thing is really non
+	 * reentrant... */
+	struct llc_prim_if_block *prim = &llc_cfm_prim;
+	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sap *sap = llc->sap;
+
+	prim_data->conn.sk     = sk;
+	prim_data->conn.pri    = 0;
+	prim_data->conn.status = ev->status;
+	prim_data->conn.link   = llc->link;
+	if (skb)
+		prim_data->conn.dev    = skb->dev;
+	else
+		printk(KERN_ERR __FUNCTION__ "ev->data.pdu.skb == NULL\n");
+	prim->data   = prim_data;
+	prim->prim   = LLC_CONN_PRIM;
+	prim->sap    = sap;
+	ev->flag     = 1;
+	ev->cfm_prim = prim;
+	return 0;
+}
+
+static int llc_conn_ac_data_confirm(struct sock *sk,
+				    struct llc_conn_state_ev *ev)
+{
+	struct llc_prim_if_block *prim = &llc_cfm_prim;
+	union llc_u_prim_data *prim_data = llc_cfm_prim.data;
+
+	prim_data->data.sk     = sk;
+	prim_data->data.pri    = 0;
+	prim_data->data.link   = llc_sk(sk)->link;
+	prim_data->data.status = LLC_STATUS_RECEIVED;
+	prim_data->data.skb    = NULL;
+	prim->data	       = prim_data;
+	prim->prim	       = LLC_DATA_PRIM;
+	prim->sap	       = llc_sk(sk)->sap;
+	ev->flag	       = 1;
+	ev->cfm_prim	       = prim;
+	return 0;
+}
+
+int llc_conn_ac_data_ind(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_conn_rtn_pdu(sk, ev->data.pdu.skb, ev);
+	return 0;
+}
+
+int llc_conn_ac_disc_ind(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	u8 reason = 0;
+	int rc = 1;
+	union llc_u_prim_data *prim_data = llc_ind_prim.data;
+	struct llc_prim_if_block *prim = &llc_ind_prim;
+
+	if (ev->type == LLC_CONN_EV_TYPE_PDU) {
+		llc_pdu_un_t *rx_pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+		if (!LLC_PDU_IS_RSP(rx_pdu) &&
+		    !LLC_PDU_TYPE_IS_U(rx_pdu) &&
+		    LLC_U_PDU_RSP(rx_pdu) == LLC_2_PDU_RSP_DM) {
+			reason = LLC_DISC_REASON_RX_DM_RSP_PDU;
+			rc = 0;
+		} else if (!LLC_PDU_IS_CMD(rx_pdu) &&
+			   !LLC_PDU_TYPE_IS_U(rx_pdu) &&
+			   LLC_U_PDU_CMD(rx_pdu) == LLC_2_PDU_CMD_DISC) {
+			reason = LLC_DISC_REASON_RX_DISC_CMD_PDU;
+			rc = 0;
+		}
+	} else if (ev->type == LLC_CONN_EV_TYPE_ACK_TMR) {
+		reason = LLC_DISC_REASON_ACK_TMR_EXP;
+		rc = 0;
+	} else {
+		reason = 0;
+		rc = 1;
+	}
+	if (!rc) {
+		prim_data->disc.sk     = sk;
+		prim_data->disc.reason = reason;
+		prim_data->disc.link   = llc_sk(sk)->link;
+		prim->data	       = prim_data;
+		prim->prim	       = LLC_DISC_PRIM;
+		prim->sap	       = llc_sk(sk)->sap;
+		ev->flag	       = 1;
+		ev->ind_prim	       = prim;
+	}
+	return rc;
+}
+
+int llc_conn_ac_disc_confirm(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	union llc_u_prim_data *prim_data = llc_cfm_prim.data;
+	struct llc_prim_if_block *prim = &llc_cfm_prim;
+
+	prim_data->disc.sk     = sk;
+	prim_data->disc.reason = ev->status;
+	prim_data->disc.link   = llc_sk(sk)->link;
+	prim->data	       = prim_data;
+	prim->prim	       = LLC_DISC_PRIM;
+	prim->sap	       = llc_sk(sk)->sap;
+	ev->flag	       = 1;
+	ev->cfm_prim	       = prim;
+	return 0;
+}
+
+int llc_conn_ac_rst_ind(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	u8 reason = 0;
+	int rc = 1;
+	llc_pdu_un_t *rx_pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+	union llc_u_prim_data *prim_data = llc_ind_prim.data;
+	struct llc_prim_if_block *prim = &llc_ind_prim;
+	struct llc_opt *llc = llc_sk(sk);
+
+	switch (ev->type) {
+		case LLC_CONN_EV_TYPE_PDU:
+			if (!LLC_PDU_IS_RSP(rx_pdu) &&
+			    !LLC_PDU_TYPE_IS_U(rx_pdu) &&
+			    LLC_U_PDU_RSP(rx_pdu) == LLC_2_PDU_RSP_FRMR) {
+				reason = LLC_RESET_REASON_LOCAL;
+				rc = 0;
+			} else if (!LLC_PDU_IS_CMD(rx_pdu) &&
+				   !LLC_PDU_TYPE_IS_U(rx_pdu) &&
+				   LLC_U_PDU_CMD(rx_pdu) ==
+				   			LLC_2_PDU_CMD_SABME) {
+				reason = LLC_RESET_REASON_REMOTE;
+				rc = 0;
+			} else {
+				reason = 0;
+				rc  = 1;
+			}
+			break;
+		case LLC_CONN_EV_TYPE_ACK_TMR:
+		case LLC_CONN_EV_TYPE_P_TMR:
+		case LLC_CONN_EV_TYPE_REJ_TMR:
+		case LLC_CONN_EV_TYPE_BUSY_TMR:
+			if (llc->retry_count > llc->n2) {
+				reason = LLC_RESET_REASON_LOCAL;
+				rc = 0;
+			} else
+				rc = 1;
+			break;
+	}
+	if (!rc) {
+		prim_data->res.sk     = sk;
+		prim_data->res.reason = reason;
+		prim_data->res.link   = llc->link;
+		prim->data	      = prim_data;
+		prim->prim	      = LLC_RESET_PRIM;
+		prim->sap	      = llc->sap;
+		ev->flag	      = 1;
+		ev->ind_prim	      = prim;
+	}
+	return rc;
+}
+
+int llc_conn_ac_rst_confirm(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	union llc_u_prim_data *prim_data = llc_cfm_prim.data;
+	struct llc_prim_if_block *prim = &llc_cfm_prim;
+
+	prim_data->res.sk   = sk;
+	prim_data->res.link = llc_sk(sk)->link;
+	prim->data	    = prim_data;
+	prim->prim	    = LLC_RESET_PRIM;
+	prim->sap	    = llc_sk(sk)->sap;
+	ev->flag	    = 1;
+	ev->cfm_prim	    = prim;
+	return 0;
+}
+
+int llc_conn_ac_report_status(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	return 0;
+}
+
+int llc_conn_ac_clear_remote_busy_if_f_eq_1(struct sock *sk,
+					struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	if (!LLC_PDU_IS_RSP(rx_pdu) &&
+	    !LLC_PDU_TYPE_IS_I(rx_pdu) &&
+	    !LLC_I_PF_IS_1(rx_pdu) && llc_sk(sk)->ack_pf)
+		llc_conn_ac_clear_remote_busy(sk, ev);
+	return 0;
+}
+
+int llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2(struct sock *sk,
+						 struct llc_conn_state_ev *ev)
+{
+	if (llc_sk(sk)->data_flag == 2) {
+		del_timer(&llc_sk(sk)->rej_sent_timer.timer);
+		llc_sk(sk)->rej_sent_timer.running = 0;
+	}
+	return 0;
+}
+
+int llc_conn_ac_send_disc_cmd_p_set_x(struct sock *sk,
+				      struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		u8 p_bit = 1;
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_CMD);
+		llc_pdu_init_as_disc_cmd(skb, p_bit);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	llc_conn_ac_set_p_flag_1(sk, ev);
+	return rc;
+}
+
+int llc_conn_ac_send_dm_rsp_f_set_p(struct sock *sk,
+				    struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+		struct sk_buff *rx_skb = ev->data.pdu.skb;
+		u8 f_bit;
+
+		skb->dev = llc->dev;
+		llc_pdu_decode_pf_bit(rx_skb, &f_bit);
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_RSP);
+		llc_pdu_init_as_dm_rsp(skb, f_bit);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_send_dm_rsp_f_set_1(struct sock *sk,
+				    struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+		u8 f_bit = 1;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_RSP);
+		llc_pdu_init_as_dm_rsp(skb, f_bit);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_send_dm_rsp_f_set_f_flag(struct sock *sk,
+					 struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+		u8 f_bit = llc->f_flag;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_RSP);
+		llc_pdu_init_as_dm_rsp(skb, f_bit);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_send_frmr_rsp_f_set_x(struct sock *sk,
+				      struct llc_conn_state_ev *ev)
+{
+	u8 f_bit;
+	int rc = 1;
+	struct sk_buff *skb, *ev_skb = ev->data.pdu.skb;
+	llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev_skb->nh.raw;
+	struct llc_opt *llc = llc_sk(sk);
+
+	llc->rx_pdu_hdr = (u32)*((u32 *)rx_pdu);
+	if (!LLC_PDU_IS_CMD(rx_pdu))
+		llc_pdu_decode_pf_bit(ev_skb, &f_bit);
+	else
+		f_bit = 0;
+	skb = llc_alloc_frame();
+	if (skb) {
+		struct llc_sap *sap = llc->sap;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_RSP);
+		llc_pdu_init_as_frmr_rsp(skb, rx_pdu, f_bit, llc->vS,
+					 llc->vR, INCORRECT);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_resend_frmr_rsp_f_set_0(struct sock *sk,
+					struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		u8 f_bit = 0;
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+		llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)&llc->rx_pdu_hdr;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_RSP);
+		llc_pdu_init_as_frmr_rsp(skb, rx_pdu, f_bit, llc->vS,
+					 llc->vR, INCORRECT);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_resend_frmr_rsp_f_set_p(struct sock *sk,
+					struct llc_conn_state_ev *ev)
+{
+	u8 f_bit;
+	int rc = 1;
+	struct sk_buff *skb;
+
+	llc_pdu_decode_pf_bit(ev->data.pdu.skb, &f_bit);
+	skb = llc_alloc_frame();
+	if (skb) {
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+		llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_RSP);
+		llc_pdu_init_as_frmr_rsp(skb, rx_pdu, f_bit, llc->vS,
+					 llc->vR, INCORRECT);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_send_i_cmd_p_set_1(struct sock *sk,
+				   struct llc_conn_state_ev *ev)
+{
+	u8 p_bit = 1;
+	struct sk_buff *skb = ev->data.prim.data->data->data.skb;
+	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sap *sap = llc->sap;
+
+	llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
+			    llc->daddr.lsap, LLC_PDU_CMD);
+	llc_pdu_init_as_i_cmd(skb, p_bit, llc->vS, llc->vR);
+	lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+	llc_conn_send_pdu(sk, skb);
+	llc_conn_ac_inc_vs_by_1(sk, ev);
+	return 0;
+}
+
+int llc_conn_ac_send_i_cmd_p_set_0(struct sock *sk,
+				   struct llc_conn_state_ev *ev)
+{
+	u8 p_bit = 0;
+	struct sk_buff *skb = ev->data.prim.data->data->data.skb;
+	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sap *sap = llc->sap;
+
+	llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
+			    llc->daddr.lsap, LLC_PDU_CMD);
+	llc_pdu_init_as_i_cmd(skb, p_bit, llc->vS, llc->vR);
+	lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+	llc_conn_send_pdu(sk, skb);
+	llc_conn_ac_inc_vs_by_1(sk, ev);
+	return 0;
+}
+
+int llc_conn_ac_resend_i_cmd_p_set_1(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	u8 nr = LLC_I_GET_NR(rx_pdu);
+
+	llc_conn_resend_i_pdu_as_cmd(sk, nr, 1);
+	return 0;
+}
+
+int llc_conn_ac_resend_i_cmd_p_set_1_or_send_rr(struct sock *sk,
+						struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	u8 nr = LLC_I_GET_NR(rx_pdu);
+	int rc = llc_conn_ac_send_rr_cmd_p_set_1(sk, ev);
+
+	if (!rc)
+		llc_conn_resend_i_pdu_as_cmd(sk, nr, 0);
+	return rc;
+}
+
+int llc_conn_ac_send_i_xxx_x_set_0(struct sock *sk,
+				   struct llc_conn_state_ev *ev)
+{
+	u8 p_bit = 0;
+	struct sk_buff *skb = ev->data.prim.data->data->data.skb;
+	struct llc_opt *llc = llc_sk(sk);
+	struct llc_sap *sap = llc->sap;
+
+	llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
+			    llc->daddr.lsap, LLC_PDU_CMD);
+	llc_pdu_init_as_i_cmd(skb, p_bit, llc->vS, llc->vR);
+	lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+	llc_conn_send_pdu(sk, skb);
+	llc_conn_ac_inc_vs_by_1(sk, ev);
+	return 0;
+}
+
+int llc_conn_ac_resend_i_xxx_x_set_0(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+	u8 nr = LLC_I_GET_NR(rx_pdu);
+
+	llc_conn_resend_i_pdu_as_cmd(sk, nr, 0);
+	return 0;
+}
+
+int llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr(struct sock *sk,
+						struct llc_conn_state_ev *ev)
+{
+	u8 nr;
+	u8 f_bit = 0;
+	llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_RSP);
+		llc_pdu_init_as_rr_rsp(skb, f_bit, llc->vR);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	if (rc) {
+		nr = LLC_I_GET_NR(rx_pdu);
+		rc = 0;
+		llc_conn_resend_i_pdu_as_cmd(sk, nr, f_bit);
+	}
+	return rc;
+}
+
+int llc_conn_ac_resend_i_rsp_f_set_1(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+	u8 nr = LLC_I_GET_NR(rx_pdu);
+
+	llc_conn_resend_i_pdu_as_rsp(sk, nr, 1);
+	return 0;
+}
+
+int llc_conn_ac_send_rej_cmd_p_set_1(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+		u8 p_bit = 1;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_CMD);
+		llc_pdu_init_as_rej_cmd(skb, p_bit, llc->vR);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_send_rej_rsp_f_set_1(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		u8 f_bit = 1;
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_RSP);
+		llc_pdu_init_as_rej_rsp(skb, f_bit, llc->vR);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_send_rej_xxx_x_set_0(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+		u8 f_bit = 0;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_RSP);
+		llc_pdu_init_as_rej_rsp(skb, f_bit, llc->vR);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_send_rnr_cmd_p_set_1(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+		u8 p_bit = 1;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_CMD);
+		llc_pdu_init_as_rnr_cmd(skb, p_bit, llc->vR);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_send_rnr_rsp_f_set_1(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+		u8 f_bit = 1;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_RSP);
+		llc_pdu_init_as_rnr_rsp(skb, f_bit, llc->vR);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_send_rnr_xxx_x_set_0(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		u8 f_bit = 0;
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_RSP);
+		llc_pdu_init_as_rnr_rsp(skb, f_bit, llc->vR);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_set_remote_busy(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	struct llc_opt *llc = llc_sk(sk);
+
+	if (!llc->remote_busy_flag) {
+		llc->remote_busy_flag = 1;
+		llc->busy_state_timer.timer.expires = jiffies +
+					llc->busy_state_timer.expire * HZ;
+		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;
+}
+
+int llc_conn_ac_opt_send_rnr_xxx_x_set_0(struct sock *sk,
+					 struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+		u8 f_bit = 0;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_RSP);
+		llc_pdu_init_as_rnr_rsp(skb, f_bit, llc->vR);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_send_rr_cmd_p_set_1(struct sock *sk,
+				    struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		u8 p_bit = 1;
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_CMD);
+		llc_pdu_init_as_rr_cmd(skb, p_bit, llc->vR);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_send_ack_cmd_p_set_1(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		u8 p_bit = 1;
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_CMD);
+		llc_pdu_init_as_rr_cmd(skb, p_bit, llc->vR);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_send_rr_rsp_f_set_1(struct sock *sk,
+				    struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+		u8 f_bit = 1;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_RSP);
+		llc_pdu_init_as_rr_rsp(skb, f_bit, llc->vR);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_send_ack_rsp_f_set_1(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+		u8 f_bit = 1;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_RSP);
+		llc_pdu_init_as_rr_rsp(skb, f_bit, llc->vR);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_send_rr_xxx_x_set_0(struct sock *sk,
+				    struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+		u8 f_bit = 0;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_RSP);
+		llc_pdu_init_as_rr_rsp(skb, f_bit, llc->vR);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_send_ack_xxx_x_set_0(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+		u8 f_bit = 0;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_RSP);
+		llc_pdu_init_as_rr_rsp(skb, f_bit, llc->vR);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_send_sabme_cmd_p_set_x(struct sock *sk,
+				       struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+	struct llc_opt *llc = llc_sk(sk);
+	u8 p_bit = 1;
+
+	if (skb) {
+		struct llc_sap *sap = llc->sap;
+		u8 *dmac = llc->daddr.mac;
+
+		if (llc->dev->flags & IFF_LOOPBACK)
+			dmac = llc->dev->dev_addr;
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_CMD);
+		llc_pdu_init_as_sabme_cmd(skb, p_bit);
+		lan_hdrs_init(skb, llc->dev->dev_addr, dmac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	llc->p_flag = p_bit;
+	return rc;
+}
+
+int llc_conn_ac_send_ua_rsp_f_set_f_flag(struct sock *sk,
+					 struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+		u8 f_bit = llc->f_flag;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_RSP);
+		llc_pdu_init_as_ua_rsp(skb, f_bit);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_send_ua_rsp_f_set_p(struct sock *sk,
+				    struct llc_conn_state_ev *ev)
+{
+	u8 f_bit;
+	int rc = 1;
+	struct sk_buff *rx_skb = ev->data.pdu.skb;
+	struct sk_buff *skb;
+
+	llc_pdu_decode_pf_bit(rx_skb, &f_bit);
+	skb = llc_alloc_frame();
+	if (skb) {
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_RSP);
+		llc_pdu_init_as_ua_rsp(skb, f_bit);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+int llc_conn_ac_set_s_flag_0(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_sk(sk)->s_flag = 0;
+	return 0;
+}
+
+int llc_conn_ac_set_s_flag_1(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_sk(sk)->s_flag = 1;
+	return 0;
+}
+
+int llc_conn_ac_start_p_timer(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	struct llc_opt *llc = llc_sk(sk);
+
+	llc->p_flag = 1;
+	del_timer(&llc->pf_cycle_timer.timer);
+	llc->pf_cycle_timer.timer.expires  = jiffies +
+						llc->pf_cycle_timer.expire * HZ;
+	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;
+}
+
+/**
+ *	llc_conn_ac_send_ack_if_needed - check if ack is needed
+ *	@sk: current connection structure
+ *	@ev: current event
+ *
+ *	Checks number of received PDUs which have not been acknowledged, yet,
+ *	If number of them reaches to "npta"(Number of PDUs To Acknowledge) then
+ *	sends an RR response as acknowledgement for them.  Returns 0 for
+ *	success, 1 otherwise.
+ */
+int llc_conn_ac_send_ack_if_needed(struct sock *sk,
+				   struct llc_conn_state_ev *ev)
+{
+	u8 pf_bit;
+	struct sk_buff *skb = ev->data.pdu.skb;
+	struct llc_opt *llc = llc_sk(sk);
+
+	llc_pdu_decode_pf_bit(skb, &pf_bit);
+	llc->ack_pf |= pf_bit & 1;
+	if (!llc->ack_must_be_send) {
+		llc->first_pdu_Ns = llc->vR;
+		llc->ack_must_be_send = 1;
+		llc->ack_pf = pf_bit & 1;
+	}
+	if (((llc->vR - llc->first_pdu_Ns + 129) % 128) >= llc->npta) {
+		llc_conn_ac_send_rr_rsp_f_set_ackpf(sk, ev);
+		llc->ack_must_be_send	= 0;
+		llc->ack_pf		= 0;
+		llc_conn_ac_inc_npta_value(sk, ev);
+	}
+	return 0;
+}
+
+/**
+ *	llc_conn_ac_rst_sendack_flag - resets ack_must_be_send flag
+ *	@sk: current connection structure
+ *	@ev: current event
+ *
+ *	This action resets ack_must_be_send flag of given connection, this flag
+ *	indicates if there is any PDU which has not been acknowledged yet.
+ *	Returns 0 for success, 1 otherwise.
+ */
+int llc_conn_ac_rst_sendack_flag(struct sock *sk,
+				   struct llc_conn_state_ev *ev)
+{
+	llc_sk(sk)->ack_must_be_send = llc_sk(sk)->ack_pf = 0;
+	return 0;
+}
+
+/**
+ *	llc_conn_ac_send_i_rsp_f_set_ackpf - acknowledge received PDUs
+ *	@sk: current connection structure
+ *	@ev: current event
+ *
+ *	Sends an I response PDU with f-bit set to ack_pf flag as acknowledge to
+ *	all received PDUs which have not been acknowledged, yet. ack_pf flag is
+ *	set to one if one PDU with p-bit set to one is received.  Returns 0 for
+ *	success, 1 otherwise.
+ */
+int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock *sk,
+				       struct llc_conn_state_ev *ev)
+{
+	struct sk_buff *skb = ev->data.prim.data->data->data.skb;
+	struct llc_opt *llc = llc_sk(sk);
+	u8 p_bit = llc->ack_pf;
+	struct llc_sap *sap = llc->sap;
+
+	llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
+			    llc->daddr.lsap, LLC_PDU_RSP);
+	llc_pdu_init_as_i_cmd(skb, p_bit, llc->vS, llc->vR);
+	lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+	llc_conn_send_pdu(sk, skb);
+	llc_conn_ac_inc_vs_by_1(sk, ev);
+	return 0;
+}
+
+/**
+ *	llc_conn_ac_send_i_as_ack - sends an I-format PDU to acknowledge rx PDUs
+ *	@sk: current connection structure.
+ *	@ev: current event.
+ *
+ *	This action sends an I-format PDU as acknowledge to received PDUs which
+ *	have not been acknowledged, yet, if there is any. By using of this
+ *	action number of acknowledgements decreases, this technic is called
+ *	piggy backing. Returns 0 for success, 1 otherwise.
+ */
+int llc_conn_ac_send_i_as_ack(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	struct llc_opt *llc = llc_sk(sk);
+
+	if (llc->ack_must_be_send) {
+		llc_conn_ac_send_i_rsp_f_set_ackpf(sk, ev);
+		llc->ack_must_be_send = 0 ;
+		llc->ack_pf = 0;
+	} else
+		llc_conn_ac_send_i_cmd_p_set_0(sk, ev);
+	return 0;
+}
+
+/**
+ *	llc_conn_ac_send_rr_rsp_f_set_ackpf - ack all rx PDUs not yet acked
+ *	@sk: current connection structure.
+ *	@ev: current event.
+ *
+ *	This action sends an RR response with f-bit set to ack_pf flag as
+ *	acknowledge to all received PDUs which have not been acknowledged, yet,
+ *	if there is any. ack_pf flag indicates if a PDU has been received with
+ *	p-bit set to one. Returns 0 for success, 1 otherwise.
+ */
+int llc_conn_ac_send_rr_rsp_f_set_ackpf(struct sock *sk,
+					struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct sk_buff *skb = llc_alloc_frame();
+
+	if (skb) {
+		struct llc_opt *llc = llc_sk(sk);
+		struct llc_sap *sap = llc->sap;
+		u8 f_bit = llc->ack_pf;
+
+		skb->dev = llc->dev;
+		llc_pdu_header_init(skb, LLC_PDU_TYPE_S, sap->laddr.lsap,
+				    llc->daddr.lsap, LLC_PDU_RSP);
+		llc_pdu_init_as_rr_rsp(skb, f_bit, llc->vR);
+		lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac);
+		rc = 0;
+		llc_conn_send_pdu(sk, skb);
+	}
+	return rc;
+}
+
+/**
+ *	llc_conn_ac_inc_npta_value - tries to make value of npta greater
+ *	@sk: current connection structure.
+ *	@ev: current event.
+ *
+ *	After "inc_cntr" times calling of this action, "npta" increase by one.
+ *	this action tries to make vale of "npta" greater as possible; number of
+ *	acknowledgements decreases by increasing of "npta". Returns 0 for
+ *	success, 1 otherwise.
+ */
+int llc_conn_ac_inc_npta_value(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	struct llc_opt *llc = llc_sk(sk);
+
+	if (!llc->inc_cntr) {
+		llc->dec_step = 0;
+		llc->dec_cntr = llc->inc_cntr = 2;
+		++llc->npta;
+		if (llc->npta > 127)
+			llc->npta = 127 ;
+	} else
+		--llc->inc_cntr;
+	return 0;
+}
+
+/**
+ *	llc_conn_ac_adjust_npta_by_rr - decreases "npta" by one
+ *	@sk: current connection structure.
+ *	@ev: current event.
+ *
+ *	After receiving "dec_cntr" times RR command, this action decreases
+ *	"npta" by one. Returns 0 for success, 1 otherwise.
+ */
+int llc_conn_ac_adjust_npta_by_rr(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	struct llc_opt *llc = llc_sk(sk);
+
+	if (!llc->connect_step && !llc->remote_busy_flag) {
+		if (!llc->dec_step) {
+			if (!llc->dec_cntr) {
+				llc->inc_cntr = llc->dec_cntr = 2;
+				if (llc->npta > 0)
+					llc->npta = llc->npta - 1;
+			} else
+				llc->dec_cntr -=1;
+		}
+	} else
+		llc->connect_step = 0 ;
+	return 0;
+}
+
+/**
+ *	llc_conn_ac_adjust_npta_by_rnr - decreases "npta" by one
+ *	@sk: current connection structure.
+ *	@ev: current event.
+ *
+ *	After receiving "dec_cntr" times RNR command, this action decreases
+ *	"npta" by one. Returns 0 for success, 1 otherwise.
+ */
+int llc_conn_ac_adjust_npta_by_rnr(struct sock *sk,
+				   struct llc_conn_state_ev *ev)
+{
+	struct llc_opt *llc = llc_sk(sk);
+
+	if (llc->remote_busy_flag)
+		if (!llc->dec_step) {
+			if (!llc->dec_cntr) {
+				llc->inc_cntr = llc->dec_cntr = 2;
+				if (llc->npta > 0)
+					--llc->npta;
+			} else
+				--llc->dec_cntr;
+		}
+	return 0;
+}
+
+/**
+ *	llc_conn_ac_dec_tx_win_size - decreases tx window size
+ *	@sk: current connection structure.
+ *	@ev: current event.
+ *
+ *	After receiving of a REJ command or response, transmit window size is
+ *	decreased by number of PDUs which are outstanding yet. Returns 0 for
+ *	success, 1 otherwise.
+ */
+int llc_conn_ac_dec_tx_win_size(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	struct llc_opt *llc = llc_sk(sk);
+	u8 unacked_pdu = skb_queue_len(&llc->pdu_unack_q);
+
+	llc->k -= unacked_pdu;
+	if (llc->k < 2)
+		llc->k = 2;
+	return 0;
+}
+
+/**
+ *	llc_conn_ac_inc_tx_win_size - tx window size is inc by 1
+ *	@sk: current connection structure.
+ *	@ev: current event.
+ *
+ *	After receiving an RR response with f-bit set to one, transmit window
+ *	size is increased by one. Returns 0 for success, 1 otherwise.
+ */
+int llc_conn_ac_inc_tx_win_size(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	struct llc_opt *llc = llc_sk(sk);
+
+	llc->k += 1;
+	if (llc->k > 128)
+		llc->k = 128 ;
+	return 0;
+}
+
+int llc_conn_ac_stop_all_timers(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	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;
+}
+
+int llc_conn_ac_stop_other_timers(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	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;
+}
+
+int llc_conn_ac_start_ack_timer(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	struct llc_opt *llc = llc_sk(sk);
+
+	del_timer(&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;
+}
+
+int llc_conn_ac_start_rej_timer(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	struct llc_opt *llc = llc_sk(sk);
+
+	del_timer(&llc->rej_sent_timer.timer);
+	llc->rej_sent_timer.timer.expires = jiffies +
+					    llc->rej_sent_timer.expire * HZ;
+	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;
+}
+
+int llc_conn_ac_start_ack_tmr_if_not_running(struct sock *sk,
+					     struct llc_conn_state_ev *ev)
+{
+	struct llc_opt *llc = llc_sk(sk);
+
+	if (!llc->ack_timer.running) {
+		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;
+}
+
+int llc_conn_ac_stop_ack_timer(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	del_timer(&llc_sk(sk)->ack_timer.timer);
+	llc_sk(sk)->ack_timer.running = 0;
+	return 0;
+}
+
+int llc_conn_ac_stop_p_timer(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	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;
+}
+
+int llc_conn_ac_stop_rej_timer(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	del_timer(&llc_sk(sk)->rej_sent_timer.timer);
+	llc_sk(sk)->rej_sent_timer.running = 0;
+	return 0;
+}
+
+int llc_conn_ac_upd_nr_received(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	int acked;
+	u16 unacked = 0;
+	u8 fbit;
+	struct sk_buff *skb = ev->data.pdu.skb;
+	llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)skb->nh.raw;
+	struct llc_opt *llc = llc_sk(sk);
+
+	llc->last_nr = PDU_SUPV_GET_Nr(rx_pdu);
+	acked = llc_conn_remove_acked_pdus(sk, llc->last_nr, &unacked);
+	/* On loopback we don't queue I frames in unack_pdu_q queue. */
+	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
+			 * can send data and must inform to upper layer. */
+			llc->failed_data_req = 0;
+			llc_conn_ac_data_confirm(sk, ev);
+		}
+		if (unacked) {
+			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;
+	       }
+	} else if (llc->failed_data_req) {
+		llc_pdu_decode_pf_bit(skb, &fbit);
+		if (fbit == 1) {
+			llc->failed_data_req = 0;
+			llc_conn_ac_data_confirm(sk, ev);
+		}
+	}
+	return 0;
+}
+
+int llc_conn_ac_upd_p_flag(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	struct sk_buff *skb = ev->data.pdu.skb;
+	llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)skb->nh.raw;
+	u8 f_bit;
+
+	if (!LLC_PDU_IS_RSP(rx_pdu) &&
+	    !llc_pdu_decode_pf_bit(skb, &f_bit) && f_bit) {
+		llc_sk(sk)->p_flag = 0;
+		llc_conn_ac_stop_p_timer(sk, ev);
+	}
+	return 0;
+}
+
+int llc_conn_ac_set_data_flag_2(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_sk(sk)->data_flag = 2;
+	return 0;
+}
+
+int llc_conn_ac_set_data_flag_0(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_sk(sk)->data_flag = 0;
+	return 0;
+}
+
+int llc_conn_ac_set_data_flag_1(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_sk(sk)->data_flag = 1;
+	return 0;
+}
+
+int llc_conn_ac_set_data_flag_1_if_data_flag_eq_0(struct sock *sk,
+						  struct llc_conn_state_ev *ev)
+{
+	if (!llc_sk(sk)->data_flag)
+		llc_sk(sk)->data_flag = 1;
+	return 0;
+}
+
+int llc_conn_ac_set_p_flag_0(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_sk(sk)->p_flag = 0;
+	return 0;
+}
+
+int llc_conn_ac_set_p_flag_1(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_sk(sk)->p_flag = 1;
+	return 0;
+}
+
+int llc_conn_ac_set_remote_busy_0(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_sk(sk)->remote_busy_flag = 0;
+	return 0;
+}
+
+int llc_conn_ac_set_cause_flag_0(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_sk(sk)->cause_flag = 0;
+	return 0;
+}
+
+int llc_conn_ac_set_cause_flag_1(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_sk(sk)->cause_flag = 1;
+	return 0;
+}
+
+int llc_conn_ac_set_retry_cnt_0(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_sk(sk)->retry_count = 0;
+	return 0;
+}
+
+int llc_conn_ac_inc_retry_cnt_by_1(struct sock *sk,
+				   struct llc_conn_state_ev *ev)
+{
+	llc_sk(sk)->retry_count++;
+	return 0;
+}
+
+int llc_conn_ac_set_vr_0(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_sk(sk)->vR = 0;
+	return 0;
+}
+
+int llc_conn_ac_inc_vr_by_1(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_sk(sk)->vR = PDU_GET_NEXT_Vr(llc_sk(sk)->vR);
+	return 0;
+}
+
+int llc_conn_ac_set_vs_0(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_sk(sk)->vS = 0;
+	return 0;
+}
+
+int llc_conn_ac_set_vs_nr(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_sk(sk)->vS = llc_sk(sk)->last_nr;
+	return 0;
+}
+
+int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_sk(sk)->vS = (llc_sk(sk)->vS + 1) % 128;
+	return 0;
+}
+
+int llc_conn_ac_set_f_flag_p(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_pdu_decode_pf_bit(ev->data.pdu.skb, &llc_sk(sk)->f_flag);
+	return 0;
+}
+
+void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data)
+{
+	struct sock *sk = (struct sock *)timeout_data;
+	struct llc_conn_state_ev *ev;
+
+	llc_sk(sk)->pf_cycle_timer.running = 0;
+	ev = llc_conn_alloc_ev(sk);
+	if (ev) {
+		ev->type = LLC_CONN_EV_TYPE_P_TMR;
+		ev->data.tmr.timer_specific = NULL;
+		llc_process_tmr_ev(sk, ev);
+	}
+}
+
+static void llc_conn_busy_tmr_cb(unsigned long timeout_data)
+{
+	struct sock *sk = (struct sock *)timeout_data;
+	struct llc_conn_state_ev *ev;
+
+	llc_sk(sk)->busy_state_timer.running = 0;
+	ev = llc_conn_alloc_ev(sk);
+	if (ev) {
+		ev->type = LLC_CONN_EV_TYPE_BUSY_TMR;
+		ev->data.tmr.timer_specific = NULL;
+		llc_process_tmr_ev(sk, ev);
+	}
+}
+
+void llc_conn_ack_tmr_cb(unsigned long timeout_data)
+{
+	struct sock* sk = (struct sock *)timeout_data;
+	struct llc_conn_state_ev *ev;
+
+	llc_sk(sk)->ack_timer.running = 0;
+	ev = llc_conn_alloc_ev(sk);
+	if (ev) {
+		ev->type = LLC_CONN_EV_TYPE_ACK_TMR;
+		ev->data.tmr.timer_specific = NULL;
+		llc_process_tmr_ev(sk, ev);
+	}
+}
+
+static void llc_conn_rej_tmr_cb(unsigned long timeout_data)
+{
+	struct sock *sk = (struct sock *)timeout_data;
+	struct llc_conn_state_ev *ev;
+
+	llc_sk(sk)->rej_sent_timer.running = 0;
+	ev = llc_conn_alloc_ev(sk);
+	if (ev) {
+		ev->type = LLC_CONN_EV_TYPE_REJ_TMR;
+		ev->data.tmr.timer_specific = NULL;
+		llc_process_tmr_ev(sk, ev);
+	}
+}
+
+int llc_conn_ac_rst_vs(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_sk(sk)->X = llc_sk(sk)->vS;
+	llc_conn_ac_set_vs_nr(sk, ev);
+	return 0;
+}
+
+int llc_conn_ac_upd_vs(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *rx_pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+	u8 nr = PDU_SUPV_GET_Nr(rx_pdu);
+
+	if (llc_circular_between(llc_sk(sk)->vS, nr, llc_sk(sk)->X))
+		llc_conn_ac_set_vs_nr(sk, ev);
+	return 0;
+}
+
+/*
+ * Non-standard actions; these not contained in IEEE specification; for
+ * our own usage
+ */
+/**
+ *	llc_conn_disc - removes connection from SAP list and frees it
+ *	@sk: closed connection
+ *	@ev: occurred event
+ *
+ *	Returns 2, to indicate the state machine that the connection was freed.
+ */
+int llc_conn_disc(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_sap_unassign_sock(llc_sk(sk)->sap, sk);
+	llc_sock_free(sk);
+	return 2;
+}
+
+/**
+ *	llc_conn_reset - resets connection
+ *	@sk : reseting connection.
+ *	@ev: occurred event.
+ *
+ *	Stop all timers, empty all queues and reset all flags.
+ */
+int llc_conn_reset(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	llc_sock_reset(sk);
+	return 0;
+}
+
+/**
+ *	llc_circular_between - designates that b is between a and c or not
+ *	@a: lower bound
+ *	@b: element to see if is between a and b
+ *	@c: upper bound
+ *
+ *	This function designates that b is between a and c or not (for example,
+ *	0 is between 127 and 1). Returns 1 if b is between a and c, 0
+ *	otherwise.
+ */
+u8 llc_circular_between(u8 a, u8 b, u8 c)
+{
+	b = b - a;
+	c = c - a;
+	return b <= c;
+}
+
+/**
+ *	llc_process_tmr_ev - timer backend
+ *	@sk: active connection
+ *	@ev: occurred event
+ *
+ *	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.
+ */
+static void llc_process_tmr_ev(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	bh_lock_sock(sk);
+	if (llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) {
+		printk(KERN_WARNING "timer called on closed connection\n");
+		llc_conn_free_ev(ev);
+		goto out;
+	}
+	if (!sk->lock.users)
+		llc_conn_send_ev(sk, ev);
+	else {
+		struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
+
+		if (skb) {
+			skb->cb[0] = LLC_EVENT;
+			skb->data = (void *)ev;
+			sk_add_backlog(sk, skb);
+		} else
+			llc_conn_free_ev(ev);
+	}
+out:	bh_unlock_sock(sk);
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/llc/llc_c_ev.c linux.20pre10-ac2/net/llc/llc_c_ev.c
--- linux.20pre10/net/llc/llc_c_ev.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/net/llc/llc_c_ev.c	2002-08-06 15:42:06.000000000 +0100
@@ -0,0 +1,872 @@
+/*
+ * llc_c_ev.c - Connection component state transition event qualifiers
+ *
+ * A 'state' consists of a number of possible event matching functions,
+ * the actions associated with each being executed when that event is
+ * matched; a 'state machine' accepts events in a serial fashion from an
+ * event queue. Each event is passed to each successive event matching
+ * function until a match is made (the event matching function returns
+ * success, or '0') or the list of event matching functions is exhausted.
+ * If a match is made, the actions associated with the event are executed
+ * and the state is changed to that event's transition state. Before some
+ * events are recognized, even after a match has been made, a certain
+ * number of 'event qualifier' functions must also be executed. If these
+ * all execute successfully, then the event is finally executed.
+ *
+ * These event functions must return 0 for success, to show a matched
+ * event, of 1 if the event does not match. Event qualifier functions
+ * must return a 0 for success or a non-zero for failure. Each function
+ * is simply responsible for verifying one single thing and returning
+ * either a success or failure.
+ *
+ * All of followed event functions are described in 802.2 LLC Protocol
+ * standard document except two functions that we added that will explain
+ * in their comments, at below.
+ *
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/netdevice.h>
+#include <net/llc_conn.h>
+#include <net/llc_sap.h>
+#include <net/sock.h>
+#include <net/llc_c_ev.h>
+#include <net/llc_pdu.h>
+
+#if 0
+#define dprintk(args...) printk(KERN_DEBUG args)
+#else
+#define dprintk(args...)
+#endif
+
+extern u16 llc_circular_between(u8 a, u8 b, u8 c);
+
+/**
+ *	llc_util_ns_inside_rx_window - check if sequence number is in rx window
+ *	@ns: sequence number of received pdu.
+ *	@vr: sequence number which receiver expects to receive.
+ *	@rw: receive window size of receiver.
+ *
+ *	Checks if sequence number of received PDU is in range of receive
+ *	window. Returns 0 for success, 1 otherwise
+ */
+static u16 llc_util_ns_inside_rx_window(u8 ns, u8 vr, u8 rw)
+{
+	return !llc_circular_between(vr, ns,
+				     (vr + rw - 1) % LLC_2_SEQ_NBR_MODULO);
+}
+
+/**
+ *	llc_util_nr_inside_tx_window - check if sequence number is in tx window
+ *	@sk: current connection.
+ *	@nr: N(R) of received PDU.
+ *
+ *	This routine checks if N(R) of received PDU is in range of transmit
+ *	window; on the other hand checks if received PDU acknowledges some
+ *	outstanding PDUs that are in transmit window. Returns 0 for success, 1
+ *	otherwise.
+ */
+static u16 llc_util_nr_inside_tx_window(struct sock *sk, u8 nr)
+{
+	u8 nr1, nr2;
+	struct sk_buff *skb;
+	llc_pdu_sn_t *pdu;
+	struct llc_opt *llc = llc_sk(sk);
+	int rc = 0;
+
+	if (llc->dev->flags & IFF_LOOPBACK)
+		goto out;
+	rc = 1;
+	if (!skb_queue_len(&llc->pdu_unack_q))
+		goto out;
+	skb = skb_peek(&llc->pdu_unack_q);
+	pdu = (llc_pdu_sn_t *)skb->nh.raw;
+	nr1 = LLC_I_GET_NS(pdu);
+	skb = skb_peek_tail(&llc->pdu_unack_q);
+	pdu = (llc_pdu_sn_t *)skb->nh.raw;
+	nr2 = LLC_I_GET_NS(pdu);
+	rc = !llc_circular_between(nr1, nr, (nr2 + 1) % LLC_2_SEQ_NBR_MODULO);
+out:	return rc;
+}
+
+int llc_conn_ev_conn_req(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	return ev->data.prim.prim == LLC_CONN_PRIM &&
+	       ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1;
+}
+
+int llc_conn_ev_conn_resp(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	return ev->data.prim.prim == LLC_CONN_PRIM &&
+	       ev->data.prim.type == LLC_PRIM_TYPE_RESP ? 0 : 1;
+}
+
+int llc_conn_ev_data_req(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	return ev->data.prim.prim == LLC_DATA_PRIM &&
+	       ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1;
+}
+
+int llc_conn_ev_disc_req(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	return ev->data.prim.prim == LLC_DISC_PRIM &&
+	       ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1;
+}
+
+int llc_conn_ev_rst_req(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	return ev->data.prim.prim == LLC_RESET_PRIM &&
+	       ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1;
+}
+
+int llc_conn_ev_rst_resp(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	return ev->data.prim.prim == LLC_RESET_PRIM &&
+	       ev->data.prim.type == LLC_PRIM_TYPE_RESP ? 0 : 1;
+}
+
+int llc_conn_ev_local_busy_detected(struct sock *sk,
+				    struct llc_conn_state_ev *ev)
+{
+	return ev->type == LLC_CONN_EV_TYPE_SIMPLE &&
+	       ev->data.a.ev == LLC_CONN_EV_LOCAL_BUSY_DETECTED ? 0 : 1;
+}
+
+int llc_conn_ev_local_busy_cleared(struct sock *sk,
+				   struct llc_conn_state_ev *ev)
+{
+	return ev->type == LLC_CONN_EV_TYPE_SIMPLE &&
+	       ev->data.a.ev == LLC_CONN_EV_LOCAL_BUSY_CLEARED ? 0 : 1;
+}
+
+int llc_conn_ev_rx_bad_pdu(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	return 1;
+}
+
+int llc_conn_ev_rx_disc_cmd_pbit_set_x(struct sock *sk,
+				       struct llc_conn_state_ev *ev)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_U(pdu) &&
+	       LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_DISC ? 0 : 1;
+}
+
+int llc_conn_ev_rx_dm_rsp_fbit_set_x(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_U(pdu) &&
+	       LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_DM ? 0 : 1;
+}
+
+int llc_conn_ev_rx_frmr_rsp_fbit_set_x(struct sock *sk,
+				       struct llc_conn_state_ev *ev)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_U(pdu) &&
+	       LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_FRMR ? 0 : 1;
+}
+
+int llc_conn_ev_rx_i_cmd_pbit_set_0(struct sock *sk,
+				    struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
+	       !LLC_I_PF_IS_0(pdu) &&
+	       LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1;
+}
+
+int llc_conn_ev_rx_i_cmd_pbit_set_1(struct sock *sk,
+				    struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
+	       !LLC_I_PF_IS_1(pdu) &&
+	       LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1;
+}
+
+int llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns(struct sock *sk,
+					      struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+	u8 vr = llc_sk(sk)->vR;
+	u8 ns = LLC_I_GET_NS(pdu);
+
+	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
+	       !LLC_I_PF_IS_0(pdu) && ns != vr &&
+	       !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1;
+}
+
+int llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns(struct sock *sk,
+					      struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+	u8 vr = llc_sk(sk)->vR;
+	u8 ns = LLC_I_GET_NS(pdu);
+
+	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
+	       !LLC_I_PF_IS_1(pdu) && ns != vr &&
+	       !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1;
+}
+
+int llc_conn_ev_rx_i_cmd_pbit_set_x_inval_ns(struct sock *sk,
+					     struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t * pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+	u8 vr = llc_sk(sk)->vR;
+	u8 ns = LLC_I_GET_NS(pdu);
+	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);
+	return rc;
+}
+
+int llc_conn_ev_rx_i_rsp_fbit_set_0(struct sock *sk,
+				    struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
+	       !LLC_I_PF_IS_0(pdu) &&
+	       LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1;
+}
+
+int llc_conn_ev_rx_i_rsp_fbit_set_1(struct sock *sk,
+				    struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
+	       !LLC_I_PF_IS_1(pdu) &&
+	       LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1;
+}
+
+int llc_conn_ev_rx_i_rsp_fbit_set_x(struct sock *sk,
+				    struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
+	       LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1;
+}
+
+int llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns(struct sock *sk,
+					      struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+	u8 vr = llc_sk(sk)->vR;
+	u8 ns = LLC_I_GET_NS(pdu);
+
+	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
+	       !LLC_I_PF_IS_0(pdu) && ns != vr &&
+	       !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1;
+}
+
+int llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns(struct sock *sk,
+					      struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+	u8 vr = llc_sk(sk)->vR;
+	u8 ns = LLC_I_GET_NS(pdu);
+
+	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
+	       !LLC_I_PF_IS_1(pdu) && ns != vr &&
+	       !llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1;
+}
+
+int llc_conn_ev_rx_i_rsp_fbit_set_x_unexpd_ns(struct sock *sk,
+					      struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+	u8 vr = llc_sk(sk)->vR;
+	u8 ns = LLC_I_GET_NS(pdu);
+
+	return !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;
+}
+
+int llc_conn_ev_rx_i_rsp_fbit_set_x_inval_ns(struct sock *sk,
+					     struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+	u8 vr = llc_sk(sk)->vR;
+	u8 ns = LLC_I_GET_NS(pdu);
+	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);
+	return rc;
+}
+
+int llc_conn_ev_rx_rej_cmd_pbit_set_0(struct sock *sk,
+				      struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
+	       !LLC_S_PF_IS_0(pdu) &&
+	       LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_REJ ? 0 : 1;
+}
+
+int llc_conn_ev_rx_rej_cmd_pbit_set_1(struct sock *sk,
+				      struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
+	       !LLC_S_PF_IS_1(pdu) &&
+	       LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_REJ ? 0 : 1;
+}
+
+int llc_conn_ev_rx_rej_rsp_fbit_set_0(struct sock *sk,
+				      struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
+	       !LLC_S_PF_IS_0(pdu) &&
+	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_REJ ? 0 : 1;
+}
+
+int llc_conn_ev_rx_rej_rsp_fbit_set_1(struct sock *sk,
+				      struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
+	       !LLC_S_PF_IS_1(pdu) &&
+	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_REJ ? 0 : 1;
+}
+
+int llc_conn_ev_rx_rej_rsp_fbit_set_x(struct sock *sk,
+				      struct llc_conn_state_ev *ev)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
+	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_REJ ? 0 : 1;
+}
+
+int llc_conn_ev_rx_rnr_cmd_pbit_set_0(struct sock *sk,
+				      struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
+	       !LLC_S_PF_IS_0(pdu) &&
+	       LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RNR ? 0 : 1;
+}
+
+int llc_conn_ev_rx_rnr_cmd_pbit_set_1(struct sock *sk,
+				      struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
+	       !LLC_S_PF_IS_1(pdu) &&
+	       LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RNR ? 0 : 1;
+}
+
+int llc_conn_ev_rx_rnr_rsp_fbit_set_0(struct sock *sk,
+				      struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
+	       !LLC_S_PF_IS_0(pdu) &&
+	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RNR ? 0 : 1;
+}
+
+int llc_conn_ev_rx_rnr_rsp_fbit_set_1(struct sock *sk,
+				      struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
+	       !LLC_S_PF_IS_1(pdu) &&
+	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RNR ? 0 : 1;
+}
+
+int llc_conn_ev_rx_rr_cmd_pbit_set_0(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
+	       !LLC_S_PF_IS_0(pdu) &&
+	       LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RR ? 0 : 1;
+}
+
+int llc_conn_ev_rx_rr_cmd_pbit_set_1(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
+	       !LLC_S_PF_IS_1(pdu) &&
+	       LLC_S_PDU_CMD(pdu) == LLC_2_PDU_CMD_RR ? 0 : 1;
+}
+
+int llc_conn_ev_rx_rr_rsp_fbit_set_0(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
+	       !LLC_S_PF_IS_0(pdu) &&
+	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1;
+}
+
+int llc_conn_ev_rx_rr_rsp_fbit_set_1(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
+	       !LLC_S_PF_IS_1(pdu) &&
+	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1;
+}
+
+int llc_conn_ev_rx_sabme_cmd_pbit_set_x(struct sock *sk,
+					struct llc_conn_state_ev *ev)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_U(pdu) &&
+	       LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_SABME ? 0 : 1;
+}
+
+int llc_conn_ev_rx_ua_rsp_fbit_set_x(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_U(pdu) &&
+	       LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_UA ? 0 : 1;
+}
+
+int llc_conn_ev_rx_xxx_cmd_pbit_set_1(struct sock *sk,
+				      struct llc_conn_state_ev *ev)
+{
+	u16 rc = 1;
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	if (!LLC_PDU_IS_CMD(pdu)) {
+		if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) {
+			if (!LLC_I_PF_IS_1(pdu))
+				rc = 0;
+		} else if (!LLC_PDU_TYPE_IS_U(pdu) && !LLC_U_PF_IS_1(pdu))
+			rc = 0;
+	}
+	return rc;
+}
+
+int llc_conn_ev_rx_xxx_cmd_pbit_set_0(struct sock *sk,
+				      struct llc_conn_state_ev *ev)
+{
+	u16 rc = 1;
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	if (!LLC_PDU_IS_CMD(pdu)) {
+		if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) {
+			if (!LLC_I_PF_IS_0(pdu))
+				rc = 0;
+		} else if (!LLC_PDU_TYPE_IS_U(pdu))
+			switch (LLC_U_PDU_CMD(pdu)) {
+				case LLC_2_PDU_CMD_SABME:
+				case LLC_2_PDU_CMD_DISC:
+					if (!LLC_U_PF_IS_0(pdu))
+						rc = 0;
+					break;
+			}
+	}
+	return rc;
+}
+
+int llc_conn_ev_rx_xxx_cmd_pbit_set_x(struct sock *sk,
+				      struct llc_conn_state_ev *ev)
+{
+	u16 rc = 1;
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+	if (!LLC_PDU_IS_CMD(pdu)) {
+		if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu))
+			rc = 0;
+		else if (!LLC_PDU_TYPE_IS_U(pdu))
+			switch (LLC_U_PDU_CMD(pdu)) {
+				case LLC_2_PDU_CMD_SABME:
+				case LLC_2_PDU_CMD_DISC:
+					rc = 0;
+					break;
+			}
+	}
+	return rc;
+}
+
+int llc_conn_ev_rx_xxx_rsp_fbit_set_1(struct sock *sk,
+				      struct llc_conn_state_ev *ev)
+{
+	u16 rc = 1;
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+	if (!LLC_PDU_IS_RSP(pdu)) {
+		if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) {
+			if (!LLC_I_PF_IS_1(pdu))
+				rc = 0;
+		} else if (!LLC_PDU_TYPE_IS_U(pdu))
+			switch (LLC_U_PDU_RSP(pdu)) {
+				case LLC_2_PDU_RSP_UA:
+				case LLC_2_PDU_RSP_DM:
+				case LLC_2_PDU_RSP_FRMR:
+					if (!LLC_U_PF_IS_1(pdu))
+						rc = 0;
+					break;
+			}
+	}
+	return rc;
+}
+
+int llc_conn_ev_rx_xxx_rsp_fbit_set_x(struct sock *sk,
+				      struct llc_conn_state_ev *ev)
+{
+	u16 rc = 1;
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+	if (!LLC_PDU_IS_RSP(pdu)) {
+		if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu))
+			rc = 0;
+		else if (!LLC_PDU_TYPE_IS_U(pdu))
+			switch (LLC_U_PDU_RSP(pdu)) {
+				case LLC_2_PDU_RSP_UA:
+				case LLC_2_PDU_RSP_DM:
+				case LLC_2_PDU_RSP_FRMR:
+					rc = 0;
+					break;
+			}
+	}
+
+	return rc;
+}
+
+int llc_conn_ev_rx_xxx_yyy(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	u16 rc = 1;
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+	if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu))
+		rc = 0;
+	else if (!LLC_PDU_TYPE_IS_U(pdu))
+		switch (LLC_U_PDU_CMD(pdu)) {
+			case LLC_2_PDU_CMD_SABME:
+			case LLC_2_PDU_CMD_DISC:
+			case LLC_2_PDU_RSP_UA:
+			case LLC_2_PDU_RSP_DM:
+			case LLC_2_PDU_RSP_FRMR:
+				rc = 0;
+				break;
+		}
+	return rc;
+}
+
+int llc_conn_ev_rx_zzz_cmd_pbit_set_x_inval_nr(struct sock *sk,
+					       struct llc_conn_state_ev *ev)
+{
+	u16 rc = 1;
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+	u8 vs = llc_sk(sk)->vS;
+	u8 nr = LLC_I_GET_NR(pdu);
+
+	if (!LLC_PDU_IS_CMD(pdu)) {
+		if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) {
+			if (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);
+				rc = 0;
+			}
+		}
+	}
+	return rc;
+}
+
+int llc_conn_ev_rx_zzz_rsp_fbit_set_x_inval_nr(struct sock *sk,
+					       struct llc_conn_state_ev *ev)
+{
+	u16 rc = 1;
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+	u8 vs = llc_sk(sk)->vS;
+	u8 nr = LLC_I_GET_NR(pdu);
+
+	if (!LLC_PDU_IS_RSP(pdu)) {
+		if (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) {
+			if (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);
+			}
+		}
+	}
+	return rc;
+}
+
+int llc_conn_ev_rx_any_frame(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	return 0;
+}
+
+int llc_conn_ev_p_tmr_exp(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	return ev->type != LLC_CONN_EV_TYPE_P_TMR;
+}
+
+int llc_conn_ev_ack_tmr_exp(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	return ev->type != LLC_CONN_EV_TYPE_ACK_TMR;
+}
+
+int llc_conn_ev_rej_tmr_exp(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	return ev->type != LLC_CONN_EV_TYPE_REJ_TMR;
+}
+
+int llc_conn_ev_busy_tmr_exp(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	return ev->type != LLC_CONN_EV_TYPE_BUSY_TMR;
+}
+
+int llc_conn_ev_any_tmr_exp(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+
+	return ev->type == LLC_CONN_EV_TYPE_P_TMR ||
+	       ev->type == LLC_CONN_EV_TYPE_ACK_TMR ||
+	       ev->type == LLC_CONN_EV_TYPE_REJ_TMR ||
+	       ev->type == LLC_CONN_EV_TYPE_BUSY_TMR ? 0 : 1;
+}
+
+int llc_conn_ev_init_p_f_cycle(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	return 1;
+}
+
+int llc_conn_ev_tx_buffer_full(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	return ev->type == LLC_CONN_EV_TYPE_SIMPLE &&
+	       ev->data.a.ev == LLC_CONN_EV_TX_BUFF_FULL ? 0 : 1;
+}
+
+/* --------------------- EVENT QUALIFIER FUNCTIONS ----------------------- *
+ * these functions simply verify the value of a state flag associated with
+ * the connection and return either a 0 for success or a non-zero value
+ * for not-success; verify the event is the type we expect
+ * ----------------------------------------------------------------------- */
+
+int llc_conn_ev_qlfy_data_flag_eq_1(struct sock *sk,
+				    struct llc_conn_state_ev *ev)
+{
+	return llc_sk(sk)->data_flag != 1;
+}
+
+int llc_conn_ev_qlfy_data_flag_eq_0(struct sock *sk,
+				    struct llc_conn_state_ev *ev)
+{
+	return llc_sk(sk)->data_flag;
+}
+
+int llc_conn_ev_qlfy_data_flag_eq_2(struct sock *sk,
+				    struct llc_conn_state_ev *ev)
+{
+	return llc_sk(sk)->data_flag != 2;
+}
+
+int llc_conn_ev_qlfy_p_flag_eq_1(struct sock *sk,
+				 struct llc_conn_state_ev *ev)
+{
+	return llc_sk(sk)->p_flag != 1;
+}
+
+/**
+ *	conn_ev_qlfy_last_frame_eq_1 - checks if frame is last in tx window
+ *	@sk: current connection structure.
+ *	@ev: current event.
+ *
+ *	This function determines when frame which is sent, is last frame of
+ *	transmit window, if it is then this function return zero else return
+ *	one.  This function is used for sending last frame of transmit window
+ *	as I-format command with p-bit set to one. Returns 0 if frame is last
+ *	frame, 1 otherwise.
+ */
+int llc_conn_ev_qlfy_last_frame_eq_1(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	return !(skb_queue_len(&llc_sk(sk)->pdu_unack_q) + 1 == llc_sk(sk)->k);
+}
+
+/**
+ *	conn_ev_qlfy_last_frame_eq_0 - checks if frame isn't last in tx window
+ *	@sk: current connection structure.
+ *	@ev: current event.
+ *
+ *	This function determines when frame which is sent, isn't last frame of
+ *	transmit window, if it isn't then this function return zero else return
+ *	one. Returns 0 if frame isn't last frame, 1 otherwise.
+ */
+int llc_conn_ev_qlfy_last_frame_eq_0(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	return skb_queue_len(&llc_sk(sk)->pdu_unack_q) + 1 == llc_sk(sk)->k;
+}
+
+int llc_conn_ev_qlfy_p_flag_eq_0(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	return llc_sk(sk)->p_flag;
+}
+
+int llc_conn_ev_qlfy_p_flag_eq_f(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	u8 f_bit;
+	struct sk_buff *skb;
+
+	if (ev->type == LLC_CONN_EV_TYPE_PDU)
+		skb = ev->data.pdu.skb;
+	else
+		skb = ev->data.prim.data->data->conn.skb;
+	llc_pdu_decode_pf_bit(skb, &f_bit);
+	return llc_sk(sk)->p_flag == f_bit ? 0 : 1;
+}
+
+int llc_conn_ev_qlfy_remote_busy_eq_0(struct sock *sk,
+				      struct llc_conn_state_ev *ev)
+{
+	return llc_sk(sk)->remote_busy_flag;
+}
+
+int llc_conn_ev_qlfy_remote_busy_eq_1(struct sock *sk,
+				      struct llc_conn_state_ev *ev)
+{
+	return !llc_sk(sk)->remote_busy_flag;
+}
+
+int llc_conn_ev_qlfy_retry_cnt_lt_n2(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	return !(llc_sk(sk)->retry_count < llc_sk(sk)->n2);
+}
+
+int llc_conn_ev_qlfy_retry_cnt_gte_n2(struct sock *sk,
+				      struct llc_conn_state_ev *ev)
+{
+	return !(llc_sk(sk)->retry_count >= llc_sk(sk)->n2);
+}
+
+int llc_conn_ev_qlfy_s_flag_eq_1(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	return !llc_sk(sk)->s_flag;
+}
+
+int llc_conn_ev_qlfy_s_flag_eq_0(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	return llc_sk(sk)->s_flag;
+}
+
+int llc_conn_ev_qlfy_cause_flag_eq_1(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	return !llc_sk(sk)->cause_flag;
+}
+
+int llc_conn_ev_qlfy_cause_flag_eq_0(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	return llc_sk(sk)->cause_flag;
+}
+
+int llc_conn_ev_qlfy_init_p_f_cycle(struct sock *sk,
+				    struct llc_conn_state_ev *ev)
+{
+	return 0;
+}
+
+int llc_conn_ev_qlfy_set_status_conn(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	ev->status = LLC_STATUS_CONN;
+	return 0;
+}
+
+int llc_conn_ev_qlfy_set_status_disc(struct sock *sk,
+				     struct llc_conn_state_ev *ev)
+{
+	ev->status = LLC_STATUS_DISC;
+	return 0;
+}
+
+int llc_conn_ev_qlfy_set_status_impossible(struct sock *sk,
+					   struct llc_conn_state_ev *ev)
+{
+	ev->status = LLC_STATUS_IMPOSSIBLE;
+	return 0;
+}
+
+int llc_conn_ev_qlfy_set_status_failed(struct sock *sk,
+				       struct llc_conn_state_ev *ev)
+{
+	ev->status = LLC_STATUS_FAILED;
+	return 0;
+}
+
+int llc_conn_ev_qlfy_set_status_remote_busy(struct sock *sk,
+					    struct llc_conn_state_ev *ev)
+{
+	ev->status = LLC_STATUS_REMOTE_BUSY;
+	return 0;
+}
+
+int llc_conn_ev_qlfy_set_status_received(struct sock *sk,
+					 struct llc_conn_state_ev *ev)
+{
+	ev->status = LLC_STATUS_RECEIVED;
+	return 0;
+}
+
+int llc_conn_ev_qlfy_set_status_refuse(struct sock *sk,
+				       struct llc_conn_state_ev *ev)
+{
+	ev->status = LLC_STATUS_REFUSE;
+	return 0;
+}
+
+int llc_conn_ev_qlfy_set_status_conflict(struct sock *sk,
+					 struct llc_conn_state_ev *ev)
+{
+	ev->status = LLC_STATUS_CONFLICT;
+	return 0;
+}
+
+int llc_conn_ev_qlfy_set_status_rst_done(struct sock *sk,
+					 struct llc_conn_state_ev *ev)
+{
+	ev->status = LLC_STATUS_RESET_DONE;
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/llc/llc_conn.c linux.20pre10-ac2/net/llc/llc_conn.c
--- linux.20pre10/net/llc/llc_conn.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/net/llc/llc_conn.c	2002-08-06 15:42:06.000000000 +0100
@@ -0,0 +1,520 @@
+/*
+ * llc_conn.c - Driver routines for connection component.
+ *
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ *		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <net/llc_if.h>
+#include <net/llc_sap.h>
+#include <net/llc_conn.h>
+#include <net/sock.h>
+#include <net/llc_main.h>
+#include <net/llc_c_ev.h>
+#include <net/llc_c_ac.h>
+#include <net/llc_c_st.h>
+#include <net/llc_mac.h>
+#include <net/llc_pdu.h>
+#include <net/llc_s_ev.h>
+
+static int llc_find_offset(int state, int ev_type);
+static void llc_conn_send_pdus(struct sock *sk);
+static int llc_conn_service(struct sock *sk, struct llc_conn_state_ev *ev);
+static int llc_exec_conn_trans_actions(struct sock *sk,
+				       struct llc_conn_state_trans *trans,
+				       struct llc_conn_state_ev *ev);
+static struct llc_conn_state_trans *
+	     llc_qualify_conn_ev(struct sock *sk, struct llc_conn_state_ev *ev);
+
+/* Offset table on connection states transition diagram */
+static int llc_offset_table[NBR_CONN_STATES][NBR_CONN_EV];
+
+/**
+ *	llc_conn_alloc_event: allocates an event
+ *	@sk: socket that event is associated
+ *
+ *	Returns pointer to allocated connection on success, %NULL on failure.
+ */
+struct llc_conn_state_ev *llc_conn_alloc_ev(struct sock *sk)
+{
+	struct llc_conn_state_ev *ev = NULL;
+
+	/* verify connection is valid, active and open */
+	if (llc_sk(sk)->state != LLC_CONN_OUT_OF_SVC) {
+		/* get event structure to build a station event */
+		ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
+		if (ev)
+			memset(ev, 0, sizeof(*ev));
+	}
+	return ev;
+}
+
+/**
+ *	llc_conn_send_event - sends event to connection state machine
+ *	@sk: connection
+ *	@ev: occurred 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 llc_conn_state_ev *ev)
+{
+	/* sending event to state machine */
+	int rc = llc_conn_service(sk, ev);
+	struct llc_opt *llc = llc_sk(sk);
+	u8 flag = ev->flag;
+	struct llc_prim_if_block *ind_prim = ev->ind_prim;
+	struct llc_prim_if_block *cfm_prim = ev->cfm_prim;
+
+	llc_conn_free_ev(ev);
+#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 __FUNCTION__ ": rc == 2\n");
+		rc = -ECONNABORTED;
+		goto out;
+	}
+#endif	/* THIS_BREAKS_DISCONNECT_NOTIFICATION_BADLY */
+	if (!flag)   /* indicate or confirm not required */
+		goto out;
+	rc = 0;
+	if (ind_prim) /* indication required */
+		llc->sap->ind(ind_prim);
+	if (!cfm_prim)  /* confirmation not required */
+		goto out;
+	/* data confirm has preconditions */
+	if (cfm_prim->prim != LLC_DATA_PRIM) {
+		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:	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);
+}
+
+/**
+ *	llc_conn_rtn_pdu - sends received data pdu to upper layer
+ *	@sk: Active connection
+ *	@skb: Received data frame
+ *	@ev: Occurred event
+ *
+ *	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.
+ */
+void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb,
+		      struct llc_conn_state_ev *ev)
+{
+	struct llc_prim_if_block *prim = &llc_ind_prim;
+	union llc_u_prim_data *prim_data = llc_ind_prim.data;
+
+	prim_data->data.sk   = sk;
+	prim_data->data.pri  = 0;
+	prim_data->data.skb  = skb;
+	prim_data->data.link = llc_sk(sk)->link;
+	prim->data	     = prim_data;
+	prim->prim	     = LLC_DATA_PRIM;
+	prim->sap	     = llc_sk(sk)->sap;
+	ev->flag	     = 1;
+	/* saving prepd prim in event for future use in llc_conn_send_ev */
+	ev->ind_prim	     = prim;
+}
+
+/**
+ *	llc_conn_resend_i_pdu_as_cmd - resend all all unacknowledged I PDUs
+ *	@sk: active connection
+ *	@nr: NR
+ *	@first_p_bit: p_bit value of first pdu
+ *
+ *	Resend all unacknowledged I PDUs, starting with the NR; send first as
+ *	command PDU with P bit equal first_p_bit; if more than one send
+ *	subsequent as command PDUs with P bit equal zero (0).
+ */
+void llc_conn_resend_i_pdu_as_cmd(struct sock *sk, u8 nr, u8 first_p_bit)
+{
+	struct sk_buff *skb;
+	llc_pdu_sn_t *pdu;
+	u16 nbr_unack_pdus;
+	u8 howmany_resend = 0;
+
+	llc_conn_remove_acked_pdus(sk, nr, &nbr_unack_pdus);
+	if (!nbr_unack_pdus)
+		goto out;
+	/* process unack PDUs only if unack queue is not empty; remove
+	 * appropriate PDUs, fix them up, and put them on mac_pdu_q. */
+	while ((skb = skb_dequeue(&llc_sk(sk)->pdu_unack_q)) != NULL) {
+		pdu = (llc_pdu_sn_t *)skb->nh.raw;
+		llc_pdu_set_cmd_rsp(skb, LLC_PDU_CMD);
+		llc_pdu_set_pf_bit(skb, first_p_bit);
+		skb_queue_tail(&sk->write_queue, skb);
+		first_p_bit = 0;
+		llc_sk(sk)->vS = LLC_I_GET_NS(pdu);
+		howmany_resend++;
+	}
+	if (howmany_resend > 0)
+		llc_sk(sk)->vS = (llc_sk(sk)->vS + 1) % LLC_2_SEQ_NBR_MODULO;
+	/* any PDUs to re-send are queued up; start sending to MAC */
+	llc_conn_send_pdus(sk);
+out:;
+}
+
+/**
+ *	llc_conn_resend_i_pdu_as_rsp - Resend all unacknowledged I PDUs
+ *	@sk: active connection.
+ *	@nr: NR
+ *	@first_f_bit: f_bit value of first pdu.
+ *
+ *	Resend all unacknowledged I PDUs, starting with the NR; send first as
+ *	response PDU with F bit equal first_f_bit; if more than one send
+ *	subsequent as response PDUs with F bit equal zero (0).
+ */
+void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr, u8 first_f_bit)
+{
+	struct sk_buff *skb;
+	llc_pdu_sn_t *pdu;
+	u16 nbr_unack_pdus;
+	u8 howmany_resend = 0;
+
+	llc_conn_remove_acked_pdus(sk, nr, &nbr_unack_pdus);
+	if (!nbr_unack_pdus)
+		goto out;
+	/* process unack PDUs only if unack queue is not empty; remove
+	 * appropriate PDUs, fix them up, and put them on mac_pdu_q */
+	while ((skb = skb_dequeue(&llc_sk(sk)->pdu_unack_q)) != NULL) {
+		pdu = (llc_pdu_sn_t *)skb->nh.raw;
+		llc_pdu_set_cmd_rsp(skb, LLC_PDU_RSP);
+		llc_pdu_set_pf_bit(skb, first_f_bit);
+		skb_queue_tail(&sk->write_queue, skb);
+		first_f_bit = 0;
+		llc_sk(sk)->vS = LLC_I_GET_NS(pdu);
+		howmany_resend++;
+	}
+	if (howmany_resend > 0)
+		llc_sk(sk)->vS = (llc_sk(sk)->vS + 1) % LLC_2_SEQ_NBR_MODULO;
+	/* any PDUs to re-send are queued up; start sending to MAC */
+	llc_conn_send_pdus(sk);
+out:;
+}
+
+/**
+ *	llc_conn_remove_acked_pdus - Removes acknowledged pdus from tx queue
+ *	@sk: active connection
+ *	nr: NR
+ *	how_many_unacked: size of pdu_unack_q after removing acked pdus
+ *
+ *	Removes acknowledged pdus from transmit queue (pdu_unack_q). Returns
+ *	the number of pdus that removed from queue.
+ */
+int llc_conn_remove_acked_pdus(struct sock *sk, u8 nr, u16 *how_many_unacked)
+{
+	int pdu_pos, i;
+	struct sk_buff *skb;
+	llc_pdu_sn_t *pdu;
+	int nbr_acked = 0;
+	int q_len = skb_queue_len(&llc_sk(sk)->pdu_unack_q);
+
+	if (!q_len)
+		goto out;
+	skb = skb_peek(&llc_sk(sk)->pdu_unack_q);
+	pdu = (llc_pdu_sn_t *)skb->nh.raw;
+
+	/* finding position of last acked pdu in queue */
+	pdu_pos = ((int)LLC_2_SEQ_NBR_MODULO + (int)nr -
+			(int)LLC_I_GET_NS(pdu)) % LLC_2_SEQ_NBR_MODULO;
+
+	for (i = 0; i < pdu_pos && i < q_len; i++) {
+		skb = skb_dequeue(&llc_sk(sk)->pdu_unack_q);
+		if (skb)
+			kfree_skb(skb);
+		nbr_acked++;
+	}
+out:	*how_many_unacked = skb_queue_len(&llc_sk(sk)->pdu_unack_q);
+	return nbr_acked;
+}
+
+/**
+ *	llc_conn_send_pdus - Sends queued PDUs
+ *	@sk: active connection
+ *
+ *	Sends queued pdus to MAC layer for transmition.
+ */
+static void llc_conn_send_pdus(struct sock *sk)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&sk->write_queue)) != NULL) {
+		llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw;
+
+		if (!LLC_PDU_TYPE_IS_I(pdu) &&
+		    !(skb->dev->flags & IFF_LOOPBACK))
+			skb_queue_tail(&llc_sk(sk)->pdu_unack_q, skb);
+		mac_send_pdu(skb);
+		if (LLC_PDU_TYPE_IS_I(pdu) ||
+		    (skb->dev && skb->dev->flags & IFF_LOOPBACK))
+			kfree_skb(skb);
+	}
+}
+
+/**
+ *	llc_conn_free_ev - free event
+ *	@ev: event to free
+ *
+ *	Free allocated event.
+ */
+void llc_conn_free_ev(struct llc_conn_state_ev *ev)
+{
+	if (ev->type == LLC_CONN_EV_TYPE_PDU) {
+		/* free the frame that binded to this event */
+		llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)ev->data.pdu.skb->nh.raw;
+
+		if (LLC_PDU_TYPE_IS_I(pdu) || !ev->flag || !ev->ind_prim)
+			kfree_skb(ev->data.pdu.skb);
+	}
+	/* free event structure to free list of the same */
+	kfree(ev);
+}
+
+/**
+ *	llc_conn_service - finds transition and changes state of connection
+ *	@sk: connection
+ *	@ev: happened event
+ *
+ *	This function finds transition that matches with happened event, then
+ *	executes related actions and finally changes state of connection.
+ *	Returns 0 for success, 1 for failure.
+ */
+static int llc_conn_service(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	int rc = 1;
+	struct llc_conn_state_trans *trans;
+
+	if (llc_sk(sk)->state > NBR_CONN_STATES)
+		goto out;
+	rc = 0;
+	trans = llc_qualify_conn_ev(sk, ev);
+	if (trans) {
+		rc = llc_exec_conn_trans_actions(sk, trans, ev);
+		if (!rc && trans->next_state != NO_STATE_CHANGE)
+			llc_sk(sk)->state = trans->next_state;
+	}
+out:	return rc;
+}
+
+/**
+ *	llc_qualify_conn_ev - finds transition for event
+ *	@sk: connection
+ *	@ev: happened event
+ *
+ *	This function finds transition that matches with happened event.
+ *	Returns pointer to found transition on success, %NULL otherwise.
+ */
+static struct llc_conn_state_trans *
+	     llc_qualify_conn_ev(struct sock *sk, struct llc_conn_state_ev *ev)
+{
+	struct llc_conn_state_trans **next_trans;
+	llc_conn_ev_qfyr_t *next_qualifier;
+	struct llc_conn_state *curr_state =
+				&llc_conn_state_table[llc_sk(sk)->state - 1];
+
+	/* search thru events for this state until list exhausted or until
+	   no more */
+	for (next_trans = curr_state->transitions +
+		llc_find_offset(llc_sk(sk)->state - 1, ev->type);
+	     (*next_trans)->ev; next_trans++) {
+		if (!((*next_trans)->ev)(sk, ev)) {
+			/* got POSSIBLE event match; the event may require
+			 * qualification based on the values of a number of
+			 * state flags; if all qualifications are met (i.e.,
+			 * if all qualifying functions return success, or 0,
+			 * then this is THE event we're looking for */
+			for (next_qualifier = (*next_trans)->ev_qualifiers;
+			     next_qualifier && *next_qualifier &&
+			     !(*next_qualifier)(sk, ev); next_qualifier++)
+				/* nothing */;
+			if (!next_qualifier || !*next_qualifier)
+				/* all qualifiers executed successfully; this is
+				 * our transition; return it so we can perform
+				 * the associated actions & change the state */
+				return *next_trans;
+		}
+	}
+	return NULL;
+}
+
+/**
+ *	llc_exec_conn_trans_actions - executes related actions
+ *	@sk: connection
+ *	@trans: transition that it's actions must be performed
+ *	@ev: happened 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)
+ */
+static int llc_exec_conn_trans_actions(struct sock *sk,
+				       struct llc_conn_state_trans *trans,
+				       struct llc_conn_state_ev *ev)
+{
+	int rc = 0;
+	llc_conn_action_t *next_action;
+
+	for (next_action = trans->ev_actions;
+	     next_action && *next_action; next_action++) {
+		int rc2 = (*next_action)(sk, ev);
+
+		if (rc2 == 2) {
+			rc = rc2;
+			break;
+		} else if (rc2)
+			rc = 1;
+	}
+	return rc;
+}
+
+/**
+ *	llc_find_sock - Finds connection in sap for the remote/local sap/mac
+ *	@sap: SAP
+ *	@daddr: address of remote LLC (MAC + SAP)
+ *	@laddr: address of local LLC (MAC + SAP)
+ *
+ *	Search connection list of the SAP and finds connection using the remote
+ *	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 *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->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)) {
+			rc = llc->sk;
+			break;
+		}
+	}
+	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.
+ *
+ *	Returns 0 if data can be sent, 1 otherwise.
+ */
+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;
+}
+
+/**
+ *	find_next_offset - finds offset for next category of transitions
+ *	@state: state table.
+ *	@offset: start offset.
+ *
+ *	Finds offset of next category of transitions in transition table.
+ *	Returns the start index of next category.
+ */
+u16 find_next_offset(struct llc_conn_state *state, u16 offset)
+{
+	u16 cnt = 0;
+	struct llc_conn_state_trans **next_trans;
+
+	for (next_trans = state->transitions + offset;
+	     (*next_trans)->ev; next_trans++)
+		++cnt;
+	return cnt;
+}
+
+/**
+ *	llc_build_offset_table - builds offset table of connection
+ *
+ *	Fills offset table of connection state transition table
+ *	(llc_offset_table).
+ */
+void __init llc_build_offset_table(void)
+{
+	struct llc_conn_state *curr_state;
+	int state, ev_type, next_offset;
+
+	memset(llc_offset_table, 0, sizeof(llc_offset_table));
+	for (state = 0; state < NBR_CONN_STATES; state++) {
+		curr_state = &llc_conn_state_table[state];
+		next_offset = 0;
+		for (ev_type = 0; ev_type < NBR_CONN_EV; ev_type++) {
+			llc_offset_table[state][ev_type] = next_offset;
+			next_offset += find_next_offset(curr_state,
+							next_offset) + 1;
+		}
+	}
+}
+
+/**
+ *	llc_find_offset - finds start offset of category of transitions
+ *	@state: state of connection
+ *	@ev_type: type of happened event
+ *
+ *	Finds start offset of desired category of transitions. Returns the
+ *	desired start offset.
+ */
+static int llc_find_offset(int state, int ev_type)
+{
+	int rc = 0;
+	/* at this stage, llc_offset_table[..][2] is not important. it is for
+	 * init_pf_cycle and I don't know what is it. */
+	switch (ev_type) {
+		case LLC_CONN_EV_TYPE_PRIM:
+			rc = llc_offset_table[state][0]; break;
+		case LLC_CONN_EV_TYPE_PDU:
+			rc = llc_offset_table[state][4]; break;
+		case LLC_CONN_EV_TYPE_SIMPLE:
+			rc = llc_offset_table[state][1]; break;
+		case LLC_CONN_EV_TYPE_P_TMR:
+		case LLC_CONN_EV_TYPE_ACK_TMR:
+		case LLC_CONN_EV_TYPE_REJ_TMR:
+		case LLC_CONN_EV_TYPE_BUSY_TMR:
+			rc = llc_offset_table[state][3]; break;
+	}
+	return rc;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/llc/llc_c_st.c linux.20pre10-ac2/net/llc/llc_c_st.c
--- linux.20pre10/net/llc/llc_c_st.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/net/llc/llc_c_st.c	2002-08-06 15:42:06.000000000 +0100
@@ -0,0 +1,4897 @@
+/*
+ * llc_c_st.c - This module contains state transition of connection component.
+ *
+ * Description of event functions and actions there is in 802.2 LLC standard,
+ * or in "llc_c_ac.c" and "llc_c_ev.c" modules.
+ *
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/types.h>
+#include <net/llc_if.h>
+#include <net/llc_sap.h>
+#include <net/llc_c_ev.h>
+#include <net/llc_c_ac.h>
+#include <net/llc_c_st.h>
+
+#define LLC_NO_EVENT_QUALIFIERS   NULL
+#define LLC_NO_TRANSITION_ACTIONS NULL
+
+/* ----------------- COMMON CONNECTION STATE transitions ----------------- *
+ * Common transitions for
+ * LLC_CONN_STATE_NORMAL,
+ * LLC_CONN_STATE_BUSY,
+ * LLC_CONN_STATE_REJ,
+ * LLC_CONN_STATE_AWAIT,
+ * LLC_CONN_STATE_AWAIT_BUSY and
+ * LLC_CONN_STATE_AWAIT_REJ states
+ */
+/* State transitions for LLC_CONN_EV_DISC_REQ event */
+static llc_conn_action_t llc_common_actions_1[] = {
+	llc_conn_ac_send_disc_cmd_p_set_x,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_stop_other_timers,
+	llc_conn_ac_set_retry_cnt_0,
+	llc_conn_ac_set_cause_flag_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_common_state_trans_1 = {
+	llc_conn_ev_disc_req,
+	LLC_CONN_STATE_D_CONN,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_common_actions_1
+};
+
+/* State transitions for LLC_CONN_EV_RESET_REQ event */
+static llc_conn_action_t llc_common_actions_2[] = {
+	llc_conn_ac_send_sabme_cmd_p_set_x,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_stop_other_timers,
+	llc_conn_ac_set_retry_cnt_0,
+	llc_conn_ac_set_cause_flag_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_common_state_trans_2 = {
+	llc_conn_ev_rst_req,
+	LLC_CONN_STATE_RESET,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_common_actions_2
+};
+
+/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event */
+static llc_conn_action_t llc_common_actions_3[] = {
+	llc_conn_ac_stop_all_timers,
+	llc_conn_ac_set_vs_0,
+	llc_conn_ac_set_vr_0,
+	llc_conn_ac_send_ua_rsp_f_set_p,
+	llc_conn_ac_rst_ind,
+	llc_conn_ac_set_p_flag_0,
+	llc_conn_ac_set_remote_busy_0,
+	llc_conn_reset,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_common_state_trans_3 = {
+	llc_conn_ev_rx_sabme_cmd_pbit_set_x,
+	LLC_CONN_STATE_NORMAL,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_common_actions_3
+};
+
+/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event */
+static llc_conn_action_t llc_common_actions_4[] = {
+	llc_conn_ac_stop_all_timers,
+	llc_conn_ac_send_ua_rsp_f_set_p,
+	llc_conn_ac_disc_ind,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_common_state_trans_4 = {
+	llc_conn_ev_rx_disc_cmd_pbit_set_x,
+	LLC_CONN_STATE_ADM,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_common_actions_4
+};
+
+/* State transitions for LLC_CONN_EV_RX_FRMR_RSP_Fbit_SET_X event */
+static llc_conn_action_t llc_common_actions_5[] = {
+	llc_conn_ac_send_sabme_cmd_p_set_x,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_stop_other_timers,
+	llc_conn_ac_set_retry_cnt_0,
+	llc_conn_ac_rst_ind,
+	llc_conn_ac_set_cause_flag_0,
+	llc_conn_reset,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_common_state_trans_5 = {
+	llc_conn_ev_rx_frmr_rsp_fbit_set_x,
+	LLC_CONN_STATE_RESET,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_common_actions_5
+};
+
+/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event */
+static llc_conn_action_t llc_common_actions_6[] = {
+	llc_conn_ac_disc_ind,
+	llc_conn_ac_stop_all_timers,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_common_state_trans_6 = {
+	llc_conn_ev_rx_dm_rsp_fbit_set_x,
+	LLC_CONN_STATE_ADM,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_common_actions_6
+};
+
+/* State transitions for LLC_CONN_EV_RX_ZZZ_CMD_Pbit_SET_X_INVAL_Nr event */
+static llc_conn_action_t llc_common_actions_7a[] = {
+	llc_conn_ac_send_frmr_rsp_f_set_x,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_stop_other_timers,
+	llc_conn_ac_set_retry_cnt_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_common_state_trans_7a = {
+	llc_conn_ev_rx_zzz_cmd_pbit_set_x_inval_nr,
+	LLC_CONN_STATE_ERROR,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_common_actions_7a
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_X_INVAL_Ns event */
+static llc_conn_action_t llc_common_actions_7b[] = {
+	llc_conn_ac_send_frmr_rsp_f_set_x,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_stop_other_timers,
+	llc_conn_ac_set_retry_cnt_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_common_state_trans_7b = {
+	llc_conn_ev_rx_i_cmd_pbit_set_x_inval_ns,
+	LLC_CONN_STATE_ERROR,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_common_actions_7b
+};
+
+/* State transitions for LLC_CONN_EV_RX_ZZZ_RSP_Fbit_SET_X_INVAL_Nr event */
+static llc_conn_action_t llc_common_actions_8a[] = {
+	llc_conn_ac_send_frmr_rsp_f_set_x,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_stop_other_timers,
+	llc_conn_ac_set_retry_cnt_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_common_state_trans_8a = {
+	llc_conn_ev_rx_zzz_rsp_fbit_set_x_inval_nr,
+	LLC_CONN_STATE_ERROR,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_common_actions_8a
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_X_INVAL_Ns event */
+static llc_conn_action_t llc_common_actions_8b[] = {
+	llc_conn_ac_send_frmr_rsp_f_set_x,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_stop_other_timers,
+	llc_conn_ac_set_retry_cnt_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_common_state_trans_8b = {
+	llc_conn_ev_rx_i_rsp_fbit_set_x_inval_ns,
+	LLC_CONN_STATE_ERROR,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_common_actions_8b
+};
+
+/* State transitions for LLC_CONN_EV_RX_BAD_PDU event */
+static llc_conn_action_t llc_common_actions_8c[] = {
+	llc_conn_ac_send_frmr_rsp_f_set_x,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_stop_other_timers,
+	llc_conn_ac_set_retry_cnt_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_common_state_trans_8c = {
+	llc_conn_ev_rx_bad_pdu,
+	LLC_CONN_STATE_ERROR,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_common_actions_8c
+};
+
+/* State transitions for LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X event */
+static llc_conn_action_t llc_common_actions_9[] = {
+	llc_conn_ac_send_frmr_rsp_f_set_x,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_stop_other_timers,
+	llc_conn_ac_set_retry_cnt_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_common_state_trans_9 = {
+	llc_conn_ev_rx_ua_rsp_fbit_set_x,
+	LLC_CONN_STATE_ERROR,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_common_actions_9
+};
+
+/* State transitions for LLC_CONN_EV_RX_XXX_RSP_Fbit_SET_1 event */
+#if 0
+static llc_conn_ev_qfyr_t llc_common_ev_qfyrs_10[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_common_actions_10[] = {
+	llc_conn_ac_send_frmr_rsp_f_set_x,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_stop_other_timers,
+	llc_conn_ac_set_retry_cnt_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_common_state_trans_10 = {
+	llc_conn_ev_rx_xxx_rsp_fbit_set_1,
+	LLC_CONN_STATE_ERROR,
+	llc_common_ev_qfyrs_10,
+	llc_common_actions_10
+};
+#endif
+
+/* State transitions for LLC_CONN_EV_P_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_common_ev_qfyrs_11a[] = {
+	llc_conn_ev_qlfy_retry_cnt_gte_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_common_actions_11a[] = {
+	llc_conn_ac_send_sabme_cmd_p_set_x,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_stop_other_timers,
+	llc_conn_ac_set_retry_cnt_0,
+	llc_conn_ac_set_cause_flag_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_common_state_trans_11a = {
+	llc_conn_ev_p_tmr_exp,
+	LLC_CONN_STATE_RESET,
+	llc_common_ev_qfyrs_11a,
+	llc_common_actions_11a
+};
+
+/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_common_ev_qfyrs_11b[] = {
+	llc_conn_ev_qlfy_retry_cnt_gte_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_common_actions_11b[] = {
+	llc_conn_ac_send_sabme_cmd_p_set_x,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_stop_other_timers,
+	llc_conn_ac_set_retry_cnt_0,
+	llc_conn_ac_set_cause_flag_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_common_state_trans_11b = {
+	llc_conn_ev_ack_tmr_exp,
+	LLC_CONN_STATE_RESET,
+	llc_common_ev_qfyrs_11b,
+	llc_common_actions_11b
+};
+
+/* State transitions for LLC_CONN_EV_REJ_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_common_ev_qfyrs_11c[] = {
+	llc_conn_ev_qlfy_retry_cnt_gte_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_common_actions_11c[] = {
+	llc_conn_ac_send_sabme_cmd_p_set_x,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_stop_other_timers,
+	llc_conn_ac_set_retry_cnt_0,
+	llc_conn_ac_set_cause_flag_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_common_state_trans_11c = {
+	llc_conn_ev_rej_tmr_exp,
+	LLC_CONN_STATE_RESET,
+	llc_common_ev_qfyrs_11c,
+	llc_common_actions_11c
+};
+
+/* State transitions for LLC_CONN_EV_BUSY_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_common_ev_qfyrs_11d[] = {
+	llc_conn_ev_qlfy_retry_cnt_gte_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_common_actions_11d[] = {
+	llc_conn_ac_send_sabme_cmd_p_set_x,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_stop_other_timers,
+	llc_conn_ac_set_retry_cnt_0,
+	llc_conn_ac_set_cause_flag_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_common_state_trans_11d = {
+	llc_conn_ev_busy_tmr_exp,
+	LLC_CONN_STATE_RESET,
+	llc_common_ev_qfyrs_11d,
+	llc_common_actions_11d
+};
+
+/*
+ * Common dummy state transition; must be last entry for all state
+ * transition groups - it'll be on .bss, so will be zeroed.
+ */
+static struct llc_conn_state_trans llc_common_state_trans_n;
+
+/* --------------------- LLC_CONN_STATE_ADM transitions -------------------- */
+/* State transitions for LLC_CONN_EV_CONN_REQ event */
+static llc_conn_action_t llc_adm_actions_1[] = {
+	llc_conn_ac_send_sabme_cmd_p_set_x,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_set_retry_cnt_0,
+	llc_conn_ac_set_s_flag_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_adm_state_trans_1 = {
+	llc_conn_ev_conn_req,
+	LLC_CONN_STATE_SETUP,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_adm_actions_1
+};
+
+/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event */
+static llc_conn_action_t llc_adm_actions_2[] = {
+	llc_conn_ac_send_ua_rsp_f_set_p,
+	llc_conn_ac_set_vs_0,
+	llc_conn_ac_set_vr_0,
+	llc_conn_ac_set_retry_cnt_0,
+	llc_conn_ac_set_p_flag_0,
+	llc_conn_ac_set_remote_busy_0,
+	llc_conn_ac_conn_ind,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_adm_state_trans_2 = {
+	llc_conn_ev_rx_sabme_cmd_pbit_set_x,
+	LLC_CONN_STATE_NORMAL,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_adm_actions_2
+};
+
+/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event */
+static llc_conn_action_t llc_adm_actions_3[] = {
+	llc_conn_ac_send_dm_rsp_f_set_p,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_adm_state_trans_3 = {
+	llc_conn_ev_rx_disc_cmd_pbit_set_x,
+	LLC_CONN_STATE_ADM,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_adm_actions_3
+};
+
+/* State transitions for LLC_CONN_EV_RX_XXX_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_adm_actions_4[] = {
+	llc_conn_ac_send_dm_rsp_f_set_1,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_adm_state_trans_4 = {
+	llc_conn_ev_rx_xxx_cmd_pbit_set_1,
+	LLC_CONN_STATE_ADM,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_adm_actions_4
+};
+
+/* State transitions for LLC_CONN_EV_RX_XXX_YYY event */
+static llc_conn_action_t llc_adm_actions_5[] = {
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_adm_state_trans_5 = {
+	llc_conn_ev_rx_any_frame,
+	LLC_CONN_OUT_OF_SVC,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_adm_actions_5
+};
+
+/*
+ * Array of pointers;
+ * one to each transition
+ */
+static struct llc_conn_state_trans *llc_adm_state_transitions[] = {
+	&llc_adm_state_trans_1,		/* Request */
+	&llc_common_state_trans_n,
+	&llc_common_state_trans_n,	/* local_busy */
+	&llc_common_state_trans_n,	/* init_pf_cycle */
+	&llc_common_state_trans_n,	/* timer */
+	&llc_adm_state_trans_2,		/* Receive frame */
+	&llc_adm_state_trans_3,
+	&llc_adm_state_trans_4,
+	&llc_adm_state_trans_5,
+	&llc_common_state_trans_n
+};
+
+/* ---------------------  LLC_CONN_STATE_SETUP transitions ----------------- */
+/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event */
+static llc_conn_action_t llc_setup_actions_1[] = {
+	llc_conn_ac_send_ua_rsp_f_set_p,
+	llc_conn_ac_set_vs_0,
+	llc_conn_ac_set_vr_0,
+	llc_conn_ac_set_s_flag_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_setup_state_trans_1 = {
+	llc_conn_ev_rx_sabme_cmd_pbit_set_x,
+	LLC_CONN_STATE_SETUP,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_setup_actions_1
+};
+
+/* State transitions for LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X event */
+static llc_conn_ev_qfyr_t llc_setup_ev_qfyrs_2[] = {
+	llc_conn_ev_qlfy_p_flag_eq_f,
+	llc_conn_ev_qlfy_set_status_conn,
+	NULL
+};
+
+static llc_conn_action_t llc_setup_actions_2[] = {
+	llc_conn_ac_stop_ack_timer,
+	llc_conn_ac_set_vs_0,
+	llc_conn_ac_set_vr_0,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_set_remote_busy_0,
+	llc_conn_ac_conn_confirm,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_setup_state_trans_2 = {
+	llc_conn_ev_rx_ua_rsp_fbit_set_x,
+	LLC_CONN_STATE_NORMAL,
+	llc_setup_ev_qfyrs_2,
+	llc_setup_actions_2
+};
+
+/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_setup_ev_qfyrs_3[] = {
+	llc_conn_ev_qlfy_s_flag_eq_1,
+	llc_conn_ev_qlfy_set_status_conn,
+	NULL
+};
+
+static llc_conn_action_t llc_setup_actions_3[] = {
+	llc_conn_ac_set_p_flag_0,
+	llc_conn_ac_set_remote_busy_0,
+	llc_conn_ac_conn_confirm,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_setup_state_trans_3 = {
+	llc_conn_ev_ack_tmr_exp,
+	LLC_CONN_STATE_NORMAL,
+	llc_setup_ev_qfyrs_3,
+	llc_setup_actions_3
+};
+
+/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event */
+static llc_conn_ev_qfyr_t llc_setup_ev_qfyrs_4[] = {
+	llc_conn_ev_qlfy_set_status_disc,
+	NULL
+};
+
+static llc_conn_action_t llc_setup_actions_4[] = {
+	llc_conn_ac_send_dm_rsp_f_set_p,
+	llc_conn_ac_stop_ack_timer,
+	llc_conn_ac_conn_confirm,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_setup_state_trans_4 = {
+	llc_conn_ev_rx_disc_cmd_pbit_set_x,
+	LLC_CONN_STATE_ADM,
+	llc_setup_ev_qfyrs_4,
+	llc_setup_actions_4
+};
+
+/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event */
+static llc_conn_ev_qfyr_t llc_setup_ev_qfyrs_5[] = {
+	llc_conn_ev_qlfy_set_status_disc,
+	NULL
+};
+
+static llc_conn_action_t llc_setup_actions_5[] = {
+	llc_conn_ac_stop_ack_timer,
+	llc_conn_ac_conn_confirm,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_setup_state_trans_5 = {
+	llc_conn_ev_rx_dm_rsp_fbit_set_x,
+	LLC_CONN_STATE_ADM,
+	llc_setup_ev_qfyrs_5,
+	llc_setup_actions_5
+};
+
+/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_setup_ev_qfyrs_7[] = {
+	llc_conn_ev_qlfy_retry_cnt_lt_n2,
+	llc_conn_ev_qlfy_s_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_setup_actions_7[] = {
+	llc_conn_ac_send_sabme_cmd_p_set_x,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_inc_retry_cnt_by_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_setup_state_trans_7 = {
+	llc_conn_ev_ack_tmr_exp,
+	LLC_CONN_STATE_SETUP,
+	llc_setup_ev_qfyrs_7,
+	llc_setup_actions_7
+};
+
+/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_setup_ev_qfyrs_8[] = {
+	llc_conn_ev_qlfy_retry_cnt_gte_n2,
+	llc_conn_ev_qlfy_s_flag_eq_0,
+	llc_conn_ev_qlfy_set_status_failed,
+	NULL
+};
+
+static llc_conn_action_t llc_setup_actions_8[] = {
+	llc_conn_ac_conn_confirm,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_setup_state_trans_8 = {
+	llc_conn_ev_ack_tmr_exp,
+	LLC_CONN_STATE_ADM,
+	llc_setup_ev_qfyrs_8,
+	llc_setup_actions_8
+};
+
+/*
+ * Array of pointers;
+ * one to each transition
+ */
+static struct llc_conn_state_trans *llc_setup_state_transitions[] = {
+	&llc_common_state_trans_n,	/* Request */
+	&llc_common_state_trans_n,	/* local busy */
+	&llc_common_state_trans_n,	/* init_pf_cycle */
+	&llc_setup_state_trans_3,	/* Timer */
+	&llc_setup_state_trans_7,
+	&llc_setup_state_trans_8,
+	&llc_common_state_trans_n,
+	&llc_setup_state_trans_1,	/* Receive frame */
+	&llc_setup_state_trans_2,
+	&llc_setup_state_trans_4,
+	&llc_setup_state_trans_5,
+	&llc_common_state_trans_n
+};
+
+/* -------------------- LLC_CONN_STATE_NORMAL transitions ------------------ */
+/* State transitions for LLC_CONN_EV_DATA_REQ event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_1[] = {
+	llc_conn_ev_qlfy_remote_busy_eq_0,
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	llc_conn_ev_qlfy_last_frame_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_1[] = {
+	llc_conn_ac_send_i_as_ack,
+	llc_conn_ac_start_ack_tmr_if_not_running,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_1 = {
+	llc_conn_ev_data_req,
+	LLC_CONN_STATE_NORMAL,
+	llc_normal_ev_qfyrs_1,
+	llc_normal_actions_1
+};
+
+/* State transitions for LLC_CONN_EV_DATA_REQ event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_2[] = {
+	llc_conn_ev_qlfy_remote_busy_eq_0,
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	llc_conn_ev_qlfy_last_frame_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_2[] = {
+	llc_conn_ac_send_i_cmd_p_set_1,
+	llc_conn_ac_start_p_timer,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_2 = {
+	llc_conn_ev_data_req,
+	LLC_CONN_STATE_NORMAL,
+	llc_normal_ev_qfyrs_2,
+	llc_normal_actions_2
+};
+
+/* State transitions for LLC_CONN_EV_DATA_REQ event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_2_1[] = {
+	llc_conn_ev_qlfy_remote_busy_eq_1,
+	llc_conn_ev_qlfy_set_status_remote_busy,
+	NULL
+};
+
+/* just one member, NULL, .bss zeroes it */
+static llc_conn_action_t llc_normal_actions_2_1[1];
+
+static struct llc_conn_state_trans llc_normal_state_trans_2_1 = {
+	llc_conn_ev_data_req,
+	LLC_CONN_STATE_NORMAL,
+	llc_normal_ev_qfyrs_2_1,
+	llc_normal_actions_2_1
+};
+
+/* State transitions for LLC_CONN_EV_LOCAL_BUSY_DETECTED event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_3[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_3[] = {
+	llc_conn_ac_rst_sendack_flag,
+	llc_conn_ac_send_rnr_xxx_x_set_0,
+	llc_conn_ac_set_data_flag_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_3 = {
+	llc_conn_ev_local_busy_detected,
+	LLC_CONN_STATE_BUSY,
+	llc_normal_ev_qfyrs_3,
+	llc_normal_actions_3
+};
+
+/* State transitions for LLC_CONN_EV_LOCAL_BUSY_DETECTED event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_4[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_4[] = {
+	llc_conn_ac_rst_sendack_flag,
+	llc_conn_ac_send_rnr_xxx_x_set_0,
+	llc_conn_ac_set_data_flag_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_4 = {
+	llc_conn_ev_local_busy_detected,
+	LLC_CONN_STATE_BUSY,
+	llc_normal_ev_qfyrs_4,
+	llc_normal_actions_4
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_5a[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_5a[] = {
+	llc_conn_ac_rst_sendack_flag,
+	llc_conn_ac_send_rej_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_start_rej_timer,
+	llc_conn_ac_clear_remote_busy_if_f_eq_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_5a = {
+	llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns,
+	LLC_CONN_STATE_REJ,
+	llc_normal_ev_qfyrs_5a,
+	llc_normal_actions_5a
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_5b[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_5b[] = {
+	llc_conn_ac_rst_sendack_flag,
+	llc_conn_ac_send_rej_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_start_rej_timer,
+	llc_conn_ac_clear_remote_busy_if_f_eq_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_5b = {
+	llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns,
+	LLC_CONN_STATE_REJ,
+	llc_normal_ev_qfyrs_5b,
+	llc_normal_actions_5b
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1_UNEXPD_Ns event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_5c[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_5c[] = {
+	llc_conn_ac_rst_sendack_flag,
+	llc_conn_ac_send_rej_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_start_rej_timer,
+	llc_conn_ac_clear_remote_busy_if_f_eq_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_5c = {
+	llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns,
+	LLC_CONN_STATE_REJ,
+	llc_normal_ev_qfyrs_5c,
+	llc_normal_actions_5c
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_6a[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_6a[] = {
+	llc_conn_ac_rst_sendack_flag,
+	llc_conn_ac_send_rej_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_start_rej_timer,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_6a = {
+	llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns,
+	LLC_CONN_STATE_REJ,
+	llc_normal_ev_qfyrs_6a,
+	llc_normal_actions_6a
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_6b[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_6b[] = {
+	llc_conn_ac_rst_sendack_flag,
+	llc_conn_ac_send_rej_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_start_rej_timer,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_6b = {
+	llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns,
+	LLC_CONN_STATE_REJ,
+	llc_normal_ev_qfyrs_6b,
+	llc_normal_actions_6b
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns event */
+static llc_conn_action_t llc_normal_actions_7[] = {
+	llc_conn_ac_rst_sendack_flag,
+	llc_conn_ac_send_rej_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_start_rej_timer,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_7 = {
+	llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns,
+	LLC_CONN_STATE_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_normal_actions_7
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_X event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_8a[] = {
+	llc_conn_ev_qlfy_p_flag_eq_f,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_8[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_clear_remote_busy_if_f_eq_1,
+	llc_conn_ac_send_ack_if_needed,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_8a = {
+	llc_conn_ev_rx_i_rsp_fbit_set_x,
+	LLC_CONN_STATE_NORMAL,
+	llc_normal_ev_qfyrs_8a,
+	llc_normal_actions_8
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_8b[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_8b = {
+	llc_conn_ev_rx_i_cmd_pbit_set_0,
+	LLC_CONN_STATE_NORMAL,
+	llc_normal_ev_qfyrs_8b,
+	llc_normal_actions_8
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_9a[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_9a[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_send_ack_if_needed,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_9a = {
+	llc_conn_ev_rx_i_rsp_fbit_set_0,
+	LLC_CONN_STATE_NORMAL,
+	llc_normal_ev_qfyrs_9a,
+	llc_normal_actions_9a
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_9b[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_9b[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_send_ack_if_needed,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_9b = {
+	llc_conn_ev_rx_i_cmd_pbit_set_0,
+	LLC_CONN_STATE_NORMAL,
+	llc_normal_ev_qfyrs_9b,
+	llc_normal_actions_9b
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_normal_actions_10[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_send_ack_rsp_f_set_1,
+	llc_conn_ac_rst_sendack_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_data_ind,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_10 = {
+	llc_conn_ev_rx_i_cmd_pbit_set_1,
+	LLC_CONN_STATE_NORMAL,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_normal_actions_10
+};
+
+/* State transitions for * LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 event */
+static llc_conn_action_t llc_normal_actions_11a[] = {
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_11a = {
+	llc_conn_ev_rx_rr_cmd_pbit_set_0,
+	LLC_CONN_STATE_NORMAL,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_normal_actions_11a
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 event */
+static llc_conn_action_t llc_normal_actions_11b[] = {
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_11b = {
+	llc_conn_ev_rx_rr_rsp_fbit_set_0,
+	LLC_CONN_STATE_NORMAL,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_normal_actions_11b
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_11c[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_11c[] = {
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_inc_tx_win_size,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_11c = {
+	llc_conn_ev_rx_rr_rsp_fbit_set_1,
+	LLC_CONN_STATE_NORMAL,
+	llc_normal_ev_qfyrs_11c,
+	llc_normal_actions_11c
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_normal_actions_12[] = {
+	llc_conn_ac_send_ack_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_adjust_npta_by_rr,
+	llc_conn_ac_rst_sendack_flag,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_12 = {
+	llc_conn_ev_rx_rr_cmd_pbit_set_1,
+	LLC_CONN_STATE_NORMAL,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_normal_actions_12
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 event */
+static llc_conn_action_t llc_normal_actions_13a[] = {
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_13a = {
+	llc_conn_ev_rx_rnr_cmd_pbit_set_0,
+	LLC_CONN_STATE_NORMAL,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_normal_actions_13a
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 event */
+static llc_conn_action_t llc_normal_actions_13b[] = {
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_13b = {
+	llc_conn_ev_rx_rnr_rsp_fbit_set_0,
+	LLC_CONN_STATE_NORMAL,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_normal_actions_13b
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_13c[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_13c[] = {
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_13c = {
+	llc_conn_ev_rx_rnr_rsp_fbit_set_1,
+	LLC_CONN_STATE_NORMAL,
+	llc_normal_ev_qfyrs_13c,
+	llc_normal_actions_13c
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_normal_actions_14[] = {
+	llc_conn_ac_send_rr_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_adjust_npta_by_rnr,
+	llc_conn_ac_rst_sendack_flag,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_14 = {
+	llc_conn_ev_rx_rnr_cmd_pbit_set_1,
+	LLC_CONN_STATE_NORMAL,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_normal_actions_14
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_15a[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_15a[] = {
+	llc_conn_ac_set_vs_nr,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_dec_tx_win_size,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_15a = {
+	llc_conn_ev_rx_rej_cmd_pbit_set_0,
+	LLC_CONN_STATE_NORMAL,
+	llc_normal_ev_qfyrs_15a,
+	llc_normal_actions_15a
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_X event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_15b[] = {
+	llc_conn_ev_qlfy_p_flag_eq_f,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_15b[] = {
+	llc_conn_ac_set_vs_nr,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_dec_tx_win_size,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_15b = {
+	llc_conn_ev_rx_rej_rsp_fbit_set_x,
+	LLC_CONN_STATE_NORMAL,
+	llc_normal_ev_qfyrs_15b,
+	llc_normal_actions_15b
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_16a[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_16a[] = {
+	llc_conn_ac_set_vs_nr,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_dec_tx_win_size,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_16a = {
+	llc_conn_ev_rx_rej_cmd_pbit_set_0,
+	LLC_CONN_STATE_NORMAL,
+	llc_normal_ev_qfyrs_16a,
+	llc_normal_actions_16a
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_16b[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_16b[] = {
+	llc_conn_ac_set_vs_nr,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_dec_tx_win_size,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_16b = {
+	llc_conn_ev_rx_rej_rsp_fbit_set_0,
+	LLC_CONN_STATE_NORMAL,
+	llc_normal_ev_qfyrs_16b,
+	llc_normal_actions_16b
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_normal_actions_17[] = {
+	llc_conn_ac_set_vs_nr,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_dec_tx_win_size,
+	llc_conn_ac_resend_i_rsp_f_set_1,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_17 = {
+	llc_conn_ev_rx_rej_cmd_pbit_set_1,
+	LLC_CONN_STATE_NORMAL,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_normal_actions_17
+};
+
+/* State transitions for LLC_CONN_EV_INIT_P_F_CYCLE event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_18[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_18[] = {
+	llc_conn_ac_send_rr_cmd_p_set_1,
+	llc_conn_ac_start_p_timer,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_18 = {
+	llc_conn_ev_init_p_f_cycle,
+	LLC_CONN_STATE_NORMAL,
+	llc_normal_ev_qfyrs_18,
+	llc_normal_actions_18
+};
+
+/* State transitions for LLC_CONN_EV_P_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_19[] = {
+	llc_conn_ev_qlfy_retry_cnt_lt_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_19[] = {
+	llc_conn_ac_rst_sendack_flag,
+	llc_conn_ac_send_rr_cmd_p_set_1,
+	llc_conn_ac_rst_vs,
+	llc_conn_ac_start_p_timer,
+	llc_conn_ac_inc_retry_cnt_by_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_19 = {
+	llc_conn_ev_p_tmr_exp,
+	LLC_CONN_STATE_AWAIT,
+	llc_normal_ev_qfyrs_19,
+	llc_normal_actions_19
+};
+
+/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_20a[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	llc_conn_ev_qlfy_retry_cnt_lt_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_20a[] = {
+	llc_conn_ac_rst_sendack_flag,
+	llc_conn_ac_send_rr_cmd_p_set_1,
+	llc_conn_ac_rst_vs,
+	llc_conn_ac_start_p_timer,
+	llc_conn_ac_inc_retry_cnt_by_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_20a = {
+	llc_conn_ev_ack_tmr_exp,
+	LLC_CONN_STATE_AWAIT,
+	llc_normal_ev_qfyrs_20a,
+	llc_normal_actions_20a
+};
+
+/* State transitions for LLC_CONN_EV_BUSY_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_20b[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	llc_conn_ev_qlfy_retry_cnt_lt_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_20b[] = {
+	llc_conn_ac_rst_sendack_flag,
+	llc_conn_ac_send_rr_cmd_p_set_1,
+	llc_conn_ac_rst_vs,
+	llc_conn_ac_start_p_timer,
+	llc_conn_ac_inc_retry_cnt_by_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_20b = {
+	llc_conn_ev_busy_tmr_exp,
+	LLC_CONN_STATE_AWAIT,
+	llc_normal_ev_qfyrs_20b,
+	llc_normal_actions_20b
+};
+
+/* State transitions for LLC_CONN_EV_TX_BUFF_FULL event */
+static llc_conn_ev_qfyr_t llc_normal_ev_qfyrs_21[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_normal_actions_21[] = {
+	llc_conn_ac_send_rr_cmd_p_set_1,
+	llc_conn_ac_start_p_timer,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_normal_state_trans_21 = {
+	llc_conn_ev_tx_buffer_full,
+	LLC_CONN_STATE_NORMAL,
+	llc_normal_ev_qfyrs_21,
+	llc_normal_actions_21
+};
+
+/*
+ * Array of pointers;
+ * one to each transition
+ */
+static struct llc_conn_state_trans *llc_normal_state_transitions[] = {
+	&llc_normal_state_trans_1,	/* Requests */
+	&llc_normal_state_trans_2,
+	&llc_normal_state_trans_2_1,
+	&llc_common_state_trans_1,
+	&llc_common_state_trans_2,
+	&llc_common_state_trans_n,
+	&llc_normal_state_trans_21,
+	&llc_normal_state_trans_3,	/* Local busy */
+	&llc_normal_state_trans_4,
+	&llc_common_state_trans_n,
+	&llc_normal_state_trans_18,	/* Init pf cycle */
+	&llc_common_state_trans_n,
+	&llc_common_state_trans_11a,	/* Timers */
+	&llc_common_state_trans_11b,
+	&llc_common_state_trans_11c,
+	&llc_common_state_trans_11d,
+	&llc_normal_state_trans_19,
+	&llc_normal_state_trans_20a,
+	&llc_normal_state_trans_20b,
+	&llc_common_state_trans_n,
+	&llc_normal_state_trans_8b,	/* Receive frames */
+	&llc_normal_state_trans_9b,
+	&llc_normal_state_trans_10,
+	&llc_normal_state_trans_11b,
+	&llc_normal_state_trans_11c,
+	&llc_normal_state_trans_5a,
+	&llc_normal_state_trans_5b,
+	&llc_normal_state_trans_5c,
+	&llc_normal_state_trans_6a,
+	&llc_normal_state_trans_6b,
+	&llc_normal_state_trans_7,
+	&llc_normal_state_trans_8a,
+	&llc_normal_state_trans_9a,
+	&llc_normal_state_trans_11a,
+	&llc_normal_state_trans_12,
+	&llc_normal_state_trans_13a,
+	&llc_normal_state_trans_13b,
+	&llc_normal_state_trans_13c,
+	&llc_normal_state_trans_14,
+	&llc_normal_state_trans_15a,
+	&llc_normal_state_trans_15b,
+	&llc_normal_state_trans_16a,
+	&llc_normal_state_trans_16b,
+	&llc_normal_state_trans_17,
+	&llc_common_state_trans_3,
+	&llc_common_state_trans_4,
+	&llc_common_state_trans_5,
+	&llc_common_state_trans_6,
+	&llc_common_state_trans_7a,
+	&llc_common_state_trans_7b,
+	&llc_common_state_trans_8a,
+	&llc_common_state_trans_8b,
+	&llc_common_state_trans_8c,
+	&llc_common_state_trans_9,
+	/*&llc_common_state_trans_10, */
+	&llc_common_state_trans_n
+};
+
+/* --------------------- LLC_CONN_STATE_BUSY transitions ------------------- */
+/* State transitions for LLC_CONN_EV_DATA_REQ event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_1[] = {
+	llc_conn_ev_qlfy_remote_busy_eq_0,
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_1[] = {
+	llc_conn_ac_send_i_xxx_x_set_0,
+	llc_conn_ac_start_ack_tmr_if_not_running,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_1 = {
+	llc_conn_ev_data_req,
+	LLC_CONN_STATE_BUSY,
+	llc_busy_ev_qfyrs_1,
+	llc_busy_actions_1
+};
+
+/* State transitions for LLC_CONN_EV_DATA_REQ event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_2[] = {
+	llc_conn_ev_qlfy_remote_busy_eq_0,
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_2[] = {
+	llc_conn_ac_send_i_xxx_x_set_0,
+	llc_conn_ac_start_ack_tmr_if_not_running,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_2 = {
+	llc_conn_ev_data_req,
+	LLC_CONN_STATE_BUSY,
+	llc_busy_ev_qfyrs_2,
+	llc_busy_actions_2
+};
+
+/* State transitions for LLC_CONN_EV_DATA_REQ event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_2_1[] = {
+	llc_conn_ev_qlfy_remote_busy_eq_1,
+	llc_conn_ev_qlfy_set_status_remote_busy,
+	NULL
+};
+
+/* just one member, NULL, .bss zeroes it */
+static llc_conn_action_t llc_busy_actions_2_1[1];
+
+static struct llc_conn_state_trans llc_busy_state_trans_2_1 = {
+	llc_conn_ev_data_req,
+	LLC_CONN_STATE_BUSY,
+	llc_busy_ev_qfyrs_2_1,
+	llc_busy_actions_2_1
+};
+
+/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_3[] = {
+	llc_conn_ev_qlfy_data_flag_eq_1,
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_3[] = {
+	llc_conn_ac_send_rej_xxx_x_set_0,
+	llc_conn_ac_start_rej_timer,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_3 = {
+	llc_conn_ev_local_busy_cleared,
+	LLC_CONN_STATE_REJ,
+	llc_busy_ev_qfyrs_3,
+	llc_busy_actions_3
+};
+
+/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_4[] = {
+	llc_conn_ev_qlfy_data_flag_eq_1,
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_4[] = {
+	llc_conn_ac_send_rej_xxx_x_set_0,
+	llc_conn_ac_start_rej_timer,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_4 = {
+	llc_conn_ev_local_busy_cleared,
+	LLC_CONN_STATE_REJ,
+	llc_busy_ev_qfyrs_4,
+	llc_busy_actions_4
+};
+
+/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_5[] = {
+	llc_conn_ev_qlfy_data_flag_eq_0,
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_5[] = {
+	llc_conn_ac_send_rr_xxx_x_set_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_5 = {
+	llc_conn_ev_local_busy_cleared,
+	LLC_CONN_STATE_NORMAL,
+	llc_busy_ev_qfyrs_5,
+	llc_busy_actions_5
+};
+
+/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_6[] = {
+	llc_conn_ev_qlfy_data_flag_eq_0,
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_6[] = {
+	llc_conn_ac_send_rr_xxx_x_set_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_6 = {
+	llc_conn_ev_local_busy_cleared,
+	LLC_CONN_STATE_NORMAL,
+	llc_busy_ev_qfyrs_6,
+	llc_busy_actions_6
+};
+
+/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_7[] = {
+	llc_conn_ev_qlfy_data_flag_eq_2,
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_7[] = {
+	llc_conn_ac_send_rr_xxx_x_set_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_7 = {
+	llc_conn_ev_local_busy_cleared,
+	LLC_CONN_STATE_REJ,
+	llc_busy_ev_qfyrs_7,
+	llc_busy_actions_7
+};
+
+/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_8[] = {
+	llc_conn_ev_qlfy_data_flag_eq_2,
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_8[] = {
+	llc_conn_ac_send_rr_xxx_x_set_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_8 = {
+	llc_conn_ev_local_busy_cleared,
+	LLC_CONN_STATE_REJ,
+	llc_busy_ev_qfyrs_8,
+	llc_busy_actions_8
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_X_UNEXPD_Ns event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_9a[] = {
+	llc_conn_ev_qlfy_p_flag_eq_f,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_9a[] = {
+	llc_conn_ac_opt_send_rnr_xxx_x_set_0,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_set_data_flag_1_if_data_flag_eq_0,
+	llc_conn_ac_clear_remote_busy_if_f_eq_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_9a = {
+	llc_conn_ev_rx_i_rsp_fbit_set_x_unexpd_ns,
+	LLC_CONN_STATE_BUSY,
+	llc_busy_ev_qfyrs_9a,
+	llc_busy_actions_9a
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_9b[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_9b[] = {
+	llc_conn_ac_opt_send_rnr_xxx_x_set_0,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_set_data_flag_1_if_data_flag_eq_0,
+	llc_conn_ac_clear_remote_busy_if_f_eq_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_9b = {
+	llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns,
+	LLC_CONN_STATE_BUSY,
+	llc_busy_ev_qfyrs_9b,
+	llc_busy_actions_9b
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_10a[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_10a[] = {
+	llc_conn_ac_opt_send_rnr_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_set_data_flag_1_if_data_flag_eq_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_10a = {
+	llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns,
+	LLC_CONN_STATE_BUSY,
+	llc_busy_ev_qfyrs_10a,
+	llc_busy_actions_10a
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_10b[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_10b[] = {
+	llc_conn_ac_opt_send_rnr_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_set_data_flag_1_if_data_flag_eq_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_10b = {
+	llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns,
+	LLC_CONN_STATE_BUSY,
+	llc_busy_ev_qfyrs_10b,
+	llc_busy_actions_10b
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns event */
+static llc_conn_action_t llc_busy_actions_11[] = {
+	llc_conn_ac_send_rnr_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_set_data_flag_1_if_data_flag_eq_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_11 = {
+	llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns,
+	LLC_CONN_STATE_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_busy_actions_11
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_busy_actions_12[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_send_rnr_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2,
+	llc_conn_ac_set_data_flag_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_12 = {
+	llc_conn_ev_rx_i_cmd_pbit_set_1,
+	LLC_CONN_STATE_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_busy_actions_12
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_X event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_13a[] = {
+	llc_conn_ev_qlfy_p_flag_eq_f,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_13a[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_opt_send_rnr_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2,
+	llc_conn_ac_set_data_flag_0,
+	llc_conn_ac_clear_remote_busy_if_f_eq_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_13a = {
+	llc_conn_ev_rx_i_rsp_fbit_set_x,
+	LLC_CONN_STATE_BUSY,
+	llc_busy_ev_qfyrs_13a,
+	llc_busy_actions_13a
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_13b[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_13b[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_opt_send_rnr_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2,
+	llc_conn_ac_set_data_flag_0,
+	llc_conn_ac_clear_remote_busy_if_f_eq_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_13b = {
+	llc_conn_ev_rx_i_cmd_pbit_set_0,
+	LLC_CONN_STATE_BUSY,
+	llc_busy_ev_qfyrs_13b,
+	llc_busy_actions_13b
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_14a[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_14a[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_opt_send_rnr_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2,
+	llc_conn_ac_set_data_flag_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_14a = {
+	llc_conn_ev_rx_i_rsp_fbit_set_0,
+	LLC_CONN_STATE_BUSY,
+	llc_busy_ev_qfyrs_14a,
+	llc_busy_actions_14a
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_14b[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_14b[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_opt_send_rnr_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2,
+	llc_conn_ac_set_data_flag_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_14b = {
+	llc_conn_ev_rx_i_cmd_pbit_set_0,
+	LLC_CONN_STATE_BUSY,
+	llc_busy_ev_qfyrs_14b,
+	llc_busy_actions_14b
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 event */
+static llc_conn_action_t llc_busy_actions_15a[] = {
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_15a = {
+	llc_conn_ev_rx_rr_cmd_pbit_set_0,
+	LLC_CONN_STATE_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_busy_actions_15a
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 event */
+static llc_conn_action_t llc_busy_actions_15b[] = {
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_15b = {
+	llc_conn_ev_rx_rr_rsp_fbit_set_0,
+	LLC_CONN_STATE_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_busy_actions_15b
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_15c[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_15c[] = {
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_15c = {
+	llc_conn_ev_rx_rr_rsp_fbit_set_1,
+	LLC_CONN_STATE_BUSY,
+	llc_busy_ev_qfyrs_15c,
+	llc_busy_actions_15c
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_busy_actions_16[] = {
+	llc_conn_ac_send_rnr_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_16 = {
+	llc_conn_ev_rx_rr_cmd_pbit_set_1,
+	LLC_CONN_STATE_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_busy_actions_16
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 event */
+static llc_conn_action_t llc_busy_actions_17a[] = {
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_17a = {
+	llc_conn_ev_rx_rnr_cmd_pbit_set_0,
+	LLC_CONN_STATE_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_busy_actions_17a
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 event */
+static llc_conn_action_t llc_busy_actions_17b[] = {
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_17b = {
+	llc_conn_ev_rx_rnr_rsp_fbit_set_0,
+	LLC_CONN_STATE_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_busy_actions_17b
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_17c[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_17c[] = {
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_17c = {
+	llc_conn_ev_rx_rnr_rsp_fbit_set_1,
+	LLC_CONN_STATE_BUSY,
+	llc_busy_ev_qfyrs_17c,
+	llc_busy_actions_17c
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_busy_actions_18[] = {
+	llc_conn_ac_send_rnr_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_18 = {
+	llc_conn_ev_rx_rnr_cmd_pbit_set_1,
+	LLC_CONN_STATE_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_busy_actions_18
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_19a[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_19a[] = {
+	llc_conn_ac_set_vs_nr,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_19a = {
+	llc_conn_ev_rx_rej_cmd_pbit_set_0,
+	LLC_CONN_STATE_BUSY,
+	llc_busy_ev_qfyrs_19a,
+	llc_busy_actions_19a
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_X event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_19b[] = {
+	llc_conn_ev_qlfy_p_flag_eq_f,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_19b[] = {
+	llc_conn_ac_set_vs_nr,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_19b = {
+	llc_conn_ev_rx_rej_rsp_fbit_set_x,
+	LLC_CONN_STATE_BUSY,
+	llc_busy_ev_qfyrs_19b,
+	llc_busy_actions_19b
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_20a[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_20a[] = {
+	llc_conn_ac_set_vs_nr,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_20a = {
+	llc_conn_ev_rx_rej_cmd_pbit_set_0,
+	LLC_CONN_STATE_BUSY,
+	llc_busy_ev_qfyrs_20a,
+	llc_busy_actions_20a
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_20b[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_20b[] = {
+	llc_conn_ac_set_vs_nr,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_20b = {
+	llc_conn_ev_rx_rej_rsp_fbit_set_0,
+	LLC_CONN_STATE_BUSY,
+	llc_busy_ev_qfyrs_20b,
+	llc_busy_actions_20b
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_busy_actions_21[] = {
+	llc_conn_ac_set_vs_nr,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_send_rnr_rsp_f_set_1,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_21 = {
+	llc_conn_ev_rx_rej_cmd_pbit_set_1,
+	LLC_CONN_STATE_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_busy_actions_21
+};
+
+/* State transitions for LLC_CONN_EV_INIT_P_F_CYCLE event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_22[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_22[] = {
+	llc_conn_ac_send_rnr_cmd_p_set_1,
+	llc_conn_ac_start_p_timer,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_22 = {
+	llc_conn_ev_init_p_f_cycle,
+	LLC_CONN_STATE_BUSY,
+	llc_busy_ev_qfyrs_22,
+	llc_busy_actions_22
+};
+
+/* State transitions for LLC_CONN_EV_P_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_23[] = {
+	llc_conn_ev_qlfy_retry_cnt_lt_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_23[] = {
+	llc_conn_ac_send_rnr_cmd_p_set_1,
+	llc_conn_ac_rst_vs,
+	llc_conn_ac_start_p_timer,
+	llc_conn_ac_inc_retry_cnt_by_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_23 = {
+	llc_conn_ev_p_tmr_exp,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	llc_busy_ev_qfyrs_23,
+	llc_busy_actions_23
+};
+
+/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_24a[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	llc_conn_ev_qlfy_retry_cnt_lt_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_24a[] = {
+	llc_conn_ac_send_rnr_cmd_p_set_1,
+	llc_conn_ac_start_p_timer,
+	llc_conn_ac_inc_retry_cnt_by_1,
+	llc_conn_ac_rst_vs,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_24a = {
+	llc_conn_ev_ack_tmr_exp,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	llc_busy_ev_qfyrs_24a,
+	llc_busy_actions_24a
+};
+
+/* State transitions for LLC_CONN_EV_BUSY_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_24b[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	llc_conn_ev_qlfy_retry_cnt_lt_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_24b[] = {
+	llc_conn_ac_send_rnr_cmd_p_set_1,
+	llc_conn_ac_start_p_timer,
+	llc_conn_ac_inc_retry_cnt_by_1,
+	llc_conn_ac_rst_vs,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_24b = {
+	llc_conn_ev_busy_tmr_exp,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	llc_busy_ev_qfyrs_24b,
+	llc_busy_actions_24b
+};
+
+/* State transitions for LLC_CONN_EV_REJ_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_25[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	llc_conn_ev_qlfy_retry_cnt_lt_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_25[] = {
+	llc_conn_ac_send_rnr_cmd_p_set_1,
+	llc_conn_ac_start_p_timer,
+	llc_conn_ac_inc_retry_cnt_by_1,
+	llc_conn_ac_rst_vs,
+	llc_conn_ac_set_data_flag_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_25 = {
+	llc_conn_ev_rej_tmr_exp,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	llc_busy_ev_qfyrs_25,
+	llc_busy_actions_25
+};
+
+/* State transitions for LLC_CONN_EV_REJ_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_busy_ev_qfyrs_26[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	llc_conn_ev_qlfy_retry_cnt_lt_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_busy_actions_26[] = {
+	llc_conn_ac_set_data_flag_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_busy_state_trans_26 = {
+	llc_conn_ev_rej_tmr_exp,
+	LLC_CONN_STATE_BUSY,
+	llc_busy_ev_qfyrs_26,
+	llc_busy_actions_26
+};
+
+/*
+ * Array of pointers;
+ * one to each transition
+ */
+static struct llc_conn_state_trans *llc_busy_state_transitions[] = {
+	&llc_common_state_trans_1,	/* Request */
+	&llc_common_state_trans_2,
+	&llc_busy_state_trans_1,
+	&llc_busy_state_trans_2,
+	&llc_busy_state_trans_2_1,
+	&llc_common_state_trans_n,
+	&llc_busy_state_trans_3,	/* Local busy */
+	&llc_busy_state_trans_4,
+	&llc_busy_state_trans_5,
+	&llc_busy_state_trans_6,
+	&llc_busy_state_trans_7,
+	&llc_busy_state_trans_8,
+	&llc_common_state_trans_n,
+	&llc_busy_state_trans_22,	/* Initiate PF cycle */
+	&llc_common_state_trans_n,
+	&llc_common_state_trans_11a,	/* Timer */
+	&llc_common_state_trans_11b,
+	&llc_common_state_trans_11c,
+	&llc_common_state_trans_11d,
+	&llc_busy_state_trans_23,
+	&llc_busy_state_trans_24a,
+	&llc_busy_state_trans_24b,
+	&llc_busy_state_trans_25,
+	&llc_busy_state_trans_26,
+	&llc_common_state_trans_n,
+	&llc_busy_state_trans_9a,	/* Receive frame */
+	&llc_busy_state_trans_9b,
+	&llc_busy_state_trans_10a,
+	&llc_busy_state_trans_10b,
+	&llc_busy_state_trans_11,
+	&llc_busy_state_trans_12,
+	&llc_busy_state_trans_13a,
+	&llc_busy_state_trans_13b,
+	&llc_busy_state_trans_14a,
+	&llc_busy_state_trans_14b,
+	&llc_busy_state_trans_15a,
+	&llc_busy_state_trans_15b,
+	&llc_busy_state_trans_15c,
+	&llc_busy_state_trans_16,
+	&llc_busy_state_trans_17a,
+	&llc_busy_state_trans_17b,
+	&llc_busy_state_trans_17c,
+	&llc_busy_state_trans_18,
+	&llc_busy_state_trans_19a,
+	&llc_busy_state_trans_19b,
+	&llc_busy_state_trans_20a,
+	&llc_busy_state_trans_20b,
+	&llc_busy_state_trans_21,
+	&llc_common_state_trans_3,
+	&llc_common_state_trans_4,
+	&llc_common_state_trans_5,
+	&llc_common_state_trans_6,
+	&llc_common_state_trans_7a,
+	&llc_common_state_trans_7b,
+	&llc_common_state_trans_8a,
+	&llc_common_state_trans_8b,
+	&llc_common_state_trans_8c,
+	&llc_common_state_trans_9,
+	/* &llc_common_state_trans_10, */
+	&llc_common_state_trans_n
+};
+
+/* -------------------- LLC_CONN_STATE_REJ transitions ------------------ */
+/* State transitions for LLC_CONN_EV_DATA_REQ event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_1[] = {
+	llc_conn_ev_qlfy_remote_busy_eq_0,
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_1[] = {
+	llc_conn_ac_send_i_xxx_x_set_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_1 = {
+	llc_conn_ev_data_req,
+	LLC_CONN_STATE_REJ,
+	llc_reject_ev_qfyrs_1,
+	llc_reject_actions_1
+};
+
+/* State transitions for LLC_CONN_EV_DATA_REQ event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_2[] = {
+	llc_conn_ev_qlfy_remote_busy_eq_0,
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_2[] = {
+	llc_conn_ac_send_i_xxx_x_set_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_2 = {
+	llc_conn_ev_data_req,
+	LLC_CONN_STATE_REJ,
+	llc_reject_ev_qfyrs_2,
+	llc_reject_actions_2
+};
+
+/* State transitions for LLC_CONN_EV_DATA_REQ event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_2_1[] = {
+	llc_conn_ev_qlfy_remote_busy_eq_1,
+	llc_conn_ev_qlfy_set_status_remote_busy,
+	NULL
+};
+
+/* just one member, NULL, .bss zeroes it */
+static llc_conn_action_t llc_reject_actions_2_1[1];
+
+static struct llc_conn_state_trans llc_reject_state_trans_2_1 = {
+	llc_conn_ev_data_req,
+	LLC_CONN_STATE_REJ,
+	llc_reject_ev_qfyrs_2_1,
+	llc_reject_actions_2_1
+};
+
+
+/* State transitions for LLC_CONN_EV_LOCAL_BUSY_DETECTED event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_3[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_3[] = {
+	llc_conn_ac_send_rnr_xxx_x_set_0,
+	llc_conn_ac_set_data_flag_2,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_3 = {
+	llc_conn_ev_local_busy_detected,
+	LLC_CONN_STATE_BUSY,
+	llc_reject_ev_qfyrs_3,
+	llc_reject_actions_3
+};
+
+/* State transitions for LLC_CONN_EV_LOCAL_BUSY_DETECTED event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_4[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_4[] = {
+	llc_conn_ac_send_rnr_xxx_x_set_0,
+	llc_conn_ac_set_data_flag_2,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_4 = {
+	llc_conn_ev_local_busy_detected,
+	LLC_CONN_STATE_BUSY,
+	llc_reject_ev_qfyrs_4,
+	llc_reject_actions_4
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */
+static llc_conn_action_t llc_reject_actions_5a[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_clear_remote_busy_if_f_eq_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_5a = {
+	llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns,
+	LLC_CONN_STATE_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_reject_actions_5a
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */
+static llc_conn_action_t llc_reject_actions_5b[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_clear_remote_busy_if_f_eq_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_5b = {
+	llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns,
+	LLC_CONN_STATE_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_reject_actions_5b
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1_UNEXPD_Ns event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_5c[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_5c[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_clear_remote_busy_if_f_eq_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_5c = {
+	llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns,
+	LLC_CONN_STATE_REJ,
+	llc_reject_ev_qfyrs_5c,
+	llc_reject_actions_5c
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns event */
+static llc_conn_action_t llc_reject_actions_6[] = {
+	llc_conn_ac_send_rr_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_6 = {
+	llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns,
+	LLC_CONN_STATE_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_reject_actions_6
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_X event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_7a[] = {
+	llc_conn_ev_qlfy_p_flag_eq_f,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_7a[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_send_ack_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_clear_remote_busy_if_f_eq_1,
+	llc_conn_ac_stop_rej_timer,
+	NULL
+
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_7a = {
+	llc_conn_ev_rx_i_rsp_fbit_set_x,
+	LLC_CONN_STATE_NORMAL,
+	llc_reject_ev_qfyrs_7a,
+	llc_reject_actions_7a
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_7b[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_7b[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_send_ack_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_clear_remote_busy_if_f_eq_1,
+	llc_conn_ac_stop_rej_timer,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_7b = {
+	llc_conn_ev_rx_i_cmd_pbit_set_0,
+	LLC_CONN_STATE_NORMAL,
+	llc_reject_ev_qfyrs_7b,
+	llc_reject_actions_7b
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_8a[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_8a[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_send_ack_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_stop_rej_timer,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_8a = {
+	llc_conn_ev_rx_i_rsp_fbit_set_0,
+	LLC_CONN_STATE_NORMAL,
+	llc_reject_ev_qfyrs_8a,
+	llc_reject_actions_8a
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_8b[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_8b[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_send_ack_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_stop_rej_timer,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_8b = {
+	llc_conn_ev_rx_i_cmd_pbit_set_0,
+	LLC_CONN_STATE_NORMAL,
+	llc_reject_ev_qfyrs_8b,
+	llc_reject_actions_8b
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_reject_actions_9[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_send_ack_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_stop_rej_timer,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_9 = {
+	llc_conn_ev_rx_i_cmd_pbit_set_1,
+	LLC_CONN_STATE_NORMAL,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_reject_actions_9
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 event */
+static llc_conn_action_t llc_reject_actions_10a[] = {
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_10a = {
+	llc_conn_ev_rx_rr_cmd_pbit_set_0,
+	LLC_CONN_STATE_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_reject_actions_10a
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 event */
+static llc_conn_action_t llc_reject_actions_10b[] = {
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_10b = {
+	llc_conn_ev_rx_rr_rsp_fbit_set_0,
+	LLC_CONN_STATE_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_reject_actions_10b
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_10c[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_10c[] = {
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_10c = {
+	llc_conn_ev_rx_rr_rsp_fbit_set_1,
+	LLC_CONN_STATE_REJ,
+	llc_reject_ev_qfyrs_10c,
+	llc_reject_actions_10c
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_reject_actions_11[] = {
+	llc_conn_ac_send_ack_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_11 = {
+	llc_conn_ev_rx_rr_cmd_pbit_set_1,
+	LLC_CONN_STATE_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_reject_actions_11
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 event */
+static llc_conn_action_t llc_reject_actions_12a[] = {
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_12a = {
+	llc_conn_ev_rx_rnr_cmd_pbit_set_0,
+	LLC_CONN_STATE_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_reject_actions_12a
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 event */
+static llc_conn_action_t llc_reject_actions_12b[] = {
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_12b = {
+	llc_conn_ev_rx_rnr_rsp_fbit_set_0,
+	LLC_CONN_STATE_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_reject_actions_12b
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_12c[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_12c[] = {
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_12c = {
+	llc_conn_ev_rx_rnr_rsp_fbit_set_1,
+	LLC_CONN_STATE_REJ,
+	llc_reject_ev_qfyrs_12c,
+	llc_reject_actions_12c
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_reject_actions_13[] = {
+	llc_conn_ac_send_rr_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_13 = {
+	llc_conn_ev_rx_rnr_cmd_pbit_set_1,
+	LLC_CONN_STATE_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_reject_actions_13
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_14a[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_14a[] = {
+	llc_conn_ac_set_vs_nr,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_14a = {
+	llc_conn_ev_rx_rej_cmd_pbit_set_0,
+	LLC_CONN_STATE_REJ,
+	llc_reject_ev_qfyrs_14a,
+	llc_reject_actions_14a
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_X event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_14b[] = {
+	llc_conn_ev_qlfy_p_flag_eq_f,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_14b[] = {
+	llc_conn_ac_set_vs_nr,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_14b = {
+	llc_conn_ev_rx_rej_rsp_fbit_set_x,
+	LLC_CONN_STATE_REJ,
+	llc_reject_ev_qfyrs_14b,
+	llc_reject_actions_14b
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_15a[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_15a[] = {
+	llc_conn_ac_set_vs_nr,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_15a = {
+	llc_conn_ev_rx_rej_cmd_pbit_set_0,
+	LLC_CONN_STATE_REJ,
+	llc_reject_ev_qfyrs_15a,
+	llc_reject_actions_15a
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_15b[] = {
+	llc_conn_ev_qlfy_p_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_15b[] = {
+	llc_conn_ac_set_vs_nr,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_15b = {
+	llc_conn_ev_rx_rej_rsp_fbit_set_0,
+	LLC_CONN_STATE_REJ,
+	llc_reject_ev_qfyrs_15b,
+	llc_reject_actions_15b
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_reject_actions_16[] = {
+	llc_conn_ac_set_vs_nr,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_resend_i_rsp_f_set_1,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_16 = {
+	llc_conn_ev_rx_rej_cmd_pbit_set_1,
+	LLC_CONN_STATE_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_reject_actions_16
+};
+
+/* State transitions for LLC_CONN_EV_INIT_P_F_CYCLE event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_17[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_17[] = {
+	llc_conn_ac_send_rr_cmd_p_set_1,
+	llc_conn_ac_start_p_timer,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_17 = {
+	llc_conn_ev_init_p_f_cycle,
+	LLC_CONN_STATE_REJ,
+	llc_reject_ev_qfyrs_17,
+	llc_reject_actions_17
+};
+
+/* State transitions for LLC_CONN_EV_REJ_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_18[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	llc_conn_ev_qlfy_retry_cnt_lt_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_18[] = {
+	llc_conn_ac_send_rej_cmd_p_set_1,
+	llc_conn_ac_start_p_timer,
+	llc_conn_ac_start_rej_timer,
+	llc_conn_ac_inc_retry_cnt_by_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_18 = {
+	llc_conn_ev_rej_tmr_exp,
+	LLC_CONN_STATE_REJ,
+	llc_reject_ev_qfyrs_18,
+	llc_reject_actions_18
+};
+
+/* State transitions for LLC_CONN_EV_P_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_19[] = {
+	llc_conn_ev_qlfy_retry_cnt_lt_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_19[] = {
+	llc_conn_ac_send_rr_cmd_p_set_1,
+	llc_conn_ac_start_p_timer,
+	llc_conn_ac_start_rej_timer,
+	llc_conn_ac_inc_retry_cnt_by_1,
+	llc_conn_ac_rst_vs,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_19 = {
+	llc_conn_ev_p_tmr_exp,
+	LLC_CONN_STATE_AWAIT_REJ,
+	llc_reject_ev_qfyrs_19,
+	llc_reject_actions_19
+};
+
+/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_20a[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	llc_conn_ev_qlfy_retry_cnt_lt_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_20a[] = {
+	llc_conn_ac_send_rr_cmd_p_set_1,
+	llc_conn_ac_start_p_timer,
+	llc_conn_ac_start_rej_timer,
+	llc_conn_ac_inc_retry_cnt_by_1,
+	llc_conn_ac_rst_vs,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_20a = {
+	llc_conn_ev_ack_tmr_exp,
+	LLC_CONN_STATE_AWAIT_REJ,
+	llc_reject_ev_qfyrs_20a,
+	llc_reject_actions_20a
+};
+
+/* State transitions for LLC_CONN_EV_BUSY_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_reject_ev_qfyrs_20b[] = {
+	llc_conn_ev_qlfy_p_flag_eq_0,
+	llc_conn_ev_qlfy_retry_cnt_lt_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_reject_actions_20b[] = {
+	llc_conn_ac_send_rr_cmd_p_set_1,
+	llc_conn_ac_start_p_timer,
+	llc_conn_ac_start_rej_timer,
+	llc_conn_ac_inc_retry_cnt_by_1,
+	llc_conn_ac_rst_vs,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_reject_state_trans_20b = {
+	llc_conn_ev_busy_tmr_exp,
+	LLC_CONN_STATE_AWAIT_REJ,
+	llc_reject_ev_qfyrs_20b,
+	llc_reject_actions_20b
+};
+
+/*
+ * Array of pointers;
+ * one to each transition
+ */
+static struct llc_conn_state_trans *llc_reject_state_transitions[] = {
+	&llc_common_state_trans_1,	/* Request */
+	&llc_common_state_trans_2,
+	&llc_common_state_trans_n,
+	&llc_reject_state_trans_1,
+	&llc_reject_state_trans_2,
+	&llc_reject_state_trans_2_1,
+	&llc_reject_state_trans_3,	/* Local busy */
+	&llc_reject_state_trans_4,
+	&llc_common_state_trans_n,
+	&llc_reject_state_trans_17,	/* Initiate PF cycle */
+	&llc_common_state_trans_n,
+	&llc_common_state_trans_11a,	/* Timer */
+	&llc_common_state_trans_11b,
+	&llc_common_state_trans_11c,
+	&llc_common_state_trans_11d,
+	&llc_reject_state_trans_18,
+	&llc_reject_state_trans_19,
+	&llc_reject_state_trans_20a,
+	&llc_reject_state_trans_20b,
+	&llc_common_state_trans_n,
+	&llc_common_state_trans_3,	/* Receive frame */
+	&llc_common_state_trans_4,
+	&llc_common_state_trans_5,
+	&llc_common_state_trans_6,
+	&llc_common_state_trans_7a,
+	&llc_common_state_trans_7b,
+	&llc_common_state_trans_8a,
+	&llc_common_state_trans_8b,
+	&llc_common_state_trans_8c,
+	&llc_common_state_trans_9,
+	/* &llc_common_state_trans_10, */
+	&llc_reject_state_trans_5a,
+	&llc_reject_state_trans_5b,
+	&llc_reject_state_trans_5c,
+	&llc_reject_state_trans_6,
+	&llc_reject_state_trans_7a,
+	&llc_reject_state_trans_7b,
+	&llc_reject_state_trans_8a,
+	&llc_reject_state_trans_8b,
+	&llc_reject_state_trans_9,
+	&llc_reject_state_trans_10a,
+	&llc_reject_state_trans_10b,
+	&llc_reject_state_trans_10c,
+	&llc_reject_state_trans_11,
+	&llc_reject_state_trans_12a,
+	&llc_reject_state_trans_12b,
+	&llc_reject_state_trans_12c,
+	&llc_reject_state_trans_13,
+	&llc_reject_state_trans_14a,
+	&llc_reject_state_trans_14b,
+	&llc_reject_state_trans_15a,
+	&llc_reject_state_trans_15b,
+	&llc_reject_state_trans_16,
+	&llc_common_state_trans_n
+};
+
+/* -------------------- LLC_CONN_STATE_AWAIT transitions ------------------- */
+/* State transitions for LLC_CONN_EV_DATA_REQ event */
+static llc_conn_ev_qfyr_t llc_await_ev_qfyrs_1_0[] = {
+	llc_conn_ev_qlfy_set_status_refuse,
+	NULL
+};
+
+/* just one member, NULL, .bss zeroes it */
+static llc_conn_action_t llc_await_actions_1_0[1];
+
+static struct llc_conn_state_trans llc_await_state_trans_1_0 = {
+	llc_conn_ev_data_req,
+	LLC_CONN_STATE_AWAIT,
+	llc_await_ev_qfyrs_1_0,
+	llc_await_actions_1_0
+};
+
+/* State transitions for LLC_CONN_EV_LOCAL_BUSY_DETECTED event */
+static llc_conn_action_t llc_await_actions_1[] = {
+	llc_conn_ac_send_rnr_xxx_x_set_0,
+	llc_conn_ac_set_data_flag_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_1 = {
+	llc_conn_ev_local_busy_detected,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_1
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1_UNEXPD_Ns event */
+static llc_conn_action_t llc_await_actions_2[] = {
+	llc_conn_ac_send_rej_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_stop_p_timer,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_start_rej_timer,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_2 = {
+	llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns,
+	LLC_CONN_STATE_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_2
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */
+static llc_conn_action_t llc_await_actions_3a[] = {
+	llc_conn_ac_send_rej_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_start_rej_timer,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_3a = {
+	llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns,
+	LLC_CONN_STATE_AWAIT_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_3a
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */
+static llc_conn_action_t llc_await_actions_3b[] = {
+	llc_conn_ac_send_rej_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_start_rej_timer,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_3b = {
+	llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns,
+	LLC_CONN_STATE_AWAIT_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_3b
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns event */
+static llc_conn_action_t llc_await_actions_4[] = {
+	llc_conn_ac_send_rej_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_start_rej_timer,
+	llc_conn_ac_start_p_timer,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_4 = {
+	llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns,
+	LLC_CONN_STATE_AWAIT_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_4
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1 event */
+static llc_conn_action_t llc_await_actions_5[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_stop_p_timer,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_5 = {
+	llc_conn_ev_rx_i_rsp_fbit_set_1,
+	LLC_CONN_STATE_NORMAL,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_5
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 event */
+static llc_conn_action_t llc_await_actions_6a[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_send_rr_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_6a = {
+	llc_conn_ev_rx_i_rsp_fbit_set_0,
+	LLC_CONN_STATE_AWAIT,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_6a
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */
+static llc_conn_action_t llc_await_actions_6b[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_send_rr_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_6b = {
+	llc_conn_ev_rx_i_cmd_pbit_set_0,
+	LLC_CONN_STATE_AWAIT,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_6b
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_await_actions_7[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_send_rr_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_7 = {
+	llc_conn_ev_rx_i_cmd_pbit_set_1,
+	LLC_CONN_STATE_AWAIT,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_7
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 event */
+static llc_conn_action_t llc_await_actions_8a[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_stop_p_timer,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_8a = {
+	llc_conn_ev_rx_rr_rsp_fbit_set_1,
+	LLC_CONN_STATE_NORMAL,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_8a
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_1 event */
+static llc_conn_action_t llc_await_actions_8b[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_stop_p_timer,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_8b = {
+	llc_conn_ev_rx_rej_rsp_fbit_set_1,
+	LLC_CONN_STATE_NORMAL,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_8b
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 event */
+static llc_conn_action_t llc_await_actions_9a[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_9a = {
+	llc_conn_ev_rx_rr_cmd_pbit_set_0,
+	LLC_CONN_STATE_AWAIT,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_9a
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 event */
+static llc_conn_action_t llc_await_actions_9b[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_9b = {
+	llc_conn_ev_rx_rr_rsp_fbit_set_0,
+	LLC_CONN_STATE_AWAIT,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_9b
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */
+static llc_conn_action_t llc_await_actions_9c[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_9c = {
+	llc_conn_ev_rx_rej_cmd_pbit_set_0,
+	LLC_CONN_STATE_AWAIT,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_9c
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 event */
+static llc_conn_action_t llc_await_actions_9d[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_9d = {
+	llc_conn_ev_rx_rej_rsp_fbit_set_0,
+	LLC_CONN_STATE_AWAIT,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_9d
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_await_actions_10a[] = {
+	llc_conn_ac_send_rr_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_10a = {
+	llc_conn_ev_rx_rr_cmd_pbit_set_1,
+	LLC_CONN_STATE_AWAIT,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_10a
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_await_actions_10b[] = {
+	llc_conn_ac_send_rr_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_10b = {
+	llc_conn_ev_rx_rej_cmd_pbit_set_1,
+	LLC_CONN_STATE_AWAIT,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_10b
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 event */
+static llc_conn_action_t llc_await_actions_11[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_stop_p_timer,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_11 = {
+	llc_conn_ev_rx_rnr_rsp_fbit_set_1,
+	LLC_CONN_STATE_NORMAL,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_11
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 event */
+static llc_conn_action_t llc_await_actions_12a[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_12a = {
+	llc_conn_ev_rx_rnr_cmd_pbit_set_0,
+	LLC_CONN_STATE_AWAIT,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_12a
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 event */
+static llc_conn_action_t llc_await_actions_12b[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_12b = {
+	llc_conn_ev_rx_rnr_rsp_fbit_set_0,
+	LLC_CONN_STATE_AWAIT,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_12b
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_await_actions_13[] = {
+	llc_conn_ac_send_rr_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_13 = {
+	llc_conn_ev_rx_rnr_cmd_pbit_set_1,
+	LLC_CONN_STATE_AWAIT,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_actions_13
+};
+
+/* State transitions for LLC_CONN_EV_P_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_await_ev_qfyrs_14[] = {
+	llc_conn_ev_qlfy_retry_cnt_lt_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_await_actions_14[] = {
+	llc_conn_ac_send_rr_cmd_p_set_1,
+	llc_conn_ac_start_p_timer,
+	llc_conn_ac_inc_retry_cnt_by_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_state_trans_14 = {
+	llc_conn_ev_p_tmr_exp,
+	LLC_CONN_STATE_AWAIT,
+	llc_await_ev_qfyrs_14,
+	llc_await_actions_14
+};
+
+/*
+ * Array of pointers;
+ * one to each transition
+ */
+static struct llc_conn_state_trans *llc_await_state_transitions[] = {
+	&llc_common_state_trans_1,	/* Request */
+	&llc_common_state_trans_2,
+	&llc_await_state_trans_1_0,
+	&llc_common_state_trans_n,
+	&llc_await_state_trans_1,	/* Local busy */
+	&llc_common_state_trans_n,
+	&llc_common_state_trans_n,	/* Initiate PF Cycle */
+	&llc_common_state_trans_11a,	/* Timer */
+	&llc_common_state_trans_11b,
+	&llc_common_state_trans_11c,
+	&llc_common_state_trans_11d,
+	&llc_await_state_trans_14,
+	&llc_common_state_trans_n,
+	&llc_common_state_trans_3,	/* Receive frame */
+	&llc_common_state_trans_4,
+	&llc_common_state_trans_5,
+	&llc_common_state_trans_6,
+	&llc_common_state_trans_7a,
+	&llc_common_state_trans_7b,
+	&llc_common_state_trans_8a,
+	&llc_common_state_trans_8b,
+	&llc_common_state_trans_8c,
+	&llc_common_state_trans_9,
+	/* &llc_common_state_trans_10, */
+	&llc_await_state_trans_2,
+	&llc_await_state_trans_3a,
+	&llc_await_state_trans_3b,
+	&llc_await_state_trans_4,
+	&llc_await_state_trans_5,
+	&llc_await_state_trans_6a,
+	&llc_await_state_trans_6b,
+	&llc_await_state_trans_7,
+	&llc_await_state_trans_8a,
+	&llc_await_state_trans_8b,
+	&llc_await_state_trans_9a,
+	&llc_await_state_trans_9b,
+	&llc_await_state_trans_9c,
+	&llc_await_state_trans_9d,
+	&llc_await_state_trans_10a,
+	&llc_await_state_trans_10b,
+	&llc_await_state_trans_11,
+	&llc_await_state_trans_12a,
+	&llc_await_state_trans_12b,
+	&llc_await_state_trans_13,
+	&llc_common_state_trans_n
+};
+
+/* ------------------ LLC_CONN_STATE_AWAIT_BUSY transitions ---------------- */
+/* State transitions for LLC_CONN_EV_DATA_CONN_REQ event */
+static llc_conn_ev_qfyr_t llc_await_busy_ev_qfyrs_1_0[] = {
+	llc_conn_ev_qlfy_set_status_refuse,
+	NULL
+};
+
+/* just one member, NULL, .bss zeroes it */
+static llc_conn_action_t llc_await_busy_actions_1_0[1];
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_1_0 = {
+	llc_conn_ev_data_req,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	llc_await_busy_ev_qfyrs_1_0,
+	llc_await_busy_actions_1_0
+};
+
+/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */
+static llc_conn_ev_qfyr_t llc_await_busy_ev_qfyrs_1[] = {
+	llc_conn_ev_qlfy_data_flag_eq_1,
+	NULL
+};
+
+static llc_conn_action_t llc_await_busy_actions_1[] = {
+	llc_conn_ac_send_rej_xxx_x_set_0,
+	llc_conn_ac_start_rej_timer,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_1 = {
+	llc_conn_ev_local_busy_cleared,
+	LLC_CONN_STATE_AWAIT_REJ,
+	llc_await_busy_ev_qfyrs_1,
+	llc_await_busy_actions_1
+};
+
+/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */
+static llc_conn_ev_qfyr_t llc_await_busy_ev_qfyrs_2[] = {
+	llc_conn_ev_qlfy_data_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_await_busy_actions_2[] = {
+	llc_conn_ac_send_rr_xxx_x_set_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_2 = {
+	llc_conn_ev_local_busy_cleared,
+	LLC_CONN_STATE_AWAIT,
+	llc_await_busy_ev_qfyrs_2,
+	llc_await_busy_actions_2
+};
+
+/* State transitions for LLC_CONN_EV_LOCAL_BUSY_CLEARED event */
+static llc_conn_ev_qfyr_t llc_await_busy_ev_qfyrs_3[] = {
+	llc_conn_ev_qlfy_data_flag_eq_2,
+	NULL
+};
+
+static llc_conn_action_t llc_await_busy_actions_3[] = {
+	llc_conn_ac_send_rr_xxx_x_set_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_3 = {
+	llc_conn_ev_local_busy_cleared,
+	LLC_CONN_STATE_AWAIT_REJ,
+	llc_await_busy_ev_qfyrs_3,
+	llc_await_busy_actions_3
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1_UNEXPD_Ns event */
+static llc_conn_action_t llc_await_busy_actions_4[] = {
+	llc_conn_ac_opt_send_rnr_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_stop_p_timer,
+	llc_conn_ac_set_data_flag_1,
+	llc_conn_ac_clear_remote_busy,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_4 = {
+	llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns,
+	LLC_CONN_STATE_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_4
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */
+static llc_conn_action_t llc_await_busy_actions_5a[] = {
+	llc_conn_ac_opt_send_rnr_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_set_data_flag_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_5a = {
+	llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_5a
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */
+static llc_conn_action_t llc_await_busy_actions_5b[] = {
+	llc_conn_ac_opt_send_rnr_xxx_x_set_0,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_set_data_flag_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_5b = {
+	llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_5b
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns event */
+static llc_conn_action_t llc_await_busy_actions_6[] = {
+	llc_conn_ac_send_rnr_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_set_data_flag_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_6 = {
+	llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_6
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1 event */
+static llc_conn_action_t llc_await_busy_actions_7[] = {
+	llc_conn_ac_opt_send_rnr_xxx_x_set_0,
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_stop_p_timer,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_set_data_flag_0,
+	llc_conn_ac_clear_remote_busy,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_7 = {
+	llc_conn_ev_rx_i_rsp_fbit_set_1,
+	LLC_CONN_STATE_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_7
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 event */
+static llc_conn_action_t llc_await_busy_actions_8a[] = {
+	llc_conn_ac_opt_send_rnr_xxx_x_set_0,
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_set_data_flag_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_8a = {
+	llc_conn_ev_rx_i_rsp_fbit_set_0,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_8a
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */
+static llc_conn_action_t llc_await_busy_actions_8b[] = {
+	llc_conn_ac_opt_send_rnr_xxx_x_set_0,
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_set_data_flag_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_8b = {
+	llc_conn_ev_rx_i_cmd_pbit_set_0,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_8b
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_await_busy_actions_9[] = {
+	llc_conn_ac_send_rnr_rsp_f_set_1,
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_set_data_flag_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_9 = {
+	llc_conn_ev_rx_i_cmd_pbit_set_1,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_9
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 event */
+static llc_conn_action_t llc_await_busy_actions_10a[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_stop_p_timer,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_10a = {
+	llc_conn_ev_rx_rr_rsp_fbit_set_1,
+	LLC_CONN_STATE_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_10a
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_1 event */
+static llc_conn_action_t llc_await_busy_actions_10b[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_stop_p_timer,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_10b = {
+	llc_conn_ev_rx_rej_rsp_fbit_set_1,
+	LLC_CONN_STATE_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_10b
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 event */
+static llc_conn_action_t llc_await_busy_actions_11a[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_11a = {
+	llc_conn_ev_rx_rr_cmd_pbit_set_0,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_11a
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 event */
+static llc_conn_action_t llc_await_busy_actions_11b[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_11b = {
+	llc_conn_ev_rx_rr_rsp_fbit_set_0,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_11b
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */
+static llc_conn_action_t llc_await_busy_actions_11c[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_11c = {
+	llc_conn_ev_rx_rej_cmd_pbit_set_0,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_11c
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 event */
+static llc_conn_action_t llc_await_busy_actions_11d[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_11d = {
+	llc_conn_ev_rx_rej_rsp_fbit_set_0,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_11d
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_await_busy_actions_12a[] = {
+	llc_conn_ac_send_rnr_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_12a = {
+	llc_conn_ev_rx_rr_cmd_pbit_set_1,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_12a
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_await_busy_actions_12b[] = {
+	llc_conn_ac_send_rnr_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_12b = {
+	llc_conn_ev_rx_rej_cmd_pbit_set_1,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_12b
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 event */
+static llc_conn_action_t llc_await_busy_actions_13[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_stop_p_timer,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_13 = {
+	llc_conn_ev_rx_rnr_rsp_fbit_set_1,
+	LLC_CONN_STATE_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_13
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 event */
+static llc_conn_action_t llc_await_busy_actions_14a[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_14a = {
+	llc_conn_ev_rx_rnr_cmd_pbit_set_0,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_14a
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 event */
+static llc_conn_action_t llc_await_busy_actions_14b[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_14b = {
+	llc_conn_ev_rx_rnr_rsp_fbit_set_0,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_14b
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_await_busy_actions_15[] = {
+	llc_conn_ac_send_rnr_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_15 = {
+	llc_conn_ev_rx_rnr_cmd_pbit_set_1,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_busy_actions_15
+};
+
+/* State transitions for LLC_CONN_EV_P_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_await_busy_ev_qfyrs_16[] = {
+	llc_conn_ev_qlfy_retry_cnt_lt_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_await_busy_actions_16[] = {
+	llc_conn_ac_send_rnr_cmd_p_set_1,
+	llc_conn_ac_start_p_timer,
+	llc_conn_ac_inc_retry_cnt_by_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_busy_state_trans_16 = {
+	llc_conn_ev_p_tmr_exp,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	llc_await_busy_ev_qfyrs_16,
+	llc_await_busy_actions_16
+};
+
+/*
+ * Array of pointers;
+ * one to each transition
+ */
+static struct llc_conn_state_trans *llc_await_busy_state_transitions[] = {
+	&llc_common_state_trans_1,		/* Request */
+	&llc_common_state_trans_2,
+	&llc_await_busy_state_trans_1_0,
+	&llc_common_state_trans_n,
+	&llc_await_busy_state_trans_1,		/* Local busy */
+	&llc_await_busy_state_trans_2,
+	&llc_await_busy_state_trans_3,
+	&llc_common_state_trans_n,
+	&llc_common_state_trans_n,		/* Initiate PF cycle */
+	&llc_common_state_trans_11a,		/* Timer */
+	&llc_common_state_trans_11b,
+	&llc_common_state_trans_11c,
+	&llc_common_state_trans_11d,
+	&llc_await_busy_state_trans_16,
+	&llc_common_state_trans_n,
+	&llc_await_busy_state_trans_4,		/* Receive frame */
+	&llc_await_busy_state_trans_5a,
+	&llc_await_busy_state_trans_5b,
+	&llc_await_busy_state_trans_6,
+	&llc_await_busy_state_trans_7,
+	&llc_await_busy_state_trans_8a,
+	&llc_await_busy_state_trans_8b,
+	&llc_await_busy_state_trans_9,
+	&llc_await_busy_state_trans_10a,
+	&llc_await_busy_state_trans_10b,
+	&llc_await_busy_state_trans_11a,
+	&llc_await_busy_state_trans_11b,
+	&llc_await_busy_state_trans_11c,
+	&llc_await_busy_state_trans_11d,
+	&llc_await_busy_state_trans_12a,
+	&llc_await_busy_state_trans_12b,
+	&llc_await_busy_state_trans_13,
+	&llc_await_busy_state_trans_14a,
+	&llc_await_busy_state_trans_14b,
+	&llc_await_busy_state_trans_15,
+	&llc_common_state_trans_3,
+	&llc_common_state_trans_4,
+	&llc_common_state_trans_5,
+	&llc_common_state_trans_6,
+	&llc_common_state_trans_7a,
+	&llc_common_state_trans_7b,
+	&llc_common_state_trans_8a,
+	&llc_common_state_trans_8b,
+	&llc_common_state_trans_8c,
+	&llc_common_state_trans_9,
+	/* &llc_common_state_trans_10, */
+	&llc_common_state_trans_n
+};
+
+/* ----------------- LLC_CONN_STATE_AWAIT_REJ transitions --------------- */
+/* State transitions for LLC_CONN_EV_DATA_CONN_REQ event */
+static llc_conn_ev_qfyr_t llc_await_reject_ev_qfyrs_1_0[] = {
+	llc_conn_ev_qlfy_set_status_refuse,
+	NULL
+};
+
+/* just one member, NULL, .bss zeroes it */
+static llc_conn_action_t llc_await_reject_actions_1_0[1];
+
+static struct llc_conn_state_trans llc_await_reject_state_trans_1_0 = {
+	llc_conn_ev_data_req,
+	LLC_CONN_STATE_AWAIT_REJ,
+	llc_await_reject_ev_qfyrs_1_0,
+	llc_await_reject_actions_1_0
+};
+
+/* State transitions for LLC_CONN_EV_LOCAL_BUSY_DETECTED event */
+static llc_conn_action_t llc_await_rejct_actions_1[] = {
+	llc_conn_ac_send_rnr_xxx_x_set_0,
+	llc_conn_ac_set_data_flag_2,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_1 = {
+	llc_conn_ev_local_busy_detected,
+	LLC_CONN_STATE_AWAIT_BUSY,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_1
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0_UNEXPD_Ns event */
+static llc_conn_action_t llc_await_rejct_actions_2a[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_2a = {
+	llc_conn_ev_rx_i_cmd_pbit_set_0_unexpd_ns,
+	LLC_CONN_STATE_AWAIT_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_2a
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0_UNEXPD_Ns event */
+static llc_conn_action_t llc_await_rejct_actions_2b[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_2b = {
+	llc_conn_ev_rx_i_rsp_fbit_set_0_unexpd_ns,
+	LLC_CONN_STATE_AWAIT_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_2b
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1_UNEXPD_Ns event */
+static llc_conn_action_t llc_await_rejct_actions_3[] = {
+	llc_conn_ac_send_rr_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_3 = {
+	llc_conn_ev_rx_i_cmd_pbit_set_1_unexpd_ns,
+	LLC_CONN_STATE_AWAIT_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_3
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1 event */
+static llc_conn_action_t llc_await_rejct_actions_4[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_stop_p_timer,
+	llc_conn_ac_stop_rej_timer,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_4 = {
+	llc_conn_ev_rx_i_rsp_fbit_set_1,
+	LLC_CONN_STATE_NORMAL,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_4
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_0 event */
+static llc_conn_action_t llc_await_rejct_actions_5a[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_send_rr_xxx_x_set_0,
+	llc_conn_ac_stop_rej_timer,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_5a = {
+	llc_conn_ev_rx_i_rsp_fbit_set_0,
+	LLC_CONN_STATE_AWAIT,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_5a
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_0 event */
+static llc_conn_action_t llc_await_rejct_actions_5b[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_send_rr_xxx_x_set_0,
+	llc_conn_ac_stop_rej_timer,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_5b = {
+	llc_conn_ev_rx_i_cmd_pbit_set_0,     LLC_CONN_STATE_AWAIT,
+	LLC_NO_EVENT_QUALIFIERS,	     llc_await_rejct_actions_5b
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_await_rejct_actions_6[] = {
+	llc_conn_ac_inc_vr_by_1,
+	llc_conn_ac_data_ind,
+	llc_conn_ac_send_rr_rsp_f_set_1,
+	llc_conn_ac_stop_rej_timer,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_6 = {
+	llc_conn_ev_rx_i_cmd_pbit_set_1,
+	LLC_CONN_STATE_AWAIT,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_6
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_1 event */
+static llc_conn_action_t llc_await_rejct_actions_7a[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_stop_p_timer,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_7a = {
+	llc_conn_ev_rx_rr_rsp_fbit_set_1,
+	LLC_CONN_STATE_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_7a
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_1 event */
+static llc_conn_action_t llc_await_rejct_actions_7b[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_stop_p_timer,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_7b = {
+	llc_conn_ev_rx_rej_rsp_fbit_set_1,
+	LLC_CONN_STATE_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_7b
+};
+
+/* State transitions for LLC_CONN_EV_RX_I_RSP_Fbit_SET_1_UNEXPD_Ns event */
+static llc_conn_action_t llc_await_rejct_actions_7c[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_stop_p_timer,
+	llc_conn_ac_resend_i_xxx_x_set_0,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_7c = {
+	llc_conn_ev_rx_i_rsp_fbit_set_1_unexpd_ns,
+	LLC_CONN_STATE_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_7c
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_0 event */
+static llc_conn_action_t llc_await_rejct_actions_8a[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_8a = {
+	llc_conn_ev_rx_rr_cmd_pbit_set_0,
+	LLC_CONN_STATE_AWAIT_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_8a
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_RSP_Fbit_SET_0 event */
+static llc_conn_action_t llc_await_rejct_actions_8b[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_8b = {
+	llc_conn_ev_rx_rr_rsp_fbit_set_0,
+	LLC_CONN_STATE_AWAIT_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_8b
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_0 event */
+static llc_conn_action_t llc_await_rejct_actions_8c[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_8c = {
+	llc_conn_ev_rx_rej_cmd_pbit_set_0,
+	LLC_CONN_STATE_AWAIT_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_8c
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_RSP_Fbit_SET_0 event */
+static llc_conn_action_t llc_await_rejct_actions_8d[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_8d = {
+	llc_conn_ev_rx_rej_rsp_fbit_set_0,
+	LLC_CONN_STATE_AWAIT_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_8d
+};
+
+/* State transitions for LLC_CONN_EV_RX_RR_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_await_rejct_actions_9a[] = {
+	llc_conn_ac_send_rr_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_9a = {
+	llc_conn_ev_rx_rr_cmd_pbit_set_1,
+	LLC_CONN_STATE_AWAIT_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_9a
+};
+
+/* State transitions for LLC_CONN_EV_RX_REJ_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_await_rejct_actions_9b[] = {
+	llc_conn_ac_send_rr_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_clear_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_9b = {
+	llc_conn_ev_rx_rej_cmd_pbit_set_1,
+	LLC_CONN_STATE_AWAIT_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_9b
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_1 event */
+static llc_conn_action_t llc_await_rejct_actions_10[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_stop_p_timer,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_10 = {
+	llc_conn_ev_rx_rnr_rsp_fbit_set_1,
+	LLC_CONN_STATE_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_10
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_0 event */
+static llc_conn_action_t llc_await_rejct_actions_11a[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_11a = {
+	llc_conn_ev_rx_rnr_cmd_pbit_set_0,
+	LLC_CONN_STATE_AWAIT_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_11a
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_RSP_Fbit_SET_0 event */
+static llc_conn_action_t llc_await_rejct_actions_11b[] = {
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_11b = {
+	llc_conn_ev_rx_rnr_rsp_fbit_set_0,
+	LLC_CONN_STATE_AWAIT_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_11b
+};
+
+/* State transitions for LLC_CONN_EV_RX_RNR_CMD_Pbit_SET_1 event */
+static llc_conn_action_t llc_await_rejct_actions_12[] = {
+	llc_conn_ac_send_rr_rsp_f_set_1,
+	llc_conn_ac_upd_nr_received,
+	llc_conn_ac_upd_vs,
+	llc_conn_ac_set_remote_busy,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_12 = {
+	llc_conn_ev_rx_rnr_cmd_pbit_set_1,
+	LLC_CONN_STATE_AWAIT_REJ,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_await_rejct_actions_12
+};
+
+/* State transitions for LLC_CONN_EV_P_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_await_rejct_ev_qfyrs_13[] = {
+	llc_conn_ev_qlfy_retry_cnt_lt_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_await_rejct_actions_13[] = {
+	llc_conn_ac_send_rej_cmd_p_set_1,
+	llc_conn_ac_stop_p_timer,
+	llc_conn_ac_inc_retry_cnt_by_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_await_rejct_state_trans_13 = {
+	llc_conn_ev_p_tmr_exp,
+	LLC_CONN_STATE_AWAIT_REJ,
+	llc_await_rejct_ev_qfyrs_13,
+	llc_await_rejct_actions_13
+};
+
+/*
+ * Array of pointers;
+ * one to each transition
+ */
+static struct llc_conn_state_trans *llc_await_rejct_state_transitions[] = {
+	&llc_await_reject_state_trans_1_0,
+	&llc_common_state_trans_1,		/* requests */
+	&llc_common_state_trans_2,
+	&llc_common_state_trans_n,
+	&llc_await_rejct_state_trans_1,		/* local busy */
+	&llc_common_state_trans_n,
+	&llc_common_state_trans_n,		/* Initiate PF cycle */
+	&llc_await_rejct_state_trans_13,	/* timers */
+	&llc_common_state_trans_11a,
+	&llc_common_state_trans_11b,
+	&llc_common_state_trans_11c,
+	&llc_common_state_trans_11d,
+	&llc_common_state_trans_n,
+	&llc_await_rejct_state_trans_2a,	/* receive frames */
+	&llc_await_rejct_state_trans_2b,
+	&llc_await_rejct_state_trans_3,
+	&llc_await_rejct_state_trans_4,
+	&llc_await_rejct_state_trans_5a,
+	&llc_await_rejct_state_trans_5b,
+	&llc_await_rejct_state_trans_6,
+	&llc_await_rejct_state_trans_7a,
+	&llc_await_rejct_state_trans_7b,
+	&llc_await_rejct_state_trans_7c,
+	&llc_await_rejct_state_trans_8a,
+	&llc_await_rejct_state_trans_8b,
+	&llc_await_rejct_state_trans_8c,
+	&llc_await_rejct_state_trans_8d,
+	&llc_await_rejct_state_trans_9a,
+	&llc_await_rejct_state_trans_9b,
+	&llc_await_rejct_state_trans_10,
+	&llc_await_rejct_state_trans_11a,
+	&llc_await_rejct_state_trans_11b,
+	&llc_await_rejct_state_trans_12,
+	&llc_common_state_trans_3,
+	&llc_common_state_trans_4,
+	&llc_common_state_trans_5,
+	&llc_common_state_trans_6,
+	&llc_common_state_trans_7a,
+	&llc_common_state_trans_7b,
+	&llc_common_state_trans_8a,
+	&llc_common_state_trans_8b,
+	&llc_common_state_trans_8c,
+	&llc_common_state_trans_9,
+	/* &llc_common_state_trans_10, */
+	&llc_common_state_trans_n
+};
+
+/* -------------------- LLC_CONN_STATE_D_CONN transitions ------------------ */
+/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event,
+ * cause_flag = 1 */
+static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_1[] = {
+	llc_conn_ev_qlfy_cause_flag_eq_1,
+	llc_conn_ev_qlfy_set_status_conflict,
+	NULL
+};
+
+static llc_conn_action_t llc_d_conn_actions_1[] = {
+	llc_conn_ac_send_dm_rsp_f_set_p,
+	llc_conn_ac_stop_ack_timer,
+	llc_conn_ac_disc_confirm,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_d_conn_state_trans_1 = {
+	llc_conn_ev_rx_sabme_cmd_pbit_set_x,
+	LLC_CONN_STATE_ADM,
+	llc_d_conn_ev_qfyrs_1,
+	llc_d_conn_actions_1
+};
+
+/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event,
+ * cause_flag = 0
+ */
+static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_1_1[] = {
+	llc_conn_ev_qlfy_cause_flag_eq_0,
+	llc_conn_ev_qlfy_set_status_conflict,
+	NULL
+};
+
+static llc_conn_action_t llc_d_conn_actions_1_1[] = {
+	llc_conn_ac_send_dm_rsp_f_set_p,
+	llc_conn_ac_stop_ack_timer,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_d_conn_state_trans_1_1 = {
+	llc_conn_ev_rx_sabme_cmd_pbit_set_x,
+	LLC_CONN_STATE_ADM,
+	llc_d_conn_ev_qfyrs_1_1,
+	llc_d_conn_actions_1_1
+};
+
+/* State transitions for LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X event,
+ * cause_flag = 1 */
+static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_2[] = {
+	llc_conn_ev_qlfy_p_flag_eq_f,
+	llc_conn_ev_qlfy_cause_flag_eq_1,
+	llc_conn_ev_qlfy_set_status_disc,
+	NULL
+};
+
+static llc_conn_action_t llc_d_conn_actions_2[] = {
+	llc_conn_ac_stop_ack_timer,
+	llc_conn_ac_disc_confirm,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_d_conn_state_trans_2 = {
+	llc_conn_ev_rx_ua_rsp_fbit_set_x,
+	LLC_CONN_STATE_ADM,
+	llc_d_conn_ev_qfyrs_2,
+	llc_d_conn_actions_2
+};
+
+/* State transitions for LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X event,
+ * cause_flag = 0 */
+static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_2_1[] = {
+	llc_conn_ev_qlfy_p_flag_eq_f,
+	llc_conn_ev_qlfy_cause_flag_eq_0,
+	llc_conn_ev_qlfy_set_status_disc,
+	NULL
+};
+
+static llc_conn_action_t llc_d_conn_actions_2_1[] = {
+	llc_conn_ac_stop_ack_timer,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_d_conn_state_trans_2_1 = {
+	llc_conn_ev_rx_ua_rsp_fbit_set_x,
+	LLC_CONN_STATE_ADM,
+	llc_d_conn_ev_qfyrs_2_1,
+	llc_d_conn_actions_2_1
+};
+
+/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event */
+static llc_conn_action_t llc_d_conn_actions_3[] = {
+	llc_conn_ac_send_ua_rsp_f_set_p,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_d_conn_state_trans_3 = {
+	llc_conn_ev_rx_disc_cmd_pbit_set_x,
+	LLC_CONN_STATE_D_CONN,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_d_conn_actions_3
+};
+
+/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event,
+ * cause_flag = 1 */
+static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_4[] = {
+	llc_conn_ev_qlfy_cause_flag_eq_1,
+	llc_conn_ev_qlfy_set_status_disc,
+	NULL
+};
+
+static llc_conn_action_t llc_d_conn_actions_4[] = {
+	llc_conn_ac_stop_ack_timer,
+	llc_conn_ac_disc_confirm,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_d_conn_state_trans_4 = {
+	llc_conn_ev_rx_dm_rsp_fbit_set_x,
+	LLC_CONN_STATE_ADM,
+	llc_d_conn_ev_qfyrs_4,
+	llc_d_conn_actions_4
+};
+
+/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event,
+ * cause_flag = 0 */
+static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_4_1[] = {
+	llc_conn_ev_qlfy_cause_flag_eq_0,
+	llc_conn_ev_qlfy_set_status_disc,
+	NULL
+};
+
+static llc_conn_action_t llc_d_conn_actions_4_1[] = {
+	llc_conn_ac_stop_ack_timer,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_d_conn_state_trans_4_1 = {
+	llc_conn_ev_rx_dm_rsp_fbit_set_x,
+	LLC_CONN_STATE_ADM,
+	llc_d_conn_ev_qfyrs_4_1,
+	llc_d_conn_actions_4_1
+};
+
+/*
+ * State transition for
+ * LLC_CONN_EV_DATA_CONN_REQ event
+ */
+static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_5[] = {
+	llc_conn_ev_qlfy_set_status_refuse,
+	NULL
+};
+
+/* just one member, NULL, .bss zeroes it */
+static llc_conn_action_t llc_d_conn_actions_5[1];
+
+static struct llc_conn_state_trans llc_d_conn_state_trans_5 = {
+	llc_conn_ev_data_req, LLC_CONN_STATE_D_CONN,
+	llc_d_conn_ev_qfyrs_5, llc_d_conn_actions_5
+};
+
+/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_6[] = {
+	llc_conn_ev_qlfy_retry_cnt_lt_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_d_conn_actions_6[] = {
+	llc_conn_ac_send_disc_cmd_p_set_x,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_inc_retry_cnt_by_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_d_conn_state_trans_6 = {
+	llc_conn_ev_ack_tmr_exp,
+	LLC_CONN_STATE_D_CONN,
+	llc_d_conn_ev_qfyrs_6,
+	llc_d_conn_actions_6
+};
+
+/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event, cause_flag = 1 */
+static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_7[] = {
+	llc_conn_ev_qlfy_retry_cnt_gte_n2,
+	llc_conn_ev_qlfy_cause_flag_eq_1,
+	llc_conn_ev_qlfy_set_status_failed,
+	NULL
+};
+
+static llc_conn_action_t llc_d_conn_actions_7[] = {
+	llc_conn_ac_disc_confirm,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_d_conn_state_trans_7 = {
+	llc_conn_ev_ack_tmr_exp,
+	LLC_CONN_STATE_ADM,
+	llc_d_conn_ev_qfyrs_7,
+	llc_d_conn_actions_7
+};
+
+/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event, cause_flag = 0 */
+static llc_conn_ev_qfyr_t llc_d_conn_ev_qfyrs_8[] = {
+	llc_conn_ev_qlfy_retry_cnt_gte_n2,
+	llc_conn_ev_qlfy_cause_flag_eq_0,
+	llc_conn_ev_qlfy_set_status_failed,
+	NULL
+};
+
+static llc_conn_action_t llc_d_conn_actions_8[] = {
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_d_conn_state_trans_8 = {
+	llc_conn_ev_ack_tmr_exp,
+	LLC_CONN_STATE_ADM,
+	llc_d_conn_ev_qfyrs_8,
+	llc_d_conn_actions_8
+};
+
+/*
+ * Array of pointers;
+ * one to each transition
+ */
+static struct llc_conn_state_trans *llc_d_conn_state_transitions[] = {
+	&llc_d_conn_state_trans_5,	/* Request */
+	&llc_common_state_trans_n,
+	&llc_common_state_trans_n,	/* Local busy */
+	&llc_common_state_trans_n,	/* Initiate PF cycle */
+	&llc_d_conn_state_trans_6,	/* Timer */
+	&llc_d_conn_state_trans_7,
+	&llc_d_conn_state_trans_8,
+	&llc_common_state_trans_n,
+	&llc_d_conn_state_trans_1,	/* Receive frame */
+	&llc_d_conn_state_trans_1_1,
+	&llc_d_conn_state_trans_2,
+	&llc_d_conn_state_trans_2_1,
+	&llc_d_conn_state_trans_3,
+	&llc_d_conn_state_trans_4,
+	&llc_d_conn_state_trans_4_1,
+	&llc_common_state_trans_n
+};
+
+/* -------------------- LLC_CONN_STATE_RESET transitions ------------------- */
+/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event */
+static llc_conn_action_t llc_rst_actions_1[] = {
+	llc_conn_ac_set_vs_0,
+	llc_conn_ac_set_vr_0,
+	llc_conn_ac_set_s_flag_1,
+	llc_conn_ac_send_ua_rsp_f_set_p,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_rst_state_trans_1 = {
+	llc_conn_ev_rx_sabme_cmd_pbit_set_x,
+	LLC_CONN_STATE_RESET,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_rst_actions_1
+};
+
+/* State transitions for LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X event,
+ * cause_flag = 1 */
+static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_2[] = {
+	llc_conn_ev_qlfy_p_flag_eq_f,
+	llc_conn_ev_qlfy_cause_flag_eq_1,
+	llc_conn_ev_qlfy_set_status_conn,
+	NULL
+};
+
+static llc_conn_action_t llc_rst_actions_2[] = {
+	llc_conn_ac_stop_ack_timer,
+	llc_conn_ac_set_vs_0,
+	llc_conn_ac_set_vr_0,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_rst_confirm,
+	llc_conn_ac_set_remote_busy_0,
+	llc_conn_reset,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_rst_state_trans_2 = {
+	llc_conn_ev_rx_ua_rsp_fbit_set_x,
+	LLC_CONN_STATE_NORMAL,
+	llc_rst_ev_qfyrs_2,
+	llc_rst_actions_2
+};
+
+/* State transitions for LLC_CONN_EV_RX_UA_RSP_Fbit_SET_X event,
+ * cause_flag = 0 */
+static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_2_1[] = {
+	llc_conn_ev_qlfy_p_flag_eq_f,
+	llc_conn_ev_qlfy_cause_flag_eq_0,
+	llc_conn_ev_qlfy_set_status_rst_done,
+	NULL
+};
+
+static llc_conn_action_t llc_rst_actions_2_1[] = {
+	llc_conn_ac_stop_ack_timer,
+	llc_conn_ac_set_vs_0,
+	llc_conn_ac_set_vr_0,
+	llc_conn_ac_upd_p_flag,
+	llc_conn_ac_rst_confirm,
+	llc_conn_ac_set_remote_busy_0,
+	llc_conn_reset,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_rst_state_trans_2_1 = {
+	llc_conn_ev_rx_ua_rsp_fbit_set_x,
+	LLC_CONN_STATE_NORMAL,
+	llc_rst_ev_qfyrs_2_1,
+	llc_rst_actions_2_1
+};
+
+/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_3[] = {
+	llc_conn_ev_qlfy_s_flag_eq_1,
+	llc_conn_ev_qlfy_set_status_rst_done,
+	NULL
+};
+
+static llc_conn_action_t llc_rst_actions_3[] = {
+	llc_conn_ac_set_p_flag_0,
+	llc_conn_ac_set_remote_busy_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_rst_state_trans_3 = {
+	llc_conn_ev_ack_tmr_exp,
+	LLC_CONN_STATE_NORMAL,
+	llc_rst_ev_qfyrs_3,
+	llc_rst_actions_3
+};
+
+/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event,
+ * cause_flag = 1 */
+static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_4[] = {
+	llc_conn_ev_qlfy_cause_flag_eq_1,
+	llc_conn_ev_qlfy_set_status_disc,
+	NULL
+};
+static llc_conn_action_t llc_rst_actions_4[] = {
+	llc_conn_ac_send_dm_rsp_f_set_p,
+	llc_conn_ac_disc_ind,
+	llc_conn_ac_stop_ack_timer,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_rst_state_trans_4 = {
+	llc_conn_ev_rx_disc_cmd_pbit_set_x,
+	LLC_CONN_STATE_ADM,
+	llc_rst_ev_qfyrs_4,
+	llc_rst_actions_4
+};
+
+/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event,
+ * cause_flag = 0 */
+static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_4_1[] = {
+	llc_conn_ev_qlfy_cause_flag_eq_0,
+	llc_conn_ev_qlfy_set_status_refuse,
+	NULL
+};
+
+static llc_conn_action_t llc_rst_actions_4_1[] = {
+	llc_conn_ac_send_dm_rsp_f_set_p,
+	llc_conn_ac_stop_ack_timer,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_rst_state_trans_4_1 = {
+	llc_conn_ev_rx_disc_cmd_pbit_set_x,
+	LLC_CONN_STATE_ADM,
+	llc_rst_ev_qfyrs_4_1,
+	llc_rst_actions_4_1
+};
+
+/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event,
+ * cause_flag = 1 */
+static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_5[] = {
+	llc_conn_ev_qlfy_cause_flag_eq_1,
+	llc_conn_ev_qlfy_set_status_disc,
+	NULL
+};
+
+static llc_conn_action_t llc_rst_actions_5[] = {
+	llc_conn_ac_disc_ind,
+	llc_conn_ac_stop_ack_timer,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_rst_state_trans_5 = {
+	llc_conn_ev_rx_dm_rsp_fbit_set_x,
+	LLC_CONN_STATE_ADM,
+	llc_rst_ev_qfyrs_5,
+	llc_rst_actions_5
+};
+
+/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event,
+ * cause_flag = 0 */
+static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_5_1[] = {
+	llc_conn_ev_qlfy_cause_flag_eq_0,
+	llc_conn_ev_qlfy_set_status_refuse,
+	NULL
+};
+
+static llc_conn_action_t llc_rst_actions_5_1[] = {
+	llc_conn_ac_stop_ack_timer,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_rst_state_trans_5_1 = {
+	llc_conn_ev_rx_dm_rsp_fbit_set_x,
+	LLC_CONN_STATE_ADM,
+	llc_rst_ev_qfyrs_5_1,
+	llc_rst_actions_5_1
+};
+
+/* State transitions for DATA_CONN_REQ event */
+static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_6[] = {
+	llc_conn_ev_qlfy_set_status_refuse,
+	NULL
+};
+
+/* just one member, NULL, .bss zeroes it */
+static llc_conn_action_t llc_rst_actions_6[1];
+
+static struct llc_conn_state_trans llc_rst_state_trans_6 = {
+	llc_conn_ev_data_req,
+	LLC_CONN_STATE_RESET,
+	llc_rst_ev_qfyrs_6,
+	llc_rst_actions_6
+};
+
+/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_7[] = {
+	llc_conn_ev_qlfy_retry_cnt_lt_n2,
+	llc_conn_ev_qlfy_s_flag_eq_0,
+	NULL
+};
+
+static llc_conn_action_t llc_rst_actions_7[] = {
+	llc_conn_ac_send_sabme_cmd_p_set_x,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_inc_retry_cnt_by_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_rst_state_trans_7 = {
+	llc_conn_ev_ack_tmr_exp,
+	LLC_CONN_STATE_RESET,
+	llc_rst_ev_qfyrs_7,
+	llc_rst_actions_7
+};
+
+/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_8[] = {
+	llc_conn_ev_qlfy_retry_cnt_gte_n2,
+	llc_conn_ev_qlfy_s_flag_eq_0,
+	llc_conn_ev_qlfy_cause_flag_eq_1,
+	llc_conn_ev_qlfy_set_status_failed,
+	NULL
+};
+static llc_conn_action_t llc_rst_actions_8[] = {
+	llc_conn_ac_disc_ind,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_rst_state_trans_8 = {
+	llc_conn_ev_ack_tmr_exp,
+	LLC_CONN_STATE_ADM,
+	llc_rst_ev_qfyrs_8,
+	llc_rst_actions_8
+};
+
+/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_rst_ev_qfyrs_8_1[] = {
+	llc_conn_ev_qlfy_retry_cnt_gte_n2,
+	llc_conn_ev_qlfy_s_flag_eq_0,
+	llc_conn_ev_qlfy_cause_flag_eq_0,
+	llc_conn_ev_qlfy_set_status_failed,
+	NULL
+};
+static llc_conn_action_t llc_rst_actions_8_1[] = {
+	llc_conn_ac_disc_ind,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_rst_state_trans_8_1 = {
+	llc_conn_ev_ack_tmr_exp,
+	LLC_CONN_STATE_ADM,
+	llc_rst_ev_qfyrs_8_1,
+	llc_rst_actions_8_1
+};
+
+/*
+ * Array of pointers;
+ * one to each transition
+ */
+static struct llc_conn_state_trans *llc_rst_state_transitions[] = {
+	&llc_rst_state_trans_6,		/* Request */
+	&llc_common_state_trans_n,
+	&llc_common_state_trans_n,	/* Local busy */
+	&llc_common_state_trans_n,	/* Initiate PF cycle */
+	&llc_rst_state_trans_3,		/* Timer */
+	&llc_rst_state_trans_7,
+	&llc_rst_state_trans_8,
+	&llc_rst_state_trans_8_1,
+	&llc_common_state_trans_n,
+	&llc_rst_state_trans_1,		/* Receive frame */
+	&llc_rst_state_trans_2,
+	&llc_rst_state_trans_2_1,
+	&llc_rst_state_trans_4,
+	&llc_rst_state_trans_4_1,
+	&llc_rst_state_trans_5,
+	&llc_rst_state_trans_5_1,
+	&llc_common_state_trans_n
+};
+
+/* -------------------- LLC_CONN_STATE_ERROR transitions ------------------- */
+/* State transitions for LLC_CONN_EV_RX_SABME_CMD_Pbit_SET_X event */
+static llc_conn_action_t llc_error_actions_1[] = {
+	llc_conn_ac_set_vs_0,
+	llc_conn_ac_set_vr_0,
+	llc_conn_ac_send_ua_rsp_f_set_p,
+	llc_conn_ac_rst_ind,
+	llc_conn_ac_set_p_flag_0,
+	llc_conn_ac_set_remote_busy_0,
+	llc_conn_ac_stop_ack_timer,
+	llc_conn_reset,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_error_state_trans_1 = {
+	llc_conn_ev_rx_sabme_cmd_pbit_set_x,
+	LLC_CONN_STATE_NORMAL,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_error_actions_1
+};
+
+/* State transitions for LLC_CONN_EV_RX_DISC_CMD_Pbit_SET_X event */
+static llc_conn_action_t llc_error_actions_2[] = {
+	llc_conn_ac_send_ua_rsp_f_set_p,
+	llc_conn_ac_disc_ind,
+	llc_conn_ac_stop_ack_timer,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_error_state_trans_2 = {
+	llc_conn_ev_rx_disc_cmd_pbit_set_x,
+	LLC_CONN_STATE_ADM,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_error_actions_2
+};
+
+/* State transitions for LLC_CONN_EV_RX_DM_RSP_Fbit_SET_X event */
+static llc_conn_action_t llc_error_actions_3[] = {
+	llc_conn_ac_disc_ind,
+	llc_conn_ac_stop_ack_timer,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_error_state_trans_3 = {
+	llc_conn_ev_rx_dm_rsp_fbit_set_x,
+	LLC_CONN_STATE_ADM,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_error_actions_3
+};
+
+/* State transitions for LLC_CONN_EV_RX_FRMR_RSP_Fbit_SET_X event */
+static llc_conn_action_t llc_error_actions_4[] = {
+	llc_conn_ac_send_sabme_cmd_p_set_x,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_set_retry_cnt_0,
+	llc_conn_ac_set_cause_flag_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_error_state_trans_4 = {
+	llc_conn_ev_rx_frmr_rsp_fbit_set_x,
+	LLC_CONN_STATE_RESET,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_error_actions_4
+};
+
+/* State transitions for LLC_CONN_EV_RX_XXX_CMD_Pbit_SET_X event */
+static llc_conn_action_t llc_error_actions_5[] = {
+	llc_conn_ac_resend_frmr_rsp_f_set_p,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_error_state_trans_5 = {
+	llc_conn_ev_rx_xxx_cmd_pbit_set_x,
+	LLC_CONN_STATE_ERROR,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_error_actions_5
+};
+
+/* State transitions for LLC_CONN_EV_RX_XXX_RSP_Fbit_SET_X event */
+static struct llc_conn_state_trans llc_error_state_trans_6 = {
+	llc_conn_ev_rx_xxx_rsp_fbit_set_x,
+	LLC_CONN_STATE_ERROR,
+	LLC_NO_EVENT_QUALIFIERS,
+	LLC_NO_TRANSITION_ACTIONS
+};
+
+/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_error_ev_qfyrs_7[] = {
+	llc_conn_ev_qlfy_retry_cnt_lt_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_error_actions_7[] = {
+	llc_conn_ac_resend_frmr_rsp_f_set_0,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_inc_retry_cnt_by_1,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_error_state_trans_7 = {
+	llc_conn_ev_ack_tmr_exp,
+	LLC_CONN_STATE_ERROR,
+	llc_error_ev_qfyrs_7,
+	llc_error_actions_7
+};
+
+/* State transitions for LLC_CONN_EV_ACK_TMR_EXP event */
+static llc_conn_ev_qfyr_t llc_error_ev_qfyrs_8[] = {
+	llc_conn_ev_qlfy_retry_cnt_gte_n2,
+	NULL
+};
+
+static llc_conn_action_t llc_error_actions_8[] = {
+	llc_conn_ac_send_sabme_cmd_p_set_x,
+	llc_conn_ac_set_s_flag_0,
+	llc_conn_ac_start_ack_timer,
+	llc_conn_ac_set_retry_cnt_0,
+	llc_conn_ac_set_cause_flag_0,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_error_state_trans_8 = {
+	llc_conn_ev_ack_tmr_exp,
+	LLC_CONN_STATE_RESET,
+	llc_error_ev_qfyrs_8,
+	llc_error_actions_8
+};
+
+/* State transitions for LLC_CONN_EV_DATA_CONN_REQ event */
+static llc_conn_ev_qfyr_t llc_error_ev_qfyrs_9[] = {
+	llc_conn_ev_qlfy_set_status_refuse,
+	NULL
+};
+
+/* just one member, NULL, .bss zeroes it */
+static llc_conn_action_t llc_error_actions_9[1];
+
+static struct llc_conn_state_trans llc_error_state_trans_9 = {
+	llc_conn_ev_data_req,
+	LLC_CONN_STATE_ERROR,
+	llc_error_ev_qfyrs_9,
+	llc_error_actions_9
+};
+
+/*
+ * Array of pointers;
+ * one to each transition
+ */
+static struct llc_conn_state_trans *llc_error_state_transitions[] = {
+	&llc_error_state_trans_9,	/* Request */
+	&llc_common_state_trans_n,
+	&llc_common_state_trans_n,	/* Local busy */
+	&llc_common_state_trans_n,	/* Initiate PF cycle */
+	&llc_error_state_trans_7,	/* Timer */
+	&llc_error_state_trans_8,
+	&llc_common_state_trans_n,
+	&llc_error_state_trans_1,	/* Receive frame */
+	&llc_error_state_trans_2,
+	&llc_error_state_trans_3,
+	&llc_error_state_trans_4,
+	&llc_error_state_trans_5,
+	&llc_error_state_trans_6,
+	&llc_common_state_trans_n
+};
+
+/* ------------------- LLC_CONN_STATE_TEMP transitions ----------------- */
+/* State transitions for LLC_CONN_EV_DISC_REQ event */
+static llc_conn_action_t llc_temp_actions_1[] = {
+	llc_conn_ac_stop_all_timers,
+	llc_conn_ac_send_disc_cmd_p_set_x,
+	llc_conn_disc,
+	NULL
+};
+
+static struct llc_conn_state_trans llc_temp_state_trans_1 = {
+	llc_conn_ev_disc_req,
+	LLC_CONN_STATE_ADM,
+	LLC_NO_EVENT_QUALIFIERS,
+	llc_temp_actions_1
+};
+
+/*
+ * Array of pointers;
+ * one to each transition
+ */
+static struct llc_conn_state_trans *llc_temp_state_transitions[] = {
+	&llc_temp_state_trans_1,	/* requests */
+	&llc_common_state_trans_n,
+	&llc_common_state_trans_n,	/* local busy */
+	&llc_common_state_trans_n,	/* init_pf_cycle */
+	&llc_common_state_trans_n,	/* timer */
+	&llc_common_state_trans_n       /* recieve */
+};
+
+/* Connection State Transition Table */
+struct llc_conn_state llc_conn_state_table[] = {
+	{ LLC_CONN_STATE_ADM,		llc_adm_state_transitions },
+	{ LLC_CONN_STATE_SETUP,		llc_setup_state_transitions },
+	{ LLC_CONN_STATE_NORMAL,	llc_normal_state_transitions },
+	{ LLC_CONN_STATE_BUSY,		llc_busy_state_transitions },
+	{ LLC_CONN_STATE_REJ,		llc_reject_state_transitions },
+	{ LLC_CONN_STATE_AWAIT,		llc_await_state_transitions },
+	{ LLC_CONN_STATE_AWAIT_BUSY,	llc_await_busy_state_transitions },
+	{ LLC_CONN_STATE_AWAIT_REJ,	llc_await_rejct_state_transitions },
+	{ LLC_CONN_STATE_D_CONN,	llc_d_conn_state_transitions },
+	{ LLC_CONN_STATE_RESET,		llc_rst_state_transitions },
+	{ LLC_CONN_STATE_ERROR,		llc_error_state_transitions },
+	{ LLC_CONN_STATE_TEMP,		llc_temp_state_transitions }
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/llc/llc_evnt.c linux.20pre10-ac2/net/llc/llc_evnt.c
--- linux.20pre10/net/llc/llc_evnt.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/net/llc/llc_evnt.c	2002-08-06 15:42:06.000000000 +0100
@@ -0,0 +1,112 @@
+/*
+ * llc_evnt.c - LLC station component event match functions
+ * Description :
+ *   Functions in this module are implementation of station component events.
+ *   Details of events can be found in IEEE-802.2 standard document.
+ *   All functions have one station and one event as input argument. All of
+ *   them return 0 On success and 1 otherwise.
+ *
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/socket.h>
+#include <net/sock.h>
+#include <net/llc_if.h>
+#include <net/llc_main.h>
+#include <net/llc_evnt.h>
+#include <net/llc_pdu.h>
+
+int llc_stat_ev_enable_with_dup_addr_check(struct llc_station *station,
+					   struct llc_station_state_ev *ev)
+{
+	return ev->type == LLC_STATION_EV_TYPE_SIMPLE &&
+	       ev->data.a.ev ==
+	       		      LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK ? 0 : 1;
+}
+
+int llc_stat_ev_enable_without_dup_addr_check(struct llc_station *station,
+					      struct llc_station_state_ev *ev)
+{
+	return ev->type == LLC_STATION_EV_TYPE_SIMPLE &&
+	       ev->data.a.ev ==
+			LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK ? 0 : 1;
+}
+
+int llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry(struct llc_station *station,
+						struct llc_station_state_ev *ev)
+{
+	return ev->type == LLC_STATION_EV_TYPE_ACK_TMR &&
+	       station->retry_count < station->maximum_retry ? 0 : 1;
+}
+
+int llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry(struct llc_station *station,
+						struct llc_station_state_ev *ev)
+{
+	return ev->type == LLC_STATION_EV_TYPE_ACK_TMR &&
+		station->retry_count == station->maximum_retry ? 0 : 1;
+}
+
+int llc_stat_ev_rx_null_dsap_xid_c(struct llc_station *station,
+				   struct llc_station_state_ev *ev)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+	return ev->type == LLC_STATION_EV_TYPE_PDU &&
+	       !LLC_PDU_IS_CMD(pdu) &&			/* command PDU */
+	       !LLC_PDU_TYPE_IS_U(pdu) &&		/* U type PDU */
+	       LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID &&
+	       !pdu->dsap ? 0 : 1;			/* NULL DSAP value */
+}
+
+int llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq(struct llc_station *station,
+					        struct llc_station_state_ev *ev)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+	return ev->type == LLC_STATION_EV_TYPE_PDU &&
+	       !LLC_PDU_IS_RSP(pdu) &&			/* response PDU */
+	       !LLC_PDU_TYPE_IS_U(pdu) &&		/* U type PDU */
+	       LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID &&
+	       !pdu->dsap &&				/* NULL DSAP value */
+	       !station->xid_r_count ? 0 : 1;
+}
+
+int llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq(struct llc_station *station,
+					        struct llc_station_state_ev *ev)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+	return ev->type == LLC_STATION_EV_TYPE_PDU &&
+	       !LLC_PDU_IS_RSP(pdu) &&			/* response PDU */
+	       !LLC_PDU_TYPE_IS_U(pdu) &&		/* U type PDU */
+	       LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID &&
+	       !pdu->dsap &&				/* NULL DSAP value */
+	       station->xid_r_count == 1 ? 0 : 1;
+}
+
+int llc_stat_ev_rx_null_dsap_test_c(struct llc_station *station,
+				    struct llc_station_state_ev *ev)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+	return ev->type == LLC_STATION_EV_TYPE_PDU &&
+	       !LLC_PDU_IS_CMD(pdu) &&			/* command PDU */
+	       !LLC_PDU_TYPE_IS_U(pdu) &&		/* U type PDU */
+	       LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST &&
+	       !pdu->dsap ? 0 : 1;			/* NULL DSAP */
+}
+
+int llc_stat_ev_disable_req(struct llc_station *station,
+			    struct llc_station_state_ev *ev)
+{
+	return ev->type == LLC_STATION_EV_TYPE_PRIM &&
+	       ev->data.prim.prim == LLC_DISABLE_PRIM &&
+	       ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/llc/llc_if.c linux.20pre10-ac2/net/llc/llc_if.c
--- linux.20pre10/net/llc/llc_if.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/net/llc/llc_if.c	2002-08-06 15:42:06.000000000 +0100
@@ -0,0 +1,514 @@
+/*
+ * llc_if.c - Defines LLC interface to upper layer
+ *
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <asm/errno.h>
+#include <net/llc_if.h>
+#include <net/llc_sap.h>
+#include <net/llc_s_ev.h>
+#include <net/llc_conn.h>
+#include <net/sock.h>
+#include <net/llc_c_ev.h>
+#include <net/llc_c_ac.h>
+#include <net/llc_c_st.h>
+#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);
+
+extern void llc_register_sap(unsigned char sap,
+			     int (*rcvfunc)(struct sk_buff *skb,
+					    struct net_device *dev,
+					    struct packet_type *pt));
+extern void llc_unregister_sap(unsigned char sap);
+
+/* table of request handler functions */
+static llc_prim_call_t llc_req_prim[LLC_NBR_PRIMITIVES] = {
+	llc_unitdata_req_handler,	/* order of functions must not change */
+	llc_conn_req_handler,
+	llc_data_req_handler,
+	llc_disc_req_handler,
+	llc_rst_req_handler,
+	llc_flowcontrol_req_handler,
+	NULL,
+	llc_xid_req_handler,
+	llc_test_req_handler,
+};
+
+/* table of response handler functions */
+static llc_prim_call_t llc_resp_prim[LLC_NBR_PRIMITIVES] = {
+	llc_no_rsp_handler,     /* order of functions must not change */
+	llc_conn_rsp_handler,
+	llc_no_rsp_handler,
+	llc_no_rsp_handler,
+	llc_rst_rsp_handler,
+	llc_no_rsp_handler,
+};
+
+/**
+ *	llc_sap_open - open interface to the upper layers.
+ *	@nw_indicate: pointer to indicate function of upper layer.
+ *	@nw_confirm: pointer to confirm function of upper layer.
+ *	@lsap: SAP number.
+ *	@sap: pointer to allocated SAP (output argument).
+ *
+ *	Interface function to upper layer. each one who wants to get a SAP
+ *	(for example NetBEUI) should call this function. Returns 0 for
+ *	success, 1 for failure.
+ */
+struct llc_sap *llc_sap_open(llc_prim_call_t nw_indicate,
+			     llc_prim_call_t nw_confirm, u8 lsap)
+{
+	/* verify this SAP is not already open; if so, return error */
+	struct llc_sap *sap;
+
+	MOD_INC_USE_COUNT;
+	sap = llc_sap_find(lsap);
+	if (sap) { /* SAP already exists */
+		sap = NULL;
+		goto err;
+	}
+	/* sap requested does not yet exist */
+	sap = llc_sap_alloc();
+	if (!sap)
+		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();
+	/* initialized SAP; add it to list of SAPs this station manages */
+	llc_sap_save(sap);
+	llc_register_sap(lsap, mac_indicate);
+out:	return sap;
+err:	MOD_DEC_USE_COUNT;
+	goto out;
+}
+
+/**
+ *	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 an open SAP (for example NetBEUI) should call this function.
+ */
+void llc_sap_close(struct llc_sap *sap)
+{
+	llc_unregister_sap(sap->laddr.lsap);
+	llc_free_sap(sap);
+	MOD_DEC_USE_COUNT;
+}
+
+/**
+ *	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 __FUNCTION__ ": invalid primitive %d\n",
+			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
+ *
+ *	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);
+
+	if (!sap)
+		goto out;
+	ev = llc_sap_alloc_ev(sap);
+	if (!ev)
+		goto out;
+	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, ev);
+out:	return rc;
+}
+
+/**
+ *	llc_test_req_handler - TEST interface for upper layers.
+ *	@prim: pointer to structure that contains service parameters.
+ *
+ *	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)
+{
+	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_alloc_ev(sap);
+	if (!ev)
+		goto out;
+	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, ev);
+out:	return rc;
+}
+
+/**
+ *	llc_xid_req_handler - XID interface for upper layers
+ *	@prim: pointer to structure that contains service parameters.
+ *
+ *	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)
+{
+	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_alloc_ev(sap);
+	if (!ev)
+		goto out;
+	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, ev);
+out:	return rc;
+}
+
+/**
+ *	llc_data_req_handler - Connection data sending for upper layers.
+ *	@prim: pointer to structure that contains service parameters
+ *
+ *	This function is called when upper layer wants to send data using
+ *	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
+ *	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)
+{
+	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;
+	if (llc_data_accept_state(llc->state)) { /* data_conn_refuse */
+		llc->failed_data_req = 1;
+		goto out;
+	}
+	if (llc->p_flag) {
+		llc->failed_data_req = 1;
+		goto out;
+	}
+	rc = -ENOMEM;
+	ev = llc_conn_alloc_ev(sk);
+	if (ev) {
+		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, ev);
+	}
+out:	release_sock(sk);
+	return rc;
+}
+
+/**
+ *	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 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.
+ *
+ *	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
+ *	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 rc = -EBUSY;
+	struct llc_opt *llc;
+	struct llc_sap *sap = prim->sap;
+	struct llc_conn_state_ev *ev;
+	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;
+	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;
+
+	memcpy(laddr.mac, sdev->dev_addr, sizeof(laddr.mac));
+	laddr.lsap = prim->data->conn.saddr.lsap;
+	memcpy(daddr.mac, ddev->dev_addr, sizeof(daddr.mac));
+	daddr.lsap = prim->data->conn.daddr.lsap;
+	sk = llc_find_sock(sap, &daddr, &laddr);
+	if (sk) {
+		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) {
+			confirm_impossible(prim);
+			goto out;
+		}
+		prim->data->conn.sk = sk;
+	}
+	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;
+	ev = llc_conn_alloc_ev(sk);
+	if (ev) {
+		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, ev);
+	}
+	if (rc) {
+		llc_sap_unassign_sock(sap, sk);
+		llc_sock_free(sk);
+		confirm_impossible(prim);
+	}
+	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.
+ *
+ *	Upper layer calls this when it wants to close an established LLC
+ *	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)
+{
+	u16 rc = 1;
+	struct llc_conn_state_ev *ev;
+	struct sock* sk = prim->data->disc.sk;
+
+	sock_hold(sk);
+	lock_sock(sk);
+	if (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 */
+	ev = llc_conn_alloc_ev(sk);
+	if (!ev)
+		goto out;
+	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, ev);
+out:	release_sock(sk);
+	sock_put(sk);
+	return rc;
+}
+
+/**
+ *	llc_rst_req_handler - 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
+ *	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 rc = 1;
+	struct sock *sk = prim->data->res.sk;
+	struct llc_conn_state_ev *ev;
+
+	lock_sock(sk);
+	ev = llc_conn_alloc_ev(sk);
+	if (ev) {
+		ev->type = LLC_CONN_EV_TYPE_PRIM;
+		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, ev);
+	}
+	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 llc_conn_state_ev *ev = llc_conn_alloc_ev(sk);
+
+	if (ev) {
+		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, ev);
+	}
+	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);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/llc/llc_mac.c linux.20pre10-ac2/net/llc/llc_mac.c
--- linux.20pre10/net/llc/llc_mac.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/net/llc/llc_mac.c	2002-08-06 15:42:06.000000000 +0100
@@ -0,0 +1,311 @@
+/*
+ * llc_mac.c - Manages interface between LLC and MAC
+ *
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_tr.h>
+#include <linux/rtnetlink.h>
+#include <net/llc_if.h>
+#include <net/llc_mac.h>
+#include <net/llc_pdu.h>
+#include <net/llc_sap.h>
+#include <net/llc_conn.h>
+#include <net/sock.h>
+#include <net/llc_main.h>
+#include <net/llc_evnt.h>
+#include <net/llc_c_ev.h>
+#include <net/llc_s_ev.h>
+#ifdef CONFIG_TR
+extern void tr_source_route(struct sk_buff *skb, struct trh_hdr *trh,
+			    struct net_device *dev);
+#endif
+/* function prototypes */
+static void fix_up_incoming_skb(struct sk_buff *skb);
+
+/**
+ *	mac_send_pdu - Sends PDU to specific device.
+ *	@skb: pdu which must be sent
+ *
+ *	If module is not initialized then returns failure, else figures out
+ *	where to direct this PDU. Sends PDU to specific device, at this point a
+ *	device must has been assigned to the PDU; If not, can't transmit the
+ *	PDU. PDU sent to MAC layer, is free to re-send at a later time. Returns
+ *	0 on success, 1 for failure.
+ */
+int mac_send_pdu(struct sk_buff *skb)
+{
+	struct sk_buff *skb2;
+	int pri = GFP_ATOMIC, rc = -1;
+
+	if (!skb->dev) {
+		printk(KERN_ERR __FUNCTION__ ": skb->dev == NULL!");
+		goto out;
+	}
+	if (skb->sk)
+		pri = (int)skb->sk->priority;
+	skb2 = skb_clone(skb, pri);
+	if (!skb2)
+		goto out;
+	rc = 0;
+	dev_queue_xmit(skb2);
+out:	return rc;
+}
+
+/**
+ *	mac_indicate - 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.
+ */
+int mac_indicate(struct sk_buff *skb, struct net_device *dev,
+		 struct packet_type *pt)
+{
+	struct llc_sap *sap;
+	llc_pdu_sn_t *pdu;
+	u8 dest;
+
+	/* 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) {
+		printk(KERN_INFO __FUNCTION__ ": PACKET_OTHERHOST\n");
+		goto drop;
+	}
+	skb = skb_share_check(skb, GFP_ATOMIC);
+	if (!skb)
+		goto out;
+	fix_up_incoming_skb(skb);
+	pdu = (llc_pdu_sn_t *)skb->nh.raw;
+	if (!pdu->dsap) { /* NULL DSAP, refer to station */
+		llc_pdu_router(NULL, NULL, skb, 0);
+		goto out;
+	}
+	sap = llc_sap_find(pdu->dsap);
+	if (!sap) /* unknown SAP */
+		goto drop;
+	llc_decode_pdu_type(skb, &dest);
+	if (dest == LLC_DEST_SAP) /* type 1 services */
+		llc_pdu_router(sap, NULL, skb, LLC_TYPE_1);
+	else if (dest == LLC_DEST_CONN) {
+		struct llc_addr saddr, daddr;
+		struct sock *sk;
+
+		llc_pdu_decode_sa(skb, saddr.mac);
+		llc_pdu_decode_ssap(skb, &saddr.lsap);
+		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)
+				goto drop;
+			memcpy(&llc_sk(sk)->daddr, &saddr, sizeof(saddr));
+			llc_sap_assign_sock(sap, sk);
+			sock_hold(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... */
+			llc_pdu_router(llc_sk(sk)->sap, sk, skb, LLC_TYPE_2);
+			bh_unlock_sock(sk);
+		} else {
+			skb->cb[0] = LLC_PACKET;
+			sk_add_backlog(sk, skb);
+			bh_unlock_sock(sk);
+		}
+		sock_put(sk);
+	} else /* unknown or not supported pdu */
+ 		goto drop;
+out:	return 0;
+drop:	kfree_skb(skb);
+	goto out;
+}
+
+/**
+ *	fix_up_incoming_skb - initializes skb pointers
+ *	@skb: This argument points to incoming skb
+ *
+ *	Initializes internal skb pointer to start of network layer by deriving
+ *	length of LLC header; finds length of LLC control field in LLC header
+ *	by looking at the two lowest-order bits of the first control field
+ *	byte; field is either 3 or 4 bytes long.
+ */
+static void fix_up_incoming_skb(struct sk_buff *skb)
+{
+	u8 llc_len = 2;
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->data;
+
+	if ((pdu->ctrl_1 & LLC_PDU_TYPE_MASK) == LLC_PDU_TYPE_U)
+		llc_len = 1;
+	llc_len += 2;
+	skb_pull(skb, llc_len);
+	if (skb->protocol == htons(ETH_P_802_2)) {
+		u16 pdulen = ((struct ethhdr *)skb->mac.raw)->h_proto,
+		    data_size = ntohs(pdulen) - llc_len;
+
+		skb_trim(skb, data_size);
+	}
+}
+
+/**
+ *	llc_pdu_router - routes received pdus to the upper layers
+ *	@sap: current sap component structure.
+ *	@sk: current connection structure.
+ *	@frame: received frame.
+ *	@type: type of received frame, that is LLC_TYPE_1 or LLC_TYPE_2
+ *
+ *	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)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw;
+	int rc = 0;
+
+	if (!pdu->dsap) {
+		struct llc_station *station = llc_station_get();
+		struct llc_station_state_ev *stat_ev =
+						  llc_station_alloc_ev(station);
+		if (stat_ev) {
+			stat_ev->type		 = LLC_STATION_EV_TYPE_PDU;
+			stat_ev->data.pdu.skb	 = skb;
+			stat_ev->data.pdu.reason = 0;
+			llc_station_send_ev(station, stat_ev);
+		}
+	} else if (type == LLC_TYPE_1) {
+		struct llc_sap_state_ev *sap_ev = llc_sap_alloc_ev(sap);
+
+		if (sap_ev) {
+			sap_ev->type		= LLC_SAP_EV_TYPE_PDU;
+			sap_ev->data.pdu.skb	= skb;
+			sap_ev->data.pdu.reason = 0;
+			llc_sap_send_ev(sap, sap_ev);
+		}
+	} else if (type == LLC_TYPE_2) {
+		struct llc_conn_state_ev *conn_ev = llc_conn_alloc_ev(sk);
+		struct llc_opt *llc = llc_sk(sk);
+
+		if (!llc->dev)
+			llc->dev = skb->dev;
+		if (conn_ev) {
+			conn_ev->type		 = LLC_CONN_EV_TYPE_PDU;
+			conn_ev->data.pdu.skb	 = skb;
+			conn_ev->data.pdu.reason = 0;
+			rc = llc_conn_send_ev(sk, conn_ev);
+		}
+	}
+	return rc;
+}
+
+/**
+ *	lan_hdrs_init - fills MAC header fields
+ *	@skb: Address of the frame to initialize its MAC header
+ *	@sa: The MAC source address
+ *	@da: The MAC destination address
+ *
+ *	Fills MAC header fields, depending on MAC type. Returns 0, If MAC type
+ *	is a valid type and initialization completes correctly 1, otherwise.
+ */
+u16 lan_hdrs_init(struct sk_buff *skb, u8 *sa, u8 *da)
+{
+	u8 *saddr;
+	u8 *daddr;
+	u16 rc = 0;
+
+	switch (skb->dev->type) {
+#ifdef CONFIG_TR
+		case ARPHRD_IEEE802_TR: {
+			struct trh_hdr *trh = (struct trh_hdr *)
+						    skb_push(skb, sizeof(*trh));
+			struct net_device *dev = skb->dev;
+
+			trh->ac = AC;
+			trh->fc = LLC_FRAME;
+			if (sa)
+				memcpy(trh->saddr, sa, dev->addr_len);
+			else
+				memset(trh->saddr, 0, dev->addr_len);
+			if (da) {
+				memcpy(trh->daddr, da, dev->addr_len);
+				tr_source_route(skb, trh, dev);
+			}
+			skb->mac.raw = skb->data;
+			break;
+		}
+#endif
+		case ARPHRD_ETHER:
+		case ARPHRD_LOOPBACK: {
+			unsigned short len = skb->len;
+
+			skb->mac.raw = skb_push(skb, sizeof(struct ethhdr));
+			memset(skb->mac.raw, 0, sizeof(struct ethhdr));
+			((struct ethhdr *)skb->mac.raw)->h_proto = htons(len);
+			daddr = ((struct ethhdr *)skb->mac.raw)->h_dest;
+			saddr = ((struct ethhdr *)skb->mac.raw)->h_source;
+			memcpy(daddr, da, ETH_ALEN);
+			memcpy(saddr, sa, ETH_ALEN);
+			break;
+		}
+		default:
+			printk(KERN_WARNING "Unknown DEVICE type : %d\n",
+			       skb->dev->type);
+			rc = 1;
+	}
+	return rc;
+}
+
+/**
+ *	mac_dev_peer - search the appropriate dev to send packets to peer
+ *	@current_dev - Current device suggested by upper layer
+ *	@type - hardware type
+ *	@mac - mac address
+ *
+ *	Check if the we should use loopback to send packets, i.e., if the
+ *	dmac belongs to one of the local interfaces, returning the pointer
+ *	to the loopback &net_device struct or the current_dev if it is not
+ *	local.
+ */
+struct net_device *mac_dev_peer(struct net_device *current_dev, int type,
+				u8 *mac)
+{
+	struct net_device *dev;
+
+        rtnl_lock();
+        dev = dev_getbyhwaddr(type, mac);
+        if (dev)
+                dev = __dev_get_by_name("lo");
+        rtnl_unlock();
+	return dev ? : current_dev;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/llc/llc_main.c linux.20pre10-ac2/net/llc/llc_main.c
--- linux.20pre10/net/llc/llc_main.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/net/llc/llc_main.c	2002-08-06 15:42:06.000000000 +0100
@@ -0,0 +1,629 @@
+/*
+ * llc_main.c - This module contains main functions to manage station, saps
+ * 	and connections of the LLC.
+ *
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <net/sock.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <net/llc_if.h>
+#include <net/llc_sap.h>
+#include <net/llc_conn.h>
+#include <net/llc_main.h>
+#include <net/llc_evnt.h>
+#include <net/llc_actn.h>
+#include <net/llc_stat.h>
+#include <net/llc_c_ac.h>
+#include <net/llc_s_ac.h>
+#include <net/llc_c_ev.h>
+#include <net/llc_c_st.h>
+#include <net/llc_s_ev.h>
+#include <net/llc_s_st.h>
+#include <net/llc_mac.h>
+#include <linux/llc.h>
+
+/* static function prototypes */
+static void llc_station_service_events(struct llc_station *station);
+static void llc_station_free_ev(struct llc_station *station,
+				struct llc_station_state_ev *ev);
+static void llc_station_send_pdus(struct llc_station *station);
+static u16 llc_station_next_state(struct llc_station *station,
+			      struct llc_station_state_ev *ev);
+static u16 llc_exec_station_trans_actions(struct llc_station *station,
+					  struct llc_station_state_trans *trans,
+					  struct llc_station_state_ev *ev);
+static struct llc_station_state_trans *
+			     llc_find_station_trans(struct llc_station *station,
+					       struct llc_station_state_ev *ev);
+static int llc_rtn_all_conns(struct llc_sap *sap);
+
+extern void llc_register_sap(unsigned char sap,
+			     int (*rcvfunc)(struct sk_buff *skb,
+					    struct net_device *dev,
+					    struct packet_type *pt));
+extern void llc_unregister_sap(unsigned char sap);
+
+static struct llc_station llc_main_station;	/* only one of its kind */
+struct llc_prim_if_block llc_ind_prim, llc_cfm_prim;
+static union llc_u_prim_data llc_ind_data_prim, llc_cfm_data_prim;
+
+/**
+ *	llc_sap_alloc - allocates and initializes sap.
+ *
+ *	Allocates and initializes sap.
+ */
+struct llc_sap *llc_sap_alloc(void)
+{
+	struct llc_sap *sap = kmalloc(sizeof(*sap), GFP_ATOMIC);
+
+	if (sap) {
+		memset(sap, 0, sizeof(*sap));
+		sap->state = LLC_SAP_STATE_ACTIVE;
+		memcpy(sap->laddr.mac, llc_main_station.mac_sa, ETH_ALEN);
+		spin_lock_init(&sap->sk_list.lock);
+		INIT_LIST_HEAD(&sap->sk_list.list);
+		skb_queue_head_init(&sap->mac_pdu_q);
+	}
+	return sap;
+}
+
+/**
+ *	llc_free_sap - frees a sap
+ *	@sap: Address of the sap
+ *
+ * 	Frees all associated connections (if any), removes this sap from
+ * 	the list of saps in te station and them frees the memory for this sap.
+ */
+void llc_free_sap(struct llc_sap *sap)
+{
+	struct llc_station *station = sap->parent_station;
+
+	llc_rtn_all_conns(sap);
+	spin_lock_bh(&station->sap_list.lock);
+	list_del(&sap->node);
+	spin_unlock_bh(&station->sap_list.lock);
+	kfree(sap);
+}
+
+/**
+ *	llc_sap_save - add sap to station list
+ *	@sap: Address of the sap
+ *
+ *	Adds a sap to the LLC's station sap list.
+ */
+void llc_sap_save(struct llc_sap *sap)
+{
+	spin_lock_bh(&llc_main_station.sap_list.lock);
+	list_add_tail(&sap->node, &llc_main_station.sap_list.list);
+	spin_unlock_bh(&llc_main_station.sap_list.lock);
+}
+
+/**
+ *	llc_sap_find - searchs a SAP in station
+ *	@sap_value: sap to be found
+ *
+ *	Searchs for a sap in the sap list of the LLC's station upon the sap ID.
+ *	Returns the sap or %NULL if not found.
+ */
+struct llc_sap *llc_sap_find(u8 sap_value)
+{
+	struct llc_sap* sap = NULL;
+	struct list_head *entry;
+
+	spin_lock_bh(&llc_main_station.sap_list.lock);
+	list_for_each(entry, &llc_main_station.sap_list.list) {
+		sap = list_entry(entry, struct llc_sap, node);
+		if (sap->laddr.lsap == sap_value)
+			break;
+	}
+	if (entry == &llc_main_station.sap_list.list) /* not found */
+		sap = NULL;
+	spin_unlock_bh(&llc_main_station.sap_list.lock);
+	return sap;
+}
+
+/**
+ *	llc_backlog_rcv - Processes rx frames and expired timers.
+ *	@sk: LLC sock (p8022 connection)
+ *	@skb: queued rx frame or event
+ *
+ *	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
+ *	callback functions(llc_c_ac.c).
+ */
+static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
+{
+	int rc = 0;
+	struct llc_opt *llc = llc_sk(sk);
+
+	if (skb->cb[0] == LLC_PACKET) {
+		if (llc->state > 1) /* not closed */
+			rc = llc_pdu_router(llc->sap, sk, skb, LLC_TYPE_2);
+		else
+			kfree_skb(skb);
+	} else if (skb->cb[0] == LLC_EVENT) {
+		struct llc_conn_state_ev *ev =
+					(struct llc_conn_state_ev *)skb->data;
+		/* timer expiration event */
+		if (llc->state > 1)  /* not closed */
+			rc = llc_conn_send_ev(sk, ev);
+		else
+			llc_conn_free_ev(ev);
+		kfree_skb(skb);
+	}
+	return rc;
+}
+
+/**
+ *     llc_sock_init - Initialize a socket with default llc values.
+ *     @sk: socket to intiailize.
+ */
+int llc_sock_init(struct sock* sk)
+{
+	struct llc_opt *llc = kmalloc(sizeof(*llc), GFP_ATOMIC);
+	int rc = -ENOMEM;
+
+	if (!llc)
+		goto out;
+	memset(llc, 0, sizeof(*llc));
+	rc = 0;
+	llc->sk			     = sk;
+	llc->state		     = LLC_CONN_STATE_ADM;
+	llc->inc_cntr		     = llc->dec_cntr = 2;
+	llc->dec_step		     = llc->connect_step = 1;
+	llc->ack_timer.expire	     = LLC_ACK_TIME;
+	llc->pf_cycle_timer.expire   = LLC_P_TIME;
+	llc->rej_sent_timer.expire   = LLC_REJ_TIME;
+	llc->busy_state_timer.expire = LLC_BUSY_TIME;
+	llc->n2			     = 2;   /* max retransmit */
+	llc->k			     = 2;   /* tx win size, will adjust dynam */
+	llc->rw			     = 128; /* rx win size (opt and equal to
+					       tx_win of remote LLC) */
+	skb_queue_head_init(&llc->pdu_unack_q);
+	sk->backlog_rcv = llc_backlog_rcv;
+	llc_sk(sk) = llc;
+out:	return rc;
+}
+
+/**
+ *	__llc_sock_alloc - Allocates LLC sock
+ *
+ *	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 *sk = sk_alloc(PF_LLC, GFP_ATOMIC, 1);
+
+	if (!sk)
+		goto out;
+	if (llc_sock_init(sk))
+		goto outsk;
+	sock_init_data(NULL, sk);
+out:	return sk;
+outsk:	sk_free(sk);
+	sk = NULL;
+	goto out;
+}
+
+/**
+ *	__llc_sock_free - Frees a LLC socket
+ *	@sk - socket to free
+ *
+ *	Frees a LLC socket
+ */
+void __llc_sock_free(struct sock *sk, u8 free)
+{
+	struct llc_opt *llc = llc_sk(sk);
+
+	llc->state = LLC_CONN_OUT_OF_SVC;
+	/* stop all (possibly) running timers */
+	llc_conn_ac_stop_all_timers(sk, NULL);
+	/* handle return of frames on lists */
+	printk(KERN_INFO __FUNCTION__ ": unackq=%d, txq=%d\n",
+		skb_queue_len(&llc->pdu_unack_q),
+		skb_queue_len(&sk->write_queue));
+	skb_queue_purge(&sk->write_queue);
+	skb_queue_purge(&llc->pdu_unack_q);
+	if (free)
+		sock_put(sk);
+}
+
+/**
+ *	llc_sock_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)
+{
+	struct llc_opt *llc = llc_sk(sk);
+
+	llc_conn_ac_stop_all_timers(sk, NULL);
+	skb_queue_purge(&sk->write_queue);
+	skb_queue_purge(&llc->pdu_unack_q);
+	llc->remote_busy_flag	= 0;
+	llc->cause_flag		= 0;
+	llc->retry_count	= 0;
+	llc->p_flag		= 0;
+	llc->f_flag		= 0;
+	llc->s_flag		= 0;
+	llc->ack_pf		= 0;
+	llc->first_pdu_Ns	= 0;
+	llc->ack_must_be_send	= 0;
+	llc->dec_step		= 1;
+	llc->inc_cntr		= 2;
+	llc->dec_cntr		= 2;
+	llc->X			= 0;
+	llc->failed_data_req	= 0 ;
+	llc->last_nr		= 0;
+}
+
+/**
+ *	llc_rtn_all_conns - Closes all connections of a sap
+ *	@sap: sap to close its connections
+ *
+ *	Closes all connections of a sap. Returns 0 if all actions complete
+ *	successfully, nonzero otherwise
+ */
+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);
+	if (list_empty(&sap->sk_list.list))
+		goto out;
+	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))
+			rc = 1;
+	}
+out:	spin_unlock_bh(&sap->sk_list.lock);
+	return rc;
+}
+
+/**
+ *	llc_station_get - get addr of global station.
+ *
+ *	Returns address of a place to copy the global station to it.
+ */
+struct llc_station *llc_station_get(void)
+{
+	return &llc_main_station;
+}
+
+/**
+ *	llc_station_alloc_ev - allocates an event
+ *	@station: Address of the station
+ *
+ *	Allocates an event in this station. Returns the allocated event on
+ *	success, %NULL otherwise.
+ */
+struct llc_station_state_ev *llc_station_alloc_ev(struct llc_station *station)
+{
+	struct llc_station_state_ev *ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
+
+	if (ev)
+		memset(ev, 0, sizeof(*ev));
+	return ev;
+}
+
+/**
+ *	llc_station_send_ev: queue event and try to process queue.
+ *	@station: Address of the station
+ *	@ev: 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 llc_station_state_ev *ev)
+{
+	spin_lock_bh(&station->ev_q.lock);
+	list_add_tail(&ev->node, &station->ev_q.list);
+	llc_station_service_events(station);
+	spin_unlock_bh(&station->ev_q.lock);
+}
+
+/**
+ *	llc_station_send_pdu - queues PDU to send
+ *	@station: Address of the station
+ *	@skb: Address of the PDU
+ *
+ *	Queues a PDU to send to the MAC layer.
+ */
+void llc_station_send_pdu(struct llc_station *station, struct sk_buff *skb)
+{
+	skb_queue_tail(&station->mac_pdu_q, skb);
+	llc_station_send_pdus(station);
+}
+
+/**
+ *	llc_station_send_pdus - tries to send queued PDUs
+ *	@station: Address of the station
+ *
+ *	Tries to send any PDUs queued in the station mac_pdu_q to the MAC
+ *	layer.
+ */
+static void llc_station_send_pdus(struct llc_station *station)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&station->mac_pdu_q)) != NULL) {
+		int rc = mac_send_pdu(skb);
+
+		kfree_skb(skb);
+		if (rc)
+			break;
+	}
+}
+
+/**
+ *	llc_station_free_ev - frees an event
+ *	@station: Address of the station
+ *	@event: Address of the event
+ *
+ *	Frees an event.
+ */
+static void llc_station_free_ev(struct llc_station *station,
+				struct llc_station_state_ev *ev)
+{
+	struct sk_buff *skb = ev->data.pdu.skb;
+
+	if (ev->type == LLC_STATION_EV_TYPE_PDU)
+		kfree_skb(skb);
+	kfree(ev);
+}
+
+/**
+ *	llc_station_service_events - service events in the queue
+ *	@station: Address of the station
+ *
+ *	Get an event from the station event queue (if any); attempt to service
+ *	the event; if event serviced, get the next event (if any) on the event
+ *	queue; if event not service, re-queue the event on the event queue and
+ *	attempt to service the next event; when serviced all events in queue,
+ *	finished; if don't transition to different state, just service all
+ *	events once; if transition to new state, service all events again.
+ *	Caller must hold station->ev_q.lock.
+ */
+static void llc_station_service_events(struct llc_station *station)
+{
+	struct llc_station_state_ev *ev;
+	struct list_head *entry, *tmp;
+
+	list_for_each_safe(entry, tmp, &station->ev_q.list) {
+		ev = list_entry(entry, struct llc_station_state_ev, node);
+		list_del(&ev->node);
+		llc_station_next_state(station, ev);
+	}
+}
+
+/**
+ *	llc_station_next_state - processes event and goes to the next state
+ *	@station: Address of the station
+ *	@ev: Address of the event
+ *
+ *	Processes an event, executes any transitions related to that event and
+ *	updates the state of the station.
+ */
+static u16 llc_station_next_state(struct llc_station *station,
+			      struct llc_station_state_ev *ev)
+{
+	u16 rc = 1;
+	struct llc_station_state_trans *trans;
+
+	if (station->state > LLC_NBR_STATION_STATES)
+		goto out;
+	trans = llc_find_station_trans(station, ev);
+	if (trans) {
+		/* got the state to which we next transition; perform the
+		 * actions associated with this transition before actually
+		 * transitioning to the next state */
+		rc = llc_exec_station_trans_actions(station, trans, ev);
+		if (!rc)
+			/* transition station to next state if all actions
+			 * execute successfully; done; wait for next event */
+			station->state = trans->next_state;
+	} else
+		/* event not recognized in current state; re-queue it for
+		 * processing again at a later time; return failure */
+		rc = 0;
+out:	llc_station_free_ev(station, ev);
+	return rc;
+}
+
+/**
+ *	llc_find_station_trans - finds transition for this event
+ *	@station: Address of the station
+ *	@ev: Address of the event
+ *
+ *	Search thru events of the current state of the station until list
+ *	exhausted or it's obvious that the event is not valid for the current
+ *	state. Returns the address of the transition if cound, %NULL otherwise.
+ */
+static struct llc_station_state_trans *
+	llc_find_station_trans(struct llc_station *station,
+				struct llc_station_state_ev *ev)
+{
+	int i = 0;
+	struct llc_station_state_trans *rc = NULL;
+	struct llc_station_state_trans **next_trans;
+	struct llc_station_state *curr_state =
+				&llc_station_state_table[station->state - 1];
+
+	for (next_trans = curr_state->transitions; next_trans[i]->ev; i++)
+		if (!next_trans[i]->ev(station, ev)) {
+			rc = next_trans[i];
+			break;
+		}
+	return rc;
+}
+
+/**
+ *	llc_exec_station_trans_actions - executes actions for transition
+ *	@station: Address of the station
+ *	@trans: Address of the transition
+ *	@ev: Address of the event that caused the transition
+ *
+ *	Executes actions of a transition of the station state machine. Returns
+ *	0 if all actions complete successfully, nonzero otherwise.
+ */
+static u16 llc_exec_station_trans_actions(struct llc_station *station,
+					  struct llc_station_state_trans *trans,
+					  struct llc_station_state_ev *ev)
+{
+	u16 rc = 0;
+	llc_station_action_t *next_action;
+
+	for (next_action = trans->ev_actions;
+	     next_action && *next_action; next_action++)
+		if ((*next_action)(station, ev))
+			rc = 1;
+	return rc;
+}
+
+/**
+ *	llc_alloc_frame - allocates sk_buff for frame
+ *
+ *	Allocates an sk_buff for frame and initializes sk_buff fields.
+ *	Returns allocated skb or %NULL when out of memory.
+ */
+struct sk_buff *llc_alloc_frame(void)
+{
+	struct sk_buff *skb = alloc_skb(128, GFP_ATOMIC);
+
+	if (skb) {
+		skb_reserve(skb, 50);
+		skb->nh.raw   = skb->h.raw = skb->data;
+		skb->protocol = htons(ETH_P_802_2);
+		skb->dev      = dev_base->next;
+		skb->mac.raw  = skb->head;
+	}
+	return skb;
+}
+
+static int llc_proc_get_info(char *bf, char **start, off_t offset, int length)
+{
+	struct llc_opt *llc;
+	struct list_head *sap_entry, *llc_entry;
+	off_t begin = 0, pos = 0;
+	int len = 0;
+
+	spin_lock_bh(&llc_main_station.sap_list.lock);
+	list_for_each(sap_entry, &llc_main_station.sap_list.list) {
+		struct llc_sap *sap = list_entry(sap_entry, struct llc_sap,
+						 node);
+
+		len += sprintf(bf + len, "lsap=%d\n", sap->laddr.lsap);
+		spin_lock_bh(&sap->sk_list.lock);
+		if (list_empty(&sap->sk_list.list)) {
+			len += sprintf(bf + len, "no connections\n");
+			goto unlock;
+		}
+		len += sprintf(bf + len,
+				"connection list:\nstate  retr txwin rxwin\n");
+		list_for_each(llc_entry, &sap->sk_list.list) {
+			llc = list_entry(llc_entry, struct llc_opt, node);
+			len += sprintf(bf + len, "  %-5d%-5d%-6d%-5d\n",
+					llc->state, llc->retry_count, llc->k,
+					llc->rw);
+		}
+unlock:		spin_unlock_bh(&sap->sk_list.lock);
+		pos = begin + len;
+		if (pos < offset) {
+			len = 0; /* Keep dumping into the buffer start */
+			begin = pos;
+		}
+		if (pos > offset + length) /* We have dumped enough */
+			break;
+	}
+	spin_unlock_bh(&llc_main_station.sap_list.lock);
+
+	/* The data in question runs from begin to begin + len */
+	*start = bf + (offset - begin); /* Start of wanted data */
+	len -= (offset - begin); /* Remove unwanted header data from length */
+	return len;
+}
+
+static char llc_banner[] __initdata =
+		KERN_INFO "LLC 2.0 by Procom, 1997, Arnaldo C. Melo, 2001\n"
+		KERN_INFO "NET4.0 IEEE 802.2 extended support\n";
+static char llc_error_msg[] __initdata =
+		KERN_ERR "LLC install NOT successful.\n";
+
+static int __init llc_init(void)
+{
+	u16 rc = 0;
+	struct llc_station_state_ev *ev;
+
+	printk(llc_banner);
+	INIT_LIST_HEAD(&llc_main_station.ev_q.list);
+	spin_lock_init(&llc_main_station.ev_q.lock);
+	INIT_LIST_HEAD(&llc_main_station.sap_list.list);
+	spin_lock_init(&llc_main_station.sap_list.lock);
+	skb_queue_head_init(&llc_main_station.mac_pdu_q);
+	ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
+	if (!ev)
+		goto err;
+	memset(ev, 0, sizeof(*ev));
+	if(dev_base->next)
+		memcpy(llc_main_station.mac_sa, dev_base->next->dev_addr, ETH_ALEN);
+	else
+		memset(llc_main_station.mac_sa, 0, ETH_ALEN);
+	llc_main_station.ack_timer.expires = jiffies + 3 * HZ;
+	/* initialize the station component */
+	llc_register_sap(0, mac_indicate);
+	llc_main_station.maximum_retry	= 1;
+	llc_main_station.state		= LLC_STATION_STATE_DOWN;
+	ev->type	= LLC_STATION_EV_TYPE_SIMPLE;
+	ev->data.a.ev	= LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK;
+	rc = llc_station_next_state(&llc_main_station, ev);
+	llc_build_offset_table();
+	llc_ind_prim.data = &llc_ind_data_prim;
+	llc_cfm_prim.data = &llc_cfm_data_prim;
+	proc_net_create("802.2", 0, llc_proc_get_info);
+	llc_ui_init();
+out:	return rc;
+err:	printk(llc_error_msg);
+	rc = 1;
+	goto out;
+}
+
+static void __exit llc_exit(void)
+{
+	llc_ui_exit();
+	llc_unregister_sap(0);
+	proc_net_remove("802.2");
+}
+
+module_init(llc_init);
+module_exit(llc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Procom, 1997, Arnaldo C. Melo, Jay Schullist, 2001");
+MODULE_DESCRIPTION("LLC 2.0, NET4.0 IEEE 802.2 extended support");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/llc/llc_pdu.c linux.20pre10-ac2/net/llc/llc_pdu.c
--- linux.20pre10/net/llc/llc_pdu.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/net/llc/llc_pdu.c	2002-08-06 15:42:06.000000000 +0100
@@ -0,0 +1,652 @@
+/*
+ * llc_pdu.c - access to PDU internals
+ *
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ *		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/netdevice.h>
+#include <linux/if_tr.h>
+#include <net/llc_pdu.h>
+#include <net/llc_if.h>
+#include <net/llc_mac.h>
+#include <net/llc_main.h>
+
+static int llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type);
+static int llc_get_llc_hdr_length(u8 pdu_type);
+static u8 llc_pdu_get_pf_bit(llc_pdu_sn_t *pdu);
+
+/**
+ *	llc_pdu_header_init - initializes pdu header
+ *	@skb: input skb that header must be set into it.
+ *	@pdu_type: type of PDU (U, I or S).
+ *	@ssap: source sap.
+ *	@dsap: destination sap.
+ *	@cr: command/response bit (0 or 1).
+ *
+ *	This function sets DSAP, SSAP and command/Response bit in LLC header.
+ */
+void llc_pdu_header_init(struct sk_buff *skb, u8 pdu_type, u8 ssap,
+			 u8 dsap, u8 cr)
+{
+	llc_pdu_un_t *p;
+
+	skb->nh.raw = skb_push(skb, llc_get_llc_hdr_length(pdu_type));
+	p = (llc_pdu_un_t *)skb->nh.raw;
+	p->dsap = dsap;
+	p->ssap = ssap;
+	p->ssap |= cr;
+}
+
+void llc_pdu_set_cmd_rsp(struct sk_buff *skb, u8 pdu_type)
+{
+	((llc_pdu_un_t *)skb->nh.raw)->ssap |= pdu_type;
+}
+
+/**
+ *	pdu_set_pf_bit - sets poll/final bit in LLC header
+ *	@pdu_frame: input frame that p/f bit must be set into it.
+ *	@bit_value: poll/final bit (0 or 1).
+ *
+ *	This function sets poll/final bit in LLC header (based on type of 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.
+ */
+void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value)
+{
+	u8 pdu_type;
+
+	if (llc_pdu_decode_pdu_type(skb, &pdu_type))
+		goto out;
+	switch (pdu_type) {
+		case LLC_PDU_TYPE_I:
+		case LLC_PDU_TYPE_S:
+			((llc_pdu_sn_t *)skb->nh.raw)->ctrl_2 =
+				(((llc_pdu_sn_t *)skb->nh.raw)->ctrl_2 & 0xFE) |
+				bit_value;
+			break;
+		case LLC_PDU_TYPE_U:
+			((llc_pdu_un_t *)skb->nh.raw)->ctrl_1 |=
+				(((llc_pdu_un_t *)skb->nh.raw)->ctrl_1 & 0xEF) |
+				(bit_value << 4);
+			break;
+	}
+out:;
+}
+
+/**
+ *	llc_pdu_decode_pf_bit - extracs poll/final bit from LLC header
+ *	@skb: input skb that p/f bit must be extracted from it
+ *	@pf_bit: poll/final bit (0 or 1)
+ *
+ *	This function extracts poll/final bit from LLC header (based on type of
+ *	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)
+{
+	u8 pdu_type;
+	int rc = llc_pdu_decode_pdu_type(skb, &pdu_type);
+
+	if (rc)
+		goto out;
+	switch (pdu_type) {
+		case LLC_PDU_TYPE_I:
+		case LLC_PDU_TYPE_S:
+			*pf_bit = ((llc_pdu_sn_t *)skb->nh.raw)->ctrl_2 &
+				  LLC_S_PF_BIT_MASK;
+			break;
+		case LLC_PDU_TYPE_U:
+			*pf_bit = (((llc_pdu_un_t *)skb->nh.raw)->ctrl_1 &
+				  LLC_U_PF_BIT_MASK) >> 4;
+			break;
+	}
+out:	return 0;
+}
+
+/**
+ *	llc_pdu_decode_cr_bit - extracs 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)
+{
+	*cr_bit = ((llc_pdu_un_t *)skb->nh.raw)->ssap & LLC_PDU_CMD_RSP_MASK;
+	return 0;
+}
+
+/**
+ *	llc_pdu_decode_sa - extracs source address (MAC) of input frame
+ *	@skb: input skb that source address must be extracted from it.
+ *	@sa: pointer to source address (6 byte array).
+ *
+ *	This function extracts source address(MAC) of input frame.
+ */
+int 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;
+}
+
+/**
+ *	llc_pdu_decode_da - extracts dest address of input frame
+ *	@skb: input skb that destination address must be extracted from it
+ *	@sa: pointer to destination address (6 byte array).
+ *
+ *	This function extracts destination address(MAC) of input frame.
+ */
+int 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;
+}
+
+/**
+ *	llc_pdu_decode_dsap - extracts dest SAP of input frame
+ *	@skb: input skb that destination SAP must be extracted from it.
+ *	@dsap: destination SAP (output argument).
+ *
+ *	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)
+{
+	*dsap = ((llc_pdu_un_t *)skb->nh.raw)->dsap & 0xFE;
+	return 0;
+}
+
+/**
+ *	llc_pdu_decode_ssap - extracts source SAP of input frame
+ *	@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
+ *	command/response bit.
+ */
+int llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap)
+{
+	*ssap = ((llc_pdu_un_t *)skb->nh.raw)->ssap & 0xFE;
+	return 0;
+}
+
+/**
+ *	llc_pdu_init_as_ui_cmd - sets LLC header as UI PDU
+ *	@skb: input skb that header must be set into it.
+ *
+ *	This function sets third byte of LLC header as a UI PDU.
+ */
+int llc_pdu_init_as_ui_cmd(struct sk_buff *skb)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw;
+
+	pdu->ctrl_1 = LLC_PDU_TYPE_U;
+	pdu->ctrl_1 |= LLC_1_PDU_CMD_UI;
+	return 0;
+}
+
+/**
+ *	llc_pdu_init_as_xid_cmd - sets bytes 3, 4 & 5 of LLC header as XID
+ *	@skb: input skb that header must be set into it.
+ *
+ *	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)
+{
+	llc_xid_info_t *xid_info;
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw;
+
+	pdu->ctrl_1 = LLC_PDU_TYPE_U;
+	pdu->ctrl_1 |= LLC_1_PDU_CMD_XID;
+	pdu->ctrl_1 |= LLC_U_PF_BIT_MASK;
+	xid_info = (llc_xid_info_t *)(((u8 *)&pdu->ctrl_1) + 1);
+	xid_info->fmt_id = LLC_XID_FMT_ID;    /* 0x81*/
+	xid_info->type = svcs_supported;
+	xid_info->rw = (rx_window << 1);  /* size of recieve window */
+	skb_put(skb, 3);
+	return 0;
+}
+
+/**
+ *	llc_pdu_init_as_test_cmd - sets PDU as TEST
+ *	@skb - Address of the skb to build
+ *
+ * 	Sets a PDU as TEST
+ */
+int llc_pdu_init_as_test_cmd(struct sk_buff *skb)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw;
+
+	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;
+}
+
+/**
+ *	llc_pdu_init_as_disc_cmd - Builds DISC PDU
+ *	@skb: Address of the skb to build
+ *	@p_bit: The P bit to set in the PDU
+ *
+ *	Builds a pdu frame as a DISC command.
+ */
+int llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw;
+
+	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
+ *	@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
+ *	@nr: The seq. number of the expected I PDU from the remote
+ *
+ *	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)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw;
+
+	pdu->ctrl_1 = LLC_PDU_TYPE_I;
+	pdu->ctrl_2 = 0;
+	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
+ *	@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)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw;
+
+	pdu->ctrl_1 = LLC_PDU_TYPE_S;
+	pdu->ctrl_1 |= LLC_2_PDU_CMD_REJ;
+	pdu->ctrl_2 = 0;
+	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
+ *	@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)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw;
+
+	pdu->ctrl_1 = LLC_PDU_TYPE_S;
+	pdu->ctrl_1 |= LLC_2_PDU_CMD_RNR;
+	pdu->ctrl_2 = 0;
+	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
+ *	@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)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw;
+
+	pdu->ctrl_1 = LLC_PDU_TYPE_S;
+	pdu->ctrl_1 |= LLC_2_PDU_CMD_RR;
+	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
+ *	@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)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw;
+
+	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
+ *	@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)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw;
+
+	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
+ *	@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)
+{
+	llc_xid_info_t *xid_info;
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw;
+
+	pdu->ctrl_1 = LLC_PDU_TYPE_U;
+	pdu->ctrl_1 |= LLC_1_PDU_CMD_XID;
+	pdu->ctrl_1 |= LLC_U_PF_BIT_MASK;
+
+	xid_info = (llc_xid_info_t *)(((u8 *)&pdu->ctrl_1) + 1);
+	xid_info->fmt_id = LLC_XID_FMT_ID;
+	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
+ *	@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)
+{
+	int dsize;
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw;
+
+	pdu->ctrl_1 = LLC_PDU_TYPE_U;
+	pdu->ctrl_1 |= LLC_1_PDU_CMD_TEST;
+	pdu->ctrl_1 |= LLC_U_PF_BIT_MASK;
+	if (ev_skb->protocol == ntohs(ETH_P_802_2)) {
+		dsize = ntohs(((struct ethhdr *)ev_skb->mac.raw)->h_proto) - 3;
+		memcpy(((u8 *)skb->nh.raw) + 3,
+		       ((u8 *)ev_skb->nh.raw) + 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
+ *	@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
+ *	@vr: rx state var value for the data link conn at the rejecting LLC
+ *	@vzyxw: completely described in the IEEE Std 802.2 document (Pg 55)
+ *
+ *	Builds a pdu frame as a FRMR response.
+ */
+int llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, llc_pdu_sn_t *prev_pdu,
+			     u8 f_bit, u8 vs, u8 vr, u8 vzyxw)
+{
+	llc_frmr_info_t *frmr_info;
+	u8 prev_pf = 0;
+	u8 *ctrl;
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw;
+
+	pdu->ctrl_1 = LLC_PDU_TYPE_U;
+	pdu->ctrl_1 |= LLC_2_PDU_RSP_FRMR;
+	pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK;
+
+	frmr_info = (llc_frmr_info_t *)&pdu->ctrl_2;
+	ctrl = (u8 *)&prev_pdu->ctrl_1;
+	FRMR_INFO_SET_REJ_CNTRL(frmr_info,ctrl);
+	FRMR_INFO_SET_Vs(frmr_info, vs);
+	FRMR_INFO_SET_Vr(frmr_info, vr);
+	prev_pf = llc_pdu_get_pf_bit(prev_pdu);
+	FRMR_INFO_SET_C_R_BIT(frmr_info, prev_pf);
+	FRMR_INFO_SET_INVALID_PDU_CTRL_IND(frmr_info, vzyxw);
+	FRMR_INFO_SET_INVALID_PDU_INFO_IND(frmr_info, vzyxw);
+	FRMR_INFO_SET_PDU_INFO_2LONG_IND(frmr_info, vzyxw);
+	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
+ *	@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)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw;
+
+	pdu->ctrl_1 = LLC_PDU_TYPE_S;
+	pdu->ctrl_1 |= LLC_2_PDU_RSP_RR;
+	pdu->ctrl_2 = 0;
+	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
+ *	@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)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw;
+
+	pdu->ctrl_1 = LLC_PDU_TYPE_S;
+	pdu->ctrl_1 |= LLC_2_PDU_RSP_REJ;
+	pdu->ctrl_2 = 0;
+	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
+ *	@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)
+{
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw;
+
+	pdu->ctrl_1 = LLC_PDU_TYPE_S;
+	pdu->ctrl_1 |= LLC_2_PDU_RSP_RNR;
+	pdu->ctrl_2 = 0;
+	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
+ *	@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)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw;
+
+	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;
+}
+
+/**
+ *	llc_pdu_decode_pdu_type - designates PDU type
+ *	@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).
+ */
+static int llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)skb->nh.raw;
+
+	if (pdu->ctrl_1 & 1) {
+		if ((pdu->ctrl_1 & LLC_PDU_TYPE_U) == LLC_PDU_TYPE_U)
+			*type = LLC_PDU_TYPE_U;
+		else
+			*type = LLC_PDU_TYPE_S;
+	} else
+		*type = LLC_PDU_TYPE_I;
+	return 0;
+}
+
+/**
+ *	llc_decode_pdu_type - designates component LLC must handle for PDU
+ *	@skb: input skb
+ *	@dest: destination component
+ *
+ *	This function designates which component of LLC must handle this PDU.
+ */
+int llc_decode_pdu_type(struct sk_buff *skb, u8 *dest)
+{
+	u8 type = LLC_DEST_CONN; /* I-PDU or S-PDU type */
+	llc_pdu_sn_t *pdu = (llc_pdu_sn_t *)skb->nh.raw;
+
+	if ((pdu->ctrl_1 & LLC_PDU_TYPE_MASK) != LLC_PDU_TYPE_U)
+		goto out;
+	switch (LLC_U_PDU_CMD(pdu)) {
+		case LLC_1_PDU_CMD_XID:
+		case LLC_1_PDU_CMD_UI:
+		case LLC_1_PDU_CMD_TEST:
+			type = LLC_DEST_SAP;
+			break;
+		case LLC_2_PDU_CMD_SABME:
+		case LLC_2_PDU_CMD_DISC:
+		case LLC_2_PDU_RSP_UA:
+		case LLC_2_PDU_RSP_DM:
+		case LLC_2_PDU_RSP_FRMR:
+			break;
+		default:
+			type = LLC_DEST_INVALID;
+			break;
+	}
+out:	*dest = type;
+	return 0;
+}
+
+/**
+ *	get_llc_hdr_len - designates LLC header length
+ *	@pdu_type: type of PDU.
+ *
+ *	This function designates LLC header length of PDU. header length for I
+ *	and S PDU is 4 and for U is 3 bytes. Returns the length of header.
+ */
+static int llc_get_llc_hdr_length(u8 pdu_type)
+{
+	int rtn_val = 0;
+
+	switch (pdu_type) {
+		case LLC_PDU_TYPE_I:
+		case LLC_PDU_TYPE_S:
+			rtn_val = 4;
+			break;
+		case LLC_PDU_TYPE_U:
+			rtn_val = 3;
+			break;
+	}
+	return rtn_val;
+}
+
+/**
+ *	llc_pdu_get_pf_bit - extracts p/f bit of input PDU
+ *	@pdu: pointer to LLC header.
+ *
+ *	This function extracts p/f bit of input PDU. at first examines type of
+ *	PDU and then extracts p/f bit. Returns the p/f bit.
+ */
+static u8 llc_pdu_get_pf_bit(llc_pdu_sn_t *pdu)
+{
+	u8 pdu_type;
+	u8 pf_bit = 0;
+
+	if (pdu->ctrl_1 & 1) {
+		if ((pdu->ctrl_1 & LLC_PDU_TYPE_U) == LLC_PDU_TYPE_U)
+			pdu_type = LLC_PDU_TYPE_U;
+		else
+			pdu_type = LLC_PDU_TYPE_S;
+	} else
+		pdu_type = LLC_PDU_TYPE_I;
+	switch (pdu_type) {
+		case LLC_PDU_TYPE_I:
+		case LLC_PDU_TYPE_S:
+			pf_bit = pdu->ctrl_2 & LLC_S_PF_BIT_MASK;
+			break;
+		case LLC_PDU_TYPE_U:
+			pf_bit = (pdu->ctrl_1 & LLC_U_PF_BIT_MASK) >> 4;
+			break;
+	}
+	return pf_bit;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/llc/llc_s_ac.c linux.20pre10-ac2/net/llc/llc_s_ac.c
--- linux.20pre10/net/llc/llc_s_ac.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/net/llc/llc_s_ac.c	2002-08-06 15:42:06.000000000 +0100
@@ -0,0 +1,222 @@
+/*
+ * llc_s_ac.c - actions performed during sap state transition.
+ *
+ * Description :
+ *   Functions in this module are implementation of sap component actions.
+ *   Details of actions can be found in IEEE-802.2 standard document.
+ *   All functions have one sap and one event as input argument. All of
+ *   them return 0 On success and 1 otherwise.
+ *
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ *		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/netdevice.h>
+#include <net/llc_if.h>
+#include <net/llc_sap.h>
+#include <net/llc_main.h>
+#include <net/llc_s_ev.h>
+#include <net/llc_pdu.h>
+#include <net/llc_mac.h>
+
+/**
+ *	llc_sap_action_unit_data_ind - forward UI PDU to network layer
+ *	@sap: SAP
+ *	@ev: the event to forward
+ *
+ *	Received a UI PDU from MAC layer; forward to network layer as a
+ *	UNITDATA INDICATION; verify our event is the kind we expect
+ */
+int llc_sap_action_unitdata_ind(struct llc_sap *sap,
+				struct llc_sap_state_ev *ev)
+{
+	llc_sap_rtn_pdu(sap, ev->data.pdu.skb, ev);
+	return 0;
+}
+
+/**
+ *	llc_sap_action_send_ui - sends UI PDU resp to UNITDATA REQ to MAC layer
+ *	@sap: SAP
+ *	@ev: the event to send
+ *
+ *	Sends a UI PDU to the MAC layer in response to a UNITDATA REQUEST
+ *	primitive from the network layer. Verifies event is a primitive type of
+ *	event. Verify the primitive is a UNITDATA REQUEST.
+ */
+int llc_sap_action_send_ui(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+{
+	struct llc_prim_if_block *prim = ev->data.prim.data;
+	struct llc_prim_unit_data *prim_data = &prim->data->udata;
+	struct sk_buff *skb = prim->data->udata.skb;
+	int rc;
+
+	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;
+	rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac);
+	if (!rc)
+		llc_sap_send_pdu(sap, skb);
+out:	return rc;
+}
+
+/**
+ *	llc_sap_action_send_xid_c - send XID PDU as response to XID REQ
+ *	@sap: SAP
+ *	@ev: the event to send
+ *
+ *	Send a XID command PDU to MAC layer in response to a XID REQUEST
+ *	primitive from the network layer. Verify event is a primitive type
+ *	event. Verify the primitive is a XID REQUEST.
+ */
+int llc_sap_action_send_xid_c(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+{
+	struct llc_prim_if_block *prim = ev->data.prim.data;
+	struct llc_prim_xid *prim_data = &prim->data->xid;
+	struct sk_buff *skb = prim_data->skb;
+	int rc;
+
+	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;
+	rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac);
+	if (!rc)
+		llc_sap_send_pdu(sap, skb);
+out:	return rc;
+}
+
+/**
+ *	llc_sap_action_send_xid_r - send XID PDU resp to MAC for received XID
+ *	@sap: SAP
+ *	@ev: the event to send
+ *
+ *	Send XID response PDU to MAC in response to an earlier received XID
+ *	command PDU. Verify event is a PDU type event
+ */
+int llc_sap_action_send_xid_r(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+{
+	u8 mac_da[ETH_ALEN], mac_sa[ETH_ALEN], dsap;
+	int rc = 1;
+	struct sk_buff *ev_skb = ev->data.pdu.skb;
+	struct sk_buff *skb;
+
+	llc_pdu_decode_sa(ev_skb, mac_da);
+	llc_pdu_decode_da(ev_skb, mac_sa);
+	llc_pdu_decode_ssap(ev_skb, &dsap);
+	skb = llc_alloc_frame();
+	if (!skb)
+		goto out;
+	skb->dev = ev_skb->dev;
+	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap, dsap,
+			    LLC_PDU_RSP);
+	rc = llc_pdu_init_as_xid_rsp(skb, LLC_XID_NULL_CLASS_2, 0);
+	if (rc)
+		goto out;
+	rc = lan_hdrs_init(skb, mac_sa, mac_da);
+	if (!rc)
+		llc_sap_send_pdu(sap, skb);
+out:	return rc;
+}
+
+/**
+ *	llc_sap_action_send_test_c - send TEST PDU to MAC in resp to TEST REQ
+ *	@sap: SAP
+ *	@ev: the event to send
+ *
+ *	Send a TEST command PDU to the MAC layer in response to a TEST REQUEST
+ *	primitive from the network layer. Verify event is a primitive type
+ *	event; verify the primitive is a TEST REQUEST.
+ */
+int llc_sap_action_send_test_c(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+{
+	struct llc_prim_if_block *prim = ev->data.prim.data;
+	struct llc_prim_test *prim_data = &prim->data->test;
+	struct sk_buff *skb = prim_data->skb;
+	int rc;
+
+	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;
+	rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac);
+	if (!rc)
+		llc_sap_send_pdu(sap, skb);
+out:	return rc;
+}
+
+int llc_sap_action_send_test_r(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+{
+	u8 mac_da[ETH_ALEN], mac_sa[ETH_ALEN], dsap;
+	int rc = 1;
+	struct sk_buff *ev_skb = ev->data.pdu.skb;
+	struct sk_buff *skb;
+
+	llc_pdu_decode_sa(ev_skb, mac_da);
+	llc_pdu_decode_da(ev_skb, mac_sa);
+	llc_pdu_decode_ssap(ev_skb, &dsap);
+	skb = llc_alloc_frame();
+	if (!skb)
+		goto out;
+	skb->dev = ev_skb->dev;
+	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap, dsap,
+			    LLC_PDU_RSP);
+	rc = llc_pdu_init_as_test_rsp(skb, ev_skb);
+	if (rc)
+		goto out;
+	rc = lan_hdrs_init(skb, mac_sa, mac_da);
+	if (!rc)
+		llc_sap_send_pdu(sap, skb);
+out:	return rc;
+}
+
+/**
+ *	llc_sap_action_report_status - report data link status to layer mgmt
+ *	@sap: SAP
+ *	@ev: the event to send
+ *
+ *	Report data link status to layer management. Verify our event is the
+ *	kind we expect.
+ */
+int llc_sap_action_report_status(struct llc_sap *sap,
+				 struct llc_sap_state_ev *ev)
+{
+	return 0;
+}
+
+/**
+ *	llc_sap_action_xid_ind - send XID PDU resp to net layer via XID IND
+ *	@sap: SAP
+ *	@ev: the event to send
+ *
+ *	Send a XID response PDU to the network layer via a XID INDICATION
+ *	primitive.
+ */
+int llc_sap_action_xid_ind(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+{
+	llc_sap_rtn_pdu(sap, ev->data.pdu.skb, ev);
+	return 0;
+}
+
+/**
+ *	llc_sap_action_test_ind - send TEST PDU to net layer via TEST IND
+ *	@sap: SAP
+ *	@ev: the event to send
+ *
+ *	Send a TEST response PDU to the network layer via a TEST INDICATION
+ *	primitive. Verify our event is a PDU type event.
+ */
+int llc_sap_action_test_ind(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+{
+	llc_sap_rtn_pdu(sap, ev->data.pdu.skb, ev);
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/llc/llc_sap.c linux.20pre10-ac2/net/llc/llc_sap.c
--- linux.20pre10/net/llc/llc_sap.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/net/llc/llc_sap.c	2002-08-06 15:42:06.000000000 +0100
@@ -0,0 +1,259 @@
+/*
+ * llc_sap.c - driver routines for SAP component.
+ *
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/skbuff.h>
+#include <net/llc_conn.h>
+#include <net/llc_sap.h>
+#include <net/llc_s_ev.h>
+#include <net/llc_s_ac.h>
+#include <net/llc_s_st.h>
+#include <net/sock.h>
+#include <net/llc_main.h>
+#include <net/llc_mac.h>
+#include <net/llc_pdu.h>
+#include <linux/if_tr.h>
+
+static void llc_sap_free_ev(struct llc_sap *sap, struct llc_sap_state_ev *ev);
+static int llc_sap_next_state(struct llc_sap *sap, struct llc_sap_state_ev *ev);
+static int llc_exec_sap_trans_actions(struct llc_sap *sap,
+				      struct llc_sap_state_trans *trans,
+				      struct llc_sap_state_ev *ev);
+static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap,
+						  struct llc_sap_state_ev *ev);
+
+/**
+ *	llc_sap_assign_sock - adds a connection to a SAP
+ *	@sap: pointer to SAP.
+ *	@conn: pointer to connection.
+ *
+ *	This function adds a connection to connection_list of a SAP.
+ */
+void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk)
+{
+	spin_lock_bh(&sap->sk_list.lock);
+	llc_sk(sk)->sap = sap;
+	list_add_tail(&llc_sk(sk)->node, &sap->sk_list.list);
+	sock_hold(sk);
+	spin_unlock_bh(&sap->sk_list.lock);
+}
+
+/**
+ *	llc_sap_unassign_sock - removes a connection from SAP
+ *	@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).
+ */
+void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk)
+{
+	spin_lock_bh(&sap->sk_list.lock);
+	list_del(&llc_sk(sk)->node);
+	sock_put(sk);
+	spin_unlock_bh(&sap->sk_list.lock);
+}
+
+/**
+ *	llc_sap_alloc_ev - allocates sap event
+ *	@sap: pointer to SAP
+ *	@ev: allocated event (output argument)
+ *
+ *	Returns the allocated sap event or %NULL when out of memory.
+ */
+struct llc_sap_state_ev *llc_sap_alloc_ev(struct llc_sap *sap)
+{
+	struct llc_sap_state_ev *ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
+
+	if (ev)
+		memset(ev, 0, sizeof(*ev));
+	return ev;
+}
+
+/**
+ *	llc_sap_send_ev - sends event to SAP state machine
+ *	@sap: pointer to SAP
+ *	@ev: 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 llc_sap_state_ev *ev)
+{
+	struct llc_prim_if_block *prim;
+	u8 flag;
+
+	llc_sap_next_state(sap, ev);
+	flag = ev->ind_cfm_flag;
+	prim = ev->prim;
+	if (flag == LLC_IND) {
+		skb_get(ev->data.pdu.skb);
+		sap->ind(prim);
+	}
+	llc_sap_free_ev(sap, ev);
+}
+
+/**
+ *	llc_sap_rtn_pdu - Informs upper layer on rx of an UI, XID or TEST pdu.
+ *	@sap: pointer to SAP
+ *	@skb: received pdu
+ *	@ev: pointer to occurred event
+ */
+void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb,
+		     struct llc_sap_state_ev *ev)
+{
+	llc_pdu_un_t *pdu;
+	struct llc_prim_if_block *prim = &llc_ind_prim;
+	union llc_u_prim_data *prim_data = llc_ind_prim.data;
+	u8 lfb;
+
+	llc_pdu_decode_sa(skb, prim_data->udata.saddr.mac);
+	llc_pdu_decode_da(skb, prim_data->udata.daddr.mac);
+	llc_pdu_decode_dsap(skb, &prim_data->udata.daddr.lsap);
+	llc_pdu_decode_ssap(skb, &prim_data->udata.saddr.lsap);
+	prim_data->udata.pri = 0;
+	prim_data->udata.skb = skb;
+	pdu = (llc_pdu_un_t *)skb->nh.raw;
+	switch (LLC_U_PDU_RSP(pdu)) {
+		case LLC_1_PDU_CMD_TEST:
+			prim->prim = LLC_TEST_PRIM;
+			break;
+		case LLC_1_PDU_CMD_XID:
+			prim->prim = LLC_XID_PRIM;
+			break;
+		case LLC_1_PDU_CMD_UI:
+			if (skb->protocol == ntohs(ETH_P_TR_802_2)) {
+				if (((struct trh_hdr *)skb->mac.raw)->rcf) {
+					lfb = ntohs(((struct trh_hdr *)
+						    skb->mac.raw)->rcf) &
+						    0x0070;
+					prim_data->udata.lfb = lfb >> 4;
+				} else {
+					lfb = 0xFF;
+					prim_data->udata.lfb = 0xFF;
+				}
+			}
+			prim->prim = LLC_DATAUNIT_PRIM;
+			break;
+	}
+	prim->data = prim_data;
+	prim->sap = sap;
+	ev->ind_cfm_flag = LLC_IND;
+	ev->prim = prim;
+}
+
+/**
+ *	llc_sap_send_pdu - Sends a frame to MAC layer for transmition
+ *	@sap: pointer to SAP
+ *	@skb: pdu that must be sent
+ */
+void llc_sap_send_pdu(struct llc_sap *sap, struct sk_buff *skb)
+{
+	mac_send_pdu(skb);
+	kfree_skb(skb);
+}
+
+/**
+ *	llc_sap_free_ev - frees an sap event
+ *	@sap: pointer to SAP
+ *	@ev: released event
+ */
+static void llc_sap_free_ev(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+{
+	if (ev->type == LLC_SAP_EV_TYPE_PDU) {
+		llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+		if (LLC_U_PDU_CMD(pdu) != LLC_1_PDU_CMD_UI)
+			kfree_skb(ev->data.pdu.skb);
+	}
+	kfree(ev);
+}
+
+/**
+ *	llc_sap_next_state - finds transition, execs actions & change SAP state
+ *	@sap: pointer to SAP
+ *	@ev: happened event
+ *
+ *	This function finds transition that matches with happened event, then
+ *	executes related actions and finally changes state of SAP. It returns
+ *	0 on success and 1 for failure.
+ */
+static int llc_sap_next_state(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+{
+	int rc = 1;
+	struct llc_sap_state_trans *trans;
+
+	if (sap->state <= LLC_NBR_SAP_STATES) {
+		trans = llc_find_sap_trans(sap, ev);
+		if (trans) {
+			/* got the state to which we next transition; perform
+			 * the actions associated with this transition before
+			 * actually transitioning to the next state */
+			rc = llc_exec_sap_trans_actions(sap, trans, ev);
+			if (!rc)
+				/* transition SAP to next state if all actions
+				   execute successfully */
+				sap->state = trans->next_state;
+		}
+	}
+	return rc;
+}
+
+/**
+ *	llc_find_sap_trans - finds transition for event
+ *	@sap: pointer to SAP
+ *	@ev: happened event
+ *
+ *	This function finds transition that matches with happened event.
+ *	Returns the pointer to found transition on success or %NULL for
+ *	failure.
+ */
+static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap,
+						    struct llc_sap_state_ev* ev)
+{
+	int i = 0;
+	struct llc_sap_state_trans *rc = NULL;
+	struct llc_sap_state_trans **next_trans;
+	struct llc_sap_state *curr_state = &llc_sap_state_table[sap->state - 1];
+	/* 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++)
+		if (!next_trans[i]->ev(sap, ev)) {
+			/* got event match; return it */
+			rc = next_trans[i];
+			break;
+		}
+	return rc;
+}
+
+/**
+ *	llc_exec_sap_trans_actions - execute actions related to event
+ *	@sap: pointer to SAP
+ *	@trans: pointer to transition that it's actions must be performed
+ *	@ev: happened event.
+ *
+ *	This function executes actions that is related to happened event.
+ *	Returns 0 for success and 1 for failure of at least one action.
+ */
+static int llc_exec_sap_trans_actions(struct llc_sap *sap,
+				      struct llc_sap_state_trans *trans,
+				      struct llc_sap_state_ev *ev)
+{
+	int rc = 0;
+	llc_sap_action_t *next_action;
+
+	for (next_action = trans->ev_actions;
+	     next_action && *next_action; next_action++)
+		if ((*next_action)(sap, ev))
+			rc = 1;
+	return rc;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/llc/llc_s_ev.c linux.20pre10-ac2/net/llc/llc_s_ev.c
--- linux.20pre10/net/llc/llc_s_ev.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/net/llc/llc_s_ev.c	2002-08-06 15:42:06.000000000 +0100
@@ -0,0 +1,101 @@
+/*
+ * llc_s_ev.c - Defines SAP component events
+ *
+ * The followed event functions are SAP component events which are described
+ * in 802.2 LLC protocol standard document.
+ *
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ *		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/socket.h>
+#include <net/sock.h>
+#include <net/llc_if.h>
+#include <net/llc_s_ev.h>
+#include <net/llc_pdu.h>
+
+int llc_sap_ev_activation_req(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+{
+	return ev->type == LLC_SAP_EV_TYPE_SIMPLE &&
+	       ev->data.a.ev == LLC_SAP_EV_ACTIVATION_REQ ? 0 : 1;
+}
+
+int llc_sap_ev_rx_ui(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+	return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_CMD(pdu) &&
+	       !LLC_PDU_TYPE_IS_U(pdu) &&
+	       LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_UI ? 0 : 1;
+}
+
+int llc_sap_ev_unitdata_req(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+{
+	return ev->type == LLC_SAP_EV_TYPE_PRIM &&
+	       ev->data.prim.prim == LLC_DATAUNIT_PRIM &&
+	       ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1;
+
+}
+
+int llc_sap_ev_xid_req(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+{
+	return ev->type == LLC_SAP_EV_TYPE_PRIM &&
+	       ev->data.prim.prim == LLC_XID_PRIM &&
+	       ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1;
+}
+
+int llc_sap_ev_rx_xid_c(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+	return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_CMD(pdu) &&
+	       !LLC_PDU_TYPE_IS_U(pdu) &&
+	       LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID ? 0 : 1;
+}
+
+int llc_sap_ev_rx_xid_r(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+	return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_RSP(pdu) &&
+	       !LLC_PDU_TYPE_IS_U(pdu) &&
+	       LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID ? 0 : 1;
+}
+
+int llc_sap_ev_test_req(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+{
+	return ev->type == LLC_SAP_EV_TYPE_PRIM &&
+	       ev->data.prim.prim == LLC_TEST_PRIM &&
+	       ev->data.prim.type == LLC_PRIM_TYPE_REQ ? 0 : 1;
+}
+
+int llc_sap_ev_rx_test_c(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+	return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_CMD(pdu) &&
+	       !LLC_PDU_TYPE_IS_U(pdu) &&
+	       LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST ? 0 : 1;
+}
+
+int llc_sap_ev_rx_test_r(struct llc_sap *sap, struct llc_sap_state_ev *ev)
+{
+	llc_pdu_un_t *pdu = (llc_pdu_un_t *)ev->data.pdu.skb->nh.raw;
+
+	return ev->type == LLC_SAP_EV_TYPE_PDU && !LLC_PDU_IS_RSP(pdu) &&
+	       !LLC_PDU_TYPE_IS_U(pdu) &&
+	       LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_TEST ? 0 : 1;
+}
+
+int llc_sap_ev_deactivation_req(struct llc_sap *sap,
+				struct llc_sap_state_ev *ev)
+{
+	return ev->type == LLC_SAP_EV_TYPE_SIMPLE &&
+	       ev->data.a.ev == LLC_SAP_EV_DEACTIVATION_REQ ? 0 : 1;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/llc/llc_sock.c linux.20pre10-ac2/net/llc/llc_sock.c
--- linux.20pre10/net/llc/llc_sock.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/net/llc/llc_sock.c	2002-08-06 15:42:06.000000000 +0100
@@ -0,0 +1,1755 @@
+/*
+ * llc_sock.c - LLC User Interface SAPs
+ * Description:
+ *   Functions in this module are implementation of socket based llc
+ *   communications for the Linux operating system. Support of llc class
+ *   one and class two is provided via SOCK_DGRAM and SOCK_STREAM
+ *   respectively.
+ *
+ *   An llc2 connection is (mac + sap), only one llc2 sap connection
+ *   is allowed per mac. Though one sap may have multiple mac + sap
+ *   connections.
+ *
+ * Copyright (c) 2001 by Jay Schulist <jschlst@samba.org>
+ *
+ * This program can be redistributed or modified under the terms of the
+ * GNU General Public License as published by the Free Software Foundation.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <asm/uaccess.h>
+#include <asm/ioctls.h>
+#include <linux/proc_fs.h>
+#include <linux/in.h>
+#include <linux/tcp.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/errno.h>
+#include <net/sock.h>
+#include <net/llc_if.h>
+#include <net/llc_sap.h>
+#include <net/llc_pdu.h>
+#include <net/llc_conn.h>
+#include <linux/llc.h>
+#include <linux/if_arp.h>
+#include <linux/rtnetlink.h>
+#include <linux/init.h>
+
+#define dprintk(format, a...) printk(KERN_INFO __FUNCTION__ ": " format, ##a)
+
+/* 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;
+static rwlock_t llc_ui_sockets_lock = RW_LOCK_UNLOCKED;
+
+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);
+
+/**
+ *	llc_ui_next_link_no - return the next unused link number for a sap
+ *	@sap: Address of sap to get link number from.
+ *
+ *	Return the next unused link number for a given 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.
+ *
+ *	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 u8 llc_ui_mac_null(u8 *mac)
+{
+	return !memcmp(mac, llc_ui_addrany, IFHWADDRLEN);
+}
+
+/**
+ *	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)
+{
+	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.
+ *
+ *	Provide the length of the llc header depending on what kind of
+ *	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)
+{
+	u8 rc = LLC_PDU_LEN_U;
+
+	if (addr->sllc_test || addr->sllc_xid)
+		rc = LLC_PDU_LEN_U;
+	else if (sk->type == SOCK_STREAM)
+		rc = LLC_PDU_LEN_I;
+	return rc;
+}
+
+/**
+ *	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.
+ *
+ *	Send data via reliable llc2 connection.
+ *	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)
+{
+	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;
+
+	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 (!rc)
+		goto try;
+	if (!llc_ui->core_sk)
+		rc = -ENOTCONN;
+out:	sock_put(sk);
+	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.
+ *
+ *	Search the local socket list and return the first instance of the sap
+ *	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)
+{
+	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);
+
+		if (!llc_ui->sap)
+			continue;
+		if (llc_ui->sap->laddr.lsap == sap) {
+			s = llc_ui->sap;
+			break;
+		}
+	}
+	read_unlock_bh(&llc_ui_sockets_lock);
+	return s;
+}
+
+static struct sock *__llc_ui_find_sk_by_exact(struct llc_addr *laddr,
+					      struct llc_addr *daddr)
+{
+	struct sock *sk;
+
+	for (sk = llc_ui_sockets; sk; sk = sk->next) {
+		struct llc_ui_opt *llc_ui = llc_ui_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))
+			break;
+	}
+	return sk;
+}
+
+/**
+ *	__llc_ui_find_sk_by_addr - return socket matching local mac + sap.
+ *	@addr: Local address to match.
+ *
+ *	Search the local socket list and return the socket which has a matching
+ *	local (mac + sap) address (allows null mac). This search will work on
+ *	unconnected and connected sockets, though find_by_link_no is recommend
+ *	for connected sockets.
+ *	Returns sock upon match, %NULL otherwise.
+ */
+static struct sock *__llc_ui_find_sk_by_addr(struct llc_addr *laddr,
+					     struct llc_addr *daddr,
+					     struct net_device *dev)
+{
+	struct sock *sk, *tmp_sk;
+
+	for (sk = llc_ui_sockets; sk; sk = sk->next) {
+		struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+
+		if (llc_ui->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))
+				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))
+			break;
+		if (dev->flags & IFF_LOOPBACK)
+			break;
+		if (!llc_ui_mac_match(llc_ui->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))
+			break;
+	}
+	return sk;
+}
+
+static struct sock *llc_ui_find_sk_by_addr(struct llc_addr *addr,
+					   struct llc_addr *daddr,
+					   struct net_device *dev)
+{
+	struct sock *sk;
+
+	read_lock(&llc_ui_sockets_lock);
+	sk = __llc_ui_find_sk_by_addr(addr, daddr, dev);
+	if (sk)
+		sock_hold(sk);
+	read_unlock(&llc_ui_sockets_lock);
+	return sk;
+}
+
+static struct sock *llc_ui_bh_find_sk_by_addr(struct llc_addr *addr,
+					      struct llc_addr *daddr,
+					      struct net_device *dev)
+{
+	struct sock *sk;
+
+	read_lock_bh(&llc_ui_sockets_lock);
+	sk = __llc_ui_find_sk_by_addr(addr, daddr, dev);
+	if (sk)
+		sock_hold(sk);
+	read_unlock_bh(&llc_ui_sockets_lock);
+	return sk;
+}
+
+/**
+ *	llc_ui_insert_socket - insert socket into list
+ *	@sk: Socket to insert.
+ *
+ *	Insert a socket into the local llc socket list.
+ */
+static inline void llc_ui_insert_socket(struct sock *sk)
+{
+	write_lock_bh(&llc_ui_sockets_lock);
+	sk->next = llc_ui_sockets;
+	if (sk->next)
+		llc_ui_sockets->pprev = &sk->next;
+	llc_ui_sockets = sk;
+	sk->pprev = &llc_ui_sockets;
+	sock_hold(sk);
+	write_unlock_bh(&llc_ui_sockets_lock);
+}
+
+/**
+ *	llc_ui_remove_socket - remove socket from list
+ *	@sk: Socket to remove.
+ *
+ *	Remove a socket from the local llc socket list.
+ */
+static inline void llc_ui_remove_socket(struct sock *sk)
+{
+	write_lock_bh(&llc_ui_sockets_lock);
+	if (sk->pprev) {
+		if (sk->next)
+			sk->next->pprev = sk->pprev;
+		*sk->pprev = sk->next;
+		sk->pprev = NULL;
+		/* this only makes sense if the socket was inserted on the
+		 * list, if sk->pprev is NULL it wasn't */
+		sock_put(sk);
+	}
+	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)
+{
+	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);
+	}
+}
+
+/**
+ *	llc_ui_create - alloc and init a new llc_ui socket
+ *	@sock: Socket to initialize and attach allocated sk to.
+ *	@protocol: Unused.
+ *
+ *	Allocate and initialize a new llc_ui socket, validate the user wants a
+ *	socket type we have available.
+ *	Returns 0 upon success, negative upon failure.
+ */
+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);
+	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:	return rc;
+outsk:	sk_free(sk);
+decmod:	MOD_DEC_USE_COUNT;
+	goto out;
+}
+
+/**
+ *	llc_ui_release - shutdown socket
+ *	@sock: Socket to release.
+ *
+ *	Shutdown and deallocate an existing socket.
+ */
+static int llc_ui_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+	struct llc_ui_opt *llc_ui;
+
+	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);
+	dprintk("rxq=%d, txq=%d\n", skb_queue_len(&sk->receive_queue),
+		skb_queue_len(&sk->write_queue));
+	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);
+	}
+out:	return 0;
+}
+
+/**
+ *	llc_ui_autoport - provide dynamicly allocate SAP number
+ *
+ *	Provide the caller with a dynamicly allocated SAP number according
+ *	to the rules that are set in this function. Returns: 0, upon failure,
+ *	SAP number otherwise.
+ */
+static int llc_ui_autoport(void)
+{
+	struct llc_sap *sap;
+	int i, tries = 0;
+
+	while (tries < LLC_SAP_DYN_TRIES) {
+		for (i = llc_ui_sap_last_autoport;
+		     i < LLC_SAP_DYN_STOP; i += 2) {
+			sap = llc_ui_find_sap(i);
+			if (!sap) {
+				llc_ui_sap_last_autoport = i + 2;
+				goto out;
+			}
+		}
+		llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
+		tries++;
+	}
+	i = 0;
+out:	return i;
+}
+
+/**
+ *	llc_ui_autobind - Bind a socket to a specific address.
+ *	@sk: Socket to bind an address to.
+ *	@addr: Address the user wants the socket bound to.
+ *
+ *	Bind a socket to a specific address. For llc a user is able to bind to
+ *	a specific sap only or mac + sap. If the user only specifies a sap and
+ *	a null dmac (all zeros) the user is attempting to bind to an entire
+ *	sap. This will stop anyone else on the local system from using that
+ *	sap.  If someone else has a mac + sap open the bind to null + sap will
+ *	fail.
+ *	If the user desires to bind to a specific mac + sap, it is possible to
+ *	have multiple sap connections via multiple macs.
+ *	Bind and autobind for that matter must enforce the correct sap usage
+ *	otherwise all hell will break loose.
+ *	Returns: 0 upon success, negative otherwise.
+ */
+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_sap *sap;
+	struct net_device *dev = NULL;
+	int rc = -EINVAL;
+
+	if (!sk->zapped)
+		goto out;
+	/* bind to a specific mac, optional. */
+	if (!llc_ui_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;
+	}
+	/* bind to a specific sap, optional. */
+	if (!addr->sllc_ssap) {
+		rc = -EUSERS;
+		addr->sllc_ssap = llc_ui_autoport();
+		if (!addr->sllc_ssap)
+			goto out;
+	}
+	sap = llc_ui_find_sap(addr->sllc_ssap);
+	if (!sap) {
+		sap = llc_sap_open(llc_ui_indicate, llc_ui_confirm,
+				   addr->sllc_ssap);
+		rc = -EBUSY; /* some other network layer is using the sap */
+		if (!sap)
+			goto out;
+	} else {
+		struct llc_addr laddr, daddr;
+		struct sock *ask;
+
+		rc = -EUSERS; /* can't get exclusive use of sap */
+		if (!dev && llc_ui_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 (sk->type != SOCK_DGRAM) {
+				rc = -EOPNOTSUPP;
+				goto out;
+			}
+			memcpy(laddr.mac, addr->sllc_mmac, IFHWADDRLEN);
+		} else
+			memcpy(laddr.mac, addr->sllc_smac, IFHWADDRLEN);
+		laddr.lsap = addr->sllc_ssap;
+		rc = -EADDRINUSE; /* mac + sap clash. */
+		ask = llc_ui_bh_find_sk_by_addr(&laddr, &daddr, dev);
+		if (ask) {
+			sock_put(ask);
+			goto out;
+		}
+	}
+	memcpy(&llc_ui->addr, addr, sizeof(*addr));
+	llc_ui->sap = sap;
+	rc = sk->zapped = 0;
+	llc_ui_insert_socket(sk);
+out:	return rc;
+}
+
+/**
+ *	llc_ui_bind - bind a socket to a specific address.
+ *	@sock: Socket to bind an address to.
+ *	@uaddr: Address the user wants the socket bound to.
+ *	@addrlen: Length of the uaddr structure.
+ *
+ *	Bind a socket to a specific address. For llc a user is able to bind to
+ *	a specific sap only or mac + sap. If the user only specifies a sap and
+ *	a null dmac (all zeros) the user is attempting to bind to an entire
+ *	sap. This will stop anyone else on the local system from using that
+ *	sap. If someone else has a mac + sap open the bind to null + sap will
+ *	fail.
+ *	If the user desires to bind to a specific mac + sap, it is possible to
+ *	have multiple sap connections via multiple macs.
+ *	Bind and autobind for that matter must enforce the correct sap usage
+ *	otherwise all hell will break loose.
+ *	Returns: 0 upon success, negative otherwise.
+ */
+static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
+{
+	struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr;
+	struct sock *sk = sock->sk;
+	int rc = -EINVAL;
+
+	if (!sk->zapped || addrlen != sizeof(*addr))
+		goto out;
+	rc = -EAFNOSUPPORT;
+	if (addr->sllc_family != AF_LLC)
+		goto out;
+	/* use autobind, to avoid code replication. */
+	rc = llc_ui_autobind(sock, addr);
+out:	return rc;
+}
+
+/**
+ *	llc_ui_shutdown - shutdown a connect llc2 socket.
+ *	@sock: Socket to shutdown.
+ *	@how: What part of the socket to shutdown.
+ *
+ *	Shutdown a connected llc2 socket. Currently this function only supports
+ *	shutting down both sends and receives (2), we could probably make this
+ *	function such that a user can shutdown only half the connection but not
+ *	right now.
+ *	Returns: 0 upon success, negative otherwise.
+ */
+static int llc_ui_shutdown(struct socket *sock, int how)
+{
+	struct sock *sk = sock->sk;
+	int rc = -ENOTCONN;
+
+	lock_sock(sk);
+	if (sk->state != TCP_ESTABLISHED)
+		goto out;
+	rc = -EINVAL;
+	if (how != 2)
+		goto out;
+	rc = llc_ui_send_disc(sk);
+	if (!rc)
+		llc_ui_wait_for_disc(sk, 255);
+	/* Wake up anyone sleeping in poll */
+	sk->state_change(sk);
+out:	release_sock(sk);
+	return rc;
+}
+
+/**
+ *	llc_ui_connect - Connect to a remote llc2 mac + sap.
+ *	@sock: Socket which will be connected to the remote destination.
+ *	@uaddr: Remote and possibly the local address of the new connection.
+ *	@addrlen: Size of uaddr structure.
+ *	@flags: Operational flags specified by the user.
+ *
+ *	Connect to a remote llc2 mac + sap. The caller must specify the
+ *	destination mac and address to connect to. If the user previously
+ *	called bind(2) with a smac the user does not need to specify the source
+ *	address and mac.
+ *	This function will autobind if user did not previously call bind.
+ *	Returns: 0 upon success, negative otherwise.
+ */
+static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
+			  int addrlen, int flags)
+{
+	struct sock *sk = sock->sk;
+	struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+	struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr;
+	struct net_device *dev;
+	int rc = -EINVAL;
+
+	lock_sock(sk);
+	if (addrlen != sizeof(*addr))
+		goto out;
+	rc = -EAFNOSUPPORT;
+	if (addr->sllc_family != AF_LLC)
+		goto out;
+	/* bind connection to sap if user hasn't done it. */
+	if (sk->zapped) {
+		/* bind to sap with null dev, exclusive */
+		rc = llc_ui_autobind(sock, addr);
+		if (rc)
+			goto out;
+	}
+	if (!llc_ui->dev) {
+		rtnl_lock();
+		dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac);
+		rtnl_unlock();
+		if (!dev)
+			goto out;
+	} else
+		dev = llc_ui->dev;
+	if (sk->type != SOCK_STREAM)
+		goto out;
+	rc = -EALREADY;
+	if (sock->state == SS_CONNECTING)
+		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);
+	if (rc) {
+		sock->state = SS_UNCONNECTED;
+		sk->state   = TCP_CLOSE;
+		goto out;
+	}
+	rc = llc_ui_wait_for_conn(sk, 255);
+out:	release_sock(sk);
+	return rc;
+}
+
+/**
+ *	llc_ui_listen - allow a normal socket to accept incoming connections
+ *	@sock: Socket to allow incoming connections on.
+ *	@backlog: Number of connections to queue.
+ *
+ *	Allow a normal socket to accept incoming connections.
+ *	Returns 0 upon success, negative otherwise.
+ */
+static int llc_ui_listen(struct socket *sock, int backlog)
+{
+	struct sock *sk = sock->sk;
+	int rc = -EINVAL;
+
+	lock_sock(sk);
+	if (sock->state != SS_UNCONNECTED)
+		goto out;
+	rc = -EOPNOTSUPP;
+	if (sk->type != SOCK_STREAM && sk->type != SOCK_SEQPACKET)
+		goto out;
+	rc = -EAGAIN;
+	if (sk->zapped)
+		goto out;
+	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;
+		sk->state = TCP_LISTEN;
+	}
+	sk->socket->flags |= __SO_ACCEPTCON;
+out:	release_sock(sk);
+	return rc;
+}
+
+static int llc_ui_wait_for_disc(struct sock *sk, int seconds)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int rc, timeout = seconds * HZ;
+
+	add_wait_queue_exclusive(sk->sleep, &wait);
+	for (;;) {
+		__set_current_state(TASK_INTERRUPTIBLE);
+		rc = 0;
+		if (sk->state != TCP_CLOSE)
+			timeout = schedule_timeout(timeout);
+		else
+			break;
+		rc = -ERESTARTSYS;
+		if (signal_pending(current))
+			break;
+		rc = -EAGAIN;
+		if (!timeout)
+			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)
+{
+	struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+	DECLARE_WAITQUEUE(wait, current);
+	int rc, timeout = seconds * HZ;
+
+	add_wait_queue_exclusive(sk->sleep, &wait);
+	for (;;) {
+		__set_current_state(TASK_INTERRUPTIBLE);
+		rc = 0;
+		if (sk->state != TCP_ESTABLISHED)
+			timeout = schedule_timeout(timeout);
+		if (sk->state == TCP_ESTABLISHED) {
+			if (!llc_ui->core_sk)
+				rc = -EAGAIN;
+			break;
+		}
+		rc = -EAGAIN;
+		if (sk->state == TCP_CLOSE)
+			break;
+		rc = -ERESTARTSYS;
+		if (signal_pending(current))
+			break;
+		rc = -EAGAIN;
+		if (!timeout)
+			break;
+	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(sk->sleep, &wait);
+	return rc;
+}
+
+/**
+ *	llc_ui_accept - accept a new incoming connection.
+ *	@sock: Socket which connections arrive on.
+ *	@newsock: Socket to move incoming connection to.
+ *	@flags: User specified operational flags.
+ *
+ *	Accept a new incoming connection.
+ *	Returns 0 upon success, negative otherwise.
+ */
+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 sk_buff *skb;
+	int rc = -EOPNOTSUPP;
+
+	lock_sock(sk);
+	if (sk->type != SOCK_SEQPACKET && 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);
+	if (rc)
+		goto frees;
+	rc = 0;
+	newsk			= newsock->sk;
+	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;
+
+	/* put original socket back into a clean listen state. */
+	sk->state = TCP_LISTEN;
+	sk->ack_backlog--;
+	llc_ui_insert_socket(newsk);
+	skb->sk = NULL;
+frees:	kfree_skb(skb);
+out:	release_sock(sk);
+	return rc;
+}
+
+/**
+ *	llc_ui_recvmsg - copy received data to the socket user.
+ *	@sock: Socket to copy data from.
+ *	@msg: Various user space related information.
+ *	@size: Size of user buffer.
+ *	@flags: User specified flags.
+ *	@scm: Unknown.
+ *
+ *	Copy received data to the socket user.
+ *	Returns non-negative upon success, negative otherwise.
+ */
+static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, int size,
+			  int flags, struct scm_cookie *scm)
+{
+	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 noblock = flags & MSG_DONTWAIT;
+
+	lock_sock(sk);
+	skb = skb_recv_datagram(sk, flags, noblock, &rc);
+	if (!skb)
+		goto out;
+	copied = skb->len;
+	if (copied > size) {
+		copied = size;
+		msg->msg_flags |= MSG_TRUNC;
+	}
+	rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+	if (rc)
+		goto dgram_free;
+	if (uaddr)
+		memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr));
+	msg->msg_namelen = sizeof(*uaddr);
+dgram_free:
+	skb_free_datagram(sk, skb); /* Free the datagram. */
+out:	release_sock(sk);
+	return rc ? : copied;
+}
+
+/**
+ *	llc_ui_sendmsg - Transmit data provided by the socket user.
+ *	@sock: Socket to transmit data from.
+ *	@msg: Various user related information.
+ *	@len: Length of data to transmit.
+ *	@scm: Unknown.
+ *
+ *	Transmit data provided by the socket user.
+ *	Returns non-negative upon success, negative otherwise.
+ */
+static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+			  struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+	struct sockaddr_llc *addr = (struct sockaddr_llc *)msg->msg_name;
+	int flags = msg->msg_flags;
+	struct net_device *dev;
+	struct sk_buff *skb;
+	int rc = -EOPNOTSUPP, size = 0;
+
+	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))
+			goto release;
+		addr = &llc_ui->addr;
+	}
+	/* must bind connection to sap if user hasn't done it. */
+	if (sk->zapped) {
+		/* bind to sap with null dev, exclusive. */
+		rc = llc_ui_autobind(sock, addr);
+		if (rc)
+			goto release;
+	}
+	if (!llc_ui->dev) {
+		rtnl_lock();
+		dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac);
+		rtnl_unlock();
+		rc = -ENETUNREACH;
+		if (!dev)
+			goto release;
+	} else
+		dev = llc_ui->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);
+	if (!skb)
+		goto release;
+	skb->sk  = sk;
+	skb->dev = dev;
+	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;
+	if (addr->sllc_test) {
+		rc = llc_ui_send_llc1(llc_ui->sap, skb, addr, LLC_TEST_PRIM);
+		goto out;
+	}
+	if (addr->sllc_xid) {
+		rc = llc_ui_send_llc1(llc_ui->sap, skb, addr, LLC_XID_PRIM);
+		goto out;
+	}
+	if (sk->type == SOCK_DGRAM || addr->sllc_ua) {
+		rc = llc_ui_send_llc1(llc_ui->sap, skb, addr, LLC_DATAUNIT_PRIM);
+		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);
+out:	if (rc)
+		skb_free_datagram(sk, skb);
+release:
+	release_sock(sk);
+	return rc ? : len;
+}
+
+/**
+ *	llc_ui_getname - return the address info of a socket
+ *	@sock: Socket to get address of.
+ *	@uaddr: Address structure to return information.
+ *	@uaddrlen: Length of address structure.
+ *	@peer: Does user want local or remote address information.
+ *
+ *	Return the address information of a socket.
+ */
+static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr,
+			  int *uaddrlen, int peer)
+{
+	struct sockaddr_llc sllc;
+	struct sock *sk = sock->sk;
+	struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+	int rc = 0;
+
+	lock_sock(sk);
+	if (sk->zapped)
+		goto out;
+	*uaddrlen = sizeof(sllc);
+	memset(uaddr, 0, *uaddrlen);
+	if (peer) {
+		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);
+	} else {
+		rc = -EINVAL;
+		if (!llc_ui->sap)
+			goto out;
+		sllc.sllc_ssap = llc_ui->sap->laddr.lsap;
+
+		if (llc_ui->dev) {
+			sllc.sllc_arphrd = llc_ui->dev->type;
+			memcpy(&sllc.sllc_smac, &llc_ui->dev->dev_addr,
+			       IFHWADDRLEN);
+		}
+	}
+	rc = 0;
+	sllc.sllc_family = AF_LLC;
+	memcpy(uaddr, &sllc, sizeof(sllc));
+out:	release_sock(sk);
+	return rc;
+}
+
+/**
+ *	llc_ui_ioctl - io controls for PF_LLC
+ *	@sock: Socket to get/set info
+ *	@cmd: command
+ *	@arg: optional argument for cmd
+ *
+ *	get/set info on llc sockets
+ */
+static int llc_ui_ioctl(struct socket *sock, unsigned int cmd,
+			unsigned long arg)
+{
+	return dev_ioctl(cmd, (void *)arg);
+}
+
+/**
+ *	llc_ui_setsockopt - set various connection specific parameters.
+ *	@sock: Socket to set options on.
+ *	@level: Socket level user is requesting operations on.
+ *	@optname: Operation name.
+ *	@optval User provided operation data.
+ *	@optlen: Length of optval.
+ *
+ *	Set various connection specific parameters.
+ */
+static int llc_ui_setsockopt(struct socket *sock, int level, int optname,
+			     char *optval, int optlen)
+{
+	struct sock *sk = sock->sk;
+	struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+	struct llc_opt *llc_core;
+	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;
+			break;
+		case LLC_OPT_SIZE:
+			if (opt > LLC_OPT_MAX_SIZE)
+				goto out;
+			llc_core->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;
+			break;
+		case LLC_OPT_P_TMR_EXP:
+			if (opt > LLC_OPT_MAX_P_TMR_EXP)
+				goto out;
+			llc_core->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;
+			break;
+		case LLC_OPT_BUSY_TMR_EXP:
+			if (opt > LLC_OPT_MAX_BUSY_TMR_EXP)
+				goto out;
+			llc_core->busy_state_timer.expire = opt;
+			break;
+		case LLC_OPT_TX_WIN:
+			if (opt > LLC_OPT_MAX_WIN)
+				goto out;
+			llc_core->k = opt;
+			break;
+		case LLC_OPT_RX_WIN:
+			if (opt > LLC_OPT_MAX_WIN)
+				goto out;
+			llc_core->rw = opt;
+			break;
+		default:
+			rc = -ENOPROTOOPT;
+			goto out;
+	}
+	rc = 0;
+out:	release_sock(sk);
+	return rc;
+}
+
+/**
+ *	llc_ui_getsockopt - get connection specific socket info
+ *	@sock: Socket to get information from.
+ *	@level: Socket level user is requesting operations on.
+ *	@optname: Operation name.
+ *	@optval: Variable to return operation data in.
+ *	@optlen: Length of optval.
+ *
+ *	Get connection specific socket information.
+ */
+static int llc_ui_getsockopt(struct socket *sock, int level, int optname,
+			     char *optval, int *optlen)
+{
+	struct sock *sk = sock->sk;
+	struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
+	struct llc_opt *llc_core;
+	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;
+		case LLC_OPT_SIZE:
+			val = llc_core->n1;				break;
+		case LLC_OPT_ACK_TMR_EXP:
+			val = llc_core->ack_timer.expire;		break;
+		case LLC_OPT_P_TMR_EXP:
+			val = llc_core->pf_cycle_timer.expire;		break;
+		case LLC_OPT_REJ_TMR_EXP:
+			val = llc_core->rej_sent_timer.expire;		break;
+		case LLC_OPT_BUSY_TMR_EXP:
+			val = llc_core->busy_state_timer.expire;	break;
+		case LLC_OPT_TX_WIN:
+			val = llc_core->k;				break;
+		case LLC_OPT_RX_WIN:
+			val = llc_core->rw;				break;
+		default:
+			rc = -ENOPROTOOPT;
+			goto out;
+	}
+	rc = 0;
+	if (put_user(len, optlen) || copy_to_user(optval, &val, len))
+		rc = -EFAULT;
+out:	release_sock(sk);
+	return rc;
+}
+
+/**
+ *	llc_ui_ind_test - handle TEST indication
+ *	@prim: Primitive block provided by the llc layer.
+ *
+ *	handle TEST indication.
+ */
+static void llc_ui_ind_test(struct llc_prim_if_block *prim)
+{
+	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 sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr,
+						 &prim_data->saddr, skb->dev);
+	if (!sk)
+		goto out;
+	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);
+	/* queue skb to the user. */
+	if (sock_queue_rcv_skb(sk, skb))
+		kfree_skb(skb);
+out_put:
+	sock_put(sk);
+out:;
+}
+
+/**
+ *	llc_ui_ind_xid - handle XID indication
+ *	@prim: Primitive block provided by the llc layer.
+ *
+ *	handle XID indication.
+ */
+static void llc_ui_ind_xid(struct llc_prim_if_block *prim)
+{
+	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 sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr,
+						 &prim_data->saddr, skb->dev);
+	if (!sk)
+		goto out;
+	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);
+	/* queue skb to the user. */
+	if (sock_queue_rcv_skb(sk, skb))
+		kfree_skb(skb);
+out_put:
+	sock_put(sk);
+out:;
+}
+
+/**
+ *	llc_ui_ind_dataunit - handle DATAUNIT indication
+ *	@prim: Primitive block provided by the llc layer.
+ *
+ *	handle DATAUNIT indication.
+ */
+static void llc_ui_ind_dataunit(struct llc_prim_if_block *prim)
+{
+	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 sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr,
+						 &prim_data->saddr, skb->dev);
+	if (!sk)
+		goto out;
+	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) {
+		dprintk("llc_ui_find_sk_by_addr failed\n");
+		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);
+	/* queue skb to the user. */
+	if (sock_queue_rcv_skb(sk, skb)) {
+		dprintk("sock_queue_rcv_skb failed!\n");
+		kfree_skb(skb);
+	}
+out_put:
+	sock_put(sk);
+out:;
+}
+
+/**
+ *	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.
+ *
+ *	LLC user interface hook into the LLC layer, every llc_ui sap references
+ *	this function as its indicate handler.
+ *	Always returns 0 to indicate reception of primitive.
+ */
+static int llc_ui_indicate(struct llc_prim_if_block *prim)
+{
+	switch (prim->prim) {
+		case LLC_TEST_PRIM:
+			llc_ui_ind_test(prim);		break;
+		case LLC_XID_PRIM:
+			llc_ui_ind_xid(prim);		break;
+		case LLC_DATAUNIT_PRIM:
+			llc_ui_ind_dataunit(prim);	break;
+		case LLC_CONN_PRIM:
+			llc_ui_ind_conn(prim);		break;
+		case LLC_DATA_PRIM:
+			llc_ui_ind_data(prim);		break;
+		case LLC_DISC_PRIM:
+			llc_ui_ind_disc(prim);		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 llc_ui_opt *llc_ui = llc_ui_sk(prim_data->sk);
+	struct sock* sk = llc_core->handler;
+
+	if (!sk) {
+		dprintk("llc_core->handler == NULL!\n");
+		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 {
+		dprintk("prim->data->conn.status = %d\n",
+			prim->data->conn.status);
+		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.
+ *
+ *	LLC user interface hook into the LLC layer, every llc_ui sap references
+ *	this function as its confirm handler.
+ *	Always returns 0 to indicate reception of primitive.
+ */
+static int llc_ui_confirm(struct llc_prim_if_block *prim)
+{
+	switch (prim->prim) {
+		case LLC_CONN_PRIM:
+			llc_ui_conf_conn(prim);		break;
+		case LLC_DATA_PRIM:
+			llc_ui_conf_data(prim);		break;
+		case LLC_DISC_PRIM:
+			llc_ui_conf_disc(prim);		break;
+		case LLC_RESET_PRIM:			break;
+		default:
+			printk(KERN_ERR __FUNCTION__ ": unknown prim %d\n",
+			       prim->prim);
+			break;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+/**
+ *	llc_ui_get_info - return info to procfs
+ *	@buffer: where to put the formatted output
+ *	@start: starting from
+ *	@offset: offset into buffer.
+ *	@length: size of the buffer
+ *
+ *	Get the output of the local llc ui socket list to the caller.
+ *	Returns the length of data wrote to buffer.
+ */
+static int llc_ui_get_info(char *buffer, char **start, off_t offset, int length)
+{
+	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");
+	/* 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))
+				len += sprintf(buffer + len,
+					"%02X:%02X:%02X:%02X:%02X:%02X",
+					llc_ui->dev->dev_addr[0],
+					llc_ui->dev->dev_addr[1],
+					llc_ui->dev->dev_addr[2],
+					llc_ui->dev->dev_addr[3],
+					llc_ui->dev->dev_addr[4],
+					llc_ui->dev->dev_addr[5]);
+			else {
+				if (!llc_ui_mac_null(llc_ui->addr.sllc_mmac))
+					len += sprintf(buffer + len,
+						"%02X:%02X:%02X:%02X:%02X:%02X",
+						llc_ui->addr.sllc_mmac[0],
+						llc_ui->addr.sllc_mmac[1],
+						llc_ui->addr.sllc_mmac[2],
+						llc_ui->addr.sllc_mmac[3],
+						llc_ui->addr.sllc_mmac[4],
+						llc_ui->addr.sllc_mmac[5]);
+				else
+					len += sprintf(buffer + len,
+							"00:00:00:00:00:00");
+			}
+			len += sprintf(buffer + len, "@%02X ",
+					llc_ui->sap->laddr.lsap);
+		} else
+			len += sprintf(buffer + len, "00:00:00:00:00:00@00 ");
+		len += sprintf(buffer + len,
+				"%02X:%02X:%02X:%02X:%02X:%02X@%02X "
+				"%08X:%08X %02X %-3d ",
+				llc_ui->addr.sllc_dmac[0], llc_ui->addr.sllc_dmac[1],
+				llc_ui->addr.sllc_dmac[2], llc_ui->addr.sllc_dmac[3],
+				llc_ui->addr.sllc_dmac[4], llc_ui->addr.sllc_dmac[5],
+				llc_ui->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");
+		/* Are we still dumping unwanted data then discard the record */
+		pos = begin + len;
+
+		if (pos < offset) {
+			len = 0; /* Keep dumping into the buffer start */
+			begin = pos;
+		}
+		if (pos > offset + length) /* We have dumped enough */
+			break;
+	}
+	read_unlock_bh(&llc_ui_sockets_lock);
+
+	/* The data in question runs from begin to begin + len */
+	*start = buffer + offset - begin; /* Start of wanted data */
+	len -= offset - begin; /* Remove unwanted header data from length */
+	if (len > length)
+		len = length; /* Remove unwanted tail data from length */
+	return len;
+}
+#endif /* CONFIG_PROC_FS */
+
+static struct net_proto_family llc_ui_family_ops = {
+	family:	PF_LLC,
+	create:	llc_ui_create,
+};
+
+static struct proto_ops SOCKOPS_WRAPPED(llc_ui_ops) = {
+	family:		PF_LLC,
+	release:	llc_ui_release,
+	bind:		llc_ui_bind,
+	connect:	llc_ui_connect,
+	socketpair:	sock_no_socketpair,
+	accept:		llc_ui_accept,
+	getname:	llc_ui_getname,
+	poll:		datagram_poll,
+	ioctl:		llc_ui_ioctl,
+	listen:		llc_ui_listen,
+	shutdown:	llc_ui_shutdown,
+	setsockopt:	llc_ui_setsockopt,
+	getsockopt:	llc_ui_getsockopt,
+	sendmsg:	llc_ui_sendmsg,
+	recvmsg:	llc_ui_recvmsg,
+	mmap:		sock_no_mmap,
+	sendpage:	sock_no_sendpage,
+};
+
+#include <linux/smp_lock.h>
+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";
+
+int __init llc_ui_init(void)
+{
+	llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
+	sock_register(&llc_ui_family_ops);
+	proc_net_create("llc", 0, llc_ui_get_info);
+	printk(llc_ui_banner);
+	return 0;
+}
+
+void __exit llc_ui_exit(void)
+{
+	proc_net_remove("llc");
+	sock_unregister(PF_LLC);
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/llc/llc_s_st.c linux.20pre10-ac2/net/llc/llc_s_st.c
--- linux.20pre10/net/llc/llc_s_st.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/net/llc/llc_s_st.c	2002-08-06 15:42:06.000000000 +0100
@@ -0,0 +1,163 @@
+/*
+ * llc_s_st.c - Defines SAP component state machine transitions.
+ *
+ * The followed transitions are SAP component state machine transitions
+ * which are described in 802.2 LLC protocol standard document.
+ *
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ *		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/types.h>
+#include <net/llc_if.h>
+#include <net/llc_s_ev.h>
+#include <net/llc_s_ac.h>
+#include <net/llc_s_st.h>
+
+/* dummy last-transition indicator; common to all state transition groups */
+/* last entry for this state */
+/* all members are zeros, .bss zeroes it */
+static struct llc_sap_state_trans llc_sap_state_trans_n;
+
+/* state LLC_SAP_STATE_INACTIVE transition for LLC_SAP_EV_ACTIVATION_REQ event */
+static llc_sap_action_t llc_sap_inactive_state_actions_1[] = {
+	llc_sap_action_report_status,
+	NULL
+};
+
+static struct llc_sap_state_trans llc_sap_inactive_state_trans_1 = {
+	llc_sap_ev_activation_req,	LLC_SAP_STATE_ACTIVE,
+					llc_sap_inactive_state_actions_1
+};
+
+/* array of pointers; one to each transition */
+static struct llc_sap_state_trans *llc_sap_inactive_state_transitions[] = {
+	&llc_sap_inactive_state_trans_1,
+	&llc_sap_state_trans_n
+};
+
+/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_RX_UI event */
+static llc_sap_action_t llc_sap_active_state_actions_1[] = {
+	llc_sap_action_unitdata_ind,
+	NULL
+};
+
+static struct llc_sap_state_trans llc_sap_active_state_trans_1 = {
+	llc_sap_ev_rx_ui,		LLC_SAP_STATE_ACTIVE,
+					llc_sap_active_state_actions_1
+};
+
+/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_UNITDATA_REQ event */
+static llc_sap_action_t llc_sap_active_state_actions_2[] = {
+	llc_sap_action_send_ui,
+	NULL
+};
+
+static struct llc_sap_state_trans llc_sap_active_state_trans_2 = {
+	llc_sap_ev_unitdata_req,	LLC_SAP_STATE_ACTIVE,
+					llc_sap_active_state_actions_2
+};
+
+
+/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_XID_REQ event */
+static llc_sap_action_t llc_sap_active_state_actions_3[] = {
+	llc_sap_action_send_xid_c,
+	NULL
+};
+
+static struct llc_sap_state_trans llc_sap_active_state_trans_3 = {
+	llc_sap_ev_xid_req,		LLC_SAP_STATE_ACTIVE,
+					llc_sap_active_state_actions_3
+};
+
+/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_RX_XID_C event */
+static llc_sap_action_t llc_sap_active_state_actions_4[] = {
+	llc_sap_action_send_xid_r,
+	NULL
+};
+
+static struct llc_sap_state_trans llc_sap_active_state_trans_4 = {
+	llc_sap_ev_rx_xid_c,		LLC_SAP_STATE_ACTIVE,
+					llc_sap_active_state_actions_4
+};
+
+/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_RX_XID_R event */
+static llc_sap_action_t llc_sap_active_state_actions_5[] = {
+	llc_sap_action_xid_ind,
+	NULL
+};
+
+static struct llc_sap_state_trans llc_sap_active_state_trans_5 = {
+	llc_sap_ev_rx_xid_r,		LLC_SAP_STATE_ACTIVE,
+					llc_sap_active_state_actions_5
+};
+
+/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_TEST_REQ event */
+static llc_sap_action_t llc_sap_active_state_actions_6[] = {
+	llc_sap_action_send_test_c,
+	NULL
+};
+
+static struct llc_sap_state_trans llc_sap_active_state_trans_6 = {
+	llc_sap_ev_test_req,		LLC_SAP_STATE_ACTIVE,
+					llc_sap_active_state_actions_6
+};
+
+/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_RX_TEST_C event */
+static llc_sap_action_t llc_sap_active_state_actions_7[] = {
+	llc_sap_action_send_test_r,
+	NULL
+};
+
+static struct llc_sap_state_trans llc_sap_active_state_trans_7 = {
+	llc_sap_ev_rx_test_c,		LLC_SAP_STATE_ACTIVE,
+					llc_sap_active_state_actions_7
+};
+
+/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_RX_TEST_R event */
+static llc_sap_action_t llc_sap_active_state_actions_8[] = {
+	llc_sap_action_test_ind,
+	NULL
+};
+
+static struct llc_sap_state_trans llc_sap_active_state_trans_8 = {
+	llc_sap_ev_rx_test_r,		LLC_SAP_STATE_ACTIVE,
+					llc_sap_active_state_actions_8
+};
+
+/* state LLC_SAP_STATE_ACTIVE transition for LLC_SAP_EV_DEACTIVATION_REQ event */
+static llc_sap_action_t llc_sap_active_state_actions_9[] = {
+	llc_sap_action_report_status,
+	NULL
+};
+
+static struct llc_sap_state_trans llc_sap_active_state_trans_9 = {
+	llc_sap_ev_deactivation_req,	LLC_SAP_STATE_INACTIVE,
+					llc_sap_active_state_actions_9
+};
+
+/* array of pointers; one to each transition */
+static struct llc_sap_state_trans *llc_sap_active_state_transitions[] = {
+	&llc_sap_active_state_trans_2,
+	&llc_sap_active_state_trans_1,
+	&llc_sap_active_state_trans_3,
+	&llc_sap_active_state_trans_4,
+	&llc_sap_active_state_trans_5,
+	&llc_sap_active_state_trans_6,
+	&llc_sap_active_state_trans_7,
+	&llc_sap_active_state_trans_8,
+	&llc_sap_active_state_trans_9,
+	&llc_sap_state_trans_n
+};
+
+/* SAP state transition table */
+struct llc_sap_state llc_sap_state_table[] = {
+	{ LLC_SAP_STATE_INACTIVE, llc_sap_inactive_state_transitions },
+	{ LLC_SAP_STATE_ACTIVE,	  llc_sap_active_state_transitions   }
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/llc/llc_stat.c linux.20pre10-ac2/net/llc/llc_stat.c
--- linux.20pre10/net/llc/llc_stat.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/net/llc/llc_stat.c	2002-08-06 15:42:06.000000000 +0100
@@ -0,0 +1,199 @@
+/*
+ * llc_stat.c - Implementation of LLC station component state machine
+ * 		transitions
+ * Copyright (c) 1997 by Procom Technology, Inc.
+ * 		 2001 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.
+ * This program is distributed without any warranty or implied warranty
+ * of merchantability or fitness for a particular purpose.
+ *
+ * See the GNU General Public License for more details.
+ */
+#include <linux/types.h>
+#include <net/llc_if.h>
+#include <net/llc_sap.h>
+#include <net/llc_evnt.h>
+#include <net/llc_actn.h>
+#include <net/llc_stat.h>
+
+/* ------------------- COMMON STATION STATE transitions ------------------ */
+
+/* dummy last-transition indicator; common to all state transition groups */
+/* last entry for this state */
+/* all members are zeros, .bss zeroes it */
+static struct llc_station_state_trans llc_stat_state_trans_n;
+
+/* ------------------------ DOWN STATE transitions ----------------------- */
+
+/* state transition for LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK event */
+static llc_station_action_t llc_stat_down_state_actions_1[] = {
+	llc_station_ac_start_ack_timer,
+	llc_station_ac_set_retry_cnt_0,
+	llc_station_ac_set_xid_r_cnt_0,
+	llc_station_ac_send_null_dsap_xid_c,
+	NULL
+};
+
+static struct llc_station_state_trans llc_stat_down_state_trans_1 = {
+	llc_stat_ev_enable_with_dup_addr_check,
+					LLC_STATION_STATE_DUP_ADDR_CHK,
+					llc_stat_down_state_actions_1
+};
+
+/* state transition for LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK event */
+static llc_station_action_t llc_stat_down_state_actions_2[] = {
+	llc_station_ac_report_status,	/* STATION UP */
+	NULL
+};
+
+static struct llc_station_state_trans llc_stat_down_state_trans_2 = {
+	llc_stat_ev_enable_without_dup_addr_check,
+					LLC_STATION_STATE_UP,
+					llc_stat_down_state_actions_2
+};
+
+/* array of pointers; one to each transition */
+static struct llc_station_state_trans *llc_stat_dwn_state_trans[] = {
+	&llc_stat_down_state_trans_1,
+	&llc_stat_down_state_trans_2,
+	&llc_stat_state_trans_n
+};
+
+/* ------------------------- UP STATE transitions ------------------------ */
+/* state transition for LLC_STATION_EV_DISABLE_REQ event */
+static llc_station_action_t llc_stat_up_state_actions_1[] = {
+	llc_station_ac_report_status,	/* STATION DOWN */
+	NULL
+};
+
+static struct llc_station_state_trans llc_stat_up_state_trans_1 = {
+	llc_stat_ev_disable_req,	LLC_STATION_STATE_DOWN,
+					llc_stat_up_state_actions_1
+};
+
+/* state transition for LLC_STATION_EV_RX_NULL_DSAP_XID_C event */
+static llc_station_action_t llc_stat_up_state_actions_2[] = {
+	llc_station_ac_send_xid_r,
+	NULL
+};
+
+static struct llc_station_state_trans llc_stat_up_state_trans_2 = {
+	llc_stat_ev_rx_null_dsap_xid_c,	LLC_STATION_STATE_UP,
+					llc_stat_up_state_actions_2
+};
+
+/* state transition for LLC_STATION_EV_RX_NULL_DSAP_TEST_C event */
+static llc_station_action_t llc_stat_up_state_actions_3[] = {
+	llc_station_ac_send_test_r,
+	NULL
+};
+
+static struct llc_station_state_trans llc_stat_up_state_trans_3 = {
+	llc_stat_ev_rx_null_dsap_test_c,	LLC_STATION_STATE_UP,
+					llc_stat_up_state_actions_3
+};
+
+/* array of pointers; one to each transition */
+static struct llc_station_state_trans *llc_stat_up_state_trans [] = {
+	&llc_stat_up_state_trans_1,
+	&llc_stat_up_state_trans_2,
+	&llc_stat_up_state_trans_3,
+	&llc_stat_state_trans_n
+};
+
+/* ---------------------- DUP ADDR CHK STATE transitions ----------------- */
+/* state transition for LLC_STATION_EV_RX_NULL_DSAP_0_XID_R_XID_R_CNT_EQ
+ * event */
+static llc_station_action_t llc_stat_dupaddr_state_actions_1[] = {
+	llc_station_ac_inc_xid_r_cnt_by_1,
+	NULL
+};
+
+static struct llc_station_state_trans llc_stat_dupaddr_state_trans_1 = {
+	llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq,
+					LLC_STATION_STATE_DUP_ADDR_CHK,
+					llc_stat_dupaddr_state_actions_1
+};
+
+/* state transition for LLC_STATION_EV_RX_NULL_DSAP_1_XID_R_XID_R_CNT_EQ
+ * event */
+static llc_station_action_t llc_stat_dupaddr_state_actions_2[] = {
+	llc_station_ac_report_status,	/* DUPLICATE ADDRESS FOUND */
+	NULL
+};
+
+static struct llc_station_state_trans llc_stat_dupaddr_state_trans_2 = {
+	llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq,
+					LLC_STATION_STATE_DOWN,
+					llc_stat_dupaddr_state_actions_2
+};
+
+/* state transition for LLC_STATION_EV_RX_NULL_DSAP_XID_C event */
+static llc_station_action_t llc_stat_dupaddr_state_actions_3[] = {
+	llc_station_ac_send_xid_r,
+	NULL
+};
+
+static struct llc_station_state_trans llc_stat_dupaddr_state_trans_3 = {
+	llc_stat_ev_rx_null_dsap_xid_c,	LLC_STATION_STATE_DUP_ADDR_CHK,
+					llc_stat_dupaddr_state_actions_3
+};
+
+/* state transition for LLC_STATION_EV_ACK_TMR_EXP_LT_RETRY_CNT_MAX_RETRY
+ * event */
+static llc_station_action_t llc_stat_dupaddr_state_actions_4[] = {
+	llc_station_ac_start_ack_timer,
+	llc_station_ac_inc_retry_cnt_by_1,
+	llc_station_ac_set_xid_r_cnt_0,
+	llc_station_ac_send_null_dsap_xid_c,
+	NULL
+};
+
+static struct llc_station_state_trans llc_stat_dupaddr_state_trans_4 = {
+	llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry,
+					LLC_STATION_STATE_DUP_ADDR_CHK,
+					llc_stat_dupaddr_state_actions_4
+};
+
+/* state transition for LLC_STATION_EV_ACK_TMR_EXP_EQ_RETRY_CNT_MAX_RETRY
+ * event */
+static llc_station_action_t llc_stat_dupaddr_state_actions_5[] = {
+	llc_station_ac_report_status,	/* STATION UP */
+	NULL
+};
+
+static struct llc_station_state_trans llc_stat_dupaddr_state_trans_5 = {
+	llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry,
+					LLC_STATION_STATE_UP,
+					llc_stat_dupaddr_state_actions_5
+};
+
+/* state transition for LLC_STATION_EV_DISABLE_REQ event */
+static llc_station_action_t llc_stat_dupaddr_state_actions_6[] = {
+	llc_station_ac_report_status,	/* STATION DOWN */
+	NULL
+};
+
+static struct llc_station_state_trans llc_stat_dupaddr_state_trans_6 = {
+	llc_stat_ev_disable_req,	LLC_STATION_STATE_DOWN,
+					llc_stat_dupaddr_state_actions_6
+};
+
+/* array of pointers; one to each transition */
+static struct llc_station_state_trans *llc_stat_dupaddr_state_trans[] = {
+	&llc_stat_dupaddr_state_trans_6,	/* Request */
+	&llc_stat_dupaddr_state_trans_4,	/* Timer */
+	&llc_stat_dupaddr_state_trans_5,
+	&llc_stat_dupaddr_state_trans_1,	/* Receive frame */
+	&llc_stat_dupaddr_state_trans_2,
+	&llc_stat_dupaddr_state_trans_3,
+	&llc_stat_state_trans_n
+};
+
+struct llc_station_state llc_station_state_table[LLC_NBR_STATION_STATES] = {
+	{ LLC_STATION_STATE_DOWN,	  llc_stat_dwn_state_trans },
+	{ LLC_STATION_STATE_DUP_ADDR_CHK, llc_stat_dupaddr_state_trans },
+	{ LLC_STATION_STATE_UP,		  llc_stat_up_state_trans }
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/llc/Makefile linux.20pre10-ac2/net/llc/Makefile
--- linux.20pre10/net/llc/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/net/llc/Makefile	2002-08-06 15:42:06.000000000 +0100
@@ -0,0 +1,38 @@
+###########################################################################
+# Makefile for the Linux 802.2 LLC (fully-functional) layer.
+#
+# Note 1! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+#
+# Copyright (c) 1997 by Procom Technology,Inc.
+#		2001 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.
+# This program is distributed without any warranty or implied warranty
+# of merchantability or fitness for a particular purpose.
+#
+# See the GNU General Public License for more details.
+###########################################################################
+
+O_TARGET := llc.o
+
+obj-y := llc_if.o llc_c_ev.o llc_c_ac.o llc_mac.o llc_sap.o llc_s_st.o \
+	 llc_main.o llc_s_ac.o llc_conn.o llc_c_st.o llc_stat.o llc_actn.o \
+	 llc_s_ev.o llc_evnt.o llc_pdu.o
+
+ifeq ($(CONFIG_LLC_UI),y)
+  obj-y += llc_sock.o
+endif
+
+# Objects that export symbols.
+export-objs := llc_if.o
+
+ifeq ($(CONFIG_LLC),m)
+  obj-m += $(O_TARGET)
+endif
+
+include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/Makefile linux.20pre10-ac2/net/Makefile
--- linux.20pre10/net/Makefile	2002-10-09 21:36:39.000000000 +0100
+++ linux.20pre10-ac2/net/Makefile	2002-08-06 15:41:56.000000000 +0100
@@ -7,7 +7,7 @@
 
 O_TARGET :=	network.o
 
-mod-subdirs :=	ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netlink sched core
+mod-subdirs :=	ipv4/netfilter ipv6/netfilter ipx irda bluetooth atm netlink sched llc core
 export-objs :=	netsyms.o
 
 subdir-y :=	core ethernet
@@ -45,7 +45,7 @@
 subdir-$(CONFIG_DECNET)		+= decnet
 subdir-$(CONFIG_ECONET)		+= econet
 subdir-$(CONFIG_VLAN_8021Q)           += 8021q
-
+subdir-$(CONFIG_LLC)		+= llc
 
 obj-y	:= socket.o $(join $(subdir-y), $(patsubst %,/%.o,$(notdir $(subdir-y))))
 ifeq ($(CONFIG_NET),y)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/netsyms.c linux.20pre10-ac2/net/netsyms.c
--- linux.20pre10/net/netsyms.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/net/netsyms.c	2002-10-09 21:53:09.000000000 +0100
@@ -82,7 +82,7 @@
 extern void destroy_8023_client(struct datalink_proto *);
 #endif
 
-#ifdef CONFIG_ATALK_MODULE
+#if defined(CONFIG_ATALK_MODULE) || defined(CONFIG_FILTER)
 #include <net/sock.h>
 #endif
 
@@ -461,6 +461,7 @@
 #endif  /* CONFIG_INET */
 
 #ifdef CONFIG_TR
+EXPORT_SYMBOL(tr_source_route);
 EXPORT_SYMBOL(tr_type_trans);
 #endif
 
@@ -479,6 +480,7 @@
 EXPORT_SYMBOL(__dev_get_by_index);
 EXPORT_SYMBOL(dev_get_by_name);
 EXPORT_SYMBOL(__dev_get_by_name);
+EXPORT_SYMBOL(dev_getbyhwaddr);
 EXPORT_SYMBOL(netdev_finish_unregister);
 EXPORT_SYMBOL(netdev_set_master);
 EXPORT_SYMBOL(eth_type_trans);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/net/sunrpc/xprt.c linux.20pre10-ac2/net/sunrpc/xprt.c
--- linux.20pre10/net/sunrpc/xprt.c	2002-10-09 21:44:50.000000000 +0100
+++ linux.20pre10-ac2/net/sunrpc/xprt.c	2002-10-09 21:53:15.000000000 +0100
@@ -949,8 +949,10 @@
 }
 
 /*
- * The following 2 routines allow a task to sleep while socket memory is
- * low.
+ * Called when more output buffer space is available for this socket.
+ * We try not to wake our writers until they can make "significant"
+ * progress, otherwise we'll waste resources thrashing sock_sendmsg
+ * with a bunch of small requests.
  */
 static void
 xprt_write_space(struct sock *sk)
@@ -964,8 +966,15 @@
 		return;
 
 	/* Wait until we have enough socket memory */
-	if (!sock_writeable(sk))
-		return;
+	if (xprt->stream) {
+		/* from net/ipv4/tcp.c:tcp_write_space */
+		if (tcp_wspace(sk) < tcp_min_write_space(sk))
+			return;
+	} else {
+		/* from net/core/sock.c:sock_def_write_space */
+		if (!sock_writeable(sk))
+			return;
+	}
 
 	if (!test_and_clear_bit(SOCK_NOSPACE, &sock->flags))
 		return;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/Rules.make linux.20pre10-ac2/Rules.make
--- linux.20pre10/Rules.make	2002-10-09 21:36:39.000000000 +0100
+++ linux.20pre10-ac2/Rules.make	2002-08-06 15:41:56.000000000 +0100
@@ -291,10 +291,6 @@
 include .depend
 endif
 
-ifneq ($(wildcard $(TOPDIR)/.hdepend),)
-include $(TOPDIR)/.hdepend
-endif
-
 #
 # Find files whose flags have changed and force recompilation.
 # For safety, this works in the converse direction:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/scripts/extract-ikconfig linux.20pre10-ac2/scripts/extract-ikconfig
--- linux.20pre10/scripts/extract-ikconfig	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/scripts/extract-ikconfig	2002-08-06 15:42:22.000000000 +0100
@@ -0,0 +1,17 @@
+#! /bin/bash -x
+# extracts .config info from a [b]zImage file
+# uses: binoffset (new), dd, zcat, strings, grep
+# $arg1 is [b]zImage filename
+
+HDR=`binoffset $1 0x1f 0x8b 0x08 0x0`
+PID=$$
+TMPFILE="$1.vmlin.$PID"
+
+# dd if=$1 bs=1 skip=$HDR | zcat - | strings /dev/stdin \
+# | grep "[A-Za-z_0-9]=[ynm]$" | sed "s/^/CONFIG_/" > $1.oldconfig.$PID
+# exit
+
+dd if=$1 bs=1 skip=$HDR | zcat - > $TMPFILE
+strings $TMPFILE | grep "^[\#[:blank:]]*CONFIG_[A-Za-z_0-9]*" > $1.oldconfig.$PID
+wc $1.oldconfig.$PID
+rm $TMPFILE
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/scripts/include_deps linux.20pre10-ac2/scripts/include_deps
--- linux.20pre10/scripts/include_deps	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/scripts/include_deps	2002-08-06 15:42:22.000000000 +0100
@@ -0,0 +1,15 @@
+# Read the .depend files, extract the dependencies for .h targets, convert
+# relative names to absolute and write the result to stdout.  It is part of
+# building the global .h dependency graph for kbuild 2.4.  KAO
+
+/^[^ 	]/		{ copy = 0; fn = "/error/"; }
+/^[^ 	][^ ]*\.h:/	{ copy = 1; fn = FILENAME; sub(/\.depend/, "", fn); }
+!copy			{ next; }
+			{
+			  indent = $0; sub(/[^ 	].*/, "", indent);
+			  if ($1 != "" && $1 !~ /^[@$\/\\]/) { $1 = fn $1 };
+			  if ($2 != "" && $2 !~ /^[@$\/\\]/) { $2 = fn $2 };
+			  $1 = $1;	# ensure $0 is rebuilt
+			  $0 = indent $0;
+			  print;
+			}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/scripts/mkconfigs.c linux.20pre10-ac2/scripts/mkconfigs.c
--- linux.20pre10/scripts/mkconfigs.c	1970-01-01 01:00:00.000000000 +0100
+++ linux.20pre10-ac2/scripts/mkconfigs.c	2002-08-06 15:42:22.000000000 +0100
@@ -0,0 +1,181 @@
+/***************************************************************************
+ * mkconfigs.c
+ * (C) 2002 Randy Dunlap <rddunlap@osdl.org>
+
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Rules for scripts/mkconfigs.c input.config output.c
+# to generate configs.c from linux/.config:
+# - drop lines that begin with '#'
+# - drop blank lines
+# - lines that use double-quotes must \\-escape-quote them
+
+################## skeleton configs.c file: ####################
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+static char *configs[] __initdata =
+
+  <insert lines selected lines of .config, quoted, with added '\n'>,
+
+;
+
+################### end configs.c file ######################
+
+ * Changelog for ver. 0.2, 2002-02-15, rddunlap@osdl.org:
+ - strip leading "CONFIG_" from config option strings;
+ - use "static" and "__attribute__((unused))";
+ - don't use EXPORT_SYMBOL();
+ - separate each config line with \newline instead of space;
+
+ * Changelog for ver. 0.3, 2002-02-18, rddunlap@osdl.org:
+ - keep all "not set" comment lines from .config so that 'make *config'
+   will be happy, but don't keep other comments;
+ - keep leading "CONFIG_" on each line;
+
+****************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define VERSION		"0.2"
+#define LINE_SIZE	1000
+
+int include_all_lines = 1;	// whether to include "=n" lines in the output
+
+void usage (const char *progname)
+{
+	fprintf (stderr, "%s ver. %s\n", progname, VERSION);
+	fprintf (stderr, "usage:  %s input.config.name path/configs.c\n",
+			progname);
+	exit (1);
+}
+
+void make_intro (FILE *sourcefile)
+{
+	fprintf (sourcefile, "#include <linux/init.h>\n");
+/////	fprintf (sourcefile, "#include <linux/module.h>\n");
+	fprintf (sourcefile, "\n");
+/////	fprintf (sourcefile, "char *configs[] __initdata = {\n");
+	fprintf (sourcefile, "static char __attribute__ ((unused)) *configs[] __initdata = {\n");
+	fprintf (sourcefile, "  \"CONFIG_BEGIN=n\\n\" ,\n");
+}
+
+void make_ending (FILE *sourcefile)
+{
+	fprintf (sourcefile, "  \"CONFIG_END=n\\n\"\n");
+	fprintf (sourcefile, "};\n");
+/////	fprintf (sourcefile, "EXPORT_SYMBOL (configs);\n");
+}
+
+void make_lines (FILE *configfile, FILE *sourcefile)
+{
+	char cfgline[LINE_SIZE];
+	char *ch;
+
+	while (fgets (cfgline, LINE_SIZE, configfile)) {
+		/* kill the trailing newline in cfgline */
+		cfgline[strlen (cfgline) - 1] = '\0';
+
+		/* don't keep #-only line or an empty/blank line */
+		if ((cfgline[0] == '#' && cfgline[1] == '\0') ||
+		    cfgline[0] == '\0')
+			continue;
+
+		if (!include_all_lines &&
+		    cfgline[0] == '#') // strip out all comment lines
+			continue;
+
+		/* really only want to keep lines that begin with
+		 * "CONFIG_" or "# CONFIG_" */
+		if (strncmp (cfgline, "CONFIG_", 7) &&
+		    strncmp (cfgline, "# CONFIG_", 9))
+		    	continue;
+
+		/*
+		 * use strchr() to check for "-quote in cfgline;
+		 * if not found, output the line, quoted;
+		 * if found, output a char at a time, with \\-quote
+		 * preceding double-quote chars
+		 */
+		if (!strchr (cfgline, '"')) {
+			fprintf (sourcefile, "  \"%s\\n\" ,\n", cfgline);
+			continue;
+		}
+
+		/* go to char-at-a-time mode for this config and
+		 * precede any double-quote with a backslash */
+		fprintf (sourcefile, "  \"");	/* lead-in */
+		for (ch = cfgline; *ch; ch++) {
+			if (*ch == '"')
+				fputc ('\\', sourcefile);
+			fputc (*ch, sourcefile);
+		}
+		fprintf (sourcefile, "\\n\" ,\n");
+	}
+}
+
+int make_configs (FILE *configfile, FILE *sourcefile)
+{
+	make_intro (sourcefile);
+	make_lines (configfile, sourcefile);
+	make_ending (sourcefile);
+}
+
+int main (int argc, char *argv[])
+{
+	char *progname = argv[0];
+	char *configname, *sourcename;
+	FILE *configfile, *sourcefile;
+
+	if (argc != 3)
+		usage (progname);
+
+	configname = argv[1];
+	sourcename = argv[2];
+
+	configfile = fopen (configname, "r");
+	if (!configfile) {
+		fprintf (stderr, "%s: cannot open '%s'\n",
+				progname, configname);
+		exit (2);
+	}
+	sourcefile = fopen (sourcename, "w");
+	if (!sourcefile) {
+		fprintf (stderr, "%s: cannot open '%s'\n",
+				progname, sourcename);
+		exit (2);
+	}
+
+	make_configs (configfile, sourcefile);
+
+	if (fclose (sourcefile)) {
+		fprintf (stderr, "%s: error %d closing '%s'\n",
+				progname, errno, sourcename);
+		exit (3);
+	}
+	if (fclose (configfile)) {
+		fprintf (stderr, "%s: error %d closing '%s'\n",
+				progname, errno, configname);
+		exit (3);
+	}
+
+	exit (0);
+}
+
+/* end mkconfigs.c */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/scripts/mkdep.c linux.20pre10-ac2/scripts/mkdep.c
--- linux.20pre10/scripts/mkdep.c	2002-10-09 21:37:04.000000000 +0100
+++ linux.20pre10-ac2/scripts/mkdep.c	2002-08-06 15:42:22.000000000 +0100
@@ -48,6 +48,8 @@
 char __depname[512] = "\n\t@touch ";
 #define depname (__depname+9)
 int hasdep;
+char cwd[PATH_MAX];
+int lcwd;
 
 struct path_struct {
 	int len;
@@ -202,8 +204,22 @@
 		memcpy(path->buffer+path->len, name, len);
 		path->buffer[path->len+len] = '\0';
 		if (access(path->buffer, F_OK) == 0) {
+			int l = lcwd + strlen(path->buffer);
+			char name2[l+2], *p;
+			if (path->buffer[0] == '/') {
+				memcpy(name2, path->buffer, l+1);
+			}
+			else {
+				memcpy(name2, cwd, lcwd);
+				name2[lcwd] = '/';
+				memcpy(name2+lcwd+1, path->buffer, path->len+len+1);
+			}
+			while ((p = strstr(name2, "/../"))) {
+				*p = '\0';
+				strcpy(strrchr(name2, '/'), p+3);
+			}
 			do_depname();
-			printf(" \\\n   %s", path->buffer);
+			printf(" \\\n   %s", name2);
 			return;
 		}
 	}
@@ -585,6 +601,12 @@
 		return 1;
 	}
 
+	if (!getcwd(cwd, sizeof(cwd))) {
+		fprintf(stderr, "mkdep: getcwd() failed %m\n");
+		return 1;
+	}
+	lcwd = strlen(cwd);
+
 	add_path(".");		/* for #include "..." */
 
 	while (++argv, --argc > 0) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/scripts/tkgen.c linux.20pre10-ac2/scripts/tkgen.c
--- linux.20pre10/scripts/tkgen.c	2002-10-09 21:37:04.000000000 +0100
+++ linux.20pre10-ac2/scripts/tkgen.c	2002-08-06 15:42:22.000000000 +0100
@@ -625,6 +625,7 @@
 		if ( ! vartable[i].global_written )
 		{
 		    global( vartable[i].name );
+                    vartable[i].global_written = 1;
 		}
 		printf( "\t" );
 	    }
@@ -699,6 +700,19 @@
     }
 
     /*
+     * Generate global declarations for the dependency chain (e.g. CONSTANT_M).
+     */
+    for ( tmp = cfg->depend; tmp; tmp = tmp->next )
+    {
+        int i = get_varnum( tmp->name );
+	if ( ! vartable[i].global_written )
+	{
+	    global( vartable[i].name );
+	    vartable[i].global_written = 1;
+	}
+    }
+
+    /*
      * Generate indentation.
      */
 	printf( "\t" );
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.20pre10/scripts/ver_linux linux.20pre10-ac2/scripts/ver_linux
--- linux.20pre10/scripts/ver_linux	2002-10-09 21:37:04.000000000 +0100
+++ linux.20pre10-ac2/scripts/ver_linux	2002-09-05 12:57:18.000000000 +0100
@@ -4,7 +4,7 @@
 # /bin /sbin /usr/bin /usr/sbin /usr/local/bin, but it may
 # differ on your system.
 #
-PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH
+PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:$PATH
 echo 'If some fields are empty or look unusual you may have an old version.'
 echo 'Compare to the current minimal requirements in Documentation/Changes.'
 echo ' '
@@ -12,7 +12,11 @@
 uname -a
 echo ' '
 
-echo "Gnu C                 " `gcc --version`
+gcc --version 2>&1| head -n 1 | grep -v gcc | awk \
+'NR==1{print "Gnu C                 ", $1}'
+
+gcc --version 2>&1| grep gcc | awk \
+'NR==1{print "Gnu C                 ", $3}'
 
 make --version 2>&1 | awk -F, '{print $1}' | awk \
       '/GNU Make/{print "Gnu make              ",$NF}'
@@ -29,7 +33,10 @@
 tune2fs 2>&1 | grep "^tune2fs" | sed 's/,//' |  awk \
 'NR==1 {print "e2fsprogs             ", $2}'
 
-reiserfsck 2>&1 | grep reiserfsprogs | awk \
+fsck.jfs -V 2>&1 | grep version | sed 's/,//' |  awk \
+'NR==1 {print "jfsutils              ", $3}'
+
+reiserfsck -V 2>&1 | grep reiserfsprogs | awk \
 'NR==1{print "reiserfsprogs         ", $NF}'
 
 cardmgr -V 2>&1| grep version | awk \
