Eric Pouech : ntdll/kernel32: SetCommState & IOCTL_SET_LINE_CONTROL

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


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

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

ntdll/kernel32: SetCommState & IOCTL_SET_LINE_CONTROL

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

---

 dlls/kernel/comm.c  |  122 +++++----------------------------------------------
 dlls/ntdll/serial.c |  112 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 124 insertions(+), 110 deletions(-)

diff --git a/dlls/kernel/comm.c b/dlls/kernel/comm.c
index a641567..f9aeb2a 100644
--- a/dlls/kernel/comm.c
+++ b/dlls/kernel/comm.c
@@ -984,11 +984,12 @@ static void dump_dcb(const DCB* lpdcb)
 BOOL WINAPI SetCommState( HANDLE handle, LPDCB lpdcb)
 {
      struct termios port;
-     int fd, bytesize, stopbits;
+     int fd;
      BOOL ret;
 
-    SERIAL_BAUD_RATE    sbr;
- 
+    SERIAL_BAUD_RATE           sbr;
+    SERIAL_LINE_CONTROL        slc;
+
     if (lpdcb == NULL)
     {
         SetLastError(ERROR_INVALID_PARAMETER);
@@ -997,9 +998,17 @@ BOOL WINAPI SetCommState( HANDLE handle,
     dump_dcb(lpdcb);
 
     sbr.BaudRate = lpdcb->BaudRate;
+             
+    slc.StopBits = lpdcb->StopBits;
+    slc.Parity = lpdcb->Parity;
+    slc.WordLength = lpdcb->ByteSize;
+
     if (!DeviceIoControl(handle, IOCTL_SERIAL_SET_BAUD_RATE,
                          &sbr, sizeof(sbr), NULL, 0, NULL, NULL))
         return FALSE;
+    if (!DeviceIoControl(handle, IOCTL_SERIAL_SET_LINE_CONTROL,
+                         &slc, sizeof(slc), NULL, 0, NULL, NULL))
+        return FALSE;
 
      fd = get_comm_fd( handle, FILE_READ_DATA );
      if (fd < 0) return FALSE;
@@ -1014,113 +1023,6 @@ BOOL WINAPI SetCommState( HANDLE handle,
 	port.c_cc[VMIN] = 0;
 	port.c_cc[VTIME] = 1;
 
-#ifdef IMAXBEL
-	port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK|IMAXBEL);
-#else
-	port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK);
-#endif
-	port.c_iflag |= (IGNBRK);
-
-	port.c_oflag &= ~(OPOST);
-
-	port.c_cflag &= ~(HUPCL);
-	port.c_cflag |= CLOCAL | CREAD;
-
-	port.c_lflag &= ~(ICANON|ECHO|ISIG);
-	port.c_lflag |= NOFLSH;
-
-        bytesize=lpdcb->ByteSize;
-        stopbits=lpdcb->StopBits;
-
-#ifdef CMSPAR
-	port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
-#else
-	port.c_cflag &= ~(PARENB | PARODD);
-#endif
-	if (lpdcb->fParity)
-            port.c_iflag |= INPCK;
-        else
-            port.c_iflag &= ~INPCK;
-        switch (lpdcb->Parity) {
-                case NOPARITY:
-                        break;
-                case ODDPARITY:
-                        port.c_cflag |= (PARENB | PARODD);
-                        break;
-                case EVENPARITY:
-                        port.c_cflag |= PARENB;
-                        break;
-#ifdef CMSPAR
-                /* Linux defines mark/space (stick) parity */
-                case MARKPARITY:
-                        port.c_cflag |= (PARENB | CMSPAR);
-                        break;
-                case SPACEPARITY:
-                        port.c_cflag |= (PARENB | PARODD |  CMSPAR);
-                        break;
-#else
-                /* try the POSIX way */
-                case MARKPARITY:
-                        if( stopbits == ONESTOPBIT) {
-                            stopbits = TWOSTOPBITS;
-                            port.c_iflag &= ~INPCK;
-                        } else {
-                            release_comm_fd( handle, fd );
-                            ERR("Cannot set MARK Parity\n");
-                            return FALSE;
-                        }
-                        break;
-                case SPACEPARITY:
-                        if( bytesize < 8) {
-                            bytesize +=1;
-                            port.c_iflag &= ~INPCK;
-                        } else {
-                            release_comm_fd( handle, fd );
-                            ERR("Cannot set SPACE Parity\n");
-                            return FALSE;
-                        }
-                        break;
-#endif
-               default:
-                        release_comm_fd( handle, fd );
-			ERR("Parity\n");
-                        return FALSE;
-        }
-
-
-	port.c_cflag &= ~CSIZE;
-	switch (bytesize) {
-		case 5:
-			port.c_cflag |= CS5;
-			break;
-		case 6:
-			port.c_cflag |= CS6;
-			break;
-		case 7:
-			port.c_cflag |= CS7;
-			break;
-		case 8:
-			port.c_cflag |= CS8;
-			break;
-		default:
-                        release_comm_fd( handle, fd );
-			ERR("ByteSize\n");
-			return FALSE;
-	}
-
-	switch (stopbits) {
-		case ONESTOPBIT:
-				port.c_cflag &= ~CSTOPB;
-				break;
-		case ONE5STOPBITS: /* will be selected if bytesize is 5 */
-		case TWOSTOPBITS:
-				port.c_cflag |= CSTOPB;
-				break;
-		default:
-                        release_comm_fd( handle, fd );
-			ERR("StopBits\n");
-			return FALSE;
-	}
 #ifdef CRTSCTS
 	if (	lpdcb->fOutxCtsFlow 			||
 		lpdcb->fRtsControl == RTS_CONTROL_HANDSHAKE
diff --git a/dlls/ntdll/serial.c b/dlls/ntdll/serial.c
index 0a7e56a..678b4fd 100644
--- a/dlls/ntdll/serial.c
+++ b/dlls/ntdll/serial.c
@@ -360,6 +360,112 @@ #endif
     return STATUS_SUCCESS;
 }
 
+static NTSTATUS set_line_control(int fd, const SERIAL_LINE_CONTROL* slc)
+{
+    struct termios port;
+    unsigned bytesize, stopbits;
+    
+    if (tcgetattr(fd, &port) == -1)
+    {
+        ERR("tcgetattr error '%s'\n", strerror(errno));
+        return FILE_GetNtStatus();
+    }
+    
+#ifdef IMAXBEL
+    port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK|IMAXBEL);
+#else
+    port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK);
+#endif
+    port.c_iflag |= IGNBRK | INPCK;
+    
+    port.c_oflag &= ~(OPOST);
+    
+    port.c_cflag &= ~(HUPCL);
+    port.c_cflag |= CLOCAL | CREAD;
+    
+    port.c_lflag &= ~(ICANON|ECHO|ISIG);
+    port.c_lflag |= NOFLSH;
+    
+    bytesize = slc->WordLength;
+    stopbits = slc->StopBits;
+    
+#ifdef CMSPAR
+    port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
+#else
+    port.c_cflag &= ~(PARENB | PARODD);
+#endif
+
+    switch (slc->Parity)
+    {
+    case NOPARITY:      port.c_iflag &= ~INPCK;                         break;
+    case ODDPARITY:     port.c_cflag |= PARENB | PARODD;                break;
+    case EVENPARITY:    port.c_cflag |= PARENB;                         break;
+#ifdef CMSPAR
+        /* Linux defines mark/space (stick) parity */
+    case MARKPARITY:    port.c_cflag |= PARENB | CMSPAR;                break;
+    case SPACEPARITY:   port.c_cflag |= PARENB | PARODD |  CMSPAR;      break;
+#else
+        /* try the POSIX way */
+    case MARKPARITY:
+        if (slc->StopBits == ONESTOPBIT)
+        {
+            stopbits = TWOSTOPBITS;
+            port.c_iflag &= ~INPCK;
+        }
+        else
+        {
+            ERR("Cannot set MARK Parity\n");
+            return STATUS_NOT_SUPPORTED;
+        }
+        break;
+    case SPACEPARITY:
+        if (slc->WordLength < 8)
+        {
+            bytesize +=1;
+            port.c_iflag &= ~INPCK;
+        }
+        else
+        {
+            ERR("Cannot set SPACE Parity\n");
+            return STATUS_NOT_SUPPORTED;
+        }
+        break;
+#endif
+    default:
+        ERR("Parity\n");
+        return STATUS_NOT_SUPPORTED;
+    }
+    
+    port.c_cflag &= ~CSIZE;
+    switch (bytesize)
+    {
+    case 5:     port.c_cflag |= CS5;    break;
+    case 6:     port.c_cflag |= CS6;    break;
+    case 7:	port.c_cflag |= CS7;	break;
+    case 8:	port.c_cflag |= CS8;	break;
+    default:
+        ERR("ByteSize\n");
+        return STATUS_NOT_SUPPORTED;
+    }
+    
+    switch (stopbits)
+    {
+    case ONESTOPBIT:    port.c_cflag &= ~CSTOPB;        break;
+    case ONE5STOPBITS: /* will be selected if bytesize is 5 */
+    case TWOSTOPBITS:	port.c_cflag |= CSTOPB;		break;
+    default:
+        ERR("StopBits\n");
+        return STATUS_NOT_SUPPORTED;
+    }
+    /* otherwise it hangs with pending input*/
+    if (tcsetattr(fd, TCSANOW, &port) == -1)
+    {
+        ERR("tcsetattr error '%s'\n", strerror(errno));
+        return FILE_GetNtStatus();
+    }
+    return STATUS_SUCCESS;
+}
+
 static NTSTATUS set_wait_mask(HANDLE hDevice, DWORD mask)
 {
     NTSTATUS status;
@@ -478,6 +584,12 @@ #else
 	status = STATUS_NOT_SUPPORTED;
 #endif
         break;
+    case IOCTL_SERIAL_SET_LINE_CONTROL:
+        if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL))
+            status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer);
+        else
+            status = STATUS_INVALID_PARAMETER;
+        break;
     case IOCTL_SERIAL_SET_WAIT_MASK:
         if (lpInBuffer && nInBufferSize == sizeof(DWORD))
         {




More information about the wine-cvs mailing list