xref: /netbsd-src/usr.bin/tip/aculib/t3000.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: t3000.c,v 1.11 2004/04/23 22:11:44 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1992, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)t3000.c	8.1 (Berkeley) 6/6/93";
36 #endif
37 __RCSID("$NetBSD: t3000.c,v 1.11 2004/04/23 22:11:44 christos Exp $");
38 #endif /* not lint */
39 
40 /*
41  * Routines for calling up on a Telebit T3000 modem.
42  * Derived from Courier driver.
43  */
44 #include "tip.h"
45 
46 #define	MAXRETRY	5
47 
48 static	int timeout = 0;
49 static	int connected = 0;
50 static	jmp_buf timeoutbuf;
51 
52 static	void	sigALRM __P((int));
53 static	int	t3000_connect __P((void));
54 static	void	t3000_nap __P((void));
55 static	void	t3000_napx __P((int));
56 static	int	t3000_swallow __P((const char *));
57 static	int	t3000_sync __P((void));
58 static	void	t3000_write __P((int, const char *, int));
59 
60 int
61 t3000_dialer(num, acu)
62 	char *num;
63 	char *acu;
64 {
65 	char *cp;
66 	struct termios cntrl;
67 #ifdef ACULOG
68 	char line[80];
69 #endif
70 
71 	if (boolean(value(VERBOSE)))
72 		printf("Using \"%s\"\n", acu);
73 
74 	tcgetattr(FD, &cntrl);
75 	cntrl.c_cflag |= HUPCL;
76 	tcsetattr(FD, TCSANOW, &cntrl);
77 	/*
78 	 * Get in synch.
79 	 */
80 	if (!t3000_sync()) {
81 badsynch:
82 		printf("can't synchronize with t3000\n");
83 #ifdef ACULOG
84 		logent(value(HOST), num, "t3000", "can't synch up");
85 #endif
86 		return (0);
87 	}
88 	t3000_write(FD, "AT E0\r", 6);	/* turn off echoing */
89 	sleep(1);
90 #ifdef DEBUG
91 	if (boolean(value(VERBOSE)))
92 		t3000_verbose_read();
93 #endif
94 	tcflush(FD, TCIOFLUSH);
95 	t3000_write(FD, "AT E0 H0 Q0 X4 V1\r", 18);
96 	if (!t3000_swallow("\r\nOK\r\n"))
97 		goto badsynch;
98 	fflush(stdout);
99 	t3000_write(FD, "AT D", 4);
100 	for (cp = num; *cp; cp++)
101 		if (*cp == '=')
102 			*cp = ',';
103 	t3000_write(FD, num, strlen(num));
104 	t3000_write(FD, "\r", 1);
105 	connected = t3000_connect();
106 #ifdef ACULOG
107 	if (timeout) {
108 		(void)snprintf(line, sizeof line, "%d second dial timeout",
109 			(int)number(value(DIALTIMEOUT)));
110 		logent(value(HOST), num, "t3000", line);
111 	}
112 #endif
113 	if (timeout)
114 		t3000_disconnect();
115 	return (connected);
116 }
117 
118 void
119 t3000_disconnect()
120 {
121 	 /* first hang up the modem*/
122 	ioctl(FD, TIOCCDTR, 0);
123 	sleep(1);
124 	ioctl(FD, TIOCSDTR, 0);
125 	t3000_sync();				/* reset */
126 	close(FD);
127 }
128 
129 void
130 t3000_abort()
131 {
132 	t3000_write(FD, "\r", 1);	/* send anything to abort the call */
133 	t3000_disconnect();
134 }
135 
136 static void
137 sigALRM(dummy)
138 	int dummy;
139 {
140 	printf("\07timeout waiting for reply\n");
141 	timeout = 1;
142 	longjmp(timeoutbuf, 1);
143 }
144 
145 static int
146 t3000_swallow(match)
147 	const char *match;
148 {
149 	sig_t f;
150 	char c;
151 
152 #if __GNUC__	/* XXX pacify gcc */
153 	(void)&match;
154 #endif
155 
156 	f = signal(SIGALRM, sigALRM);
157 	timeout = 0;
158 	do {
159 		if (*match =='\0') {
160 			signal(SIGALRM, f);
161 			return (1);
162 		}
163 		if (setjmp(timeoutbuf)) {
164 			signal(SIGALRM, f);
165 			return (0);
166 		}
167 		alarm(number(value(DIALTIMEOUT)));
168 		read(FD, &c, 1);
169 		alarm(0);
170 		c &= 0177;
171 #ifdef DEBUG
172 		if (boolean(value(VERBOSE)))
173 			putchar(c);
174 #endif
175 	} while (c == *match++);
176 #ifdef DEBUG
177 	if (boolean(value(VERBOSE)))
178 		fflush(stdout);
179 #endif
180 	signal(SIGALRM, SIG_DFL);
181 	return (0);
182 }
183 
184 #ifndef B19200		/* XXX */
185 #define	B19200	EXTA
186 #define	B38400	EXTB
187 #endif
188 
189 struct tbaud_msg {
190 	const char *msg;
191 	int baud;
192 	int baud2;
193 } tbaud_msg[] = {
194 	{ "",		B300,	0 },
195 	{ " 1200",	B1200,	0 },
196 	{ " 2400",	B2400,	0 },
197 	{ " 4800",	B4800,	0 },
198 	{ " 9600",	B9600,	0 },
199 	{ " 14400",	B19200,	B9600 },
200 	{ " 19200",	B19200,	B9600 },
201 	{ " 38400",	B38400,	B9600 },
202 	{ " 57600",	B38400,	B9600 },
203 	{ " 7512",	B9600,	0 },
204 	{ " 1275",	B2400,	0 },
205 	{ " 7200",	B9600,	0 },
206 	{ " 12000",	B19200,	B9600 },
207 	{ 0,		0,	0 },
208 };
209 
210 static int
211 t3000_connect()
212 {
213 	char c;
214 	int nc, nl, n;
215 	char dialer_buf[64];
216 	struct tbaud_msg *bm;
217 	sig_t f;
218 
219 #if __GNUC__	/* XXX pacify gcc */
220 	(void)&nc;
221 	(void)&nl;
222 #endif
223 
224 	if (t3000_swallow("\r\n") == 0)
225 		return (0);
226 	f = signal(SIGALRM, sigALRM);
227 again:
228 	memset(dialer_buf, 0, sizeof(dialer_buf));
229 	timeout = 0;
230 	for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) {
231 		if (setjmp(timeoutbuf))
232 			break;
233 		alarm(number(value(DIALTIMEOUT)));
234 		n = read(FD, &c, 1);
235 		alarm(0);
236 		if (n <= 0)
237 			break;
238 		c &= 0x7f;
239 		if (c == '\r') {
240 			if (t3000_swallow("\n") == 0)
241 				break;
242 			if (!dialer_buf[0])
243 				goto again;
244 			if (strcmp(dialer_buf, "RINGING") == 0 &&
245 			    boolean(value(VERBOSE))) {
246 #ifdef DEBUG
247 				printf("%s\r\n", dialer_buf);
248 #endif
249 				goto again;
250 			}
251 			if (strncmp(dialer_buf, "CONNECT",
252 				    sizeof("CONNECT")-1) != 0)
253 				break;
254 			for (bm = tbaud_msg ; bm->msg ; bm++)
255 				if (strcmp(bm->msg,
256 				    dialer_buf+sizeof("CONNECT")-1) == 0) {
257 					struct termios	cntrl;
258 
259 					tcgetattr(FD, &cntrl);
260 					cfsetospeed(&cntrl, bm->baud);
261 					cfsetispeed(&cntrl, bm->baud);
262 					tcsetattr(FD, TCSAFLUSH, &cntrl);
263 					signal(SIGALRM, f);
264 #ifdef DEBUG
265 					if (boolean(value(VERBOSE)))
266 						printf("%s\r\n", dialer_buf);
267 #endif
268 					return (1);
269 				}
270 			break;
271 		}
272 		dialer_buf[nc] = c;
273 #ifdef notdef
274 		if (boolean(value(VERBOSE)))
275 			putchar(c);
276 #endif
277 	}
278 	printf("%s\r\n", dialer_buf);
279 	signal(SIGALRM, f);
280 	return (0);
281 }
282 
283 /*
284  * This convoluted piece of code attempts to get
285  * the t3000 in sync.
286  */
287 static int
288 t3000_sync()
289 {
290 	int already = 0;
291 	int len;
292 	char buf[40];
293 
294 	while (already++ < MAXRETRY) {
295 		tcflush(FD, TCIOFLUSH);
296 		t3000_write(FD, "\rAT Z\r", 6);	/* reset modem */
297 		memset(buf, 0, sizeof(buf));
298 		sleep(2);
299 		ioctl(FD, FIONREAD, &len);
300 #if 1
301 if (len == 0) len = 1;
302 #endif
303 		if (len) {
304 			len = read(FD, buf, sizeof(buf));
305 #ifdef DEBUG
306 			buf[len] = '\0';
307 			printf("t3000_sync: (\"%s\")\n\r", buf);
308 #endif
309 			if (strchr(buf, '0') ||
310 		   	   (strchr(buf, 'O') && strchr(buf, 'K')))
311 				return(1);
312 		}
313 		/*
314 		 * If not strapped for DTR control,
315 		 * try to get command mode.
316 		 */
317 		sleep(1);
318 		t3000_write(FD, "+++", 3);
319 		sleep(1);
320 		/*
321 		 * Toggle DTR to force anyone off that might have left
322 		 * the modem connected.
323 		 */
324 		ioctl(FD, TIOCCDTR, 0);
325 		sleep(1);
326 		ioctl(FD, TIOCSDTR, 0);
327 	}
328 	t3000_write(FD, "\rAT Z\r", 6);
329 	return (0);
330 }
331 
332 static void
333 t3000_write(fd, cp, n)
334 	int fd;
335 	const char *cp;
336 	int n;
337 {
338 
339 #ifdef notdef
340 	if (boolean(value(VERBOSE)))
341 		write(1, cp, n);
342 #endif
343 	tcdrain(fd);
344 	t3000_nap();
345 	for ( ; n-- ; cp++) {
346 		write(fd, cp, 1);
347 		tcdrain(fd);
348 		t3000_nap();
349 	}
350 }
351 
352 #ifdef DEBUG
353 t3000_verbose_read()
354 {
355 	int n = 0;
356 	char buf[BUFSIZ];
357 
358 	if (ioctl(FD, FIONREAD, &n) < 0)
359 		return;
360 	if (n <= 0)
361 		return;
362 	if (read(FD, buf, n) != n)
363 		return;
364 	write(1, buf, n);
365 }
366 #endif
367 
368 #define setsa(sa, a) \
369 	sa.sa_handler = a; sigemptyset(&sa.sa_mask); sa.sa_flags = 0
370 
371 static int napms = 50; /* Give the t3000 50 milliseconds between characters */
372 
373 static int ringring;
374 
375 void
376 t3000_nap()
377 {
378 
379 	struct itimerval itv, oitv;
380 	struct itimerval *itp = &itv;
381 	struct sigaction sa, osa;
382 	sigset_t sm, osm;
383 
384 	timerclear(&itp->it_interval);
385 	timerclear(&itp->it_value);
386 	if (setitimer(ITIMER_REAL, itp, &oitv) < 0)
387 		return;
388 
389 	sigemptyset(&sm);
390 	sigaddset(&sm, SIGALRM);
391 	(void)sigprocmask(SIG_BLOCK, &sm, &osm);
392 
393 	itp->it_value.tv_sec = napms/1000;
394 	itp->it_value.tv_usec = ((napms%1000)*1000);
395 
396 	setsa(sa, t3000_napx);
397 	(void)sigaction(SIGALRM, &sa, &osa);
398 
399 	(void)setitimer(ITIMER_REAL, itp, NULL);
400 
401 	sm = osm;
402 	sigdelset(&sm, SIGALRM);
403 
404 	for (ringring = 0; !ringring; )
405 		sigsuspend(&sm);
406 
407 	(void)sigaction(SIGALRM, &osa, NULL);
408 	(void)setitimer(ITIMER_REAL, &oitv, NULL);
409 	(void)sigprocmask(SIG_SETMASK, &osm, NULL);
410 }
411 
412 static void
413 t3000_napx(dummy)
414 	int dummy;
415 {
416 
417         ringring = 1;
418 }
419