Home | History | Annotate | Download | only in common
      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