[PATCH 01/11] [NtDll/Kernel32]: SetCommState & IOCTL_SET_BAUD_RATE

Eric Pouech eric.pouech at wanadoo.fr
Sun May 7 07:10:32 CDT 2006


- created dump_dcb to print out DCB information
- implemented ntdll's serial IOCTL SET_BAUD_RATE
- used this IOCTL in kernel32!SetCommState

A+
---

 dlls/kernel/comm.c  |  245 +++++++--------------------------------------------
 dlls/ntdll/serial.c |  140 +++++++++++++++++++++++++++++
 2 files changed, 174 insertions(+), 211 deletions(-)

diff --git a/dlls/kernel/comm.c b/dlls/kernel/comm.c
index cd25666..a641567 100644
--- a/dlls/kernel/comm.c
+++ b/dlls/kernel/comm.c
@@ -950,6 +950,21 @@ BOOL WINAPI SetCommMask(HANDLE handle, D
                            &evtmask, sizeof(evtmask), NULL, 0, NULL, NULL);
 }
 
+static void dump_dcb(const DCB* lpdcb)
+{
+    TRACE("bytesize=%d baudrate=%ld fParity=%d Parity=%d stopbits=%d\n",
+          lpdcb->ByteSize, lpdcb->BaudRate, lpdcb->fParity, lpdcb->Parity,
+          (lpdcb->StopBits == ONESTOPBIT) ? 1 :
+          (lpdcb->StopBits == TWOSTOPBITS) ? 2 : 0);
+    TRACE("%sIXON %sIXOFF\n", (lpdcb->fInX) ? "" : "~", (lpdcb->fOutX) ? "" : "~");
+    TRACE("fOutxCtsFlow=%d fRtsControl=%d\n", lpdcb->fOutxCtsFlow, lpdcb->fRtsControl);
+    TRACE("fOutxDsrFlow=%d fDtrControl=%d\n", lpdcb->fOutxDsrFlow, lpdcb->fDtrControl);
+    if (lpdcb->fOutxCtsFlow || lpdcb->fRtsControl == RTS_CONTROL_HANDSHAKE)
+        TRACE("CRTSCTS\n");
+    else
+        TRACE("~CRTSCTS\n");
+}
+
 /*****************************************************************************
  *	SetCommState    (KERNEL32.@)
  *
@@ -957,30 +972,34 @@ BOOL WINAPI SetCommMask(HANDLE handle, D
  *  with values from a device control block without effecting the input and output
  *  queues.
  *
+ * PARAMS
+ *
+ *      handle  [in]    The communications device
+ *      lpdcb   [out]   The device control block
+ *
  * RETURNS
  *
  *  True on success, false on failure eg if the XonChar is equal to the XoffChar.
  */
-BOOL WINAPI SetCommState(
-    HANDLE handle, /* [in] The communications device. */
-    LPDCB  lpdcb)  /* [out] The device control block. */
+BOOL WINAPI SetCommState( HANDLE handle, LPDCB lpdcb)
 {
      struct termios port;
      int fd, bytesize, stopbits;
      BOOL ret;
 
-     TRACE("handle %p, ptr %p\n", handle, lpdcb);
-     TRACE("bytesize %d baudrate %ld fParity %d Parity %d stopbits %d\n",
-	   lpdcb->ByteSize,lpdcb->BaudRate,lpdcb->fParity, lpdcb->Parity,
-	   (lpdcb->StopBits == ONESTOPBIT)?1:
-	   (lpdcb->StopBits == TWOSTOPBITS)?2:0);
-     TRACE("%s %s\n",(lpdcb->fInX)?"IXON":"~IXON",
-	   (lpdcb->fOutX)?"IXOFF":"~IXOFF");
-     TRACE("fOutxCtsFlow %d fRtsControl %d\n", lpdcb->fOutxCtsFlow,
-             lpdcb->fRtsControl);
-     TRACE("fOutxDsrFlow %d fDtrControl%d\n", lpdcb->fOutxDsrFlow,
-             lpdcb->fDtrControl);
-             
+    SERIAL_BAUD_RATE    sbr;
+ 
+    if (lpdcb == NULL)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+    dump_dcb(lpdcb);
+
+    sbr.BaudRate = lpdcb->BaudRate;
+    if (!DeviceIoControl(handle, IOCTL_SERIAL_SET_BAUD_RATE,
+                         &sbr, sizeof(sbr), NULL, 0, NULL, NULL))
+        return FALSE;
 
      fd = get_comm_fd( handle, FILE_READ_DATA );
      if (fd < 0) return FALSE;
@@ -1010,202 +1029,6 @@ BOOL WINAPI SetCommState(
 	port.c_lflag &= ~(ICANON|ECHO|ISIG);
 	port.c_lflag |= NOFLSH;
 
-#ifdef CBAUD
-	port.c_cflag &= ~CBAUD;
-	switch (lpdcb->BaudRate) {
-		case 0:
-			port.c_cflag |= B0;
-			break;
-		case 50:
-			port.c_cflag |= B50;
-			break;
-		case 75:
-			port.c_cflag |= B75;
-			break;
-		case 110:
-		case CBR_110:
-			port.c_cflag |= B110;
-			break;
-		case 134:
-			port.c_cflag |= B134;
-			break;
-		case 150:
-			port.c_cflag |= B150;
-			break;
-		case 200:
-			port.c_cflag |= B200;
-			break;
-		case 300:
-		case CBR_300:
-			port.c_cflag |= B300;
-			break;
-		case 600:
-		case CBR_600:
-			port.c_cflag |= B600;
-			break;
-		case 1200:
-		case CBR_1200:
-			port.c_cflag |= B1200;
-			break;
-		case 1800:
-			port.c_cflag |= B1800;
-			break;
-		case 2400:
-		case CBR_2400:
-			port.c_cflag |= B2400;
-			break;
-		case 4800:
-		case CBR_4800:
-			port.c_cflag |= B4800;
-			break;
-		case 9600:
-		case CBR_9600:
-			port.c_cflag |= B9600;
-			break;
-		case 19200:
-		case CBR_19200:
-			port.c_cflag |= B19200;
-			break;
-		case 38400:
-		case CBR_38400:
-			port.c_cflag |= B38400;
-			break;
-#ifdef B57600
-		case 57600:
-			port.c_cflag |= B57600;
-			break;
-#endif
-#ifdef B115200
-		case 115200:
-			port.c_cflag |= B115200;
-			break;
-#endif
-#ifdef B230400
-		case 230400:
-			port.c_cflag |= B230400;
-			break;
-#endif
-#ifdef B460800
-		case 460800:
-			port.c_cflag |= B460800;
-			break;
-#endif
-       	        default:
-#if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCSSERIAL)
-                        {   struct serial_struct nuts;
-			    int arby;
-			    ioctl(fd, TIOCGSERIAL, &nuts);
-			    nuts.custom_divisor = nuts.baud_base / lpdcb->BaudRate;
-			    if (!(nuts.custom_divisor)) nuts.custom_divisor = 1;
-			    arby = nuts.baud_base / nuts.custom_divisor;
-			    nuts.flags &= ~ASYNC_SPD_MASK;
-			    nuts.flags |= ASYNC_SPD_CUST;
-			    WARN("You (or a program acting at your behest) have specified\n"
-                                 "a non-standard baud rate %ld.  Wine will set the rate to %d,\n"
-                                 "which is as close as we can get by our present understanding of your\n"
-                                 "hardware. I hope you know what you are doing.  Any disruption Wine\n"
-                                 "has caused to your linux system can be undone with setserial \n"
-                                 "(see man setserial). If you have incapacitated a Hayes type modem,\n"
-                                 "reset it and it will probably recover.\n", lpdcb->BaudRate, arby);
-  			    ioctl(fd, TIOCSSERIAL, &nuts);
-			    port.c_cflag |= B38400;
- 			}
- 			break;
-#endif    /* Don't have linux/serial.h or lack TIOCSSERIAL */
-
-
-                        release_comm_fd( handle, fd );
-			ERR("baudrate %ld\n",lpdcb->BaudRate);
-			return FALSE;
-	}
-#elif !defined(__EMX__)
-        switch (lpdcb->BaudRate) {
-                case 0:
-                        port.c_ospeed = B0;
-                        break;
-                case 50:
-                        port.c_ospeed = B50;
-                        break;
-                case 75:
-                        port.c_ospeed = B75;
-                        break;
-                case 110:
-                case CBR_110:
-                        port.c_ospeed = B110;
-                        break;
-                case 134:
-                        port.c_ospeed = B134;
-                        break;
-                case 150:
-                        port.c_ospeed = B150;
-                        break;
-                case 200:
-                        port.c_ospeed = B200;
-                        break;
-                case 300:
-                case CBR_300:
-                        port.c_ospeed = B300;
-                        break;
-                case 600:
-                case CBR_600:
-                        port.c_ospeed = B600;
-                        break;
-                case 1200:
-                case CBR_1200:
-                        port.c_ospeed = B1200;
-                        break;
-                case 1800:
-                        port.c_ospeed = B1800;
-                        break;
-                case 2400:
-                case CBR_2400:
-                        port.c_ospeed = B2400;
-                        break;
-                case 4800:
-                case CBR_4800:
-                        port.c_ospeed = B4800;
-                        break;
-                case 9600:
-                case CBR_9600:
-                        port.c_ospeed = B9600;
-                        break;
-                case 19200:
-                case CBR_19200:
-                        port.c_ospeed = B19200;
-                        break;
-                case 38400:
-                case CBR_38400:
-                        port.c_ospeed = B38400;
-                        break;
-#ifdef B57600
-		case 57600:
-		case CBR_57600:
-			port.c_cflag |= B57600;
-			break;
-#endif
-#ifdef B115200
-		case 115200:
-		case CBR_115200:
-			port.c_cflag |= B115200;
-			break;
-#endif
-#ifdef B230400
-		case 230400:
-			port.c_cflag |= B230400;
-			break;
-#endif
-#ifdef B460800
-		case 460800:
-			port.c_cflag |= B460800;
-			break;
-#endif
-                default:
-                        release_comm_fd( handle, fd );
-			ERR("baudrate %ld\n",lpdcb->BaudRate);
-                        return FALSE;
-        }
-        port.c_ispeed = port.c_ospeed;
-#endif
         bytesize=lpdcb->ByteSize;
         stopbits=lpdcb->StopBits;
 
diff --git a/dlls/ntdll/serial.c b/dlls/ntdll/serial.c
index 879f6f1..0a7e56a 100644
--- a/dlls/ntdll/serial.c
+++ b/dlls/ntdll/serial.c
@@ -226,6 +226,140 @@ static NTSTATUS purge(int fd, DWORD flag
     return STATUS_SUCCESS;
 }
 
+static NTSTATUS set_baud_rate(int fd, const SERIAL_BAUD_RATE* sbr)
+{
+    struct termios port;
+
+    if (tcgetattr(fd, &port) == -1)
+    {
+        ERR("tcgetattr error '%s'\n", strerror(errno));
+        return FILE_GetNtStatus();
+    }
+
+#ifdef CBAUD
+    port.c_cflag &= ~CBAUD;
+    switch (sbr->BaudRate)
+    {
+    case 0:             port.c_cflag |= B0;     break;
+    case 50:            port.c_cflag |= B50;    break;
+    case 75:            port.c_cflag |= B75;    break;
+    case 110:   
+    case CBR_110:       port.c_cflag |= B110;   break;
+    case 134:           port.c_cflag |= B134;   break;
+    case 150:           port.c_cflag |= B150;   break;
+    case 200:           port.c_cflag |= B200;   break;
+    case 300:           
+    case CBR_300:       port.c_cflag |= B300;   break;
+    case 600:
+    case CBR_600:       port.c_cflag |= B600;   break;
+    case 1200:
+    case CBR_1200:	port.c_cflag |= B1200;  break;
+    case 1800:		port.c_cflag |= B1800;	break;
+    case 2400:
+    case CBR_2400:	port.c_cflag |= B2400;	break;
+    case 4800:
+    case CBR_4800:	port.c_cflag |= B4800;	break;
+    case 9600:
+    case CBR_9600:	port.c_cflag |= B9600;	break;
+    case 19200:
+    case CBR_19200:	port.c_cflag |= B19200;	break;
+    case 38400:
+    case CBR_38400:	port.c_cflag |= B38400;	break;
+#ifdef B57600
+    case 57600:		port.c_cflag |= B57600;	break;
+#endif
+#ifdef B115200
+    case 115200:	port.c_cflag |= B115200;break;
+#endif
+#ifdef B230400
+    case 230400:	port.c_cflag |= B230400;break;
+#endif
+#ifdef B460800
+    case 460800:	port.c_cflag |= B460800;break;
+#endif
+    default:
+#if defined (HAVE_LINUX_SERIAL_H) && defined (TIOCSSERIAL)
+        {
+            struct serial_struct nuts;
+            int arby;
+	
+            ioctl(fd, TIOCGSERIAL, &nuts);
+            nuts.custom_divisor = nuts.baud_base / sbr->BaudRate;
+            if (!(nuts.custom_divisor)) nuts.custom_divisor = 1;
+            arby = nuts.baud_base / nuts.custom_divisor;
+            nuts.flags &= ~ASYNC_SPD_MASK;
+            nuts.flags |= ASYNC_SPD_CUST;
+            WARN("You (or a program acting at your behest) have specified\n"
+                 "a non-standard baud rate %ld.  Wine will set the rate to %d,\n"
+                 "which is as close as we can get by our present understanding of your\n"
+                 "hardware. I hope you know what you are doing.  Any disruption Wine\n"
+                 "has caused to your linux system can be undone with setserial \n"
+                 "(see man setserial). If you have incapacitated a Hayes type modem,\n"
+                 "reset it and it will probably recover.\n", sbr->BaudRate, arby);
+            ioctl(fd, TIOCSSERIAL, &nuts);
+            port.c_cflag |= B38400;
+        }
+        break;
+#endif    /* Don't have linux/serial.h or lack TIOCSSERIAL */
+        ERR("baudrate %ld\n", sbr->BaudRate);
+        return STATUS_NOT_SUPPORTED;
+    }
+#elif !defined(__EMX__)
+    switch (sbr->BaudRate)
+    {
+    case 0:             port.c_ospeed = B0;     break;
+    case 50:            port.c_ospeed = B50;    break;
+    case 75:            port.c_ospeed = B75;    break;
+    case 110:
+    case CBR_110:       port.c_ospeed = B110;   break;
+    case 134:           port.c_ospeed = B134;   break;
+    case 150:           port.c_ospeed = B150;   break;
+    case 200:           port.c_ospeed = B200;   break;
+    case 300:
+    case CBR_300:       port.c_ospeed = B300;   break;
+    case 600:
+    case CBR_600:       port.c_ospeed = B600;   break;
+    case 1200:
+    case CBR_1200:      port.c_ospeed = B1200;  break;
+    case 1800:          port.c_ospeed = B1800;  break;
+    case 2400:
+    case CBR_2400:      port.c_ospeed = B2400;  break;
+    case 4800:
+    case CBR_4800:      port.c_ospeed = B4800;  break;
+    case 9600:
+    case CBR_9600:      port.c_ospeed = B9600;  break;
+    case 19200:
+    case CBR_19200:     port.c_ospeed = B19200; break;
+    case 38400:
+    case CBR_38400:     port.c_ospeed = B38400; break;
+#ifdef B57600
+    case 57600:
+    case CBR_57600:     port.c_cflag |= B57600; break;
+#endif
+#ifdef B115200
+    case 115200:
+    case CBR_115200:    port.c_cflag |= B115200;break;
+#endif
+#ifdef B230400
+    case 230400:	port.c_cflag |= B230400;break;
+#endif
+#ifdef B460800
+    case 460800:	port.c_cflag |= B460800;break;
+#endif
+    default:
+        ERR("baudrate %ld\n", sbr->BaudRate);
+        return STATUS_NOT_SUPPORTED;
+    }
+    port.c_ispeed = port.c_ospeed;
+#endif
+    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;
@@ -314,6 +448,12 @@ NTSTATUS COMM_DeviceIoControl(HANDLE hDe
         else
             status = STATUS_INVALID_PARAMETER;
         break;
+    case IOCTL_SERIAL_SET_BAUD_RATE:
+        if (lpInBuffer && nInBufferSize == sizeof(SERIAL_BAUD_RATE))
+            status = set_baud_rate(fd, (const SERIAL_BAUD_RATE*)lpInBuffer);
+        else
+            status = STATUS_INVALID_PARAMETER;
+        break;
     case IOCTL_SERIAL_SET_BREAK_OFF:
 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
 	if (ioctl(fd, TIOCCBRK, 0) == -1)





More information about the wine-patches mailing list