uboot/common/s_record.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2000
   4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   5 */
   6
   7#include <common.h>
   8#include <s_record.h>
   9
  10static int hex1_bin (char  c);
  11static int hex2_bin (char *s);
  12
  13int 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
 155static 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
 166static 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