diff -Nurb linux-2.6.24.3/arch/x86/kernel/cobalt.c linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/cobalt.c
--- linux-2.6.24.3/arch/x86/kernel/cobalt.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/cobalt.c	2008-03-02 14:55:48.000000000 -0800
@@ -0,0 +1,279 @@
+/* $Id: cobalt.c,v 1.34 2002/11/04 17:54:14 thockin Exp $ */
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/ptrace.h>
+#include <linux/reboot.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+
+#include <cobalt/cobalt.h>
+#include <cobalt/misc.h>
+#include <cobalt/led.h>
+#include <cobalt/wdt.h>
+#include <cobalt/acpi.h>
+#include <cobalt/superio.h>
+#include <cobalt/systype.h>
+
+#define MAX_NMI_PS	10
+
+static u8 last_err;
+static u32 last_address;
+static unsigned long nmi_repeats;
+static struct timer_list nmi_timer;
+static int timer_added;
+static unsigned long nmi_count;
+static spinlock_t nmi_state_lock = SPIN_LOCK_UNLOCKED;
+
+static inline void 
+ledonoff(unsigned long on, unsigned long off)
+{
+#ifdef CONFIG_COBALT_LED
+	unsigned long start;
+	int haltok = current_cpu_data.hlt_works_ok;
+
+	if (on) {
+		start = jiffies;
+		cobalt_led_set(cobalt_led_get() | LED_SHUTDOWN);
+		while (jiffies < start + on) {
+			if (haltok) __asm__("hlt");
+		}
+	}
+
+	if (off) {
+		start = jiffies;
+		cobalt_led_set(cobalt_led_get() & ~LED_SHUTDOWN);
+		while (jiffies < start + off) {
+			if (haltok) __asm__("hlt");
+		}
+	}
+#endif
+}
+
+/* clla this holding nmi_state_lock */
+static inline void
+do_repeats(void)
+{
+	if (nmi_repeats) {
+		printk("NMI: last error repeated %lu times\n", nmi_repeats);
+		nmi_repeats = 0;
+	}
+}
+
+static void 
+nmi_throttle_fn(unsigned long data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&nmi_state_lock, flags);
+
+	/* clear any repeated NMIs */
+	do_repeats();
+
+	/* have we had a lot of errors this second */
+	if (nmi_count > MAX_NMI_PS) {
+		printk("NMI: %lu messages were throttled\n", 
+			nmi_count - MAX_NMI_PS);
+		nmi_count = 0;
+	}
+
+	/* de-activate the timer - will be reactivated by an NMI */
+	del_timer(&nmi_timer);
+	timer_added = 0;
+
+	spin_unlock_irqrestore(&nmi_state_lock, flags);
+}
+
+void 
+cobalt_nmi(unsigned char reason, struct pt_regs *regs)
+{
+	if (cobt_is_5k()) {
+		static struct pci_dev *cnb_dev;
+		u8 err;
+		u32 address = 0;
+		unsigned long flags;
+
+		/* find our memory controller */
+		if (!cnb_dev) {
+			cnb_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+				  PCI_DEVICE_ID_SERVERWORKS_LE, NULL);
+		}
+		if (!cnb_dev) {
+			EPRINTK("can't find north bridge for NMI status\n");
+			return;
+		}
+
+		/* read the error number */
+		pci_read_config_byte(cnb_dev, 0x47, &err);
+
+		/* if a memory error was detected, where? */
+		if (err & 0x06) {
+			pci_read_config_dword(cnb_dev, 0x94, &address);
+		}
+
+		spin_lock_irqsave(&nmi_state_lock, flags);
+
+		/* set up the timer, if it isn't set to go already */
+		if (!timer_added) {
+			init_timer(&nmi_timer);
+			nmi_timer.expires = jiffies + HZ;
+			nmi_timer.function = nmi_throttle_fn;
+			add_timer(&nmi_timer);
+			timer_added = 1;
+		}
+
+		/* if we already printed this error */
+		if (last_err && err == last_err && address == last_address) {
+			nmi_repeats++;
+			spin_unlock_irqrestore(&nmi_state_lock, flags);
+		} else {
+			unsigned long nmi_now;
+
+			/* different error - show repeats */
+			do_repeats();
+
+			/* we only want to do a few messages per second */
+			nmi_now = nmi_count++;
+
+			spin_unlock_irqrestore(&nmi_state_lock, flags);
+
+			/* generate a new message */
+			if (nmi_now < MAX_NMI_PS) {
+				/* only remember NMIs that we can print */
+				last_err = err;
+				last_address = address;
+
+				printk("NMI:");
+				if (err & 0x40)
+					printk(" (PCI tx data error)");
+				if (err & 0x20)
+					printk(" (PCI rx data error)");
+				if (err & 0x10)
+					printk(" (PCI address error)");
+				if (err & 0x04)
+					printk(" (DRAM uncorrectable error)");
+				if (err & 0x02)
+					printk(" (DRAM correctable error)");
+				if (err & 0x01)
+					printk(" (Shutdown cycle detected)");
+
+				if (err & 0x06) {
+					u8 row, dimm, ecc;
+
+					row = (address >> 29) & 0x7;
+					pci_read_config_byte(cnb_dev, 
+						0x7c + (row >> 1), &dimm);
+					dimm = ((row & 1) ? 
+						(dimm >> 4) : dimm) & 0xf;
+					pci_read_config_byte(cnb_dev, 0xe8, 
+						&ecc);
+
+					printk(" [memory row %d, DIMM type %d, "
+						"col=0x%x, row=0x%x, ECC=0x%x]",
+						row, dimm, 
+						(address >> 15) & 0x3fff, 
+						address & 0x7fff, ecc);
+				} 
+				printk("\n");
+			}
+		}
+
+		/* clear errors */
+		pci_write_config_byte(cnb_dev, 0x47, err); 
+	} else {
+		/* TODO: make throttling generic, handle GP NMIs */
+		printk("NMI: unknown error\n");
+	}
+}
+
+void 
+cobalt_restart(void)
+{
+	if (cobt_is_3k()) {
+		/* kick watchdog */
+		cobalt_wdt_trigger_reboot();
+	} else if (cobt_is_5k()) {
+		/* set "Enable Hard Reset" bit to 1 */
+		outb(0x02, 0x0cf9);
+
+		/* 0-to-1 transition of bit 2 will cause reset of processor */
+		outb(0x06, 0x0cf9);
+	}
+	mdelay(3000);
+
+	/* we should not get here unless there is a BAD error */
+	EPRINTK("can not restart - halting\n");
+	machine_halt();
+}
+
+void
+cobalt_halt(void)
+{
+	int haltok = current_cpu_data.hlt_works_ok;
+
+	if (cobt_is_5k()) {
+		/* we have soft power-off */
+		machine_power_off();
+	}
+
+	/* 
+	 * we want to do cpu_idle, but we don't actually want to 
+	 * call cpu_idle. bleah. 
+	 */
+	while (1) {
+		ledonoff(HZ >> 1, HZ >> 1);
+		if (haltok) {
+			__asm__("hlt");
+		}
+	}
+}
+
+void
+cobalt_power_off(void)
+{
+	u16 addr;
+
+	if (cobt_is_monterey()) {
+		u8 val;
+		/* use card control reg. 7 to select logical device 2 (APC) */
+		addr = superio_ldev_base(PC87317_DEV_RTC);
+
+		/* set up bank 2 */
+		outb(PC87317_RTC_CRA, addr);
+		val = inb(addr + 1) & 0x8f;
+		outb(val | PC87317_RTC_BANK_2, addr + 1);
+
+		/* power off the machine with APCR1 */
+		outb(PC87317_APCR1, addr);
+		val = inb(addr + 1);
+		outb(0x20 | val, addr + 1);
+	} else if (cobt_is_alpine()) {
+		int i;
+		/* clear status bits, base addr 3 */
+		addr = superio_ldev_base_n(PC87417_DEV_SWC, 3);
+		for (i = 0; i < 4; i++) {
+			/* 
+			 * if we have an event while running, 
+			 * we can't halt unless we clear these
+			 * */
+			outb(0xff, addr+i);
+		}
+
+		/* set sleep state, base addr 2 */
+		addr = superio_ldev_base_n(PC87417_DEV_SWC, 2);
+		/* PM1b_CNT_HIGH @offset 1 - set state to S5 */
+		outb(0x34, addr+1);
+	}
+	mdelay(3000);
+	EPRINTK("can not power off\n");
+}
+
+/* put arch specific stuff to run at init time here */
+static int __init
+cobalt_arch_init(void)
+{
+	return 0;
+}
+module_init(cobalt_arch_init);
diff -Nurb linux-2.6.24.3/arch/x86/kernel/Makefile_32 linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/Makefile_32
--- linux-2.6.24.3/arch/x86/kernel/Makefile_32	2008-02-25 16:20:20.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/Makefile_32	2008-03-02 14:55:48.000000000 -0800
@@ -58,6 +58,7 @@
 targets += vsyscall-note_32.o vsyscall_32.lds
 
 # The DSO images are built using a special linker script.
+obj-$(CONFIG_COBALT_RAQ)	+= cobalt.o
 quiet_cmd_syscall = SYSCALL $@
       cmd_syscall = $(CC) -m elf_i386 -nostdlib $(SYSCFLAGS_$(@F)) \
 		          -Wl,-T,$(filter-out FORCE,$^) -o $@
diff -Nurb linux-2.6.24.3/arch/x86/kernel/Makefile_32.orig linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/Makefile_32.orig
--- linux-2.6.24.3/arch/x86/kernel/Makefile_32.orig	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/Makefile_32.orig	2008-02-25 16:20:20.000000000 -0800
@@ -0,0 +1,89 @@
+#
+# Makefile for the linux kernel.
+#
+
+extra-y := head_32.o init_task.o vmlinux.lds
+CPPFLAGS_vmlinux.lds += -Ui386
+
+obj-y	:= process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \
+		ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \
+		pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\
+		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o
+
+obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
+obj-y				+= cpu/
+obj-y				+= acpi/
+obj-$(CONFIG_X86_BIOS_REBOOT)	+= reboot_32.o
+obj-$(CONFIG_MCA)		+= mca_32.o
+obj-$(CONFIG_X86_MSR)		+= msr.o
+obj-$(CONFIG_X86_CPUID)		+= cpuid.o
+obj-$(CONFIG_MICROCODE)		+= microcode.o
+obj-$(CONFIG_PCI)		+= early-quirks.o
+apm-y				:= apm_32.o
+obj-$(CONFIG_APM)		+= apm.o
+obj-$(CONFIG_X86_SMP)		+= smp_32.o smpboot_32.o tsc_sync.o
+obj-$(CONFIG_SMP)		+= smpcommon_32.o
+obj-$(CONFIG_X86_TRAMPOLINE)	+= trampoline_32.o
+obj-$(CONFIG_X86_MPPARSE)	+= mpparse_32.o
+obj-$(CONFIG_X86_LOCAL_APIC)	+= apic_32.o nmi_32.o
+obj-$(CONFIG_X86_IO_APIC)	+= io_apic_32.o
+obj-$(CONFIG_X86_REBOOTFIXUPS)	+= reboot_fixups_32.o
+obj-$(CONFIG_KEXEC)		+= machine_kexec_32.o relocate_kernel_32.o crash.o
+obj-$(CONFIG_CRASH_DUMP)	+= crash_dump_32.o
+obj-$(CONFIG_X86_NUMAQ)		+= numaq_32.o
+obj-$(CONFIG_X86_SUMMIT_NUMA)	+= summit_32.o
+obj-$(CONFIG_KPROBES)		+= kprobes_32.o
+obj-$(CONFIG_MODULES)		+= module_32.o
+obj-y				+= sysenter_32.o vsyscall_32.o
+obj-$(CONFIG_ACPI_SRAT) 	+= srat_32.o
+obj-$(CONFIG_EFI) 		+= efi_32.o efi_stub_32.o
+obj-$(CONFIG_DOUBLEFAULT) 	+= doublefault_32.o
+obj-$(CONFIG_VM86)		+= vm86_32.o
+obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
+obj-$(CONFIG_HPET_TIMER) 	+= hpet.o
+obj-$(CONFIG_K8_NB)		+= k8.o
+obj-$(CONFIG_MGEODE_LX)		+= geode_32.o mfgpt_32.o
+
+obj-$(CONFIG_VMI)		+= vmi_32.o vmiclock_32.o
+obj-$(CONFIG_PARAVIRT)		+= paravirt_32.o
+obj-y				+= pcspeaker.o
+
+obj-$(CONFIG_SCx200)		+= scx200_32.o
+
+# vsyscall_32.o contains the vsyscall DSO images as __initdata.
+# We must build both images before we can assemble it.
+# Note: kbuild does not track this dependency due to usage of .incbin
+$(obj)/vsyscall_32.o: $(obj)/vsyscall-int80_32.so $(obj)/vsyscall-sysenter_32.so
+targets += $(foreach F,int80 sysenter,vsyscall-$F_32.o vsyscall-$F_32.so)
+targets += vsyscall-note_32.o vsyscall_32.lds
+
+# The DSO images are built using a special linker script.
+quiet_cmd_syscall = SYSCALL $@
+      cmd_syscall = $(CC) -m elf_i386 -nostdlib $(SYSCFLAGS_$(@F)) \
+		          -Wl,-T,$(filter-out FORCE,$^) -o $@
+
+export CPPFLAGS_vsyscall_32.lds += -P -C -Ui386
+
+vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 \
+		 $(call ld-option, -Wl$(comma)--hash-style=sysv)
+SYSCFLAGS_vsyscall-sysenter_32.so	= $(vsyscall-flags)
+SYSCFLAGS_vsyscall-int80_32.so	= $(vsyscall-flags)
+
+$(obj)/vsyscall-int80_32.so $(obj)/vsyscall-sysenter_32.so: \
+$(obj)/vsyscall-%.so: $(src)/vsyscall_32.lds \
+		      $(obj)/vsyscall-%.o $(obj)/vsyscall-note_32.o FORCE
+	$(call if_changed,syscall)
+
+# We also create a special relocatable object that should mirror the symbol
+# table and layout of the linked DSO.  With ld -R we can then refer to
+# these symbols in the kernel code rather than hand-coded addresses.
+extra-y += vsyscall-syms.o
+$(obj)/built-in.o: $(obj)/vsyscall-syms.o
+$(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o
+
+SYSCFLAGS_vsyscall-syms.o = -r
+$(obj)/vsyscall-syms.o: $(src)/vsyscall_32.lds \
+			$(obj)/vsyscall-sysenter_32.o $(obj)/vsyscall-note_32.o FORCE
+	$(call if_changed,syscall)
+
+
diff -Nurb linux-2.6.24.3/arch/x86/kernel/process_32.c linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/process_32.c
--- linux-2.6.24.3/arch/x86/kernel/process_32.c	2008-02-25 16:20:20.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/process_32.c	2008-03-02 14:55:48.000000000 -0800
@@ -51,6 +51,11 @@
 #include <asm/math_emu.h>
 #endif
 
+#ifdef CONFIG_COBALT_RAQ
+#include <cobalt/misc.h>
+#include <cobalt/lcd.h>
+#endif
+
 #include <linux/err.h>
 
 #include <asm/tlbflush.h>
@@ -531,6 +536,12 @@
 {
 	int i;
 
+#ifdef CONFIG_COBALT_RAQ
+	wait_for_flush();
+	cobalt_restart();
+#endif
+
+
 /* changed the size calculations - should hopefully work better. lbt */
 	dump->magic = CMAGIC;
 	dump->start_code = 0;
diff -Nurb linux-2.6.24.3/arch/x86/kernel/process_32.c.orig linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/process_32.c.orig
--- linux-2.6.24.3/arch/x86/kernel/process_32.c.orig	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/process_32.c.orig	2008-02-25 16:20:20.000000000 -0800
@@ -0,0 +1,984 @@
+/*
+ *  Copyright (C) 1995  Linus Torvalds
+ *
+ *  Pentium III FXSR, SSE support
+ *	Gareth Hughes <gareth@valinux.com>, May 2000
+ */
+
+/*
+ * This file handles the architecture-dependent parts of process handling..
+ */
+
+#include <stdarg.h>
+
+#include <linux/cpu.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/elfcore.h>
+#include <linux/smp.h>
+#include <linux/stddef.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/interrupt.h>
+#include <linux/utsname.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/mc146818rtc.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+#include <linux/ptrace.h>
+#include <linux/random.h>
+#include <linux/personality.h>
+#include <linux/tick.h>
+#include <linux/percpu.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/ldt.h>
+#include <asm/processor.h>
+#include <asm/i387.h>
+#include <asm/desc.h>
+#include <asm/vm86.h>
+#ifdef CONFIG_MATH_EMULATION
+#include <asm/math_emu.h>
+#endif
+
+#include <linux/err.h>
+
+#include <asm/tlbflush.h>
+#include <asm/cpu.h>
+
+asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
+
+static int hlt_counter;
+
+unsigned long boot_option_idle_override = 0;
+EXPORT_SYMBOL(boot_option_idle_override);
+
+DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task;
+EXPORT_PER_CPU_SYMBOL(current_task);
+
+DEFINE_PER_CPU(int, cpu_number);
+EXPORT_PER_CPU_SYMBOL(cpu_number);
+
+/*
+ * Return saved PC of a blocked thread.
+ */
+unsigned long thread_saved_pc(struct task_struct *tsk)
+{
+	return ((unsigned long *)tsk->thread.esp)[3];
+}
+
+/*
+ * Powermanagement idle function, if any..
+ */
+void (*pm_idle)(void);
+EXPORT_SYMBOL(pm_idle);
+static DEFINE_PER_CPU(unsigned int, cpu_idle_state);
+
+void disable_hlt(void)
+{
+	hlt_counter++;
+}
+
+EXPORT_SYMBOL(disable_hlt);
+
+void enable_hlt(void)
+{
+	hlt_counter--;
+}
+
+EXPORT_SYMBOL(enable_hlt);
+
+/*
+ * We use this if we don't have any better
+ * idle routine..
+ */
+void default_idle(void)
+{
+	if (!hlt_counter && boot_cpu_data.hlt_works_ok) {
+		current_thread_info()->status &= ~TS_POLLING;
+		/*
+		 * TS_POLLING-cleared state must be visible before we
+		 * test NEED_RESCHED:
+		 */
+		smp_mb();
+
+		local_irq_disable();
+		if (!need_resched())
+			safe_halt();	/* enables interrupts racelessly */
+		else
+			local_irq_enable();
+		current_thread_info()->status |= TS_POLLING;
+	} else {
+		/* loop is done by the caller */
+		cpu_relax();
+	}
+}
+#ifdef CONFIG_APM_MODULE
+EXPORT_SYMBOL(default_idle);
+#endif
+
+/*
+ * On SMP it's slightly faster (but much more power-consuming!)
+ * to poll the ->work.need_resched flag instead of waiting for the
+ * cross-CPU IPI to arrive. Use this option with caution.
+ */
+static void poll_idle (void)
+{
+	cpu_relax();
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+#include <asm/nmi.h>
+/* We don't actually take CPU down, just spin without interrupts. */
+static inline void play_dead(void)
+{
+	/* This must be done before dead CPU ack */
+	cpu_exit_clear();
+	wbinvd();
+	mb();
+	/* Ack it */
+	__get_cpu_var(cpu_state) = CPU_DEAD;
+
+	/*
+	 * With physical CPU hotplug, we should halt the cpu
+	 */
+	local_irq_disable();
+	while (1)
+		halt();
+}
+#else
+static inline void play_dead(void)
+{
+	BUG();
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
+/*
+ * The idle thread. There's no useful work to be
+ * done, so just try to conserve power and have a
+ * low exit latency (ie sit in a loop waiting for
+ * somebody to say that they'd like to reschedule)
+ */
+void cpu_idle(void)
+{
+	int cpu = smp_processor_id();
+
+	current_thread_info()->status |= TS_POLLING;
+
+	/* endless idle loop with no priority at all */
+	while (1) {
+		tick_nohz_stop_sched_tick();
+		while (!need_resched()) {
+			void (*idle)(void);
+
+			if (__get_cpu_var(cpu_idle_state))
+				__get_cpu_var(cpu_idle_state) = 0;
+
+			check_pgt_cache();
+			rmb();
+			idle = pm_idle;
+
+			if (!idle)
+				idle = default_idle;
+
+			if (cpu_is_offline(cpu))
+				play_dead();
+
+			__get_cpu_var(irq_stat).idle_timestamp = jiffies;
+			idle();
+		}
+		tick_nohz_restart_sched_tick();
+		preempt_enable_no_resched();
+		schedule();
+		preempt_disable();
+	}
+}
+
+static void do_nothing(void *unused)
+{
+}
+
+void cpu_idle_wait(void)
+{
+	unsigned int cpu, this_cpu = get_cpu();
+	cpumask_t map, tmp = current->cpus_allowed;
+
+	set_cpus_allowed(current, cpumask_of_cpu(this_cpu));
+	put_cpu();
+
+	cpus_clear(map);
+	for_each_online_cpu(cpu) {
+		per_cpu(cpu_idle_state, cpu) = 1;
+		cpu_set(cpu, map);
+	}
+
+	__get_cpu_var(cpu_idle_state) = 0;
+
+	wmb();
+	do {
+		ssleep(1);
+		for_each_online_cpu(cpu) {
+			if (cpu_isset(cpu, map) && !per_cpu(cpu_idle_state, cpu))
+				cpu_clear(cpu, map);
+		}
+		cpus_and(map, map, cpu_online_map);
+		/*
+		 * We waited 1 sec, if a CPU still did not call idle
+		 * it may be because it is in idle and not waking up
+		 * because it has nothing to do.
+		 * Give all the remaining CPUS a kick.
+		 */
+		smp_call_function_mask(map, do_nothing, 0, 0);
+	} while (!cpus_empty(map));
+
+	set_cpus_allowed(current, tmp);
+}
+EXPORT_SYMBOL_GPL(cpu_idle_wait);
+
+/*
+ * This uses new MONITOR/MWAIT instructions on P4 processors with PNI,
+ * which can obviate IPI to trigger checking of need_resched.
+ * We execute MONITOR against need_resched and enter optimized wait state
+ * through MWAIT. Whenever someone changes need_resched, we would be woken
+ * up from MWAIT (without an IPI).
+ *
+ * New with Core Duo processors, MWAIT can take some hints based on CPU
+ * capability.
+ */
+void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
+{
+	if (!need_resched()) {
+		__monitor((void *)&current_thread_info()->flags, 0, 0);
+		smp_mb();
+		if (!need_resched())
+			__mwait(eax, ecx);
+	}
+}
+
+/* Default MONITOR/MWAIT with no hints, used for default C1 state */
+static void mwait_idle(void)
+{
+	local_irq_enable();
+	mwait_idle_with_hints(0, 0);
+}
+
+void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
+{
+	if (cpu_has(c, X86_FEATURE_MWAIT)) {
+		printk("monitor/mwait feature present.\n");
+		/*
+		 * Skip, if setup has overridden idle.
+		 * One CPU supports mwait => All CPUs supports mwait
+		 */
+		if (!pm_idle) {
+			printk("using mwait in idle threads.\n");
+			pm_idle = mwait_idle;
+		}
+	}
+}
+
+static int __init idle_setup(char *str)
+{
+	if (!strcmp(str, "poll")) {
+		printk("using polling idle threads.\n");
+		pm_idle = poll_idle;
+#ifdef CONFIG_X86_SMP
+		if (smp_num_siblings > 1)
+			printk("WARNING: polling idle and HT enabled, performance may degrade.\n");
+#endif
+	} else if (!strcmp(str, "mwait"))
+		force_mwait = 1;
+	else
+		return -1;
+
+	boot_option_idle_override = 1;
+	return 0;
+}
+early_param("idle", idle_setup);
+
+void __show_registers(struct pt_regs *regs, int all)
+{
+	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
+	unsigned long d0, d1, d2, d3, d6, d7;
+	unsigned long esp;
+	unsigned short ss, gs;
+
+	if (user_mode_vm(regs)) {
+		esp = regs->esp;
+		ss = regs->xss & 0xffff;
+		savesegment(gs, gs);
+	} else {
+		esp = (unsigned long) (&regs->esp);
+		savesegment(ss, ss);
+		savesegment(gs, gs);
+	}
+
+	printk("\n");
+	printk("Pid: %d, comm: %s %s (%s %.*s)\n",
+			task_pid_nr(current), current->comm,
+			print_tainted(), init_utsname()->release,
+			(int)strcspn(init_utsname()->version, " "),
+			init_utsname()->version);
+
+	printk("EIP: %04x:[<%08lx>] EFLAGS: %08lx CPU: %d\n",
+			0xffff & regs->xcs, regs->eip, regs->eflags,
+			smp_processor_id());
+	print_symbol("EIP is at %s\n", regs->eip);
+
+	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: %08lx\n",
+		regs->esi, regs->edi, regs->ebp, esp);
+	printk(" DS: %04x ES: %04x FS: %04x GS: %04x SS: %04x\n",
+	       regs->xds & 0xffff, regs->xes & 0xffff,
+	       regs->xfs & 0xffff, gs, ss);
+
+	if (!all)
+		return;
+
+	cr0 = read_cr0();
+	cr2 = read_cr2();
+	cr3 = read_cr3();
+	cr4 = read_cr4_safe();
+	printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n",
+			cr0, cr2, cr3, cr4);
+
+	get_debugreg(d0, 0);
+	get_debugreg(d1, 1);
+	get_debugreg(d2, 2);
+	get_debugreg(d3, 3);
+	printk("DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n",
+			d0, d1, d2, d3);
+
+	get_debugreg(d6, 6);
+	get_debugreg(d7, 7);
+	printk("DR6: %08lx DR7: %08lx\n",
+			d6, d7);
+}
+
+void show_regs(struct pt_regs *regs)
+{
+	__show_registers(regs, 1);
+	show_trace(NULL, regs, &regs->esp);
+}
+
+/*
+ * This gets run with %ebx containing the
+ * function to call, and %edx containing
+ * the "args".
+ */
+extern void kernel_thread_helper(void);
+
+/*
+ * Create a kernel thread
+ */
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+	struct pt_regs regs;
+
+	memset(&regs, 0, sizeof(regs));
+
+	regs.ebx = (unsigned long) fn;
+	regs.edx = (unsigned long) arg;
+
+	regs.xds = __USER_DS;
+	regs.xes = __USER_DS;
+	regs.xfs = __KERNEL_PERCPU;
+	regs.orig_eax = -1;
+	regs.eip = (unsigned long) kernel_thread_helper;
+	regs.xcs = __KERNEL_CS | get_kernel_rpl();
+	regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2;
+
+	/* Ok, create the new process.. */
+	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
+}
+EXPORT_SYMBOL(kernel_thread);
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+	/* The process may have allocated an io port bitmap... nuke it. */
+	if (unlikely(test_thread_flag(TIF_IO_BITMAP))) {
+		struct task_struct *tsk = current;
+		struct thread_struct *t = &tsk->thread;
+		int cpu = get_cpu();
+		struct tss_struct *tss = &per_cpu(init_tss, cpu);
+
+		kfree(t->io_bitmap_ptr);
+		t->io_bitmap_ptr = NULL;
+		clear_thread_flag(TIF_IO_BITMAP);
+		/*
+		 * Careful, clear this in the TSS too:
+		 */
+		memset(tss->io_bitmap, 0xff, tss->io_bitmap_max);
+		t->io_bitmap_max = 0;
+		tss->io_bitmap_owner = NULL;
+		tss->io_bitmap_max = 0;
+		tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
+		put_cpu();
+	}
+}
+
+void flush_thread(void)
+{
+	struct task_struct *tsk = current;
+
+	memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8);
+	memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));	
+	clear_tsk_thread_flag(tsk, TIF_DEBUG);
+	/*
+	 * Forget coprocessor state..
+	 */
+	clear_fpu(tsk);
+	clear_used_math();
+}
+
+void release_thread(struct task_struct *dead_task)
+{
+	BUG_ON(dead_task->mm);
+	release_vm86_irqs(dead_task);
+}
+
+/*
+ * This gets called before we allocate a new thread and copy
+ * the current task into it.
+ */
+void prepare_to_copy(struct task_struct *tsk)
+{
+	unlazy_fpu(tsk);
+}
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
+	unsigned long unused,
+	struct task_struct * p, struct pt_regs * regs)
+{
+	struct pt_regs * childregs;
+	struct task_struct *tsk;
+	int err;
+
+	childregs = task_pt_regs(p);
+	*childregs = *regs;
+	childregs->eax = 0;
+	childregs->esp = esp;
+
+	p->thread.esp = (unsigned long) childregs;
+	p->thread.esp0 = (unsigned long) (childregs+1);
+
+	p->thread.eip = (unsigned long) ret_from_fork;
+
+	savesegment(gs,p->thread.gs);
+
+	tsk = current;
+	if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) {
+		p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr,
+						IO_BITMAP_BYTES, GFP_KERNEL);
+		if (!p->thread.io_bitmap_ptr) {
+			p->thread.io_bitmap_max = 0;
+			return -ENOMEM;
+		}
+		set_tsk_thread_flag(p, TIF_IO_BITMAP);
+	}
+
+	/*
+	 * Set a new TLS for the child thread?
+	 */
+	if (clone_flags & CLONE_SETTLS) {
+		struct desc_struct *desc;
+		struct user_desc info;
+		int idx;
+
+		err = -EFAULT;
+		if (copy_from_user(&info, (void __user *)childregs->esi, sizeof(info)))
+			goto out;
+		err = -EINVAL;
+		if (LDT_empty(&info))
+			goto out;
+
+		idx = info.entry_number;
+		if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
+			goto out;
+
+		desc = p->thread.tls_array + idx - GDT_ENTRY_TLS_MIN;
+		desc->a = LDT_entry_a(&info);
+		desc->b = LDT_entry_b(&info);
+	}
+
+	err = 0;
+ out:
+	if (err && p->thread.io_bitmap_ptr) {
+		kfree(p->thread.io_bitmap_ptr);
+		p->thread.io_bitmap_max = 0;
+	}
+	return err;
+}
+
+/*
+ * fill in the user structure for a core dump..
+ */
+void dump_thread(struct pt_regs * regs, struct user * dump)
+{
+	int i;
+
+/* changed the size calculations - should hopefully work better. lbt */
+	dump->magic = CMAGIC;
+	dump->start_code = 0;
+	dump->start_stack = regs->esp & ~(PAGE_SIZE - 1);
+	dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
+	dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
+	dump->u_dsize -= dump->u_tsize;
+	dump->u_ssize = 0;
+	for (i = 0; i < 8; i++)
+		dump->u_debugreg[i] = current->thread.debugreg[i];  
+
+	if (dump->start_stack < TASK_SIZE)
+		dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
+
+	dump->regs.ebx = regs->ebx;
+	dump->regs.ecx = regs->ecx;
+	dump->regs.edx = regs->edx;
+	dump->regs.esi = regs->esi;
+	dump->regs.edi = regs->edi;
+	dump->regs.ebp = regs->ebp;
+	dump->regs.eax = regs->eax;
+	dump->regs.ds = regs->xds;
+	dump->regs.es = regs->xes;
+	dump->regs.fs = regs->xfs;
+	savesegment(gs,dump->regs.gs);
+	dump->regs.orig_eax = regs->orig_eax;
+	dump->regs.eip = regs->eip;
+	dump->regs.cs = regs->xcs;
+	dump->regs.eflags = regs->eflags;
+	dump->regs.esp = regs->esp;
+	dump->regs.ss = regs->xss;
+
+	dump->u_fpvalid = dump_fpu (regs, &dump->i387);
+}
+EXPORT_SYMBOL(dump_thread);
+
+/* 
+ * Capture the user space registers if the task is not running (in user space)
+ */
+int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
+{
+	struct pt_regs ptregs = *task_pt_regs(tsk);
+	ptregs.xcs &= 0xffff;
+	ptregs.xds &= 0xffff;
+	ptregs.xes &= 0xffff;
+	ptregs.xss &= 0xffff;
+
+	elf_core_copy_regs(regs, &ptregs);
+
+	return 1;
+}
+
+#ifdef CONFIG_SECCOMP
+void hard_disable_TSC(void)
+{
+	write_cr4(read_cr4() | X86_CR4_TSD);
+}
+void disable_TSC(void)
+{
+	preempt_disable();
+	if (!test_and_set_thread_flag(TIF_NOTSC))
+		/*
+		 * Must flip the CPU state synchronously with
+		 * TIF_NOTSC in the current running context.
+		 */
+		hard_disable_TSC();
+	preempt_enable();
+}
+void hard_enable_TSC(void)
+{
+	write_cr4(read_cr4() & ~X86_CR4_TSD);
+}
+#endif /* CONFIG_SECCOMP */
+
+static noinline void
+__switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
+		 struct tss_struct *tss)
+{
+	struct thread_struct *next;
+
+	next = &next_p->thread;
+
+	if (test_tsk_thread_flag(next_p, TIF_DEBUG)) {
+		set_debugreg(next->debugreg[0], 0);
+		set_debugreg(next->debugreg[1], 1);
+		set_debugreg(next->debugreg[2], 2);
+		set_debugreg(next->debugreg[3], 3);
+		/* no 4 and 5 */
+		set_debugreg(next->debugreg[6], 6);
+		set_debugreg(next->debugreg[7], 7);
+	}
+
+#ifdef CONFIG_SECCOMP
+	if (test_tsk_thread_flag(prev_p, TIF_NOTSC) ^
+	    test_tsk_thread_flag(next_p, TIF_NOTSC)) {
+		/* prev and next are different */
+		if (test_tsk_thread_flag(next_p, TIF_NOTSC))
+			hard_disable_TSC();
+		else
+			hard_enable_TSC();
+	}
+#endif
+
+	if (!test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) {
+		/*
+		 * Disable the bitmap via an invalid offset. We still cache
+		 * the previous bitmap owner and the IO bitmap contents:
+		 */
+		tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
+		return;
+	}
+
+	if (likely(next == tss->io_bitmap_owner)) {
+		/*
+		 * Previous owner of the bitmap (hence the bitmap content)
+		 * matches the next task, we dont have to do anything but
+		 * to set a valid offset in the TSS:
+		 */
+		tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET;
+		return;
+	}
+	/*
+	 * Lazy TSS's I/O bitmap copy. We set an invalid offset here
+	 * and we let the task to get a GPF in case an I/O instruction
+	 * is performed.  The handler of the GPF will verify that the
+	 * faulting task has a valid I/O bitmap and, it true, does the
+	 * real copy and restart the instruction.  This will save us
+	 * redundant copies when the currently switched task does not
+	 * perform any I/O during its timeslice.
+	 */
+	tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY;
+}
+
+/*
+ *	switch_to(x,yn) should switch tasks from x to y.
+ *
+ * We fsave/fwait so that an exception goes off at the right time
+ * (as a call from the fsave or fwait in effect) rather than to
+ * the wrong process. Lazy FP saving no longer makes any sense
+ * with modern CPU's, and this simplifies a lot of things (SMP
+ * and UP become the same).
+ *
+ * NOTE! We used to use the x86 hardware context switching. The
+ * reason for not using it any more becomes apparent when you
+ * try to recover gracefully from saved state that is no longer
+ * valid (stale segment register values in particular). With the
+ * hardware task-switch, there is no way to fix up bad state in
+ * a reasonable manner.
+ *
+ * The fact that Intel documents the hardware task-switching to
+ * be slow is a fairly red herring - this code is not noticeably
+ * faster. However, there _is_ some room for improvement here,
+ * so the performance issues may eventually be a valid point.
+ * More important, however, is the fact that this allows us much
+ * more flexibility.
+ *
+ * The return value (in %eax) will be the "prev" task after
+ * the task-switch, and shows up in ret_from_fork in entry.S,
+ * for example.
+ */
+struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
+{
+	struct thread_struct *prev = &prev_p->thread,
+				 *next = &next_p->thread;
+	int cpu = smp_processor_id();
+	struct tss_struct *tss = &per_cpu(init_tss, cpu);
+
+	/* never put a printk in __switch_to... printk() calls wake_up*() indirectly */
+
+	__unlazy_fpu(prev_p);
+
+
+	/* we're going to use this soon, after a few expensive things */
+	if (next_p->fpu_counter > 5)
+		prefetch(&next->i387.fxsave);
+
+	/*
+	 * Reload esp0.
+	 */
+	load_esp0(tss, next);
+
+	/*
+	 * Save away %gs. No need to save %fs, as it was saved on the
+	 * stack on entry.  No need to save %es and %ds, as those are
+	 * always kernel segments while inside the kernel.  Doing this
+	 * before setting the new TLS descriptors avoids the situation
+	 * where we temporarily have non-reloadable segments in %fs
+	 * and %gs.  This could be an issue if the NMI handler ever
+	 * used %fs or %gs (it does not today), or if the kernel is
+	 * running inside of a hypervisor layer.
+	 */
+	savesegment(gs, prev->gs);
+
+	/*
+	 * Load the per-thread Thread-Local Storage descriptor.
+	 */
+	load_TLS(next, cpu);
+
+	/*
+	 * Restore IOPL if needed.  In normal use, the flags restore
+	 * in the switch assembly will handle this.  But if the kernel
+	 * is running virtualized at a non-zero CPL, the popf will
+	 * not restore flags, so it must be done in a separate step.
+	 */
+	if (get_kernel_rpl() && unlikely(prev->iopl != next->iopl))
+		set_iopl_mask(next->iopl);
+
+	/*
+	 * Now maybe handle debug registers and/or IO bitmaps
+	 */
+	if (unlikely(task_thread_info(prev_p)->flags & _TIF_WORK_CTXSW_PREV ||
+		     task_thread_info(next_p)->flags & _TIF_WORK_CTXSW_NEXT))
+		__switch_to_xtra(prev_p, next_p, tss);
+
+	/*
+	 * Leave lazy mode, flushing any hypercalls made here.
+	 * This must be done before restoring TLS segments so
+	 * the GDT and LDT are properly updated, and must be
+	 * done before math_state_restore, so the TS bit is up
+	 * to date.
+	 */
+	arch_leave_lazy_cpu_mode();
+
+	/* If the task has used fpu the last 5 timeslices, just do a full
+	 * restore of the math state immediately to avoid the trap; the
+	 * chances of needing FPU soon are obviously high now
+	 */
+	if (next_p->fpu_counter > 5)
+		math_state_restore();
+
+	/*
+	 * Restore %gs if needed (which is common)
+	 */
+	if (prev->gs | next->gs)
+		loadsegment(gs, next->gs);
+
+	x86_write_percpu(current_task, next_p);
+
+	return prev_p;
+}
+
+asmlinkage int sys_fork(struct pt_regs regs)
+{
+	return do_fork(SIGCHLD, regs.esp, &regs, 0, NULL, NULL);
+}
+
+asmlinkage int sys_clone(struct pt_regs regs)
+{
+	unsigned long clone_flags;
+	unsigned long newsp;
+	int __user *parent_tidptr, *child_tidptr;
+
+	clone_flags = regs.ebx;
+	newsp = regs.ecx;
+	parent_tidptr = (int __user *)regs.edx;
+	child_tidptr = (int __user *)regs.edi;
+	if (!newsp)
+		newsp = regs.esp;
+	return do_fork(clone_flags, newsp, &regs, 0, parent_tidptr, child_tidptr);
+}
+
+/*
+ * This is trivial, and on the face of it looks like it
+ * could equally well be done in user mode.
+ *
+ * Not so, for quite unobvious reasons - register pressure.
+ * In user mode vfork() cannot have a stack frame, and if
+ * done by calling the "clone()" system call directly, you
+ * do not have enough call-clobbered registers to hold all
+ * the information you need.
+ */
+asmlinkage int sys_vfork(struct pt_regs regs)
+{
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, &regs, 0, NULL, NULL);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(struct pt_regs regs)
+{
+	int error;
+	char * filename;
+
+	filename = getname((char __user *) regs.ebx);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
+		goto out;
+	error = do_execve(filename,
+			(char __user * __user *) regs.ecx,
+			(char __user * __user *) regs.edx,
+			&regs);
+	if (error == 0) {
+		task_lock(current);
+		current->ptrace &= ~PT_DTRACE;
+		task_unlock(current);
+		/* Make sure we don't return using sysenter.. */
+		set_thread_flag(TIF_IRET);
+	}
+	putname(filename);
+out:
+	return error;
+}
+
+#define top_esp                (THREAD_SIZE - sizeof(unsigned long))
+#define top_ebp                (THREAD_SIZE - 2*sizeof(unsigned long))
+
+unsigned long get_wchan(struct task_struct *p)
+{
+	unsigned long ebp, esp, eip;
+	unsigned long stack_page;
+	int count = 0;
+	if (!p || p == current || p->state == TASK_RUNNING)
+		return 0;
+	stack_page = (unsigned long)task_stack_page(p);
+	esp = p->thread.esp;
+	if (!stack_page || esp < stack_page || esp > top_esp+stack_page)
+		return 0;
+	/* include/asm-i386/system.h:switch_to() pushes ebp last. */
+	ebp = *(unsigned long *) esp;
+	do {
+		if (ebp < stack_page || ebp > top_ebp+stack_page)
+			return 0;
+		eip = *(unsigned long *) (ebp+4);
+		if (!in_sched_functions(eip))
+			return eip;
+		ebp = *(unsigned long *) ebp;
+	} while (count++ < 16);
+	return 0;
+}
+
+/*
+ * sys_alloc_thread_area: get a yet unused TLS descriptor index.
+ */
+static int get_free_idx(void)
+{
+	struct thread_struct *t = &current->thread;
+	int idx;
+
+	for (idx = 0; idx < GDT_ENTRY_TLS_ENTRIES; idx++)
+		if (desc_empty(t->tls_array + idx))
+			return idx + GDT_ENTRY_TLS_MIN;
+	return -ESRCH;
+}
+
+/*
+ * Set a given TLS descriptor:
+ */
+asmlinkage int sys_set_thread_area(struct user_desc __user *u_info)
+{
+	struct thread_struct *t = &current->thread;
+	struct user_desc info;
+	struct desc_struct *desc;
+	int cpu, idx;
+
+	if (copy_from_user(&info, u_info, sizeof(info)))
+		return -EFAULT;
+	idx = info.entry_number;
+
+	/*
+	 * index -1 means the kernel should try to find and
+	 * allocate an empty descriptor:
+	 */
+	if (idx == -1) {
+		idx = get_free_idx();
+		if (idx < 0)
+			return idx;
+		if (put_user(idx, &u_info->entry_number))
+			return -EFAULT;
+	}
+
+	if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
+		return -EINVAL;
+
+	desc = t->tls_array + idx - GDT_ENTRY_TLS_MIN;
+
+	/*
+	 * We must not get preempted while modifying the TLS.
+	 */
+	cpu = get_cpu();
+
+	if (LDT_empty(&info)) {
+		desc->a = 0;
+		desc->b = 0;
+	} else {
+		desc->a = LDT_entry_a(&info);
+		desc->b = LDT_entry_b(&info);
+	}
+	load_TLS(t, cpu);
+
+	put_cpu();
+
+	return 0;
+}
+
+/*
+ * Get the current Thread-Local Storage area:
+ */
+
+#define GET_BASE(desc) ( \
+	(((desc)->a >> 16) & 0x0000ffff) | \
+	(((desc)->b << 16) & 0x00ff0000) | \
+	( (desc)->b        & 0xff000000)   )
+
+#define GET_LIMIT(desc) ( \
+	((desc)->a & 0x0ffff) | \
+	 ((desc)->b & 0xf0000) )
+	
+#define GET_32BIT(desc)		(((desc)->b >> 22) & 1)
+#define GET_CONTENTS(desc)	(((desc)->b >> 10) & 3)
+#define GET_WRITABLE(desc)	(((desc)->b >>  9) & 1)
+#define GET_LIMIT_PAGES(desc)	(((desc)->b >> 23) & 1)
+#define GET_PRESENT(desc)	(((desc)->b >> 15) & 1)
+#define GET_USEABLE(desc)	(((desc)->b >> 20) & 1)
+
+asmlinkage int sys_get_thread_area(struct user_desc __user *u_info)
+{
+	struct user_desc info;
+	struct desc_struct *desc;
+	int idx;
+
+	if (get_user(idx, &u_info->entry_number))
+		return -EFAULT;
+	if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX)
+		return -EINVAL;
+
+	memset(&info, 0, sizeof(info));
+
+	desc = current->thread.tls_array + idx - GDT_ENTRY_TLS_MIN;
+
+	info.entry_number = idx;
+	info.base_addr = GET_BASE(desc);
+	info.limit = GET_LIMIT(desc);
+	info.seg_32bit = GET_32BIT(desc);
+	info.contents = GET_CONTENTS(desc);
+	info.read_exec_only = !GET_WRITABLE(desc);
+	info.limit_in_pages = GET_LIMIT_PAGES(desc);
+	info.seg_not_present = !GET_PRESENT(desc);
+	info.useable = GET_USEABLE(desc);
+
+	if (copy_to_user(u_info, &info, sizeof(info)))
+		return -EFAULT;
+	return 0;
+}
+
+unsigned long arch_align_stack(unsigned long sp)
+{
+	if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
+		sp -= get_random_int() % 8192;
+	return sp & ~0xf;
+}
diff -Nurb linux-2.6.24.3/arch/x86/kernel/reboot_32.c linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/reboot_32.c
--- linux-2.6.24.3/arch/x86/kernel/reboot_32.c	2008-02-25 16:20:20.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/reboot_32.c	2008-03-02 14:55:48.000000000 -0800
@@ -17,6 +17,11 @@
 #include <asm/reboot_fixups.h>
 #include <asm/reboot.h>
 
+#ifdef CONFIG_COBALT_RAQ
+#include <cobalt/misc.h>
+#include <cobalt/lcd.h>
+#endif
+
 /*
  * Power off function, if any
  */
@@ -297,7 +302,13 @@
 {
 #ifdef CONFIG_SMP
 	int reboot_cpu_id;
-
+#endif
+#ifdef CONFIG_COBALT_RAQ
+	wait_for_flush();
+	//cobalt_halt();
+	cobalt_lcd_print("It is now safe", "to remove power");
+#endif
+#ifdef CONFIG_SMP
 	/* The boot cpu is always logical cpu 0 */
 	reboot_cpu_id = 0;
 
@@ -338,6 +349,9 @@
 
 static void native_machine_emergency_restart(void)
 {
+#ifdef CONFIG_COBALT_RAQ
+	cobalt_restart();
+#endif
 	if (!reboot_thru_bios) {
 		if (efi_enabled) {
 			efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, NULL);
@@ -360,8 +374,35 @@
 	machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
 }
 
+/* kill some time at halt/reboot to allow drives with large cache to sync */
+void wait_for_flush(void)
+{
+      int i;
+      static int flushed;
+
+      if (flushed)
+              return;
+      flushed = 1;
+
+      printk("waiting for devices to flush");
+      for (i = 0 ; i < 10; i++) {
+              printk(".");
+              mdelay(500);
+#ifdef CONFIG_COBALT_LCD
+              if (i == 8)
+                      cobalt_lcd_off();
+#endif
+      }
+      printk("done\n");
+}
+
 static void native_machine_restart(char * __unused)
 {
+#ifdef CONFIG_COBALT_RAQ
+      wait_for_flush();
+      cobalt_restart();
+#endif
+
 	machine_shutdown();
 	machine_emergency_restart();
 }
diff -Nurb linux-2.6.24.3/arch/x86/kernel/reboot_32.c.orig linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/reboot_32.c.orig
--- linux-2.6.24.3/arch/x86/kernel/reboot_32.c.orig	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/reboot_32.c.orig	2008-02-25 16:20:20.000000000 -0800
@@ -0,0 +1,413 @@
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/mc146818rtc.h>
+#include <linux/efi.h>
+#include <linux/dmi.h>
+#include <linux/ctype.h>
+#include <linux/pm.h>
+#include <linux/reboot.h>
+#include <asm/uaccess.h>
+#include <asm/apic.h>
+#include <asm/hpet.h>
+#include <asm/desc.h>
+#include "mach_reboot.h"
+#include <asm/reboot_fixups.h>
+#include <asm/reboot.h>
+
+/*
+ * Power off function, if any
+ */
+void (*pm_power_off)(void);
+EXPORT_SYMBOL(pm_power_off);
+
+static int reboot_mode;
+static int reboot_thru_bios;
+
+#ifdef CONFIG_SMP
+static int reboot_cpu = -1;
+#endif
+static int __init reboot_setup(char *str)
+{
+	while(1) {
+		switch (*str) {
+		case 'w': /* "warm" reboot (no memory testing etc) */
+			reboot_mode = 0x1234;
+			break;
+		case 'c': /* "cold" reboot (with memory testing etc) */
+			reboot_mode = 0x0;
+			break;
+		case 'b': /* "bios" reboot by jumping through the BIOS */
+			reboot_thru_bios = 1;
+			break;
+		case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */
+			reboot_thru_bios = 0;
+			break;
+#ifdef CONFIG_SMP
+		case 's': /* "smp" reboot by executing reset on BSP or other CPU*/
+			if (isdigit(*(str+1))) {
+				reboot_cpu = (int) (*(str+1) - '0');
+				if (isdigit(*(str+2)))
+					reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
+			}
+				/* we will leave sorting out the final value 
+				when we are ready to reboot, since we might not
+ 				have set up boot_cpu_id or smp_num_cpu */
+			break;
+#endif
+		}
+		if((str = strchr(str,',')) != NULL)
+			str++;
+		else
+			break;
+	}
+	return 1;
+}
+
+__setup("reboot=", reboot_setup);
+
+/*
+ * Reboot options and system auto-detection code provided by
+ * Dell Inc. so their systems "just work". :-)
+ */
+
+/*
+ * Some machines require the "reboot=b"  commandline option, this quirk makes that automatic.
+ */
+static int __init set_bios_reboot(const struct dmi_system_id *d)
+{
+	if (!reboot_thru_bios) {
+		reboot_thru_bios = 1;
+		printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident);
+	}
+	return 0;
+}
+
+static struct dmi_system_id __initdata reboot_dmi_table[] = {
+	{	/* Handle problems with rebooting on Dell E520's */
+		.callback = set_bios_reboot,
+		.ident = "Dell E520",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"),
+		},
+	},
+	{	/* Handle problems with rebooting on Dell 1300's */
+		.callback = set_bios_reboot,
+		.ident = "Dell PowerEdge 1300",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
+		},
+	},
+	{	/* Handle problems with rebooting on Dell 300's */
+		.callback = set_bios_reboot,
+		.ident = "Dell PowerEdge 300",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
+		},
+	},
+	{       /* Handle problems with rebooting on Dell Optiplex 745's SFF*/
+		.callback = set_bios_reboot,
+		.ident = "Dell OptiPlex 745",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+			DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
+			DMI_MATCH(DMI_BOARD_NAME, "0WF810"),
+		},
+	},
+	{	/* Handle problems with rebooting on Dell 2400's */
+		.callback = set_bios_reboot,
+		.ident = "Dell PowerEdge 2400",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
+		},
+	},
+	{	/* Handle problems with rebooting on HP laptops */
+		.callback = set_bios_reboot,
+		.ident = "HP Compaq Laptop",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"),
+		},
+	},
+	{ }
+};
+
+static int __init reboot_init(void)
+{
+	dmi_check_system(reboot_dmi_table);
+	return 0;
+}
+
+core_initcall(reboot_init);
+
+/* The following code and data reboots the machine by switching to real
+   mode and jumping to the BIOS reset entry point, as if the CPU has
+   really been reset.  The previous version asked the keyboard
+   controller to pulse the CPU reset line, which is more thorough, but
+   doesn't work with at least one type of 486 motherboard.  It is easy
+   to stop this code working; hence the copious comments. */
+
+static unsigned long long
+real_mode_gdt_entries [3] =
+{
+	0x0000000000000000ULL,	/* Null descriptor */
+	0x00009a000000ffffULL,	/* 16-bit real-mode 64k code at 0x00000000 */
+	0x000092000100ffffULL	/* 16-bit real-mode 64k data at 0x00000100 */
+};
+
+static struct Xgt_desc_struct
+real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)real_mode_gdt_entries },
+real_mode_idt = { 0x3ff, 0 },
+no_idt = { 0, 0 };
+
+
+/* This is 16-bit protected mode code to disable paging and the cache,
+   switch to real mode and jump to the BIOS reset code.
+
+   The instruction that switches to real mode by writing to CR0 must be
+   followed immediately by a far jump instruction, which set CS to a
+   valid value for real mode, and flushes the prefetch queue to avoid
+   running instructions that have already been decoded in protected
+   mode.
+
+   Clears all the flags except ET, especially PG (paging), PE
+   (protected-mode enable) and TS (task switch for coprocessor state
+   save).  Flushes the TLB after paging has been disabled.  Sets CD and
+   NW, to disable the cache on a 486, and invalidates the cache.  This
+   is more like the state of a 486 after reset.  I don't know if
+   something else should be done for other chips.
+
+   More could be done here to set up the registers as if a CPU reset had
+   occurred; hopefully real BIOSs don't assume much. */
+
+static unsigned char real_mode_switch [] =
+{
+	0x66, 0x0f, 0x20, 0xc0,			/*    movl  %cr0,%eax        */
+	0x66, 0x83, 0xe0, 0x11,			/*    andl  $0x00000011,%eax */
+	0x66, 0x0d, 0x00, 0x00, 0x00, 0x60,	/*    orl   $0x60000000,%eax */
+	0x66, 0x0f, 0x22, 0xc0,			/*    movl  %eax,%cr0        */
+	0x66, 0x0f, 0x22, 0xd8,			/*    movl  %eax,%cr3        */
+	0x66, 0x0f, 0x20, 0xc3,			/*    movl  %cr0,%ebx        */
+	0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60,	/*    andl  $0x60000000,%ebx */
+	0x74, 0x02,				/*    jz    f                */
+	0x0f, 0x09,				/*    wbinvd                 */
+	0x24, 0x10,				/* f: andb  $0x10,al         */
+	0x66, 0x0f, 0x22, 0xc0			/*    movl  %eax,%cr0        */
+};
+static unsigned char jump_to_bios [] =
+{
+	0xea, 0x00, 0x00, 0xff, 0xff		/*    ljmp  $0xffff,$0x0000  */
+};
+
+/*
+ * Switch to real mode and then execute the code
+ * specified by the code and length parameters.
+ * We assume that length will aways be less that 100!
+ */
+void machine_real_restart(unsigned char *code, int length)
+{
+	local_irq_disable();
+
+	/* Write zero to CMOS register number 0x0f, which the BIOS POST
+	   routine will recognize as telling it to do a proper reboot.  (Well
+	   that's what this book in front of me says -- it may only apply to
+	   the Phoenix BIOS though, it's not clear).  At the same time,
+	   disable NMIs by setting the top bit in the CMOS address register,
+	   as we're about to do peculiar things to the CPU.  I'm not sure if
+	   `outb_p' is needed instead of just `outb'.  Use it to be on the
+	   safe side.  (Yes, CMOS_WRITE does outb_p's. -  Paul G.)
+	 */
+
+	spin_lock(&rtc_lock);
+	CMOS_WRITE(0x00, 0x8f);
+	spin_unlock(&rtc_lock);
+
+	/* Remap the kernel at virtual address zero, as well as offset zero
+	   from the kernel segment.  This assumes the kernel segment starts at
+	   virtual address PAGE_OFFSET. */
+
+	memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
+		sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
+
+	/*
+	 * Use `swapper_pg_dir' as our page directory.
+	 */
+	load_cr3(swapper_pg_dir);
+
+	/* Write 0x1234 to absolute memory location 0x472.  The BIOS reads
+	   this on booting to tell it to "Bypass memory test (also warm
+	   boot)".  This seems like a fairly standard thing that gets set by
+	   REBOOT.COM programs, and the previous reset routine did this
+	   too. */
+
+	*((unsigned short *)0x472) = reboot_mode;
+
+	/* For the switch to real mode, copy some code to low memory.  It has
+	   to be in the first 64k because it is running in 16-bit mode, and it
+	   has to have the same physical and virtual address, because it turns
+	   off paging.  Copy it near the end of the first page, out of the way
+	   of BIOS variables. */
+
+	memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100),
+		real_mode_switch, sizeof (real_mode_switch));
+	memcpy ((void *) (0x1000 - 100), code, length);
+
+	/* Set up the IDT for real mode. */
+
+	load_idt(&real_mode_idt);
+
+	/* Set up a GDT from which we can load segment descriptors for real
+	   mode.  The GDT is not used in real mode; it is just needed here to
+	   prepare the descriptors. */
+
+	load_gdt(&real_mode_gdt);
+
+	/* Load the data segment registers, and thus the descriptors ready for
+	   real mode.  The base address of each segment is 0x100, 16 times the
+	   selector value being loaded here.  This is so that the segment
+	   registers don't have to be reloaded after switching to real mode:
+	   the values are consistent for real mode operation already. */
+
+	__asm__ __volatile__ ("movl $0x0010,%%eax\n"
+				"\tmovl %%eax,%%ds\n"
+				"\tmovl %%eax,%%es\n"
+				"\tmovl %%eax,%%fs\n"
+				"\tmovl %%eax,%%gs\n"
+				"\tmovl %%eax,%%ss" : : : "eax");
+
+	/* Jump to the 16-bit code that we copied earlier.  It disables paging
+	   and the cache, switches to real mode, and jumps to the BIOS reset
+	   entry point. */
+
+	__asm__ __volatile__ ("ljmp $0x0008,%0"
+				:
+				: "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100)));
+}
+#ifdef CONFIG_APM_MODULE
+EXPORT_SYMBOL(machine_real_restart);
+#endif
+
+static void native_machine_shutdown(void)
+{
+#ifdef CONFIG_SMP
+	int reboot_cpu_id;
+
+	/* The boot cpu is always logical cpu 0 */
+	reboot_cpu_id = 0;
+
+	/* See if there has been given a command line override */
+	if ((reboot_cpu != -1) && (reboot_cpu < NR_CPUS) &&
+		cpu_isset(reboot_cpu, cpu_online_map)) {
+		reboot_cpu_id = reboot_cpu;
+	}
+
+	/* Make certain the cpu I'm rebooting on is online */
+	if (!cpu_isset(reboot_cpu_id, cpu_online_map)) {
+		reboot_cpu_id = smp_processor_id();
+	}
+
+	/* Make certain I only run on the appropriate processor */
+	set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id));
+
+	/* O.K. Now that I'm on the appropriate processor, stop
+	 * all of the others, and disable their local APICs.
+	 */
+
+	smp_send_stop();
+#endif /* CONFIG_SMP */
+
+	lapic_shutdown();
+
+#ifdef CONFIG_X86_IO_APIC
+	disable_IO_APIC();
+#endif
+#ifdef CONFIG_HPET_TIMER
+	hpet_disable();
+#endif
+}
+
+void __attribute__((weak)) mach_reboot_fixups(void)
+{
+}
+
+static void native_machine_emergency_restart(void)
+{
+	if (!reboot_thru_bios) {
+		if (efi_enabled) {
+			efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, NULL);
+			load_idt(&no_idt);
+			__asm__ __volatile__("int3");
+		}
+		/* rebooting needs to touch the page at absolute addr 0 */
+		*((unsigned short *)__va(0x472)) = reboot_mode;
+		for (;;) {
+			mach_reboot_fixups(); /* for board specific fixups */
+			mach_reboot();
+			/* That didn't work - force a triple fault.. */
+			load_idt(&no_idt);
+			__asm__ __volatile__("int3");
+		}
+	}
+	if (efi_enabled)
+		efi.reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL);
+
+	machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
+}
+
+static void native_machine_restart(char * __unused)
+{
+	machine_shutdown();
+	machine_emergency_restart();
+}
+
+static void native_machine_halt(void)
+{
+}
+
+static void native_machine_power_off(void)
+{
+	if (pm_power_off) {
+		machine_shutdown();
+		pm_power_off();
+	}
+}
+
+
+struct machine_ops machine_ops = {
+	.power_off = native_machine_power_off,
+	.shutdown = native_machine_shutdown,
+	.emergency_restart = native_machine_emergency_restart,
+	.restart = native_machine_restart,
+	.halt = native_machine_halt,
+};
+
+void machine_power_off(void)
+{
+	machine_ops.power_off();
+}
+
+void machine_shutdown(void)
+{
+	machine_ops.shutdown();
+}
+
+void machine_emergency_restart(void)
+{
+	machine_ops.emergency_restart();
+}
+
+void machine_restart(char *cmd)
+{
+	machine_ops.restart(cmd);
+}
+
+void machine_halt(void)
+{
+	machine_ops.halt();
+}
diff -Nurb linux-2.6.24.3/arch/x86/kernel/traps_32.c linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/traps_32.c
--- linux-2.6.24.3/arch/x86/kernel/traps_32.c	2008-02-25 16:20:20.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/traps_32.c	2008-03-02 14:55:48.000000000 -0800
@@ -66,6 +66,10 @@
 DECLARE_BITMAP(used_vectors, NR_VECTORS);
 EXPORT_SYMBOL_GPL(used_vectors);
 
+#ifdef CONFIG_COBALT_RAQ
+#include <cobalt/misc.h>
+#endif
+
 asmlinkage int system_call(void);
 
 /* Do we ignore FPU interrupts ? */
@@ -633,9 +637,13 @@
 static __kprobes void
 mem_parity_error(unsigned char reason, struct pt_regs * regs)
 {
+#ifdef CONFIG_COBALT_RAQ
+	cobalt_nmi(reason, regs);
+#else
 	printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on "
 		"CPU %d.\n", reason, smp_processor_id());
 	printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n");
+#endif
 
 #if defined(CONFIG_EDAC)
 	if(edac_handler_set()) {
diff -Nurb linux-2.6.24.3/arch/x86/kernel/traps_32.c.orig linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/traps_32.c.orig
--- linux-2.6.24.3/arch/x86/kernel/traps_32.c.orig	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/arch/x86/kernel/traps_32.c.orig	2008-02-25 16:20:20.000000000 -0800
@@ -0,0 +1,1224 @@
+/*
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Pentium III FXSR, SSE support
+ *	Gareth Hughes <gareth@valinux.com>, May 2000
+ */
+
+/*
+ * 'Traps.c' handles hardware traps and faults after we have saved some
+ * state in 'asm.s'.
+ */
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/highmem.h>
+#include <linux/kallsyms.h>
+#include <linux/ptrace.h>
+#include <linux/utsname.h>
+#include <linux/kprobes.h>
+#include <linux/kexec.h>
+#include <linux/unwind.h>
+#include <linux/uaccess.h>
+#include <linux/nmi.h>
+#include <linux/bug.h>
+
+#ifdef CONFIG_EISA
+#include <linux/ioport.h>
+#include <linux/eisa.h>
+#endif
+
+#ifdef CONFIG_MCA
+#include <linux/mca.h>
+#endif
+
+#if defined(CONFIG_EDAC)
+#include <linux/edac.h>
+#endif
+
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/debugreg.h>
+#include <asm/desc.h>
+#include <asm/i387.h>
+#include <asm/nmi.h>
+#include <asm/unwind.h>
+#include <asm/smp.h>
+#include <asm/arch_hooks.h>
+#include <linux/kdebug.h>
+#include <asm/stacktrace.h>
+
+#include <linux/module.h>
+
+#include "mach_traps.h"
+
+int panic_on_unrecovered_nmi;
+
+DECLARE_BITMAP(used_vectors, NR_VECTORS);
+EXPORT_SYMBOL_GPL(used_vectors);
+
+asmlinkage int system_call(void);
+
+/* Do we ignore FPU interrupts ? */
+char ignore_fpu_irq = 0;
+
+/*
+ * The IDT has to be page-aligned to simplify the Pentium
+ * F0 0F bug workaround.. We have a special link segment
+ * for this.
+ */
+struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, };
+
+asmlinkage void divide_error(void);
+asmlinkage void debug(void);
+asmlinkage void nmi(void);
+asmlinkage void int3(void);
+asmlinkage void overflow(void);
+asmlinkage void bounds(void);
+asmlinkage void invalid_op(void);
+asmlinkage void device_not_available(void);
+asmlinkage void coprocessor_segment_overrun(void);
+asmlinkage void invalid_TSS(void);
+asmlinkage void segment_not_present(void);
+asmlinkage void stack_segment(void);
+asmlinkage void general_protection(void);
+asmlinkage void page_fault(void);
+asmlinkage void coprocessor_error(void);
+asmlinkage void simd_coprocessor_error(void);
+asmlinkage void alignment_check(void);
+asmlinkage void spurious_interrupt_bug(void);
+asmlinkage void machine_check(void);
+
+int kstack_depth_to_print = 24;
+static unsigned int code_bytes = 64;
+
+static inline int valid_stack_ptr(struct thread_info *tinfo, void *p, unsigned size)
+{
+	return	p > (void *)tinfo &&
+		p <= (void *)tinfo + THREAD_SIZE - size;
+}
+
+/* The form of the top of the frame on the stack */
+struct stack_frame {
+	struct stack_frame *next_frame;
+	unsigned long return_address;
+};
+
+static inline unsigned long print_context_stack(struct thread_info *tinfo,
+				unsigned long *stack, unsigned long ebp,
+				const struct stacktrace_ops *ops, void *data)
+{
+#ifdef	CONFIG_FRAME_POINTER
+	struct stack_frame *frame = (struct stack_frame *)ebp;
+	while (valid_stack_ptr(tinfo, frame, sizeof(*frame))) {
+		struct stack_frame *next;
+		unsigned long addr;
+
+		addr = frame->return_address;
+		ops->address(data, addr);
+		/*
+		 * break out of recursive entries (such as
+		 * end_of_stack_stop_unwind_function). Also,
+		 * we can never allow a frame pointer to
+		 * move downwards!
+		 */
+		next = frame->next_frame;
+		if (next <= frame)
+			break;
+		frame = next;
+	}
+#else
+	while (valid_stack_ptr(tinfo, stack, sizeof(*stack))) {
+		unsigned long addr;
+
+		addr = *stack++;
+		if (__kernel_text_address(addr))
+			ops->address(data, addr);
+	}
+#endif
+	return ebp;
+}
+
+#define MSG(msg) ops->warning(data, msg)
+
+void dump_trace(struct task_struct *task, struct pt_regs *regs,
+	        unsigned long *stack,
+		const struct stacktrace_ops *ops, void *data)
+{
+	unsigned long ebp = 0;
+
+	if (!task)
+		task = current;
+
+	if (!stack) {
+		unsigned long dummy;
+		stack = &dummy;
+		if (task != current)
+			stack = (unsigned long *)task->thread.esp;
+	}
+
+#ifdef CONFIG_FRAME_POINTER
+	if (!ebp) {
+		if (task == current) {
+			/* Grab ebp right from our regs */
+			asm ("movl %%ebp, %0" : "=r" (ebp) : );
+		} else {
+			/* ebp is the last reg pushed by switch_to */
+			ebp = *(unsigned long *) task->thread.esp;
+		}
+	}
+#endif
+
+	while (1) {
+		struct thread_info *context;
+		context = (struct thread_info *)
+			((unsigned long)stack & (~(THREAD_SIZE - 1)));
+		ebp = print_context_stack(context, stack, ebp, ops, data);
+		/* Should be after the line below, but somewhere
+		   in early boot context comes out corrupted and we
+		   can't reference it -AK */
+		if (ops->stack(data, "IRQ") < 0)
+			break;
+		stack = (unsigned long*)context->previous_esp;
+		if (!stack)
+			break;
+		touch_nmi_watchdog();
+	}
+}
+EXPORT_SYMBOL(dump_trace);
+
+static void
+print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
+{
+	printk(data);
+	print_symbol(msg, symbol);
+	printk("\n");
+}
+
+static void print_trace_warning(void *data, char *msg)
+{
+	printk("%s%s\n", (char *)data, msg);
+}
+
+static int print_trace_stack(void *data, char *name)
+{
+	return 0;
+}
+
+/*
+ * Print one address/symbol entries per line.
+ */
+static void print_trace_address(void *data, unsigned long addr)
+{
+	printk("%s [<%08lx>] ", (char *)data, addr);
+	print_symbol("%s\n", addr);
+	touch_nmi_watchdog();
+}
+
+static const struct stacktrace_ops print_trace_ops = {
+	.warning = print_trace_warning,
+	.warning_symbol = print_trace_warning_symbol,
+	.stack = print_trace_stack,
+	.address = print_trace_address,
+};
+
+static void
+show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
+		   unsigned long * stack, char *log_lvl)
+{
+	dump_trace(task, regs, stack, &print_trace_ops, log_lvl);
+	printk("%s =======================\n", log_lvl);
+}
+
+void show_trace(struct task_struct *task, struct pt_regs *regs,
+		unsigned long * stack)
+{
+	show_trace_log_lvl(task, regs, stack, "");
+}
+
+static void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
+			       unsigned long *esp, char *log_lvl)
+{
+	unsigned long *stack;
+	int i;
+
+	if (esp == NULL) {
+		if (task)
+			esp = (unsigned long*)task->thread.esp;
+		else
+			esp = (unsigned long *)&esp;
+	}
+
+	stack = esp;
+	for(i = 0; i < kstack_depth_to_print; i++) {
+		if (kstack_end(stack))
+			break;
+		if (i && ((i % 8) == 0))
+			printk("\n%s       ", log_lvl);
+		printk("%08lx ", *stack++);
+	}
+	printk("\n%sCall Trace:\n", log_lvl);
+	show_trace_log_lvl(task, regs, esp, log_lvl);
+}
+
+void show_stack(struct task_struct *task, unsigned long *esp)
+{
+	printk("       ");
+	show_stack_log_lvl(task, NULL, esp, "");
+}
+
+/*
+ * The architecture-independent dump_stack generator
+ */
+void dump_stack(void)
+{
+	unsigned long stack;
+
+	printk("Pid: %d, comm: %.20s %s %s %.*s\n",
+		current->pid, current->comm, print_tainted(),
+		init_utsname()->release,
+		(int)strcspn(init_utsname()->version, " "),
+		init_utsname()->version);
+	show_trace(current, NULL, &stack);
+}
+
+EXPORT_SYMBOL(dump_stack);
+
+void show_registers(struct pt_regs *regs)
+{
+	int i;
+
+	print_modules();
+	__show_registers(regs, 0);
+	printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)",
+		TASK_COMM_LEN, current->comm, task_pid_nr(current),
+		current_thread_info(), current, task_thread_info(current));
+	/*
+	 * When in-kernel, we also print out the stack and code at the
+	 * time of the fault..
+	 */
+	if (!user_mode_vm(regs)) {
+		u8 *eip;
+		unsigned int code_prologue = code_bytes * 43 / 64;
+		unsigned int code_len = code_bytes;
+		unsigned char c;
+
+		printk("\n" KERN_EMERG "Stack: ");
+		show_stack_log_lvl(NULL, regs, &regs->esp, KERN_EMERG);
+
+		printk(KERN_EMERG "Code: ");
+
+		eip = (u8 *)regs->eip - code_prologue;
+		if (eip < (u8 *)PAGE_OFFSET ||
+			probe_kernel_address(eip, c)) {
+			/* try starting at EIP */
+			eip = (u8 *)regs->eip;
+			code_len = code_len - code_prologue + 1;
+		}
+		for (i = 0; i < code_len; i++, eip++) {
+			if (eip < (u8 *)PAGE_OFFSET ||
+				probe_kernel_address(eip, c)) {
+				printk(" Bad EIP value.");
+				break;
+			}
+			if (eip == (u8 *)regs->eip)
+				printk("<%02x> ", c);
+			else
+				printk("%02x ", c);
+		}
+	}
+	printk("\n");
+}	
+
+int is_valid_bugaddr(unsigned long eip)
+{
+	unsigned short ud2;
+
+	if (eip < PAGE_OFFSET)
+		return 0;
+	if (probe_kernel_address((unsigned short *)eip, ud2))
+		return 0;
+
+	return ud2 == 0x0b0f;
+}
+
+/*
+ * This is gone through when something in the kernel has done something bad and
+ * is about to be terminated.
+ */
+void die(const char * str, struct pt_regs * regs, long err)
+{
+	static struct {
+		raw_spinlock_t lock;
+		u32 lock_owner;
+		int lock_owner_depth;
+	} die = {
+		.lock =			__RAW_SPIN_LOCK_UNLOCKED,
+		.lock_owner =		-1,
+		.lock_owner_depth =	0
+	};
+	static int die_counter;
+	unsigned long flags;
+
+	oops_enter();
+
+	if (die.lock_owner != raw_smp_processor_id()) {
+		console_verbose();
+		raw_local_irq_save(flags);
+		__raw_spin_lock(&die.lock);
+		die.lock_owner = smp_processor_id();
+		die.lock_owner_depth = 0;
+		bust_spinlocks(1);
+	} else
+		raw_local_irq_save(flags);
+
+	if (++die.lock_owner_depth < 3) {
+		unsigned long esp;
+		unsigned short ss;
+
+		report_bug(regs->eip, regs);
+
+		printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff,
+		       ++die_counter);
+#ifdef CONFIG_PREEMPT
+		printk("PREEMPT ");
+#endif
+#ifdef CONFIG_SMP
+		printk("SMP ");
+#endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+		printk("DEBUG_PAGEALLOC");
+#endif
+		printk("\n");
+
+		if (notify_die(DIE_OOPS, str, regs, err,
+					current->thread.trap_no, SIGSEGV) !=
+				NOTIFY_STOP) {
+			show_registers(regs);
+			/* Executive summary in case the oops scrolled away */
+			esp = (unsigned long) (&regs->esp);
+			savesegment(ss, ss);
+			if (user_mode(regs)) {
+				esp = regs->esp;
+				ss = regs->xss & 0xffff;
+			}
+			printk(KERN_EMERG "EIP: [<%08lx>] ", regs->eip);
+			print_symbol("%s", regs->eip);
+			printk(" SS:ESP %04x:%08lx\n", ss, esp);
+		}
+		else
+			regs = NULL;
+  	} else
+		printk(KERN_EMERG "Recursive die() failure, output suppressed\n");
+
+	bust_spinlocks(0);
+	die.lock_owner = -1;
+	add_taint(TAINT_DIE);
+	__raw_spin_unlock(&die.lock);
+	raw_local_irq_restore(flags);
+
+	if (!regs)
+		return;
+
+	if (kexec_should_crash(current))
+		crash_kexec(regs);
+
+	if (in_interrupt())
+		panic("Fatal exception in interrupt");
+
+	if (panic_on_oops)
+		panic("Fatal exception");
+
+	oops_exit();
+	do_exit(SIGSEGV);
+}
+
+static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
+{
+	if (!user_mode_vm(regs))
+		die(str, regs, err);
+}
+
+static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86,
+			      struct pt_regs * regs, long error_code,
+			      siginfo_t *info)
+{
+	struct task_struct *tsk = current;
+
+	if (regs->eflags & VM_MASK) {
+		if (vm86)
+			goto vm86_trap;
+		goto trap_signal;
+	}
+
+	if (!user_mode(regs))
+		goto kernel_trap;
+
+	trap_signal: {
+		/*
+		 * We want error_code and trap_no set for userspace faults and
+		 * kernelspace faults which result in die(), but not
+		 * kernelspace faults which are fixed up.  die() gives the
+		 * process no chance to handle the signal and notice the
+		 * kernel fault information, so that won't result in polluting
+		 * the information about previously queued, but not yet
+		 * delivered, faults.  See also do_general_protection below.
+		 */
+		tsk->thread.error_code = error_code;
+		tsk->thread.trap_no = trapnr;
+
+		if (info)
+			force_sig_info(signr, info, tsk);
+		else
+			force_sig(signr, tsk);
+		return;
+	}
+
+	kernel_trap: {
+		if (!fixup_exception(regs)) {
+			tsk->thread.error_code = error_code;
+			tsk->thread.trap_no = trapnr;
+			die(str, regs, error_code);
+		}
+		return;
+	}
+
+	vm86_trap: {
+		int ret = handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr);
+		if (ret) goto trap_signal;
+		return;
+	}
+}
+
+#define DO_ERROR(trapnr, signr, str, name) \
+fastcall void do_##name(struct pt_regs * regs, long error_code) \
+{ \
+	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
+						== NOTIFY_STOP) \
+		return; \
+	do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
+}
+
+#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr, irq) \
+fastcall void do_##name(struct pt_regs * regs, long error_code) \
+{ \
+	siginfo_t info; \
+	if (irq) \
+		local_irq_enable(); \
+	info.si_signo = signr; \
+	info.si_errno = 0; \
+	info.si_code = sicode; \
+	info.si_addr = (void __user *)siaddr; \
+	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
+						== NOTIFY_STOP) \
+		return; \
+	do_trap(trapnr, signr, str, 0, regs, error_code, &info); \
+}
+
+#define DO_VM86_ERROR(trapnr, signr, str, name) \
+fastcall void do_##name(struct pt_regs * regs, long error_code) \
+{ \
+	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
+						== NOTIFY_STOP) \
+		return; \
+	do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \
+}
+
+#define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
+fastcall void do_##name(struct pt_regs * regs, long error_code) \
+{ \
+	siginfo_t info; \
+	info.si_signo = signr; \
+	info.si_errno = 0; \
+	info.si_code = sicode; \
+	info.si_addr = (void __user *)siaddr; \
+	trace_hardirqs_fixup(); \
+	if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \
+						== NOTIFY_STOP) \
+		return; \
+	do_trap(trapnr, signr, str, 1, regs, error_code, &info); \
+}
+
+DO_VM86_ERROR_INFO( 0, SIGFPE,  "divide error", divide_error, FPE_INTDIV, regs->eip)
+#ifndef CONFIG_KPROBES
+DO_VM86_ERROR( 3, SIGTRAP, "int3", int3)
+#endif
+DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow)
+DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds)
+DO_ERROR_INFO( 6, SIGILL,  "invalid opcode", invalid_op, ILL_ILLOPN, regs->eip, 0)
+DO_ERROR( 9, SIGFPE,  "coprocessor segment overrun", coprocessor_segment_overrun)
+DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
+DO_ERROR(11, SIGBUS,  "segment not present", segment_not_present)
+DO_ERROR(12, SIGBUS,  "stack segment", stack_segment)
+DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0, 0)
+DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0, 1)
+
+fastcall void __kprobes do_general_protection(struct pt_regs * regs,
+					      long error_code)
+{
+	int cpu = get_cpu();
+	struct tss_struct *tss = &per_cpu(init_tss, cpu);
+	struct thread_struct *thread = &current->thread;
+
+	/*
+	 * Perform the lazy TSS's I/O bitmap copy. If the TSS has an
+	 * invalid offset set (the LAZY one) and the faulting thread has
+	 * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS
+	 * and we set the offset field correctly. Then we let the CPU to
+	 * restart the faulting instruction.
+	 */
+	if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY &&
+	    thread->io_bitmap_ptr) {
+		memcpy(tss->io_bitmap, thread->io_bitmap_ptr,
+		       thread->io_bitmap_max);
+		/*
+		 * If the previously set map was extending to higher ports
+		 * than the current one, pad extra space with 0xff (no access).
+		 */
+		if (thread->io_bitmap_max < tss->io_bitmap_max)
+			memset((char *) tss->io_bitmap +
+				thread->io_bitmap_max, 0xff,
+				tss->io_bitmap_max - thread->io_bitmap_max);
+		tss->io_bitmap_max = thread->io_bitmap_max;
+		tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET;
+		tss->io_bitmap_owner = thread;
+		put_cpu();
+		return;
+	}
+	put_cpu();
+
+	if (regs->eflags & VM_MASK)
+		goto gp_in_vm86;
+
+	if (!user_mode(regs))
+		goto gp_in_kernel;
+
+	current->thread.error_code = error_code;
+	current->thread.trap_no = 13;
+	if (show_unhandled_signals && unhandled_signal(current, SIGSEGV) &&
+	    printk_ratelimit())
+		printk(KERN_INFO
+		    "%s[%d] general protection eip:%lx esp:%lx error:%lx\n",
+		    current->comm, task_pid_nr(current),
+		    regs->eip, regs->esp, error_code);
+
+	force_sig(SIGSEGV, current);
+	return;
+
+gp_in_vm86:
+	local_irq_enable();
+	handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
+	return;
+
+gp_in_kernel:
+	if (!fixup_exception(regs)) {
+		current->thread.error_code = error_code;
+		current->thread.trap_no = 13;
+		if (notify_die(DIE_GPF, "general protection fault", regs,
+				error_code, 13, SIGSEGV) == NOTIFY_STOP)
+			return;
+		die("general protection fault", regs, error_code);
+	}
+}
+
+static __kprobes void
+mem_parity_error(unsigned char reason, struct pt_regs * regs)
+{
+	printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on "
+		"CPU %d.\n", reason, smp_processor_id());
+	printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n");
+
+#if defined(CONFIG_EDAC)
+	if(edac_handler_set()) {
+		edac_atomic_assert_error();
+		return;
+	}
+#endif
+
+	if (panic_on_unrecovered_nmi)
+                panic("NMI: Not continuing");
+
+	printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
+
+	/* Clear and disable the memory parity error line. */
+	clear_mem_error(reason);
+}
+
+static __kprobes void
+io_check_error(unsigned char reason, struct pt_regs * regs)
+{
+	unsigned long i;
+
+	printk(KERN_EMERG "NMI: IOCK error (debug interrupt?)\n");
+	show_registers(regs);
+
+	/* Re-enable the IOCK line, wait for a few seconds */
+	reason = (reason & 0xf) | 8;
+	outb(reason, 0x61);
+	i = 2000;
+	while (--i) udelay(1000);
+	reason &= ~8;
+	outb(reason, 0x61);
+}
+
+static __kprobes void
+unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
+{
+#ifdef CONFIG_MCA
+	/* Might actually be able to figure out what the guilty party
+	* is. */
+	if( MCA_bus ) {
+		mca_handle_nmi();
+		return;
+	}
+#endif
+	printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on "
+		"CPU %d.\n", reason, smp_processor_id());
+	printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n");
+	if (panic_on_unrecovered_nmi)
+                panic("NMI: Not continuing");
+
+	printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
+}
+
+static DEFINE_SPINLOCK(nmi_print_lock);
+
+void __kprobes die_nmi(struct pt_regs *regs, const char *msg)
+{
+	if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) ==
+	    NOTIFY_STOP)
+		return;
+
+	spin_lock(&nmi_print_lock);
+	/*
+	* We are in trouble anyway, lets at least try
+	* to get a message out.
+	*/
+	bust_spinlocks(1);
+	printk(KERN_EMERG "%s", msg);
+	printk(" on CPU%d, eip %08lx, registers:\n",
+		smp_processor_id(), regs->eip);
+	show_registers(regs);
+	console_silent();
+	spin_unlock(&nmi_print_lock);
+	bust_spinlocks(0);
+
+	/* If we are in kernel we are probably nested up pretty bad
+	 * and might aswell get out now while we still can.
+	*/
+	if (!user_mode_vm(regs)) {
+		current->thread.trap_no = 2;
+		crash_kexec(regs);
+	}
+
+	do_exit(SIGSEGV);
+}
+
+static __kprobes void default_do_nmi(struct pt_regs * regs)
+{
+	unsigned char reason = 0;
+
+	/* Only the BSP gets external NMIs from the system.  */
+	if (!smp_processor_id())
+		reason = get_nmi_reason();
+ 
+	if (!(reason & 0xc0)) {
+		if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
+							== NOTIFY_STOP)
+			return;
+#ifdef CONFIG_X86_LOCAL_APIC
+		/*
+		 * Ok, so this is none of the documented NMI sources,
+		 * so it must be the NMI watchdog.
+		 */
+		if (nmi_watchdog_tick(regs, reason))
+			return;
+		if (!do_nmi_callback(regs, smp_processor_id()))
+#endif
+			unknown_nmi_error(reason, regs);
+
+		return;
+	}
+	if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
+		return;
+	if (reason & 0x80)
+		mem_parity_error(reason, regs);
+	if (reason & 0x40)
+		io_check_error(reason, regs);
+	/*
+	 * Reassert NMI in case it became active meanwhile
+	 * as it's edge-triggered.
+	 */
+	reassert_nmi();
+}
+
+static int ignore_nmis;
+
+fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code)
+{
+	int cpu;
+
+	nmi_enter();
+
+	cpu = smp_processor_id();
+
+	++nmi_count(cpu);
+
+	if (!ignore_nmis)
+		default_do_nmi(regs);
+
+	nmi_exit();
+}
+
+void stop_nmi(void)
+{
+	acpi_nmi_disable();
+	ignore_nmis++;
+}
+
+void restart_nmi(void)
+{
+	ignore_nmis--;
+	acpi_nmi_enable();
+}
+
+#ifdef CONFIG_KPROBES
+fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code)
+{
+	trace_hardirqs_fixup();
+
+	if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP)
+			== NOTIFY_STOP)
+		return;
+	/* This is an interrupt gate, because kprobes wants interrupts
+	disabled.  Normal trap handlers don't. */
+	restore_interrupts(regs);
+	do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL);
+}
+#endif
+
+/*
+ * Our handling of the processor debug registers is non-trivial.
+ * We do not clear them on entry and exit from the kernel. Therefore
+ * it is possible to get a watchpoint trap here from inside the kernel.
+ * However, the code in ./ptrace.c has ensured that the user can
+ * only set watchpoints on userspace addresses. Therefore the in-kernel
+ * watchpoint trap can only occur in code which is reading/writing
+ * from user space. Such code must not hold kernel locks (since it
+ * can equally take a page fault), therefore it is safe to call
+ * force_sig_info even though that claims and releases locks.
+ * 
+ * Code in ./signal.c ensures that the debug control register
+ * is restored before we deliver any signal, and therefore that
+ * user code runs with the correct debug control register even though
+ * we clear it here.
+ *
+ * Being careful here means that we don't have to be as careful in a
+ * lot of more complicated places (task switching can be a bit lazy
+ * about restoring all the debug state, and ptrace doesn't have to
+ * find every occurrence of the TF bit that could be saved away even
+ * by user code)
+ */
+fastcall void __kprobes do_debug(struct pt_regs * regs, long error_code)
+{
+	unsigned int condition;
+	struct task_struct *tsk = current;
+
+	trace_hardirqs_fixup();
+
+	get_debugreg(condition, 6);
+
+	if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
+					SIGTRAP) == NOTIFY_STOP)
+		return;
+	/* It's safe to allow irq's after DR6 has been saved */
+	if (regs->eflags & X86_EFLAGS_IF)
+		local_irq_enable();
+
+	/* Mask out spurious debug traps due to lazy DR7 setting */
+	if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
+		if (!tsk->thread.debugreg[7])
+			goto clear_dr7;
+	}
+
+	if (regs->eflags & VM_MASK)
+		goto debug_vm86;
+
+	/* Save debug status register where ptrace can see it */
+	tsk->thread.debugreg[6] = condition;
+
+	/*
+	 * Single-stepping through TF: make sure we ignore any events in
+	 * kernel space (but re-enable TF when returning to user mode).
+	 */
+	if (condition & DR_STEP) {
+		/*
+		 * We already checked v86 mode above, so we can
+		 * check for kernel mode by just checking the CPL
+		 * of CS.
+		 */
+		if (!user_mode(regs))
+			goto clear_TF_reenable;
+	}
+
+	/* Ok, finally something we can handle */
+	send_sigtrap(tsk, regs, error_code);
+
+	/* Disable additional traps. They'll be re-enabled when
+	 * the signal is delivered.
+	 */
+clear_dr7:
+	set_debugreg(0, 7);
+	return;
+
+debug_vm86:
+	handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
+	return;
+
+clear_TF_reenable:
+	set_tsk_thread_flag(tsk, TIF_SINGLESTEP);
+	regs->eflags &= ~TF_MASK;
+	return;
+}
+
+/*
+ * Note that we play around with the 'TS' bit in an attempt to get
+ * the correct behaviour even in the presence of the asynchronous
+ * IRQ13 behaviour
+ */
+void math_error(void __user *eip)
+{
+	struct task_struct * task;
+	siginfo_t info;
+	unsigned short cwd, swd;
+
+	/*
+	 * Save the info for the exception handler and clear the error.
+	 */
+	task = current;
+	save_init_fpu(task);
+	task->thread.trap_no = 16;
+	task->thread.error_code = 0;
+	info.si_signo = SIGFPE;
+	info.si_errno = 0;
+	info.si_code = __SI_FAULT;
+	info.si_addr = eip;
+	/*
+	 * (~cwd & swd) will mask out exceptions that are not set to unmasked
+	 * status.  0x3f is the exception bits in these regs, 0x200 is the
+	 * C1 reg you need in case of a stack fault, 0x040 is the stack
+	 * fault bit.  We should only be taking one exception at a time,
+	 * so if this combination doesn't produce any single exception,
+	 * then we have a bad program that isn't syncronizing its FPU usage
+	 * and it will suffer the consequences since we won't be able to
+	 * fully reproduce the context of the exception
+	 */
+	cwd = get_fpu_cwd(task);
+	swd = get_fpu_swd(task);
+	switch (swd & ~cwd & 0x3f) {
+		case 0x000: /* No unmasked exception */
+			return;
+		default:    /* Multiple exceptions */
+			break;
+		case 0x001: /* Invalid Op */
+			/*
+			 * swd & 0x240 == 0x040: Stack Underflow
+			 * swd & 0x240 == 0x240: Stack Overflow
+			 * User must clear the SF bit (0x40) if set
+			 */
+			info.si_code = FPE_FLTINV;
+			break;
+		case 0x002: /* Denormalize */
+		case 0x010: /* Underflow */
+			info.si_code = FPE_FLTUND;
+			break;
+		case 0x004: /* Zero Divide */
+			info.si_code = FPE_FLTDIV;
+			break;
+		case 0x008: /* Overflow */
+			info.si_code = FPE_FLTOVF;
+			break;
+		case 0x020: /* Precision */
+			info.si_code = FPE_FLTRES;
+			break;
+	}
+	force_sig_info(SIGFPE, &info, task);
+}
+
+fastcall void do_coprocessor_error(struct pt_regs * regs, long error_code)
+{
+	ignore_fpu_irq = 1;
+	math_error((void __user *)regs->eip);
+}
+
+static void simd_math_error(void __user *eip)
+{
+	struct task_struct * task;
+	siginfo_t info;
+	unsigned short mxcsr;
+
+	/*
+	 * Save the info for the exception handler and clear the error.
+	 */
+	task = current;
+	save_init_fpu(task);
+	task->thread.trap_no = 19;
+	task->thread.error_code = 0;
+	info.si_signo = SIGFPE;
+	info.si_errno = 0;
+	info.si_code = __SI_FAULT;
+	info.si_addr = eip;
+	/*
+	 * The SIMD FPU exceptions are handled a little differently, as there
+	 * is only a single status/control register.  Thus, to determine which
+	 * unmasked exception was caught we must mask the exception mask bits
+	 * at 0x1f80, and then use these to mask the exception bits at 0x3f.
+	 */
+	mxcsr = get_fpu_mxcsr(task);
+	switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) {
+		case 0x000:
+		default:
+			break;
+		case 0x001: /* Invalid Op */
+			info.si_code = FPE_FLTINV;
+			break;
+		case 0x002: /* Denormalize */
+		case 0x010: /* Underflow */
+			info.si_code = FPE_FLTUND;
+			break;
+		case 0x004: /* Zero Divide */
+			info.si_code = FPE_FLTDIV;
+			break;
+		case 0x008: /* Overflow */
+			info.si_code = FPE_FLTOVF;
+			break;
+		case 0x020: /* Precision */
+			info.si_code = FPE_FLTRES;
+			break;
+	}
+	force_sig_info(SIGFPE, &info, task);
+}
+
+fastcall void do_simd_coprocessor_error(struct pt_regs * regs,
+					  long error_code)
+{
+	if (cpu_has_xmm) {
+		/* Handle SIMD FPU exceptions on PIII+ processors. */
+		ignore_fpu_irq = 1;
+		simd_math_error((void __user *)regs->eip);
+	} else {
+		/*
+		 * Handle strange cache flush from user space exception
+		 * in all other cases.  This is undocumented behaviour.
+		 */
+		if (regs->eflags & VM_MASK) {
+			handle_vm86_fault((struct kernel_vm86_regs *)regs,
+					  error_code);
+			return;
+		}
+		current->thread.trap_no = 19;
+		current->thread.error_code = error_code;
+		die_if_kernel("cache flush denied", regs, error_code);
+		force_sig(SIGSEGV, current);
+	}
+}
+
+fastcall void do_spurious_interrupt_bug(struct pt_regs * regs,
+					  long error_code)
+{
+#if 0
+	/* No need to warn about this any longer. */
+	printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
+#endif
+}
+
+fastcall unsigned long patch_espfix_desc(unsigned long uesp,
+					  unsigned long kesp)
+{
+	struct desc_struct *gdt = __get_cpu_var(gdt_page).gdt;
+	unsigned long base = (kesp - uesp) & -THREAD_SIZE;
+	unsigned long new_kesp = kesp - base;
+	unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT;
+	__u64 desc = *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS];
+	/* Set up base for espfix segment */
+ 	desc &= 0x00f0ff0000000000ULL;
+ 	desc |=	((((__u64)base) << 16) & 0x000000ffffff0000ULL) |
+		((((__u64)base) << 32) & 0xff00000000000000ULL) |
+		((((__u64)lim_pages) << 32) & 0x000f000000000000ULL) |
+		(lim_pages & 0xffff);
+	*(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS] = desc;
+	return new_kesp;
+}
+
+/*
+ *  'math_state_restore()' saves the current math information in the
+ * old math state array, and gets the new ones from the current task
+ *
+ * Careful.. There are problems with IBM-designed IRQ13 behaviour.
+ * Don't touch unless you *really* know how it works.
+ *
+ * Must be called with kernel preemption disabled (in this case,
+ * local interrupts are disabled at the call-site in entry.S).
+ */
+asmlinkage void math_state_restore(void)
+{
+	struct thread_info *thread = current_thread_info();
+	struct task_struct *tsk = thread->task;
+
+	clts();		/* Allow maths ops (or we recurse) */
+	if (!tsk_used_math(tsk))
+		init_fpu(tsk);
+	restore_fpu(tsk);
+	thread->status |= TS_USEDFPU;	/* So we fnsave on switch_to() */
+	tsk->fpu_counter++;
+}
+EXPORT_SYMBOL_GPL(math_state_restore);
+
+#ifndef CONFIG_MATH_EMULATION
+
+asmlinkage void math_emulate(long arg)
+{
+	printk(KERN_EMERG "math-emulation not enabled and no coprocessor found.\n");
+	printk(KERN_EMERG "killing %s.\n",current->comm);
+	force_sig(SIGFPE,current);
+	schedule();
+}
+
+#endif /* CONFIG_MATH_EMULATION */
+
+/*
+ * This needs to use 'idt_table' rather than 'idt', and
+ * thus use the _nonmapped_ version of the IDT, as the
+ * Pentium F0 0F bugfix can have resulted in the mapped
+ * IDT being write-protected.
+ */
+void set_intr_gate(unsigned int n, void *addr)
+{
+	_set_gate(n, DESCTYPE_INT, addr, __KERNEL_CS);
+}
+
+/*
+ * This routine sets up an interrupt gate at directory privilege level 3.
+ */
+static inline void set_system_intr_gate(unsigned int n, void *addr)
+{
+	_set_gate(n, DESCTYPE_INT | DESCTYPE_DPL3, addr, __KERNEL_CS);
+}
+
+static void __init set_trap_gate(unsigned int n, void *addr)
+{
+	_set_gate(n, DESCTYPE_TRAP, addr, __KERNEL_CS);
+}
+
+static void __init set_system_gate(unsigned int n, void *addr)
+{
+	_set_gate(n, DESCTYPE_TRAP | DESCTYPE_DPL3, addr, __KERNEL_CS);
+}
+
+static void __init set_task_gate(unsigned int n, unsigned int gdt_entry)
+{
+	_set_gate(n, DESCTYPE_TASK, (void *)0, (gdt_entry<<3));
+}
+
+
+void __init trap_init(void)
+{
+	int i;
+
+#ifdef CONFIG_EISA
+	void __iomem *p = ioremap(0x0FFFD9, 4);
+	if (readl(p) == 'E'+('I'<<8)+('S'<<16)+('A'<<24)) {
+		EISA_bus = 1;
+	}
+	iounmap(p);
+#endif
+
+#ifdef CONFIG_X86_LOCAL_APIC
+	init_apic_mappings();
+#endif
+
+	set_trap_gate(0,&divide_error);
+	set_intr_gate(1,&debug);
+	set_intr_gate(2,&nmi);
+	set_system_intr_gate(3, &int3); /* int3/4 can be called from all */
+	set_system_gate(4,&overflow);
+	set_trap_gate(5,&bounds);
+	set_trap_gate(6,&invalid_op);
+	set_trap_gate(7,&device_not_available);
+	set_task_gate(8,GDT_ENTRY_DOUBLEFAULT_TSS);
+	set_trap_gate(9,&coprocessor_segment_overrun);
+	set_trap_gate(10,&invalid_TSS);
+	set_trap_gate(11,&segment_not_present);
+	set_trap_gate(12,&stack_segment);
+	set_trap_gate(13,&general_protection);
+	set_intr_gate(14,&page_fault);
+	set_trap_gate(15,&spurious_interrupt_bug);
+	set_trap_gate(16,&coprocessor_error);
+	set_trap_gate(17,&alignment_check);
+#ifdef CONFIG_X86_MCE
+	set_trap_gate(18,&machine_check);
+#endif
+	set_trap_gate(19,&simd_coprocessor_error);
+
+	if (cpu_has_fxsr) {
+		/*
+		 * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned.
+		 * Generates a compile-time "error: zero width for bit-field" if
+		 * the alignment is wrong.
+		 */
+		struct fxsrAlignAssert {
+			int _:!(offsetof(struct task_struct,
+					thread.i387.fxsave) & 15);
+		};
+
+		printk(KERN_INFO "Enabling fast FPU save and restore... ");
+		set_in_cr4(X86_CR4_OSFXSR);
+		printk("done.\n");
+	}
+	if (cpu_has_xmm) {
+		printk(KERN_INFO "Enabling unmasked SIMD FPU exception "
+				"support... ");
+		set_in_cr4(X86_CR4_OSXMMEXCPT);
+		printk("done.\n");
+	}
+
+	set_system_gate(SYSCALL_VECTOR,&system_call);
+
+	/* Reserve all the builtin and the syscall vector. */
+	for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++)
+		set_bit(i, used_vectors);
+	set_bit(SYSCALL_VECTOR, used_vectors);
+
+	/*
+	 * Should be a barrier for any external CPU state.
+	 */
+	cpu_init();
+
+	trap_init_hook();
+}
+
+static int __init kstack_setup(char *s)
+{
+	kstack_depth_to_print = simple_strtoul(s, NULL, 0);
+	return 1;
+}
+__setup("kstack=", kstack_setup);
+
+static int __init code_bytes_setup(char *s)
+{
+	code_bytes = simple_strtoul(s, NULL, 0);
+	if (code_bytes > 8192)
+		code_bytes = 8192;
+
+	return 1;
+}
+__setup("code_bytes=", code_bytes_setup);
diff -Nurb linux-2.6.24.3/drivers/char/Kconfig linux-2.6.24.3-cobalt3-tw/drivers/char/Kconfig
--- linux-2.6.24.3/drivers/char/Kconfig	2008-02-25 16:20:20.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/char/Kconfig	2008-03-02 14:55:48.000000000 -0800
@@ -813,7 +813,7 @@
 	  will get access to the real time clock (or hardware clock) built
 	  into your computer.
 
-config COBALT_LCD
+config COBALT_MIPS_LCD
 	bool "Support for Cobalt LCD"
 	depends on MIPS_COBALT
 	help
diff -Nurb linux-2.6.24.3/drivers/char/Kconfig.orig linux-2.6.24.3-cobalt3-tw/drivers/char/Kconfig.orig
--- linux-2.6.24.3/drivers/char/Kconfig.orig	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/char/Kconfig.orig	2008-02-25 16:20:20.000000000 -0800
@@ -0,0 +1,1044 @@
+#
+# Character device configuration
+#
+
+menu "Character devices"
+
+config VT
+	bool "Virtual terminal" if EMBEDDED
+	depends on !S390
+	select INPUT
+	default y if !VIOCONS
+	---help---
+	  If you say Y here, you will get support for terminal devices with
+	  display and keyboard devices. These are called "virtual" because you
+	  can run several virtual terminals (also called virtual consoles) on
+	  one physical terminal. This is rather useful, for example one
+	  virtual terminal can collect system messages and warnings, another
+	  one can be used for a text-mode user session, and a third could run
+	  an X session, all in parallel. Switching between virtual terminals
+	  is done with certain key combinations, usually Alt-<function key>.
+
+	  The setterm command ("man setterm") can be used to change the
+	  properties (such as colors or beeping) of a virtual terminal. The
+	  man page console_codes(4) ("man console_codes") contains the special
+	  character sequences that can be used to change those properties
+	  directly. The fonts used on virtual terminals can be changed with
+	  the setfont ("man setfont") command and the key bindings are defined
+	  with the loadkeys ("man loadkeys") command.
+
+	  You need at least one virtual terminal device in order to make use
+	  of your keyboard and monitor. Therefore, only people configuring an
+	  embedded system would want to say N here in order to save some
+	  memory; the only way to log into such a system is then via a serial
+	  or network connection.
+
+	  If unsure, say Y, or else you won't be able to do much with your new
+	  shiny Linux system :-)
+
+config VT_CONSOLE
+	bool "Support for console on virtual terminal" if EMBEDDED
+	depends on VT
+	default y
+	---help---
+	  The system console is the device which receives all kernel messages
+	  and warnings and which allows logins in single user mode. If you
+	  answer Y here, a virtual terminal (the device used to interact with
+	  a physical terminal) can be used as system console. This is the most
+	  common mode of operations, so you should say Y here unless you want
+	  the kernel messages be output only to a serial port (in which case
+	  you should say Y to "Console on serial port", below).
+
+	  If you do say Y here, by default the currently visible virtual
+	  terminal (/dev/tty0) will be used as system console. You can change
+	  that with a kernel command line option such as "console=tty3" which
+	  would use the third virtual terminal as system console. (Try "man
+	  bootparam" or see the documentation of your boot loader (lilo or
+	  loadlin) about how to pass options to the kernel at boot time.)
+
+	  If unsure, say Y.
+
+config HW_CONSOLE
+	bool
+	depends on VT && !S390 && !UML
+	default y
+
+config VT_HW_CONSOLE_BINDING
+       bool "Support for binding and unbinding console drivers"
+       depends on HW_CONSOLE
+       default n
+       ---help---
+         The virtual terminal is the device that interacts with the physical
+         terminal through console drivers. On these systems, at least one
+         console driver is loaded. In other configurations, additional console
+         drivers may be enabled, such as the framebuffer console. If more than
+         1 console driver is enabled, setting this to 'y' will allow you to
+         select the console driver that will serve as the backend for the
+         virtual terminals.
+
+	 See <file:Documentation/console/console.txt> for more
+	 information. For framebuffer console users, please refer to
+	 <file:Documentation/fb/fbcon.txt>.
+
+config SERIAL_NONSTANDARD
+	bool "Non-standard serial port support"
+	depends on HAS_IOMEM
+	---help---
+	  Say Y here if you have any non-standard serial boards -- boards
+	  which aren't supported using the standard "dumb" serial driver.
+	  This includes intelligent serial boards such as Cyclades,
+	  Digiboards, etc. These are usually used for systems that need many
+	  serial ports because they serve many terminals or dial-in
+	  connections.
+
+	  Note that the answer to this question won't directly affect the
+	  kernel: saying N will just cause the configurator to skip all
+	  the questions about non-standard serial boards.
+
+	  Most people can say N here.
+
+config COMPUTONE
+	tristate "Computone IntelliPort Plus serial support"
+	depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
+	---help---
+	  This driver supports the entire family of Intelliport II/Plus
+	  controllers with the exception of the MicroChannel controllers and
+	  products previous to the Intelliport II. These are multiport cards,
+	  which give you many serial ports. You would need something like this
+	  to connect more than two modems to your Linux box, for instance in
+	  order to become a dial-in server. If you have a card like that, say
+	  Y here and read <file:Documentation/computone.txt>.
+
+	  To compile this driver as modules, choose M here: the
+	  modules will be called ip2 and ip2main.
+
+config ROCKETPORT
+	tristate "Comtrol RocketPort support"
+	depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
+	help
+	  This driver supports Comtrol RocketPort and RocketModem PCI boards.   
+          These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or
+          modems.  For information about the RocketPort/RocketModem  boards
+          and this driver read <file:Documentation/rocket.txt>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rocket.
+
+	  If you want to compile this driver into the kernel, say Y here.  If
+          you don't have a Comtrol RocketPort/RocketModem card installed, say N.
+
+config CYCLADES
+	tristate "Cyclades async mux support"
+	depends on SERIAL_NONSTANDARD && (PCI || ISA)
+	select FW_LOADER
+	---help---
+	  This driver supports Cyclades Z and Y multiserial boards.
+	  You would need something like this to connect more than two modems to
+	  your Linux box, for instance in order to become a dial-in server.
+
+	  For information about the Cyclades-Z card, read
+	  <file:Documentation/README.cycladesZ>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cyclades.
+
+	  If you haven't heard about it, it's safe to say N.
+
+config CYZ_INTR
+	bool "Cyclades-Z interrupt mode operation (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && CYCLADES
+	help
+	  The Cyclades-Z family of multiport cards allows 2 (two) driver op
+	  modes: polling and interrupt. In polling mode, the driver will check
+	  the status of the Cyclades-Z ports every certain amount of time
+	  (which is called polling cycle and is configurable). In interrupt
+	  mode, it will use an interrupt line (IRQ) in order to check the
+	  status of the Cyclades-Z ports. The default op mode is polling. If
+	  unsure, say N.
+
+config DIGIEPCA
+	tristate "Digiboard Intelligent Async Support"
+	depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
+	---help---
+	  This is a driver for Digi International's Xx, Xeve, and Xem series
+	  of cards which provide multiple serial ports. You would need
+	  something like this to connect more than two modems to your Linux
+	  box, for instance in order to become a dial-in server. This driver
+	  supports the original PC (ISA) boards as well as PCI, and EISA. If
+	  you have a card like this, say Y here and read the file
+	  <file:Documentation/digiepca.txt>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called epca.
+
+config ESPSERIAL
+	tristate "Hayes ESP serial port support"
+	depends on SERIAL_NONSTANDARD && ISA && ISA_DMA_API
+	help
+	  This is a driver which supports Hayes ESP serial ports.  Both single
+	  port cards and multiport cards are supported.  Make sure to read
+	  <file:Documentation/hayes-esp.txt>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called esp.
+
+	  If unsure, say N.
+
+config MOXA_INTELLIO
+	tristate "Moxa Intellio support"
+	depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
+	help
+	  Say Y here if you have a Moxa Intellio multiport serial card.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called moxa.
+
+config MOXA_SMARTIO
+	tristate "Moxa SmartIO support (OBSOLETE)"
+	depends on SERIAL_NONSTANDARD
+	help
+	  Say Y here if you have a Moxa SmartIO multiport serial card.
+
+	  This driver can also be built as a module ( = code which can be
+	  inserted in and removed from the running kernel whenever you want).
+	  The module will be called mxser. If you want to do that, say M
+	  here.
+
+config MOXA_SMARTIO_NEW
+	tristate "Moxa SmartIO support v. 2.0"
+	depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA)
+	help
+	  Say Y here if you have a Moxa SmartIO multiport serial card and/or
+	  want to help develop a new version of this driver.
+
+	  This is upgraded (1.9.1) driver from original Moxa drivers with
+	  changes finally resulting in PCI probing.
+
+	  This driver can also be built as a module. The module will be called
+	  mxser_new. If you want to do that, say M here.
+
+config ISI
+	tristate "Multi-Tech multiport card support (EXPERIMENTAL)"
+	depends on SERIAL_NONSTANDARD && PCI
+	select FW_LOADER
+	help
+	  This is a driver for the Multi-Tech cards which provide several
+	  serial ports.  The driver is experimental and can currently only be
+	  built as a module. The module will be called isicom.
+	  If you want to do that, choose M here.
+
+config SYNCLINK
+	tristate "Microgate SyncLink card support"
+	depends on SERIAL_NONSTANDARD && PCI && ISA_DMA_API
+	help
+	  Provides support for the SyncLink ISA and PCI multiprotocol serial
+	  adapters. These adapters support asynchronous and HDLC bit
+	  synchronous communication up to 10Mbps (PCI adapter).
+
+	  This driver can only be built as a module ( = code which can be
+	  inserted in and removed from the running kernel whenever you want).
+	  The module will be called synclink.  If you want to do that, say M
+	  here.
+
+config SYNCLINKMP
+	tristate "SyncLink Multiport support"
+	depends on SERIAL_NONSTANDARD && PCI
+	help
+	  Enable support for the SyncLink Multiport (2 or 4 ports)
+	  serial adapter, running asynchronous and HDLC communications up
+	  to 2.048Mbps. Each ports is independently selectable for
+	  RS-232, V.35, RS-449, RS-530, and X.21
+
+	  This driver may be built as a module ( = code which can be
+	  inserted in and removed from the running kernel whenever you want).
+	  The module will be called synclinkmp.  If you want to do that, say M
+	  here.
+
+config SYNCLINK_GT
+	tristate "SyncLink GT/AC support"
+	depends on SERIAL_NONSTANDARD && PCI
+	help
+	  Support for SyncLink GT and SyncLink AC families of
+	  synchronous and asynchronous serial adapters
+	  manufactured by Microgate Systems, Ltd. (www.microgate.com)
+
+config N_HDLC
+	tristate "HDLC line discipline support"
+	depends on SERIAL_NONSTANDARD
+	help
+	  Allows synchronous HDLC communications with tty device drivers that
+	  support synchronous HDLC such as the Microgate SyncLink adapter.
+
+	  This driver can only be built as a module ( = code which can be
+	  inserted in and removed from the running kernel whenever you want).
+	  The module will be called n_hdlc. If you want to do that, say M
+	  here.
+
+config RISCOM8
+	tristate "SDL RISCom/8 card support"
+	depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP
+	help
+	  This is a driver for the SDL Communications RISCom/8 multiport card,
+	  which gives you many serial ports. You would need something like
+	  this to connect more than two modems to your Linux box, for instance
+	  in order to become a dial-in server. If you have a card like that,
+	  say Y here and read the file <file:Documentation/riscom8.txt>.
+
+	  Also it's possible to say M here and compile this driver as kernel
+	  loadable module; the module will be called riscom8.
+
+config SPECIALIX
+	tristate "Specialix IO8+ card support"
+	depends on SERIAL_NONSTANDARD
+	help
+	  This is a driver for the Specialix IO8+ multiport card (both the
+	  ISA and the PCI version) which gives you many serial ports. You
+	  would need something like this to connect more than two modems to
+	  your Linux box, for instance in order to become a dial-in server.
+
+	  If you have a card like that, say Y here and read the file
+	  <file:Documentation/specialix.txt>. Also it's possible to say M here
+	  and compile this driver as kernel loadable module which will be
+	  called specialix.
+
+config SPECIALIX_RTSCTS
+	bool "Specialix DTR/RTS pin is RTS"
+	depends on SPECIALIX
+	help
+	  The Specialix IO8+ card can only support either RTS or DTR. If you
+	  say N here, the driver will use the pin as "DTR" when the tty is in
+	  software handshake mode.  If you say Y here or hardware handshake is
+	  on, it will always be RTS.  Read the file
+	  <file:Documentation/specialix.txt> for more information.
+
+config SX
+	tristate "Specialix SX (and SI) card support"
+	depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA)
+	help
+	  This is a driver for the SX and SI multiport serial cards.
+	  Please read the file <file:Documentation/sx.txt> for details.
+
+	  This driver can only be built as a module ( = code which can be
+	  inserted in and removed from the running kernel whenever you want).
+	  The module will be called sx. If you want to do that, say M here.
+
+config RIO
+	tristate "Specialix RIO system support"
+	depends on SERIAL_NONSTANDARD
+	help
+	  This is a driver for the Specialix RIO, a smart serial card which
+	  drives an outboard box that can support up to 128 ports.  Product
+	  information is at <http://www.perle.com/support/documentation.html#multiport>.
+	  There are both ISA and PCI versions.
+
+config RIO_OLDPCI
+	bool "Support really old RIO/PCI cards"
+	depends on RIO
+	help
+	  Older RIO PCI cards need some initialization-time configuration to
+	  determine the IRQ and some control addresses.  If you have a RIO and
+	  this doesn't seem to work, try setting this to Y.
+
+config STALDRV
+	bool "Stallion multiport serial support"
+	depends on SERIAL_NONSTANDARD
+	help
+	  Stallion cards give you many serial ports.  You would need something
+	  like this to connect more than two modems to your Linux box, for
+	  instance in order to become a dial-in server.  If you say Y here,
+	  you will be asked for your specific card model in the next
+	  questions.  Make sure to read <file:Documentation/stallion.txt> in
+	  this case.  If you have never heard about all this, it's safe to
+	  say N.
+
+config STALLION
+	tristate "Stallion EasyIO or EC8/32 support"
+	depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI)
+	help
+	  If you have an EasyIO or EasyConnection 8/32 multiport Stallion
+	  card, then this is for you; say Y.  Make sure to read
+	  <file:Documentation/stallion.txt>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called stallion.
+
+config ISTALLION
+	tristate "Stallion EC8/64, ONboard, Brumby support"
+	depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI)
+	help
+	  If you have an EasyConnection 8/64, ONboard, Brumby or Stallion
+	  serial multiport card, say Y here. Make sure to read
+	  <file:Documentation/stallion.txt>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called istallion.
+
+config A2232
+	tristate "Commodore A2232 serial support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP
+	---help---
+	  This option supports the 2232 7-port serial card shipped with the
+	  Amiga 2000 and other Zorro-bus machines, dating from 1989.  At
+	  a max of 19,200 bps, the ports are served by a 6551 ACIA UART chip
+	  each, plus a 8520 CIA, and a master 6502 CPU and buffer as well. The
+	  ports were connected with 8 pin DIN connectors on the card bracket,
+	  for which 8 pin to DB25 adapters were supplied. The card also had
+	  jumpers internally to toggle various pinning configurations.
+
+	  This driver can be built as a module; but then "generic_serial"
+	  will also be built as a module. This has to be loaded before
+	  "ser_a2232". If you want to do this, answer M here.
+
+config SGI_SNSC
+	bool "SGI Altix system controller communication support"
+	depends on (IA64_SGI_SN2 || IA64_GENERIC)
+	help
+	  If you have an SGI Altix and you want to enable system
+	  controller communication from user space (you want this!),
+	  say Y.  Otherwise, say N.
+
+config SGI_TIOCX
+       bool "SGI TIO CX driver support"
+       depends on (IA64_SGI_SN2 || IA64_GENERIC)
+       help
+         If you have an SGI Altix and you have fpga devices attached
+         to your TIO, say Y here, otherwise say N.
+
+config SGI_MBCS
+       tristate "SGI FPGA Core Services driver support"
+       depends on SGI_TIOCX
+       help
+         If you have an SGI Altix with an attached SABrick
+         say Y or M here, otherwise say N.
+
+source "drivers/serial/Kconfig"
+
+config UNIX98_PTYS
+	bool "Unix98 PTY support" if EMBEDDED
+	default y
+	---help---
+	  A pseudo terminal (PTY) is a software device consisting of two
+	  halves: a master and a slave. The slave device behaves identical to
+	  a physical terminal; the master device is used by a process to
+	  read data from and write data to the slave, thereby emulating a
+	  terminal. Typical programs for the master side are telnet servers
+	  and xterms.
+
+	  Linux has traditionally used the BSD-like names /dev/ptyxx for
+	  masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
+	  has a number of problems. The GNU C library glibc 2.1 and later,
+	  however, supports the Unix98 naming standard: in order to acquire a
+	  pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
+	  terminal is then made available to the process and the pseudo
+	  terminal slave can be accessed as /dev/pts/<number>. What was
+	  traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
+
+	  All modern Linux systems use the Unix98 ptys.  Say Y unless
+	  you're on an embedded system and want to conserve memory.
+
+config LEGACY_PTYS
+	bool "Legacy (BSD) PTY support"
+	default y
+	---help---
+	  A pseudo terminal (PTY) is a software device consisting of two
+	  halves: a master and a slave. The slave device behaves identical to
+	  a physical terminal; the master device is used by a process to
+	  read data from and write data to the slave, thereby emulating a
+	  terminal. Typical programs for the master side are telnet servers
+	  and xterms.
+
+	  Linux has traditionally used the BSD-like names /dev/ptyxx
+	  for masters and /dev/ttyxx for slaves of pseudo
+	  terminals. This scheme has a number of problems, including
+	  security.  This option enables these legacy devices; on most
+	  systems, it is safe to say N.
+
+
+config LEGACY_PTY_COUNT
+	int "Maximum number of legacy PTY in use"
+	depends on LEGACY_PTYS
+	range 0 256
+	default "256"
+	---help---
+	  The maximum number of legacy PTYs that can be used at any one time.
+	  The default is 256, and should be more than enough.  Embedded
+	  systems may want to reduce this to save memory.
+
+	  When not in use, each legacy PTY occupies 12 bytes on 32-bit
+	  architectures and 24 bytes on 64-bit architectures.
+
+config BRIQ_PANEL
+	tristate 'Total Impact briQ front panel driver'
+	depends on PPC_CHRP
+	---help---
+	  The briQ is a small footprint CHRP computer with a frontpanel VFD, a
+	  tristate led and two switches. It is the size of a CDROM drive.
+
+	  If you have such one and want anything showing on the VFD then you
+	  must answer Y here.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called briq_panel.
+
+	  It's safe to say N here.
+
+config PRINTER
+	tristate "Parallel printer support"
+	depends on PARPORT
+	---help---
+	  If you intend to attach a printer to the parallel port of your Linux
+	  box (as opposed to using a serial printer; if the connector at the
+	  printer has 9 or 25 holes ["female"], then it's serial), say Y.
+	  Also read the Printing-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  It is possible to share one parallel port among several devices
+	  (e.g. printer and ZIP drive) and it is safe to compile the
+	  corresponding drivers into the kernel.
+
+	  To compile this driver as a module, choose M here and read
+	  <file:Documentation/parport.txt>.  The module will be called lp.
+
+	  If you have several parallel ports, you can specify which ports to
+	  use with the "lp" kernel command line option.  (Try "man bootparam"
+	  or see the documentation of your boot loader (lilo or loadlin) about
+	  how to pass options to the kernel at boot time.)  The syntax of the
+	  "lp" command line option can be found in <file:drivers/char/lp.c>.
+
+	  If you have more than 8 printers, you need to increase the LP_NO
+	  macro in lp.c and the PARPORT_MAX macro in parport.h.
+
+config LP_CONSOLE
+	bool "Support for console on line printer"
+	depends on PRINTER
+	---help---
+	  If you want kernel messages to be printed out as they occur, you
+	  can have a console on the printer. This option adds support for
+	  doing that; to actually get it to happen you need to pass the
+	  option "console=lp0" to the kernel at boot time.
+
+	  If the printer is out of paper (or off, or unplugged, or too
+	  busy..) the kernel will stall until the printer is ready again.
+	  By defining CONSOLE_LP_STRICT to 0 (at your own risk) you
+	  can make the kernel continue when this happens,
+	  but it'll lose the kernel messages.
+
+	  If unsure, say N.
+
+config PPDEV
+	tristate "Support for user-space parallel port device drivers"
+	depends on PARPORT
+	---help---
+	  Saying Y to this adds support for /dev/parport device nodes.  This
+	  is needed for programs that want portable access to the parallel
+	  port, for instance deviceid (which displays Plug-and-Play device
+	  IDs).
+
+	  This is the parallel port equivalent of SCSI generic support (sg).
+	  It is safe to say N to this -- it is not needed for normal printing
+	  or parallel port CD-ROM/disk support.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ppdev.
+
+	  If unsure, say N.
+
+config HVC_DRIVER
+	bool
+	help
+	  Generic "hypervisor virtual console" infrastructure for various
+	  hypervisors (pSeries, iSeries, Xen, lguest).
+	  It will automatically be selected if one of the back-end console drivers
+	  is selected.
+
+
+config HVC_CONSOLE
+	bool "pSeries Hypervisor Virtual Console support"
+	depends on PPC_PSERIES
+	select HVC_DRIVER
+	help
+	  pSeries machines when partitioned support a hypervisor virtual
+	  console. This driver allows each pSeries partition to have a console
+	  which is accessed via the HMC.
+
+config HVC_ISERIES
+	bool "iSeries Hypervisor Virtual Console support"
+	depends on PPC_ISERIES
+	default y
+	select HVC_DRIVER
+	help
+	  iSeries machines support a hypervisor virtual console.
+
+config HVC_RTAS
+	bool "IBM RTAS Console support"
+	depends on PPC_RTAS
+	select HVC_DRIVER
+	help
+	  IBM Console device driver which makes use of RTAS
+
+config HVC_BEAT
+	bool "Toshiba's Beat Hypervisor Console support"
+	depends on PPC_CELLEB
+	select HVC_DRIVER
+	help
+	  Toshiba's Cell Reference Set Beat Console device driver
+
+config HVC_XEN
+	bool "Xen Hypervisor Console support"
+	depends on XEN
+	select HVC_DRIVER
+	default y
+	help
+	  Xen virtual console device driver
+
+config VIRTIO_CONSOLE
+	bool
+	select HVC_DRIVER
+
+config HVCS
+	tristate "IBM Hypervisor Virtual Console Server support"
+	depends on PPC_PSERIES
+	help
+	  Partitionable IBM Power5 ppc64 machines allow hosting of
+	  firmware virtual consoles from one Linux partition by
+	  another Linux partition.  This driver allows console data
+	  from Linux partitions to be accessed through TTY device
+	  interfaces in the device tree of a Linux partition running
+	  this driver.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called hvcs.ko.  Additionally, this module
+	  will depend on arch specific APIs exported from hvcserver.ko
+	  which will also be compiled when this driver is built as a
+	  module.
+
+source "drivers/char/ipmi/Kconfig"
+
+config DS1620
+	tristate "NetWinder thermometer support"
+	depends on ARCH_NETWINDER
+	help
+	  Say Y here to include support for the thermal management hardware
+	  found in the NetWinder. This driver allows the user to control the
+	  temperature set points and to read the current temperature.
+
+	  It is also possible to say M here to build it as a module (ds1620)
+	  It is recommended to be used on a NetWinder, but it is not a
+	  necessity.
+
+config NWBUTTON
+	tristate "NetWinder Button"
+	depends on ARCH_NETWINDER
+	---help---
+	  If you say Y here and create a character device node /dev/nwbutton
+	  with major and minor numbers 10 and 158 ("man mknod"), then every
+	  time the orange button is pressed a number of times, the number of
+	  times the button was pressed will be written to that device.
+
+	  This is most useful for applications, as yet unwritten, which
+	  perform actions based on how many times the button is pressed in a
+	  row.
+
+	  Do not hold the button down for too long, as the driver does not
+	  alter the behaviour of the hardware reset circuitry attached to the
+	  button; it will still execute a hard reset if the button is held
+	  down for longer than approximately five seconds.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called nwbutton.
+
+	  Most people will answer Y to this question and "Reboot Using Button"
+	  below to be able to initiate a system shutdown from the button.
+
+config NWBUTTON_REBOOT
+	bool "Reboot Using Button"
+	depends on NWBUTTON
+	help
+	  If you say Y here, then you will be able to initiate a system
+	  shutdown and reboot by pressing the orange button a number of times.
+	  The number of presses to initiate the shutdown is two by default,
+	  but this can be altered by modifying the value of NUM_PRESSES_REBOOT
+	  in nwbutton.h and recompiling the driver or, if you compile the
+	  driver as a module, you can specify the number of presses at load
+	  time with "insmod button reboot_count=<something>".
+
+config NWFLASH
+	tristate "NetWinder flash support"
+	depends on ARCH_NETWINDER
+	---help---
+	  If you say Y here and create a character device /dev/flash with
+	  major 10 and minor 160 you can manipulate the flash ROM containing
+	  the NetWinder firmware. Be careful as accidentally overwriting the
+	  flash contents can render your computer unbootable. On no account
+	  allow random users access to this device. :-)
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called nwflash.
+
+	  If you're not sure, say N.
+
+source "drivers/char/hw_random/Kconfig"
+
+config NVRAM
+	tristate "/dev/nvram support"
+	depends on ATARI || X86 || ARM || GENERIC_NVRAM
+	---help---
+	  If you say Y here and create a character special file /dev/nvram
+	  with major number 10 and minor number 144 using mknod ("man mknod"),
+	  you get read and write access to the extra bytes of non-volatile
+	  memory in the real time clock (RTC), which is contained in every PC
+	  and most Ataris.  The actual number of bytes varies, depending on the
+	  nvram in the system, but is usually 114 (128-14 for the RTC).
+
+	  This memory is conventionally called "CMOS RAM" on PCs and "NVRAM"
+	  on Ataris. /dev/nvram may be used to view settings there, or to
+	  change them (with some utility). It could also be used to frequently
+	  save a few bits of very important data that may not be lost over
+	  power-off and for which writing to disk is too insecure. Note
+	  however that most NVRAM space in a PC belongs to the BIOS and you
+	  should NEVER idly tamper with it. See Ralf Brown's interrupt list
+	  for a guide to the use of CMOS bytes by your BIOS.
+
+	  On Atari machines, /dev/nvram is always configured and does not need
+	  to be selected.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called nvram.
+
+config RTC
+	tristate "Enhanced Real Time Clock Support"
+	depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390
+	---help---
+	  If you say Y here and create a character special file /dev/rtc with
+	  major number 10 and minor number 135 using mknod ("man mknod"), you
+	  will get access to the real time clock (or hardware clock) built
+	  into your computer.
+
+	  Every PC has such a clock built in. It can be used to generate
+	  signals from as low as 1Hz up to 8192Hz, and can also be used
+	  as a 24 hour alarm. It reports status information via the file
+	  /proc/driver/rtc and its behaviour is set by various ioctls on
+	  /dev/rtc.
+
+	  If you run Linux on a multiprocessor machine and said Y to
+	  "Symmetric Multi Processing" above, you should say Y here to read
+	  and set the RTC in an SMP compatible fashion.
+
+	  If you think you have a use for such a device (such as periodic data
+	  sampling), then say Y here, and read <file:Documentation/rtc.txt>
+	  for details.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rtc.
+
+config JS_RTC
+	tristate "Enhanced Real Time Clock Support"
+	depends on SPARC32 && PCI
+	---help---
+	  If you say Y here and create a character special file /dev/rtc with
+	  major number 10 and minor number 135 using mknod ("man mknod"), you
+	  will get access to the real time clock (or hardware clock) built
+	  into your computer.
+
+	  Every PC has such a clock built in. It can be used to generate
+	  signals from as low as 1Hz up to 8192Hz, and can also be used
+	  as a 24 hour alarm. It reports status information via the file
+	  /proc/driver/rtc and its behaviour is set by various ioctls on
+	  /dev/rtc.
+
+	  If you think you have a use for such a device (such as periodic data
+	  sampling), then say Y here, and read <file:Documentation/rtc.txt>
+	  for details.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called js-rtc.
+
+config SGI_DS1286
+	tristate "SGI DS1286 RTC support"
+	depends on SGI_IP22
+	help
+	  If you say Y here and create a character special file /dev/rtc with
+	  major number 10 and minor number 135 using mknod ("man mknod"), you
+	  will get access to the real time clock built into your computer.
+	  Every SGI has such a clock built in. It reports status information
+	  via the file /proc/rtc and its behaviour is set by various ioctls on
+	  /dev/rtc.
+
+config SGI_IP27_RTC
+	bool "SGI M48T35 RTC support"
+	depends on SGI_IP27
+	help
+	  If you say Y here and create a character special file /dev/rtc with
+	  major number 10 and minor number 135 using mknod ("man mknod"), you
+	  will get access to the real time clock built into your computer.
+	  Every SGI has such a clock built in. It reports status information
+	  via the file /proc/rtc and its behaviour is set by various ioctls on
+	  /dev/rtc.
+
+config GEN_RTC
+	tristate "Generic /dev/rtc emulation"
+	depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH
+	---help---
+	  If you say Y here and create a character special file /dev/rtc with
+	  major number 10 and minor number 135 using mknod ("man mknod"), you
+	  will get access to the real time clock (or hardware clock) built
+	  into your computer.
+
+	  It reports status information via the file /proc/driver/rtc and its
+	  behaviour is set by various ioctls on /dev/rtc. If you enable the
+	  "extended RTC operation" below it will also provide an emulation
+	  for RTC_UIE which is required by some programs and may improve
+	  precision in some cases.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called genrtc.
+
+config GEN_RTC_X
+	bool "Extended RTC operation"
+	depends on GEN_RTC
+	help
+	  Provides an emulation for RTC_UIE which is required by some programs
+	  and may improve precision of the generic RTC support in some cases.
+
+config EFI_RTC
+	bool "EFI Real Time Clock Services"
+	depends on IA64
+
+config DS1302
+	tristate "DS1302 RTC support"
+	depends on M32R && (PLAT_M32700UT || PLAT_OPSPUT)
+	help
+	  If you say Y here and create a character special file /dev/rtc with
+	  major number 121 and minor number 0 using mknod ("man mknod"), you
+	  will get access to the real time clock (or hardware clock) built
+	  into your computer.
+
+config COBALT_LCD
+	bool "Support for Cobalt LCD"
+	depends on MIPS_COBALT
+	help
+	  This option enables support for the LCD display and buttons found
+	  on Cobalt systems through a misc device.
+
+config DTLK
+	tristate "Double Talk PC internal speech card support"
+	depends on ISA
+	help
+	  This driver is for the DoubleTalk PC, a speech synthesizer
+	  manufactured by RC Systems (<http://www.rcsys.com/>).  It is also
+	  called the `internal DoubleTalk'.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called dtlk.
+
+config R3964
+	tristate "Siemens R3964 line discipline"
+	---help---
+	  This driver allows synchronous communication with devices using the
+	  Siemens R3964 packet protocol. Unless you are dealing with special
+	  hardware like PLCs, you are unlikely to need this.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called n_r3964.
+
+	  If unsure, say N.
+
+config APPLICOM
+	tristate "Applicom intelligent fieldbus card support"
+	depends on PCI
+	---help---
+	  This driver provides the kernel-side support for the intelligent
+	  fieldbus cards made by Applicom International. More information
+	  about these cards can be found on the WWW at the address
+	  <http://www.applicom-int.com/>, or by email from David Woodhouse
+	  <dwmw2@infradead.org>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called applicom.
+
+	  If unsure, say N.
+
+config SONYPI
+	tristate "Sony Vaio Programmable I/O Control Device support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && X86 && PCI && INPUT && !64BIT
+	---help---
+	  This driver enables access to the Sony Programmable I/O Control
+	  Device which can be found in many (all ?) Sony Vaio laptops.
+
+	  If you have one of those laptops, read
+	  <file:Documentation/sonypi.txt>, and say Y or M here.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sonypi.
+
+config GPIO_TB0219
+	tristate "TANBAC TB0219 GPIO support"
+	depends on TANBAC_TB022X
+	select GPIO_VR41XX
+
+source "drivers/char/pcmcia/Kconfig"
+
+config MWAVE
+	tristate "ACP Modem (Mwave) support"
+	depends on X86
+	select SERIAL_8250
+	---help---
+	  The ACP modem (Mwave) for Linux is a WinModem. It is composed of a
+	  kernel driver and a user level application. Together these components
+	  support direct attachment to public switched telephone networks (PSTNs)
+	  and support selected world wide countries.
+
+	  This version of the ACP Modem driver supports the IBM Thinkpad 600E,
+	  600, and 770 that include on board ACP modem hardware.
+
+	  The modem also supports the standard communications port interface
+	  (ttySx) and is compatible with the Hayes AT Command Set.
+
+	  The user level application needed to use this driver can be found at
+	  the IBM Linux Technology Center (LTC) web site:
+	  <http://www.ibm.com/linux/ltc/>.
+
+	  If you own one of the above IBM Thinkpads which has the Mwave chipset
+	  in it, say Y.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mwave.
+
+config SCx200_GPIO
+	tristate "NatSemi SCx200 GPIO Support"
+	depends on SCx200
+	select NSC_GPIO
+	help
+	  Give userspace access to the GPIO pins on the National
+	  Semiconductor SCx200 processors.
+
+	  If compiled as a module, it will be called scx200_gpio.
+
+config PC8736x_GPIO
+	tristate "NatSemi PC8736x GPIO Support"
+	depends on X86
+	default SCx200_GPIO	# mostly N
+	select NSC_GPIO		# needed for support routines
+	help
+	  Give userspace access to the GPIO pins on the National
+	  Semiconductor PC-8736x (x=[03456]) SuperIO chip.  The chip
+	  has multiple functional units, inc several managed by
+	  hwmon/pc87360 driver.  Tested with PC-87366
+
+	  If compiled as a module, it will be called pc8736x_gpio.
+
+config NSC_GPIO
+	tristate "NatSemi Base GPIO Support"
+	depends on X86_32
+	# selected by SCx200_GPIO and PC8736x_GPIO
+	# what about 2 selectors differing: m != y
+	help
+	  Common support used (and needed) by scx200_gpio and
+	  pc8736x_gpio drivers.  If those drivers are built as
+	  modules, this one will be too, named nsc_gpio
+
+config CS5535_GPIO
+	tristate "AMD CS5535/CS5536 GPIO (Geode Companion Device)"
+	depends on X86_32
+	help
+	  Give userspace access to the GPIO pins on the AMD CS5535 and
+	  CS5536 Geode companion devices.
+
+	  If compiled as a module, it will be called cs5535_gpio.
+
+config GPIO_VR41XX
+	tristate "NEC VR4100 series General-purpose I/O Unit support"
+	depends on CPU_VR41XX
+
+config RAW_DRIVER
+	tristate "RAW driver (/dev/raw/rawN)"
+	depends on BLOCK
+	help
+	  The raw driver permits block devices to be bound to /dev/raw/rawN.
+	  Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O.
+	  See the raw(8) manpage for more details.
+
+          Applications should preferably open the device (eg /dev/hda1)
+          with the O_DIRECT flag.
+
+config MAX_RAW_DEVS
+	int "Maximum number of RAW devices to support (1-8192)"
+	depends on RAW_DRIVER
+	default "256"
+	help
+	  The maximum number of RAW devices that are supported.
+	  Default is 256. Increase this number in case you need lots of
+	  raw devices.
+
+config HPET
+	bool "HPET - High Precision Event Timer" if (X86 || IA64)
+	default n
+	depends on ACPI
+	help
+	  If you say Y here, you will have a miscdevice named "/dev/hpet/".  Each
+	  open selects one of the timers supported by the HPET.  The timers are
+	  non-periodic and/or periodic.
+
+config HPET_RTC_IRQ
+	bool "HPET Control RTC IRQ" if !HPET_EMULATE_RTC
+	default n
+	depends on HPET
+	help
+	  If you say Y here, you will disable RTC_IRQ in drivers/char/rtc.c. It
+	  is assumed the platform called hpet_alloc with the RTC IRQ values for
+	  the HPET timers.
+
+config HPET_MMAP
+	bool "Allow mmap of HPET"
+	default y
+	depends on HPET
+	help
+	  If you say Y here, user applications will be able to mmap
+	  the HPET registers.
+
+	  In some hardware implementations, the page containing HPET
+	  registers may also contain other things that shouldn't be
+	  exposed to the user.  If this applies to your hardware,
+	  say N here.
+
+config HANGCHECK_TIMER
+	tristate "Hangcheck timer"
+	depends on X86 || IA64 || PPC64 || S390
+	help
+	  The hangcheck-timer module detects when the system has gone
+	  out to lunch past a certain margin.  It can reboot the system
+	  or merely print a warning.
+
+config MMTIMER
+	tristate "MMTIMER Memory mapped RTC for SGI Altix"
+	depends on IA64_GENERIC || IA64_SGI_SN2
+	default y
+	help
+	  The mmtimer device allows direct userspace access to the
+	  Altix system timer.
+
+source "drivers/char/tpm/Kconfig"
+
+config TELCLOCK
+	tristate "Telecom clock driver for ATCA SBC"
+	depends on EXPERIMENTAL && X86
+	default n
+	help
+	  The telecom clock device is specific to the MPCBL0010 and MPCBL0050
+	  ATCA computers and allows direct userspace access to the
+	  configuration of the telecom clock configuration settings.  This
+	  device is used for hardware synchronization across the ATCA backplane
+	  fabric.  Upon loading, the driver exports a sysfs directory,
+	  /sys/devices/platform/telco_clock, with a number of files for
+	  controlling the behavior of this hardware.
+
+config DEVPORT
+	bool
+	depends on !M68K
+	depends on ISA || PCI
+	default y
+
+source "drivers/s390/char/Kconfig"
+
+endmenu
+
diff -Nurb linux-2.6.24.3/drivers/char/Makefile linux-2.6.24.3-cobalt3-tw/drivers/char/Makefile
--- linux-2.6.24.3/drivers/char/Makefile	2008-02-25 16:20:20.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/char/Makefile	2008-03-02 14:55:48.000000000 -0800
@@ -85,7 +85,7 @@
 obj-$(CONFIG_I8K)		+= i8k.o
 obj-$(CONFIG_DS1620)		+= ds1620.o
 obj-$(CONFIG_HW_RANDOM)		+= hw_random/
-obj-$(CONFIG_COBALT_LCD)	+= lcd.o
+obj-$(CONFIG_COBALT_MIPS_LCD)	+= lcd.o
 obj-$(CONFIG_PPDEV)		+= ppdev.o
 obj-$(CONFIG_NWBUTTON)		+= nwbutton.o
 obj-$(CONFIG_NWFLASH)		+= nwflash.o
diff -Nurb linux-2.6.24.3/drivers/char/misc.c linux-2.6.24.3-cobalt3-tw/drivers/char/misc.c
--- linux-2.6.24.3/drivers/char/misc.c	2008-02-25 16:20:20.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/char/misc.c	2008-03-02 14:55:48.000000000 -0800
@@ -50,6 +50,17 @@
 #include <linux/tty.h>
 #include <linux/kmod.h>
 
+#ifdef CONFIG_COBALT_RAQ
+#include <cobalt/cobalt.h>
+#include <cobalt/systype.h>
+#include <cobalt/superio.h>
+#include <cobalt/serialnum.h>
+#include <cobalt/i2c.h>
+#include <cobalt/misc.h>
+#include <cobalt/lcd.h>
+#endif
+
+
 /*
  * Head entry for the doubly linked miscdevice list
  */
@@ -64,6 +75,13 @@
 
 extern int pmu_device_init(void);
 
+#ifdef CONFIG_COBALT_RAQ
+extern int cobalt_init(void);
+#endif
+#ifdef CONFIG_COBALT_MIPS_LCD
+extern int lcd_init(void);
+#endif
+
 #ifdef CONFIG_PROC_FS
 static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
 {
@@ -273,7 +291,9 @@
 	misc_class = class_create(THIS_MODULE, "misc");
 	if (IS_ERR(misc_class))
 		return PTR_ERR(misc_class);
-
+#ifdef CONFIG_COBALT_MIPS_LCD
+	lcd_init();
+#endif
 	if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
 		printk("unable to get major %d for misc devices\n",
 		       MISC_MAJOR);
diff -Nurb linux-2.6.24.3/drivers/char/nvram.c linux-2.6.24.3-cobalt3-tw/drivers/char/nvram.c
--- linux-2.6.24.3/drivers/char/nvram.c	2008-02-25 16:20:20.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/char/nvram.c	2008-03-02 14:55:48.000000000 -0800
@@ -42,12 +42,18 @@
 
 #define PC		1
 #define ATARI		2
+#define COBALT		3
 
 /* select machine configuration */
 #if defined(CONFIG_ATARI)
 #  define MACH ATARI
 #elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)  /* and others?? */
+#  if defined(CONFIG_COBALT_RAQ)
+#    include <cobalt/nvram.h>
+#    define MACH COBALT
+#  else
 #  define MACH PC
+#  endif
 #else
 #  error Cannot build nvram driver for this machine configuration.
 #endif
@@ -69,6 +75,18 @@
 
 #endif
 
+#if MACH == COBALT
+
+#define CHECK_DRIVER_INIT()	1
+
+#define NVRAM_BYTES		(128-NVRAM_FIRST_BYTE)
+
+#define mach_check_checksum	cobalt_check_checksum
+#define mach_set_checksum	cobalt_set_checksum
+#define mach_proc_infos		cobalt_proc_infos
+
+#endif
+
 #if MACH == ATARI
 
 /* Special parameters for RTC in Atari machines */
@@ -585,6 +603,177 @@
 
 #endif /* MACH == PC */
 
+#if MACH == COBALT
+
+/* the cobalt CMOS has a wider range of its checksum */
+static int cobalt_check_checksum(void)
+{
+	int i;
+	unsigned short sum = 0;
+	unsigned short expect;
+
+	for (i = COBT_CMOS_CKS_START; i <= COBT_CMOS_CKS_END; ++i) {
+		if ((i == COBT_CMOS_CHECKSUM) || (i == (COBT_CMOS_CHECKSUM+1)))
+			continue;
+
+		sum += __nvram_read_byte(i);
+	}
+	expect = __nvram_read_byte(COBT_CMOS_CHECKSUM) << 8 |
+	    __nvram_read_byte(COBT_CMOS_CHECKSUM+1);
+	return ((sum & 0xffff) == expect);
+}
+
+static void cobalt_set_checksum(void)
+{
+	int i;
+	unsigned short sum = 0;
+
+	for (i = COBT_CMOS_CKS_START; i <= COBT_CMOS_CKS_END; ++i) {
+		if ((i == COBT_CMOS_CHECKSUM) || (i == (COBT_CMOS_CHECKSUM+1)))
+			continue;
+
+		sum += __nvram_read_byte(i);
+	}
+
+	__nvram_write_byte(sum >> 8, COBT_CMOS_CHECKSUM);
+	__nvram_write_byte(sum & 0xff, COBT_CMOS_CHECKSUM+1);
+}
+
+#ifdef CONFIG_PROC_FS
+
+static int cobalt_proc_infos(unsigned char *nvram, char *buffer, int *len,
+	off_t *begin, off_t offset, int size)
+{
+	int i;
+	unsigned int checksum;
+	unsigned int flags;
+	char sernum[14];
+	char *key = "cNoEbTaWlOtR!";
+	unsigned char bto_csum;
+
+	spin_lock_irq(&rtc_lock);
+	checksum = __nvram_check_checksum();
+	spin_unlock_irq(&rtc_lock);
+
+	PRINT_PROC("Checksum status: %svalid\n", checksum ? "" : "not ");
+
+	flags = nvram[COBT_CMOS_FLAG_BYTE_0] << 8
+	    | nvram[COBT_CMOS_FLAG_BYTE_1];
+
+	PRINT_PROC("Console: %s\n",
+		flags & COBT_CMOS_CONSOLE_FLAG ?  "on": "off");
+
+	PRINT_PROC("Firmware Debug Messages: %s\n",
+		flags & COBT_CMOS_DEBUG_FLAG ? "on": "off");
+
+	PRINT_PROC("Auto Prompt: %s\n",
+		flags & COBT_CMOS_AUTO_PROMPT_FLAG ? "on": "off");
+
+	PRINT_PROC("Shutdown Status: %s\n",
+		flags & COBT_CMOS_CLEAN_BOOT_FLAG ? "clean": "dirty");
+
+	PRINT_PROC("Hardware Probe: %s\n",
+		flags & COBT_CMOS_HW_NOPROBE_FLAG ? "partial": "full");
+
+	PRINT_PROC("System Fault: %sdetected\n",
+		flags & COBT_CMOS_SYSFAULT_FLAG ? "": "not ");
+
+	PRINT_PROC("Panic on OOPS: %s\n",
+		flags & COBT_CMOS_OOPSPANIC_FLAG ? "yes": "no");
+
+	PRINT_PROC("Delayed Cache Initialization: %s\n",
+		flags & COBT_CMOS_DELAY_CACHE_FLAG ? "yes": "no");
+
+	PRINT_PROC("Show Logo at Boot: %s\n",
+		flags & COBT_CMOS_NOLOGO_FLAG ? "no": "yes");
+
+	PRINT_PROC("Boot Method: ");
+	switch (nvram[COBT_CMOS_BOOT_METHOD]) {
+	case COBT_CMOS_BOOT_METHOD_DISK:
+		PRINT_PROC("disk\n");
+		break;
+
+	case COBT_CMOS_BOOT_METHOD_ROM:
+		PRINT_PROC("rom\n");
+		break;
+
+	case COBT_CMOS_BOOT_METHOD_NET:
+		PRINT_PROC("net\n");
+		break;
+
+	default:
+		PRINT_PROC("unknown\n");
+		break;
+	}
+
+	PRINT_PROC("Primary Boot Device: %d:%d\n",
+		nvram[COBT_CMOS_BOOT_DEV0_MAJ],
+		nvram[COBT_CMOS_BOOT_DEV0_MIN] );
+	PRINT_PROC("Secondary Boot Device: %d:%d\n",
+		nvram[COBT_CMOS_BOOT_DEV1_MAJ],
+		nvram[COBT_CMOS_BOOT_DEV1_MIN] );
+	PRINT_PROC("Tertiary Boot Device: %d:%d\n",
+		nvram[COBT_CMOS_BOOT_DEV2_MAJ],
+		nvram[COBT_CMOS_BOOT_DEV2_MIN] );
+
+	PRINT_PROC("Uptime: %d\n",
+		nvram[COBT_CMOS_UPTIME_0] << 24 |
+		nvram[COBT_CMOS_UPTIME_1] << 16 |
+		nvram[COBT_CMOS_UPTIME_2] << 8  |
+		nvram[COBT_CMOS_UPTIME_3]);
+
+	PRINT_PROC("Boot Count: %d\n",
+		nvram[COBT_CMOS_BOOTCOUNT_0] << 24 |
+		nvram[COBT_CMOS_BOOTCOUNT_1] << 16 |
+		nvram[COBT_CMOS_BOOTCOUNT_2] << 8  |
+		nvram[COBT_CMOS_BOOTCOUNT_3]);
+
+	/* 13 bytes of serial num */
+	for (i=0 ; i<13 ; i++) {
+		sernum[i] = nvram[COBT_CMOS_SYS_SERNUM_0 + i];
+	}
+	sernum[13] = '\0';
+
+	checksum = 0;
+	for (i=0 ; i<13 ; i++) {
+		checksum += sernum[i] ^ key[i];
+	}
+	checksum = ((checksum & 0x7f) ^ (0xd6)) & 0xff;
+
+	PRINT_PROC("Serial Number: %s", sernum);
+	if (checksum != nvram[COBT_CMOS_SYS_SERNUM_CSUM]) {
+		PRINT_PROC(" (invalid checksum)");
+	}
+	PRINT_PROC("\n");
+
+	PRINT_PROC("Rom Revison: %d.%d.%d\n", nvram[COBT_CMOS_ROM_REV_MAJ],
+		nvram[COBT_CMOS_ROM_REV_MIN], nvram[COBT_CMOS_ROM_REV_REV]);
+
+	PRINT_PROC("BTO Server: %d.%d.%d.%d", nvram[COBT_CMOS_BTO_IP_0],
+		nvram[COBT_CMOS_BTO_IP_1], nvram[COBT_CMOS_BTO_IP_2],
+		nvram[COBT_CMOS_BTO_IP_3]);
+	bto_csum = nvram[COBT_CMOS_BTO_IP_0] + nvram[COBT_CMOS_BTO_IP_1]
+		+ nvram[COBT_CMOS_BTO_IP_2] + nvram[COBT_CMOS_BTO_IP_3];
+	if (bto_csum != nvram[COBT_CMOS_BTO_IP_CSUM]) {
+		PRINT_PROC(" (invalid checksum)");
+	}
+	PRINT_PROC("\n");
+
+	if (flags & COBT_CMOS_VERSION_FLAG
+	 && nvram[COBT_CMOS_VERSION] >= COBT_CMOS_VER_BTOCODE) {
+		PRINT_PROC("BTO Code: 0x%x\n",
+			nvram[COBT_CMOS_BTO_CODE_0] << 24 |
+			nvram[COBT_CMOS_BTO_CODE_1] << 16 |
+			nvram[COBT_CMOS_BTO_CODE_2] << 8 |
+			nvram[COBT_CMOS_BTO_CODE_3]);
+	}
+
+	return 1;
+}
+#endif /* CONFIG_PROC_FS */
+
+#endif /* MACH == COBALT */
+
 #if MACH == ATARI
 
 static int
diff -Nurb linux-2.6.24.3/drivers/cobalt/acpi.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/acpi.c
--- linux-2.6.24.3/drivers/cobalt/acpi.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/acpi.c	2008-03-02 14:55:48.000000000 -0800
@@ -0,0 +1,1993 @@
+ /* 
+ * cobalt acpi driver 
+ * Copyright (c) 2000, Cobalt Networks, Inc.
+ * Copyright (c) 2001, Sun Microsystems, Inc.
+ * $Id: acpi.c,v 1.32 2002/06/26 19:08:54 duncan Exp $
+ *
+ * author: asun@cobalt.com, thockin@sun.com
+ * modified by: jeff@404ster.com
+ *
+ * this driver just sets stuff up for ACPI interrupts
+ *
+ * if acpi support really existed in the kernel, we would read
+ * data from the ACPI tables. however, it doesn't. as a result,
+ * we use some hardcoded values. 
+ *
+ * This should be SMP safe.  The only data that needs protection is the acpi
+ * handler list.  It gets scanned at timer-interrupts, must use
+ * irqsave/restore locks. Read/write locks would be useful if there were any
+ * other times that the list was read but never written. --TPH
+ *
+ * /proc/acpi emulation emulates the /proc/acpi/events interface supplied by 
+ * the INTEL acpi drivers.  A lot of the code to handle it has been adapted
+ * from there.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/proc_fs.h>
+#include <linux/poll.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <cobalt/cobalt.h>
+#include <cobalt/systype.h>
+#include <cobalt/acpi.h>
+#include <cobalt/superio.h>
+
+#define ACPI_DRIVER			"Cobalt Networks ACPI driver"
+#define ACPI_DRIVER_VMAJ		1
+#define ACPI_DRIVER_VMIN		0
+
+#define POWER_BUTTON_SHUTDOWN	0
+
+#define ACPI_IRQ	10	/* XXX: hardcoded interrupt */
+#define ACPI_NAME	"sci"
+#define ACPI_MAGIC	0xc0b7ac21
+
+#define SUPERIO_EVENT	0xff
+#define OSB4_EVENT	0x40
+#define OSB4_INDEX_PORT	SERVERWORKS_ACPI_INDEX_PORT
+#define OSB4_DATA_PORT	SERVERWORKS_ACPI_DATA_PORT
+
+#define GEN_ACPI_TMR_STS      (0x1 <<  0)
+#define GEN_ACPI_BM_STS       (0x1 <<  4)
+#define GEN_ACPI_GBL_STS      (0x1 <<  5)
+#define GEN_ACPI_PWRBTN_STS   (0x1 <<  8)
+#define GEN_ACPI_SLPBTN_STS   (0x1 <<  9)
+#define GEN_ACPI_RTC_STS      (0x1 << 10)
+#define GEN_ACPI_WAK_STS      (0x1 << 15)
+
+#ifdef CONFIG_COBALT_EMU_ACPI
+static int cobalt_acpi_setup_proc(void);
+static int cobalt_acpi_open_event(struct inode *inode, struct file *file);
+static int cobalt_acpi_close_event(struct inode *inode, struct file *file);
+static ssize_t cobalt_acpi_read_event(struct file *file, char *buf, 
+	size_t count, loff_t *ppos);
+static unsigned int cobalt_acpi_poll_event(struct file *file, poll_table *wait);
+#endif
+
+
+
+typedef struct 
+{
+    u16 hw_type;
+    cobalt_acpi_hw_handler hw_handler;
+    cobalt_acpi_enable_handler en_handler;
+    void *data;
+    struct list_head link;
+} hw_handler_datum;
+
+typedef struct 
+{
+    u16 hw_type;
+    u16 table_len;
+    u16 *table;
+    struct list_head link;
+} trans_table_datum;
+
+typedef struct 
+{
+    cobalt_acpi_evt_handler handler;
+    u16 ev_type;
+    void *data;
+    struct list_head link;
+} evt_handler_datum;
+
+typedef struct 
+{
+    cobalt_acpi_evt evt;
+    struct list_head link;
+} evt_list_datum;
+
+static LIST_HEAD( hw_handler_list );
+static spinlock_t hw_handler_list_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD( trans_table_list );
+static spinlock_t trans_table_list_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD( evt_handler_list );
+static spinlock_t evt_handler_list_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD( dispatch_queue );
+static spinlock_t dispatch_queue_lock = SPIN_LOCK_UNLOCKED;
+ 
+typedef struct
+{
+    u16 hw_type;
+
+	/* block lengths */
+    u16 pm1_evt_len;
+    u16 pm1_cnt_len;
+    u16 pm2_cnt_len;
+    u16 pm_tmr_len;
+    u16 gpe0_len;
+    u16 gpe1_len;
+    
+	/* block I/O locations */
+    u16 pm1a_evt_blk;
+    u16 pm1b_evt_blk;
+    u16 pm1a_cnt_blk;
+    u16 pm1b_cnt_blk;
+    u16 pm2_cnt_blk;
+    u16 pm_tmr_blk;
+    u16 p_blk;
+    u16 gpe0_blk;
+    u16 gpe1_blk;
+
+	/* ponters to strings for the io names */
+    char *pm1a_evt_nam;
+    char *pm1b_evt_nam;
+    char *pm1a_cnt_nam;
+    char *pm1b_cnt_nam;
+    char *pm2_cnt_nam;
+    char *pm_tmr_nam;
+    char *p_nam;
+    char *gpe0_nam;
+    char *gpe1_nam;
+
+	/* reference counts for events */
+    atomic_t tmr_ref_cnt;
+    atomic_t bm_ref_cnt;
+    atomic_t gbl_ref_cnt;
+    atomic_t pwrbtn_ref_cnt;
+    atomic_t slpbtn_ref_cnt;
+    atomic_t rtc_ref_cnt;
+    atomic_t wak_ref_cnt;
+    atomic_t *gpe_ref_cnt;
+
+
+} generic_acpi_regions;
+
+
+static void cobalt_acpi_enable_event( u16 ev_type, int en );
+static void cobalt_acpi_run_enable_handler( u16 hw_type, u16 ev_type, 
+					    u16 ev_data, int en);
+static int cobalt_acpi_apply_evt_handlers( evt_list_datum *d );
+static int cobalt_acpi_run_dispatch_queue( void );
+static irqreturn_t acpi_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void cobalt_acpi_cleanup( void );
+
+static int register_acpi_regions( generic_acpi_regions *regions, char * subsys_name );
+static int unregister_acpi_regions( generic_acpi_regions *regions );
+static void cobalt_acpi_handle_pm1_blk( u16 io_addr, u16 len, 
+					generic_acpi_regions * regions );
+static void cobalt_acpi_handle_gpe_blk( u16 io_addr, u16 len, 
+					generic_acpi_regions * regions );
+static int cobalt_acpi_generic_hw_handler( int irq, void *dev_id, 
+					   struct pt_regs *regs, void * data );
+
+static int cobalt_acpi_osb4_init( void );
+static int cobalt_acpi_osb4_cleanup( void );
+static int get_osb4_regions( generic_acpi_regions *regions);
+
+static int cobalt_acpi_csb5_init( void );
+static int cobalt_acpi_csb5_cleanup( void );
+static int get_csb5_regions( generic_acpi_regions *regions);
+
+static int cobalt_acpi_pc8731x_init( void );
+static int cobalt_acpi_pc8731x_cleanup( void );
+static int get_pc8731x_regions( generic_acpi_regions *regions );
+
+static int cobalt_acpi_pc8741x_init( void );
+static int cobalt_acpi_pc8741x_cleanup( void );
+static int get_pc8741x_regions( generic_acpi_regions *regions );
+
+static int cobalt_acpi_monterey_init( void );
+static int cobalt_acpi_monterey_cleanup( void );
+
+static int cobalt_acpi_alpine_init( void );
+static int cobalt_acpi_alpine_cleanup( void );
+
+static __inline__ struct list_head *list_pop( struct list_head *head )
+{
+    struct list_head *e;
+    
+    if( list_empty( head ) )
+	return NULL;
+    
+    e = head->next;
+    list_del( e );
+    return e;
+}
+
+static __inline__ u16 get_reg(u16 index, u16 data, u8 port)
+{
+    u16 reg;
+
+    outb(port, index);
+    reg = inb(data);
+    outb(port + 1, index);
+    reg |= inb(data) << 8;
+    return reg;
+}
+
+/*
+ *
+ * Main ACPI Subsystem Code
+ *
+ */
+
+extern int cobalt_acpi_register_hw_handler( u16 hw_type,
+					    cobalt_acpi_hw_handler hw_handler, 
+					    cobalt_acpi_enable_handler en_handler,
+					    void *data )
+{
+    hw_handler_datum *d;
+    unsigned long flags;
+
+    if( ! (d = (hw_handler_datum *) kmalloc( sizeof( hw_handler_datum ), GFP_ATOMIC )) )
+	return -ENOMEM;
+
+    d->hw_type = hw_type;
+    d->hw_handler = hw_handler;
+    d->en_handler = en_handler;
+    d->data = data;
+
+    spin_lock_irqsave( &hw_handler_list_lock, flags );
+    list_add( &(d->link), &hw_handler_list );
+    spin_unlock_irqrestore( &hw_handler_list_lock, flags );
+
+    return 0;
+}
+
+extern int cobalt_acpi_unregister_hw_handler( cobalt_acpi_hw_handler handler )
+{
+    struct list_head *pos;
+    unsigned long flags;
+    
+    spin_lock_irqsave( &hw_handler_list_lock, flags );
+    list_for_each( pos, &hw_handler_list )
+	{
+	    if( list_entry( pos, hw_handler_datum, link )->hw_handler == handler )
+	    {
+		list_del( pos );
+		spin_unlock_irqrestore( &hw_handler_list_lock, flags );
+
+		kfree( list_entry( pos, hw_handler_datum, link ) );
+		return 0;
+	    }
+		
+	};
+    
+    spin_unlock_irqrestore( &hw_handler_list_lock, flags );
+    return -1;
+}
+
+extern int cobalt_acpi_register_trans_table( u16 hw_type, u16 table_len, u16 *table )
+{
+    trans_table_datum *d;
+    unsigned long flags;
+    
+    if( ! (d = (trans_table_datum *) kmalloc( sizeof( trans_table_datum ), GFP_ATOMIC )) )
+	return -ENOMEM;
+
+    d->hw_type = hw_type;
+    d->table_len = table_len;
+    d->table = table;
+
+    spin_lock_irqsave( &trans_table_list_lock, flags );
+    list_add( &(d->link), &trans_table_list );
+    spin_unlock_irqrestore( &trans_table_list_lock, flags );
+
+    return 0;
+}
+
+extern int cobalt_acpi_unregister_trans_table( u16 hw_type )
+{
+    struct list_head *pos;
+    unsigned long flags;
+    
+    spin_lock_irqsave( &trans_table_list_lock, flags );
+    list_for_each( pos, &trans_table_list )
+	{
+	    if( list_entry( pos, trans_table_datum, link )->hw_type == hw_type )
+	    {
+		list_del( pos );
+		spin_unlock_irqrestore( &trans_table_list_lock, flags );
+		
+		kfree( list_entry( pos, trans_table_datum, link ) );
+		return 0;
+	    }
+		
+	};
+    
+    spin_unlock_irqrestore( &trans_table_list_lock, flags );
+    return -1;
+}
+
+extern int cobalt_acpi_register_evt_handler( cobalt_acpi_evt_handler handler, 
+					     u16 ev_type,
+					     void *data )
+{
+    evt_handler_datum *d;
+    unsigned long flags;
+    
+    if( ! (d = (evt_handler_datum *) kmalloc( sizeof( evt_handler_datum ), GFP_ATOMIC )) )
+	return -ENOMEM;
+
+    d->handler = handler;
+    d->data = data;
+    d->ev_type = ev_type;
+
+    spin_lock_irqsave( &evt_handler_list_lock, flags );
+    list_add( &(d->link), &evt_handler_list );
+    spin_unlock_irqrestore( &evt_handler_list_lock, flags );
+
+    cobalt_acpi_enable_event( ev_type, 1 );
+
+    return 0;
+}
+
+extern int cobalt_acpi_unregister_evt_handler( cobalt_acpi_evt_handler handler )
+{
+    struct list_head *pos;
+    unsigned long flags;
+    
+
+    spin_lock_irqsave( &evt_handler_list_lock, flags );
+    list_for_each( pos, &evt_handler_list )
+	{
+	    if( list_entry( pos, evt_handler_datum, link )->handler == handler )
+	    {
+		list_del( pos );
+		spin_unlock_irqrestore( &evt_handler_list_lock, flags );
+		
+		cobalt_acpi_enable_event( list_entry( pos, 
+						      evt_handler_datum, 
+						      link )->ev_type, 0 );
+
+		kfree( list_entry( pos, evt_handler_datum, link ) );
+		return 0;
+	    }
+		
+	};
+    
+    spin_unlock_irqrestore( &evt_handler_list_lock, flags );
+    return -EINVAL;
+}
+
+static void cobalt_acpi_enable_event( u16 ev_type, int en )
+{
+    if( ev_type >= 0x8000 )
+    {
+	struct list_head *pos;
+	trans_table_datum *d;
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave( &trans_table_list_lock, flags );
+	list_for_each( pos, &trans_table_list )
+	    {
+		d = list_entry( pos, trans_table_datum, link );
+		for( i=0 ; i<d->table_len ; i++ )
+		{
+		    if( d->table[i] == ev_type )
+		    {
+			cobalt_acpi_run_enable_handler( d->hw_type, 
+							COBALT_ACPI_EVT_GPE, 
+							i, en );
+		    }
+		}
+	    }
+	spin_unlock_irqrestore( &trans_table_list_lock, flags );
+    }
+    else
+	cobalt_acpi_run_enable_handler( COBALT_ACPI_HW_ANY, ev_type, 0, en);
+}
+
+static void cobalt_acpi_run_enable_handler( u16 hw_type, u16 ev_type, 
+					    u16 ev_data, int en)
+{   
+    struct list_head *pos;
+    unsigned long flags;
+    hw_handler_datum *d;
+
+    spin_lock_irqsave(&hw_handler_list_lock, flags);
+    list_for_each( pos, &hw_handler_list )
+	{
+	    d = list_entry( pos, hw_handler_datum, link );
+	    if( (!hw_type) || (d->hw_type == hw_type) )
+		d->en_handler( ev_type, ev_data, en, d->data );
+	}
+    spin_unlock_irqrestore(&hw_handler_list_lock, flags);
+    
+}
+
+static int cobalt_acpi_translate_event( cobalt_acpi_evt *evt )
+{
+    struct list_head *pos;
+    unsigned long flags;
+    trans_table_datum *d;
+
+    if( evt->ev_type != COBALT_ACPI_EVT_GPE )
+	return 0;
+
+    spin_lock_irqsave( &trans_table_list_lock, flags );
+    list_for_each( pos, &trans_table_list )
+	{
+	    d = list_entry( pos, trans_table_datum, link );
+	    if( d->hw_type == evt->hw_type )
+	    {
+		if( evt->ev_data >= d->table_len )
+		    goto err_out;
+
+		if( d->table[ evt->ev_data ] != COBALT_ACPI_EVT_NONE )
+		{
+		    evt->ev_type = d->table[ evt->ev_data ];
+		    evt->ev_data = 0;
+		}
+		
+		spin_unlock_irqrestore( &trans_table_list_lock, flags );
+		return 0;
+	    }
+	}
+
+  err_out:
+    spin_unlock_irqrestore( &trans_table_list_lock, flags );
+    return -1;
+}
+
+extern int cobalt_acpi_post_event( cobalt_acpi_evt evt )
+{
+    evt_list_datum *d;
+    unsigned long flags;
+    
+    if( ! (d = (evt_list_datum *) kmalloc( sizeof( evt_handler_datum ), GFP_ATOMIC )) )
+	return -ENOMEM;
+    
+
+    cobalt_acpi_translate_event( &evt );
+
+    memcpy( &(d->evt), &evt, sizeof(evt) );
+
+    spin_lock_irqsave( &dispatch_queue_lock, flags );
+    list_add_tail( &(d->link), &dispatch_queue );
+    spin_unlock_irqrestore( &dispatch_queue_lock, flags );
+
+    return 0;
+}
+
+static int cobalt_acpi_apply_evt_handlers( evt_list_datum *d )
+{
+    struct list_head *pos;
+    evt_handler_datum *evt_h;
+    int ret,err = 0;
+    unsigned long flags;
+    
+    spin_lock_irqsave( &evt_handler_list_lock, flags );
+    list_for_each( pos, &evt_handler_list )
+	{
+	    evt_h = list_entry( pos, evt_handler_datum, link );
+	    if( (! evt_h->ev_type) || (evt_h->ev_type == d->evt.ev_type) )
+	    {
+		if( (ret = evt_h->handler( &d->evt, evt_h->data )) < 0 )
+		    err = ret;
+	    }
+	}
+    spin_unlock_irqrestore( &evt_handler_list_lock, flags );
+
+    return err;
+}
+
+static int cobalt_acpi_run_dispatch_queue( void )
+{
+    struct list_head *pos;
+    int ret;
+    int err=0;
+    evt_list_datum *d;
+    unsigned long flags;
+
+    spin_lock_irqsave( &dispatch_queue_lock, flags );
+    while( (pos = list_pop( &dispatch_queue )) )
+    {
+	d = list_entry( pos, evt_list_datum, link );
+	if( (ret = cobalt_acpi_apply_evt_handlers( d )) < 0 )
+	    err = ret;
+#ifdef CONFIG_COBALT_EMU_ACPI
+	cobalt_acpi_generate_proc_evt( &d->evt );
+#endif
+	kfree( d );
+    }
+    spin_unlock_irqrestore( &dispatch_queue_lock, flags );
+
+    return err;
+}
+
+static irqreturn_t acpi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct list_head *pos;
+    hw_handler_datum *d;
+    int ret=0, err=0;
+    unsigned long flags;
+
+    spin_lock_irqsave(&hw_handler_list_lock, flags);
+    list_for_each( pos, &hw_handler_list )
+	{
+	    d = list_entry( pos, hw_handler_datum, link );
+	    if( (ret = d->hw_handler( irq, dev_id, regs, d->data )) < 0 )
+		err = ret;
+	    
+	}
+    spin_unlock_irqrestore(&hw_handler_list_lock, flags);
+
+    if( (err = cobalt_acpi_run_dispatch_queue()) < 0 )
+	err = ret;
+
+    if( err )
+	EPRINTK( "error at interrupt time of type %d.\n", err );
+
+    return IRQ_HANDLED;
+}
+
+
+
+
+int __init cobalt_acpi_init(void)
+{
+    int err;
+
+    printk(KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", ACPI_DRIVER,ACPI_DRIVER_VMAJ,ACPI_DRIVER_VMIN);
+    
+    if( cobt_is_monterey() )
+	cobalt_acpi_monterey_init();
+    else if( cobt_is_alpine() )
+	cobalt_acpi_alpine_init();
+
+    if( cobt_is_5k() )
+    {
+	if( pci_find_device(PCI_VENDOR_ID_SERVERWORKS, 
+			    PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL ) )
+	{
+	    if( (err = cobalt_acpi_osb4_init()) < 0 )
+	    {
+		goto cleanup;
+	    }
+	}
+	
+	if( pci_find_device(PCI_VENDOR_ID_SERVERWORKS, 
+			    PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL ) )
+	{
+	    if( (err = cobalt_acpi_csb5_init()) < 0 )
+	    {
+		goto cleanup;
+	    }
+	}
+
+	switch( superio_type() )
+	{
+	    case SIO_TYPE_PC8731X:
+		if( (err = cobalt_acpi_pc8731x_init()) )
+		{
+		    goto cleanup;
+		}
+		break;
+
+	    case SIO_TYPE_PC8741X:
+		if( (err = cobalt_acpi_pc8741x_init()) )
+		{
+		    goto cleanup;
+		}
+		break;
+
+	    case SIO_TYPE_UNKNOWN:
+		EPRINTK("unknown superio type\n");
+		break;
+	}
+	
+	    /* setup an interrupt handler for an ACPI SCI */
+	err = request_irq(ACPI_IRQ, acpi_interrupt, 
+			  SA_SHIRQ, ACPI_NAME, (void *)ACPI_MAGIC);
+	if (err) {
+	    EPRINTK("can't assign ACPI IRQ (%d)\n", ACPI_IRQ);
+	    return err;
+	}
+
+#ifdef CONFIG_COBALT_EMU_ACPI
+	cobalt_acpi_setup_proc();
+#endif
+    }
+
+	/* enable some events we may want */
+    cobalt_acpi_enable_event( COBALT_ACPI_EVT_PWRBTN, 1 );
+
+    return 0;
+    
+  cleanup:
+    cobalt_acpi_cleanup();
+    return err;
+}
+
+static void cobalt_acpi_cleanup( void )
+{
+    cobalt_acpi_osb4_cleanup();
+    cobalt_acpi_csb5_cleanup();
+    cobalt_acpi_pc8731x_cleanup();
+    cobalt_acpi_pc8741x_cleanup();
+
+    if( cobt_is_monterey() )
+	cobalt_acpi_monterey_cleanup();
+    if( cobt_is_alpine() )
+	cobalt_acpi_alpine_cleanup();
+}
+
+/*
+ *
+ * Generic ACPI HW Support
+ *
+ */
+
+static __inline__ char *region_name( char * subsys_name, char * blk_name )
+{
+    char * new_name;
+    
+    if( !( new_name = (char *) kmalloc( strlen(subsys_name) + strlen(blk_name) + 14,
+					GFP_ATOMIC)) )
+	return NULL;
+
+    sprintf( new_name, "%s (%s)", subsys_name, blk_name );
+    return new_name;
+}
+
+static void free_region_names( generic_acpi_regions *regions )
+{
+    if( regions->pm1a_evt_nam )
+	kfree( regions->pm1a_evt_nam );
+
+    if( regions->pm1b_evt_nam )
+	kfree( regions->pm1b_evt_nam );
+
+    if( regions->pm1a_cnt_nam )
+	kfree( regions->pm1a_cnt_nam );
+
+    if( regions->pm1b_cnt_nam )
+	kfree( regions->pm1b_cnt_nam );
+
+    if( regions->pm2_cnt_nam )
+	kfree( regions->pm2_cnt_nam );
+
+    if( regions->pm_tmr_nam )
+	kfree( regions->pm_tmr_nam );
+
+    if( regions->p_nam )
+	kfree( regions->p_nam );
+
+    if( regions->gpe0_nam )
+	kfree( regions->gpe0_nam );
+
+    if( regions->gpe1_nam )
+	kfree( regions->gpe1_nam );
+}
+
+static int register_acpi_regions( generic_acpi_regions *regions,  char * subsys_name )
+{
+    int i;
+    
+    if( regions->pm1a_evt_blk && regions->pm1_evt_len )
+    {
+	if( !(regions->pm1a_evt_nam = region_name( subsys_name, "pm1a_evt_blk" )) )
+	    goto cleanup0;
+
+	if( !request_region( regions->pm1a_evt_blk, regions->pm1_evt_len, 
+			     regions->pm1a_evt_nam ) )
+	    goto cleanup0;
+    }
+
+    if( regions->pm1b_evt_blk && regions->pm1_evt_len )
+    {
+	if( !(regions->pm1b_evt_nam = region_name( subsys_name, "pm1b_evt_blk" )) )
+	    goto cleanup0;
+
+	if( !request_region( regions->pm1b_evt_blk, regions->pm1_evt_len,
+			     regions->pm1b_evt_nam) )
+	    goto cleanup1;
+    }
+
+    if( regions->pm1a_cnt_blk && regions->pm1_cnt_len )
+    {
+	if( !(regions->pm1a_cnt_nam = region_name( subsys_name, "pm1a_cnt_blk" )) )
+	    goto cleanup1;
+
+	if( !request_region( regions->pm1a_cnt_blk, regions->pm1_cnt_len,
+			     regions->pm1a_cnt_nam ) )
+	    goto cleanup2;
+    }
+
+    if( regions->pm1b_cnt_blk && regions->pm1_cnt_len )
+    {
+	if( !(regions->pm1b_cnt_nam = region_name( subsys_name, "pm1b_cnt_blk" )) )
+	    goto cleanup2;
+
+	if( !request_region( regions->pm1b_cnt_blk, regions->pm1_cnt_len,
+			     regions->pm1b_cnt_nam ) )
+	    goto cleanup3;
+    }
+
+    if( regions->pm2_cnt_blk && regions->pm2_cnt_len )
+    {
+	if( !(regions->pm2_cnt_nam = region_name( subsys_name, "pm2_cnt_blk" )) )
+	    goto cleanup3;
+
+	if( !request_region( regions->pm2_cnt_blk, regions->pm2_cnt_len,
+			     regions->pm2_cnt_nam ) )
+	    goto cleanup4;
+    }
+
+    if( regions->pm_tmr_blk && regions->pm_tmr_len )
+    {
+	if( !(regions->pm_tmr_nam = region_name( subsys_name, "pm_tmp_blk" )) )
+	    goto cleanup4;
+
+	if( !request_region( regions->pm_tmr_blk, regions->pm_tmr_len,
+			     regions->pm_tmr_nam ) )
+	    goto cleanup5;
+    }
+
+    if( regions->p_blk )
+    {
+	if( !(regions->p_nam = region_name( subsys_name, "p_blk" )) )
+	    goto cleanup5;
+
+	if( !request_region( regions->p_blk, 6, regions->p_nam ) )
+	    goto cleanup6;
+    }
+
+    if( regions->gpe0_blk && regions->gpe0_len )
+    {
+	if( !(regions->gpe0_nam = region_name( subsys_name, "gpe0_blk" )) )
+	    goto cleanup6;
+
+	if( !request_region( regions->gpe0_blk, regions->gpe0_len, 
+			     regions->gpe0_nam ) )
+	    goto cleanup7;
+    }
+
+    if( regions->gpe1_blk && regions->gpe1_len )
+    {
+	if( !(regions->gpe1_nam = region_name( subsys_name, "gpe1_blk" )) )
+	    goto cleanup7;
+
+	if( !request_region( regions->gpe1_blk, regions->gpe1_len,
+			     regions->gpe1_nam ) )
+	    goto cleanup8;
+    }
+
+    if( (regions->gpe_ref_cnt = (atomic_t *) kmalloc( sizeof( atomic_t ) * 
+						      regions->gpe0_len * 8,
+						      GFP_ATOMIC)) == NULL )
+	goto cleanup9;
+
+    memset( regions->gpe_ref_cnt, 0x0, sizeof( atomic_t ) * regions->gpe0_len * 8 );
+
+	/* disable all events and ack them */
+    if( regions->pm1a_evt_blk )
+    {
+	outw( 0x0000, regions->pm1a_evt_blk + regions->pm1_evt_len/2 );
+	outw( 0xffff, regions->pm1a_evt_blk );
+    }
+
+    if( regions->pm1b_evt_blk )
+    {
+	outw( 0x0000, regions->pm1b_evt_blk + regions->pm1_evt_len/2 );
+	outw( 0xffff, regions->pm1b_evt_blk );
+    }
+
+    if( regions->gpe0_blk )
+    {
+	for( i=0 ; i<(regions->gpe0_len/2) ; i++ )
+	{
+	    outb( 0x00, regions->gpe0_blk + regions->gpe0_len/2 + i );
+	    outb( 0xff, regions->gpe0_blk + i );
+	}
+    }
+
+    if( regions->gpe1_blk )
+    {
+	for( i=0 ; i<(regions->gpe1_len/2) ; i++ )
+	{
+	    outb( 0x00, regions->gpe1_blk + regions->gpe1_len/2 + i );
+	    outb( 0xff, regions->gpe1_blk + i );
+	}
+    }
+
+    return 0;
+	
+  cleanup9:
+    if( regions->gpe1_blk )
+    {
+	release_region( regions->gpe1_blk, regions->gpe1_len );
+	regions->gpe1_blk = 0;
+    }
+
+  cleanup8:
+    if( regions->gpe0_blk )
+    {
+	release_region( regions->gpe0_blk, regions->gpe0_len );
+	regions->gpe0_blk = 0;
+    }
+
+  cleanup7:
+    if( regions->p_blk )
+    {
+	release_region( regions->p_blk, 6 );
+	regions->p_blk = 0;
+    }
+
+  cleanup6:
+    if( regions->pm_tmr_blk )
+    {
+	release_region( regions->pm_tmr_blk, regions->pm_tmr_len );
+	regions->pm_tmr_blk = 0;
+    }
+
+  cleanup5:
+    if( regions->pm2_cnt_blk )
+    {
+	release_region( regions->pm2_cnt_blk, regions->pm2_cnt_len );
+	regions->pm2_cnt_blk = 0;
+    }
+
+  cleanup4:
+    if( regions->pm1b_cnt_blk )
+    {
+	release_region( regions->pm1b_cnt_blk, regions->pm1_cnt_len );
+	regions->pm1b_cnt_blk = 0;
+    }
+
+  cleanup3:
+    if( regions->pm1a_cnt_blk )
+    {
+	release_region( regions->pm1a_cnt_blk, regions->pm1_cnt_len );
+	regions->pm1a_cnt_blk = 0;
+    }
+
+  cleanup2:
+    if( regions->pm1b_evt_blk )
+    {
+	release_region( regions->pm1b_evt_blk, regions->pm1_evt_len );
+	regions->pm1b_evt_blk = 0;
+    }
+
+  cleanup1:
+    if( regions->pm1a_evt_blk )
+    {
+	release_region( regions->pm1a_evt_blk, regions->pm1_evt_len );
+	regions->pm1a_evt_blk = 0;
+    }
+
+  cleanup0:
+    free_region_names( regions );
+    
+    return -EBUSY;
+}
+
+static int unregister_acpi_regions( generic_acpi_regions *regions )
+{
+    if( regions->pm1a_evt_blk && regions->pm1_evt_len )
+    {
+	release_region( regions->pm1a_evt_blk, regions->pm1_evt_len );
+	regions->pm1a_evt_blk = 0;
+    }
+    
+    if( regions->pm1b_evt_blk && regions->pm1_evt_len )
+    {
+	release_region( regions->pm1b_evt_blk, regions->pm1_evt_len );
+	regions->pm1b_evt_blk = 0;
+    }
+
+    if( regions->pm1a_cnt_blk && regions->pm1_cnt_len )
+    {
+	release_region( regions->pm1a_cnt_blk, regions->pm1_cnt_len );
+	regions->pm1a_cnt_blk = 0;
+    }
+
+    if( regions->pm1b_cnt_blk && regions->pm1_cnt_len )
+    {
+	release_region( regions->pm1b_cnt_blk, regions->pm1_cnt_len );
+	regions->pm1b_cnt_blk = 0;
+    }
+
+    if( regions->pm2_cnt_blk && regions->pm2_cnt_len )
+    {
+	release_region( regions->pm2_cnt_blk, regions->pm2_cnt_len );
+	regions->pm2_cnt_blk = 0;
+    }
+
+    if( regions->pm_tmr_blk && regions->pm_tmr_len )
+    {
+	release_region( regions->pm_tmr_blk, regions->pm_tmr_len );
+	regions->pm_tmr_blk = 0;
+    }
+
+    if( regions->p_blk )
+    {
+	release_region( regions->p_blk, 6 );
+	regions->p_blk = 0;
+    }
+
+    if( regions->gpe0_blk && regions->gpe0_len )
+    {
+	release_region( regions->gpe0_blk, regions->gpe0_len );
+	regions->gpe0_blk = 0;
+    }
+
+    if( regions->gpe1_blk && regions->gpe1_len )
+    {
+	release_region( regions->gpe1_blk, regions->gpe1_len );
+	regions->gpe1_blk = 0;
+    }
+
+    if( regions->gpe_ref_cnt )
+	kfree( regions->gpe_ref_cnt );
+    
+    free_region_names( regions );
+
+    return 0;
+}
+
+static void cobalt_acpi_handle_pm1_blk( u16 io_addr, u16 len, 
+				       generic_acpi_regions * regions )
+{
+    cobalt_acpi_evt evt;
+    u16 sts, en;
+    
+    evt.hw_type = regions->hw_type;
+    
+    if( (sts = inw( io_addr )) &&
+	(en  = inw( io_addr + len/2 )) )
+    {
+
+
+	    /* clear status bits */
+	outw( sts, io_addr);
+
+	if( (en  & GEN_ACPI_TMR_STS) &&
+	    (sts & GEN_ACPI_TMR_STS) )
+	{
+	    evt.ev_type = COBALT_ACPI_EVT_TMR;
+	    evt.ev_data = 0x0;
+	    cobalt_acpi_post_event( evt );
+	}
+	if( (en & GEN_ACPI_BM_STS) &&
+	    (sts & GEN_ACPI_BM_STS) )
+	{
+	    evt.ev_type = COBALT_ACPI_EVT_BM;
+	    evt.ev_data = 0x0;
+	    cobalt_acpi_post_event( evt );
+	}
+	if( (en  & GEN_ACPI_GBL_STS) &&
+	    (sts & GEN_ACPI_GBL_STS) )
+	{
+	    evt.ev_type = COBALT_ACPI_EVT_GBL;
+	    evt.ev_data = 0x0;
+	    cobalt_acpi_post_event( evt );
+	}
+	if( (en  & GEN_ACPI_PWRBTN_STS) &&
+	    (sts & GEN_ACPI_PWRBTN_STS) )
+	{
+	    evt.ev_type = COBALT_ACPI_EVT_PWRBTN;
+	    evt.ev_data = 0x0;
+	    cobalt_acpi_post_event( evt );
+	}
+	if( (en  & GEN_ACPI_SLPBTN_STS) &&
+	    (sts & GEN_ACPI_SLPBTN_STS) )
+	{
+	    evt.ev_type = COBALT_ACPI_EVT_SLPBTN;
+	    evt.ev_data = 0x0;
+	    cobalt_acpi_post_event( evt );
+	}
+	if( (en & GEN_ACPI_RTC_STS) &&
+	    (sts & GEN_ACPI_RTC_STS) )
+	{
+	    evt.ev_type = COBALT_ACPI_EVT_RTC;
+	    evt.ev_data = 0x0;
+	    cobalt_acpi_post_event( evt );
+	}
+	if( (sts & GEN_ACPI_WAK_STS) )
+	{
+	    evt.ev_type = COBALT_ACPI_EVT_WAK;
+	    evt.ev_data = 0x0;
+	    cobalt_acpi_post_event( evt );
+	}
+    }
+}
+
+static void cobalt_acpi_handle_gpe_blk( u16 io_addr, u16 len, 
+					generic_acpi_regions * regions )
+{
+    cobalt_acpi_evt evt;
+    int i,j;
+    u8 sts, en;
+    
+    evt.hw_type = regions->hw_type;
+    evt.ev_type = COBALT_ACPI_EVT_GPE;
+
+    for( i=0 ; i<(len/2) ; i++ )
+    {
+	sts = inb( io_addr + i );
+	en =  inb( io_addr + len/2 + i );
+
+	    /* clear status bits */
+	outb( sts, io_addr);
+
+	for( j=0 ; j<8 ; j++ )
+	{
+	    if( (en  & 0x1) &&
+		(sts & 0x1) )
+	    {
+		evt.ev_data = i*8 + j;
+		cobalt_acpi_post_event( evt );
+	    }
+	    en >>= 1;
+	    sts >>= 1;
+	}
+    }
+}
+
+static int cobalt_acpi_generic_hw_handler( int irq, void *dev_id, 
+					   struct pt_regs *regs, void * data )
+{
+    generic_acpi_regions * regions = (generic_acpi_regions *) data;
+    cobalt_acpi_evt evt;
+
+    evt.hw_type = regions->hw_type;
+
+	/* various PM events */
+    if( regions->pm1a_evt_blk )
+	cobalt_acpi_handle_pm1_blk( regions->pm1a_evt_blk, regions->pm1_evt_len, regions );
+
+    if( regions->pm1b_evt_blk )
+	cobalt_acpi_handle_pm1_blk( regions->pm1b_evt_blk, regions->pm1_evt_len, regions );
+
+    if( regions->gpe0_blk )
+	cobalt_acpi_handle_gpe_blk( regions->gpe0_blk, regions->gpe0_len, regions );
+
+    if( regions->gpe1_blk )
+	cobalt_acpi_handle_gpe_blk( regions->gpe1_blk, regions->gpe1_len, regions );
+	
+
+    return 0;
+}
+
+static int cobalt_acpi_generic_en_handler( u16 ev_type, u16 ev_data, int en, void *data )
+{
+    generic_acpi_regions * regions = (generic_acpi_regions *) data;
+    int block, offset;
+    u8 data8;
+    u16 data16;
+    
+    switch( ev_type )
+    {
+	case COBALT_ACPI_EVT_TMR:
+	    data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) );
+	    
+	    if( en )
+	    {
+		data16 |= GEN_ACPI_TMR_STS;
+		atomic_inc( &regions->tmr_ref_cnt );
+	    }
+	    else
+	    {
+		if( atomic_dec_and_test( &regions->tmr_ref_cnt ) )
+		    data16 &= ~GEN_ACPI_TMR_STS;
+	    }
+	    outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) );
+	    break;
+	    
+	case COBALT_ACPI_EVT_BM:
+	    data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) );
+	    
+	    if( en )
+	    {
+		data16 |= GEN_ACPI_BM_STS;
+		atomic_inc( &regions->bm_ref_cnt );
+	    }
+	    else
+	    {
+		if( atomic_dec_and_test( &regions->bm_ref_cnt ) )
+		    data16 &= ~GEN_ACPI_BM_STS;
+	    }
+	    outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) );
+	    break;
+	    
+	case COBALT_ACPI_EVT_GBL:
+	    data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) );
+	    
+	    if( en )
+	    {
+		data16 |= GEN_ACPI_GBL_STS;
+		atomic_inc( &regions->gbl_ref_cnt );
+	    }
+	    else
+	    {
+		if( atomic_dec_and_test( &regions->gbl_ref_cnt ) )
+		    data16 &= ~GEN_ACPI_GBL_STS;
+	    }
+	    outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) );
+	    break;
+	    
+	case COBALT_ACPI_EVT_PWRBTN:
+	    data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) );
+	    
+	    if( en )
+	    {
+		data16 |= GEN_ACPI_PWRBTN_STS;
+		atomic_inc( &regions->pwrbtn_ref_cnt );
+	    }
+	    else
+	    {
+		if( atomic_dec_and_test( &regions->pwrbtn_ref_cnt ) )
+		    data16 &= ~GEN_ACPI_PWRBTN_STS;
+	    }
+	    outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) );
+	    break;
+	    
+	case COBALT_ACPI_EVT_SLPBTN:
+	    data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) );
+	    
+	    if( en )
+	    {
+		data16 |= GEN_ACPI_SLPBTN_STS;
+		atomic_inc( &regions->slpbtn_ref_cnt );
+	    }
+	    else
+	    {
+		if( atomic_dec_and_test( &regions->slpbtn_ref_cnt ) )
+		    data16 &= ~GEN_ACPI_SLPBTN_STS;
+	    }
+	    outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) );
+	    break;
+	    
+	case COBALT_ACPI_EVT_RTC:
+	    data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) );
+	    
+	    if( en )
+	    {
+		data16 |= GEN_ACPI_RTC_STS;
+		atomic_inc( &regions->rtc_ref_cnt );
+	    }
+	    else
+	    {
+		if( atomic_dec_and_test( &regions->rtc_ref_cnt ) )
+		    data16 &= ~GEN_ACPI_RTC_STS;
+	    }
+	    outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) );
+	    break;
+	    
+	case COBALT_ACPI_EVT_WAK:
+	    data16 = inw( regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) );
+	    
+	    if( en )
+	    {
+		data16 |= GEN_ACPI_WAK_STS;
+		atomic_inc( &regions->wak_ref_cnt );
+	    }
+	    else
+	    {
+		if( atomic_dec_and_test( &regions->wak_ref_cnt ) )
+		    data16 &= ~GEN_ACPI_WAK_STS;
+	    }
+	    outw( data16, regions->pm1a_evt_blk + (regions->pm1_evt_len / 2) );
+	    break;
+	    
+	case COBALT_ACPI_EVT_GPE:
+	    if( (ev_data/8) >= (regions->gpe0_len / 2) )
+		return -EINVAL;
+	    
+	    block = ev_data / 8;
+	    offset = ev_data % 8;
+	    
+	    data8 = inb( regions->gpe0_blk + (regions->gpe0_len / 2) + block );
+	    
+	    if( en )
+	    {
+		data8 |= 0x1 << offset;
+		atomic_inc( &regions->gpe_ref_cnt[ev_data] );
+	    }
+	    else
+	    {
+		if( atomic_dec_and_test( &regions->gpe_ref_cnt[ev_data] ) )
+		    data8 &= ~( 0x1 << offset );
+	    }
+	    
+	    outb( data8, regions->gpe0_blk + (regions->gpe0_len / 2) + block );
+	    
+	    break;
+	    
+	default:
+	    return -EINVAL;
+		    
+    }
+
+    return 0;
+}
+
+/*
+ *
+ * Generic ServerWorks region code
+ *
+ */
+
+static int get_serverworks_regions( generic_acpi_regions *regions, u16 type )
+{
+   int reg;
+    
+    memset( regions, 0x0, sizeof( *regions ) );
+    
+    regions->hw_type = type;
+
+    regions->pm1_evt_len = 4;
+    regions->pm1_cnt_len = 2;
+    regions->pm_tmr_len = 4;
+    regions->gpe0_len = 8;
+
+    if( (reg = get_reg(OSB4_INDEX_PORT, OSB4_DATA_PORT, 0x20)) )
+    	regions->pm1a_evt_blk = (u16) reg;
+    
+    if( (reg = get_reg(OSB4_INDEX_PORT, OSB4_DATA_PORT, 0x22)) )
+	regions->pm1a_cnt_blk = (u16) reg;
+    
+    if( (reg = get_reg(OSB4_INDEX_PORT, OSB4_DATA_PORT, 0x24)) )
+	regions->pm_tmr_blk = (u16) reg;
+    
+    if( (reg = get_reg(OSB4_INDEX_PORT, OSB4_DATA_PORT, 0x26)) )
+	regions->p_blk = (u16) reg;
+    
+    if( (reg = get_reg(OSB4_INDEX_PORT, OSB4_DATA_PORT, 0x28)) )
+	regions->gpe0_blk = (u16) reg;
+
+    if( type == COBALT_ACPI_HW_OSB4 )
+    {
+	regions->pm2_cnt_len = 1;
+	if( (reg = get_reg(OSB4_INDEX_PORT, OSB4_DATA_PORT, 0x2E)) )
+	    regions->pm2_cnt_blk = (u16) reg;
+    }
+
+    switch( type )
+    {
+	case COBALT_ACPI_HW_OSB4:
+	    return register_acpi_regions( regions, "OSB4" );
+
+	case COBALT_ACPI_HW_CSB5:
+	    return register_acpi_regions( regions, "CSB5" );
+    }
+    
+    return -EINVAL;
+
+}
+
+/*
+ *
+ * ServerWorks OSB4
+ *
+ */
+
+static generic_acpi_regions osb4_regions;
+
+static int cobalt_acpi_osb4_init( void )
+{
+    int err;
+    
+    if( (err = get_osb4_regions( &osb4_regions )) < 0 )
+	return err;
+
+    if( (err = cobalt_acpi_register_hw_handler( COBALT_ACPI_HW_OSB4,
+						cobalt_acpi_generic_hw_handler, 
+						cobalt_acpi_generic_en_handler, 
+						&osb4_regions )) < 0 )
+	return err;
+
+    return 0;
+}
+
+static int cobalt_acpi_osb4_cleanup( void )
+{
+    unregister_acpi_regions( &osb4_regions );
+    return 0;
+}
+
+static int get_osb4_regions( generic_acpi_regions *regions)
+{
+    return get_serverworks_regions( regions, COBALT_ACPI_HW_OSB4 );
+}
+
+/*
+ *
+ * ServerWorks CSB5
+ *
+ */
+
+/* static generic_acpi_regions csb5_regions; */
+
+static generic_acpi_regions csb5_regions;
+
+static int cobalt_acpi_csb5_init( void )
+{
+    int err;
+    
+    if( (err = get_csb5_regions( &csb5_regions )) < 0 )
+	return err;
+
+    if( (err = cobalt_acpi_register_hw_handler( COBALT_ACPI_HW_CSB5,
+						cobalt_acpi_generic_hw_handler, 
+						cobalt_acpi_generic_en_handler, 
+						&csb5_regions )) < 0 )
+	return err;
+
+    return 0;
+}
+
+static int cobalt_acpi_csb5_cleanup( void )
+{
+    unregister_acpi_regions( &csb5_regions );
+    return 0;
+}
+
+static int get_csb5_regions( generic_acpi_regions *regions)
+{
+    return get_serverworks_regions( regions, COBALT_ACPI_HW_CSB5 );
+}
+
+/*
+ *
+ * NatSemi PC8731x
+ *
+ */
+static generic_acpi_regions pc8731x_regions;
+
+static int cobalt_acpi_pc8731x_init( void )
+{
+    int err;
+    
+    if( (err = get_pc8731x_regions( &pc8731x_regions )) < 0 )
+	return err;
+
+    if( (err = cobalt_acpi_register_hw_handler( COBALT_ACPI_HW_PC8731X,
+						cobalt_acpi_generic_hw_handler, 
+						cobalt_acpi_generic_en_handler, 
+						&pc8731x_regions )) < 0 )
+	return err;
+
+    return 0;
+}
+
+static int cobalt_acpi_pc8731x_cleanup( void )
+{
+    unregister_acpi_regions( &pc8731x_regions );
+    return 0;
+}
+
+static int get_pc8731x_regions( generic_acpi_regions *regions )
+{
+    int reg;
+    u16 addr;
+    
+    memset( regions, 0x0, sizeof( *regions ) );
+
+    regions->hw_type = COBALT_ACPI_HW_PC8731X;
+
+    regions->pm1_evt_len = 4;
+    regions->pm1_cnt_len = 2;
+    regions->pm_tmr_len = 4;
+    regions->gpe0_len = 4;
+    
+	/* superi/o -- select pm logical device and get base address */
+    addr = superio_ldev_base(PC87317_DEV_PM);
+    if( addr )
+    {
+	    /* get registers */
+	if( (reg = get_reg(addr, addr + 1, 0x08)) )
+	    regions->pm1a_evt_blk = reg;
+
+	if( (reg = get_reg(addr, addr + 1, 0x0a)) )
+	    regions->pm_tmr_blk = reg;
+
+	if( (reg = get_reg(addr, addr + 1, 0x0c)) )
+	    regions->pm1a_cnt_blk = reg;
+
+	if( (reg = get_reg(addr, addr + 1, 0x0e)) )
+	    regions->gpe0_blk = reg;
+    }
+    
+    return register_acpi_regions( regions, "pc8731x" );
+}
+
+/*
+ *
+ * NatSemi PC8741x
+ *
+ */
+
+static generic_acpi_regions pc8741x_regions;
+
+static int cobalt_acpi_pc8741x_init( void )
+{
+    int err;
+    
+    if( (err = get_pc8741x_regions( &pc8741x_regions )) < 0 )
+	return err;
+
+    if( (err = cobalt_acpi_register_hw_handler( COBALT_ACPI_HW_PC8741X,
+						cobalt_acpi_generic_hw_handler, 
+						cobalt_acpi_generic_en_handler, 
+						&pc8741x_regions )) < 0 )
+	return err;
+
+    return 0;
+}
+
+static int cobalt_acpi_pc8741x_cleanup( void )
+{
+    unregister_acpi_regions( &pc8741x_regions );
+    return 0;
+}
+
+static int get_pc8741x_regions( generic_acpi_regions *regions )
+{
+    int reg;
+    
+    memset( regions, 0x0, sizeof( *regions ) );
+
+    regions->hw_type = COBALT_ACPI_HW_PC8741X;
+
+    regions->pm1_evt_len = 4;
+    regions->pm1_cnt_len = 2;
+    regions->pm_tmr_len = 4;
+    regions->gpe0_len = 8;
+    
+	/* get registers */
+    if( (reg = superio_ldev_base_n(PC87417_DEV_SWC, 1)) )
+	regions->pm1a_evt_blk = reg;
+
+    if( (reg = superio_ldev_base_n(PC87417_DEV_SWC, 2)) )
+	regions->pm1a_cnt_blk = reg;
+
+    if( (reg = superio_ldev_base_n(PC87417_DEV_SWC, 3)) )
+	regions->gpe0_blk = reg;
+
+    return register_acpi_regions( regions, "pc8741x" );
+}
+
+/*
+ *
+ * Platform support
+ * 
+ */
+
+/*
+ *
+ * Monterey
+ *
+ */
+
+static u16 cobalt_acpi_monterey_osb4_table[] = {
+/* GPE  0 */ COBALT_ACPI_EVT_NONE,
+/* GPE  1 */ COBALT_ACPI_EVT_NONE,
+/* GPE  2 */ COBALT_ACPI_EVT_NONE,
+/* GPE  3 */ COBALT_ACPI_EVT_NONE,
+/* GPE  4 */ COBALT_ACPI_EVT_NONE,
+/* GPE  5 */ COBALT_ACPI_EVT_NONE,
+/* GPE  6 */ COBALT_ACPI_EVT_SLED,
+/* GPE  7 */ COBALT_ACPI_EVT_NONE,
+/* GPE  8 */ COBALT_ACPI_EVT_NONE,
+/* GPE  9 */ COBALT_ACPI_EVT_NONE,
+/* GPE 10 */ COBALT_ACPI_EVT_NONE,
+/* GPE 11 */ COBALT_ACPI_EVT_NONE,
+/* GPE 12 */ COBALT_ACPI_EVT_NONE,
+/* GPE 13 */ COBALT_ACPI_EVT_NONE,
+/* GPE 14 */ COBALT_ACPI_EVT_NONE,
+/* GPE 15 */ COBALT_ACPI_EVT_NONE };
+
+static u16 cobalt_acpi_monterey_superio_table[] = {
+/* GPE  0 */ COBALT_ACPI_EVT_NONE,
+/* GPE  1 */ COBALT_ACPI_EVT_NONE,
+/* GPE  2 */ COBALT_ACPI_EVT_NONE,
+/* GPE  3 */ COBALT_ACPI_EVT_NONE,
+/* GPE  4 */ COBALT_ACPI_EVT_NONE,
+/* GPE  5 */ COBALT_ACPI_EVT_NONE,
+/* GPE  6 */ COBALT_ACPI_EVT_NONE,
+/* GPE  7 */ COBALT_ACPI_EVT_NONE,
+/* GPE  8 */ COBALT_ACPI_EVT_NONE,
+/* GPE  9 */ COBALT_ACPI_EVT_NONE,
+/* GPE 10 */ COBALT_ACPI_EVT_NONE,
+/* GPE 11 */ COBALT_ACPI_EVT_NONE,
+/* GPE 12 */ COBALT_ACPI_EVT_NONE,
+/* GPE 13 */ COBALT_ACPI_EVT_NONE,
+/* GPE 14 */ COBALT_ACPI_EVT_NONE,
+/* GPE 15 */ COBALT_ACPI_EVT_NONE,
+/* GPE 16 */ COBALT_ACPI_EVT_NONE,
+/* GPE 17 */ COBALT_ACPI_EVT_NONE,
+/* GPE 18 */ COBALT_ACPI_EVT_NONE,
+/* GPE 19 */ COBALT_ACPI_EVT_NONE,
+/* GPE 20 */ COBALT_ACPI_EVT_NONE,
+/* GPE 21 */ COBALT_ACPI_EVT_NONE,
+/* GPE 22 */ COBALT_ACPI_EVT_NONE,
+/* GPE 23 */ COBALT_ACPI_EVT_NONE,
+/* GPE 24 */ COBALT_ACPI_EVT_NONE,
+/* GPE 25 */ COBALT_ACPI_EVT_NONE,
+/* GPE 26 */ COBALT_ACPI_EVT_NONE,
+/* GPE 27 */ COBALT_ACPI_EVT_NONE,
+/* GPE 28 */ COBALT_ACPI_EVT_NONE,
+/* GPE 29 */ COBALT_ACPI_EVT_NONE,
+/* GPE 30 */ COBALT_ACPI_EVT_NONE,
+/* GPE 31 */ COBALT_ACPI_EVT_NONE };
+
+static int cobalt_acpi_monterey_init( void )
+{
+    int err;
+    
+    err = cobalt_acpi_register_trans_table( COBALT_ACPI_HW_OSB4, 
+					    sizeof( cobalt_acpi_monterey_osb4_table )/sizeof( u16 ),
+					    cobalt_acpi_monterey_osb4_table );			      
+    if( err < 0 )
+	return err;
+
+    err = cobalt_acpi_register_trans_table( COBALT_ACPI_HW_PC8731X, 
+					    sizeof( cobalt_acpi_monterey_superio_table )/sizeof( u16 ),
+					    cobalt_acpi_monterey_superio_table );
+    if( err < 0 )
+	return err;
+
+    return 0;
+}
+
+static int cobalt_acpi_monterey_cleanup( void )
+{
+    cobalt_acpi_unregister_trans_table( COBALT_ACPI_HW_OSB4 );
+    cobalt_acpi_unregister_trans_table( COBALT_ACPI_HW_PC8731X );
+
+    return 0;
+}
+
+/*
+ *
+ * Alpine
+ *
+ */
+
+static u16 cobalt_acpi_alpine_csb5_table[] = {
+/* GPE  0 */ COBALT_ACPI_EVT_NONE,
+/* GPE  1 */ COBALT_ACPI_EVT_NONE,
+/* GPE  2 */ COBALT_ACPI_EVT_NONE,
+/* GPE  3 */ COBALT_ACPI_EVT_FAN,
+/* GPE  4 */ COBALT_ACPI_EVT_NONE,
+/* GPE  5 */ COBALT_ACPI_EVT_SM_INT,
+/* GPE  6 */ COBALT_ACPI_EVT_THERM,
+/* GPE  7 */ COBALT_ACPI_EVT_NONE,
+/* GPE  8 */ COBALT_ACPI_EVT_NONE,
+/* GPE  9 */ COBALT_ACPI_EVT_NONE,
+/* GPE 10 */ COBALT_ACPI_EVT_NONE,
+/* GPE 11 */ COBALT_ACPI_EVT_NONE,
+/* GPE 12 */ COBALT_ACPI_EVT_NONE,
+/* GPE 13 */ COBALT_ACPI_EVT_NONE,
+/* GPE 14 */ COBALT_ACPI_EVT_NONE,
+/* GPE 15 */ COBALT_ACPI_EVT_NONE };
+
+static u16 cobalt_acpi_alpine_superio_table[] = {
+/* GPE  0 */ COBALT_ACPI_EVT_NONE,
+/* GPE  1 */ COBALT_ACPI_EVT_NONE,
+/* GPE  2 */ COBALT_ACPI_EVT_NONE,
+/* GPE  3 */ COBALT_ACPI_EVT_NONE,
+/* GPE  4 */ COBALT_ACPI_EVT_NONE,
+/* GPE  5 */ COBALT_ACPI_EVT_NONE,
+/* GPE  6 */ COBALT_ACPI_EVT_NONE,
+/* GPE  7 */ COBALT_ACPI_EVT_NONE,
+/* GPE  8 */ COBALT_ACPI_EVT_NONE,
+/* GPE  9 */ COBALT_ACPI_EVT_NONE,
+/* GPE 10 */ COBALT_ACPI_EVT_NONE,
+/* GPE 11 */ COBALT_ACPI_EVT_NONE,
+/* GPE 12 */ COBALT_ACPI_EVT_NONE,
+/* GPE 13 */ COBALT_ACPI_EVT_NONE,
+/* GPE 14 */ COBALT_ACPI_EVT_NONE,
+/* GPE 15 */ COBALT_ACPI_EVT_NONE,
+/* GPE 16 */ COBALT_ACPI_EVT_NONE,
+/* GPE 17 */ COBALT_ACPI_EVT_NONE,
+/* GPE 18 */ COBALT_ACPI_EVT_NONE,
+/* GPE 19 */ COBALT_ACPI_EVT_NONE,
+/* GPE 20 */ COBALT_ACPI_EVT_NONE,
+/* GPE 21 */ COBALT_ACPI_EVT_NONE,
+/* GPE 22 */ COBALT_ACPI_EVT_NONE,
+/* GPE 23 */ COBALT_ACPI_EVT_NONE,
+/* GPE 24 */ COBALT_ACPI_EVT_NONE,
+/* GPE 25 */ COBALT_ACPI_EVT_NONE,
+/* GPE 26 */ COBALT_ACPI_EVT_NONE,
+/* GPE 27 */ COBALT_ACPI_EVT_NONE,
+/* GPE 28 */ COBALT_ACPI_EVT_NONE,
+/* GPE 29 */ COBALT_ACPI_EVT_NONE,
+/* GPE 30 */ COBALT_ACPI_EVT_NONE,
+/* GPE 31 */ COBALT_ACPI_EVT_NONE };
+
+static int cobalt_acpi_alpine_init( void )
+{
+    int err;
+    
+    err = cobalt_acpi_register_trans_table( COBALT_ACPI_HW_CSB5, 
+					    sizeof( cobalt_acpi_alpine_csb5_table )/sizeof( u16 ),
+					    cobalt_acpi_alpine_csb5_table );			      
+    if( err < 0 )
+	return err;
+
+    err = cobalt_acpi_register_trans_table( COBALT_ACPI_HW_PC8741X, 
+					    sizeof( cobalt_acpi_alpine_superio_table )/sizeof( u16 ),
+					    cobalt_acpi_alpine_superio_table );
+    if( err < 0 )
+	return err;
+
+    return 0;
+}
+
+static int cobalt_acpi_alpine_cleanup( void )
+{
+    cobalt_acpi_unregister_trans_table( COBALT_ACPI_HW_CSB5 );
+    cobalt_acpi_unregister_trans_table( COBALT_ACPI_HW_PC8741X );
+
+    return 0;
+}
+
+/*
+ * end platform support
+ */
+#ifdef CONFIG_COBALT_EMU_ACPI
+/*
+ * This is all necessary because we don't have BIOS support for ACPI yet.
+ * We can fake it here, and when full support is ready just yank this.
+ */
+typedef struct {
+	char *device_type;
+	char *device_instance;
+	u32 event_type;
+	u32 event_data;
+	struct list_head list;
+} cobalt_acpi_event_t;
+
+#define COBALT_ACPI_MAX_STRING_LENGTH	80
+
+static LIST_HEAD(cobalt_acpi_event_list);
+static DECLARE_WAIT_QUEUE_HEAD(cobalt_acpi_event_wait_queue);
+static int event_is_open = 0;
+static spinlock_t cobalt_acpi_event_lock = SPIN_LOCK_UNLOCKED;
+
+static struct proc_dir_entry *cobalt_acpi_proc_root;
+static struct proc_dir_entry *cobalt_acpi_proc_event;
+
+static struct file_operations proc_event_ops = {
+	open: cobalt_acpi_open_event,
+	read: cobalt_acpi_read_event,
+	release: cobalt_acpi_close_event,
+	poll: cobalt_acpi_poll_event,
+};
+
+static int
+cobalt_acpi_setup_proc(void)
+{
+	cobalt_acpi_proc_root = proc_mkdir("acpi", NULL);
+	if (!cobalt_acpi_proc_root) {
+		return -ENOMEM;
+	}
+
+	cobalt_acpi_proc_event = create_proc_entry("event", S_IRUSR, 
+						cobalt_acpi_proc_root);
+	if (!cobalt_acpi_proc_event) {
+		return -ENOMEM;
+	}
+
+	cobalt_acpi_proc_event->proc_fops = &proc_event_ops;
+ 
+	return 0;
+}
+
+
+int
+cobalt_acpi_generate_proc_evt( cobalt_acpi_evt * evt )
+{
+	cobalt_acpi_event_t *event = NULL, *tmp;
+	unsigned long flags = 0;
+	char *dev_type;
+	char *dev_instance;
+	u32 event_type;
+	u32 event_data;
+	struct list_head *pos;
+
+	/* drop event on the floor if no one's listening */
+	if (!event_is_open)
+		return 0;
+	
+	event_type = (evt->ev_type << 0x10) |
+	    evt->hw_type;
+	event_data = evt->ev_data;
+
+
+	    /*
+	     * Check to see if an event of this type is already
+	     * pending
+	     */
+	spin_lock_irqsave(&cobalt_acpi_event_lock, flags);
+	list_for_each( pos, &cobalt_acpi_event_list )
+	    {
+		tmp = list_entry(pos, cobalt_acpi_event_t, list);
+		if( (tmp->event_type == event_type) &&
+		    (tmp->event_data == event_data) )
+		{
+		    spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags);
+		    return 0;
+		}
+
+
+	    }
+	spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags);
+
+
+	    /* parse the event struct */
+	switch( evt->ev_type )
+	{
+	    case COBALT_ACPI_EVT_TMR:
+		dev_type = "generic";
+		dev_instance = "timer";
+		break;
+
+	    case COBALT_ACPI_EVT_BM:
+		dev_type = "generic";
+		dev_instance = "bus-master";
+		break;
+		
+	    case COBALT_ACPI_EVT_GBL:
+		dev_type = "generic";
+		dev_instance = "global";
+		break;	    
+		
+	    case COBALT_ACPI_EVT_PWRBTN:
+		dev_type = "button";
+		dev_instance = "power";
+		break;	    
+
+	    case COBALT_ACPI_EVT_SLPBTN:
+		dev_type = "button";
+		dev_instance = "sleep";
+		break;	    
+		
+	    case COBALT_ACPI_EVT_RTC:
+		dev_type = "generic";
+		dev_instance = "rtc";
+		break;	    
+
+	    case COBALT_ACPI_EVT_WAK:
+		dev_type = "generic";
+		dev_instance = "wake";
+		break;	    
+
+	    case COBALT_ACPI_EVT_GPE:
+		dev_type = "generic";
+		dev_instance = "gpe";
+		break;	    
+
+	    case COBALT_ACPI_EVT_SLED:
+		dev_type = "cobalt";
+		dev_instance = "sled";
+		break;	    
+		
+	    case COBALT_ACPI_EVT_THERM:
+		dev_type = "cobalt";
+		dev_instance = "therm_trip";
+		break;
+
+	    case COBALT_ACPI_EVT_FAN:
+		dev_type = "cobalt";
+		dev_instance = "fan";
+		break;
+
+	    case COBALT_ACPI_EVT_SM_INT:
+		dev_type = "cobalt";
+		dev_instance = "sm_int";
+		break;
+
+	    case COBALT_ACPI_EVT_VOLT:
+		dev_type = "cobalt";
+		dev_instance = "volt_trip";
+		break;
+		
+	    default:
+		dev_type = "unknown";
+		dev_instance = "unknown";
+		break;
+	}
+	      
+		
+	/*
+	 * Allocate a new event structure.
+	 */
+	event = kmalloc(sizeof(*event), GFP_ATOMIC);
+	if (!event)
+		goto alloc_error;
+
+	event->device_type=NULL;
+	event->device_instance=NULL;
+
+	event->device_type = kmalloc(strlen(dev_type) + sizeof(char), 
+		GFP_ATOMIC);
+	if (!event->device_type)
+		goto alloc_error;
+
+	event->device_instance = kmalloc(strlen(dev_instance) + sizeof(char), 
+		GFP_ATOMIC );
+	if (!event->device_instance)
+		goto alloc_error;
+
+	/*
+	 * Set event data.
+	 */
+	strcpy(event->device_type, dev_type);
+	strcpy(event->device_instance, dev_instance);
+	event->event_type = event_type;
+	event->event_data = event_data;
+
+	/*
+	 * Add to the end of our event list.
+	 */
+	spin_lock_irqsave(&cobalt_acpi_event_lock, flags);
+	list_add_tail(&event->list, &cobalt_acpi_event_list);
+	spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags);
+
+	/*
+	 * Signal waiting threads (if any).
+	 */
+	wake_up_interruptible(&cobalt_acpi_event_wait_queue);
+
+	return 0;
+
+alloc_error:
+	if(event)
+	{
+	    if (event->device_instance)
+		kfree(event->device_instance);
+	    
+	    if (event->device_type)
+		kfree(event->device_type);
+	    
+	    kfree(event);		
+	}
+
+	return -ENOMEM;
+}
+
+
+static int 
+cobalt_acpi_open_event(struct inode *inode, struct file *file)
+{
+    unsigned long flags;
+    spin_lock_irqsave(&cobalt_acpi_event_lock, flags);
+
+    if (event_is_open)
+	goto out_busy;
+
+    event_is_open = 1;
+    
+    spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags);
+    return 0;
+
+out_busy:
+    spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags);
+    return -EBUSY;
+}
+
+
+static int 
+cobalt_acpi_close_event(struct inode *inode, struct file *file)
+{
+    unsigned long flags;
+    struct list_head *pos;
+    cobalt_acpi_event_t *tmp;
+    
+    spin_lock_irqsave(&cobalt_acpi_event_lock, flags);
+
+    while( (pos = list_pop( &cobalt_acpi_event_list )) )
+    {
+	tmp = list_entry(pos, cobalt_acpi_event_t, list);
+	if (tmp->device_instance)
+		kfree(tmp->device_instance);
+	    
+	if (tmp->device_type)
+		kfree(tmp->device_type);
+	
+	kfree( tmp );
+    }
+    event_is_open = 0;
+    spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags);
+    return 0;
+}
+
+#define ACPI_MAX_STRING_LENGTH		80
+static ssize_t
+cobalt_acpi_read_event(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+	cobalt_acpi_event_t *event = NULL;
+	unsigned long flags = 0;
+	static char str[ACPI_MAX_STRING_LENGTH];
+	static int strsize;
+	static char *ptr;
+
+	if (!strsize) {
+		DECLARE_WAITQUEUE(wait, current);
+
+		if (list_empty(&cobalt_acpi_event_list)) {
+			if (file->f_flags & O_NONBLOCK) {
+				return -EAGAIN;
+			}
+			set_current_state(TASK_INTERRUPTIBLE);
+			add_wait_queue(&cobalt_acpi_event_wait_queue, &wait);
+	
+			if (list_empty(&cobalt_acpi_event_list)) {
+				schedule();
+			}
+	
+			remove_wait_queue(&cobalt_acpi_event_wait_queue, &wait);
+			set_current_state(TASK_RUNNING);
+	 
+			if (signal_pending(current)) {
+				return -ERESTARTSYS;
+			}
+		}
+
+		spin_lock_irqsave(&cobalt_acpi_event_lock, flags);
+		event = list_entry(cobalt_acpi_event_list.next, 
+			cobalt_acpi_event_t, list);
+		list_del(&event->list);
+		spin_unlock_irqrestore(&cobalt_acpi_event_lock, flags);
+
+		strsize = sprintf(str, "%s %s %08x %08x\n",
+			event->device_type, event->device_instance,
+			event->event_type, event->event_data);
+		ptr = str;
+
+		kfree(event->device_type);
+		kfree(event->device_instance);
+		kfree(event);
+	}
+	if (strsize < count)
+		count = strsize;
+
+	if (copy_to_user(buf, ptr, count))
+		return -EFAULT;
+
+	*ppos += count;
+	strsize -= count;
+	ptr += count;
+
+	return count;
+}
+
+static unsigned int 
+cobalt_acpi_poll_event(struct file *file, poll_table *wait)
+{
+	poll_wait(file, &cobalt_acpi_event_wait_queue, wait);
+	if (!list_empty(&cobalt_acpi_event_list))
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+#endif /* CONFIG_COBALT_EMU_ACPI */
diff -Nurb linux-2.6.24.3/drivers/cobalt/fans.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/fans.c
--- linux-2.6.24.3/drivers/cobalt/fans.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/fans.c	2008-03-02 14:55:48.000000000 -0800
@@ -0,0 +1,418 @@
+/* $Id: fans.c,v 1.18 2002/03/16 21:33:02 duncan Exp $
+ * Copyright (c) 2000-2001 Sun Microsystems, Inc 
+ *
+ * This should be SMP safe.  The critical data (the info list) and the
+ * critical code (inb()/outb() calls) are protected by fan_lock.  It is 
+ * locked at the only external access points - the proc read()/write() 
+ * methods. --TPH
+ */
+#if defined(CONFIG_COBALT_FANS) || defined(CONFIG_COBALT_FANS_MODULE)
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/time.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <cobalt/cobalt.h>
+#include <cobalt/systype.h>
+
+#define FAN_DRIVER      "Cobalt Networks Fan driver"
+#define FAN_DRIVER_VMAJ 1
+#define FAN_DRIVER_VMIN 0
+
+/* GPIO base is assigned by BIOS, perhaps we should probe it */
+#define GPIO_BASE		0x600
+#define FAN_GPIO_MAX		8
+#define FAN_RPM(fn,ms)		((fn).hcyl * (60000000 / (fn).poles) / (ms))
+#define FAN_VALID(f)		((f)->mask && (f)->poles)
+#define FAN_CACHE_TIME		2 /* seconds */
+#define FAN_SAMPLE_LEN		50 /* milliseconds */
+
+/* 
+ * fans are attached to GPIO pins
+ * each pin is part of a port, multiple fans are controlled by a port
+ */
+struct fan_info {
+	int id;			/* fan number */
+	uint8_t mask;		/* mask within the port */
+	int poles;		/* # of magnetic poles (divisor) */
+	int hcyl;		/* # of half cycles */
+	unsigned rpm;		/* calculated fan speed */
+	char *type;		/* FAN description */
+};
+
+struct fan_gpio {
+	int port;		/* GPIO Port */
+	uint16_t base;		/* GPDI (data in) base address */
+	uint8_t latch;		/* latched 'data in' value */
+	long tcache;		/* latched 'epoch' value */
+	struct fan_info fan[FAN_GPIO_MAX];
+};
+
+/* the current fanlist */
+static struct fan_gpio *sys_fanlist;
+static spinlock_t fan_lock = SPIN_LOCK_UNLOCKED;
+
+static struct fan_gpio fan_gpio_raqxtr[] = {
+	{
+		port: 1,
+		base: GPIO_BASE,
+		fan: {
+			{ mask: 0x2, poles: 4, type: "processor" },
+			{ mask: 0x4, poles: 4, type: "processor" },
+			{ mask: 0 },
+		},
+	},
+	{
+		port: 2,
+		base: GPIO_BASE+4,
+		fan: {
+			{ mask: 0x10, poles: 4 },
+			{ mask: 0x20, poles: 4 },
+			{ mask: 0x40, poles: 4 },
+			{ mask: 0x80, poles: 4 },
+			{ mask: 0 },
+		},
+	},
+	{ port: -1 }
+};
+
+static struct fan_gpio fan_gpio_alpine[] = {
+	{
+		port: 2,
+		base: GPIO_BASE+7,
+		fan:  {
+			{ mask: 0x4, poles: 4 },
+			{ mask: 0x8, poles: 4 },
+			{ mask: 0x10, poles: 4 },
+			{ mask: 0x20, poles: 4, type: "power supply" },
+			{ mask: 0x40, poles: 4, type: "processor" },
+			{ mask: 0 },
+		},
+	},
+	{ port: -1 }
+};
+
+#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_COBALT_OLDPROC
+static struct proc_dir_entry *proc_faninfo;
+#endif /* CONFIG_COBALT_OLDPROC */
+static struct proc_dir_entry *proc_cfaninfo;
+#endif /* CONFIG_PROC_FS */
+
+static struct fan_info *fan_info_find(int id);
+static int fan_control(struct fan_info *fi, int todo);
+static int fan_info_print(char *buffer);
+static int fan_read_proc(char *buf, char **start, off_t pos,
+			 int len, int *eof, void *x);
+static int fan_write_proc(struct file *file, const char *buf,
+			  unsigned long len, void *x);
+
+int __init 
+cobalt_fan_init(void)
+{
+	if (cobt_is_monterey()) {
+		sys_fanlist = (struct fan_gpio *)fan_gpio_raqxtr;
+	} else if (cobt_is_alpine()) {
+		sys_fanlist = (struct fan_gpio *)fan_gpio_alpine;
+	} else {
+		sys_fanlist = NULL;
+		return -ENOSYS;
+	}
+
+    printk(KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", FAN_DRIVER,FAN_DRIVER_VMAJ,FAN_DRIVER_VMIN);
+    
+#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_COBALT_OLDPROC
+	proc_faninfo = create_proc_entry("faninfo", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, NULL);
+	if (!proc_faninfo) {
+		EPRINTK("can't create /proc/faninfo\n");
+		return -ENOENT;
+	}
+	proc_faninfo->owner = THIS_MODULE;
+	proc_faninfo->read_proc = fan_read_proc;
+	proc_faninfo->write_proc = fan_write_proc;
+#endif /* CONFIG_COBALT_OLDPROC */
+	proc_cfaninfo = create_proc_entry("faninfo", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, proc_cobalt);
+	if (!proc_cfaninfo) {
+		EPRINTK("can't create /proc/cobalt/faninfo\n");
+		return -ENOENT;
+	}
+	proc_cfaninfo->owner = THIS_MODULE;
+	proc_cfaninfo->read_proc = fan_read_proc;
+	proc_cfaninfo->write_proc = fan_write_proc;
+#endif /* CONFIG_PROC_FS */
+
+	return 0;
+}
+
+static void __exit
+cobalt_fan_exit(void)
+{
+#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_COBALT_OLDPROC
+	if (proc_faninfo) {
+		remove_proc_entry("faninfo", NULL);
+	}
+#endif /* CONFIG_COBALT_OLDPROC */
+	if (proc_cfaninfo) {
+		remove_proc_entry("faninfo", proc_cobalt);
+	}
+#endif /* CONFIG_PROC_FS */
+
+	sys_fanlist = NULL;
+}
+
+/*
+ * Samples fan tachometer square wave to calculate and report RPM
+ */
+static int 
+get_faninfo(char *buffer)
+{
+	struct fan_gpio *fg;
+	struct timeval utime;
+	unsigned long elapsed, start;
+	int i, val, len;
+
+	if (!sys_fanlist || !cobt_is_5k()) {
+		/* software is keyed off this string - do not change it ! */
+		return sprintf(buffer, "Fan monitoring not supported.\n");
+	}
+
+	/* save start timestamp */
+	do_gettimeofday(&utime);
+	start = utime.tv_usec;
+
+	/* initialize 'previous' values. we do edge detection by
+	 * looking for transitions from previous values */
+	for (fg = sys_fanlist; fg->port >= 0; fg++) {
+		if (fg->tcache && utime.tv_sec < fg->tcache+FAN_CACHE_TIME) {
+			return fan_info_print(buffer);
+		}
+		fg->tcache = utime.tv_sec;
+		fg->latch = inb(fg->base);
+		for (i = 0; i < FAN_GPIO_MAX; i++) {
+			fg->fan[i].hcyl = 0;
+			fg->fan[i].rpm = 0;
+		}
+	}
+
+	/* We are counting the number of halfcycles in a square wave
+	 * that pass in a given amount of time to determine frequency */
+	do {
+		for (fg=sys_fanlist; fg->port>=0; fg++) {
+			val = inb(fg->base);
+			for (i=0; i<FAN_GPIO_MAX; i++) {
+				struct fan_info *p = &fg->fan[i];
+				if (FAN_VALID(p)) {
+					if ((val ^ fg->latch) & p->mask) {
+						p->hcyl++;
+					}
+				}
+			}
+			fg->latch = val;
+		}
+
+		do_gettimeofday(&utime);
+		if (utime.tv_usec > start) {
+			elapsed = utime.tv_usec - start;
+		} else {
+			elapsed = utime.tv_usec + 1000001 - start;
+		}
+
+	} while (elapsed < (FAN_SAMPLE_LEN) * 1000);
+
+	/* Fan rpm = 60 / ( t * poles )
+	 *  where t is 1/2 the period and poles are the number of 
+	 *  magnetic poles for the fan.
+	 *  
+	 * For the Sunon KDE1204PKBX fans on Raq XTR, poles = 4
+	 * So, in terms of cycles,
+	 *
+	 *  rpm = 60 s/m    halfcycles       
+	 *        ------ *  -------------- * 1,000,000 us/s * 2
+	 *        4         2 * elapsed us
+	 *
+	 *      = (60,000,000 / 4 poles) * halfcycles / elapsed
+	 *      = 15,000,000 * halfcycles / elapsed
+	 *
+	 * Note, by this method and sampling for 50ms, our accuracy
+	 *  is +/- 300 rpm.  The fans are spec'ed for +/- 1000 rpm 
+	 */
+	for (val=len=0, fg=sys_fanlist; fg->port>=0; fg++) {
+		for (i=0; i<FAN_GPIO_MAX; i++) {
+			struct fan_info *p = &fg->fan[i];
+			if (FAN_VALID(p)) {
+				p->id = val++;
+				p->rpm = FAN_RPM(fg->fan[i], elapsed);
+				len += sprintf(buffer+len, "fan %d     : %u\n",
+					p->id, p->rpm);
+			}
+		}
+	}
+
+	return len;
+}
+
+static int
+fan_info_print(char *buffer)
+{
+	struct fan_gpio *fg;
+	int i, len=0;
+
+	if (!sys_fanlist) {
+		return -1;
+	}
+
+	for (fg=sys_fanlist; fg->port>=0; fg++) {
+		for (i=0; i<FAN_GPIO_MAX; i++) {
+			struct fan_info *p = &fg->fan[i];
+			if (FAN_VALID(p)) {
+				len += sprintf(buffer+len, "fan %d     : %u\n",
+					p->id, p->rpm);
+			}
+		}
+	}
+
+	return len;
+}
+
+/* FIXME: generify */
+static int
+fan_control(struct fan_info *fi, int todo)
+{
+	if (fi && cobt_is_alpine()) {
+		switch (fi->id) {
+		case 4:	{
+			/* CPU FAN */
+			uint8_t gpdo = inb(GPIO_BASE+6);
+
+			if (todo) {
+				gpdo &= ~fi->mask; /* 0 = on */
+			} else {
+				gpdo |= fi->mask;  /* 1 = off */
+			}
+			outb(gpdo, GPIO_BASE+6);
+			return 0;
+		}
+		default:
+			return -ENODEV;
+		}
+	}
+
+	return -ENOSYS;
+}
+
+static struct fan_info *
+fan_info_find(int id)
+{
+	struct fan_gpio *fg;
+	int i;
+
+	if (!sys_fanlist) {
+		return NULL;
+	}
+
+	for (fg=sys_fanlist; fg->port>=0; fg++) {
+		for (i=0; i<FAN_GPIO_MAX; i++) {
+			if (FAN_VALID(&fg->fan[i])) {
+				if (fg->fan[i].id == id) {
+					return &fg->fan[i];
+				}
+			}
+		}
+	}
+
+	return NULL;
+}
+
+#ifdef CONFIG_PROC_FS
+static int 
+fan_read_proc(char *buf, char **start, off_t pos, int len, int *eof, void *x)
+{
+	int plen;
+
+	//MOD_INC_USE_COUNT;
+
+	spin_lock(&fan_lock);
+	plen = get_faninfo(buf);
+	spin_unlock(&fan_lock);
+
+	//MOD_DEC_USE_COUNT;
+
+	return cobalt_gen_proc_read(buf, plen, start, pos, len, eof);
+}
+
+static int
+fan_write_proc(struct file *file, const char *buf, unsigned long len, void *x)
+{
+	char *page;
+	int retval = -EINVAL;
+
+	//MOD_INC_USE_COUNT;
+
+	if (len > PAGE_SIZE) {
+		//MOD_DEC_USE_COUNT;
+		return -EOVERFLOW;
+	}
+
+	page = (char *)__get_free_page(GFP_KERNEL);
+	if (!page) {
+		//MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
+
+	if (copy_from_user(page, buf, len)) {
+		free_page((unsigned long)page);
+		//MOD_DEC_USE_COUNT;
+		return -EFAULT;
+	}
+	page[len] = '\0';
+
+	/* format: `fan ID COMMAND' */
+	if (len>5 && !strncmp("fan ", page, 4)) {
+		if (*(page+4) != '\0') {
+			struct fan_info *finf;
+			char *nextpg = NULL;
+
+			spin_lock(&fan_lock);
+			finf = fan_info_find(simple_strtoul(page+4,&nextpg,0));
+			if (!finf) {
+				retval = -ENOENT;
+			} else if (nextpg != '\0') {
+				if (!strncmp("on", nextpg+1, 2)) {
+					retval = fan_control(finf, 1);
+				}
+				else if (!strncmp("off", nextpg+1, 3)) {
+					retval = fan_control(finf, 0);
+				}
+			}
+			spin_unlock(&fan_lock);
+		}
+	}
+
+	free_page((unsigned long)page);
+	//MOD_DEC_USE_COUNT;
+	
+	return (retval < 0) ? retval : len;
+}
+#endif /* CONFIG_PROC_FS */
+
+#if defined(CONFIG_COBALT_FANS_MODULE)
+module_init(cobalt_fan_init);
+module_exit(cobalt_fan_exit);
+
+MODULE_AUTHOR("Sun Cobalt");
+MODULE_DESCRIPTION("Sun Cobalt fan tachometers");
+#endif
+
+#endif /* CONFIG_COBALT_FANS || CONFIG_COBALT_FANS_MODULE */
diff -Nurb linux-2.6.24.3/drivers/cobalt/i2c.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/i2c.c
--- linux-2.6.24.3/drivers/cobalt/i2c.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/i2c.c	2008-03-02 14:55:48.000000000 -0800
@@ -0,0 +1,518 @@
+/*
+ * $Id: i2c.c,v 1.19 2002/09/17 23:41:29 sparker Exp $
+ * i2c.c : Cobalt I2C driver support
+ *
+ * Copyright (C) 2000 Cobalt Networks, Inc. 
+ * Copyright (C) 2001 Sun Microsystems, Inc. 
+ *
+ * Modified By: jeff@404ster.com
+ *
+ * This should be SMP safe.  All the exported functions lock on enter and
+ * unlock on exit.  These exported functions may be called at interupt time,
+ * so we have to use the IRQ safe locks.  NOTE: no function herein may call 
+ * any exported function herein. --TPH
+ */
+#include <stddef.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <asm/io.h>
+
+#include <cobalt/cobalt.h>
+#include <cobalt/i2c.h>
+#include <cobalt/systype.h>
+
+#define I2C_3K_STATUS			0x00
+#define I2C_3K_CMD			0x01
+#define I2C_3K_START			0x02
+#define I2C_3K_ADDR			0x03
+#define I2C_3K_LOW_DATA			0x04
+#define I2C_3K_HIGH_DATA		0x05
+#define I2C_3K_BLOCK_DATA		0x06
+#define I2C_3K_INDEX			0x07
+#define I2C_3K_STATUS_IDLE		0x04
+#define I2C_3K_CMD_RW_BYTE		0x20
+#define I2C_3K_CMD_RW_WORD		0x30
+#define I2C_3K_CMD_RW_BLOCK		0xC0
+#define I2C_3K_CMD_RESET_PTR		0x80
+
+#define I2C_5K_HOST_STATUS		0x00
+#define I2C_5K_SLAVE_STATUS		0x01
+#define I2C_5K_HOST_CONTROL		0x02
+#define I2C_5K_HOST_COMMAND		0x03
+#define I2C_5K_HOST_ADDR		0x04
+#define I2C_5K_DATA_0			0x05
+#define I2C_5K_DATA_1			0x06
+#define I2C_5K_BLOCK_DATA		0x07
+#define I2C_5K_SLAVE_CONTROL		0x08
+#define I2C_5K_SHADOW_COMMAND		0x09
+#define I2C_5K_SLAVE_EVENT		0x0a
+#define I2C_5K_SLAVE_DATA		0x0c
+#define I2C_5K_HOST_STATUS_BUSY		0x01
+#define I2C_5K_HOST_CMD_START		0x40
+#define I2C_5K_HOST_CMD_QUICK_RW	(0 << 2)
+#define I2C_5K_HOST_CMD_BYTE_RW		(1 << 2)
+#define I2C_5K_HOST_CMD_BYTE_DATA_RW	(2 << 2)
+#define I2C_5K_HOST_CMD_WORD_DATA_RW	(3 << 2)
+#define I2C_5K_HOST_CMD_BLOCK_DATA_RW	(5 << 2)
+
+#define I2C_WRITE			0
+#define I2C_READ			1
+
+/* this delay was determined empirically */
+#define I2C_WRITE_UDELAY                1000
+
+struct cobalt_i2c_data {
+	const unsigned char status;
+	const unsigned char addr;
+	const unsigned char index;
+	const unsigned char data_low;
+	const unsigned char data_high;
+	const unsigned char data_block;
+	const unsigned char rw_byte;
+	const unsigned char rw_word;
+	const unsigned char rw_block;
+	unsigned int io_port;
+};
+
+struct cobalt_i2c_data cobalt_i2c_3k = {
+	I2C_3K_STATUS,
+	I2C_3K_ADDR,
+	I2C_3K_INDEX,
+	I2C_3K_LOW_DATA,
+	I2C_3K_HIGH_DATA,
+	I2C_3K_BLOCK_DATA,
+	I2C_3K_CMD_RW_BYTE,
+	I2C_3K_CMD_RW_WORD,
+	I2C_3K_CMD_RW_BLOCK,
+	0L
+};
+
+struct cobalt_i2c_data cobalt_i2c_5k = {
+	I2C_5K_HOST_STATUS,
+	I2C_5K_HOST_ADDR,
+	I2C_5K_HOST_COMMAND,
+	I2C_5K_DATA_0,
+	I2C_5K_DATA_1,
+	I2C_5K_BLOCK_DATA,
+	I2C_5K_HOST_CMD_BYTE_DATA_RW,
+	I2C_5K_HOST_CMD_WORD_DATA_RW,
+	I2C_5K_HOST_CMD_BLOCK_DATA_RW,
+	0L
+};
+
+/* a global pointer for our i2c data */
+struct cobalt_i2c_data *i2c_data;
+
+#define I2C_REG(r)			(i2c_data->io_port + i2c_data->r)
+#define I2C_CMD(c)			(i2c_data->c)
+
+#define I2C_LOCK	(1 << 0)
+#define I2C_DEAD	(1 << 1)
+static unsigned long i2c_state;
+
+static int initialized;
+
+static inline int 
+do_i2c_lock(void)
+{
+	int i = 0;
+
+	if (test_bit(I2C_DEAD, &i2c_state))
+		return -1;
+
+	while (test_and_set_bit(I2C_LOCK, &i2c_state)) {
+		if (i++ > 5)
+			return -1;
+		udelay(10);
+	}
+	udelay(1);
+	return 0;
+}
+
+static inline void 
+do_i2c_unlock(void)
+{
+	clear_bit(I2C_LOCK, &i2c_state);
+}
+
+/* do a little squelching */
+#define NOISE_RATE (5*HZ)
+static int 
+i2c_noisy(void)
+{
+	static unsigned long last_time;
+	static unsigned int messages;
+
+	if ((long) (jiffies - last_time) > NOISE_RATE) {
+		last_time = jiffies;
+		if (messages) {
+			WPRINTK("skipped %u kernel messages\n", messages);
+			messages = 0;
+		}
+		return 0;
+	}
+	messages++;
+	return 1;
+}
+
+static int 
+i2c_wait_for_smi(void)
+{
+	static unsigned int shutup = 0;
+	int timeout=10;
+	int status;
+
+	while (timeout--) {
+		udelay(100); /* wait */
+		status = inb_p(I2C_REG(status));
+
+		if (cobt_is_3k()) {
+			if (status & I2C_3K_STATUS_IDLE) {
+				return 0;
+			}
+		} else if (cobt_is_5k()) {
+			if (!(status & I2C_5K_HOST_STATUS_BUSY)) {
+				return 0;
+			}
+		}
+		outb_p(status, I2C_REG(status));
+	}
+
+	/* still busy - complain */
+	if (!i2c_noisy()) {
+		if (++shutup > 2) {
+			EPRINTK("i2c seems to be dead - sorry\n");
+			set_bit(I2C_DEAD, &i2c_state);
+		} else {
+			WPRINTK("i2c timeout: status busy (0x%x), resetting\n",
+				status);
+		}
+	}
+
+	/* punch the abort bit */
+	if (cobt_is_3k()) {
+		outb_p(4, i2c_data->io_port + I2C_3K_CMD);
+	} else if (cobt_is_5k()) {
+		outb_p(2, i2c_data->io_port + I2C_5K_HOST_CONTROL);
+		outb_p(1, i2c_data->io_port + I2C_5K_HOST_CONTROL);
+	}
+
+	return -1;
+}
+
+static inline int 
+i2c_setup(const int dev, const int index, const int r)
+{
+	if (i2c_wait_for_smi() < 0)
+		return -1;
+
+	/* clear status */
+	outb_p(0xff, I2C_REG(status));
+
+	/* device address */
+	outb_p((dev|r) & 0xff, I2C_REG(addr));
+
+	/* I2C index */
+	outb_p(index & 0xff, I2C_REG(index));
+
+	return 0;
+}
+	
+static inline int 
+i2c_cmd(const unsigned char command)
+{
+	if (cobt_is_3k()) {
+		outb_p(command, i2c_data->io_port + I2C_3K_CMD); 
+		outb_p(0xff, i2c_data->io_port + I2C_3K_START);
+	} else if (cobt_is_5k()) {
+		outb_p(I2C_5K_HOST_CMD_START | command,
+			i2c_data->io_port + I2C_5K_HOST_CONTROL);
+	}
+
+	if (i2c_wait_for_smi() < 0)
+		return -1;
+
+	return 0;
+}
+
+int 
+cobalt_i2c_init(void)
+{
+	struct pci_dev *i2cdev = NULL;
+
+        if( ! initialized ) {
+		if (cobt_is_3k()) {
+			i2c_data = &cobalt_i2c_3k;
+			i2cdev = pci_find_device(PCI_VENDOR_ID_AL, 
+				PCI_DEVICE_ID_AL_M7101, NULL);
+			if (!i2cdev) {
+				EPRINTK("can't find PMU for i2c access\n");
+				return -1;
+			}
+			pci_read_config_dword(i2cdev, 0x14, &i2c_data->io_port);
+		} else if (cobt_is_5k()) {
+			i2c_data = &cobalt_i2c_5k;
+			i2cdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+				PCI_DEVICE_ID_SERVERWORKS_OSB4, i2cdev);
+			if (!i2cdev) {
+			    i2cdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+			    PCI_DEVICE_ID_SERVERWORKS_CSB5, i2cdev);
+			    if (!i2cdev) {
+				EPRINTK("can't find OSB4 or CSB5 for i2c access\n");
+				return -1;
+			    }
+			}
+			pci_read_config_dword(i2cdev, 0x90, &i2c_data->io_port);
+		}
+
+		i2c_data->io_port &= 0xfff0;
+		if (!i2c_data->io_port) {
+			EPRINTK("i2c IO port not found\n");
+           	}
+		initialized = 1;
+	}
+
+	return 0;
+}
+
+int 
+cobalt_i2c_reset(void)
+{
+	int r;
+
+	if( !initialized ) {
+		if( cobalt_i2c_init() < 0 )
+			return -1;
+	}
+
+       	if (do_i2c_lock() < 0)
+		return -1;
+
+	if (cobt_is_3k()) {
+		/* clear status */
+		outb_p(0xff, i2c_data->io_port + I2C_3K_STATUS);
+		/* reset SMB devs */
+		outb_p(0x08, i2c_data->io_port + I2C_3K_CMD);
+		/* start command */
+		outb_p(0xff, i2c_data->io_port + I2C_3K_START);
+	} else if (cobt_is_5k()) {
+		/* clear status */
+		outb_p(0x2, i2c_data->io_port + I2C_5K_HOST_CONTROL);
+		outb_p(0x1, i2c_data->io_port + I2C_5K_HOST_CONTROL);
+		outb_p(0xff, i2c_data->io_port + I2C_5K_HOST_STATUS);
+		outb_p(I2C_5K_HOST_CMD_START | 0x08, 
+			i2c_data->io_port + I2C_5K_HOST_CONTROL);
+	}
+
+	r = i2c_wait_for_smi();
+
+	do_i2c_unlock();
+
+	return r;
+}
+
+int 
+cobalt_i2c_read_byte(const int dev, const int index)
+{
+	int val = 0;
+
+	if( !initialized ) {
+		if( cobalt_i2c_init() < 0 )
+			return -1;
+	}
+
+	if (do_i2c_lock() < 0)
+		return -1;
+
+	if (i2c_setup(dev, index, I2C_READ) < 0 
+	 || i2c_cmd(I2C_CMD(rw_byte)) < 0) {
+		val = -1;
+	}
+
+	if (val == 0) {
+		val = inb_p(I2C_REG(data_low));
+	}
+
+	do_i2c_unlock();
+
+	return val;
+}
+
+int 
+cobalt_i2c_read_word(const int dev, const int index)
+{
+	int val = 0;
+
+	if( !initialized ) {
+		if( cobalt_i2c_init() < 0 )
+			return -1;
+	}
+
+	if (do_i2c_lock() < 0)
+		return -1;
+	
+	if (i2c_setup(dev, index, I2C_READ) < 0 
+	 || i2c_cmd(I2C_CMD(rw_word)) < 0) {
+		val = -1;
+	}
+
+	if (val == 0) {
+		val = inb_p(I2C_REG(data_low));
+		val += inb_p(I2C_REG(data_high)) << 8;
+	}
+
+	do_i2c_unlock();
+
+	return val;
+}
+
+int 
+cobalt_i2c_read_block(const int dev, const int index, 
+	unsigned char *data, int count)
+{
+	if( !initialized ) {
+		if( cobalt_i2c_init() < 0 )
+			return -1;
+	}
+
+	if (do_i2c_lock() < 0)
+		return -1;
+	
+	if (i2c_setup(dev, index, I2C_READ) < 0) { 
+		do_i2c_unlock();
+		return -1;
+	}
+
+	outb_p(count & 0xff, I2C_REG(data_low));
+	outb_p(count & 0xff, I2C_REG(data_high));
+
+	if (i2c_cmd(I2C_CMD(rw_block)) < 0) {
+		do_i2c_unlock();
+		return -1;
+	}
+
+	while (count) {
+		/* read a byte of block data */
+		*data = inb_p(I2C_REG(data_block));
+		data++;
+		count--;
+	}
+
+	do_i2c_unlock();
+
+	return 0;	
+}
+
+int 
+cobalt_i2c_write_byte(const int dev, const int index, const u8 val)
+{
+	int r = 0;
+
+	if( !initialized ) {
+		if( cobalt_i2c_init() < 0 )
+			return -1;
+	}
+
+	if (do_i2c_lock() < 0)
+		return -1;
+
+	if (i2c_setup(dev, index, I2C_WRITE) < 0) {
+		r = -1;
+	}
+
+	if (r == 0) {
+		outb_p(val & 0xff, I2C_REG(data_low));
+
+		if (i2c_cmd(I2C_CMD(rw_byte)) < 0) {
+			r = -1;
+		}
+	}
+
+ 	udelay(I2C_WRITE_UDELAY);
+
+	do_i2c_unlock();
+
+	return r;	
+}
+
+int 
+cobalt_i2c_write_word(const int dev, const int index, const u16 val)
+{
+	int r = 0;
+
+	if( !initialized ) {
+		if( cobalt_i2c_init() < 0 )
+			return -1;
+	}
+
+	if (do_i2c_lock() < 0)
+		return -1;
+
+	if (i2c_setup(dev, index, I2C_WRITE) < 0) {
+		r = -1;
+	}
+
+	if (r == 0) {
+		outb_p(val & 0xff, I2C_REG(data_low));
+		outb_p((val >> 8) & 0xff, I2C_REG(data_high));
+
+		if (i2c_cmd(I2C_CMD(rw_word)) < 0) {
+			r = -1;
+		}
+	}
+        
+ 	udelay(I2C_WRITE_UDELAY);
+
+	do_i2c_unlock();
+
+	return r;	
+}
+
+int 
+cobalt_i2c_write_block(int dev, int index, unsigned char *data, int count)
+{
+	if( !initialized ) {
+		if( cobalt_i2c_init() < 0 )
+			return -1;
+	}
+
+	if (do_i2c_lock() < 0)
+		return -1;
+
+	if (i2c_setup(dev, index, I2C_WRITE) < 0) {
+		do_i2c_unlock();
+		return -1;
+	}
+
+	outb_p(count & 0xff, I2C_REG(data_low));
+	outb_p(count & 0xff, I2C_REG(data_high));
+
+	if (i2c_cmd(I2C_CMD(rw_block)) < 0) {
+		do_i2c_unlock();
+		return -1;
+	}
+
+	while (count) {
+		/* write a byte of block data */
+		outb_p(*data, I2C_REG(data_block));
+		data++;
+		count--;
+	}
+
+ 	udelay(I2C_WRITE_UDELAY);
+
+	do_i2c_unlock();
+
+	return 0;	
+}
+
+EXPORT_SYMBOL(cobalt_i2c_reset);
+EXPORT_SYMBOL(cobalt_i2c_read_byte);
+EXPORT_SYMBOL(cobalt_i2c_read_word);
+EXPORT_SYMBOL(cobalt_i2c_read_block);
+EXPORT_SYMBOL(cobalt_i2c_write_byte);
+EXPORT_SYMBOL(cobalt_i2c_write_word);
+EXPORT_SYMBOL(cobalt_i2c_write_block);
diff -Nurb linux-2.6.24.3/drivers/cobalt/init.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/init.c
--- linux-2.6.24.3/drivers/cobalt/init.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/init.c	2008-03-02 14:55:48.000000000 -0800
@@ -0,0 +1,117 @@
+/* $Id: init.c,v 1.22 2002/11/04 17:54:15 thockin Exp $ */
+/*
+ *   Copyright (c) 2001  Sun Microsystems
+ *   Generic initialization, to reduce pollution of other files
+ */
+#include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <cobalt/cobalt.h>
+#include <cobalt/powermode.h>
+
+static int cobalt_proc_init(void);
+extern int cobalt_i2c_init(void);
+extern int cobalt_net_init(void);
+extern int cobalt_systype_init(void);
+extern void cobalt_boardrev_init(void);
+extern int cobalt_led_init(void);
+extern int cobalt_lcd_init(void);
+extern int cobalt_serialnum_init(void);
+extern int cobalt_wdt_init(void);
+extern int cobalt_sensors_init(void);
+extern int cobalt_fan_init(void);
+extern int cobalt_acpi_init(void);
+extern int cobalt_ruler_init(void);
+extern int cobalt_raminfo_init(void);
+
+#ifdef CONFIG_PROC_FS
+struct proc_dir_entry *proc_cobalt;
+EXPORT_SYMBOL(proc_cobalt);
+#endif
+spinlock_t cobalt_superio_lock = SPIN_LOCK_UNLOCKED;
+
+/* initialize all the cobalt specific stuff */
+int __init
+cobalt_init(void)
+{
+    cobalt_proc_init();
+    cobalt_systype_init();
+#ifdef CONFIG_COBALT_RAQ
+    /* we might keep the boardrev on an i2c chip */
+    cobalt_i2c_init();
+#endif
+    cobalt_boardrev_init();
+#ifdef CONFIG_COBALT_ACPI
+    cobalt_acpi_init();
+#endif
+#ifdef CONFIG_COBALT_LED
+    cobalt_net_init();
+    cobalt_led_init();
+#endif
+#ifdef CONFIG_COBALT_LCD
+    cobalt_lcd_init();
+#endif
+#ifdef CONFIG_COBALT_RULER
+    cobalt_ruler_init();
+#endif
+#ifdef CONFIG_COBALT_SERNUM
+    cobalt_serialnum_init();
+#endif
+#ifdef CONFIG_COBALT_RAQ
+    /* some systems use WDT it for reboot */
+    cobalt_wdt_init();
+#endif
+#ifdef CONFIG_COBALT_SENSORS
+    cobalt_sensors_init();
+#endif
+#ifdef CONFIG_COBALT_FANS
+    cobalt_fan_init();
+#endif
+#ifdef CONFIG_COBALT_RAMINFO
+    cobalt_raminfo_init();
+#endif
+#ifdef CONFIG_COBALT_POWERMODE
+    cobalt_powermode_init();
+#endif
+    return 0;
+}
+
+static int __init
+cobalt_proc_init(void)
+{
+#ifdef CONFIG_PROC_FS
+	proc_cobalt = proc_mkdir("cobalt", 0);
+	if (!proc_cobalt) {
+		EPRINTK("can't create /proc/cobalt\n");
+		return -1;
+	}
+#endif
+
+	return 0;
+}
+
+/* a function that handles the blah stuff in a simple proc read function */
+int
+cobalt_gen_proc_read(char *buf, int plen, char **start, off_t pos, 
+	int len, int *eof)
+{
+	/* trying to read a bad offset? */
+	if (pos >= plen) {
+		*eof = 1;
+		return 0;
+	}
+
+	/* did we write everything we wanted to? */
+	if (len >= (plen-pos)) {
+		*eof = 1;
+	}
+
+	*start = buf + pos;
+	plen -= pos;
+
+	return (len > plen) ? plen : len;
+}
+EXPORT_SYMBOL(cobalt_gen_proc_read);
diff -Nurb linux-2.6.24.3/drivers/cobalt/Kconfig linux-2.6.24.3-cobalt3-tw/drivers/cobalt/Kconfig
--- linux-2.6.24.3/drivers/cobalt/Kconfig	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/Kconfig	2008-03-02 14:55:48.000000000 -0800
@@ -0,0 +1,156 @@
+#
+# Cobalt Drivers
+#
+
+menu "Cobalt RaQ/Qube Hardware"
+
+config COBALT_RAQ
+	bool "Cobalt RaQ/Qube Hardware Support"
+	select INPUT
+	default n
+	---help---
+	  NOTE: This support is for x86 Cobalts, not MIPS versions
+	  
+	  If you have a Gen III or Gen V Cobalt RaQ/Qube machine, it's probably
+	  a good idea to say Y here and choose from the options below.
+
+config COBALT_GEN_III
+	bool "Gen III (3000 series) system support"
+	depends on COBALT_RAQ
+	default y
+	---help---
+	  If you have one of the following Gen III Cobalt systems, say Y here.
+	  Otherwise, it's best to say N.
+	  
+	   - RaQ 3
+	   - RaQ 4
+	   - Qube3
+
+config COBALT_GEN_V
+	bool "Gen V (5000 series) system support"
+	depends on COBALT_RAQ
+	default n
+	---help---
+	  If you have one of the following Gen V Cobalt systems, say Y here.
+	  Otherwise, it's best to say N.
+	  
+	   - RaQ XTR
+	   - RaQ550
+
+config COBALT_OLDPROC
+	bool "Create legacy /proc files"
+	depends on COBALT_RAQ
+	depends on PROC_FS
+	default y
+	---help---
+	  Creates entries in /proc/cobalt which provide useful information about
+	  your RaQ/Qube.  Best to say Y here.
+
+#config COBALT_BOOTLOADER
+#	bool "Cobalt Bootloader Support"
+#	depends on COBALT_RAQ
+#	default n
+#	---help---
+#	  If you are going to being burning this kernel to the RaQ/Qube's ROM to
+#	  act as a loader kernel, this is required to load the system kernel and
+#	  hand off control to it.  It is recommended you say N here unless you
+#	  know what you're getting yourself into.
+#
+menu "Cobalt Hardware Options"
+	depends on COBALT_RAQ
+	
+	config COBALT_LCD
+			bool "Front panel LCD support"
+			default y
+			---help---
+			  Handles support for the front panel LCD screen and buttons.
+	
+	config COBALT_LCD_TWIDDLE
+			bool "Twiddle LCD on boot"
+			depends on COBALT_LCD
+			default y
+			---help---
+			  Gives you a nice little twiddle on the LCD while booting.
+	
+	config COBALT_LED
+			bool "Software controlled LED support"
+			default y
+			---help---
+			  Allows software to play with the LEDs on the front of the
+			  system.
+	
+	config COBALT_SERNUM
+			tristate "Serial number support"
+			depends on COBALT_OLDPROC
+			default y
+			---help---
+			  Allows you to retrieve the system's serial number via a /proc
+			  entry.
+	
+	config COBALT_WDT
+			bool "Watchdog timer support"
+			depends on WATCHDOG
+			default y
+			---help---
+			  w00f?
+	
+	config COBALT_POWERMODE
+			bool "Powermode Restore support"
+			depends on COBALT_OLDPROC
+			depends on COBALT_GEN_V
+			default y
+			---help---
+			  On GenV RaQs you can specify what action to take should a
+			  power failure occur.  This code allows you to set that action
+			  via /proc/cobalt/powermode.  Your options are "on", "off", and
+			  "same", except on Monterey hardware (XTR's) where there is no
+			  support for "on".
+	
+	config COBALT_SENSORS
+			bool "System sensors support"
+			depends on COBALT_OLDPROC
+			default y
+			---help---
+			  Allows you to retrieve system temperatures via /proc entries.
+	
+	config COBALT_FANS
+			tristate "Fan tachometer support"
+			depends on COBALT_OLDPROC
+			depends on COBALT_GEN_V
+			default y
+			---help---
+			  Allows you to retrieve fan speeds via /proc entries.
+	
+	config COBALT_RAMINFO
+			tristate "Memory information support"
+			depends on COBALT_OLDPROC
+			default y
+			---help---
+			  Got DIMMs?  This will tell you how much and in which slot via a
+			  /proc entry.
+	
+	config COBALT_RULER
+			bool "Disk drive ruler support"
+			depends on COBALT_OLDPROC
+			depends on COBALT_GEN_V
+			default y
+			---help---
+			  Not sure what this does... A purple tape measure maybe?
+	
+	config COBALT_ACPI
+			bool "Cobalt ACPI support"
+			depends on COBALT_GEN_V
+			default y
+			---help---
+			  ACPI support for the Generation V Cobalts.
+	
+	config COBALT_EMU_ACPI
+			bool "/proc/acpi emulation"
+			depends on COBALT_ACPI
+			default y
+			---help---
+			  Emulates the /proc/acpi interface.
+
+endmenu
+
+endmenu
diff -Nurb linux-2.6.24.3/drivers/cobalt/lcd.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/lcd.c
--- linux-2.6.24.3/drivers/cobalt/lcd.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/lcd.c	2008-03-02 14:55:48.000000000 -0800
@@ -0,0 +1,858 @@
+/*
+ * $Id: lcd.c,v 1.44 2002/05/10 18:44:45 duncan Exp $
+ * lcd.c : driver for Cobalt LCD/Buttons
+ *
+ * Copyright 1996-2000 Cobalt Networks, Inc.
+ * Copyright 2001 Sun Microsystems, Inc.
+ *
+ * By:	Andrew Bose
+ *	Timothy Stonis
+ *	Tim Hockin
+ *	Adrian Sun
+ *	Duncan Laurie
+ *
+ * Modified By: jeff@404ster.com
+ *
+ * This should be SMP safe. We're hardly performance critical,
+ * so we lock around lcd_ioctl() and just where needed by other external
+ * functions.  There is a static global waiters variable that is atomic_t, and
+ * so should be safe. --TPH
+ */
+
+#ifdef CONFIG_COBALT_LCD
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/in6.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/checksum.h>
+#include <linux/delay.h>
+
+#include <cobalt/cobalt.h>
+#include <cobalt/systype.h>
+#include <cobalt/lcd.h>
+#include <cobalt/superio.h>
+#include <cobalt/i2c.h>
+
+#define TWIDDLE_HZ (HZ/10)
+
+#ifndef min
+#define min(a, b)  ((a) < (b) ? (a) : (b))
+#endif
+
+#define LCD_DRIVER		"Cobalt Networks LCD driver"
+#define LCD_DRIVER_VMAJ		4
+#define LCD_DRIVER_VMIN		0
+
+/* io registers */
+#define LPT			0x0378
+#define LCD_DATA_ADDRESS	LPT+0
+#define LCD_CONTROL_ADDRESS	LPT+2
+
+/* LCD device info */
+#define LCD_Addr		0x80
+#define DD_R00			0x00
+#define DD_R01			0x27
+#define DD_R10			0x40
+#define DD_R11			0x67
+
+/* driver functions */
+static int cobalt_lcd_open(struct inode *, struct file *);
+static ssize_t cobalt_lcd_read(struct file *, char *, size_t, loff_t *);
+static int cobalt_lcd_read_proc(char *, char **, off_t, int, int *, void *);
+static char *cobalt_lcddev_read_line(int, char *);
+static int cobalt_lcd_ioctl(struct inode *, struct file *,
+	unsigned int, unsigned long);
+static int cobalt_lcd_panic(struct notifier_block *self, unsigned long, void *);
+
+/* globals used throughout */
+#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_COBALT_OLDPROC
+static struct proc_dir_entry *proc_lcd;
+#endif
+static struct proc_dir_entry *proc_clcd;
+#endif
+static int lcd_present;
+static int has_i2c_lcd;
+static spinlock_t lcd_lock = SPIN_LOCK_UNLOCKED;
+
+/* various file operations we support for this driver */
+static struct file_operations lcd_fops = {
+	.read = cobalt_lcd_read,
+	.ioctl = cobalt_lcd_ioctl,
+	.open = cobalt_lcd_open,
+};
+
+/* device structure */
+static struct miscdevice lcd_dev = {
+	MISC_DYNAMIC_MINOR,
+	"lcd",
+	&lcd_fops
+};
+
+static int disable_lcd;
+static int __init 
+lcd_disable_setup(char *str)
+{
+	disable_lcd = 1;
+	return 0;
+}
+__setup("nolcd", lcd_disable_setup);
+
+/* Read a control instruction from the LCD */
+static inline int 
+lcddev_read_inst(void)
+{
+	int a = 0;
+
+	if (cobt_is_5k() && has_i2c_lcd) {
+		a = cobalt_i2c_read_byte(
+			COBALT_I2C_DEV_LCD_INST | COBALT_I2C_READ, 0);
+	} else if (cobt_is_3k() || (cobt_is_5k() && !has_i2c_lcd)) {
+		outb(0x21, LCD_CONTROL_ADDRESS); /* RS=0, R/W=1, E=0 */
+		outb(0x20, LCD_CONTROL_ADDRESS); /* RS=0, R/W=1, E=1 */
+		a = inb(LCD_DATA_ADDRESS);
+		outb(0x21, LCD_CONTROL_ADDRESS); /* RS=0, R/W=1, E=0 */
+		outb(0x01, LCD_CONTROL_ADDRESS); /* RS=0, R/W=1, E=0 */
+	} 
+
+	/* small delay */
+	udelay(100);
+
+	return a;
+}
+
+#define LCD_MAX_POLL 10000
+static inline void 
+lcddev_poll_wait(void) 
+{
+	int i=0;
+
+	while (i++ < LCD_MAX_POLL) {
+		int r = lcddev_read_inst();
+		if (r < 0 || !(r & 0x80))
+			break;
+	}
+}
+
+/* Write a control instruction to the LCD */
+static inline void 
+lcddev_write_inst(unsigned char data)
+{
+	lcddev_poll_wait();
+
+	if (cobt_is_5k() && has_i2c_lcd) {
+		cobalt_i2c_write_byte(
+			COBALT_I2C_DEV_LCD_INST | COBALT_I2C_WRITE, 0, data);
+	} else if (cobt_is_3k() || (cobt_is_5k() && !has_i2c_lcd)) {
+		outb(0x03, LCD_CONTROL_ADDRESS); /* RS=0, R/W=0, E=0 */
+		outb(data, LCD_DATA_ADDRESS);
+		outb(0x02, LCD_CONTROL_ADDRESS); /* RS=0, R/W=0, E=1 */
+		outb(0x03, LCD_CONTROL_ADDRESS); /* RS=0, R/W=0, E=0 */
+		outb(0x01, LCD_CONTROL_ADDRESS); /* RS=0, R/W=1, E=0 */
+	}
+
+	/* small delay */
+	udelay(100);
+}
+
+/* Write one byte of data to the LCD */
+static inline void 
+lcddev_write_data(unsigned char data)
+{
+	lcddev_poll_wait();
+
+	if (cobt_is_5k() && has_i2c_lcd) {
+		cobalt_i2c_write_byte(
+			COBALT_I2C_DEV_LCD_DATA | COBALT_I2C_WRITE, 0, data);
+	} else if (cobt_is_3k() || (cobt_is_5k() && !has_i2c_lcd)) {
+		outb(0x07, LCD_CONTROL_ADDRESS); /* RS=1, R/W=0, E=0 */
+		outb(data, LCD_DATA_ADDRESS);
+		outb(0x06, LCD_CONTROL_ADDRESS); /* RS=1, R/W=0, E=1 */
+		outb(0x07, LCD_CONTROL_ADDRESS); /* RS=1, R/W=0, E=0 */
+		outb(0x05, LCD_CONTROL_ADDRESS); /* RS=1, R/W=1, E=0 */
+	}
+	/* small delay */
+	udelay(100);
+}
+
+/* Read one byte of data from the LCD */
+static inline unsigned char 
+lcddev_read_data(void)
+{
+	unsigned char a = 0;
+
+	lcddev_poll_wait();
+
+	if (cobt_is_5k() && has_i2c_lcd) {
+		a = cobalt_i2c_read_byte(
+			COBALT_I2C_DEV_LCD_DATA | COBALT_I2C_READ, 0);
+	} else if (cobt_is_3k() || (cobt_is_5k() && !has_i2c_lcd)) {
+		outb(0x25, LCD_CONTROL_ADDRESS); /* RS=1, R/W=1, E=0 */
+		outb(0x24, LCD_CONTROL_ADDRESS); /* RS=1, R/W=1, E=1 */
+		a = inb(LCD_DATA_ADDRESS);
+		outb(0x25, LCD_CONTROL_ADDRESS); /* RS=1, R/W=1, E=0 */
+		outb(0x01, LCD_CONTROL_ADDRESS); /* RS=1, R/W=1, E=0 */
+	}
+
+	/* small delay */
+	udelay(100);
+
+	return a;
+}
+
+static inline void
+lcddev_init(void)
+{
+	lcddev_write_inst(0x38);
+	lcddev_write_inst(0x38);
+	lcddev_write_inst(0x38);
+	lcddev_write_inst(0x06);
+	lcddev_write_inst(0x0c);
+}
+
+static inline char 
+read_buttons(void)
+{
+	char r = 0;
+
+	if (cobt_is_5k() && has_i2c_lcd) {
+		unsigned char inst;
+		inst = cobalt_i2c_read_byte(COBALT_I2C_DEV_FP_BUTTONS, 0);
+		switch (inst) {
+			case 0x3e: r = BUTTON_Next_B; break;
+			case 0x3d: r = BUTTON_Enter_B; break;
+			case 0x1f: r = BUTTON_Left_B; break;
+			case 0x3b: r = BUTTON_Right_B; break;
+			case 0x2f: r = BUTTON_Up_B; break;
+			case 0x37: r = BUTTON_Down_B; break;
+			case 0x3f: 
+			default: r = BUTTON_NONE_B;
+		}
+	} else if (cobt_is_3k() || (cobt_is_5k() && !has_i2c_lcd)) {
+		outb(0x29, LCD_CONTROL_ADDRESS); /* Sel=0, Bi=1 */
+		r = inb(LCD_DATA_ADDRESS) & BUTTON_MASK;
+	}
+	
+	return r;
+}
+
+static inline int 
+button_pressed(void)
+{
+	unsigned char b;
+	unsigned long flags;
+
+	spin_lock_irqsave(&lcd_lock, flags);
+	b = read_buttons();
+	spin_unlock_irqrestore(&lcd_lock, flags);
+
+	switch (b) {
+	case BUTTON_Next:
+	case BUTTON_Next_B:
+	case BUTTON_Reset_B:
+		return b;
+	default:
+	    break;
+	}
+
+	return 0;
+}
+
+/* this could be protected by CAP_RAW_IO here, or by the FS permissions */
+static int 
+cobalt_lcd_ioctl(struct inode *inode, struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	struct lcd_display button_display, display;
+	unsigned long address, a;
+	int index;
+	int dlen = sizeof(struct lcd_display);
+	int r = 0;
+	unsigned long flags;
+
+#ifdef CONFIG_COBALT_LCD_TWIDDLE
+	cobalt_lcd_stop_twiddle();
+#endif	
+	switch (cmd) {
+	/* Turn the LCD on */
+	case LCD_On:
+		spin_lock_irqsave(&lcd_lock, flags);
+		lcddev_write_inst(0x0F);
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		break;		
+
+	/* Turn the LCD off */
+	case LCD_Off:
+		spin_lock_irqsave(&lcd_lock, flags);
+		lcddev_write_inst(0x08);
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		break;
+
+	/* Reset the LCD */
+	case LCD_Reset:
+		spin_lock_irqsave(&lcd_lock, flags);
+		lcddev_write_inst(0x3F);
+		lcddev_write_inst(0x3F);
+		lcddev_write_inst(0x3F);
+		lcddev_write_inst(0x3F);
+		lcddev_write_inst(0x01);
+		lcddev_write_inst(0x06);
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		break;
+
+	/* Clear the LCD */
+	case LCD_Clear:
+		spin_lock_irqsave(&lcd_lock, flags);
+		lcddev_write_inst(0x01);
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		break;
+
+	/* Move the cursor one position to the left */
+	case LCD_Cursor_Left:
+		spin_lock_irqsave(&lcd_lock, flags);
+		lcddev_write_inst(0x10);
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		break;
+
+	/* Move the cursor one position to the right */
+	case LCD_Cursor_Right:
+		spin_lock_irqsave(&lcd_lock, flags);
+		lcddev_write_inst(0x14);
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		break;	
+
+	/* Turn the cursor off */
+	case LCD_Cursor_Off:
+		spin_lock_irqsave(&lcd_lock, flags);
+		lcddev_write_inst(0x0C);
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		break;
+
+	/* Turn the cursor on */
+	case LCD_Cursor_On:
+		spin_lock_irqsave(&lcd_lock, flags);
+		lcddev_write_inst(0x0F);
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		break;
+
+	/* Turn blinking off? I don't know what this does - TJS */
+	case LCD_Blink_Off:
+		spin_lock_irqsave(&lcd_lock, flags);
+		lcddev_write_inst(0x0E);
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		break;
+
+	/* Get the current cursor position */
+	case LCD_Get_Cursor_Pos:
+		spin_lock_irqsave(&lcd_lock, flags);
+		display.cursor_address = (unsigned char)lcddev_read_inst();
+		display.cursor_address = display.cursor_address & 0x07F;
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		if (copy_to_user((struct lcd_display *)arg, &display, dlen)) {
+			r = -EFAULT;
+		}
+		break;
+
+	/* Set the cursor position */
+	case LCD_Set_Cursor_Pos:
+		if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) {
+			r = -EFAULT;
+			break;
+		}
+		a = display.cursor_address | LCD_Addr;
+		spin_lock_irqsave(&lcd_lock, flags);
+		lcddev_write_inst(a);
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		break;
+
+	/* Get the value at the current cursor position? - TJS */
+	case LCD_Get_Cursor:
+		spin_lock_irqsave(&lcd_lock, flags);
+		display.character = lcddev_read_data();
+		lcddev_write_inst(0x10);
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		if (copy_to_user((struct lcd_display *)arg, &display, dlen)) {
+			r = -EFAULT;
+		}
+		break;
+
+	/* Set the character at the cursor position? - TJS */
+	case LCD_Set_Cursor:
+		if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) {
+			r = -EFAULT;
+			break;
+		}
+		spin_lock_irqsave(&lcd_lock, flags);
+		lcddev_write_data(display.character);
+		lcddev_write_inst(0x10);
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		break;
+
+	/* Dunno what this does - TJS */ 
+	case LCD_Disp_Left:
+		spin_lock_irqsave(&lcd_lock, flags);
+		lcddev_write_inst(0x18);
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		break;
+
+	/* Dunno what this does - TJS */ 
+	case LCD_Disp_Right:
+		spin_lock_irqsave(&lcd_lock, flags);
+		lcddev_write_inst(0x1C);
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		break;
+
+	/* Dunno what this does - TJS */ 
+	case LCD_Home:
+		spin_lock_irqsave(&lcd_lock, flags);
+		lcddev_write_inst(0x02);
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		break;
+
+	/* Write a string to the LCD */
+	case LCD_Write:
+		if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) {
+			r = -EFAULT;
+			break;
+		}
+
+		spin_lock_irqsave(&lcd_lock, flags);
+
+		display.size1 = display.size1 > 0 ? 
+		  min(display.size1, (int) sizeof(display.line1)) : 0;
+		display.size2 = display.size2 > 0 ? 
+		  min(display.size2, (int) sizeof(display.line2)) : 0;
+
+		/* First line */
+		lcddev_write_inst(0x80);
+		for (index = 0; index < display.size1; index++)
+			lcddev_write_data(display.line1[index]);
+		for (index = display.size1; index < sizeof(display.line1); index++)
+			lcddev_write_data(' ');
+
+		/* Second line */
+		lcddev_write_inst(0xC0);	
+		for (index = 0; index < display.size2; index++)
+			lcddev_write_data(display.line2[index]);
+		for (index = display.size2; index < sizeof(display.line2); index++)
+			lcddev_write_data(' ');
+
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		break;	
+
+	/* Read what's on the LCD */
+	case LCD_Read:
+		spin_lock_irqsave(&lcd_lock, flags);
+
+		for (address = DD_R00; address <= DD_R01; address++) {
+			lcddev_write_inst(address | LCD_Addr);
+			display.line1[address] = lcddev_read_data();
+		}
+		for (address = DD_R10; address <= DD_R11; address++) {
+			lcddev_write_inst(address | LCD_Addr);
+			display.line2[address - DD_R10] = lcddev_read_data();
+		}
+
+		spin_unlock_irqrestore(&lcd_lock, flags);
+
+		display.line1[DD_R01] = '\0';
+		display.line2[DD_R01] = '\0';
+
+		if (copy_to_user((struct lcd_display *)arg, &display, dlen)) {
+			r = -EFAULT;
+		}
+		break;
+
+	case LCD_Raw_Inst:
+		if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) {
+			r = -EFAULT;
+			break;
+		}
+		spin_lock_irqsave(&lcd_lock, flags);
+		lcddev_write_inst(display.character);
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		break;
+
+	case LCD_Raw_Data:
+		if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) {
+			r = -EFAULT;
+			break;
+		}
+		spin_lock_irqsave(&lcd_lock, flags);
+		lcddev_write_data(display.character);
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		break;
+
+	case LCD_Type:
+		if (cobt_is_5k() && has_i2c_lcd) {
+			if (put_user(LCD_TYPE_I2C, (int *)arg)) {
+				r = -EFAULT;
+			}
+		} else if (cobt_is_3k() || (cobt_is_5k() && !has_i2c_lcd)) {
+			if (put_user(LCD_TYPE_PARALLEL_B, (int *)arg)) {
+				r = -EFAULT;
+			}
+		}
+		break;
+		
+	/* Read the buttons */
+	case BUTTON_Read:
+		spin_lock_irqsave(&lcd_lock, flags);
+		button_display.buttons = read_buttons();
+		spin_unlock_irqrestore(&lcd_lock, flags);
+		if (copy_to_user((struct lcd_display *)arg, 
+				&button_display, dlen)) {
+			r = -EFAULT;
+		}
+		break;
+	
+#ifdef CONFIG_COBALT_LED
+	/* a slightly different api that allows you to set 32 leds */
+	case LED32_Set:
+		cobalt_led_set_lazy(arg);
+		break;
+
+	case LED32_Bit_Set:
+		cobalt_led_set_bits_lazy(arg);
+		break;
+
+	case LED32_Bit_Clear:
+		cobalt_led_clear_bits_lazy(arg);
+		break;
+
+	case LED32_Get:
+		*(unsigned int *)arg = cobalt_led_get();
+		break;
+
+	/* set all the leds */
+	case LED_Set:
+		if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) {
+			r = -EFAULT;
+			break;
+		}
+		cobalt_led_set_lazy(display.leds);
+		break;
+
+	/* set a single led */
+	case LED_Bit_Set:
+		if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) {
+			r = -EFAULT;
+			break;
+		}
+		cobalt_led_set_bits_lazy(display.leds);
+		break;
+
+	/* clear an led */
+	case LED_Bit_Clear:
+		if (copy_from_user(&display, (struct lcd_display *)arg, dlen)) {
+			r = -EFAULT;
+			break;
+		}
+		cobalt_led_clear_bits_lazy(display.leds);
+		break;
+#endif
+
+	default:
+	    break;
+	}
+
+	return r;
+}
+
+static int 
+cobalt_lcd_open(struct inode *inode, struct file *file)
+{
+	if (!lcd_present) {
+		return -ENXIO;
+	} else {
+		return 0;
+	}
+}
+
+/* LCD daemon sits on this, we wake it up once a key is pressed */
+static ssize_t 
+cobalt_lcd_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+	int bnow;
+	static unsigned long lcd_waiters;
+
+	if (test_and_set_bit(0, &lcd_waiters)) {
+		return -EINVAL;
+	}
+
+	while (((bnow = button_pressed()) == 0) && !(signal_pending(current))) {
+		if (file->f_flags & O_NONBLOCK) {
+			lcd_waiters = 0;
+			return -EAGAIN;
+		}
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(2 * HZ);
+	}
+	lcd_waiters = 0;
+
+	if (signal_pending(current)) {
+		return -ERESTARTSYS;
+	}
+
+	return bnow;
+}
+
+/* read a single line from the LCD into a string */
+static char *
+cobalt_lcddev_read_line(int lineno, char *line)
+{
+	unsigned long addr, min, max;
+	unsigned long flags;
+	
+	switch (lineno) {
+	case 0:
+		min = DD_R00;
+		max = DD_R01;
+		break;
+	case 1:
+		min = DD_R10;
+		max = DD_R11;
+		break;
+	default:
+		min = 1;
+		max = 0;
+	}
+
+	spin_lock_irqsave(&lcd_lock, flags);
+	for (addr = min; addr <= max; addr++) {
+		lcddev_write_inst(addr | LCD_Addr);
+		udelay(150);
+		line[addr-min] = lcddev_read_data();
+		udelay(150);
+	}
+	spin_unlock_irqrestore(&lcd_lock, flags);
+	line[addr-min] = '\0';
+
+	return line;
+}
+
+#ifdef CONFIG_PROC_FS
+static int 
+cobalt_lcd_read_proc(char *buf, char **start, off_t pos,
+				int len, int *eof, void *private)
+{
+	int plen = 0;
+	char line[COBALT_LCD_LINELEN+1];
+
+	/* first line */
+	cobalt_lcddev_read_line(0, line);
+	plen += sprintf(buf+plen, "%s\n", line);
+
+	/* second line */
+	cobalt_lcddev_read_line(1, line);
+	plen += sprintf(buf+plen, "%s\n", line);
+	
+	return cobalt_gen_proc_read(buf, plen, start, pos, len, eof);
+}
+#endif
+
+void cobalt_lcd_print(char * line1, char * line2)
+{
+    int i;
+    int len;
+
+    if( !lcd_present )
+         return;
+
+#ifdef CONFIG_COBALT_LCD_TWIDDLE
+    cobalt_lcd_stop_twiddle();
+#endif
+
+    lcddev_write_inst( (DD_R00) | LCD_Addr);
+    len = strlen( line1 );
+    for( i=0 ; i<16 ; i++ )
+        lcddev_write_data( (i<len)?line1[i]:' ' );
+
+    lcddev_write_inst( (DD_R10) | LCD_Addr);
+    len = strlen( line2 );
+    for( i=0 ; i<16 ; i++ )
+        lcddev_write_data( (i<len)?line2[i]:' ' );
+
+    return;
+}
+
+static char *lcd_panic_str1 = "Kernel";
+static char *lcd_panic_str2 = "Panic!";
+
+static int cobalt_lcd_panic(struct notifier_block *self, unsigned long a, void *b)
+{
+    int i;
+    int len;
+    
+    if( !lcd_present )
+        return 0;
+    
+#ifdef CONFIG_COBALT_LCD_TWIDDLE
+    cobalt_lcd_stop_twiddle();
+#endif
+
+    lcddev_write_inst( (DD_R00) | LCD_Addr);
+    len = strlen( lcd_panic_str1 );
+    for( i=0 ; i<16 ; i++ )
+	lcddev_write_data( (i<len)?lcd_panic_str1[i]:' ' );
+
+    lcddev_write_inst( (DD_R10) | LCD_Addr);
+    len = strlen( lcd_panic_str2 );
+    for( i=0 ; i<16 ; i++ )
+	lcddev_write_data( (i<len)?lcd_panic_str2[i]:' ' );
+
+    return 0;
+}
+
+#ifdef CONFIG_COBALT_LCD_TWIDDLE
+static struct timer_list twiddle_timer;
+static int twiddling;
+static void 
+twiddle_timer_func(unsigned long data)
+{
+	static int state=1;
+	static int pos=0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&lcd_lock, flags);
+
+	lcddev_write_inst((DD_R10+4+pos) | LCD_Addr);
+	lcddev_write_data(' ');
+
+	pos += state;
+	if (pos < 0) {
+		state = 1; 
+		pos = 1;
+	}
+	if (pos > 11) {
+		state = -1; 
+		pos = 10;
+	}
+
+	lcddev_write_inst((DD_R10+4+pos) | LCD_Addr);
+	lcddev_write_data(0xff);
+
+	spin_unlock_irqrestore(&lcd_lock, flags);
+
+	mod_timer(&twiddle_timer, jiffies + TWIDDLE_HZ);
+}
+
+void 
+cobalt_lcd_start_twiddle(void)
+{
+    init_timer(&twiddle_timer);
+	twiddle_timer.expires = jiffies + TWIDDLE_HZ;
+	twiddle_timer.data = 0;
+	twiddle_timer.function = &twiddle_timer_func;
+	add_timer(&twiddle_timer); 
+	twiddling=1; 
+}
+
+void 
+cobalt_lcd_stop_twiddle(void)
+{
+	unsigned long flags;
+    
+    spin_lock_irqsave(&lcd_lock, flags);
+	if (twiddling) {
+		del_timer_sync(&twiddle_timer);
+		twiddling = 0;
+	}
+	spin_unlock_irqrestore(&lcd_lock, flags);
+}
+#endif /* CONFIG_COBALT_LCD_TWIDDLE */
+
+/* stop the lcd */
+void cobalt_lcd_off(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&lcd_lock, flags);
+	lcddev_write_inst(0x01); /* clear */
+	lcddev_write_inst(0x08); /* off */
+	spin_unlock_irqrestore(&lcd_lock, flags);
+}
+
+static int initialized;
+static struct notifier_block lcd_nb;
+
+int __init 
+cobalt_lcd_init(void)
+{	
+    int retval;
+    
+	if (initialized)
+		return 0;
+
+	initialized=1;
+    printk(KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", LCD_DRIVER,LCD_DRIVER_VMAJ,LCD_DRIVER_VMIN);
+    
+	if (disable_lcd) {
+		printk(KERN_INFO "%s DISABLED\n", LCD_DRIVER);
+		return 0;
+	}
+
+    retval = misc_register(&lcd_dev);
+	
+	if (cobt_is_monterey() 
+	 && (cobalt_i2c_read_byte(COBALT_I2C_DEV_LCD_INST, 0) != 0xff)) {
+	    printk(KERN_INFO "  - LCD is an I2C device\n");
+		has_i2c_lcd = 1;
+	} else {
+		has_i2c_lcd = 0;
+	}
+
+	/* flag ourselves as present */
+	lcd_present = 1;
+
+	/* initialize the device */
+	lcddev_init();
+
+#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_COBALT_OLDPROC
+	/* create /proc/lcd */
+	proc_lcd = create_proc_read_entry("lcd", S_IRUSR, NULL, 
+		cobalt_lcd_read_proc, NULL);
+	if (!proc_lcd) {
+		EPRINTK("can't create /proc/lcd\n");
+	}
+#endif
+    proc_clcd = create_proc_read_entry("lcd", S_IRUSR, proc_cobalt, 
+		cobalt_lcd_read_proc, NULL);
+	if (!proc_clcd) {
+		EPRINTK("can't create /proc/cobalt/lcd\n");
+	}
+#endif
+
+#ifdef CONFIG_COBALT_LCD_TWIDDLE
+	cobalt_lcd_start_twiddle();
+#endif
+
+            /* register panic notifier */
+        lcd_nb.notifier_call = cobalt_lcd_panic;
+        lcd_nb.next = NULL;
+        lcd_nb.priority = 0;
+        
+        atomic_notifier_chain_register( &panic_notifier_list, &lcd_nb );
+
+	return 0;
+}
+
+#endif /* CONFIG_COBALT_LCD */
diff -Nurb linux-2.6.24.3/drivers/cobalt/led.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/led.c
--- linux-2.6.24.3/drivers/cobalt/led.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/led.c	2008-03-02 14:55:48.000000000 -0800
@@ -0,0 +1,502 @@
+ /*
+ * $Id: led.c,v 1.36 2002/05/10 18:44:45 duncan Exp $
+ * led.c : driver for Cobalt LEDs
+ *
+ * Copyright 1996-2000 Cobalt Networks, Inc.
+ * Copyright 2001 Sun Microsystems, Inc.
+ *
+ * By:	Andrew Bose
+ *	Timothy Stonis
+ *	Tim Hockin
+ *	Adrian Sun
+ *	Duncan Laurie
+ *
+ * Modified By: jeff@404ster.com
+ *
+ * This should be SMP safe.  There is one definite critical region: the
+ * handler list (led_handler_lock).  The led_state is protected by led_lock, 
+ * so should be safe against simultaneous writes.  Bit banging of lights is 
+ * currently also a protected region (led_lock, rather than add a new lock).
+ */
+
+#ifdef CONFIG_COBALT_LED
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/nvram.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+
+#include <cobalt/cobalt.h>
+#include <cobalt/systype.h>
+#include <cobalt/led.h>
+#include <cobalt/i2c.h>
+#include <cobalt/superio.h>
+
+#define LED_DRIVER			"Cobalt Networks LED driver"
+#define LED_DRIVER_VMAJ		1
+#define LED_DRIVER_VMIN		0
+
+/* the rate at which software controlled frontpanel LEDs blink */
+#define FPLED_DEFAULT_HZ	(HZ/20)
+
+/* 
+ * This is the abstracted state of active LEDs - see the defines for LED_* 
+ * LED masks are always 'unsigned int'.  You must hold led_lock to muck with
+ * these.
+ */
+static unsigned int led_state;
+static unsigned int led_blips;
+
+/* leds are PCI on genIII */
+static struct pci_dev *led_dev;
+/* on XTR the front panel LEDs are software controlled */
+struct led_handler {
+	unsigned int (*function)(void *);
+	void *data;
+	struct led_handler *next;
+	struct led_handler *prev;
+};
+struct led_handler *led_handler_list;
+static spinlock_t led_handler_lock = SPIN_LOCK_UNLOCKED;
+static struct timer_list timer;
+
+static spinlock_t led_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * RaQ 3
+ * RaQ 4
+ * Qube 3
+ */
+#define RAQ3_SHUTLOGO_ADDR	0x7e
+#define RAQ3_SHUTDOWN_OFF	0x40 /* reverse polarity */
+#define RAQ3_COBALTLOGO_ON	0x80
+#define QUBE3_LIGHTBAR_ON	0xc0 /* direct polarity */
+#define RAQ3_WEBLIGHT_ADDR	0xb8
+#define RAQ3_WEBLIGHT_ON	0x80
+
+/*
+ * RaQ XTR
+ */
+#define MONTEREY_FPLED00		0x8000
+#define MONTEREY_FPLED01		0x4000
+#define MONTEREY_FPLED02		0x2000
+#define MONTEREY_FPLED03		0x0200
+#define MONTEREY_FPLED04		0x0080
+#define MONTEREY_FPLED05		0x0040
+#define MONTEREY_FPLED10		0x1000
+#define MONTEREY_FPLED11		0x0800
+#define MONTEREY_FPLED12		0x0400
+#define MONTEREY_FPLED13		0x0100
+#define MONTEREY_FPLED14		0x0020
+#define MONTEREY_FPLED15		0x0010
+#define MONTEREY_FPLED_ETH0_TXRX	MONTEREY_FPLED00
+#define MONTEREY_FPLED_ETH0_LINK	MONTEREY_FPLED10
+#define MONTEREY_FPLED_ETH1_TXRX	MONTEREY_FPLED01
+#define MONTEREY_FPLED_ETH1_LINK	MONTEREY_FPLED11
+#define MONTEREY_FPLED_DISK0		MONTEREY_FPLED02
+#define MONTEREY_FPLED_DISK1		MONTEREY_FPLED03
+#define MONTEREY_FPLED_DISK2		MONTEREY_FPLED04
+#define MONTEREY_FPLED_DISK3		MONTEREY_FPLED05
+#define MONTEREY_FPLED_WEB 		MONTEREY_FPLED12
+#define MONTEREY_LOGOLED_BIT		0x40
+#define MONTEREY_SYSFAULTLED_BIT	0x80
+#define MONTEREY_SLED0			(1<<3)
+#define MONTEREY_SLED1			(1<<2)
+#define MONTEREY_SLED2			(1<<1)
+#define MONTEREY_SLED3			(1<<0)
+
+/*
+ * Alpine
+ */
+#define ALPINE_WEBLED_PORT		0x60e
+#define ALPINE_WEBLED_BIT		0x20
+#define ALPINE_POWERLED_PORT		0x50b
+#define ALPINE_POWERLED_CFG             0x23
+#define ALPINE_LOGOLED_BIT		0x02
+#define ALPINE_SYSFAULTLED_BIT		0x07
+
+/* 
+ * actually set the leds (icky details hidden within) 
+ * this must be protected against itself with led_lock
+ * */
+static void 
+__set_led_hw(const unsigned int newstate)
+{
+	if (cobt_is_pacifica() && led_dev) {
+		unsigned char tmp;
+		/* RaQ 3, RaQ 4
+		 * - shutdown light
+		 * - logo light
+		 * - web light
+		 */
+
+		/* read the current state of shutdown/logo lights */
+		pci_read_config_byte(led_dev, RAQ3_SHUTLOGO_ADDR, &tmp);
+
+		/* reverse polarity for shutdown light */
+		if (newstate & LED_SHUTDOWN)
+			tmp &= ~RAQ3_SHUTDOWN_OFF;
+		else
+			tmp |= RAQ3_SHUTDOWN_OFF;
+
+		/* logo light is straight forward */
+		if (newstate & LED_COBALTLOGO)
+			tmp |= RAQ3_COBALTLOGO_ON;
+		else
+			tmp &= ~RAQ3_COBALTLOGO_ON;
+
+		/* write new shutdown/logo light state */
+		pci_write_config_byte(led_dev, RAQ3_SHUTLOGO_ADDR, tmp);
+
+		/* read web light state */
+		pci_read_config_byte(led_dev, RAQ3_WEBLIGHT_ADDR, &tmp);
+		if (newstate & LED_WEBLIGHT) {
+			tmp |= RAQ3_WEBLIGHT_ON;
+		} else {
+			tmp &= ~RAQ3_WEBLIGHT_ON;
+		}
+
+		/* write new web light state */
+		pci_write_config_byte(led_dev, RAQ3_WEBLIGHT_ADDR, tmp);
+	} else if (cobt_is_carmel() && led_dev) {
+		unsigned char tmp;
+		/* Qube 3
+		 * - no shutdown light
+		 * - lightbar instead of logo
+		 * - no web led (wired to 2nd IDE reset for staggered startup)
+		 */
+
+		/* read the current state of lightbar */
+		pci_read_config_byte(led_dev, RAQ3_SHUTLOGO_ADDR, &tmp);
+		if (newstate & LED_COBALTLOGO) {
+			tmp |= QUBE3_LIGHTBAR_ON;
+		} else {
+			tmp &= ~QUBE3_LIGHTBAR_ON;
+		}
+
+		/* write new lightbar state */
+		pci_write_config_byte(led_dev, RAQ3_SHUTLOGO_ADDR, tmp);
+	} else if (cobt_is_monterey()) {
+		unsigned int tmp = 0;
+		u8 val; 
+		unsigned long flags;
+
+		if (newstate & LED_WEBLIGHT) {
+			tmp |= MONTEREY_FPLED_WEB;
+		}
+		if (newstate & LED_ETH0_TXRX) {
+			tmp |= MONTEREY_FPLED_ETH0_TXRX;
+		}
+		if (newstate & LED_ETH0_LINK) {
+			tmp |= MONTEREY_FPLED_ETH0_LINK;
+		}
+		if (newstate & LED_ETH1_TXRX) {
+			tmp |= MONTEREY_FPLED_ETH1_TXRX;
+		}
+		if (newstate & LED_ETH1_LINK) {
+			tmp |= MONTEREY_FPLED_ETH1_LINK;
+		}
+		if (newstate & LED_DISK0) {
+			tmp |= MONTEREY_FPLED_DISK0;
+		}
+		if (newstate & LED_DISK1) {
+			tmp |= MONTEREY_FPLED_DISK1;
+		}
+		if (newstate & LED_DISK2) {
+			tmp |= MONTEREY_FPLED_DISK2;
+		}
+		if (newstate & LED_DISK3) {
+			tmp |= MONTEREY_FPLED_DISK3;
+		}
+		/* 3 LED's are unused on Monterey, but we support them */
+		if (newstate & LED_MONTEREY_UNUSED0) {
+			tmp |= MONTEREY_FPLED13;
+		}
+		if (newstate & LED_MONTEREY_UNUSED1) {
+			tmp |= MONTEREY_FPLED14;
+		}
+		if (newstate & LED_MONTEREY_UNUSED2) {
+			tmp |= MONTEREY_FPLED15;
+		}
+		/* I2C controlled front-panel lights */
+		cobalt_i2c_write_byte(COBALT_I2C_DEV_LED_I, 0, tmp & 0xff);
+		cobalt_i2c_write_byte(COBALT_I2C_DEV_LED_II, 0, tmp >> 8);
+		
+		/* drive sled LEDs are on a different i2c device */
+		tmp = 0xf0; /* high nibble means something else */
+		if (newstate * LED_SLED0)
+			tmp |= MONTEREY_SLED0;
+		if (newstate * LED_SLED1)
+			tmp |= MONTEREY_SLED1;
+		if (newstate * LED_SLED2)
+			tmp |= MONTEREY_SLED2;
+		if (newstate * LED_SLED3)
+			tmp |= MONTEREY_SLED3;
+		cobalt_i2c_write_byte(COBALT_I2C_DEV_RULER, 0, tmp);
+
+		/* sysfault and logo are in APC page of nvram */
+		spin_lock_irqsave(&rtc_lock, flags);
+		superio_set_rtc_bank(PC87317_RTC_BANK_APC);
+		val = CMOS_READ(PC87317_APCR4);
+
+		/* reverse polarity */
+		if (newstate & LED_COBALTLOGO) {
+			val &= ~MONTEREY_LOGOLED_BIT; /* logo is on */
+		} else {
+			val |= MONTEREY_LOGOLED_BIT; /* logo is off */
+		}
+
+		if (newstate & LED_SYSFAULT) {
+			val |= MONTEREY_SYSFAULTLED_BIT;
+		} else {
+			val &= ~MONTEREY_SYSFAULTLED_BIT;
+		}
+
+		CMOS_WRITE(val, PC87317_APCR4);
+		superio_set_rtc_bank(PC87317_RTC_BANK_MAIN);
+		spin_unlock_irqrestore(&rtc_lock, flags);
+	} else if (cobt_is_alpine()) {
+		unsigned char val;
+	    
+		/* web LED is reverse polarity */
+		val = inb(ALPINE_WEBLED_PORT);
+		if (newstate & LED_WEBLIGHT) {
+			val &= ~ALPINE_WEBLED_BIT;
+		} else {
+			val |= ALPINE_WEBLED_BIT;
+		}
+		outb(val, ALPINE_WEBLED_PORT);
+
+                    /* 
+                     * the power led is controled by switching the pin between
+                     * a GPIO pin (on) and a LED pin (off)
+                     */
+
+                outb( ALPINE_POWERLED_CFG, 0x2e );
+                val = inb( 0x2f );
+		if (newstate & LED_COBALTLOGO) {
+			val &= ~ALPINE_LOGOLED_BIT;
+		} else {
+			val |= ALPINE_LOGOLED_BIT;	
+		}
+                outb( val, 0x2f );
+
+		if (newstate & LED_SYSFAULT) {
+                    val = ALPINE_SYSFAULTLED_BIT;
+		} else {
+                    val = 0;
+		}
+
+		outb(val, ALPINE_POWERLED_PORT);
+	}
+}
+
+/* blip the front panel leds */
+static void 
+led_timer_func(unsigned long data)
+{
+	unsigned int leds = 0;
+	struct led_handler *p;
+	unsigned long flags;
+
+	/* call all registered callbacks */
+	spin_lock_irqsave(&led_handler_lock, flags);
+	for (p = led_handler_list; p; p = p->next) {
+		leds |= p->function(p->data);
+	}
+	spin_unlock_irqrestore(&led_handler_lock, flags);
+	
+	/* set the led hardware */
+	spin_lock_irqsave(&led_lock, flags);
+	__set_led_hw(led_state | leds | led_blips);
+	led_blips = 0;
+	spin_unlock_irqrestore(&led_lock, flags);
+
+	/* re-arm ourself */
+	mod_timer(&timer, jiffies + FPLED_DEFAULT_HZ);
+}
+
+static void
+__cobalt_led_set(const unsigned int leds)
+{
+	led_state = leds;
+	__set_led_hw(leds);
+}
+
+void 
+cobalt_led_set(const unsigned int leds)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&led_lock, flags);
+	__cobalt_led_set(leds);
+	spin_unlock_irqrestore(&led_lock, flags);
+}
+
+void 
+cobalt_led_set_bits(const unsigned int leds)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&led_lock, flags);
+	__cobalt_led_set(led_state | leds);
+	spin_unlock_irqrestore(&led_lock, flags);
+}
+
+void 
+cobalt_led_clear_bits(const unsigned int leds)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&led_lock, flags);
+	__cobalt_led_set(led_state & ~leds);
+	spin_unlock_irqrestore(&led_lock, flags);
+}
+
+static void
+__cobalt_led_set_lazy(const unsigned int leds)
+{
+	/* the next led timer run will catch these changes */
+	led_state = leds;
+	/* remember lights that were 'blipped' to force an edge */
+	led_blips |= leds;
+}
+
+void 
+cobalt_led_set_lazy(const unsigned int leds)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&led_lock, flags);
+	__cobalt_led_set_lazy(leds);
+	spin_unlock_irqrestore(&led_lock, flags);
+}
+
+void 
+cobalt_led_set_bits_lazy(const unsigned int leds)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&led_lock, flags);
+	__cobalt_led_set_lazy(led_state | leds);
+	spin_unlock_irqrestore(&led_lock, flags);
+}
+
+void 
+cobalt_led_clear_bits_lazy(const unsigned int leds)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&led_lock, flags);
+	__cobalt_led_set_lazy(led_state & ~leds);
+	spin_unlock_irqrestore(&led_lock, flags);
+}
+
+unsigned int 
+cobalt_led_get(void)
+{
+	unsigned int r;
+	unsigned long flags;
+
+	spin_lock_irqsave(&led_lock, flags);
+	r = led_state;
+	spin_unlock_irqrestore(&led_lock, flags);
+
+	return r;
+}
+
+int 
+cobalt_fpled_register(unsigned int (*function)(void *), void *data)
+{
+	struct led_handler *newh;
+	unsigned long flags;
+
+	newh = kmalloc(sizeof(*newh), GFP_ATOMIC);
+	if (!newh) {
+		EPRINTK("can't allocate memory for handler %p(%p)\n",
+			function, data);
+		return -1;
+	}
+
+	spin_lock_irqsave(&led_handler_lock, flags);
+
+	/* head insert */
+	newh->function = function;
+	newh->data = data;
+	newh->next = led_handler_list;
+	newh->prev = NULL;
+	if (led_handler_list) {
+		led_handler_list->prev = newh;
+	}
+	led_handler_list = newh;
+	
+	spin_unlock_irqrestore(&led_handler_lock, flags);
+
+	return 0;
+}
+
+int 
+cobalt_fpled_unregister(unsigned int (*function)(void *), void *data)
+{
+	int r = -1;
+	struct led_handler *p;
+	unsigned long flags;
+	
+	spin_lock_irqsave(&led_handler_lock, flags);
+
+	for (p = led_handler_list; p; p = p->next) {
+		if (p->function == function && p->data == data) {
+			if (p->prev) {
+				p->prev->next = p->next;
+			}
+			if (p->next) {
+				p->next->prev = p->prev;
+			}
+			r = 0;
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&led_handler_lock, flags);
+
+	return r;
+}
+
+int __init 
+cobalt_led_init(void)
+{	
+	unsigned int leds = LED_SHUTDOWN | LED_COBALTLOGO;
+    
+    printk(KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", LED_DRIVER,LED_DRIVER_VMAJ,LED_DRIVER_VMIN);
+
+	if (cobt_is_3k()) {
+		/* LEDs for RaQ3/4 and Qube3 are on the PMU */
+		led_dev = pci_find_device(PCI_VENDOR_ID_AL,
+			PCI_DEVICE_ID_AL_M7101, NULL);
+		if (!led_dev) {
+			EPRINTK("can't find PMU for LED control\n");
+			return -1;
+		}
+	} 
+	
+	/* setup up timer for fp leds */
+	init_timer(&timer);
+	timer.expires = jiffies + FPLED_DEFAULT_HZ;
+	timer.data = 0;
+	timer.function = &led_timer_func;
+	add_timer(&timer);
+
+	/* set the initial state */
+	leds |= cobalt_cmos_read_flag(COBT_CMOS_SYSFAULT_FLAG) ? 
+		LED_SYSFAULT : 0;
+	led_state = leds;
+	__set_led_hw(leds);
+
+	return 0;
+}
+
+#endif /* CONFIG_COBALT_LED */
diff -Nurb linux-2.6.24.3/drivers/cobalt/Makefile linux-2.6.24.3-cobalt3-tw/drivers/cobalt/Makefile
--- linux-2.6.24.3/drivers/cobalt/Makefile	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/Makefile	2008-03-02 14:55:48.000000000 -0800
@@ -0,0 +1,18 @@
+#
+# Makefile for the Sun/Cobalt device drivers
+#
+
+#O_TARGET := cobalt.o
+
+#export-objs := init.o systype.o wdt.o i2c.o
+
+obj-$(CONFIG_COBALT_RAQ)	+= init.o systype.o i2c.o wdt.o 
+obj-$(CONFIG_COBALT_ACPI)	+= acpi.o
+obj-$(CONFIG_COBALT_SERNUM)	+= serialnum.o
+obj-$(CONFIG_COBALT_LCD)	+= lcd.o
+obj-$(CONFIG_COBALT_LED)	+= net.o led.o
+obj-$(CONFIG_COBALT_SENSORS)	+= sensors.o
+obj-$(CONFIG_COBALT_FANS)	+= fans.o
+obj-$(CONFIG_COBALT_RAMINFO)	+= raminfo.o
+obj-$(CONFIG_COBALT_RULER)	+= ruler.o
+obj-$(CONFIG_COBALT_POWERMODE)	+= powermode.o
diff -Nurb linux-2.6.24.3/drivers/cobalt/net.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/net.c
--- linux-2.6.24.3/drivers/cobalt/net.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/net.c	2008-03-02 14:55:48.000000000 -0800
@@ -0,0 +1,132 @@
+/* 
+ * cobalt net wrappers
+ * Copyright (c) 2000, Cobalt Networks, Inc.
+ * Copyright (c) 2001, Sun Microsystems, Inc.
+ * $Id: net.c,v 1.11 2001/10/27 00:40:24 thockin Exp $
+ * author: thockin@sun.com
+ *
+ * This should be SMP safe.  The only critical data is the list of devices.
+ * The LED handler runs at timer-interrupt, so we must use the IRQ safe forms
+ * of the locks. --TPH
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/netdevice.h>
+#include <asm/io.h>
+
+#include <cobalt/cobalt.h>
+#include <cobalt/net.h>
+#include <cobalt/led.h>
+
+#define MAX_COBT_NETDEVS	2
+static struct net_device *netdevs[MAX_COBT_NETDEVS];
+static int n_netdevs;
+static spinlock_t cobaltnet_lock = SPIN_LOCK_UNLOCKED;
+
+#if defined(CONFIG_COBALT_LED)
+static unsigned int
+net_led_handler(void *data)
+{
+	int i;
+	unsigned int leds = 0;
+	static int txrxmap[MAX_COBT_NETDEVS] = {LED_ETH0_TXRX, LED_ETH1_TXRX};
+	static int linkmap[MAX_COBT_NETDEVS] = {LED_ETH0_LINK, LED_ETH1_LINK};
+	unsigned long flags;
+	static unsigned long net_old[MAX_COBT_NETDEVS];
+
+	spin_lock_irqsave(&cobaltnet_lock, flags);
+
+	for (i = 0; i < n_netdevs; i++) {
+		unsigned long txrxstate;
+		struct net_device *dev = netdevs[i];
+		if (!dev) {
+			continue;
+		}
+		/* check for link */
+		if (netif_running(dev) && netif_carrier_ok(dev)) {
+			leds |= linkmap[i];
+		}
+		/* check for tx/rx */
+		txrxstate = dev->trans_start ^ dev->last_rx;
+		if (txrxstate != net_old[i]) {
+			leds |= txrxmap[i];
+			net_old[i] = txrxstate;
+		}
+	}
+
+	spin_unlock_irqrestore(&cobaltnet_lock, flags);
+
+	return leds;
+}
+#endif
+
+/* 
+ * We try to be VERY explicit here.  Fine for now, may eventually break down.
+ */
+void 
+cobalt_net_register(struct net_device *ndev)
+{
+	unsigned long flags;
+	int i;
+	
+	if (!ndev) {
+		return;
+	}
+
+	/* we'll track the first MAX_COBT_NETDEVS NICs */
+	if (n_netdevs >= MAX_COBT_NETDEVS) {
+		return;
+	}
+
+	spin_lock_irqsave(&cobaltnet_lock, flags);
+
+	/* find a free slot */
+	for (i = 0; i < MAX_COBT_NETDEVS; i++) {
+		if (!netdevs[i]) {
+			netdevs[i] = ndev;
+			n_netdevs++;
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&cobaltnet_lock, flags);
+}
+
+void 
+cobalt_net_unregister(struct net_device *ndev)
+{
+	int i;
+	unsigned long flags;
+	
+	if (!ndev) {
+		return;
+	}
+
+	spin_lock_irqsave(&cobaltnet_lock, flags);
+
+	/* try to remove it from the list */
+	for (i = 0; i < MAX_COBT_NETDEVS; i++) {
+		if (netdevs[i] == ndev) {
+			netdevs[i] = NULL;
+			n_netdevs--;
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(&cobaltnet_lock, flags);
+}
+
+int __init
+cobalt_net_init(void)
+{
+#if defined(CONFIG_COBALT_LED)
+	/* register an LED handler */
+	cobalt_fpled_register(net_led_handler, NULL);
+#endif
+
+	return 0;
+}
diff -Nurb linux-2.6.24.3/drivers/cobalt/powermode.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/powermode.c
--- linux-2.6.24.3/drivers/cobalt/powermode.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/powermode.c	2008-03-02 14:55:48.000000000 -0800
@@ -0,0 +1,279 @@
+/* 
+ * $Id: powermode.c,v 1.17 2007/02/20 23:14:23 illogical Exp $
+ *
+ * Copyright (c) 2001, Sun Microsystems, Inc.
+ * All Rights Reserved
+ *
+ * Port of powermode functionality from sysctl.c
+ */
+
+#if defined (CONFIG_COBALT_POWERMODE) || defined (MODULE)
+
+//#include <linux/module.h>
+//#include <linux/moduleparam.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+//#include <linux/nvram.h>
+
+#include <linux/string.h>
+#include <asm/uaccess.h>
+#include <cobalt/cobalt.h>
+//#include <cobalt/nvram.h>
+#include <cobalt/powermode.h>
+#include <cobalt/systype.h>
+#include <cobalt/superio.h>
+
+static int cobalt_powermode_status;
+
+static int set_powermode (void);
+static void get_powermode (void);
+static int cobalt_powermode_fail (const int set, const int val);
+static int cobalt_powermode_apply (const int set, const int val);
+
+#define POWERMODE_DRIVER			"Cobalt Networks Powermode driver"
+#define POWERMODE_DRIVER_VMAJ		1
+#define POWERMODE_DRIVER_VMIN		0
+
+struct proc_dir_entry *cobalt_powermode_proc;
+
+int __init cobalt_powermode_init (void) {
+	printk (KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", POWERMODE_DRIVER, POWERMODE_DRIVER_VMAJ, POWERMODE_DRIVER_VMIN);
+	if (cobt_is_monterey ()) {
+		printk (KERN_INFO "    NOTE: Monterey systems do not support the powermode \"on\"\n");
+	} else if (cobt_is_3k ()) {
+		EPRINTK ("No support for GenIII systems!\n");
+		return -ENOENT;
+	}
+
+	cobalt_powermode_proc = create_proc_entry ("powermode", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, proc_cobalt);
+	if (! cobalt_powermode_proc) {
+		EPRINTK ("Cannot create /proc/cobalt/powermode\n");
+		return -ENOENT;
+	}
+	cobalt_powermode_proc->owner = THIS_MODULE;
+	cobalt_powermode_proc->write_proc = cobalt_powermode_write_proc;
+	cobalt_powermode_proc->read_proc = cobalt_powermode_read_proc;
+	return 0;
+}
+
+void __exit cobalt_powermode_exit (void) {
+	if (cobalt_powermode_proc) {
+		remove_proc_entry ("powermode", proc_cobalt);
+		cobalt_powermode_proc = NULL;
+	}
+}
+
+int cobalt_powermode_read_proc (char *buf, char **st, off_t off, int len, int *eof, void *x) {
+	int rlen;
+	
+	get_powermode ();
+	
+	rlen = 0;
+	if (cobalt_powermode_status == COBALT_POWER_ON) {
+		rlen += sprintf(buf + rlen, "on\n");
+	} else if (cobalt_powermode_status == COBALT_POWER_OFF) {
+		rlen += sprintf(buf + rlen, "off\n");
+	} else if (cobalt_powermode_status == COBALT_POWER_SAME) {
+		rlen += sprintf(buf + rlen, "same\n");
+	} else {
+		rlen += sprintf(buf + rlen, "uknown\n");
+	}
+	return cobalt_gen_proc_read(buf, rlen, st, off, len, eof);
+}
+
+int cobalt_powermode_write_proc (struct file *file, const char *buffer, unsigned long count, void *data) {
+	int len, set_ret;
+	char *p;
+	char buf [9];
+	enum cobalt_powermode val;
+	
+	if (count > 8)
+	  len = 8;
+	else
+	  len = count;
+	
+	if (copy_from_user (buf, buffer, len)) {
+	  return -EFAULT;
+	}
+	buf [len] = '\0';
+	
+	val = simple_strtol(buf, &p, 0);
+	if (p != buf) {
+		if ((val < 1) || (val > 3)) {
+			return -EINVAL;
+		}
+		cobalt_powermode_status = val;
+	} else {
+		if (buf [len - 1] == '\n')
+			buf [len - 1] = '\0';
+		if (! strcmp (buf, "on")) {
+			cobalt_powermode_status = COBALT_POWER_ON;
+		} else if (! strcmp (buf, "off")) {
+			cobalt_powermode_status = COBALT_POWER_OFF;
+		} else if (! strcmp (buf, "same")) {
+			cobalt_powermode_status = COBALT_POWER_SAME;
+		} else {
+			return -EINVAL;
+		}
+	}
+	set_ret = set_powermode ();
+	if (set_ret != 0) {
+		return set_ret;
+	}
+	return len;	
+}
+
+static int set_powermode (void) {
+	int r0,r1;
+	int fail, apply;
+	
+	r0 = 0; r1 = 0;
+	
+	fail = cobalt_powermode_fail (0, 0);
+	apply = cobalt_powermode_apply (0, 0);
+	
+	switch (cobalt_powermode_status) {
+		case COBALT_POWER_ON:
+			r0 = cobalt_powermode_fail (1, 1);
+			r1 = cobalt_powermode_apply (1, 1);
+			break;
+		case COBALT_POWER_OFF:
+			r0 = cobalt_powermode_fail (1, 0);
+			r1 = cobalt_powermode_apply (1, 0);
+			break;
+		case COBALT_POWER_SAME:
+			r0 = cobalt_powermode_fail (1, 1);
+			r1 = cobalt_powermode_apply (1, 0);
+			break;
+	}
+	
+	if (r0 < 0 || r1 < 0) {
+		cobalt_powermode_fail (1, fail);
+		cobalt_powermode_apply (1, apply);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void get_powermode (void) {
+	int fail, apply;
+	
+	fail = cobalt_powermode_fail (0, 0);
+	apply = cobalt_powermode_apply (0, 0);
+	
+	if (fail && apply) {
+		cobalt_powermode_status = COBALT_POWER_ON;
+	} else if (! fail && ! apply) {
+		cobalt_powermode_status = COBALT_POWER_OFF;
+	} else if (fail && ! apply) {
+		cobalt_powermode_status = COBALT_POWER_SAME;
+	} else {
+		
+	}
+}
+
+static int cobalt_powermode_fail (const int set, const int val) {
+	int r = 0;
+	if (cobt_is_monterey ()) {
+		u8 reg;
+		unsigned long flags;
+
+		spin_lock_irqsave (&rtc_lock, flags);
+		superio_set_rtc_bank (PC87317_RTC_BANK_APC);
+		reg = CMOS_READ (PC87317_APCR6);
+		r = reg & 0x80 ? 0 : 1;
+		if (set) {
+			if (val) {
+				reg &= ~0xc0;
+			} else {
+				reg |= 0x80;
+			}
+			CMOS_WRITE (reg, PC87317_APCR6);
+		}
+		superio_set_rtc_bank (PC87317_RTC_BANK_MAIN);
+		spin_unlock_irqrestore (&rtc_lock, flags);
+	} else if (cobt_is_alpine ()) {
+		u16 addr;
+		u8 reg;
+		
+		addr = superio_ldev_base (PC87417_DEV_SWC);
+		reg = inb (addr + PC87417_SWC_PWONCTL);
+		r = reg & 0x20 ? 1 : 0;
+		if (set) {
+			if (val) {
+				reg |= 0x20;
+			} else {
+				reg &= ~0x20;
+			}
+			outb (reg, addr + PC87417_SWC_PWONCTL);
+		}
+	}
+	return r;
+}
+
+#define NS_GP1_EN0_PME2_E	0x02
+#define NS_EVENT_WAKEUP_S345	0x03
+static int cobalt_powermode_apply (const int set, const int val) {
+	int r = 0;
+	if (cobt_is_monterey ()) {
+#if 0 /* not supported on monterey hardware */
+		u8 reg;
+		u16 pmaddr;
+		u16 gpeaddr;
+	
+		/* figure out the PM base address */
+		pmaddr = superio_ldev_base (PC87317_DEV_PM);
+		/* figure out the GPE base address */
+		outb (PC87317_PMDEV_GPELO, pmaddr);
+		gpeaddr = inb (pmaddr + 1);
+		outb (PC87317_PMDEV_GPEHI, pmaddr);
+		gpeaddr |= inb (pmaddr + 1) << 8;
+
+		reg = inb (gpeaddr + PC87317_GPE_GP1_EN0);
+		r = (reg & NS_GP1_EN0_PME2_E) ? 1 : 0;
+		if (set) {
+			if (val) {
+				reg |= NS_GP1_EN0_PME2_E;
+			} else {
+				reg &= ~NS_GP1_EN0_PME2_E;
+			}
+			outb (reg, gpeaddr + PC87317_GPE_GP1_EN0);
+		}
+#endif
+		if (set && val) {
+			return -1;
+		} else {
+			return 0;
+		}
+	} else if (cobt_is_alpine ()) {
+		u16 pmaddr;
+		u8 reg;
+
+		/* power event is attached to GPIOE42 */
+		pmaddr = superio_ldev_base (PC87417_DEV_SWC);
+		outb (PC87417_SWCWKEVENT_GPIOE42, pmaddr + PC87417_SWC_WKEVENT);
+		reg = inb (pmaddr + PC87417_SWC_WKSTATE);
+		r = reg & NS_EVENT_WAKEUP_S345 ? 1 : 0;
+		if (set) {
+			if (val) {
+				reg |= NS_EVENT_WAKEUP_S345;
+			} else {
+				/* disable wakeup */
+				reg &= ~NS_EVENT_WAKEUP_S345;
+			}
+			outb (reg, pmaddr + PC87417_SWC_WKSTATE);
+		}
+	}
+	return r;
+}
+
+//#ifdef MODULE
+//module_init (cobalt_powermode_init);
+//module_exit (cobalt_powermode_exit);
+//#endif
+
+//MODULE_AUTHOR ("Sun Cobalt");
+//MODULE_DESCRIPTION ("Power State Storage");
+//MODULE_LICENSE ("GPL");
+
+#endif
diff -Nurb linux-2.6.24.3/drivers/cobalt/raminfo.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/raminfo.c
--- linux-2.6.24.3/drivers/cobalt/raminfo.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/raminfo.c	2008-03-02 14:55:48.000000000 -0800
@@ -0,0 +1,318 @@
+/* $Id: raminfo.c,v 1.7 2001/10/29 22:21:36 thockin Exp $
+ *
+ * Copyright (c) 2000-2001 Sun Microsystems, Inc.
+ * All Rights Reserved.
+ *
+ * This is SMP safe - the init runs once on load, and the rest is just
+ * printing information. --TPH
+ */
+#if defined(CONFIG_COBALT_RAMINFO) || defined(CONFIG_COBALT_RAMINFO_MODULE)
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+
+#include <cobalt/cobalt.h>
+#include <cobalt/systype.h>
+
+#define RAM_DRIVER			"Cobalt Networks RAM Info driver"
+#define RAM_DRIVER_VMAJ		1
+#define RAM_DRIVER_VMIN		0
+
+#define MAX_DIMM_SLOTS	4
+
+enum dimm_t {
+	DIMM_TYPE_FPM_DRAM,
+	DIMM_TYPE_EDO_DRAM,
+	DIMM_TYPE_REG_SDRAM,
+	DIMM_TYPE_SDRAM
+};
+
+static char *dimm_desc[] = {
+	"Fast-page Mode DRAM",
+	"EDO DRAM",
+	"Registered SDRAM",
+	"SDRAM",
+};
+
+struct dimm_slot {
+	int num;
+	enum dimm_t type;
+	uint16_t size;
+	int ecc;
+};
+
+struct raminfo {
+	int total;
+	int (*query)(struct dimm_slot *);
+	struct pci_dev *dev;
+	struct dimm_slot *dimm;
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *proc;
+#endif /* CONFIG_PROC_FS */
+};
+
+/*########################################################################*/
+
+static int serverworks_le_dimm_info(struct dimm_slot *);
+static int ali_1541_dimm_info(struct dimm_slot *);
+static int raminfo_read_proc(char*, char**, off_t, int, int*, void*);
+
+/* RaQ-3, RaQ-4, Qube-3
+ * - uses ALI M1541 for memory controller
+ * - has 2 dimm slots */
+static struct raminfo gen3_raminfo = {
+	total: 2,
+	query: ali_1541_dimm_info
+};
+/* RaQ-XTR (Monterey)
+ * - uses ServerWorks CNB30LE for Memory Controller
+ * - has 4 dimm slots */
+static struct raminfo gen5_monterey_raminfo = {
+	total: 4,
+	query: serverworks_le_dimm_info
+};
+/* RaQ (Alpine)
+ * - uses ServerWorks CNB30LE for Memory Controller
+ * - has 2 dimm slots */
+static struct raminfo gen5_alpine_raminfo = {
+	total: 2,
+	query: serverworks_le_dimm_info
+};
+
+static struct raminfo *sys_raminfo;
+
+/*########################################################################*/
+
+#define SERVERWORKS_DRAM_MRPR		(0x90)
+#define SERVERWORKS_DRAM_MRAR(slot)	(0x7c + (slot))
+#define SERVERWORKS_DRAM_ECCR		(0xe0)
+
+static int
+serverworks_le_dimm_info(struct dimm_slot *dimm)
+{
+	int row;
+	uint8_t rar, active, eccr;
+	uint16_t ma_map[] = {
+		32, 16, 32, 256, 512, 128, 128, 64, 256, 128, 64, 64, 128,
+	};
+
+	if (!sys_raminfo || !sys_raminfo->dev || !dimm)
+		return -ENOSYS;
+
+	pci_read_config_byte(sys_raminfo->dev,
+			     SERVERWORKS_DRAM_MRPR, &active);
+	pci_read_config_byte(sys_raminfo->dev,
+			     SERVERWORKS_DRAM_MRAR(dimm->num), &rar);
+
+	/* serverworks uses only registered sdram */
+	dimm->type = DIMM_TYPE_REG_SDRAM;
+	dimm->size = 0;
+
+	/* check to see if ECC is enabled (bit 4 of reg 0xE0) */
+	pci_read_config_byte(sys_raminfo->dev,
+			     SERVERWORKS_DRAM_ECCR, &eccr);
+	dimm->ecc = (eccr & (1<<2)) ? 1 : 0;
+
+	/* two rows for each dimm slot */
+	for (row=2*dimm->num; row<=(2*dimm->num+1); row++) {
+		/* each active row will have corresponding bit
+		 * set in the Memory Row Presence Register */
+		if (active & (1 << row)) {
+			/* lookup size ma_map table */
+			dimm->size += ma_map[ rar & 0xf ];
+		}
+		/* two rows per RAR register, bits 7-4 and bits 3-0 */
+		rar >>= 4;
+	}
+
+	return 0;
+}
+
+#define ALI_DRAM_CONF_1(row)		(0x60 + ((row) * 2))
+#define ALI_DRAM_CONF_2(row)		(0x61 + ((row) * 2))
+#define ALI_DIMM_TYPE(d2)		(((d2) >> 4) & 0x3)
+#define ALI_DIMM_MMAP(d2)		(((d2) >> 6) & 0x3)
+#define ALI_DIMM_SIZE(d1, d2)		(((((d2) & 0xf) << 8) | (d1)) + 1)
+
+static int
+ali_1541_dimm_info(struct dimm_slot *dimm)
+{
+	int row;
+	uint8_t dbc1, dbc2;
+
+	if (!sys_raminfo || !sys_raminfo->dev || !dimm)
+		return -ENOSYS;
+
+	dimm->size = 0;
+	dimm->ecc  = 0;
+
+	/* read two rows per dimm (for double-side) */
+	for (row=2*dimm->num; row<=(2*dimm->num + 1); row++) {
+		pci_read_config_byte(sys_raminfo->dev,
+				     ALI_DRAM_CONF_2(row), &dbc2);
+
+		/* row is empty iff dimm type and ma_map are both 0 */
+		if (!ALI_DIMM_TYPE(dbc2) && !ALI_DIMM_MMAP(dbc2))
+			continue;
+
+		pci_read_config_byte(sys_raminfo->dev,
+				     ALI_DRAM_CONF_1(row), &dbc1);
+
+		/* type is bits 4-5 of dimm conf reg 2 */
+		dimm->type = ALI_DIMM_TYPE(dbc2);
+
+		/* A27-A20 address lines are bits 7-0 of dimm conf reg 1
+		 * A31-A28 address lines are bits 3-0 of dimm conf reg 2 */
+		dimm->size = ALI_DIMM_SIZE(dbc1, dbc2);
+	}
+
+	/* the M1541 uses "not less than" policy to determine which row a
+	 * memory address resides in.  the top address boundary for each
+	 * row is the maximum memory value minus 1.  so to determine the 
+	 * size of a row you must subtract the size of the previous row.
+	 * (unless this is slot 0 or the first populated slot) */
+	if (dimm->num > 0 && dimm->size > 0) {
+		uint16_t sz;
+		pci_read_config_byte(sys_raminfo->dev,
+				     ALI_DRAM_CONF_1(2*dimm->num - 1), &dbc1);
+		pci_read_config_byte(sys_raminfo->dev,
+				     ALI_DRAM_CONF_2(2*dimm->num - 1), &dbc2);
+		sz = ALI_DIMM_SIZE(dbc1, dbc2);
+		dimm->size -= (sz > 1) ? sz : 0;
+	}
+	
+	return 0;
+}
+
+int __init
+cobalt_raminfo_init(void)
+{
+	int j;
+
+	/* determine system type and find memory controller pci dev
+	 * so we don't have to do pci lookup for each proc read */
+	if (cobt_is_3k()) {
+		sys_raminfo = &gen3_raminfo;
+		sys_raminfo->dev = pci_find_device(PCI_VENDOR_ID_AL,
+				   PCI_DEVICE_ID_AL_M1541, NULL);
+	} else if (cobt_is_5k()) {
+		if (cobt_is_monterey()) {
+			sys_raminfo = &gen5_monterey_raminfo;
+		} else if (cobt_is_alpine()) {
+			sys_raminfo = &gen5_alpine_raminfo;
+		} else {
+			EPRINTK("unable to identify gen5 board\n");
+			return -ENOSYS;
+		}
+		sys_raminfo->dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+				   PCI_DEVICE_ID_SERVERWORKS_LE, NULL);
+	}
+
+	if (!sys_raminfo || !sys_raminfo->dev) {
+		EPRINTK("unable to identify system type\n");
+		return -ENOSYS;
+	}
+	
+	printk(KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", RAM_DRIVER,RAM_DRIVER_VMAJ,RAM_DRIVER_VMIN);
+
+#ifdef CONFIG_PROC_FS
+	/* add entry to /proc filesytem */
+	sys_raminfo->proc = create_proc_entry("raminfo",
+			    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, proc_cobalt);
+	if (!sys_raminfo->proc) {
+		EPRINTK("can't create /proc/cobalt/raminfo\n");
+		return -ENOENT;
+	}
+	sys_raminfo->proc->owner = THIS_MODULE;
+	sys_raminfo->proc->write_proc = NULL;
+	sys_raminfo->proc->read_proc = raminfo_read_proc;
+#endif /* CONFIG_PROC_FS */
+
+	/* create arrary of dimm slots to store info */
+	sys_raminfo->dimm = kmalloc(
+		sys_raminfo->total * sizeof(struct dimm_slot), GFP_ATOMIC);
+	if (!sys_raminfo->dimm) {
+		EPRINTK("unable to allocate memory\n");
+#ifdef CONFIG_PROC_FS
+		if (sys_raminfo->proc) {
+			remove_proc_entry("raminfo", proc_cobalt);
+			sys_raminfo->proc = NULL;
+		}
+#endif /* CONFIG_PROC_FS */
+		return -ENOMEM;
+	}
+
+	{
+		struct dimm_slot *ds = sys_raminfo->dimm;
+		for (j=0; j<sys_raminfo->total; j++, ds++) {
+			if (!ds) continue;
+			ds->num = j;
+			if (sys_raminfo->query(ds) < 0) {
+				EPRINTK("unable to read dimm %d\n", j);
+				ds->num = -1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static void __exit
+cobalt_raminfo_exit(void)
+{
+#ifdef CONFIG_PROC_FS
+	if (sys_raminfo->proc) {
+		remove_proc_entry("raminfo", proc_cobalt);
+		sys_raminfo->proc = NULL;
+	}
+#endif /* CONFIG_PROC_FS */
+
+	if (sys_raminfo->dimm) {
+		kfree(sys_raminfo->dimm);
+		sys_raminfo->dimm = NULL;
+	}
+
+	sys_raminfo->dev = NULL;
+	sys_raminfo = NULL;
+}
+
+#ifdef CONFIG_PROC_FS
+static int
+raminfo_read_proc(char *buf, char **st, off_t off, int len, int *eof, void *x)
+{
+	int rlen, i;
+	struct dimm_slot *ds;
+
+	if (!sys_raminfo)
+		return -ENOSYS;
+
+	//MOD_INC_USE_COUNT;
+
+	ds = sys_raminfo->dimm;
+	for (rlen=i=0; i<sys_raminfo->total; i++, ds++) {
+		if (!ds || ds->num < 0)
+			continue;
+		rlen += sprintf(buf+rlen, "%d [%s%s]: %u MB\n", i,
+				ds->size ? dimm_desc[ds->type] : "Empty",
+				ds->size ? ds->ecc ? "+ECC" : "" : "",
+				ds->size);
+	}
+
+	//MOD_DEC_USE_COUNT;
+
+	return cobalt_gen_proc_read(buf, rlen, st, off, len, eof);
+}
+#endif /* CONFIG_PROC_FS */
+
+#ifdef CONFIG_COBALT_RAMINFO_MODULE
+module_init(cobalt_raminfo_init);
+module_exit(cobalt_raminfo_exit);
+#endif
+
+MODULE_AUTHOR("Sun Cobalt");
+MODULE_DESCRIPTION("DIMM Information");
+MODULE_LICENSE("GPL");
+
+#endif /* CONFIG_COBALT_RAMINFO || CONFIG_COBALT_RAMINFO_MODULE */
diff -Nurb linux-2.6.24.3/drivers/cobalt/README linux-2.6.24.3-cobalt3-tw/drivers/cobalt/README
--- linux-2.6.24.3/drivers/cobalt/README	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/README	2008-03-02 14:55:48.000000000 -0800
@@ -0,0 +1,19 @@
+Notes on Cobalt's drivers:
+
+You will notice in several places constructs such as this:
+
+	if (cobt_is_3k()) {
+		foo();
+	} else if (cobt_is_5k()) {
+		bar();
+	}
+
+The goal here is to only compile in code that is needed, but to allow one to
+define support for both 3k and 5k (and more?) style systems.  The systype
+check macros are very simple and clean.  They check whether config-time
+support for the generation has been enabled, and (if so) whether the current
+systype matches the spcified generation.  This leaves the code free from 
+#ifdef cruft, but lets the compiler throw out unsupported generation-specific 
+code with if (0) detection.
+
+--
diff -Nurb linux-2.6.24.3/drivers/cobalt/ruler.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/ruler.c
--- linux-2.6.24.3/drivers/cobalt/ruler.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/ruler.c	2008-03-02 14:55:48.000000000 -0800
@@ -0,0 +1,418 @@
+/* 
+ * cobalt ruler driver 
+ * Copyright (c) 2000, Cobalt Networks, Inc.
+ * Copyright (c) 2001, Sun Microsystems, Inc.
+ * $Id: ruler.c,v 1.23 2002/08/29 00:33:01 uzi Exp $
+ *
+ * author: asun@cobalt.com, thockin@sun.com
+ *
+ * This should be SMP safe.  There is one critical piece of data, and thus
+ * one lock.  The ruler_lock protects the arrays of channels(hwifs) and
+ * busproc function pointers.  These are only ever written in the
+ * register/unregister functions but read in several other places.  A
+ * read/write lock is appropriate. The global switches and sled_leds are 
+ * atomic_t. --TPH
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/ide.h>
+#include <linux/hdreg.h>
+#include <linux/notifier.h>
+#include <linux/sysctl.h>
+#include <linux/reboot.h>
+#include <linux/delay.h>
+#include <linux/ide.h>
+#include <asm/io.h>
+
+#include <cobalt/cobalt.h>
+#include <cobalt/systype.h>
+#include <cobalt/i2c.h>
+#include <cobalt/acpi.h>
+#include <cobalt/led.h>
+#include <cobalt/ruler.h>
+
+#define RULER_TIMEOUT		(HZ >> 1)  /* .5s */
+#define MAX_COBT_DRIVES		4
+
+#define RULER_DRIVER			"Cobalt Networks Disk Ruler driver"
+#define RULER_DRIVER_VMAJ		1
+#define RULER_DRIVER_VMIN		0
+
+/* all of this is for gen V */
+static struct timer_list cobalt_ruler_timer;
+static rwlock_t ruler_lock = RW_LOCK_UNLOCKED;
+static ide_drive_t *channels[MAX_COBT_DRIVES];
+
+static int (*busprocs[MAX_COBT_DRIVES])(ide_drive_t *, int);
+
+//static cob_busprocs_t busprocs[MAX_COBT_DRIVES];
+
+/* NOTE: switches is a bitmask of DETACHED sleds */
+static atomic_t switches = ATOMIC_INIT(0);	
+static atomic_t sled_leds = ATOMIC_INIT(0);
+static int sled_led_map[] = {LED_SLED0, LED_SLED1, LED_SLED2, LED_SLED3};
+static int ruler_detect;
+static int initialized;
+
+static void ruler_hwif_added(ide_hwif_t *hwif, int idx);
+
+static inline u8
+read_switches(void)
+{
+	u8 state = 0;
+	if (cobt_is_monterey()) {
+		int tries = 3;
+
+		/* i2c can be busy, and this can read wrong - try a few times */
+		while (tries--) {
+			state = cobalt_i2c_read_byte(COBALT_I2C_DEV_DRV_SWITCH, 
+				0);
+			if ((state & 0xf0) != 0xf0) {
+				break;
+			}
+		}
+	}
+
+	return state;
+}
+
+static inline unsigned int
+get_sled_leds(void)
+{
+	return atomic_read(&sled_leds);
+}
+
+/*
+ * deal with sled leds: LED on means OK to remove
+ * NOTE: all the reset lines are kept high. 
+ * NOTE: the reset lines are in the reverse order of the switches. 
+ */
+static void
+set_sled_leds(unsigned int leds)
+{
+	if (cobt_is_monterey()) {
+		unsigned int offed = get_sled_leds();
+
+		offed &= ~leds;
+		atomic_set(&sled_leds, leds);
+#ifdef CONFIG_COBALT_LED
+		cobalt_led_clear_bits_lazy(offed);
+		cobalt_led_set_bits_lazy(leds);
+#endif
+	}
+}
+
+/* this must be called with the ruler_lock held for read */
+static int
+do_busproc(int idx, ide_drive_t *drive, int arg)
+{
+	if (cobt_is_monterey()) {
+		/* sed sled LEDs */
+		switch (arg) {
+			case BUSSTATE_ON:
+				set_sled_leds(get_sled_leds() & 
+					~sled_led_map[idx]);
+				break;
+			case BUSSTATE_OFF:
+			case BUSSTATE_TRISTATE:
+				set_sled_leds(get_sled_leds() | 
+					sled_led_map[idx]);
+				break;
+			default:
+				WPRINTK("unknown busproc argument (%d)\n", arg);
+		}
+	}
+
+	/* do the real work */
+	return busprocs[idx](drive, arg);
+}
+
+static void 
+ruler_timer_fn(unsigned long data)
+{
+	if (cobt_is_monterey()) {
+		u8 state;
+		int i;
+		unsigned int now, expected, bit, swcur;
+
+		state = read_switches();
+		if ((state & 0xf0) == 0xf0) {
+			return;
+		}
+		swcur = atomic_read(&switches);
+	
+		state &= 0xf;
+		read_lock(&ruler_lock);
+		for (i = 0; i < MAX_COBT_DRIVES; i++) {
+			bit = 1 << i;
+			now = state & bit;
+			expected = swcur & bit;
+			if (now == expected) {
+				/* no changes to worry about */
+				continue;
+			}
+
+			if (now) {
+				/* a freshly detached drive */
+				atomic_set(&switches, swcur | bit);
+		 		if (channels[i]) {
+					printk("disabling ide ruler "
+						"channel %d\n", i);
+					do_busproc(i, channels[i], 
+						BUSSTATE_TRISTATE);
+		 		} else {
+					WPRINTK("drive detach on bad "
+						"channel (%d)\n", i);
+				}
+				set_sled_leds(get_sled_leds() | 
+					sled_led_map[i]);
+			} else {
+				/* 
+				 * do we want to do anything when a re-attach 
+				 * is detected?
+				 */
+			}
+		}
+		read_unlock(&ruler_lock);
+	}
+}
+
+#ifdef CONFIG_COBALT_ACPI
+static int
+ruler_interrupt(cobalt_acpi_evt *evt, void * data)
+{
+	if (cobt_is_monterey() && ruler_detect) {
+		u8 state;
+
+		state = read_switches();
+		if ((state & 0xf0) != 0xf0) {
+			/* this is protected inside mod_timer */
+			mod_timer(&cobalt_ruler_timer, jiffies + RULER_TIMEOUT);
+		}
+		
+		evt->ev_data = state;
+		/* empirical: delay enough to debounce */
+		udelay(10);
+	}
+	return 0;
+}
+#endif /* CONFIG_COBALT_ACPI */
+
+#if defined(CONFIG_COBALT_LED)
+/* figure which LEDs to blink */
+static unsigned int
+ide_led_handler(void *data)
+{
+	ide_hwif_t *hwif;
+	unsigned int leds = 0;
+
+	if (cobt_is_monterey()) {
+		int i;
+		static int ledmap[MAX_COBT_DRIVES] = { 
+			LED_DISK0, LED_DISK1, LED_DISK2, LED_DISK3
+		};
+		static unsigned long old[MAX_COBT_DRIVES];
+
+		read_lock(&ruler_lock);
+
+		for (i = 0; i < MAX_COBT_DRIVES; i++) {
+			if (channels[i])
+			{
+				hwif = HWIF(channels[i]);
+				if (hwif->drives[0].present &&
+				    hwif->drives[0].service_start != old[i]) {
+					leds |= ledmap[i];
+					old[i] = hwif->drives[0].service_start;
+				}
+			}
+		}
+
+		read_unlock(&ruler_lock);
+	}
+
+	return leds;
+}
+#endif
+
+/* this is essentially an exported function - it is in the hwif structs */
+static int ruler_busproc_fn(ide_drive_t *drive, int arg)
+{
+	int r = 0;
+	if (cobt_is_monterey()) {
+		int idx;
+
+		read_lock(&ruler_lock);
+
+		for (idx = 0; idx < MAX_COBT_DRIVES; idx++) {
+			if (channels[idx] == drive) {
+				break;
+			}
+		}
+
+		if (idx >= MAX_COBT_DRIVES) {
+			/* not a hwif we manage? */
+			return 0;
+		}
+
+		r = do_busproc(idx, drive, arg);
+		read_unlock(&ruler_lock);
+	}
+
+	return r;
+}
+	
+/* 
+ * We try to be VERY explicit here.  Fine for now, may eventually break down.
+ */
+void 
+cobalt_ruler_register(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = HWIF(drive);
+
+	if (cobt_is_monterey()) {
+		struct pci_dev *dev;
+		int idx;
+		unsigned long flags;
+
+		if (!hwif) {
+			return;
+		}
+
+		/* Cobalt rulers only have HPT370 controllers on bus 1 */
+		dev = hwif->pci_dev;
+		if (!dev)
+			return;
+
+		if (dev->vendor != PCI_VENDOR_ID_TTI
+		 || dev->device != PCI_DEVICE_ID_TTI_HPT366
+		 || dev->bus->number != 1) {
+			/* ignore it */
+			return;
+		}
+
+		/* IDE ruler has controllers at dev 3 and 4, ONLY */
+		if (dev->devfn == PCI_DEVFN(3,0)) {
+			idx = hwif->channel;
+		} else if (dev->devfn == PCI_DEVFN(4,0)) {
+			idx = 2 + hwif->channel;
+		} else {
+			return;
+		}
+
+		if (idx >= MAX_COBT_DRIVES) {
+			return;
+		}
+
+		write_lock_irqsave(&ruler_lock, flags);
+
+		/* save a pointer to the hwif, and trap it's busproc() */
+		channels[idx] = drive;
+		if (hwif->busproc) {
+			busprocs[idx] = HWIF(drive)->busproc;
+			hwif->busproc = &ruler_busproc_fn;
+		}
+
+		write_unlock_irqrestore(&ruler_lock, flags);
+
+		/* now that we have trapped it, do what we need to initialize 
+		 * the drive - if we haven't been initialized, we'll call this
+		 * later. 
+		 */
+		if (initialized) {
+			ruler_hwif_added(hwif, idx);
+		}
+	}
+}
+
+static void
+ruler_hwif_added(ide_hwif_t *hwif, int idx)
+{
+	/* the associated switch should be closed */
+	if (hwif->drives[0].present) {
+		/* set the sled LED off - not safe to remove */
+		set_sled_leds(get_sled_leds() & ~sled_led_map[idx]);
+	}
+}
+
+void cobalt_ruler_unregister(ide_drive_t *drive)
+{
+	if (cobt_is_monterey()) {
+		int i;
+		unsigned long flags;
+
+		write_lock_irqsave(&ruler_lock, flags);
+
+		for (i = 0; i < MAX_COBT_DRIVES; i++) {
+			if (channels[i] == drive) {
+				channels[i] = NULL;
+				HWIF(drive)->busproc = busprocs[i];
+				busprocs[i] = NULL;
+			}
+		}
+
+		write_unlock_irqrestore(&ruler_lock, flags);
+	}
+}
+
+int __init 
+cobalt_ruler_init(void)
+{
+	if (cobt_is_monterey()) {
+		int err;
+		u8 tmp;
+		int i;
+
+		/* initialize switches */
+		tmp = read_switches();
+		ruler_detect = ((tmp & 0xf0) == 0xf0) ? 0 : 1;
+		tmp &= 0xf;
+		atomic_set(&switches, tmp);
+
+		/* initialize our timer */
+		init_timer(&cobalt_ruler_timer);
+		cobalt_ruler_timer.function = ruler_timer_fn;
+        
+        printk(KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", RULER_DRIVER,RULER_DRIVER_VMAJ,RULER_DRIVER_VMIN);
+        
+#ifdef CONFIG_COBALT_ACPI
+		err = cobalt_acpi_register_evt_handler(ruler_interrupt, 
+			COBALT_ACPI_EVT_SLED, NULL );
+		
+		if (err) {
+			EPRINTK("can't register interrupt handler %p\n", 
+				ruler_interrupt);
+		}
+#endif
+        
+		/* set initial sled LED state */
+		set_sled_leds(LED_SLED0 | LED_SLED1 | LED_SLED2 | LED_SLED3);
+
+		/* run through any devices that were registered before */
+		for (i = 0; i < MAX_COBT_DRIVES; i++) {
+			if (channels[i]) {
+				ruler_hwif_added(HWIF(channels[i]), i);
+			}
+		}
+		
+#if defined(CONFIG_COBALT_LED)
+		/* register for a blinky LEDs callback */
+		err = cobalt_fpled_register(ide_led_handler, NULL);
+		if (err) {
+			EPRINTK("can't register LED handler %p\n", 
+				ide_led_handler);
+		}
+#endif
+	}
+
+	initialized = 1;
+
+	return 0;
+}
diff -Nurb linux-2.6.24.3/drivers/cobalt/sensors.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/sensors.c
--- linux-2.6.24.3/drivers/cobalt/sensors.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/sensors.c	2008-03-02 14:55:48.000000000 -0800
@@ -0,0 +1,523 @@
+/* $Id: sensors.c,v 1.31 2002/08/29 00:33:01 uzi Exp $
+ * Copyright (c) 2000-2001 Sun Microsystems, Inc 
+ *
+ * This should be SMP safe.  There is just one race - the read in /proc.
+ * It now guards against itself with a semaphore.  Note that we don't use a
+ * spinlock because any of the methods may (and do!) block.
+ */
+#ifdef CONFIG_COBALT_SENSORS
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/proc_fs.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <cobalt/cobalt.h>
+#include <cobalt/systype.h>
+#include <cobalt/i2c.h>
+#include <cobalt/sensors.h>
+#include <cobalt/acpi.h>
+
+#define SENS_DRIVER			"Cobalt Networks Sensor driver"
+#define SENS_DRIVER_VMAJ		1
+#define SENS_DRIVER_VMIN		0
+
+/* externals */
+unsigned int cobalt_nthermals;
+unsigned int cobalt_nvoltages;
+
+/* data about a sensor for generic handling */
+/* we could add data about a low/high range, if needed */
+struct sensor {
+	int sensor; /* sensor #, so maps can be logically ordered */
+	char *desc;
+	int last_val;
+	unsigned long cache;
+	unsigned long cache_timeout;
+	/* pre/post hook - 1 for pre, 0 for post */
+	void (*setup)(struct sensor *s, int pre); 
+	/* read as an int, to be passed to format() */
+	int (*read)(struct sensor *s);
+	/* hook for scaling values */
+	int (*scale)(struct sensor *s, int val);
+	/* format the value as a string */
+	char *(*format)(struct sensor *s, int val, char *buf, int len);
+};
+
+/* some stuff for generic formatting */
+#define DEC_SCALAR		100
+static char *decimal_format(struct sensor *s, int val, char *buf, int len);
+
+static DECLARE_MUTEX(sensor_sem);
+static struct sensor *therm_map;
+static struct sensor *volt_map;
+
+#define CACHE_DEF		30
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *proc_csensors;
+static struct proc_dir_entry *proc_therm;
+static struct proc_dir_entry *proc_volt;
+static int therm_read_proc(char *buf, char **start, off_t pos, int len,
+	int *eof, void *x);
+static int therm_write_proc(struct file *file, const char *buf,
+	unsigned long len, void *x);
+static int volt_read_proc(char *buf, char **start, off_t pos, int len,
+	int *eof, void *x);
+static int volt_write_proc(struct file *file, const char *buf,
+	unsigned long len, void *x);
+#endif
+
+static int lm77_therm_read(struct sensor *s);
+static int adm1029_init(void);
+static int adm1029_therm_read(struct sensor *s);
+static int adm1029_volt_read(struct sensor *s);
+static int alpine_vcore_scale(struct sensor *s, int val);
+static void alpine_vbat_switch(struct sensor *s, int pre);
+static int alpine_vbat_scale(struct sensor *s, int val);
+
+/* sensor name mappings */
+static struct sensor gen3_therm_map[] = {
+	{0, "CPU", 0, 0, CACHE_DEF, NULL, lm77_therm_read, NULL, decimal_format},
+};
+static struct sensor monterey_therm_map[] = {
+	{0, "CPU0", 0, 0, CACHE_DEF, NULL, lm77_therm_read, NULL, decimal_format},
+	{1, "CPU1", 0, 0, CACHE_DEF, NULL, lm77_therm_read, NULL, decimal_format},
+	{2, "Case0", 0, 0, CACHE_DEF, NULL, lm77_therm_read, NULL, decimal_format},
+	{3, "Case1", 0, 0, CACHE_DEF, NULL, lm77_therm_read, NULL, decimal_format},
+};
+static struct sensor alpine_therm_map[] = {
+	{1, "CPU", 0, 0, CACHE_DEF, NULL, adm1029_therm_read, NULL, decimal_format},
+	{0, "Case", 0, 0, CACHE_DEF, NULL, adm1029_therm_read, NULL, decimal_format},
+};
+static struct sensor alpine_volt_map[] = {
+	{0, "Vcore", 0, 0, CACHE_DEF, NULL, adm1029_volt_read, 
+		alpine_vcore_scale, decimal_format},
+	{1, "Vtt", 0, 0, CACHE_DEF, NULL, adm1029_volt_read, NULL, decimal_format},
+	{0, "Vbat", 0, 0, CACHE_DEF<<10, alpine_vbat_switch, adm1029_volt_read, 
+		alpine_vbat_scale, decimal_format},
+};
+
+int __init
+cobalt_sensors_init(void)
+{
+	if (cobt_is_3k()) {
+		cobalt_nthermals = 1;
+		cobalt_nvoltages = 0;
+		therm_map = gen3_therm_map;
+	} else if (cobt_is_monterey()) {
+		cobalt_nthermals = 4;
+		cobalt_nvoltages = 0;
+		therm_map = monterey_therm_map;
+	} else if (cobt_is_alpine()) {
+		cobalt_nthermals = 2;
+		cobalt_nvoltages = 3;
+		therm_map = alpine_therm_map;
+		volt_map = alpine_volt_map;
+		adm1029_init();
+	} else  {
+		return -1;
+	}
+    
+    printk(KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", SENS_DRIVER,SENS_DRIVER_VMAJ,SENS_DRIVER_VMIN);
+    
+#ifdef CONFIG_PROC_FS
+	/* make files in /proc */
+	proc_csensors = proc_mkdir("sensors", proc_cobalt);
+	if (!proc_csensors) {
+		EPRINTK("can't create /proc/cobalt/sensors\n");
+		return -1;
+	}
+	if (cobalt_nthermals) {
+		proc_therm = create_proc_entry("thermal",
+					       S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
+					       proc_csensors);
+		if (!proc_therm) {
+			EPRINTK("can't create /proc/cobalt/sensors/thermal\n");
+		}
+		proc_therm->read_proc = therm_read_proc;
+		proc_therm->write_proc = therm_write_proc;
+	}
+	if (cobalt_nvoltages) {
+		proc_volt = create_proc_entry("voltage",
+					      S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
+					      proc_csensors);
+		if (!proc_volt) {
+			EPRINTK("can't create /proc/cobalt/sensors/voltage\n");
+		}
+		proc_volt->read_proc = volt_read_proc;
+		proc_volt->write_proc = volt_write_proc;
+
+	}
+#endif
+
+	return 0;
+}
+
+static char *
+sensor_read(struct sensor *s, char *buf, int len)
+{
+	int val;
+
+	if (s->cache && time_after(s->cache_timeout*HZ + s->cache, jiffies))
+		val = s->last_val;
+	else {
+		if (s->setup) s->setup(s, 1);
+		val = s->read(s);
+		s->last_val = val;
+		s->cache = jiffies;
+		if (s->setup) s->setup(s, 0);
+	}
+		
+	if (s->scale) val = s->scale(s, val);
+	return s->format(s, val, buf, len);
+}
+
+/* exported - nicer inline functions in header */
+char *
+__cobalt_thermal_read(unsigned int idx, char *buf, int len)
+{
+	if (idx >= cobalt_nthermals || !buf) {
+		return NULL;
+	}
+
+	return sensor_read(&therm_map[idx], buf, len);
+}
+
+/* exported - nicer inline functions in header */
+char *
+__cobalt_voltage_read(unsigned int idx, char *buf, int len)
+{
+	if (idx >= cobalt_nvoltages || !buf) {
+		return NULL;
+	}
+
+	return sensor_read(&volt_map[idx], buf, len);
+}
+
+/* generic function for formatting decimal scaled data */
+static char *
+decimal_format(struct sensor *s, int val, char *buf, int len)
+{
+	int plen;
+	
+	if (!buf || len <= 0) {
+		return NULL;
+	}
+
+	plen = snprintf(buf, len, "%d", val/DEC_SCALAR);
+	len -= plen;
+
+	if (val % DEC_SCALAR && len > 0) {
+		snprintf(buf+plen, len, ".%02d", val%DEC_SCALAR);
+	}
+
+	return buf;
+}
+
+#define LM77_TEMP		0x0
+static int 
+lm77_therm_read(struct sensor *s)
+{
+	int sensor = s->sensor;
+	int tmp;
+	int val = 0;
+	int tries = 2;
+
+	/* sometimes it reads as zero... try again */
+	while (tries--) {
+		/* LM77 returns the bytes backwards - <shrug> */
+		/* address = base + deviceid + 1 for read */
+		val = cobalt_i2c_read_word(COBALT_I2C_DEV_LM77 +
+			(sensor<<1) + 1, LM77_TEMP);
+		if (val < 0) {
+			/* read failed, return the last known value */
+			return s->last_val;
+		}
+
+		tmp = (val<<8 & 0xff00) + (val>>8 & 0x00ff);
+		if (tmp) {
+			val = tmp >> 4;
+			val *= DEC_SCALAR;
+			if (tmp & 0x8) {
+				val += DEC_SCALAR/2;
+			}
+			break;
+		}
+	}
+	return val;
+}
+
+#define ADM1029_CTL_CFAULT_OVER		0x01
+#define ADM1029_CTL_ALARM_OVER		0x02
+#define ADM1029_CTL_INT_OVER		0x04
+#define ADM1029_CTL_ALARM_LOW		0x08
+#define ADM1029_CTL_CFAULT_UNDER	0x10
+#define ADM1029_CTL_ALARM_UNDER		0x20
+#define ADM1029_CTL_INT_UNDER		0x40
+#define ADM1029_CTL_LATCH		0x80
+
+#define ADM1029_FAN_CTL(i)		(0x18 + i)
+#define ADM1029_TEMP_CTL(i)		(0x40 + i)
+#define ADM1029_AIN_CTL(i)		(0x50 + i)
+
+#define ADM1029_TEMP_HIGH(i)		(0x90 + i)
+#define ADM1029_TEMP_LOW(i)		(0x98 + i)
+#define ADM1029_AIN_HIGH(i)		(0xa8 + i)
+#define ADM1029_AIN_LOW(i)		(0xb0 + i)
+
+#define ADM1029_TEMP_VALUE(i)		(0xa0 + i)
+#define ADM1029_AIN_VALUE(i)		(0xb8 + i)
+
+#ifdef CONFIG_COBALT_ACPI
+static int
+adm1029_handler(cobalt_acpi_evt *evt, void * data)
+{
+	int j, k;
+
+	switch (evt->ev_type) {
+	case COBALT_ACPI_EVT_SM_INT:
+		evt->ev_data = 0;
+		evt->ev_type = COBALT_ACPI_EVT_VOLT;
+		for (j=0; j<cobalt_nvoltages; j++) {
+			k = cobalt_i2c_read_byte(COBALT_I2C_DEV_ADM1029,
+				 ADM1029_AIN_CTL(volt_map[j].sensor));
+			if (k & ADM1029_CTL_LATCH) {
+				evt->ev_data |= (1 << j);
+				volt_map[j].cache = 0;
+			}
+		}
+		break;
+
+	case COBALT_ACPI_EVT_THERM:
+		evt->ev_data = 0;
+		for (j=0; j<cobalt_nthermals; j++) {
+			k = cobalt_i2c_read_byte(COBALT_I2C_DEV_ADM1029,
+				 ADM1029_TEMP_CTL(therm_map[j].sensor));
+			if (k & ADM1029_CTL_LATCH) {
+				evt->ev_data |= (1 << j);
+				therm_map[j].cache = 0;
+			}
+		}
+		break;
+
+	default:
+		return -1;
+	}
+	return 0;
+}
+#endif /* CONFIG_COBALT_ACPI */
+
+static int 
+adm1029_init(void)
+{
+
+#ifdef CONFIG_COBALT_ACPI
+	cobalt_acpi_register_evt_handler(adm1029_handler, 
+		COBALT_ACPI_EVT_THERM, NULL);
+	cobalt_acpi_register_evt_handler(adm1029_handler, 
+		COBALT_ACPI_EVT_SM_INT, NULL);
+#endif
+
+	return 0;
+}
+
+static int 
+adm1029_therm_read(struct sensor *s)
+{
+	int sensor = s->sensor;
+	int val;
+
+	val = cobalt_i2c_read_byte(COBALT_I2C_DEV_ADM1029, 
+		ADM1029_TEMP_VALUE(sensor));
+	if (val < 0) {
+		/* read failed, return the last known value */
+		return s->last_val;
+	}
+	if (val & 0x80) {
+		val -= 256;
+	}
+	val *= DEC_SCALAR;
+
+	return val;
+}
+
+static int
+adm1029_volt_read(struct sensor *s)
+{
+	int sensor = s->sensor;
+	int val;
+
+	val = cobalt_i2c_read_byte(COBALT_I2C_DEV_ADM1029, 
+		ADM1029_AIN_VALUE(sensor));
+	if (val < 0) {
+		/* read failed, return the last known value */
+		return s->last_val;
+	}
+	
+	/* already scaled by 100 */
+	val *= DEC_SCALAR/100;
+
+	return val;
+}
+
+static int
+alpine_vcore_scale(struct sensor *s, int val)
+{
+	/* the measured Vbat switch cost is negligable
+	 * due to very low current through the diode */
+	return val;
+}
+
+#define VBAT_REG	0x608
+#define VBAT_BIT	0x1
+static void
+alpine_vbat_switch(struct sensor *s, int pre)
+{
+	unsigned char v = inb(VBAT_REG);
+	unsigned long j = jiffies;
+
+	if (pre) {
+		v |= VBAT_BIT;
+		/*
+		 * disable AIN0 INT# assertion before switching to
+		 * Vbat because the input is shared with Vcore and
+		 * their acceptable ranges are very different.
+		 */
+		cobalt_i2c_write_byte(COBALT_I2C_DEV_ADM1029,
+			ADM1029_AIN_CTL(s->sensor), 0x0);
+	} else {
+		v &= ~VBAT_BIT;
+	}
+
+	outb(v, VBAT_REG);
+
+	/*
+	 * wait for the round-robin monitor to complete a cycle
+	 * before _and_ after toggling Vbat switch, otherwise
+	 * stale data in AIN0 will trigger INT# assertion.
+	 */
+	while ((jiffies - j) < HZ) {
+		/* block for ~ 1sec */
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ);
+	}
+
+	if (!pre) {
+		/*
+		 * now re-enable INT# assertion capability for AIN0
+		 * (this also clears the AIN0 fault latch at bit 7)
+		 */
+		cobalt_i2c_write_byte(COBALT_I2C_DEV_ADM1029,
+			ADM1029_AIN_CTL(s->sensor),
+			ADM1029_CTL_INT_OVER | ADM1029_CTL_INT_UNDER);
+	}
+}
+
+static int
+alpine_vbat_scale(struct sensor *s, int val)
+{
+	/* 
+	 * The spec says 2.5V max - but empirically, 3.3V works :)
+	 * The Vbat switch costs 0.3 volts
+	 */
+	if (val) val += (3 * DEC_SCALAR)/10;
+
+	return val;
+}
+
+#ifdef CONFIG_PROC_FS
+static int
+sensor_write_proc(int nsensors, struct sensor *map,
+	struct file *file, const char *buf, unsigned long len, void *x)
+{
+	char *pg;
+
+	if (len > PAGE_SIZE) {
+		return -EOVERFLOW;
+	}
+
+	pg = (char *)__get_free_page(GFP_KERNEL);
+	if (!pg) {
+		return -ENOMEM;
+	}
+
+	if (copy_from_user(pg, buf, len)) {
+		free_page((unsigned long)pg);
+		return -EFAULT;
+	}
+	pg[len] = '\0';
+
+	/* format: `cache_timeout #' in seconds */
+	if (len>15 && !strncmp("cache_timeout ", pg, 14) && isdigit(*(pg+14))) {
+		unsigned long i, sec = simple_strtoul(pg+14, NULL, 0);
+		for (i=0; i<nsensors; i++)
+			map[i].cache_timeout = sec;
+	}
+
+	free_page((unsigned long)pg);
+	return len;
+}
+
+static int
+sensor_read_proc(int nsensors, struct sensor *map,
+	char *buf, char **start, off_t pos, int len, int *eof, void *x)
+{
+	int i;
+	static int plen = 0;
+
+	down(&sensor_sem);
+
+	/* remember how big our last read was to avoid read() calling twice */
+	if (pos && pos >= plen) {
+		*eof = 1;
+		up(&sensor_sem);
+		return 0;
+	}
+
+	plen = 0;
+	for (i = 0; i < nsensors; i++) {
+		char sbuf[32];
+		if (sensor_read(&map[i], sbuf, sizeof(sbuf)))
+			plen += sprintf(buf+plen, "%d [%s]: %s\n", i, map[i].desc, sbuf);
+	}
+
+	up(&sensor_sem);
+
+	return cobalt_gen_proc_read(buf, plen, start, pos, len, eof);
+}
+
+static int
+therm_read_proc(char *buf, char **start, off_t pos, int len, int *eof, void *x)
+{
+	return sensor_read_proc(cobalt_nthermals, therm_map,
+		buf, start, pos, len, eof, x);
+}
+static int
+therm_write_proc(struct file *file, const char *buf, unsigned long len, void *x)
+{
+	return sensor_write_proc(cobalt_nthermals, therm_map, file, buf, len, x);
+}
+
+static int
+volt_read_proc(char *buf, char **start, off_t pos, int len, int *eof, void *x)
+{
+	return sensor_read_proc(cobalt_nvoltages, volt_map,
+		buf, start, pos, len, eof, x);
+}
+static int
+volt_write_proc(struct file *file, const char *buf, unsigned long len, void *x)
+{
+	return sensor_write_proc(cobalt_nvoltages, volt_map, file, buf, len, x);
+}
+#endif /* CONFIG_PROC_FS */
+
+#endif /* CONFIG_COBALT_SENSORS */
diff -Nurb linux-2.6.24.3/drivers/cobalt/serialnum.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/serialnum.c
--- linux-2.6.24.3/drivers/cobalt/serialnum.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/serialnum.c	2008-03-02 14:55:48.000000000 -0800
@@ -0,0 +1,452 @@
+/* $Id: serialnum.c,v 1.15 2001/10/23 20:15:27 thockin Exp $ */
+/*
+ *
+ *   Author: Philip Gladstone, Axent Technologies
+ *           modified for Nat Semi PC[89]7317 by asun@cobalt.com
+ *           ported to 2.4.x by thockin@sun.com
+ *           alpine serial eeprom by erik.glling@sun.com
+ *   Copyright (c) 2000  Axent Technologies, Cobalt Networks
+ *   Copyright (c) 2001  Axent Technologies, Sun Microsystems
+ *
+ *   This module interrogates the DS2401 Silicon Serial Number chip
+ *   that is attached to all x86 Cobalt systems.
+ *
+ *   It exports /proc/cobalt/hostid which is four bytes generated from of 
+ *   the id. It can be linked to /var/adm/hostid or /etc/hostid for the 
+ *   hostid command to use.
+ *
+ *   It exports /proc/cobalt/serialnumber which is the entire 64 bit value 
+ *   read back (in ascii).
+ *
+ *   For the guts of the 1 wire protocol used herein, please see the DS2401
+ *   specification.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * This driver is SMP safe by nature. --TPH
+ */
+#if defined (CONFIG_COBALT_SERNUM) || defined(CONFIG_COBALT_SERNUM_MODULE)
+
+#include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <asm/io.h>
+
+#include <cobalt/cobalt.h>
+#include <cobalt/systype.h>
+#include <cobalt/superio.h>
+#include <cobalt/serialnum.h>
+#include <cobalt/i2c.h>
+
+#include <linux/interrupt.h>
+
+#define SN_DRIVER			"Cobalt Networks Serial Number driver"
+#define SN_DRIVER_VMAJ		1
+#define SN_DRIVER_VMIN		6
+
+/* dependent on systype */
+static unsigned int sn_direction;
+static unsigned int sn_output;
+static unsigned int sn_input;
+static unsigned int sn_mask;
+
+/* 3k style systems */
+#define III_SN_DIRECTION	0x7d
+#define III_SN_OUTPUT		0x7e
+#define III_SN_INPUT		0x7f
+#define III_SN_MASK		0x08
+static struct pci_dev *id_dev;
+
+/* 5k style systems */
+#define V_SN_DIRECTION		(sn_io_base + 0x01)
+#define V_SN_OUTPUT		(sn_io_base + 0x00)
+#define V_SN_INPUT		(sn_io_base + 0x00)
+#define V_SN_MASK		(sn_io_base + 0x01)
+static unsigned int sn_io_base;
+
+#define SSN_SIZE	8	/* bytes */
+static char ssn_string[SSN_SIZE * 2 + 1];
+static unsigned long hostid;
+static int debug;
+#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_COBALT_OLDPROC
+static struct proc_dir_entry *proc_hostid;
+static struct proc_dir_entry *proc_serialnum;
+#endif
+static struct proc_dir_entry *proc_chostid;
+static struct proc_dir_entry *proc_cserialnum;
+#endif
+
+static int
+hostid_read(char *buf, char **start, off_t pos, int len, int *eof, void *x)
+{
+	int plen = sizeof(hostid);
+	memcpy(buf, &hostid, sizeof(hostid));
+	return cobalt_gen_proc_read(buf, plen, start, pos, len, eof);
+}
+
+static int
+serialnum_read(char *buf, char **start, off_t pos, int len, int *eof, void *x)
+{
+	int plen = sizeof(ssn_string);
+	sprintf(buf, "%s\n", ssn_string);
+	return cobalt_gen_proc_read(buf, plen, start, pos, len, eof);
+}
+
+/* set up the requisite IO bits */
+static int __init 
+io_init(void)
+{
+	unsigned char data;
+
+	if (cobt_is_3k()) {
+		/* The GPIO tied to the ID chip is on the PMU */
+		id_dev = pci_find_device(PCI_VENDOR_ID_AL, 
+			PCI_DEVICE_ID_AL_M7101, NULL);
+		if (!id_dev) {
+			EPRINTK("can't find PMU for serialnumber access\n");
+			return -ENXIO;
+		}
+
+		/* Set input mode on GPIO3 */
+		pci_read_config_byte(id_dev, sn_direction, &data);
+		if (debug > 1) {
+			WPRINTK("read of register 0x%x = 0x%x\n",
+				sn_direction, data);
+		}
+		if (data & sn_mask) {
+			pci_write_config_byte(id_dev, sn_direction, 
+				data & ~sn_mask);
+		}
+
+		/* Set the output value to be 0 */
+		pci_read_config_byte(id_dev, sn_output, &data);
+		if (debug > 1) {
+			WPRINTK("read of register 0x%x = 0x%x\n",
+				sn_output, data);
+		}
+		if (data & sn_mask) {
+			pci_write_config_byte(id_dev, sn_output, 
+				data & ~sn_mask);
+		}
+	} else if (cobt_is_5k()) {
+		u16 addr;
+
+		addr = superio_ldev_base(PC87317_DEV_GPIO);
+		if (addr) {
+			u8 val;
+
+			sn_io_base = addr;
+
+			/* set output value to 0 */
+			val = inb(sn_direction);
+			outb(val | sn_mask, sn_direction);
+			data = inb(sn_output);
+			if (data & sn_mask) {
+				outb(data & ~sn_mask, sn_output);
+			}
+			/* set to input */
+			outb(val & ~sn_mask, sn_direction);
+		}
+	} else {
+		return -ENXIO;
+	}
+
+	/* pick proper variables */
+	if (cobt_is_3k()) {
+		sn_direction = III_SN_DIRECTION;
+		sn_output = III_SN_OUTPUT;
+		sn_input = III_SN_INPUT;
+		sn_mask = III_SN_MASK;
+	} else if (cobt_is_5k()) {
+		sn_direction = V_SN_DIRECTION;
+		sn_output = V_SN_OUTPUT;
+		sn_input = V_SN_INPUT;
+		sn_mask = V_SN_MASK;
+	} else {
+		return -1;
+	}
+
+	/* Let things calm down */
+	udelay(500);
+	return 0;
+}
+
+/* write out a bit */
+static void __init
+io_write(int delay)
+{
+	if (cobt_is_3k()) {
+		unsigned char data;
+		/* Set output mode on GPIO3 */
+		pci_read_config_byte(id_dev, sn_direction, &data);
+		pci_write_config_byte(id_dev, sn_direction, data | sn_mask);
+		udelay(delay);
+
+		/* Set input mode */
+		pci_write_config_byte(id_dev, sn_direction, data & ~sn_mask);
+	} else if (cobt_is_5k()) {
+		unsigned char direction;
+
+		/* change to output and back */
+		direction = inb(sn_direction); 
+		outb(direction | sn_mask, sn_direction);
+		udelay(delay);
+		outb(direction & ~sn_mask, sn_direction);
+	}
+}
+
+/* read in a bit */
+static int __init
+io_read(void)
+{
+	unsigned char data = 0;
+
+	/* Get the input value */
+	if (cobt_is_3k()) {
+		pci_read_config_byte(id_dev, sn_input, &data);
+	} else if (cobt_is_5k()) {
+		data = inb(sn_input);
+	}
+
+	return (data & sn_mask) ? 1 : 0;
+}
+
+static void __init
+io_write_byte(unsigned char c)
+{
+	int i;
+	unsigned long flags;
+
+	local_save_flags(flags);
+
+	for (i = 0; i < 8; i++, c >>= 1) {
+		local_irq_disable();
+		if (c & 1) {
+			/* Transmit a 1 */
+			io_write(5);
+			udelay(80);
+		} else {
+			/* Transmit a 0 */
+			io_write(80);
+			udelay(10);
+		}
+		local_irq_restore(flags);
+	}
+}
+
+static int __init
+io_read_byte(void)
+{
+	int i;
+	int c = 0;
+	unsigned long flags;
+
+	local_save_flags(flags);
+
+	for (i = 0; i < 8; i++) {
+		local_irq_disable();
+		io_write(1);	/* Start the read */
+		udelay(2);
+		if (io_read()) {
+			c |= 1 << i;
+		}
+		udelay(60);
+		local_irq_restore(flags);
+	}
+
+	return c;
+}
+
+static int __init
+get_ssn(unsigned char *buf)
+{
+	int i;
+	unsigned long flags;
+
+	/* 
+	 * Alpine does not have a dallas chip.  Instead
+	 * we read from an eprom.
+	 */
+	if (cobt_is_alpine()) {
+		for (i = 0; i < 8; i++) {
+			buf[i] = cobalt_i2c_read_byte(COBALT_I2C_DEV_AT24C02, 
+				12 + i);
+		}
+		return 0;
+	}
+
+	/*
+	 * bit-bang the Dallas 2401
+	 */
+
+	local_save_flags(flags);
+	local_irq_disable();
+
+	/* Master Reset Pulse */
+	for (i = 0; i < 600; i += 30) {
+		if (io_read()) {
+			break;
+		}
+	}
+
+	if (i >= 600) {
+		if (debug) {
+			EPRINTK("the data line seems to be held low\n");
+		}
+		local_irq_restore(flags);
+		return -ENXIO;
+	}
+
+	io_write(600);
+
+	for (i = 0; i < 300; i += 15) {
+		udelay(15);
+		if (io_read() == 0) {
+			/* We got a presence pulse */
+			udelay(600);	/* Wait for things to quiet down */
+			break;
+		}
+	}
+	local_irq_restore(flags);
+
+	if (i >= 300) {
+		if (debug)
+			EPRINTK("no presence pulse detected\n");
+		return -ENXIO;
+	}
+
+	io_write_byte(0x33);
+
+	for (i = 0; i < 8; i++) {
+		int rc;
+
+		rc = io_read_byte();
+		if (rc < 0) {
+			return rc;
+		}
+
+		*buf++ = rc;
+	}
+
+	return 0;
+}
+
+int __init
+cobalt_serialnum_init(void)
+{
+	unsigned char ssn[SSN_SIZE];
+	int rc;
+	int i;
+
+    printk(KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", SN_DRIVER,SN_DRIVER_VMAJ,SN_DRIVER_VMIN);
+	/* set up for proper IO */
+	rc = io_init();
+	if (rc) {
+		return rc;
+	}
+
+	/*
+	 * NOTE: the below algorithm CAN NOT be changed.  We have many systems
+	 * out there registered with the serial number AS DERIVED by this
+	 * algorithm.
+	 */
+
+	rc = get_ssn(ssn);
+	if (rc) {
+		return rc;
+	}
+
+	/* Convert to ssn_string */
+	for (i = 7; i >= 0; i--) {
+		sprintf(ssn_string + (7 - i) * 2, "%02x", ssn[i]);
+	}
+
+	/* get four bytes for a pretty unique (not guaranteed) hostid */
+	hostid = *(unsigned long *)ssn ^ *(unsigned long *)(ssn+4);
+
+#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_COBALT_OLDPROC
+	proc_hostid = create_proc_read_entry("hostid", 0, NULL, 
+		hostid_read, NULL);
+	if (!proc_hostid) {
+		EPRINTK("can't create /proc/hostid\n");
+	}
+	proc_serialnum = create_proc_read_entry("serialnumber", 0, NULL,
+		serialnum_read, NULL);
+	if (!proc_serialnum) {
+		EPRINTK("can't create /proc/serialnumber\n");
+	}
+#endif
+	proc_chostid = create_proc_read_entry("hostid", 0, proc_cobalt, 
+		hostid_read, NULL);
+	if (!proc_chostid) {
+		EPRINTK("can't create /proc/cobalt/hostid\n");
+	}
+	proc_cserialnum = create_proc_read_entry("serialnumber", 0, 
+		proc_cobalt, serialnum_read, NULL);
+	if (!proc_cserialnum) {
+		EPRINTK("can't create /proc/cobalt/serialnumber\n");
+	}
+#endif
+
+	return 0;
+}
+
+char *
+cobalt_serialnum_get(void)
+{
+	return ssn_string;
+}
+
+unsigned long
+cobalt_hostid_get(void)
+{
+	return hostid;
+}
+
+#if defined(CONFIG_COBALT_SERNUM_MODULE)
+MODULE_PARM(debug, "i");
+
+int
+init_module(void)
+{
+	return cobalt_serialnum_init();
+}
+
+void
+cleanup_module(void)
+{
+#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_COBALT_OLDPROC
+	remove_proc_entry("hostid", NULL);
+	remove_proc_entry("serialnumber", NULL);
+#endif
+	remove_proc_entry("hostid", proc_cobalt);
+	remove_proc_entry("serialnumber", proc_cobalt);
+#endif
+}
+
+module_init(init_module);
+module_exit(cleanup_module);
+#endif /* MODULE */
+
+#endif /* CONFIG_COBALT_SERNUM */
diff -Nurb linux-2.6.24.3/drivers/cobalt/systype.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/systype.c
--- linux-2.6.24.3/drivers/cobalt/systype.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/systype.c	2008-03-02 14:55:48.000000000 -0800
@@ -0,0 +1,278 @@
+/*
+ * $Id: systype.c,v 1.33 2002/11/04 17:54:15 thockin Exp $
+ * systype.c : routines for figuring out which Cobalt system this is
+ *
+ * Copyright 2001-2002 Sun Microsystems, Inc.
+ *
+ * By:  Tim Hockin
+ *	Adrian Sun
+ *	Duncan Laurie
+ *
+ * This driver is SMP safe by nature. --TPH
+ */
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/module.h>
+
+#include <cobalt/cobalt.h>
+#include <cobalt/systype.h>
+#include <cobalt/i2c.h>
+
+/* for easy first-pass analysis */
+#if defined(CONFIG_COBALT_GEN_III)
+int COBALT_GENERATION_III_DEFINED;
+#endif
+#if defined(CONFIG_COBALT_GEN_V)
+int COBALT_GENERATION_V_DEFINED;
+#endif
+
+cobt_sys_t cobt_type = COBT_UNINITIALIZED;
+EXPORT_SYMBOL(cobt_type);
+unsigned long cobt_rev;
+EXPORT_SYMBOL(cobt_rev);
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *proc_systype;
+#endif
+static int systype_read_proc(char *buf, char **start, off_t pos, int len,
+	int *eof, void *x);
+static char *systype_str(cobt_sys_t type);
+static unsigned long boardrev_read(void);
+
+void __init
+cobalt_boardrev_init(void)
+{
+	cobt_rev = boardrev_read();
+}
+
+int __init 
+cobalt_systype_init(void)
+{
+	cobalt_systype_probe();
+    
+#ifdef CONFIG_PROC_FS
+	proc_systype = create_proc_read_entry("systype", 0, 
+		proc_cobalt, systype_read_proc, NULL);
+	if (!proc_systype) {
+		EPRINTK("can't create /proc/cobalt/systype\n");
+	}
+#endif
+
+	if (cobt_type == COBT_UNKNOWN) {
+		printk(KERN_INFO "Cobalt system type is unknown, trouble will ensue (I can vouch for this)\n");
+		return -1;
+	} else {
+	    printk(KERN_INFO "Cobalt system type is %s\n",systype_str(cobt_type));
+	    return 0;
+    }
+}
+
+#if defined(CONFIG_COBALT_GEN_III)
+static cobt_sys_t
+systype_probe_3k(void)
+{
+	struct pci_dev *pdev;
+	cobt_sys_t retval = COBT_UNKNOWN;
+
+	/* board identifier for RaQ3/4 vs Qube3 is on the PMU @ 0x7f */
+	pdev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, NULL);
+	if (pdev) {
+		/* 
+		 * check to see what board we are on
+		 * ( RaQ 3, RaQ 4, Qube 3 )
+		 */
+		unsigned char val;
+
+	    /* momentarily set DOGB# to input */
+		pci_read_config_byte(pdev, 0x7d, &val);
+		pci_write_config_byte(pdev, 0x7d, val & ~0x20);
+
+		/* read the GPIO register */
+		pci_read_config_byte(pdev, 0x7f, &val);
+		/* RaQ3/4 boards have DOGB (0x20) high, 
+		 * Qube3 has DOGB low */ 
+		if (val & 0x20) {
+		    retval = COBT_PACIFICA;
+		} else {
+		    retval = COBT_CARMEL;
+		}
+
+		/* change DOGB back to output */
+		pci_read_config_byte(pdev, 0x7d, &val);
+		pci_write_config_byte(pdev, 0x7d, val | 0x20);
+	}
+    
+	/* assign to this, so the compiler shuts up */
+	COBALT_GENERATION_III_DEFINED = 1;
+
+	return retval;
+}
+#else
+#define systype_probe_3k()	(COBT_UNKNOWN)
+#endif
+
+#if defined(CONFIG_COBALT_GEN_V)
+static cobt_sys_t
+systype_probe_5k(void)
+{
+	struct pci_dev *pdev;
+	cobt_sys_t retval = COBT_UNKNOWN;
+
+	/* is it a gen V ? */
+	pdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+		PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+	if (pdev) {
+		retval = COBT_MONTEREY;
+		goto out;
+	}
+
+	pdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+		PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL);
+	if (pdev) {
+		pdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+			PCI_DEVICE_ID_SERVERWORKS_LE, NULL);
+		if (pdev) {
+			retval = COBT_ALPINE;
+			goto out;
+		}
+	}
+
+out:
+	/* assign to this, so the compiler shuts up */
+	COBALT_GENERATION_V_DEFINED = 1;
+
+	return retval;
+}
+#else
+#define systype_probe_5k()	(COBT_UNKNOWN)
+#endif
+
+static cobt_sys_t
+systype_probe_gp(void)
+{
+	struct pci_dev *pdev;
+	cobt_sys_t retval = COBT_UNKNOWN;
+
+	/* is it a GP system? */
+	pdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+		PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL);
+	if (pdev) {
+		pdev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+			PCI_DEVICE_ID_SERVERWORKS_HE, NULL);
+		if (pdev) {
+			retval = COBT_BIGBEAR;
+		}	
+	}
+
+	return retval;
+}
+
+cobt_sys_t
+cobalt_systype_probe(void)
+{
+	static int init_done = 0;
+
+	if (init_done) {
+		return cobt_type;
+	}
+
+	/* check for 3k family systems */
+	
+	cobt_type = systype_probe_3k();
+	if (cobt_type != COBT_UNKNOWN)
+		goto out;
+
+	/* check for 5k family systems */
+	cobt_type = systype_probe_5k();
+	if (cobt_type != COBT_UNKNOWN)
+		goto out;
+
+	/* it's a GP system or unknown */
+	cobt_type = systype_probe_gp();
+
+out:
+	if (cobt_type != COBT_UNKNOWN) {
+		init_done = 1;
+	}
+
+	return cobt_type;
+}
+EXPORT_SYMBOL(cobalt_systype_probe);
+
+#ifdef CONFIG_PROC_FS
+static int 
+systype_read_proc(char *buf, char **start, off_t pos, int len,
+	int *eof, void *x)
+{
+	int plen = sprintf(buf, "%s\n", systype_str(cobt_type));
+	return cobalt_gen_proc_read(buf, plen, start, pos, len, eof);
+}
+#endif
+
+static char *
+systype_str(cobt_sys_t type)
+{
+	switch (type) {
+		case COBT_PACIFICA:
+			return "Pacifica";
+			break;
+		case COBT_CARMEL:
+			return "Carmel";
+			break;
+		case COBT_MONTEREY:
+			return "Monterey";
+			break;
+		case COBT_ALPINE:
+			return "Alpine";
+			break;
+		case COBT_BIGBEAR:
+			return "BigBear";
+			break;
+		case COBT_UNKNOWN:
+		default:
+			return "unknown";
+			break;
+	}
+}
+
+static unsigned long
+boardrev_read(void)
+{
+	unsigned long rev;
+
+	switch (cobt_type) {
+#ifdef CONFIG_COBALT_RAQ
+	case COBT_PACIFICA:
+	case COBT_CARMEL:
+		/* No usable board rev on these systems */
+		return 0;
+	case COBT_MONTEREY:
+		/*
+		 * the boardrev on monterey is strapped off of GPM[3:0]
+		 * and is read from port 0xc52
+		 */
+		return inb(0xc52);
+	case COBT_ALPINE:
+		/*
+		 * the boardrev on alpine in stored in the i2c eeprom
+		 * location 4
+		 */
+		rev = cobalt_i2c_read_byte(COBALT_I2C_DEV_AT24C02, 0x04);
+		rev |= cobalt_i2c_read_byte(COBALT_I2C_DEV_AT24C02, 0x05) << 8;
+		rev |= cobalt_i2c_read_byte(COBALT_I2C_DEV_AT24C02, 0x06) << 16;
+		rev |= cobalt_i2c_read_byte(COBALT_I2C_DEV_AT24C02, 0x07) << 24;
+		if (rev == 0xffffffff)
+			rev = 0;
+		return rev;
+#endif
+	case COBT_BIGBEAR:
+		/* No board revs at this time */
+		return 0;
+	case COBT_UNKNOWN:
+	case COBT_UNINITIALIZED:
+		return 0;
+	}
+	return 0;
+}
diff -Nurb linux-2.6.24.3/drivers/cobalt/wdt.c linux-2.6.24.3-cobalt3-tw/drivers/cobalt/wdt.c
--- linux-2.6.24.3/drivers/cobalt/wdt.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/cobalt/wdt.c	2008-03-02 14:55:48.000000000 -0800
@@ -0,0 +1,421 @@
+/* $Id: wdt.c,v 1.21 2002/07/02 00:38:17 asun Exp $ */
+/* 
+ * Cobalt kernel WDT timer driver
+ * Tim Hockin <thockin@cobaltnet.com>
+ * Adrian Sun <asun@cobalt.com>
+ * Chris Johnson <cjohnson@cobalt.com>
+ * Copyright (c)1999-2000, Cobalt Networks
+ * Copyright (c)2001, Sun Microsystems
+ *
+ * This should be SMP safe.  Every external function (except trigger_reboot)
+ * grabs the wdt lock.  No function in this file may call any exported
+ * function (excepting trigger_reboot).  The disable counter is an atomic, so
+ * there should be no issues there. --TPH
+ */
+#include <linux/module.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/msr.h>
+
+#include <cobalt/cobalt.h>
+#include <cobalt/systype.h>
+#include <cobalt/wdt.h>
+#include <cobalt/superio.h>
+
+#define DOGB			0x20
+#define ALI_7101_WDT		0x92
+#define ALI_WDT_ARM		0x01
+#define WDT_3K_TIMEOUT 		(HZ >> 4)	/* 1/16 second */
+
+#define WDT_SUPERIO_TIMEOUT	(0x01)		/* 1 minute */
+#define WDT_5K_TIMEOUT 		(HZ << 3)	/* 8 seconds */
+
+#define WDT_DRIVER			"Cobalt Networks Watchdog Timer driver"
+#define WDT_DRIVER_VMAJ		1
+#define WDT_DRIVER_VMIN		0
+
+static unsigned long wdt_timeout;
+static unsigned long long tsc_per_wdt;
+static int initialized;
+
+#ifdef CONFIG_COBALT_WDT
+struct timer_list cobalt_wdt_timer;
+static atomic_t cobalt_wdt_disable_count = ATOMIC_INIT(0);
+static spinlock_t wdt_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
+/* gen III */
+static struct pci_dev *cobalt_pmu;
+static int use_pic;
+/* gen V */
+static u16 superio_pm_port;
+
+#ifdef CONFIG_COBALT_WDT
+static void do_refresh(void);
+static void do_cleardog(void);
+static void do_disable(void);
+static void do_reenable(void);
+#endif
+	
+static unsigned long __init 
+chipset_setup(void)
+{
+	unsigned char tmp;
+	if (cobt_is_3k()) {
+		/* 
+		 * Set up the PMU for 3k boards. It has a max
+		 * of a 1 second timeout. 
+		 */
+		struct pci_dev *south;
+
+		/* PMU (1543 ver A1-E) has a built-in WDT.  Set it to 1 sec */
+		cobalt_pmu = pci_find_device(PCI_VENDOR_ID_AL, 
+			PCI_DEVICE_ID_AL_M7101, NULL);
+		if (!cobalt_pmu) {
+			EPRINTK("can't find south bridge for WDT\n");
+			return 0;
+		}
+		pci_write_config_byte(cobalt_pmu, ALI_7101_WDT, 0x02);
+	
+		/* why it is called 1543, but DevId is 1533 I'll never know */
+		south = pci_find_device(PCI_VENDOR_ID_AL, 
+			PCI_DEVICE_ID_AL_M1533, NULL);
+		if (!south) {
+			EPRINTK("can't find south bridge for WDT\n");
+			use_pic = 1;
+		} else {
+			/* reversion # is here - must match ???1001?(b)
+			 * else use PIC for WDT */
+			pci_read_config_byte(south, 0x5e, &tmp);
+			use_pic = ((tmp & 0x1e) != 0x12);
+		}
+
+		if (!use_pic) {
+			/* set DOGB GPIO pin to OUTPUT - JIC */
+			pci_read_config_byte(cobalt_pmu, 0x7d, &tmp);
+			pci_write_config_byte(cobalt_pmu, 0x7d, tmp | DOGB);
+		}
+		return WDT_3K_TIMEOUT;
+	} else if (cobt_is_monterey()) {
+		/* 
+		 * Set up the Nat. Semi SuperI/O for XTR. It has a 
+		 * minimum of a 1 minute timeout. 
+		 */
+	
+		/* superi/o -- select pm logical device and get base address */
+		superio_pm_port = superio_ldev_base(PC87317_DEV_PM);
+#ifdef CONFIG_COBALT_WDT
+		if (!superio_pm_port) {
+			return 0;
+		}
+		outb(PC87317_PMDEV_WDTO, superio_pm_port);
+		outb(WDT_SUPERIO_TIMEOUT, superio_pm_port + 1); 
+#endif
+		return WDT_5K_TIMEOUT;
+	} else if (cobt_is_alpine()) {
+		/* 
+		 * Set up the Nat. Semi SuperI/O for Alpine. It has a 
+		 * minimum of a 1 minute timeout. 
+		 */
+	
+		/* superi/o -- select pm logical device and get base address */
+		superio_pm_port = superio_ldev_base(PC87417_DEV_SWC);
+#ifdef CONFIG_COBALT_WDT
+		if (!superio_pm_port) {
+			return 0;
+		}
+		/* select the WDT bank of SWC */
+		outb(PC87417_SWCBANK_WDT, superio_pm_port+PC87417_SWC_BANK);
+		/* clear event config... */
+		tmp = inb(superio_pm_port+PC87417_WDT_CONFIG);
+		outb(0, superio_pm_port+PC87417_WDT_CONFIG);
+		/* ...before mucking with timeout */
+		outb(WDT_SUPERIO_TIMEOUT, 
+			superio_pm_port+PC87417_WDT_TIMEOUT); 
+		/* restore the event config */
+		outb(tmp, superio_pm_port+PC87417_WDT_CONFIG);
+		/* enable the counter */
+		outb(1, superio_pm_port+PC87417_WDT_CONTROL);
+#endif
+		return WDT_5K_TIMEOUT;
+	}
+
+	return 0;
+}
+
+void __init 
+cobalt_wdt_init(void)
+{
+	unsigned long long start, stop;
+
+    printk(KERN_INFO "%s %d.%d (modified by jeff@404ster.com)\n", WDT_DRIVER,WDT_DRIVER_VMAJ,WDT_DRIVER_VMIN);
+    
+	wdt_timeout = chipset_setup();
+
+	/* figure out time */
+	rdtscll(start);
+	udelay(100);
+	rdtscll(stop);
+
+	/*
+	 * (int) (stop - start) * 10 == tsc per msec
+	 * 1000 / HZ == msec per tick
+	 * wdt_timeout == ticks per watchdog rearm
+	 */
+	tsc_per_wdt = (int) (stop - start) * 10 * (1000 * wdt_timeout / HZ);
+
+#ifdef CONFIG_COBALT_WDT
+	/* set the timer going */
+	init_timer(&cobalt_wdt_timer);
+	cobalt_wdt_timer.function = cobalt_wdt_refresh;
+	cobalt_wdt_timer.data = 1;
+	cobalt_wdt_timer.expires = jiffies + wdt_timeout;
+	add_timer(&cobalt_wdt_timer);
+
+	/* the first timer tick will set it going */
+
+	if (cobt_is_3k() && use_pic) {
+		WPRINTK("Cobalt WDT - old board, using PIC controller\n");
+	}
+#endif /* CONFIG_COBALT_WDT */
+
+	initialized = 1;
+}
+
+static inline void
+hw_disable(void)
+{
+	if (cobt_is_3k()) {
+		char tmp;
+		/* read the value, disable (reset) WDT */
+		pci_read_config_byte(cobalt_pmu, ALI_7101_WDT, &tmp);
+		pci_write_config_byte(cobalt_pmu, ALI_7101_WDT, 
+			(tmp & ~ALI_WDT_ARM));
+	} else if (cobt_is_monterey()) {
+		outb(PC87317_PMDEV_WDTO, superio_pm_port);
+		outb(0, superio_pm_port + 1);
+	} else if (cobt_is_alpine()) {
+		unsigned char tmp;
+		/* select the WDT bank of SWC */
+		outb(PC87417_SWCBANK_WDT, superio_pm_port + PC87417_SWC_BANK);
+		/* clear event config before mucking with timeout */
+		tmp = inb(superio_pm_port + PC87417_WDT_CONFIG);
+		outb(0, superio_pm_port + PC87417_WDT_CONFIG);
+		/* 
+		 * Disable it by setting a 0 time-out.
+		 * The spec says 00h is reserved, but NSC confirms this is the
+		 * way to disable the device.
+		 */
+		outb(0, superio_pm_port + PC87417_WDT_TIMEOUT);
+		/* restore the event config */
+		outb(tmp, superio_pm_port + PC87417_WDT_CONFIG);
+	}
+}
+
+static inline void
+hw_enable(void)
+{
+	if (cobt_is_3k()) {
+		unsigned char tmp;
+		/* read the value, disable (reset) WDT, enable WDT */
+		pci_read_config_byte(cobalt_pmu, ALI_7101_WDT, &tmp);
+		pci_write_config_byte(cobalt_pmu, ALI_7101_WDT, 
+			(tmp | ALI_WDT_ARM));
+		if (use_pic) {
+			/* transition GPIO 5 (DOGB) to arm/clear timer */
+			pci_read_config_byte(cobalt_pmu, 0x7e, &tmp);
+			pci_write_config_byte(cobalt_pmu, 0x7e, tmp ^ DOGB);
+		}
+	} else if (cobt_is_monterey()) {
+		outb(PC87317_PMDEV_WDTO, superio_pm_port);
+		outb(WDT_SUPERIO_TIMEOUT, superio_pm_port + 1);
+	} else if (cobt_is_alpine()) {
+		unsigned char tmp;
+		/* select the WDT bank of SWC */
+		outb(PC87417_SWCBANK_WDT, superio_pm_port + PC87417_SWC_BANK);
+		/* clear event config before mucking with timeout */
+		tmp = inb(superio_pm_port + PC87417_WDT_CONFIG);
+		outb(0, superio_pm_port + PC87417_WDT_CONFIG);
+		/* enable and refresh the timer */
+		outb(WDT_SUPERIO_TIMEOUT, 
+			superio_pm_port + PC87417_WDT_TIMEOUT);
+		outb(0x80, superio_pm_port + PC87417_WDT_CONTROL);
+		/* restore event config */
+		outb(tmp, superio_pm_port + PC87417_WDT_CONFIG);
+	}
+}
+
+#ifdef CONFIG_COBALT_WDT
+static void
+do_refresh(void)
+{
+	if (!initialized) {
+		return;
+	}
+
+	do_cleardog();
+	
+	/* re-arm the timer - this is locked in mod_timer() */
+	mod_timer(&cobalt_wdt_timer, jiffies + wdt_timeout);
+}
+#endif
+
+EXPORT_SYMBOL(cobalt_wdt_refresh);
+void 
+cobalt_wdt_refresh(unsigned long refresh_timer)
+{
+#ifdef CONFIG_COBALT_WDT
+	unsigned long flags;
+	spin_lock_irqsave(&wdt_lock, flags);
+	do_refresh();
+	spin_unlock_irqrestore(&wdt_lock, flags);
+#endif
+}
+
+#ifdef CONFIG_COBALT_WDT
+static void
+do_cleardog(void)
+{
+	static unsigned long long last_tsc = 0;
+	unsigned long long tmp;
+
+	if (!initialized || (atomic_read(&cobalt_wdt_disable_count) > 0)) {
+		return;
+	}
+
+	/* only bother if we're due */
+	rdtscll(tmp);
+	if ((int)(tmp - last_tsc) < tsc_per_wdt) {
+		return;
+	}
+
+	if (cobt_is_3k() || cobt_is_monterey()) {
+		/* this is how we re-start the clock */
+		hw_disable();
+		hw_enable();
+	} else if (cobt_is_alpine()) {
+		/* select the WDT bank of SWC */
+		outb(PC87417_SWCBANK_WDT, superio_pm_port + PC87417_SWC_BANK);
+		/* refresh the timer */
+		outb(0x80, superio_pm_port + PC87417_WDT_CONTROL);
+	}
+
+	rdtscll(last_tsc);
+}
+#endif
+
+EXPORT_SYMBOL(cobalt_wdt_cleardog);
+void 
+cobalt_wdt_cleardog(void)
+{
+#ifdef CONFIG_COBALT_WDT
+	unsigned long flags;
+
+	spin_lock_irqsave(&wdt_lock, flags);
+	do_cleardog();
+	spin_unlock_irqrestore(&wdt_lock, flags);
+#endif
+}
+
+/* 
+ * this is called from machine_restart. it should not be used on
+ * 5k machines. 
+ */
+EXPORT_SYMBOL(cobalt_wdt_trigger_reboot);
+void 
+cobalt_wdt_trigger_reboot(void)
+{
+	if (cobt_is_3k()) {
+		if (!cobalt_pmu) {
+			WPRINTK("no PMU found!\n");
+			WPRINTK("reboot not possible!\n");
+			return;
+		}
+
+#ifdef CONFIG_COBALT_WDT
+		/* stop feeding it */
+		del_timer_sync(&cobalt_wdt_timer);
+#endif
+
+		/* kiss your rear goodbye... */
+		initialized = 0;
+		hw_disable();
+		hw_enable();
+	}
+}
+
+#ifdef CONFIG_COBALT_WDT
+static void
+do_disable(void)
+{
+	if (!initialized) {
+		return;
+	}
+
+	if (atomic_read(&cobalt_wdt_disable_count) == 0) {
+		atomic_inc(&cobalt_wdt_disable_count);
+		del_timer_sync(&cobalt_wdt_timer);
+		hw_disable();
+	}
+}
+#endif
+
+EXPORT_SYMBOL(cobalt_wdt_disable);
+void 
+cobalt_wdt_disable(void)
+{
+#ifdef CONFIG_COBALT_WDT
+	unsigned long flags;
+
+	if (cobt_is_3k() && use_pic) {
+		WPRINTK("in PIC mode - cannot disable\n");
+		return;
+	}
+
+	spin_lock_irqsave(&wdt_lock, flags);
+	do_disable();
+	spin_unlock_irqrestore(&wdt_lock, flags);
+#endif
+}
+
+#ifdef CONFIG_COBALT_WDT
+static void
+do_reenable(void)
+{
+	int dcnt;
+
+	if (!initialized) { 
+		return;
+	}
+
+	atomic_dec(&cobalt_wdt_disable_count);
+	dcnt = atomic_read(&cobalt_wdt_disable_count);
+
+	if (dcnt == 0) {
+		do_refresh();
+	} else if (dcnt < 0) {
+		WPRINTK("too many enables\n");
+		atomic_set(&cobalt_wdt_disable_count, 0);
+	}
+}
+#endif
+
+
+EXPORT_SYMBOL(cobalt_wdt_reenable);
+void 
+cobalt_wdt_reenable(void)
+{
+#ifdef CONFIG_COBALT_WDT
+	unsigned long flags;
+
+	spin_lock_irqsave(&wdt_lock, flags);
+	do_reenable();
+	spin_unlock_irqrestore(&wdt_lock, flags);
+#endif
+}
diff -Nurb linux-2.6.24.3/drivers/Kconfig linux-2.6.24.3-cobalt3-tw/drivers/Kconfig
--- linux-2.6.24.3/drivers/Kconfig	2008-02-25 16:20:20.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/Kconfig	2008-03-02 14:55:48.000000000 -0800
@@ -90,6 +90,8 @@
 
 source "drivers/auxdisplay/Kconfig"
 
+source "drivers/cobalt/Kconfig"
+
 source "drivers/kvm/Kconfig"
 
 source "drivers/uio/Kconfig"
diff -Nurb linux-2.6.24.3/drivers/Kconfig.orig linux-2.6.24.3-cobalt3-tw/drivers/Kconfig.orig
--- linux-2.6.24.3/drivers/Kconfig.orig	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/Kconfig.orig	2008-02-25 16:20:20.000000000 -0800
@@ -0,0 +1,98 @@
+# drivers/Kconfig
+
+menu "Device Drivers"
+
+source "drivers/base/Kconfig"
+
+source "drivers/connector/Kconfig"
+
+source "drivers/mtd/Kconfig"
+
+source "drivers/of/Kconfig"
+
+source "drivers/parport/Kconfig"
+
+source "drivers/pnp/Kconfig"
+
+source "drivers/block/Kconfig"
+
+# misc before ide - BLK_DEV_SGIIOC4 depends on SGI_IOC4
+
+source "drivers/misc/Kconfig"
+
+source "drivers/ide/Kconfig"
+
+source "drivers/scsi/Kconfig"
+
+source "drivers/ata/Kconfig"
+
+source "drivers/md/Kconfig"
+
+source "drivers/message/fusion/Kconfig"
+
+source "drivers/ieee1394/Kconfig"
+
+source "drivers/message/i2o/Kconfig"
+
+source "drivers/macintosh/Kconfig"
+
+source "drivers/net/Kconfig"
+
+source "drivers/isdn/Kconfig"
+
+source "drivers/telephony/Kconfig"
+
+# input before char - char/joystick depends on it. As does USB.
+
+source "drivers/input/Kconfig"
+
+source "drivers/char/Kconfig"
+
+source "drivers/i2c/Kconfig"
+
+source "drivers/spi/Kconfig"
+
+source "drivers/w1/Kconfig"
+
+source "drivers/power/Kconfig"
+
+source "drivers/hwmon/Kconfig"
+
+source "drivers/watchdog/Kconfig"
+
+source "drivers/ssb/Kconfig"
+
+source "drivers/mfd/Kconfig"
+
+source "drivers/media/Kconfig"
+
+source "drivers/video/Kconfig"
+
+source "sound/Kconfig"
+
+source "drivers/hid/Kconfig"
+
+source "drivers/usb/Kconfig"
+
+source "drivers/mmc/Kconfig"
+
+source "drivers/leds/Kconfig"
+
+source "drivers/infiniband/Kconfig"
+
+source "drivers/edac/Kconfig"
+
+source "drivers/rtc/Kconfig"
+
+source "drivers/dma/Kconfig"
+
+source "drivers/dca/Kconfig"
+
+source "drivers/auxdisplay/Kconfig"
+
+source "drivers/kvm/Kconfig"
+
+source "drivers/uio/Kconfig"
+
+source "drivers/virtio/Kconfig"
+endmenu
diff -Nurb linux-2.6.24.3/drivers/Makefile linux-2.6.24.3-cobalt3-tw/drivers/Makefile
--- linux-2.6.24.3/drivers/Makefile	2008-02-25 16:20:20.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/Makefile	2008-03-02 14:55:48.000000000 -0800
@@ -68,6 +68,8 @@
 obj-$(CONFIG_WATCHDOG)		+= watchdog/
 obj-$(CONFIG_PHONE)		+= telephony/
 obj-$(CONFIG_MD)		+= md/
+obj-$(CONFIG_COBALT_RAQ)	+= cobalt/
+
 obj-$(CONFIG_BT)		+= bluetooth/
 obj-$(CONFIG_ISDN)		+= isdn/
 obj-$(CONFIG_EDAC)		+= edac/
diff -Nurb linux-2.6.24.3/drivers/Makefile.orig linux-2.6.24.3-cobalt3-tw/drivers/Makefile.orig
--- linux-2.6.24.3/drivers/Makefile.orig	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/Makefile.orig	2008-02-25 16:20:20.000000000 -0800
@@ -0,0 +1,93 @@
+#
+# Makefile for the Linux kernel device drivers.
+#
+# 15 Sep 2000, Christoph Hellwig <hch@infradead.org>
+# Rewritten to use lists instead of if-statements.
+#
+
+obj-$(CONFIG_PCI)		+= pci/
+obj-$(CONFIG_PARISC)		+= parisc/
+obj-$(CONFIG_RAPIDIO)		+= rapidio/
+obj-y				+= video/
+obj-$(CONFIG_ACPI)		+= acpi/
+# PnP must come after ACPI since it will eventually need to check if acpi
+# was used and do nothing if so
+obj-$(CONFIG_PNP)		+= pnp/
+obj-$(CONFIG_ARM_AMBA)		+= amba/
+
+obj-$(CONFIG_XEN)		+= xen/
+
+# char/ comes before serial/ etc so that the VT console is the boot-time
+# default.
+obj-y				+= char/
+
+obj-$(CONFIG_CONNECTOR)		+= connector/
+
+# i810fb and intelfb depend on char/agp/
+obj-$(CONFIG_FB_I810)           += video/i810/
+obj-$(CONFIG_FB_INTEL)          += video/intelfb/
+
+obj-y				+= serial/
+obj-$(CONFIG_PARPORT)		+= parport/
+obj-y				+= base/ block/ misc/ mfd/ net/ media/
+obj-$(CONFIG_NUBUS)		+= nubus/
+obj-$(CONFIG_ATM)		+= atm/
+obj-y				+= macintosh/
+obj-$(CONFIG_IDE)		+= ide/
+obj-$(CONFIG_SCSI)		+= scsi/
+obj-$(CONFIG_ATA)		+= ata/
+obj-$(CONFIG_FUSION)		+= message/
+obj-$(CONFIG_FIREWIRE)		+= firewire/
+obj-$(CONFIG_IEEE1394)		+= ieee1394/
+obj-$(CONFIG_UIO)		+= uio/
+obj-y				+= cdrom/
+obj-y				+= auxdisplay/
+obj-$(CONFIG_MTD)		+= mtd/
+obj-$(CONFIG_SPI)		+= spi/
+obj-$(CONFIG_PCCARD)		+= pcmcia/
+obj-$(CONFIG_DIO)		+= dio/
+obj-$(CONFIG_SBUS)		+= sbus/
+obj-$(CONFIG_KVM)		+= kvm/
+obj-$(CONFIG_ZORRO)		+= zorro/
+obj-$(CONFIG_MAC)		+= macintosh/
+obj-$(CONFIG_ATA_OVER_ETH)	+= block/aoe/
+obj-$(CONFIG_PARIDE) 		+= block/paride/
+obj-$(CONFIG_TC)		+= tc/
+obj-$(CONFIG_USB)		+= usb/
+obj-$(CONFIG_PCI)		+= usb/
+obj-$(CONFIG_USB_GADGET)	+= usb/gadget/
+obj-$(CONFIG_SERIO)		+= input/serio/
+obj-$(CONFIG_GAMEPORT)		+= input/gameport/
+obj-$(CONFIG_INPUT)		+= input/
+obj-$(CONFIG_I2O)		+= message/
+obj-$(CONFIG_RTC_LIB)		+= rtc/
+obj-y				+= i2c/
+obj-$(CONFIG_W1)		+= w1/
+obj-$(CONFIG_POWER_SUPPLY)	+= power/
+obj-$(CONFIG_HWMON)		+= hwmon/
+obj-$(CONFIG_WATCHDOG)		+= watchdog/
+obj-$(CONFIG_PHONE)		+= telephony/
+obj-$(CONFIG_MD)		+= md/
+obj-$(CONFIG_BT)		+= bluetooth/
+obj-$(CONFIG_ISDN)		+= isdn/
+obj-$(CONFIG_EDAC)		+= edac/
+obj-$(CONFIG_MCA)		+= mca/
+obj-$(CONFIG_EISA)		+= eisa/
+obj-$(CONFIG_LGUEST_GUEST)	+= lguest/
+obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
+obj-$(CONFIG_CPU_IDLE)		+= cpuidle/
+obj-$(CONFIG_MMC)		+= mmc/
+obj-$(CONFIG_NEW_LEDS)		+= leds/
+obj-$(CONFIG_INFINIBAND)	+= infiniband/
+obj-$(CONFIG_SGI_SN)		+= sn/
+obj-y				+= firmware/
+obj-$(CONFIG_CRYPTO)		+= crypto/
+obj-$(CONFIG_SUPERH)		+= sh/
+obj-$(CONFIG_GENERIC_TIME)	+= clocksource/
+obj-$(CONFIG_DMA_ENGINE)	+= dma/
+obj-$(CONFIG_DCA)		+= dca/
+obj-$(CONFIG_HID)		+= hid/
+obj-$(CONFIG_PPC_PS3)		+= ps3/
+obj-$(CONFIG_OF)		+= of/
+obj-$(CONFIG_SSB)		+= ssb/
+obj-$(CONFIG_VIRTIO)		+= virtio/
diff -Nurb linux-2.6.24.3/drivers/net/e100.c linux-2.6.24.3-cobalt3-tw/drivers/net/e100.c
--- linux-2.6.24.3/drivers/net/e100.c	2008-02-25 16:20:20.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/net/e100.c	2008-03-02 14:55:48.000000000 -0800
@@ -163,6 +163,7 @@
 #define DRV_DESCRIPTION		"Intel(R) PRO/100 Network Driver"
 #define DRV_COPYRIGHT		"Copyright(c) 1999-2006 Intel Corporation"
 #define PFX			DRV_NAME ": "
+#define DRV_MODIFIED		"Modified by <jeff@404ster.com> to ignore bad EEPROM checksums"
 
 #define E100_WATCHDOG_PERIOD	(2 * HZ)
 #define E100_NAPI_WEIGHT	16
@@ -760,9 +761,15 @@
 	 * the sum of words should be 0xBABA */
 	checksum = le16_to_cpu(0xBABA - checksum);
 	if(checksum != nic->eeprom[nic->eeprom_wc - 1]) {
+#if defined(CONFIG_E100_IGNORE_CSUM)
+		DPRINTK(PROBE, ERR, "EEPROM corrupted, ignoring and moving on\n");
+		DPRINTK(PROBE, ERR, "    Caclulated Checksum: %X\n",checksum);
+		DPRINTK(PROBE, ERR, "    EEPROM Checksum:     %X\n",nic->eeprom[nic->eeprom_wc - 1]);
+#else
 		DPRINTK(PROBE, ERR, "EEPROM corrupted\n");
 		if (!eeprom_bad_csum_allow)
 			return -EAGAIN;
+#endif
 	}
 
 	return 0;
@@ -2882,6 +2889,9 @@
 	if(((1 << debug) - 1) & NETIF_MSG_DRV) {
 		printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
 		printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT);
+#if defined(CONFIG_E100_IGNORE_CSUM)
+		printk(KERN_INFO PFX "%s\n", DRV_MODIFIED);
+#endif
 	}
 	return pci_register_driver(&e100_driver);
 }
diff -Nurb linux-2.6.24.3/drivers/net/e100.c.orig linux-2.6.24.3-cobalt3-tw/drivers/net/e100.c.orig
--- linux-2.6.24.3/drivers/net/e100.c.orig	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/net/e100.c.orig	2008-02-25 16:20:20.000000000 -0800
@@ -0,0 +1,2895 @@
+/*******************************************************************************
+
+  Intel PRO/100 Linux driver
+  Copyright(c) 1999 - 2006 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/*
+ *	e100.c: Intel(R) PRO/100 ethernet driver
+ *
+ *	(Re)written 2003 by scott.feldman@intel.com.  Based loosely on
+ *	original e100 driver, but better described as a munging of
+ *	e100, e1000, eepro100, tg3, 8139cp, and other drivers.
+ *
+ *	References:
+ *		Intel 8255x 10/100 Mbps Ethernet Controller Family,
+ *		Open Source Software Developers Manual,
+ *		http://sourceforge.net/projects/e1000
+ *
+ *
+ *	                      Theory of Operation
+ *
+ *	I.   General
+ *
+ *	The driver supports Intel(R) 10/100 Mbps PCI Fast Ethernet
+ *	controller family, which includes the 82557, 82558, 82559, 82550,
+ *	82551, and 82562 devices.  82558 and greater controllers
+ *	integrate the Intel 82555 PHY.  The controllers are used in
+ *	server and client network interface cards, as well as in
+ *	LAN-On-Motherboard (LOM), CardBus, MiniPCI, and ICHx
+ *	configurations.  8255x supports a 32-bit linear addressing
+ *	mode and operates at 33Mhz PCI clock rate.
+ *
+ *	II.  Driver Operation
+ *
+ *	Memory-mapped mode is used exclusively to access the device's
+ *	shared-memory structure, the Control/Status Registers (CSR). All
+ *	setup, configuration, and control of the device, including queuing
+ *	of Tx, Rx, and configuration commands is through the CSR.
+ *	cmd_lock serializes accesses to the CSR command register.  cb_lock
+ *	protects the shared Command Block List (CBL).
+ *
+ *	8255x is highly MII-compliant and all access to the PHY go
+ *	through the Management Data Interface (MDI).  Consequently, the
+ *	driver leverages the mii.c library shared with other MII-compliant
+ *	devices.
+ *
+ *	Big- and Little-Endian byte order as well as 32- and 64-bit
+ *	archs are supported.  Weak-ordered memory and non-cache-coherent
+ *	archs are supported.
+ *
+ *	III. Transmit
+ *
+ *	A Tx skb is mapped and hangs off of a TCB.  TCBs are linked
+ *	together in a fixed-size ring (CBL) thus forming the flexible mode
+ *	memory structure.  A TCB marked with the suspend-bit indicates
+ *	the end of the ring.  The last TCB processed suspends the
+ *	controller, and the controller can be restarted by issue a CU
+ *	resume command to continue from the suspend point, or a CU start
+ *	command to start at a given position in the ring.
+ *
+ *	Non-Tx commands (config, multicast setup, etc) are linked
+ *	into the CBL ring along with Tx commands.  The common structure
+ *	used for both Tx and non-Tx commands is the Command Block (CB).
+ *
+ *	cb_to_use is the next CB to use for queuing a command; cb_to_clean
+ *	is the next CB to check for completion; cb_to_send is the first
+ *	CB to start on in case of a previous failure to resume.  CB clean
+ *	up happens in interrupt context in response to a CU interrupt.
+ *	cbs_avail keeps track of number of free CB resources available.
+ *
+ * 	Hardware padding of short packets to minimum packet size is
+ * 	enabled.  82557 pads with 7Eh, while the later controllers pad
+ * 	with 00h.
+ *
+ *	IV.  Recieve
+ *
+ *	The Receive Frame Area (RFA) comprises a ring of Receive Frame
+ *	Descriptors (RFD) + data buffer, thus forming the simplified mode
+ *	memory structure.  Rx skbs are allocated to contain both the RFD
+ *	and the data buffer, but the RFD is pulled off before the skb is
+ *	indicated.  The data buffer is aligned such that encapsulated
+ *	protocol headers are u32-aligned.  Since the RFD is part of the
+ *	mapped shared memory, and completion status is contained within
+ *	the RFD, the RFD must be dma_sync'ed to maintain a consistent
+ *	view from software and hardware.
+ *
+ *	Under typical operation, the  receive unit (RU) is start once,
+ *	and the controller happily fills RFDs as frames arrive.  If
+ *	replacement RFDs cannot be allocated, or the RU goes non-active,
+ *	the RU must be restarted.  Frame arrival generates an interrupt,
+ *	and Rx indication and re-allocation happen in the same context,
+ *	therefore no locking is required.  A software-generated interrupt
+ *	is generated from the watchdog to recover from a failed allocation
+ *	senario where all Rx resources have been indicated and none re-
+ *	placed.
+ *
+ *	V.   Miscellaneous
+ *
+ * 	VLAN offloading of tagging, stripping and filtering is not
+ * 	supported, but driver will accommodate the extra 4-byte VLAN tag
+ * 	for processing by upper layers.  Tx/Rx Checksum offloading is not
+ * 	supported.  Tx Scatter/Gather is not supported.  Jumbo Frames is
+ * 	not supported (hardware limitation).
+ *
+ * 	MagicPacket(tm) WoL support is enabled/disabled via ethtool.
+ *
+ * 	Thanks to JC (jchapman@katalix.com) for helping with
+ * 	testing/troubleshooting the development driver.
+ *
+ * 	TODO:
+ * 	o several entry points race with dev->close
+ * 	o check for tx-no-resources/stop Q races with tx clean/wake Q
+ *
+ *	FIXES:
+ * 2005/12/02 - Michael O'Donnell <Michael.ODonnell at stratus dot com>
+ *	- Stratus87247: protect MDI control register manipulations
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/string.h>
+#include <asm/unaligned.h>
+
+
+#define DRV_NAME		"e100"
+#define DRV_EXT			"-NAPI"
+#define DRV_VERSION		"3.5.23-k4"DRV_EXT
+#define DRV_DESCRIPTION		"Intel(R) PRO/100 Network Driver"
+#define DRV_COPYRIGHT		"Copyright(c) 1999-2006 Intel Corporation"
+#define PFX			DRV_NAME ": "
+
+#define E100_WATCHDOG_PERIOD	(2 * HZ)
+#define E100_NAPI_WEIGHT	16
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+static int debug = 3;
+static int eeprom_bad_csum_allow = 0;
+static int use_io = 0;
+module_param(debug, int, 0);
+module_param(eeprom_bad_csum_allow, int, 0);
+module_param(use_io, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+MODULE_PARM_DESC(eeprom_bad_csum_allow, "Allow bad eeprom checksums");
+MODULE_PARM_DESC(use_io, "Force use of i/o access mode");
+#define DPRINTK(nlevel, klevel, fmt, args...) \
+	(void)((NETIF_MSG_##nlevel & nic->msg_enable) && \
+	printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \
+		__FUNCTION__ , ## args))
+
+#define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\
+	PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \
+	PCI_CLASS_NETWORK_ETHERNET << 8, 0xFFFF00, ich }
+static struct pci_device_id e100_id_table[] = {
+	INTEL_8255X_ETHERNET_DEVICE(0x1029, 0),
+	INTEL_8255X_ETHERNET_DEVICE(0x1030, 0),
+	INTEL_8255X_ETHERNET_DEVICE(0x1031, 3),
+	INTEL_8255X_ETHERNET_DEVICE(0x1032, 3),
+	INTEL_8255X_ETHERNET_DEVICE(0x1033, 3),
+	INTEL_8255X_ETHERNET_DEVICE(0x1034, 3),
+	INTEL_8255X_ETHERNET_DEVICE(0x1038, 3),
+	INTEL_8255X_ETHERNET_DEVICE(0x1039, 4),
+	INTEL_8255X_ETHERNET_DEVICE(0x103A, 4),
+	INTEL_8255X_ETHERNET_DEVICE(0x103B, 4),
+	INTEL_8255X_ETHERNET_DEVICE(0x103C, 4),
+	INTEL_8255X_ETHERNET_DEVICE(0x103D, 4),
+	INTEL_8255X_ETHERNET_DEVICE(0x103E, 4),
+	INTEL_8255X_ETHERNET_DEVICE(0x1050, 5),
+	INTEL_8255X_ETHERNET_DEVICE(0x1051, 5),
+	INTEL_8255X_ETHERNET_DEVICE(0x1052, 5),
+	INTEL_8255X_ETHERNET_DEVICE(0x1053, 5),
+	INTEL_8255X_ETHERNET_DEVICE(0x1054, 5),
+	INTEL_8255X_ETHERNET_DEVICE(0x1055, 5),
+	INTEL_8255X_ETHERNET_DEVICE(0x1056, 5),
+	INTEL_8255X_ETHERNET_DEVICE(0x1057, 5),
+	INTEL_8255X_ETHERNET_DEVICE(0x1059, 0),
+	INTEL_8255X_ETHERNET_DEVICE(0x1064, 6),
+	INTEL_8255X_ETHERNET_DEVICE(0x1065, 6),
+	INTEL_8255X_ETHERNET_DEVICE(0x1066, 6),
+	INTEL_8255X_ETHERNET_DEVICE(0x1067, 6),
+	INTEL_8255X_ETHERNET_DEVICE(0x1068, 6),
+	INTEL_8255X_ETHERNET_DEVICE(0x1069, 6),
+	INTEL_8255X_ETHERNET_DEVICE(0x106A, 6),
+	INTEL_8255X_ETHERNET_DEVICE(0x106B, 6),
+	INTEL_8255X_ETHERNET_DEVICE(0x1091, 7),
+	INTEL_8255X_ETHERNET_DEVICE(0x1092, 7),
+	INTEL_8255X_ETHERNET_DEVICE(0x1093, 7),
+	INTEL_8255X_ETHERNET_DEVICE(0x1094, 7),
+	INTEL_8255X_ETHERNET_DEVICE(0x1095, 7),
+	INTEL_8255X_ETHERNET_DEVICE(0x1209, 0),
+	INTEL_8255X_ETHERNET_DEVICE(0x1229, 0),
+	INTEL_8255X_ETHERNET_DEVICE(0x2449, 2),
+	INTEL_8255X_ETHERNET_DEVICE(0x2459, 2),
+	INTEL_8255X_ETHERNET_DEVICE(0x245D, 2),
+	INTEL_8255X_ETHERNET_DEVICE(0x27DC, 7),
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, e100_id_table);
+
+enum mac {
+	mac_82557_D100_A  = 0,
+	mac_82557_D100_B  = 1,
+	mac_82557_D100_C  = 2,
+	mac_82558_D101_A4 = 4,
+	mac_82558_D101_B0 = 5,
+	mac_82559_D101M   = 8,
+	mac_82559_D101S   = 9,
+	mac_82550_D102    = 12,
+	mac_82550_D102_C  = 13,
+	mac_82551_E       = 14,
+	mac_82551_F       = 15,
+	mac_82551_10      = 16,
+	mac_unknown       = 0xFF,
+};
+
+enum phy {
+	phy_100a     = 0x000003E0,
+	phy_100c     = 0x035002A8,
+	phy_82555_tx = 0x015002A8,
+	phy_nsc_tx   = 0x5C002000,
+	phy_82562_et = 0x033002A8,
+	phy_82562_em = 0x032002A8,
+	phy_82562_ek = 0x031002A8,
+	phy_82562_eh = 0x017002A8,
+	phy_unknown  = 0xFFFFFFFF,
+};
+
+/* CSR (Control/Status Registers) */
+struct csr {
+	struct {
+		u8 status;
+		u8 stat_ack;
+		u8 cmd_lo;
+		u8 cmd_hi;
+		u32 gen_ptr;
+	} scb;
+	u32 port;
+	u16 flash_ctrl;
+	u8 eeprom_ctrl_lo;
+	u8 eeprom_ctrl_hi;
+	u32 mdi_ctrl;
+	u32 rx_dma_count;
+};
+
+enum scb_status {
+	rus_ready        = 0x10,
+	rus_mask         = 0x3C,
+};
+
+enum ru_state  {
+	RU_SUSPENDED = 0,
+	RU_RUNNING	 = 1,
+	RU_UNINITIALIZED = -1,
+};
+
+enum scb_stat_ack {
+	stat_ack_not_ours    = 0x00,
+	stat_ack_sw_gen      = 0x04,
+	stat_ack_rnr         = 0x10,
+	stat_ack_cu_idle     = 0x20,
+	stat_ack_frame_rx    = 0x40,
+	stat_ack_cu_cmd_done = 0x80,
+	stat_ack_not_present = 0xFF,
+	stat_ack_rx = (stat_ack_sw_gen | stat_ack_rnr | stat_ack_frame_rx),
+	stat_ack_tx = (stat_ack_cu_idle | stat_ack_cu_cmd_done),
+};
+
+enum scb_cmd_hi {
+	irq_mask_none = 0x00,
+	irq_mask_all  = 0x01,
+	irq_sw_gen    = 0x02,
+};
+
+enum scb_cmd_lo {
+	cuc_nop        = 0x00,
+	ruc_start      = 0x01,
+	ruc_load_base  = 0x06,
+	cuc_start      = 0x10,
+	cuc_resume     = 0x20,
+	cuc_dump_addr  = 0x40,
+	cuc_dump_stats = 0x50,
+	cuc_load_base  = 0x60,
+	cuc_dump_reset = 0x70,
+};
+
+enum cuc_dump {
+	cuc_dump_complete       = 0x0000A005,
+	cuc_dump_reset_complete = 0x0000A007,
+};
+
+enum port {
+	software_reset  = 0x0000,
+	selftest        = 0x0001,
+	selective_reset = 0x0002,
+};
+
+enum eeprom_ctrl_lo {
+	eesk = 0x01,
+	eecs = 0x02,
+	eedi = 0x04,
+	eedo = 0x08,
+};
+
+enum mdi_ctrl {
+	mdi_write = 0x04000000,
+	mdi_read  = 0x08000000,
+	mdi_ready = 0x10000000,
+};
+
+enum eeprom_op {
+	op_write = 0x05,
+	op_read  = 0x06,
+	op_ewds  = 0x10,
+	op_ewen  = 0x13,
+};
+
+enum eeprom_offsets {
+	eeprom_cnfg_mdix  = 0x03,
+	eeprom_id         = 0x0A,
+	eeprom_config_asf = 0x0D,
+	eeprom_smbus_addr = 0x90,
+};
+
+enum eeprom_cnfg_mdix {
+	eeprom_mdix_enabled = 0x0080,
+};
+
+enum eeprom_id {
+	eeprom_id_wol = 0x0020,
+};
+
+enum eeprom_config_asf {
+	eeprom_asf = 0x8000,
+	eeprom_gcl = 0x4000,
+};
+
+enum cb_status {
+	cb_complete = 0x8000,
+	cb_ok       = 0x2000,
+};
+
+enum cb_command {
+	cb_nop    = 0x0000,
+	cb_iaaddr = 0x0001,
+	cb_config = 0x0002,
+	cb_multi  = 0x0003,
+	cb_tx     = 0x0004,
+	cb_ucode  = 0x0005,
+	cb_dump   = 0x0006,
+	cb_tx_sf  = 0x0008,
+	cb_cid    = 0x1f00,
+	cb_i      = 0x2000,
+	cb_s      = 0x4000,
+	cb_el     = 0x8000,
+};
+
+struct rfd {
+	u16 status;
+	u16 command;
+	u32 link;
+	u32 rbd;
+	u16 actual_size;
+	u16 size;
+};
+
+struct rx {
+	struct rx *next, *prev;
+	struct sk_buff *skb;
+	dma_addr_t dma_addr;
+};
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+#define X(a,b)	b,a
+#else
+#define X(a,b)	a,b
+#endif
+struct config {
+/*0*/	u8 X(byte_count:6, pad0:2);
+/*1*/	u8 X(X(rx_fifo_limit:4, tx_fifo_limit:3), pad1:1);
+/*2*/	u8 adaptive_ifs;
+/*3*/	u8 X(X(X(X(mwi_enable:1, type_enable:1), read_align_enable:1),
+	   term_write_cache_line:1), pad3:4);
+/*4*/	u8 X(rx_dma_max_count:7, pad4:1);
+/*5*/	u8 X(tx_dma_max_count:7, dma_max_count_enable:1);
+/*6*/	u8 X(X(X(X(X(X(X(late_scb_update:1, direct_rx_dma:1),
+	   tno_intr:1), cna_intr:1), standard_tcb:1), standard_stat_counter:1),
+	   rx_discard_overruns:1), rx_save_bad_frames:1);
+/*7*/	u8 X(X(X(X(X(rx_discard_short_frames:1, tx_underrun_retry:2),
+	   pad7:2), rx_extended_rfd:1), tx_two_frames_in_fifo:1),
+	   tx_dynamic_tbd:1);
+/*8*/	u8 X(X(mii_mode:1, pad8:6), csma_disabled:1);
+/*9*/	u8 X(X(X(X(X(rx_tcpudp_checksum:1, pad9:3), vlan_arp_tco:1),
+	   link_status_wake:1), arp_wake:1), mcmatch_wake:1);
+/*10*/	u8 X(X(X(pad10:3, no_source_addr_insertion:1), preamble_length:2),
+	   loopback:2);
+/*11*/	u8 X(linear_priority:3, pad11:5);
+/*12*/	u8 X(X(linear_priority_mode:1, pad12:3), ifs:4);
+/*13*/	u8 ip_addr_lo;
+/*14*/	u8 ip_addr_hi;
+/*15*/	u8 X(X(X(X(X(X(X(promiscuous_mode:1, broadcast_disabled:1),
+	   wait_after_win:1), pad15_1:1), ignore_ul_bit:1), crc_16_bit:1),
+	   pad15_2:1), crs_or_cdt:1);
+/*16*/	u8 fc_delay_lo;
+/*17*/	u8 fc_delay_hi;
+/*18*/	u8 X(X(X(X(X(rx_stripping:1, tx_padding:1), rx_crc_transfer:1),
+	   rx_long_ok:1), fc_priority_threshold:3), pad18:1);
+/*19*/	u8 X(X(X(X(X(X(X(addr_wake:1, magic_packet_disable:1),
+	   fc_disable:1), fc_restop:1), fc_restart:1), fc_reject:1),
+	   full_duplex_force:1), full_duplex_pin:1);
+/*20*/	u8 X(X(X(pad20_1:5, fc_priority_location:1), multi_ia:1), pad20_2:1);
+/*21*/	u8 X(X(pad21_1:3, multicast_all:1), pad21_2:4);
+/*22*/	u8 X(X(rx_d102_mode:1, rx_vlan_drop:1), pad22:6);
+	u8 pad_d102[9];
+};
+
+#define E100_MAX_MULTICAST_ADDRS	64
+struct multi {
+	u16 count;
+	u8 addr[E100_MAX_MULTICAST_ADDRS * ETH_ALEN + 2/*pad*/];
+};
+
+/* Important: keep total struct u32-aligned */
+#define UCODE_SIZE			134
+struct cb {
+	u16 status;
+	u16 command;
+	u32 link;
+	union {
+		u8 iaaddr[ETH_ALEN];
+		u32 ucode[UCODE_SIZE];
+		struct config config;
+		struct multi multi;
+		struct {
+			u32 tbd_array;
+			u16 tcb_byte_count;
+			u8 threshold;
+			u8 tbd_count;
+			struct {
+				u32 buf_addr;
+				u16 size;
+				u16 eol;
+			} tbd;
+		} tcb;
+		u32 dump_buffer_addr;
+	} u;
+	struct cb *next, *prev;
+	dma_addr_t dma_addr;
+	struct sk_buff *skb;
+};
+
+enum loopback {
+	lb_none = 0, lb_mac = 1, lb_phy = 3,
+};
+
+struct stats {
+	u32 tx_good_frames, tx_max_collisions, tx_late_collisions,
+		tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions,
+		tx_multiple_collisions, tx_total_collisions;
+	u32 rx_good_frames, rx_crc_errors, rx_alignment_errors,
+		rx_resource_errors, rx_overrun_errors, rx_cdt_errors,
+		rx_short_frame_errors;
+	u32 fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported;
+	u16 xmt_tco_frames, rcv_tco_frames;
+	u32 complete;
+};
+
+struct mem {
+	struct {
+		u32 signature;
+		u32 result;
+	} selftest;
+	struct stats stats;
+	u8 dump_buf[596];
+};
+
+struct param_range {
+	u32 min;
+	u32 max;
+	u32 count;
+};
+
+struct params {
+	struct param_range rfds;
+	struct param_range cbs;
+};
+
+struct nic {
+	/* Begin: frequently used values: keep adjacent for cache effect */
+	u32 msg_enable				____cacheline_aligned;
+	struct net_device *netdev;
+	struct pci_dev *pdev;
+
+	struct rx *rxs				____cacheline_aligned;
+	struct rx *rx_to_use;
+	struct rx *rx_to_clean;
+	struct rfd blank_rfd;
+	enum ru_state ru_running;
+
+	spinlock_t cb_lock			____cacheline_aligned;
+	spinlock_t cmd_lock;
+	struct csr __iomem *csr;
+	enum scb_cmd_lo cuc_cmd;
+	unsigned int cbs_avail;
+	struct napi_struct napi;
+	struct cb *cbs;
+	struct cb *cb_to_use;
+	struct cb *cb_to_send;
+	struct cb *cb_to_clean;
+	u16 tx_command;
+	/* End: frequently used values: keep adjacent for cache effect */
+
+	enum {
+		ich                = (1 << 0),
+		promiscuous        = (1 << 1),
+		multicast_all      = (1 << 2),
+		wol_magic          = (1 << 3),
+		ich_10h_workaround = (1 << 4),
+	} flags					____cacheline_aligned;
+
+	enum mac mac;
+	enum phy phy;
+	struct params params;
+	struct timer_list watchdog;
+	struct timer_list blink_timer;
+	struct mii_if_info mii;
+	struct work_struct tx_timeout_task;
+	enum loopback loopback;
+
+	struct mem *mem;
+	dma_addr_t dma_addr;
+
+	dma_addr_t cbs_dma_addr;
+	u8 adaptive_ifs;
+	u8 tx_threshold;
+	u32 tx_frames;
+	u32 tx_collisions;
+	u32 tx_deferred;
+	u32 tx_single_collisions;
+	u32 tx_multiple_collisions;
+	u32 tx_fc_pause;
+	u32 tx_tco_frames;
+
+	u32 rx_fc_pause;
+	u32 rx_fc_unsupported;
+	u32 rx_tco_frames;
+	u32 rx_over_length_errors;
+
+	u16 leds;
+	u16 eeprom_wc;
+	u16 eeprom[256];
+	spinlock_t mdio_lock;
+};
+
+static inline void e100_write_flush(struct nic *nic)
+{
+	/* Flush previous PCI writes through intermediate bridges
+	 * by doing a benign read */
+	(void)ioread8(&nic->csr->scb.status);
+}
+
+static void e100_enable_irq(struct nic *nic)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&nic->cmd_lock, flags);
+	iowrite8(irq_mask_none, &nic->csr->scb.cmd_hi);
+	e100_write_flush(nic);
+	spin_unlock_irqrestore(&nic->cmd_lock, flags);
+}
+
+static void e100_disable_irq(struct nic *nic)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&nic->cmd_lock, flags);
+	iowrite8(irq_mask_all, &nic->csr->scb.cmd_hi);
+	e100_write_flush(nic);
+	spin_unlock_irqrestore(&nic->cmd_lock, flags);
+}
+
+static void e100_hw_reset(struct nic *nic)
+{
+	/* Put CU and RU into idle with a selective reset to get
+	 * device off of PCI bus */
+	iowrite32(selective_reset, &nic->csr->port);
+	e100_write_flush(nic); udelay(20);
+
+	/* Now fully reset device */
+	iowrite32(software_reset, &nic->csr->port);
+	e100_write_flush(nic); udelay(20);
+
+	/* Mask off our interrupt line - it's unmasked after reset */
+	e100_disable_irq(nic);
+}
+
+static int e100_self_test(struct nic *nic)
+{
+	u32 dma_addr = nic->dma_addr + offsetof(struct mem, selftest);
+
+	/* Passing the self-test is a pretty good indication
+	 * that the device can DMA to/from host memory */
+
+	nic->mem->selftest.signature = 0;
+	nic->mem->selftest.result = 0xFFFFFFFF;
+
+	iowrite32(selftest | dma_addr, &nic->csr->port);
+	e100_write_flush(nic);
+	/* Wait 10 msec for self-test to complete */
+	msleep(10);
+
+	/* Interrupts are enabled after self-test */
+	e100_disable_irq(nic);
+
+	/* Check results of self-test */
+	if(nic->mem->selftest.result != 0) {
+		DPRINTK(HW, ERR, "Self-test failed: result=0x%08X\n",
+			nic->mem->selftest.result);
+		return -ETIMEDOUT;
+	}
+	if(nic->mem->selftest.signature == 0) {
+		DPRINTK(HW, ERR, "Self-test failed: timed out\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data)
+{
+	u32 cmd_addr_data[3];
+	u8 ctrl;
+	int i, j;
+
+	/* Three cmds: write/erase enable, write data, write/erase disable */
+	cmd_addr_data[0] = op_ewen << (addr_len - 2);
+	cmd_addr_data[1] = (((op_write << addr_len) | addr) << 16) |
+		cpu_to_le16(data);
+	cmd_addr_data[2] = op_ewds << (addr_len - 2);
+
+	/* Bit-bang cmds to write word to eeprom */
+	for(j = 0; j < 3; j++) {
+
+		/* Chip select */
+		iowrite8(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
+		e100_write_flush(nic); udelay(4);
+
+		for(i = 31; i >= 0; i--) {
+			ctrl = (cmd_addr_data[j] & (1 << i)) ?
+				eecs | eedi : eecs;
+			iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo);
+			e100_write_flush(nic); udelay(4);
+
+			iowrite8(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
+			e100_write_flush(nic); udelay(4);
+		}
+		/* Wait 10 msec for cmd to complete */
+		msleep(10);
+
+		/* Chip deselect */
+		iowrite8(0, &nic->csr->eeprom_ctrl_lo);
+		e100_write_flush(nic); udelay(4);
+	}
+};
+
+/* General technique stolen from the eepro100 driver - very clever */
+static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr)
+{
+	u32 cmd_addr_data;
+	u16 data = 0;
+	u8 ctrl;
+	int i;
+
+	cmd_addr_data = ((op_read << *addr_len) | addr) << 16;
+
+	/* Chip select */
+	iowrite8(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
+	e100_write_flush(nic); udelay(4);
+
+	/* Bit-bang to read word from eeprom */
+	for(i = 31; i >= 0; i--) {
+		ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs;
+		iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo);
+		e100_write_flush(nic); udelay(4);
+
+		iowrite8(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
+		e100_write_flush(nic); udelay(4);
+
+		/* Eeprom drives a dummy zero to EEDO after receiving
+		 * complete address.  Use this to adjust addr_len. */
+		ctrl = ioread8(&nic->csr->eeprom_ctrl_lo);
+		if(!(ctrl & eedo) && i > 16) {
+			*addr_len -= (i - 16);
+			i = 17;
+		}
+
+		data = (data << 1) | (ctrl & eedo ? 1 : 0);
+	}
+
+	/* Chip deselect */
+	iowrite8(0, &nic->csr->eeprom_ctrl_lo);
+	e100_write_flush(nic); udelay(4);
+
+	return le16_to_cpu(data);
+};
+
+/* Load entire EEPROM image into driver cache and validate checksum */
+static int e100_eeprom_load(struct nic *nic)
+{
+	u16 addr, addr_len = 8, checksum = 0;
+
+	/* Try reading with an 8-bit addr len to discover actual addr len */
+	e100_eeprom_read(nic, &addr_len, 0);
+	nic->eeprom_wc = 1 << addr_len;
+
+	for(addr = 0; addr < nic->eeprom_wc; addr++) {
+		nic->eeprom[addr] = e100_eeprom_read(nic, &addr_len, addr);
+		if(addr < nic->eeprom_wc - 1)
+			checksum += cpu_to_le16(nic->eeprom[addr]);
+	}
+
+	/* The checksum, stored in the last word, is calculated such that
+	 * the sum of words should be 0xBABA */
+	checksum = le16_to_cpu(0xBABA - checksum);
+	if(checksum != nic->eeprom[nic->eeprom_wc - 1]) {
+		DPRINTK(PROBE, ERR, "EEPROM corrupted\n");
+		if (!eeprom_bad_csum_allow)
+			return -EAGAIN;
+	}
+
+	return 0;
+}
+
+/* Save (portion of) driver EEPROM cache to device and update checksum */
+static int e100_eeprom_save(struct nic *nic, u16 start, u16 count)
+{
+	u16 addr, addr_len = 8, checksum = 0;
+
+	/* Try reading with an 8-bit addr len to discover actual addr len */
+	e100_eeprom_read(nic, &addr_len, 0);
+	nic->eeprom_wc = 1 << addr_len;
+
+	if(start + count >= nic->eeprom_wc)
+		return -EINVAL;
+
+	for(addr = start; addr < start + count; addr++)
+		e100_eeprom_write(nic, addr_len, addr, nic->eeprom[addr]);
+
+	/* The checksum, stored in the last word, is calculated such that
+	 * the sum of words should be 0xBABA */
+	for(addr = 0; addr < nic->eeprom_wc - 1; addr++)
+		checksum += cpu_to_le16(nic->eeprom[addr]);
+	nic->eeprom[nic->eeprom_wc - 1] = le16_to_cpu(0xBABA - checksum);
+	e100_eeprom_write(nic, addr_len, nic->eeprom_wc - 1,
+		nic->eeprom[nic->eeprom_wc - 1]);
+
+	return 0;
+}
+
+#define E100_WAIT_SCB_TIMEOUT 20000 /* we might have to wait 100ms!!! */
+#define E100_WAIT_SCB_FAST 20       /* delay like the old code */
+static int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
+{
+	unsigned long flags;
+	unsigned int i;
+	int err = 0;
+
+	spin_lock_irqsave(&nic->cmd_lock, flags);
+
+	/* Previous command is accepted when SCB clears */
+	for(i = 0; i < E100_WAIT_SCB_TIMEOUT; i++) {
+		if(likely(!ioread8(&nic->csr->scb.cmd_lo)))
+			break;
+		cpu_relax();
+		if(unlikely(i > E100_WAIT_SCB_FAST))
+			udelay(5);
+	}
+	if(unlikely(i == E100_WAIT_SCB_TIMEOUT)) {
+		err = -EAGAIN;
+		goto err_unlock;
+	}
+
+	if(unlikely(cmd != cuc_resume))
+		iowrite32(dma_addr, &nic->csr->scb.gen_ptr);
+	iowrite8(cmd, &nic->csr->scb.cmd_lo);
+
+err_unlock:
+	spin_unlock_irqrestore(&nic->cmd_lock, flags);
+
+	return err;
+}
+
+static int e100_exec_cb(struct nic *nic, struct sk_buff *skb,
+	void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *))
+{
+	struct cb *cb;
+	unsigned long flags;
+	int err = 0;
+
+	spin_lock_irqsave(&nic->cb_lock, flags);
+
+	if(unlikely(!nic->cbs_avail)) {
+		err = -ENOMEM;
+		goto err_unlock;
+	}
+
+	cb = nic->cb_to_use;
+	nic->cb_to_use = cb->next;
+	nic->cbs_avail--;
+	cb->skb = skb;
+
+	if(unlikely(!nic->cbs_avail))
+		err = -ENOSPC;
+
+	cb_prepare(nic, cb, skb);
+
+	/* Order is important otherwise we'll be in a race with h/w:
+	 * set S-bit in current first, then clear S-bit in previous. */
+	cb->command |= cpu_to_le16(cb_s);
+	wmb();
+	cb->prev->command &= cpu_to_le16(~cb_s);
+
+	while(nic->cb_to_send != nic->cb_to_use) {
+		if(unlikely(e100_exec_cmd(nic, nic->cuc_cmd,
+			nic->cb_to_send->dma_addr))) {
+			/* Ok, here's where things get sticky.  It's
+			 * possible that we can't schedule the command
+			 * because the controller is too busy, so
+			 * let's just queue the command and try again
+			 * when another command is scheduled. */
+			if(err == -ENOSPC) {
+				//request a reset
+				schedule_work(&nic->tx_timeout_task);
+			}
+			break;
+		} else {
+			nic->cuc_cmd = cuc_resume;
+			nic->cb_to_send = nic->cb_to_send->next;
+		}
+	}
+
+err_unlock:
+	spin_unlock_irqrestore(&nic->cb_lock, flags);
+
+	return err;
+}
+
+static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
+{
+	u32 data_out = 0;
+	unsigned int i;
+	unsigned long flags;
+
+
+	/*
+	 * Stratus87247: we shouldn't be writing the MDI control
+	 * register until the Ready bit shows True.  Also, since
+	 * manipulation of the MDI control registers is a multi-step
+	 * procedure it should be done under lock.
+	 */
+	spin_lock_irqsave(&nic->mdio_lock, flags);
+	for (i = 100; i; --i) {
+		if (ioread32(&nic->csr->mdi_ctrl) & mdi_ready)
+			break;
+		udelay(20);
+	}
+	if (unlikely(!i)) {
+		printk("e100.mdio_ctrl(%s) won't go Ready\n",
+			nic->netdev->name );
+		spin_unlock_irqrestore(&nic->mdio_lock, flags);
+		return 0;		/* No way to indicate timeout error */
+	}
+	iowrite32((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl);
+
+	for (i = 0; i < 100; i++) {
+		udelay(20);
+		if ((data_out = ioread32(&nic->csr->mdi_ctrl)) & mdi_ready)
+			break;
+	}
+	spin_unlock_irqrestore(&nic->mdio_lock, flags);
+	DPRINTK(HW, DEBUG,
+		"%s:addr=%d, reg=%d, data_in=0x%04X, data_out=0x%04X\n",
+		dir == mdi_read ? "READ" : "WRITE", addr, reg, data, data_out);
+	return (u16)data_out;
+}
+
+static int mdio_read(struct net_device *netdev, int addr, int reg)
+{
+	return mdio_ctrl(netdev_priv(netdev), addr, mdi_read, reg, 0);
+}
+
+static void mdio_write(struct net_device *netdev, int addr, int reg, int data)
+{
+	mdio_ctrl(netdev_priv(netdev), addr, mdi_write, reg, data);
+}
+
+static void e100_get_defaults(struct nic *nic)
+{
+	struct param_range rfds = { .min = 16, .max = 256, .count = 256 };
+	struct param_range cbs  = { .min = 64, .max = 256, .count = 128 };
+
+	/* MAC type is encoded as rev ID; exception: ICH is treated as 82559 */
+	nic->mac = (nic->flags & ich) ? mac_82559_D101M : nic->pdev->revision;
+	if(nic->mac == mac_unknown)
+		nic->mac = mac_82557_D100_A;
+
+	nic->params.rfds = rfds;
+	nic->params.cbs = cbs;
+
+	/* Quadwords to DMA into FIFO before starting frame transmit */
+	nic->tx_threshold = 0xE0;
+
+	/* no interrupt for every tx completion, delay = 256us if not 557*/
+	nic->tx_command = cpu_to_le16(cb_tx | cb_tx_sf |
+		((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i));
+
+	/* Template for a freshly allocated RFD */
+	nic->blank_rfd.command = cpu_to_le16(cb_el);
+	nic->blank_rfd.rbd = 0xFFFFFFFF;
+	nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN);
+
+	/* MII setup */
+	nic->mii.phy_id_mask = 0x1F;
+	nic->mii.reg_num_mask = 0x1F;
+	nic->mii.dev = nic->netdev;
+	nic->mii.mdio_read = mdio_read;
+	nic->mii.mdio_write = mdio_write;
+}
+
+static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb)
+{
+	struct config *config = &cb->u.config;
+	u8 *c = (u8 *)config;
+
+	cb->command = cpu_to_le16(cb_config);
+
+	memset(config, 0, sizeof(struct config));
+
+	config->byte_count = 0x16;		/* bytes in this struct */
+	config->rx_fifo_limit = 0x8;		/* bytes in FIFO before DMA */
+	config->direct_rx_dma = 0x1;		/* reserved */
+	config->standard_tcb = 0x1;		/* 1=standard, 0=extended */
+	config->standard_stat_counter = 0x1;	/* 1=standard, 0=extended */
+	config->rx_discard_short_frames = 0x1;	/* 1=discard, 0=pass */
+	config->tx_underrun_retry = 0x3;	/* # of underrun retries */
+	config->mii_mode = 0x1;			/* 1=MII mode, 0=503 mode */
+	config->pad10 = 0x6;
+	config->no_source_addr_insertion = 0x1;	/* 1=no, 0=yes */
+	config->preamble_length = 0x2;		/* 0=1, 1=3, 2=7, 3=15 bytes */
+	config->ifs = 0x6;			/* x16 = inter frame spacing */
+	config->ip_addr_hi = 0xF2;		/* ARP IP filter - not used */
+	config->pad15_1 = 0x1;
+	config->pad15_2 = 0x1;
+	config->crs_or_cdt = 0x0;		/* 0=CRS only, 1=CRS or CDT */
+	config->fc_delay_hi = 0x40;		/* time delay for fc frame */
+	config->tx_padding = 0x1;		/* 1=pad short frames */
+	config->fc_priority_threshold = 0x7;	/* 7=priority fc disabled */
+	config->pad18 = 0x1;
+	config->full_duplex_pin = 0x1;		/* 1=examine FDX# pin */
+	config->pad20_1 = 0x1F;
+	config->fc_priority_location = 0x1;	/* 1=byte#31, 0=byte#19 */
+	config->pad21_1 = 0x5;
+
+	config->adaptive_ifs = nic->adaptive_ifs;
+	config->loopback = nic->loopback;
+
+	if(nic->mii.force_media && nic->mii.full_duplex)
+		config->full_duplex_force = 0x1;	/* 1=force, 0=auto */
+
+	if(nic->flags & promiscuous || nic->loopback) {
+		config->rx_save_bad_frames = 0x1;	/* 1=save, 0=discard */
+		config->rx_discard_short_frames = 0x0;	/* 1=discard, 0=save */
+		config->promiscuous_mode = 0x1;		/* 1=on, 0=off */
+	}
+
+	if(nic->flags & multicast_all)
+		config->multicast_all = 0x1;		/* 1=accept, 0=no */
+
+	/* disable WoL when up */
+	if(netif_running(nic->netdev) || !(nic->flags & wol_magic))
+		config->magic_packet_disable = 0x1;	/* 1=off, 0=on */
+
+	if(nic->mac >= mac_82558_D101_A4) {
+		config->fc_disable = 0x1;	/* 1=Tx fc off, 0=Tx fc on */
+		config->mwi_enable = 0x1;	/* 1=enable, 0=disable */
+		config->standard_tcb = 0x0;	/* 1=standard, 0=extended */
+		config->rx_long_ok = 0x1;	/* 1=VLANs ok, 0=standard */
+		if (nic->mac >= mac_82559_D101M) {
+			config->tno_intr = 0x1;		/* TCO stats enable */
+			/* Enable TCO in extended config */
+			if (nic->mac >= mac_82551_10) {
+				config->byte_count = 0x20; /* extended bytes */
+				config->rx_d102_mode = 0x1; /* GMRC for TCO */
+			}
+		} else {
+			config->standard_stat_counter = 0x0;
+		}
+	}
+
+	DPRINTK(HW, DEBUG, "[00-07]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+		c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
+	DPRINTK(HW, DEBUG, "[08-15]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+		c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15]);
+	DPRINTK(HW, DEBUG, "[16-23]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+		c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]);
+}
+
+/********************************************************/
+/*  Micro code for 8086:1229 Rev 8                      */
+/********************************************************/
+
+/*  Parameter values for the D101M B-step  */
+#define D101M_CPUSAVER_TIMER_DWORD		78
+#define D101M_CPUSAVER_BUNDLE_DWORD		65
+#define D101M_CPUSAVER_MIN_SIZE_DWORD		126
+
+#define D101M_B_RCVBUNDLE_UCODE \
+{\
+0x00550215, 0xFFFF0437, 0xFFFFFFFF, 0x06A70789, 0xFFFFFFFF, 0x0558FFFF, \
+0x000C0001, 0x00101312, 0x000C0008, 0x00380216, \
+0x0010009C, 0x00204056, 0x002380CC, 0x00380056, \
+0x0010009C, 0x00244C0B, 0x00000800, 0x00124818, \
+0x00380438, 0x00000000, 0x00140000, 0x00380555, \
+0x00308000, 0x00100662, 0x00100561, 0x000E0408, \
+0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
+0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
+0x000C007E, 0x00222C21, 0x000C0002, 0x00103093, \
+0x00380C7A, 0x00080000, 0x00103090, 0x00380C7A, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x00244C2D, 0x00010004, 0x00041000, \
+0x003A0437, 0x00044010, 0x0038078A, 0x00000000, \
+0x00100099, 0x00206C7A, 0x0010009C, 0x00244C48, \
+0x00130824, 0x000C0001, 0x00101213, 0x00260C75, \
+0x00041000, 0x00010004, 0x00130826, 0x000C0006, \
+0x002206A8, 0x0013C926, 0x00101313, 0x003806A8, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
+0x00101210, 0x00380C34, 0x00000000, 0x00000000, \
+0x0021155B, 0x00100099, 0x00206559, 0x0010009C, \
+0x00244559, 0x00130836, 0x000C0000, 0x00220C62, \
+0x000C0001, 0x00101B13, 0x00229C0E, 0x00210C0E, \
+0x00226C0E, 0x00216C0E, 0x0022FC0E, 0x00215C0E, \
+0x00214C0E, 0x00380555, 0x00010004, 0x00041000, \
+0x00278C67, 0x00040800, 0x00018100, 0x003A0437, \
+0x00130826, 0x000C0001, 0x00220559, 0x00101313, \
+0x00380559, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00130831, 0x0010090B, 0x00124813, \
+0x000CFF80, 0x002606AB, 0x00041000, 0x00010004, \
+0x003806A8, 0x00000000, 0x00000000, 0x00000000, \
+}
+
+/********************************************************/
+/*  Micro code for 8086:1229 Rev 9                      */
+/********************************************************/
+
+/*  Parameter values for the D101S  */
+#define D101S_CPUSAVER_TIMER_DWORD		78
+#define D101S_CPUSAVER_BUNDLE_DWORD		67
+#define D101S_CPUSAVER_MIN_SIZE_DWORD		128
+
+#define D101S_RCVBUNDLE_UCODE \
+{\
+0x00550242, 0xFFFF047E, 0xFFFFFFFF, 0x06FF0818, 0xFFFFFFFF, 0x05A6FFFF, \
+0x000C0001, 0x00101312, 0x000C0008, 0x00380243, \
+0x0010009C, 0x00204056, 0x002380D0, 0x00380056, \
+0x0010009C, 0x00244F8B, 0x00000800, 0x00124818, \
+0x0038047F, 0x00000000, 0x00140000, 0x003805A3, \
+0x00308000, 0x00100610, 0x00100561, 0x000E0408, \
+0x00134861, 0x000C0002, 0x00103093, 0x00308000, \
+0x00100624, 0x00100561, 0x000E0408, 0x00100861, \
+0x000C007E, 0x00222FA1, 0x000C0002, 0x00103093, \
+0x00380F90, 0x00080000, 0x00103090, 0x00380F90, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x0010009C, 0x00244FAD, 0x00010004, 0x00041000, \
+0x003A047E, 0x00044010, 0x00380819, 0x00000000, \
+0x00100099, 0x00206FFD, 0x0010009A, 0x0020AFFD, \
+0x0010009C, 0x00244FC8, 0x00130824, 0x000C0001, \
+0x00101213, 0x00260FF7, 0x00041000, 0x00010004, \
+0x00130826, 0x000C0006, 0x00220700, 0x0013C926, \
+0x00101313, 0x00380700, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00080600, 0x00101B10, 0x00050004, 0x00100826, \
+0x00101210, 0x00380FB6, 0x00000000, 0x00000000, \
+0x002115A9, 0x00100099, 0x002065A7, 0x0010009A, \
+0x0020A5A7, 0x0010009C, 0x002445A7, 0x00130836, \
+0x000C0000, 0x00220FE4, 0x000C0001, 0x00101B13, \
+0x00229F8E, 0x00210F8E, 0x00226F8E, 0x00216F8E, \
+0x0022FF8E, 0x00215F8E, 0x00214F8E, 0x003805A3, \
+0x00010004, 0x00041000, 0x00278FE9, 0x00040800, \
+0x00018100, 0x003A047E, 0x00130826, 0x000C0001, \
+0x002205A7, 0x00101313, 0x003805A7, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00130831, \
+0x0010090B, 0x00124813, 0x000CFF80, 0x00260703, \
+0x00041000, 0x00010004, 0x00380700  \
+}
+
+/********************************************************/
+/*  Micro code for the 8086:1229 Rev F/10               */
+/********************************************************/
+
+/*  Parameter values for the D102 E-step  */
+#define D102_E_CPUSAVER_TIMER_DWORD		42
+#define D102_E_CPUSAVER_BUNDLE_DWORD		54
+#define D102_E_CPUSAVER_MIN_SIZE_DWORD		46
+
+#define     D102_E_RCVBUNDLE_UCODE \
+{\
+0x007D028F, 0x0E4204F9, 0x14ED0C85, 0x14FA14E9, 0x0EF70E36, 0x1FFF1FFF, \
+0x00E014B9, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014BD, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014D5, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014C1, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00E014C8, 0x00000000, 0x00000000, 0x00000000, \
+0x00200600, 0x00E014EE, 0x00000000, 0x00000000, \
+0x0030FF80, 0x00940E46, 0x00038200, 0x00102000, \
+0x00E00E43, 0x00000000, 0x00000000, 0x00000000, \
+0x00300006, 0x00E014FB, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00906E41, 0x00800E3C, 0x00E00E39, 0x00000000, \
+0x00906EFD, 0x00900EFD, 0x00E00EF8, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+0x00000000, 0x00000000, 0x00000000, 0x00000000, \
+}
+
+static void e100_setup_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb)
+{
+/* *INDENT-OFF* */
+	static struct {
+		u32 ucode[UCODE_SIZE + 1];
+		u8 mac;
+		u8 timer_dword;
+		u8 bundle_dword;
+		u8 min_size_dword;
+	} ucode_opts[] = {
+		{ D101M_B_RCVBUNDLE_UCODE,
+		  mac_82559_D101M,
+		  D101M_CPUSAVER_TIMER_DWORD,
+		  D101M_CPUSAVER_BUNDLE_DWORD,
+		  D101M_CPUSAVER_MIN_SIZE_DWORD },
+		{ D101S_RCVBUNDLE_UCODE,
+		  mac_82559_D101S,
+		  D101S_CPUSAVER_TIMER_DWORD,
+		  D101S_CPUSAVER_BUNDLE_DWORD,
+		  D101S_CPUSAVER_MIN_SIZE_DWORD },
+		{ D102_E_RCVBUNDLE_UCODE,
+		  mac_82551_F,
+		  D102_E_CPUSAVER_TIMER_DWORD,
+		  D102_E_CPUSAVER_BUNDLE_DWORD,
+		  D102_E_CPUSAVER_MIN_SIZE_DWORD },
+		{ D102_E_RCVBUNDLE_UCODE,
+		  mac_82551_10,
+		  D102_E_CPUSAVER_TIMER_DWORD,
+		  D102_E_CPUSAVER_BUNDLE_DWORD,
+		  D102_E_CPUSAVER_MIN_SIZE_DWORD },
+		{ {0}, 0, 0, 0, 0}
+	}, *opts;
+/* *INDENT-ON* */
+
+/*************************************************************************
+*  CPUSaver parameters
+*
+*  All CPUSaver parameters are 16-bit literals that are part of a
+*  "move immediate value" instruction.  By changing the value of
+*  the literal in the instruction before the code is loaded, the
+*  driver can change the algorithm.
+*
+*  INTDELAY - This loads the dead-man timer with its initial value.
+*    When this timer expires the interrupt is asserted, and the
+*    timer is reset each time a new packet is received.  (see
+*    BUNDLEMAX below to set the limit on number of chained packets)
+*    The current default is 0x600 or 1536.  Experiments show that
+*    the value should probably stay within the 0x200 - 0x1000.
+*
+*  BUNDLEMAX -
+*    This sets the maximum number of frames that will be bundled.  In
+*    some situations, such as the TCP windowing algorithm, it may be
+*    better to limit the growth of the bundle size than let it go as
+*    high as it can, because that could cause too much added latency.
+*    The default is six, because this is the number of packets in the
+*    default TCP window size.  A value of 1 would make CPUSaver indicate
+*    an interrupt for every frame received.  If you do not want to put
+*    a limit on the bundle size, set this value to xFFFF.
+*
+*  BUNDLESMALL -
+*    This contains a bit-mask describing the minimum size frame that
+*    will be bundled.  The default masks the lower 7 bits, which means
+*    that any frame less than 128 bytes in length will not be bundled,
+*    but will instead immediately generate an interrupt.  This does
+*    not affect the current bundle in any way.  Any frame that is 128
+*    bytes or large will be bundled normally.  This feature is meant
+*    to provide immediate indication of ACK frames in a TCP environment.
+*    Customers were seeing poor performance when a machine with CPUSaver
+*    enabled was sending but not receiving.  The delay introduced when
+*    the ACKs were received was enough to reduce total throughput, because
+*    the sender would sit idle until the ACK was finally seen.
+*
+*    The current default is 0xFF80, which masks out the lower 7 bits.
+*    This means that any frame which is x7F (127) bytes or smaller
+*    will cause an immediate interrupt.  Because this value must be a
+*    bit mask, there are only a few valid values that can be used.  To
+*    turn this feature off, the driver can write the value xFFFF to the
+*    lower word of this instruction (in the same way that the other
+*    parameters are used).  Likewise, a value of 0xF800 (2047) would
+*    cause an interrupt to be generated for every frame, because all
+*    standard Ethernet frames are <= 2047 bytes in length.
+*************************************************************************/
+
+/* if you wish to disable the ucode functionality, while maintaining the
+ * workarounds it provides, set the following defines to:
+ * BUNDLESMALL 0
+ * BUNDLEMAX 1
+ * INTDELAY 1
+ */
+#define BUNDLESMALL 1
+#define BUNDLEMAX (u16)6
+#define INTDELAY (u16)1536 /* 0x600 */
+
+	/* do not load u-code for ICH devices */
+	if (nic->flags & ich)
+		goto noloaducode;
+
+	/* Search for ucode match against h/w revision */
+	for (opts = ucode_opts; opts->mac; opts++) {
+		int i;
+		u32 *ucode = opts->ucode;
+		if (nic->mac != opts->mac)
+			continue;
+
+		/* Insert user-tunable settings */
+		ucode[opts->timer_dword] &= 0xFFFF0000;
+		ucode[opts->timer_dword] |= INTDELAY;
+		ucode[opts->bundle_dword] &= 0xFFFF0000;
+		ucode[opts->bundle_dword] |= BUNDLEMAX;
+		ucode[opts->min_size_dword] &= 0xFFFF0000;
+		ucode[opts->min_size_dword] |= (BUNDLESMALL) ? 0xFFFF : 0xFF80;
+
+		for (i = 0; i < UCODE_SIZE; i++)
+			cb->u.ucode[i] = cpu_to_le32(ucode[i]);
+		cb->command = cpu_to_le16(cb_ucode | cb_el);
+		return;
+	}
+
+noloaducode:
+	cb->command = cpu_to_le16(cb_nop | cb_el);
+}
+
+static inline int e100_exec_cb_wait(struct nic *nic, struct sk_buff *skb,
+	void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *))
+{
+	int err = 0, counter = 50;
+	struct cb *cb = nic->cb_to_clean;
+
+	if ((err = e100_exec_cb(nic, NULL, e100_setup_ucode)))
+		DPRINTK(PROBE,ERR, "ucode cmd failed with error %d\n", err);
+
+	/* must restart cuc */
+	nic->cuc_cmd = cuc_start;
+
+	/* wait for completion */
+	e100_write_flush(nic);
+	udelay(10);
+
+	/* wait for possibly (ouch) 500ms */
+	while (!(cb->status & cpu_to_le16(cb_complete))) {
+		msleep(10);
+		if (!--counter) break;
+	}
+
+	/* ack any interrupts, something could have been set */
+	iowrite8(~0, &nic->csr->scb.stat_ack);
+
+	/* if the command failed, or is not OK, notify and return */
+	if (!counter || !(cb->status & cpu_to_le16(cb_ok))) {
+		DPRINTK(PROBE,ERR, "ucode load failed\n");
+		err = -EPERM;
+	}
+
+	return err;
+}
+
+static void e100_setup_iaaddr(struct nic *nic, struct cb *cb,
+	struct sk_buff *skb)
+{
+	cb->command = cpu_to_le16(cb_iaaddr);
+	memcpy(cb->u.iaaddr, nic->netdev->dev_addr, ETH_ALEN);
+}
+
+static void e100_dump(struct nic *nic, struct cb *cb, struct sk_buff *skb)
+{
+	cb->command = cpu_to_le16(cb_dump);
+	cb->u.dump_buffer_addr = cpu_to_le32(nic->dma_addr +
+		offsetof(struct mem, dump_buf));
+}
+
+#define NCONFIG_AUTO_SWITCH	0x0080
+#define MII_NSC_CONG		MII_RESV1
+#define NSC_CONG_ENABLE		0x0100
+#define NSC_CONG_TXREADY	0x0400
+#define ADVERTISE_FC_SUPPORTED	0x0400
+static int e100_phy_init(struct nic *nic)
+{
+	struct net_device *netdev = nic->netdev;
+	u32 addr;
+	u16 bmcr, stat, id_lo, id_hi, cong;
+
+	/* Discover phy addr by searching addrs in order {1,0,2,..., 31} */
+	for(addr = 0; addr < 32; addr++) {
+		nic->mii.phy_id = (addr == 0) ? 1 : (addr == 1) ? 0 : addr;
+		bmcr = mdio_read(netdev, nic->mii.phy_id, MII_BMCR);
+		stat = mdio_read(netdev, nic->mii.phy_id, MII_BMSR);
+		stat = mdio_read(netdev, nic->mii.phy_id, MII_BMSR);
+		if(!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0))))
+			break;
+	}
+	DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id);
+	if(addr == 32)
+		return -EAGAIN;
+
+	/* Selected the phy and isolate the rest */
+	for(addr = 0; addr < 32; addr++) {
+		if(addr != nic->mii.phy_id) {
+			mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE);
+		} else {
+			bmcr = mdio_read(netdev, addr, MII_BMCR);
+			mdio_write(netdev, addr, MII_BMCR,
+				bmcr & ~BMCR_ISOLATE);
+		}
+	}
+
+	/* Get phy ID */
+	id_lo = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID1);
+	id_hi = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID2);
+	nic->phy = (u32)id_hi << 16 | (u32)id_lo;
+	DPRINTK(HW, DEBUG, "phy ID = 0x%08X\n", nic->phy);
+
+	/* Handle National tx phys */
+#define NCS_PHY_MODEL_MASK	0xFFF0FFFF
+	if((nic->phy & NCS_PHY_MODEL_MASK) == phy_nsc_tx) {
+		/* Disable congestion control */
+		cong = mdio_read(netdev, nic->mii.phy_id, MII_NSC_CONG);
+		cong |= NSC_CONG_TXREADY;
+		cong &= ~NSC_CONG_ENABLE;
+		mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong);
+	}
+
+	if((nic->mac >= mac_82550_D102) || ((nic->flags & ich) &&
+	   (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) &&
+		!(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) {
+		/* enable/disable MDI/MDI-X auto-switching. */
+		mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG,
+				nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH);
+	}
+
+	return 0;
+}
+
+static int e100_hw_init(struct nic *nic)
+{
+	int err;
+
+	e100_hw_reset(nic);
+
+	DPRINTK(HW, ERR, "e100_hw_init\n");
+	if(!in_interrupt() && (err = e100_self_test(nic)))
+		return err;
+
+	if((err = e100_phy_init(nic)))
+		return err;
+	if((err = e100_exec_cmd(nic, cuc_load_base, 0)))
+		return err;
+	if((err = e100_exec_cmd(nic, ruc_load_base, 0)))
+		return err;
+	if ((err = e100_exec_cb_wait(nic, NULL, e100_setup_ucode)))
+		return err;
+	if((err = e100_exec_cb(nic, NULL, e100_configure)))
+		return err;
+	if((err = e100_exec_cb(nic, NULL, e100_setup_iaaddr)))
+		return err;
+	if((err = e100_exec_cmd(nic, cuc_dump_addr,
+		nic->dma_addr + offsetof(struct mem, stats))))
+		return err;
+	if((err = e100_exec_cmd(nic, cuc_dump_reset, 0)))
+		return err;
+
+	e100_disable_irq(nic);
+
+	return 0;
+}
+
+static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb)
+{
+	struct net_device *netdev = nic->netdev;
+	struct dev_mc_list *list = netdev->mc_list;
+	u16 i, count = min(netdev->mc_count, E100_MAX_MULTICAST_ADDRS);
+
+	cb->command = cpu_to_le16(cb_multi);
+	cb->u.multi.count = cpu_to_le16(count * ETH_ALEN);
+	for(i = 0; list && i < count; i++, list = list->next)
+		memcpy(&cb->u.multi.addr[i*ETH_ALEN], &list->dmi_addr,
+			ETH_ALEN);
+}
+
+static void e100_set_multicast_list(struct net_device *netdev)
+{
+	struct nic *nic = netdev_priv(netdev);
+
+	DPRINTK(HW, DEBUG, "mc_count=%d, flags=0x%04X\n",
+		netdev->mc_count, netdev->flags);
+
+	if(netdev->flags & IFF_PROMISC)
+		nic->flags |= promiscuous;
+	else
+		nic->flags &= ~promiscuous;
+
+	if(netdev->flags & IFF_ALLMULTI ||
+		netdev->mc_count > E100_MAX_MULTICAST_ADDRS)
+		nic->flags |= multicast_all;
+	else
+		nic->flags &= ~multicast_all;
+
+	e100_exec_cb(nic, NULL, e100_configure);
+	e100_exec_cb(nic, NULL, e100_multi);
+}
+
+static void e100_update_stats(struct nic *nic)
+{
+	struct net_device *dev = nic->netdev;
+	struct net_device_stats *ns = &dev->stats;
+	struct stats *s = &nic->mem->stats;
+	u32 *complete = (nic->mac < mac_82558_D101_A4) ? &s->fc_xmt_pause :
+		(nic->mac < mac_82559_D101M) ? (u32 *)&s->xmt_tco_frames :
+		&s->complete;
+
+	/* Device's stats reporting may take several microseconds to
+	 * complete, so where always waiting for results of the
+	 * previous command. */
+
+	if(*complete == le32_to_cpu(cuc_dump_reset_complete)) {
+		*complete = 0;
+		nic->tx_frames = le32_to_cpu(s->tx_good_frames);
+		nic->tx_collisions = le32_to_cpu(s->tx_total_collisions);
+		ns->tx_aborted_errors += le32_to_cpu(s->tx_max_collisions);
+		ns->tx_window_errors += le32_to_cpu(s->tx_late_collisions);
+		ns->tx_carrier_errors += le32_to_cpu(s->tx_lost_crs);
+		ns->tx_fifo_errors += le32_to_cpu(s->tx_underruns);
+		ns->collisions += nic->tx_collisions;
+		ns->tx_errors += le32_to_cpu(s->tx_max_collisions) +
+			le32_to_cpu(s->tx_lost_crs);
+		ns->rx_length_errors += le32_to_cpu(s->rx_short_frame_errors) +
+			nic->rx_over_length_errors;
+		ns->rx_crc_errors += le32_to_cpu(s->rx_crc_errors);
+		ns->rx_frame_errors += le32_to_cpu(s->rx_alignment_errors);
+		ns->rx_over_errors += le32_to_cpu(s->rx_overrun_errors);
+		ns->rx_fifo_errors += le32_to_cpu(s->rx_overrun_errors);
+		ns->rx_missed_errors += le32_to_cpu(s->rx_resource_errors);
+		ns->rx_errors += le32_to_cpu(s->rx_crc_errors) +
+			le32_to_cpu(s->rx_alignment_errors) +
+			le32_to_cpu(s->rx_short_frame_errors) +
+			le32_to_cpu(s->rx_cdt_errors);
+		nic->tx_deferred += le32_to_cpu(s->tx_deferred);
+		nic->tx_single_collisions +=
+			le32_to_cpu(s->tx_single_collisions);
+		nic->tx_multiple_collisions +=
+			le32_to_cpu(s->tx_multiple_collisions);
+		if(nic->mac >= mac_82558_D101_A4) {
+			nic->tx_fc_pause += le32_to_cpu(s->fc_xmt_pause);
+			nic->rx_fc_pause += le32_to_cpu(s->fc_rcv_pause);
+			nic->rx_fc_unsupported +=
+				le32_to_cpu(s->fc_rcv_unsupported);
+			if(nic->mac >= mac_82559_D101M) {
+				nic->tx_tco_frames +=
+					le16_to_cpu(s->xmt_tco_frames);
+				nic->rx_tco_frames +=
+					le16_to_cpu(s->rcv_tco_frames);
+			}
+		}
+	}
+
+
+	if(e100_exec_cmd(nic, cuc_dump_reset, 0))
+		DPRINTK(TX_ERR, DEBUG, "exec cuc_dump_reset failed\n");
+}
+
+static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex)
+{
+	/* Adjust inter-frame-spacing (IFS) between two transmits if
+	 * we're getting collisions on a half-duplex connection. */
+
+	if(duplex == DUPLEX_HALF) {
+		u32 prev = nic->adaptive_ifs;
+		u32 min_frames = (speed == SPEED_100) ? 1000 : 100;
+
+		if((nic->tx_frames / 32 < nic->tx_collisions) &&
+		   (nic->tx_frames > min_frames)) {
+			if(nic->adaptive_ifs < 60)
+				nic->adaptive_ifs += 5;
+		} else if (nic->tx_frames < min_frames) {
+			if(nic->adaptive_ifs >= 5)
+				nic->adaptive_ifs -= 5;
+		}
+		if(nic->adaptive_ifs != prev)
+			e100_exec_cb(nic, NULL, e100_configure);
+	}
+}
+
+static void e100_watchdog(unsigned long data)
+{
+	struct nic *nic = (struct nic *)data;
+	struct ethtool_cmd cmd;
+
+	DPRINTK(TIMER, DEBUG, "right now = %ld\n", jiffies);
+
+	/* mii library handles link maintenance tasks */
+
+	mii_ethtool_gset(&nic->mii, &cmd);
+
+	if(mii_link_ok(&nic->mii) && !netif_carrier_ok(nic->netdev)) {
+		DPRINTK(LINK, INFO, "link up, %sMbps, %s-duplex\n",
+			cmd.speed == SPEED_100 ? "100" : "10",
+			cmd.duplex == DUPLEX_FULL ? "full" : "half");
+	} else if(!mii_link_ok(&nic->mii) && netif_carrier_ok(nic->netdev)) {
+		DPRINTK(LINK, INFO, "link down\n");
+	}
+
+	mii_check_link(&nic->mii);
+
+	/* Software generated interrupt to recover from (rare) Rx
+	 * allocation failure.
+	 * Unfortunately have to use a spinlock to not re-enable interrupts
+	 * accidentally, due to hardware that shares a register between the
+	 * interrupt mask bit and the SW Interrupt generation bit */
+	spin_lock_irq(&nic->cmd_lock);
+	iowrite8(ioread8(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi);
+	e100_write_flush(nic);
+	spin_unlock_irq(&nic->cmd_lock);
+
+	e100_update_stats(nic);
+	e100_adjust_adaptive_ifs(nic, cmd.speed, cmd.duplex);
+
+	if(nic->mac <= mac_82557_D100_C)
+		/* Issue a multicast command to workaround a 557 lock up */
+		e100_set_multicast_list(nic->netdev);
+
+	if(nic->flags & ich && cmd.speed==SPEED_10 && cmd.duplex==DUPLEX_HALF)
+		/* Need SW workaround for ICH[x] 10Mbps/half duplex Tx hang. */
+		nic->flags |= ich_10h_workaround;
+	else
+		nic->flags &= ~ich_10h_workaround;
+
+	mod_timer(&nic->watchdog,
+		  round_jiffies(jiffies + E100_WATCHDOG_PERIOD));
+}
+
+static void e100_xmit_prepare(struct nic *nic, struct cb *cb,
+	struct sk_buff *skb)
+{
+	cb->command = nic->tx_command;
+	/* interrupt every 16 packets regardless of delay */
+	if((nic->cbs_avail & ~15) == nic->cbs_avail)
+		cb->command |= cpu_to_le16(cb_i);
+	cb->u.tcb.tbd_array = cb->dma_addr + offsetof(struct cb, u.tcb.tbd);
+	cb->u.tcb.tcb_byte_count = 0;
+	cb->u.tcb.threshold = nic->tx_threshold;
+	cb->u.tcb.tbd_count = 1;
+	cb->u.tcb.tbd.buf_addr = cpu_to_le32(pci_map_single(nic->pdev,
+		skb->data, skb->len, PCI_DMA_TODEVICE));
+	/* check for mapping failure? */
+	cb->u.tcb.tbd.size = cpu_to_le16(skb->len);
+}
+
+static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct nic *nic = netdev_priv(netdev);
+	int err;
+
+	if(nic->flags & ich_10h_workaround) {
+		/* SW workaround for ICH[x] 10Mbps/half duplex Tx hang.
+		   Issue a NOP command followed by a 1us delay before
+		   issuing the Tx command. */
+		if(e100_exec_cmd(nic, cuc_nop, 0))
+			DPRINTK(TX_ERR, DEBUG, "exec cuc_nop failed\n");
+		udelay(1);
+	}
+
+	err = e100_exec_cb(nic, skb, e100_xmit_prepare);
+
+	switch(err) {
+	case -ENOSPC:
+		/* We queued the skb, but now we're out of space. */
+		DPRINTK(TX_ERR, DEBUG, "No space for CB\n");
+		netif_stop_queue(netdev);
+		break;
+	case -ENOMEM:
+		/* This is a hard error - log it. */
+		DPRINTK(TX_ERR, DEBUG, "Out of Tx resources, returning skb\n");
+		netif_stop_queue(netdev);
+		return 1;
+	}
+
+	netdev->trans_start = jiffies;
+	return 0;
+}
+
+static int e100_tx_clean(struct nic *nic)
+{
+	struct net_device *dev = nic->netdev;
+	struct cb *cb;
+	int tx_cleaned = 0;
+
+	spin_lock(&nic->cb_lock);
+
+	/* Clean CBs marked complete */
+	for(cb = nic->cb_to_clean;
+	    cb->status & cpu_to_le16(cb_complete);
+	    cb = nic->cb_to_clean = cb->next) {
+		DPRINTK(TX_DONE, DEBUG, "cb[%d]->status = 0x%04X\n",
+		        (int)(((void*)cb - (void*)nic->cbs)/sizeof(struct cb)),
+		        cb->status);
+
+		if(likely(cb->skb != NULL)) {
+			dev->stats.tx_packets++;
+			dev->stats.tx_bytes += cb->skb->len;
+
+			pci_unmap_single(nic->pdev,
+				le32_to_cpu(cb->u.tcb.tbd.buf_addr),
+				le16_to_cpu(cb->u.tcb.tbd.size),
+				PCI_DMA_TODEVICE);
+			dev_kfree_skb_any(cb->skb);
+			cb->skb = NULL;
+			tx_cleaned = 1;
+		}
+		cb->status = 0;
+		nic->cbs_avail++;
+	}
+
+	spin_unlock(&nic->cb_lock);
+
+	/* Recover from running out of Tx resources in xmit_frame */
+	if(unlikely(tx_cleaned && netif_queue_stopped(nic->netdev)))
+		netif_wake_queue(nic->netdev);
+
+	return tx_cleaned;
+}
+
+static void e100_clean_cbs(struct nic *nic)
+{
+	if(nic->cbs) {
+		while(nic->cbs_avail != nic->params.cbs.count) {
+			struct cb *cb = nic->cb_to_clean;
+			if(cb->skb) {
+				pci_unmap_single(nic->pdev,
+					le32_to_cpu(cb->u.tcb.tbd.buf_addr),
+					le16_to_cpu(cb->u.tcb.tbd.size),
+					PCI_DMA_TODEVICE);
+				dev_kfree_skb(cb->skb);
+			}
+			nic->cb_to_clean = nic->cb_to_clean->next;
+			nic->cbs_avail++;
+		}
+		pci_free_consistent(nic->pdev,
+			sizeof(struct cb) * nic->params.cbs.count,
+			nic->cbs, nic->cbs_dma_addr);
+		nic->cbs = NULL;
+		nic->cbs_avail = 0;
+	}
+	nic->cuc_cmd = cuc_start;
+	nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean =
+		nic->cbs;
+}
+
+static int e100_alloc_cbs(struct nic *nic)
+{
+	struct cb *cb;
+	unsigned int i, count = nic->params.cbs.count;
+
+	nic->cuc_cmd = cuc_start;
+	nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = NULL;
+	nic->cbs_avail = 0;
+
+	nic->cbs = pci_alloc_consistent(nic->pdev,
+		sizeof(struct cb) * count, &nic->cbs_dma_addr);
+	if(!nic->cbs)
+		return -ENOMEM;
+
+	for(cb = nic->cbs, i = 0; i < count; cb++, i++) {
+		cb->next = (i + 1 < count) ? cb + 1 : nic->cbs;
+		cb->prev = (i == 0) ? nic->cbs + count - 1 : cb - 1;
+
+		cb->dma_addr = nic->cbs_dma_addr + i * sizeof(struct cb);
+		cb->link = cpu_to_le32(nic->cbs_dma_addr +
+			((i+1) % count) * sizeof(struct cb));
+		cb->skb = NULL;
+	}
+
+	nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = nic->cbs;
+	nic->cbs_avail = count;
+
+	return 0;
+}
+
+static inline void e100_start_receiver(struct nic *nic, struct rx *rx)
+{
+	if(!nic->rxs) return;
+	if(RU_SUSPENDED != nic->ru_running) return;
+
+	/* handle init time starts */
+	if(!rx) rx = nic->rxs;
+
+	/* (Re)start RU if suspended or idle and RFA is non-NULL */
+	if(rx->skb) {
+		e100_exec_cmd(nic, ruc_start, rx->dma_addr);
+		nic->ru_running = RU_RUNNING;
+	}
+}
+
+#define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN)
+static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
+{
+	if(!(rx->skb = netdev_alloc_skb(nic->netdev, RFD_BUF_LEN + NET_IP_ALIGN)))
+		return -ENOMEM;
+
+	/* Align, init, and map the RFD. */
+	skb_reserve(rx->skb, NET_IP_ALIGN);
+	skb_copy_to_linear_data(rx->skb, &nic->blank_rfd, sizeof(struct rfd));
+	rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data,
+		RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);
+
+	if(pci_dma_mapping_error(rx->dma_addr)) {
+		dev_kfree_skb_any(rx->skb);
+		rx->skb = NULL;
+		rx->dma_addr = 0;
+		return -ENOMEM;
+	}
+
+	/* Link the RFD to end of RFA by linking previous RFD to
+	 * this one, and clearing EL bit of previous.  */
+	if(rx->prev->skb) {
+		struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data;
+		put_unaligned(cpu_to_le32(rx->dma_addr),
+			(u32 *)&prev_rfd->link);
+		wmb();
+		prev_rfd->command &= ~cpu_to_le16(cb_el);
+		pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,
+			sizeof(struct rfd), PCI_DMA_TODEVICE);
+	}
+
+	return 0;
+}
+
+static int e100_rx_indicate(struct nic *nic, struct rx *rx,
+	unsigned int *work_done, unsigned int work_to_do)
+{
+	struct net_device *dev = nic->netdev;
+	struct sk_buff *skb = rx->skb;
+	struct rfd *rfd = (struct rfd *)skb->data;
+	u16 rfd_status, actual_size;
+
+	if(unlikely(work_done && *work_done >= work_to_do))
+		return -EAGAIN;
+
+	/* Need to sync before taking a peek at cb_complete bit */
+	pci_dma_sync_single_for_cpu(nic->pdev, rx->dma_addr,
+		sizeof(struct rfd), PCI_DMA_FROMDEVICE);
+	rfd_status = le16_to_cpu(rfd->status);
+
+	DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status);
+
+	/* If data isn't ready, nothing to indicate */
+	if(unlikely(!(rfd_status & cb_complete)))
+		return -ENODATA;
+
+	/* Get actual data size */
+	actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF;
+	if(unlikely(actual_size > RFD_BUF_LEN - sizeof(struct rfd)))
+		actual_size = RFD_BUF_LEN - sizeof(struct rfd);
+
+	/* Get data */
+	pci_unmap_single(nic->pdev, rx->dma_addr,
+		RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
+
+	/* this allows for a fast restart without re-enabling interrupts */
+	if(le16_to_cpu(rfd->command) & cb_el)
+		nic->ru_running = RU_SUSPENDED;
+
+	/* Pull off the RFD and put the actual data (minus eth hdr) */
+	skb_reserve(skb, sizeof(struct rfd));
+	skb_put(skb, actual_size);
+	skb->protocol = eth_type_trans(skb, nic->netdev);
+
+	if(unlikely(!(rfd_status & cb_ok))) {
+		/* Don't indicate if hardware indicates errors */
+		dev_kfree_skb_any(skb);
+	} else if(actual_size > ETH_DATA_LEN + VLAN_ETH_HLEN) {
+		/* Don't indicate oversized frames */
+		nic->rx_over_length_errors++;
+		dev_kfree_skb_any(skb);
+	} else {
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += actual_size;
+		nic->netdev->last_rx = jiffies;
+		netif_receive_skb(skb);
+		if(work_done)
+			(*work_done)++;
+	}
+
+	rx->skb = NULL;
+
+	return 0;
+}
+
+static void e100_rx_clean(struct nic *nic, unsigned int *work_done,
+	unsigned int work_to_do)
+{
+	struct rx *rx;
+	int restart_required = 0;
+	struct rx *rx_to_start = NULL;
+
+	/* are we already rnr? then pay attention!!! this ensures that
+	 * the state machine progression never allows a start with a
+	 * partially cleaned list, avoiding a race between hardware
+	 * and rx_to_clean when in NAPI mode */
+	if(RU_SUSPENDED == nic->ru_running)
+		restart_required = 1;
+
+	/* Indicate newly arrived packets */
+	for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {
+		int err = e100_rx_indicate(nic, rx, work_done, work_to_do);
+		if(-EAGAIN == err) {
+			/* hit quota so have more work to do, restart once
+			 * cleanup is complete */
+			restart_required = 0;
+			break;
+		} else if(-ENODATA == err)
+			break; /* No more to clean */
+	}
+
+	/* save our starting point as the place we'll restart the receiver */
+	if(restart_required)
+		rx_to_start = nic->rx_to_clean;
+
+	/* Alloc new skbs to refill list */
+	for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {
+		if(unlikely(e100_rx_alloc_skb(nic, rx)))
+			break; /* Better luck next time (see watchdog) */
+	}
+
+	if(restart_required) {
+		// ack the rnr?
+		writeb(stat_ack_rnr, &nic->csr->scb.stat_ack);
+		e100_start_receiver(nic, rx_to_start);
+		if(work_done)
+			(*work_done)++;
+	}
+}
+
+static void e100_rx_clean_list(struct nic *nic)
+{
+	struct rx *rx;
+	unsigned int i, count = nic->params.rfds.count;
+
+	nic->ru_running = RU_UNINITIALIZED;
+
+	if(nic->rxs) {
+		for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
+			if(rx->skb) {
+				pci_unmap_single(nic->pdev, rx->dma_addr,
+					RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
+				dev_kfree_skb(rx->skb);
+			}
+		}
+		kfree(nic->rxs);
+		nic->rxs = NULL;
+	}
+
+	nic->rx_to_use = nic->rx_to_clean = NULL;
+}
+
+static int e100_rx_alloc_list(struct nic *nic)
+{
+	struct rx *rx;
+	unsigned int i, count = nic->params.rfds.count;
+
+	nic->rx_to_use = nic->rx_to_clean = NULL;
+	nic->ru_running = RU_UNINITIALIZED;
+
+	if(!(nic->rxs = kcalloc(count, sizeof(struct rx), GFP_ATOMIC)))
+		return -ENOMEM;
+
+	for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
+		rx->next = (i + 1 < count) ? rx + 1 : nic->rxs;
+		rx->prev = (i == 0) ? nic->rxs + count - 1 : rx - 1;
+		if(e100_rx_alloc_skb(nic, rx)) {
+			e100_rx_clean_list(nic);
+			return -ENOMEM;
+		}
+	}
+
+	nic->rx_to_use = nic->rx_to_clean = nic->rxs;
+	nic->ru_running = RU_SUSPENDED;
+
+	return 0;
+}
+
+static irqreturn_t e100_intr(int irq, void *dev_id)
+{
+	struct net_device *netdev = dev_id;
+	struct nic *nic = netdev_priv(netdev);
+	u8 stat_ack = ioread8(&nic->csr->scb.stat_ack);
+
+	DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack);
+
+	if(stat_ack == stat_ack_not_ours ||	/* Not our interrupt */
+	   stat_ack == stat_ack_not_present)	/* Hardware is ejected */
+		return IRQ_NONE;
+
+	/* Ack interrupt(s) */
+	iowrite8(stat_ack, &nic->csr->scb.stat_ack);
+
+	/* We hit Receive No Resource (RNR); restart RU after cleaning */
+	if(stat_ack & stat_ack_rnr)
+		nic->ru_running = RU_SUSPENDED;
+
+	if(likely(netif_rx_schedule_prep(netdev, &nic->napi))) {
+		e100_disable_irq(nic);
+		__netif_rx_schedule(netdev, &nic->napi);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int e100_poll(struct napi_struct *napi, int budget)
+{
+	struct nic *nic = container_of(napi, struct nic, napi);
+	struct net_device *netdev = nic->netdev;
+	unsigned int work_done = 0;
+
+	e100_rx_clean(nic, &work_done, budget);
+	e100_tx_clean(nic);
+
+	/* If budget not fully consumed, exit the polling mode */
+	if (work_done < budget) {
+		netif_rx_complete(netdev, napi);
+		e100_enable_irq(nic);
+	}
+
+	return work_done;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void e100_netpoll(struct net_device *netdev)
+{
+	struct nic *nic = netdev_priv(netdev);
+
+	e100_disable_irq(nic);
+	e100_intr(nic->pdev->irq, netdev);
+	e100_tx_clean(nic);
+	e100_enable_irq(nic);
+}
+#endif
+
+static int e100_set_mac_address(struct net_device *netdev, void *p)
+{
+	struct nic *nic = netdev_priv(netdev);
+	struct sockaddr *addr = p;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+	e100_exec_cb(nic, NULL, e100_setup_iaaddr);
+
+	return 0;
+}
+
+static int e100_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	if(new_mtu < ETH_ZLEN || new_mtu > ETH_DATA_LEN)
+		return -EINVAL;
+	netdev->mtu = new_mtu;
+	return 0;
+}
+
+static int e100_asf(struct nic *nic)
+{
+	/* ASF can be enabled from eeprom */
+	return((nic->pdev->device >= 0x1050) && (nic->pdev->device <= 0x1057) &&
+	   (nic->eeprom[eeprom_config_asf] & eeprom_asf) &&
+	   !(nic->eeprom[eeprom_config_asf] & eeprom_gcl) &&
+	   ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE));
+}
+
+static int e100_up(struct nic *nic)
+{
+	int err;
+
+	if((err = e100_rx_alloc_list(nic)))
+		return err;
+	if((err = e100_alloc_cbs(nic)))
+		goto err_rx_clean_list;
+	if((err = e100_hw_init(nic)))
+		goto err_clean_cbs;
+	e100_set_multicast_list(nic->netdev);
+	e100_start_receiver(nic, NULL);
+	mod_timer(&nic->watchdog, jiffies);
+	if((err = request_irq(nic->pdev->irq, e100_intr, IRQF_SHARED,
+		nic->netdev->name, nic->netdev)))
+		goto err_no_irq;
+	netif_wake_queue(nic->netdev);
+	napi_enable(&nic->napi);
+	/* enable ints _after_ enabling poll, preventing a race between
+	 * disable ints+schedule */
+	e100_enable_irq(nic);
+	return 0;
+
+err_no_irq:
+	del_timer_sync(&nic->watchdog);
+err_clean_cbs:
+	e100_clean_cbs(nic);
+err_rx_clean_list:
+	e100_rx_clean_list(nic);
+	return err;
+}
+
+static void e100_down(struct nic *nic)
+{
+	/* wait here for poll to complete */
+	napi_disable(&nic->napi);
+	netif_stop_queue(nic->netdev);
+	e100_hw_reset(nic);
+	free_irq(nic->pdev->irq, nic->netdev);
+	del_timer_sync(&nic->watchdog);
+	netif_carrier_off(nic->netdev);
+	e100_clean_cbs(nic);
+	e100_rx_clean_list(nic);
+}
+
+static void e100_tx_timeout(struct net_device *netdev)
+{
+	struct nic *nic = netdev_priv(netdev);
+
+	/* Reset outside of interrupt context, to avoid request_irq
+	 * in interrupt context */
+	schedule_work(&nic->tx_timeout_task);
+}
+
+static void e100_tx_timeout_task(struct work_struct *work)
+{
+	struct nic *nic = container_of(work, struct nic, tx_timeout_task);
+	struct net_device *netdev = nic->netdev;
+
+	DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n",
+		ioread8(&nic->csr->scb.status));
+	e100_down(netdev_priv(netdev));
+	e100_up(netdev_priv(netdev));
+}
+
+static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
+{
+	int err;
+	struct sk_buff *skb;
+
+	/* Use driver resources to perform internal MAC or PHY
+	 * loopback test.  A single packet is prepared and transmitted
+	 * in loopback mode, and the test passes if the received
+	 * packet compares byte-for-byte to the transmitted packet. */
+
+	if((err = e100_rx_alloc_list(nic)))
+		return err;
+	if((err = e100_alloc_cbs(nic)))
+		goto err_clean_rx;
+
+	/* ICH PHY loopback is broken so do MAC loopback instead */
+	if(nic->flags & ich && loopback_mode == lb_phy)
+		loopback_mode = lb_mac;
+
+	nic->loopback = loopback_mode;
+	if((err = e100_hw_init(nic)))
+		goto err_loopback_none;
+
+	if(loopback_mode == lb_phy)
+		mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR,
+			BMCR_LOOPBACK);
+
+	e100_start_receiver(nic, NULL);
+
+	if(!(skb = netdev_alloc_skb(nic->netdev, ETH_DATA_LEN))) {
+		err = -ENOMEM;
+		goto err_loopback_none;
+	}
+	skb_put(skb, ETH_DATA_LEN);
+	memset(skb->data, 0xFF, ETH_DATA_LEN);
+	e100_xmit_frame(skb, nic->netdev);
+
+	msleep(10);
+
+	pci_dma_sync_single_for_cpu(nic->pdev, nic->rx_to_clean->dma_addr,
+			RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
+
+	if(memcmp(nic->rx_to_clean->skb->data + sizeof(struct rfd),
+	   skb->data, ETH_DATA_LEN))
+		err = -EAGAIN;
+
+err_loopback_none:
+	mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR, 0);
+	nic->loopback = lb_none;
+	e100_clean_cbs(nic);
+	e100_hw_reset(nic);
+err_clean_rx:
+	e100_rx_clean_list(nic);
+	return err;
+}
+
+#define MII_LED_CONTROL	0x1B
+static void e100_blink_led(unsigned long data)
+{
+	struct nic *nic = (struct nic *)data;
+	enum led_state {
+		led_on     = 0x01,
+		led_off    = 0x04,
+		led_on_559 = 0x05,
+		led_on_557 = 0x07,
+	};
+
+	nic->leds = (nic->leds & led_on) ? led_off :
+		(nic->mac < mac_82559_D101M) ? led_on_557 : led_on_559;
+	mdio_write(nic->netdev, nic->mii.phy_id, MII_LED_CONTROL, nic->leds);
+	mod_timer(&nic->blink_timer, jiffies + HZ / 4);
+}
+
+static int e100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
+{
+	struct nic *nic = netdev_priv(netdev);
+	return mii_ethtool_gset(&nic->mii, cmd);
+}
+
+static int e100_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
+{
+	struct nic *nic = netdev_priv(netdev);
+	int err;
+
+	mdio_write(netdev, nic->mii.phy_id, MII_BMCR, BMCR_RESET);
+	err = mii_ethtool_sset(&nic->mii, cmd);
+	e100_exec_cb(nic, NULL, e100_configure);
+
+	return err;
+}
+
+static void e100_get_drvinfo(struct net_device *netdev,
+	struct ethtool_drvinfo *info)
+{
+	struct nic *nic = netdev_priv(netdev);
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->fw_version, "N/A");
+	strcpy(info->bus_info, pci_name(nic->pdev));
+}
+
+#define E100_PHY_REGS 0x1C
+static int e100_get_regs_len(struct net_device *netdev)
+{
+	struct nic *nic = netdev_priv(netdev);
+	return 1 + E100_PHY_REGS + sizeof(nic->mem->dump_buf);
+}
+
+static void e100_get_regs(struct net_device *netdev,
+	struct ethtool_regs *regs, void *p)
+{
+	struct nic *nic = netdev_priv(netdev);
+	u32 *buff = p;
+	int i;
+
+	regs->version = (1 << 24) | nic->pdev->revision;
+	buff[0] = ioread8(&nic->csr->scb.cmd_hi) << 24 |
+		ioread8(&nic->csr->scb.cmd_lo) << 16 |
+		ioread16(&nic->csr->scb.status);
+	for(i = E100_PHY_REGS; i >= 0; i--)
+		buff[1 + E100_PHY_REGS - i] =
+			mdio_read(netdev, nic->mii.phy_id, i);
+	memset(nic->mem->dump_buf, 0, sizeof(nic->mem->dump_buf));
+	e100_exec_cb(nic, NULL, e100_dump);
+	msleep(10);
+	memcpy(&buff[2 + E100_PHY_REGS], nic->mem->dump_buf,
+		sizeof(nic->mem->dump_buf));
+}
+
+static void e100_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+	struct nic *nic = netdev_priv(netdev);
+	wol->supported = (nic->mac >= mac_82558_D101_A4) ?  WAKE_MAGIC : 0;
+	wol->wolopts = (nic->flags & wol_magic) ? WAKE_MAGIC : 0;
+}
+
+static int e100_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+	struct nic *nic = netdev_priv(netdev);
+
+	if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0)
+		return -EOPNOTSUPP;
+
+	if(wol->wolopts)
+		nic->flags |= wol_magic;
+	else
+		nic->flags &= ~wol_magic;
+
+	e100_exec_cb(nic, NULL, e100_configure);
+
+	return 0;
+}
+
+static u32 e100_get_msglevel(struct net_device *netdev)
+{
+	struct nic *nic = netdev_priv(netdev);
+	return nic->msg_enable;
+}
+
+static void e100_set_msglevel(struct net_device *netdev, u32 value)
+{
+	struct nic *nic = netdev_priv(netdev);
+	nic->msg_enable = value;
+}
+
+static int e100_nway_reset(struct net_device *netdev)
+{
+	struct nic *nic = netdev_priv(netdev);
+	return mii_nway_restart(&nic->mii);
+}
+
+static u32 e100_get_link(struct net_device *netdev)
+{
+	struct nic *nic = netdev_priv(netdev);
+	return mii_link_ok(&nic->mii);
+}
+
+static int e100_get_eeprom_len(struct net_device *netdev)
+{
+	struct nic *nic = netdev_priv(netdev);
+	return nic->eeprom_wc << 1;
+}
+
+#define E100_EEPROM_MAGIC	0x1234
+static int e100_get_eeprom(struct net_device *netdev,
+	struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+	struct nic *nic = netdev_priv(netdev);
+
+	eeprom->magic = E100_EEPROM_MAGIC;
+	memcpy(bytes, &((u8 *)nic->eeprom)[eeprom->offset], eeprom->len);
+
+	return 0;
+}
+
+static int e100_set_eeprom(struct net_device *netdev,
+	struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+	struct nic *nic = netdev_priv(netdev);
+
+	if(eeprom->magic != E100_EEPROM_MAGIC)
+		return -EINVAL;
+
+	memcpy(&((u8 *)nic->eeprom)[eeprom->offset], bytes, eeprom->len);
+
+	return e100_eeprom_save(nic, eeprom->offset >> 1,
+		(eeprom->len >> 1) + 1);
+}
+
+static void e100_get_ringparam(struct net_device *netdev,
+	struct ethtool_ringparam *ring)
+{
+	struct nic *nic = netdev_priv(netdev);
+	struct param_range *rfds = &nic->params.rfds;
+	struct param_range *cbs = &nic->params.cbs;
+
+	ring->rx_max_pending = rfds->max;
+	ring->tx_max_pending = cbs->max;
+	ring->rx_mini_max_pending = 0;
+	ring->rx_jumbo_max_pending = 0;
+	ring->rx_pending = rfds->count;
+	ring->tx_pending = cbs->count;
+	ring->rx_mini_pending = 0;
+	ring->rx_jumbo_pending = 0;
+}
+
+static int e100_set_ringparam(struct net_device *netdev,
+	struct ethtool_ringparam *ring)
+{
+	struct nic *nic = netdev_priv(netdev);
+	struct param_range *rfds = &nic->params.rfds;
+	struct param_range *cbs = &nic->params.cbs;
+
+	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+		return -EINVAL;
+
+	if(netif_running(netdev))
+		e100_down(nic);
+	rfds->count = max(ring->rx_pending, rfds->min);
+	rfds->count = min(rfds->count, rfds->max);
+	cbs->count = max(ring->tx_pending, cbs->min);
+	cbs->count = min(cbs->count, cbs->max);
+	DPRINTK(DRV, INFO, "Ring Param settings: rx: %d, tx %d\n",
+	        rfds->count, cbs->count);
+	if(netif_running(netdev))
+		e100_up(nic);
+
+	return 0;
+}
+
+static const char e100_gstrings_test[][ETH_GSTRING_LEN] = {
+	"Link test     (on/offline)",
+	"Eeprom test   (on/offline)",
+	"Self test        (offline)",
+	"Mac loopback     (offline)",
+	"Phy loopback     (offline)",
+};
+#define E100_TEST_LEN	sizeof(e100_gstrings_test) / ETH_GSTRING_LEN
+
+static void e100_diag_test(struct net_device *netdev,
+	struct ethtool_test *test, u64 *data)
+{
+	struct ethtool_cmd cmd;
+	struct nic *nic = netdev_priv(netdev);
+	int i, err;
+
+	memset(data, 0, E100_TEST_LEN * sizeof(u64));
+	data[0] = !mii_link_ok(&nic->mii);
+	data[1] = e100_eeprom_load(nic);
+	if(test->flags & ETH_TEST_FL_OFFLINE) {
+
+		/* save speed, duplex & autoneg settings */
+		err = mii_ethtool_gset(&nic->mii, &cmd);
+
+		if(netif_running(netdev))
+			e100_down(nic);
+		data[2] = e100_self_test(nic);
+		data[3] = e100_loopback_test(nic, lb_mac);
+		data[4] = e100_loopback_test(nic, lb_phy);
+
+		/* restore speed, duplex & autoneg settings */
+		err = mii_ethtool_sset(&nic->mii, &cmd);
+
+		if(netif_running(netdev))
+			e100_up(nic);
+	}
+	for(i = 0; i < E100_TEST_LEN; i++)
+		test->flags |= data[i] ? ETH_TEST_FL_FAILED : 0;
+
+	msleep_interruptible(4 * 1000);
+}
+
+static int e100_phys_id(struct net_device *netdev, u32 data)
+{
+	struct nic *nic = netdev_priv(netdev);
+
+	if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
+		data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
+	mod_timer(&nic->blink_timer, jiffies);
+	msleep_interruptible(data * 1000);
+	del_timer_sync(&nic->blink_timer);
+	mdio_write(netdev, nic->mii.phy_id, MII_LED_CONTROL, 0);
+
+	return 0;
+}
+
+static const char e100_gstrings_stats[][ETH_GSTRING_LEN] = {
+	"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
+	"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
+	"rx_length_errors", "rx_over_errors", "rx_crc_errors",
+	"rx_frame_errors", "rx_fifo_errors", "rx_missed_errors",
+	"tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
+	"tx_heartbeat_errors", "tx_window_errors",
+	/* device-specific stats */
+	"tx_deferred", "tx_single_collisions", "tx_multi_collisions",
+	"tx_flow_control_pause", "rx_flow_control_pause",
+	"rx_flow_control_unsupported", "tx_tco_packets", "rx_tco_packets",
+};
+#define E100_NET_STATS_LEN	21
+#define E100_STATS_LEN	sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN
+
+static int e100_get_sset_count(struct net_device *netdev, int sset)
+{
+	switch (sset) {
+	case ETH_SS_TEST:
+		return E100_TEST_LEN;
+	case ETH_SS_STATS:
+		return E100_STATS_LEN;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static void e100_get_ethtool_stats(struct net_device *netdev,
+	struct ethtool_stats *stats, u64 *data)
+{
+	struct nic *nic = netdev_priv(netdev);
+	int i;
+
+	for(i = 0; i < E100_NET_STATS_LEN; i++)
+		data[i] = ((unsigned long *)&netdev->stats)[i];
+
+	data[i++] = nic->tx_deferred;
+	data[i++] = nic->tx_single_collisions;
+	data[i++] = nic->tx_multiple_collisions;
+	data[i++] = nic->tx_fc_pause;
+	data[i++] = nic->rx_fc_pause;
+	data[i++] = nic->rx_fc_unsupported;
+	data[i++] = nic->tx_tco_frames;
+	data[i++] = nic->rx_tco_frames;
+}
+
+static void e100_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
+{
+	switch(stringset) {
+	case ETH_SS_TEST:
+		memcpy(data, *e100_gstrings_test, sizeof(e100_gstrings_test));
+		break;
+	case ETH_SS_STATS:
+		memcpy(data, *e100_gstrings_stats, sizeof(e100_gstrings_stats));
+		break;
+	}
+}
+
+static const struct ethtool_ops e100_ethtool_ops = {
+	.get_settings		= e100_get_settings,
+	.set_settings		= e100_set_settings,
+	.get_drvinfo		= e100_get_drvinfo,
+	.get_regs_len		= e100_get_regs_len,
+	.get_regs		= e100_get_regs,
+	.get_wol		= e100_get_wol,
+	.set_wol		= e100_set_wol,
+	.get_msglevel		= e100_get_msglevel,
+	.set_msglevel		= e100_set_msglevel,
+	.nway_reset		= e100_nway_reset,
+	.get_link		= e100_get_link,
+	.get_eeprom_len		= e100_get_eeprom_len,
+	.get_eeprom		= e100_get_eeprom,
+	.set_eeprom		= e100_set_eeprom,
+	.get_ringparam		= e100_get_ringparam,
+	.set_ringparam		= e100_set_ringparam,
+	.self_test		= e100_diag_test,
+	.get_strings		= e100_get_strings,
+	.phys_id		= e100_phys_id,
+	.get_ethtool_stats	= e100_get_ethtool_stats,
+	.get_sset_count		= e100_get_sset_count,
+};
+
+static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+	struct nic *nic = netdev_priv(netdev);
+
+	return generic_mii_ioctl(&nic->mii, if_mii(ifr), cmd, NULL);
+}
+
+static int e100_alloc(struct nic *nic)
+{
+	nic->mem = pci_alloc_consistent(nic->pdev, sizeof(struct mem),
+		&nic->dma_addr);
+	return nic->mem ? 0 : -ENOMEM;
+}
+
+static void e100_free(struct nic *nic)
+{
+	if(nic->mem) {
+		pci_free_consistent(nic->pdev, sizeof(struct mem),
+			nic->mem, nic->dma_addr);
+		nic->mem = NULL;
+	}
+}
+
+static int e100_open(struct net_device *netdev)
+{
+	struct nic *nic = netdev_priv(netdev);
+	int err = 0;
+
+	netif_carrier_off(netdev);
+	if((err = e100_up(nic)))
+		DPRINTK(IFUP, ERR, "Cannot open interface, aborting.\n");
+	return err;
+}
+
+static int e100_close(struct net_device *netdev)
+{
+	e100_down(netdev_priv(netdev));
+	return 0;
+}
+
+static int __devinit e100_probe(struct pci_dev *pdev,
+	const struct pci_device_id *ent)
+{
+	struct net_device *netdev;
+	struct nic *nic;
+	int err;
+	DECLARE_MAC_BUF(mac);
+
+	if(!(netdev = alloc_etherdev(sizeof(struct nic)))) {
+		if(((1 << debug) - 1) & NETIF_MSG_PROBE)
+			printk(KERN_ERR PFX "Etherdev alloc failed, abort.\n");
+		return -ENOMEM;
+	}
+
+	netdev->open = e100_open;
+	netdev->stop = e100_close;
+	netdev->hard_start_xmit = e100_xmit_frame;
+	netdev->set_multicast_list = e100_set_multicast_list;
+	netdev->set_mac_address = e100_set_mac_address;
+	netdev->change_mtu = e100_change_mtu;
+	netdev->do_ioctl = e100_do_ioctl;
+	SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops);
+	netdev->tx_timeout = e100_tx_timeout;
+	netdev->watchdog_timeo = E100_WATCHDOG_PERIOD;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	netdev->poll_controller = e100_netpoll;
+#endif
+	strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
+
+	nic = netdev_priv(netdev);
+	netif_napi_add(netdev, &nic->napi, e100_poll, E100_NAPI_WEIGHT);
+	nic->netdev = netdev;
+	nic->pdev = pdev;
+	nic->msg_enable = (1 << debug) - 1;
+	pci_set_drvdata(pdev, netdev);
+
+	if((err = pci_enable_device(pdev))) {
+		DPRINTK(PROBE, ERR, "Cannot enable PCI device, aborting.\n");
+		goto err_out_free_dev;
+	}
+
+	if(!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+		DPRINTK(PROBE, ERR, "Cannot find proper PCI device "
+			"base address, aborting.\n");
+		err = -ENODEV;
+		goto err_out_disable_pdev;
+	}
+
+	if((err = pci_request_regions(pdev, DRV_NAME))) {
+		DPRINTK(PROBE, ERR, "Cannot obtain PCI resources, aborting.\n");
+		goto err_out_disable_pdev;
+	}
+
+	if((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) {
+		DPRINTK(PROBE, ERR, "No usable DMA configuration, aborting.\n");
+		goto err_out_free_res;
+	}
+
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+
+	if (use_io)
+		DPRINTK(PROBE, INFO, "using i/o access mode\n");
+
+	nic->csr = pci_iomap(pdev, (use_io ? 1 : 0), sizeof(struct csr));
+	if(!nic->csr) {
+		DPRINTK(PROBE, ERR, "Cannot map device registers, aborting.\n");
+		err = -ENOMEM;
+		goto err_out_free_res;
+	}
+
+	if(ent->driver_data)
+		nic->flags |= ich;
+	else
+		nic->flags &= ~ich;
+
+	e100_get_defaults(nic);
+
+	/* locks must be initialized before calling hw_reset */
+	spin_lock_init(&nic->cb_lock);
+	spin_lock_init(&nic->cmd_lock);
+	spin_lock_init(&nic->mdio_lock);
+
+	/* Reset the device before pci_set_master() in case device is in some
+	 * funky state and has an interrupt pending - hint: we don't have the
+	 * interrupt handler registered yet. */
+	e100_hw_reset(nic);
+
+	pci_set_master(pdev);
+
+	init_timer(&nic->watchdog);
+	nic->watchdog.function = e100_watchdog;
+	nic->watchdog.data = (unsigned long)nic;
+	init_timer(&nic->blink_timer);
+	nic->blink_timer.function = e100_blink_led;
+	nic->blink_timer.data = (unsigned long)nic;
+
+	INIT_WORK(&nic->tx_timeout_task, e100_tx_timeout_task);
+
+	if((err = e100_alloc(nic))) {
+		DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	if((err = e100_eeprom_load(nic)))
+		goto err_out_free;
+
+	e100_phy_init(nic);
+
+	memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
+	memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN);
+	if (!is_valid_ether_addr(netdev->perm_addr)) {
+		if (!eeprom_bad_csum_allow) {
+			DPRINTK(PROBE, ERR, "Invalid MAC address from "
+			        "EEPROM, aborting.\n");
+			err = -EAGAIN;
+			goto err_out_free;
+		} else {
+			DPRINTK(PROBE, ERR, "Invalid MAC address from EEPROM, "
+			        "you MUST configure one.\n");
+		}
+	}
+
+	/* Wol magic packet can be enabled from eeprom */
+	if((nic->mac >= mac_82558_D101_A4) &&
+	   (nic->eeprom[eeprom_id] & eeprom_id_wol))
+		nic->flags |= wol_magic;
+
+	/* ack any pending wake events, disable PME */
+	err = pci_enable_wake(pdev, 0, 0);
+	if (err)
+		DPRINTK(PROBE, ERR, "Error clearing wake event\n");
+
+	strcpy(netdev->name, "eth%d");
+	if((err = register_netdev(netdev))) {
+		DPRINTK(PROBE, ERR, "Cannot register net device, aborting.\n");
+		goto err_out_free;
+	}
+
+	DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %s\n",
+		(unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0),
+		pdev->irq, print_mac(mac, netdev->dev_addr));
+
+	return 0;
+
+err_out_free:
+	e100_free(nic);
+err_out_iounmap:
+	pci_iounmap(pdev, nic->csr);
+err_out_free_res:
+	pci_release_regions(pdev);
+err_out_disable_pdev:
+	pci_disable_device(pdev);
+err_out_free_dev:
+	pci_set_drvdata(pdev, NULL);
+	free_netdev(netdev);
+	return err;
+}
+
+static void __devexit e100_remove(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+
+	if(netdev) {
+		struct nic *nic = netdev_priv(netdev);
+		unregister_netdev(netdev);
+		e100_free(nic);
+		iounmap(nic->csr);
+		free_netdev(netdev);
+		pci_release_regions(pdev);
+		pci_disable_device(pdev);
+		pci_set_drvdata(pdev, NULL);
+	}
+}
+
+#ifdef CONFIG_PM
+static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct nic *nic = netdev_priv(netdev);
+
+	if (netif_running(netdev))
+		napi_disable(&nic->napi);
+	del_timer_sync(&nic->watchdog);
+	netif_carrier_off(nic->netdev);
+	netif_device_detach(netdev);
+
+	pci_save_state(pdev);
+
+	if ((nic->flags & wol_magic) | e100_asf(nic)) {
+		pci_enable_wake(pdev, PCI_D3hot, 1);
+		pci_enable_wake(pdev, PCI_D3cold, 1);
+	} else {
+		pci_enable_wake(pdev, PCI_D3hot, 0);
+		pci_enable_wake(pdev, PCI_D3cold, 0);
+	}
+
+	free_irq(pdev->irq, netdev);
+
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, PCI_D3hot);
+
+	return 0;
+}
+
+static int e100_resume(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct nic *nic = netdev_priv(netdev);
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	/* ack any pending wake events, disable PME */
+	pci_enable_wake(pdev, 0, 0);
+
+	netif_device_attach(netdev);
+	if (netif_running(netdev))
+		e100_up(nic);
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static void e100_shutdown(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct nic *nic = netdev_priv(netdev);
+
+	if (netif_running(netdev))
+		napi_disable(&nic->napi);
+	del_timer_sync(&nic->watchdog);
+	netif_carrier_off(nic->netdev);
+
+	if ((nic->flags & wol_magic) | e100_asf(nic)) {
+		pci_enable_wake(pdev, PCI_D3hot, 1);
+		pci_enable_wake(pdev, PCI_D3cold, 1);
+	} else {
+		pci_enable_wake(pdev, PCI_D3hot, 0);
+		pci_enable_wake(pdev, PCI_D3cold, 0);
+	}
+
+	free_irq(pdev->irq, netdev);
+
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, PCI_D3hot);
+}
+
+/* ------------------ PCI Error Recovery infrastructure  -------------- */
+/**
+ * e100_io_error_detected - called when PCI error is detected.
+ * @pdev: Pointer to PCI device
+ * @state: The current pci conneection state
+ */
+static pci_ers_result_t e100_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct nic *nic = netdev_priv(netdev);
+
+	/* Similar to calling e100_down(), but avoids adpater I/O. */
+	netdev->stop(netdev);
+
+	/* Detach; put netif into state similar to hotplug unplug. */
+	napi_enable(&nic->napi);
+	netif_device_detach(netdev);
+	pci_disable_device(pdev);
+
+	/* Request a slot reset. */
+	return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * e100_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch.
+ */
+static pci_ers_result_t e100_io_slot_reset(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct nic *nic = netdev_priv(netdev);
+
+	if (pci_enable_device(pdev)) {
+		printk(KERN_ERR "e100: Cannot re-enable PCI device after reset.\n");
+		return PCI_ERS_RESULT_DISCONNECT;
+	}
+	pci_set_master(pdev);
+
+	/* Only one device per card can do a reset */
+	if (0 != PCI_FUNC(pdev->devfn))
+		return PCI_ERS_RESULT_RECOVERED;
+	e100_hw_reset(nic);
+	e100_phy_init(nic);
+
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * e100_io_resume - resume normal operations
+ * @pdev: Pointer to PCI device
+ *
+ * Resume normal operations after an error recovery
+ * sequence has been completed.
+ */
+static void e100_io_resume(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct nic *nic = netdev_priv(netdev);
+
+	/* ack any pending wake events, disable PME */
+	pci_enable_wake(pdev, 0, 0);
+
+	netif_device_attach(netdev);
+	if (netif_running(netdev)) {
+		e100_open(netdev);
+		mod_timer(&nic->watchdog, jiffies);
+	}
+}
+
+static struct pci_error_handlers e100_err_handler = {
+	.error_detected = e100_io_error_detected,
+	.slot_reset = e100_io_slot_reset,
+	.resume = e100_io_resume,
+};
+
+static struct pci_driver e100_driver = {
+	.name =         DRV_NAME,
+	.id_table =     e100_id_table,
+	.probe =        e100_probe,
+	.remove =       __devexit_p(e100_remove),
+#ifdef CONFIG_PM
+	/* Power Management hooks */
+	.suspend =      e100_suspend,
+	.resume =       e100_resume,
+#endif
+	.shutdown =     e100_shutdown,
+	.err_handler = &e100_err_handler,
+};
+
+static int __init e100_init_module(void)
+{
+	if(((1 << debug) - 1) & NETIF_MSG_DRV) {
+		printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
+		printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT);
+	}
+	return pci_register_driver(&e100_driver);
+}
+
+static void __exit e100_cleanup_module(void)
+{
+	pci_unregister_driver(&e100_driver);
+}
+
+module_init(e100_init_module);
+module_exit(e100_cleanup_module);
diff -Nurb linux-2.6.24.3/drivers/net/Kconfig linux-2.6.24.3-cobalt3-tw/drivers/net/Kconfig
--- linux-2.6.24.3/drivers/net/Kconfig	2008-02-25 16:20:20.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/net/Kconfig	2008-03-02 14:55:48.000000000 -0800
@@ -1440,6 +1440,16 @@
 	  To compile this driver as a module, choose M here. The module
 	  will be called e100.
 
+config E100_IGNORE_CSUM
+	bool "Ignore bad EEPROM checksum"
+	depends on E100 && EXPERIMENTAL && !CLEAN_COMPILE
+	help
+	  This option tells the e100 driver to ignore bad EEPROM checksums.
+	  Usually this is a bad idea, as an incorrect checksum can indicate a
+	  serious issue with the network card.
+	  
+	  If unsure, say N.
+
 config LNE390
 	tristate "Mylex EISA LNE390A/B support (EXPERIMENTAL)"
 	depends on NET_PCI && EISA && EXPERIMENTAL
diff -Nurb linux-2.6.24.3/drivers/net/Kconfig.orig linux-2.6.24.3-cobalt3-tw/drivers/net/Kconfig.orig
--- linux-2.6.24.3/drivers/net/Kconfig.orig	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.24.3-cobalt3-tw/drivers/net/Kconfig.orig	2008-02-25 16:20:20.000000000 -0800
@@ -0,0 +1,3069 @@
+
+#
+# Network device configuration
+#
+
+menuconfig NETDEVICES
+	default y if UML
+	depends on NET
+	bool "Network device support"
+	---help---
+	  You can say N here if you don't intend to connect your Linux box to
+	  any other computer at all.
+
+	  You'll have to say Y if your computer contains a network card that
+	  you want to use under Linux. If you are going to run SLIP or PPP over
+	  telephone line or null modem cable you need say Y here. Connecting
+	  two machines with parallel ports using PLIP needs this, as well as
+	  AX.25/KISS for sending Internet traffic over amateur radio links.
+
+	  See also "The Linux Network Administrator's Guide" by Olaf Kirch and
+	  Terry Dawson. Available at <http://www.tldp.org/guides.html>.
+
+	  If unsure, say Y.
+
+# All the following symbols are dependent on NETDEVICES - do not repeat
+# that for each of the symbols.
+if NETDEVICES
+
+config NETDEVICES_MULTIQUEUE
+	bool "Netdevice multiple hardware queue support"
+	---help---
+	  Say Y here if you want to allow the network stack to use multiple
+	  hardware TX queues on an ethernet device.
+
+	  Most people will say N here.
+
+config IFB
+	tristate "Intermediate Functional Block support"
+	depends on NET_CLS_ACT
+	---help---
+	  This is an intermediate driver that allows sharing of
+	  resources.
+	  To compile this driver as a module, choose M here: the module
+	  will be called ifb.  If you want to use more than one ifb
+	  device at a time, you need to compile this driver as a module.
+	  Instead of 'ifb', the devices will then be called 'ifb0',
+	  'ifb1' etc.
+	  Look at the iproute2 documentation directory for usage etc
+
+config DUMMY
+	tristate "Dummy net driver support"
+	---help---
+	  This is essentially a bit-bucket device (i.e. traffic you send to
+	  this device is consigned into oblivion) with a configurable IP
+	  address. It is most commonly used in order to make your currently
+	  inactive SLIP address seem like a real address for local programs.
+	  If you use SLIP or PPP, you might want to say Y here. Since this
+	  thing often comes in handy, the default is Y. It won't enlarge your
+	  kernel either. What a deal. Read about it in the Network
+	  Administrator's Guide, available from
+	  <http://www.tldp.org/docs.html#guide>.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called dummy.  If you want to use more than one dummy
+	  device at a time, you need to compile this driver as a module.
+	  Instead of 'dummy', the devices will then be called 'dummy0',
+	  'dummy1' etc.
+
+config BONDING
+	tristate "Bonding driver support"
+	depends on INET
+	---help---
+	  Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet
+	  Channels together. This is called 'Etherchannel' by Cisco,
+	  'Trunking' by Sun, 802.3ad by the IEEE, and 'Bonding' in Linux.
+
+	  The driver supports multiple bonding modes to allow for both high
+	  performance and high availability operation.
+
+	  Refer to <file:Documentation/networking/bonding.txt> for more
+	  information.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called bonding.
+
+config MACVLAN
+	tristate "MAC-VLAN support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	---help---
+	  This allows one to create virtual interfaces that map packets to
+	  or from specific MAC addresses to a particular interface.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called macvlan.
+
+config EQUALIZER
+	tristate "EQL (serial line load balancing) support"
+	---help---
+	  If you have two serial connections to some other computer (this
+	  usually requires two modems and two telephone lines) and you use
+	  SLIP (the protocol for sending Internet traffic over telephone
+	  lines) or PPP (a better SLIP) on them, you can make them behave like
+	  one double speed connection using this driver.  Naturally, this has
+	  to be supported at the other end as well, either with a similar EQL
+	  Linux driver or with a Livingston Portmaster 2e.
+
+	  Say Y if you want this and read
+	  <file:Documentation/networking/eql.txt>.  You may also want to read
+	  section 6.2 of the NET-3-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called eql.  If unsure, say N.
+
+config TUN
+	tristate "Universal TUN/TAP device driver support"
+	select CRC32
+	---help---
+	  TUN/TAP provides packet reception and transmission for user space
+	  programs.  It can be viewed as a simple Point-to-Point or Ethernet
+	  device, which instead of receiving packets from a physical media,
+	  receives them from user space program and instead of sending packets
+	  via physical media writes them to the user space program.
+
+	  When a program opens /dev/net/tun, driver creates and registers
+	  corresponding net device tunX or tapX.  After a program closed above
+	  devices, driver will automatically delete tunXX or tapXX device and
+	  all routes corresponding to it.
+
+	  Please read <file:Documentation/networking/tuntap.txt> for more
+	  information.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called tun.
+
+	  If you don't know what to use this for, you don't need it.
+
+config VETH
+	tristate "Virtual ethernet pair device"
+	---help---
+	  This device is a local ethernet tunnel. Devices are created in pairs.
+	  When one end receives the packet it appears on its pair and vice
+	  versa.
+
+config NET_SB1000
+	tristate "General Instruments Surfboard 1000"
+	depends on PNP
+	---help---
+	  This is a driver for the General Instrument (also known as
+	  NextLevel) SURFboard 1000 internal
+	  cable modem. This is an ISA card which is used by a number of cable
+	  TV companies to provide cable modem access. It's a one-way
+	  downstream-only cable modem, meaning that your upstream net link is
+	  provided by your regular phone modem.
+
+	  At present this driver only compiles as a module, so say M here if
+	  you have this card. The module will be called sb1000. Then read
+	  <file:Documentation/networking/README.sb1000> for information on how
+	  to use this module, as it needs special ppp scripts for establishing
+	  a connection. Further documentation and the necessary scripts can be
+	  found at:
+
+	  <http://www.jacksonville.net/~fventuri/>
+	  <http://home.adelphia.net/~siglercm/sb1000.html>
+	  <http://linuxpower.cx/~cable/>
+
+	  If you don't have this card, of course say N.
+
+source "drivers/net/arcnet/Kconfig"
+
+source "drivers/net/phy/Kconfig"
+
+#
+#	Ethernet
+#
+
+menuconfig NET_ETHERNET
+	bool "Ethernet (10 or 100Mbit)"
+	depends on !UML
+	---help---
+	  Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
+	  type of Local Area Network (LAN) in universities and companies.
+
+	  Common varieties of Ethernet are: 10BASE-2 or Thinnet (10 Mbps over
+	  coaxial cable, linking computers in a chain), 10BASE-T or twisted
+	  pair (10 Mbps over twisted pair cable, linking computers to central
+	  hubs), 10BASE-F (10 Mbps over optical fiber links, using hubs),
+	  100BASE-TX (100 Mbps over two twisted pair cables, using hubs),
+	  100BASE-T4 (100 Mbps over 4 standard voice-grade twisted pair
+	  cables, using hubs), 100BASE-FX (100 Mbps over optical fiber links)
+	  [the 100BASE varieties are also known as Fast Ethernet], and Gigabit
+	  Ethernet (1 Gbps over optical fiber or short copper links).
+
+	  If your Linux machine will be connected to an Ethernet and you have
+	  an Ethernet network interface card (NIC) installed in your computer,
+	  say Y here and read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>. You will then also have
+	  to say Y to the driver for your particular NIC.
+
+	  Note that the answer to this question won't directly affect the
+	  kernel: saying N will just cause the configurator to skip all
+	  the questions about Ethernet network cards. If unsure, say N.
+
+if NET_ETHERNET
+
+config MII
+	tristate "Generic Media Independent Interface device support"
+	help
+	  Most ethernet controllers have MII transceiver either as an external
+	  or internal device.  It is safe to say Y or M here even if your
+	  ethernet card lack MII.
+
+config MACB
+	tristate "Atmel MACB support"
+	depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263
+	select PHYLIB
+	help
+	  The Atmel MACB ethernet interface is found on many AT32 and AT91
+	  parts. Say Y to include support for the MACB chip.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called macb.
+
+source "drivers/net/arm/Kconfig"
+
+config AX88796
+	tristate "ASIX AX88796 NE2000 clone support"
+	depends on ARM || MIPS || SUPERH
+	select CRC32
+	select MII
+	help
+	  AX88796 driver, using platform bus to provide
+	  chip detection and resources
+
+config AX88796_93CX6
+	bool "ASIX AX88796 external 93CX6 eeprom support"
+	depends on AX88796
+	select EEPROM_93CX6
+	help
+	  Select this if your platform comes with an external 93CX6 eeprom.
+
+config MACE
+	tristate "MACE (Power Mac ethernet) support"
+	depends on PPC_PMAC && PPC32
+	select CRC32
+	help
+	  Power Macintoshes and clones with Ethernet built-in on the
+	  motherboard will usually use a MACE (Medium Access Control for
+	  Ethernet) interface. Say Y to include support for the MACE chip.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called mace.
+
+config MACE_AAUI_PORT
+	bool "Use AAUI port instead of TP by default"
+	depends on MACE
+	help
+	  Some Apple machines (notably the Apple Network Server) which use the
+	  MACE ethernet chip have an Apple AUI port (small 15-pin connector),
+	  instead of an 8-pin RJ45 connector for twisted-pair ethernet.  Say
+	  Y here if you have such a machine.  If unsure, say N.
+	  The driver will default to AAUI on ANS anyway, and if you use it as
+	  a module, you can provide the port_aaui=0|1 to force the driver.
+
+config BMAC
+	tristate "BMAC (G3 ethernet) support"
+	depends on PPC_PMAC && PPC32
+	select CRC32
+	help
+	  Say Y for support of BMAC Ethernet interfaces. These are used on G3
+	  computers.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called bmac.
+
+config ARIADNE
+	tristate "Ariadne support"
+	depends on ZORRO
+	help
+	  If you have a Village Tronic Ariadne Ethernet adapter, say Y.
+	  Otherwise, say N.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called ariadne.
+
+config A2065
+	tristate "A2065 support"
+	depends on ZORRO
+	select CRC32
+	help
+	  If you have a Commodore A2065 Ethernet adapter, say Y. Otherwise,
+	  say N.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called a2065.
+
+config HYDRA
+	tristate "Hydra support"
+	depends on ZORRO
+	select CRC32
+	help
+	  If you have a Hydra Ethernet adapter, say Y. Otherwise, say N.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called hydra.
+
+config ZORRO8390
+	tristate "Zorro NS8390-based Ethernet support"
+	depends on ZORRO
+	select CRC32
+	help
+	  This driver is for Zorro Ethernet cards using an NS8390-compatible
+	  chipset, like the Village Tronic Ariadne II and the Individual
+	  Computers X-Surf Ethernet cards. If you have such a card, say Y.
+	  Otherwise, say N.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called zorro8390.
+
+config APNE
+	tristate "PCMCIA NE2000 support"
+	depends on AMIGA_PCMCIA
+	select CRC32
+	help
+	  If you have a PCMCIA NE2000 compatible adapter, say Y.  Otherwise,
+	  say N.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called apne.
+
+config APOLLO_ELPLUS
+	tristate "Apollo 3c505 support"
+	depends on APOLLO
+	help
+	  Say Y or M here if your Apollo has a 3Com 3c505 ISA Ethernet card.
+	  If you don't have one made for Apollos, you can use one from a PC,
+	  except that your Apollo won't be able to boot from it (because the
+	  code in the ROM will be for a PC).
+
+config MAC8390
+	bool "Macintosh NS 8390 based ethernet cards"
+	depends on MAC
+	select CRC32
+	help
+	  If you want to include a driver to support Nubus or LC-PDS
+	  Ethernet cards using an NS8390 chipset or its equivalent, say Y
+	  and read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+config MAC89x0
+	tristate "Macintosh CS89x0 based ethernet cards"
+	depends on MAC
+	---help---
+	  Support for CS89x0 chipset based Ethernet cards.  If you have a
+	  Nubus or LC-PDS network (Ethernet) card of this type, say Y and
+	  read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. This module will
+	  be called mac89x0.
+
+config MACSONIC
+	tristate "Macintosh SONIC based ethernet (onboard, NuBus, LC, CS)"
+	depends on MAC
+	---help---
+	  Support for NatSemi SONIC based Ethernet devices.  This includes
+	  the onboard Ethernet in many Quadras as well as some LC-PDS,
+	  a few Nubus and all known Comm Slot Ethernet cards.  If you have
+	  one of these say Y and read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. This module will
+	  be called macsonic.
+
+config MACMACE
+	bool "Macintosh (AV) onboard MACE ethernet"
+	depends on MAC
+	select CRC32
+	help
+	  Support for the onboard AMD 79C940 MACE Ethernet controller used in
+	  the 660AV and 840AV Macintosh.  If you have one of these Macintoshes
+	  say Y and read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+config MVME147_NET
+	tristate "MVME147 (Lance) Ethernet support"
+	depends on MVME147
+	select CRC32
+	help
+	  Support for the on-board Ethernet interface on the Motorola MVME147
+	  single-board computer.  Say Y here to include the
+	  driver for this chip in your kernel.
+	  To compile this driver as a module, choose M here.
+
+config MVME16x_NET
+	tristate "MVME16x Ethernet support"
+	depends on MVME16x
+	help
+	  This is the driver for the Ethernet interface on the Motorola
+	  MVME162, 166, 167, 172 and 177 boards.  Say Y here to include the
+	  driver for this chip in your kernel.
+	  To compile this driver as a module, choose M here.
+
+config BVME6000_NET
+	tristate "BVME6000 Ethernet support"
+	depends on BVME6000
+	help
+	  This is the driver for the Ethernet interface on BVME4000 and
+	  BVME6000 VME boards.  Say Y here to include the driver for this chip
+	  in your kernel.
+	  To compile this driver as a module, choose M here.
+
+config ATARILANCE
+	tristate "Atari Lance support"
+	depends on ATARI
+	help
+	  Say Y to include support for several Atari Ethernet adapters based
+	  on the AMD Lance chipset: RieblCard (with or without battery), or
+	  PAMCard VME (also the version by Rhotron, with different addresses).
+
+config SUN3LANCE
+	tristate "Sun3/Sun3x on-board LANCE support"
+	depends on SUN3 || SUN3X
+	help
+	  Most Sun3 and Sun3x motherboards (including the 3/50, 3/60 and 3/80)
+	  featured an AMD Lance 10Mbit Ethernet controller on board; say Y
+	  here to compile in the Linux driver for this and enable Ethernet.
+	  General Linux information on the Sun 3 and 3x series (now
+	  discontinued) is at
+	  <http://www.angelfire.com/ca2/tech68k/sun3.html>.
+
+	  If you're not building a kernel for a Sun 3, say N.
+
+config SUN3_82586
+	bool "Sun3 on-board Intel 82586 support"
+	depends on SUN3
+	help
+	  This driver enables support for the on-board Intel 82586 based
+	  Ethernet adapter found on Sun 3/1xx and 3/2xx motherboards.  Note
+	  that this driver does not support 82586-based adapters on additional
+	  VME boards.
+
+config HPLANCE
+	bool "HP on-board LANCE support"
+	depends on DIO
+	select CRC32
+	help
+	  If you want to use the builtin "LANCE" Ethernet controller on an
+	  HP300 machine, say Y here.
+
+config LASI_82596
+	tristate "Lasi ethernet"
+	depends on GSC
+	help
+	  Say Y here to support the builtin Intel 82596 ethernet controller
+	  found in Hewlett-Packard PA-RISC machines with 10Mbit ethernet.
+
+config SNI_82596
+	tristate "SNI RM ethernet"
+	depends on NET_ETHERNET && SNI_RM
+	help
+	  Say Y here to support the on-board Intel 82596 ethernet controller
+	  built into SNI RM machines.
+
+config MIPS_JAZZ_SONIC
+	tristate "MIPS JAZZ onboard SONIC Ethernet support"
+	depends on MACH_JAZZ
+	help
+	  This is the driver for the onboard card of MIPS Magnum 4000,
+	  Acer PICA, Olivetti M700-10 and a few other identical OEM systems.
+
+config MIPS_AU1X00_ENET
+	bool "MIPS AU1000 Ethernet support"
+	depends on SOC_AU1X00
+	select PHYLIB
+	select CRC32
+	help
+	  If you have an Alchemy Semi AU1X00 based system
+	  say Y.  Otherwise, say N.
+
+config SGI_IOC3_ETH
+	bool "SGI IOC3 Ethernet"
+	depends on PCI && SGI_IP27
+	select CRC32
+	select MII
+	help
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+config MIPS_SIM_NET
+	tristate "MIPS simulator Network device"
+	depends on MIPS_SIM
+	help
+	  The MIPSNET device is a simple Ethernet network device which is
+	  emulated by the MIPS Simulator.
+	  If you are not using a MIPSsim or are unsure, say N.
+
+config SGI_O2MACE_ETH
+	tristate "SGI O2 MACE Fast Ethernet support"
+	depends on SGI_IP32=y
+
+config STNIC
+	tristate "National DP83902AV  support"
+	depends on SUPERH
+	select CRC32
+	help
+	  Support for cards based on the National Semiconductor DP83902AV
+	  ST-NIC Serial Network Interface Controller for Twisted Pair.  This
+	  is a 10Mbit/sec Ethernet controller.  Product overview and specs at
+	  <http://www.national.com/pf/DP/DP83902A.html>.
+
+	  If unsure, say N.
+
+config SUNLANCE
+	tristate "Sun LANCE support"
+	depends on SBUS
+	select CRC32
+	help
+	  This driver supports the "le" interface present on all 32-bit Sparc
+	  systems, on some older Ultra systems and as an Sbus option.  These
+	  cards are based on the AMD Lance chipset, which is better known
+	  via the NE2100 cards.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called sunlance.
+
+config HAPPYMEAL
+	tristate "Sun Happy Meal 10/100baseT support"
+	depends on SBUS || PCI
+	select CRC32
+	help
+	  This driver supports the "hme" interface present on most Ultra
+	  systems and as an option on older Sbus systems. This driver supports
+	  both PCI and Sbus devices. This driver also supports the "qfe" quad
+	  100baseT device available in both PCI and Sbus configurations.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called sunhme.
+
+config SUNBMAC
+	tristate "Sun BigMAC 10/100baseT support (EXPERIMENTAL)"
+	depends on SBUS && EXPERIMENTAL
+	select CRC32
+	help
+	  This driver supports the "be" interface available as an Sbus option.
+	  This is Sun's older 100baseT Ethernet device.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called sunbmac.
+
+config SUNQE
+	tristate "Sun QuadEthernet support"
+	depends on SBUS
+	select CRC32
+	help
+	  This driver supports the "qe" 10baseT Ethernet device, available as
+	  an Sbus option. Note that this is not the same as Quad FastEthernet
+	  "qfe" which is supported by the Happy Meal driver instead.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called sunqe.
+
+config SUNGEM
+	tristate "Sun GEM support"
+	depends on PCI
+	select CRC32
+	help
+	  Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0.  See also
+	  <http://www.sun.com/products-n-solutions/hardware/docs/pdf/806-3985-10.pdf>.
+
+config CASSINI
+	tristate "Sun Cassini support"
+	depends on PCI
+	select CRC32
+	help
+	  Support for the Sun Cassini chip, aka Sun GigaSwift Ethernet. See also
+	  <http://www.sun.com/products-n-solutions/hardware/docs/pdf/817-4341-10.pdf>
+
+config SUNVNET
+	tristate "Sun Virtual Network support"
+	depends on SUN_LDOMS
+	help
+	  Support for virtual network devices under Sun Logical Domains.
+
+config NET_VENDOR_3COM
+	bool "3COM cards"
+	depends on ISA || EISA || MCA || PCI
+	help
+	  If you have a network (Ethernet) card belonging to this class, say Y
+	  and read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  Note that the answer to this question doesn't directly affect the
+	  kernel: saying N will just cause the configurator to skip all
+	  the questions about 3COM cards. If you say Y, you will be asked for
+	  your specific card in the following questions.
+
+config EL1
+	tristate "3c501 \"EtherLink\" support"
+	depends on NET_VENDOR_3COM && ISA
+	---help---
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.  Also, consider buying a
+	  new card, since the 3c501 is slow, broken, and obsolete: you will
+	  have problems.  Some people suggest to ping ("man ping") a nearby
+	  machine every minute ("man cron") when using this card.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called 3c501.
+
+config EL2
+	tristate "3c503 \"EtherLink II\" support"
+	depends on NET_VENDOR_3COM && ISA
+	select CRC32
+	help
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called 3c503.
+
+config ELPLUS
+	tristate "3c505 \"EtherLink Plus\" support"
+	depends on NET_VENDOR_3COM && ISA && ISA_DMA_API
+	---help---
+	  Information about this network (Ethernet) card can be found in
+	  <file:Documentation/networking/3c505.txt>.  If you have a card of
+	  this type, say Y and read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called 3c505.
+
+config EL16
+	tristate "3c507 \"EtherLink 16\" support (EXPERIMENTAL)"
+	depends on NET_VENDOR_3COM && ISA && EXPERIMENTAL
+	help
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called 3c507.
+
+config EL3
+	tristate "3c509/3c529 (MCA)/3c579 \"EtherLink III\" support"
+	depends on NET_VENDOR_3COM && (ISA || EISA || MCA)
+	---help---
+	  If you have a network (Ethernet) card belonging to the 3Com
+	  EtherLinkIII series, say Y and read the Ethernet-HOWTO, available
+	  from <http://www.tldp.org/docs.html#howto>.
+
+	  If your card is not working you may need to use the DOS
+	  setup disk to disable Plug & Play mode, and to select the default
+	  media type.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called 3c509.
+
+config 3C515
+	tristate "3c515 ISA \"Fast EtherLink\""
+	depends on NET_VENDOR_3COM && (ISA || EISA) && ISA_DMA_API
+	help
+	  If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet
+	  network card, say Y and read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called 3c515.
+
+config ELMC
+	tristate "3c523 \"EtherLink/MC\" support"
+	depends on NET_VENDOR_3COM && MCA_LEGACY
+	help
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called 3c523.
+
+config ELMC_II
+	tristate "3c527 \"EtherLink/MC 32\" support (EXPERIMENTAL)"
+	depends on NET_VENDOR_3COM && MCA && MCA_LEGACY
+	help
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called 3c527.
+
+config VORTEX
+	tristate "3c590/3c900 series (592/595/597) \"Vortex/Boomerang\" support"
+	depends on NET_VENDOR_3COM && (PCI || EISA)
+	select MII
+	---help---
+	  This option enables driver support for a large number of 10Mbps and
+	  10/100Mbps EISA, PCI and PCMCIA 3Com network cards:
+
+	  "Vortex"    (Fast EtherLink 3c590/3c592/3c595/3c597) EISA and PCI
+	  "Boomerang" (EtherLink XL 3c900 or 3c905)            PCI
+	  "Cyclone"   (3c540/3c900/3c905/3c980/3c575/3c656)    PCI and Cardbus
+	  "Tornado"   (3c905)                                  PCI
+	  "Hurricane" (3c555/3cSOHO)                           PCI
+
+	  If you have such a card, say Y and read the Ethernet-HOWTO,
+	  available from <http://www.tldp.org/docs.html#howto>. More
+	  specific information is in
+	  <file:Documentation/networking/vortex.txt> and in the comments at
+	  the beginning of <file:drivers/net/3c59x.c>.
+
+	  To compile this support as a module, choose M here.
+
+config TYPHOON
+	tristate "3cr990 series \"Typhoon\" support"
+	depends on NET_VENDOR_3COM && PCI
+	select CRC32
+	---help---
+	  This option enables driver support for the 3cr990 series of cards:
+
+	  3C990-TX, 3CR990-TX-95, 3CR990-TX-97, 3CR990-FX-95, 3CR990-FX-97,
+	  3CR990SVR, 3CR990SVR95, 3CR990SVR97, 3CR990-FX-95 Server,
+	  3CR990-FX-97 Server, 3C990B-TX-M, 3C990BSVR
+
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called typhoon.
+
+config LANCE
+	tristate "AMD LANCE and PCnet (AT1500 and NE2100) support"
+	depends on ISA && ISA_DMA_API
+	help
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>. Some LinkSys cards are
+	  of this type.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called lance.  This is recommended.
+
+config NET_VENDOR_SMC
+	bool "Western Digital/SMC cards"
+	depends on ISA || MCA || EISA || MAC
+	help
+	  If you have a network (Ethernet) card belonging to this class, say Y
+	  and read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  Note that the answer to this question doesn't directly affect the
+	  kernel: saying N will just cause the configurator to skip all
+	  the questions about Western Digital cards. If you say Y, you will be
+	  asked for your specific card in the following questions.
+
+config WD80x3
+	tristate "WD80*3 support"
+	depends on NET_VENDOR_SMC && ISA
+	select CRC32
+	help
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called wd.
+
+config ULTRAMCA
+	tristate "SMC Ultra MCA support"
+	depends on NET_VENDOR_SMC && MCA
+	select CRC32
+	help
+	  If you have a network (Ethernet) card of this type and are running
+	  an MCA based system (PS/2), say Y and read the Ethernet-HOWTO,
+	  available from <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called smc-mca.
+
+config ULTRA
+	tristate "SMC Ultra support"
+	depends on NET_VENDOR_SMC && ISA
+	select CRC32
+	---help---
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  Important: There have been many reports that, with some motherboards
+	  mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible,
+	  such as some BusLogic models) causes corruption problems with many
+	  operating systems. The Linux smc-ultra driver has a work-around for
+	  this but keep it in mind if you have such a SCSI card and have
+	  problems.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called smc-ultra.
+
+config ULTRA32
+	tristate "SMC Ultra32 EISA support"
+	depends on NET_VENDOR_SMC && EISA
+	select CRC32
+	help
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called smc-ultra32.
+
+config BFIN_MAC
+	tristate "Blackfin 536/537 on-chip mac support"
+	depends on NET_ETHERNET && (BF537 || BF536) && (!BF537_PORT_H)
+	select CRC32
+	select MII
+	select PHYLIB
+	select BFIN_MAC_USE_L1 if DMA_UNCACHED_NONE
+	help
+	  This is the driver for blackfin on-chip mac device. Say Y if you want it
+	  compiled into the kernel. This driver is also available as a module
+	  ( = code which can be inserted in and removed from the running kernel
+	  whenever you want). The module will be called bfin_mac.
+
+config BFIN_MAC_USE_L1
+	bool "Use L1 memory for rx/tx packets"
+	depends on BFIN_MAC && BF537
+	default y
+	help
+	  To get maximum network performance, you should use L1 memory as rx/tx buffers.
+	  Say N here if you want to reserve L1 memory for other uses.
+
+config BFIN_TX_DESC_NUM
+	int "Number of transmit buffer packets"
+	depends on BFIN_MAC
+	range 6 10 if BFIN_MAC_USE_L1
+	range 10 100
+	default "10"
+	help
+	  Set the number of buffer packets used in driver.
+
+config BFIN_RX_DESC_NUM
+	int "Number of receive buffer packets"
+	depends on BFIN_MAC
+	range 20 100 if BFIN_MAC_USE_L1
+	range 20 800
+	default "20"
+	help
+	  Set the number of buffer packets used in driver.
+
+config BFIN_MAC_RMII
+	bool "RMII PHY Interface (EXPERIMENTAL)"
+	depends on BFIN_MAC && EXPERIMENTAL
+	default n
+	help
+	  Use Reduced PHY MII Interface
+
+config SMC9194
+	tristate "SMC 9194 support"
+	depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN)
+	select CRC32
+	---help---
+	  This is support for the SMC9xxx based Ethernet cards. Choose this
+	  option if you have a DELL laptop with the docking station, or
+	  another SMC9192/9194 based chipset.  Say Y if you want it compiled
+	  into the kernel, and read the file
+	  <file:Documentation/networking/smc9.txt> and the Ethernet-HOWTO,
+	  available from <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called smc9194.
+
+config SMC91X
+	tristate "SMC 91C9x/91C1xxx support"
+	select CRC32
+	select MII
+	depends on ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || SOC_AU1X00 || BLACKFIN
+	help
+	  This is a driver for SMC's 91x series of Ethernet chipsets,
+	  including the SMC91C94 and the SMC91C111. Say Y if you want it
+	  compiled into the kernel, and read the file
+	  <file:Documentation/networking/smc9.txt>  and the Ethernet-HOWTO,
+	  available from  <http://www.linuxdoc.org/docs.html#howto>.
+
+	  This driver is also available as a module ( = code which can be
+	  inserted in and removed from the running kernel whenever you want).
+	  The module will be called smc91x.  If you want to compile it as a
+	  module, say M here and read <file:Documentation/kbuild/modules.txt>.
+
+config NET_NETX
+	tristate "NetX Ethernet support"
+	select MII
+	depends on ARCH_NETX
+	help
+	  This is support for the Hilscher netX builtin Ethernet ports
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called netx-eth.
+
+config DM9000
+	tristate "DM9000 support"
+	depends on ARM || BLACKFIN || MIPS
+	select CRC32
+	select MII
+	---help---
+	  Support for DM9000 chipset.
+
+	  To compile this driver as a module, choose M here.  The module
+	  will be called dm9000.
+
+config SMC911X
+	tristate "SMSC LAN911[5678] support"
+	select CRC32
+	select MII
+	depends on ARCH_PXA || SH_MAGIC_PANEL_R2
+	help
+	  This is a driver for SMSC's LAN911x series of Ethernet chipsets
+	  including the new LAN9115, LAN9116, LAN9117, and LAN9118.
+	  Say Y if you want it compiled into the kernel, 
+	  and read the Ethernet-HOWTO, available from
+	  <http://www.linuxdoc.org/docs.html#howto>.
+
+	  This driver is also available as a module. The module will be 
+	  called smc911x.  If you want to compile it as a module, say M 
+	  here and read <file:Documentation/kbuild/modules.txt>
+
+config NET_VENDOR_RACAL
+	bool "Racal-Interlan (Micom) NI cards"
+	depends on ISA
+	help
+	  If you have a network (Ethernet) card belonging to this class, such
+	  as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO,
+	  available from <http://www.tldp.org/docs.html#howto>.
+
+	  Note that the answer to this question doesn't directly affect the
+	  kernel: saying N will just cause the configurator to skip all
+	  the questions about NI cards. If you say Y, you will be asked for
+	  your specific card in the following questions.
+
+config NI5010
+	tristate "NI5010 support (EXPERIMENTAL)"
+	depends on NET_VENDOR_RACAL && ISA && EXPERIMENTAL && BROKEN_ON_SMP
+	---help---
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>. Note that this is still
+	  experimental code.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called ni5010.
+
+config NI52
+	tristate "NI5210 support"
+	depends on NET_VENDOR_RACAL && ISA
+	help
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called ni52.
+
+config NI65
+	tristate "NI6510 support"
+	depends on NET_VENDOR_RACAL && ISA && ISA_DMA_API
+	help
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called ni65.
+
+source "drivers/net/tulip/Kconfig"
+
+config AT1700
+	tristate "AT1700/1720 support (EXPERIMENTAL)"
+	depends on (ISA || MCA_LEGACY) && EXPERIMENTAL
+	select CRC32
+	---help---
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called at1700.
+
+config DEPCA
+	tristate "DEPCA, DE10x, DE200, DE201, DE202, DE422 support"
+	depends on ISA || EISA || MCA
+	select CRC32
+	---help---
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto> as well as
+	  <file:drivers/net/depca.c>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called depca.
+
+config HP100
+	tristate "HP 10/100VG PCLAN (ISA, EISA, PCI) support"
+	depends on ISA || EISA || PCI
+	help
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called hp100.
+
+config NET_ISA
+	bool "Other ISA cards"
+	depends on ISA
+	---help---
+	  If your network (Ethernet) card hasn't been mentioned yet and its
+	  bus system (that's the way the cards talks to the other components
+	  of your computer) is ISA (as opposed to EISA, VLB or PCI), say Y.
+	  Make sure you know the name of your card. Read the Ethernet-HOWTO,
+	  available from <http://www.tldp.org/docs.html#howto>.
+
+	  If unsure, say Y.
+
+	  Note that the answer to this question doesn't directly affect the
+	  kernel: saying N will just cause the configurator to skip all
+	  the remaining ISA network card questions. If you say Y, you will be
+	  asked for your specific card in the following questions.
+
+config E2100
+	tristate "Cabletron E21xx support"
+	depends on NET_ISA
+	select CRC32
+	help
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called e2100.
+
+config EWRK3
+	tristate "EtherWORKS 3 (DE203, DE204, DE205) support"
+	depends on NET_ISA
+	select CRC32
+	---help---
+	  This driver supports the DE203, DE204 and DE205 network (Ethernet)
+	  cards. If this is for you, say Y and read
+	  <file:Documentation/networking/ewrk3.txt> in the kernel source as
+	  well as the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called ewrk3.
+
+config EEXPRESS
+	tristate "EtherExpress 16 support"
+	depends on NET_ISA
+	---help---
+	  If you have an EtherExpress16 network (Ethernet) card, say Y and
+	  read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.  Note that the Intel
+	  EtherExpress16 card used to be regarded as a very poor choice
+	  because the driver was very unreliable. We now have a new driver
+	  that should do better.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called eexpress.
+
+config EEXPRESS_PRO
+	tristate "EtherExpressPro support/EtherExpress 10 (i82595) support"
+	depends on NET_ISA
+	---help---
+	  If you have a network (Ethernet) card of this type, say Y. This
+	  driver supports Intel i82595{FX,TX} based boards. Note however
+	  that the EtherExpress PRO/100 Ethernet card has its own separate
+	  driver.  Please read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called eepro.
+
+config HPLAN_PLUS
+	tristate "HP PCLAN+ (27247B and 27252A) support"
+	depends on NET_ISA
+	select CRC32
+	help
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called hp-plus.
+
+config HPLAN
+	tristate "HP PCLAN (27245 and other 27xxx series) support"
+	depends on NET_ISA
+	select CRC32
+	help
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called hp.
+
+config LP486E
+	tristate "LP486E on board Ethernet"
+	depends on NET_ISA
+	help
+	  Say Y here to support the 82596-based on-board Ethernet controller
+	  for the Panther motherboard, which is one of the two shipped in the
+	  Intel Professional Workstation.
+
+config ETH16I
+	tristate "ICL EtherTeam 16i/32 support"
+	depends on NET_ISA
+	help
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called eth16i.
+
+config NE2000
+	tristate "NE2000/NE1000 support"
+	depends on NET_ISA || (Q40 && m) || M32R || TOSHIBA_RBTX4927 || TOSHIBA_RBTX4938
+	select CRC32
+	---help---
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.  Many Ethernet cards
+	  without a specific driver are compatible with NE2000.
+
+	  If you have a PCI NE2000 card however, say N here and Y to "PCI
+	  NE2000 and clone support" under "EISA, VLB, PCI and on board
+	  controllers" below. If you have a NE2000 card and are running on
+	  an MCA system (a bus system used on some IBM PS/2 computers and
+	  laptops), say N here and Y to "NE/2 (ne2000 MCA version) support",
+	  below.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called ne.
+
+config ZNET
+	tristate "Zenith Z-Note support (EXPERIMENTAL)"
+	depends on NET_ISA && EXPERIMENTAL && ISA_DMA_API
+	help
+	  The Zenith Z-Note notebook computer has a built-in network
+	  (Ethernet) card, and this is the Linux driver for it. Note that the
+	  IBM Thinkpad 300 is compatible with the Z-Note and is also supported
+	  by this driver. Read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+config SEEQ8005
+	tristate "SEEQ8005 support (EXPERIMENTAL)"
+	depends on NET_ISA && EXPERIMENTAL
+	help
+	  This is a driver for the SEEQ 8005 network (Ethernet) card.  If this
+	  is for you, read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called seeq8005.
+
+config NE2_MCA
+	tristate "NE/2 (ne2000 MCA version) support"
+	depends on MCA_LEGACY
+	select CRC32
+	help
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called ne2.
+
+config IBMLANA
+	tristate "IBM LAN Adapter/A support"
+	depends on MCA && MCA_LEGACY
+	---help---
+	  This is a Micro Channel Ethernet adapter.  You need to set
+	  CONFIG_MCA to use this driver.  It is both available as an in-kernel
+	  driver and as a module.
+
+	  To compile this driver as a module, choose M here. The only
+	  currently supported card is the IBM LAN Adapter/A for Ethernet.  It
+	  will both support 16K and 32K memory windows, however a 32K window
+	  gives a better security against packet losses.  Usage of multiple
+	  boards with this driver should be possible, but has not been tested
+	  up to now due to lack of hardware.
+
+config IBMVETH
+	tristate "IBM LAN Virtual Ethernet support"
+	depends on PPC_PSERIES
+	---help---
+	  This driver supports virtual ethernet adapters on newer IBM iSeries
+	  and pSeries systems.
+
+	  To compile this driver as a module, choose M here. The module will
+	  be called ibmveth.
+
+source "drivers/net/ibm_emac/Kconfig"
+source "drivers/net/ibm_newemac/Kconfig"
+
+config NET_PCI
+	bool "EISA, VLB, PCI and on board controllers"
+	depends on ISA || EISA || PCI
+	help
+	  This is another class of network cards which attach directly to the
+	  bus. If you have one of those, say Y and read the Ethernet-HOWTO,
+	  available from <http://www.tldp.org/docs.html#howto>.
+
+	  Note that the answer to this question doesn't directly affect the
+	  kernel: saying N will just cause the configurator to skip all
+	  the questions about this class of network cards. If you say Y, you
+	  will be asked for your specific card in the following questions. If
+	  you are unsure, say Y.
+
+config PCNET32
+	tristate "AMD PCnet32 PCI support"
+	depends on NET_PCI && PCI
+	select CRC32
+	select MII
+	help
+	  If you have a PCnet32 or PCnetPCI based network (Ethernet) card,
+	  answer Y here and read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called pcnet32.
+
+config PCNET32_NAPI
+	bool "Use RX polling (NAPI)"
+	depends on PCNET32
+	help
+	  NAPI is a new driver API designed to reduce CPU and interrupt load
+	  when the driver is receiving lots of packets from the card. It is
+	  still somewhat experimental and thus not yet enabled by default.
+
+	  If your estimated Rx load is 10kpps or more, or if the card will be
+	  deployed on potentially unfriendly networks (e.g. in a firewall),
+	  then say Y here.
+
+	  If in doubt, say N.
+
+config AMD8111_ETH
+	tristate "AMD 8111 (new PCI lance) support"
+	depends on NET_PCI && PCI
+	select CRC32
+	select MII
+	help
+	  If you have an AMD 8111-based PCI lance ethernet card,
+	  answer Y here and read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called amd8111e.
+
+config AMD8111E_NAPI
+	bool "Use RX polling (NAPI)"
+	depends on AMD8111_ETH
+	help
+	  NAPI is a new driver API designed to reduce CPU and interrupt load
+	  when the driver is receiving lots of packets from the card. It is
+	  still somewhat experimental and thus not yet enabled by default.
+
+	  If your estimated Rx load is 10kpps or more, or if the card will be
+	  deployed on potentially unfriendly networks (e.g. in a firewall),
+	  then say Y here.
+
+	  If in doubt, say N.
+
+config ADAPTEC_STARFIRE
+	tristate "Adaptec Starfire/DuraLAN support"
+	depends on NET_PCI && PCI
+	select CRC32
+	select MII
+	help
+	  Say Y here if you have an Adaptec Starfire (or DuraLAN) PCI network
+	  adapter. The DuraLAN chip is used on the 64 bit PCI boards from
+	  Adaptec e.g. the ANA-6922A. The older 32 bit boards use the tulip
+	  driver.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called starfire.  This is recommended.
+
+config ADAPTEC_STARFIRE_NAPI
+	bool "Use Rx Polling (NAPI) (EXPERIMENTAL)"
+	depends on ADAPTEC_STARFIRE && EXPERIMENTAL
+	help
+	  NAPI is a new driver API designed to reduce CPU and interrupt load
+	  when the driver is receiving lots of packets from the card. It is
+	  still somewhat experimental and thus not yet enabled by default.
+
+	  If your estimated Rx load is 10kpps or more, or if the card will be
+	  deployed on potentially unfriendly networks (e.g. in a firewall),
+	  then say Y here.
+
+	  If in doubt, say N.
+
+config AC3200
+	tristate "Ansel Communications EISA 3200 support (EXPERIMENTAL)"
+	depends on NET_PCI && (ISA || EISA) && EXPERIMENTAL
+	select CRC32
+	help
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called ac3200.
+
+config APRICOT
+	tristate "Apricot Xen-II on board Ethernet"
+	depends on NET_PCI && ISA
+	help
+	  If you have a network (Ethernet) controller of this type, say Y and
+	  read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called apricot.
+
+config B44
+	tristate "Broadcom 440x/47xx ethernet support"
+	depends on SSB_POSSIBLE
+	select SSB
+	select MII
+	help
+	  If you have a network (Ethernet) controller of this type, say Y
+	  or M and read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called b44.
+
+# Auto-select SSB PCI-HOST support, if possible
+config B44_PCI_AUTOSELECT
+	bool
+	depends on B44 && SSB_PCIHOST_POSSIBLE
+	select SSB_PCIHOST
+	default y
+
+# Auto-select SSB PCICORE driver, if possible
+config B44_PCICORE_AUTOSELECT
+	bool
+	depends on B44 && SSB_DRIVER_PCICORE_POSSIBLE
+	select SSB_DRIVER_PCICORE
+	default y
+
+config B44_PCI
+	bool
+	depends on B44_PCI_AUTOSELECT && B44_PCICORE_AUTOSELECT
+	default y
+
+config FORCEDETH
+	tristate "nForce Ethernet support"
+	depends on NET_PCI && PCI
+	help
+	  If you have a network (Ethernet) controller of this type, say Y and
+	  read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called forcedeth.
+
+config FORCEDETH_NAPI
+	bool "Use Rx Polling (NAPI) (EXPERIMENTAL)"
+	depends on FORCEDETH && EXPERIMENTAL
+	help
+	  NAPI is a new driver API designed to reduce CPU and interrupt load
+	  when the driver is receiving lots of packets from the card. It is
+	  still somewhat experimental and thus not yet enabled by default.
+
+	  If your estimated Rx load is 10kpps or more, or if the card will be
+	  deployed on potentially unfriendly networks (e.g. in a firewall),
+	  then say Y here.
+
+	  If in doubt, say N.
+
+config CS89x0
+	tristate "CS89x0 support"
+	depends on NET_PCI && (ISA || MACH_IXDP2351 || ARCH_IXDP2X01 || ARCH_PNX010X)
+	---help---
+	  Support for CS89x0 chipset based Ethernet cards. If you have a
+	  network (Ethernet) card of this type, say Y and read the
+	  Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto> as well as
+	  <file:Documentation/networking/cs89x0.txt>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called cs89x0.
+
+config TC35815
+	tristate "TOSHIBA TC35815 Ethernet support"
+	depends on NET_PCI && PCI && MIPS
+	select MII
+
+config EEPRO100
+	tristate "EtherExpressPro/100 support (eepro100, original Becker driver)"
+	depends on NET_PCI && PCI
+	select MII
+	help
+	  If you have an Intel EtherExpress PRO/100 PCI network (Ethernet)
+	  card, say Y and read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called eepro100.
+
+
+config E100
+	tristate "Intel(R) PRO/100+ support"
+	depends on NET_PCI && PCI
+	select MII
+	---help---
+	  This driver supports Intel(R) PRO/100 family of adapters.
+	  To verify that your adapter is supported, find the board ID number 
+	  on the adapter. Look for a label that has a barcode and a number 
+	  in the format 123456-001 (six digits hyphen three digits). 
+
+	  Use the above information and the Adapter & Driver ID Guide at:
+
+	  <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+          to identify the adapter.
+
+	  For the latest Intel PRO/100 network driver for Linux, see:
+
+	  <http://appsr.intel.com/scripts-df/support_intel.asp>
+
+	  More specific information on configuring the driver is in 
+	  <file:Documentation/networking/e100.txt>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called e100.
+
+config LNE390
+	tristate "Mylex EISA LNE390A/B support (EXPERIMENTAL)"
+	depends on NET_PCI && EISA && EXPERIMENTAL
+	select CRC32
+	help
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called lne390.
+
+config FEALNX
+	tristate "Myson MTD-8xx PCI Ethernet support"
+	depends on NET_PCI && PCI
+	select CRC32
+	select MII
+	help
+	  Say Y here to support the Mysom MTD-800 family of PCI-based Ethernet
+	  cards. Specifications and data at
+	  <http://www.myson.com.hk/mtd/datasheet/>.
+
+config NATSEMI
+	tristate "National Semiconductor DP8381x series PCI Ethernet support"
+	depends on NET_PCI && PCI
+	select CRC32
+	help
+	  This driver is for the National Semiconductor DP83810 series,
+	  which is used in cards from PureData, NetGear, Linksys
+	  and others, including the 83815 chip.
+	  More specific information and updates are available from
+	  <http://www.scyld.com/network/natsemi.html>.
+
+config NE2K_PCI
+	tristate "PCI NE2000 and clones support (see help)"
+	depends on NET_PCI && PCI
+	select CRC32
+	---help---
+	  This driver is for NE2000 compatible PCI cards. It will not work
+	  with ISA NE2000 cards (they have their own driver, "NE2000/NE1000
+	  support" below). If you have a PCI NE2000 network (Ethernet) card,
+	  say Y and read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  This driver also works for the following NE2000 clone cards:
+	  RealTek RTL-8029  Winbond 89C940  Compex RL2000  KTI ET32P2
+	  NetVin NV5000SC   Via 86C926      SureCom NE34   Winbond
+	  Holtek HT80232    Holtek HT80229
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called ne2k-pci.
+
+config NE3210
+	tristate "Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)"
+	depends on NET_PCI && EISA && EXPERIMENTAL
+	select CRC32
+	---help---
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.  Note that this driver
+	  will NOT WORK for NE3200 cards as they are completely different.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called ne3210.
+
+config ES3210
+	tristate "Racal-Interlan EISA ES3210 support (EXPERIMENTAL)"
+	depends on NET_PCI && EISA && EXPERIMENTAL
+	select CRC32
+	help
+	  If you have a network (Ethernet) card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called es3210.
+
+config 8139CP
+	tristate "RealTek RTL-8139 C+ PCI Fast Ethernet Adapter support (EXPERIMENTAL)"
+	depends on NET_PCI && PCI && EXPERIMENTAL
+	select CRC32
+	select MII
+	help
+	  This is a driver for the Fast Ethernet PCI network cards based on
+	  the RTL8139C+ chips. If you have one of those, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called 8139cp.  This is recommended.
+
+config 8139TOO
+	tristate "RealTek RTL-8129/8130/8139 PCI Fast Ethernet Adapter support"
+	depends on NET_PCI && PCI
+	select CRC32
+	select MII
+	---help---
+	  This is a driver for the Fast Ethernet PCI network cards based on
+	  the RTL 8129/8130/8139 chips. If you have one of those, say Y and
+	  read the Ethernet-HOWTO <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called 8139too.  This is recommended.
+
+config 8139TOO_PIO
+	bool "Use PIO instead of MMIO"
+	default y
+	depends on 8139TOO
+	help
+	  This instructs the driver to use programmed I/O ports (PIO) instead
+	  of PCI shared memory (MMIO).  This can possibly solve some problems
+	  in case your mainboard has memory consistency issues.  If unsure,
+	  say N.
+
+config 8139TOO_TUNE_TWISTER
+	bool "Support for uncommon RTL-8139 rev. K (automatic channel equalization)"
+	depends on 8139TOO
+	help
+	  This implements a function which might come in handy in case you
+	  are using low quality on long cabling. It is required for RealTek
+	  RTL-8139 revision K boards, and totally unused otherwise.  It tries
+	  to match the transceiver to the cable characteristics. This is
+	  experimental since hardly documented by the manufacturer.
+	  If unsure, say Y.
+
+config 8139TOO_8129
+	bool "Support for older RTL-8129/8130 boards"
+	depends on 8139TOO
+	help
+	  This enables support for the older and uncommon RTL-8129 and
+	  RTL-8130 chips, which support MII via an external transceiver,
+	  instead of an internal one.  Disabling this option will save some
+	  memory by making the code size smaller.  If unsure, say Y.
+
+config 8139_OLD_RX_RESET
+	bool "Use older RX-reset method"
+	depends on 8139TOO
+	help
+	  The 8139too driver was recently updated to contain a more rapid
+	  reset sequence, in the face of severe receive errors.  This "new"
+	  RX-reset method should be adequate for all boards.  But if you
+	  experience problems, you can enable this option to restore the
+	  old RX-reset behavior.  If unsure, say N.
+
+config SIS900
+	tristate "SiS 900/7016 PCI Fast Ethernet Adapter support"
+	depends on NET_PCI && PCI
+	select CRC32
+	select MII
+	---help---
+	  This is a driver for the Fast Ethernet PCI network cards based on
+	  the SiS 900 and SiS 7016 chips. The SiS 900 core is also embedded in
+	  SiS 630 and SiS 540 chipsets.
+
+	  This driver also supports AMD 79C901 HomePNA so that you can use
+	  your phone line as a network cable.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called sis900.  This is recommended.
+
+config EPIC100
+	tristate "SMC EtherPower II"
+	depends on NET_PCI && PCI
+	select CRC32
+	select MII
+	help
+	  This driver is for the SMC EtherPower II 9432 PCI Ethernet NIC,
+	  which is based on the SMC83c17x (EPIC/100).
+	  More specific information and updates are available from
+	  <http://www.scyld.com/network/epic100.html>.
+
+config SUNDANCE
+	tristate "Sundance Alta support"
+	depends on NET_PCI && PCI
+	select CRC32
+	select MII
+	help
+	  This driver is for the Sundance "Alta" chip.
+	  More specific information and updates are available from
+	  <http://www.scyld.com/network/sundance.html>.
+
+config SUNDANCE_MMIO
+	bool "Use MMIO instead of PIO"
+	depends on SUNDANCE
+	help
+	  Enable memory-mapped I/O for interaction with Sundance NIC registers.
+	  Do NOT enable this by default, PIO (enabled when MMIO is disabled)
+	  is known to solve bugs on certain chips.
+
+	  If unsure, say N.
+
+config TLAN
+	tristate "TI ThunderLAN support"
+	depends on NET_PCI && (PCI || EISA) && !64BIT
+	---help---
+	  If you have a PCI Ethernet network card based on the ThunderLAN chip
+	  which is supported by this driver, say Y and read the
+	  Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  Devices currently supported by this driver are Compaq Netelligent,
+	  Compaq NetFlex and Olicom cards.  Please read the file
+	  <file:Documentation/networking/tlan.txt> for more details.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called tlan.
+
+	  Please email feedback to <torben.mathiasen@compaq.com>.
+
+config VIA_RHINE
+	tristate "VIA Rhine support"
+	depends on NET_PCI && PCI
+	select CRC32
+	select MII
+	help
+	  If you have a VIA "Rhine" based network card (Rhine-I (VT86C100A),
+	  Rhine-II (VT6102), or Rhine-III (VT6105)), say Y here. Rhine-type
+	  Ethernet functions can also be found integrated on South Bridges
+	  (e.g. VT8235).
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called via-rhine.
+
+config VIA_RHINE_MMIO
+	bool "Use MMIO instead of PIO"
+	depends on VIA_RHINE
+	help
+	  This instructs the driver to use PCI shared memory (MMIO) instead of
+	  programmed I/O ports (PIO). Enabling this gives an improvement in
+	  processing time in parts of the driver.
+
+	  If unsure, say Y.
+
+config VIA_RHINE_NAPI
+	bool "Use Rx Polling (NAPI)"
+	depends on VIA_RHINE
+	help
+	  NAPI is a new driver API designed to reduce CPU and interrupt load
+	  when the driver is receiving lots of packets from the card.
+
+	  If your estimated Rx load is 10kpps or more, or if the card will be
+	  deployed on potentially unfriendly networks (e.g. in a firewall),
+	  then say Y here.
+
+config LAN_SAA9730
+	bool "Philips SAA9730 Ethernet support"
+	depends on NET_PCI && PCI && MIPS_ATLAS
+	help
+	  The SAA9730 is a combined multimedia and peripheral controller used
+	  in thin clients, Internet access terminals, and diskless
+	  workstations.
+	  See <http://www.semiconductors.philips.com/pip/SAA9730_flyer_1>.
+
+config SC92031
+	tristate "Silan SC92031 PCI Fast Ethernet Adapter driver (EXPERIMENTAL)"
+	depends on NET_PCI && PCI && EXPERIMENTAL
+	select CRC32
+	---help---
+	  This is a driver for the Fast Ethernet PCI network cards based on
+	  the Silan SC92031 chip (sometimes also called Rsltek 8139D). If you
+	  have one of these, say Y here.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called sc92031.  This is recommended.
+
+config CPMAC
+	tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)"
+	depends on NET_ETHERNET && EXPERIMENTAL && AR7
+	select PHYLIB
+	select FIXED_PHY
+	select FIXED_MII_100_FDX
+	help
+	  TI AR7 CPMAC Ethernet support
+
+config NET_POCKET
+	bool "Pocket and portable adapters"
+	depends on PARPORT
+	---help---
+	  Cute little network (Ethernet) devices which attach to the parallel
+	  port ("pocket adapters"), commonly used with laptops. If you have
+	  one of those, say Y and read the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  If you want to plug a network (or some other) card into the PCMCIA
+	  (or PC-card) slot of your laptop instead (PCMCIA is the standard for
+	  credit card size extension cards used by all modern laptops), you
+	  need the pcmcia-cs package (location contained in the file
+	  <file:Documentation/Changes>) and you can say N here.
+
+	  Laptop users should read the Linux Laptop home page at
+	  <http://www.linux-on-laptops.com/> or
+	  Tuxmobil - Linux on Mobile Computers at <http://www.tuxmobil.org/>.
+
+	  Note that the answer to this question doesn't directly affect the
+	  kernel: saying N will just cause the configurator to skip all
+	  the questions about this class of network devices. If you say Y, you
+	  will be asked for your specific device in the following questions.
+
+config ATP
+	tristate "AT-LAN-TEC/RealTek pocket adapter support"
+	depends on NET_POCKET && PARPORT && X86
+	select CRC32
+	---help---
+	  This is a network (Ethernet) device which attaches to your parallel
+	  port. Read <file:drivers/net/atp.c> as well as the Ethernet-HOWTO,
+	  available from <http://www.tldp.org/docs.html#howto>, if you
+	  want to use this.  If you intend to use this driver, you should have
+	  said N to the "Parallel printer support", because the two drivers
+	  don't like each other.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called atp.
+
+config DE600
+	tristate "D-Link DE600 pocket adapter support"
+	depends on NET_POCKET && PARPORT
+	---help---
+	  This is a network (Ethernet) device which attaches to your parallel
+	  port. Read <file:Documentation/networking/DLINK.txt> as well as the
+	  Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>, if you want to use
+	  this. It is possible to have several devices share a single parallel
+	  port and it is safe to compile the corresponding drivers into the
+	  kernel.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called de600.
+
+config DE620
+	tristate "D-Link DE620 pocket adapter support"
+	depends on NET_POCKET && PARPORT
+	---help---
+	  This is a network (Ethernet) device which attaches to your parallel
+	  port. Read <file:Documentation/networking/DLINK.txt> as well as the
+	  Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>, if you want to use
+	  this. It is possible to have several devices share a single parallel
+	  port and it is safe to compile the corresponding drivers into the
+	  kernel.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called de620.
+
+config SGISEEQ
+	tristate "SGI Seeq ethernet controller support"
+	depends on SGI_IP22
+	help
+	  Say Y here if you have an Seeq based Ethernet network card. This is
+	  used in many Silicon Graphics machines.
+
+config DECLANCE
+	tristate "DEC LANCE ethernet controller support"
+	depends on MACH_DECSTATION
+	select CRC32
+	help
+	  This driver is for the series of Ethernet controllers produced by
+	  DEC (now Compaq) based on the AMD Lance chipset, including the
+	  DEPCA series.  (This chipset is better known via the NE2100 cards.)
+
+config 68360_ENET
+	bool "Motorola 68360 ethernet controller"
+	depends on M68360
+	help
+	  Say Y here if you want to use the built-in ethernet controller of
+	  the Motorola 68360 processor.
+
+config FEC
+	bool "FEC ethernet controller (of ColdFire CPUs)"
+	depends on M523x || M527x || M5272 || M528x || M520x
+	help
+	  Say Y here if you want to use the built-in 10/100 Fast ethernet
+	  controller on some Motorola ColdFire processors.
+
+config FEC2
+	bool "Second FEC ethernet controller (on some ColdFire CPUs)"
+	depends on FEC
+	help
+	  Say Y here if you want to use the second built-in 10/100 Fast
+	  ethernet controller on some Motorola ColdFire processors.
+
+config FEC_MPC52xx
+	tristate "MPC52xx FEC driver"
+	depends on PPC_MERGE && PPC_MPC52xx && PPC_BESTCOMM_FEC
+	select CRC32
+	select PHYLIB
+	---help---
+	  This option enables support for the MPC5200's on-chip
+	  Fast Ethernet Controller
+	  If compiled as module, it will be called 'fec_mpc52xx.ko'.
+
+config FEC_MPC52xx_MDIO
+	bool "MPC52xx FEC MDIO bus driver"
+	depends on FEC_MPC52xx
+	default y
+	---help---
+	  The MPC5200's FEC can connect to the Ethernet either with
+	  an external MII PHY chip or 10 Mbps 7-wire interface
+	  (Motorola? industry standard).
+	  If your board uses an external PHY connected to FEC, enable this.
+	  If not sure, enable.
+	  If compiled as module, it will be called 'fec_mpc52xx_phy.ko'.
+
+config NE_H8300
+	tristate "NE2000 compatible support for H8/300"
+	depends on H8300
+	help
+	  Say Y here if you want to use the NE2000 compatible
+	  controller on the Renesas H8/300 processor.
+
+source "drivers/net/fec_8xx/Kconfig"
+source "drivers/net/fs_enet/Kconfig"
+
+endif # NET_ETHERNET
+
+#
+#	Gigabit Ethernet
+#
+
+menuconfig NETDEV_1000
+	bool "Ethernet (1000 Mbit)"
+	depends on !UML
+	default y
+	---help---
+	  Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
+	  type of Local Area Network (LAN) in universities and companies.
+
+	  Say Y here to get to see options for Gigabit Ethernet drivers.
+	  This option alone does not add any kernel code.
+	  Note that drivers supporting both 100 and 1000 MBit may be listed
+	  under "Ethernet (10 or 100MBit)" instead.
+
+	  If you say N, all options in this submenu will be skipped and disabled.
+
+if NETDEV_1000
+
+config ACENIC
+	tristate "Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support"
+	depends on PCI
+	---help---
+	  Say Y here if you have an Alteon AceNIC, 3Com 3C985(B), NetGear
+	  GA620, SGI Gigabit or Farallon PN9000-SX PCI Gigabit Ethernet
+	  adapter. The driver allows for using the Jumbo Frame option (9000
+	  bytes/frame) however it requires that your switches can handle this
+	  as well. To enable Jumbo Frames, add `mtu 9000' to your ifconfig
+	  line.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called acenic.
+
+config ACENIC_OMIT_TIGON_I
+	bool "Omit support for old Tigon I based AceNICs"
+	depends on ACENIC
+	help
+	  Say Y here if you only have Tigon II based AceNICs and want to leave
+	  out support for the older Tigon I based cards which are no longer
+	  being sold (ie. the original Alteon AceNIC and 3Com 3C985 (non B
+	  version)).  This will reduce the size of the driver object by
+	  app. 100KB.  If you are not sure whether your card is a Tigon I or a
+	  Tigon II, say N here.
+
+	  The safe and default value for this is N.
+
+config DL2K
+	tristate "DL2000/TC902x-based Gigabit Ethernet support"
+	depends on PCI
+	select CRC32
+	help
+	  This driver supports DL2000/TC902x-based Gigabit ethernet cards,
+	  which includes
+	  D-Link DGE-550T Gigabit Ethernet Adapter.
+	  D-Link DL2000-based Gigabit Ethernet Adapter.
+	  Sundance/Tamarack TC902x Gigabit Ethernet Adapter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called dl2k.
+
+config E1000
+	tristate "Intel(R) PRO/1000 Gigabit Ethernet support"
+	depends on PCI
+	---help---
+	  This driver supports Intel(R) PRO/1000 gigabit ethernet family of
+	  adapters.  For more information on how to identify your adapter, go 
+	  to the Adapter & Driver ID Guide at:
+
+	  <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+	  For general information and support, go to the Intel support
+	  website at:
+
+	  <http://support.intel.com>
+
+	  More specific information on configuring the driver is in 
+	  <file:Documentation/networking/e1000.txt>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called e1000.
+
+config E1000_NAPI
+	bool "Use Rx Polling (NAPI)"
+	depends on E1000
+	help
+	  NAPI is a new driver API designed to reduce CPU and interrupt load
+	  when the driver is receiving lots of packets from the card. It is
+	  still somewhat experimental and thus not yet enabled by default.
+
+	  If your estimated Rx load is 10kpps or more, or if the card will be
+	  deployed on potentially unfriendly networks (e.g. in a firewall),
+	  then say Y here.
+
+	  If in doubt, say N.
+
+config E1000_DISABLE_PACKET_SPLIT
+	bool "Disable Packet Split for PCI express adapters"
+	depends on E1000
+	help
+	  Say Y here if you want to use the legacy receive path for PCI express
+	  hardware.
+
+	  If in doubt, say N.
+
+config E1000E
+	tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support"
+	depends on PCI
+	---help---
+	  This driver supports the PCI-Express Intel(R) PRO/1000 gigabit
+	  ethernet family of adapters. For PCI or PCI-X e1000 adapters,
+	  use the regular e1000 driver For more information on how to
+	  identify your adapter, go to the Adapter & Driver ID Guide at:
+
+	  <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+	  For general information and support, go to the Intel support
+	  website at:
+
+	  <http://support.intel.com>
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called e1000e.
+
+config IP1000
+	tristate "IP1000 Gigabit Ethernet support"
+	depends on PCI && EXPERIMENTAL
+	select MII
+	---help---
+	  This driver supports IP1000 gigabit Ethernet cards.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called ipg.  This is recommended.
+
+source "drivers/net/ixp2000/Kconfig"
+
+config MYRI_SBUS
+	tristate "MyriCOM Gigabit Ethernet support"
+	depends on SBUS
+	help
+	  This driver supports MyriCOM Sbus gigabit Ethernet cards.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called myri_sbus.  This is recommended.
+
+config NS83820
+	tristate "National Semiconductor DP83820 support"
+	depends on PCI
+	help
+	  This is a driver for the National Semiconductor DP83820 series
+	  of gigabit ethernet MACs.  Cards using this chipset include
+	  the D-Link DGE-500T, PureData's PDP8023Z-TG, SMC's SMC9462TX,
+	  SOHO-GA2000T, SOHO-GA2500T.  The driver supports the use of
+	  zero copy.
+
+config HAMACHI
+	tristate "Packet Engines Hamachi GNIC-II support"
+	depends on PCI
+	select MII
+	help
+	  If you have a Gigabit Ethernet card of this type, say Y and read
+	  the Ethernet-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here. The module will be
+	  called hamachi.
+
+config YELLOWFIN
+	tristate "Packet Engines Yellowfin Gigabit-NIC support (EXPERIMENTAL)"
+	depends on PCI && EXPERIMENTAL
+	select CRC32
+	---help---
+	  Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet
+	  adapter or the SYM53C885 Ethernet controller. The Gigabit adapter is
+	  used by the Beowulf Linux cluster project.  See
+	  <http://cesdis.gsfc.nasa.gov/linux/drivers/yellowfin.html> for more
+	  information about this driver in particular and Beowulf in general.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called yellowfin.  This is recommended.
+
+config R8169
+	tristate "Realtek 8169 gigabit ethernet support"
+	depends on PCI
+	select CRC32
+	---help---
+	  Say Y here if you have a Realtek 8169 PCI Gigabit Ethernet adapter.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called r8169.  This is recommended.
+
+config R8169_NAPI
+	bool "Use Rx Polling (NAPI) (EXPERIMENTAL)"
+	depends on R8169 && EXPERIMENTAL
+	help
+	  NAPI is a new driver API designed to reduce CPU and interrupt load
+	  when the driver is receiving lots of packets from the card. It is
+	  still somewhat experimental and thus not yet enabled by default.
+
+	  If your estimated Rx load is 10kpps or more, or if the card will be
+	  deployed on potentially unfriendly networks (e.g. in a firewall),
+	  then say Y here.
+
+	  If in doubt, say N.
+
+config R8169_VLAN
+	bool "VLAN support"
+	depends on R8169 && VLAN_8021Q
+	---help---
+	  Say Y here for the r8169 driver to support the functions required
+	  by the kernel 802.1Q code.
+	  
+	  If in doubt, say Y.
+
+config SB1250_MAC
+	tristate "SB1250 Gigabit Ethernet support"
+	depends on SIBYTE_SB1xxx_SOC
+	select PHYLIB
+	---help---
+	  This driver supports Gigabit Ethernet interfaces based on the
+	  Broadcom SiByte family of System-On-a-Chip parts.  They include
+	  the BCM1120, BCM1125, BCM1125H, BCM1250, BCM1255, BCM1280, BCM1455
+	  and BCM1480 chips.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called sb1250-mac.
+
+config SIS190
+	tristate "SiS190/SiS191 gigabit ethernet support"
+	depends on PCI
+	select CRC32
+	select MII
+	---help---
+	  Say Y here if you have a SiS 190 PCI Fast Ethernet adapter or
+	  a SiS 191 PCI Gigabit Ethernet adapter. Both are expected to
+	  appear in lan on motherboard designs which are based on SiS 965
+	  and SiS 966 south bridge.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called sis190.  This is recommended.
+
+config SKGE
+	tristate "New SysKonnect GigaEthernet support"
+	depends on PCI
+	select CRC32
+	---help---
+	  This driver support the Marvell Yukon or SysKonnect SK-98xx/SK-95xx
+	  and related Gigabit Ethernet adapters. It is a new smaller driver
+	  with better performance and more complete ethtool support.
+
+	  It does not support the link failover and network management 
+	  features that "portable" vendor supplied sk98lin driver does.
+
+	  This driver supports adapters based on the original Yukon chipset:
+	  Marvell 88E8001, Belkin F5D5005, CNet GigaCard, DLink DGE-530T,
+	  Linksys EG1032/EG1064, 3Com 3C940/3C940B, SysKonnect SK-9871/9872.
+
+	  It does not support the newer Yukon2 chipset: a separate driver,
+	  sky2, is provided for Yukon2-based adapters.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called skge.  This is recommended.
+
+config SKGE_DEBUG
+       bool "Debugging interface"
+       depends on SKGE && DEBUG_FS
+       help
+	 This option adds the ability to dump driver state for debugging.
+	 The file debugfs/skge/ethX displays the state of the internal
+	 transmit and receive rings.
+
+	 If unsure, say N.
+
+config SKY2
+	tristate "SysKonnect Yukon2 support"
+	depends on PCI
+	select CRC32
+	---help---
+	  This driver supports Gigabit Ethernet adapters based on the
+	  Marvell Yukon 2 chipset:
+	  Marvell 88E8021/88E8022/88E8035/88E8036/88E8038/88E8050/88E8052/
+	  88E8053/88E8055/88E8061/88E8062, SysKonnect SK-9E21D/SK-9S21
+
+	  There is companion driver for the older Marvell Yukon and
+	  Genesis based adapters: skge.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called sky2.  This is recommended.
+
+config SKY2_DEBUG
+       bool "Debugging interface"
+       depends on SKY2 && DEBUG_FS
+       help
+	 This option adds the ability to dump driver state for debugging.
+	 The file debugfs/sky2/ethX displays the state of the internal
+	 transmit and receive rings.
+
+	 If unsure, say N.
+
+config SK98LIN
+	tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support (DEPRECATED)"
+	depends on PCI
+	---help---
+	  Say Y here if you have a Marvell Yukon or SysKonnect SK-98xx/SK-95xx
+	  compliant Gigabit Ethernet Adapter.
+
+	  This driver supports the original Yukon chipset. This driver is
+	  deprecated and will be removed from the kernel in the near future,
+	  it has been replaced by the skge driver. skge is cleaner and
+	  seems to work better.
+
+	  This driver does not support the newer Yukon2 chipset. A separate
+	  driver, sky2, is provided to support Yukon2-based adapters.
+
+	  The following adapters are supported by this driver:
+	    - 3Com 3C940 Gigabit LOM Ethernet Adapter
+	    - 3Com 3C941 Gigabit LOM Ethernet Adapter
+	    - Allied Telesyn AT-2970LX Gigabit Ethernet Adapter
+	    - Allied Telesyn AT-2970LX/2SC Gigabit Ethernet Adapter
+	    - Allied Telesyn AT-2970SX Gigabit Ethernet Adapter
+	    - Allied Telesyn AT-2970SX/2SC Gigabit Ethernet Adapter
+	    - Allied Telesyn AT-2970TX Gigabit Ethernet Adapter
+	    - Allied Telesyn AT-2970TX/2TX Gigabit Ethernet Adapter
+	    - Allied Telesyn AT-2971SX Gigabit Ethernet Adapter
+	    - Allied Telesyn AT-2971T Gigabit Ethernet Adapter
+	    - Belkin Gigabit Desktop Card 10/100/1000Base-T Adapter, Copper RJ-45
+	    - EG1032 v2 Instant Gigabit Network Adapter
+	    - EG1064 v2 Instant Gigabit Network Adapter
+	    - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Abit)
+	    - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Albatron)
+	    - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Asus)
+	    - Marvell 88E8001 Gigabit LOM Ethernet Adapter (ECS)
+	    - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Epox)
+	    - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Foxconn)
+	    - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Gigabyte)
+	    - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Iwill)
+	    - Marvell 88E8050 Gigabit LOM Ethernet Adapter (Intel)
+	    - Marvell RDK-8001 Adapter
+	    - Marvell RDK-8002 Adapter
+	    - Marvell RDK-8003 Adapter
+	    - Marvell RDK-8004 Adapter
+	    - Marvell RDK-8006 Adapter
+	    - Marvell RDK-8007 Adapter
+	    - Marvell RDK-8008 Adapter
+	    - Marvell RDK-8009 Adapter
+	    - Marvell RDK-8010 Adapter
+	    - Marvell RDK-8011 Adapter
+	    - Marvell RDK-8012 Adapter
+	    - Marvell RDK-8052 Adapter
+	    - Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (32 bit)
+	    - Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (64 bit)
+	    - N-Way PCI-Bus Giga-Card 1000/100/10Mbps(L)
+	    - SK-9521 10/100/1000Base-T Adapter
+	    - SK-9521 V2.0 10/100/1000Base-T Adapter
+	    - SK-9821 Gigabit Ethernet Server Adapter (SK-NET GE-T)
+	    - SK-9821 V2.0 Gigabit Ethernet 10/100/1000Base-T Adapter
+	    - SK-9822 Gigabit Ethernet Server Adapter (SK-NET GE-T dual link)
+	    - SK-9841 Gigabit Ethernet Server Adapter (SK-NET GE-LX)
+	    - SK-9841 V2.0 Gigabit Ethernet 1000Base-LX Adapter
+	    - SK-9842 Gigabit Ethernet Server Adapter (SK-NET GE-LX dual link)
+	    - SK-9843 Gigabit Ethernet Server Adapter (SK-NET GE-SX)
+	    - SK-9843 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+	    - SK-9844 Gigabit Ethernet Server Adapter (SK-NET GE-SX dual link)
+	    - SK-9851 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+	    - SK-9861 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition)
+	    - SK-9861 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+	    - SK-9862 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition dual link)
+	    - SK-9871 Gigabit Ethernet Server Adapter (SK-NET GE-ZX)
+	    - SK-9871 V2.0 Gigabit Ethernet 1000Base-ZX Adapter
+	    - SK-9872 Gigabit Ethernet Server Adapter (SK-NET GE-ZX dual link)
+	    - SMC EZ Card 1000 (SMC9452TXV.2)
+	  
+	  The adapters support Jumbo Frames.
+	  The dual link adapters support link-failover and dual port features.
+	  Both Marvell Yukon and SysKonnect SK-98xx/SK-95xx adapters support 
+	  the scatter-gather functionality with sendfile(). Please refer to 
+	  <file:Documentation/networking/sk98lin.txt> for more information about
+	  optional driver parameters.
+	  Questions concerning this driver may be addressed to:
+	      <linux@syskonnect.de>
+	  
+	  If you want to compile this driver as a module ( = code which can be
+	  inserted in and removed from the running kernel whenever you want),
+	  say M here and read <file:Documentation/kbuild/modules.txt>. The module will
+	  be called sk98lin. This is recommended.
+
+config VIA_VELOCITY
+	tristate "VIA Velocity support"
+	depends on PCI
+	select CRC32
+	select CRC_CCITT
+	select MII
+	help
+	  If you have a VIA "Velocity" based network card say Y here.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called via-velocity.
+
+config TIGON3
+	tristate "Broadcom Tigon3 support"
+	depends on PCI
+	help
+	  This driver supports Broadcom Tigon3 based gigabit Ethernet cards.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called tg3.  This is recommended.
+
+config BNX2
+	tristate "Broadcom NetXtremeII support"
+	depends on PCI
+	select CRC32
+	select ZLIB_INFLATE
+	help
+	  This driver supports Broadcom NetXtremeII gigabit Ethernet cards.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called bnx2.  This is recommended.
+
+config SPIDER_NET
+	tristate "Spider Gigabit Ethernet driver"
+	depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB)
+	select FW_LOADER
+	help
+	  This driver supports the Gigabit Ethernet chips present on the
+	  Cell Processor-Based Blades from IBM.
+
+config TSI108_ETH
+	   tristate "Tundra TSI108 gigabit Ethernet support"
+	   depends on TSI108_BRIDGE
+	   help
+	     This driver supports Tundra TSI108 gigabit Ethernet ports.
+	     To compile this driver as a module, choose M here: the module
+	     will be called tsi108_eth.
+
+config GELIC_NET
+	tristate "PS3 Gigabit Ethernet driver"
+	depends on PPC_PS3
+	help
+	  This driver supports the network device on the PS3 game
+	  console.  This driver has built-in support for Ethernet.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ps3_gelic.
+
+config GIANFAR
+	tristate "Gianfar Ethernet"
+	depends on 85xx || 83xx || PPC_86xx
+	select PHYLIB
+	select CRC32
+	help
+	  This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx,
+	  and MPC86xx family of chips, and the FEC on the 8540.
+
+config GFAR_NAPI
+	bool "Use Rx Polling (NAPI)"
+	depends on GIANFAR
+
+config UCC_GETH
+	tristate "Freescale QE Gigabit Ethernet"
+	depends on QUICC_ENGINE
+	select PHYLIB
+	help
+	  This driver supports the Gigabit Ethernet mode of the QUICC Engine,
+	  which is available on some Freescale SOCs.
+
+config UGETH_NAPI
+	bool "Use Rx Polling (NAPI)"
+	depends on UCC_GETH
+
+config UGETH_MAGIC_PACKET
+	bool "Magic Packet detection support"
+	depends on UCC_GETH
+
+config UGETH_FILTERING
+	bool "Mac address filtering support"
+	depends on UCC_GETH
+
+config UGETH_TX_ON_DEMAND
+	bool "Transmit on Demand support"
+	depends on UCC_GETH
+
+config MV643XX_ETH
+	tristate "Marvell Discovery (643XX) and Orion ethernet support"
+	depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || ARCH_ORION
+	select MII
+	help
+	  This driver supports the gigabit ethernet MACs in the
+	  Marvell Discovery PPC/MIPS chipset family (MV643XX) and
+	  in the Marvell Orion ARM SoC family.
+
+	  Some boards that use the Discovery chipset are the Momenco
+	  Ocelot C and Jaguar ATX and Pegasos II.
+
+config QLA3XXX
+	tristate "QLogic QLA3XXX Network Driver Support"
+	depends on PCI
+	help
+	  This driver supports QLogic ISP3XXX gigabit Ethernet cards.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called qla3xxx.
+
+config ATL1
+	tristate "Attansic L1 Gigabit Ethernet support (EXPERIMENTAL)"
+	depends on PCI && EXPERIMENTAL
+	select CRC32
+	select MII
+	help
+	  This driver supports the Attansic L1 gigabit ethernet adapter.
+
+	  To compile this driver as a module, choose M here.  The module
+	  will be called atl1.
+
+endif # NETDEV_1000
+
+#
+#	10 Gigabit Ethernet
+#
+
+menuconfig NETDEV_10000
+	bool "Ethernet (10000 Mbit)"
+	depends on !UML
+	default y
+	---help---
+	  Say Y here to get to see options for 10 Gigabit Ethernet drivers.
+	  This option alone does not add any kernel code.
+
+	  If you say N, all options in this submenu will be skipped and disabled.
+
+if NETDEV_10000
+
+config CHELSIO_T1
+        tristate "Chelsio 10Gb Ethernet support"
+        depends on PCI
+	select CRC32
+        help
+          This driver supports Chelsio gigabit and 10-gigabit
+          Ethernet cards. More information about adapter features and
+	  performance tuning is in <file:Documentation/networking/cxgb.txt>.
+
+          For general information about Chelsio and our products, visit
+          our website at <http://www.chelsio.com>.
+
+          For customer support, please visit our customer support page at
+          <http://www.chelsio.com/support.htm>.
+
+          Please send feedback to <linux-bugs@chelsio.com>.
+
+          To compile this driver as a module, choose M here: the module
+          will be called cxgb.
+
+config CHELSIO_T1_1G
+        bool "Chelsio gigabit Ethernet support"
+        depends on CHELSIO_T1
+        help
+          Enables support for Chelsio's gigabit Ethernet PCI cards.  If you
+          are using only 10G cards say 'N' here.
+
+config CHELSIO_T1_NAPI
+	bool "Use Rx Polling (NAPI)"
+	depends on CHELSIO_T1
+	default y
+	help
+	  NAPI is a driver API designed to reduce CPU and interrupt load
+	  when the driver is receiving lots of packets from the card.
+
+config CHELSIO_T3
+	tristate "Chelsio Communications T3 10Gb Ethernet support"
+	depends on PCI
+	select FW_LOADER
+	help
+	  This driver supports Chelsio T3-based gigabit and 10Gb Ethernet
+	  adapters.
+
+	  For general information about Chelsio and our products, visit
+	  our website at <http://www.chelsio.com>.
+
+	  For customer support, please visit our customer support page at
+	  <http://www.chelsio.com/support.htm>.
+
+	  Please send feedback to <linux-bugs@chelsio.com>.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called cxgb3.
+
+config EHEA
+	tristate "eHEA Ethernet support"
+	depends on IBMEBUS && INET
+	select INET_LRO
+	---help---
+	  This driver supports the IBM pSeries eHEA ethernet adapter.
+
+	  To compile the driver as a module, choose M here. The module
+	  will be called ehea.
+
+config IXGBE
+	tristate "Intel(R) 10GbE PCI Express adapters support"
+	depends on PCI
+	---help---
+	  This driver supports Intel(R) 10GbE PCI Express family of
+	  adapters.  For more information on how to identify your adapter, go
+	  to the Adapter & Driver ID Guide at:
+
+	  <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+	  For general information and support, go to the Intel support
+	  website at:
+
+	  <http://support.intel.com>
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called ixgbe.
+
+config IXGB
+	tristate "Intel(R) PRO/10GbE support"
+	depends on PCI
+	---help---
+	  This driver supports Intel(R) PRO/10GbE family of adapters for
+	  PCI-X type cards. For PCI-E type cards, use the "ixgbe" driver
+	  instead. For more information on how to identify your adapter, go
+	  to the Adapter & Driver ID Guide at:
+
+	  <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+	  For general information and support, go to the Intel support
+	  website at:
+
+	  <http://support.intel.com>
+
+	  More specific information on configuring the driver is in 
+	  <file:Documentation/networking/ixgb.txt>.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called ixgb.
+
+config IXGB_NAPI
+	bool "Use Rx Polling (NAPI) (EXPERIMENTAL)"
+	depends on IXGB && EXPERIMENTAL
+	help
+	  NAPI is a new driver API designed to reduce CPU and interrupt load
+	  when the driver is receiving lots of packets from the card. It is
+	  still somewhat experimental and thus not yet enabled by default.
+
+	  If your estimated Rx load is 10kpps or more, or if the card will be
+	  deployed on potentially unfriendly networks (e.g. in a firewall),
+	  then say Y here.
+
+	  If in doubt, say N.
+
+config S2IO
+	tristate "S2IO 10Gbe XFrame NIC"
+	depends on PCI
+	---help---
+	  This driver supports the 10Gbe XFrame NIC of S2IO. 
+	  More specific information on configuring the driver is in 
+	  <file:Documentation/networking/s2io.txt>.
+
+config S2IO_NAPI
+	bool "Use Rx Polling (NAPI) (EXPERIMENTAL)"
+	depends on S2IO && EXPERIMENTAL
+	help
+	  NAPI is a new driver API designed to reduce CPU and interrupt load
+	  when the driver is receiving lots of packets from the card. It is
+	  still somewhat experimental and thus not yet enabled by default.
+
+	  If your estimated Rx load is 10kpps or more, or if the card will be
+	  deployed on potentially unfriendly networks (e.g. in a firewall),
+	  then say Y here.
+
+	  If in doubt, say N.
+
+config MYRI10GE
+	tristate "Myricom Myri-10G Ethernet support"
+	depends on PCI && INET
+	select FW_LOADER
+	select CRC32
+	select INET_LRO
+	---help---
+	  This driver supports Myricom Myri-10G Dual Protocol interface in
+	  Ethernet mode. If the eeprom on your board is not recent enough,
+	  you will need a newer firmware image.
+	  You may get this image or more information, at:
+
+	  <http://www.myri.com/scs/download-Myri10GE.html>
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called myri10ge.
+
+config NETXEN_NIC
+	tristate "NetXen Multi port (1/10) Gigabit Ethernet NIC"
+	depends on PCI
+	help
+	  This enables the support for NetXen's Gigabit Ethernet card.
+
+config NIU
+	tristate "Sun Neptune 10Gbit Ethernet support"
+	depends on PCI
+	help
+	  This enables support for cards based upon Sun's
+	  Neptune chipset.
+
+config PASEMI_MAC
+	tristate "PA Semi 1/10Gbit MAC"
+	depends on PPC64 && PCI
+	select PHYLIB
+	help
+	  This driver supports the on-chip 1/10Gbit Ethernet controller on
+	  PA Semi's PWRficient line of chips.
+
+config MLX4_CORE
+	tristate
+	depends on PCI
+	default n
+
+config MLX4_DEBUG
+	bool "Verbose debugging output" if (MLX4_CORE && EMBEDDED)
+	depends on MLX4_CORE
+	default y
+	---help---
+	  This option causes debugging code to be compiled into the
+	  mlx4_core driver.  The output can be turned on via the
+	  debug_level module parameter (which can also be set after
+	  the driver is loaded through sysfs).
+
+config TEHUTI
+	tristate "Tehuti Networks 10G Ethernet"
+	depends on PCI
+	help
+	  Tehuti Networks 10G Ethernet NIC
+
+endif # NETDEV_10000
+
+source "drivers/net/tokenring/Kconfig"
+
+source "drivers/net/wireless/Kconfig"
+
+source "drivers/net/usb/Kconfig"
+
+source "drivers/net/pcmcia/Kconfig"
+
+source "drivers/net/wan/Kconfig"
+
+source "drivers/atm/Kconfig"
+
+source "drivers/s390/net/Kconfig"
+
+config XEN_NETDEV_FRONTEND
+	tristate "Xen network device frontend driver"
+	depends on XEN
+	default y
+	help
+	  The network device frontend driver allows the kernel to
+	  access network devices exported exported by a virtual
+	  machine containing a physical network device driver. The
+	  frontend driver is intended for unprivileged guest domains;
+	  if you are compiling a kernel for a Xen guest, you almost
+	  certainly want to enable this.
+
+config ISERIES_VETH
+	tristate "iSeries Virtual Ethernet driver support"
+	depends on PPC_ISERIES
+
+config RIONET
+	tristate "RapidIO Ethernet over messaging driver support"
+	depends on RAPIDIO
+
+config RIONET_TX_SIZE
+	int "Number of outbound queue entries"
+	depends on RIONET
+	default "128"
+
+config RIONET_RX_SIZE
+	int "Number of inbound queue entries"
+	depends on RIONET
+	default "128"
+
+config FDDI
+	bool "FDDI driver support"
+	depends on (PCI || EISA || TC)
+	help
+	  Fiber Distributed Data Interface is a high speed local area network
+	  design; essentially a replacement for high speed Ethernet. FDDI can
+	  run over copper or fiber. If you are connected to such a network and
+	  want a driver for the FDDI card in your computer, say Y here (and
+	  then also Y to the driver for your FDDI card, below). Most people
+	  will say N.
+
+config DEFXX
+	tristate "Digital DEFTA/DEFEA/DEFPA adapter support"
+	depends on FDDI && (PCI || EISA || TC)
+	---help---
+	  This is support for the DIGITAL series of TURBOchannel (DEFTA),
+	  EISA (DEFEA) and PCI (DEFPA) controllers which can connect you
+	  to a local FDDI network.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called defxx.  If unsure, say N.
+
+config DEFXX_MMIO
+	bool
+	prompt "Use MMIO instead of PIO" if PCI || EISA
+	depends on DEFXX
+	default n if PCI || EISA
+	default y
+	---help---
+	  This instructs the driver to use EISA or PCI memory-mapped I/O
+	  (MMIO) as appropriate instead of programmed I/O ports (PIO).
+	  Enabling this gives an improvement in processing time in parts
+	  of the driver, but it may cause problems with EISA (DEFEA)
+	  adapters.  TURBOchannel does not have the concept of I/O ports,
+	  so MMIO is always used for these (DEFTA) adapters.
+
+	  If unsure, say N.
+
+config SKFP
+	tristate "SysKonnect FDDI PCI support"
+	depends on FDDI && PCI
+	select BITREVERSE
+	---help---
+	  Say Y here if you have a SysKonnect FDDI PCI adapter.
+	  The following adapters are supported by this driver:
+	  - SK-5521 (SK-NET FDDI-UP)
+	  - SK-5522 (SK-NET FDDI-UP DAS)
+	  - SK-5541 (SK-NET FDDI-FP)
+	  - SK-5543 (SK-NET FDDI-LP)
+	  - SK-5544 (SK-NET FDDI-LP DAS)
+	  - SK-5821 (SK-NET FDDI-UP64)
+	  - SK-5822 (SK-NET FDDI-UP64 DAS)
+	  - SK-5841 (SK-NET FDDI-FP64)
+	  - SK-5843 (SK-NET FDDI-LP64)
+	  - SK-5844 (SK-NET FDDI-LP64 DAS)
+	  - Netelligent 100 FDDI DAS Fibre SC
+	  - Netelligent 100 FDDI SAS Fibre SC
+	  - Netelligent 100 FDDI DAS UTP
+	  - Netelligent 100 FDDI SAS UTP
+	  - Netelligent 100 FDDI SAS Fibre MIC
+
+	  Read <file:Documentation/networking/skfp.txt> for information about
+	  the driver.
+
+	  Questions concerning this driver can be addressed to:
+	  <linux@syskonnect.de>
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called skfp.  This is recommended.
+
+config HIPPI
+	bool "HIPPI driver support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && INET && PCI
+	help
+	  HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and
+	  1600Mbit/sec dual-simplex switched or point-to-point network. HIPPI
+	  can run over copper (25m) or fiber (300m on multi-mode or 10km on
+	  single-mode). HIPPI networks are commonly used for clusters and to
+	  connect to super computers. If you are connected to a HIPPI network
+	  and have a HIPPI network card in your computer that you want to use
+	  under Linux, say Y here (you must also remember to enable the driver
+	  for your HIPPI card below). Most people will say N here.
+
+config ROADRUNNER
+	tristate "Essential RoadRunner HIPPI PCI adapter support (EXPERIMENTAL)"
+	depends on HIPPI && PCI
+	help
+	  Say Y here if this is your PCI HIPPI network card.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called rrunner.  If unsure, say N.
+
+config ROADRUNNER_LARGE_RINGS
+	bool "Use large TX/RX rings (EXPERIMENTAL)"
+	depends on ROADRUNNER
+	help
+	  If you say Y here, the RoadRunner driver will preallocate up to 2 MB
+	  of additional memory to allow for fastest operation, both for
+	  transmitting and receiving. This memory cannot be used by any other
+	  kernel code or by user space programs. Say Y here only if you have
+	  the memory.
+
+config PLIP
+	tristate "PLIP (parallel port) support"
+	depends on PARPORT
+	---help---
+	  PLIP (Parallel Line Internet Protocol) is used to create a
+	  reasonably fast mini network consisting of two (or, rarely, more)
+	  local machines.  A PLIP link from a Linux box is a popular means to
+	  install a Linux distribution on a machine which doesn't have a
+	  CD-ROM drive (a minimal system has to be transferred with floppies
+	  first). The kernels on both machines need to have this PLIP option
+	  enabled for this to work.
+
+	  The PLIP driver has two modes, mode 0 and mode 1.  The parallel
+	  ports (the connectors at the computers with 25 holes) are connected
+	  with "null printer" or "Turbo Laplink" cables which can transmit 4
+	  bits at a time (mode 0) or with special PLIP cables, to be used on
+	  bidirectional parallel ports only, which can transmit 8 bits at a
+	  time (mode 1); you can find the wiring of these cables in
+	  <file:Documentation/networking/PLIP.txt>.  The cables can be up to
+	  15m long.  Mode 0 works also if one of the machines runs DOS/Windows
+	  and has some PLIP software installed, e.g. the Crynwr PLIP packet
+	  driver (<http://oak.oakland.edu/simtel.net/msdos/pktdrvr-pre.html>)
+	  and winsock or NCSA's telnet.
+
+	  If you want to use PLIP, say Y and read the PLIP mini-HOWTO as well
+	  as the NET-3-HOWTO, both available from
+	  <http://www.tldp.org/docs.html#howto>.  Note that the PLIP
+	  protocol has been changed and this PLIP driver won't work together
+	  with the PLIP support in Linux versions 1.0.x.  This option enlarges
+	  your kernel by about 8 KB.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called plip. If unsure, say Y or M, in case you buy
+	  a laptop later.
+
+config PPP
+	tristate "PPP (point-to-point protocol) support"
+	select SLHC
+	---help---
+	  PPP (Point to Point Protocol) is a newer and better SLIP.  It serves
+	  the same purpose: sending Internet traffic over telephone (and other
+	  serial) lines.  Ask your access provider if they support it, because
+	  otherwise you can't use it; most Internet access providers these
+	  days support PPP rather than SLIP.
+
+	  To use PPP, you need an additional program called pppd as described
+	  in the PPP-HOWTO, available at
+	  <http://www.tldp.org/docs.html#howto>.  Make sure that you have
+	  the version of pppd recommended in <file:Documentation/Changes>.
+	  The PPP option enlarges your kernel by about 16 KB.
+
+	  There are actually two versions of PPP: the traditional PPP for
+	  asynchronous lines, such as regular analog phone lines, and
+	  synchronous PPP which can be used over digital ISDN lines for
+	  example.  If you want to use PPP over phone lines or other
+	  asynchronous serial lines, you need to say Y (or M) here and also to
+	  the next option, "PPP support for async serial ports".  For PPP over
+	  synchronous lines, you should say Y (or M) here and to "Support
+	  synchronous PPP", below.
+
+	  If you said Y to "Version information on all symbols" above, then
+	  you cannot compile the PPP driver into the kernel; you can then only
+	  compile it as a module. To compile this driver as a module, choose M
+	  here. The module will be called ppp_generic.
+
+config PPP_MULTILINK
+	bool "PPP multilink support (EXPERIMENTAL)"
+	depends on PPP && EXPERIMENTAL
+	help
+	  PPP multilink is a protocol (defined in RFC 1990) which allows you
+	  to combine several (logical or physical) lines into one logical PPP
+	  connection, so that you can utilize your full bandwidth.
+
+	  This has to be supported at the other end as well and you need a
+	  version of the pppd daemon which understands the multilink protocol.
+
+	  If unsure, say N.
+
+config PPP_FILTER
+	bool "PPP filtering"
+	depends on PPP
+	help
+	  Say Y here if you want to be able to filter the packets passing over
+	  PPP interfaces.  This allows you to control which packets count as
+	  activity (i.e. which packets will reset the idle timer or bring up
+	  a demand-dialed link) and which packets are to be dropped entirely.
+	  You need to say Y here if you wish to use the pass-filter and
+	  active-filter options to pppd.
+
+	  If unsure, say N.
+
+config PPP_ASYNC
+	tristate "PPP support for async serial ports"
+	depends on PPP
+	select CRC_CCITT
+	---help---
+	  Say Y (or M) here if you want to be able to use PPP over standard
+	  asynchronous serial ports, such as COM1 or COM2 on a PC.  If you use
+	  a modem (not a synchronous or ISDN modem) to contact your ISP, you
+	  need this option.
+
+	  To compile this driver as a module, choose M here.
+
+	  If unsure, say Y.
+
+config PPP_SYNC_TTY
+	tristate "PPP support for sync tty ports"
+	depends on PPP
+	help
+	  Say Y (or M) here if you want to be able to use PPP over synchronous
+	  (HDLC) tty devices, such as the SyncLink adapter. These devices
+	  are often used for high-speed leased lines like T1/E1.
+
+	  To compile this driver as a module, choose M here.
+
+config PPP_DEFLATE
+	tristate "PPP Deflate compression"
+	depends on PPP
+	select ZLIB_INFLATE
+	select ZLIB_DEFLATE
+	---help---
+	  Support for the Deflate compression method for PPP, which uses the
+	  Deflate algorithm (the same algorithm that gzip uses) to compress
+	  each PPP packet before it is sent over the wire.  The machine at the
+	  other end of the PPP link (usually your ISP) has to support the
+	  Deflate compression method as well for this to be useful.  Even if
+	  they don't support it, it is safe to say Y here.
+
+	  To compile this driver as a module, choose M here.
+
+config PPP_BSDCOMP
+	tristate "PPP BSD-Compress compression"
+	depends on PPP
+	---help---
+	  Support for the BSD-Compress compression method for PPP, which uses
+	  the LZW compression method to compress each PPP packet before it is
+	  sent over the wire. The machine at the other end of the PPP link
+	  (usually your ISP) has to support the BSD-Compress compression
+	  method as well for this to be useful. Even if they don't support it,
+	  it is safe to say Y here.
+
+	  The PPP Deflate compression method ("PPP Deflate compression",
+	  above) is preferable to BSD-Compress, because it compresses better
+	  and is patent-free.
+
+	  Note that the BSD compression code will always be compiled as a
+	  module; it is called bsd_comp and will show up in the directory
+	  modules once you have said "make modules". If unsure, say N.
+
+config PPP_MPPE
+       tristate "PPP MPPE compression (encryption) (EXPERIMENTAL)"
+       depends on PPP && EXPERIMENTAL
+       select CRYPTO
+       select CRYPTO_SHA1
+       select CRYPTO_ARC4
+       select CRYPTO_ECB
+       ---help---
+         Support for the MPPE Encryption protocol, as employed by the
+	 Microsoft Point-to-Point Tunneling Protocol.
+
+	 See http://pptpclient.sourceforge.net/ for information on
+	 configuring PPTP clients and servers to utilize this method.
+
+config PPPOE
+	tristate "PPP over Ethernet (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && PPP
+	help
+	  Support for PPP over Ethernet.
+
+	  This driver requires the latest version of pppd from the CVS
+	  repository at cvs.samba.org.  Alternatively, see the 
+	  RoaringPenguin package (<http://www.roaringpenguin.com/pppoe>)
+	  which contains instruction on how to use this driver (under 
+	  the heading "Kernel mode PPPoE").
+
+config PPPOATM
+	tristate "PPP over ATM"
+	depends on ATM && PPP
+	help
+	  Support PPP (Point to Point Protocol) encapsulated in ATM frames.
+	  This implementation does not yet comply with section 8 of RFC2364,
+	  which can lead to bad results if the ATM peer loses state and
+	  changes its encapsulation unilaterally.
+
+config PPPOL2TP
+	tristate "PPP over L2TP (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && PPP && INET
+	help
+	  Support for PPP-over-L2TP socket family. L2TP is a protocol
+	  used by ISPs and enterprises to tunnel PPP traffic over UDP
+	  tunnels. L2TP is replacing PPTP for VPN uses.
+
+	  This kernel component handles only L2TP data packets: a
+	  userland daemon handles L2TP the control protocol (tunnel
+	  and session setup). One such daemon is OpenL2TP
+	  (http://openl2tp.sourceforge.net/).
+
+config SLIP
+	tristate "SLIP (serial line) support"
+	---help---
+	  Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to
+	  connect to your Internet service provider or to connect to some
+	  other local Unix box or if you want to configure your Linux box as a
+	  Slip/CSlip server for other people to dial in. SLIP (Serial Line
+	  Internet Protocol) is a protocol used to send Internet traffic over
+	  serial connections such as telephone lines or null modem cables;
+	  nowadays, the protocol PPP is more commonly used for this same
+	  purpose.
+
+	  Normally, your access provider has to support SLIP in order for you
+	  to be able to use it, but there is now a SLIP emulator called SLiRP
+	  around (available from
+	  <ftp://ibiblio.org/pub/Linux/system/network/serial/>) which
+	  allows you to use SLIP over a regular dial up shell connection. If
+	  you plan to use SLiRP, make sure to say Y to CSLIP, below. The
+	  NET-3-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>, explains how to
+	  configure SLIP. Note that you don't need this option if you just
+	  want to run term (term is a program which gives you almost full
+	  Internet connectivity if you have a regular dial up shell account on
+	  some Internet connected Unix computer. Read
+	  <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>). SLIP
+	  support will enlarge your kernel by about 4 KB. If unsure, say N.
+
+	  To compile this driver as a module, choose M here. The module
+	  will be called slip.
+
+config SLIP_COMPRESSED
+	bool "CSLIP compressed headers"
+	depends on SLIP
+	select SLHC
+	---help---
+	  This protocol is faster than SLIP because it uses compression on the
+	  TCP/IP headers (not on the data itself), but it has to be supported
+	  on both ends. Ask your access provider if you are not sure and
+	  answer Y, just in case. You will still be able to use plain SLIP. If
+	  you plan to use SLiRP, the SLIP emulator (available from
+	  <ftp://ibiblio.org/pub/Linux/system/network/serial/>) which
+	  allows you to use SLIP over a regular dial up shell connection, you
+	  definitely want to say Y here. The NET-3-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>, explains how to configure
+	  CSLIP. This won't enlarge your kernel.
+
+config SLHC
+	tristate
+	help
+	  This option enables Van Jacobsen serial line header compression
+	  routines.
+
+config SLIP_SMART
+	bool "Keepalive and linefill"
+	depends on SLIP
+	help
+	  Adds additional capabilities to the SLIP driver to support the
+	  RELCOM line fill and keepalive monitoring. Ideal on poor quality
+	  analogue lines.
+
+config SLIP_MODE_SLIP6
+	bool "Six bit SLIP encapsulation"
+	depends on SLIP
+	help
+	  Just occasionally you may need to run IP over hostile serial
+	  networks that don't pass all control characters or are only seven
+	  bit. Saying Y here adds an extra mode you can use with SLIP:
+	  "slip6". In this mode, SLIP will only send normal ASCII symbols over
+	  the serial device. Naturally, this has to be supported at the other
+	  end of the link as well. It's good enough, for example, to run IP
+	  over the async ports of a Camtec JNT Pad. If unsure, say N.
+
+config NET_FC
+	bool "Fibre Channel driver support"
+	depends on SCSI && PCI
+	help
+	  Fibre Channel is a high speed serial protocol mainly used to connect
+	  large storage devices to the computer; it is compatible with and
+	  intended to replace SCSI.
+
+	  If you intend to use Fibre Channel, you need to have a Fibre channel
+	  adaptor card in your computer; say Y here and to the driver for your
+	  adaptor below. You also should have said Y to "SCSI support" and
+	  "SCSI generic support".
+
+config SHAPER
+	tristate "Traffic Shaper (OBSOLETE)"
+	depends on EXPERIMENTAL
+	---help---
+	  The traffic shaper is a virtual network device that allows you to
+	  limit the rate of outgoing data flow over some other network device.
+	  The traffic that you want to slow down can then be routed through
+	  these virtual devices. See
+	  <file:Documentation/networking/shaper.txt> for more information.
+
+	  An alternative to this traffic shaper are traffic schedulers which
+	  you'll get if you say Y to "QoS and/or fair queuing" in
+	  "Networking options".
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called shaper.  If unsure, say N.
+
+config NETCONSOLE
+	tristate "Network console logging support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	---help---
+	If you want to log kernel messages over the network, enable this.
+	See <file:Documentation/networking/netco
