10f3bdf5dSMark Murray /* $OpenBSD: t3000.c,v 1.9 2001/10/24 18:38:58 millert Exp $ */ 20f3bdf5dSMark Murray /* $NetBSD: t3000.c,v 1.5 1997/02/11 09:24:18 mrg Exp $ */ 30f3bdf5dSMark Murray 40f3bdf5dSMark Murray /* 50f3bdf5dSMark Murray * Copyright (c) 1992, 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[] = "@(#)t3000.c 8.1 (Berkeley) 6/6/93"; 400f3bdf5dSMark Murray #endif 410f3bdf5dSMark Murray static char rcsid[] = "$OpenBSD: t3000.c,v 1.9 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 Telebit T3000 modem. 460f3bdf5dSMark Murray * Derived from Courier driver. 470f3bdf5dSMark Murray */ 480f3bdf5dSMark Murray #include "tip.h" 490f3bdf5dSMark Murray 500f3bdf5dSMark Murray #include <sys/ioctl.h> 510f3bdf5dSMark Murray #include <stdio.h> 520f3bdf5dSMark Murray 530f3bdf5dSMark Murray #define MAXRETRY 5 540f3bdf5dSMark Murray 550f3bdf5dSMark Murray static void sigALRM(); 560f3bdf5dSMark Murray static int timeout = 0; 570f3bdf5dSMark Murray static int connected = 0; 580f3bdf5dSMark Murray static jmp_buf timeoutbuf, intbuf; 590f3bdf5dSMark Murray static int t3000_sync(), t3000_connect(), t3000_swallow(); 600f3bdf5dSMark Murray static void t3000_nap(); 610f3bdf5dSMark Murray 620f3bdf5dSMark Murray int 630f3bdf5dSMark Murray t3000_dialer(num, acu) 640f3bdf5dSMark Murray char *num; 650f3bdf5dSMark Murray char *acu; 660f3bdf5dSMark Murray { 670f3bdf5dSMark Murray char *cp; 680f3bdf5dSMark Murray struct termios cntrl; 690f3bdf5dSMark Murray #ifdef ACULOG 700f3bdf5dSMark Murray char line[80]; 710f3bdf5dSMark Murray #endif 720f3bdf5dSMark Murray 730f3bdf5dSMark Murray if (boolean(value(VERBOSE))) 740f3bdf5dSMark Murray printf("Using \"%s\"\n", acu); 750f3bdf5dSMark Murray 760f3bdf5dSMark Murray tcgetattr(FD, &cntrl); 770f3bdf5dSMark Murray cntrl.c_cflag |= HUPCL; 780f3bdf5dSMark Murray tcsetattr(FD, TCSANOW, &cntrl); 790f3bdf5dSMark Murray /* 800f3bdf5dSMark Murray * Get in synch. 810f3bdf5dSMark Murray */ 820f3bdf5dSMark Murray if (!t3000_sync()) { 830f3bdf5dSMark Murray badsynch: 840f3bdf5dSMark Murray printf("can't synchronize with t3000\n"); 850f3bdf5dSMark Murray #ifdef ACULOG 860f3bdf5dSMark Murray logent(value(HOST), num, "t3000", "can't synch up"); 870f3bdf5dSMark Murray #endif 880f3bdf5dSMark Murray return (0); 890f3bdf5dSMark Murray } 900f3bdf5dSMark Murray t3000_write(FD, "AT E0\r", 6); /* turn off echoing */ 910f3bdf5dSMark Murray sleep(1); 920f3bdf5dSMark Murray #ifdef DEBUG 930f3bdf5dSMark Murray if (boolean(value(VERBOSE))) 940f3bdf5dSMark Murray t3000_verbose_read(); 950f3bdf5dSMark Murray #endif 960f3bdf5dSMark Murray tcflush(FD, TCIOFLUSH); 970f3bdf5dSMark Murray t3000_write(FD, "AT E0 H0 Q0 X4 V1\r", 18); 980f3bdf5dSMark Murray if (!t3000_swallow("\r\nOK\r\n")) 990f3bdf5dSMark Murray goto badsynch; 1000f3bdf5dSMark Murray fflush(stdout); 1010f3bdf5dSMark Murray t3000_write(FD, "AT D", 4); 1020f3bdf5dSMark Murray for (cp = num; *cp; cp++) 1030f3bdf5dSMark Murray if (*cp == '=') 1040f3bdf5dSMark Murray *cp = ','; 1050f3bdf5dSMark Murray t3000_write(FD, num, strlen(num)); 1060f3bdf5dSMark Murray t3000_write(FD, "\r", 1); 1070f3bdf5dSMark Murray connected = t3000_connect(); 1080f3bdf5dSMark Murray #ifdef ACULOG 1090f3bdf5dSMark Murray if (timeout) { 1100f3bdf5dSMark Murray (void)sprintf(line, "%ld second dial timeout", 1110f3bdf5dSMark Murray number(value(DIALTIMEOUT))); 1120f3bdf5dSMark Murray logent(value(HOST), num, "t3000", line); 1130f3bdf5dSMark Murray } 1140f3bdf5dSMark Murray #endif 1150f3bdf5dSMark Murray if (timeout) 1160f3bdf5dSMark Murray t3000_disconnect(); 1170f3bdf5dSMark Murray return (connected); 1180f3bdf5dSMark Murray } 1190f3bdf5dSMark Murray 1200f3bdf5dSMark Murray void 1210f3bdf5dSMark Murray t3000_disconnect() 1220f3bdf5dSMark Murray { 1230f3bdf5dSMark Murray /* first hang up the modem*/ 1240f3bdf5dSMark Murray ioctl(FD, TIOCCDTR, 0); 1250f3bdf5dSMark Murray sleep(1); 1260f3bdf5dSMark Murray ioctl(FD, TIOCSDTR, 0); 1270f3bdf5dSMark Murray t3000_sync(); /* reset */ 1280f3bdf5dSMark Murray close(FD); 1290f3bdf5dSMark Murray } 1300f3bdf5dSMark Murray 1310f3bdf5dSMark Murray void 1320f3bdf5dSMark Murray t3000_abort() 1330f3bdf5dSMark Murray { 1340f3bdf5dSMark Murray t3000_write(FD, "\r", 1); /* send anything to abort the call */ 1350f3bdf5dSMark Murray t3000_disconnect(); 1360f3bdf5dSMark Murray } 1370f3bdf5dSMark Murray 1380f3bdf5dSMark Murray static void 1390f3bdf5dSMark Murray sigALRM() 1400f3bdf5dSMark Murray { 1410f3bdf5dSMark Murray printf("\07timeout waiting for reply\n"); 1420f3bdf5dSMark Murray timeout = 1; 1430f3bdf5dSMark Murray longjmp(timeoutbuf, 1); 1440f3bdf5dSMark Murray } 1450f3bdf5dSMark Murray 1460f3bdf5dSMark Murray static int 1470f3bdf5dSMark Murray t3000_swallow(match) 1480f3bdf5dSMark Murray char *match; 1490f3bdf5dSMark Murray { 1500f3bdf5dSMark Murray sig_t f; 1510f3bdf5dSMark Murray char c; 1520f3bdf5dSMark Murray 1530f3bdf5dSMark Murray f = signal(SIGALRM, sigALRM); 1540f3bdf5dSMark Murray timeout = 0; 1550f3bdf5dSMark Murray do { 1560f3bdf5dSMark Murray if (*match =='\0') { 1570f3bdf5dSMark Murray signal(SIGALRM, f); 1580f3bdf5dSMark Murray return (1); 1590f3bdf5dSMark Murray } 1600f3bdf5dSMark Murray if (setjmp(timeoutbuf)) { 1610f3bdf5dSMark Murray signal(SIGALRM, f); 1620f3bdf5dSMark Murray return (0); 1630f3bdf5dSMark Murray } 1640f3bdf5dSMark Murray alarm(number(value(DIALTIMEOUT))); 1650f3bdf5dSMark Murray read(FD, &c, 1); 1660f3bdf5dSMark Murray alarm(0); 1670f3bdf5dSMark Murray c &= 0177; 1680f3bdf5dSMark Murray #ifdef DEBUG 1690f3bdf5dSMark Murray if (boolean(value(VERBOSE))) 1700f3bdf5dSMark Murray putchar(c); 1710f3bdf5dSMark Murray #endif 1720f3bdf5dSMark Murray } while (c == *match++); 1730f3bdf5dSMark Murray #ifdef DEBUG 1740f3bdf5dSMark Murray if (boolean(value(VERBOSE))) 1750f3bdf5dSMark Murray fflush(stdout); 1760f3bdf5dSMark Murray #endif 1770f3bdf5dSMark Murray signal(SIGALRM, SIG_DFL); 1780f3bdf5dSMark Murray return (0); 1790f3bdf5dSMark Murray } 1800f3bdf5dSMark Murray 1810f3bdf5dSMark Murray #ifndef B19200 /* XXX */ 1820f3bdf5dSMark Murray #define B19200 EXTA 1830f3bdf5dSMark Murray #define B38400 EXTB 1840f3bdf5dSMark Murray #endif 1850f3bdf5dSMark Murray 1860f3bdf5dSMark Murray struct tbaud_msg { 1870f3bdf5dSMark Murray char *msg; 1880f3bdf5dSMark Murray int baud; 1890f3bdf5dSMark Murray int baud2; 1900f3bdf5dSMark Murray } tbaud_msg[] = { 1910f3bdf5dSMark Murray "", B300, 0, 1920f3bdf5dSMark Murray " 1200", B1200, 0, 1930f3bdf5dSMark Murray " 2400", B2400, 0, 1940f3bdf5dSMark Murray " 4800", B4800, 0, 1950f3bdf5dSMark Murray " 9600", B9600, 0, 1960f3bdf5dSMark Murray " 14400", B19200, B9600, 1970f3bdf5dSMark Murray " 19200", B19200, B9600, 1980f3bdf5dSMark Murray " 38400", B38400, B9600, 1990f3bdf5dSMark Murray " 57600", B38400, B9600, 2000f3bdf5dSMark Murray " 7512", B9600, 0, 2010f3bdf5dSMark Murray " 1275", B2400, 0, 2020f3bdf5dSMark Murray " 7200", B9600, 0, 2030f3bdf5dSMark Murray " 12000", B19200, B9600, 2040f3bdf5dSMark Murray 0, 0, 0, 2050f3bdf5dSMark Murray }; 2060f3bdf5dSMark Murray 2070f3bdf5dSMark Murray static int 2080f3bdf5dSMark Murray t3000_connect() 2090f3bdf5dSMark Murray { 2100f3bdf5dSMark Murray char c; 2110f3bdf5dSMark Murray int nc, nl, n; 2120f3bdf5dSMark Murray char dialer_buf[64]; 2130f3bdf5dSMark Murray struct tbaud_msg *bm; 2140f3bdf5dSMark Murray sig_t f; 2150f3bdf5dSMark Murray 2160f3bdf5dSMark Murray if (t3000_swallow("\r\n") == 0) 2170f3bdf5dSMark Murray return (0); 2180f3bdf5dSMark Murray f = signal(SIGALRM, sigALRM); 2190f3bdf5dSMark Murray again: 2200f3bdf5dSMark Murray nc = 0; nl = sizeof(dialer_buf)-1; 2210f3bdf5dSMark Murray bzero(dialer_buf, sizeof(dialer_buf)); 2220f3bdf5dSMark Murray timeout = 0; 2230f3bdf5dSMark Murray for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) { 2240f3bdf5dSMark Murray if (setjmp(timeoutbuf)) 2250f3bdf5dSMark Murray break; 2260f3bdf5dSMark Murray alarm(number(value(DIALTIMEOUT))); 2270f3bdf5dSMark Murray n = read(FD, &c, 1); 2280f3bdf5dSMark Murray alarm(0); 2290f3bdf5dSMark Murray if (n <= 0) 2300f3bdf5dSMark Murray break; 2310f3bdf5dSMark Murray c &= 0x7f; 2320f3bdf5dSMark Murray if (c == '\r') { 2330f3bdf5dSMark Murray if (t3000_swallow("\n") == 0) 2340f3bdf5dSMark Murray break; 2350f3bdf5dSMark Murray if (!dialer_buf[0]) 2360f3bdf5dSMark Murray goto again; 2370f3bdf5dSMark Murray if (strcmp(dialer_buf, "RINGING") == 0 && 2380f3bdf5dSMark Murray boolean(value(VERBOSE))) { 2390f3bdf5dSMark Murray #ifdef DEBUG 2400f3bdf5dSMark Murray printf("%s\r\n", dialer_buf); 2410f3bdf5dSMark Murray #endif 2420f3bdf5dSMark Murray goto again; 2430f3bdf5dSMark Murray } 2440f3bdf5dSMark Murray if (strncmp(dialer_buf, "CONNECT", 2450f3bdf5dSMark Murray sizeof("CONNECT")-1) != 0) 2460f3bdf5dSMark Murray break; 2470f3bdf5dSMark Murray for (bm = tbaud_msg ; bm->msg ; bm++) 2480f3bdf5dSMark Murray if (strcmp(bm->msg, 2490f3bdf5dSMark Murray dialer_buf+sizeof("CONNECT")-1) == 0) { 2500f3bdf5dSMark Murray struct termios cntrl; 2510f3bdf5dSMark Murray 2520f3bdf5dSMark Murray tcgetattr(FD, &cntrl); 2530f3bdf5dSMark Murray cfsetospeed(&cntrl, bm->baud); 2540f3bdf5dSMark Murray cfsetispeed(&cntrl, bm->baud); 2550f3bdf5dSMark Murray tcsetattr(FD, TCSAFLUSH, &cntrl); 2560f3bdf5dSMark Murray signal(SIGALRM, f); 2570f3bdf5dSMark Murray #ifdef DEBUG 2580f3bdf5dSMark Murray if (boolean(value(VERBOSE))) 2590f3bdf5dSMark Murray printf("%s\r\n", dialer_buf); 2600f3bdf5dSMark Murray #endif 2610f3bdf5dSMark Murray return (1); 2620f3bdf5dSMark Murray } 2630f3bdf5dSMark Murray break; 2640f3bdf5dSMark Murray } 2650f3bdf5dSMark Murray dialer_buf[nc] = c; 2660f3bdf5dSMark Murray #ifdef notdef 2670f3bdf5dSMark Murray if (boolean(value(VERBOSE))) 2680f3bdf5dSMark Murray putchar(c); 2690f3bdf5dSMark Murray #endif 2700f3bdf5dSMark Murray } 2710f3bdf5dSMark Murray printf("%s\r\n", dialer_buf); 2720f3bdf5dSMark Murray signal(SIGALRM, f); 2730f3bdf5dSMark Murray return (0); 2740f3bdf5dSMark Murray } 2750f3bdf5dSMark Murray 2760f3bdf5dSMark Murray /* 2770f3bdf5dSMark Murray * This convoluted piece of code attempts to get 2780f3bdf5dSMark Murray * the t3000 in sync. 2790f3bdf5dSMark Murray */ 2800f3bdf5dSMark Murray static int 2810f3bdf5dSMark Murray t3000_sync() 2820f3bdf5dSMark Murray { 2830f3bdf5dSMark Murray int already = 0; 2840f3bdf5dSMark Murray int len; 2850f3bdf5dSMark Murray char buf[40]; 2860f3bdf5dSMark Murray 2870f3bdf5dSMark Murray while (already++ < MAXRETRY) { 2880f3bdf5dSMark Murray tcflush(FD, TCIOFLUSH); 2890f3bdf5dSMark Murray t3000_write(FD, "\rAT Z\r", 6); /* reset modem */ 2900f3bdf5dSMark Murray bzero(buf, sizeof(buf)); 2910f3bdf5dSMark Murray sleep(2); 2920f3bdf5dSMark Murray ioctl(FD, FIONREAD, &len); 2930f3bdf5dSMark Murray #if 1 2940f3bdf5dSMark Murray if (len == 0) len = 1; 2950f3bdf5dSMark Murray #endif 2960f3bdf5dSMark Murray if (len) { 2970f3bdf5dSMark Murray len = read(FD, buf, sizeof(buf)); 2980f3bdf5dSMark Murray #ifdef DEBUG 2990f3bdf5dSMark Murray buf[len] = '\0'; 3000f3bdf5dSMark Murray printf("t3000_sync: (\"%s\")\n\r", buf); 3010f3bdf5dSMark Murray #endif 3020f3bdf5dSMark Murray if (strchr(buf, '0') || 3030f3bdf5dSMark Murray (strchr(buf, 'O') && strchr(buf, 'K'))) 3040f3bdf5dSMark Murray return(1); 3050f3bdf5dSMark Murray } 3060f3bdf5dSMark Murray /* 3070f3bdf5dSMark Murray * If not strapped for DTR control, 3080f3bdf5dSMark Murray * try to get command mode. 3090f3bdf5dSMark Murray */ 3100f3bdf5dSMark Murray sleep(1); 3110f3bdf5dSMark Murray t3000_write(FD, "+++", 3); 3120f3bdf5dSMark Murray sleep(1); 3130f3bdf5dSMark Murray /* 3140f3bdf5dSMark Murray * Toggle DTR to force anyone off that might have left 3150f3bdf5dSMark Murray * the modem connected. 3160f3bdf5dSMark Murray */ 3170f3bdf5dSMark Murray ioctl(FD, TIOCCDTR, 0); 3180f3bdf5dSMark Murray sleep(1); 3190f3bdf5dSMark Murray ioctl(FD, TIOCSDTR, 0); 3200f3bdf5dSMark Murray } 3210f3bdf5dSMark Murray t3000_write(FD, "\rAT Z\r", 6); 3220f3bdf5dSMark Murray return (0); 3230f3bdf5dSMark Murray } 3240f3bdf5dSMark Murray 3250f3bdf5dSMark Murray static int 3260f3bdf5dSMark Murray t3000_write(fd, cp, n) 3270f3bdf5dSMark Murray int fd; 3280f3bdf5dSMark Murray char *cp; 3290f3bdf5dSMark Murray int n; 3300f3bdf5dSMark Murray { 3310f3bdf5dSMark Murray #ifdef notdef 3320f3bdf5dSMark Murray if (boolean(value(VERBOSE))) 3330f3bdf5dSMark Murray write(1, cp, n); 3340f3bdf5dSMark Murray #endif 3350f3bdf5dSMark Murray tcdrain(fd); 3360f3bdf5dSMark Murray t3000_nap(); 3370f3bdf5dSMark Murray for ( ; n-- ; cp++) { 3380f3bdf5dSMark Murray write(fd, cp, 1); 3390f3bdf5dSMark Murray tcdrain(fd); 3400f3bdf5dSMark Murray t3000_nap(); 3410f3bdf5dSMark Murray } 3420f3bdf5dSMark Murray } 3430f3bdf5dSMark Murray 3440f3bdf5dSMark Murray #ifdef DEBUG 3450f3bdf5dSMark Murray t3000_verbose_read() 3460f3bdf5dSMark Murray { 3470f3bdf5dSMark Murray int n = 0; 3480f3bdf5dSMark Murray char buf[BUFSIZ]; 3490f3bdf5dSMark Murray 3500f3bdf5dSMark Murray if (ioctl(FD, FIONREAD, &n) < 0) 3510f3bdf5dSMark Murray return; 3520f3bdf5dSMark Murray if (n <= 0) 3530f3bdf5dSMark Murray return; 3540f3bdf5dSMark Murray if (read(FD, buf, n) != n) 3550f3bdf5dSMark Murray return; 3560f3bdf5dSMark Murray write(1, buf, n); 3570f3bdf5dSMark Murray } 3580f3bdf5dSMark Murray #endif 3590f3bdf5dSMark Murray 3600f3bdf5dSMark Murray /* Give the t3000 50 milliseconds between characters */ 3610f3bdf5dSMark Murray void 3620f3bdf5dSMark Murray t3000_nap() 3630f3bdf5dSMark Murray { 3640f3bdf5dSMark Murray struct timespec ts; 3650f3bdf5dSMark Murray 3660f3bdf5dSMark Murray ts.tv_sec = 0; 3670f3bdf5dSMark Murray ts.tv_nsec = 50 * 1000000; 3680f3bdf5dSMark Murray 3690f3bdf5dSMark Murray nanosleep(&ts, NULL); 3700f3bdf5dSMark Murray } 371