xref: /netbsd-src/usr.bin/tip/aculib/t3000.c (revision ffe34450414a71a1dea7aa084cc0e2fae0724115)
1*ffe34450Schristos /*	$NetBSD: t3000.c,v 1.15 2006/12/14 17:09:43 christos Exp $	*/
239801cccSjtc 
33075e8d6Sjtc /*
43075e8d6Sjtc  * Copyright (c) 1992, 1993
53075e8d6Sjtc  *	The Regents of the University of California.  All rights reserved.
63075e8d6Sjtc  *
73075e8d6Sjtc  * Redistribution and use in source and binary forms, with or without
83075e8d6Sjtc  * modification, are permitted provided that the following conditions
93075e8d6Sjtc  * are met:
103075e8d6Sjtc  * 1. Redistributions of source code must retain the above copyright
113075e8d6Sjtc  *    notice, this list of conditions and the following disclaimer.
123075e8d6Sjtc  * 2. Redistributions in binary form must reproduce the above copyright
133075e8d6Sjtc  *    notice, this list of conditions and the following disclaimer in the
143075e8d6Sjtc  *    documentation and/or other materials provided with the distribution.
1589aaa1bbSagc  * 3. Neither the name of the University nor the names of its contributors
163075e8d6Sjtc  *    may be used to endorse or promote products derived from this software
173075e8d6Sjtc  *    without specific prior written permission.
183075e8d6Sjtc  *
193075e8d6Sjtc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
203075e8d6Sjtc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
213075e8d6Sjtc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
223075e8d6Sjtc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
233075e8d6Sjtc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
243075e8d6Sjtc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
253075e8d6Sjtc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
263075e8d6Sjtc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
273075e8d6Sjtc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
283075e8d6Sjtc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
293075e8d6Sjtc  * SUCH DAMAGE.
303075e8d6Sjtc  */
313075e8d6Sjtc 
32e37283e1Slukem #include <sys/cdefs.h>
333075e8d6Sjtc #ifndef lint
3439801cccSjtc #if 0
353075e8d6Sjtc static char sccsid[] = "@(#)t3000.c	8.1 (Berkeley) 6/6/93";
3639801cccSjtc #endif
37*ffe34450Schristos __RCSID("$NetBSD: t3000.c,v 1.15 2006/12/14 17:09:43 christos Exp $");
383075e8d6Sjtc #endif /* not lint */
393075e8d6Sjtc 
403075e8d6Sjtc /*
413075e8d6Sjtc  * Routines for calling up on a Telebit T3000 modem.
423075e8d6Sjtc  * Derived from Courier driver.
433075e8d6Sjtc  */
443075e8d6Sjtc #include "tip.h"
45258108ceSpk 
463075e8d6Sjtc #define	MAXRETRY	5
473075e8d6Sjtc 
483075e8d6Sjtc static	int timeout = 0;
493075e8d6Sjtc static	int connected = 0;
50e37283e1Slukem static	jmp_buf timeoutbuf;
513075e8d6Sjtc 
5258c2151fSperry static	void	sigALRM(int);
5358c2151fSperry static	int	t3000_connect(void);
5458c2151fSperry static	void	t3000_nap(void);
5558c2151fSperry static	void	t3000_napx(int);
5658c2151fSperry static	int	t3000_swallow(const char *);
5758c2151fSperry static	int	t3000_sync(void);
5858c2151fSperry static	void	t3000_write(int, const char *, int);
59e37283e1Slukem 
60e37283e1Slukem int
t3000_dialer(char * num,char * acu)6158c2151fSperry t3000_dialer(char *num, char *acu)
623075e8d6Sjtc {
63e37283e1Slukem 	char *cp;
64258108ceSpk 	struct termios cntrl;
653075e8d6Sjtc 
663075e8d6Sjtc 	if (boolean(value(VERBOSE)))
67*ffe34450Schristos 		(void)printf("Using \"%s\"\n", acu);
683075e8d6Sjtc 
69*ffe34450Schristos 	(void)tcgetattr(FD, &cntrl);
70258108ceSpk 	cntrl.c_cflag |= HUPCL;
71*ffe34450Schristos 	(void)tcsetattr(FD, TCSANOW, &cntrl);
723075e8d6Sjtc 	/*
733075e8d6Sjtc 	 * Get in synch.
743075e8d6Sjtc 	 */
753075e8d6Sjtc 	if (!t3000_sync()) {
763075e8d6Sjtc badsynch:
77*ffe34450Schristos 		(void)printf("can't synchronize with t3000\n");
783075e8d6Sjtc 		return (0);
793075e8d6Sjtc 	}
803075e8d6Sjtc 	t3000_write(FD, "AT E0\r", 6);	/* turn off echoing */
81*ffe34450Schristos 	(void)sleep(1);
823075e8d6Sjtc #ifdef DEBUG
833075e8d6Sjtc 	if (boolean(value(VERBOSE)))
843075e8d6Sjtc 		t3000_verbose_read();
853075e8d6Sjtc #endif
86*ffe34450Schristos 	(void)tcflush(FD, TCIOFLUSH);
873075e8d6Sjtc 	t3000_write(FD, "AT E0 H0 Q0 X4 V1\r", 18);
883075e8d6Sjtc 	if (!t3000_swallow("\r\nOK\r\n"))
893075e8d6Sjtc 		goto badsynch;
90*ffe34450Schristos 	(void)fflush(stdout);
913075e8d6Sjtc 	t3000_write(FD, "AT D", 4);
923075e8d6Sjtc 	for (cp = num; *cp; cp++)
933075e8d6Sjtc 		if (*cp == '=')
943075e8d6Sjtc 			*cp = ',';
95*ffe34450Schristos 	t3000_write(FD, num, (int)strlen(num));
963075e8d6Sjtc 	t3000_write(FD, "\r", 1);
973075e8d6Sjtc 	connected = t3000_connect();
983075e8d6Sjtc 	if (timeout)
993075e8d6Sjtc 		t3000_disconnect();
1003075e8d6Sjtc 	return (connected);
1013075e8d6Sjtc }
1023075e8d6Sjtc 
103e37283e1Slukem void
t3000_disconnect(void)10458c2151fSperry t3000_disconnect(void)
1053075e8d6Sjtc {
1063075e8d6Sjtc 	 /* first hang up the modem*/
107*ffe34450Schristos 	(void)ioctl(FD, TIOCCDTR, 0);
108*ffe34450Schristos 	(void)sleep(1);
109*ffe34450Schristos 	(void)ioctl(FD, TIOCSDTR, 0);
110*ffe34450Schristos 	(void)t3000_sync();				/* reset */
111*ffe34450Schristos 	(void)close(FD);
1123075e8d6Sjtc }
1133075e8d6Sjtc 
114e37283e1Slukem void
t3000_abort(void)11558c2151fSperry t3000_abort(void)
1163075e8d6Sjtc {
1173075e8d6Sjtc 	t3000_write(FD, "\r", 1);	/* send anything to abort the call */
1183075e8d6Sjtc 	t3000_disconnect();
1193075e8d6Sjtc }
1203075e8d6Sjtc 
1213075e8d6Sjtc static void
122*ffe34450Schristos /*ARGSUSED*/
sigALRM(int dummy __unused)123*ffe34450Schristos sigALRM(int dummy __unused)
1243075e8d6Sjtc {
125*ffe34450Schristos 	(void)printf("\07timeout waiting for reply\n");
1263075e8d6Sjtc 	timeout = 1;
1273075e8d6Sjtc 	longjmp(timeoutbuf, 1);
1283075e8d6Sjtc }
1293075e8d6Sjtc 
1303075e8d6Sjtc static int
t3000_swallow(const char * volatile match)131239d1ed1Schristos t3000_swallow(const char * volatile match)
1323075e8d6Sjtc {
1333075e8d6Sjtc 	sig_t f;
1343075e8d6Sjtc 	char c;
1353075e8d6Sjtc 
1363075e8d6Sjtc 	f = signal(SIGALRM, sigALRM);
1373075e8d6Sjtc 	timeout = 0;
1383075e8d6Sjtc 	do {
1393075e8d6Sjtc 		if (*match =='\0') {
140*ffe34450Schristos 			(void)signal(SIGALRM, f);
1413075e8d6Sjtc 			return (1);
1423075e8d6Sjtc 		}
1433075e8d6Sjtc 		if (setjmp(timeoutbuf)) {
144*ffe34450Schristos 			(void)signal(SIGALRM, f);
1453075e8d6Sjtc 			return (0);
1463075e8d6Sjtc 		}
147*ffe34450Schristos 		(void)alarm((unsigned)number(value(DIALTIMEOUT)));
148*ffe34450Schristos 		(void)read(FD, &c, 1);
149*ffe34450Schristos 		(void)alarm(0);
1503075e8d6Sjtc 		c &= 0177;
1513075e8d6Sjtc #ifdef DEBUG
1523075e8d6Sjtc 		if (boolean(value(VERBOSE)))
153*ffe34450Schristos 			(void)putchar(c);
1543075e8d6Sjtc #endif
1553075e8d6Sjtc 	} while (c == *match++);
1563075e8d6Sjtc #ifdef DEBUG
1573075e8d6Sjtc 	if (boolean(value(VERBOSE)))
158*ffe34450Schristos 		(void)fflush(stdout);
1593075e8d6Sjtc #endif
160*ffe34450Schristos 	(void)signal(SIGALRM, SIG_DFL);
1613075e8d6Sjtc 	return (0);
1623075e8d6Sjtc }
1633075e8d6Sjtc 
1643075e8d6Sjtc #ifndef B19200		/* XXX */
1653075e8d6Sjtc #define	B19200	EXTA
1663075e8d6Sjtc #define	B38400	EXTB
1673075e8d6Sjtc #endif
1683075e8d6Sjtc 
1693075e8d6Sjtc struct tbaud_msg {
1704f6045fcSchristos 	const char *msg;
171*ffe34450Schristos 	unsigned int baud;
172*ffe34450Schristos 	unsigned int baud2;
1733075e8d6Sjtc } tbaud_msg[] = {
174e37283e1Slukem 	{ "",		B300,	0 },
175e37283e1Slukem 	{ " 1200",	B1200,	0 },
176e37283e1Slukem 	{ " 2400",	B2400,	0 },
177e37283e1Slukem 	{ " 4800",	B4800,	0 },
178e37283e1Slukem 	{ " 9600",	B9600,	0 },
179e37283e1Slukem 	{ " 14400",	B19200,	B9600 },
180e37283e1Slukem 	{ " 19200",	B19200,	B9600 },
181e37283e1Slukem 	{ " 38400",	B38400,	B9600 },
182e37283e1Slukem 	{ " 57600",	B38400,	B9600 },
183e37283e1Slukem 	{ " 7512",	B9600,	0 },
184e37283e1Slukem 	{ " 1275",	B2400,	0 },
185e37283e1Slukem 	{ " 7200",	B9600,	0 },
186e37283e1Slukem 	{ " 12000",	B19200,	B9600 },
187e37283e1Slukem 	{ 0,		0,	0 },
1883075e8d6Sjtc };
1893075e8d6Sjtc 
1903075e8d6Sjtc static int
t3000_connect(void)19158c2151fSperry t3000_connect(void)
1923075e8d6Sjtc {
1933075e8d6Sjtc 	char c;
194239d1ed1Schristos 	int volatile nc;
195239d1ed1Schristos 	int volatile nl;
196239d1ed1Schristos 	int n;
1973075e8d6Sjtc 	char dialer_buf[64];
1983075e8d6Sjtc 	struct tbaud_msg *bm;
1993075e8d6Sjtc 	sig_t f;
2003075e8d6Sjtc 
2013075e8d6Sjtc 	if (t3000_swallow("\r\n") == 0)
2023075e8d6Sjtc 		return (0);
2033075e8d6Sjtc 	f = signal(SIGALRM, sigALRM);
2043075e8d6Sjtc again:
205*ffe34450Schristos 	(void)memset(dialer_buf, 0, sizeof(dialer_buf));
2063075e8d6Sjtc 	timeout = 0;
2073075e8d6Sjtc 	for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) {
2083075e8d6Sjtc 		if (setjmp(timeoutbuf))
2093075e8d6Sjtc 			break;
210*ffe34450Schristos 		(void)alarm((unsigned)number(value(DIALTIMEOUT)));
2113075e8d6Sjtc 		n = read(FD, &c, 1);
212*ffe34450Schristos 		(void)alarm(0);
2133075e8d6Sjtc 		if (n <= 0)
2143075e8d6Sjtc 			break;
2153075e8d6Sjtc 		c &= 0x7f;
2163075e8d6Sjtc 		if (c == '\r') {
2173075e8d6Sjtc 			if (t3000_swallow("\n") == 0)
2183075e8d6Sjtc 				break;
2193075e8d6Sjtc 			if (!dialer_buf[0])
2203075e8d6Sjtc 				goto again;
2213075e8d6Sjtc 			if (strcmp(dialer_buf, "RINGING") == 0 &&
2223075e8d6Sjtc 			    boolean(value(VERBOSE))) {
2233075e8d6Sjtc #ifdef DEBUG
224*ffe34450Schristos 				(void)printf("%s\r\n", dialer_buf);
2253075e8d6Sjtc #endif
2263075e8d6Sjtc 				goto again;
2273075e8d6Sjtc 			}
2283075e8d6Sjtc 			if (strncmp(dialer_buf, "CONNECT",
2293075e8d6Sjtc 				    sizeof("CONNECT")-1) != 0)
2303075e8d6Sjtc 				break;
2313075e8d6Sjtc 			for (bm = tbaud_msg ; bm->msg ; bm++)
2323075e8d6Sjtc 				if (strcmp(bm->msg,
2333075e8d6Sjtc 				    dialer_buf+sizeof("CONNECT")-1) == 0) {
234258108ceSpk 					struct termios	cntrl;
235258108ceSpk 
236*ffe34450Schristos 					(void)tcgetattr(FD, &cntrl);
237*ffe34450Schristos 					(void)cfsetospeed(&cntrl, bm->baud);
238*ffe34450Schristos 					(void)cfsetispeed(&cntrl, bm->baud);
239*ffe34450Schristos 					(void)tcsetattr(FD, TCSAFLUSH, &cntrl);
240*ffe34450Schristos 					(void)signal(SIGALRM, f);
2413075e8d6Sjtc #ifdef DEBUG
2423075e8d6Sjtc 					if (boolean(value(VERBOSE)))
243*ffe34450Schristos 						(void)printf("%s\r\n", dialer_buf);
2443075e8d6Sjtc #endif
2453075e8d6Sjtc 					return (1);
2463075e8d6Sjtc 				}
2473075e8d6Sjtc 			break;
2483075e8d6Sjtc 		}
2493075e8d6Sjtc 		dialer_buf[nc] = c;
2503075e8d6Sjtc #ifdef notdef
2513075e8d6Sjtc 		if (boolean(value(VERBOSE)))
252*ffe34450Schristos 			(void)putchar(c);
2533075e8d6Sjtc #endif
2543075e8d6Sjtc 	}
255*ffe34450Schristos 	(void)printf("%s\r\n", dialer_buf);
256*ffe34450Schristos 	(void)signal(SIGALRM, f);
2573075e8d6Sjtc 	return (0);
2583075e8d6Sjtc }
2593075e8d6Sjtc 
2603075e8d6Sjtc /*
2613075e8d6Sjtc  * This convoluted piece of code attempts to get
2623075e8d6Sjtc  * the t3000 in sync.
2633075e8d6Sjtc  */
2643075e8d6Sjtc static int
t3000_sync(void)26558c2151fSperry t3000_sync(void)
2663075e8d6Sjtc {
2673075e8d6Sjtc 	int already = 0;
2683075e8d6Sjtc 	int len;
2693075e8d6Sjtc 	char buf[40];
2703075e8d6Sjtc 
2713075e8d6Sjtc 	while (already++ < MAXRETRY) {
272*ffe34450Schristos 		(void)tcflush(FD, TCIOFLUSH);
2733075e8d6Sjtc 		t3000_write(FD, "\rAT Z\r", 6);	/* reset modem */
274*ffe34450Schristos 		(void)memset(buf, 0, sizeof(buf));
275*ffe34450Schristos 		(void)sleep(2);
276*ffe34450Schristos 		(void)ioctl(FD, FIONREAD, &len);
2773075e8d6Sjtc #if 1
2783075e8d6Sjtc if (len == 0) len = 1;
2793075e8d6Sjtc #endif
2803075e8d6Sjtc 		if (len) {
2813075e8d6Sjtc 			len = read(FD, buf, sizeof(buf));
2823075e8d6Sjtc #ifdef DEBUG
2833075e8d6Sjtc 			buf[len] = '\0';
284*ffe34450Schristos 			(void)printf("t3000_sync: (\"%s\")\n\r", buf);
2853075e8d6Sjtc #endif
286e37283e1Slukem 			if (strchr(buf, '0') ||
287e37283e1Slukem 		   	   (strchr(buf, 'O') && strchr(buf, 'K')))
2883075e8d6Sjtc 				return(1);
2893075e8d6Sjtc 		}
2903075e8d6Sjtc 		/*
2913075e8d6Sjtc 		 * If not strapped for DTR control,
2923075e8d6Sjtc 		 * try to get command mode.
2933075e8d6Sjtc 		 */
294*ffe34450Schristos 		(void)sleep(1);
2953075e8d6Sjtc 		t3000_write(FD, "+++", 3);
296*ffe34450Schristos 		(void)sleep(1);
2973075e8d6Sjtc 		/*
2983075e8d6Sjtc 		 * Toggle DTR to force anyone off that might have left
2993075e8d6Sjtc 		 * the modem connected.
3003075e8d6Sjtc 		 */
301*ffe34450Schristos 		(void)ioctl(FD, TIOCCDTR, 0);
302*ffe34450Schristos 		(void)sleep(1);
303*ffe34450Schristos 		(void)ioctl(FD, TIOCSDTR, 0);
3043075e8d6Sjtc 	}
3053075e8d6Sjtc 	t3000_write(FD, "\rAT Z\r", 6);
3063075e8d6Sjtc 	return (0);
3073075e8d6Sjtc }
3083075e8d6Sjtc 
309e37283e1Slukem static void
t3000_write(int fd,const char * cp,int n)31058c2151fSperry t3000_write(int fd, const char *cp, int n)
3113075e8d6Sjtc {
31297eafd50Smrg 
3133075e8d6Sjtc #ifdef notdef
3143075e8d6Sjtc 	if (boolean(value(VERBOSE)))
315*ffe34450Schristos 		(void)write(1, cp, n);
3163075e8d6Sjtc #endif
317*ffe34450Schristos 	(void)tcdrain(fd);
3183075e8d6Sjtc 	t3000_nap();
3193075e8d6Sjtc 	for ( ; n-- ; cp++) {
320*ffe34450Schristos 		(void)write(fd, cp, 1);
321*ffe34450Schristos 		(void)tcdrain(fd);
3223075e8d6Sjtc 		t3000_nap();
3233075e8d6Sjtc 	}
3243075e8d6Sjtc }
3253075e8d6Sjtc 
3263075e8d6Sjtc #ifdef DEBUG
t3000_verbose_read(void)32758c2151fSperry t3000_verbose_read(void)
3283075e8d6Sjtc {
3293075e8d6Sjtc 	int n = 0;
3303075e8d6Sjtc 	char buf[BUFSIZ];
3313075e8d6Sjtc 
3323075e8d6Sjtc 	if (ioctl(FD, FIONREAD, &n) < 0)
3333075e8d6Sjtc 		return;
3343075e8d6Sjtc 	if (n <= 0)
3353075e8d6Sjtc 		return;
3363075e8d6Sjtc 	if (read(FD, buf, n) != n)
3373075e8d6Sjtc 		return;
338*ffe34450Schristos 	(void)write(1, buf, n);
3393075e8d6Sjtc }
3403075e8d6Sjtc #endif
3413075e8d6Sjtc 
3424dadb162Schristos #define setsa(sa, a) \
343*ffe34450Schristos 	sa.sa_handler = a; (void)sigemptyset(&sa.sa_mask); sa.sa_flags = 0
3443075e8d6Sjtc 
3459de74469Smrg static int napms = 50; /* Give the t3000 50 milliseconds between characters */
3463075e8d6Sjtc 
3473075e8d6Sjtc static int ringring;
3483075e8d6Sjtc 
3494dadb162Schristos void
t3000_nap(void)35058c2151fSperry t3000_nap(void)
3513075e8d6Sjtc {
3523075e8d6Sjtc 
3533075e8d6Sjtc 	struct itimerval itv, oitv;
354e37283e1Slukem 	struct itimerval *itp = &itv;
3554dadb162Schristos 	struct sigaction sa, osa;
3564dadb162Schristos 	sigset_t sm, osm;
3573075e8d6Sjtc 
3583075e8d6Sjtc 	timerclear(&itp->it_interval);
3593075e8d6Sjtc 	timerclear(&itp->it_value);
3603075e8d6Sjtc 	if (setitimer(ITIMER_REAL, itp, &oitv) < 0)
3613075e8d6Sjtc 		return;
3624dadb162Schristos 
363*ffe34450Schristos 	(void)sigemptyset(&sm);
364*ffe34450Schristos 	(void)sigaddset(&sm, SIGALRM);
3654dadb162Schristos 	(void)sigprocmask(SIG_BLOCK, &sm, &osm);
3664dadb162Schristos 
3673075e8d6Sjtc 	itp->it_value.tv_sec = napms/1000;
3683075e8d6Sjtc 	itp->it_value.tv_usec = ((napms%1000)*1000);
3694dadb162Schristos 
3704dadb162Schristos 	setsa(sa, t3000_napx);
3714dadb162Schristos 	(void)sigaction(SIGALRM, &sa, &osa);
3724dadb162Schristos 
3734dadb162Schristos 	(void)setitimer(ITIMER_REAL, itp, NULL);
3744dadb162Schristos 
3754dadb162Schristos 	sm = osm;
376*ffe34450Schristos 	(void)sigdelset(&sm, SIGALRM);
3774dadb162Schristos 
3784dadb162Schristos 	for (ringring = 0; !ringring; )
379*ffe34450Schristos 		(void)sigsuspend(&sm);
3804dadb162Schristos 
3814dadb162Schristos 	(void)sigaction(SIGALRM, &osa, NULL);
3824dadb162Schristos 	(void)setitimer(ITIMER_REAL, &oitv, NULL);
3834dadb162Schristos 	(void)sigprocmask(SIG_SETMASK, &osm, NULL);
3843075e8d6Sjtc }
3853075e8d6Sjtc 
3863075e8d6Sjtc static void
387*ffe34450Schristos /*ARGSUSED*/
t3000_napx(int dummy __unused)388*ffe34450Schristos t3000_napx(int dummy __unused)
3893075e8d6Sjtc {
39097eafd50Smrg 
3913075e8d6Sjtc         ringring = 1;
3923075e8d6Sjtc }
393