1 /* $Header: /p/tcsh/cvsroot/tcsh/mi.termios.c,v 1.5 2006/03/02 18:46:44 christos Exp $ */ 2 /* termios.c - fake termios interface using sgtty interface 3 * by Magnus Doell and Bruce Evans. 4 * 5 */ 6 #include "sh.h" 7 RCSID("$tcsh: mi.termios.c,v 1.5 2006/03/02 18:46:44 christos Exp $") 8 9 #if defined(_MINIX) && !defined(_MINIX_VMD) 10 11 12 /* Undefine everything that clashes with sgtty.h. */ 13 #undef B0 14 #undef B50 15 #undef B75 16 #undef B110 17 #undef B134 18 #undef B150 19 #undef B200 20 #undef B300 21 #undef B600 22 #undef B1200 23 #undef B1800 24 #undef B2400 25 #undef B4800 26 #undef B9600 27 #undef B19200 28 #undef B28800 29 #undef B38400 30 #undef B57600 31 #undef B115200 32 /* Do not #undef CRMOD. We want a warning when they differ! */ 33 #undef ECHO 34 /* Do not #undef XTABS. We want a warning when they differ! */ 35 36 /* Redefine some of the termios.h names just undefined with 'T_' prefixed 37 * to the name. Don't bother with the low speeds - Minix does not support 38 * them. Add support for higher speeds (speeds are now easy and don't need 39 * defines because they are not encoded). 40 */ 41 #define T_ECHO 000001 42 43 #include <errno.h> 44 #include <sgtty.h> 45 46 static _PROTOTYPE( int tc_to_sg_speed, (speed_t speed) ); 47 static _PROTOTYPE( speed_t sg_to_tc_speed, (int speed) ); 48 #define B19200 192 49 50 /* The speed get/set functions could be macros in the Minix implementation 51 * because there are speed fields in the structure with no fancy packing 52 * and it is not practical to check the values outside the driver. 53 * Where tests are necessary because the driver acts different from what 54 * POSIX requires, they are done in tcsetattr. 55 */ 56 57 speed_t cfgetispeed(termios_p) 58 struct termios *termios_p; 59 { 60 return termios_p->c_ispeed; 61 } 62 63 speed_t cfgetospeed(termios_p) 64 struct termios *termios_p; 65 { 66 return termios_p->c_ospeed; 67 } 68 69 speed_t cfsetispeed(termios_p, speed) 70 struct termios *termios_p; 71 speed_t speed; 72 { 73 termios_p->c_ispeed = speed; 74 return 0; 75 } 76 77 speed_t cfsetospeed(termios_p, speed) 78 struct termios *termios_p; 79 speed_t speed; 80 { 81 termios_p->c_ospeed = speed; 82 return 0; 83 } 84 85 static speed_t sg_to_tc_speed(speed) 86 int speed; 87 { 88 /* The speed encodings in sgtty.h and termios.h are different. Both are 89 * inflexible. Minix doesn't really support B0 but we map it through 90 * anyway. It doesn't support B50, B75 or B134. 91 */ 92 switch (speed) { 93 case B0: return 0; 94 case B110: return 110; 95 case B200: return 200; 96 case B300: return 300; 97 case B600: return 600; 98 case B1200: return 1200; 99 case B1800: return 1800; 100 case B2400: return 2400; 101 case B4800: return 4800; 102 case B9600: return 9600; 103 case B19200: return 19200; 104 #ifdef B28800 105 case B28800: return 28800; 106 #endif 107 #ifdef B38400 108 case B38400: return 38400; 109 #endif 110 #ifdef B57600 111 case B57600: return 57600; 112 #endif 113 #ifdef B115200 114 case B115200: return 115200; 115 #endif 116 default: return (speed_t)-1; 117 } 118 } 119 120 static int tc_to_sg_speed(speed) 121 speed_t speed; 122 { 123 /* Don't use a switch here in case the compiler is 16-bit and doesn't 124 * properly support longs (speed_t's) in switches. It turns out the 125 * switch is larger and slower for most compilers anyway! 126 */ 127 if (speed == 0) return 0; 128 if (speed == 110) return B110; 129 if (speed == 200) return B200; 130 if (speed == 300) return B300; 131 if (speed == 600) return B600; 132 if (speed == 1200) return B1200; 133 if (speed == 1800) return B1800; 134 if (speed == 2400) return B2400; 135 if (speed == 4800) return B4800; 136 if (speed == 9600) return B9600; 137 if (speed == 19200) return B19200; 138 #ifdef B28800 139 if (speed == 28800) return B28800; 140 #endif 141 #ifdef B38400 142 if (speed == 38400) return B38400; 143 #endif 144 #ifdef B57600 145 if (speed == 57600) return B57600; 146 #endif 147 #ifdef B115200 148 if (speed == 115200) return B115200; 149 #endif 150 return -1; 151 } 152 153 int tcgetattr(filedes, termios_p) 154 int filedes; 155 struct termios *termios_p; 156 { 157 struct sgttyb sgbuf; 158 struct tchars tcbuf; 159 160 if (ioctl(filedes, TIOCGETP, &sgbuf) < 0 161 || ioctl(filedes, TIOCGETC, (struct sgttyb *) &tcbuf) < 0) 162 { 163 return -1; 164 } 165 166 /* Minix input flags: 167 * BRKINT: forced off (break is not recognized) 168 * IGNBRK: forced on (break is not recognized) 169 * ICRNL: set if CRMOD is set and not RAW (CRMOD also controls output) 170 * IGNCR: forced off (ignoring cr's is not supported) 171 * INLCR: forced off (mapping nl's to cr's is not supported) 172 * ISTRIP: forced off (should be off for consoles, on for rs232 no RAW) 173 * IXOFF: forced off (rs232 uses CTS instead of XON/XOFF) 174 * IXON: forced on if not RAW 175 * PARMRK: forced off (no '\377', '\0', X sequence on errors) 176 * ? IGNPAR: forced off (input with parity/framing errors is kept) 177 * ? INPCK: forced off (input parity checking is not supported) 178 */ 179 termios_p->c_iflag = IGNBRK; 180 if (!(sgbuf.sg_flags & RAW)) 181 { 182 termios_p->c_iflag |= IXON; 183 if (sgbuf.sg_flags & CRMOD) 184 { 185 termios_p->c_iflag |= ICRNL; 186 } 187 } 188 189 /* Minix output flags: 190 * OPOST: set if CRMOD or XTABS is set 191 * XTABS: copied from sg_flags 192 * CRMOD: copied from sg_flags 193 */ 194 termios_p->c_oflag = sgbuf.sg_flags & (CRMOD | XTABS); 195 if (termios_p->c_oflag) 196 { 197 termios_p->c_oflag |= OPOST; 198 } 199 200 /* Minix local flags: 201 * ECHO: set if ECHO is set 202 * ECHOE: set if ECHO is set (ERASE echoed as error-corecting backspace) 203 * ECHOK: set if ECHO is set ('\n' echoed after KILL char) 204 * ECHONL: forced off ('\n' not echoed when ECHO isn't set) 205 * ICANON: set if neither CBREAK nor RAW 206 * IEXTEN: forced off 207 * ISIG: set if not RAW 208 * NOFLSH: forced off (input/output queues are always flushed) 209 * TOSTOP: forced off (no job control) 210 */ 211 termios_p->c_lflag = 0; 212 if (sgbuf.sg_flags & ECHO) 213 { 214 termios_p->c_lflag |= T_ECHO | ECHOE | ECHOK; 215 } 216 if (!(sgbuf.sg_flags & RAW)) 217 { 218 termios_p->c_lflag |= ISIG; 219 if (!(sgbuf.sg_flags & CBREAK)) 220 { 221 termios_p->c_lflag |= ICANON; 222 } 223 } 224 225 /* Minix control flags: 226 * CLOCAL: forced on (ignore modem status lines - not quite right) 227 * CREAD: forced on (receiver is always enabled) 228 * CSIZE: CS5-CS8 correspond directly to BITS5-BITS8 229 * CSTOPB: set for B110 (driver will generate 2 stop-bits than) 230 * HUPCL: forced off 231 * PARENB: set if EVENP or ODDP is set 232 * PARODD: set if ODDP is set 233 */ 234 termios_p->c_cflag = CLOCAL | CREAD; 235 switch (sgbuf.sg_flags & BITS8) 236 { 237 case BITS5: termios_p->c_cflag |= CS5; break; 238 case BITS6: termios_p->c_cflag |= CS6; break; 239 case BITS7: termios_p->c_cflag |= CS7; break; 240 case BITS8: termios_p->c_cflag |= CS8; break; 241 } 242 if (sgbuf.sg_flags & ODDP) 243 { 244 termios_p->c_cflag |= PARENB | PARODD; 245 } 246 if (sgbuf.sg_flags & EVENP) 247 { 248 termios_p->c_cflag |= PARENB; 249 } 250 if (sgbuf.sg_ispeed == B110) 251 { 252 termios_p->c_cflag |= CSTOPB; 253 } 254 255 /* Minix may give back different input and output baudrates, 256 * but only the input baudrate is valid for both. 257 * As our termios emulation will fail, if input baudrate differs 258 * from output baudrate, force them to be equal. 259 * Otherwise it would be very suprisingly not to be able to set 260 * the terminal back to the state returned by tcgetattr :). 261 */ 262 termios_p->c_ospeed = 263 termios_p->c_ispeed = 264 sg_to_tc_speed((unsigned char) sgbuf.sg_ispeed); 265 266 /* Minix control characters correspond directly except VSUSP and the 267 * important VMIN and VTIME are not really supported. 268 */ 269 termios_p->c_cc[VEOF] = tcbuf.t_eofc; 270 termios_p->c_cc[VEOL] = tcbuf.t_brkc; 271 termios_p->c_cc[VERASE] = sgbuf.sg_erase; 272 termios_p->c_cc[VINTR] = tcbuf.t_intrc; 273 termios_p->c_cc[VKILL] = sgbuf.sg_kill; 274 termios_p->c_cc[VQUIT] = tcbuf.t_quitc; 275 termios_p->c_cc[VSTART] = tcbuf.t_startc; 276 termios_p->c_cc[VSTOP] = tcbuf.t_stopc; 277 termios_p->c_cc[VMIN] = 1; 278 termios_p->c_cc[VTIME] = 0; 279 termios_p->c_cc[VSUSP] = 0; 280 281 return 0; 282 } 283 284 int tcsetattr(filedes, opt_actions, termios_p) 285 int filedes; 286 int opt_actions; 287 struct termios *termios_p; 288 { 289 struct sgttyb sgbuf; 290 struct tchars tcbuf; 291 int sgspeed; 292 293 /* Posix 1003.1-1988 page 135 says: 294 * Attempts to set unsupported baud rates shall be ignored, and it is 295 * implementation-defined whether an error is returned by any or all of 296 * cfsetispeed(), cfsetospeed(), or tcsetattr(). This refers both to 297 * changes to baud rates not supported by the hardware, and to changes 298 * setting the input and output baud rates to different values if the 299 * hardware does not support it. 300 * Ignoring means not to change the existing settings, doesn't it? 301 */ 302 if ((termios_p->c_ispeed != 0 && termios_p->c_ispeed != termios_p->c_ospeed) 303 || (sgspeed = tc_to_sg_speed(termios_p->c_ospeed)) < 0) 304 { 305 errno = EINVAL; 306 return -1; 307 } 308 309 sgbuf.sg_ispeed = sgbuf.sg_ospeed = sgspeed; 310 sgbuf.sg_flags = 0; 311 312 /* I don't know what should happen with requests that are not supported by 313 * old Minix drivers and therefore cannot be emulated. 314 * Returning an error may confuse the application (the values aren't really 315 * invalid or unsupported by the hardware, they just couldn't be satisfied 316 * by the driver). Not returning an error might be even worse because the 317 * driver will act different to what the application requires it to act 318 * after sucessfully setting the attributes as specified. 319 * Settings that cannot be emulated fully include: 320 * c_ospeed != 110 && c_cflag & CSTOPB 321 * c_ospeed == 110 && ! c_cflag & CSTOPB 322 * (c_cc[VMIN] != 1 || c_cc[VTIME] != 0) && ! c_lflag & ICANON 323 * c_lflag & ICANON && ! c_lflag & ISIG 324 * For the moment I just ignore these conflicts. 325 */ 326 327 if (termios_p->c_oflag & OPOST) 328 { 329 /* CRMOD isn't Posix and may conflict with ICRNL, which is Posix, 330 * so we just ignore it. 331 */ 332 if (termios_p->c_oflag & XTABS) 333 { 334 sgbuf.sg_flags |= XTABS; 335 } 336 } 337 338 if (termios_p->c_iflag & ICRNL) 339 { 340 /* We couldn't do it better :-(. */ 341 sgbuf.sg_flags |= CRMOD; 342 } 343 344 if (termios_p->c_lflag & T_ECHO) 345 { 346 sgbuf.sg_flags |= ECHO; 347 } 348 if (!(termios_p->c_lflag & ICANON)) 349 { 350 if (termios_p->c_lflag & ISIG) 351 { 352 sgbuf.sg_flags |= CBREAK; 353 } 354 else 355 { 356 sgbuf.sg_flags |= RAW; 357 } 358 } 359 360 switch (termios_p->c_cflag & CSIZE) 361 { 362 case CS5: sgbuf.sg_flags |= BITS5; break; 363 case CS6: sgbuf.sg_flags |= BITS6; break; 364 case CS7: sgbuf.sg_flags |= BITS7; break; 365 case CS8: sgbuf.sg_flags |= BITS8; break; 366 } 367 if (termios_p->c_cflag & PARENB) 368 { 369 if (termios_p->c_cflag & PARODD) 370 { 371 sgbuf.sg_flags |= ODDP; 372 } 373 else 374 { 375 sgbuf.sg_flags |= EVENP; 376 } 377 } 378 379 sgbuf.sg_erase = termios_p->c_cc[VERASE]; 380 sgbuf.sg_kill = termios_p->c_cc[VKILL]; 381 382 tcbuf.t_intrc = termios_p->c_cc[VINTR]; 383 tcbuf.t_quitc = termios_p->c_cc[VQUIT]; 384 tcbuf.t_startc = termios_p->c_cc[VSTART]; 385 tcbuf.t_stopc = termios_p->c_cc[VSTOP]; 386 tcbuf.t_eofc = termios_p->c_cc[VEOF]; 387 tcbuf.t_brkc = termios_p->c_cc[VEOL]; 388 389 return ioctl(filedes, TIOCSETP, &sgbuf) < 0 && 390 ioctl(filedes, TIOCSETC, (struct sgttyb *) &tcbuf) < 0 ? 391 -1 : 0; 392 } 393 #endif /* _MINIX && !_MINIX_VMD */ 394