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