coreboot-v2/src/lib/xmodem.c
<<
>>
Prefs
   1/*
   2        Copyright 2006 Arastra, Inc.
   3        Copyright 2001, 2002 Georges Menie (www.menie.org)
   4
   5    This program is free software; you can redistribute it and/or modify
   6    it under the terms of the GNU Lesser General Public License as published by
   7    the Free Software Foundation; either version 2 of the License, or
   8    (at your option) any later version.
   9
  10    This program is distributed in the hope that it will be useful,
  11    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13    GNU Lesser General Public License for more details.
  14
  15    You should have received a copy of the GNU Lesser General Public License
  16    along with this program; if not, write to the Free Software
  17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  18*/
  19
  20#include <string.h>
  21#include <delay.h>
  22#include <uart8250.h>
  23
  24static int _inbyte(int msec)
  25{
  26        while (!uart8250_can_rx_byte(CONFIG_TTYS0_BASE)) {
  27                udelay(1000);
  28                if (msec-- <= 0)
  29                        return -1;
  30        }
  31        return uart8250_rx_byte(CONFIG_TTYS0_BASE);
  32}
  33
  34static void _outbyte(unsigned char c)
  35{
  36        uart8250_tx_byte(CONFIG_TTYS0_BASE, c);
  37}
  38
  39static unsigned short crc16_ccitt(const unsigned char *buf, int sz)
  40{
  41        unsigned short crc = 0;
  42        while (--sz >= 0) {
  43                int i;
  44                crc ^= (unsigned short) *buf++ << 8;
  45                for (i = 0; i < 8; i++)
  46                        if (crc & 0x8000)
  47                                crc = crc << 1 ^ 0x1021;
  48                        else
  49                                crc <<= 1;
  50        }
  51        return crc;
  52}
  53
  54#define SOH  0x01
  55#define STX  0x02
  56#define EOT  0x04
  57#define ACK  0x06
  58#define NAK  0x15
  59#define CAN  0x18
  60#define CTRLZ 0x1A
  61
  62#define DLY_1S 1000
  63#define MAXRETRANS 25
  64
  65static int check(int crc, const unsigned char *buf, int sz)
  66{
  67        if (crc) {
  68                unsigned short crc = crc16_ccitt(buf, sz);
  69                unsigned short tcrc = (buf[sz]<<8)+buf[sz+1];
  70                if (crc == tcrc)
  71                        return 1;
  72        }
  73        else {
  74                int i;
  75                unsigned char cks = 0;
  76                for (i = 0; i < sz; ++i) {
  77                        cks += buf[i];
  78                }
  79                if (cks == buf[sz])
  80                return 1;
  81        }
  82
  83        return 0;
  84}
  85
  86static void flushinput(void)
  87{
  88        while (_inbyte(((DLY_1S)*3)>>1) >= 0)
  89                ;
  90}
  91
  92int xmodemReceive(unsigned char *dest, int destsz)
  93{
  94        unsigned char xbuff[1030]; /* 1024 for XModem 1k + 3 head chars + 2 crc + nul */
  95        unsigned char *p;
  96        int bufsz, crc = 0;
  97        unsigned char trychar = 'C';
  98        unsigned char packetno = 1;
  99        int i, c, len = 0;
 100        int retry, retrans = MAXRETRANS;
 101
 102        for(;;) {
 103                for( retry = 0; retry < 16; ++retry) {
 104                        if (trychar) _outbyte(trychar);
 105                        if ((c = _inbyte((DLY_1S)<<1)) >= 0) {
 106                                switch (c) {
 107                                case SOH:
 108                                        bufsz = 128;
 109                                        goto start_recv;
 110                                case STX:
 111                                        bufsz = 1024;
 112                                        goto start_recv;
 113                                case EOT:
 114                                        flushinput();
 115                                        _outbyte(ACK);
 116                                        return len; /* normal end */
 117                                case CAN:
 118                                        if ((c = _inbyte(DLY_1S)) == CAN) {
 119                                                flushinput();
 120                                                _outbyte(ACK);
 121                                                return -1; /* canceled by remote */
 122                                        }
 123                                        break;
 124                                default:
 125                                        break;
 126                                }
 127                        }
 128                }
 129                if (trychar == 'C') { trychar = NAK; continue; }
 130                flushinput();
 131                _outbyte(CAN);
 132                _outbyte(CAN);
 133                _outbyte(CAN);
 134                return -2; /* sync error */
 135
 136        start_recv:
 137                if (trychar == 'C') crc = 1;
 138                trychar = 0;
 139                p = xbuff;
 140                *p++ = c;
 141                for (i = 0;  i < (bufsz+(crc?1:0)+3); ++i) {
 142                        if ((c = _inbyte(DLY_1S)) < 0) goto reject;
 143                        *p++ = c;
 144                }
 145
 146                if (xbuff[1] == (unsigned char)(~xbuff[2]) && 
 147                        (xbuff[1] == packetno || xbuff[1] == (unsigned char)packetno-1) &&
 148                        check(crc, &xbuff[3], bufsz)) {
 149                        if (xbuff[1] == packetno)       {
 150                                register int count = destsz - len;
 151                                if (count > bufsz) count = bufsz;
 152                                if (count > 0) {
 153                                        memcpy (&dest[len], &xbuff[3], count);
 154                                        len += count;
 155                                }
 156                                ++packetno;
 157                                retrans = MAXRETRANS+1;
 158                        }
 159                        if (--retrans <= 0) {
 160                                flushinput();
 161                                _outbyte(CAN);
 162                                _outbyte(CAN);
 163                                _outbyte(CAN);
 164                                return -3; /* too many retry error */
 165                        }
 166                        _outbyte(ACK);
 167                        continue;
 168                }
 169        reject:
 170                flushinput();
 171                _outbyte(NAK);
 172        }
 173}
 174
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.