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