summaryrefslogtreecommitdiff
path: root/pico/osdep/raw.c
diff options
context:
space:
mode:
Diffstat (limited to 'pico/osdep/raw.c')
-rw-r--r--pico/osdep/raw.c449
1 files changed, 449 insertions, 0 deletions
diff --git a/pico/osdep/raw.c b/pico/osdep/raw.c
new file mode 100644
index 00000000..a886e0b6
--- /dev/null
+++ b/pico/osdep/raw.c
@@ -0,0 +1,449 @@
+#if !defined(lint) && !defined(DOS)
+static char rcsid[] = "$Id: raw.c 761 2007-10-23 22:35:18Z hubert@u.washington.edu $";
+#endif
+
+/*
+ * ========================================================================
+ * Copyright 2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * ========================================================================
+ */
+
+/*
+ * TTY setup routines.
+ */
+
+#include <system.h>
+#include <general.h>
+
+#include "../estruct.h"
+
+#include "raw.h"
+
+
+#if HAS_TERMIOS
+/*
+ * These are the TERMIOS-style (POSIX) routines.
+ */
+
+static struct termios _raw_tty, _original_tty;
+
+#elif HAS_TERMIO
+/*
+ * These are the TERMIO-style (System V) routines.
+ */
+
+static struct termio _raw_tty, _original_tty;
+
+#else /* RAW_BSD */
+/*
+ * These are for the BSD-style routines.
+ */
+
+static struct sgttyb _raw_tty, _original_tty;
+static struct ltchars _raw_ltchars, _original_ltchars;
+static struct tchars _raw_tchars, _original_tchars;
+static int _raw_lmode, _original_lmode;
+
+#endif
+
+/*
+ * current raw state
+ */
+static short _inraw = 0;
+
+/*
+ * Set up the tty driver
+ *
+ * Args: state -- which state to put it in. 1 means go into raw (cbreak),
+ * 0 out of raw.
+ *
+ * Result: returns 0 if successful and -1 if not.
+ */
+int
+Raw(int state)
+{
+ /** state is either ON or OFF, as indicated by call **/
+ /* Check return code only on first call. If it fails we're done for and
+ if it goes OK the others will probably go OK too. */
+
+ if(state == 0 && _inraw){
+ /*----- restore state to original -----*/
+
+#if HAS_TERMIOS
+
+ if(tcsetattr(STDIN_FD, TCSADRAIN, &_original_tty) < 0)
+ return -1;
+
+#elif HAS_TERMIO
+
+ if(ioctl(STDIN_FD, TCSETAW, &_original_tty) < 0)
+ return(-1);
+
+#else /* RAW_BSD */
+
+ if(ioctl(STDIN_FD, TIOCSETP, &_original_tty) < 0)
+ return(-1);
+
+ (void)ioctl(STDIN_FD, TIOCSLTC, &_original_ltchars);
+ (void)ioctl(STDIN_FD, TIOCSETC, &_original_tchars);
+ (void)ioctl(STDIN_FD, TIOCLSET, &_original_lmode);
+
+#endif
+
+ _inraw = 0;
+ }
+ else if(state == 1 && ! _inraw){
+ /*----- Go into raw mode (cbreak actually) ----*/
+
+#if HAS_TERMIOS
+
+ if(tcgetattr(STDIN_FD, &_original_tty) < 0)
+ return -1;
+
+ tcgetattr(STDIN_FD, &_raw_tty);
+ _raw_tty.c_lflag &= ~(ICANON | ECHO | IEXTEN); /* noecho raw mode */
+ _raw_tty.c_lflag &= ~ISIG; /* disable signals */
+ _raw_tty.c_iflag &= ~ICRNL; /* turn off CR->NL on input */
+ _raw_tty.c_oflag &= ~ONLCR; /* turn off NL->CR on output */
+
+ _raw_tty.c_cc[VMIN] = '\01'; /* min # of chars to queue */
+ _raw_tty.c_cc[VTIME] = '\0'; /* min time to wait for input*/
+ _raw_tty.c_cc[VINTR] = ctrl('C'); /* make it our special char */
+ _raw_tty.c_cc[VQUIT] = 0;
+ _raw_tty.c_cc[VSUSP] = 0;
+ tcsetattr(STDIN_FD, TCSADRAIN, &_raw_tty);
+
+#elif HAS_TERMIO
+
+ if(ioctl(STDIN_FD, TCGETA, &_original_tty) < 0)
+ return(-1);
+
+ (void)ioctl(STDIN_FD, TCGETA, &_raw_tty); /** again! **/
+ _raw_tty.c_lflag &= ~(ICANON | ECHO); /* noecho raw mode */
+ _raw_tty.c_lflag &= ~ISIG; /* disable signals */
+ _raw_tty.c_iflag &= ~ICRNL; /* turn off CR->NL on input */
+ _raw_tty.c_oflag &= ~ONLCR; /* turn off NL->CR on output */
+ _raw_tty.c_cc[VMIN] = 1; /* min # of chars to queue */
+ _raw_tty.c_cc[VTIME] = 0; /* min time to wait for input*/
+ _raw_tty.c_cc[VINTR] = ctrl('C'); /* make it our special char */
+ _raw_tty.c_cc[VQUIT] = 0;
+ (void)ioctl(STDIN_FD, TCSETAW, &_raw_tty);
+
+#else /* RAW_BSD */
+ if(ioctl(STDIN_FD, TIOCGETP, &_original_tty) < 0)
+ return(-1);
+
+ (void)ioctl(STDIN_FD, TIOCGETP, &_raw_tty);
+ (void)ioctl(STDIN_FD, TIOCGETC, &_original_tchars);
+ (void)ioctl(STDIN_FD, TIOCGETC, &_raw_tchars);
+ (void)ioctl(STDIN_FD, TIOCGLTC, &_original_ltchars);
+ (void)ioctl(STDIN_FD, TIOCGLTC, &_raw_ltchars);
+ (void)ioctl(STDIN_FD, TIOCLGET, &_original_lmode);
+ (void)ioctl(STDIN_FD, TIOCLGET, &_raw_lmode);
+
+ _raw_tty.sg_flags &= ~(ECHO); /* echo off */
+ _raw_tty.sg_flags |= CBREAK; /* raw on */
+ _raw_tty.sg_flags &= ~CRMOD; /* Turn off CR -> LF mapping */
+
+ _raw_tchars.t_intrc = -1; /* Turn off ^C and ^D */
+ _raw_tchars.t_eofc = -1;
+
+ _raw_ltchars.t_lnextc = -1; /* Turn off ^V so we can use it */
+ _raw_ltchars.t_dsuspc = -1; /* Turn off ^Y so we can use it */
+ _raw_ltchars.t_suspc = -1; /* Turn off ^Z; we just read 'em */
+ _raw_ltchars.t_werasc = -1; /* Turn off ^w word erase */
+ _raw_ltchars.t_rprntc = -1; /* Turn off ^R reprint line */
+ _raw_ltchars.t_flushc = -1; /* Turn off ^O output flush */
+
+ (void)ioctl(STDIN_FD, TIOCSETP, &_raw_tty);
+ (void)ioctl(STDIN_FD, TIOCSLTC, &_raw_ltchars);
+ (void)ioctl(STDIN_FD, TIOCSETC, &_raw_tchars);
+ (void)ioctl(STDIN_FD, TIOCLSET, &_raw_lmode);
+#endif
+ _inraw = 1;
+ }
+
+ return(0);
+}
+
+
+/*
+ * Set up the tty driver to use XON/XOFF flow control
+ *
+ * Args: state -- True to make sure XON/XOFF turned on, FALSE off.
+ *
+ * Result: none.
+ */
+void
+xonxoff_proc(int state)
+{
+ if(_inraw){
+ if(state){
+#if HAS_TERMIOS
+
+ if(!(_raw_tty.c_iflag & IXON)){
+ _raw_tty.c_iflag |= IXON;
+ tcsetattr (STDIN_FD, TCSADRAIN, &_raw_tty);
+ }
+
+#elif HAS_TERMIO
+
+ if(!(_raw_tty.c_iflag & IXON)){
+ _raw_tty.c_iflag |= IXON; /* turn ON ^S/^Q on input */
+ (void)ioctl(STDIN_FD, TCSETAW, &_raw_tty);
+
+#else /* RAW_BSD */
+
+ if(_raw_tchars.t_startc == -1 || _raw_tchars.t_stopc == -1){
+ _raw_tchars.t_startc = 'Q' - '@'; /* Turn ON ^S/^Q */
+ _raw_tchars.t_stopc = 'S' - '@';
+ (void)ioctl(STDIN_FD, TIOCSETC, &_raw_tchars);
+ }
+
+#endif
+ }
+ else{
+#if HAS_TERMIOS
+
+ if(_raw_tty.c_iflag & IXON){
+ _raw_tty.c_iflag &= ~IXON; /* turn off ^S/^Q on input */
+ tcsetattr (STDIN_FD, TCSADRAIN, &_raw_tty);
+ }
+
+#elif HAS_TERMIO
+
+ if(_raw_tty.c_iflag & IXON){
+ _raw_tty.c_iflag &= ~IXON; /* turn off ^S/^Q on input */
+ (void)ioctl(STDIN_FD, TCSETAW, &_raw_tty);
+ }
+
+#else /* RAW_BSD */
+ if(!(_raw_tchars.t_startc == -1 && _raw_tchars.t_stopc == -1)){
+ _raw_tchars.t_startc = -1; /* Turn off ^S/^Q */
+ _raw_tchars.t_stopc = -1;
+ (void)ioctl(STDIN_FD, TIOCSETC, &_raw_tchars);
+ }
+#endif
+ }
+ }
+}
+
+
+/*
+ * Set up the tty driver to do LF->CR translation
+ *
+ * Args: state -- True to turn on translation, false to write raw LF's
+ *
+ * Result: none.
+ */
+void
+crlf_proc(int state)
+{
+ if(_inraw){
+ if(state){ /* turn ON NL->CR on output */
+#if HAS_TERMIOS
+
+ if(!(_raw_tty.c_oflag & ONLCR)){
+ _raw_tty.c_oflag |= ONLCR;
+ tcsetattr (STDIN_FD, TCSADRAIN, &_raw_tty);
+ }
+
+#elif HAS_TERMIO
+
+ if(!(_raw_tty.c_oflag & ONLCR)){
+ _raw_tty.c_oflag |= ONLCR;
+ (void)ioctl(STDIN_FD, TCSETAW, &_raw_tty);
+ }
+
+#else /* RAW_BSD */
+ if(!(_raw_tty.sg_flags & CRMOD)){
+ _raw_tty.sg_flags |= CRMOD;
+ (void)ioctl(STDIN_FD, TIOCSETP, &_raw_tty);
+ }
+#endif
+ }
+ else{ /* turn OFF NL-CR on output */
+#if HAS_TERMIOS
+
+ if(_raw_tty.c_oflag & ONLCR){
+ _raw_tty.c_oflag &= ~ONLCR;
+ tcsetattr (STDIN_FD, TCSADRAIN, &_raw_tty);
+ }
+
+#elif HAS_TERMIO
+
+ if(_raw_tty.c_oflag & ONLCR){
+ _raw_tty.c_oflag &= ~ONLCR;
+ (void)ioctl(STDIN_FD, TCSETAW, &_raw_tty);
+ }
+
+#else /* RAW_BSD */
+
+ if(_raw_tty.sg_flags & CRMOD){
+ _raw_tty.sg_flags &= ~CRMOD;
+ (void)ioctl(STDIN_FD, TIOCSETP, &_raw_tty);
+ }
+
+#endif
+ }
+ }
+}
+
+
+/*
+ * Set up the tty driver to hanle interrupt char
+ *
+ * Args: state -- True to turn on interrupt char, false to not
+ *
+ * Result: tty driver that'll send us SIGINT or not
+ */
+void
+intr_proc(int state)
+{
+ if(_inraw){
+ if(state){
+#if HAS_TERMIOS
+
+ _raw_tty.c_lflag |= ISIG; /* enable signals */
+ tcsetattr(STDIN_FD, TCSADRAIN, &_raw_tty);
+
+#elif HAS_TERMIO
+
+ _raw_tty.c_lflag |= ISIG; /* enable signals */
+ (void)ioctl(STDIN_FD, TCSETAW, &_raw_tty);
+
+#else /* RAW_BSD */
+
+ _raw_tchars.t_intrc = ctrl('C');
+ (void)ioctl(STDIN_FD, TIOCSETC, &_raw_tchars);
+
+#endif
+ }
+ else{
+#if HAS_TERMIOS
+
+ _raw_tty.c_lflag &= ~ISIG; /* disable signals */
+ tcsetattr(STDIN_FD, TCSADRAIN, &_raw_tty);
+
+#elif HAS_TERMIO
+
+ _raw_tty.c_lflag &= ~ISIG; /* disable signals */
+ (void)ioctl(STDIN_FD, TCSETAW, &_raw_tty);
+
+#else /* RAW_BSD */
+ _raw_tchars.t_intrc = -1;
+ (void)ioctl(STDIN_FD, TIOCSETC, &_raw_tchars);
+#endif
+ }
+ }
+}
+
+
+/*
+ * Discard any pending input characters
+ *
+ * Args: none
+ *
+ * Result: pending input buffer flushed
+ */
+void
+flush_input(void)
+{
+#if HAS_TERMIOS
+
+ tcflush(STDIN_FD, TCIFLUSH);
+
+#elif HAS_TERMIO
+
+ ioctl(STDIN_FD, TCFLSH, 0);
+
+#else /* RAW_BSD */
+
+#ifdef TIOCFLUSH
+#ifdef FREAD
+ int i = FREAD;
+#else
+ int i = 1;
+#endif
+ ioctl(STDIN_FD, TIOCFLUSH, &i);
+#endif /* TIOCFLUSH */
+
+#endif
+}
+
+
+/*
+ * Turn off hi bit stripping
+ */
+void
+bit_strip_off(void)
+{
+#if HAS_TERMIOS
+
+ _raw_tty.c_iflag &= ~ISTRIP;
+ tcsetattr(STDIN_FD, TCSADRAIN, &_raw_tty);
+
+#elif HAS_TERMIO
+
+ /* no op */
+
+#else /* RAW_BSD */
+
+#ifdef LPASS8
+ _raw_lmode |= LPASS8;
+#endif
+
+#ifdef LPASS8OUT
+ _raw_lmode |= LPASS8OUT;
+#endif
+
+ (void)ioctl(STDIN_FD, TIOCLSET, &_raw_lmode);
+
+#endif
+}
+
+
+/*
+ * Turn off quit character (^\) if possible
+ */
+void
+quit_char_off(void)
+{
+#if HAS_TERMIOS
+
+#elif HAS_TERMIO
+
+#else /* RAW_BSD */
+ _raw_tchars.t_quitc = -1;
+ (void)ioctl(STDIN_FD, TIOCSETC, &_raw_tchars);
+#endif
+}
+
+
+/*
+ * Returns TRUE if tty is < 4800, 0 otherwise.
+ */
+int
+ttisslow(void)
+{
+#if HAS_TERMIOS
+
+ return(cfgetospeed(&_raw_tty) < B4800);
+
+#elif HAS_TERMIO
+
+ return((_raw_tty.c_cflag&CBAUD) < (unsigned int)B4800);
+
+#else /* RAW_BSD */
+
+ return((int)_raw_tty.sg_ispeed < B4800);
+
+#endif
+}