1 #ident "@(#)$Id: tio.c,v 4.9 2006/06/14 09:49:24 gert Exp $ Copyright (c) 1993 Gert Doering" 2 3 /* tio.c 4 * 5 * contains routines dealing with SysV termio / POSIX termios / BSD sgtty 6 * 7 */ 8 9 #include <unistd.h> 10 #include <sys/types.h> 11 #include <errno.h> 12 13 #ifdef NeXT 14 #include <sys/file.h> 15 #endif 16 17 #include "mgetty.h" 18 #include "tio.h" 19 20 #ifdef POSIX_TERMIOS 21 # ident "@(#)tio.c compiled with POSIX_TERMIOS" 22 #endif 23 #ifdef SYSV_TERMIO 24 # ident "@(#)tio.c compiled with SYSV_TERMIO" 25 #endif 26 #ifdef BSD_SGTTY 27 # ident "@(#)tio.c compiled with BSD_SGTTY" 28 #endif 29 30 #ifdef USE_TERMIOX 31 # include <sys/termiox.h> 32 #endif 33 34 #if defined( M_UNIX ) && defined( MAM_BUG ) 35 #include <fcntl.h> 36 #endif 37 38 #ifdef sysV68 39 #include <fcntl.h> 40 #include <errno.h> 41 #include <sys/tty.h> 42 #include <sys/sxt.h> 43 #include <sys/mvme332xt.h> 44 #endif 45 46 /* some systems do not define all flags needed later, e.g. NetBSD */ 47 48 #if defined(BSD) || defined(__FreeBSD_kernel__) 49 # ifndef IUCLC 50 # define IUCLC 0 51 # endif 52 # ifndef TAB3 53 # ifdef NeXT 54 # define TAB3 XTABS 55 # else 56 # define TAB3 OXTABS 57 # endif /* !NeXT */ 58 # endif 59 #endif 60 61 /* baud rate table */ 62 static struct speedtab { 63 #ifdef POSIX_TERMIOS 64 speed_t cbaud; 65 #else 66 unsigned short cbaud; /* baud rate, e.g. B9600 */ 67 #endif 68 int nspeed; /* speed in numeric format */ 69 char *speed; /* speed in display format */ 70 } speedtab[] = { 71 { B50, 50, "50" }, 72 { B75, 75, "75" }, 73 { B110, 110, "110" }, 74 { B134, 134, "134" }, 75 { B150, 150, "150" }, 76 { B200, 200, "200" }, 77 { B300, 300, "300" }, 78 { B600, 600, "600" }, 79 #ifdef B900 80 { B900, 900, "900" }, 81 #endif 82 { B1200, 1200, "1200" }, 83 { B1800, 1800, "1800" }, 84 { B2400, 2400, "2400" }, 85 #ifdef B3600 86 { B3600, 3600, "3600" }, 87 #endif 88 { B4800, 4800, "4800" }, 89 #ifdef B7200 90 { B7200, 7200, "7200" }, 91 #endif 92 { B9600, 9600, "9600" }, 93 #ifdef B14400 94 { B14400, 14400, "14400" }, 95 #endif 96 #ifdef B19200 97 { B19200, 19200, "19200" }, 98 #endif /* B19200 */ 99 #ifdef B28800 100 { B28800, 28800, "28800" }, 101 #endif 102 #ifdef B38400 103 { B38400, 38400, "38400" }, 104 #endif /* B38400 */ 105 #ifdef EXTA 106 { EXTA, 19200, "EXTA" }, 107 #endif 108 #ifdef EXTB 109 { EXTB, 38400, "EXTB" }, 110 #endif 111 #ifdef B57600 112 { B57600, 57600, "57600" }, 113 #endif 114 #ifdef B76800 115 { B76800, 76800, "76800" }, 116 #endif 117 #ifdef B115200 118 { B115200,115200,"115200"}, 119 #endif 120 #ifdef B230400 121 { B230400,230400,"230400"}, 122 #endif 123 #ifdef B460800 124 { B460800,460800,"460800"}, 125 #endif 126 { 0, 0, "" } 127 }; 128 129 130 /* get current tio settings for given filedescriptor */ 131 132 int tio_get _P2((fd, t), int fd, TIO *t ) 133 { 134 #ifdef SYSV_TERMIO 135 if ( ioctl( fd, TCGETA, t ) < 0 ) 136 { 137 lprintf( L_ERROR, "TCGETA failed" ); return ERROR; 138 } 139 #endif 140 #ifdef POSIX_TERMIOS 141 if ( tcgetattr( fd, t ) < 0 ) 142 { 143 lprintf( L_ERROR, "tcgetattr failed" ); return ERROR; 144 } 145 #endif 146 #ifdef BSD_SGTTY 147 if ( gtty( fd, t ) < 0 ) 148 { 149 lprintf( L_ERROR, "gtty failed" ); return ERROR; 150 } 151 #endif 152 return NOERROR; 153 } 154 155 int tio_set _P2( (fd, t), int fd, TIO * t) /*!! FIXME: flags, wait */ 156 { 157 #ifdef sunos4 158 int modem_lines; 159 #endif 160 #ifdef SYSV_TERMIO 161 if ( ioctl( fd, TCSETA, t ) < 0 ) 162 { 163 lprintf( L_ERROR, "ioctl TCSETA failed" ); return ERROR; 164 } 165 #endif 166 #ifdef POSIX_TERMIOS 167 if ( tcsetattr( fd, TCSANOW, t ) < 0 ) 168 { 169 lprintf( L_ERROR, "tcsetattr failed" ); return ERROR; 170 } 171 #ifdef sunos4 172 /* On SunOS, make sure that RTS and DTR are asserted if you wanna 173 * use hardware flow control 174 */ 175 if (t->c_cflag & CRTSCTS) 176 { 177 /* make sure RTS is asserted!!!!!! */ 178 ioctl(fd, TIOCMGET, &modem_lines); 179 modem_lines |= (TIOCM_RTS | TIOCM_DTR); 180 ioctl(fd, TIOCMSET, &modem_lines); 181 } 182 #endif /* sunos4 */ 183 #endif /* posix_termios */ 184 185 #ifdef BSD_SGTTY 186 if ( stty( fd, t ) < 0 ) 187 { 188 lprintf( L_ERROR, "stty failed" ); return ERROR; 189 } 190 #endif 191 return NOERROR; 192 } 193 194 /* check whether a given speed (integer) is valid for the given system */ 195 int tio_check_speed _P1( (speed), int speed ) 196 { 197 int i; 198 for ( i=0; speedtab[i].cbaud != 0; i++ ) 199 { 200 if ( speedtab[i].nspeed == speed ) 201 { 202 return speedtab[i].cbaud; 203 } 204 } 205 lprintf( L_NOISE, "speed %d not found in table", speed ); 206 errno=EINVAL; 207 return -1; 208 } 209 210 /* set speed, do not touch the other flags 211 * "speed" is given as numeric baud rate, not as Bxxx constant 212 */ 213 int tio_set_speed _P2( (t, speed ), TIO *t, unsigned int speed ) 214 { 215 int i, symspeed=0; 216 217 for ( i=0; speedtab[i].cbaud != 0; i++ ) 218 { 219 if ( speedtab[i].nspeed == speed ) 220 { symspeed = speedtab[i].cbaud; break; } 221 } 222 223 if ( symspeed == 0 ) 224 { 225 errno=EINVAL; 226 lprintf( L_ERROR, "tss: unknown/unsupported bit rate: %d", speed ); 227 return ERROR; 228 } 229 230 lprintf( L_NOISE, "tss: set speed to %d (%03o)", speed, symspeed ); 231 232 #ifdef SYSV_TERMIO 233 t->c_cflag = ( t->c_cflag & ~CBAUD) | symspeed; 234 #endif 235 #ifdef POSIX_TERMIOS 236 cfsetospeed( t, symspeed ); 237 cfsetispeed( t, symspeed ); 238 #endif 239 #ifdef BSD_SGTTY 240 t->sg_ispeed = t->sg_ospeed = symspeed; 241 #endif 242 return NOERROR; 243 } 244 245 /* get port speed. Return integer value, not symbolic constant */ 246 int tio_get_speed _P1( (t), TIO *t ) 247 { 248 #ifdef SYSV_TERMIO 249 ushort cbaud = t->c_cflag & CBAUD; 250 #endif 251 #ifdef POSIX_TERMIOS 252 speed_t cbaud = cfgetospeed( t ); 253 #endif 254 #ifdef BSD_SGTTY 255 int cbaud = t->sg_ospeed; 256 #endif 257 struct speedtab * p; 258 259 for ( p=speedtab; p->nspeed != 0; p++ ) 260 { 261 if ( p->cbaud == cbaud ) break; 262 } 263 return p->nspeed; 264 } 265 266 267 /* set "raw" mode: do not process input or output, do not buffer */ 268 /* do not touch cflags or xon/xoff flow control flags */ 269 270 void tio_mode_raw _P1( (t), TIO * t ) 271 { 272 #if defined(SYSV_TERMIO) || defined( POSIX_TERMIOS) 273 t->c_iflag &= ( IXON | IXOFF | IXANY ); /* clear all flags except */ 274 /* xon / xoff handshake */ 275 t->c_oflag = 0; /* no output processing */ 276 t->c_lflag = 0; /* no signals, no echo */ 277 278 t->c_cc[VMIN] = 1; /* disable line buffering */ 279 t->c_cc[VTIME] = 0; 280 #else 281 t->sg_flags = RAW; 282 #endif 283 } 284 285 /* "cbreak" mode - do not process input in lines, but process ctrl 286 * characters, echo characters back, ... 287 * warning: must be based on raw / sane mode 288 */ 289 void tio_mode_cbreak _P1( (t), TIO * t ) 290 { 291 #if defined(SYSV_TERMIO) || defined(POSIX_TERMIOS) 292 t->c_oflag = 0; 293 t->c_iflag &= ~( IGNCR | ICRNL | INLCR | IUCLC ); 294 t->c_lflag &= ~( ICANON | ISIG ); 295 t->c_cc[VMIN] = 1; 296 t->c_cc[VTIME]= 0; 297 #else 298 t->sg_flags |= CBREAK; 299 #endif 300 } 301 302 /* set "sane" mode, usable for login, ... 303 * unlike the other tio_mode_* functions, this function initializes 304 * all flags, and should be called before calling any other function 305 */ 306 void tio_mode_sane _P2( (t, local), TIO * t, int local ) 307 { 308 #if defined(SYSV_TERMIO) || defined( POSIX_TERMIOS ) 309 t->c_iflag = BRKINT | IGNPAR | IXON | IXANY; 310 t->c_oflag = OPOST | TAB3; 311 /* be careful, only touch "known" flags */ 312 t->c_cflag&= ~(CSIZE | CSTOPB | PARENB | PARODD | CLOCAL); 313 t->c_cflag|= CS8 | CREAD | HUPCL | ( local? CLOCAL:0 ); 314 t->c_lflag = ECHOK | ECHOE | ECHO | ISIG | ICANON; 315 316 #if !defined(POSIX_TERMIOS) 317 t->c_line = 0; 318 #endif 319 320 /* initialize the most important c_cc's here */ 321 t->c_cc[VEOF] = 0x04; 322 #if defined(VEOL) && VEOL < TIONCC 323 t->c_cc[VEOL] = 0; 324 #endif 325 326 #ifdef VSWTCH 327 t->c_cc[VSWTCH] = 0; 328 #endif 329 330 #else /* BSD_SGTTY */ 331 t->sg_flags = ECHO | EVENP | ODDP; 332 /* t->sg_flags = ECHO; */ 333 t->sg_erase = 0x7f; /* erase character */ 334 t->sg_kill = 0x25; /* kill character, ^u */ 335 #endif 336 } 337 338 /* tio_default_cc( TIO ) 339 * 340 * initialize all c_cc fields (for POSIX and SYSV) to proper start 341 * values (normally, the serial driver should do this, but there are 342 * numerous systems where some of the more esoteric (VDSUSP...) flags 343 * are plain wrong (e.g. set to "m" or so) 344 * 345 * do /not/ initialize VERASE and VINTR, since some systems use 346 * ^H / DEL here, others DEL / ^C. 347 */ 348 void tio_default_cc _P1( (t), TIO *t ) 349 { 350 #ifdef BSD_SGTTY 351 t->sg_erase = 0x7f; /* erase character */ 352 t->sg_kill = 0x25; /* kill character, ^u */ 353 354 #else /* posix or sysv */ 355 t->c_cc[VQUIT] = CQUIT; 356 t->c_cc[VKILL] = CKILL; 357 t->c_cc[VEOF] = CEOF; 358 #if defined(VEOL) && VEOL < TIONCC 359 t->c_cc[VEOL] = CEOL; 360 #endif 361 #if defined(VSTART) && VSTART < TIONCC 362 t->c_cc[VSTART] = CSTART; 363 #endif 364 #if defined(VSTOP) && VSTOP < TIONCC 365 t->c_cc[VSTOP] = CSTOP; 366 #endif 367 #if defined(VSUSP) && VSUSP < TIONCC 368 t->c_cc[VSUSP] = CSUSP; 369 #endif 370 #if defined(VSWTCH) && VSWTCH < TIONCC 371 t->c_cc[VSWTCH] = CSWTCH; 372 #endif 373 /* the following are for SVR4.2 (and higher) */ 374 #if defined(VDSUSP) && VDSUSP < TIONCC 375 t->c_cc[VDSUSP] = CDSUSP; 376 #endif 377 #if defined(VREPRINT) && VREPRINT < TIONCC 378 t->c_cc[VREPRINT] = CRPRNT; 379 #endif 380 #if defined(VDISCARD) && VDISCARD < TIONCC 381 t->c_cc[VDISCARD] = CFLUSH; 382 #endif 383 #if defined(VWERASE) && VWERASE < TIONCC 384 t->c_cc[VWERASE] = CWERASE; 385 #endif 386 #if defined(VLNEXT) && VLNEXT < TIONCC 387 t->c_cc[VLNEXT] = CLNEXT; 388 #endif 389 390 #endif /* bsd <-> posix + sysv */ 391 } 392 393 394 void tio_map_cr _P2( (t, perform_mapping), TIO * t, int 395 perform_mapping ) 396 { 397 #if defined(SYSV_TERMIO) || defined(POSIX_TERMIOS) 398 if ( perform_mapping ) 399 { 400 t->c_iflag |= ICRNL; 401 t->c_oflag |= ONLCR; 402 } 403 else 404 { 405 t->c_iflag &= ~ICRNL; 406 t->c_oflag &= ~ONLCR; 407 } 408 #else /* BSD_SGTTY (tested only on NeXT yet, but should work) */ 409 if ( perform_mapping ) 410 { 411 t->sg_flags |= CRMOD ; 412 } 413 else 414 { 415 t->sg_flags &= ~CRMOD ; 416 } 417 #endif 418 } 419 420 /* enable uppercase <-> lowercase mapping */ 421 422 void tio_map_uclc _P2( (t, perform_mapping), TIO * t, int 423 perform_mapping ) 424 { 425 #if defined(__bsdi__) || !defined(OLCUC) || !defined(XCASE) 426 lprintf( L_WARN, "uclc mapping not available" ); 427 #else 428 # if defined(SYSV_TERMIO) || defined(POSIX_TERMIOS) 429 if ( perform_mapping ) 430 { 431 t->c_iflag |= IUCLC; 432 t->c_oflag |= OLCUC; 433 t->c_lflag |= XCASE; 434 } 435 else 436 { 437 t->c_iflag &= ~IUCLC; 438 t->c_oflag &= ~OLCUC; 439 t->c_lflag &= ~XCASE; 440 } 441 # else /* BSD_SGTTY */ 442 # include "not implemented yet" 443 # endif 444 #endif /* BSDI */ 445 } 446 447 /* tio_carrier() 448 * specify whether the port should be carrier-sensitive or not 449 */ 450 451 void tio_carrier _P2( (t, carrier_sensitive), TIO *t, int carrier_sensitive ) 452 { 453 #if defined(SYSV_TERMIO) || defined(POSIX_TERMIOS) 454 if ( carrier_sensitive ) 455 { 456 t->c_cflag &= ~CLOCAL; 457 } 458 else 459 { 460 t->c_cflag |= CLOCAL; 461 } 462 #else /* BSD_SGTTY (tested only on NeXT yet, but should work) */ 463 if ( carrier_sensitive ) 464 { 465 t->sg_flags &= ~LNOHANG ; 466 } 467 else 468 { 469 t->sg_flags |= LNOHANG ; 470 } 471 #endif 472 } 473 474 /* set handshake */ 475 476 /* hardware handshake flags - use what is available on local system 477 */ 478 479 #ifdef CRTSCTS 480 # define HARDWARE_HANDSHAKE CRTSCTS /* linux, SunOS */ 481 #else 482 # ifdef CRTSFL 483 # define HARDWARE_HANDSHAKE CRTSFL /* SCO 3.2v4.2 */ 484 # else 485 # ifdef RTSFLOW 486 # define HARDWARE_HANDSHAKE RTSFLOW | CTSFLOW /* SCO 3.2v2 */ 487 # else 488 # ifdef CTSCD 489 # define HARDWARE_HANDSHAKE CTSCD /* AT&T 3b1? */ 490 # else 491 # define HARDWARE_HANDSHAKE 0 /* nothing there... */ 492 # endif 493 # endif 494 # endif 495 #endif 496 497 /* Dial-Out parallel to a Dial-in on SCO 3.2v4.0 does only work if 498 * *only* CTSFLOW is set (Uwe S. Fuerst) 499 */ 500 #ifdef BROKEN_SCO_324 501 # undef HARDWARE_HANDSHAKE 502 # define HARDWARE_HANDSHAKE CTSFLOW 503 #endif 504 505 /* tio_set_flow_control 506 * 507 * set flow control according to the <type> parameter. It can be any 508 * combination of 509 * FLOW_XON_IN - use Xon/Xoff on incoming data 510 * FLOW_XON_OUT- respect Xon/Xoff on outgoing data 511 * FLOW_HARD - use RTS/respect CTS line for hardware handshake 512 * (not every combination will work on every system) 513 * 514 * WARNING: for most systems, this function will not touch the tty 515 * settings, only modify the TIO structure. On some systems, 516 * you have to use extra ioctl()s [notably SVR4, sysV68, and 517 * AIX] to modify hardware flow control settings. On those 518 * systems, these calls are done immediately. 519 */ 520 521 int tio_set_flow_control _P3( (fd, t, type), int fd, TIO * t, int type ) 522 { 523 #ifdef USE_TERMIOX 524 struct termiox tix; 525 #endif 526 527 lprintf( L_NOISE, "tio_set_flow_control(%s%s%s )", 528 type & FLOW_HARD ? " HARD": "", 529 type & FLOW_XON_IN ? " XON_IN": "", 530 type & FLOW_XON_OUT? " XON_OUT": "" ); 531 532 #if defined( SYSV_TERMIO ) || defined( POSIX_TERMIOS ) 533 t->c_cflag &= ~HARDWARE_HANDSHAKE; 534 t->c_iflag &= ~( IXON | IXOFF | IXANY ); 535 536 if ( type & FLOW_HARD ) 537 t->c_cflag |= HARDWARE_HANDSHAKE; 538 if ( type & FLOW_XON_IN ) 539 t->c_iflag |= IXOFF; 540 /* for login, we want IXON|IXANY, for voice, we must not set IXANY! */ 541 if ( type & FLOW_XON_OUT ) 542 { 543 t->c_iflag |= IXON; 544 if ( type & FLOW_XON_IXANY ) 545 t->c_iflag |= IXANY; 546 } 547 #else 548 # ifdef NEXTSGTTY 549 lprintf( L_WARN, "tio_set_flow_control: not yet implemented" ); 550 # else 551 # include "not yet implemented" 552 # endif 553 #endif 554 555 /* SVR4 came up with a new method of setting h/w flow control */ 556 #ifdef USE_TERMIOX 557 lprintf( L_NOISE, "tio_set_flow_control: using termiox" ); 558 559 if (ioctl(fd, TCGETX, &tix) < 0) 560 { 561 lprintf( L_ERROR, "ioctl TCGETX" ); return ERROR; 562 } 563 if ( type & FLOW_HARD ) 564 tix.x_hflag |= (RTSXOFF | CTSXON); 565 else 566 tix.x_hflag &= ~(RTSXOFF | CTSXON); 567 568 if ( ioctl(fd, TCSETX, &tix) < 0 ) 569 { 570 lprintf( L_ERROR, "ioctl TCSETX" ); return ERROR; 571 } 572 #endif 573 /* AIX has yet another method to set hardware flow control 574 * interesting enough, in AIX 4, this ioctl still exists but doesn't 575 * work anymore -- instead, they have adopted termiox. *bah* 576 */ 577 #if defined(_AIX) && !defined(USE_TERMIOX) 578 lprintf( L_NOISE, "tio_set_flow_control: using TXADDCD" ); 579 580 if ( ioctl( fd, ( type & FLOW_HARD ) ? TXADDCD : TXDELCD, "rts" ) < 0 ) 581 { 582 lprintf( L_NOISE, "ioctl TXADDCD/TXDELCD failed, errno=%d", errno); 583 return ERROR; 584 } 585 #ifdef DEBUG 586 { union txname t; int i; 587 lprintf( L_NOISE, "control disciplines:"); 588 for ( i=1; ; i++ ) { 589 t.tx_which = i; 590 if ( ioctl( fd, TXGETCD, &t ) ) { 591 lprintf( L_FATAL, "TXGETCD error" ); break; 592 } 593 if ( t.tx_name == NULL || !t.tx_name[0] ) break; 594 lputc( L_NOISE, ' '); 595 lputs( L_NOISE, t.tx_name ); 596 } 597 } 598 #endif /* DEBUG */ 599 #endif /* _AIX */ 600 601 /* 602 * sysV68 uses special ioctls, too. The following code should work for 603 * mvme332xt controllers. The mvme337 driver supports the same ioctls 604 * but has not been tested. Others may not support hardware flow 605 * control at all. Refer to the corresponding mvmeXXX(7) manpage for 606 * details. 607 */ 608 #ifdef sysV68 609 lprintf( L_NOISE, "tio_set_flow_control: using TCSETHW" ); 610 611 if ( type & FLOW_HARD ) { 612 if ( ioctl(fd, TCSETHW, 1) < 0 ) { 613 lprintf( L_ERROR, "ioctl TCSETHW on failed" ); 614 return ERROR; 615 } 616 } else { 617 if ( ioctl(fd, TCSETHW, 0) < 0 ) { 618 /* We use a lower logging priority if errno is EINVAL, so 619 * mgetty can be used on devices which do not support the 620 * special m332xt ioctls without filling syslog with 621 * unnecessary error messages. 622 */ 623 if (EINVAL == errno) { 624 lprintf( L_NOISE, "ioctl TCSETHW off failed" ); 625 } else { 626 lprintf( L_ERROR, "ioctl TCSETHW off failed" ); 627 return ERROR; 628 } 629 } 630 } 631 #endif /* sysV68 */ 632 return NOERROR; 633 } 634 635 /* for convenience - do not have to get termio settings before, but 636 * it's slower (two system calls more) 637 */ 638 int tio_set_flow_control2 _P2( (fd, type), int fd, int type ) 639 { 640 TIO t; 641 642 if ( tio_get( fd, &t ) == ERROR ) return ERROR; 643 644 tio_set_flow_control( fd, &t, type ); 645 646 return tio_set( fd, &t ); 647 } 648 649 int tio_toggle_dtr _P2( (fd, msec_wait), int fd, int msec_wait ) 650 { 651 /* On SVR4.2, lowering DTR by setting the port speed to zero will 652 * bring the port to some strange state where every ioctl() later 653 * on simply fails - so use special "modem control" ioctl()s to 654 * lower and raise DTR 655 * Strange enough, on *some* platforms, you have to pass the mctl 656 * flag word by value, on others by reference. Oh world... 657 */ 658 #if defined(TIOCMBIS) && \ 659 ( defined(sun) || defined(SVR4) || defined(NeXT) || defined(linux) ) 660 661 int mctl = TIOCM_DTR; 662 663 #if !defined( TIOCM_VALUE ) 664 if ( ioctl( fd, TIOCMBIC, &mctl ) < 0 ) 665 #else 666 if ( ioctl( fd, TIOCMBIC, (char *) mctl ) < 0 ) 667 #endif 668 { 669 lprintf( L_ERROR, "TIOCMBIC failed" ); return ERROR; 670 } 671 delay( msec_wait ); 672 #if !defined( TIOCM_VALUE) 673 if ( ioctl( fd, TIOCMBIS, &mctl ) < 0 ) 674 #else 675 if ( ioctl( fd, TIOCMBIS, (char *) mctl ) < 0 ) 676 #endif 677 { 678 lprintf( L_ERROR, "TIOCMBIS failed" ); return ERROR; 679 } 680 return NOERROR; 681 #else /* !TIOCMBI* */ 682 683 /* On HP/UX, lowering DTR by setting the port speed to B0 will 684 * leave it there. So, do it via HP/UX's special ioctl()'s... 685 */ 686 #if defined(_HPUX_SOURCE) || defined(MCGETA) 687 unsigned long mflag = 0L; 688 689 if ( ioctl( fd, MCSETAF, &mflag ) < 0 ) 690 { 691 lprintf( L_ERROR, "MCSETAF failed" ); return ERROR; 692 } 693 delay( msec_wait ); 694 if ( ioctl( fd, MCGETA, &mflag ) < 0 ) 695 { 696 lprintf( L_ERROR, "MCGETA failed" ); return ERROR; 697 } 698 mflag = MRTS | MDTR; 699 if ( ioctl( fd, MCSETAF, &mflag ) < 0 ) 700 { 701 lprintf( L_ERROR, "MCSETAF failed" ); return ERROR; 702 } 703 return NOERROR; 704 705 #else /* !MCGETA */ 706 707 /* The "standard" way of doing things - via speed = B0 708 */ 709 TIO t, save_t; 710 #ifdef sunos4 711 int modem_lines; 712 #endif 713 int result; 714 715 if ( tio_get( fd, &t ) == ERROR ) return ERROR; 716 717 save_t = t; 718 719 #ifdef SYSV_TERMIO 720 t.c_cflag = ( t.c_cflag & ~CBAUD ) | B0; /* speed = 0 */ 721 #endif 722 #ifdef POSIX_TERMIOS 723 cfsetospeed( &t, B0 ); 724 cfsetispeed( &t, B0 ); 725 #endif 726 #ifdef BSD_SGTTY 727 t.sg_ispeed = t.sg_ospeed = B0 728 #endif 729 730 tio_set( fd, &t ); 731 delay( msec_wait ); 732 733 #ifdef sunos4 734 /* on SunOS, if you hangup via B0, the DTR line will *stay* low. 735 * So: enable it manually again. 736 */ 737 ioctl(fd, TIOCMGET, &modem_lines); 738 modem_lines |= (TIOCM_RTS | TIOCM_DTR); 739 ioctl(fd, TIOCMSET, &modem_lines); 740 #endif 741 result = tio_set( fd, &save_t ); 742 743 #if (defined(M_UNIX) && defined(MAM_BUG)) || defined (sysV68) 744 /* some Unix variants apparently forget to raise DTR again 745 * after lowering it. Reopening the port fixes it. Crude, but works. 746 */ 747 close( open( "/dev/tty", O_RDONLY | O_NDELAY ) ); 748 #endif 749 750 return result; 751 #endif /* !MCSETA */ 752 #endif /* !SVR4 */ 753 } 754 755 756 /* flush input or output data queue 757 * 758 * "queue" is one of the TIO_Q* values from tio.h 759 */ 760 761 int tio_flush_queue _P2( (fd, queue), int fd, int queue ) 762 { 763 int r = NOERROR; 764 #ifdef POSIX_TERMIOS 765 switch( queue ) 766 { 767 case TIO_Q_IN: r = tcflush( fd, TCIFLUSH ); break; 768 case TIO_Q_OUT: r = tcflush( fd, TCOFLUSH ); break; 769 case TIO_Q_BOTH: r = tcflush( fd, TCIOFLUSH );break; 770 default: 771 lprintf( L_WARN, "tio_flush_queue: invalid ``queue'' argument" ); 772 return ERROR; 773 } 774 #endif 775 #ifdef SYSV_TERMIO 776 switch ( queue ) 777 { 778 case TIO_Q_IN: r = ioctl( fd, TCFLSH, 0 ); break; 779 case TIO_Q_OUT: r = ioctl( fd, TCFLSH, 1 ); break; 780 case TIO_Q_BOTH: r = ioctl( fd, TCFLSH, 2 ); break; 781 default: 782 lprintf( L_WARN, "tio_flush_queue: invalid ``queue'' argument" ); 783 return ERROR; 784 } 785 #endif 786 #ifdef BSD_SGTTY 787 int arg; 788 789 switch ( queue ) 790 { 791 case TIO_Q_IN: arg = FREAD; break; 792 case TIO_Q_OUT: arg = FWRITE; break; 793 case TIO_Q_BOTH: arg = FREAD | FWRITE; break; 794 default: 795 lprintf( L_WARN, "tio_flush_queue: invalid ``queue'' argument" ); 796 return ERROR; 797 } 798 r = ioctl( fd, TIOCFLUSH, (char *) &arg ); 799 #endif 800 if ( r != 0 ) lprintf( L_ERROR, "tio: cannot flush queue" ); 801 802 return r; 803 } 804 805 /* control flow control: if "restart_output" is TRUE, stopped tty output is 806 * resumed, if it is FALSE, the output is stopped 807 * 808 * I'm fairly sure it won't work on all supported systems... 809 */ 810 811 int tio_flow _P2( (fd, restart_output), int fd, int restart_output ) 812 { 813 int r; 814 #ifdef POSIX_TERMIOS 815 if ( restart_output ) r = tcflow( fd, TCOON ); 816 else r = tcflow( fd, TCOOFF ); 817 #endif 818 #ifdef SYSV_TERMIO 819 if ( restart_output ) r = ioctl( fd, TCXONC, 1 ); 820 else r = ioctl( fd, TCXONC, 0 ); 821 #endif 822 #ifdef BSD_SGTTY 823 if ( restart_output ) r = ioctl( fd, TIOCSTART, NULL ); 824 else r = ioctl( fd, TIOCSTOP, NULL ); 825 #endif 826 if ( r != 0 ) lprintf( L_ERROR, "tio: cannot change flow ctrl state" ); 827 828 return r; 829 } 830 831 832 /* tio_drain(fd): wait for output queue to drain 833 */ 834 835 int tio_drain_output _P1( (fd), int fd ) 836 { 837 #ifdef POSIX_TERMIOS 838 if ( tcdrain( fd ) == ERROR ) 839 { 840 lprintf( L_ERROR, "tio_drain: tcdrain" ); return ERROR; 841 } 842 #else 843 # ifdef SYSV_TERMIO 844 if ( ioctl( fd, TCSBRK, 1 ) == ERROR ) 845 { 846 lprintf( L_ERROR, "tio_drain: TCSBRK/1" ); return ERROR; 847 } 848 # else /* no way to wait for data to drain with BSD_SGTTY */ 849 lprintf( L_WARN, "tio_drain: expect spurious failures" ); 850 # endif 851 #endif 852 return NOERROR; 853 } 854 855 /* send a BREAK signal to the tty 856 * 857 * kernel break via tcsendbreak() or ioctl(TCSENDBRK) lasts at least 858 * 0.25 seconds. We can speed up this by switching baud rate to 1/4, 859 * and then sending a 0-byte (activated #ifdef FAST_BREAK). 860 * 861 * on some systems (don't we love it all?) the "real" break functions 862 * don't work, so we must use FAST_BREAK. 863 */ 864 865 int tio_break _P1((fd), int fd) 866 { 867 /* SunOS4 doesn't seem to like "tcsendbreak" (noop), so send a "long zero" */ 868 #if defined(sunos4) || defined(M_UNIX) || defined(FAST_BREAK) 869 TIO tio, tio_save; int speed; char null = 0; 870 871 lprintf( L_NOISE, "sending FAST break" ); 872 873 if ( tio_get( fd, &tio ) == ERROR ) 874 { 875 lprintf( L_ERROR, "tio_break: can't get tio" ); return ERROR; 876 } 877 tio_save = tio; 878 if ( (speed = tio_get_speed( &tio ) ) < 150 || 879 tio_set_speed( &tio, speed/4 ) == ERROR || 880 tio_set( fd, &tio ) == ERROR ) 881 { 882 lprintf( L_ERROR, "tio_break: can't set 1/4 speed" ); return ERROR; 883 } 884 if ( write( fd, &null, 1 ) != 1 ) 885 { 886 lprintf( L_ERROR, "tio_break: can't write 0-byte" ); return ERROR; 887 } 888 889 /* before we switch baud rates back, make sure zero byte has been sent! 890 */ 891 if ( tio_drain_output( fd ) == ERROR ) return ERROR; 892 893 if ( tio_set( fd, &tio_save ) == ERROR ) 894 { 895 lprintf( L_ERROR, "tio_break: can't reset old TIO state" ); return ERROR; 896 } 897 898 #else /* !FAST_BREAK -> use standard functions */ 899 900 lprintf( L_NOISE, "sending system call break" ); 901 #ifdef POSIX_TERMIOS 902 if ( tcsendbreak( fd, 0 ) < 0 ) 903 { 904 lprintf( L_ERROR, "tcsendbreak() failed" ); 905 return ERROR; 906 } 907 #endif 908 #ifdef SYSV_TERMIO 909 if ( ioctl( fd, TCSBRK, 0 ) < 0 ) 910 { 911 lprintf( L_ERROR, "ioctl( TCSBRK ) failed" ); 912 return ERROR; 913 } 914 #endif 915 #ifdef BSD_SGTTY 916 if ( ioctl( fd, TIOCSBRK, 0 ) < 0 ) 917 { 918 lprintf( L_ERROR, "ioctl( TIOCSBRK ) failed" ); 919 return ERROR; 920 } 921 delay( 250 ); 922 if ( ioctl( fd, TIOCCBRK, 0 ) < 0 ) 923 { 924 lprintf( L_ERROR, "ioctl( TIOCCBRK ) failed" ); 925 return ERROR; 926 } 927 #endif 928 #endif /* FAST_BREAK */ 929 return NOERROR; 930 } 931 932 /* tio_get_rs232_lines() 933 * 934 * get the status of all RS232 status lines 935 * (coded by the TIO_F_* flags. On systems that have the BSD TIOCM_* 936 * flags, we use them, on others we may have to do some other tricks) 937 * 938 * "-1" can mean "error" or "not supported on this system" (e.g. SCO). 939 */ 940 941 int tio_get_rs232_lines _P1( (fd), int fd) 942 { 943 int flags; 944 #ifdef TIO_F_SYSTEM_DEFS 945 if ( ioctl(fd, TIOCMGET, &flags ) < 0 ) 946 lprintf( L_ERROR, "tio_get_rs232_lines: TIOCMGET failed" ); 947 948 #else /* !TIO_F_SYSTEM_DEFS */ 949 flags=-1; 950 #endif 951 952 if ( flags != -1 ) 953 { 954 lprintf( L_NOISE, "tio_get_rs232_lines: status:" ); 955 if ( flags & TIO_F_RTS ) lputs( L_NOISE, " RTS" ); 956 if ( flags & TIO_F_CTS ) lputs( L_NOISE, " CTS" ); 957 if ( flags & TIO_F_DSR ) lputs( L_NOISE, " DSR" ); 958 if ( flags & TIO_F_DTR ) lputs( L_NOISE, " DTR" ); 959 if ( flags & TIO_F_DCD ) lputs( L_NOISE, " DCD" ); 960 if ( flags & TIO_F_RI ) lputs( L_NOISE, " RI" ); 961 } 962 return flags; 963 } 964 965 /* tio_set_rs232_lines() 966 * 967 * set the status of the DTR and RTS RS232 status lines 968 * (coded by the TIO_F_* flags. On systems that have the BSD TIOCM_* 969 * flags, we use them, on others we may have to do some other tricks) 970 * 971 * "-1" can mean "error" or "not supported on this system" (e.g. SCO). 972 */ 973 974 int tio_set_rs232_lines _P3( (fd, do_dtr, do_rts), 975 int fd, int do_dtr, int do_rts ) 976 { 977 int mctl, rc=0; 978 979 #ifdef TIO_F_SYSTEM_DEFS 980 mctl = TIOCM_DTR; 981 if ( do_dtr != -1 && 982 ioctl( fd, do_dtr? TIOCMBIS: TIOCMBIC, &mctl ) < 0 ) 983 { 984 lprintf( L_ERROR, "tio_set_rs232_lines: %s DTR failed", 985 do_dtr? "set": "clear" ); 986 rc=-1; 987 } 988 989 mctl = TIOCM_RTS; 990 if ( do_rts != -1 && 991 ioctl( fd, do_rts? TIOCMBIS: TIOCMBIC, &mctl ) < 0 ) 992 { 993 lprintf( L_ERROR, "tio_set_rs232_lines: %s RTS failed", 994 do_rts? "set": "clear" ); 995 rc=-1; 996 } 997 998 #else 999 lprintf( L_WARN, "setting of RS232 lines not supported" ); 1000 #endif 1001 return rc; 1002 } 1003