1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2000 4 * Wolfgang Denk, DENX Software Engineering, wd (at) 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 } 179