diff -ruN linux-2.4.26/Makefile linux-2.4.26-BF2-C7_III/Makefile --- linux-2.4.26/Makefile 2004-07-10 22:40:44.000000000 -0600 +++ linux-2.4.26-BF2-C7_III/Makefile 2004-07-10 22:53:29.813133240 -0600 @@ -1,7 +1,13 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 26 -EXTRAVERSION = +EXTRAVERSION = -BF2-C7_III + +# This patch was created by fixing the linux-2.4.20-cobalt.patch +# available at http://cobalt.iceblink.org/redhat/build/ to work +# with 2.4.26 +# +# Travis Morgan, July 10, 2004, travis@bigfiber.net KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) @@ -194,6 +200,7 @@ DRIVERS-$(CONFIG_HOTPLUG_PCI) += drivers/hotplug/vmlinux-obj.o DRIVERS-$(CONFIG_ISDN_BOOL) += drivers/isdn/vmlinux-obj.o DRIVERS-$(CONFIG_CRYPTO) += crypto/crypto.o +DRIVERS-$(CONFIG_COBALT) += drivers/cobalt/cobalt.o DRIVERS := $(DRIVERS-y) diff -ruN linux-2.4.26/arch/i386/config.in linux-2.4.26-BF2-C7_III/arch/i386/config.in --- linux-2.4.26/arch/i386/config.in 2004-07-10 22:40:44.000000000 -0600 +++ linux-2.4.26-BF2-C7_III/arch/i386/config.in 2004-07-10 22:52:14.971510896 -0600 @@ -277,6 +277,7 @@ define_bool CONFIG_PCI y define_bool CONFIG_ISA n else + source drivers/cobalt/Config.in if [ "$CONFIG_SMP" = "y" ]; then define_bool CONFIG_X86_IO_APIC y define_bool CONFIG_X86_LOCAL_APIC y diff -ruN linux-2.4.26/arch/i386/kernel/Makefile linux-2.4.26-BF2-C7_III/arch/i386/kernel/Makefile --- linux-2.4.26/arch/i386/kernel/Makefile 2004-07-10 22:40:44.000000000 -0600 +++ linux-2.4.26-BF2-C7_III/arch/i386/kernel/Makefile 2004-07-10 22:52:14.992507704 -0600 @@ -43,5 +43,6 @@ obj-$(CONFIG_X86_IO_APIC) += io_apic.o obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o obj-$(CONFIG_EDD) += edd.o +obj-$(CONFIG_COBALT_RAQ) += cobalt.o include $(TOPDIR)/Rules.make diff -ruN linux-2.4.26/arch/i386/kernel/cobalt.c linux-2.4.26-BF2-C7_III/arch/i386/kernel/cobalt.c --- linux-2.4.26/arch/i386/kernel/cobalt.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/arch/i386/kernel/cobalt.c 2004-07-10 22:52:14.992507704 -0600 @@ -0,0 +1,283 @@ +/* $Id: cobalt.c,v 1.34 2002/11/04 17:54:14 thockin Exp $ */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define MAX_NMI_PS 10 + +static inline void ledonoff(unsigned long on, unsigned long off); + +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; + +/* 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"); + } + } +} + +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 +} + +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 -ruN linux-2.4.26/arch/i386/kernel/process.c linux-2.4.26-BF2-C7_III/arch/i386/kernel/process.c --- linux-2.4.26/arch/i386/kernel/process.c 2004-07-10 22:40:44.000000000 -0600 +++ linux-2.4.26-BF2-C7_III/arch/i386/kernel/process.c 2004-07-10 22:52:14.993507552 -0600 @@ -48,6 +48,12 @@ #ifdef CONFIG_MATH_EMULATION #include #endif + +#ifdef CONFIG_COBALT_RAQ +#include +#include +#endif + #include #include @@ -365,6 +371,30 @@ : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100))); } +/* kill some time at halt/reboot to allow drives with large cache to sync */ +static inline void +wait_for_flush(void) +{ + int i; + static int flushed; + + if (flushed) + return; + flushed = 1; + + printk("waiting for devices to flush"); + for (i = 0 ; i < 10; i++) { + printk("."); + mdelay(500); +#ifdef CONFIG_COBALT_LCD + if (i == 8) + cobalt_lcd_off(); +#endif + } + printk("done\n"); +} + + void machine_restart(char * __unused) { #if CONFIG_SMP @@ -412,6 +442,11 @@ disable_IO_APIC(); #endif + wait_for_flush(); +#ifdef CONFIG_COBALT_RAQ + cobalt_restart(); +#endif + if(!reboot_thru_bios) { /* rebooting needs to touch the page at absolute addr 0 */ *((unsigned short *)__va(0x472)) = reboot_mode; @@ -434,10 +469,18 @@ void machine_halt(void) { + wait_for_flush(); +#ifdef CONFIG_COBALT_RAQ + cobalt_halt(); +#endif } void machine_power_off(void) { + wait_for_flush(); +#ifdef CONFIG_COBALT_RAQ + cobalt_power_off(); +#endif if (pm_power_off) pm_power_off(); } diff -ruN linux-2.4.26/arch/i386/kernel/process.c.orig linux-2.4.26-BF2-C7_III/arch/i386/kernel/process.c.orig --- linux-2.4.26/arch/i386/kernel/process.c.orig 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/arch/i386/kernel/process.c.orig 2004-07-10 22:52:14.995507248 -0600 @@ -0,0 +1,794 @@ +/* + * linux/arch/i386/kernel/process.c + * + * Copyright (C) 1995 Linus Torvalds + * + * Pentium III FXSR, SSE support + * Gareth Hughes , May 2000 + */ + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +#define __KERNEL_SYSCALLS__ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_MATH_EMULATION +#include +#endif +#include + +#include + +asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); + +int hlt_counter; + +/* + * Powermanagement idle function, if any.. + */ +void (*pm_idle)(void); + +/* + * Power off function, if any + */ +void (*pm_power_off)(void); + +void disable_hlt(void) +{ + hlt_counter++; +} + +void enable_hlt(void) +{ + hlt_counter--; +} + +/* + * We use this if we don't have any better + * idle routine.. + */ +void default_idle(void) +{ + if (current_cpu_data.hlt_works_ok && !hlt_counter) { + __cli(); + if (!current->need_resched) + safe_halt(); + else + __sti(); + } +} + +/* + * On SMP it's slightly faster (but much more power-consuming!) + * to poll the ->need_resched flag instead of waiting for the + * cross-CPU IPI to arrive. Use this option with caution. + */ +static void poll_idle (void) +{ + int oldval; + + __sti(); + + /* + * Deal with another CPU just having chosen a thread to + * run here: + */ + oldval = xchg(¤t->need_resched, -1); + + if (!oldval) + asm volatile( + "2:" + "cmpl $-1, %0;" + "rep; nop;" + "je 2b;" + : :"m" (current->need_resched)); +} + +/* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +void cpu_idle (void) +{ + /* endless idle loop with no priority at all */ + init_idle(); + current->nice = 20; + current->counter = -100; + + while (1) { + void (*idle)(void) = pm_idle; + if (!idle) + idle = default_idle; + while (!current->need_resched) + idle(); + schedule(); + check_pgt_cache(); + } +} + +static int __init idle_setup (char *str) +{ + if (!strncmp(str, "poll", 4)) { + printk("using polling idle threads.\n"); + pm_idle = poll_idle; + } + + return 1; +} + +__setup("idle=", idle_setup); + +static int reboot_mode; +int reboot_thru_bios; + +#ifdef CONFIG_SMP +int reboot_smp = 0; +static int reboot_cpu = -1; +/* shamelessly grabbed from lib/vsprintf.c for readability */ +#define is_digit(c) ((c) >= '0' && (c) <= '9') +#endif +static int __init reboot_setup(char *str) +{ + while(1) { + switch (*str) { + case 'w': /* "warm" reboot (no memory testing etc) */ + reboot_mode = 0x1234; + break; + case 'c': /* "cold" reboot (with memory testing etc) */ + reboot_mode = 0x0; + break; + case 'b': /* "bios" reboot by jumping through the BIOS */ + reboot_thru_bios = 1; + break; + case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */ + reboot_thru_bios = 0; + break; +#ifdef CONFIG_SMP + case 's': /* "smp" reboot by executing reset on BSP or other CPU*/ + reboot_smp = 1; + if (is_digit(*(str+1))) { + reboot_cpu = (int) (*(str+1) - '0'); + if (is_digit(*(str+2))) + reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0'); + } + /* we will leave sorting out the final value + when we are ready to reboot, since we might not + have set up boot_cpu_id or smp_num_cpu */ + break; +#endif + } + if((str = strchr(str,',')) != NULL) + str++; + else + break; + } + return 1; +} + +__setup("reboot=", reboot_setup); + +/* The following code and data reboots the machine by switching to real + mode and jumping to the BIOS reset entry point, as if the CPU has + really been reset. The previous version asked the keyboard + controller to pulse the CPU reset line, which is more thorough, but + doesn't work with at least one type of 486 motherboard. It is easy + to stop this code working; hence the copious comments. */ + +static unsigned long long +real_mode_gdt_entries [3] = +{ + 0x0000000000000000ULL, /* Null descriptor */ + 0x00009a000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */ + 0x000092000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */ +}; + +static struct +{ + unsigned short size __attribute__ ((packed)); + unsigned long long * base __attribute__ ((packed)); +} +real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries }, +real_mode_idt = { 0x3ff, 0 }, +no_idt = { 0, 0 }; + +/* This is 16-bit protected mode code to disable paging and the cache, + switch to real mode and jump to the BIOS reset code. + + The instruction that switches to real mode by writing to CR0 must be + followed immediately by a far jump instruction, which set CS to a + valid value for real mode, and flushes the prefetch queue to avoid + running instructions that have already been decoded in protected + mode. + + Clears all the flags except ET, especially PG (paging), PE + (protected-mode enable) and TS (task switch for coprocessor state + save). Flushes the TLB after paging has been disabled. Sets CD and + NW, to disable the cache on a 486, and invalidates the cache. This + is more like the state of a 486 after reset. I don't know if + something else should be done for other chips. + + More could be done here to set up the registers as if a CPU reset had + occurred; hopefully real BIOSs don't assume much. */ + +static unsigned char real_mode_switch [] = +{ + 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */ + 0x66, 0x83, 0xe0, 0x11, /* andl $0x00000011,%eax */ + 0x66, 0x0d, 0x00, 0x00, 0x00, 0x60, /* orl $0x60000000,%eax */ + 0x66, 0x0f, 0x22, 0xc0, /* movl %eax,%cr0 */ + 0x66, 0x0f, 0x22, 0xd8, /* movl %eax,%cr3 */ + 0x66, 0x0f, 0x20, 0xc3, /* movl %cr0,%ebx */ + 0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60, /* andl $0x60000000,%ebx */ + 0x74, 0x02, /* jz f */ + 0x0f, 0x09, /* wbinvd */ + 0x24, 0x10, /* f: andb $0x10,al */ + 0x66, 0x0f, 0x22, 0xc0 /* movl %eax,%cr0 */ +}; +static unsigned char jump_to_bios [] = +{ + 0xea, 0x00, 0x00, 0xff, 0xff /* ljmp $0xffff,$0x0000 */ +}; + +static inline void kb_wait(void) +{ + int i; + + for (i=0; i<0x10000; i++) + if ((inb_p(0x64) & 0x02) == 0) + break; +} + +/* + * Switch to real mode and then execute the code + * specified by the code and length parameters. + * We assume that length will aways be less that 100! + */ +void machine_real_restart(unsigned char *code, int length) +{ + unsigned long flags; + + cli(); + + /* Write zero to CMOS register number 0x0f, which the BIOS POST + routine will recognize as telling it to do a proper reboot. (Well + that's what this book in front of me says -- it may only apply to + the Phoenix BIOS though, it's not clear). At the same time, + disable NMIs by setting the top bit in the CMOS address register, + as we're about to do peculiar things to the CPU. I'm not sure if + `outb_p' is needed instead of just `outb'. Use it to be on the + safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) + */ + + spin_lock_irqsave(&rtc_lock, flags); + CMOS_WRITE(0x00, 0x8f); + spin_unlock_irqrestore(&rtc_lock, flags); + + /* Remap the kernel at virtual address zero, as well as offset zero + from the kernel segment. This assumes the kernel segment starts at + virtual address PAGE_OFFSET. */ + + memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, + sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS); + + /* Make sure the first page is mapped to the start of physical memory. + It is normally not mapped, to trap kernel NULL pointer dereferences. */ + + pg0[0] = _PAGE_RW | _PAGE_PRESENT; + + /* + * Use `swapper_pg_dir' as our page directory. + */ + load_cr3(swapper_pg_dir); + + /* Write 0x1234 to absolute memory location 0x472. The BIOS reads + this on booting to tell it to "Bypass memory test (also warm + boot)". This seems like a fairly standard thing that gets set by + REBOOT.COM programs, and the previous reset routine did this + too. */ + + *((unsigned short *)0x472) = reboot_mode; + + /* For the switch to real mode, copy some code to low memory. It has + to be in the first 64k because it is running in 16-bit mode, and it + has to have the same physical and virtual address, because it turns + off paging. Copy it near the end of the first page, out of the way + of BIOS variables. */ + + memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100), + real_mode_switch, sizeof (real_mode_switch)); + memcpy ((void *) (0x1000 - 100), code, length); + + /* Set up the IDT for real mode. */ + + __asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt)); + + /* Set up a GDT from which we can load segment descriptors for real + mode. The GDT is not used in real mode; it is just needed here to + prepare the descriptors. */ + + __asm__ __volatile__ ("lgdt %0" : : "m" (real_mode_gdt)); + + /* Load the data segment registers, and thus the descriptors ready for + real mode. The base address of each segment is 0x100, 16 times the + selector value being loaded here. This is so that the segment + registers don't have to be reloaded after switching to real mode: + the values are consistent for real mode operation already. */ + + __asm__ __volatile__ ("movl $0x0010,%%eax\n" + "\tmovl %%eax,%%ds\n" + "\tmovl %%eax,%%es\n" + "\tmovl %%eax,%%fs\n" + "\tmovl %%eax,%%gs\n" + "\tmovl %%eax,%%ss" : : : "eax"); + + /* Jump to the 16-bit code that we copied earlier. It disables paging + and the cache, switches to real mode, and jumps to the BIOS reset + entry point. */ + + __asm__ __volatile__ ("ljmp $0x0008,%0" + : + : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100))); +} + +void machine_restart(char * __unused) +{ +#if CONFIG_SMP + int cpuid; + + cpuid = GET_APIC_ID(apic_read(APIC_ID)); + + if (reboot_smp) { + + /* check to see if reboot_cpu is valid + if its not, default to the BSP */ + if ((reboot_cpu == -1) || + (reboot_cpu > (NR_CPUS -1)) || + !(phys_cpu_present_map & apicid_to_phys_cpu_present(cpuid))) + reboot_cpu = boot_cpu_physical_apicid; + + reboot_smp = 0; /* use this as a flag to only go through this once*/ + /* re-run this function on the other CPUs + it will fall though this section since we have + cleared reboot_smp, and do the reboot if it is the + correct CPU, otherwise it halts. */ + if (reboot_cpu != cpuid) + smp_call_function((void *)machine_restart , NULL, 1, 0); + } + + /* if reboot_cpu is still -1, then we want a tradional reboot, + and if we are not running on the reboot_cpu,, halt */ + if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) { + for (;;) + __asm__ __volatile__ ("hlt"); + } + /* + * Stop all CPUs and turn off local APICs and the IO-APIC, so + * other OSs see a clean IRQ state. + */ + smp_send_stop(); +#elif CONFIG_X86_LOCAL_APIC + if (cpu_has_apic) { + __cli(); + disable_local_APIC(); + __sti(); + } +#endif +#ifdef CONFIG_X86_IO_APIC + disable_IO_APIC(); +#endif + + if(!reboot_thru_bios) { + /* rebooting needs to touch the page at absolute addr 0 */ + *((unsigned short *)__va(0x472)) = reboot_mode; + for (;;) { + int i; + for (i=0; i<100; i++) { + kb_wait(); + udelay(50); + outb(0xfe,0x64); /* pulse reset low */ + udelay(50); + } + /* That didn't work - force a triple fault.. */ + __asm__ __volatile__("lidt %0": :"m" (no_idt)); + __asm__ __volatile__("int3"); + } + } + + machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); +} + +void machine_halt(void) +{ +} + +void machine_power_off(void) +{ + if (pm_power_off) + pm_power_off(); +} + +extern void show_trace(unsigned long* esp); + +void show_regs(struct pt_regs * regs) +{ + unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; + + printk("\n"); + printk("Pid: %d, comm: %20s\n", current->pid, current->comm); + printk("EIP: %04x:[<%08lx>] CPU: %d",0xffff & regs->xcs,regs->eip, smp_processor_id()); + if (regs->xcs & 3) + printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp); + printk(" EFLAGS: %08lx %s\n",regs->eflags, print_tainted()); + printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", + regs->eax,regs->ebx,regs->ecx,regs->edx); + printk("ESI: %08lx EDI: %08lx EBP: %08lx", + regs->esi, regs->edi, regs->ebp); + printk(" DS: %04x ES: %04x\n", + 0xffff & regs->xds,0xffff & regs->xes); + + __asm__("movl %%cr0, %0": "=r" (cr0)); + __asm__("movl %%cr2, %0": "=r" (cr2)); + __asm__("movl %%cr3, %0": "=r" (cr3)); + /* This could fault if %cr4 does not exist */ + __asm__("1: movl %%cr4, %0 \n" + "2: \n" + ".section __ex_table,\"a\" \n" + ".long 1b,2b \n" + ".previous \n" + : "=r" (cr4): "0" (0)); + printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4); + show_trace(®s->esp); +} + +/* + * Create a kernel thread + */ +int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + long retval, d0; + + __asm__ __volatile__( + "movl %%esp,%%esi\n\t" + "int $0x80\n\t" /* Linux/i386 system call */ + "cmpl %%esp,%%esi\n\t" /* child or parent? */ + "je 1f\n\t" /* parent - jump */ + /* Load the argument into eax, and push it. That way, it does + * not matter whether the called function is compiled with + * -mregparm or not. */ + "movl %4,%%eax\n\t" + "pushl %%eax\n\t" + "call *%5\n\t" /* call fn */ + "movl %3,%0\n\t" /* exit */ + "int $0x80\n" + "1:\t" + :"=&a" (retval), "=&S" (d0) + :"0" (__NR_clone), "i" (__NR_exit), + "r" (arg), "r" (fn), + "b" (flags | CLONE_VM) + : "memory"); + + return retval; +} + +/* + * Free current thread data structures etc.. + */ +void exit_thread(void) +{ + /* nothing to do ... */ +} + +void flush_thread(void) +{ + struct task_struct *tsk = current; + + memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8); + /* + * Forget coprocessor state.. + */ + clear_fpu(tsk); + tsk->used_math = 0; +} + +void release_thread(struct task_struct *dead_task) +{ + if (dead_task->mm) { + // temporary debugging check + if (dead_task->mm->context.size) { + printk("WARNING: dead process %8s still has LDT? <%p/%d>\n", + dead_task->comm, + dead_task->mm->context.ldt, + dead_task->mm->context.size); + BUG(); + } + } + release_x86_irqs(dead_task); +} + +/* + * Save a segment. + */ +#define savesegment(seg,value) \ + asm volatile("movl %%" #seg ",%0":"=m" (*(int *)&(value))) + +int copy_thread(int nr, unsigned long clone_flags, unsigned long esp, + unsigned long unused, + struct task_struct * p, struct pt_regs * regs) +{ + struct pt_regs * childregs; + + childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p)) - 1; + struct_cpy(childregs, regs); + childregs->eax = 0; + childregs->esp = esp; + + p->thread.esp = (unsigned long) childregs; + p->thread.esp0 = (unsigned long) (childregs+1); + + p->thread.eip = (unsigned long) ret_from_fork; + + savesegment(fs,p->thread.fs); + savesegment(gs,p->thread.gs); + + unlazy_fpu(current); + struct_cpy(&p->thread.i387, ¤t->thread.i387); + + return 0; +} + +/* + * fill in the user structure for a core dump.. + */ +void dump_thread(struct pt_regs * regs, struct user * dump) +{ + int i; + +/* changed the size calculations - should hopefully work better. lbt */ + dump->magic = CMAGIC; + dump->start_code = 0; + dump->start_stack = regs->esp & ~(PAGE_SIZE - 1); + dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; + dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT; + dump->u_dsize -= dump->u_tsize; + dump->u_ssize = 0; + for (i = 0; i < 8; i++) + dump->u_debugreg[i] = current->thread.debugreg[i]; + + if (dump->start_stack < TASK_SIZE) + dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; + + dump->regs.ebx = regs->ebx; + dump->regs.ecx = regs->ecx; + dump->regs.edx = regs->edx; + dump->regs.esi = regs->esi; + dump->regs.edi = regs->edi; + dump->regs.ebp = regs->ebp; + dump->regs.eax = regs->eax; + dump->regs.ds = regs->xds; + dump->regs.es = regs->xes; + savesegment(fs,dump->regs.fs); + savesegment(gs,dump->regs.gs); + dump->regs.orig_eax = regs->orig_eax; + dump->regs.eip = regs->eip; + dump->regs.cs = regs->xcs; + dump->regs.eflags = regs->eflags; + dump->regs.esp = regs->esp; + dump->regs.ss = regs->xss; + + dump->u_fpvalid = dump_fpu (regs, &dump->i387); +} + +/* + * This special macro can be used to load a debugging register + */ +#define loaddebug(thread,register) \ + __asm__("movl %0,%%db" #register \ + : /* no output */ \ + :"r" (thread->debugreg[register])) + +/* + * switch_to(x,yn) should switch tasks from x to y. + * + * We fsave/fwait so that an exception goes off at the right time + * (as a call from the fsave or fwait in effect) rather than to + * the wrong process. Lazy FP saving no longer makes any sense + * with modern CPU's, and this simplifies a lot of things (SMP + * and UP become the same). + * + * NOTE! We used to use the x86 hardware context switching. The + * reason for not using it any more becomes apparent when you + * try to recover gracefully from saved state that is no longer + * valid (stale segment register values in particular). With the + * hardware task-switch, there is no way to fix up bad state in + * a reasonable manner. + * + * The fact that Intel documents the hardware task-switching to + * be slow is a fairly red herring - this code is not noticeably + * faster. However, there _is_ some room for improvement here, + * so the performance issues may eventually be a valid point. + * More important, however, is the fact that this allows us much + * more flexibility. + */ +void __switch_to(struct task_struct *prev_p, struct task_struct *next_p) +{ + struct thread_struct *prev = &prev_p->thread, + *next = &next_p->thread; + struct tss_struct *tss = init_tss + smp_processor_id(); + + unlazy_fpu(prev_p); + + /* + * Reload esp0, LDT and the page table pointer: + */ + tss->esp0 = next->esp0; + + /* + * Save away %fs and %gs. No need to save %es and %ds, as + * those are always kernel segments while inside the kernel. + */ + asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->fs)); + asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs)); + + /* + * Restore %fs and %gs. + */ + loadsegment(fs, next->fs); + loadsegment(gs, next->gs); + + /* + * Now maybe reload the debug registers + */ + if (next->debugreg[7]){ + loaddebug(next, 0); + loaddebug(next, 1); + loaddebug(next, 2); + loaddebug(next, 3); + /* no 4 and 5 */ + loaddebug(next, 6); + loaddebug(next, 7); + } + + if (prev->ioperm || next->ioperm) { + if (next->ioperm) { + /* + * 4 cachelines copy ... not good, but not that + * bad either. Anyone got something better? + * This only affects processes which use ioperm(). + * [Putting the TSSs into 4k-tlb mapped regions + * and playing VM tricks to switch the IO bitmap + * is not really acceptable.] + */ + memcpy(tss->io_bitmap, next->io_bitmap, + IO_BITMAP_BYTES); + tss->bitmap = IO_BITMAP_OFFSET; + } else + /* + * a bitmap offset pointing outside of the TSS limit + * causes a nicely controllable SIGSEGV if a process + * tries to use a port IO instruction. The first + * sys_ioperm() call sets up the bitmap properly. + */ + tss->bitmap = INVALID_IO_BITMAP_OFFSET; + } +} + +asmlinkage int sys_fork(struct pt_regs regs) +{ + return do_fork(SIGCHLD, regs.esp, ®s, 0); +} + +asmlinkage int sys_clone(struct pt_regs regs) +{ + unsigned long clone_flags; + unsigned long newsp; + + clone_flags = regs.ebx; + newsp = regs.ecx; + if (!newsp) + newsp = regs.esp; + return do_fork(clone_flags, newsp, ®s, 0); +} + +/* + * This is trivial, and on the face of it looks like it + * could equally well be done in user mode. + * + * Not so, for quite unobvious reasons - register pressure. + * In user mode vfork() cannot have a stack frame, and if + * done by calling the "clone()" system call directly, you + * do not have enough call-clobbered registers to hold all + * the information you need. + */ +asmlinkage int sys_vfork(struct pt_regs regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, ®s, 0); +} + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys_execve(struct pt_regs regs) +{ + int error; + char * filename; + + filename = getname((char *) regs.ebx); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, (char **) regs.ecx, (char **) regs.edx, ®s); + if (error == 0) + current->ptrace &= ~PT_DTRACE; + putname(filename); +out: + return error; +} + +/* + * These bracket the sleeping functions.. + */ +extern void scheduling_functions_start_here(void); +extern void scheduling_functions_end_here(void); +#define first_sched ((unsigned long) scheduling_functions_start_here) +#define last_sched ((unsigned long) scheduling_functions_end_here) + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long ebp, esp, eip; + unsigned long stack_page; + int count = 0; + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + stack_page = (unsigned long)p; + esp = p->thread.esp; + if (!stack_page || esp < stack_page || esp > 8188+stack_page) + return 0; + /* include/asm-i386/system.h:switch_to() pushes ebp last. */ + ebp = *(unsigned long *) esp; + do { + if (ebp < stack_page || ebp > 8184+stack_page) + return 0; + eip = *(unsigned long *) (ebp+4); + if (eip < first_sched || eip >= last_sched) + return eip; + ebp = *(unsigned long *) ebp; + } while (count++ < 16); + return 0; +} +#undef last_sched +#undef first_sched diff -ruN linux-2.4.26/arch/i386/kernel/traps.c linux-2.4.26-BF2-C7_III/arch/i386/kernel/traps.c --- linux-2.4.26/arch/i386/kernel/traps.c 2004-07-10 22:40:44.000000000 -0600 +++ linux-2.4.26-BF2-C7_III/arch/i386/kernel/traps.c 2004-07-10 22:52:14.996507096 -0600 @@ -50,6 +50,10 @@ #include #include +#ifdef CONFIG_COBALT_RAQ +#include +#endif + asmlinkage int system_call(void); asmlinkage void lcall7(void); asmlinkage void lcall27(void); @@ -428,9 +432,12 @@ static void mem_parity_error(unsigned char reason, struct pt_regs * regs) { +#ifdef CONFIG_COBALT_RAQ + cobalt_nmi(reason, regs); +#else printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n"); printk("You probably have a hardware problem with your RAM chips\n"); - +#endif /* Clear and disable the memory parity error line. */ reason = (reason & 0xf) | 4; outb(reason, 0x61); diff -ruN linux-2.4.26/drivers/Makefile linux-2.4.26-BF2-C7_III/drivers/Makefile --- linux-2.4.26/drivers/Makefile 2004-07-10 22:40:44.000000000 -0600 +++ linux-2.4.26-BF2-C7_III/drivers/Makefile 2004-07-10 22:52:15.086493416 -0600 @@ -49,4 +49,6 @@ subdir-$(CONFIG_BLUEZ) += bluetooth +subdir-$(CONFIG_COBALT) += cobalt + include $(TOPDIR)/Rules.make diff -ruN linux-2.4.26/drivers/char/Makefile linux-2.4.26-BF2-C7_III/drivers/char/Makefile --- linux-2.4.26/drivers/char/Makefile 2004-07-10 22:40:44.000000000 -0600 +++ linux-2.4.26-BF2-C7_III/drivers/char/Makefile 2004-07-10 22:52:15.102490984 -0600 @@ -270,7 +270,7 @@ obj-$(CONFIG_AU1X00_GPIO) += au1000_gpio.o obj-$(CONFIG_AU1X00_USB_TTY) += au1000_usbtty.o obj-$(CONFIG_AU1X00_USB_RAW) += au1000_usbraw.o -obj-$(CONFIG_COBALT_LCD) += lcd.o +obj-$(CONFIG_COBALT_MIPS_LCD) += lcd.o obj-$(CONFIG_QIC02_TAPE) += tpqic02.o diff -ruN linux-2.4.26/drivers/char/Makefile.orig linux-2.4.26-BF2-C7_III/drivers/char/Makefile.orig --- linux-2.4.26/drivers/char/Makefile.orig 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/drivers/char/Makefile.orig 2004-07-10 22:52:15.104490680 -0600 @@ -0,0 +1,355 @@ +# +# Makefile for the kernel character device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now inherited from the +# parent makes.. +# + +# +# This file contains the font map for the default (hardware) font +# +FONTMAPFILE = cp437.uni + +O_TARGET := char.o + +obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o raw.o pty.o misc.o random.o + +# All of the (potential) objects that export symbols. +# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. + +export-objs := busmouse.o console.o keyboard.o sysrq.o \ + misc.o pty.o random.o selection.o serial.o \ + sonypi.o tty_io.o tty_ioctl.o generic_serial.o \ + au1000_gpio.o vac-serial.o hp_psaux.o nvram.o \ + scx200.o fetchop.o + +mod-subdirs := joystick ftape drm drm-4.0 pcmcia + +list-multi := + +KEYMAP =defkeymap.o +KEYBD =pc_keyb.o +CONSOLE =console.o +SERIAL =serial.o + +ifeq ($(ARCH),s390) + KEYMAP = + KEYBD = + CONSOLE = + SERIAL = +endif + +ifeq ($(ARCH),mips) + ifneq ($(CONFIG_PC_KEYB),y) + KEYBD = + endif + ifeq ($(CONFIG_VR41XX_KIU),y) + KEYMAP = + KEYBD = vr41xx_keyb.o + endif +endif + +ifeq ($(ARCH),s390x) + KEYMAP = + KEYBD = + CONSOLE = + SERIAL = +endif + +ifeq ($(ARCH),m68k) + ifdef CONFIG_AMIGA + KEYBD = amikeyb.o + else + ifndef CONFIG_MAC + KEYBD = + endif + endif + SERIAL = +endif + +ifeq ($(ARCH),parisc) + ifdef CONFIG_GSC_PS2 + KEYBD = hp_psaux.o hp_keyb.o + else + KEYBD = + endif + ifdef CONFIG_SERIAL_MUX + CONSOLE += mux.o + endif + ifdef CONFIG_PDC_CONSOLE + CONSOLE += pdc_console.o + endif +endif + +ifdef CONFIG_Q40 + KEYBD += q40_keyb.o + SERIAL = serial.o +endif + +ifdef CONFIG_APOLLO + KEYBD += dn_keyb.o +endif + +ifeq ($(ARCH),parisc) + ifdef CONFIG_GSC_PS2 + KEYBD = hp_psaux.o hp_keyb.o + else + KEYBD = + endif + ifdef CONFIG_PDC_CONSOLE + CONSOLE += pdc_console.o + endif +endif + +ifeq ($(ARCH),arm) + ifneq ($(CONFIG_PC_KEYMAP),y) + KEYMAP = + endif + ifneq ($(CONFIG_PC_KEYB),y) + KEYBD = + endif +endif + +ifeq ($(ARCH),sh) + KEYMAP = + KEYBD = + CONSOLE = + ifeq ($(CONFIG_SH_HP600),y) + KEYMAP = defkeymap.o + KEYBD = scan_keyb.o hp600_keyb.o + CONSOLE = console.o + endif + ifeq ($(CONFIG_SH_DMIDA),y) + # DMIDA does not connect the HD64465 PS/2 keyboard port + # but we allow for USB keyboards to be plugged in. + KEYMAP = defkeymap.o + KEYBD = # hd64465_keyb.o pc_keyb.o + CONSOLE = console.o + endif + ifeq ($(CONFIG_SH_EC3104),y) + KEYMAP = defkeymap.o + KEYBD = ec3104_keyb.o + CONSOLE = console.o + endif + ifeq ($(CONFIG_SH_DREAMCAST),y) + KEYMAP = defkeymap.o + KEYBD = + CONSOLE = console.o + endif +endif + +ifeq ($(CONFIG_DECSTATION),y) + KEYMAP = + KEYBD = +endif + +ifeq ($(CONFIG_BAGET_MIPS),y) + KEYBD = + SERIAL = vac-serial.o +endif + +ifeq ($(CONFIG_NINO),y) + SERIAL = +endif + +ifneq ($(CONFIG_SUN_SERIAL),) + SERIAL = +endif + +ifeq ($(CONFIG_QTRONIX_KEYBOARD),y) + KEYBD = qtronix.o + KEYMAP = qtronixmap.o +endif + +ifeq ($(CONFIG_DUMMY_KEYB),y) + KEYBD = dummy_keyb.o +endif + +obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o +obj-$(CONFIG_SERIAL) += $(SERIAL) +obj-$(CONFIG_SERIAL_HCDP) += hcdp_serial.o +obj-$(CONFIG_SERIAL_21285) += serial_21285.o +obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o +obj-$(CONFIG_SERIAL_AMBA) += serial_amba.o +obj-$(CONFIG_TS_AU1X00_ADS7846) += au1000_ts.o +obj-$(CONFIG_SERIAL_DEC) += decserial.o + +ifndef CONFIG_SUN_KEYBOARD + obj-$(CONFIG_VT) += keyboard.o $(KEYMAP) $(KEYBD) +else + obj-$(CONFIG_PCI) += keyboard.o $(KEYMAP) +endif + +obj-$(CONFIG_HIL) += hp_keyb.o +obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o +obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o +obj-$(CONFIG_ROCKETPORT) += rocket.o +obj-$(CONFIG_MOXA_SMARTIO) += mxser.o +obj-$(CONFIG_MOXA_INTELLIO) += moxa.o +obj-$(CONFIG_DIGI) += pcxx.o +obj-$(CONFIG_DIGIEPCA) += epca.o +obj-$(CONFIG_CYCLADES) += cyclades.o +obj-$(CONFIG_STALLION) += stallion.o +obj-$(CONFIG_ISTALLION) += istallion.o +obj-$(CONFIG_SIBYTE_SB1250_DUART) += sb1250_duart.o +obj-$(CONFIG_COMPUTONE) += ip2.o ip2main.o +obj-$(CONFIG_RISCOM8) += riscom8.o +obj-$(CONFIG_ISI) += isicom.o +obj-$(CONFIG_ESPSERIAL) += esp.o +obj-$(CONFIG_SYNCLINK) += synclink.o +obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o +obj-$(CONFIG_N_HDLC) += n_hdlc.o +obj-$(CONFIG_SPECIALIX) += specialix.o +obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o +obj-$(CONFIG_A2232) += ser_a2232.o generic_serial.o +obj-$(CONFIG_SX) += sx.o generic_serial.o +obj-$(CONFIG_RIO) += rio/rio.o generic_serial.o +obj-$(CONFIG_SH_SCI) += sh-sci.o generic_serial.o +obj-$(CONFIG_SERIAL167) += serial167.o +obj-$(CONFIG_MVME147_SCC) += generic_serial.o vme_scc.o +obj-$(CONFIG_MVME162_SCC) += generic_serial.o vme_scc.o +obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o +obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o +obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o +obj-$(CONFIG_TXX927_SERIAL) += serial_txx927.o +obj-$(CONFIG_SERIAL_TXX9) += generic_serial.o serial_txx9.o +obj-$(CONFIG_IP22_SERIAL) += sgiserial.o +obj-$(CONFIG_AU1X00_UART) += au1x00-serial.o +obj-$(CONFIG_SGI_L1_SERIAL) += sn_serial.o + +subdir-$(CONFIG_RIO) += rio +subdir-$(CONFIG_INPUT) += joystick + +obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o +obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o +obj-$(CONFIG_PRINTER) += lp.o +obj-$(CONFIG_TIPAR) += tipar.o +obj-$(CONFIG_OBMOUSE) += obmouse.o + +ifeq ($(CONFIG_INPUT),y) +obj-y += joystick/js.o +endif + +obj-$(CONFIG_FETCHOP) += fetchop.o +obj-$(CONFIG_BUSMOUSE) += busmouse.o +obj-$(CONFIG_DTLK) += dtlk.o +obj-$(CONFIG_R3964) += n_r3964.o +obj-$(CONFIG_APPLICOM) += applicom.o +obj-$(CONFIG_SONYPI) += sonypi.o +obj-$(CONFIG_MS_BUSMOUSE) += msbusmouse.o +obj-$(CONFIG_82C710_MOUSE) += qpmouse.o +obj-$(CONFIG_AMIGAMOUSE) += amigamouse.o +obj-$(CONFIG_ATARIMOUSE) += atarimouse.o +obj-$(CONFIG_ADBMOUSE) += adbmouse.o +obj-$(CONFIG_PC110_PAD) += pc110pad.o +obj-$(CONFIG_MK712_MOUSE) += mk712.o +obj-$(CONFIG_RTC) += rtc.o +obj-$(CONFIG_GEN_RTC) += genrtc.o +obj-$(CONFIG_EFI_RTC) += efirtc.o +obj-$(CONFIG_SGI_DS1286) += ds1286.o +obj-$(CONFIG_MIPS_RTC) += mips_rtc.o +obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o +ifeq ($(CONFIG_PPC),) + obj-$(CONFIG_NVRAM) += nvram.o +endif +obj-$(CONFIG_TOSHIBA) += toshiba.o +obj-$(CONFIG_I8K) += i8k.o +obj-$(CONFIG_DS1620) += ds1620.o +obj-$(CONFIG_DS1742) += ds1742.o +obj-$(CONFIG_INTEL_RNG) += i810_rng.o +obj-$(CONFIG_AMD_RNG) += amd768_rng.o +obj-$(CONFIG_HW_RANDOM) += hw_random.o +obj-$(CONFIG_AMD_PM768) += amd76x_pm.o +obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o + +obj-$(CONFIG_ITE_GPIO) += ite_gpio.o +obj-$(CONFIG_AU1X00_GPIO) += au1000_gpio.o +obj-$(CONFIG_AU1X00_USB_TTY) += au1000_usbtty.o +obj-$(CONFIG_AU1X00_USB_RAW) += au1000_usbraw.o +obj-$(CONFIG_COBALT_LCD) += lcd.o + +obj-$(CONFIG_QIC02_TAPE) += tpqic02.o + +subdir-$(CONFIG_FTAPE) += ftape +subdir-$(CONFIG_DRM_OLD) += drm-4.0 +subdir-$(CONFIG_DRM_NEW) += drm +subdir-$(CONFIG_PCMCIA) += pcmcia +subdir-$(CONFIG_AGP) += agp + +ifeq ($(CONFIG_FTAPE),y) +obj-y += ftape/ftape.o +endif + +obj-$(CONFIG_H8) += h8.o +obj-$(CONFIG_PPDEV) += ppdev.o +obj-$(CONFIG_DZ) += dz.o +obj-$(CONFIG_NWBUTTON) += nwbutton.o +obj-$(CONFIG_NWFLASH) += nwflash.o +obj-$(CONFIG_SCx200) += scx200.o +obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o + +# Only one watchdog can succeed. We probe the hardware watchdog +# drivers first, then the softdog driver. This means if your hardware +# watchdog dies or is 'borrowed' for some reason the software watchdog +# still gives you some cover. + +obj-$(CONFIG_PCWATCHDOG) += pcwd.o +obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o +obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o +obj-$(CONFIG_IB700_WDT) += ib700wdt.o +obj-$(CONFIG_MIXCOMWD) += mixcomwd.o +obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o +obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o +obj-$(CONFIG_SC520_WDT) += sc520_wdt.o +obj-$(CONFIG_WDT) += wdt.o +obj-$(CONFIG_WDTPCI) += wdt_pci.o +obj-$(CONFIG_21285_WATCHDOG) += wdt285.o +obj-$(CONFIG_977_WATCHDOG) += wdt977.o +obj-$(CONFIG_I810_TCO) += i810-tco.o +obj-$(CONFIG_MACHZ_WDT) += machzwd.o +obj-$(CONFIG_SH_WDT) += shwdt.o +obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o +obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o +obj-$(CONFIG_ALIM1535_WDT) += alim1535d_wdt.o +obj-$(CONFIG_INDYDOG) += indydog.o +obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o +obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o +obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o +obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o +obj-$(CONFIG_AMD7XX_TCO) += amd7xx_tco.o +obj-$(CONFIG_INDYDOG) += indydog.o +obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o + +subdir-$(CONFIG_MWAVE) += mwave +ifeq ($(CONFIG_MWAVE),y) + obj-y += mwave/mwave.o +endif + +subdir-$(CONFIG_IPMI_HANDLER) += ipmi +ifeq ($(CONFIG_IPMI_HANDLER),y) + obj-y += ipmi/ipmi.o +endif + +include $(TOPDIR)/Rules.make + +fastdep: + +conmakehash: conmakehash.c + $(HOSTCC) $(HOSTCFLAGS) -o conmakehash conmakehash.c + +consolemap_deftbl.c: $(FONTMAPFILE) conmakehash + ./conmakehash $(FONTMAPFILE) > consolemap_deftbl.c + +consolemap_deftbl.o: consolemap_deftbl.c $(TOPDIR)/include/linux/types.h + +.DELETE_ON_ERROR: + +defkeymap.c: defkeymap.map + set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@ + +qtronixmap.c: qtronixmap.map + set -e ; loadkeys --mktable $< | sed -e 's/^static *//' > $@ diff -ruN linux-2.4.26/drivers/char/misc.c linux-2.4.26-BF2-C7_III/drivers/char/misc.c --- linux-2.4.26/drivers/char/misc.c 2004-07-10 22:40:44.000000000 -0600 +++ linux-2.4.26-BF2-C7_III/drivers/char/misc.c 2004-07-10 22:52:15.107490224 -0600 @@ -266,7 +266,7 @@ #ifdef CONFIG_TOSHIBA tosh_init(); #endif -#ifdef CONFIG_COBALT_LCD +#ifdef CONFIG_COBALT_MIPS_LCD lcd_init(); #endif #ifdef CONFIG_I8K diff -ruN linux-2.4.26/drivers/cobalt/Config.in linux-2.4.26-BF2-C7_III/drivers/cobalt/Config.in --- linux-2.4.26/drivers/cobalt/Config.in 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/drivers/cobalt/Config.in 2004-07-10 22:52:15.107490224 -0600 @@ -0,0 +1,42 @@ +# +# Cobalt Networks hardware support +# +mainmenu_option next_comment +comment 'Sun and Cobalt Networks support' +bool 'Support for Sun and Cobalt Networks x86 systems' CONFIG_COBALT + +if [ "$CONFIG_COBALT" != "n" ]; then + bool ' Cobalt RaQ/Qube hardware' CONFIG_COBALT_RAQ + if [ "$CONFIG_COBALT_RAQ" != "n" ]; then + bool ' Gen III (3000 series) system support' CONFIG_COBALT_GEN_III + bool ' Gen V (5000 series) system support' CONFIG_COBALT_GEN_V + bool ' Create legacy /proc files' CONFIG_COBALT_OLDPROC + bool ' Cobalt Bootloader Support' CONFIG_COBALT_BOOTLOADER + + comment 'Cobalt hardware options' + + bool ' Front panel (LCD) support' CONFIG_COBALT_LCD + if [ "$CONFIG_COBALT_LCD" != "n" ]; then + bool ' Use compatible device number' CONFIG_COBALT_LCD_DEV_COMPAT + bool ' Twiddle LCD on boot' CONFIG_COBALT_LCD_TWIDDLE + fi + bool ' Software controlled LED support' CONFIG_COBALT_LED + tristate ' Serial number support' CONFIG_COBALT_SERNUM + if [ "$CONFIG_KDB" != "y" ]; then + bool ' Watchdog timer support' CONFIG_COBALT_WDT + fi + bool ' System sensors support' CONFIG_COBALT_SENSORS + tristate ' Fan tachometer support' CONFIG_COBALT_FANS + tristate ' Memory information support' CONFIG_COBALT_RAMINFO + bool ' Disk drive ruler support' CONFIG_COBALT_RULER + if [ "$CONFIG_COBALT_GEN_V" != "n" ]; then + bool ' Cobalt ACPI support' CONFIG_COBALT_ACPI + else + define_bool CONFIG_COBALT_ACPI n + fi + if [ "$CONFIG_COBALT_ACPI" != "n" ]; then + bool ' /proc/acpi emulation' CONFIG_COBALT_EMU_ACPI + fi + fi +fi +endmenu diff -ruN linux-2.4.26/drivers/cobalt/Makefile linux-2.4.26-BF2-C7_III/drivers/cobalt/Makefile --- linux-2.4.26/drivers/cobalt/Makefile 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/drivers/cobalt/Makefile 2004-07-10 22:52:15.108490072 -0600 @@ -0,0 +1,20 @@ +# +# Makefile for the Sun/Cobalt device drivers +# + +O_TARGET := cobalt.o + +export-objs := init.o systype.o wdt.o i2c.o + +obj-$(CONFIG_COBALT) += init.o systype.o +obj-$(CONFIG_COBALT_RAQ) += 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 + +include $(TOPDIR)/Rules.make diff -ruN linux-2.4.26/drivers/cobalt/README linux-2.4.26-BF2-C7_III/drivers/cobalt/README --- linux-2.4.26/drivers/cobalt/README 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/drivers/cobalt/README 2004-07-10 22:52:15.108490072 -0600 @@ -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 -ruN linux-2.4.26/drivers/cobalt/acpi.c linux-2.4.26-BF2-C7_III/drivers/cobalt/acpi.c --- linux-2.4.26/drivers/cobalt/acpi.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/drivers/cobalt/acpi.c 2004-07-10 22:52:15.111489616 -0600 @@ -0,0 +1,1988 @@ + /* + * 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 void 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 ; itable_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 void 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; +} + + + + +int __init cobalt_acpi_init(void) +{ + int err; + + printk(KERN_INFO "Initializing Cobalt ACPI driver.\n"); + + 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( ®ions->tmr_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->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( ®ions->bm_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->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( ®ions->gbl_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->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( ®ions->pwrbtn_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->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( ®ions->slpbtn_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->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( ®ions->rtc_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->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( ®ions->wak_ref_cnt ); + } + else + { + if( atomic_dec_and_test( ®ions->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( ®ions->gpe_ref_cnt[ev_data] ); + } + else + { + if( atomic_dec_and_test( ®ions->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; + u32 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) +{ + int 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 -ruN linux-2.4.26/drivers/cobalt/fans.c linux-2.4.26-BF2-C7_III/drivers/cobalt/fans.c --- linux-2.4.26/drivers/cobalt/fans.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/drivers/cobalt/fans.c 2004-07-10 22:52:15.112489464 -0600 @@ -0,0 +1,413 @@ +/* $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 +#if defined(CONFIG_COBALT_FANS) || defined(CONFIG_COBALT_FANS_MODULE) + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +/* 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; + } + +#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; ifan[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; ifan[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; ifan[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; ifan[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 -ruN linux-2.4.26/drivers/cobalt/i2c.c linux-2.4.26-BF2-C7_III/drivers/cobalt/i2c.c --- linux-2.4.26/drivers/cobalt/i2c.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/drivers/cobalt/i2c.c 2004-07-10 22:52:15.114489160 -0600 @@ -0,0 +1,517 @@ +/* + * $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. + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 int 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 -ruN linux-2.4.26/drivers/cobalt/init.c linux-2.4.26-BF2-C7_III/drivers/cobalt/init.c --- linux-2.4.26/drivers/cobalt/init.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/drivers/cobalt/init.c 2004-07-10 22:52:15.114489160 -0600 @@ -0,0 +1,111 @@ +/* $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 +#include +#include +#include +#include +#include +#include +#include + +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); + +#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 for reboot */ + cobalt_wdt_init(); +#endif +#ifdef CONFIG_COBALT_SENSORS + cobalt_sensors_init(); +#endif +#ifdef CONFIG_COBALT_FANS + cobalt_fan_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 -ruN linux-2.4.26/drivers/cobalt/lcd.c linux-2.4.26-BF2-C7_III/drivers/cobalt/lcd.c --- linux-2.4.26/drivers/cobalt/lcd.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/drivers/cobalt/lcd.c 2004-07-10 22:52:15.116488856 -0600 @@ -0,0 +1,843 @@ +/* + * $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 + * + * 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 + +#ifdef CONFIG_COBALT_LCD + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#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 + +/* this is the generic device minor assigned to /dev/lcd */ +#define COBALT_LCD_MINOR 156 +#define COBALT_LCD_OLD_MINOR 140 + +/* 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 = { + owner: THIS_MODULE, + read: cobalt_lcd_read, + ioctl: cobalt_lcd_ioctl, + open: cobalt_lcd_open, +}; + +/* device structure */ +static struct miscdevice lcd_dev = { + COBALT_LCD_MINOR, + "lcd", + &lcd_fops +}; +#ifdef CONFIG_COBALT_LCD_DEV_COMPAT +/* device structure */ +static struct miscdevice lcd_compat_dev = { + COBALT_LCD_OLD_MINOR, + "lcd (compatible)", + &lcd_fops +}; +#endif + +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: + } + + 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: + } + + 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 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 int 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 int 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) +{ + if (initialized) + return 0; + + initialized=1; + + if (disable_lcd) { + printk(KERN_INFO "%s DISABLED\n", LCD_DRIVER); + return 0; + } + + misc_register(&lcd_dev); +#ifdef CONFIG_COBALT_LCD_DEV_COMPAT + misc_register(&lcd_compat_dev); +#endif + + if (cobt_is_monterey() + && (cobalt_i2c_read_byte(COBALT_I2C_DEV_LCD_INST, 0) != 0xff)) { + 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; + + notifier_chain_register( &panic_notifier_list, &lcd_nb ); + + return 0; +} + +#endif /* CONFIG_COBALT_LCD */ diff -ruN linux-2.4.26/drivers/cobalt/led.c linux-2.4.26-BF2-C7_III/drivers/cobalt/led.c --- linux-2.4.26/drivers/cobalt/led.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/drivers/cobalt/led.c 2004-07-10 22:52:15.117488704 -0600 @@ -0,0 +1,502 @@ +/* + * $Id: led.c,v 1.36 2002/05/10 18:44:45 duncan Exp $ + * led.c : driver for Cobalt LEDs + * + * Copyright 1996-2000 Cobalt Networks, Inc. + * Copyright 2001 Sun Microsystems, Inc. + * + * By: Andrew Bose + * Timothy Stonis + * Tim Hockin + * Adrian Sun + * Duncan Laurie + * + * 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 + +#ifdef CONFIG_COBALT_LED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include + +#include +#include +#include +#include +#include + +#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); + +#if 0 + /* 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); +#endif + } 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; + + 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 -ruN linux-2.4.26/drivers/cobalt/net.c linux-2.4.26-BF2-C7_III/drivers/cobalt/net.c --- linux-2.4.26/drivers/cobalt/net.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/drivers/cobalt/net.c 2004-07-10 22:52:15.117488704 -0600 @@ -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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 -ruN linux-2.4.26/drivers/cobalt/raminfo.c linux-2.4.26-BF2-C7_III/drivers/cobalt/raminfo.c --- linux-2.4.26/drivers/cobalt/raminfo.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/drivers/cobalt/raminfo.c 2004-07-10 22:52:15.118488552 -0600 @@ -0,0 +1,312 @@ +/* $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 + +#if defined(CONFIG_COBALT_RAMINFO) || defined(CONFIG_COBALT_RAMINFO_MODULE) + +#include +#include +#include +#include + +#include +#include + +#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; + } + +#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; jtotal; 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; itotal; 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 */ + +module_init(cobalt_raminfo_init); +module_exit(cobalt_raminfo_exit); + +MODULE_AUTHOR("Sun Cobalt"); +MODULE_DESCRIPTION("DIMM Information"); +MODULE_LICENSE("GPL"); + +#endif /* CONFIG_COBALT_RAMINFO || CONFIG_COBALT_RAMINFO_MODULE */ diff -ruN linux-2.4.26/drivers/cobalt/ruler.c linux-2.4.26-BF2-C7_III/drivers/cobalt/ruler.c --- linux-2.4.26/drivers/cobalt/ruler.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/drivers/cobalt/ruler.c 2004-07-10 22:52:15.119488400 -0600 @@ -0,0 +1,407 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#define RULER_TIMEOUT (HZ >> 1) /* .5s */ +#define MAX_COBT_DRIVES 4 + +/* all of this is for gen V */ +static struct timer_list cobalt_ruler_timer; +static rwlock_t ruler_lock = RW_LOCK_UNLOCKED; +static ide_hwif_t *channels[MAX_COBT_DRIVES]; +static ide_busproc_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_hwif_t *hwif, 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](hwif, 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) +{ + 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] && channels[i]->drives[0].present + && channels[i]->drives[0].service_start != old[i]) { + leds |= ledmap[i]; + old[i] = channels[i]->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_hwif_t *hwif, 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] == hwif) { + break; + } + } + + if (idx >= MAX_COBT_DRIVES) { + /* not a hwif we manage? */ + return 0; + } + + r = do_busproc(idx, hwif, 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_hwif_t *hwif) +{ + 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] = hwif; + if (hwif->busproc) { + busprocs[idx] = hwif->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_hwif_t *hwif) +{ + 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] == hwif) { + channels[i] = NULL; + hwif->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; + +#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(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 -ruN linux-2.4.26/drivers/cobalt/sensors.c linux-2.4.26-BF2-C7_III/drivers/cobalt/sensors.c --- linux-2.4.26/drivers/cobalt/sensors.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/drivers/cobalt/sensors.c 2004-07-10 22:52:15.130486728 -0600 @@ -0,0 +1,519 @@ +/* $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 +#ifdef CONFIG_COBALT_SENSORS + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +/* 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; + } + +#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 - */ + /* 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; jev_data |= (1 << j); + volt_map[j].cache = 0; + } + } + break; + + case COBALT_ACPI_EVT_THERM: + evt->ev_data = 0; + for (j=0; jev_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= 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 -ruN linux-2.4.26/drivers/cobalt/serialnum.c linux-2.4.26-BF2-C7_III/drivers/cobalt/serialnum.c --- linux-2.4.26/drivers/cobalt/serialnum.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/drivers/cobalt/serialnum.c 2004-07-10 22:52:15.132486424 -0600 @@ -0,0 +1,448 @@ +/* $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 +#if defined (CONFIG_COBALT_SERNUM) || defined(CONFIG_COBALT_SERNUM_MODULE) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define SERNUM_VER "1.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; + + save_flags(flags); + + for (i = 0; i < 8; i++, c >>= 1) { + cli(); + if (c & 1) { + /* Transmit a 1 */ + io_write(5); + udelay(80); + } else { + /* Transmit a 0 */ + io_write(80); + udelay(10); + } + restore_flags(flags); + } +} + +static int __init +io_read_byte(void) +{ + int i; + int c = 0; + unsigned long flags; + + save_flags(flags); + + for (i = 0; i < 8; i++) { + cli(); + io_write(1); /* Start the read */ + udelay(2); + if (io_read()) { + c |= 1 << i; + } + udelay(60); + restore_flags(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 + */ + + save_flags(flags); + cli(); + + /* 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"); + } + restore_flags(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; + } + } + restore_flags(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; + + /* 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 -ruN linux-2.4.26/drivers/cobalt/systype.c linux-2.4.26-BF2-C7_III/drivers/cobalt/systype.c --- linux-2.4.26/drivers/cobalt/systype.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/drivers/cobalt/systype.c 2004-07-10 22:52:15.132486424 -0600 @@ -0,0 +1,274 @@ +/* + * $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 + +#include +#include +#include +#include + +#include +#include +#include + +/* 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("Cobalt system type is unknown (trouble will ensue)\n"); + return -1; + } + + 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 */ + retval = (val & 0x20) ? COBT_PACIFICA : 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 -ruN linux-2.4.26/drivers/cobalt/wdt.c linux-2.4.26-BF2-C7_III/drivers/cobalt/wdt.c --- linux-2.4.26/drivers/cobalt/wdt.c 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/drivers/cobalt/wdt.c 2004-07-10 22:52:15.133486272 -0600 @@ -0,0 +1,419 @@ +/* $Id: wdt.c,v 1.21 2002/07/02 00:38:17 asun Exp $ */ +/* + * Cobalt kernel WDT timer driver + * Tim Hockin + * Adrian Sun + * Chris Johnson + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 */ + +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) +{ + if (cobt_is_3k()) { + /* + * Set up the PMU for 3k boards. It has a max + * of a 1 second timeout. + */ + struct pci_dev *south; + char tmp; + + /* 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. + */ + unsigned char tmp; + + /* 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; + + 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 -ruN linux-2.4.26/include/cobalt/acpi.h linux-2.4.26-BF2-C7_III/include/cobalt/acpi.h --- linux-2.4.26/include/cobalt/acpi.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/include/cobalt/acpi.h 2004-07-10 22:52:15.133486272 -0600 @@ -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 -ruN linux-2.4.26/include/cobalt/cobalt.h linux-2.4.26-BF2-C7_III/include/cobalt/cobalt.h --- linux-2.4.26/include/cobalt/cobalt.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/include/cobalt/cobalt.h 2004-07-10 22:52:15.134486120 -0600 @@ -0,0 +1,58 @@ +/* $Id: cobalt.h,v 1.16 2002/11/04 17:54:15 thockin Exp $ */ +/* Copyright 2001 Sun Microsystems, Inc. */ +#include +#if !defined(COBALT_H) && defined(CONFIG_COBALT) +#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 +#include + +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) */ diff -ruN linux-2.4.26/include/cobalt/i2c.h linux-2.4.26-BF2-C7_III/include/cobalt/i2c.h --- linux-2.4.26/include/cobalt/i2c.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/include/cobalt/i2c.h 2004-07-10 22:52:15.134486120 -0600 @@ -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 +#include + +#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 -ruN linux-2.4.26/include/cobalt/lcd.h linux-2.4.26-BF2-C7_III/include/cobalt/lcd.h --- linux-2.4.26/include/cobalt/lcd.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/include/cobalt/lcd.h 2004-07-10 22:52:15.134486120 -0600 @@ -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 +#endif +#include + +#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 -ruN linux-2.4.26/include/cobalt/led.h linux-2.4.26-BF2-C7_III/include/cobalt/led.h --- linux-2.4.26/include/cobalt/led.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/include/cobalt/led.h 2004-07-10 22:52:15.135485968 -0600 @@ -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 -ruN linux-2.4.26/include/cobalt/misc.h linux-2.4.26-BF2-C7_III/include/cobalt/misc.h --- linux-2.4.26/include/cobalt/misc.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/include/cobalt/misc.h 2004-07-10 22:52:15.135485968 -0600 @@ -0,0 +1,11 @@ +/* $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_nmi(unsigned char reason, struct pt_regs *regs); +void cobalt_restart(void); +void cobalt_halt(void); +void cobalt_power_off(void); + +#endif diff -ruN linux-2.4.26/include/cobalt/net.h linux-2.4.26-BF2-C7_III/include/cobalt/net.h --- linux-2.4.26/include/cobalt/net.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/include/cobalt/net.h 2004-07-10 22:52:15.135485968 -0600 @@ -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 +#include + +void cobalt_net_register(struct net_device *ndev); +void cobalt_net_unregister(struct net_device *ndev); + +#endif diff -ruN linux-2.4.26/include/cobalt/nvram.h linux-2.4.26-BF2-C7_III/include/cobalt/nvram.h --- linux-2.4.26/include/cobalt/nvram.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/include/cobalt/nvram.h 2004-07-10 22:52:15.137485664 -0600 @@ -0,0 +1,130 @@ +/* + * $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 + +/* for all current systems, this is where NVRAM starts */ +#define NVRAM_FIRST_BYTE 14 +/* all these functions expect an NVRAM offset, not an absolute */ +#define NVRAM_OFFSET(x) ((x)-NVRAM_FIRST_BYTE) + +#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 -ruN linux-2.4.26/include/cobalt/ruler.h linux-2.4.26-BF2-C7_III/include/cobalt/ruler.h --- linux-2.4.26/include/cobalt/ruler.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/include/cobalt/ruler.h 2004-07-10 22:52:15.137485664 -0600 @@ -0,0 +1,11 @@ +/* $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 + +void cobalt_ruler_register(ide_hwif_t *hwif); +void cobalt_ruler_unregister(ide_hwif_t *hwif); + +#endif diff -ruN linux-2.4.26/include/cobalt/sensors.h linux-2.4.26-BF2-C7_III/include/cobalt/sensors.h --- linux-2.4.26/include/cobalt/sensors.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/include/cobalt/sensors.h 2004-07-10 22:52:15.137485664 -0600 @@ -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 + +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 -ruN linux-2.4.26/include/cobalt/serialnum.h linux-2.4.26-BF2-C7_III/include/cobalt/serialnum.h --- linux-2.4.26/include/cobalt/serialnum.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/include/cobalt/serialnum.h 2004-07-10 22:52:15.137485664 -0600 @@ -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 + +char *cobalt_serialnum_get(void); +unsigned long cobalt_hostid_get(void); + +#endif /* COBALT_SERIALNUM_H */ diff -ruN linux-2.4.26/include/cobalt/superio.h linux-2.4.26-BF2-C7_III/include/cobalt/superio.h --- linux-2.4.26/include/cobalt/superio.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/include/cobalt/superio.h 2004-07-10 22:52:15.138485512 -0600 @@ -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 +#include + +/* 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 -ruN linux-2.4.26/include/cobalt/systype.h linux-2.4.26-BF2-C7_III/include/cobalt/systype.h --- linux-2.4.26/include/cobalt/systype.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/include/cobalt/systype.h 2004-07-10 22:52:15.139485360 -0600 @@ -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 + +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 -ruN linux-2.4.26/include/cobalt/wdt.h linux-2.4.26-BF2-C7_III/include/cobalt/wdt.h --- linux-2.4.26/include/cobalt/wdt.h 1969-12-31 17:00:00.000000000 -0700 +++ linux-2.4.26-BF2-C7_III/include/cobalt/wdt.h 2004-07-10 22:52:15.139485360 -0600 @@ -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 + +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 -ruN linux-2.4.26/init/main.c linux-2.4.26-BF2-C7_III/init/main.c --- linux-2.4.26/init/main.c 2004-07-10 22:40:44.000000000 -0600 +++ linux-2.4.26-BF2-C7_III/init/main.c 2004-07-10 22:52:15.167481104 -0600 @@ -112,6 +112,10 @@ extern void ipc_init(void); #endif +#ifdef CONFIG_COBALT +extern int cobalt_init(void); +#endif + /* * Boot command-line arguments */ @@ -529,6 +533,9 @@ #ifdef CONFIG_TC tc_init(); #endif +#ifdef CONFIG_COBALT + cobalt_init(); +#endif /* Networking initialization needs a process context */ sock_init();