xref: /openbmc/u-boot/common/s_record.c (revision affae2bf)
1 /*
2  * (C) Copyright 2000
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23 
24 #include <common.h>
25 #include <s_record.h>
26 
27 static int hex1_bin (char  c);
28 static int hex2_bin (char *s);
29 
30 int srec_decode (char *input, int *count, ulong *addr, char *data)
31 {
32 	int	i;
33 	int	v;				/* conversion buffer	*/
34 	int	srec_type;			/* S-Record type	*/
35 	unsigned char chksum;			/* buffer for checksum	*/
36 
37 	chksum = 0;
38 
39 	/* skip anything before 'S', and the 'S' itself.
40 	 * Return error if not found
41 	 */
42 
43 	for (; *input; ++input) {
44 		if (*input == 'S') {		/* skip 'S' */
45 			++input;
46 			break;
47 		}
48 	}
49 	if (*input == '\0') {			/* no more data?	*/
50 		return (SREC_EMPTY);
51 	}
52 
53 	v = *input++;				/* record type		*/
54 
55 	if ((*count = hex2_bin(input)) < 0) {
56 		return (SREC_E_NOSREC);
57 	}
58 
59 	chksum += *count;
60 	input  += 2;
61 
62 	switch (v) {				/* record type		*/
63 
64 	case '0':				/* start record		*/
65 		srec_type = SREC_START;		/* 2 byte addr field	*/
66 		*count   -= 3;			/* - checksum and addr	*/
67 		break;
68 	case '1':
69 		srec_type = SREC_DATA2;		/* 2 byte addr field	*/
70 		*count   -= 3;			/* - checksum and addr	*/
71 		break;
72 	case '2':
73 		srec_type = SREC_DATA3;		/* 3 byte addr field	*/
74 		*count   -= 4;			/* - checksum and addr	*/
75 		break;
76 	case '3':				/* data record with a	*/
77 		srec_type = SREC_DATA4;		/* 4 byte addr field	*/
78 		*count   -= 5;			/* - checksum and addr	*/
79 		break;
80 /***	case '4'  ***/
81 	case '5':			/* count record, addr field contains */
82 		srec_type = SREC_COUNT;	/* a 2 byte record counter	*/
83 		*count    = 0;			/* no data		*/
84 		break;
85 /***	case '6' -- not used  ***/
86 	case '7':				/* end record with a	*/
87 		srec_type = SREC_END4;		/* 4 byte addr field	*/
88 		*count   -= 5;			/* - checksum and addr	*/
89 		break;
90 	case '8':				/* end record with a	*/
91 		srec_type = SREC_END3;		/* 3 byte addr field	*/
92 		*count   -= 4;			/* - checksum and addr	*/
93 		break;
94 	case '9':				/* end record with a	*/
95 		srec_type = SREC_END2;		/* 2 byte addr field	*/
96 		*count   -= 3;			/* - checksum and addr	*/
97 		break;
98 	default:
99 		return (SREC_E_BADTYPE);
100 	}
101 
102 	/* read address field */
103 	*addr = 0;
104 
105 	switch (v) {
106 	case '3':				/* 4 byte addr field	*/
107 	case '7':
108 		if ((v = hex2_bin(input)) < 0) {
109 			return (SREC_E_NOSREC);
110 		}
111 		*addr  += v;
112 		chksum += v;
113 		input  += 2;
114 		/* FALL THRU */
115 	case '2':				/* 3 byte addr field	*/
116 	case '8':
117 		if ((v = hex2_bin(input)) < 0) {
118 			return (SREC_E_NOSREC);
119 		}
120 		*addr <<= 8;
121 		*addr  += v;
122 		chksum += v;
123 		input  += 2;
124 		/* FALL THRU */
125 	case '0':				/* 2 byte addr field	*/
126 	case '1':
127 	case '5':
128 	case '9':
129 		if ((v = hex2_bin(input)) < 0) {
130 			return (SREC_E_NOSREC);
131 		}
132 		*addr <<= 8;
133 		*addr  += v;
134 		chksum += v;
135 		input  += 2;
136 
137 		if ((v = hex2_bin(input)) < 0) {
138 			return (SREC_E_NOSREC);
139 		}
140 		*addr <<= 8;
141 		*addr  += v;
142 		chksum += v;
143 		input  += 2;
144 
145 		break;
146 	default:
147 		return (SREC_E_BADTYPE);
148 	}
149 
150 	/* convert data and calculate checksum */
151 	for (i=0; i < *count; ++i) {
152 		if ((v = hex2_bin(input)) < 0) {
153 			return (SREC_E_NOSREC);
154 		}
155 		data[i] = v;
156 		chksum += v;
157 		input  += 2;
158 	}
159 
160 	/* read anc check checksum */
161 	if ((v = hex2_bin(input)) < 0) {
162 		return (SREC_E_NOSREC);
163 	}
164 
165 	if ((unsigned char)v != (unsigned char)~chksum) {
166 		return (SREC_E_BADCHKS);
167 	}
168 
169 	return (srec_type);
170 }
171 
172 static int hex1_bin (char c)
173 {
174 	if (c >= '0' && c <= '9')
175 		return (c - '0');
176 	if (c >= 'a' && c <= 'f')
177 		return (c + 10 - 'a');
178 	if (c >= 'A' && c <= 'F')
179 		return (c + 10 - 'A');
180 	return (-1);
181 }
182 
183 static int hex2_bin (char *s)
184 {
185 	int i, j;
186 
187 	if ((i = hex1_bin(*s++)) < 0) {
188 		return (-1);
189 	}
190 	if ((j = hex1_bin(*s)) < 0) {
191 		return (-1);
192 	}
193 
194 	return ((i<<4) + j);
195 }
196