This patch unifies the use of config options in v2 to all start with CONFIG_
[coreboot.git] / src / lib / xmodem.c
1 /*
2         Copyright 2006 Arastra, Inc.
3         Copyright 2001, 2002 Georges Menie (www.menie.org)
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU Lesser General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU Lesser General Public License for more details.
14
15     You should have received a copy of the GNU Lesser General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20 #include <string.h>
21 #include <delay.h>
22
23 extern void uart8250_tx_byte(unsigned, unsigned char);
24 extern int uart8250_can_rx_byte(unsigned);
25 extern unsigned char uart8250_rx_byte(unsigned);
26
27 static int _inbyte(int msec)
28 {
29         while (!uart8250_can_rx_byte(CONFIG_TTYS0_BASE)) {
30                 udelay(1000);
31                 if (msec-- <= 0)
32                         return -1;
33         }
34         return uart8250_rx_byte(CONFIG_TTYS0_BASE);
35 }
36
37 static void _outbyte(unsigned char c)
38 {
39         uart8250_tx_byte(CONFIG_TTYS0_BASE, c);
40 }
41
42 static unsigned short crc16_ccitt(const unsigned char *buf, int sz)
43 {
44         unsigned short crc = 0;
45         while (--sz >= 0) {
46                 int i;
47                 crc ^= (unsigned short) *buf++ << 8;
48                 for (i = 0; i < 8; i++)
49                         if (crc & 0x8000)
50                                 crc = crc << 1 ^ 0x1021;
51                         else
52                                 crc <<= 1;
53         }
54         return crc;
55 }
56
57 #define SOH  0x01
58 #define STX  0x02
59 #define EOT  0x04
60 #define ACK  0x06
61 #define NAK  0x15
62 #define CAN  0x18
63 #define CTRLZ 0x1A
64
65 #define DLY_1S 1000
66 #define MAXRETRANS 25
67
68 static int check(int crc, const unsigned char *buf, int sz)
69 {
70         if (crc) {
71                 unsigned short crc = crc16_ccitt(buf, sz);
72                 unsigned short tcrc = (buf[sz]<<8)+buf[sz+1];
73                 if (crc == tcrc)
74                         return 1;
75         }
76         else {
77                 int i;
78                 unsigned char cks = 0;
79                 for (i = 0; i < sz; ++i) {
80                         cks += buf[i];
81                 }
82                 if (cks == buf[sz])
83                 return 1;
84         }
85
86         return 0;
87 }
88
89 static void flushinput(void)
90 {
91         while (_inbyte(((DLY_1S)*3)>>1) >= 0)
92                 ;
93 }
94
95 int xmodemReceive(unsigned char *dest, int destsz)
96 {
97         unsigned char xbuff[1030]; /* 1024 for XModem 1k + 3 head chars + 2 crc + nul */
98         unsigned char *p;
99         int bufsz, crc = 0;
100         unsigned char trychar = 'C';
101         unsigned char packetno = 1;
102         int i, c, len = 0;
103         int retry, retrans = MAXRETRANS;
104
105         for(;;) {
106                 for( retry = 0; retry < 16; ++retry) {
107                         if (trychar) _outbyte(trychar);
108                         if ((c = _inbyte((DLY_1S)<<1)) >= 0) {
109                                 switch (c) {
110                                 case SOH:
111                                         bufsz = 128;
112                                         goto start_recv;
113                                 case STX:
114                                         bufsz = 1024;
115                                         goto start_recv;
116                                 case EOT:
117                                         flushinput();
118                                         _outbyte(ACK);
119                                         return len; /* normal end */
120                                 case CAN:
121                                         if ((c = _inbyte(DLY_1S)) == CAN) {
122                                                 flushinput();
123                                                 _outbyte(ACK);
124                                                 return -1; /* canceled by remote */
125                                         }
126                                         break;
127                                 default:
128                                         break;
129                                 }
130                         }
131                 }
132                 if (trychar == 'C') { trychar = NAK; continue; }
133                 flushinput();
134                 _outbyte(CAN);
135                 _outbyte(CAN);
136                 _outbyte(CAN);
137                 return -2; /* sync error */
138
139         start_recv:
140                 if (trychar == 'C') crc = 1;
141                 trychar = 0;
142                 p = xbuff;
143                 *p++ = c;
144                 for (i = 0;  i < (bufsz+(crc?1:0)+3); ++i) {
145                         if ((c = _inbyte(DLY_1S)) < 0) goto reject;
146                         *p++ = c;
147                 }
148
149                 if (xbuff[1] == (unsigned char)(~xbuff[2]) && 
150                         (xbuff[1] == packetno || xbuff[1] == (unsigned char)packetno-1) &&
151                         check(crc, &xbuff[3], bufsz)) {
152                         if (xbuff[1] == packetno)       {
153                                 register int count = destsz - len;
154                                 if (count > bufsz) count = bufsz;
155                                 if (count > 0) {
156                                         memcpy (&dest[len], &xbuff[3], count);
157                                         len += count;
158                                 }
159                                 ++packetno;
160                                 retrans = MAXRETRANS+1;
161                         }
162                         if (--retrans <= 0) {
163                                 flushinput();
164                                 _outbyte(CAN);
165                                 _outbyte(CAN);
166                                 _outbyte(CAN);
167                                 return -3; /* too many retry error */
168                         }
169                         _outbyte(ACK);
170                         continue;
171                 }
172         reject:
173                 flushinput();
174                 _outbyte(NAK);
175         }
176 }