Home | History | Annotate | Line # | Download | only in aculib
t3000.c revision 1.11
      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