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