Mercurial > ecos
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(); + } +}
