xref: /freebsd/usr.bin/tip/libacu/hayes.c (revision 0f3bdf5df978c1d74d4b5e0429ced9613debcc3c)
10f3bdf5dSMark Murray /*	$OpenBSD: hayes.c,v 1.8 2001/10/24 18:38:58 millert Exp $	*/
20f3bdf5dSMark Murray /*	$NetBSD: hayes.c,v 1.6 1997/02/11 09:24:17 mrg Exp $	*/
30f3bdf5dSMark Murray 
40f3bdf5dSMark Murray /*
50f3bdf5dSMark Murray  * Copyright (c) 1983, 1993
60f3bdf5dSMark Murray  *	The Regents of the University of California.  All rights reserved.
70f3bdf5dSMark Murray  *
80f3bdf5dSMark Murray  * Redistribution and use in source and binary forms, with or without
90f3bdf5dSMark Murray  * modification, are permitted provided that the following conditions
100f3bdf5dSMark Murray  * are met:
110f3bdf5dSMark Murray  * 1. Redistributions of source code must retain the above copyright
120f3bdf5dSMark Murray  *    notice, this list of conditions and the following disclaimer.
130f3bdf5dSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
140f3bdf5dSMark Murray  *    notice, this list of conditions and the following disclaimer in the
150f3bdf5dSMark Murray  *    documentation and/or other materials provided with the distribution.
160f3bdf5dSMark Murray  * 3. All advertising materials mentioning features or use of this software
170f3bdf5dSMark Murray  *    must display the following acknowledgement:
180f3bdf5dSMark Murray  *	This product includes software developed by the University of
190f3bdf5dSMark Murray  *	California, Berkeley and its contributors.
200f3bdf5dSMark Murray  * 4. Neither the name of the University nor the names of its contributors
210f3bdf5dSMark Murray  *    may be used to endorse or promote products derived from this software
220f3bdf5dSMark Murray  *    without specific prior written permission.
230f3bdf5dSMark Murray  *
240f3bdf5dSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
250f3bdf5dSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
260f3bdf5dSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
270f3bdf5dSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
280f3bdf5dSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
290f3bdf5dSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
300f3bdf5dSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
310f3bdf5dSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
320f3bdf5dSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
330f3bdf5dSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
340f3bdf5dSMark Murray  * SUCH DAMAGE.
350f3bdf5dSMark Murray  */
360f3bdf5dSMark Murray 
370f3bdf5dSMark Murray #ifndef lint
380f3bdf5dSMark Murray #if 0
390f3bdf5dSMark Murray static char sccsid[] = "@(#)hayes.c	8.1 (Berkeley) 6/6/93";
400f3bdf5dSMark Murray #endif
410f3bdf5dSMark Murray static char rcsid[] = "$OpenBSD: hayes.c,v 1.8 2001/10/24 18:38:58 millert Exp $";
420f3bdf5dSMark Murray #endif /* not lint */
430f3bdf5dSMark Murray 
440f3bdf5dSMark Murray /*
450f3bdf5dSMark Murray  * Routines for calling up on a Hayes Modem
460f3bdf5dSMark Murray  * (based on the old VenTel driver).
470f3bdf5dSMark Murray  * The modem is expected to be strapped for "echo".
480f3bdf5dSMark Murray  * Also, the switches enabling the DTR and CD lines
490f3bdf5dSMark Murray  * must be set correctly.
500f3bdf5dSMark Murray  * NOTICE:
510f3bdf5dSMark Murray  * The easy way to hang up a modem is always simply to
520f3bdf5dSMark Murray  * clear the DTR signal. However, if the +++ sequence
530f3bdf5dSMark Murray  * (which switches the modem back to local mode) is sent
540f3bdf5dSMark Murray  * before modem is hung up, removal of the DTR signal
550f3bdf5dSMark Murray  * has no effect (except that it prevents the modem from
560f3bdf5dSMark Murray  * recognizing commands).
570f3bdf5dSMark Murray  * (by Helge Skrivervik, Calma Company, Sunnyvale, CA. 1984)
580f3bdf5dSMark Murray  */
590f3bdf5dSMark Murray /*
600f3bdf5dSMark Murray  * TODO:
610f3bdf5dSMark Murray  * It is probably not a good idea to switch the modem
620f3bdf5dSMark Murray  * state between 'verbose' and terse (status messages).
630f3bdf5dSMark Murray  * This should be kicked out and we should use verbose
640f3bdf5dSMark Murray  * mode only. This would make it consistent with normal
650f3bdf5dSMark Murray  * interactive use thru the command 'tip dialer'.
660f3bdf5dSMark Murray  */
670f3bdf5dSMark Murray #include "tip.h"
680f3bdf5dSMark Murray 
690f3bdf5dSMark Murray #include <termios.h>
700f3bdf5dSMark Murray #include <sys/ioctl.h>
710f3bdf5dSMark Murray 
720f3bdf5dSMark Murray #define	min(a,b)	((a < b) ? a : b)
730f3bdf5dSMark Murray 
740f3bdf5dSMark Murray static	void sigALRM();
750f3bdf5dSMark Murray static	int timeout = 0;
760f3bdf5dSMark Murray static	jmp_buf timeoutbuf;
770f3bdf5dSMark Murray static 	char gobble();
780f3bdf5dSMark Murray #define DUMBUFLEN	40
790f3bdf5dSMark Murray static char dumbuf[DUMBUFLEN];
800f3bdf5dSMark Murray 
810f3bdf5dSMark Murray #define	DIALING		1
820f3bdf5dSMark Murray #define IDLE		2
830f3bdf5dSMark Murray #define CONNECTED	3
840f3bdf5dSMark Murray #define	FAILED		4
850f3bdf5dSMark Murray static	int state = IDLE;
860f3bdf5dSMark Murray 
870f3bdf5dSMark Murray int
880f3bdf5dSMark Murray hay_dialer(num, acu)
890f3bdf5dSMark Murray 	char *num;
900f3bdf5dSMark Murray 	char *acu;
910f3bdf5dSMark Murray {
920f3bdf5dSMark Murray 	char *cp;
930f3bdf5dSMark Murray 	int connected = 0;
940f3bdf5dSMark Murray 	char dummy;
950f3bdf5dSMark Murray 	struct termios cntrl;
960f3bdf5dSMark Murray #ifdef ACULOG
970f3bdf5dSMark Murray 	char line[80];
980f3bdf5dSMark Murray #endif
990f3bdf5dSMark Murray 	if (hay_sync() == 0)		/* make sure we can talk to the modem */
1000f3bdf5dSMark Murray 		return(0);
1010f3bdf5dSMark Murray 	if (boolean(value(VERBOSE)))
1020f3bdf5dSMark Murray 		printf("\ndialing...");
1030f3bdf5dSMark Murray 	fflush(stdout);
1040f3bdf5dSMark Murray 	tcgetattr(FD, &cntrl);
1050f3bdf5dSMark Murray 	cntrl.c_cflag |= HUPCL;
1060f3bdf5dSMark Murray 	tcsetattr(FD, TCSANOW, &cntrl);
1070f3bdf5dSMark Murray 	tcflush(FD, TCIOFLUSH);
1080f3bdf5dSMark Murray 	write(FD, "ATv0\r", 5);	/* tell modem to use short status codes */
1090f3bdf5dSMark Murray 	gobble("\r");
1100f3bdf5dSMark Murray 	gobble("\r");
1110f3bdf5dSMark Murray 	write(FD, "ATTD", 4);	/* send dial command */
1120f3bdf5dSMark Murray 	for (cp = num; *cp; cp++)
1130f3bdf5dSMark Murray 		if (*cp == '=')
1140f3bdf5dSMark Murray 			*cp = ',';
1150f3bdf5dSMark Murray 	write(FD, num, strlen(num));
1160f3bdf5dSMark Murray 	state = DIALING;
1170f3bdf5dSMark Murray 	write(FD, "\r", 1);
1180f3bdf5dSMark Murray 	connected = 0;
1190f3bdf5dSMark Murray 	if (gobble("\r")) {
1200f3bdf5dSMark Murray 		if ((dummy = gobble("01234")) != '1')
1210f3bdf5dSMark Murray 			error_rep(dummy);
1220f3bdf5dSMark Murray 		else
1230f3bdf5dSMark Murray 			connected = 1;
1240f3bdf5dSMark Murray 	}
1250f3bdf5dSMark Murray 	if (connected)
1260f3bdf5dSMark Murray 		state = CONNECTED;
1270f3bdf5dSMark Murray 	else {
1280f3bdf5dSMark Murray 		state = FAILED;
1290f3bdf5dSMark Murray 		return (connected);	/* lets get out of here.. */
1300f3bdf5dSMark Murray 	}
1310f3bdf5dSMark Murray 	tcflush(FD, TCIOFLUSH);
1320f3bdf5dSMark Murray #ifdef ACULOG
1330f3bdf5dSMark Murray 	if (timeout) {
1340f3bdf5dSMark Murray 		(void)sprintf(line, "%ld second dial timeout",
1350f3bdf5dSMark Murray 			number(value(DIALTIMEOUT)));
1360f3bdf5dSMark Murray 		logent(value(HOST), num, "hayes", line);
1370f3bdf5dSMark Murray 	}
1380f3bdf5dSMark Murray #endif
1390f3bdf5dSMark Murray 	if (timeout)
1400f3bdf5dSMark Murray 		hay_disconnect();	/* insurance */
1410f3bdf5dSMark Murray 	return (connected);
1420f3bdf5dSMark Murray }
1430f3bdf5dSMark Murray 
1440f3bdf5dSMark Murray 
1450f3bdf5dSMark Murray void
1460f3bdf5dSMark Murray hay_disconnect()
1470f3bdf5dSMark Murray {
1480f3bdf5dSMark Murray 	/* first hang up the modem*/
1490f3bdf5dSMark Murray #ifdef DEBUG
1500f3bdf5dSMark Murray 	printf("\rdisconnecting modem....\n\r");
1510f3bdf5dSMark Murray #endif
1520f3bdf5dSMark Murray 	ioctl(FD, TIOCCDTR, 0);
1530f3bdf5dSMark Murray 	sleep(1);
1540f3bdf5dSMark Murray 	ioctl(FD, TIOCSDTR, 0);
1550f3bdf5dSMark Murray 	goodbye();
1560f3bdf5dSMark Murray }
1570f3bdf5dSMark Murray 
1580f3bdf5dSMark Murray void
1590f3bdf5dSMark Murray hay_abort()
1600f3bdf5dSMark Murray {
1610f3bdf5dSMark Murray 
1620f3bdf5dSMark Murray 	write(FD, "\r", 1);	/* send anything to abort the call */
1630f3bdf5dSMark Murray 	hay_disconnect();
1640f3bdf5dSMark Murray }
1650f3bdf5dSMark Murray 
1660f3bdf5dSMark Murray static void
1670f3bdf5dSMark Murray sigALRM()
1680f3bdf5dSMark Murray {
1690f3bdf5dSMark Murray 
1700f3bdf5dSMark Murray 	printf("\07timeout waiting for reply\n\r");
1710f3bdf5dSMark Murray 	timeout = 1;
1720f3bdf5dSMark Murray 	longjmp(timeoutbuf, 1);
1730f3bdf5dSMark Murray }
1740f3bdf5dSMark Murray 
1750f3bdf5dSMark Murray static char
1760f3bdf5dSMark Murray gobble(match)
1770f3bdf5dSMark Murray 	char *match;
1780f3bdf5dSMark Murray {
1790f3bdf5dSMark Murray 	char c;
1800f3bdf5dSMark Murray 	sig_t f;
1810f3bdf5dSMark Murray 	int i, status = 0;
1820f3bdf5dSMark Murray 
1830f3bdf5dSMark Murray 	f = signal(SIGALRM, sigALRM);
1840f3bdf5dSMark Murray 	timeout = 0;
1850f3bdf5dSMark Murray #ifdef DEBUG
1860f3bdf5dSMark Murray 	printf("\ngobble: waiting for %s\n", match);
1870f3bdf5dSMark Murray #endif
1880f3bdf5dSMark Murray 	do {
1890f3bdf5dSMark Murray 		if (setjmp(timeoutbuf)) {
1900f3bdf5dSMark Murray 			signal(SIGALRM, f);
1910f3bdf5dSMark Murray 			return (0);
1920f3bdf5dSMark Murray 		}
1930f3bdf5dSMark Murray 		alarm(number(value(DIALTIMEOUT)));
1940f3bdf5dSMark Murray 		read(FD, &c, 1);
1950f3bdf5dSMark Murray 		alarm(0);
1960f3bdf5dSMark Murray 		c &= 0177;
1970f3bdf5dSMark Murray #ifdef DEBUG
1980f3bdf5dSMark Murray 		printf("%c 0x%x ", c, c);
1990f3bdf5dSMark Murray #endif
2000f3bdf5dSMark Murray 		for (i = 0; i < strlen(match); i++)
2010f3bdf5dSMark Murray 			if (c == match[i])
2020f3bdf5dSMark Murray 				status = c;
2030f3bdf5dSMark Murray 	} while (status == 0);
2040f3bdf5dSMark Murray 	signal(SIGALRM, SIG_DFL);
2050f3bdf5dSMark Murray #ifdef DEBUG
2060f3bdf5dSMark Murray 	printf("\n");
2070f3bdf5dSMark Murray #endif
2080f3bdf5dSMark Murray 	return (status);
2090f3bdf5dSMark Murray }
2100f3bdf5dSMark Murray 
2110f3bdf5dSMark Murray static void
2120f3bdf5dSMark Murray error_rep(c)
2130f3bdf5dSMark Murray 	char c;
2140f3bdf5dSMark Murray {
2150f3bdf5dSMark Murray 	printf("\n\r");
2160f3bdf5dSMark Murray 	switch (c) {
2170f3bdf5dSMark Murray 
2180f3bdf5dSMark Murray 	case '0':
2190f3bdf5dSMark Murray 		printf("OK");
2200f3bdf5dSMark Murray 		break;
2210f3bdf5dSMark Murray 
2220f3bdf5dSMark Murray 	case '1':
2230f3bdf5dSMark Murray 		printf("CONNECT");
2240f3bdf5dSMark Murray 		break;
2250f3bdf5dSMark Murray 
2260f3bdf5dSMark Murray 	case '2':
2270f3bdf5dSMark Murray 		printf("RING");
2280f3bdf5dSMark Murray 		break;
2290f3bdf5dSMark Murray 
2300f3bdf5dSMark Murray 	case '3':
2310f3bdf5dSMark Murray 		printf("NO CARRIER");
2320f3bdf5dSMark Murray 		break;
2330f3bdf5dSMark Murray 
2340f3bdf5dSMark Murray 	case '4':
2350f3bdf5dSMark Murray 		printf("ERROR in input");
2360f3bdf5dSMark Murray 		break;
2370f3bdf5dSMark Murray 
2380f3bdf5dSMark Murray 	case '5':
2390f3bdf5dSMark Murray 		printf("CONNECT 1200");
2400f3bdf5dSMark Murray 		break;
2410f3bdf5dSMark Murray 
2420f3bdf5dSMark Murray 	default:
2430f3bdf5dSMark Murray 		printf("Unknown Modem error: %c (0x%x)", c, c);
2440f3bdf5dSMark Murray 	}
2450f3bdf5dSMark Murray 	printf("\n\r");
2460f3bdf5dSMark Murray 	return;
2470f3bdf5dSMark Murray }
2480f3bdf5dSMark Murray 
2490f3bdf5dSMark Murray /*
2500f3bdf5dSMark Murray  * set modem back to normal verbose status codes.
2510f3bdf5dSMark Murray  */
2520f3bdf5dSMark Murray void
2530f3bdf5dSMark Murray goodbye()
2540f3bdf5dSMark Murray {
2550f3bdf5dSMark Murray 	int len;
2560f3bdf5dSMark Murray 	char c;
2570f3bdf5dSMark Murray 
2580f3bdf5dSMark Murray 	tcflush(FD, TCIOFLUSH);
2590f3bdf5dSMark Murray 	if (hay_sync()) {
2600f3bdf5dSMark Murray 		sleep(1);
2610f3bdf5dSMark Murray #ifndef DEBUG
2620f3bdf5dSMark Murray 		tcflush(FD, TCIOFLUSH);
2630f3bdf5dSMark Murray #endif
2640f3bdf5dSMark Murray 		write(FD, "ATH0\r", 5);		/* insurance */
2650f3bdf5dSMark Murray #ifndef DEBUG
2660f3bdf5dSMark Murray 		c = gobble("03");
2670f3bdf5dSMark Murray 		if (c != '0' && c != '3') {
2680f3bdf5dSMark Murray 			printf("cannot hang up modem\n\r");
2690f3bdf5dSMark Murray 			printf("please use 'tip dialer' to make sure the line is hung up\n\r");
2700f3bdf5dSMark Murray 		}
2710f3bdf5dSMark Murray #endif
2720f3bdf5dSMark Murray 		sleep(1);
2730f3bdf5dSMark Murray 		ioctl(FD, FIONREAD, &len);
2740f3bdf5dSMark Murray #ifdef DEBUG
2750f3bdf5dSMark Murray 		printf("goodbye1: len=%d -- ", len);
2760f3bdf5dSMark Murray 		rlen = read(FD, dumbuf, min(len, DUMBUFLEN));
2770f3bdf5dSMark Murray 		dumbuf[rlen] = '\0';
2780f3bdf5dSMark Murray 		printf("read (%d): %s\r\n", rlen, dumbuf);
2790f3bdf5dSMark Murray #endif
2800f3bdf5dSMark Murray 		write(FD, "ATv1\r", 5);
2810f3bdf5dSMark Murray 		sleep(1);
2820f3bdf5dSMark Murray #ifdef DEBUG
2830f3bdf5dSMark Murray 		ioctl(FD, FIONREAD, &len);
2840f3bdf5dSMark Murray 		printf("goodbye2: len=%d -- ", len);
2850f3bdf5dSMark Murray 		rlen = read(FD, dumbuf, min(len, DUMBUFLEN));
2860f3bdf5dSMark Murray 		dumbuf[rlen] = '\0';
2870f3bdf5dSMark Murray 		printf("read (%d): %s\r\n", rlen, dumbuf);
2880f3bdf5dSMark Murray #endif
2890f3bdf5dSMark Murray 	}
2900f3bdf5dSMark Murray 	tcflush(FD, TCIOFLUSH);
2910f3bdf5dSMark Murray 	ioctl(FD, TIOCCDTR, 0);		/* clear DTR (insurance) */
2920f3bdf5dSMark Murray 	close(FD);
2930f3bdf5dSMark Murray }
2940f3bdf5dSMark Murray 
2950f3bdf5dSMark Murray #define MAXRETRY	5
2960f3bdf5dSMark Murray 
2970f3bdf5dSMark Murray int
2980f3bdf5dSMark Murray hay_sync()
2990f3bdf5dSMark Murray {
3000f3bdf5dSMark Murray 	int len, retry = 0;
3010f3bdf5dSMark Murray 
3020f3bdf5dSMark Murray 	while (retry++ <= MAXRETRY) {
3030f3bdf5dSMark Murray 		write(FD, "AT\r", 3);
3040f3bdf5dSMark Murray 		sleep(1);
3050f3bdf5dSMark Murray 		ioctl(FD, FIONREAD, &len);
3060f3bdf5dSMark Murray 		if (len) {
3070f3bdf5dSMark Murray 			len = read(FD, dumbuf, min(len, DUMBUFLEN));
3080f3bdf5dSMark Murray 			if (strchr(dumbuf, '0') ||
3090f3bdf5dSMark Murray 		   	(strchr(dumbuf, 'O') && strchr(dumbuf, 'K')))
3100f3bdf5dSMark Murray 				return(1);
3110f3bdf5dSMark Murray #ifdef DEBUG
3120f3bdf5dSMark Murray 			dumbuf[len] = '\0';
3130f3bdf5dSMark Murray 			printf("hay_sync: (\"%s\") %d\n\r", dumbuf, retry);
3140f3bdf5dSMark Murray #endif
3150f3bdf5dSMark Murray 		}
3160f3bdf5dSMark Murray 		ioctl(FD, TIOCCDTR, 0);
3170f3bdf5dSMark Murray 		ioctl(FD, TIOCSDTR, 0);
3180f3bdf5dSMark Murray 	}
3190f3bdf5dSMark Murray 	printf("Cannot synchronize with hayes...\n\r");
3200f3bdf5dSMark Murray 	return(0);
3210f3bdf5dSMark Murray }
322