1 /* termios.c - fake termios interface using sgtty interface
2 * by Magnus Doell and Bruce Evans.
7 #if defined(_MINIX) && !defined(_MINIX_VMD)
10 /* Undefine everything that clashes with sgtty.h. */
30 /* Do not #undef CRMOD. We want a warning when they differ! */
32 /* Do not #undef XTABS. We want a warning when they differ! */
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).
44 static _PROTOTYPE( int tc_to_sg_speed, (speed_t speed) );
45 static _PROTOTYPE( speed_t sg_to_tc_speed, (int speed) );
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.
55 speed_t cfgetispeed(termios_p)
56 struct termios *termios_p;
58 return termios_p->c_ispeed;
61 speed_t cfgetospeed(termios_p)
62 struct termios *termios_p;
64 return termios_p->c_ospeed;
67 speed_t cfsetispeed(termios_p, speed)
68 struct termios *termios_p;
71 termios_p->c_ispeed = speed;
75 speed_t cfsetospeed(termios_p, speed)
76 struct termios *termios_p;
79 termios_p->c_ospeed = speed;
83 static speed_t sg_to_tc_speed(speed)
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.
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;
103 case B28800: return 28800;
106 case B38400: return 38400;
109 case B57600: return 57600;
112 case B115200: return 115200;
114 default: return (speed_t)-1;
118 static int tc_to_sg_speed(speed)
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!
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;
137 if (speed == 28800) return B28800;
140 if (speed == 38400) return B38400;
143 if (speed == 57600) return B57600;
146 if (speed == 115200) return B115200;
151 int tcgetattr(filedes, termios_p)
153 struct termios *termios_p;
158 if (ioctl(filedes, TIOCGETP, &sgbuf) < 0
159 || ioctl(filedes, TIOCGETC, (struct sgttyb *) &tcbuf) < 0)
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)
177 termios_p->c_iflag = IGNBRK;
178 if (!(sgbuf.sg_flags & RAW))
180 termios_p->c_iflag |= IXON;
181 if (sgbuf.sg_flags & CRMOD)
183 termios_p->c_iflag |= ICRNL;
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
192 termios_p->c_oflag = sgbuf.sg_flags & (CRMOD | XTABS);
193 if (termios_p->c_oflag)
195 termios_p->c_oflag |= OPOST;
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
205 * ISIG: set if not RAW
206 * NOFLSH: forced off (input/output queues are always flushed)
207 * TOSTOP: forced off (no job control)
209 termios_p->c_lflag = 0;
210 if (sgbuf.sg_flags & ECHO)
212 termios_p->c_lflag |= T_ECHO | ECHOE | ECHOK;
214 if (!(sgbuf.sg_flags & RAW))
216 termios_p->c_lflag |= ISIG;
217 if (!(sgbuf.sg_flags & CBREAK))
219 termios_p->c_lflag |= ICANON;
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)
229 * PARENB: set if EVENP or ODDP is set
230 * PARODD: set if ODDP is set
232 termios_p->c_cflag = CLOCAL | CREAD;
233 switch (sgbuf.sg_flags & BITS8)
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;
240 if (sgbuf.sg_flags & ODDP)
242 termios_p->c_cflag |= PARENB | PARODD;
244 if (sgbuf.sg_flags & EVENP)
246 termios_p->c_cflag |= PARENB;
248 if (sgbuf.sg_ispeed == B110)
250 termios_p->c_cflag |= CSTOPB;
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 :).
260 termios_p->c_ospeed =
261 termios_p->c_ispeed =
262 sg_to_tc_speed((unsigned char) sgbuf.sg_ispeed);
264 /* Minix control characters correspond directly except VSUSP and the
265 * important VMIN and VTIME are not really supported.
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;
282 int tcsetattr(filedes, opt_actions, termios_p)
285 struct termios *termios_p;
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?
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)
307 sgbuf.sg_ispeed = sgbuf.sg_ospeed = sgspeed;
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.
325 if (termios_p->c_oflag & OPOST)
327 /* CRMOD isn't Posix and may conflict with ICRNL, which is Posix,
328 * so we just ignore it.
330 if (termios_p->c_oflag & XTABS)
332 sgbuf.sg_flags |= XTABS;
336 if (termios_p->c_iflag & ICRNL)
338 /* We couldn't do it better :-(. */
339 sgbuf.sg_flags |= CRMOD;
342 if (termios_p->c_lflag & T_ECHO)
344 sgbuf.sg_flags |= ECHO;
346 if (!(termios_p->c_lflag & ICANON))
348 if (termios_p->c_lflag & ISIG)
350 sgbuf.sg_flags |= CBREAK;
354 sgbuf.sg_flags |= RAW;
358 switch (termios_p->c_cflag & CSIZE)
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;
365 if (termios_p->c_cflag & PARENB)
367 if (termios_p->c_cflag & PARODD)
369 sgbuf.sg_flags |= ODDP;
373 sgbuf.sg_flags |= EVENP;
377 sgbuf.sg_erase = termios_p->c_cc[VERASE];
378 sgbuf.sg_kill = termios_p->c_cc[VKILL];
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];
387 return ioctl(filedes, TIOCSETP, &sgbuf) < 0 &&
388 ioctl(filedes, TIOCSETC, (struct sgttyb *) &tcbuf) < 0 ?
391 #endif /* _MINIX && !_MINIX_VMD */