diff options
Diffstat (limited to 'qemu/roms/u-boot/common/xyzModem.c')
-rw-r--r-- | qemu/roms/u-boot/common/xyzModem.c | 817 |
1 files changed, 0 insertions, 817 deletions
diff --git a/qemu/roms/u-boot/common/xyzModem.c b/qemu/roms/u-boot/common/xyzModem.c deleted file mode 100644 index 39f7d17a7..000000000 --- a/qemu/roms/u-boot/common/xyzModem.c +++ /dev/null @@ -1,817 +0,0 @@ -/* - *========================================================================== - * - * xyzModem.c - * - * RedBoot stream handler for xyzModem protocol - * - *========================================================================== - * SPDX-License-Identifier: eCos-2.0 - *========================================================================== - *#####DESCRIPTIONBEGIN#### - * - * Author(s): gthomas - * Contributors: gthomas, tsmith, Yoshinori Sato - * Date: 2000-07-14 - * Purpose: - * Description: - * - * This code is part of RedBoot (tm). - * - *####DESCRIPTIONEND#### - * - *========================================================================== - */ -#include <common.h> -#include <xyzModem.h> -#include <stdarg.h> -#include <crc.h> - -/* Assumption - run xyzModem protocol over the console port */ - -/* Values magic to the protocol */ -#define SOH 0x01 -#define STX 0x02 -#define EOT 0x04 -#define ACK 0x06 -#define BSP 0x08 -#define NAK 0x15 -#define CAN 0x18 -#define EOF 0x1A /* ^Z for DOS officionados */ - -#define USE_YMODEM_LENGTH - -/* Data & state local to the protocol */ -static struct -{ -#ifdef REDBOOT - hal_virtual_comm_table_t *__chan; -#else - int *__chan; -#endif - unsigned char pkt[1024], *bufp; - unsigned char blk, cblk, crc1, crc2; - unsigned char next_blk; /* Expected block */ - int len, mode, total_retries; - int total_SOH, total_STX, total_CAN; - bool crc_mode, at_eof, tx_ack; -#ifdef USE_YMODEM_LENGTH - unsigned long file_length, read_length; -#endif -} xyz; - -#define xyzModem_CHAR_TIMEOUT 2000 /* 2 seconds */ -#define xyzModem_MAX_RETRIES 20 -#define xyzModem_MAX_RETRIES_WITH_CRC 10 -#define xyzModem_CAN_COUNT 3 /* Wait for 3 CAN before quitting */ - - -#ifndef REDBOOT /*SB */ -typedef int cyg_int32; -static int -CYGACC_COMM_IF_GETC_TIMEOUT (char chan, char *c) -{ -#define DELAY 20 - unsigned long counter = 0; - while (!tstc () && (counter < xyzModem_CHAR_TIMEOUT * 1000 / DELAY)) - { - udelay (DELAY); - counter++; - } - if (tstc ()) - { - *c = getc (); - return 1; - } - return 0; -} - -static void -CYGACC_COMM_IF_PUTC (char x, char y) -{ - putc (y); -} - -/* Validate a hex character */ -__inline__ static bool -_is_hex (char c) -{ - return (((c >= '0') && (c <= '9')) || - ((c >= 'A') && (c <= 'F')) || ((c >= 'a') && (c <= 'f'))); -} - -/* Convert a single hex nibble */ -__inline__ static int -_from_hex (char c) -{ - int ret = 0; - - if ((c >= '0') && (c <= '9')) - { - ret = (c - '0'); - } - else if ((c >= 'a') && (c <= 'f')) - { - ret = (c - 'a' + 0x0a); - } - else if ((c >= 'A') && (c <= 'F')) - { - ret = (c - 'A' + 0x0A); - } - return ret; -} - -/* Convert a character to lower case */ -__inline__ static char -_tolower (char c) -{ - if ((c >= 'A') && (c <= 'Z')) - { - c = (c - 'A') + 'a'; - } - return c; -} - -/* Parse (scan) a number */ -static bool -parse_num (char *s, unsigned long *val, char **es, char *delim) -{ - bool first = true; - int radix = 10; - char c; - unsigned long result = 0; - int digit; - - while (*s == ' ') - s++; - while (*s) - { - if (first && (s[0] == '0') && (_tolower (s[1]) == 'x')) - { - radix = 16; - s += 2; - } - first = false; - c = *s++; - if (_is_hex (c) && ((digit = _from_hex (c)) < radix)) - { - /* Valid digit */ -#ifdef CYGPKG_HAL_MIPS - /* FIXME: tx49 compiler generates 0x2539018 for MUL which */ - /* isn't any good. */ - if (16 == radix) - result = result << 4; - else - result = 10 * result; - result += digit; -#else - result = (result * radix) + digit; -#endif - } - else - { - if (delim != (char *) 0) - { - /* See if this character is one of the delimiters */ - char *dp = delim; - while (*dp && (c != *dp)) - dp++; - if (*dp) - break; /* Found a good delimiter */ - } - return false; /* Malformatted number */ - } - } - *val = result; - if (es != (char **) 0) - { - *es = s; - } - return true; -} - -#endif - -#define USE_SPRINTF -#ifdef DEBUG -#ifndef USE_SPRINTF -/* - * Note: this debug setup only works if the target platform has two serial ports - * available so that the other one (currently only port 1) can be used for debug - * messages. - */ -static int -zm_dprintf (char *fmt, ...) -{ - int cur_console; - va_list args; - - va_start (args, fmt); -#ifdef REDBOOT - cur_console = - CYGACC_CALL_IF_SET_CONSOLE_COMM - (CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT); - CYGACC_CALL_IF_SET_CONSOLE_COMM (1); -#endif - diag_vprintf (fmt, args); -#ifdef REDBOOT - CYGACC_CALL_IF_SET_CONSOLE_COMM (cur_console); -#endif -} - -static void -zm_flush (void) -{ -} - -#else -/* - * Note: this debug setup works by storing the strings in a fixed buffer - */ -#define FINAL -#ifdef FINAL -static char *zm_out = (char *) 0x00380000; -static char *zm_out_start = (char *) 0x00380000; -#else -static char zm_buf[8192]; -static char *zm_out = zm_buf; -static char *zm_out_start = zm_buf; - -#endif -static int -zm_dprintf (char *fmt, ...) -{ - int len; - va_list args; - - va_start (args, fmt); - len = diag_vsprintf (zm_out, fmt, args); - zm_out += len; - return len; -} - -static void -zm_flush (void) -{ -#ifdef REDBOOT - char *p = zm_out_start; - while (*p) - mon_write_char (*p++); -#endif - zm_out = zm_out_start; -} -#endif - -static void -zm_dump_buf (void *buf, int len) -{ -#ifdef REDBOOT - diag_vdump_buf_with_offset (zm_dprintf, buf, len, 0); -#else - -#endif -} - -static unsigned char zm_buf[2048]; -static unsigned char *zm_bp; - -static void -zm_new (void) -{ - zm_bp = zm_buf; -} - -static void -zm_save (unsigned char c) -{ - *zm_bp++ = c; -} - -static void -zm_dump (int line) -{ - zm_dprintf ("Packet at line: %d\n", line); - zm_dump_buf (zm_buf, zm_bp - zm_buf); -} - -#define ZM_DEBUG(x) x -#else -#define ZM_DEBUG(x) -#endif - -/* Wait for the line to go idle */ -static void -xyzModem_flush (void) -{ - int res; - char c; - while (true) - { - res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c); - if (!res) - return; - } -} - -static int -xyzModem_get_hdr (void) -{ - char c; - int res; - bool hdr_found = false; - int i, can_total, hdr_chars; - unsigned short cksum; - - ZM_DEBUG (zm_new ()); - /* Find the start of a header */ - can_total = 0; - hdr_chars = 0; - - if (xyz.tx_ack) - { - CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK); - xyz.tx_ack = false; - } - while (!hdr_found) - { - res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c); - ZM_DEBUG (zm_save (c)); - if (res) - { - hdr_chars++; - switch (c) - { - case SOH: - xyz.total_SOH++; - case STX: - if (c == STX) - xyz.total_STX++; - hdr_found = true; - break; - case CAN: - xyz.total_CAN++; - ZM_DEBUG (zm_dump (__LINE__)); - if (++can_total == xyzModem_CAN_COUNT) - { - return xyzModem_cancel; - } - else - { - /* Wait for multiple CAN to avoid early quits */ - break; - } - case EOT: - /* EOT only supported if no noise */ - if (hdr_chars == 1) - { - CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK); - ZM_DEBUG (zm_dprintf ("ACK on EOT #%d\n", __LINE__)); - ZM_DEBUG (zm_dump (__LINE__)); - return xyzModem_eof; - } - default: - /* Ignore, waiting for start of header */ - ; - } - } - else - { - /* Data stream timed out */ - xyzModem_flush (); /* Toss any current input */ - ZM_DEBUG (zm_dump (__LINE__)); - CYGACC_CALL_IF_DELAY_US ((cyg_int32) 250000); - return xyzModem_timeout; - } - } - - /* Header found, now read the data */ - res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.blk); - ZM_DEBUG (zm_save (xyz.blk)); - if (!res) - { - ZM_DEBUG (zm_dump (__LINE__)); - return xyzModem_timeout; - } - res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.cblk); - ZM_DEBUG (zm_save (xyz.cblk)); - if (!res) - { - ZM_DEBUG (zm_dump (__LINE__)); - return xyzModem_timeout; - } - xyz.len = (c == SOH) ? 128 : 1024; - xyz.bufp = xyz.pkt; - for (i = 0; i < xyz.len; i++) - { - res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c); - ZM_DEBUG (zm_save (c)); - if (res) - { - xyz.pkt[i] = c; - } - else - { - ZM_DEBUG (zm_dump (__LINE__)); - return xyzModem_timeout; - } - } - res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.crc1); - ZM_DEBUG (zm_save (xyz.crc1)); - if (!res) - { - ZM_DEBUG (zm_dump (__LINE__)); - return xyzModem_timeout; - } - if (xyz.crc_mode) - { - res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.crc2); - ZM_DEBUG (zm_save (xyz.crc2)); - if (!res) - { - ZM_DEBUG (zm_dump (__LINE__)); - return xyzModem_timeout; - } - } - ZM_DEBUG (zm_dump (__LINE__)); - /* Validate the message */ - if ((xyz.blk ^ xyz.cblk) != (unsigned char) 0xFF) - { - ZM_DEBUG (zm_dprintf - ("Framing error - blk: %x/%x/%x\n", xyz.blk, xyz.cblk, - (xyz.blk ^ xyz.cblk))); - ZM_DEBUG (zm_dump_buf (xyz.pkt, xyz.len)); - xyzModem_flush (); - return xyzModem_frame; - } - /* Verify checksum/CRC */ - if (xyz.crc_mode) - { - cksum = cyg_crc16 (xyz.pkt, xyz.len); - if (cksum != ((xyz.crc1 << 8) | xyz.crc2)) - { - ZM_DEBUG (zm_dprintf ("CRC error - recvd: %02x%02x, computed: %x\n", - xyz.crc1, xyz.crc2, cksum & 0xFFFF)); - return xyzModem_cksum; - } - } - else - { - cksum = 0; - for (i = 0; i < xyz.len; i++) - { - cksum += xyz.pkt[i]; - } - if (xyz.crc1 != (cksum & 0xFF)) - { - ZM_DEBUG (zm_dprintf - ("Checksum error - recvd: %x, computed: %x\n", xyz.crc1, - cksum & 0xFF)); - return xyzModem_cksum; - } - } - /* If we get here, the message passes [structural] muster */ - return 0; -} - -int -xyzModem_stream_open (connection_info_t * info, int *err) -{ -#ifdef REDBOOT - int console_chan; -#endif - int stat = 0; - int retries = xyzModem_MAX_RETRIES; - int crc_retries = xyzModem_MAX_RETRIES_WITH_CRC; - -/* ZM_DEBUG(zm_out = zm_out_start); */ -#ifdef xyzModem_zmodem - if (info->mode == xyzModem_zmodem) - { - *err = xyzModem_noZmodem; - return -1; - } -#endif - -#ifdef REDBOOT - /* 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 (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); -#else -/* TODO: CHECK ! */ - int dummy = 0; - xyz.__chan = &dummy; -#endif - xyz.len = 0; - xyz.crc_mode = true; - xyz.at_eof = false; - xyz.tx_ack = false; - xyz.mode = info->mode; - xyz.total_retries = 0; - xyz.total_SOH = 0; - xyz.total_STX = 0; - xyz.total_CAN = 0; -#ifdef USE_YMODEM_LENGTH - xyz.read_length = 0; - xyz.file_length = 0; -#endif - - CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK)); - - if (xyz.mode == xyzModem_xmodem) - { - /* X-modem doesn't have an information header - exit here */ - xyz.next_blk = 1; - return 0; - } - - while (retries-- > 0) - { - stat = xyzModem_get_hdr (); - if (stat == 0) - { - /* Y-modem file information header */ - if (xyz.blk == 0) - { -#ifdef USE_YMODEM_LENGTH - /* skip filename */ - while (*xyz.bufp++); - /* get the length */ - parse_num ((char *) xyz.bufp, &xyz.file_length, NULL, " "); -#endif - /* The rest of the file name data block quietly discarded */ - xyz.tx_ack = true; - } - xyz.next_blk = 1; - xyz.len = 0; - return 0; - } - else if (stat == xyzModem_timeout) - { - if (--crc_retries <= 0) - xyz.crc_mode = false; - CYGACC_CALL_IF_DELAY_US (5 * 100000); /* Extra delay for startup */ - CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK)); - xyz.total_retries++; - ZM_DEBUG (zm_dprintf ("NAK (%d)\n", __LINE__)); - } - if (stat == xyzModem_cancel) - { - break; - } - } - *err = stat; - ZM_DEBUG (zm_flush ()); - return -1; -} - -int -xyzModem_stream_read (char *buf, int size, int *err) -{ - int stat, total, len; - int retries; - - total = 0; - stat = xyzModem_cancel; - /* Try and get 'size' bytes into the buffer */ - while (!xyz.at_eof && (size > 0)) - { - if (xyz.len == 0) - { - retries = xyzModem_MAX_RETRIES; - while (retries-- > 0) - { - stat = xyzModem_get_hdr (); - if (stat == 0) - { - if (xyz.blk == xyz.next_blk) - { - xyz.tx_ack = true; - ZM_DEBUG (zm_dprintf - ("ACK block %d (%d)\n", xyz.blk, __LINE__)); - xyz.next_blk = (xyz.next_blk + 1) & 0xFF; - -#if defined(xyzModem_zmodem) || defined(USE_YMODEM_LENGTH) - if (xyz.mode == xyzModem_xmodem || xyz.file_length == 0) - { -#else - if (1) - { -#endif - /* Data blocks can be padded with ^Z (EOF) characters */ - /* This code tries to detect and remove them */ - if ((xyz.bufp[xyz.len - 1] == EOF) && - (xyz.bufp[xyz.len - 2] == EOF) && - (xyz.bufp[xyz.len - 3] == EOF)) - { - while (xyz.len - && (xyz.bufp[xyz.len - 1] == EOF)) - { - xyz.len--; - } - } - } - -#ifdef USE_YMODEM_LENGTH - /* - * See if accumulated length exceeds that of the file. - * If so, reduce size (i.e., cut out pad bytes) - * Only do this for Y-modem (and Z-modem should it ever - * be supported since it can fall back to Y-modem mode). - */ - if (xyz.mode != xyzModem_xmodem && 0 != xyz.file_length) - { - xyz.read_length += xyz.len; - if (xyz.read_length > xyz.file_length) - { - xyz.len -= (xyz.read_length - xyz.file_length); - } - } -#endif - break; - } - else if (xyz.blk == ((xyz.next_blk - 1) & 0xFF)) - { - /* Just re-ACK this so sender will get on with it */ - CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK); - continue; /* Need new header */ - } - else - { - stat = xyzModem_sequence; - } - } - if (stat == xyzModem_cancel) - { - break; - } - if (stat == xyzModem_eof) - { - CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK); - ZM_DEBUG (zm_dprintf ("ACK (%d)\n", __LINE__)); - if (xyz.mode == xyzModem_ymodem) - { - CYGACC_COMM_IF_PUTC (*xyz.__chan, - (xyz.crc_mode ? 'C' : NAK)); - xyz.total_retries++; - ZM_DEBUG (zm_dprintf ("Reading Final Header\n")); - stat = xyzModem_get_hdr (); - CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK); - ZM_DEBUG (zm_dprintf ("FINAL ACK (%d)\n", __LINE__)); - } - xyz.at_eof = true; - break; - } - CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK)); - xyz.total_retries++; - ZM_DEBUG (zm_dprintf ("NAK (%d)\n", __LINE__)); - } - if (stat < 0) - { - *err = stat; - xyz.len = -1; - return total; - } - } - /* Don't "read" data from the EOF protocol package */ - if (!xyz.at_eof) - { - len = xyz.len; - if (size < len) - len = size; - memcpy (buf, xyz.bufp, len); - size -= len; - buf += len; - total += len; - xyz.len -= len; - xyz.bufp += len; - } - } - return total; -} - -void -xyzModem_stream_close (int *err) -{ - diag_printf - ("xyzModem - %s mode, %d(SOH)/%d(STX)/%d(CAN) packets, %d retries\n", - xyz.crc_mode ? "CRC" : "Cksum", xyz.total_SOH, xyz.total_STX, - xyz.total_CAN, xyz.total_retries); - ZM_DEBUG (zm_flush ()); -} - -/* Need to be able to clean out the input buffer, so have to take the */ -/* getc */ -void -xyzModem_stream_terminate (bool abort, int (*getc) (void)) -{ - int c; - - 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 */ - /* number of Backspaces is a friendly way to get the other end to abort. */ - CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN); - CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN); - CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN); - CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN); - CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP); - CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP); - CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP); - CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP); - /* Now consume the rest of what's waiting on the line. */ - ZM_DEBUG (zm_dprintf ("Flushing serial line.\n")); - xyzModem_flush (); - xyz.at_eof = true; - break; -#ifdef xyzModem_zmodem - case xyzModem_zmodem: - /* Might support it some day I suppose. */ -#endif - break; - } - } - else - { - ZM_DEBUG (zm_dprintf ("Engaging cleanup mode...\n")); - /* - * Consume any trailing crap left in the inbuffer from - * previous received 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. - */ - ZM_DEBUG (zm_dprintf ("Trailing gunk:\n")); - while ((c = (*getc) ()) > -1); - 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); - } -} - -char * -xyzModem_error (int err) -{ - switch (err) - { - case xyzModem_access: - return "Can't access file"; - break; - case xyzModem_noZmodem: - return "Sorry, zModem not available yet"; - break; - case xyzModem_timeout: - return "Timed out"; - break; - case xyzModem_eof: - return "End of file"; - break; - case xyzModem_cancel: - return "Cancelled"; - break; - case xyzModem_frame: - return "Invalid framing"; - break; - case xyzModem_cksum: - return "CRC/checksum error"; - break; - case xyzModem_sequence: - return "Block sequence error"; - break; - default: - return "Unknown error"; - break; - } -} - -/* - * RedBoot interface - */ -#if 0 /* SB */ -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, xyzModem_xmodem); -RedBoot_load (ymodem, xyzModem_io, false, false, xyzModem_ymodem); -#endif |