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