uboot/common/s_record.c
<<
>>
Prefs
   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
  11static int hex1_bin (char  c);
  12static int hex2_bin (char *s);
  13
  14int 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
 156static 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
 167static 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