advapi32: Implement and test SystemFunction004.
[wine] / dlls / kernel / comm.c
1 /*
2  * DEC 93 Erik Bos <erik@xs4all.nl>
3  *
4  * Copyright 1996 Marcus Meissner
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #ifdef HAVE_TERMIOS_H
28 #include <termios.h>
29 #endif
30 #include <fcntl.h>
31 #include <string.h>
32 #ifdef HAVE_STRINGS_H
33 # include <strings.h>
34 #endif
35 #include <errno.h>
36 #include <ctype.h>
37 #ifdef HAVE_SYS_STAT_H
38 # include <sys/stat.h>
39 #endif
40 #ifdef HAVE_SYS_FILIO_H
41 # include <sys/filio.h>
42 #endif
43 #ifdef HAVE_SYS_IOCTL_H
44 #include <sys/ioctl.h>
45 #endif
46 #ifdef HAVE_UNISTD_H
47 # include <unistd.h>
48 #endif
49 #ifdef HAVE_SYS_POLL_H
50 # include <sys/poll.h>
51 #endif
52 #ifdef HAVE_SYS_MODEM_H
53 # include <sys/modem.h>
54 #endif
55 #ifdef HAVE_SYS_STRTIO_H
56 # include <sys/strtio.h>
57 #endif
58
59 #define NONAMELESSUNION
60 #define NONAMELESSSTRUCT
61 #include "windef.h"
62 #include "winbase.h"
63 #include "winerror.h"
64 #include "winioctl.h"
65 #include "ddk/ntddser.h"
66
67 #include "wine/server.h"
68 #include "wine/unicode.h"
69
70 #include "wine/debug.h"
71
72 #ifdef HAVE_LINUX_SERIAL_H
73 #include <linux/serial.h>
74 #endif
75
76 WINE_DEFAULT_DEBUG_CHANNEL(comm);
77
78 /* retrieve the Unix handle corresponding to a comm handle */
79 static int get_comm_fd( HANDLE handle, DWORD access )
80 {
81     int fd, ret;
82
83     ret = wine_server_handle_to_fd( handle, access, &fd, NULL );
84     if (ret) SetLastError( RtlNtStatusToDosError(ret) );
85     return fd;
86 }
87
88 /* release the Unix handle returned by get_comm_fd */
89 static inline void release_comm_fd( HANDLE handle, int fd )
90 {
91     wine_server_release_fd( handle, fd );
92 }
93
94 /*             serial_irq_info
95  * local structure holding the irq values we need for WaitCommEvent()
96  *
97  * Stripped down from struct serial_icounter_struct, which may not be available on some systems
98  * As the modem line interrupts (cts, dsr, rng, dcd) only get updated with TIOCMIWAIT active,
99  * no need to carry them in the internal structure
100  *
101  */
102 typedef struct serial_irq_info
103 {
104     int rx , tx, frame, overrun, parity, brk, buf_overrun;
105 }serial_irq_info;
106
107 /***********************************************************************
108  * Data needed by the thread polling for the changing CommEvent
109  */
110 typedef struct async_commio
111 {
112     HANDLE              handle;
113     char*               buffer;
114     HANDLE              hEvent;
115     DWORD               evtmask;
116     DWORD               mstat;
117     serial_irq_info     irq_info;
118 } async_commio;
119
120 /***********************************************************************/
121
122 #if !defined(TIOCINQ) && defined(FIONREAD)
123 #define TIOCINQ FIONREAD
124 #endif
125
126 /***********************************************************************
127  *   Get extended interrupt count info, needed for WaitCommEvent
128  */
129 static int COMM_GetEInfo(int fd, serial_irq_info *irq_info)
130 {
131 #ifdef TIOCGICOUNT
132     struct serial_icounter_struct einfo;
133     if (!ioctl(fd,TIOCGICOUNT, &einfo))
134     {
135         irq_info->rx          = einfo.rx;
136         irq_info->tx          = einfo.tx;
137         irq_info->frame       = einfo.frame;
138         irq_info->overrun     = einfo.overrun;
139         irq_info->parity      = einfo.parity;
140         irq_info->brk         = einfo.brk;
141         irq_info->buf_overrun = einfo.buf_overrun;
142         return 0;
143     }
144 #endif
145     memset(irq_info,0, sizeof(serial_irq_info));
146     return -1;
147 }
148
149
150 /***********************************************************************
151  *           COMM_Parse*   (Internal)
152  *
153  *  The following COMM_Parse* functions are used by the BuildCommDCB
154  *  functions to help parse the various parts of the device control string.
155  */
156 static LPCWSTR COMM_ParseStart(LPCWSTR ptr)
157 {
158         static const WCHAR comW[] = {'C','O','M',0};
159
160         /* The device control string may optionally start with "COMx" followed
161            by an optional ':' and spaces. */
162         if(!strncmpiW(ptr, comW, 3))
163         {
164                 ptr += 3;
165
166                 /* Allow any com port above 0 as Win 9x does (NT only allows
167                    values for com ports which are actually present) */
168                 if(*ptr < '1' || *ptr > '9')
169                         return NULL;
170                 
171                 /* Advance pointer past port number */
172                 while(*ptr >= '0' && *ptr <= '9') ptr++;
173                 
174                 /* The com port number must be followed by a ':' or ' ' */
175                 if(*ptr != ':' && *ptr != ' ')
176                         return NULL;
177
178                 /* Advance pointer to beginning of next parameter */
179                 while(*ptr == ' ') ptr++;
180                 if(*ptr == ':')
181                 {
182                         ptr++;
183                         while(*ptr == ' ') ptr++;
184                 }
185         }
186         /* The device control string must not start with a space. */
187         else if(*ptr == ' ')
188                 return NULL;
189         
190         return ptr;
191 }
192  
193 static LPCWSTR COMM_ParseNumber(LPCWSTR ptr, LPDWORD lpnumber)
194 {
195         if(*ptr < '0' || *ptr > '9') return NULL;
196         *lpnumber = strtoulW(ptr, NULL, 10);
197         while(*ptr >= '0' && *ptr <= '9') ptr++;
198         return ptr;
199 }
200
201 static LPCWSTR COMM_ParseParity(LPCWSTR ptr, LPBYTE lpparity)
202 {
203         /* Contrary to what you might expect, Windows only sets the Parity
204            member of DCB and not fParity even when parity is specified in the
205            device control string */
206
207         switch(toupperW(*ptr++))
208         {
209         case 'E':
210                 *lpparity = EVENPARITY;
211                 break;
212         case 'M':
213                 *lpparity = MARKPARITY;
214                 break;
215         case 'N':
216                 *lpparity = NOPARITY;
217                 break;
218         case 'O':
219                 *lpparity = ODDPARITY;
220                 break;
221         case 'S':
222                 *lpparity = SPACEPARITY;
223                 break;
224         default:
225                 return NULL;
226         }
227
228         return ptr;
229 }
230
231 static LPCWSTR COMM_ParseByteSize(LPCWSTR ptr, LPBYTE lpbytesize)
232 {
233         DWORD temp;
234
235         if(!(ptr = COMM_ParseNumber(ptr, &temp)))
236                 return NULL;
237
238         if(temp >= 5 && temp <= 8)
239         {
240                 *lpbytesize = temp;
241                 return ptr;
242         }
243         else
244                 return NULL;
245 }
246
247 static LPCWSTR COMM_ParseStopBits(LPCWSTR ptr, LPBYTE lpstopbits)
248 {
249         DWORD temp;
250         static const WCHAR stopbits15W[] = {'1','.','5',0};
251
252         if(!strncmpW(stopbits15W, ptr, 3))
253         {
254                 ptr += 3;
255                 *lpstopbits = ONE5STOPBITS;
256         }
257         else
258         {
259                 if(!(ptr = COMM_ParseNumber(ptr, &temp)))
260                         return NULL;
261
262                 if(temp == 1)
263                         *lpstopbits = ONESTOPBIT;
264                 else if(temp == 2)
265                         *lpstopbits = TWOSTOPBITS;
266                 else
267                         return NULL;
268         }
269         
270         return ptr;
271 }
272
273 static LPCWSTR COMM_ParseOnOff(LPCWSTR ptr, LPDWORD lponoff)
274 {
275         static const WCHAR onW[] = {'o','n',0};
276         static const WCHAR offW[] = {'o','f','f',0};
277
278         if(!strncmpiW(onW, ptr, 2))
279         {
280                 ptr += 2;
281                 *lponoff = 1;
282         }
283         else if(!strncmpiW(offW, ptr, 3))
284         {
285                 ptr += 3;
286                 *lponoff = 0;
287         }
288         else
289                 return NULL;
290
291         return ptr;
292 }
293
294 /***********************************************************************
295  *           COMM_BuildOldCommDCB   (Internal)
296  *
297  *  Build a DCB using the old style settings string eg: "96,n,8,1"
298  */
299 static BOOL COMM_BuildOldCommDCB(LPCWSTR device, LPDCB lpdcb)
300 {
301         WCHAR last = 0;
302
303         if(!(device = COMM_ParseNumber(device, &lpdcb->BaudRate)))
304                 return FALSE;
305         
306         switch(lpdcb->BaudRate)
307         {
308         case 11:
309         case 30:
310         case 60:
311                 lpdcb->BaudRate *= 10;
312                 break;
313         case 12:
314         case 24:
315         case 48:
316         case 96:
317                 lpdcb->BaudRate *= 100;
318                 break;
319         case 19:
320                 lpdcb->BaudRate = 19200;
321                 break;
322         }
323
324         while(*device == ' ') device++;
325         if(*device++ != ',') return FALSE;
326         while(*device == ' ') device++;
327
328         if(!(device = COMM_ParseParity(device, &lpdcb->Parity)))
329                 return FALSE;
330
331         while(*device == ' ') device++;
332         if(*device++ != ',') return FALSE;
333         while(*device == ' ') device++;
334                 
335         if(!(device = COMM_ParseByteSize(device, &lpdcb->ByteSize)))
336                 return FALSE;
337
338         while(*device == ' ') device++;
339         if(*device++ != ',') return FALSE;
340         while(*device == ' ') device++;
341
342         if(!(device = COMM_ParseStopBits(device, &lpdcb->StopBits)))
343                 return FALSE;
344
345         /* The last parameter for flow control is optional. */
346         while(*device == ' ') device++;
347         if(*device == ',')
348         {
349                 device++;
350                 while(*device == ' ') device++;
351                 if(*device) last = toupperW(*device++);
352                 while(*device == ' ') device++;
353         }
354
355         /* Win NT sets the flow control members based on (or lack of) the last
356            parameter.  Win 9x does not set these members. */
357         switch(last)
358         {
359         case 0:
360                 lpdcb->fInX = FALSE;
361                 lpdcb->fOutX = FALSE;
362                 lpdcb->fOutxCtsFlow = FALSE;
363                 lpdcb->fOutxDsrFlow = FALSE;
364                 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
365                 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
366                 break;
367         case 'X':
368                 lpdcb->fInX = TRUE;
369                 lpdcb->fOutX = TRUE;
370                 lpdcb->fOutxCtsFlow = FALSE;
371                 lpdcb->fOutxDsrFlow = FALSE;
372                 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
373                 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
374                 break;
375         case 'P':
376                 lpdcb->fInX = FALSE;
377                 lpdcb->fOutX = FALSE;
378                 lpdcb->fOutxCtsFlow = TRUE;
379                 lpdcb->fOutxDsrFlow = TRUE;
380                 lpdcb->fDtrControl = DTR_CONTROL_HANDSHAKE;
381                 lpdcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
382                 break;
383         default:
384                 return FALSE;
385         }
386
387         /* This should be the end of the string. */
388         if(*device) return FALSE;
389         
390         return TRUE;
391 }
392
393 /***********************************************************************
394  *           COMM_BuildNewCommDCB   (Internal)
395  *
396  *  Build a DCB using the new style settings string.
397  *   eg: "baud=9600 parity=n data=8 stop=1 xon=on to=on"
398  */
399 static BOOL COMM_BuildNewCommDCB(LPCWSTR device, LPDCB lpdcb, LPCOMMTIMEOUTS lptimeouts)
400 {
401         DWORD temp;
402         BOOL baud = FALSE, stop = FALSE;
403         static const WCHAR baudW[] = {'b','a','u','d','=',0};
404         static const WCHAR parityW[] = {'p','a','r','i','t','y','=',0};
405         static const WCHAR dataW[] = {'d','a','t','a','=',0};
406         static const WCHAR stopW[] = {'s','t','o','p','=',0};
407         static const WCHAR toW[] = {'t','o','=',0};
408         static const WCHAR xonW[] = {'x','o','n','=',0};
409         static const WCHAR odsrW[] = {'o','d','s','r','=',0};
410         static const WCHAR octsW[] = {'o','c','t','s','=',0};
411         static const WCHAR dtrW[] = {'d','t','r','=',0};
412         static const WCHAR rtsW[] = {'r','t','s','=',0};
413         static const WCHAR idsrW[] = {'i','d','s','r','=',0};
414
415         while(*device)
416         {
417                 while(*device == ' ') device++;
418
419                 if(!strncmpiW(baudW, device, 5))
420                 {
421                         baud = TRUE;
422                         
423                         if(!(device = COMM_ParseNumber(device + 5, &lpdcb->BaudRate)))
424                                 return FALSE;
425                 }
426                 else if(!strncmpiW(parityW, device, 7))
427                 {
428                         if(!(device = COMM_ParseParity(device + 7, &lpdcb->Parity)))
429                                 return FALSE;
430                 }
431                 else if(!strncmpiW(dataW, device, 5))
432                 {
433                         if(!(device = COMM_ParseByteSize(device + 5, &lpdcb->ByteSize)))
434                                 return FALSE;
435                 }
436                 else if(!strncmpiW(stopW, device, 5))
437                 {
438                         stop = TRUE;
439                         
440                         if(!(device = COMM_ParseStopBits(device + 5, &lpdcb->StopBits)))
441                                 return FALSE;
442                 }
443                 else if(!strncmpiW(toW, device, 3))
444                 {
445                         if(!(device = COMM_ParseOnOff(device + 3, &temp)))
446                                 return FALSE;
447
448                         lptimeouts->ReadIntervalTimeout = 0;
449                         lptimeouts->ReadTotalTimeoutMultiplier = 0;
450                         lptimeouts->ReadTotalTimeoutConstant = 0;
451                         lptimeouts->WriteTotalTimeoutMultiplier = 0;
452                         lptimeouts->WriteTotalTimeoutConstant = temp ? 60000 : 0;
453                 }
454                 else if(!strncmpiW(xonW, device, 4))
455                 {
456                         if(!(device = COMM_ParseOnOff(device + 4, &temp)))
457                                 return FALSE;
458
459                         lpdcb->fOutX = temp;
460                         lpdcb->fInX = temp;
461                 }
462                 else if(!strncmpiW(odsrW, device, 5))
463                 {
464                         if(!(device = COMM_ParseOnOff(device + 5, &temp)))
465                                 return FALSE;
466
467                         lpdcb->fOutxDsrFlow = temp;
468                 }
469                 else if(!strncmpiW(octsW, device, 5))
470                 {
471                         if(!(device = COMM_ParseOnOff(device + 5, &temp)))
472                                 return FALSE;
473
474                         lpdcb->fOutxCtsFlow = temp;
475                 }
476                 else if(!strncmpiW(dtrW, device, 4))
477                 {
478                         if(!(device = COMM_ParseOnOff(device + 4, &temp)))
479                                 return FALSE;
480
481                         lpdcb->fDtrControl = temp;
482                 }
483                 else if(!strncmpiW(rtsW, device, 4))
484                 {
485                         if(!(device = COMM_ParseOnOff(device + 4, &temp)))
486                                 return FALSE;
487
488                         lpdcb->fRtsControl = temp;
489                 }
490                 else if(!strncmpiW(idsrW, device, 5))
491                 {
492                         if(!(device = COMM_ParseOnOff(device + 5, &temp)))
493                                 return FALSE;
494
495                         /* Win NT sets the fDsrSensitivity member based on the
496                            idsr parameter.  Win 9x sets fOutxDsrFlow instead. */
497                         lpdcb->fDsrSensitivity = temp;
498                 }
499                 else
500                         return FALSE;
501
502                 /* After the above parsing, the next character (if not the end of
503                    the string) should be a space */
504                 if(*device && *device != ' ')
505                         return FALSE;
506         }
507
508         /* If stop bits were not specified, a default is always supplied. */
509         if(!stop)
510         {
511                 if(baud && lpdcb->BaudRate == 110)
512                         lpdcb->StopBits = TWOSTOPBITS;
513                 else
514                         lpdcb->StopBits = ONESTOPBIT;
515         }
516
517         return TRUE;
518 }
519
520 /**************************************************************************
521  *         BuildCommDCBA                (KERNEL32.@)
522  *
523  *  Updates a device control block data structure with values from an
524  *  ascii device control string.  The device control string has two forms
525  *  normal and extended, it must be exclusively in one or the other form.
526  *
527  * RETURNS
528  *
529  *  True on success, false on a malformed control string.
530  */
531 BOOL WINAPI BuildCommDCBA(
532     LPCSTR device, /* [in] The ascii device control string used to update the DCB. */
533     LPDCB  lpdcb)  /* [out] The device control block to be updated. */
534 {
535         return BuildCommDCBAndTimeoutsA(device,lpdcb,NULL);
536 }
537
538 /**************************************************************************
539  *         BuildCommDCBAndTimeoutsA             (KERNEL32.@)
540  *
541  *  Updates a device control block data structure with values from an
542  *  ascii device control string.  Taking timeout values from a timeouts
543  *  struct if desired by the control string.
544  *
545  * RETURNS
546  *
547  *  True on success, false bad handles etc.
548  */
549 BOOL WINAPI BuildCommDCBAndTimeoutsA(
550     LPCSTR         device,     /* [in] The ascii device control string. */
551     LPDCB          lpdcb,      /* [out] The device control block to be updated. */
552     LPCOMMTIMEOUTS lptimeouts) /* [in] The COMMTIMEOUTS structure to be updated. */
553 {
554         BOOL ret = FALSE;
555         UNICODE_STRING deviceW;
556
557         TRACE("(%s,%p,%p)\n",device,lpdcb,lptimeouts);
558         if(device) RtlCreateUnicodeStringFromAsciiz(&deviceW,device);
559         else deviceW.Buffer = NULL;
560
561         if(deviceW.Buffer) ret = BuildCommDCBAndTimeoutsW(deviceW.Buffer,lpdcb,lptimeouts);
562
563         RtlFreeUnicodeString(&deviceW);
564         return ret;
565 }
566
567 /**************************************************************************
568  *         BuildCommDCBAndTimeoutsW     (KERNEL32.@)
569  *
570  *  Updates a device control block data structure with values from a
571  *  unicode device control string.  Taking timeout values from a timeouts
572  *  struct if desired by the control string.
573  *
574  * RETURNS
575  *
576  *  True on success, false bad handles etc
577  */
578 BOOL WINAPI BuildCommDCBAndTimeoutsW(
579     LPCWSTR        devid,      /* [in] The unicode device control string. */
580     LPDCB          lpdcb,      /* [out] The device control block to be updated. */
581     LPCOMMTIMEOUTS lptimeouts) /* [in] The COMMTIMEOUTS structure to be updated. */
582 {
583         DCB dcb;
584         COMMTIMEOUTS timeouts;
585         BOOL result;
586         LPCWSTR ptr = devid;
587         
588         TRACE("(%s,%p,%p)\n",debugstr_w(devid),lpdcb,lptimeouts);
589
590         /* Set DCBlength. (Windows NT does not do this, but 9x does) */
591         lpdcb->DCBlength = sizeof(DCB);
592
593         /* Make a copy of the original data structures to work with since if
594            if there is an error in the device control string the originals
595            should not be modified (except possibly DCBlength) */
596         memcpy(&dcb, lpdcb, sizeof(DCB));
597         if(lptimeouts) memcpy(&timeouts, lptimeouts, sizeof(COMMTIMEOUTS));
598
599         ptr = COMM_ParseStart(ptr);
600
601         if(ptr == NULL)
602                 result = FALSE;
603         else if(strchrW(ptr, ','))
604                 result = COMM_BuildOldCommDCB(ptr, &dcb);
605         else
606                 result = COMM_BuildNewCommDCB(ptr, &dcb, &timeouts);
607
608         if(result)
609         {
610                 memcpy(lpdcb, &dcb, sizeof(DCB));
611                 if(lptimeouts) memcpy(lptimeouts, &timeouts, sizeof(COMMTIMEOUTS));
612                 return TRUE;
613         }
614         else
615         {
616                 WARN("Invalid device control string: %s\n", debugstr_w(devid));
617                 SetLastError(ERROR_INVALID_PARAMETER);
618                 return FALSE;
619         }       
620 }
621
622 /**************************************************************************
623  *         BuildCommDCBW                (KERNEL32.@)
624  *
625  *  Updates a device control block structure with values from an
626  *  unicode device control string.  The device control string has two forms
627  *  normal and extended, it must be exclusively in one or the other form.
628  *
629  * RETURNS
630  *
631  *  True on success, false on a malformed control string.
632  */
633 BOOL WINAPI BuildCommDCBW(
634     LPCWSTR devid, /* [in] The unicode device control string. */
635     LPDCB   lpdcb) /* [out] The device control block to be updated. */
636 {
637         return BuildCommDCBAndTimeoutsW(devid,lpdcb,NULL);
638 }
639
640 /*****************************************************************************
641  *      SetCommBreak            (KERNEL32.@)
642  *
643  *  Halts the transmission of characters to a communications device.
644  *
645  * PARAMS
646  *      handle  [in] The communications device to suspend
647  *
648  * RETURNS
649  *
650  *  True on success, and false if the communications device could not be found,
651  *  the control is not supported.
652  *
653  * BUGS
654  *
655  *  Only TIOCSBRK and TIOCCBRK are supported.
656  */
657 BOOL WINAPI SetCommBreak(HANDLE handle)
658 {
659     return DeviceIoControl(handle, IOCTL_SERIAL_SET_BREAK_ON, NULL, 0, NULL, 0, NULL, NULL);
660 }
661
662 /*****************************************************************************
663  *      ClearCommBreak          (KERNEL32.@)
664  *
665  *  Resumes character transmission from a communication device.
666  *
667  * PARAMS
668  *
669  *      handle [in] The halted communication device whose character transmission is to be resumed
670  *
671  * RETURNS
672  *
673  *  True on success and false if the communications device could not be found.
674  *
675  * BUGS
676  *
677  *  Only TIOCSBRK and TIOCCBRK are supported.
678  */
679 BOOL WINAPI ClearCommBreak(HANDLE handle)
680 {
681     return DeviceIoControl(handle, IOCTL_SERIAL_SET_BREAK_OFF, NULL, 0, NULL, 0, NULL, NULL);
682 }
683
684 /*****************************************************************************
685  *      EscapeCommFunction      (KERNEL32.@)
686  *
687  *  Directs a communication device to perform an extended function.
688  *
689  * PARAMS
690  *
691  *      handle          [in] The communication device to perform the extended function
692  *      nFunction       [in] The extended function to be performed
693  *
694  * RETURNS
695  *
696  *  True or requested data on successful completion of the command,
697  *  false if the device is not present cannot execute the command
698  *  or the command failed.
699  */
700 BOOL WINAPI EscapeCommFunction(HANDLE handle, UINT func)
701 {
702     DWORD       ioc;
703
704     switch (func)
705     {
706     case CLRDTR:        ioc = IOCTL_SERIAL_CLR_DTR;             break;
707     case CLRRTS:        ioc = IOCTL_SERIAL_CLR_RTS;             break;
708     case SETDTR:        ioc = IOCTL_SERIAL_SET_DTR;             break;
709     case SETRTS:        ioc = IOCTL_SERIAL_SET_RTS;             break;
710     case SETXOFF:       ioc = IOCTL_SERIAL_SET_XOFF;            break;
711     case SETXON:        ioc = IOCTL_SERIAL_SET_XON;             break;
712     case SETBREAK:      ioc = IOCTL_SERIAL_SET_BREAK_ON;        break;
713     case CLRBREAK:      ioc = IOCTL_SERIAL_SET_BREAK_OFF;       break;
714     case RESETDEV:      ioc = IOCTL_SERIAL_RESET_DEVICE;        break;
715     default:
716         ERR("Unknown function code (%u)\n", func);
717         SetLastError(ERROR_INVALID_PARAMETER);
718         return FALSE;
719     }
720     return DeviceIoControl(handle, ioc, NULL, 0, NULL, 0, NULL, NULL);
721 }
722
723 /********************************************************************
724  *      PurgeComm        (KERNEL32.@)
725  *
726  *  Terminates pending operations and/or discards buffers on a
727  *  communication resource.
728  *
729  * PARAMS
730  *
731  *      handle  [in] The communication resource to be purged
732  *      flags   [in] Flags for clear pending/buffer on input/output
733  *
734  * RETURNS
735  *
736  *  True on success and false if the communications handle is bad.
737  */
738 BOOL WINAPI PurgeComm(HANDLE handle, DWORD flags)
739 {
740     return DeviceIoControl(handle, IOCTL_SERIAL_PURGE, &flags, sizeof(flags),
741                            NULL, 0, NULL, NULL);
742 }
743
744 /*****************************************************************************
745  *      ClearCommError  (KERNEL32.@)
746  *
747  *  Enables further I/O operations on a communications resource after
748  *  supplying error and current status information.
749  *
750  * PARAMS
751  *
752  *      handle  [in]    The communication resource with the error
753  *      errors  [out]   Flags indicating error the resource experienced
754  *      lpStat  [out] The status of the communication resource
755  * RETURNS
756  *
757  *  True on success, false if the communication resource handle is bad.
758  */
759 BOOL WINAPI ClearCommError(HANDLE handle, LPDWORD errors, LPCOMSTAT lpStat)
760 {
761     SERIAL_STATUS       ss;
762
763     if (!DeviceIoControl(handle, IOCTL_SERIAL_GET_COMMSTATUS, NULL, 0,
764                          &ss, sizeof(ss), NULL, NULL))
765         return FALSE;
766
767     if (errors)
768     {
769         *errors = 0;
770         if (ss.Errors & SERIAL_ERROR_BREAK)             *errors |= CE_BREAK;
771         if (ss.Errors & SERIAL_ERROR_FRAMING)           *errors |= CE_FRAME;
772         if (ss.Errors & SERIAL_ERROR_OVERRUN)           *errors |= CE_OVERRUN;
773         if (ss.Errors & SERIAL_ERROR_QUEUEOVERRUN)      *errors |= CE_RXOVER;
774         if (ss.Errors & SERIAL_ERROR_PARITY)            *errors |= CE_RXPARITY;
775     }
776  
777     if (lpStat)
778     {
779         memset(lpStat, 0, sizeof(*lpStat));
780
781         if (ss.HoldReasons & SERIAL_TX_WAITING_FOR_CTS)         lpStat->fCtsHold = TRUE;
782         if (ss.HoldReasons & SERIAL_TX_WAITING_FOR_DSR)         lpStat->fDsrHold = TRUE;
783         if (ss.HoldReasons & SERIAL_TX_WAITING_FOR_DCD)         lpStat->fRlsdHold = TRUE;
784         if (ss.HoldReasons & SERIAL_TX_WAITING_FOR_XON)         lpStat->fXoffHold = TRUE;
785         if (ss.HoldReasons & SERIAL_TX_WAITING_XOFF_SENT)       lpStat->fXoffSent = TRUE;
786         if (ss.EofReceived)                                     lpStat->fEof = TRUE;
787         if (ss.WaitForImmediate)                                lpStat->fTxim = TRUE;
788         lpStat->cbInQue = ss.AmountInInQueue;
789         lpStat->cbOutQue = ss.AmountInOutQueue;
790     }
791     return TRUE;
792 }
793
794 /*****************************************************************************
795  *      SetupComm       (KERNEL32.@)
796  *
797  *  Called after CreateFile to hint to the communication resource to use
798  *  specified sizes for input and output buffers rather than the default values.
799  *
800  * PARAMS
801  *      handle  [in]    The just created communication resource handle
802  *      insize  [in]    The suggested size of the communication resources input buffer in bytes
803  *      outsize [in]    The suggested size of the communication resources output buffer in bytes
804  *
805  * RETURNS
806  *
807  *  True if successful, false if the communications resource handle is bad.
808  *
809  * BUGS
810  *
811  *  Stub.
812  */
813 BOOL WINAPI SetupComm(HANDLE handle, DWORD insize, DWORD outsize)
814 {
815     SERIAL_QUEUE_SIZE   sqs;
816
817     sqs.InSize = insize;
818     sqs.OutSize = outsize;
819     return DeviceIoControl(handle, IOCTL_SERIAL_SET_QUEUE_SIZE,
820                            &sqs, sizeof(sqs), NULL, 0, NULL, NULL);
821 }
822
823 /*****************************************************************************
824  *      GetCommMask     (KERNEL32.@)
825  *
826  *  Obtain the events associated with a communication device that will cause
827  *  a call WaitCommEvent to return.
828  *
829  *  PARAMS
830  *
831  *      handle  [in]    The communications device
832  *      evtmask [out]   The events which cause WaitCommEvent to return
833  *
834  *  RETURNS
835  *
836  *   True on success, fail on bad device handle etc.
837  */
838 BOOL WINAPI GetCommMask(HANDLE handle, LPDWORD evtmask)
839 {
840     TRACE("handle %p, mask %p\n", handle, evtmask);
841     return DeviceIoControl(handle, IOCTL_SERIAL_GET_WAIT_MASK,
842                            NULL, 0, evtmask, sizeof(*evtmask), NULL, NULL);
843 }
844
845 /*****************************************************************************
846  *      SetCommMask     (KERNEL32.@)
847  *
848  *  There be some things we need to hear about yon there communications device.
849  *  (Set which events associated with a communication device should cause
850  *  a call WaitCommEvent to return.)
851  *
852  * PARAMS
853  *
854  *      handle  [in]    The communications device
855  *      evtmask [in]    The events that are to be monitored
856  *
857  * RETURNS
858  *
859  *  True on success, false on bad handle etc.
860  */
861 BOOL WINAPI SetCommMask(HANDLE handle, DWORD evtmask)
862 {
863     TRACE("handle %p, mask %lx\n", handle, evtmask);
864     return DeviceIoControl(handle, IOCTL_SERIAL_SET_WAIT_MASK,
865                            &evtmask, sizeof(evtmask), NULL, 0, NULL, NULL);
866 }
867
868 static void dump_dcb(const DCB* lpdcb)
869 {
870     TRACE("bytesize=%d baudrate=%ld fParity=%d Parity=%d stopbits=%d\n",
871           lpdcb->ByteSize, lpdcb->BaudRate, lpdcb->fParity, lpdcb->Parity,
872           (lpdcb->StopBits == ONESTOPBIT) ? 1 :
873           (lpdcb->StopBits == TWOSTOPBITS) ? 2 : 0);
874     TRACE("%sIXON %sIXOFF\n", (lpdcb->fInX) ? "" : "~", (lpdcb->fOutX) ? "" : "~");
875     TRACE("fOutxCtsFlow=%d fRtsControl=%d\n", lpdcb->fOutxCtsFlow, lpdcb->fRtsControl);
876     TRACE("fOutxDsrFlow=%d fDtrControl=%d\n", lpdcb->fOutxDsrFlow, lpdcb->fDtrControl);
877     if (lpdcb->fOutxCtsFlow || lpdcb->fRtsControl == RTS_CONTROL_HANDSHAKE)
878         TRACE("CRTSCTS\n");
879     else
880         TRACE("~CRTSCTS\n");
881 }
882
883 /*****************************************************************************
884  *      SetCommState    (KERNEL32.@)
885  *
886  *  Re-initializes all hardware and control settings of a communications device,
887  *  with values from a device control block without effecting the input and output
888  *  queues.
889  *
890  * PARAMS
891  *
892  *      handle  [in]    The communications device
893  *      lpdcb   [out]   The device control block
894  *
895  * RETURNS
896  *
897  *  True on success, false on failure eg if the XonChar is equal to the XoffChar.
898  */
899 BOOL WINAPI SetCommState( HANDLE handle, LPDCB lpdcb)
900 {
901     SERIAL_BAUD_RATE           sbr;
902     SERIAL_LINE_CONTROL        slc;
903     SERIAL_HANDFLOW            shf;
904     SERIAL_CHARS               sc;
905
906     if (lpdcb == NULL)
907     {
908         SetLastError(ERROR_INVALID_PARAMETER);
909         return FALSE;
910     }
911     dump_dcb(lpdcb);
912
913     sbr.BaudRate = lpdcb->BaudRate;
914              
915     slc.StopBits = lpdcb->StopBits;
916     slc.Parity = lpdcb->Parity;
917     slc.WordLength = lpdcb->ByteSize;
918
919     shf.ControlHandShake = 0;
920     shf.FlowReplace = 0;
921     if (lpdcb->fOutxCtsFlow)      shf.ControlHandShake |= SERIAL_CTS_HANDSHAKE;
922     if (lpdcb->fOutxDsrFlow)      shf.ControlHandShake |= SERIAL_DSR_HANDSHAKE;
923     switch (lpdcb->fDtrControl)
924     {
925     case DTR_CONTROL_DISABLE:                                                  break;
926     case DTR_CONTROL_ENABLE:      shf.ControlHandShake |= SERIAL_DTR_CONTROL;  break;
927     case DTR_CONTROL_HANDSHAKE:   shf.ControlHandShake |= SERIAL_DTR_HANDSHAKE;break;
928     default:
929         SetLastError(ERROR_INVALID_PARAMETER);
930         return FALSE;
931     }
932     switch (lpdcb->fDtrControl)
933     {
934     case RTS_CONTROL_DISABLE:                                                  break;
935     case RTS_CONTROL_ENABLE:      shf.FlowReplace |= SERIAL_RTS_CONTROL;       break;
936     case RTS_CONTROL_HANDSHAKE:   shf.FlowReplace |= SERIAL_RTS_HANDSHAKE;     break;
937     case RTS_CONTROL_TOGGLE:      shf.FlowReplace |= SERIAL_RTS_CONTROL | 
938                                                      SERIAL_RTS_HANDSHAKE;     break;
939     default:
940         SetLastError(ERROR_INVALID_PARAMETER);
941         return FALSE;
942     }
943     if (lpdcb->fDsrSensitivity)   shf.ControlHandShake |= SERIAL_DSR_SENSITIVITY;
944     if (lpdcb->fAbortOnError)     shf.ControlHandShake |= SERIAL_ERROR_ABORT;
945
946     if (lpdcb->fErrorChar)        shf.FlowReplace |= SERIAL_ERROR_CHAR;
947     if (lpdcb->fNull)             shf.FlowReplace |= SERIAL_NULL_STRIPPING;
948     if (lpdcb->fTXContinueOnXoff) shf.FlowReplace |= SERIAL_XOFF_CONTINUE;
949     if (lpdcb->fOutX)             shf.FlowReplace |= SERIAL_AUTO_TRANSMIT;
950     if (lpdcb->fInX)              shf.FlowReplace |= SERIAL_AUTO_RECEIVE;
951
952     shf.XonLimit = lpdcb->XonLim;
953     shf.XoffLimit = lpdcb->XoffLim;
954
955     sc.EofChar = lpdcb->EofChar;
956     sc.ErrorChar = lpdcb->ErrorChar;
957     sc.BreakChar = 0;
958     sc.EventChar = lpdcb->EvtChar;
959     sc.XonChar = lpdcb->XonChar;
960     sc.XoffChar = lpdcb->XoffChar;
961
962     /* note: change DTR/RTS lines after setting the comm attributes,
963      * so flow control does not interfere.
964      */
965     return (DeviceIoControl(handle, IOCTL_SERIAL_SET_BAUD_RATE,
966                             &sbr, sizeof(sbr), NULL, 0, NULL, NULL) &&
967             DeviceIoControl(handle, IOCTL_SERIAL_SET_LINE_CONTROL,
968                             &slc, sizeof(slc), NULL, 0, NULL, NULL) &&
969             DeviceIoControl(handle, IOCTL_SERIAL_SET_HANDFLOW,
970                             &shf, sizeof(shf), NULL, 0, NULL, NULL) &&
971             DeviceIoControl(handle, IOCTL_SERIAL_SET_CHARS,
972                             &sc, sizeof(sc), NULL, 0, NULL, NULL));
973 }
974
975
976 /*****************************************************************************
977  *      GetCommState    (KERNEL32.@)
978  *
979  *  Fills in a device control block with information from a communications device.
980  *
981  * PARAMS
982  *      handle          [in]    The communications device
983  *      lpdcb           [out]   The device control block
984  *
985  * RETURNS
986  *
987  *  True on success, false if the communication device handle is bad etc
988  *
989  * BUGS
990  *
991  *  XonChar and XoffChar are not set.
992  */
993 BOOL WINAPI GetCommState(HANDLE handle, LPDCB lpdcb)
994 {
995     SERIAL_BAUD_RATE    sbr;
996     SERIAL_LINE_CONTROL slc;
997     SERIAL_HANDFLOW     shf;
998     SERIAL_CHARS        sc;
999
1000     TRACE("handle %p, ptr %p\n", handle, lpdcb);
1001
1002     if (!lpdcb)
1003     {
1004         SetLastError(ERROR_INVALID_PARAMETER);
1005         return FALSE;
1006     }
1007     
1008     if (!DeviceIoControl(handle, IOCTL_SERIAL_GET_BAUD_RATE,
1009                          NULL, 0, &sbr, sizeof(sbr), NULL, NULL) ||
1010         !DeviceIoControl(handle, IOCTL_SERIAL_GET_LINE_CONTROL,
1011                          NULL, 0, &slc, sizeof(slc), NULL, NULL) ||
1012         !DeviceIoControl(handle, IOCTL_SERIAL_GET_HANDFLOW,
1013                          NULL, 0, &shf, sizeof(shf), NULL, NULL) ||
1014         !DeviceIoControl(handle, IOCTL_SERIAL_GET_CHARS,
1015                          NULL, 0, &sc, sizeof(sc), NULL, NULL))
1016         return FALSE;
1017
1018     memset(lpdcb, 0, sizeof(*lpdcb));
1019     lpdcb->DCBlength = sizeof(*lpdcb);
1020
1021     /* yes, they seem no never be (re)set on NT */
1022     lpdcb->fBinary = 1;
1023     lpdcb->fParity = 0;
1024
1025     lpdcb->BaudRate = sbr.BaudRate;
1026
1027     lpdcb->StopBits = slc.StopBits;
1028     lpdcb->Parity = slc.Parity;
1029     lpdcb->ByteSize = slc.WordLength;
1030
1031     if (shf.ControlHandShake & SERIAL_CTS_HANDSHAKE)    lpdcb->fOutxCtsFlow = 1;
1032     if (shf.ControlHandShake & SERIAL_DSR_HANDSHAKE)    lpdcb->fOutxDsrFlow = 1;
1033     switch (shf.ControlHandShake & (SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE))
1034     {
1035     case 0:                     lpdcb->fDtrControl = DTR_CONTROL_DISABLE; break;
1036     case SERIAL_DTR_CONTROL:    lpdcb->fDtrControl = DTR_CONTROL_ENABLE; break;
1037     case SERIAL_DTR_HANDSHAKE:  lpdcb->fDtrControl = DTR_CONTROL_HANDSHAKE; break;
1038     }
1039     switch (shf.FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE))
1040     {
1041     case 0:                     lpdcb->fRtsControl = RTS_CONTROL_DISABLE; break;
1042     case SERIAL_RTS_CONTROL:    lpdcb->fRtsControl = RTS_CONTROL_ENABLE; break;
1043     case SERIAL_RTS_HANDSHAKE:  lpdcb->fRtsControl = RTS_CONTROL_HANDSHAKE; break;
1044     case SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE:
1045                                 lpdcb->fRtsControl = RTS_CONTROL_TOGGLE; break;
1046     }
1047     if (shf.ControlHandShake & SERIAL_DSR_SENSITIVITY)  lpdcb->fDsrSensitivity = 1;
1048     if (shf.ControlHandShake & SERIAL_ERROR_ABORT)      lpdcb->fAbortOnError = 1;
1049     if (shf.FlowReplace & SERIAL_ERROR_CHAR)            lpdcb->fErrorChar = 1;
1050     if (shf.FlowReplace & SERIAL_NULL_STRIPPING)        lpdcb->fNull = 1;
1051     if (shf.FlowReplace & SERIAL_XOFF_CONTINUE)         lpdcb->fTXContinueOnXoff = 1;
1052     lpdcb->XonLim = shf.XonLimit;
1053     lpdcb->XoffLim = shf.XoffLimit;
1054
1055     if (shf.FlowReplace & SERIAL_AUTO_TRANSMIT) lpdcb->fOutX = 1;
1056     if (shf.FlowReplace & SERIAL_AUTO_RECEIVE)  lpdcb->fInX = 1;
1057
1058     lpdcb->EofChar = sc.EofChar;
1059     lpdcb->ErrorChar = sc.ErrorChar;
1060     lpdcb->EvtChar = sc.EventChar;
1061     lpdcb->XonChar = sc.XonChar;
1062     lpdcb->XoffChar = sc.XoffChar;
1063
1064     TRACE("OK\n");
1065     dump_dcb(lpdcb);
1066
1067     return TRUE;
1068 }
1069
1070 /*****************************************************************************
1071  *      TransmitCommChar        (KERNEL32.@)
1072  *
1073  *  Transmits a single character in front of any pending characters in the
1074  *  output buffer.  Usually used to send an interrupt character to a host.
1075  *
1076  * PARAMS
1077  *      hComm           [in]    The communication device in need of a command character
1078  *      chTransmit      [in]    The character to transmit
1079  *
1080  * RETURNS
1081  *
1082  *  True if the call succeeded, false if the previous command character to the
1083  *  same device has not been sent yet the handle is bad etc.
1084  *
1085  */
1086 BOOL WINAPI TransmitCommChar(HANDLE hComm, CHAR chTransmit)
1087 {
1088     return DeviceIoControl(hComm, IOCTL_SERIAL_IMMEDIATE_CHAR,
1089                            &chTransmit, sizeof(chTransmit), NULL, 0, NULL, NULL);
1090 }
1091
1092
1093 /*****************************************************************************
1094  *      GetCommTimeouts         (KERNEL32.@)
1095  *
1096  *  Obtains the request timeout values for the communications device.
1097  *
1098  * PARAMS
1099  *      hComm           [in]    The communications device
1100  *      lptimeouts      [out]   The struct of request timeouts
1101  *
1102  * RETURNS
1103  *
1104  *  True on success, false if communications device handle is bad
1105  *  or the target structure is null.
1106  */
1107 BOOL WINAPI GetCommTimeouts(HANDLE hComm, LPCOMMTIMEOUTS lptimeouts)
1108 {
1109     SERIAL_TIMEOUTS     st;
1110
1111     TRACE("(%p, %p)\n", hComm, lptimeouts);
1112     if (!lptimeouts)
1113     {
1114         SetLastError(ERROR_INVALID_PARAMETER);
1115         return FALSE;
1116     }
1117     if (!DeviceIoControl(hComm, IOCTL_SERIAL_GET_TIMEOUTS,
1118                          NULL, 0, &st, sizeof(st), NULL, NULL))
1119         return FALSE;
1120     lptimeouts->ReadIntervalTimeout         = st.ReadIntervalTimeout;
1121     lptimeouts->ReadTotalTimeoutMultiplier  = st.ReadTotalTimeoutMultiplier;
1122     lptimeouts->ReadTotalTimeoutConstant    = st.ReadTotalTimeoutConstant;
1123     lptimeouts->WriteTotalTimeoutMultiplier = st.WriteTotalTimeoutMultiplier;
1124     lptimeouts->WriteTotalTimeoutConstant   = st.WriteTotalTimeoutConstant;
1125     return TRUE;
1126 }
1127
1128 /*****************************************************************************
1129  *      SetCommTimeouts         (KERNEL32.@)
1130  *
1131  * Sets the timeouts used when reading and writing data to/from COMM ports.
1132  *
1133  * PARAMS
1134  *      hComm           [in]    handle of COMM device
1135  *      lptimeouts      [in]    pointer to COMMTIMEOUTS structure
1136  *
1137  * ReadIntervalTimeout
1138  *     - converted and passes to linux kernel as c_cc[VTIME]
1139  * ReadTotalTimeoutMultiplier, ReadTotalTimeoutConstant
1140  *     - used in ReadFile to calculate GetOverlappedResult's timeout
1141  * WriteTotalTimeoutMultiplier, WriteTotalTimeoutConstant
1142  *     - used in WriteFile to calculate GetOverlappedResult's timeout
1143  *
1144  * RETURNS
1145  *
1146  *  True if the timeouts were set, false otherwise.
1147  */
1148 BOOL WINAPI SetCommTimeouts(HANDLE hComm, LPCOMMTIMEOUTS lptimeouts)
1149 {
1150     SERIAL_TIMEOUTS     st;
1151
1152     TRACE("(%p, %p)\n", hComm, lptimeouts);
1153
1154     if (lptimeouts == NULL)
1155     {
1156         SetLastError(ERROR_INVALID_PARAMETER);
1157         return FALSE;
1158     }
1159     st.ReadIntervalTimeout         = lptimeouts->ReadIntervalTimeout;
1160     st.ReadTotalTimeoutMultiplier  = lptimeouts->ReadTotalTimeoutMultiplier;
1161     st.ReadTotalTimeoutConstant    = lptimeouts->ReadTotalTimeoutConstant;
1162     st.WriteTotalTimeoutMultiplier = lptimeouts->WriteTotalTimeoutMultiplier;
1163     st.WriteTotalTimeoutConstant   = lptimeouts->WriteTotalTimeoutConstant;
1164  
1165     return DeviceIoControl(hComm, IOCTL_SERIAL_SET_TIMEOUTS,
1166                            &st, sizeof(st), NULL, 0, NULL, NULL);
1167 }
1168
1169 /***********************************************************************
1170  *           GetCommModemStatus   (KERNEL32.@)
1171  *
1172  *  Obtains the four control register bits if supported by the hardware.
1173  *
1174  * PARAMS
1175  *
1176  *      hFile           [in]    The communications device
1177  *      lpModemStat     [out]   The control register bits
1178  *
1179  * RETURNS
1180  *
1181  *  True if the communications handle was good and for hardware that
1182  *  control register access, false otherwise.
1183  */
1184 BOOL WINAPI GetCommModemStatus(HANDLE hFile, LPDWORD lpModemStat)
1185 {
1186     return DeviceIoControl(hFile, IOCTL_SERIAL_GET_MODEMSTATUS,
1187                            NULL, 0, lpModemStat, sizeof(DWORD), NULL, NULL);
1188 }
1189
1190 static DWORD WINAPI Comm_CheckEvents(int fd, DWORD mask, serial_irq_info *new, serial_irq_info *old, DWORD new_mstat, DWORD old_mstat)
1191 {
1192     DWORD ret = 0, queue;
1193
1194     TRACE("mask 0x%08lx\n", mask);
1195     TRACE("old->rx          0x%08x vs. new->rx          0x%08x\n", old->rx, new->rx);
1196     TRACE("old->tx          0x%08x vs. new->tx          0x%08x\n", old->tx, new->tx);
1197     TRACE("old->frame       0x%08x vs. new->frame       0x%08x\n", old->frame, new->frame);
1198     TRACE("old->overrun     0x%08x vs. new->overrun     0x%08x\n", old->overrun, new->overrun);
1199     TRACE("old->parity      0x%08x vs. new->parity      0x%08x\n", old->parity, new->parity);
1200     TRACE("old->brk         0x%08x vs. new->brk         0x%08x\n", old->brk, new->brk);
1201     TRACE("old->buf_overrun 0x%08x vs. new->buf_overrun 0x%08x\n", old->buf_overrun, new->buf_overrun);
1202
1203     ret |= ((mask & EV_BREAK) && ( old->brk != new->brk))?EV_BREAK:0;
1204     ret |= ((mask & EV_CTS  ) && ((old_mstat&MS_CTS_ON )!=(new_mstat&MS_CTS_ON )))?EV_CTS  :0;
1205     ret |= ((mask & EV_DSR  ) && ((old_mstat&MS_DSR_ON )!=(new_mstat&MS_DSR_ON )))?EV_DSR  :0;
1206     ret |= ((mask & EV_RING ) && ((old_mstat&MS_RING_ON)!=(new_mstat&MS_RING_ON)))?EV_RING :0;
1207     ret |= ((mask & EV_RLSD ) && ((old_mstat&MS_RLSD_ON)!=(new_mstat&MS_RLSD_ON)))?EV_RLSD :0;
1208     ret |= ((mask & EV_ERR  ) && (( old->frame != new->frame) ||(old->overrun != new->overrun)
1209                 || (old->parity != new->parity)) )?EV_ERR  :0;
1210     if (mask & EV_RXCHAR)
1211     {
1212         queue = 0;
1213 #ifdef TIOCINQ
1214         if(ioctl(fd, TIOCINQ, &queue))
1215             WARN("TIOCINQ returned error\n");
1216 #endif
1217         if (queue)
1218             ret |= EV_RXCHAR;
1219     }
1220     if (mask & EV_TXEMPTY)
1221     {
1222         queue = 0;
1223 /* We really want to know when all characters have gone out of the transmitter */
1224 #if defined(TIOCSERGETLSR) 
1225         if(ioctl(fd, TIOCSERGETLSR, &queue))
1226             WARN("TIOCSERGETLSR returned error\n");
1227         if (queue)
1228 /* TIOCINQ only checks for an empty buffer */
1229 #elif defined(TIOCINQ)
1230         if(ioctl(fd, TIOCOUTQ, &queue))
1231             WARN("TIOCOUTQ returned error\n");
1232         if (!queue)
1233 #endif
1234            ret |= EV_TXEMPTY;
1235         TRACE("OUTQUEUE %ld, Transmitter %sempty\n", queue, (ret & EV_TXEMPTY)?"":"not ");
1236     }
1237     return ret;
1238     
1239 }
1240
1241 /***********************************************************************
1242  *             COMM_WaitCommEventService      (INTERNAL)
1243  *
1244  *  We need to poll for what is interesting
1245  *  TIOCMIWAIT only checks modem status line and may not be aborted by a changing mask
1246  *
1247  */
1248 static DWORD WINAPI COMM_WaitCommEventService(LPVOID arg)
1249 {
1250     async_commio *commio = (async_commio*) arg;
1251     int waitmask = 0;
1252     int rc, fd, abort;
1253     serial_irq_info new_irq_info;
1254     DWORD new_mstat, new_evtmask;
1255
1256     fd=get_comm_fd( commio->handle, FILE_READ_DATA );
1257
1258     TRACE("handle %p fd 0x%08x, mask 0x%08lx buffer %p event %p irq_info %p waitmask 0x%08x\n", 
1259           commio->handle, fd, commio->evtmask, commio->buffer, commio->hEvent, &commio->irq_info, waitmask);
1260     do
1261     {
1262         /*
1263          * TIOCMIWAIT is not adequate
1264          *
1265          * FIXME:
1266          * We don't handle the EV_RXFLAG (the eventchar)
1267          */
1268         Sleep(1);
1269         rc= COMM_GetEInfo(fd,&new_irq_info);
1270         if (rc)
1271             TRACE("TIOCGICOUNT err %s\n", strerror(errno));
1272         rc = GetCommModemStatus(commio->handle, &new_mstat);
1273         if (!rc)
1274             TRACE("GetCommModemStatus failed\n");
1275         rc = Comm_CheckEvents(fd, commio->evtmask,&new_irq_info,&commio->irq_info, new_mstat, commio->mstat);
1276         GetCommMask(commio->handle, &new_evtmask);
1277         abort = (commio->evtmask != new_evtmask);
1278         TRACE("resulting Eventmask 0x%08x\n", rc);
1279     } while (!rc && ! abort);
1280     if (abort) rc = 0;
1281     release_comm_fd( commio->handle, fd );
1282     *commio->buffer = rc;
1283     if (commio->hEvent != INVALID_HANDLE_VALUE )
1284         NtSetEvent( commio->hEvent, NULL );
1285     HeapFree(GetProcessHeap(), 0, commio );
1286     return 0;
1287 }
1288
1289
1290 /***********************************************************************
1291  *             COMM_WaitCommEvent         (INTERNAL)
1292  *
1293  *  This function must have an lpOverlapped.
1294  */
1295 static BOOL COMM_WaitCommEvent(
1296     HANDLE hFile,              /* [in] handle of comm port to wait for */
1297     LPDWORD lpdwEvents,        /* [out] event(s) that were detected */
1298     LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
1299 {
1300     int                 fd;
1301     async_commio*       commio;
1302     DWORD               result_mask;
1303     BOOL res;
1304
1305     if (!lpOverlapped)
1306     {
1307         SetLastError(ERROR_INVALID_PARAMETER);
1308         return FALSE;
1309     }
1310
1311     if (NtResetEvent(lpOverlapped->hEvent,NULL))
1312         return FALSE;
1313
1314     fd = get_comm_fd( hFile, FILE_WRITE_DATA );
1315     if (fd < 0) return FALSE;
1316
1317     commio = HeapAlloc(GetProcessHeap(), 0, sizeof (async_commio));
1318     if (!commio)
1319     {
1320         release_comm_fd( hFile, fd );
1321         return FALSE;
1322     }
1323
1324     commio->handle = hFile;
1325     commio->buffer = (char *)lpdwEvents;
1326     commio->hEvent = lpOverlapped->hEvent;
1327     GetCommMask(hFile, &commio->evtmask);
1328
1329 /* We may never return, if some capabilities miss
1330  * Return error in that case
1331  */
1332 #if !defined(TIOCINQ)
1333     if(commio->evtmask & EV_RXCHAR)
1334         goto error;
1335 #endif
1336 #if !(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)
1337     if(commio->evtmask & EV_TXEMPTY)
1338         goto error;
1339 #endif
1340 #if !defined(TIOCMGET)
1341     if(commio->evtmask & (EV_CTS | EV_DSR| EV_RING| EV_RLSD))
1342         goto error;
1343 #endif
1344 #if !defined(TIOCM_CTS)
1345     if(commio->evtmask & EV_CTS)
1346         goto error;
1347 #endif
1348 #if !defined(TIOCM_DSR)
1349     if(commio->evtmask & EV_DSR)
1350         goto error;
1351 #endif
1352 #if !defined(TIOCM_RNG)
1353     if(commio->evtmask & EV_RING)
1354         goto error;
1355 #endif
1356 #if !defined(TIOCM_CAR)
1357     if(commio->evtmask & EV_RLSD)
1358         goto error;
1359 #endif
1360     if(commio->evtmask & EV_RXFLAG)
1361         FIXME("EV_RXFLAG not handled\n");
1362     COMM_GetEInfo(fd,&commio->irq_info);
1363     GetCommModemStatus(hFile, &commio->mstat);
1364     /* We might have received something or the TX bufffer is delivered*/
1365     result_mask = Comm_CheckEvents( fd, commio->evtmask, &commio->irq_info, &commio->irq_info,commio->mstat,commio->mstat);
1366     if (result_mask) 
1367     {
1368         TRACE("Event already met\n");
1369         *lpdwEvents = result_mask;
1370         HeapFree(GetProcessHeap(), 0, commio );
1371         res = TRUE;
1372     }
1373     else
1374     {
1375         CreateThread(NULL, 0, COMM_WaitCommEventService, (LPVOID)commio, 0, NULL);
1376         SetLastError(ERROR_IO_PENDING);
1377         res = FALSE;
1378     }
1379     release_comm_fd( hFile, fd );
1380     return res;
1381 #if !defined(TIOCINQ) || (!(defined(TIOCSERGETLSR) && defined(TIOCSER_TEMT)) || !defined(TIOCINQ)) || !defined(TIOCMGET) || !defined(TIOCM_CTS) ||!defined(TIOCM_DSR) || !defined(TIOCM_RNG) || !defined(TIOCM_CAR)
1382  error:
1383     FIXME("Returning error because of missing capabilities\n");
1384     release_comm_fd( hFile, fd );
1385     HeapFree(GetProcessHeap(), 0, commio );
1386     SetLastError(ERROR_INVALID_PARAMETER);
1387     return FALSE;
1388 #endif
1389 }
1390 /***********************************************************************
1391  *           WaitCommEvent   (KERNEL32.@)
1392  *
1393  * Wait until something interesting happens on a COMM port.
1394  * Interesting things (events) are set by calling SetCommMask before
1395  * this function is called.
1396  *
1397  * RETURNS
1398  *   TRUE if successful
1399  *   FALSE if failure
1400  *
1401  *   The set of detected events will be written to *lpdwEventMask
1402  *   ERROR_IO_PENDING will be returned the overlapped structure was passed
1403  *
1404  * BUGS:
1405  *  Only supports EV_RXCHAR and EV_TXEMPTY
1406  */
1407 BOOL WINAPI WaitCommEvent(
1408     HANDLE hFile,              /* [in] handle of comm port to wait for */
1409     LPDWORD lpdwEvents,        /* [out] event(s) that were detected */
1410     LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
1411 {
1412     OVERLAPPED ov;
1413     int ret = 0;
1414     DWORD res, err;
1415
1416     TRACE("(%p %p %p )\n",hFile, lpdwEvents,lpOverlapped);
1417
1418     if(lpOverlapped)
1419         return COMM_WaitCommEvent(hFile, lpdwEvents, lpOverlapped);
1420
1421     /* if there is no overlapped structure, create our own */
1422     ov.hEvent = CreateEventW(NULL,FALSE,FALSE,NULL);
1423
1424     res = COMM_WaitCommEvent(hFile, lpdwEvents, &ov);
1425     err = GetLastError();
1426     if (!res)
1427     {
1428         if (err == ERROR_IO_PENDING)
1429         {
1430             do 
1431             {
1432                 res = WaitForSingleObjectEx(ov.hEvent, INFINITE, FALSE);
1433             } while (res != WAIT_OBJECT_0);
1434             TRACE("Event met\n:");
1435             ret = TRUE;
1436         }
1437         else
1438         {
1439             FIXME("Unknown error 0x%08lx\n", err);
1440             ret = FALSE;
1441         }
1442     }
1443     else
1444         ret = TRUE;
1445     CloseHandle(ov.hEvent);
1446
1447     return ret;
1448 }
1449
1450 /***********************************************************************
1451  *           GetCommProperties   (KERNEL32.@)
1452  *
1453  * This function fills in a structure with the capabilities of the
1454  * communications port driver.
1455  *
1456  * RETURNS
1457  *
1458  *  TRUE on success, FALSE on failure
1459  *  If successful, the lpCommProp structure be filled in with
1460  *  properties of the comm port.
1461  */
1462 BOOL WINAPI GetCommProperties(
1463     HANDLE hFile,          /* [in] handle of the comm port */
1464     LPCOMMPROP lpCommProp) /* [out] pointer to struct to be filled */
1465 {
1466     FIXME("(%p %p )\n",hFile,lpCommProp);
1467     if(!lpCommProp)
1468         return FALSE;
1469
1470     /*
1471      * These values should be valid for LINUX's serial driver
1472      * FIXME: Perhaps they deserve an #ifdef LINUX
1473      */
1474     memset(lpCommProp,0,sizeof(COMMPROP));
1475     lpCommProp->wPacketLength       = 1;
1476     lpCommProp->wPacketVersion      = 1;
1477     lpCommProp->dwServiceMask       = SP_SERIALCOMM;
1478     lpCommProp->dwReserved1         = 0;
1479     lpCommProp->dwMaxTxQueue        = 4096;
1480     lpCommProp->dwMaxRxQueue        = 4096;
1481     lpCommProp->dwMaxBaud           = BAUD_115200;
1482     lpCommProp->dwProvSubType       = PST_RS232;
1483     lpCommProp->dwProvCapabilities  = PCF_DTRDSR | PCF_PARITY_CHECK | PCF_RTSCTS | PCF_TOTALTIMEOUTS;
1484     lpCommProp->dwSettableParams    = SP_BAUD | SP_DATABITS | SP_HANDSHAKING |
1485                                       SP_PARITY | SP_PARITY_CHECK | SP_STOPBITS ;
1486     lpCommProp->dwSettableBaud      = BAUD_075 | BAUD_110 | BAUD_134_5 | BAUD_150 |
1487                 BAUD_300 | BAUD_600 | BAUD_1200 | BAUD_1800 | BAUD_2400 | BAUD_4800 |
1488                 BAUD_9600 | BAUD_19200 | BAUD_38400 | BAUD_57600 | BAUD_115200 ;
1489     lpCommProp->wSettableData       = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8 ;
1490     lpCommProp->wSettableStopParity = STOPBITS_10 | STOPBITS_15 | STOPBITS_20 |
1491                 PARITY_NONE | PARITY_ODD |PARITY_EVEN | PARITY_MARK | PARITY_SPACE;
1492     lpCommProp->dwCurrentTxQueue    = lpCommProp->dwMaxTxQueue;
1493     lpCommProp->dwCurrentRxQueue    = lpCommProp->dwMaxRxQueue;
1494
1495     return TRUE;
1496 }
1497
1498 /***********************************************************************
1499  * FIXME:
1500  * The functionality of CommConfigDialogA, GetDefaultCommConfig and
1501  * SetDefaultCommConfig is implemented in a DLL (usually SERIALUI.DLL).
1502  * This is dependent on the type of COMM port, but since it is doubtful
1503  * anybody will get around to implementing support for fancy serial
1504  * ports in WINE, this is hardcoded for the time being.  The name of
1505  * this DLL should be stored in and read from the system registry in
1506  * the hive HKEY_LOCAL_MACHINE, key
1507  * System\\CurrentControlSet\\Services\\Class\\Ports\\????
1508  * where ???? is the port number... that is determined by PNP
1509  * The DLL should be loaded when the COMM port is opened, and closed
1510  * when the COMM port is closed. - MJM 20 June 2000
1511  ***********************************************************************/
1512 static const WCHAR lpszSerialUI[] = { 
1513    's','e','r','i','a','l','u','i','.','d','l','l',0 };
1514
1515
1516 /***********************************************************************
1517  *           CommConfigDialogA   (KERNEL32.@)
1518  *
1519  * Raises a dialog that allows the user to configure a comm port.
1520  * Fills the COMMCONFIG struct with information specified by the user.
1521  * This function should call a similar routine in the COMM driver...
1522  *
1523  * RETURNS
1524  *
1525  *  TRUE on success, FALSE on failure
1526  *  If successful, the lpCommConfig structure will contain a new
1527  *  configuration for the comm port, as specified by the user.
1528  *
1529  * BUGS
1530  *  The library with the CommConfigDialog code is never unloaded.
1531  * Perhaps this should be done when the comm port is closed?
1532  */
1533 BOOL WINAPI CommConfigDialogA(
1534     LPCSTR lpszDevice,         /* [in] name of communications device */
1535     HWND hWnd,                 /* [in] parent window for the dialog */
1536     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
1537 {
1538     FARPROC lpfnCommDialog;
1539     HMODULE hConfigModule;
1540     BOOL r = FALSE;
1541
1542     TRACE("(%p %p %p)\n",lpszDevice, hWnd, lpCommConfig);
1543
1544     hConfigModule = LoadLibraryW(lpszSerialUI);
1545     if(!hConfigModule)
1546         return FALSE;
1547
1548     lpfnCommDialog = GetProcAddress(hConfigModule, "drvCommConfigDialogA");
1549
1550     if(lpfnCommDialog)
1551         r = lpfnCommDialog(lpszDevice,hWnd,lpCommConfig);
1552
1553     FreeLibrary(hConfigModule);
1554
1555     return r;
1556 }
1557
1558 /***********************************************************************
1559  *           CommConfigDialogW   (KERNEL32.@)
1560  *
1561  * See CommConfigDialogA.
1562  */
1563 BOOL WINAPI CommConfigDialogW(
1564     LPCWSTR lpszDevice,        /* [in] name of communications device */
1565     HWND hWnd,                 /* [in] parent window for the dialog */
1566     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
1567 {
1568     FARPROC lpfnCommDialog;
1569     HMODULE hConfigModule;
1570     BOOL r = FALSE;
1571
1572     TRACE("(%p %p %p)\n",lpszDevice, hWnd, lpCommConfig);
1573
1574     hConfigModule = LoadLibraryW(lpszSerialUI);
1575     if(!hConfigModule)
1576         return FALSE;
1577
1578     lpfnCommDialog = GetProcAddress(hConfigModule, "drvCommConfigDialogW");
1579
1580     if(lpfnCommDialog)
1581         r = lpfnCommDialog(lpszDevice,hWnd,lpCommConfig);
1582
1583     FreeLibrary(hConfigModule);
1584
1585     return r;
1586 }
1587
1588 /***********************************************************************
1589  *           GetCommConfig     (KERNEL32.@)
1590  *
1591  * Fill in the COMMCONFIG structure for the comm port hFile
1592  *
1593  * RETURNS
1594  *
1595  *  TRUE on success, FALSE on failure
1596  *  If successful, lpCommConfig contains the comm port configuration.
1597  *
1598  * BUGS
1599  *
1600  */
1601 BOOL WINAPI GetCommConfig(
1602     HANDLE       hFile,        /* [in] The communications device. */
1603     LPCOMMCONFIG lpCommConfig, /* [out] The communications configuration of the device (if it fits). */
1604     LPDWORD      lpdwSize)     /* [in/out] Initially the size of the configuration buffer/structure,
1605                                   afterwards the number of bytes copied to the buffer or
1606                                   the needed size of the buffer. */
1607 {
1608     BOOL r;
1609
1610     TRACE("(%p %p)\n",hFile,lpCommConfig);
1611
1612     if(lpCommConfig == NULL)
1613         return FALSE;
1614     r = *lpdwSize < sizeof(COMMCONFIG); /* TRUE if not enough space */
1615     *lpdwSize = sizeof(COMMCONFIG);
1616     if(r)
1617         return FALSE;
1618
1619     lpCommConfig->dwSize = sizeof(COMMCONFIG);
1620     lpCommConfig->wVersion = 1;
1621     lpCommConfig->wReserved = 0;
1622     r = GetCommState(hFile,&lpCommConfig->dcb);
1623     lpCommConfig->dwProviderSubType = PST_RS232;
1624     lpCommConfig->dwProviderOffset = 0;
1625     lpCommConfig->dwProviderSize = 0;
1626
1627     return r;
1628 }
1629
1630 /***********************************************************************
1631  *           SetCommConfig     (KERNEL32.@)
1632  *
1633  *  Sets the configuration of the communications device.
1634  *
1635  * RETURNS
1636  *
1637  *  True on success, false if the handle was bad is not a communications device.
1638  */
1639 BOOL WINAPI SetCommConfig(
1640     HANDLE       hFile,         /* [in] The communications device. */
1641     LPCOMMCONFIG lpCommConfig,  /* [in] The desired configuration. */
1642     DWORD dwSize)               /* [in] size of the lpCommConfig struct */
1643 {
1644     TRACE("(%p %p)\n",hFile,lpCommConfig);
1645     return SetCommState(hFile,&lpCommConfig->dcb);
1646 }
1647
1648 /***********************************************************************
1649  *           SetDefaultCommConfigA   (KERNEL32.@)
1650  *
1651  *  Initializes the default configuration for the specified communication
1652  *  device. (ascii)
1653  *
1654  * RETURNS
1655  *
1656  *  True if the device was found and the defaults set, false otherwise
1657  */
1658 BOOL WINAPI SetDefaultCommConfigW(
1659     LPCWSTR       lpszDevice,  /* [in] The ascii name of the device targeted for configuration. */
1660     LPCOMMCONFIG lpCommConfig, /* [in] The default configuration for the device. */
1661     DWORD        dwSize)       /* [in] The number of bytes in the configuration structure. */
1662 {
1663     FARPROC lpfnSetDefaultCommConfig;
1664     HMODULE hConfigModule;
1665     BOOL r = FALSE;
1666
1667     TRACE("(%p %p %lx)\n",lpszDevice, lpCommConfig, dwSize);
1668
1669     hConfigModule = LoadLibraryW(lpszSerialUI);
1670     if(!hConfigModule)
1671         return r;
1672
1673     lpfnSetDefaultCommConfig = GetProcAddress(hConfigModule, "drvSetDefaultCommConfigW");
1674     if (lpfnSetDefaultCommConfig)
1675         r = lpfnSetDefaultCommConfig(lpszDevice, lpCommConfig, dwSize);
1676
1677     FreeLibrary(hConfigModule);
1678
1679     return r;
1680 }
1681
1682
1683 /***********************************************************************
1684  *           SetDefaultCommConfigW     (KERNEL32.@)
1685  *
1686  *  Initializes the default configuration for the specified
1687  *  communication device. (unicode)
1688  *
1689  * RETURNS
1690  *
1691  */
1692 BOOL WINAPI SetDefaultCommConfigA(
1693     LPCSTR      lpszDevice,    /* [in] The unicode name of the device targeted for configuration. */
1694     LPCOMMCONFIG lpCommConfig, /* [in] The default configuration for the device. */
1695     DWORD        dwSize)       /* [in] The number of bytes in the configuration structure. */
1696 {
1697     BOOL r;
1698     LPWSTR lpDeviceW = NULL;
1699     DWORD len;
1700
1701     TRACE("(%s %p %lx)\n",debugstr_a(lpszDevice),lpCommConfig,dwSize);
1702
1703     if (lpszDevice)
1704     {
1705         len = MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, NULL, 0 );
1706         lpDeviceW = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
1707         MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, lpDeviceW, len );
1708     }
1709     r = SetDefaultCommConfigW(lpDeviceW,lpCommConfig,dwSize);
1710     HeapFree( GetProcessHeap(), 0, lpDeviceW );
1711     return r;
1712 }
1713
1714
1715 /***********************************************************************
1716  *           GetDefaultCommConfigW   (KERNEL32.@)
1717  *
1718  *   Acquires the default configuration of the specified communication device. (unicode)
1719  *
1720  *  RETURNS
1721  *
1722  *   True on successful reading of the default configuration,
1723  *   if the device is not found or the buffer is too small.
1724  */
1725 BOOL WINAPI GetDefaultCommConfigW(
1726     LPCWSTR      lpszName, /* [in] The unicode name of the device targeted for configuration. */
1727     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
1728     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
1729                               afterwards the number of bytes copied to the buffer or
1730                               the needed size of the buffer. */
1731 {
1732      LPDCB lpdcb = &(lpCC->dcb);
1733      WCHAR temp[40];
1734      static const WCHAR comW[] = {'C','O','M',0};
1735      static const WCHAR formatW[] = {'C','O','M','%','c',':','3','8','4','0','0',',','n',',','8',',','1',0};
1736
1737      if (strncmpiW(lpszName,comW,3)) {
1738         ERR("not implemented for <%s>\n", debugstr_w(lpszName));
1739         return FALSE;
1740      }
1741
1742      TRACE("(%s %p %ld)\n", debugstr_w(lpszName), lpCC, *lpdwSize );
1743      if (*lpdwSize < sizeof(COMMCONFIG)) {
1744          *lpdwSize = sizeof(COMMCONFIG);
1745          return FALSE;
1746        }
1747
1748      *lpdwSize = sizeof(COMMCONFIG);
1749
1750      lpCC->dwSize = sizeof(COMMCONFIG);
1751      lpCC->wVersion = 1;
1752      lpCC->dwProviderSubType = PST_RS232;
1753      lpCC->dwProviderOffset = 0L;
1754      lpCC->dwProviderSize = 0L;
1755
1756      sprintfW( temp, formatW, lpszName[3]);
1757      FIXME("setting %s as default\n", debugstr_w(temp));
1758
1759      return BuildCommDCBW( temp, lpdcb);
1760 }
1761
1762 /**************************************************************************
1763  *         GetDefaultCommConfigA                (KERNEL32.@)
1764  *
1765  *   Acquires the default configuration of the specified communication device. (ascii)
1766  *
1767  *  RETURNS
1768  *
1769  *   True on successful reading of the default configuration,
1770  *   if the device is not found or the buffer is too small.
1771  */
1772 BOOL WINAPI GetDefaultCommConfigA(
1773     LPCSTR       lpszName, /* [in] The ascii name of the device targeted for configuration. */
1774     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
1775     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
1776                               afterwards the number of bytes copied to the buffer or
1777                               the needed size of the buffer. */
1778 {
1779         BOOL ret = FALSE;
1780         UNICODE_STRING lpszNameW;
1781
1782         TRACE("(%s,%p,%ld)\n",lpszName,lpCC,*lpdwSize);
1783         if(lpszName) RtlCreateUnicodeStringFromAsciiz(&lpszNameW,lpszName);
1784         else lpszNameW.Buffer = NULL;
1785
1786         if(lpszNameW.Buffer) ret = GetDefaultCommConfigW(lpszNameW.Buffer,lpCC,lpdwSize);
1787
1788         RtlFreeUnicodeString(&lpszNameW);
1789         return ret;
1790 }