1*59674Shibler /* 2*59674Shibler * Copyright (c) 1992 The Regents of the University of California. 3*59674Shibler * All rights reserved. 4*59674Shibler * 5*59674Shibler * %sccs.include.redist.c% 6*59674Shibler */ 7*59674Shibler 8*59674Shibler #ifndef lint 9*59674Shibler static char sccsid[] = "@(#)t3000.c 5.1 (Berkeley) 05/03/93"; 10*59674Shibler #endif /* not lint */ 11*59674Shibler 12*59674Shibler /* 13*59674Shibler * Routines for calling up on a Telebit T3000 modem. 14*59674Shibler * Derived from Courier driver. 15*59674Shibler */ 16*59674Shibler #include "tip.h" 17*59674Shibler #include <stdio.h> 18*59674Shibler 19*59674Shibler #define MAXRETRY 5 20*59674Shibler 21*59674Shibler static void sigALRM(); 22*59674Shibler static int timeout = 0; 23*59674Shibler static int connected = 0; 24*59674Shibler static jmp_buf timeoutbuf, intbuf; 25*59674Shibler static int t3000_sync(); 26*59674Shibler 27*59674Shibler t3000_dialer(num, acu) 28*59674Shibler register char *num; 29*59674Shibler char *acu; 30*59674Shibler { 31*59674Shibler register char *cp; 32*59674Shibler #ifdef ACULOG 33*59674Shibler char line[80]; 34*59674Shibler #endif 35*59674Shibler static int t3000_connect(), t3000_swallow(); 36*59674Shibler 37*59674Shibler if (boolean(value(VERBOSE))) 38*59674Shibler printf("Using \"%s\"\n", acu); 39*59674Shibler 40*59674Shibler ioctl(FD, TIOCHPCL, 0); 41*59674Shibler /* 42*59674Shibler * Get in synch. 43*59674Shibler */ 44*59674Shibler if (!t3000_sync()) { 45*59674Shibler badsynch: 46*59674Shibler printf("can't synchronize with t3000\n"); 47*59674Shibler #ifdef ACULOG 48*59674Shibler logent(value(HOST), num, "t3000", "can't synch up"); 49*59674Shibler #endif 50*59674Shibler return (0); 51*59674Shibler } 52*59674Shibler t3000_write(FD, "AT E0\r", 6); /* turn off echoing */ 53*59674Shibler sleep(1); 54*59674Shibler #ifdef DEBUG 55*59674Shibler if (boolean(value(VERBOSE))) 56*59674Shibler t3000_verbose_read(); 57*59674Shibler #endif 58*59674Shibler ioctl(FD, TIOCFLUSH, 0); /* flush any clutter */ 59*59674Shibler t3000_write(FD, "AT E0 H0 Q0 X4 V1\r", 18); 60*59674Shibler if (!t3000_swallow("\r\nOK\r\n")) 61*59674Shibler goto badsynch; 62*59674Shibler fflush(stdout); 63*59674Shibler t3000_write(FD, "AT D", 4); 64*59674Shibler for (cp = num; *cp; cp++) 65*59674Shibler if (*cp == '=') 66*59674Shibler *cp = ','; 67*59674Shibler t3000_write(FD, num, strlen(num)); 68*59674Shibler t3000_write(FD, "\r", 1); 69*59674Shibler connected = t3000_connect(); 70*59674Shibler #ifdef ACULOG 71*59674Shibler if (timeout) { 72*59674Shibler sprintf(line, "%d second dial timeout", 73*59674Shibler number(value(DIALTIMEOUT))); 74*59674Shibler logent(value(HOST), num, "t3000", line); 75*59674Shibler } 76*59674Shibler #endif 77*59674Shibler if (timeout) 78*59674Shibler t3000_disconnect(); 79*59674Shibler return (connected); 80*59674Shibler } 81*59674Shibler 82*59674Shibler t3000_disconnect() 83*59674Shibler { 84*59674Shibler /* first hang up the modem*/ 85*59674Shibler ioctl(FD, TIOCCDTR, 0); 86*59674Shibler sleep(1); 87*59674Shibler ioctl(FD, TIOCSDTR, 0); 88*59674Shibler t3000_sync(); /* reset */ 89*59674Shibler close(FD); 90*59674Shibler } 91*59674Shibler 92*59674Shibler t3000_abort() 93*59674Shibler { 94*59674Shibler t3000_write(FD, "\r", 1); /* send anything to abort the call */ 95*59674Shibler t3000_disconnect(); 96*59674Shibler } 97*59674Shibler 98*59674Shibler static void 99*59674Shibler sigALRM() 100*59674Shibler { 101*59674Shibler printf("\07timeout waiting for reply\n"); 102*59674Shibler timeout = 1; 103*59674Shibler longjmp(timeoutbuf, 1); 104*59674Shibler } 105*59674Shibler 106*59674Shibler static int 107*59674Shibler t3000_swallow(match) 108*59674Shibler register char *match; 109*59674Shibler { 110*59674Shibler sig_t f; 111*59674Shibler char c; 112*59674Shibler 113*59674Shibler f = signal(SIGALRM, sigALRM); 114*59674Shibler timeout = 0; 115*59674Shibler do { 116*59674Shibler if (*match =='\0') { 117*59674Shibler signal(SIGALRM, f); 118*59674Shibler return (1); 119*59674Shibler } 120*59674Shibler if (setjmp(timeoutbuf)) { 121*59674Shibler signal(SIGALRM, f); 122*59674Shibler return (0); 123*59674Shibler } 124*59674Shibler alarm(number(value(DIALTIMEOUT))); 125*59674Shibler read(FD, &c, 1); 126*59674Shibler alarm(0); 127*59674Shibler c &= 0177; 128*59674Shibler #ifdef DEBUG 129*59674Shibler if (boolean(value(VERBOSE))) 130*59674Shibler putchar(c); 131*59674Shibler #endif 132*59674Shibler } while (c == *match++); 133*59674Shibler #ifdef DEBUG 134*59674Shibler if (boolean(value(VERBOSE))) 135*59674Shibler fflush(stdout); 136*59674Shibler #endif 137*59674Shibler signal(SIGALRM, SIG_DFL); 138*59674Shibler return (0); 139*59674Shibler } 140*59674Shibler 141*59674Shibler #ifndef B19200 /* XXX */ 142*59674Shibler #define B19200 EXTA 143*59674Shibler #define B38400 EXTB 144*59674Shibler #endif 145*59674Shibler 146*59674Shibler struct tbaud_msg { 147*59674Shibler char *msg; 148*59674Shibler int baud; 149*59674Shibler int baud2; 150*59674Shibler } tbaud_msg[] = { 151*59674Shibler "", B300, 0, 152*59674Shibler " 1200", B1200, 0, 153*59674Shibler " 2400", B2400, 0, 154*59674Shibler " 4800", B4800, 0, 155*59674Shibler " 9600", B9600, 0, 156*59674Shibler " 14400", B19200, B9600, 157*59674Shibler " 19200", B19200, B9600, 158*59674Shibler " 38400", B38400, B9600, 159*59674Shibler " 57600", B38400, B9600, 160*59674Shibler " 7512", B9600, 0, 161*59674Shibler " 1275", B2400, 0, 162*59674Shibler " 7200", B9600, 0, 163*59674Shibler " 12000", B19200, B9600, 164*59674Shibler 0, 0, 0, 165*59674Shibler }; 166*59674Shibler 167*59674Shibler static int 168*59674Shibler t3000_connect() 169*59674Shibler { 170*59674Shibler char c; 171*59674Shibler int nc, nl, n; 172*59674Shibler struct sgttyb sb; 173*59674Shibler char dialer_buf[64]; 174*59674Shibler struct tbaud_msg *bm; 175*59674Shibler sig_t f; 176*59674Shibler 177*59674Shibler if (t3000_swallow("\r\n") == 0) 178*59674Shibler return (0); 179*59674Shibler f = signal(SIGALRM, sigALRM); 180*59674Shibler again: 181*59674Shibler nc = 0; nl = sizeof(dialer_buf)-1; 182*59674Shibler bzero(dialer_buf, sizeof(dialer_buf)); 183*59674Shibler timeout = 0; 184*59674Shibler for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) { 185*59674Shibler if (setjmp(timeoutbuf)) 186*59674Shibler break; 187*59674Shibler alarm(number(value(DIALTIMEOUT))); 188*59674Shibler n = read(FD, &c, 1); 189*59674Shibler alarm(0); 190*59674Shibler if (n <= 0) 191*59674Shibler break; 192*59674Shibler c &= 0x7f; 193*59674Shibler if (c == '\r') { 194*59674Shibler if (t3000_swallow("\n") == 0) 195*59674Shibler break; 196*59674Shibler if (!dialer_buf[0]) 197*59674Shibler goto again; 198*59674Shibler if (strcmp(dialer_buf, "RINGING") == 0 && 199*59674Shibler boolean(value(VERBOSE))) { 200*59674Shibler #ifdef DEBUG 201*59674Shibler printf("%s\r\n", dialer_buf); 202*59674Shibler #endif 203*59674Shibler goto again; 204*59674Shibler } 205*59674Shibler if (strncmp(dialer_buf, "CONNECT", 206*59674Shibler sizeof("CONNECT")-1) != 0) 207*59674Shibler break; 208*59674Shibler for (bm = tbaud_msg ; bm->msg ; bm++) 209*59674Shibler if (strcmp(bm->msg, 210*59674Shibler dialer_buf+sizeof("CONNECT")-1) == 0) { 211*59674Shibler if (ioctl(FD, TIOCGETP, &sb) < 0) { 212*59674Shibler perror("TIOCGETP"); 213*59674Shibler goto error; 214*59674Shibler } 215*59674Shibler sb.sg_ispeed = sb.sg_ospeed = bm->baud; 216*59674Shibler if (ioctl(FD, TIOCSETP, &sb) < 0) { 217*59674Shibler if (bm->baud2) { 218*59674Shibler sb.sg_ispeed = 219*59674Shibler sb.sg_ospeed = 220*59674Shibler bm->baud2; 221*59674Shibler if (ioctl(FD, 222*59674Shibler TIOCSETP, 223*59674Shibler &sb) >= 0) 224*59674Shibler goto isok; 225*59674Shibler } 226*59674Shibler perror("TIOCSETP"); 227*59674Shibler goto error; 228*59674Shibler } 229*59674Shibler isok: 230*59674Shibler signal(SIGALRM, f); 231*59674Shibler #ifdef DEBUG 232*59674Shibler if (boolean(value(VERBOSE))) 233*59674Shibler printf("%s\r\n", dialer_buf); 234*59674Shibler #endif 235*59674Shibler return (1); 236*59674Shibler } 237*59674Shibler break; 238*59674Shibler } 239*59674Shibler dialer_buf[nc] = c; 240*59674Shibler #ifdef notdef 241*59674Shibler if (boolean(value(VERBOSE))) 242*59674Shibler putchar(c); 243*59674Shibler #endif 244*59674Shibler } 245*59674Shibler error1: 246*59674Shibler printf("%s\r\n", dialer_buf); 247*59674Shibler error: 248*59674Shibler signal(SIGALRM, f); 249*59674Shibler return (0); 250*59674Shibler } 251*59674Shibler 252*59674Shibler /* 253*59674Shibler * This convoluted piece of code attempts to get 254*59674Shibler * the t3000 in sync. 255*59674Shibler */ 256*59674Shibler static int 257*59674Shibler t3000_sync() 258*59674Shibler { 259*59674Shibler int already = 0; 260*59674Shibler int len; 261*59674Shibler char buf[40]; 262*59674Shibler 263*59674Shibler while (already++ < MAXRETRY) { 264*59674Shibler ioctl(FD, TIOCFLUSH, 0); /* flush any clutter */ 265*59674Shibler t3000_write(FD, "\rAT Z\r", 6); /* reset modem */ 266*59674Shibler bzero(buf, sizeof(buf)); 267*59674Shibler sleep(2); 268*59674Shibler ioctl(FD, FIONREAD, &len); 269*59674Shibler #if 1 270*59674Shibler if (len == 0) len = 1; 271*59674Shibler #endif 272*59674Shibler if (len) { 273*59674Shibler len = read(FD, buf, sizeof(buf)); 274*59674Shibler #ifdef DEBUG 275*59674Shibler buf[len] = '\0'; 276*59674Shibler printf("t3000_sync: (\"%s\")\n\r", buf); 277*59674Shibler #endif 278*59674Shibler if (index(buf, '0') || 279*59674Shibler (index(buf, 'O') && index(buf, 'K'))) 280*59674Shibler return(1); 281*59674Shibler } 282*59674Shibler /* 283*59674Shibler * If not strapped for DTR control, 284*59674Shibler * try to get command mode. 285*59674Shibler */ 286*59674Shibler sleep(1); 287*59674Shibler t3000_write(FD, "+++", 3); 288*59674Shibler sleep(1); 289*59674Shibler /* 290*59674Shibler * Toggle DTR to force anyone off that might have left 291*59674Shibler * the modem connected. 292*59674Shibler */ 293*59674Shibler ioctl(FD, TIOCCDTR, 0); 294*59674Shibler sleep(1); 295*59674Shibler ioctl(FD, TIOCSDTR, 0); 296*59674Shibler } 297*59674Shibler t3000_write(FD, "\rAT Z\r", 6); 298*59674Shibler return (0); 299*59674Shibler } 300*59674Shibler 301*59674Shibler t3000_write(fd, cp, n) 302*59674Shibler int fd; 303*59674Shibler char *cp; 304*59674Shibler int n; 305*59674Shibler { 306*59674Shibler struct sgttyb sb; 307*59674Shibler 308*59674Shibler #ifdef notdef 309*59674Shibler if (boolean(value(VERBOSE))) 310*59674Shibler write(1, cp, n); 311*59674Shibler #endif 312*59674Shibler ioctl(fd, TIOCGETP, &sb); 313*59674Shibler ioctl(fd, TIOCSETP, &sb); 314*59674Shibler t3000_nap(); 315*59674Shibler for ( ; n-- ; cp++) { 316*59674Shibler write(fd, cp, 1); 317*59674Shibler ioctl(fd, TIOCGETP, &sb); 318*59674Shibler ioctl(fd, TIOCSETP, &sb); 319*59674Shibler t3000_nap(); 320*59674Shibler } 321*59674Shibler } 322*59674Shibler 323*59674Shibler #ifdef DEBUG 324*59674Shibler t3000_verbose_read() 325*59674Shibler { 326*59674Shibler int n = 0; 327*59674Shibler char buf[BUFSIZ]; 328*59674Shibler 329*59674Shibler if (ioctl(FD, FIONREAD, &n) < 0) 330*59674Shibler return; 331*59674Shibler if (n <= 0) 332*59674Shibler return; 333*59674Shibler if (read(FD, buf, n) != n) 334*59674Shibler return; 335*59674Shibler write(1, buf, n); 336*59674Shibler } 337*59674Shibler #endif 338*59674Shibler 339*59674Shibler /* 340*59674Shibler * Code stolen from /usr/src/lib/libc/gen/sleep.c 341*59674Shibler */ 342*59674Shibler #define mask(s) (1<<((s)-1)) 343*59674Shibler #define setvec(vec, a) \ 344*59674Shibler vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0 345*59674Shibler 346*59674Shibler static napms = 50; /* Give the t3000 50 milliseconds between characters */ 347*59674Shibler 348*59674Shibler static int ringring; 349*59674Shibler 350*59674Shibler t3000_nap() 351*59674Shibler { 352*59674Shibler 353*59674Shibler static void t3000_napx(); 354*59674Shibler int omask; 355*59674Shibler struct itimerval itv, oitv; 356*59674Shibler register struct itimerval *itp = &itv; 357*59674Shibler struct sigvec vec, ovec; 358*59674Shibler 359*59674Shibler timerclear(&itp->it_interval); 360*59674Shibler timerclear(&itp->it_value); 361*59674Shibler if (setitimer(ITIMER_REAL, itp, &oitv) < 0) 362*59674Shibler return; 363*59674Shibler setvec(ovec, SIG_DFL); 364*59674Shibler omask = sigblock(mask(SIGALRM)); 365*59674Shibler itp->it_value.tv_sec = napms/1000; 366*59674Shibler itp->it_value.tv_usec = ((napms%1000)*1000); 367*59674Shibler setvec(vec, t3000_napx); 368*59674Shibler ringring = 0; 369*59674Shibler (void) sigvec(SIGALRM, &vec, &ovec); 370*59674Shibler (void) setitimer(ITIMER_REAL, itp, (struct itimerval *)0); 371*59674Shibler while (!ringring) 372*59674Shibler sigpause(omask &~ mask(SIGALRM)); 373*59674Shibler (void) sigvec(SIGALRM, &ovec, (struct sigvec *)0); 374*59674Shibler (void) setitimer(ITIMER_REAL, &oitv, (struct itimerval *)0); 375*59674Shibler (void) sigsetmask(omask); 376*59674Shibler } 377*59674Shibler 378*59674Shibler static void 379*59674Shibler t3000_napx() 380*59674Shibler { 381*59674Shibler ringring = 1; 382*59674Shibler } 383