diff options
author | Koen Kooi <koen@openembedded.org> | 2005-06-30 08:19:37 +0000 |
---|---|---|
committer | OpenEmbedded Project <openembedded-devel@lists.openembedded.org> | 2005-06-30 08:19:37 +0000 |
commit | c8e5702127e507e82e6f68a4b8c546803accea9d (patch) | |
tree | 00583491f40ecc640f2b28452af995e3a63a09d7 /packages/linux/linux-colinux-2.4.28/colinux-0.6.1.patch | |
parent | 87ec8ca4d2e2eb4d1c1e1e1a6b46a395d56805b9 (diff) |
import clean BK tree at cset 1.3670
Diffstat (limited to 'packages/linux/linux-colinux-2.4.28/colinux-0.6.1.patch')
-rw-r--r-- | packages/linux/linux-colinux-2.4.28/colinux-0.6.1.patch | 5156 |
1 files changed, 5156 insertions, 0 deletions
diff --git a/packages/linux/linux-colinux-2.4.28/colinux-0.6.1.patch b/packages/linux/linux-colinux-2.4.28/colinux-0.6.1.patch index e69de29bb2..fca3c277ee 100644 --- a/packages/linux/linux-colinux-2.4.28/colinux-0.6.1.patch +++ b/packages/linux/linux-colinux-2.4.28/colinux-0.6.1.patch @@ -0,0 +1,5156 @@ + +# +# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher +# + +--- linux-2.4.28/CREDITS~colinux-0.6.1 2004-11-17 06:54:20.000000000 -0500 ++++ linux-2.4.28/CREDITS 2004-11-27 15:59:21.283010512 -0500 +@@ -54,6 +54,12 @@ + S: CH-1015 Lausanne + S: Switzerland + ++A: Dan Aloni ++E: da-x@gmx.net ++D: Cooperative Linux ++D: Various kernel patches ++S: Israel ++ + N: Tim Alpaerts + E: tim_alpaerts@toyota-motor-europe.com + D: 802.2 class II logical link control layer, +--- linux-2.4.28/Documentation/devices.txt~colinux-0.6.1 2004-02-18 08:36:30.000000000 -0500 ++++ linux-2.4.28/Documentation/devices.txt 2004-11-27 15:59:21.285010208 -0500 +@@ -1926,6 +1926,13 @@ + 17 = /dev/cosa1c1 2nd board, 2nd channel + ... + ++ block coLinux Block devices ++ 0 = /dev/cobd0 First coLinux device ++ 1 = /dev/cobd1 Second coLinux device ++ ... ++ ++ These block devices map to files or devices in the host FS. ++ + 118 char Solidum ??? + 0 = /dev/solnp0 + 1 = /dev/solnp1 +--- linux-2.4.28/Makefile~colinux-0.6.1 2004-11-17 06:54:22.000000000 -0500 ++++ linux-2.4.28/Makefile 2004-11-27 15:59:30.235649504 -0500 +@@ -1,7 +1,7 @@ + VERSION = 2 + PATCHLEVEL = 4 + SUBLEVEL = 28 +-EXTRAVERSION = ++EXTRAVERSION = -co-0.6.1 + + KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) + +@@ -27,7 +27,11 @@ + + AS = $(CROSS_COMPILE)as + LD = $(CROSS_COMPILE)ld +-CC = $(CROSS_COMPILE)gcc ++ifeq ($(GCCTRACE),Y) ++CC = $(CROSS_COMPILE)$(COLINUX_ROOT)/bin/tracewrapper.py gcc ++else ++CC = $(CROSS_COMPILE)gcc ++endif + CPP = $(CC) -E + AR = $(CROSS_COMPILE)ar + NM = $(CROSS_COMPILE)nm +--- linux-2.4.28/arch/i386/config.in~colinux-0.6.1 2004-11-17 06:54:21.000000000 -0500 ++++ linux-2.4.28/arch/i386/config.in 2004-11-27 15:59:21.286010056 -0500 +@@ -226,13 +226,20 @@ + bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR + bool 'Symmetric multi-processing support' CONFIG_SMP + if [ "$CONFIG_SMP" != "y" ]; then +- bool 'Local APIC support on uniprocessors' CONFIG_X86_UP_APIC +- dep_bool 'IO-APIC support on uniprocessors' CONFIG_X86_UP_IOAPIC $CONFIG_X86_UP_APIC +- if [ "$CONFIG_X86_UP_APIC" = "y" ]; then +- define_bool CONFIG_X86_LOCAL_APIC y +- fi +- if [ "$CONFIG_X86_UP_IOAPIC" = "y" ]; then +- define_bool CONFIG_X86_IO_APIC y ++ if [ "$CONFIG_COOPERATIVE" = "y" ]; then ++ bool 'Cooperative PIC (COPIC) support' CONFIG_X86_UP_COPIC ++ if [ "$CONFIG_X86_UP_COPIC" = "y" ]; then ++ define_bool CONFIG_X86_COPIC y ++ fi ++ else ++ bool 'Local APIC support on uniprocessors' CONFIG_X86_UP_APIC ++ dep_bool 'IO-APIC support on uniprocessors' CONFIG_X86_UP_IOAPIC $CONFIG_X86_UP_APIC ++ if [ "$CONFIG_X86_UP_APIC" = "y" ]; then ++ define_bool CONFIG_X86_LOCAL_APIC y ++ fi ++ if [ "$CONFIG_X86_UP_IOAPIC" = "y" ]; then ++ define_bool CONFIG_X86_IO_APIC y ++ fi + fi + else + int 'Maximum number of CPUs (2-32)' CONFIG_NR_CPUS 32 +@@ -343,12 +350,13 @@ + bool ' Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF + fi + ++bool 'Cooperative Mode' CONFIG_COOPERATIVE ++ + source drivers/acpi/Config.in + + endmenu + + source drivers/mtd/Config.in +- + source drivers/parport/Config.in + + source drivers/pnp/Config.in +@@ -445,7 +453,11 @@ + if [ "$CONFIG_VT" = "y" ]; then + mainmenu_option next_comment + comment 'Console drivers' +- bool 'VGA text console' CONFIG_VGA_CONSOLE ++ if [ "$CONFIG_COOPERATIVE" = "n" ]; then ++ bool 'VGA text console' CONFIG_VGA_CONSOLE ++ else ++ bool 'coLinux Pseudo-VGA text console' CONFIG_COOPERATIVE_CONSOLE ++ fi + bool 'Video mode selection support' CONFIG_VIDEO_SELECT + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'MDA text console (dual-headed) (EXPERIMENTAL)' CONFIG_MDA_CONSOLE +--- linux-2.4.28/arch/i386/kernel/Makefile~colinux-0.6.1 2003-11-28 13:26:19.000000000 -0500 ++++ linux-2.4.28/arch/i386/kernel/Makefile 2004-11-27 15:59:21.287009904 -0500 +@@ -18,7 +18,7 @@ + + obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ + ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ +- pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o ++ pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o cooperative.o \ + + + ifdef CONFIG_PCI +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.28/arch/i386/kernel/cooperative.c 2004-11-27 15:59:21.287009904 -0500 +@@ -0,0 +1,160 @@ ++#include <linux/kernel.h> ++#include <linux/string.h> ++#include <linux/interrupt.h> ++#include <linux/mm.h> ++ ++#include <asm/keyboard.h> ++#include <linux/kbd_ll.h> ++#include <linux/cooperative.h> ++#include <asm/smp.h> ++#include <asm/desc.h> ++ ++CO_TRACE_STOP; ++ ++ ++/* ++ * The next asm code is the first Linux code that runs in the ++ * coLinux kernel context. It receives %ecx which contains the ++ * address of the passage page. The passage page code sets %ecx ++ * to this value in its context restore part. ++ */ ++ ++asm( ++ "" ++ ".section .text\n" ++ ".globl colinux_start\n" ++ "colinux_start:\n" ++ " call colinux_start_arch\n" ++ ".previous\n" ++ ""); ++ ++static void colinux_early_cpu_init(void) ++{ ++ /* ++ * On the first switch to Linux we must set up a valid TR because ++ * the passage page code assumes such one exists. This is basically ++ * copied code from cpu_init(). ++ * ++ * P.S this is protected by CO_TRACE_STOP so that we don't ++ * have a monitor context switch. ++ */ ++ ++ int nr = smp_processor_id(); ++ struct tss_struct * t = &init_tss[nr]; ++ ++ set_tss_desc(nr,t); ++ gdt_table[__TSS(nr)].b &= 0xfffffdff; ++ load_TR(nr); ++ gdt_table[__TSS(nr)].b &= 0xfffffdff; ++ ++ __asm__ __volatile__("movl %%cr4, %0" : "=r" (mmu_cr4_features)); ++} ++ ++void colinux_start_arch() ++{ ++ colinux_early_cpu_init(); ++ colinux_start_c(); ++} ++ ++extern void ctrl_alt_del(void); ++ ++void co_handle_device_interrupt(co_linux_message_t *message) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ ++ switch (message->device) { ++ case CO_DEVICE_TIMER: { ++ co_linux_message_idle_t data = *(co_linux_message_idle_t *)message->data; ++ ++ if (data.tick_count > HZ) { ++ xtime.tv_sec += data.tick_count / HZ; ++ data.tick_count -= ((data.tick_count / HZ) * HZ); ++ } ++ ++ ++ while (data.tick_count > 0) { ++ struct pt_regs regs = {0, }; ++ regs.orig_eax = TIMER_IRQ; ++ do_IRQ(regs); ++ ++ data.tick_count--; ++ } ++ break; ++ } ++ case CO_DEVICE_POWER: { ++ co_linux_message_power_t *type = (co_scan_code_t *)message->data; ++ switch (type->type) { ++ case CO_LINUX_MESSAGE_POWER_ALT_CTRL_DEL: { ++ ctrl_alt_del(); ++ break; ++ } ++ } ++ break; ++ } ++ ++ case CO_DEVICE_KEYBOARD: { ++ struct pt_regs regs; ++ co_received_message(message); ++ regs.orig_eax = KEYBOARD_IRQ; ++ do_IRQ(regs); ++ break; ++ } ++ ++ case CO_DEVICE_NETWORK: { ++ struct pt_regs regs; ++ if (message->size > 1600) { ++ printk("co_handle_device_interrupt: warning, packet len: %d\n", message->size); ++ break; ++ } ++ co_received_message(message); ++ regs.orig_eax = NETWORK_IRQ; ++ do_IRQ(regs); ++ break; ++ } ++ default: ++ break; ++ } ++ ++ local_irq_restore(flags); ++} ++ ++void co_switch_wrapper_protected(void) ++{ ++ /* ++ * We don't trust the passage page code to safely restore %gs and %fs. ++ * ++ * This wrapper ensures that if %fs or %gs are invalid, the processes ++ * exits with a segmentation fault rather than bringing down the ++ * machine. ++ **/ ++ unsigned long fs = 0; ++ unsigned long gs = 0; ++ ++ asm volatile("movl %%fs,%0": "=m" (fs)); ++ asm volatile("movl %%gs,%0": "=m" (gs)); ++ ++ /* ++ * Nullify the registers so the passage page code restores to ++ * null segment values on return. ++ */ ++ asm volatile("movl %0, %%fs; movl %0, %%gs" : : "r" (0)); ++ ++ /* And switch... */ ++ co_switch(); ++ ++ /* ++ * Safely restore the registers. ++ */ ++ loadsegment(fs, fs); ++ loadsegment(gs, gs); ++} ++ ++void co_switch_wrapper(void) ++{ ++ co_switch_wrapper_protected(); ++} ++ ++CO_TRACE_CONTINUE; ++ +--- linux-2.4.28/arch/i386/kernel/head.S~colinux-0.6.1 2003-11-28 13:26:19.000000000 -0500 ++++ linux-2.4.28/arch/i386/kernel/head.S 2004-11-27 15:59:21.287009904 -0500 +@@ -320,7 +320,7 @@ + ret + + ENTRY(stack_start) +- .long SYMBOL_NAME(init_task_union)+8192 ++ .long SYMBOL_NAME(init_task_union)+8192-100 + .long __KERNEL_DS + + /* This is the default interrupt "handler" :-) */ +@@ -361,12 +361,14 @@ + + ALIGN + .word 0 ++.globl idt_descr + idt_descr: + .word IDT_ENTRIES*8-1 # idt contains 256 entries + SYMBOL_NAME(idt): + .long SYMBOL_NAME(idt_table) + + .word 0 ++.globl gdt_descr + gdt_descr: + .word GDT_ENTRIES*8-1 + SYMBOL_NAME(gdt): +--- linux-2.4.28/arch/i386/kernel/i387.c~colinux-0.6.1 2003-08-25 07:44:39.000000000 -0400 ++++ linux-2.4.28/arch/i386/kernel/i387.c 2004-11-27 15:59:21.288009752 -0500 +@@ -342,6 +342,8 @@ + return 1; + } + ++CO_TRACE_STOP; ++ + int save_i387( struct _fpstate *buf ) + { + if ( !current->used_math ) +@@ -363,6 +365,8 @@ + } + } + ++CO_TRACE_CONTINUE; ++ + static inline int restore_i387_fsave( struct _fpstate *buf ) + { + struct task_struct *tsk = current; +@@ -383,6 +387,8 @@ + return err ? 1 : convert_fxsr_from_user( &tsk->thread.i387.fxsave, buf ); + } + ++CO_TRACE_STOP; ++ + int restore_i387( struct _fpstate *buf ) + { + int err; +@@ -400,6 +406,8 @@ + return err; + } + ++CO_TRACE_CONTINUE; ++ + /* + * ptrace request handlers. + */ +--- linux-2.4.28/arch/i386/kernel/i8259.c~colinux-0.6.1 2004-08-07 19:26:04.000000000 -0400 ++++ linux-2.4.28/arch/i386/kernel/i8259.c 2004-11-27 15:59:21.288009752 -0500 +@@ -24,6 +24,7 @@ + #include <asm/apic.h> + + #include <linux/irq.h> ++#include <linux/cooperative.h> + + /* + * Common place to define all x86 IRQ vectors +@@ -121,6 +122,81 @@ + #undef IRQ + #undef IRQLIST_16 + ++#ifdef CONFIG_COOPERATIVE ++ ++CO_TRACE_STOP; ++ ++void proxy_interrupt_handler(unsigned long interrupt, struct pt_regs regs) ++{ ++ co_passage_page->operation = CO_OPERATION_FORWARD_INTERRUPT; ++ co_passage_page->params[0] = interrupt + 0x20; ++ co_passage_page->params[1] = regs.eip; ++ co_passage_page->params[2] = (unsigned long)(&((&interrupt)[10])); ++ co_passage_page->host_state.flags &= ~(1 << 9); /* Turn IF off */ ++ ++ co_switch_wrapper(); ++ co_callback(); ++} ++ ++CO_TRACE_CONTINUE; ++ ++#define IRQLIST_16(x) \ ++ IRQ(x,0) IRQ(x,1) IRQ(x,2) IRQ(x,3) \ ++ IRQ(x,4) IRQ(x,5) IRQ(x,6) IRQ(x,7) \ ++ IRQ(x,8) IRQ(x,9) IRQ(x,a) IRQ(x,b) \ ++ IRQ(x,c) IRQ(x,d) IRQ(x,e) IRQ(x,f) ++ ++#define IRQLIST_224 \ ++ IRQLIST_16(0x0) IRQLIST_16(0x1) IRQLIST_16(0x2) IRQLIST_16(0x3) \ ++ IRQLIST_16(0x4) IRQLIST_16(0x5) IRQLIST_16(0x6) IRQLIST_16(0x7) \ ++ IRQLIST_16(0x8) IRQLIST_16(0x9) IRQLIST_16(0xa) IRQLIST_16(0xb) \ ++ IRQLIST_16(0xc) IRQLIST_16(0xd) ++ ++#define IRQ(x,y) \ ++ extern asmlinkage void IRQ_proxy_##x##y##_interrupt(void); ++IRQLIST_224; ++#undef IRQ ++ ++struct _fpstate co_interrupt_register_state; ++ ++#define BIRQ(id) \ ++asm( \ ++ "\n"__ALIGN_STR"\n" \ ++ ".section .text\n" \ ++ ".globl IRQ_proxy_" #id "_interrupt\n" \ ++ "IRQ_proxy_" #id "_interrupt:\n" \ ++ "push %eax\n\t" \ ++ SAVE_ALL \ ++ \ ++ "pushl $co_interrupt_register_state\n\t" \ ++ "call save_i387\n\t" \ ++ "popl %ebx\n\t" \ ++ "pushl $" #id "\n\t" \ ++ "call proxy_interrupt_handler\n\t" \ ++ "popl %ebx\n\t" \ ++ "pushl $co_interrupt_register_state\n\t" \ ++ "call restore_i387\n\t" \ ++ "popl %ebx\n\t" \ ++ \ ++ "jmp ret_from_intr\n" \ ++ ".previous\n" \ ++ ); \ ++ ++#define IRQ(x,y) BIRQ(x##y) ++IRQLIST_224; ++#undef IRQ ++ ++#define IRQ(x,y) &IRQ_proxy_##x##y##_interrupt, ++void (*proxy_interrupt[NR_IRQS])(void) = { ++ IRQLIST_224 ++}; ++#undef IRQ ++ ++#undef IRQLIST_16 ++#undef IRQLIST_224 ++ ++#endif ++ + /* + * This is the 'legacy' 8259A Programmable Interrupt Controller, + * present in the majority of PC/AT boxes. +@@ -441,15 +517,74 @@ + } + } + ++#ifdef CONFIG_X86_COPIC ++ ++/* ++ * Not like you have any other choice other than using ++ * COPIC in Cooperative mode. ++ */ ++ ++static void end_COPIC_irq(unsigned int irq) ++{ ++} ++ ++#define shutdown_COPIC_irq disable_COPIC_irq ++ ++static void mask_and_ack_COPIC(unsigned int irq) ++{ ++} ++ ++static unsigned int startup_COPIC_irq(unsigned int irq) ++{ ++ return 0; ++} ++ ++void disable_COPIC_irq(unsigned int irq) ++{ ++} ++ ++void enable_COPIC_irq(unsigned int irq) ++{ ++} ++ ++static struct hw_interrupt_type co_pic_irq_type = { ++ "CO-PIC", ++ startup_COPIC_irq, ++ shutdown_COPIC_irq, ++ enable_COPIC_irq, ++ disable_COPIC_irq, ++ mask_and_ack_COPIC, ++ end_COPIC_irq, ++ NULL ++}; ++ ++void __init init_COPIC_irqs(void) ++{ ++ int i; ++ ++ for (i = 0; i < NR_IRQS; i++) { ++ irq_desc[i].status = IRQ_DISABLED; ++ irq_desc[i].action = 0; ++ irq_desc[i].depth = 1; ++ ++ irq_desc[i].handler = &co_pic_irq_type; ++ } ++ ++} ++ ++#endif ++ + void __init init_IRQ(void) + { + int i; + ++#ifndef CONFIG_COOPERATIVE + #ifndef CONFIG_X86_VISWS_APIC + init_ISA_irqs(); + #else + init_VISWS_APIC_irqs(); + #endif ++ + /* + * Cover the whole vector space, no vector can escape + * us. (some of these will be overridden and become +@@ -490,6 +625,8 @@ + set_intr_gate(ERROR_APIC_VECTOR, error_interrupt); + #endif + ++ ++#ifndef CONFIG_COOPERATIVE + /* + * Set the clock to HZ Hz, we already have a valid + * vector now: +@@ -509,4 +646,20 @@ + */ + if (boot_cpu_data.hard_math && !cpu_has_fpu) + setup_irq(13, &irq13); ++#endif ++ ++#else ++ printk("Setting proxy interrupt vectors\n"); ++ ++#ifdef CONFIG_X86_COPIC ++ init_COPIC_irqs(); ++#endif ++ ++ for (i = 0; i < NR_IRQS; i++) { ++ int vector = FIRST_EXTERNAL_VECTOR + i; ++ if (vector != SYSCALL_VECTOR) { ++ set_intr_gate(vector, proxy_interrupt[i]); ++ } ++ } ++#endif + } +--- linux-2.4.28/arch/i386/kernel/ioport.c~colinux-0.6.1 2003-06-13 10:51:29.000000000 -0400 ++++ linux-2.4.28/arch/i386/kernel/ioport.c 2004-11-27 15:59:21.289009600 -0500 +@@ -54,6 +54,7 @@ + */ + asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on) + { ++#ifndef CONFIG_COOPERATIVE + struct thread_struct * t = ¤t->thread; + struct tss_struct * tss = init_tss + smp_processor_id(); + +@@ -86,6 +87,10 @@ + } + + return 0; ++#else ++ /* No ports for yer VM */ ++ return -EPERM; ++#endif + } + + /* +@@ -101,6 +106,7 @@ + + asmlinkage int sys_iopl(unsigned long unused) + { ++#ifndef CONFIG_COOPERATIVE + struct pt_regs * regs = (struct pt_regs *) &unused; + unsigned int level = regs->ebx; + unsigned int old = (regs->eflags >> 12) & 3; +@@ -114,4 +120,8 @@ + } + regs->eflags = (regs->eflags & 0xffffcfff) | (level << 12); + return 0; ++#else ++ /* No IPL for yer VM */ ++ return -EPERM; ++#endif + } +--- linux-2.4.28/arch/i386/kernel/process.c~colinux-0.6.1 2004-11-17 06:54:21.000000000 -0500 ++++ linux-2.4.28/arch/i386/kernel/process.c 2004-11-27 15:59:21.289009600 -0500 +@@ -51,6 +51,7 @@ + #include <asm/apic.h> + + #include <linux/irq.h> ++#include <linux/cooperative.h> + + asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); + +@@ -131,11 +132,15 @@ + current->counter = -100; + + while (1) { ++#ifdef CONFIG_COOPERATIVE ++ co_idle_processor(); ++#else + void (*idle)(void) = pm_idle; + if (!idle) + idle = default_idle; + while (!current->need_resched) + idle(); ++#endif + schedule(); + check_pgt_cache(); + } +@@ -280,6 +285,7 @@ + */ + void machine_real_restart(unsigned char *code, int length) + { ++#ifndef CONFIG_COOPERATIVE + unsigned long flags; + + cli(); +@@ -363,10 +369,14 @@ + __asm__ __volatile__ ("ljmp $0x0008,%0" + : + : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100))); ++#else ++ co_terminate(CO_TERMINATE_REBOOT); ++#endif + } + + void machine_restart(char * __unused) + { ++#ifndef CONFIG_COOPERATIVE + #if CONFIG_SMP + int cpuid; + +@@ -430,16 +440,26 @@ + } + + machine_real_restart(jump_to_bios, sizeof(jump_to_bios)); ++#else ++ co_terminate(CO_TERMINATE_REBOOT); ++#endif + } + + void machine_halt(void) + { ++#ifdef CONFIG_COOPERATIVE ++ co_terminate(CO_TERMINATE_HALT); ++#endif + } + + void machine_power_off(void) + { ++#ifndef CONFIG_COOPERATIVE + if (pm_power_off) + pm_power_off(); ++#else ++ co_terminate(CO_TERMINATE_POWEROFF); ++#endif + } + + extern void show_trace(unsigned long* esp); +@@ -657,12 +677,20 @@ + */ + tss->esp0 = next->esp0; + ++#ifdef CONFIG_COOPERATIVE ++ /* ++ * We would save %fs and %gs using an atomic operation in the ++ * just before the LDT of the next process is loaded. It is ++ * not here, it's in... ++ */ ++#else + /* + * 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)); ++#endif + + /* + * Restore %fs and %gs. +--- linux-2.4.28/arch/i386/kernel/setup.c~colinux-0.6.1 2004-08-07 19:26:04.000000000 -0400 ++++ linux-2.4.28/arch/i386/kernel/setup.c 2004-11-27 15:59:21.291009296 -0500 +@@ -108,6 +108,7 @@ + #include <asm/processor.h> + #include <linux/console.h> + #include <linux/module.h> ++#include <linux/cooperative.h> + #include <asm/mtrr.h> + #include <asm/uaccess.h> + #include <asm/system.h> +@@ -782,9 +783,18 @@ + int len = 0; + int userdef = 0; + ++#ifdef CONFIG_COOPERATIVE ++ /* ++ * Better to have 'root=/dev/cobd0' here. ++ */ ++ from = co_boot_parameters; ++ snprintf(saved_command_line, COMMAND_LINE_SIZE, "%s", ++ co_boot_parameters); ++#else + /* Save unparsed command line copy for /proc/cmdline */ + memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); + saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; ++#endif + + for (;;) { + if (c != ' ') +@@ -1044,16 +1054,23 @@ + static unsigned long __init setup_memory(void) + { + unsigned long bootmap_size, start_pfn, max_low_pfn; +- ++#ifdef CONFIG_COOPERATIVE ++ unsigned long bootmem_size; ++ unsigned long bootmem_start; ++#endif + /* + * partially used pages are not usable - thus + * we are rounding upwards: + */ + start_pfn = PFN_UP(__pa(&_end)); + ++#ifdef CONFIG_COOPERATIVE ++ max_low_pfn = max_pfn = co_memory_size / PAGE_SIZE; ++#else + find_max_pfn(); + + max_low_pfn = find_max_low_pfn(); ++#endif + + #ifdef CONFIG_HIGHMEM + highstart_pfn = highend_pfn = max_pfn; +@@ -1065,12 +1082,19 @@ + #endif + printk(KERN_NOTICE "%ldMB LOWMEM available.\n", + pages_to_mb(max_low_pfn)); ++ + /* + * Initialize the boot-time allocator (with low memory only): + */ + bootmap_size = init_bootmem(start_pfn, max_low_pfn); + +- register_bootmem_low_pages(max_low_pfn); ++#ifdef CONFIG_COOPERATIVE ++ bootmap_size = (bootmap_size + PAGE_SIZE - 1) & PAGE_MASK; ++ bootmem_size = (0x800 << PAGE_SHIFT) - bootmap_size; ++ bootmem_start = co_core_end + bootmap_size; ++ ++ free_bootmem(__pa(bootmem_start), bootmem_size); ++#else + + /* + * Reserve the bootmem bitmap itself as well. We do this in two +@@ -1124,7 +1148,7 @@ + } + } + #endif +- ++#endif + return max_low_pfn; + } + +@@ -1176,7 +1200,9 @@ + + void __init setup_arch(char **cmdline_p) + { ++#ifndef CONFIG_COOPERATIVE + unsigned long max_low_pfn; ++#endif + + #ifdef CONFIG_VISWS + visws_get_board_type_and_rev(); +@@ -1186,6 +1212,7 @@ + blk_nohighio = 1; + #endif + ++ boot_cpu_data.hard_math = 1; + ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV); + drive_info = DRIVE_INFO; + screen_info = SCREEN_INFO; +@@ -1203,7 +1230,10 @@ + rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); + rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); + #endif ++ ++#ifndef CONFIG_COOPERATIVE + setup_memory_region(); ++#endif + copy_edd(); + + if (!MOUNT_ROOT_RDONLY) +@@ -1230,8 +1260,10 @@ + #ifdef CONFIG_SMP + smp_alloc_memory(); /* AP processor realmode stacks in low memory*/ + #endif ++ + paging_init(); + ++#ifndef CONFIG_COOPERATIVE + dmi_scan_machine(); + + /* +@@ -1248,14 +1280,19 @@ + #endif + + register_memory(max_low_pfn); ++#endif + + #ifdef CONFIG_VT ++#ifdef CONFIG_COOPERATIVE_CONSOLE ++ conswitchp = &colinux_con; ++#else + #if defined(CONFIG_VGA_CONSOLE) + conswitchp = &vga_con; + #elif defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; + #endif + #endif ++#endif + } + + static int cachesize_override __initdata = -1; +@@ -3216,29 +3253,41 @@ + if(current->mm) + BUG(); + enter_lazy_tlb(&init_mm, current, nr); +- + t->esp0 = current->thread.esp0; ++ + set_tss_desc(nr,t); + gdt_table[__TSS(nr)].b &= 0xfffffdff; ++ + load_TR(nr); + load_LDT(&init_mm.context); + + /* + * Clear all 6 debug registers: + */ +- ++#ifndef CONFIG_COOPERATIVE + #define CD(register) __asm__("movl %0,%%db" #register ::"r"(0) ); + + CD(0); CD(1); CD(2); CD(3); /* no db4 and db5 */; CD(6); CD(7); + + #undef CD +- ++#endif + /* + * Force FPU initialization: + */ + current->flags &= ~PF_USEDFPU; + current->used_math = 0; ++#ifndef CONFIG_COOPERATIVE + stts(); ++#else ++#if (0) ++ clear_in_cr4(X86_CR4_PVI); ++ clear_in_cr4(X86_CR4_DE); ++ clear_in_cr4(X86_CR4_MCE); ++ clear_in_cr4(X86_CR4_PGE); ++ flush_tlb_all(); ++ clear_in_cr4(X86_CR4_OSXMMEXCPT); ++#endif ++#endif + } + + /* +--- linux-2.4.28/arch/i386/kernel/time.c~colinux-0.6.1 2004-02-18 08:36:30.000000000 -0500 ++++ linux-2.4.28/arch/i386/kernel/time.c 2004-11-27 15:59:21.292009144 -0500 +@@ -84,8 +84,24 @@ + + spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; + +-static inline unsigned long do_fast_gettimeoffset(void) ++static inline unsigned long long rdtsc_u64(void) ++{ ++ register unsigned long eax, edx; ++ ++ rdtsc(eax,edx); ++ ++ return ((((unsigned long long)edx) << 32) | eax); ++} ++ ++#ifdef CONFIG_COOPERATIVE ++static unsigned long long co_last_interrupt_time; ++static unsigned long co_tsc_per_5_ticks; ++static long co_last_time_offset; ++#endif ++ ++static inline long do_fast_gettimeoffset(void) + { ++#ifndef CONFIG_COOPERATIVE + register unsigned long eax, edx; + + /* Read the Time Stamp Counter */ +@@ -111,6 +127,32 @@ + + /* our adjusted time offset in microseconds */ + return delay_at_last_interrupt + edx; ++#else ++ union { ++ unsigned long long ll_var; ++ struct { unsigned long low, high; }; ++ } differential; ++ unsigned long edx; ++ unsigned long ret = 0; ++ ++ differential.ll_var = rdtsc_u64() - co_last_interrupt_time; ++ if (differential.high) ++ return 0; ++ ++ if (co_tsc_per_5_ticks == 0) ++ return 0; ++ ++ differential.ll_var *= 50000; ++ ++ __asm__("divl %2" ++ :"=a" (ret), "=d" (edx) ++ :"r" (co_tsc_per_5_ticks), ++ "0" (differential.low), "1" (differential.high)); ++ ++ ret += co_last_time_offset; ++ ++ return ret; ++#endif + } + + #define TICK_SIZE tick +@@ -121,6 +163,8 @@ + + extern spinlock_t i8259A_lock; + ++#ifndef CONFIG_COOPERATIVE ++ + #ifndef CONFIG_X86_TSC + + /* This function must be called with interrupts disabled +@@ -254,7 +298,16 @@ + return count; + } + +-static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; ++#else ++ ++static unsigned long do_slow_gettimeoffset(void) ++{ ++ return 0; ++} ++ ++#endif ++ ++static long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; + + + /* IBM Summit (EXA) Cyclone Timer code*/ +@@ -305,7 +358,7 @@ + delay_at_last_interrupt = (count + LATCH/2) / LATCH; + } + +-static unsigned long do_gettimeoffset_cyclone(void) ++static long do_gettimeoffset_cyclone(void) + { + u32 offset; + +@@ -443,7 +496,8 @@ + void do_gettimeofday(struct timeval *tv) + { + unsigned long flags; +- unsigned long usec, sec; ++ unsigned long sec; ++ long usec; + + read_lock_irqsave(&xtime_lock, flags); + usec = do_gettimeoffset(); +@@ -461,6 +515,11 @@ + sec++; + } + ++ if (usec < 0) { ++ usec = usec + 1000000; ++ sec -= 1; ++ } ++ + tv->tv_sec = sec; + tv->tv_usec = usec; + } +@@ -502,6 +561,7 @@ + */ + static int set_rtc_mmss(unsigned long nowtime) + { ++#ifndef CONFIG_COOPERATIVE + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + unsigned char save_control, save_freq_select; +@@ -554,8 +614,13 @@ + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + spin_unlock(&rtc_lock); +- + return retval; ++#else ++ /* ++ * Don't let Linux change the system time of the host machine. ++ */ ++ return -1; ++#endif + } + + /* last time the cmos clock got updated */ +@@ -603,6 +668,7 @@ + smp_local_timer_interrupt(regs); + #endif + ++#ifndef CONFIG_COOPERATIVE + /* + * If we have an externally synchronized Linux clock, then update + * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be +@@ -617,6 +683,7 @@ + else + last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ + } ++#endif + + #ifdef CONFIG_MCA + if( MCA_bus ) { +@@ -655,6 +722,7 @@ + */ + write_lock(&xtime_lock); + ++#ifndef CONFIG_COOPERATIVE + if(use_cyclone) + mark_timeoffset_cyclone(); + else if (use_tsc) { +@@ -706,7 +774,15 @@ + count = ((LATCH-1) - count) * TICK_SIZE; + delay_at_last_interrupt = (count + LATCH/2) / LATCH; + } +- ++#else ++ if (use_tsc) { ++ if (co_last_interrupt_time == 0) ++ co_last_time_offset = 0; ++ else ++ co_last_time_offset = ((long)do_fast_gettimeoffset()) - 10000; ++ co_last_interrupt_time = rdtsc_u64(); ++ } ++#endif + do_timer_interrupt(irq, NULL, regs); + + write_unlock(&xtime_lock); +@@ -716,6 +792,7 @@ + /* not static: needed by APM */ + unsigned long get_cmos_time(void) + { ++#ifndef CONFIG_COOPERATIVE + unsigned int year, mon, day, hour, min, sec; + int i; + +@@ -753,6 +830,9 @@ + if ((year += 1900) < 1970) + year += 100; + return mktime(year, mon, day, hour, min, sec); ++#else ++ return co_get_host_time(); ++#endif + } + + static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL}; +@@ -818,6 +898,10 @@ + if (endlow <= CALIBRATE_TIME) + goto bad_ctc; + ++#ifdef CONFIG_COOPERATIVE ++ co_tsc_per_5_ticks = endlow; ++#endif ++ + __asm__("divl %2" + :"=a" (endlow), "=d" (endhigh) + :"r" (endlow), "0" (0), "1" (CALIBRATE_TIME)); +@@ -870,7 +954,13 @@ + + if(use_cyclone) + init_cyclone_clock(); +- ++ ++#ifdef CONFIG_COOPERATIVE ++ /* ++ * We pretty much depend on this at the moment... ++ */ ++ set_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability); ++#endif + if (cpu_has_tsc) { + unsigned long tsc_quotient = calibrate_tsc(); + if (tsc_quotient) { +--- linux-2.4.28/arch/i386/kernel/traps.c~colinux-0.6.1 2002-11-28 18:53:09.000000000 -0500 ++++ linux-2.4.28/arch/i386/kernel/traps.c 2004-11-27 15:59:21.293008992 -0500 +@@ -852,11 +852,20 @@ + "rorl $16,%%eax" \ + : "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type)) + ++CO_TRACE_STOP; ++ ++/* ++ * We use this in colinux_early_cpu_init(), so it must be protected ++ * from traces. ++ */ ++ + void set_tss_desc(unsigned int n, void *addr) + { + _set_tssldt_desc(gdt_table+__TSS(n), (int)addr, 235, 0x89); + } + ++CO_TRACE_CONTINUE; ++ + void set_ldt_desc(unsigned int n, void *addr, unsigned int size) + { + _set_tssldt_desc(gdt_table+__LDT(n), (int)addr, ((size << 3)-1), 0x82); +--- linux-2.4.28/arch/i386/mm/fault.c~colinux-0.6.1 2004-08-07 19:26:04.000000000 -0400 ++++ linux-2.4.28/arch/i386/mm/fault.c 2004-11-27 15:59:21.293008992 -0500 +@@ -380,7 +380,11 @@ + pte_t *pte_k; + + asm("movl %%cr3,%0":"=r" (pgd)); ++#ifndef CONFIG_COOPERATIVE + pgd = offset + (pgd_t *)__va(pgd); ++#else ++ pgd = offset + (pgd_t *)CO_VA(((unsigned long)pgd)); ++#endif + pgd_k = init_mm.pgd + offset; + + if (!pgd_present(*pgd_k)) +--- linux-2.4.28/arch/i386/mm/init.c~colinux-0.6.1 2004-04-14 09:05:25.000000000 -0400 ++++ linux-2.4.28/arch/i386/mm/init.c 2004-11-27 15:59:21.294008840 -0500 +@@ -38,6 +38,8 @@ + #include <asm/apic.h> + #include <asm/tlb.h> + ++#include <linux/cooperative.h> ++ + mmu_gather_t mmu_gathers[NR_CPUS]; + unsigned long highstart_pfn, highend_pfn; + static unsigned long totalram_pages; +@@ -122,7 +124,7 @@ + + /* References to section boundaries */ + +-extern char _text, _etext, _edata, __bss_start, _end; ++extern char _text, _etext, _edata, _sdata, __bss_start, _end; + extern char __init_begin, __init_end; + + static inline void set_pte_phys (unsigned long vaddr, +@@ -204,6 +206,7 @@ + + static void __init pagetable_init (void) + { ++#ifndef CONFIG_COOPERATIVE + unsigned long vaddr, end; + pgd_t *pgd, *pgd_base; + int i, j, k; +@@ -300,6 +303,8 @@ + */ + pgd_base[0] = pgd_base[USER_PTRS_PER_PGD]; + #endif ++#else ++#endif + } + + void __init zap_low_mappings (void) +@@ -325,6 +330,7 @@ + unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; + unsigned int max_dma, high, low; + ++#ifndef CONFIG_COOPERATIVE + max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; + low = max_low_pfn; + high = highend_pfn; +@@ -338,6 +344,11 @@ + zones_size[ZONE_HIGHMEM] = high - low; + #endif + } ++#else ++ zones_size[ZONE_DMA] = 0; ++ zones_size[ZONE_NORMAL] = max_low_pfn; ++ zones_size[ZONE_HIGHMEM] = 0; ++#endif + free_area_init(zones_size); + } + +@@ -485,6 +496,22 @@ + + bad_ppro = ppro_with_ram_bug(); + ++#ifdef CONFIG_COOPERATIVE ++ /* ++ * Only at this stage, after the buddy allocator's maps ++ * have been allocated, we can let the kernel use its ++ * other pseudo physical space. ++ */ ++ { ++ unsigned long bootmem_end = co_core_end + ++ (0x800 << PAGE_SHIFT); ++ unsigned long physical_end = __PAGE_OFFSET + ++ (max_low_pfn << PAGE_SHIFT); ++ ++ free_bootmem(__pa(bootmem_end), physical_end - bootmem_end); ++ } ++ ++#endif + /* this will put all low memory onto the freelists */ + totalram_pages += free_all_bootmem(); + +@@ -529,7 +556,7 @@ + reservedpages = free_pages_init(); + + codesize = (unsigned long) &_etext - (unsigned long) &_text; +- datasize = (unsigned long) &_edata - (unsigned long) &_etext; ++ datasize = (unsigned long) &_edata - (unsigned long) &_sdata; + initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; + + printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n", +@@ -546,19 +573,21 @@ + if (!cpu_has_pae) + panic("cannot execute a PAE-enabled kernel on a PAE-less CPU!"); + #endif ++#ifndef CONFIG_COOPERATIVE + if (boot_cpu_data.wp_works_ok < 0) + test_wp_bit(); +- ++#endif + /* + * Subtle. SMP is doing it's boot stuff late (because it has to + * fork idle threads) - but it also needs low mappings for the + * protected-mode entry to work. We zap these entries only after + * the WP-bit has been tested. + */ ++#ifndef CONFIG_COOPERATIVE + #ifndef CONFIG_SMP + zap_low_mappings(); + #endif +- ++#endif + } + + /* Put this after the callers, so that it cannot be inlined */ +--- linux-2.4.28/arch/i386/vmlinux.lds~colinux-0.6.1 2002-02-25 14:37:53.000000000 -0500 ++++ linux-2.4.28/arch/i386/vmlinux.lds 2004-11-27 15:59:21.294008840 -0500 +@@ -7,50 +7,72 @@ + SECTIONS + { + . = 0xC0000000 + 0x100000; +- _text = .; /* Text and read-only data */ ++ _kernel_start = .; + .text : { ++ _text = .; /* Text and read-only data */ + *(.text) + *(.fixup) + *(.gnu.warning) +- } = 0x9090 +- +- _etext = .; /* End of text section */ ++ _etext = .; /* End of text section */ ++ } + + .rodata : { *(.rodata) *(.rodata.*) } + .kstrtab : { *(.kstrtab) } + + . = ALIGN(16); /* Exception table */ +- __start___ex_table = .; +- __ex_table : { *(__ex_table) } +- __stop___ex_table = .; ++ __ex_table : { ++ __start___ex_table = .; ++ *(__ex_table) ++ __stop___ex_table = .; ++ } + +- __start___ksymtab = .; /* Kernel symbol table */ +- __ksymtab : { *(__ksymtab) } +- __stop___ksymtab = .; ++ . = ALIGN(4); ++ __import_table_address : { ++ __start_import_address = .; ++ *(__im_table_address) ++ __stop_import_address = .; ++ } + ++ __ksymtab : { ++ __start___ksymtab = .; /* Kernel symbol table */ ++ *(__ksymtab) ++ __stop___ksymtab = .; ++ } + .data : { /* Data */ ++ _sdata = .; /* Start of data section */ + *(.data) + CONSTRUCTORS +- } ++ _edata = .; /* End of data section */ ++ } + +- _edata = .; /* End of data section */ ++ . = ALIGN(4096); /* gdt */ ++ .data.gdt : { ++ *(.data.gdt) ++ } ++ .data.idt : { ++ *(.data.idt) ++ } + + . = ALIGN(8192); /* init_task */ +- .data.init_task : { *(.data.init_task) } ++ .data.init_task : { ++ *(.data.init_task) ++ } + + . = ALIGN(4096); /* Init code and data */ +- __init_begin = .; +- .text.init : { *(.text.init) } +- .data.init : { *(.data.init) } +- . = ALIGN(16); +- __setup_start = .; +- .setup.init : { *(.setup.init) } +- __setup_end = .; +- __initcall_start = .; +- .initcall.init : { *(.initcall.init) } +- __initcall_end = .; +- . = ALIGN(4096); +- __init_end = .; ++ .init : { ++ __init_begin = .; ++ *(.text.init) ++ *(.data.init) ++ . = ALIGN(16); ++ __setup_start = .; ++ *(.setup.init) ++ __setup_end = .; ++ __initcall_start = .; ++ *(.initcall.init) ++ __initcall_end = .; ++ . = ALIGN(4096); ++ __init_end = .; ++ } + + . = ALIGN(4096); + .data.page_aligned : { *(.data.idt) } +@@ -58,11 +80,11 @@ + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + +- __bss_start = .; /* BSS */ + .bss : { ++ __bss_start = .; /* BSS */ + *(.bss) +- } +- _end = . ; ++ _end = . ; ++ } + + /* Sections to be discarded */ + /DISCARD/ : { +--- linux-2.4.28/drivers/block/Config.in~colinux-0.6.1 2004-08-07 19:26:04.000000000 -0400 ++++ linux-2.4.28/drivers/block/Config.in 2004-11-27 15:59:21.294008840 -0500 +@@ -50,6 +50,10 @@ + fi + dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM + ++if [ "$CONFIG_COOPERATIVE" = "y" ]; then ++ tristate 'coLinux block device support' CONFIG_BLK_DEV_PBD ++fi ++ + bool 'Per partition statistics in /proc/partitions' CONFIG_BLK_STATS + + endmenu +--- linux-2.4.28/drivers/block/Makefile~colinux-0.6.1 2004-08-07 19:26:04.000000000 -0400 ++++ linux-2.4.28/drivers/block/Makefile 2004-11-27 15:59:21.295008688 -0500 +@@ -31,6 +31,7 @@ + obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o + obj-$(CONFIG_BLK_DEV_UMEM) += umem.o + obj-$(CONFIG_BLK_DEV_NBD) += nbd.o ++obj-$(CONFIG_BLK_DEV_PBD) += cobd.o + obj-$(CONFIG_BLK_DEV_SX8) += sx8.o + + subdir-$(CONFIG_PARIDE) += paride +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.28/drivers/block/cobd.c 2004-11-27 15:59:21.295008688 -0500 +@@ -0,0 +1,334 @@ ++/* ++ * Copyright (C) 2003 Dan Aloni <da-x@gmx.net> ++ * ++ * Cooperative Linux Block Device implementation ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/fs.h> ++#include <linux/errno.h> ++#include <linux/major.h> ++#include <linux/slab.h> ++#include <linux/devfs_fs_kernel.h> ++ ++#define MAJOR_NR COLINUX_MAJOR ++#define DEVICE_NR(device) MINOR(device) /* has no partition bits */ ++#define DEVICE_NAME "cobd" /* name for messaging */ ++#define DEVICE_NO_RANDOM /* no entropy to contribute */ ++#define DEVICE_REQUEST cobd_request ++#define DEVICE_OFF(d) /* do-nothing */ ++ ++#include <linux/blk.h> ++#include <linux/blkpg.h> ++#include <linux/hdreg.h> ++#include <linux/cooperative.h> ++ ++#include <asm/uaccess.h> ++ ++#define PBD_BLOCK_SIZE 512 ++ ++static int *cobd_sizes; ++static int *cobd_blksizes; ++static int *cobd_hardsects; ++static int cobd_devs; ++static int cobd_rahead = 1; ++ ++struct cobd_device_aliases_minor { ++ int cobd_minor; ++}; ++ ++struct cobd_device_aliases_major { ++ int sizes[0x100]; ++ int blksizes[0x100]; ++ int cobd_hardsects[0x100]; ++ struct cobd_device_aliases_minor *minors[0x100]; ++}; ++ ++static struct cobd_device_aliases_major *alias_majors; ++ ++static int cobd_stat(int dev, co_block_request_t *out_request) ++{ ++ co_block_request_t *request; ++ unsigned long flags; ++ long rc = 0; ++ ++ local_irq_save(flags); ++ co_passage_page->operation = CO_OPERATION_DEVICE; ++ co_passage_page->params[0] = CO_DEVICE_BLOCK; ++ co_passage_page->params[1] = dev; ++ request = (co_block_request_t *)&co_passage_page->params[2]; ++ request->type = CO_BLOCK_STAT; ++ co_switch_wrapper(); ++ rc = request->rc; ++ *out_request = *request; ++ local_irq_restore(flags); ++ ++ return rc; ++} ++ ++static int cobd_ioctl(struct inode * inode, struct file * file, ++ unsigned int cmd, unsigned long arg) ++{ ++ int err; ++ int dev; ++ ++ dev = MINOR(inode->i_rdev); ++ ++ switch(cmd) { ++ ++ case BLKGETSIZE: { ++ unsigned long size; ++ ++ /* Return the device size, expressed in sectors */ ++ if (!arg) ++ return -EINVAL; /* NULL pointer: not valid */ ++ ++ err = !access_ok (VERIFY_WRITE, arg, sizeof(long)); ++ if (err) ++ return -EFAULT; ++ ++ size = (cobd_sizes[dev]) * (1024 / cobd_hardsects[dev]); ++ if (copy_to_user((unsigned long *) arg, &size, sizeof (unsigned long))) ++ return -EFAULT; ++ ++ return 0; ++ } ++ ++ case BLKGETSIZE64: { ++ unsigned long long size; ++ ++ /* Return the device size, expressed in sectors */ ++ if (!arg) ++ return -EINVAL; /* NULL pointer: not valid */ ++ ++ err = !access_ok (VERIFY_WRITE, arg, sizeof(unsigned long long)); ++ if (err) ++ return -EFAULT; ++ ++ size = cobd_sizes[dev]; ++ size = size * 1024; ++ if (copy_to_user((unsigned long long *) arg, &size, sizeof (unsigned long long))) ++ return -EFAULT; ++ ++ return 0; ++ } ++ ++ case BLKRRPART: /* reread partition table: can't do it */ ++ return -ENOTTY; ++ ++ default: ++ /* ++ * For ioctls we don't understand, let the block layer ++ * handle them. ++ */ ++ return blk_ioctl(inode->i_rdev, cmd, arg); ++ } ++ ++ return -ENOTTY; /* unknown command */ ++} ++ ++static int cobd_open(struct inode *inode, struct file *file) ++{ ++ co_block_request_t *co_request; ++ co_block_request_t stat_request; ++ unsigned long flags; ++ int ret = 0; ++ int dev = MINOR(inode->i_rdev); ++ ++ if (dev >= cobd_devs) ++ return -EIO; ++ ++ if (!cobd_stat(dev, &stat_request)) { ++ unsigned long long size; ++ ++ /* Request succeeded */ ++ size = stat_request.disk_size; ++ cobd_sizes[dev] = size / 1024; ++ } else { ++ cobd_sizes[dev] = 0; ++ } ++ ++ local_irq_save(flags); ++ co_passage_page->operation = CO_OPERATION_DEVICE; ++ co_passage_page->params[0] = CO_DEVICE_BLOCK; ++ co_passage_page->params[1] = DEVICE_NR(inode->i_rdev); ++ co_request = (co_block_request_t *)&co_passage_page->params[2]; ++ co_request->type = CO_BLOCK_OPEN; ++ co_switch_wrapper(); ++ if (co_request->rc) ++ ret = -EIO; ++ local_irq_restore(flags); ++ ++ return ret; ++} ++ ++static int cobd_release(struct inode *inode, struct file *file) ++{ ++ co_block_request_t *co_request; ++ unsigned long flags; ++ int ret = 0; ++ local_irq_save(flags); ++ ++ co_passage_page->operation = CO_OPERATION_DEVICE; ++ co_passage_page->params[0] = CO_DEVICE_BLOCK; ++ co_passage_page->params[1] = DEVICE_NR(inode->i_rdev); ++ co_request = (co_block_request_t *)&co_passage_page->params[2]; ++ co_request->type = CO_BLOCK_CLOSE; ++ co_switch_wrapper(); ++ if (co_request->rc) ++ ret = -EIO; ++ local_irq_restore(flags); ++ ++ return ret; ++} ++ ++static int cobd_transfer(int dev, const struct request *req) ++{ ++ co_block_request_t *co_request; ++ unsigned long flags; ++ int ret = 0; ++ ++ local_irq_save(flags); ++ ++ co_passage_page->operation = CO_OPERATION_DEVICE; ++ co_passage_page->params[0] = CO_DEVICE_BLOCK; ++ co_passage_page->params[1] = dev; ++ co_request = (co_block_request_t *)&co_passage_page->params[2]; ++ if (req->cmd == READ) ++ co_request->type = CO_BLOCK_READ; ++ else ++ co_request->type = CO_BLOCK_WRITE; ++ co_request->offset = ((unsigned long long)req->sector) * PBD_BLOCK_SIZE; ++ co_request->size = req->current_nr_sectors * PBD_BLOCK_SIZE; ++ co_request->address = req->buffer; ++ co_request->rc = 0; ++ ++ co_switch_wrapper(); ++ ++ if (!co_request->rc) ++ ret = 1; ++ ++ local_irq_restore(flags); ++ ++ return ret; ++} ++ ++static void cobd_request(request_queue_t *q) ++{ ++ int status; ++ int devno; ++ ++ while (1) { ++ INIT_REQUEST; /* returns when queue is empty */ ++ ++ devno = DEVICE_NR(CURRENT->rq_dev); ++ ++ status = cobd_transfer(devno, CURRENT); ++ ++ end_request(status); ++ } ++} ++ ++static int cobd_check_change(kdev_t dev) ++{ ++ return 1; ++} ++ ++static struct block_device_operations cobd_fops = { ++ owner: THIS_MODULE, ++ open: cobd_open, ++ release: cobd_release, ++ ioctl: cobd_ioctl, ++ check_media_change: cobd_check_change, ++}; ++ ++int __init cobd_init(void) ++{ ++ int result; ++ int i; ++ ++ if (devfs_register_blkdev(MAJOR_NR, "cobd", &cobd_fops)) { ++ printk(KERN_WARNING "Unable to get major number %d for cobd device\n", MAJOR_NR); ++ return -EIO; ++ } ++ ++ blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), cobd_request); ++ ++ read_ahead[MAJOR_NR] = cobd_rahead; ++ result = -ENOMEM; /* for the possible errors */ ++ ++ cobd_devs = CO_MODULE_MAX_COBD; ++ ++ cobd_sizes = kmalloc(cobd_devs * sizeof(int), GFP_KERNEL); ++ if (!cobd_sizes) ++ goto fail_malloc; ++ ++ cobd_blksizes = kmalloc(cobd_devs * sizeof(int), GFP_KERNEL); ++ if (!cobd_blksizes) ++ goto fail_malloc_1; ++ ++ cobd_hardsects = kmalloc(cobd_devs * sizeof(int), GFP_KERNEL); ++ if (!cobd_hardsects) ++ goto fail_malloc_2; ++ ++ for (i=0; i < cobd_devs; i++) { ++ co_block_request_t request; ++ unsigned long long size = 0; ++ ++ if (!cobd_stat(i, &request)) { ++ /* Request successed */ ++ size = request.disk_size; ++ cobd_sizes[i] = size >> 10; ++ } else { ++ cobd_sizes[i] = 0; ++ } ++ ++ if (cobd_sizes[i] != 0) ++ printk(KERN_DEBUG "cobd%d size: %d kb\n", i, cobd_sizes[i]); ++ ++ cobd_blksizes[i] = PAGE_SIZE; ++ cobd_hardsects[i] = PBD_BLOCK_SIZE; ++ } ++ ++ blk_size[MAJOR_NR] = cobd_sizes; ++ blksize_size[MAJOR_NR] = cobd_blksizes; ++ hardsect_size[MAJOR_NR] = cobd_hardsects; ++ ++ devfs_register_series(NULL, "cobd%u", cobd_devs, DEVFS_FL_DEFAULT, ++ MAJOR_NR, 0, ++ S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, ++ &cobd_fops, NULL); ++ ++ printk(KERN_DEBUG "cobd: loaded (max %d devices)\n", cobd_devs); ++ ++ return 0; ++ ++fail_malloc_2: ++ kfree(cobd_blksizes); ++fail_malloc_1: ++ kfree(cobd_sizes); ++fail_malloc: ++ ++ if (devfs_unregister_blkdev(MAJOR_NR, "cobd")) ++ printk(KERN_WARNING "loop: cannot unregister blkdev\n"); ++ ++ return result; ++} ++ ++void cobd_exit(void) ++{ ++ blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); ++ ++ if (devfs_unregister_blkdev(MAJOR_NR, "cobd")) ++ printk(KERN_WARNING "cobd: cannot unregister blkdev\n"); ++ ++ kfree(blk_size[MAJOR_NR]); ++ kfree(blksize_size[MAJOR_NR]); ++ kfree(hardsect_size[MAJOR_NR]); ++} ++ ++module_init(cobd_init); ++module_exit(cobd_exit); ++ ++ +--- linux-2.4.28/drivers/block/ll_rw_blk.c~colinux-0.6.1 2004-11-17 06:54:21.000000000 -0500 ++++ linux-2.4.28/drivers/block/ll_rw_blk.c 2004-11-27 15:59:21.298008232 -0500 +@@ -1576,7 +1576,7 @@ + #ifdef CONFIG_BLK_DEV_FD + floppy_init(); + #else +-#if defined(__i386__) /* Do we even need this? */ ++#if defined(__i386__) && !defined(CONFIG_COOPERATIVE) /* Do we even need this? */ + outb_p(0xc, 0x3f2); + #endif + #endif +--- linux-2.4.28/drivers/char/Makefile~colinux-0.6.1 2004-08-07 19:26:04.000000000 -0400 ++++ linux-2.4.28/drivers/char/Makefile 2004-11-27 15:59:21.298008232 -0500 +@@ -169,6 +169,10 @@ + KEYBD = dummy_keyb.o + endif + ++ifeq ($(CONFIG_COOPERATIVE),y) ++ KEYBD = colx_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_PARPORT_SERIAL) += parport_serial.o +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.28/drivers/char/colx_keyb.c 2004-11-27 15:59:21.299008080 -0500 +@@ -0,0 +1,1228 @@ ++/* ++ * linux/drivers/char/pc_keyb.c ++ * ++ * Separation of the PC low-level part by Geert Uytterhoeven, May 1997 ++ * See keyboard.c for the whole history. ++ * ++ * Major cleanup by Martin Mares, May 1997 ++ * ++ * Combined the keyboard and PS/2 mouse handling into one file, ++ * because they share the same hardware. ++ * Johan Myreen <jem@iki.fi> 1998-10-08. ++ * ++ * Code fixes to handle mouse ACKs properly. ++ * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29. ++ * ++ */ ++ ++#include <linux/config.h> ++ ++#include <linux/spinlock.h> ++#include <linux/sched.h> ++#include <linux/interrupt.h> ++#include <linux/tty.h> ++#include <linux/mm.h> ++#include <linux/signal.h> ++#include <linux/init.h> ++#include <linux/kbd_ll.h> ++#include <linux/delay.h> ++#include <linux/random.h> ++#include <linux/poll.h> ++#include <linux/miscdevice.h> ++#include <linux/slab.h> ++#include <linux/kbd_kern.h> ++#include <linux/vt_kern.h> ++#include <linux/smp_lock.h> ++#include <linux/kd.h> ++#include <linux/pm.h> ++ ++#include <asm/keyboard.h> ++#include <asm/bitops.h> ++#include <asm/uaccess.h> ++#include <asm/irq.h> ++#include <asm/system.h> ++ ++#include <asm/io.h> ++ ++/* Some configuration switches are present in the include file... */ ++ ++#include <linux/pc_keyb.h> ++ ++/* Simple translation table for the SysRq keys */ ++ ++#ifdef CONFIG_MAGIC_SYSRQ ++unsigned char pckbd_sysrq_xlate[128] = ++ "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ ++ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ ++ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ ++ "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ ++ "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ ++ "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ ++ "\r\000/"; /* 0x60 - 0x6f */ ++#endif ++ ++static void kbd_write_command_w(int data); ++static void kbd_write_output_w(int data); ++#ifdef CONFIG_PSMOUSE ++static void aux_write_ack(int val); ++static void __aux_write_ack(int val); ++static int aux_reconnect = 0; ++#endif ++ ++#ifndef kbd_controller_present ++#define kbd_controller_present() 1 ++#endif ++static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; ++static unsigned char handle_kbd_event(void); ++ ++/* used only by send_data - set by keyboard_interrupt */ ++static volatile unsigned char reply_expected; ++static volatile unsigned char acknowledge; ++static volatile unsigned char resend; ++ ++ ++#if defined CONFIG_PSMOUSE ++/* ++ * PS/2 Auxiliary Device ++ */ ++ ++static int __init psaux_init(void); ++ ++#define AUX_RECONNECT1 0xaa /* scancode1 when ps2 device is plugged (back) in */ ++#define AUX_RECONNECT2 0x00 /* scancode2 when ps2 device is plugged (back) in */ ++ ++static struct aux_queue *queue; /* Mouse data buffer. */ ++static int aux_count; ++/* used when we send commands to the mouse that expect an ACK. */ ++static unsigned char mouse_reply_expected; ++ ++#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT) ++#define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT) ++ ++#define MAX_RETRIES 60 /* some aux operations take long time*/ ++#endif /* CONFIG_PSMOUSE */ ++ ++/* ++ * Wait for keyboard controller input buffer to drain. ++ * ++ * Don't use 'jiffies' so that we don't depend on ++ * interrupts.. ++ * ++ * Quote from PS/2 System Reference Manual: ++ * ++ * "Address hex 0060 and address hex 0064 should be written only when ++ * the input-buffer-full bit and output-buffer-full bit in the ++ * Controller Status register are set 0." ++ */ ++ ++static void kb_wait(void) ++{ ++ unsigned long timeout = KBC_TIMEOUT; ++ ++ do { ++ /* ++ * "handle_kbd_event()" will handle any incoming events ++ * while we wait - keypresses or mouse movement. ++ */ ++ unsigned char status = handle_kbd_event(); ++ ++ if (! (status & KBD_STAT_IBF)) ++ return; ++ mdelay(1); ++ timeout--; ++ } while (timeout); ++#ifdef KBD_REPORT_TIMEOUTS ++ printk(KERN_WARNING "Keyboard timed out[1]\n"); ++#endif ++} ++ ++/* ++ * Translation of escaped scancodes to keycodes. ++ * This is now user-settable. ++ * The keycodes 1-88,96-111,119 are fairly standard, and ++ * should probably not be changed - changing might confuse X. ++ * X also interprets scancode 0x5d (KEY_Begin). ++ * ++ * For 1-88 keycode equals scancode. ++ */ ++ ++#define E0_KPENTER 96 ++#define E0_RCTRL 97 ++#define E0_KPSLASH 98 ++#define E0_PRSCR 99 ++#define E0_RALT 100 ++#define E0_BREAK 101 /* (control-pause) */ ++#define E0_HOME 102 ++#define E0_UP 103 ++#define E0_PGUP 104 ++#define E0_LEFT 105 ++#define E0_RIGHT 106 ++#define E0_END 107 ++#define E0_DOWN 108 ++#define E0_PGDN 109 ++#define E0_INS 110 ++#define E0_DEL 111 ++ ++#define E1_PAUSE 119 ++ ++/* ++ * The keycodes below are randomly located in 89-95,112-118,120-127. ++ * They could be thrown away (and all occurrences below replaced by 0), ++ * but that would force many users to use the `setkeycodes' utility, where ++ * they needed not before. It does not matter that there are duplicates, as ++ * long as no duplication occurs for any single keyboard. ++ */ ++#define SC_LIM 89 ++ ++#define FOCUS_PF1 85 /* actual code! */ ++#define FOCUS_PF2 89 ++#define FOCUS_PF3 90 ++#define FOCUS_PF4 91 ++#define FOCUS_PF5 92 ++#define FOCUS_PF6 93 ++#define FOCUS_PF7 94 ++#define FOCUS_PF8 95 ++#define FOCUS_PF9 120 ++#define FOCUS_PF10 121 ++#define FOCUS_PF11 122 ++#define FOCUS_PF12 123 ++ ++#define JAP_86 124 ++/* tfj@olivia.ping.dk: ++ * The four keys are located over the numeric keypad, and are ++ * labelled A1-A4. It's an rc930 keyboard, from ++ * Regnecentralen/RC International, Now ICL. ++ * Scancodes: 59, 5a, 5b, 5c. ++ */ ++#define RGN1 124 ++#define RGN2 125 ++#define RGN3 126 ++#define RGN4 127 ++ ++static unsigned char high_keys[128 - SC_LIM] = { ++ RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ ++ 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */ ++ 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */ ++ FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */ ++ FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */ ++}; ++ ++/* BTC */ ++#define E0_MACRO 112 ++/* LK450 */ ++#define E0_F13 113 ++#define E0_F14 114 ++#define E0_HELP 115 ++#define E0_DO 116 ++#define E0_F17 117 ++#define E0_KPMINPLUS 118 ++/* ++ * My OmniKey generates e0 4c for the "OMNI" key and the ++ * right alt key does nada. [kkoller@nyx10.cs.du.edu] ++ */ ++#define E0_OK 124 ++/* ++ * New microsoft keyboard is rumoured to have ++ * e0 5b (left window button), e0 5c (right window button), ++ * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU] ++ * [or: Windows_L, Windows_R, TaskMan] ++ */ ++#define E0_MSLW 125 ++#define E0_MSRW 126 ++#define E0_MSTM 127 ++ ++static unsigned char e0_keys[128] = { ++ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */ ++ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ ++ 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ ++ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ ++ 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */ ++ E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */ ++ E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */ ++ E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */ ++ E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */ ++ 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ ++ 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */ ++ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ ++ 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ ++}; ++ ++int pckbd_setkeycode(unsigned int scancode, unsigned int keycode) ++{ ++ if (scancode < SC_LIM || scancode > 255 || keycode > 127) ++ return -EINVAL; ++ if (scancode < 128) ++ high_keys[scancode - SC_LIM] = keycode; ++ else ++ e0_keys[scancode - 128] = keycode; ++ return 0; ++} ++ ++int pckbd_getkeycode(unsigned int scancode) ++{ ++ return ++ (scancode < SC_LIM || scancode > 255) ? -EINVAL : ++ (scancode < 128) ? high_keys[scancode - SC_LIM] : ++ e0_keys[scancode - 128]; ++} ++ ++static int do_acknowledge(unsigned char scancode) ++{ ++ if (reply_expected) { ++ /* Unfortunately, we must recognise these codes only if we know they ++ * are known to be valid (i.e., after sending a command), because there ++ * are some brain-damaged keyboards (yes, FOCUS 9000 again) which have ++ * keys with such codes :( ++ */ ++ if (scancode == KBD_REPLY_ACK) { ++ acknowledge = 1; ++ reply_expected = 0; ++ return 0; ++ } else if (scancode == KBD_REPLY_RESEND) { ++ resend = 1; ++ reply_expected = 0; ++ return 0; ++ } ++ /* Should not happen... */ ++#if 0 ++ printk(KERN_DEBUG "keyboard reply expected - got %02x\n", ++ scancode); ++#endif ++ } ++ return 1; ++} ++ ++int pckbd_translate(unsigned char scancode, unsigned char *keycode, ++ char raw_mode) ++{ ++ static int prev_scancode; ++ ++ /* special prefix scancodes.. */ ++ if (scancode == 0xe0 || scancode == 0xe1) { ++ prev_scancode = scancode; ++ return 0; ++ } ++ ++ /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */ ++ if (scancode == 0x00 || scancode == 0xff) { ++ prev_scancode = 0; ++ return 0; ++ } ++ ++ scancode &= 0x7f; ++ ++ if (prev_scancode) { ++ /* ++ * usually it will be 0xe0, but a Pause key generates ++ * e1 1d 45 e1 9d c5 when pressed, and nothing when released ++ */ ++ if (prev_scancode != 0xe0) { ++ if (prev_scancode == 0xe1 && scancode == 0x1d) { ++ prev_scancode = 0x100; ++ return 0; ++ } else if (prev_scancode == 0x100 && scancode == 0x45) { ++ *keycode = E1_PAUSE; ++ prev_scancode = 0; ++ } else { ++#ifdef KBD_REPORT_UNKN ++ if (!raw_mode) ++ printk(KERN_INFO "keyboard: unknown e1 escape sequence\n"); ++#endif ++ prev_scancode = 0; ++ return 0; ++ } ++ } else { ++ prev_scancode = 0; ++ /* ++ * The keyboard maintains its own internal caps lock and ++ * num lock statuses. In caps lock mode E0 AA precedes make ++ * code and E0 2A follows break code. In num lock mode, ++ * E0 2A precedes make code and E0 AA follows break code. ++ * We do our own book-keeping, so we will just ignore these. ++ */ ++ /* ++ * For my keyboard there is no caps lock mode, but there are ++ * both Shift-L and Shift-R modes. The former mode generates ++ * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs. ++ * So, we should also ignore the latter. - aeb@cwi.nl ++ */ ++ if (scancode == 0x2a || scancode == 0x36) ++ return 0; ++ ++ if (e0_keys[scancode]) ++ *keycode = e0_keys[scancode]; ++ else { ++#ifdef KBD_REPORT_UNKN ++ if (!raw_mode) ++ printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n", ++ scancode); ++#endif ++ return 0; ++ } ++ } ++ } else if (scancode >= SC_LIM) { ++ /* This happens with the FOCUS 9000 keyboard ++ Its keys PF1..PF12 are reported to generate ++ 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f ++ Moreover, unless repeated, they do not generate ++ key-down events, so we have to zero up_flag below */ ++ /* Also, Japanese 86/106 keyboards are reported to ++ generate 0x73 and 0x7d for \ - and \ | respectively. */ ++ /* Also, some Brazilian keyboard is reported to produce ++ 0x73 and 0x7e for \ ? and KP-dot, respectively. */ ++ ++ *keycode = high_keys[scancode - SC_LIM]; ++ ++ if (!*keycode) { ++ if (!raw_mode) { ++#ifdef KBD_REPORT_UNKN ++ printk(KERN_INFO "keyboard: unrecognized scancode (%02x)" ++ " - ignored\n", scancode); ++#endif ++ } ++ return 0; ++ } ++ } else ++ *keycode = scancode; ++ return 1; ++} ++ ++char pckbd_unexpected_up(unsigned char keycode) ++{ ++ /* unexpected, but this can happen: maybe this was a key release for a ++ FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */ ++ if (keycode >= SC_LIM || keycode == 85) ++ return 0; ++ else ++ return 0200; ++} ++ ++int pckbd_pm_resume(struct pm_dev *dev, pm_request_t rqst, void *data) ++{ ++#if defined CONFIG_PSMOUSE ++ unsigned long flags; ++ ++ if (rqst == PM_RESUME) { ++ if (queue) { /* Aux port detected */ ++ if (aux_count == 0) { /* Mouse not in use */ ++ spin_lock_irqsave(&kbd_controller_lock, flags); ++ /* ++ * Dell Lat. C600 A06 enables mouse after resume. ++ * When user touches the pad, it posts IRQ 12 ++ * (which we do not process), thus holding keyboard. ++ */ ++ kbd_write_command(KBD_CCMD_MOUSE_DISABLE); ++ /* kbd_write_cmd(AUX_INTS_OFF); */ /* Config & lock */ ++ kb_wait(); ++ kbd_write_command(KBD_CCMD_WRITE_MODE); ++ kb_wait(); ++ kbd_write_output(AUX_INTS_OFF); ++ spin_unlock_irqrestore(&kbd_controller_lock, flags); ++ } ++ } ++ } ++#endif ++ return 0; ++} ++ ++ ++static inline void handle_mouse_event(unsigned char scancode) ++{ ++#ifdef CONFIG_PSMOUSE ++ static unsigned char prev_code; ++ if (mouse_reply_expected) { ++ if (scancode == AUX_ACK) { ++ mouse_reply_expected--; ++ return; ++ } ++ mouse_reply_expected = 0; ++ } ++ else if(scancode == AUX_RECONNECT2 && prev_code == AUX_RECONNECT1 ++ && aux_reconnect) { ++ printk (KERN_INFO "PS/2 mouse reconnect detected\n"); ++ queue->head = queue->tail = 0; /* Flush input queue */ ++ __aux_write_ack(AUX_ENABLE_DEV); /* ping the mouse :) */ ++ return; ++ } ++ ++ prev_code = scancode; ++ add_mouse_randomness(scancode); ++ if (aux_count) { ++ int head = queue->head; ++ ++ queue->buf[head] = scancode; ++ head = (head + 1) & (AUX_BUF_SIZE-1); ++ if (head != queue->tail) { ++ queue->head = head; ++ kill_fasync(&queue->fasync, SIGIO, POLL_IN); ++ wake_up_interruptible(&queue->proc_list); ++ } ++ } ++#endif ++} ++ ++static unsigned char kbd_exists = 1; ++ ++void handle_keyboard_event(unsigned char scancode) ++{ ++#ifdef CONFIG_VT ++ kbd_exists = 1; ++ if (do_acknowledge(scancode)) ++ handle_scancode(scancode, !(scancode & 0x80)); ++#endif ++ tasklet_schedule(&keyboard_tasklet); ++} ++ ++/* ++ * This reads the keyboard status port, and does the ++ * appropriate action. ++ * ++ * It requires that we hold the keyboard controller ++ * spinlock. ++ */ ++static unsigned char handle_kbd_event(void) ++{ ++ unsigned char scancode; ++ co_linux_message_t *message; ++ ++ while (co_get_message(&message, CO_DEVICE_KEYBOARD)) { ++ co_scan_code_t *sc = (co_scan_code_t *)message->data; ++ unsigned long scancode = sc->code; ++ ++ if (!sc->down) ++ scancode |= 0x80; ++ ++ handle_keyboard_event(scancode); ++ ++ co_free_message(message); ++ } ++ ++ return 0; ++} ++ ++ ++static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++{ ++#ifdef CONFIG_VT ++ kbd_pt_regs = regs; ++#endif ++ ++ spin_lock_irq(&kbd_controller_lock); ++ handle_kbd_event(); ++ spin_unlock_irq(&kbd_controller_lock); ++} ++ ++/* ++ * send_data sends a character to the keyboard and waits ++ * for an acknowledge, possibly retrying if asked to. Returns ++ * the success status. ++ * ++ * Don't use 'jiffies', so that we don't depend on interrupts ++ */ ++static int send_data(unsigned char data) ++{ ++ return 0; ++} ++ ++void pckbd_leds(unsigned char leds) ++{ ++ if (kbd_exists && (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds))) { ++ send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */ ++ kbd_exists = 0; ++ } ++} ++ ++#define DEFAULT_KEYB_REP_DELAY 250 ++#define DEFAULT_KEYB_REP_RATE 30 /* cps */ ++ ++static struct kbd_repeat kbdrate={ ++ DEFAULT_KEYB_REP_DELAY, ++ DEFAULT_KEYB_REP_RATE ++}; ++ ++static unsigned char parse_kbd_rate(struct kbd_repeat *r) ++{ ++ static struct r2v{ ++ int rate; ++ unsigned char val; ++ } kbd_rates[]={ {5,0x14}, ++ {7,0x10}, ++ {10,0x0c}, ++ {15,0x08}, ++ {20,0x04}, ++ {25,0x02}, ++ {30,0x00} ++ }; ++ static struct d2v{ ++ int delay; ++ unsigned char val; ++ } kbd_delays[]={{250,0}, ++ {500,1}, ++ {750,2}, ++ {1000,3} ++ }; ++ int rate=0,delay=0; ++ if (r != NULL){ ++ int i,new_rate=30,new_delay=250; ++ if (r->rate <= 0) ++ r->rate=kbdrate.rate; ++ if (r->delay <= 0) ++ r->delay=kbdrate.delay; ++ for (i=0; i < sizeof(kbd_rates)/sizeof(struct r2v); i++) ++ if (kbd_rates[i].rate == r->rate){ ++ new_rate=kbd_rates[i].rate; ++ rate=kbd_rates[i].val; ++ break; ++ } ++ for (i=0; i < sizeof(kbd_delays)/sizeof(struct d2v); i++) ++ if (kbd_delays[i].delay == r->delay){ ++ new_delay=kbd_delays[i].delay; ++ delay=kbd_delays[i].val; ++ break; ++ } ++ r->rate=new_rate; ++ r->delay=new_delay; ++ } ++ return (delay << 5) | rate; ++} ++ ++static int write_kbd_rate(unsigned char r) ++{ ++ if (!send_data(KBD_CMD_SET_RATE) || !send_data(r)){ ++ send_data(KBD_CMD_ENABLE); /* re-enable kbd if any errors */ ++ return 0; ++ }else ++ return 1; ++} ++ ++static int pckbd_rate(struct kbd_repeat *rep) ++{ ++ if (rep == NULL) ++ return -EINVAL; ++ else{ ++ unsigned char r=parse_kbd_rate(rep); ++ struct kbd_repeat old_rep; ++ memcpy(&old_rep,&kbdrate,sizeof(struct kbd_repeat)); ++ if (write_kbd_rate(r)){ ++ memcpy(&kbdrate,rep,sizeof(struct kbd_repeat)); ++ memcpy(rep,&old_rep,sizeof(struct kbd_repeat)); ++ return 0; ++ } ++ } ++ return -EIO; ++} ++ ++/* ++ * In case we run on a non-x86 hardware we need to initialize both the ++ * keyboard controller and the keyboard. On a x86, the BIOS will ++ * already have initialized them. ++ * ++ * Some x86 BIOSes do not correctly initialize the keyboard, so the ++ * "kbd-reset" command line options can be given to force a reset. ++ * [Ranger] ++ */ ++#ifdef __i386__ ++ int kbd_startup_reset __initdata = 0; ++#else ++ int kbd_startup_reset __initdata = 1; ++#endif ++ ++/* for "kbd-reset" cmdline param */ ++static int __init kbd_reset_setup(char *str) ++{ ++ kbd_startup_reset = 1; ++ return 1; ++} ++ ++__setup("kbd-reset", kbd_reset_setup); ++ ++#define KBD_NO_DATA (-1) /* No data */ ++#define KBD_BAD_DATA (-2) /* Parity or other error */ ++ ++static int __init kbd_read_data(void) ++{ ++ int retval = KBD_NO_DATA; ++ ++#if (0) ++ status = kbd_read_status(); ++ if (status & KBD_STAT_OBF) { ++ unsigned char data = kbd_read_input(); ++ ++ retval = data; ++ if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) ++ retval = KBD_BAD_DATA; ++ } ++#endif ++ return retval; ++} ++ ++static void __init kbd_clear_input(void) ++{ ++ int maxread = 100; /* Random number */ ++ ++ do { ++ if (kbd_read_data() == KBD_NO_DATA) ++ break; ++ } while (--maxread); ++} ++ ++static int __init kbd_wait_for_input(void) ++{ ++ long timeout = KBD_INIT_TIMEOUT; ++ ++ do { ++ int retval = kbd_read_data(); ++ if (retval >= 0) ++ return retval; ++ mdelay(1); ++ } while (--timeout); ++ return -1; ++} ++ ++static void kbd_write_command_w(int data) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&kbd_controller_lock, flags); ++ kb_wait(); ++ kbd_write_command(data); ++ spin_unlock_irqrestore(&kbd_controller_lock, flags); ++} ++ ++static void kbd_write_output_w(int data) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&kbd_controller_lock, flags); ++ kb_wait(); ++ kbd_write_output(data); ++ spin_unlock_irqrestore(&kbd_controller_lock, flags); ++} ++ ++#if defined(__alpha__) ++/* ++ * Some Alphas cannot mask some/all interrupts, so we have to ++ * make sure not to allow interrupts AT ALL when polling for ++ * specific return values from the keyboard. ++ * ++ * I think this should work on any architecture, but for now, only Alpha. ++ */ ++static int kbd_write_command_w_and_wait(int data) ++{ ++ unsigned long flags; ++ int input; ++ ++ spin_lock_irqsave(&kbd_controller_lock, flags); ++ kb_wait(); ++ kbd_write_command(data); ++ input = kbd_wait_for_input(); ++ spin_unlock_irqrestore(&kbd_controller_lock, flags); ++ return input; ++} ++ ++static int kbd_write_output_w_and_wait(int data) ++{ ++ unsigned long flags; ++ int input; ++ ++ spin_lock_irqsave(&kbd_controller_lock, flags); ++ kb_wait(); ++ kbd_write_output(data); ++ input = kbd_wait_for_input(); ++ spin_unlock_irqrestore(&kbd_controller_lock, flags); ++ return input; ++} ++#else ++static int kbd_write_command_w_and_wait(int data) ++{ ++ kbd_write_command_w(data); ++ return kbd_wait_for_input(); ++} ++ ++static int kbd_write_output_w_and_wait(int data) ++{ ++ kbd_write_output_w(data); ++ return kbd_wait_for_input(); ++} ++#endif /* __alpha__ */ ++ ++#if defined CONFIG_PSMOUSE ++static void kbd_write_cmd(int cmd) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&kbd_controller_lock, flags); ++ kb_wait(); ++ kbd_write_command(KBD_CCMD_WRITE_MODE); ++ kb_wait(); ++ kbd_write_output(cmd); ++ spin_unlock_irqrestore(&kbd_controller_lock, flags); ++} ++#endif /* CONFIG_PSMOUSE */ ++ ++static char * __init initialize_kbd(void) ++{ ++ int status; ++ ++ /* ++ * Test the keyboard interface. ++ * This seems to be the only way to get it going. ++ * If the test is successful a x55 is placed in the input buffer. ++ */ ++ kbd_write_command_w(KBD_CCMD_SELF_TEST); ++ if (kbd_wait_for_input() != 0x55) ++ return "Keyboard failed self test"; ++ ++ /* ++ * Perform a keyboard interface test. This causes the controller ++ * to test the keyboard clock and data lines. The results of the ++ * test are placed in the input buffer. ++ */ ++ kbd_write_command_w(KBD_CCMD_KBD_TEST); ++ if (kbd_wait_for_input() != 0x00) ++ return "Keyboard interface failed self test"; ++ ++ /* ++ * Enable the keyboard by allowing the keyboard clock to run. ++ */ ++ kbd_write_command_w(KBD_CCMD_KBD_ENABLE); ++ ++ /* ++ * Reset keyboard. If the read times out ++ * then the assumption is that no keyboard is ++ * plugged into the machine. ++ * This defaults the keyboard to scan-code set 2. ++ * ++ * Set up to try again if the keyboard asks for RESEND. ++ */ ++ do { ++ kbd_write_output_w(KBD_CMD_RESET); ++ status = kbd_wait_for_input(); ++ if (status == KBD_REPLY_ACK) ++ break; ++ if (status != KBD_REPLY_RESEND) ++ return "Keyboard reset failed, no ACK"; ++ } while (1); ++ ++ if (kbd_wait_for_input() != KBD_REPLY_POR) ++ return "Keyboard reset failed, no POR"; ++ ++ /* ++ * Set keyboard controller mode. During this, the keyboard should be ++ * in the disabled state. ++ * ++ * Set up to try again if the keyboard asks for RESEND. ++ */ ++ do { ++ kbd_write_output_w(KBD_CMD_DISABLE); ++ status = kbd_wait_for_input(); ++ if (status == KBD_REPLY_ACK) ++ break; ++ if (status != KBD_REPLY_RESEND) ++ return "Disable keyboard: no ACK"; ++ } while (1); ++ ++ kbd_write_command_w(KBD_CCMD_WRITE_MODE); ++ kbd_write_output_w(KBD_MODE_KBD_INT ++ | KBD_MODE_SYS ++ | KBD_MODE_DISABLE_MOUSE ++ | KBD_MODE_KCC); ++ ++ /* ibm powerpc portables need this to use scan-code set 1 -- Cort */ ++ if (!(kbd_write_command_w_and_wait(KBD_CCMD_READ_MODE) & KBD_MODE_KCC)) ++ { ++ /* ++ * If the controller does not support conversion, ++ * Set the keyboard to scan-code set 1. ++ */ ++ kbd_write_output_w(0xF0); ++ kbd_wait_for_input(); ++ kbd_write_output_w(0x01); ++ kbd_wait_for_input(); ++ } ++ ++ if (kbd_write_output_w_and_wait(KBD_CMD_ENABLE) != KBD_REPLY_ACK) ++ return "Enable keyboard: no ACK"; ++ ++ /* ++ * Finally, set the typematic rate to maximum. ++ */ ++ if (kbd_write_output_w_and_wait(KBD_CMD_SET_RATE) != KBD_REPLY_ACK) ++ return "Set rate: no ACK"; ++ if (kbd_write_output_w_and_wait(0x00) != KBD_REPLY_ACK) ++ return "Set rate: no 2nd ACK"; ++ ++ return NULL; ++} ++ ++void __init pckbd_init_hw(void) ++{ ++ if (!kbd_controller_present()) { ++ kbd_exists = 0; ++ return; ++ } ++ ++ kbd_request_region(); ++ ++ /* Flush any pending input. */ ++ kbd_clear_input(); ++ ++ if (kbd_startup_reset) { ++ char *msg = initialize_kbd(); ++ if (msg) ++ printk(KERN_WARNING "initialize_kbd: %s\n", msg); ++ } ++ ++#if defined CONFIG_PSMOUSE ++ psaux_init(); ++#endif ++ ++ kbd_rate = pckbd_rate; ++ ++ /* Ok, finally allocate the IRQ, and off we go.. */ ++ kbd_request_irq(keyboard_interrupt); ++} ++ ++#if defined CONFIG_PSMOUSE ++ ++static int __init aux_reconnect_setup (char *str) ++{ ++ aux_reconnect = 1; ++ return 1; ++} ++ ++__setup("psaux-reconnect", aux_reconnect_setup); ++ ++/* ++ * Check if this is a dual port controller. ++ */ ++static int __init detect_auxiliary_port(void) ++{ ++ unsigned long flags; ++ int loops = 10; ++ int retval = 0; ++ ++ /* Check if the BIOS detected a device on the auxiliary port. */ ++ if (aux_device_present == 0xaa) ++ return 1; ++ ++ spin_lock_irqsave(&kbd_controller_lock, flags); ++ ++ /* Put the value 0x5A in the output buffer using the "Write ++ * Auxiliary Device Output Buffer" command (0xD3). Poll the ++ * Status Register for a while to see if the value really ++ * turns up in the Data Register. If the KBD_STAT_MOUSE_OBF ++ * bit is also set to 1 in the Status Register, we assume this ++ * controller has an Auxiliary Port (a.k.a. Mouse Port). ++ */ ++ kb_wait(); ++ kbd_write_command(KBD_CCMD_WRITE_AUX_OBUF); ++ ++ kb_wait(); ++ kbd_write_output(0x5a); /* 0x5a is a random dummy value. */ ++ ++ do { ++ unsigned char status = kbd_read_status(); ++ ++ if (status & KBD_STAT_OBF) { ++ (void) kbd_read_input(); ++ if (status & KBD_STAT_MOUSE_OBF) { ++ printk(KERN_INFO "Detected PS/2 Mouse Port.\n"); ++ retval = 1; ++ } ++ break; ++ } ++ mdelay(1); ++ } while (--loops); ++ spin_unlock_irqrestore(&kbd_controller_lock, flags); ++ ++ return retval; ++} ++ ++/* ++ * Send a byte to the mouse. ++ */ ++static void aux_write_dev(int val) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&kbd_controller_lock, flags); ++ kb_wait(); ++ kbd_write_command(KBD_CCMD_WRITE_MOUSE); ++ kb_wait(); ++ kbd_write_output(val); ++ spin_unlock_irqrestore(&kbd_controller_lock, flags); ++} ++ ++/* ++ * Send a byte to the mouse & handle returned ack ++ */ ++static void __aux_write_ack(int val) ++{ ++ kb_wait(); ++ kbd_write_command(KBD_CCMD_WRITE_MOUSE); ++ kb_wait(); ++ kbd_write_output(val); ++ /* we expect an ACK in response. */ ++ mouse_reply_expected++; ++ kb_wait(); ++} ++ ++static void aux_write_ack(int val) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&kbd_controller_lock, flags); ++ __aux_write_ack(val); ++ spin_unlock_irqrestore(&kbd_controller_lock, flags); ++} ++ ++static unsigned char get_from_queue(void) ++{ ++ unsigned char result; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&kbd_controller_lock, flags); ++ result = queue->buf[queue->tail]; ++ queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); ++ spin_unlock_irqrestore(&kbd_controller_lock, flags); ++ return result; ++} ++ ++ ++static inline int queue_empty(void) ++{ ++ return queue->head == queue->tail; ++} ++ ++static int fasync_aux(int fd, struct file *filp, int on) ++{ ++ int retval; ++ ++ retval = fasync_helper(fd, filp, on, &queue->fasync); ++ if (retval < 0) ++ return retval; ++ return 0; ++} ++ ++ ++/* ++ * Random magic cookie for the aux device ++ */ ++#define AUX_DEV ((void *)queue) ++ ++static int release_aux(struct inode * inode, struct file * file) ++{ ++ lock_kernel(); ++ fasync_aux(-1, file, 0); ++ if (--aux_count) { ++ unlock_kernel(); ++ return 0; ++ } ++ kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */ ++ kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE); ++ aux_free_irq(AUX_DEV); ++ unlock_kernel(); ++ return 0; ++} ++ ++/* ++ * Install interrupt handler. ++ * Enable auxiliary device. ++ */ ++ ++static int open_aux(struct inode * inode, struct file * file) ++{ ++ if (aux_count++) { ++ return 0; ++ } ++ queue->head = queue->tail = 0; /* Flush input queue */ ++ if (aux_request_irq(keyboard_interrupt, AUX_DEV)) { ++ aux_count--; ++ return -EBUSY; ++ } ++ kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable the ++ auxiliary port on ++ controller. */ ++ aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ ++ kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */ ++ ++ mdelay(2); /* Ensure we follow the kbc access delay rules.. */ ++ ++ send_data(KBD_CMD_ENABLE); /* try to workaround toshiba4030cdt problem */ ++ ++ return 0; ++} ++ ++/* ++ * Put bytes from input queue to buffer. ++ */ ++ ++static ssize_t read_aux(struct file * file, char * buffer, ++ size_t count, loff_t *ppos) ++{ ++ DECLARE_WAITQUEUE(wait, current); ++ ssize_t i = count; ++ unsigned char c; ++ ++ if (queue_empty()) { ++ if (file->f_flags & O_NONBLOCK) ++ return -EAGAIN; ++ add_wait_queue(&queue->proc_list, &wait); ++repeat: ++ set_current_state(TASK_INTERRUPTIBLE); ++ if (queue_empty() && !signal_pending(current)) { ++ schedule(); ++ goto repeat; ++ } ++ current->state = TASK_RUNNING; ++ remove_wait_queue(&queue->proc_list, &wait); ++ } ++ while (i > 0 && !queue_empty()) { ++ c = get_from_queue(); ++ put_user(c, buffer++); ++ i--; ++ } ++ if (count-i) { ++ file->f_dentry->d_inode->i_atime = CURRENT_TIME; ++ return count-i; ++ } ++ if (signal_pending(current)) ++ return -ERESTARTSYS; ++ return 0; ++} ++ ++/* ++ * Write to the aux device. ++ */ ++ ++static ssize_t write_aux(struct file * file, const char * buffer, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t retval = 0; ++ ++ if (count) { ++ ssize_t written = 0; ++ ++ if (count > 32) ++ count = 32; /* Limit to 32 bytes. */ ++ do { ++ char c; ++ get_user(c, buffer++); ++ aux_write_dev(c); ++ written++; ++ } while (--count); ++ retval = -EIO; ++ if (written) { ++ retval = written; ++ file->f_dentry->d_inode->i_mtime = CURRENT_TIME; ++ } ++ } ++ ++ return retval; ++} ++ ++/* No kernel lock held - fine */ ++static unsigned int aux_poll(struct file *file, poll_table * wait) ++{ ++ poll_wait(file, &queue->proc_list, wait); ++ if (!queue_empty()) ++ return POLLIN | POLLRDNORM; ++ return 0; ++} ++ ++struct file_operations psaux_fops = { ++ read: read_aux, ++ write: write_aux, ++ poll: aux_poll, ++ open: open_aux, ++ release: release_aux, ++ fasync: fasync_aux, ++}; ++ ++/* ++ * Initialize driver. ++ */ ++static struct miscdevice psaux_mouse = { ++ PSMOUSE_MINOR, "psaux", &psaux_fops ++}; ++ ++static int __init psaux_init(void) ++{ ++ int retval; ++ ++ if (!detect_auxiliary_port()) ++ return -EIO; ++ ++ if ((retval = misc_register(&psaux_mouse))) ++ return retval; ++ ++ queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); ++ if (queue == NULL) { ++ printk(KERN_ERR "psaux_init(): out of memory\n"); ++ misc_deregister(&psaux_mouse); ++ return -ENOMEM; ++ } ++ memset(queue, 0, sizeof(*queue)); ++ queue->head = queue->tail = 0; ++ init_waitqueue_head(&queue->proc_list); ++ ++#ifdef INITIALIZE_MOUSE ++ kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */ ++ aux_write_ack(AUX_SET_SAMPLE); ++ aux_write_ack(100); /* 100 samples/sec */ ++ aux_write_ack(AUX_SET_RES); ++ aux_write_ack(3); /* 8 counts per mm */ ++ aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */ ++#endif /* INITIALIZE_MOUSE */ ++ kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */ ++ kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */ ++ ++ return 0; ++} ++ ++#endif /* CONFIG_PSMOUSE */ ++ ++ ++static int blink_frequency = HZ/2; ++ ++/* Tell the user who may be running in X and not see the console that we have ++ panic'ed. This is to distingush panics from "real" lockups. ++ Could in theory send the panic message as morse, but that is left as an ++ exercise for the reader. */ ++void panic_blink(void) ++{ ++ static unsigned long last_jiffie; ++ static char led; ++ /* Roughly 1/2s frequency. KDB uses about 1s. Make sure it is ++ different. */ ++ if (!blink_frequency) ++ return; ++ if (jiffies - last_jiffie > blink_frequency) { ++ led ^= 0x01 | 0x04; ++ while (kbd_read_status() & KBD_STAT_IBF) mdelay(1); ++ kbd_write_output(KBD_CMD_SET_LEDS); ++ mdelay(1); ++ while (kbd_read_status() & KBD_STAT_IBF) mdelay(1); ++ mdelay(1); ++ kbd_write_output(led); ++ last_jiffie = jiffies; ++ } ++} ++ ++static int __init panicblink_setup(char *str) ++{ ++ int par; ++ if (get_option(&str,&par)) ++ blink_frequency = par*(1000/HZ); ++ return 1; ++} ++ ++/* panicblink=0 disables the blinking as it caused problems with some console ++ switches. otherwise argument is ms of a blink period. */ ++__setup("panicblink=", panicblink_setup); ++ +--- linux-2.4.28/drivers/char/mem.c~colinux-0.6.1 2004-08-07 19:26:04.000000000 -0400 ++++ linux-2.4.28/drivers/char/mem.c 2004-11-27 15:59:21.304007320 -0500 +@@ -667,20 +667,24 @@ + static int memory_open(struct inode * inode, struct file * filp) + { + switch (MINOR(inode->i_rdev)) { ++#ifndef CONFIG_COOPERATIVE + case 1: + filp->f_op = &mem_fops; + break; + case 2: + filp->f_op = &kmem_fops; + break; ++#endif + case 3: + filp->f_op = &null_fops; + break; ++#ifndef CONFIG_COOPERATIVE + #if defined(CONFIG_ISA) || !defined(__mc68000__) + case 4: + filp->f_op = &port_fops; + break; + #endif ++#endif + case 5: + filp->f_op = &zero_fops; + break; +@@ -710,12 +714,16 @@ + umode_t mode; + struct file_operations *fops; + } list[] = { /* list of minor devices */ ++#ifndef CONFIG_COOPERATIVE + {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops}, + {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops}, ++#endif + {3, "null", S_IRUGO | S_IWUGO, &null_fops}, ++#ifndef CONFIG_COOPERATIVE + #if defined(CONFIG_ISA) || !defined(__mc68000__) + {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops}, + #endif ++#endif + {5, "zero", S_IRUGO | S_IWUGO, &zero_fops}, + {7, "full", S_IRUGO | S_IWUGO, &full_fops}, + {8, "random", S_IRUGO | S_IWUSR, &random_fops}, +--- linux-2.4.28/drivers/char/vt.c~colinux-0.6.1 2002-11-28 18:53:12.000000000 -0500 ++++ linux-2.4.28/drivers/char/vt.c 2004-11-27 15:59:21.305007168 -0500 +@@ -90,10 +90,10 @@ + * comments - KDMKTONE doesn't put the process to sleep. + */ + +-#if defined(__i386__) || defined(__alpha__) || defined(CONFIG_PPC_ISATIMER) \ +- || (defined(__mips__) && defined(CONFIG_ISA)) \ +- || (defined(__arm__) && defined(CONFIG_HOST_FOOTBRIDGE)) \ +- || defined(__x86_64__) ++#if (defined(__i386__) || defined(__alpha__) || defined(CONFIG_PPC_ISATIMER) \ ++ || (defined(__mips__) && defined(CONFIG_ISA)) \ ++ || (defined(__arm__) && defined(CONFIG_HOST_FOOTBRIDGE)) \ ++ || defined(__x86_64__)) && !defined(CONFIG_COOPERATIVE) + + static void + kd_nosound(unsigned long ignored) +--- linux-2.4.28/drivers/net/Config.in~colinux-0.6.1 2004-08-07 19:26:04.000000000 -0400 ++++ linux-2.4.28/drivers/net/Config.in 2004-11-27 15:59:21.306007016 -0500 +@@ -287,6 +287,10 @@ + dep_tristate 'iSeries Virtual Ethernet driver support' CONFIG_VETH $CONFIG_PPC_ISERIES + fi + ++if [ "$CONFIG_COOPERATIVE" = "y" ]; then ++ tristate 'Coooperative Virtual Ethernet driver support' CONFIG_COOPERATIVE_CONET ++fi ++ + if [ "$CONFIG_4xx" = "y" ]; then + source drivers/net/ibm_emac/Config.in + fi +--- linux-2.4.28/drivers/net/Makefile~colinux-0.6.1 2004-08-07 19:26:04.000000000 -0400 ++++ linux-2.4.28/drivers/net/Makefile 2004-11-27 15:59:21.306007016 -0500 +@@ -212,6 +212,7 @@ + + # This is also a 82596 and should probably be merged + obj-$(CONFIG_LP486E) += lp486e.o ++obj-$(CONFIG_COOPERATIVE_CONET) += conet.o + + obj-$(CONFIG_ETH16I) += eth16i.o + obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.28/drivers/net/conet.c 2004-11-27 15:59:21.307006864 -0500 +@@ -0,0 +1,309 @@ ++/* ++ * Copyright (C) 2003-2004 Dan Aloni <da-x@gmx.net> ++ * Copyright (C) 2004 Pat Erley ++ * Copyright (C) 2004 George Boutwell ++ * ++ * Cooperative Linux Network Device implementation ++ */ ++ ++#include <linux/config.h> ++#include <linux/version.h> ++#include <linux/module.h> ++ ++#include <linux/kernel.h> ++ ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> ++#include <linux/ethtool.h> ++ ++#include <linux/cooperative.h> ++#include <asm/irq.h> ++ ++struct conet_priv { ++ struct net_device_stats stats; ++ co_linux_message_t *message; ++ int status; ++ int unit; ++ int enabled; ++}; ++ ++struct net_device *conet_dev[CO_MODULE_MAX_CONET]; ++ ++void conet_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr); ++ ++static int conet_get_mac(int unit, char *address) ++{ ++ unsigned long flags = 0; ++ co_network_request_t *net_request; ++ int result = 0; ++ ++ local_irq_save(flags); ++ co_passage_page->operation = CO_OPERATION_DEVICE; ++ co_passage_page->params[0] = CO_DEVICE_NETWORK; ++ net_request = (typeof(net_request))&co_passage_page->params[1]; ++ net_request->unit = unit; ++ net_request->type = CO_NETWORK_GET_MAC; ++ co_switch_wrapper(); ++ memcpy(address, net_request->mac_address, ETH_ALEN); ++ result = net_request->result; ++ local_irq_restore(flags); ++ ++ return result; ++} ++ ++int conet_open(struct net_device *dev) ++{ ++ struct conet_priv *priv = (struct conet_priv *)dev->priv; ++ ++ if (priv->enabled) ++ return 0; ++ ++ MOD_INC_USE_COUNT; ++ ++ conet_get_mac(priv->unit, dev->dev_addr); ++ ++ priv->enabled = 1; ++ ++ netif_start_queue(dev); ++ ++ return 0; ++} ++ ++int conet_stop(struct net_device *dev) ++{ ++ struct conet_priv *priv = (struct conet_priv *)dev->priv; ++ ++ priv->enabled = 0; ++ ++ netif_stop_queue(dev); /* can't transmit any more */ ++ ++ MOD_DEC_USE_COUNT; ++ ++ return 0; ++} ++ ++int conet_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ int len; ++ char *data; ++ struct conet_priv *priv = (struct conet_priv *)dev->priv; ++ ++ len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; ++ data = skb->data; ++ ++ dev->trans_start = jiffies; /* save the timestamp */ ++ ++ co_send_message(CO_MODULE_LINUX, ++ CO_MODULE_CONET0 + priv->unit, ++ CO_PRIORITY_DISCARDABLE, ++ CO_MESSAGE_TYPE_OTHER, ++ len, ++ data); ++ ++ priv->stats.tx_bytes+=skb->len; ++ priv->stats.tx_packets++; ++ ++ dev_kfree_skb(skb); ++ ++ return 0; ++} ++ ++void conet_rx(struct net_device *dev) ++{ ++ struct sk_buff *skb; ++ struct conet_priv *priv = (struct conet_priv *)dev->priv; ++ int len; ++ unsigned char *buf; ++ co_linux_message_t *message; ++ ++ message = priv->message; ++ if (message == NULL) { ++ printk("conet rx: no message\n"); ++ return; ++ } ++ ++ priv->message = NULL; ++ ++ len = message->size; ++ buf = message->data; ++ ++ /* ++ * The packet has been retrieved from the transmission ++ * medium. Build an skb around it, so upper layers can handle it ++ */ ++ skb = dev_alloc_skb(len+2); ++ if (!skb) { ++ printk("conet rx: low on mem - packet dropped\n"); ++ priv->stats.rx_dropped++; ++ co_free_message(message); ++ return; ++ } ++ ++ memcpy(skb_put(skb, len), buf, len); ++ ++ /* Write metadata, and then pass to the receive level */ ++ skb->dev = dev; ++ skb->protocol = eth_type_trans(skb, dev); ++ skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ ++ ++ priv->stats.rx_bytes += len; ++ priv->stats.rx_packets++; ++ ++ netif_rx(skb); ++ ++ co_free_message(message); ++ return; ++} ++ ++void conet_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr) ++{ ++ co_linux_message_t *message; ++ ++ while (co_get_message(&message, CO_DEVICE_NETWORK)) { ++ struct net_device *dev; ++ struct conet_priv *priv; ++ ++ if (message->unit < 0 || message->unit >= CO_MODULE_MAX_CONET) { ++ printk("conet intrrupt: buggy network reception\n"); ++ return; ++ } ++ ++ dev = conet_dev[message->unit]; ++ if (!netif_running(dev)) { ++ co_free_message(message); ++ continue; ++ } ++ ++ priv = (struct conet_priv *)dev->priv; ++ if (priv->message != NULL) { ++ printk("conet intrrupt: freeing unhandled packet\n"); ++ co_free_message(message); ++ continue; ++ } ++ ++ priv->message = message; ++ conet_rx(dev); ++ } ++} ++ ++struct net_device_stats* conet_get_stats(struct net_device *dev) ++{ ++ return (struct net_device_stats *)dev->priv; ++} ++ ++int conet_init(struct net_device *dev) ++{ ++ struct conet_priv *priv = (struct conet_priv *)dev->priv; ++ ++ memset(&priv->stats, 0, sizeof(priv->stats)); ++ ++ ether_setup(dev); ++ ++ dev->open = conet_open; ++ dev->stop = conet_stop; ++ dev->hard_start_xmit = conet_hard_start_xmit; ++ dev->get_stats = conet_get_stats; ++ dev->irq = NETWORK_IRQ; ++ ++ SET_MODULE_OWNER(dev); ++ ++ return 0; ++} ++ ++void conet_uninit(struct net_device *dev) ++{ ++} ++ ++static struct net_device *conet_create(int unit) ++{ ++ struct net_device *dev; ++ struct conet_priv *priv; ++ int result = 0; ++ ++ dev = kmalloc(sizeof(struct net_device), GFP_KERNEL); ++ if (!dev) { ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ memset(dev, 0, sizeof(struct net_device)); ++ ++ priv = kmalloc(sizeof(struct conet_priv), GFP_KERNEL); ++ if (priv == NULL) { ++ kfree(dev); ++ return ERR_PTR(-ENOMEM); ++ } ++ ++ memset(priv, 0, sizeof(struct conet_priv)); ++ priv->unit = unit; ++ ++ dev->priv = priv; ++ dev->init = conet_init; ++ dev->uninit = conet_uninit; ++ strcpy(dev->name, "eth%d"); ++ ++ result = register_netdev(dev); ++ if (result) { ++ printk("conet: error %d registering device \"%s\"\n", result, dev->name); ++ kfree(dev->priv); ++ kfree(dev); ++ return ERR_PTR(-ENODEV); ++ } ++ ++ printk("conet%d: initialized\n", priv->unit); ++ ++ return dev; ++} ++ ++static void conet_destroy(struct net_device *dev) ++{ ++ struct conet_priv *priv = (struct conet_priv *) dev->priv; ++ ++ printk("conet%d: freed\n", priv->unit); ++ ++ unregister_netdev(dev); ++ kfree(dev->priv); ++ kfree(dev); ++} ++ ++static int __init conet_init_module(void) ++{ ++ int unit = 0, result; ++ struct net_device *dev; ++ char mac_address[6]; ++ ++ result = request_irq(NETWORK_IRQ, &conet_interrupt, 0, "conet", NULL); ++ ++ printk("conet: loaded (max %d devices)\n", CO_MODULE_MAX_CONET); ++ ++ for (unit=0; unit < CO_MODULE_MAX_CONET; unit++) { ++ conet_dev[unit] = NULL; ++ ++ result = conet_get_mac(unit, mac_address); ++ if (!result) ++ continue; ++ ++ dev = conet_create(unit); ++ if (!IS_ERR(dev)) ++ conet_dev[unit] = dev; ++ } ++ ++ return result; ++} ++ ++static void __exit conet_cleanup_module(void) ++{ ++ int unit = 0; ++ ++ free_irq(NETWORK_IRQ, NULL); ++ ++ for (unit=0; unit < CO_MODULE_MAX_CONET; unit++) { ++ if (!conet_dev[unit]) ++ continue; ++ ++ conet_destroy(conet_dev[unit]); ++ } ++} ++ ++module_init(conet_init_module); ++module_exit(conet_cleanup_module); +--- linux-2.4.28/drivers/video/Makefile~colinux-0.6.1 2004-02-18 08:36:31.000000000 -0500 ++++ linux-2.4.28/drivers/video/Makefile 2004-11-27 15:59:21.307006864 -0500 +@@ -15,7 +15,8 @@ + fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \ + fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \ + fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o \ +- cyber2000fb.o sa1100fb.o fbcon-hga.o fbgen.o ++ cyber2000fb.o sa1100fb.o fbcon-hga.o fbgen.o cocon.o \ ++ + + # Each configuration option enables a list of files. + +@@ -23,6 +24,7 @@ + obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o + obj-$(CONFIG_PROM_CONSOLE) += promcon.o promcon_tbl.o + obj-$(CONFIG_VGA_CONSOLE) += vgacon.o ++obj-$(CONFIG_COOPERATIVE_CONSOLE) += cocon.o + obj-$(CONFIG_MDA_CONSOLE) += mdacon.o + + obj-$(CONFIG_FONT_SUN8x16) += font_sun8x16.o +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.28/drivers/video/cocon.c 2004-11-27 15:59:21.308006712 -0500 +@@ -0,0 +1,484 @@ ++/* ++ * linux/drivers/video/cocon.c -- Cooperative Linux console VGA driver ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ * ++ * Based on code copied from vgacon.c. ++ * ++ * Dan Aloni <da-x@gmx.net>, 2003-2004 (c) ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/sched.h> ++#include <linux/fs.h> ++#include <linux/kernel.h> ++#include <linux/tty.h> ++#include <linux/console.h> ++#include <linux/console_struct.h> ++#include <linux/string.h> ++#include <linux/kd.h> ++#include <linux/slab.h> ++#include <linux/vt_kern.h> ++#include <linux/selection.h> ++#include <linux/init.h> ++ ++#include <linux/cooperative.h> ++ ++/* ++ * Interface used by the world ++ */ ++ ++static const char *cocon_startup(void); ++static void cocon_init(struct vc_data *c, int init); ++static void cocon_deinit(struct vc_data *c); ++static void cocon_clear(struct vc_data *c, int, int, int, int); ++static void cocon_cursor(struct vc_data *c, int mode); ++static int cocon_switch(struct vc_data *c); ++static int cocon_blank(struct vc_data *c, int blank); ++static int cocon_font_op(struct vc_data *c, struct console_font_op *op); ++static int cocon_set_palette(struct vc_data *c, unsigned char *table); ++static int cocon_scrolldelta(struct vc_data *c, int lines); ++static int cocon_set_origin(struct vc_data *c); ++static void cocon_save_screen(struct vc_data *c); ++static int cocon_scroll(struct vc_data *c, int t, int b, int dir, int lines); ++static u8 cocon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse); ++static void cocon_invert_region(struct vc_data *c, u16 *p, int count); ++ ++static const char __init *cocon_startup(void) ++{ ++ unsigned long flags; ++ co_console_message_t *message; ++ co_message_t *co_message; ++ ++ co_message = co_send_message_save(&flags); ++ message = (co_console_message_t *)co_message->data; ++ co_message->from = CO_MODULE_LINUX; ++ co_message->to = CO_MODULE_CONSOLE; ++ co_message->priority = CO_PRIORITY_DISCARDABLE; ++ co_message->type = CO_MESSAGE_TYPE_STRING; ++ co_message->size = ((char *)(&message->type + 1)) - ((char *)message); ++ message->type = CO_OPERATION_CONSOLE_STARTUP; ++ co_send_message_restore(flags); ++ ++ return "CoCON"; ++} ++ ++static void cocon_init(struct vc_data *c, int init) ++{ ++ unsigned long flags; ++ co_console_message_t *message; ++ co_message_t *co_message; ++ ++ /* We cannot be loaded as a module, therefore init is always 1 */ ++ c->vc_can_do_color = 1; ++ c->vc_cols = 80; ++ c->vc_rows = 25; ++ c->vc_complement_mask = 0x7700; ++ c->vc_visible_origin = 0; ++ c->vc_origin = 0; ++ ++ co_message = co_send_message_save(&flags); ++ message = (co_console_message_t *)co_message->data; ++ co_message->from = CO_MODULE_LINUX; ++ co_message->to = CO_MODULE_CONSOLE; ++ co_message->priority = CO_PRIORITY_DISCARDABLE; ++ co_message->type = CO_MESSAGE_TYPE_STRING; ++ co_message->size = ((char *)(&message->type + 1)) - ((char *)message); ++ message->type = CO_OPERATION_CONSOLE_INIT; ++ co_send_message_restore(flags); ++} ++ ++static void cocon_deinit(struct vc_data *c) ++{ ++ unsigned long flags; ++ co_console_message_t *message; ++ co_message_t *co_message; ++ ++ co_message = co_send_message_save(&flags); ++ message = (co_console_message_t *)co_message->data; ++ co_message->from = CO_MODULE_LINUX; ++ co_message->to = CO_MODULE_CONSOLE; ++ co_message->priority = CO_PRIORITY_DISCARDABLE; ++ co_message->type = CO_MESSAGE_TYPE_STRING; ++ co_message->size = ((char *)(&message->type + 1)) - ((char *)message); ++ message->type = CO_OPERATION_CONSOLE_DEINIT; ++ co_send_message_restore(flags); ++ ++} ++ ++static void cocon_clear(struct vc_data *c, int top, int left, int rows, int cols) ++{ ++ unsigned long flags; ++ co_console_message_t *message; ++ co_message_t *co_message; ++ ++ co_message = co_send_message_save(&flags); ++ message = (co_console_message_t *)co_message->data; ++ co_message->from = CO_MODULE_LINUX; ++ co_message->to = CO_MODULE_CONSOLE; ++ co_message->priority = CO_PRIORITY_DISCARDABLE; ++ co_message->type = CO_MESSAGE_TYPE_STRING; ++ co_message->size = ((char *)(&message->clear + 1)) - ((char *)message); ++ message->type = CO_OPERATION_CONSOLE_CLEAR; ++ message->clear.top = top; ++ message->clear.left = left; ++ message->clear.bottom = top + rows - 1; ++ message->clear.right = left + cols - 1; ++ message->clear.charattr = c->vc_video_erase_char; ++ co_send_message_restore(flags); ++} ++ ++static void cocon_putc(struct vc_data *c, int charattr, int y, int x) ++{ ++ unsigned long flags; ++ co_message_t *co_message; ++ co_console_message_t *message; ++ ++ co_message = co_send_message_save(&flags); ++ message = (co_console_message_t *)co_message->data; ++ co_message->from = CO_MODULE_LINUX; ++ co_message->to = CO_MODULE_CONSOLE; ++ co_message->priority = CO_PRIORITY_DISCARDABLE; ++ co_message->type = CO_MESSAGE_TYPE_STRING; ++ co_message->size = ((char *)(&message->putc + 1)) - ((char *)message); ++ message->type = CO_OPERATION_CONSOLE_PUTC; ++ message->putc.x = x; ++ message->putc.y = y; ++ message->putc.charattr = charattr; ++ co_send_message_restore(flags); ++} ++ ++ ++static void cocon_putcs(struct vc_data *conp, ++ const unsigned short *s, int count, int yy, int xx) ++{ ++ unsigned long flags; ++ co_console_message_t *message; ++ co_message_t *co_message; ++ ++ if (count > CO_MAX_PARAM_SIZE/2 - 16) ++ return; ++ ++ co_message = co_send_message_save(&flags); ++ message = (co_console_message_t *)co_message->data; ++ co_message->from = CO_MODULE_LINUX; ++ co_message->to = CO_MODULE_CONSOLE; ++ co_message->priority = CO_PRIORITY_DISCARDABLE; ++ co_message->type = CO_MESSAGE_TYPE_STRING; ++ co_message->size = ((char *)(&message->putcs + 1)) - ((char *)message) + ++ count * sizeof(unsigned short); ++ message->type = CO_OPERATION_CONSOLE_PUTCS; ++ message->putcs.x = xx; ++ message->putcs.y = yy; ++ message->putcs.count = count; ++ memcpy(&message->putcs.data, s, count * sizeof(unsigned short)); ++ co_send_message_restore(flags); ++} ++ ++static u8 cocon_build_attr(struct vc_data *c, u8 color, u8 intensity, u8 blink, u8 underline, u8 reverse) ++{ ++ u8 attr = color; ++ ++ if (underline) ++ attr = (attr & 0xf0) | c->vc_ulcolor; ++ else if (intensity == 0) ++ attr = (attr & 0xf0) | c->vc_halfcolor; ++ if (reverse) ++ attr = ((attr) & 0x88) | ((((attr) >> 4) | ((attr) << 4)) & 0x77); ++ if (blink) ++ attr ^= 0x80; ++ if (intensity == 2) ++ attr ^= 0x08; ++ ++ return attr; ++} ++ ++static void cocon_invert_region(struct vc_data *c, u16 *p, int count) ++{ ++ unsigned long flags; ++ co_message_t *co_message; ++ co_console_message_t *message; ++ unsigned x = p - c->vc_origin ; // UPDATE: vc_origin = 0; but not yet ++ ++ co_message = co_send_message_save(&flags); ++ message = (co_console_message_t *)co_message->data; ++ co_message->from = CO_MODULE_LINUX; ++ co_message->to = CO_MODULE_CONSOLE; ++ co_message->priority = CO_PRIORITY_DISCARDABLE; ++ co_message->type = CO_MESSAGE_TYPE_STRING; ++ co_message->size = ((char *)(&message->invert + 1)) - ((char *)message); ++ message->type = CO_OPERATION_CONSOLE_INVERT_REGION; ++ message->invert.y = ((unsigned)x)/c->vc_cols; ++ message->invert.x = ((unsigned)x)-(message->invert.y); ++ message->invert.count = count; ++ co_send_message_restore(flags); ++ ++ while (count--) { ++ u16 a = scr_readw(p); ++ a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4); ++ scr_writew(a, p++); ++ } ++ ++} ++ ++static void cocon_cursor(struct vc_data *c, int mode) ++{ ++ unsigned long flags; ++ co_console_message_t *message; ++ co_message_t *co_message; ++ ++ co_message = co_send_message_save(&flags); ++ message = (co_console_message_t *)co_message->data; ++ co_message->from = CO_MODULE_LINUX; ++ co_message->to = CO_MODULE_CONSOLE; ++ co_message->priority = CO_PRIORITY_DISCARDABLE; ++ co_message->type = CO_MESSAGE_TYPE_STRING; ++ co_message->size = ((char *)(&message->cursor + 1)) - ((char *)message);; ++ if (mode==CM_ERASE) { ++ message->type = CO_OPERATION_CONSOLE_CURSOR_ERASE; ++ message->cursor.height = 0; ++ co_send_message_restore(flags); ++ return; ++ } ++ ++ if(mode==CM_MOVE) { ++ message->type = CO_OPERATION_CONSOLE_CURSOR_MOVE; ++ } else /*(mode==CM_DRAW)*/ { ++ message->type = CO_OPERATION_CONSOLE_CURSOR_DRAW; ++ } ++ message->cursor.x = c->vc_x; ++ message->cursor.y = c->vc_y; ++ ++ switch (c->vc_cursor_type & CUR_HWMASK) { ++ case CUR_UNDERLINE: ++ message->cursor.height = 5; ++ break; ++ case CUR_TWO_THIRDS: ++ message->cursor.height = 66; ++ break; ++ case CUR_LOWER_THIRD: ++ message->cursor.height = 33; ++ break; ++ case CUR_LOWER_HALF: ++ message->cursor.height = 50; ++ break; ++ case CUR_NONE: ++ message->cursor.height = 0; ++ break; ++ default: ++ message->cursor.height = 5; ++ break; ++ } ++ ++ co_send_message_restore(flags); ++} ++ ++static int cocon_switch(struct vc_data *c) ++{ ++ unsigned long flags; ++ co_console_message_t *message; ++ co_message_t *co_message; ++ ++ co_message = co_send_message_save(&flags); ++ message = (co_console_message_t *)co_message->data; ++ co_message->from = CO_MODULE_LINUX; ++ co_message->to = CO_MODULE_CONSOLE; ++ co_message->priority = CO_PRIORITY_DISCARDABLE; ++ co_message->type = CO_MESSAGE_TYPE_STRING; ++ co_message->size = ((char *)(&message->type + 1)) - ((char *)message); ++ message->type = CO_OPERATION_CONSOLE_SWITCH; ++ co_send_message_restore(flags); ++ ++ return 1; /* Redrawing not needed */ ++} ++ ++static int cocon_set_palette(struct vc_data *c, unsigned char *table) ++{ ++ unsigned long flags; ++ co_console_message_t *message; ++ co_message_t *co_message; ++ ++ co_message = co_send_message_save(&flags); ++ message = (co_console_message_t *)co_message->data; ++ co_message->from = CO_MODULE_LINUX; ++ co_message->to = CO_MODULE_CONSOLE; ++ co_message->priority = CO_PRIORITY_DISCARDABLE; ++ co_message->type = CO_MESSAGE_TYPE_STRING; ++ co_message->size = ((char *)(&message->type + 1)) - ((char *)message); ++ message->type = CO_OPERATION_CONSOLE_SET_PALETTE; ++ co_send_message_restore(flags); ++ ++ return 1; ++} ++ ++static int cocon_blank(struct vc_data *c, int blank) ++{ ++ unsigned long flags; ++ co_console_message_t *message; ++ co_message_t *co_message; ++ ++ co_message = co_send_message_save(&flags); ++ message = (co_console_message_t *)co_message->data; ++ co_message->from = CO_MODULE_LINUX; ++ co_message->to = CO_MODULE_CONSOLE; ++ co_message->priority = CO_PRIORITY_DISCARDABLE; ++ co_message->type = CO_MESSAGE_TYPE_STRING; ++ co_message->size = ((char *)(&message->type + 1)) - ((char *)message); ++ message->type = CO_OPERATION_CONSOLE_BLANK; ++ co_send_message_restore(flags); ++ ++ return 1; ++} ++ ++static int cocon_font_op(struct vc_data *c, struct console_font_op *op) ++{ ++ unsigned long flags; ++ co_console_message_t *message; ++ co_message_t *co_message; ++ ++ co_message = co_send_message_save(&flags); ++ message = (co_console_message_t *)co_message->data; ++ co_message->from = CO_MODULE_LINUX; ++ co_message->to = CO_MODULE_CONSOLE; ++ co_message->priority = CO_PRIORITY_DISCARDABLE; ++ co_message->type = CO_MESSAGE_TYPE_STRING; ++ co_message->size = ((char *)(&message->type + 1)) - ((char *)message); ++ message->type = CO_OPERATION_CONSOLE_FONT_OP; ++ co_send_message_restore(flags); ++ ++ return 1; ++} ++ ++static int cocon_scrolldelta(struct vc_data *c, int lines) ++{ ++ unsigned long flags; ++ co_console_message_t *message; ++ co_message_t *co_message; ++ ++ co_message = co_send_message_save(&flags); ++ message = (co_console_message_t *)co_message->data; ++ co_message->from = CO_MODULE_LINUX; ++ co_message->to = CO_MODULE_CONSOLE; ++ co_message->priority = CO_PRIORITY_DISCARDABLE; ++ co_message->type = CO_MESSAGE_TYPE_STRING; ++ co_message->size = ((char *)(&message->type + 1)) - ((char *)message); ++ message->type = CO_OPERATION_CONSOLE_SCROLLDELTA; ++ co_send_message_restore(flags); ++ ++ return 1; ++} ++ ++static int cocon_set_origin(struct vc_data *c) ++{ ++ unsigned long flags; ++ co_console_message_t *message; ++ co_message_t *co_message; ++ ++ co_message = co_send_message_save(&flags); ++ message = (co_console_message_t *)co_message->data; ++ co_message->from = CO_MODULE_LINUX; ++ co_message->to = CO_MODULE_CONSOLE; ++ co_message->priority = CO_PRIORITY_DISCARDABLE; ++ co_message->type = CO_MESSAGE_TYPE_STRING; ++ co_message->size = ((char *)(&message->type + 1)) - ((char *)message); ++ message->type = CO_OPERATION_CONSOLE_SET_ORIGIN; ++ co_send_message_restore(flags); ++ ++ return 1; ++} ++ ++static void cocon_save_screen(struct vc_data *c) ++{ ++ unsigned long flags; ++ co_console_message_t *message; ++ co_message_t *co_message; ++ ++ co_message = co_send_message_save(&flags); ++ message = (co_console_message_t *)co_message->data; ++ co_message->from = CO_MODULE_LINUX; ++ co_message->to = CO_MODULE_CONSOLE; ++ co_message->priority = CO_PRIORITY_DISCARDABLE; ++ co_message->type = CO_MESSAGE_TYPE_STRING; ++ co_message->size = ((char *)(&message->type + 1)) - ((char *)message); ++ message->type = CO_OPERATION_CONSOLE_SAVE_SCREEN; ++ co_send_message_restore(flags); ++} ++ ++static int cocon_scroll(struct vc_data *c, int t, int b, int dir, int lines) ++{ ++ unsigned long flags; ++ co_console_message_t *message; ++ co_message_t *co_message; ++ ++ co_message = co_send_message_save(&flags); ++ message = (co_console_message_t *)co_message->data; ++ co_message->from = CO_MODULE_LINUX; ++ co_message->to = CO_MODULE_CONSOLE; ++ co_message->priority = CO_PRIORITY_DISCARDABLE; ++ co_message->type = CO_MESSAGE_TYPE_STRING; ++ co_message->size = ((char *)(&message->scroll + 1)) - ((char *)message); ++ if (dir == SM_UP) ++ message->type = CO_OPERATION_CONSOLE_SCROLL_UP; ++ else ++ message->type = CO_OPERATION_CONSOLE_SCROLL_DOWN; ++ message->scroll.top = t; ++ message->scroll.bottom = b-1; ++ message->scroll.lines = lines; ++ co_send_message_restore(flags); ++ ++ return 0; ++} ++ ++static void cocon_bmove(struct vc_data *c, int sy, int sx, int dy, int dx, int h, int w) ++{ ++ unsigned long flags; ++ co_console_message_t *message; ++ co_message_t *co_message; ++ ++ co_message = co_send_message_save(&flags); ++ message = (co_console_message_t *)co_message->data; ++ co_message->from = CO_MODULE_LINUX; ++ co_message->to = CO_MODULE_CONSOLE; ++ co_message->priority = CO_PRIORITY_DISCARDABLE; ++ co_message->type = CO_MESSAGE_TYPE_STRING; ++ co_message->size = ((char *)(&message->bmove + 1)) - ((char *)message); ++ message->type = CO_OPERATION_CONSOLE_BMOVE; ++ message->bmove.row = dy; ++ message->bmove.column = dx; ++ message->bmove.top = sy; ++ message->bmove.left = sx; ++ message->bmove.bottom = sy + h - 1; ++ message->bmove.right = sx + w - 1; ++ co_send_message_restore(flags); ++} ++ ++/* ++ * The console `switch' structure for the VGA based console ++ */ ++ ++const struct consw colinux_con = { ++ con_startup: cocon_startup, ++ con_init: cocon_init, ++ con_deinit: cocon_deinit, ++ con_clear: cocon_clear, ++ con_putc: cocon_putc, ++ con_putcs: cocon_putcs, ++ con_cursor: cocon_cursor, ++ con_scroll: cocon_scroll, ++ con_bmove: cocon_bmove, ++ con_switch: cocon_switch, ++ con_blank: cocon_blank, ++ con_font_op: cocon_font_op, ++ con_set_palette: cocon_set_palette, ++ con_scrolldelta: cocon_scrolldelta, ++ con_set_origin: cocon_set_origin, ++ con_save_screen: cocon_save_screen, ++ con_build_attr: cocon_build_attr, ++ con_invert_region: cocon_invert_region, ++}; ++ ++MODULE_LICENSE("GPL"); +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.28/include/asm-i386/cooperative.h 2004-11-27 15:59:21.308006712 -0500 +@@ -0,0 +1,175 @@ ++#ifndef __LINUX_ASM_COOPERATIVE_H__ ++#define __LINUX_ASM_COOPERATIVE_H__ ++ ++typedef struct { ++ unsigned short size; ++ struct x86_idt_entry *table; ++} __attribute__((packed)) x86_idt_t; ++ ++typedef struct { ++ unsigned short limit; ++ struct x86_dt_entry *base; ++} __attribute__((packed)) x86_gdt_t; ++ ++typedef struct { ++ unsigned char border2[0x4]; ++ ++ unsigned long cs; ++ #define CO_ARCH_STATE_STACK_CS "0x04" ++ ++ unsigned long ds; ++ #define CO_ARCH_STATE_STACK_DS "0x08" ++ ++ unsigned long es; ++ #define CO_ARCH_STATE_STACK_ES "0x0C" ++ ++ unsigned long cr3; ++ #define CO_ARCH_STATE_STACK_CR3 "0x10" ++ ++ unsigned long cr4; ++ #define CO_ARCH_STATE_STACK_CR4 "0x14" ++ ++ unsigned long cr2; ++ #define CO_ARCH_STATE_STACK_CR2 "0x18" ++ ++ unsigned long cr0; ++ #define CO_ARCH_STATE_STACK_CR0 "0x1C" ++ ++ x86_gdt_t gdt; ++ #define CO_ARCH_STATE_STACK_GDT "0x20" ++ ++ unsigned long fs; ++ #define CO_ARCH_STATE_STACK_FS "0x26" ++ ++ unsigned long gs; ++ #define CO_ARCH_STATE_STACK_GS "0x2A" ++ ++ unsigned short ldt; ++ #define CO_ARCH_STATE_STACK_LDT "0x2E" ++ ++ x86_idt_t idt; ++ #define CO_ARCH_STATE_STACK_IDT "0x30" ++ ++ unsigned short tr; ++ #define CO_ARCH_STATE_STACK_TR "0x36" ++ ++ unsigned long return_eip; ++ #define CO_ARCH_STATE_STACK_RETURN_EIP "0x38" ++ ++ unsigned long flags; ++ #define CO_ARCH_STATE_STACK_FLAGS "0x3C" ++ ++ unsigned long esp; ++ #define CO_ARCH_STATE_STACK_ESP "0x40" ++ ++ unsigned long ss; ++ #define CO_ARCH_STATE_STACK_SS "0x44" ++ ++ unsigned long dr0; ++ #define CO_ARCH_STATE_STACK_DR0 "0x48" ++ ++ unsigned long dr1; ++ #define CO_ARCH_STATE_STACK_DR1 "0x4C" ++ ++ unsigned long dr2; ++ #define CO_ARCH_STATE_STACK_DR2 "0x50" ++ ++ unsigned long dr3; ++ #define CO_ARCH_STATE_STACK_DR3 "0x54" ++ ++ unsigned long dr6; ++ #define CO_ARCH_STATE_STACK_DR6 "0x58" ++ ++ unsigned long dr7; ++ #define CO_ARCH_STATE_STACK_DR7 "0x5C" ++ ++ unsigned long other_map; ++ #define CO_ARCH_STATE_STACK_OTHERMAP "0x60" ++ ++ unsigned long relocate_eip; ++ #define CO_ARCH_STATE_STACK_RELOCATE_EIP "0x64" ++ #define CO_ARCH_STATE_STACK_RELOCATE_EIP_AFTER "0x68" ++ ++ unsigned long pad1; ++ unsigned long pad2; ++ ++ unsigned char fxstate[0x200]; ++ #define CO_ARCH_STATE_STACK_FXSTATE "0x70" ++} __attribute__((packed)) co_arch_state_stack_t; ++ ++extern void co_debug(const char *fmt, ...); ++ ++static inline void co_passage_page_dump_state(co_arch_state_stack_t *state) ++{ ++ co_debug("cs: %04x ds: %04x es: %04x fs: %04x gs: %04x ss: %04x\n", ++ state->cs, state->ds, state->es, state->fs, state->gs, state->ss); ++ ++ co_debug("cr0: %08x cr2: %08x cr3: %08x cr4: %08x\n", ++ state->cr0, state->cr2, state->cr3, state->cr4); ++ ++ co_debug("dr0: %08x dr1: %08x dr2: %08x dr3: %08x dr6: %08x dr7: %08x\n", ++ state->dr0, state->dr1, state->dr2, state->dr3, state->dr6, state->dr7); ++ ++ co_debug("gdt: %08x:%04x idt:%08x:%04x ldt:%04x tr:%04x\n", ++ state->gdt.base, state->gdt.limit, state->idt.table, state->idt.size, ++ state->ldt, state->tr); ++ ++ co_debug("return_eip: %08x flags: %08x esp: %8x\n", ++ state->return_eip, state->flags, state->esp); ++ ++ co_debug("other_map: %08x relocate_eip: %08x\n", ++ state->other_map, state->relocate_eip); ++} ++ ++#define CO_MAX_PARAM_SIZE 0x400 ++ ++typedef struct co_arch_passage_page { ++ union { ++ struct { ++ union { ++ struct { ++ unsigned long temp_pgd_physical; ++ unsigned long dr0; ++ unsigned long dr1; ++ unsigned long dr2; ++ unsigned long dr3; ++ unsigned long dr6; ++ unsigned long dr7; ++ unsigned char code[0x1c0]; ++ } __attribute__((packed)); ++ unsigned char pad[0x210]; ++ } __attribute__((packed)); ++ ++ /* Machine states */ ++ co_arch_state_stack_t host_state; ++ co_arch_state_stack_t linuxvm_state; ++ ++ /* Control parameters */ ++ unsigned long operation; ++ unsigned long params[]; ++ } __attribute__((packed)); ++ unsigned char first_page[0x1000]; ++ }; ++ unsigned long temp_pgd[0x400]; ++ unsigned long temp_pte[2][0x400]; ++} co_arch_passage_page_t; ++ ++static inline void co_passage_page_dump(co_arch_passage_page_t *page) ++{ ++ co_debug("Host state\n"); ++ co_passage_page_dump_state(&page->host_state); ++ ++ co_debug("Linux state\n"); ++ co_passage_page_dump_state(&page->linuxvm_state); ++} ++ ++/* ++ * Address space layout: ++ */ ++ ++#define CO_VPTR_PHYSICAL_TO_PSEUDO_PFN_MAP (0xff000000) ++#define CO_VPTR_PSEUDO_RAM_PAGE_TABLES (0xfef00000) ++#define CO_VPTR_PASSAGE_PAGE (0xfeeff000) ++#define CO_VPTR_SELF_MAP (0xfec00000) ++ ++#endif +--- linux-2.4.28/include/asm-i386/dma.h~colinux-0.6.1 2003-08-25 07:44:43.000000000 -0400 ++++ linux-2.4.28/include/asm-i386/dma.h 2004-11-27 15:59:21.309006560 -0500 +@@ -268,6 +268,8 @@ + * + * Assumes DMA flip-flop is clear. + */ ++ ++#ifndef CONFIG_COOPERATIVE + static __inline__ int get_dma_residue(unsigned int dmanr) + { + unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE +@@ -281,7 +283,7 @@ + + return (dmanr<=3)? count : (count<<1); + } +- ++#endif + + /* These are in kernel/dma.c: */ + extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */ +--- linux-2.4.28/include/asm-i386/io.h~colinux-0.6.1 2003-06-13 10:51:38.000000000 -0400 ++++ linux-2.4.28/include/asm-i386/io.h 2004-11-27 15:59:21.309006560 -0500 +@@ -2,6 +2,7 @@ + #define _ASM_IO_H + + #include <linux/config.h> ++#include <linux/cooperative.h> + + /* + * This file contains the definitions for the x86 IO instructions +@@ -45,6 +46,7 @@ + #ifdef __KERNEL__ + + #include <linux/vmalloc.h> ++#include <linux/cooperative.h> + + /* + * Temporary debugging check to catch old code using +@@ -121,6 +123,9 @@ + + static inline void * ioremap (unsigned long offset, unsigned long size) + { ++#ifdef CONFIG_COOPERATIVE ++ panic("ioremap %ld:%ld\n", offset, size); ++#endif + return __ioremap(offset, size, 0); + } + +@@ -146,6 +151,9 @@ + + static inline void * ioremap_nocache (unsigned long offset, unsigned long size) + { ++#ifdef CONFIG_COOPERATIVE ++ panic("ioremap_nocache %ld:%ld\n", offset, size); ++#endif + return __ioremap(offset, size, _PAGE_PCD); + } + +@@ -308,6 +316,8 @@ + + #endif /* __KERNEL__ */ + ++#ifndef CONFIG_COOPERATIVE_NOT ++ + #ifdef SLOW_IO_BY_JUMPING + #define __SLOW_DOWN_IO "\njmp 1f\n1:\tjmp 1f\n1:" + #else +@@ -427,4 +437,21 @@ + __OUTS(w) + __OUTS(l) + ++#else ++ ++static inline unsigned long badio(const char *file, int line) ++{ ++#ifdef CONFIG_COOPERATIVE ++ panic("badio %s:%d\n", file, line); ++#endif ++ return 0; ++} ++ ++#define outb(port, data) badio(__FILE__, __LINE__) ++#define inb(port) badio(__FILE__, __LINE__) ++#define outb_p(port, data) badio(__FILE__, __LINE__) ++#define inb_p(port) badio(__FILE__, __LINE__) ++ ++#endif ++ + #endif +--- linux-2.4.28/include/asm-i386/irq.h~colinux-0.6.1 2002-08-02 20:39:45.000000000 -0400 ++++ linux-2.4.28/include/asm-i386/irq.h 2004-11-27 15:59:21.310006408 -0500 +@@ -14,6 +14,10 @@ + + #define TIMER_IRQ 0 + ++#ifdef CONFIG_COOPERATIVE ++#define NETWORK_IRQ 2 ++#endif ++ + /* + * 16 8259A IRQ's, 208 potential APIC interrupt sources. + * Right now the APIC is mostly only used for SMP. +@@ -23,7 +27,7 @@ + * Since vectors 0x00-0x1f are used/reserved for the CPU, + * the usable vector space is 0x20-0xff (224 vectors) + */ +-#ifdef CONFIG_X86_IO_APIC ++#if defined(CONFIG_X86_IO_APIC) || defined(CONFIG_X86_COPIC) + #define NR_IRQS 224 + #else + #define NR_IRQS 16 +--- linux-2.4.28/include/asm-i386/mc146818rtc.h~colinux-0.6.1 2001-11-22 14:46:58.000000000 -0500 ++++ linux-2.4.28/include/asm-i386/mc146818rtc.h 2004-11-27 15:59:21.310006408 -0500 +@@ -4,6 +4,7 @@ + #ifndef _ASM_MC146818RTC_H + #define _ASM_MC146818RTC_H + ++#include <linux/config.h> + #include <asm/io.h> + + #ifndef RTC_PORT +@@ -11,6 +12,7 @@ + #define RTC_ALWAYS_BCD 1 /* RTC operates in binary mode */ + #endif + ++#ifndef CONFIG_COOPERATIVE + /* + * The yet supported machines all access the RTC index register via + * an ISA port access but the way to access the date register differs ... +@@ -24,6 +26,11 @@ + outb_p((val),RTC_PORT(1)); \ + }) + ++#else ++#define CMOS_READ(addr) (0) ++#define CMOS_WRITE(val, addr) (0) ++#endif ++ + #define RTC_IRQ 8 + + #endif /* _ASM_MC146818RTC_H */ +--- linux-2.4.28/include/asm-i386/page.h~colinux-0.6.1 2002-08-02 20:39:45.000000000 -0400 ++++ linux-2.4.28/include/asm-i386/page.h 2004-11-27 15:59:21.310006408 -0500 +@@ -1,6 +1,10 @@ + #ifndef _I386_PAGE_H + #define _I386_PAGE_H + ++#ifdef CONFIG_COOPERATIVE ++#define WANT_PAGE_VIRTUAL ++#endif ++ + /* PAGE_SHIFT determines the page size */ + #define PAGE_SHIFT 12 + #define PAGE_SIZE (1UL << PAGE_SHIFT) +@@ -10,6 +14,7 @@ + #ifndef __ASSEMBLY__ + + #include <linux/config.h> ++#include <asm/cooperative.h> + + #ifdef CONFIG_X86_USE_3DNOW + +@@ -80,6 +85,22 @@ + + #define __PAGE_OFFSET (0xC0000000) + ++#ifdef CONFIG_COOPERATIVE ++ ++#define CO_PPTM_OFFSET (CO_VPTR_PSEUDO_RAM_PAGE_TABLES) ++#define CO_RPPTM_OFFSET (CO_VPTR_PHYSICAL_TO_PSEUDO_PFN_MAP) ++ ++#define CO_PFN(vaddr) ((((unsigned long)vaddr) - __PAGE_OFFSET) >> PAGE_SHIFT) ++#define CO_PA(pfn) (((unsigned long *)CO_PPTM_OFFSET)[pfn]) ++#define CO_PFN_PA(vaddr) CO_PA(CO_PFN(vaddr)) ++#define CO_PPTM_SIZE (max_low_pfn * sizeof(pte_t)) ++ ++#define CO_VA_PFN(pa) (((unsigned long *)CO_RPPTM_OFFSET)[((pa) >> PAGE_SHIFT)]) ++#define CO_VA_PAGE(pa) (mem_map + CO_VA_PFN(pa)) ++#define CO_VA(pa) ((CO_VA_PFN(pa) << PAGE_SHIFT) + __PAGE_OFFSET) ++ ++#endif ++ + /* + * This much address space is reserved for vmalloc() and iomap() + * as well as fixmap mappings. +@@ -96,11 +117,16 @@ + */ + + #if 1 /* Set to zero for a slightly smaller kernel */ ++#ifdef CONFIG_COOPERATIVE ++#define BUG() do { panic("BUG %s:%d\n", __FILE__, __LINE__); } while(0) ++#else + #define BUG() \ + __asm__ __volatile__( "ud2\n" \ + "\t.word %c0\n" \ + "\t.long %c1\n" \ + : : "i" (__LINE__), "i" (__FILE__)) ++ ++#endif + #else + #define BUG() __asm__ __volatile__("ud2\n") + #endif +@@ -129,9 +155,11 @@ + #define VMALLOC_RESERVE ((unsigned long)__VMALLOC_RESERVE) + #define __MAXMEM (-__PAGE_OFFSET-__VMALLOC_RESERVE) + #define MAXMEM ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE)) +-#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) + #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) ++#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) ++ + #define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT)) ++ + #define VALID_PAGE(page) ((page - mem_map) < max_mapnr) + + #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ +--- linux-2.4.28/include/asm-i386/pgalloc.h~colinux-0.6.1 2003-08-25 07:44:43.000000000 -0400 ++++ linux-2.4.28/include/asm-i386/pgalloc.h 2004-11-27 15:59:21.313005952 -0500 +@@ -11,8 +11,13 @@ + #define pte_quicklist (current_cpu_data.pte_quick) + #define pgtable_cache_size (current_cpu_data.pgtable_cache_sz) + ++#ifndef CONFIG_COOPERATIVE + #define pmd_populate(mm, pmd, pte) \ +- set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))) ++ set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))) ++#else ++#define pmd_populate(mm, pmd, pte) \ ++ set_pmd(pmd, __pmd(_PAGE_TABLE + (CO_PFN_PA(pte) & PAGE_MASK))) ++#endif + + /* + * Allocate and free page tables. +--- linux-2.4.28/include/asm-i386/pgtable-2level.h~colinux-0.6.1 2002-11-28 18:53:15.000000000 -0500 ++++ linux-2.4.28/include/asm-i386/pgtable-2level.h 2004-11-27 15:59:21.313005952 -0500 +@@ -58,8 +58,14 @@ + } + #define ptep_get_and_clear(xp) __pte(xchg(&(xp)->pte_low, 0)) + #define pte_same(a, b) ((a).pte_low == (b).pte_low) +-#define pte_page(x) (mem_map+((unsigned long)(((x).pte_low >> PAGE_SHIFT)))) + #define pte_none(x) (!(x).pte_low) ++ ++#ifndef CONFIG_COOPERATIVE ++#define pte_page(x) (mem_map+((unsigned long)(((x).pte_low >> PAGE_SHIFT)))) + #define __mk_pte(page_nr,pgprot) __pte(((page_nr) << PAGE_SHIFT) | pgprot_val(pgprot)) ++#else ++#define pte_page(x) CO_VA_PAGE((x).pte_low) ++#define __mk_pte(page_nr,pgprot) __pte((CO_PA(page_nr) & PAGE_MASK) | pgprot_val(pgprot)) ++#endif + + #endif /* _I386_PGTABLE_2LEVEL_H */ +--- linux-2.4.28/include/asm-i386/pgtable.h~colinux-0.6.1 2002-11-28 18:53:15.000000000 -0500 ++++ linux-2.4.28/include/asm-i386/pgtable.h 2004-11-27 15:59:21.313005952 -0500 +@@ -320,8 +320,13 @@ + + #define page_pte(page) page_pte_prot(page, __pgprot(0)) + ++#ifndef CONFIG_COOPERATIVE + #define pmd_page(pmd) \ +-((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) ++ ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) ++#else ++#define pmd_page(pmd) \ ++ (CO_VA(pmd_val(pmd))) ++#endif + + /* to find an entry in a page-table-directory. */ + #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) +--- linux-2.4.28/include/asm-i386/processor.h~colinux-0.6.1 2004-02-18 08:36:32.000000000 -0500 ++++ linux-2.4.28/include/asm-i386/processor.h 2004-11-27 15:59:21.314005800 -0500 +@@ -181,8 +181,18 @@ + #define X86_CR4_OSFXSR 0x0200 /* enable fast FPU save and restore */ + #define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */ + ++#ifndef CONFIG_COOPERATIVE + #define load_cr3(pgdir) \ +- asm volatile("movl %0,%%cr3": :"r" (__pa(pgdir))); ++asm volatile("movl %0,%%cr3": :"r" (__pa(pgdir))); ++#else ++/* ++ * In coLinux Mode we can't load CR3 with the pseudo physical ++ * address. Instead, we need to translate the pseudo physical address ++ * to the real physical address. ++ */ ++#define load_cr3(pgdir) \ ++asm volatile("movl %0,%%cr3": :"r" (CO_PFN_PA(pgdir))); ++#endif + + /* + * Save the cr4 feature set we're using (ie +--- linux-2.4.28/include/asm-i386/system.h~colinux-0.6.1 2004-04-14 09:05:40.000000000 -0400 ++++ linux-2.4.28/include/asm-i386/system.h 2004-11-27 15:59:21.314005800 -0500 +@@ -12,7 +12,15 @@ + struct task_struct; /* one of the stranger aspects of C forward declarations.. */ + extern void FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next)); + ++#ifdef CONFIG_COOPERATIVE ++#define prepare_to_switch() { \ ++ asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->thread.fs)); \ ++ asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->thread.gs)); \ ++} ++#else + #define prepare_to_switch() do { } while(0) ++#endif ++ + #define switch_to(prev,next,last) do { \ + asm volatile("pushl %%esi\n\t" \ + "pushl %%edi\n\t" \ +--- linux-2.4.28/include/linux/console.h~colinux-0.6.1 2004-02-18 08:36:32.000000000 -0500 ++++ linux-2.4.28/include/linux/console.h 2004-11-27 15:59:21.315005648 -0500 +@@ -55,6 +55,7 @@ + extern const struct consw dummy_con; /* dummy console buffer */ + extern const struct consw fb_con; /* frame buffer based console */ + extern const struct consw vga_con; /* VGA text console */ ++extern const struct consw colinux_con; /* coLinux Mode text console */ + extern const struct consw newport_con; /* SGI Newport console */ + extern const struct consw prom_con; /* SPARC PROM console */ + +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.28/include/linux/cooperative.h 2004-11-27 15:59:21.315005648 -0500 +@@ -0,0 +1,323 @@ ++#ifndef __LINUX_COOPERATIVE_H__ ++#define __LINUX_COOPERATIVE_H__ ++ ++#ifdef __KERNEL__ ++#ifndef CO_KERNEL ++#define CO_COLINUX_KERNEL ++#define CO_KERNEL ++#endif ++#endif ++ ++extern void co_debug(const char *fmt, ...); ++ ++#include <asm/cooperative.h> ++ ++#define CO_LINUX_ABI_VERSION 1 ++ ++#pragma pack(0) ++ ++#define CO_BOOTPARAM_STRING_LENGTH 0x100 ++ ++extern char co_boot_parameters[CO_BOOTPARAM_STRING_LENGTH]; ++ ++typedef enum { ++ CO_OPERATION_EMPTY=0, ++ CO_OPERATION_START, ++ CO_OPERATION_IDLE, ++ CO_OPERATION_TERMINATE, ++ CO_OPERATION_MESSAGE_TO_MONITOR, ++ CO_OPERATION_MESSAGE_FROM_MONITOR, ++ CO_OPERATION_FORWARD_INTERRUPT, ++ CO_OPERATION_DEVICE, ++ CO_OPERATION_GET_TIME, ++ CO_OPERATION_DEBUG_LINE, ++ CO_OPERATION_GET_HIGH_PREC_QUOTIENT, ++ CO_OPERATION_TRACE_POINT, ++} co_operation_t; ++ ++#define CO_MODULE_MAX_CONET 16 ++#define CO_MODULE_MAX_COBD 32 ++ ++typedef enum { ++ CO_MODULE_LINUX, ++ CO_MODULE_MONITOR, ++ CO_MODULE_DAEMON, ++ CO_MODULE_IDLE, ++ CO_MODULE_KERNEL_SWITCH, ++ CO_MODULE_USER_SWITCH, ++ CO_MODULE_CONSOLE, ++ CO_MODULE_PRINTK, ++ ++ CO_MODULE_CONET0, ++ CO_MODULE_CONET_END=CO_MODULE_CONET0+CO_MODULE_MAX_CONET-1, ++ ++ CO_MODULE_COBD0, ++ CO_MODULE_COBD_END=CO_MODULE_COBD0+CO_MODULE_MAX_COBD-1, ++} co_module_t; ++ ++typedef enum { ++ CO_PRIORITY_DISCARDABLE=0, ++ CO_PRIORITY_IMPORTANT, ++} co_priority_t; ++ ++typedef enum { ++ CO_MESSAGE_TYPE_STRING=0, ++ CO_MESSAGE_TYPE_OTHER=1, ++} co_message_type_t; ++ ++typedef struct { ++ co_module_t from; ++ co_module_t to; ++ co_priority_t priority; ++ co_message_type_t type; ++ unsigned long size; ++ char data[0]; ++} __attribute__((packed)) co_message_t; ++ ++typedef enum { ++ CO_DEVICE_BLOCK=0, ++ CO_DEVICE_CONSOLE, ++ CO_DEVICE_KEYBOARD, ++ CO_DEVICE_NETWORK, ++ CO_DEVICE_TIMER, ++ CO_DEVICE_POWER, ++ ++ CO_DEVICES_TOTAL, ++} co_device_t; ++ ++typedef struct { ++ unsigned char code; ++ int down; ++} co_scan_code_t; ++ ++typedef enum { ++ CO_LINUX_MESSAGE_POWER_ALT_CTRL_DEL=0, ++} co_linux_message_power_type_t; ++ ++typedef struct { ++ co_linux_message_power_type_t type; ++} __attribute__((packed)) co_linux_message_power_t; ++ ++typedef struct { ++ unsigned long tick_count; ++} __attribute__((packed)) co_linux_message_idle_t; ++ ++typedef struct { ++ co_device_t device; ++ unsigned long unit; ++ unsigned long size; ++ char data[]; ++} __attribute__((packed)) co_linux_message_t; ++ ++typedef enum { ++ CO_TERMINATE_END=0, ++ CO_TERMINATE_REBOOT, ++ CO_TERMINATE_POWEROFF, ++ CO_TERMINATE_PANIC, ++ CO_TERMINATE_HALT, ++ CO_TERMINATE_FORCED_OFF, ++ CO_TERMINATE_FORCED_END, ++ CO_TERMINATE_INVALID_OPERATION, ++} co_termination_reason_t; ++ ++typedef void (*co_switcher_t)(co_arch_passage_page_t *page, ++ unsigned char *from, ++ unsigned char *to); ++ ++#define co_passage_page_func_low(_from_,_to_) \ ++ (((co_switcher_t)(co_passage_page->code)) \ ++ (co_passage_page, \ ++ (char *)&_from_.border2, \ ++ (char *)&_to_.border2)) ++ ++#define co_passage_page_func(_from_,_to_) \ ++ co_passage_page_func_low(co_passage_page->_from_, co_passage_page->_to_) ++ ++#ifdef CO_KERNEL ++# ifdef CO_COLINUX_KERNEL ++# define co_passage_page ((co_arch_passage_page_t *)(CO_VPTR_PASSAGE_PAGE)) ++# define co_current (co_passage_page->linuxvm_state) ++# define co_other (co_passage_page->host_state) ++# else ++# define co_passage_page (cmon->passage_page) ++# define co_other (co_passage_page->linuxvm_state) ++# define co_current (co_passage_page->host_state) ++# endif ++ ++# define co_switch() co_passage_page_func_low(co_current, co_other) ++#endif ++ ++/* ++ * Defines operations on various virtual devices. ++ */ ++ ++typedef enum { ++ CO_OPERATION_CONSOLE_STARTUP=0, ++ CO_OPERATION_CONSOLE_INIT=1, ++ CO_OPERATION_CONSOLE_DEINIT, ++ CO_OPERATION_CONSOLE_CLEAR, ++ CO_OPERATION_CONSOLE_PUTC, ++ CO_OPERATION_CONSOLE_PUTCS, ++ CO_OPERATION_CONSOLE_CURSOR_DRAW, ++ CO_OPERATION_CONSOLE_CURSOR_ERASE, ++ CO_OPERATION_CONSOLE_CURSOR_MOVE, ++ CO_OPERATION_CONSOLE_SCROLL_UP, ++ CO_OPERATION_CONSOLE_SCROLL_DOWN, ++ CO_OPERATION_CONSOLE_BMOVE, ++ CO_OPERATION_CONSOLE_SWITCH, ++ CO_OPERATION_CONSOLE_BLANK, ++ CO_OPERATION_CONSOLE_FONT_OP, ++ CO_OPERATION_CONSOLE_SET_PALETTE, ++ CO_OPERATION_CONSOLE_SCROLLDELTA, ++ CO_OPERATION_CONSOLE_SET_ORIGIN, ++ CO_OPERATION_CONSOLE_SAVE_SCREEN, ++ CO_OPERATION_CONSOLE_INVERT_REGION, ++} co_operation_console_t; ++ ++ ++typedef char co_console_code; ++typedef unsigned short co_console_character; ++typedef unsigned short co_console_unit; ++ ++typedef struct { ++ co_console_unit x; ++ co_console_unit y; ++ co_console_unit height; ++} __attribute__((packed)) co_cursor_pos_t; ++ ++typedef struct { ++ co_operation_console_t type; ++ union { ++ struct { ++ co_console_unit top; ++ co_console_unit bottom; ++ co_console_unit lines; ++ } scroll; ++ struct { ++ co_console_unit y; ++ co_console_unit x; ++ co_console_unit count; ++ co_console_character data[]; ++ } putcs; ++ struct { ++ co_console_unit x; ++ co_console_unit y; ++ co_console_character charattr; ++ } putc; ++ struct { ++ co_console_unit top; ++ co_console_unit left; ++ co_console_unit bottom; ++ co_console_unit right; ++ co_console_character charattr; ++ } clear; ++ struct { ++ co_console_unit y; ++ co_console_unit x; ++ co_console_unit count; ++ } invert; ++ struct { ++ co_console_unit row; ++ co_console_unit column; ++ co_console_unit top; ++ co_console_unit left; ++ co_console_unit bottom; ++ co_console_unit right; ++ } bmove; ++ co_cursor_pos_t cursor; ++ }; ++} __attribute__((packed)) co_console_message_t; ++ ++typedef struct { ++ unsigned long index; ++ unsigned long flags; ++ unsigned long func; ++ unsigned long pid; ++} __attribute__((packed)) co_trace_point_info_t; ++ ++extern void co_printk(char *line); ++extern void co_callback(void); ++extern void co_switch_wrapper(void); ++extern void co_idle_processor(void); ++extern void co_terminate(co_termination_reason_t reason); ++ ++extern void co_send_message(co_module_t from, ++ co_module_t to, ++ co_priority_t priority, ++ co_message_type_t type, ++ unsigned long size, ++ char *data); ++extern co_message_t *co_send_message_save(unsigned long *flags); ++extern co_message_t *co_get_message_save(unsigned long *flags); ++extern void co_send_message_restore(unsigned long flags); ++ ++extern void co_handle_device_interrupt(co_linux_message_t *message); ++extern void co_received_message(co_linux_message_t *message); ++extern int co_get_message(co_linux_message_t **message, co_device_t device); ++extern void co_free_message(co_linux_message_t *message); ++ ++extern unsigned long co_bootmem_pages; ++extern unsigned long co_core_end; ++extern unsigned long co_memory_size; ++extern unsigned long co_rpptm_size; ++ ++extern unsigned long co_get_host_time(void); ++extern void handle_keyboard_event(unsigned char scancode); ++ ++typedef enum { ++ CO_BLOCK_OPEN=0, ++ CO_BLOCK_STAT, ++ CO_BLOCK_READ, ++ CO_BLOCK_WRITE, ++ CO_BLOCK_CLOSE, ++ CO_BLOCK_GET_ALIAS, ++} co_block_request_type_t; ++ ++typedef enum { ++ CO_NETWORK_GET_MAC=0, ++} co_network_request_type_t; ++ ++#ifdef CO_KERNEL ++/* If we are compiling kernel code (Linux or Host Driver) */ ++# ifdef CO_COLINUX_KERNEL ++/* Inside Linux, vm_ptr_t considered a valid pointer in its virtual address space */ ++typedef void *vm_ptr_t; ++# else ++/* But inside the host, the type is considered not to be a pointer in its own address space */ ++typedef unsigned long vm_ptr_t; ++# endif ++ ++typedef struct { ++ co_block_request_type_t type; ++ long rc; ++ union { ++ struct { ++ unsigned long long offset; ++ unsigned long long size; ++ unsigned long long disk_size; ++ vm_ptr_t address; ++ }; ++ struct { ++ char alias[20]; ++ }; ++ }; ++} __attribute__((packed)) co_block_request_t; ++ ++typedef struct { ++ co_network_request_type_t type; ++ unsigned long unit; ++ char mac_address[6]; ++ char _pad[2]; ++ int result; ++} __attribute__((packed)) co_network_request_t; ++ ++#endif ++ ++#ifndef COLINUX_TRACE ++#define CO_TRACE_STOP ++#define CO_TRACE_CONTINUE ++#endif ++ ++#pragma pack() ++ ++#endif +--- linux-2.4.28/include/linux/major.h~colinux-0.6.1 2003-06-13 10:51:38.000000000 -0400 ++++ linux-2.4.28/include/linux/major.h 2004-11-27 15:59:21.315005648 -0500 +@@ -142,6 +142,7 @@ + #define LVM_CHAR_MAJOR 109 /* Logical Volume Manager */ + + #define UMEM_MAJOR 116 /* http://www.umem.com/ Battery Backed RAM */ ++#define COLINUX_MAJOR 117 + + #define RTF_MAJOR 150 + #define RAW_MAJOR 162 +--- linux-2.4.28/init/do_mounts.c~colinux-0.6.1 2003-11-28 13:26:21.000000000 -0500 ++++ linux-2.4.28/init/do_mounts.c 2004-11-27 15:59:21.316005496 -0500 +@@ -255,6 +255,9 @@ + { "ftld", 0x2c18 }, + { "mtdblock", 0x1f00 }, + { "nb", 0x2b00 }, ++#ifdef CONFIG_COOPERATIVE ++ { "cobd", 0x7500 }, ++#endif + { NULL, 0 } + }; + +--- linux-2.4.28/init/main.c~colinux-0.6.1 2004-11-17 06:54:22.000000000 -0500 ++++ linux-2.4.28/init/main.c 2004-11-27 15:59:21.317005344 -0500 +@@ -74,6 +74,8 @@ + #include <asm/smp.h> + #endif + ++#include <linux/cooperative.h> ++ + /* + * Versions of gcc older than that listed below may actually compile + * and link okay, but the end product can have subtle run time bugs. +@@ -305,7 +307,14 @@ + #ifdef CONFIG_X86_LOCAL_APIC + static void __init smp_init(void) + { ++#ifdef CONFIG_COOPERATIVE ++ /* ++ * It doesn't work yet because I haven't implemented the ++ * timer interrupt yet ++ */ ++#else + APIC_init_uniprocessor(); ++#endif + } + #else + #define smp_init() do { } while (0) +--- linux-2.4.28/kernel/Makefile~colinux-0.6.1 2001-09-17 00:22:40.000000000 -0400 ++++ linux-2.4.28/kernel/Makefile 2004-11-27 15:59:21.317005344 -0500 +@@ -14,7 +14,7 @@ + obj-y = sched.o dma.o fork.o exec_domain.o panic.o printk.o \ + module.o exit.o itimer.o info.o time.o softirq.o resource.o \ + sysctl.o acct.o capability.o ptrace.o timer.o user.o \ +- signal.o sys.o kmod.o context.o ++ signal.o sys.o kmod.o context.o cooperative.o + + obj-$(CONFIG_UID16) += uid16.o + obj-$(CONFIG_MODULES) += ksyms.o +--- /dev/null 2004-04-06 13:56:48.000000000 -0400 ++++ linux-2.4.28/kernel/cooperative.c 2004-11-27 15:59:21.318005192 -0500 +@@ -0,0 +1,337 @@ ++/* ++ * linux/kernel/cooperative.c ++ * ++ * Code for Cooperative mode (coLinux) ++ * ++ * Dan Aloni <da-x@gmx.net>, 2003 (C). ++ * ++ */ ++ ++#include <linux/kernel.h> ++#include <linux/string.h> ++#include <linux/interrupt.h> ++#include <linux/mm.h> ++#include <linux/slab.h> ++#include <linux/cooperative.h> ++ ++CO_TRACE_STOP; ++ ++void start_kernel(void); ++extern char _kernel_start, _end; ++ ++unsigned long co_core_end = 0; ++unsigned long co_memory_size = 0; ++char co_boot_parameters[CO_BOOTPARAM_STRING_LENGTH]; ++ ++void colinux_start_c() ++{ ++ co_core_end = co_passage_page->params[0]; ++ co_memory_size = co_passage_page->params[1]; ++ memcpy(co_boot_parameters, &co_passage_page->params[2], ++ sizeof(co_boot_parameters)); ++ ++ start_kernel(); ++ ++ co_terminate(CO_TERMINATE_END); ++} ++ ++co_message_t *co_send_message_save(unsigned long *flags) ++{ ++ local_irq_save(*flags); ++ co_passage_page->operation = CO_OPERATION_MESSAGE_TO_MONITOR; ++ co_passage_page->params[0] = 1; ++ return (co_message_t *)(&co_passage_page->params[1]); ++} ++ ++void co_send_message_restore(unsigned long flags) ++{ ++ co_switch_wrapper(); ++ local_irq_restore(flags); ++} ++ ++void co_send_message_s(co_message_t *message, char *data) ++{ ++ if ((sizeof(co_message_t) + message->size) < 2000) { ++ co_message_t *params; ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ co_passage_page->operation = CO_OPERATION_MESSAGE_TO_MONITOR; ++ co_passage_page->params[0] = 1; ++ params = (co_message_t *)(&co_passage_page->params[1]); ++ *params = *message; ++ memcpy(params->data, data, message->size); ++ co_switch_wrapper(); ++ local_irq_restore(flags); ++ return; ++ } ++} ++ ++void co_send_message(co_module_t from, ++ co_module_t to, ++ co_priority_t priority, ++ co_message_type_t type, ++ unsigned long size, ++ char *data) ++{ ++ co_message_t params; ++ ++ params.from = from; ++ params.to = to; ++ params.priority = priority; ++ params.type = type; ++ params.size = size; ++ ++ co_send_message_s(¶ms, data); ++} ++ ++void co_receive_message(co_message_t *message) ++{ ++ struct { ++ co_message_t message; ++ co_linux_message_t linux_part; ++ } *linux_message; ++ ++ linux_message = (typeof(linux_message))message; ++ ++ co_handle_device_interrupt(&linux_message->linux_part); ++} ++ ++void co_callback(void) ++{ ++ while (co_passage_page->operation == CO_OPERATION_MESSAGE_FROM_MONITOR) { ++ co_receive_message((co_message_t *)&co_passage_page->params[1]); ++ if (co_passage_page->params[0] == 0) { ++ break; ++ } ++ ++ co_passage_page->operation = CO_OPERATION_MESSAGE_FROM_MONITOR; ++ co_switch_wrapper(); ++ } ++} ++ ++void co_idle_processor(void) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ co_passage_page->operation = CO_OPERATION_IDLE; ++ co_switch_wrapper(); ++ co_callback(); ++ local_irq_restore(flags); ++} ++ ++void co_printk(char *line) ++{ ++ co_send_message(CO_MODULE_LINUX, ++ CO_MODULE_PRINTK, ++ CO_PRIORITY_DISCARDABLE, ++ CO_MESSAGE_TYPE_STRING, ++ strlen(line)+1, ++ line); ++} ++ ++void co_debug_line(char *line) ++{ ++ unsigned long flags; ++ ++ if (!line) ++ return; ++ ++ if (strlen(line) > 0x200) ++ return; ++ ++ local_irq_save(flags); ++ co_passage_page->operation = CO_OPERATION_DEBUG_LINE; ++ strcpy((char *)&co_passage_page->params[0], line); ++ co_switch_wrapper(); ++ local_irq_restore(flags); ++} ++ ++void co_trace_ent_name(void *func, const char *name) ++{ ++ static int reenterent = 0; ++ static int count = 0; ++ static char private_buffer[0x100]; ++ unsigned long flags; ++ ++ if (reenterent) ++ return; ++ ++ reenterent = 1; ++ ++ local_irq_save(flags); ++ count += 1; ++ ++ if (count > 1900000) { ++ snprintf(private_buffer, sizeof(private_buffer), "%d: %d: %x %s\n", count, current->pid, func, name); ++ co_debug_line(private_buffer); ++ } ++ ++ local_irq_restore(flags); ++ ++ reenterent = 0; ++} ++ ++static unsigned long trace_index = 0; ++ ++void co_trace_ent(void *func) ++{ ++ unsigned long flags; ++ co_trace_point_info_t *trace_point; ++ ++ local_irq_save(flags); ++ trace_index++; ++ co_passage_page->operation = CO_OPERATION_TRACE_POINT; ++ trace_point = (co_trace_point_info_t *)&co_passage_page->params[0]; ++ trace_point->pid = 0; ++ if (current) ++ trace_point->pid = current->pid; ++ trace_point->index = trace_index; ++ trace_point->flags = 1; ++ trace_point->func = (unsigned long)(func); ++ co_switch_wrapper(); ++ local_irq_restore(flags); ++} ++ ++void co_trace_ret(void *func) ++{ ++ unsigned long flags; ++ co_trace_point_info_t *trace_point; ++ ++ local_irq_save(flags); ++ trace_index++; ++ co_passage_page->operation = CO_OPERATION_TRACE_POINT; ++ trace_point = (co_trace_point_info_t *)&co_passage_page->params[0]; ++ trace_point->pid = 0; ++ if (current) ++ trace_point->pid = current->pid; ++ trace_point->index = trace_index; ++ trace_point->flags = 0; ++ trace_point->func = (unsigned long)(func); ++ co_switch_wrapper(); ++ local_irq_restore(flags); ++} ++ ++void co_debug(const char *fmt, ...) ++{ ++ static char co_buf[1024]; ++ unsigned long flags; ++ va_list args; ++ ++ local_irq_save(flags); ++ va_start(args, fmt); ++ vsnprintf(co_buf, sizeof(co_buf), fmt, args); ++ va_end(args); ++ co_debug_line(co_buf); ++ local_irq_restore(flags); ++} ++ ++void co_terminate(co_termination_reason_t reason) ++{ ++ unsigned long flags; ++ ++ local_irq_save(flags); ++ co_passage_page->operation = CO_OPERATION_TERMINATE; ++ co_passage_page->params[0] = reason; ++ co_switch_wrapper(); ++ local_irq_restore(flags); ++} ++ ++unsigned long co_get_host_time(void) ++{ ++ unsigned long flags; ++ unsigned long time; ++ ++ local_irq_save(flags); ++ co_passage_page->operation = CO_OPERATION_GET_TIME; ++ co_switch_wrapper(); ++ time = co_passage_page->params[0]; ++ local_irq_restore(flags); ++ ++ return time; ++} ++ ++typedef struct { ++ struct list_head node; ++ co_linux_message_t msg; ++} co_linux_message_node_t; ++ ++typedef struct { ++ struct list_head list; ++ int num_messages; ++} co_linux_message_queue_t; ++ ++co_linux_message_queue_t *co_msgqueues = NULL; ++ ++void co_received_message(co_linux_message_t *message) ++{ ++ co_linux_message_node_t *copy; ++ co_linux_message_queue_t *queue; ++ ++ if (!co_msgqueues) ++ return; ++ ++ if (message->device < 0 || (message->device >= CO_DEVICES_TOTAL)) ++ return; ++ ++ copy = (co_linux_message_node_t *)kmalloc(sizeof(co_linux_message_node_t) + message->size, GFP_ATOMIC); ++ if (!copy) ++ return; ++ ++ queue = &co_msgqueues[message->device]; ++ memcpy(©->msg, message, sizeof(co_linux_message_t) + message->size); ++ list_add(©->node, &queue->list); ++ queue->num_messages++; ++} ++ ++static int __init initcall_message_queues(void) ++{ ++ int queue_index; ++ ++ co_msgqueues = kmalloc(sizeof(co_linux_message_queue_t) * CO_DEVICES_TOTAL, GFP_KERNEL); ++ if (!co_msgqueues) { ++ panic("Unable to allocate message queues\n"); ++ } ++ ++ for (queue_index=0; queue_index < CO_DEVICES_TOTAL; queue_index++) { ++ co_linux_message_queue_t *queue = &co_msgqueues[queue_index]; ++ queue->num_messages = 0; ++ INIT_LIST_HEAD(&queue->list); ++ } ++ ++ return 0; ++} ++ ++__initcall(initcall_message_queues); ++ ++int co_get_message(co_linux_message_t **message, co_device_t device) ++{ ++ co_linux_message_queue_t *queue; ++ co_linux_message_node_t *node; ++ ++ if (!co_msgqueues) ++ return 0; ++ ++ queue = &co_msgqueues[device]; ++ if (list_empty(&queue->list)) ++ return 0; ++ ++ node = list_entry(queue->list.prev, co_linux_message_node_t, node); ++ list_del(&node->node); ++ queue->num_messages--; ++ *message = &node->msg; ++ return 1; ++} ++ ++void co_free_message(co_linux_message_t *message) ++{ ++ co_linux_message_node_t *node = NULL; ++ ++ node = (co_linux_message_node_t *)(((char *)message) - ((long)&node->msg)); ++ ++ kfree(node); ++} ++ ++ ++CO_TRACE_CONTINUE; +--- linux-2.4.28/kernel/panic.c~colinux-0.6.1 2004-11-17 06:54:22.000000000 -0500 ++++ linux-2.4.28/kernel/panic.c 2004-11-27 15:59:21.318005192 -0500 +@@ -18,6 +18,8 @@ + #include <linux/interrupt.h> + #include <linux/console.h> + ++#include <linux/cooperative.h> ++ + asmlinkage void sys_sync(void); /* it's really int */ + + int panic_timeout; +@@ -70,6 +72,8 @@ + sys_sync(); + bust_spinlocks(0); + ++ co_terminate(CO_TERMINATE_PANIC); ++ + #ifdef CONFIG_SMP + smp_send_stop(); + #endif +--- linux-2.4.28/kernel/printk.c~colinux-0.6.1 2004-11-17 06:54:22.000000000 -0500 ++++ linux-2.4.28/kernel/printk.c 2004-11-27 15:59:21.319005040 -0500 +@@ -29,6 +29,8 @@ + + #include <asm/uaccess.h> + ++#include <linux/cooperative.h> ++ + #if !defined(CONFIG_LOG_BUF_SHIFT) || (CONFIG_LOG_BUF_SHIFT == 0) + #if defined(CONFIG_MULTIQUAD) || defined(CONFIG_IA64) + #define LOG_BUF_LEN (65536) +@@ -433,6 +435,9 @@ + printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args); + va_end(args); + ++#ifdef CONFIG_COOPERATIVE ++ co_printk(printk_buf); ++#endif + /* + * Copy the output into log_buf. If the caller didn't provide + * appropriate log level tags, we insert them here +@@ -459,6 +464,7 @@ + spin_unlock_irqrestore(&logbuf_lock, flags); + goto out; + } ++ + if (!down_trylock(&console_sem)) { + /* + * We own the drivers. We can drop the spinlock and let |