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