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