1 /* 2 * (C) Copyright 2000 3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4 * 5 * See file CREDITS for list of people who contributed to this 6 * project. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of 11 * the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21 * MA 02111-1307 USA 22 */ 23 24 #include <common.h> 25 #include <s_record.h> 26 27 static int hex1_bin (char c); 28 static int hex2_bin (char *s); 29 30 int srec_decode (char *input, int *count, ulong *addr, char *data) 31 { 32 int i; 33 int v; /* conversion buffer */ 34 int srec_type; /* S-Record type */ 35 unsigned char chksum; /* buffer for checksum */ 36 37 chksum = 0; 38 39 /* skip anything before 'S', and the 'S' itself. 40 * Return error if not found 41 */ 42 43 for (; *input; ++input) { 44 if (*input == 'S') { /* skip 'S' */ 45 ++input; 46 break; 47 } 48 } 49 if (*input == '\0') { /* no more data? */ 50 return (SREC_EMPTY); 51 } 52 53 v = *input++; /* record type */ 54 55 if ((*count = hex2_bin(input)) < 0) { 56 return (SREC_E_NOSREC); 57 } 58 59 chksum += *count; 60 input += 2; 61 62 switch (v) { /* record type */ 63 64 case '0': /* start record */ 65 srec_type = SREC_START; /* 2 byte addr field */ 66 *count -= 3; /* - checksum and addr */ 67 break; 68 case '1': 69 srec_type = SREC_DATA2; /* 2 byte addr field */ 70 *count -= 3; /* - checksum and addr */ 71 break; 72 case '2': 73 srec_type = SREC_DATA3; /* 3 byte addr field */ 74 *count -= 4; /* - checksum and addr */ 75 break; 76 case '3': /* data record with a */ 77 srec_type = SREC_DATA4; /* 4 byte addr field */ 78 *count -= 5; /* - checksum and addr */ 79 break; 80 /*** case '4' ***/ 81 case '5': /* count record, addr field contains */ 82 srec_type = SREC_COUNT; /* a 2 byte record counter */ 83 *count = 0; /* no data */ 84 break; 85 /*** case '6' -- not used ***/ 86 case '7': /* end record with a */ 87 srec_type = SREC_END4; /* 4 byte addr field */ 88 *count -= 5; /* - checksum and addr */ 89 break; 90 case '8': /* end record with a */ 91 srec_type = SREC_END3; /* 3 byte addr field */ 92 *count -= 4; /* - checksum and addr */ 93 break; 94 case '9': /* end record with a */ 95 srec_type = SREC_END2; /* 2 byte addr field */ 96 *count -= 3; /* - checksum and addr */ 97 break; 98 default: 99 return (SREC_E_BADTYPE); 100 } 101 102 /* read address field */ 103 *addr = 0; 104 105 switch (v) { 106 case '3': /* 4 byte addr field */ 107 case '7': 108 if ((v = hex2_bin(input)) < 0) { 109 return (SREC_E_NOSREC); 110 } 111 *addr += v; 112 chksum += v; 113 input += 2; 114 /* FALL THRU */ 115 case '2': /* 3 byte addr field */ 116 case '8': 117 if ((v = hex2_bin(input)) < 0) { 118 return (SREC_E_NOSREC); 119 } 120 *addr <<= 8; 121 *addr += v; 122 chksum += v; 123 input += 2; 124 /* FALL THRU */ 125 case '0': /* 2 byte addr field */ 126 case '1': 127 case '5': 128 case '9': 129 if ((v = hex2_bin(input)) < 0) { 130 return (SREC_E_NOSREC); 131 } 132 *addr <<= 8; 133 *addr += v; 134 chksum += v; 135 input += 2; 136 137 if ((v = hex2_bin(input)) < 0) { 138 return (SREC_E_NOSREC); 139 } 140 *addr <<= 8; 141 *addr += v; 142 chksum += v; 143 input += 2; 144 145 break; 146 default: 147 return (SREC_E_BADTYPE); 148 } 149 150 /* convert data and calculate checksum */ 151 for (i=0; i < *count; ++i) { 152 if ((v = hex2_bin(input)) < 0) { 153 return (SREC_E_NOSREC); 154 } 155 data[i] = v; 156 chksum += v; 157 input += 2; 158 } 159 160 /* read anc check checksum */ 161 if ((v = hex2_bin(input)) < 0) { 162 return (SREC_E_NOSREC); 163 } 164 165 if ((unsigned char)v != (unsigned char)~chksum) { 166 return (SREC_E_BADCHKS); 167 } 168 169 return (srec_type); 170 } 171 172 static int hex1_bin (char c) 173 { 174 if (c >= '0' && c <= '9') 175 return (c - '0'); 176 if (c >= 'a' && c <= 'f') 177 return (c + 10 - 'a'); 178 if (c >= 'A' && c <= 'F') 179 return (c + 10 - 'A'); 180 return (-1); 181 } 182 183 static int hex2_bin (char *s) 184 { 185 int i, j; 186 187 if ((i = hex1_bin(*s++)) < 0) { 188 return (-1); 189 } 190 if ((j = hex1_bin(*s)) < 0) { 191 return (-1); 192 } 193 194 return ((i<<4) + j); 195 } 196