msvcrt: Don't include msvcrt headers, instead duplicate the definitions in msvcrt.h.
[wine] / dlls / kernel32 / 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winerror.h"
33 #include "winioctl.h"
34 #include "ddk/ntddser.h"
35
36 #include "wine/server.h"
37 #include "wine/unicode.h"
38
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(comm);
42
43 /***********************************************************************
44  *           COMM_Parse*   (Internal)
45  *
46  *  The following COMM_Parse* functions are used by the BuildCommDCB
47  *  functions to help parse the various parts of the device control string.
48  */
49 static LPCWSTR COMM_ParseStart(LPCWSTR ptr)
50 {
51         static const WCHAR comW[] = {'C','O','M',0};
52
53         /* The device control string may optionally start with "COMx" followed
54            by an optional ':' and spaces. */
55         if(!strncmpiW(ptr, comW, 3))
56         {
57                 ptr += 3;
58
59                 /* Allow any com port above 0 as Win 9x does (NT only allows
60                    values for com ports which are actually present) */
61                 if(*ptr < '1' || *ptr > '9')
62                         return NULL;
63                 
64                 /* Advance pointer past port number */
65                 while(*ptr >= '0' && *ptr <= '9') ptr++;
66                 
67                 /* The com port number must be followed by a ':' or ' ' */
68                 if(*ptr != ':' && *ptr != ' ')
69                         return NULL;
70
71                 /* Advance pointer to beginning of next parameter */
72                 while(*ptr == ' ') ptr++;
73                 if(*ptr == ':')
74                 {
75                         ptr++;
76                         while(*ptr == ' ') ptr++;
77                 }
78         }
79         /* The device control string must not start with a space. */
80         else if(*ptr == ' ')
81                 return NULL;
82         
83         return ptr;
84 }
85  
86 static LPCWSTR COMM_ParseNumber(LPCWSTR ptr, LPDWORD lpnumber)
87 {
88         if(*ptr < '0' || *ptr > '9') return NULL;
89         *lpnumber = strtoulW(ptr, NULL, 10);
90         while(*ptr >= '0' && *ptr <= '9') ptr++;
91         return ptr;
92 }
93
94 static LPCWSTR COMM_ParseParity(LPCWSTR ptr, LPBYTE lpparity)
95 {
96         /* Contrary to what you might expect, Windows only sets the Parity
97            member of DCB and not fParity even when parity is specified in the
98            device control string */
99
100         switch(toupperW(*ptr++))
101         {
102         case 'E':
103                 *lpparity = EVENPARITY;
104                 break;
105         case 'M':
106                 *lpparity = MARKPARITY;
107                 break;
108         case 'N':
109                 *lpparity = NOPARITY;
110                 break;
111         case 'O':
112                 *lpparity = ODDPARITY;
113                 break;
114         case 'S':
115                 *lpparity = SPACEPARITY;
116                 break;
117         default:
118                 return NULL;
119         }
120
121         return ptr;
122 }
123
124 static LPCWSTR COMM_ParseByteSize(LPCWSTR ptr, LPBYTE lpbytesize)
125 {
126         DWORD temp;
127
128         if(!(ptr = COMM_ParseNumber(ptr, &temp)))
129                 return NULL;
130
131         if(temp >= 5 && temp <= 8)
132         {
133                 *lpbytesize = temp;
134                 return ptr;
135         }
136         else
137                 return NULL;
138 }
139
140 static LPCWSTR COMM_ParseStopBits(LPCWSTR ptr, LPBYTE lpstopbits)
141 {
142         DWORD temp;
143         static const WCHAR stopbits15W[] = {'1','.','5',0};
144
145         if(!strncmpW(stopbits15W, ptr, 3))
146         {
147                 ptr += 3;
148                 *lpstopbits = ONE5STOPBITS;
149         }
150         else
151         {
152                 if(!(ptr = COMM_ParseNumber(ptr, &temp)))
153                         return NULL;
154
155                 if(temp == 1)
156                         *lpstopbits = ONESTOPBIT;
157                 else if(temp == 2)
158                         *lpstopbits = TWOSTOPBITS;
159                 else
160                         return NULL;
161         }
162         
163         return ptr;
164 }
165
166 static LPCWSTR COMM_ParseOnOff(LPCWSTR ptr, LPDWORD lponoff)
167 {
168         static const WCHAR onW[] = {'o','n',0};
169         static const WCHAR offW[] = {'o','f','f',0};
170
171         if(!strncmpiW(onW, ptr, 2))
172         {
173                 ptr += 2;
174                 *lponoff = 1;
175         }
176         else if(!strncmpiW(offW, ptr, 3))
177         {
178                 ptr += 3;
179                 *lponoff = 0;
180         }
181         else
182                 return NULL;
183
184         return ptr;
185 }
186
187 /***********************************************************************
188  *           COMM_BuildOldCommDCB   (Internal)
189  *
190  *  Build a DCB using the old style settings string eg: "96,n,8,1"
191  */
192 static BOOL COMM_BuildOldCommDCB(LPCWSTR device, LPDCB lpdcb)
193 {
194         WCHAR last = 0;
195
196         if(!(device = COMM_ParseNumber(device, &lpdcb->BaudRate)))
197                 return FALSE;
198         
199         switch(lpdcb->BaudRate)
200         {
201         case 11:
202         case 30:
203         case 60:
204                 lpdcb->BaudRate *= 10;
205                 break;
206         case 12:
207         case 24:
208         case 48:
209         case 96:
210                 lpdcb->BaudRate *= 100;
211                 break;
212         case 19:
213                 lpdcb->BaudRate = 19200;
214                 break;
215         }
216
217         while(*device == ' ') device++;
218         if(*device++ != ',') return FALSE;
219         while(*device == ' ') device++;
220
221         if(!(device = COMM_ParseParity(device, &lpdcb->Parity)))
222                 return FALSE;
223
224         while(*device == ' ') device++;
225         if(*device++ != ',') return FALSE;
226         while(*device == ' ') device++;
227                 
228         if(!(device = COMM_ParseByteSize(device, &lpdcb->ByteSize)))
229                 return FALSE;
230
231         while(*device == ' ') device++;
232         if(*device++ != ',') return FALSE;
233         while(*device == ' ') device++;
234
235         if(!(device = COMM_ParseStopBits(device, &lpdcb->StopBits)))
236                 return FALSE;
237
238         /* The last parameter for flow control is optional. */
239         while(*device == ' ') device++;
240         if(*device == ',')
241         {
242                 device++;
243                 while(*device == ' ') device++;
244                 if(*device) last = toupperW(*device++);
245                 while(*device == ' ') device++;
246         }
247
248         /* Win NT sets the flow control members based on (or lack of) the last
249            parameter.  Win 9x does not set these members. */
250         switch(last)
251         {
252         case 0:
253                 lpdcb->fInX = FALSE;
254                 lpdcb->fOutX = FALSE;
255                 lpdcb->fOutxCtsFlow = FALSE;
256                 lpdcb->fOutxDsrFlow = FALSE;
257                 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
258                 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
259                 break;
260         case 'X':
261                 lpdcb->fInX = TRUE;
262                 lpdcb->fOutX = TRUE;
263                 lpdcb->fOutxCtsFlow = FALSE;
264                 lpdcb->fOutxDsrFlow = FALSE;
265                 lpdcb->fDtrControl = DTR_CONTROL_ENABLE;
266                 lpdcb->fRtsControl = RTS_CONTROL_ENABLE;
267                 break;
268         case 'P':
269                 lpdcb->fInX = FALSE;
270                 lpdcb->fOutX = FALSE;
271                 lpdcb->fOutxCtsFlow = TRUE;
272                 lpdcb->fOutxDsrFlow = TRUE;
273                 lpdcb->fDtrControl = DTR_CONTROL_HANDSHAKE;
274                 lpdcb->fRtsControl = RTS_CONTROL_HANDSHAKE;
275                 break;
276         default:
277                 return FALSE;
278         }
279
280         /* This should be the end of the string. */
281         if(*device) return FALSE;
282         
283         return TRUE;
284 }
285
286 /***********************************************************************
287  *           COMM_BuildNewCommDCB   (Internal)
288  *
289  *  Build a DCB using the new style settings string.
290  *   eg: "baud=9600 parity=n data=8 stop=1 xon=on to=on"
291  */
292 static BOOL COMM_BuildNewCommDCB(LPCWSTR device, LPDCB lpdcb, LPCOMMTIMEOUTS lptimeouts)
293 {
294         DWORD temp;
295         BOOL baud = FALSE, stop = FALSE;
296         static const WCHAR baudW[] = {'b','a','u','d','=',0};
297         static const WCHAR parityW[] = {'p','a','r','i','t','y','=',0};
298         static const WCHAR dataW[] = {'d','a','t','a','=',0};
299         static const WCHAR stopW[] = {'s','t','o','p','=',0};
300         static const WCHAR toW[] = {'t','o','=',0};
301         static const WCHAR xonW[] = {'x','o','n','=',0};
302         static const WCHAR odsrW[] = {'o','d','s','r','=',0};
303         static const WCHAR octsW[] = {'o','c','t','s','=',0};
304         static const WCHAR dtrW[] = {'d','t','r','=',0};
305         static const WCHAR rtsW[] = {'r','t','s','=',0};
306         static const WCHAR idsrW[] = {'i','d','s','r','=',0};
307
308         while(*device)
309         {
310                 while(*device == ' ') device++;
311
312                 if(!strncmpiW(baudW, device, 5))
313                 {
314                         baud = TRUE;
315                         
316                         if(!(device = COMM_ParseNumber(device + 5, &lpdcb->BaudRate)))
317                                 return FALSE;
318                 }
319                 else if(!strncmpiW(parityW, device, 7))
320                 {
321                         if(!(device = COMM_ParseParity(device + 7, &lpdcb->Parity)))
322                                 return FALSE;
323                 }
324                 else if(!strncmpiW(dataW, device, 5))
325                 {
326                         if(!(device = COMM_ParseByteSize(device + 5, &lpdcb->ByteSize)))
327                                 return FALSE;
328                 }
329                 else if(!strncmpiW(stopW, device, 5))
330                 {
331                         stop = TRUE;
332                         
333                         if(!(device = COMM_ParseStopBits(device + 5, &lpdcb->StopBits)))
334                                 return FALSE;
335                 }
336                 else if(!strncmpiW(toW, device, 3))
337                 {
338                         if(!(device = COMM_ParseOnOff(device + 3, &temp)))
339                                 return FALSE;
340
341                         lptimeouts->ReadIntervalTimeout = 0;
342                         lptimeouts->ReadTotalTimeoutMultiplier = 0;
343                         lptimeouts->ReadTotalTimeoutConstant = 0;
344                         lptimeouts->WriteTotalTimeoutMultiplier = 0;
345                         lptimeouts->WriteTotalTimeoutConstant = temp ? 60000 : 0;
346                 }
347                 else if(!strncmpiW(xonW, device, 4))
348                 {
349                         if(!(device = COMM_ParseOnOff(device + 4, &temp)))
350                                 return FALSE;
351
352                         lpdcb->fOutX = temp;
353                         lpdcb->fInX = temp;
354                 }
355                 else if(!strncmpiW(odsrW, device, 5))
356                 {
357                         if(!(device = COMM_ParseOnOff(device + 5, &temp)))
358                                 return FALSE;
359
360                         lpdcb->fOutxDsrFlow = temp;
361                 }
362                 else if(!strncmpiW(octsW, device, 5))
363                 {
364                         if(!(device = COMM_ParseOnOff(device + 5, &temp)))
365                                 return FALSE;
366
367                         lpdcb->fOutxCtsFlow = temp;
368                 }
369                 else if(!strncmpiW(dtrW, device, 4))
370                 {
371                         if(!(device = COMM_ParseOnOff(device + 4, &temp)))
372                                 return FALSE;
373
374                         lpdcb->fDtrControl = temp;
375                 }
376                 else if(!strncmpiW(rtsW, device, 4))
377                 {
378                         if(!(device = COMM_ParseOnOff(device + 4, &temp)))
379                                 return FALSE;
380
381                         lpdcb->fRtsControl = temp;
382                 }
383                 else if(!strncmpiW(idsrW, device, 5))
384                 {
385                         if(!(device = COMM_ParseOnOff(device + 5, &temp)))
386                                 return FALSE;
387
388                         /* Win NT sets the fDsrSensitivity member based on the
389                            idsr parameter.  Win 9x sets fOutxDsrFlow instead. */
390                         lpdcb->fDsrSensitivity = temp;
391                 }
392                 else
393                         return FALSE;
394
395                 /* After the above parsing, the next character (if not the end of
396                    the string) should be a space */
397                 if(*device && *device != ' ')
398                         return FALSE;
399         }
400
401         /* If stop bits were not specified, a default is always supplied. */
402         if(!stop)
403         {
404                 if(baud && lpdcb->BaudRate == 110)
405                         lpdcb->StopBits = TWOSTOPBITS;
406                 else
407                         lpdcb->StopBits = ONESTOPBIT;
408         }
409
410         return TRUE;
411 }
412
413 /**************************************************************************
414  *         BuildCommDCBA                (KERNEL32.@)
415  *
416  *  Updates a device control block data structure with values from an
417  *  ascii device control string.  The device control string has two forms
418  *  normal and extended, it must be exclusively in one or the other form.
419  *
420  * RETURNS
421  *
422  *  True on success, false on a malformed control string.
423  */
424 BOOL WINAPI BuildCommDCBA(
425     LPCSTR device, /* [in] The ascii device control string used to update the DCB. */
426     LPDCB  lpdcb)  /* [out] The device control block to be updated. */
427 {
428         return BuildCommDCBAndTimeoutsA(device,lpdcb,NULL);
429 }
430
431 /**************************************************************************
432  *         BuildCommDCBAndTimeoutsA             (KERNEL32.@)
433  *
434  *  Updates a device control block data structure with values from an
435  *  ascii device control string.  Taking timeout values from a timeouts
436  *  struct if desired by the control string.
437  *
438  * RETURNS
439  *
440  *  True on success, false bad handles etc.
441  */
442 BOOL WINAPI BuildCommDCBAndTimeoutsA(
443     LPCSTR         device,     /* [in] The ascii device control string. */
444     LPDCB          lpdcb,      /* [out] The device control block to be updated. */
445     LPCOMMTIMEOUTS lptimeouts) /* [in] The COMMTIMEOUTS structure to be updated. */
446 {
447         BOOL ret = FALSE;
448         UNICODE_STRING deviceW;
449
450         TRACE("(%s,%p,%p)\n",device,lpdcb,lptimeouts);
451         if(device) RtlCreateUnicodeStringFromAsciiz(&deviceW,device);
452         else deviceW.Buffer = NULL;
453
454         if(deviceW.Buffer) ret = BuildCommDCBAndTimeoutsW(deviceW.Buffer,lpdcb,lptimeouts);
455
456         RtlFreeUnicodeString(&deviceW);
457         return ret;
458 }
459
460 /**************************************************************************
461  *         BuildCommDCBAndTimeoutsW     (KERNEL32.@)
462  *
463  *  Updates a device control block data structure with values from a
464  *  unicode device control string.  Taking timeout values from a timeouts
465  *  struct if desired by the control string.
466  *
467  * RETURNS
468  *
469  *  True on success, false bad handles etc
470  */
471 BOOL WINAPI BuildCommDCBAndTimeoutsW(
472     LPCWSTR        devid,      /* [in] The unicode device control string. */
473     LPDCB          lpdcb,      /* [out] The device control block to be updated. */
474     LPCOMMTIMEOUTS lptimeouts) /* [in] The COMMTIMEOUTS structure to be updated. */
475 {
476         DCB dcb;
477         COMMTIMEOUTS timeouts;
478         BOOL result;
479         LPCWSTR ptr = devid;
480
481         TRACE("(%s,%p,%p)\n",debugstr_w(devid),lpdcb,lptimeouts);
482
483         memset(&timeouts, 0, sizeof timeouts);
484
485         /* Set DCBlength. (Windows NT does not do this, but 9x does) */
486         lpdcb->DCBlength = sizeof(DCB);
487
488         /* Make a copy of the original data structures to work with since if
489            if there is an error in the device control string the originals
490            should not be modified (except possibly DCBlength) */
491         dcb = *lpdcb;
492         if(lptimeouts) timeouts = *lptimeouts;
493
494         ptr = COMM_ParseStart(ptr);
495
496         if(ptr == NULL)
497                 result = FALSE;
498         else if(strchrW(ptr, ','))
499                 result = COMM_BuildOldCommDCB(ptr, &dcb);
500         else
501                 result = COMM_BuildNewCommDCB(ptr, &dcb, &timeouts);
502
503         if(result)
504         {
505                 *lpdcb = dcb;
506                 if(lptimeouts) *lptimeouts = timeouts;
507                 return TRUE;
508         }
509         else
510         {
511                 WARN("Invalid device control string: %s\n", debugstr_w(devid));
512                 SetLastError(ERROR_INVALID_PARAMETER);
513                 return FALSE;
514         }       
515 }
516
517 /**************************************************************************
518  *         BuildCommDCBW                (KERNEL32.@)
519  *
520  *  Updates a device control block structure with values from an
521  *  unicode device control string.  The device control string has two forms
522  *  normal and extended, it must be exclusively in one or the other form.
523  *
524  * RETURNS
525  *
526  *  True on success, false on a malformed control string.
527  */
528 BOOL WINAPI BuildCommDCBW(
529     LPCWSTR devid, /* [in] The unicode device control string. */
530     LPDCB   lpdcb) /* [out] The device control block to be updated. */
531 {
532         return BuildCommDCBAndTimeoutsW(devid,lpdcb,NULL);
533 }
534
535 /*****************************************************************************
536  *      SetCommBreak            (KERNEL32.@)
537  *
538  *  Halts the transmission of characters to a communications device.
539  *
540  * PARAMS
541  *      handle  [in] The communications device to suspend
542  *
543  * RETURNS
544  *
545  *  True on success, and false if the communications device could not be found,
546  *  the control is not supported.
547  *
548  * BUGS
549  *
550  *  Only TIOCSBRK and TIOCCBRK are supported.
551  */
552 BOOL WINAPI SetCommBreak(HANDLE handle)
553 {
554     return DeviceIoControl(handle, IOCTL_SERIAL_SET_BREAK_ON, NULL, 0, NULL, 0, NULL, NULL);
555 }
556
557 /*****************************************************************************
558  *      ClearCommBreak          (KERNEL32.@)
559  *
560  *  Resumes character transmission from a communication device.
561  *
562  * PARAMS
563  *
564  *      handle [in] The halted communication device whose character transmission is to be resumed
565  *
566  * RETURNS
567  *
568  *  True on success and false if the communications device could not be found.
569  *
570  * BUGS
571  *
572  *  Only TIOCSBRK and TIOCCBRK are supported.
573  */
574 BOOL WINAPI ClearCommBreak(HANDLE handle)
575 {
576     return DeviceIoControl(handle, IOCTL_SERIAL_SET_BREAK_OFF, NULL, 0, NULL, 0, NULL, NULL);
577 }
578
579 /*****************************************************************************
580  *      EscapeCommFunction      (KERNEL32.@)
581  *
582  *  Directs a communication device to perform an extended function.
583  *
584  * PARAMS
585  *
586  *      handle          [in] The communication device to perform the extended function
587  *      nFunction       [in] The extended function to be performed
588  *
589  * RETURNS
590  *
591  *  True or requested data on successful completion of the command,
592  *  false if the device is not present cannot execute the command
593  *  or the command failed.
594  */
595 BOOL WINAPI EscapeCommFunction(HANDLE handle, UINT func)
596 {
597     DWORD       ioc;
598
599     switch (func)
600     {
601     case CLRDTR:        ioc = IOCTL_SERIAL_CLR_DTR;             break;
602     case CLRRTS:        ioc = IOCTL_SERIAL_CLR_RTS;             break;
603     case SETDTR:        ioc = IOCTL_SERIAL_SET_DTR;             break;
604     case SETRTS:        ioc = IOCTL_SERIAL_SET_RTS;             break;
605     case SETXOFF:       ioc = IOCTL_SERIAL_SET_XOFF;            break;
606     case SETXON:        ioc = IOCTL_SERIAL_SET_XON;             break;
607     case SETBREAK:      ioc = IOCTL_SERIAL_SET_BREAK_ON;        break;
608     case CLRBREAK:      ioc = IOCTL_SERIAL_SET_BREAK_OFF;       break;
609     case RESETDEV:      ioc = IOCTL_SERIAL_RESET_DEVICE;        break;
610     default:
611         ERR("Unknown function code (%u)\n", func);
612         SetLastError(ERROR_INVALID_PARAMETER);
613         return FALSE;
614     }
615     return DeviceIoControl(handle, ioc, NULL, 0, NULL, 0, NULL, NULL);
616 }
617
618 /********************************************************************
619  *      PurgeComm        (KERNEL32.@)
620  *
621  *  Terminates pending operations and/or discards buffers on a
622  *  communication resource.
623  *
624  * PARAMS
625  *
626  *      handle  [in] The communication resource to be purged
627  *      flags   [in] Flags for clear pending/buffer on input/output
628  *
629  * RETURNS
630  *
631  *  True on success and false if the communications handle is bad.
632  */
633 BOOL WINAPI PurgeComm(HANDLE handle, DWORD flags)
634 {
635     return DeviceIoControl(handle, IOCTL_SERIAL_PURGE, &flags, sizeof(flags),
636                            NULL, 0, NULL, NULL);
637 }
638
639 /*****************************************************************************
640  *      ClearCommError  (KERNEL32.@)
641  *
642  *  Enables further I/O operations on a communications resource after
643  *  supplying error and current status information.
644  *
645  * PARAMS
646  *
647  *      handle  [in]    The communication resource with the error
648  *      errors  [out]   Flags indicating error the resource experienced
649  *      lpStat  [out] The status of the communication resource
650  * RETURNS
651  *
652  *  True on success, false if the communication resource handle is bad.
653  */
654 BOOL WINAPI ClearCommError(HANDLE handle, LPDWORD errors, LPCOMSTAT lpStat)
655 {
656     SERIAL_STATUS       ss;
657
658     if (!DeviceIoControl(handle, IOCTL_SERIAL_GET_COMMSTATUS, NULL, 0,
659                          &ss, sizeof(ss), NULL, NULL))
660         return FALSE;
661
662     if (errors)
663     {
664         *errors = 0;
665         if (ss.Errors & SERIAL_ERROR_BREAK)             *errors |= CE_BREAK;
666         if (ss.Errors & SERIAL_ERROR_FRAMING)           *errors |= CE_FRAME;
667         if (ss.Errors & SERIAL_ERROR_OVERRUN)           *errors |= CE_OVERRUN;
668         if (ss.Errors & SERIAL_ERROR_QUEUEOVERRUN)      *errors |= CE_RXOVER;
669         if (ss.Errors & SERIAL_ERROR_PARITY)            *errors |= CE_RXPARITY;
670     }
671  
672     if (lpStat)
673     {
674         memset(lpStat, 0, sizeof(*lpStat));
675
676         if (ss.HoldReasons & SERIAL_TX_WAITING_FOR_CTS)         lpStat->fCtsHold = TRUE;
677         if (ss.HoldReasons & SERIAL_TX_WAITING_FOR_DSR)         lpStat->fDsrHold = TRUE;
678         if (ss.HoldReasons & SERIAL_TX_WAITING_FOR_DCD)         lpStat->fRlsdHold = TRUE;
679         if (ss.HoldReasons & SERIAL_TX_WAITING_FOR_XON)         lpStat->fXoffHold = TRUE;
680         if (ss.HoldReasons & SERIAL_TX_WAITING_XOFF_SENT)       lpStat->fXoffSent = TRUE;
681         if (ss.EofReceived)                                     lpStat->fEof = TRUE;
682         if (ss.WaitForImmediate)                                lpStat->fTxim = TRUE;
683         lpStat->cbInQue = ss.AmountInInQueue;
684         lpStat->cbOutQue = ss.AmountInOutQueue;
685     }
686     return TRUE;
687 }
688
689 /*****************************************************************************
690  *      SetupComm       (KERNEL32.@)
691  *
692  *  Called after CreateFile to hint to the communication resource to use
693  *  specified sizes for input and output buffers rather than the default values.
694  *
695  * PARAMS
696  *      handle  [in]    The just created communication resource handle
697  *      insize  [in]    The suggested size of the communication resources input buffer in bytes
698  *      outsize [in]    The suggested size of the communication resources output buffer in bytes
699  *
700  * RETURNS
701  *
702  *  True if successful, false if the communications resource handle is bad.
703  *
704  * BUGS
705  *
706  *  Stub.
707  */
708 BOOL WINAPI SetupComm(HANDLE handle, DWORD insize, DWORD outsize)
709 {
710     SERIAL_QUEUE_SIZE   sqs;
711
712     sqs.InSize = insize;
713     sqs.OutSize = outsize;
714     return DeviceIoControl(handle, IOCTL_SERIAL_SET_QUEUE_SIZE,
715                            &sqs, sizeof(sqs), NULL, 0, NULL, NULL);
716 }
717
718 /*****************************************************************************
719  *      GetCommMask     (KERNEL32.@)
720  *
721  *  Obtain the events associated with a communication device that will cause
722  *  a call WaitCommEvent to return.
723  *
724  *  PARAMS
725  *
726  *      handle  [in]    The communications device
727  *      evtmask [out]   The events which cause WaitCommEvent to return
728  *
729  *  RETURNS
730  *
731  *   True on success, fail on bad device handle etc.
732  */
733 BOOL WINAPI GetCommMask(HANDLE handle, LPDWORD evtmask)
734 {
735     TRACE("handle %p, mask %p\n", handle, evtmask);
736     return DeviceIoControl(handle, IOCTL_SERIAL_GET_WAIT_MASK,
737                            NULL, 0, evtmask, sizeof(*evtmask), NULL, NULL);
738 }
739
740 /*****************************************************************************
741  *      SetCommMask     (KERNEL32.@)
742  *
743  *  There be some things we need to hear about yon there communications device.
744  *  (Set which events associated with a communication device should cause
745  *  a call WaitCommEvent to return.)
746  *
747  * PARAMS
748  *
749  *      handle  [in]    The communications device
750  *      evtmask [in]    The events that are to be monitored
751  *
752  * RETURNS
753  *
754  *  True on success, false on bad handle etc.
755  */
756 BOOL WINAPI SetCommMask(HANDLE handle, DWORD evtmask)
757 {
758     TRACE("handle %p, mask %x\n", handle, evtmask);
759     return DeviceIoControl(handle, IOCTL_SERIAL_SET_WAIT_MASK,
760                            &evtmask, sizeof(evtmask), NULL, 0, NULL, NULL);
761 }
762
763 static void dump_dcb(const DCB* lpdcb)
764 {
765     TRACE("bytesize=%d baudrate=%d fParity=%d Parity=%d stopbits=%d\n",
766           lpdcb->ByteSize, lpdcb->BaudRate, lpdcb->fParity, lpdcb->Parity,
767           (lpdcb->StopBits == ONESTOPBIT) ? 1 :
768           (lpdcb->StopBits == TWOSTOPBITS) ? 2 : 0);
769     TRACE("%sIXON %sIXOFF\n", (lpdcb->fInX) ? "" : "~", (lpdcb->fOutX) ? "" : "~");
770     TRACE("fOutxCtsFlow=%d fRtsControl=%d\n", lpdcb->fOutxCtsFlow, lpdcb->fRtsControl);
771     TRACE("fOutxDsrFlow=%d fDtrControl=%d\n", lpdcb->fOutxDsrFlow, lpdcb->fDtrControl);
772     if (lpdcb->fOutxCtsFlow || lpdcb->fRtsControl == RTS_CONTROL_HANDSHAKE)
773         TRACE("CRTSCTS\n");
774     else
775         TRACE("~CRTSCTS\n");
776 }
777
778 /*****************************************************************************
779  *      SetCommState    (KERNEL32.@)
780  *
781  *  Re-initializes all hardware and control settings of a communications device,
782  *  with values from a device control block without affecting the input and output
783  *  queues.
784  *
785  * PARAMS
786  *
787  *      handle  [in]    The communications device
788  *      lpdcb   [out]   The device control block
789  *
790  * RETURNS
791  *
792  *  True on success, false on failure, e.g., if the XonChar is equal to the XoffChar.
793  */
794 BOOL WINAPI SetCommState( HANDLE handle, LPDCB lpdcb)
795 {
796     SERIAL_BAUD_RATE           sbr;
797     SERIAL_LINE_CONTROL        slc;
798     SERIAL_HANDFLOW            shf;
799     SERIAL_CHARS               sc;
800
801     if (lpdcb == NULL)
802     {
803         SetLastError(ERROR_INVALID_PARAMETER);
804         return FALSE;
805     }
806     dump_dcb(lpdcb);
807
808     sbr.BaudRate = lpdcb->BaudRate;
809              
810     slc.StopBits = lpdcb->StopBits;
811     slc.Parity = lpdcb->Parity;
812     slc.WordLength = lpdcb->ByteSize;
813
814     shf.ControlHandShake = 0;
815     shf.FlowReplace = 0;
816     if (lpdcb->fOutxCtsFlow)      shf.ControlHandShake |= SERIAL_CTS_HANDSHAKE;
817     if (lpdcb->fOutxDsrFlow)      shf.ControlHandShake |= SERIAL_DSR_HANDSHAKE;
818     switch (lpdcb->fDtrControl)
819     {
820     case DTR_CONTROL_DISABLE:                                                  break;
821     case DTR_CONTROL_ENABLE:      shf.ControlHandShake |= SERIAL_DTR_CONTROL;  break;
822     case DTR_CONTROL_HANDSHAKE:   shf.ControlHandShake |= SERIAL_DTR_HANDSHAKE;break;
823     default:
824         SetLastError(ERROR_INVALID_PARAMETER);
825         return FALSE;
826     }
827     switch (lpdcb->fRtsControl)
828     {
829     case RTS_CONTROL_DISABLE:                                                  break;
830     case RTS_CONTROL_ENABLE:      shf.FlowReplace |= SERIAL_RTS_CONTROL;       break;
831     case RTS_CONTROL_HANDSHAKE:   shf.FlowReplace |= SERIAL_RTS_HANDSHAKE;     break;
832     case RTS_CONTROL_TOGGLE:      shf.FlowReplace |= SERIAL_RTS_CONTROL | 
833                                                      SERIAL_RTS_HANDSHAKE;     break;
834     default:
835         SetLastError(ERROR_INVALID_PARAMETER);
836         return FALSE;
837     }
838     if (lpdcb->fDsrSensitivity)   shf.ControlHandShake |= SERIAL_DSR_SENSITIVITY;
839     if (lpdcb->fAbortOnError)     shf.ControlHandShake |= SERIAL_ERROR_ABORT;
840
841     if (lpdcb->fErrorChar)        shf.FlowReplace |= SERIAL_ERROR_CHAR;
842     if (lpdcb->fNull)             shf.FlowReplace |= SERIAL_NULL_STRIPPING;
843     if (lpdcb->fTXContinueOnXoff) shf.FlowReplace |= SERIAL_XOFF_CONTINUE;
844     if (lpdcb->fOutX)             shf.FlowReplace |= SERIAL_AUTO_TRANSMIT;
845     if (lpdcb->fInX)              shf.FlowReplace |= SERIAL_AUTO_RECEIVE;
846
847     shf.XonLimit = lpdcb->XonLim;
848     shf.XoffLimit = lpdcb->XoffLim;
849
850     sc.EofChar = lpdcb->EofChar;
851     sc.ErrorChar = lpdcb->ErrorChar;
852     sc.BreakChar = 0;
853     sc.EventChar = lpdcb->EvtChar;
854     sc.XonChar = lpdcb->XonChar;
855     sc.XoffChar = lpdcb->XoffChar;
856
857     /* note: change DTR/RTS lines after setting the comm attributes,
858      * so flow control does not interfere.
859      */
860     return (DeviceIoControl(handle, IOCTL_SERIAL_SET_BAUD_RATE,
861                             &sbr, sizeof(sbr), NULL, 0, NULL, NULL) &&
862             DeviceIoControl(handle, IOCTL_SERIAL_SET_LINE_CONTROL,
863                             &slc, sizeof(slc), NULL, 0, NULL, NULL) &&
864             DeviceIoControl(handle, IOCTL_SERIAL_SET_HANDFLOW,
865                             &shf, sizeof(shf), NULL, 0, NULL, NULL) &&
866             DeviceIoControl(handle, IOCTL_SERIAL_SET_CHARS,
867                             &sc, sizeof(sc), NULL, 0, NULL, NULL));
868 }
869
870
871 /*****************************************************************************
872  *      GetCommState    (KERNEL32.@)
873  *
874  *  Fills in a device control block with information from a communications device.
875  *
876  * PARAMS
877  *      handle          [in]    The communications device
878  *      lpdcb           [out]   The device control block
879  *
880  * RETURNS
881  *
882  *  True on success, false if the communication device handle is bad etc
883  *
884  * BUGS
885  *
886  *  XonChar and XoffChar are not set.
887  */
888 BOOL WINAPI GetCommState(HANDLE handle, LPDCB lpdcb)
889 {
890     SERIAL_BAUD_RATE    sbr;
891     SERIAL_LINE_CONTROL slc;
892     SERIAL_HANDFLOW     shf;
893     SERIAL_CHARS        sc;
894
895     TRACE("handle %p, ptr %p\n", handle, lpdcb);
896
897     if (!lpdcb)
898     {
899         SetLastError(ERROR_INVALID_PARAMETER);
900         return FALSE;
901     }
902     
903     if (!DeviceIoControl(handle, IOCTL_SERIAL_GET_BAUD_RATE,
904                          NULL, 0, &sbr, sizeof(sbr), NULL, NULL) ||
905         !DeviceIoControl(handle, IOCTL_SERIAL_GET_LINE_CONTROL,
906                          NULL, 0, &slc, sizeof(slc), NULL, NULL) ||
907         !DeviceIoControl(handle, IOCTL_SERIAL_GET_HANDFLOW,
908                          NULL, 0, &shf, sizeof(shf), NULL, NULL) ||
909         !DeviceIoControl(handle, IOCTL_SERIAL_GET_CHARS,
910                          NULL, 0, &sc, sizeof(sc), NULL, NULL))
911         return FALSE;
912
913     memset(lpdcb, 0, sizeof(*lpdcb));
914     lpdcb->DCBlength = sizeof(*lpdcb);
915
916     /* yes, they seem no never be (re)set on NT */
917     lpdcb->fBinary = 1;
918     lpdcb->fParity = 0;
919
920     lpdcb->BaudRate = sbr.BaudRate;
921
922     lpdcb->StopBits = slc.StopBits;
923     lpdcb->Parity = slc.Parity;
924     lpdcb->ByteSize = slc.WordLength;
925
926     if (shf.ControlHandShake & SERIAL_CTS_HANDSHAKE)    lpdcb->fOutxCtsFlow = 1;
927     if (shf.ControlHandShake & SERIAL_DSR_HANDSHAKE)    lpdcb->fOutxDsrFlow = 1;
928     switch (shf.ControlHandShake & (SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE))
929     {
930     case 0:                     lpdcb->fDtrControl = DTR_CONTROL_DISABLE; break;
931     case SERIAL_DTR_CONTROL:    lpdcb->fDtrControl = DTR_CONTROL_ENABLE; break;
932     case SERIAL_DTR_HANDSHAKE:  lpdcb->fDtrControl = DTR_CONTROL_HANDSHAKE; break;
933     }
934     switch (shf.FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE))
935     {
936     case 0:                     lpdcb->fRtsControl = RTS_CONTROL_DISABLE; break;
937     case SERIAL_RTS_CONTROL:    lpdcb->fRtsControl = RTS_CONTROL_ENABLE; break;
938     case SERIAL_RTS_HANDSHAKE:  lpdcb->fRtsControl = RTS_CONTROL_HANDSHAKE; break;
939     case SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE:
940                                 lpdcb->fRtsControl = RTS_CONTROL_TOGGLE; break;
941     }
942     if (shf.ControlHandShake & SERIAL_DSR_SENSITIVITY)  lpdcb->fDsrSensitivity = 1;
943     if (shf.ControlHandShake & SERIAL_ERROR_ABORT)      lpdcb->fAbortOnError = 1;
944     if (shf.FlowReplace & SERIAL_ERROR_CHAR)            lpdcb->fErrorChar = 1;
945     if (shf.FlowReplace & SERIAL_NULL_STRIPPING)        lpdcb->fNull = 1;
946     if (shf.FlowReplace & SERIAL_XOFF_CONTINUE)         lpdcb->fTXContinueOnXoff = 1;
947     lpdcb->XonLim = shf.XonLimit;
948     lpdcb->XoffLim = shf.XoffLimit;
949
950     if (shf.FlowReplace & SERIAL_AUTO_TRANSMIT) lpdcb->fOutX = 1;
951     if (shf.FlowReplace & SERIAL_AUTO_RECEIVE)  lpdcb->fInX = 1;
952
953     lpdcb->EofChar = sc.EofChar;
954     lpdcb->ErrorChar = sc.ErrorChar;
955     lpdcb->EvtChar = sc.EventChar;
956     lpdcb->XonChar = sc.XonChar;
957     lpdcb->XoffChar = sc.XoffChar;
958
959     TRACE("OK\n");
960     dump_dcb(lpdcb);
961
962     return TRUE;
963 }
964
965 /*****************************************************************************
966  *      TransmitCommChar        (KERNEL32.@)
967  *
968  *  Transmits a single character in front of any pending characters in the
969  *  output buffer.  Usually used to send an interrupt character to a host.
970  *
971  * PARAMS
972  *      hComm           [in]    The communication device in need of a command character
973  *      chTransmit      [in]    The character to transmit
974  *
975  * RETURNS
976  *
977  *  True if the call succeeded, false if the previous command character to the
978  *  same device has not been sent yet the handle is bad etc.
979  *
980  */
981 BOOL WINAPI TransmitCommChar(HANDLE hComm, CHAR chTransmit)
982 {
983     return DeviceIoControl(hComm, IOCTL_SERIAL_IMMEDIATE_CHAR,
984                            &chTransmit, sizeof(chTransmit), NULL, 0, NULL, NULL);
985 }
986
987
988 /*****************************************************************************
989  *      GetCommTimeouts         (KERNEL32.@)
990  *
991  *  Obtains the request timeout values for the communications device.
992  *
993  * PARAMS
994  *      hComm           [in]    The communications device
995  *      lptimeouts      [out]   The struct of request timeouts
996  *
997  * RETURNS
998  *
999  *  True on success, false if communications device handle is bad
1000  *  or the target structure is null.
1001  */
1002 BOOL WINAPI GetCommTimeouts(HANDLE hComm, LPCOMMTIMEOUTS lptimeouts)
1003 {
1004     SERIAL_TIMEOUTS     st;
1005
1006     TRACE("(%p, %p)\n", hComm, lptimeouts);
1007     if (!lptimeouts)
1008     {
1009         SetLastError(ERROR_INVALID_PARAMETER);
1010         return FALSE;
1011     }
1012     if (!DeviceIoControl(hComm, IOCTL_SERIAL_GET_TIMEOUTS,
1013                          NULL, 0, &st, sizeof(st), NULL, NULL))
1014         return FALSE;
1015     lptimeouts->ReadIntervalTimeout         = st.ReadIntervalTimeout;
1016     lptimeouts->ReadTotalTimeoutMultiplier  = st.ReadTotalTimeoutMultiplier;
1017     lptimeouts->ReadTotalTimeoutConstant    = st.ReadTotalTimeoutConstant;
1018     lptimeouts->WriteTotalTimeoutMultiplier = st.WriteTotalTimeoutMultiplier;
1019     lptimeouts->WriteTotalTimeoutConstant   = st.WriteTotalTimeoutConstant;
1020     return TRUE;
1021 }
1022
1023 /*****************************************************************************
1024  *      SetCommTimeouts         (KERNEL32.@)
1025  *
1026  * Sets the timeouts used when reading and writing data to/from COMM ports.
1027  *
1028  * PARAMS
1029  *      hComm           [in]    handle of COMM device
1030  *      lptimeouts      [in]    pointer to COMMTIMEOUTS structure
1031  *
1032  * ReadIntervalTimeout
1033  *     - converted and passes to linux kernel as c_cc[VTIME]
1034  * ReadTotalTimeoutMultiplier, ReadTotalTimeoutConstant
1035  *     - used in ReadFile to calculate GetOverlappedResult's timeout
1036  * WriteTotalTimeoutMultiplier, WriteTotalTimeoutConstant
1037  *     - used in WriteFile to calculate GetOverlappedResult's timeout
1038  *
1039  * RETURNS
1040  *
1041  *  True if the timeouts were set, false otherwise.
1042  */
1043 BOOL WINAPI SetCommTimeouts(HANDLE hComm, LPCOMMTIMEOUTS lptimeouts)
1044 {
1045     SERIAL_TIMEOUTS     st;
1046
1047     TRACE("(%p, %p)\n", hComm, lptimeouts);
1048
1049     if (lptimeouts == NULL)
1050     {
1051         SetLastError(ERROR_INVALID_PARAMETER);
1052         return FALSE;
1053     }
1054     st.ReadIntervalTimeout         = lptimeouts->ReadIntervalTimeout;
1055     st.ReadTotalTimeoutMultiplier  = lptimeouts->ReadTotalTimeoutMultiplier;
1056     st.ReadTotalTimeoutConstant    = lptimeouts->ReadTotalTimeoutConstant;
1057     st.WriteTotalTimeoutMultiplier = lptimeouts->WriteTotalTimeoutMultiplier;
1058     st.WriteTotalTimeoutConstant   = lptimeouts->WriteTotalTimeoutConstant;
1059  
1060     return DeviceIoControl(hComm, IOCTL_SERIAL_SET_TIMEOUTS,
1061                            &st, sizeof(st), NULL, 0, NULL, NULL);
1062 }
1063
1064 /***********************************************************************
1065  *           GetCommModemStatus   (KERNEL32.@)
1066  *
1067  *  Obtains the four control register bits if supported by the hardware.
1068  *
1069  * PARAMS
1070  *
1071  *      hFile           [in]    The communications device
1072  *      lpModemStat     [out]   The control register bits
1073  *
1074  * RETURNS
1075  *
1076  *  True if the communications handle was good and for hardware that
1077  *  control register access, false otherwise.
1078  */
1079 BOOL WINAPI GetCommModemStatus(HANDLE hFile, LPDWORD lpModemStat)
1080 {
1081     return DeviceIoControl(hFile, IOCTL_SERIAL_GET_MODEMSTATUS,
1082                            NULL, 0, lpModemStat, sizeof(DWORD), NULL, NULL);
1083 }
1084
1085 /***********************************************************************
1086  *           WaitCommEvent   (KERNEL32.@)
1087  *
1088  * Wait until something interesting happens on a COMM port.
1089  * Interesting things (events) are set by calling SetCommMask before
1090  * this function is called.
1091  *
1092  * RETURNS
1093  *   TRUE if successful
1094  *   FALSE if failure
1095  *
1096  *   The set of detected events will be written to *lpdwEventMask
1097  *   ERROR_IO_PENDING will be returned the overlapped structure was passed
1098  *
1099  * BUGS:
1100  *  Only supports EV_RXCHAR and EV_TXEMPTY
1101  */
1102 BOOL WINAPI WaitCommEvent(
1103     HANDLE hFile,              /* [in] handle of comm port to wait for */
1104     LPDWORD lpdwEvents,        /* [out] event(s) that were detected */
1105     LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
1106 {
1107     return DeviceIoControl(hFile, IOCTL_SERIAL_WAIT_ON_MASK, NULL, 0,
1108                            lpdwEvents, sizeof(DWORD), NULL, lpOverlapped);
1109 }
1110
1111 /***********************************************************************
1112  *           GetCommProperties   (KERNEL32.@)
1113  *
1114  * This function fills in a structure with the capabilities of the
1115  * communications port driver.
1116  *
1117  * RETURNS
1118  *
1119  *  TRUE on success, FALSE on failure
1120  *  If successful, the lpCommProp structure be filled in with
1121  *  properties of the comm port.
1122  */
1123 BOOL WINAPI GetCommProperties(
1124     HANDLE hFile,          /* [in] handle of the comm port */
1125     LPCOMMPROP lpCommProp) /* [out] pointer to struct to be filled */
1126 {
1127     FIXME("(%p %p )\n",hFile,lpCommProp);
1128     if(!lpCommProp)
1129         return FALSE;
1130
1131     /*
1132      * These values should be valid for LINUX's serial driver
1133      * FIXME: Perhaps they deserve an #ifdef LINUX
1134      */
1135     memset(lpCommProp,0,sizeof(COMMPROP));
1136     lpCommProp->wPacketLength       = 1;
1137     lpCommProp->wPacketVersion      = 1;
1138     lpCommProp->dwServiceMask       = SP_SERIALCOMM;
1139     lpCommProp->dwReserved1         = 0;
1140     lpCommProp->dwMaxTxQueue        = 4096;
1141     lpCommProp->dwMaxRxQueue        = 4096;
1142     lpCommProp->dwMaxBaud           = BAUD_115200;
1143     lpCommProp->dwProvSubType       = PST_RS232;
1144     lpCommProp->dwProvCapabilities  = PCF_DTRDSR | PCF_PARITY_CHECK | PCF_RTSCTS | PCF_TOTALTIMEOUTS;
1145     lpCommProp->dwSettableParams    = SP_BAUD | SP_DATABITS | SP_HANDSHAKING |
1146                                       SP_PARITY | SP_PARITY_CHECK | SP_STOPBITS ;
1147     lpCommProp->dwSettableBaud      = BAUD_075 | BAUD_110 | BAUD_134_5 | BAUD_150 |
1148                 BAUD_300 | BAUD_600 | BAUD_1200 | BAUD_1800 | BAUD_2400 | BAUD_4800 |
1149                 BAUD_9600 | BAUD_19200 | BAUD_38400 | BAUD_57600 | BAUD_115200 ;
1150     lpCommProp->wSettableData       = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8 ;
1151     lpCommProp->wSettableStopParity = STOPBITS_10 | STOPBITS_15 | STOPBITS_20 |
1152                 PARITY_NONE | PARITY_ODD |PARITY_EVEN | PARITY_MARK | PARITY_SPACE;
1153     lpCommProp->dwCurrentTxQueue    = lpCommProp->dwMaxTxQueue;
1154     lpCommProp->dwCurrentRxQueue    = lpCommProp->dwMaxRxQueue;
1155
1156     return TRUE;
1157 }
1158
1159 /***********************************************************************
1160  * FIXME:
1161  * The functionality of CommConfigDialogA, GetDefaultCommConfig and
1162  * SetDefaultCommConfig is implemented in a DLL (usually SERIALUI.DLL).
1163  * This is dependent on the type of COMM port, but since it is doubtful
1164  * anybody will get around to implementing support for fancy serial
1165  * ports in WINE, this is hardcoded for the time being.  The name of
1166  * this DLL should be stored in and read from the system registry in
1167  * the hive HKEY_LOCAL_MACHINE, key
1168  * System\\CurrentControlSet\\Services\\Class\\Ports\\????
1169  * where ???? is the port number... that is determined by PNP
1170  * The DLL should be loaded when the COMM port is opened, and closed
1171  * when the COMM port is closed. - MJM 20 June 2000
1172  ***********************************************************************/
1173 static const WCHAR lpszSerialUI[] = { 
1174    's','e','r','i','a','l','u','i','.','d','l','l',0 };
1175
1176
1177 /***********************************************************************
1178  *           CommConfigDialogA   (KERNEL32.@)
1179  *
1180  * Raises a dialog that allows the user to configure a comm port.
1181  * Fills the COMMCONFIG struct with information specified by the user.
1182  * This function should call a similar routine in the COMM driver...
1183  *
1184  * RETURNS
1185  *
1186  *  TRUE on success, FALSE on failure
1187  *  If successful, the lpCommConfig structure will contain a new
1188  *  configuration for the comm port, as specified by the user.
1189  *
1190  * BUGS
1191  *  The library with the CommConfigDialog code is never unloaded.
1192  * Perhaps this should be done when the comm port is closed?
1193  */
1194 BOOL WINAPI CommConfigDialogA(
1195     LPCSTR lpszDevice,         /* [in] name of communications device */
1196     HWND hWnd,                 /* [in] parent window for the dialog */
1197     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
1198 {
1199     LPWSTR  lpDeviceW = NULL;
1200     DWORD   len;
1201     BOOL    r;
1202
1203     TRACE("(%s, %p, %p)\n", debugstr_a(lpszDevice), hWnd, lpCommConfig);
1204
1205     if (lpszDevice)
1206     {
1207         len = MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, NULL, 0 );
1208         lpDeviceW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1209         MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, lpDeviceW, len );
1210     }
1211     r = CommConfigDialogW(lpDeviceW, hWnd, lpCommConfig);
1212     HeapFree( GetProcessHeap(), 0, lpDeviceW );
1213     return r;
1214 }
1215
1216 /***********************************************************************
1217  *           CommConfigDialogW   (KERNEL32.@)
1218  *
1219  * See CommConfigDialogA.
1220  */
1221 BOOL WINAPI CommConfigDialogW(
1222     LPCWSTR lpszDevice,        /* [in] name of communications device */
1223     HWND hWnd,                 /* [in] parent window for the dialog */
1224     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
1225 {
1226     FARPROC pCommConfigDialog;
1227     HMODULE hConfigModule;
1228     DWORD   res = ERROR_INVALID_PARAMETER;
1229
1230     TRACE("(%s, %p, %p)\n", debugstr_w(lpszDevice), hWnd, lpCommConfig);
1231     hConfigModule = LoadLibraryW(lpszSerialUI);
1232
1233     if (hConfigModule) {
1234         pCommConfigDialog = GetProcAddress(hConfigModule, "drvCommConfigDialogW");
1235         if (pCommConfigDialog) {
1236             res = pCommConfigDialog(lpszDevice, hWnd, lpCommConfig);
1237         }
1238         FreeLibrary(hConfigModule);
1239     }
1240
1241     if (res) SetLastError(res);
1242     return (res == ERROR_SUCCESS);
1243 }
1244
1245 /***********************************************************************
1246  *           GetCommConfig     (KERNEL32.@)
1247  *
1248  * Fill in the COMMCONFIG structure for the comm port hFile
1249  *
1250  * RETURNS
1251  *
1252  *  TRUE on success, FALSE on failure
1253  *  If successful, lpCommConfig contains the comm port configuration.
1254  *
1255  * BUGS
1256  *
1257  */
1258 BOOL WINAPI GetCommConfig(
1259     HANDLE       hFile,        /* [in] The communications device. */
1260     LPCOMMCONFIG lpCommConfig, /* [out] The communications configuration of the device (if it fits). */
1261     LPDWORD      lpdwSize)     /* [in/out] Initially the size of the configuration buffer/structure,
1262                                   afterwards the number of bytes copied to the buffer or
1263                                   the needed size of the buffer. */
1264 {
1265     BOOL r;
1266
1267     TRACE("(%p, %p, %p) *lpdwSize: %u\n", hFile, lpCommConfig, lpdwSize, lpdwSize ? *lpdwSize : 0 );
1268
1269     if(lpCommConfig == NULL)
1270         return FALSE;
1271     r = *lpdwSize < sizeof(COMMCONFIG); /* TRUE if not enough space */
1272     *lpdwSize = sizeof(COMMCONFIG);
1273     if(r)
1274         return FALSE;
1275
1276     lpCommConfig->dwSize = sizeof(COMMCONFIG);
1277     lpCommConfig->wVersion = 1;
1278     lpCommConfig->wReserved = 0;
1279     r = GetCommState(hFile,&lpCommConfig->dcb);
1280     lpCommConfig->dwProviderSubType = PST_RS232;
1281     lpCommConfig->dwProviderOffset = 0;
1282     lpCommConfig->dwProviderSize = 0;
1283
1284     return r;
1285 }
1286
1287 /***********************************************************************
1288  *           SetCommConfig     (KERNEL32.@)
1289  *
1290  *  Sets the configuration of the communications device.
1291  *
1292  * RETURNS
1293  *
1294  *  True on success, false if the handle was bad is not a communications device.
1295  */
1296 BOOL WINAPI SetCommConfig(
1297     HANDLE       hFile,         /* [in] The communications device. */
1298     LPCOMMCONFIG lpCommConfig,  /* [in] The desired configuration. */
1299     DWORD dwSize)               /* [in] size of the lpCommConfig struct */
1300 {
1301     TRACE("(%p, %p, %u)\n", hFile, lpCommConfig, dwSize);
1302     return SetCommState(hFile,&lpCommConfig->dcb);
1303 }
1304
1305 /***********************************************************************
1306  *           SetDefaultCommConfigW  (KERNEL32.@)
1307  *
1308  * Initializes the default configuration for a communication device.
1309  *
1310  * PARAMS
1311  *  lpszDevice   [I] Name of the device targeted for configuration
1312  *  lpCommConfig [I] PTR to a buffer with the configuration for the device
1313  *  dwSize       [I] Number of bytes in the buffer
1314  *
1315  * RETURNS
1316  *  Failure: FALSE
1317  *  Success: TRUE, and default configuration saved
1318  *
1319  */
1320 BOOL WINAPI SetDefaultCommConfigW(LPCWSTR lpszDevice, LPCOMMCONFIG lpCommConfig, DWORD dwSize)
1321 {
1322     FARPROC lpfnSetDefaultCommConfig;
1323     HMODULE hConfigModule;
1324     BOOL r = FALSE;
1325
1326     TRACE("(%s, %p, %u)\n", debugstr_w(lpszDevice), lpCommConfig, dwSize);
1327
1328     hConfigModule = LoadLibraryW(lpszSerialUI);
1329     if(!hConfigModule)
1330         return r;
1331
1332     lpfnSetDefaultCommConfig = GetProcAddress(hConfigModule, "drvSetDefaultCommConfigW");
1333     if (lpfnSetDefaultCommConfig)
1334         r = lpfnSetDefaultCommConfig(lpszDevice, lpCommConfig, dwSize);
1335
1336     FreeLibrary(hConfigModule);
1337
1338     return r;
1339 }
1340
1341
1342 /***********************************************************************
1343  *           SetDefaultCommConfigA     (KERNEL32.@)
1344  *
1345  * Initializes the default configuration for a communication device.
1346  *
1347  * See SetDefaultCommConfigW.
1348  *
1349  */
1350 BOOL WINAPI SetDefaultCommConfigA(LPCSTR lpszDevice, LPCOMMCONFIG lpCommConfig, DWORD dwSize)
1351 {
1352     BOOL r;
1353     LPWSTR lpDeviceW = NULL;
1354     DWORD len;
1355
1356     TRACE("(%s, %p, %u)\n", debugstr_a(lpszDevice), lpCommConfig, dwSize);
1357
1358     if (lpszDevice)
1359     {
1360         len = MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, NULL, 0 );
1361         lpDeviceW = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
1362         MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, lpDeviceW, len );
1363     }
1364     r = SetDefaultCommConfigW(lpDeviceW,lpCommConfig,dwSize);
1365     HeapFree( GetProcessHeap(), 0, lpDeviceW );
1366     return r;
1367 }
1368
1369
1370 /***********************************************************************
1371  *           GetDefaultCommConfigW   (KERNEL32.@)
1372  *
1373  *   Acquires the default configuration of the specified communication device. (unicode)
1374  *
1375  *  RETURNS
1376  *
1377  *   True on successful reading of the default configuration,
1378  *   if the device is not found or the buffer is too small.
1379  */
1380 BOOL WINAPI GetDefaultCommConfigW(
1381     LPCWSTR      lpszName, /* [in] The unicode name of the device targeted for configuration. */
1382     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
1383     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
1384                               afterwards the number of bytes copied to the buffer or
1385                               the needed size of the buffer. */
1386 {
1387     FARPROC pGetDefaultCommConfig;
1388     HMODULE hConfigModule;
1389     DWORD   res = ERROR_INVALID_PARAMETER;
1390
1391     TRACE("(%s, %p, %p)  *lpdwSize: %u\n", debugstr_w(lpszName), lpCC, lpdwSize, lpdwSize ? *lpdwSize : 0 );
1392     hConfigModule = LoadLibraryW(lpszSerialUI);
1393
1394     if (hConfigModule) {
1395         pGetDefaultCommConfig = GetProcAddress(hConfigModule, "drvGetDefaultCommConfigW");
1396         if (pGetDefaultCommConfig) {
1397             res = pGetDefaultCommConfig(lpszName, lpCC, lpdwSize);
1398         }
1399         FreeLibrary(hConfigModule);
1400     }
1401
1402     if (res) SetLastError(res);
1403     return (res == ERROR_SUCCESS);
1404 }
1405
1406 /**************************************************************************
1407  *         GetDefaultCommConfigA                (KERNEL32.@)
1408  *
1409  *   Acquires the default configuration of the specified communication device. (ascii)
1410  *
1411  *  RETURNS
1412  *
1413  *   True on successful reading of the default configuration,
1414  *   if the device is not found or the buffer is too small.
1415  */
1416 BOOL WINAPI GetDefaultCommConfigA(
1417     LPCSTR       lpszName, /* [in] The ascii name of the device targeted for configuration. */
1418     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
1419     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
1420                               afterwards the number of bytes copied to the buffer or
1421                               the needed size of the buffer. */
1422 {
1423         BOOL ret = FALSE;
1424         UNICODE_STRING lpszNameW;
1425
1426         TRACE("(%s, %p, %p)  *lpdwSize: %u\n", debugstr_a(lpszName), lpCC, lpdwSize, lpdwSize ? *lpdwSize : 0 );
1427         if(lpszName) RtlCreateUnicodeStringFromAsciiz(&lpszNameW,lpszName);
1428         else lpszNameW.Buffer = NULL;
1429
1430         ret = GetDefaultCommConfigW(lpszNameW.Buffer,lpCC,lpdwSize);
1431
1432         RtlFreeUnicodeString(&lpszNameW);
1433         return ret;
1434 }