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