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 { 79 #ifdef REDBOOT 80 hal_virtual_comm_table_t *__chan; 81 #else 82 int *__chan; 83 #endif 84 unsigned char pkt[1024], *bufp; 85 unsigned char blk, cblk, crc1, crc2; 86 unsigned char next_blk; /* Expected block */ 87 int len, mode, total_retries; 88 int total_SOH, total_STX, total_CAN; 89 bool crc_mode, at_eof, tx_ack; 90 #ifdef USE_YMODEM_LENGTH 91 unsigned long file_length, read_length; 92 #endif 93 } xyz; 94 95 #define xyzModem_CHAR_TIMEOUT 2000 /* 2 seconds */ 96 #define xyzModem_MAX_RETRIES 20 97 #define xyzModem_MAX_RETRIES_WITH_CRC 10 98 #define xyzModem_CAN_COUNT 3 /* Wait for 3 CAN before quitting */ 99 100 101 #ifndef REDBOOT /*SB */ 102 typedef int cyg_int32; 103 static int 104 CYGACC_COMM_IF_GETC_TIMEOUT (char chan, char *c) 105 { 106 #define DELAY 20 107 unsigned long counter = 0; 108 while (!tstc () && (counter < xyzModem_CHAR_TIMEOUT * 1000 / DELAY)) 109 { 110 udelay (DELAY); 111 counter++; 112 } 113 if (tstc ()) 114 { 115 *c = getc (); 116 return 1; 117 } 118 return 0; 119 } 120 121 static void 122 CYGACC_COMM_IF_PUTC (char x, char y) 123 { 124 putc (y); 125 } 126 127 /* Validate a hex character */ 128 __inline__ static bool 129 _is_hex (char c) 130 { 131 return (((c >= '0') && (c <= '9')) || 132 ((c >= 'A') && (c <= 'F')) || ((c >= 'a') && (c <= 'f'))); 133 } 134 135 /* Convert a single hex nibble */ 136 __inline__ static int 137 _from_hex (char c) 138 { 139 int ret = 0; 140 141 if ((c >= '0') && (c <= '9')) 142 { 143 ret = (c - '0'); 144 } 145 else if ((c >= 'a') && (c <= 'f')) 146 { 147 ret = (c - 'a' + 0x0a); 148 } 149 else if ((c >= 'A') && (c <= 'F')) 150 { 151 ret = (c - 'A' + 0x0A); 152 } 153 return ret; 154 } 155 156 /* Convert a character to lower case */ 157 __inline__ static char 158 _tolower (char c) 159 { 160 if ((c >= 'A') && (c <= 'Z')) 161 { 162 c = (c - 'A') + 'a'; 163 } 164 return c; 165 } 166 167 /* Parse (scan) a number */ 168 static bool 169 parse_num (char *s, unsigned long *val, char **es, char *delim) 170 { 171 bool first = true; 172 int radix = 10; 173 char c; 174 unsigned long result = 0; 175 int digit; 176 177 while (*s == ' ') 178 s++; 179 while (*s) 180 { 181 if (first && (s[0] == '0') && (_tolower (s[1]) == 'x')) 182 { 183 radix = 16; 184 s += 2; 185 } 186 first = false; 187 c = *s++; 188 if (_is_hex (c) && ((digit = _from_hex (c)) < radix)) 189 { 190 /* Valid digit */ 191 #ifdef CYGPKG_HAL_MIPS 192 /* FIXME: tx49 compiler generates 0x2539018 for MUL which */ 193 /* isn't any good. */ 194 if (16 == radix) 195 result = result << 4; 196 else 197 result = 10 * result; 198 result += digit; 199 #else 200 result = (result * radix) + digit; 201 #endif 202 } 203 else 204 { 205 if (delim != (char *) 0) 206 { 207 /* See if this character is one of the delimiters */ 208 char *dp = delim; 209 while (*dp && (c != *dp)) 210 dp++; 211 if (*dp) 212 break; /* Found a good delimiter */ 213 } 214 return false; /* Malformatted number */ 215 } 216 } 217 *val = result; 218 if (es != (char **) 0) 219 { 220 *es = s; 221 } 222 return true; 223 } 224 225 #endif 226 227 #define USE_SPRINTF 228 #ifdef DEBUG 229 #ifndef USE_SPRINTF 230 /* 231 * Note: this debug setup only works if the target platform has two serial ports 232 * available so that the other one (currently only port 1) can be used for debug 233 * messages. 234 */ 235 static int 236 zm_dprintf (char *fmt, ...) 237 { 238 int cur_console; 239 va_list args; 240 241 va_start (args, fmt); 242 #ifdef REDBOOT 243 cur_console = 244 CYGACC_CALL_IF_SET_CONSOLE_COMM 245 (CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT); 246 CYGACC_CALL_IF_SET_CONSOLE_COMM (1); 247 #endif 248 diag_vprintf (fmt, args); 249 #ifdef REDBOOT 250 CYGACC_CALL_IF_SET_CONSOLE_COMM (cur_console); 251 #endif 252 } 253 254 static void 255 zm_flush (void) 256 { 257 } 258 259 #else 260 /* 261 * Note: this debug setup works by storing the strings in a fixed buffer 262 */ 263 #define FINAL 264 #ifdef FINAL 265 static char *zm_out = (char *) 0x00380000; 266 static char *zm_out_start = (char *) 0x00380000; 267 #else 268 static char zm_buf[8192]; 269 static char *zm_out = zm_buf; 270 static char *zm_out_start = zm_buf; 271 272 #endif 273 static int 274 zm_dprintf (char *fmt, ...) 275 { 276 int len; 277 va_list args; 278 279 va_start (args, fmt); 280 len = diag_vsprintf (zm_out, fmt, args); 281 zm_out += len; 282 return len; 283 } 284 285 static void 286 zm_flush (void) 287 { 288 #ifdef REDBOOT 289 char *p = zm_out_start; 290 while (*p) 291 mon_write_char (*p++); 292 #endif 293 zm_out = zm_out_start; 294 } 295 #endif 296 297 static void 298 zm_dump_buf (void *buf, int len) 299 { 300 #ifdef REDBOOT 301 diag_vdump_buf_with_offset (zm_dprintf, buf, len, 0); 302 #else 303 304 #endif 305 } 306 307 static unsigned char zm_buf[2048]; 308 static unsigned char *zm_bp; 309 310 static void 311 zm_new (void) 312 { 313 zm_bp = zm_buf; 314 } 315 316 static void 317 zm_save (unsigned char c) 318 { 319 *zm_bp++ = c; 320 } 321 322 static void 323 zm_dump (int line) 324 { 325 zm_dprintf ("Packet at line: %d\n", line); 326 zm_dump_buf (zm_buf, zm_bp - zm_buf); 327 } 328 329 #define ZM_DEBUG(x) x 330 #else 331 #define ZM_DEBUG(x) 332 #endif 333 334 /* Wait for the line to go idle */ 335 static void 336 xyzModem_flush (void) 337 { 338 int res; 339 char c; 340 while (true) 341 { 342 res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c); 343 if (!res) 344 return; 345 } 346 } 347 348 static int 349 xyzModem_get_hdr (void) 350 { 351 char c; 352 int res; 353 bool hdr_found = false; 354 int i, can_total, hdr_chars; 355 unsigned short cksum; 356 357 ZM_DEBUG (zm_new ()); 358 /* Find the start of a header */ 359 can_total = 0; 360 hdr_chars = 0; 361 362 if (xyz.tx_ack) 363 { 364 CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK); 365 xyz.tx_ack = false; 366 } 367 while (!hdr_found) 368 { 369 res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c); 370 ZM_DEBUG (zm_save (c)); 371 if (res) 372 { 373 hdr_chars++; 374 switch (c) 375 { 376 case SOH: 377 xyz.total_SOH++; 378 case STX: 379 if (c == STX) 380 xyz.total_STX++; 381 hdr_found = true; 382 break; 383 case CAN: 384 xyz.total_CAN++; 385 ZM_DEBUG (zm_dump (__LINE__)); 386 if (++can_total == xyzModem_CAN_COUNT) 387 { 388 return xyzModem_cancel; 389 } 390 else 391 { 392 /* Wait for multiple CAN to avoid early quits */ 393 break; 394 } 395 case EOT: 396 /* EOT only supported if no noise */ 397 if (hdr_chars == 1) 398 { 399 CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK); 400 ZM_DEBUG (zm_dprintf ("ACK on EOT #%d\n", __LINE__)); 401 ZM_DEBUG (zm_dump (__LINE__)); 402 return xyzModem_eof; 403 } 404 default: 405 /* Ignore, waiting for start of header */ 406 ; 407 } 408 } 409 else 410 { 411 /* Data stream timed out */ 412 xyzModem_flush (); /* Toss any current input */ 413 ZM_DEBUG (zm_dump (__LINE__)); 414 CYGACC_CALL_IF_DELAY_US ((cyg_int32) 250000); 415 return xyzModem_timeout; 416 } 417 } 418 419 /* Header found, now read the data */ 420 res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.blk); 421 ZM_DEBUG (zm_save (xyz.blk)); 422 if (!res) 423 { 424 ZM_DEBUG (zm_dump (__LINE__)); 425 return xyzModem_timeout; 426 } 427 res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.cblk); 428 ZM_DEBUG (zm_save (xyz.cblk)); 429 if (!res) 430 { 431 ZM_DEBUG (zm_dump (__LINE__)); 432 return xyzModem_timeout; 433 } 434 xyz.len = (c == SOH) ? 128 : 1024; 435 xyz.bufp = xyz.pkt; 436 for (i = 0; i < xyz.len; i++) 437 { 438 res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c); 439 ZM_DEBUG (zm_save (c)); 440 if (res) 441 { 442 xyz.pkt[i] = c; 443 } 444 else 445 { 446 ZM_DEBUG (zm_dump (__LINE__)); 447 return xyzModem_timeout; 448 } 449 } 450 res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.crc1); 451 ZM_DEBUG (zm_save (xyz.crc1)); 452 if (!res) 453 { 454 ZM_DEBUG (zm_dump (__LINE__)); 455 return xyzModem_timeout; 456 } 457 if (xyz.crc_mode) 458 { 459 res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.crc2); 460 ZM_DEBUG (zm_save (xyz.crc2)); 461 if (!res) 462 { 463 ZM_DEBUG (zm_dump (__LINE__)); 464 return xyzModem_timeout; 465 } 466 } 467 ZM_DEBUG (zm_dump (__LINE__)); 468 /* Validate the message */ 469 if ((xyz.blk ^ xyz.cblk) != (unsigned char) 0xFF) 470 { 471 ZM_DEBUG (zm_dprintf 472 ("Framing error - blk: %x/%x/%x\n", xyz.blk, xyz.cblk, 473 (xyz.blk ^ xyz.cblk))); 474 ZM_DEBUG (zm_dump_buf (xyz.pkt, xyz.len)); 475 xyzModem_flush (); 476 return xyzModem_frame; 477 } 478 /* Verify checksum/CRC */ 479 if (xyz.crc_mode) 480 { 481 cksum = cyg_crc16 (xyz.pkt, xyz.len); 482 if (cksum != ((xyz.crc1 << 8) | xyz.crc2)) 483 { 484 ZM_DEBUG (zm_dprintf ("CRC error - recvd: %02x%02x, computed: %x\n", 485 xyz.crc1, xyz.crc2, cksum & 0xFFFF)); 486 return xyzModem_cksum; 487 } 488 } 489 else 490 { 491 cksum = 0; 492 for (i = 0; i < xyz.len; i++) 493 { 494 cksum += xyz.pkt[i]; 495 } 496 if (xyz.crc1 != (cksum & 0xFF)) 497 { 498 ZM_DEBUG (zm_dprintf 499 ("Checksum error - recvd: %x, computed: %x\n", xyz.crc1, 500 cksum & 0xFF)); 501 return xyzModem_cksum; 502 } 503 } 504 /* If we get here, the message passes [structural] muster */ 505 return 0; 506 } 507 508 int 509 xyzModem_stream_open (connection_info_t * info, int *err) 510 { 511 #ifdef REDBOOT 512 int console_chan; 513 #endif 514 int stat = 0; 515 int retries = xyzModem_MAX_RETRIES; 516 int crc_retries = xyzModem_MAX_RETRIES_WITH_CRC; 517 518 /* ZM_DEBUG(zm_out = zm_out_start); */ 519 #ifdef xyzModem_zmodem 520 if (info->mode == xyzModem_zmodem) 521 { 522 *err = xyzModem_noZmodem; 523 return -1; 524 } 525 #endif 526 527 #ifdef REDBOOT 528 /* Set up the I/O channel. Note: this allows for using a different port in the future */ 529 console_chan = 530 CYGACC_CALL_IF_SET_CONSOLE_COMM 531 (CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT); 532 if (info->chan >= 0) 533 { 534 CYGACC_CALL_IF_SET_CONSOLE_COMM (info->chan); 535 } 536 else 537 { 538 CYGACC_CALL_IF_SET_CONSOLE_COMM (console_chan); 539 } 540 xyz.__chan = CYGACC_CALL_IF_CONSOLE_PROCS (); 541 542 CYGACC_CALL_IF_SET_CONSOLE_COMM (console_chan); 543 CYGACC_COMM_IF_CONTROL (*xyz.__chan, __COMMCTL_SET_TIMEOUT, 544 xyzModem_CHAR_TIMEOUT); 545 #else 546 /* TODO: CHECK ! */ 547 int dummy = 0; 548 xyz.__chan = &dummy; 549 #endif 550 xyz.len = 0; 551 xyz.crc_mode = true; 552 xyz.at_eof = false; 553 xyz.tx_ack = false; 554 xyz.mode = info->mode; 555 xyz.total_retries = 0; 556 xyz.total_SOH = 0; 557 xyz.total_STX = 0; 558 xyz.total_CAN = 0; 559 #ifdef USE_YMODEM_LENGTH 560 xyz.read_length = 0; 561 xyz.file_length = 0; 562 #endif 563 564 CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK)); 565 566 if (xyz.mode == xyzModem_xmodem) 567 { 568 /* X-modem doesn't have an information header - exit here */ 569 xyz.next_blk = 1; 570 return 0; 571 } 572 573 while (retries-- > 0) 574 { 575 stat = xyzModem_get_hdr (); 576 if (stat == 0) 577 { 578 /* Y-modem file information header */ 579 if (xyz.blk == 0) 580 { 581 #ifdef USE_YMODEM_LENGTH 582 /* skip filename */ 583 while (*xyz.bufp++); 584 /* get the length */ 585 parse_num ((char *) xyz.bufp, &xyz.file_length, NULL, " "); 586 #endif 587 /* The rest of the file name data block quietly discarded */ 588 xyz.tx_ack = true; 589 } 590 xyz.next_blk = 1; 591 xyz.len = 0; 592 return 0; 593 } 594 else if (stat == xyzModem_timeout) 595 { 596 if (--crc_retries <= 0) 597 xyz.crc_mode = false; 598 CYGACC_CALL_IF_DELAY_US (5 * 100000); /* Extra delay for startup */ 599 CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK)); 600 xyz.total_retries++; 601 ZM_DEBUG (zm_dprintf ("NAK (%d)\n", __LINE__)); 602 } 603 if (stat == xyzModem_cancel) 604 { 605 break; 606 } 607 } 608 *err = stat; 609 ZM_DEBUG (zm_flush ()); 610 return -1; 611 } 612 613 int 614 xyzModem_stream_read (char *buf, int size, int *err) 615 { 616 int stat, total, len; 617 int retries; 618 619 total = 0; 620 stat = xyzModem_cancel; 621 /* Try and get 'size' bytes into the buffer */ 622 while (!xyz.at_eof && (size > 0)) 623 { 624 if (xyz.len == 0) 625 { 626 retries = xyzModem_MAX_RETRIES; 627 while (retries-- > 0) 628 { 629 stat = xyzModem_get_hdr (); 630 if (stat == 0) 631 { 632 if (xyz.blk == xyz.next_blk) 633 { 634 xyz.tx_ack = true; 635 ZM_DEBUG (zm_dprintf 636 ("ACK block %d (%d)\n", xyz.blk, __LINE__)); 637 xyz.next_blk = (xyz.next_blk + 1) & 0xFF; 638 639 #if defined(xyzModem_zmodem) || defined(USE_YMODEM_LENGTH) 640 if (xyz.mode == xyzModem_xmodem || xyz.file_length == 0) 641 { 642 #else 643 if (1) 644 { 645 #endif 646 /* Data blocks can be padded with ^Z (EOF) characters */ 647 /* This code tries to detect and remove them */ 648 if ((xyz.bufp[xyz.len - 1] == EOF) && 649 (xyz.bufp[xyz.len - 2] == EOF) && 650 (xyz.bufp[xyz.len - 3] == EOF)) 651 { 652 while (xyz.len 653 && (xyz.bufp[xyz.len - 1] == EOF)) 654 { 655 xyz.len--; 656 } 657 } 658 } 659 660 #ifdef USE_YMODEM_LENGTH 661 /* 662 * See if accumulated length exceeds that of the file. 663 * If so, reduce size (i.e., cut out pad bytes) 664 * Only do this for Y-modem (and Z-modem should it ever 665 * be supported since it can fall back to Y-modem mode). 666 */ 667 if (xyz.mode != xyzModem_xmodem && 0 != xyz.file_length) 668 { 669 xyz.read_length += xyz.len; 670 if (xyz.read_length > xyz.file_length) 671 { 672 xyz.len -= (xyz.read_length - xyz.file_length); 673 } 674 } 675 #endif 676 break; 677 } 678 else if (xyz.blk == ((xyz.next_blk - 1) & 0xFF)) 679 { 680 /* Just re-ACK this so sender will get on with it */ 681 CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK); 682 continue; /* Need new header */ 683 } 684 else 685 { 686 stat = xyzModem_sequence; 687 } 688 } 689 if (stat == xyzModem_cancel) 690 { 691 break; 692 } 693 if (stat == xyzModem_eof) 694 { 695 CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK); 696 ZM_DEBUG (zm_dprintf ("ACK (%d)\n", __LINE__)); 697 if (xyz.mode == xyzModem_ymodem) 698 { 699 CYGACC_COMM_IF_PUTC (*xyz.__chan, 700 (xyz.crc_mode ? 'C' : NAK)); 701 xyz.total_retries++; 702 ZM_DEBUG (zm_dprintf ("Reading Final Header\n")); 703 stat = xyzModem_get_hdr (); 704 CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK); 705 ZM_DEBUG (zm_dprintf ("FINAL ACK (%d)\n", __LINE__)); 706 } 707 xyz.at_eof = true; 708 break; 709 } 710 CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK)); 711 xyz.total_retries++; 712 ZM_DEBUG (zm_dprintf ("NAK (%d)\n", __LINE__)); 713 } 714 if (stat < 0) 715 { 716 *err = stat; 717 xyz.len = -1; 718 return total; 719 } 720 } 721 /* Don't "read" data from the EOF protocol package */ 722 if (!xyz.at_eof) 723 { 724 len = xyz.len; 725 if (size < len) 726 len = size; 727 memcpy (buf, xyz.bufp, len); 728 size -= len; 729 buf += len; 730 total += len; 731 xyz.len -= len; 732 xyz.bufp += len; 733 } 734 } 735 return total; 736 } 737 738 void 739 xyzModem_stream_close (int *err) 740 { 741 diag_printf 742 ("xyzModem - %s mode, %d(SOH)/%d(STX)/%d(CAN) packets, %d retries\n", 743 xyz.crc_mode ? "CRC" : "Cksum", xyz.total_SOH, xyz.total_STX, 744 xyz.total_CAN, xyz.total_retries); 745 ZM_DEBUG (zm_flush ()); 746 } 747 748 /* Need to be able to clean out the input buffer, so have to take the */ 749 /* getc */ 750 void 751 xyzModem_stream_terminate (bool abort, int (*getc) (void)) 752 { 753 int c; 754 755 if (abort) 756 { 757 ZM_DEBUG (zm_dprintf ("!!!! TRANSFER ABORT !!!!\n")); 758 switch (xyz.mode) 759 { 760 case xyzModem_xmodem: 761 case xyzModem_ymodem: 762 /* The X/YMODEM Spec seems to suggest that multiple CAN followed by an equal */ 763 /* number of Backspaces is a friendly way to get the other end to abort. */ 764 CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN); 765 CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN); 766 CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN); 767 CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN); 768 CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP); 769 CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP); 770 CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP); 771 CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP); 772 /* Now consume the rest of what's waiting on the line. */ 773 ZM_DEBUG (zm_dprintf ("Flushing serial line.\n")); 774 xyzModem_flush (); 775 xyz.at_eof = true; 776 break; 777 #ifdef xyzModem_zmodem 778 case xyzModem_zmodem: 779 /* Might support it some day I suppose. */ 780 #endif 781 break; 782 } 783 } 784 else 785 { 786 ZM_DEBUG (zm_dprintf ("Engaging cleanup mode...\n")); 787 /* 788 * Consume any trailing crap left in the inbuffer from 789 * previous received blocks. Since very few files are an exact multiple 790 * of the transfer block size, there will almost always be some gunk here. 791 * If we don't eat it now, RedBoot will think the user typed it. 792 */ 793 ZM_DEBUG (zm_dprintf ("Trailing gunk:\n")); 794 while ((c = (*getc) ()) > -1); 795 ZM_DEBUG (zm_dprintf ("\n")); 796 /* 797 * Make a small delay to give terminal programs like minicom 798 * time to get control again after their file transfer program 799 * exits. 800 */ 801 CYGACC_CALL_IF_DELAY_US ((cyg_int32) 250000); 802 } 803 } 804 805 char * 806 xyzModem_error (int err) 807 { 808 switch (err) 809 { 810 case xyzModem_access: 811 return "Can't access file"; 812 break; 813 case xyzModem_noZmodem: 814 return "Sorry, zModem not available yet"; 815 break; 816 case xyzModem_timeout: 817 return "Timed out"; 818 break; 819 case xyzModem_eof: 820 return "End of file"; 821 break; 822 case xyzModem_cancel: 823 return "Cancelled"; 824 break; 825 case xyzModem_frame: 826 return "Invalid framing"; 827 break; 828 case xyzModem_cksum: 829 return "CRC/checksum error"; 830 break; 831 case xyzModem_sequence: 832 return "Block sequence error"; 833 break; 834 default: 835 return "Unknown error"; 836 break; 837 } 838 } 839 840 /* 841 * RedBoot interface 842 */ 843 #if 0 /* SB */ 844 GETC_IO_FUNCS (xyzModem_io, xyzModem_stream_open, xyzModem_stream_close, 845 xyzModem_stream_terminate, xyzModem_stream_read, 846 xyzModem_error); 847 RedBoot_load (xmodem, xyzModem_io, false, false, xyzModem_xmodem); 848 RedBoot_load (ymodem, xyzModem_io, false, false, xyzModem_ymodem); 849 #endif 850