Submitted By: Jim Gifford (patches at jg555 dot com)
Date: 2006-11-29
Initial Package Version: 2.6.19
Origin: Gentoo - Jeff Waters
Upstream Status: N/A
Description: Adds Support for the x86 Cobalt Series

diff -Naur linux-2.6.19.orig/Makefile linux-2.6.19/Makefile
--- linux-2.6.19.orig/Makefile	2006-11-29 13:57:37.000000000 -0800
+++ linux-2.6.19/Makefile	2006-11-29 19:13:54.000000000 -0800
@@ -203,6 +203,7 @@
 KBUILD_MODULES :=
 KBUILD_BUILTIN := 1
 
+DRIVERS-$(CONFIG_COBALT_RAQ) += drivers/cobalt/cobalt.o
 #	If we have only "make modules", don't compile built-in objects.
 #	When we're building modules with modversions, we need to consider
 #	the built-in objects during the descend as well, in order to
@@ -709,6 +710,11 @@
       cmd_kallsyms = $(NM) -n $< | $(KALLSYMS) \
                      $(if $(CONFIG_KALLSYMS_ALL),--all-symbols) > $@
 
+
+cobalt: vmlinux
+	strip vmlinux
+	bzip2 vmlinux
+
 .tmp_kallsyms1.o .tmp_kallsyms2.o .tmp_kallsyms3.o: %.o: %.S scripts FORCE
 	$(call if_changed_dep,as_o_S)
 
diff -Naur linux-2.6.19.orig/arch/i386/kernel/Makefile linux-2.6.19/arch/i386/kernel/Makefile
--- linux-2.6.19.orig/arch/i386/kernel/Makefile	2006-11-29 13:57:37.000000000 -0800
+++ linux-2.6.19/arch/i386/kernel/Makefile	2006-11-29 19:13:54.000000000 -0800
@@ -52,6 +52,7 @@
 targets += vsyscall-note.o vsyscall.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 -Naur linux-2.6.19.orig/arch/i386/kernel/cobalt.c linux-2.6.19/arch/i386/kernel/cobalt.c
--- linux-2.6.19.orig/arch/i386/kernel/cobalt.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/arch/i386/kernel/cobalt.c	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,281 @@
+/* $Id: cobalt.c,v 1.34 2002/11/04 17:54:14 thockin Exp $ */
+/* #include <linux/config.h> */
+
+#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 -Naur linux-2.6.19.orig/arch/i386/kernel/process.c linux-2.6.19/arch/i386/kernel/process.c
--- linux-2.6.19.orig/arch/i386/kernel/process.c	2006-11-29 13:57:37.000000000 -0800
+++ linux-2.6.19/arch/i386/kernel/process.c	2006-11-29 19:13:54.000000000 -0800
@@ -52,6 +52,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>
@@ -483,6 +488,12 @@
 void dump_thread(struct pt_regs * regs, struct user * dump)
 {
 	int i;
+	
+#ifdef CONFIG_COBALT_RAQ
+	cobalt_flush();
+	cobalt_restart();
+#endif
+
 
 /* changed the size calculations - should hopefully work better. lbt */
 	dump->magic = CMAGIC;
diff -Naur linux-2.6.19.orig/arch/i386/kernel/reboot.c linux-2.6.19/arch/i386/kernel/reboot.c
--- linux-2.6.19.orig/arch/i386/kernel/reboot.c	2006-11-29 13:57:37.000000000 -0800
+++ linux-2.6.19/arch/i386/kernel/reboot.c	2006-11-29 19:13:54.000000000 -0800
@@ -18,6 +18,11 @@
 #include "mach_reboot.h"
 #include <linux/reboot_fixups.h>
 
+#ifdef CONFIG_COBALT_RAQ
+#include <cobalt/misc.h>
+#include <cobalt/lcd.h>
+#endif
+
 /*
  * Power off function, if any
  */
@@ -279,8 +284,38 @@
 EXPORT_SYMBOL(machine_real_restart);
 #endif
 
+/* kill some time at halt/reboot to allow drives with large cache to sync */
+
+#ifdef CONFIG_COBALT_RAQ
+void cobalt_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");
+}
+#endif
+
 void machine_shutdown(void)
 {
+#ifdef CONFIG_COBALT_RAQ
+	cobalt_flush();
+	cobalt_halt();
+#endif
+
 #ifdef CONFIG_SMP
 	int reboot_cpu_id;
 
@@ -317,6 +352,9 @@
 
 void 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);
@@ -341,6 +379,10 @@
 
 void machine_restart(char * __unused)
 {
+#ifdef CONFIG_COBALT_RAQ
+	cobalt_flush();
+	cobalt_restart();
+#endif
 	machine_shutdown();
 	machine_emergency_restart();
 }
diff -Naur linux-2.6.19.orig/arch/i386/kernel/traps.c linux-2.6.19/arch/i386/kernel/traps.c
--- linux-2.6.19.orig/arch/i386/kernel/traps.c	2006-11-29 13:57:37.000000000 -0800
+++ linux-2.6.19/arch/i386/kernel/traps.c	2006-11-29 19:15:56.000000000 -0800
@@ -59,6 +59,10 @@
 
 int panic_on_unrecovered_nmi;
 
+#ifdef CONFIG_COBALT_RAQ
+#include <cobalt/misc.h>
+#endif
+
 asmlinkage int system_call(void);
 
 struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 },
@@ -705,6 +709,9 @@
 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 probably have a hardware problem with your RAM "
@@ -713,7 +720,7 @@
                 panic("NMI: Not continuing");
 
 	printk(KERN_EMERG "Dazed and confused, but trying to continue\n");
-
+#endif
 	/* Clear and disable the memory parity error line. */
 	clear_mem_error(reason);
 }
diff -Naur linux-2.6.19.orig/drivers/Kconfig linux-2.6.19/drivers/Kconfig
--- linux-2.6.19.orig/drivers/Kconfig	2006-11-29 13:57:37.000000000 -0800
+++ linux-2.6.19/drivers/Kconfig	2006-11-29 19:13:54.000000000 -0800
@@ -78,4 +78,6 @@
 
 source "drivers/dma/Kconfig"
 
+source "drivers/cobalt/Kconfig"
+
 endmenu
diff -Naur linux-2.6.19.orig/drivers/Makefile linux-2.6.19/drivers/Makefile
--- linux-2.6.19.orig/drivers/Makefile	2006-11-29 13:57:37.000000000 -0800
+++ linux-2.6.19/drivers/Makefile	2006-11-29 19:13:54.000000000 -0800
@@ -66,6 +66,8 @@
 obj-$(CONFIG_EDAC)		+= edac/
 obj-$(CONFIG_MCA)		+= mca/
 obj-$(CONFIG_EISA)		+= eisa/
+obj-$(CONFIG_COBALT_RAQ)	+= cobalt/
+
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
 obj-$(CONFIG_MMC)		+= mmc/
 obj-$(CONFIG_NEW_LEDS)		+= leds/
diff -Naur linux-2.6.19.orig/drivers/char/Kconfig linux-2.6.19/drivers/char/Kconfig
--- linux-2.6.19.orig/drivers/char/Kconfig	2006-11-29 13:57:37.000000000 -0800
+++ linux-2.6.19/drivers/char/Kconfig	2006-11-29 19:13:54.000000000 -0800
@@ -793,7 +793,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 -Naur linux-2.6.19.orig/drivers/char/Makefile linux-2.6.19/drivers/char/Makefile
--- linux-2.6.19.orig/drivers/char/Makefile	2006-11-29 13:57:37.000000000 -0800
+++ linux-2.6.19/drivers/char/Makefile	2006-11-29 19:13:54.000000000 -0800
@@ -79,7 +79,7 @@
 obj-$(CONFIG_DS1620)		+= ds1620.o
 obj-$(CONFIG_HW_RANDOM)		+= hw_random/
 obj-$(CONFIG_FTAPE)		+= ftape/
-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 -Naur linux-2.6.19.orig/drivers/char/misc.c linux-2.6.19/drivers/char/misc.c
--- linux-2.6.19.orig/drivers/char/misc.c	2006-11-29 13:57:37.000000000 -0800
+++ linux-2.6.19/drivers/char/misc.c	2006-11-29 19:13:54.000000000 -0800
@@ -49,6 +49,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
  */
@@ -63,6 +74,13 @@
 
 extern int pmu_device_init(void);
 
+#ifdef CONFIG_COBALT_RAQ
+extern int cobalt_init(void);
+#endif
+#ifdef CONFIG_COBALT_MIPS_LCD
+module_init(lcd_init);
+#endif
+
 #ifdef CONFIG_PROC_FS
 static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
 {
diff -Naur linux-2.6.19.orig/drivers/char/nvram.c linux-2.6.19/drivers/char/nvram.c
--- linux-2.6.19.orig/drivers/char/nvram.c	2006-11-29 13:57:37.000000000 -0800
+++ linux-2.6.19/drivers/char/nvram.c	2006-11-29 19:13:54.000000000 -0800
@@ -49,8 +49,7 @@
 #if defined(CONFIG_ATARI)
 #  define MACH ATARI
 #elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)  /* and others?? */
-#define MACH PC
-#  if defined(CONFIG_COBALT)
+#  if defined(CONFIG_COBALT_RAQ)
 #    include <linux/cobalt-nvram.h>
 #    define MACH COBALT
 #  else
diff -Naur linux-2.6.19.orig/drivers/cobalt/Kconfig linux-2.6.19/drivers/cobalt/Kconfig
--- linux-2.6.19.orig/drivers/cobalt/Kconfig	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/drivers/cobalt/Kconfig	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,133 @@
+#
+# 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
+	default y
+	---help---
+	  Creates entries in /proc/cobalt which provide useful information about
+	  your RaQ/Qube.  Best to say Y here.
+
+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_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 -Naur linux-2.6.19.orig/drivers/cobalt/Makefile linux-2.6.19/drivers/cobalt/Makefile
--- linux-2.6.19.orig/drivers/cobalt/Makefile	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/drivers/cobalt/Makefile	2006-11-29 19:13:54.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
+
diff -Naur linux-2.6.19.orig/drivers/cobalt/README linux-2.6.19/drivers/cobalt/README
--- linux-2.6.19.orig/drivers/cobalt/README	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/drivers/cobalt/README	2006-11-29 19:13:54.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 -Naur linux-2.6.19.orig/drivers/cobalt/acpi.c linux-2.6.19/drivers/cobalt/acpi.c
--- linux-2.6.19.orig/drivers/cobalt/acpi.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/drivers/cobalt/acpi.c	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,1994 @@
+ /* 
+ * 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/config.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 -Naur linux-2.6.19.orig/drivers/cobalt/fans.c linux-2.6.19/drivers/cobalt/fans.c
--- linux-2.6.19.orig/drivers/cobalt/fans.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/drivers/cobalt/fans.c	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,419 @@
+/* $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
+ */
+/* #include <linux/config.h> */
+#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 -Naur linux-2.6.19.orig/drivers/cobalt/i2c.c linux-2.6.19/drivers/cobalt/i2c.c
--- linux-2.6.19.orig/drivers/cobalt/i2c.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/drivers/cobalt/i2c.c	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,519 @@
+/*
+ * $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/config.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 -Naur linux-2.6.19.orig/drivers/cobalt/init.c linux-2.6.19/drivers/cobalt/init.c
--- linux-2.6.19.orig/drivers/cobalt/init.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/drivers/cobalt/init.c	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,114 @@
+/* $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/config.h> */
+#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>
+
+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
+    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 -Naur linux-2.6.19.orig/drivers/cobalt/lcd.c linux-2.6.19/drivers/cobalt/lcd.c
--- linux-2.6.19.orig/drivers/cobalt/lcd.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/drivers/cobalt/lcd.c	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,835 @@
+/*
+ * $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
+ */
+
+/* #include <linux/config.h> */
+
+#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
+
+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 -Naur linux-2.6.19.orig/drivers/cobalt/led.c linux-2.6.19/drivers/cobalt/led.c
--- linux-2.6.19.orig/drivers/cobalt/led.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/drivers/cobalt/led.c	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,504 @@
+ /*
+ * $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).
+ */
+
+/* #include <linux/config.h> */
+
+#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 -Naur linux-2.6.19.orig/drivers/cobalt/net.c linux-2.6.19/drivers/cobalt/net.c
--- linux-2.6.19.orig/drivers/cobalt/net.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/drivers/cobalt/net.c	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,133 @@
+/* 
+ * 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/config.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 -Naur linux-2.6.19.orig/drivers/cobalt/raminfo.c linux-2.6.19/drivers/cobalt/raminfo.c
--- linux-2.6.19.orig/drivers/cobalt/raminfo.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/drivers/cobalt/raminfo.c	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,320 @@
+/* $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
+ */
+/* #include <linux/config.h> */
+
+#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 -Naur linux-2.6.19.orig/drivers/cobalt/ruler.c linux-2.6.19/drivers/cobalt/ruler.c
--- linux-2.6.19.orig/drivers/cobalt/ruler.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/drivers/cobalt/ruler.c	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,419 @@
+/* 
+ * 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/config.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 -Naur linux-2.6.19.orig/drivers/cobalt/sensors.c linux-2.6.19/drivers/cobalt/sensors.c
--- linux-2.6.19.orig/drivers/cobalt/sensors.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/drivers/cobalt/sensors.c	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,525 @@
+/* $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.
+ */
+/* #include <linux/config.h> */
+#ifdef CONFIG_COBALT_SENSORS
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+/* #include <linux/config.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 -Naur linux-2.6.19.orig/drivers/cobalt/serialnum.c linux-2.6.19/drivers/cobalt/serialnum.c
--- linux-2.6.19.orig/drivers/cobalt/serialnum.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/drivers/cobalt/serialnum.c	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,453 @@
+/* $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
+ */
+/* #include <linux/config.h> */
+#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 -Naur linux-2.6.19.orig/drivers/cobalt/systype.c linux-2.6.19/drivers/cobalt/systype.c
--- linux-2.6.19.orig/drivers/cobalt/systype.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/drivers/cobalt/systype.c	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,280 @@
+/*
+ * $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/config.h> */
+
+#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 -Naur linux-2.6.19.orig/drivers/cobalt/wdt.c linux-2.6.19/drivers/cobalt/wdt.c
--- linux-2.6.19.orig/drivers/cobalt/wdt.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/drivers/cobalt/wdt.c	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,424 @@
+/* $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/config.h> */
+
+#include <linux/module.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+/* #include <linux/config.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 -Naur linux-2.6.19.orig/drivers/net/Kconfig linux-2.6.19/drivers/net/Kconfig
--- linux-2.6.19.orig/drivers/net/Kconfig	2006-11-29 13:57:37.000000000 -0800
+++ linux-2.6.19/drivers/net/Kconfig	2006-11-29 19:13:54.000000000 -0800
@@ -1516,6 +1516,16 @@
 	  <file:Documentation/networking/net-modules.txt>.  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 -Naur linux-2.6.19.orig/drivers/net/e100.c linux-2.6.19/drivers/net/e100.c
--- linux-2.6.19.orig/drivers/net/e100.c	2006-11-29 13:57:37.000000000 -0800
+++ linux-2.6.19/drivers/net/e100.c	2006-11-29 19:17:22.000000000 -0800
@@ -162,6 +162,7 @@
 #define DRV_VERSION		"3.5.17-k2"DRV_EXT
 #define DRV_DESCRIPTION		"Intel(R) PRO/100 Network Driver"
 #define DRV_COPYRIGHT		"Copyright(c) 1999-2006 Intel Corporation"
+#define DRV_MODIFIED		"Modified by <jeff@404ster.com> to ignore bad EEPROM checksums"
 #define PFX			DRV_NAME ": "
 
 #define E100_WATCHDOG_PERIOD	(2 * HZ)
@@ -758,9 +759,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;
@@ -2880,6 +2887,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 -Naur linux-2.6.19.orig/include/cobalt/acpi.h linux-2.6.19/include/cobalt/acpi.h
--- linux-2.6.19.orig/include/cobalt/acpi.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/include/cobalt/acpi.h	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,82 @@
+/*
+ * $Id: cobalt-acpi.h,v 1.7 2001/10/27 07:03:31 erik Exp $
+ * cobalt-acpi.h : support for ACPI interrupts
+ *
+ * Copyright 2000 Cobalt Networks, Inc.
+ * Copyright 2001 Sun Microsystems, Inc.
+ */
+#ifndef COBALT_ACPI_H
+#define COBALT_ACPI_H
+
+#define SERVERWORKS_ACPI_INDEX_PORT	0x0cd6
+#define SERVERWORKS_ACPI_DATA_PORT	0x0cd7
+
+
+typedef struct
+{
+    u16 hw_type;
+    u16 ev_type;
+    u32 ev_data;
+} cobalt_acpi_evt;
+
+enum __cobalt_acpi_hw_types
+{
+    COBALT_ACPI_HW_ANY = 0x0000,
+    COBALT_ACPI_HW_OSB4 = 0x0001,
+    COBALT_ACPI_HW_CSB5 = 0x0002,
+    COBALT_ACPI_HW_PC8731X = 0x0003,
+    COBALT_ACPI_HW_PC8741X = 0x0004,
+};
+
+enum __cobalt_acpi_event_types
+{
+    COBALT_ACPI_EVT_NONE = 0x0000,
+    COBALT_ACPI_EVT_TMR = 0x0001, /* Timer Event */
+    COBALT_ACPI_EVT_BM = 0x00002, /* Bus Master Event */
+    COBALT_ACPI_EVT_GBL = 0x0003, /* BIOS Global Lock release */
+    COBALT_ACPI_EVT_PWRBTN = 0x0004, /* Power Button press */
+    COBALT_ACPI_EVT_SLPBTN = 0x0005, /* Sleep Button press */
+    COBALT_ACPI_EVT_RTC = 0x0006, /* RTC Alarm */
+    COBALT_ACPI_EVT_WAK = 0x0007, /* Wake event */
+    COBALT_ACPI_EVT_GPE = 0x0008, /* General Purpose Event (ev_data = gpe number) */
+
+	/* events greater than 0x7fff are symbolic events */
+    COBALT_ACPI_EVT_SLED = 0x8000, /* Sled removal */
+    COBALT_ACPI_EVT_THERM = 0x8001, /* Thermal trip */
+    COBALT_ACPI_EVT_FAN = 0x8002, /* Fan Down */
+    COBALT_ACPI_EVT_SM_INT = 0x8003, /* System Monitor Interrupt */
+    COBALT_ACPI_EVT_VOLT = 0x8004, /* System Monitor Interrupt */
+    
+};
+
+typedef int (* cobalt_acpi_hw_handler)( int irq, void *dev_id, struct pt_regs *regs, void * data );
+typedef int (* cobalt_acpi_enable_handler)( u16 ev_type, u16 ev_data, int en, void *data );
+typedef int (* cobalt_acpi_evt_handler)( cobalt_acpi_evt *evt, void * data );
+
+
+extern int cobalt_acpi_register_hw_handler( u16 hw_type,
+					    cobalt_acpi_hw_handler hw_handler, 
+					    cobalt_acpi_enable_handler en_handler,
+					    void *data );
+extern int cobalt_acpi_unregister_hw_handler( cobalt_acpi_hw_handler handler );
+
+extern int cobalt_acpi_register_trans_table( u16 hw_type, u16 table_len, u16 *table ); 
+extern int cobalt_acpi_unregister_trans_table( u16 hw_type );
+
+extern int cobalt_acpi_register_evt_handler( cobalt_acpi_evt_handler handler, 
+					     u16 evt_type,
+					     void *data );
+extern int cobalt_acpi_unregister_evt_handler( cobalt_acpi_evt_handler handler );
+
+extern int cobalt_acpi_post_event( cobalt_acpi_evt evt );
+
+#ifdef CONFIG_COBALT_EMU_ACPI
+int cobalt_acpi_generate_proc_evt( cobalt_acpi_evt * evt );
+#else
+#define cobalt_acpi_generate_proc_evt( a )
+#endif
+
+    
+
+
+#endif /* COBALT_ACPI_H */
diff -Naur linux-2.6.19.orig/include/cobalt/cobalt.h linux-2.6.19/include/cobalt/cobalt.h
--- linux-2.6.19.orig/include/cobalt/cobalt.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/include/cobalt/cobalt.h	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,58 @@
+/* $Id: cobalt.h,v 1.16 2002/11/04 17:54:15 thockin Exp $ */
+/* Copyright 2001 Sun Microsystems, Inc. */
+/* #include <linux/config.h> */
+#if !defined(COBALT_H) && defined(CONFIG_COBALT_RAQ)
+#define COBALT_H
+
+/* generational support - for easy checking */
+#ifdef CONFIG_COBALT_GEN_III
+# define COBT_SUPPORT_GEN_III 1
+#else
+# define COBT_SUPPORT_GEN_III 0
+#endif
+
+#ifdef CONFIG_COBALT_GEN_V
+# define COBT_SUPPORT_GEN_V 1
+#else
+# define COBT_SUPPORT_GEN_V 0
+#endif
+
+/* macros for consistent errors/warnings */
+#define EPRINTK(fmt, args...) \
+	printk(KERN_ERR "%s:%s: " fmt , __FILE__ , __FUNCTION__ , ##args)
+
+#define WPRINTK(fmt, args...) \
+	printk(KERN_WARNING "%s:%s: " fmt , __FILE__ , __FUNCTION__ , ##args)
+
+/* the root of /proc/cobalt */
+extern struct proc_dir_entry *proc_cobalt;
+int cobalt_gen_proc_read(char *buf, int plen, char **start, off_t pos, 
+	int len, int *eof);
+
+//#ifdef CONFIG_COBALT_RAQ
+/* keep this test up to date with new generation defines */
+#if !defined(CONFIG_COBALT_GEN_III) && !defined(CONFIG_COBALT_GEN_V)
+/* barf if no generation has been selected */
+#error You asked for CONFIG_COBALT_RAQ, but no CONFIG_COBALT_GEN_* !
+#endif
+
+/* accesses for CMOS */
+#include <linux/mc146818rtc.h>
+#include <cobalt/nvram.h>
+
+static inline int
+cobalt_cmos_read_flag(const unsigned int flag)
+{
+	unsigned long flags;
+	u16 cmosfl;
+
+	spin_lock_irqsave(&rtc_lock, flags);
+	cmosfl = CMOS_READ(COBT_CMOS_FLAG_BYTE_0) << 8;
+	cmosfl |= CMOS_READ(COBT_CMOS_FLAG_BYTE_1);
+	spin_unlock_irqrestore(&rtc_lock, flags);
+
+	return (cmosfl & flag) ? 1 : 0;
+}
+//#endif /* CONFIG_COBALT_RAQ */
+
+#endif /* !defined(COBALT_H) && defined(CONFIG_COBALT_RAQ) */
diff -Naur linux-2.6.19.orig/include/cobalt/i2c.h linux-2.6.19/include/cobalt/i2c.h
--- linux-2.6.19.orig/include/cobalt/i2c.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/include/cobalt/i2c.h	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,40 @@
+/*
+ * $Id: cobalt-i2c.h,v 1.3 2001/08/22 05:48:04 asun Exp $
+ * cobalt-i2c.h : I2C support for LCD/Front Panel
+ *
+ * Copyright 2000 Cobalt Networks, Inc.
+ * Copyright 2001 Sun Microsystems, Inc.
+ */
+#ifndef COBALT_I2C_H
+#define COBALT_I2C_H
+
+#include <linux/types.h>
+#include <cobalt/cobalt.h>
+
+#define COBALT_I2C_DEV_LED_I		0x40
+#define COBALT_I2C_DEV_LED_II		0x42
+#define COBALT_I2C_DEV_LCD_DATA		0x4a
+#define COBALT_I2C_DEV_LCD_INST		0x48
+#define COBALT_I2C_DEV_FP_BUTTONS	0x41
+#define COBALT_I2C_DEV_DRV_SWITCH	0x45
+#define COBALT_I2C_DEV_RULER		0x46
+#define COBALT_I2C_DEV_LM77		0x90
+#define COBALT_I2C_DEV_ADM1029		0x5e
+#define COBALT_I2C_DEV_AT24C02		0xae
+
+#define COBALT_I2C_READ			0x01
+#define COBALT_I2C_WRITE		0x00
+
+extern int cobalt_i2c_reset(void);
+extern int cobalt_i2c_read_byte(const int dev, const int index);
+extern int cobalt_i2c_read_word(const int dev, const int index);
+extern int cobalt_i2c_read_block(const int dev, const int index,
+				 unsigned char *data, int count);
+extern int cobalt_i2c_write_byte(const int dev, const int index,
+				 const u8 val);
+extern int cobalt_i2c_write_word(const int dev, const int index,
+				 const u16 val);
+extern int cobalt_i2c_write_block(const int dev, const int index,
+				  unsigned char *data, int count);
+
+#endif /* COBALT_I2C_H */
diff -Naur linux-2.6.19.orig/include/cobalt/lcd.h linux-2.6.19/include/cobalt/lcd.h
--- linux-2.6.19.orig/include/cobalt/lcd.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/include/cobalt/lcd.h	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,95 @@
+/*
+ * $Id: cobalt-lcd.h,v 1.12 2001/11/30 05:38:46 asun Exp $
+ * cobalt-lcd.h : some useful defines for the Cobalt LCD driver
+ *		(must be useable from both kernel and user space)
+ *
+ * Copyright 1996-2000 Cobalt Networks, Inc.
+ * Copyright 2001 Sun Microsystems, Inc.
+ *
+ * By:	Andrew Bose	
+ *	Timothy Stonis (x86 version)
+ *	Tim Hockin
+ *	Adrian Sun
+ *	Erik Gilling
+ *	Duncan Laurie
+ */
+#ifndef COBALT_LCD_H
+#define COBALT_LCD_H
+
+#ifdef __KERNEL__
+#include <cobalt/cobalt.h>
+#endif
+#include <cobalt/led.h>
+
+#define COBALT_LCD_LINELEN	40
+struct lcd_display {
+	unsigned long buttons;
+	int size1;
+	int size2;
+	unsigned char line1[COBALT_LCD_LINELEN];
+	unsigned char line2[COBALT_LCD_LINELEN];
+	unsigned char cursor_address;
+	unsigned char character;
+	unsigned char leds;
+	unsigned char *RomImage;
+};
+
+/* different lcd types */
+#define LCD_TYPE_UNKNOWN	0
+#define LCD_TYPE_PARALLEL	1
+#define LCD_TYPE_PARALLEL_B	2
+#define LCD_TYPE_I2C		3
+
+/* Function command codes for ioctl */
+#define LCD_On			1
+#define LCD_Off			2
+#define LCD_Clear		3
+#define LCD_Reset		4
+#define LCD_Cursor_Left		5
+#define LCD_Cursor_Right	6
+#define LCD_Disp_Left		7
+#define LCD_Disp_Right		8
+#define LCD_Get_Cursor		9
+#define LCD_Set_Cursor		10
+#define LCD_Home		11
+#define LCD_Read		12		
+#define LCD_Write		13	
+#define LCD_Cursor_Off		14
+#define LCD_Cursor_On		15
+#define LCD_Get_Cursor_Pos	16
+#define LCD_Set_Cursor_Pos	17
+#define LCD_Blink_Off		18
+#define LCD_Raw_Inst		19
+#define LCD_Raw_Data		20
+#define LCD_Type		21
+
+/* LED controls */
+#define LED_Set			40	
+#define LED_Bit_Set		41
+#define LED_Bit_Clear		42
+#define LED32_Set		43	
+#define LED32_Bit_Set		44
+#define LED32_Bit_Clear		45
+#define LED32_Get		46	
+
+/* button ioctls */
+#define BUTTON_Read		50
+
+/* Button defs */
+#define BUTTON_Next		0x3D
+#define BUTTON_Next_B		0x7E
+#define BUTTON_Reset_B		0xFC
+#define BUTTON_NONE_B		0xFE
+#define BUTTON_Left_B		0xFA
+#define BUTTON_Right_B		0xDE
+#define BUTTON_Up_B		0xF6
+#define BUTTON_Down_B		0xEE
+#define BUTTON_Enter_B		0xBE
+
+#define BUTTON_MASK             0xFE
+
+void cobalt_lcd_start_twiddle(void);
+void cobalt_lcd_stop_twiddle(void);
+void cobalt_lcd_off(void);
+
+#endif /* COBALT_LCD_H */
diff -Naur linux-2.6.19.orig/include/cobalt/led.h linux-2.6.19/include/cobalt/led.h
--- linux-2.6.19.orig/include/cobalt/led.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/include/cobalt/led.h	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,59 @@
+/*
+ * $Id: cobalt-led.h,v 1.7 2001/11/08 01:15:33 thockin Exp $
+ * cobalt-led.c
+ *
+ * Copyright 1996-2000 Cobalt Networks, Inc.
+ * Copyright 2001 Sun Microsystems, Inc.
+ *
+ * By:	Andrew Bose	
+ *	Timothy Stonis (x86 version)
+ *	Tim Hockin
+ *	Adrian Sun
+ *	Erik Gilling
+ *	Duncan Laurie
+ */
+#ifndef COBALT_LED_H
+#define COBALT_LED_H
+
+/* the set of all leds available on Cobalt systems */
+#define LED_SHUTDOWN		(1 << 0)
+#define LED_WEBLIGHT		(1 << 1)
+#define LED_COBALTLOGO		(1 << 2)
+#define LED_ETH0_TXRX		(1 << 3)
+#define LED_ETH0_LINK		(1 << 4)
+#define LED_ETH1_TXRX		(1 << 5)
+#define LED_ETH1_LINK		(1 << 6)
+#define LED_DISK0		(1 << 7)
+#define LED_DISK1		(1 << 8)
+#define LED_DISK2		(1 << 9)
+#define LED_DISK3		(1 << 10)
+#define LED_SYSFAULT		(1 << 11)
+#define LED_MONTEREY_UNUSED0	(1 << 12)
+#define LED_MONTEREY_UNUSED1	(1 << 13)
+/* LED_MONTEREY_UNUSED2 is below */
+#define LED_HEART		LED_MONTEREY_UNUSED0
+#define LED_SPARE		LED_MONTEREY_UNUSED1
+#define LED_SLED0		(1 << 14)
+#define LED_SLED1		(1 << 15)
+#define LED_SLED2		(1 << 16)
+#define LED_SLED3		(1 << 17)
+#define LED_MONTEREY_UNUSED2	(1 << 18)
+#define LED_SPARE2		LED_MONTEREY_UNUSED2
+
+#ifdef __KERNEL__
+
+extern void cobalt_led_set(const unsigned int leds);
+extern void cobalt_led_set_bits(const unsigned int leds);
+extern void cobalt_led_clear_bits(const unsigned int leds);
+extern void cobalt_led_set_lazy(const unsigned int leds);
+extern void cobalt_led_set_bits_lazy(const unsigned int leds);
+extern void cobalt_led_clear_bits_lazy(const unsigned int leds);
+extern unsigned int cobalt_led_get(void);
+
+extern int cobalt_fpled_register(unsigned int (*fn)(void *), void *data);
+extern int cobalt_fpled_unregister(unsigned int (*fn)(void *), void *data);
+
+#endif /* __KERNEL__ */
+
+#endif /* COBALT_LED_H */
+
diff -Naur linux-2.6.19.orig/include/cobalt/misc.h linux-2.6.19/include/cobalt/misc.h
--- linux-2.6.19.orig/include/cobalt/misc.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/include/cobalt/misc.h	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,12 @@
+/* $Id: cobalt-misc.h,v 1.1 2001/04/04 03:36:43 thockin Exp $ */
+/* Copyright 2001 Sun Microsystems, Inc. */
+#ifndef COBALT_MISC_H
+#define COBALT_MISC_H
+
+void cobalt_flush(void);
+void cobalt_nmi(unsigned char reason, struct pt_regs *regs);
+void cobalt_restart(void);
+void cobalt_halt(void);
+void cobalt_power_off(void);
+
+#endif
diff -Naur linux-2.6.19.orig/include/cobalt/net.h linux-2.6.19/include/cobalt/net.h
--- linux-2.6.19.orig/include/cobalt/net.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/include/cobalt/net.h	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,12 @@
+/* $Id: cobalt-net.h,v 1.3 2002/10/25 01:02:42 thockin Exp $ */
+/* Copyright 2001 Sun Microsystems, Inc. */
+#ifndef COBALT_NET_H
+#define COBALT_NET_H
+
+#include <linux/netdevice.h>
+/* #include <linux/config.h> */
+
+void cobalt_net_register(struct net_device *ndev);
+void cobalt_net_unregister(struct net_device *ndev);
+
+#endif
diff -Naur linux-2.6.19.orig/include/cobalt/nvram.h linux-2.6.19/include/cobalt/nvram.h
--- linux-2.6.19.orig/include/cobalt/nvram.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/include/cobalt/nvram.h	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,125 @@
+/*
+ * $Id: cobalt-nvram.h,v 1.21 2002/11/02 00:57:06 thockin Exp $
+ * cobalt-nvram.h : defines for the various fields in the cobalt NVRAM
+ *
+ * Copyright 2001 Sun Microsystems, Inc.
+ */
+
+#ifndef COBALT_NVRAM_H
+#define COBALT_NVRAM_H
+
+#include <linux/nvram.h>
+
+#define COBT_CMOS_INFO_MAX		0x7f	/* top address allowed */
+#define COBT_CMOS_BIOS_DRIVE_INFO	0x12	/* drive info would go here */
+
+#define COBT_CMOS_CKS_START		NVRAM_OFFSET(0x0e)
+#define COBT_CMOS_CKS_END		NVRAM_OFFSET(0x7f)
+
+/* flag bytes - 16 flags for now, leave room for more */
+#define COBT_CMOS_FLAG_BYTE_0		NVRAM_OFFSET(0x10)
+#define COBT_CMOS_FLAG_BYTE_1		NVRAM_OFFSET(0x11)
+
+/* flags in flag bytes - up to 16 */
+#define COBT_CMOS_FLAG_MIN		0x0001
+#define COBT_CMOS_CONSOLE_FLAG		0x0001 /* console on/off */
+#define COBT_CMOS_DEBUG_FLAG		0x0002 /* ROM debug messages */
+#define COBT_CMOS_AUTO_PROMPT_FLAG	0x0004 /* boot to ROM prompt? */
+#define COBT_CMOS_CLEAN_BOOT_FLAG	0x0008 /* set by a clean shutdown */
+#define COBT_CMOS_HW_NOPROBE_FLAG	0x0010 /* go easy on the probing */
+#define COBT_CMOS_SYSFAULT_FLAG		0x0020 /* system fault detected */
+#define COBT_CMOS_OOPSPANIC_FLAG	0x0040 /* panic on oops */
+#define COBT_CMOS_DELAY_CACHE_FLAG	0x0080 /* delay cache initialization */
+#define COBT_CMOS_NOLOGO_FLAG		0x0100 /* hide "C" logo @ boot */
+#define COBT_CMOS_VERSION_FLAG		0x0200 /* the version field is valid */
+#define COBT_CMOS_FLAG_MAX		0x0200
+
+/* leave byte 0x12 blank - Linux looks for drive info here */
+
+/* CMOS structure version, valid if COBT_CMOS_VERSION_FLAG is true */
+#define COBT_CMOS_VERSION		NVRAM_OFFSET(0x13)
+#define COBT_CMOS_VER_BTOCODE		1 /* min. version needed for btocode */
+
+/* index of default boot method */
+#define COBT_CMOS_BOOT_METHOD		NVRAM_OFFSET(0x20)
+#define COBT_CMOS_BOOT_METHOD_DISK	0
+#define COBT_CMOS_BOOT_METHOD_ROM	1
+#define COBT_CMOS_BOOT_METHOD_NET	2
+#define COBT_CMOS_BOOT_METHOD_NNET	3
+#define COBT_CMOS_BOOT_METHOD_OTHER	4
+
+#define COBT_CMOS_BOOT_DEV_MIN		NVRAM_OFFSET(0x21)
+/* major #, minor # of first through fourth boot device */
+#define COBT_CMOS_BOOT_DEV0_MAJ		NVRAM_OFFSET(0x21)
+#define COBT_CMOS_BOOT_DEV0_MIN		NVRAM_OFFSET(0x22)
+#define COBT_CMOS_BOOT_DEV1_MAJ		NVRAM_OFFSET(0x23)
+#define COBT_CMOS_BOOT_DEV1_MIN		NVRAM_OFFSET(0x24)
+#define COBT_CMOS_BOOT_DEV2_MAJ		NVRAM_OFFSET(0x25)
+#define COBT_CMOS_BOOT_DEV2_MIN		NVRAM_OFFSET(0x26)
+#define COBT_CMOS_BOOT_DEV3_MAJ		NVRAM_OFFSET(0x27)
+#define COBT_CMOS_BOOT_DEV3_MIN		NVRAM_OFFSET(0x28)
+#define COBT_CMOS_BOOT_DEV_MAX		NVRAM_OFFSET(0x28)
+
+/* checksum of bytes 0xe-0x7f */
+#define COBT_CMOS_CHECKSUM		NVRAM_OFFSET(0x2e)
+
+/* running uptime counter, units of 5 minutes (32 bits =~ 41000 years) */
+#define COBT_CMOS_UPTIME_0		NVRAM_OFFSET(0x30)
+#define COBT_CMOS_UPTIME_1		NVRAM_OFFSET(0x31)
+#define COBT_CMOS_UPTIME_2		NVRAM_OFFSET(0x32)
+#define COBT_CMOS_UPTIME_3		NVRAM_OFFSET(0x33)
+
+/* count of successful boots (32 bits) */
+#define COBT_CMOS_BOOTCOUNT_0		NVRAM_OFFSET(0x38)
+#define COBT_CMOS_BOOTCOUNT_1		NVRAM_OFFSET(0x39)
+#define COBT_CMOS_BOOTCOUNT_2		NVRAM_OFFSET(0x3a)
+#define COBT_CMOS_BOOTCOUNT_3		NVRAM_OFFSET(0x3b)
+
+/* 13 bytes: system serial number, same as on the back of the system */
+#define COBT_CMOS_SYS_SERNUM_LEN	13
+#define COBT_CMOS_SYS_SERNUM_0		NVRAM_OFFSET(0x40)
+#define COBT_CMOS_SYS_SERNUM_1		NVRAM_OFFSET(0x41)
+#define COBT_CMOS_SYS_SERNUM_2		NVRAM_OFFSET(0x42)
+#define COBT_CMOS_SYS_SERNUM_3		NVRAM_OFFSET(0x43)
+#define COBT_CMOS_SYS_SERNUM_4		NVRAM_OFFSET(0x44)
+#define COBT_CMOS_SYS_SERNUM_5		NVRAM_OFFSET(0x45)
+#define COBT_CMOS_SYS_SERNUM_6		NVRAM_OFFSET(0x46)
+#define COBT_CMOS_SYS_SERNUM_7		NVRAM_OFFSET(0x47)
+#define COBT_CMOS_SYS_SERNUM_8		NVRAM_OFFSET(0x48)
+#define COBT_CMOS_SYS_SERNUM_9		NVRAM_OFFSET(0x49)
+#define COBT_CMOS_SYS_SERNUM_10		NVRAM_OFFSET(0x4a)
+#define COBT_CMOS_SYS_SERNUM_11		NVRAM_OFFSET(0x4b)
+#define COBT_CMOS_SYS_SERNUM_12		NVRAM_OFFSET(0x4c)
+/* checksum for serial num - 1 byte */
+#define COBT_CMOS_SYS_SERNUM_CSUM	NVRAM_OFFSET(0x4f)
+
+#define COBT_CMOS_ROM_REV_MAJ		NVRAM_OFFSET(0x50)
+#define COBT_CMOS_ROM_REV_MIN		NVRAM_OFFSET(0x51)
+#define COBT_CMOS_ROM_REV_REV		NVRAM_OFFSET(0x52)
+
+#define COBT_CMOS_BTO_CODE_0		NVRAM_OFFSET(0x53)
+#define COBT_CMOS_BTO_CODE_1		NVRAM_OFFSET(0x54)
+#define COBT_CMOS_BTO_CODE_2		NVRAM_OFFSET(0x55)
+#define COBT_CMOS_BTO_CODE_3		NVRAM_OFFSET(0x56)
+
+#define COBT_CMOS_BTO_IP_CSUM		NVRAM_OFFSET(0x57)
+#define COBT_CMOS_BTO_IP_0		NVRAM_OFFSET(0x58)
+#define COBT_CMOS_BTO_IP_1		NVRAM_OFFSET(0x59)
+#define COBT_CMOS_BTO_IP_2		NVRAM_OFFSET(0x5a)
+#define COBT_CMOS_BTO_IP_3		NVRAM_OFFSET(0x5b)
+
+/* byte for load/run methods */
+#define COBT_CMOS_BOOT_TYPE		NVRAM_OFFSET(0x5c)
+#define COBT_CMOS_BOOT_KERN_DEV		0x01 /* use kernel on major/minor */
+#define COBT_CMOS_BOOT_KERN_ROM		0x02 /* use rom kernel */
+#define COBT_CMOS_BOOT_KERN_NET		0x03 /* use net kernel */
+#define COBT_CMOS_BOOT_KERN_MASK	0x0f /* mask for above */
+
+#define COBT_CMOS_BOOT_FS_DEV		0x10 /* use major/minor number dev */
+#define COBT_CMOS_BOOT_FS_NET		0x30 /* use net fs */
+#define COBT_CMOS_BOOT_FS_MASK		0xf0 /* mask for above */
+
+/* HA mode we're in (Twin Peaks) */
+#define COBT_CMOS_HA_MODE		NVRAM_OFFSET(0x62)
+
+#endif /* COBALT_NVRAM_H */
diff -Naur linux-2.6.19.orig/include/cobalt/ruler.h linux-2.6.19/include/cobalt/ruler.h
--- linux-2.6.19.orig/include/cobalt/ruler.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/include/cobalt/ruler.h	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,15 @@
+/* $Id: cobalt-ruler.h,v 1.4 2001/06/08 20:46:44 thockin Exp $ */
+/* Copyright 2001 Sun Microsystems, Inc. */
+#ifndef COBALT_RULER_H
+#define COBALT_RULER_H
+
+#include <linux/ide.h>
+
+void cobalt_ruler_register(ide_drive_t *hwif);
+void cobalt_ruler_unregister(ide_drive_t *hwif);
+
+//typedef int (*cob_busproc_t) (struct hwif_s *, int);
+
+//int *cob_busproc_t (ide_drive_t *, int);
+
+#endif
diff -Naur linux-2.6.19.orig/include/cobalt/sensors.h linux-2.6.19/include/cobalt/sensors.h
--- linux-2.6.19.orig/include/cobalt/sensors.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/include/cobalt/sensors.h	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,29 @@
+/* $Id: cobalt-sensors.h,v 1.2 2001/09/25 18:10:29 thockin Exp $ */
+/* Copyright 2001 Sun Microsystems, Inc. */
+#ifndef COBALT_SENSORS_H
+#define COBALT_SENSORS_H
+
+#include <cobalt/cobalt.h>
+
+extern unsigned int cobalt_nthermals;
+extern unsigned int cobalt_nvoltages;
+
+/* return NULL if the sensor doesn't exist, fill buf if it does */
+char *__cobalt_thermal_read(unsigned int sensor, char *buf, int len);
+char *__cobalt_voltage_read(unsigned int sensor, char *buf, int len);
+
+static inline char *
+cobalt_thermal_read(unsigned int sensor)
+{
+	char buf[32];
+	return __cobalt_thermal_read(sensor, buf, sizeof(buf)-1);
+}
+
+static inline char *
+cobalt_voltage_read(unsigned int sensor)
+{
+	char buf[32];
+	return __cobalt_voltage_read(sensor, buf, sizeof(buf)-1);
+}
+
+#endif
diff -Naur linux-2.6.19.orig/include/cobalt/serialnum.h linux-2.6.19/include/cobalt/serialnum.h
--- linux-2.6.19.orig/include/cobalt/serialnum.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/include/cobalt/serialnum.h	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,16 @@
+/*
+ * $Id: cobalt-serialnum.h,v 1.1 2001/03/07 01:58:24 thockin Exp $
+ * cobalt-serialnum.h : access to the DS2401 serial number
+ *
+ * Copyright 2000 Cobalt Networks, Inc.
+ * Copyright 2001 Sun Microsystems, Inc.
+ */
+#ifndef COBALT_SERIALNUM_H
+#define COBALT_SERIALNUM_H
+
+#include <cobalt/cobalt.h>
+
+char *cobalt_serialnum_get(void);
+unsigned long cobalt_hostid_get(void);
+
+#endif /* COBALT_SERIALNUM_H */
diff -Naur linux-2.6.19.orig/include/cobalt/superio.h linux-2.6.19/include/cobalt/superio.h
--- linux-2.6.19.orig/include/cobalt/superio.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/include/cobalt/superio.h	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,225 @@
+/*
+ * $Id: cobalt-superio.h,v 1.11 2001/11/02 12:00:03 duncan Exp $
+ * cobalt-superio.h : SuperIO support for Sun/Cobalt servers
+ *
+ * Copyright 2000 Cobalt Networks, Inc.
+ * Copyright 2001 Sun Microsystems, Inc.
+ */
+#ifndef COBALT_SUPERIO_H
+#define COBALT_SUPERIO_H
+
+#include <cobalt/cobalt.h>
+#include <cobalt/systype.h>
+
+/* the lock that protects superio accesses */
+extern spinlock_t cobalt_superio_lock;
+
+/* 
+ * The main functions of the SuperIO are accessed via index/data registers
+ * These are the same for both SuperIO chip families
+ */
+#define SUPERIO_INDEX_PORT	0x2e
+#define SUPERIO_DATA_PORT	0x2f
+
+/* 
+ * This index allows you to select a logical device 
+ */
+#define SUPERIO_LOGICAL_DEV	0x07
+
+/*
+ * Type of SUPERIO
+ */
+#define SUPERIO_SID             0x20
+
+/* 
+ * Some indices that are common to all logical devices 
+ */
+#define SUPERIO_ACTIVATE	0x30
+#define SUPERIO_ADDR_HIGH	0x60
+#define SUPERIO_ADDR_LOW	0x61
+#define SUPERIO_INTR_PIN	0x70
+#define SUPERIO_INTR_TYPE	0x71
+
+
+/* 
+ * PC87317 SuperIO is found on XTR 
+ */
+
+/*
+ * logical devices - write to LOGICAL_DEV index
+ */
+#define PC87317_DEV_RTC		0x02
+#define PC87317_DEV_GPIO	0x07
+#define PC87317_DEV_PM		0x08
+
+/* withing the PM dev, are the following indices */
+#define PC87317_PMDEV_WDTO	0x05
+#define PC87317_PMDEV_GPELO	0x0e
+#define PC87317_PMDEV_GPEHI	0x0f
+
+/* within the APC bank of RTC */
+#define PC87317_APCR1		0x40
+#define PC87317_APCR2		0x41
+#define PC87317_APCR3		0x49
+#define PC87317_APCR4		0x4a
+#define PC87317_APCR5		0x4b
+#define PC87317_APCR6		0x4c
+#define PC87317_APCR7		0x4d
+
+#define PC87317_RTC_BANK_MAIN	0
+#define PC87317_RTC_BANK_RTC	1
+#define PC87317_RTC_BANK_APC	2
+#define PC87317_RTC_CRA		0x0a
+#define PC87317_RTC_BANK_0	0x20
+#define PC87317_RTC_BANK_1	0x30
+#define PC87317_RTC_BANK_2	0x40
+
+#define PC87317_PWRBUTTON	0x01
+#define PC87317_PM1_STATUS	0x01
+
+/* offsets from GPEHI/GPELO */
+#define PC87317_GPE_GP1_STS0	0x00
+#define PC87317_GPE_GP1_STS1	0x01
+#define PC87317_GPE_GP1_STS2	0x02
+#define PC87317_GPE_GP1_STS3	0x03
+#define PC87317_GPE_GP1_EN0	0x04
+#define PC87317_GPE_GP1_EN1	0x05
+#define PC87317_GPE_GP1_EN2	0x06
+#define PC87317_GPE_GP1_EN3	0x07
+#define PC87317_GPE_GP2_EN0	0x08
+#define PC87317_GPE_SMI_CMD	0x0c
+
+/*
+ * PC87417 family is found on alpine 
+ */
+
+#define PC87417_DEV_SWC		0x4
+#define PC87417_DEV_GPIO	0x7
+#define PC87417_DEV_RTC		0x10
+
+/* registers in the SWC dev */
+#define PC87417_SWC_PWONCTL	0x9
+/*
+ * within the System Wake Control device, there are banks, write the bank you
+ * want to SWC_BANK
+ */
+#define PC87417_SWC_BANK	0xf
+#define PC87417_SWCBANK_ACPI	0x2
+#define PC87417_SWCBANK_WDT	0x3
+
+/*
+ * the SWC WDT bank has 3 main registers 
+ */
+#define PC87417_WDT_CONTROL	0x10
+#define PC87417_WDT_TIMEOUT	0x11
+#define PC87417_WDT_CONFIG	0x12
+
+/*
+ * within the SWC, two regs serve as index/data for wake-event enabling
+ */
+#define PC87417_SWC_WKEVENT	0x0
+#define PC87417_SWC_WKSTATE	0x1
+#define PC87417_SWCWKEVENT_GPIOE42 0xa
+#define PC87417_SWCWKEVENT_RTC 	0x18
+
+
+/*
+ * types of superIOs
+ */
+enum superio_type_t
+{
+    SIO_TYPE_UNKNOWN,
+    SIO_TYPE_PC8731X,
+    SIO_TYPE_PC8741X,
+};
+
+
+
+#define PC8731X_SID 0xd0
+#define PC9731X_SID 0xdf
+#define PC8741X_SID 0xee
+
+static inline int superio_type( void )
+{
+    u8 reg;
+    unsigned long flags;
+    enum superio_type_t type;
+
+    spin_lock_irqsave(&cobalt_superio_lock, flags);
+
+    outb(SUPERIO_SID, SUPERIO_INDEX_PORT);
+    reg = inb( SUPERIO_DATA_PORT );
+    switch( reg )
+    {
+	case PC8731X_SID:
+	case PC9731X_SID:
+	    type = SIO_TYPE_PC8731X;
+	    break;
+
+	case PC8741X_SID:
+	    type = SIO_TYPE_PC8741X;
+	    break;
+
+	default:
+	    type = SIO_TYPE_UNKNOWN;
+	    break;
+    }
+
+    spin_unlock_irqrestore(&cobalt_superio_lock, flags);
+
+    return type;
+}
+
+/*
+ * stuff to make life easier
+ */
+
+/* read the base address of a particular superio logical device */
+#define superio_ldev_base(ldev)		superio_ldev_base_n(ldev, 0)
+static inline unsigned short
+superio_ldev_base_n(int ldev, int n)
+{
+	unsigned long flags;
+	unsigned short addr;
+
+	spin_lock_irqsave(&cobalt_superio_lock, flags);
+
+	/* select the logical device */
+	outb(SUPERIO_LOGICAL_DEV, SUPERIO_INDEX_PORT);
+	outb(ldev, SUPERIO_DATA_PORT);
+
+	/* read the 2-byte base address */
+	outb(SUPERIO_ADDR_HIGH+(n*2), SUPERIO_INDEX_PORT);
+	addr = inb(SUPERIO_DATA_PORT) << 8;
+	outb(SUPERIO_ADDR_LOW+(n*2), SUPERIO_INDEX_PORT);
+	addr |= inb(SUPERIO_DATA_PORT);
+
+	spin_unlock_irqrestore(&cobalt_superio_lock, flags);
+
+	return addr;
+}
+
+static inline void
+superio_set_rtc_bank(const unsigned int page)
+{
+	if (cobt_is_monterey()) {
+		unsigned char val;
+
+		val = CMOS_READ(0xa);
+		val &= ~0x70;
+		switch (page) {
+		case PC87317_RTC_BANK_MAIN:
+			val |= 0x20;
+			break;
+		case PC87317_RTC_BANK_RTC:
+			val |= 0x30;
+			break;
+		case PC87317_RTC_BANK_APC:
+			val |= 0x40;
+			break;
+		}
+		CMOS_WRITE(val, 0xa);
+	}
+}
+
+#endif /* COBALT_SUPERIO_H */
diff -Naur linux-2.6.19.orig/include/cobalt/systype.h linux-2.6.19/include/cobalt/systype.h
--- linux-2.6.19.orig/include/cobalt/systype.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/include/cobalt/systype.h	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,99 @@
+/*
+ * $Id: cobalt-systype.h,v 1.8 2002/08/08 22:46:50 carls Exp $
+ * cobalt-systype.h : figure out what Cobalt system we are on
+ *
+ * Copyright 2000 Cobalt Networks, Inc.
+ * Copyright 2001-2002 Sun Microsystems, Inc.
+ */
+#ifndef COBALT_SYSTYPE_H
+#define COBALT_SYSTYPE_H
+
+#include <cobalt/cobalt.h>
+
+typedef enum {
+	COBT_UNINITIALIZED,
+	COBT_UNKNOWN,
+	COBT_PACIFICA,
+	COBT_CARMEL,
+	COBT_MONTEREY,
+	COBT_ALPINE,
+	COBT_BIGBEAR,
+} cobt_sys_t;
+
+extern cobt_sys_t cobt_type;
+extern cobt_sys_t cobalt_systype_probe(void);
+extern unsigned long cobt_rev;
+
+/* 
+ * one test for each major board-type 
+ * COBT_SUPPORT_* from cobalt.h
+ */
+
+/* pacifica is the RaQ 3 and RaQ 4 platform */
+static inline int
+cobt_is_pacifica(void)
+{
+	if (!COBT_SUPPORT_GEN_III) {
+		return 0;
+	}
+	if (cobt_type == COBT_UNINITIALIZED) {
+		cobalt_systype_probe();
+	}
+	return (cobt_type == COBT_PACIFICA);
+}
+
+/* carmel is the Qube 3 platform */
+static inline int
+cobt_is_carmel(void)
+{
+	if (!COBT_SUPPORT_GEN_III) {
+		return 0;
+	}
+	if (cobt_type == COBT_UNINITIALIZED) {
+		cobalt_systype_probe();
+	}
+	return (cobt_type == COBT_CARMEL);
+}
+
+/* monterey is the RaQ XTR platform */
+static inline int
+cobt_is_monterey(void)
+{
+	if (!COBT_SUPPORT_GEN_V) {
+		return 0;
+	}
+	if (cobt_type == COBT_UNINITIALIZED) {
+		cobalt_systype_probe();
+	}
+	return (cobt_type == COBT_MONTEREY);
+}
+
+static inline int
+cobt_is_alpine(void)
+{
+	if (!COBT_SUPPORT_GEN_V) {
+		return 0;
+	}
+	if (cobt_type == COBT_UNINITIALIZED) {
+		cobalt_systype_probe();
+	}
+	return (cobt_type == COBT_ALPINE);
+}
+
+static inline int
+cobt_is_bigbear(void)
+{
+	if (!COBT_SUPPORT_GEN_V) {
+		return 0;
+	}
+	if (cobt_type == COBT_UNINITIALIZED) {
+		cobalt_systype_probe();
+	}
+	return (cobt_type == COBT_BIGBEAR);
+}
+
+/* one for each major generation */
+#define cobt_is_3k()	 (cobt_is_pacifica() || cobt_is_carmel())
+#define cobt_is_5k()	 (cobt_is_monterey() || cobt_is_alpine() || cobt_is_bigbear())
+
+#endif
diff -Naur linux-2.6.19.orig/include/cobalt/wdt.h linux-2.6.19/include/cobalt/wdt.h
--- linux-2.6.19.orig/include/cobalt/wdt.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.19/include/cobalt/wdt.h	2006-11-29 19:13:54.000000000 -0800
@@ -0,0 +1,16 @@
+/* $Id: cobalt-wdt.h,v 1.1 2001/03/07 01:58:24 thockin Exp $ */
+/* Copyright 2001 Sun Microsystems, Inc. */
+#ifndef COBALT_WDT_H
+#define COBALT_WDT_H
+
+#include <cobalt/cobalt.h>
+
+void cobalt_wdt_refresh(unsigned long refresh_timer);
+void cobalt_wdt_trigger_reboot(void);
+
+void cobalt_wdt_disable(void);
+void cobalt_wdt_reenable(void);
+
+void cobalt_wdt_cleardog(void);
+
+#endif
diff -Naur linux-2.6.19.orig/init/main.c linux-2.6.19/init/main.c
--- linux-2.6.19.orig/init/main.c	2006-11-29 13:57:37.000000000 -0800
+++ linux-2.6.19/init/main.c	2006-11-29 19:13:54.000000000 -0800
@@ -673,6 +673,10 @@
  *
  * Now we can finally start doing some real work..
  */
+#ifdef CONFIG_COBALT_RAQ
+extern int cobalt_init(void);
+#endif
+
 static void __init do_basic_setup(void)
 {
 	/* drivers will send hotplug events */
@@ -685,6 +689,10 @@
 #endif
 
 	do_initcalls();
+	
+#ifdef CONFIG_COBALT_RAQ
+    cobalt_init();
+#endif
 }
 
 static void do_pre_smp_initcalls(void)
