diff options
Diffstat (limited to 'sys/boot/arm/at91/libat91/xmodem.c')
-rw-r--r-- | sys/boot/arm/at91/libat91/xmodem.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/sys/boot/arm/at91/libat91/xmodem.c b/sys/boot/arm/at91/libat91/xmodem.c new file mode 100644 index 0000000..c3903aa --- /dev/null +++ b/sys/boot/arm/at91/libat91/xmodem.c @@ -0,0 +1,127 @@ +/*- + * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software is derived from software provide by Kwikbyte who specifically + * disclaimed copyright on the code. This version of xmodem has been nearly + * completely rewritten, but the CRC is from the original. + * + * $FreeBSD$ + */ + +#include "lib.h" + +#define PACKET_SIZE 128 + +/* Line control codes */ +#define SOH 0x01 /* start of header */ +#define ACK 0x06 /* Acknowledge */ +#define NAK 0x15 /* Negative acknowledge */ +#define CAN 0x18 /* Cancel */ +#define EOT 0x04 /* end of text */ + +/* + * int GetRecord(char , char *) + * This private function receives a x-modem record to the pointer and + * returns non-zero on success. + */ +static int +GetRecord(char blocknum, char *dest) +{ + int size; + int ch; + unsigned chk, j; + + chk = 0; + + if ((ch = getc(1)) == -1) + goto err; + if (ch != blocknum) + goto err; + if ((ch = getc(1)) == -1) + goto err; + if (ch != (~blocknum & 0xff)) + goto err; + + for (size = 0; size < PACKET_SIZE; ++size) { + if ((ch = getc(1)) == -1) + goto err; + chk = chk ^ ch << 8; + for (j = 0; j < 8; ++j) { + if (chk & 0x8000) + chk = chk << 1 ^ 0x1021; + else + chk = chk << 1; + } + *dest++ = ch; + } + + chk &= 0xFFFF; + + if (((ch = getc(1)) == -1) || ((ch & 0xff) != ((chk >> 8) & 0xFF))) + goto err; + if (((ch = getc(1)) == -1) || ((ch & 0xff) != (chk & 0xFF))) + goto err; + putchar(ACK); + + return (1); +err:; + putchar(CAN); + // We should allow for resend, but we don't. + return (0); +} + +/* + * int xmodem_rx(char *) + * This global function receives a x-modem transmission consisting of + * (potentially) several blocks. Returns the number of bytes received or + * -1 on error. + */ +int +xmodem_rx(char *dest) +{ + int starting, ch; + char packetNumber, *startAddress = dest; + + packetNumber = 1; + starting = 1; + + while (1) { + if (starting) + putchar('C'); + if (((ch = getc(1)) == -1) || (ch != SOH && ch != EOT)) + continue; + if (ch == EOT) { + putchar(ACK); + return (dest - startAddress); + } + starting = 0; + // Xmodem packets: SOH PKT# ~PKT# 128-bytes CRC16 + if (!GetRecord(packetNumber, dest)) + return (-1); + dest += PACKET_SIZE; + packetNumber++; + } + + // the loop above should return in all cases + return (-1); +} |