If the dibsection is based on a file-mapping object, then make sure
[wine] / dlls / kernel / comm.c
index e0a74cd..2f1a3fc 100644 (file)
@@ -3,41 +3,61 @@
  *
  * Copyright 1996 Marcus Meissner
  *
- * Mar 31, 1999. Ove Kåven <ovek@arcticnet.no>
- * - Implemented buffers and EnableCommNotification.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * History:
  *
  * Apr 3, 1999.  Lawson Whitney <lawson_whitney@juno.com>
  * - Fixed the modem control part of EscapeCommFunction16.
  *
+ * Mar 31, 1999. Ove Kåven <ovek@arcticnet.no>
+ * - Implemented buffers and EnableCommNotification.
+ *
  * Mar 3, 1999. Ove Kåven <ovek@arcticnet.no>
  * - Use port indices instead of unixfds for win16
  * - Moved things around (separated win16 and win32 routines)
  * - Added some hints on how to implement buffers and EnableCommNotification.
  *
+ * Oktober 98, Rein Klazes [RHK]
+ * A program that wants to monitor the modem status line (RLSD/DCD) may
+ * poll the modem status register in the commMask structure. I update the bit
+ * in GetCommError, waiting for an implementation of communication events.
+ *
+ * July 6, 1998. Fixes and comments by Valentijn Sessink
+ *                                     <vsessink@ic.uva.nl> [V]
+ *
+ * August 12, 1997.  Take a bash at SetCommEventMask - Lawson Whitney
+ *                                     <lawson_whitney@juno.com>
+ *
  * May 26, 1997.  Fixes and comments by Rick Richardson <rick@dgii.com> [RER]
  * - ptr->fd wasn't getting cleared on close.
  * - GetCommEventMask() and GetCommError() didn't do much of anything.
  *   IMHO, they are still wrong, but they at least implement the RXCHAR
  *   event and return I/O queue sizes, which makes the app I'm interested
  *   in (analog devices EZKIT DSP development system) work.
- *
- * August 12, 1997.  Take a bash at SetCommEventMask - Lawson Whitney
- *                                     <lawson_whitney@juno.com>
- * July 6, 1998. Fixes and comments by Valentijn Sessink
- *                                     <vsessink@ic.uva.nl> [V]
- * Oktober 98, Rein Klazes [RHK]
- * A program that wants to monitor the modem status line (RLSD/DCD) may
- * poll the modem status register in the commMask structure. I update the bit
- * in GetCommError, waiting for an implementation of communication events.
- * 
  */
 
 #include "config.h"
 #include "wine/port.h"
 
 #include <stdlib.h>
+#include <stdarg.h>
 #include <stdio.h>
+#ifdef HAVE_TERMIOS_H
 #include <termios.h>
+#endif
 #include <fcntl.h>
 #include <string.h>
 #ifdef HAVE_STRINGS_H
 #ifdef HAVE_SYS_FILIO_H
 # include <sys/filio.h>
 #endif
+#ifdef HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
-#include <unistd.h>
-#include <sys/poll.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef HAVE_SYS_POLL_H
+# include <sys/poll.h>
+#endif
 #ifdef HAVE_SYS_MODEM_H
 # include <sys/modem.h>
 #endif
 # include <sys/strtio.h>
 #endif
 
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+#include "ntstatus.h"
+#include "windef.h"
 #include "winbase.h"
 #include "winerror.h"
 
 #include "wine/server.h"
-#include "file.h"
-#include "heap.h"
-
-#include "debugtools.h"
+#include "wine/unicode.h"
+#include "thread.h"
 
-DEFAULT_DEBUG_CHANNEL(comm);
+#include "wine/debug.h"
 
-#if !defined(TIOCINQ) && defined(FIONREAD)
-#define        TIOCINQ FIONREAD
+#ifdef HAVE_LINUX_SERIAL_H
+#include <linux/serial.h>
 #endif
 
-static int WinError(void)
+WINE_DEFAULT_DEBUG_CHANNEL(comm);
+
+/* retrieve the Unix handle corresponding to a comm handle */
+static int get_comm_fd( HANDLE handle, DWORD access )
 {
-        TRACE("errno = %d\n", errno);
-       switch (errno) {
-               default:
-                       return CE_IOE;
-               }
+    int fd, ret;
+
+    ret = wine_server_handle_to_fd( handle, access, &fd, NULL );
+    if (ret) SetLastError( RtlNtStatusToDosError(ret) );
+    return fd;
 }
 
+/* release the Unix handle returned by get_comm_fd */
+static inline void release_comm_fd( HANDLE handle, int fd )
+{
+    wine_server_release_fd( handle, fd );
+}
+
+
+/***********************************************************************
+ * Asynchronous I/O for asynchronous wait requests                     *
+ */
+
+typedef struct async_commio
+{
+    HANDLE              handle;
+    PIO_APC_ROUTINE     apc_internal;
+    int                 type;
+    char*               buffer;
+    int                 fd;
+} async_commio;
+
+/***********************************************************************/
+
+#if !defined(TIOCINQ) && defined(FIONREAD)
+#define        TIOCINQ FIONREAD
+#endif
+
 static int COMM_WhackModem(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
 }
 
 /***********************************************************************
- *           COMM_BuildOldCommDCB   (Internal)
+ *           COMM_Parse*   (Internal)
  *
- *  Build a DCB using the old style settings string eg: "COMx:96,n,8,1"
- *  We ignore the COM port index, since we can support more than 4 ports.
+ *  The following COMM_Parse* functions are used by the BuildCommDCB
+ *  functions to help parse the various parts of the device control string.
  */
-BOOL WINAPI COMM_BuildOldCommDCB(LPCSTR device, LPDCB lpdcb)
+static LPCWSTR COMM_ParseStart(LPCWSTR ptr)
 {
-       /* "COM1:96,n,8,1"      */
-       /*  012345              */
-       char *ptr, temp[256], last;
-       int rate;
+       static const WCHAR comW[] = {'C','O','M',0};
 
-       TRACE("(%s), ptr %p\n", device, lpdcb);
+       /* The device control string may optionally start with "COMx" followed
+          by an optional ':' and spaces. */
+       if(!strncmpiW(ptr, comW, 3))
+       {
+               ptr += 3;
+
+               /* Allow any com port above 0 as Win 9x does (NT only allows
+                  values for com ports which are actually present) */
+               if(*ptr < '1' || *ptr > '9')
+                       return NULL;
+               
+               /* Advance pointer past port number */
+               while(*ptr >= '0' && *ptr <= '9') ptr++;
+               
+               /* The com port number must be followed by a ':' or ' ' */
+               if(*ptr != ':' && *ptr != ' ')
+                       return NULL;
+
+               /* Advance pointer to beginning of next parameter */
+               while(*ptr == ' ') ptr++;
+               if(*ptr == ':')
+               {
+                       ptr++;
+                       while(*ptr == ' ') ptr++;
+               }
+       }
+       /* The device control string must not start with a space. */
+       else if(*ptr == ' ')
+               return NULL;
+       
+       return ptr;
+}
+static LPCWSTR COMM_ParseNumber(LPCWSTR ptr, LPDWORD lpnumber)
+{
+       if(*ptr < '0' || *ptr > '9') return NULL;
+       *lpnumber = strtoulW(ptr, NULL, 10);
+       while(*ptr >= '0' && *ptr <= '9') ptr++;
+       return ptr;
+}
 
-       if (strncasecmp(device,"COM",3))
-               return FALSE;
+static LPCWSTR COMM_ParseParity(LPCWSTR ptr, LPBYTE lpparity)
+{
+       /* Contrary to what you might expect, Windows only sets the Parity
+          member of DCB and not fParity even when parity is specified in the
+          device control string */
 
-       if (!*(device+4))
-               return FALSE;
+       switch(toupperW(*ptr++))
+       {
+       case 'E':
+               *lpparity = EVENPARITY;
+               break;
+       case 'M':
+               *lpparity = MARKPARITY;
+               break;
+       case 'N':
+               *lpparity = NOPARITY;
+               break;
+       case 'O':
+               *lpparity = ODDPARITY;
+               break;
+       case 'S':
+               *lpparity = SPACEPARITY;
+               break;
+       default:
+               return NULL;
+       }
 
-       if (*(device+4) != ':')
-               return FALSE;
+       return ptr;
+}
+
+static LPCWSTR COMM_ParseByteSize(LPCWSTR ptr, LPBYTE lpbytesize)
+{
+       DWORD temp;
+
+       if(!(ptr = COMM_ParseNumber(ptr, &temp)))
+               return NULL;
+
+       if(temp >= 5 && temp <= 8)
+       {
+               *lpbytesize = temp;
+               return ptr;
+       }
+       else
+               return NULL;
+}
+
+static LPCWSTR COMM_ParseStopBits(LPCWSTR ptr, LPBYTE lpstopbits)
+{
+       DWORD temp;
+       static const WCHAR stopbits15W[] = {'1','.','5',0};
+
+       if(!strncmpW(stopbits15W, ptr, 3))
+       {
+               ptr += 3;
+               *lpstopbits = ONE5STOPBITS;
+       }
+       else
+       {
+               if(!(ptr = COMM_ParseNumber(ptr, &temp)))
+                       return NULL;
+
+               if(temp == 1)
+                       *lpstopbits = ONESTOPBIT;
+               else if(temp == 2)
+                       *lpstopbits = TWOSTOPBITS;
+               else
+                       return NULL;
+       }
        
-       strcpy(temp,device+5);
-       last=temp[strlen(temp)-1];
-       ptr = strtok(temp, ", "); 
-
-        /* DOS/Windows only compares the first two numbers
-        * and assigns an appropriate baud rate.
-        * You can supply 961324245, it still returns 9600 ! */
-       if (strlen(ptr) < 2)
+       return ptr;
+}
+
+static LPCWSTR COMM_ParseOnOff(LPCWSTR ptr, LPDWORD lponoff)
+{
+       static const WCHAR onW[] = {'o','n',0};
+       static const WCHAR offW[] = {'o','f','f',0};
+
+       if(!strncmpiW(onW, ptr, 2))
+       {
+               ptr += 2;
+               *lponoff = 1;
+       }
+       else if(!strncmpiW(offW, ptr, 3))
        {
-               WARN("Unknown baudrate string '%s' !\n", ptr);
-               return FALSE; /* error: less than 2 chars */
+               ptr += 3;
+               *lponoff = 0;
        }
-       ptr[2] = '\0';
-       rate = atoi(ptr);
+       else
+               return NULL;
+
+       return ptr;
+}
+
+/***********************************************************************
+ *           COMM_BuildOldCommDCB   (Internal)
+ *
+ *  Build a DCB using the old style settings string eg: "96,n,8,1"
+ */
+static BOOL COMM_BuildOldCommDCB(LPCWSTR device, LPDCB lpdcb)
+{
+       WCHAR last = 0;
 
-       switch (rate) {
+       if(!(device = COMM_ParseNumber(device, &lpdcb->BaudRate)))
+               return FALSE;
+       
+       switch(lpdcb->BaudRate)
+       {
        case 11:
        case 30:
        case 60:
-               rate *= 10;
+               lpdcb->BaudRate *= 10;
                break;
        case 12:
        case 24:
        case 48:
        case 96:
-               rate *= 100;
+               lpdcb->BaudRate *= 100;
                break;
        case 19:
-               rate = 19200;
+               lpdcb->BaudRate = 19200;
                break;
-       default:
-               WARN("Unknown baudrate indicator %d !\n", rate);
-               return FALSE;
        }
-                       
-        lpdcb->BaudRate = rate;
-       TRACE("baudrate (%ld)\n", lpdcb->BaudRate);
 
-       ptr = strtok(NULL, ", ");
-       if (islower(*ptr))
-               *ptr = toupper(*ptr);
+       while(*device == ' ') device++;
+       if(*device++ != ',') return FALSE;
+       while(*device == ' ') device++;
 
-               TRACE("parity (%c)\n", *ptr);
-       lpdcb->fParity = TRUE;
-       switch (*ptr) {
-       case 'N':
-               lpdcb->Parity = NOPARITY;
-               lpdcb->fParity = FALSE;
-               break;                  
-       case 'E':
-               lpdcb->Parity = EVENPARITY;
-               break;                  
-       case 'M':
-               lpdcb->Parity = MARKPARITY;
-               break;                  
-       case 'O':
-               lpdcb->Parity = ODDPARITY;
-               break;                  
-       default:
-               WARN("Unknown parity `%c'!\n", *ptr);
+       if(!(device = COMM_ParseParity(device, &lpdcb->Parity)))
+               return FALSE;
+
+       while(*device == ' ') device++;
+       if(*device++ != ',') return FALSE;
+       while(*device == ' ') device++;
+               
+       if(!(device = COMM_ParseByteSize(device, &lpdcb->ByteSize)))
                return FALSE;
+
+       while(*device == ' ') device++;
+       if(*device++ != ',') return FALSE;
+       while(*device == ' ') device++;
+
+       if(!(device = COMM_ParseStopBits(device, &lpdcb->StopBits)))
+               return FALSE;
+
+       /* The last parameter for flow control is optional. */
+       while(*device == ' ') device++;
+       if(*device == ',')
+       {
+               device++;
+               while(*device == ' ') device++;
+               if(*device) last = toupperW(*device++);
+               while(*device == ' ') device++;
        }
 
-       ptr = strtok(NULL, ", "); 
-               TRACE("charsize (%c)\n", *ptr);
-       lpdcb->ByteSize = *ptr - '0';
-
-       ptr = strtok(NULL, ", ");
-               TRACE("stopbits (%c)\n", *ptr);
-       switch (*ptr) {
-       case '1':
-               lpdcb->StopBits = ONESTOPBIT;
-               break;                  
-       case '2':
-               lpdcb->StopBits = TWOSTOPBITS;
-               break;                  
+       /* Win NT sets the flow control members based on (or lack of) the last
+          parameter.  Win 9x does not set these members. */
+       switch(last)
+       {
+       case 0:
+               lpdcb->fInX = FALSE;
+               lpdcb->fOutX = FALSE;
+               lpdcb->fOutxCtsFlow = FALSE;
+               lpdcb->fOutxDsrFlow = FALSE;
+               lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
+               lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
+               break;
+       case 'X':
+               lpdcb->fInX = TRUE;
+               lpdcb->fOutX = TRUE;
+               lpdcb->fOutxCtsFlow = FALSE;
+               lpdcb->fOutxDsrFlow = FALSE;
+               lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
+               lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
+               break;
+       case 'P':
+               lpdcb->fInX = FALSE;
+               lpdcb->fOutX = FALSE;
+               lpdcb->fOutxCtsFlow = TRUE;
+               lpdcb->fOutxDsrFlow = TRUE;
+               lpdcb->fDtrControl = DTR_CONTROL_HANDSHAKE;
+               lpdcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
+               break;
        default:
-               WARN("Unknown # of stopbits `%c'!\n", *ptr);
                return FALSE;
-       }       
+       }
 
-       if (last == 'x') {
-               lpdcb->fInX             = TRUE;
-               lpdcb->fOutX            = TRUE;
-               lpdcb->fOutxCtsFlow     = FALSE;
-               lpdcb->fOutxDsrFlow     = FALSE;
-               lpdcb->fDtrControl      = DTR_CONTROL_ENABLE;
-               lpdcb->fRtsControl      = RTS_CONTROL_ENABLE;
-       } else if (last=='p') {
-               lpdcb->fInX             = FALSE;
-               lpdcb->fOutX            = FALSE;
-               lpdcb->fOutxCtsFlow     = TRUE;
-               lpdcb->fOutxDsrFlow     = TRUE;
-               lpdcb->fDtrControl      = DTR_CONTROL_HANDSHAKE;
-               lpdcb->fRtsControl      = RTS_CONTROL_HANDSHAKE;
-       } else {
-               lpdcb->fInX             = FALSE;
-               lpdcb->fOutX            = FALSE;
-               lpdcb->fOutxCtsFlow     = FALSE;
-               lpdcb->fOutxDsrFlow     = FALSE;
-               lpdcb->fDtrControl      = DTR_CONTROL_ENABLE;
-               lpdcb->fRtsControl      = RTS_CONTROL_ENABLE;
+       /* This should be the end of the string. */
+       if(*device) return FALSE;
+       
+       return TRUE;
+}
+
+/***********************************************************************
+ *           COMM_BuildNewCommDCB   (Internal)
+ *
+ *  Build a DCB using the new style settings string.
+ *   eg: "baud=9600 parity=n data=8 stop=1 xon=on to=on"
+ */
+static BOOL COMM_BuildNewCommDCB(LPCWSTR device, LPDCB lpdcb, LPCOMMTIMEOUTS lptimeouts)
+{
+       DWORD temp;
+       BOOL baud = FALSE, stop = FALSE;
+       static const WCHAR baudW[] = {'b','a','u','d','=',0};
+       static const WCHAR parityW[] = {'p','a','r','i','t','y','=',0};
+       static const WCHAR dataW[] = {'d','a','t','a','=',0};
+       static const WCHAR stopW[] = {'s','t','o','p','=',0};
+       static const WCHAR toW[] = {'t','o','=',0};
+       static const WCHAR xonW[] = {'x','o','n','=',0};
+       static const WCHAR odsrW[] = {'o','d','s','r','=',0};
+       static const WCHAR octsW[] = {'o','c','t','s','=',0};
+       static const WCHAR dtrW[] = {'d','t','r','=',0};
+       static const WCHAR rtsW[] = {'r','t','s','=',0};
+       static const WCHAR idsrW[] = {'i','d','s','r','=',0};
+
+       while(*device)
+       {
+               while(*device == ' ') device++;
+
+               if(!strncmpiW(baudW, device, 5))
+               {
+                       baud = TRUE;
+                       
+                       if(!(device = COMM_ParseNumber(device + 5, &lpdcb->BaudRate)))
+                               return FALSE;
+               }
+               else if(!strncmpiW(parityW, device, 7))
+               {
+                       if(!(device = COMM_ParseParity(device + 7, &lpdcb->Parity)))
+                               return FALSE;
+               }
+               else if(!strncmpiW(dataW, device, 5))
+               {
+                       if(!(device = COMM_ParseByteSize(device + 5, &lpdcb->ByteSize)))
+                               return FALSE;
+               }
+               else if(!strncmpiW(stopW, device, 5))
+               {
+                       stop = TRUE;
+                       
+                       if(!(device = COMM_ParseStopBits(device + 5, &lpdcb->StopBits)))
+                               return FALSE;
+               }
+               else if(!strncmpiW(toW, device, 3))
+               {
+                       if(!(device = COMM_ParseOnOff(device + 3, &temp)))
+                               return FALSE;
+
+                       lptimeouts->ReadIntervalTimeout = 0;
+                       lptimeouts->ReadTotalTimeoutMultiplier = 0;
+                       lptimeouts->ReadTotalTimeoutConstant = 0;
+                       lptimeouts->WriteTotalTimeoutMultiplier = 0;
+                       lptimeouts->WriteTotalTimeoutConstant = temp ? 60000 : 0;
+               }
+               else if(!strncmpiW(xonW, device, 4))
+               {
+                       if(!(device = COMM_ParseOnOff(device + 4, &temp)))
+                               return FALSE;
+
+                       lpdcb->fOutX = temp;
+                       lpdcb->fInX = temp;
+               }
+               else if(!strncmpiW(odsrW, device, 5))
+               {
+                       if(!(device = COMM_ParseOnOff(device + 5, &temp)))
+                               return FALSE;
+
+                       lpdcb->fOutxDsrFlow = temp;
+               }
+               else if(!strncmpiW(octsW, device, 5))
+               {
+                       if(!(device = COMM_ParseOnOff(device + 5, &temp)))
+                               return FALSE;
+
+                       lpdcb->fOutxCtsFlow = temp;
+               }
+               else if(!strncmpiW(dtrW, device, 4))
+               {
+                       if(!(device = COMM_ParseOnOff(device + 4, &temp)))
+                               return FALSE;
+
+                       lpdcb->fDtrControl = temp;
+               }
+               else if(!strncmpiW(rtsW, device, 4))
+               {
+                       if(!(device = COMM_ParseOnOff(device + 4, &temp)))
+                               return FALSE;
+
+                       lpdcb->fRtsControl = temp;
+               }
+               else if(!strncmpiW(idsrW, device, 5))
+               {
+                       if(!(device = COMM_ParseOnOff(device + 5, &temp)))
+                               return FALSE;
+
+                       /* Win NT sets the fDsrSensitivity member based on the
+                          idsr parameter.  Win 9x sets fOutxDsrFlow instead. */
+                       lpdcb->fDsrSensitivity = temp;
+               }
+               else
+                       return FALSE;
+
+               /* After the above parsing, the next character (if not the end of
+                  the string) should be a space */
+               if(*device && *device != ' ')
+                       return FALSE;
+       }
+
+       /* If stop bits were not specified, a default is always supplied. */
+       if(!stop)
+       {
+               if(baud && lpdcb->BaudRate == 110)
+                       lpdcb->StopBits = TWOSTOPBITS;
+               else
+                       lpdcb->StopBits = ONESTOPBIT;
        }
 
-       return 0;
+       return TRUE;
 }
 
 /**************************************************************************
@@ -233,7 +533,7 @@ BOOL WINAPI COMM_BuildOldCommDCB(LPCSTR device, LPDCB lpdcb)
  *
  * RETURNS
  *
- *  True on success, false on an malformed control string.
+ *  True on success, false on a malformed control string.
  */
 BOOL WINAPI BuildCommDCBA(
     LPCSTR device, /* [in] The ascii device control string used to update the DCB. */
@@ -243,122 +543,87 @@ BOOL WINAPI BuildCommDCBA(
 }
 
 /**************************************************************************
- *         BuildCommDCBAndTimeoutsA    (KERNEL32.@)
+ *         BuildCommDCBAndTimeoutsA            (KERNEL32.@)
  *
  *  Updates a device control block data structure with values from an
- *  ascii device control string.  Taking time out values from a time outs
+ *  ascii device control string.  Taking timeout values from a timeouts
  *  struct if desired by the control string.
  *
  * RETURNS
  *
- *  True on success, false bad handles etc
+ *  True on success, false bad handles etc.
  */
 BOOL WINAPI BuildCommDCBAndTimeoutsA(
     LPCSTR         device,     /* [in] The ascii device control string. */
     LPDCB          lpdcb,      /* [out] The device control block to be updated. */
-    LPCOMMTIMEOUTS lptimeouts) /* [in] The time outs to use if asked to set them by the control string. */
+    LPCOMMTIMEOUTS lptimeouts) /* [in] The COMMTIMEOUTS structure to be updated. */
 {
-       int     port;
-       char    *ptr,*temp;
+       BOOL ret = FALSE;
+       UNICODE_STRING deviceW;
 
        TRACE("(%s,%p,%p)\n",device,lpdcb,lptimeouts);
+       if(device) RtlCreateUnicodeStringFromAsciiz(&deviceW,device);
+       else deviceW.Buffer = NULL;
 
-       if (!strncasecmp(device,"COM",3)) {
-               port=device[3]-'0';
-               if (port--==0) {
-                       ERR("BUG! COM0 can't exist!\n");
-                       return FALSE;
-               }
-               if (*(device+4)!=':')
-                       return FALSE;
-               temp=(LPSTR)(device+5);
-       } else
-               temp=(LPSTR)device;
+       if(deviceW.Buffer) ret = BuildCommDCBAndTimeoutsW(deviceW.Buffer,lpdcb,lptimeouts);
 
-       memset(lpdcb,0,sizeof (DCB));
-       lpdcb->DCBlength        = sizeof(DCB);
-       if (strchr(temp,',')) { /* old style */
-
-               return COMM_BuildOldCommDCB(device,lpdcb);
-       }
-       ptr=strtok(temp," "); 
-       while (ptr) {
-               DWORD   flag,x;
-
-               flag=0;
-               if (!strncmp("baud=",ptr,5)) {
-                       if (!sscanf(ptr+5,"%ld",&x))
-                               WARN("Couldn't parse %s\n",ptr);
-                       lpdcb->BaudRate = x;
-                       flag=1;
-               }
-               if (!strncmp("stop=",ptr,5)) {
-                       if (!sscanf(ptr+5,"%ld",&x))
-                               WARN("Couldn't parse %s\n",ptr);
-                       lpdcb->StopBits = x;
-                       flag=1;
-               }
-               if (!strncmp("data=",ptr,5)) {
-                       if (!sscanf(ptr+5,"%ld",&x))
-                               WARN("Couldn't parse %s\n",ptr);
-                       lpdcb->ByteSize = x;
-                       flag=1;
-               }
-               if (!strncmp("parity=",ptr,7)) {
-                       lpdcb->fParity  = TRUE;
-                       switch (ptr[8]) {
-                       case 'N':case 'n':
-                               lpdcb->fParity  = FALSE;
-                               lpdcb->Parity   = NOPARITY;
-                               break;
-                       case 'E':case 'e':
-                               lpdcb->Parity   = EVENPARITY;
-                               break;
-                       case 'O':case 'o':
-                               lpdcb->Parity   = ODDPARITY;
-                               break;
-                       case 'M':case 'm':
-                               lpdcb->Parity   = MARKPARITY;
-                               break;
-                       }
-                       flag=1;
-               }
-               if (!flag)
-                       ERR("Unhandled specifier '%s', please report.\n",ptr);
-               ptr=strtok(NULL," ");
-       }
-       if (lpdcb->BaudRate==110)
-               lpdcb->StopBits = 2;
-       return TRUE;
+       RtlFreeUnicodeString(&deviceW);
+       return ret;
 }
 
 /**************************************************************************
- *         BuildCommDCBAndTimeoutsW            (KERNEL32.@)
+ *         BuildCommDCBAndTimeoutsW    (KERNEL32.@)
  *
- *  Updates a device control block data structure with values from an
- *  unicode device control string.  Taking time out values from a time outs
+ *  Updates a device control block data structure with values from a
+ *  unicode device control string.  Taking timeout values from a timeouts
  *  struct if desired by the control string.
  *
  * RETURNS
  *
- *  True on success, false bad handles etc.
+ *  True on success, false bad handles etc
  */
 BOOL WINAPI BuildCommDCBAndTimeoutsW(
     LPCWSTR        devid,      /* [in] The unicode device control string. */
     LPDCB          lpdcb,      /* [out] The device control block to be updated. */
-    LPCOMMTIMEOUTS lptimeouts) /* [in] The time outs to use if asked to set them by the control string. */
+    LPCOMMTIMEOUTS lptimeouts) /* [in] The COMMTIMEOUTS structure to be updated. */
 {
-       BOOL ret = FALSE;
-       LPSTR   devidA;
+       DCB dcb;
+       COMMTIMEOUTS timeouts;
+       BOOL result;
+       LPCWSTR ptr = devid;
+       
+       TRACE("(%s,%p,%p)\n",debugstr_w(devid),lpdcb,lptimeouts);
 
-       TRACE("(%p,%p,%p)\n",devid,lpdcb,lptimeouts);
-       devidA = HEAP_strdupWtoA( GetProcessHeap(), 0, devid );
-       if (devidA)
+       /* Set DCBlength. (Windows NT does not do this, but 9x does) */
+       lpdcb->DCBlength = sizeof(DCB);
+
+       /* Make a copy of the original data structures to work with since if
+          if there is an error in the device control string the originals
+          should not be modified (except possibly DCBlength) */
+       memcpy(&dcb, lpdcb, sizeof(DCB));
+       if(lptimeouts) memcpy(&timeouts, lptimeouts, sizeof(COMMTIMEOUTS));
+
+       ptr = COMM_ParseStart(ptr);
+
+       if(ptr == NULL)
+               result = FALSE;
+       else if(strchrW(ptr, ','))
+               result = COMM_BuildOldCommDCB(ptr, &dcb);
+       else
+               result = COMM_BuildNewCommDCB(ptr, &dcb, &timeouts);
+
+       if(result)
        {
-       ret=BuildCommDCBAndTimeoutsA(devidA,lpdcb,lptimeouts);
-        HeapFree( GetProcessHeap(), 0, devidA );
+               memcpy(lpdcb, &dcb, sizeof(DCB));
+               if(lptimeouts) memcpy(lptimeouts, &timeouts, sizeof(COMMTIMEOUTS));
+               return TRUE;
        }
-       return ret;
+       else
+       {
+               WARN("Invalid device control string: %s\n", debugstr_w(devid));
+               SetLastError(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }       
 }
 
 /**************************************************************************
@@ -379,8 +644,38 @@ BOOL WINAPI BuildCommDCBW(
        return BuildCommDCBAndTimeoutsW(devid,lpdcb,NULL);
 }
 
-/* FIXME: having these global for win32 for now */
-int commerror=0;
+static BOOL COMM_SetCommError(HANDLE handle, DWORD error)
+{
+    DWORD ret;
+
+    SERVER_START_REQ( set_serial_info )
+    {
+        req->handle = handle;
+        req->flags = SERIALINFO_SET_ERROR;
+        req->commerror = error;
+        ret = !wine_server_call_err( req );
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
+static BOOL COMM_GetCommError(HANDLE handle, LPDWORD lperror)
+{
+    DWORD ret;
+
+    if(!lperror)
+        return FALSE;
+
+    SERVER_START_REQ( get_serial_info )
+    {
+        req->handle = handle;
+        ret = !wine_server_call_err( req );
+        *lperror = reply->commerror;
+    }
+    SERVER_END_REQ;
+
+    return ret;
+}
 
 /*****************************************************************************
  *     SetCommBreak            (KERNEL32.@)
@@ -394,21 +689,18 @@ int commerror=0;
  *
  * BUGS
  *
- *  Only TIOCSBRK and TIOCCBRK are supported. 
+ *  Only TIOCSBRK and TIOCCBRK are supported.
  */
 BOOL WINAPI SetCommBreak(
-    HANDLE handle) /* [in] The communictions device to suspend. */
+    HANDLE handle) /* [in] The communications device to suspend. */
 {
 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
         int fd,result;
-       fd = FILE_GetUnixHandle( handle, GENERIC_READ );
-       if(fd<0) {
-               TRACE("FILE_GetUnixHandle failed\n");
-               return FALSE;
-       }
+
+       fd = get_comm_fd( handle, GENERIC_READ );
+       if(fd<0) return FALSE;
        result = ioctl(fd,TIOCSBRK,0);
-       close(fd);
+       release_comm_fd( handle, fd );
        if (result ==-1)
          {
                TRACE("ioctl failed\n");
@@ -434,21 +726,18 @@ BOOL WINAPI SetCommBreak(
  *
  * BUGS
  *
- *  Only TIOCSBRK and TIOCCBRK are supported. 
+ *  Only TIOCSBRK and TIOCCBRK are supported.
  */
 BOOL WINAPI ClearCommBreak(
     HANDLE handle) /* [in] The halted communication device whose character transmission is to be resumed. */
 {
 #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */
         int fd,result;
-       fd = FILE_GetUnixHandle( handle, GENERIC_READ );
-       if(fd<0) {
-               TRACE("FILE_GetUnixHandle failed\n");
-               return FALSE;
-       }
+
+       fd = get_comm_fd( handle, GENERIC_READ );
+       if(fd<0) return FALSE;
        result = ioctl(fd,TIOCCBRK,0);
-       close(fd);
+       release_comm_fd( handle, fd );
        if (result ==-1)
          {
                TRACE("ioctl failed\n");
@@ -481,23 +770,20 @@ BOOL WINAPI EscapeCommFunction(
        int fd,direct=FALSE,result=FALSE;
        struct termios  port;
 
-       TRACE("handle %d, function=%d\n", handle, nFunction);
-       fd = FILE_GetUnixHandle( handle, GENERIC_READ );
-       if(fd<0) {
-               FIXME("handle %d not found.\n",handle);
-               return FALSE;
-       }
+       TRACE("handle %p, function=%d\n", handle, nFunction);
+       fd = get_comm_fd( handle, GENERIC_READ );
+       if(fd<0) return FALSE;
 
        if (tcgetattr(fd,&port) == -1) {
-               commerror=WinError();
-               close(fd);
+               COMM_SetCommError(handle,CE_IOE);
+               release_comm_fd( handle, fd );
                return FALSE;
        }
 
        switch (nFunction) {
                case RESETDEV:
                        TRACE("\n");
-                       break;                                  
+                       break;
 
                case CLRDTR:
                        TRACE("CLRDTR\n");
@@ -514,7 +800,7 @@ BOOL WINAPI EscapeCommFunction(
                        result= COMM_WhackModem(fd, ~TIOCM_RTS, 0);
                        break;
 #endif
-       
+
                case SETDTR:
                        TRACE("SETDTR\n");
 #ifdef TIOCM_DTR
@@ -525,7 +811,7 @@ BOOL WINAPI EscapeCommFunction(
 
                case SETRTS:
                        TRACE("SETRTS\n");
-#ifdef TIOCM_DTR
+#ifdef TIOCM_RTS
                        direct=TRUE;
                        result= COMM_WhackModem(fd, 0, TIOCM_RTS);
                        break;
@@ -555,29 +841,29 @@ BOOL WINAPI EscapeCommFunction(
                        break;
 #endif
                default:
-                       WARN("(handle=%d,nFunction=%d): Unknown function\n", 
+                       WARN("(handle=%p,nFunction=%d): Unknown function\n",
                        handle, nFunction);
-                       break;                          
+                       break;
        }
-       
+
        if (!direct)
          if (tcsetattr(fd, TCSADRAIN, &port) == -1) {
-               commerror = WinError();
-               close(fd);
-               return FALSE;   
-         } else 
+               release_comm_fd( handle, fd );
+               COMM_SetCommError(handle,CE_IOE);
+               return FALSE;
+         } else
                result= TRUE;
        else
          {
            if (result == -1)
              {
                result= FALSE;
-               commerror=WinError();
+               COMM_SetCommError(handle,CE_IOE);
              }
            else
              result = TRUE;
          }
-       close(fd);
+       release_comm_fd( handle, fd );
        return result;
 }
 
@@ -597,13 +883,10 @@ BOOL WINAPI PurgeComm(
 {
      int fd;
 
-     TRACE("handle %d, flags %lx\n", handle, flags);
+     TRACE("handle %p, flags %lx\n", handle, flags);
 
-     fd = FILE_GetUnixHandle( handle, GENERIC_READ );
-     if(fd<0) {
-       FIXME("no handle %d found\n",handle);
-       return FALSE;
-     }
+     fd = get_comm_fd( handle, GENERIC_READ );
+     if(fd<0) return FALSE;
 
      /*
      ** not exactly sure how these are different
@@ -618,7 +901,7 @@ BOOL WINAPI PurgeComm(
          tcflush(fd,TCOFLUSH);
      if(flags&PURGE_RXCLEAR)
          tcflush(fd,TCIFLUSH);
-     close(fd);
+     release_comm_fd( handle, fd );
 
      return 1;
 }
@@ -640,16 +923,19 @@ BOOL WINAPI ClearCommError(
 {
     int fd;
 
-    fd=FILE_GetUnixHandle( handle, GENERIC_READ );
-    if(0>fd) 
-    {
-       FIXME("no handle %d found\n",handle);
-        return FALSE;
-    }
+    fd=get_comm_fd( handle, GENERIC_READ );
+    if(0>fd) return FALSE;
 
-    if (lpStat) 
+    if (lpStat)
     {
-       lpStat->status = 0;
+        lpStat->fCtsHold = 0;
+       lpStat->fDsrHold = 0;
+       lpStat->fRlsdHold = 0;
+       lpStat->fXoffHold = 0;
+       lpStat->fXoffSent = 0;
+       lpStat->fEof = 0;
+       lpStat->fTxim = 0;
+       lpStat->fReserved = 0;
 
 #ifdef TIOCOUTQ
        if(ioctl(fd, TIOCOUTQ, &lpStat->cbOutQue))
@@ -663,21 +949,14 @@ BOOL WINAPI ClearCommError(
            WARN("ioctl returned error\n");
 #endif
 
-       TRACE("handle %d cbInQue = %ld cbOutQue = %ld\n",
+       TRACE("handle %p cbInQue = %ld cbOutQue = %ld\n",
              handle, lpStat->cbInQue, lpStat->cbOutQue);
     }
 
-    close(fd);
+    release_comm_fd( handle, fd );
 
-    if(errors)
-        *errors = 0;
-
-    /*
-    ** After an asynchronous write opperation, the
-    ** app will call ClearCommError to see if the
-    ** results are ready yet. It waits for ERROR_IO_PENDING
-    */
-    commerror = ERROR_IO_PENDING;
+    COMM_GetCommError(handle, errors);
+    COMM_SetCommError(handle, 0);
 
     return TRUE;
 }
@@ -704,20 +983,17 @@ BOOL WINAPI SetupComm(
     int fd;
 
     FIXME("insize %ld outsize %ld unimplemented stub\n", insize, outsize);
-    fd=FILE_GetUnixHandle( handle, GENERIC_READ );
-    if(0>fd) {
-       FIXME("handle %d not found?\n",handle);
-        return FALSE;
-    }
-    close(fd);
+    fd=get_comm_fd( handle, GENERIC_READ );
+    if(0>fd) return FALSE;
+    release_comm_fd( handle, fd );
     return TRUE;
-} 
+}
 
 /*****************************************************************************
  *     GetCommMask     (KERNEL32.@)
  *
- *  Obtain the events associated with a communication device that will cause a call
- *  WaitCommEvent to return.
+ *  Obtain the events associated with a communication device that will cause
+ *  a call WaitCommEvent to return.
  *
  *  RETURNS
  *
@@ -729,14 +1005,14 @@ BOOL WINAPI GetCommMask(
 {
     BOOL ret;
 
-    TRACE("handle %d, mask %p\n", handle, evtmask);
+    TRACE("handle %p, mask %p\n", handle, evtmask);
 
     SERVER_START_REQ( get_serial_info )
     {
         req->handle = handle;
-        if ((ret = !SERVER_CALL_ERR()))
+        if ((ret = !wine_server_call_err( req )))
         {
-            if (evtmask) *evtmask = req->eventmask;
+            if (evtmask) *evtmask = reply->eventmask;
         }
     }
     SERVER_END_REQ;
@@ -756,18 +1032,18 @@ BOOL WINAPI GetCommMask(
  */
 BOOL WINAPI SetCommMask(
     HANDLE handle,  /* [in] The communications device.  */
-    DWORD  evtmask) /* [in] The events that to be monitored. */
+    DWORD  evtmask) /* [in] The events that are to be monitored. */
 {
     BOOL ret;
 
-    TRACE("handle %d, mask %lx\n", handle, evtmask);
+    TRACE("handle %p, mask %lx\n", handle, evtmask);
 
     SERVER_START_REQ( set_serial_info )
     {
         req->handle    = handle;
         req->flags     = SERIALINFO_SET_MASK;
         req->eventmask = evtmask;
-        ret = !SERVER_CALL_ERR();
+        ret = !wine_server_call_err( req );
     }
     SERVER_END_REQ;
     return ret;
@@ -790,25 +1066,28 @@ BOOL WINAPI SetCommState(
 {
      struct termios port;
      int fd, bytesize, stopbits;
+     BOOL ret;
 
-     TRACE("handle %d, ptr %p\n", handle, lpdcb);
+     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);
+             
 
-     fd = FILE_GetUnixHandle( handle, GENERIC_READ );
-     if (fd < 0)  {
-       FIXME("no handle %d found\n",handle);
-       return FALSE;
-     }
+     fd = get_comm_fd( handle, GENERIC_READ );
+     if (fd < 0) return FALSE;
 
      if ((tcgetattr(fd,&port)) == -1) {
          int save_error = errno;
-         commerror = WinError();
-         close( fd );
+         COMM_SetCommError(handle,CE_IOE);
+         release_comm_fd( handle, fd );
          ERR("tcgetattr error '%s'\n", strerror(save_error));
          return FALSE;
      }
@@ -831,81 +1110,139 @@ BOOL WINAPI SetCommState(
        port.c_lflag &= ~(ICANON|ECHO|ISIG);
        port.c_lflag |= NOFLSH;
 
-     /*
-     ** MJM - removed default baudrate settings
-     ** TRACE(comm,"baudrate %ld\n",lpdcb->BaudRate);
-     */
 #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;          
+                       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;          
+                       break;
                case 600:
                case CBR_600:
                        port.c_cflag |= B600;
-                       break;          
+                       break;
                case 1200:
                case CBR_1200:
                        port.c_cflag |= B1200;
-                       break;          
+                       break;
+               case 1800:
+                       port.c_cflag |= B1800;
+                       break;
                case 2400:
                case CBR_2400:
                        port.c_cflag |= B2400;
-                       break;          
+                       break;
                case 4800:
                case CBR_4800:
                        port.c_cflag |= B4800;
-                       break;          
+                       break;
                case 9600:
                case CBR_9600:
                        port.c_cflag |= B9600;
-                       break;          
+                       break;
                case 19200:
                case CBR_19200:
                        port.c_cflag |= B19200;
-                       break;          
+                       break;
                case 38400:
                case CBR_38400:
                        port.c_cflag |= B38400;
-                       break;          
+                       break;
 #ifdef B57600
                case 57600:
                        port.c_cflag |= B57600;
-                       break;          
+                       break;
 #endif
 #ifdef B115200
                case 115200:
                        port.c_cflag |= B115200;
-                       break;          
+                       break;
 #endif
 #ifdef B230400
                case 230400:
                        port.c_cflag |= B230400;
-                       break;          
+                       break;
 #endif
 #ifdef B460800
-               case 460600:
+               case 460800:
                        port.c_cflag |= B460800;
-                       break;          
+                       break;
 #endif
                        default:
-                       commerror = IE_BAUDRATE;
-                       close( fd );
+#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 */
+
+
+                        COMM_SetCommError(handle,IE_BAUDRATE);
+                        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;
@@ -918,6 +1255,9 @@ BOOL WINAPI SetCommState(
                 case CBR_1200:
                         port.c_ospeed = B1200;
                         break;
+                case 1800:
+                        port.c_ospeed = B1800;
+                        break;
                 case 2400:
                 case CBR_2400:
                         port.c_ospeed = B2400;
@@ -938,9 +1278,31 @@ BOOL WINAPI SetCommState(
                 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:
-                        commerror = IE_BAUDRATE;
-                        close( fd );
+                        COMM_SetCommError(handle,IE_BAUDRATE);
+                        release_comm_fd( handle, fd );
                        ERR("baudrate %ld\n",lpdcb->BaudRate);
                         return FALSE;
         }
@@ -982,8 +1344,8 @@ BOOL WINAPI SetCommState(
                             stopbits = TWOSTOPBITS;
                             port.c_iflag &= ~INPCK;
                         } else {
-                            commerror = IE_BYTESIZE;
-                            close( fd );
+                            COMM_SetCommError(handle,IE_BYTESIZE);
+                            release_comm_fd( handle, fd );
                             ERR("Cannot set MARK Parity\n");
                             return FALSE;
                         }
@@ -993,20 +1355,20 @@ BOOL WINAPI SetCommState(
                             bytesize +=1;
                             port.c_iflag &= ~INPCK;
                         } else {
-                            commerror = IE_BYTESIZE;
-                            close( fd );
+                            COMM_SetCommError(handle,IE_BYTESIZE);
+                            release_comm_fd( handle, fd );
                             ERR("Cannot set SPACE Parity\n");
                             return FALSE;
                         }
                         break;
 #endif
                default:
-                        commerror = IE_BYTESIZE;
-                        close( fd );
+                        COMM_SetCommError(handle,IE_BYTESIZE);
+                        release_comm_fd( handle, fd );
                        ERR("Parity\n");
                         return FALSE;
         }
-       
+
 
        port.c_cflag &= ~CSIZE;
        switch (bytesize) {
@@ -1023,42 +1385,36 @@ BOOL WINAPI SetCommState(
                        port.c_cflag |= CS8;
                        break;
                default:
-                       commerror = IE_BYTESIZE;
-                        close( fd );
+                        COMM_SetCommError(handle,IE_BYTESIZE);
+                        release_comm_fd( handle, fd );
                        ERR("ByteSize\n");
                        return FALSE;
        }
-        
+
        switch (stopbits) {
                case ONESTOPBIT:
                                port.c_cflag &= ~CSTOPB;
                                break;
-               case ONE5STOPBITS: /* wil be selected if bytesize is 5 */
+               case ONE5STOPBITS: /* will be selected if bytesize is 5 */
                case TWOSTOPBITS:
                                port.c_cflag |= CSTOPB;
                                break;
                default:
-                       commerror = IE_BYTESIZE;
-                        close( fd );
+                        COMM_SetCommError(handle,IE_BYTESIZE);
+                        release_comm_fd( handle, fd );
                        ERR("StopBits\n");
                        return FALSE;
        }
 #ifdef CRTSCTS
        if (    lpdcb->fOutxCtsFlow                     ||
-               lpdcb->fRtsControl == RTS_CONTROL_ENABLE
-       ) 
+               lpdcb->fRtsControl == RTS_CONTROL_HANDSHAKE
+       )
          {
            port.c_cflag |= CRTSCTS;
            TRACE("CRTSCTS\n");
          }
-       
-       if (lpdcb->fDtrControl == DTR_CONTROL_ENABLE)
-         {
-           port.c_cflag &= ~CRTSCTS;
-           TRACE("~CRTSCTS\n");
-         }
+#endif
 
-#endif 
        if (lpdcb->fInX)
                port.c_iflag |= IXON;
        else
@@ -1069,16 +1425,39 @@ BOOL WINAPI SetCommState(
                port.c_iflag &= ~IXOFF;
 
        if (tcsetattr(fd,TCSANOW,&port)==-1) { /* otherwise it hangs with pending input*/
-               int save_error=errno;
-               commerror = WinError(); 
-                close( fd );
-                ERR("tcsetattr error '%s'\n", strerror(save_error));
-               return FALSE;
+                ERR("tcsetattr error '%s'\n", strerror(errno));
+                COMM_SetCommError(handle,CE_IOE);
+               ret = FALSE;
        } else {
-               commerror = 0;
-                close( fd );
-               return TRUE;
+                COMM_SetCommError(handle,0);
+               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;
+
 }
 
 
@@ -1090,7 +1469,7 @@ BOOL WINAPI SetCommState(
  * RETURNS
  *
  *  True on success, false if the communication device handle is bad etc
- *  
+ *
  * BUGS
  *
  *  XonChar and XoffChar are not set.
@@ -1101,23 +1480,24 @@ BOOL WINAPI GetCommState(
 {
      struct termios port;
      int fd,speed;
+     int stat = DTR_CONTROL_ENABLE | RTS_CONTROL_ENABLE;
 
-     TRACE("handle %d, ptr %p\n", handle, lpdcb);
+     TRACE("handle %p, ptr %p\n", handle, lpdcb);
 
-     fd = FILE_GetUnixHandle( handle, GENERIC_READ );
-     if (fd < 0) 
-       {
-        ERR("FILE_GetUnixHandle failed\n");
-        return FALSE;
-       }
-     if (tcgetattr(fd, &port) == -1) {
+     fd = get_comm_fd( handle, GENERIC_READ );
+     if (fd < 0) return FALSE;
+     if (tcgetattr(fd, &port) == -1
+#ifdef TIOCMGET
+             || ioctl(fd, TIOCMGET, &stat) == -1
+#endif
+             ) {
                 int save_error=errno;
-                ERR("tcgetattr error '%s'\n", strerror(save_error));
-               commerror = WinError(); 
-                close( fd );
+                ERR("tcgetattr or ioctl error '%s'\n", strerror(save_error));
+                COMM_SetCommError(handle,CE_IOE);
+                release_comm_fd( handle, fd );
                return FALSE;
        }
-     close( fd );
+     release_comm_fd( handle, fd );
 #ifndef __EMX__
 #ifdef CBAUD
      speed= (port.c_cflag & CBAUD);
@@ -1125,9 +1505,27 @@ BOOL WINAPI GetCommState(
      speed= (cfgetospeed(&port));
 #endif
      switch (speed) {
+               case B0:
+                       lpdcb->BaudRate = 0;
+                       break;
+               case B50:
+                       lpdcb->BaudRate = 50;
+                       break;
+               case B75:
+                       lpdcb->BaudRate = 75;
+                       break;
                case B110:
                        lpdcb->BaudRate = 110;
                        break;
+               case B134:
+                       lpdcb->BaudRate = 134;
+                       break;
+               case B150:
+                       lpdcb->BaudRate = 150;
+                       break;
+               case B200:
+                       lpdcb->BaudRate = 200;
+                       break;
                case B300:
                        lpdcb->BaudRate = 300;
                        break;
@@ -1137,6 +1535,9 @@ BOOL WINAPI GetCommState(
                case B1200:
                        lpdcb->BaudRate = 1200;
                        break;
+               case B1800:
+                       lpdcb->BaudRate = 1800;
+                       break;
                case B2400:
                        lpdcb->BaudRate = 2400;
                        break;
@@ -1155,22 +1556,22 @@ BOOL WINAPI GetCommState(
 #ifdef B57600
                case B57600:
                        lpdcb->BaudRate = 57600;
-                       break;          
+                       break;
 #endif
 #ifdef B115200
                case B115200:
                        lpdcb->BaudRate = 115200;
-                       break;          
+                       break;
 #endif
 #ifdef B230400
                 case B230400:
                        lpdcb->BaudRate = 230400;
-                       break;          
+                       break;
 #endif
 #ifdef B460800
                 case B460800:
                        lpdcb->BaudRate = 460800;
-                       break;          
+                       break;
 #endif
                default:
                        ERR("unknown speed %x \n",speed);
@@ -1191,8 +1592,8 @@ BOOL WINAPI GetCommState(
                        break;
                default:
                        ERR("unknown size %x \n",port.c_cflag & CSIZE);
-       }       
-       
+       }
+
         if(port.c_iflag & INPCK)
             lpdcb->fParity = TRUE;
         else
@@ -1210,14 +1611,14 @@ BOOL WINAPI GetCommState(
                        lpdcb->Parity = EVENPARITY;
                        break;
                case (PARENB | PARODD):
-                       lpdcb->Parity = ODDPARITY;              
+                       lpdcb->Parity = ODDPARITY;
                        break;
 #ifdef CMSPAR
                case (PARENB | CMSPAR):
-                       lpdcb->Parity = MARKPARITY;             
+                       lpdcb->Parity = MARKPARITY;
                        break;
                 case (PARENB | PARODD | CMSPAR):
-                       lpdcb->Parity = SPACEPARITY;            
+                       lpdcb->Parity = SPACEPARITY;
                        break;
 #endif
        }
@@ -1233,18 +1634,28 @@ BOOL WINAPI GetCommState(
        lpdcb->fNull = 0;
        lpdcb->fBinary = 1;
 
+       /* termios does not support DTR/DSR flow control */
+       lpdcb->fOutxDsrFlow = 0;
+       lpdcb->fDtrControl =
+#ifdef TIOCM_DTR
+            !(stat & TIOCM_DTR) ?  DTR_CONTROL_DISABLE:
+#endif
+                DTR_CONTROL_ENABLE  ;
+
 #ifdef CRTSCTS
 
        if (port.c_cflag & CRTSCTS) {
-               lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
-               lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
+               lpdcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
                lpdcb->fOutxCtsFlow = 1;
-               lpdcb->fOutxDsrFlow = 1;
-       } else 
+       } else
 #endif
        {
-               lpdcb->fDtrControl = DTR_CONTROL_DISABLE;
-               lpdcb->fRtsControl = RTS_CONTROL_DISABLE;
+               lpdcb->fRtsControl = 
+#ifdef TIOCM_RTS
+                    !(stat & TIOCM_RTS) ?  RTS_CONTROL_DISABLE :
+#endif
+                    RTS_CONTROL_ENABLE ;
+               lpdcb->fOutxCtsFlow = 0;
        }
        if (port.c_iflag & IXON)
                lpdcb->fInX = 1;
@@ -1256,33 +1667,35 @@ BOOL WINAPI GetCommState(
        else
                lpdcb->fOutX = 0;
 /*
-       lpdcb->XonChar = 
-       lpdcb->XoffChar = 
+       lpdcb->XonChar =
+       lpdcb->XoffChar =
  */
        lpdcb->XonLim = 10;
        lpdcb->XoffLim = 10;
 
-       commerror = 0;
+        COMM_SetCommError(handle,0);
 
         TRACE("OK\n");
+
        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);
 #ifdef CRTSCTS
        if (    lpdcb->fOutxCtsFlow                     ||
-               lpdcb->fDtrControl == DTR_CONTROL_ENABLE||
-               lpdcb->fRtsControl == RTS_CONTROL_ENABLE
-               ) 
+               lpdcb->fRtsControl == RTS_CONTROL_HANDSHAKE
+               )
          TRACE("CRTSCTS\n");
-       
-       if (lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
+        else
+
          TRACE("~CRTSCTS\n");
-       
-#endif 
+#endif
        return TRUE;
 }
 
@@ -1305,14 +1718,17 @@ BOOL WINAPI TransmitCommChar(
     HANDLE hComm,      /* [in] The communication device in need of a command character. */
     CHAR   chTransmit) /* [in] The character to transmit. */
 {
-       FIXME("(%x,'%c'), use win32 handle!\n",hComm,chTransmit);
-       return TRUE;
+    DWORD w;
+    WARN("(%p,'%c') not perfect!\n",hComm,chTransmit);
+
+    return WriteFile( hComm, &chTransmit, 1, &w, NULL );
 }
 
+
 /*****************************************************************************
  *     GetCommTimeouts         (KERNEL32.@)
  *
- *  Obtains the request time out values for the communications device.
+ *  Obtains the request timeout values for the communications device.
  *
  * RETURNS
  *
@@ -1321,11 +1737,11 @@ BOOL WINAPI TransmitCommChar(
  */
 BOOL WINAPI GetCommTimeouts(
     HANDLE         hComm,      /* [in] The communications device. */
-    LPCOMMTIMEOUTS lptimeouts) /* [out] The struct of request time outs. */
+    LPCOMMTIMEOUTS lptimeouts) /* [out] The struct of request timeouts. */
 {
     BOOL ret;
 
-    TRACE("(%x,%p)\n",hComm,lptimeouts);
+    TRACE("(%p,%p)\n",hComm,lptimeouts);
 
     if(!lptimeouts)
     {
@@ -1336,13 +1752,13 @@ BOOL WINAPI GetCommTimeouts(
     SERVER_START_REQ( get_serial_info )
     {
         req->handle = hComm;
-        if ((ret = !SERVER_CALL_ERR()))
+        if ((ret = !wine_server_call_err( req )))
         {
-            lptimeouts->ReadIntervalTimeout         = req->readinterval;
-            lptimeouts->ReadTotalTimeoutMultiplier  = req->readmult;
-            lptimeouts->ReadTotalTimeoutConstant    = req->readconst;
-            lptimeouts->WriteTotalTimeoutMultiplier = req->writemult;
-            lptimeouts->WriteTotalTimeoutConstant   = req->writeconst;
+            lptimeouts->ReadIntervalTimeout         = reply->readinterval;
+            lptimeouts->ReadTotalTimeoutMultiplier  = reply->readmult;
+            lptimeouts->ReadTotalTimeoutConstant    = reply->readconst;
+            lptimeouts->WriteTotalTimeoutMultiplier = reply->writemult;
+            lptimeouts->WriteTotalTimeoutConstant   = reply->writeconst;
         }
     }
     SERVER_END_REQ;
@@ -1354,7 +1770,7 @@ BOOL WINAPI GetCommTimeouts(
  *
  * Sets the timeouts used when reading and writing data to/from COMM ports.
  *
- * ReadIntervalTimeout 
+ * ReadIntervalTimeout
  *     - converted and passes to linux kernel as c_cc[VTIME]
  * ReadTotalTimeoutMultiplier, ReadTotalTimeoutConstant
  *     - used in ReadFile to calculate GetOverlappedResult's timeout
@@ -1363,7 +1779,7 @@ BOOL WINAPI GetCommTimeouts(
  *
  * RETURNS
  *
- *  True if the time outs were set, false otherwise.
+ *  True if the timeouts were set, false otherwise.
  */
 BOOL WINAPI SetCommTimeouts(
     HANDLE hComm,              /* [in] handle of COMM device */
@@ -1373,7 +1789,7 @@ BOOL WINAPI SetCommTimeouts(
     int fd;
     struct termios tios;
 
-    TRACE("(%x,%p)\n",hComm,lptimeouts);
+    TRACE("(%p,%p)\n",hComm,lptimeouts);
 
     if(!lptimeouts)
     {
@@ -1390,20 +1806,18 @@ BOOL WINAPI SetCommTimeouts(
         req->readconst    = lptimeouts->ReadTotalTimeoutConstant ;
         req->writemult    = lptimeouts->WriteTotalTimeoutMultiplier ;
         req->writeconst   = lptimeouts->WriteTotalTimeoutConstant ;
-        ret = !SERVER_CALL_ERR();
+        ret = !wine_server_call_err( req );
     }
     SERVER_END_REQ;
     if (!ret) return FALSE;
 
     /* FIXME: move this stuff to the server */
-    fd = FILE_GetUnixHandle( hComm, GENERIC_READ );
-    if (fd < 0) {
-       FIXME("no fd for handle = %0x!.\n",hComm);
-       return FALSE;
-    }
+    fd = get_comm_fd( hComm, GENERIC_READ );
+    if (fd < 0) return FALSE;
 
     if (-1==tcgetattr(fd,&tios)) {
         FIXME("tcgetattr on fd %d failed!\n",fd);
+        release_comm_fd( hComm, fd );
         return FALSE;
     }
 
@@ -1428,9 +1842,10 @@ BOOL WINAPI SetCommTimeouts(
 
     if (-1==tcsetattr(fd,0,&tios)) {
         FIXME("tcsetattr on fd %d failed!\n",fd);
+        release_comm_fd( hComm, fd );
         return FALSE;
     }
-    close(fd);
+    release_comm_fd( hComm, fd );
     return TRUE;
 }
 
@@ -1449,14 +1864,14 @@ BOOL WINAPI GetCommModemStatus(
     LPDWORD lpModemStat) /* [out] The control register bits. */
 {
        int fd,mstat, result=FALSE;
-       
+
        *lpModemStat=0;
 #ifdef TIOCMGET
-       fd = FILE_GetUnixHandle( hFile, GENERIC_READ );
+       fd = get_comm_fd( hFile, GENERIC_READ );
        if(fd<0)
                return FALSE;
        result = ioctl(fd, TIOCMGET, &mstat);
-       close(fd);
+       release_comm_fd( hFile, fd );
        if (result == -1)
          {
            WARN("ioctl failed\n");
@@ -1496,27 +1911,30 @@ BOOL WINAPI GetCommModemStatus(
  *  This function is called while the client is waiting on the
  *  server, so we can't make any server calls here.
  */
-static void COMM_WaitCommEventService(async_private *ovp, int events)
+static void WINAPI COMM_WaitCommEventService(void* ovp, IO_STATUS_BLOCK* iosb, ULONG status)
 {
-    LPOVERLAPPED lpOverlapped = ovp->lpOverlapped;
+    async_commio *commio = (async_commio*) ovp;
 
-    TRACE("overlapped %p wait complete %p <- %x\n",lpOverlapped,ovp->buffer,events);
-    if(events&POLLNVAL)
-    {
-        lpOverlapped->Internal = STATUS_HANDLES_CLOSED;
-        return;
-    }
-    if(ovp->buffer)
+    TRACE("iosb %p\n", iosb);
+
+    switch (status)
     {
-        if(events&POLLIN)
-            *ovp->buffer = EV_RXCHAR;
+    case STATUS_ALERTED: /* got some new stuff */
+        /* FIXME: detect other events */
+        *commio->buffer = EV_RXCHAR;
+        iosb->u.Status = STATUS_SUCCESS;
+        break;
+    default:
+        iosb->u.Status = status;
+        break;
     }
-    lpOverlapped->Internal = STATUS_SUCCESS;
+    wine_server_release_fd( commio->handle, commio->fd );
+    if ( ((LPOVERLAPPED)iosb)->hEvent != INVALID_HANDLE_VALUE )
+        NtSetEvent( ((LPOVERLAPPED)iosb)->hEvent, NULL );
+    HeapFree(GetProcessHeap(), 0, commio );
 }
 
 
-
 /***********************************************************************
  *             COMM_WaitCommEvent         (INTERNAL)
  *
@@ -1527,65 +1945,52 @@ static BOOL COMM_WaitCommEvent(
     LPDWORD lpdwEvents,        /* [out] event(s) that were detected */
     LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
 {
-    int fd,ret;
-    async_private *ovp;
+    int                 fd;
+    async_commio*       commio;
+    NTSTATUS            status;
 
-    if(!lpOverlapped)
+    if (!lpOverlapped)
     {
         SetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
 
-    if(NtResetEvent(lpOverlapped->hEvent,NULL))
+    if (NtResetEvent(lpOverlapped->hEvent,NULL))
         return FALSE;
 
-    lpOverlapped->Internal = STATUS_PENDING;
+    fd = get_comm_fd( hFile, GENERIC_WRITE );
+    if (fd < 0) return FALSE;
+
+    commio = (async_commio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_commio));
+    if (!commio)
+    {
+        release_comm_fd( hFile, fd );
+        return FALSE;
+    }
+
+    commio->handle = hFile;
+    commio->type = ASYNC_TYPE_WAIT;
+    commio->apc_internal = COMM_WaitCommEventService;
+    commio->buffer = (char *)lpdwEvents;
+    commio->fd = fd;  /* FIXME */
+
     lpOverlapped->InternalHigh = 0;
     lpOverlapped->Offset = 0;
     lpOverlapped->OffsetHigh = 0;
 
-    /* start an ASYNCHRONOUS WaitCommEvent */
-    SERVER_START_REQ( create_async )
+    SERVER_START_REQ( register_async )
     {
-        req->file_handle = hFile;
+        req->handle = hFile;
+        req->io_apc = COMM_WaitCommEventService;
+        req->io_user = commio;
+        req->io_sb = (IO_STATUS_BLOCK*)lpOverlapped;
         req->count = 0;
-        req->type = ASYNC_TYPE_WAIT;
-
-        ret=SERVER_CALL_ERR();
+        status = wine_server_call( req );
     }
     SERVER_END_REQ;
 
-    if (ret)
-        return FALSE;
-  
-    fd = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
-    if(fd<0)
-       return FALSE;
-
-    ovp = (async_private *) HeapAlloc(GetProcessHeap(), 0, sizeof (async_private));
-    if(!ovp)
-    {
-        close(fd);
-        return FALSE;
-    }
-    ovp->lpOverlapped = lpOverlapped;
-    ovp->timeout = 0;
-    ovp->tv.tv_sec = 0;
-    ovp->tv.tv_usec = 0;
-    ovp->event = POLLIN;
-    ovp->func = COMM_WaitCommEventService;
-    ovp->buffer = (char *)lpdwEvents;
-    ovp->fd = fd;
-    ovp->count = 0;
-    ovp->completion_func = 0;                                                  
-  
-    ovp->next = NtCurrentTeb()->pending_list;
-    ovp->prev = NULL;
-    if(ovp->next)
-        ovp->next->prev=ovp;
-    NtCurrentTeb()->pending_list = ovp;
-  
-    SetLastError(ERROR_IO_PENDING);
+    if ( status ) SetLastError( RtlNtStatusToDosError(status) );
+    else NtCurrentTeb()->num_async_io++;
 
     return FALSE;
 }
@@ -1615,33 +2020,27 @@ BOOL WINAPI WaitCommEvent(
     OVERLAPPED ov;
     int ret;
 
-    TRACE("(%x %p %p )\n",hFile, lpdwEvents,lpOverlapped);
+    TRACE("(%p %p %p )\n",hFile, lpdwEvents,lpOverlapped);
 
     if(lpOverlapped)
         return COMM_WaitCommEvent(hFile, lpdwEvents, lpOverlapped);
 
     /* if there is no overlapped structure, create our own */
-    ov.hEvent = CreateEventA(NULL,FALSE,FALSE,NULL);
+    ov.hEvent = CreateEventW(NULL,FALSE,FALSE,NULL);
 
     COMM_WaitCommEvent(hFile, lpdwEvents, &ov);
 
-    if(GetLastError()!=STATUS_PENDING)
-    {
-        CloseHandle(ov.hEvent);
-        return FALSE;
-    }
-
     /* wait for the overlapped to complete */
     ret = GetOverlappedResult(hFile, &ov, NULL, TRUE);
     CloseHandle(ov.hEvent);
 
     return ret;
 }
-  
+
 /***********************************************************************
  *           GetCommProperties   (KERNEL32.@)
  *
- * This function fills in a structure with the capabilities of the 
+ * This function fills in a structure with the capabilities of the
  * communications port driver.
  *
  * RETURNS
@@ -1654,7 +2053,7 @@ BOOL WINAPI GetCommProperties(
     HANDLE hFile,          /* [in] handle of the comm port */
     LPCOMMPROP lpCommProp) /* [out] pointer to struct to be filled */
 {
-    FIXME("(%d %p )\n",hFile,lpCommProp);
+    FIXME("(%p %p )\n",hFile,lpCommProp);
     if(!lpCommProp)
         return FALSE;
 
@@ -1671,14 +2070,14 @@ BOOL WINAPI GetCommProperties(
     lpCommProp->dwMaxRxQueue        = 4096;
     lpCommProp->dwMaxBaud           = BAUD_115200;
     lpCommProp->dwProvSubType       = PST_RS232;
-    lpCommProp->dwProvCapabilities  = PCF_DTRDSR | PCF_PARITY_CHECK | PCF_RTSCTS ;
-    lpCommProp->dwSettableParams    = SP_BAUD | SP_DATABITS | SP_HANDSHAKING | 
+    lpCommProp->dwProvCapabilities  = PCF_DTRDSR | PCF_PARITY_CHECK | PCF_RTSCTS | PCF_TOTALTIMEOUTS;
+    lpCommProp->dwSettableParams    = SP_BAUD | SP_DATABITS | SP_HANDSHAKING |
                                       SP_PARITY | SP_PARITY_CHECK | SP_STOPBITS ;
     lpCommProp->dwSettableBaud      = BAUD_075 | BAUD_110 | BAUD_134_5 | BAUD_150 |
                 BAUD_300 | BAUD_600 | BAUD_1200 | BAUD_1800 | BAUD_2400 | BAUD_4800 |
                 BAUD_9600 | BAUD_19200 | BAUD_38400 | BAUD_57600 | BAUD_115200 ;
     lpCommProp->wSettableData       = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8 ;
-    lpCommProp->wSettableStopParity = STOPBITS_10 | STOPBITS_15 | STOPBITS_20 | 
+    lpCommProp->wSettableStopParity = STOPBITS_10 | STOPBITS_15 | STOPBITS_20 |
                 PARITY_NONE | PARITY_ODD |PARITY_EVEN | PARITY_MARK | PARITY_SPACE;
     lpCommProp->dwCurrentTxQueue    = lpCommProp->dwMaxTxQueue;
     lpCommProp->dwCurrentRxQueue    = lpCommProp->dwMaxRxQueue;
@@ -1692,15 +2091,16 @@ BOOL WINAPI GetCommProperties(
  * SetDefaultCommConfig is implemented in a DLL (usually SERIALUI.DLL).
  * This is dependent on the type of COMM port, but since it is doubtful
  * anybody will get around to implementing support for fancy serial
- * ports in WINE, this is hardcoded for the time being.  The name of 
- * this DLL should be stored in and read from the system registry in 
+ * ports in WINE, this is hardcoded for the time being.  The name of
+ * this DLL should be stored in and read from the system registry in
  * the hive HKEY_LOCAL_MACHINE, key
  * System\\CurrentControlSet\\Services\\Class\\Ports\\????
  * where ???? is the port number... that is determined by PNP
- * The DLL should be loaded when the COMM port is opened, and closed 
+ * The DLL should be loaded when the COMM port is opened, and closed
  * when the COMM port is closed. - MJM 20 June 2000
  ***********************************************************************/
-static CHAR lpszSerialUI[] = "serialui.dll";
+static WCHAR lpszSerialUI[] = { 
+   's','e','r','i','a','l','u','i','.','d','l','l',0 };
 
 
 /***********************************************************************
@@ -1727,22 +2127,20 @@ BOOL WINAPI CommConfigDialogA(
 {
     FARPROC lpfnCommDialog;
     HMODULE hConfigModule;
-    BOOL r;
+    BOOL r = FALSE;
 
-    TRACE("(%p %x %p)\n",lpszDevice, hWnd, lpCommConfig);
+    TRACE("(%p %p %p)\n",lpszDevice, hWnd, lpCommConfig);
 
-    hConfigModule = LoadLibraryA(lpszSerialUI);
+    hConfigModule = LoadLibraryW(lpszSerialUI);
     if(!hConfigModule)
         return FALSE;
 
-    lpfnCommDialog = GetProcAddress(hConfigModule, (LPCSTR)3L);
+    lpfnCommDialog = GetProcAddress(hConfigModule, "drvCommConfigDialogA");
 
-    if(!lpfnCommDialog)
-        return FALSE;
+    if(lpfnCommDialog)
+        r = lpfnCommDialog(lpszDevice,hWnd,lpCommConfig);
 
-    r = lpfnCommDialog(lpszDevice,hWnd,lpCommConfig);
-
-    /* UnloadLibrary(hConfigModule); */
+    FreeLibrary(hConfigModule);
 
     return r;
 }
@@ -1757,14 +2155,23 @@ BOOL WINAPI CommConfigDialogW(
     HANDLE hWnd,               /* [in] parent window for the dialog */
     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
 {
-    BOOL r;
-    LPSTR lpDeviceA;
+    FARPROC lpfnCommDialog;
+    HMODULE hConfigModule;
+    BOOL r = FALSE;
+
+    TRACE("(%p %p %p)\n",lpszDevice, hWnd, lpCommConfig);
 
-    lpDeviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszDevice );
-    if(lpDeviceA)
+    hConfigModule = LoadLibraryW(lpszSerialUI);
+    if(!hConfigModule)
         return FALSE;
-    r = CommConfigDialogA(lpDeviceA,hWnd,lpCommConfig);
-    HeapFree( GetProcessHeap(), 0, lpDeviceA );
+
+    lpfnCommDialog = GetProcAddress(hConfigModule, "drvCommConfigDialogW");
+
+    if(lpfnCommDialog)
+        r = lpfnCommDialog(lpszDevice,hWnd,lpCommConfig);
+
+    FreeLibrary(hConfigModule);
+
     return r;
 }
 
@@ -1780,27 +2187,23 @@ BOOL WINAPI CommConfigDialogW(
  *
  * BUGS
  *
- *  The signature is missing a the parameter for the size of the COMMCONFIG
- *  structure/buffer it should be
- *  BOOL WINAPI GetCommConfig(HANDLE hFile,LPCOMMCONFIG lpCommConfig,LPDWORD lpdwSize)
  */
 BOOL WINAPI GetCommConfig(
     HANDLE       hFile,        /* [in] The communications device. */
     LPCOMMCONFIG lpCommConfig, /* [out] The communications configuration of the device (if it fits). */
     LPDWORD      lpdwSize)     /* [in/out] Initially the size of the configuration buffer/structure,
-                                  afterwards the number of bytes copied to the buffer or 
+                                  afterwards the number of bytes copied to the buffer or
                                   the needed size of the buffer. */
 {
     BOOL r;
 
-    TRACE("(%x %p)\n",hFile,lpCommConfig);
+    TRACE("(%p %p)\n",hFile,lpCommConfig);
 
     if(lpCommConfig == NULL)
         return FALSE;
-
-    r = *lpdwSize < sizeof(COMMCONFIG);
+    r = *lpdwSize < sizeof(COMMCONFIG); /* TRUE if not enough space */
     *lpdwSize = sizeof(COMMCONFIG);
-    if(!r)   
+    if(r)
         return FALSE;
 
     lpCommConfig->dwSize = sizeof(COMMCONFIG);
@@ -1817,17 +2220,18 @@ BOOL WINAPI GetCommConfig(
 /***********************************************************************
  *           SetCommConfig     (KERNEL32.@)
  *
- *  Sets the configuration of the commications device.
+ *  Sets the configuration of the communications device.
  *
  * RETURNS
  *
  *  True on success, false if the handle was bad is not a communications device.
  */
 BOOL WINAPI SetCommConfig(
-    HANDLE       hFile,        /* [in] The communications device. */
-    LPCOMMCONFIG lpCommConfig) /* [in] The desired configuration. */
+    HANDLE       hFile,                /* [in] The communications device. */
+    LPCOMMCONFIG lpCommConfig, /* [in] The desired configuration. */
+    DWORD dwSize)              /* [in] size of the lpCommConfig struct */
 {
-    TRACE("(%x %p)\n",hFile,lpCommConfig);
+    TRACE("(%p %p)\n",hFile,lpCommConfig);
     return SetCommState(hFile,&lpCommConfig->dcb);
 }
 
@@ -1841,29 +2245,26 @@ BOOL WINAPI SetCommConfig(
  *
  *  True if the device was found and the defaults set, false otherwise
  */
-BOOL WINAPI SetDefaultCommConfigA(
-    LPCSTR       lpszDevice,   /* [in] The ascii name of the device targeted for configuration. */
+BOOL WINAPI SetDefaultCommConfigW(
+    LPCWSTR       lpszDevice,  /* [in] The ascii name of the device targeted for configuration. */
     LPCOMMCONFIG lpCommConfig, /* [in] The default configuration for the device. */
     DWORD        dwSize)       /* [in] The number of bytes in the configuration structure. */
 {
     FARPROC lpfnSetDefaultCommConfig;
     HMODULE hConfigModule;
-    BOOL r;
+    BOOL r = FALSE;
 
     TRACE("(%p %p %lx)\n",lpszDevice, lpCommConfig, dwSize);
 
-    hConfigModule = LoadLibraryA(lpszSerialUI);
+    hConfigModule = LoadLibraryW(lpszSerialUI);
     if(!hConfigModule)
-        return FALSE;
-
-    lpfnSetDefaultCommConfig = GetProcAddress(hConfigModule, (LPCSTR)4L);
+        return r;
 
-    if(! lpfnSetDefaultCommConfig)
-       return TRUE;
-
-    r = lpfnSetDefaultCommConfig(lpszDevice, lpCommConfig, dwSize);
+    lpfnSetDefaultCommConfig = GetProcAddress(hConfigModule, "drvSetDefaultCommConfigW");
+    if (lpfnSetDefaultCommConfig)
+        r = lpfnSetDefaultCommConfig(lpszDevice, lpCommConfig, dwSize);
 
-    /* UnloadLibrary(hConfigModule); */
+    FreeLibrary(hConfigModule);
 
     return r;
 }
@@ -1878,27 +2279,31 @@ BOOL WINAPI SetDefaultCommConfigA(
  * RETURNS
  *
  */
-BOOL WINAPI SetDefaultCommConfigW(
-    LPCWSTR      lpszDevice,   /* [in] The unicode name of the device targeted for configuration. */
+BOOL WINAPI SetDefaultCommConfigA(
+    LPCSTR      lpszDevice,    /* [in] The unicode name of the device targeted for configuration. */
     LPCOMMCONFIG lpCommConfig, /* [in] The default configuration for the device. */
     DWORD        dwSize)       /* [in] The number of bytes in the configuration structure. */
 {
     BOOL r;
-    LPSTR lpDeviceA;
+    LPWSTR lpDeviceW = NULL;
+    DWORD len;
 
-    TRACE("(%s %p %lx)\n",debugstr_w(lpszDevice),lpCommConfig,dwSize);
+    TRACE("(%s %p %lx)\n",debugstr_a(lpszDevice),lpCommConfig,dwSize);
 
-    lpDeviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszDevice );
-    if(lpDeviceA)
-        return FALSE;
-    r = SetDefaultCommConfigA(lpDeviceA,lpCommConfig,dwSize);
-    HeapFree( GetProcessHeap(), 0, lpDeviceA );
+    if (lpszDevice)
+    {
+        len = MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, NULL, 0 );
+        lpDeviceW = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
+        MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, lpDeviceW, len );
+    }
+    r = SetDefaultCommConfigW(lpDeviceW,lpCommConfig,dwSize);
+    HeapFree( GetProcessHeap(), 0, lpDeviceW );
     return r;
 }
 
 
 /***********************************************************************
- *           GetDefaultCommConfigA   (KERNEL32.@)
+ *           GetDefaultCommConfigW   (KERNEL32.@)
  *
  *   Acquires the default configuration of the specified communication device. (unicode)
  *
@@ -1907,22 +2312,24 @@ BOOL WINAPI SetDefaultCommConfigW(
  *   True on successful reading of the default configuration,
  *   if the device is not found or the buffer is too small.
  */
-BOOL WINAPI GetDefaultCommConfigA(
-    LPCSTR       lpszName, /* [in] The ascii name of the device targeted for configuration. */
+BOOL WINAPI GetDefaultCommConfigW(
+    LPCWSTR      lpszName, /* [in] The unicode name of the device targeted for configuration. */
     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
                               afterwards the number of bytes copied to the buffer or
                               the needed size of the buffer. */
 {
      LPDCB lpdcb = &(lpCC->dcb);
-     char  temp[40];
+     WCHAR temp[40];
+     static const WCHAR comW[] = {'C','O','M',0};
+     static const WCHAR formatW[] = {'C','O','M','%','c',':','3','8','4','0','0',',','n',',','8',',','1',0};
 
-     if (strncasecmp(lpszName,"COM",3)) {
-        ERR("not implemented for <%s>\n", lpszName);
+     if (strncmpiW(lpszName,comW,3)) {
+        ERR("not implemented for <%s>\n", debugstr_w(lpszName));
         return FALSE;
      }
 
-     TRACE("(%s %p %ld)\n", lpszName, lpCC, *lpdwSize );
+     TRACE("(%s %p %ld)\n", debugstr_w(lpszName), lpCC, *lpdwSize );
      if (*lpdwSize < sizeof(COMMCONFIG)) {
          *lpdwSize = sizeof(COMMCONFIG);
          return FALSE;
@@ -1936,39 +2343,38 @@ BOOL WINAPI GetDefaultCommConfigA(
      lpCC->dwProviderOffset = 0L;
      lpCC->dwProviderSize = 0L;
 
-     (void) sprintf( temp, "COM%c:38400,n,8,1", lpszName[3]);
-     FIXME("setting %s as default\n", temp);
+     sprintfW( temp, formatW, lpszName[3]);
+     FIXME("setting %s as default\n", debugstr_w(temp));
 
-     return BuildCommDCBA( temp, lpdcb);
+     return BuildCommDCBW( temp, lpdcb);
 }
 
 /**************************************************************************
- *         GetDefaultCommConfigW               (KERNEL32.@)
+ *         GetDefaultCommConfigA               (KERNEL32.@)
  *
- *   Acquires the default configuration of the specified communication device. (unicode)
+ *   Acquires the default configuration of the specified communication device. (ascii)
  *
  *  RETURNS
  *
  *   True on successful reading of the default configuration,
  *   if the device is not found or the buffer is too small.
  */
-BOOL WINAPI GetDefaultCommConfigW(
-    LPCWSTR      lpszName, /* [in] The unicode name of the device targeted for configuration. */
+BOOL WINAPI GetDefaultCommConfigA(
+    LPCSTR       lpszName, /* [in] The ascii name of the device targeted for configuration. */
     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
                              afterwards the number of bytes copied to the buffer or
                               the needed size of the buffer. */
 {
        BOOL ret = FALSE;
-       LPSTR   lpszNameA;
+       UNICODE_STRING lpszNameW;
 
-       TRACE("(%p,%p,%ld)\n",lpszName,lpCC,*lpdwSize);
-       lpszNameA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpszName );
-       if (lpszNameA)
-       {
-       ret=GetDefaultCommConfigA(lpszNameA,lpCC,lpdwSize);
-        HeapFree( GetProcessHeap(), 0, lpszNameA );
-       }
+       TRACE("(%s,%p,%ld)\n",lpszName,lpCC,*lpdwSize);
+       if(lpszName) RtlCreateUnicodeStringFromAsciiz(&lpszNameW,lpszName);
+       else lpszNameW.Buffer = NULL;
+
+       if(lpszNameW.Buffer) ret = GetDefaultCommConfigW(lpszNameW.Buffer,lpCC,lpdwSize);
+
+       RtlFreeUnicodeString(&lpszNameW);
        return ret;
 }
-