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