/* fhandler_serial.cc This file is part of Cygwin. This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" #include #include #include "cygerrno.h" #include "security.h" #include "path.h" #include "fhandler.h" #include "sigproc.h" #include "pinfo.h" #include #include #include #include "cygwait.h" /**********************************************************************/ /* fhandler_serial */ fhandler_serial::fhandler_serial () : fhandler_base (), vmin_ (0), vtime_ (0), pgrp_ (myself->pgid) { need_fork_fixup (true); } void __reg3 fhandler_serial::raw_read (void *ptr, size_t& ulen) { OVERLAPPED ov = { 0 }; DWORD io_err; COMSTAT st; DWORD bytes_to_read, read_bytes; ssize_t tot = 0; if (ulen > SSIZE_MAX) ulen = SSIZE_MAX; if (ulen == 0) return; /* If MIN > 0 in blocking mode, we have to read at least VMIN chars, otherwise we're in polling mode and there's no minimum chars. */ ssize_t minchars = (!is_nonblocking () && vmin_) ? MIN (vmin_, ulen) : 0; debug_printf ("ulen %ld, vmin_ %u, vtime_ %u", ulen, vmin_, vtime_); ov.hEvent = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); do { /* First check if chars are already in the inbound queue. */ if (!ClearCommError (get_handle (), &io_err, &st)) goto err; /* FIXME: In case of I/O error, do we really want to bail out or is it better just trying to pull through? */ if (io_err) { termios_printf ("error detected %x", io_err); SetLastError (ERROR_IO_DEVICE); goto err; } /* ReadFile only handles up to DWORD bytes. */ bytes_to_read = MIN (ulen, UINT32_MAX); if (is_nonblocking ()) { /* In O_NONBLOCK mode we just care for the number of chars already in the inbound queue. */ if (!st.cbInQue) break; bytes_to_read = MIN (st.cbInQue, bytes_to_read); } else { /* If the number of chars in the inbound queue is sufficent (minchars defines the minimum), set bytes_to_read accordingly and don't wait. */ if (st.cbInQue && (ssize_t) st.cbInQue >= minchars) bytes_to_read = MIN (st.cbInQue, bytes_to_read); } ResetEvent (ov.hEvent); if (!ReadFile (get_handle (), ptr, bytes_to_read, &read_bytes, &ov)) { if (GetLastError () != ERROR_IO_PENDING) goto err; if (is_nonblocking ()) { CancelIo (get_handle ()); if (!GetOverlappedResult (get_handle (), &ov, &read_bytes, TRUE)) goto err; } else { switch (cygwait (ov.hEvent)) { default: /* Handle an error case from cygwait basically like a cancel condition and see if we got "something" */ CancelIo (get_handle ()); fallthrough; case WAIT_OBJECT_0: if (!GetOverlappedResult (get_handle (), &ov, &read_bytes, TRUE)) goto err; debug_printf ("got %u bytes from ReadFile", read_bytes); break; case WAIT_SIGNALED: CancelIo (get_handle ()); if (!GetOverlappedResult (get_handle (), &ov, &read_bytes, TRUE)) goto err; /* Only if no bytes read, return with EINTR. */ if (!tot && !read_bytes) { tot = -1; set_sig_errno (EINTR); debug_printf ("signal received, set EINTR"); } else debug_printf ("signal received but ignored"); goto out; case WAIT_CANCELED: CancelIo (get_handle ()); GetOverlappedResult (get_handle (), &ov, &read_bytes, TRUE); debug_printf ("thread canceled"); pthread::static_cancel_self (); /*NOTREACHED*/ } } } tot += read_bytes; ptr = (void *) ((caddr_t) ptr + read_bytes); ulen -= read_bytes; minchars -= read_bytes; debug_printf ("vtime_ %u, vmin_ %u, read_bytes %u, tot %D", vtime_, vmin_, read_bytes, tot); continue; err: debug_printf ("err %E"); if (GetLastError () != ERROR_OPERATION_ABORTED) { if (tot == 0) { tot = -1; __seterrno (); } break; } } /* ALL of these are required to loop: Still room in user space buffer AND still a minchars requirement (implies blocking mode) AND vtime_ is not set. */ while (ulen > 0 && minchars > 0 && vtime_ == 0); out: CloseHandle (ov.hEvent); ulen = (size_t) tot; if (is_nonblocking () && ulen == 0) { ulen = (size_t) -1; set_errno (EAGAIN); } } /* Cover function to WriteFile to provide Posix interface and semantics (as much as possible). */ ssize_t __reg3 fhandler_serial::raw_write (const void *ptr, size_t len) { DWORD bytes_written; OVERLAPPED write_status; memset (&write_status, 0, sizeof (write_status)); write_status.hEvent = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); ProtectHandle (write_status.hEvent); for (;;) { if (WriteFile (get_handle (), ptr, len, &bytes_written, &write_status)) break; switch (GetLastError ()) { case ERROR_OPERATION_ABORTED: DWORD ev; if (!ClearCommError (get_handle (), &ev, NULL)) goto err; if (ev) termios_printf ("error detected %x", ev); continue; case ERROR_IO_PENDING: break; default: goto err; } if (!is_nonblocking ()) { switch (cygwait (write_status.hEvent)) { case WAIT_OBJECT_0: break; case WAIT_SIGNALED: PurgeComm (get_handle (), PURGE_TXABORT); set_sig_errno (EINTR); ForceCloseHandle (write_status.hEvent); return -1; case WAIT_CANCELED: PurgeComm (get_handle (), PURGE_TXABORT); pthread::static_cancel_self (); /*NOTREACHED*/ default: goto err; } } if (!GetOverlappedResult (get_handle (), &write_status, &bytes_written, TRUE)) goto err; break; } ForceCloseHandle (write_status.hEvent); return bytes_written; err: __seterrno (); ForceCloseHandle (write_status.hEvent); return -1; } int fhandler_serial::init (HANDLE f, DWORD flags, mode_t bin) { return open (flags, bin & (O_BINARY | O_TEXT)); } int fhandler_serial::open (int flags, mode_t mode) { int res; COMMTIMEOUTS to; syscall_printf ("fhandler_serial::open (%s, %y, 0%o)", get_name (), flags, mode); if (!fhandler_base::open (flags, mode)) return 0; res = 1; SetCommMask (get_handle (), EV_RXCHAR); memset (&to, 0, sizeof (to)); SetCommTimeouts (get_handle (), &to); /* Reset serial port to known state of 9600-8-1-no flow control on open for better behavior under Win 95. FIXME: This should only be done when explicitly opening the com port. It should not be reset if an fd is inherited. Using __progname in this way, to determine how far along in the initialization we are, is really a terrible kludge and should be fixed ASAP. */ if (reset_com && __progname) { DCB state; GetCommState (get_handle (), &state); syscall_printf ("setting initial state on %s (reset_com %d)", get_name (), reset_com); state.BaudRate = CBR_9600; state.ByteSize = 8; state.StopBits = ONESTOPBIT; state.Parity = NOPARITY; /* FIXME: correct default? */ state.fBinary = TRUE; /* binary xfer */ state.EofChar = 0; /* no end-of-data in binary mode */ state.fNull = FALSE; /* don't discard nulls in binary mode */ state.fParity = FALSE; /* ignore parity errors */ state.fErrorChar = FALSE; state.fTXContinueOnXoff = TRUE; /* separate TX and RX flow control */ state.fOutX = FALSE; /* disable transmission flow control */ state.fInX = FALSE; /* disable reception flow control */ state.XonChar = 0x11; state.XoffChar = 0x13; state.fOutxDsrFlow = FALSE; /* disable DSR flow control */ state.fRtsControl = RTS_CONTROL_ENABLE; /* ignore lead control except DTR */ state.fOutxCtsFlow = FALSE; /* disable output flow control */ state.fDtrControl = DTR_CONTROL_ENABLE; /* assert DTR */ state.fDsrSensitivity = FALSE; /* don't assert DSR */ state.fAbortOnError = TRUE; if (!SetCommState (get_handle (), &state)) system_printf ("couldn't set initial state for %s, %E", get_name ()); } SetCommMask (get_handle (), EV_RXCHAR); set_open_status (); syscall_printf ("%p = fhandler_serial::open (%s, %y, 0%o)", res, get_name (), flags, mode); return res; } /* tcsendbreak: POSIX 7.2.2.1 */ /* Break for 250-500 milliseconds if duration == 0 */ /* Otherwise, units for duration are undefined */ int fhandler_serial::tcsendbreak (int duration) { unsigned int sleeptime = 300000; if (duration > 0) sleeptime *= duration; if (SetCommBreak (get_handle ()) == 0) return -1; /* FIXME: need to send zero bits during duration */ usleep (sleeptime); if (ClearCommBreak (get_handle ()) == 0) return -1; syscall_printf ("0 = fhandler_serial:tcsendbreak (%d)", duration); return 0; } /* tcdrain: POSIX 7.2.2.1 */ int fhandler_serial::tcdrain () { if (FlushFileBuffers (get_handle ()) == 0) return -1; return 0; } /* tcflow: POSIX 7.2.2.1 */ int fhandler_serial::tcflow (int action) { DWORD win32action = 0; DCB dcb; char xchar; termios_printf ("action %d", action); switch (action) { case TCOOFF: win32action = SETXOFF; break; case TCOON: win32action = SETXON; break; case TCION: case TCIOFF: if (GetCommState (get_handle (), &dcb) == 0) return -1; if (action == TCION) xchar = (dcb.XonChar ? dcb.XonChar : 0x11); else xchar = (dcb.XoffChar ? dcb.XoffChar : 0x13); if (TransmitCommChar (get_handle (), xchar) == 0) return -1; return 0; break; default: return -1; break; } if (EscapeCommFunction (get_handle (), win32action) == 0) return -1; return 0; } /* switch_modem_lines: set or clear RTS and/or DTR */ int fhandler_serial::switch_modem_lines (int set, int clr) { int res = 0; if (set & TIOCM_RTS) { if (EscapeCommFunction (get_handle (), SETRTS)) rts = TIOCM_RTS; else { __seterrno (); res = -1; } } else if (clr & TIOCM_RTS) { if (EscapeCommFunction (get_handle (), CLRRTS)) rts = 0; else { __seterrno (); res = -1; } } if (set & TIOCM_DTR) { if (EscapeCommFunction (get_handle (), SETDTR)) rts = TIOCM_DTR; else { __seterrno (); res = -1; } } else if (clr & TIOCM_DTR) { if (EscapeCommFunction (get_handle (), CLRDTR)) rts = 0; else { __seterrno (); res = -1; } } return res; } /* ioctl: */ int fhandler_serial::ioctl (unsigned int cmd, void *buf) { int res = 0; # define ibuf ((int) (intptr_t) buf) # define ipbuf (*(int *) buf) DWORD ev; COMSTAT st; if (!ClearCommError (get_handle (), &ev, &st)) { __seterrno (); res = -1; } else switch (cmd) { case TCFLSH: res = tcflush (ibuf); break; case TIOCMGET: DWORD modem_lines; if (!GetCommModemStatus (get_handle (), &modem_lines)) { __seterrno (); res = -1; } else { ipbuf = 0; if (modem_lines & MS_CTS_ON) ipbuf |= TIOCM_CTS; if (modem_lines & MS_DSR_ON) ipbuf |= TIOCM_DSR; if (modem_lines & MS_RING_ON) ipbuf |= TIOCM_RI; if (modem_lines & MS_RLSD_ON) ipbuf |= TIOCM_CD; DWORD cb; DWORD mcr; if (!DeviceIoControl (get_handle (), IOCTL_SERIAL_GET_DTRRTS, NULL, 0, &mcr, 4, &cb, 0) || cb != 4) ipbuf |= rts | dtr; else { if (mcr & 2) ipbuf |= TIOCM_RTS; if (mcr & 1) ipbuf |= TIOCM_DTR; } } break; case TIOCMSET: if (switch_modem_lines (ipbuf, ~ipbuf)) res = -1; break; case TIOCMBIS: if (switch_modem_lines (ipbuf, 0)) res = -1; break; case TIOCMBIC: if (switch_modem_lines (0, ipbuf)) res = -1; break; case TIOCCBRK: if (ClearCommBreak (get_handle ()) == 0) { __seterrno (); res = -1; } break; case TIOCSBRK: if (SetCommBreak (get_handle ()) == 0) { __seterrno (); res = -1; } break; case TIOCINQ: ipbuf = st.cbInQue; break; case TIOCGWINSZ: ((struct winsize *) buf)->ws_row = 0; ((struct winsize *) buf)->ws_col = 0; break; case FIONREAD: set_errno (ENOTSUP); res = -1; break; default: res = fhandler_base::ioctl (cmd, buf); break; } termios_printf ("%d = ioctl(%x, %p)", res, cmd, buf); # undef ibuf # undef ipbuf return res; } /* tcflush: POSIX 7.2.2.1 */ int fhandler_serial::tcflush (int queue) { DWORD flags; switch (queue) { case TCOFLUSH: flags = PURGE_TXABORT | PURGE_TXCLEAR; break; case TCIFLUSH: flags = PURGE_RXABORT | PURGE_RXCLEAR; break; case TCIOFLUSH: flags = PURGE_TXABORT | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_RXCLEAR; break; default: termios_printf ("Invalid tcflush queue %d", queue); set_errno (EINVAL); return -1; } if (!PurgeComm (get_handle (), flags)) { __seterrno (); return -1; } return 0; } /* tcsetattr: POSIX 7.2.1.1 */ int fhandler_serial::tcsetattr (int action, const struct termios *t) { /* Possible actions: TCSANOW: immediately change attributes. TCSADRAIN: flush output, then change attributes. TCSAFLUSH: flush output and discard input, then change attributes. */ bool dropDTR = false; COMMTIMEOUTS to; DCB ostate, state; int tmpDtr, tmpRts, res; res = tmpDtr = tmpRts = 0; termios_printf ("action %d", action); if ((action == TCSADRAIN) || (action == TCSAFLUSH)) { FlushFileBuffers (get_handle ()); termios_printf ("flushed file buffers"); } if (action == TCSAFLUSH) PurgeComm (get_handle (), (PURGE_RXABORT | PURGE_RXCLEAR)); /* get default/last comm state */ if (!GetCommState (get_handle (), &ostate)) return -1; state = ostate; /* -------------- Set baud rate ------------------ */ /* FIXME: WIN32 also has 14400, 56000, 128000, and 256000. Unix also has 230400. */ switch (t->c_ospeed) { case B0: /* Drop DTR - but leave DCB-resident bitrate as-is since 0 is an invalid bitrate in Win32 */ dropDTR = true; break; case B110: state.BaudRate = CBR_110; break; case B300: state.BaudRate = CBR_300; break; case B600: state.BaudRate = CBR_600; break; case B1200: state.BaudRate = CBR_1200; break; case B2400: state.BaudRate = CBR_2400; break; case B4800: state.BaudRate = CBR_4800; break; case B9600: state.BaudRate = CBR_9600; break; case B19200: state.BaudRate = CBR_19200; break; case B38400: state.BaudRate = CBR_38400; break; case B57600: state.BaudRate = CBR_57600; break; case B115200: state.BaudRate = CBR_115200; break; case B128000: state.BaudRate = CBR_128000; break; case B230400: state.BaudRate = 230400 /* CBR_230400 - not defined */; break; case B256000: state.BaudRate = CBR_256000; break; case B460800: state.BaudRate = 460800 /* CBR_460800 - not defined */; break; case B500000: state.BaudRate = 500000 /* CBR_500000 - not defined */; break; case B576000: state.BaudRate = 576000 /* CBR_576000 - not defined */; break; case B921600: state.BaudRate = 921600 /* CBR_921600 - not defined */; break; case B1000000: state.BaudRate = 1000000 /* CBR_1000000 - not defined */; break; case B1152000: state.BaudRate = 1152000 /* CBR_1152000 - not defined */; break; case B1500000: state.BaudRate = 1500000 /* CBR_1500000 - not defined */; break; case B2000000: state.BaudRate = 2000000 /* CBR_2000000 - not defined */; break; case B2500000: state.BaudRate = 2500000 /* CBR_2500000 - not defined */; break; case B3000000: state.BaudRate = 3000000 /* CBR_3000000 - not defined */; break; default: /* Unsupported baud rate! */ termios_printf ("Invalid t->c_ospeed %u", t->c_ospeed); set_errno (EINVAL); return -1; } /* -------------- Set byte size ------------------ */ switch (t->c_cflag & CSIZE) { case CS5: state.ByteSize = 5; break; case CS6: state.ByteSize = 6; break; case CS7: state.ByteSize = 7; break; case CS8: state.ByteSize = 8; break; default: /* Unsupported byte size! */ termios_printf ("Invalid t->c_cflag byte size %u", t->c_cflag & CSIZE); set_errno (EINVAL); return -1; } /* -------------- Set stop bits ------------------ */ if (t->c_cflag & CSTOPB) state.StopBits = TWOSTOPBITS; else state.StopBits = ONESTOPBIT; /* -------------- Set parity ------------------ */ if (t->c_cflag & PARENB) { if(t->c_cflag & CMSPAR) state.Parity = (t->c_cflag & PARODD) ? MARKPARITY : SPACEPARITY; else state.Parity = (t->c_cflag & PARODD) ? ODDPARITY : EVENPARITY; } else state.Parity = NOPARITY; state.fBinary = TRUE; /* Binary transfer */ state.EofChar = 0; /* No end-of-data in binary mode */ state.fNull = FALSE; /* Don't discard nulls in binary mode */ /* -------------- Parity errors ------------------ */ /* fParity combines the function of INPCK and NOT IGNPAR */ if ((t->c_iflag & INPCK) && !(t->c_iflag & IGNPAR)) state.fParity = TRUE; /* detect parity errors */ else state.fParity = FALSE; /* ignore parity errors */ /* Only present in Win32, Unix has no equivalent */ state.fErrorChar = FALSE; state.ErrorChar = 0; /* -------------- Set software flow control ------------------ */ /* Set fTXContinueOnXoff to FALSE. This prevents the triggering of a premature XON when the remote device interprets a received character as XON (same as IXANY on the remote side). Otherwise, a TRUE value separates the TX and RX functions. */ state.fTXContinueOnXoff = TRUE; /* separate TX and RX flow control */ /* Transmission flow control */ if (t->c_iflag & IXON) state.fOutX = TRUE; /* enable */ else state.fOutX = FALSE; /* disable */ /* Reception flow control */ if (t->c_iflag & IXOFF) state.fInX = TRUE; /* enable */ else state.fInX = FALSE; /* disable */ /* XoffLim and XonLim are left at default values */ state.XonChar = (t->c_cc[VSTART] ? t->c_cc[VSTART] : 0x11); state.XoffChar = (t->c_cc[VSTOP] ? t->c_cc[VSTOP] : 0x13); /* -------------- Set hardware flow control ------------------ */ /* Disable DSR flow control */ state.fOutxDsrFlow = FALSE; /* Some old flavors of Unix automatically enabled hardware flow control when software flow control was not enabled. Since newer Unices tend to require explicit setting of hardware flow-control, this is what we do. */ /* RTS/CTS flow control */ if (t->c_cflag & CRTSCTS) { /* enable */ state.fOutxCtsFlow = TRUE; state.fRtsControl = RTS_CONTROL_HANDSHAKE; } else { /* disable */ state.fRtsControl = RTS_CONTROL_ENABLE; state.fOutxCtsFlow = FALSE; tmpRts = TIOCM_RTS; } if (t->c_cflag & CRTSXOFF) state.fRtsControl = RTS_CONTROL_HANDSHAKE; /* -------------- DTR ------------------ */ /* Assert DTR on device open */ state.fDtrControl = DTR_CONTROL_ENABLE; /* -------------- DSR ------------------ */ /* Assert DSR at the device? */ if (t->c_cflag & CLOCAL) state.fDsrSensitivity = FALSE; /* no */ else state.fDsrSensitivity = TRUE; /* yes */ /* -------------- Error handling ------------------ */ /* Since read/write operations terminate upon error, we will use ClearCommError() to resume. */ state.fAbortOnError = TRUE; if ((memcmp (&ostate, &state, sizeof (state)) != 0) && !SetCommState (get_handle (), &state)) { /* SetCommState() failed, usually due to invalid DCB param. Keep track of this so we can set errno to EINVAL later and return failure */ termios_printf ("SetCommState() failed, %E"); __seterrno (); res = -1; } rbinary ((t->c_iflag & IGNCR) ? false : true); wbinary ((t->c_oflag & ONLCR) ? false : true); if (dropDTR) { EscapeCommFunction (get_handle (), CLRDTR); tmpDtr = 0; } else { /* FIXME: Sometimes when CLRDTR is set, setting state.fDtrControl = DTR_CONTROL_ENABLE will fail. This is a problem since a program might want to change some parameters while DTR is still down. */ EscapeCommFunction (get_handle (), SETDTR); tmpDtr = TIOCM_DTR; } rts = tmpRts; dtr = tmpDtr; /* The following documentation on was taken from "Linux Serial Programming HOWTO". It explains how MIN (t->c_cc[VMIN] || vmin_) and TIME (t->c_cc[VTIME] || vtime_) is to be used. In non-canonical input processing mode, input is not assembled into lines and input processing (erase, kill, delete, etc.) does not occur. Two parameters control the behavior of this mode: c_cc[VTIME] sets the character timer, and c_cc[VMIN] sets the minimum number of characters to receive before satisfying the read. If MIN > 0 and TIME = 0, MIN sets the number of characters to receive before the read is satisfied. As TIME is zero, the timer is not used. If MIN = 0 and TIME > 0, TIME serves as a timeout value. The read will be satisfied if a single character is read, or TIME is exceeded (t = TIME *0.1 s). If TIME is exceeded, no character will be returned. If MIN > 0 and TIME > 0, TIME serves as an inter-character timer. The read will be satisfied if MIN characters are received, or the time between two characters exceeds TIME. The timer is restarted every time a character is received and only becomes active after the first character has been received. If MIN = 0 and TIME = 0, read will be satisfied immediately. The number of characters currently available, or the number of characters requested will be returned. According to Antonino (see contributions), you could issue a fcntl(fd, F_SETFL, FNDELAY); before reading to get the same result. */ if (t->c_lflag & ICANON) { vmin_ = 0; vtime_ = 0; } else { vtime_ = t->c_cc[VTIME]; vmin_ = t->c_cc[VMIN]; } debug_printf ("vtime %u, vmin %u", vtime_, vmin_); memset (&to, 0, sizeof (to)); if ((vmin_ > 0) && (vtime_ == 0)) { /* Returns immediately with whatever is in buffer on a ReadFile(); or blocks if nothing found. We will keep calling ReadFile(); until vmin_ characters are read */ to.ReadIntervalTimeout = to.ReadTotalTimeoutMultiplier = MAXDWORD; to.ReadTotalTimeoutConstant = MAXDWORD - 1; } else if ((vmin_ == 0) && (vtime_ > 0)) { /* set timeoout constant appropriately and we will only try to read one character in ReadFile() */ to.ReadTotalTimeoutConstant = vtime_ * 100; to.ReadIntervalTimeout = to.ReadTotalTimeoutMultiplier = MAXDWORD; } else if ((vmin_ > 0) && (vtime_ > 0)) { /* time applies to the interval time for this case */ to.ReadIntervalTimeout = vtime_ * 100; } else if ((vmin_ == 0) && (vtime_ == 0)) { /* returns immediately with whatever is in buffer as per Time-Outs docs in Win32 SDK API docs */ to.ReadIntervalTimeout = MAXDWORD; } debug_printf ("ReadTotalTimeoutConstant %u, ReadIntervalTimeout %u, " "ReadTotalTimeoutMultiplier %u", to.ReadTotalTimeoutConstant, to.ReadIntervalTimeout, to.ReadTotalTimeoutMultiplier); if (!SetCommTimeouts(get_handle (), &to)) { /* SetCommTimeouts() failed. Keep track of this so we can set errno to EINVAL later and return failure */ termios_printf ("SetCommTimeouts() failed, %E"); __seterrno (); res = -1; } return res; } /* tcgetattr: POSIX 7.2.1.1 */ int fhandler_serial::tcgetattr (struct termios *t) { DCB state; /* Get current Win32 comm state */ if (GetCommState (get_handle (), &state) == 0) return -1; /* for safety */ memset (t, 0, sizeof (*t)); t->c_cflag = 0; /* -------------- Baud rate ------------------ */ switch (state.BaudRate) { case CBR_110: t->c_ospeed = t->c_ispeed = B110; break; case CBR_300: t->c_ospeed = t->c_ispeed = B300; break; case CBR_600: t->c_ospeed = t->c_ispeed = B600; break; case CBR_1200: t->c_ospeed = t->c_ispeed = B1200; break; case CBR_2400: t->c_ospeed = t->c_ispeed = B2400; break; case CBR_4800: t->c_ospeed = t->c_ispeed = B4800; break; case CBR_9600: t->c_ospeed = t->c_ispeed = B9600; break; case CBR_19200: t->c_ospeed = t->c_ispeed = B19200; break; case CBR_38400: t->c_ospeed = t->c_ispeed = B38400; break; case CBR_57600: t->c_ospeed = t->c_ispeed = B57600; break; case CBR_115200: t->c_ospeed = t->c_ispeed = B115200; break; case CBR_128000: t->c_ospeed = t->c_ispeed = B128000; break; case 230400: /* CBR_230400 - not defined */ t->c_ospeed = t->c_ispeed = B230400; break; case CBR_256000: t->c_ospeed = t->c_ispeed = B256000; break; case 460800: /* CBR_460000 - not defined */ t->c_ospeed = t->c_ispeed = B460800; break; case 500000: /* CBR_500000 - not defined */ t->c_ospeed = t->c_ispeed = B500000; break; case 576000: /* CBR_576000 - not defined */ t->c_ospeed = t->c_ispeed = B576000; break; case 921600: /* CBR_921600 - not defined */ t->c_ospeed = t->c_ispeed = B921600; break; case 1000000: /* CBR_1000000 - not defined */ t->c_ospeed = t->c_ispeed = B1000000; break; case 1152000: /* CBR_1152000 - not defined */ t->c_ospeed = t->c_ispeed = B1152000; break; case 1500000: /* CBR_1500000 - not defined */ t->c_ospeed = t->c_ispeed = B1500000; break; case 2000000: /* CBR_2000000 - not defined */ t->c_ospeed = t->c_ispeed = B2000000; break; case 2500000: /* CBR_2500000 - not defined */ t->c_ospeed = t->c_ispeed = B2500000; break; case 3000000: /* CBR_3000000 - not defined */ t->c_ospeed = t->c_ispeed = B3000000; break; default: /* Unsupported baud rate! */ termios_printf ("Invalid baud rate %u", state.BaudRate); set_errno (EINVAL); return -1; } /* -------------- Byte size ------------------ */ switch (state.ByteSize) { case 5: t->c_cflag |= CS5; break; case 6: t->c_cflag |= CS6; break; case 7: t->c_cflag |= CS7; break; case 8: t->c_cflag |= CS8; break; default: /* Unsupported byte size! */ termios_printf ("Invalid byte size %u", state.ByteSize); set_errno (EINVAL); return -1; } /* -------------- Stop bits ------------------ */ if (state.StopBits == TWOSTOPBITS) t->c_cflag |= CSTOPB; /* -------------- Parity ------------------ */ if (state.Parity == ODDPARITY) t->c_cflag |= (PARENB | PARODD); if (state.Parity == EVENPARITY) t->c_cflag |= PARENB; if (state.Parity == MARKPARITY) t->c_cflag |= (PARENB | PARODD | CMSPAR); if (state.Parity == SPACEPARITY) t->c_cflag |= (PARENB | CMSPAR); /* -------------- Parity errors ------------------ */ /* fParity combines the function of INPCK and NOT IGNPAR */ if (state.fParity) t->c_iflag |= INPCK; else t->c_iflag |= IGNPAR; /* not necessarily! */ /* -------------- Software flow control ------------------ */ /* transmission flow control */ if (state.fOutX) t->c_iflag |= IXON; /* reception flow control */ if (state.fInX) t->c_iflag |= IXOFF; t->c_cc[VSTART] = (state.XonChar ? state.XonChar : 0x11); t->c_cc[VSTOP] = (state.XoffChar ? state.XoffChar : 0x13); /* -------------- Hardware flow control ------------------ */ /* Some old flavors of Unix automatically enabled hardware flow control when software flow control was not enabled. Since newer Unices tend to require explicit setting of hardware flow-control, this is what we do. */ /* Input flow-control */ if ((state.fRtsControl == RTS_CONTROL_HANDSHAKE) && state.fOutxCtsFlow) t->c_cflag |= CRTSCTS; if (state.fRtsControl == RTS_CONTROL_HANDSHAKE) t->c_cflag |= CRTSXOFF; /* -------------- CLOCAL --------------- */ /* DSR is only lead toggled only by CLOCAL. Check it to see if CLOCAL was called. */ /* FIXME: If tcsetattr() hasn't been called previously, this may give a false CLOCAL. */ if (!state.fDsrSensitivity) t->c_cflag |= CLOCAL; /* FIXME: need to handle IGNCR */ #if 0 if (!rbinary ()) t->c_iflag |= IGNCR; #endif if (!wbinary ()) t->c_oflag |= ONLCR; t->c_cc[VTIME] = vtime_; t->c_cc[VMIN] = vmin_; debug_printf ("vmin_ %u, vtime_ %u", vmin_, vtime_); return 0; }