Blame view

common/xyzModem.c 17.7 KB
cf48eb9ab   Wolfgang Denk   Some code cleanup
1
2
3
4
5
6
7
8
  /*
   *==========================================================================
   *
   *      xyzModem.c
   *
   *      RedBoot stream handler for xyzModem protocol
   *
   *==========================================================================
e85427fd6   Wolfgang Denk   Add eCos-2.0 SPDX...
9
   * SPDX-License-Identifier:	eCos-2.0
cf48eb9ab   Wolfgang Denk   Some code cleanup
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
   *==========================================================================
   *#####DESCRIPTIONBEGIN####
   *
   * Author(s):    gthomas
   * Contributors: gthomas, tsmith, Yoshinori Sato
   * Date:         2000-07-14
   * Purpose:
   * Description:
   *
   * This code is part of RedBoot (tm).
   *
   *####DESCRIPTIONEND####
   *
   *==========================================================================
   */
f2841d377   Markus Klotzbuecher   Add support for y...
25
26
27
28
  #include <common.h>
  #include <xyzModem.h>
  #include <stdarg.h>
  #include <crc.h>
cf48eb9ab   Wolfgang Denk   Some code cleanup
29
  /* Assumption - run xyzModem protocol over the console port */
f2841d377   Markus Klotzbuecher   Add support for y...
30

cf48eb9ab   Wolfgang Denk   Some code cleanup
31
  /* Values magic to the protocol */
f2841d377   Markus Klotzbuecher   Add support for y...
32
33
34
35
36
37
38
  #define SOH 0x01
  #define STX 0x02
  #define EOT 0x04
  #define ACK 0x06
  #define BSP 0x08
  #define NAK 0x15
  #define CAN 0x18
7d0432c9e   Wolfgang Denk   Coding Style clea...
39
  #define EOF 0x1A		/* ^Z for DOS officionados */
f2841d377   Markus Klotzbuecher   Add support for y...
40
41
  
  #define USE_YMODEM_LENGTH
cf48eb9ab   Wolfgang Denk   Some code cleanup
42
  /* Data & state local to the protocol */
7d0432c9e   Wolfgang Denk   Coding Style clea...
43
44
  static struct
  {
f2841d377   Markus Klotzbuecher   Add support for y...
45
  #ifdef REDBOOT
7d0432c9e   Wolfgang Denk   Coding Style clea...
46
    hal_virtual_comm_table_t *__chan;
f2841d377   Markus Klotzbuecher   Add support for y...
47
  #else
7d0432c9e   Wolfgang Denk   Coding Style clea...
48
    int *__chan;
f2841d377   Markus Klotzbuecher   Add support for y...
49
  #endif
7d0432c9e   Wolfgang Denk   Coding Style clea...
50
51
52
53
54
55
    unsigned char pkt[1024], *bufp;
    unsigned char blk, cblk, crc1, crc2;
    unsigned char next_blk;	/* Expected block */
    int len, mode, total_retries;
    int total_SOH, total_STX, total_CAN;
    bool crc_mode, at_eof, tx_ack;
f2841d377   Markus Klotzbuecher   Add support for y...
56
  #ifdef USE_YMODEM_LENGTH
7d0432c9e   Wolfgang Denk   Coding Style clea...
57
    unsigned long file_length, read_length;
f2841d377   Markus Klotzbuecher   Add support for y...
58
59
  #endif
  } xyz;
7d0432c9e   Wolfgang Denk   Coding Style clea...
60
  #define xyzModem_CHAR_TIMEOUT            2000	/* 2 seconds */
f2841d377   Markus Klotzbuecher   Add support for y...
61
62
  #define xyzModem_MAX_RETRIES             20
  #define xyzModem_MAX_RETRIES_WITH_CRC    10
7d0432c9e   Wolfgang Denk   Coding Style clea...
63
  #define xyzModem_CAN_COUNT                3	/* Wait for 3 CAN before quitting */
f2841d377   Markus Klotzbuecher   Add support for y...
64

7d0432c9e   Wolfgang Denk   Coding Style clea...
65
  #ifndef REDBOOT			/*SB */
f2841d377   Markus Klotzbuecher   Add support for y...
66
  typedef int cyg_int32;
199adb601   Kim Phillips   common/misc: spar...
67
  static int
7d0432c9e   Wolfgang Denk   Coding Style clea...
68
69
  CYGACC_COMM_IF_GETC_TIMEOUT (char chan, char *c)
  {
f2841d377   Markus Klotzbuecher   Add support for y...
70
  #define DELAY 20
7d0432c9e   Wolfgang Denk   Coding Style clea...
71
72
73
74
75
76
77
78
79
80
81
82
    unsigned long counter = 0;
    while (!tstc () && (counter < xyzModem_CHAR_TIMEOUT * 1000 / DELAY))
      {
        udelay (DELAY);
        counter++;
      }
    if (tstc ())
      {
        *c = getc ();
        return 1;
      }
    return 0;
f2841d377   Markus Klotzbuecher   Add support for y...
83
  }
199adb601   Kim Phillips   common/misc: spar...
84
  static void
7d0432c9e   Wolfgang Denk   Coding Style clea...
85
86
87
  CYGACC_COMM_IF_PUTC (char x, char y)
  {
    putc (y);
f2841d377   Markus Klotzbuecher   Add support for y...
88
  }
cf48eb9ab   Wolfgang Denk   Some code cleanup
89
  /* Validate a hex character */
f2841d377   Markus Klotzbuecher   Add support for y...
90
  __inline__ static bool
7d0432c9e   Wolfgang Denk   Coding Style clea...
91
  _is_hex (char c)
f2841d377   Markus Klotzbuecher   Add support for y...
92
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
93
94
    return (((c >= '0') && (c <= '9')) ||
  	  ((c >= 'A') && (c <= 'F')) || ((c >= 'a') && (c <= 'f')));
f2841d377   Markus Klotzbuecher   Add support for y...
95
  }
cf48eb9ab   Wolfgang Denk   Some code cleanup
96
  /* Convert a single hex nibble */
f2841d377   Markus Klotzbuecher   Add support for y...
97
  __inline__ static int
7d0432c9e   Wolfgang Denk   Coding Style clea...
98
  _from_hex (char c)
f2841d377   Markus Klotzbuecher   Add support for y...
99
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
100
101
102
103
104
105
106
107
108
    int ret = 0;
  
    if ((c >= '0') && (c <= '9'))
      {
        ret = (c - '0');
      }
    else if ((c >= 'a') && (c <= 'f'))
      {
        ret = (c - 'a' + 0x0a);
f2841d377   Markus Klotzbuecher   Add support for y...
109
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
110
111
112
113
114
    else if ((c >= 'A') && (c <= 'F'))
      {
        ret = (c - 'A' + 0x0A);
      }
    return ret;
f2841d377   Markus Klotzbuecher   Add support for y...
115
  }
cf48eb9ab   Wolfgang Denk   Some code cleanup
116
  /* Convert a character to lower case */
f2841d377   Markus Klotzbuecher   Add support for y...
117
  __inline__ static char
7d0432c9e   Wolfgang Denk   Coding Style clea...
118
  _tolower (char c)
f2841d377   Markus Klotzbuecher   Add support for y...
119
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
120
121
122
    if ((c >= 'A') && (c <= 'Z'))
      {
        c = (c - 'A') + 'a';
f2841d377   Markus Klotzbuecher   Add support for y...
123
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
124
    return c;
f2841d377   Markus Klotzbuecher   Add support for y...
125
  }
cf48eb9ab   Wolfgang Denk   Some code cleanup
126
  /* Parse (scan) a number */
199adb601   Kim Phillips   common/misc: spar...
127
  static bool
7d0432c9e   Wolfgang Denk   Coding Style clea...
128
  parse_num (char *s, unsigned long *val, char **es, char *delim)
f2841d377   Markus Klotzbuecher   Add support for y...
129
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
    bool first = true;
    int radix = 10;
    char c;
    unsigned long result = 0;
    int digit;
  
    while (*s == ' ')
      s++;
    while (*s)
      {
        if (first && (s[0] == '0') && (_tolower (s[1]) == 'x'))
  	{
  	  radix = 16;
  	  s += 2;
  	}
        first = false;
        c = *s++;
        if (_is_hex (c) && ((digit = _from_hex (c)) < radix))
  	{
  	  /* Valid digit */
f2841d377   Markus Klotzbuecher   Add support for y...
150
  #ifdef CYGPKG_HAL_MIPS
7d0432c9e   Wolfgang Denk   Coding Style clea...
151
152
153
154
155
156
157
  	  /* FIXME: tx49 compiler generates 0x2539018 for MUL which */
  	  /* isn't any good. */
  	  if (16 == radix)
  	    result = result << 4;
  	  else
  	    result = 10 * result;
  	  result += digit;
f2841d377   Markus Klotzbuecher   Add support for y...
158
  #else
7d0432c9e   Wolfgang Denk   Coding Style clea...
159
  	  result = (result * radix) + digit;
f2841d377   Markus Klotzbuecher   Add support for y...
160
  #endif
7d0432c9e   Wolfgang Denk   Coding Style clea...
161
162
163
164
165
166
167
168
169
170
171
172
173
174
  	}
        else
  	{
  	  if (delim != (char *) 0)
  	    {
  	      /* See if this character is one of the delimiters */
  	      char *dp = delim;
  	      while (*dp && (c != *dp))
  		dp++;
  	      if (*dp)
  		break;		/* Found a good delimiter */
  	    }
  	  return false;		/* Malformatted number */
  	}
f2841d377   Markus Klotzbuecher   Add support for y...
175
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
176
177
178
179
    *val = result;
    if (es != (char **) 0)
      {
        *es = s;
f2841d377   Markus Klotzbuecher   Add support for y...
180
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
181
    return true;
f2841d377   Markus Klotzbuecher   Add support for y...
182
183
184
185
186
187
188
  }
  
  #endif
  
  #define USE_SPRINTF
  #ifdef DEBUG
  #ifndef USE_SPRINTF
cf48eb9ab   Wolfgang Denk   Some code cleanup
189
190
191
192
193
  /*
   * Note: this debug setup only works if the target platform has two serial ports
   * available so that the other one (currently only port 1) can be used for debug
   * messages.
   */
f2841d377   Markus Klotzbuecher   Add support for y...
194
  static int
7d0432c9e   Wolfgang Denk   Coding Style clea...
195
  zm_dprintf (char *fmt, ...)
f2841d377   Markus Klotzbuecher   Add support for y...
196
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
197
198
    int cur_console;
    va_list args;
f2841d377   Markus Klotzbuecher   Add support for y...
199

7d0432c9e   Wolfgang Denk   Coding Style clea...
200
    va_start (args, fmt);
f2841d377   Markus Klotzbuecher   Add support for y...
201
  #ifdef REDBOOT
7d0432c9e   Wolfgang Denk   Coding Style clea...
202
203
204
205
    cur_console =
      CYGACC_CALL_IF_SET_CONSOLE_COMM
      (CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
    CYGACC_CALL_IF_SET_CONSOLE_COMM (1);
f2841d377   Markus Klotzbuecher   Add support for y...
206
  #endif
7d0432c9e   Wolfgang Denk   Coding Style clea...
207
    diag_vprintf (fmt, args);
f2841d377   Markus Klotzbuecher   Add support for y...
208
  #ifdef REDBOOT
7d0432c9e   Wolfgang Denk   Coding Style clea...
209
    CYGACC_CALL_IF_SET_CONSOLE_COMM (cur_console);
f2841d377   Markus Klotzbuecher   Add support for y...
210
211
212
213
  #endif
  }
  
  static void
7d0432c9e   Wolfgang Denk   Coding Style clea...
214
  zm_flush (void)
f2841d377   Markus Klotzbuecher   Add support for y...
215
216
217
218
  {
  }
  
  #else
cf48eb9ab   Wolfgang Denk   Some code cleanup
219
220
221
  /*
   * Note: this debug setup works by storing the strings in a fixed buffer
   */
f2841d377   Markus Klotzbuecher   Add support for y...
222
223
  #define FINAL
  #ifdef FINAL
7d0432c9e   Wolfgang Denk   Coding Style clea...
224
225
  static char *zm_out = (char *) 0x00380000;
  static char *zm_out_start = (char *) 0x00380000;
f2841d377   Markus Klotzbuecher   Add support for y...
226
227
  #else
  static char zm_buf[8192];
7d0432c9e   Wolfgang Denk   Coding Style clea...
228
  static char *zm_out = zm_buf;
f2841d377   Markus Klotzbuecher   Add support for y...
229
230
231
232
  static char *zm_out_start = zm_buf;
  
  #endif
  static int
7d0432c9e   Wolfgang Denk   Coding Style clea...
233
  zm_dprintf (char *fmt, ...)
f2841d377   Markus Klotzbuecher   Add support for y...
234
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
235
236
    int len;
    va_list args;
f2841d377   Markus Klotzbuecher   Add support for y...
237

7d0432c9e   Wolfgang Denk   Coding Style clea...
238
239
240
241
    va_start (args, fmt);
    len = diag_vsprintf (zm_out, fmt, args);
    zm_out += len;
    return len;
f2841d377   Markus Klotzbuecher   Add support for y...
242
243
244
  }
  
  static void
7d0432c9e   Wolfgang Denk   Coding Style clea...
245
  zm_flush (void)
f2841d377   Markus Klotzbuecher   Add support for y...
246
  {
f2841d377   Markus Klotzbuecher   Add support for y...
247
  #ifdef REDBOOT
7d0432c9e   Wolfgang Denk   Coding Style clea...
248
249
250
    char *p = zm_out_start;
    while (*p)
      mon_write_char (*p++);
f2841d377   Markus Klotzbuecher   Add support for y...
251
  #endif
7d0432c9e   Wolfgang Denk   Coding Style clea...
252
    zm_out = zm_out_start;
f2841d377   Markus Klotzbuecher   Add support for y...
253
254
255
256
  }
  #endif
  
  static void
7d0432c9e   Wolfgang Denk   Coding Style clea...
257
  zm_dump_buf (void *buf, int len)
f2841d377   Markus Klotzbuecher   Add support for y...
258
259
  {
  #ifdef REDBOOT
7d0432c9e   Wolfgang Denk   Coding Style clea...
260
    diag_vdump_buf_with_offset (zm_dprintf, buf, len, 0);
f2841d377   Markus Klotzbuecher   Add support for y...
261
262
263
264
265
266
267
268
269
  #else
  
  #endif
  }
  
  static unsigned char zm_buf[2048];
  static unsigned char *zm_bp;
  
  static void
7d0432c9e   Wolfgang Denk   Coding Style clea...
270
  zm_new (void)
f2841d377   Markus Klotzbuecher   Add support for y...
271
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
272
    zm_bp = zm_buf;
f2841d377   Markus Klotzbuecher   Add support for y...
273
274
275
  }
  
  static void
7d0432c9e   Wolfgang Denk   Coding Style clea...
276
  zm_save (unsigned char c)
f2841d377   Markus Klotzbuecher   Add support for y...
277
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
278
    *zm_bp++ = c;
f2841d377   Markus Klotzbuecher   Add support for y...
279
280
281
  }
  
  static void
7d0432c9e   Wolfgang Denk   Coding Style clea...
282
  zm_dump (int line)
f2841d377   Markus Klotzbuecher   Add support for y...
283
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
284
285
286
    zm_dprintf ("Packet at line: %d
  ", line);
    zm_dump_buf (zm_buf, zm_bp - zm_buf);
f2841d377   Markus Klotzbuecher   Add support for y...
287
288
289
290
291
292
  }
  
  #define ZM_DEBUG(x) x
  #else
  #define ZM_DEBUG(x)
  #endif
cf48eb9ab   Wolfgang Denk   Some code cleanup
293
  /* Wait for the line to go idle */
f2841d377   Markus Klotzbuecher   Add support for y...
294
  static void
7d0432c9e   Wolfgang Denk   Coding Style clea...
295
  xyzModem_flush (void)
f2841d377   Markus Klotzbuecher   Add support for y...
296
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
297
298
299
300
301
302
303
    int res;
    char c;
    while (true)
      {
        res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c);
        if (!res)
  	return;
f2841d377   Markus Klotzbuecher   Add support for y...
304
305
306
307
      }
  }
  
  static int
7d0432c9e   Wolfgang Denk   Coding Style clea...
308
  xyzModem_get_hdr (void)
f2841d377   Markus Klotzbuecher   Add support for y...
309
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
    char c;
    int res;
    bool hdr_found = false;
    int i, can_total, hdr_chars;
    unsigned short cksum;
  
    ZM_DEBUG (zm_new ());
    /* Find the start of a header */
    can_total = 0;
    hdr_chars = 0;
  
    if (xyz.tx_ack)
      {
        CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
        xyz.tx_ack = false;
f2841d377   Markus Klotzbuecher   Add support for y...
325
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
    while (!hdr_found)
      {
        res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c);
        ZM_DEBUG (zm_save (c));
        if (res)
  	{
  	  hdr_chars++;
  	  switch (c)
  	    {
  	    case SOH:
  	      xyz.total_SOH++;
  	    case STX:
  	      if (c == STX)
  		xyz.total_STX++;
  	      hdr_found = true;
  	      break;
  	    case CAN:
  	      xyz.total_CAN++;
  	      ZM_DEBUG (zm_dump (__LINE__));
  	      if (++can_total == xyzModem_CAN_COUNT)
  		{
  		  return xyzModem_cancel;
  		}
  	      else
  		{
  		  /* Wait for multiple CAN to avoid early quits */
  		  break;
  		}
  	    case EOT:
  	      /* EOT only supported if no noise */
  	      if (hdr_chars == 1)
  		{
  		  CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
  		  ZM_DEBUG (zm_dprintf ("ACK on EOT #%d
  ", __LINE__));
  		  ZM_DEBUG (zm_dump (__LINE__));
  		  return xyzModem_eof;
  		}
  	    default:
  	      /* Ignore, waiting for start of header */
  	      ;
  	    }
  	}
        else
  	{
  	  /* Data stream timed out */
  	  xyzModem_flush ();	/* Toss any current input */
  	  ZM_DEBUG (zm_dump (__LINE__));
  	  CYGACC_CALL_IF_DELAY_US ((cyg_int32) 250000);
  	  return xyzModem_timeout;
  	}
f2841d377   Markus Klotzbuecher   Add support for y...
377
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
378
379
380
381
382
383
384
    /* Header found, now read the data */
    res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.blk);
    ZM_DEBUG (zm_save (xyz.blk));
    if (!res)
      {
        ZM_DEBUG (zm_dump (__LINE__));
        return xyzModem_timeout;
f2841d377   Markus Klotzbuecher   Add support for y...
385
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
386
387
388
389
390
391
    res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.cblk);
    ZM_DEBUG (zm_save (xyz.cblk));
    if (!res)
      {
        ZM_DEBUG (zm_dump (__LINE__));
        return xyzModem_timeout;
f2841d377   Markus Klotzbuecher   Add support for y...
392
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
    xyz.len = (c == SOH) ? 128 : 1024;
    xyz.bufp = xyz.pkt;
    for (i = 0; i < xyz.len; i++)
      {
        res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, &c);
        ZM_DEBUG (zm_save (c));
        if (res)
  	{
  	  xyz.pkt[i] = c;
  	}
        else
  	{
  	  ZM_DEBUG (zm_dump (__LINE__));
  	  return xyzModem_timeout;
  	}
f2841d377   Markus Klotzbuecher   Add support for y...
408
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
409
410
411
412
413
414
    res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.crc1);
    ZM_DEBUG (zm_save (xyz.crc1));
    if (!res)
      {
        ZM_DEBUG (zm_dump (__LINE__));
        return xyzModem_timeout;
f2841d377   Markus Klotzbuecher   Add support for y...
415
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
416
417
418
419
420
421
422
423
424
    if (xyz.crc_mode)
      {
        res = CYGACC_COMM_IF_GETC_TIMEOUT (*xyz.__chan, (char *) &xyz.crc2);
        ZM_DEBUG (zm_save (xyz.crc2));
        if (!res)
  	{
  	  ZM_DEBUG (zm_dump (__LINE__));
  	  return xyzModem_timeout;
  	}
f2841d377   Markus Klotzbuecher   Add support for y...
425
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
426
427
428
429
430
431
432
433
434
435
436
    ZM_DEBUG (zm_dump (__LINE__));
    /* Validate the message */
    if ((xyz.blk ^ xyz.cblk) != (unsigned char) 0xFF)
      {
        ZM_DEBUG (zm_dprintf
  		("Framing error - blk: %x/%x/%x
  ", xyz.blk, xyz.cblk,
  		 (xyz.blk ^ xyz.cblk)));
        ZM_DEBUG (zm_dump_buf (xyz.pkt, xyz.len));
        xyzModem_flush ();
        return xyzModem_frame;
f2841d377   Markus Klotzbuecher   Add support for y...
437
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
438
439
440
441
442
443
444
445
446
447
448
    /* Verify checksum/CRC */
    if (xyz.crc_mode)
      {
        cksum = cyg_crc16 (xyz.pkt, xyz.len);
        if (cksum != ((xyz.crc1 << 8) | xyz.crc2))
  	{
  	  ZM_DEBUG (zm_dprintf ("CRC error - recvd: %02x%02x, computed: %x
  ",
  				xyz.crc1, xyz.crc2, cksum & 0xFFFF));
  	  return xyzModem_cksum;
  	}
f2841d377   Markus Klotzbuecher   Add support for y...
449
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
    else
      {
        cksum = 0;
        for (i = 0; i < xyz.len; i++)
  	{
  	  cksum += xyz.pkt[i];
  	}
        if (xyz.crc1 != (cksum & 0xFF))
  	{
  	  ZM_DEBUG (zm_dprintf
  		    ("Checksum error - recvd: %x, computed: %x
  ", xyz.crc1,
  		     cksum & 0xFF));
  	  return xyzModem_cksum;
  	}
      }
    /* If we get here, the message passes [structural] muster */
    return 0;
f2841d377   Markus Klotzbuecher   Add support for y...
468
  }
cf48eb9ab   Wolfgang Denk   Some code cleanup
469
  int
7d0432c9e   Wolfgang Denk   Coding Style clea...
470
  xyzModem_stream_open (connection_info_t * info, int *err)
f2841d377   Markus Klotzbuecher   Add support for y...
471
  {
f90a39213   Stefan Roese   Fix compile warni...
472
  #ifdef REDBOOT
7d0432c9e   Wolfgang Denk   Coding Style clea...
473
    int console_chan;
f90a39213   Stefan Roese   Fix compile warni...
474
  #endif
7d0432c9e   Wolfgang Denk   Coding Style clea...
475
476
477
    int stat = 0;
    int retries = xyzModem_MAX_RETRIES;
    int crc_retries = xyzModem_MAX_RETRIES_WITH_CRC;
f2841d377   Markus Klotzbuecher   Add support for y...
478

cf48eb9ab   Wolfgang Denk   Some code cleanup
479
  /*    ZM_DEBUG(zm_out = zm_out_start); */
f2841d377   Markus Klotzbuecher   Add support for y...
480
  #ifdef xyzModem_zmodem
7d0432c9e   Wolfgang Denk   Coding Style clea...
481
482
483
484
    if (info->mode == xyzModem_zmodem)
      {
        *err = xyzModem_noZmodem;
        return -1;
f2841d377   Markus Klotzbuecher   Add support for y...
485
486
487
488
      }
  #endif
  
  #ifdef REDBOOT
7d0432c9e   Wolfgang Denk   Coding Style clea...
489
490
491
492
493
494
495
    /* Set up the I/O channel.  Note: this allows for using a different port in the future */
    console_chan =
      CYGACC_CALL_IF_SET_CONSOLE_COMM
      (CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
    if (info->chan >= 0)
      {
        CYGACC_CALL_IF_SET_CONSOLE_COMM (info->chan);
f2841d377   Markus Klotzbuecher   Add support for y...
496
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
497
498
499
500
501
    else
      {
        CYGACC_CALL_IF_SET_CONSOLE_COMM (console_chan);
      }
    xyz.__chan = CYGACC_CALL_IF_CONSOLE_PROCS ();
f2841d377   Markus Klotzbuecher   Add support for y...
502

7d0432c9e   Wolfgang Denk   Coding Style clea...
503
504
505
    CYGACC_CALL_IF_SET_CONSOLE_COMM (console_chan);
    CYGACC_COMM_IF_CONTROL (*xyz.__chan, __COMMCTL_SET_TIMEOUT,
  			  xyzModem_CHAR_TIMEOUT);
f2841d377   Markus Klotzbuecher   Add support for y...
506
  #else
cf48eb9ab   Wolfgang Denk   Some code cleanup
507
  /* TODO: CHECK ! */
2a2ed845c   Kim Phillips   common: fix 'dumm...
508
    int dummy = 0;
7d0432c9e   Wolfgang Denk   Coding Style clea...
509
    xyz.__chan = &dummy;
f2841d377   Markus Klotzbuecher   Add support for y...
510
  #endif
7d0432c9e   Wolfgang Denk   Coding Style clea...
511
512
513
514
515
516
517
518
519
    xyz.len = 0;
    xyz.crc_mode = true;
    xyz.at_eof = false;
    xyz.tx_ack = false;
    xyz.mode = info->mode;
    xyz.total_retries = 0;
    xyz.total_SOH = 0;
    xyz.total_STX = 0;
    xyz.total_CAN = 0;
f2841d377   Markus Klotzbuecher   Add support for y...
520
  #ifdef USE_YMODEM_LENGTH
7d0432c9e   Wolfgang Denk   Coding Style clea...
521
522
    xyz.read_length = 0;
    xyz.file_length = 0;
f2841d377   Markus Klotzbuecher   Add support for y...
523
  #endif
cf48eb9ab   Wolfgang Denk   Some code cleanup
524

7d0432c9e   Wolfgang Denk   Coding Style clea...
525
    CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
f2841d377   Markus Klotzbuecher   Add support for y...
526

7d0432c9e   Wolfgang Denk   Coding Style clea...
527
528
529
530
531
    if (xyz.mode == xyzModem_xmodem)
      {
        /* X-modem doesn't have an information header - exit here */
        xyz.next_blk = 1;
        return 0;
f2841d377   Markus Klotzbuecher   Add support for y...
532
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
533
534
535
536
537
538
539
540
    while (retries-- > 0)
      {
        stat = xyzModem_get_hdr ();
        if (stat == 0)
  	{
  	  /* Y-modem file information header */
  	  if (xyz.blk == 0)
  	    {
f2841d377   Markus Klotzbuecher   Add support for y...
541
  #ifdef USE_YMODEM_LENGTH
7d0432c9e   Wolfgang Denk   Coding Style clea...
542
543
544
545
  	      /* skip filename */
  	      while (*xyz.bufp++);
  	      /* get the length */
  	      parse_num ((char *) xyz.bufp, &xyz.file_length, NULL, " ");
f2841d377   Markus Klotzbuecher   Add support for y...
546
  #endif
7d0432c9e   Wolfgang Denk   Coding Style clea...
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
  	      /* The rest of the file name data block quietly discarded */
  	      xyz.tx_ack = true;
  	    }
  	  xyz.next_blk = 1;
  	  xyz.len = 0;
  	  return 0;
  	}
        else if (stat == xyzModem_timeout)
  	{
  	  if (--crc_retries <= 0)
  	    xyz.crc_mode = false;
  	  CYGACC_CALL_IF_DELAY_US (5 * 100000);	/* Extra delay for startup */
  	  CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
  	  xyz.total_retries++;
  	  ZM_DEBUG (zm_dprintf ("NAK (%d)
  ", __LINE__));
  	}
        if (stat == xyzModem_cancel)
  	{
  	  break;
  	}
f2841d377   Markus Klotzbuecher   Add support for y...
568
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
569
570
571
    *err = stat;
    ZM_DEBUG (zm_flush ());
    return -1;
f2841d377   Markus Klotzbuecher   Add support for y...
572
  }
cf48eb9ab   Wolfgang Denk   Some code cleanup
573
  int
7d0432c9e   Wolfgang Denk   Coding Style clea...
574
  xyzModem_stream_read (char *buf, int size, int *err)
f2841d377   Markus Klotzbuecher   Add support for y...
575
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
    int stat, total, len;
    int retries;
  
    total = 0;
    stat = xyzModem_cancel;
    /* Try and get 'size' bytes into the buffer */
    while (!xyz.at_eof && (size > 0))
      {
        if (xyz.len == 0)
  	{
  	  retries = xyzModem_MAX_RETRIES;
  	  while (retries-- > 0)
  	    {
  	      stat = xyzModem_get_hdr ();
  	      if (stat == 0)
  		{
  		  if (xyz.blk == xyz.next_blk)
  		    {
  		      xyz.tx_ack = true;
  		      ZM_DEBUG (zm_dprintf
  				("ACK block %d (%d)
  ", xyz.blk, __LINE__));
  		      xyz.next_blk = (xyz.next_blk + 1) & 0xFF;
f2841d377   Markus Klotzbuecher   Add support for y...
599
600
  
  #if defined(xyzModem_zmodem) || defined(USE_YMODEM_LENGTH)
7d0432c9e   Wolfgang Denk   Coding Style clea...
601
602
  		      if (xyz.mode == xyzModem_xmodem || xyz.file_length == 0)
  			{
f2841d377   Markus Klotzbuecher   Add support for y...
603
  #else
7d0432c9e   Wolfgang Denk   Coding Style clea...
604
605
  		      if (1)
  			{
f2841d377   Markus Klotzbuecher   Add support for y...
606
  #endif
7d0432c9e   Wolfgang Denk   Coding Style clea...
607
608
609
610
611
612
613
614
615
616
617
618
619
  			  /* Data blocks can be padded with ^Z (EOF) characters */
  			  /* This code tries to detect and remove them */
  			  if ((xyz.bufp[xyz.len - 1] == EOF) &&
  			      (xyz.bufp[xyz.len - 2] == EOF) &&
  			      (xyz.bufp[xyz.len - 3] == EOF))
  			    {
  			      while (xyz.len
  				     && (xyz.bufp[xyz.len - 1] == EOF))
  				{
  				  xyz.len--;
  				}
  			    }
  			}
f2841d377   Markus Klotzbuecher   Add support for y...
620
621
  
  #ifdef USE_YMODEM_LENGTH
7d0432c9e   Wolfgang Denk   Coding Style clea...
622
623
624
625
626
627
628
629
630
631
632
633
634
635
  		      /*
  		       * See if accumulated length exceeds that of the file.
  		       * If so, reduce size (i.e., cut out pad bytes)
  		       * Only do this for Y-modem (and Z-modem should it ever
  		       * be supported since it can fall back to Y-modem mode).
  		       */
  		      if (xyz.mode != xyzModem_xmodem && 0 != xyz.file_length)
  			{
  			  xyz.read_length += xyz.len;
  			  if (xyz.read_length > xyz.file_length)
  			    {
  			      xyz.len -= (xyz.read_length - xyz.file_length);
  			    }
  			}
f2841d377   Markus Klotzbuecher   Add support for y...
636
  #endif
7d0432c9e   Wolfgang Denk   Coding Style clea...
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
  		      break;
  		    }
  		  else if (xyz.blk == ((xyz.next_blk - 1) & 0xFF))
  		    {
  		      /* Just re-ACK this so sender will get on with it */
  		      CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
  		      continue;	/* Need new header */
  		    }
  		  else
  		    {
  		      stat = xyzModem_sequence;
  		    }
  		}
  	      if (stat == xyzModem_cancel)
  		{
  		  break;
  		}
  	      if (stat == xyzModem_eof)
  		{
  		  CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
  		  ZM_DEBUG (zm_dprintf ("ACK (%d)
  ", __LINE__));
  		  if (xyz.mode == xyzModem_ymodem)
  		    {
  		      CYGACC_COMM_IF_PUTC (*xyz.__chan,
  					   (xyz.crc_mode ? 'C' : NAK));
  		      xyz.total_retries++;
  		      ZM_DEBUG (zm_dprintf ("Reading Final Header
  "));
  		      stat = xyzModem_get_hdr ();
  		      CYGACC_COMM_IF_PUTC (*xyz.__chan, ACK);
  		      ZM_DEBUG (zm_dprintf ("FINAL ACK (%d)
  ", __LINE__));
  		    }
  		  xyz.at_eof = true;
  		  break;
  		}
  	      CYGACC_COMM_IF_PUTC (*xyz.__chan, (xyz.crc_mode ? 'C' : NAK));
  	      xyz.total_retries++;
  	      ZM_DEBUG (zm_dprintf ("NAK (%d)
  ", __LINE__));
  	    }
  	  if (stat < 0)
  	    {
  	      *err = stat;
  	      xyz.len = -1;
  	      return total;
  	    }
  	}
        /* Don't "read" data from the EOF protocol package */
        if (!xyz.at_eof)
  	{
  	  len = xyz.len;
  	  if (size < len)
  	    len = size;
  	  memcpy (buf, xyz.bufp, len);
  	  size -= len;
  	  buf += len;
  	  total += len;
  	  xyz.len -= len;
  	  xyz.bufp += len;
  	}
f2841d377   Markus Klotzbuecher   Add support for y...
699
      }
7d0432c9e   Wolfgang Denk   Coding Style clea...
700
    return total;
f2841d377   Markus Klotzbuecher   Add support for y...
701
702
703
  }
  
  void
7d0432c9e   Wolfgang Denk   Coding Style clea...
704
  xyzModem_stream_close (int *err)
f2841d377   Markus Klotzbuecher   Add support for y...
705
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
706
707
708
709
710
711
    diag_printf
      ("xyzModem - %s mode, %d(SOH)/%d(STX)/%d(CAN) packets, %d retries
  ",
       xyz.crc_mode ? "CRC" : "Cksum", xyz.total_SOH, xyz.total_STX,
       xyz.total_CAN, xyz.total_retries);
    ZM_DEBUG (zm_flush ());
f2841d377   Markus Klotzbuecher   Add support for y...
712
  }
cf48eb9ab   Wolfgang Denk   Some code cleanup
713
714
  /* Need to be able to clean out the input buffer, so have to take the */
  /* getc */
7d0432c9e   Wolfgang Denk   Coding Style clea...
715
716
  void
  xyzModem_stream_terminate (bool abort, int (*getc) (void))
f2841d377   Markus Klotzbuecher   Add support for y...
717
718
  {
    int c;
7d0432c9e   Wolfgang Denk   Coding Style clea...
719
720
721
722
723
724
    if (abort)
      {
        ZM_DEBUG (zm_dprintf ("!!!! TRANSFER ABORT !!!!
  "));
        switch (xyz.mode)
  	{
f2841d377   Markus Klotzbuecher   Add support for y...
725
726
  	case xyzModem_xmodem:
  	case xyzModem_ymodem:
cf48eb9ab   Wolfgang Denk   Some code cleanup
727
728
  	  /* The X/YMODEM Spec seems to suggest that multiple CAN followed by an equal */
  	  /* number of Backspaces is a friendly way to get the other end to abort. */
7d0432c9e   Wolfgang Denk   Coding Style clea...
729
730
731
732
733
734
735
736
  	  CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
  	  CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
  	  CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
  	  CYGACC_COMM_IF_PUTC (*xyz.__chan, CAN);
  	  CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
  	  CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
  	  CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
  	  CYGACC_COMM_IF_PUTC (*xyz.__chan, BSP);
cf48eb9ab   Wolfgang Denk   Some code cleanup
737
  	  /* Now consume the rest of what's waiting on the line. */
7d0432c9e   Wolfgang Denk   Coding Style clea...
738
739
740
741
742
  	  ZM_DEBUG (zm_dprintf ("Flushing serial line.
  "));
  	  xyzModem_flush ();
  	  xyz.at_eof = true;
  	  break;
f2841d377   Markus Klotzbuecher   Add support for y...
743
744
  #ifdef xyzModem_zmodem
  	case xyzModem_zmodem:
cf48eb9ab   Wolfgang Denk   Some code cleanup
745
  	  /* Might support it some day I suppose. */
f2841d377   Markus Klotzbuecher   Add support for y...
746
  #endif
7d0432c9e   Wolfgang Denk   Coding Style clea...
747
748
749
750
751
752
753
  	  break;
  	}
      }
    else
      {
        ZM_DEBUG (zm_dprintf ("Engaging cleanup mode...
  "));
cf48eb9ab   Wolfgang Denk   Some code cleanup
754
755
        /*
         * Consume any trailing crap left in the inbuffer from
162630879   Mike Williams   cleanup: Fix typo...
756
         * previous received blocks. Since very few files are an exact multiple
cf48eb9ab   Wolfgang Denk   Some code cleanup
757
758
759
         * of the transfer block size, there will almost always be some gunk here.
         * If we don't eat it now, RedBoot will think the user typed it.
         */
7d0432c9e   Wolfgang Denk   Coding Style clea...
760
761
762
763
764
        ZM_DEBUG (zm_dprintf ("Trailing gunk:
  "));
        while ((c = (*getc) ()) > -1);
        ZM_DEBUG (zm_dprintf ("
  "));
cf48eb9ab   Wolfgang Denk   Some code cleanup
765
766
767
768
769
        /*
         * Make a small delay to give terminal programs like minicom
         * time to get control again after their file transfer program
         * exits.
         */
7d0432c9e   Wolfgang Denk   Coding Style clea...
770
771
        CYGACC_CALL_IF_DELAY_US ((cyg_int32) 250000);
      }
f2841d377   Markus Klotzbuecher   Add support for y...
772
773
774
  }
  
  char *
7d0432c9e   Wolfgang Denk   Coding Style clea...
775
  xyzModem_error (int err)
f2841d377   Markus Klotzbuecher   Add support for y...
776
  {
7d0432c9e   Wolfgang Denk   Coding Style clea...
777
778
    switch (err)
      {
f2841d377   Markus Klotzbuecher   Add support for y...
779
      case xyzModem_access:
7d0432c9e   Wolfgang Denk   Coding Style clea...
780
781
        return "Can't access file";
        break;
f2841d377   Markus Klotzbuecher   Add support for y...
782
      case xyzModem_noZmodem:
7d0432c9e   Wolfgang Denk   Coding Style clea...
783
784
        return "Sorry, zModem not available yet";
        break;
f2841d377   Markus Klotzbuecher   Add support for y...
785
      case xyzModem_timeout:
7d0432c9e   Wolfgang Denk   Coding Style clea...
786
787
        return "Timed out";
        break;
f2841d377   Markus Klotzbuecher   Add support for y...
788
      case xyzModem_eof:
7d0432c9e   Wolfgang Denk   Coding Style clea...
789
790
        return "End of file";
        break;
f2841d377   Markus Klotzbuecher   Add support for y...
791
      case xyzModem_cancel:
7d0432c9e   Wolfgang Denk   Coding Style clea...
792
793
        return "Cancelled";
        break;
f2841d377   Markus Klotzbuecher   Add support for y...
794
      case xyzModem_frame:
7d0432c9e   Wolfgang Denk   Coding Style clea...
795
796
        return "Invalid framing";
        break;
f2841d377   Markus Klotzbuecher   Add support for y...
797
      case xyzModem_cksum:
7d0432c9e   Wolfgang Denk   Coding Style clea...
798
799
        return "CRC/checksum error";
        break;
f2841d377   Markus Klotzbuecher   Add support for y...
800
      case xyzModem_sequence:
7d0432c9e   Wolfgang Denk   Coding Style clea...
801
802
        return "Block sequence error";
        break;
f2841d377   Markus Klotzbuecher   Add support for y...
803
      default:
7d0432c9e   Wolfgang Denk   Coding Style clea...
804
805
        return "Unknown error";
        break;
f2841d377   Markus Klotzbuecher   Add support for y...
806
807
      }
  }
cf48eb9ab   Wolfgang Denk   Some code cleanup
808
809
810
  /*
   * RedBoot interface
   */
7d0432c9e   Wolfgang Denk   Coding Style clea...
811
812
813
814
815
816
  #if 0				/* SB */
  GETC_IO_FUNCS (xyzModem_io, xyzModem_stream_open, xyzModem_stream_close,
  	       xyzModem_stream_terminate, xyzModem_stream_read,
  	       xyzModem_error);
  RedBoot_load (xmodem, xyzModem_io, false, false, xyzModem_xmodem);
  RedBoot_load (ymodem, xyzModem_io, false, false, xyzModem_ymodem);
cf48eb9ab   Wolfgang Denk   Some code cleanup
817
  #endif