
This patch provides support for loadb and loady and enables the broken feature. xyzModem.c is brought in from U-Boot V1, Lindent, checkpatch and sparse cleaned :).
Signed-off-by: Nishanth Menonx0nishan@ti.com
--- commands/Kconfig | 14 commands/Makefile | 1 commands/loadb.c | 182 ++++++++--- commands/xyzModem.c | 792 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/Makefile | 1 5 files changed, 932 insertions(+), 58 deletions(-)
Index: u-boot-v2.git/commands/Kconfig =================================================================== --- u-boot-v2.git.orig/commands/Kconfig 2008-05-20 17:53:55.000000000 -0500 +++ u-boot-v2.git/commands/Kconfig 2008-05-20 17:54:18.000000000 -0500 @@ -121,13 +121,23 @@ endmenu
menu "memory " +config LOAD_ADDR + depends on CMD_LOADB + hex + prompt "default load address" + help + Provide the default load address for the platform
config CMD_LOADB - depends on BROKEN select CRC16 - tristate + bool prompt "loadb"
+config CMD_LOADY + select CRC16 + bool + prompt "loady" + config CMD_LOADS depends on BROKEN tristate Index: u-boot-v2.git/commands/Makefile =================================================================== --- u-boot-v2.git.orig/commands/Makefile 2008-05-20 17:53:55.000000000 -0500 +++ u-boot-v2.git/commands/Makefile 2008-05-20 17:54:18.000000000 -0500 @@ -1,5 +1,6 @@ obj-$(CONFIG_CMD_BOOTM) += bootm.o obj-$(CONFIG_CMD_LOADB) += loadb.o xyzModem.o +obj-$(CONFIG_CMD_LOADY) += loadb.o xyzModem.o obj-$(CONFIG_CMD_LOADS) += loads.o obj-$(CONFIG_CMD_ECHO) += echo.o obj-$(CONFIG_CMD_MEMORY) += mem.o Index: u-boot-v2.git/commands/loadb.c =================================================================== --- u-boot-v2.git.orig/commands/loadb.c 2008-05-20 17:53:55.000000000 -0500 +++ u-boot-v2.git/commands/loadb.c 2008-05-20 17:58:05.000000000 -0500 @@ -1,3 +1,12 @@ +/** + * @file + * @brief LoadB and LoadY support. + * + * Provides loadb (over Kermit) and LoadY(over Y modem) support to download + * images. + * + * FileName: commands/loadb.c + */ /* * (C) Copyright 2000-2004 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. @@ -26,14 +35,16 @@ */ #include <common.h> #include <command.h> -#include <s_record.h> -#include <net.h> -#include <exports.h> #include <xyzModem.h> +#include <console.h> +#include <errno.h> +#include <environment.h> +#include <cache.h>
-DECLARE_GLOBAL_DATA_PTR;
+#ifdef CONFIG_CMD_LOADY static ulong load_serial_ymodem (ulong offset); +#endif
#define XON_CHAR 17 #define XOFF_CHAR 19 @@ -50,36 +61,70 @@ #define tochar(x) ((char) (((x) + SPACE) & 0xff)) #define untochar(x) ((int) (((x) - SPACE) & 0xff))
-extern int os_data_count; -extern int os_data_header[8];
static void set_kerm_bin_mode(unsigned long *); static int k_recv(void); static ulong load_serial_bin (ulong offset);
-char his_eol; /* character he needs at end of packet */ -int his_pad_count; /* number of pad chars he needs */ -char his_pad_char; /* pad chars he needs */ -char his_quote; /* quote chars he'll use */ +static char his_eol; /* character he needs at end of packet */ +static int his_pad_count; /* number of pad chars he needs */ +static char his_pad_char; /* pad chars he needs */ +static char his_quote; /* quote chars he'll use */ +
-int do_load_serial_bin (cmd_tbl_t *cmdtp, int argc, char *argv[]) +/** + * @brief returns current used console device + * + * @return console device which is registered with CONSOLE_STDIN and + * CONSOLE_STDOUT + */ +static struct console_device *get_current_console(void) +{ + struct console_device *cdev; + /* + * Assumption to have BOTH CONSOLE_STDIN AND STDOUT in the + * same output console + */ + for_each_console(cdev) { + if ((cdev->f_active & (CONSOLE_STDIN | CONSOLE_STDOUT))) + return cdev; + } + return NULL; +} + +/** + * @brief provide the loadb(Kermit) or loadY mode support + * + * @param cmdtp + * @param argc + * @param argv + * + * @return success or failure + */ +static int do_load_serial_bin(cmd_tbl_t *cmdtp, int argc, char *argv[]) { ulong offset = 0; ulong addr; int load_baudrate, current_baudrate; int rcode = 0; char *s; + struct console_device *cdev = get_current_console(); + if (NULL == cdev) { + printf("No device with STDIN and STDOUT\n"); + return -ENODEV; + }
- /* pre-set offset from CFG_LOAD_ADDR */ - offset = CFG_LOAD_ADDR; + /* pre-set offset from CONFIG_LOAD_ADDR */ + offset = CONFIG_LOAD_ADDR;
/* pre-set offset from $loadaddr */ - if ((s = getenv("loadaddr")) != NULL) { + s = (char *) getenv("loadaddr"); + if (s != NULL) offset = simple_strtoul(s, NULL, 16); - }
- load_baudrate = current_baudrate = gd->baudrate; + load_baudrate = current_baudrate = + simple_strtoul(cdev->baudrate_string, NULL, 10);
if (argc >= 2) { offset = simple_strtoul(argv[1], NULL, 16); @@ -96,15 +141,14 @@ printf ("## Switch baudrate to %d bps and press ENTER ...\n", load_baudrate); udelay(50000); - gd->baudrate = load_baudrate; - serial_setbrg (); + cdev->setbrg(cdev, load_baudrate); udelay(50000); for (;;) { if (getc() == '\r') break; } } - +#ifdef CONFIG_CMD_LOADY if (strcmp(argv[0],"loady")==0) { printf ("## Ready for binary (ymodem) download " "to 0x%08lX at %d bps...\n", @@ -113,7 +157,10 @@
addr = load_serial_ymodem (offset);
- } else { + } +#endif +#ifdef CONFIG_CMD_LOADB + if (strcmp(argv[0],"loadb")==0) {
printf ("## Ready for binary (kermit) download " "to 0x%08lX at %d bps...\n", @@ -122,20 +169,18 @@ addr = load_serial_bin (offset);
if (addr == ~0) { - load_addr = 0; printf ("## Binary (kermit) download aborted\n"); rcode = 1; } else { printf ("## Start Addr = 0x%08lX\n", addr); - load_addr = addr; } } +#endif if (load_baudrate != current_baudrate) { printf ("## Switch baudrate to %d bps and press ESC ...\n", current_baudrate); udelay (50000); - gd->baudrate = current_baudrate; - serial_setbrg (); + cdev->setbrg(cdev, current_baudrate); udelay (50000); for (;;) { if (getc() == 0x1B) /* ESC */ @@ -147,6 +192,14 @@ }
+#ifdef CONFIG_CMD_LOADB +/** + * @brief loadb Support over kermit protocol + * + * @param offset where to download to + * + * @return downloaded address + */ static ulong load_serial_bin (ulong offset) { int size, i; @@ -175,17 +228,18 @@
return offset; } +#endif
-void send_pad (void) +static void send_pad (void) { int count = his_pad_count;
while (count-- > 0) - putc (his_pad_char); + console_putc (CONSOLE_STDOUT, his_pad_char); }
/* converts escaped kermit char to binary char */ -char ktrans (char in) +static char ktrans(char in) { if ((in & 0x60) == 0x40) { return (char) (in & ~0x40); @@ -195,7 +249,7 @@ return in; }
-int chk1 (char *buffer) +static int chk1 (char *buffer) { int total = 0;
@@ -205,16 +259,16 @@ return (int) ((total + ((total >> 6) & 0x03)) & 0x3f); }
-void s1_sendpacket (char *packet) +static void s1_sendpacket (char *packet) { send_pad (); while (*packet) { - putc (*packet++); + console_putc (CONSOLE_STDOUT, *packet++); } }
static char a_b[24]; -void send_ack (int n) +static void send_ack (int n) { a_b[0] = START_CHAR; a_b[1] = tochar (3); @@ -227,7 +281,7 @@ s1_sendpacket (a_b); }
-void send_nack (int n) +static void send_nack (int n) { a_b[0] = START_CHAR; a_b[1] = tochar (3); @@ -246,14 +300,15 @@
if image is binary, no header is stored in os_data_header. */ -void (*os_data_init) (void); -void (*os_data_char) (char new_char); +static void (*os_data_init) (void); +static void (*os_data_char) (char new_char); static int os_data_state, os_data_state_saved; -int os_data_count; +static int os_data_count; static int os_data_count_saved; static char *os_data_addr, *os_data_addr_saved; static char *bin_start_address; -int os_data_header[8]; +/* FIXME: carry over feature to use this. commented for sparse warning +static int os_data_header[8]; */ static void bin_data_init (void) { os_data_state = 0; @@ -291,22 +346,22 @@
/* k_data_* simply handles the kermit escape translations */ static int k_data_escape, k_data_escape_saved; -void k_data_init (void) +static void k_data_init(void) { k_data_escape = 0; os_data_init (); } -void k_data_save (void) +static void k_data_save(void) { k_data_escape_saved = k_data_escape; os_data_save (); } -void k_data_restore (void) +static void k_data_restore(void) { k_data_escape = k_data_escape_saved; os_data_restore (); } -void k_data_char (char new_char) +static void k_data_char(char new_char) { if (k_data_escape) { /* last char was escape - translate this character */ @@ -324,12 +379,12 @@ }
#define SEND_DATA_SIZE 20 -char send_parms[SEND_DATA_SIZE]; -char *send_ptr; +static char send_parms[SEND_DATA_SIZE]; +static char *send_ptr;
/* handle_send_packet interprits the protocol info and builds and sends an appropriate ack for what we can do */ -void handle_send_packet (int n) +static void handle_send_packet(int n) { int length = 3; int bytes; @@ -588,11 +643,19 @@ return ((ulong) os_data_addr - (ulong) bin_start_address); }
+#ifdef CONFIG_CMD_LOADY static int getcxmodem(void) { if (tstc()) return (getc()); return -1; } +/** + * @brief LoadY over ymodem protocol + * + * @param offset address to download to + * + * @return address downloaded + */ static ulong load_serial_ymodem (ulong offset) { int size; @@ -633,19 +696,26 @@
return offset; } +#endif
-U_BOOT_CMD( - loadb, 3, 0, do_load_serial_bin, - "loadb - load binary file over serial line (kermit mode)\n", - "[ off ] [ baud ]\n" - " - load binary file over serial line" - " with offset 'off' and baudrate 'baud'\n" -); - -U_BOOT_CMD( - loady, 3, 0, do_load_serial_bin, - "loady - load binary file over serial line (ymodem mode)\n", +static const __maybe_unused char cmd_loadb_help[] = "[ off ] [ baud ]\n" " - load binary file over serial line" - " with offset 'off' and baudrate 'baud'\n" -); + " with offset 'off' and baudrate 'baud'\n"; +#ifdef CONFIG_CMD_LOADB +U_BOOT_CMD_START(loadb) + .maxargs = 3, + .cmd = do_load_serial_bin, + .usage = "load binary file over serial line (kermit mode)", + U_BOOT_CMD_HELP(cmd_loadb_help) +U_BOOT_CMD_END +#endif + +#ifdef CONFIG_CMD_LOADY +U_BOOT_CMD_START(loady) + .maxargs = 3, + .cmd = do_load_serial_bin, + .usage = "load binary file over serial line (ymodem mode)", + U_BOOT_CMD_HELP(cmd_loadb_help) +U_BOOT_CMD_END +#endif Index: u-boot-v2.git/commands/xyzModem.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ u-boot-v2.git/commands/xyzModem.c 2008-05-20 17:54:18.000000000 -0500 @@ -0,0 +1,792 @@ +/** + * @file + * @brief RedBoot stream handler for xyzModem protocol + * + * FileName: commands/xyzModem.c + * Originally from U-Boot V1 xyzModem.c + */ +/* + * 2008 - Nishanth Menon x0nishan@ti.com + * Modified for sparse and checkpatch.pl compliance + */ +/* + *========================================================================== + * + * xyzModem.c + * + * RedBoot stream handler for xyzModem protocol + * + *========================================================================== + *####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. + * + * eCos is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with eCos; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + * + * Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. + * at http: *sources.redhat.com/ecos/ecos-license/ + * ------------------------------------------- + *####ECOSGPLCOPYRIGHTEND#### + *========================================================================== + *#####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 <stdio.h> +#include <console.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 +/* Wait for 3 CAN before quitting */ +#define xyzModem_CAN_COUNT 3 + +#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) +{ + console_putc(CONSOLE_STDOUT, y); +} + +/* Validate a hex character */ +static inline bool _is_hex(char c) +{ + return (((c >= '0') && (c <= '9')) || + ((c >= 'A') && (c <= 'F')) || ((c >= 'a') && (c <= 'f'))); +} + +/* Convert a single hex nibble */ +static inline 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 */ +static inline 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); + if (_is_hex(c) && (digit < 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; + 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; + /* Extra delay for startup */ + CYGACC_CALL_IF_DELAY_US(5 * 100000); + 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 + /* WARNING - Leaving formatting aside for code + * clarity */ + /* 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 + /* WARNING - Leaving formatting aside for code + * clarity */ + /* + * 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); + /* Need new header */ + continue; + } 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 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. + */ + 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 Index: u-boot-v2.git/lib/Makefile =================================================================== --- u-boot-v2.git.orig/lib/Makefile 2008-05-20 17:53:55.000000000 -0500 +++ u-boot-v2.git/lib/Makefile 2008-05-20 17:54:18.000000000 -0500 @@ -19,6 +19,7 @@ obj-$(CONFIG_BZLIB) += bzlib.o bzlib_crctable.o bzlib_decompress.o bzlib_huffman.o bzlib_randtable.o obj-$(CONFIG_ZLIB) += zlib.o gunzip.o obj-$(CONFIG_CRC32) += crc32.o +obj-$(CONFIG_CRC16) += crc16.o obj-$(CONFIG_CMDLINE_EDITING) += readline.o obj-$(CONFIG_SIMPLE_READLINE) += readline_simple.o obj-$(CONFIG_GLOB) += fnmatch.o