diff packages/redboot/current/src/net/net_io.c @ 115:6ed91473a1cd ecos-sw-2000-08-21

Merge from eCos master repository on 2000-08-21-22:40:54-BST
author jlarmour
date Fri, 25 Aug 2000 17:32:38 +0000
parents
children bd1a71e3e476
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/packages/redboot/current/src/net/net_io.c
@@ -0,0 +1,496 @@
+//==========================================================================
+//
+//      net/net_io.c
+//
+//      Stand-alone network logical I/O support for RedBoot
+//
+//==========================================================================
+//####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:         2000-07-14
+// Purpose:      
+// Description:  
+//              
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <net/net.h>
+#include <cyg/hal/hal_misc.h>   // Helper functions
+#include <cyg/hal/hal_if.h>     // HAL I/O interfaces
+
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+#include <flash_config.h>
+
+RedBoot_config_option("GDB connection port",
+                      gdb_port,
+                      ALWAYS_ENABLED, true,
+                      CONFIG_INT
+    );
+RedBoot_config_option("Network debug at boot time", 
+                      net_debug, 
+                      ALWAYS_ENABLED, true,
+                      CONFIG_BOOL
+    );
+// Note: the following options are related.  If 'bootp' is false, then
+// the other values are used in the configuration.  Because of the way
+// that configuration tables are generated, they should have names which
+// are related.  The configuration options will show up lexicographically
+// ordered, thus the peculiar naming.  In this case, the 'use' option is
+// negated (if false, the others apply) which makes the names even more
+// confusing.
+RedBoot_config_option("Use BOOTP for network configuration",
+                      bootp, 
+                      ALWAYS_ENABLED, true,
+                      CONFIG_BOOL
+    );
+RedBoot_config_option("Local IP address",
+                      bootp_my_ip,
+                      "bootp", false,
+                      CONFIG_IP
+    );
+RedBoot_config_option("Default server IP address",
+                      bootp_server_ip,
+                      "bootp", false,
+                      CONFIG_IP
+    );
+#endif
+
+#define TCP_CHANNEL CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS
+
+#ifdef DEBUG_TCP
+int show_tcp = 0;
+#endif 
+
+static tcp_socket_t tcp_sock;
+static int state;
+static int _timeout = 500;
+static int orig_console, orig_debug;
+
+static int in_buflen = 0;
+static unsigned char in_buf[128];
+static unsigned char *in_bufp;
+static int out_buflen = 0;
+static unsigned char out_buf[256];
+static unsigned char *out_bufp;
+
+// Functions in this module
+static void net_io_flush(void);
+static void net_io_revert_console(void);
+
+static cyg_bool
+net_io_getc_nonblock(void* __ch_data, cyg_uint8* ch)
+{
+    if (in_buflen == 0) {
+        __tcp_poll();
+        if (tcp_sock.state == _CLOSE_WAIT) {
+            // This connection is breaking
+            if (tcp_sock.data_bytes == 0) {
+                __tcp_close(&tcp_sock);
+            }
+            return false;
+        }
+        if (tcp_sock.state == _CLOSED) {
+            // The connection is gone
+            net_io_revert_console();
+            *ch = '\n';
+            return true;
+        }
+        in_buflen = __tcp_read(&tcp_sock, in_buf, sizeof(in_buf));
+        in_bufp = in_buf;
+#ifdef DEBUG_TCP
+        if (show_tcp && (in_buflen > 0)) {
+            int old_console;
+            old_console = start_console();  
+            printf("%s:%d\n", __FUNCTION__, __LINE__);  
+            dump_buf(in_buf, in_buflen);  
+            end_console(old_console);
+        }
+#endif // DEBUG_TCP
+    }
+    if (in_buflen) {
+        *ch = *in_bufp++;
+        in_buflen--;
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static cyg_uint8
+net_io_getc(void* __ch_data)
+{
+    cyg_uint8 ch;
+    int idle_timeout = 100;  // 10ms
+
+    CYGARC_HAL_SAVE_GP();
+    while (true) {
+        if (net_io_getc_nonblock(__ch_data, &ch)) break;
+        if (--idle_timeout == 0) {
+            net_io_flush();
+            idle_timeout = 100;
+        } else {
+            CYGACC_CALL_IF_DELAY_US(100);
+        }
+    }
+    CYGARC_HAL_RESTORE_GP();
+    return ch;
+}
+
+static void
+net_io_flush(void)
+{
+    int n;
+    char *bp = out_buf;
+
+    while (out_buflen) {
+        if (tcp_sock.state == _CLOSE_WAIT) {
+            // This connection is tring to close
+            __tcp_close(&tcp_sock);
+        }
+        if (tcp_sock.state == _CLOSED) {
+            // The connection is gone!
+            net_io_revert_console();
+            break;
+        }
+#ifdef DEBUG_TCP
+        if (show_tcp) {
+            int old_console;
+            old_console = start_console();  
+            printf("%s.%d\n", __FUNCTION__, __LINE__);
+            dump_buf(out_buf, out_buflen);  
+            end_console(old_console);
+        }
+#endif // SHOW_TCP
+        n = __tcp_write(&tcp_sock, bp, out_buflen);
+        if (n > 0) {
+            out_buflen -= n;
+            bp += n;
+        }
+        __tcp_poll();
+    }
+    out_bufp = out_buf;  out_buflen = 0;
+    // Check interrupt flag
+    if (CYGACC_CALL_IF_CONSOLE_INTERRUPT_FLAG()) {
+        cyg_hal_user_break(0);
+        CYGACC_CALL_IF_CONSOLE_INTERRUPT_FLAG_SET(0);
+    }
+}
+
+static void
+net_io_putc(void* __ch_data, cyg_uint8 c)
+{
+    static bool have_dollar, have_hash;
+    static int hash_count;
+
+    *out_bufp++ = c;
+    if (c == '$') have_dollar = true;
+    if (have_dollar && (c == '#')) {
+        have_hash = true;
+        hash_count = 0;
+    }
+    if ((++out_buflen == sizeof(out_buf)) || 
+        (have_hash && (++hash_count == 3))) {
+        net_io_flush();
+        have_dollar = false;
+    }
+}
+
+static void
+net_io_write(void* __ch_data, const cyg_uint8* __buf, cyg_uint32 __len)
+{
+    int old_console;
+
+    old_console = start_console();
+    printf("%s.%d\n", __FUNCTION__, __LINE__);
+    end_console(old_console);
+#if 0
+    CYGARC_HAL_SAVE_GP();
+
+    while(__len-- > 0)
+        net_io_putc(__ch_data, *__buf++);
+
+    CYGARC_HAL_RESTORE_GP();
+#endif
+}
+
+static void
+net_io_read(void* __ch_data, cyg_uint8* __buf, cyg_uint32 __len)
+{
+    int old_console;
+
+    old_console = start_console();
+    printf("%s.%d\n", __FUNCTION__, __LINE__);
+    end_console(old_console);
+#if 0
+    CYGARC_HAL_SAVE_GP();
+
+    while(__len-- > 0)
+        *__buf++ = net_io_getc(__ch_data);
+
+    CYGARC_HAL_RESTORE_GP();
+#endif
+}
+
+static cyg_bool
+net_io_getc_timeout(void* __ch_data, cyg_uint8* ch)
+{
+    int delay_count;
+    cyg_bool res;
+    CYGARC_HAL_SAVE_GP();
+
+    net_io_flush();  // Make sure any output has been sent
+    delay_count = _timeout * 10; // delay in .1 ms steps
+
+    for(;;) {
+        res = net_io_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
+net_io_control(void *__ch_data, __comm_control_cmd_t __func, ...)
+{
+    int ret = 0;
+    int old_console;
+
+    CYGARC_HAL_SAVE_GP();
+
+    switch (__func) {
+    case __COMMCTL_IRQ_ENABLE:
+        old_console = start_console();
+        printf("%s.%d\n", __FUNCTION__, __LINE__);
+        end_console(old_console);
+        break;
+    case __COMMCTL_IRQ_DISABLE:
+        old_console = start_console();
+        printf("%s.%d\n", __FUNCTION__, __LINE__);
+        end_console(old_console);
+        ret = 0;
+        break;
+    case __COMMCTL_DBG_ISR_VECTOR:
+        old_console = start_console();
+        printf("%s.%d\n", __FUNCTION__, __LINE__);
+        end_console(old_console);
+        ret = 0;
+        break;
+    case __COMMCTL_SET_TIMEOUT:
+    {
+        va_list ap;
+
+        va_start(ap, __func);
+
+        ret = _timeout;
+        _timeout = va_arg(ap, cyg_uint32);
+
+        va_end(ap);
+    }        
+    default:
+        break;
+    }
+    CYGARC_HAL_RESTORE_GP();
+    return ret;
+}
+
+static int
+net_io_isr(void *__ch_data, int* __ctrlc, 
+                     CYG_ADDRWORD __vector, CYG_ADDRWORD __data)
+{
+    int old_console;
+
+    old_console = start_console();
+    printf("%s.%d\n", __FUNCTION__, __LINE__);
+    end_console(old_console);
+}
+
+// TEMP
+
+int 
+start_console(void)
+{
+    int cur_console;
+    cur_console = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+    CYGACC_CALL_IF_SET_CONSOLE_COMM(0);
+    return cur_console;
+}
+
+void
+end_console(int old_console)
+{
+    // Restore original console
+    CYGACC_CALL_IF_SET_CONSOLE_COMM(old_console);
+}
+// TEMP
+
+static void
+net_io_revert_console(void)
+{
+#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
+    console_selected = false;
+#endif
+    CYGACC_CALL_IF_SET_CONSOLE_COMM(orig_console);
+    CYGACC_CALL_IF_SET_DEBUG_COMM(orig_debug);
+}
+
+static void
+net_io_assume_console(void)
+{
+#ifdef CYGPKG_REDBOOT_ANY_CONSOLE
+    console_selected = true;
+#endif
+    orig_console = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+    CYGACC_CALL_IF_SET_CONSOLE_COMM(TCP_CHANNEL);
+    orig_debug = CYGACC_CALL_IF_SET_DEBUG_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+    CYGACC_CALL_IF_SET_DEBUG_COMM(TCP_CHANNEL);
+}
+
+static void
+net_io_init(void)
+{
+    static int init = 0;
+    if (!init) {
+        hal_virtual_comm_table_t* comm;
+        int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+
+        // Setup procs in the vector table
+        CYGACC_CALL_IF_SET_CONSOLE_COMM(TCP_CHANNEL);
+        comm = CYGACC_CALL_IF_CONSOLE_PROCS();
+        //CYGACC_COMM_IF_CH_DATA_SET(*comm, chan);
+        CYGACC_COMM_IF_WRITE_SET(*comm, net_io_write);
+        CYGACC_COMM_IF_READ_SET(*comm, net_io_read);
+        CYGACC_COMM_IF_PUTC_SET(*comm, net_io_putc);
+        CYGACC_COMM_IF_GETC_SET(*comm, net_io_getc);
+        CYGACC_COMM_IF_CONTROL_SET(*comm, net_io_control);
+        CYGACC_COMM_IF_DBG_ISR_SET(*comm, net_io_isr);
+        CYGACC_COMM_IF_GETC_TIMEOUT_SET(*comm, net_io_getc_timeout);
+
+        // Restore original console
+        CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
+
+        init = 1;
+    }
+    __tcp_listen(&tcp_sock, gdb_port);
+    state = tcp_sock.state; 
+#ifdef DEBUG_TCP
+    printf("show tcp = %p\n", (void *)&show_tcp);
+#endif
+}
+
+void
+net_io_test(void)
+{
+    __tcp_poll();
+    if (state != tcp_sock.state) {
+        // Something has changed
+        if (tcp_sock.state == _ESTABLISHED) {
+            // A new connection has arrived
+            net_io_assume_console();
+            in_bufp = in_buf;  in_buflen = 1;  *in_bufp = '\r';
+            out_bufp = out_buf;  out_buflen = 0;
+        }
+        if (tcp_sock.state == _CLOSED) {
+            net_io_init();  // Get ready for another connection
+        }
+    }
+    state = tcp_sock.state;
+}
+
+//
+// Network initialization
+//
+#include <eth_drv.h>
+#include <netdev.h>
+#include <cyg/hal/hal_tables.h>
+
+// Define table boundaries
+CYG_HAL_TABLE_BEGIN( __NETDEVTAB__, netdev );
+CYG_HAL_TABLE_END( __NETDEVTAB_END__, netdev );
+
+RedBoot_init(net_init, RedBoot_INIT_LAST);
+
+void
+net_init(void)
+{
+    cyg_netdevtab_entry_t *t;
+
+    if (!config_ok) {
+        // Set defaults as appropriate
+        use_bootp = true;
+        net_debug = false;
+        gdb_port = CYGNUM_REDBOOT_NETWORKING_TCP_PORT;
+#ifdef CYGSEM_REDBOOT_FLASH_CONFIG
+    } else {
+        flash_get_config("net_debug", &net_debug, CONFIG_BOOL);
+        flash_get_config("gdb_port", &gdb_port, CONFIG_INT);
+        flash_get_config("bootp", &use_bootp, CONFIG_BOOL);
+        flash_get_config("bootp_my_ip", &__local_ip_addr, CONFIG_IP);
+        flash_get_config("bootp_server_ip", &my_bootp_info.bp_siaddr, CONFIG_IP);
+#endif
+    }
+    have_net = false;
+    // Make sure the recv buffers are set up
+    eth_drv_buffers_init();
+    __pktbuf_init();
+    // Initialize all network devices
+    for (t = &__NETDEVTAB__[0]; t != &__NETDEVTAB_END__; t++) {
+        if (t->init(t)) {
+            t->status = CYG_NETDEVTAB_STATUS_AVAIL;
+        } else {
+            // What to do if device init fails?
+            t->status = 0;  // Device not [currently] available
+        }
+    }
+    if (!__local_enet_sc) {
+        printf("No network interfaces found\n");
+        return;
+    }    
+    // Initialize the network [if present]
+    if (use_bootp) {
+        if (__bootp_find_local_ip(&my_bootp_info) == 0) {
+            have_net = true;
+        } else {
+            printf("Can't get BOOTP info - network disabled!\n");
+        }
+    } else {
+        have_net = true;  // Assume values in FLASH were OK
+    }
+    if (have_net) {
+        printf("IP: %s", inet_ntoa((in_addr_t *)&__local_ip_addr));
+        printf(", Default server: %s\n", inet_ntoa(&my_bootp_info.bp_siaddr));
+        net_io_init();
+    }
+}