Merge branch 'master' of git://git.denx.de/u-boot
[oweals/u-boot.git] / common / s_record.c
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
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
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
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 }