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