changeset 110:84e4bde58b26 ecos-sw-2000-07-14

Merge from eCos master repository on 2000-07-14-22:00:02-BST
author jlarmour
date Mon, 17 Jul 2000 14:42:27 +0000
parents 5720c4b6e1d2
children 211b8a635ce9
files host/libcdl/ChangeLog host/libcdl/conflict.cxx host/tools/configtool/standalone/common/ChangeLog host/tools/configtool/standalone/common/cdl_exec.cxx packages/ChangeLog packages/cygmon/current/misc/arm/board.h packages/ecos.db packages/hal/arm/arch/current/ChangeLog packages/hal/arm/arch/current/src/arm_stub.c packages/hal/arm/arch/current/src/hal_misc.c packages/hal/arm/arch/current/src/vectors.S packages/hal/arm/cma230/current/ChangeLog packages/hal/arm/cma230/current/cdl/hal_arm_cma230.cdl packages/hal/arm/cma230/current/include/hal_diag.h packages/hal/arm/cma230/current/include/plf_stub.h packages/hal/arm/cma230/current/src/cma230_misc.c packages/hal/arm/cma230/current/src/hal_diag.c packages/hal/arm/ebsa285/current/ChangeLog packages/hal/arm/ebsa285/current/cdl/hal_arm_ebsa285.cdl packages/hal/arm/ebsa285/current/include/hal_diag.h packages/hal/arm/ebsa285/current/include/hal_platform_ints.h packages/hal/arm/ebsa285/current/include/plf_stub.h packages/hal/arm/ebsa285/current/src/ebsa285_misc.c packages/hal/arm/ebsa285/current/src/hal_diag.c packages/hal/arm/edb7xxx/current/ChangeLog packages/hal/arm/edb7xxx/current/cdl/hal_arm_edb7xxx.cdl packages/hal/arm/edb7xxx/current/include/hal_diag.h packages/hal/arm/edb7xxx/current/include/hal_platform_setup.h packages/hal/arm/edb7xxx/current/include/plf_stub.h packages/hal/arm/edb7xxx/current/src/edb7xxx_misc.c packages/hal/arm/edb7xxx/current/src/hal_diag.c packages/hal/arm/pid/current/ChangeLog packages/hal/arm/pid/current/cdl/hal_arm_pid.cdl packages/hal/arm/pid/current/src/hal_diag.c packages/hal/arm/sa11x0/assabet/current/ChangeLog packages/hal/arm/sa11x0/assabet/current/cdl/hal_arm_sa11x0_assabet.cdl packages/hal/arm/sa11x0/brutus/current/ChangeLog packages/hal/arm/sa11x0/brutus/current/cdl/hal_arm_sa11x0_brutus.cdl packages/hal/arm/sa11x0/var/current/ChangeLog packages/hal/arm/sa11x0/var/current/include/hal_diag.h packages/hal/arm/sa11x0/var/current/src/hal_diag.c packages/hal/arm/sa11x0/var/current/src/sa11x0_misc.c packages/hal/common/current/ChangeLog packages/hal/common/current/cdl/debugging.cdl packages/hal/common/current/src/hal_if.c packages/hal/common/current/src/hal_stub.c packages/hal/sh/arch/current/ChangeLog packages/hal/sh/arch/current/cdl/hal_sh.cdl packages/hal/sh/arch/current/include/hal_intr.h packages/hal/sh/arch/current/include/sh_regs.h packages/hal/sh/cq7708/current/ChangeLog packages/hal/sh/cq7708/current/cdl/hal_sh_sh7708_cq7708.cdl packages/hal/sh/cq7708/current/src/hal_diag.c packages/hal/sh/edk/current/ChangeLog packages/hal/sh/edk/current/cdl/hal_sh_edk7708.cdl packages/net/drivers/eth/common/current/src/eth_drv.c packages/net/snmp/agent/current/ChangeLog packages/net/snmp/agent/current/tests/snmpping.c packages/net/tcpip/current/ChangeLog packages/net/tcpip/current/cdl/net.cdl packages/net/tcpip/current/include/bootp.h packages/net/tcpip/current/include/dhcp.h packages/net/tcpip/current/include/netdev.h packages/net/tcpip/current/include/sys/param.h packages/net/tcpip/current/src/ecos/support.c packages/net/tcpip/current/src/lib/bootp_support.c packages/net/tcpip/current/src/lib/dhcp_prot.c packages/net/tcpip/current/src/lib/dhcp_support.c packages/net/tcpip/current/src/lib/network_support.c packages/net/tcpip/current/src/sys/net/if.c packages/net/tcpip/current/tests/dhcp_test.c packages/net/tcpip/current/tests/flood.c packages/net/tcpip/current/tests/ftp_test.c packages/net/tcpip/current/tests/nc_test_master.c packages/net/tcpip/current/tests/nc_test_slave.c packages/net/tcpip/current/tests/ping_lo_test.c packages/net/tcpip/current/tests/ping_test.c packages/net/tcpip/current/tests/server_test.c packages/net/tcpip/current/tests/set_mac_address.c packages/net/tcpip/current/tests/tcp_echo.c packages/net/tcpip/current/tests/tftp_client_test.c packages/net/tcpip/current/tests/tftp_server_test.c
diffstat 82 files changed, 4066 insertions(+), 766 deletions(-) [+]
line wrap: on
line diff
--- a/host/libcdl/ChangeLog
+++ b/host/libcdl/ChangeLog
@@ -1,3 +1,9 @@
+2000-07-06  Bart Veer  <bartv@redhat.com>
+
+	* conflict.cxx (get_explanation):
+	Put quotes around "requires" in the conflict explanation.
+	Requested by the eCos team.
+
 2000-07-04  Bart Veer  <bartv@redhat.com>
 
 	* value.cxx (save):
--- a/host/libcdl/conflict.cxx
+++ b/host/libcdl/conflict.cxx
@@ -909,7 +909,7 @@ CdlConflict_RequiresBody::get_explanatio
     CYG_ASSERTC(0 != gexpr);
     
     std::string result = "";
-    result += "Requires constraint not satisfied: " + gexpr->get_original_string();
+    result += "\"requires\" constraint not satisfied: " + gexpr->get_original_string();
 
     CYG_REPORT_RETURN();
     return result;
--- a/host/tools/configtool/standalone/common/ChangeLog
+++ b/host/tools/configtool/standalone/common/ChangeLog
@@ -1,3 +1,8 @@
+2000-07-07  Bart Veer  <bartv@redhat.com>
+
+	* cdl_exec.cxx (transaction_callback):
+	Output the correct value irrespective of the option flavor.
+
 2000-06-28  Bart Veer  <bartv@redhat.com>
 
 	* cdl_exec.cxx, cdl_exec.hxx, ecosconfig.cxx:
--- a/host/tools/configtool/standalone/common/cdl_exec.cxx
+++ b/host/tools/configtool/standalone/common/cdl_exec.cxx
@@ -662,8 +662,11 @@ cdl_exec::transaction_callback(const Cdl
     for (i = 0; i < callback_data.value_changes.size(); i++) {
         CdlValuable valuable = callback_data.value_changes[i];
         if (CdlValueSource_Inferred == valuable->get_source()) {
+            CdlEvalContext context(0, valuable, 0);
+            CdlSimpleValue simple_val;
+            CdlSimpleValue::eval_valuable(context, valuable, simple_val);
             std::string msg = std::string("U ") + valuable->get_name() + ", new inferred value ";
-            std::string value = valuable->get_value();
+            std::string value = simple_val.get_value();
             if ("" == value) {
                 msg += "\"\"";
             } else {
--- a/packages/ChangeLog
+++ b/packages/ChangeLog
@@ -1,3 +1,8 @@
+2000-07-07  Jesper Skov  <jskov@redhat.com>
+
+	* ecos.db: Removed 'enable' statements from SH targets. Moved to
+	individual HAL CDL files.
+
 2000-06-23  Jesper Skov  <jskov@redhat.com>
 
 	* ecos.db: Added CqREEK serial package.
new file mode 100644
--- /dev/null
+++ b/packages/cygmon/current/misc/arm/board.h
@@ -0,0 +1,72 @@
+#ifndef __CYGMON_ARM_BOARD_H__
+#define __CYGMON_ARM_BOARD_H__
+//==========================================================================
+//
+//      board.h
+//
+//      Cygmon board/platform configuration file
+//
+//==========================================================================
+//####COPYRIGHTBEGIN####
+//                                                                          
+// -------------------------------------------                              
+// The contents of this file are subject to the Red Hat eCos Public License 
+// Version 1.1 (the "License"); you may not use this file except in         
+// compliance with the License.  You may obtain a copy of the License at    
+// http://www.redhat.com/                                                   
+//                                                                          
+// 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 Configurable Operating System,      
+// released September 30, 1998.                                             
+//                                                                          
+// The Initial Developer of the Original Code is Red Hat.                   
+// Portions created by Red Hat are                                          
+// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.                             
+// All Rights Reserved.                                                     
+// -------------------------------------------                              
+//                                                                          
+//####COPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    gthomas
+// Contributors: gthomas
+// Date:         1999-10-20
+// Purpose:      
+// Description:  
+//               
+//
+//####DESCRIPTIONEND####
+//
+//=========================================================================
+// Hardware/platform/configuration specifics
+
+#include <pkgconf/hal.h>
+#include <pkgconf/cygmon.h>
+
+#define HAVE_FLOAT_REGS         0
+#define HAVE_DOUBLE_REGS        0
+#define HAVE_CACHE              0 // FIXME
+#define HAVE_USAGE              0 // FIXME
+#define USE_CYGMON_PROTOTYPES   1
+#define NOMAIN                  1
+#define CYGMON_SYSTEM_SERVICES  0 // Not used, fall back to BSP support
+#ifdef CYGDAT_CYGMON_USE_HELP
+#define USE_HELP                1
+#endif
+
+// For breakpoint support
+#define NO_MALLOC               1
+#define MAX_BP_NUM              8
+#include "cpu_info.h"
+#define TRAP_SIZE               4
+#define __set_breakpoint        set_breakpoint
+#define __remove_breakpoint     clear_breakpoint
+#define __write_mem_safe        memcpy
+#define _breakinst              bsp_breakinsn
+
+#endif //  __CYGMON_ARM_BOARD_H__
--- a/packages/ecos.db
+++ b/packages/ecos.db
@@ -289,7 +289,6 @@ package CYGPKG_DEVS_ETH_POWERPC_QUICC {
 	script		quicc_eth_drivers.cdl
         description     "Ethernet driver for PowerPC QUICC (MPC8xx) based boards."
 }
-
 package CYGPKG_IO_PCI	{
 	alias		{ "PCI configuration library" io_pci }
 	directory	io/pci
@@ -999,7 +998,6 @@ target sh7708 {
 	              CYGPKG_IO_SERIAL_SH_EDK7708
                       CYGPKG_DEVICES_WATCHDOG_SH_SH3
         }
-	enable      { CYGPKG_HAL_SH_7708 }
         description "
            The sh7708 target provides the packages needed to run
            eCos on a Hitachi EDK/SH7708 board."
@@ -1011,7 +1009,6 @@ target cq7708 {
                    CYGPKG_HAL_SH_SH7708_CQ7708
 	           CYGPKG_IO_SERIAL_SH_CQ7708
         }
-        enable      { CYGPKG_HAL_SH_7708 }
         description "
            The cq7708 target provides the packages needed to run
            eCos on a CqREEK SH7708 board."
--- a/packages/hal/arm/arch/current/ChangeLog
+++ b/packages/hal/arm/arch/current/ChangeLog
@@ -1,3 +1,16 @@
+2000-07-07  Jesper Skov  <jskov@redhat.com>
+
+	* src/arm_stub.c: Changes to support CygMon changes.
+
+	* src/hal_misc.c: Fix warnings.
+
+2000-07-05  Jesper Skov  <jskov@redhat.com>
+
+	* src/hal_misc.c: 
+	* src/vectors.S:
+	All platforms now has VECTOR_SUPPORT (or provide alternative
+	implementations). Removed checks for the option.
+
 2000-06-28  Jesper Skov  <jskov@redhat.com>
 
 	* src/hal_mk_defs.c:
--- a/packages/hal/arm/arch/current/src/arm_stub.c
+++ b/packages/hal/arm/arch/current/src/arm_stub.c
@@ -45,9 +45,6 @@
 #include <stddef.h>
 
 #include <pkgconf/hal.h>
-#ifdef CYGPKG_CYGMON
-#include <pkgconf/cygmon.h>
-#endif
 
 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
 
@@ -495,7 +492,6 @@ void __clear_single_step (void)
     }
 }
 
-#if !defined(CYGPKG_CYGMON)
 void __install_breakpoints (void)
 {
 //    FIXME();
@@ -505,7 +501,6 @@ void __clear_breakpoints (void)
 {
 //    FIXME();
 }
-#endif // !CYGPKG_CYGMON
 
 /* If the breakpoint we hit is in the breakpoint() instruction, return a
    non-zero value. */
--- a/packages/hal/arm/arch/current/src/hal_misc.c
+++ b/packages/hal/arm/arch/current/src/hal_misc.c
@@ -81,9 +81,10 @@ extern void *__mem_fault_handler;
 
 #define ARM_VECTORS 8
 extern unsigned long vectors[];  // exception vectors as defined by the stubs
+
+#if !defined(CYGPKG_CYGMON)
 static unsigned long *hardware_vectors = (unsigned long *)0x20;
 static unsigned long hold_vectors[ARM_VECTORS];
-
 static int exception_level;
 
 static void
@@ -101,6 +102,7 @@ static void
     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 // !CYGPKG_CYGMON
 #endif
 
 void
@@ -173,9 +175,8 @@ cyg_hal_invoke_constructors (void)
 }
 
 /*------------------------------------------------------------------------*/
-/* default ISR                                                            */
+/* Architecture default ISR                                               */
 
-#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
 externC cyg_uint32
 hal_arch_default_isr(CYG_ADDRWORD vector, CYG_ADDRWORD data)
 {
@@ -186,29 +187,6 @@ hal_arch_default_isr(CYG_ADDRWORD vector
     CYG_FAIL("Spurious Interrupt!!!");
     return 0;
 }
-#else
-externC cyg_uint32
-hal_default_isr(CYG_ADDRWORD vector, CYG_ADDRWORD data)
-{
-    CYG_TRACE1(true, "Interrupt: %d", vector);
-
-#ifndef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
-#ifdef CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT
-#ifdef CYGDBG_HAL_CTRLC_ISR
-    // then see if it is an incoming character interrupt and break
-    // into the stub ROM if the char is a ^C.
-    if ( CYGDBG_HAL_CTRLC_ISR( vector, data ) )
-        return 1; // interrupt handled
-#endif
-#endif
-#endif
-
-    diag_printf("Spurious Interrupt!!! - vector: %d, data: %x\n", vector, 
-                data);
-    CYG_FAIL("Spurious Interrupt!!!");
-    return 0;
-}
-#endif // CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
 
 /*------------------------------------------------------------------------*/
 /* Idle thread action                                                     */
--- a/packages/hal/arm/arch/current/src/vectors.S
+++ b/packages/hal/arm/arch/current/src/vectors.S
@@ -189,8 +189,8 @@ hal_dram_size:
         .long   0        
 
         .balign 16
-#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT // this _check_ should go away
-        // Vectors used to communicate between eCos and ROM environments
+#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
+	// Vectors used to communicate between eCos and ROM environments
         .globl  hal_virtual_vector_table
 hal_virtual_vector_table:
         .rept   CYGNUM_CALL_IF_TABLE_SIZE
@@ -388,13 +388,11 @@ 2:
         str     r2,[r0,#0x24]
 #endif
         
-#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT // this _check_ should go away
 #if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) \
     || defined(CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT)
         .extern hal_ctrlc_isr_init
         bl      hal_ctrlc_isr_init
 #endif
-#endif
 
         LED 2
         
@@ -716,7 +714,6 @@ 10:
 
         mov     r0,v1                   // vector #
 
-#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT // this _check_ should go away
 #if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) \
     || defined(CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT)
         // If we are supporting Ctrl-C interrupts from GDB, we must squirrel
@@ -727,7 +724,6 @@ 10:
         ldr     r2,=hal_saved_interrupt_state
         str     v6,[r2]
 #endif
-#endif        
 
 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_IGNORE_SPURIOUS     
         cmp     r0,#0                   // ignore spurious interrupts
--- a/packages/hal/arm/cma230/current/ChangeLog
+++ b/packages/hal/arm/cma230/current/ChangeLog
@@ -1,3 +1,13 @@
+2000-07-05  Jesper Skov  <jskov@redhat.com>
+
+	* cdl/hal_arm_cma230.cdl:
+	* include/hal_diag.h:
+	* include/plf_stub.h:
+	* src/cma230_misc.c:
+	* src/hal_diag.c:
+	* src/plf_stub.c: [deleted]
+	Changed to support virtual vectors.
+
 2000-06-18  Gary Thomas  <gthomas@redhat.com>
 
 	* include/pkgconf/mlt_arm_cma222_ram.ldi: 
--- a/packages/hal/arm/cma230/current/cdl/hal_arm_cma230.cdl
+++ b/packages/hal/arm/cma230/current/cdl/hal_arm_cma230.cdl
@@ -50,10 +50,11 @@ cdl_package CYGPKG_HAL_ARM_CMA230 {
         The cma230 HAL package provides the support needed to run
         eCos on Cogent Computer Systems CMA2xx (CMA230, CMA222) boards."
 
-    compile       hal_diag.c plf_stub.c cma230_misc.c
+    compile       hal_diag.c cma230_misc.c
 
     implements    CYGINT_HAL_DEBUG_GDB_STUBS
     implements    CYGINT_HAL_DEBUG_GDB_STUBS_BREAK
+    implements    CYGINT_HAL_VIRTUAL_VECTOR_SUPPORT
 
     define_proc {
         puts $::cdl_system_header "#define CYGBLD_HAL_TARGET_H   <pkgconf/hal_arm.h>"
@@ -85,17 +86,7 @@ cdl_package CYGPKG_HAL_ARM_CMA230 {
             into ROM."
     }
 
-    cdl_option CYGHWR_HAL_ARM_CMA230_DIAG_PORT {
-        display       "Diagnostic serial port"
-        flavor        data
-        legal_values  0 1
-        default_value 0
-        description   "
-            The CMA230 board has two separate serial ports.  This option
-            chooses which of these ports will be used."
-    }
-    
-    cdl_option CYGHWR_HAL_ARM_CMA230_DIAG_BAUD {
+    cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD {
         display       "Diagnostic serial port baud rate"
         flavor        data
         legal_values  9600 19200 38400 115200
@@ -106,18 +97,7 @@ cdl_package CYGPKG_HAL_ARM_CMA230 {
             diagnostic and GDB port are the same."
     }
     
-    cdl_option CYGHWR_HAL_ARM_CMA230_GDB_PORT {
-        display       "GDB serial port"
-        flavor        data
-        legal_values  0 1
-        default_value 0
-        description   "
-            The CMA230 board has two separate serial ports.  This option
-            chooses which of these ports will be used to connect to a host
-            running GDB."
-    }
-
-    cdl_option CYGHWR_HAL_ARM_CMA230_GDB_BAUD {
+    cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL_BAUD {
         display       "GDB serial port baud rate"
         flavor        data
         legal_values  9600 19200 38400 115200
@@ -126,6 +106,33 @@ cdl_package CYGPKG_HAL_ARM_CMA230 {
             This option controls the baud rate used for the GDB connection."
     }
 
+    cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS {
+        display      "Number of communication channels on the board"
+        flavor       data
+        calculated   2
+    }
+ 
+    cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL {
+        display          "Debug serial port"
+        flavor data
+        legal_values     0 to CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS-1
+        default_value    0
+        description      "
+            The CMA230 board has two serial ports. This option
+            chooses which port will be used to connect to a host
+            running GDB."
+     }
+ 
+     cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL {
+         display          "Diagnostic serial port"
+         flavor data
+         legal_values     0 to CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS-1
+         default_value    0
+         description      "
+            The CMA230 board has two serial ports.  This option
+            chooses which port will be used for diagnostic output."
+     }
+
     # Real-time clock/counter specifics
     cdl_component CYGNUM_HAL_RTC_CONSTANTS {
         display       "Real-time clock constants"
@@ -219,8 +226,8 @@ cdl_package CYGPKG_HAL_ARM_CMA230 {
             requires { CYG_HAL_STARTUP == "ROM" }
             requires CYGSEM_HAL_ROM_MONITOR
             requires CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
-            requires ! CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
-            requires ! CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT
+            requires CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
+            requires CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT
             requires ! CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT
             requires ! CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM
             no_define
@@ -285,4 +292,25 @@ cdl_package CYGPKG_HAL_ARM_CMA230 {
             application. This enables features such as utilizing a separate
             interrupt stack when exceptions are generated."
     }
+
+    cdl_option CYGSEM_HAL_USE_ROM_MONITOR {
+         display       "Work with a ROM monitor"
+         flavor        booldata
+         legal_values  { "Generic" "GDB_stubs" }
+         default_value { CYG_HAL_STARTUP == "RAM" ? "GDB_stubs" : 0 }
+         parent        CYGPKG_HAL_ROM_MONITOR
+         requires      { CYG_HAL_STARTUP == "RAM" }
+         description   "
+             Support can be enabled for different varieties of ROM monitor.
+             This support changes various eCos semantics such as the encoding
+             of diagnostic output, or the overriding of hardware interrupt
+             vectors.
+             Firstly there is \"Generic\" support which prevents the HAL
+             from overriding the hardware vectors that it does not use, to
+             instead allow an installed ROM monitor to handle them. This is
+             the most basic support which is likely to be common to most
+             implementations of ROM monitor.
+             \"GDB_stubs\" provides support when GDB stubs are included in
+             the ROM monitor or boot ROM."
+     }
 }
--- a/packages/hal/arm/cma230/current/include/hal_diag.h
+++ b/packages/hal/arm/cma230/current/include/hal_diag.h
@@ -49,6 +49,16 @@
 
 #include <cyg/infra/cyg_type.h>
 
+#if defined(CYGSEM_HAL_VIRTUAL_VECTOR_DIAG)
+
+#include <cyg/hal/hal_if.h>
+
+#define HAL_DIAG_INIT() hal_if_diag_init()
+#define HAL_DIAG_WRITE_CHAR(_c_) hal_if_diag_write_char(_c_)
+#define HAL_DIAG_READ_CHAR(_c_) hal_if_diag_read_char(&_c_)
+
+#else // everything by steam
+
 /*---------------------------------------------------------------------------*/
 /* functions implemented in hal_diag.c                                       */
 
@@ -64,6 +74,8 @@ externC void hal_diag_read_char(char *c)
 
 #define HAL_DIAG_READ_CHAR(_c_) hal_diag_read_char(&_c_)
 
+#endif // CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
+
 /*---------------------------------------------------------------------------*/
 /* end of hal_diag.h                                                         */
 #endif /* CYGONCE_HAL_DIAG_H */
--- a/packages/hal/arm/cma230/current/include/plf_stub.h
+++ b/packages/hal/arm/cma230/current/include/plf_stub.h
@@ -54,29 +54,29 @@
 #include <cyg/hal/arm_stub.h>           // architecture stub support
 
 //----------------------------------------------------------------------------
-// Define serial stuff.
+// Define some platform specific communication details. This is mostly
+// handled by hal_if now, but we need to make sure the comms tables are
+// properly initialized.
 
-extern void hal_cma230_init_serial(void);
-extern int  hal_cma230_get_char(void);
-extern void hal_cma230_put_char(int c);
-extern int  hal_cma230_interruptible(int);
+externC void cyg_hal_plf_comms_init(void);
 
-#define HAL_STUB_PLATFORM_INIT_SERIAL()       hal_cma230_init_serial()
-#define HAL_STUB_PLATFORM_GET_CHAR()          hal_cma230_get_char()
-#define HAL_STUB_PLATFORM_PUT_CHAR(c)         hal_cma230_put_char((c))
+#define HAL_STUB_PLATFORM_INIT_SERIAL()       cyg_hal_plf_comms_init()
+
 #define HAL_STUB_PLATFORM_SET_BAUD_RATE(baud) CYG_UNUSED_PARAM(int, (baud))
-#define HAL_STUB_PLATFORM_INTERRUPTIBLE       (&hal_cma230_interruptible)
+#define HAL_STUB_PLATFORM_INTERRUPTIBLE       0
 #define HAL_STUB_PLATFORM_INIT_BREAK_IRQ()    CYG_EMPTY_STATEMENT
 
 //----------------------------------------------------------------------------
 // Stub initializer.
 #define HAL_STUB_PLATFORM_INIT()              CYG_EMPTY_STATEMENT
 
+#endif // ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
+
 //----------------------------------------------------------------------------
 // Reset.
 #define HAL_STUB_PLATFORM_RESET()             CYG_EMPTY_STATEMENT
 
-#endif // ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
+#define HAL_STUB_PLATFORM_RESET_ENTRY 0xe000000
 
 //-----------------------------------------------------------------------------
 #endif // CYGONCE_HAL_PLF_STUB_H
--- a/packages/hal/arm/cma230/current/src/cma230_misc.c
+++ b/packages/hal/arm/cma230/current/src/cma230_misc.c
@@ -47,6 +47,7 @@
 #include <cyg/infra/cyg_trac.h>         // tracing macros
 #include <cyg/infra/cyg_ass.h>          // assertion macros
 
+#include <cyg/hal/hal_if.h>             // calling interface API
 #include <cyg/hal/hal_io.h>             // IO macros
 #include <cyg/hal/hal_arch.h>           // Register state info
 #include <cyg/hal/hal_diag.h>
@@ -110,6 +111,9 @@ void hal_hardware_init(void)
     // Reset all interrupt masks (disable all interrupt sources)
     *(volatile cyg_uint8 *)CMA230_IMRw = 0;
     *(volatile cyg_uint8 *)CMA230_CLR = 0xFF;  // Clear all current interrupts
+
+    // Set up eCos/ROM interfaces
+    hal_if_init();
 }
 
 //
--- a/packages/hal/arm/cma230/current/src/hal_diag.c
+++ b/packages/hal/arm/cma230/current/src/hal_diag.c
@@ -53,85 +53,96 @@
 #include <cyg/hal/hal_io.h>             // IO macros
 #include <cyg/hal/hal_diag.h>
 #include <cyg/hal/hal_cma230.h>         // Hardware definitions
-#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
-#include <cyg/hal/drv_api.h>
-#include <cyg/hal/hal_stub.h>           // cyg_hal_gdb_interrupt
-#endif
+#include <cyg/hal/hal_if.h>             // Calling-if API
+#include <cyg/hal/drv_api.h>            // driver API
+#include <cyg/hal/hal_misc.h>           // Helper functions
+
+#if defined(CYGSEM_HAL_VIRTUAL_VECTOR_DIAG) \
+    || defined(CYGPRI_HAL_IMPLEMENTS_IF_SERVICES)
+
+static void cyg_hal_plf_serial_init(void);
+
+// FIXME: Copy LCD driver from powerpc/cogent
+//static void cyg_hal_plf_lcd_init(void);
+
+void
+cyg_hal_plf_comms_init(void)
+{
+    static int initialized = 0;
+
+    if (initialized)
+        return;
+
+    initialized = 1;
+
+    cyg_hal_plf_serial_init();
+//    cyg_hal_plf_lcd_init();
+}
+#endif // CYGSEM_HAL_VIRTUAL_VECTOR_DIAG || CYGPRI_HAL_IMPLEMENTS_IF_SERVICES
 
-// Assumption: all diagnostic output must be GDB packetized unless this is a ROM (i.e.
-// totally stand-alone) system.
+//=============================================================================
+// Serial driver
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// There are two serial ports.
+#define CYG_DEV_SERIAL_BASE_A    0xe900047 // port A
+#define CYG_DEV_SERIAL_BASE_B    0xe900007 // port B
 
-#if defined(CYG_HAL_STARTUP_ROM) || defined(CYGDBG_HAL_DIAG_DISABLE_GDB_PROTOCOL)
-#define HAL_DIAG_USES_HARDWARE
+//-----------------------------------------------------------------------------
+// Default baud rate is 38400
+// Based on 3.6864 MHz xtal
+#if CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD==9600
+#define CYG_DEV_SERIAL_BAUD_MSB        0x00
+#define CYG_DEV_SERIAL_BAUD_LSB        0x18
+#endif
+#if CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD==19200
+#define CYG_DEV_SERIAL_BAUD_MSB        0x00
+#define CYG_DEV_SERIAL_BAUD_LSB        0x0C
+#endif
+#if CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD==38400
+#define CYG_DEV_SERIAL_BAUD_MSB        0x00
+#define CYG_DEV_SERIAL_BAUD_LSB        0x06
+#endif
+#if CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD==115200
+#define CYG_DEV_SERIAL_BAUD_MSB        0x00
+#define CYG_DEV_SERIAL_BAUD_LSB        0x02
 #endif
 
-/*---------------------------------------------------------------------------*/
-#if CYGHWR_HAL_ARM_CMA230_DIAG_PORT==0
-// This is the base address of the A-channel
-#define CYG_DEVICE_SERIAL_RS232_16550_BASE      CMA101_DUARTA
-#define CYG_DEVICE_SERIAL_INT                   CYGNUM_HAL_INTERRUPT_SERIAL_A
-#else
-// This is the base address of the B-channel
-#define CYG_DEVICE_SERIAL_RS232_16550_BASE      CMA101_DUARTB
-#define CYG_DEVICE_SERIAL_INT                   CYGNUM_HAL_INTERRUPT_SERIAL_B
-#endif
-
-// Based on 3.6864 MHz xtal
-#if CYGHWR_HAL_ARM_CMA230_DIAG_BAUD==9600
-#define CYG_DEVICE_SERIAL_RS232_BAUD_MSB        0x00
-#define CYG_DEVICE_SERIAL_RS232_BAUD_LSB        0x18
-#endif
-#if CYGHWR_HAL_ARM_CMA230_DIAG_BAUD==19200
-#define CYG_DEVICE_SERIAL_RS232_BAUD_MSB        0x00
-#define CYG_DEVICE_SERIAL_RS232_BAUD_LSB        0x0C
-#endif
-#if CYGHWR_HAL_ARM_CMA230_DIAG_BAUD==38400
-#define CYG_DEVICE_SERIAL_RS232_BAUD_MSB        0x00
-#define CYG_DEVICE_SERIAL_RS232_BAUD_LSB        0x06
-#endif
-#if CYGHWR_HAL_ARM_CMA230_DIAG_BAUD==115200
-#define CYG_DEVICE_SERIAL_RS232_BAUD_MSB        0x00
-#define CYG_DEVICE_SERIAL_RS232_BAUD_LSB        0x02
-#endif
-
-#ifndef CYG_DEVICE_SERIAL_RS232_BAUD_MSB
+#ifndef CYG_DEV_SERIAL_BAUD_MSB
 #error Missing/incorrect serial baud rate defined - CDL error?
 #endif
 
-// Define the serial registers.
-#define CYG_DEVICE_SERIAL_RS232_16550_RBR \
-    ((volatile cyg_uint8 *) CYG_DEVICE_SERIAL_RS232_16550_BASE + 0x00)
-    // receiver buffer register, read, dlab = 0
-#define CYG_DEVICE_SERIAL_RS232_16550_THR \
-    ((volatile cyg_uint8 *) CYG_DEVICE_SERIAL_RS232_16550_BASE + 0x00)
-    // transmitter holding register, write, dlab = 0
-#define CYG_DEVICE_SERIAL_RS232_16550_DLL \
-    ((volatile cyg_uint8 *) CYG_DEVICE_SERIAL_RS232_16550_BASE + 0x00)
-    // divisor latch (LS), read/write, dlab = 1
-#define CYG_DEVICE_SERIAL_RS232_16550_IER \
-    ((volatile cyg_uint8 *) CYG_DEVICE_SERIAL_RS232_16550_BASE + 0x08)
-    // interrupt enable register, read/write, dlab = 0
-#define CYG_DEVICE_SERIAL_RS232_16550_DLM \
-    ((volatile cyg_uint8 *) CYG_DEVICE_SERIAL_RS232_16550_BASE + 0x08)
-    // divisor latch (MS), read/write, dlab = 1
-#define CYG_DEVICE_SERIAL_RS232_16550_IIR \
-    ((volatile cyg_uint8 *) CYG_DEVICE_SERIAL_RS232_16550_BASE + 0x10)
-    // interrupt identification register, read, dlab = 0
-#define CYG_DEVICE_SERIAL_RS232_16550_FCR \
-    ((volatile cyg_uint8 *) CYG_DEVICE_SERIAL_RS232_16550_BASE + 0x10)
-    // fifo control register, write, dlab = 0
-#define CYG_DEVICE_SERIAL_RS232_16550_LCR \
-    ((volatile cyg_uint8 *) CYG_DEVICE_SERIAL_RS232_16550_BASE + 0x18)
-    // line control register, read/write
-#define CYG_DEVICE_SERIAL_RS232_16550_MCR \
-    ((volatile cyg_uint8 *) CYG_DEVICE_SERIAL_RS232_16550_BASE + 0x20)
-    // modem control register, read/write
-#define CYG_DEVICE_SERIAL_RS232_16550_LSR \
-    ((volatile cyg_uint8 *) CYG_DEVICE_SERIAL_RS232_16550_BASE + 0x28)
-    // line status register, read
-#define CYG_DEVICE_SERIAL_RS232_16550_MSR \
-    ((volatile cyg_uint8 *) CYG_DEVICE_SERIAL_RS232_16550_BASE + 0x30)
-    // modem status register, read
+//-----------------------------------------------------------------------------
+// Define the serial registers. The Cogent board is equipped with a 16552
+// serial chip.
+#define CYG_DEV_SERIAL_RBR   0x00  // receiver buffer register, read, dlab = 0
+#define CYG_DEV_SERIAL_THR   0x00 // transmitter holding register, write, dlab = 0
+#define CYG_DEV_SERIAL_DLL   0x00 // divisor latch (LS), read/write, dlab = 1
+#define CYG_DEV_SERIAL_IER   0x08 // interrupt enable register, read/write, dlab = 0
+#define CYG_DEV_SERIAL_DLM   0x08 // divisor latch (MS), read/write, dlab = 1
+#define CYG_DEV_SERIAL_IIR   0x10 // interrupt identification register, read, dlab = 0
+#define CYG_DEV_SERIAL_FCR   0x10 // fifo control register, write, dlab = 0
+#define CYG_DEV_SERIAL_AFR   0x10 // alternate function register, read/write, dlab = 1
+#define CYG_DEV_SERIAL_LCR   0x18 // line control register, read/write
+#define CYG_DEV_SERIAL_MCR   0x20
+#define CYG_DEV_SERIAL_MCR_A 0x20
+#define CYG_DEV_SERIAL_MCR_B 0x20
+#define CYG_DEV_SERIAL_LSR   0x28 // line status register, read
+#define CYG_DEV_SERIAL_MSR   0x30 // modem status register, read
+#define CYG_DEV_SERIAL_SCR   0x38 // scratch pad register
+
+// The interrupt enable register bits.
+#define SIO_IER_ERDAI   0x01            // enable received data available irq
+#define SIO_IER_ETHREI  0x02            // enable THR empty interrupt
+#define SIO_IER_ELSI    0x04            // enable receiver line status irq
+#define SIO_IER_EMSI    0x08            // enable modem status interrupt
+
+// The interrupt identification register bits.
+#define SIO_IIR_IP      0x01            // 0 if interrupt pending
+#define SIO_IIR_ID_MASK 0x0e            // mask for interrupt ID bits
+#define ISR_Tx  0x02
+#define ISR_Rx  0x04
 
 // The line status register bits.
 #define SIO_LSR_DR      0x01            // data ready
@@ -163,6 +174,299 @@
 #define SIO_LCR_SB     0x40             // set break
 #define SIO_LCR_DLAB   0x80             // divisor latch access bit
 
+// The FIFO control register
+#define SIO_FCR_FCR0   0x01             // enable xmit and rcvr fifos
+#define SIO_FCR_FCR1   0x02             // clear RCVR FIFO
+#define SIO_FCR_FCR2   0x04             // clear XMIT FIFO
+
+
+//-----------------------------------------------------------------------------
+typedef struct {
+    cyg_uint8* base;
+    cyg_int32 msec_timeout;
+    int isr_vector;
+} channel_data_t;
+
+//-----------------------------------------------------------------------------
+static void
+init_serial_channel(const channel_data_t* __ch_data)
+{
+    cyg_uint8* base = __ch_data->base;
+    cyg_uint8 lcr;
+
+    // 8-1-no parity.
+    HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_LCR,
+                     SIO_LCR_WLS0 | SIO_LCR_WLS1);
+
+    HAL_READ_UINT8(base+CYG_DEV_SERIAL_LCR, lcr);
+    lcr |= SIO_LCR_DLAB;
+    HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_LCR, lcr);
+    HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_DLL, CYG_DEV_SERIAL_BAUD_LSB);
+    HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_DLM, CYG_DEV_SERIAL_BAUD_MSB);
+    lcr &= ~SIO_LCR_DLAB;
+    HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_LCR, lcr);
+    HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_FCR, 0x07);  // Enable & clear FIFO
+}
+
+static cyg_bool
+cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch)
+{
+    cyg_uint8* base = ((channel_data_t*)__ch_data)->base;
+    cyg_uint8 lsr;
+
+    HAL_READ_UINT8(base+CYG_DEV_SERIAL_LSR, lsr);
+    if ((lsr & SIO_LSR_DR) == 0)
+        return false;
+
+    HAL_READ_UINT8(base+CYG_DEV_SERIAL_RBR, *ch);
+
+    return true;
+}
+
+
+cyg_uint8
+cyg_hal_plf_serial_getc(void* __ch_data)
+{
+    cyg_uint8 ch;
+    CYGARC_HAL_SAVE_GP();
+
+    while(!cyg_hal_plf_serial_getc_nonblock(__ch_data, &ch));
+
+    CYGARC_HAL_RESTORE_GP();
+    return ch;
+}
+
+void
+cyg_hal_plf_serial_putc(void* __ch_data, cyg_uint8 c)
+{
+    cyg_uint8* base = ((channel_data_t*)__ch_data)->base;
+    cyg_uint8 lsr;
+    CYGARC_HAL_SAVE_GP();
+
+    do {
+        HAL_READ_UINT8(base+CYG_DEV_SERIAL_LSR, lsr);
+    } while ((lsr & SIO_LSR_THRE) == 0);
+
+    HAL_WRITE_UINT8(base+CYG_DEV_SERIAL_THR, c);
+
+    // Hang around until the character has been safely sent.
+    do {
+        HAL_READ_UINT8(base+CYG_DEV_SERIAL_LSR, lsr);
+    } while ((lsr & SIO_LSR_THRE) == 0);
+
+    CYGARC_HAL_RESTORE_GP();
+}
+
+#if defined(CYGSEM_HAL_VIRTUAL_VECTOR_DIAG) \
+    || defined(CYGPRI_HAL_IMPLEMENTS_IF_SERVICES)
+
+static const channel_data_t channels[2] = {
+    { (cyg_uint8*)CMA101_DUARTA, 1000, CYGNUM_HAL_INTERRUPT_SERIAL_A},
+    { (cyg_uint8*)CMA101_DUARTB, 1000, CYGNUM_HAL_INTERRUPT_SERIAL_B}
+};
+
+static void
+cyg_hal_plf_serial_write(void* __ch_data, const cyg_uint8* __buf, 
+                         cyg_uint32 __len)
+{
+    CYGARC_HAL_SAVE_GP();
+
+    while(__len-- > 0)
+        cyg_hal_plf_serial_putc(__ch_data, *__buf++);
+
+    CYGARC_HAL_RESTORE_GP();
+}
+
+static void
+cyg_hal_plf_serial_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
+{
+    CYGARC_HAL_SAVE_GP();
+
+    while(__len-- > 0)
+        *__buf++ = cyg_hal_plf_serial_getc(__ch_data);
+
+    CYGARC_HAL_RESTORE_GP();
+}
+
+cyg_bool
+cyg_hal_plf_serial_getc_timeout(void* __ch_data, cyg_uint8* ch)
+{
+    int delay_count;
+    channel_data_t* chan = (channel_data_t*)__ch_data;
+    cyg_bool res;
+    CYGARC_HAL_SAVE_GP();
+
+    delay_count = chan->msec_timeout * 10; // delay in .1 ms steps
+    for(;;) {
+        res = cyg_hal_plf_serial_getc_nonblock(__ch_data, ch);
+        if (res || 0 == delay_count--)
+            break;
+        
+        CYGACC_CALL_IF_DELAY_US(100);
+    }
+
+    CYGARC_HAL_RESTORE_GP();
+    return res;
+}
+
+static int
+cyg_hal_plf_serial_control(void *__ch_data, __comm_control_cmd_t __func, ...)
+{
+    static int irq_state = 0;
+    channel_data_t* chan = (channel_data_t*)__ch_data;
+    cyg_uint8 ier;
+    int ret = 0;
+    CYGARC_HAL_SAVE_GP();
+
+    switch (__func) {
+    case __COMMCTL_IRQ_ENABLE:
+        HAL_INTERRUPT_UNMASK(chan->isr_vector);
+        HAL_INTERRUPT_SET_LEVEL(chan->isr_vector, 1);
+        HAL_READ_UINT8(chan->base+CYG_DEV_SERIAL_IER, ier);
+        ier |= SIO_IER_ERDAI;
+        HAL_WRITE_UINT8(chan->base+CYG_DEV_SERIAL_IER, ier);
+        irq_state = 1;
+        break;
+    case __COMMCTL_IRQ_DISABLE:
+        ret = irq_state;
+        irq_state = 0;
+        HAL_INTERRUPT_MASK(chan->isr_vector);
+        HAL_READ_UINT8(chan->base+CYG_DEV_SERIAL_IER, ier);
+        ier &= ~SIO_IER_ERDAI;
+        HAL_WRITE_UINT8(chan->base+CYG_DEV_SERIAL_IER, ier);
+        break;
+    case __COMMCTL_DBG_ISR_VECTOR:
+        ret = chan->isr_vector;
+        break;
+    case __COMMCTL_SET_TIMEOUT:
+    {
+        va_list ap;
+
+        va_start(ap, __func);
+
+        ret = chan->msec_timeout;
+        chan->msec_timeout = va_arg(ap, cyg_uint32);
+
+        va_end(ap);
+    }        
+    default:
+        break;
+    }
+    CYGARC_HAL_RESTORE_GP();
+    return ret;
+}
+
+static int
+cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc, 
+                       CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
+{
+    channel_data_t* chan = (channel_data_t*)__ch_data;
+    cyg_uint8 _iir;
+    int res = 0;
+    CYGARC_HAL_SAVE_GP();
+
+    HAL_READ_UINT8(chan->base+CYG_DEV_SERIAL_IIR, _iir);
+    _iir &= SIO_IIR_ID_MASK;
+
+    *__ctrlc = 0;
+    if ( ISR_Rx == _iir ) {
+        cyg_uint8 c, lsr;
+        HAL_READ_UINT8(chan->base+CYG_DEV_SERIAL_LSR, lsr);
+        if (lsr & SIO_LSR_DR) {
+
+            HAL_READ_UINT8(chan->base+CYG_DEV_SERIAL_RBR, c);
+
+            if( cyg_hal_is_break( &c , 1 ) )
+                *__ctrlc = 1;
+        }
+
+        // Acknowledge the interrupt
+        HAL_INTERRUPT_ACKNOWLEDGE(chan->isr_vector);
+        res = CYG_ISR_HANDLED;
+    }
+
+    CYGARC_HAL_RESTORE_GP();
+    return res;
+}
+
+static void
+cyg_hal_plf_serial_init(void)
+{
+    hal_virtual_comm_table_t* comm;
+    int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+
+    // Disable interrupts.
+    HAL_INTERRUPT_MASK(channels[0].isr_vector);
+    HAL_INTERRUPT_MASK(channels[1].isr_vector);
+
+    // Init channels
+    init_serial_channel(&channels[0]);
+    init_serial_channel(&channels[1]);
+
+    // Setup procs in the vector table
+
+    // Set channel 0
+    CYGACC_CALL_IF_SET_CONSOLE_COMM(0);
+    comm = CYGACC_CALL_IF_CONSOLE_PROCS();
+    CYGACC_COMM_IF_CH_DATA_SET(*comm, &channels[0]);
+    CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
+    CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
+    CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
+    CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
+    CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
+    CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
+    CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
+
+    // Set channel 1
+    CYGACC_CALL_IF_SET_CONSOLE_COMM(1);
+    comm = CYGACC_CALL_IF_CONSOLE_PROCS();
+    CYGACC_COMM_IF_CH_DATA_SET(*comm, &channels[1]);
+    CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
+    CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
+    CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
+    CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
+    CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
+    CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
+    CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
+    
+    // Restore original console
+    CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
+}
+
+#endif // CYGSEM_HAL_VIRTUAL_VECTOR_DIAG || CYGPRI_HAL_IMPLEMENTS_IF_SERVICES
+
+
+//=============================================================================
+// Compatibility with older stubs
+//=============================================================================
+
+#ifndef CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
+
+
+#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
+#include <cyg/hal/drv_api.h>
+#include <cyg/hal/hal_stub.h>           // cyg_hal_gdb_interrupt
+#endif
+
+// Assumption: all diagnostic output must be GDB packetized unless this is a ROM (i.e.
+// totally stand-alone) system.
+
+#if defined(CYG_HAL_STARTUP_ROM) || defined(CYGDBG_HAL_DIAG_DISABLE_GDB_PROTOCOL)
+#define HAL_DIAG_USES_HARDWARE
+#endif
+
+/*---------------------------------------------------------------------------*/
+#if CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL==0
+// This is the base address of the A-channel
+#define CYG_DEV_SERIAL_BASE      CMA101_DUARTA
+#define CYG_DEV_SERIAL_INT       CYGNUM_HAL_INTERRUPT_SERIAL_A
+#else
+// This is the base address of the B-channel
+#define CYG_DEV_SERIAL_BASE      CMA101_DUARTB
+#define CYG_DEV_SERIAL_INT       CYGNUM_HAL_INTERRUPT_SERIAL_B
+#endif
+
+static channel_data_t ser_channel = { (cyg_uint8*)CYG_DEV_SERIAL_BASE, 0, 0};
 
 #ifdef HAL_DIAG_USES_HARDWARE
 
@@ -173,20 +477,9 @@ void hal_diag_init(void)
     cyg_uint8 lcr;
 
     if (init++) return;
-    // 8-1-no parity.
-    HAL_WRITE_UINT8 (CYG_DEVICE_SERIAL_RS232_16550_LCR,
-                     SIO_LCR_WLS0 | SIO_LCR_WLS1);
 
-    HAL_READ_UINT8 (CYG_DEVICE_SERIAL_RS232_16550_LCR, lcr);
-    lcr |= SIO_LCR_DLAB;
-    HAL_WRITE_UINT8 (CYG_DEVICE_SERIAL_RS232_16550_LCR, lcr);
-    HAL_WRITE_UINT8 (CYG_DEVICE_SERIAL_RS232_16550_DLL,
-                     CYG_DEVICE_SERIAL_RS232_BAUD_LSB);
-    HAL_WRITE_UINT8 (CYG_DEVICE_SERIAL_RS232_16550_DLM,
-                     CYG_DEVICE_SERIAL_RS232_BAUD_MSB);
-    lcr &= ~SIO_LCR_DLAB;
-    HAL_WRITE_UINT8 (CYG_DEVICE_SERIAL_RS232_16550_LCR, lcr);
-    HAL_WRITE_UINT8 (CYG_DEVICE_SERIAL_RS232_16550_FCR, 0x07);  // Enable & clear FIFO
+    init_serial_channel(&ser_channel);
+
     while (*msg) hal_diag_write_char(*msg++);
 }
 
@@ -205,11 +498,9 @@ void hal_diag_write_char(char c)
     cyg_uint8 lsr;
 
     hal_diag_init();
-    do {
-        HAL_READ_UINT8 (CYG_DEVICE_SERIAL_RS232_16550_LSR, lsr);
-    } while ((lsr & SIO_LSR_THRE) == 0);
 
-    HAL_WRITE_UINT8 (CYG_DEVICE_SERIAL_RS232_16550_THR, c);
+    cyg_hal_plf_serial_putc(&ser_channel, c)
+
 #ifdef DEBUG_DIAG
     diag_buffer[diag_bp++] = c;
     if (diag_bp == DIAG_BUFSIZE) {
@@ -221,13 +512,7 @@ void hal_diag_write_char(char c)
 
 void hal_diag_read_char(char *c)
 {
-    cyg_uint8 lsr;
-
-    do {
-        HAL_READ_UINT8 (CYG_DEVICE_SERIAL_RS232_16550_LSR, lsr);
-    } while ((lsr & SIO_LSR_DR) == 0);
-
-    HAL_READ_UINT8 (CYG_DEVICE_SERIAL_RS232_16550_RBR, *c);
+    *c = cyg_hal_plf_serial_getc(&ser_channel);
 }
 
 #else // HAL_DIAG relies on GDB
@@ -235,37 +520,23 @@ void hal_diag_read_char(char *c)
 // Initialize diag port - assume GDB channel is already set up
 void hal_diag_init(void)
 {
+    if (0) init_serial_channel(&ser_channel); // avoid warning
 }
 
 // Actually send character down the wire
 static void
 hal_diag_write_char_serial(char c)
 {
-    cyg_uint8 lsr;
-
-    hal_diag_init();
-    do {
-        HAL_READ_UINT8 (CYG_DEVICE_SERIAL_RS232_16550_LSR, lsr);
-    } while ((lsr & SIO_LSR_THRE) == 0);
-
-    HAL_WRITE_UINT8 (CYG_DEVICE_SERIAL_RS232_16550_THR, c);
-    HAL_IO_BARRIER ();
+    cyg_hal_plf_serial_putc(&ser_channel, c);
 }
 
 static bool
 hal_diag_read_serial(char *c)
 {
     long timeout = 1000000000;  // A long time...
-    cyg_uint8 lsr;
+    while (!cyg_hal_plf_serial_getc_nonblock(&ser_channel, c))
+        if (0 == --timeout) return false;
 
-    do {
-        HAL_READ_UINT8 (CYG_DEVICE_SERIAL_RS232_16550_LSR, lsr);
-        if (--timeout == 0) return false;
-    } while ((lsr & SIO_LSR_DR) == 0);
-    HAL_IO_BARRIER ();                  // Prevent RBR preload.
-
-    HAL_READ_UINT8 (CYG_DEVICE_SERIAL_RS232_16550_RBR, *c);
-    HAL_IO_BARRIER ();
     return true;
 }
 
@@ -335,7 +606,7 @@ hal_diag_write_char(char c)
                 break;              // a good acknowledge
 
 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
-            cyg_drv_interrupt_acknowledge(CYG_DEVICE_SERIAL_INT);
+            cyg_drv_interrupt_acknowledge(CYG_DEV_SERIAL_INT);
             if( c1 == 3 ) {
                 // Ctrl-C: breakpoint.
                 cyg_hal_gdb_interrupt (__builtin_return_address(0));
@@ -358,5 +629,7 @@ hal_diag_write_char(char c)
 }
 #endif
 
+#endif // CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
+
 /*---------------------------------------------------------------------------*/
 /* End of hal_diag.c */
--- a/packages/hal/arm/ebsa285/current/ChangeLog
+++ b/packages/hal/arm/ebsa285/current/ChangeLog
@@ -1,3 +1,14 @@
+2000-07-04  Jesper Skov  <jskov@redhat.com>
+
+	* src/plf_stub.c: [deleted]
+	* src/hal_diag.c:
+	* src/ebsa285_misc.c: 
+	* include/plf_stub.h: 
+	* include/hal_platform_ints.h: 
+	* include/hal_diag.h: 
+	* cdl/hal_arm_ebsa285.cdl: 
+	Changed to use virtual vector table.
+
 2000-06-19  Gary Thomas  <gthomas@redhat.com>
 
 	* include/hal_platform_setup.h: 
--- a/packages/hal/arm/ebsa285/current/cdl/hal_arm_ebsa285.cdl
+++ b/packages/hal/arm/ebsa285/current/cdl/hal_arm_ebsa285.cdl
@@ -49,10 +49,11 @@ cdl_package CYGPKG_HAL_ARM_EBSA285 {
         The EBSA285 HAL package provides the support needed to run
         eCos on a Intel EBSA285 StrongARM eval board."
 
-    compile hal_diag.c plf_stub.c ebsa285_misc.c mem285.S
+    compile hal_diag.c ebsa285_misc.c mem285.S
 
     implements    CYGINT_HAL_DEBUG_GDB_STUBS
     implements    CYGINT_HAL_DEBUG_GDB_STUBS_BREAK
+    implements    CYGINT_HAL_VIRTUAL_VECTOR_SUPPORT
 
     define_proc {
         puts $::cdl_system_header "#define CYGBLD_HAL_TARGET_H   <pkgconf/hal_arm.h>"
@@ -102,6 +103,33 @@ cdl_package CYGPKG_HAL_ARM_EBSA285 {
            increments."
    }
 
+    cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS {
+        display      "Number of communication channels on the board"
+        flavor       data
+        calculated   1
+    }
+ 
+    cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL {
+        display          "Debug serial port"
+        flavor data
+        legal_values     0 to CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS-1
+        default_value    0
+        description      "
+            The EBSA285 board has only one serial port. This option
+            chooses which port will be used to connect to a host
+            running GDB."
+     }
+ 
+     cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL {
+         display          "Diagnostic serial port"
+         flavor data
+         legal_values     0 to CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS-1
+         default_value    0
+         description      "
+            The EBSA285 board has only one serial port.  This option
+            chooses which port will be used for diagnostic output."
+     }
+
     # Real-time clock/counter specifics
     cdl_component CYGNUM_HAL_RTC_CONSTANTS {
         display       "Real-time clock constants"
@@ -172,8 +200,8 @@ cdl_package CYGPKG_HAL_ARM_EBSA285 {
             requires CYGSEM_HAL_ROM_MONITOR
             requires CYGBLD_BUILD_COMMON_GDB_STUBS
             requires CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
-            requires ! CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
-            requires ! CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT
+            requires CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
+            requires CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT
             requires ! CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT
             requires ! CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM
             no_define
@@ -271,4 +299,25 @@ cdl_package CYGPKG_HAL_ARM_EBSA285 {
             application. This enables features such as utilizing a separate
             interrupt stack when exceptions are generated."
     }
+
+    cdl_option CYGSEM_HAL_USE_ROM_MONITOR {
+         display       "Work with a ROM monitor"
+         flavor        booldata
+         legal_values  { "Generic" "GDB_stubs" }
+         default_value { CYG_HAL_STARTUP == "RAM" ? "GDB_stubs" : 0 }
+         parent        CYGPKG_HAL_ROM_MONITOR
+         requires      { CYG_HAL_STARTUP == "RAM" }
+         description   "
+             Support can be enabled for different varieties of ROM monitor.
+             This support changes various eCos semantics such as the encoding
+             of diagnostic output, or the overriding of hardware interrupt
+             vectors.
+             Firstly there is \"Generic\" support which prevents the HAL
+             from overriding the hardware vectors that it does not use, to
+             instead allow an installed ROM monitor to handle them. This is
+             the most basic support which is likely to be common to most
+             implementations of ROM monitor.
+             \"GDB_stubs\" provides support when GDB stubs are included in
+             the ROM monitor or boot ROM."
+     }
 }
--- a/packages/hal/arm/ebsa285/current/include/hal_diag.h
+++ b/packages/hal/arm/ebsa285/current/include/hal_diag.h
@@ -49,6 +49,16 @@
 
 #include <cyg/infra/cyg_type.h>
 
+#if defined(CYGSEM_HAL_VIRTUAL_VECTOR_DIAG)
+
+#include <cyg/hal/hal_if.h>
+
+#define HAL_DIAG_INIT() hal_if_diag_init()
+#define HAL_DIAG_WRITE_CHAR(_c_) hal_if_diag_write_char(_c_)
+#define HAL_DIAG_READ_CHAR(_c_) hal_if_diag_read_char(&_c_)
+
+#else // everything by steam
+
 /*---------------------------------------------------------------------------*/
 /* functions implemented in hal_diag.c                                       */
 
@@ -64,6 +74,8 @@ externC void hal_diag_read_char(char *c)
 
 #define HAL_DIAG_READ_CHAR(_c_) hal_diag_read_char(&_c_)
 
+#endif // CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
+
 /*---------------------------------------------------------------------------*/
 /* end of hal_diag.h                                                         */
 #endif /* CYGONCE_HAL_DIAG_H */
--- a/packages/hal/arm/ebsa285/current/include/hal_platform_ints.h
+++ b/packages/hal/arm/ebsa285/current/include/hal_platform_ints.h
@@ -88,15 +88,4 @@
 // The vector used by the Real time clock
 #define CYGNUM_HAL_INTERRUPT_RTC        CYGNUM_HAL_INTERRUPT_TIMER_3
 
-// The vector used by hal_diag (for reception)
-#define CYG_DIAG_DEV_INT                CYGNUM_HAL_INTERRUPT_SERIAL_RX
-// The vector used by gdb stubs (for reception)
-#define CYG_GDB_DEV_INT                 CYGNUM_HAL_INTERRUPT_SERIAL_RX
-
-// Do we want to poll in the default ISR for ^C interrupt chars?
-#ifdef CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT
-extern int hal_ctrlc_isr( CYG_ADDRWORD vector, CYG_ADDRWORD data);
-#define CYGDBG_HAL_CTRLC_ISR( _V_, _D_ ) hal_ctrlc_isr( _V_, _D_ )
-#endif
-
 #endif // CYGONCE_HAL_PLATFORM_INTS_H
--- a/packages/hal/arm/ebsa285/current/include/plf_stub.h
+++ b/packages/hal/arm/ebsa285/current/include/plf_stub.h
@@ -51,29 +51,32 @@
 
 #include <cyg/infra/cyg_type.h>         // CYG_UNUSED_PARAM
 
-#include <cyg/hal/hal_ebsa285.h>        // registers
-#include <cyg/hal/hal_io.h>             // IO macros
 #include <cyg/hal/arm_stub.h>           // architecture stub support
 
 //----------------------------------------------------------------------------
-// Define serial stuff.
+// Define some platform specific communication details. This is mostly
+// handled by hal_if now, but we need to make sure the comms tables are
+// properly initialized.
+
+externC void cyg_hal_plf_comms_init(void);
 
-extern void hal_ebsa285_init_serial(void);
-extern int  hal_ebsa285_get_char(void);
-extern void hal_ebsa285_put_char(int c);
-extern int  hal_ebsa285_interruptible(int);
+#define HAL_STUB_PLATFORM_INIT_SERIAL()       cyg_hal_plf_comms_init()
 
-#define HAL_STUB_PLATFORM_INIT_SERIAL()       hal_ebsa285_init_serial()
-#define HAL_STUB_PLATFORM_GET_CHAR()          hal_ebsa285_get_char()
-#define HAL_STUB_PLATFORM_PUT_CHAR(c)         hal_ebsa285_put_char((c))
 #define HAL_STUB_PLATFORM_SET_BAUD_RATE(baud) CYG_UNUSED_PARAM(int, (baud))
+#define HAL_STUB_PLATFORM_INTERRUPTIBLE       0
+#define HAL_STUB_PLATFORM_INIT_BREAK_IRQ()    CYG_EMPTY_STATEMENT
 
 //----------------------------------------------------------------------------
 // Stub initializer.
 #define HAL_STUB_PLATFORM_INIT()              CYG_EMPTY_STATEMENT
 
+#endif // ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
+
 //----------------------------------------------------------------------------
 // Reset.
+#include <cyg/hal/hal_ebsa285.h>        // registers
+#include <cyg/hal/hal_io.h>             // IO macros
+
 #define HAL_STUB_PLATFORM_RESET()                                          \
     CYG_MACRO_START                                                        \
     cyg_uint32 ctrl;                                                       \
@@ -95,14 +98,7 @@ extern int  hal_ebsa285_interruptible(in
     for(;;); /* wait for it */                                             \
     CYG_MACRO_END
 
-#ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
-#define HAL_STUB_PLATFORM_INIT_BREAK_IRQ()    CYG_EMPTY_STATEMENT
-#define HAL_STUB_PLATFORM_INTERRUPTIBLE       (&hal_ebsa285_interruptible)
-#else
-#define HAL_STUB_PLATFORM_INTERRUPTIBLE       0
-#endif
-
-#endif // ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
+#define HAL_STUB_PLATFORM_RESET_ENTRY 0x41000000
 
 //-----------------------------------------------------------------------------
 #endif // CYGONCE_HAL_PLF_STUB_H
--- a/packages/hal/arm/ebsa285/current/src/ebsa285_misc.c
+++ b/packages/hal/arm/ebsa285/current/src/ebsa285_misc.c
@@ -50,6 +50,7 @@
 #include <cyg/infra/cyg_ass.h>          // assertion macros
 
 #include <cyg/hal/hal_io.h>             // IO macros
+#include <cyg/hal/hal_if.h>             // calling interface API
 #include <cyg/hal/hal_arch.h>           // Register state info
 #include <cyg/hal/hal_diag.h>
 #include <cyg/hal/hal_intr.h>           // Interrupt names
@@ -112,15 +113,8 @@ void hal_hardware_init(void)
     HAL_DCACHE_ENABLE();
     HAL_ICACHE_ENABLE();
 
-#ifndef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
-#ifdef CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT
-    // then enable the interrupt for incoming characters and break
-    // into the stub ROM if the char is a ^C.
-    HAL_INTERRUPT_UNMASK( CYG_DIAG_DEV_INT );
-    // hal_diag.c: hal_ctrlc_isr( CYG_ADDRWORD vector, CYG_ADDRWORD data)
-    // is polled from the default ISR so it's OK just to enable this.   
-#endif
-#endif
+    // Set up eCos/ROM interfaces
+    hal_if_init();
 }
 
 // -------------------------------------------------------------------------
--- a/packages/hal/arm/ebsa285/current/src/hal_diag.c
+++ b/packages/hal/arm/ebsa285/current/src/hal_diag.c
@@ -52,12 +52,273 @@
 #include <cyg/hal/hal_arch.h>           // basic machine info
 #include <cyg/hal/hal_intr.h>           // interrupt macros
 #include <cyg/hal/hal_io.h>             // IO macros
+#include <cyg/hal/hal_if.h>             // calling interface API
+#include <cyg/hal/hal_misc.h>           // helper functions
 #include <cyg/hal/hal_diag.h>
+#include <cyg/hal/hal_ebsa285.h>        // Hardware definitions
+#include <cyg/hal/drv_api.h>            // cyg_drv_interrupt_acknowledge
+
+/*---------------------------------------------------------------------------*/
+
+struct ebsa_serial {
+  volatile cyg_uint32 data_register;
+  volatile cyg_uint32 rxstat;
+  volatile cyg_uint32 h_baud_control;
+  volatile cyg_uint32 m_baud_control;
+  volatile cyg_uint32 l_baud_control;
+  volatile cyg_uint32 control_register;
+  volatile cyg_uint32 flag_register;
+};
+
+/*---------------------------------------------------------------------------*/
+
+static void
+init_channel(void* __ch_data)
+{
+    volatile struct ebsa_serial* base = (struct ebsa_serial*)__ch_data;
+
+    int dummy;
+    /*
+     * Make sure everything is off
+     */
+    base->control_register = SA110_UART_DISABLED | SA110_SIR_DISABLED;
+    
+    /*
+     * Read the RXStat to drain the fifo
+     */
+    dummy = base->rxstat;
+
+    /*
+     * Set the baud rate - this also turns the uart on.
+     *
+     * Note that the ordering of these writes is critical,
+     * and the writes to the H_BAUD_CONTROL and CONTROL_REGISTER
+     * are necessary to force the UART to update its register
+     * contents.
+     */
+    base->l_baud_control   = 0x13; // bp->divisor_low;
+    base->m_baud_control   = 0x00; // bp->divisor_high;
+    base->h_baud_control = SA110_UART_BREAK_DISABLED    |
+        SA110_UART_PARITY_DISABLED   |
+        SA110_UART_STOP_BITS_ONE     |
+        SA110_UART_FIFO_ENABLED      |
+        SA110_UART_DATA_LENGTH_8_BITS;
+    base->control_register = SA110_UART_ENABLED | SA110_SIR_DISABLED;
+    // All done
+}
+
+void
+cyg_hal_plf_serial_putc(void *__ch_data, char c)
+{
+    volatile struct ebsa_serial* base = (struct ebsa_serial*)__ch_data;
+    CYGARC_HAL_SAVE_GP();
+
+    // Wait for Tx FIFO not full
+    while ((base->flag_register & SA110_TX_FIFO_STATUS_MASK) == SA110_TX_FIFO_BUSY)
+        ;
+    base->data_register = c;
+
+    CYGARC_HAL_RESTORE_GP();
+}
+
+
+static cyg_bool
+cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch)
+{
+    volatile struct ebsa_serial* base = (struct ebsa_serial*)__ch_data;
+
+
+    if ((base->flag_register & SA110_RX_FIFO_STATUS_MASK) == SA110_RX_FIFO_EMPTY)
+        return false;
+
+    *ch = (char)(base->data_register & 0xFF);
+
+    return true;
+}
+
+
+cyg_uint8
+cyg_hal_plf_serial_getc(void* __ch_data)
+{
+    cyg_uint8 ch;
+    CYGARC_HAL_SAVE_GP();
+
+    while(!cyg_hal_plf_serial_getc_nonblock(__ch_data, &ch));
+
+    CYGARC_HAL_RESTORE_GP();
+    return ch;
+}
+
+#if defined(CYGSEM_HAL_VIRTUAL_VECTOR_DIAG) \
+    || defined(CYGPRI_HAL_IMPLEMENTS_IF_SERVICES)
+
+static cyg_int32 msec_timeout;
+
+static void
+cyg_hal_plf_serial_write(void* __ch_data, const cyg_uint8* __buf, 
+                         cyg_uint32 __len)
+{
+    CYGARC_HAL_SAVE_GP();
+
+    while(__len-- > 0)
+        cyg_hal_plf_serial_putc(__ch_data, *__buf++);
+
+    CYGARC_HAL_RESTORE_GP();
+}
+
+static void
+cyg_hal_plf_serial_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
+{
+    CYGARC_HAL_SAVE_GP();
+
+    while(__len-- > 0)
+        *__buf++ = cyg_hal_plf_serial_getc(__ch_data);
+
+    CYGARC_HAL_RESTORE_GP();
+}
+
+cyg_bool
+cyg_hal_plf_serial_getc_timeout(void* __ch_data, cyg_uint8* ch)
+{
+    int delay_count;
+    cyg_bool res;
+    CYGARC_HAL_SAVE_GP();
+
+    delay_count = msec_timeout * 10; // delay in .1 ms steps
+
+    for(;;) {
+        res = cyg_hal_plf_serial_getc_nonblock(__ch_data, ch);
+        if (res || 0 == delay_count--)
+            break;
+        
+        CYGACC_CALL_IF_DELAY_US(100);
+    }
+
+    CYGARC_HAL_RESTORE_GP();
+    return res;
+}
+
+static int
+cyg_hal_plf_serial_control(void *__ch_data, __comm_control_cmd_t __func, ...)
+{
+    static int irq_state = 0;
+    int ret = 0;
+    CYGARC_HAL_SAVE_GP();
+
+    switch (__func) {
+    case __COMMCTL_IRQ_ENABLE:
+        irq_state = 1;
+
+        HAL_INTERRUPT_UNMASK(CYGNUM_HAL_INTERRUPT_SERIAL_RX);
+        break;
+    case __COMMCTL_IRQ_DISABLE:
+        ret = irq_state;
+        irq_state = 0;
+
+        HAL_INTERRUPT_MASK(CYGNUM_HAL_INTERRUPT_SERIAL_RX);
+        break;
+    case __COMMCTL_DBG_ISR_VECTOR:
+        ret = CYGNUM_HAL_INTERRUPT_SERIAL_RX;
+        break;
+    case __COMMCTL_SET_TIMEOUT:
+    {
+        va_list ap;
+
+        va_start(ap, __func);
+
+        ret = msec_timeout;
+        msec_timeout = va_arg(ap, cyg_uint32);
+
+        va_end(ap);
+    }        
+    default:
+        break;
+    }
+    CYGARC_HAL_RESTORE_GP();
+    return ret;
+}
+
+static int
+cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc, 
+                       CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
+{
+    int reg, res = 0;
+    volatile struct ebsa_serial* base = (struct ebsa_serial*)__ch_data;
+    char c;
+    CYGARC_HAL_SAVE_GP();
+
+    if ( CYGNUM_HAL_INTERRUPT_SERIAL_RX == __vector ) {
+      reg = base->flag_register;
+      // read it anyway just in case - no harm done and we might
+      // prevent an interrup loop
+      c = (char)(base->data_register & 0xFF);
+
+      cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_SERIAL_RX);
+      *__ctrlc = 0;
+      if ( (reg & SA110_RX_FIFO_STATUS_MASK) != SA110_RX_FIFO_EMPTY ) {
+        if( cyg_hal_is_break( &c , 1 ) )
+          *__ctrlc = 1;
+
+        res = CYG_ISR_HANDLED;
+      }
+    }
+
+    CYGARC_HAL_RESTORE_GP();
+    return res;
+}
+
+static void
+cyg_hal_plf_serial_init(void)
+{
+    hal_virtual_comm_table_t* comm;
+    int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+
+    // Init channels
+    init_channel((void*)UART_BASE_0);
+
+    // Setup procs in the vector table
+
+    // Set channel 0
+    CYGACC_CALL_IF_SET_CONSOLE_COMM(0);
+    comm = CYGACC_CALL_IF_CONSOLE_PROCS();
+    CYGACC_COMM_IF_CH_DATA_SET(*comm, UART_BASE_0);
+    CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
+    CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
+    CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
+    CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
+    CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
+    CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
+    CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
+
+    // Restore original console
+    CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
+}
+
+void
+cyg_hal_plf_comms_init(void)
+{
+    static int initialized = 0;
+
+    if (initialized)
+        return;
+
+    initialized = 1;
+
+    cyg_hal_plf_serial_init();
+}
+#endif // CYGSEM_HAL_VIRTUAL_VECTOR_DIAG || CYGPRI_HAL_IMPLEMENTS_IF_SERVICES
+
+
+
+//=============================================================================
+// Compatibility with older stubs
+//=============================================================================
+
+#ifndef CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
+
 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
-#include <cyg/hal/drv_api.h>            // cyg_drv_interrupt_acknowledge
 #include <cyg/hal/hal_stub.h>           // cyg_hal_gdb_interrupt
 #endif
-#include <cyg/hal/hal_ebsa285.h>        // Hardware definitions
 
 #ifdef CYGSEM_HAL_ROM_MONITOR
 #define CYG_HAL_STARTUP_ROM
@@ -71,24 +332,26 @@
 /*---------------------------------------------------------------------------*/
 // EBSA285 Serial Port (UARTx) for Debug
 
+void hal_diag_init(void)
+{
+  init_channel((void*)UART_BASE_0);
+}
+
+
 // Actually send character down the wire
 static void
 hal_diag_write_char_serial(char c)
 {
-    // Wait for Tx FIFO not full
-    while ((*SA110_UART_FLAG_REGISTER & SA110_TX_FIFO_STATUS_MASK) == SA110_TX_FIFO_BUSY)
-        ;
-    *SA110_UART_DATA_REGISTER = c;
+    cyg_hal_plf_serial_putc((void*)UART_BASE_0, c);
 }
 
 static bool
 hal_diag_read_serial(char *c)
 {
     long timeout = 1000000000;  // A long time...
-    while ((*SA110_UART_FLAG_REGISTER & SA110_RX_FIFO_STATUS_MASK) == SA110_RX_FIFO_EMPTY)
-        if ( --timeout == 0 )
-            return false;
-    *c = (char)(*SA110_UART_DATA_REGISTER & 0xFF);
+    while (! cyg_hal_plf_serial_getc_nonblock((void*)UART_BASE_0, c) )
+        if ( --timeout == 0 ) return false;
+
     return true;
 }
 
@@ -124,39 +387,6 @@ const static struct _baud bauds[] = {
 };
 #endif
 
-void hal_diag_init(void)
-{
-    int dummy;
-    /*
-     * Make sure everything is off
-     */
-    *SA110_UART_CONTROL_REGISTER = SA110_UART_DISABLED | SA110_SIR_DISABLED;
-    
-    /*
-     * Read the RXStat to drain the fifo
-     */
-    dummy = *SA110_UART_RXSTAT;
-
-    /*
-     * Set the baud rate - this also turns the uart on.
-     *
-     * Note that the ordering of these writes is critical,
-     * and the writes to the H_BAUD_CONTROL and CONTROL_REGISTER
-     * are necessary to force the UART to update its register
-     * contents.
-     */
-    *SA110_UART_L_BAUD_CONTROL   = 0x13; // bp->divisor_low;
-    *SA110_UART_M_BAUD_CONTROL   = 0x00; // bp->divisor_high;
-    *SA110_UART_H_BAUD_CONTROL = SA110_UART_BREAK_DISABLED    |
-        SA110_UART_PARITY_DISABLED   |
-        SA110_UART_STOP_BITS_ONE     |
-        SA110_UART_FIFO_ENABLED      |
-        SA110_UART_DATA_LENGTH_8_BITS;
-    *SA110_UART_CONTROL_REGISTER = SA110_UART_ENABLED | 
-        SA110_SIR_DISABLED;
-    // All done
-}
-
 #ifdef HAL_DIAG_USES_HARDWARE
 
 #ifdef DEBUG_DIAG
@@ -270,7 +500,7 @@ hal_diag_write_char(char c)
                 break;              // a good acknowledge
 
 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
-            cyg_drv_interrupt_acknowledge(CYG_DIAG_DEV_INT);
+            cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_SERIAL_RX);
             if( c1 == 3 ) {
                 // Ctrl-C: breakpoint.
                 cyg_hal_gdb_interrupt(
@@ -297,31 +527,7 @@ hal_diag_write_char(char c)
 }
 #endif
 
-/*---------------------------------------------------------------------------*/
-#ifndef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
-#ifdef CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT
-// This routine is polled from the default ISR - the assumption is that any
-// other ISR installed knows what it's going and can handle a ^C correctly.
-int hal_ctrlc_isr( CYG_ADDRWORD vector, CYG_ADDRWORD data)
-{
-    char c;
-    int reg;
-    if ( CYG_DIAG_DEV_INT != vector )
-        return 0; // not for us
-
-    reg = *SA110_UART_FLAG_REGISTER;
-    // read it anyway just in case - no harm done and we might prevent an
-    // interrup loop
-    c = (char)(*SA110_UART_DATA_REGISTER & 0xFF);
-    if ( (reg & SA110_RX_FIFO_STATUS_MASK) != SA110_RX_FIFO_EMPTY ) {
-        if ( 3 == c ) {
-            HAL_BREAKPOINT( hal_ctrlc_isr_breakinst );
-        }
-    }
-    return 1;
-}
-#endif
-#endif
+#endif // !CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
 
 /*---------------------------------------------------------------------------*/
 /* End of hal_diag.c */
--- a/packages/hal/arm/edb7xxx/current/ChangeLog
+++ b/packages/hal/arm/edb7xxx/current/ChangeLog
@@ -1,3 +1,27 @@
+2000-07-07  Jesper Skov  <jskov@redhat.com>
+
+	* src/edb7xxx_misc.c (dram_delay_loop): 
+	* src/hal_diag.c (cyg_hal_plf_serial_getc,
+	(cyg_hal_plf_serial_putc): Added delay loop.
+
+2000-07-05  Jesper Skov  <jskov@redhat.com>
+
+	* include/plf_stub.h (HAL_STUB_PLATFORM_RESET_ENTRY): Not comitted.
+
+	* src/hal_diag.c: 
+	* cdl/hal_arm_edb7xxx.cdl: 
+	Clean up channel options.
+	
+	* src/plf_stub.c: [deleted]
+	* src/hal_diag.c:
+	* src/edb7xxx_misc.c: 
+	* include/plf_stub.h:
+	* include/hal_diag.h: 
+	* cdl/hal_arm_edb7xxx.cdl: 
+	Changed to use virtual vectors.
+
+	* include/hal_platform_setup.h: #error instead of #err.
+
 2000-06-18  Gary Thomas  <gthomas@redhat.com>
 
 	* include/pkgconf/mlt_arm_cl7111_ram.ldi: 
--- a/packages/hal/arm/edb7xxx/current/cdl/hal_arm_edb7xxx.cdl
+++ b/packages/hal/arm/edb7xxx/current/cdl/hal_arm_edb7xxx.cdl
@@ -50,10 +50,11 @@ cdl_package CYGPKG_HAL_ARM_EDB7XXX {
         The EDB7XXX HAL package provides the support needed to run
         eCos on a Cirrus Logic development board."
 
-    compile       hal_diag.c plf_stub.c edb7xxx_misc.c
+    compile       hal_diag.c edb7xxx_misc.c
 
     implements    CYGINT_HAL_DEBUG_GDB_STUBS
     implements    CYGINT_HAL_DEBUG_GDB_STUBS_BREAK
+    implements    CYGINT_HAL_VIRTUAL_VECTOR_SUPPORT
 
     define_proc {
         puts $::cdl_system_header "#define CYGBLD_HAL_TARGET_H   <pkgconf/hal_arm.h>"
@@ -115,17 +116,7 @@ cdl_package CYGPKG_HAL_ARM_EDB7XXX {
             into ROM."
     }
 
-    cdl_option CYGHWR_HAL_ARM_EDB7XXX_DIAG_PORT {
-        display       "Diagnostic serial port"
-        flavor        data
-        legal_values  0 1
-        default_value 0
-        description   "
-            The Cirrus Logic evaluation boards have two separate serial ports.  This option
-            chooses which of these ports will be used."
-    }
-
-    cdl_option CYGHWR_HAL_ARM_EDB7XXX_DIAG_BAUD {
+    cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD {
         display       "Diagnostic serial port baud rate"
         flavor        data
         legal_values  9600 19200 38400 115200
@@ -136,18 +127,7 @@ cdl_package CYGPKG_HAL_ARM_EDB7XXX {
             diagnostic and GDB port are the same."
     }
 
-    cdl_option CYGHWR_HAL_ARM_EDB7XXX_GDB_PORT {
-        display       "GDB serial port"
-        flavor        data
-        legal_values  0 1
-        default_value 0
-        description   "
-            The Cirrus Logic evlauation boards have two separate serial ports.  This option
-            chooses which of these ports will be used to connect to a host
-            running GDB."
-    }
-
-    cdl_option CYGHWR_HAL_ARM_EDB7XXX_GDB_BAUD {
+    cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL_BAUD {
         display       "GDB serial port baud rate"
         flavor        data
         legal_values  9600 19200 38400 115200
@@ -156,6 +136,33 @@ cdl_package CYGPKG_HAL_ARM_EDB7XXX {
             This option controls the baud rate used for the GDB connection."
     }
     
+    cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS {
+        display      "Number of communication channels on the board"
+        flavor       data
+        calculated   2
+    }
+ 
+    cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL {
+        display          "Debug serial port"
+        flavor data
+        legal_values     0 to CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS-1
+        default_value    0
+        description      "
+            The EDB7xxx boards have two serial ports. This option
+            chooses which port will be used to connect to a host
+            running GDB."
+     }
+ 
+     cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL {
+         display          "Diagnostic serial port"
+         flavor data
+         legal_values     0 to CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS-1
+         default_value    0
+         description      "
+            The EDB7xxx boards have two serial ports.  This option
+            chooses which port will be used for diagnostic output."
+     }
+
     cdl_option CYGHWR_HAL_ARM_EDB7XXX_PROCESSOR_CLOCK {
         display       "Processor clock rate"
         flavor        data
@@ -268,8 +275,8 @@ cdl_package CYGPKG_HAL_ARM_EDB7XXX {
             requires CYGSEM_HAL_ROM_MONITOR
             requires CYGBLD_BUILD_COMMON_GDB_STUBS
             requires CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
-            requires ! CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
-            requires ! CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT
+            requires CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
+            requires CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT
             requires ! CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT
             requires ! CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM
             no_define
@@ -531,4 +538,25 @@ cdl_package CYGPKG_HAL_ARM_EDB7XXX {
             }
         }
     }
+
+    cdl_option CYGSEM_HAL_USE_ROM_MONITOR {
+         display       "Work with a ROM monitor"
+         flavor        booldata
+         legal_values  { "Generic" "GDB_stubs" }
+         default_value { CYG_HAL_STARTUP == "RAM" ? "GDB_stubs" : 0 }
+         parent        CYGPKG_HAL_ROM_MONITOR
+         requires      { CYG_HAL_STARTUP == "RAM" }
+         description   "
+             Support can be enabled for different varieties of ROM monitor.
+             This support changes various eCos semantics such as the encoding
+             of diagnostic output, or the overriding of hardware interrupt
+             vectors.
+             Firstly there is \"Generic\" support which prevents the HAL
+             from overriding the hardware vectors that it does not use, to
+             instead allow an installed ROM monitor to handle them. This is
+             the most basic support which is likely to be common to most
+             implementations of ROM monitor.
+             \"GDB_stubs\" provides support when GDB stubs are included in
+             the ROM monitor or boot ROM."
+     }
 }
--- a/packages/hal/arm/edb7xxx/current/include/hal_diag.h
+++ b/packages/hal/arm/edb7xxx/current/include/hal_diag.h
@@ -49,6 +49,16 @@
 
 #include <cyg/infra/cyg_type.h>
 
+#if defined(CYGSEM_HAL_VIRTUAL_VECTOR_DIAG)
+
+#include <cyg/hal/hal_if.h>
+
+#define HAL_DIAG_INIT() hal_if_diag_init()
+#define HAL_DIAG_WRITE_CHAR(_c_) hal_if_diag_write_char(_c_)
+#define HAL_DIAG_READ_CHAR(_c_) hal_if_diag_read_char(&_c_)
+
+#else // everything by steam
+
 /*---------------------------------------------------------------------------*/
 /* functions implemented in hal_diag.c                                       */
 
@@ -64,6 +74,8 @@ externC void hal_diag_read_char(char *c)
 
 #define HAL_DIAG_READ_CHAR(_c_) hal_diag_read_char(&_c_)
 
+#endif // CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
+
 /*---------------------------------------------------------------------------*/
 /* end of hal_diag.h                                                         */
 #endif /* CYGONCE_HAL_DIAG_H */
--- a/packages/hal/arm/edb7xxx/current/include/hal_platform_setup.h
+++ b/packages/hal/arm/edb7xxx/current/include/hal_platform_setup.h
@@ -113,7 +113,7 @@
 // Define startup code [macros]
 #if defined(CYGSEM_HAL_INSTALL_MMU_TABLES) && !defined(CYG_HAL_STARTUP_RAM)
 
-#ifdef CYGPKG_HAL_ARM_CL7111 // CL7111, 710 processor
+#ifdef CYGHWR_HAL_ARM_EDB7XXX_VARIANT_CL_PS7111 // CL7111, 710 processor
 #define MMU_INITIALIZE                                                   \
 	ldr	r2,=MMU_Control_Init                                    ;\
 	mcr	MMU_CP,0,r2,MMU_Control,c0	/* MMU off */           ;\
@@ -315,7 +315,7 @@ 15:	mov	r6,r5		/* Build page table entry
         b       10b             /* Next section */                           ;\
 20:
 #else
-#err Invalid DRAM size select
+#error Invalid DRAM size select
 #endif
 
 #define PLATFORM_SETUP1                                                       \
--- a/packages/hal/arm/edb7xxx/current/include/plf_stub.h
+++ b/packages/hal/arm/edb7xxx/current/include/plf_stub.h
@@ -54,24 +54,24 @@
 #include <cyg/hal/arm_stub.h>           // architecture stub support
 
 //----------------------------------------------------------------------------
-// Define serial stuff.
+// Define some platform specific communication details. This is mostly
+// handled by hal_if now, but we need to make sure the comms tables are
+// properly initialized.
 
-extern void hal_edb7xxx_init_serial(void);
-extern int  hal_edb7xxx_get_char(void);
-extern void hal_edb7xxx_put_char(int c);
-extern int  hal_edb7xxx_interruptible(int);
+externC void cyg_hal_plf_comms_init(void);
 
-#define HAL_STUB_PLATFORM_INIT_SERIAL()       hal_edb7xxx_init_serial()
-#define HAL_STUB_PLATFORM_GET_CHAR()          hal_edb7xxx_get_char()
-#define HAL_STUB_PLATFORM_PUT_CHAR(c)         hal_edb7xxx_put_char((c))
+#define HAL_STUB_PLATFORM_INIT_SERIAL()       cyg_hal_plf_comms_init()
+
 #define HAL_STUB_PLATFORM_SET_BAUD_RATE(baud) CYG_UNUSED_PARAM(int, (baud))
-#define HAL_STUB_PLATFORM_INTERRUPTIBLE       (&hal_edb7xxx_interruptible)
+#define HAL_STUB_PLATFORM_INTERRUPTIBLE       0
 #define HAL_STUB_PLATFORM_INIT_BREAK_IRQ()    CYG_EMPTY_STATEMENT
 
 //----------------------------------------------------------------------------
 // Stub initializer.
 #define HAL_STUB_PLATFORM_INIT()              CYG_EMPTY_STATEMENT
 
+#endif // ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
+
 //----------------------------------------------------------------------------
 // Reset.
 
@@ -80,7 +80,7 @@ extern int  hal_edb7xxx_interruptible(in
 externC void reset_platform(void);
 #define HAL_STUB_PLATFORM_RESET() reset_platform()
 
-#endif // ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
+#define HAL_STUB_PLATFORM_RESET_ENTRY 0xe0000000
 
 //-----------------------------------------------------------------------------
 #endif // CYGONCE_HAL_PLF_STUB_H
--- a/packages/hal/arm/edb7xxx/current/src/edb7xxx_misc.c
+++ b/packages/hal/arm/edb7xxx/current/src/edb7xxx_misc.c
@@ -55,6 +55,7 @@
 #include <cyg/hal/hal_intr.h>           // Interrupt names
 #include <cyg/hal/hal_cache.h>
 #include <cyg/hal/hal_edb7xxx.h>         // Hardware definitions
+#include <cyg/hal/hal_if.h>             // calling interface API
 
 // #define CYGHWR_HAL_ARM_EDB7XXX_BATLOW
 #ifdef CYGHWR_HAL_ARM_EDB7XXX_BATLOW
@@ -155,6 +156,16 @@ void hal_clock_read(cyg_uint32 *pvalue)
     *pvalue = (cyg_uint32)(_period - clock_val);    // 'clock_val' counts down and wraps
 }
 
+void
+dram_delay_loop(void)
+{
+    // Temporary fix for DRAM starvation problem
+    if (CYGHWR_HAL_ARM_EDB7XXX_PROCESSOR_CLOCK > 37000) {
+        int i;
+        for (i = 0;  i < (CYGHWR_HAL_ARM_EDB7XXX_PROCESSOR_CLOCK*2)/24;  i++) ;  // approx 300 us
+    }
+}
+
 // These tables map the various [soft] interrupt numbers onto the hardware
 
 static cyg_uint32 hal_interrupt_bitmap[] = {
@@ -382,6 +393,9 @@ void hal_hardware_init(void)
     cyg_drv_interrupt_attach(batlow_interrupt_handle);
     cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_BLINT);
 #endif
+
+    // Set up eCos/ROM interfaces
+    hal_if_init();
 }
 
 //
--- a/packages/hal/arm/edb7xxx/current/src/hal_diag.c
+++ b/packages/hal/arm/edb7xxx/current/src/hal_diag.c
@@ -52,25 +52,277 @@
 #include <cyg/hal/hal_arch.h>           // basic machine info
 #include <cyg/hal/hal_intr.h>           // interrupt macros
 #include <cyg/hal/hal_io.h>             // IO macros
+#include <cyg/hal/hal_if.h>             // calling interface API
+#include <cyg/hal/hal_misc.h>           // helper functions
 #include <cyg/hal/hal_diag.h>
-#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
 #include <cyg/hal/drv_api.h>
-#include <cyg/hal/hal_stub.h>           // cyg_hal_gdb_interrupt
-#endif
 #include <cyg/hal/hal_edb7xxx.h>         // Hardware definitions
 
-#if CYGHWR_HAL_ARM_EDB7XXX_DIAG_PORT == 0
-#define CYG_DIAG_DEV_DATA UARTDR1
-#define CYG_DIAG_DEV_BLCR UBLCR1
-#define CYG_DIAG_DEV_STAT SYSFLG1
-#define CYG_DIAG_DEV_CTRL SYSCON1
-#define CYG_DIAG_DEV_INT  CYGNUM_HAL_INTERRUPT_URXINT1
-#else
-#define CYG_DIAG_DEV_DATA UARTDR2
-#define CYG_DIAG_DEV_STAT SYSFLG2
-#define CYG_DIAG_DEV_CTRL SYSCON2
-#define CYG_DIAG_DEV_BLCR UBLCR2
-#define CYG_DIAG_DEV_INT  CYGNUM_HAL_INTERRUPT_URXINT2
+//-----------------------------------------------------------------------------
+
+struct edb_serial {
+    volatile cyg_uint32 ctrl;
+    cyg_uint32 pad004_040[16-1];
+    volatile cyg_uint32 stat;
+    cyg_uint32 pad044_37c[208-1];
+    union {
+        volatile cyg_uint8 write;
+        volatile cyg_uint32 read;    // Need to read 32 bits
+    } data;
+    cyg_uint32 pad384_3BC[16-1];
+    volatile cyg_uint32 blcr;
+};
+
+//-----------------------------------------------------------------------------
+typedef struct {
+    volatile struct edb_serial* base;
+    cyg_int32 msec_timeout;
+    int isr_vector;
+} channel_data_t;
+
+//-----------------------------------------------------------------------------
+
+static void
+cyg_hal_plf_serial_init_channel(channel_data_t* __ch_data)
+{
+    channel_data_t* chan = (channel_data_t*)__ch_data;
+
+    // Enable port
+    chan->base->ctrl |= SYSCON1_UART1EN;
+    // Configure
+    chan->base->blcr = UART_BITRATE(CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD) |
+                       UBLCR_FIFOEN | UBLCR_WRDLEN8;
+}
+
+
+// Call this delay function when polling for serial access - otherwise
+// the CPU will keep the memory bus busy and thus prevent DRAM refresh
+// (and the resulting memory corruption).
+externC void dram_delay_loop(void);
+
+void
+cyg_hal_plf_serial_putc(void *__ch_data, char c)
+{
+    channel_data_t* chan = (channel_data_t*)__ch_data;
+    CYGARC_HAL_SAVE_GP();
+
+    // Wait for Tx FIFO not full
+    while ((chan->base->stat & SYSFLG1_UTXFF1) != 0) 
+        dram_delay_loop();
+
+    chan->base->data.write = c;
+
+    CYGARC_HAL_RESTORE_GP();
+}
+
+static cyg_bool
+cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch)
+{
+    channel_data_t* chan = (channel_data_t*)__ch_data;
+
+    if ((chan->base->stat & SYSFLG1_URXFE1) != 0)
+        return false;
+
+    *ch = (cyg_uint8)(chan->base->data.read & 0xFF);
+
+    return true;
+}
+
+cyg_uint8
+cyg_hal_plf_serial_getc(void* __ch_data)
+{
+    cyg_uint8 ch;
+    CYGARC_HAL_SAVE_GP();
+
+    while(!cyg_hal_plf_serial_getc_nonblock(__ch_data, &ch))
+        dram_delay_loop();
+
+    CYGARC_HAL_RESTORE_GP();
+    return ch;
+}
+
+#if defined(CYGSEM_HAL_VIRTUAL_VECTOR_DIAG) \
+    || defined(CYGPRI_HAL_IMPLEMENTS_IF_SERVICES)
+
+static channel_data_t edb_ser_channels[2] = {
+    {(volatile struct edb_serial*)SYSCON1, 1000, CYGNUM_HAL_INTERRUPT_URXINT1},
+    {(volatile struct edb_serial*)SYSCON2, 1000, CYGNUM_HAL_INTERRUPT_URXINT2}
+};
+
+static void
+cyg_hal_plf_serial_write(void* __ch_data, const cyg_uint8* __buf, 
+                         cyg_uint32 __len)
+{
+    CYGARC_HAL_SAVE_GP();
+
+    while(__len-- > 0)
+        cyg_hal_plf_serial_putc(__ch_data, *__buf++);
+
+    CYGARC_HAL_RESTORE_GP();
+}
+
+static void
+cyg_hal_plf_serial_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
+{
+    CYGARC_HAL_SAVE_GP();
+
+    while(__len-- > 0)
+        *__buf++ = cyg_hal_plf_serial_getc(__ch_data);
+
+    CYGARC_HAL_RESTORE_GP();
+}
+
+cyg_bool
+cyg_hal_plf_serial_getc_timeout(void* __ch_data, cyg_uint8* ch)
+{
+    int delay_count;
+    channel_data_t* chan = (channel_data_t*)__ch_data;
+    cyg_bool res;
+    CYGARC_HAL_SAVE_GP();
+
+    delay_count = chan->msec_timeout * 10; // delay in .1 ms steps
+
+    for(;;) {
+        res = cyg_hal_plf_serial_getc_nonblock(__ch_data, ch);
+        if (res || 0 == delay_count--)
+            break;
+        
+        CYGACC_CALL_IF_DELAY_US(100);
+    }
+
+    CYGARC_HAL_RESTORE_GP();
+    return res;
+}
+
+static int
+cyg_hal_plf_serial_control(void *__ch_data, __comm_control_cmd_t __func, ...)
+{
+    static int irq_state = 0;
+    channel_data_t* chan = (channel_data_t*)__ch_data;
+    int ret = 0;
+    CYGARC_HAL_SAVE_GP();
+
+    switch (__func) {
+    case __COMMCTL_IRQ_ENABLE:
+        irq_state = 1;
+        HAL_INTERRUPT_UNMASK(chan->isr_vector);
+        break;
+    case __COMMCTL_IRQ_DISABLE:
+        ret = irq_state;
+        irq_state = 0;
+        HAL_INTERRUPT_MASK(chan->isr_vector);
+        break;
+    case __COMMCTL_DBG_ISR_VECTOR:
+        ret = chan->isr_vector;
+        break;
+    case __COMMCTL_SET_TIMEOUT:
+    {
+        va_list ap;
+
+        va_start(ap, __func);
+
+        ret = chan->msec_timeout;
+        chan->msec_timeout = va_arg(ap, cyg_uint32);
+
+        va_end(ap);
+    }        
+    default:
+        break;
+    }
+    CYGARC_HAL_RESTORE_GP();
+    return ret;
+}
+
+static int
+cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc, 
+                       CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
+{
+    int res = 0;
+    channel_data_t* chan = (channel_data_t*)__ch_data;
+    char c;
+    CYGARC_HAL_SAVE_GP();
+
+    cyg_drv_interrupt_acknowledge(chan->isr_vector);
+
+    *__ctrlc = 0;
+    if ((chan->base->stat & SYSFLG1_URXFE1) == 0) {
+        c = (cyg_uint8)(chan->base->data.read & 0xFF);
+        if( cyg_hal_is_break( &c , 1 ) )
+            *__ctrlc = 1;
+
+        res = CYG_ISR_HANDLED;
+    }
+
+    CYGARC_HAL_RESTORE_GP();
+    return res;
+}
+
+static void
+cyg_hal_plf_serial_init(void)
+{
+    hal_virtual_comm_table_t* comm;
+    int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+
+    // Disable interrupts.
+    HAL_INTERRUPT_MASK(edb_ser_channels[0].isr_vector);
+    HAL_INTERRUPT_MASK(edb_ser_channels[1].isr_vector);
+
+    // Init channels
+    cyg_hal_plf_serial_init_channel(&edb_ser_channels[0]);
+    cyg_hal_plf_serial_init_channel(&edb_ser_channels[1]);
+
+    // Setup procs in the vector table
+
+    // Set channel 0
+    CYGACC_CALL_IF_SET_CONSOLE_COMM(0);
+    comm = CYGACC_CALL_IF_CONSOLE_PROCS();
+    CYGACC_COMM_IF_CH_DATA_SET(*comm, &edb_ser_channels[0]);
+    CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
+    CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
+    CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
+    CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
+    CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
+    CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
+    CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
+
+    // Set channel 1
+    CYGACC_CALL_IF_SET_CONSOLE_COMM(1);
+    comm = CYGACC_CALL_IF_CONSOLE_PROCS();
+    CYGACC_COMM_IF_CH_DATA_SET(*comm, &edb_ser_channels[1]);
+    CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
+    CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
+    CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
+    CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_plf_serial_getc);
+    CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_plf_serial_control);
+    CYGACC_COMM_IF_DBG_ISR_SET(*comm, cyg_hal_plf_serial_isr);
+    CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, cyg_hal_plf_serial_getc_timeout);
+
+    // Restore original console
+    CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
+}
+
+void
+cyg_hal_plf_comms_init(void)
+{
+    static int initialized = 0;
+
+    if (initialized)
+        return;
+
+    initialized = 1;
+
+    cyg_hal_plf_serial_init();
+}
+#endif // CYGSEM_HAL_VIRTUAL_VECTOR_DIAG || CYGPRI_HAL_IMPLEMENTS_IF_SERVICES
+
+//=============================================================================
+// Compatibility with older stubs
+//=============================================================================
+
+#ifndef CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
+
+#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
+#include <cyg/hal/hal_stub.h>           // cyg_hal_gdb_interrupt
 #endif
 
 // Assumption: all diagnostic output must be GDB packetized unless this is a ROM (i.e.
@@ -86,11 +338,23 @@
 #else
 #if defined(CYGDBG_HAL_DIAG_DISABLE_GDB_PROTOCOL)
 #define HAL_DIAG_USES_HARDWARE
-#elif CYGHWR_HAL_ARM_EDB7XXX_DIAG_PORT != CYGHWR_HAL_ARM_EDB7XXX_GDB_PORT
+#elif CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL != CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL
 #define HAL_DIAG_USES_HARDWARE
 #endif
 #endif
 
+#if CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL == 0
+# define __BASE ((volatile struct edb_serial*)SYSCON1)
+# define __IRQ  CYGNUM_HAL_INTERRUPT_URXINT1
+#else
+# define __BASE ((volatile struct edb_serial*)SYSCON2)
+# define __IRQ  CYGNUM_HAL_INTERRUPT_URXINT2
+#endif
+
+static channel_data_t edb_ser_channel = {
+    __BASE, 0, 0
+};
+
 /*---------------------------------------------------------------------------*/
 // EDB7XXX Serial Port (UARTx) for Debug
 
@@ -98,27 +362,17 @@
 static void
 hal_diag_write_char_serial(char c)
 {
-    cyg_uint32 stat;
-    // Wait for Tx FIFO not full
-    do {
-        stat = *(volatile cyg_uint32 *)CYG_DIAG_DEV_STAT;
-    } while ((stat & SYSFLG1_UTXFF1) != 0) ;
-    *(volatile cyg_uint8 *)CYG_DIAG_DEV_DATA = c;
+    cyg_hal_plf_serial_putc(&edb_ser_channel, c);
 }
 
 static bool
 hal_diag_read_serial(char *c)
 {
     long timeout = 1000000000;  // A long time...
-    cyg_uint32 stat, val;
 
-    do {
-        stat = *(volatile cyg_uint32 *)CYG_DIAG_DEV_STAT;
+    while (! cyg_hal_plf_serial_getc_nonblock(&edb_ser_channel, c) )
         if (--timeout == 0) return false;
-    } while ((stat & SYSFLG1_URXFE1) != 0);
-    // Need to read 32 bits
-    val = *(volatile cyg_uint32 *)CYG_DIAG_DEV_DATA & 0xFF;
-    *c = val;
+
     return true;
 }
 
@@ -132,12 +386,8 @@ void hal_diag_init(void)
 #endif
     if (init++) return;
 
-    // Enable port
-    *(volatile cyg_uint32 *)CYG_DIAG_DEV_CTRL |= SYSCON1_UART1EN;
-    // Configure
-    *(volatile cyg_uint32 *)CYG_DIAG_DEV_BLCR = 
-        UART_BITRATE(CYGHWR_HAL_ARM_EDB7XXX_DIAG_BAUD) |
-        UBLCR_FIFOEN | UBLCR_WRDLEN8;
+    cyg_hal_plf_serial_init_channel(&edb_ser_channel);
+
 #ifndef CYG_HAL_STARTUP_ROM
     while (*msg) hal_diag_write_char(*msg++);
 #endif
@@ -173,14 +423,8 @@ void hal_diag_read_char(char *c)
 // Initialize diag port
 void hal_diag_init(void)
 {
-#if 0  // Assume port is already setup
-    // Enable port
-    *(volatile cyg_uint32 *)CYG_DIAG_DEV_CTRL |= SYSCON1_UART1EN;
-    // Configure
-    *(volatile cyg_uint32 *)CYG_DIAG_DEV_BLCR = 
-        UART_BITRATE(CYGHWR_HAL_ARM_EDB7XXX_DIAG_BAUD) |
-        UBLCR_FIFOEN | UBLCR_WRDLEN8;
-#endif
+    // Assume port is already setup
+    if (0) cyg_hal_plf_serial_init_channel(&edb_ser_channel);
 }
 
 void 
@@ -250,7 +494,7 @@ hal_diag_write_char(char c)
                 break;              // a good acknowledge
 
 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
-            cyg_drv_interrupt_acknowledge(CYG_DIAG_DEV_INT);
+            cyg_drv_interrupt_acknowledge(__IRQ);
             if( c1 == 3 ) {
                 // Ctrl-C: breakpoint.
                 cyg_hal_gdb_interrupt (__builtin_return_address(0));
@@ -274,5 +518,7 @@ hal_diag_write_char(char c)
 }
 #endif
 
+#endif // !CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
+
 /*---------------------------------------------------------------------------*/
 /* End of hal_diag.c */
--- a/packages/hal/arm/pid/current/ChangeLog
+++ b/packages/hal/arm/pid/current/ChangeLog
@@ -1,3 +1,13 @@
+2000-07-07  Jesper Skov  <jskov@redhat.com>
+
+	* cdl/hal_arm_pid.cdl: CygMon changed to use virtual vectors.
+
+2000-07-05  Jesper Skov  <jskov@redhat.com>
+
+	* src/hal_diag.c:
+	* cdl/hal_arm_pid.cdl:
+	Clean up channel options.
+
 2000-07-04  Jesper Skov  <jskov@redhat.com>
 
 	* cdl/hal_arm_pid.cdl:
--- a/packages/hal/arm/pid/current/cdl/hal_arm_pid.cdl
+++ b/packages/hal/arm/pid/current/cdl/hal_arm_pid.cdl
@@ -84,17 +84,7 @@ cdl_package CYGPKG_HAL_ARM_PID {
 
     }
 
-    cdl_option CYGHWR_HAL_ARM_PID_DIAG_PORT {
-        display       "Diagnostic serial port"
-        flavor        data
-        legal_values  0 1
-        default_value 0
-        description   "
-            The PID board has two separate serial ports.  This option
-            chooses which of these ports will be used."
-    }
-
-    cdl_option CYGHWR_HAL_ARM_PID_DIAG_BAUD {
+    cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD {
         display       "Diagnostic serial port baud rate"
         flavor        data
         legal_values  9600 19200 38400 115200
@@ -105,18 +95,7 @@ cdl_package CYGPKG_HAL_ARM_PID {
             diagnostic and GDB port are the same."
     }
 
-    cdl_option CYGHWR_HAL_ARM_PID_GDB_PORT {
-        display       "GDB serial port"
-        flavor        data
-        legal_values  0 1
-        default_value 0
-        description   "
-            The PID board has two separate serial ports.  This option
-            chooses which of these ports will be used to connect to a host
-            running GDB."
-    }
-
-    cdl_option CYGHWR_HAL_ARM_PID_GDB_BAUD {
+    cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL_BAUD {
         display       "GDB serial port baud rate"
         flavor        data
         legal_values  9600 19200 38400 115200
@@ -153,7 +132,7 @@ cdl_package CYGPKG_HAL_ARM_PID {
         display          "Debug serial port"
         flavor data
         legal_values     0 to CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS-1
-        default_value    CYGHWR_HAL_ARM_PID_GDB_PORT
+        default_value    0
         description      "
             The PID board has only one serial port. This option
             chooses which port will be used to connect to a host
@@ -164,7 +143,7 @@ cdl_package CYGPKG_HAL_ARM_PID {
          display          "Diagnostic serial port"
          flavor data
          legal_values     0 to CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS-1
-         default_value    CYGHWR_HAL_ARM_PID_DIAG_PORT
+         default_value    0
          description      "
             The PID board has only one serial port.  This option
             chooses which port will be used for diagnostic output."
@@ -272,7 +251,7 @@ cdl_package CYGPKG_HAL_ARM_PID {
             display "Build flash programming tool"
             default_value 0
             requires { CYG_HAL_STARTUP == "RAM" }
-            requires CYGHWR_HAL_ARM_PID_DIAG_PORT == 1
+            requires CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL == 1
             requires CYGPKG_LIBC
             requires CYGPKG_KERNEL
             no_define
@@ -294,7 +273,7 @@ cdl_package CYGPKG_HAL_ARM_PID {
             display "Build flash programming tool for BE images on LE boards"
             default_value 0
             requires { CYG_HAL_STARTUP == "RAM" }
-            requires CYGHWR_HAL_ARM_PID_DIAG_PORT == 1
+            requires CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL == 1
             requires CYGPKG_LIBC
             requires CYGPKG_KERNEL
             no_define
@@ -364,28 +343,11 @@ cdl_package CYGPKG_HAL_ARM_PID {
         no_define
         parent        CYGPKG_CYGMON
         active_if     CYGPKG_CYGMON
-        requires      CYGPKG_IO_SERIAL_ARM_PID
-        requires      {(CYGDAT_CYGMON_CONSOLE_DEV != "\"/dev/ser0\"") || \
-                       (CYGPKG_IO_SERIAL_ARM_PID_SERIAL0 &&              \
-                       (CYGNUM_IO_SERIAL_ARM_PID_SERIAL0_BUFSIZE == 512))}
-        requires      {(CYGDAT_CYGMON_CONSOLE_DEV != "\"/dev/ser1\"") || \
-                       (CYGPKG_IO_SERIAL_ARM_PID_SERIAL1 &&              \
-                       (CYGNUM_IO_SERIAL_ARM_PID_SERIAL1_BUFSIZE == 512))}
         description   "
             This option also lists the target's requirements for a valid CygMon
             configuration."
 
 
-        cdl_option CYGDAT_CYGMON_CONSOLE_DEV {
-            display       "Serial port for default console"
-            flavor data
-            default_value { "\"/dev/ser0\"" }
-            description   "
-                This option selects the physical device to use as the default
-                console device for CygMon."
-
-        }
-
         cdl_option CYGBLD_BUILD_CYGMON_BIN {
             display       "Build CygMon ROM binary image"
             active_if     CYGBLD_BUILD_CYGMON
--- a/packages/hal/arm/pid/current/src/hal_diag.c
+++ b/packages/hal/arm/pid/current/src/hal_diag.c
@@ -58,19 +58,19 @@
 
 /*---------------------------------------------------------------------------*/
 /* From serial_16550.h */
-#if CYGHWR_HAL_ARM_PID_DIAG_BAUD==9600
+#if CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD==9600
 #define CYG_DEVICE_SERIAL_BAUD_MSB        0x00
 #define CYG_DEVICE_SERIAL_BAUD_LSB        0x0C
 #endif
-#if CYGHWR_HAL_ARM_PID_DIAG_BAUD==19200
+#if CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD==19200
 #define CYG_DEVICE_SERIAL_BAUD_MSB        0x00
 #define CYG_DEVICE_SERIAL_BAUD_LSB        0x06
 #endif
-#if CYGHWR_HAL_ARM_PID_DIAG_BAUD==38400
+#if CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD==38400
 #define CYG_DEVICE_SERIAL_BAUD_MSB        0x00
 #define CYG_DEVICE_SERIAL_BAUD_LSB        0x03
 #endif
-#if CYGHWR_HAL_ARM_PID_DIAG_BAUD==115200
+#if CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD==115200
 #define CYG_DEVICE_SERIAL_BAUD_MSB        0x00
 #define CYG_DEVICE_SERIAL_BAUD_LSB        0x01
 #endif
@@ -414,7 +414,7 @@ hal_diag_led(int n)
 #include <cyg/hal/hal_stub.h>           // cyg_hal_gdb_interrupt
 #endif
 
-#if CYGHWR_HAL_ARM_PID_DIAG_PORT==0
+#if CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL==0
 // This is the base address of the A-channel
 #define CYG_DEV_SERIAL_BASE      0x0D800000
 #define CYG_DEVICE_SERIAL_INT    CYGNUM_HAL_INTERRUPT_SERIALA
@@ -436,7 +436,7 @@ static channel_data_t pid_ser_channel = 
 #endif
 
 #ifndef HAL_DIAG_USES_HARDWARE
-#if (CYGHWR_HAL_ARM_PID_DIAG_PORT != CYGHWR_HAL_ARM_PID_GDB_PORT)
+#if (CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL != CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL)
 #define HAL_DIAG_USES_HARDWARE
 #endif
 #endif
--- a/packages/hal/arm/sa11x0/assabet/current/ChangeLog
+++ b/packages/hal/arm/sa11x0/assabet/current/ChangeLog
@@ -1,3 +1,7 @@
+2000-07-05  Jesper Skov  <jskov@redhat.com>
+
+	* cdl/hal_arm_sa11x0_assabet.cdl: Cleanup channel options.
+
 2000-06-27  Jesper Skov  <jskov@redhat.com>
 
 	* cdl/hal_arm_sa11x0_assabet.cdl: Changed PORT values.
--- a/packages/hal/arm/sa11x0/assabet/current/cdl/hal_arm_sa11x0_assabet.cdl
+++ b/packages/hal/arm/sa11x0/assabet/current/cdl/hal_arm_sa11x0_assabet.cdl
@@ -79,19 +79,7 @@ cdl_package CYGPKG_HAL_ARM_SA11X0_ASSABE
            building the eCos GDB stubs themselves."
     }
 
-    # Assabet board has only 1 serial port useable for diagnostic/GDB
-##    define CYGHWR_HAL_ARM_SA11X0_DIAG_PORT 1
-# FIXME - make this fixed.
-    cdl_option CYGHWR_HAL_ARM_SA11X0_DIAG_PORT {
-        display       "Diagnostic serial port"
-        flavor        data
-        legal_values  0 0
-        default_value 0
-        description   "
-            The Assabet evaluation boards has only one serial port."
-    }
-
-    cdl_option CYGHWR_HAL_ARM_SA11X0_DIAG_BAUD {
+    cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD {
         display       "Diagnostic serial port baud rate"
         flavor        data
         legal_values  9600 19200 38400 115200
@@ -102,16 +90,7 @@ cdl_package CYGPKG_HAL_ARM_SA11X0_ASSABE
             diagnostic and GDB port are the same."
     }
 
-    cdl_option CYGHWR_HAL_ARM_SA11X0_GDB_PORT {
-        display       "GDB serial port"
-        flavor        data
-        legal_values  0 0
-        default_value 0
-        description   "
-            The Assabet evaluation boards has only one serial port."
-    }
-
-    cdl_option CYGHWR_HAL_ARM_SA11X0_GDB_BAUD {
+    cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL_BAUD {
         display       "GDB serial port baud rate"
         flavor        data
         legal_values  9600 19200 38400 115200
--- a/packages/hal/arm/sa11x0/brutus/current/ChangeLog
+++ b/packages/hal/arm/sa11x0/brutus/current/ChangeLog
@@ -1,3 +1,7 @@
+2000-07-05  Jesper Skov  <jskov@redhat.com>
+
+	* cdl/hal_arm_sa11x0_brutus.cdl: Cleanup channel options.
+
 2000-06-26  Jesper Skov  <jskov@redhat.com>
 
 	* include/hal_platform_ints.h: Removed Ctrl-c handling.
--- a/packages/hal/arm/sa11x0/brutus/current/cdl/hal_arm_sa11x0_brutus.cdl
+++ b/packages/hal/arm/sa11x0/brutus/current/cdl/hal_arm_sa11x0_brutus.cdl
@@ -79,17 +79,7 @@ cdl_package CYGPKG_HAL_ARM_SA11X0_BRUTUS
            building the eCos GDB stubs themselves."
     }
 
-    cdl_option CYGHWR_HAL_ARM_SA11X0_DIAG_PORT {
-        display       "Diagnostic serial port"
-        flavor        data
-        legal_values  0 1
-        default_value 1
-        description   "
-            The Brutus evaluation boards have two separate serial ports.  This option
-            chooses which of these ports will be used."
-    }
-
-    cdl_option CYGHWR_HAL_ARM_SA11X0_DIAG_BAUD {
+    cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD {
         display       "Diagnostic serial port baud rate"
         flavor        data
         legal_values  9600 19200 38400 115200
@@ -100,17 +90,7 @@ cdl_package CYGPKG_HAL_ARM_SA11X0_BRUTUS
             diagnostic and GDB port are the same."
     }
 
-    cdl_option CYGHWR_HAL_ARM_SA11X0_GDB_PORT {
-        display       "GDB serial port"
-        flavor        data
-        legal_values  0 1
-        default_value 1
-        description   "
-            The Brutus evaluation boards have two separate serial ports.  This option
-            chooses which of these ports will be used."
-    }
-
-    cdl_option CYGHWR_HAL_ARM_SA11X0_GDB_BAUD {
+    cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL_BAUD {
         display       "GDB serial port baud rate"
         flavor        data
         legal_values  9600 19200 38400 115200
@@ -131,7 +111,7 @@ cdl_package CYGPKG_HAL_ARM_SA11X0_BRUTUS
         display          "Debug serial port"
         flavor data
         legal_values     0 to CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS-1
-        default_value    CYGHWR_HAL_ARM_SA11X0_GDB_PORT
+        default_value    1
         description      "
             The brutus board has two serial ports. This option
             chooses which port will be used to connect to a host
@@ -142,7 +122,7 @@ cdl_package CYGPKG_HAL_ARM_SA11X0_BRUTUS
          display          "Diagnostic serial port"
          flavor data
          legal_values     0 to CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS-1
-         default_value    CYGHWR_HAL_ARM_SA11X0_DIAG_PORT
+         default_value    1
          description      "
             The brutus board has two serial ports.  This option
             chooses which port will be used for diagnostic output."
--- a/packages/hal/arm/sa11x0/var/current/ChangeLog
+++ b/packages/hal/arm/sa11x0/var/current/ChangeLog
@@ -1,3 +1,18 @@
+2000-07-14  Gary Thomas  <gthomas@redhat.com>
+
+	* include/hal_diag.h (HAL_DELAY_US): Define.
+
+	* src/sa11x0_misc.c (hal_delay_us): New function.  Used to 
+	provide timers/delays in non-kernel systems.
+
+2000-07-05  Jesper Skov  <jskov@redhat.com>
+
+	* cdl/hal_arm_sa11x0.cdl: 
+	* src/hal_diag.c:
+	Cleaned up channel options.
+	
+	* src/hal_diag.c: Use per-channel structure instead of code cruft.
+
 2000-06-30  Jesper Skov  <jskov@redhat.com>
 
 	* src/hal_diag.c: calling i/f macro changes.
--- a/packages/hal/arm/sa11x0/var/current/include/hal_diag.h
+++ b/packages/hal/arm/sa11x0/var/current/include/hal_diag.h
@@ -60,6 +60,11 @@
 #define HAL_DIAG_WRITE_CHAR(_c_) hal_if_diag_write_char(_c_)
 #define HAL_DIAG_READ_CHAR(_c_)  hal_if_diag_read_char(&_c_)
 
+// Not the best place for this, but ...
+extern void hal_delay_us(cyg_int32 usecs);
+
+#define HAL_DELAY_US(n)          hal_delay_us(n);
+
 #else
 
 /*---------------------------------------------------------------------------*/
--- a/packages/hal/arm/sa11x0/var/current/src/hal_diag.c
+++ b/packages/hal/arm/sa11x0/var/current/src/hal_diag.c
@@ -71,13 +71,20 @@ struct sa11x0_serial {
   volatile cyg_uint32 utsr1;
 };
 
+//-----------------------------------------------------------------------------
+typedef struct {
+    volatile struct sa11x0_serial* base;
+    cyg_int32 msec_timeout;
+    int isr_vector;
+} channel_data_t;
+
 /*---------------------------------------------------------------------------*/
 // SA11x0 Serial Port (UARTx) for Debug
 
 static void
-init_channel(void* __ch_data)
+init_channel(channel_data_t* __ch_data)
 {
-    volatile struct sa11x0_serial* base = (struct sa11x0_serial*)__ch_data;
+    volatile struct sa11x0_serial* base = __ch_data->base;
     cyg_uint32 brd;
 
     // Disable Receiver and Transmitter (clears FIFOs)
@@ -106,7 +113,7 @@ init_channel(void* __ch_data)
                   SA11X0_UART_DATA_BITS_8;
 
     // Set the desired baud rate.
-    brd = SA11X0_UART_BAUD_RATE_DIVISOR(CYGHWR_HAL_ARM_SA11X0_DIAG_BAUD);
+    brd = SA11X0_UART_BAUD_RATE_DIVISOR(CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD);
     base->utcr1 = (brd >> 8) & SA11X0_UART_H_BAUD_RATE_DIVISOR_MASK;
     base->utcr2 = brd & SA11X0_UART_L_BAUD_RATE_DIVISOR_MASK;
 
@@ -119,7 +126,7 @@ init_channel(void* __ch_data)
 void
 cyg_hal_plf_serial_putc(void *__ch_data, char c)
 {
-    volatile struct sa11x0_serial* base = (struct sa11x0_serial*)__ch_data;
+    volatile struct sa11x0_serial* base = ((channel_data_t*)__ch_data)->base;
     CYGARC_HAL_SAVE_GP();
 
     // Wait for Tx FIFO not full
@@ -137,7 +144,7 @@ cyg_hal_plf_serial_putc(void *__ch_data,
 static cyg_bool
 cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch)
 {
-    volatile struct sa11x0_serial* base = (struct sa11x0_serial*)__ch_data;
+    volatile struct sa11x0_serial* base = ((channel_data_t*)__ch_data)->base;
 
     // If receive fifo is empty, return false
     if ((base->utsr1 & SA11X0_UART_RX_FIFO_NOT_EMPTY) == 0)
@@ -167,6 +174,11 @@ cyg_hal_plf_serial_getc(void* __ch_data)
 #if defined(CYGSEM_HAL_VIRTUAL_VECTOR_DIAG) \
     || defined(CYGPRI_HAL_IMPLEMENTS_IF_SERVICES)
 
+static channel_data_t ser_channels[2] = {
+    { (volatile struct sa11x0_serial*)SA11X0_UART1_BASE, 1000, CYGNUM_HAL_INTERRUPT_UART1 },
+    { (volatile struct sa11x0_serial*)SA11X0_UART3_BASE, 1000, CYGNUM_HAL_INTERRUPT_UART3 }
+};
+
 static void
 cyg_hal_plf_serial_write(void* __ch_data, const cyg_uint8* __buf, 
                          cyg_uint32 __len)
@@ -190,22 +202,15 @@ cyg_hal_plf_serial_read(void* __ch_data,
     CYGARC_HAL_RESTORE_GP();
 }
 
-cyg_int32 msec_timeout[2] = { 1000, 1000 };
-
 cyg_bool
 cyg_hal_plf_serial_getc_timeout(void* __ch_data, cyg_uint8* ch)
 {
     int delay_count;
-    int index;
+    channel_data_t* chan = (channel_data_t*)__ch_data;
     cyg_bool res;
     CYGARC_HAL_SAVE_GP();
 
-    if (SA11X0_UART1_BASE == __ch_data)
-        index = 0;
-    else
-        index = 1;
-
-    delay_count = msec_timeout[index] * 10; // delay in .1 ms steps
+    delay_count = chan->msec_timeout * 10; // delay in .1 ms steps
 
     for(;;) {
         res = cyg_hal_plf_serial_getc_nonblock(__ch_data, ch);
@@ -219,41 +224,32 @@ cyg_hal_plf_serial_getc_timeout(void* __
     return res;
 }
 
-static int isr_vectors[2] = {CYGNUM_HAL_INTERRUPT_UART1,
-                             CYGNUM_HAL_INTERRUPT_UART3};
-
 static int
 cyg_hal_plf_serial_control(void *__ch_data, __comm_control_cmd_t __func, ...)
 {
     static int irq_state = 0;
-    volatile struct sa11x0_serial* base = (struct sa11x0_serial*)__ch_data;
+    channel_data_t* chan = (channel_data_t*)__ch_data;
     int ret = 0;
-    int index;
     CYGARC_HAL_SAVE_GP();
 
-    if (SA11X0_UART1_BASE == __ch_data)
-        index = 0;
-    else
-        index = 1;
-
     switch (__func) {
     case __COMMCTL_IRQ_ENABLE:
         irq_state = 1;
 
-        base->utcr3 |= SA11X0_UART_RX_FIFO_INT_ENABLED;
+        chan->base->utcr3 |= SA11X0_UART_RX_FIFO_INT_ENABLED;
 
-        HAL_INTERRUPT_UNMASK(isr_vectors[index]);
+        HAL_INTERRUPT_UNMASK(chan->isr_vector);
         break;
     case __COMMCTL_IRQ_DISABLE:
         ret = irq_state;
         irq_state = 0;
 
-        base->utcr3 &= ~SA11X0_UART_RX_FIFO_INT_ENABLED;
+        chan->base->utcr3 &= ~SA11X0_UART_RX_FIFO_INT_ENABLED;
 
-        HAL_INTERRUPT_MASK(isr_vectors[index]);
+        HAL_INTERRUPT_MASK(chan->isr_vector);
         break;
     case __COMMCTL_DBG_ISR_VECTOR:
-        ret = isr_vectors[index];
+        ret = chan->isr_vector;
         break;
     case __COMMCTL_SET_TIMEOUT:
     {
@@ -261,8 +257,8 @@ cyg_hal_plf_serial_control(void *__ch_da
 
         va_start(ap, __func);
 
-        ret = msec_timeout[index];
-        msec_timeout[index] = va_arg(ap, cyg_uint32);
+        ret = chan->msec_timeout;
+        chan->msec_timeout = va_arg(ap, cyg_uint32);
 
         va_end(ap);
     }        
@@ -277,28 +273,23 @@ static int
 cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc, 
                        CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
 {
-    int index, res = 0;
-    volatile struct sa11x0_serial* base = (struct sa11x0_serial*)__ch_data;
+    int res = 0;
+    channel_data_t* chan = (channel_data_t*)__ch_data;
     char c;
     int reg;
     CYGARC_HAL_SAVE_GP();
 
-    if (SA11X0_UART1_BASE == __ch_data)
-        index = 0;
-    else
-        index = 1;
-
-    reg = base->utsr1;
+    reg = chan->base->utsr1;
 
     // read it anyway just in case - no harm done and we might prevent an
     // interrupt loop
-    c = (char)base->utdr;
+    c = (char)chan->base->utdr;
 
     //Clear receiver idle status bit, to allow another interrupt to
     //occur in the case where the receive fifo is almost empty.
-    base->utsr0 = SA11X0_UART_RX_IDLE;
+    chan->base->utsr0 = SA11X0_UART_RX_IDLE;
 
-    cyg_drv_interrupt_acknowledge(isr_vectors[index]);
+    cyg_drv_interrupt_acknowledge(chan->isr_vector);
 
     *__ctrlc = 0;
     if ( (reg & SA11X0_UART_RX_FIFO_NOT_EMPTY) != 0 ) {
@@ -319,9 +310,9 @@ cyg_hal_plf_serial_init(void)
     int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
 
     // Init channels
-    init_channel((void*)SA11X0_UART1_BASE);
+    init_channel(&ser_channels[0]);
 #if (CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS == 2)
-    init_channel((void*)SA11X0_UART3_BASE);
+    init_channel(&ser_channels[1]);
 #endif
 
     // Setup procs in the vector table
@@ -329,7 +320,7 @@ cyg_hal_plf_serial_init(void)
     // Set channel 0
     CYGACC_CALL_IF_SET_CONSOLE_COMM(0);
     comm = CYGACC_CALL_IF_CONSOLE_PROCS();
-    CYGACC_COMM_IF_CH_DATA_SET(*comm, SA11X0_UART1_BASE);
+    CYGACC_COMM_IF_CH_DATA_SET(*comm, &ser_channels[0]);
     CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
     CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
     CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
@@ -342,7 +333,7 @@ cyg_hal_plf_serial_init(void)
     // Set channel 1
     CYGACC_CALL_IF_SET_CONSOLE_COMM(1);
     comm = CYGACC_CALL_IF_CONSOLE_PROCS();
-    CYGACC_COMM_IF_CH_DATA_SET(*comm, SA11X0_UART3_BASE);
+    CYGACC_COMM_IF_CH_DATA_SET(*comm, &ser_channels[1]);
     CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_plf_serial_write);
     CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_plf_serial_read);
     CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_plf_serial_putc);
@@ -379,10 +370,12 @@ cyg_hal_plf_comms_init(void)
 
 #include <cyg/hal/hal_stub.h>           // cyg_hal_gdb_interrupt
 
-#if (CYGHWR_HAL_ARM_SA11X0_DIAG_PORT == 0)
+#if (CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL == 0)
 # define __BASE ((void*)SA11X0_UART1_BASE)
+# define CYGHWR_HAL_GDB_PORT_VECTOR CYGNUM_HAL_INTERRUPT_UART1
 #else
 # define __BASE ((void*)SA11X0_UART3_BASE)
+# define CYGHWR_HAL_GDB_PORT_VECTOR CYGNUM_HAL_INTERRUPT_UART3
 #endif
 
 #ifdef CYGSEM_HAL_ROM_MONITOR
@@ -394,15 +387,19 @@ cyg_hal_plf_comms_init(void)
 #define HAL_DIAG_USES_HARDWARE
 #elif defined(CYGDBG_HAL_DIAG_DISABLE_GDB_PROTOCOL)
 #define HAL_DIAG_USES_HARDWARE
-#elif CYGHWR_HAL_ARM_SA11X0_DIAG_PORT != CYGHWR_HAL_ARM_SA11X0_GDB_PORT
+#elif CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL != CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL
 #define HAL_DIAG_USES_HARDWARE
 #endif
 
+static channel_data_t ser_channel = {
+    (volatile struct sa11x0_serial*)__BASE, 0, CYGHWR_HAL_GDB_PORT_VECTOR
+};
+
 void 
 hal_diag_init(void)
 {
     // Init serial device
-    init_channel(__BASE);
+    init_channel(&ser_channel);
 }
 
 #ifdef HAL_DIAG_USES_HARDWARE
@@ -417,7 +414,7 @@ static int diag_bp = 0;
 
 void hal_diag_read_char(char *c)
 {
-    *c = cyg_hal_plf_serial_getc(__BASE);
+    *c = cyg_hal_plf_serial_getc(&ser_channel);
 }
 
 void hal_diag_write_char(char c)
@@ -428,7 +425,7 @@ void hal_diag_write_char(char c)
     if (diag_bp == sizeof(diag_buffer)) diag_bp = 0;
 #endif
 #endif
-    cyg_hal_plf_serial_putc(__BASE, c);
+    cyg_hal_plf_serial_putc(&ser_channel, c);
 }
 
 #else // not HAL_DIAG_USES_HARDWARE - it uses GDB protocol
@@ -436,7 +433,7 @@ void hal_diag_write_char(char c)
 void 
 hal_diag_read_char(char *c)
 {
-    *c = cyg_hal_plf_serial_getc(__BASE);
+    *c = cyg_hal_plf_serial_getc(&ser_channel);
 }
 
 void 
@@ -476,22 +473,22 @@ hal_diag_write_char(char c)
 #ifndef CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT
             char c1;
 #endif        
-            cyg_hal_plf_serial_putc(__BASE, '$');
-            cyg_hal_plf_serial_putc(__BASE, 'O');
+            cyg_hal_plf_serial_putc(&ser_channel, '$');
+            cyg_hal_plf_serial_putc(&ser_channel, 'O');
             csum += 'O';
             for( i = 0; i < pos; i++ )
             {
                 char ch = line[i];
                 char h = hex[(ch>>4)&0xF];
                 char l = hex[ch&0xF];
-                cyg_hal_plf_serial_putc(__BASE, h);
-                cyg_hal_plf_serial_putc(__BASE, l);
+                cyg_hal_plf_serial_putc(&ser_channel, h);
+                cyg_hal_plf_serial_putc(&ser_channel, l);
                 csum += h;
                 csum += l;
             }
-            cyg_hal_plf_serial_putc(__BASE, '#');
-            cyg_hal_plf_serial_putc(__BASE, hex[(csum>>4)&0xF]);
-            cyg_hal_plf_serial_putc(__BASE, hex[csum&0xF]);
+            cyg_hal_plf_serial_putc(&ser_channel, '#');
+            cyg_hal_plf_serial_putc(&ser_channel, hex[(csum>>4)&0xF]);
+            cyg_hal_plf_serial_putc(&ser_channel, hex[csum&0xF]);
 
 #ifdef CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT
 
@@ -502,7 +499,7 @@ hal_diag_write_char(char c)
             // Wait for the ACK character '+' from GDB here and handle
             // receiving a ^C instead.  This is the reason for this clause
             // being a loop.
-            c1 = cyg_hal_plf_serial_getc(__BASE);
+            c1 = cyg_hal_plf_serial_getc(&ser_channel);
 
             if( c1 == '+' )
                 break;              // a good acknowledge
--- a/packages/hal/arm/sa11x0/var/current/src/sa11x0_misc.c
+++ b/packages/hal/arm/sa11x0/var/current/src/sa11x0_misc.c
@@ -85,6 +85,10 @@ void hal_hardware_init(void)
     // Perform any platform specific initializations
     plf_hardware_init();
 
+    // Let the "OS" counter run
+    *SA11X0_OSCR = 0;
+    *SA11X0_OSMR0 = 0;
+
     // Set up eCos/ROM interfaces
     hal_if_init();
 
@@ -159,6 +163,30 @@ void hal_clock_read(cyg_uint32 *pvalue)
     *pvalue = ctr;
 }
 
+//
+// Delay for some number of micro-seconds
+//
+void hal_delay_us(cyg_int32 usecs)
+{
+    int diff, diff2;
+    cyg_uint32 val1, val2;
+    while (usecs-- > 0) {
+        diff = 0;
+        while (diff < 3) {
+            val1 = *SA11X0_OSCR;
+            while ((val2 = *SA11X0_OSCR) == val1) ;
+            if (*SA11X0_OSMR0) {
+                // A kernel is running, the counter may get reset as we watch
+                diff2 = val2 - val1;
+                if (diff2 < 0) diff2 += *SA11X0_OSMR0;
+                diff += diff2;
+            } else {
+                diff += val2 - val1;
+            }
+        }
+    }
+}
+
 // -------------------------------------------------------------------------
 
 // This routine is called to respond to a hardware interrupt (IRQ).  It
--- a/packages/hal/common/current/ChangeLog
+++ b/packages/hal/common/current/ChangeLog
@@ -1,3 +1,25 @@
+2000-07-14  Gary Thomas  <gthomas@redhat.com>
+
+	* src/hal_if.c (delay_us): Use HAL_DELAY_US() if defined.
+
+2000-07-07  Jesper Skov  <jskov@redhat.com>
+
+	* src/hal_stub.c (initHardware): Fix #endif location.
+
+	* src/hal_if.c (hal_ctrlc_isr_init): Added hack to work around a
+	silly but critical problem.
+
+	* src/hal_stub.c: Removed some CygMon conditional exclusions.
+
+	* src/hal_if.c (hal_ctrlc_isr_init): Don't enable interrupts when
+	configured as ROM monitor.
+
+2000-07-05  Jesper Skov  <jskov@redhat.com>
+
+	* cdl/debugging.cdl: Only allow CTRLC support if there's stubs or
+	a ROM monitor to handle it. (Haruki Kashiwaya (kashiwaya at redhat
+	dot com)).
+
 2000-06-30  Jesper Skov  <jskov@redhat.com>
 
 	* include/hal_if.h: Make CYGACC macros call functions. May have to
@@ -826,7 +848,6 @@ 1999-01-29  Jesper Skov  <jskov@cygnus.c
 
 	* include/pkgconf/hal.h: Added simple MPC8xx configuration.
 
-
 1999-01-26  Hugo Tyson  <hmt@cygnus.co.uk>
 
 	* tests/cache.c (time0): Waste much less time if running in a
@@ -865,7 +886,6 @@ 1999-01-21  Jesper Skov  <jskov@cygnus.c
 	* include/pkgconf/hal.h: 
 	Add CYG_KERNEL_USE_INIT_PRIORITY for SPARCLITE.
 
-
 1999-01-18  Jesper Skov  <jskov@cygnus.co.uk>
         PR 18823
 	* include/pkgconf/hal.h: Don't allow GDB stubs to be configured
@@ -912,7 +932,6 @@ Wed Dec  9 14:07:30 GMT 1998  Chris Prov
 	* include/pkgconf/hal.h: Compile the i386 linux target with
 	CYG_KERNEL_USE_INIT_PRIORITY defined.
 
-
 1999-01-04  Jesper Skov  <jskov@cygnus.co.uk>
 
 	* src/generic-stub.c (interruptible): Cleaned up a bit.
--- a/packages/hal/common/current/cdl/debugging.cdl
+++ b/packages/hal/common/current/cdl/debugging.cdl
@@ -91,6 +91,7 @@ cdl_interface CYGINT_HAL_DEBUG_GDB_CTRLC
 cdl_option CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT {
     display       "Include GDB external break support when no stubs"
     requires      !CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
+    active_if     { CYGSEM_HAL_USE_ROM_MONITOR || CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS }
     active_if     { CYGINT_HAL_DEBUG_GDB_CTRLC_UNSUPPORTED == 0 }
     default_value 1
     description   "
--- a/packages/hal/common/current/src/hal_if.c
+++ b/packages/hal/common/current/src/hal_if.c
@@ -104,6 +104,11 @@ delay_us(cyg_int32 usecs)
     } while (usec_ticks > 0);
 
     CYGARC_HAL_RESTORE_GP();
+#else
+    // Use a HAL feature if defined
+#ifdef HAL_DELAY_US
+    HAL_DELAY_US(usecs);
+#endif
 #endif
 }
 
@@ -364,14 +369,26 @@ struct Hal_SavedRegisters *hal_saved_int
 void
 hal_ctrlc_isr_init(void)
 {
+    // A ROM monitor never enables the interrupt itself. This is left
+    // to the (RAM) application.
+#ifndef CYGSEM_HAL_ROM_MONITOR
     hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_DEBUG_PROCS();
 
 #if 1 // Prevents crash on older stubs
     if (CYGNUM_CALL_IF_TABLE_VERSION != CYGACC_CALL_IF_VERSION())
         return;
+
+    // Now trash that value - otherwise downloading an image with
+    // builtin stubs on a board with older stubs may cause all
+    // subsequent runs to (wrongly) fall through to the below code.
+    // If there is a new stub on the board, it will reinitialize the
+    // version field on reset.
+    // Yes, this is a gross hack!
+    CYGACC_CALL_IF_VERSION_SET(CYGNUM_CALL_IF_TABLE_VERSION+1);
 #endif
 
     CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_IRQ_ENABLE);
+#endif
 }
 
 cyg_uint32
--- a/packages/hal/common/current/src/hal_stub.c
+++ b/packages/hal/common/current/src/hal_stub.c
@@ -501,7 +501,6 @@ initHardware (void)
         return;
     initialized = 1;
 
-#if !defined(CYGPKG_CYGMON)
     // Get serial port initialized.
     HAL_STUB_PLATFORM_INIT_SERIAL();
 
@@ -530,28 +529,25 @@ initHardware (void)
         // Set the debug channel.
         CYGACC_CALL_IF_SET_DEBUG_COMM(CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL);
     }
+#endif // CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
 
 #ifdef HAL_STUB_PLATFORM_INIT
     // If the platform defines any initialization code, call it here.
     HAL_STUB_PLATFORM_INIT();
 #endif        
-#endif
 
-#ifndef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
+#ifndef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT // this should go away
 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
     // Get interrupt handler initialized.
     HAL_STUB_PLATFORM_INIT_BREAK_IRQ();
 #endif
-#endif // CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
-#endif // CYGPKG_CYGMON
-
+#endif // !CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
 }
 
 // Reset the board.
 void 
 __reset (void)
 {
-#if !defined(CYGPKG_CYGMON)
 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
     __call_if_reset_t __rom_reset = CYGACC_CALL_IF_RESET_GET();
     if (__rom_reset)
@@ -559,7 +555,6 @@ void
 #else
     HAL_STUB_PLATFORM_RESET();
 #endif
-#endif
 }
 
 //-----------------------------------------------------------------------------
--- a/packages/hal/sh/arch/current/ChangeLog
+++ b/packages/hal/sh/arch/current/ChangeLog
@@ -58,13 +58,6 @@ 2000-06-08  Jesper Skov  <jskov@redhat.c
 	* src/vectors.S:
 	Minor config change to get rid of growing list of variant checks.
 
-2000-06-08  Jesper Skov  <jskov@redhat.com>
-
-	* include/mod_7707a.h: 
-	* src/vectors.S:
-	* cdl/hal_sh.cdl: 
-	Added first level of support for 7707A variant.
-
 2000-06-06  Jesper Skov  <jskov@redhat.com>
 
 	* src/vectors.S: INTEVT2 is not defined on all variants. Protect
--- a/packages/hal/sh/arch/current/cdl/hal_sh.cdl
+++ b/packages/hal/sh/arch/current/cdl/hal_sh.cdl
@@ -91,21 +91,6 @@ cdl_package CYGPKG_HAL_SH {
         @rm target.tmp
     }
 
-    cdl_option CYGPKG_HAL_SH_7707A {
-        display       "SH 7707A microprocessor"
-        implements    CYGINT_HAL_SH_VARIANT
-        default_value 0
-        no_define
-        define        -file=system.h CYGPKG_HAL_SH_7707A
-        description "
-            The SH3 7707A microprocessor. This is an embedded part that in
-            addition to the SH3 processor core has built in peripherals
-            such as memory controllers, serial ports, LCD controller and
-            timers/counters."               
-        define_proc {
-            puts $cdl_system_header "#define CYGBLD_HAL_CPU_MODULES_H <cyg/hal/mod_7707a.h>"
-        }
-    }
 
     cdl_option CYGPKG_HAL_SH_7708 {
         display       "SH 7708 microprocessor"
--- a/packages/hal/sh/arch/current/include/hal_intr.h
+++ b/packages/hal/sh/arch/current/include/hal_intr.h
@@ -130,6 +130,9 @@
 
 #define CYGNUM_HAL_ISR_MAX                   CYGNUM_HAL_INTERRUPT_REF_ROVI
 
+//----------------------------------------------------------------------------
+// Additional vectors provided by INTC V2
+
 //#ifdef CYGARC_SH_MOD_INTC_V2 // FIXME
 #define CYGNUM_HAL_INTERRUPT_RESERVED_5C0    32
 #define CYGNUM_HAL_INTERRUPT_HUDI_HUDI       33
@@ -170,6 +173,7 @@
 
 #endif // CYGARC_SH_MOD_INTC_V2
 
+
 // CYGNUM_HAL_ISR_COUNT must match CYG_ISR_TABLE_SIZE defined in vectors.S.
 #define CYGNUM_HAL_ISR_MIN                   CYGNUM_HAL_INTERRUPT_NMI
 #define CYGNUM_HAL_ISR_COUNT                 ( CYGNUM_HAL_ISR_MAX + 1 )
--- a/packages/hal/sh/arch/current/include/sh_regs.h
+++ b/packages/hal/sh/arch/current/include/sh_regs.h
@@ -341,6 +341,7 @@
 # define CYGARC_REG_IPRE                0xa400001a
 //#endif
 
+
 #define CYGARC_REG_IPRA_TMU0_MASK       0xf000
 #define CYGARC_REG_IPRA_TMU0_PRI1       0x1000
 #define CYGARC_REG_IPRA_TMU1_MASK       0x0f00
--- a/packages/hal/sh/cq7708/current/ChangeLog
+++ b/packages/hal/sh/cq7708/current/ChangeLog
@@ -1,3 +1,11 @@
+2000-07-07  Jesper Skov  <jskov@redhat.com>
+
+	* cdl/hal_sh_sh7708_cq7708.cdl: Require sub-variant package.
+
+2000-07-05  Jesper Skov  <jskov@redhat.com>
+
+	* src/hal_diag.c: Include hal_if.c
+
 2000-06-29  Jesper Skov  <jskov@redhat.com>
 
 	* src/hal_diag.c: serial driver API changes.
--- a/packages/hal/sh/cq7708/current/cdl/hal_sh_sh7708_cq7708.cdl
+++ b/packages/hal/sh/cq7708/current/cdl/hal_sh_sh7708_cq7708.cdl
@@ -43,6 +43,7 @@
 cdl_package CYGPKG_HAL_SH_SH7708_CQ7708 {
     display       "CqREEK SH7708 board"
     parent        CYGPKG_HAL_SH
+    requires      CYGPKG_HAL_SH_7708
     define_header hal_sh_sh7708_cq7708.h
     include_dir   cyg/hal
     description   "
--- a/packages/hal/sh/cq7708/current/src/hal_diag.c
+++ b/packages/hal/sh/cq7708/current/src/hal_diag.c
@@ -47,6 +47,7 @@
 
 #include <cyg/infra/cyg_type.h>         // base types, externC
 #include <cyg/hal/hal_io.h>             // IO macros
+#include <cyg/hal/hal_if.h>             // calling interface API
 #include <cyg/hal/hal_intr.h>           // Interrupt macros
 #include <cyg/hal/sh3_sci.h>            // driver API
 #include <cyg/hal/hal_misc.h>           // Helper functions
--- a/packages/hal/sh/edk/current/ChangeLog
+++ b/packages/hal/sh/edk/current/ChangeLog
@@ -1,3 +1,7 @@
+2000-07-07  Jesper Skov  <jskov@redhat.com>
+
+	* cdl/hal_sh_edk7708.cdl: Require sub-variant package.
+
 2000-06-29  Jesper Skov  <jskov@redhat.com>
 
 	* src/hal_diag.c: serial driver API changes.
--- a/packages/hal/sh/edk/current/cdl/hal_sh_edk7708.cdl
+++ b/packages/hal/sh/edk/current/cdl/hal_sh_edk7708.cdl
@@ -43,6 +43,7 @@
 cdl_package CYGPKG_HAL_SH_EDK7708 {
     display       "Hitachi EDK/SH7708 board"
     parent        CYGPKG_HAL_SH
+    requires      CYGPKG_HAL_SH_7708
     define_header hal_sh_edk7708.h
     include_dir   cyg/hal
     description   "
--- a/packages/net/drivers/eth/common/current/src/eth_drv.c
+++ b/packages/net/drivers/eth/common/current/src/eth_drv.c
@@ -440,4 +440,5 @@ eth_drv_recv(struct eth_drv_sc *sc, int 
     ether_input(ifp, eh, m);
 }
 
+
 // EOF eth_drv.c
--- a/packages/net/snmp/agent/current/ChangeLog
+++ b/packages/net/snmp/agent/current/ChangeLog
@@ -1,3 +1,8 @@
+2000-07-13  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* tests/snmpping.c: Up the stack size to cope with full DHCP
+	initialization in init_all_network_interfaces().
+
 2000-06-27  Hugo Tyson  <hmt@cygnus.co.uk>
 
 	* src/mibgroup/mibII/dot3.c (var_dot3StatsTable): Forgot the
--- a/packages/net/snmp/agent/current/tests/snmpping.c
+++ b/packages/net/snmp/agent/current/tests/snmpping.c
@@ -138,7 +138,7 @@ CONNECTION WITH THE USE OR PERFORMANCE O
 
 #include <network.h>
 
-#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
 static char stack[STACK_SIZE];
 static cyg_thread thread_data;
 static cyg_handle_t thread_handle;
@@ -354,3 +354,5 @@ cyg_start(void)
     cyg_thread_resume(thread_handle);  // Start it
     cyg_scheduler_start();
 }
+
+// EOF snmpping.c
--- a/packages/net/tcpip/current/ChangeLog
+++ b/packages/net/tcpip/current/ChangeLog
@@ -1,3 +1,102 @@
+2000-07-14  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* include/bootp.h: export init_loopback_interface();
+
+2000-07-14  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* cdl/net.cdl: Add option controlling whether to have a separate
+	DHCP lease management thread, and what its parameter is to be -
+	which controls whether it loops or quits if a lease fails.
+
+	* src/lib/dhcp_support.c (dhcp_start_dhcp_mgt_thread): Provide the
+	DHCP management thread function and code to instantiate and start
+	the thread if so configured.
+
+	* src/lib/network_support.c (init_all_network_interfaces): Call
+	the function that starts the DHCP management thread function.
+
+	* include/dhcp.h: Declare the DHCP management thread function &c
+	if so configured.
+
+	* tests/dhcp_test.c (net_test): Only poll for need to rebind DHCP
+	leases if there is no service thread to do the same.
+
+2000-07-14  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* include/bootp.h (build_bootp_record): Export this, no harm in
+	it, and some folk want to use this rather than configured
+	initialization or bootp/dhcp.
+	Also commented the other APIs somewhat better.
+
+	* src/lib/network_support.c (build_bootp_record): Unconditionally
+	provide this; selective linking will look after it if unused.
+
+2000-07-14  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* src/lib/network_support.c (build_bootp_record): [Static
+	configuration of interface parameters] Add the gateway into the
+	options section with TAG_GATEWAY so that init_net() will pick it
+	up and set up a route accordingly.
+
+2000-07-13  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* tests/dhcp_test.c:
+	* tests/flood.c:
+	* tests/ftp_test.c:
+	* tests/nc_test_master.c:
+	* tests/nc_test_slave.c:
+	* tests/ping_lo_test.c:
+	* tests/ping_test.c:
+	* tests/server_test.c:
+	* tests/set_mac_address.c:
+	* tests/tcp_echo.c:
+	* tests/tftp_client_test.c:
+	* tests/tftp_server_test.c:
+	Up the stack size to cope with full DHCP initialization in
+	init_all_network_interfaces().
+	
+2000-07-13  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* cdl/net.cdl: Add DHCP enable and interface-specific controls.
+
+	* include/dhcp.h: New file: describe the DHCP APIs and behaviour,
+	as well as some internal APIs that are also available.
+
+	* src/lib/dhcp_support.c: New file: the surrounding management
+	routines, a bit like network_support.c, which know about multiple
+	interfaces and so on.
+
+	* src/lib/dhcp_prot.c: New file: the interface-independent DHCP
+	protocol machine, which is called from dhcp_support.c routines and
+	init_all_network_interfaces() in network_support.c
+
+	* include/bootp.h (struct bootp): Make the packet bigger if DHCP
+	so that a mininal DHCP packet will fit.
+
+	* src/lib/bootp_support.c (do_bootp): If no reply, fail gracefully
+	and tidy up so that other interfaces can be upbrung.
+	(show_bootp): Tell us a lot more about DHCP-specific info in the
+	packet structure.
+	(get_bootp_option): be aware of DHCP extensions to re-use file and
+	sname fields for options.
+
+	* src/lib/network_support.c (init_all_network_interfaces): Call
+	do_dhcp() rather than do_bootp() if so configured, and initialize
+	the per-interface DHCP state variables accordingly.
+
+	* tests/dhcp_test.c (net_test): New test file that diddles the
+	DHCP machine while doing a ping test.
+
+2000-07-11  Gary Thomas  <gthomas@redhat.com>
+
+	* include/netdev.h: Add single-inclusion fences.
+
+	* include/sys/param.h: Add traced versions of splx() routines,
+	selectable by a configuration option.
+
+	* src/ecos/support.c: Rework splx() emulation routines to
+	be more robust and realtime friendly.
+
 2000-07-04  Hugo Tyson  <hmt@cygnus.co.uk>
 
 	* include/bootp.h: Fix namespace pollution from "#define int32
--- a/packages/net/tcpip/current/cdl/net.cdl
+++ b/packages/net/tcpip/current/cdl/net.cdl
@@ -88,6 +88,8 @@ cdl_package CYGPKG_NET {
 	sys/netinet/tcp_timer.c \
 	lib/inet_addr.c \
 	lib/bootp_support.c \
+	lib/dhcp_support.c \
+	lib/dhcp_prot.c \
 	lib/network_support.c \
 	lib/getproto.c \
 	lib/getserv.c \
@@ -178,6 +180,52 @@ cdl_package CYGPKG_NET {
         }
     }
 
+    cdl_component CYGPKG_NET_DHCP {
+	display "Use full DHCP instead of BOOTP"
+	active_if (CYGHWR_NET_DRIVERS > 0)
+	flavor bool
+	default_value 1
+	description "
+	    Provide DHCP for initializing the IP address
+	    of network interfaces.  The DHCP client is capable of falling
+	    back to BOOTP usage if the server does not support DHCP, so it
+	    should never be necessary to disable this option.  However,
+	    depending on other configuration the DHCP client may provide or
+	    require a kernel thread of its own; this consumes quite a lot
+	    of resource which a BOOTP solution does not require."
+
+	cdl_option CYGOPT_NET_DHCP_DHCP_THREAD {
+	    display "DHCP management thread"
+	    flavor bool
+	    default_value 1
+	    description "
+	        Provide a separate thread to renew DHCP leases; otherwise
+	        the application MUST periodically examine the semaphore
+	        dhcp_needs_attention and call dhcp_bind() if it is
+	        signalled.  If enabled, this thread does all that for you.
+	        Independent of this option, initialization of the
+	        interfaces still occurs in init_all_network_interfaces()
+	        and your startup code must call that.  It will start the
+	        DHCP management thread if necessary.  If a lease fails to
+	        be renewed, the management thread will shut down all
+	        interfaces and attempt to initialize all the interfaces
+	        again from scratch.  This may cause application problems,
+	        in which case managing the DHCP state in an application
+	        aware thread is recommended.  See comments in dhcp.h"
+	}
+
+	cdl_option CYGOPT_NET_DHCP_DHCP_THREAD_PARAM {
+	    display "DHCP management thread loops forever"
+	    flavor  data
+	    default_value 0
+	    active_if CYGOPT_NET_DHCP_DHCP_THREAD
+	    description "
+	        If the parameter is nonzero, it loops forever; if zero,
+	        the thread exits if a lease expires, and the application
+	        must detect this and tidy up or reboot the whole machine."
+	}
+    }
+
     cdl_option CYGPKG_NET_SYSCTL {
         display "Support BSD 'sysctl()' function"
         flavor  bool
@@ -316,6 +364,7 @@ cdl_package CYGPKG_NET {
 		    tests/set_mac_address \
 		    tests/flood \
 		    tests/ping_test \
+		    tests/dhcp_test \
 		    tests/ping_lo_test \
 		    tests/tcp_lo_test \
 		    tests/udp_lo_test \
@@ -381,6 +430,13 @@ cdl_package CYGPKG_NET {
             default_value 1
             implements CYGHWR_NET_DRIVER_ETH0_SETUP	
 
+            cdl_option CYGHWR_NET_DRIVER_ETH0_DHCP {
+                display "Use DHCP rather than BOOTP for 'eth0'?"
+                flavor  bool
+                default_value 1
+		active_if CYGPKG_NET_DHCP
+            }
+
             cdl_option CYGHWR_NET_DRIVER_ETH0_BOOTP_SHOW {
                 display "Show BOOTP/DHCP initialization values?"
                 flavor  bool
@@ -452,6 +508,13 @@ cdl_package CYGPKG_NET {
             default_value 1
             implements CYGHWR_NET_DRIVER_ETH1_SETUP	
 
+            cdl_option CYGHWR_NET_DRIVER_ETH1_DHCP {
+                display "Use DHCP rather than BOOTP for 'eth1'?"
+                flavor  bool
+                default_value 1
+		active_if CYGPKG_NET_DHCP
+            }
+
             cdl_option CYGHWR_NET_DRIVER_ETH1_BOOTP_SHOW {
                 display "Show BOOTP/DHCP initialization values?"
                 flavor  bool
--- a/packages/net/tcpip/current/include/bootp.h
+++ b/packages/net/tcpip/current/include/bootp.h
@@ -86,6 +86,10 @@ SOFTWARE.
  */
 
 #ifdef __ECOS
+
+#include <pkgconf/system.h>
+#include <pkgconf/net.h>
+
 #include <machine/types.h>
 #else
 #include "bptypes.h"	/* for int32, u_int32 */
@@ -94,8 +98,15 @@ SOFTWARE.
 #define BP_CHADDR_LEN	 16
 #define BP_SNAME_LEN	 64
 #define BP_FILE_LEN	128
+
+#ifdef CYGPKG_NET_DHCP
+// The standard requires only 312 bytes here
+#define BP_VEND_LEN	(312 + 32)
+#define BP_MINPKTSZ	576
+#else
 #define BP_VEND_LEN	 64
 #define BP_MINPKTSZ	300	/* to check sizeof(struct bootp) */
+#endif
 
 struct bootp {
     unsigned char    bp_op;			/* packet opcode type */
@@ -331,11 +342,45 @@ extern struct bootp eth1_bootp_data;
 extern cyg_bool_t   eth1_up;
 extern const char  *eth1_name;
 #endif
-cyg_bool_t do_bootp(const char *interface, struct bootp *res);
-cyg_bool_t init_net(const char *interface, struct bootp *res);
-void show_bootp(const char *interface, struct bootp *res);
-cyg_bool_t get_bootp_option(struct bootp *bp, unsigned char tag, void *res);
-void init_all_network_interfaces(void);
+
+// ------------------------------------------------------------------------
+// Initialize your own bootp record however you like, as far as is needed
+// to bring up an interface.
+extern void
+build_bootp_record(struct bootp *bp,
+                   const char *addrs_ip,
+                   const char *addrs_netmask,
+                   const char *addrs_broadcast,
+                   const char *addrs_gateway,
+                   const char *addrs_server);
+
+// Do bootp to fill in the bootp record from the net (other interfaces must
+// be down for this to work, because of the "half-up" state of the
+// interface in use)
+extern cyg_bool_t do_bootp(const char *interface, struct bootp *res);
+
+// Initialize an interface (which is down) according to a bootp structure
+extern cyg_bool_t init_net(const char *interface, struct bootp *res);
+
+// Dump contents to diag_printf
+extern void show_bootp(const char *interface, struct bootp *res);
+
+// Interrogate a bootp record for a particular option
+extern cyg_bool_t get_bootp_option(struct bootp *bp, unsigned char tag, void *res);
+
+// ------------------------------------------------------------------------
+// This isn't exactly the right place for this since bootp is not involved
+// BUT you will only be using this API if you are using bootp-style
+// initialization of the other interfaces; it fits here in a documentation
+// sense.
+extern cyg_bool_t init_loopback_interface(int lo);
+
+// ------------------------------------------------------------------------
+// Do all the above automatically according to the configuration.  Do not
+// mix using this and making the above calls yourself.
+// (this is also declared in the much simpler API in network.h)
+extern void init_all_network_interfaces(void);
+
 #endif
 
 #endif // _BOOTP_H_
new file mode 100644
--- /dev/null
+++ b/packages/net/tcpip/current/include/dhcp.h
@@ -0,0 +1,254 @@
+#ifndef CYGONCE_NET_TCPIP_DHCP_H
+#define CYGONCE_NET_TCPIP_DHCP_H
+
+//==========================================================================
+//
+//      include/dhcp.h
+//
+//      DHCP protocol support
+//
+//==========================================================================
+//####COPYRIGHTBEGIN####
+//                                                                          
+// -------------------------------------------                              
+// The contents of this file are subject to the Red Hat eCos Public License 
+// Version 1.1 (the "License"); you may not use this file except in         
+// compliance with the License.  You may obtain a copy of the License at    
+// http://www.redhat.com/                                                   
+//                                                                          
+// 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 Configurable Operating System,      
+// released September 30, 1998.                                             
+//                                                                          
+// The Initial Developer of the Original Code is Red Hat.                   
+// Portions created by Red Hat are                                          
+// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.                             
+// All Rights Reserved.                                                     
+// -------------------------------------------                              
+//                                                                          
+//####COPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD or other sources,
+// and are covered by the appropriate copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    hmt
+// Contributors: gthomas
+// Date:         2000-07-01
+// Purpose:      Support DHCP initialization in eCos TCPIP stack
+// Description:  
+//              
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// 
+// DHCP.  RFC2131, RFC1533, RFC1534
+// See also bootp.h
+// 
+
+#include <pkgconf/system.h>
+#include <pkgconf/net.h>
+
+#ifdef CYGPKG_NET_DHCP
+
+#include <machine/types.h>
+
+#include <cyg/kernel/kapi.h>
+
+#include <bootp.h>
+
+// DHCP messages; these are sent in the tag TAG_DHCP_MESS_TYPE already
+// defined in bootp.h
+
+#define DHCPDISCOVER	1
+#define DHCPOFFER	2
+#define DHCPREQUEST	3
+#define DHCPDECLINE	4
+#define DHCPACK		5
+#define DHCPNAK		6
+#define DHCPRELEASE	7
+
+// DHCP interface state machine states; these are published so that app
+// code can know what to do... (see page 35 of RFC2131)
+
+// These we will use in the normal course of events
+#define DHCPSTATE_INIT		   1
+#define DHCPSTATE_SELECTING	   2 // wait for replies to b/c DISCOVER
+#define DHCPSTATE_REQUESTING	   3
+#define DHCPSTATE_REQUEST_RECV	   4 // wait for replies to b/c REQUEST
+#define DHCPSTATE_BOUND		   5
+#define DHCPSTATE_RENEWING	   6 // wait for replies to u/c REQUEST
+#define DHCPSTATE_RENEW_RECV	   7
+#define DHCPSTATE_REBINDING	   8 // wait for replies to b/c REQUEST
+#define DHCPSTATE_REBIND_RECV      9
+#define DHCPSTATE_BOOTP_FALLBACK  10 // fall back to plain bootp
+#define DHCPSTATE_NOTBOUND        11 // To let app tidy up
+#define DHCPSTATE_FAILED          12 // Net is down
+#define DHCPSTATE_DO_RELEASE      13 // Force release of the current lease
+// These we don't use
+//#define DHCPSTATE_INITREBOOT
+//#define DHCPSTATE_REBOOTING
+
+// These are to let the app inspect the state of the interfaces when
+// managing them itself, by analogy with eth0_up &c; eth0_bootp_data and so
+// on will still be used with DHCP.
+#ifdef CYGHWR_NET_DRIVER_ETH0
+extern cyg_uint8   eth0_dhcpstate;
+#endif
+#ifdef CYGHWR_NET_DRIVER_ETH1
+extern cyg_uint8   eth1_dhcpstate;
+#endif
+
+// This is public so the app wait on it or poll it when managing DHCP
+// itself.  It will be zero while the app should wait, and posted when a
+// call to do_dhcp() is needed.
+extern cyg_sem_t dhcp_needs_attention;
+
+// This routine is used at startup time, and after relinquishing leases or
+// after a lease timeout: it does DHCP or bootp or static setup according
+// to configuration.
+extern void init_all_network_interfaces(void);
+
+// This routine does the work of renewing leases &c.
+// return value: 1 => everything OK, no change.
+// 0 => close your connections, then call do_dhcp_halt() to halt the
+// interface(s) in question (it knows because the state will be NOTBOUND).
+// After that you can return to the start and use
+// init_all_network_interfaces() as usual.
+extern int dhcp_bind( void );
+
+// Shutdown any interface which is not already shut down - whether
+// initialized by DHCP or not.  Reason: because of the broadcast-while-not-
+// -fully-initialized nature of the DHCP conversation, all other interfaces
+// must be shut down during that.  So one down, all down, is required.
+extern int dhcp_halt( void );
+
+// Release (and set state to DHCPSTATE_NOTBOUND) all interfaces - we are
+// closing down.  (unlikely but useful for testing)
+// Interfaces are left up; use dhcp_halt() to bring them right down, then
+// call init_all_network_interfaces() as usual to restart all.
+extern int dhcp_release( void );
+
+// The intent with this API is that a simple DHCP client thread, which
+// maintains the state of the interfaces, can go as follows:
+// (after init_all_networks is called from elsewhere)
+//
+//    while ( 1 ) {
+//        while ( 1 ) {
+//            cyg_semaphore_wait( &dhcp_needs_attention );
+//            if ( ! dhcp_bind() ) // a lease expired
+//                break; // If we need to re-bind
+//        }
+//        dhcp_halt(); // tear everything down
+//        init_all_network_interfaces(); // re-initialize
+//    }
+//
+// and if the application does not want to suffer the overhead of a
+// separate thread and its stack for this, this functionality can be placed
+// in the app's server loop in an obvious fashion.  That is the goal of
+// breaking out these internal elements.  For example, some server might
+// be arranged to poll DHCP from time to time like this:
+//
+//    while ( 1 ) {
+//        init_all_network_interfaces();
+//        open-my-listen-sockets();
+//        while ( 1 ) {
+//            serve-one-request();
+//            // sleeps if no connections, but not forever; so this loop is
+//            // polled a few times a minute...
+//            if ( cyg_semaphore_trywait( &dhcp_needs_attention )) {
+//                if ( ! dhcp_bind() ) {
+//                    close-my-listen-sockets();
+//                    dhcp_halt();
+//                    break;
+//                }
+//            }
+//        }
+//    }
+//
+// ------------------------------------------------------------------------
+
+#ifdef CYGOPT_NET_DHCP_DHCP_THREAD
+// Then we provide such a thread...
+
+// Provide a separate thread to renew DHCP leases; otherwise the
+// application MUST periodically examine the semaphore dhcp_needs_attention
+// and call dhcp_bind() if it is signalled.  If enabled, this thread does
+// all that for you.  Independent of this option, initialization of the
+// interfaces still occurs in init_all_network_interfaces() and your
+// startup code must call that.  It will start the DHCP management thread
+// if necessary.  If a lease fails to be renewed, the management thread
+// will shut down all interfaces and attempt to initialize all the
+// interfaces again from scratch.  This may cause chaos in the app, which
+// is why managing the DHCP state in an application aware thread is
+// actually better, just far less convenient for testing.
+
+extern cyg_handle_t dhcp_mgt_thread_h; // To allow its external manipulation.
+extern cyg_thread   dhcp_mgt_thread;   // The object itself
+
+extern void dhcp_start_dhcp_mgt_thread( void );
+
+#endif
+
+// The function is provided unconditionally so that the app can put it in a
+// thread of its own.  If the parameter is true, it loops forever; if
+// false, the call returns if a lease expires, and the caller must tidy up
+// or reboot the whole machine.
+extern cyg_thread_entry_t dhcp_mgt_entry;
+extern void dhcp_mgt_entry( cyg_addrword_t loop_on_failure ); // the function
+
+// ---------------------------------------------------------------------------
+// These are rather more internal routines, internal to the protocol engine
+// in dhcp_prot.c - those above are in dhcp_support.c
+
+#define DHCP_LEASE_T1 1
+#define DHCP_LEASE_T2 2
+#define DHCP_LEASE_EX 4
+
+struct dhcp_lease {
+    cyg_tick_count_t    t1, t2, expiry;
+    volatile cyg_uint8  next;
+    volatile cyg_uint8  which;
+    cyg_handle_t        alarm;
+    cyg_alarm           alarm_obj;
+};
+
+#ifdef CYGHWR_NET_DRIVER_ETH0
+extern struct dhcp_lease eth0_lease;
+#endif
+#ifdef CYGHWR_NET_DRIVER_ETH1
+extern struct dhcp_lease eth1_lease;
+#endif
+
+extern int
+do_dhcp(const char *interface, struct bootp *res,
+        cyg_uint8 *pstate, struct dhcp_lease *lease);
+// NB *res and *pstate and *lease are all INOUT; *res must point to a valid
+// record from "last time".
+
+extern int
+do_dhcp_down_net(const char *intf, struct bootp *res,
+        cyg_uint8 *pstate, struct dhcp_lease *lease);
+
+extern int
+do_dhcp_release(const char *intf, struct bootp *res,
+        cyg_uint8 *pstate, struct dhcp_lease *lease);
+
+#endif // CYGPKG_NET_DHCP
+
+#endif // CYGONCE_NET_TCPIP_DHCP_H
+// EOF dhcp.h
--- a/packages/net/tcpip/current/include/netdev.h
+++ b/packages/net/tcpip/current/include/netdev.h
@@ -1,3 +1,5 @@
+#ifndef _NETDEV_H_
+#define _NETDEV_H_
 //==========================================================================
 //
 //      include/netdev.h
@@ -72,3 +74,5 @@ cyg_netdevtab_entry_t _l __attribute__ (
    _init,                                                            \
    _instance                                                         \
 };
+
+#endif // _NETDEV_H_
--- a/packages/net/tcpip/current/include/sys/param.h
+++ b/packages/net/tcpip/current/include/sys/param.h
@@ -330,6 +330,21 @@ extern void cyg_wakeup(void *);
 #define tsleep(e,p,w,t) cyg_tsleep(e,0,w,t)
 #define wakeup(e)       cyg_wakeup(e)
 
+#ifdef CYGIMPL_TRACE_SPLX   
+extern cyg_uint32  cyg_splimp(const char *file, const int line);
+extern cyg_uint32  cyg_splnet(const char *file, const int line);
+extern cyg_uint32  cyg_splclock(const char *file, const int line);
+extern cyg_uint32  cyg_splsoftnet(const char *file, const int line);
+extern void        cyg_splx(cyg_uint32, const char *file, const int line);
+#define splimp()   cyg_splimp(__FUNCTION__, __LINE__)
+#define splnet()   cyg_splnet(__FUNCTION__, __LINE__)
+#define splclock() cyg_splclock(__FUNCTION__, __LINE__)
+#define splsoftnet() cyg_splsoftnet(__FUNCTION__, __LINE__)
+#define splx(x)    cyg_splx(x, __FUNCTION__, __LINE__)
+#define cyg_scheduler_lock() _cyg_scheduler_lock(__FUNCTION__, __LINE__)
+#define cyg_scheduler_safe_lock() _cyg_scheduler_safe_lock(__FUNCTION__, __LINE__)
+#define cyg_scheduler_unlock() _cyg_scheduler_unlock(__FUNCTION__, __LINE__)
+#else
 extern cyg_uint32  cyg_splimp(void);
 extern cyg_uint32  cyg_splnet(void);
 extern cyg_uint32  cyg_splclock(void);
@@ -340,6 +355,7 @@ extern void        cyg_splx(cyg_uint32);
 #define splclock   cyg_splclock
 #define splsoftnet cyg_splsoftnet
 #define splx       cyg_splx
+#endif
 
 extern void cyg_panic(const char *msg, ...);
 #define panic cyg_panic
--- a/packages/net/tcpip/current/src/ecos/support.c
+++ b/packages/net/tcpip/current/src/ecos/support.c
@@ -102,143 +102,177 @@ cyg_panic(const char *msg, ...)
     cyg_test_exit();  // FIXME
 }
 
-
-// ------------------------------------------------------------------------
-#define SPLSOFTNET_IS_A_MUTEX 1
-// ------------------------------------------------------------------------
-#ifdef SPLSOFTNET_IS_A_MUTEX
+//---------------------------- splx() emulation ------------------------------
+//
+// This variable (and the associated bit patterns) is used to keep track
+// of the "splx()" level.  This is an artifact of the original stack, based
+// on the BSD interrupt world (interrupts and processing could be masked
+// based on a level value, supported by hardware).  This is not very real-time,
+// so the emulation uses proper eCos tools and techniques to accomplish the
+// same result.  The key here is in the analysis of the various "levels", why
+// they are used, etc.  
+//
+static cyg_uint32 spl_state;
+#define SPL_STATE_IMP     0x01
+#define SPL_STATE_NET     0x02
+#define SPL_STATE_CLOCK   0x04
+#define SPL_STATE_SOFTNET 0x08
 
-#define MUTEX 0x50F750F7
-#define HOLD  MUTEX+1
-
-static cyg_mutex_t mutex;
-static volatile cyg_handle_t owner;
+static cyg_mutex_t softnet_mutex;
+static volatile cyg_handle_t softnet_thread;
 
 #define SPLINIT() CYG_MACRO_START               \
-    cyg_mutex_init( &mutex );                   \
-    owner = 0;                                  \
+    cyg_mutex_init( &softnet_mutex );           \
+    softnet_thread = 0;                         \
 CYG_MACRO_END
 
-// use the scheduler lock for SPLX() and a mutex for softnet
-
-static inline cyg_uint32
-cyg_splin_softnet(void)
+//
+// This function is called in order to protect internal data structures
+// short-term, primarily so that interrupt processing does not interfere
+// with them.
+//
+// Simply protecting against interrupts (DSRs) should suffice.
+//
+cyg_uint32
+#ifdef CYGIMPL_TRACE_SPLX   
+cyg_splimp(const char *file, const int line)
+#else
+cyg_splimp(void)
+#endif
 {
-    if ( 0 == cyg_scheduler_read_lock() ) {
-        cyg_handle_t self = cyg_thread_self();
-        if ( self != owner ) {
-            cyg_mutex_lock( &mutex ); // Perfectly OK for this to wait
-            owner = self;
-            return MUTEX; // release when restoring here
-        }
-        return HOLD; // do not release when restoring to this value
+    cyg_uint32 old_ints;
+    cyg_scheduler_lock();
+#ifdef CYGIMPL_TRACE_SPLX   
+    do_sched_event(__FUNCTION__, file, line, cyg_scheduler_read_lock());
+#endif
+    old_ints = spl_state;
+    spl_state |= SPL_STATE_IMP;
+    if (old_ints & SPL_STATE_IMP) {
+        // Already at this state/level, no need to retake scheduler lock
+        cyg_scheduler_unlock();
     }
-    cyg_scheduler_lock();
-    return cyg_scheduler_read_lock() - 1;
-}
-
-static inline cyg_uint32
-cyg_splin(void)
-{
-    cyg_scheduler_lock();
-    return cyg_scheduler_read_lock() - 1;
+    return old_ints;
 }
 
-static inline void
-cyg_splout(cyg_uint32 orig)
-{
-    if ( MUTEX == orig ) {
-        CYG_ASSERT( cyg_thread_self() == owner, "Not owner release!" );
-        cyg_scheduler_lock();
-        owner = 0;
-        cyg_mutex_unlock( &mutex );
-        cyg_scheduler_unlock();
-        return;
-    }
-    if ( HOLD == orig ) {
-        CYG_ASSERT( cyg_thread_self() == owner, "Not owner hold!" );
-        return;
-    }
-    CYG_ASSERT( 0 == (0xffff0000 & orig), "Scary splx value" );
-    while ( cyg_scheduler_read_lock() > orig )
-        cyg_scheduler_unlock();
-}
-
-#define SPL_ENTER(x)    (x) = cyg_splin()
-#define SPL_SOFTNET(x)  (x) = cyg_splin_softnet()
-#define SPL_EXIT(x)     cyg_splout((x))
-
+//
+// This function is called in order to ensure that a timestamp is valid
+// i.e. no time passes while the stamp is being taken (since it is a 
+// potentially non-idempotent data structure).
+//
+// Simply protecting against interrupts (DSRs) should suffice.
+//
+cyg_uint32
+#ifdef CYGIMPL_TRACE_SPLX   
+cyg_splclock(const char *file, const int line)
 #else
-#if 1
-
-// use the scheduler lock for SPLX()
-static inline cyg_uint32
-cyg_splin(void)
-{
-    cyg_scheduler_lock();
-    return cyg_scheduler_read_lock() - 1;
-}
-
-static inline void
-cyg_splout(cyg_uint32 orig)
-{
-    CYG_ASSERT( 0 == (0xffff0000 & orig), "Scary splx value" );
-    while ( cyg_scheduler_read_lock() > orig )
-        cyg_scheduler_unlock();
-}
-
-#define SPL_ENTER(x)    (x) = cyg_splin()
-#define SPL_SOFTNET(x)  (x) = cyg_splin()
-#define SPL_EXIT(x)     cyg_splout((x))
-
-#else
-
-// Old interrupt based version
-#define SPL_ENTER(x)    HAL_DISABLE_INTERRUPTS((x))
-#define SPL_SOFTNET(x)  HAL_DISABLE_INTERRUPTS((x))
-#define SPL_EXIT(x)     HAL_RESTORE_INTERRUPTS((x))
-
+cyg_splclock(void)
 #endif
-#endif
-// ------------------------------------------------------------------------
-
-cyg_uint32
-cyg_splimp(void)
 {
     cyg_uint32 old_ints;
-    SPL_ENTER(old_ints);
+    cyg_scheduler_lock();
+#ifdef CYGIMPL_TRACE_SPLX   
+    do_sched_event(__FUNCTION__, file, line, cyg_scheduler_read_lock());
+#endif
+    old_ints = spl_state;
+    spl_state |= SPL_STATE_CLOCK;
+    if (old_ints & SPL_STATE_CLOCK) {
+        // Already at this state/level, no need to retake scheduler lock
+        cyg_scheduler_unlock();
+    }
     return old_ints;
 }
 
 cyg_uint32
+#ifdef CYGIMPL_TRACE_SPLX   
+cyg_splnet(const char *file, const int line)
+#else
 cyg_splnet(void)
+#endif
 {
     cyg_uint32 old_ints;
-    SPL_ENTER(old_ints);
+    cyg_scheduler_lock();
+#ifdef CYGIMPL_TRACE_SPLX   
+    do_sched_event(__FUNCTION__, file, line, cyg_scheduler_read_lock());
+#endif
+    old_ints = spl_state;
+    spl_state |= SPL_STATE_NET;
+    if (old_ints & SPL_STATE_NET) {
+        // Already at this state/level, no need to retake scheduler lock
+        cyg_scheduler_unlock();
+    }
     return old_ints;
 }
 
+//
+// Prevent all other stack processing, including interrupts (DSRs), etc.
+//
 cyg_uint32
-cyg_splclock(void)
+#ifdef CYGIMPL_TRACE_SPLX   
+cyg_splsoftnet(const char *file, const int line)
+#else
+cyg_splsoftnet(void)
+#endif
 {
     cyg_uint32 old_ints;
-    SPL_ENTER(old_ints);
+    cyg_scheduler_lock();
+#ifdef CYGIMPL_TRACE_SPLX   
+    do_sched_event(__FUNCTION__, file, line, cyg_scheduler_read_lock());
+#endif
+    if (spl_state & SPL_STATE_SOFTNET) {
+        if (softnet_thread == cyg_thread_self()) {
+            // Do nothing
+            old_ints = spl_state;
+            spl_state |= SPL_STATE_SOFTNET;
+            cyg_scheduler_unlock();
+            return old_ints;
+        }
+    }
+    cyg_scheduler_unlock();
+    cyg_mutex_lock(&softnet_mutex);
+    cyg_scheduler_lock();
+    softnet_thread = cyg_thread_self();
+    old_ints = spl_state;
+    spl_state |= SPL_STATE_SOFTNET;
     return old_ints;
 }
 
-cyg_uint32
-cyg_splsoftnet(void)
+//
+// Return to a previous interrupt state/level.
+//
+void
+#ifdef CYGIMPL_TRACE_SPLX   
+cyg_splx(cyg_uint32 old_state, const char *file, const int line)
+#else
+cyg_splx(cyg_uint32 old_state)
+#endif
 {
-    cyg_uint32 old_ints;
-    SPL_SOFTNET(old_ints);
-    return old_ints;
+    cyg_uint32 new_state = spl_state;
+    cyg_scheduler_lock();  // Extra security while messing about
+#ifdef CYGIMPL_TRACE_SPLX   
+    do_sched_event(__FUNCTION__, file, line, cyg_scheduler_read_lock());
+#endif
+    if ((spl_state & SPL_STATE_SOFTNET) && !(old_state & SPL_STATE_SOFTNET)) {
+        new_state &= ~SPL_STATE_SOFTNET;
+        softnet_thread = 0;
+        cyg_mutex_unlock(&softnet_mutex);
+        cyg_scheduler_unlock();
+    }
+    if ((spl_state & SPL_STATE_NET) && !(old_state & SPL_STATE_NET)) {
+        new_state &= ~SPL_STATE_NET;
+        cyg_scheduler_unlock();
+    }
+    if ((spl_state & SPL_STATE_CLOCK) && !(old_state & SPL_STATE_CLOCK)) {
+        new_state &= ~SPL_STATE_CLOCK;
+        cyg_scheduler_unlock();
+    }
+    if ((spl_state & SPL_STATE_IMP) && !(old_state & SPL_STATE_IMP)) {
+        new_state &= ~SPL_STATE_IMP;
+        cyg_scheduler_unlock();
+    }
+    spl_state = new_state;
+    cyg_scheduler_unlock();
 }
-
-void
-cyg_splx(cyg_uint32 old_lev)
-{
-    SPL_EXIT(old_lev);
-}
+//---------------------------- splx() emulation ------------------------------
 
 void
 setsoftnet(void)
@@ -405,7 +439,6 @@ cyg_kmem_init(void)
     mclrefcnt = net_clusters_refcnt;
 }
 
-
 void cyg_kmem_print_stats( void )
 {
     cyg_mempool_info info;
@@ -557,6 +590,7 @@ ovbcopy(const void *s, void *d, size_t l
     memcpy(d, s, len);
 }
 
+//------------------ tsleep() and wakeup() emulation ---------------------------
 //
 // Structure used to keep track of 'tsleep' style events
 //
@@ -600,15 +634,13 @@ cyg_tsleep(void *chan, int pri, char *wm
     int i, res = 0;
     struct wakeup_event *ev;    
     cyg_tick_count_t sleep_time;
-#ifdef SPLSOFTNET_IS_A_MUTEX
-    int olock; // this does the same as safe_lock() but keeping the old state
+    int olock; // current state of scheduler lock - so it can be replaced
+    cyg_handle_t self = cyg_thread_self();
+
     cyg_scheduler_lock(); // ...around.
     olock = cyg_scheduler_read_lock();
     if ( olock > 1 )
         cyg_scheduler_unlock();
-#else
-    cyg_scheduler_safe_lock();  // Ensure safe scan
-#endif
 
     for (i = 0, ev = wakeup_list;  i < CYGPKG_NET_NUM_WAKEUP_EVENTS;  i++, ev++) {
         if (ev->chan == 0) {
@@ -619,40 +651,40 @@ cyg_tsleep(void *chan, int pri, char *wm
     if (i == CYGPKG_NET_NUM_WAKEUP_EVENTS) {
         panic("no sleep slots");
     }
-    CYG_ASSERT( 1 == cyg_scheduler_read_lock(), "Sleep won't!" );
+    if ( 1 != cyg_scheduler_read_lock()) {
+        panic("Tsleep - called with scheduler locked\n");
+    }
+
+    // Then we must release the 'softnet' mutex when we wait - if we have it
+    if ( self == softnet_thread ) {
+        softnet_thread = 0;
+        spl_state &= ~SPL_STATE_SOFTNET;
+        cyg_mutex_unlock( &softnet_mutex );
+    } else {
+        self = 0; // Flag no need to reclaim
+    }
 
-#ifdef SPLSOFTNET_IS_A_MUTEX
-    {   // Then we must release the mutex when we wait - if we have it
-        cyg_handle_t self = cyg_thread_self();
-        if ( self == owner ) {
-            owner = 0;
-            cyg_mutex_unlock( &mutex );
-        } else {
-            self = 0; // Flag no need to reclaim
+    // This part actually does the wait:
+    cyg_scheduler_unlock();
+    if (timo) {
+        sleep_time = cyg_current_time() + timo;
+        if (!cyg_semaphore_timed_wait(&ev->sem, sleep_time)) {
+            res = ETIMEDOUT;
+            ev->chan = 0;  // Free slot
         }
-#endif
+    } else {
+        cyg_semaphore_wait(&ev->sem);
+    }
 
-        // This part actually does the wait:
+    if ( self ) { // return to previous state
+        cyg_mutex_lock( &softnet_mutex ); // this might wait
+        cyg_scheduler_lock();
+        softnet_thread = self; // got it now...
+        spl_state |= SPL_STATE_SOFTNET;
         cyg_scheduler_unlock();
-        if (timo) {
-            sleep_time = cyg_current_time() + timo;
-            if (!cyg_semaphore_timed_wait(&ev->sem, sleep_time)) {
-                res = ETIMEDOUT;
-                ev->chan = 0;  // Free slot
-            }
-        } else {
-            cyg_semaphore_wait(&ev->sem);
-        }
-
-#ifdef SPLSOFTNET_IS_A_MUTEX
-        if ( self ) { // return to previous state
-            cyg_mutex_lock( &mutex ); // this might wait
-            owner = self; // got it now...
-        }
-        if ( olock > 1 )
-            cyg_scheduler_lock();
     }
-#endif
+    if ( olock > 1 )
+        cyg_scheduler_lock();
 
     return res;
 }
@@ -669,6 +701,7 @@ cyg_timeout_init(void)
         cyg_semaphore_init(&ev->sem, 0);
     }
 }
+//------------------ tsleep() and wakeup() emulation ---------------------------
 
 //
 // Network software interrupt handler
@@ -680,10 +713,11 @@ static void
 cyg_netint(cyg_addrword_t param)
 {
     cyg_flag_value_t curisr;
+    int s;
     while (true) {
         curisr = cyg_flag_wait(&netint_flags, NETISR_ANY, 
                                CYG_FLAG_WAITMODE_OR|CYG_FLAG_WAITMODE_CLR);
-        cyg_scheduler_lock();  // This code should not be preempted
+        s = splsoftnet();      // Prevent any overlapping "stack" processing
 #ifdef INET
         if (curisr & (1 << NETISR_ARP)) {
             // Pending ARP requests
@@ -700,7 +734,7 @@ cyg_netint(cyg_addrword_t param)
             ip6intr();
         }
 #endif
-        cyg_scheduler_unlock();
+        splx(s);
     }
 }
 
@@ -719,6 +753,9 @@ cyg_net_init(void)
     static int _init = false;
     cyg_netdevtab_entry_t *t;
 
+#ifdef CYGIMPL_TRACE_SPLX   
+    show_sched_events();
+#endif
     if (_init) return;
     cyg_do_net_init();  // Just forces the linking in of the initializer/constructor
     // Initialize interrupt "flags"
@@ -765,3 +802,71 @@ cyg_net_init(void)
     // Done
     _init = true;
 }
+
+#ifdef CYGIMPL_TRACE_SPLX   
+#undef cyg_scheduler_lock
+#undef cyg_scheduler_safe_lock
+#undef cyg_scheduler_unlock
+
+#define MAX_SCHED_EVENTS 256
+static struct _sched_event {
+    char *fun, *file;
+    int line, lock;
+} sched_event[MAX_SCHED_EVENTS];
+static int next_sched_event = 0;
+static int total_sched_events = 0;
+
+static void
+do_sched_event(char *fun, char *file, int line, int lock)
+{
+    struct _sched_event *se = &sched_event[next_sched_event];
+    if (++next_sched_event == MAX_SCHED_EVENTS) {
+        next_sched_event = 0;
+    }
+    se->fun = fun;
+    se->file = file;
+    se->line = line;
+    se->lock = lock;
+    total_sched_events++;
+}
+
+static void
+show_sched_events(void)
+{
+    int i;
+    struct _sched_event *se;
+    if (total_sched_events < MAX_SCHED_EVENTS) {
+        i = 0;
+    } else {
+        i = next_sched_event + 1;
+        if (i == MAX_SCHED_EVENTS) i = 0;
+    }
+    diag_printf("%d total scheduler events\n", total_sched_events);
+    while (i != next_sched_event) {
+        se = &sched_event[i];
+        diag_printf("%s - lock: %d, called from %s.%d\n", se->fun, se->lock, se->file, se->line);
+        if (++i == MAX_SCHED_EVENTS) i = 0;
+    }
+}
+
+void
+_cyg_scheduler_lock(char *file, int line)
+{
+    cyg_scheduler_lock();
+    do_sched_event(__FUNCTION__, file, line, cyg_scheduler_read_lock());
+}
+
+void
+_cyg_scheduler_safe_lock(char *file, int line)
+{
+    cyg_scheduler_safe_lock();
+    do_sched_event(__FUNCTION__, file, line, cyg_scheduler_read_lock());
+}
+
+void
+_cyg_scheduler_unlock(char *file, int line)
+{
+    cyg_scheduler_unlock();
+    do_sched_event(__FUNCTION__, file, line, cyg_scheduler_read_lock());
+}
+#endif // CYGIMPL_TRACE_SPLX
--- a/packages/net/tcpip/current/src/lib/bootp_support.c
+++ b/packages/net/tcpip/current/src/lib/bootp_support.c
@@ -52,7 +52,10 @@
 //
 //==========================================================================
 
-// BOOTP support
+// BOOTP support (and a little DHCP support also)
+
+#include <pkgconf/system.h>
+#include <pkgconf/net.h>
 
 #include <network.h>
 
@@ -71,6 +74,7 @@ do_bootp(const char *intf, struct bootp 
     struct bootp bootp_xmit;
     unsigned char mincookie[] = {99,130,83,99,255} ;
     struct timeval tv;
+    cyg_bool_t retcode = true;
 
     // Ensure clean slate
     route_reinit();  // Force any existing routes to be forgotten
@@ -196,11 +200,13 @@ do_bootp(const char *intf, struct bootp 
     addrlen = sizeof(bootp_server_addr);
     if (recvfrom(s, recv, sizeof(struct bootp), 0,
                  (struct sockaddr *)&bootp_server_addr, &addrlen) < 0) {
-        perror("recvfrom error");
-        return false;
+        // This is an "acceptable" error, it means there is no server for
+        // us: do not initialize the interface.
+        retcode = false;
     }
 
-
+    // Shut things down regardless of success of rx, otherwise other
+    // interfaces cannot be initialised!
     memset(addrp, 0, sizeof(*addrp));
     addrp->sin_family = AF_INET;
     addrp->sin_len = sizeof(*addrp);
@@ -221,22 +227,30 @@ do_bootp(const char *intf, struct bootp 
 
     // All done with socket
     close(s);
-    return true;
+    return retcode;
 }
 
 static char *_bootp_op[] = {"", "REQUEST", "REPLY"};
 static char *_bootp_hw_type[] = {"", "Ethernet", "Exp Ethernet", "AX25",
                                      "Pronet", "Chaos", "IEEE802", "Arcnet"};
 
+static char *_dhcpmsgs[] = {"","DISCOVER", "OFFER", "REQUEST", "DECLINE",
+                           "ACK", "NAK", "RELEASE" };
+
 void
 show_bootp(const char *intf, struct bootp *bp)
 {
     int i, len;
-    unsigned char *op, *ap = 0;
+    unsigned char *op, *ap = 0, optover;
     unsigned char name[128];
     struct in_addr addr[32];
     diag_printf("BOOTP[%s] op: %s\n", intf, _bootp_op[bp->bp_op]);
-    diag_printf("       hw_type: %s\n", _bootp_hw_type[bp->bp_htype]);
+    diag_printf("       htype: %s\n", _bootp_hw_type[bp->bp_htype]);
+    diag_printf("        hlen: %d\n", bp->bp_hlen );
+    diag_printf("        hops: %d\n", bp->bp_hops );
+    diag_printf("         xid: 0x%x\n", bp->bp_xid );
+    diag_printf("        secs: %d\n", bp->bp_secs );
+    diag_printf("       flags: 0x%x\n", bp->bp_flags );
     diag_printf("       hw_addr: ");
     for (i = 0;  i < bp->bp_hlen;  i++) {
         diag_printf("%02x", bp->bp_chaddr[i]);
@@ -247,12 +261,13 @@ show_bootp(const char *intf, struct boot
     diag_printf("         my IP: %s\n", inet_ntoa(bp->bp_yiaddr));
     diag_printf("     server IP: %s\n", inet_ntoa(bp->bp_siaddr));
     diag_printf("    gateway IP: %s\n", inet_ntoa(bp->bp_giaddr));
-    if (bp->bp_sname[0]) {
+
+    optover = 0; // See whether sname and file are overridden for options
+    (void)get_bootp_option( bp, TAG_DHCP_OPTOVER, &optover );
+    if ( !(1 & optover) && bp->bp_sname[0] )
         diag_printf("        server: %s\n", bp->bp_sname);
-    }
-    if (bp->bp_file[0]) {
+    if ( ! (2 & optover) && bp->bp_file[0] )
         diag_printf("          file: %s\n", bp->bp_file);
-    }
     if (bp->bp_vend[0]) {
         diag_printf("  options:\n");
         op = &bp->bp_vend[4];
@@ -291,8 +306,51 @@ show_bootp(const char *intf, struct boot
                 if (*op == TAG_HOST_NAME)   ap =  "   host name";
                 diag_printf("       %s: %s\n", ap, name);
                 break;
+            case TAG_DHCP_MESS_TYPE:
+                diag_printf("        DHCP message: %d %s\n",
+                            op[2], _dhcpmsgs[op[2]] );
+                break;
+            case TAG_DHCP_REQ_IP:
+                diag_printf("        DHCP requested ip: %d.%d.%d.%d\n",
+                            op[2], op[3], op[4], op[5] );  
+                break;
+            case TAG_DHCP_LEASE_TIME   :
+            case TAG_DHCP_RENEWAL_TIME :
+            case TAG_DHCP_REBIND_TIME  :
+                diag_printf("        DHCP time %d: %d\n",
+                            *op, ((((((op[2]<<8)+op[3])<<8)+op[4])<<8)+op[5]) );
+
+                break;
+            case TAG_DHCP_SERVER_ID    :
+                diag_printf("        DHCP server id: %d.%d.%d.%d\n",
+                            op[2], op[3], op[4], op[5] );  
+                break;
+
+            case TAG_DHCP_OPTOVER      :
+            case TAG_DHCP_PARM_REQ_LIST:
+            case TAG_DHCP_TEXT_MESSAGE :
+            case TAG_DHCP_MAX_MSGSZ    :
+            case TAG_DHCP_CLASSID      :
+            case TAG_DHCP_CLIENTID     :
+                diag_printf("        DHCP option: %x/%d.%d:", *op, *op, *(op+1));
+                if ( 1 == op[1] )
+                    diag_printf( " %d", op[2] );
+                else if ( 2 == op[1] )
+                    diag_printf( " %d", (op[2]<<8)+op[3] );
+                else if ( 4 == op[1] )
+                    diag_printf( " %d", ((((((op[2]<<8)+op[3])<<8)+op[4])<<8)+op[5]) );
+                else
+                    for ( i = 2; i < 2 + op[1]; i++ )
+                        diag_printf(" %d",op[i]);
+                diag_printf("\n");
+                break;
+
             default:
-                diag_printf("Unknown option: %x.%d\n", *op, *(op+1));
+                diag_printf("Unknown option: %x/%d.%d:", *op, *op, *(op+1));
+                for ( i = 2; i < 2 + op[1]; i++ )
+                    diag_printf(" %d",op[i]);
+                diag_printf("\n");
+                break;
             }                
             op += *(op+1)+2;
         }
@@ -302,19 +360,38 @@ show_bootp(const char *intf, struct boot
 cyg_bool_t
 get_bootp_option(struct bootp *bp, unsigned char tag, void *opt)
 {
-    unsigned char *op;
     unsigned char *val = (unsigned char *)opt;
     int i;
-    op = &bp->bp_vend[4];
-    while (*op != TAG_END) {
-        if (*op == tag) {
-            for (i = 0;  i < *(op+1);  i++) {
-                *val++ = *(op+i+2);
-            }
-            return true;
-        }
-        op += *(op+1)+2;
-    }
+    cyg_uint8 optover;
+
+#define SCANTAG( ptr ) CYG_MACRO_START          \
+    unsigned char *op = (ptr);                  \
+    while (*op != TAG_END) {                    \
+        if (*op == tag) {                       \
+            for (i = 0;  i < *(op+1);  i++) {   \
+                *val++ = *(op+i+2);             \
+            }                                   \
+            return true;                        \
+        }                                       \
+        op += *(op+1)+2;                        \
+    }                                           \
+CYG_MACRO_END
+
+    SCANTAG( &bp->bp_vend[4] );
+
+    if ( TAG_DHCP_OPTOVER == tag ) // prevent recursion > once
+        return false;
+    // else, look for that tag to see if there's more...
+    optover = 0;
+    if ( ! get_bootp_option( bp, TAG_DHCP_OPTOVER, &optover ) )
+        return false;
+
+    if ( 1 & optover ) // then the file field also holds options
+        SCANTAG( &bp->bp_file[0] );
+
+    if ( 2 & optover ) // then the sname field also holds options
+        SCANTAG( &bp->bp_sname[0] );
+
     return false;
 }
 
new file mode 100644
--- /dev/null
+++ b/packages/net/tcpip/current/src/lib/dhcp_prot.c
@@ -0,0 +1,1024 @@
+/*==========================================================================
+//
+//      dhcp_prot.c
+//
+//      DHCP protocol implementation for DHCP client
+//
+//==========================================================================
+//####COPYRIGHTBEGIN####
+//                                                                          
+// -------------------------------------------                              
+// The contents of this file are subject to the Red Hat eCos Public License 
+// Version 1.1 (the "License"); you may not use this file except in         
+// compliance with the License.  You may obtain a copy of the License at    
+// http://www.redhat.com/                                                   
+//                                                                          
+// 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 Configurable Operating System,      
+// released September 30, 1998.                                             
+//                                                                          
+// The Initial Developer of the Original Code is Red Hat.                   
+// Portions created by Red Hat are                                          
+// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.                             
+// All Rights Reserved.                                                     
+// -------------------------------------------                              
+//                                                                          
+//####COPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):   hmt
+// Contributors: gthomas
+// Date:        2000-07-01
+// Purpose:     DHCP support
+// Description: 
+//
+//####DESCRIPTIONEND####
+//
+//========================================================================*/
+
+#include <pkgconf/system.h>
+#include <pkgconf/net.h>
+
+#ifdef CYGPKG_NET_DHCP
+
+#if 0
+#define perror( txt ) // nothing
+#endif
+
+#include <network.h>
+#include <dhcp.h>
+
+#include <cyg/infra/cyg_ass.h>
+
+// ------------------------------------------------------------------------
+// Get the actual packet size of an initialized buffer
+
+static int
+dhcp_size( struct bootp *ppkt )
+{
+    unsigned char *op;
+    
+    op = &ppkt->bp_vend[0];
+    // First check for the cookie!
+    if ( op[0] !=  99 ||
+         op[1] != 130 ||
+         op[2] !=  83 ||
+         op[3] !=  99 ) {
+        CYG_FAIL( "Bad DHCP cookie" );
+        return 0;
+    }
+    op += 4;
+    while (*op != TAG_END) {
+        op += *(op+1)+2;
+        if ( op > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
+            CYG_FAIL( "Oversize DHCP packet in dhcp_size" );
+            return 0;
+        }
+    }
+    return (op - (unsigned char *)ppkt) + 1;
+}
+
+// ------------------------------------------------------------------------
+// Insert/set an option value in an initialized buffer
+
+static int
+set_fixed_tag( struct bootp *ppkt,
+               unsigned char tag,
+               cyg_uint32 value,
+               int len)
+{
+    unsigned char *op;
+
+    // Initially this will only scan the options field.
+    
+    op = &ppkt->bp_vend[4];
+    while (*op != TAG_END) {
+        if ( op > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
+            CYG_FAIL( "Oversize DHCP packet in set_fixed_tag" );
+            return false;
+        }
+        if (*op == tag)                 // Found it...
+            break;
+        op += *(op+1)+2;
+    }
+    
+    if (*op == tag) { // Found it...
+        if ( *(op+1) != len ) {
+            CYG_FAIL( "Wrong size in set_fixed_tag" );
+            return false;           // wrong size
+        }
+    }
+    else { // overwrite the end tag and install a new one
+        if ( op + len + 2 > &ppkt->bp_vend[BP_VEND_LEN-1] ) {
+            CYG_FAIL( "Oversize DHCP packet in set_fixed_tag append" );
+            return false;
+        }
+        *op = tag;
+        *(op+1) = len;
+        *(op + len + 2) = TAG_END;
+    }
+    // and insert the value.  Net order is BE.
+    op += len + 2 - 1;              // point to end of value
+    while ( len-- > 0 ) {
+        *op-- = (unsigned char)(value & 255);
+        value >>= 8;
+    }
+    return true;
+}
+
+// ------------------------------------------------------------------------
+// Bring up an interface enough to broadcast, before we know who we are
+
+static int
+bring_half_up(const char *intf, struct ifreq *ifrp )
+{
+    int s;
+    int one = 1;
+
+    struct sockaddr_in *addrp;
+    struct ecos_rtentry route;
+
+    // Ensure clean slate
+    route_reinit();  // Force any existing routes to be forgotten
+
+    s = socket(AF_INET, SOCK_DGRAM, 0);
+    if (s < 0) {
+        perror("socket");
+        return false;
+    }
+
+    if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one))) {
+        perror("setsockopt");
+        return false;
+    }
+
+    addrp = (struct sockaddr_in *) &ifrp->ifr_addr;
+    memset(addrp, 0, sizeof(*addrp));
+    addrp->sin_family = AF_INET;
+    addrp->sin_len = sizeof(*addrp);
+    addrp->sin_port = 0;
+    addrp->sin_addr.s_addr = INADDR_ANY;
+
+    strcpy(ifrp->ifr_name, intf);
+    if (ioctl(s, SIOCSIFADDR, ifrp)) { /* set ifnet address */
+        perror("SIOCSIFADDR");
+        return false;
+    }
+
+    if (ioctl(s, SIOCSIFNETMASK, ifrp)) { /* set net addr mask */
+        perror("SIOCSIFNETMASK");
+        return false;
+    }
+
+    /* the broadcast address is 255.255.255.255 */
+    memset(&addrp->sin_addr, 255, sizeof(addrp->sin_addr));
+    if (ioctl(s, SIOCSIFBRDADDR, ifrp)) { /* set broadcast addr */
+        perror("SIOCSIFBRDADDR");
+        return false;
+    }
+
+    ifrp->ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;
+    if (ioctl(s, SIOCSIFFLAGS, ifrp)) { /* set ifnet flags */
+        perror("SIOCSIFFLAGS up");
+        return false;
+    }
+
+    if (ioctl(s, SIOCGIFHWADDR, ifrp) < 0) { /* get MAC address */
+        perror("SIOCGIFHWADDR 1");
+        return false;
+    }
+
+    // Set up routing
+    /* the broadcast address is 255.255.255.255 */
+    memset(&addrp->sin_addr, 255, sizeof(addrp->sin_addr));
+    memset(&route, 0, sizeof(route));
+    memcpy(&route.rt_gateway, addrp, sizeof(*addrp));
+
+    addrp->sin_family = AF_INET;
+    addrp->sin_port = 0;
+    addrp->sin_addr.s_addr = INADDR_ANY;
+    memcpy(&route.rt_dst, addrp, sizeof(*addrp));
+    memcpy(&route.rt_genmask, addrp, sizeof(*addrp));
+
+    route.rt_dev = ifrp->ifr_name;
+    route.rt_flags = RTF_UP|RTF_GATEWAY;
+    route.rt_metric = 0;
+
+    if (ioctl(s, SIOCADDRT, &route)) { /* add route */
+        if (errno != EEXIST) {
+            perror("SIOCADDRT 3");
+            return false;
+        }
+    }
+
+    close(s);
+
+    return true;
+}
+
+
+// ------------------------------------------------------------------------
+// DHCP retransmission timeouts and number of tries
+
+static unsigned char timeout_random = 0;
+
+static inline void reset_timeout( struct timeval *ptv )
+{
+    timeout_random++;
+    ptv->tv_sec = 3 + (timeout_random & 3);
+    ptv->tv_usec = 65536 * (timeout_random & 15);
+}
+
+static inline int next_timeout( struct timeval *ptv )
+{
+    timeout_random++;
+    ptv->tv_sec = ptv->tv_sec * 2 - 2 + (timeout_random & 3);
+    return ptv->tv_sec < 48; // If longer, too many tries...
+}
+
+// ------------------------------------------------------------------------
+// Lease expiry and alarms to notify it
+
+static cyg_alarm_t alarm_function;
+
+static void alarm_function(cyg_handle_t alarm, cyg_addrword_t data)
+{
+    struct dhcp_lease *lease = (struct dhcp_lease *)data;
+    lease->which |= lease->next;
+    cyg_semaphore_post( &dhcp_needs_attention );
+
+    // Step the lease on into its next state of being alarmed ;-)
+    if ( lease->next & DHCP_LEASE_EX ) {
+        cyg_alarm_disable( alarm );
+    }
+    else if ( lease->next & DHCP_LEASE_T2 ) {
+        cyg_alarm_initialize( lease->alarm, lease->expiry, 0 );
+        cyg_alarm_enable( lease->alarm );
+        lease->next = DHCP_LEASE_EX;
+    }
+    else if ( lease->next & DHCP_LEASE_T1 ) {
+        cyg_alarm_initialize( lease->alarm, lease->t2, 0 );
+        cyg_alarm_enable( lease->alarm );
+        lease->next = DHCP_LEASE_T2;
+    }
+}
+
+static inline void no_lease( struct dhcp_lease *lease )
+{
+    if ( lease->alarm ) {
+        // Already set: delete this.
+        cyg_alarm_disable( lease->alarm );
+        cyg_alarm_delete( lease->alarm );
+        lease->alarm = 0;
+    }
+}
+
+static inline void new_lease( struct bootp *bootp, struct dhcp_lease *lease )
+{
+    cyg_tick_count_t now = cyg_current_time();
+    cyg_tick_count_t then;
+    cyg_uint32 tag = 0;
+    cyg_resolution_t resolution = 
+        cyg_clock_get_resolution(cyg_real_time_clock());
+    cyg_handle_t h;
+
+    // Silence any jabbering from past lease on this interface
+    no_lease( lease );
+    lease->which = lease->next = 0;
+    cyg_clock_to_counter(cyg_real_time_clock(), &h);
+    cyg_alarm_create( h, alarm_function, (cyg_addrword_t)lease,
+                      &lease->alarm, &lease->alarm_obj );
+
+    // extract the lease time and scale it &c to now.
+    get_bootp_option( bootp, TAG_DHCP_LEASE_TIME, &tag );
+
+    if ( 0xffffffff == tag ) {
+        lease->expiry = 0xffffffffffffffff;
+        lease->t2     = 0xffffffffffffffff;
+        lease->t1     = 0xffffffffffffffff;
+        return; // it's an infinite lease, hurrah!
+    }
+
+    then = (cyg_uint64)(ntohl(tag));
+
+    then *= 1000000000; // into nS - we know there is room in a tick_count_t
+    then = (then / resolution.dividend) * resolution.divisor; // into system ticks
+    lease->expiry = now + then;
+
+    get_bootp_option( bootp, TAG_DHCP_REBIND_TIME, &tag );
+    then = (cyg_uint64)(ntohl(tag));
+    then *= 1000000000; // into nS - we know there is room in a tick_count_t
+    then = (then / resolution.dividend) * resolution.divisor; // into system ticks
+    lease->t2 = now + then;
+
+    get_bootp_option( bootp, TAG_DHCP_RENEWAL_TIME, &tag );
+    then = (cyg_uint64)(ntohl(tag));
+    then *= 1000000000; // into nS - we know there is room in a tick_count_t
+    then = (then / resolution.dividend) * resolution.divisor; // into system ticks
+    lease->t1 = now + then;
+
+#if 0 // for testing this mechanism
+    lease->expiry = now + 5000; // 1000 here makes for failure in the DHCP test
+    lease->t2     = now + 3500;
+    lease->t1     = now + 2500;
+#endif
+
+    lease->next = DHCP_LEASE_T1;
+
+    cyg_alarm_initialize( lease->alarm, lease->t1, 0 );
+    cyg_alarm_enable( lease->alarm );
+}
+
+
+// ------------------------------------------------------------------------
+// the DHCP state machine - this does all the work
+
+int
+do_dhcp(const char *intf, struct bootp *res,
+        cyg_uint8 *pstate, struct dhcp_lease *lease)
+{
+    struct ifreq ifr;
+    struct sockaddr_in cli_addr, broadcast_addr, server_addr, rx_addr;
+    int s, addrlen;
+    int one = 1;
+    unsigned char mincookie[] = {99,130,83,99,255} ;
+    struct timeval tv;
+    cyg_uint8 oldstate = *pstate;
+    cyg_uint8 msgtype = 0, seen_bootp_reply = 0;
+
+    cyg_uint32 xid;
+
+    // IMPORTANT: xmit is the same as res throughout this; *received is a
+    // scratch buffer for reception; its contents are always copied to res
+    // when we are happy with them.  So we always transmit from the
+    // existing state.
+    struct bootp rx_local;
+    struct bootp *received = &rx_local;
+    struct bootp *xmit = res;
+
+    // First, get a socket on the interface in question.  But Zeroth, if
+    // needs be, bring it to the half-up broadcast only state if needs be.
+    
+    if ( DHCPSTATE_INIT      == oldstate
+         || DHCPSTATE_FAILED == oldstate
+         || 0                == oldstate ) {
+        // either explicit init state or the beginning of time or retry
+        if ( ! bring_half_up( intf, &ifr ) )
+            return false;
+        *pstate = DHCPSTATE_INIT;
+        xid = (cyg_uint32)res + (cyg_uint32)(0xffffffff & cyg_current_time());
+    }
+    else
+        xid = res->bp_xid; // use what's there already
+
+    s = socket(AF_INET, SOCK_DGRAM, 0);
+    if (s < 0) {
+        perror("socket");
+        return false;
+    }
+
+    if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one))) {
+        perror("setsockopt");
+        return false;
+    }
+
+    memset((char *) &cli_addr, 0, sizeof(cli_addr));
+    cli_addr.sin_family = AF_INET;
+    cli_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+    cli_addr.sin_port = htons(IPPORT_BOOTPC);
+    
+    memset((char *) &broadcast_addr, 0, sizeof(broadcast_addr));
+    broadcast_addr.sin_family = AF_INET;
+    broadcast_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
+    broadcast_addr.sin_port = htons(IPPORT_BOOTPS);
+
+    memset((char *) &server_addr, 0, sizeof(server_addr));
+    server_addr.sin_family = AF_INET;
+    server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); // overwrite later
+    server_addr.sin_port = htons(IPPORT_BOOTPS);
+
+    if(bind(s, (struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0) {
+        perror("bind error");
+        return false;
+    }
+    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
+        perror("setsockopt SO_REUSEADDR");
+        return false;
+    }
+    if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) {
+        perror("setsockopt SO_REUSEPORT");
+        return false;
+    }
+    
+    // Now, we can launch into the DHCP state machine.  I think this will
+    // be the neatest way to do it; it returns from within the switch arms
+    // when all is well, or utterly failed.
+
+    reset_timeout( &tv );
+
+    while ( 1 ) {
+
+        // If we are active rather than in the process of shutting down,
+        // check for any lease expiry every time round, so that alarms
+        // *can* change the course of events even when already renewing,
+        // for example.
+        if ( DHCPSTATE_DO_RELEASE   != *pstate
+             && DHCPSTATE_NOTBOUND  != *pstate
+             && DHCPSTATE_FAILED    != *pstate ) {
+            cyg_uint8 lease_state;
+
+            cyg_scheduler_lock();
+            lease_state = lease->which;
+            lease->which = 0; // flag that we have noticed it
+            cyg_scheduler_unlock();
+
+            if ( lease_state & DHCP_LEASE_EX ) {
+                // then the lease has expired completely!
+                *pstate = DHCPSTATE_NOTBOUND;
+            }
+            else if ( lease_state & DHCP_LEASE_T2 ) {
+                // Time to renew
+                reset_timeout( &tv ); // for the next conversation
+                *pstate = DHCPSTATE_REBINDING;
+            }
+            else if ( lease_state & DHCP_LEASE_T1 ) {
+                // Time to renew
+                reset_timeout( &tv ); // for the next conversation
+                *pstate = DHCPSTATE_RENEWING;
+            }
+        }
+
+        switch ( *pstate ) {
+
+        case DHCPSTATE_INIT:
+
+            // Send the DHCPDISCOVER packet
+
+            if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0) { /* get MAC address */
+                perror("SIOCGIFHWADDR 2");
+                return false;
+            }
+
+            // Fill in the BOOTP request - DHCPDISCOVER packet
+            bzero(xmit, sizeof(*xmit));
+            xmit->bp_op = BOOTREQUEST;
+            xmit->bp_htype = ifr.ifr_hwaddr.sa_family;
+            xmit->bp_hlen = IFHWADDRLEN;
+            xmit->bp_xid = xid;
+            xmit->bp_secs = 0;
+            bcopy(ifr.ifr_hwaddr.sa_data, &xmit->bp_chaddr, xmit->bp_hlen);
+            bcopy(mincookie, xmit->bp_vend, sizeof(mincookie));
+
+            // remove the next line to test ability to handle bootp packets.
+            set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPDISCOVER, 1 );
+
+            set_fixed_tag( xmit, TAG_DHCP_MAX_MSGSZ, BP_MINPKTSZ, 2 );
+
+#ifdef DHCP_CHATTER
+            diag_printf( "---------DHCPSTATE_INIT sending:\n" );
+            show_bootp( intf, xmit );
+#endif            
+            if(sendto(s, xmit, dhcp_size(xmit), 0, 
+                      (struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0) {
+                *pstate = DHCPSTATE_FAILED;
+                break;
+            }
+
+            seen_bootp_reply = 0;
+            *pstate = DHCPSTATE_SELECTING;
+            break;
+
+        case DHCPSTATE_SELECTING:
+            // This is a separate state so that we can listen again
+            // *without* retransmitting.
+            
+            // listen for the DHCPOFFER reply
+
+            setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+
+            addrlen = sizeof(rx_addr);
+            if (recvfrom(s, received, sizeof(struct bootp), 0,
+                         (struct sockaddr *)&rx_addr, &addrlen) < 0) {
+                // No packet arrived (this time)
+                if ( seen_bootp_reply ) { // then already have a bootp reply
+                    // Save the good packet in *xmit
+                    bcopy( received, xmit, dhcp_size(received) );
+                    *pstate = DHCPSTATE_BOOTP_FALLBACK;
+                    reset_timeout( &tv );
+                    break;
+                }       
+                // go to the next larger timeout and re-send:
+                if ( ! next_timeout( &tv ) ) {
+                    *pstate = DHCPSTATE_FAILED;
+                    break;
+                }
+                *pstate = DHCPSTATE_INIT; // to retransmit
+                break;
+            }
+
+#ifdef DHCP_CHATTER
+            diag_printf( "---------DHCPSTATE_SELECTING received:\n" );
+            diag_printf( "...rx_addr is family %d, addr %08x, port %d\n",
+                         rx_addr.sin_family,
+                         rx_addr.sin_addr.s_addr,
+                         rx_addr.sin_port );
+            show_bootp( intf, received );
+#endif            
+            if ( received->bp_xid != xid )   // not the same transaction;
+                break;                  // listen again...
+
+            if ( 0 == received->bp_siaddr.s_addr ) {
+                // then fill in from the options...
+                get_bootp_option( received, TAG_DHCP_SERVER_ID,
+                                  &received->bp_siaddr.s_addr );
+            }
+
+            // see if it was a DHCP reply or a bootp reply; it could be
+            // either.
+            if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype ) ) {
+                if ( DHCPOFFER == msgtype ) { // all is well
+                    // Save the good packet in *xmit
+                    bcopy( received, xmit, dhcp_size(received) );
+                    // we like the packet, so reset the timeout for next time
+                    reset_timeout( &tv );
+                    *pstate = DHCPSTATE_REQUESTING;
+                }
+            }
+            else // No TAG_DHCP_MESS_TYPE entry so it's a bootp reply
+                seen_bootp_reply = 1; // (keep the bootp packet in received)
+                
+            // If none of the above state changes occurred, we got a packet
+            // that "should not happen", OR we have a bootp reply in our
+            // hand; so listen again with the same timeout, without
+            // retrying the send, in the hope of getting a DHCP reply.
+            break;
+
+        case DHCPSTATE_REQUESTING:
+            // Just send what you got with a DHCPREQUEST in the message type.
+            // then wait for an ACK in DHCPSTATE_REQUEST_RECV.
+
+            // Fill in the BOOTP request - DHCPREQUEST packet
+            xmit->bp_op = BOOTREQUEST;
+
+            set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPREQUEST, 1 );
+            set_fixed_tag( xmit, TAG_DHCP_MAX_MSGSZ, BP_MINPKTSZ, 2 );
+
+            // And this will be a new one:
+            set_fixed_tag( xmit, TAG_DHCP_REQ_IP, ntohl(xmit->bp_yiaddr.s_addr), 4 );
+            
+#ifdef DHCP_CHATTER
+            diag_printf( "---------DHCPSTATE_REQUESTING sending:\n" );
+            show_bootp( intf, xmit );
+#endif            
+            if(sendto(s, xmit, dhcp_size(xmit), 0, 
+                      (struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0) {
+                *pstate = DHCPSTATE_FAILED;
+                break;
+            }
+
+            *pstate = DHCPSTATE_REQUEST_RECV;
+            break;
+
+        case DHCPSTATE_REQUEST_RECV:
+            // wait for an ACK or a NACK - retry by going back to
+            // DHCPSTATE_REQUESTING; NACK means go back to INIT.
+
+            setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+
+            addrlen = sizeof(rx_addr);
+            if (recvfrom(s, received, sizeof(struct bootp), 0,
+                         (struct sockaddr *)&rx_addr, &addrlen) < 0) {
+                // No packet arrived
+                // go to the next larger timeout and re-send:
+                if ( ! next_timeout( &tv ) ) {
+                    *pstate = DHCPSTATE_FAILED;
+                    break;
+                }
+                *pstate = DHCPSTATE_REQUESTING;
+                break;
+            }
+
+#ifdef DHCP_CHATTER
+            diag_printf( "---------DHCPSTATE_REQUEST_RECV received:\n" );
+            diag_printf( "...rx_addr is family %d, addr %08x, port %d\n",
+                         rx_addr.sin_family,
+                         rx_addr.sin_addr.s_addr,
+                         rx_addr.sin_port );
+            show_bootp( intf, received );
+#endif            
+            if ( received->bp_xid != xid )   // not the same transaction;
+                break;                  // listen again...
+
+            if ( 0 == received->bp_siaddr.s_addr ) {
+                // then fill in from the options...
+                get_bootp_option( received, TAG_DHCP_SERVER_ID,
+                                  &received->bp_siaddr.s_addr );
+            }
+
+            // check it was a DHCP reply
+            if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype ) ) {
+                if ( DHCPACK == msgtype // Same offer & server?
+                     && received->bp_yiaddr.s_addr == xmit->bp_yiaddr.s_addr
+                     && received->bp_siaddr.s_addr == xmit->bp_siaddr.s_addr) {
+                    // Save the good packet in *xmit
+                    bcopy( received, xmit, dhcp_size(received) );
+                    // we like the packet, so reset the timeout for next time
+                    reset_timeout( &tv );
+                    // Record the new lease and set up timers &c
+                    new_lease( received, lease );
+                    *pstate = DHCPSTATE_BOUND;
+                    break;
+                }
+                if ( DHCPNAK == msgtype ) { // we're bounced!
+                    *pstate = DHCPSTATE_INIT;  // So back the start of the rigmarole.
+                    reset_timeout( &tv );
+                    break;
+                }
+                // otherwise it's something else, maybe another offer.
+                // Just listen again, which implicitly discards it.
+            }
+            break;
+
+        case DHCPSTATE_BOUND:
+
+            // We are happy now, we have our address.
+
+            // All done with socket
+            close(s);
+
+            // Re-initialize the interface with the new state
+            if ( DHCPSTATE_BOUND != oldstate ) {
+                // Then need to go down and up
+                do_dhcp_down_net( intf, res, &oldstate, lease ); // oldstate used
+                if ( 0 != oldstate ) {
+                    // Then not called from init_all_network_interfaces()
+                    // so we must initialize the interface ourselves
+                    if (!init_net(intf, res)) {
+                        do_dhcp_down_net( intf, res, pstate, lease );
+                        *pstate = DHCPSTATE_FAILED;
+                        return false;
+                    }
+                }
+            }
+
+            // Otherwise, nothing whatsoever to do...
+            return true;
+
+        case DHCPSTATE_RENEWING:
+            // Just send what you got with a DHCPREQUEST in the message
+            // type UNICAST straight to the server.  Then wait for an ACK.
+
+            // Fill in the BOOTP request - DHCPREQUEST packet
+            xmit->bp_op = BOOTREQUEST;
+
+            set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPREQUEST, 1 );
+            set_fixed_tag( xmit, TAG_DHCP_MAX_MSGSZ, BP_MINPKTSZ, 2 );
+
+            // And this will be a new one:
+            set_fixed_tag( xmit, TAG_DHCP_REQ_IP, ntohl(xmit->bp_yiaddr.s_addr), 4 );
+            
+            // Set unicast address to *server*
+            server_addr.sin_addr.s_addr = res->bp_siaddr.s_addr;
+
+#ifdef DHCP_CHATTER
+            diag_printf( "---------DHCPSTATE_RENEWING sending:\n" );
+            diag_printf( "UNICAST to family %d, addr %08x, port %d\n",
+                         server_addr.sin_family,
+                         server_addr.sin_addr.s_addr,
+                         server_addr.sin_port );
+            show_bootp( intf, xmit );
+#endif            
+            
+            if(sendto(s, xmit, dhcp_size(xmit), 0, 
+                       // UNICAST address of the server:
+                      (struct sockaddr *)&server_addr,
+                      sizeof(server_addr)) < 0) {
+                *pstate = DHCPSTATE_FAILED;
+                break;
+            }
+
+            *pstate = DHCPSTATE_RENEW_RECV;
+            break;
+
+        case DHCPSTATE_RENEW_RECV:
+            // wait for an ACK or a NACK - retry by going back to
+            // DHCPSTATE_RENEWING; NACK means go to NOTBOUND.
+
+            setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+
+            addrlen = sizeof(rx_addr);
+            if (recvfrom(s, received, sizeof(struct bootp), 0,
+                         (struct sockaddr *)&rx_addr, &addrlen) < 0) {
+                // No packet arrived
+                // go to the next larger timeout and re-send:
+                if ( ! next_timeout( &tv ) ) {
+                    reset_timeout( &tv );
+                    *pstate = DHCPSTATE_REBINDING;
+                    break;
+                }
+                *pstate = DHCPSTATE_RENEWING;
+                break;
+            }
+
+#ifdef DHCP_CHATTER
+            diag_printf( "---------DHCPSTATE_RENEW_RECV received:\n" );
+            diag_printf( "...rx_addr is family %d, addr %08x, port %d\n",
+                         rx_addr.sin_family,
+                         rx_addr.sin_addr.s_addr,
+                         rx_addr.sin_port );
+            show_bootp( intf, received );
+#endif            
+            if ( received->bp_xid != xid )   // not the same transaction;
+                break;                  // listen again...
+
+            if ( 0 == received->bp_siaddr.s_addr ) {
+                // then fill in from the options...
+                get_bootp_option( received, TAG_DHCP_SERVER_ID,
+                                  &received->bp_siaddr.s_addr );
+            }
+
+            // check it was a DHCP reply
+            if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype ) ) {
+                if ( DHCPACK == msgtype  // Same offer?
+                     && received->bp_yiaddr.s_addr == xmit->bp_yiaddr.s_addr) {
+                    // Save the good packet in *xmit
+                    bcopy( received, xmit, dhcp_size(received) );
+                    // we like the packet, so reset the timeout for next time
+                    reset_timeout( &tv );
+                    // Record the new lease and set up timers &c
+                    new_lease( received, lease );
+                    *pstate = DHCPSTATE_BOUND;
+                    break;
+                }
+                if ( DHCPNAK == msgtype ) { // we're bounced!
+                    *pstate = DHCPSTATE_NOTBOUND;  // So quit out.
+                    reset_timeout( &tv );
+                    break;
+                }
+                // otherwise it's something else, maybe another offer.
+                // Just listen again, which implicitly discards it.
+            }
+            break;
+
+        case DHCPSTATE_REBINDING:
+            // Just send what you got with a DHCPREQUEST in the message type.
+            // Then wait for an ACK.  This one is BROADCAST.
+
+            // Fill in the BOOTP request - DHCPREQUEST packet
+            xmit->bp_op = BOOTREQUEST;
+
+            set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPREQUEST, 1 );
+            set_fixed_tag( xmit, TAG_DHCP_MAX_MSGSZ, BP_MINPKTSZ, 2 );
+
+            // And this will be a new one:
+            set_fixed_tag( xmit, TAG_DHCP_REQ_IP, ntohl(xmit->bp_yiaddr.s_addr), 4 );
+            
+#ifdef DHCP_CHATTER
+            diag_printf( "---------DHCPSTATE_REBINDING sending:\n" );
+            show_bootp( intf, xmit );
+#endif            
+            if(sendto(s, xmit, dhcp_size(xmit), 0, 
+                      (struct sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) < 0) {
+                *pstate = DHCPSTATE_FAILED;
+                break;
+            }
+
+            *pstate = DHCPSTATE_REBIND_RECV;
+            break;
+
+        case DHCPSTATE_REBIND_RECV:
+            // wait for an ACK or a NACK - retry by going back to
+            // DHCPSTATE_REBINDING; NACK means go to NOTBOUND.
+
+            setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+
+            addrlen = sizeof(rx_addr);
+            if (recvfrom(s, received, sizeof(struct bootp), 0,
+                         (struct sockaddr *)&rx_addr, &addrlen) < 0) {
+                // No packet arrived
+                // go to the next larger timeout and re-send:
+                if ( ! next_timeout( &tv ) ) {
+                    reset_timeout( &tv );
+                    *pstate = DHCPSTATE_FAILED;
+                    break;
+                }
+                *pstate = DHCPSTATE_REBINDING;
+                break;
+            }
+
+#ifdef DHCP_CHATTER
+            diag_printf( "---------DHCPSTATE_REBIND_RECV received:\n" );
+            diag_printf( "...rx_addr is family %d, addr %08x, port %d\n",
+                         rx_addr.sin_family,
+                         rx_addr.sin_addr.s_addr,
+                         rx_addr.sin_port );
+            show_bootp( intf, received );
+#endif            
+            if ( received->bp_xid != xid )   // not the same transaction;
+                break;                  // listen again...
+
+            if ( 0 == received->bp_siaddr.s_addr ) {
+                // then fill in from the options...
+                get_bootp_option( received, TAG_DHCP_SERVER_ID,
+                                  &received->bp_siaddr.s_addr );
+            }
+
+            // check it was a DHCP reply
+            if ( get_bootp_option( received, TAG_DHCP_MESS_TYPE, &msgtype ) ) {
+                if ( DHCPACK == msgtype  // Same offer?
+                     && received->bp_yiaddr.s_addr == xmit->bp_yiaddr.s_addr) {
+                    // Save the good packet in *xmit
+                    bcopy( received, xmit, dhcp_size(received) );
+                    // we like the packet, so reset the timeout for next time
+                    reset_timeout( &tv );
+                    // Record the new lease and set up timers &c
+                    new_lease( received, lease );
+                    *pstate = DHCPSTATE_BOUND;
+                    break;
+                }
+                else if ( DHCPNAK == msgtype ) { // we're bounced!
+                    *pstate = DHCPSTATE_NOTBOUND;  // So back the start of the rigmarole.
+                    reset_timeout( &tv );
+                    break;
+                }
+                // otherwise it's something else, maybe another offer.
+                // Just listen again, which implicitly discards it.
+            }
+            break;
+
+        case DHCPSTATE_BOOTP_FALLBACK:
+            // All done with socket
+            close(s);
+            // And no lease should have become active, but JIC
+            no_lease( lease );
+            // Re-initialize the interface with the new state
+            if ( DHCPSTATE_BOOTP_FALLBACK != oldstate ) {
+                // Then need to go down and up
+                do_dhcp_down_net( intf, res, &oldstate, lease ); // oldstate used
+                if ( 0 != oldstate ) {
+                    // Then not called from init_all_network_interfaces()
+                    // so we must initialize the interface ourselves
+                    if (!init_net(intf, res)) {
+                        do_dhcp_down_net( intf, res, pstate, lease );
+                        *pstate = DHCPSTATE_FAILED;
+                        return false;
+                    }
+                }
+            }
+
+            // Otherwise, nothing whatsoever to do...
+            return true;
+
+        case DHCPSTATE_NOTBOUND:
+            // All done with socket
+            close(s);
+            // No lease active
+            no_lease( lease );
+            // Leave interface up so app can tidy.
+            return false;
+
+        case DHCPSTATE_FAILED:
+            // All done with socket
+            close(s);
+            // No lease active
+            no_lease( lease );
+            // Unconditionally down the interface.
+            do_dhcp_down_net( intf, res, &oldstate, lease );
+            return false;
+
+        case DHCPSTATE_DO_RELEASE:
+            // We have been forced here by external means, to release the
+            // lease for graceful shutdown.
+
+            // Just send what you got with a DHCPRELEASE in the message
+            // type UNICAST straight to the server.  No ACK.  Then go to
+            // NOTBOUND state.
+
+            xmit->bp_op = BOOTREQUEST;
+            set_fixed_tag( xmit, TAG_DHCP_MESS_TYPE, DHCPRELEASE, 1 );
+
+            // Set unicast address to *server*
+            server_addr.sin_addr.s_addr = res->bp_siaddr.s_addr;
+
+#ifdef DHCP_CHATTER
+            diag_printf( "---------DHCPSTATE_DO_RELEASE sending:\n" );
+            diag_printf( "UNICAST to family %d, addr %08x, port %d\n",
+                         server_addr.sin_family,
+                         server_addr.sin_addr.s_addr,
+                         server_addr.sin_port );
+            show_bootp( intf, xmit );
+#endif            
+            if(sendto(s, xmit, dhcp_size(xmit), 0, 
+                       // UNICAST address of the server:
+                      (struct sockaddr *)&server_addr,
+                      sizeof(server_addr)) < 0) {
+                *pstate = DHCPSTATE_FAILED;
+                break;
+            }
+
+            *pstate = DHCPSTATE_NOTBOUND;
+            break;
+
+        default:
+            no_lease( lease );
+            close(s);
+            return false;
+        }
+    }
+    /* NOTREACHED */
+    return false;
+}
+
+// ------------------------------------------------------------------------
+// Bring an interface down, failed to initialize it or lease is expired
+// Also part of normal startup, bring down for proper reinitialization
+
+int
+do_dhcp_down_net(const char *intf, struct bootp *res,
+        cyg_uint8 *pstate, struct dhcp_lease *lease)
+{
+    struct sockaddr_in *addrp;
+    struct ifreq ifr;
+    int s;
+
+    // Ensure clean slate
+    route_reinit();  // Force any existing routes to be forgotten
+
+    s = socket(AF_INET, SOCK_DGRAM, 0);
+    if (s < 0) {
+        perror("socket");
+        return false;
+    }
+
+    addrp = (struct sockaddr_in *) &ifr.ifr_addr;
+
+    // Remove any existing address
+    if ( DHCPSTATE_FAILED  == *pstate
+         || DHCPSTATE_INIT == *pstate
+         || 0              == *pstate ) {
+        // it was configured for broadcast only, "half-up"
+        memset(addrp, 0, sizeof(*addrp));
+        addrp->sin_family = AF_INET;
+        addrp->sin_len = sizeof(*addrp);
+        addrp->sin_port = 0;
+        addrp->sin_addr.s_addr = INADDR_ANY;
+    }
+    else {
+        // get the specific address that was used
+        strcpy(ifr.ifr_name, intf);
+        if (ioctl(s, SIOCGIFADDR, &ifr)) {
+            perror("SIOCGIFADDR 1");
+            return false;
+        }
+    }
+
+    strcpy(ifr.ifr_name, intf);
+    if (ioctl(s, SIOCDIFADDR, &ifr)) { /* delete IF addr */
+        perror("SIOCDIFADDR1");
+    }
+
+    // Shut down interface so it can be reinitialized
+    ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
+    if (ioctl(s, SIOCSIFFLAGS, &ifr)) { /* set ifnet flags */
+        perror("SIOCSIFFLAGS down");
+        return false;
+    }
+
+    // All done with socket
+    close(s);
+
+    if ( 0 != *pstate ) // preserve initial state
+        *pstate = DHCPSTATE_INIT;
+
+    return true;
+}
+
+// ------------------------------------------------------------------------
+// Release (relinquish) a leased address - if we have one - and bring down
+// the interface.
+int
+do_dhcp_release(const char *intf, struct bootp *res,
+        cyg_uint8 *pstate, struct dhcp_lease *lease)
+{
+    if ( 0                           != *pstate
+         && DHCPSTATE_INIT           != *pstate
+         && DHCPSTATE_NOTBOUND       != *pstate
+         && DHCPSTATE_FAILED         != *pstate
+         && DHCPSTATE_BOOTP_FALLBACK != *pstate ) {
+        *pstate = DHCPSTATE_DO_RELEASE;
+        do_dhcp( intf, res, pstate, lease ); // to send the release packet
+        cyg_thread_delay( 100 );             // to let it leave the building
+    }
+    return true;
+}
+
+// ------------------------------------------------------------------------
+
+#endif // CYGPKG_NET_DHCP
+
+// EOF dhcp_prot.c
new file mode 100644
--- /dev/null
+++ b/packages/net/tcpip/current/src/lib/dhcp_support.c
@@ -0,0 +1,235 @@
+/*==========================================================================
+//
+//      dhcp_support.c
+//
+//      Support code == friendly API for DHCP client
+//
+//==========================================================================
+//####COPYRIGHTBEGIN####
+//                                                                          
+// -------------------------------------------                              
+// The contents of this file are subject to the Red Hat eCos Public License 
+// Version 1.1 (the "License"); you may not use this file except in         
+// compliance with the License.  You may obtain a copy of the License at    
+// http://www.redhat.com/                                                   
+//                                                                          
+// 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 Configurable Operating System,      
+// released September 30, 1998.                                             
+//                                                                          
+// The Initial Developer of the Original Code is Red Hat.                   
+// Portions created by Red Hat are                                          
+// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.                             
+// All Rights Reserved.                                                     
+// -------------------------------------------                              
+//                                                                          
+//####COPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):   hmt
+// Contributors: gthomas
+// Date:        2000-07-01
+// Purpose:     DHCP support
+// Description: 
+//
+//####DESCRIPTIONEND####
+//
+//========================================================================*/
+
+#include <pkgconf/system.h>
+#include <pkgconf/net.h>
+
+#ifdef CYGPKG_NET_DHCP
+
+#include <network.h>
+#include <dhcp.h>
+
+// ---------------------------------------------------------------------------
+#ifdef CYGHWR_NET_DRIVER_ETH0
+cyg_uint8   eth0_dhcpstate = 0;
+#endif
+#ifdef CYGHWR_NET_DRIVER_ETH1
+cyg_uint8   eth1_dhcpstate = 0;
+#endif
+
+cyg_sem_t dhcp_needs_attention;
+
+#ifdef CYGHWR_NET_DRIVER_ETH0
+struct dhcp_lease eth0_lease = { 0,0,0,0 };
+#endif
+#ifdef CYGHWR_NET_DRIVER_ETH1
+struct dhcp_lease eth1_lease = { 0,0,0,0 };
+#endif
+
+// ---------------------------------------------------------------------------
+//
+// The point of this module is to deal with all the horrid written out in
+// full stuff of having two interfaces; it's ugly but it's also most
+// flexible.  The dhcp_prot.c module should do all the work... 
+//
+// ---------------------------------------------------------------------------
+
+// return value: 1 => everything OK, no change.
+// 0 => close your connections, then call do_dhcp_halt() to halt the
+// interface(s) in question (it knows because the state will be NOTBOUND).
+// After that you can return to the start and use
+// init_all_network_interfaces(); as usual, or call do_dhcp_bind() by hand,
+// or whatever...
+int dhcp_bind( void )
+{
+#ifdef CYGHWR_NET_DRIVER_ETH0
+    cyg_uint8 old_eth0_dhcpstate = eth0_dhcpstate;
+#endif
+#ifdef CYGHWR_NET_DRIVER_ETH1
+    cyg_uint8 old_eth1_dhcpstate = eth1_dhcpstate;
+#endif
+
+    // If there are no interfaces at all, init it every time, doesn't
+    // matter.
+    if ( 1
+#ifdef CYGHWR_NET_DRIVER_ETH0
+         && eth0_dhcpstate == 0
+#endif
+#ifdef CYGHWR_NET_DRIVER_ETH1
+         && eth1_dhcpstate == 0
+#endif
+        )
+        cyg_semaphore_init( &dhcp_needs_attention, 0 );
+
+    // Run the state machine...
+#ifdef CYGHWR_NET_DRIVER_ETH0
+    if (eth0_up
+        && DHCPSTATE_FAILED != eth0_dhcpstate )
+            eth0_up = do_dhcp(eth0_name, &eth0_bootp_data, &eth0_dhcpstate, &eth0_lease);
+#endif            
+#ifdef CYGHWR_NET_DRIVER_ETH0
+    if (eth1_up
+        && DHCPSTATE_FAILED != eth1_dhcpstate )
+            eth1_up = do_dhcp(eth1_name, &eth1_bootp_data, &eth1_dhcpstate, &eth1_lease);
+#endif            
+
+    // If the interface newly came up, initialize it:
+    // (this duplicates the code in init_all_network_interfaces() really).
+#ifdef CYGHWR_NET_DRIVER_ETH0
+    if ( eth0_up
+         && eth0_dhcpstate == DHCPSTATE_BOUND
+         && old_eth0_dhcpstate != eth0_dhcpstate ) {
+        if (!init_net(eth0_name, &eth0_bootp_data)) {
+            eth0_up = false;
+        }
+    }
+#endif
+#ifdef CYGHWR_NET_DRIVER_ETH1
+    if ( eth1_up
+         && eth1_dhcpstate == DHCPSTATE_BOUND
+         && old_eth1_dhcpstate != eth1_dhcpstate ) {
+        if (!init_net(eth1_name, &eth1_bootp_data)) {
+            eth1_up = false;
+        }
+    }
+#endif
+
+#ifdef CYGHWR_NET_DRIVER_ETH0
+    if ( old_eth0_dhcpstate == DHCPSTATE_BOUND &&
+         eth0_dhcpstate == DHCPSTATE_NOTBOUND )
+        return 0; // a lease timed out; we became unbound
+#endif
+#ifdef CYGHWR_NET_DRIVER_ETH0
+    if ( old_eth1_dhcpstate == DHCPSTATE_BOUND &&
+         eth1_dhcpstate == DHCPSTATE_NOTBOUND )
+        return 0; // a lease timed out; we became unbound
+#endif
+    return 1; // all is well
+}
+
+
+// Shutdown any interface whose state is DHCPSTATE_NOTBOUND.
+int dhcp_halt( void )
+{
+#ifdef CYGHWR_NET_DRIVER_ETH0
+    if ( eth0_up
+         && eth0_dhcpstate != DHCPSTATE_FAILED ) {
+        do_dhcp_down_net(eth0_name, &eth0_bootp_data, &eth0_dhcpstate, &eth0_lease);
+    }
+    eth0_up = false;
+#endif
+#ifdef CYGHWR_NET_DRIVER_ETH1
+    if ( eth1_up
+         && eth1_dhcpstate != DHCPSTATE_FAILED ) {
+        do_dhcp_down_net(eth1_name, &eth1_bootp_data, &eth1_dhcpstate, &eth1_lease);
+    }
+    eth1_up = false;
+#endif
+}
+
+
+// Release (and set state to DHCPSTATE_NOTBOUND) all interfaces - we are
+// closing down.  (unlikely but maybe useful for testing)
+int dhcp_release( void )
+{
+#ifdef CYGHWR_NET_DRIVER_ETH0
+    if (eth0_up)
+        do_dhcp_release(eth0_name, &eth0_bootp_data, &eth0_dhcpstate, &eth0_lease);
+#endif
+#ifdef CYGHWR_NET_DRIVER_ETH1
+    if (eth1_up)
+        do_dhcp_release(eth1_name, &eth1_bootp_data, &eth1_dhcpstate, &eth1_lease);
+#endif
+}
+
+
+// ------------------------------------------------------------------------
+// The management thread function
+void dhcp_mgt_entry( cyg_addrword_t loop_on_failure )
+{
+    while ( 1 ) {
+        while ( 1 ) {
+            cyg_semaphore_wait( &dhcp_needs_attention );
+            if ( ! dhcp_bind() ) // a lease expired
+                break; // If we need to re-bind
+        }
+        dhcp_halt(); // tear everything down
+        if ( loop_on_failure )
+            init_all_network_interfaces(); // re-initialize
+        else
+            return; // exit the thread/return
+    }
+}
+
+#ifdef CYGOPT_NET_DHCP_DHCP_THREAD
+// Then we provide such a thread...
+cyg_handle_t dhcp_mgt_thread_h = 0;
+cyg_thread   dhcp_mgt_thread;
+
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + sizeof(struct bootp))
+static cyg_uint8 dhcp_mgt_stack[ STACK_SIZE ];
+
+void dhcp_start_dhcp_mgt_thread( void )
+{
+    if ( ! dhcp_mgt_thread_h ) {
+        cyg_thread_create(
+            CYGPKG_NET_THREAD_PRIORITY+1, /* scheduling info (eg pri) */
+            dhcp_mgt_entry,             /* entry point function */
+            CYGOPT_NET_DHCP_DHCP_THREAD_PARAM, /* entry data */
+            "DHCP lease mgt",           /* optional thread name */
+            dhcp_mgt_stack,             /* stack base, NULL = alloc */
+            STACK_SIZE,                 /* stack size, 0 = default */
+            &dhcp_mgt_thread_h,         /* returned thread handle */
+            &dhcp_mgt_thread           /* put thread here */
+            );
+
+        cyg_thread_resume(dhcp_mgt_thread_h);
+    }
+}
+
+
+#endif // CYGOPT_NET_DHCP_DHCP_THREAD
+
+#endif // CYGPKG_NET_DHCP
+
+// EOF dhcp_support.c
--- a/packages/net/tcpip/current/src/lib/network_support.c
+++ b/packages/net/tcpip/current/src/lib/network_support.c
@@ -76,6 +76,12 @@
 #include <network.h>
 #include <arpa/inet.h>
 
+#include <eth_drv.h>
+
+#ifdef CYGPKG_NET_DHCP
+#include <dhcp.h>
+#endif
+
 #ifdef CYGHWR_NET_DRIVER_ETH0
 struct bootp eth0_bootp_data;
 cyg_bool_t   eth0_up = false;
@@ -181,8 +187,6 @@ cyg_bool_t init_loopback_interface(int l
 #endif
 
 
-#if defined(CYGHWR_NET_DRIVER_ETH0_ADDRS_IP) \
- || defined(CYGHWR_NET_DRIVER_ETH1_ADDRS_IP)
 //
 // Internal function which builds up a fake BOOTP database for
 // an interface.
@@ -204,7 +208,7 @@ add_tag(unsigned char *vp,
     return vp;
 }
 
-static void
+void
 build_bootp_record(struct bootp *bp,
                    const char *addrs_ip,
                    const char *addrs_netmask,
@@ -235,9 +239,11 @@ build_bootp_record(struct bootp *bp,
     vp = add_tag(vp, TAG_SUBNET_MASK, &addr, sizeof(in_addr_t));
     addr = inet_addr(addrs_broadcast);
     vp = add_tag(vp, TAG_IP_BROADCAST, &addr, sizeof(in_addr_t));
+    addr = inet_addr(addrs_gateway);
+    vp = add_tag(vp, TAG_GATEWAY, &addr, sizeof(in_addr_t));
     *vp = TAG_END;
 }
-#endif
+
 
 //
 // Initialize network interface[s] using BOOTP/DHCP
@@ -262,12 +268,22 @@ init_all_network_interfaces(void)
 #ifdef CYGHWR_NET_DRIVER_ETH0_BOOTP
         // Perform a complete initialization, using BOOTP/DHCP
         eth0_up = true;
-        if (do_bootp(eth0_name, &eth0_bootp_data)) {
+#ifdef CYGHWR_NET_DRIVER_ETH0_DHCP
+        eth0_dhcpstate = 0; // Says that initialization is external to dhcp
+        if (do_dhcp(eth0_name, &eth0_bootp_data, &eth0_dhcpstate, &eth0_lease)) 
+#else
+#ifdef CYGPKG_NET_DHCP
+        eth0_dhcpstate = DHCPSTATE_BOOTP_FALLBACK;
+        // so the dhcp machine does no harm if called
+#endif
+        if (do_bootp(eth0_name, &eth0_bootp_data)) 
+#endif
+        {
 #ifdef CYGHWR_NET_DRIVER_ETH0_BOOTP_SHOW
             show_bootp(eth0_name, &eth0_bootp_data);
 #endif
         } else {
-            diag_printf("BOOTP failed on eth0\n");
+            diag_printf("BOOTP/DHCP failed on eth0\n");
             eth0_up = false;
         }
 #elif defined(CYGHWR_NET_DRIVER_ETH0_ADDRS_IP)
@@ -287,12 +303,22 @@ init_all_network_interfaces(void)
 #ifdef CYGHWR_NET_DRIVER_ETH1_BOOTP
         // Perform a complete initialization, using BOOTP/DHCP
         eth1_up = true;
-        if (do_bootp(eth1_name, &eth1_bootp_data)) {
+#ifdef CYGHWR_NET_DRIVER_ETH1_DHCP
+        eth1_dhcpstate = 0; // Says that initialization is external to dhcp
+        if (do_dhcp(eth1_name, &eth1_bootp_data, &eth1_dhcpstate, &eth1_lease)) 
+#else
+#ifdef CYGPKG_NET_DHCP
+        eth1_dhcpstate = DHCPSTATE_BOOTP_FALLBACK;
+        // so the dhcp machine does no harm if called
+#endif
+        if (do_bootp(eth1_name, &eth1_bootp_data))
+#endif
+        {
 #ifdef CYGHWR_NET_DRIVER_ETH1_BOOTP_SHOW
             show_bootp(eth1_name, &eth1_bootp_data);
 #endif
         } else {
-            diag_printf("BOOTP failed on eth1\n");
+            diag_printf("BOOTP/DHCP failed on eth1\n");
             eth1_up = false;
         }
 #elif defined(CYGHWR_NET_DRIVER_ETH1_ADDRS_IP)
@@ -340,6 +366,13 @@ init_all_network_interfaces(void)
 #endif
 #endif
 
+#ifdef CYGOPT_NET_DHCP_DHCP_THREAD
+    dhcp_start_dhcp_mgt_thread();
+#endif
+
     // Open the monitor to other threads.
     in_init_all_network_interfaces = 0;
+
 }
+
+// EOF network_support.c
--- a/packages/net/tcpip/current/src/sys/net/if.c
+++ b/packages/net/tcpip/current/src/sys/net/if.c
@@ -311,6 +311,10 @@ void
 if_attach(ifp)
 	struct ifnet *ifp;
 {
+// Initialize queue - moved here to support "late" attaches
+    if (ifp->if_snd.ifq_maxlen == 0)
+        ifp->if_snd.ifq_maxlen = ifqmaxlen;
+//
 	if (if_index == 0)
 		TAILQ_INIT(&ifnet);
 	TAILQ_INIT(&ifp->if_addrlist);
new file mode 100644
--- /dev/null
+++ b/packages/net/tcpip/current/tests/dhcp_test.c
@@ -0,0 +1,341 @@
+//==========================================================================
+//
+//      tests/dhcp_test.c
+//
+//      Simple test of DHCP (ICMP) and networking support
+//
+//==========================================================================
+//####COPYRIGHTBEGIN####
+//                                                                          
+// -------------------------------------------                              
+// The contents of this file are subject to the Red Hat eCos Public License 
+// Version 1.1 (the "License"); you may not use this file except in         
+// compliance with the License.  You may obtain a copy of the License at    
+// http://www.redhat.com/                                                   
+//                                                                          
+// 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 Configurable Operating System,      
+// released September 30, 1998.                                             
+//                                                                          
+// The Initial Developer of the Original Code is Red Hat.                   
+// Portions created by Red Hat are                                          
+// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.                             
+// All Rights Reserved.                                                     
+// -------------------------------------------                              
+//                                                                          
+//####COPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD or other sources,
+// and are covered by the appropriate copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    gthomas
+// Contributors: gthomas
+// Date:         2000-01-10
+// Purpose:      
+// Description:  
+//              
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// DHCP test code
+
+#include <network.h>
+
+#include <pkgconf/system.h>
+#include <pkgconf/net.h>
+
+#include <dhcp.h>
+
+#include <cyg/infra/testcase.h>
+
+#ifdef CYGBLD_DEVS_ETH_DEVICE_H    // Get the device config if it exists
+#include CYGBLD_DEVS_ETH_DEVICE_H  // May provide CYGTST_DEVS_ETH_TEST_NET_REALTIME
+#endif
+
+#ifdef CYGPKG_NET_TESTS_USE_RT_TEST_HARNESS // do we use the rt test?
+# ifdef CYGTST_DEVS_ETH_TEST_NET_REALTIME // Get the test ancilla if it exists
+#  include CYGTST_DEVS_ETH_TEST_NET_REALTIME
+# endif
+#endif
+
+// Fill in the blanks if necessary
+#ifndef TNR_OFF
+# define TNR_OFF()
+#endif
+#ifndef TNR_ON
+# define TNR_ON()
+#endif
+#ifndef TNR_INIT
+# define TNR_INIT()
+#endif
+#ifndef TNR_PRINT_ACTIVITY
+# define TNR_PRINT_ACTIVITY()
+#endif
+
+
+
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
+static char stack[STACK_SIZE];
+static cyg_thread thread_data;
+static cyg_handle_t thread_handle;
+
+#define NUM_PINGS 16
+#define MAX_PACKET 4096
+#define MIN_PACKET   64
+#define MAX_SEND   4000
+
+#define PACKET_ADD  ((MAX_SEND - MIN_PACKET)/NUM_PINGS)
+#define nPACKET_ADD  1 
+
+static unsigned char pkt1[MAX_PACKET], pkt2[MAX_PACKET];
+
+#define UNIQUEID 0x1234
+
+void
+pexit(char *s)
+{
+    CYG_TEST_FAIL_FINISH(s);
+}
+
+// Compute INET checksum
+int
+inet_cksum(u_short *addr, int len)
+{
+    register int nleft = len;
+    register u_short *w = addr;
+    register u_short answer;
+    register u_int sum = 0;
+    u_short odd_byte = 0;
+
+    /*
+     *  Our algorithm is simple, using a 32 bit accumulator (sum),
+     *  we add sequential 16 bit words to it, and at the end, fold
+     *  back all the carry bits from the top 16 bits into the lower
+     *  16 bits.
+     */
+    while( nleft > 1 )  {
+        sum += *w++;
+        nleft -= 2;
+    }
+
+    /* mop up an odd byte, if necessary */
+    if( nleft == 1 ) {
+        *(u_char *)(&odd_byte) = *(u_char *)w;
+        sum += odd_byte;
+    }
+
+    /*
+     * add back carry outs from top 16 bits to low 16 bits
+     */
+    sum = (sum >> 16) + (sum & 0x0000ffff); /* add hi 16 to low 16 */
+    sum += (sum >> 16);                     /* add carry */
+    answer = ~sum;                          /* truncate to 16 bits */
+    return (answer);
+}
+
+static int
+show_icmp(unsigned char *pkt, int len, 
+          struct sockaddr_in *from, struct sockaddr_in *to)
+{
+    cyg_tick_count_t *tp, tv;
+    struct ip *ip;
+    struct icmp *icmp;
+    tv = cyg_current_time();
+    ip = (struct ip *)pkt;
+    if ((len < sizeof(*ip)) || ip->ip_v != IPVERSION) {
+        diag_printf("%s: Short packet or not IP! - Len: %d, Version: %d\n", 
+                    inet_ntoa(from->sin_addr), len, ip->ip_v);
+        return 0;
+    }
+    icmp = (struct icmp *)(pkt + sizeof(*ip));
+    len -= (sizeof(*ip) + 8);
+    tp = (cyg_tick_count_t *)&icmp->icmp_data;
+    if (icmp->icmp_type != ICMP_ECHOREPLY) {
+        diag_printf("%s: Invalid ICMP - type: %d\n", 
+                    inet_ntoa(from->sin_addr), icmp->icmp_type);
+        return 0;
+    }
+    if (icmp->icmp_id != UNIQUEID) {
+        diag_printf("%s: ICMP received for wrong id - sent: %x, recvd: %x\n", 
+                    inet_ntoa(from->sin_addr), UNIQUEID, icmp->icmp_id);
+    }
+    diag_printf("%d bytes from %s: ", len, inet_ntoa(from->sin_addr));
+    diag_printf("icmp_seq=%d", icmp->icmp_seq);
+    diag_printf(", time=%dms\n", (int)(tv - *tp)*10);
+    return (from->sin_addr.s_addr == to->sin_addr.s_addr);
+}
+
+static void
+ping_host(int s, struct sockaddr_in *host)
+{
+    struct icmp *icmp = (struct icmp *)pkt1;
+    int icmp_len = MIN_PACKET;
+    int seq, ok_recv, bogus_recv;
+    cyg_tick_count_t *tp;
+    long *dp;
+    struct sockaddr_in from;
+    int i, len, fromlen;
+
+    ok_recv = 0;
+    bogus_recv = 0;
+    diag_printf("PING server %s\n", inet_ntoa(host->sin_addr));
+    for (seq = 0;  seq < NUM_PINGS;  seq++, icmp_len += PACKET_ADD ) {
+        TNR_ON();
+        // Build ICMP packet
+        icmp->icmp_type = ICMP_ECHO;
+        icmp->icmp_code = 0;
+        icmp->icmp_cksum = 0;
+        icmp->icmp_seq = seq;
+        icmp->icmp_id = 0x1234;
+        // Set up ping data
+        tp = (cyg_tick_count_t *)&icmp->icmp_data;
+        *tp++ = cyg_current_time();
+        dp = (long *)tp;
+        for (i = sizeof(*tp);  i < icmp_len;  i += sizeof(*dp)) {
+            *dp++ = i;
+        }
+        // Add checksum
+        icmp->icmp_cksum = inet_cksum( (u_short *)icmp, icmp_len+8);
+        // Send it off
+        if (sendto(s, icmp, icmp_len+8, 0, (struct sockaddr *)host, sizeof(*host)) < 0) {
+            TNR_OFF();
+            perror("sendto");
+            continue;
+        }
+        // Wait for a response
+        fromlen = sizeof(from);
+        len = recvfrom(s, pkt2, sizeof(pkt2), 0, (struct sockaddr *)&from, &fromlen);
+        TNR_OFF();
+        if (len < 0) {
+            perror("recvfrom");
+            seq+=4;
+        } else {
+            if (show_icmp(pkt2, len, &from, host)) {
+                ok_recv++;
+            } else {
+                bogus_recv++;
+            }
+        }
+    }
+    TNR_OFF();
+}
+
+static void
+ping_test(struct bootp *bp)
+{
+    struct protoent *p;
+    struct timeval tv;
+    struct sockaddr_in host;
+    int s;
+
+    if ((p = getprotobyname("icmp")) == (struct protoent *)0) {
+        pexit("getprotobyname");
+        return;
+    }
+    s = socket(AF_INET, SOCK_RAW, p->p_proto);
+    if (s < 0) {
+        pexit("socket");
+        return;
+    }
+    tv.tv_sec = 1;
+    tv.tv_usec = 0;
+    setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+    // Set up host address
+    host.sin_family = AF_INET;
+    host.sin_addr = bp->bp_siaddr;
+    host.sin_port = 0;
+    ping_host(s, &host);
+    // Now try a bogus host
+    host.sin_addr.s_addr = htonl(ntohl(host.sin_addr.s_addr) + 32);
+    ping_host(s, &host);
+    close(s);
+}
+
+void
+net_test(cyg_addrword_t p)
+{
+#ifndef CYGPKG_NET_DHCP
+    CYG_TEST_NA_FINISH( "DHCP is not enabled" );
+#else
+    int i;
+    diag_printf("Start DHCP test\n");
+    TNR_INIT();
+    init_all_network_interfaces();
+
+    for ( i = 10; i > 0; i-- ) {
+#ifdef CYGHWR_NET_DRIVER_ETH0
+        if (eth0_up) {
+            ping_test(&eth0_bootp_data);
+        }
+#endif
+        // Now do the DHCP renewal ritual...
+        if ( cyg_semaphore_trywait( &dhcp_needs_attention )) {
+            if ( ! dhcp_bind() ) {
+                // All done
+                dhcp_halt();
+                CYG_TEST_FAIL_FINISH( "Rebind after lease failed");
+                break;
+            }
+        }
+#ifdef CYGHWR_NET_DRIVER_ETH1
+        if (eth1_up) {
+            ping_test(&eth1_bootp_data);
+        }
+#endif
+
+#ifndef CYGOPT_NET_DHCP_DHCP_THREAD
+        // Now do the DHCP renewal ritual...
+        if ( cyg_semaphore_trywait( &dhcp_needs_attention )) {
+            if ( ! dhcp_bind() ) {
+                // All done
+                dhcp_halt();
+                CYG_TEST_FAIL_FINISH( "Rebind after lease failed");
+                break;
+            }
+        }
+#endif // not CYGOPT_NET_DHCP_DHCP_THREAD 
+
+        if ( 1 == (i & 3) ) {
+            dhcp_release();             // relinquish leases
+            dhcp_halt();
+            init_all_network_interfaces();
+        }
+    }
+    dhcp_release();
+
+    TNR_PRINT_ACTIVITY();
+    CYG_TEST_PASS_FINISH("Dhcp test OK");
+#endif
+}
+
+void
+cyg_start(void)
+{
+    // Create a main thread, so we can run the scheduler and have time 'pass'
+    cyg_thread_create(10,                // Priority - just a number
+                      net_test,          // entry
+                      0,                 // entry parameter
+                      "Network test",    // Name
+                      &stack[0],         // Stack
+                      STACK_SIZE,        // Size
+                      &thread_handle,    // Handle
+                      &thread_data       // Thread data structure
+            );
+    cyg_thread_resume(thread_handle);  // Start it
+    cyg_scheduler_start();
+}
--- a/packages/net/tcpip/current/tests/flood.c
+++ b/packages/net/tcpip/current/tests/flood.c
@@ -88,7 +88,7 @@
 #define MAX_PACKET 4096
 
 #define NUMTHREADS 3
-#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + MAX_PACKET + MAX_PACKET)
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + MAX_PACKET + MAX_PACKET + 0x1000)
 static char thread_stack[NUMTHREADS][STACK_SIZE];
 static cyg_thread thread_data[NUMTHREADS];
 static cyg_handle_t thread_handle[NUMTHREADS];
--- a/packages/net/tcpip/current/tests/ftp_test.c
+++ b/packages/net/tcpip/current/tests/ftp_test.c
@@ -55,7 +55,7 @@
 
 #include <network.h>
 
-#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
 static char stack[STACK_SIZE];
 static cyg_thread thread_data;
 static cyg_handle_t thread_handle;
--- a/packages/net/tcpip/current/tests/nc_test_master.c
+++ b/packages/net/tcpip/current/tests/nc_test_master.c
@@ -57,7 +57,7 @@
 #include "nc_test_framework.h"
 
 #ifdef __ECOS
-#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
 static char stack[STACK_SIZE];
 static cyg_thread thread_data;
 static cyg_handle_t thread_handle;
--- a/packages/net/tcpip/current/tests/nc_test_slave.c
+++ b/packages/net/tcpip/current/tests/nc_test_slave.c
@@ -58,7 +58,7 @@
 #include <math.h>
 
 #ifdef __ECOS
-#define STACK_SIZE               CYGNUM_HAL_STACK_SIZE_TYPICAL
+#define STACK_SIZE               (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
 #define MAX_LOAD_THREAD_LEVEL    20
 #define MIN_LOAD_THREAD_LEVEL    0
 #define NUM_LOAD_THREADS         10
--- a/packages/net/tcpip/current/tests/ping_lo_test.c
+++ b/packages/net/tcpip/current/tests/ping_lo_test.c
@@ -58,7 +58,7 @@
 
 #include <cyg/infra/testcase.h>
 
-#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
 static char stack[STACK_SIZE];
 static cyg_thread thread_data;
 static cyg_handle_t thread_handle;
--- a/packages/net/tcpip/current/tests/ping_test.c
+++ b/packages/net/tcpip/current/tests/ping_test.c
@@ -87,7 +87,7 @@
 
 
 
-#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
 static char stack[STACK_SIZE];
 static cyg_thread thread_data;
 static cyg_handle_t thread_handle;
--- a/packages/net/tcpip/current/tests/server_test.c
+++ b/packages/net/tcpip/current/tests/server_test.c
@@ -55,7 +55,7 @@
 #include <stdio.h>
 #include <network.h>
 
-#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
 static char stack[STACK_SIZE];
 static cyg_thread thread_data;
 static cyg_handle_t thread_handle;
--- a/packages/net/tcpip/current/tests/set_mac_address.c
+++ b/packages/net/tcpip/current/tests/set_mac_address.c
@@ -66,7 +66,7 @@
 #include <netinet/if_ether.h>
 
 #define NUMTHREADS 1
-#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL)
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
 static char thread_stack[NUMTHREADS][STACK_SIZE];
 static cyg_thread thread_data[NUMTHREADS];
 static cyg_handle_t thread_handle[NUMTHREADS];
--- a/packages/net/tcpip/current/tests/tcp_echo.c
+++ b/packages/net/tcpip/current/tests/tcp_echo.c
@@ -108,7 +108,7 @@ struct test_status {
     long ok;
 };
 
-#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
 static char stack[STACK_SIZE];
 static cyg_thread thread_data;
 static cyg_handle_t thread_handle;
--- a/packages/net/tcpip/current/tests/tftp_client_test.c
+++ b/packages/net/tcpip/current/tests/tftp_client_test.c
@@ -58,7 +58,7 @@
 
 // Note: the TFTP client calls need at least (SEGSIZE==512)+4
 // additional bytes of workspace, thus the padding.
-#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL+1024)
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL+0x1000)
 static char stack[STACK_SIZE];
 static cyg_thread thread_data;
 static cyg_handle_t thread_handle;
--- a/packages/net/tcpip/current/tests/tftp_server_test.c
+++ b/packages/net/tcpip/current/tests/tftp_server_test.c
@@ -86,7 +86,7 @@
 #include <network.h>
 #include <tftp_support.h>
 
-#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
 static char stack[STACK_SIZE];
 static cyg_thread thread_data;
 static cyg_handle_t thread_handle;