xref: /openbmc/u-boot/common/xyzModem.c (revision e807f6b5f9a164dc1fc35e1c733fa343acf335c0)
183d290c5STom Rini // SPDX-License-Identifier: eCos-2.0
2cf48eb9aSWolfgang Denk /*
3cf48eb9aSWolfgang Denk  *==========================================================================
4cf48eb9aSWolfgang Denk  *
5cf48eb9aSWolfgang Denk  *      xyzModem.c
6cf48eb9aSWolfgang Denk  *
7cf48eb9aSWolfgang Denk  *      RedBoot stream handler for xyzModem protocol
8cf48eb9aSWolfgang Denk  *
9cf48eb9aSWolfgang Denk  *==========================================================================
10cf48eb9aSWolfgang Denk  *#####DESCRIPTIONBEGIN####
11cf48eb9aSWolfgang Denk  *
12cf48eb9aSWolfgang Denk  * Author(s):    gthomas
13cf48eb9aSWolfgang Denk  * Contributors: gthomas, tsmith, Yoshinori Sato
14cf48eb9aSWolfgang Denk  * Date:         2000-07-14
15cf48eb9aSWolfgang Denk  * Purpose:
16cf48eb9aSWolfgang Denk  * Description:
17cf48eb9aSWolfgang Denk  *
18cf48eb9aSWolfgang Denk  * This code is part of RedBoot (tm).
19cf48eb9aSWolfgang Denk  *
20cf48eb9aSWolfgang Denk  *####DESCRIPTIONEND####
21cf48eb9aSWolfgang Denk  *
22cf48eb9aSWolfgang Denk  *==========================================================================
23cf48eb9aSWolfgang Denk  */
24f2841d37SMarkus Klotzbuecher #include <common.h>
25f2841d37SMarkus Klotzbuecher #include <xyzModem.h>
26f2841d37SMarkus Klotzbuecher #include <stdarg.h>
27a740ee91SPhilipp Tomsich #include <u-boot/crc.h>
28*a4773c55SLokesh Vutla #include <watchdog.h>
29f2841d37SMarkus Klotzbuecher 
30cf48eb9aSWolfgang Denk /* Assumption - run xyzModem protocol over the console port */
31f2841d37SMarkus Klotzbuecher 
32cf48eb9aSWolfgang Denk /* Values magic to the protocol */
33f2841d37SMarkus Klotzbuecher #define SOH 0x01
34f2841d37SMarkus Klotzbuecher #define STX 0x02
35f2841d37SMarkus Klotzbuecher #define EOT 0x04
36f2841d37SMarkus Klotzbuecher #define ACK 0x06
37f2841d37SMarkus Klotzbuecher #define BSP 0x08
38f2841d37SMarkus Klotzbuecher #define NAK 0x15
39f2841d37SMarkus Klotzbuecher #define CAN 0x18
40cf48eb9aSWolfgang Denk #define EOF 0x1A		/* ^Z for DOS officionados */
41f2841d37SMarkus Klotzbuecher 
42cf48eb9aSWolfgang Denk /* Data & state local to the protocol */
437d0432c9SWolfgang Denk static struct
447d0432c9SWolfgang Denk {
45f2841d37SMarkus Klotzbuecher   int *__chan;
46f2841d37SMarkus Klotzbuecher   unsigned char pkt[1024], *bufp;
47f2841d37SMarkus Klotzbuecher   unsigned char blk, cblk, crc1, crc2;
48cf48eb9aSWolfgang Denk   unsigned char next_blk;	/* Expected block */
49f2841d37SMarkus Klotzbuecher   int len, mode, total_retries;
50f2841d37SMarkus Klotzbuecher   int total_SOH, total_STX, total_CAN;
51f2841d37SMarkus Klotzbuecher   bool crc_mode, at_eof, tx_ack;
52f2841d37SMarkus Klotzbuecher   unsigned long file_length, read_length;
53f2841d37SMarkus Klotzbuecher } xyz;
54f2841d37SMarkus Klotzbuecher 
55cf48eb9aSWolfgang Denk #define xyzModem_CHAR_TIMEOUT            2000	/* 2 seconds */
56f2841d37SMarkus Klotzbuecher #define xyzModem_MAX_RETRIES             20
57f2841d37SMarkus Klotzbuecher #define xyzModem_MAX_RETRIES_WITH_CRC    10
58cf48eb9aSWolfgang Denk #define xyzModem_CAN_COUNT                3	/* Wait for 3 CAN before quitting */
59f2841d37SMarkus Klotzbuecher 
60f2841d37SMarkus Klotzbuecher 
61f2841d37SMarkus Klotzbuecher typedef int cyg_int32;
62199adb60SKim Phillips static int
CYGACC_COMM_IF_GETC_TIMEOUT(char chan,char * c)637d0432c9SWolfgang Denk CYGACC_COMM_IF_GETC_TIMEOUT (char chan, char *c)
647d0432c9SWolfgang Denk {
652c77c0d6Stomas.melin@vaisala.com 
662c77c0d6Stomas.melin@vaisala.com   ulong now = get_timer(0);
67*a4773c55SLokesh Vutla   WATCHDOG_RESET();
682c77c0d6Stomas.melin@vaisala.com   while (!tstc ())
697d0432c9SWolfgang Denk     {
702c77c0d6Stomas.melin@vaisala.com       if (get_timer(now) > xyzModem_CHAR_TIMEOUT)
712c77c0d6Stomas.melin@vaisala.com         break;
72f2841d37SMarkus Klotzbuecher     }
737d0432c9SWolfgang Denk   if (tstc ())
747d0432c9SWolfgang Denk     {
75f2841d37SMarkus Klotzbuecher       *c = getc ();
76f2841d37SMarkus Klotzbuecher       return 1;
77f2841d37SMarkus Klotzbuecher     }
78f2841d37SMarkus Klotzbuecher   return 0;
79f2841d37SMarkus Klotzbuecher }
80f2841d37SMarkus Klotzbuecher 
81199adb60SKim Phillips static void
CYGACC_COMM_IF_PUTC(char x,char y)827d0432c9SWolfgang Denk CYGACC_COMM_IF_PUTC (char x, char y)
837d0432c9SWolfgang Denk {
84f2841d37SMarkus Klotzbuecher   putc (y);
85f2841d37SMarkus Klotzbuecher }
86f2841d37SMarkus Klotzbuecher 
87cf48eb9aSWolfgang Denk /* Validate a hex character */
88f2841d37SMarkus Klotzbuecher __inline__ static bool
_is_hex(char c)89f2841d37SMarkus Klotzbuecher _is_hex (char c)
90f2841d37SMarkus Klotzbuecher {
91f2841d37SMarkus Klotzbuecher   return (((c >= '0') && (c <= '9')) ||
927d0432c9SWolfgang Denk 	  ((c >= 'A') && (c <= 'F')) || ((c >= 'a') && (c <= 'f')));
93f2841d37SMarkus Klotzbuecher }
94f2841d37SMarkus Klotzbuecher 
95cf48eb9aSWolfgang Denk /* Convert a single hex nibble */
96f2841d37SMarkus Klotzbuecher __inline__ static int
_from_hex(char c)97f2841d37SMarkus Klotzbuecher _from_hex (char c)
98f2841d37SMarkus Klotzbuecher {
99f2841d37SMarkus Klotzbuecher   int ret = 0;
100f2841d37SMarkus Klotzbuecher 
1017d0432c9SWolfgang Denk   if ((c >= '0') && (c <= '9'))
1027d0432c9SWolfgang Denk     {
103f2841d37SMarkus Klotzbuecher       ret = (c - '0');
1047d0432c9SWolfgang Denk     }
1057d0432c9SWolfgang Denk   else if ((c >= 'a') && (c <= 'f'))
1067d0432c9SWolfgang Denk     {
107f2841d37SMarkus Klotzbuecher       ret = (c - 'a' + 0x0a);
1087d0432c9SWolfgang Denk     }
1097d0432c9SWolfgang Denk   else if ((c >= 'A') && (c <= 'F'))
1107d0432c9SWolfgang Denk     {
111f2841d37SMarkus Klotzbuecher       ret = (c - 'A' + 0x0A);
112f2841d37SMarkus Klotzbuecher     }
113f2841d37SMarkus Klotzbuecher   return ret;
114f2841d37SMarkus Klotzbuecher }
115f2841d37SMarkus Klotzbuecher 
116cf48eb9aSWolfgang Denk /* Convert a character to lower case */
117f2841d37SMarkus Klotzbuecher __inline__ static char
_tolower(char c)118f2841d37SMarkus Klotzbuecher _tolower (char c)
119f2841d37SMarkus Klotzbuecher {
1207d0432c9SWolfgang Denk   if ((c >= 'A') && (c <= 'Z'))
1217d0432c9SWolfgang Denk     {
122f2841d37SMarkus Klotzbuecher       c = (c - 'A') + 'a';
123f2841d37SMarkus Klotzbuecher     }
124f2841d37SMarkus Klotzbuecher   return c;
125f2841d37SMarkus Klotzbuecher }
126f2841d37SMarkus Klotzbuecher 
127cf48eb9aSWolfgang Denk /* Parse (scan) a number */
128199adb60SKim Phillips static bool
parse_num(char * s,unsigned long * val,char ** es,char * delim)129f2841d37SMarkus Klotzbuecher parse_num (char *s, unsigned long *val, char **es, char *delim)
130f2841d37SMarkus Klotzbuecher {
131f2841d37SMarkus Klotzbuecher   bool first = true;
132f2841d37SMarkus Klotzbuecher   int radix = 10;
133f2841d37SMarkus Klotzbuecher   char c;
134f2841d37SMarkus Klotzbuecher   unsigned long result = 0;
135f2841d37SMarkus Klotzbuecher   int digit;
136f2841d37SMarkus Klotzbuecher 
1377d0432c9SWolfgang Denk   while (*s == ' ')
1387d0432c9SWolfgang Denk     s++;
1397d0432c9SWolfgang Denk   while (*s)
1407d0432c9SWolfgang Denk     {
1417d0432c9SWolfgang Denk       if (first && (s[0] == '0') && (_tolower (s[1]) == 'x'))
1427d0432c9SWolfgang Denk 	{
143f2841d37SMarkus Klotzbuecher 	  radix = 16;
144f2841d37SMarkus Klotzbuecher 	  s += 2;
145f2841d37SMarkus Klotzbuecher 	}
146f2841d37SMarkus Klotzbuecher       first = false;
147f2841d37SMarkus Klotzbuecher       c = *s++;
1487d0432c9SWolfgang Denk       if (_is_hex (c) && ((digit = _from_hex (c)) < radix))
1497d0432c9SWolfgang Denk 	{
150cf48eb9aSWolfgang Denk 	  /* Valid digit */
151f2841d37SMarkus Klotzbuecher 	  result = (result * radix) + digit;
1527d0432c9SWolfgang Denk 	}
1537d0432c9SWolfgang Denk       else
1547d0432c9SWolfgang Denk 	{
1557d0432c9SWolfgang Denk 	  if (delim != (char *) 0)
1567d0432c9SWolfgang Denk 	    {
157cf48eb9aSWolfgang Denk 	      /* See if this character is one of the delimiters */
158f2841d37SMarkus Klotzbuecher 	      char *dp = delim;
1597d0432c9SWolfgang Denk 	      while (*dp && (c != *dp))
1607d0432c9SWolfgang Denk 		dp++;
1617d0432c9SWolfgang Denk 	      if (*dp)
1627d0432c9SWolfgang Denk 		break;		/* Found a good delimiter */
163f2841d37SMarkus Klotzbuecher 	    }
164cf48eb9aSWolfgang Denk 	  return false;		/* Malformatted number */
165f2841d37SMarkus Klotzbuecher 	}
166f2841d37SMarkus Klotzbuecher     }
167f2841d37SMarkus Klotzbuecher   *val = result;
1687d0432c9SWolfgang Denk   if (es != (char **) 0)
1697d0432c9SWolfgang Denk     {
170f2841d37SMarkus Klotzbuecher       *es = s;
171f2841d37SMarkus Klotzbuecher     }
172f2841d37SMarkus Klotzbuecher   return true;
173f2841d37SMarkus Klotzbuecher }
174f2841d37SMarkus Klotzbuecher 
175f2841d37SMarkus Klotzbuecher 
1768140816eSAlex Kiernan #if defined(DEBUG) && !defined(CONFIG_USE_TINY_PRINTF)
177cf48eb9aSWolfgang Denk /*
178cf48eb9aSWolfgang Denk  * Note: this debug setup works by storing the strings in a fixed buffer
179cf48eb9aSWolfgang Denk  */
180b09ece08SAlexandru Gagniuc static char zm_debug_buf[8192];
181b09ece08SAlexandru Gagniuc static char *zm_out = zm_debug_buf;
182b09ece08SAlexandru Gagniuc static char *zm_out_start = zm_debug_buf;
183f2841d37SMarkus Klotzbuecher 
184f2841d37SMarkus Klotzbuecher static int
zm_dprintf(char * fmt,...)185f2841d37SMarkus Klotzbuecher zm_dprintf(char *fmt, ...)
186f2841d37SMarkus Klotzbuecher {
187f2841d37SMarkus Klotzbuecher 	int len;
188f2841d37SMarkus Klotzbuecher 	va_list args;
189f2841d37SMarkus Klotzbuecher 
190f2841d37SMarkus Klotzbuecher 	va_start(args, fmt);
191f2841d37SMarkus Klotzbuecher 	len = diag_vsprintf(zm_out, fmt, args);
19223c64898SHeinrich Schuchardt 	va_end(args);
193f2841d37SMarkus Klotzbuecher 	zm_out += len;
194f2841d37SMarkus Klotzbuecher 	return len;
195f2841d37SMarkus Klotzbuecher }
196f2841d37SMarkus Klotzbuecher 
197f2841d37SMarkus Klotzbuecher static void
zm_flush(void)198f2841d37SMarkus Klotzbuecher zm_flush (void)
199f2841d37SMarkus Klotzbuecher {
200f2841d37SMarkus Klotzbuecher   zm_out = zm_out_start;
201f2841d37SMarkus Klotzbuecher }
202f2841d37SMarkus Klotzbuecher 
203f2841d37SMarkus Klotzbuecher static void
zm_dump_buf(void * buf,int len)204f2841d37SMarkus Klotzbuecher zm_dump_buf (void *buf, int len)
205f2841d37SMarkus Klotzbuecher {
206f2841d37SMarkus Klotzbuecher 
207f2841d37SMarkus Klotzbuecher }
208f2841d37SMarkus Klotzbuecher 
209f2841d37SMarkus Klotzbuecher static unsigned char zm_buf[2048];
210f2841d37SMarkus Klotzbuecher static unsigned char *zm_bp;
211f2841d37SMarkus Klotzbuecher 
212f2841d37SMarkus Klotzbuecher static void
zm_new(void)213f2841d37SMarkus Klotzbuecher zm_new (void)
214f2841d37SMarkus Klotzbuecher {
215f2841d37SMarkus Klotzbuecher   zm_bp = zm_buf;
216f2841d37SMarkus Klotzbuecher }
217f2841d37SMarkus Klotzbuecher 
218f2841d37SMarkus Klotzbuecher static void
zm_save(unsigned char c)219f2841d37SMarkus Klotzbuecher zm_save (unsigned char c)
220f2841d37SMarkus Klotzbuecher {
221f2841d37SMarkus Klotzbuecher   *zm_bp++ = c;
222f2841d37SMarkus Klotzbuecher }
223f2841d37SMarkus Klotzbuecher 
224f2841d37SMarkus Klotzbuecher static void
zm_dump(int line)225f2841d37SMarkus Klotzbuecher zm_dump (int line)
226f2841d37SMarkus Klotzbuecher {
227f2841d37SMarkus Klotzbuecher   zm_dprintf ("Packet at line: %d\n", line);
228f2841d37SMarkus Klotzbuecher   zm_dump_buf (zm_buf, zm_bp - zm_buf);
229f2841d37SMarkus Klotzbuecher }
230f2841d37SMarkus Klotzbuecher 
231f2841d37SMarkus Klotzbuecher #define ZM_DEBUG(x) x
232f2841d37SMarkus Klotzbuecher #else
233f2841d37SMarkus Klotzbuecher #define ZM_DEBUG(x)
234f2841d37SMarkus Klotzbuecher #endif
235f2841d37SMarkus Klotzbuecher 
236cf48eb9aSWolfgang Denk /* Wait for the line to go idle */
237f2841d37SMarkus Klotzbuecher static void
xyzModem_flush(void)238f2841d37SMarkus Klotzbuecher xyzModem_flush (void)
239f2841d37SMarkus Klotzbuecher {
240f2841d37SMarkus Klotzbuecher   int res;
241f2841d37SMarkus Klotzbuecher   char c;
2427d0432c9SWolfgang Denk   while (true)
2437d0432c9SWolfgang Denk     {
244f2841d37SMarkus Klotzbuecher       res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c);
2457d0432c9SWolfgang Denk       if (!res)
2467d0432c9SWolfgang Denk 	return;
247f2841d37SMarkus Klotzbuecher     }
248f2841d37SMarkus Klotzbuecher }
249f2841d37SMarkus Klotzbuecher 
250f2841d37SMarkus Klotzbuecher static int
xyzModem_get_hdr(void)251f2841d37SMarkus Klotzbuecher xyzModem_get_hdr (void)
252f2841d37SMarkus Klotzbuecher {
253f2841d37SMarkus Klotzbuecher   char c;
254f2841d37SMarkus Klotzbuecher   int res;
255f2841d37SMarkus Klotzbuecher   bool hdr_found = false;
256f2841d37SMarkus Klotzbuecher   int i, can_total, hdr_chars;
257f2841d37SMarkus Klotzbuecher   unsigned short cksum;
258f2841d37SMarkus Klotzbuecher 
259f2841d37SMarkus Klotzbuecher   ZM_DEBUG (zm_new ());
260cf48eb9aSWolfgang Denk   /* Find the start of a header */
261f2841d37SMarkus Klotzbuecher   can_total = 0;
262f2841d37SMarkus Klotzbuecher   hdr_chars = 0;
263f2841d37SMarkus Klotzbuecher 
2647d0432c9SWolfgang Denk   if (xyz.tx_ack)
2657d0432c9SWolfgang Denk     {
266f2841d37SMarkus Klotzbuecher       CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
267f2841d37SMarkus Klotzbuecher       xyz.tx_ack = false;
268f2841d37SMarkus Klotzbuecher     }
2697d0432c9SWolfgang Denk   while (!hdr_found)
2707d0432c9SWolfgang Denk     {
271f2841d37SMarkus Klotzbuecher       res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c);
272f2841d37SMarkus Klotzbuecher       ZM_DEBUG (zm_save (c));
2737d0432c9SWolfgang Denk       if (res)
2747d0432c9SWolfgang Denk 	{
275f2841d37SMarkus Klotzbuecher 	  hdr_chars++;
2767d0432c9SWolfgang Denk 	  switch (c)
2777d0432c9SWolfgang Denk 	    {
278f2841d37SMarkus Klotzbuecher 	    case SOH:
279f2841d37SMarkus Klotzbuecher 	      xyz.total_SOH++;
280f2841d37SMarkus Klotzbuecher 	    case STX:
2817d0432c9SWolfgang Denk 	      if (c == STX)
2827d0432c9SWolfgang Denk 		xyz.total_STX++;
283f2841d37SMarkus Klotzbuecher 	      hdr_found = true;
284f2841d37SMarkus Klotzbuecher 	      break;
285f2841d37SMarkus Klotzbuecher 	    case CAN:
286f2841d37SMarkus Klotzbuecher 	      xyz.total_CAN++;
287f2841d37SMarkus Klotzbuecher 	      ZM_DEBUG (zm_dump (__LINE__));
2887d0432c9SWolfgang Denk 	      if (++can_total == xyzModem_CAN_COUNT)
2897d0432c9SWolfgang Denk 		{
290f2841d37SMarkus Klotzbuecher 		  return xyzModem_cancel;
2917d0432c9SWolfgang Denk 		}
2927d0432c9SWolfgang Denk 	      else
2937d0432c9SWolfgang Denk 		{
294cf48eb9aSWolfgang Denk 		  /* Wait for multiple CAN to avoid early quits */
295f2841d37SMarkus Klotzbuecher 		  break;
296f2841d37SMarkus Klotzbuecher 		}
297f2841d37SMarkus Klotzbuecher 	    case EOT:
298cf48eb9aSWolfgang Denk 	      /* EOT only supported if no noise */
2997d0432c9SWolfgang Denk 	      if (hdr_chars == 1)
3007d0432c9SWolfgang Denk 		{
301f2841d37SMarkus Klotzbuecher 		  CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
302f2841d37SMarkus Klotzbuecher 		  ZM_DEBUG (zm_dprintf ("ACK on EOT #%d\n", __LINE__));
303f2841d37SMarkus Klotzbuecher 		  ZM_DEBUG (zm_dump (__LINE__));
304f2841d37SMarkus Klotzbuecher 		  return xyzModem_eof;
305f2841d37SMarkus Klotzbuecher 		}
306f2841d37SMarkus Klotzbuecher 	    default:
307cf48eb9aSWolfgang Denk 	      /* Ignore, waiting for start of header */
308f2841d37SMarkus Klotzbuecher 	      ;
309f2841d37SMarkus Klotzbuecher 	    }
3107d0432c9SWolfgang Denk 	}
3117d0432c9SWolfgang Denk       else
3127d0432c9SWolfgang Denk 	{
313cf48eb9aSWolfgang Denk 	  /* Data stream timed out */
314cf48eb9aSWolfgang Denk 	  xyzModem_flush ();	/* Toss any current input */
315f2841d37SMarkus Klotzbuecher 	  ZM_DEBUG (zm_dump (__LINE__));
316f2841d37SMarkus Klotzbuecher 	  CYGACC_CALL_IF_DELAY_US ((cyg_int32) 250000);
317f2841d37SMarkus Klotzbuecher 	  return xyzModem_timeout;
318f2841d37SMarkus Klotzbuecher 	}
319f2841d37SMarkus Klotzbuecher     }
320f2841d37SMarkus Klotzbuecher 
321cf48eb9aSWolfgang Denk   /* Header found, now read the data */
322f90a3921SStefan Roese   res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.blk);
323f2841d37SMarkus Klotzbuecher   ZM_DEBUG (zm_save (xyz.blk));
3247d0432c9SWolfgang Denk   if (!res)
3257d0432c9SWolfgang Denk     {
326f2841d37SMarkus Klotzbuecher       ZM_DEBUG (zm_dump (__LINE__));
327f2841d37SMarkus Klotzbuecher       return xyzModem_timeout;
328f2841d37SMarkus Klotzbuecher     }
329f90a3921SStefan Roese   res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.cblk);
330f2841d37SMarkus Klotzbuecher   ZM_DEBUG (zm_save (xyz.cblk));
3317d0432c9SWolfgang Denk   if (!res)
3327d0432c9SWolfgang Denk     {
333f2841d37SMarkus Klotzbuecher       ZM_DEBUG (zm_dump (__LINE__));
334f2841d37SMarkus Klotzbuecher       return xyzModem_timeout;
335f2841d37SMarkus Klotzbuecher     }
336f2841d37SMarkus Klotzbuecher   xyz.len = (c == SOH) ? 128 : 1024;
337f2841d37SMarkus Klotzbuecher   xyz.bufp = xyz.pkt;
3387d0432c9SWolfgang Denk   for (i = 0; i < xyz.len; i++)
3397d0432c9SWolfgang Denk     {
340f2841d37SMarkus Klotzbuecher       res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c);
341f2841d37SMarkus Klotzbuecher       ZM_DEBUG (zm_save (c));
3427d0432c9SWolfgang Denk       if (res)
3437d0432c9SWolfgang Denk 	{
344f2841d37SMarkus Klotzbuecher 	  xyz.pkt[i] = c;
3457d0432c9SWolfgang Denk 	}
3467d0432c9SWolfgang Denk       else
3477d0432c9SWolfgang Denk 	{
348f2841d37SMarkus Klotzbuecher 	  ZM_DEBUG (zm_dump (__LINE__));
349f2841d37SMarkus Klotzbuecher 	  return xyzModem_timeout;
350f2841d37SMarkus Klotzbuecher 	}
351f2841d37SMarkus Klotzbuecher     }
352f90a3921SStefan Roese   res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.crc1);
353f2841d37SMarkus Klotzbuecher   ZM_DEBUG (zm_save (xyz.crc1));
3547d0432c9SWolfgang Denk   if (!res)
3557d0432c9SWolfgang Denk     {
356f2841d37SMarkus Klotzbuecher       ZM_DEBUG (zm_dump (__LINE__));
357f2841d37SMarkus Klotzbuecher       return xyzModem_timeout;
358f2841d37SMarkus Klotzbuecher     }
3597d0432c9SWolfgang Denk   if (xyz.crc_mode)
3607d0432c9SWolfgang Denk     {
361f90a3921SStefan Roese       res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.crc2);
362f2841d37SMarkus Klotzbuecher       ZM_DEBUG (zm_save (xyz.crc2));
3637d0432c9SWolfgang Denk       if (!res)
3647d0432c9SWolfgang Denk 	{
365f2841d37SMarkus Klotzbuecher 	  ZM_DEBUG (zm_dump (__LINE__));
366f2841d37SMarkus Klotzbuecher 	  return xyzModem_timeout;
367f2841d37SMarkus Klotzbuecher 	}
368f2841d37SMarkus Klotzbuecher     }
369f2841d37SMarkus Klotzbuecher   ZM_DEBUG (zm_dump (__LINE__));
370cf48eb9aSWolfgang Denk   /* Validate the message */
3717d0432c9SWolfgang Denk   if ((xyz.blk ^ xyz.cblk) != (unsigned char) 0xFF)
3727d0432c9SWolfgang Denk     {
3737d0432c9SWolfgang Denk       ZM_DEBUG (zm_dprintf
3747d0432c9SWolfgang Denk 		("Framing error - blk: %x/%x/%x\n", xyz.blk, xyz.cblk,
3757d0432c9SWolfgang Denk 		 (xyz.blk ^ xyz.cblk)));
376f2841d37SMarkus Klotzbuecher       ZM_DEBUG (zm_dump_buf (xyz.pkt, xyz.len));
377f2841d37SMarkus Klotzbuecher       xyzModem_flush ();
378f2841d37SMarkus Klotzbuecher       return xyzModem_frame;
379f2841d37SMarkus Klotzbuecher     }
380cf48eb9aSWolfgang Denk   /* Verify checksum/CRC */
3817d0432c9SWolfgang Denk   if (xyz.crc_mode)
3827d0432c9SWolfgang Denk     {
383ecb57f69SStefan Roese       cksum = crc16_ccitt(0, xyz.pkt, xyz.len);
3847d0432c9SWolfgang Denk       if (cksum != ((xyz.crc1 << 8) | xyz.crc2))
3857d0432c9SWolfgang Denk 	{
386f2841d37SMarkus Klotzbuecher 	  ZM_DEBUG (zm_dprintf ("CRC error - recvd: %02x%02x, computed: %x\n",
387f2841d37SMarkus Klotzbuecher 				xyz.crc1, xyz.crc2, cksum & 0xFFFF));
388f2841d37SMarkus Klotzbuecher 	  return xyzModem_cksum;
389f2841d37SMarkus Klotzbuecher 	}
3907d0432c9SWolfgang Denk     }
3917d0432c9SWolfgang Denk   else
3927d0432c9SWolfgang Denk     {
393f2841d37SMarkus Klotzbuecher       cksum = 0;
3947d0432c9SWolfgang Denk       for (i = 0; i < xyz.len; i++)
3957d0432c9SWolfgang Denk 	{
396f2841d37SMarkus Klotzbuecher 	  cksum += xyz.pkt[i];
397f2841d37SMarkus Klotzbuecher 	}
3987d0432c9SWolfgang Denk       if (xyz.crc1 != (cksum & 0xFF))
3997d0432c9SWolfgang Denk 	{
4007d0432c9SWolfgang Denk 	  ZM_DEBUG (zm_dprintf
4017d0432c9SWolfgang Denk 		    ("Checksum error - recvd: %x, computed: %x\n", xyz.crc1,
4027d0432c9SWolfgang Denk 		     cksum & 0xFF));
403f2841d37SMarkus Klotzbuecher 	  return xyzModem_cksum;
404f2841d37SMarkus Klotzbuecher 	}
405f2841d37SMarkus Klotzbuecher     }
406cf48eb9aSWolfgang Denk   /* If we get here, the message passes [structural] muster */
407f2841d37SMarkus Klotzbuecher   return 0;
408f2841d37SMarkus Klotzbuecher }
409f2841d37SMarkus Klotzbuecher 
410f2841d37SMarkus Klotzbuecher int
xyzModem_stream_open(connection_info_t * info,int * err)411f2841d37SMarkus Klotzbuecher xyzModem_stream_open (connection_info_t * info, int *err)
412f2841d37SMarkus Klotzbuecher {
413f90a3921SStefan Roese   int stat = 0;
414f2841d37SMarkus Klotzbuecher   int retries = xyzModem_MAX_RETRIES;
415f2841d37SMarkus Klotzbuecher   int crc_retries = xyzModem_MAX_RETRIES_WITH_CRC;
416f2841d37SMarkus Klotzbuecher 
417cf48eb9aSWolfgang Denk /*    ZM_DEBUG(zm_out = zm_out_start); */
418f2841d37SMarkus Klotzbuecher #ifdef xyzModem_zmodem
4197d0432c9SWolfgang Denk   if (info->mode == xyzModem_zmodem)
4207d0432c9SWolfgang Denk     {
421f2841d37SMarkus Klotzbuecher       *err = xyzModem_noZmodem;
422f2841d37SMarkus Klotzbuecher       return -1;
423f2841d37SMarkus Klotzbuecher     }
424f2841d37SMarkus Klotzbuecher #endif
425f2841d37SMarkus Klotzbuecher 
426cf48eb9aSWolfgang Denk /* TODO: CHECK ! */
4272a2ed845SKim Phillips   int dummy = 0;
428f2841d37SMarkus Klotzbuecher   xyz.__chan = &dummy;
429f2841d37SMarkus Klotzbuecher   xyz.len = 0;
430f2841d37SMarkus Klotzbuecher   xyz.crc_mode = true;
431f2841d37SMarkus Klotzbuecher   xyz.at_eof = false;
432f2841d37SMarkus Klotzbuecher   xyz.tx_ack = false;
433f2841d37SMarkus Klotzbuecher   xyz.mode = info->mode;
434f2841d37SMarkus Klotzbuecher   xyz.total_retries = 0;
435f2841d37SMarkus Klotzbuecher   xyz.total_SOH = 0;
436f2841d37SMarkus Klotzbuecher   xyz.total_STX = 0;
437f2841d37SMarkus Klotzbuecher   xyz.total_CAN = 0;
438f2841d37SMarkus Klotzbuecher   xyz.read_length = 0;
439f2841d37SMarkus Klotzbuecher   xyz.file_length = 0;
440f2841d37SMarkus Klotzbuecher 
441f2841d37SMarkus Klotzbuecher   CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
442f2841d37SMarkus Klotzbuecher 
4437d0432c9SWolfgang Denk   if (xyz.mode == xyzModem_xmodem)
4447d0432c9SWolfgang Denk     {
445cf48eb9aSWolfgang Denk       /* X-modem doesn't have an information header - exit here */
446f2841d37SMarkus Klotzbuecher       xyz.next_blk = 1;
447f2841d37SMarkus Klotzbuecher       return 0;
448f2841d37SMarkus Klotzbuecher     }
449f2841d37SMarkus Klotzbuecher 
4507d0432c9SWolfgang Denk   while (retries-- > 0)
4517d0432c9SWolfgang Denk     {
452f2841d37SMarkus Klotzbuecher       stat = xyzModem_get_hdr ();
4537d0432c9SWolfgang Denk       if (stat == 0)
4547d0432c9SWolfgang Denk 	{
455cf48eb9aSWolfgang Denk 	  /* Y-modem file information header */
4567d0432c9SWolfgang Denk 	  if (xyz.blk == 0)
4577d0432c9SWolfgang Denk 	    {
458cf48eb9aSWolfgang Denk 	      /* skip filename */
459f2841d37SMarkus Klotzbuecher 	      while (*xyz.bufp++);
460cf48eb9aSWolfgang Denk 	      /* get the length */
461f90a3921SStefan Roese 	      parse_num ((char *) xyz.bufp, &xyz.file_length, NULL, " ");
462cf48eb9aSWolfgang Denk 	      /* The rest of the file name data block quietly discarded */
463f2841d37SMarkus Klotzbuecher 	      xyz.tx_ack = true;
464f2841d37SMarkus Klotzbuecher 	    }
465f2841d37SMarkus Klotzbuecher 	  xyz.next_blk = 1;
466f2841d37SMarkus Klotzbuecher 	  xyz.len = 0;
467f2841d37SMarkus Klotzbuecher 	  return 0;
4687d0432c9SWolfgang Denk 	}
4697d0432c9SWolfgang Denk       else if (stat == xyzModem_timeout)
4707d0432c9SWolfgang Denk 	{
4717d0432c9SWolfgang Denk 	  if (--crc_retries <= 0)
4727d0432c9SWolfgang Denk 	    xyz.crc_mode = false;
473cf48eb9aSWolfgang Denk 	  CYGACC_CALL_IF_DELAY_US (5 * 100000);	/* Extra delay for startup */
474f2841d37SMarkus Klotzbuecher 	  CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
475f2841d37SMarkus Klotzbuecher 	  xyz.total_retries++;
476f2841d37SMarkus Klotzbuecher 	  ZM_DEBUG (zm_dprintf ("NAK (%d)\n", __LINE__));
477f2841d37SMarkus Klotzbuecher 	}
4787d0432c9SWolfgang Denk       if (stat == xyzModem_cancel)
4797d0432c9SWolfgang Denk 	{
480f2841d37SMarkus Klotzbuecher 	  break;
481f2841d37SMarkus Klotzbuecher 	}
482f2841d37SMarkus Klotzbuecher     }
483f2841d37SMarkus Klotzbuecher   *err = stat;
484f2841d37SMarkus Klotzbuecher   ZM_DEBUG (zm_flush ());
485f2841d37SMarkus Klotzbuecher   return -1;
486f2841d37SMarkus Klotzbuecher }
487f2841d37SMarkus Klotzbuecher 
488f2841d37SMarkus Klotzbuecher int
xyzModem_stream_read(char * buf,int size,int * err)489f2841d37SMarkus Klotzbuecher xyzModem_stream_read (char *buf, int size, int *err)
490f2841d37SMarkus Klotzbuecher {
491f2841d37SMarkus Klotzbuecher   int stat, total, len;
492f2841d37SMarkus Klotzbuecher   int retries;
493f2841d37SMarkus Klotzbuecher 
494f2841d37SMarkus Klotzbuecher   total = 0;
495f2841d37SMarkus Klotzbuecher   stat = xyzModem_cancel;
496cf48eb9aSWolfgang Denk   /* Try and get 'size' bytes into the buffer */
4977d0432c9SWolfgang Denk   while (!xyz.at_eof && (size > 0))
4987d0432c9SWolfgang Denk     {
4997d0432c9SWolfgang Denk       if (xyz.len == 0)
5007d0432c9SWolfgang Denk 	{
501f2841d37SMarkus Klotzbuecher 	  retries = xyzModem_MAX_RETRIES;
5027d0432c9SWolfgang Denk 	  while (retries-- > 0)
5037d0432c9SWolfgang Denk 	    {
504f2841d37SMarkus Klotzbuecher 	      stat = xyzModem_get_hdr ();
5057d0432c9SWolfgang Denk 	      if (stat == 0)
5067d0432c9SWolfgang Denk 		{
5077d0432c9SWolfgang Denk 		  if (xyz.blk == xyz.next_blk)
5087d0432c9SWolfgang Denk 		    {
509f2841d37SMarkus Klotzbuecher 		      xyz.tx_ack = true;
5107d0432c9SWolfgang Denk 		      ZM_DEBUG (zm_dprintf
5117d0432c9SWolfgang Denk 				("ACK block %d (%d)\n", xyz.blk, __LINE__));
512f2841d37SMarkus Klotzbuecher 		      xyz.next_blk = (xyz.next_blk + 1) & 0xFF;
513f2841d37SMarkus Klotzbuecher 
5147d0432c9SWolfgang Denk 		      if (xyz.mode == xyzModem_xmodem || xyz.file_length == 0)
5157d0432c9SWolfgang Denk 			{
516cf48eb9aSWolfgang Denk 			  /* Data blocks can be padded with ^Z (EOF) characters */
517cf48eb9aSWolfgang Denk 			  /* This code tries to detect and remove them */
518f2841d37SMarkus Klotzbuecher 			  if ((xyz.bufp[xyz.len - 1] == EOF) &&
519f2841d37SMarkus Klotzbuecher 			      (xyz.bufp[xyz.len - 2] == EOF) &&
5207d0432c9SWolfgang Denk 			      (xyz.bufp[xyz.len - 3] == EOF))
5217d0432c9SWolfgang Denk 			    {
5227d0432c9SWolfgang Denk 			      while (xyz.len
5237d0432c9SWolfgang Denk 				     && (xyz.bufp[xyz.len - 1] == EOF))
5247d0432c9SWolfgang Denk 				{
525f2841d37SMarkus Klotzbuecher 				  xyz.len--;
526f2841d37SMarkus Klotzbuecher 				}
527f2841d37SMarkus Klotzbuecher 			    }
528f2841d37SMarkus Klotzbuecher 			}
529f2841d37SMarkus Klotzbuecher 
530cf48eb9aSWolfgang Denk 		      /*
531cf48eb9aSWolfgang Denk 		       * See if accumulated length exceeds that of the file.
532cf48eb9aSWolfgang Denk 		       * If so, reduce size (i.e., cut out pad bytes)
533cf48eb9aSWolfgang Denk 		       * Only do this for Y-modem (and Z-modem should it ever
534cf48eb9aSWolfgang Denk 		       * be supported since it can fall back to Y-modem mode).
535cf48eb9aSWolfgang Denk 		       */
5367d0432c9SWolfgang Denk 		      if (xyz.mode != xyzModem_xmodem && 0 != xyz.file_length)
5377d0432c9SWolfgang Denk 			{
538f2841d37SMarkus Klotzbuecher 			  xyz.read_length += xyz.len;
5397d0432c9SWolfgang Denk 			  if (xyz.read_length > xyz.file_length)
5407d0432c9SWolfgang Denk 			    {
541f2841d37SMarkus Klotzbuecher 			      xyz.len -= (xyz.read_length - xyz.file_length);
542f2841d37SMarkus Klotzbuecher 			    }
543f2841d37SMarkus Klotzbuecher 			}
544f2841d37SMarkus Klotzbuecher 		      break;
5457d0432c9SWolfgang Denk 		    }
5467d0432c9SWolfgang Denk 		  else if (xyz.blk == ((xyz.next_blk - 1) & 0xFF))
5477d0432c9SWolfgang Denk 		    {
548cf48eb9aSWolfgang Denk 		      /* Just re-ACK this so sender will get on with it */
549f2841d37SMarkus Klotzbuecher 		      CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
550cf48eb9aSWolfgang Denk 		      continue;	/* Need new header */
5517d0432c9SWolfgang Denk 		    }
5527d0432c9SWolfgang Denk 		  else
5537d0432c9SWolfgang Denk 		    {
554f2841d37SMarkus Klotzbuecher 		      stat = xyzModem_sequence;
555f2841d37SMarkus Klotzbuecher 		    }
556f2841d37SMarkus Klotzbuecher 		}
5577d0432c9SWolfgang Denk 	      if (stat == xyzModem_cancel)
5587d0432c9SWolfgang Denk 		{
559f2841d37SMarkus Klotzbuecher 		  break;
560f2841d37SMarkus Klotzbuecher 		}
5617d0432c9SWolfgang Denk 	      if (stat == xyzModem_eof)
5627d0432c9SWolfgang Denk 		{
563f2841d37SMarkus Klotzbuecher 		  CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
564f2841d37SMarkus Klotzbuecher 		  ZM_DEBUG (zm_dprintf ("ACK (%d)\n", __LINE__));
5657d0432c9SWolfgang Denk 		  if (xyz.mode == xyzModem_ymodem)
5667d0432c9SWolfgang Denk 		    {
5677d0432c9SWolfgang Denk 		      CYGACC_COMM_IF_PUTC (*xyz.__chan,
5687d0432c9SWolfgang Denk 					   (xyz.crc_mode ? 'C' : NAK));
569f2841d37SMarkus Klotzbuecher 		      xyz.total_retries++;
570f2841d37SMarkus Klotzbuecher 		      ZM_DEBUG (zm_dprintf ("Reading Final Header\n"));
571f2841d37SMarkus Klotzbuecher 		      stat = xyzModem_get_hdr ();
572f2841d37SMarkus Klotzbuecher 		      CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
573f2841d37SMarkus Klotzbuecher 		      ZM_DEBUG (zm_dprintf ("FINAL ACK (%d)\n", __LINE__));
574f2841d37SMarkus Klotzbuecher 		    }
575f2841d37SMarkus Klotzbuecher 		  xyz.at_eof = true;
576f2841d37SMarkus Klotzbuecher 		  break;
577f2841d37SMarkus Klotzbuecher 		}
578f2841d37SMarkus Klotzbuecher 	      CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
579f2841d37SMarkus Klotzbuecher 	      xyz.total_retries++;
580f2841d37SMarkus Klotzbuecher 	      ZM_DEBUG (zm_dprintf ("NAK (%d)\n", __LINE__));
581f2841d37SMarkus Klotzbuecher 	    }
5827d0432c9SWolfgang Denk 	  if (stat < 0)
5837d0432c9SWolfgang Denk 	    {
584f2841d37SMarkus Klotzbuecher 	      *err = stat;
585f2841d37SMarkus Klotzbuecher 	      xyz.len = -1;
586f2841d37SMarkus Klotzbuecher 	      return total;
587f2841d37SMarkus Klotzbuecher 	    }
588f2841d37SMarkus Klotzbuecher 	}
589cf48eb9aSWolfgang Denk       /* Don't "read" data from the EOF protocol package */
5907d0432c9SWolfgang Denk       if (!xyz.at_eof)
5917d0432c9SWolfgang Denk 	{
592f2841d37SMarkus Klotzbuecher 	  len = xyz.len;
5937d0432c9SWolfgang Denk 	  if (size < len)
5947d0432c9SWolfgang Denk 	    len = size;
595f2841d37SMarkus Klotzbuecher 	  memcpy (buf, xyz.bufp, len);
596f2841d37SMarkus Klotzbuecher 	  size -= len;
597f2841d37SMarkus Klotzbuecher 	  buf += len;
598f2841d37SMarkus Klotzbuecher 	  total += len;
599f2841d37SMarkus Klotzbuecher 	  xyz.len -= len;
600f2841d37SMarkus Klotzbuecher 	  xyz.bufp += len;
601f2841d37SMarkus Klotzbuecher 	}
602f2841d37SMarkus Klotzbuecher     }
603f2841d37SMarkus Klotzbuecher   return total;
604f2841d37SMarkus Klotzbuecher }
605f2841d37SMarkus Klotzbuecher 
606f2841d37SMarkus Klotzbuecher void
xyzModem_stream_close(int * err)607f2841d37SMarkus Klotzbuecher xyzModem_stream_close (int *err)
608f2841d37SMarkus Klotzbuecher {
6097d0432c9SWolfgang Denk   diag_printf
6107d0432c9SWolfgang Denk     ("xyzModem - %s mode, %d(SOH)/%d(STX)/%d(CAN) packets, %d retries\n",
6117d0432c9SWolfgang Denk      xyz.crc_mode ? "CRC" : "Cksum", xyz.total_SOH, xyz.total_STX,
6127d0432c9SWolfgang Denk      xyz.total_CAN, xyz.total_retries);
613f2841d37SMarkus Klotzbuecher   ZM_DEBUG (zm_flush ());
614f2841d37SMarkus Klotzbuecher }
615f2841d37SMarkus Klotzbuecher 
616cf48eb9aSWolfgang Denk /* Need to be able to clean out the input buffer, so have to take the */
617cf48eb9aSWolfgang Denk /* getc */
6187d0432c9SWolfgang Denk void
xyzModem_stream_terminate(bool abort,int (* getc)(void))6197d0432c9SWolfgang Denk xyzModem_stream_terminate (bool abort, int (*getc) (void))
620f2841d37SMarkus Klotzbuecher {
621f2841d37SMarkus Klotzbuecher   int c;
622f2841d37SMarkus Klotzbuecher 
6237d0432c9SWolfgang Denk   if (abort)
6247d0432c9SWolfgang Denk     {
625f2841d37SMarkus Klotzbuecher       ZM_DEBUG (zm_dprintf ("!!!! TRANSFER ABORT !!!!\n"));
6267d0432c9SWolfgang Denk       switch (xyz.mode)
6277d0432c9SWolfgang Denk 	{
628f2841d37SMarkus Klotzbuecher 	case xyzModem_xmodem:
629f2841d37SMarkus Klotzbuecher 	case xyzModem_ymodem:
630cf48eb9aSWolfgang Denk 	  /* The X/YMODEM Spec seems to suggest that multiple CAN followed by an equal */
631cf48eb9aSWolfgang Denk 	  /* number of Backspaces is a friendly way to get the other end to abort. */
632f2841d37SMarkus Klotzbuecher 	  CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
633f2841d37SMarkus Klotzbuecher 	  CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
634f2841d37SMarkus Klotzbuecher 	  CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
635f2841d37SMarkus Klotzbuecher 	  CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
636f2841d37SMarkus Klotzbuecher 	  CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
637f2841d37SMarkus Klotzbuecher 	  CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
638f2841d37SMarkus Klotzbuecher 	  CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
639f2841d37SMarkus Klotzbuecher 	  CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
640cf48eb9aSWolfgang Denk 	  /* Now consume the rest of what's waiting on the line. */
641f2841d37SMarkus Klotzbuecher 	  ZM_DEBUG (zm_dprintf ("Flushing serial line.\n"));
642f2841d37SMarkus Klotzbuecher 	  xyzModem_flush ();
643f2841d37SMarkus Klotzbuecher 	  xyz.at_eof = true;
644f2841d37SMarkus Klotzbuecher 	  break;
645f2841d37SMarkus Klotzbuecher #ifdef xyzModem_zmodem
646f2841d37SMarkus Klotzbuecher 	case xyzModem_zmodem:
647cf48eb9aSWolfgang Denk 	  /* Might support it some day I suppose. */
648f2841d37SMarkus Klotzbuecher #endif
649f2841d37SMarkus Klotzbuecher 	  break;
650f2841d37SMarkus Klotzbuecher 	}
6517d0432c9SWolfgang Denk     }
6527d0432c9SWolfgang Denk   else
6537d0432c9SWolfgang Denk     {
654f2841d37SMarkus Klotzbuecher       ZM_DEBUG (zm_dprintf ("Engaging cleanup mode...\n"));
655cf48eb9aSWolfgang Denk       /*
656cf48eb9aSWolfgang Denk        * Consume any trailing crap left in the inbuffer from
65716263087SMike Williams        * previous received blocks. Since very few files are an exact multiple
658cf48eb9aSWolfgang Denk        * of the transfer block size, there will almost always be some gunk here.
659cf48eb9aSWolfgang Denk        * If we don't eat it now, RedBoot will think the user typed it.
660cf48eb9aSWolfgang Denk        */
661f2841d37SMarkus Klotzbuecher       ZM_DEBUG (zm_dprintf ("Trailing gunk:\n"));
662e153b13cSJeroen Hofstee       while ((c = (*getc) ()) > -1)
663e153b13cSJeroen Hofstee         ;
664f2841d37SMarkus Klotzbuecher       ZM_DEBUG (zm_dprintf ("\n"));
665cf48eb9aSWolfgang Denk       /*
666cf48eb9aSWolfgang Denk        * Make a small delay to give terminal programs like minicom
667cf48eb9aSWolfgang Denk        * time to get control again after their file transfer program
668cf48eb9aSWolfgang Denk        * exits.
669cf48eb9aSWolfgang Denk        */
670f2841d37SMarkus Klotzbuecher       CYGACC_CALL_IF_DELAY_US ((cyg_int32) 250000);
671f2841d37SMarkus Klotzbuecher     }
672f2841d37SMarkus Klotzbuecher }
673f2841d37SMarkus Klotzbuecher 
674f2841d37SMarkus Klotzbuecher char *
xyzModem_error(int err)675f2841d37SMarkus Klotzbuecher xyzModem_error (int err)
676f2841d37SMarkus Klotzbuecher {
6777d0432c9SWolfgang Denk   switch (err)
6787d0432c9SWolfgang Denk     {
679f2841d37SMarkus Klotzbuecher     case xyzModem_access:
680f2841d37SMarkus Klotzbuecher       return "Can't access file";
681f2841d37SMarkus Klotzbuecher       break;
682f2841d37SMarkus Klotzbuecher     case xyzModem_noZmodem:
683f2841d37SMarkus Klotzbuecher       return "Sorry, zModem not available yet";
684f2841d37SMarkus Klotzbuecher       break;
685f2841d37SMarkus Klotzbuecher     case xyzModem_timeout:
686f2841d37SMarkus Klotzbuecher       return "Timed out";
687f2841d37SMarkus Klotzbuecher       break;
688f2841d37SMarkus Klotzbuecher     case xyzModem_eof:
689f2841d37SMarkus Klotzbuecher       return "End of file";
690f2841d37SMarkus Klotzbuecher       break;
691f2841d37SMarkus Klotzbuecher     case xyzModem_cancel:
692f2841d37SMarkus Klotzbuecher       return "Cancelled";
693f2841d37SMarkus Klotzbuecher       break;
694f2841d37SMarkus Klotzbuecher     case xyzModem_frame:
695f2841d37SMarkus Klotzbuecher       return "Invalid framing";
696f2841d37SMarkus Klotzbuecher       break;
697f2841d37SMarkus Klotzbuecher     case xyzModem_cksum:
698f2841d37SMarkus Klotzbuecher       return "CRC/checksum error";
699f2841d37SMarkus Klotzbuecher       break;
700f2841d37SMarkus Klotzbuecher     case xyzModem_sequence:
701f2841d37SMarkus Klotzbuecher       return "Block sequence error";
702f2841d37SMarkus Klotzbuecher       break;
703f2841d37SMarkus Klotzbuecher     default:
704f2841d37SMarkus Klotzbuecher       return "Unknown error";
705f2841d37SMarkus Klotzbuecher       break;
706f2841d37SMarkus Klotzbuecher     }
707f2841d37SMarkus Klotzbuecher }
708f2841d37SMarkus Klotzbuecher 
709cf48eb9aSWolfgang Denk /*
710cf48eb9aSWolfgang Denk  * RedBoot interface
711cf48eb9aSWolfgang Denk  */
712