Index: tches/linux-2.6.19.1-cobalt_x86-1.patch
===================================================================
--- patches/linux-2.6.19.1-cobalt_x86-1.patch	(revision e20f88123b151cb8f34cd68559834781989e14b1)
+++ 	(revision )
@@ -1,8750 +1,0 @@
-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)
Index: patches/linux-2.6.19.1-cobalt_x86-2.patch
===================================================================
--- patches/linux-2.6.19.1-cobalt_x86-2.patch	(revision 8b704c8d67bcf66453dec0f6d1dd003e91520253)
+++ patches/linux-2.6.19.1-cobalt_x86-2.patch	(revision 8b704c8d67bcf66453dec0f6d1dd003e91520253)
@@ -0,0 +1,8750 @@
+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)
