xmodem.c revision 157873
1/*- 2 * Copyright (c) 2006 M. Warner Losh. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * 24 * This software is derived from software provide by Kwikbyte who specifically 25 * disclaimed copyright on the code. This version of xmodem has been nearly 26 * completely rewritten, but the CRC is from the original. 27 * 28 * $FreeBSD: head/sys/boot/arm/at91/libat91/xmodem.c 157873 2006-04-19 17:16:49Z imp $ 29 */ 30 31#include "lib.h" 32 33#define PACKET_SIZE 128 34 35/* Line control codes */ 36#define SOH 0x01 /* start of header */ 37#define ACK 0x06 /* Acknowledge */ 38#define NAK 0x15 /* Negative acknowledge */ 39#define CAN 0x18 /* Cancel */ 40#define EOT 0x04 /* end of text */ 41 42/* 43 * int GetRecord(char , char *) 44 * This private function receives a x-modem record to the pointer and 45 * returns non-zero on success. 46 */ 47static int 48GetRecord(char blocknum, char *dest) 49{ 50 int size; 51 int ch; 52 unsigned chk, j; 53 54 chk = 0; 55 56 if ((ch = getc(1)) == -1) 57 goto err; 58 if (ch != blocknum) 59 goto err; 60 if ((ch = getc(1)) == -1) 61 goto err; 62 if (ch != (~blocknum & 0xff)) 63 goto err; 64 65 for (size = 0; size < PACKET_SIZE; ++size) { 66 if ((ch = getc(1)) == -1) 67 goto err; 68 chk = chk ^ ch << 8; 69 for (j = 0; j < 8; ++j) { 70 if (chk & 0x8000) 71 chk = chk << 1 ^ 0x1021; 72 else 73 chk = chk << 1; 74 } 75 *dest++ = ch; 76 } 77 78 chk &= 0xFFFF; 79 80 if (((ch = getc(1)) == -1) || ((ch & 0xff) != ((chk >> 8) & 0xFF))) 81 goto err; 82 if (((ch = getc(1)) == -1) || ((ch & 0xff) != (chk & 0xFF))) 83 goto err; 84 putchar(ACK); 85 86 return (1); 87err:; 88 putchar(CAN); 89 // We should allow for resend, but we don't. 90 return (0); 91} 92 93/* 94 * int xmodem_rx(char *) 95 * This global function receives a x-modem transmission consisting of 96 * (potentially) several blocks. Returns the number of bytes received or 97 * -1 on error. 98 */ 99int 100xmodem_rx(char *dest) 101{ 102 int starting, ch; 103 char packetNumber, *startAddress = dest; 104 105 packetNumber = 1; 106 starting = 1; 107 108 while (1) { 109 if (starting) 110 putchar('C'); 111 if (((ch = getc(1)) == -1) || (ch != SOH && ch != EOT)) 112 continue; 113 if (ch == EOT) { 114 putchar(ACK); 115 return (dest - startAddress); 116 } 117 starting = 0; 118 // Xmodem packets: SOH PKT# ~PKT# 128-bytes CRC16 119 if (!GetRecord(packetNumber, dest)) 120 return (-1); 121 dest += PACKET_SIZE; 122 packetNumber++; 123 } 124 125 // the loop above should return in all cases 126 return (-1); 127} 128