xref: /titanic_52/usr/src/boot/sys/boot/arm/at91/libat91/xmodem.c (revision 4a5d661a82b942b6538acd26209d959ce98b593a)
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$
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 #define TO	10
43 /*
44  * int GetRecord(char , char *)
45  *  This private function receives a x-modem record to the pointer and
46  * returns non-zero on success.
47  */
48 static int
49 GetRecord(char blocknum, char *dest)
50 {
51 	int		size;
52 	int		ch;
53 	unsigned	chk, j;
54 
55 	chk = 0;
56 
57 	if ((ch = getc(TO)) == -1)
58 		goto err;
59 	if (ch != blocknum)
60 		goto err;
61 	if ((ch = getc(TO)) == -1)
62 		goto err;
63 	if (ch != (~blocknum & 0xff))
64 		goto err;
65 
66 	for (size = 0; size < PACKET_SIZE; ++size) {
67 		if ((ch = getc(TO)) == -1)
68 			goto err;
69 		chk = chk ^ ch << 8;
70 		for (j = 0; j < 8; ++j) {
71 			if (chk & 0x8000)
72 				chk = chk << 1 ^ 0x1021;
73 			else
74 				chk = chk << 1;
75 		}
76 		*dest++ = ch;
77 	}
78 
79 	chk &= 0xFFFF;
80 
81 	if (((ch = getc(TO)) == -1) || ((ch & 0xff) != ((chk >> 8) & 0xFF)))
82 		goto err;
83 	if (((ch = getc(TO)) == -1) || ((ch & 0xff) != (chk & 0xFF)))
84 		goto err;
85 	putchar(ACK);
86 
87 	return (1);
88 err:;
89 	putchar(CAN);
90 	// We should allow for resend, but we don't.
91 	return (0);
92 }
93 
94 /*
95  * int xmodem_rx(char *)
96  *  This global function receives a x-modem transmission consisting of
97  * (potentially) several blocks.  Returns the number of bytes received or
98  * -1 on error.
99  */
100 int
101 xmodem_rx(char *dest)
102 {
103 	int		starting, ch;
104 	char		packetNumber, *startAddress = dest;
105 
106 	packetNumber = 1;
107 	starting = 1;
108 
109 	while (1) {
110 		if (starting)
111 			putchar('C');
112 		if (((ch = getc(1)) == -1) || (ch != SOH && ch != EOT))
113 			continue;
114 		if (ch == EOT) {
115 			putchar(ACK);
116 			return (dest - startAddress);
117 		}
118 		starting = 0;
119 		// Xmodem packets: SOH PKT# ~PKT# 128-bytes CRC16
120 		if (!GetRecord(packetNumber, dest))
121 			return (-1);
122 		dest += PACKET_SIZE;
123 		packetNumber++;
124 	}
125 
126 	// the loop above should return in all cases
127 	return (-1);
128 }
129