⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fhandler_serial.cc

📁 cygwin, 著名的在win32下模拟unix操作系统的东东
💻 CC
📖 第 1 页 / 共 2 页
字号:
/* fhandler_serial.cc   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.This file is part of Cygwin.This software is a copyrighted work licensed under the terms of theCygwin license.  Please consult the file "CYGWIN_LICENSE" fordetails. */#include "winsup.h"#include <errno.h>#include <unistd.h>#include <stdlib.h>#include "cygerrno.h"#include "security.h"#include "fhandler.h"#include "sigproc.h"#include "pinfo.h"#include <sys/termios.h>#include <ddk/ntddser.h>/**********************************************************************//* fhandler_serial */fhandler_serial::fhandler_serial (int unit)  : fhandler_base (FH_SERIAL, unit), vmin_ (0), vtime_ (0), pgrp_ (myself->pgid){  set_need_fork_fixup ();}voidfhandler_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;}intfhandler_serial::raw_read (void *ptr, size_t ulen){  int tot;  DWORD n;  HANDLE w4[2];  size_t minchars = vmin_ ?: ulen;  w4[0] = io_status.hEvent;  w4[1] = signal_arrived;  debug_printf ("ulen %d, vmin_ %d, vtime_ %d, hEvent %p", ulen, vmin_, vtime_,		io_status.hEvent);  if (!overlapped_armed)    {      (void) 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 = 1;      n = 0;      if (!vtime_ && !vmin_)	inq = ulen;      else if (vtime_)	{	  inq = ulen;	// non-interruptible -- have to use kernel timeouts			// also note that this is not strictly correct.			// if vmin > ulen then things won't work right.	  overlapped_armed = -1;	}      if (!ClearCommError (get_handle (), &ev, &st))	goto err;      else if (ev)	termios_printf ("error detected %x", ev);      else if (st.cbInQue)	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	    {	      overlapped_armed = 1;	      switch (WaitForMultipleObjects (2, 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:		  tot = -1;		  PurgeComm (get_handle (), PURGE_RXABORT);		  overlapped_armed = 0;		  set_sig_errno (EINTR);		  goto out;		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, min (inq, ulen), &n, &io_status))	/* Got something */;      else if (GetLastError () != ERROR_IO_PENDING)	goto err;      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:      PurgeComm (get_handle (), PURGE_RXABORT);      debug_printf ("err %E");      if (GetLastError () == ERROR_OPERATION_ABORTED)	n = 0;      else	{	  tot = -1;	  __seterrno ();	  break;	}    }out:  return tot;}/* Cover function to WriteFile to provide Posix interface and semantics   (as much as possible).  */intfhandler_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:	    continue;	  case ERROR_IO_PENDING:	    break;	  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;}voidfhandler_serial::dump (void){  paranoid_printf ("here");}voidfhandler_serial::init (HANDLE f, DWORD flags, mode_t bin){  (void) open (NULL, flags, bin & (O_BINARY | O_TEXT));}intfhandler_serial::open (path_conv *, 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 (!(res = this->fhandler_base::open (NULL, flags, mode)))    return 0;  res = 1;  (void) SetCommMask (get_handle (), EV_RXCHAR);  set_r_no_interrupt (1);	// Handled explicitly in read code  overlapped_setup ();  memset (&to, 0, sizeof (to));  (void) 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.  */  extern char *__progname;  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 ());    }  /* setting rts and dtr to known state so that ioctl() function with  request TIOCMGET could return correct value of RTS and DTR lines.  Important only for Win 9x systems */  if (!wincap.supports_reading_modem_output_lines ())    {      if (EscapeCommFunction (get_handle (), SETDTR) == 0)	system_printf ("couldn't set initial state of DTR for %s, %E", get_name ());      if (EscapeCommFunction (get_handle (), SETRTS) == 0)	system_printf ("couldn't set initial state of RTS for %s, %E", get_name ());      /* even though one of above functions fail I have to set rts and dtr      variables to initial value. */      rts = TIOCM_RTS;      dtr = TIOCM_DTR;    }  SetCommMask (get_handle (), EV_RXCHAR);  set_open_status ();  syscall_printf ("%p = fhandler_serial::open (%s, %p, %p)",			res, get_name (), flags, mode);  return res;}intfhandler_serial::close (){  (void) 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 */intfhandler_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 */intfhandler_serial::tcdrain (void){  if (FlushFileBuffers (get_handle ()) == 0)    return -1;  return 0;}/* tcflow: POSIX 7.2.2.1 */intfhandler_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;}/* ioctl: */intfhandler_serial::ioctl (unsigned int cmd, void *buffer){  int res = 0;# define ibuffer ((int) buffer)# define ipbuffer (*(int *) buffer)  DWORD ev;  COMSTAT st;  if (!ClearCommError (get_handle (), &ev, &st))    {      __seterrno ();      res = -1;    }  else    switch (cmd)      {      case TCFLSH:	res = tcflush (ibuffer);	break;      case TIOCMGET:	DWORD modem_lines;	if (!GetCommModemStatus (get_handle (), &modem_lines))	  {	    __seterrno ();	    res = -1;	  }	else	  {	    ipbuffer = 0;	    if (modem_lines & MS_CTS_ON)	      ipbuffer |= TIOCM_CTS;	    if (modem_lines & MS_DSR_ON)	      ipbuffer |= TIOCM_DSR;	    if (modem_lines & MS_RING_ON)	      ipbuffer |= TIOCM_RI;	    if (modem_lines & MS_RLSD_ON)	      ipbuffer |= TIOCM_CD;	    DWORD cb;	    DWORD mcr;	    if (!DeviceIoControl (get_handle (), IOCTL_SERIAL_GET_DTRRTS,				  NULL, 0, &mcr, 4, &cb, 0) || cb != 4)	      ipbuffer |= rts | dtr;	    else	      {		if (mcr & 2)		  ipbuffer |= TIOCM_RTS;		if (mcr & 1)		  ipbuffer |= TIOCM_DTR;	      }	  }	break;      case TIOCMSET:	if (ipbuffer & TIOCM_RTS)	  {	    if (EscapeCommFunction (get_handle (), SETRTS))	      rts = TIOCM_RTS;	    else	      {		__seterrno ();		res = -1;	      }	  }	else	  {	    if (EscapeCommFunction (get_handle (), CLRRTS))	      rts = 0;	    else	      {		__seterrno ();		res = -1;	      }	  }	if (ipbuffer & TIOCM_DTR)	  {	    if (EscapeCommFunction (get_handle (), SETDTR))	      dtr = TIOCM_DTR;	    else	      {		__seterrno ();		res = -1;	      }	  }	else if (EscapeCommFunction (get_handle (), CLRDTR))	  dtr = 0;	else	  {	    __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	 ipbuffer = st.cbInQue;       break;     default:       set_errno (ENOSYS);       res = -1;       break;     }  termios_printf ("%d = ioctl (%p, %p)", res, cmd, buffer);# undef ibuffer# undef ipbuffer  return res;}/* tcflush: POSIX 7.2.2.1 */intfhandler_serial::tcflush (int queue){  if (queue == TCOFLUSH || queue == TCIOFLUSH)    PurgeComm (get_handle (), PURGE_TXABORT | PURGE_TXCLEAR);  if (queue == TCIFLUSH || queue == TCIOFLUSH)    /* Input flushing by polling until nothing turns up       (we stop after 1000 chars anyway) */    for (int max = 1000; max > 0; max--)      {	COMSTAT st;	if (!PurgeComm (get_handle (), PURGE_RXABORT | PURGE_RXCLEAR))	  break;	low_priority_sleep (100);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -