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