1 /* $NetBSD: t3000.c,v 1.9 1998/12/19 23:02:02 christos 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.9 1998/12/19 23:02:02 christos 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 memset(dialer_buf, 0, sizeof(dialer_buf)); 233 timeout = 0; 234 for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) { 235 if (setjmp(timeoutbuf)) 236 break; 237 alarm(number(value(DIALTIMEOUT))); 238 n = read(FD, &c, 1); 239 alarm(0); 240 if (n <= 0) 241 break; 242 c &= 0x7f; 243 if (c == '\r') { 244 if (t3000_swallow("\n") == 0) 245 break; 246 if (!dialer_buf[0]) 247 goto again; 248 if (strcmp(dialer_buf, "RINGING") == 0 && 249 boolean(value(VERBOSE))) { 250 #ifdef DEBUG 251 printf("%s\r\n", dialer_buf); 252 #endif 253 goto again; 254 } 255 if (strncmp(dialer_buf, "CONNECT", 256 sizeof("CONNECT")-1) != 0) 257 break; 258 for (bm = tbaud_msg ; bm->msg ; bm++) 259 if (strcmp(bm->msg, 260 dialer_buf+sizeof("CONNECT")-1) == 0) { 261 struct termios cntrl; 262 263 tcgetattr(FD, &cntrl); 264 cfsetospeed(&cntrl, bm->baud); 265 cfsetispeed(&cntrl, bm->baud); 266 tcsetattr(FD, TCSAFLUSH, &cntrl); 267 signal(SIGALRM, f); 268 #ifdef DEBUG 269 if (boolean(value(VERBOSE))) 270 printf("%s\r\n", dialer_buf); 271 #endif 272 return (1); 273 } 274 break; 275 } 276 dialer_buf[nc] = c; 277 #ifdef notdef 278 if (boolean(value(VERBOSE))) 279 putchar(c); 280 #endif 281 } 282 printf("%s\r\n", dialer_buf); 283 signal(SIGALRM, f); 284 return (0); 285 } 286 287 /* 288 * This convoluted piece of code attempts to get 289 * the t3000 in sync. 290 */ 291 static int 292 t3000_sync() 293 { 294 int already = 0; 295 int len; 296 char buf[40]; 297 298 while (already++ < MAXRETRY) { 299 tcflush(FD, TCIOFLUSH); 300 t3000_write(FD, "\rAT Z\r", 6); /* reset modem */ 301 memset(buf, 0, sizeof(buf)); 302 sleep(2); 303 ioctl(FD, FIONREAD, &len); 304 #if 1 305 if (len == 0) len = 1; 306 #endif 307 if (len) { 308 len = read(FD, buf, sizeof(buf)); 309 #ifdef DEBUG 310 buf[len] = '\0'; 311 printf("t3000_sync: (\"%s\")\n\r", buf); 312 #endif 313 if (strchr(buf, '0') || 314 (strchr(buf, 'O') && strchr(buf, 'K'))) 315 return(1); 316 } 317 /* 318 * If not strapped for DTR control, 319 * try to get command mode. 320 */ 321 sleep(1); 322 t3000_write(FD, "+++", 3); 323 sleep(1); 324 /* 325 * Toggle DTR to force anyone off that might have left 326 * the modem connected. 327 */ 328 ioctl(FD, TIOCCDTR, 0); 329 sleep(1); 330 ioctl(FD, TIOCSDTR, 0); 331 } 332 t3000_write(FD, "\rAT Z\r", 6); 333 return (0); 334 } 335 336 static void 337 t3000_write(fd, cp, n) 338 int fd; 339 char *cp; 340 int n; 341 { 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 #define setsa(sa, a) \ 373 sa.sa_handler = a; sigemptyset(&sa.sa_mask); sa.sa_flags = 0 374 375 static int napms = 50; /* Give the t3000 50 milliseconds between characters */ 376 377 static int ringring; 378 379 void 380 t3000_nap() 381 { 382 383 struct itimerval itv, oitv; 384 struct itimerval *itp = &itv; 385 struct sigaction sa, osa; 386 sigset_t sm, osm; 387 388 timerclear(&itp->it_interval); 389 timerclear(&itp->it_value); 390 if (setitimer(ITIMER_REAL, itp, &oitv) < 0) 391 return; 392 393 sigemptyset(&sm); 394 sigaddset(&sm, SIGALRM); 395 (void)sigprocmask(SIG_BLOCK, &sm, &osm); 396 397 itp->it_value.tv_sec = napms/1000; 398 itp->it_value.tv_usec = ((napms%1000)*1000); 399 400 setsa(sa, t3000_napx); 401 (void)sigaction(SIGALRM, &sa, &osa); 402 403 (void)setitimer(ITIMER_REAL, itp, NULL); 404 405 sm = osm; 406 sigdelset(&sm, SIGALRM); 407 408 for (ringring = 0; !ringring; ) 409 sigsuspend(&sm); 410 411 (void)sigaction(SIGALRM, &osa, NULL); 412 (void)setitimer(ITIMER_REAL, &oitv, NULL); 413 (void)sigprocmask(SIG_SETMASK, &osm, NULL); 414 } 415 416 static void 417 t3000_napx(dummy) 418 int dummy; 419 { 420 421 ringring = 1; 422 } 423