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