Eric Pouech : ntdll/kernel32: SetCommState & IOCTL_SET_HANDFLOW

Alexandre Julliard julliard at wine.codeweavers.com
Tue May 9 14:15:44 CDT 2006


Module: wine
Branch: refs/heads/master
Commit: b68203ea90464eddddf43ef6521303b2b1da32e8
URL:    http://source.winehq.org/git/?p=wine.git;a=commit;h=b68203ea90464eddddf43ef6521303b2b1da32e8

Author: Eric Pouech <eric.pouech at wanadoo.fr>
Date:   Sun May  7 14:10:39 2006 +0200

ntdll/kernel32: SetCommState & IOCTL_SET_HANDFLOW

- implemented ntdll's serial IOCTL SET_HANDFLOW
- used this IOCTL in kernel32.SetCommState

---

 dlls/kernel/comm.c  |   85 ++++++++++++++++++++++++++-------------------------
 dlls/ntdll/serial.c |   80 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 124 insertions(+), 41 deletions(-)

diff --git a/dlls/kernel/comm.c b/dlls/kernel/comm.c
index f9aeb2a..58e1b13 100644
--- a/dlls/kernel/comm.c
+++ b/dlls/kernel/comm.c
@@ -989,6 +989,7 @@ BOOL WINAPI SetCommState( HANDLE handle,
 
     SERIAL_BAUD_RATE           sbr;
     SERIAL_LINE_CONTROL        slc;
+    SERIAL_HANDFLOW            shf;
 
     if (lpdcb == NULL)
     {
@@ -1003,6 +1004,45 @@ BOOL WINAPI SetCommState( HANDLE handle,
     slc.Parity = lpdcb->Parity;
     slc.WordLength = lpdcb->ByteSize;
 
+    shf.ControlHandShake = 0;
+    shf.FlowReplace = 0;
+    if (lpdcb->fOutxCtsFlow)      shf.ControlHandShake |= SERIAL_CTS_HANDSHAKE;
+    if (lpdcb->fOutxDsrFlow)      shf.ControlHandShake |= SERIAL_DSR_HANDSHAKE;
+    switch (lpdcb->fDtrControl)
+    {
+    case DTR_CONTROL_DISABLE:                                                  break;
+    case DTR_CONTROL_ENABLE:      shf.ControlHandShake |= SERIAL_DTR_CONTROL;  break;
+    case DTR_CONTROL_HANDSHAKE:   shf.ControlHandShake |= SERIAL_DTR_HANDSHAKE;break;
+    default:
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+    switch (lpdcb->fDtrControl)
+    {
+    case RTS_CONTROL_DISABLE:                                                  break;
+    case RTS_CONTROL_ENABLE:      shf.FlowReplace |= SERIAL_RTS_CONTROL;       break;
+    case RTS_CONTROL_HANDSHAKE:   shf.FlowReplace |= SERIAL_RTS_HANDSHAKE;     break;
+    case RTS_CONTROL_TOGGLE:      shf.FlowReplace |= SERIAL_RTS_CONTROL | 
+                                                     SERIAL_RTS_HANDSHAKE;     break;
+    default:
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+    if (lpdcb->fDsrSensitivity)   shf.ControlHandShake |= SERIAL_DSR_SENSITIVITY;
+    if (lpdcb->fAbortOnError)     shf.ControlHandShake |= SERIAL_ERROR_ABORT;
+
+    if (lpdcb->fErrorChar)        shf.FlowReplace |= SERIAL_ERROR_CHAR;
+    if (lpdcb->fNull)             shf.FlowReplace |= SERIAL_NULL_STRIPPING;
+    if (lpdcb->fTXContinueOnXoff) shf.FlowReplace |= SERIAL_XOFF_CONTINUE;
+    if (lpdcb->fOutX)             shf.FlowReplace |= SERIAL_AUTO_TRANSMIT;
+    if (lpdcb->fInX)              shf.FlowReplace |= SERIAL_AUTO_RECEIVE;
+
+    shf.XonLimit = lpdcb->XonLim;
+    shf.XoffLimit = lpdcb->XoffLim;
+
+    /* note: change DTR/RTS lines after setting the comm attributes,
+     * so flow control does not interfere.
+     */
     if (!DeviceIoControl(handle, IOCTL_SERIAL_SET_BAUD_RATE,
                          &sbr, sizeof(sbr), NULL, 0, NULL, NULL))
         return FALSE;
@@ -1010,6 +1050,10 @@ BOOL WINAPI SetCommState( HANDLE handle,
                          &slc, sizeof(slc), NULL, 0, NULL, NULL))
         return FALSE;
 
+    if (!DeviceIoControl(handle, IOCTL_SERIAL_SET_HANDFLOW,
+                         &shf, sizeof(shf), NULL, 0, NULL, NULL))
+        return FALSE;
+
      fd = get_comm_fd( handle, FILE_READ_DATA );
      if (fd < 0) return FALSE;
 
@@ -1023,25 +1067,6 @@ BOOL WINAPI SetCommState( HANDLE handle,
 	port.c_cc[VMIN] = 0;
 	port.c_cc[VTIME] = 1;
 
-#ifdef CRTSCTS
-	if (	lpdcb->fOutxCtsFlow 			||
-		lpdcb->fRtsControl == RTS_CONTROL_HANDSHAKE
-	)
-	  {
-	    port.c_cflag |= CRTSCTS;
-	    TRACE("CRTSCTS\n");
-	  }
-#endif
-
-	if (lpdcb->fInX)
-		port.c_iflag |= IXON;
-	else
-		port.c_iflag &= ~IXON;
-	if (lpdcb->fOutX)
-		port.c_iflag |= IXOFF;
-	else
-		port.c_iflag &= ~IXOFF;
-
 	if (tcsetattr(fd,TCSANOW,&port)==-1) { /* otherwise it hangs with pending input*/
                 ERR("tcsetattr error '%s'\n", strerror(errno));
 		ret = FALSE;
@@ -1050,28 +1075,6 @@ #endif
 		ret = TRUE;
 	}
 
-        /* note: change DTR/RTS lines after setting the comm attributes,
-         * so flow control does not interfere. */
-#ifdef TIOCM_DTR
-	if (lpdcb->fDtrControl == DTR_CONTROL_HANDSHAKE)
-        {
-             WARN("DSR/DTR flow control not supported\n");
-	} else if(lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
-            COMM_WhackModem(fd, ~TIOCM_DTR, 0);
-        else    
-            COMM_WhackModem(fd, 0, TIOCM_DTR);
-#endif
-#ifdef TIOCM_RTS
-	if(!lpdcb->fOutxCtsFlow )
-        {
-            if(lpdcb->fRtsControl == RTS_CONTROL_DISABLE)
-                COMM_WhackModem(fd, ~TIOCM_RTS, 0);
-            else    
-                COMM_WhackModem(fd, 0, TIOCM_RTS);
-        }
-#endif
-        if(lpdcb->fRtsControl == RTS_CONTROL_TOGGLE)
-            FIXME("RTS_CONTROL_TOGGLE is not supported.\n");
         release_comm_fd( handle, fd );
         return ret;
 
diff --git a/dlls/ntdll/serial.c b/dlls/ntdll/serial.c
index 678b4fd..0225ba8 100644
--- a/dlls/ntdll/serial.c
+++ b/dlls/ntdll/serial.c
@@ -360,6 +360,80 @@ #endif
     return STATUS_SUCCESS;
 }
 
+static int whack_modem(int fd, unsigned int andy, unsigned int orrie)
+{
+#ifdef TIOCMGET
+    unsigned int mstat, okay;
+    okay = ioctl(fd, TIOCMGET, &mstat);
+    if (okay) return okay;
+    if (andy) mstat &= andy;
+    mstat |= orrie;
+    return ioctl(fd, TIOCMSET, &mstat);
+#else
+    return 0;
+#endif
+}
+
+static NTSTATUS set_handflow(int fd, const SERIAL_HANDFLOW* shf)
+{
+    struct termios port;
+
+    if ((shf->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE)) == 
+        (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE))
+        return STATUS_NOT_SUPPORTED;
+
+    if (tcgetattr(fd, &port) == -1)
+    {
+        ERR("tcgetattr error '%s'\n", strerror(errno));
+        return FILE_GetNtStatus();
+    }
+    
+#ifdef CRTSCTS
+    if ((shf->ControlHandShake & SERIAL_CTS_HANDSHAKE) ||
+        (shf->FlowReplace & SERIAL_RTS_HANDSHAKE))
+    {
+        port.c_cflag |= CRTSCTS;
+        TRACE("CRTSCTS\n");
+    }
+    else
+        port.c_cflag &= ~CRTSCTS;
+#endif
+#ifdef TIOCM_DTR
+    if (shf->ControlHandShake & SERIAL_DTR_HANDSHAKE)
+    {
+        WARN("DSR/DTR flow control not supported\n");
+    } else if (shf->ControlHandShake & SERIAL_DTR_CONTROL)
+        whack_modem(fd, ~TIOCM_DTR, 0);
+    else    
+        whack_modem(fd, 0, TIOCM_DTR);
+#endif
+#ifdef TIOCM_RTS
+    if (!(shf->ControlHandShake & SERIAL_DSR_HANDSHAKE))
+    {
+        if ((shf->FlowReplace & (SERIAL_RTS_CONTROL|SERIAL_RTS_HANDSHAKE)) == 0)
+            whack_modem(fd, ~TIOCM_RTS, 0);
+        else    
+            whack_modem(fd, 0, TIOCM_RTS);
+    }
+#endif
+
+    if (shf->FlowReplace & SERIAL_AUTO_RECEIVE)
+        port.c_iflag |= IXON;
+    else
+        port.c_iflag &= ~IXON;
+    if (shf->FlowReplace & SERIAL_AUTO_TRANSMIT)
+        port.c_iflag |= IXOFF;
+    else
+        port.c_iflag &= ~IXOFF;
+    if (tcsetattr(fd, TCSANOW, &port) == -1)
+    {
+        ERR("tcsetattr error '%s'\n", strerror(errno));
+        return FILE_GetNtStatus();
+    }
+
+    return STATUS_SUCCESS;
+}
+
 static NTSTATUS set_line_control(int fd, const SERIAL_LINE_CONTROL* slc)
 {
     struct termios port;
@@ -584,6 +658,12 @@ #else
 	status = STATUS_NOT_SUPPORTED;
 #endif
         break;
+    case IOCTL_SERIAL_SET_HANDFLOW:
+        if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
+            status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);
+        else
+            status = STATUS_INVALID_PARAMETER;
+        break;
     case IOCTL_SERIAL_SET_LINE_CONTROL:
         if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL))
             status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer);




More information about the wine-cvs mailing list