diff -Naur linux-2.4.19.orig/Documentation/Configure.help linux-2.4.19.lkcd/Documentation/Configure.help
--- linux-2.4.19.orig/Documentation/Configure.help	Sat Aug  3 05:39:42 2002
+++ linux-2.4.19.lkcd/Documentation/Configure.help	Tue Nov 19 13:49:50 2002
@@ -3813,6 +3813,13 @@
   Not necessary unless you're using a very out-of-date binutils
   version.  You probably want KCORE_ELF.
 
+Kernel crash dumps (version 2)
+CONFIG_DUMP
+  This creates a dump driver suitable for dumping system memory on
+  system failure to an appropriate dump device.  Use a dump utility
+  program to open up /dev/dump to perform dump configuration.
+  More information about dumping is at http://lkcd.sourceforge.net/.
+
 Kernel support for ELF binaries
 CONFIG_BINFMT_ELF
   ELF (Executable and Linkable Format) is a format for libraries and
diff -Naur linux-2.4.19.orig/Makefile linux-2.4.19.lkcd/Makefile
--- linux-2.4.19.orig/Makefile	Sat Aug  3 05:39:46 2002
+++ linux-2.4.19.lkcd/Makefile	Tue Nov 19 13:49:50 2002
@@ -153,6 +153,7 @@
 DRIVERS-$(CONFIG_FC4) += drivers/fc4/fc4.a
 DRIVERS-$(CONFIG_SCSI) += drivers/scsi/scsidrv.o
 DRIVERS-$(CONFIG_FUSION_BOOT) += drivers/message/fusion/fusion.o
+DRIVERS-$(CONFIG_DUMP) += drivers/dump/dumpdrv.o
 DRIVERS-$(CONFIG_IEEE1394) += drivers/ieee1394/ieee1394drv.o
 
 ifneq ($(CONFIG_CD_NO_IDESCSI)$(CONFIG_BLK_DEV_IDECD)$(CONFIG_BLK_DEV_SR)$(CONFIG_PARIDE_PCD),)
@@ -276,7 +277,7 @@
 boot: vmlinux
 	@$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" -C arch/$(ARCH)/boot
 
-vmlinux: include/linux/version.h $(CONFIGURATION) init/main.o init/version.o init/do_mounts.o linuxsubdirs
+vmlinux: include/linux/version.h $(CONFIGURATION) init/main.o init/version.o init/do_mounts.o Kerntypes linuxsubdirs
 	$(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o init/do_mounts.o \
 		--start-group \
 		$(CORE_FILES) \
@@ -287,6 +288,11 @@
 		-o vmlinux
 	$(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
 
+Kerntypes: init/kerntypes.o
+	@if [ -f init/kerntypes.o ]; then \
+		mv init/kerntypes.o Kerntypes; \
+	fi
+
 symlinks:
 	rm -f include/asm
 	( cd include ; ln -sf asm-$(ARCH) asm)
@@ -354,6 +360,9 @@
 
 comma	:= ,
 
+init/kerntypes.o: init/kerntypes.c include/config/MARKER
+	$(CC) $(CFLAGS) $(CFLAGS_KERNEL) $(PROFILING) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -gstabs -c -o $@ $<
+
 init/version.o: init/version.c include/linux/compile.h include/config/MARKER
 	$(CC) $(CFLAGS) $(CFLAGS_KERNEL) -DUTS_MACHINE='"$(ARCH)"' -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) -c -o init/version.o init/version.c
 
diff -Naur linux-2.4.19.orig/arch/alpha/config.in linux-2.4.19.lkcd/arch/alpha/config.in
--- linux-2.4.19.orig/arch/alpha/config.in	Sat Aug  3 05:39:42 2002
+++ linux-2.4.19.lkcd/arch/alpha/config.in	Tue Nov 19 13:49:50 2002
@@ -410,6 +410,16 @@
 
 bool 'Legacy kernel start address' CONFIG_ALPHA_LEGACY_START_ADDRESS
 
+tristate 'Linux Kernel Crash Dump (LKCD) Support' CONFIG_DUMP
+if [ "$CONFIG_DUMP" = "y" ]; then
+   dep_bool '  LKCD RLE compression' CONFIG_DUMP_COMPRESS_RLE $CONFIG_DUMP
+   dep_bool '  LKCD GZIP compression' CONFIG_DUMP_COMPRESS_GZIP $CONFIG_DUMP
+fi
+if [ "$CONFIG_DUMP" = "m" ]; then
+   dep_tristate '  LKCD RLE compression' CONFIG_DUMP_COMPRESS_RLE $CONFIG_DUMP
+   dep_tristate '  LKCD GZIP compression' CONFIG_DUMP_COMPRESS_GZIP $CONFIG_DUMP
+fi
+
 bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
 if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
    tristate '  Kernel FP software completion' CONFIG_MATHEMU
diff -Naur linux-2.4.19.orig/arch/alpha/kernel/setup.c linux-2.4.19.lkcd/arch/alpha/kernel/setup.c
--- linux-2.4.19.orig/arch/alpha/kernel/setup.c	Sat Aug  3 05:39:42 2002
+++ linux-2.4.19.lkcd/arch/alpha/kernel/setup.c	Tue Nov 19 13:49:50 2002
@@ -387,7 +387,11 @@
 extern void setup_memory(void *);
 #endif /* !CONFIG_DISCONTIGMEM */
 
+#ifndef CONFIG_DUMP
 int __init
+#else
+int
+#endif
 page_is_ram(unsigned long pfn)
 {
 	struct memclust_struct * cluster;
diff -Naur linux-2.4.19.orig/arch/alpha/kernel/traps.c linux-2.4.19.lkcd/arch/alpha/kernel/traps.c
--- linux-2.4.19.orig/arch/alpha/kernel/traps.c	Wed Nov 21 04:49:31 2001
+++ linux-2.4.19.lkcd/arch/alpha/kernel/traps.c	Tue Nov 19 13:49:50 2002
@@ -14,6 +14,7 @@
 #include <linux/tty.h>
 #include <linux/delay.h>
 #include <linux/smp_lock.h>
+#include <linux/dump.h>
 
 #include <asm/gentrap.h>
 #include <asm/uaccess.h>
@@ -186,6 +187,7 @@
 		while (1);
 	}
 	current->thread.flags |= (1UL << 63);
+	dump((char *)str, regs);
 	do_exit(SIGSEGV);
 }
 
diff -Naur linux-2.4.19.orig/arch/i386/boot/Makefile linux-2.4.19.lkcd/arch/i386/boot/Makefile
--- linux-2.4.19.orig/arch/i386/boot/Makefile	Mon Aug  6 01:13:19 2001
+++ linux-2.4.19.lkcd/arch/i386/boot/Makefile	Tue Nov 19 13:49:50 2002
@@ -32,12 +32,14 @@
 zlilo: $(CONFIGURE) $(BOOTIMAGE)
 	if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
 	if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
+	if [ -f $(INSTALL_PATH)/Kerntypes ]; then mv $(INSTALL_PATH)/Kerntypes $(INSTALL_PATH)/Kerntypes.old; fi
 	cat $(BOOTIMAGE) > $(INSTALL_PATH)/vmlinuz
 	cp $(TOPDIR)/System.map $(INSTALL_PATH)/
+	cp $(TOPDIR)/Kerntypes $(INSTALL_PATH)/
 	if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
 
 install: $(CONFIGURE) $(BOOTIMAGE)
-	sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map "$(INSTALL_PATH)"
+	sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map $(TOPDIR)/Kerntypes "$(INSTALL_PATH)"
 
 tools/build: tools/build.c
 	$(HOSTCC) $(HOSTCFLAGS) -o $@ $< -I$(TOPDIR)/include
diff -Naur linux-2.4.19.orig/arch/i386/boot/install.sh linux-2.4.19.lkcd/arch/i386/boot/install.sh
--- linux-2.4.19.orig/arch/i386/boot/install.sh	Sat Sep 15 02:04:06 2001
+++ linux-2.4.19.lkcd/arch/i386/boot/install.sh	Tue Nov 19 13:49:50 2002
@@ -16,7 +16,8 @@
 #   $1 - kernel version
 #   $2 - kernel image file
 #   $3 - kernel map file
-#   $4 - default install path (blank if root directory)
+#   $4 - kernel type file
+#   $5 - default install path (blank if root directory)
 #
 
 # User may have a custom install script
@@ -26,15 +27,20 @@
 
 # Default install - same as make zlilo
 
-if [ -f $4/vmlinuz ]; then
-	mv $4/vmlinuz $4/vmlinuz.old
+if [ -f $5/vmlinuz ]; then
+	mv $5/vmlinuz $5/vmlinuz.old
 fi
 
-if [ -f $4/System.map ]; then
-	mv $4/System.map $4/System.old
+if [ -f $5/System.map ]; then
+	mv $5/System.map $5/System.old
 fi
 
-cat $2 > $4/vmlinuz
-cp $3 $4/System.map
+if [ -f $5/Kerntypes ]; then
+	mv $5/Kerntypes $5/Kerntypes.old
+fi
+
+cat $2 > $5/vmlinuz
+cp $3 $5/System.map
+cp $4 $5/Kerntypes
 
 if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
diff -Naur linux-2.4.19.orig/arch/i386/config.in linux-2.4.19.lkcd/arch/i386/config.in
--- linux-2.4.19.orig/arch/i386/config.in	Sat Aug  3 05:39:42 2002
+++ linux-2.4.19.lkcd/arch/i386/config.in	Tue Nov 19 13:49:50 2002
@@ -415,6 +415,16 @@
 mainmenu_option next_comment
 comment 'Kernel hacking'
 
+tristate 'Linux Kernel Crash Dump (LKCD) Support' CONFIG_DUMP
+if [ "$CONFIG_DUMP" = "y" ]; then
+   dep_bool '  LKCD RLE compression' CONFIG_DUMP_COMPRESS_RLE $CONFIG_DUMP
+   dep_bool '  LKCD GZIP compression' CONFIG_DUMP_COMPRESS_GZIP $CONFIG_DUMP
+fi
+if [ "$CONFIG_DUMP" = "m" ]; then
+   dep_tristate '  LKCD RLE compression' CONFIG_DUMP_COMPRESS_RLE $CONFIG_DUMP
+   dep_tristate '  LKCD GZIP compression' CONFIG_DUMP_COMPRESS_GZIP $CONFIG_DUMP
+fi
+
 bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
 if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
    bool '  Debug high memory support' CONFIG_DEBUG_HIGHMEM
diff -Naur linux-2.4.19.orig/arch/i386/kernel/i386_ksyms.c linux-2.4.19.lkcd/arch/i386/kernel/i386_ksyms.c
--- linux-2.4.19.orig/arch/i386/kernel/i386_ksyms.c	Sat Aug  3 05:39:42 2002
+++ linux-2.4.19.lkcd/arch/i386/kernel/i386_ksyms.c	Tue Nov 19 13:49:50 2002
@@ -14,6 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/tty.h>
+#include <linux/highmem.h>
 
 #include <asm/semaphore.h>
 #include <asm/processor.h>
@@ -162,6 +163,27 @@
 
 EXPORT_SYMBOL(rtc_lock);
 
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+#ifdef CONFIG_SMP
+extern irq_desc_t irq_desc[];
+extern unsigned long irq_affinity[];
+EXPORT_SYMBOL(irq_affinity);
+EXPORT_SYMBOL(irq_desc);
+extern void dump_send_ipi(void);
+EXPORT_SYMBOL(dump_send_ipi);
+extern int (*dump_ipi_function_ptr)(struct pt_regs *);
+EXPORT_SYMBOL(dump_ipi_function_ptr);
+extern void (*dump_trace_ptr)(struct pt_regs *);
+EXPORT_SYMBOL(dump_trace_ptr);
+extern void show_this_cpu_state(int, struct pt_regs *, struct task_struct *);
+EXPORT_SYMBOL(show_this_cpu_state);
+#endif
+#ifdef CONFIG_HIGHMEM
+EXPORT_SYMBOL(kmap_prot);
+EXPORT_SYMBOL(kmap_pte);
+#endif
+#endif
+
 #undef memcpy
 #undef memset
 extern void * memset(void *,int,__kernel_size_t);
diff -Naur linux-2.4.19.orig/arch/i386/kernel/irq.c linux-2.4.19.lkcd/arch/i386/kernel/irq.c
--- linux-2.4.19.orig/arch/i386/kernel/irq.c	Fri Oct 26 01:53:46 2001
+++ linux-2.4.19.lkcd/arch/i386/kernel/irq.c	Tue Nov 19 13:49:50 2002
@@ -1076,7 +1076,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 -Naur linux-2.4.19.orig/arch/i386/kernel/nmi.c linux-2.4.19.lkcd/arch/i386/kernel/nmi.c
--- linux-2.4.19.orig/arch/i386/kernel/nmi.c	Sat Aug  3 05:39:42 2002
+++ linux-2.4.19.lkcd/arch/i386/kernel/nmi.c	Tue Nov 19 13:49:50 2002
@@ -18,6 +18,7 @@
 #include <linux/bootmem.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
+#include <linux/dump.h>
 #include <linux/mc146818rtc.h>
 #include <linux/kernel_stat.h>
 
@@ -343,6 +344,14 @@
 	 */
 	int sum, cpu = smp_processor_id();
 
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+	/*
+	 * Ignore watchdog when dumping is in progress.
+	 * Todo: consider using the touch_nmi_watchdog() approach instead
+	 */
+	if (dump_in_progress && cpu != dumping_cpu) return;
+#endif
+
 	sum = apic_timer_irqs[cpu];
 
 	if (last_irq_sums[cpu] == sum) {
@@ -361,6 +370,7 @@
 			printk("NMI Watchdog detected LOCKUP on CPU%d, eip %08lx, registers:\n", cpu, regs->eip);
 			show_registers(regs);
 			printk("console shuts up ...\n");
+			dump("NMI Watchdog Detected", regs);
 			console_silent();
 			spin_unlock(&nmi_print_lock);
 			bust_spinlocks(0);
diff -Naur linux-2.4.19.orig/arch/i386/kernel/smp.c linux-2.4.19.lkcd/arch/i386/kernel/smp.c
--- linux-2.4.19.orig/arch/i386/kernel/smp.c	Sat Aug  3 05:39:42 2002
+++ linux-2.4.19.lkcd/arch/i386/kernel/smp.c	Tue Nov 19 13:49:50 2002
@@ -18,6 +18,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/mc146818rtc.h>
 #include <linux/cache.h>
+#include <linux/dump.h>
 
 #include <asm/mtrr.h>
 #include <asm/pgalloc.h>
@@ -144,6 +145,15 @@
 	 */
 	cfg = __prepare_ICR(shortcut, vector);
 
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+	if (vector == DUMP_VECTOR) {
+		/*
+		 * Setup DUMP IPI to be delivered as an NMI
+		 */
+		cfg = (cfg&~APIC_VECTOR_MASK)|APIC_DM_NMI;
+	}
+#endif	/* CONFIG_DUMP */
+
 	/*
 	 * Send the IPI. The write to APIC_ICR fires this off.
 	 */
@@ -386,6 +396,11 @@
 static void flush_tlb_others (unsigned long cpumask, struct mm_struct *mm,
 						unsigned long va)
 {
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+	/* some cpu may not be running... LWS */
+	unsigned long ipi_mask;
+#endif
+
 	/*
 	 * A couple of (to be removed) sanity checks:
 	 *
@@ -395,8 +410,14 @@
 	 */
 	if (!cpumask)
 		BUG();
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+	/* Some cpus may be stopped...like at crash dump time... LWS */
+	if ((ipi_mask = cpumask & cpu_online_map) == 0)
+		return;
+#else
 	if ((cpumask & cpu_online_map) != cpumask)
 		BUG();
+#endif
 	if (cpumask & (1 << smp_processor_id()))
 		BUG();
 	if (!mm)
@@ -412,12 +433,20 @@
 	
 	flush_mm = mm;
 	flush_va = va;
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+	atomic_set_mask(ipi_mask, &flush_cpumask);
+#else
 	atomic_set_mask(cpumask, &flush_cpumask);
+#endif
 	/*
 	 * We have to send the IPI only to
 	 * CPUs affected.
 	 */
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+	send_IPI_mask(ipi_mask, INVALIDATE_TLB_VECTOR);
+#else
 	send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR);
+#endif
 
 	while (flush_cpumask)
 		/* nothing. lockup detection does not belong here */;
@@ -488,6 +517,13 @@
 	do_flush_tlb_all_local();
 }
 
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+void dump_send_ipi(void)
+{
+	send_IPI_allbutself(DUMP_VECTOR);
+}
+#endif	
+
 /*
  * this function sends a 'reschedule' IPI to another CPU.
  * it goes straight through and wastes no time serializing
@@ -496,7 +532,15 @@
 
 void smp_send_reschedule(int cpu)
 {
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+	/* only do this for on-line CPUs */
+	unsigned long cpumask = (1 << cpu) & cpu_online_map;
+	if (cpumask) {
+		send_IPI_mask(1 << cpu, RESCHEDULE_VECTOR);
+	}
+#else
 	send_IPI_mask(1 << cpu, RESCHEDULE_VECTOR);
+#endif
 }
 
 /*
@@ -555,8 +599,25 @@
 	send_IPI_allbutself(CALL_FUNCTION_VECTOR);
 
 	/* Wait for response */
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+	if (dump_in_progress) {
+		int i = 1 * 1000;	/* milliseconds to delay waiting for other CPU to start IPI processing (1 second) */
+		while (atomic_read(&data.started) != cpus && i--) {
+			mdelay(1);
+			barrier();
+		}
+		if (i <= 0) {
+			spin_unlock_bh(&call_lock);
+			return -ETIMEDOUT;
+		}
+	} else {
+		while (atomic_read(&data.started) != cpus)
+			barrier();
+	}
+#else
 	while (atomic_read(&data.started) != cpus)
 		barrier();
+#endif
 
 	if (wait)
 		while (atomic_read(&data.finished) != cpus)
diff -Naur linux-2.4.19.orig/arch/i386/kernel/smpboot.c linux-2.4.19.lkcd/arch/i386/kernel/smpboot.c
--- linux-2.4.19.orig/arch/i386/kernel/smpboot.c	Sat Aug  3 05:39:42 2002
+++ linux-2.4.19.lkcd/arch/i386/kernel/smpboot.c	Tue Nov 19 13:49:50 2002
@@ -61,7 +61,11 @@
 int __initdata phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */
 
 /* Bitmask of currently online CPUs */
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+volatile unsigned long cpu_online_map;
+#else
 unsigned long cpu_online_map;
+#endif
 
 static volatile unsigned long cpu_callin_map;
 static volatile unsigned long cpu_callout_map;
diff -Naur linux-2.4.19.orig/arch/i386/kernel/traps.c linux-2.4.19.lkcd/arch/i386/kernel/traps.c
--- linux-2.4.19.orig/arch/i386/kernel/traps.c	Sat Aug  3 05:39:42 2002
+++ linux-2.4.19.lkcd/arch/i386/kernel/traps.c	Tue Nov 19 13:49:50 2002
@@ -19,6 +19,7 @@
 #include <linux/ptrace.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
+#include <linux/dump.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
@@ -88,6 +89,108 @@
 int kstack_depth_to_print = 24;
 
 
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+#ifdef CONFIG_SMP
+void (*dump_trace_ptr)(struct pt_regs *) = NULL;
+/* 
+ * This code mimics show_trace() etc in arch/i386/kernel/traps.c. We don't 
+ * use them directly as they depend on 8K aligned kernel stacks that our
+ * saved stacks don't satisfy. However, there is move to relax the requirement
+ * on task_struct to be 8K-aligned. Once that happens, we could simpify this
+ * function.
+ */
+void show_this_cpu_state(int cpu, struct pt_regs * regs, struct task_struct *tsk)
+{
+	int i;
+	unsigned long *esp;
+	unsigned char *c;
+	int in_kernel = 1;
+
+	esp = (unsigned long *)regs->esp;
+	c = (unsigned char *)regs->eip;
+
+	if (regs->xcs & 3) {
+		in_kernel = 0;
+	}
+	printk("CPU:    %d\nEIP:    %04x:[<%08lx>]\nEFLAGS: %08lx\n",
+		cpu, 0xffff & regs->xcs, regs->eip, regs->eflags);
+	printk("eax: %08lx   ebx: %08lx   ecx: %08lx   edx: %08lx\n",
+		regs->eax, regs->ebx, regs->ecx, regs->edx);
+	printk("esi: %08lx   edi: %08lx   ebp: %08lx   esp: %p\n",
+		regs->esi, regs->edi, regs->ebp, esp);
+	printk("ds: %04x   es: %04x   ss: %04x\n",
+		regs->xds & 0xffff, regs->xes & 0xffff, regs->xss & 0xffff);
+	if (!tsk) {
+		printk("no stack for this cpu\n");
+		return;
+	}
+	printk("Process %s (pid: %d, stackpage=%08lx)",
+		tsk->comm, tsk->pid, 4096+(regs->esp & ~(THREAD_SIZE-1)));
+	/*
+	 * When in-kernel, we also print out the stack and code at the
+	 * time of the fault..
+	 */
+	if (in_kernel) {
+		unsigned long *stack;
+		unsigned long addr, module_start, module_end;
+		extern char _stext, _etext;
+
+		extern int kstack_depth_to_print;
+
+		esp = (unsigned long *)((unsigned long)tsk + (regs->esp & (THREAD_SIZE-1)));
+
+		printk("\nStack: ");
+		stack = esp;
+		for(i=0; i < kstack_depth_to_print; i++) {
+			if ((unsigned long)stack > (unsigned long)tsk + THREAD_SIZE-1)
+				break;
+			if (i && ((i % 8) == 0))
+				printk("\n       ");
+			printk("%08lx ", *stack++);
+		}
+		
+		printk("\nCall Trace: ");
+		i = 1;
+		stack = esp;
+		module_start = VMALLOC_START;
+		module_end = VMALLOC_END;
+		module_end = 0;
+		while ((unsigned long)stack < (unsigned long)tsk + THREAD_SIZE) {
+			addr = *stack++;
+			/*
+			 * If the address is either in the text segment of the
+			 * kernel, or in the region which contains vmalloc'ed
+			 * memory, it *may* be the address of a calling
+			 * routine; if so, print it so that someone tracing
+			 * down the cause of the crash will be able to figure
+			 * out the call path that was taken.
+			 */
+			if (((addr >= (unsigned long) &_stext) &&
+			     (addr <= (unsigned long) &_etext)) ||
+			    ((addr >= module_start) && (addr <= module_end))) {
+				if (i && ((i % 8) == 0))
+					printk("\n       ");
+				printk("[<%08lx>] ", addr);
+				i++;
+			}
+		}
+		printk("\n");
+
+		printk("\nCode: ");
+		if(regs->eip < PAGE_OFFSET) {
+			printk("eip in user space. error.\n");
+		}
+
+		for(i=0;i<20;i++) {
+			printk("%02x ", *c++);
+		}
+	}
+	printk("\n");
+	return;
+}	
+#endif /* CONFIG_SMP */
+#endif /* CONFIG_DUMP */
+
 /*
  * If the address is either in the .text section of the
  * kernel, or in the vmalloc'ed module regions, it *may* 
@@ -282,6 +385,7 @@
 	handle_BUG(regs);
 	printk("%s: %04lx\n", str, err & 0xffff);
 	show_registers(regs);
+	dump((char *)str, regs);
 	bust_spinlocks(0);
 	spin_unlock_irq(&die_lock);
 	do_exit(SIGSEGV);
@@ -439,6 +543,23 @@
 	outb(reason, 0x61);
 }
 
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+#ifdef CONFIG_SMP
+int (*dump_ipi_function_ptr)(struct pt_regs *) = NULL;
+static int dump_ipi(struct pt_regs *regs)
+{
+	if (!(dump_ipi_function_ptr && dump_ipi_function_ptr(regs))) {
+		return 0;
+	}
+	ack_APIC_irq();
+	return 1;
+}
+#else
+#define dump_ipi(regs) 0
+#endif
+#endif
+
+
 static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
 {
 #ifdef CONFIG_MCA
@@ -460,6 +581,12 @@
 
 	++nmi_count(smp_processor_id());
 
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+        if (dump_ipi(regs)) {
+                return;
+        }
+#endif
+
 	if (!(reason & 0xc0)) {
 #if CONFIG_X86_LOCAL_APIC
 		/*
diff -Naur linux-2.4.19.orig/arch/i386/mm/init.c linux-2.4.19.lkcd/arch/i386/mm/init.c
--- linux-2.4.19.orig/arch/i386/mm/init.c	Sat Aug  3 05:39:42 2002
+++ linux-2.4.19.lkcd/arch/i386/mm/init.c	Tue Nov 19 13:49:50 2002
@@ -415,7 +415,11 @@
 	}
 }
 
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+int page_is_ram (unsigned long pagenr)
+#else
 static inline int page_is_ram (unsigned long pagenr)
+#endif
 {
 	int i;
 
diff -Naur linux-2.4.19.orig/arch/ia64/config.in linux-2.4.19.lkcd/arch/ia64/config.in
--- linux-2.4.19.orig/arch/ia64/config.in	Sat Aug  3 05:39:42 2002
+++ linux-2.4.19.lkcd/arch/ia64/config.in	Tue Nov 19 13:49:50 2002
@@ -265,6 +265,16 @@
 	"16MB			CONFIG_IA64_GRANULE_16MB	\
 	 64MB			CONFIG_IA64_GRANULE_64MB" 64MB
 
+tristate 'Linux Kernel Crash Dump (LKCD) Support' CONFIG_DUMP
+if [ "$CONFIG_DUMP" = "y" ]; then
+   dep_bool '  LKCD RLE compression' CONFIG_DUMP_COMPRESS_RLE $CONFIG_DUMP
+   dep_bool '  LKCD GZIP compression' CONFIG_DUMP_COMPRESS_GZIP $CONFIG_DUMP
+fi
+if [ "$CONFIG_DUMP" = "m" ]; then
+   dep_tristate '  LKCD RLE compression' CONFIG_DUMP_COMPRESS_RLE $CONFIG_DUMP
+   dep_tristate '  LKCD GZIP compression' CONFIG_DUMP_COMPRESS_GZIP $CONFIG_DUMP
+fi
+
 bool 'Kernel debugging' CONFIG_DEBUG_KERNEL
 if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
    bool '  Print possible IA64 hazards to console' CONFIG_IA64_PRINT_HAZARDS
diff -Naur linux-2.4.19.orig/arch/ia64/kernel/irq.c linux-2.4.19.lkcd/arch/ia64/kernel/irq.c
--- linux-2.4.19.orig/arch/ia64/kernel/irq.c	Sat Aug  3 05:39:42 2002
+++ linux-2.4.19.lkcd/arch/ia64/kernel/irq.c	Tue Nov 19 13:49:50 2002
@@ -1094,7 +1094,11 @@
 
 static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
 
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
+#else
 static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
+#endif
 static char irq_redir [NR_IRQS]; // = { [0 ... NR_IRQS-1] = 1 };
 
 void set_irq_affinity_info(int irq, int hwid, int redir)
diff -Naur linux-2.4.19.orig/arch/ia64/kernel/smp.c linux-2.4.19.lkcd/arch/ia64/kernel/smp.c
--- linux-2.4.19.orig/arch/ia64/kernel/smp.c	Fri Dec 21 22:41:53 2001
+++ linux-2.4.19.lkcd/arch/ia64/kernel/smp.c	Tue Nov 19 13:49:50 2002
@@ -73,6 +73,11 @@
 #define IPI_CALL_FUNC		0
 #define IPI_CPU_STOP		1
 
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+#define IPI_DUMP_INTERRUPT      4
+int (*dump_ipi_function_ptr)(struct pt_regs *) = NULL;
+#endif
+
 static void
 stop_this_cpu (void)
 {
@@ -136,6 +141,17 @@
 			stop_this_cpu();
 			break;
 
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+		case IPI_DUMP_INTERRUPT:
+			if( dump_ipi_function_ptr != NULL ) {
+				if (!dump_ipi_function_ptr(regs)) {
+					 printk(KERN_ERR "(*dump_ipi_function_ptr)(): rejected IPI_DUMP_INTERRUPT\n");
+				}
+			}
+			break;
+#endif
+		
+
 		default:
 			printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which);
 			break;
@@ -284,8 +300,25 @@
 	send_IPI_allbutself(IPI_CALL_FUNC);
 
 	/* Wait for response */
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+	if (dump_in_progress) {
+		int i = 1 * 1000;	/* milliseconds to delay waiting for other CPU to start IPI processing (1 second) */
+		while (atomic_read(&data.started) != cpus && i--) {
+			mdelay(1);
+			barrier();
+		}
+		if (i <= 0) {
+			spin_unlock_bh(&call_lock);
+			return -ETIMEDOUT;
+		}
+	} else {
+		while (atomic_read(&data.started) != cpus)
+			barrier();
+	}
+#else
 	while (atomic_read(&data.started) != cpus)
 		barrier();
+#endif
 
 	if (wait)
 		while (atomic_read(&data.finished) != cpus)
@@ -322,3 +355,10 @@
 {
 	return -EINVAL;
 }
+
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+void dump_send_ipi(void)
+{
+	send_IPI_allbutself(IPI_DUMP_INTERRUPT);
+}
+#endif
diff -Naur linux-2.4.19.orig/arch/ia64/kernel/traps.c linux-2.4.19.lkcd/arch/ia64/kernel/traps.c
--- linux-2.4.19.orig/arch/ia64/kernel/traps.c	Sat Aug  3 05:39:42 2002
+++ linux-2.4.19.lkcd/arch/ia64/kernel/traps.c	Tue Nov 19 13:49:50 2002
@@ -38,6 +38,7 @@
 #include <asm/ia32.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
+#include <linux/dump.h>
 
 #include <asm/fpswa.h>
 
@@ -108,6 +109,7 @@
 	if (++die.lock_owner_depth < 3) {
 		printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err);
 		show_regs(regs);
+		dump((char *)str, regs);
   	} else
 		printk(KERN_ERR "Recursive die() failure, output suppressed\n");
 
diff -Naur linux-2.4.19.orig/drivers/Makefile linux-2.4.19.lkcd/drivers/Makefile
--- linux-2.4.19.orig/drivers/Makefile	Sat Aug  3 05:39:43 2002
+++ linux-2.4.19.lkcd/drivers/Makefile	Tue Nov 19 13:49:50 2002
@@ -7,7 +7,7 @@
 
 
 mod-subdirs :=	dio mtd sbus video macintosh usb input telephony sgi ide \
-		message/i2o message/fusion scsi md ieee1394 pnp isdn atm \
+		message/i2o message/fusion scsi md ieee1394 pnp isdn dump atm \
 		fc4 net/hamradio i2c acpi bluetooth
 
 subdir-y :=	parport char block net sound misc media cdrom hotplug
@@ -38,6 +38,7 @@
 subdir-$(CONFIG_PNP)		+= pnp
 subdir-$(CONFIG_ISDN_BOOL)	+= isdn
 subdir-$(CONFIG_ATM)		+= atm
+subdir-$(CONFIG_DUMP)		+= dump
 subdir-$(CONFIG_FC4)		+= fc4
 
 # CONFIG_HAMRADIO can be set without CONFIG_NETDEVICE being set  -- ch
diff -Naur linux-2.4.19.orig/drivers/char/sysrq.c linux-2.4.19.lkcd/drivers/char/sysrq.c
--- linux-2.4.19.orig/drivers/char/sysrq.c	Sat Aug  3 05:39:43 2002
+++ linux-2.4.19.lkcd/drivers/char/sysrq.c	Tue Nov 19 13:49:50 2002
@@ -1,6 +1,6 @@
 /* -*- linux-c -*-
  *
- *	$Id: sysrq.c,v 1.15 1998/08/23 14:56:41 mj Exp $
+ *	$Id: sysrq.c,v 1.9 2002/01/24 09:44:12 yakker Exp $
  *
  *	Linux Magic System Request Key Hacks
  *
@@ -25,6 +25,7 @@
 #include <linux/sysrq.h>
 #include <linux/kbd_kern.h>
 #include <linux/quotaops.h>
+#include <linux/dump.h>
 #include <linux/smp_lock.h>
 #include <linux/module.h>
 
@@ -295,6 +296,38 @@
 	}
 }
 
+static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs,
+		struct kbd_struct *kbd, struct tty_struct *tty) {
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+	dump("sysrq", pt_regs);
+#endif
+}
+static struct sysrq_key_op sysrq_crashdump_op = {
+	handler:	sysrq_handle_crashdump,
+	help_msg:	"Crash",
+	action_msg:	"Start a Crash Dump (If Configured)",
+};
+
+static void sysrq_handle_dumpregs(int key, struct pt_regs *pt_regs,
+		struct kbd_struct *kbd, struct tty_struct *tty) {
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+#if defined(CONFIG_X86) && defined(CONFIG_SMP)
+	extern void (*dump_trace_ptr)(struct pt_regs *);
+	printk("Show state of all cpus\n");
+	if (dump_trace_ptr) {
+		dump_trace_ptr(pt_regs);
+	} else {
+		printk("Load dump module/configure first\n");
+	}
+#endif
+#endif
+}
+static struct sysrq_key_op sysrq_dumpregs_op = {
+	handler:	sysrq_handle_dumpregs,
+	help_msg:	"Dumpregisters",
+	action_msg:	"Dump CPU Registers (If Configured)"
+};
+
 static void sysrq_handle_term(int key, struct pt_regs *pt_regs,
 		struct kbd_struct *kbd, struct tty_struct *tty) {
 	send_sig_all(SIGTERM);
@@ -338,8 +371,8 @@
 		 it is handled specially on the spark
 		 and will never arive */
 /* b */	&sysrq_reboot_op,
-/* c */	NULL,
-/* d */	NULL,
+/* c */	&sysrq_crashdump_op,
+/* d */	&sysrq_dumpregs_op,
 /* e */	&sysrq_term_op,
 /* f */	NULL,
 /* g */	NULL,
diff -Naur linux-2.4.19.orig/drivers/dump/Makefile linux-2.4.19.lkcd/drivers/dump/Makefile
--- linux-2.4.19.orig/drivers/dump/Makefile	Thu Jan  1 05:00:00 1970
+++ linux-2.4.19.lkcd/drivers/dump/Makefile	Tue Nov 19 13:49:50 2002
@@ -0,0 +1,36 @@
+#
+# Makefile for the dump device drivers.
+#
+# 12 June 2000, Christoph Hellwig <schch@pe.tu-clausthal.de>
+# Rewritten by Matt D. Robinson (yakker@sourceforge.net) for
+# the dump directory.
+#
+
+O_TARGET	:=	dumpdrv.o
+export-objs	:=	dump_base.o
+
+list-multi	:=	dump.o
+dump-objs	:=	dump_base.o
+
+# get the base dump module and compression modules out of the way
+obj-$(CONFIG_DUMP_COMPRESS_RLE)		+= dump_rle.o
+obj-$(CONFIG_DUMP_COMPRESS_GZIP)	+= dump_gzip.o
+obj-$(CONFIG_DUMP)			+= dump.o
+
+# now deal with each individual architecture.
+ifeq ($(ARCH),i386)
+	dump-objs		+= dump_i386.o
+endif
+
+ifeq ($(ARCH),alpha)
+	dump-objs		+= dump_alpha.o
+endif
+
+ifeq ($(ARCH),ia64)
+	dump-objs		+= dump_ia64.o
+endif
+
+include $(TOPDIR)/Rules.make
+
+dump.o:	$(dump-objs)
+	$(LD) -r -o $@ $(dump-objs)
diff -Naur linux-2.4.19.orig/drivers/dump/dump_alpha.c linux-2.4.19.lkcd/drivers/dump/dump_alpha.c
--- linux-2.4.19.orig/drivers/dump/dump_alpha.c	Thu Jan  1 05:00:00 1970
+++ linux-2.4.19.lkcd/drivers/dump/dump_alpha.c	Tue Nov 19 13:49:50 2002
@@ -0,0 +1,103 @@
+/*
+ * Architecture specific (alpha) functions for Linux crash dumps.
+ *
+ * 2.3 kernel modifications by: Matt D. Robinson (yakker@turbolinux.com)
+ * Copyright 2000 TurboLinux, Inc.  All rights reserved.
+ * 2.4 modifications by Matt D. Robinson (yakker@aparity.com)
+ * Copyright 2001 Matt D. Robinson.  All rights reserved.
+ * 
+ * This code is released under version 2 of the GNU GPL.
+ */
+
+/*
+ * The hooks for dumping the kernel virtual memory to disk are in this
+ * file.  Any time a modification is made to the virtual memory mechanism,
+ * these routines must be changed to use the new mechanisms.
+ */
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/dump.h>
+#include <linux/mm.h>
+
+/* static variables */
+static dump_header_asm_t dump_header_asm;
+
+/*
+ * Name: __dump_configure_header()
+ * Func: Configure the dump header with all proper values.
+ */
+int
+__dump_configure_header(struct pt_regs *regs)
+{
+	dump_header_asm.dha_magic_number = DUMP_ASM_MAGIC_NUMBER;
+	dump_header_asm.dha_version = DUMP_ASM_VERSION_NUMBER;
+	dump_header_asm.dha_header_size = sizeof(dump_header_asm_t);
+
+	/* copy the registers if they are valid */
+	if (regs) {
+		memcpy((void *)&(dump_header_asm.dha_regs),
+			(const void *)regs, sizeof(struct pt_regs));
+	}
+
+	return (1);
+}
+
+/*
+ * Name: __dump_write_header()
+ * Func: Update the header information with all architecture specific
+ *       information.
+ */
+int
+__dump_write_header(char *dpage)
+{
+	memcpy((void *)(dpage + sizeof(dump_header_t)),
+		(const void *)&dump_header_asm, sizeof(dump_header_asm_t));
+
+	return (1);
+}
+
+/*
+ * Name: __dump_init()
+ * Func: Initialize the dumping routine process.  This is in case
+ *       it's necessary in the future.
+ */
+void
+__dump_init(uint64_t local_memory_start)
+{
+	/* return */
+	return;
+}
+
+/*
+ * Name: __dump_open()
+ * Func: Open the dump device (architecture specific).  This is in
+ *       case it's necessary in the future.
+ */
+void
+__dump_open(struct file *dump_file, uint64_t memory_size)
+{
+	/* return */
+	return;
+}
+
+/*
+ * Name: __dump_silence_system()
+ * Func: Do an architecture-specific silencing of the system.
+ */
+unsigned int
+__dump_silence_system(unsigned int stage)
+{
+	/* return */
+	return (0);
+}
+
+/*
+ * Name: __dump_resume_system()
+ * Func: Resume the system state in an architecture-specific way.
+ */
+unsigned int
+__dump_resume_system(unsigned int stage)
+{
+	/* return */
+	return (0);
+}
diff -Naur linux-2.4.19.orig/drivers/dump/dump_base.c linux-2.4.19.lkcd/drivers/dump/dump_base.c
--- linux-2.4.19.orig/drivers/dump/dump_base.c	Thu Jan  1 05:00:00 1970
+++ linux-2.4.19.lkcd/drivers/dump/dump_base.c	Tue Nov 19 13:49:50 2002
@@ -0,0 +1,2025 @@
+/*
+ * Standard kernel functions for Linux crash dumps.
+ *
+ * Created by: Matt Robinson (yakker@sourceforge.net)
+ * Contributions from SGI, IBM, HP, MCL, and others.
+ *
+ * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000 - 2002 TurboLinux, Inc.  All rights reserved.
+ * Copyright (C) 2001 - 2002 Matt D. Robinson.  All rights reserved.
+ * Copyright (C) 2002 Free Software Foundation, Inc. All rights reserved.
+ *
+ * This code is released under version 2 of the GNU GPL.
+ */
+
+/*
+ * -----------------------------------------------------------------------
+ *
+ * DUMP HISTORY
+ *
+ * This dump code goes back to SGI's first attempts at dumping system
+ * memory on SGI systems running IRIX.  A few developers at SGI needed
+ * a way to take this system dump and analyze it, and created 'icrash',
+ * or IRIX Crash.  The mechanism (the dumps and 'icrash') were used
+ * by support people to generate crash reports when a system failure
+ * occurred.  This was vital for large system configurations that
+ * couldn't apply patch after patch after fix just to hope that the
+ * problems would go away.  So the system memory, along with the crash
+ * dump analyzer, allowed support people to quickly figure out what the
+ * problem was on the system with the crash dump.
+ *
+ * In comes Linux.  SGI started moving towards the open source community,
+ * and upon doing so, SGI wanted to take its support utilities into Linux
+ * with the hopes that they would end up the in kernel and user space to
+ * be used by SGI's customers buying SGI Linux systems.  One of the first
+ * few products to be open sourced by SGI was LKCD, or Linux Kernel Crash
+ * Dumps.  LKCD comprises of a patch to the kernel to enable system
+ * dumping, along with 'lcrash', or Linux Crash, to analyze the system
+ * memory dump.  A few additional system scripts and kernel modifications
+ * are also included to make the dump mechanism and dump data easier to
+ * process and use.
+ *
+ * As soon as LKCD was released into the open source community, a number
+ * of larger companies started to take advantage of it.  Today, there are
+ * many commmunity members that contribute to LKCD, and it continues to
+ * flourish and grow as an open source project.
+ *
+ * -----------------------------------------------------------------------
+ *
+ * SYSTEM DUMP LAYOUT
+ * 
+ * System dumps are currently the combination of a dump header and a set
+ * of data pages which contain the system memory.  The layout of the dump
+ * (for full dumps) is as follows:
+ *
+ *             +-----------------------------+
+ *             |     generic dump header     |
+ *             +-----------------------------+
+ *             |   architecture dump header  |
+ *             +-----------------------------+
+ *             |         page header         |
+ *             +-----------------------------+
+ *             |          page data          |
+ *             +-----------------------------+
+ *             |         page header         |
+ *             +-----------------------------+
+ *             |          page data          |
+ *             +-----------------------------+
+ *             |              |              |
+ *             |              |              |
+ *             |              |              |
+ *             |              |              |
+ *             |              V              |
+ *             +-----------------------------+
+ *             |        PAGE_END header      |
+ *             +-----------------------------+
+ *
+ * There are two dump headers, the first which is architecture
+ * independent, and the other which is architecture dependent.  This
+ * allows different architectures to dump different data structures
+ * which are specific to their chipset, CPU, etc.
+ *
+ * After the dump headers come a succession of dump page headers along
+ * with dump pages.  The page header contains information about the page
+ * size, any flags associated with the page (whether it's compressed or
+ * not), and the address of the page.  After the page header is the page
+ * data, which is either compressed (or not).  Each page of data is
+ * dumped in succession, until the final dump header (PAGE_END) is
+ * placed at the end of the dump, assuming the dump device isn't out
+ * of space.
+ *
+ * This mechanism allows for multiple compression types, different
+ * types of data structures, different page ordering, etc., etc., etc.
+ * It's a very straightforward mechanism for dumping system memory.
+ * -----------------------------------------------------------------------
+ *
+ * DUMP IMPLEMENTATION
+ *
+ * Dumps are implemented using a "start at the top and work your way
+ * to the bottom" method.  The starting location of kernel memory is
+ * determined, and each successive page is passed through to the
+ * dump_add_page() function, which determines whether to compress the
+ * page, throw it out, add the page header, etc.  This mechanism is
+ * going to change over time as non-disruptive dumps are created, so
+ * it is best to read through the code (it is commented pretty well),
+ * and let the developers know if it isn't clear enough.  We believe
+ * in well-documented, well-commented code.
+ *
+ * -----------------------------------------------------------------------
+ *
+ * DUMP TUNABLES
+ *
+ * This is the list of system tunables (via /proc) that are available
+ * for Linux systems.  All the read, write, etc., functions are listed
+ * here.  Currently, there are a few different tunables for dumps:
+ *
+ * dump_device (used to be dumpdev):
+ *     The device for dumping the memory pages out to.  This is almost
+ *     always the primary swap partition for disruptive dumps.
+ *
+ * dump_compress (used to be dump_compress_pages):
+ *     This is the flag which indicates which compression mechanism
+ *     to use.  This is a BITMASK, not an index (0,1,2,4,8,16,etc.).
+ *     This is the current set of values:
+ *
+ *     0: DUMP_COMPRESS_NONE -- Don't compress any pages.
+ *     1: DUMP_COMPRESS_RLE  -- This uses RLE compression.
+ *     2: DUMP_COMPRESS_GZIP -- This uses GZIP compression.
+ *
+ * dump_level:
+ *     The amount of effort the dump module should make to save
+ *     information for post crash analysis.  This value is now
+ *     a BITMASK value, not an index:
+ *
+ *     0:   Do nothing, no dumping. (DUMP_LEVEL_NONE)
+ *
+ *     1:   Print out the dump information to the dump header, and
+ *          write it out to the dump_device. (DUMP_LEVEL_HEADER)
+ *
+ *     2:   Write out the dump header and all kernel memory pages.
+ *          (DUMP_LEVEL_KERN)
+ *
+ *     4:   Write out the dump header and all kernel and user
+ *          memory pages.  (DUMP_LEVEL_USED)
+ *
+ *     8:   Write out the dump header and all conventional/cached 
+ *	    memory (RAM) pages in the system (kernel, user, free).  
+ *	    (DUMP_LEVEL_ALL_RAM)
+ *
+ *    16:   Write out everything, including non-conventional memory
+ *	    like firmware, proms, I/O registers, uncached memory.
+ *	    (DUMP_LEVEL_ALL)
+ *
+ *     The dump_level will default to 1.
+ *
+ *      REMIND: How about we change these to 1, 3, 7, 15, 31.
+ *	        If we reserve the bits for individual passes
+ *		it's easer to test things like non-conventional
+ *		memory dump on systems with limited disk space.
+ *		If would be more consistant with dump_level being 
+ *		a bitmask. We might also consider changeing the name 
+ *		to 'dump_passes' to make it more clear that the bitmask 
+ *		is not a index.
+ * 
+ *
+ * dump_flags:
+ *     These are the flags to use when talking about dumps.  There
+ *     are lots of possibilities.  This is a BITMASK value, not an index.
+ * 
+ *     1:  Try to keep the system running _after_ we are done
+ *         dumping -- for non-disruptive dumps.  (DUMP_FLAGS_NONDISRUPT)
+ *
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * -----------------------------------------------------------------------
+ *                      H E A D E R   F I L E S
+ * -----------------------------------------------------------------------
+ */
+
+/* header files */
+#include <asm/system.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <asm/uaccess.h>
+#include <linux/dump.h>
+#include <linux/smp_lock.h>
+#include <linux/mm.h>
+#include <linux/proc_fs.h>
+#include <linux/file.h>
+#include <linux/sysctl.h>
+#include <linux/iobuf.h>
+#include <linux/mman.h>
+#include <linux/init.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/utsname.h>
+#include <linux/highmem.h>
+#include <asm/hardirq.h>
+#include <linux/version.h>
+#include <asm/system.h>
+
+/*
+ * -----------------------------------------------------------------------
+ *                       D E F I N I T I O N S
+ * -----------------------------------------------------------------------
+ */
+#define DUMP_MODULE_NAME "dump"
+
+#if DUMP_DEBUG
+#define DUMP_PREFIX __func__
+#else
+#define DUMP_PREFIX DUMP_MODULE_NAME
+#endif
+
+
+#define DUMP_PRINTN(args...)  {						\
+	printk("\n");							\
+	DUMP_PRINTF(args);						\
+}
+#define DUMP_PRINTF(args...)  {						\
+	printk("%s: ", DUMP_PREFIX);					\
+	printk (args);							\
+}
+#define DUMP_PRINT(args...) {						\
+	printk(args);							\
+}
+
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(a,b,c) (((a) << 16) | ((b) << 8) | (c))
+#endif
+
+/* 
+ * Handle printing of 64-bit values  
+ *
+ * NOTE: on ia64 %llx is recomend for ia32. 
+ *       on RedHat 7.2 	%llx work in user space but not in the kernel.
+ *	 Perhaps this is dependent on the kernel version.
+ */
+#if BITS_PER_LONG == 64
+#define PU64X "%lx"
+#else
+#define PU64X "%Lx"
+#endif
+
+
+/*
+ * -----------------------------------------------------------------------
+ *                         V A R I A B L E S
+ * -----------------------------------------------------------------------
+ */
+
+/* Dump tunables */
+kdev_t dump_device;                /* the actual kdev_t device number      */
+int dump_level;                    /* the current dump level               */
+int dump_compress;                 /* whether to try to compress each page */
+int dump_flags;                    /* whether to try to compress each page */
+
+/* Other global fields */
+char dumpdev_name[PATH_MAX];       /* the name of the dump device          */
+void *dump_page_buf;               /* dump page buffer for memcpy()!       */
+void *dump_page_buf_0;             /* dump page buffer returned by kmalloc */
+int dump_blk_size;                 /* sector size for dump_device          */
+int dump_blk_shift;                /* shift need to convert to sector size */
+dump_header_t dump_header;         /* the primary dump header              */
+dump_header_asm_t dump_header_asm; /* the arch-specific dump header        */
+struct kiobuf *dump_iobuf;         /* kiobuf for raw I/O to disk           */
+loff_t dump_fpos;                  /* the offset in the output device      */
+int dump_mbanks;		   /* number of  physical memory banks     */
+dump_mbank_t dump_mbank[MAXCHUNKS];/* describes layout of physical memory  */
+long dump_unreserved_mem = 0;      /* Save Pages even if it isn't reserved */
+long dump_unreferenced_mem = 0;    /* Save Pages even if page_count == 0   */
+long dump_nonconventional_mem = 0;  /* Save non-conventional mem (firmware) */
+
+static int dump_compress_none(char *old, int oldsize, char *new, int newsize);
+
+static dump_compress_t dump_none_compression = {
+	compress_type:	DUMP_COMPRESS_NONE,
+	compress_func:	dump_compress_none,
+};
+
+/* our device operations and functions */
+static int dump_open(struct inode *i, struct file *f);
+static int dump_release(struct inode *i, struct file *f);
+static int dump_ioctl(struct inode *i, struct file *f,
+	unsigned int cmd, unsigned long arg);
+
+static struct file_operations dump_fops = {
+	open:		dump_open,
+	release:	dump_release,
+	ioctl:		dump_ioctl,
+};
+
+/* function pointers and prototypes */
+int (*dump_compress_func)(char *old, int oldsize, char *new, int newsize);
+
+/* proc entries */
+static struct proc_dir_entry *dump_root;    /* /proc/sys/dump root dir     */
+static struct proc_dir_entry *dump_dd;      /* dump_device tunable         */
+static struct proc_dir_entry *dump_cp;      /* dump_compress tunable       */
+static struct proc_dir_entry *dump_l;       /* dump_level tunable          */
+static struct proc_dir_entry *dump_f;       /* dump_flags tunable          */
+
+/* static variables                                                        */
+static int dump_okay = FALSE;      	   /* can we dump out to disk?     */
+static char dpcpage[DUMP_DPC_PAGE_SIZE];  /* buffer used for compression   */
+static unsigned long dump_save_flags;     /* save_flags()/restore_flags()  */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4))
+static unsigned long dump_blocks[KIO_MAX_SECTORS];
+#endif
+
+/* for dumping from interrupt context (Fixme)  */
+static int saved_irq_count; 	/* remember the current irq nesting level   */
+static int saved_bh_count;	/* remember if we were in soft irq context  */
+
+/* used for dump compressors */
+static struct list_head dump_compress_list = LIST_HEAD_INIT(dump_compress_list);
+
+/* external variables                                                      */
+extern volatile int dumping_cpu;   /* cpu on which dump is progressing     */
+extern volatile int dump_in_progress;         /* note when we're dumping   */
+extern int panic_timeout;          /* time before reboot                   */
+extern int *blk_size[];            /* device block size calculations       */
+extern struct new_utsname system_utsname;     /* system information        */
+
+#if !defined(irq_count) && !defined(bh_count)
+extern irq_cpustat_t irq_stat[];
+#endif
+
+/* external functions                                                      */
+extern void si_meminfo(struct sysinfo *);
+extern void *kmalloc(size_t, int);
+extern void kfree(const void *);
+extern unsigned long simple_strtoul(const char *,char **,unsigned int);
+
+/* lkcd info structure -- this is used by lcrash for basic system data     */
+lkcdinfo_t lkcdinfo = {
+	0,
+	(sizeof(void *) * 8),
+#if defined(__LITTLE_ENDIAN) 
+	__LITTLE_ENDIAN,
+#else
+	__BIG_ENDIAN,
+#endif
+	0,
+	PAGE_SHIFT,
+	PAGE_SIZE,
+	PAGE_MASK,
+	PAGE_OFFSET,
+	0
+};
+
+#if DUMP_DEBUG
+void dump_bp(void) {}
+#endif
+
+
+/*
+ * -----------------------------------------------------------------------
+ *            / P R O C   T U N A B L E   F U N C T I O N S
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * Name: dump_read_proc()
+ * Func: Read the proc data for dump tunables.
+ */
+static int
+dump_read_proc(char *page, char **start, off_t off,
+	int count, int *eof, void *data)
+{
+	int len;
+	char *out = page;
+	struct proc_dir_entry *p = (struct proc_dir_entry *)data;
+
+
+	if (0 == strcmp(p->name, DUMP_LEVEL_NAME)) {
+		out += sprintf(out, "%d\n", dump_level);
+		len = out - page;
+	} else if (0 == strcmp(p->name, DUMP_FLAGS_NAME)) {
+		out += sprintf(out, "%d\n", dump_flags);
+		len = out - page;
+	} else if (0 == strcmp(p->name, DUMP_COMPRESS_NAME)) {
+		out += sprintf(out, "%d\n", dump_compress);
+		len = out - page;
+	} else if (0 == strcmp(p->name, DUMP_DEVICE_NAME)) {
+#if 0
+		len = strlen(dumpdev_name);
+		memcpy((void *)page, (const void *)dumpdev_name, len);
+#else
+		out += sprintf(out, "%s\n", dumpdev_name);
+		len = out - page;
+#endif
+	} else {
+		return (0);
+	}
+	len -= off;
+	if (len < count) {
+		*eof = 1;
+		if (len <= 0) return 0;
+	} else {
+		len = count;
+	}
+	*start = page + off;
+	return (len);
+}
+
+/*
+ * -----------------------------------------------------------------------
+ *              C O M P R E S S I O N   F U N C T I O N S
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * Name: dump_compress_none()
+ * Func: Don't do any compression, period.
+ */
+static int
+dump_compress_none(char *old, int oldsize, char *new, int newsize)
+{
+	/* just return the old size */
+	return (oldsize);
+}
+
+/*
+ * -----------------------------------------------------------------------
+ *                  U T I L I T Y   F U N C T I O N S
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * Name: dump_kernel_write()
+ *
+ * Func: Write out kernel information, check the device limitations,
+ *       block sizes, etc.  The thing I don't like about this function
+ *       is that most of it is a duplicate of what rw_raw_dev() does,
+ *       but sct doesn't want rw_raw_dev() to do kernel kiobuf stuff, and
+ *       brw_kiovec() isn't a good place to do device checks, since we'd
+ *       have to check all this stuff anyway, and device block calculations
+ *       are ugly in there for each call to the function.  So we do it all
+ *       here, call brw_kiovec() on our own, and return the results.
+ *
+ * 	 Writes DUMP_BUFFER_SIZE bytes in page buffer
+ *
+ * Returns: number of bytes written or -ERRNO. 
+ *	    At EOF it returns 0.
+ */
+static ssize_t
+dump_kernel_write(int *eof)
+{
+	int		err = 0, iosize, i;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4))
+	unsigned long	*b = dump_blocks;
+#else
+	unsigned long	*b = dump_iobuf->blocks;
+#endif
+	unsigned long blocknr, blocks, limit;
+	
+	/* check the device size to make sure we are in-line */
+	if (blk_size[MAJOR(dump_device)]) {
+		limit = (((loff_t) blk_size[MAJOR(dump_device)][MINOR(dump_device)])
+				<< BLOCK_SIZE_BITS) >> dump_blk_shift;
+	} else {
+		limit = INT_MAX;
+	}
+
+	/* not aligned? */
+	if (dump_fpos & (dump_blk_size - 1)) {
+		DUMP_PRINTN("invalid buffer alignment!");
+		return (-EINVAL);
+	}
+
+	/* beyond the end of the device -- not really an error, per se */
+	if ((dump_fpos >> dump_blk_shift) > limit) {
+		DUMP_PRINTN("no space left on device!");
+		DUMP_BP();
+		return (0);
+	}
+
+	/* 
+	 * If near the end of the dump device we set *eof (if ptr provided) to
+	 * let the caller know that it's near the EOF on the dump device.
+	 */
+	if ( ((dump_fpos + (4 * DUMP_BUFFER_SIZE)) >> dump_blk_shift) > limit) {
+		if(eof != NULL) {
+			*eof = 1;
+		}
+		DUMP_BP();
+	}
+	/* 
+	 * If near the end of the dump device we set *eof (if ptr provided) to
+	 * let the caller know that it's near the EOF on the dump device.
+	 */
+	else if ( ((dump_fpos + (2 * DUMP_BUFFER_SIZE)) >> dump_blk_shift) > limit) {
+		if(eof != NULL) {
+			*eof = 1;
+		}
+		DUMP_BP();
+	}
+
+	/* reset the block number values */
+	blocknr = dump_fpos >> dump_blk_shift;
+
+	/* calculate the number of blocks */
+	blocks = DUMP_BUFFER_SIZE >> dump_blk_shift;
+	if (blocks > (KIO_MAX_SECTORS >> (dump_blk_shift - 9))) {
+		blocks = KIO_MAX_SECTORS >> (dump_blk_shift - 9);
+	}
+
+	/* don't write more blocks than our max limit */
+	if (blocks > limit - blocknr) {
+		blocks = limit - blocknr;
+	}
+
+	/* make sure we have blocks to write! */
+	if (!blocks) {
+		DUMP_PRINTN("no blocks left on dump device!");
+		return (0);
+	}
+
+	/* map the kernel kiobuf based on the iosize */
+	iosize = blocks << dump_blk_shift;
+
+	/* map the block numbers */
+	for (i = 0; i < blocks; i++) {
+		b[i] = blocknr++;
+	}
+
+	/* write out the data to disk */
+	err = brw_kiovec(WRITE, 1, &dump_iobuf, dump_device, b, dump_blk_size);
+
+	/* make sure our I/O size matches return from brw_kiovec() */
+	if (err < 0) {
+		DUMP_PRINTN("brw_kiovec() returned %d!", err);
+		return (-EFAULT);
+	}
+
+	if (err != DUMP_BUFFER_SIZE) {
+		DUMP_PRINTN("brw_kiovec() did not write out DUMP_BUFFER_SIZE!");
+		return (-EFAULT);
+	}
+
+	/* err is the transferred bytes -- return those */
+	dump_fpos += err;
+	return (err);
+}
+
+/*
+ * Name: dump_add_end_marker()
+ * Func: add last dump page marker to the end of the dump buffer.
+ */
+static void
+dump_add_end_marker(unsigned long *toffset, int flags)
+{
+	dump_page_t dp;
+
+	/* set the end marker */
+	dp.dp_address = dp.dp_size = 0x0;
+	dp.dp_flags = flags;
+
+#if DUMP_DEBUG >= 6
+	dp.dp_byte_offset = dump_header.dh_num_bytes + DUMP_BUFFER_SIZE + PAGE_SIZE;
+	dp.dp_page_index = dump_header.dh_num_dump_pages;
+#endif
+
+	/* clear the buffer and copy the page header */
+	memcpy((void *)(dump_page_buf + *toffset),
+		(const void *)&dp, sizeof(dump_page_t));
+	*toffset += sizeof(dump_page_t);
+
+#if DUMP_DEBUG >= 6
+	dump_header.dh_num_bytes += sizeof(dump_page_t);
+#endif
+	dump_header.dh_num_dump_pages++;
+
+	return;
+}
+
+
+long dump_add_page_debug = 0;
+long dump_add_page_test_pattern = 0;
+
+/*
+ * Name: dump_add_page()
+ * Func: Add a hardware page to the dump buffer.
+ *
+ * NB: page is a DUMP_PAGE_SIZE page, 
+ *     not a system page (PAGE_SIZE).
+ * 
+ * REMIND:
+ *	We should likely move some of this to
+ *	arch specific code and/or clean it up.
+ */
+static int
+dump_add_page(unsigned long page_index, unsigned long *toffset, int pass)
+{
+#if defined(CONFIG_X86) || defined(CONFIG_ALPHA)
+	extern int page_is_ram(unsigned long);
+#endif
+	unsigned long size;
+	dump_page_t dp;
+	void *vaddr;
+	u64 paddr = (((u64)page_index) << DUMP_PAGE_SHIFT);
+	struct page *p;
+
+#if !defined(CONFIG_DISCONTIGMEM) && !defined(CONFIG_IA64)
+	p = (struct page *) &(mem_map[page_index]);
+
+	/*
+	 * If the address is in highmem, map it before copying to
+	 * the dump buffer.  In essence, the dump buffer is the
+	 * bounce buffer.
+	 */
+#ifdef CONFIG_HIGHMEM
+	if (PageHighMem(p)) {
+		/*
+		 * Since this can be executed from IRQ context,
+		 * reentrance on the same CPU must be avoided:
+		 */
+		vaddr = kmap_atomic(p, KM_USER0);
+	}
+	else
+#endif
+#if defined(CONFIG_X86) || defined(CONFIG_ALPHA)
+	if (!page_is_ram(page_index)) {
+		return (1);
+	}
+	else
+#endif
+	/* low memory */
+	vaddr = page_address(p);
+
+#else /*  CONFIG_DISCONTIGMEM || CONFIG_IA64 */
+	vaddr = __va(paddr);
+	p = virt_to_page(vaddr);
+#endif
+	dp.dp_address = paddr;
+	dp.dp_flags = DUMP_DH_RAW;
+
+
+#if DUMP_DEBUG >= 6
+	/*
+	 * Helpfull when looking at hexdump of /dev/vdump.
+	 * 
+	 *                                               Dump Header         Swap Header
+	 */
+	dp.dp_byte_offset = dump_header.dh_num_bytes + DUMP_BUFFER_SIZE + DUMP_HEADER_OFFSET;
+	dp.dp_page_index = dump_header.dh_num_dump_pages;
+
+	switch(pass) {
+	    case 1:	break;
+	    case 2:	return(1);					/* Already Dumped */
+	    case 3:	return(1);					/* Already Dumped */
+	    case 4:	break;
+	}
+#else
+	/*
+ 	 * Selective dump:
+	 *  	Some systems, have huge memories, NUMA for example, where
+	 *	a dump of all of memory isn't likely to fit on a swap partition.
+	 *	This is a simple 1st attempt at ordering the dump so the most 
+	 *	important pages are dumped first.
+	 *
+	 *	pass1: Reserved Pages
+	 *	pass2: Page count > 0
+	 *	pass3: the rest of conventional memory
+	 *	pass4: non-conventional memory,
+	 */
+	switch (pass) {
+	case 1:
+		if (PageReserved(p) == 0) {
+			return(1); 				/* Skip on this pass */
+		}
+		break;
+
+	case 2: 
+		if( PageReserved(p) || page_count(p) == 0) {
+			return(1);				/* Skip on this pass */
+		}
+		break;
+
+	case 3:
+		if(  PageReserved(p) ||  page_count(p) > 0) {
+			return(1);
+		}
+		break;
+
+	case 4:
+		break;
+
+	}
+#endif
+
+#if !defined(CONFIG_DISCONTIGMEM) && !defined(CONFIG_IA64)
+	if( !kern_addr_valid(dp.dp_address) ) {
+		/* dump of I/O memory not supported yet */
+		printk(KERN_ALERT "dump_add_page: !kern_addr_valid(dp.dp_address: " PU64X "\n", 
+								   dp.dp_address);
+		return(1);
+	}
+#endif
+
+#if DUMP_DEBUG
+	if(dump_add_page_debug) {
+		printk(KERN_ALERT "dump_add_page(page:%lx, *toffset:%lx):\n",  
+				                 page,     *toffset);
+	}
+#endif
+
+	/*
+	 * Don't compress the page if any part of it overlaps
+	 * with the current task_struct or current stack.
+	 */
+	if ((((unsigned long)vaddr < (unsigned long)current + THREAD_SIZE)  &&
+		((unsigned long)vaddr + DUMP_PAGE_SIZE >
+		(unsigned long)current))) {
+			size = DUMP_PAGE_SIZE;
+	}
+	else {
+		size = dump_compress_func((char *)vaddr, DUMP_PAGE_SIZE,
+			(char *)dpcpage, DUMP_DPC_PAGE_SIZE);
+		if (!size) {
+			/* dump compression failed -- default to raw mode */
+			size = DUMP_PAGE_SIZE;
+		}
+		/* set the compressed flag if the page did compress */
+		if (size < DUMP_PAGE_SIZE) {
+			dp.dp_flags = DUMP_DH_COMPRESSED;
+		}
+	}
+
+	/* set the universal size */
+	dp.dp_size = size;
+
+	/* copy the page header */
+	memcpy((void *)(dump_page_buf + *toffset), (const void *)&dp,
+		sizeof(dump_page_t));
+
+	*toffset += sizeof(dump_page_t);
+
+	if (dp.dp_flags & DUMP_DH_COMPRESSED) {
+		/* copy the compressed page */
+		memcpy((void *)(dump_page_buf + *toffset),
+			(const void *)dpcpage, size);
+	} else {
+		/* copy directly from memory */
+		DUMP_memcpy((void *)(dump_page_buf + *toffset),
+			(const void *)vaddr, size);
+	}
+
+#if DUMP_DEBUG
+	/*
+	 * Write a Test Pattern:
+	 *	Page data is full of bytes with the page number.
+	 */	
+	if (dump_add_page_test_pattern) {
+		unsigned char num_pages = (char) (dump_header.dh_num_dump_pages & 0Xff);
+		char *cp = (dump_page_buf + *toffset);
+		int i;
+
+		for( i = 0; i < size; i++) {
+			*cp++ = num_pages;	
+		}
+	}
+#endif
+
+#ifdef CONFIG_HIGHMEM
+	if (PageHighMem(p)) {
+		/*
+		 * Since this can be executed from IRQ context,
+		 * reentrance on the same CPU must be avoided:
+		 */
+		kunmap_atomic(vaddr, KM_USER0);
+	}
+#endif
+	*toffset += size;
+
+#if DUMP_DEBUG >= 6
+	if (dump_add_page_debug) {
+		printk(KERN_ALERT "dump_add_page: *toffset:%lx += size:%lx:\n",  
+						  *toffset,       size);
+	}
+	dump_header.dh_num_bytes += (size + sizeof(dump_page_t));
+#endif
+
+	dump_header.dh_num_dump_pages++;
+
+	return (0);
+}
+
+
+/*
+ * Name: dump_silence_system()
+ * Func: Silence the system, or make CPUs spin, etc.  The intention
+ *       here is to get things to a "quiet" state, so we can dump.
+ */
+void
+dump_silence_system(void)
+{
+	unsigned int stage = 0;
+	int cpu = smp_processor_id();
+
+	if (in_interrupt()) {
+		printk(KERN_ALERT "Dumping from interrupt handler !\n");
+		printk(KERN_ALERT "Uncertain scenario - but will try my best\n");
+		/* 
+		 * Must be an unrelated interrupt, not in the middle of io ! 
+		 * If we've panic'ed in the middle of io we should take 
+		 * another approach 
+		 */
+	}
+	/* see if there's something to do before we re-enable interrupts */
+	(void)__dump_silence_system(stage);
+
+	/* we set this to FALSE so we don't ever re-enter this code! */
+	dump_okay = FALSE;
+	dumping_cpu = cpu;
+	dump_in_progress = TRUE;
+	save_flags(dump_save_flags);
+
+	/* -------------------------------------------------- */
+	/* Kludge - dump from interrupt context is unreliable (Fixme)
+	 *
+	 * We do this so that softirqs initiated for dump i/o 
+	 * get processed and we don't hang while waiting for i/o
+	 * to complete or in any irq synchronization attempt.
+	 *
+	 * This is not quite legal of course, as it has the side 
+	 * effect of making all interrupts & softirqs triggered 
+	 * while dump is in progress complete before currently 
+	 * pending softirqs and the currently executing interrupt 
+	 * code. 
+	 */
+	/*
+	 * We use irq_stat directly instead of using local_irq_count
+	 * and local_bh_count as they can't be used as Lvalues on
+	 * uniprocessor machines. 
+	 */
+#if defined(irq_count) && defined(bh_count)
+	saved_irq_count = irq_count(cpu);
+	saved_bh_count =  bh_count(cpu);
+	irq_count(cpu) = 0;
+	bh_count(cpu) = 0;
+#else
+	saved_irq_count = irq_stat[cpu].__local_irq_count;
+	saved_bh_count = irq_stat[cpu].__local_bh_count;
+	irq_stat[cpu].__local_irq_count = 0;
+	irq_stat[cpu].__local_bh_count = 0;
+#endif
+	/* -----------------------------------------------------*/
+
+	sti(); /* enable interrupts just in case ... */
+
+	/* now increment the stage and do stuff after interrupts are enabled */
+	stage++;
+	(void)__dump_silence_system(stage);
+
+	/* time to leave */
+	return;
+}
+
+/*
+ * Name: dump_resume_system()
+ * Func: Resume the system state.
+ */
+void
+dump_resume_system(void)
+{
+	unsigned int stage = 0;
+
+	/* let the architectures return their proper system state */
+	(void)__dump_resume_system(stage);
+
+	/* restore flags and other dump state fields */
+	restore_flags(dump_save_flags);
+
+#if defined(irq_count) && defined(bh_count)
+	irq_count(dumping_cpu) =  saved_irq_count;
+	bh_count(dumping_cpu) = saved_bh_count;
+#else
+	irq_stat[dumping_cpu].__local_irq_count = saved_irq_count;
+	irq_stat[dumping_cpu].__local_bh_count = saved_bh_count;
+#endif
+
+	dump_in_progress = FALSE;
+	dump_okay = TRUE;
+
+	/* reboot the system if this isn't a disrupted dump */
+	if ((panic_timeout > 0) && (!(dump_flags & DUMP_FLAGS_NONDISRUPT))) {
+		DUMP_PRINTF("Dump: Rebooting in %d seconds ...", panic_timeout);
+		mdelay(panic_timeout * 1000);
+		machine_restart(NULL);
+	}
+
+	return;
+}
+
+static void
+dump_speedo(void)
+{
+	static int i = 0;
+
+	switch (++i%4) {
+	case 0:
+		printk("|\b");
+		break;
+	case 1:
+		printk("\\\b");
+		break;
+	case 2:
+		printk("-\b");
+		break;
+	case 3:
+		printk("/\b");
+		break;
+	}
+}
+
+/*
+ * -----------------------------------------------------------------------
+ *                     H E A D E R   F U N C T I O N S
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * Name: dump_configure_header()
+ * Func: Update the header with the appropriate information.
+ */
+static int
+dump_configure_header(char *panic_str, struct pt_regs *regs)
+{
+	/* make sure the dump header isn't TOO big */
+	if ((sizeof(dump_header_t) +
+		sizeof(dump_header_asm_t)) > DUMP_BUFFER_SIZE) {
+			DUMP_PRINTN("dump_configure_header(): combined "
+				"headers larger than DUMP_BUFFER_SIZE!");
+			return (0);
+	}
+
+	/* configure dump header values */
+	dump_header.dh_magic_number = DUMP_MAGIC_NUMBER;
+	dump_header.dh_version = DUMP_VERSION_NUMBER;
+	dump_header.dh_memory_start = PAGE_OFFSET;
+	dump_header.dh_memory_end = DUMP_MAGIC_NUMBER;
+	dump_header.dh_header_size = sizeof(dump_header_t);
+	dump_header.dh_dump_page_size = DUMP_PAGE_SIZE;
+	dump_header.dh_dump_level = dump_level;
+	dump_header.dh_current_task = current;
+	dump_header.dh_dump_compress = dump_compress;
+	dump_header.dh_dump_flags = dump_flags;
+	dump_header.dh_dump_device = dump_device;
+
+#if DUMP_DEBUG >= 6
+	dump_header.dh_num_bytes = 0;
+#endif
+	dump_header.dh_num_dump_pages = 0;
+	do_gettimeofday(&dump_header.dh_time);
+
+#ifndef UTSNAME_ENTRY_SZ
+#define UTSNAME_ENTRY_SZ 65
+#endif
+	memcpy((void *)&(dump_header.dh_utsname_sysname), 
+		(const void *)&(system_utsname.sysname), UTSNAME_ENTRY_SZ);
+	memcpy((void *)&(dump_header.dh_utsname_nodename), 
+		(const void *)&(system_utsname.nodename), UTSNAME_ENTRY_SZ);
+	memcpy((void *)&(dump_header.dh_utsname_release), 
+		(const void *)&(system_utsname.release), UTSNAME_ENTRY_SZ);
+	memcpy((void *)&(dump_header.dh_utsname_version), 
+		(const void *)&(system_utsname.version), UTSNAME_ENTRY_SZ);
+	memcpy((void *)&(dump_header.dh_utsname_machine), 
+		(const void *)&(system_utsname.machine), UTSNAME_ENTRY_SZ);
+	memcpy((void *)&(dump_header.dh_utsname_domainname), 
+		(const void *)&(system_utsname.domainname), UTSNAME_ENTRY_SZ);
+
+	if (panic_str) {
+		memcpy((void *)&(dump_header.dh_panic_string),
+			(const void *)panic_str, DUMP_PANIC_LEN);
+	}
+
+        dump_header_asm.dha_magic_number = DUMP_ASM_MAGIC_NUMBER;
+        dump_header_asm.dha_version = DUMP_ASM_VERSION_NUMBER;
+        dump_header_asm.dha_header_size = sizeof(dump_header_asm_t);
+
+	/* copy the registers if they are valid */
+	if (regs) {
+		memcpy((void *)&(dump_header_asm.dha_regs),
+			(const void *)regs, sizeof(struct pt_regs));
+	}
+
+	/* configure architecture-specific dump header values */
+	if (!__dump_configure_header(regs)) {
+		return (0);
+	}
+	return (1);
+}
+
+/*
+ * Name: dump_write_header()
+ * Func: Write out the dump header.
+ *
+ * Returns:
+ *	-1: failed
+ *	 0: wrote o bytes (truncated)
+ *	+1: wrote header
+ */
+static int
+dump_write_header(void)
+{
+	int state;
+	loff_t toffset;
+
+	/* clear the dump page buffer */
+	memset(dump_page_buf, 0, DUMP_BUFFER_SIZE);
+
+	/* copy the dump header directly into the dump page buffer */
+	memcpy(dump_page_buf, (const void *)&dump_header,
+		sizeof(dump_header_t));
+
+	memcpy((void *)(dump_page_buf + sizeof(dump_header_t)),
+		(const void *)&dump_header_asm, sizeof(dump_header_asm_t));
+
+	/* save our file pointer */
+	toffset = dump_fpos;
+
+	/* 
+	 * ALWAYS write out the dump header at DUMP_HEADER_OFFSET, 
+	 * this is after the longest swap header possibly written by mkswap;
+	 * likely the largest PAGE_SIZE supported by the archecture.
+	 */
+	dump_fpos = DUMP_HEADER_OFFSET;
+
+	/* do the real write here */
+	state = dump_kernel_write(NULL);
+	dump_fpos = toffset;
+	if (state < 0) {
+		DUMP_PRINTF("dump_kernel_write() failed!\n");
+		return (-1);
+	} else if (!state) {
+		/* wrote zero bytes - failed */
+		return (0);
+	}
+	/* Wrote the header - success */
+	return (1);
+}
+
+/*
+ * -----------------------------------------------------------------------
+ *                  E X E C U T E   F U N C T I O N S
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * Name: dump_execute_memdump()
+ * Func: Perform the actual memory dump.  This walks through the
+ *       memory pages and dumps the data to disk (using other functions).
+ *
+ * Returns:
+ *	-1: failed
+ *	 0: dump truncated	
+ *	 1: success
+ */
+static int
+dump_execute_memdump(void)
+{
+	int counter = 0, n_bytes = 0, i;
+	unsigned long buf_loc;
+	u64 mem_loc;
+	int dump_truncated = 0;
+	int pass = 0;
+
+	DUMP_PRINTN("Compression value is 0x%x, Writing dump header ", dump_compress);
+
+	/* update the header to disk the first time */
+	n_bytes = dump_write_header();
+	DUMP_PRINT("\n");
+
+	if (n_bytes < 0) {
+		DUMP_PRINTF("Initial dump header update failed!\n");
+		return (-1);
+	} else if (n_bytes == 0) {
+		return (0);
+	}
+
+	/* if we only want the header, return */
+	if (dump_level & DUMP_LEVEL_HEADER) {
+		return (1);
+	}
+
+	/* set beginning offset to keep compats right with swap devices */
+	dump_fpos = DUMP_HEADER_OFFSET + DUMP_BUFFER_SIZE;
+
+	/* clear the dump page buffer */
+	memset(dump_page_buf, 0, DUMP_BUFFER_SIZE);
+
+	/* set the buffer location */
+	buf_loc = 0;
+
+	for (pass = 1; pass <= 4; pass++) {
+
+		if( (pass == 2) && dump_unreserved_mem == 0) {
+			 continue;
+		}
+		if( (pass == 3) && dump_unreferenced_mem == 0) {
+			 continue;
+		}
+		if (pass == 4) { 
+			if (dump_nonconventional_mem == 0) break;
+			if (dump_mbanks == 1) break;				/* Contigious Mem Sys have 1 mbank */
+		} 
+		/* Algorithm suggested by Jack Steiner <steiner@sgi.com */
+		switch(pass) {
+			case 1:	DUMP_PRINTN("Pass 1: Saving Reserved Pages: "); 				break;
+			case 2:	DUMP_PRINTN("Pass 2: Saving Remaining Referenced Pages: "); 			break;
+			case 3:	DUMP_PRINTN("Pass 3: Saving Remaining Unreferenced Pages: ");			break;
+			case 4:	DUMP_PRINTN("Pass 4: Saving Unconventional Memory: ");				break;
+		}
+		for (i = 0; i < dump_mbanks; i++) {
+		  u64 mem_bank_start = dump_mbank[ i ].start;
+		  u64 mem_bank_end = dump_mbank[ i ].end;
+		  int type = dump_mbank[ i ].type;
+
+		  if ( (type != DUMP_MBANK_TYPE_CONVENTIONAL_MEMORY) && (pass != 4) ) continue;
+		  if ( (type == DUMP_MBANK_TYPE_CONVENTIONAL_MEMORY) && (pass == 4) ) continue;
+	
+		  DUMP_PRINTN("Memory Bank[%d]: " PU64X " ... " PU64X ": ", i, mem_bank_start, mem_bank_end);
+		  for (mem_loc = mem_bank_start; mem_loc < mem_bank_end; mem_loc += DUMP_PAGE_SIZE) {
+	
+			/* add the page (if it's real RAM) */
+			if (dump_add_page((mem_loc >> DUMP_PAGE_SHIFT), 
+						&buf_loc, pass)) {
+				/* didn't add a page to buffer */
+				continue;
+			}
+	
+			/* see if we've filled the buffer */
+			if (buf_loc >= DUMP_BUFFER_SIZE) {
+				int near_eof = 0;
+	
+				/* write out the dump page buffer */
+				n_bytes = dump_kernel_write(&near_eof);
+				if (n_bytes < 0) {
+					DUMP_PRINTN("Write of dump pages failed!");
+					return(-1);
+				} else if (n_bytes == 0) {
+					DUMP_PRINTN("EOF on Write of dump pages; dump terminated!");
+					return(0);
+				}
+				if( near_eof ) {
+					DUMP_PRINTN("Near EOF on Write of dump pages; truncating dump,");
+					dump_truncated = 1;
+				}
+	
+				/* bump the counter for writing out the header */
+				counter++;
+	
+				/*
+				 * Update the header every once in a while -- this
+				 * _must_ be done before we write the overflow end of
+				 * the dump_page_buf into the top of dump_page_buf,
+				 * as dump_write_header() uses dump_page_buf to
+				 * write the default/asm dump headers.  After we are
+				 * done updating the header, _then_ we can move the
+				 * leftover dump data into the top of dump_page_buf.
+				 *
+				 * NOTE: a period is printed to indicate that the header
+				 *	 was updated. Speedo shows page outactivity.
+				 */
+				if ((counter & 0x3f) == 0) {
+					n_bytes = dump_write_header();
+					if (n_bytes < 0) {
+						DUMP_PRINTN("Dump header update failed!");
+						return (-1);
+					} else if (n_bytes == 0) {
+						DUMP_PRINTN("Dump header update failed; bizzare");
+						return (0);
+					}
+					DUMP_PRINT(".");
+				} else {
+					if ((counter & 0x07) == 0) {
+						dump_speedo();
+					}
+				}
+	
+				/* clear the dump page buffer */
+				memset(dump_page_buf, 0, DUMP_BUFFER_SIZE);
+	
+				/* adjust leftover data back to the top of the page */
+				if (buf_loc > DUMP_BUFFER_SIZE) {
+	        			/* copy the dump page buffer remnants */
+	        			memcpy((void *)dump_page_buf,
+	                			(const void *)(dump_page_buf +
+							DUMP_BUFFER_SIZE),
+	                			buf_loc - DUMP_BUFFER_SIZE);
+	
+	        			/* set the new buffer location */
+	        			buf_loc -= DUMP_BUFFER_SIZE;
+				} else {
+					/* reset the buffer location counter */
+					buf_loc = 0;
+				}
+			}
+			if (dump_truncated) {
+				break;
+			}
+		    }
+		    DUMP_PRINT(" ");	
+		    if (dump_truncated) {
+			break;
+		    }
+		}
+		if (dump_truncated) {
+			break;
+		}
+		DUMP_PRINT("\n");
+	}
+
+	/* 
+	 * we have written out most of the dump pages, a few may still be in the
+	 * page buffer and it's possible we had to truncate the dump because we
+	 * got very close to the end of the dump partition. Now we add a EOF
+	 * marker to the page out buffer and flush out the remaining pages.
+	 *
+	 * We need to write the DUMP_DH_END even for truncated data because
+	 * the reader won't get an EOF if he reads the data in smaller chunks
+	 * than the DUMP_BUFFER_SIZE it's written in.
+	 */
+	if (dump_truncated) {
+		dump_add_end_marker(&buf_loc, (DUMP_DH_END | DUMP_DH_TRUNCATED));
+	} else {
+		dump_add_end_marker(&buf_loc, DUMP_DH_END);
+	}
+	n_bytes = dump_kernel_write(NULL);
+
+	if (n_bytes < 0) {
+                DUMP_PRINTN("Final write of last of page buffer and DUMP_DH_END failed!");
+                return (-1);
+        } else if (n_bytes == 0) {
+		DUMP_PRINTN("Hit EOF writing DUMP_DH_END; bad luck\n");
+                return (0);
+        }
+
+	/*
+	 * Writing out DUMP_DH_END may have pushed us past the end of the first
+	 * part of the page buffer, if it did we have to write out one last 
+	 * DUMP_BUFFER with the spill over page.
+	 */
+	if (buf_loc > DUMP_BUFFER_SIZE) {
+		/* clear the first part of the buffer */
+		memset(dump_page_buf, 0, DUMP_BUFFER_SIZE);
+
+		/*
+		 * Copy the dump page buffer remnants in the second 
+		 * part of the buffer to the first part.
+		 */
+		memcpy((void *)dump_page_buf,
+			(const void *)(dump_page_buf + DUMP_BUFFER_SIZE),
+			buf_loc - DUMP_BUFFER_SIZE);
+
+		n_bytes = dump_kernel_write(NULL);
+		if (n_bytes < 0) {
+			DUMP_PRINTN("Final write of spillover page failed!");
+			return (-1);
+		} else if (n_bytes == 0) {
+			DUMP_PRINTN("Hit EOF writing spill over page with DUMP_DH_END; very bad luck!\n");
+			return (0);
+		}
+	}
+	if (dump_truncated) {
+		return(0);
+	}
+	/* success */
+	return (1);
+}
+
+/*
+ * Name: dump_execute()
+ * Func: Execute the dumping process.  This makes sure all the appropriate
+ *       fields are updated correctly, and calls dump_execute_memdump(),
+ *       which does the real work.
+ * 
+ * if( dump_flags & DUMP_FLAGS_NONDISRUPT ) {
+ *    Returns:
+ *      -1: failed
+ *       0: dump truncated
+ *       1: success
+ * }
+ */
+int
+dump_execute(char *panic_str, struct pt_regs *regs)
+{
+	int state = 1;
+
+	/* make sure we can dump */
+	if (dump_okay == FALSE) {
+		return(-1);
+	}
+
+	if(!dump_configure_header(panic_str, regs)) {
+		DUMP_PRINTN("dump header could not be configured!");
+		return(-1);
+	}
+
+	/* silence the system */
+	dump_silence_system();
+
+	/* tell interested parties that a dump is happening */
+	notifier_call_chain(&dump_notifier_list, DUMP_BEGIN, &dump_device);
+
+	/* bail out if we're not going to do any dumping */
+	if (dump_level != DUMP_LEVEL_NONE) {
+		/* inform users of what we are about to do */
+		DUMP_PRINTN("Dumping to device 0x%x [%s] on CPU %d ...",
+			dump_device, bdevname(dump_device),
+			smp_processor_id());
+
+		/* start walking through the page tables */
+		state = dump_execute_memdump();
+
+		DUMP_PRINT("\n");
+
+		/* update header to disk for the last time */
+		if (dump_write_header() < 0) {
+			DUMP_PRINTF("Final dump header update failed!\n");
+		}
+
+		if (state < 0) {
+			DUMP_PRINTF("Dump Failed!\n");
+		} else if (state == 0) {
+			DUMP_PRINTF("Dump Truncated (likely out of space).\n");
+		} else {
+			DUMP_PRINTF("Dump Complete; %d dump pages saved.\n", dump_header.dh_num_dump_pages);
+		}
+	}
+
+	/* tell interested parties that a dump has completed */
+	notifier_call_chain(&dump_notifier_list, DUMP_END, &dump_device);
+
+	/* put the system state back */
+	dump_resume_system();
+
+	return (state);
+}
+
+/*
+ * Name: dump_register_compression()
+ * Func: Register a dump compression mechanism.
+ */
+void
+dump_register_compression(dump_compress_t *item)
+{
+	/* let's make sure our list is valid */
+	if (!item) {
+		return;
+	}
+
+	/* add our item */
+	list_add(&(item->list), &dump_compress_list);
+
+	/* print information to callers */
+	DUMP_PRINTF("Registering dump compression type 0x%x\n", item->compress_type);
+}
+
+/*
+ * Name: dump_unregister_compression()
+ * Func: Remove a dump compression mechanism, and re-assign the dump
+ *       compression pointer if necessary.
+ */
+void
+dump_unregister_compression(int compression_type)
+{
+	struct list_head *tmp;
+	dump_compress_t *dc;
+
+	/* let's make sure our list is valid */
+	if (compression_type == DUMP_COMPRESS_NONE) {
+		DUMP_PRINTN("Compression list is invalid!");
+		return;
+	}
+
+	/* try to remove the compression item */
+	list_for_each(tmp, &dump_compress_list) {
+		dc = list_entry(tmp, dump_compress_t, list);
+		if (dc->compress_type == compression_type) {
+			list_del(&(dc->list));
+			DUMP_PRINTN("De-registering dump compression type 0x%x\n",
+				compression_type);
+			return;
+		}
+	}
+}
+
+/*
+ * Name: dump_compress_init()
+ * Func: Initialize (or re-initialize) compression scheme.
+ */
+static int
+dump_compress_init(int compression_type)
+{
+	struct list_head *tmp;
+	dump_compress_t *dc;
+
+	/* try to remove the compression item */
+	list_for_each(tmp, &dump_compress_list) {
+		dc = list_entry(tmp, dump_compress_t, list);
+		if (dc->compress_type == compression_type) {
+			dump_compress_func = dc->compress_func;
+			dump_compress = compression_type;
+
+			DUMP_PRINTF("dump_compress = %d\n", dump_compress);
+			DUMP_BP();
+			return (0);
+		}
+	}
+
+	/* 
+	 * nothing on the list -- return ENODATA to indicate an error 
+	 *
+	 * NB: 
+	 *	EAGAIN: reports "Resource temporarily unavailable" which
+	 *		isn't very enlightening.
+	 */
+	DUMP_PRINTF("compression_type:%d not found\n", compression_type);
+	DUMP_BP();
+
+	return (-ENODATA);
+}
+
+void dump_iobuf_end_io(struct kiobuf *iobuf)
+{
+	/* No wakeup needed since we've stopped scheduling */
+	return;
+}
+/*
+ * Name: dump_open_kdev()
+ * Func: Try to open the kdev_t argument as the real dump device.
+ *       This is where all the work is done for setting up the dump
+ *       device.  It's assumed at this point that by passing in the
+ *       dump device's major/minor number, we can open it up, check
+ *       it out, and use it for whatever purposes.
+ */
+static int
+dump_open_kdev(kdev_t tmp_dump_device)
+{
+	int i;
+	unsigned long a;
+	unsigned long dump_page_addr;
+
+	/* make sure this is a valid block device */
+	if (!tmp_dump_device) {
+		return (-EINVAL);
+	}
+
+	/* we'd better have a name here, or this isn't valid ... */
+	if (!get_blkfops(MAJOR(tmp_dump_device))) {
+		return (-ENODEV);
+	}
+
+	/* if this is the second call to this function, clean up ... */
+	if ((dump_okay == TRUE) && (dump_page_buf_0 != (void *)NULL)) {
+		kfree((const void *)dump_page_buf_0);
+	}
+
+	/* 
+	 * Allocate buffer to be used for copying pages (only once ...) 
+	 *
+	 * An extra:
+	 *	 2 * DUMP_PAGE_SIZE:
+	 * 		is needed for the page overflow of last page, it's page header
+	 * 		and the EOF page header.
+	 *
+	 * and an  extra:
+	 *	1 * PAGE_SIZE:
+	 *		is needed for rounding up the start of the dump_page_buf to
+	 *		a system page (PAGE_SIZE) boundry.
+	 * 
+	 */
+	dump_page_buf = dump_page_buf_0 = (void *)kmalloc(
+						DUMP_BUFFER_SIZE + (DUMP_PAGE_SIZE * 2) + PAGE_SIZE,
+						GFP_KERNEL);
+
+
+	if (dump_page_buf_0 == (void *)0) {
+		DUMP_PRINTF("Cannot kmalloc() dump page buffer!\n");
+		dump_okay = FALSE;
+		return (-ENOMEM);
+	}
+
+	/*
+	 * Allocate our kiobuf -- we used to do this in dump_execute(),
+	 * but since the memory allocation schemes and the kiobuf code
+	 * keeps changing out underneath us, we'll do it when we open
+	 * up the dump device.
+	 */
+	dump_iobuf = (struct kiobuf *)NULL;
+
+	/* allocate a new one for use */
+	if (alloc_kiovec(1, &dump_iobuf)) {
+		DUMP_PRINTF("alloc_kiovec() call failed!\n");
+		dump_okay = FALSE;
+		return (-ENOMEM);
+	}
+
+	/* align the dump page addresses */
+	dump_page_addr = (unsigned long) dump_page_buf;
+	if (dump_page_addr % PAGE_SIZE) {
+		dump_page_buf = (void *) PAGE_ALIGN(dump_page_addr);
+	}
+
+	a = (unsigned long) dump_page_buf;
+	/* get the base address, and copy the number of total pages */
+	for (i = 0; i < (DUMP_BUFFER_SIZE >> PAGE_SHIFT); i++, a += PAGE_SIZE) {
+		dump_iobuf->maplist[i] = (struct page *)virt_to_page(a);
+	}
+	dump_iobuf->locked = 1;
+	dump_iobuf->offset = 0;
+	dump_iobuf->length = DUMP_BUFFER_SIZE;
+	dump_iobuf->nr_pages = (DUMP_BUFFER_SIZE >> PAGE_SHIFT);
+	dump_iobuf->end_io = dump_iobuf_end_io;
+
+	/* assign the new dump file structure */
+	dump_device = tmp_dump_device;
+	memcpy(dumpdev_name, bdevname(dump_device), PATH_MAX);
+
+	/* set the sector size information */
+	dump_blk_size = PAGE_SIZE;
+	set_blocksize(dump_device, dump_blk_size);
+
+	/* set the sector bits */
+	i = dump_blk_size;
+	for (dump_blk_shift = 0; !(i & 1);) {
+		i >>= 1, dump_blk_shift++;
+	}
+	 DUMP_PRINTF("dump_blk_shift:%d,  PAGE_SHIFT:%d\n", 
+		      dump_blk_shift,     PAGE_SHIFT);
+
+	/* set the dump okay flag to 1, the dump device is valid */
+	dump_okay = TRUE;
+
+	DUMP_PRINTN("dump device 0x%x opened; Ready to take a save a core dump\n", dump_device);
+
+	/* after opening the block device, return */
+	return (0);
+}
+
+/*
+ * Name: dump_release()
+ * Func: Release the dump device -- it's never necessary to call
+ *       this function, but it's here regardless.
+ */
+static int
+dump_release(struct inode *i, struct file *f)
+{
+	return (0);
+}
+
+/*
+ * Name: dump_ioctl()
+ * Func: Allow all dump tunables through a standard ioctl() mechanism.
+ *       This is far better than before, where we'd go through /proc,
+ *       because now this will work for multiple OS and architectures.
+ */
+static int
+dump_ioctl(struct inode *i, struct file *f,
+	unsigned int cmd, unsigned long arg)
+{
+	/* check capabilities */
+	if (!capable(CAP_SYS_ADMIN)) {
+		return (-EPERM);
+	}
+
+	/*
+	 * This is the main mechanism for controlling get/set data
+	 * for various dump device parameters.  The real trick here
+	 * is setting the dump device (DIOSDUMPDEV).  That's what
+	 * triggers everything else.
+	 */
+	switch (cmd) {
+		/* set dump_device */
+		case DIOSDUMPDEV:
+			/* check flags */
+			if (!(f->f_flags & O_RDWR)) {
+				return (-EPERM);
+			}
+			__dump_open();
+			return (dump_open_kdev((kdev_t)arg));
+
+		/* get dump_device */
+		case DIOGDUMPDEV:
+			return (put_user((long)dump_device, (long *)arg));
+
+		/* set dump_level */
+		case DIOSDUMPLEVEL:
+			/* check flags */
+			if (!(f->f_flags & O_RDWR)) {
+				return (-EPERM);
+			}
+			/* make sure we have a positive value */
+			if (arg < 0) {
+				return (-EINVAL);
+			}
+			dump_level = (int)arg;
+
+			/*
+			 * REMIND: Still in development:
+			 *
+			 *	We will consider reserved pages a initial proxy for kernel pages.
+			 */
+			if (dump_level > DUMP_LEVEL_KERN) {
+				dump_unreserved_mem = 1;
+			} else {
+				dump_unreserved_mem = 0;
+			}
+
+			/*
+			 * REMIND: Still in development:
+			 *
+			 * 	Using refcount > 1 as a proxy for kernel & user pages.
+			 */
+			if (dump_level > DUMP_LEVEL_USED) {
+				dump_unreferenced_mem = 1;
+			} else {
+				dump_unreferenced_mem = 0;
+			}
+
+			/*
+			 *  REMIND: Still in development:
+			 *
+			 *	This may not be 100% stable on all ia64
+			 *	memory banks. Accessing uncached memory
+			 *	with cached accesses can cause subsequent
+			 *	bus errors when the cache is flushed.
+			 */
+			if( dump_level > DUMP_LEVEL_ALL_RAM ) {
+				dump_nonconventional_mem = 1;
+			} else {
+				dump_nonconventional_mem = 0;
+			}
+			break;
+
+		/* get dump_level */
+		case DIOGDUMPLEVEL:
+			return (put_user((long)dump_level, (long *)arg));
+
+		/* set dump_flags */
+		case DIOSDUMPFLAGS:
+			/* check flags */
+			if (!(f->f_flags & O_RDWR)) {
+				return (-EPERM);
+			}
+			/* make sure we have a positive value */
+			if (arg < 0) {
+				return (-EINVAL);
+			}
+			dump_flags = (int)arg;
+			break;
+
+		/* get dump_flags */
+		case DIOGDUMPFLAGS:
+			return (put_user((long)dump_flags, (long *)arg));
+
+		/* set the dump_compress status */
+		case DIOSDUMPCOMPRESS:
+			/* check flags */
+			if (!(f->f_flags & O_RDWR)) {
+				return (-EPERM);
+			}
+			return (dump_compress_init((int)arg));
+
+		/* get the dump_compress status */
+		case DIOGDUMPCOMPRESS:
+			return (put_user((long)dump_compress, (long *)arg));
+
+#if DUMP_DEBUG
+		case DIODUMPTEST:
+		/*
+		 * The lkcd_config cmd has a -t option available for testing dump
+		 * when DUMP_DEBUG is defined in dump.h. The -t option is followed
+		 * by a string that is parsed here.
+		 *
+		 * A string compare is used instead of more DUMP constants to make 
+		 * it easy to add new options quickley while debugging the dump driver.
+		 */
+		if (dump_okay) {
+			int saved_dump_flags = dump_flags;
+			char *bogus_pointer = 0;
+			char bogus_data;
+			char buffer[128];
+			int dumps_wanted = 0;
+			int stop_wanted = 0;
+			int tlb_flush_wanted = 0;
+			char *dump_test = "test";
+			int success;
+	
+			unlock_kernel();
+			if( ((caddr_t) arg) == NULL ) {
+				DUMP_PRINTF("arg == NULL; default test is to do nothing");
+				return (0);
+			} else {
+				/*
+				 * These functions are suppose to be dynamic and configurable
+				 * for your current needs; no sweet if you check in whats
+				 * currently usefull for you. Perhaps it should be checked in empty
+				 * while no new platforms are being worked on.
+				 */
+				if (strncpy_from_user(&buffer[0], (char *)arg, sizeof(buffer) - 1) < 0) {
+					DUMP_PRINTF("strncpy_from_user() failed\n");
+		                        return( -EFAULT );
+		                }
+				if (strncmp(&buffer[0], "panic", sizeof(buffer)) == 0) {
+					dump_flags |= DUMP_FLAGS_NONDISRUPT;
+					panic("test panic and dump");
+					/* NOTREACHED */
+				}
+				if (strncmp(&buffer[0], "dump", sizeof(buffer)) == 0) {		/* dump */
+					dumps_wanted = 1;
+					dump_test = "test dump";
+				}
+#ifdef CONFIG_SMP
+				if (strncmp(&buffer[0], "stop", sizeof(buffer)) == 0) {
+					dumps_wanted = 1;
+					stop_wanted = 1;
+					dump_test = "test dump with cpu's stopped";
+				}
+				if (strncmp(&buffer[0], "flush", sizeof(buffer)) == 0) {	/* OK */
+					dumps_wanted = 1;
+					tlb_flush_wanted = 1;
+					dump_test = "test dump with cpu TLB's flushed";
+				}
+#endif
+				if (strncmp(&buffer[0], "trap", sizeof(buffer)) == 0) {		/* OK */
+					*(int *)0 = 0;
+					DUMP_PRINTF("*(int *)0 = 0; should have cause a trap and died");
+					bogus_data =  *bogus_pointer;
+					DUMP_PRINTF("*bogus_pointer; should have taken a trap and died");
+					BUG();
+					return( -EFAULT );
+				}
+				if (strncmp(&buffer[0], "forever", sizeof(buffer)) == 0) {	/* OK */
+					dumps_wanted = 0XEFFF;
+					dump_test = "test dump forever";
+				}
+			}
+			if (dumps_wanted) {
+				int dumps = 0;
+
+				dump_flags |= DUMP_FLAGS_NONDISRUPT;
+				/*
+				 * REMIND: How to break loop on intr/<ctrl-Z> ?
+				 */
+				do {
+
+#if defined(CONFIG_SMP) && defined(CONFIG_IA64_SGI_SN1)
+					if( stop_wanted ) {
+						smp_send_stop();
+					}
+					if( tlb_flush_wanted ) {
+						extern void smp_send_flush_tlb(void);
+
+						smp_send_flush_tlb();
+					}
+#endif
+					success = dump_execute(dump_test, NULL);
+					dumps++;
+					DUMP_PRINTF("Test '%s': success:%d, dumps:%d\n", dump_test, success, dumps);
+				} while (success && (dumps < dumps_wanted));
+
+				DUMP_PRINTF("success:%d\n", success);
+				dump_flags = saved_dump_flags;
+
+				if( dumps >= dumps_wanted ) {
+					return ( 0 );
+				} else {
+					return ( -EINTR );
+				}
+			}
+			DUMP_PRINTF("Test '%s' not known.\n", &buffer[0]);
+			return( -ENOSYS );
+		} else {
+			/* doing a panic when dump_okay == 0 is almost always a waste of time */
+			DUMP_PRINTF("dump_okay == 0 (Not ready to dump memory).\n");
+		}
+		break;
+#endif /* DUMP_DEBUG */
+	}
+	return (0);
+}
+
+/*
+ * Name: dump_open()
+ * Func: Open the dump device for use when the system crashes.
+ */
+static int
+dump_open(struct inode *i, struct file *f)
+{
+	/* opening a device is straightforward -- nothing to do here */
+	return (0);
+}
+
+/*
+ * -----------------------------------------------------------------------
+ *                     I N I T   F U N C T I O N S
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * Name: dump_init_proc_entry()
+ * Func: Create a dump proc entry based on the /proc dump root.
+ *       Returns 1 on failure, 0 on success.
+ */
+int
+dump_init_proc_entry(char *name, struct proc_dir_entry *dirent)
+{
+	if (!(dirent = create_proc_entry(name,
+		S_IFREG|S_IRUGO|S_IWUSR, dump_root))) {
+			DUMP_PRINT("unable to initialize "
+				"/proc/%s/%s!\n", DUMP_ROOT_NAME, name);
+		return (1);
+	}
+	dirent->data = (void *)dirent;
+	dirent->read_proc = &dump_read_proc;
+	dirent->write_proc = NULL;
+	dirent->size = 16;
+	return (0);
+}
+
+/*
+ * Name: dump_proc_init()
+ * Func: Initialize the /proc interfaces for dumping.
+ * 
+ * Typically:
+ *	/proc/sys/dump/
+ *		dump_compress  dump_device  dump_flags  dump_level
+ */
+int
+dump_proc_init(void)
+{
+	/* create the proc entries for the various tunables */
+	dump_root = create_proc_entry(DUMP_ROOT_NAME, S_IFDIR, 0);
+	if (dump_root) {
+		dump_root->owner = THIS_MODULE;
+	} else {
+		DUMP_PRINTF("unable to initialize /proc/%s!\n", DUMP_ROOT_NAME);
+		return (-EBUSY);
+	}
+
+	if (dump_init_proc_entry(DUMP_DEVICE_NAME, dump_dd)) {
+		remove_proc_entry(DUMP_ROOT_NAME, 0);
+		return (-EBUSY);
+	}
+	if (dump_init_proc_entry(DUMP_LEVEL_NAME, dump_l)) {
+		remove_proc_entry(DUMP_ROOT_NAME, 0);
+		remove_proc_entry(DUMP_DEVICE_NAME, dump_root);
+		return (-EBUSY);
+	}
+	if (dump_init_proc_entry(DUMP_FLAGS_NAME, dump_f)) {
+		remove_proc_entry(DUMP_ROOT_NAME, 0);
+		remove_proc_entry(DUMP_DEVICE_NAME, dump_root);
+		remove_proc_entry(DUMP_LEVEL_NAME, dump_root);
+		return (-EBUSY);
+	}
+	if (dump_init_proc_entry(DUMP_COMPRESS_NAME, dump_cp)) {
+		remove_proc_entry(DUMP_ROOT_NAME, 0);
+		remove_proc_entry(DUMP_DEVICE_NAME, dump_root);
+		remove_proc_entry(DUMP_LEVEL_NAME, dump_root);
+		remove_proc_entry(DUMP_FLAGS_NAME, dump_root);
+		return (-EBUSY);
+	}
+	return (0);
+}
+
+/*
+ * Name: dump_proc_cleanup()
+ * Func: Cleanup the /proc interfaces for dumping.
+ */
+void
+dump_proc_cleanup(void)
+{
+	/* remove the proc entries */
+	remove_proc_entry(DUMP_DEVICE_NAME, dump_root);
+	remove_proc_entry(DUMP_LEVEL_NAME, dump_root);
+	remove_proc_entry(DUMP_FLAGS_NAME, dump_root);
+	remove_proc_entry(DUMP_COMPRESS_NAME, dump_root);
+	remove_proc_entry(DUMP_ROOT_NAME, 0);
+	return;
+}
+
+/*
+ * Name: dump_init()
+ * Func: Initialize the dump process.  This will set up any architecture
+ *       dependent code.  The big key is we need the memory offsets before
+ *       the page table is initialized, because the base memory offset
+ *       is changed after paging_init() is called.
+ */
+int
+dump_init(void)
+{
+	struct sysinfo info;
+	int i; 
+
+	/* try to initialize /proc interfaces */
+	if (dump_proc_init() < 0) {
+		DUMP_PRINTF("dump_proc_init failed!; dump not initialized\n");
+		return (-EBUSY);
+	}
+
+	/* try to create our dump device */
+	if (devfs_register_chrdev(DUMP_MAJOR, "dump", &dump_fops)) {
+		DUMP_PRINTF("cannot register dump character device!\n");
+		return (-EBUSY);
+	}
+
+	/* initialize the dump headers to zero */
+	memset(&dump_header, 0, sizeof(dump_header));
+	memset(&dump_header_asm, 0, sizeof(dump_header_asm));
+
+#if    !defined(CONFIG_DISCONTIGMEM) && !defined(CONFIG_IA64)
+	/* 
+	 * CONFIG_DISCONTIGMEM and CONFIG_IA64 systems are responsible 
+	 * for initializing dump_mbank[] in __dump_init().
+	 */
+	dump_mbanks = 1;
+	dump_mbank[ 0 ].start = 0;
+	dump_mbank[ 0 ].end  = (((u64) max_mapnr) << PAGE_SHIFT) - 1;
+	dump_mbank[ 0 ].type = DUMP_MBANK_TYPE_CONVENTIONAL_MEMORY;
+#endif
+
+	/* 
+	 * initialize the dump device at the arch level.
+ 	 *
+	 * if defined(CONFIG_DISCONTIGMEM) {
+	 *       __dump_init() must set up dump_mbank[].
+	 * }
+	 */
+	__dump_init((u64)PAGE_OFFSET);
+
+	/* initialize the dump page buffer */
+	dump_page_buf = (void *)0;
+
+	/* set the dump function pointer for dump execution */
+	dump_function_ptr = dump_execute;
+
+	/* set the dump_compression_list structure up */
+	dump_compress = DUMP_COMPRESS_NONE;
+	dump_compress_func = dump_compress_none;
+	dump_register_compression(&dump_none_compression);
+
+	/* initialize the dump flags, dump level and dump_compress fields */
+	dump_flags = DUMP_FLAGS_NONE;
+	dump_level = DUMP_LEVEL_ALL;
+
+	/* grab the total memory size now (not if/when we crash) */
+	si_meminfo(&info);
+
+	/* set the memory size */
+	dump_header.dh_memory_size = (u64)info.totalram;
+
+	for (i = 0; i < dump_mbanks; i++) {
+		DUMP_PRINTF("mbank[%d]: type:%d, phys_addr: " PU64X " ... " PU64X "\n",
+			i,
+			dump_mbank[i].type,
+			dump_mbank[i].start,
+			dump_mbank[i].end);
+
+		if (dump_mbank[i].start % DUMP_PAGE_SIZE) {
+			DUMP_PRINTF("oops, start is not DUMP_PAGE_SIZE:%x aligned!\n", (int) DUMP_PAGE_SIZE);
+		}
+		if ((dump_mbank[i].end + 1) % DUMP_PAGE_SIZE) {
+			DUMP_PRINTF("oops, end is not DUMP_PAGE_SIZE:%x aligned!\n", (int) DUMP_PAGE_SIZE);
+		}
+	}
+	DUMP_PRINTF("Crash dump driver initialized.\n");
+	return (0);
+}
+
+void
+dump_cleanup(void)
+{
+	/* get rid of the allocated dump page buffer */
+	if (dump_page_buf_0) {
+		kfree((const void *)dump_page_buf_0);
+	}
+
+	/* arch-specific cleanup routine */
+	__dump_cleanup();
+
+	/* remove the proc entries */
+	dump_proc_cleanup();
+
+	/* try to create our dump device */
+	if (devfs_unregister_chrdev(DUMP_MAJOR, "dump")) {
+		DUMP_PRINT("cannot unregister dump character device!\n");
+	}
+
+	/* reset the dump function pointer */
+	dump_function_ptr = NULL;
+
+	return;
+}
+
+EXPORT_SYMBOL(dump_register_compression);
+EXPORT_SYMBOL(dump_unregister_compression);
+
+#ifdef MODULE
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,16))
+#if !defined(MODULE_LICENSE)
+#define MODULE_LICENSE(str)
+#endif
+#endif
+
+MODULE_AUTHOR("Matt D. Robinson <yakker@sourceforge.net>");
+MODULE_DESCRIPTION("Linux Kernel Crash Dump (LKCD) driver");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,16))
+MODULE_LICENSE("GPL");
+#endif
+module_init(dump_init);
+module_exit(dump_cleanup);
+#endif /* MODULE */
diff -Naur linux-2.4.19.orig/drivers/dump/dump_gzip.c linux-2.4.19.lkcd/drivers/dump/dump_gzip.c
--- linux-2.4.19.orig/drivers/dump/dump_gzip.c	Thu Jan  1 05:00:00 1970
+++ linux-2.4.19.lkcd/drivers/dump/dump_gzip.c	Tue Nov 19 13:55:34 2002
@@ -0,0 +1,144 @@
+/*
+ * GZIP Compression functions for kernel crash dumps.
+ *
+ * Created by: Matt Robinson (yakker@sourceforge.net)
+ * Copyright 2001 Matt D. Robinson.  All rights reserved.
+ *
+ * This code is released under version 2 of the GNU GPL.
+ */
+
+/* header files */
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/dump.h>
+#include "dump_zlib.c"
+
+MODULE_AUTHOR("Matt D. Robinson <yakker@sourceforge.net>");
+MODULE_DESCRIPTION("GZIP Compression Module for LKCD");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,16))
+MODULE_LICENSE("GPL");
+#endif
+
+/*
+ * -----------------------------------------------------------------------
+ *                       D E F I N I T I O N S
+ * -----------------------------------------------------------------------
+ */
+#define DUMP_MODULE_NAME "dump_gzip"
+#define DUMP_PRINTN(format, args...) \
+	printk("%s: " format , DUMP_MODULE_NAME , ## args);
+#define DUMP_PRINT(format, args...) \
+	printk(format , ## args);
+
+/*
+ * Name: dump_compress_gzip_alloc()
+ * Func: The kmalloc function for gzip dump compression.
+ */
+static void *
+dump_compress_gzip_alloc(void *arg, unsigned int items, unsigned int size)
+{
+	return ((void *)kmalloc((size * items), GFP_ATOMIC));
+}
+
+/*
+ * Name: dump_compress_gzip_free()
+ * Func: The kfree function for gzip dump compression.
+ */
+static void
+dump_compress_gzip_free(void *arg, void *ptr)
+{
+	kfree(ptr);
+	return;
+}
+
+/*
+ * Name: dump_compress_gzip()
+ * Func: Compress a DUMP_PAGE_SIZE page using gzip-style algorithms (the.
+ *       deflate functions similar to what's used in PPP).
+ */
+static int
+dump_compress_gzip(char *old, int oldsize, char *new, int newsize)
+{
+	/* error code and dump stream */
+	int err;
+	z_stream dump_stream;
+
+	/* setup the alloc/free functions */
+	dump_stream.zalloc = dump_compress_gzip_alloc;
+	dump_stream.zfree = dump_compress_gzip_free;
+	dump_stream.opaque = (void *)0;
+
+	if ((err = deflateInit(&dump_stream, Z_BEST_COMPRESSION)) != Z_OK) {
+		/* fall back to RLE compression */
+		DUMP_PRINT("dump_compress_gzip(): deflateInit() "
+			"failed (%d)!\n", err);
+		return (0);
+	}
+
+	/* use old (page of memory) and size (DUMP_PAGE_SIZE) as in-streams */
+	dump_stream.next_in = old;
+	dump_stream.avail_in = oldsize;
+
+	/* out streams are new (dpcpage) and new size (DUMP_DPC_PAGE_SIZE) */
+	dump_stream.next_out = new;
+	dump_stream.avail_out = newsize;
+
+	/* deflate the page -- check for error */
+	err = deflate(&dump_stream, Z_FINISH);
+	if (err != Z_STREAM_END) {
+		/* zero is return code here */
+		(void)deflateEnd(&dump_stream);
+		DUMP_PRINT("dump_compress_gzip(): deflate() failed (%d)!\n",
+			err);
+		return (0);
+	}
+
+	/* let's end the deflated compression stream */
+	if ((err = deflateEnd(&dump_stream)) != Z_OK) {
+		DUMP_PRINT("dump_compress_gzip(): deflateEnd() "
+			"failed (%d)!\n", err);
+	}
+
+	/* return the compressed byte total (if it's smaller) */
+	if (dump_stream.total_out >= oldsize) {
+		return (oldsize);
+	}
+	return (dump_stream.total_out);
+}
+
+/* setup the gzip compression functionality */
+static dump_compress_t dump_gzip_compression = {
+	compress_type:	DUMP_COMPRESS_GZIP,
+	compress_func:	dump_compress_gzip,
+};
+
+/*
+ * Name: dump_compress_gzip_init()
+ * Func: Initialize gzip as a compression mechanism.
+ */
+int __init
+dump_compress_gzip_init(void)
+{
+	dump_register_compression(&dump_gzip_compression);
+	return (0);
+}
+
+/*
+ * Name: dump_compress_gzip_cleanup()
+ * Func: Remove gzip as a compression mechanism.
+ */
+void __init
+dump_compress_gzip_cleanup(void)
+{
+	dump_unregister_compression(DUMP_COMPRESS_GZIP);
+}
+
+/* module initialization */
+module_init(dump_compress_gzip_init);
+module_exit(dump_compress_gzip_cleanup);
diff -Naur linux-2.4.19.orig/drivers/dump/dump_i386.c linux-2.4.19.lkcd/drivers/dump/dump_i386.c
--- linux-2.4.19.orig/drivers/dump/dump_i386.c	Thu Jan  1 05:00:00 1970
+++ linux-2.4.19.lkcd/drivers/dump/dump_i386.c	Tue Nov 19 13:49:50 2002
@@ -0,0 +1,316 @@
+/*
+ * Architecture specific (i386) functions for Linux crash dumps.
+ *
+ * Created by: Matt Robinson (yakker@sgi.com)
+ *
+ * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
+ *
+ * 2.3 kernel modifications by: Matt D. Robinson (yakker@turbolinux.com)
+ * Copyright 2000 TurboLinux, Inc.  All rights reserved.
+ * 
+ * This code is released under version 2 of the GNU GPL.
+ */
+
+/*
+ * The hooks for dumping the kernel virtual memory to disk are in this
+ * file.  Any time a modification is made to the virtual memory mechanism,
+ * these routines must be changed to use the new mechanisms.
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/dump.h>
+#include <linux/mm.h>
+#include <asm/processor.h>
+#include <asm/hardirq.h>
+#include <linux/irq.h>
+
+static int alloc_dha_stack(void)
+{
+	int i;
+	void *ptr;
+	
+	if (dump_header_asm.dha_stack[0])
+		return 0;
+
+       	ptr = vmalloc(THREAD_SIZE * smp_num_cpus);
+	if (!ptr) {
+		printk("vmalloc for dha_stacks failed\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < smp_num_cpus; i++) {
+		dump_header_asm.dha_stack[i] = (void *)((unsigned long)ptr + (i * THREAD_SIZE));
+	}
+	return 0;
+}
+
+static int free_dha_stack(void) 
+{
+	if (dump_header_asm.dha_stack[0])
+		vfree(dump_header_asm.dha_stack[0]);	
+	return 0;
+}
+
+/* In case of panic dumps, we collects regs on entry to panic.
+ * so, we shouldn't 'fix' ssesp here again. But it is hard to
+ * tell just looking at regs whether ssesp need fixing. We make
+ * this decision by looking at xss in regs. If we have better
+ * means to determine that ssesp are valid (by some flag which
+ * tells that we are here due to panic dump), then we can use
+ * that instead of this kludge.
+ */
+static inline void 
+fix_ssesp(struct pt_regs *regs, int cpu)
+{
+	if (!user_mode(regs)) {
+		if ((cpu == dump_header_asm.dha_dumping_cpu) &&
+			regs->xss == __KERNEL_DS) 
+			return;
+		dump_header_asm.dha_smp_regs[cpu].esp = 
+				(unsigned long)&(regs->esp);
+		__asm__ __volatile__ ("movw %%ss, %%ax;"
+			:"=a"(dump_header_asm.dha_smp_regs[cpu].xss));
+	}
+}
+
+static void
+save_this_cpu_state(int cpu, struct pt_regs *regs, struct task_struct *tsk)
+{
+	dump_header_asm.dha_smp_regs[cpu] = *regs;
+	dump_header_asm.dha_smp_current_task[cpu] = tsk;
+	fix_ssesp(regs, cpu);
+
+	if (dump_header_asm.dha_stack[cpu]) {
+		memcpy(dump_header_asm.dha_stack[cpu], tsk, THREAD_SIZE);
+	}
+	return;
+}
+
+#ifdef CONFIG_SMP
+static int dump_expect_ipi[NR_CPUS];
+static atomic_t waiting_for_dump_ipi;
+static int wait_for_dump_ipi = 1; /* always wait for ipi to to be handled */
+extern void (*dump_trace_ptr)(struct pt_regs *);
+static unsigned long saved_affinity[NR_IRQS];
+
+static int
+dump_ipi_handler(struct pt_regs *regs) 
+{
+	int cpu = smp_processor_id();
+
+	if (!dump_expect_ipi[cpu]) {
+		return 0;
+	}
+	
+	save_this_cpu_state(cpu, regs, current);
+
+	dump_expect_ipi[cpu] = 0;
+	atomic_dec(&waiting_for_dump_ipi);
+	return 1;
+}
+
+/* save registers on other processors */
+void 
+save_other_cpu_states(void)
+{
+	int i;
+
+	if (smp_num_cpus > 1) {
+		atomic_set(&waiting_for_dump_ipi, smp_num_cpus-1);
+		for (i = 0; i < NR_CPUS; i++)
+			dump_expect_ipi[i] = 1;
+		
+		dump_ipi_function_ptr = dump_ipi_handler;
+		dump_send_ipi();
+		/* may be we dont need to wait for NMI to be processed. 
+		   just write out the header at the end of dumping, if
+		   this IPI is not processed untill then, there probably
+		   is a problem and we just fail to capture state of 
+		   other cpus. */
+		if (wait_for_dump_ipi) {
+			while(atomic_read(&waiting_for_dump_ipi))
+				barrier();
+			dump_ipi_function_ptr = NULL;
+		}
+	}
+	return;
+}
+
+/* located in arch/i386/kernel/traps.c */
+extern void show_this_cpu_state(int cpu, struct pt_regs * regs, struct task_struct *tsk);
+
+void 
+show_cpu_state(struct pt_regs * regs)
+{
+	int i;
+	__dump_configure_header(regs);	
+	for (i = 0; i < smp_num_cpus; i++) {
+		show_this_cpu_state(i, &dump_header_asm.dha_smp_regs[i], 
+			dump_header_asm.dha_stack[i]);
+	}
+	return;
+}
+
+/*
+ * Non dumping cpus will spin here. If a cpu is handling an irq when ipi is
+ * received, we let go of it here while making sure that it hits schedule
+ * on the way up and make it spin there instead.
+ */
+static void
+__dump_spin(void *arg)
+{
+	if (in_irq()) {
+		current->need_resched = 1;
+	} else {
+		while (dump_in_progress) ;
+	}
+	return;
+}
+
+/*
+ * Routine to save the old irq affinities and change affinities of all irqs to
+ * the dumping cpu.
+ */
+static void
+__dump_set_irq_affinity(void)
+{
+	int i;
+	int cpu = smp_processor_id();
+
+	memcpy(saved_affinity, irq_affinity, NR_IRQS * sizeof(unsigned long));
+	for (i = 0; i < NR_IRQS; i++) {
+		if (irq_desc[i].handler == NULL)
+			continue;
+		irq_affinity[i] = 1UL << cpu;
+		if (irq_desc[i].handler->set_affinity != NULL)
+			irq_desc[i].handler->set_affinity(i, irq_affinity[i]);
+	}
+}
+
+/*
+ * Restore old irq affinities.
+ */
+static void
+__dump_reset_irq_affinity(void)
+{
+	int i;
+
+	memcpy(irq_affinity, saved_affinity, NR_IRQS * sizeof(unsigned long));
+	for (i = 0; i < NR_IRQS; i++) {
+		if (irq_desc[i].handler == NULL)
+			continue;
+		if (irq_desc[i].handler->set_affinity != NULL)
+			irq_desc[i].handler->set_affinity(i, saved_affinity[i]);
+	}
+}
+
+#else /* !CONFIG_SMP */
+#define save_other_cpu_states()
+#endif /* !CONFIG_SMP */
+
+/*
+ * Name: __dump_silence_system()
+ * Func: Do an architecture-specific silencing of the system.
+ *     - Change irq affinities
+ *     - Wait for other cpus to come out of irq handling
+ *     - Send CALL_FUNCTION_VECTOR ipi to other cpus to put them to spin
+ */
+unsigned int
+__dump_silence_system(unsigned int stage)
+{
+#ifdef CONFIG_SMP
+	if (stage) {	/* Do this after interrupts are enabled */
+		/* read the comments above ... */
+		__dump_set_irq_affinity();
+		synchronize_irq();
+		smp_call_function(__dump_spin, NULL, 0, 0);
+	}
+#endif
+
+	/* return */
+	return (0);
+}
+
+/*
+ * Name: __dump_resume_system()
+ * Func: Resume the system state in an architecture-specific way.
+ */
+unsigned int
+__dump_resume_system(unsigned int stage)
+{
+#ifdef CONFIG_SMP
+	/* put the irq affinity tables back */
+	__dump_reset_irq_affinity();
+#endif
+
+	/* return */
+	return (0);
+}
+
+/*
+ * Name: __dump_configure_header()
+ * Func: Configure the dump header with all proper values.
+ */
+int
+__dump_configure_header(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+
+	dump_header_asm.dha_smp_num_cpus = smp_num_cpus;
+	dump_header_asm.dha_dumping_cpu = cpu;
+
+	save_this_cpu_state(cpu, regs, current);
+
+	save_other_cpu_states();
+
+	return (1);
+}
+
+/*
+ * Name: __dump_init()
+ * Func: Initialize the dumping routine process.  This is in case
+ *       it's necessary in the future.
+ */
+void
+__dump_init(uint64_t local_memory_start)
+{
+	/* return */
+	return;
+}
+
+/*
+ * Name: __dump_open()
+ * Func: Open the dump device (architecture specific).  This is in
+ *       case it's necessary in the future.
+ */
+void
+__dump_open(void)
+{
+	alloc_dha_stack();
+#ifdef CONFIG_SMP	
+	dump_trace_ptr = show_cpu_state;
+#endif
+	/* return */
+	return;
+}
+
+/*
+ * Name: __dump_cleanup()
+ * Func: Free any architecture specific data structures. This is called
+ *       when the dump module is being removed.
+ */
+void
+__dump_cleanup(void)
+{
+	free_dha_stack();
+#ifdef CONFIG_SMP
+	dump_trace_ptr = NULL;
+#endif
+	/* return */
+	return;
+}
+
diff -Naur linux-2.4.19.orig/drivers/dump/dump_ia64.c linux-2.4.19.lkcd/drivers/dump/dump_ia64.c
--- linux-2.4.19.orig/drivers/dump/dump_ia64.c	Thu Jan  1 05:00:00 1970
+++ linux-2.4.19.lkcd/drivers/dump/dump_ia64.c	Tue Nov 19 13:49:50 2002
@@ -0,0 +1,382 @@
+/*
+ * Architecture specific (ia64) functions for Linux crash dumps.
+ *
+ * Created by: Matt Robinson (yakker@sgi.com)
+ * Contributions from SGI, IBM, and others.
+ *
+ * 2.4  kernel modifications by:  Matt D. Robinson (yakker@alacritech.com)
+ * ia64 kernel modifications by: Piet Delaney (piet@www.piet.net)
+ *
+ * Copyright (C) 2001 - 2002 Matt D. Robinson (yakker@alacritech.com)
+ * Copyright (C) 2002 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2002 Free Software Foundation, Inc. All rights reserved.
+ *
+ * This code is released under version 2 of the GNU GPL.
+ */
+
+/*
+ * The hooks for dumping the kernel virtual memory to disk are in this
+ * file.  Any time a modification is made to the virtual memory mechanism,
+ * these routines must be changed to use the new mechanisms.
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/fs.h>
+#include <linux/vmalloc.h>
+#include <linux/dump.h>
+#include <linux/mm.h>
+#include <asm/processor.h>
+#include <asm/hardirq.h>
+#include <linux/irq.h>
+
+extern unsigned long irq_affinity[];
+
+/* static variables */
+static dump_header_asm_t dump_header_asm;
+static unsigned long saved_affinity[NR_IRQS];
+
+static int alloc_dha_stack(void)
+{
+	int i;
+	void *ptr;
+	
+	if (dump_header_asm.dha_stack[0])
+		return 0;
+
+       	ptr = vmalloc(THREAD_SIZE * smp_num_cpus);
+	if (!ptr) {
+		printk("vmalloc for dha_stacks failed\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < smp_num_cpus; i++) {
+		dump_header_asm.dha_stack[i] = (void *)((unsigned long)ptr + (i * THREAD_SIZE));
+	}
+	return 0;
+}
+
+static int free_dha_stack(void) 
+{
+	if (dump_header_asm.dha_stack[0])
+		vfree(dump_header_asm.dha_stack[0]);
+
+	return 0;
+}
+
+static void
+save_this_cpu_state(int cpu, struct pt_regs *regs, struct task_struct *tsk)
+{
+	if( regs ) {
+		dump_header_asm.dha_smp_regs[cpu] = *regs;
+	}
+	dump_header_asm.dha_smp_current_task[cpu] = tsk;
+
+	if (tsk && dump_header_asm.dha_stack[cpu]) {
+		memcpy(dump_header_asm.dha_stack[cpu], tsk, THREAD_SIZE);
+	}
+	return;
+}
+
+#ifdef CONFIG_SMP
+static int dump_expect_ipi[NR_CPUS];
+static atomic_t waiting_for_dump_ipi;
+static int wait_for_dump_ipi = 1; 			/* always wait for ipi to to be handled */
+extern void (*dump_trace_ptr)(struct pt_regs *);
+
+static int
+dump_ipi_handler(struct pt_regs *regs) 
+{
+	int cpu = smp_processor_id();
+
+	if (!dump_expect_ipi[cpu]) {
+		return 0;
+	}
+	
+	save_this_cpu_state(cpu, regs, current);
+
+	dump_expect_ipi[cpu] = 0;
+	atomic_dec(&waiting_for_dump_ipi);
+	return 1;
+}
+
+/* save registers on other processors */
+void 
+save_other_cpu_states(void)
+{
+	int i;
+
+	if (smp_num_cpus > 1) {
+		atomic_set(&waiting_for_dump_ipi, smp_num_cpus-1);
+		for (i = 0; i < NR_CPUS; i++)
+			dump_expect_ipi[i] = 1;
+		
+		dump_ipi_function_ptr = dump_ipi_handler;
+		dump_send_ipi();
+		/* 
+		 * may be we dont need to wait for NMI to be processed. 
+		 * just write out the header at the end of dumping, if
+		 * this IPI is not processed untill then, there probably
+		 * is a problem and we just fail to capture state of 
+		 * other cpus. 
+		 */
+		if (wait_for_dump_ipi) {
+			while(atomic_read(&waiting_for_dump_ipi))
+				barrier();
+
+			dump_ipi_function_ptr = NULL;
+		}
+	}
+	return;
+}
+
+#else
+#define save_other_cpu_states()
+#endif
+
+/*
+ * Name: __dump_configure_header()
+ * Func: Configure the dump header with all proper values.
+ */
+int
+__dump_configure_header(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+
+	/* flush the dirty registers to backing store */
+	asm("flushrs");
+
+	dump_header_asm.dha_smp_num_cpus = smp_num_cpus;
+	dump_header_asm.dha_dumping_cpu = cpu;
+
+	/* Save the pointer to the pt_regs struct */
+	dump_header_asm.dha_pt_regs = regs;
+
+	save_this_cpu_state(cpu, regs, current);
+
+	save_other_cpu_states();
+
+	/* return success */
+	return (1);
+}
+
+
+#define dim(x) (sizeof(x)/sizeof(*(x)))
+
+void
+__init_mem_banks(void)
+{
+	void *p;
+	int i = 0;
+	void *efi_map_start = __va(ia64_boot_param->efi_memmap);
+	void *efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size;
+	u64 efi_desc_size = ia64_boot_param->efi_memdesc_size;
+
+	memset (dump_mbank, 0, sizeof dump_mbank);
+
+	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
+		efi_memory_desc_t *md = p;
+		u64 start = md->phys_addr;
+		u64 end = start + (md->num_pages << DUMP_EF_PAGE_SHIFT) - 1;
+		int type;
+
+		if (i >= dim(dump_mbank)) {
+			break;
+		}
+
+		/*
+		 * NB: The attribute EFI_MEMORY_UC means the memory bank can support Uncached access,
+		 *      not that the memory us curently running with Uncached access.
+		 */
+		if ( (md->attribute & (EFI_MEMORY_WB | EFI_MEMORY_WT)) == 0 ) {
+			continue;
+		}
+		switch(md->type) {
+		case EFI_UNUSABLE_MEMORY:		/* Ignore it */
+			continue;
+
+		case EFI_LOADER_CODE:
+		case EFI_LOADER_DATA:
+		case EFI_BOOT_SERVICES_CODE:
+		case EFI_BOOT_SERVICES_DATA:
+		case EFI_CONVENTIONAL_MEMORY:
+			type = DUMP_MBANK_TYPE_CONVENTIONAL_MEMORY;
+			break;
+		
+		default:
+			type = DUMP_MBANK_TYPE_OTHER;
+			break;
+
+		}
+		dump_mbank[ i ].type = type;
+		dump_mbank[ i ].start = start;
+		dump_mbank[ i ].end = end;
+		i++;
+	}
+	dump_mbanks = i;
+	return;
+}
+
+/*
+ * Name: __dump_init()
+ * Func: Initialize the dumping routine process.  This is in case
+ *       it's necessary in the future.
+ */
+void
+__dump_init(uint64_t local_memory_start)
+{
+	__init_mem_banks();		/* Initialize Memory Banks */
+	return;
+}
+
+/*
+ * Name: __dump_open()
+ * Func: Open the dump device (architecture specific).  This is in
+ *       case it's necessary in the future.
+ */
+void
+__dump_open(void)
+{
+	alloc_dha_stack();
+
+	return;
+}
+
+
+/*
+ * Name: __dump_cleanup()
+ * Func: Free any architecture specific data structures. This is called
+ *       when the dump module is being removed.
+ */
+void
+__dump_cleanup(void)
+{
+	free_dha_stack();
+
+	return;
+}
+
+#ifdef CONFIG_SMP
+/*
+ * Non dumping cpus will spin here. If a cpu is handling an irq when ipi is
+ * received, we let go of it here while making sure that it hits schedule
+ * on the way up and make it spin there instead.
+ */
+static void
+__dump_spin(void *arg)
+{
+	if (in_irq()) {
+		current->need_resched = 1;
+	} else {
+		while (dump_in_progress) ;
+	}
+	return;
+}
+#endif
+
+/*
+ * Routine to save the old irq affinities and change affinities of all irqs to
+ * the dumping cpu.
+ * 
+ * NB: Need to be expanded to multiple nodes.
+ */
+static void
+__dump_set_irq_affinity(void)
+{
+	int i;
+	int cpu = smp_processor_id();
+
+	memcpy(saved_affinity, irq_affinity, NR_IRQS * sizeof(unsigned long));
+
+	for (i = 0; i < NR_IRQS; i++) {
+		if (irq_desc(i)->handler == NULL) {
+			continue;
+		}
+		irq_affinity[i] = 1UL << cpu;
+		if (irq_desc(i)->handler->set_affinity != NULL) {
+			irq_desc(i)->handler->set_affinity(i, irq_affinity[i]);
+		}
+	}
+}
+
+/*
+ * Restore old irq affinities.
+ */
+static void
+__dump_reset_irq_affinity(void)
+{
+	int i;
+
+	memcpy(irq_affinity, saved_affinity, NR_IRQS * sizeof(unsigned long));
+
+	for (i = 0; i < NR_IRQS; i++) {
+		if (irq_desc(i)->handler == NULL) {
+			continue;
+		}
+		if (irq_desc(i)->handler->set_affinity != NULL) {
+			irq_desc(i)->handler->set_affinity(i, saved_affinity[i]);
+		}
+	}
+}
+
+
+/*
+ * Name: __dump_silence_system()
+ * Func: Do an architecture-specific silencing of the system.
+ */
+unsigned int
+__dump_silence_system(unsigned int stage)
+{
+	
+	if (stage) {	/* Do this after interrupts are enabled */
+		/* read the comments above ... */
+		__dump_set_irq_affinity();
+		synchronize_irq();
+		smp_call_function(__dump_spin, NULL, 0, 0);
+	}
+	return (0);
+}
+
+/*
+ * Name: __dump_resume_system()
+ * Func: Resume the system state in an architecture-specific way.
+ */
+unsigned int
+__dump_resume_system(unsigned int stage)
+{
+	/* put the irq affinity tables back */
+	__dump_reset_irq_affinity();
+
+	return (0);
+}
+
+
+int __dump_memcpy_mc_expected = 0;		/* Doesn't help yet */
+
+/*
+ * An ia64 version of memcpy() that trys to avoid machine checks.
+ *
+ * NB: 
+ * 	By itself __dump_memcpy_mc_expected() ins't providing any
+ *	protection against Machine Checks. We are looking into the
+ *	possability of adding code to the arch/ia64/kernel/mca.c fuction
+ *	ia64_mca_ucmc_handler() to restore state so that a IA64_MCA_CORRECTED
+ *	can be returned to the firmware. Curently it always returns 
+ *	IA64_MCA_COLD_BOOT and reboots the machine.
+ */
+void * __dump_memcpy(void * dest, const void *src, size_t count)
+{
+	void *vp;
+
+	if (__dump_memcpy_mc_expected) {
+		ia64_pal_mc_expected((u64) 1, 0);
+	}
+
+	vp = memcpy(dest, src, count);
+
+	if (__dump_memcpy_mc_expected) {
+		ia64_pal_mc_expected((u64) 0, 0);
+	}
+	return(vp);
+}
diff -Naur linux-2.4.19.orig/drivers/dump/dump_rle.c linux-2.4.19.lkcd/drivers/dump/dump_rle.c
--- linux-2.4.19.orig/drivers/dump/dump_rle.c	Thu Jan  1 05:00:00 1970
+++ linux-2.4.19.lkcd/drivers/dump/dump_rle.c	Tue Nov 19 13:55:52 2002
@@ -0,0 +1,177 @@
+/*
+ * RLE Compression functions for kernel crash dumps.
+ *
+ * Created by: Matt Robinson (yakker@sourceforge.net)
+ * Copyright 2001 Matt D. Robinson.  All rights reserved.
+ *
+ * This code is released under version 2 of the GNU GPL.
+ */
+
+/* header files */
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/init.h>
+#include <linux/dump.h>
+
+MODULE_AUTHOR("Matt D. Robinson <yakker@sourceforge.net>");
+MODULE_DESCRIPTION("RLE Compression Module for LKCD");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,16))
+MODULE_LICENSE("GPL");
+#endif
+
+/*
+ * Name: dump_compress_rle()
+ * Func: Compress a DUMP_PAGE_SIZE (hardware) page down to something more reasonable,
+ *       if possible.  This is the same routine we use in IRIX.
+ */
+static int
+dump_compress_rle(char *old, int oldsize, char *new, int newsize)
+{
+	int ri, wi, count = 0;
+	u_char value = 0, cur_byte;
+
+	/*
+	 * If the block should happen to "compress" to larger than the
+	 * buffer size, allocate a larger one and change cur_buf_size.
+	 */
+
+	wi = ri = 0;
+
+	while (ri < oldsize) {
+		if (!ri) {
+			cur_byte = value = old[ri];
+			count = 0;
+		} else {
+			if (count == 255) {
+				if (wi + 3 > oldsize) {
+					return oldsize;
+				}
+				new[wi++] = 0;
+				new[wi++] = count;
+				new[wi++] = value;
+				value = cur_byte = old[ri];
+				count = 0;
+			} else { 
+				if ((cur_byte = old[ri]) == value) {
+					count++;
+				} else {
+					if (count > 1) {
+						if (wi + 3 > oldsize) {
+							return oldsize;
+						}
+						new[wi++] = 0;
+						new[wi++] = count;
+						new[wi++] = value;
+					} else if (count == 1) {
+						if (value == 0) {
+							if (wi + 3 > oldsize) {
+								return oldsize;
+							}
+							new[wi++] = 0;
+							new[wi++] = 1;
+							new[wi++] = 0;
+						} else {
+							if (wi + 2 > oldsize) {
+								return oldsize;
+							}
+							new[wi++] = value;
+							new[wi++] = value;
+						}
+					} else { /* count == 0 */
+						if (value == 0) {
+							if (wi + 2 > oldsize) {
+								return oldsize;
+							}
+							new[wi++] = value;
+							new[wi++] = value;
+						} else {
+							if (wi + 1 > oldsize) {
+								return oldsize;
+							}
+							new[wi++] = value;
+						}
+					} /* if count > 1 */
+
+					value = cur_byte;
+					count = 0;
+
+				} /* if byte == value */
+
+			} /* if count == 255 */
+
+		} /* if ri == 0 */
+		ri++;
+
+	}
+	if (count > 1) {
+		if (wi + 3 > oldsize) {
+			return oldsize;
+		}
+		new[wi++] = 0;
+		new[wi++] = count;
+		new[wi++] = value;
+	} else if (count == 1) {
+		if (value == 0) {
+			if (wi + 3 > oldsize)
+				return oldsize;
+			new[wi++] = 0;
+			new[wi++] = 1;
+			new[wi++] = 0;
+		} else {
+			if (wi + 2 > oldsize)
+				return oldsize;
+			new[wi++] = value;
+			new[wi++] = value;
+		}
+	} else { /* count == 0 */
+		if (value == 0) {
+			if (wi + 2 > oldsize)
+				return oldsize;
+			new[wi++] = value;
+			new[wi++] = value;
+		} else {
+			if (wi + 1 > oldsize)
+				return oldsize;
+			new[wi++] = value;
+		}
+	} /* if count > 1 */
+
+	value = cur_byte;
+	count = 0;
+	return (wi);
+}
+
+/* setup the rle compression functionality */
+static dump_compress_t dump_rle_compression = {
+	compress_type:	DUMP_COMPRESS_RLE,
+	compress_func:	dump_compress_rle,
+};
+
+/*
+ * Name: dump_compress_rle_init()
+ * Func: Initialize rle compression for dumping.
+ */
+int __init
+dump_compress_rle_init(void)
+{
+	dump_register_compression(&dump_rle_compression);
+	return (0);
+}
+
+/*
+ * Name: dump_compress_rle_cleanup()
+ * Func: Remove rle compression for dumping.
+ */
+void
+dump_compress_rle_cleanup(void)
+{
+	dump_unregister_compression(DUMP_COMPRESS_RLE);
+}
+
+/* module initialization */
+module_init(dump_compress_rle_init);
+module_exit(dump_compress_rle_cleanup);
diff -Naur linux-2.4.19.orig/drivers/dump/dump_zlib.c linux-2.4.19.lkcd/drivers/dump/dump_zlib.c
--- linux-2.4.19.orig/drivers/dump/dump_zlib.c	Thu Jan  1 05:00:00 1970
+++ linux-2.4.19.lkcd/drivers/dump/dump_zlib.c	Tue Nov 19 13:49:50 2002
@@ -0,0 +1,5374 @@
+/*
+ * This file is derived from various .h and .c files from the zlib-1.0.4
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets.  See zlib.h for conditions of
+ * distribution and use.
+ *
+ * Changes that have been made include:
+ * - added Z_PACKET_FLUSH (see zlib.h for details)
+ * - added inflateIncomp and deflateOutputPending
+ * - allow strm->next_out to be NULL, meaning discard the output
+ *
+ * $Id: dump_zlib.c,v 1.1 2001/10/27 23:43:41 yakker Exp $
+ */
+
+/* 
+ *  ==FILEVERSION 971210==
+ *
+ * This marker is used by the Linux installation script to determine
+ * whether an up-to-date version of this file is already installed.
+ */
+
+#define NO_DUMMY_DECL
+#define NO_ZCFUNCS
+#define MY_ZCALLOC
+
+#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL))
+#define inflate	inflate_ppp	/* FreeBSD already has an inflate :-( */
+#endif
+
+
+/* +++ zutil.h */
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* From: zutil.h,v 1.16 1996/07/24 13:41:13 me Exp $ */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+#include "dump_zlib.h"
+
+#if defined(KERNEL) || defined(_KERNEL)
+/* Assume this is a *BSD or SVR4 kernel */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/systm.h>
+#  define HAVE_MEMCPY
+#  define memcpy(d, s, n)	bcopy((s), (d), (n))
+#  define memset(d, v, n)	bzero((d), (n))
+#  define memcmp		bcmp
+
+#else
+#if defined(__KERNEL__)
+/* Assume this is a Linux kernel */
+#include <linux/string.h>
+#define HAVE_MEMCPY
+
+#else /* not kernel */
+
+#if defined(MSDOS)||defined(VMS)||defined(CRAY)||defined(WIN32)||defined(RISCOS)
+#   include <stddef.h>
+#   include <errno.h>
+#else
+    extern int errno;
+#endif
+#ifdef STDC
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+#endif /* __KERNEL__ */
+#endif /* _KERNEL || KERNEL */
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+  return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+        /* common constants */
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+        /* target dependencies */
+
+#ifdef MSDOS
+#  define OS_CODE  0x00
+#  ifdef __TURBOC__
+#    include <alloc.h>
+#  else /* MSC or DJGPP */
+#    include <malloc.h>
+#  endif
+#endif
+
+#ifdef OS2
+#  define OS_CODE  0x06
+#endif
+
+#ifdef WIN32 /* Window 95 & Windows NT */
+#  define OS_CODE  0x0b
+#endif
+
+#if defined(VAXC) || defined(VMS)
+#  define OS_CODE  0x02
+#  define FOPEN(name, mode) \
+     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#ifdef AMIGA
+#  define OS_CODE  0x01
+#endif
+
+#if defined(ATARI) || defined(atarist)
+#  define OS_CODE  0x05
+#endif
+
+#ifdef MACOS
+#  define OS_CODE  0x07
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+#  define OS_CODE  0x0F
+#endif
+
+#ifdef TOPS20
+#  define OS_CODE  0x0a
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+#  define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+        /* Common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+#ifndef FOPEN
+#  define FOPEN(name, mode) fopen((name), (mode))
+#endif
+
+         /* functions */
+
+#ifdef HAVE_STRERROR
+   extern char *strerror OF((int));
+#  define zstrerror(errnum) strerror(errnum)
+#else
+#  define zstrerror(errnum) ""
+#endif
+
+#if defined(pyr)
+#  define NO_MEMCPY
+#endif
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+  * You may have to use the same strategy for Borland C (untested).
+  */
+#  define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+#  define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+#    define zmemcpy _fmemcpy
+#    define zmemcmp _fmemcmp
+#    define zmemzero(dest, len) _fmemset(dest, 0, len)
+#  else
+#    define zmemcpy memcpy
+#    define zmemcmp memcmp
+#    define zmemzero(dest, len) memset(dest, 0, len)
+#  endif
+#else
+   extern void zmemcpy  OF((Bytef* dest, Bytef* source, uInt len));
+   extern int  zmemcmp  OF((Bytef* s1,   Bytef* s2, uInt len));
+   extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG_ZLIB
+#  include <stdio.h>
+#  ifndef verbose
+#    define verbose 0
+#  endif
+   extern void z_error    OF((char *m));
+#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+
+typedef uLong (*check_func) OF((uLong check, const Bytef *buf, uInt len));
+
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void   zcfree  OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+           (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* _Z_UTIL_H */
+/* --- zutil.h */
+
+/* +++ deflate.h */
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-1996 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* From: deflate.h,v 1.10 1996/07/02 12:41:00 me Exp $ */
+
+#ifndef _DEFLATE_H
+#define _DEFLATE_H
+
+/* #include "zutil.h" */
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE    42
+#define BUSY_STATE   113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+    union {
+        ush  freq;       /* frequency count */
+        ush  code;       /* bit string */
+    } fc;
+    union {
+        ush  dad;        /* father node in Huffman tree */
+        ush  len;        /* length of bit string */
+    } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+typedef struct static_tree_desc_s  static_tree_desc;
+
+typedef struct tree_desc_s {
+    ct_data *dyn_tree;           /* the dynamic tree */
+    int     max_code;            /* largest code with non zero frequency */
+    static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct deflate_state {
+    z_streamp strm;      /* pointer back to this zlib stream */
+    int   status;        /* as the name implies */
+    Bytef *pending_buf;  /* output still pending */
+    ulg   pending_buf_size; /* size of pending_buf */
+    Bytef *pending_out;  /* next pending byte to output to the stream */
+    int   pending;       /* nb of bytes in the pending buffer */
+    int   noheader;      /* suppress zlib header and adler32 */
+    Byte  data_type;     /* UNKNOWN, BINARY or ASCII */
+    Byte  method;        /* STORED (for zip only) or DEFLATED */
+    int   last_flush;    /* value of flush param for previous deflate call */
+
+                /* used by deflate.c: */
+
+    uInt  w_size;        /* LZ77 window size (32K by default) */
+    uInt  w_bits;        /* log2(w_size)  (8..16) */
+    uInt  w_mask;        /* w_size - 1 */
+
+    Bytef *window;
+    /* Sliding window. Input bytes are read into the second half of the window,
+     * and move to the first half later to keep a dictionary of at least wSize
+     * bytes. With this organization, matches are limited to a distance of
+     * wSize-MAX_MATCH bytes, but this ensures that IO is always
+     * performed with a length multiple of the block size. Also, it limits
+     * the window size to 64K, which is quite useful on MSDOS.
+     * To do: use the user input buffer as sliding window.
+     */
+
+    ulg window_size;
+    /* Actual size of window: 2*wSize, except when the user input buffer
+     * is directly used as sliding window.
+     */
+
+    Posf *prev;
+    /* Link to older string with same hash index. To limit the size of this
+     * array to 64K, this link is maintained only for the last 32K strings.
+     * An index in this array is thus a window index modulo 32K.
+     */
+
+    Posf *head; /* Heads of the hash chains or NIL. */
+
+    uInt  ins_h;          /* hash index of string to be inserted */
+    uInt  hash_size;      /* number of elements in hash table */
+    uInt  hash_bits;      /* log2(hash_size) */
+    uInt  hash_mask;      /* hash_size-1 */
+
+    uInt  hash_shift;
+    /* Number of bits by which ins_h must be shifted at each input
+     * step. It must be such that after MIN_MATCH steps, the oldest
+     * byte no longer takes part in the hash key, that is:
+     *   hash_shift * MIN_MATCH >= hash_bits
+     */
+
+    long block_start;
+    /* Window position at the beginning of the current output block. Gets
+     * negative when the window is moved backwards.
+     */
+
+    uInt match_length;           /* length of best match */
+    IPos prev_match;             /* previous match */
+    int match_available;         /* set if previous match exists */
+    uInt strstart;               /* start of string to insert */
+    uInt match_start;            /* start of matching string */
+    uInt lookahead;              /* number of valid bytes ahead in window */
+
+    uInt prev_length;
+    /* Length of the best match at previous step. Matches not greater than this
+     * are discarded. This is used in the lazy match evaluation.
+     */
+
+    uInt max_chain_length;
+    /* To speed up deflation, hash chains are never searched beyond this
+     * length.  A higher limit improves compression ratio but degrades the
+     * speed.
+     */
+
+    uInt max_lazy_match;
+    /* Attempt to find a better match only when the current match is strictly
+     * smaller than this value. This mechanism is used only for compression
+     * levels >= 4.
+     */
+#   define max_insert_length  max_lazy_match
+    /* Insert new strings in the hash table only if the match length is not
+     * greater than this length. This saves time but degrades compression.
+     * max_insert_length is used only for compression levels <= 3.
+     */
+
+    int level;    /* compression level (1..9) */
+    int strategy; /* favor or force Huffman coding*/
+
+    uInt good_match;
+    /* Use a faster search when the previous match is longer than this */
+
+    int nice_match; /* Stop searching when current match exceeds this */
+
+                /* used by trees.c: */
+    /* Didn't use ct_data typedef below to suppress compiler warning */
+    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
+
+    struct tree_desc_s l_desc;               /* desc. for literal tree */
+    struct tree_desc_s d_desc;               /* desc. for distance tree */
+    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
+
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
+    int heap_len;               /* number of elements in the heap */
+    int heap_max;               /* element of largest frequency */
+    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+     * The same heap array is used to build all trees.
+     */
+
+    uch depth[2*L_CODES+1];
+    /* Depth of each subtree used as tie breaker for trees of equal frequency
+     */
+
+    uchf *l_buf;          /* buffer for literals or lengths */
+
+    uInt  lit_bufsize;
+    /* Size of match buffer for literals/lengths.  There are 4 reasons for
+     * limiting lit_bufsize to 64K:
+     *   - frequencies can be kept in 16 bit counters
+     *   - if compression is not successful for the first block, all input
+     *     data is still in the window so we can still emit a stored block even
+     *     when input comes from standard input.  (This can also be done for
+     *     all blocks if lit_bufsize is not greater than 32K.)
+     *   - if compression is not successful for a file smaller than 64K, we can
+     *     even emit a stored file instead of a stored block (saving 5 bytes).
+     *     This is applicable only for zip (not gzip or zlib).
+     *   - creating new Huffman trees less frequently may not provide fast
+     *     adaptation to changes in the input data statistics. (Take for
+     *     example a binary file with poorly compressible code followed by
+     *     a highly compressible string table.) Smaller buffer sizes give
+     *     fast adaptation but have of course the overhead of transmitting
+     *     trees more frequently.
+     *   - I can't count above 4
+     */
+
+    uInt last_lit;      /* running index in l_buf */
+
+    ushf *d_buf;
+    /* Buffer for distances. To simplify the code, d_buf and l_buf have
+     * the same number of elements. To use different lengths, an extra flag
+     * array would be necessary.
+     */
+
+    ulg opt_len;        /* bit length of current block with optimal trees */
+    ulg static_len;     /* bit length of current block with static trees */
+    ulg compressed_len; /* total bit length of compressed file */
+    uInt matches;       /* number of string matches in current block */
+    int last_eob_len;   /* bit length of EOB code for last block */
+
+#ifdef DEBUG_ZLIB
+    ulg bits_sent;      /* bit length of the compressed data */
+#endif
+
+    ush bi_buf;
+    /* Output buffer. bits are inserted starting at the bottom (least
+     * significant bits).
+     */
+    int bi_valid;
+    /* Number of valid bits in bi_buf.  All bits above the last valid bit
+     * are always zero.
+     */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+        /* in trees.c */
+void _tr_init         OF((deflate_state *s));
+int  _tr_tally        OF((deflate_state *s, unsigned dist, unsigned lc));
+ulg  _tr_flush_block  OF((deflate_state *s, charf *buf, ulg stored_len,
+			  int eof));
+void _tr_align        OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+                          int eof));
+void _tr_stored_type_only OF((deflate_state *));
+
+#endif
+/* --- deflate.h */
+
+/* +++ deflate.c */
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process depends on being able to identify portions
+ *      of the input text which are identical to earlier input (within a
+ *      sliding window trailing behind the input currently being processed).
+ *
+ *      The most straightforward technique turns out to be the fastest for
+ *      most input files: try all possible matches and select the longest.
+ *      The key feature of this algorithm is that insertions into the string
+ *      dictionary are very simple and thus fast, and deletions are avoided
+ *      completely. Insertions are performed at each input character, whereas
+ *      string matches are performed only when the previous match ends. So it
+ *      is preferable to spend more time in matches to allow very fast string
+ *      insertions and avoid deletions. The matching algorithm for small
+ *      strings is inspired from that of Rabin & Karp. A brute force approach
+ *      is used to find longer strings when a small match has been found.
+ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ *      (by Leonid Broukhis).
+ *         A previous version of this file used a more sophisticated algorithm
+ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
+ *      time, but has a larger average cost, uses more memory and is patented.
+ *      However the F&G algorithm may be faster for some highly redundant
+ *      files if the parameter max_chain_length (described below) is too large.
+ *
+ *  ACKNOWLEDGEMENTS
+ *
+ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ *      I found it in 'freeze' written by Leonid Broukhis.
+ *      Thanks to many people for bug reports and testing.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ *      Available in ftp://ds.internic.net/rfc/rfc1951.txt
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ *      Fiala,E.R., and Greene,D.H.
+ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* From: deflate.c,v 1.15 1996/07/24 13:40:58 me Exp $ */
+
+/* #include "deflate.h" */
+
+char deflate_copyright[] = " deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ *  Function prototypes.
+ */
+typedef enum {
+    need_more,      /* block not completed, need more input or more output */
+    block_done,     /* block flush performed */
+    finish_started, /* finish started, need only more output at next deflate */
+    finish_done     /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window    OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast   OF((deflate_state *s, int flush));
+local block_state deflate_slow   OF((deflate_state *s, int flush));
+local void lm_init        OF((deflate_state *s));
+local void putShortMSB    OF((deflate_state *s, uInt b));
+local void flush_pending  OF((z_streamp strm));
+local int read_buf        OF((z_streamp strm, charf *buf, unsigned size));
+#ifdef ASMV
+      void match_init OF((void)); /* asm code initialization */
+      uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#endif
+
+#ifdef DEBUG_ZLIB
+local  void check_match OF((deflate_state *s, IPos start, IPos match,
+                            int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+   ush good_length; /* reduce lazy search above this match length */
+   ush max_lazy;    /* do not perform lazy search above this match length */
+   ush nice_length; /* quit search above this match length */
+   ush max_chain;
+   compress_func func;
+} config;
+
+local config configuration_table[10] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}, /* maximum speed, no lazy matches */
+/* 2 */ {4,    5, 16,    8, deflate_fast},
+/* 3 */ {4,    6, 32,   32, deflate_fast},
+
+/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
+/* 5 */ {8,   16, 32,   32, deflate_slow},
+/* 6 */ {8,   16, 128, 128, deflate_slow},
+/* 7 */ {8,   32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to UPDATE_HASH are made with consecutive
+ *    input characters, so that a running hash key can be computed from the
+ *    previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * IN  assertion: all calls to INSERT_STRING are made with consecutive
+ *    input characters and the first MIN_MATCH bytes of str are valid
+ *    (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+    s->head[s->hash_size-1] = NIL; \
+    zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int deflateInit_(strm, level, version, stream_size)
+    z_streamp strm;
+    int level;
+    const char *version;
+    int stream_size;
+{
+    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+			 Z_DEFAULT_STRATEGY, version, stream_size);
+    /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+		  version, stream_size)
+    z_streamp strm;
+    int  level;
+    int  method;
+    int  windowBits;
+    int  memLevel;
+    int  strategy;
+    const char *version;
+    int stream_size;
+{
+    deflate_state *s;
+    int noheader = 0;
+    static char* my_version = ZLIB_VERSION;
+
+    ushf *overlay;
+    /* We overlay pending_buf and d_buf+l_buf. This works since the average
+     * output size for (length,distance) codes is <= 24 bits.
+     */
+
+    if (version == Z_NULL || version[0] != my_version[0] ||
+        stream_size != sizeof(z_stream)) {
+	return Z_VERSION_ERROR;
+    }
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->msg = Z_NULL;
+#ifndef NO_ZCFUNCS
+    if (strm->zalloc == Z_NULL) {
+	strm->zalloc = zcalloc;
+	strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == Z_NULL) strm->zfree = zcfree;
+#endif
+
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+
+    if (windowBits < 0) { /* undocumented feature: suppress zlib header */
+        noheader = 1;
+        windowBits = -windowBits;
+    }
+    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+	strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+        return Z_STREAM_ERROR;
+    }
+    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+    if (s == Z_NULL) return Z_MEM_ERROR;
+    strm->state = (struct internal_state FAR *)s;
+    s->strm = strm;
+
+    s->noheader = noheader;
+    s->w_bits = windowBits;
+    s->w_size = 1 << s->w_bits;
+    s->w_mask = s->w_size - 1;
+
+    s->hash_bits = memLevel + 7;
+    s->hash_size = 1 << s->hash_bits;
+    s->hash_mask = s->hash_size - 1;
+    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
+    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+    s->pending_buf = (uchf *) overlay;
+    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+        s->pending_buf == Z_NULL) {
+        strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+        deflateEnd (strm);
+        return Z_MEM_ERROR;
+    }
+    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+    s->level = level;
+    s->strategy = strategy;
+    s->method = (Byte)method;
+
+    return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int deflateSetDictionary (strm, dictionary, dictLength)
+    z_streamp strm;
+    const Bytef *dictionary;
+    uInt  dictLength;
+{
+    deflate_state *s;
+    uInt length = dictLength;
+    uInt n;
+    IPos hash_head = 0;
+
+    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
+	return Z_STREAM_ERROR;
+
+    s = (deflate_state *) strm->state;
+    if (s->status != INIT_STATE) return Z_STREAM_ERROR;
+
+    strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+    if (length < MIN_MATCH) return Z_OK;
+    if (length > MAX_DIST(s)) {
+	length = MAX_DIST(s);
+#ifndef USE_DICT_HEAD
+	dictionary += dictLength - length; /* use the tail of the dictionary */
+#endif
+    }
+    zmemcpy((charf *)s->window, dictionary, length);
+    s->strstart = length;
+    s->block_start = (long)length;
+
+    /* Insert all strings in the hash table (except for the last two bytes).
+     * s->lookahead stays null, so s->ins_h will be recomputed at the next
+     * call of fill_window.
+     */
+    s->ins_h = s->window[0];
+    UPDATE_HASH(s, s->ins_h, s->window[1]);
+    for (n = 0; n <= length - MIN_MATCH; n++) {
+	INSERT_STRING(s, n, hash_head);
+    }
+    if (hash_head) hash_head = 0;  /* to make compiler happy */
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int deflateReset (strm)
+    z_streamp strm;
+{
+    deflate_state *s;
+    
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->total_in = strm->total_out = 0;
+    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+    strm->data_type = Z_UNKNOWN;
+
+    s = (deflate_state *)strm->state;
+    s->pending = 0;
+    s->pending_out = s->pending_buf;
+
+    if (s->noheader < 0) {
+        s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
+    }
+    s->status = s->noheader ? BUSY_STATE : INIT_STATE;
+    strm->adler = 1;
+    s->last_flush = Z_NO_FLUSH;
+
+    _tr_init(s);
+    lm_init(s);
+
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int deflateParams(strm, level, strategy)
+    z_streamp strm;
+    int level;
+    int strategy;
+{
+    deflate_state *s;
+    compress_func func;
+    int err = Z_OK;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = (deflate_state *) strm->state;
+
+    if (level == Z_DEFAULT_COMPRESSION) {
+	level = 6;
+    }
+    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+	return Z_STREAM_ERROR;
+    }
+    func = configuration_table[s->level].func;
+
+    if (func != configuration_table[level].func && strm->total_in != 0) {
+	/* Flush the last buffer: */
+	err = deflate(strm, Z_PARTIAL_FLUSH);
+    }
+    if (s->level != level) {
+	s->level = level;
+	s->max_lazy_match   = configuration_table[level].max_lazy;
+	s->good_match       = configuration_table[level].good_length;
+	s->nice_match       = configuration_table[level].nice_length;
+	s->max_chain_length = configuration_table[level].max_chain;
+    }
+    s->strategy = strategy;
+    return err;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+    deflate_state *s;
+    uInt b;
+{
+    put_byte(s, (Byte)(b >> 8));
+    put_byte(s, (Byte)(b & 0xff));
+}   
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+    z_streamp strm;
+{
+    deflate_state *s = (deflate_state *) strm->state;
+    unsigned len = s->pending;
+
+    if (len > strm->avail_out) len = strm->avail_out;
+    if (len == 0) return;
+
+    if (strm->next_out != Z_NULL) {
+	zmemcpy(strm->next_out, s->pending_out, len);
+	strm->next_out += len;
+    }
+    s->pending_out += len;
+    strm->total_out += len;
+    strm->avail_out  -= len;
+    s->pending -= len;
+    if (s->pending == 0) {
+        s->pending_out = s->pending_buf;
+    }
+}
+
+/* ========================================================================= */
+int deflate (strm, flush)
+    z_streamp strm;
+    int flush;
+{
+    int old_flush; /* value of flush param for previous deflate call */
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+	flush > Z_FINISH || flush < 0) {
+        return Z_STREAM_ERROR;
+    }
+    s = (deflate_state *) strm->state;
+
+    if ((strm->next_in == Z_NULL && strm->avail_in != 0) ||
+	(s->status == FINISH_STATE && flush != Z_FINISH)) {
+        ERR_RETURN(strm, Z_STREAM_ERROR);
+    }
+    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+    s->strm = strm; /* just in case */
+    old_flush = s->last_flush;
+    s->last_flush = flush;
+
+    /* Write the zlib header */
+    if (s->status == INIT_STATE) {
+
+        uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+        uInt level_flags = (s->level-1) >> 1;
+
+        if (level_flags > 3) level_flags = 3;
+        header |= (level_flags << 6);
+	if (s->strstart != 0) header |= PRESET_DICT;
+        header += 31 - (header % 31);
+
+        s->status = BUSY_STATE;
+        putShortMSB(s, header);
+
+	/* Save the adler32 of the preset dictionary: */
+	if (s->strstart != 0) {
+	    putShortMSB(s, (uInt)(strm->adler >> 16));
+	    putShortMSB(s, (uInt)(strm->adler & 0xffff));
+	}
+	strm->adler = 1L;
+    }
+
+    /* Flush as much pending output as possible */
+    if (s->pending != 0) {
+        flush_pending(strm);
+        if (strm->avail_out == 0) {
+	    /* Since avail_out is 0, deflate will be called again with
+	     * more output space, but possibly with both pending and
+	     * avail_in equal to zero. There won't be anything to do,
+	     * but this is not an error situation so make sure we
+	     * return OK instead of BUF_ERROR at next call of deflate:
+             */
+	    s->last_flush = -1;
+	    return Z_OK;
+	}
+
+    /* Make sure there is something to do and avoid duplicate consecutive
+     * flushes. For repeated and useless calls with Z_FINISH, we keep
+     * returning Z_STREAM_END instead of Z_BUFF_ERROR.
+     */
+    } else if (strm->avail_in == 0 && flush <= old_flush &&
+	       flush != Z_FINISH) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* User must not provide more input after the first FINISH: */
+    if (s->status == FINISH_STATE && strm->avail_in != 0) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* Start a new block or continue the current one.
+     */
+    if (strm->avail_in != 0 || s->lookahead != 0 ||
+        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+        block_state bstate;
+
+	bstate = (*(configuration_table[s->level].func))(s, flush);
+
+        if (bstate == finish_started || bstate == finish_done) {
+            s->status = FINISH_STATE;
+        }
+        if (bstate == need_more || bstate == finish_started) {
+	    if (strm->avail_out == 0) {
+	        s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+	    }
+	    return Z_OK;
+	    /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+	     * of deflate should use the same flush parameter to make sure
+	     * that the flush is complete. So we don't have to output an
+	     * empty block here, this will be done at next call. This also
+	     * ensures that for a very small output buffer, we emit at most
+	     * one empty block.
+	     */
+	}
+        if (bstate == block_done) {
+            if (flush == Z_PARTIAL_FLUSH) {
+                _tr_align(s);
+	    } else if (flush == Z_PACKET_FLUSH) {
+		/* Output just the 3-bit `stored' block type value,
+		   but not a zero length. */
+		_tr_stored_type_only(s);
+            } else { /* FULL_FLUSH or SYNC_FLUSH */
+                _tr_stored_block(s, (char*)0, 0L, 0);
+                /* For a full flush, this empty block will be recognized
+                 * as a special marker by inflate_sync().
+                 */
+                if (flush == Z_FULL_FLUSH) {
+                    CLEAR_HASH(s);             /* forget history */
+                }
+            }
+            flush_pending(strm);
+	    if (strm->avail_out == 0) {
+	      s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+	      return Z_OK;
+	    }
+        }
+    }
+    Assert(strm->avail_out > 0, "bug2");
+
+//    if (flush != Z_FINISH) return Z_OK;
+    if (flush != Z_FINISH) {
+    	return Z_OK;
+    }
+    if (s->noheader) return Z_STREAM_END;
+
+    /* Write the zlib trailer (adler32) */
+    putShortMSB(s, (uInt)(strm->adler >> 16));
+    putShortMSB(s, (uInt)(strm->adler & 0xffff));
+    flush_pending(strm);
+    /* If avail_out is zero, the application will call deflate again
+     * to flush the rest.
+     */
+    s->noheader = -1; /* write the trailer only once! */
+    return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int deflateEnd (strm)
+    z_streamp strm;
+{
+    int status;
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = (deflate_state *) strm->state;
+
+    status = s->status;
+    if (status != INIT_STATE && status != BUSY_STATE &&
+	status != FINISH_STATE) {
+      return Z_STREAM_ERROR;
+    }
+
+    /* Deallocate in reverse order of allocations: */
+    TRY_FREE(strm, s->pending_buf);
+    TRY_FREE(strm, s->head);
+    TRY_FREE(strm, s->prev);
+    TRY_FREE(strm, s->window);
+
+    ZFREE(strm, s);
+    strm->state = Z_NULL;
+
+    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ */
+int deflateCopy (dest, source)
+    z_streamp dest;
+    z_streamp source;
+{
+    deflate_state *ds;
+    deflate_state *ss;
+    ushf *overlay;
+
+    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL)
+        return Z_STREAM_ERROR;
+    ss = (deflate_state *) source->state;
+
+    *dest = *source;
+
+    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+    if (ds == Z_NULL) return Z_MEM_ERROR;
+    dest->state = (struct internal_state FAR *) ds;
+    *ds = *ss;
+    ds->strm = dest;
+
+    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
+    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
+    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+    ds->pending_buf = (uchf *) overlay;
+
+    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+        ds->pending_buf == Z_NULL) {
+        deflateEnd (dest);
+        return Z_MEM_ERROR;
+    }
+    /* ??? following zmemcpy doesn't work for 16-bit MSDOS */
+    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+    zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+    zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+    ds->l_desc.dyn_tree = ds->dyn_ltree;
+    ds->d_desc.dyn_tree = ds->dyn_dtree;
+    ds->bl_desc.dyn_tree = ds->bl_tree;
+
+    return Z_OK;
+}
+
+/* ===========================================================================
+ * Return the number of bytes of output which are immediately available
+ * for output from the decompressor.
+ */
+int deflateOutputPending (strm)
+    z_streamp strm;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL) return 0;
+    
+    return ((deflate_state *)(strm->state))->pending;
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read.  All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+    z_streamp strm;
+    charf *buf;
+    unsigned size;
+{
+    unsigned len = strm->avail_in;
+
+    if (len > size) len = size;
+    if (len == 0) return 0;
+
+    strm->avail_in  -= len;
+
+    if (!((deflate_state *)(strm->state))->noheader) {
+        strm->adler = adler32(strm->adler, strm->next_in, len);
+    }
+    zmemcpy(buf, strm->next_in, len);
+    strm->next_in  += len;
+    strm->total_in += len;
+
+    return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+    deflate_state *s;
+{
+    s->window_size = (ulg)2L*s->w_size;
+
+    CLEAR_HASH(s);
+
+    /* Set the default configuration parameters:
+     */
+    s->max_lazy_match   = configuration_table[s->level].max_lazy;
+    s->good_match       = configuration_table[s->level].good_length;
+    s->nice_match       = configuration_table[s->level].nice_length;
+    s->max_chain_length = configuration_table[s->level].max_chain;
+
+    s->strstart = 0;
+    s->block_start = 0L;
+    s->lookahead = 0;
+    s->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    s->ins_h = 0;
+#ifdef ASMV
+    match_init(); /* initialize the asm code */
+#endif
+}
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    unsigned chain_length = s->max_chain_length;/* max hash chain length */
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = s->prev_length;              /* best match length so far */
+    int nice_match = s->nice_match;             /* stop if match long enough */
+    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+        s->strstart - (IPos)MAX_DIST(s) : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+    Posf *prev = s->prev;
+    uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+    /* Compare two bytes at a time. Note: this is not always beneficial.
+     * Try with and without -DUNALIGNED_OK to check.
+     */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ushf*)scan;
+    register ush scan_end   = *(ushf*)(scan+best_len-1);
+#else
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+    register Byte scan_end1  = scan[best_len-1];
+    register Byte scan_end   = scan[best_len];
+#endif
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    /* Do not waste too much time if we already have a good match: */
+    if (s->prev_length >= s->good_match) {
+        chain_length >>= 2;
+    }
+    /* Do not look for matches beyond the end of the input. This is necessary
+     * to make deflate deterministic.
+     */
+    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    do {
+        Assert(cur_match < s->strstart, "no future");
+        match = s->window + cur_match;
+
+        /* Skip to next match if the match length cannot increase
+         * or if the match length is less than 2:
+         */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+        /* This code assumes sizeof(unsigned short) == 2. Do not use
+         * UNALIGNED_OK if your compiler uses a different size.
+         */
+        if (*(ushf*)(match+best_len-1) != scan_end ||
+            *(ushf*)match != scan_start) continue;
+
+        /* It is not necessary to compare scan[2] and match[2] since they are
+         * always equal when the other bytes match, given that the hash keys
+         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+         * strstart+3, +5, ... up to strstart+257. We check for insufficient
+         * lookahead only every 4th comparison; the 128th check will be made
+         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+         * necessary to put more guard bytes at the end of the window, or
+         * to check more often for insufficient lookahead.
+         */
+        Assert(scan[2] == match[2], "scan[2]?");
+        scan++, match++;
+        do {
+        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+        if (*scan == *match) scan++;
+
+        len = (MAX_MATCH - 1) - (int)(strend-scan);
+        scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+        if (match[best_len]   != scan_end  ||
+            match[best_len-1] != scan_end1 ||
+            *match            != *scan     ||
+            *++match          != scan[1])      continue;
+
+        /* The check at best_len-1 can be removed because it will be made
+         * again later. (This heuristic is not always a win.)
+         * It is not necessary to compare scan[2] and match[2] since they
+         * are always equal when the other bytes match, given that
+         * the hash keys are equal and that HASH_BITS >= 8.
+         */
+        scan += 2, match++;
+        Assert(*scan == *match, "match[2]?");
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            s->match_start = cur_match;
+            best_len = len;
+            if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+            scan_end = *(ushf*)(scan+best_len-1);
+#else
+            scan_end1  = scan[best_len-1];
+            scan_end   = scan[best_len];
+#endif
+        }
+    } while ((cur_match = prev[cur_match & wmask]) > limit
+             && --chain_length != 0);
+
+    if ((uInt)best_len <= s->lookahead) return best_len;
+    return s->lookahead;
+}
+#endif /* ASMV */
+
+#ifdef DEBUG_ZLIB
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+    deflate_state *s;
+    IPos start, match;
+    int length;
+{
+    /* check that the match is indeed a match */
+    if (zmemcmp((charf *)s->window + match,
+                (charf *)s->window + start, length) != EQUAL) {
+        fprintf(stderr, " start %u, match %u, length %d\n",
+		start, match, length);
+        do {
+	    fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+	} while (--length != 0);
+        z_error("invalid match");
+    }
+    if (z_verbose > 1) {
+        fprintf(stderr,"\\[%d,%d]", start-match, length);
+        do { putc(s->window[start++], stderr); } while (--length != 0);
+    }
+}
+#else
+#  define check_match(s, start, match, length)
+#endif
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ *    At least one byte has been read, or avail_in == 0; reads are
+ *    performed for at least two bytes (required for the zip translate_eol
+ *    option -- not supported here).
+ */
+local void fill_window(s)
+    deflate_state *s;
+{
+    register unsigned n, m;
+    register Posf *p;
+    unsigned more;    /* Amount of free space at the end of the window. */
+    uInt wsize = s->w_size;
+
+    do {
+        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+        /* Deal with !@#$% 64K limit: */
+        if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+            more = wsize;
+
+        } else if (more == (unsigned)(-1)) {
+            /* Very unlikely, but possible on 16 bit machine if strstart == 0
+             * and lookahead == 1 (input done one byte at time)
+             */
+            more--;
+
+        /* If the window is almost full and there is insufficient lookahead,
+         * move the upper half to the lower one to make room in the upper half.
+         */
+        } else if (s->strstart >= wsize+MAX_DIST(s)) {
+
+            zmemcpy((charf *)s->window, (charf *)s->window+wsize,
+                   (unsigned)wsize);
+            s->match_start -= wsize;
+            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
+            s->block_start -= (long) wsize;
+
+            /* Slide the hash table (could be avoided with 32 bit values
+               at the expense of memory usage). We slide even when level == 0
+               to keep the hash table consistent if we switch back to level > 0
+               later. (Using level 0 permanently is not an optimal usage of
+               zlib, so we don't care about this pathological case.)
+             */
+            n = s->hash_size;
+            p = &s->head[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+            } while (--n);
+
+            n = wsize;
+            p = &s->prev[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+                /* If n is not on any hash chain, prev[n] is garbage but
+                 * its value will never be used.
+                 */
+            } while (--n);
+            more += wsize;
+        }
+        if (s->strm->avail_in == 0) return;
+
+        /* If there was no sliding:
+         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+         *    more == window_size - lookahead - strstart
+         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+         * => more >= window_size - 2*WSIZE + 2
+         * In the BIG_MEM or MMAP case (not yet supported),
+         *   window_size == input_size + MIN_LOOKAHEAD  &&
+         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+         * Otherwise, window_size == 2*WSIZE so more >= 2.
+         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+         */
+        Assert(more >= 2, "more < 2");
+
+        n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead,
+                     more);
+        s->lookahead += n;
+
+        /* Initialize the hash value now that we have some input: */
+        if (s->lookahead >= MIN_MATCH) {
+            s->ins_h = s->window[s->strstart];
+            UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+            Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+        }
+        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+         * but this is not important since only literal bytes will be emitted.
+         */
+
+    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+   _tr_flush_block(s, (s->block_start >= 0L ? \
+                   (charf *)&s->window[(unsigned)s->block_start] : \
+                   (charf *)Z_NULL), \
+		(ulg)((long)s->strstart - s->block_start), \
+		(eof)); \
+   s->block_start = s->strstart; \
+   flush_pending(s->strm); \
+   Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+   FLUSH_BLOCK_ONLY(s, eof); \
+   if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+     * to pending_buf_size, and each stored block has a 5 byte header:
+     */
+    ulg max_block_size = 0xffff;
+    ulg max_start;
+
+    if (max_block_size > s->pending_buf_size - 5) {
+        max_block_size = s->pending_buf_size - 5;
+    }
+
+    /* Copy as much as possible from input to output: */
+    for (;;) {
+        /* Fill the window as much as possible: */
+        if (s->lookahead <= 1) {
+
+            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+		   s->block_start >= (long)s->w_size, "slide too late");
+
+            fill_window(s);
+            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+	Assert(s->block_start >= 0L, "block gone");
+
+	s->strstart += s->lookahead;
+	s->lookahead = 0;
+
+	/* Emit a stored block if pending_buf will be full: */
+ 	max_start = s->block_start + max_block_size;
+        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+	    /* strstart == 0 is possible when wraparound on 16-bit machine */
+	    s->lookahead = (uInt)(s->strstart - max_start);
+	    s->strstart = (uInt)max_start;
+            FLUSH_BLOCK(s, 0);
+	}
+	/* Flush if we may have to slide, otherwise block_start may become
+         * negative and the data will be gone:
+         */
+        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+            FLUSH_BLOCK(s, 0);
+	}
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL; /* head of the hash chain */
+    int bflush;           /* set if current block must be flushed */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+	        return need_more;
+	    }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         * At this point we have always match_length < MIN_MATCH
+         */
+        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            if (s->strategy != Z_HUFFMAN_ONLY) {
+                s->match_length = longest_match (s, hash_head);
+            }
+            /* longest_match() sets match_start */
+        }
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->match_start, s->match_length);
+
+            bflush = _tr_tally(s, s->strstart - s->match_start,
+                               s->match_length - MIN_MATCH);
+
+            s->lookahead -= s->match_length;
+
+            /* Insert new strings in the hash table only if the match length
+             * is not too large. This saves time but degrades compression.
+             */
+            if (s->match_length <= s->max_insert_length &&
+                s->lookahead >= MIN_MATCH) {
+                s->match_length--; /* string at strstart already in hash table */
+                do {
+                    s->strstart++;
+                    INSERT_STRING(s, s->strstart, hash_head);
+                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                     * always MIN_MATCH bytes ahead.
+                     */
+                } while (--s->match_length != 0);
+                s->strstart++; 
+            } else {
+                s->strstart += s->match_length;
+                s->match_length = 0;
+                s->ins_h = s->window[s->strstart];
+                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+                Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+                 * matter since it will be recomputed at next deflate call.
+                 */
+            }
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            bflush = _tr_tally (s, 0, s->window[s->strstart]);
+            s->lookahead--;
+            s->strstart++; 
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL;    /* head of hash chain */
+    int bflush;              /* set if current block must be flushed */
+
+    /* Process the input block. */
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+	        return need_more;
+	    }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         */
+        s->prev_length = s->match_length, s->prev_match = s->match_start;
+        s->match_length = MIN_MATCH-1;
+
+        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+            s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            if (s->strategy != Z_HUFFMAN_ONLY) {
+                s->match_length = longest_match (s, hash_head);
+            }
+            /* longest_match() sets match_start */
+
+            if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
+                 (s->match_length == MIN_MATCH &&
+                  s->strstart - s->match_start > TOO_FAR))) {
+
+                /* If prev_match is also MIN_MATCH, match_start is garbage
+                 * but we will ignore the current match anyway.
+                 */
+                s->match_length = MIN_MATCH-1;
+            }
+        }
+        /* If there was a match at the previous step and the current
+         * match is not better, output the previous match:
+         */
+        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+            /* Do not insert strings in hash table beyond this. */
+
+            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+            bflush = _tr_tally(s, s->strstart -1 - s->prev_match,
+                               s->prev_length - MIN_MATCH);
+
+            /* Insert in hash table all strings up to the end of the match.
+             * strstart-1 and strstart are already inserted. If there is not
+             * enough lookahead, the last two strings are not inserted in
+             * the hash table.
+             */
+            s->lookahead -= s->prev_length-1;
+            s->prev_length -= 2;
+            do {
+                if (++s->strstart <= max_insert) {
+                    INSERT_STRING(s, s->strstart, hash_head);
+                }
+            } while (--s->prev_length != 0);
+            s->match_available = 0;
+            s->match_length = MIN_MATCH-1;
+            s->strstart++;
+
+            if (bflush) FLUSH_BLOCK(s, 0);
+
+        } else if (s->match_available) {
+            /* If there was no match at the previous position, output a
+             * single literal. If there was a match but the current match
+             * is longer, truncate the previous match to a single literal.
+             */
+            Tracevv((stderr,"%c", s->window[s->strstart-1]));
+            if (_tr_tally (s, 0, s->window[s->strstart-1])) {
+                FLUSH_BLOCK_ONLY(s, 0);
+            }
+            s->strstart++;
+            s->lookahead--;
+            if (s->strm->avail_out == 0) return need_more;
+        } else {
+            /* There is no previous match to compare with, wait for
+             * the next step to decide.
+             */
+            s->match_available = 1;
+            s->strstart++;
+            s->lookahead--;
+        }
+    }
+    Assert (flush != Z_NO_FLUSH, "no flush?");
+    if (s->match_available) {
+        Tracevv((stderr,"%c", s->window[s->strstart-1]));
+        _tr_tally (s, 0, s->window[s->strstart-1]);
+        s->match_available = 0;
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+/* --- deflate.c */
+
+/* +++ trees.c */
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-1996 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values).  The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */
+
+/* #include "deflate.h" */
+
+#ifdef DEBUG_ZLIB
+#  include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6      16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10    17
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+
+#define REPZ_11_138  18
+/* repeat a zero length 11-138 times  (7 bits of repeat count) */
+
+local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local int extra_dbits[D_CODES] /* extra bits for each distance code */
+   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local uch bl_order[BL_CODES]
+   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+local uch dist_code[512];
+/* distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+local uch length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+struct static_tree_desc_s {
+    ct_data *static_tree;        /* static tree or NULL */
+    intf    *extra_bits;         /* extra bits for each code or NULL */
+    int     extra_base;          /* base index for extra_bits */
+    int     elems;               /* max number of elements in the tree */
+    int     max_length;          /* max bit length for the codes */
+};
+
+local static_tree_desc  static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc  static_d_desc =
+{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
+
+local static_tree_desc  static_bl_desc =
+{(ct_data *)0, extra_blbits, 0,      BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block     OF((deflate_state *s));
+local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
+local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree     OF((deflate_state *s, tree_desc *desc));
+local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local int  build_bl_tree  OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+                              int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+                              ct_data *dtree));
+local void set_data_type  OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup      OF((deflate_state *s));
+local void bi_flush       OF((deflate_state *s));
+local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
+                              int header));
+
+#ifndef DEBUG_ZLIB
+#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+   /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG_ZLIB */
+#  define send_code(s, c, tree) \
+     { if (verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+       send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+#define d_code(dist) \
+   ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. dist_code[256] and dist_code[257] are never
+ * used.
+ */
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+    put_byte(s, (uch)((w) & 0xff)); \
+    put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG_ZLIB
+local void send_bits      OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+    deflate_state *s;
+    int value;  /* value to send */
+    int length; /* number of bits */
+{
+    Tracevv((stderr," l %2d v %4x ", length, value));
+    Assert(length > 0 && length <= 15, "invalid length");
+    s->bits_sent += (ulg)length;
+
+    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+     * unused bits in value.
+     */
+    if (s->bi_valid > (int)Buf_size - length) {
+        s->bi_buf |= (value << s->bi_valid);
+        put_short(s, s->bi_buf);
+        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+        s->bi_valid += length - Buf_size;
+    } else {
+        s->bi_buf |= value << s->bi_valid;
+        s->bi_valid += length;
+    }
+}
+#else /* !DEBUG_ZLIB */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+  if (s->bi_valid > (int)Buf_size - len) {\
+    int val = value;\
+    s->bi_buf |= (val << s->bi_valid);\
+    put_short(s, s->bi_buf);\
+    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+    s->bi_valid += len - Buf_size;\
+  } else {\
+    s->bi_buf |= (value) << s->bi_valid;\
+    s->bi_valid += len;\
+  }\
+}
+#endif /* DEBUG_ZLIB */
+
+
+#define MAX(a,b) (a >= b ? a : b)
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables. In a multi-threaded environment,
+ * this function may be called by two threads concurrently, but this is
+ * harmless since both invocations do exactly the same thing.
+ */
+local void tr_static_init()
+{
+    static int static_init_done;
+    int n;        /* iterates over tree elements */
+    int bits;     /* bit counter */
+    int length;   /* length value */
+    int code;     /* code value */
+    int dist;     /* distance index */
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    if (static_init_done) return;
+
+    /* Initialize the mapping length (0..255) -> length code (0..28) */
+    length = 0;
+    for (code = 0; code < LENGTH_CODES-1; code++) {
+        base_length[code] = length;
+        for (n = 0; n < (1<<extra_lbits[code]); n++) {
+            length_code[length++] = (uch)code;
+        }
+    }
+    Assert (length == 256, "tr_static_init: length != 256");
+    /* Note that the length 255 (match length 258) can be represented
+     * in two different ways: code 284 + 5 bits or code 285, so we
+     * overwrite length_code[255] to use the best encoding:
+     */
+    length_code[length-1] = (uch)code;
+
+    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: dist != 256");
+    dist >>= 7; /* from now on, all distances are divided by 128 */
+    for ( ; code < D_CODES; code++) {
+        base_dist[code] = dist << 7;
+        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+            dist_code[256 + dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+    /* Construct the codes of the static literal tree */
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+    n = 0;
+    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+    /* Codes 286 and 287 do not exist, but we must include them in the
+     * tree construction to get a canonical Huffman tree (longest code
+     * all ones)
+     */
+    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+    /* The static distance tree is trivial: */
+    for (n = 0; n < D_CODES; n++) {
+        static_dtree[n].Len = 5;
+        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+    }
+    static_init_done = 1;
+}
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void _tr_init(s)
+    deflate_state *s;
+{
+    tr_static_init();
+
+    s->compressed_len = 0L;
+
+    s->l_desc.dyn_tree = s->dyn_ltree;
+    s->l_desc.stat_desc = &static_l_desc;
+
+    s->d_desc.dyn_tree = s->dyn_dtree;
+    s->d_desc.stat_desc = &static_d_desc;
+
+    s->bl_desc.dyn_tree = s->bl_tree;
+    s->bl_desc.stat_desc = &static_bl_desc;
+
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG_ZLIB
+    s->bits_sent = 0L;
+#endif
+
+    /* Initialize the first block of the first file: */
+    init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+    deflate_state *s;
+{
+    int n; /* iterates over tree elements */
+
+    /* Initialize the trees. */
+    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
+    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
+    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+    s->dyn_ltree[END_BLOCK].Freq = 1;
+    s->opt_len = s->static_len = 0L;
+    s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+    top = s->heap[SMALLEST]; \
+    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+    pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+   (tree[n].Freq < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+    deflate_state *s;
+    ct_data *tree;  /* the tree to restore */
+    int k;               /* node to move down */
+{
+    int v = s->heap[k];
+    int j = k << 1;  /* left son of k */
+    while (j <= s->heap_len) {
+        /* Set j to the smallest of the two sons: */
+        if (j < s->heap_len &&
+            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+            j++;
+        }
+        /* Exit if v is smaller than both sons */
+        if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+        /* Exchange v with the smallest son */
+        s->heap[k] = s->heap[j];  k = j;
+
+        /* And continue down the tree, setting j to the left son of k */
+        j <<= 1;
+    }
+    s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+local void gen_bitlen(s, desc)
+    deflate_state *s;
+    tree_desc *desc;    /* the tree descriptor */
+{
+    ct_data *tree  = desc->dyn_tree;
+    int max_code   = desc->max_code;
+    ct_data *stree = desc->stat_desc->static_tree;
+    intf *extra    = desc->stat_desc->extra_bits;
+    int base       = desc->stat_desc->extra_base;
+    int max_length = desc->stat_desc->max_length;
+    int h;              /* heap index */
+    int n, m;           /* iterate over the tree elements */
+    int bits;           /* bit length */
+    int xbits;          /* extra bits */
+    ush f;              /* frequency */
+    int overflow = 0;   /* number of elements with bit length too large */
+
+    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+    /* In a first pass, compute the optimal bit lengths (which may
+     * overflow in the case of the bit length tree).
+     */
+    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+        n = s->heap[h];
+        bits = tree[tree[n].Dad].Len + 1;
+        if (bits > max_length) bits = max_length, overflow++;
+        tree[n].Len = (ush)bits;
+        /* We overwrite tree[n].Dad which is no longer needed */
+
+        if (n > max_code) continue; /* not a leaf node */
+
+        s->bl_count[bits]++;
+        xbits = 0;
+        if (n >= base) xbits = extra[n-base];
+        f = tree[n].Freq;
+        s->opt_len += (ulg)f * (bits + xbits);
+        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+    }
+    if (overflow == 0) return;
+
+    Trace((stderr,"\nbit length overflow\n"));
+    /* This happens for example on obj2 and pic of the Calgary corpus */
+
+    /* Find the first bit length which could increase: */
+    do {
+        bits = max_length-1;
+        while (s->bl_count[bits] == 0) bits--;
+        s->bl_count[bits]--;      /* move one leaf down the tree */
+        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+        s->bl_count[max_length]--;
+        /* The brother of the overflow item also moves one step up,
+         * but this does not affect bl_count[max_length]
+         */
+        overflow -= 2;
+    } while (overflow > 0);
+
+    /* Now recompute all bit lengths, scanning in increasing frequency.
+     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+     * lengths instead of fixing only the wrong ones. This idea is taken
+     * from 'ar' written by Haruhiko Okumura.)
+     */
+    for (bits = max_length; bits != 0; bits--) {
+        n = s->bl_count[bits];
+        while (n != 0) {
+            m = s->heap[--h];
+            if (m > max_code) continue;
+            if (tree[m].Len != (unsigned) bits) {
+                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+                s->opt_len += ((long)bits - (long)tree[m].Len)
+                              *(long)tree[m].Freq;
+                tree[m].Len = (ush)bits;
+            }
+            n--;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+    ct_data *tree;             /* the tree to decorate */
+    int max_code;              /* largest code with non zero frequency */
+    ushf *bl_count;            /* number of codes at each bit length */
+{
+    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+    ush code = 0;              /* running code value */
+    int bits;                  /* bit index */
+    int n;                     /* code index */
+
+    /* The distribution counts are first used to generate the code values
+     * without bit reversal.
+     */
+    for (bits = 1; bits <= MAX_BITS; bits++) {
+        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+    }
+    /* Check that the bit counts in bl_count are consistent. The last code
+     * must be all ones.
+     */
+    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= max_code; n++) {
+        int len = tree[n].Len;
+        if (len == 0) continue;
+        /* Now reverse the bits */
+        tree[n].Code = bi_reverse(next_code[len]++, len);
+
+        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+    }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+    deflate_state *s;
+    tree_desc *desc; /* the tree descriptor */
+{
+    ct_data *tree   = desc->dyn_tree;
+    ct_data *stree  = desc->stat_desc->static_tree;
+    int elems       = desc->stat_desc->elems;
+    int n, m;          /* iterate over heap elements */
+    int max_code = -1; /* largest code with non zero frequency */
+    int node;          /* new node being created */
+
+    /* Construct the initial heap, with least frequent element in
+     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+     * heap[0] is not used.
+     */
+    s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+    for (n = 0; n < elems; n++) {
+        if (tree[n].Freq != 0) {
+            s->heap[++(s->heap_len)] = max_code = n;
+            s->depth[n] = 0;
+        } else {
+            tree[n].Len = 0;
+        }
+    }
+
+    /* The pkzip format requires that at least one distance code exists,
+     * and that at least one bit should be sent even if there is only one
+     * possible code. So to avoid special checks later on we force at least
+     * two codes of non zero frequency.
+     */
+    while (s->heap_len < 2) {
+        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+        tree[node].Freq = 1;
+        s->depth[node] = 0;
+        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+        /* node is 0 or 1 so it does not have extra bits */
+    }
+    desc->max_code = max_code;
+
+    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+     * establish sub-heaps of increasing lengths:
+     */
+    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+    /* Construct the Huffman tree by repeatedly combining the least two
+     * frequent nodes.
+     */
+    node = elems;              /* next internal node of the tree */
+    do {
+        pqremove(s, tree, n);  /* n = node of least frequency */
+        m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+        s->heap[--(s->heap_max)] = m;
+
+        /* Create a new node father of n and m */
+        tree[node].Freq = tree[n].Freq + tree[m].Freq;
+        s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
+        tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+        if (tree == s->bl_tree) {
+            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+        }
+#endif
+        /* and insert the new node in the heap */
+        s->heap[SMALLEST] = node++;
+        pqdownheap(s, tree, SMALLEST);
+
+    } while (s->heap_len >= 2);
+
+    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+    /* At this point, the fields freq and dad are set. We can now
+     * generate the bit lengths.
+     */
+    gen_bitlen(s, (tree_desc *)desc);
+
+    /* The field len is now set, we can generate the bit codes */
+    gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree;   /* the tree to be scanned */
+    int max_code;    /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    if (nextlen == 0) max_count = 138, min_count = 3;
+    tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            s->bl_tree[curlen].Freq += count;
+        } else if (curlen != 0) {
+            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+            s->bl_tree[REP_3_6].Freq++;
+        } else if (count <= 10) {
+            s->bl_tree[REPZ_3_10].Freq++;
+        } else {
+            s->bl_tree[REPZ_11_138].Freq++;
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    /* tree[max_code+1].Len = -1; */  /* guard already set */
+    if (nextlen == 0) max_count = 138, min_count = 3;
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+        } else if (curlen != 0) {
+            if (curlen != prevlen) {
+                send_code(s, curlen, s->bl_tree); count--;
+            }
+            Assert(count >= 3 && count <= 6, " 3_6?");
+            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+        } else if (count <= 10) {
+            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+        } else {
+            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+    deflate_state *s;
+{
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    /* Determine the bit length frequencies for literal and distance trees */
+    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+    /* Build the bit length tree: */
+    build_tree(s, (tree_desc *)(&(s->bl_desc)));
+    /* opt_len now includes the length of the tree representations, except
+     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+     */
+
+    /* Determine the number of bit length codes to send. The pkzip format
+     * requires that at least 4 bit length codes be sent. (appnote.txt says
+     * 3 but the actual value used is 4.)
+     */
+    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+    }
+    /* Update opt_len to include the bit length tree and counts */
+    s->opt_len += 3*(max_blindex+1) + 5+5+4;
+    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+            s->opt_len, s->static_len));
+
+    return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+    deflate_state *s;
+    int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+    int rank;                    /* index in bl_order */
+
+    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+            "too many codes");
+    Tracev((stderr, "\nbl counts: "));
+    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+    send_bits(s, dcodes-1,   5);
+    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
+    for (rank = 0; rank < blcodes; rank++) {
+        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+    }
+    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void _tr_stored_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    send_bits(s, (STORED_BLOCK<<1)+eof, 3);  /* send block type */
+    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+    s->compressed_len += (stored_len + 4) << 3;
+
+    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* Send just the `stored block' type code without any length bytes or data.
+ */
+void _tr_stored_type_only(s)
+    deflate_state *s;
+{
+    send_bits(s, (STORED_BLOCK << 1), 3);
+    bi_windup(s);
+    s->compressed_len = (s->compressed_len + 3) & ~7L;
+}
+
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align(s)
+    deflate_state *s;
+{
+    send_bits(s, STATIC_TREES<<1, 3);
+    send_code(s, END_BLOCK, static_ltree);
+    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+    bi_flush(s);
+    /* Of the 10 bits for the empty block, we have already sent
+     * (10 - bi_valid) bits. The lookahead for the last real code (before
+     * the EOB of the previous block) was thus at least one plus the length
+     * of the EOB plus what we have just sent of the empty static block.
+     */
+    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+        send_bits(s, STATIC_TREES<<1, 3);
+        send_code(s, END_BLOCK, static_ltree);
+        s->compressed_len += 10L;
+        bi_flush(s);
+    }
+    s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file. This function
+ * returns the total compressed length for the file so far.
+ */
+ulg _tr_flush_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block, or NULL if too old */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+    int max_blindex = 0;  /* index of last bit length code of non zero freq */
+
+    /* Build the Huffman trees unless a stored block is forced */
+    if (s->level > 0) {
+
+	 /* Check if the file is ascii or binary */
+	if (s->data_type == Z_UNKNOWN) set_data_type(s);
+
+	/* Construct the literal and distance trees */
+	build_tree(s, (tree_desc *)(&(s->l_desc)));
+	Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+		s->static_len));
+
+	build_tree(s, (tree_desc *)(&(s->d_desc)));
+	Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+		s->static_len));
+	/* At this point, opt_len and static_len are the total bit lengths of
+	 * the compressed block data, excluding the tree representations.
+	 */
+
+	/* Build the bit length tree for the above two trees, and get the index
+	 * in bl_order of the last bit length code to send.
+	 */
+	max_blindex = build_bl_tree(s);
+
+	/* Determine the best encoding. Compute first the block length in bytes*/
+	opt_lenb = (s->opt_len+3+7)>>3;
+	static_lenb = (s->static_len+3+7)>>3;
+
+	Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+		opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+		s->last_lit));
+
+	if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+    } else {
+        Assert(buf != (char*)0, "lost buf");
+	opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+    }
+
+    /* If compression failed and this is the first and last block,
+     * and if the .zip file can be seeked (to rewrite the local header),
+     * the whole file is transformed into a stored file:
+     */
+#ifdef STORED_FILE_OK
+#  ifdef FORCE_STORED_FILE
+    if (eof && s->compressed_len == 0L) { /* force stored file */
+#  else
+    if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) {
+#  endif
+        /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
+        if (buf == (charf*)0) error ("block vanished");
+
+        copy_block(s, buf, (unsigned)stored_len, 0); /* without header */
+        s->compressed_len = stored_len << 3;
+        s->method = STORED;
+    } else
+#endif /* STORED_FILE_OK */
+
+#ifdef FORCE_STORED
+    if (buf != (char*)0) { /* force stored block */
+#else
+    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+                       /* 4: two words for the lengths */
+#endif
+        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+         * Otherwise we can't have processed more than WSIZE input bytes since
+         * the last block flush, because compression would have been
+         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+         * transform a block into a stored block.
+         */
+        _tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+    } else if (static_lenb >= 0) { /* force static trees */
+#else
+    } else if (static_lenb == opt_lenb) {
+#endif
+        send_bits(s, (STATIC_TREES<<1)+eof, 3);
+        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+        s->compressed_len += 3 + s->static_len;
+    } else {
+        send_bits(s, (DYN_TREES<<1)+eof, 3);
+        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+                       max_blindex+1);
+        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+        s->compressed_len += 3 + s->opt_len;
+    }
+    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+    init_block(s);
+
+    if (eof) {
+        bi_windup(s);
+        s->compressed_len += 7;  /* align on byte boundary */
+    }
+    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+           s->compressed_len-7*eof));
+
+    return s->compressed_len >> 3;
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (s, dist, lc)
+    deflate_state *s;
+    unsigned dist;  /* distance of matched string */
+    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+    s->d_buf[s->last_lit] = (ush)dist;
+    s->l_buf[s->last_lit++] = (uch)lc;
+    if (dist == 0) {
+        /* lc is the unmatched char */
+        s->dyn_ltree[lc].Freq++;
+    } else {
+        s->matches++;
+        /* Here, lc is the match length - MIN_MATCH */
+        dist--;             /* dist = match distance - 1 */
+        Assert((ush)dist < (ush)MAX_DIST(s) &&
+               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
+
+        s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
+        s->dyn_dtree[d_code(dist)].Freq++;
+    }
+
+    /* Try to guess if it is profitable to stop the current block here */
+    if (s->level > 2 && (s->last_lit & 0xfff) == 0) {
+        /* Compute an upper bound for the compressed length */
+        ulg out_length = (ulg)s->last_lit*8L;
+        ulg in_length = (ulg)((long)s->strstart - s->block_start);
+        int dcode;
+        for (dcode = 0; dcode < D_CODES; dcode++) {
+            out_length += (ulg)s->dyn_dtree[dcode].Freq *
+                (5L+extra_dbits[dcode]);
+        }
+        out_length >>= 3;
+        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+               s->last_lit, in_length, out_length,
+               100L - out_length*100L/in_length));
+        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+    }
+    return (s->last_lit == s->lit_bufsize-1);
+    /* We avoid equality with lit_bufsize because of wraparound at 64K
+     * on 16 bit machines and because stored blocks are restricted to
+     * 64K-1 bytes.
+     */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+    deflate_state *s;
+    ct_data *ltree; /* literal tree */
+    ct_data *dtree; /* distance tree */
+{
+    unsigned dist;      /* distance of matched string */
+    int lc;             /* match length or unmatched char (if dist == 0) */
+    unsigned lx = 0;    /* running index in l_buf */
+    unsigned code;      /* the code to send */
+    int extra;          /* number of extra bits to send */
+
+    if (s->last_lit != 0) do {
+        dist = s->d_buf[lx];
+        lc = s->l_buf[lx++];
+        if (dist == 0) {
+            send_code(s, lc, ltree); /* send a literal byte */
+            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+        } else {
+            /* Here, lc is the match length - MIN_MATCH */
+            code = length_code[lc];
+            send_code(s, code+LITERALS+1, ltree); /* send the length code */
+            extra = extra_lbits[code];
+            if (extra != 0) {
+                lc -= base_length[code];
+                send_bits(s, lc, extra);       /* send the extra length bits */
+            }
+            dist--; /* dist is now the match distance - 1 */
+            code = d_code(dist);
+            Assert (code < D_CODES, "bad d_code");
+
+            send_code(s, code, dtree);       /* send the distance code */
+            extra = extra_dbits[code];
+            if (extra != 0) {
+                dist -= base_dist[code];
+                send_bits(s, dist, extra);   /* send the extra distance bits */
+            }
+        } /* literal or match pair ? */
+
+        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+        Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
+
+    } while (lx < s->last_lit);
+
+    send_code(s, END_BLOCK, ltree);
+    s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+local void set_data_type(s)
+    deflate_state *s;
+{
+    int n = 0;
+    unsigned ascii_freq = 0;
+    unsigned bin_freq = 0;
+    while (n < 7)        bin_freq += s->dyn_ltree[n++].Freq;
+    while (n < 128)    ascii_freq += s->dyn_ltree[n++].Freq;
+    while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
+    s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+    unsigned code; /* the value to invert */
+    int len;       /* its bit length */
+{
+    register unsigned res = 0;
+    do {
+        res |= code & 1;
+        code >>= 1, res <<= 1;
+    } while (--len > 0);
+    return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+    deflate_state *s;
+{
+    if (s->bi_valid == 16) {
+        put_short(s, s->bi_buf);
+        s->bi_buf = 0;
+        s->bi_valid = 0;
+    } else if (s->bi_valid >= 8) {
+        put_byte(s, (Byte)s->bi_buf);
+        s->bi_buf >>= 8;
+        s->bi_valid -= 8;
+    }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+    deflate_state *s;
+{
+    if (s->bi_valid > 8) {
+        put_short(s, s->bi_buf);
+    } else if (s->bi_valid > 0) {
+        put_byte(s, (Byte)s->bi_buf);
+    }
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+#ifdef DEBUG_ZLIB
+    s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+    deflate_state *s;
+    charf    *buf;    /* the input data */
+    unsigned len;     /* its length */
+    int      header;  /* true if block header must be written */
+{
+    bi_windup(s);        /* align on byte boundary */
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+
+    if (header) {
+        put_short(s, (ush)len);   
+        put_short(s, (ush)~len);
+#ifdef DEBUG_ZLIB
+        s->bits_sent += 2*16;
+#endif
+    }
+#ifdef DEBUG_ZLIB
+    s->bits_sent += (ulg)len<<3;
+#endif
+    /* bundle up the put_byte(s, *buf++) calls */
+    zmemcpy(&s->pending_buf[s->pending], buf, len);
+    s->pending += len;
+}
+/* --- trees.c */
+
+/* +++ inflate.c */
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* #include "zutil.h" */
+
+/* +++ infblock.h */
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+extern inflate_blocks_statef * inflate_blocks_new OF((
+    z_streamp z,
+    check_func c,               /* check function */
+    uInt w));                   /* window size */
+
+extern int inflate_blocks OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));                      /* initial return code */
+
+extern void inflate_blocks_reset OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    uLongf *));                  /* check value on output */
+
+extern int inflate_blocks_free OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    uLongf *));                  /* check value on output */
+
+extern void inflate_set_dictionary OF((
+    inflate_blocks_statef *s,
+    const Bytef *d,  /* dictionary */
+    uInt  n));       /* dictionary length */
+
+extern int inflate_addhistory OF((
+    inflate_blocks_statef *,
+    z_streamp));
+
+extern int inflate_packet_flush OF((
+    inflate_blocks_statef *));
+/* --- infblock.h */
+
+#ifndef NO_DUMMY_DECL
+struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
+#endif
+
+/* inflate private state */
+struct internal_state {
+
+  /* mode */
+  enum {
+      METHOD,   /* waiting for method byte */
+      FLAG,     /* waiting for flag byte */
+      DICT4,    /* four dictionary check bytes to go */
+      DICT3,    /* three dictionary check bytes to go */
+      DICT2,    /* two dictionary check bytes to go */
+      DICT1,    /* one dictionary check byte to go */
+      DICT0,    /* waiting for inflateSetDictionary */
+      BLOCKS,   /* decompressing blocks */
+      CHECK4,   /* four check bytes to go */
+      CHECK3,   /* three check bytes to go */
+      CHECK2,   /* two check bytes to go */
+      CHECK1,   /* one check byte to go */
+      DONE,     /* finished check, done */
+      BAD}      /* got an error--stay here */
+    mode;               /* current inflate mode */
+
+  /* mode dependent information */
+  union {
+    uInt method;        /* if FLAGS, method byte */
+    struct {
+      uLong was;                /* computed check value */
+      uLong need;               /* stream check value */
+    } check;            /* if CHECK, check values to compare */
+    uInt marker;        /* if BAD, inflateSync's marker bytes count */
+  } sub;        /* submode */
+
+  /* mode independent information */
+  int  nowrap;          /* flag for no wrapper */
+  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
+  inflate_blocks_statef 
+    *blocks;            /* current inflate_blocks state */
+
+};
+
+
+int inflateReset(z)
+z_streamp z;
+{
+  uLong c;
+
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->total_in = z->total_out = 0;
+  z->msg = Z_NULL;
+  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+  inflate_blocks_reset(z->state->blocks, z, &c);
+  Trace((stderr, "inflate: reset\n"));
+  return Z_OK;
+}
+
+
+int inflateEnd(z)
+z_streamp z;
+{
+  uLong c;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->blocks != Z_NULL)
+    inflate_blocks_free(z->state->blocks, z, &c);
+  ZFREE(z, z->state);
+  z->state = Z_NULL;
+  Trace((stderr, "inflate: end\n"));
+  return Z_OK;
+}
+
+
+int inflateInit2_(z, w, version, stream_size)
+z_streamp z;
+int w;
+const char *version;
+int stream_size;
+{
+  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+      stream_size != sizeof(z_stream))
+      return Z_VERSION_ERROR;
+
+  /* initialize state */
+  if (z == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->msg = Z_NULL;
+#ifndef NO_ZCFUNCS
+  if (z->zalloc == Z_NULL)
+  {
+    z->zalloc = zcalloc;
+    z->opaque = (voidpf)0;
+  }
+  if (z->zfree == Z_NULL) z->zfree = zcfree;
+#endif
+  if ((z->state = (struct internal_state FAR *)
+       ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+    return Z_MEM_ERROR;
+  z->state->blocks = Z_NULL;
+
+  /* handle undocumented nowrap option (no zlib header or check) */
+  z->state->nowrap = 0;
+  if (w < 0)
+  {
+    w = - w;
+    z->state->nowrap = 1;
+  }
+
+  /* set window size */
+  if (w < 8 || w > 15)
+  {
+    inflateEnd(z);
+    return Z_STREAM_ERROR;
+  }
+  z->state->wbits = (uInt)w;
+
+  /* create inflate_blocks state */
+  if ((z->state->blocks =
+      inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
+      == Z_NULL)
+  {
+    inflateEnd(z);
+    return Z_MEM_ERROR;
+  }
+  Trace((stderr, "inflate: allocated\n"));
+
+  /* reset state */
+  inflateReset(z);
+  return Z_OK;
+}
+
+
+int inflateInit_(z, version, stream_size)
+z_streamp z;
+const char *version;
+int stream_size;
+{
+  return inflateInit2_(z, DEF_WBITS, version, stream_size);
+}
+
+
+#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int inflate(z, f)
+z_streamp z;
+int f;
+{
+  int r;
+  uInt b;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL || f < 0)
+    return Z_STREAM_ERROR;
+  r = Z_BUF_ERROR;
+  while (1) switch (z->state->mode)
+  {
+    case METHOD:
+      NEEDBYTE
+      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"unknown compression method";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"invalid window size";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      z->state->mode = FLAG;
+    case FLAG:
+      NEEDBYTE
+      b = NEXTBYTE;
+      if (((z->state->sub.method << 8) + b) % 31)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"incorrect header check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Trace((stderr, "inflate: zlib header ok\n"));
+      if (!(b & PRESET_DICT))
+      {
+        z->state->mode = BLOCKS;
+	break;
+      }
+      z->state->mode = DICT4;
+    case DICT4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = DICT3;
+    case DICT3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = DICT2;
+    case DICT2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = DICT1;
+    case DICT1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+      z->adler = z->state->sub.check.need;
+      z->state->mode = DICT0;
+      return Z_NEED_DICT;
+    case DICT0:
+      z->state->mode = BAD;
+      z->msg = (char*)"need dictionary";
+      z->state->sub.marker = 0;       /* can try inflateSync */
+      return Z_STREAM_ERROR;
+    case BLOCKS:
+      r = inflate_blocks(z->state->blocks, z, r);
+      if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
+	  r = inflate_packet_flush(z->state->blocks);
+      if (r == Z_DATA_ERROR)
+      {
+        z->state->mode = BAD;
+        z->state->sub.marker = 0;       /* can try inflateSync */
+        break;
+      }
+      if (r != Z_STREAM_END)
+        return r;
+      r = Z_OK;
+      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+      if (z->state->nowrap)
+      {
+        z->state->mode = DONE;
+        break;
+      }
+      z->state->mode = CHECK4;
+    case CHECK4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = CHECK3;
+    case CHECK3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = CHECK2;
+    case CHECK2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = CHECK1;
+    case CHECK1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+
+      if (z->state->sub.check.was != z->state->sub.check.need)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"incorrect data check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Trace((stderr, "inflate: zlib check ok\n"));
+      z->state->mode = DONE;
+    case DONE:
+      return Z_STREAM_END;
+    case BAD:
+      return Z_DATA_ERROR;
+    default:
+      return Z_STREAM_ERROR;
+  }
+
+ empty:
+  if (f != Z_PACKET_FLUSH)
+    return r;
+  z->state->mode = BAD;
+  z->msg = (char *)"need more for packet flush";
+  z->state->sub.marker = 0;       /* can try inflateSync */
+  return Z_DATA_ERROR;
+}
+
+
+int inflateSetDictionary(z, dictionary, dictLength)
+z_streamp z;
+const Bytef *dictionary;
+uInt  dictLength;
+{
+  uInt length = dictLength;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0)
+    return Z_STREAM_ERROR;
+
+  if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
+  z->adler = 1L;
+
+  if (length >= ((uInt)1<<z->state->wbits))
+  {
+    length = (1<<z->state->wbits)-1;
+    dictionary += dictLength - length;
+  }
+  inflate_set_dictionary(z->state->blocks, dictionary, length);
+  z->state->mode = BLOCKS;
+  return Z_OK;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS).  On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+
+int inflateIncomp(z)
+z_stream *z;
+{
+    if (z->state->mode != BLOCKS)
+	return Z_DATA_ERROR;
+    return inflate_addhistory(z->state->blocks, z);
+}
+
+
+int inflateSync(z)
+z_streamp z;
+{
+  uInt n;       /* number of bytes to look at */
+  Bytef *p;     /* pointer to bytes */
+  uInt m;       /* number of marker bytes found in a row */
+  uLong r, w;   /* temporaries to save total_in and total_out */
+
+  /* set up */
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->mode != BAD)
+  {
+    z->state->mode = BAD;
+    z->state->sub.marker = 0;
+  }
+  if ((n = z->avail_in) == 0)
+    return Z_BUF_ERROR;
+  p = z->next_in;
+  m = z->state->sub.marker;
+
+  /* search */
+  while (n && m < 4)
+  {
+    if (*p == (Byte)(m < 2 ? 0 : 0xff))
+      m++;
+    else if (*p)
+      m = 0;
+    else
+      m = 4 - m;
+    p++, n--;
+  }
+
+  /* restore */
+  z->total_in += p - z->next_in;
+  z->next_in = p;
+  z->avail_in = n;
+  z->state->sub.marker = m;
+
+  /* return no joy or set up to restart on a new block */
+  if (m != 4)
+    return Z_DATA_ERROR;
+  r = z->total_in;  w = z->total_out;
+  inflateReset(z);
+  z->total_in = r;  z->total_out = w;
+  z->state->mode = BLOCKS;
+  return Z_OK;
+}
+
+#undef NEEDBYTE
+#undef NEXTBYTE
+/* --- inflate.c */
+
+/* +++ infblock.c */
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* #include "zutil.h" */
+/* #include "infblock.h" */
+
+/* +++ inftrees.h */
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+   that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+  union {
+    struct {
+      Byte Exop;        /* number of extra bits or operation */
+      Byte Bits;        /* number of bits in this code or subcode */
+    } what;
+    Bytef *pad;         /* pad structure to a power of 2 (4 bytes for */
+  } word;               /*  16-bit, 8 bytes for 32-bit machines) */
+  union {
+    uInt Base;          /* literal, length base, or distance base */
+    inflate_huft *Next; /* pointer to next level of table */
+  } more;
+};
+
+#ifdef DEBUG_ZLIB
+  extern uInt inflate_hufts;
+#endif
+
+extern int inflate_trees_bits OF((
+    uIntf *,                    /* 19 code lengths */
+    uIntf *,                    /* bits tree desired/actual depth */
+    inflate_huft * FAR *,       /* bits tree result */
+    z_streamp ));               /* for zalloc, zfree functions */
+
+extern int inflate_trees_dynamic OF((
+    uInt,                       /* number of literal/length codes */
+    uInt,                       /* number of distance codes */
+    uIntf *,                    /* that many (total) code lengths */
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *,       /* distance tree result */
+    z_streamp ));               /* for zalloc, zfree functions */
+
+extern int inflate_trees_fixed OF((
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *));     /* distance tree result */
+
+extern int inflate_trees_free OF((
+    inflate_huft *,             /* tables to free */
+    z_streamp ));               /* for zfree function */
+
+/* --- inftrees.h */
+
+/* +++ infcodes.h */
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+extern inflate_codes_statef *inflate_codes_new OF((
+    uInt, uInt,
+    inflate_huft *, inflate_huft *,
+    z_streamp ));
+
+extern int inflate_codes OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));
+
+extern void inflate_codes_free OF((
+    inflate_codes_statef *,
+    z_streamp ));
+
+/* --- infcodes.h */
+
+/* +++ infutil.h */
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFUTIL_H
+#define _INFUTIL_H
+
+typedef enum {
+      TYPE,     /* get type bits (3, including end bit) */
+      LENS,     /* get lengths for stored */
+      STORED,   /* processing stored block */
+      TABLE,    /* get table lengths */
+      BTREE,    /* get bit lengths tree for a dynamic block */
+      DTREE,    /* get length, distance trees for a dynamic block */
+      CODES,    /* processing fixed or dynamic block */
+      DRY,      /* output remaining window bytes */
+      DONEB,    /* finished last block, done */
+      BADB}     /* got a data error--stuck here */
+inflate_block_mode;
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+  /* mode */
+  inflate_block_mode  mode;     /* current inflate_block mode */
+
+  /* mode dependent information */
+  union {
+    uInt left;          /* if STORED, bytes left to copy */
+    struct {
+      uInt table;               /* table lengths (14 bits) */
+      uInt index;               /* index into blens (or border) */
+      uIntf *blens;             /* bit lengths of codes */
+      uInt bb;                  /* bit length tree depth */
+      inflate_huft *tb;         /* bit length decoding tree */
+    } trees;            /* if DTREE, decoding info for trees */
+    struct {
+      inflate_huft *tl;
+      inflate_huft *td;         /* trees to free */
+      inflate_codes_statef 
+         *codes;
+    } decode;           /* if CODES, current state */
+  } sub;                /* submode */
+  uInt last;            /* true if this block is the last block */
+
+  /* mode independent information */
+  uInt bitk;            /* bits in bit buffer */
+  uLong bitb;           /* bit buffer */
+  Bytef *window;        /* sliding window */
+  Bytef *end;           /* one byte after sliding window */
+  Bytef *read;          /* window read pointer */
+  Bytef *write;         /* window write pointer */
+  check_func checkfn;   /* check function */
+  uLong check;          /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/*   update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/*   get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/*   output bytes */
+#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
+#define WWRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WWRAP if(m==0){FLUSH WWRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/*   load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
+extern uInt inflate_mask[17];
+
+/* copy as much as possible from the sliding window to the output area */
+extern int inflate_flush OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));
+
+#ifndef NO_DUMMY_DECL
+struct internal_state      {int dummy;}; /* for buggy compilers */
+#endif
+
+#endif
+/* --- infutil.h */
+
+#ifndef NO_DUMMY_DECL
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+#endif
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local const uInt border[] = { /* Order of the bit length code lengths */
+        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+   Notes beyond the 1.93a appnote.txt:
+
+   1. Distance pointers never point before the beginning of the output
+      stream.
+   2. Distance pointers can point back across blocks, up to 32k away.
+   3. There is an implied maximum of 7 bits for the bit length table and
+      15 bits for the actual data.
+   4. If only one code exists, then it is encoded using one bit.  (Zero
+      would be more efficient, but perhaps a little confusing.)  If two
+      codes exist, they are coded using one bit each (0 and 1).
+   5. There is no way of sending zero distance codes--a dummy must be
+      sent if there are none.  (History: a pre 2.0 version of PKZIP would
+      store blocks with no distance codes, but this was discovered to be
+      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
+      zero distance codes, which is sent as one code of zero bits in
+      length.
+   6. There are up to 286 literal/length codes.  Code 256 represents the
+      end-of-block.  Note however that the static length tree defines
+      288 codes just to fill out the Huffman codes.  Codes 286 and 287
+      cannot be used though, since there is no length base or extra bits
+      defined for them.  Similarily, there are up to 30 distance codes.
+      However, static trees define 32 codes (all 5 bits) to fill out the
+      Huffman codes, but the last two had better not show up in the data.
+   7. Unzip can check dynamic Huffman blocks for complete code sets.
+      The exception is that a single code would not be complete (see #4).
+   8. The five bits following the block type is really the number of
+      literal codes sent minus 257.
+   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+      (1+6+6).  Therefore, to output three times the length, you output
+      three codes (1+1+1), whereas to output four times the same length,
+      you only need two codes (1+3).  Hmm.
+  10. In the tree reconstruction algorithm, Code = Code + Increment
+      only if BitLength(i) is not zero.  (Pretty obvious.)
+  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
+  12. Note: length code 284 can represent 227-258, but length code 285
+      really is 258.  The last length deserves its own, short code
+      since it gets used a lot in very redundant files.  The length
+      258 is special since 258 - 3 (the min match length) is 255.
+  13. The literal/length and distance code bit lengths are read as a
+      single stream of lengths.  It is possible (and advantageous) for
+      a repeat code (16, 17, or 18) to go across the boundary between
+      the two sets of lengths.
+ */
+
+
+void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+  if (s->checkfn != Z_NULL)
+    *c = s->check;
+  if (s->mode == BTREE || s->mode == DTREE)
+    ZFREE(z, s->sub.trees.blens);
+  if (s->mode == CODES)
+  {
+    inflate_codes_free(s->sub.decode.codes, z);
+    inflate_trees_free(s->sub.decode.td, z);
+    inflate_trees_free(s->sub.decode.tl, z);
+  }
+  s->mode = TYPE;
+  s->bitk = 0;
+  s->bitb = 0;
+  s->read = s->write = s->window;
+  if (s->checkfn != Z_NULL)
+    z->adler = s->check = (*s->checkfn)(0L, Z_NULL, 0);
+  Trace((stderr, "inflate:   blocks reset\n"));
+}
+
+
+inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_streamp z;
+check_func c;
+uInt w;
+{
+  inflate_blocks_statef *s;
+
+  if ((s = (inflate_blocks_statef *)ZALLOC
+       (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
+    return s;
+  if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+  {
+    ZFREE(z, s);
+    return Z_NULL;
+  }
+  s->end = s->window + w;
+  s->checkfn = c;
+  s->mode = TYPE;
+  Trace((stderr, "inflate:   blocks allocated\n"));
+  inflate_blocks_reset(s, z, &s->check);
+  return s;
+}
+
+
+#ifdef DEBUG_ZLIB
+  extern uInt inflate_hufts;
+#endif
+int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt t;               /* temporary storage */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input based on current state */
+  while (1) switch (s->mode)
+  {
+    case TYPE:
+      NEEDBITS(3)
+      t = (uInt)b & 7;
+      s->last = t & 1;
+      switch (t >> 1)
+      {
+        case 0:                         /* stored */
+          Trace((stderr, "inflate:     stored block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          t = k & 7;                    /* go to byte boundary */
+          DUMPBITS(t)
+          s->mode = LENS;               /* get length of stored block */
+          break;
+        case 1:                         /* fixed */
+          Trace((stderr, "inflate:     fixed codes block%s\n",
+                 s->last ? " (last)" : ""));
+          {
+            uInt bl, bd;
+            inflate_huft *tl, *td;
+
+            inflate_trees_fixed(&bl, &bd, &tl, &td);
+            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+            if (s->sub.decode.codes == Z_NULL)
+            {
+              r = Z_MEM_ERROR;
+              LEAVE
+            }
+            s->sub.decode.tl = Z_NULL;  /* don't try to free these */
+            s->sub.decode.td = Z_NULL;
+          }
+          DUMPBITS(3)
+          s->mode = CODES;
+          break;
+        case 2:                         /* dynamic */
+          Trace((stderr, "inflate:     dynamic codes block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          s->mode = TABLE;
+          break;
+        case 3:                         /* illegal */
+          DUMPBITS(3)
+          s->mode = BADB;
+          z->msg = (char*)"invalid block type";
+          r = Z_DATA_ERROR;
+          LEAVE
+      }
+      break;
+    case LENS:
+      NEEDBITS(32)
+      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
+      {
+        s->mode = BADB;
+        z->msg = (char*)"invalid stored block lengths";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+      s->sub.left = (uInt)b & 0xffff;
+      b = k = 0;                      /* dump bits */
+      Tracev((stderr, "inflate:       stored length %u\n", s->sub.left));
+      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
+      break;
+    case STORED:
+      if (n == 0)
+        LEAVE
+      NEEDOUT
+      t = s->sub.left;
+      if (t > n) t = n;
+      if (t > m) t = m;
+      zmemcpy(q, p, t);
+      p += t;  n -= t;
+      q += t;  m -= t;
+      if ((s->sub.left -= t) != 0)
+        break;
+      Tracev((stderr, "inflate:       stored end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      s->mode = s->last ? DRY : TYPE;
+      break;
+    case TABLE:
+      NEEDBITS(14)
+      s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+      {
+        s->mode = BADB;
+        z->msg = (char*)"too many length or distance symbols";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+#endif
+      t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+      if (t < 19)
+        t = 19;
+      if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+      {
+        r = Z_MEM_ERROR;
+        LEAVE
+      }
+      DUMPBITS(14)
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       table sizes ok\n"));
+      s->mode = BTREE;
+    case BTREE:
+      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+      {
+        NEEDBITS(3)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+        DUMPBITS(3)
+      }
+      while (s->sub.trees.index < 19)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+      s->sub.trees.bb = 7;
+      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+                             &s->sub.trees.tb, z);
+      if (t != Z_OK)
+      {
+        ZFREE(z, s->sub.trees.blens);
+        r = t;
+        if (r == Z_DATA_ERROR)
+          s->mode = BADB;
+        LEAVE
+      }
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       bits tree ok\n"));
+      s->mode = DTREE;
+    case DTREE:
+      while (t = s->sub.trees.table,
+             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+      {
+        inflate_huft *h;
+        uInt i, j, c;
+
+        t = s->sub.trees.bb;
+        NEEDBITS(t)
+        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+        t = h->word.what.Bits;
+        c = h->more.Base;
+        if (c < 16)
+        {
+          DUMPBITS(t)
+          s->sub.trees.blens[s->sub.trees.index++] = c;
+        }
+        else /* c == 16..18 */
+        {
+          i = c == 18 ? 7 : c - 14;
+          j = c == 18 ? 11 : 3;
+          NEEDBITS(t + i)
+          DUMPBITS(t)
+          j += (uInt)b & inflate_mask[i];
+          DUMPBITS(i)
+          i = s->sub.trees.index;
+          t = s->sub.trees.table;
+          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+              (c == 16 && i < 1))
+          {
+            inflate_trees_free(s->sub.trees.tb, z);
+            ZFREE(z, s->sub.trees.blens);
+            s->mode = BADB;
+            z->msg = (char*)"invalid bit length repeat";
+            r = Z_DATA_ERROR;
+            LEAVE
+          }
+          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+          do {
+            s->sub.trees.blens[i++] = c;
+          } while (--j);
+          s->sub.trees.index = i;
+        }
+      }
+      inflate_trees_free(s->sub.trees.tb, z);
+      s->sub.trees.tb = Z_NULL;
+      {
+        uInt bl, bd;
+        inflate_huft *tl, *td;
+        inflate_codes_statef *c;
+
+        bl = 9;         /* must be <= 9 for lookahead assumptions */
+        bd = 6;         /* must be <= 9 for lookahead assumptions */
+        t = s->sub.trees.table;
+#ifdef DEBUG_ZLIB
+      inflate_hufts = 0;
+#endif
+        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+                                  s->sub.trees.blens, &bl, &bd, &tl, &td, z);
+        ZFREE(z, s->sub.trees.blens);
+        if (t != Z_OK)
+        {
+          if (t == (uInt)Z_DATA_ERROR)
+            s->mode = BADB;
+          r = t;
+          LEAVE
+        }
+        Tracev((stderr, "inflate:       trees ok, %d * %d bytes used\n",
+              inflate_hufts, sizeof(inflate_huft)));
+        if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+        {
+          inflate_trees_free(td, z);
+          inflate_trees_free(tl, z);
+          r = Z_MEM_ERROR;
+          LEAVE
+        }
+        s->sub.decode.codes = c;
+        s->sub.decode.tl = tl;
+        s->sub.decode.td = td;
+      }
+      s->mode = CODES;
+    case CODES:
+      UPDATE
+      if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+        return inflate_flush(s, z, r);
+      r = Z_OK;
+      inflate_codes_free(s->sub.decode.codes, z);
+      inflate_trees_free(s->sub.decode.td, z);
+      inflate_trees_free(s->sub.decode.tl, z);
+      LOAD
+      Tracev((stderr, "inflate:       codes end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      if (!s->last)
+      {
+        s->mode = TYPE;
+        break;
+      }
+      if (k > 7)              /* return unused byte, if any */
+      {
+        Assert(k < 16, "inflate_codes grabbed too many bytes")
+        k -= 8;
+        n++;
+        p--;                    /* can always return one */
+      }
+      s->mode = DRY;
+    case DRY:
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      s->mode = DONEB;
+    case DONEB:
+      r = Z_STREAM_END;
+      LEAVE
+    case BADB:
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+}
+
+
+int inflate_blocks_free(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+  inflate_blocks_reset(s, z, c);
+  ZFREE(z, s->window);
+  ZFREE(z, s);
+  Trace((stderr, "inflate:   blocks freed\n"));
+  return Z_OK;
+}
+
+
+void inflate_set_dictionary(s, d, n)
+inflate_blocks_statef *s;
+const Bytef *d;
+uInt  n;
+{
+  zmemcpy((charf *)s->window, d, n);
+  s->read = s->write = s->window + n;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS).  On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+int inflate_addhistory(s, z)
+inflate_blocks_statef *s;
+z_stream *z;
+{
+    uLong b;              /* bit buffer */  /* NOT USED HERE */
+    uInt k;               /* bits in bit buffer */ /* NOT USED HERE */
+    uInt t;               /* temporary storage */
+    Bytef *p;             /* input data pointer */
+    uInt n;               /* bytes available there */
+    Bytef *q;             /* output window write pointer */
+    uInt m;               /* bytes to end of window or read pointer */
+
+    if (s->read != s->write)
+	return Z_STREAM_ERROR;
+    if (s->mode != TYPE)
+	return Z_DATA_ERROR;
+
+    /* we're ready to rock */
+    LOAD
+    /* while there is input ready, copy to output buffer, moving
+     * pointers as needed.
+     */
+    while (n) {
+	t = n;  /* how many to do */
+	/* is there room until end of buffer? */
+	if (t > m) t = m;
+	/* update check information */
+	if (s->checkfn != Z_NULL)
+	    s->check = (*s->checkfn)(s->check, q, t);
+	zmemcpy(q, p, t);
+	q += t;
+	p += t;
+	n -= t;
+	z->total_out += t;
+	s->read = q;    /* drag read pointer forward */
+/*      WWRAP  */ 	/* expand WWRAP macro by hand to handle s->read */
+	if (q == s->end) {
+	    s->read = q = s->window;
+	    m = WAVAIL;
+	}
+    }
+    UPDATE
+    return Z_OK;
+}
+
+
+/*
+ * At the end of a Deflate-compressed PPP packet, we expect to have seen
+ * a `stored' block type value but not the (zero) length bytes.
+ */
+int inflate_packet_flush(s)
+    inflate_blocks_statef *s;
+{
+    if (s->mode != LENS)
+	return Z_DATA_ERROR;
+    s->mode = TYPE;
+    return Z_OK;
+}
+/* --- infblock.c */
+
+/* +++ inftrees.c */
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* #include "zutil.h" */
+/* #include "inftrees.h" */
+
+char inflate_copyright[] = " inflate 1.0.4 Copyright 1995-1996 Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+#ifndef NO_DUMMY_DECL
+struct internal_state  {int dummy;}; /* for buggy compilers */
+#endif
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+    uIntf *,            /* code lengths in bits */
+    uInt,               /* number of codes */
+    uInt,               /* number of "simple" codes */
+    const uIntf *,      /* list of base values for non-simple codes */
+    const uIntf *,      /* list of extra bits for non-simple codes */
+    inflate_huft * FAR*,/* result: starting table */
+    uIntf *,            /* maximum lookup bits (returns actual) */
+    z_streamp ));       /* for zalloc function */
+
+local voidpf falloc OF((
+    voidpf,             /* opaque pointer (not used) */
+    uInt,               /* number of items */
+    uInt));             /* size of item */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+        /* see note #13 above about 258 */
+local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
+local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577};
+local const uInt cpdext[30] = { /* Extra bits for distance codes */
+        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13};
+
+/*
+   Huffman code decoding is performed using a multi-level table lookup.
+   The fastest way to decode is to simply build a lookup table whose
+   size is determined by the longest code.  However, the time it takes
+   to build this table can also be a factor if the data being decoded
+   is not very long.  The most common codes are necessarily the
+   shortest codes, so those codes dominate the decoding time, and hence
+   the speed.  The idea is you can have a shorter table that decodes the
+   shorter, more probable codes, and then point to subsidiary tables for
+   the longer codes.  The time it costs to decode the longer codes is
+   then traded against the time it takes to make longer tables.
+
+   This results of this trade are in the variables lbits and dbits
+   below.  lbits is the number of bits the first level table for literal/
+   length codes can decode in one step, and dbits is the same thing for
+   the distance codes.  Subsequent tables are also less than or equal to
+   those sizes.  These values may be adjusted either when all of the
+   codes are shorter than that, in which case the longest code length in
+   bits is used, or when the shortest code is *longer* than the requested
+   table size, in which case the length of the shortest code in bits is
+   used.
+
+   There are two different values for the two tables, since they code a
+   different number of possibilities each.  The literal/length table
+   codes 286 possible values, or in a flat code, a little over eight
+   bits.  The distance table codes 30 possible values, or a little less
+   than five bits, flat.  The optimum values for speed end up being
+   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+   The optimum values may differ though from machine to machine, and
+   possibly even between compilers.  Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15         /* maximum bit length of any code */
+#define N_MAX 288       /* maximum number of codes in any set */
+
+#ifdef DEBUG_ZLIB
+  uInt inflate_hufts;
+#endif
+
+local int huft_build(b, n, s, d, e, t, m, zs)
+uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
+uInt n;                 /* number of codes (assumed <= N_MAX) */
+uInt s;                 /* number of simple-valued codes (0..s-1) */
+const uIntf *d;         /* list of base values for non-simple codes */
+const uIntf *e;         /* list of extra bits for non-simple codes */
+inflate_huft * FAR *t;  /* result: starting table */
+uIntf *m;               /* maximum lookup bits, returns actual */
+z_streamp zs;           /* for zalloc function */
+/* Given a list of code lengths and a maximum table size, make a set of
+   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
+   if the given code set is incomplete (the tables are still built in this
+   case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
+   lengths), or Z_MEM_ERROR if not enough memory. */
+{
+
+  uInt a;                       /* counter for codes of length k */
+  uInt c[BMAX+1];               /* bit length count table */
+  uInt f;                       /* i repeats in table every f entries */
+  int g;                        /* maximum code length */
+  int h;                        /* table level */
+  register uInt i;              /* counter, current code */
+  register uInt j;              /* counter */
+  register int k;               /* number of bits in current code */
+  int l;                        /* bits per table (returned in m) */
+  register uIntf *p;            /* pointer into c[], b[], or v[] */
+  inflate_huft *q;              /* points to current table */
+  struct inflate_huft_s r;      /* table entry for structure assignment */
+  inflate_huft *u[BMAX];        /* table stack */
+  uInt v[N_MAX];                /* values in order of bit length */
+  register int w;               /* bits before this table == (l * h) */
+  uInt x[BMAX+1];               /* bit offsets, then code stack */
+  uIntf *xp;                    /* pointer into x */
+  int y;                        /* number of dummy codes added */
+  uInt z;                       /* number of entries in current table */
+
+
+  /* Generate counts for each bit length */
+  p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+  C4                            /* clear c[]--assume BMAX+1 is 16 */
+  p = b;  i = n;
+  do {
+    c[*p++]++;                  /* assume all entries <= BMAX */
+  } while (--i);
+  if (c[0] == n)                /* null input--all zero length codes */
+  {
+    *t = (inflate_huft *)Z_NULL;
+    *m = 0;
+    return Z_OK;
+  }
+
+
+  /* Find minimum and maximum length, bound *m by those */
+  l = *m;
+  for (j = 1; j <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((uInt)l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((uInt)l > i)
+    l = i;
+  *m = l;
+
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0)
+      return Z_DATA_ERROR;
+  if ((y -= c[i]) < 0)
+    return Z_DATA_ERROR;
+  c[i] += y;
+
+
+  /* Generate starting offsets into the value table for each length */
+  x[1] = j = 0;
+  p = c + 1;  xp = x + 2;
+  while (--i) {                 /* note that i == g from above */
+    *xp++ = (j += *p++);
+  }
+
+
+  /* Make a table of values in order of bit lengths */
+  p = b;  i = 0;
+  do {
+    if ((j = *p++) != 0)
+      v[x[j]++] = i;
+  } while (++i < n);
+  n = x[g];                   /* set n to length of v */
+
+
+  /* Generate the Huffman codes and for each, make the table entries */
+  x[0] = i = 0;                 /* first Huffman code is zero */
+  p = v;                        /* grab values in bit order */
+  h = -1;                       /* no tables yet--level -1 */
+  w = -l;                       /* bits decoded == (l * h) */
+  u[0] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */
+  q = (inflate_huft *)Z_NULL;   /* ditto */
+  z = 0;                        /* ditto */
+
+  /* go through the bit lengths (k already is bits in shortest code) */
+  for (; k <= g; k++)
+  {
+    a = c[k];
+    while (a--)
+    {
+      /* here i is the Huffman code of length k bits for value *p */
+      /* make tables up to required level */
+      while (k > w + l)
+      {
+        h++;
+        w += l;                 /* previous table always l bits */
+
+        /* compute minimum size table less than or equal to l bits */
+        z = g - w;
+        z = z > (uInt)l ? l : z;        /* table size upper limit */
+        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
+        {                       /* too few codes for k-w bit table */
+          f -= a + 1;           /* deduct codes from patterns left */
+          xp = c + k;
+          if (j < z)
+            while (++j < z)     /* try smaller tables up to z bits */
+            {
+              if ((f <<= 1) <= *++xp)
+                break;          /* enough codes to use up j bits */
+              f -= *xp;         /* else deduct codes from patterns */
+            }
+        }
+        z = 1 << j;             /* table entries for j-bit table */
+
+        /* allocate and link in new table */
+        if ((q = (inflate_huft *)ZALLOC
+             (zs,z + 1,sizeof(inflate_huft))) == Z_NULL)
+        {
+          if (h)
+            inflate_trees_free(u[0], zs);
+          return Z_MEM_ERROR;   /* not enough memory */
+        }
+#ifdef DEBUG_ZLIB
+        inflate_hufts += z + 1;
+#endif
+        *t = q + 1;             /* link to list for huft_free() */
+        *(t = &(q->next)) = Z_NULL;
+        u[h] = ++q;             /* table starts after link */
+
+        /* connect to last table, if there is one */
+        if (h)
+        {
+          x[h] = i;             /* save pattern for backing up */
+          r.bits = (Byte)l;     /* bits to dump before this table */
+          r.exop = (Byte)j;     /* bits in this table */
+          r.next = q;           /* pointer to this table */
+          j = i >> (w - l);     /* (get around Turbo C bug) */
+          u[h-1][j] = r;        /* connect to last table */
+        }
+      }
+
+      /* set up table entry in r */
+      r.bits = (Byte)(k - w);
+      if (p >= v + n)
+        r.exop = 128 + 64;      /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
+        r.base = *p++;          /* simple code is just the value */
+      }
+      else
+      {
+        r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
+        r.base = d[*p++ - s];
+      }
+
+      /* fill code-like entries with r */
+      f = 1 << (k - w);
+      for (j = i >> w; j < z; j += f)
+        q[j] = r;
+
+      /* backwards increment the k-bit code i */
+      for (j = 1 << (k - 1); i & j; j >>= 1)
+        i ^= j;
+      i ^= j;
+
+      /* backup over finished tables */
+      while ((i & ((1 << w) - 1)) != x[h])
+      {
+        h--;                    /* don't need to update q */
+        w -= l;
+      }
+    }
+  }
+
+
+  /* Return Z_BUF_ERROR if we were given an incomplete table */
+  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+int inflate_trees_bits(c, bb, tb, z)
+uIntf *c;               /* 19 code lengths */
+uIntf *bb;              /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+z_streamp z;            /* for zfree function */
+{
+  int r;
+
+  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z);
+  if (r == Z_DATA_ERROR)
+    z->msg = (char*)"oversubscribed dynamic bit lengths tree";
+  else if (r == Z_BUF_ERROR || *bb == 0)
+  {
+    inflate_trees_free(*tb, z);
+    z->msg = (char*)"incomplete dynamic bit lengths tree";
+    r = Z_DATA_ERROR;
+  }
+  return r;
+}
+
+
+int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
+uInt nl;                /* number of literal/length codes */
+uInt nd;                /* number of distance codes */
+uIntf *c;               /* that many (total) code lengths */
+uIntf *bl;              /* literal desired/actual bit depth */
+uIntf *bd;              /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+z_streamp z;            /* for zfree function */
+{
+  int r;
+
+  /* build literal/length tree */
+  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z);
+  if (r != Z_OK || *bl == 0)
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = (char*)"oversubscribed literal/length tree";
+    else if (r != Z_MEM_ERROR)
+    {
+      inflate_trees_free(*tl, z);
+      z->msg = (char*)"incomplete literal/length tree";
+      r = Z_DATA_ERROR;
+    }
+    return r;
+  }
+
+  /* build distance tree */
+  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z);
+  if (r != Z_OK || (*bd == 0 && nl > 257))
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = (char*)"oversubscribed distance tree";
+    else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+      r = Z_OK;
+    }
+#else
+      inflate_trees_free(*td, z);
+      z->msg = (char*)"incomplete distance tree";
+      r = Z_DATA_ERROR;
+    }
+    else if (r != Z_MEM_ERROR)
+    {
+      z->msg = (char*)"empty distance tree with lengths";
+      r = Z_DATA_ERROR;
+    }
+    inflate_trees_free(*tl, z);
+    return r;
+#endif
+  }
+
+  /* done */
+  return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+local int fixed_built = 0;
+#define FIXEDH 530      /* number of hufts used by fixed tables */
+local inflate_huft fixed_mem[FIXEDH];
+local uInt fixed_bl;
+local uInt fixed_bd;
+local inflate_huft *fixed_tl;
+local inflate_huft *fixed_td;
+
+
+local voidpf falloc(q, n, s)
+voidpf q;       /* opaque pointer */
+uInt n;         /* number of items */
+uInt s;         /* size of item */
+{
+  Assert(s == sizeof(inflate_huft) && n <= *(intf *)q,
+         "inflate_trees falloc overflow");
+  *(intf *)q -= n+s-s; /* s-s to avoid warning */
+  return (voidpf)(fixed_mem + *(intf *)q);
+}
+
+
+int inflate_trees_fixed(bl, bd, tl, td)
+uIntf *bl;               /* literal desired/actual bit depth */
+uIntf *bd;               /* distance desired/actual bit depth */
+inflate_huft * FAR *tl;  /* literal/length tree result */
+inflate_huft * FAR *td;  /* distance tree result */
+{
+  /* build fixed tables if not already (multiple overlapped executions ok) */
+  if (!fixed_built)
+  {
+    int k;              /* temporary variable */
+    unsigned c[288];    /* length list for huft_build */
+    z_stream z;         /* for falloc function */
+    int f = FIXEDH;     /* number of hufts left in fixed_mem */
+
+    /* set up fake z_stream for memory routines */
+    z.zalloc = falloc;
+    z.zfree = Z_NULL;
+    z.opaque = (voidpf)&f;
+
+    /* literal table */
+    for (k = 0; k < 144; k++)
+      c[k] = 8;
+    for (; k < 256; k++)
+      c[k] = 9;
+    for (; k < 280; k++)
+      c[k] = 7;
+    for (; k < 288; k++)
+      c[k] = 8;
+    fixed_bl = 7;
+    huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z);
+
+    /* distance table */
+    for (k = 0; k < 30; k++)
+      c[k] = 5;
+    fixed_bd = 5;
+    huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z);
+
+    /* done */
+    Assert(f == 0, "invalid build of fixed tables");
+    fixed_built = 1;
+  }
+  *bl = fixed_bl;
+  *bd = fixed_bd;
+  *tl = fixed_tl;
+  *td = fixed_td;
+  return Z_OK;
+}
+
+
+int inflate_trees_free(t, z)
+inflate_huft *t;        /* table to free */
+z_streamp z;            /* for zfree function */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+   list of the tables it made, with the links in a dummy first entry of
+   each table. */
+{
+  register inflate_huft *p, *q, *r;
+
+  /* Reverse linked list */
+  p = Z_NULL;
+  q = t;
+  while (q != Z_NULL)
+  {
+    r = (q - 1)->next;
+    (q - 1)->next = p;
+    p = q;
+    q = r;
+  }
+  /* Go through linked list, freeing from the malloced (t[-1]) address. */
+  while (p != Z_NULL)
+  {
+    q = (--p)->next;
+    ZFREE(z,p);
+    p = q;
+  } 
+  return Z_OK;
+}
+/* --- inftrees.c */
+
+/* +++ infcodes.c */
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* #include "zutil.h" */
+/* #include "inftrees.h" */
+/* #include "infblock.h" */
+/* #include "infcodes.h" */
+/* #include "infutil.h" */
+
+/* +++ inffast.h */
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+extern int inflate_fast OF((
+    uInt,
+    uInt,
+    inflate_huft *,
+    inflate_huft *,
+    inflate_blocks_statef *,
+    z_streamp ));
+/* --- inffast.h */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+  /* mode */
+  enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+      START,    /* x: set up for LEN */
+      LEN,      /* i: get length/literal/eob next */
+      LENEXT,   /* i: getting length extra (have base) */
+      DIST,     /* i: get distance next */
+      DISTEXT,  /* i: getting distance extra */
+      COPY,     /* o: copying bytes in window, waiting for space */
+      LIT,      /* o: got literal, waiting for output space */
+      WASH,     /* o: got eob, possibly still output waiting */
+      END,      /* x: got eob and all data flushed */
+      BADCODE}  /* x: got error */
+    mode;               /* current inflate_codes mode */
+
+  /* mode dependent information */
+  uInt len;
+  union {
+    struct {
+      inflate_huft *tree;       /* pointer into tree */
+      uInt need;                /* bits needed */
+    } code;             /* if LEN or DIST, where in tree */
+    uInt lit;           /* if LIT, literal */
+    struct {
+      uInt get;                 /* bits to get for extra */
+      uInt dist;                /* distance back to copy from */
+    } copy;             /* if EXT or COPY, where and how much */
+  } sub;                /* submode */
+
+  /* mode independent information */
+  Byte lbits;           /* ltree bits decoded per branch */
+  Byte dbits;           /* dtree bits decoder per branch */
+  inflate_huft *ltree;          /* literal/length/eob tree */
+  inflate_huft *dtree;          /* distance tree */
+
+};
+
+
+inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+z_streamp z;
+{
+  inflate_codes_statef *c;
+
+  if ((c = (inflate_codes_statef *)
+       ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
+  {
+    c->mode = START;
+    c->lbits = (Byte)bl;
+    c->dbits = (Byte)bd;
+    c->ltree = tl;
+    c->dtree = td;
+    Tracev((stderr, "inflate:       codes new\n"));
+  }
+  return c;
+}
+
+
+int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt j;               /* temporary storage */
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  Bytef *f;             /* pointer to copy strings from */
+  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input and output based on current state */
+  while (1) switch (c->mode)
+  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+    case START:         /* x: set up for LEN */
+#ifndef SLOW
+      if (m >= 258 && n >= 10)
+      {
+        UPDATE
+        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+        LOAD
+        if (r != Z_OK)
+        {
+          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+          break;
+        }
+      }
+#endif /* !SLOW */
+      c->sub.code.need = c->lbits;
+      c->sub.code.tree = c->ltree;
+      c->mode = LEN;
+    case LEN:           /* i: get length/literal/eob next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e == 0)               /* literal */
+      {
+        c->sub.lit = t->base;
+        Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                 "inflate:         literal '%c'\n" :
+                 "inflate:         literal 0x%02x\n", t->base));
+        c->mode = LIT;
+        break;
+      }
+      if (e & 16)               /* length */
+      {
+        c->sub.copy.get = e & 15;
+        c->len = t->base;
+        c->mode = LENEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t->next;
+        break;
+      }
+      if (e & 32)               /* end of block */
+      {
+        Tracevv((stderr, "inflate:         end of block\n"));
+        c->mode = WASH;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"invalid literal/length code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case LENEXT:        /* i: getting length extra (have base) */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->len += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      c->sub.code.need = c->dbits;
+      c->sub.code.tree = c->dtree;
+      Tracevv((stderr, "inflate:         length %u\n", c->len));
+      c->mode = DIST;
+    case DIST:          /* i: get distance next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e & 16)               /* distance */
+      {
+        c->sub.copy.get = e & 15;
+        c->sub.copy.dist = t->base;
+        c->mode = DISTEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t->next;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"invalid distance code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case DISTEXT:       /* i: getting distance extra */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->sub.copy.dist += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      Tracevv((stderr, "inflate:         distance %u\n", c->sub.copy.dist));
+      c->mode = COPY;
+    case COPY:          /* o: copying bytes in window, waiting for space */
+#ifndef __TURBOC__ /* Turbo C bug for following expression */
+      f = (uInt)(q - s->window) < c->sub.copy.dist ?
+          s->end - (c->sub.copy.dist - (q - s->window)) :
+          q - c->sub.copy.dist;
+#else
+      f = q - c->sub.copy.dist;
+      if ((uInt)(q - s->window) < c->sub.copy.dist)
+        f = s->end - (c->sub.copy.dist - (uInt)(q - s->window));
+#endif
+      while (c->len)
+      {
+        NEEDOUT
+        OUTBYTE(*f++)
+        if (f == s->end)
+          f = s->window;
+        c->len--;
+      }
+      c->mode = START;
+      break;
+    case LIT:           /* o: got literal, waiting for output space */
+      NEEDOUT
+      OUTBYTE(c->sub.lit)
+      c->mode = START;
+      break;
+    case WASH:          /* o: got eob, possibly more output */
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      c->mode = END;
+    case END:
+      r = Z_STREAM_END;
+      LEAVE
+    case BADCODE:       /* x: got error */
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+}
+
+
+void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_streamp z;
+{
+  ZFREE(z, c);
+  Tracev((stderr, "inflate:       codes free\n"));
+}
+/* --- infcodes.c */
+
+/* +++ infutil.c */
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* #include "zutil.h" */
+/* #include "infblock.h" */
+/* #include "inftrees.h" */
+/* #include "infcodes.h" */
+/* #include "infutil.h" */
+
+#ifndef NO_DUMMY_DECL
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+#endif
+
+/* And'ing with mask[n] masks the lower n bits */
+uInt inflate_mask[17] = {
+    0x0000,
+    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+
+/* copy as much as possible from the sliding window to the output area */
+int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt n;
+  Bytef *p;
+  Bytef *q;
+
+  /* local copies of source and destination pointers */
+  p = z->next_out;
+  q = s->read;
+
+  /* compute number of bytes to copy as far as end of window */
+  n = (uInt)((q <= s->write ? s->write : s->end) - q);
+  if (n > z->avail_out) n = z->avail_out;
+  if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+  /* update counters */
+  z->avail_out -= n;
+  z->total_out += n;
+
+  /* update check information */
+  if (s->checkfn != Z_NULL)
+    z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+  /* copy as far as end of window */
+  if (p != Z_NULL) {
+    zmemcpy(p, q, n);
+    p += n;
+  }
+  q += n;
+
+  /* see if more to copy at beginning of window */
+  if (q == s->end)
+  {
+    /* wrap pointers */
+    q = s->window;
+    if (s->write == s->end)
+      s->write = s->window;
+
+    /* compute bytes to copy */
+    n = (uInt)(s->write - q);
+    if (n > z->avail_out) n = z->avail_out;
+    if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+    /* update counters */
+    z->avail_out -= n;
+    z->total_out += n;
+
+    /* update check information */
+    if (s->checkfn != Z_NULL)
+      z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+    /* copy */
+    if (p != Z_NULL) {
+      zmemcpy(p, q, n);
+      p += n;
+    }
+    q += n;
+  }
+
+  /* update pointers */
+  z->next_out = p;
+  s->read = q;
+
+  /* done */
+  return r;
+}
+/* --- infutil.c */
+
+/* +++ inffast.c */
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* #include "zutil.h" */
+/* #include "inftrees.h" */
+/* #include "infblock.h" */
+/* #include "infcodes.h" */
+/* #include "infutil.h" */
+/* #include "inffast.h" */
+
+#ifndef NO_DUMMY_DECL
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+#endif
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {n+=(c=k>>3);p-=c;k&=7;}
+
+/* Called with number of bytes left to write in window at least 258
+   (the maximum string length) and number of input bytes available
+   at least ten.  The ten bytes are six bytes for the longest length/
+   distance pair plus four bytes for overloading the bit buffer. */
+
+int inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+inflate_blocks_statef *s;
+z_streamp z;
+{
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  uInt ml;              /* mask for literal/length tree */
+  uInt md;              /* mask for distance tree */
+  uInt c;               /* bytes to copy */
+  uInt d;               /* distance back to copy from */
+  Bytef *r;             /* copy source pointer */
+
+  /* load input, output, bit values */
+  LOAD
+
+  /* initialize masks */
+  ml = inflate_mask[bl];
+  md = inflate_mask[bd];
+
+  /* do until not enough input or output space for fast loop */
+  do {                          /* assume called with m >= 258 && n >= 10 */
+    /* get literal/length code */
+    GRABBITS(20)                /* max bits for literal/length code */
+    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+    {
+      DUMPBITS(t->bits)
+      Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                "inflate:         * literal '%c'\n" :
+                "inflate:         * literal 0x%02x\n", t->base));
+      *q++ = (Byte)t->base;
+      m--;
+      continue;
+    }
+    do {
+      DUMPBITS(t->bits)
+      if (e & 16)
+      {
+        /* get extra bits for length */
+        e &= 15;
+        c = t->base + ((uInt)b & inflate_mask[e]);
+        DUMPBITS(e)
+        Tracevv((stderr, "inflate:         * length %u\n", c));
+
+        /* decode distance base of block to copy */
+        GRABBITS(15);           /* max bits for distance code */
+        e = (t = td + ((uInt)b & md))->exop;
+        do {
+          DUMPBITS(t->bits)
+          if (e & 16)
+          {
+            /* get extra bits to add to distance base */
+            e &= 15;
+            GRABBITS(e)         /* get extra bits (up to 13) */
+            d = t->base + ((uInt)b & inflate_mask[e]);
+            DUMPBITS(e)
+            Tracevv((stderr, "inflate:         * distance %u\n", d));
+
+            /* do the copy */
+            m -= c;
+            if ((uInt)(q - s->window) >= d)     /* offset before dest */
+            {                                   /*  just copy */
+              r = q - d;
+              *q++ = *r++;  c--;        /* minimum count is three, */
+              *q++ = *r++;  c--;        /*  so unroll loop a little */
+            }
+            else                        /* else offset after destination */
+            {
+              e = d - (uInt)(q - s->window); /* bytes from offset to end */
+              r = s->end - e;           /* pointer to offset */
+              if (c > e)                /* if source crosses, */
+              {
+                c -= e;                 /* copy to end of window */
+                do {
+                  *q++ = *r++;
+                } while (--e);
+                r = s->window;          /* copy rest from start of window */
+              }
+            }
+            do {                        /* copy all or what's left */
+              *q++ = *r++;
+            } while (--c);
+            break;
+          }
+          else if ((e & 64) == 0)
+            e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop;
+          else
+          {
+            z->msg = (char*)"invalid distance code";
+            UNGRAB
+            UPDATE
+            return Z_DATA_ERROR;
+          }
+        } while (1);
+        break;
+      }
+      if ((e & 64) == 0)
+      {
+        if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0)
+        {
+          DUMPBITS(t->bits)
+          Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                    "inflate:         * literal '%c'\n" :
+                    "inflate:         * literal 0x%02x\n", t->base));
+          *q++ = (Byte)t->base;
+          m--;
+          break;
+        }
+      }
+      else if (e & 32)
+      {
+        Tracevv((stderr, "inflate:         * end of block\n"));
+        UNGRAB
+        UPDATE
+        return Z_STREAM_END;
+      }
+      else
+      {
+        z->msg = (char*)"invalid literal/length code";
+        UNGRAB
+        UPDATE
+        return Z_DATA_ERROR;
+      }
+    } while (1);
+  } while (m >= 258 && n >= 10);
+
+  /* not enough input or output--restore pointers and return */
+  UNGRAB
+  UPDATE
+  return Z_OK;
+}
+/* --- inffast.c */
+
+/* +++ zutil.c */
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */
+
+/* #include "zutil.h" */
+
+#ifndef NO_DUMMY_DECL
+struct internal_state      {int dummy;}; /* for buggy compilers */
+#endif
+
+#ifndef STDC
+extern void exit OF((int));
+#endif
+
+const char *z_errmsg[10] = {
+"need dictionary",     /* Z_NEED_DICT       2  */
+"stream end",          /* Z_STREAM_END      1  */
+"",                    /* Z_OK              0  */
+"file error",          /* Z_ERRNO         (-1) */
+"stream error",        /* Z_STREAM_ERROR  (-2) */
+"data error",          /* Z_DATA_ERROR    (-3) */
+"insufficient memory", /* Z_MEM_ERROR     (-4) */
+"buffer error",        /* Z_BUF_ERROR     (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char *zlibVersion()
+{
+    return ZLIB_VERSION;
+}
+
+#ifdef DEBUG_ZLIB
+void z_error (m)
+    char *m;
+{
+    fprintf(stderr, "%s\n", m);
+    exit(1);
+}
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+    Bytef* dest;
+    Bytef* source;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = *source++; /* ??? to be unrolled */
+    } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+    Bytef* s1;
+    Bytef* s2;
+    uInt  len;
+{
+    uInt j;
+
+    for (j = 0; j < len; j++) {
+        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+    }
+    return 0;
+}
+
+void zmemzero(dest, len)
+    Bytef* dest;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = 0;  /* ??? to be unrolled */
+    } while (--len != 0);
+}
+#endif
+
+#ifdef __TURBOC__
+#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
+/* Small and medium model in Turbo C are for now limited to near allocation
+ * with reduced MAX_WBITS and MAX_MEM_LEVEL
+ */
+#  define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+    voidpf org_ptr;
+    voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    voidpf buf = opaque; /* just to make some compilers happy */
+    ulg bsize = (ulg)items*size;
+
+    /* If we allocate less than 65520 bytes, we assume that farmalloc
+     * will return a usable pointer which doesn't have to be normalized.
+     */
+    if (bsize < 65520L) {
+        buf = farmalloc(bsize);
+        if (*(ush*)&buf != 0) return buf;
+    } else {
+        buf = farmalloc(bsize + 16L);
+    }
+    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+    table[next_ptr].org_ptr = buf;
+
+    /* Normalize the pointer to seg:0 */
+    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+    *(ush*)&buf = 0;
+    table[next_ptr++].new_ptr = buf;
+    return buf;
+}
+
+void  zcfree (voidpf opaque, voidpf ptr)
+{
+    int n;
+    if (*(ush*)&ptr != 0) { /* object < 64K */
+        farfree(ptr);
+        return;
+    }
+    /* Find the original pointer */
+    for (n = 0; n < next_ptr; n++) {
+        if (ptr != table[n].new_ptr) continue;
+
+        farfree(table[n].org_ptr);
+        while (++n < next_ptr) {
+            table[n-1] = table[n];
+        }
+        next_ptr--;
+        return;
+    }
+    ptr = opaque; /* just to make some compilers happy */
+    Assert(0, "zcfree: ptr not found");
+}
+#endif
+#endif /* __TURBOC__ */
+
+
+#if defined(M_I86) && !defined(__32BIT__)
+/* Microsoft C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER < 600))
+#  define _halloc  halloc
+#  define _hfree   hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    return _halloc((long)items, size);
+}
+
+void  zcfree (voidpf opaque, voidpf ptr)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    _hfree(ptr);
+}
+
+#endif /* MSC */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp  calloc OF((uInt items, uInt size));
+extern void   free   OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+    voidpf opaque;
+    unsigned items;
+    unsigned size;
+{
+    if (opaque) items += size - size; /* make compiler happy */
+    return (voidpf)calloc(items, size);
+}
+
+void  zcfree (opaque, ptr)
+    voidpf opaque;
+    voidpf ptr;
+{
+    free(ptr);
+    if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
+/* --- zutil.c */
+
+/* +++ adler32.c */
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* From: adler32.c,v 1.10 1996/05/22 11:52:18 me Exp $ */
+
+/* #include "zlib.h" */
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf)   DO8(buf,0); DO8(buf,8);
+
+/* ========================================================================= */
+uLong adler32(adler, buf, len)
+    uLong adler;
+    const Bytef *buf;
+    uInt len;
+{
+    unsigned long s1 = adler & 0xffff;
+    unsigned long s2 = (adler >> 16) & 0xffff;
+    int k;
+
+    if (buf == Z_NULL) return 1L;
+
+    while (len > 0) {
+        k = len < NMAX ? len : NMAX;
+        len -= k;
+        while (k >= 16) {
+            DO16(buf);
+	    buf += 16;
+            k -= 16;
+        }
+        if (k != 0) do {
+            s1 += *buf++;
+	    s2 += s1;
+        } while (--k);
+        s1 %= BASE;
+        s2 %= BASE;
+    }
+    return (s2 << 16) | s1;
+}
+/* --- adler32.c */
diff -Naur linux-2.4.19.orig/drivers/dump/dump_zlib.h linux-2.4.19.lkcd/drivers/dump/dump_zlib.h
--- linux-2.4.19.orig/drivers/dump/dump_zlib.h	Thu Jan  1 05:00:00 1970
+++ linux-2.4.19.lkcd/drivers/dump/dump_zlib.h	Tue Nov 19 13:49:50 2002
@@ -0,0 +1,1010 @@
+/*	$Id: dump_zlib.h,v 1.1 2001/09/24 09:39:01 yakker Exp $	*/
+
+/*
+ * This file is derived from zlib.h and zconf.h from the zlib-1.0.4
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets.
+ */
+
+/*
+ *  ==FILEVERSION 971127==
+ *
+ * This marker is used by the Linux installation script to determine
+ * whether an up-to-date version of this file is already installed.
+ */
+
+
+/* +++ zlib.h */
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.0.4, Jul 24th, 1996.
+
+  Copyright (C) 1995-1996 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  gzip@prep.ai.mit.edu    madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* +++ zconf.h */
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* From: zconf.h,v 1.20 1996/07/02 15:09:28 me Exp $ */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+#  define deflateInit_	z_deflateInit_
+#  define deflate	z_deflate
+#  define deflateEnd	z_deflateEnd
+#  define inflateInit_ 	z_inflateInit_
+#  define inflate	z_inflate
+#  define inflateEnd	z_inflateEnd
+#  define deflateInit2_	z_deflateInit2_
+#  define deflateSetDictionary z_deflateSetDictionary
+#  define deflateCopy	z_deflateCopy
+#  define deflateReset	z_deflateReset
+#  define deflateParams	z_deflateParams
+#  define inflateInit2_	z_inflateInit2_
+#  define inflateSetDictionary z_inflateSetDictionary
+#  define inflateSync	z_inflateSync
+#  define inflateReset	z_inflateReset
+#  define compress	z_compress
+#  define uncompress	z_uncompress
+#  define adler32	z_adler32
+#  define crc32		z_crc32
+#  define get_crc_table z_get_crc_table
+
+#  define Byte		z_Byte
+#  define uInt		z_uInt
+#  define uLong		z_uLong
+#  define Bytef	        z_Bytef
+#  define charf		z_charf
+#  define intf		z_intf
+#  define uIntf		z_uIntf
+#  define uLongf	z_uLongf
+#  define voidpf	z_voidpf
+#  define voidp		z_voidp
+#endif
+
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
+#  define WIN32
+#endif
+#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
+#  ifndef __32BIT__
+#    define __32BIT__
+#  endif
+#endif
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#if defined(MSDOS) && !defined(__32BIT__)
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32))  && !defined(STDC)
+#  define STDC
+#endif
+#if (defined(__STDC__) || defined(__cplusplus)) && !defined(STDC)
+#  define STDC
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const
+#  endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
+#  define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            1 << (windowBits+2)   +  1 << (memLevel+9)
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
+   /* MSC small or medium model */
+#  define SMALL_MEDIUM
+#  ifdef _MSC_VER
+#    define FAR __far
+#  else
+#    define FAR far
+#  endif
+#endif
+#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
+#  ifndef __32BIT__
+#    define SMALL_MEDIUM
+#    define FAR __far
+#  endif
+#endif
+#ifndef FAR
+#   define FAR
+#endif
+
+typedef unsigned char  Byte;  /* 8 bits */
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#if defined(__BORLANDC__) && defined(SMALL_MEDIUM)
+   /* Borland C/C++ ignores FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void FAR *voidpf;
+   typedef void     *voidp;
+#else
+   typedef Byte FAR *voidpf;
+   typedef Byte     *voidp;
+#endif
+
+
+/* Compile with -DZLIB_DLL for Windows DLL support */
+#if (defined(_WINDOWS) || defined(WINDOWS)) && defined(ZLIB_DLL)
+#  include <windows.h>
+#  define EXPORT  WINAPI
+#else
+#  define EXPORT
+#endif
+
+#endif /* _ZCONF_H */
+/* --- zconf.h */
+
+#define ZLIB_VERSION "1.0.4P"
+
+/* 
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms may be added later and will have the same
+  stream interface.
+
+     For compression the application must provide the output buffer and
+  may optionally provide the input buffer for optimization. For decompression,
+  the application must provide the input buffer and may optionally provide
+  the output buffer for optimization.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+     The library does not install any signal handler. It is recommended to
+  add at least a handler for SIGSEGV when decompressing; the library checks
+  the consistency of the input data whenever possible but may go nuts
+  for some forms of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidpf     opaque;  /* private data object passed to zalloc and zfree */
+
+    int     data_type;  /* best guess about the data type: ascii or binary */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1
+#define Z_PACKET_FLUSH	2
+#define Z_SYNC_FLUSH    3
+#define Z_FULL_FLUSH    4
+#define Z_FINISH        5
+/* Allowed flush values; see deflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_ASCII    1
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+                        /* basic functions */
+
+extern const char * EXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is
+   not compatible with the zlib.h header file used by the application.
+   This check is automatically made by deflateInit and inflateInit.
+ */
+
+/* 
+extern int EXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.
+   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+   use default allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at
+   all (the input data is simply copied a block at a time).
+   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+   compression (currently equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).
+   msg is set to null if there is no error message.  deflateInit does not
+   perform any compression: this will be done by deflate().
+*/
+
+
+extern int EXPORT deflate OF((z_streamp strm, int flush));
+/*
+  Performs one or both of the following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly. This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).
+    Some output may be provided even if flush is not set.
+
+  Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating avail_in or avail_out accordingly; avail_out
+  should never be zero before the call. The application can consume the
+  compressed output when it wants, for example when the output buffer is full
+  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+  and with zero avail_out, it must be called again after making room in the
+  output buffer because there might be more output pending.
+
+    If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression
+  block is terminated and flushed to the output buffer so that the
+  decompressor can get all input data available so far. For method 9, a future
+  variant on method 8, the current block will be flushed but not terminated.
+  Z_SYNC_FLUSH has the same effect as partial flush except that the compressed
+  output is byte aligned (the compressor can clear its internal bit buffer)
+  and the current block is always terminated; this can be useful if the
+  compressor has to be restarted from scratch after an interruption (in which
+  case the internal state of the compressor may be lost).
+    If flush is set to Z_FULL_FLUSH, the compression block is terminated, a
+  special marker is output and the compression dictionary is discarded; this
+  is useful to allow the decompressor to synchronize if one compressed block
+  has been damaged (see inflateSync below).  Flushing degrades compression and
+  so should be used only when necessary.  Using Z_FULL_FLUSH too often can
+  seriously degrade the compression. If deflate returns with avail_out == 0,
+  this function must be called again with the same value of the flush
+  parameter and more output space (updated avail_out), until the flush is
+  complete (deflate returns with non-zero avail_out).
+
+    If the parameter flush is set to Z_PACKET_FLUSH, the compression
+  block is terminated, and a zero-length stored block is output,
+  omitting the length bytes (the effect of this is that the 3-bit type
+  code 000 for a stored block is output, and the output is then
+  byte-aligned).  This is designed for use at the end of a PPP packet.
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there
+  was enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error. After
+  deflate has returned Z_STREAM_END, the only possible operations on the
+  stream are deflateReset or deflateEnd.
+  
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step. In this case, avail_out must be at least
+  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() may update data_type if it can make a good guess about
+  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+  binary. This field is only for information purposes and does not affect
+  the compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible.
+*/
+
+
+extern int EXPORT deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded). In the error case,
+   msg may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+/* 
+extern int EXPORT inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.  If
+   zalloc and zfree are set to Z_NULL, inflateInit updates them to use default
+   allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_VERSION_ERROR if the zlib library version is incompatible
+   with the version assumed by the caller.  msg is set to null if there is no
+   error message. inflateInit does not perform any decompression: this will be
+   done by inflate().
+*/
+
+
+extern int EXPORT inflate OF((z_streamp strm, int flush));
+/*
+  Performs one or both of the following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there
+    is no more input data or no more space in the output buffer (see below
+    about the flush parameter).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+  must be called again after making room in the output buffer because there
+  might be more output pending.
+
+    If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
+  inflate flushes as much output as possible to the output buffer. The
+  flushing behavior of inflate is not specified for values of the flush
+  parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
+  current implementation actually flushes as much output as possible
+  anyway.  For Z_PACKET_FLUSH, inflate checks that once all the input data
+  has been consumed, it is expecting to see the length field of a stored
+  block; if not, it returns Z_DATA_ERROR.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster routine
+  may be used for the single inflate() call.
+
+    inflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if the end of the
+  compressed data has been reached and all uncompressed output has been
+  produced, Z_NEED_DICT if a preset dictionary is needed at this point (see
+  inflateSetDictionary below), Z_DATA_ERROR if the input data was corrupted,
+  Z_STREAM_ERROR if the stream structure was inconsistent (for example if
+  next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+  Z_BUF_ERROR if no progress is possible or if there was not enough room in
+  the output buffer when Z_FINISH is used. In the Z_DATA_ERROR case, the
+  application may then call inflateSync to look for a good compression block.
+  In the Z_NEED_DICT case, strm->adler is set to the Adler32 value of the
+  dictionary chosen by the compressor.
+*/
+
+
+extern int EXPORT inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*   
+extern int EXPORT deflateInit2 OF((z_streamp strm,
+                                   int  level,
+                                   int  method,
+                                   int  windowBits,
+                                   int  memLevel,
+                                   int  strategy));
+
+     This is another version of deflateInit with more compression options. The
+   fields next_in, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The method parameter is the compression method. It must be Z_DEFLATED in
+   this version of the library. (Method 9 will allow a 64K history buffer and
+   partial block flushes.)
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer).  It should be in the range 8..15 for this
+   version of the library (the value 16 will be allowed for method 9). Larger
+   values of this parameter result in better compression at the expense of
+   memory usage. The default value is 15 if deflateInit is used instead.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state. memLevel=1 uses minimum memory but
+   is slow and reduces compression ratio; memLevel=9 uses maximum memory
+   for optimal speed. The default value is 8. See zconf.h for total memory
+   usage as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm. Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match).  Filtered data consists mostly of small values with a
+   somewhat random distribution. In this case, the compression algorithm is
+   tuned to compress them better. The effect of Z_FILTERED is to force more
+   Huffman coding and less string matching; it is somewhat intermediate
+   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
+   the compression ratio but not the correctness of the compressed output even
+   if it is not set appropriately.
+
+     If next_in is not null, the library will use this buffer to hold also
+   some history information; the buffer must either hold the entire input
+   data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in
+   is null, the library will allocate its own history buffer (and leave next_in
+   null). next_out need not be provided here but must be provided by the
+   application for the next call of deflate().
+
+     If the history buffer is provided by the application, next_in must
+   must never be changed by the application since the compressor maintains
+   information inside this buffer from call to call; the application
+   must provide more input only by increasing avail_in. next_in is always
+   reset by the library in this case.
+
+      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+   not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+   an invalid method). msg is set to null if there is no error message.
+   deflateInit2 does not perform any compression: this will be done by
+   deflate(). 
+*/
+                            
+extern int EXPORT deflateSetDictionary OF((z_streamp strm,
+                                           const Bytef *dictionary,
+				           uInt  dictLength));
+/*
+     Initializes the compression dictionary (history buffer) from the given
+   byte sequence without producing any compressed output. This function must
+   be called immediately after deflateInit or deflateInit2, before any call
+   of deflate. The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary. Using a
+   dictionary is most useful when the data to be compressed is short and
+   can be predicted with good accuracy; the data can then be compressed better
+   than with the default empty dictionary. In this version of the library,
+   only the last 32K bytes of the dictionary are used.
+     Upon return of this function, strm->adler is set to the Adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor. (The Adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.)
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state
+   is inconsistent (for example if deflate has already been called for this
+   stream). deflateSetDictionary does not perform any compression: this will
+   be done by deflate(). 
+*/
+
+extern int EXPORT deflateCopy OF((z_streamp dest,
+                                  z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.  If
+   the source stream is using an application-supplied history buffer, a new
+   buffer is allocated for the destination stream.  The compressed output
+   buffer is always application-supplied. It's the responsibility of the
+   application to provide the correct values of next_out and avail_out for the
+   next call of deflate.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter. The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and
+   can consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+extern int EXPORT deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.
+   The stream will keep the same compression level and any other attributes
+   that may have been set by deflateInit2.
+
+      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+extern int EXPORT deflateParams OF((z_streamp strm, int level, int strategy));
+/*
+     Dynamically update the compression level and compression strategy.
+   This can be used to switch between compression and straight copy of
+   the input data, or to switch to a different kind of input data requiring
+   a different strategy. If the compression level is changed, the input
+   available so far is compressed with the old level (and may be flushed);
+   the new level will take effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to
+   be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+   if strm->avail_out was zero.
+*/
+
+extern int EXPORT deflateOutputPending OF((z_streamp strm));
+/*
+     Returns the number of bytes of output which are immediately
+   available from the compressor (i.e. without any further input
+   or flush).
+*/
+
+/*   
+extern int EXPORT inflateInit2 OF((z_streamp strm,
+                                   int  windowBits));
+
+     This is another version of inflateInit with more compression options. The
+   fields next_out, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library (the value 16 will be allowed soon). The
+   default value is 15 if inflateInit is used instead. If a compressed stream
+   with a larger window size is given as input, inflate() will return with
+   the error code Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     If next_out is not null, the library will use this buffer for the history
+   buffer; the buffer must either be large enough to hold the entire output
+   data, or have at least 1<<windowBits bytes.  If next_out is null, the
+   library will allocate its own buffer (and leave next_out null). next_in
+   need not be provided here but must be provided by the application for the
+   next call of inflate().
+
+     If the history buffer is provided by the application, next_out must
+   never be changed by the application since the decompressor maintains
+   history information inside this buffer from call to call; the application
+   can only reset next_out to the beginning of the history buffer when
+   avail_out is zero and all output has been consumed.
+
+      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+   not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+   windowBits < 8). msg is set to null if there is no error message.
+   inflateInit2 does not perform any decompression: this will be done by
+   inflate().
+*/
+
+extern int EXPORT inflateSetDictionary OF((z_streamp strm,
+				           const Bytef *dictionary,
+					   uInt  dictLength));
+/*
+     Initializes the decompression dictionary (history buffer) from the given
+   uncompressed byte sequence. This function must be called immediately after
+   a call of inflate if this call returned Z_NEED_DICT. The dictionary chosen
+   by the compressor can be determined from the Adler32 value returned by this
+   call of inflate. The compressor and decompressor must use exactly the same
+   dictionary (see deflateSetDictionary).
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect Adler32 value). inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+extern int EXPORT inflateSync OF((z_streamp strm));
+/* 
+    Skips invalid compressed data until the special marker (see deflate()
+  above) can be found, or until all available input is skipped. No output
+  is provided.
+
+    inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no marker has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+extern int EXPORT inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+extern int inflateIncomp OF((z_stream *strm));
+/*
+     This function adds the data at next_in (avail_in bytes) to the output
+   history without performing any output.  There must be no pending output,
+   and the decompressor must be expecting to see the start of a block.
+   Calling this function is equivalent to decompressing a stored block
+   containing the data at next_in (except that the data is not output).
+*/
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the
+   basic stream-oriented functions. To simplify the interface, some
+   default options are assumed (compression level, window size,
+   standard memory allocation functions). The source code of these
+   utility functions can easily be modified if you need special options.
+*/
+
+extern int EXPORT compress OF((Bytef *dest,   uLongf *destLen,
+			       const Bytef *source, uLong sourceLen));
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be at least 0.1% larger than
+   sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
+   compressed buffer.
+     This function can be used to compress a whole file at once if the
+   input file is mmap'ed.
+     compress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer.
+*/
+
+extern int EXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
+				 const Bytef *source, uLong sourceLen));
+/*
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+
+
+typedef voidp gzFile;
+
+extern gzFile EXPORT gzopen  OF((const char *path, const char *mode));
+/*
+     Opens a gzip (.gz) file for reading or writing. The mode parameter
+   is as in fopen ("rb" or "wb") but can also include a compression level
+   ("wb9").  gzopen can be used to read a file which is not in gzip format;
+   in this case gzread will directly read from the file without decompression.
+     gzopen returns NULL if the file could not be opened or if there was
+   insufficient memory to allocate the (de)compression state; errno
+   can be checked to distinguish the two cases (if errno is zero, the
+   zlib error is Z_MEM_ERROR).
+*/
+
+extern gzFile EXPORT gzdopen  OF((int fd, const char *mode));
+/*
+     gzdopen() associates a gzFile with the file descriptor fd.  File
+   descriptors are obtained from calls like open, dup, creat, pipe or
+   fileno (in the file has been previously opened with fopen).
+   The mode parameter is as in gzopen.
+     The next call of gzclose on the returned gzFile will also close the
+   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+     gzdopen returns NULL if there was insufficient memory to allocate
+   the (de)compression state.
+*/
+
+extern int EXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
+/*
+     Reads the given number of uncompressed bytes from the compressed file.
+   If the input file was not in gzip format, gzread copies the given number
+   of bytes into the buffer.
+     gzread returns the number of uncompressed bytes actually read (0 for
+   end of file, -1 for error). */
+
+extern int EXPORT    gzwrite OF((gzFile file, const voidp buf, unsigned len));
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes actually written
+   (0 in case of error).
+*/
+
+extern int EXPORT    gzflush OF((gzFile file, int flush));
+/*
+     Flushes all pending output into the compressed file. The parameter
+   flush is as in the deflate() function. The return value is the zlib
+   error number (see function gzerror below). gzflush returns Z_OK if
+   the flush parameter is Z_FINISH and all output could be flushed.
+     gzflush should be called only when strictly necessary because it can
+   degrade compression.
+*/
+
+extern int EXPORT    gzclose OF((gzFile file));
+/*
+     Flushes all pending output if necessary, closes the compressed file
+   and deallocates all the (de)compression state. The return value is the zlib
+   error number (see function gzerror below).
+*/
+
+extern const char * EXPORT gzerror OF((gzFile file, int *errnum));
+/*
+     Returns the error message for the last error which occurred on the
+   given compressed file. errnum is set to zlib error number. If an
+   error occurred in the file system and not in the compression library,
+   errnum is set to Z_ERRNO and the application may consult errno
+   to get the exact error code.
+*/
+
+                        /* checksum functions */
+
+/*
+     These functions are not related to compression but are exported
+   anyway because they might be useful in applications using the
+   compression library.
+*/
+
+extern uLong EXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+extern uLong EXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
+/*
+     Update a running crc with the bytes buf[0..len-1] and return the updated
+   crc. If buf is NULL, this function returns the required initial value
+   for the crc. Pre- and post-conditioning (one's complement) is performed
+   within this function so it shouldn't be done by the application.
+   Usage example:
+
+     uLong crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+*/
+
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+extern int EXPORT deflateInit_ OF((z_streamp strm, int level,
+			           const char *version, int stream_size));
+extern int EXPORT inflateInit_ OF((z_streamp strm,
+				   const char *version, int stream_size));
+extern int EXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
+				    int windowBits, int memLevel, int strategy,
+				    const char *version, int stream_size));
+extern int EXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
+				    const char *version, int stream_size));
+#define deflateInit(strm, level) \
+        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+		      (strategy),           ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+
+#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+uLongf *get_crc_table OF((void)); /* can be used by asm versions of crc32() */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZLIB_H */
+/* --- zlib.h */
diff -Naur linux-2.4.19.orig/fs/iobuf.c linux-2.4.19.lkcd/fs/iobuf.c
--- linux-2.4.19.orig/fs/iobuf.c	Sat Aug  3 05:39:45 2002
+++ linux-2.4.19.lkcd/fs/iobuf.c	Tue Nov 19 13:49:50 2002
@@ -18,7 +18,11 @@
 	if (atomic_dec_and_test(&kiobuf->io_count)) {
 		if (kiobuf->end_io)
 			kiobuf->end_io(kiobuf);
-		wake_up(&kiobuf->wait_queue);
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+			/* the end_io fn should take care of waiters too */
+		else
+#endif
+			wake_up(&kiobuf->wait_queue);
 	}
 }
 
@@ -125,7 +129,6 @@
 	return 0;
 }
 
-
 void kiobuf_wait_for_io(struct kiobuf *kiobuf)
 {
 	struct task_struct *tsk = current;
diff -Naur linux-2.4.19.orig/include/asm-alpha/dump.h linux-2.4.19.lkcd/include/asm-alpha/dump.h
--- linux-2.4.19.orig/include/asm-alpha/dump.h	Thu Jan  1 05:00:00 1970
+++ linux-2.4.19.lkcd/include/asm-alpha/dump.h	Tue Nov 19 13:49:50 2002
@@ -0,0 +1,59 @@
+/*
+ * Kernel header file for Linux crash dumps.
+ *
+ * Created by: Matt Robinson (yakker@sgi.com)
+ *
+ * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
+ * 
+ * This code is released under version 2 of the GNU GPL.
+ */
+
+/* This header file holds the architecture specific crash dump header */
+#ifndef _ASM_DUMP_H
+#define _ASM_DUMP_H
+
+/* necessary header files */
+#include <asm/ptrace.h>                          /* for pt_regs             */
+
+/* definitions */
+#define DUMP_ASM_MAGIC_NUMBER     0xdeaddeadULL  /* magic number            */
+#define DUMP_ASM_VERSION_NUMBER   0x2            /* version number          */
+
+
+/*
+ * Structure: dump_header_asm_t
+ *  Function: This is the header for architecture-specific stuff.  It
+ *            follows right after the dump header.
+ */
+typedef struct _dump_header_asm_s {
+
+        /* the dump magic number -- unique to verify dump is valid */
+        uint64_t             dha_magic_number;
+
+        /* the version number of this dump */
+        uint32_t             dha_version;
+
+        /* the size of this header (in case we can't read it) */
+        uint32_t             dha_header_size;
+
+	/* the stack pointer for Alpha systems */
+	uint64_t             dha_sp;
+
+	/* the return address for Alpha systems */
+	uint64_t             dha_ra;
+
+	/* the dump registers */
+	struct pt_regs       dha_regs;
+
+} dump_header_asm_t;
+
+#ifdef __KERNEL__
+#define get_current()                                           \
+({                                                              \
+        register unsigned long sp;                              \
+        asm("bis $30,$30,%0" : "=r" (sp));                      \
+        sp;                                                     \
+})          
+#endif
+
+#endif /* _ASM_DUMP_H */
diff -Naur linux-2.4.19.orig/include/asm-i386/dump.h linux-2.4.19.lkcd/include/asm-i386/dump.h
--- linux-2.4.19.orig/include/asm-i386/dump.h	Thu Jan  1 05:00:00 1970
+++ linux-2.4.19.lkcd/include/asm-i386/dump.h	Tue Nov 19 13:49:50 2002
@@ -0,0 +1,89 @@
+/*
+ * Kernel header file for Linux crash dumps.
+ *
+ * Created by: Matt Robinson (yakker@sgi.com)
+ *
+ * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
+ *
+ * This code is released under version 2 of the GNU GPL.
+ */
+
+/* This header file holds the architecture specific crash dump header */
+#ifndef _ASM_DUMP_H
+#define _ASM_DUMP_H
+
+/* necessary header files */
+#include <asm/ptrace.h>                          /* for pt_regs             */
+#include <linux/threads.h>
+
+/* definitions */
+#define DUMP_ASM_MAGIC_NUMBER     0xdeaddeadULL  /* magic number            */
+#define DUMP_ASM_VERSION_NUMBER   0x2            /* version number          */
+
+
+/*
+ * Structure: dump_header_asm_t
+ *  Function: This is the header for architecture-specific stuff.  It
+ *            follows right after the dump header.
+ */
+typedef struct _dump_header_asm_s {
+
+        /* the dump magic number -- unique to verify dump is valid */
+        uint64_t             dha_magic_number;
+
+        /* the version number of this dump */
+        uint32_t             dha_version;
+
+        /* the size of this header (in case we can't read it) */
+        uint32_t             dha_header_size;
+
+	/* the esp for i386 systems */
+	uint32_t             dha_esp;
+
+	/* the eip for i386 systems */
+	uint32_t             dha_eip;
+
+	/* the dump registers */
+	struct pt_regs       dha_regs;
+
+	/* smp specific */
+	uint32_t	     dha_smp_num_cpus;
+	int		     dha_dumping_cpu;	
+	struct pt_regs	     dha_smp_regs[NR_CPUS];
+	void *		     dha_smp_current_task[NR_CPUS];
+	void *		     dha_stack[NR_CPUS];
+} dump_header_asm_t;
+
+#ifdef __KERNEL__
+static inline void get_current_regs(struct pt_regs *regs)
+{
+	__asm__ __volatile__("movl %%ebx,%0" : "=m"(regs->ebx));
+	__asm__ __volatile__("movl %%ecx,%0" : "=m"(regs->ecx));
+	__asm__ __volatile__("movl %%edx,%0" : "=m"(regs->edx));
+	__asm__ __volatile__("movl %%esi,%0" : "=m"(regs->esi));
+	__asm__ __volatile__("movl %%edi,%0" : "=m"(regs->edi));
+	__asm__ __volatile__("movl %%ebp,%0" : "=m"(regs->ebp));
+	__asm__ __volatile__("movl %%eax,%0" : "=m"(regs->eax));
+	__asm__ __volatile__("movl %%esp,%0" : "=m"(regs->esp));
+	__asm__ __volatile__("movw %%ss, %%ax;" :"=a"(regs->xss));
+	__asm__ __volatile__("movw %%cs, %%ax;" :"=a"(regs->xcs));
+	__asm__ __volatile__("movw %%ds, %%ax;" :"=a"(regs->xds));
+	__asm__ __volatile__("movw %%es, %%ax;" :"=a"(regs->xes));
+	__asm__ __volatile__("pushfl; popl %0" :"=m"(regs->eflags));
+	regs->eip = (unsigned long)current_text_addr();
+	
+}
+
+extern volatile int dump_in_progress;
+extern unsigned long irq_affinity[];
+extern dump_header_asm_t dump_header_asm;
+
+#ifdef CONFIG_SMP
+extern int (*dump_ipi_function_ptr)(struct pt_regs *);
+extern void dump_send_ipi(void);
+#else
+#define dump_send_ipi()
+#endif
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_DUMP_H */
diff -Naur linux-2.4.19.orig/include/asm-i386/hw_irq.h linux-2.4.19.lkcd/include/asm-i386/hw_irq.h
--- linux-2.4.19.orig/include/asm-i386/hw_irq.h	Fri Nov 23 00:46:18 2001
+++ linux-2.4.19.lkcd/include/asm-i386/hw_irq.h	Tue Nov 19 13:49:50 2002
@@ -42,6 +42,9 @@
 #define INVALIDATE_TLB_VECTOR	0xfd
 #define RESCHEDULE_VECTOR	0xfc
 #define CALL_FUNCTION_VECTOR	0xfb
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+#define DUMP_VECTOR		0xfa
+#endif
 
 /*
  * Local APIC timer IRQ vector is on a different priority level,
diff -Naur linux-2.4.19.orig/include/asm-ia64/dump.h linux-2.4.19.lkcd/include/asm-ia64/dump.h
--- linux-2.4.19.orig/include/asm-ia64/dump.h	Thu Jan  1 05:00:00 1970
+++ linux-2.4.19.lkcd/include/asm-ia64/dump.h	Tue Nov 19 13:49:50 2002
@@ -0,0 +1,140 @@
+/*
+ * Kernel header file for Linux crash dumps.
+ *
+ * Created by: Matt Robinson (yakker@sgi.com)
+ *
+ * Copyright 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
+ *
+ * This code is released under version 2 of the GNU GPL.
+ */
+
+/* This header file holds the architecture specific crash dump header */
+#ifndef _ASM_DUMP_H
+#define _ASM_DUMP_H
+
+/* definitions */
+#define DUMP_ASM_MAGIC_NUMBER     0xdeaddeadULL  /* magic number            */
+#define DUMP_ASM_VERSION_NUMBER   0x3            /* version number          */
+
+#ifdef __KERNEL__
+#include <asm/efi.h>
+#include <asm/pal.h>
+#ifdef CONFIG_SMP
+extern int (*dump_ipi_function_ptr)(struct pt_regs *);
+extern void dump_send_ipi(void);
+#else /* !CONFIG_SMP */
+#define dump_send_ipi()
+#endif
+
+#else  /* !__KERNEL__ */
+/* necessary header files */
+#include <asm/ptrace.h>                          /* for pt_regs             */
+#include <linux/threads.h>
+#endif /* __KERNEL__ */
+
+/* 
+ * mkswap.c calls getpagesize() to get the system page size,
+ * which is not  necessarily the same as the hardware page size.
+ *
+ * For ia64 the kernel PAGE_SIZE can be configured from 4KB ... 16KB.
+ *
+ * The physical memory is layed out out in the hardware/minimal pages.
+ * This is the size we need to use for dumping physical pages.
+ *
+ * Note ths hardware/minimal page size being use in;
+ *      arch/ia64/kernel/efi.c`efi_memmap_walk():
+ *	    curr.end   = curr.start + (md->num_pages << 12);
+ *
+ * Since the system page size could change between the kernel we boot
+ * on the the kernel that cause the core dume we may want to have something
+ * more constant like the maximum system page size (See include/asm-ia64/page.h).
+ */
+#define DUMP_MIN_PAGE_SHIFT                 	12
+#define DUMP_MIN_PAGE_SIZE                  	(1UL << DUMP_MIN_PAGE_SHIFT)
+#define DUMP_MIN_PAGE_MASK                  	(~(DUMP_MIN_PAGE_SIZE - 1))
+#define DUMP_MIN_PAGE_ALIGN(addr)           	(((addr) + DUMP_MIN_PAGE_SIZE - 1) & DUMP_MIN_PAGE_MASK)
+
+#define DUMP_MAX_PAGE_SHIFT                 	16
+#define DUMP_MAX_PAGE_SIZE                  	(1UL << DUMP_MAX_PAGE_SHIFT)
+#define DUMP_MAX_PAGE_MASK                  	(~(DUMP_MAX_PAGE_SIZE - 1))
+#define DUMP_MAX_PAGE_ALIGN(addr)           	(((addr) + DUMP_MAX_PAGE_SIZE - 1) & DUMP_MAX_PAGE_MASK)
+
+
+#undef	DUMP_PAGE_SHIFT				/* Redefining Default for ia64  */
+#undef	DUMP_PAGE_SIZE				/* "	"	"	"	*/
+#undef	DUMP_PAGE_MASK				/* "    "       "       "       */
+#undef	DUMP_PAGE_ALIGN				/* "    "       "       "       */
+#undef	DUMP_HEADER_OFFSET			/* "    "       "       "       */
+
+#define DUMP_HEADER_OFFSET              	DUMP_MAX_PAGE_SIZE
+
+#define DUMP_EF_PAGE_SHIFT			DUMP_MIN_PAGE_SHIFT
+
+#define DUMP_PAGE_SHIFT				DUMP_MIN_PAGE_SHIFT
+#define DUMP_PAGE_SIZE				DUMP_MIN_PAGE_SIZE
+#define DUMP_PAGE_MASK				DUMP_MIN_PAGE_MASK
+#define DUMP_PAGE_ALIGN(addr)			DUMP_MIN_PAGE_ALIGN(addr)
+
+/*
+ * Structure: dump_header_asm_t
+ *  Function: This is the header for architecture-specific stuff.  It
+ *            follows right after the dump header.
+ */
+typedef struct _dump_header_asm_s {
+
+        /* the dump magic number -- unique to verify dump is valid */
+        uint64_t             dha_magic_number;
+
+        /* the version number of this dump */
+        uint32_t             dha_version;
+
+        /* the size of this header (in case we can't read it) */
+        uint32_t             dha_header_size;
+
+        /* pointer to pt_regs */
+	struct pt_regs      *dha_pt_regs;
+
+	/* the dump registers */
+	struct pt_regs       dha_regs;
+
+        /* the rnat register saved after flushrs */
+        uint64_t             dha_rnat;
+
+	/* the pfs register saved after flushrs */
+	uint64_t             dha_pfs;
+
+	/* the bspstore register saved after flushrs */
+	uint64_t             dha_bspstore;
+
+	/* smp specific */
+	uint32_t	     dha_smp_num_cpus;
+	int		     dha_dumping_cpu;	
+	struct pt_regs	     dha_smp_regs[NR_CPUS];
+	void *		     dha_smp_current_task[NR_CPUS];
+	void *		     dha_stack[NR_CPUS];
+
+} dump_header_asm_t;
+
+
+
+#ifdef __KERNEL__
+static inline void get_current_regs(struct pt_regs *regs)
+{
+	/* 
+	 * REMIND: Looking at functions/Macros like:
+	 *		 DO_SAVE_SWITCH_STACK
+	 *		 ia64_switch_to()
+	 *		 ia64_save_extra()
+	 *		 switch_to()
+	 *	   to implement this new feature that Matt seem to have added
+	 *	   to panic.c; seems all platforms are now expected to provide
+	 *	   this function to dump the current registers into the pt_regs
+	 *	   structure.
+	 */
+}
+
+/* Perhaps added to Common Arch Specific Functions and moved to dump.h some day */
+extern void * __dump_memcpy(void *, const void *, size_t);
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_DUMP_H */
diff -Naur linux-2.4.19.orig/include/linux/dump.h linux-2.4.19.lkcd/include/linux/dump.h
--- linux-2.4.19.orig/include/linux/dump.h	Thu Jan  1 05:00:00 1970
+++ linux-2.4.19.lkcd/include/linux/dump.h	Tue Nov 19 13:49:50 2002
@@ -0,0 +1,375 @@
+/*
+ * Kernel header file for Linux crash dumps.
+ *
+ * Created by: Matt Robinson (yakker@sgi.com)
+ * Copyright 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
+ *
+ * vmdump.h to dump.h by: Matt D. Robinson (yakker@sourceforge.net)
+ * Copyright 2001 - 2002 Matt D. Robinson.  All rights reserved.
+ * Copyright (C) 2002 Free Software Foundation, Inc. All rights reserved.
+ *
+ * Most of this is the same old stuff from vmdump.h, except now we're
+ * actually a stand-alone driver plugged into the block layer interface,
+ * with the exception that we now allow for compression modes externally
+ * loaded (e.g., someone can come up with their own).
+ *
+ * This code is released under version 2 of the GNU GPL.
+ */
+
+/* This header file includes all structure definitions for crash dumps. */
+#ifndef _DUMP_H
+#define _DUMP_H
+
+#include <linux/list.h>
+#include <linux/notifier.h>
+
+/* define TRUE and FALSE for use in our dump modules */
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+
+/*
+ * DUMP_DEBUG: a debug level for the kernel dump code and
+ *             the supporting lkcd libraries in user space.
+ *
+ * 0: FALSE: No Debug Added
+ * 1: TRUE:  Break Points
+ * .
+ * .
+ * .
+ * 6: Add Debug Data to Structures
+ * .
+ * .
+ * 9: Max
+ */
+#define DUMP_DEBUG FALSE
+
+#if DUMP_DEBUG
+void dump_bp(void);			/* Called when something exceptional occures */
+#define DUMP_BP() dump_bp()			/* BreakPoint */
+#else
+#define DUMP_BP()
+#endif
+
+/* 
+ * Predefine default DUMP_PAGE constants, asm header may override.
+ *
+ * On ia64 discontinuous memory systems it's possible for the memory
+ * banks to stop at 2**12 page alignments, the smallest possible page
+ * size. But the system page size, PAGE_SIZE, is in fact larger.
+ */
+#define DUMP_PAGE_SHIFT 	PAGE_SHIFT
+#define DUMP_PAGE_SIZE		PAGE_SIZE
+#define DUMP_PAGE_MASK		PAGE_MASK
+#define DUMP_PAGE_ALIGN(addr)	PAGE_ALIGN(addr)
+#define DUMP_HEADER_OFFSET	PAGE_SIZE
+
+/* 
+ * Predefined default memcpy() to use when copying memory to the dump buffer.
+ *
+ * On ia64 there is a heads up function that can be called to let the prom
+ * machine check monitor know that the current activity is risky and it should
+ * ignore the fault (nofault). In this case the ia64 header will redefine this
+ * macro to __dump_memcpy() and use it's arch specific version.
+ */
+#define DUMP_memcpy		memcpy
+
+
+/* necessary header files */
+#include <asm/dump.h>                   /* for architecture-specific header */
+
+/* necessary header definitions in all cases */
+#define DUMP_KIOBUF_NUMBER  0xdeadbeef  /* special number for kiobuf maps   */
+
+/* 
+ * Size of the buffer that's used to hold:
+ *
+ *	1. the dump header (paded to fill the complete buffer)
+ *	2. the possibly compressed page headers and data
+ */
+#define DUMP_BUFFER_SIZE        (64 * 1024)  /* size of dump buffer (0x10000) */
+#define DUMP_HEADER_SIZE	 DUMP_BUFFER_SIZE
+
+/* header definitions for s390 dump */
+#define DUMP_MAGIC_S390     0xa8190173618f23fdULL  /* s390 magic number     */
+#define S390_DUMP_HEADER_SIZE     4096
+
+/* standard header definitions */
+#define DUMP_MAGIC_NUMBER   0xa8190173618f23edULL  /* dump magic number     */
+#define DUMP_MAGIC_LIVE     0xa8190173618f23cdULL  /* live magic number     */
+#define DUMP_VERSION_NUMBER   0x7       /* dump version number              */
+#define DUMP_PANIC_LEN        0x100     /* dump panic string length         */
+
+/* dump levels - type specific stuff added later -- add as necessary */
+#define DUMP_LEVEL_NONE        0x0      /* no dumping at all -- just bail   */
+#define DUMP_LEVEL_HEADER      0x1      /* kernel dump header only          */
+#define DUMP_LEVEL_KERN        0x2      /* dump header and kernel pages     */
+#define DUMP_LEVEL_USED        0x4      /* dump header, kernel/user pages   */
+#define DUMP_LEVEL_ALL_RAM     0x8      /* dump header, all RAM pages       */
+#define DUMP_LEVEL_ALL        0x10      /* dump all memory RAM and firmware */
+
+
+/* dump compression options -- add as necessary */
+#define DUMP_COMPRESS_NONE     0x0      /* don't compress this dump         */
+#define DUMP_COMPRESS_RLE      0x1      /* use RLE compression              */
+#define DUMP_COMPRESS_GZIP     0x2      /* use GZIP compression             */
+
+/* dump flags - any dump-type specific flags -- add as necessary */
+#define DUMP_FLAGS_NONE        0x0      /* no flags are set for this dump   */
+#define DUMP_FLAGS_NONDISRUPT  0x1      /* try to keep running after dump   */
+
+/* dump header flags -- add as necessary */
+#define DUMP_DH_FLAGS_NONE     0x0      /* no flags set (error condition!)  */
+#define DUMP_DH_RAW            0x1      /* raw page (no compression)        */
+#define DUMP_DH_COMPRESSED     0x2      /* page is compressed               */
+#define DUMP_DH_END            0x4      /* end marker on a full dump        */
+#define DUMP_DH_TRUNCATED      0x8	/* dump is incomplete               */
+#define DUMP_DH_TEST_PATTERN   0x10	/* dump page is a test pattern      */
+#define DUMP_DH_NOT_USED       0x20	/* 1st bit not used in flags        */
+
+/* names for various dump tunables (they are now all read-only) */
+#define DUMP_ROOT_NAME         "sys/dump"
+#define DUMP_DEVICE_NAME       "dump_device"
+#define DUMP_COMPRESS_NAME     "dump_compress"
+#define DUMP_LEVEL_NAME        "dump_level"
+#define DUMP_FLAGS_NAME        "dump_flags"
+
+/* page size for gzip compression -- buffered slightly beyond hardware PAGE_SIZE used by DUMP */
+#define DUMP_DPC_PAGE_SIZE     (DUMP_PAGE_SIZE + 512)
+
+/* dump ioctl() control options */
+#define DIOSDUMPDEV		1       /* set the dump device              */
+#define DIOGDUMPDEV		2       /* get the dump device              */
+#define DIOSDUMPLEVEL		3       /* set the dump level               */
+#define DIOGDUMPLEVEL		4       /* get the dump level               */
+#define DIOSDUMPFLAGS		5       /* set the dump flag parameters     */
+#define DIOGDUMPFLAGS		6       /* get the dump flag parameters     */
+#define DIOSDUMPCOMPRESS	7       /* set the dump compress level       */
+#define DIOGDUMPCOMPRESS	8       /* get the dump compress level        */
+#define DIODUMPTEST		99      /* test the dump facility (panic/dump) */
+
+/* the major number used for the dumping device */
+#ifndef DUMP_MAJOR
+#define DUMP_MAJOR              227
+#endif
+
+/*
+ * Structure: dump_header_t
+ *  Function: This is the header dumped at the top of every valid crash
+ *            dump.  
+ *            easy reassembly of each crash dump page.  The address bits
+ *            are split to make things easier for 64-bit/32-bit system
+ *            conversions.
+ */
+typedef struct _dump_header_s {
+	/* the dump magic number -- unique to verify dump is valid */
+	uint64_t             dh_magic_number;
+
+	/* the version number of this dump */
+	uint32_t             dh_version;
+
+	/* the size of this header (in case we can't read it) */
+	uint32_t             dh_header_size;
+
+	/* the level of this dump (just a header?) */
+	uint32_t             dh_dump_level;
+
+	/* 
+	 * The size of a hardware/physical memory page (DUMP_PAGE_SIZE).
+	 * NB: Not the configurable system page (PAGE_SIZE) (4K, 8K, 16K, etc.) 
+	 */
+	uint32_t             dh_dump_page_size;
+
+	/* the size of all physical memory */
+	uint64_t             dh_memory_size;
+
+	/* the start of physical memory */
+	uint64_t             dh_memory_start;
+
+	/* the end of physical memory */
+	uint64_t             dh_memory_end;
+
+#if DUMP_DEBUG >= 6
+	/* the number of bytes in this dump specifically */
+	uint64_t             dh_num_bytes;
+#endif
+
+	/* the number of hardware/physical pages in this dump specifically */
+	uint32_t             dh_num_dump_pages;
+
+	/* the panic string, if available */
+	char                 dh_panic_string[DUMP_PANIC_LEN];
+
+	/* the time of the system crash */
+	struct timeval       dh_time;
+
+	/* the NEW utsname (uname) information -- in character form */
+	/* we do this so we don't have to include utsname.h         */
+	/* plus it helps us be more architecture independent        */
+	/* now maybe one day soon they'll make the [65] a #define!  */
+	char                 dh_utsname_sysname[65];
+	char                 dh_utsname_nodename[65];
+	char                 dh_utsname_release[65];
+	char                 dh_utsname_version[65];
+	char                 dh_utsname_machine[65];
+	char                 dh_utsname_domainname[65];
+
+	/* the address of current task (OLD = task_struct *, NEW = void *) */
+	void                *dh_current_task;
+
+	/* what type of compression we're using in this dump (if any) */
+	uint32_t             dh_dump_compress;
+
+	/* any additional flags */
+	uint32_t             dh_dump_flags;
+
+	/* any additional flags */
+	uint32_t             dh_dump_device;
+
+} dump_header_t;
+
+/*
+ * Structure: dump_page_t
+ *  Function: To act as the header associated to each physical page of
+ *            memory saved in the system crash dump.  This allows for
+ *            easy reassembly of each crash dump page.  The address bits
+ *            are split to make things easier for 64-bit/32-bit system
+ *            conversions.
+ *
+ * dp_byte_offset and dp_page_index are landmarks that are helpfull when
+ * looking at a hexdump of /dev/vmdump,
+ */
+typedef struct _dump_page_s {
+
+#if DUMP_DEBUG >= 6
+	/* byte offset */
+	uint64_t		dp_byte_offset;
+
+	/* page index */
+	uint64_t		dp_page_index;
+#endif
+	/* the address of this dump page */
+	uint64_t             dp_address;
+
+	/* the size of this dump page */
+	uint32_t             dp_size;
+
+	/* flags (currently DUMP_COMPRESSED, DUMP_RAW or DUMP_END) */
+	uint32_t             dp_flags;
+} dump_page_t;
+
+/*
+ * This structure contains information needed for the lkcdutils
+ * package (particularly lcrash) to determine what information is
+ * associated to this kernel, specifically.
+ */
+typedef struct lkcdinfo_s {
+	int             arch;
+	int             ptrsz;
+	int             byte_order;
+	int             linux_release;
+	int             page_shift;
+	int             page_size;
+	uint64_t        page_mask;
+	uint64_t        page_offset;
+	int             stack_offset;
+} lkcdinfo_t;
+
+#ifdef __KERNEL__
+
+/*
+ * Structure: dump_compress_t
+ *  Function: This is what an individual compression mechanism can use
+ *            to plug in their own compression techniques.  It's always
+ *            best to build these as individual modules so that people
+ *            can put in whatever they want.
+ */
+typedef struct dump_compress_s {
+	/* the list_head structure for list storage */
+	struct list_head list;
+
+	/* the type of compression to use (DUMP_COMPRESS_XXX) */
+        int compress_type;
+
+	/* the compression function to call */
+        int (*compress_func)(char *, int, char *, int);
+} dump_compress_t;
+
+/* functions for dump compression registration */
+extern void dump_register_compression(dump_compress_t *);
+extern void dump_unregister_compression(int);
+
+/*
+ * Structure dump_mbank[]:
+ *
+ * For CONFIG_DISCONTIGMEM systems this array specifies the
+ * memory banks/chunks that need to be dumped after a panic.
+ *
+ * For clasic systems it specifies a single set of pages from
+ * 0 to max_mapnr.
+ */
+typedef struct dump_mbank {
+        u64 		start;
+        u64 		end;
+	int		type;
+	int		pad1;
+	long		pad2;
+} dump_mbank_t;
+
+#define DUMP_MBANK_TYPE_CONVENTIONAL_MEMORY		1
+#define DUMP_MBANK_TYPE_OTHER				2
+
+
+#define MAXCHUNKS 256
+extern int dump_mbanks;
+extern dump_mbank_t dump_mbank[MAXCHUNKS];
+
+extern struct notifier_block *dump_notifier_list;
+extern int register_dump_notifier(struct notifier_block *);
+extern int unregister_dump_notifier(struct notifier_block *);
+
+/* notification codes */
+#define DUMP_BEGIN	0x0001	/* Notify of dump beginning */
+#define DUMP_END	0x0002	/* Notify of dump ending */
+
+extern int dump_init(void);
+int dump_execute(char *, struct pt_regs *);
+extern volatile int dump_in_progress;
+extern volatile int dumping_cpu;
+extern int (*dump_function_ptr)(char *, struct pt_regs *);
+
+#if defined(CONFIG_X86) || defined(CONFIG_ALPHA)
+extern int page_is_ram(unsigned long);
+#endif
+
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+static inline void dump(char * str, struct pt_regs * regs)
+{
+	if (dump_function_ptr) {
+		dump_function_ptr((char *)str, regs);
+	}
+}
+#else
+static inline void dump(char * str, struct pt_regs * regs)
+{
+}
+#endif /* CONFIG_DUMP */
+
+/*
+ * Common Arch Specific Functions should be declared here.
+ * This allows the C compiler to detect discrepancies.
+ */
+extern void 		__dump_open(void);
+extern void 		__dump_cleanup(void);
+extern void 		__dump_init(uint64_t);
+extern int 		__dump_configure_header(struct pt_regs *);
+extern unsigned int  	__dump_silence_system(unsigned int);
+extern unsigned int  	__dump_resume_system(unsigned int);
+#endif /* __KERNEL__ */
+
+#endif /* _DUMP_H */
diff -Naur linux-2.4.19.orig/init/kerntypes.c linux-2.4.19.lkcd/init/kerntypes.c
--- linux-2.4.19.orig/init/kerntypes.c	Thu Jan  1 05:00:00 1970
+++ linux-2.4.19.lkcd/init/kerntypes.c	Tue Nov 19 13:49:50 2002
@@ -0,0 +1,28 @@
+/*
+ * kerntypes.c
+ *
+ * Copyright (C) 2000 Tom Morano (tjm@sgi.com) and
+ *                    Matt D. Robinson (yakker@alacritech.com)
+ *
+ * Dummy module that includes headers for all kernel types of interest. 
+ * The kernel type information is used by the lcrash utility when 
+ * analyzing system crash dumps or the live system. Using the type 
+ * information for the running system, rather than kernel header files,
+ * makes for a more flexible and robust analysis tool.
+ *
+ * This source code is released under version 2 of the GNU GPL.
+ */
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+#include <linux/module.h>
+#include <linux/autoconf.h>
+#include <linux/mm.h>
+#include <linux/config.h>
+#include <linux/utsname.h>
+#include <linux/dump.h>
+
+void
+kerntypes_dummy(void)
+{
+}
diff -Naur linux-2.4.19.orig/init/main.c linux-2.4.19.lkcd/init/main.c
--- linux-2.4.19.orig/init/main.c	Sat Aug  3 05:39:46 2002
+++ linux-2.4.19.lkcd/init/main.c	Tue Nov 19 13:49:50 2002
@@ -25,6 +25,7 @@
 #include <linux/blk.h>
 #include <linux/hdreg.h>
 #include <linux/iobuf.h>
+#include <linux/dump.h>
 #include <linux/bootmem.h>
 #include <linux/tty.h>
 
@@ -118,6 +119,16 @@
 
 int rows, cols;
 
+/*
+ * The kernel_magic value represents the address of _end, which allows
+ * namelist tools to "match" each other respectively.  That way a tool
+ * that looks at /dev/mem can verify that it is using the right System.map
+ * file -- if kernel_magic doesn't equal the namelist value of _end,
+ * something's wrong.
+ */
+extern unsigned long _end;
+unsigned long *kernel_magic = &_end;
+
 char *execute_command;
 
 static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
@@ -423,6 +434,9 @@
 #if defined(CONFIG_SYSVIPC)
 	ipc_init();
 #endif
+#if defined(CONFIG_DUMP)
+	dump_init();
+#endif
 	check_bugs();
 	printk("POSIX conformance testing by UNIFIX\n");
 
diff -Naur linux-2.4.19.orig/kernel/ksyms.c linux-2.4.19.lkcd/kernel/ksyms.c
--- linux-2.4.19.orig/kernel/ksyms.c	Sat Aug  3 05:39:46 2002
+++ linux-2.4.19.lkcd/kernel/ksyms.c	Tue Nov 19 13:49:50 2002
@@ -40,6 +40,7 @@
 #include <linux/mmzone.h>
 #include <linux/mm.h>
 #include <linux/capability.h>
+#include <linux/dump.h>
 #include <linux/highuid.h>
 #include <linux/brlock.h>
 #include <linux/fs.h>
@@ -64,6 +65,7 @@
 extern int request_dma(unsigned int dmanr, char * deviceID);
 extern void free_dma(unsigned int dmanr);
 extern spinlock_t dma_spin_lock;
+extern int panic_timeout;
 
 #ifdef CONFIG_MODVERSIONS
 const struct module_symbol __export_Using_Versions
@@ -359,6 +361,21 @@
 EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax);
 EXPORT_SYMBOL(proc_doulongvec_minmax);
 
+/* dump (system crash dump) functions and needed parameters */
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+EXPORT_SYMBOL(get_blkfops);
+EXPORT_SYMBOL(dump_function_ptr);
+#if defined(CONFIG_X86) || defined(CONFIG_ALPHA)
+EXPORT_SYMBOL(page_is_ram);
+#endif
+EXPORT_SYMBOL(dump_in_progress);
+EXPORT_SYMBOL(dumping_cpu);
+EXPORT_SYMBOL(panic_timeout);
+EXPORT_SYMBOL(register_dump_notifier);
+EXPORT_SYMBOL(unregister_dump_notifier);
+EXPORT_SYMBOL(dump_notifier_list);
+#endif
+
 /* interrupt handling */
 EXPORT_SYMBOL(add_timer);
 EXPORT_SYMBOL(del_timer);
diff -Naur linux-2.4.19.orig/kernel/panic.c linux-2.4.19.lkcd/kernel/panic.c
--- linux-2.4.19.orig/kernel/panic.c	Sat Aug  3 05:39:46 2002
+++ linux-2.4.19.lkcd/kernel/panic.c	Tue Nov 19 13:49:50 2002
@@ -13,6 +13,7 @@
 #include <linux/delay.h>
 #include <linux/reboot.h>
 #include <linux/notifier.h>
+#include <linux/dump.h>
 #include <linux/init.h>
 #include <linux/sysrq.h>
 #include <linux/interrupt.h>
@@ -20,6 +21,11 @@
 asmlinkage void sys_sync(void);	/* it's really int */
 
 int panic_timeout;
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+int (*dump_function_ptr)(char *, struct pt_regs *) = 0;
+volatile int dump_in_progress = 0;
+volatile int dumping_cpu = 0;
+#endif
 
 struct notifier_block *panic_notifier_list;
 
@@ -49,6 +55,11 @@
         unsigned long caller = (unsigned long) __builtin_return_address(0);
 #endif
 
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+	struct pt_regs regs;
+	get_current_regs(&regs);
+#endif
+
 	bust_spinlocks(1);
 	va_start(args, fmt);
 	vsprintf(buf, fmt, args);
@@ -62,12 +73,18 @@
 		sys_sync();
 	bust_spinlocks(0);
 
+#if !defined(CONFIG_DUMP) && !defined(CONFIG_DUMP_MODULE)
 #ifdef CONFIG_SMP
 	smp_send_stop();
 #endif
+#endif
 
 	notifier_call_chain(&panic_notifier_list, 0, NULL);
 
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+	dump(buf, &regs);
+#endif
+
 	if (panic_timeout > 0)
 	{
 		/*
diff -Naur linux-2.4.19.orig/kernel/sched.c linux-2.4.19.lkcd/kernel/sched.c
--- linux-2.4.19.orig/kernel/sched.c	Sat Aug  3 05:39:46 2002
+++ linux-2.4.19.lkcd/kernel/sched.c	Tue Nov 19 13:49:50 2002
@@ -27,6 +27,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/completion.h>
+#include <linux/dump.h>
 #include <linux/prefetch.h>
 #include <linux/compiler.h>
 
@@ -554,6 +555,12 @@
 	int this_cpu, c;
 
 
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+	if (dump_in_progress) {
+		goto dump_scheduling_disabled;
+	}
+#endif
+
 	spin_lock_prefetch(&runqueue_lock);
 
 	BUG_ON(!current->active_mm);
@@ -702,6 +709,23 @@
 	if (current->need_resched)
 		goto need_resched_back;
 	return;
+
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+dump_scheduling_disabled:
+
+	/* make sure we assign our this_cpu ... */
+	if (!current->active_mm) BUG();
+	this_cpu = current->processor;
+
+	/*
+	 * If this is not the dumping cpu, then spin right here
+	 * till the dump is complete
+	 */
+	if (this_cpu != dumping_cpu) {
+		while (dump_in_progress);
+	}
+#endif
+	return;
 }
 
 /*
diff -Naur linux-2.4.19.orig/kernel/sys.c linux-2.4.19.lkcd/kernel/sys.c
--- linux-2.4.19.orig/kernel/sys.c	Sat Aug  3 05:39:46 2002
+++ linux-2.4.19.lkcd/kernel/sys.c	Tue Nov 19 13:49:50 2002
@@ -14,6 +14,9 @@
 #include <linux/prctl.h>
 #include <linux/init.h>
 #include <linux/highuid.h>
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+#include <linux/dump.h>
+#endif
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -49,6 +52,9 @@
  */
 
 static struct notifier_block *reboot_notifier_list;
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+struct notifier_block *dump_notifier_list;
+#endif
 rwlock_t notifier_lock = RW_LOCK_UNLOCKED;
 
 /**
@@ -167,6 +173,39 @@
 	return notifier_chain_unregister(&reboot_notifier_list, nb);
 }
 
+#if defined(CONFIG_DUMP) || defined(CONFIG_DUMP_MODULE)
+/**
+ *	register_dump_notifier - Register function to be called at dump time
+ *	@nb: Info about notifier function to be called
+ *
+ *	Registers a function with the list of functions
+ *	to be called at dump time.
+ *
+ *	Currently always returns zero, as notifier_chain_register
+ *	always returns zero.
+ */
+ 
+int register_dump_notifier(struct notifier_block * nb)
+{
+	return notifier_chain_register(&dump_notifier_list, nb);
+}
+
+/**
+ *	unregister_dump_notifier - Unregister previously registered dump notifier
+ *	@nb: Hook to be unregistered
+ *
+ *	Unregisters a previously registered dump
+ *	notifier function.
+ *
+ *	Returns zero on success, or %-ENOENT on failure.
+ */
+ 
+int unregister_dump_notifier(struct notifier_block * nb)
+{
+	return notifier_chain_unregister(&dump_notifier_list, nb);
+}
+#endif
+
 asmlinkage long sys_ni_syscall(void)
 {
 	return -ENOSYS;
