changeset 228:e1b642d73533

Improve load command - make I/O methods table driven.
author gthomas
date Mon, 01 Jul 2002 20:55:25 +0000
parents bded64db11ce
children ff3465255c3a
files packages/redboot/current/ChangeLog packages/redboot/current/cdl/redboot.cdl packages/redboot/current/include/net/http.h packages/redboot/current/include/net/tftp_support.h packages/redboot/current/include/redboot.h packages/redboot/current/src/fs/disk.c packages/redboot/current/src/load.c packages/redboot/current/src/net/http_client.c packages/redboot/current/src/net/tftp_client.c packages/redboot/current/src/xyzModem.c packages/redboot/current/src/xyzModem.h
diffstat 11 files changed, 372 insertions(+), 505 deletions(-) [+]
line wrap: on
line diff
--- a/packages/redboot/current/ChangeLog
+++ b/packages/redboot/current/ChangeLog
@@ -1,3 +1,16 @@
+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
--- a/packages/redboot/current/cdl/redboot.cdl
+++ b/packages/redboot/current/cdl/redboot.cdl
@@ -9,6 +9,7 @@
 ## -------------------------------------------
 ## 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
@@ -151,8 +152,8 @@ cdl_package CYGPKG_REDBOOT {
                      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
@@ -169,8 +170,8 @@ cdl_package CYGPKG_REDBOOT {
         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"
@@ -188,7 +189,7 @@ cdl_package CYGPKG_REDBOOT {
             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"
         }
--- a/packages/redboot/current/include/net/http.h
+++ b/packages/redboot/current/include/net/http.h
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // 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
@@ -55,9 +56,9 @@
 #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
@@ -65,4 +66,5 @@ extern char *http_error(int err);
 #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_
--- a/packages/redboot/current/include/net/tftp_support.h
+++ b/packages/redboot/current/include/net/tftp_support.h
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // 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
@@ -83,17 +84,17 @@
  * Client support
  */
 
-extern int   tftp_get(char *, struct sockaddr_in *, char *, int, int, int *);
+extern int   tftp_stream_open(connection_info_t *info, int *err);
+extern int   tftp_stream_read(char *buf, int len, int *err);
+extern void  tftp_stream_close(int *err);
 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_read(char *buf, int len, int *err);
-extern int   tftp_stream_close(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_
--- a/packages/redboot/current/include/redboot.h
+++ b/packages/redboot/current/include/redboot.h
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // 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
@@ -64,7 +65,6 @@
 
 #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);
@@ -149,9 +149,45 @@ externC char *flash_lookup_alias(char *a
 #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 {
@@ -231,7 +267,7 @@ struct idle_tab_entry _idle_tab_##_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 {
@@ -256,12 +292,6 @@ externC bool scan_opts(int argc, char *a
                        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)
--- a/packages/redboot/current/src/fs/disk.c
+++ b/packages/redboot/current/src/fs/disk.c
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // 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
@@ -356,9 +357,10 @@ 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.
@@ -425,3 +427,9 @@ disk_error(int err)
     }
 }
 
+//
+// 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);
--- a/packages/redboot/current/src/load.c
+++ b/packages/redboot/current/src/load.c
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // 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
@@ -58,13 +59,43 @@
 #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;
@@ -77,35 +108,152 @@ struct {
 #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"
+//
+// 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
-#ifdef CYGPKG_REDBOOT_DISK
-                      " | disk"
-#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;
+}
+
+static void
+redboot_getc_rewind(void)
+{
+    getc_info.bufp = getc_info.buf;
+    getc_info.avail = getc_info.len;
+}
 
-// Exported CLI function
-RedBoot_cmd("load", 
-            "Load a file", 
-            usage,
-            do_load 
-    );
+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)
 {
@@ -124,8 +272,11 @@ static int
 }
 #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;
@@ -218,16 +369,9 @@ load_elf_image(getc_t getc, terminate_t 
             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) {
@@ -294,9 +438,8 @@ static long
 // 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;
@@ -310,7 +453,7 @@ load_srec_image(getc_t getc, terminate_t
     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;
@@ -319,7 +462,7 @@ load_srec_image(getc_t getc, terminate_t
         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;
         }
@@ -348,14 +491,9 @@ load_srec_image(getc_t getc, terminate_t
             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);
@@ -369,7 +507,7 @@ load_srec_image(getc_t getc, terminate_t
             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;
@@ -385,7 +523,7 @@ load_srec_image(getc_t getc, terminate_t
             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);
@@ -396,7 +534,7 @@ load_srec_image(getc_t getc, terminate_t
 
             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;
@@ -407,138 +545,19 @@ load_srec_image(getc_t getc, terminate_t
 }
 
 //
-// 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;
-}
+//   -d - Decompress data [packed via 'zlib']
 #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);
-        }
-    }
-#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;
@@ -557,7 +576,9 @@ do_load(int argc, char *argv[])
     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));
@@ -566,11 +587,6 @@ do_load(int argc, char *argv[])
     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");
@@ -616,77 +632,45 @@ do_load(int argc, char *argv[])
         }
     }
 #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;
+        }
+        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);
             }
-#endif
-        } else {
-            diag_printf("Invalid 'mode': %s\n", mode_str);
+            diag_printf("\n");
+        }
+        if (!io) {
             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
-            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
     }
-#endif
 #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS
     if (base_addr_set &&
         ((base < (unsigned long)user_ram_start) ||
@@ -699,74 +683,31 @@ do_load(int argc, char *argv[])
         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;
@@ -778,6 +719,7 @@ do_load(int argc, char *argv[])
         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);
@@ -794,36 +736,16 @@ do_load(int argc, char *argv[])
             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;
 }
--- a/packages/redboot/current/src/net/http_client.c
+++ b/packages/redboot/current/src/net/http_client.c
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // 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
@@ -79,19 +80,17 @@ min(int a, int 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;
@@ -99,7 +98,7 @@ http_stream_open(char *filename,
     return 0;
 }
 
-int
+void
 http_stream_close(int *err)
 {    
     struct _stream *s = &http_stream;
@@ -108,7 +107,6 @@ http_stream_close(int *err)
         __tcp_close(&s->sock);
         s->open = false;    
     }
-    return 0;
 }
 
 int
@@ -234,3 +232,10 @@ http_error(int err)
     }
     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);
--- a/packages/redboot/current/src/net/tftp_client.c
+++ b/packages/redboot/current/src/net/tftp_client.c
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // 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
@@ -62,132 +63,6 @@
 // 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;
@@ -199,9 +74,7 @@ static struct {
 } 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;
@@ -216,17 +89,12 @@ 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';
 
@@ -235,15 +103,15 @@ tftp_stream_open(char *filename,
     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;
@@ -269,11 +137,10 @@ tftp_stream_open(char *filename,
     }
 }
 
-int
+void
 tftp_stream_close(int *err)
 {
     tftp_stream.open = false;
-    return 0;
 }
 
 int
@@ -382,3 +249,11 @@ tftp_error(int err)
     }
     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);
+
--- a/packages/redboot/current/src/xyzModem.c
+++ b/packages/redboot/current/src/xyzModem.c
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // 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
@@ -316,7 +317,7 @@ xyzModem_get_hdr(void)
 }
 
 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;
@@ -324,7 +325,7 @@ xyzModem_stream_open(char *filename, int
 
 //    ZM_DEBUG(zm_out = zm_out_start);
 #ifdef xyzModem_zmodem
-    if (mode == xyzModem_zmodem) {
+    if (info->mode == xyzModem_zmodem) {
         *err = xyzModem_noZmodem;
         return -1;
     }
@@ -332,8 +333,8 @@ xyzModem_stream_open(char *filename, int
 
     // 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);
     }
@@ -344,7 +345,7 @@ xyzModem_stream_open(char *filename, int
     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;
@@ -498,12 +499,11 @@ xyzModem_stream_close(int *err)
 
 // 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:
@@ -529,7 +529,7 @@ void xyzModem_stream_terminate(int metho
 #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
@@ -542,7 +542,6 @@ void xyzModem_stream_terminate(int metho
       // time to get control again after their file transfer program
       // exits.
       CYGACC_CALL_IF_DELAY_US((cyg_int32)250000);
-      break;
   }
 }
 
@@ -579,3 +578,11 @@ xyzModem_error(int err)
         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);
--- a/packages/redboot/current/src/xyzModem.h
+++ b/packages/redboot/current/src/xyzModem.h
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // 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
@@ -72,10 +73,12 @@
 #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_