mxc_nand: remove unused defines
[barebox-mini2440.git] / commands / xyzModem.c
blob7f6955c5aec195b9df9300d0630429f7c08f0d89
1 /**
2 * @file
3 * @brief RedBoot stream handler for xyzModem protocol
5 * FileName: commands/xyzModem.c
6 * Originally from U-Boot V1 xyzModem.c
7 */
8 /*
9 * 2008 - Nishanth Menon <x0nishan@ti.com>
10 * Modified for sparse and checkpatch.pl compliance
13 *==========================================================================
15 * xyzModem.c
17 * RedBoot stream handler for xyzModem protocol
19 *==========================================================================
20 *####ECOSGPLCOPYRIGHTBEGIN####
21 * -------------------------------------------
22 * This file is part of eCos, the Embedded Configurable Operating System.
23 * Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
24 * Copyright (C) 2002 Gary Thomas
26 * eCos is free software; you can redistribute it and/or modify it under
27 * the terms of the GNU General Public License as published by the Free
28 * Software Foundation; either version 2 or (at your option) any later version.
30 * eCos is distributed in the hope that it will be useful, but WITHOUT ANY
31 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
32 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
33 * for more details.
35 * You should have received a copy of the GNU General Public License along
36 * with eCos; if not, write to the Free Software Foundation, Inc.,
37 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
39 * As a special exception, if other files instantiate templates or use macros
40 * or inline functions from this file, or you compile this file and link it
41 * with other works to produce a work based on this file, this file does not
42 * by itself cause the resulting work to be covered by the GNU General Public
43 * License. However the source code for this file must still be made available
44 * in accordance with section (3) of the GNU General Public License.
46 * This exception does not invalidate any other reasons why a work based on
47 * this file might be covered by the GNU General Public License.
49 * Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
50 * at http: *sources.redhat.com/ecos/ecos-license/
51 * -------------------------------------------
52 *####ECOSGPLCOPYRIGHTEND####
53 *==========================================================================
54 *#####DESCRIPTIONBEGIN####
56 * Author(s): gthomas
57 * Contributors: gthomas, tsmith, Yoshinori Sato
58 * Date: 2000-07-14
59 * Purpose:
60 * Description:
62 * This code is part of RedBoot (tm).
64 *####DESCRIPTIONEND####
66 *==========================================================================
68 #include <common.h>
69 #include <xyzModem.h>
70 #include <stdarg.h>
71 #include <stdio.h>
72 #include <console.h>
73 #include <crc.h>
74 #include <linux/ctype.h>
76 /* Assumption - run xyzModem protocol over the console port */
78 /* Values magic to the protocol */
79 #define SOH 0x01
80 #define STX 0x02
81 #define EOT 0x04
82 #define ACK 0x06
83 #define BSP 0x08
84 #define NAK 0x15
85 #define CAN 0x18
86 #define EOF 0x1A /* ^Z for DOS officionados */
88 #define USE_YMODEM_LENGTH
90 /* Data & state local to the protocol */
91 static struct {
92 #ifdef REDBOOT
93 hal_virtual_comm_table_t *__chan;
94 #else
95 int *__chan;
96 #endif
97 unsigned char pkt[1024], *bufp;
98 unsigned char blk, cblk, crc1, crc2;
99 unsigned char next_blk; /* Expected block */
100 int len, mode, total_retries;
101 int total_SOH, total_STX, total_CAN;
102 bool crc_mode, at_eof, tx_ack;
103 #ifdef USE_YMODEM_LENGTH
104 unsigned long file_length, read_length;
105 #endif
106 } xyz;
108 #define xyzModem_CHAR_TIMEOUT 2000 /* 2 seconds */
109 #define xyzModem_MAX_RETRIES 20
110 #define xyzModem_MAX_RETRIES_WITH_CRC 10
111 /* Wait for 3 CAN before quitting */
112 #define xyzModem_CAN_COUNT 3
114 #ifndef REDBOOT /*SB */
115 typedef int cyg_int32;
116 static int CYGACC_COMM_IF_GETC_TIMEOUT(char chan, char *c)
118 #define DELAY 20
119 unsigned long counter = 0;
120 while (!tstc() && (counter < xyzModem_CHAR_TIMEOUT * 1000 / DELAY)) {
121 udelay(DELAY);
122 counter++;
124 if (tstc()) {
125 *c = getc();
126 return 1;
128 return 0;
131 static void CYGACC_COMM_IF_PUTC(char x, char y)
133 console_putc(CONSOLE_STDOUT, y);
136 /* Validate a hex character */
137 static inline bool _is_hex(char c)
139 return (((c >= '0') && (c <= '9')) ||
140 ((c >= 'A') && (c <= 'F')) || ((c >= 'a') && (c <= 'f')));
143 /* Convert a single hex nibble */
144 static inline int _from_hex(char c)
146 int ret = 0;
148 if ((c >= '0') && (c <= '9'))
149 ret = (c - '0');
150 else if ((c >= 'a') && (c <= 'f'))
151 ret = (c - 'a' + 0x0a);
152 else if ((c >= 'A') && (c <= 'F'))
153 ret = (c - 'A' + 0x0A);
155 return ret;
158 /* Parse (scan) a number */
159 static bool parse_num(char *s, unsigned long *val, char **es, char *delim)
161 bool first = true;
162 int radix = 10;
163 char c;
164 unsigned long result = 0;
165 int digit = 0;
167 while (*s == ' ')
168 s++;
169 while (*s) {
170 if (first && (s[0] == '0') && (tolower(s[1]) == 'x')) {
171 radix = 16;
172 s += 2;
174 first = false;
175 c = *s++;
176 if (_is_hex(c))
177 digit = _from_hex(c);
178 if (_is_hex(c) && (digit < radix)) {
179 /* Valid digit */
180 #ifdef CYGPKG_HAL_MIPS
181 /* FIXME: tx49 compiler generates 0x2539018 for
182 * MUL which isn't any good. */
183 if (16 == radix)
184 result = result << 4;
185 else
186 result = 10 * result;
187 result += digit;
188 #else
189 result = (result * radix) + digit;
190 #endif
191 } else {
192 if (delim != (char *)0) {
193 /* See if this character is one of the
194 * delimiters */
195 char *dp = delim;
196 while (*dp && (c != *dp))
197 dp++;
198 if (*dp)
199 break; /* Found a good delimiter */
201 return false; /* Malformatted number */
204 *val = result;
205 if (es != (char **)0)
206 *es = s;
207 return true;
210 #endif
212 #define USE_SPRINTF
213 #ifdef DEBUG
214 #ifndef USE_SPRINTF
216 * Note: this debug setup only works if the target platform has two serial ports
217 * available so that the other one (currently only port 1) can be used for debug
218 * messages.
220 static int zm_dprintf(char *fmt, ...)
222 int cur_console;
223 va_list args;
225 va_start(args, fmt);
226 #ifdef REDBOOT
227 cur_console =
228 CYGACC_CALL_IF_SET_CONSOLE_COMM
229 (CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
230 CYGACC_CALL_IF_SET_CONSOLE_COMM(1);
231 #endif
232 diag_vprintf(fmt, args);
233 #ifdef REDBOOT
234 CYGACC_CALL_IF_SET_CONSOLE_COMM(cur_console);
235 #endif
238 static void zm_flush(void)
242 #else
244 * Note: this debug setup works by storing the strings in a fixed buffer
246 #define FINAL
247 #ifdef FINAL
248 static char *zm_out = (char *)0x00380000;
249 static char *zm_out_start = (char *)0x00380000;
250 #else
251 static char zm_buf[8192];
252 static char *zm_out = zm_buf;
253 static char *zm_out_start = zm_buf;
255 #endif
256 static int zm_dprintf(char *fmt, ...)
258 int len;
259 va_list args;
261 va_start(args, fmt);
262 len = diag_vsprintf(zm_out, fmt, args);
263 zm_out += len;
264 return len;
267 static void zm_flush(void)
269 #ifdef REDBOOT
270 char *p = zm_out_start;
271 while (*p)
272 mon_write_char(*p++);
273 #endif
274 zm_out = zm_out_start;
276 #endif
278 static void zm_dump_buf(void *buf, int len)
280 #ifdef REDBOOT
281 diag_vdump_buf_with_offset(zm_dprintf, buf, len, 0);
282 #else
284 #endif
287 static unsigned char zm_buf[2048];
288 static unsigned char *zm_bp;
290 static void zm_new(void)
292 zm_bp = zm_buf;
295 static void zm_save(unsigned char c)
297 *zm_bp++ = c;
300 static void zm_dump(int line)
302 zm_dprintf("Packet at line: %d\n", line);
303 zm_dump_buf(zm_buf, zm_bp - zm_buf);
306 #define ZM_DEBUG(x) x
307 #else
308 #define ZM_DEBUG(x)
309 #endif
311 /* Wait for the line to go idle */
312 static void xyzModem_flush(void)
314 int res;
315 char c;
316 while (true) {
317 res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, &c);
318 if (!res)
319 return;
323 static int xyzModem_get_hdr(void)
325 char c;
326 int res;
327 bool hdr_found = false;
328 int i, can_total, hdr_chars;
329 unsigned short cksum;
331 ZM_DEBUG(zm_new());
332 /* Find the start of a header */
333 can_total = 0;
334 hdr_chars = 0;
336 if (xyz.tx_ack) {
337 CYGACC_COMM_IF_PUTC(*xyz.__chan, ACK);
338 xyz.tx_ack = false;
340 while (!hdr_found) {
341 res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, &c);
342 ZM_DEBUG(zm_save(c));
343 if (res) {
344 hdr_chars++;
345 switch (c) {
346 case SOH:
347 xyz.total_SOH++;
348 case STX:
349 if (c == STX)
350 xyz.total_STX++;
351 hdr_found = true;
352 break;
353 case CAN:
354 xyz.total_CAN++;
355 ZM_DEBUG(zm_dump(__LINE__));
356 if (++can_total == xyzModem_CAN_COUNT) {
357 return xyzModem_cancel;
358 } else {
359 /* Wait for multiple CAN to avoid
360 * early quits */
361 break;
363 case EOT:
364 /* EOT only supported if no noise */
365 if (hdr_chars == 1) {
366 CYGACC_COMM_IF_PUTC(*xyz.__chan, ACK);
367 ZM_DEBUG(zm_dprintf
368 ("ACK on EOT #%d\n",
369 __LINE__));
370 ZM_DEBUG(zm_dump(__LINE__));
371 return xyzModem_eof;
373 default:
374 /* Ignore, waiting for start of header */
377 } else {
378 /* Data stream timed out */
379 xyzModem_flush(); /* Toss any current input */
380 ZM_DEBUG(zm_dump(__LINE__));
381 CYGACC_CALL_IF_DELAY_US((cyg_int32) 250000);
382 return xyzModem_timeout;
386 /* Header found, now read the data */
387 res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, (char *)&xyz.blk);
388 ZM_DEBUG(zm_save(xyz.blk));
389 if (!res) {
390 ZM_DEBUG(zm_dump(__LINE__));
391 return xyzModem_timeout;
393 res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, (char *)&xyz.cblk);
394 ZM_DEBUG(zm_save(xyz.cblk));
395 if (!res) {
396 ZM_DEBUG(zm_dump(__LINE__));
397 return xyzModem_timeout;
399 xyz.len = (c == SOH) ? 128 : 1024;
400 xyz.bufp = xyz.pkt;
401 for (i = 0; i < xyz.len; i++) {
402 res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, &c);
403 ZM_DEBUG(zm_save(c));
404 if (res) {
405 xyz.pkt[i] = c;
406 } else {
407 ZM_DEBUG(zm_dump(__LINE__));
408 return xyzModem_timeout;
411 res = CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, (char *)&xyz.crc1);
412 ZM_DEBUG(zm_save(xyz.crc1));
413 if (!res) {
414 ZM_DEBUG(zm_dump(__LINE__));
415 return xyzModem_timeout;
417 if (xyz.crc_mode) {
418 res =
419 CYGACC_COMM_IF_GETC_TIMEOUT(*xyz.__chan, (char *)&xyz.crc2);
420 ZM_DEBUG(zm_save(xyz.crc2));
421 if (!res) {
422 ZM_DEBUG(zm_dump(__LINE__));
423 return xyzModem_timeout;
426 ZM_DEBUG(zm_dump(__LINE__));
427 /* Validate the message */
428 if ((xyz.blk ^ xyz.cblk) != (unsigned char)0xFF) {
429 ZM_DEBUG(zm_dprintf
430 ("Framing error - blk: %x/%x/%x\n", xyz.blk, xyz.cblk,
431 (xyz.blk ^ xyz.cblk)));
432 ZM_DEBUG(zm_dump_buf(xyz.pkt, xyz.len));
433 xyzModem_flush();
434 return xyzModem_frame;
436 /* Verify checksum/CRC */
437 if (xyz.crc_mode) {
438 cksum = cyg_crc16(xyz.pkt, xyz.len);
439 if (cksum != ((xyz.crc1 << 8) | xyz.crc2)) {
440 ZM_DEBUG(zm_dprintf
441 ("CRC error - recvd: %02x%02x, computed: %x\n",
442 xyz.crc1, xyz.crc2, cksum & 0xFFFF));
443 return xyzModem_cksum;
445 } else {
446 cksum = 0;
447 for (i = 0; i < xyz.len; i++)
448 cksum += xyz.pkt[i];
449 if (xyz.crc1 != (cksum & 0xFF)) {
450 ZM_DEBUG(zm_dprintf
451 ("Checksum error - recvd: %x, computed: %x\n",
452 xyz.crc1, cksum & 0xFF));
453 return xyzModem_cksum;
456 /* If we get here, the message passes [structural] muster */
457 return 0;
460 int xyzModem_stream_open(connection_info_t *info, int *err)
462 #ifdef REDBOOT
463 int console_chan;
464 #endif
465 int stat = 0;
466 int retries = xyzModem_MAX_RETRIES;
467 int crc_retries = xyzModem_MAX_RETRIES_WITH_CRC;
469 /* ZM_DEBUG(zm_out = zm_out_start); */
470 #ifdef xyzModem_zmodem
471 if (info->mode == xyzModem_zmodem) {
472 *err = xyzModem_noZmodem;
473 return -1;
475 #endif
477 #ifdef REDBOOT
478 /* Set up the I/O channel. Note: this allows for using a different
479 * port in the future */
480 console_chan =
481 CYGACC_CALL_IF_SET_CONSOLE_COMM
482 (CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
483 if (info->chan >= 0)
484 CYGACC_CALL_IF_SET_CONSOLE_COMM(info->chan);
485 else
486 CYGACC_CALL_IF_SET_CONSOLE_COMM(console_chan);
488 xyz.__chan = CYGACC_CALL_IF_CONSOLE_PROCS();
490 CYGACC_CALL_IF_SET_CONSOLE_COMM(console_chan);
491 CYGACC_COMM_IF_CONTROL(*xyz.__chan, __COMMCTL_SET_TIMEOUT,
492 xyzModem_CHAR_TIMEOUT);
493 #else
494 /* TODO: CHECK ! */
495 int dummy;
496 xyz.__chan = &dummy;
497 #endif
498 xyz.len = 0;
499 xyz.crc_mode = true;
500 xyz.at_eof = false;
501 xyz.tx_ack = false;
502 xyz.mode = info->mode;
503 xyz.total_retries = 0;
504 xyz.total_SOH = 0;
505 xyz.total_STX = 0;
506 xyz.total_CAN = 0;
507 #ifdef USE_YMODEM_LENGTH
508 xyz.read_length = 0;
509 xyz.file_length = 0;
510 #endif
512 CYGACC_COMM_IF_PUTC(*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
514 if (xyz.mode == xyzModem_xmodem) {
515 /* X-modem doesn't have an information header - exit here */
516 xyz.next_blk = 1;
517 return 0;
520 while (retries-- > 0) {
521 stat = xyzModem_get_hdr();
522 if (stat == 0) {
523 /* Y-modem file information header */
524 if (xyz.blk == 0) {
525 #ifdef USE_YMODEM_LENGTH
526 /* skip filename */
527 while (*xyz.bufp++) ;
528 /* get the length */
529 parse_num((char *)xyz.bufp, &xyz.file_length,
530 NULL, " ");
531 #endif
532 /* The rest of the file name data block
533 * quietly discarded
535 xyz.tx_ack = true;
537 xyz.next_blk = 1;
538 xyz.len = 0;
539 return 0;
540 } else if (stat == xyzModem_timeout) {
541 if (--crc_retries <= 0)
542 xyz.crc_mode = false;
543 /* Extra delay for startup */
544 CYGACC_CALL_IF_DELAY_US(5 * 100000);
545 CYGACC_COMM_IF_PUTC(*xyz.__chan,
546 (xyz.crc_mode ? 'C' : NAK));
547 xyz.total_retries++;
548 ZM_DEBUG(zm_dprintf("NAK (%d)\n", __LINE__));
550 if (stat == xyzModem_cancel)
551 break;
553 *err = stat;
554 ZM_DEBUG(zm_flush());
555 return -1;
558 int xyzModem_stream_read(char *buf, int size, int *err)
560 int stat, total, len;
561 int retries;
563 total = 0;
564 stat = xyzModem_cancel;
565 /* Try and get 'size' bytes into the buffer */
566 while (!xyz.at_eof && (size > 0)) {
567 if (xyz.len == 0) {
568 retries = xyzModem_MAX_RETRIES;
569 while (retries-- > 0) {
570 stat = xyzModem_get_hdr();
571 if (stat == 0) {
572 if (xyz.blk == xyz.next_blk) {
573 xyz.tx_ack = true;
574 ZM_DEBUG(zm_dprintf
575 ("ACK block %d (%d)\n",
576 xyz.blk, __LINE__));
577 xyz.next_blk =
578 (xyz.next_blk + 1) & 0xFF;
580 #if defined(xyzModem_zmodem) || defined(USE_YMODEM_LENGTH)
581 if (xyz.mode == xyzModem_xmodem
582 || xyz.file_length == 0) {
583 #else
584 if (1) {
585 #endif
586 /* WARNING - Leaving formatting aside for code
587 * clarity */
588 /* Data blocks can be padded with ^Z (EOF) characters */
589 /* This code tries to detect and remove them */
590 if ((xyz.bufp[xyz.len - 1] == EOF)
591 && (xyz.bufp[xyz.len - 2] == EOF)
592 && (xyz.bufp[xyz.len - 3] == EOF)) {
593 while (xyz.len &&
594 (xyz.bufp[xyz.len - 1] == EOF))
595 xyz.len--;
598 #ifdef USE_YMODEM_LENGTH
599 /* WARNING - Leaving formatting aside for code
600 * clarity */
602 * See if accumulated length exceeds that of the file.
603 * If so, reduce size (i.e., cut out pad bytes)
604 * Only do this for Y-modem (and Z-modem should it ever
605 * be supported since it can fall back to Y-modem mode).
607 if (xyz.mode != xyzModem_xmodem
608 && 0 != xyz.file_length) {
609 xyz.read_length += xyz.len;
610 if (xyz.read_length > xyz.file_length)
611 xyz.len -= (xyz.read_length -
612 xyz.file_length);
614 #endif
615 break;
616 } else if (xyz.blk ==
617 ((xyz.next_blk - 1) &
618 0xFF)) {
619 /* Just re-ACK this so sender
620 * will get on with it */
621 CYGACC_COMM_IF_PUTC(*xyz.__chan,
622 ACK);
623 /* Need new header */
624 continue;
625 } else
626 stat = xyzModem_sequence;
628 if (stat == xyzModem_cancel)
629 break;
630 if (stat == xyzModem_eof) {
631 CYGACC_COMM_IF_PUTC(*xyz.__chan, ACK);
632 ZM_DEBUG(zm_dprintf
633 ("ACK (%d)\n", __LINE__));
634 if (xyz.mode == xyzModem_ymodem) {
635 CYGACC_COMM_IF_PUTC(*xyz.__chan,
636 (xyz.
637 crc_mode ?
638 'C' :
639 NAK));
640 xyz.total_retries++;
641 ZM_DEBUG(zm_dprintf
642 ("Reading Final Header\n"));
643 stat = xyzModem_get_hdr();
644 CYGACC_COMM_IF_PUTC(*xyz.__chan,
645 ACK);
646 ZM_DEBUG(zm_dprintf
647 ("FINAL ACK (%d)\n",
648 __LINE__));
650 xyz.at_eof = true;
651 break;
653 CYGACC_COMM_IF_PUTC(*xyz.__chan,
654 (xyz.crc_mode ? 'C' : NAK));
655 xyz.total_retries++;
656 ZM_DEBUG(zm_dprintf("NAK (%d)\n", __LINE__));
658 if (stat < 0) {
659 *err = stat;
660 xyz.len = -1;
661 return total;
664 /* Don't "read" data from the EOF protocol package */
665 if (!xyz.at_eof) {
666 len = xyz.len;
667 if (size < len)
668 len = size;
669 memcpy(buf, xyz.bufp, len);
670 size -= len;
671 buf += len;
672 total += len;
673 xyz.len -= len;
674 xyz.bufp += len;
677 return total;
680 void xyzModem_stream_close(int *err)
682 diag_printf
683 ("xyzModem - %s mode, %d(SOH)/%d(STX)/%d(CAN) packets,"
684 " %d retries\n",
685 xyz.crc_mode ? "CRC" : "Cksum", xyz.total_SOH, xyz.total_STX,
686 xyz.total_CAN, xyz.total_retries);
687 ZM_DEBUG(zm_flush());
690 /* Need to be able to clean out the input buffer, so have to take the */
691 /* getc */
692 void xyzModem_stream_terminate(bool abort, int (*getc) (void))
694 int c;
696 if (abort) {
697 ZM_DEBUG(zm_dprintf("!!!! TRANSFER ABORT !!!!\n"));
698 switch (xyz.mode) {
699 case xyzModem_xmodem:
700 case xyzModem_ymodem:
701 /* The X/YMODEM Spec seems to suggest that multiple CAN
702 * followed by an equal number of Backspaces is a
703 * friendly way to get the other end to abort. */
704 CYGACC_COMM_IF_PUTC(*xyz.__chan, CAN);
705 CYGACC_COMM_IF_PUTC(*xyz.__chan, CAN);
706 CYGACC_COMM_IF_PUTC(*xyz.__chan, CAN);
707 CYGACC_COMM_IF_PUTC(*xyz.__chan, CAN);
708 CYGACC_COMM_IF_PUTC(*xyz.__chan, BSP);
709 CYGACC_COMM_IF_PUTC(*xyz.__chan, BSP);
710 CYGACC_COMM_IF_PUTC(*xyz.__chan, BSP);
711 CYGACC_COMM_IF_PUTC(*xyz.__chan, BSP);
712 /* Now consume the rest of what's waiting on the line.*/
713 ZM_DEBUG(zm_dprintf("Flushing serial line.\n"));
714 xyzModem_flush();
715 xyz.at_eof = true;
716 break;
717 #ifdef xyzModem_zmodem
718 case xyzModem_zmodem:
719 /* Might support it some day I suppose. */
720 #endif
721 break;
723 } else {
724 ZM_DEBUG(zm_dprintf("Engaging cleanup mode...\n"));
726 * Consume any trailing crap left in the inbuffer from
727 * previous recieved blocks. Since very few files are an
728 * exact multiple of the transfer block size, there will
729 * almost always be some gunk here.
730 * If we don't eat it now, RedBoot will think the user typed it.
732 ZM_DEBUG(zm_dprintf("Trailing gunk:\n"));
733 while ((c = (*getc) ()) > -1) ;
734 ZM_DEBUG(zm_dprintf("\n"));
736 * Make a small delay to give terminal programs like minicom
737 * time to get control again after their file transfer program
738 * exits.
740 CYGACC_CALL_IF_DELAY_US((cyg_int32) 250000);
744 char *xyzModem_error(int err)
746 switch (err) {
747 case xyzModem_access:
748 return "Can't access file";
749 break;
750 case xyzModem_noZmodem:
751 return "Sorry, zModem not available yet";
752 break;
753 case xyzModem_timeout:
754 return "Timed out";
755 break;
756 case xyzModem_eof:
757 return "End of file";
758 break;
759 case xyzModem_cancel:
760 return "Cancelled";
761 break;
762 case xyzModem_frame:
763 return "Invalid framing";
764 break;
765 case xyzModem_cksum:
766 return "CRC/checksum error";
767 break;
768 case xyzModem_sequence:
769 return "Block sequence error";
770 break;
771 default:
772 return "Unknown error";
773 break;
778 * RedBoot interface
780 #if 0 /* SB */
781 GETC_IO_FUNCS(xyzModem_io, xyzModem_stream_open, xyzModem_stream_close,
782 xyzModem_stream_terminate, xyzModem_stream_read, xyzModem_error);
783 RedBoot_load(xmodem, xyzModem_io, false, false, xyzModem_xmodem);
784 RedBoot_load(ymodem, xyzModem_io, false, false, xyzModem_ymodem);
785 #endif