/contrib/tcsh/mi.termios.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 393 lines · 258 code · 33 blank · 102 comment · 59 complexity · 561f7bcad895bdf2c8213243fa08b900 MD5 · raw file

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