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