1161754Sru/* $OpenBSD: t3000.c,v 1.14 2006/03/17 19:17:13 moritz Exp $ */ 288276Smarkm/* $NetBSD: t3000.c,v 1.5 1997/02/11 09:24:18 mrg Exp $ */ 388276Smarkm 47527Sjkh/* 57527Sjkh * Copyright (c) 1992, 1993 67527Sjkh * The Regents of the University of California. All rights reserved. 77527Sjkh * 87527Sjkh * Redistribution and use in source and binary forms, with or without 97527Sjkh * modification, are permitted provided that the following conditions 107527Sjkh * are met: 117527Sjkh * 1. Redistributions of source code must retain the above copyright 127527Sjkh * notice, this list of conditions and the following disclaimer. 137527Sjkh * 2. Redistributions in binary form must reproduce the above copyright 147527Sjkh * notice, this list of conditions and the following disclaimer in the 157527Sjkh * documentation and/or other materials provided with the distribution. 16161754Sru * 3. Neither the name of the University nor the names of its contributors 177527Sjkh * may be used to endorse or promote products derived from this software 187527Sjkh * without specific prior written permission. 197527Sjkh * 207527Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 217527Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 227527Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 237527Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 247527Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 257527Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 267527Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 277527Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 287527Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 297527Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 307527Sjkh * SUCH DAMAGE. 317527Sjkh */ 327527Sjkh 3388276Smarkm#include <sys/cdefs.h> 3488276Smarkm__FBSDID("$FreeBSD$"); 3588276Smarkm 367527Sjkh#ifndef lint 3788276Smarkm#if 0 3888276Smarkmstatic char sccsid[] = "@(#)t3000.c 8.1 (Berkeley) 6/6/93"; 39161754Srustatic const char rcsid[] = "$OpenBSD: t3000.c,v 1.14 2006/03/17 19:17:13 moritz Exp $"; 4080381Ssheldonh#endif 4188276Smarkm#endif /* not lint */ 427527Sjkh 437527Sjkh/* 447527Sjkh * Routines for calling up on a Telebit T3000 modem. 457527Sjkh * Derived from Courier driver. 467527Sjkh */ 477527Sjkh#include "tip.h" 4888276Smarkm 4988276Smarkm#include <sys/ioctl.h> 507527Sjkh#include <stdio.h> 517527Sjkh 527527Sjkh#define MAXRETRY 5 537527Sjkh 54161754Srustatic int dialtimeout = 0; 557527Sjkhstatic int connected = 0; 56161754Srustatic jmp_buf timeoutbuf; 577527Sjkh 58161754Srustatic void sigALRM(int); 59161754Srustatic int t3000_swallow(char *); 60161754Srustatic int t3000_connect(void); 61161754Srustatic int t3000_sync(void); 62161754Srustatic void t3000_write(int, char *, int); 63161754Srustatic void t3000_nap(void); 64161754Sru#ifdef DEBUG 65161754Srustatic void t3000_verbose_read(void); 66161754Sru#endif 67161754Sru 6888276Smarkmint 69161754Srut3000_dialer(char *num, char *acu) 707527Sjkh{ 7188276Smarkm char *cp; 7288276Smarkm struct termios cntrl; 7388276Smarkm#ifdef ACULOG 747527Sjkh char line[80]; 757527Sjkh#endif 767527Sjkh 777527Sjkh if (boolean(value(VERBOSE))) 787527Sjkh printf("Using \"%s\"\n", acu); 797527Sjkh 8088276Smarkm tcgetattr(FD, &cntrl); 8188276Smarkm cntrl.c_cflag |= HUPCL; 8288276Smarkm tcsetattr(FD, TCSANOW, &cntrl); 837527Sjkh /* 847527Sjkh * Get in synch. 857527Sjkh */ 867527Sjkh if (!t3000_sync()) { 877527Sjkhbadsynch: 887527Sjkh printf("can't synchronize with t3000\n"); 8988276Smarkm#ifdef ACULOG 907527Sjkh logent(value(HOST), num, "t3000", "can't synch up"); 917527Sjkh#endif 927527Sjkh return (0); 937527Sjkh } 947527Sjkh t3000_write(FD, "AT E0\r", 6); /* turn off echoing */ 957527Sjkh sleep(1); 967527Sjkh#ifdef DEBUG 977527Sjkh if (boolean(value(VERBOSE))) 987527Sjkh t3000_verbose_read(); 997527Sjkh#endif 10088276Smarkm tcflush(FD, TCIOFLUSH); 1017527Sjkh t3000_write(FD, "AT E0 H0 Q0 X4 V1\r", 18); 1027527Sjkh if (!t3000_swallow("\r\nOK\r\n")) 1037527Sjkh goto badsynch; 1047527Sjkh fflush(stdout); 1057527Sjkh t3000_write(FD, "AT D", 4); 1067527Sjkh for (cp = num; *cp; cp++) 1077527Sjkh if (*cp == '=') 1087527Sjkh *cp = ','; 1097527Sjkh t3000_write(FD, num, strlen(num)); 1107527Sjkh t3000_write(FD, "\r", 1); 1117527Sjkh connected = t3000_connect(); 11288276Smarkm#ifdef ACULOG 113161754Sru if (dialtimeout) { 114161754Sru (void)snprintf(line, sizeof line, "%ld second dial timeout", 1157527Sjkh number(value(DIALTIMEOUT))); 1167527Sjkh logent(value(HOST), num, "t3000", line); 1177527Sjkh } 1187527Sjkh#endif 119161754Sru if (dialtimeout) 1207527Sjkh t3000_disconnect(); 1217527Sjkh return (connected); 1227527Sjkh} 1237527Sjkh 12488276Smarkmvoid 125161754Srut3000_disconnect(void) 1267527Sjkh{ 1277527Sjkh /* first hang up the modem*/ 1287527Sjkh ioctl(FD, TIOCCDTR, 0); 1297527Sjkh sleep(1); 1307527Sjkh ioctl(FD, TIOCSDTR, 0); 1317527Sjkh t3000_sync(); /* reset */ 1327527Sjkh close(FD); 1337527Sjkh} 1347527Sjkh 13588276Smarkmvoid 136161754Srut3000_abort(void) 1377527Sjkh{ 1387527Sjkh t3000_write(FD, "\r", 1); /* send anything to abort the call */ 1397527Sjkh t3000_disconnect(); 1407527Sjkh} 1417527Sjkh 142161754Sru/*ARGSUSED*/ 1437527Sjkhstatic void 144161754SrusigALRM(int signo) 1457527Sjkh{ 1467527Sjkh printf("\07timeout waiting for reply\n"); 147161754Sru dialtimeout = 1; 1487527Sjkh longjmp(timeoutbuf, 1); 1497527Sjkh} 1507527Sjkh 1517527Sjkhstatic int 152161754Srut3000_swallow(char *match) 15388276Smarkm{ 1547527Sjkh sig_t f; 1557527Sjkh char c; 1567527Sjkh 1577527Sjkh f = signal(SIGALRM, sigALRM); 158161754Sru dialtimeout = 0; 1597527Sjkh do { 1607527Sjkh if (*match =='\0') { 1617527Sjkh signal(SIGALRM, f); 1627527Sjkh return (1); 1637527Sjkh } 1647527Sjkh if (setjmp(timeoutbuf)) { 1657527Sjkh signal(SIGALRM, f); 1667527Sjkh return (0); 1677527Sjkh } 1687527Sjkh alarm(number(value(DIALTIMEOUT))); 1697527Sjkh read(FD, &c, 1); 1707527Sjkh alarm(0); 1717527Sjkh c &= 0177; 1727527Sjkh#ifdef DEBUG 1737527Sjkh if (boolean(value(VERBOSE))) 1747527Sjkh putchar(c); 1757527Sjkh#endif 1767527Sjkh } while (c == *match++); 1777527Sjkh#ifdef DEBUG 1787527Sjkh if (boolean(value(VERBOSE))) 1797527Sjkh fflush(stdout); 1807527Sjkh#endif 1817527Sjkh signal(SIGALRM, SIG_DFL); 1827527Sjkh return (0); 1837527Sjkh} 1847527Sjkh 1857527Sjkh#ifndef B19200 /* XXX */ 1867527Sjkh#define B19200 EXTA 1877527Sjkh#define B38400 EXTB 1887527Sjkh#endif 1897527Sjkh 1907527Sjkhstruct tbaud_msg { 1917527Sjkh char *msg; 1927527Sjkh int baud; 1937527Sjkh int baud2; 1947527Sjkh} tbaud_msg[] = { 195161754Sru { "", B300, 0 }, 196161754Sru { " 1200", B1200, 0 }, 197161754Sru { " 2400", B2400, 0 }, 198161754Sru { " 4800", B4800, 0 }, 199161754Sru { " 9600", B9600, 0 }, 200161754Sru { " 14400", B19200, B9600 }, 201161754Sru { " 19200", B19200, B9600 }, 202161754Sru { " 38400", B38400, B9600 }, 203161754Sru { " 57600", B38400, B9600 }, 204161754Sru { " 7512", B9600, 0 }, 205161754Sru { " 1275", B2400, 0 }, 206161754Sru { " 7200", B9600, 0 }, 207161754Sru { " 12000", B19200, B9600 }, 208161754Sru { 0, 0, 0 }, 2097527Sjkh}; 2107527Sjkh 2117527Sjkhstatic int 212161754Srut3000_connect(void) 2137527Sjkh{ 2147527Sjkh char c; 2157527Sjkh int nc, nl, n; 2167527Sjkh char dialer_buf[64]; 2177527Sjkh struct tbaud_msg *bm; 2187527Sjkh sig_t f; 2197527Sjkh 2207527Sjkh if (t3000_swallow("\r\n") == 0) 2217527Sjkh return (0); 2227527Sjkh f = signal(SIGALRM, sigALRM); 2237527Sjkhagain: 2247527Sjkh nc = 0; nl = sizeof(dialer_buf)-1; 2257527Sjkh bzero(dialer_buf, sizeof(dialer_buf)); 226161754Sru dialtimeout = 0; 2277527Sjkh for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) { 2287527Sjkh if (setjmp(timeoutbuf)) 2297527Sjkh break; 2307527Sjkh alarm(number(value(DIALTIMEOUT))); 2317527Sjkh n = read(FD, &c, 1); 2327527Sjkh alarm(0); 2337527Sjkh if (n <= 0) 2347527Sjkh break; 2357527Sjkh c &= 0x7f; 2367527Sjkh if (c == '\r') { 2377527Sjkh if (t3000_swallow("\n") == 0) 2387527Sjkh break; 2397527Sjkh if (!dialer_buf[0]) 2407527Sjkh goto again; 2417527Sjkh if (strcmp(dialer_buf, "RINGING") == 0 && 2427527Sjkh boolean(value(VERBOSE))) { 2437527Sjkh#ifdef DEBUG 2447527Sjkh printf("%s\r\n", dialer_buf); 2457527Sjkh#endif 2467527Sjkh goto again; 2477527Sjkh } 2487527Sjkh if (strncmp(dialer_buf, "CONNECT", 2497527Sjkh sizeof("CONNECT")-1) != 0) 2507527Sjkh break; 2517527Sjkh for (bm = tbaud_msg ; bm->msg ; bm++) 2527527Sjkh if (strcmp(bm->msg, 2537527Sjkh dialer_buf+sizeof("CONNECT")-1) == 0) { 25488276Smarkm struct termios cntrl; 25588276Smarkm 25688276Smarkm tcgetattr(FD, &cntrl); 25788276Smarkm cfsetospeed(&cntrl, bm->baud); 25888276Smarkm cfsetispeed(&cntrl, bm->baud); 25988276Smarkm tcsetattr(FD, TCSAFLUSH, &cntrl); 2607527Sjkh signal(SIGALRM, f); 2617527Sjkh#ifdef DEBUG 2627527Sjkh if (boolean(value(VERBOSE))) 2637527Sjkh printf("%s\r\n", dialer_buf); 2647527Sjkh#endif 2657527Sjkh return (1); 2667527Sjkh } 2677527Sjkh break; 2687527Sjkh } 2697527Sjkh dialer_buf[nc] = c; 2707527Sjkh#ifdef notdef 2717527Sjkh if (boolean(value(VERBOSE))) 2727527Sjkh putchar(c); 2737527Sjkh#endif 2747527Sjkh } 2757527Sjkh printf("%s\r\n", dialer_buf); 2767527Sjkh signal(SIGALRM, f); 2777527Sjkh return (0); 2787527Sjkh} 2797527Sjkh 2807527Sjkh/* 2817527Sjkh * This convoluted piece of code attempts to get 2827527Sjkh * the t3000 in sync. 2837527Sjkh */ 2847527Sjkhstatic int 285161754Srut3000_sync(void) 2867527Sjkh{ 2877527Sjkh int already = 0; 2887527Sjkh int len; 2897527Sjkh char buf[40]; 2907527Sjkh 2917527Sjkh while (already++ < MAXRETRY) { 29288276Smarkm tcflush(FD, TCIOFLUSH); 2937527Sjkh t3000_write(FD, "\rAT Z\r", 6); /* reset modem */ 2947527Sjkh bzero(buf, sizeof(buf)); 2957527Sjkh sleep(2); 2967527Sjkh ioctl(FD, FIONREAD, &len); 2977527Sjkh#if 1 2987527Sjkhif (len == 0) len = 1; 2997527Sjkh#endif 3007527Sjkh if (len) { 3017527Sjkh len = read(FD, buf, sizeof(buf)); 3027527Sjkh#ifdef DEBUG 3037527Sjkh buf[len] = '\0'; 3047527Sjkh printf("t3000_sync: (\"%s\")\n\r", buf); 3057527Sjkh#endif 30688276Smarkm if (strchr(buf, '0') || 30788276Smarkm (strchr(buf, 'O') && strchr(buf, 'K'))) 3087527Sjkh return(1); 3097527Sjkh } 3107527Sjkh /* 3117527Sjkh * If not strapped for DTR control, 3127527Sjkh * try to get command mode. 3137527Sjkh */ 3147527Sjkh sleep(1); 3157527Sjkh t3000_write(FD, "+++", 3); 3167527Sjkh sleep(1); 3177527Sjkh /* 3187527Sjkh * Toggle DTR to force anyone off that might have left 3197527Sjkh * the modem connected. 3207527Sjkh */ 3217527Sjkh ioctl(FD, TIOCCDTR, 0); 3227527Sjkh sleep(1); 3237527Sjkh ioctl(FD, TIOCSDTR, 0); 3247527Sjkh } 3257527Sjkh t3000_write(FD, "\rAT Z\r", 6); 3267527Sjkh return (0); 3277527Sjkh} 3287527Sjkh 329161754Srustatic void 330161754Srut3000_write(int fd, char *cp, int n) 3317527Sjkh{ 3327527Sjkh#ifdef notdef 3337527Sjkh if (boolean(value(VERBOSE))) 33488276Smarkm write(1, cp, n); 3357527Sjkh#endif 33688276Smarkm tcdrain(fd); 3377527Sjkh t3000_nap(); 3387527Sjkh for ( ; n-- ; cp++) { 3397527Sjkh write(fd, cp, 1); 34088276Smarkm tcdrain(fd); 3417527Sjkh t3000_nap(); 3427527Sjkh } 3437527Sjkh} 3447527Sjkh 3457527Sjkh#ifdef DEBUG 346161754Srustatic void 347161754Srut3000_verbose_read(void) 3487527Sjkh{ 3497527Sjkh int n = 0; 3507527Sjkh char buf[BUFSIZ]; 3517527Sjkh 3527527Sjkh if (ioctl(FD, FIONREAD, &n) < 0) 3537527Sjkh return; 3547527Sjkh if (n <= 0) 3557527Sjkh return; 3567527Sjkh if (read(FD, buf, n) != n) 3577527Sjkh return; 35888276Smarkm write(1, buf, n); 3597527Sjkh} 3607527Sjkh#endif 3617527Sjkh 36288276Smarkm/* Give the t3000 50 milliseconds between characters */ 363161754Srustatic void 364161754Srut3000_nap(void) 3657527Sjkh{ 36688276Smarkm struct timespec ts; 36788276Smarkm 36888276Smarkm ts.tv_sec = 0; 36988276Smarkm ts.tv_nsec = 50 * 1000000; 37088276Smarkm 37188276Smarkm nanosleep(&ts, NULL); 3727527Sjkh} 373