xref: /netbsd-src/usr.bin/tip/aculib/t3000.c (revision c41a4eebefede43f6950f838a387dc18c6a431bf)
1 /*	$NetBSD: t3000.c,v 1.6 1997/11/22 07:28:57 lukem 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.6 1997/11/22 07:28:57 lukem 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 	nc = 0; nl = sizeof(dialer_buf)-1;
233 	memset(dialer_buf, 0, sizeof(dialer_buf));
234 	timeout = 0;
235 	for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) {
236 		if (setjmp(timeoutbuf))
237 			break;
238 		alarm(number(value(DIALTIMEOUT)));
239 		n = read(FD, &c, 1);
240 		alarm(0);
241 		if (n <= 0)
242 			break;
243 		c &= 0x7f;
244 		if (c == '\r') {
245 			if (t3000_swallow("\n") == 0)
246 				break;
247 			if (!dialer_buf[0])
248 				goto again;
249 			if (strcmp(dialer_buf, "RINGING") == 0 &&
250 			    boolean(value(VERBOSE))) {
251 #ifdef DEBUG
252 				printf("%s\r\n", dialer_buf);
253 #endif
254 				goto again;
255 			}
256 			if (strncmp(dialer_buf, "CONNECT",
257 				    sizeof("CONNECT")-1) != 0)
258 				break;
259 			for (bm = tbaud_msg ; bm->msg ; bm++)
260 				if (strcmp(bm->msg,
261 				    dialer_buf+sizeof("CONNECT")-1) == 0) {
262 					struct termios	cntrl;
263 
264 					tcgetattr(FD, &cntrl);
265 					cfsetospeed(&cntrl, bm->baud);
266 					cfsetispeed(&cntrl, bm->baud);
267 					tcsetattr(FD, TCSAFLUSH, &cntrl);
268 					signal(SIGALRM, f);
269 #ifdef DEBUG
270 					if (boolean(value(VERBOSE)))
271 						printf("%s\r\n", dialer_buf);
272 #endif
273 					return (1);
274 				}
275 			break;
276 		}
277 		dialer_buf[nc] = c;
278 #ifdef notdef
279 		if (boolean(value(VERBOSE)))
280 			putchar(c);
281 #endif
282 	}
283 	printf("%s\r\n", dialer_buf);
284 	signal(SIGALRM, f);
285 	return (0);
286 }
287 
288 /*
289  * This convoluted piece of code attempts to get
290  * the t3000 in sync.
291  */
292 static int
293 t3000_sync()
294 {
295 	int already = 0;
296 	int len;
297 	char buf[40];
298 
299 	while (already++ < MAXRETRY) {
300 		tcflush(FD, TCIOFLUSH);
301 		t3000_write(FD, "\rAT Z\r", 6);	/* reset modem */
302 		memset(buf, 0, sizeof(buf));
303 		sleep(2);
304 		ioctl(FD, FIONREAD, &len);
305 #if 1
306 if (len == 0) len = 1;
307 #endif
308 		if (len) {
309 			len = read(FD, buf, sizeof(buf));
310 #ifdef DEBUG
311 			buf[len] = '\0';
312 			printf("t3000_sync: (\"%s\")\n\r", buf);
313 #endif
314 			if (strchr(buf, '0') ||
315 		   	   (strchr(buf, 'O') && strchr(buf, 'K')))
316 				return(1);
317 		}
318 		/*
319 		 * If not strapped for DTR control,
320 		 * try to get command mode.
321 		 */
322 		sleep(1);
323 		t3000_write(FD, "+++", 3);
324 		sleep(1);
325 		/*
326 		 * Toggle DTR to force anyone off that might have left
327 		 * the modem connected.
328 		 */
329 		ioctl(FD, TIOCCDTR, 0);
330 		sleep(1);
331 		ioctl(FD, TIOCSDTR, 0);
332 	}
333 	t3000_write(FD, "\rAT Z\r", 6);
334 	return (0);
335 }
336 
337 static void
338 t3000_write(fd, cp, n)
339 	int fd;
340 	char *cp;
341 	int n;
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 /*
373  * Code stolen from /usr/src/lib/libc/gen/sleep.c
374  */
375 #define mask(s) (1<<((s)-1))
376 #define setvec(vec, a) \
377         vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0
378 
379 static napms = 50; /* Give the t3000 50 milliseconds between characters */
380 
381 static int ringring;
382 
383 static void
384 t3000_nap()
385 {
386 
387 	int omask;
388         struct itimerval itv, oitv;
389         struct itimerval *itp = &itv;
390         struct sigvec vec, ovec;
391 
392         timerclear(&itp->it_interval);
393         timerclear(&itp->it_value);
394         if (setitimer(ITIMER_REAL, itp, &oitv) < 0)
395                 return;
396         setvec(ovec, SIG_DFL);
397         omask = sigblock(mask(SIGALRM));
398         itp->it_value.tv_sec = napms/1000;
399 	itp->it_value.tv_usec = ((napms%1000)*1000);
400         setvec(vec, t3000_napx);
401         ringring = 0;
402         (void) sigvec(SIGALRM, &vec, &ovec);
403         (void) setitimer(ITIMER_REAL, itp, (struct itimerval *)0);
404         while (!ringring)
405                 sigpause(omask &~ mask(SIGALRM));
406         (void) sigvec(SIGALRM, &ovec, (struct sigvec *)0);
407         (void) setitimer(ITIMER_REAL, &oitv, (struct itimerval *)0);
408 	(void) sigsetmask(omask);
409 }
410 
411 static void
412 t3000_napx(dummy)
413 	int dummy;
414 {
415         ringring = 1;
416 }
417