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