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