diff options
Diffstat (limited to 'winsup/cygwin/fhandler_serial.cc')
-rw-r--r-- | winsup/cygwin/fhandler_serial.cc | 1180 |
1 files changed, 0 insertions, 1180 deletions
diff --git a/winsup/cygwin/fhandler_serial.cc b/winsup/cygwin/fhandler_serial.cc deleted file mode 100644 index b8b5c2158..000000000 --- a/winsup/cygwin/fhandler_serial.cc +++ /dev/null @@ -1,1180 +0,0 @@ -/* fhandler_serial.cc - - Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, - 2006, 2007, 2008, 2009, 2011 Red Hat, Inc. - -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 <unistd.h> -#include "cygerrno.h" -#include "security.h" -#include "path.h" -#include "fhandler.h" -#include "sigproc.h" -#include "pinfo.h" -#include <asm/socket.h> -#include <ddk/ntddser.h> - -/**********************************************************************/ -/* fhandler_serial */ - -fhandler_serial::fhandler_serial () - : fhandler_base (), vmin_ (0), vtime_ (0), pgrp_ (myself->pgid) -{ - need_fork_fixup (true); -} - -void -fhandler_serial::overlapped_setup () -{ - memset (&io_status, 0, sizeof (io_status)); - io_status.hEvent = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); - ProtectHandle (io_status.hEvent); - overlapped_armed = 0; -} - -void __stdcall -fhandler_serial::raw_read (void *ptr, size_t& ulen) -{ - int tot; - DWORD n; - - size_t minchars = vmin_ ? min (vmin_, ulen) : ulen; - - debug_printf ("ulen %d, vmin_ %d, vtime_ %d, hEvent %p", ulen, vmin_, vtime_, - io_status.hEvent); - if (!overlapped_armed) - { - SetCommMask (get_handle (), EV_RXCHAR); - ResetEvent (io_status.hEvent); - } - - for (n = 0, tot = 0; ulen; ulen -= n, ptr = (char *) ptr + n) - { - COMSTAT st; - DWORD inq = vmin_ ? minchars : vtime_ ? ulen : 1; - - n = 0; - - if (vtime_) // non-interruptible -- have to use kernel timeouts - overlapped_armed = -1; - - if (!ClearCommError (get_handle (), &ev, &st)) - goto err; - else if (ev) - termios_printf ("error detected %x", ev); - else if (st.cbInQue && !vtime_) - inq = st.cbInQue; - else if (!overlapped_armed) - { - if ((size_t) tot >= minchars) - break; - else if (WaitCommEvent (get_handle (), &ev, &io_status)) - { - debug_printf ("WaitCommEvent succeeded: ev %x", ev); - if (!ev) - continue; - } - else if (GetLastError () != ERROR_IO_PENDING) - goto err; - else if (is_nonblocking ()) - { - PurgeComm (get_handle (), PURGE_RXABORT); - if (tot == 0) - { - tot = -1; - set_errno (EAGAIN); - } - goto out; - } - else - { - HANDLE w4[3] = { io_status.hEvent, signal_arrived, - pthread::get_cancel_event () }; - DWORD cnt = w4[2] ? 3 : 2; - overlapped_armed = 1; -restart: - switch (WaitForMultipleObjects (cnt, w4, FALSE, INFINITE)) - { - case WAIT_OBJECT_0: - if (!GetOverlappedResult (get_handle (), &io_status, &n, - FALSE)) - goto err; - debug_printf ("n %d, ev %x", n, ev); - break; - case WAIT_OBJECT_0 + 1: - if (_my_tls.call_signal_handler ()) - goto restart; - tot = -1; - PurgeComm (get_handle (), PURGE_RXABORT); - overlapped_armed = 0; - set_sig_errno (EINTR); - goto out; - case WAIT_OBJECT_0 + 2: - PurgeComm (get_handle (), PURGE_RXABORT); - overlapped_armed = 0; - pthread::static_cancel_self (); - /*NOTREACHED*/ - default: - goto err; - } - } - } - - overlapped_armed = 0; - ResetEvent (io_status.hEvent); - if (inq > ulen) - inq = ulen; - debug_printf ("inq %d", inq); - if (ReadFile (get_handle (), ptr, inq, &n, &io_status)) - /* Got something */; - else if (GetLastError () != ERROR_IO_PENDING) - goto err; - else if (is_nonblocking ()) - { - PurgeComm (get_handle (), PURGE_RXABORT); - if (tot == 0) - { - tot = -1; - set_errno (EAGAIN); - } - goto out; - } - else if (!GetOverlappedResult (get_handle (), &io_status, &n, TRUE)) - goto err; - - tot += n; - debug_printf ("vtime_ %d, vmin_ %d, n %d, tot %d", vtime_, vmin_, n, tot); - if (vtime_ || !vmin_ || !n) - break; - continue; - - err: - debug_printf ("err %E"); - if (GetLastError () != ERROR_OPERATION_ABORTED) - { - PurgeComm (get_handle (), PURGE_RXABORT); - tot = -1; - __seterrno (); - break; - } - - n = 0; - } - -out: - ulen = tot; -} - -/* Cover function to WriteFile to provide Posix interface and semantics - (as much as possible). */ -ssize_t __stdcall -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 ()) - { - HANDLE w4[3] = { write_status.hEvent, signal_arrived, - pthread::get_cancel_event () }; - DWORD cnt = w4[2] ? 3 : 2; - restart: - switch (WaitForMultipleObjects (cnt, w4, FALSE, INFINITE)) - { - case WAIT_OBJECT_0: - break; - case WAIT_OBJECT_0 + 1: - if (_my_tls.call_signal_handler ()) - goto restart; - PurgeComm (get_handle (), PURGE_TXABORT); - set_sig_errno (EINTR); - ForceCloseHandle (write_status.hEvent); - return -1; - case WAIT_OBJECT_0 + 2: - 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; - extern BOOL reset_com; - - syscall_printf ("fhandler_serial::open (%s, %p, %p)", - get_name (), flags, mode); - - if (!fhandler_base::open (flags, mode)) - return 0; - - res = 1; - - SetCommMask (get_handle (), EV_RXCHAR); - - overlapped_setup (); - - 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, %p, %p)", - res, get_name (), flags, mode); - return res; -} - -int -fhandler_serial::close () -{ - ForceCloseHandle (io_status.hEvent); - return fhandler_base::close (); -} - -/* 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) 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: - if (ev & CE_FRAME || ev & CE_IOE || ev & CE_OVERRUN || ev & CE_RXOVER - || ev & CE_RXPARITY) - { - set_errno (EINVAL); /* FIXME: Use correct errno */ - res = -1; - } - else - 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 (%p, %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; - unsigned int ovtime = vtime_, ovmin = vmin_; - 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 %d", 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 %d", - 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) - 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] * 100; - vmin_ = t->c_cc[VMIN]; - } - - debug_printf ("vtime %d, vmin %d", vtime_, vmin_); - - if (ovmin != vmin_ || ovtime != vtime_) - { - 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_; - to.ReadIntervalTimeout = to.ReadTotalTimeoutMultiplier = MAXDWORD; - } - else if ((vmin_ > 0) && (vtime_ > 0)) - { - /* time applies to the interval time for this case */ - to.ReadIntervalTimeout = vtime_; - } - 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 %d, ReadIntervalTimeout %d, ReadTotalTimeoutMultiplier %d", - 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 %d", 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 %d", 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; - - /* -------------- 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_ / 100; - t->c_cc[VMIN] = vmin_; - - debug_printf ("vmin_ %d, vtime_ %d", vmin_, vtime_); - - return 0; -} - -void -fhandler_serial::fixup_after_fork (HANDLE parent) -{ - if (close_on_exec ()) - fhandler_base::fixup_after_fork (parent); - overlapped_setup (); - debug_printf ("io_status.hEvent %p", io_status.hEvent); -} - -void -fhandler_serial::fixup_after_exec () -{ - if (!close_on_exec ()) - overlapped_setup (); - debug_printf ("io_status.hEvent %p, close_on_exec %d", io_status.hEvent, close_on_exec ()); -} - -int -fhandler_serial::dup (fhandler_base *child) -{ - fhandler_serial *fhc = (fhandler_serial *) child; - fhc->overlapped_setup (); - return fhandler_base::dup (child); -} |