1167465Smp/* $Header: /p/tcsh/cvsroot/tcsh/mi.termios.c,v 1.5 2006/03/02 18:46:44 christos Exp $ */ 259243Sobrien/* termios.c - fake termios interface using sgtty interface 359243Sobrien * by Magnus Doell and Bruce Evans. 459243Sobrien * 559243Sobrien */ 659243Sobrien#include "sh.h" 7167465SmpRCSID("$tcsh: mi.termios.c,v 1.5 2006/03/02 18:46:44 christos Exp $") 859243Sobrien 969408Sache#if defined(_MINIX) && !defined(_MINIX_VMD) 1059243Sobrien 1159243Sobrien 1259243Sobrien/* Undefine everything that clashes with sgtty.h. */ 1359243Sobrien#undef B0 1459243Sobrien#undef B50 1559243Sobrien#undef B75 1659243Sobrien#undef B110 1759243Sobrien#undef B134 1859243Sobrien#undef B150 1959243Sobrien#undef B200 2059243Sobrien#undef B300 2159243Sobrien#undef B600 2259243Sobrien#undef B1200 2359243Sobrien#undef B1800 2459243Sobrien#undef B2400 2559243Sobrien#undef B4800 2659243Sobrien#undef B9600 2759243Sobrien#undef B19200 2859243Sobrien#undef B28800 2959243Sobrien#undef B38400 3059243Sobrien#undef B57600 3159243Sobrien#undef B115200 3259243Sobrien/* Do not #undef CRMOD. We want a warning when they differ! */ 3359243Sobrien#undef ECHO 3459243Sobrien/* Do not #undef XTABS. We want a warning when they differ! */ 3559243Sobrien 3659243Sobrien/* Redefine some of the termios.h names just undefined with 'T_' prefixed 3759243Sobrien * to the name. Don't bother with the low speeds - Minix does not support 3859243Sobrien * them. Add support for higher speeds (speeds are now easy and don't need 3959243Sobrien * defines because they are not encoded). 4059243Sobrien */ 4159243Sobrien#define T_ECHO 000001 4259243Sobrien 4359243Sobrien#include <errno.h> 4459243Sobrien#include <sgtty.h> 4559243Sobrien 4659243Sobrienstatic _PROTOTYPE( int tc_to_sg_speed, (speed_t speed) ); 4759243Sobrienstatic _PROTOTYPE( speed_t sg_to_tc_speed, (int speed) ); 4859243Sobrien#define B19200 192 4959243Sobrien 5059243Sobrien/* The speed get/set functions could be macros in the Minix implementation 5159243Sobrien * because there are speed fields in the structure with no fancy packing 5259243Sobrien * and it is not practical to check the values outside the driver. 5359243Sobrien * Where tests are necessary because the driver acts different from what 5459243Sobrien * POSIX requires, they are done in tcsetattr. 5559243Sobrien */ 5659243Sobrien 5759243Sobrienspeed_t cfgetispeed(termios_p) 5859243Sobrienstruct termios *termios_p; 5959243Sobrien{ 6059243Sobrien return termios_p->c_ispeed; 6159243Sobrien} 6259243Sobrien 6359243Sobrienspeed_t cfgetospeed(termios_p) 6459243Sobrienstruct termios *termios_p; 6559243Sobrien{ 6659243Sobrien return termios_p->c_ospeed; 6759243Sobrien} 6859243Sobrien 6959243Sobrienspeed_t cfsetispeed(termios_p, speed) 7059243Sobrienstruct termios *termios_p; 7159243Sobrienspeed_t speed; 7259243Sobrien{ 7359243Sobrien termios_p->c_ispeed = speed; 7459243Sobrien return 0; 7559243Sobrien} 7659243Sobrien 7759243Sobrienspeed_t cfsetospeed(termios_p, speed) 7859243Sobrienstruct termios *termios_p; 7959243Sobrienspeed_t speed; 8059243Sobrien{ 8159243Sobrien termios_p->c_ospeed = speed; 8259243Sobrien return 0; 8359243Sobrien} 8459243Sobrien 8559243Sobrienstatic speed_t sg_to_tc_speed(speed) 8659243Sobrienint speed; 8759243Sobrien{ 8859243Sobrien /* The speed encodings in sgtty.h and termios.h are different. Both are 8959243Sobrien * inflexible. Minix doesn't really support B0 but we map it through 9059243Sobrien * anyway. It doesn't support B50, B75 or B134. 9159243Sobrien */ 9259243Sobrien switch (speed) { 9359243Sobrien case B0: return 0; 9459243Sobrien case B110: return 110; 9559243Sobrien case B200: return 200; 9659243Sobrien case B300: return 300; 9759243Sobrien case B600: return 600; 9859243Sobrien case B1200: return 1200; 9959243Sobrien case B1800: return 1800; 10059243Sobrien case B2400: return 2400; 10159243Sobrien case B4800: return 4800; 10259243Sobrien case B9600: return 9600; 10359243Sobrien case B19200: return 19200; 10459243Sobrien#ifdef B28800 10559243Sobrien case B28800: return 28800; 10659243Sobrien#endif 10759243Sobrien#ifdef B38400 10859243Sobrien case B38400: return 38400; 10959243Sobrien#endif 11059243Sobrien#ifdef B57600 11159243Sobrien case B57600: return 57600; 11259243Sobrien#endif 11359243Sobrien#ifdef B115200 11459243Sobrien case B115200: return 115200; 11559243Sobrien#endif 11659243Sobrien default: return (speed_t)-1; 11759243Sobrien } 11859243Sobrien} 11959243Sobrien 12059243Sobrienstatic int tc_to_sg_speed(speed) 12159243Sobrienspeed_t speed; 12259243Sobrien{ 12359243Sobrien /* Don't use a switch here in case the compiler is 16-bit and doesn't 12459243Sobrien * properly support longs (speed_t's) in switches. It turns out the 12559243Sobrien * switch is larger and slower for most compilers anyway! 12659243Sobrien */ 12759243Sobrien if (speed == 0) return 0; 12859243Sobrien if (speed == 110) return B110; 12959243Sobrien if (speed == 200) return B200; 13059243Sobrien if (speed == 300) return B300; 13159243Sobrien if (speed == 600) return B600; 13259243Sobrien if (speed == 1200) return B1200; 13359243Sobrien if (speed == 1800) return B1800; 13459243Sobrien if (speed == 2400) return B2400; 13559243Sobrien if (speed == 4800) return B4800; 13659243Sobrien if (speed == 9600) return B9600; 13759243Sobrien if (speed == 19200) return B19200; 13859243Sobrien#ifdef B28800 13959243Sobrien if (speed == 28800) return B28800; 14059243Sobrien#endif 14159243Sobrien#ifdef B38400 14259243Sobrien if (speed == 38400) return B38400; 14359243Sobrien#endif 14459243Sobrien#ifdef B57600 14559243Sobrien if (speed == 57600) return B57600; 14659243Sobrien#endif 14759243Sobrien#ifdef B115200 14859243Sobrien if (speed == 115200) return B115200; 14959243Sobrien#endif 15059243Sobrien return -1; 15159243Sobrien} 15259243Sobrien 15359243Sobrienint tcgetattr(filedes, termios_p) 15459243Sobrienint filedes; 15559243Sobrienstruct termios *termios_p; 15659243Sobrien{ 15759243Sobrien struct sgttyb sgbuf; 15859243Sobrien struct tchars tcbuf; 15959243Sobrien 16059243Sobrien if (ioctl(filedes, TIOCGETP, &sgbuf) < 0 16159243Sobrien || ioctl(filedes, TIOCGETC, (struct sgttyb *) &tcbuf) < 0) 16259243Sobrien { 16359243Sobrien return -1; 16459243Sobrien } 16559243Sobrien 16659243Sobrien /* Minix input flags: 16759243Sobrien * BRKINT: forced off (break is not recognized) 16859243Sobrien * IGNBRK: forced on (break is not recognized) 16959243Sobrien * ICRNL: set if CRMOD is set and not RAW (CRMOD also controls output) 17059243Sobrien * IGNCR: forced off (ignoring cr's is not supported) 17159243Sobrien * INLCR: forced off (mapping nl's to cr's is not supported) 17259243Sobrien * ISTRIP: forced off (should be off for consoles, on for rs232 no RAW) 17359243Sobrien * IXOFF: forced off (rs232 uses CTS instead of XON/XOFF) 17459243Sobrien * IXON: forced on if not RAW 17559243Sobrien * PARMRK: forced off (no '\377', '\0', X sequence on errors) 17659243Sobrien * ? IGNPAR: forced off (input with parity/framing errors is kept) 17759243Sobrien * ? INPCK: forced off (input parity checking is not supported) 17859243Sobrien */ 17959243Sobrien termios_p->c_iflag = IGNBRK; 18059243Sobrien if (!(sgbuf.sg_flags & RAW)) 18159243Sobrien { 18259243Sobrien termios_p->c_iflag |= IXON; 18359243Sobrien if (sgbuf.sg_flags & CRMOD) 18459243Sobrien { 18559243Sobrien termios_p->c_iflag |= ICRNL; 18659243Sobrien } 18759243Sobrien } 18859243Sobrien 18959243Sobrien /* Minix output flags: 19059243Sobrien * OPOST: set if CRMOD or XTABS is set 19159243Sobrien * XTABS: copied from sg_flags 19259243Sobrien * CRMOD: copied from sg_flags 19359243Sobrien */ 19459243Sobrien termios_p->c_oflag = sgbuf.sg_flags & (CRMOD | XTABS); 19559243Sobrien if (termios_p->c_oflag) 19659243Sobrien { 19759243Sobrien termios_p->c_oflag |= OPOST; 19859243Sobrien } 19959243Sobrien 20059243Sobrien /* Minix local flags: 20159243Sobrien * ECHO: set if ECHO is set 20259243Sobrien * ECHOE: set if ECHO is set (ERASE echoed as error-corecting backspace) 20359243Sobrien * ECHOK: set if ECHO is set ('\n' echoed after KILL char) 20459243Sobrien * ECHONL: forced off ('\n' not echoed when ECHO isn't set) 20559243Sobrien * ICANON: set if neither CBREAK nor RAW 20659243Sobrien * IEXTEN: forced off 20759243Sobrien * ISIG: set if not RAW 20859243Sobrien * NOFLSH: forced off (input/output queues are always flushed) 20959243Sobrien * TOSTOP: forced off (no job control) 21059243Sobrien */ 21159243Sobrien termios_p->c_lflag = 0; 21259243Sobrien if (sgbuf.sg_flags & ECHO) 21359243Sobrien { 21459243Sobrien termios_p->c_lflag |= T_ECHO | ECHOE | ECHOK; 21559243Sobrien } 21659243Sobrien if (!(sgbuf.sg_flags & RAW)) 21759243Sobrien { 21859243Sobrien termios_p->c_lflag |= ISIG; 21959243Sobrien if (!(sgbuf.sg_flags & CBREAK)) 22059243Sobrien { 22159243Sobrien termios_p->c_lflag |= ICANON; 22259243Sobrien } 22359243Sobrien } 22459243Sobrien 22559243Sobrien /* Minix control flags: 22659243Sobrien * CLOCAL: forced on (ignore modem status lines - not quite right) 22759243Sobrien * CREAD: forced on (receiver is always enabled) 22859243Sobrien * CSIZE: CS5-CS8 correspond directly to BITS5-BITS8 22959243Sobrien * CSTOPB: set for B110 (driver will generate 2 stop-bits than) 23059243Sobrien * HUPCL: forced off 23159243Sobrien * PARENB: set if EVENP or ODDP is set 23259243Sobrien * PARODD: set if ODDP is set 23359243Sobrien */ 23459243Sobrien termios_p->c_cflag = CLOCAL | CREAD; 23559243Sobrien switch (sgbuf.sg_flags & BITS8) 23659243Sobrien { 23759243Sobrien case BITS5: termios_p->c_cflag |= CS5; break; 23859243Sobrien case BITS6: termios_p->c_cflag |= CS6; break; 23959243Sobrien case BITS7: termios_p->c_cflag |= CS7; break; 24059243Sobrien case BITS8: termios_p->c_cflag |= CS8; break; 24159243Sobrien } 24259243Sobrien if (sgbuf.sg_flags & ODDP) 24359243Sobrien { 24459243Sobrien termios_p->c_cflag |= PARENB | PARODD; 24559243Sobrien } 24659243Sobrien if (sgbuf.sg_flags & EVENP) 24759243Sobrien { 24859243Sobrien termios_p->c_cflag |= PARENB; 24959243Sobrien } 25059243Sobrien if (sgbuf.sg_ispeed == B110) 25159243Sobrien { 25259243Sobrien termios_p->c_cflag |= CSTOPB; 25359243Sobrien } 25459243Sobrien 25559243Sobrien /* Minix may give back different input and output baudrates, 25659243Sobrien * but only the input baudrate is valid for both. 25759243Sobrien * As our termios emulation will fail, if input baudrate differs 25859243Sobrien * from output baudrate, force them to be equal. 25959243Sobrien * Otherwise it would be very suprisingly not to be able to set 26059243Sobrien * the terminal back to the state returned by tcgetattr :). 26159243Sobrien */ 26259243Sobrien termios_p->c_ospeed = 26359243Sobrien termios_p->c_ispeed = 26459243Sobrien sg_to_tc_speed((unsigned char) sgbuf.sg_ispeed); 26559243Sobrien 26659243Sobrien /* Minix control characters correspond directly except VSUSP and the 26759243Sobrien * important VMIN and VTIME are not really supported. 26859243Sobrien */ 26959243Sobrien termios_p->c_cc[VEOF] = tcbuf.t_eofc; 27059243Sobrien termios_p->c_cc[VEOL] = tcbuf.t_brkc; 27159243Sobrien termios_p->c_cc[VERASE] = sgbuf.sg_erase; 27259243Sobrien termios_p->c_cc[VINTR] = tcbuf.t_intrc; 27359243Sobrien termios_p->c_cc[VKILL] = sgbuf.sg_kill; 27459243Sobrien termios_p->c_cc[VQUIT] = tcbuf.t_quitc; 27559243Sobrien termios_p->c_cc[VSTART] = tcbuf.t_startc; 27659243Sobrien termios_p->c_cc[VSTOP] = tcbuf.t_stopc; 27759243Sobrien termios_p->c_cc[VMIN] = 1; 27859243Sobrien termios_p->c_cc[VTIME] = 0; 27959243Sobrien termios_p->c_cc[VSUSP] = 0; 28059243Sobrien 28159243Sobrien return 0; 28259243Sobrien} 28359243Sobrien 28459243Sobrienint tcsetattr(filedes, opt_actions, termios_p) 28559243Sobrienint filedes; 28659243Sobrienint opt_actions; 28759243Sobrienstruct termios *termios_p; 28859243Sobrien{ 28959243Sobrien struct sgttyb sgbuf; 29059243Sobrien struct tchars tcbuf; 29159243Sobrien int sgspeed; 29259243Sobrien 29359243Sobrien /* Posix 1003.1-1988 page 135 says: 29459243Sobrien * Attempts to set unsupported baud rates shall be ignored, and it is 29559243Sobrien * implementation-defined whether an error is returned by any or all of 29659243Sobrien * cfsetispeed(), cfsetospeed(), or tcsetattr(). This refers both to 29759243Sobrien * changes to baud rates not supported by the hardware, and to changes 29859243Sobrien * setting the input and output baud rates to different values if the 29959243Sobrien * hardware does not support it. 30059243Sobrien * Ignoring means not to change the existing settings, doesn't it? 30159243Sobrien */ 30259243Sobrien if ((termios_p->c_ispeed != 0 && termios_p->c_ispeed != termios_p->c_ospeed) 30359243Sobrien || (sgspeed = tc_to_sg_speed(termios_p->c_ospeed)) < 0) 30459243Sobrien { 30559243Sobrien errno = EINVAL; 30659243Sobrien return -1; 30759243Sobrien } 30859243Sobrien 30959243Sobrien sgbuf.sg_ispeed = sgbuf.sg_ospeed = sgspeed; 31059243Sobrien sgbuf.sg_flags = 0; 31159243Sobrien 31259243Sobrien /* I don't know what should happen with requests that are not supported by 31359243Sobrien * old Minix drivers and therefore cannot be emulated. 31459243Sobrien * Returning an error may confuse the application (the values aren't really 31559243Sobrien * invalid or unsupported by the hardware, they just couldn't be satisfied 31659243Sobrien * by the driver). Not returning an error might be even worse because the 31759243Sobrien * driver will act different to what the application requires it to act 31859243Sobrien * after sucessfully setting the attributes as specified. 31959243Sobrien * Settings that cannot be emulated fully include: 32059243Sobrien * c_ospeed != 110 && c_cflag & CSTOPB 32159243Sobrien * c_ospeed == 110 && ! c_cflag & CSTOPB 32259243Sobrien * (c_cc[VMIN] != 1 || c_cc[VTIME] != 0) && ! c_lflag & ICANON 32359243Sobrien * c_lflag & ICANON && ! c_lflag & ISIG 32459243Sobrien * For the moment I just ignore these conflicts. 32559243Sobrien */ 32659243Sobrien 32759243Sobrien if (termios_p->c_oflag & OPOST) 32859243Sobrien { 32959243Sobrien /* CRMOD isn't Posix and may conflict with ICRNL, which is Posix, 33059243Sobrien * so we just ignore it. 33159243Sobrien */ 33259243Sobrien if (termios_p->c_oflag & XTABS) 33359243Sobrien { 33459243Sobrien sgbuf.sg_flags |= XTABS; 33559243Sobrien } 33659243Sobrien } 33759243Sobrien 33859243Sobrien if (termios_p->c_iflag & ICRNL) 33959243Sobrien { 34059243Sobrien /* We couldn't do it better :-(. */ 34159243Sobrien sgbuf.sg_flags |= CRMOD; 34259243Sobrien } 34359243Sobrien 34459243Sobrien if (termios_p->c_lflag & T_ECHO) 34559243Sobrien { 34659243Sobrien sgbuf.sg_flags |= ECHO; 34759243Sobrien } 34859243Sobrien if (!(termios_p->c_lflag & ICANON)) 34959243Sobrien { 35059243Sobrien if (termios_p->c_lflag & ISIG) 35159243Sobrien { 35259243Sobrien sgbuf.sg_flags |= CBREAK; 35359243Sobrien } 35459243Sobrien else 35559243Sobrien { 35659243Sobrien sgbuf.sg_flags |= RAW; 35759243Sobrien } 35859243Sobrien } 35959243Sobrien 36059243Sobrien switch (termios_p->c_cflag & CSIZE) 36159243Sobrien { 36259243Sobrien case CS5: sgbuf.sg_flags |= BITS5; break; 36359243Sobrien case CS6: sgbuf.sg_flags |= BITS6; break; 36459243Sobrien case CS7: sgbuf.sg_flags |= BITS7; break; 36559243Sobrien case CS8: sgbuf.sg_flags |= BITS8; break; 36659243Sobrien } 36759243Sobrien if (termios_p->c_cflag & PARENB) 36859243Sobrien { 36959243Sobrien if (termios_p->c_cflag & PARODD) 37059243Sobrien { 37159243Sobrien sgbuf.sg_flags |= ODDP; 37259243Sobrien } 37359243Sobrien else 37459243Sobrien { 37559243Sobrien sgbuf.sg_flags |= EVENP; 37659243Sobrien } 37759243Sobrien } 37859243Sobrien 37959243Sobrien sgbuf.sg_erase = termios_p->c_cc[VERASE]; 38059243Sobrien sgbuf.sg_kill = termios_p->c_cc[VKILL]; 38159243Sobrien 38259243Sobrien tcbuf.t_intrc = termios_p->c_cc[VINTR]; 38359243Sobrien tcbuf.t_quitc = termios_p->c_cc[VQUIT]; 38459243Sobrien tcbuf.t_startc = termios_p->c_cc[VSTART]; 38559243Sobrien tcbuf.t_stopc = termios_p->c_cc[VSTOP]; 38659243Sobrien tcbuf.t_eofc = termios_p->c_cc[VEOF]; 38759243Sobrien tcbuf.t_brkc = termios_p->c_cc[VEOL]; 38859243Sobrien 38959243Sobrien return ioctl(filedes, TIOCSETP, &sgbuf) < 0 && 39059243Sobrien ioctl(filedes, TIOCSETC, (struct sgttyb *) &tcbuf) < 0 ? 39159243Sobrien -1 : 0; 39259243Sobrien} 39369408Sache#endif /* _MINIX && !_MINIX_VMD */ 394