This is the mail archive of the ecos-patches@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RedBoot - improve load command


Index: redboot/current/ChangeLog
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/ChangeLog,v
retrieving revision 1.57
diff -u -5 -p -r1.57 ChangeLog
--- redboot/current/ChangeLog	31 May 2002 17:10:26 -0000	1.57
+++ redboot/current/ChangeLog	1 Jul 2002 15:22:37 -0000
@@ -1,5 +1,18 @@
+2002-07-01  Gary Thomas  <gary@chez-thomas.org>
+
+	* src/net/tftp_client.c: 
+	* src/net/http_client.c: 
+	* src/fs/disk.c: 
+	* src/xyzModem.h: 
+	* src/xyzModem.c: 
+	* src/load.c: 
+	* include/net/tftp_support.h: 
+	* include/net/http.h: 
+	* include/redboot.h: 
+	* cdl/redboot.cdl: Make 'load' command stream I/O table driven.
+
 2002-05-31  Jesper Skov  <jskov@redhat.com>
 
 	* doc/redboot_installing.sgml: Updated the remaining installation
 	instructions (well, the top mode details anyway).
 
Index: redboot/current/cdl/redboot.cdl
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/cdl/redboot.cdl,v
retrieving revision 1.37
diff -u -5 -p -r1.37 redboot.cdl
--- redboot/current/cdl/redboot.cdl	23 May 2002 23:08:25 -0000	1.37
+++ redboot/current/cdl/redboot.cdl	1 Jul 2002 19:59:46 -0000
@@ -7,10 +7,11 @@
 # ====================================================================
 #####ECOSGPLCOPYRIGHTBEGIN####
 ## -------------------------------------------
 ## This file is part of eCos, the Embedded Configurable Operating System.
 ## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+## Copyright (C) 2002 Gary Thomas
 ##
 ## eCos is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free
 ## Software Foundation; either version 2 or (at your option) any later version.
 ##
@@ -149,12 +150,12 @@ cdl_package CYGPKG_REDBOOT {
                      The image may require further relocation or symbol
                      stripping before being converted to a binary image.
                      This is handled by a rule in the target CDL."
 
         compile main.c crc.c
-        compile misc_funs.c io.c parse.c ticks.c xyzModem.c syscall.c alias.c
-        compile -library=libextras.a load.c
+        compile misc_funs.c io.c parse.c ticks.c syscall.c alias.c
+        compile -library=libextras.a load.c xyzModem.c 
 
         make -priority 320 {
             <PREFIX>/bin/redboot.elf : $(PREFIX)/lib/target.ld $(PREFIX)/lib/vectors.o $(PREFIX)/lib/libtarget.a $(PREFIX)/lib/libextras.a
                     @sh -c "mkdir -p $(dir $@)"
                     $(CC) -c $(INCLUDE_PATH) $(CFLAGS) -o $(PREFIX)/lib/version.o $(REPOSITORY)/$(PACKAGE)/src/version.c
@@ -167,12 +168,12 @@ cdl_package CYGPKG_REDBOOT {
         flavor        bool
         active_if     CYGPKG_IO_ETH_DRIVERS
         default_value 1
         compile net/bootp.c net/udp.c net/ip.c net/pktbuf.c net/cksum.c
         compile net/enet.c net/icmp.c net/tcp.c net/timers.c net/arp.c
-        compile net/tftp_client.c net/net_io.c net/inet_addr.c
-        compile -library=libextras.a net/ping.c
+        compile net/net_io.c net/inet_addr.c
+        compile -library=libextras.a net/ping.c net/tftp_client.c 
         description "This option includes networking support in RedBoot."
         define_proc {
             puts $::cdl_system_header "#define CYGNUM_HAL_VIRTUAL_VECTOR_AUX_CHANNELS 1"
         }
 
@@ -186,11 +187,11 @@ cdl_package CYGPKG_REDBOOT {
 
         cdl_option CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD {
             display          "Support HTTP for download"
             flavor           bool
             default_value    1
-            compile          net/http_client.c
+            compile          -library=libextras.a net/http_client.c
             description      "
                 This option enables the use of the HTTP protocol for download"
         }
 
         cdl_component CYGDAT_REDBOOT_DEFAULT_IP_ADDR {
Index: redboot/current/include/redboot.h
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/include/redboot.h,v
retrieving revision 1.23
diff -u -5 -p -r1.23 redboot.h
--- redboot/current/include/redboot.h	23 May 2002 23:08:27 -0000	1.23
+++ redboot/current/include/redboot.h	1 Jul 2002 19:59:59 -0000
@@ -7,10 +7,11 @@
 //==========================================================================
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
 // Software Foundation; either version 2 or (at your option) any later version.
 //
@@ -62,11 +63,10 @@
 #include <cyg/infra/diag.h>
 #include <string.h>
 
 #ifdef CYGPKG_REDBOOT_NETWORKING
 #include <net/net.h>
-#include <net/tftp_support.h>
 #include <net/bootp.h>
 // Determine an IP address for this node, using BOOTP
 extern int __bootp_find_local_ip(bootp_header_t *info);
 #endif
 
@@ -147,13 +147,49 @@ unsigned long  crc32(unsigned char *buf,
 #ifdef CYGSEM_REDBOOT_FLASH_ALIASES
 externC char *flash_lookup_alias(char *alias, char *alias_buf);
 #endif
 externC void expand_aliases(char *line, int len);
 
-typedef int (*getc_t)(void);
-typedef void (*terminate_t)(int method, getc_t get_c);
+//
+// Stream I/O support
+//
+
+typedef struct {
+    char *filename;
+    struct load_io_entry *mode;
+    int   chan;
+#ifdef CYGPKG_REDBOOT_NETWORKING
+    struct sockaddr_in *server;
+#endif
+} connection_info_t;
+
+typedef struct {
+    int   (*open)(connection_info_t *info, int *err);    
+    void  (*close)(int *err);    
+    void  (*terminate)(bool abort, int (*getc)(void));    
+    int   (*read)(char *buf, int size, int *err);    
+    char *(*error)(int err);
+} getc_io_funcs_t;
+
+#define GETC_IO_FUNCS(_label_, _open_, _close_, _terminate_, _read_, _error_)   \
+getc_io_funcs_t _label_ = {                                                     \
+    _open_, _close_, _terminate_, _read_, _error_                               \
+};
 
+struct load_io_entry {
+    char            *mode;
+    getc_io_funcs_t *funcs;    
+    bool             can_verbose;
+    bool             need_filename;
+} CYG_HAL_TABLE_TYPE;
+#define _RedBoot_load(_mode_,_funcs_,_verbose_,_filename_)              \
+struct load_io_entry _load_tab_##_funcs_##_mode_                        \
+   CYG_HAL_TABLE_QUALIFIED_ENTRY(RedBoot_load,_funcs_##_mode) =         \
+     { #_mode_, &_funcs_, _verbose_, _filename_ }; 
+#define RedBoot_load(_mode_,_funcs_,_verbose_,_filename_)               \
+   _RedBoot_load(_mode_,_funcs_,_verbose_,_filename_)
+ 
 #ifdef CYGPKG_COMPRESS_ZLIB
 // Decompression support
 typedef struct _pipe {
     unsigned char* in_buf;              // only changed by producer
     int in_avail;                       // only changed by producer
@@ -229,11 +265,11 @@ struct idle_tab_entry _idle_tab_##_p_##_
 #define RedBoot_idle(_f_,_p_) _RedBoot_idle(_f_,_p_)
 
 // This function called when changing idle/not - mostly used by I/O
 // to support idle when timeout, etc.
 void do_idle(bool state);
- 
+
 // Option processing support
 
 struct option_info {
     char flag;
     bool takes_arg;
@@ -253,16 +289,10 @@ externC struct cmd *parse(char **line, i
 externC void init_opts(struct option_info *opts, char flag, bool takes_arg, 
                        int arg_type, void **arg, bool *arg_set, char *name);
 externC bool scan_opts(int argc, char *argv[], int first, 
                        struct option_info *opts, int num_opts, 
                        void **def_arg, int def_arg_type, char *def_descr);
-
-externC int redboot_getc(void);
-externC void redboot_getc_init(int (*fun)(char *, int, int *), 
-                               int verbose, int decompress);
-externC void redboot_getc_rewind(void);
-externC void redboot_getc_close(void);
 
 #ifdef CYGNUM_HAL_VIRTUAL_VECTOR_AUX_CHANNELS
 #define CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS \
   (CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS+CYGNUM_HAL_VIRTUAL_VECTOR_AUX_CHANNELS)
 #else
Index: redboot/current/include/net/http.h
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/include/net/http.h,v
retrieving revision 1.1
diff -u -5 -p -r1.1 http.h
--- redboot/current/include/net/http.h	23 May 2002 23:08:29 -0000	1.1
+++ redboot/current/include/net/http.h	1 Jul 2002 20:00:11 -0000
@@ -7,10 +7,11 @@
 //==========================================================================
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
 // Software Foundation; either version 2 or (at your option) any later version.
 //
@@ -53,16 +54,17 @@
 //==========================================================================
 
 #ifndef _HTTP_H_
 #define _HTTP_H_
 
-extern int   http_stream_open(char *file, struct sockaddr_in *server, int *err);
+extern int   http_stream_open(connection_info_t *info, int *err);
 extern int   http_stream_read(char *buf, int len, int *err);
-extern int   http_stream_close(int *err);
+extern void  http_stream_close(int *err);
 extern char *http_error(int err);
 
 #define HTTP_NOERR    0   // No error
 #define HTTP_BADHDR   1   // Invalid HTTP header (response)
 #define HTTP_OPEN     2   // Problems opening connection
 #define HTTP_IO       3   // Misc I/O problems
 
+extern getc_io_funcs_t http_io;
 #endif // _HTTP_H_
Index: redboot/current/include/net/tftp_support.h
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/include/net/tftp_support.h,v
retrieving revision 1.5
diff -u -5 -p -r1.5 tftp_support.h
--- redboot/current/include/net/tftp_support.h	23 May 2002 23:08:29 -0000	1.5
+++ redboot/current/include/net/tftp_support.h	1 Jul 2002 20:00:25 -0000
@@ -7,10 +7,11 @@
 //==========================================================================
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
 // Software Foundation; either version 2 or (at your option) any later version.
 //
@@ -81,19 +82,19 @@
 
 /*
  * Client support
  */
 
-extern int   tftp_get(char *, struct sockaddr_in *, char *, int, int, int *);
-extern char *tftp_error(int err);
-
-extern int   tftp_stream_open(char *file, struct sockaddr_in *server, int mode, int *err);
+extern int   tftp_stream_open(connection_info_t *info, int *err);
 extern int   tftp_stream_read(char *buf, int len, int *err);
-extern int   tftp_stream_close(int *err);
+extern void  tftp_stream_close(int *err);
+extern char *tftp_error(int err);
 
 #define TFTP_TIMEOUT_PERIOD 5
 #define TFTP_TIMEOUT_MAX   15
 #define TFTP_RETRIES_MAX    5
 
 #define TFTP_PORT           69
+
+extern getc_io_funcs_t tftp_io;
 
 #endif // _TFTP_SUPPORT_H_
Index: redboot/current/src/load.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/src/load.c,v
retrieving revision 1.24
diff -u -5 -p -r1.24 load.c
--- redboot/current/src/load.c	29 May 2002 18:28:34 -0000	1.24
+++ redboot/current/src/load.c	1 Jul 2002 20:00:38 -0000
@@ -7,10 +7,11 @@
 //==========================================================================
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
 // Software Foundation; either version 2 or (at your option) any later version.
 //
@@ -56,17 +57,47 @@
 #include <xyzModem.h>
 #include <elf.h>
 #ifdef CYGPKG_REDBOOT_DISK
 #include <fs/disk.h>
 #endif
+#ifdef CYGPKG_REDBOOT_NETWORKING
+#include <net/tftp_support.h>
 #ifdef CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD
 #include <net/http.h>
 #endif
+#endif
+
+static char usage[] = "[-r] [-v] "
+#ifdef CYGPKG_COMPRESS_ZLIB
+                      "[-d] "
+#endif
+                      "[-h <host>] [-m <varies>] "
+#if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1
+                      "[-c <channel_number>] "
+#endif
+                      "\n        [-b <base_address>] <file_name>";
+
+// Exported CLI function
+RedBoot_cmd("load", 
+            "Load a file", 
+            usage,
+            do_load 
+    );
+
+//
+// Stream I/O support
+//
+
+// Table describing the various I/O methods
+CYG_HAL_TABLE_BEGIN( __RedBoot_LOAD_TAB__, RedBoot_load );
+CYG_HAL_TABLE_END( __RedBoot_LOAD_TAB_END__, RedBoot_load );
+extern struct load_io_entry __RedBoot_LOAD_TAB__[], __RedBoot_LOAD_TAB_END__;
 
 // Buffers, data used by redboot_getc
 #define BUF_SIZE 256
 struct {
+    getc_io_funcs_t *io;
     int (*fun)(char *, int len, int *err);
     unsigned char  buf[BUF_SIZE];
     unsigned char *bufp;
     int   avail, len, err;
     int   verbose, decompress, tick;
@@ -75,39 +106,156 @@ struct {
     _pipe_t load_pipe;
     unsigned char _buffer[CYGNUM_REDBOOT_LOAD_ZLIB_BUFFER];
 #endif
 } getc_info;
 
-static char usage[] = "[-r] [-v] "
+typedef int (*getc_t)(void);
+
+//
+// Read the next data byte from the stream.
+// Returns:
+//    >= 0 - actual data
+//      -1 - error or EOF, status in getc_info.err
+//
+static int 
+redboot_getc(void)
+{
+    static char spin[] = "|/-\\|-";
+    if (getc_info.avail < 0) {
+      return -1;
+    }
+    if (getc_info.avail == 0) {
+        if (getc_info.verbose) {
+            diag_printf("%c\b", spin[getc_info.tick++]);
+            if (getc_info.tick >= sizeof(spin)) {
+                getc_info.tick = 0;
+            }
+        }
+        if (getc_info.len < BUF_SIZE) {
+            // No more data available
+            if (getc_info.verbose) diag_printf("\n");
+            return -1;
+        }
+        getc_info.bufp = getc_info.buf;
+        getc_info.len = (*getc_info.fun)(getc_info.bufp, BUF_SIZE, &getc_info.err);
+        if ((getc_info.avail = getc_info.len) <= 0) {
+            if (getc_info.verbose) diag_printf("\n");
+            return -1;
+        }
+    }
+    getc_info.avail--;
+    return *getc_info.bufp++;
+}
+
 #ifdef CYGPKG_COMPRESS_ZLIB
-                      "[-d] "
-#endif
-                      "[-h <host>] [-m {TFTP "
-#ifdef CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD
-                      "| HTTP"
-#endif
-#ifdef xyzModem_zmodem
-                      "| {x|y|z}MODEM"
-#else
-                      "| {x|y}MODEM"
-#endif
-#ifdef CYGPKG_REDBOOT_DISK
-                      " | disk"
+//
+// Called to fetch a new chunk of data and decompress it
+//
+static int 
+_decompress_stream(char *buf, int len, int *err)
+{
+    _pipe_t* p = &getc_info.load_pipe;
+    int res, total;
+
+    total = 0;
+    while (len > 0) {
+        if (p->in_avail == 0) {
+            p->in_buf = &getc_info._buffer[0];
+            res = (*getc_info.raw_fun)(p->in_buf, CYGNUM_REDBOOT_LOAD_ZLIB_BUFFER, 
+                                       &getc_info.err);
+            if ((p->in_avail = res) <= 0) {
+                // No more data
+                return total;
+            }
+        }
+        p->out_buf = buf;
+        p->out_size = 0;
+        p->out_max = len;
+        res = (*_dc_inflate)(p);
+        if (res != 0) {
+            *err = res;
+            return total;
+        }        
+        len -= p->out_size;
+        buf += p->out_size;
+        total += p->out_size;
+    }
+    return total;
+}
 #endif
-#if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1
-                      " -c <channel_number>"
+
+static int
+redboot_getc_init(connection_info_t *info, getc_io_funcs_t *funcs, 
+                  int verbose, int decompress)
+{
+    int res;
+
+    res = (funcs->open)(info, &getc_info.err);    
+    if (res < 0) {
+        diag_printf("Can't load '%s': %s\n", info->filename, (funcs->error)(getc_info.err));
+            return res;
+    }
+    getc_info.io = funcs;
+    getc_info.fun = funcs->read;
+    getc_info.avail = 0;
+    getc_info.len = BUF_SIZE;
+    getc_info.verbose = verbose;
+    getc_info.decompress = decompress;
+    getc_info.tick = 0;
+#ifdef CYGPKG_COMPRESS_ZLIB
+    if (decompress) {
+        _pipe_t* p = &getc_info.load_pipe;
+        p->out_buf = &getc_info.buf[0];
+        p->out_size = 0;
+        p->in_avail = 0;
+        getc_info.raw_fun = getc_info.fun;
+        getc_info.fun = _decompress_stream;
+        getc_info.err = (*_dc_init)(p);
+        if (0 != getc_info.err && p->msg) {
+            diag_printf("open decompression error: %s\n", p->msg);
+        }
+    }
 #endif
-                      "}]\n        [-b <base_address>] <file_name>";
+    return 0;
+}
 
-// Exported CLI function
-RedBoot_cmd("load", 
-            "Load a file", 
-            usage,
-            do_load 
-    );
+static void
+redboot_getc_rewind(void)
+{
+    getc_info.bufp = getc_info.buf;
+    getc_info.avail = getc_info.len;
+}
+
+static void
+redboot_getc_terminate(bool abort)
+{
+    if (getc_info.io->terminate) {
+        (getc_info.io->terminate)(abort, redboot_getc);
+    }
+}
+
+static void
+redboot_getc_close(void)
+{
+    (getc_info.io->close)(&getc_info.err);
+#ifdef CYGPKG_COMPRESS_ZLIB
+    if (getc_info.decompress) {
+        _pipe_t* p = &getc_info.load_pipe;
+        int err = getc_info.err;
+        if (0 != err && p->msg) {
+            diag_printf("decompression error: %s\n", p->msg);
+        }
+        err = (*_dc_close)(p, getc_info.err);
+    }
+#endif
+}
 
 #ifdef CYGSEM_REDBOOT_ELF
+//
+// Support function - used to read bytes into a buffer
+// Returns the number of bytes read (stops short on errors)
+//
 static int
 _read(int (*getc)(void), unsigned char *buf, int len)
 {
     int total = 0;
     int ch;
@@ -122,12 +270,15 @@ _read(int (*getc)(void), unsigned char *
     }
     return total;
 }
 #endif
 
+//
+// Load an ELF [binary] image 
+//
 static unsigned long
-load_elf_image(getc_t getc, terminate_t terminate, unsigned long base)
+load_elf_image(getc_t getc, unsigned long base)
 {
 #ifdef CYGSEM_REDBOOT_ELF
     Elf32_Ehdr ehdr;
 #define MAX_PHDR 8
     Elf32_Phdr phdr[MAX_PHDR];
@@ -216,20 +367,13 @@ load_elf_image(getc_t getc, terminate_t 
             }
             // Copy data into memory
             while (len-- > 0) {
 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
                 if ((addr < user_ram_start) || (addr > user_ram_end)) {
-                    // Only if there is no need to stop the download before printing
-                    // output can we ask confirmation questions.
-                    if (terminate) {
-                        (*terminate)(xyzModem_abort, getc);
-                        diag_printf("*** Warning! Attempt to load ELF data to address: %p\nRedBoot does not believe this is in RAM\nUse TFTP for a chance to override this.\n",(void*)addr);
-                    } else {
-                        if (!verify_action("Attempt to load ELF data to address: %p\n"
-                                           "RedBoot does not believe this is in RAM", (void*)addr))
-                            return 0;
-                    }
+                    redboot_getc_terminate(true);
+                    diag_printf("*** Abort! Attempt to load ELF data to address: %p which is not in RAM\n", (void*)addr);
+                    return 0;
                 }
 #endif
                 if ((ch = (*getc)()) < 0) {
                     diag_printf(SHORT_DATA);
                     return 0;
@@ -292,13 +436,12 @@ _hex2(int (*getc)(void), int len, long *
 // the first section of the data, so if there are non-contiguous
 // pieces of data, they will end up relocated in the same fashion.
 // Because of this, "base" probably only makes sense for a set of
 // data which has only one section, e.g. a ROM image.
 //
-#define MAX_LINE 80
 static unsigned long
-load_srec_image(getc_t getc, terminate_t terminate, unsigned long base)
+load_srec_image(getc_t getc, unsigned long base)
 {
     int  c;
     long offset = 0, count, sum, val, cksum;
     unsigned char *addr, *base_addr;
     char type;
@@ -308,20 +451,20 @@ load_srec_image(getc_t getc, terminate_t
     unsigned long lowest_address = 0xFFFFFFFF;
 
     while ((c = (*getc)()) > 0) {
         // Start of line
         if (c != 'S') {
-	    if (terminate) (*terminate)(xyzModem_abort, getc);
+            redboot_getc_terminate(true);
             diag_printf("Invalid S-record at offset %p, input: %c\n", 
                    (void *)offset, c);
             return 0;
         }
         type = (*getc)();
         offset += 2;
         sum = 0;
         if ((count = _hex2(getc, 1, &sum)) < 0) {
-	    if (terminate) (*terminate)(xyzModem_abort, getc);
+            redboot_getc_terminate(true);
             diag_printf("Bad S-record count at offset %p\n", (void *)offset);
             return 0;
         }
         offset += 1;
         switch (type) {
@@ -346,18 +489,13 @@ load_srec_image(getc_t getc, terminate_t
             }
 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
             if ((addr < user_ram_start) || (addr > user_ram_end)) {
 	      // Only if there is no need to stop the download before printing
 	      // output can we ask confirmation questions.
-	      if (terminate) {
-		(*terminate)(xyzModem_abort, getc);
-		diag_printf("*** Warning! Attempt to load S-record to address: %p\nRedBoot does not believe this is in RAM\nUse TFTP for a chance to override this.\n",(void*)addr);
-	      } else {
-                if (!verify_action("Attempt to load S-record data to address: %p\n"
-                                   "RedBoot does not believe this is in RAM", (void*)addr))
-                    return 0;
-	      }
+                redboot_getc_terminate(true);
+		diag_printf("*** Abort! Attempt to load S-record to address: %p, which is not in RAM\n",(void*)addr);
+                return 0;
             }
 #endif
             count -= ((type-'1'+2)+1);
             offset += count;
             while (count-- > 0) {
@@ -367,11 +505,11 @@ load_srec_image(getc_t getc, terminate_t
             cksum = _hex2(getc, 1, 0);
             offset += 1;
             sum = sum & 0xFF;
             cksum = (~cksum & 0xFF);
             if (cksum != sum) {
-		if (terminate) (*terminate)(xyzModem_abort, getc);
+                redboot_getc_terminate(true);
                 diag_printf("*** Warning! Checksum failure - Addr: %lx, %02lX <> %02lX\n", 
                        (unsigned long)base_addr, sum, cksum);
                 return 0;
             }
             if ((unsigned long)(addr-addr_offset) > highest_address) {
@@ -383,164 +521,45 @@ load_srec_image(getc_t getc, terminate_t
         case '9':
             addr = (unsigned char *)_hex2(getc, ('9'-type+2), &sum);
             offset += ('9'-type+2);
             // Save entry address
             entry_address = (unsigned long)addr;
-	    if (terminate) (*terminate)(xyzModem_close, getc);
+            redboot_getc_terminate(false);
             if (addr_offset) diag_printf("Address offset = %p\n", (void *)addr_offset);
             diag_printf("Entry point: %p, address range: %p-%p\n", 
                    (void*)entry_address, (void *)lowest_address, (void *)highest_address);
 
             // Save load base/top
             load_address = lowest_address;
             load_address_end = highest_address;
 
             return highest_address;
         default:
-	    if (terminate) (*terminate)(xyzModem_abort, getc);
+            redboot_getc_terminate(true);
             diag_printf("Invalid S-record at offset 0x%lx, type: %x\n", 
                    (unsigned long)offset, type);
             return 0;
         }
         while ((c = (*getc)()) != '\n') offset++;
     }
     return 0;
 }
 
 //
-// Stream I/O support
-//
-int
-redboot_getc(void)
-{
-    static char spin[] = "|/-\\|-";
-    if (getc_info.avail < 0) {
-      return -1;
-    }
-    if (getc_info.avail == 0) {
-        if (getc_info.verbose) {
-            diag_printf("%c\b", spin[getc_info.tick++]);
-            if (getc_info.tick >= sizeof(spin)) {
-                getc_info.tick = 0;
-            }
-        }
-        if (getc_info.len < BUF_SIZE) {
-            // No more data available
-            if (getc_info.verbose) diag_printf("\n");
-            return -1;
-        }
-        getc_info.bufp = getc_info.buf;
-        getc_info.len = (*getc_info.fun)(getc_info.bufp, BUF_SIZE, &getc_info.err);
-        if ((getc_info.avail = getc_info.len) <= 0) {
-            if (getc_info.verbose) diag_printf("\n");
-            return -1;
-        }
-    }
-    getc_info.avail--;
-    return *getc_info.bufp++;
-}
-
+// 'load' CLI command processing
+//   -b - specify a load [base] address
+//   -m - specify an I/O stream/method
+//   -c - Alternate serial I/O channel
 #ifdef CYGPKG_COMPRESS_ZLIB
-// Called to fetch a new chunk of data and decompress it
-int 
-_decompress_stream(char *buf, int len, int *err)
-{
-    _pipe_t* p = &getc_info.load_pipe;
-    int res, total;
-
-    total = 0;
-    while (len > 0) {
-        if (p->in_avail == 0) {
-            p->in_buf = &getc_info._buffer[0];
-            res = (*getc_info.raw_fun)(p->in_buf, CYGNUM_REDBOOT_LOAD_ZLIB_BUFFER, 
-                                       &getc_info.err);
-            if ((p->in_avail = res) <= 0) {
-                // No more data
-                return total;
-            }
-        }
-        p->out_buf = buf;
-        p->out_size = 0;
-        p->out_max = len;
-        res = (*_dc_inflate)(p);
-        if (res != 0) {
-            *err = res;
-            return total;
-        }        
-        len -= p->out_size;
-        buf += p->out_size;
-        total += p->out_size;
-    }
-    return total;
-}
-#endif
-
-void
-redboot_getc_init(int (*fun)(char *, int, int *), 
-                  int verbose, int decompress)
-{
-    getc_info.avail = 0;
-    getc_info.len = BUF_SIZE;
-    getc_info.fun = fun;
-    getc_info.verbose = verbose;
-    getc_info.decompress = decompress;
-    getc_info.tick = 0;
-#ifdef CYGPKG_COMPRESS_ZLIB
-    if (decompress) {
-        _pipe_t* p = &getc_info.load_pipe;
-        int err;
-        p->out_buf = &getc_info.buf[0];
-        p->out_size = 0;
-        p->in_avail = 0;
-        getc_info.fun = _decompress_stream;
-        getc_info.raw_fun = fun;
-        err = (*_dc_init)(p);
-        if (0 != err && p->msg) {
-            diag_printf("open decompression error: %s\n", p->msg);
-        }
-    }
+//   -d - Decompress data [packed via 'zlib']
 #endif
-}
-
-void
-redboot_getc_rewind(void)
-{
-    getc_info.bufp = getc_info.buf;
-    getc_info.avail = getc_info.len;
-}
-
-void
-redboot_getc_close(void)
-{
-#ifdef CYGPKG_COMPRESS_ZLIB
-    if (getc_info.decompress) {
-        _pipe_t* p = &getc_info.load_pipe;
-        int err = getc_info.err;
-        if (0 != err && p->msg) {
-            diag_printf("decompression error: %s\n", p->msg);
-        }
-        err = (*_dc_close)(p, getc_info.err);
-    }
-#endif
-}
-
-#define MODE_TFTP   0
-#define MODE_XMODEM xyzModem_xmodem  // 1
-#define MODE_YMODEM xyzModem_ymodem  // 2
-#ifdef xyzModem_zmodem
-#define MODE_ZMODEM xyzModem_zmodem  // 3
-#endif
-#define MODE_DISK   4
-#ifdef CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD
-#define MODE_HTTP   5
-#endif
-
+//
 void 
 do_load(int argc, char *argv[])
 {
     int res, num_options;
-    int i, err, mode;
+    int i, err;
     bool verbose, raw;
     bool base_addr_set, mode_str_set;
     char *mode_str;
 #ifdef CYGPKG_REDBOOT_NETWORKING
     struct sockaddr_in host;
@@ -555,24 +574,21 @@ do_load(int argc, char *argv[])
     unsigned long base = 0;
     unsigned long end = 0;
     char type[4];
     char *filename = 0;
     struct option_info opts[7];
-    terminate_t terminate = NULL;
+    connection_info_t info;
+    getc_io_funcs_t *io;
+    struct load_io_entry *io_tab;
 
 #ifdef CYGPKG_REDBOOT_NETWORKING
     memset((char *)&host, 0, sizeof(host));
     host.sin_len = sizeof(host);
     host.sin_family = AF_INET;
     host.sin_addr = my_bootp_info.bp_siaddr;
     host.sin_port = 0;
 #endif
-#ifdef CYGPKG_REDBOOT_NETWORKING
-    mode = MODE_TFTP;
-#else
-    mode = MODE_YMODEM;
-#endif
 
     init_opts(&opts[0], 'v', false, OPTION_ARG_TYPE_FLG, 
               (void **)&verbose, 0, "verbose");
     init_opts(&opts[1], 'r', false, OPTION_ARG_TYPE_FLG, 
               (void **)&raw, 0, "load raw data");
@@ -614,81 +630,49 @@ do_load(int argc, char *argv[])
                         hostname, inet_ntoa((in_addr_t *)&host));
             return;
         }
     }
 #endif
+    if (chan >= CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS) {
+        diag_printf("Invalid I/O channel: %d\n", chan);
+        return;
+    }
     if (mode_str_set) {
-        if (strncasecmp(&mode_str[1], "modem", strlen(&mode_str[1])) == 0) {
-            switch (_tolower(mode_str[0])) {
-            case 'x':
-                mode = MODE_XMODEM;
-                break;
-            case 'y':
-                mode = MODE_YMODEM;
+        io = (getc_io_funcs_t *)NULL;
+        for (io_tab = __RedBoot_LOAD_TAB__; 
+             io_tab != &__RedBoot_LOAD_TAB_END__;  io_tab++) {
+            if (strncasecmp(&mode_str[0], io_tab->mode, strlen(&mode_str[0])) == 0) {
+                io = io_tab->funcs;
                 break;
-#ifdef xyzModem_zmodem
-            case 'z':
-                mode = MODE_ZMODEM;
-                break;
-#endif
-            default:
-                diag_printf("Invalid 'mode': %s\n", mode_str);
-                return;
-            }
-            // When using a serial download type, override verbose
-            // setting: spinner interferes with the protocol.
-            verbose = false;
-#ifdef CYGPKG_REDBOOT_DISK
-	} else if (strcasecmp(mode_str, "disk") == 0) {
-            mode = MODE_DISK;
-#endif
-#ifdef CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD
-	} else if (strcasecmp(mode_str, "http") == 0) {
-            mode = MODE_HTTP;
-#endif
-#ifdef CYGPKG_REDBOOT_NETWORKING
-        } else if (strcasecmp(mode_str, "tftp") == 0) {
-            mode = MODE_TFTP;
-            if (!have_net) {
-                diag_printf("TFTP mode requires a working network\n");
-                return;
             }
-#endif
-        } else {
-            diag_printf("Invalid 'mode': %s\n", mode_str);
-            return;
         }
-    }
-#if defined(CYGPKG_REDBOOT_NETWORKING) || defined(CYGPKG_REDBOOT_DISK)
-    if ((mode == MODE_TFTP || mode == MODE_DISK) && !filename) {
-        diag_printf("File name missing\n");
-        diag_printf("usage: load %s\n", usage);
-        return;
-    }
-#endif
-#if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1
-    if (chan_set) {
-        if ((mode != MODE_XMODEM) && 
-#ifdef MODE_ZMODEM
-            (mode != MODE_ZMODEM) && 
-#endif
-            (mode != MODE_YMODEM)) {
-#ifdef xyzModem_zmodem
-            diag_printf("I/O channel can only be used with {xyz}Modem\n");
-#else
-            diag_printf("I/O channel can only be used with {xy}Modem\n");
-#endif
+        if (!io) {
+            diag_printf("Invalid 'mode': %s.  Valid modes are:", mode_str);
+            for (io_tab = __RedBoot_LOAD_TAB__; 
+                 io_tab != &__RedBoot_LOAD_TAB_END__;  io_tab++) {
+                diag_printf(" %s", io_tab->mode);
+            }
+            diag_printf("\n");
+        }
+        if (!io) {
             return;
         }
-        if (chan >= CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS) {
-            diag_printf("Invalid I/O channel: %d\n", chan);
+        verbose &= io_tab->can_verbose;
+        if (io_tab->need_filename && !filename) {
+            diag_printf("File name required\n");
+            diag_printf("usage: load %s\n", usage);
             return;
         }
     } else {
-        chan = -1;
-    }
+        io_tab = (struct load_io_entry *)NULL;  // Default
+#ifdef CYGPKG_REDBOOT_NETWORKING
+        io = &tftp_io;
+#else
+        io = &xyzModem_io;
+        verbose = false;
 #endif
+    }
 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
     if (base_addr_set &&
         ((base < (unsigned long)user_ram_start) ||
          (base > (unsigned long)user_ram_end))) {
         if (!verify_action("Specified address (%p) is not believed to be in RAM", (void*)base))
@@ -697,78 +681,35 @@ do_load(int argc, char *argv[])
 #endif
     if (raw && !base_addr_set) {
         diag_printf("Raw load requires a memory address\n");
         return;
     }
+    info.filename = filename;
+    info.chan = chan;
+    info.mode = io_tab;
 #ifdef CYGPKG_REDBOOT_NETWORKING
-    if (mode == MODE_TFTP) {
-        res = tftp_stream_open(filename, &host, TFTP_OCTET, &err);    
-        if (res < 0) {
-            diag_printf("Can't load '%s': %s\n", filename, tftp_error(err));
-            return;
-        }
-        redboot_getc_init(tftp_stream_read, verbose, decompress);
-    }
-#endif
-#ifdef CYGPKG_REDBOOT_DISK
-    else if (mode == MODE_DISK) {
-        res = disk_stream_open(filename, &err);
-        if (res < 0) {
-
-            diag_printf("Can't load '%s': %s\n", filename, disk_error(err));
-            return;
-        }
-        redboot_getc_init(disk_stream_read, verbose, decompress);
-    }
+    info.server = &host;
 #endif
-#ifdef CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD
-    else if (mode == MODE_HTTP) {
-        res = http_stream_open(filename, &host, &err);
-        if (res < 0) {
-
-            diag_printf("Can't load '%s': %s\n", filename, http_error(err));
-            return;
-        }
-        redboot_getc_init(http_stream_read, verbose, decompress);
-    }
-#endif
-    else {
-        res = xyzModem_stream_open(filename, mode, chan, &err);
-        if (res < 0) {
-            diag_printf("Can't load '%s': %s\n", filename, xyzModem_error(err));
-            return;
-        }
-        // Suppress verbosity when using xyz modem download
-        redboot_getc_init(xyzModem_stream_read, 0 && verbose, decompress);
-
-        terminate = xyzModem_stream_terminate;
+    res = redboot_getc_init(&info, io, verbose, decompress);
+    if (res < 0) {
+        return;
     }
 
+    // Stream open, process the data
     if (raw) {
-        bool continue_load = false;
         unsigned char *mp = (unsigned char *)base;
         err = 0;
         while ((res = redboot_getc()) >= 0) {
 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
-            if (!continue_load && mp >= user_ram_end) {
+            if (mp >= user_ram_end) {
                 // Only if there is no need to stop the download
                 // before printing output can we ask confirmation
                 // questions.
-                if (terminate) {
-                    (*terminate)(xyzModem_abort, redboot_getc);
-                    diag_printf("*** Warning! RAW data spills over limit of user RAM at %p\nRedBoot does not believe this is in RAM\nUse TFTP for a chance to override this.\n",(void*)mp);
-                    err = -1;
-                    break;
-                } else {
-                    if (!verify_action("RAW data spills over limit of user RAM at %p\n"
-                                       "Continuing may cause a hang or crash", (void*)mp)) {
-                        err = -1;
-                        break;
-                    }
-                    // Don't ask again
-                    continue_load = true;
-                }
+                redboot_getc_terminate(true);
+                diag_printf("*** Abort! RAW data spills over limit of user RAM at %p\n",(void*)mp);
+                err = -1;
+                break;
             }
 #endif
             *mp++ = res;
         }
         end = (unsigned long) mp;
@@ -776,10 +717,11 @@ do_load(int argc, char *argv[])
         // Save load base/top
         load_address = base;
         load_address_end = end;
         entry_address = base;           // best guess
 
+        redboot_getc_terminate(false);
         if (0 == err)
             diag_printf("Raw file loaded %p-%p, assumed entry at %p\n", 
                         (void *)base, (void *)end, (void*)base);
     } else {
         // Read initial header - to determine file [image] type
@@ -792,38 +734,18 @@ do_load(int argc, char *argv[])
         }
         if (res >= 0) {
             redboot_getc_rewind();  // Restore header to stream
             // Treat data as some sort of executable image
             if (strncmp(&type[1], "ELF", 3) == 0) {
-                end = load_elf_image(redboot_getc, terminate, base);
+                end = load_elf_image(redboot_getc, base);
             } else if ((type[0] == 'S') &&
                        ((type[1] >= '0') && (type[1] <= '9'))) {
-		end = load_srec_image(redboot_getc, terminate, base);
+		end = load_srec_image(redboot_getc, base);
             } else {
                 diag_printf("Unrecognized image type: 0x%lx\n", *(unsigned long *)type);
             }
         }
     }
 
-    switch (mode) {
-#ifdef CYGPKG_REDBOOT_DISK
-      case MODE_DISK:
-        disk_stream_close(&err);
-	break;
-#endif
-#ifdef CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD
-      case MODE_HTTP:
-        http_stream_close(&err);
-	break;
-#endif
-#ifdef CYGPKG_REDBOOT_NETWORKING
-      case MODE_TFTP:
-        tftp_stream_close(&err);
-	break;
-#endif
-      default:
-        xyzModem_stream_close(&err);
-	break;
-    }
     redboot_getc_close();  // Clean up
     return;
 }
Index: redboot/current/src/xyzModem.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/src/xyzModem.c,v
retrieving revision 1.14
diff -u -5 -p -r1.14 xyzModem.c
--- redboot/current/src/xyzModem.c	23 May 2002 23:08:32 -0000	1.14
+++ redboot/current/src/xyzModem.c	1 Jul 2002 20:01:05 -0000
@@ -7,10 +7,11 @@
 //==========================================================================
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
 // Software Foundation; either version 2 or (at your option) any later version.
 //
@@ -314,39 +315,39 @@ xyzModem_get_hdr(void)
     // If we get here, the message passes [structural] muster
     return 0;
 }
 
 int 
-xyzModem_stream_open(char *filename, int mode, int chan, int *err)
+xyzModem_stream_open(connection_info_t *info, int *err)
 {
     int console_chan, stat;
     int retries = xyzModem_MAX_RETRIES;
     int crc_retries = xyzModem_MAX_RETRIES_WITH_CRC;
 
 //    ZM_DEBUG(zm_out = zm_out_start);
 #ifdef xyzModem_zmodem
-    if (mode == xyzModem_zmodem) {
+    if (info->mode == xyzModem_zmodem) {
         *err = xyzModem_noZmodem;
         return -1;
     }
 #endif
 
     // Set up the I/O channel.  Note: this allows for using a different port in the future
     console_chan = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
-    if (chan >= 0) {
-        CYGACC_CALL_IF_SET_CONSOLE_COMM(chan);
+    if (info->chan >= 0) {
+        CYGACC_CALL_IF_SET_CONSOLE_COMM(info->chan);
     } else {
         CYGACC_CALL_IF_SET_CONSOLE_COMM(console_chan);
     }
     xyz.__chan = CYGACC_CALL_IF_CONSOLE_PROCS();
     CYGACC_CALL_IF_SET_CONSOLE_COMM(console_chan);
     CYGACC_COMM_IF_CONTROL(*xyz.__chan, __COMMCTL_SET_TIMEOUT, xyzModem_CHAR_TIMEOUT);
     xyz.len = 0;
     xyz.crc_mode = true;
     xyz.at_eof = false;
     xyz.tx_ack = false;
-    xyz.mode = mode;
+    xyz.mode = info->mode;
     xyz.total_retries = 0;
     xyz.total_SOH = 0;
     xyz.total_STX = 0;
     xyz.total_CAN = 0;
 #ifdef USE_YMODEM_LENGTH
@@ -496,16 +497,15 @@ xyzModem_stream_close(int *err)
 //    ZM_DEBUG(zm_flush());
 }
 
 // Need to be able to clean out the input buffer, so have to take the
 // getc
-void xyzModem_stream_terminate(int method, int (*getc)(void))
+void xyzModem_stream_terminate(bool abort, int (*getc)(void))
 {
   int c;
 
-  switch (method) {
-    case xyzModem_abort:
+  if (abort) {
       ZM_DEBUG(zm_dprintf("!!!! TRANSFER ABORT !!!!\n"));
       switch (xyz.mode) {
 	case xyzModem_xmodem:
 	case xyzModem_ymodem:
 	  // The X/YMODEM Spec seems to suggest that multiple CAN followed by an equal
@@ -527,11 +527,11 @@ void xyzModem_stream_terminate(int metho
 	case xyzModem_zmodem:
 	  // Might support it some day I suppose.
 #endif
 	break;
       }
-    default:
+  } else {
       ZM_DEBUG(zm_dprintf("Engaging cleanup mode...\n"));
       // Consume any trailing crap left in the inbuffer from
       // previous recieved blocks. Since very few files are an exact multiple
       // of the transfer block size, there will almost always be some gunk here.
       // If we don't eat it now, RedBoot will think the user typed it.
@@ -540,11 +540,10 @@ void xyzModem_stream_terminate(int metho
       ZM_DEBUG(zm_dprintf("\n"));
       // Make a small delay to give terminal programs like minicom
       // time to get control again after their file transfer program
       // exits.
       CYGACC_CALL_IF_DELAY_US((cyg_int32)250000);
-      break;
   }
 }
 
 char *
 xyzModem_error(int err)
@@ -577,5 +576,13 @@ xyzModem_error(int err)
     default:
         return "Unknown error";
         break;
     }
 }
+
+//
+// RedBoot interface
+//
+GETC_IO_FUNCS(xyzModem_io, xyzModem_stream_open, xyzModem_stream_close,
+              xyzModem_stream_terminate, xyzModem_stream_read, xyzModem_error);
+RedBoot_load(xmodem, xyzModem_io, false, false);
+RedBoot_load(ymodem, xyzModem_io, false, false);
Index: redboot/current/src/xyzModem.h
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/src/xyzModem.h,v
retrieving revision 1.6
diff -u -5 -p -r1.6 xyzModem.h
--- redboot/current/src/xyzModem.h	23 May 2002 23:08:33 -0000	1.6
+++ redboot/current/src/xyzModem.h	1 Jul 2002 20:01:15 -0000
@@ -7,10 +7,11 @@
 //==========================================================================
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
 // Software Foundation; either version 2 or (at your option) any later version.
 //
@@ -70,12 +71,14 @@
 #define xyzModem_sequence -8
 
 #define xyzModem_close 1
 #define xyzModem_abort 2
 
-int   xyzModem_stream_open(char *filename, int mode, int chan, int *err);    
+int   xyzModem_stream_open(connection_info_t *info, int *err);    
 void  xyzModem_stream_close(int *err);    
 void  xyzModem_stream_terminate(int method, int (*getc)(void));    
 int   xyzModem_stream_read(char *buf, int size, int *err);    
 char *xyzModem_error(int err);
+
+extern getc_io_funcs_t xyzModem_io;
 
 #endif // _XYZMODEM_H_
Index: redboot/current/src/fs/disk.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/src/fs/disk.c,v
retrieving revision 1.8
diff -u -5 -p -r1.8 disk.c
--- redboot/current/src/fs/disk.c	23 May 2002 23:08:33 -0000	1.8
+++ redboot/current/src/fs/disk.c	1 Jul 2002 20:01:31 -0000
@@ -7,10 +7,11 @@
 //==========================================================================
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
 // Software Foundation; either version 2 or (at your option) any later version.
 //
@@ -354,13 +355,14 @@ do_disks(int argc, char *argv[])
 
 static void *fileptr;
 static partition_t *file_part;
 
 externC int 
-disk_stream_open(char *filename, int *err)
+disk_stream_open(connection_info_t *info, int *err)
 {
     const char *filepath;
+    char *filename = info->filename;
 
     // The filename is in <disk>:<path> format.
     // Convert to a partition and path.
     if (!disk_parse_filename(filename, &file_part, &filepath)) {
 	*err = diskerr_badname;
@@ -423,5 +425,11 @@ disk_error(int err)
         return "Unknown error";
         break;
     }
 }
 
+//
+// RedBoot interface
+//
+GETC_IO_FUNCS(disk_io, disk_stream_open, disk_stream_close,
+              0, disk_stream_read, disk_error);
+RedBoot_load(disk, disk_io, true, true);
Index: redboot/current/src/net/http_client.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/src/net/http_client.c,v
retrieving revision 1.1
diff -u -5 -p -r1.1 http_client.c
--- redboot/current/src/net/http_client.c	23 May 2002 23:08:35 -0000	1.1
+++ redboot/current/src/net/http_client.c	1 Jul 2002 20:01:39 -0000
@@ -7,10 +7,11 @@
 //==========================================================================
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
 // Software Foundation; either version 2 or (at your option) any later version.
 //
@@ -77,40 +78,37 @@ min(int a, int b)
     else
         return b;
 }
 
 int
-http_stream_open(char *filename,
-                 struct sockaddr_in *server,
-                 int *err)
+http_stream_open(connection_info_t *info, int *err)
 {
     int res;
     struct _stream *s = &http_stream;
 
-    server->sin_port = 80;  // HTTP port
-    if ((res = __tcp_open(&s->sock, server, get_port++, 5000, err)) < 0) {
+    info->server->sin_port = 80;  // HTTP port
+    if ((res = __tcp_open(&s->sock, info->server, get_port++, 5000, err)) < 0) {
         *err = HTTP_OPEN;
         return -1;
     }
-    diag_sprintf(s->data, "GET %s HTTP 1.0\r\n\r\n", filename);
+    diag_sprintf(s->data, "GET %s HTTP 1.0\r\n\r\n", info->filename);
     __tcp_write_block(&s->sock, s->data, strlen(s->data));    
     s->avail = 0;
     s->open = true;
     s->pos = 0;
     return 0;
 }
 
-int
+void
 http_stream_close(int *err)
 {    
     struct _stream *s = &http_stream;
 
     if (s->open) {
         __tcp_close(&s->sock);
         s->open = false;    
     }
-    return 0;
 }
 
 int
 http_stream_read(char *buf,
                  int len,
@@ -232,5 +230,12 @@ http_error(int err)
     case HTTP_IO:
         return "I/O error";
     }
     return errmsg;
 }
+
+//
+// RedBoot interface
+//
+GETC_IO_FUNCS(http_io, http_stream_open, http_stream_close,
+              0, http_stream_read, http_error);
+RedBoot_load(http, http_io, true, true);
Index: redboot/current/src/net/tftp_client.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/redboot/current/src/net/tftp_client.c,v
retrieving revision 1.9
diff -u -5 -p -r1.9 tftp_client.c
--- redboot/current/src/net/tftp_client.c	23 May 2002 23:08:36 -0000	1.9
+++ redboot/current/src/net/tftp_client.c	1 Jul 2002 20:01:47 -0000
@@ -7,10 +7,11 @@
 //==========================================================================
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002 Gary Thomas
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
 // Software Foundation; either version 2 or (at your option) any later version.
 //
@@ -60,136 +61,10 @@
 #include <net/tftp_support.h>
 
 // So we remember which ports have been used
 static int get_port = 7700;
 
-#if 0 // No longer used
-//
-// Read a file from a host into a local buffer.  Returns the
-// number of bytes actually read, or (-1) if an error occurs.
-// On error, *err will hold the reason.
-//
-int
-tftp_get(char *filename,
-         struct sockaddr_in *server,
-         char *buf,
-         int len,
-         int mode,
-         int *err)
-{
-    int res = 0;
-    int actual_len, data_len, recv_len;
-    struct sockaddr_in local_addr, from_addr;
-    char data[SEGSIZE+sizeof(struct tftphdr)];
-    struct tftphdr *hdr = (struct tftphdr *)data;
-    char *cp, *fp;
-    struct timeval timeout;
-    int last_good_block = 0;
-    int total_timeouts = 0;
-
-    *err = 0;  // Just in case
-
-    // Create initial request
-    hdr->th_opcode = htons(RRQ);  // Read file
-    cp = (char *)&hdr->th_stuff;
-    fp = filename;
-    while (*fp) *cp++ = *fp++;
-    *cp++ = '\0';
-    if (mode == TFTP_NETASCII) {
-        fp = "NETASCII";
-    } else if (mode == TFTP_OCTET) {
-        fp = "OCTET";
-    } else {
-        *err = TFTP_INVALID;
-        return -1;
-    }
-    while (*fp) *cp++ = *fp++;
-    *cp++ = '\0';
-
-    memset((char *)&local_addr, 0, sizeof(local_addr));
-    local_addr.sin_family = AF_INET;
-    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-    local_addr.sin_port = htons(get_port++);
-
-    if (server->sin_port == 0) {
-        server->sin_port = htons(TFTP_PORT);
-    }
-
-    // Send request
-    if (__udp_sendto(data, sizeof(data), server, &local_addr) < 0) {
-        // Problem sending request
-        *err = TFTP_NETERR;
-        return -1;
-    }
-
-    // Read data
-    fp = buf;
-    while (true) {
-        timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
-        timeout.tv_usec = 0;
-        recv_len = sizeof(data);
-        if ((data_len = __udp_recvfrom(&data[0], recv_len, &from_addr, &local_addr,  &timeout)) < 0) {
-            // No data, try again
-            if ((++total_timeouts > TFTP_TIMEOUT_MAX) || (last_good_block == 0)) {
-                // Timeout - no data received
-                *err = TFTP_TIMEOUT;
-                return -1;
-            }
-            // Try resending last ACK
-            hdr->th_opcode = htons(ACK);
-            hdr->th_block = htons(last_good_block);
-            if (__udp_sendto(data, 4 /* FIXME */, &from_addr, &local_addr) < 0) {
-                // Problem sending request
-                *err = TFTP_NETERR;
-                return -1;
-            }
-        } else {
-            if (ntohs(hdr->th_opcode) == DATA) {
-                actual_len = 0;
-                if (ntohs(hdr->th_block) == (last_good_block+1)) {
-                    // Consume this data
-                    cp = hdr->th_data;
-                    data_len -= 4;  /* Sizeof TFTP header */
-                    actual_len = data_len;
-                    res += actual_len;
-                    while (data_len-- > 0) {
-                        if (len-- > 0) {
-                            *fp++ = *cp++;
-                        } else {
-                            // Buffer overflow
-                            *err = TFTP_TOOLARGE;
-                            return -1;
-                        }
-                    }
-                    last_good_block++;
-                }
-                // Send out the ACK
-                hdr->th_opcode = htons(ACK);
-                hdr->th_block = htons(last_good_block);
-                if (__udp_sendto(data, 4 /* FIXME */, &from_addr, &local_addr) < 0) {
-                    // Problem sending ACK
-                    *err = TFTP_NETERR;
-                    return -1;
-                }
-                if ((actual_len >= 0) && (actual_len < SEGSIZE)) {
-                    // End of data
-                    return res;
-                }
-            } else 
-            if (ntohs(hdr->th_opcode) == ERROR) {
-                *err = ntohs(hdr->th_code);
-                return -1;
-            } else {
-                // What kind of packet is this?
-                *err = TFTP_PROTOCOL;
-                return -1;
-            }
-        }
-    }
-}
-#endif
-
 static struct {
     bool open;
     int  total_timeouts;
     int  last_good_block;
     int  avail, actual_len;
@@ -197,13 +72,11 @@ static struct {
     char data[SEGSIZE+sizeof(struct tftphdr)];
     char *bufp;
 } tftp_stream;
 
 int
-tftp_stream_open(char *filename,
-                 struct sockaddr_in *server,
-                 int mode,
+tftp_stream_open(connection_info_t *info,
                  int *err)
 {
     struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;
     char *cp, *fp;
     char test_buf;
@@ -214,38 +87,33 @@ tftp_stream_open(char *filename,
     }
 
     // Create initial request
     hdr->th_opcode = htons(RRQ);  // Read file
     cp = (char *)&hdr->th_stuff;
-    fp = filename;
+    fp = info->filename;
     while (*fp) *cp++ = *fp++;
     *cp++ = '\0';
-    if (mode == TFTP_NETASCII) {
-        fp = "NETASCII";
-    } else if (mode == TFTP_OCTET) {
-        fp = "OCTET";
-    } else {
-        *err = TFTP_INVALID;
-        return -1;
-    }
+    // Since this is used for downloading data, OCTET (binary) is the
+    // only mode that makes sense.
+    fp = "OCTET";
     while (*fp) *cp++ = *fp++;
     *cp++ = '\0';
 
     memset((char *)&tftp_stream.local_addr, 0, sizeof(tftp_stream.local_addr));
     tftp_stream.local_addr.sin_family = AF_INET;
     tftp_stream.local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
     tftp_stream.local_addr.sin_port = htons(get_port++);
 
-    if (server->sin_port == 0) {
-        server->sin_port = htons(TFTP_PORT);
+    if (info->server->sin_port == 0) {
+        info->server->sin_port = htons(TFTP_PORT);
     }
 
     // Send request - note: RFC 1350 (TFTP rev 2) indicates that this should be
     // only as long as required to hold the request, with the nul terminator.
     // Some servers silently go to lunch if the request is not the correct size.
     if (__udp_sendto(tftp_stream.data, cp-(char *)hdr, 
-                     server, &tftp_stream.local_addr) < 0) {
+                     info->server, &tftp_stream.local_addr) < 0) {
         // Problem sending request
         *err = TFTP_NETERR;
         return -1;
     }
 
@@ -267,15 +135,14 @@ tftp_stream_open(char *filename,
         tftp_stream.open = false;
         return -1; // Couldn't read
     }
 }
 
-int
+void
 tftp_stream_close(int *err)
 {
     tftp_stream.open = false;
-    return 0;
 }
 
 int
 tftp_stream_read(char *buf,
                  int len,
@@ -380,5 +247,13 @@ tftp_error(int err)
     case TFTP_TOOLARGE:
         return "file is larger than buffer";
     }
     return errmsg;
 }
+
+//
+// RedBoot interface
+//
+GETC_IO_FUNCS(tftp_io, tftp_stream_open, tftp_stream_close,
+              0, tftp_stream_read, tftp_error);
+RedBoot_load(tftp, tftp_io, true, true);
+




Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]