159674Shibler /*
2*62317Sbostic * Copyright (c) 1992, 1993
3*62317Sbostic * The Regents of the University of California. All rights reserved.
459674Shibler *
559674Shibler * %sccs.include.redist.c%
659674Shibler */
759674Shibler
859674Shibler #ifndef lint
9*62317Sbostic static char sccsid[] = "@(#)t3000.c 8.1 (Berkeley) 06/06/93";
1059674Shibler #endif /* not lint */
1159674Shibler
1259674Shibler /*
1359674Shibler * Routines for calling up on a Telebit T3000 modem.
1459674Shibler * Derived from Courier driver.
1559674Shibler */
1659674Shibler #include "tip.h"
1759674Shibler #include <stdio.h>
1859674Shibler
1959674Shibler #define MAXRETRY 5
2059674Shibler
2159674Shibler static void sigALRM();
2259674Shibler static int timeout = 0;
2359674Shibler static int connected = 0;
2459674Shibler static jmp_buf timeoutbuf, intbuf;
2559674Shibler static int t3000_sync();
2659674Shibler
t3000_dialer(num,acu)2759674Shibler t3000_dialer(num, acu)
2859674Shibler register char *num;
2959674Shibler char *acu;
3059674Shibler {
3159674Shibler register char *cp;
3259674Shibler #ifdef ACULOG
3359674Shibler char line[80];
3459674Shibler #endif
3559674Shibler static int t3000_connect(), t3000_swallow();
3659674Shibler
3759674Shibler if (boolean(value(VERBOSE)))
3859674Shibler printf("Using \"%s\"\n", acu);
3959674Shibler
4059674Shibler ioctl(FD, TIOCHPCL, 0);
4159674Shibler /*
4259674Shibler * Get in synch.
4359674Shibler */
4459674Shibler if (!t3000_sync()) {
4559674Shibler badsynch:
4659674Shibler printf("can't synchronize with t3000\n");
4759674Shibler #ifdef ACULOG
4859674Shibler logent(value(HOST), num, "t3000", "can't synch up");
4959674Shibler #endif
5059674Shibler return (0);
5159674Shibler }
5259674Shibler t3000_write(FD, "AT E0\r", 6); /* turn off echoing */
5359674Shibler sleep(1);
5459674Shibler #ifdef DEBUG
5559674Shibler if (boolean(value(VERBOSE)))
5659674Shibler t3000_verbose_read();
5759674Shibler #endif
5859674Shibler ioctl(FD, TIOCFLUSH, 0); /* flush any clutter */
5959674Shibler t3000_write(FD, "AT E0 H0 Q0 X4 V1\r", 18);
6059674Shibler if (!t3000_swallow("\r\nOK\r\n"))
6159674Shibler goto badsynch;
6259674Shibler fflush(stdout);
6359674Shibler t3000_write(FD, "AT D", 4);
6459674Shibler for (cp = num; *cp; cp++)
6559674Shibler if (*cp == '=')
6659674Shibler *cp = ',';
6759674Shibler t3000_write(FD, num, strlen(num));
6859674Shibler t3000_write(FD, "\r", 1);
6959674Shibler connected = t3000_connect();
7059674Shibler #ifdef ACULOG
7159674Shibler if (timeout) {
7259674Shibler sprintf(line, "%d second dial timeout",
7359674Shibler number(value(DIALTIMEOUT)));
7459674Shibler logent(value(HOST), num, "t3000", line);
7559674Shibler }
7659674Shibler #endif
7759674Shibler if (timeout)
7859674Shibler t3000_disconnect();
7959674Shibler return (connected);
8059674Shibler }
8159674Shibler
t3000_disconnect()8259674Shibler t3000_disconnect()
8359674Shibler {
8459674Shibler /* first hang up the modem*/
8559674Shibler ioctl(FD, TIOCCDTR, 0);
8659674Shibler sleep(1);
8759674Shibler ioctl(FD, TIOCSDTR, 0);
8859674Shibler t3000_sync(); /* reset */
8959674Shibler close(FD);
9059674Shibler }
9159674Shibler
t3000_abort()9259674Shibler t3000_abort()
9359674Shibler {
9459674Shibler t3000_write(FD, "\r", 1); /* send anything to abort the call */
9559674Shibler t3000_disconnect();
9659674Shibler }
9759674Shibler
9859674Shibler static void
sigALRM()9959674Shibler sigALRM()
10059674Shibler {
10159674Shibler printf("\07timeout waiting for reply\n");
10259674Shibler timeout = 1;
10359674Shibler longjmp(timeoutbuf, 1);
10459674Shibler }
10559674Shibler
10659674Shibler static int
t3000_swallow(match)10759674Shibler t3000_swallow(match)
10859674Shibler register char *match;
10959674Shibler {
11059674Shibler sig_t f;
11159674Shibler char c;
11259674Shibler
11359674Shibler f = signal(SIGALRM, sigALRM);
11459674Shibler timeout = 0;
11559674Shibler do {
11659674Shibler if (*match =='\0') {
11759674Shibler signal(SIGALRM, f);
11859674Shibler return (1);
11959674Shibler }
12059674Shibler if (setjmp(timeoutbuf)) {
12159674Shibler signal(SIGALRM, f);
12259674Shibler return (0);
12359674Shibler }
12459674Shibler alarm(number(value(DIALTIMEOUT)));
12559674Shibler read(FD, &c, 1);
12659674Shibler alarm(0);
12759674Shibler c &= 0177;
12859674Shibler #ifdef DEBUG
12959674Shibler if (boolean(value(VERBOSE)))
13059674Shibler putchar(c);
13159674Shibler #endif
13259674Shibler } while (c == *match++);
13359674Shibler #ifdef DEBUG
13459674Shibler if (boolean(value(VERBOSE)))
13559674Shibler fflush(stdout);
13659674Shibler #endif
13759674Shibler signal(SIGALRM, SIG_DFL);
13859674Shibler return (0);
13959674Shibler }
14059674Shibler
14159674Shibler #ifndef B19200 /* XXX */
14259674Shibler #define B19200 EXTA
14359674Shibler #define B38400 EXTB
14459674Shibler #endif
14559674Shibler
14659674Shibler struct tbaud_msg {
14759674Shibler char *msg;
14859674Shibler int baud;
14959674Shibler int baud2;
15059674Shibler } tbaud_msg[] = {
15159674Shibler "", B300, 0,
15259674Shibler " 1200", B1200, 0,
15359674Shibler " 2400", B2400, 0,
15459674Shibler " 4800", B4800, 0,
15559674Shibler " 9600", B9600, 0,
15659674Shibler " 14400", B19200, B9600,
15759674Shibler " 19200", B19200, B9600,
15859674Shibler " 38400", B38400, B9600,
15959674Shibler " 57600", B38400, B9600,
16059674Shibler " 7512", B9600, 0,
16159674Shibler " 1275", B2400, 0,
16259674Shibler " 7200", B9600, 0,
16359674Shibler " 12000", B19200, B9600,
16459674Shibler 0, 0, 0,
16559674Shibler };
16659674Shibler
16759674Shibler static int
t3000_connect()16859674Shibler t3000_connect()
16959674Shibler {
17059674Shibler char c;
17159674Shibler int nc, nl, n;
17259674Shibler struct sgttyb sb;
17359674Shibler char dialer_buf[64];
17459674Shibler struct tbaud_msg *bm;
17559674Shibler sig_t f;
17659674Shibler
17759674Shibler if (t3000_swallow("\r\n") == 0)
17859674Shibler return (0);
17959674Shibler f = signal(SIGALRM, sigALRM);
18059674Shibler again:
18159674Shibler nc = 0; nl = sizeof(dialer_buf)-1;
18259674Shibler bzero(dialer_buf, sizeof(dialer_buf));
18359674Shibler timeout = 0;
18459674Shibler for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) {
18559674Shibler if (setjmp(timeoutbuf))
18659674Shibler break;
18759674Shibler alarm(number(value(DIALTIMEOUT)));
18859674Shibler n = read(FD, &c, 1);
18959674Shibler alarm(0);
19059674Shibler if (n <= 0)
19159674Shibler break;
19259674Shibler c &= 0x7f;
19359674Shibler if (c == '\r') {
19459674Shibler if (t3000_swallow("\n") == 0)
19559674Shibler break;
19659674Shibler if (!dialer_buf[0])
19759674Shibler goto again;
19859674Shibler if (strcmp(dialer_buf, "RINGING") == 0 &&
19959674Shibler boolean(value(VERBOSE))) {
20059674Shibler #ifdef DEBUG
20159674Shibler printf("%s\r\n", dialer_buf);
20259674Shibler #endif
20359674Shibler goto again;
20459674Shibler }
20559674Shibler if (strncmp(dialer_buf, "CONNECT",
20659674Shibler sizeof("CONNECT")-1) != 0)
20759674Shibler break;
20859674Shibler for (bm = tbaud_msg ; bm->msg ; bm++)
20959674Shibler if (strcmp(bm->msg,
21059674Shibler dialer_buf+sizeof("CONNECT")-1) == 0) {
21159674Shibler if (ioctl(FD, TIOCGETP, &sb) < 0) {
21259674Shibler perror("TIOCGETP");
21359674Shibler goto error;
21459674Shibler }
21559674Shibler sb.sg_ispeed = sb.sg_ospeed = bm->baud;
21659674Shibler if (ioctl(FD, TIOCSETP, &sb) < 0) {
21759674Shibler if (bm->baud2) {
21859674Shibler sb.sg_ispeed =
21959674Shibler sb.sg_ospeed =
22059674Shibler bm->baud2;
22159674Shibler if (ioctl(FD,
22259674Shibler TIOCSETP,
22359674Shibler &sb) >= 0)
22459674Shibler goto isok;
22559674Shibler }
22659674Shibler perror("TIOCSETP");
22759674Shibler goto error;
22859674Shibler }
22959674Shibler isok:
23059674Shibler signal(SIGALRM, f);
23159674Shibler #ifdef DEBUG
23259674Shibler if (boolean(value(VERBOSE)))
23359674Shibler printf("%s\r\n", dialer_buf);
23459674Shibler #endif
23559674Shibler return (1);
23659674Shibler }
23759674Shibler break;
23859674Shibler }
23959674Shibler dialer_buf[nc] = c;
24059674Shibler #ifdef notdef
24159674Shibler if (boolean(value(VERBOSE)))
24259674Shibler putchar(c);
24359674Shibler #endif
24459674Shibler }
24559674Shibler error1:
24659674Shibler printf("%s\r\n", dialer_buf);
24759674Shibler error:
24859674Shibler signal(SIGALRM, f);
24959674Shibler return (0);
25059674Shibler }
25159674Shibler
25259674Shibler /*
25359674Shibler * This convoluted piece of code attempts to get
25459674Shibler * the t3000 in sync.
25559674Shibler */
25659674Shibler static int
t3000_sync()25759674Shibler t3000_sync()
25859674Shibler {
25959674Shibler int already = 0;
26059674Shibler int len;
26159674Shibler char buf[40];
26259674Shibler
26359674Shibler while (already++ < MAXRETRY) {
26459674Shibler ioctl(FD, TIOCFLUSH, 0); /* flush any clutter */
26559674Shibler t3000_write(FD, "\rAT Z\r", 6); /* reset modem */
26659674Shibler bzero(buf, sizeof(buf));
26759674Shibler sleep(2);
26859674Shibler ioctl(FD, FIONREAD, &len);
26959674Shibler #if 1
27059674Shibler if (len == 0) len = 1;
27159674Shibler #endif
27259674Shibler if (len) {
27359674Shibler len = read(FD, buf, sizeof(buf));
27459674Shibler #ifdef DEBUG
27559674Shibler buf[len] = '\0';
27659674Shibler printf("t3000_sync: (\"%s\")\n\r", buf);
27759674Shibler #endif
27859674Shibler if (index(buf, '0') ||
27959674Shibler (index(buf, 'O') && index(buf, 'K')))
28059674Shibler return(1);
28159674Shibler }
28259674Shibler /*
28359674Shibler * If not strapped for DTR control,
28459674Shibler * try to get command mode.
28559674Shibler */
28659674Shibler sleep(1);
28759674Shibler t3000_write(FD, "+++", 3);
28859674Shibler sleep(1);
28959674Shibler /*
29059674Shibler * Toggle DTR to force anyone off that might have left
29159674Shibler * the modem connected.
29259674Shibler */
29359674Shibler ioctl(FD, TIOCCDTR, 0);
29459674Shibler sleep(1);
29559674Shibler ioctl(FD, TIOCSDTR, 0);
29659674Shibler }
29759674Shibler t3000_write(FD, "\rAT Z\r", 6);
29859674Shibler return (0);
29959674Shibler }
30059674Shibler
t3000_write(fd,cp,n)30159674Shibler t3000_write(fd, cp, n)
30259674Shibler int fd;
30359674Shibler char *cp;
30459674Shibler int n;
30559674Shibler {
30659674Shibler struct sgttyb sb;
30759674Shibler
30859674Shibler #ifdef notdef
30959674Shibler if (boolean(value(VERBOSE)))
31059674Shibler write(1, cp, n);
31159674Shibler #endif
31259674Shibler ioctl(fd, TIOCGETP, &sb);
31359674Shibler ioctl(fd, TIOCSETP, &sb);
31459674Shibler t3000_nap();
31559674Shibler for ( ; n-- ; cp++) {
31659674Shibler write(fd, cp, 1);
31759674Shibler ioctl(fd, TIOCGETP, &sb);
31859674Shibler ioctl(fd, TIOCSETP, &sb);
31959674Shibler t3000_nap();
32059674Shibler }
32159674Shibler }
32259674Shibler
32359674Shibler #ifdef DEBUG
t3000_verbose_read()32459674Shibler t3000_verbose_read()
32559674Shibler {
32659674Shibler int n = 0;
32759674Shibler char buf[BUFSIZ];
32859674Shibler
32959674Shibler if (ioctl(FD, FIONREAD, &n) < 0)
33059674Shibler return;
33159674Shibler if (n <= 0)
33259674Shibler return;
33359674Shibler if (read(FD, buf, n) != n)
33459674Shibler return;
33559674Shibler write(1, buf, n);
33659674Shibler }
33759674Shibler #endif
33859674Shibler
33959674Shibler /*
34059674Shibler * Code stolen from /usr/src/lib/libc/gen/sleep.c
34159674Shibler */
34259674Shibler #define mask(s) (1<<((s)-1))
34359674Shibler #define setvec(vec, a) \
34459674Shibler vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0
34559674Shibler
34659674Shibler static napms = 50; /* Give the t3000 50 milliseconds between characters */
34759674Shibler
34859674Shibler static int ringring;
34959674Shibler
t3000_nap()35059674Shibler t3000_nap()
35159674Shibler {
35259674Shibler
35359674Shibler static void t3000_napx();
35459674Shibler int omask;
35559674Shibler struct itimerval itv, oitv;
35659674Shibler register struct itimerval *itp = &itv;
35759674Shibler struct sigvec vec, ovec;
35859674Shibler
35959674Shibler timerclear(&itp->it_interval);
36059674Shibler timerclear(&itp->it_value);
36159674Shibler if (setitimer(ITIMER_REAL, itp, &oitv) < 0)
36259674Shibler return;
36359674Shibler setvec(ovec, SIG_DFL);
36459674Shibler omask = sigblock(mask(SIGALRM));
36559674Shibler itp->it_value.tv_sec = napms/1000;
36659674Shibler itp->it_value.tv_usec = ((napms%1000)*1000);
36759674Shibler setvec(vec, t3000_napx);
36859674Shibler ringring = 0;
36959674Shibler (void) sigvec(SIGALRM, &vec, &ovec);
37059674Shibler (void) setitimer(ITIMER_REAL, itp, (struct itimerval *)0);
37159674Shibler while (!ringring)
37259674Shibler sigpause(omask &~ mask(SIGALRM));
37359674Shibler (void) sigvec(SIGALRM, &ovec, (struct sigvec *)0);
37459674Shibler (void) setitimer(ITIMER_REAL, &oitv, (struct itimerval *)0);
37559674Shibler (void) sigsetmask(omask);
37659674Shibler }
37759674Shibler
37859674Shibler static void
t3000_napx()37959674Shibler t3000_napx()
38059674Shibler {
38159674Shibler ringring = 1;
38259674Shibler }
383