Tools for working with Cidco Mailstations
1/*
2 * sendload
3 *
4 * must be run as root to set iopl and use inb/outb
5 *
6 * assumes Loader has been loaded on the Mailstation and is running
7 */
8
9#include <err.h>
10#include <errno.h>
11#include <fcntl.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <signal.h>
16#include <termios.h>
17#include <unistd.h>
18#include <sys/stat.h>
19#include <sys/types.h>
20
21#include "tribble.h"
22
23static int serial_fd = -1;
24static int serial_speed = B115200;
25
26void
27usage(void)
28{
29 errx(1, "usage: %s [-dr] [-p lpt address | serial device] "
30 "[-s serial speed] <file to send>", getprogname());
31}
32
33int
34sendbyte_shim(char b)
35{
36 if (serial_fd >= 0)
37 return (write(serial_fd, &b, 1) != 1);
38 else
39 return sendbyte(b);
40}
41
42void
43setupserial(speed_t speed)
44{
45 struct termios tty;
46
47 if (tcgetattr(serial_fd, &tty) < 0)
48 err(1, "tcgetattr");
49
50 cfsetospeed(&tty, speed);
51 cfsetispeed(&tty, speed);
52
53 tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
54 tty.c_cflag &= ~CSIZE;
55 tty.c_cflag |= CS8; /* 8-bit characters */
56 tty.c_cflag &= ~PARENB; /* no parity bit */
57 tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
58
59 /* setup for non-canonical mode */
60 tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
61 tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
62 tty.c_oflag &= ~OPOST;
63
64 /* fetch bytes as they become available */
65 tty.c_cc[VMIN] = 1;
66 tty.c_cc[VTIME] = 1;
67
68 if (tcsetattr(serial_fd, TCSANOW, &tty) != 0)
69 err(1, "tcsetattr");
70}
71
72int
73main(int argc, char *argv[])
74{
75 FILE *pFile;
76 struct stat sb;
77 unsigned int sent = 0, size = 0, raw = 0;
78 int ch;
79 char *fn, *serial_dev = NULL;
80
81 while ((ch = getopt(argc, argv, "dp:rs:")) != -1) {
82 switch (ch) {
83 case 'd':
84 tribble_debug = 1;
85 break;
86 case 'p':
87 if (optarg[0] == '/') {
88 if ((serial_dev = strdup(optarg)) == NULL)
89 err(1, "strdup");
90 serial_fd = open(serial_dev,
91 O_RDWR | O_NOCTTY | O_SYNC);
92 if (serial_fd < 0)
93 err(1, "can't open %s", optarg);
94 } else {
95 tribble_port = (unsigned)strtol(optarg, NULL,
96 0);
97 if (errno)
98 err(1, "invalid port value");
99 }
100 break;
101 case 'r':
102 raw = 1;
103 break;
104 case 's':
105 serial_speed = (unsigned)strtol(optarg, NULL, 0);
106 if (errno)
107 err(1, "invalid serial port speed value");
108 break;
109 default:
110 usage();
111 }
112 }
113 argc -= optind;
114 argv += optind;
115
116 if (argc != 1)
117 usage();
118
119 if (serial_fd >= 0)
120 setupserial(serial_speed);
121 else
122 checkio();
123
124 fn = argv[0];
125 pFile = fopen(fn, "rb");
126 if (!pFile)
127 err(1, "open: %s", fn);
128
129 if (fstat(fileno(pFile), &sb) != 0)
130 err(1, "fstat: %s", fn);
131
132 /* we're never going to send huge files */
133 size = (unsigned int)sb.st_size;
134
135 if (serial_fd >= 0)
136 printf("[%s]", serial_dev);
137 else
138 printf("[lpt port 0x%x]", tribble_port);
139
140 printf(" sending %s (%d bytes)...", fn, size);
141 fflush(stdout);
142
143 /* loader expects two bytes, the low and then high of the file size */
144 if (!raw) {
145 if (sendbyte_shim(size & 0xff) != 0)
146 errx(1, "sendbyte failed");
147 if (sendbyte_shim((size >> 8) & 0xff) != 0)
148 errx(1, "sendbyte failed");
149 }
150
151 while (sent < size) {
152 if (sendbyte_shim(fgetc(pFile)) != 0)
153 errx(1, "sendbyte failed at %d/%d", sent, size);
154
155 if (sent++ == 0)
156 printf("\n");
157
158 if (sent % (raw ? 64 : 1024) == 0 || sent == size) {
159 printf("\rsent: %07d/%07d", sent, size);
160 fflush(stdout);
161 }
162 }
163 fclose(pFile);
164
165 printf("\n");
166
167 return 0;
168}