uboot/common/s_record.c
<<
>>
Prefs
   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
  27static int hex1_bin (char  c);
  28static int hex2_bin (char *s);
  29
  30int 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
 172static 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
 183static 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