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