1 /* $NetBSD: t3000.c,v 1.6 1997/11/22 07:28:57 lukem Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)t3000.c 8.1 (Berkeley) 6/6/93"; 40 #endif 41 __RCSID("$NetBSD: t3000.c,v 1.6 1997/11/22 07:28:57 lukem Exp $"); 42 #endif /* not lint */ 43 44 /* 45 * Routines for calling up on a Telebit T3000 modem. 46 * Derived from Courier driver. 47 */ 48 #include "tip.h" 49 50 #define MAXRETRY 5 51 52 static int timeout = 0; 53 static int connected = 0; 54 static jmp_buf timeoutbuf; 55 56 static void sigALRM __P((int)); 57 static int t3000_connect __P((void)); 58 static void t3000_nap __P((void)); 59 static void t3000_napx __P((int)); 60 static int t3000_swallow __P((char *)); 61 static int t3000_sync __P((void)); 62 static void t3000_write __P((int, char *, int)); 63 64 int 65 t3000_dialer(num, acu) 66 char *num; 67 char *acu; 68 { 69 char *cp; 70 struct termios cntrl; 71 #ifdef ACULOG 72 char line[80]; 73 #endif 74 75 if (boolean(value(VERBOSE))) 76 printf("Using \"%s\"\n", acu); 77 78 tcgetattr(FD, &cntrl); 79 cntrl.c_cflag |= HUPCL; 80 tcsetattr(FD, TCSANOW, &cntrl); 81 /* 82 * Get in synch. 83 */ 84 if (!t3000_sync()) { 85 badsynch: 86 printf("can't synchronize with t3000\n"); 87 #ifdef ACULOG 88 logent(value(HOST), num, "t3000", "can't synch up"); 89 #endif 90 return (0); 91 } 92 t3000_write(FD, "AT E0\r", 6); /* turn off echoing */ 93 sleep(1); 94 #ifdef DEBUG 95 if (boolean(value(VERBOSE))) 96 t3000_verbose_read(); 97 #endif 98 tcflush(FD, TCIOFLUSH); 99 t3000_write(FD, "AT E0 H0 Q0 X4 V1\r", 18); 100 if (!t3000_swallow("\r\nOK\r\n")) 101 goto badsynch; 102 fflush(stdout); 103 t3000_write(FD, "AT D", 4); 104 for (cp = num; *cp; cp++) 105 if (*cp == '=') 106 *cp = ','; 107 t3000_write(FD, num, strlen(num)); 108 t3000_write(FD, "\r", 1); 109 connected = t3000_connect(); 110 #ifdef ACULOG 111 if (timeout) { 112 (void)snprintf(line, sizeof line, "%d second dial timeout", 113 (int)number(value(DIALTIMEOUT))); 114 logent(value(HOST), num, "t3000", line); 115 } 116 #endif 117 if (timeout) 118 t3000_disconnect(); 119 return (connected); 120 } 121 122 void 123 t3000_disconnect() 124 { 125 /* first hang up the modem*/ 126 ioctl(FD, TIOCCDTR, 0); 127 sleep(1); 128 ioctl(FD, TIOCSDTR, 0); 129 t3000_sync(); /* reset */ 130 close(FD); 131 } 132 133 void 134 t3000_abort() 135 { 136 t3000_write(FD, "\r", 1); /* send anything to abort the call */ 137 t3000_disconnect(); 138 } 139 140 static void 141 sigALRM(dummy) 142 int dummy; 143 { 144 printf("\07timeout waiting for reply\n"); 145 timeout = 1; 146 longjmp(timeoutbuf, 1); 147 } 148 149 static int 150 t3000_swallow(match) 151 char *match; 152 { 153 sig_t f; 154 char c; 155 156 #if __GNUC__ /* XXX pacify gcc */ 157 (void)&match; 158 #endif 159 160 f = signal(SIGALRM, sigALRM); 161 timeout = 0; 162 do { 163 if (*match =='\0') { 164 signal(SIGALRM, f); 165 return (1); 166 } 167 if (setjmp(timeoutbuf)) { 168 signal(SIGALRM, f); 169 return (0); 170 } 171 alarm(number(value(DIALTIMEOUT))); 172 read(FD, &c, 1); 173 alarm(0); 174 c &= 0177; 175 #ifdef DEBUG 176 if (boolean(value(VERBOSE))) 177 putchar(c); 178 #endif 179 } while (c == *match++); 180 #ifdef DEBUG 181 if (boolean(value(VERBOSE))) 182 fflush(stdout); 183 #endif 184 signal(SIGALRM, SIG_DFL); 185 return (0); 186 } 187 188 #ifndef B19200 /* XXX */ 189 #define B19200 EXTA 190 #define B38400 EXTB 191 #endif 192 193 struct tbaud_msg { 194 char *msg; 195 int baud; 196 int baud2; 197 } tbaud_msg[] = { 198 { "", B300, 0 }, 199 { " 1200", B1200, 0 }, 200 { " 2400", B2400, 0 }, 201 { " 4800", B4800, 0 }, 202 { " 9600", B9600, 0 }, 203 { " 14400", B19200, B9600 }, 204 { " 19200", B19200, B9600 }, 205 { " 38400", B38400, B9600 }, 206 { " 57600", B38400, B9600 }, 207 { " 7512", B9600, 0 }, 208 { " 1275", B2400, 0 }, 209 { " 7200", B9600, 0 }, 210 { " 12000", B19200, B9600 }, 211 { 0, 0, 0 }, 212 }; 213 214 static int 215 t3000_connect() 216 { 217 char c; 218 int nc, nl, n; 219 char dialer_buf[64]; 220 struct tbaud_msg *bm; 221 sig_t f; 222 223 #if __GNUC__ /* XXX pacify gcc */ 224 (void)&nc; 225 (void)&nl; 226 #endif 227 228 if (t3000_swallow("\r\n") == 0) 229 return (0); 230 f = signal(SIGALRM, sigALRM); 231 again: 232 nc = 0; nl = sizeof(dialer_buf)-1; 233 memset(dialer_buf, 0, sizeof(dialer_buf)); 234 timeout = 0; 235 for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) { 236 if (setjmp(timeoutbuf)) 237 break; 238 alarm(number(value(DIALTIMEOUT))); 239 n = read(FD, &c, 1); 240 alarm(0); 241 if (n <= 0) 242 break; 243 c &= 0x7f; 244 if (c == '\r') { 245 if (t3000_swallow("\n") == 0) 246 break; 247 if (!dialer_buf[0]) 248 goto again; 249 if (strcmp(dialer_buf, "RINGING") == 0 && 250 boolean(value(VERBOSE))) { 251 #ifdef DEBUG 252 printf("%s\r\n", dialer_buf); 253 #endif 254 goto again; 255 } 256 if (strncmp(dialer_buf, "CONNECT", 257 sizeof("CONNECT")-1) != 0) 258 break; 259 for (bm = tbaud_msg ; bm->msg ; bm++) 260 if (strcmp(bm->msg, 261 dialer_buf+sizeof("CONNECT")-1) == 0) { 262 struct termios cntrl; 263 264 tcgetattr(FD, &cntrl); 265 cfsetospeed(&cntrl, bm->baud); 266 cfsetispeed(&cntrl, bm->baud); 267 tcsetattr(FD, TCSAFLUSH, &cntrl); 268 signal(SIGALRM, f); 269 #ifdef DEBUG 270 if (boolean(value(VERBOSE))) 271 printf("%s\r\n", dialer_buf); 272 #endif 273 return (1); 274 } 275 break; 276 } 277 dialer_buf[nc] = c; 278 #ifdef notdef 279 if (boolean(value(VERBOSE))) 280 putchar(c); 281 #endif 282 } 283 printf("%s\r\n", dialer_buf); 284 signal(SIGALRM, f); 285 return (0); 286 } 287 288 /* 289 * This convoluted piece of code attempts to get 290 * the t3000 in sync. 291 */ 292 static int 293 t3000_sync() 294 { 295 int already = 0; 296 int len; 297 char buf[40]; 298 299 while (already++ < MAXRETRY) { 300 tcflush(FD, TCIOFLUSH); 301 t3000_write(FD, "\rAT Z\r", 6); /* reset modem */ 302 memset(buf, 0, sizeof(buf)); 303 sleep(2); 304 ioctl(FD, FIONREAD, &len); 305 #if 1 306 if (len == 0) len = 1; 307 #endif 308 if (len) { 309 len = read(FD, buf, sizeof(buf)); 310 #ifdef DEBUG 311 buf[len] = '\0'; 312 printf("t3000_sync: (\"%s\")\n\r", buf); 313 #endif 314 if (strchr(buf, '0') || 315 (strchr(buf, 'O') && strchr(buf, 'K'))) 316 return(1); 317 } 318 /* 319 * If not strapped for DTR control, 320 * try to get command mode. 321 */ 322 sleep(1); 323 t3000_write(FD, "+++", 3); 324 sleep(1); 325 /* 326 * Toggle DTR to force anyone off that might have left 327 * the modem connected. 328 */ 329 ioctl(FD, TIOCCDTR, 0); 330 sleep(1); 331 ioctl(FD, TIOCSDTR, 0); 332 } 333 t3000_write(FD, "\rAT Z\r", 6); 334 return (0); 335 } 336 337 static void 338 t3000_write(fd, cp, n) 339 int fd; 340 char *cp; 341 int n; 342 { 343 #ifdef notdef 344 if (boolean(value(VERBOSE))) 345 write(1, cp, n); 346 #endif 347 tcdrain(fd); 348 t3000_nap(); 349 for ( ; n-- ; cp++) { 350 write(fd, cp, 1); 351 tcdrain(fd); 352 t3000_nap(); 353 } 354 } 355 356 #ifdef DEBUG 357 t3000_verbose_read() 358 { 359 int n = 0; 360 char buf[BUFSIZ]; 361 362 if (ioctl(FD, FIONREAD, &n) < 0) 363 return; 364 if (n <= 0) 365 return; 366 if (read(FD, buf, n) != n) 367 return; 368 write(1, buf, n); 369 } 370 #endif 371 372 /* 373 * Code stolen from /usr/src/lib/libc/gen/sleep.c 374 */ 375 #define mask(s) (1<<((s)-1)) 376 #define setvec(vec, a) \ 377 vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0 378 379 static napms = 50; /* Give the t3000 50 milliseconds between characters */ 380 381 static int ringring; 382 383 static void 384 t3000_nap() 385 { 386 387 int omask; 388 struct itimerval itv, oitv; 389 struct itimerval *itp = &itv; 390 struct sigvec vec, ovec; 391 392 timerclear(&itp->it_interval); 393 timerclear(&itp->it_value); 394 if (setitimer(ITIMER_REAL, itp, &oitv) < 0) 395 return; 396 setvec(ovec, SIG_DFL); 397 omask = sigblock(mask(SIGALRM)); 398 itp->it_value.tv_sec = napms/1000; 399 itp->it_value.tv_usec = ((napms%1000)*1000); 400 setvec(vec, t3000_napx); 401 ringring = 0; 402 (void) sigvec(SIGALRM, &vec, &ovec); 403 (void) setitimer(ITIMER_REAL, itp, (struct itimerval *)0); 404 while (!ringring) 405 sigpause(omask &~ mask(SIGALRM)); 406 (void) sigvec(SIGALRM, &ovec, (struct sigvec *)0); 407 (void) setitimer(ITIMER_REAL, &oitv, (struct itimerval *)0); 408 (void) sigsetmask(omask); 409 } 410 411 static void 412 t3000_napx(dummy) 413 int dummy; 414 { 415 ringring = 1; 416 } 417