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