changeset 38:e7ba79f6d3a8 ecos-sw-1999-09-23

Merge from eCos master repository on 1999-09-23-20:10:25-BST
author jlarmour
date Thu, 23 Sep 1999 19:52:27 +0000
parents 0b25345c9c69
children 542bd7fab9d0
files packages/hal/arm/arch/current/ChangeLog packages/hal/arm/arch/current/include/arm_stub.h packages/hal/arm/arch/current/include/hal_arch.h packages/hal/arm/arch/current/src/arm.ld packages/hal/arm/arch/current/src/arm_stub.c packages/hal/arm/arch/current/src/context.S packages/hal/arm/arch/current/src/hal_misc.c packages/hal/arm/arch/current/src/vectors.S packages/hal/arm/cl7211/current/ChangeLog packages/hal/arm/cl7211/current/images/gdb_module.bin packages/hal/arm/cl7211/current/include/pkgconf/mlt_arm_eb7211_ram.ldi packages/hal/arm/cl7211/current/include/pkgconf/mlt_arm_eb7211_ram.mlt packages/hal/arm/cl7211/current/misc/kbd_support.c packages/hal/arm/cl7211/current/misc/kbd_test.c packages/hal/arm/cl7211/current/misc/lcd_panel_support.c packages/hal/arm/cl7211/current/misc/lcd_support.c packages/hal/arm/cl7211/current/misc/panel_test.c packages/hal/arm/cl7211/current/src/cl7211_misc.c packages/hal/arm/cl7211/current/src/hal_diag.c packages/hal/arm/cl7211/current/src/plf_stub.c packages/hal/arm/cl7211/current/support/Makefile packages/hal/arm/cl7211/current/support/download_file.c packages/hal/common/current/ChangeLog packages/hal/common/current/include/pkgconf/hal.h packages/hal/common/current/src/generic-stub.c packages/hal/common/current/src/hal_stub.c packages/hal/common/current/src/thread-packets.c packages/hal/mips/arch/current/ChangeLog packages/hal/mips/arch/current/src/hal_misc.c packages/hal/mips/arch/current/src/vectors.S packages/hal/mips/tx39/current/ChangeLog packages/hal/mips/tx39/current/include/var_arch.h packages/hal/mips/tx39/current/include/variant.inc packages/hal/mips/tx39/current/src/hal_diag.c packages/hal/powerpc/arch/current/ChangeLog packages/hal/powerpc/arch/current/include/hal_cache.h packages/hal/powerpc/arch/current/src/hal_misc.c packages/hal/powerpc/arch/current/src/vectors.S packages/hal/powerpc/mbx/current/ChangeLog packages/hal/powerpc/mbx/current/include/pkgconf/hal_powerpc_mbx.h packages/hal/powerpc/mbx/current/misc/stubrom.perm packages/hal/powerpc/mbx/current/src/mbx.S packages/hal/powerpc/sim/current/ChangeLog packages/hal/powerpc/sim/current/runtime/tree packages/io/serial/current/src/PKGconf.mak packages/kernel/current/ChangeLog packages/kernel/current/src/common/kapi.cxx packages/kernel/current/src/intr/intr.cxx packages/kernel/current/tests/stress_threads.c packages/kernel/current/tests/tm_basic.cxx packages/language/c/libc/current/ChangeLog packages/language/c/libc/current/tests/signal/signal2.c
diffstat 52 files changed, 1924 insertions(+), 654 deletions(-) [+]
line wrap: on
line diff
--- a/packages/hal/arm/arch/current/ChangeLog
+++ b/packages/hal/arm/arch/current/ChangeLog
@@ -1,3 +1,26 @@
+1999-09-21  Gary Thomas  <gthomas@cygnus.co.uk>
+
+	* include/hal_arch.h: Remove FIXME about GDB register layout.
+
+	* src/context.S (hal_thread_save_context): Change function prologue
+	to match APCS more closely (keeps GDB happier).
+
+1999-09-19  Gary Thomas  <gthomas@cygnus.co.uk>
+
+	* src/vectors.S (spurious_IRQ): Make sure interrupts are masked
+	when switching to IRQ mode.
+
+	* src/hal_misc.c (exception_handler): GDB stubs only take over
+	memory exceptions.  This allows proper handling when an application
+	has it's own IRQ/FIQ VSR.
+
+1999-09-13  Gary Thomas  <gthomas@cygnus.co.uk>
+
+	* src/vectors.S (handle_IRQ_or_FIQ): Allow spurious interrupts
+	to be ignored.  Some platforms (CL7xxx) have non-debounced 
+	interrupt sources which can vanish before the hardware can be
+	queried.
+
 1999-09-11  Jonathan Larmour  <jlarmour@cygnus.co.uk>
 
 	* src/arm_stub.c (__computeSignal): Synchronise return value with
--- a/packages/hal/arm/arch/current/include/arm_stub.h
+++ b/packages/hal/arm/arch/current/include/arm_stub.h
@@ -34,6 +34,9 @@ enum regnames {
 #define PS_C 0x20000000
 #define PS_V 0x10000000
 
+#define PS_I CPSR_IRQ_DISABLE
+#define PS_F CPSR_FIQ_DISABLE
+
 typedef enum regnames regnames_t;
 
 /* Given a trap value TRAP, return the corresponding signal. */
--- a/packages/hal/arm/arch/current/include/hal_arch.h
+++ b/packages/hal/arm/arch/current/include/hal_arch.h
@@ -184,8 +184,6 @@ asm volatile (" .globl  " #_label_ ";"  
 //--------------------------------------------------------------------------
 // Thread register state manipulation for GDB support.
 
-// FIX ME!!  What does GDB expect?
-
 // GDB expects the registers in this structure:
 //   r0..r10, fp, ip, sp, lr, pc  - 4 bytes each
 //   f0..f7                       - 12 bytes each (N/A on ARM7)
--- a/packages/hal/arm/arch/current/src/arm.ld
+++ b/packages/hal/arm/arch/current/src/arm.ld
@@ -61,7 +61,7 @@ GROUP(libtarget.a libgcc.a)
     .text _vma_ : _lma_ \
     { stext = ABSOLUTE(.); \
     PROVIDE (__stext = ABSOLUTE(.)); \
-    *(.text*) *(.gnu.warning) *(.gnu.linkonce*) *(.init) } \
+    *(.text*) *(.gnu.warning) *(.gnu.linkonce*) *(.init) }\
     > _region_ \
     etext = .; PROVIDE (__etext = .);
 
--- a/packages/hal/arm/arch/current/src/arm_stub.c
+++ b/packages/hal/arm/arch/current/src/arm_stub.c
@@ -58,7 +58,6 @@ int __computeSignal (unsigned int trap_n
 
 
 /* Return the trap number corresponding to the last-taken trap. */
-volatile int jifl;
 int __get_trap_number (void)
 {
     // The vector is not not part of the GDB register set so get it
--- a/packages/hal/arm/arch/current/src/context.S
+++ b/packages/hal/arm/arch/current/src/context.S
@@ -67,8 +67,8 @@ name:
 	
 FUNC_START(hal_thread_switch_context)
 	mov	ip,sp			// saved stack pointer
-	sub	sp,sp,#ARMREG_SIZE	// make space for saved registers
-	stmea	sp,{r0-r10,fp,ip,lr,pc}
+        stmfd   sp!,{fp,ip,lr,pc}       // filler
+	stmfd	sp!,{r0-r10,fp,ip,lr,pc}
 	mrs	r2,cpsr
 	str	r2,[sp,#armreg_cpsr]
 	str	sp,[r1]			// return new stack pointer
@@ -90,8 +90,8 @@ FUNC_START(hal_thread_load_context)
 	msr	cpsr,r0
 	ldr	r0,[fp,#armreg_cpsr]
 	msr	spsr,r0
-	ldmfd	fp,{r0-r10,fp,sp,lr}	// also restores saved PSR
-	movs	pc,lr
+	ldmfd	fp,{r0-r10,fp,sp,lr}
+	movs	pc,lr	                // also restores saved PSR
 
 // ------------------------------------------------------------------------------
 //  HAL longjmp, setjmp implementations
--- a/packages/hal/arm/arch/current/src/hal_misc.c
+++ b/packages/hal/arm/arch/current/src/hal_misc.c
@@ -70,6 +70,8 @@ extern void *__mem_fault_handler;
    processing is underway.  The only vector that can't be handled this way
    is the illegal instruction vector which is used for breakpoint/single-step
    and must be maintained by the stubs at all times.
+   Note: the interrupt vectors are _not_ preempted as the stubs probably can't
+   handle them properly.
 */
 
 #define ARM_VECTORS 8
@@ -82,20 +84,17 @@ static int exception_level;
 static void
 __take_over_debug_traps(void)
 {
-    int i;
-    for (i = 0;  i < ARM_VECTORS;  i++) {
-        hold_vectors[i] = hardware_vectors[i];
-        hardware_vectors[i] = vectors[i];
-    }
+    hold_vectors[CYGNUM_HAL_VECTOR_ABORT_PREFETCH] = hardware_vectors[CYGNUM_HAL_VECTOR_ABORT_PREFETCH];
+    hardware_vectors[CYGNUM_HAL_VECTOR_ABORT_PREFETCH] = vectors[CYGNUM_HAL_VECTOR_ABORT_PREFETCH];
+    hold_vectors[CYGNUM_HAL_VECTOR_ABORT_DATA] = hardware_vectors[CYGNUM_HAL_VECTOR_ABORT_DATA];
+    hardware_vectors[CYGNUM_HAL_VECTOR_ABORT_DATA] = vectors[CYGNUM_HAL_VECTOR_ABORT_DATA];
 }
 
 static void
 __restore_debug_traps(void)
 {
-    int i;
-    for (i = 0;  i < ARM_VECTORS;  i++) {
-        hardware_vectors[i] = hold_vectors[i];
-    }
+    hardware_vectors[CYGNUM_HAL_VECTOR_ABORT_PREFETCH] = hold_vectors[CYGNUM_HAL_VECTOR_ABORT_PREFETCH];
+    hardware_vectors[CYGNUM_HAL_VECTOR_ABORT_DATA] = hold_vectors[CYGNUM_HAL_VECTOR_ABORT_DATA];
 }
 #endif
 
@@ -114,15 +113,15 @@ exception_handler(HAL_SavedRegisters *re
     _hal_registers = regs;
     __handle_exception();
 
+    if (--exception_level == 0) __restore_debug_traps();
+
+#elif defined(CYGPKG_KERNEL_EXCEPTIONS)
+
     // We should decode the vector and pass a more appropriate
     // value as the second argument. For now we simply pass a
     // pointer to the saved registers. We should also divert
     // breakpoint and other debug vectors into the debug stubs.
 
-    if (--exception_level == 0) __restore_debug_traps();
-
-#elif defined(CYGPKG_KERNEL_EXCEPTIONS)
-
     cyg_hal_deliver_exception( regs->vector, (CYG_ADDRWORD)regs );
 
 #else
--- a/packages/hal/arm/arch/current/src/vectors.S
+++ b/packages/hal/arm/arch/current/src/vectors.S
@@ -480,7 +480,12 @@ call_exception_handler:
 
 	mrs	r0,cpsr			// move back to IRQ mode
 	bic	r0,r0,#CPSR_MODE_BITS
-	orr	r0,r0,#CPSR_IRQ_MODE
+	orr	r0,r0,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE
+	msr	cpsr,r0
+        nop
+        nop
+
+       	orr	r0,r0,#CPSR_IRQ_MODE
 	msr	cpsr,r0
 
 	mov	sp,ip
@@ -578,6 +583,10 @@ 10:
 #endif
 
 	mov	r0,v1			// vector #
+#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS	
+        cmp     r0,#0                   // ignore spurious interrupts
+        beq     spurious_IRQ
+#endif // CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS        
 	ldr	r1,.hal_interrupt_data
 	ldr	r1,[r1,v1,lsl #2]	// handler data
 	ldr	r2,.hal_interrupt_handlers
@@ -588,6 +597,10 @@ 10:
 	mov	lr,pc			// invoke handler (call indirect
 	mov	pc,v3                   // thru v3)
 
+#ifdef CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS	
+spurious_IRQ:           
+#endif // CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS	
+
 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_USE_INTERRUPT_STACK
 	// If we are returning from the last nested interrupt, move back
 	// to the thread stack. interrupt_end() must be called on the
@@ -620,6 +633,11 @@ 10:
 	ldr	sp,[sp,#armreg_sp]
 
 	mrs	r0,cpsr			// move back to IRQ mode
+	orr	r0,r0,#CPSR_IRQ_DISABLE|CPSR_FIQ_DISABLE
+	msr	cpsr,r0
+        nop
+        nop
+        
 	bic	r0,r0,#CPSR_MODE_BITS
 	orr	r0,r0,#CPSR_IRQ_MODE
 	msr	cpsr,r0
--- a/packages/hal/arm/cl7211/current/ChangeLog
+++ b/packages/hal/arm/cl7211/current/ChangeLog
@@ -1,3 +1,29 @@
+1999-09-15  Gary Thomas  <gthomas@cygnus.co.uk>
+
+	* misc/nand_test.c (nand_exercise): Check "read ID" function.
+
+	* misc/lcd_panel_support.c (lcd_panel_server): Reorg sampling
+	loop to use a weighted average (try and avoid bad results).
+
+	* misc/kbd_test.c (kbd_exercise): Use new kbd_getc() function.
+
+	* misc/kbd_support.c (kbd_getc): New function.
+
+	* misc/lcd_support.c: Add simple printf() code. 
+
+1999-09-13  Gary Thomas  <gthomas@cygnus.co.uk>
+
+	* include/pkgconf/mlt_arm_eb7211_ram.ldi: 
+	* include/pkgconf/mlt_arm_eb7211_ram.mlt: Fix DRAM limits.
+
+1999-09-12  Gary Thomas  <gthomas@cygnus.co.uk>
+
+	* misc/kbd_support.c: New file.  Also change to more or less
+	ignore interrupts since they don't work for many keys!
+
+	* misc/kbd_test.c: Move keyboard support routines to separate
+	file.
+
 1999-09-10  Gary Thomas  <gthomas@cygnus.co.uk>
 
 	* include/hal_platform_setup.h: Fix spelling error.
index 54384e59563b3a0492f0e638a3e00cb1fcfe06c4..2c7a2a184b51637e191c514dccbddc5fba971895
GIT binary patch
literal 16068
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
Q!}qee$C&-M<woKBZ|qPLBLDyZ
--- a/packages/hal/arm/cl7211/current/include/pkgconf/mlt_arm_eb7211_ram.ldi
+++ b/packages/hal/arm/cl7211/current/include/pkgconf/mlt_arm_eb7211_ram.ldi
@@ -32,7 +32,7 @@
 
 MEMORY
 {
-    ram : ORIGIN = 0x8000, LENGTH = 0x1b8000
+    ram : ORIGIN = 0x8000, LENGTH = 0x00FF8000
 }
 
 SECTIONS
--- a/packages/hal/arm/cl7211/current/include/pkgconf/mlt_arm_eb7211_ram.mlt
+++ b/packages/hal/arm/cl7211/current/include/pkgconf/mlt_arm_eb7211_ram.mlt
@@ -1,5 +1,5 @@
 version 0
-region ram 8000 1b8000 0 !
+region ram 8000 ff8000 0 !
 section rom_vectors 0 1 0 1 1 1 1 1 8000 8000 text text !
 section text 0 1 0 1 0 1 0 1 fini fini !
 section fini 0 1 0 1 0 1 0 1 rodata rodata !
new file mode 100644
--- /dev/null
+++ b/packages/hal/arm/cl7211/current/misc/kbd_support.c
@@ -0,0 +1,455 @@
+//==========================================================================
+//
+//        kbd_support.c
+//
+//        Cirrus CL72xx eval board ASCII keyboard support functions
+//
+//==========================================================================
+//####COPYRIGHTBEGIN####
+//
+// -------------------------------------------
+// The contents of this file are subject to the Cygnus eCos Public License
+// Version 1.0 (the "License"); you may not use this file except in
+// compliance with the License.  You may obtain a copy of the License at
+// http://sourceware.cygnus.com/ecos
+// 
+// Software distributed under the License is distributed on an "AS IS"
+// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the
+// License for the specific language governing rights and limitations under
+// the License.
+// 
+// The Original Code is eCos - Embedded Cygnus Operating System, released
+// September 30, 1998.
+// 
+// The Initial Developer of the Original Code is Cygnus.  Portions created
+// by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions.  All Rights Reserved.
+// -------------------------------------------
+//
+//####COPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     gthomas
+// Contributors:  gthomas
+// Date:          1999-05-15
+// Description:   Functions used to support ASCII keyboard
+//####DESCRIPTIONEND####
+
+static char kbd_server_stack[STACK_SIZE];
+static cyg_thread kbd_server_thread_data;
+static cyg_handle_t kbd_server_thread_handle;
+
+static cyg_interrupt kbd_interrupt;
+static cyg_handle_t  kbd_interrupt_handle;
+
+static cyg_mbox      kbd_events_mbox;
+static cyg_handle_t  kbd_events_mbox_handle;
+static cyg_sem_t     kbd_sem;
+
+static cyg_uint8 col_state[8];
+static cyg_uint8 ext_state[8];
+
+static void
+kbd_delay(void)
+{
+    volatile int i;
+    for (i = 0;  i < 250;  i++) ;
+}
+
+static void
+kbd_scan(void)
+{
+    int i;
+    cyg_uint8 port_data, ext_data;
+    // Turn off drive (de-select) all columns
+    *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) |
+        SYSCON1_KBD_LOW;
+    for (i = 0;  i < 8;  i++) {
+        // Select column 'i'
+        *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) |
+            SYSCON1_KBD_COL(i);
+        // Small pause to let the wires charge up :-)
+        kbd_delay();
+        // Grab the data
+        col_state[i] = port_data = *(volatile cyg_uint8 *)PADR;
+        ext_state[i] = ext_data = *(volatile cyg_uint8 *)KBD_PORT;
+        // De-Select column 'i'
+        *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) |
+            SYSCON1_KBD_TRISTATE;
+        // Allow line to gl slack
+        kbd_delay();
+    }
+    // Turn on drive (select) all columns - necessary to see interrupts
+    *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) |
+        SYSCON1_KBD_HIGH;
+}
+
+static cyg_uint8     kbd_state[128];      // Known state of each key
+static cyg_uint8     kbd_new_state[128];  // Current state of each key
+
+// Row #1
+#define KBD_Escape     0x00
+#define KBD_F1         0x01
+#define KBD_F2         0x02
+#define KBD_F3         0x03
+#define KBD_F4         0x04
+#define KBD_F5         0x05
+#define KBD_F6         0x06
+#define KBD_F7         0x07
+#define KBD_F8         0x08
+#define KBD_F9         0x09
+#define KBD_F10        0x0A
+#define KBD_NumLock    0x0B
+#define KBD_SysReq     0x0C
+#define KBD_ScrlLock   0x0D
+#define KBD_Break      0x0E
+// Row #2
+#define KBD_1          0x10
+#define KBD_2          0x11
+#define KBD_3          0x12
+#define KBD_4          0x13
+#define KBD_5          0x14
+#define KBD_6          0x15
+#define KBD_7          0x16
+#define KBD_8          0x17
+#define KBD_9          0x18
+#define KBD_0          0x19
+#define KBD_Hyphen     0x1A
+#define KBD_Equals     0x1B
+#define KBD_BackSpace  0x1C
+#define KBD_Home       0x1D
+// Row #3
+#define KBD_Tab        0x20
+#define KBD_Q          0x21
+#define KBD_W          0x22
+#define KBD_E          0x23
+#define KBD_R          0x24
+#define KBD_T          0x25
+#define KBD_Y          0x26
+#define KBD_U          0x27
+#define KBD_I          0x28
+#define KBD_O          0x29
+#define KBD_P          0x2A
+#define KBD_LeftBrkt   0x2B
+#define KBD_RightBrkt  0x2C
+#define KBD_BackSlash  0x2D
+#define KBD_PageUp     0x2E
+// Row #4
+#define KBD_CapsLock   0x30
+#define KBD_A          0x31
+#define KBD_S          0x32
+#define KBD_D          0x33
+#define KBD_F          0x34
+#define KBD_G          0x35
+#define KBD_H          0x36
+#define KBD_J          0x37
+#define KBD_K          0x38
+#define KBD_L          0x39
+#define KBD_SemiColon  0x3A
+#define KBD_Quote      0x3B
+#define KBD_Enter      0x3C
+#define KBD_PageDown   0x3D
+// Row #5
+#define KBD_LeftShift  0x40
+#define KBD_Z          0x41
+#define KBD_X          0x42
+#define KBD_C          0x43
+#define KBD_V          0x44
+#define KBD_B          0x45
+#define KBD_N          0x46
+#define KBD_M          0x47
+#define KBD_Comma      0x48
+#define KBD_Period     0x49
+#define KBD_Slash      0x4A
+#define KBD_RightShift 0x4B
+#define KBD_UpArrow    0x4C
+#define KBD_End        0x4D
+// Row #6
+#define KBD_Ctrl       0x50
+#define KBD_Function   0x51
+#define KBD_LeftAlt    0x52
+#define KBD_Accent     0x53
+#define KBD_Space      0x54
+#define KBD_RightAlt   0x55
+#define KBD_Ins        0x56
+#define KBD_Del        0x57
+#define KBD_LeftArrow  0x58
+#define KBD_DownArrow  0x59
+#define KBD_RightArrow 0x5A
+
+#define KBD_Press      0x80  // Event has this bit when the key is pressed
+#define KBD_Empty      0xFF
+
+// Map column, bit -> keycode
+static cyg_uint32    kbd_map[8][16] = {
+    // Column #0
+    {KBD_Escape,    KBD_1,          KBD_Tab,        KBD_CapsLock,
+     KBD_BackSlash, KBD_Space,      KBD_LeftArrow,  KBD_UpArrow,
+     KBD_DownArrow, KBD_RightArrow, KBD_LeftShift,  KBD_Ctrl, 
+     KBD_Function,  KBD_LeftAlt,    KBD_RightAlt,   KBD_RightShift },
+    // Column #1
+    {KBD_F5,        KBD_6,          KBD_T,          KBD_G,  
+     KBD_B,         KBD_Slash,      KBD_SemiColon,  KBD_P,  
+     KBD_Hyphen,    KBD_F10,        KBD_Empty,      KBD_Empty,
+     KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty     },
+    // Column #2
+    {KBD_F4,        KBD_5,          KBD_R,          KBD_F,  
+     KBD_V,         KBD_Del,        KBD_Quote,      KBD_LeftBrkt,  
+     KBD_Equals,    KBD_NumLock,    KBD_Empty,      KBD_Empty,
+     KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty },
+    // Column #3
+    {KBD_F3,        KBD_4,          KBD_E,          KBD_D,  
+     KBD_C,         KBD_Ins,        KBD_Empty,      KBD_RightBrkt,  
+     KBD_BackSpace, KBD_SysReq,     KBD_Empty,      KBD_Empty,
+     KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty },
+    // Column #4
+    {KBD_F2,        KBD_3,          KBD_W,          KBD_S,  
+     KBD_X,         KBD_Empty,      KBD_Enter,      KBD_Empty,
+     KBD_Empty,     KBD_ScrlLock,   KBD_Empty,      KBD_Empty,
+     KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty },
+    // Column #5
+    {KBD_F1,        KBD_2,          KBD_Q,          KBD_A,  
+     KBD_Z,         KBD_End,        KBD_PageDown,   KBD_PageUp,
+     KBD_Home,      KBD_Break,      KBD_Empty,      KBD_Empty,
+     KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty },
+    // Column #6
+    {KBD_F6,        KBD_7,          KBD_Y,          KBD_H,  
+     KBD_N,         KBD_Period,     KBD_L,          KBD_O,  
+     KBD_0,         KBD_F9,         KBD_Empty,      KBD_Empty,
+     KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty },
+    // Column #7
+    {KBD_F7,        KBD_8,          KBD_U,          KBD_J,  
+     KBD_M,         KBD_Comma,      KBD_K,          KBD_I,  
+     KBD_9,         KBD_F8,         KBD_Empty,      KBD_Empty,
+     KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty },
+};
+
+static cyg_uint8 kbd_chars[96] = {
+    /* 0x00 - 0x0F */
+    0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    /* 0x10 - 0x1F */
+     '1',  '2',  '3',  '4',  '5',  '6',  '7',  '8',  '9',  '0',  '-',  '=', 0x08, 0x00, 0x00, 0x00,
+    /* 0x20 - 0x2F */
+    '\t',  'q',  'w',  'e',  'r',  't',  'y',  'u',  'i',  'o',  'p',  '[',  ']', '\\', 0x00, 0x00,
+    /* 0x30 - 0x3F */
+    0x00,  'a',  's',  'd',  'f',  'g',  'h',  'j',  'k',  'l',  ';', '\'', 0x0D, 0x00, 0x00, 0x00,
+    /* 0x40 - 0x4F */
+    0x00,  'z',  'x',  'c',  'v',  'b',  'n',  'm',  ',',  '.',  '/', 0x00, 0x00, 0x00, 0x00, 0x00,
+    /* 0x50 - 0x5F */
+    0x00, 0x00, 0x00, 0x00,  ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static cyg_uint8 kbd_shifted_chars[96] = {
+    /* 0x00 - 0x0F */
+    '\b', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    /* 0x10 - 0x1F */
+     '!',  '@',  '#',  '$',  '%',  '^',  '&',  '*',  '(',  ')',  '_',  '+', 0x08, 0x00, 0x00, 0x00,
+    /* 0x20 - 0x2F */
+    '\t',  'Q',  'W',  'E',  'R',  'T',  'Y',  'U',  'I',  'O',  'P',  '{',  '}',  '|', 0x00, 0x00,
+    /* 0x30 - 0x3F */
+    0x00,  'A',  'S',  'D',  'F',  'G',  'H',  'J',  'K',  'L',  ':',  '"', 0x0D, 0x00, 0x00, 0x00,
+    /* 0x40 - 0x4F */
+    0x00,  'Z',  'X',  'C',  'V',  'B',  'N',  'M',  '<',  '>',  '?', 0x00, 0x00, 0x00, 0x00, 0x00,
+    /* 0x50 - 0x5F */
+    0x00, 0x00, 0x00, 0x00,  ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+// This ISR is called when the keyboard interrupt occurs
+static int
+keyboard_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs)
+{
+    cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_KBDINT);
+    return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR
+}
+
+// This DSR handles the keyboard [logical] processing
+static void
+keyboard_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
+{
+    // Tell the keyboard processing thread to give it a shot
+    cyg_semaphore_post(&kbd_sem);
+}
+
+static void
+kbd_server(cyg_addrword_t p)
+{
+    int col, bit, key, event, timeout;
+    diag_printf("KBD server here\n");
+    while (TRUE) {
+        cyg_semaphore_wait(&kbd_sem);
+        // As long as keys are pressed, scan and update
+        timeout = 0;
+        while (TRUE) {
+            // Wait for 20ms - time to debounce keyboard
+            cyg_thread_delay(2);
+            // Scan keyboard
+            kbd_scan();
+            // Reset state
+            for (key = 0;  key < sizeof(kbd_new_state);  key++) {
+                kbd_new_state[key] = 0;
+            }
+            // Check state of all keys and send events for those that change
+            for (col = 0;  col < 8;  col++) {
+                for (bit = 0;  bit < 8;  bit++) {
+                    if (col_state[col] & (1<<bit)) {
+                        key = kbd_map[col][bit];
+                        if (key != KBD_Empty) {
+                            kbd_new_state[key] = 1;
+                        }
+                    }
+                    if (ext_state[col] & (1<<bit)) {
+                        key = kbd_map[col][bit+8];
+                        if (key != KBD_Empty) {
+                            kbd_new_state[key] = 1;
+                        }
+                    }
+                }
+            }
+            // Compare new and old (known) states, generate events for changes
+            // Send events for modifier keys first.
+            for (key = 0;  key < sizeof(kbd_new_state);  key++) {
+                if (kbd_state[key] != kbd_new_state[key]) {
+                    event = 0xFF;
+                    switch (key) {
+                    case KBD_LeftShift:
+                    case KBD_RightShift:
+                    case KBD_Ctrl:
+                    case KBD_LeftAlt:
+                    case KBD_RightAlt:
+                    case KBD_Function:
+                    case KBD_CapsLock:
+                        if (kbd_state[key]) {
+                            // Key going up
+                            event = key;
+                        } else {
+                            // Key going down
+                            event = key + KBD_Press;
+                        }
+                        kbd_state[key] = kbd_new_state[key];
+                    }
+                    if (event != 0xFF) {
+                        if (!cyg_mbox_tryput(kbd_events_mbox_handle, (void *)event)) {
+                            diag_printf("KBD event lost: %x\n", event);
+                        }
+                    }
+                }
+            }
+            // First key up events
+            for (key = 0;  key < sizeof(kbd_new_state);  key++) {
+                if (kbd_state[key] != kbd_new_state[key]) {
+                    if (kbd_state[key]) {
+                        // Key going up
+                        event = key;
+                    } else {
+                        // Key going down
+                        event = key + KBD_Press;
+                    }
+                    if (!cyg_mbox_tryput(kbd_events_mbox_handle, (void *)event)) {
+                        diag_printf("KBD event lost: %x\n", event);
+                    }
+                }
+                kbd_state[key] = kbd_new_state[key];
+            }
+            // Clear interrupt (true when keys are pressed)
+            cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_KBDINT);
+#if 0
+            if (*(volatile cyg_uint32 *)INTSR2 & INTSR2_KBDINT) {
+                timeout = 0;
+            } else if (++timeout == 5) {
+                // No keys for 100ms
+                break;
+            }
+#endif
+        }
+        // Allow interrupts to happen again
+        cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_KBDINT);
+        cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_KBDINT);
+    }
+}
+
+void
+kbd_init(void)
+{
+    // Initialize environment, setup interrupt handler
+    cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_KBDINT,
+                             99,                     // Priority - what goes here?
+                             0,                      //  Data item passed to interrupt handler
+                             (cyg_ISR_t *)keyboard_isr,
+                             (cyg_DSR_t *)keyboard_dsr,
+                             &kbd_interrupt_handle,
+                             &kbd_interrupt);
+    cyg_drv_interrupt_attach(kbd_interrupt_handle);
+    cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_KBDINT);
+    cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_KBDINT);
+    // Set up the mbox for keyboard data
+    cyg_mbox_create(&kbd_events_mbox_handle, &kbd_events_mbox);
+    // This semaphore is set when there is a keypress
+    cyg_semaphore_init(&kbd_sem, 0);  
+    // Create a thread whose job it is to de-bounce the keyboard and
+    // actually process the input, turning it into a series of events
+    cyg_thread_create(10,                           // Priority - just a number
+                      kbd_server,                   // entry
+                      0,                            // initial parameter
+                      "KBD_server",                 // Name
+                      &kbd_server_stack[0],         // Stack
+                      STACK_SIZE,                   // Size
+                      &kbd_server_thread_handle,    // Handle
+                      &kbd_server_thread_data       // Thread data structure
+            );
+    cyg_thread_resume(kbd_server_thread_handle);  // Start it
+}
+
+#define MOD_Shift    0x40
+#define MOD_Ctrl     0x20
+#define MOD_CapsLock 0x10
+static cyg_uint32    kbd_modifiers;
+
+cyg_uint8 
+kbd_getc(void)
+{
+    cyg_uint8 ch;
+    cyg_uint32 kbd_event;
+    while (TRUE) {
+        kbd_event = (cyg_uint32)cyg_mbox_get(kbd_events_mbox_handle);
+        switch (kbd_event & 0x7F) {
+        case KBD_LeftShift:
+        case KBD_RightShift:
+            if (kbd_event & KBD_Press) {
+                kbd_modifiers |= MOD_Shift;
+            } else {
+                kbd_modifiers &= ~MOD_Shift;
+            }
+            break;
+        case KBD_Ctrl:
+            if (kbd_event & KBD_Press) {
+                kbd_modifiers |= MOD_Ctrl;
+            } else {
+                kbd_modifiers &= ~MOD_Ctrl;
+            }
+            break;
+        case KBD_CapsLock:
+            if (kbd_event & KBD_Press) {                
+                kbd_modifiers ^= MOD_CapsLock;
+            }
+            break;
+        case KBD_LeftAlt:
+        case KBD_RightAlt:
+        case KBD_Function:
+        default:
+        }
+        // Return character [if one has arrived]
+        if (kbd_event & KBD_Press) {
+            if (kbd_modifiers & (MOD_Shift|MOD_CapsLock)) {
+                ch = kbd_shifted_chars[kbd_event & 0x7F];
+            } else {
+                ch = kbd_chars[kbd_event & 0x7F];
+            }
+            if (kbd_modifiers & MOD_Ctrl) {
+                ch &= 0x1F;
+            }
+            if (ch) {
+                return (ch);
+            }
+        }
+    }
+}
--- a/packages/hal/arm/cl7211/current/misc/kbd_test.c
+++ b/packages/hal/arm/cl7211/current/misc/kbd_test.c
@@ -57,14 +57,8 @@ static char stack[STACK_SIZE];
 static cyg_thread thread_data;
 static cyg_handle_t thread_handle;
 
-static char kbd_server_stack[STACK_SIZE];
-static cyg_thread kbd_server_thread_data;
-static cyg_handle_t kbd_server_thread_handle;
-
-static cyg_interrupt kbd_interrupt;
-static cyg_handle_t  kbd_interrupt_handle;
-
 #include "lcd_support.c"
+#include "kbd_support.c"
 
 // FUNCTIONS
 
@@ -74,384 +68,18 @@ cyg_test_exit(void)
     while (TRUE) ;
 }
 
-static cyg_uint8 col_state[8];
-static cyg_uint8 ext_state[8];
-
-static void
-kbd_delay(void)
-{
-    volatile int i;
-    for (i = 0;  i < 250;  i++) ;
-}
-
-static void
-kbd_scan(void)
-{
-    int i;
-    cyg_uint8 port_data, ext_data;
-    // Turn off drive (de-select) all columns
-    *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) |
-        SYSCON1_KBD_LOW;
-    for (i = 0;  i < 8;  i++) {
-        // Select column 'i'
-        *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) |
-            SYSCON1_KBD_COL(i);
-        // Small pause to let the wires charge up :-)
-        kbd_delay();
-        // Grab the data
-        col_state[i] = port_data = *(volatile cyg_uint8 *)PADR;
-        ext_state[i] = ext_data = *(volatile cyg_uint8 *)KBD_PORT;
-        // De-Select column 'i'
-        *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) |
-            SYSCON1_KBD_TRISTATE;
-        // Allow line to gl slack
-        kbd_delay();
-    }
-    // Turn on drive (select) all columns - necessary to see interrupts
-    *(volatile cyg_uint32 *)SYSCON1 = (*(volatile cyg_uint32 *)SYSCON1 & ~SYSCON1_KBD_CTL) |
-        SYSCON1_KBD_HIGH;
-}
-
-
-static cyg_mbox      kbd_events_mbox;
-static cyg_handle_t  kbd_events_mbox_handle;
-static cyg_sem_t     kbd_sem;
-static cyg_uint8     kbd_state[128];      // Known state of each key
-static cyg_uint8     kbd_new_state[128];  // Current state of each key
-
-#define MOD_Shift    0x40
-#define MOD_Ctrl     0x20
-#define MOD_CapsLock 0x10
-static cyg_uint32    kbd_modifiers;
-
-// Row #1
-#define KBD_Escape     0x00
-#define KBD_F1         0x01
-#define KBD_F2         0x02
-#define KBD_F3         0x03
-#define KBD_F4         0x04
-#define KBD_F5         0x05
-#define KBD_F6         0x06
-#define KBD_F7         0x07
-#define KBD_F8         0x08
-#define KBD_F9         0x09
-#define KBD_F10        0x0A
-#define KBD_NumLock    0x0B
-#define KBD_SysReq     0x0C
-#define KBD_ScrlLock   0x0D
-#define KBD_Break      0x0E
-// Row #2
-#define KBD_1          0x10
-#define KBD_2          0x11
-#define KBD_3          0x12
-#define KBD_4          0x13
-#define KBD_5          0x14
-#define KBD_6          0x15
-#define KBD_7          0x16
-#define KBD_8          0x17
-#define KBD_9          0x18
-#define KBD_0          0x19
-#define KBD_Hyphen     0x1A
-#define KBD_Equals     0x1B
-#define KBD_BackSpace  0x1C
-#define KBD_Home       0x1D
-// Row #3
-#define KBD_Tab        0x20
-#define KBD_Q          0x21
-#define KBD_W          0x22
-#define KBD_E          0x23
-#define KBD_R          0x24
-#define KBD_T          0x25
-#define KBD_Y          0x26
-#define KBD_U          0x27
-#define KBD_I          0x28
-#define KBD_O          0x29
-#define KBD_P          0x2A
-#define KBD_LeftBrkt   0x2B
-#define KBD_RightBrkt  0x2C
-#define KBD_BackSlash  0x2D
-#define KBD_PageUp     0x2E
-// Row #4
-#define KBD_CapsLock   0x30
-#define KBD_A          0x31
-#define KBD_S          0x32
-#define KBD_D          0x33
-#define KBD_F          0x34
-#define KBD_G          0x35
-#define KBD_H          0x36
-#define KBD_J          0x37
-#define KBD_K          0x38
-#define KBD_L          0x39
-#define KBD_SemiColon  0x3A
-#define KBD_Quote      0x3B
-#define KBD_Enter      0x3C
-#define KBD_PageDown   0x3D
-// Row #5
-#define KBD_LeftShift  0x40
-#define KBD_Z          0x41
-#define KBD_X          0x42
-#define KBD_C          0x43
-#define KBD_V          0x44
-#define KBD_B          0x45
-#define KBD_N          0x46
-#define KBD_M          0x47
-#define KBD_Comma      0x48
-#define KBD_Period     0x49
-#define KBD_Slash      0x4A
-#define KBD_RightShift 0x4B
-#define KBD_UpArrow    0x4C
-#define KBD_End        0x4D
-// Row #6
-#define KBD_Ctrl       0x50
-#define KBD_Function   0x51
-#define KBD_LeftAlt    0x52
-#define KBD_Accent     0x53
-#define KBD_Space      0x54
-#define KBD_RightAlt   0x55
-#define KBD_Ins        0x56
-#define KBD_Del        0x57
-#define KBD_LeftArrow  0x58
-#define KBD_DownArrow  0x59
-#define KBD_RightArrow 0x5A
-
-#define KBD_Press      0x80  // Event has this bit when the key is pressed
-#define KBD_Empty      0xFF
-
-// Map column, bit -> keycode
-static cyg_uint32    kbd_map[8][16] = {
-    // Column #0
-    {KBD_Escape,    KBD_1,          KBD_Tab,        KBD_CapsLock,
-     KBD_BackSlash, KBD_Space,      KBD_LeftArrow,  KBD_UpArrow,
-     KBD_DownArrow, KBD_RightArrow, KBD_LeftShift,  KBD_Ctrl, 
-     KBD_Function,  KBD_LeftAlt,    KBD_RightAlt,   KBD_RightShift },
-    // Column #1
-    {KBD_F5,        KBD_6,          KBD_T,          KBD_G,  
-     KBD_B,         KBD_Slash,      KBD_SemiColon,  KBD_P,  
-     KBD_Hyphen,    KBD_F10,        KBD_Empty,      KBD_Empty,
-     KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty     },
-    // Column #2
-    {KBD_F4,        KBD_5,          KBD_R,          KBD_F,  
-     KBD_V,         KBD_Del,        KBD_Quote,      KBD_LeftBrkt,  
-     KBD_Equals,    KBD_NumLock,    KBD_Empty,      KBD_Empty,
-     KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty },
-    // Column #3
-    {KBD_F3,        KBD_4,          KBD_E,          KBD_D,  
-     KBD_C,         KBD_Ins,        KBD_Empty,      KBD_RightBrkt,  
-     KBD_BackSpace, KBD_SysReq,     KBD_Empty,      KBD_Empty,
-     KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty },
-    // Column #4
-    {KBD_F2,        KBD_3,          KBD_W,          KBD_S,  
-     KBD_X,         KBD_Empty,      KBD_Enter,      KBD_Empty,
-     KBD_Empty,     KBD_ScrlLock,   KBD_Empty,      KBD_Empty,
-     KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty },
-    // Column #5
-    {KBD_F1,        KBD_2,          KBD_Q,          KBD_A,  
-     KBD_Z,         KBD_End,        KBD_PageDown,   KBD_PageUp,
-     KBD_Home,      KBD_Break,      KBD_Empty,      KBD_Empty,
-     KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty },
-    // Column #6
-    {KBD_F6,        KBD_7,          KBD_Y,          KBD_H,  
-     KBD_N,         KBD_Period,     KBD_L,          KBD_O,  
-     KBD_Empty,     KBD_F9,         KBD_Empty,      KBD_Empty,
-     KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty },
-    // Column #7
-    {KBD_F7,        KBD_8,          KBD_U,          KBD_J,  
-     KBD_M,         KBD_Comma,      KBD_K,          KBD_I,  
-     KBD_Empty,     KBD_F8,         KBD_Empty,      KBD_Empty,
-     KBD_Empty,     KBD_Empty,      KBD_Empty,      KBD_Empty },
-};
-
-static cyg_uint8 kbd_chars[96] = {
-    /* 0x00 - 0x0F */
-    0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    /* 0x10 - 0x1F */
-     '1',  '2',  '3',  '4',  '5',  '6',  '7',  '8',  '9',  '0',  '-',  '=', 0x08, 0x00, 0x00, 0x00,
-    /* 0x20 - 0x2F */
-    '\t',  'q',  'w',  'e',  'r',  't',  'y',  'u',  'i',  'o',  'p',  '[',  ']', '\\', 0x00, 0x00,
-    /* 0x30 - 0x3F */
-    0x00,  'a',  's',  'd',  'f',  'g',  'h',  'j',  'k',  'l',  ';', '\'', 0x0D, 0x00, 0x00, 0x00,
-    /* 0x40 - 0x4F */
-    0x00,  'z',  'x',  'c',  'v',  'b',  'n',  'm',  ',',  '.',  '/', 0x00, 0x00, 0x00, 0x00, 0x00,
-    /* 0x50 - 0x5F */
-    0x00, 0x00, 0x00, 0x00,  ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-static cyg_uint8 kbd_shifted_chars[96] = {
-    /* 0x00 - 0x0F */
-    '\b', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-    /* 0x10 - 0x1F */
-     '!',  '@',  '#',  '$',  '%',  '^',  '&',  '*',  '(',  ')',  '_',  '+', 0x08, 0x00, 0x00, 0x00,
-    /* 0x20 - 0x2F */
-    '\t',  'Q',  'W',  'E',  'R',  'T',  'Y',  'U',  'I',  'O',  'P',  '{',  '}',  '|', 0x00, 0x00,
-    /* 0x30 - 0x3F */
-    0x00,  'A',  'S',  'D',  'F',  'G',  'H',  'J',  'K',  'L',  ':',  '"', 0x0D, 0x00, 0x00, 0x00,
-    /* 0x40 - 0x4F */
-    0x00,  'Z',  'X',  'C',  'V',  'B',  'N',  'M',  '<',  '>',  '?', 0x00, 0x00, 0x00, 0x00, 0x00,
-    /* 0x50 - 0x5F */
-    0x00, 0x00, 0x00, 0x00,  ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-// This ISR is called when the keyboard interrupt occurs
-int
-keyboard_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs)
-{
-    cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_KBDINT);
-    return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR
-}
-
-// This DSR handles the keyboard [logical] processing
-void
-keyboard_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
-{
-    // Tell the keyboard processing thread to give it a shot
-    cyg_semaphore_post(&kbd_sem);
-}
-
-static void
-kbd_server(cyg_addrword_t p)
-{
-    int col, bit, key, event, timeout;
-    diag_printf("KBD server here\n");
-    // This semaphore is set when there is a keypress
-    cyg_semaphore_init(&kbd_sem, 0);  
-    while (TRUE) {
-        cyg_semaphore_wait(&kbd_sem);
-        // As long as keys are pressed, scan and update
-        timeout = 0;
-        while (TRUE) {
-            // Wait for 20ms - time to debounce keyboard
-            cyg_thread_delay(2);
-            // Scan keyboard
-            kbd_scan();
-            // Reset state
-            for (key = 0;  key < sizeof(kbd_new_state);  key++) {
-                kbd_new_state[key] = 0;
-            }
-            // Check state of all keys and send events for those that change
-            for (col = 0;  col < 8;  col++) {
-                for (bit = 0;  bit < 8;  bit++) {
-                    if (col_state[col] & (1<<bit)) {
-                        key = kbd_map[col][bit];
-                        if (key != KBD_Empty) {
-                            kbd_new_state[key] = 1;
-                        }
-                    }
-                    if (ext_state[col] & (1<<bit)) {
-                        key = kbd_map[col][bit+8];
-                        if (key != KBD_Empty) {
-                            kbd_new_state[key] = 1;
-                        }
-                    }
-                }
-            }
-            // Compare new and old (known) states, generate events for changes
-            // Send events for modifier keys first.
-            for (key = 0;  key < sizeof(kbd_new_state);  key++) {
-                if (kbd_state[key] != kbd_new_state[key]) {
-                    event = 0xFF;
-                    switch (key) {
-                    case KBD_LeftShift:
-                    case KBD_RightShift:
-                    case KBD_Ctrl:
-                    case KBD_LeftAlt:
-                    case KBD_RightAlt:
-                    case KBD_Function:
-                    case KBD_CapsLock:
-                        if (kbd_state[key]) {
-                            // Key going up
-                            event = key;
-                        } else {
-                            // Key going down
-                            event = key + KBD_Press;
-                        }
-                        kbd_state[key] = kbd_new_state[key];
-                    }
-                    if (event != 0xFF) {
-                        if (!cyg_mbox_tryput(kbd_events_mbox_handle, (void *)event)) {
-                            diag_printf("KBD event lost: %x\n", event);
-                        }
-                    }
-                }
-            }
-            // First key up events
-            for (key = 0;  key < sizeof(kbd_new_state);  key++) {
-                if (kbd_state[key] != kbd_new_state[key]) {
-                    if (kbd_state[key]) {
-                        // Key going up
-                        event = key;
-                    } else {
-                        // Key going down
-                        event = key + KBD_Press;
-                    }
-                    if (!cyg_mbox_tryput(kbd_events_mbox_handle, (void *)event)) {
-                        diag_printf("KBD event lost: %x\n", event);
-                    }
-                }
-                kbd_state[key] = kbd_new_state[key];
-            }
-            // Clear interrupt (true when keys are pressed)
-            cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_KBDINT);
-            if (*(volatile cyg_uint32 *)INTSR2 & INTSR2_KBDINT) {
-                timeout = 0;
-            } else if (++timeout == 5) {
-                // No keys for 100ms
-                break;
-            }
-        }
-        // Allow interrupts to happen again
-        cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_KBDINT);
-        cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_KBDINT);
-    }
-}
-
 static void
 kbd_exercise(cyg_addrword_t p)
 {
-    int i;
-    cyg_uint8 kbd_event, ch;
+    cyg_uint8 ch;
     diag_printf("KBD test here!\n");
 
+    // Initialize keyboard driver
+    kbd_init();
+
     while (TRUE) {
-        kbd_event = (cyg_uint8)cyg_mbox_get(kbd_events_mbox_handle);
-        switch (kbd_event & 0x7F) {
-        case KBD_LeftShift:
-        case KBD_RightShift:
-            if (kbd_event & KBD_Press) {
-                kbd_modifiers |= MOD_Shift;
-            } else {
-                kbd_modifiers &= ~MOD_Shift;
-            }
-            break;
-        case KBD_Ctrl:
-            if (kbd_event & KBD_Press) {
-                kbd_modifiers |= MOD_Ctrl;
-            } else {
-                kbd_modifiers &= ~MOD_Ctrl;
-            }
-            break;
-        case KBD_CapsLock:
-            if (kbd_event & KBD_Press) {
-                kbd_modifiers |= MOD_CapsLock;
-            } else {
-                kbd_modifiers &= ~MOD_CapsLock;
-            }
-            break;
-        case KBD_LeftAlt:
-        case KBD_RightAlt:
-        case KBD_Function:
-        default:
-        }
-        // Show character
-        if (kbd_event & KBD_Press) {
-            if (kbd_modifiers & (MOD_Shift|MOD_CapsLock)) {
-                ch = kbd_shifted_chars[kbd_event & 0x7F];
-            } else {
-                ch = kbd_chars[kbd_event & 0x7F];
-            }
-            if (ch) {
-                diag_printf("CH = 0x%x:'%c'\n", ch, ch);
-            }
-        }
+        ch = kbd_getc();
+        diag_printf("CH = 0x%x:'%c'\n", ch, ch);
     }
 
     diag_printf("All done!\n");
@@ -461,20 +89,6 @@ kbd_exercise(cyg_addrword_t p)
 externC void
 cyg_start( void )
 {
-    // Initialize environment, setup interrupt handler
-    *(volatile cyg_uint8 *)PADDR   = 0x00;  // All bits input
-    cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_KBDINT,
-                             99,                     // Priority - what goes here?
-                             0,                      //  Data item passed to interrupt handler
-                             (cyg_ISR_t *)keyboard_isr,
-                             (cyg_DSR_t *)keyboard_dsr,
-                             &kbd_interrupt_handle,
-                             &kbd_interrupt);
-    cyg_drv_interrupt_attach(kbd_interrupt_handle);
-    cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_KBDINT);
-    cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_KBDINT);
-    // Set up the mbox for keyboard data
-    cyg_mbox_create(&kbd_events_mbox_handle, &kbd_events_mbox);
     // Create a main thread, so we can run the scheduler and have time 'pass'
     cyg_thread_create(11,                // Priority - just a number
                       kbd_exercise,      // entry
@@ -486,18 +100,6 @@ cyg_start( void )
                       &thread_data       // Thread data structure
             );
     cyg_thread_resume(thread_handle);  // Start it
-    // Create another thread whose job it is to de-bounce the keyboard and
-    // actually process the input, turning it into a series of events
-    cyg_thread_create(10,                           // Priority - just a number
-                      kbd_server,                   // entry
-                      0,                            // initial parameter
-                      "KBD_server",                 // Name
-                      &kbd_server_stack[0],         // Stack
-                      STACK_SIZE,                   // Size
-                      &kbd_server_thread_handle,    // Handle
-                      &kbd_server_thread_data       // Thread data structure
-            );
-    cyg_thread_resume(kbd_server_thread_handle);  // Start it
     // Let 'em fly...
     cyg_scheduler_start();
 } // cyg_package_start()
new file mode 100644
--- /dev/null
+++ b/packages/hal/arm/cl7211/current/misc/lcd_panel_support.c
@@ -0,0 +1,213 @@
+//==========================================================================
+//
+//        panel_support.c
+//
+//        Cirrus CL72xx eval board LCD touch panel support code
+//
+//==========================================================================
+//####COPYRIGHTBEGIN####
+//
+// -------------------------------------------
+// The contents of this file are subject to the Cygnus eCos Public License
+// Version 1.0 (the "License"); you may not use this file except in
+// compliance with the License.  You may obtain a copy of the License at
+// http://sourceware.cygnus.com/ecos
+// 
+// Software distributed under the License is distributed on an "AS IS"
+// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the
+// License for the specific language governing rights and limitations under
+// the License.
+// 
+// The Original Code is eCos - Embedded Cygnus Operating System, released
+// September 30, 1998.
+// 
+// The Initial Developer of the Original Code is Cygnus.  Portions created
+// by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions.  All Rights Reserved.
+// -------------------------------------------
+//
+//####COPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     gthomas
+// Contributors:  gthomas
+// Date:          1999-09-13
+// Description:   Tool used to support the LCD touch panel
+//####DESCRIPTIONEND####
+
+static char lcd_panel_server_stack[STACK_SIZE];
+static cyg_thread lcd_panel_server_thread_data;
+static cyg_handle_t lcd_panel_server_thread_handle;
+
+static cyg_interrupt lcd_panel_interrupt;
+static cyg_handle_t  lcd_panel_interrupt_handle;
+
+static cyg_mbox      lcd_panel_events_mbox;
+static cyg_handle_t  lcd_panel_events_mbox_handle;
+static cyg_sem_t     lcd_panel_sem;
+
+#define SYNCIO_TXFRMEN     (1<<14)
+#define SYNCIO_FRAMELEN(n) (n<<8)
+#define ADC_START          (1<<7)
+#define ADC_CHAN(n)        (n<<4)
+#define ADC_UNIPOLAR       (1<<3)
+#define ADC_SINGLE         (1<<2)
+#define ADC_EXT_CLOCK      (3<<0)
+#define TOUCH_CTL          KBD_PORT
+
+// FUNCTIONS
+
+static cyg_uint32
+adc_sample(int chan)
+{
+    cyg_uint32 val;
+    *(volatile cyg_uint32 *)SYNCIO = SYNCIO_TXFRMEN | SYNCIO_FRAMELEN(24) |
+        ADC_START | ADC_CHAN(chan) | ADC_UNIPOLAR | ADC_SINGLE | ADC_EXT_CLOCK;
+    while (*(volatile cyg_uint32 *)SYSFLG1 & SYSFLG1_SSIBUSY) ;
+    val = *(volatile cyg_uint32 *)SYNCIO;
+    return (val & 0xFFFF);
+}
+
+static void
+panel_delay(void)
+{
+    volatile int i;
+    for (i = 0;  i < 800;  i++) ;
+}
+
+// This ISR is called when the touch panel interrupt occurs
+static int 
+lcd_panel_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs)
+{
+    cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_EINT2);
+    return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR
+}
+
+// This DSR starts up the touch panel [logical] processing
+static void
+lcd_panel_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
+{
+    // Tell the panel processing thread to give it a shot
+    cyg_semaphore_post(&lcd_panel_sem);
+}
+
+// Assumption: if the keypress vanishes for 5*20 ms, it probably isn't there
+#define LCD_PANEL_TIMEOUT 5
+
+static __inline__ int
+abs(int x)
+{
+    if (x < 0) return -x;
+    return x;
+}
+
+static void
+lcd_panel_server(cyg_addrword_t p)
+{
+    int iX, iY, newX, newY, diffX, diffY, timeout, samples;
+    cyg_uint32 event;
+    diag_printf("LCD panel server here\n");
+    while (TRUE) {
+        cyg_semaphore_wait(&lcd_panel_sem);
+        samples = 0;  iX = 0;  iY = 0;
+        // Wait for press to go away (no drag support)
+        timeout = 0;
+        while (timeout < LCD_PANEL_TIMEOUT) {
+            *(volatile cyg_uint8 *)TOUCH_CTL = 0x00;  // Disable drives
+            while (*(volatile cyg_uint32 *)INTSR1 & INTSR1_EINT2) ;
+            *(volatile cyg_uint8 *)TOUCH_CTL = 0x70;  // Idle state (so interrupt works)
+            cyg_thread_delay(2);  // Wait 20 ms
+            if (*(volatile cyg_uint32 *)INTSR1 & INTSR1_EINT2) {
+                // Still pressed
+                // Drive TSPY, ground TSMY, and disconnect TSPX and TSMX
+                *(volatile cyg_uint8 *)TOUCH_CTL = 0x50;  
+                panel_delay();
+                newY = adc_sample(2);
+                // Drive TSPX, ground TSMX, and disconnect TSPY and TSMY
+                *(volatile cyg_uint8 *)TOUCH_CTL = 0xA0;  
+                panel_delay();
+                newX = adc_sample(7);
+#if 0
+                diag_printf("timeout: %d, ISR: %x, newX: %d, newY: %d\n", 
+                            timeout, *(volatile cyg_uint32 *)INTSR1, newX, newY);
+#endif
+                // See if this sample makes any sense
+                if (samples) {
+                    diffX = abs(iX/samples - newX);
+                    diffY = abs(iY/samples - newY);
+                    if ((diffX <= ((iX/samples)/4)) &&
+                        (diffY <= ((iY/samples)/4))) {
+                        samples++;
+                        iX += newX;
+                        iY += newY;
+                    } else {
+#if 0
+                        diag_printf("Discard - newX: %d, X: %d, newY: %d, Y: %d\n",
+                                    newX, iX/samples, newY, iY/samples);
+#endif
+                        break;
+                    }
+                } else {
+                    iX = newX;
+                    iY = newY;
+                    samples = 1;
+                }
+                timeout = 0;
+            } else {
+                timeout++;
+            }
+        }
+        if (samples) {
+            // Send event to user level
+            event = (iX/samples)<<16 | (iY/samples);
+            if (!cyg_mbox_tryput(lcd_panel_events_mbox_handle, (void *)event)) {
+                diag_printf("LCD event lost: %x\n", event);
+            }
+        }
+        *(volatile cyg_uint8 *)TOUCH_CTL = 0x00;  // Disable drives
+        while (*(volatile cyg_uint32 *)INTSR1 & INTSR1_EINT2) ;
+        *(volatile cyg_uint8 *)TOUCH_CTL = 0x70;  // Idle state (so interrupt works)
+        cyg_thread_delay(10);
+        cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EINT2);
+    }
+}
+
+static void
+lcd_panel_init(void)
+{
+    // Enable touch panel
+    *(volatile cyg_uint8 *)PEDR   |= 0x04;  
+
+    // Idle state (so interrupt works)
+    *(volatile cyg_uint8 *)TOUCH_CTL = 0x70;  
+
+    // Enable ADC machinery
+    *(volatile cyg_uint32 *)SYSCON1 |= SYSCON1_ADC_CLOCK_128kHZ;
+
+    cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_EINT2,
+                             99,                     // Priority - what goes here?
+                             0,                      //  Data item passed to interrupt handler
+                             lcd_panel_isr,
+                             lcd_panel_dsr,
+                             &lcd_panel_interrupt_handle,
+                             &lcd_panel_interrupt);
+    cyg_drv_interrupt_attach(lcd_panel_interrupt_handle);
+    cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_EINT2);
+    cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EINT2);
+    // Set up the mbox for panel data
+    cyg_mbox_create(&lcd_panel_events_mbox_handle, &lcd_panel_events_mbox);
+    // This semaphore is set when there is a touch
+    cyg_semaphore_init(&lcd_panel_sem, 0);  
+    // Create a thread whose job it is to de-bounce the keyboard and
+    // actually process the input, turning it into a series of events
+    cyg_thread_create(10,                           // Priority - just a number
+                      lcd_panel_server,             // entry
+                      0,                            // initial parameter
+                      "LCD_PANEL_server",           // Name
+                      &lcd_panel_server_stack[0],   // Stack
+                      STACK_SIZE,                   // Size
+                      &lcd_panel_server_thread_handle,    // Handle
+                      &lcd_panel_server_thread_data       // Thread data structure
+            );
+    cyg_thread_resume(lcd_panel_server_thread_handle);  // Start it
+}
--- a/packages/hal/arm/cl7211/current/misc/lcd_support.c
+++ b/packages/hal/arm/cl7211/current/misc/lcd_support.c
@@ -41,6 +41,8 @@
 #define LAST_CHAR  0x7E
 #define FONT_HEIGHT 8
 #define FONT_WIDTH  8
+#define CURSOR_ON  0x5F
+#define CURSOR_OFF 0x20
 static char font_table[LAST_CHAR-FIRST_CHAR+1][8] =
 {
         {        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /*   */
@@ -155,20 +157,21 @@ static char font_table[LAST_CHAR-FIRST_C
 #define PIXEL_MASK      ((1<<PIXELS_PER_BYTE)-1)
 
 // Physical screen info
-int lcd_depth;  // Should be 1, 2, or 4
-int lcd_width  = LCD_WIDTH;
-int lcd_height = LCD_HEIGHT;
-cyg_uint8 *lcd_base = (cyg_uint8 *)0xC0000000;
+static int lcd_depth;  // Should be 1, 2, or 4
+static int lcd_width  = LCD_WIDTH;
+static int lcd_height = LCD_HEIGHT;
+static cyg_uint8 *lcd_base = (cyg_uint8 *)0xC0000000;
 
 // Virtual screen info
-int curX = 0;  // Last used position
-int curY = 0;
-int width = LCD_WIDTH / (FONT_WIDTH*NIBBLES_PER_PIXEL);
-int height = LCD_HEIGHT / (FONT_HEIGHT*SCREEN_SCALE);
-int fg = 0x0F;
-int bg = 0x00;
+static int curX = 0;  // Last used position
+static int curY = 0;
+static int width = LCD_WIDTH / (FONT_WIDTH*NIBBLES_PER_PIXEL);
+static int height = LCD_HEIGHT / (FONT_HEIGHT*SCREEN_SCALE);
+static int fg = 0x0F;
+static int bg = 0x00;
 
 // Functions
+static void lcd_drawc(cyg_int8 c, int x, int y);
 
 void
 lcd_on(int depth)
@@ -226,7 +229,7 @@ lcd_on(int depth)
 }
 
 // Clear screen
-static void
+void
 lcd_clear(void)
 {
     cyg_int8 *ptr = lcd_base;
@@ -235,6 +238,21 @@ lcd_clear(void)
         *ptr++ = 0;
     }
     curX = 0;  curY = 0;
+    lcd_drawc(CURSOR_ON, curX, curY);
+}
+
+// Position cursor
+void
+lcd_moveto(int X, int Y)
+{
+    lcd_drawc(CURSOR_OFF, curX, curY);
+    if (X < 0) X = 0;
+    if (X >= width) X = width-1;
+    curX = X;
+    if (Y < 0) Y = 0;
+    if (Y >= height) Y = height-1;
+    curY = Y;
+    lcd_drawc(CURSOR_ON, curX, curY);
 }
 
 // Render a character at position (X,Y) with current background/foreground
@@ -291,9 +309,11 @@ lcd_drawc(cyg_int8 c, int x, int y)
     }
 }
 
-static void
+// Draw one character at the current position
+void
 lcd_putc(cyg_int8 c)
 {
+    lcd_drawc(CURSOR_OFF, curX, curY);
     switch (c) {
     case '\r':
         curX = 0;
@@ -308,6 +328,7 @@ lcd_putc(cyg_int8 c)
             if (curY < 0) curY = 0;
             curX = width-1;
         }
+        break;
     default:
         lcd_drawc(c, curX, curY);
         curX++;
@@ -316,5 +337,163 @@ lcd_putc(cyg_int8 c)
             curX = 0;
         }
     } 
+    lcd_drawc(CURSOR_ON, curX, curY);
+}
+
+// Basic LCD 'printf()' support
+
+#ifndef FALSE
+#define FALSE 0
+#define TRUE  1
+#endif
+
+#include <stdarg.h>
+
+#define is_digit(c) ((c >= '0') && (c <= '9'))
+
+static int
+_cvt(unsigned long val, char *buf, long radix, char *digits)
+{
+    char temp[80];
+    char *cp = temp;
+    int length = 0;
+    if (val == 0) {
+        /* Special case */
+        *cp++ = '0';
+    } else {
+        while (val) {
+            *cp++ = digits[val % radix];
+            val /= radix;
+        }
+    }
+    while (cp != temp) {
+        *buf++ = *--cp;
+        length++;
+    }
+    *buf = '\0';
+    return (length);
 }
 
+int
+lcd_vprintf(void (*putc)(cyg_int8), const char *fmt0, va_list ap)
+{
+    char c, sign, *cp;
+    int left_prec, right_prec, zero_fill, length, pad, pad_on_right;
+    char buf[32];
+    long val;
+    while ((c = *fmt0++)) {
+        cp = buf;
+        length = 0;
+        if (c == '%') {
+            c = *fmt0++;
+            left_prec = right_prec = pad_on_right = 0;
+            if (c == '-') {
+                c = *fmt0++;
+                pad_on_right++;
+            }
+            if (c == '0') {
+                zero_fill = TRUE;
+                c = *fmt0++;
+            } else {
+                zero_fill = FALSE;
+            }
+            while (is_digit(c)) {
+                left_prec = (left_prec * 10) + (c - '0');
+                c = *fmt0++;
+            }
+            if (c == '.') {
+                c = *fmt0++;
+                zero_fill++;
+                while (is_digit(c)) {
+                    right_prec = (right_prec * 10) + (c - '0');
+                    c = *fmt0++;
+                }
+            } else {
+                right_prec = left_prec;
+            }
+            sign = '\0';
+            switch (c) {
+            case 'd':
+            case 'x':
+            case 'X':
+                val = va_arg(ap, long);
+                switch (c) {
+                case 'd':
+                    if (val < 0) {
+                        sign = '-';
+                        val = -val;
+                    }
+                    length = _cvt(val, buf, 10, "0123456789");
+                    break;
+                case 'x':
+                    length = _cvt(val, buf, 16, "0123456789abcdef");
+                    break;
+                case 'X':
+                    length = _cvt(val, buf, 16, "0123456789ABCDEF");
+                    break;
+                }
+                break;
+            case 's':
+                cp = va_arg(ap, char *);
+                length = strlen(cp);
+                break;
+            case 'c':
+                c = va_arg(ap, long /*char*/);
+                (*putc)(c);
+                continue;
+            default:
+                (*putc)('?');
+            }
+            pad = left_prec - length;
+            if (sign != '\0') {
+                pad--;
+            }
+            if (zero_fill) {
+                c = '0';
+                if (sign != '\0') {
+                    (*putc)(sign);
+                    sign = '\0';
+                }
+            } else {
+                c = ' ';
+            }
+            if (!pad_on_right) {
+                while (pad-- > 0) {
+                    (*putc)(c);
+                }
+            }
+            if (sign != '\0') {
+                (*putc)(sign);
+            }
+            while (length-- > 0) {
+                (*putc)(c = *cp++);
+                if (c == '\n') {
+                    (*putc)('\r');
+                }
+            }
+            if (pad_on_right) {
+                while (pad-- > 0) {
+                    (*putc)(' ');
+                }
+            }
+        } else {
+            (*putc)(c);
+            if (c == '\n') {
+                (*putc)('\r');
+            }
+        }
+    }
+}
+
+int
+lcd_printf(char const *fmt, ...)
+{
+	int ret;
+	va_list ap;
+
+	va_start(ap, fmt);
+	ret = lcd_vprintf(lcd_putc, fmt, ap);
+	va_end(ap);
+	return (ret);
+}
+
--- a/packages/hal/arm/cl7211/current/misc/panel_test.c
+++ b/packages/hal/arm/cl7211/current/misc/panel_test.c
@@ -31,7 +31,7 @@
 //
 // Author(s):     gthomas
 // Contributors:  gthomas
-// Date:          1999-05-15
+// Date:          1999-09-06
 // Description:   Tool used to test LCD touch panel
 //####DESCRIPTIONEND####
 
@@ -56,19 +56,9 @@
 static char stack[STACK_SIZE];
 static cyg_thread thread_data;
 static cyg_handle_t thread_handle;
-static cyg_interrupt panel_interrupt;
-static cyg_handle_t  panel_interrupt_handle;
 
 #include "lcd_support.c"
-
-#define SYNCIO_TXFRMEN     (1<<14)
-#define SYNCIO_FRAMELEN(n) (n<<8)
-#define ADC_START          (1<<7)
-#define ADC_CHAN(n)        (n<<4)
-#define ADC_UNIPOLAR       (1<<3)
-#define ADC_SINGLE         (1<<2)
-#define ADC_EXT_CLOCK      (3<<0)
-#define TOUCH_CTL          KBD_PORT
+#include "lcd_panel_support.c"
 
 // FUNCTIONS
 
@@ -78,78 +68,20 @@ cyg_test_exit(void)
     while (TRUE) ;
 }
 
-static cyg_uint32
-adc_sample(int chan)
-{
-    cyg_uint32 val;
-    *(volatile cyg_uint32 *)SYNCIO = SYNCIO_TXFRMEN | SYNCIO_FRAMELEN(24) |
-        ADC_START | ADC_CHAN(chan) | ADC_UNIPOLAR | ADC_SINGLE | ADC_EXT_CLOCK;
-    while (*(volatile cyg_uint32 *)SYSFLG1 & SYSFLG1_SSIBUSY) ;
-    val = *(volatile cyg_uint32 *)SYNCIO;
-    return val & 0xFFFF;
-}
-
-static void
-panel_delay(void)
-{
-    volatile int i;
-    for (i = 0;  i < 50;  i++) ;
-}
-
-// This ISR is called when the touch panel interrupt occurs
-int 
-cyg_hal_panel_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs)
-{
-    int iX, iY;
-    cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_EINT2);
-    diag_printf("Touched!\n");
-    *(volatile cyg_uint8 *)TOUCH_CTL = 0x50;  // Drive TSPY, ground TSMY, and disconnect TSPX and TSMX
-    panel_delay();
-    iY = adc_sample(2);
-    *(volatile cyg_uint8 *)TOUCH_CTL = 0xA0;  // Drive TSPX, ground TSMX, and disconnect TSPY and TSMY
-    panel_delay();
-    iX = adc_sample(7);
-    diag_printf("X = %d, Y = %d, ISR1: %x\n", iX, iY, *(volatile cyg_uint32 *)INTSR1);
-    *(volatile cyg_uint8 *)TOUCH_CTL = 0x00;  // Disable drives
-    while (*(volatile cyg_uint32 *)INTSR1 & INTSR1_EINT2) ;
-    *(volatile cyg_uint8 *)TOUCH_CTL = 0x70;  // Idle state (so interrupt works)
-//    cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EINT2);
-    return 0;  // No need to run DSR
-}
-
 static void
 panel_exercise(cyg_addrword_t p)
 {
-    int i, j;
+    int i;
+    cyg_uint32 val;
+
     diag_printf("LCD touch panel test here!\n");
 
-    *(volatile cyg_uint8 *)PEDDR   = 0x0F;  // Register E data direction
-    *(volatile cyg_uint8 *)PEDR   |= 0x04;  // Enable touch panel
-
-    diag_printf("PEDR = %x\n", *(volatile cyg_uint8 *)PEDR);
-
-    *(volatile cyg_uint8 *)TOUCH_CTL = 0x70;  // Idle state (so interrupt works)
-
-    lcd_on(4);
-    lcd_clear();
-
-    *(volatile cyg_uint32 *)SYSCON1 |= SYSCON1_ADC_CLOCK_128kHZ;
-
-    cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_EINT2,
-                             99,                     // Priority - what goes here?
-                             0,                      //  Data item passed to interrupt handler
-                             cyg_hal_panel_isr,
-                             0,
-                             &panel_interrupt_handle,
-                             &panel_interrupt);
-    cyg_drv_interrupt_attach(panel_interrupt_handle);
-    cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_EINT2);
-    cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EINT2);
+    lcd_panel_init();
 
     for (i = 0;  i < 50;  i++) {
         diag_printf("Please touch screen now:\n");
-        cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EINT2);
-        cyg_thread_delay(5*100);
+        val = (cyg_uint32)cyg_mbox_get(lcd_panel_events_mbox_handle);
+        diag_printf("val = %x, X = %d, Y = %d\n", val, (val>>16), val & 0xFFFF);
     }
 
     diag_printf("All done!\n");
--- a/packages/hal/arm/cl7211/current/src/cl7211_misc.c
+++ b/packages/hal/arm/cl7211/current/src/cl7211_misc.c
@@ -279,6 +279,8 @@ void hal_hardware_init(void)
 // reading the hardware a lot, since the interrupt status is split across
 // three separate registers.
 
+int hal_spurious_ints;
+
 int hal_IRQ_handler(void)
 {
     struct regmap *map = hal_interrupt_status_regmap;
@@ -291,6 +293,7 @@ int hal_IRQ_handler(void)
         }
         map++;  // Next interrupt status register
     }
+    hal_spurious_ints++;
     return CYGNUM_HAL_INTERRUPT_unused; // This shouldn't happen!
 }
 
--- a/packages/hal/arm/cl7211/current/src/hal_diag.c
+++ b/packages/hal/arm/cl7211/current/src/hal_diag.c
@@ -86,6 +86,7 @@
 #endif
 #endif
 
+
 /*---------------------------------------------------------------------------*/
 // CL7211 Serial Port (UARTx) for Debug
 
--- a/packages/hal/arm/cl7211/current/src/plf_stub.c
+++ b/packages/hal/arm/cl7211/current/src/plf_stub.c
@@ -73,6 +73,7 @@ static cyg_interrupt gdb_interrupt;
 static cyg_handle_t  gdb_interrupt_handle;
 #endif
 
+
 //-----------------------------------------------------------------------------
 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
 
--- a/packages/hal/arm/cl7211/current/support/Makefile
+++ b/packages/hal/arm/cl7211/current/support/Makefile
@@ -3,8 +3,12 @@
 #
 
 DL_FILES = dl_7211.o io.o
+DOWNLOAD_FILES = download_file.o io.o
 
-all: dl_7211
+all: dl_7211 download
 
 dl_7211: $(DL_FILES)
-	$(CC) -o $@ $(DL_FILES)
\ No newline at end of file
+	$(CC) -o $@ $(DL_FILES)
+
+download: $(DOWNLOAD_FILES)
+	$(CC) -o $@ $(DOWNLOAD_FILES)
new file mode 100644
--- /dev/null
+++ b/packages/hal/arm/cl7211/current/support/download_file.c
@@ -0,0 +1,260 @@
+//****************************************************************************
+//
+// download_file.c - Send a raw data file to the EB72xx board.
+// 
+// Adapted from the Cirrus Logic 'DOWNLOAD.C' program
+//
+// Copyright (c) 1999 Cirrus Logic, Inc.
+//
+// Adapted for Linux by Cygnus Solutions, Inc.
+//
+//****************************************************************************
+#include <stdio.h>
+#include "bootcode.h"
+
+#define DEFAULT_PORT "/dev/ttyS0"
+extern char ReceiveChar(long);
+extern void SendChar(long, char);
+extern void SetBaud(long, long);
+extern int  CharRead(long port);
+extern void WaitForOutputReady(long port);
+extern long OpenPort(char *);
+
+//****************************************************************************
+//
+// WaitFor waits until a specific character is read from the comm port.
+//
+//****************************************************************************
+void
+WaitFor(long lPort, char cWaitChar)
+{
+    char cChar;
+
+    //
+    // Wait until we read a specific character from the comm port.
+    //
+    while(1)
+    {
+        //
+        // Read a character.
+        //
+        cChar = ReceiveChar(lPort);
+
+        //
+        // Stop waiting if we received the character.
+        //
+        if(cChar == cWaitChar)
+        {
+            break;
+        }
+    }
+}
+
+//****************************************************************************
+//
+// This program waits for the '<' character from the boot ROM, sends the boot
+// code, waits for the '>' from the boot ROM, waits for the '?' from the boot
+// code, changes the serial port rate (preferably to 115200), downloads the
+// user data file, and then prints out progress status as the boot code writes
+// the user data file to the flash.
+//
+//****************************************************************************
+void
+main(int argc, char *argv[])
+{
+    long lPort;
+    long lRate = 38400;
+    long lFileSize, lIdx;
+    char cChar, cFirstChar, *pcFile, cRateChar;
+    FILE *pFile;
+
+    //
+    // Make sure that a filename was specified.
+    //
+    if(argc < 2)
+    {
+        fprintf(stderr, "Usage: download <filename> {<baud rate> {<comm port>}}\n");
+        return;
+    }
+
+    //
+    // If a baud rate was specified, then read it and make sure it is valid.
+    //
+    if(argc > 2)
+    {
+        lRate = atoi(argv[2]);
+        if((lRate != 9600) && (lRate != 19200) && (lRate != 28800) &&
+           (lRate != 38400) && (lRate != 57600) && (lRate != 115200))
+        {
+            fprintf(stderr, "Invalid baud rate.\n");
+            return;
+        }
+    }
+
+    //
+    // If a comm port was specified, then read it and make sure it is valid.
+    //
+    if(argc > 3)
+    {
+        lPort = OpenPort(argv[3]);
+    } else 
+    {
+        lPort = OpenPort(DEFAULT_PORT);
+    }
+    if (lPort < 0) 
+    {
+        fprintf(stderr, "Can't open port\n");
+        return;
+    }
+
+    //
+    // Open the file to be downloaded.
+    //
+    pFile = fopen(argv[1], "rb");
+    if(!pFile)
+    {
+        fprintf(stderr, "Could not open file '%s'.\n", argv[1]);
+        return;
+    }
+
+    //
+    // Get the size of the file.
+    //
+    fseek(pFile, 0, SEEK_END);
+    lFileSize = ftell(pFile);
+    fseek(pFile, 0, SEEK_SET);
+
+    //
+    // Allocate memory to hold the file contents.
+    //
+    pcFile = (char *)malloc(lFileSize);
+    if(!pcFile)
+    {
+        fprintf(stderr, "Failed to allocate memory for the file.\n");
+        return;
+    }
+
+    //
+    // Read the contents of the file into memory.
+    //
+    if(fread(pcFile, 1, lFileSize, pFile) != lFileSize)
+    {
+        fprintf(stderr, "Failed to read file '%s'.\n", argv[1]);
+        return;
+    }
+
+    //
+    // Close the file.
+    //
+    fclose(pFile);
+
+    //
+    // Open the port to the desired baud rate.
+    //
+    SetBaud(lPort, lRate);
+
+    //
+    // Empty out the input queue.
+    //
+    while(CharReady(lPort))
+    {
+        cChar = ReceiveChar(lPort);
+    }
+
+    //
+    // Tell the user to reset the board.
+    //
+    fprintf(stderr, "Waiting for the board to wakeup...");
+
+    //
+    // Send a '-' character until we receive back a '?' character.
+    //
+    while(1)
+    {
+        //
+        // Send a '-' character.
+        //
+        SendChar(lPort, '-');
+
+        //
+        // Wait a little bit.
+        //
+        for(lIdx = 0; lIdx < 1024 * 1024; lIdx++)
+        {
+        }
+
+        //
+        // See if there is a character waiting to be read.
+        //
+        if(CharReady(lPort))
+        {
+            //
+            // Read the character.
+            //
+            cChar = ReceiveChar(lPort);
+
+            //
+            // Quit waiting if this is a '?'.
+            //
+            if(cChar == '?')
+            {
+                break;
+            }
+        }
+    }
+
+    //
+    // Empty out the input queue.
+    //
+    while(CharReady(lPort))
+    {
+        cChar = ReceiveChar(lPort);
+    }
+
+    //
+    // Send the download file "command"
+    //
+    SendChar(lPort, 'D');
+
+    //
+    // Send the length of the data file.
+    //
+    SendChar(lPort, (char)(lFileSize & 0xFF));
+    SendChar(lPort, (char)((lFileSize >> 8) & 0xFF));
+    SendChar(lPort, (char)((lFileSize >> 16) & 0xFF));
+    SendChar(lPort, (char)((lFileSize >> 24) & 0xFF));
+
+    //
+    // Tell the user that we are downloading the file data.
+    //
+    fprintf(stderr, "\nDownloading file data...(  0%%)");
+
+    //
+    // Send the actual data in the file.
+    //
+    for(lIdx = 0; lIdx < lFileSize; lIdx++)
+    {
+        //
+        // Send this byte.
+        //
+        SendChar(lPort, pcFile[lIdx]);
+
+        //
+        // Periodically print out our progress.
+        //
+        if((lIdx & 127) == 127)
+        {
+            fprintf(stderr, "\b\b\b\b\b%3d%%)", ((lIdx + 1) * 100) / lFileSize);
+            //
+            // Read a character from the boot code.
+            //
+            cChar = ReceiveChar(lPort);
+        }
+    }
+
+    //
+    // Tell the user we are done.
+    //
+    fprintf(stderr, "\nSuccessfully downloaded '%s'.\n", argv[1]);
+}
+
--- a/packages/hal/common/current/ChangeLog
+++ b/packages/hal/common/current/ChangeLog
@@ -1,3 +1,15 @@
+1999-09-21  Gary Thomas  <gthomas@cygnus.co.uk>
+
+	* src/thread-packets.c: Fix some typos in comments.
+
+1999-09-13  Gary Thomas  <gthomas@cygnus.co.uk>
+
+	* include/pkgconf/hal.h: Add new config option to allow spurious
+	interrupts to be ignored by the HAL.
+
+	* src/generic-stub.c (__process_packet): Build in version string
+	(date/time) for stubs in ROM to be returned via 'd' packet.
+
 1999-09-09  Jonathan Larmour  <jlarmour@cygnus.co.uk>
 
 	* include/pkgconf/hal.h (CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS): Rename
--- a/packages/hal/common/current/include/pkgconf/hal.h
+++ b/packages/hal/common/current/include/pkgconf/hal.h
@@ -205,6 +205,18 @@
          of RAM needed for interrupt decoding tables and code."
  }
 
+ cdl_option CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS {
+     display      "Ignore spurious [fleeting] interrupts"
+     parent       CYGPKG_HAL_COMMON_INTERRUPTS
+     description  "
+         On some hardware, interrupt sources may not be de-bounced or
+         de-glitched.  Rather than try to handle these interrupts (no
+         handling may be possible), this option allows the HAL to simply
+         ignore them.  In most cases, if the interrupt is real it will
+         reoccur in a detectable form."
+ }
+
+
  }}CFG_DATA
 
 */
@@ -214,6 +226,7 @@
 #undef  CYGSEM_HAL_COMMON_INTERRUPTS_ALLOW_NESTING
 #define CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT
 #undef  CYGIMP_HAL_COMMON_INTERRUPTS_CHAIN
+#undef  CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS
 
 
 /* {{CFG_DATA
--- a/packages/hal/common/current/src/generic-stub.c
+++ b/packages/hal/common/current/src/generic-stub.c
@@ -838,6 +838,11 @@ int
 
     case 'd':
       /* toggle debug flag */
+#ifdef __ECOS__
+#if !defined(CYG_HAL_STARTUP_RAM)    // Only for ROM based stubs
+      strcpy(remcomOutBuffer, "eCos GDB stubs - built " __DATE__ " / " __TIME__);
+#endif
+#endif // __ECOS__
       break;
 
     case 'q':
--- a/packages/hal/common/current/src/hal_stub.c
+++ b/packages/hal/common/current/src/hal_stub.c
@@ -117,6 +117,7 @@ void
 
 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
 
+
 #if (HAL_BREAKINST_SIZE == 1)
 typedef cyg_uint8 t_inst;
 #elif (HAL_BREAKINST_SIZE == 2)
@@ -162,6 +163,7 @@ cyg_hal_gdb_remove_break (target_registe
     return 0;
 }
 
+
 #endif // CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
 
 // Use this function to disable serial interrupts whenever reply
--- a/packages/hal/common/current/src/thread-packets.c
+++ b/packages/hal/common/current/src/thread-packets.c
@@ -160,7 +160,7 @@ static char * unpack_int(char * buf, int
   return buf + 8 ;
 }
 
-/* We are NOT depending upun extensive libraries */
+/* We are NOT depending upon extensive libraries */
 static int ishex(char ch,int *val)
 {
   if ((ch >= 'a') && (ch <= 'f'))
@@ -211,7 +211,7 @@ static char * pack_varlen_hex(
           n[i] = value & 0x0f ;
           value = value >> 4 ;
         }
-      i = 0 ;                  /* we had descrmented it to -1 */
+      i = 0 ;                  /* we had decrmented it to -1 */
       while (n[i] == 0 ) i++ ; /* drop leading zeroes */
       while (i++ < 8) *pkt++ = hexchars[n[i]] ; /* pack the number */
     }
@@ -336,8 +336,8 @@ static char * pack_threadid(char * pkt, 
   return pkt ;
 } /* stub_pack_threadid */
 
-/* UNFORTUNATLY, not all ow the extended debugging system has yet been
-   converted to 64 but thread referenecces and process identifiers.
+/* UNFORTUNATELY, not all of the extended debugging system has yet been
+   converted to 64 but thread references and process identifiers.
    These routines do the conversion.
    An array of bytes is the correct treatment of an opaque identifier.
    ints have endian issues.
--- a/packages/hal/mips/arch/current/ChangeLog
+++ b/packages/hal/mips/arch/current/ChangeLog
@@ -1,3 +1,32 @@
+1999-09-17  Jonathan Larmour  <jlarmour@cygnus.co.uk>
+
+	* src/vectors.S (__default_exception_vsr):
+	Rename exception_handler()->cyg_hal_exception_handler()
+	After all, we will just do a jump rather than a jal into
+	cyg_hal_exception_handler()
+	(restore_state): Make the change below (by Hugo) be conditional
+	on CYG_HAL_USE_ROM_MONITOR_CYGMON.
+	Add explanatory comment about the additions for Cygmon
+
+	* src/hal_misc.c (hal_default_isr): Use new format HAL_DIAG_IRQ_CHECK()
+	and check return code is negative; if so, return
+	(cyg_hal_exception_handler): Rename from exception_handler()
+	Now return cyg_uint32, but default to returning 0 always
+
+1999-09-16  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	This set of changes with matching ones in jmr3904 comes from Mark
+	Salter's work to make jmr3904 CygMon talk Ethernet.
+	
+	* src/vectors.S (restore_state): Call CygMon for exceptions or
+	unhandled interrupts if CYG_HAL_USE_ROM_MONITOR.  This is why the
+	return value from the ISR is preserved.  Don't fully understand
+	this.
+
+	* src/hal_misc.c (hal_default_isr): Call into hal_diag via
+	HAL_DIAG_IRQ_CHECK if it's defined and CYG_HAL_USE_ROM_MONITOR.
+	This lets CygMon check for network interrupts &c.
+
 1999-09-09  Nick Garnett  <nickg@cygnus.co.uk>
 
 	* include/arch.inc:
--- a/packages/hal/mips/arch/current/src/hal_misc.c
+++ b/packages/hal/mips/arch/current/src/hal_misc.c
@@ -72,7 +72,7 @@ externC void *__mem_fault_handler;
 
 externC cyg_uint8 cyg_hal_mips_process_fpe( HAL_SavedRegisters *regs );
 
-externC void exception_handler(HAL_SavedRegisters *regs)
+externC cyg_uint32 cyg_hal_exception_handler(HAL_SavedRegisters *regs)
 {
 #ifdef  CYGHWR_HAL_MIPS_FPU
     // We may be required to emulate certain unimplemented Floating Point
@@ -84,7 +84,7 @@ externC void exception_handler(HAL_Saved
         // the exception successfully. If so, we just return
 
         if ( cyg_hal_mips_process_fpe(regs) )
-            return;
+            return 0;
     }
 #endif
 
@@ -94,7 +94,7 @@ externC void exception_handler(HAL_Saved
     // and if so jump to the saved address
     if (__mem_fault_handler) {
         regs->pc = (CYG_ADDRWORD)__mem_fault_handler;
-        return; // Caught an exception inside stubs        
+        return 0; // Caught an exception inside stubs        
     }
 
     // Set the pointer to the registers of the current exception
@@ -117,7 +117,7 @@ externC void exception_handler(HAL_Saved
     CYG_FAIL("Exception!!!");
     
 #endif    
-    return;
+    return 0;
 }
 
 /*------------------------------------------------------------------------*/
@@ -137,6 +137,17 @@ externC cyg_uint32 hal_default_isr(CYG_A
         if( result != 0 ) return result;
     }
     
+#if defined(CYG_HAL_USE_ROM_MONITOR_CYGMON)
+#if defined(HAL_DIAG_IRQ_CHECK)
+    {
+        cyg_uint32 ret;
+        /* let ROM monitor handle unexpected interrupts */
+        HAL_DIAG_IRQ_CHECK(vector, ret);
+        if (ret<=0)
+            return ret;
+    }
+#endif // def HAL_DIAG_IRQ_CHECK
+#endif // def CYG_HAL_USE_ROM_MONITOR
 #endif
     
     CYG_TRACE1(true, "Interrupt: %d", vector);
--- a/packages/hal/mips/arch/current/src/vectors.S
+++ b/packages/hal/mips/arch/current/src/vectors.S
@@ -377,8 +377,8 @@ FUNC_START(__default_exception_vsr)
 
 	hal_cpu_except_enable			# reenable exceptions
 		
-	.extern	exception_handler
-	j	exception_handler		# call C code
+	.extern	cyg_hal_exception_handler
+	j	cyg_hal_exception_handler	# call C code
 	move	a0,s0				# arg0 = register dump (delay slot)
 
 	# When the exception handler returns, it will
@@ -562,7 +562,7 @@ 8:
 	
 	lw	sp,mips_stack_frame_size(sp)	# sp = *sp
 	subu	sp,sp,mips_stack_frame_size	# make a null frame		
-#endif	
+#endif
 	
 #ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT
 
@@ -579,7 +579,7 @@ 8:
 	# the register dump, the vector offset and the interrupt number
 	# respectively.
 
-	move	a0,v0				# put ISR result in arg0
+	move	s2,v0
 		
 	la	a1,hal_interrupt_objects	# interrupt object table
 	add	a1,a1,s1			# address of object ptr
@@ -589,11 +589,13 @@ 8:
 	
 	.extern	interrupt_end
 	jal	interrupt_end			# call into C to finish off 
-	nop					# (delay slot)
-
+	 move	a0,v0				# put ISR result in arg0
+	
+	move	v0,s2				# return value from isr
 #endif
 				
-restore_state:	
+restore_state:
+	move	k0,v0
 
 	# All done, restore CPU state and continue
 
@@ -648,7 +650,36 @@ restore_state:
 	lw	$30,(mipsreg_regs+30*4)(sp)	# == FP
 	lw	$31,(mipsreg_regs+31*4)(sp)	# == RA
 	.set	at
-	
+
+
+#if defined(CYG_HAL_USE_ROM_MONITOR_CYGMON)
+
+        # If we have a Cygmon that wants to listen to network interrupts, then
+        # the return code from the earlier call to hal_default_isr() will
+        # have been negative to indicate this. So we jump into Cygmon here
+        # because Cygmon requires the processor state to be the same as when
+        # the interrupt was taken, but with k0 as the exception number.
+        
+	bgez	k0,1f
+	nop
+	# Check for new cygmon
+	sw	k0,(mipsreg_regs+26*4)(sp)	# save k0
+	la	k1,0x80000100 + 41*4		# New cygmon "magic" id
+	lw	k1,0(k1)
+	lui	k0,0x55aa
+	ori	k0,0x4321
+	bne	k0,k1,1f
+			
+	# Need to let cygmon handle this
+	la	k1,0x80000100 + 39*4		# stub entry vector
+	lw	k0,(mipsreg_regs+26*4)(sp)	# restore k0
+	lw	k1,0(k1)
+	lw	sp,(mipsreg_regs+29*4)(sp)	# restore SP
+	sll	k0,1				# clear bit 31.
+	jr	k1
+        srl	k0,1
+    1:
+#endif
 	lw	k0,mipsreg_pc(sp)		# K0 = return PC
 	lw	k1,mipsreg_sr(sp)		# K1 = saved SR
 	lw	sp,(mipsreg_regs+29*4)(sp)	# load SP
--- a/packages/hal/mips/tx39/current/ChangeLog
+++ b/packages/hal/mips/tx39/current/ChangeLog
@@ -1,3 +1,31 @@
+1999-09-17  Jonathan Larmour  <jlarmour@cygnus.co.uk>
+
+	* src/hal_diag.c: Only avoid SERIAL0 if CYG_HAL_USE_ROM_MONITOR_CYGMON
+	since we default to assuming Cygmon
+
+	* include/variant.inc (hal_memc_init): Don't make conditional on
+	ROM startup - makes sense anyway so that users can change amount
+	of memory in system
+	(hal_memc_init_dram): Likewise
+
+	* include/var_arch.h (HAL_DIAG_IRQ_CHECK): Give extra return parameter
+	rather than relying on this being an expression which evaluates
+	
+1999-09-16  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	This set of changes with matching ones in arch comes from Mark
+	Salter's work to make jmr3904 CygMon talk Ethernet.
+
+	* include/variant.inc: Do not re-initialize and disable all
+	interrupts if RAM start, this stops networked CygMon working.
+	Likewise don't re-init memory.
+
+	* src/hal_diag.c: Add alternate hal_diag...() routines that talk
+	via CygMon so that ethernet debugging works.
+
+	* include/var_arch.h: If CYG_HAL_USE_ROM_MONITOR, export macro for
+	polling unknown interrupts in CygMon, HAL_DIAG_IRQ_CHECK.
+ 	
 1999-08-25  Nick Garnett  <nickg@cygnus.co.uk>
 
 	* include/variant.inc: Added clock-speed dependent values for the
--- a/packages/hal/mips/tx39/current/include/var_arch.h
+++ b/packages/hal/mips/tx39/current/include/var_arch.h
@@ -47,6 +47,16 @@
 #include <pkgconf/hal.h>
 #include <cyg/infra/cyg_type.h>
 
+#ifdef CYG_HAL_USE_ROM_MONITOR_CYGMON
+externC int
+hal_diag_irq_check(int vector);
+
+#define HAL_DIAG_IRQ_CHECK(_vector_, _ret_) \
+CYG_MACRO_START                             \
+_ret_ =  hal_diag_irq_check((_vector_));    \
+CYG_MACRO_END
+#endif
+
 //--------------------------------------------------------------------------
 #endif // CYGONCE_HAL_VAR_ARCH_H
 // End of var_arch.h
--- a/packages/hal/mips/tx39/current/include/variant.inc
+++ b/packages/hal/mips/tx39/current/include/variant.inc
@@ -157,10 +157,6 @@
 	.endm
 
 
-#if defined(CYG_HAL_STARTUP_ROM)
-
-	# Only do this in ROM configurations.
-
 	.macro hal_memc_init_dram	
 	# DRAM Configuration
 	la	v0, 0xffff8000
@@ -183,11 +179,6 @@
 	sw	v1, 0(v0)
 	.endm
 
-#else
-	.macro	hal_memc_init_dram
-	.endm	
-#endif
-
 #define CYGPKG_HAL_MIPS_MEMC_DEFINED
 		
 #endif	
@@ -201,12 +192,15 @@
 
 	# Set all ILRX registers to 0, masking all external interrupts.
 	.macro	hal_intc_init
+
+#ifndef CYG_HAL_STARTUP_RAM
 	la	v0,0xFFFFC010
 	move	v1,zero
 	sw	v1,0(v0)
 	sw	v1,4(v0)
 	sw	v1,8(v0)
 	sw	v1,12(v0)
+#endif
 	.endm
 
 	.macro	hal_intc_decode vnum
--- a/packages/hal/mips/tx39/current/src/hal_diag.c
+++ b/packages/hal/mips/tx39/current/src/hal_diag.c
@@ -55,10 +55,12 @@
 /*---------------------------------------------------------------------------*/
 
 //#define CYG_KERNEL_DIAG_LCD
-#define CYG_KERNEL_DIAG_SERIAL0
+#define CYG_KERNEL_DIAG_SERIAL0 // For ROM start but see immediately below:
 
-#if defined(CYG_HAL_USE_ROM_MONITOR)
-
+#if defined(CYG_HAL_USE_ROM_MONITOR_CYGMON)
+#undef CYG_KERNEL_DIAG_SERIAL0
+#undef CYG_KERNEL_DIAG_LCD
+#define CYG_KERNEL_DIAG_CYGMON
 #define CYG_KERNEL_DIAG_GDB
 
 #endif
@@ -85,7 +87,7 @@ void hal_diag_led(int x)
 
 /*---------------------------------------------------------------------------*/
 
-#ifdef CYG_KERNEL_DIAG_SERIAL0
+#if defined(CYG_KERNEL_DIAG_SERIAL0) || defined(CYG_KERNEL_DIAG_CYGMON)
 
 #define DIAG_BASE       0xfffff300
 #define DIAG_SLCR       (DIAG_BASE+0x00)
@@ -192,7 +194,11 @@ void hal_diag_read_char_serial0(char *c)
 }
 
 
+#if defined(CYG_KERNEL_DIAG_CYGMON)
+void hal_diag_dumb_write_char(char c)
+#else
 void hal_diag_write_char(char c)
+#endif
 {
 #ifdef CYG_KERNEL_DIAG_GDB    
 #if 0 //defined(CYG_HAL_USE_ROM_MONITOR)
@@ -250,8 +256,12 @@ void hal_diag_write_char(char c)
 
             if( c1 == '+' ) break;
 
-            if( cyg_hal_is_break( &c1 , 1 ) )
-                cyg_hal_user_break( NULL );    
+            {
+                extern void cyg_hal_user_break(CYG_ADDRWORD *regs);
+                extern cyg_bool cyg_hal_is_break(char *buf, int size);
+                if( cyg_hal_is_break( &c1 , 1 ) )
+                    cyg_hal_user_break( NULL );    
+            }
             
             break;
         }
@@ -272,6 +282,7 @@ void hal_diag_write_char(char c)
 #endif    
 }
 
+
 void hal_diag_read_char(char *c)
 {
     for(;;)
@@ -314,8 +325,263 @@ void hal_diag_read_char(char *c)
     }
 }
 
+#endif // defined(CYG_KERNEL_DIAG_SERIAL0) || defined(CYG_KERNEL_DIAG_CYGMON)
+
+
+#if defined(CYG_KERNEL_DIAG_CYGMON) // only
+
+/* This code has been imported from the BSP module. The definitions have
+ * been left as-is, even though there was scope for doing more, to avoid
+ * too much drift from the original sources
+ */
+
+struct bsp_comm_procs {
+    void *ch_data;
+    void (*__write)(void *ch_data, const char *buf, int len);
+    int  (*__read)(void *ch_data, char *buf, int len);
+    void (*__putc)(void *ch_data, char ch);
+    int  (*__getc)(void *ch_data);
+    int  (*__control)(void *ch_data, int func, ...);
+};
+
+// This is pointed to by entry BSP_NOTVEC_BSP_COMM_PROCS:
+typedef struct {
+    int  version;       /* version number for future expansion */
+    void *__ictrl_table;
+    void *__exc_table;
+    void *__dbg_vector;
+    void *__kill_vector;
+    struct bsp_comm_procs *__console_procs;
+    struct bsp_comm_procs *__debug_procs;
+    void *__flush_dcache;
+    void *__flush_icache;
+    void *__cpu_data;
+    void *__board_data;
+    void *__sysinfo;
+    int  (*__set_debug_comm)(int __comm_id);
+    int  (*__set_console_comm)(int __comm_id);
+    int  (*__set_serial_baud)(int __comm_id, int baud);
+    void *__dbg_data;
+    void (*__reset)(void);
+    int  __console_interrupt_flag;
+} bsp_shared_t;
+
+/*
+ * Core Exception vectors.
+ */
+#define BSP_EXC_INT	    0
+#define BSP_EXC_TLBMOD	    1
+#define BSP_EXC_TLBL	    2
+#define BSP_EXC_TLBS	    3
+#define BSP_EXC_ADEL	    4
+#define BSP_EXC_ADES	    5
+#define BSP_EXC_IBE         6
+#define BSP_EXC_DBE         7
+#define BSP_EXC_SYSCALL     8
+#define BSP_EXC_BREAK       9
+#define BSP_EXC_ILL        10
+#define BSP_EXC_CPU        11
+#define BSP_EXC_OV         12
+#define BSP_EXC_TRAP       13
+#define BSP_EXC_VCEI       14
+#define BSP_EXC_FPE        15
+#define BSP_EXC_RSV16      16
+#define BSP_EXC_RSV17      17
+#define BSP_EXC_RSV18      18
+#define BSP_EXC_RSV19      19
+#define BSP_EXC_RSV20      20
+#define BSP_EXC_RSV21      21
+#define BSP_EXC_RSV22      22
+#define BSP_EXC_WATCH      23
+#define BSP_EXC_RSV24      24
+#define BSP_EXC_RSV25      25
+#define BSP_EXC_RSV26      26
+#define BSP_EXC_RSV27      27
+#define BSP_EXC_RSV28      28
+#define BSP_EXC_RSV29      29
+#define BSP_EXC_RSV30      30
+#define BSP_EXC_VCED       31
+/* tx39 debug exception */
+#define BSP_EXC_DEBUG      32
+#define BSP_EXC_TLB        33
+#define BSP_EXC_NMI        34
+/*
+ * Hack for eCos on tx39 to set an async breakpoint.
+ */
+#define BSP_VEC_BP_HOOK    35
+
+#define BSP_EXC_XTLB	   36
+#define BSP_EXC_CACHE	   37
+
+#define BSP_MAX_EXCEPTIONS 38
+
+/*
+ * Another hack for tx39 eCos compatibility.
+ */
+#if defined(__CPU_R3900__)
+#define BSP_VEC_MT_DEBUG   15
+#else
+#define BSP_VEC_MT_DEBUG   38
 #endif
 
+#define BSP_VEC_STUB_ENTRY 39
+#define BSP_VEC_BSPDATA    40
+#define BSP_VEC_MAGIC      41
+#define BSP_VEC_IRQ_CHECK  42
+
+#define BSP_VEC_PAD        43
+#define NUM_VTAB_ENTRIES   44
+
+
+#define BSP_MAGIC_VAL      0x55aa4321
+
+#define SYS_interrupt 1000
+
+// These vectors should be called with:
+//
+//  k0 - Exception Number
+
+#define CYGMON_VECTOR_TABLE_BASE 0x80000100
+#define CYGMON_VECTOR_TABLE ((CYG_ADDRESS *)CYGMON_VECTOR_TABLE_BASE)
+
+#if 0 // UNUSED
+static int
+hal_bsp_set_debug_comm(int arg)
+{
+    bsp_shared_t *shared;
+
+    shared = (bsp_shared_t *)
+        (CYGMON_VECTOR_TABLE[ BSP_VEC_BSPDATA ]);
+
+    if (0 != shared->__set_debug_comm) {
+        return (*(shared->__set_debug_comm))(arg);
+    }
+    return 0;
+}
+
+static int
+hal_bsp_set_console_comm(int arg)
+{
+    bsp_shared_t *shared;
+
+    shared = (bsp_shared_t *)
+        (CYGMON_VECTOR_TABLE[ BSP_VEC_BSPDATA ]);
+
+    if (0 != shared->__set_console_comm) {
+        return (*(shared->__set_console_comm))(arg);
+    }
+    return 0;
+}
+#endif // 0 UNUSED
+
+static void bsp_trap(int trap_num);
+
+static int
+hal_bsp_console_write(const void *p, int len)
+{
+    bsp_shared_t *shared;
+    struct bsp_comm_procs *com;
+    int  magic;
+
+    /*hal_bsp_set_console_comm(0);*/
+
+    /* If this is not a BSP-based CygMon, return 0 */
+    magic = (int)(CYGMON_VECTOR_TABLE[ BSP_VEC_MAGIC ]);
+    if (magic != BSP_MAGIC_VAL)
+	return 0;
+
+    shared = (bsp_shared_t *)
+        (CYGMON_VECTOR_TABLE[ BSP_VEC_BSPDATA ]);
+
+    com = shared->__console_procs;
+
+    if (0 != com) {
+	shared->__console_interrupt_flag = 0;
+        com->__write(com->ch_data, p, len);
+	if (shared->__console_interrupt_flag) {
+	    /* debug interrupt; stop here */
+	    bsp_trap(SYS_interrupt);
+	}
+
+        return 1;
+    }
+    return 0;
+}
+
+static void
+bsp_trap(int trap_num)
+{
+    asm("syscall\n");
+}
+
+
+static void
+hal_dumb_serial_write(const char *p, int len)
+{
+    int i;
+    for ( i = 0 ; i < len; i++ ) {
+	hal_diag_dumb_write_char(p[i]);
+    }
+} 
+
+void hal_diag_write_char(char c)
+{
+    static char line[100];
+    static int pos = 0;
+
+    // No need to send CRs
+    if( c == '\r' ) return;
+
+    line[pos++] = c;
+
+    if( c == '\n' || pos == sizeof(line) ) {
+        CYG_INTERRUPT_STATE old;
+
+        // Disable interrupts. This prevents GDB trying to interrupt us
+        // while we are in the middle of sending a packet. The serial
+        // receive interrupt will be seen when we re-enable interrupts
+        // later.
+        
+        HAL_DISABLE_INTERRUPTS(old);
+        
+        if ( ! hal_bsp_console_write( line, pos ) )
+            // then there is no function registered, just spew it out serial
+            hal_dumb_serial_write( line, pos );
+        
+        pos = 0;
+
+        // And re-enable interrupts
+        HAL_RESTORE_INTERRUPTS(old);
+
+    }
+}
+
+int
+hal_diag_irq_check(int vector)
+{
+    typedef int irq_check_fn(int irq_nr);
+    irq_check_fn *fn = (irq_check_fn *)(CYGMON_VECTOR_TABLE[ BSP_VEC_IRQ_CHECK ]);
+    int  magic;
+    
+
+    /* If this is not a BSP-based CygMon, return 0 */
+    magic = (int)(CYGMON_VECTOR_TABLE[ BSP_VEC_MAGIC ]);
+    if (magic != BSP_MAGIC_VAL)
+	return 0;
+
+#if defined(CYGPKG_HAL_MIPS_TX3904)
+    /* convert vector to BSP irq number */
+    if (vector == 16)
+	vector = 2;
+    else
+	vector += 3;
+#endif
+
+    return fn(vector);
+}
+
+#endif // defined(CYG_KERNEL_DIAG_CYGMON) *only*
+
 /*---------------------------------------------------------------------------*/
 
 #if defined(CYGPKG_HAL_MIPS_TX39_JMR3904) && defined(CYG_KERNEL_DIAG_LCD)
--- a/packages/hal/powerpc/arch/current/ChangeLog
+++ b/packages/hal/powerpc/arch/current/ChangeLog
@@ -1,3 +1,14 @@
+1999-09-23  Jonathan Larmour  <jlarmour@cygnus.co.uk>
+
+	* src/hal_misc.c (cyg_hal_exception_handler): Catch exceptions
+	generated from within the GDB stub so we can recover from bad memory
+	accesses
+	Also part of the fix for case 102104
+
+1999-09-23  Jesper Skov  <jskov@cygnus.co.uk>
+        Case 102104
+	* include/hal_cache.h (HAL_ICACHE_SYNC): Invalidate I cache.
+
 1999-09-06  Jesper Skov  <jskov@cygnus.co.uk>
 
 	* src/hal_misc.c (hal_null_call): 
--- a/packages/hal/powerpc/arch/current/include/hal_cache.h
+++ b/packages/hal/powerpc/arch/current/include/hal_cache.h
@@ -475,7 +475,8 @@ externC cyg_memdesc_t cyg_hal_mem_map[];
                       "r" (CYGARC_REG_IC_CMD_IA))
 
 // Synchronize the contents of the cache with memory.
-#define HAL_ICACHE_SYNC()
+#define HAL_ICACHE_SYNC()                               \
+    HAL_ICACHE_INVALIDATE_ALL()
 
 // Query the state of the instruction cache
 #define HAL_ICACHE_IS_ENABLED(_state_)                          \
--- a/packages/hal/powerpc/arch/current/src/hal_misc.c
+++ b/packages/hal/powerpc/arch/current/src/hal_misc.c
@@ -103,11 +103,20 @@ externC void __handle_exception (void);
 
 externC HAL_SavedRegisters *_hal_registers;
 
+externC void *__mem_fault_handler;
+
 void
 cyg_hal_exception_handler(HAL_SavedRegisters *regs)
 {
 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
 
+    // If we caught an exception inside the stubs, see if we were expecting it
+    // and if so jump to the saved address
+    if (__mem_fault_handler) {
+        regs->pc = (CYG_ADDRWORD)__mem_fault_handler;
+        return; // Caught an exception inside stubs        
+    }
+
     // Set the pointer to the registers of the current exception
     // context. At entry the GDB stub will expand the
     // HAL_SavedRegisters structure into a (bigger) register array.
--- a/packages/hal/powerpc/arch/current/src/vectors.S
+++ b/packages/hal/powerpc/arch/current/src/vectors.S
@@ -378,7 +378,7 @@ 2:
         .extern hal_MMU_init
         bl      hal_MMU_init
 
-        # Enable MMU it so we can safely enable caches.
+        # Enable MMU so we can safely enable caches.
         lwi     r3,CYG_MSR_NO_INTS              # interrupts enabled later
         sync
         mtmsr   r3
--- a/packages/hal/powerpc/mbx/current/ChangeLog
+++ b/packages/hal/powerpc/mbx/current/ChangeLog
@@ -1,3 +1,19 @@
+1999-09-20  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* include/pkgconf/hal_powerpc_mbx.h:
+	(CYGHWR_HAL_POWERPC_MBX_BOOT_32BIT_FLASH) new config option to
+	control chip select initialization.
+	
+	* src/mbx.S: Take notice of CYGHWR_HAL_POWERPC_MBX_BOOT_32BIT_FLASH.
+
+	* misc/stubrom.perm: Reference the new option for folks who want
+	to boot from the 32-bit flash.
+
+1999-09-13  Gary Thomas  <gthomas@cygnus.co.uk>
+
+	* include/pkgconf/hal_powerpc_mbx.h (CYGHWR_HAL_POWERPC_BOARD_SPEED): 
+	Missing default value (wouldn't build sans ConfigTool).
+
 1999-09-09  Gary Thomas  <gthomas@cygnus.co.uk>
 
 	* include/pkgconf/hal_powerpc_mbx.h (CYGHWR_HAL_POWERPC_MBX_BOARD_SPEED): 
--- a/packages/hal/powerpc/mbx/current/include/pkgconf/hal_powerpc_mbx.h
+++ b/packages/hal/powerpc/mbx/current/include/pkgconf/hal_powerpc_mbx.h
@@ -85,11 +85,29 @@
        # setting it to 30, for example, would not work.
    }
 
+   cdl_option CYGHWR_HAL_POWERPC_MBX_BOOT_32BIT_FLASH {
+       display          "Boot ROM is 32-bit Flash device"
+       parent           CYGPKG_HAL_POWERPC_MBX
+       type             boolean
+       description      "
+           MBX Development Boards have a socketed 8-bit ROM (AM27F040,
+           AM29F040 or similar) and a permanently soldered 32-bit flash
+           device.  Which is used for booting is link selectable (refer to
+           the MBX Series documentation from Motorola).  Enable this option
+           when booting from the 32-bit flash so that the correct memory
+           timing and access method is initialized.  This consideration
+           does apply to RAM start eCos applications as well as ROM start
+           or stub ROMs."
+   }
+
    }}CFG_DATA */
 
 #define CYGHWR_HAL_POWERPC_MBX_STARTUP       ram
 
-#define CYGHWR_HAL_POWERPC_MBX_BOARD_SPEED   50
+#define CYGHWR_HAL_POWERPC_BOARD_SPEED       50
+
+// Normally, the 8-bit socketed ROM is used
+#undef CYGHWR_HAL_POWERPC_MBX_BOOT_32BIT_FLASH
 
 // Real-time clock/counter specifics
 
--- a/packages/hal/powerpc/mbx/current/misc/stubrom.perm
+++ b/packages/hal/powerpc/mbx/current/misc/stubrom.perm
@@ -8,6 +8,11 @@
 #    Where <SOURCEDIR> is the path to your source repository.
 #    (If necessary, make sure the system clock speed is set correctly in
 #     pkgconf/hal_powerpc_mbx.h:  40MHz (MPC821) versus 50MHz (MPC860) by default)
+#    If you do not have permtest, use the config tool or an editor to make
+#    the changes listed below to the relevant configuration files.
+#    If you intend to install the image into the 32-bit flash device instead of
+#    the 8-bit socketed ROM, set the option CYGHWR_HAL_POWERPC_MBX_BOOT_32BIT_FLASH
+#    in hal_powerpc_mbx.h
 # 3. Run: make
 # 4. Run: make -C hal/common/current/src/stubrom
 #
--- a/packages/hal/powerpc/mbx/current/src/mbx.S
+++ b/packages/hal/powerpc/mbx/current/src/mbx.S
@@ -262,9 +262,14 @@ FUNC_START( hal_hardware_init )
 #else
         lwi	r5,0xff800930
 #endif
+#ifdef CYGHWR_HAL_POWERPC_MBX_BOOT_32BIT_FLASH
+	// Then the 32-bit FLASH device is on CS0, the "ROM" is on CS7
+        stw	r3,BR7(r4)
+        stw	r5,OR7(r4)
+#else	// Boot from 8-bit ROM - the default, on CS0
         stw	r3,BR0(r4)
         stw	r5,OR0(r4)
-
+#endif
 	/* ONBOARD DRAM */
         lwi	r3,0x00000081	# 32-bit, UPMA
         lwi	r5,0xffc00400
@@ -312,9 +317,14 @@ FUNC_START( hal_hardware_init )
 #else
         lwi	r5,0xff800930
 #endif
+#ifdef CYGHWR_HAL_POWERPC_MBX_BOOT_32BIT_FLASH
+	// Then the 32-bit FLASH device is on CS0, the "ROM" is on CS7
+        stw	r3,BR0(r4)
+        stw	r5,OR0(r4)
+#else	// Boot from 8-bit ROM - so the 32-bit FLASH is on CS7
         stw	r3,BR7(r4)
         stw	r5,OR7(r4)
-	
+#endif
 	/*
 	 *  SYSTEM CLOCK CONTROL REGISTER
 	 *
--- a/packages/hal/powerpc/sim/current/ChangeLog
+++ b/packages/hal/powerpc/sim/current/ChangeLog
@@ -1,3 +1,7 @@
+1999-09-23  Jonathan Larmour  <jlarmour@cygnus.co.uk>
+
+	* runtime/tree: Delete. Now obsolete.
+
 1999-06-11  Hugo Tyson  <hmt@cygnus.co.uk>
 
 	* src/PKGconf.mak: Build the new file.
deleted file mode 100644
--- a/packages/hal/powerpc/sim/current/runtime/tree
+++ /dev/null
@@ -1,5 +0,0 @@
-/#address-cells 1
-/openprom/init/register/pc 0x100
-/iobus@0xf0000000/reg 0xf0000000 0x01000000
-/iobus/pal@0xf0001000/reg 0xf0001000 32
-
--- a/packages/io/serial/current/src/PKGconf.mak
+++ b/packages/io/serial/current/src/PKGconf.mak
@@ -40,7 +40,7 @@ endif
 ifdef CYG_HAL_ARM_AEB
 EXTRAS_COMPILE  += arm/aeb_serial.c
 endif
-ifdef CYG_HAL_ARM_CL7211
+ifdef CYG_HAL_ARM_EB7211
 EXTRAS_COMPILE  += arm/cl7211_serial.c
 endif
 ifdef CYG_HAL_MN10300_AM31
--- a/packages/kernel/current/ChangeLog
+++ b/packages/kernel/current/ChangeLog
@@ -1,3 +1,25 @@
+1999-09-16  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* tests/tm_basic.cxx (run_mutex_tests): Must unlock mutices before
+	destroying, given the change below.
+
+	* src/common/kapi.cxx (cyg_cond_destroy): Call the correct
+	destructor.  As it happens, it didn't matter because all these
+	destructors do is assert the queue is empty, and the queue is the
+	2nd word in every case.
+	(cyg_mutex_destroy): Call the destructor at all, so that
+	assertions are made.
+
+1999-09-13  Gary Thomas  <gthomas@cygnus.co.uk>
+
+	* src/intr/intr.cxx (call_pending_DSRs_inner): Add assert to check
+	for valid DSR (before trying to use it).
+
+1999-09-13  Jesper Skov  <jskov@cygnus.co.uk>
+
+	* tests/stress_threads.c: Print out malloc system info.
+	(print_statistics): Fix buglet.
+
 1999-09-10  Jesper Skov  <jskov@cygnus.co.uk>
 
 	* tests/stress_threads.c: Print out more info. Reduce dump
--- a/packages/kernel/current/src/common/kapi.cxx
+++ b/packages/kernel/current/src/common/kapi.cxx
@@ -1005,7 +1005,7 @@ externC void cyg_mutex_init(
 
 externC void cyg_mutex_destroy( cyg_mutex_t *mutex )
 {
-    // no need to do anything here
+    ((Cyg_Mutex *)mutex)->~Cyg_Mutex();
 }
 
 externC cyg_bool_t cyg_mutex_lock( cyg_mutex_t *mutex )
@@ -1045,7 +1045,7 @@ externC void cyg_cond_init(
 
 externC void cyg_cond_destroy( cyg_cond_t *cond )
 {
-    ((Cyg_Counting_Semaphore *)cond)->~Cyg_Counting_Semaphore();
+    ((Cyg_Condition_Variable *)cond)->~Cyg_Condition_Variable();
 }
 
 externC void cyg_cond_wait( cyg_cond_t *cond )
--- a/packages/kernel/current/src/intr/intr.cxx
+++ b/packages/kernel/current/src/intr/intr.cxx
@@ -147,6 +147,8 @@ Cyg_Interrupt::call_pending_DSRs_inner(v
 
         CYG_INSTRUMENT_INTR(CALL_DSR, intr->vector, 0);
         
+        CYG_ASSERT( intr->dsr != NULL , "No DSR defined");
+
         intr->dsr( intr->vector, 1, (CYG_ADDRWORD)intr->data );
     }
     
@@ -168,6 +170,8 @@ Cyg_Interrupt::call_pending_DSRs_inner(v
         intr->dsr_count = 0;
         
         HAL_RESTORE_INTERRUPTS(old_intr);
+        
+        CYG_ASSERT( intr->dsr != NULL , "No DSR defined");
 
         intr->dsr( intr->vector, count, (CYG_ADDRWORD)intr->data );
         
--- a/packages/kernel/current/tests/stress_threads.c
+++ b/packages/kernel/current/tests/stress_threads.c
@@ -165,16 +165,23 @@ volatile int free_handler_pri = 0;
 volatile int free_handler_id = -1;
 
 /* a global variable with which the client and server coordinate */
-int client_makes_request = 0;
+volatile int client_makes_request = 0;
+
+/* if this is true, clients will not make requests */
+volatile int clients_paused = 0;
+
 
 /* indicates that it's time to print out a report */
-int time_to_report = 0;
+volatile int time_to_report = 0;
 /* print status after a delay of this many secs. */
 int time_report_delay;
 
 /*** now application-specific variables ***/
 /* an array that stores whether the handler threads are in use */
-int handler_thread_in_use[MAX_HANDLERS];
+volatile int handler_thread_in_use[MAX_HANDLERS];
+/* total count of active handlers */
+volatile int handler_thread_in_use_count;
+
 
 /***** statistics-gathering variables *****/
 struct s_statistics {
@@ -204,7 +211,8 @@ void sc_thread_create(
     cyg_thread          *thread                 /* put thread here           */
     );
 
-int get_handler_slot(cyg_handle_t current_threadH);
+void start_handler(void);
+void stop_handler(int handler_id, int handler_pri);
 void perform_stressful_tasks(void);
 void permute_array(char a[], int size, int seed);
 void setup_death_alarm(cyg_addrword_t data, cyg_handle_t *deathHp,
@@ -251,6 +259,7 @@ main(void)
     for (i = 0; i < MAX_HANDLERS; ++i) {
         handler_thread_in_use[i] = 0;
     }
+    handler_thread_in_use_count = 0;
     for (i = 0; i < N_LISTENERS; ++i) {
         int prio = P_BASE_LISTENER + i;
         char* name = &thread_name[prio][0];
@@ -327,34 +336,34 @@ void main_program(cyg_addrword_t data)
         } cyg_mutex_unlock(&free_handler_lock);
 
         if (-1 != handler_id) {
-            // Free the handler resources. This is done outside of the
-            // free_handler_lock to avoid deadlocks.
-            cyg_mutex_lock(&handler_slot_lock); {
-                CYG_ASSERT(1 == priority_in_use[handler_pri], 
-                           "Priority not in use!");
-                CYG_ASSERT(1 == handler_thread_in_use[handler_id], 
-                           "Handler not in use!");
-                handler_thread_in_use[handler_id]--;
-                priority_in_use[handler_pri]--;
-
-                // Finally delete the handler thread. This must be done in a
-                // loop, waiting for the call to return true. If it returns
-                // false, go to sleep for a bit, so the killed thread gets a
-                // chance to run and complete its business.
-                while (!cyg_thread_delete(handlerH[handler_id])) {
-                    cyg_thread_delay(2);
-                }
-            } cyg_mutex_unlock(&handler_slot_lock);
+            stop_handler(handler_id, handler_pri);
         }
 
-        // Print status if time.
+        // If it's time to report status or quit, set pause flag and
+        // keep looping until all handlers have stopped.
         if (time_to_report) {
-            time_to_report = 0;
-            print_statistics(0);
+            // Pause clients
+            cyg_mutex_lock(&client_request_lock); {
+                clients_paused = 1;
+            } cyg_mutex_unlock(&client_request_lock);
+
+            // When all handlers have stopped, we can print statistics
+            // knowing that all (handler allocated) resources should have
+            // been freed. That is, we should be able to determine leaks.
+            if (0 == handler_thread_in_use_count) {
+                print_statistics(0);
+
+                // We've done the printing now. Resume the system.
+                time_to_report = 0;
+                cyg_mutex_lock(&client_request_lock); {
+                    clients_paused = 0;
+                } cyg_mutex_unlock(&client_request_lock);
+            } 
         }
 
 #ifdef DEATH_TIME_LIMIT
-        // Stop test if time.
+        // Stop test if time. We don't care about resource state here
+        // since we've only run for a limited time anyway.
         if (is_dead) {
             print_statistics(1);
             CYG_TEST_PASS_FINISH("Kernel thread stress test OK");
@@ -378,7 +387,8 @@ void client_program(cyg_addrword_t data)
 
         /* now send a request to the server */
         cyg_mutex_lock(&client_request_lock); {
-            ++client_makes_request;
+            if (0 == clients_paused)
+                client_makes_request++;
         } cyg_mutex_unlock(&client_request_lock);
 
         cyg_thread_delay(10+delay);
@@ -389,9 +399,6 @@ void client_program(cyg_addrword_t data)
    take care of the request */
 void listener_program(cyg_addrword_t data)
 {
-/*   int message = (int) data; */
-    int handler_slot;
-
     for (;;) {
         int make_request = 0;
         cyg_mutex_lock(&client_request_lock); {
@@ -401,27 +408,9 @@ void listener_program(cyg_addrword_t dat
             }
         } cyg_mutex_unlock(&client_request_lock);
         
-        if (make_request) {
-            int prio;
-            char* name;
-
-            handler_slot = get_handler_slot(listenerH[(int) data]);
-            prio = P_BASE_HANDLER+handler_slot;
-
-            name = &thread_name[prio][0];
-            sprintf(name, "handler-%02d/%02d", handler_slot, prio);
-
-            CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!");
-            priority_in_use[prio]++;
-            sc_thread_create(prio, handler_program,
-                             (cyg_addrword_t) handler_slot,
-                             name, (void *) handler_stack[handler_slot],
-                             STACK_SIZE_HANDLER, &handlerH[handler_slot],
-                             &handler_thread_s[handler_slot]);
-            cyg_thread_resume(handlerH[handler_slot]);
-            ++statistics.handler_invocation_histogram[handler_slot];
-        }
-
+        if (make_request)
+            start_handler();
+        
         cyg_thread_delay(2 + (rand() % 10));
     }
 }
@@ -434,7 +423,6 @@ void handler_program(cyg_addrword_t data
 
     cyg_thread_delay(4 + (int) (0.5*log(1.0 + fabs((rand() % 1000000)))));
 
-    ++statistics.thread_exits;
     {
         // Loop until the handler id and priority can be communicated to
         // the main_program.
@@ -456,18 +444,21 @@ void handler_program(cyg_addrword_t data
     cyg_thread_exit();
 }
 
-/* look for an available handler thread */
-int get_handler_slot(cyg_handle_t current_threadH)
+/* start a new handler */
+void start_handler(void)
 {
-    int i;
+    int prio;
+    char* name;
+    int handler_slot;
     int found = 0;
 
     while (!found) {
         cyg_mutex_lock(&handler_slot_lock); {
-            for (i = 0; i < MAX_HANDLERS; ++i) {
-                if (!handler_thread_in_use[i]) {
+            for (handler_slot = 0; handler_slot < MAX_HANDLERS;++handler_slot){
+                if (!handler_thread_in_use[handler_slot]) {
                     found = 1;
-                    handler_thread_in_use[i]++;
+                    handler_thread_in_use[handler_slot]++;
+                    handler_thread_in_use_count++;
                     break;
                 }
             }
@@ -476,27 +467,66 @@ int get_handler_slot(cyg_handle_t curren
             cyg_thread_delay(1);
     }
 
-    CYG_ASSERT(1 == handler_thread_in_use[i], "Handler usage count wrong!");
+    CYG_ASSERT(1 == handler_thread_in_use[handler_slot], 
+               "Handler usage count wrong!");
+
+    prio = P_BASE_HANDLER+handler_slot;
+    CYG_ASSERT(0 == priority_in_use[prio], "Priority already in use!");
+    priority_in_use[prio]++;
+
+    name = &thread_name[prio][0];
+    sprintf(name, "handler-%02d/%02d", handler_slot, prio);
+
+    sc_thread_create(prio, handler_program,
+                     (cyg_addrword_t) handler_slot,
+                     name, (void *) handler_stack[handler_slot],
+                     STACK_SIZE_HANDLER, &handlerH[handler_slot],
+                     &handler_thread_s[handler_slot]);
+    cyg_thread_resume(handlerH[handler_slot]);
+    ++statistics.handler_invocation_histogram[handler_slot];
+}
 
-    return i;
+/* free a locked handler thread */
+void stop_handler(int handler_id, int handler_pri)
+{
+    // Finally delete the handler thread. This must be done in a
+    // loop, waiting for the call to return true. If it returns
+    // false, go to sleep for a bit, so the killed thread gets a
+    // chance to run and complete its business.
+    while (!cyg_thread_delete(handlerH[handler_id])) {
+        cyg_thread_delay(1);
+    }
+    ++statistics.thread_exits;
+    
+    // Free the handler resources.
+    cyg_mutex_lock(&handler_slot_lock); {
+        handler_thread_in_use[handler_id]--;
+        handler_thread_in_use_count--;
+        priority_in_use[handler_pri]--;
+        CYG_ASSERT(0 == priority_in_use[handler_pri], 
+                   "Priority not in use!");
+        CYG_ASSERT(0 == handler_thread_in_use[handler_id], 
+                   "Handler not in use!");
+        CYG_ASSERT(0 <= handler_thread_in_use_count, 
+                   "Stopped more handlers than was started!");
+    } cyg_mutex_unlock(&handler_slot_lock);
+        
 }
 
+
 /* do things which will stress the system */
 void perform_stressful_tasks()
 {
 #define MAX_MALLOCED_SPACES 100  /* do this many mallocs at most */
 #define MALLOCED_BASE_SIZE 1    /* basic size in bytes */
     char *spaces[MAX_MALLOCED_SPACES];
-    unsigned int i;
-
-    cyg_mutex_t tmp_lock;
+    int  sizes[MAX_MALLOCED_SPACES];
+    unsigned int i, j, size;
 
     cyg_uint8 pool_space[10][100];
     cyg_handle_t mempool_handles[10];
     cyg_mempool_fix mempool_objects[10];
 
-    cyg_mutex_init(&tmp_lock);
-
     /* here I use malloc, which uses the kernel's variable memory pools.
        note that malloc/free is a bit simple-minded here: it does not
        try to really fragment things, and it does not try to make the
@@ -504,8 +534,17 @@ void perform_stressful_tasks()
        (although I'm about to throw in a yield()) */
     for (i = 0; i < MAX_MALLOCED_SPACES; ++i) {
         ++statistics.malloc_tries;
-/*      spaces[i] = (char *) malloc(((int)(sqrt(i*2.0))+1)*MALLOCED_BASE_SIZE); */
-        spaces[i] = (char *) malloc(((int)i*2.0+1)*MALLOCED_BASE_SIZE);
+        size = (i*2+1)*MALLOCED_BASE_SIZE;
+        spaces[i] = (char *) malloc(size);
+        sizes[i] = size;
+
+        if (spaces[i] != NULL) {
+            // Fill with a known value (differs between chunk).
+            for (j = 0; j < size; ++j) {
+                spaces[i][j] = 0x50 | ((j+i) & 0x0f);
+            }
+        }
+
         if (i % (MAX_MALLOCED_SPACES/10) == 0) {
             cyg_thread_yield();
         }
@@ -514,11 +553,17 @@ void perform_stressful_tasks()
         }
     }
 
+    cyg_thread_delay(5);
+
     /* now free it all up */
     for (i = 0; i < MAX_MALLOCED_SPACES; ++i) {
         if (spaces[i] != NULL) {
-            unsigned int j;
-            for (j = 0; j < (i*2+1)*MALLOCED_BASE_SIZE; ++j) {
+            size = sizes[i];
+            for (j = 0; j < size; ++j) {
+                // Validate chunk data.
+                if ((0x50 | ((j+i) & 0x0f)) != spaces[i][j]) {
+                    printf("Bad byte in chunk\n");
+                }
                 spaces[i][j] = 0xAA;    /* write a bit pattern */
             }
             free(spaces[i]);
@@ -526,6 +571,7 @@ void perform_stressful_tasks()
             ++statistics.malloc_failures;
         }
     }
+
     /* now allocate and then free some fixed-size memory pools; for
        now this is simple-minded because it does not have many threads
        sharing the memory pools and racing for memory. */
@@ -543,8 +589,6 @@ void perform_stressful_tasks()
             cyg_mempool_fix_delete(mempool_handles[i]);
         }
     }
-
-    cyg_mutex_destroy(&tmp_lock);
 }
 
 /* report_alarm_func() is invoked as an alarm handler, so it should be
@@ -622,7 +666,7 @@ void sc_thread_create(
 
 #define MINS_HOUR (60)
 #define MINS_DAY  (60*24)
-externC void *cyg_libc_get_pool( void );
+externC void *cyg_libc_get_malloc_pool( void );
 
 void print_statistics(int print_full)
 {
@@ -660,7 +704,8 @@ void print_statistics(int print_full)
     }
 
     printf("\nState dump %d (%d hours, %d minutes) [numbers >>%d]\n",
-           ++print_count, minutes / MINS_HOUR, minutes, shift_count);
+           ++print_count, minutes / MINS_HOUR, minutes % MINS_HOUR, 
+           shift_count);
 
     cyg_mutex_lock(&statistics_print_lock); {
         //--------------------------------
@@ -683,24 +728,18 @@ void print_statistics(int print_full)
             statistics.malloc_tries >>= 1;
             statistics.malloc_failures >>= 1;
         }
+    } cyg_mutex_unlock(&statistics_print_lock);
 
-        //--------------------------------
-        // System information
-#if 0
-        // We want to (occasionally) pause the test so all memory is
-        // freed. Otherwise it's hard to tell if there's a malloc
-        // leak.
-        {
-            cyg_mempool_info mem_info;
+    //--------------------------------
+    // System information
+    {
+        cyg_mempool_info mem_info;
 
-            cyg_mempool_var_get_info((cyg_handle_t) cyg_libc_get_pool(), 
-                                     &mem_info);
-            printf(" Memory system: Total=0x%08x Free=0x%08x Max=0x%08x\n", 
-                   mem_info.totalmem, mem_info.freemem, mem_info.maxfree);
-        }
-#endif
-
-    } cyg_mutex_unlock(&statistics_print_lock);
+        cyg_mempool_var_get_info((cyg_handle_t) cyg_libc_get_malloc_pool(), 
+                                 &mem_info);
+        printf(" Memory system: Total=0x%08x Free=0x%08x Max=0x%08x\n", 
+               mem_info.totalmem, mem_info.freemem, mem_info.maxfree);
+    }
 
     // Dump stack status
     printf(" Stack usage:\n");
--- a/packages/kernel/current/tests/tm_basic.cxx
+++ b/packages/kernel/current/tests/tm_basic.cxx
@@ -744,6 +744,11 @@ run_mutex_tests(void)
     }
     show_times(mutex_ft, nmutexes, "Trylock [locked] mutex");
 
+    // Must unlock mutices before destroying them.
+    for (i = 0;  i < nmutexes;  i++) {
+        cyg_mutex_unlock(&test_mutexes[i]);
+    }
+
     wait_for_tick(); // Wait until the next clock tick to minimize aberations
     for (i = 0;  i < nmutexes;  i++) {
         HAL_CLOCK_READ(&mutex_ft[i].start);
--- a/packages/language/c/libc/current/ChangeLog
+++ b/packages/language/c/libc/current/ChangeLog
@@ -1,3 +1,8 @@
+1999-09-15  Jesper Skov  <jskov@cygnus.co.uk>
+
+	* tests/signal/signal2.c (cause_fpe): Try both float and integer
+	division by zero.
+
 1999-09-10  Jesper Skov  <jskov@cygnus.co.uk>
 
 	* src/stdlib/malloc.cxx (cyg_libc_get_malloc_pool): Added for
--- a/packages/language/c/libc/current/tests/signal/signal2.c
+++ b/packages/language/c/libc/current/tests/signal/signal2.c
@@ -108,10 +108,19 @@ cause_memerror(void)
 
 // num must always be 0 - do it this way in case the optimizer tries to
 // get smart
-static double
+static int
 cause_fpe(int num)
 {
-    return 1.0/num;
+    double a;
+
+    a = 1.0/num;                        // Depending on FPU emulation and/or
+                                        // the FPU architecture, this may
+                                        // cause an exception.
+                                        // (float division by zero)
+
+    return ((int)a)/num;                // This may cause an exception if
+                                        // the architecture supports it.
+                                        // (integer division by zero).
 } // cause_fpe()
 
 #endif