xref: /openbmc/u-boot/common/s_record.c (revision ad5b5801)
1 /*
2  * (C) Copyright 2000
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * SPDX-License-Identifier:	GPL-2.0+
6  */
7 
8 #include <common.h>
9 #include <s_record.h>
10 
11 static int hex1_bin (char  c);
12 static int hex2_bin (char *s);
13 
14 int srec_decode (char *input, int *count, ulong *addr, char *data)
15 {
16 	int	i;
17 	int	v;				/* conversion buffer	*/
18 	int	srec_type;			/* S-Record type	*/
19 	unsigned char chksum;			/* buffer for checksum	*/
20 
21 	chksum = 0;
22 
23 	/* skip anything before 'S', and the 'S' itself.
24 	 * Return error if not found
25 	 */
26 
27 	for (; *input; ++input) {
28 		if (*input == 'S') {		/* skip 'S' */
29 			++input;
30 			break;
31 		}
32 	}
33 	if (*input == '\0') {			/* no more data?	*/
34 		return (SREC_EMPTY);
35 	}
36 
37 	v = *input++;				/* record type		*/
38 
39 	if ((*count = hex2_bin(input)) < 0) {
40 		return (SREC_E_NOSREC);
41 	}
42 
43 	chksum += *count;
44 	input  += 2;
45 
46 	switch (v) {				/* record type		*/
47 
48 	case '0':				/* start record		*/
49 		srec_type = SREC_START;		/* 2 byte addr field	*/
50 		*count   -= 3;			/* - checksum and addr	*/
51 		break;
52 	case '1':
53 		srec_type = SREC_DATA2;		/* 2 byte addr field	*/
54 		*count   -= 3;			/* - checksum and addr	*/
55 		break;
56 	case '2':
57 		srec_type = SREC_DATA3;		/* 3 byte addr field	*/
58 		*count   -= 4;			/* - checksum and addr	*/
59 		break;
60 	case '3':				/* data record with a	*/
61 		srec_type = SREC_DATA4;		/* 4 byte addr field	*/
62 		*count   -= 5;			/* - checksum and addr	*/
63 		break;
64 /***	case '4'  ***/
65 	case '5':			/* count record, addr field contains */
66 		srec_type = SREC_COUNT;	/* a 2 byte record counter	*/
67 		*count    = 0;			/* no data		*/
68 		break;
69 /***	case '6' -- not used  ***/
70 	case '7':				/* end record with a	*/
71 		srec_type = SREC_END4;		/* 4 byte addr field	*/
72 		*count   -= 5;			/* - checksum and addr	*/
73 		break;
74 	case '8':				/* end record with a	*/
75 		srec_type = SREC_END3;		/* 3 byte addr field	*/
76 		*count   -= 4;			/* - checksum and addr	*/
77 		break;
78 	case '9':				/* end record with a	*/
79 		srec_type = SREC_END2;		/* 2 byte addr field	*/
80 		*count   -= 3;			/* - checksum and addr	*/
81 		break;
82 	default:
83 		return (SREC_E_BADTYPE);
84 	}
85 
86 	/* read address field */
87 	*addr = 0;
88 
89 	switch (v) {
90 	case '3':				/* 4 byte addr field	*/
91 	case '7':
92 		if ((v = hex2_bin(input)) < 0) {
93 			return (SREC_E_NOSREC);
94 		}
95 		*addr  += v;
96 		chksum += v;
97 		input  += 2;
98 		/* FALL THRU */
99 	case '2':				/* 3 byte addr field	*/
100 	case '8':
101 		if ((v = hex2_bin(input)) < 0) {
102 			return (SREC_E_NOSREC);
103 		}
104 		*addr <<= 8;
105 		*addr  += v;
106 		chksum += v;
107 		input  += 2;
108 		/* FALL THRU */
109 	case '0':				/* 2 byte addr field	*/
110 	case '1':
111 	case '5':
112 	case '9':
113 		if ((v = hex2_bin(input)) < 0) {
114 			return (SREC_E_NOSREC);
115 		}
116 		*addr <<= 8;
117 		*addr  += v;
118 		chksum += v;
119 		input  += 2;
120 
121 		if ((v = hex2_bin(input)) < 0) {
122 			return (SREC_E_NOSREC);
123 		}
124 		*addr <<= 8;
125 		*addr  += v;
126 		chksum += v;
127 		input  += 2;
128 
129 		break;
130 	default:
131 		return (SREC_E_BADTYPE);
132 	}
133 
134 	/* convert data and calculate checksum */
135 	for (i=0; i < *count; ++i) {
136 		if ((v = hex2_bin(input)) < 0) {
137 			return (SREC_E_NOSREC);
138 		}
139 		data[i] = v;
140 		chksum += v;
141 		input  += 2;
142 	}
143 
144 	/* read anc check checksum */
145 	if ((v = hex2_bin(input)) < 0) {
146 		return (SREC_E_NOSREC);
147 	}
148 
149 	if ((unsigned char)v != (unsigned char)~chksum) {
150 		return (SREC_E_BADCHKS);
151 	}
152 
153 	return (srec_type);
154 }
155 
156 static int hex1_bin (char c)
157 {
158 	if (c >= '0' && c <= '9')
159 		return (c - '0');
160 	if (c >= 'a' && c <= 'f')
161 		return (c + 10 - 'a');
162 	if (c >= 'A' && c <= 'F')
163 		return (c + 10 - 'A');
164 	return (-1);
165 }
166 
167 static int hex2_bin (char *s)
168 {
169 	int i, j;
170 
171 	if ((i = hex1_bin(*s++)) < 0) {
172 		return (-1);
173 	}
174 	if ((j = hex1_bin(*s)) < 0) {
175 		return (-1);
176 	}
177 
178 	return ((i<<4) + j);
179 }
180