msvcrt: Improved locale initialization.
[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     DWORD dwBytesReturned;
555     return DeviceIoControl(handle, IOCTL_SERIAL_SET_BREAK_ON, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
556 }
557
558 /*****************************************************************************
559  *      ClearCommBreak          (KERNEL32.@)
560  *
561  *  Resumes character transmission from a communication device.
562  *
563  * PARAMS
564  *
565  *      handle [in] The halted communication device whose character transmission is to be resumed
566  *
567  * RETURNS
568  *
569  *  True on success and false if the communications device could not be found.
570  *
571  * BUGS
572  *
573  *  Only TIOCSBRK and TIOCCBRK are supported.
574  */
575 BOOL WINAPI ClearCommBreak(HANDLE handle)
576 {
577     DWORD dwBytesReturned;
578     return DeviceIoControl(handle, IOCTL_SERIAL_SET_BREAK_OFF, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
579 }
580
581 /*****************************************************************************
582  *      EscapeCommFunction      (KERNEL32.@)
583  *
584  *  Directs a communication device to perform an extended function.
585  *
586  * PARAMS
587  *
588  *      handle          [in] The communication device to perform the extended function
589  *      nFunction       [in] The extended function to be performed
590  *
591  * RETURNS
592  *
593  *  True or requested data on successful completion of the command,
594  *  false if the device is not present cannot execute the command
595  *  or the command failed.
596  */
597 BOOL WINAPI EscapeCommFunction(HANDLE handle, UINT func)
598 {
599     DWORD       ioc;
600     DWORD dwBytesReturned;
601
602     switch (func)
603     {
604     case CLRDTR:        ioc = IOCTL_SERIAL_CLR_DTR;             break;
605     case CLRRTS:        ioc = IOCTL_SERIAL_CLR_RTS;             break;
606     case SETDTR:        ioc = IOCTL_SERIAL_SET_DTR;             break;
607     case SETRTS:        ioc = IOCTL_SERIAL_SET_RTS;             break;
608     case SETXOFF:       ioc = IOCTL_SERIAL_SET_XOFF;            break;
609     case SETXON:        ioc = IOCTL_SERIAL_SET_XON;             break;
610     case SETBREAK:      ioc = IOCTL_SERIAL_SET_BREAK_ON;        break;
611     case CLRBREAK:      ioc = IOCTL_SERIAL_SET_BREAK_OFF;       break;
612     case RESETDEV:      ioc = IOCTL_SERIAL_RESET_DEVICE;        break;
613     default:
614         ERR("Unknown function code (%u)\n", func);
615         SetLastError(ERROR_INVALID_PARAMETER);
616         return FALSE;
617     }
618     return DeviceIoControl(handle, ioc, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
619 }
620
621 /********************************************************************
622  *      PurgeComm        (KERNEL32.@)
623  *
624  *  Terminates pending operations and/or discards buffers on a
625  *  communication resource.
626  *
627  * PARAMS
628  *
629  *      handle  [in] The communication resource to be purged
630  *      flags   [in] Flags for clear pending/buffer on input/output
631  *
632  * RETURNS
633  *
634  *  True on success and false if the communications handle is bad.
635  */
636 BOOL WINAPI PurgeComm(HANDLE handle, DWORD flags)
637 {
638     DWORD dwBytesReturned;
639     return DeviceIoControl(handle, IOCTL_SERIAL_PURGE, &flags, sizeof(flags),
640                            NULL, 0, &dwBytesReturned, NULL);
641 }
642
643 /*****************************************************************************
644  *      ClearCommError  (KERNEL32.@)
645  *
646  *  Enables further I/O operations on a communications resource after
647  *  supplying error and current status information.
648  *
649  * PARAMS
650  *
651  *      handle  [in]    The communication resource with the error
652  *      errors  [out]   Flags indicating error the resource experienced
653  *      lpStat  [out] The status of the communication resource
654  * RETURNS
655  *
656  *  True on success, false if the communication resource handle is bad.
657  */
658 BOOL WINAPI ClearCommError(HANDLE handle, LPDWORD errors, LPCOMSTAT lpStat)
659 {
660     SERIAL_STATUS       ss;
661     DWORD dwBytesReturned;
662
663     if (!DeviceIoControl(handle, IOCTL_SERIAL_GET_COMMSTATUS, NULL, 0,
664                          &ss, sizeof(ss), &dwBytesReturned, NULL))
665         return FALSE;
666
667     if (errors)
668     {
669         *errors = 0;
670         if (ss.Errors & SERIAL_ERROR_BREAK)             *errors |= CE_BREAK;
671         if (ss.Errors & SERIAL_ERROR_FRAMING)           *errors |= CE_FRAME;
672         if (ss.Errors & SERIAL_ERROR_OVERRUN)           *errors |= CE_OVERRUN;
673         if (ss.Errors & SERIAL_ERROR_QUEUEOVERRUN)      *errors |= CE_RXOVER;
674         if (ss.Errors & SERIAL_ERROR_PARITY)            *errors |= CE_RXPARITY;
675     }
676  
677     if (lpStat)
678     {
679         memset(lpStat, 0, sizeof(*lpStat));
680
681         if (ss.HoldReasons & SERIAL_TX_WAITING_FOR_CTS)         lpStat->fCtsHold = TRUE;
682         if (ss.HoldReasons & SERIAL_TX_WAITING_FOR_DSR)         lpStat->fDsrHold = TRUE;
683         if (ss.HoldReasons & SERIAL_TX_WAITING_FOR_DCD)         lpStat->fRlsdHold = TRUE;
684         if (ss.HoldReasons & SERIAL_TX_WAITING_FOR_XON)         lpStat->fXoffHold = TRUE;
685         if (ss.HoldReasons & SERIAL_TX_WAITING_XOFF_SENT)       lpStat->fXoffSent = TRUE;
686         if (ss.EofReceived)                                     lpStat->fEof = TRUE;
687         if (ss.WaitForImmediate)                                lpStat->fTxim = TRUE;
688         lpStat->cbInQue = ss.AmountInInQueue;
689         lpStat->cbOutQue = ss.AmountInOutQueue;
690     }
691     return TRUE;
692 }
693
694 /*****************************************************************************
695  *      SetupComm       (KERNEL32.@)
696  *
697  *  Called after CreateFile to hint to the communication resource to use
698  *  specified sizes for input and output buffers rather than the default values.
699  *
700  * PARAMS
701  *      handle  [in]    The just created communication resource handle
702  *      insize  [in]    The suggested size of the communication resources input buffer in bytes
703  *      outsize [in]    The suggested size of the communication resources output buffer in bytes
704  *
705  * RETURNS
706  *
707  *  True if successful, false if the communications resource handle is bad.
708  *
709  * BUGS
710  *
711  *  Stub.
712  */
713 BOOL WINAPI SetupComm(HANDLE handle, DWORD insize, DWORD outsize)
714 {
715     SERIAL_QUEUE_SIZE   sqs;
716     DWORD dwBytesReturned;
717
718     sqs.InSize = insize;
719     sqs.OutSize = outsize;
720     return DeviceIoControl(handle, IOCTL_SERIAL_SET_QUEUE_SIZE,
721                            &sqs, sizeof(sqs), NULL, 0, &dwBytesReturned, NULL);
722 }
723
724 /*****************************************************************************
725  *      GetCommMask     (KERNEL32.@)
726  *
727  *  Obtain the events associated with a communication device that will cause
728  *  a call WaitCommEvent to return.
729  *
730  *  PARAMS
731  *
732  *      handle  [in]    The communications device
733  *      evtmask [out]   The events which cause WaitCommEvent to return
734  *
735  *  RETURNS
736  *
737  *   True on success, fail on bad device handle etc.
738  */
739 BOOL WINAPI GetCommMask(HANDLE handle, LPDWORD evtmask)
740 {
741     DWORD dwBytesReturned;
742     TRACE("handle %p, mask %p\n", handle, evtmask);
743     return DeviceIoControl(handle, IOCTL_SERIAL_GET_WAIT_MASK,
744                            NULL, 0, evtmask, sizeof(*evtmask), &dwBytesReturned, NULL);
745 }
746
747 /*****************************************************************************
748  *      SetCommMask     (KERNEL32.@)
749  *
750  *  There be some things we need to hear about yon there communications device.
751  *  (Set which events associated with a communication device should cause
752  *  a call WaitCommEvent to return.)
753  *
754  * PARAMS
755  *
756  *      handle  [in]    The communications device
757  *      evtmask [in]    The events that are to be monitored
758  *
759  * RETURNS
760  *
761  *  True on success, false on bad handle etc.
762  */
763 BOOL WINAPI SetCommMask(HANDLE handle, DWORD evtmask)
764 {
765     DWORD dwBytesReturned;
766     TRACE("handle %p, mask %x\n", handle, evtmask);
767     return DeviceIoControl(handle, IOCTL_SERIAL_SET_WAIT_MASK,
768                            &evtmask, sizeof(evtmask), NULL, 0, &dwBytesReturned, NULL);
769 }
770
771 static void dump_dcb(const DCB* lpdcb)
772 {
773     TRACE("bytesize=%d baudrate=%d fParity=%d Parity=%d stopbits=%d\n",
774           lpdcb->ByteSize, lpdcb->BaudRate, lpdcb->fParity, lpdcb->Parity,
775           (lpdcb->StopBits == ONESTOPBIT) ? 1 :
776           (lpdcb->StopBits == TWOSTOPBITS) ? 2 : 0);
777     TRACE("%sIXON %sIXOFF\n", (lpdcb->fOutX) ? "" : "~", (lpdcb->fInX) ? "" : "~");
778     TRACE("fOutxCtsFlow=%d fRtsControl=%d\n", lpdcb->fOutxCtsFlow, lpdcb->fRtsControl);
779     TRACE("fOutxDsrFlow=%d fDtrControl=%d\n", lpdcb->fOutxDsrFlow, lpdcb->fDtrControl);
780     if (lpdcb->fOutxCtsFlow || lpdcb->fRtsControl == RTS_CONTROL_HANDSHAKE)
781         TRACE("CRTSCTS\n");
782     else
783         TRACE("~CRTSCTS\n");
784 }
785
786 /*****************************************************************************
787  *      SetCommState    (KERNEL32.@)
788  *
789  *  Re-initializes all hardware and control settings of a communications device,
790  *  with values from a device control block without affecting the input and output
791  *  queues.
792  *
793  * PARAMS
794  *
795  *      handle  [in]    The communications device
796  *      lpdcb   [out]   The device control block
797  *
798  * RETURNS
799  *
800  *  True on success, false on failure, e.g., if the XonChar is equal to the XoffChar.
801  */
802 BOOL WINAPI SetCommState( HANDLE handle, LPDCB lpdcb)
803 {
804     SERIAL_BAUD_RATE           sbr;
805     SERIAL_LINE_CONTROL        slc;
806     SERIAL_HANDFLOW            shf;
807     SERIAL_CHARS               sc;
808     DWORD dwBytesReturned;
809
810     if (lpdcb == NULL)
811     {
812         SetLastError(ERROR_INVALID_PARAMETER);
813         return FALSE;
814     }
815     dump_dcb(lpdcb);
816
817     sbr.BaudRate = lpdcb->BaudRate;
818              
819     slc.StopBits = lpdcb->StopBits;
820     slc.Parity = lpdcb->Parity;
821     slc.WordLength = lpdcb->ByteSize;
822
823     shf.ControlHandShake = 0;
824     shf.FlowReplace = 0;
825     if (lpdcb->fOutxCtsFlow)      shf.ControlHandShake |= SERIAL_CTS_HANDSHAKE;
826     if (lpdcb->fOutxDsrFlow)      shf.ControlHandShake |= SERIAL_DSR_HANDSHAKE;
827     switch (lpdcb->fDtrControl)
828     {
829     case DTR_CONTROL_DISABLE:                                                  break;
830     case DTR_CONTROL_ENABLE:      shf.ControlHandShake |= SERIAL_DTR_CONTROL;  break;
831     case DTR_CONTROL_HANDSHAKE:   shf.ControlHandShake |= SERIAL_DTR_HANDSHAKE;break;
832     default:
833         SetLastError(ERROR_INVALID_PARAMETER);
834         return FALSE;
835     }
836     switch (lpdcb->fRtsControl)
837     {
838     case RTS_CONTROL_DISABLE:                                                  break;
839     case RTS_CONTROL_ENABLE:      shf.FlowReplace |= SERIAL_RTS_CONTROL;       break;
840     case RTS_CONTROL_HANDSHAKE:   shf.FlowReplace |= SERIAL_RTS_HANDSHAKE;     break;
841     case RTS_CONTROL_TOGGLE:      shf.FlowReplace |= SERIAL_RTS_CONTROL | 
842                                                      SERIAL_RTS_HANDSHAKE;     break;
843     default:
844         SetLastError(ERROR_INVALID_PARAMETER);
845         return FALSE;
846     }
847     if (lpdcb->fDsrSensitivity)   shf.ControlHandShake |= SERIAL_DSR_SENSITIVITY;
848     if (lpdcb->fAbortOnError)     shf.ControlHandShake |= SERIAL_ERROR_ABORT;
849
850     if (lpdcb->fErrorChar)        shf.FlowReplace |= SERIAL_ERROR_CHAR;
851     if (lpdcb->fNull)             shf.FlowReplace |= SERIAL_NULL_STRIPPING;
852     if (lpdcb->fTXContinueOnXoff) shf.FlowReplace |= SERIAL_XOFF_CONTINUE;
853     if (lpdcb->fOutX)             shf.FlowReplace |= SERIAL_AUTO_TRANSMIT;
854     if (lpdcb->fInX)              shf.FlowReplace |= SERIAL_AUTO_RECEIVE;
855
856     shf.XonLimit = lpdcb->XonLim;
857     shf.XoffLimit = lpdcb->XoffLim;
858
859     sc.EofChar = lpdcb->EofChar;
860     sc.ErrorChar = lpdcb->ErrorChar;
861     sc.BreakChar = 0;
862     sc.EventChar = lpdcb->EvtChar;
863     sc.XonChar = lpdcb->XonChar;
864     sc.XoffChar = lpdcb->XoffChar;
865
866     /* note: change DTR/RTS lines after setting the comm attributes,
867      * so flow control does not interfere.
868      */
869     return (DeviceIoControl(handle, IOCTL_SERIAL_SET_BAUD_RATE,
870                             &sbr, sizeof(sbr), NULL, 0, &dwBytesReturned, NULL) &&
871             DeviceIoControl(handle, IOCTL_SERIAL_SET_LINE_CONTROL,
872                             &slc, sizeof(slc), NULL, 0, &dwBytesReturned, NULL) &&
873             DeviceIoControl(handle, IOCTL_SERIAL_SET_HANDFLOW,
874                             &shf, sizeof(shf), NULL, 0, &dwBytesReturned, NULL) &&
875             DeviceIoControl(handle, IOCTL_SERIAL_SET_CHARS,
876                             &sc, sizeof(sc), NULL, 0, &dwBytesReturned, NULL));
877 }
878
879
880 /*****************************************************************************
881  *      GetCommState    (KERNEL32.@)
882  *
883  *  Fills in a device control block with information from a communications device.
884  *
885  * PARAMS
886  *      handle          [in]    The communications device
887  *      lpdcb           [out]   The device control block
888  *
889  * RETURNS
890  *
891  *  True on success, false if the communication device handle is bad etc
892  *
893  * BUGS
894  *
895  *  XonChar and XoffChar are not set.
896  */
897 BOOL WINAPI GetCommState(HANDLE handle, LPDCB lpdcb)
898 {
899     SERIAL_BAUD_RATE    sbr;
900     SERIAL_LINE_CONTROL slc;
901     SERIAL_HANDFLOW     shf;
902     SERIAL_CHARS        sc;
903     DWORD dwBytesReturned;
904
905     TRACE("handle %p, ptr %p\n", handle, lpdcb);
906
907     if (!lpdcb)
908     {
909         SetLastError(ERROR_INVALID_PARAMETER);
910         return FALSE;
911     }
912     
913     if (!DeviceIoControl(handle, IOCTL_SERIAL_GET_BAUD_RATE,
914                          NULL, 0, &sbr, sizeof(sbr), &dwBytesReturned, NULL) ||
915         !DeviceIoControl(handle, IOCTL_SERIAL_GET_LINE_CONTROL,
916                          NULL, 0, &slc, sizeof(slc), &dwBytesReturned, NULL) ||
917         !DeviceIoControl(handle, IOCTL_SERIAL_GET_HANDFLOW,
918                          NULL, 0, &shf, sizeof(shf), &dwBytesReturned, NULL) ||
919         !DeviceIoControl(handle, IOCTL_SERIAL_GET_CHARS,
920                          NULL, 0, &sc, sizeof(sc), &dwBytesReturned, NULL))
921         return FALSE;
922
923     memset(lpdcb, 0, sizeof(*lpdcb));
924     lpdcb->DCBlength = sizeof(*lpdcb);
925
926     /* yes, they seem no never be (re)set on NT */
927     lpdcb->fBinary = 1;
928     lpdcb->fParity = 0;
929
930     lpdcb->BaudRate = sbr.BaudRate;
931
932     lpdcb->StopBits = slc.StopBits;
933     lpdcb->Parity = slc.Parity;
934     lpdcb->ByteSize = slc.WordLength;
935
936     if (shf.ControlHandShake & SERIAL_CTS_HANDSHAKE)    lpdcb->fOutxCtsFlow = 1;
937     if (shf.ControlHandShake & SERIAL_DSR_HANDSHAKE)    lpdcb->fOutxDsrFlow = 1;
938     switch (shf.ControlHandShake & (SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE))
939     {
940     case 0:                     lpdcb->fDtrControl = DTR_CONTROL_DISABLE; break;
941     case SERIAL_DTR_CONTROL:    lpdcb->fDtrControl = DTR_CONTROL_ENABLE; break;
942     case SERIAL_DTR_HANDSHAKE:  lpdcb->fDtrControl = DTR_CONTROL_HANDSHAKE; break;
943     }
944     switch (shf.FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE))
945     {
946     case 0:                     lpdcb->fRtsControl = RTS_CONTROL_DISABLE; break;
947     case SERIAL_RTS_CONTROL:    lpdcb->fRtsControl = RTS_CONTROL_ENABLE; break;
948     case SERIAL_RTS_HANDSHAKE:  lpdcb->fRtsControl = RTS_CONTROL_HANDSHAKE; break;
949     case SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE:
950                                 lpdcb->fRtsControl = RTS_CONTROL_TOGGLE; break;
951     }
952     if (shf.ControlHandShake & SERIAL_DSR_SENSITIVITY)  lpdcb->fDsrSensitivity = 1;
953     if (shf.ControlHandShake & SERIAL_ERROR_ABORT)      lpdcb->fAbortOnError = 1;
954     if (shf.FlowReplace & SERIAL_ERROR_CHAR)            lpdcb->fErrorChar = 1;
955     if (shf.FlowReplace & SERIAL_NULL_STRIPPING)        lpdcb->fNull = 1;
956     if (shf.FlowReplace & SERIAL_XOFF_CONTINUE)         lpdcb->fTXContinueOnXoff = 1;
957     lpdcb->XonLim = shf.XonLimit;
958     lpdcb->XoffLim = shf.XoffLimit;
959
960     if (shf.FlowReplace & SERIAL_AUTO_TRANSMIT) lpdcb->fOutX = 1;
961     if (shf.FlowReplace & SERIAL_AUTO_RECEIVE)  lpdcb->fInX = 1;
962
963     lpdcb->EofChar = sc.EofChar;
964     lpdcb->ErrorChar = sc.ErrorChar;
965     lpdcb->EvtChar = sc.EventChar;
966     lpdcb->XonChar = sc.XonChar;
967     lpdcb->XoffChar = sc.XoffChar;
968
969     TRACE("OK\n");
970     dump_dcb(lpdcb);
971
972     return TRUE;
973 }
974
975 /*****************************************************************************
976  *      TransmitCommChar        (KERNEL32.@)
977  *
978  *  Transmits a single character in front of any pending characters in the
979  *  output buffer.  Usually used to send an interrupt character to a host.
980  *
981  * PARAMS
982  *      hComm           [in]    The communication device in need of a command character
983  *      chTransmit      [in]    The character to transmit
984  *
985  * RETURNS
986  *
987  *  True if the call succeeded, false if the previous command character to the
988  *  same device has not been sent yet the handle is bad etc.
989  *
990  */
991 BOOL WINAPI TransmitCommChar(HANDLE hComm, CHAR chTransmit)
992 {
993     DWORD dwBytesReturned;
994     return DeviceIoControl(hComm, IOCTL_SERIAL_IMMEDIATE_CHAR,
995                            &chTransmit, sizeof(chTransmit), NULL, 0, &dwBytesReturned, NULL);
996 }
997
998
999 /*****************************************************************************
1000  *      GetCommTimeouts         (KERNEL32.@)
1001  *
1002  *  Obtains the request timeout values for the communications device.
1003  *
1004  * PARAMS
1005  *      hComm           [in]    The communications device
1006  *      lptimeouts      [out]   The struct of request timeouts
1007  *
1008  * RETURNS
1009  *
1010  *  True on success, false if communications device handle is bad
1011  *  or the target structure is null.
1012  */
1013 BOOL WINAPI GetCommTimeouts(HANDLE hComm, LPCOMMTIMEOUTS lptimeouts)
1014 {
1015     SERIAL_TIMEOUTS     st;
1016     DWORD dwBytesReturned;
1017
1018     TRACE("(%p, %p)\n", hComm, lptimeouts);
1019     if (!lptimeouts)
1020     {
1021         SetLastError(ERROR_INVALID_PARAMETER);
1022         return FALSE;
1023     }
1024     if (!DeviceIoControl(hComm, IOCTL_SERIAL_GET_TIMEOUTS,
1025                          NULL, 0, &st, sizeof(st), &dwBytesReturned, NULL))
1026         return FALSE;
1027     lptimeouts->ReadIntervalTimeout         = st.ReadIntervalTimeout;
1028     lptimeouts->ReadTotalTimeoutMultiplier  = st.ReadTotalTimeoutMultiplier;
1029     lptimeouts->ReadTotalTimeoutConstant    = st.ReadTotalTimeoutConstant;
1030     lptimeouts->WriteTotalTimeoutMultiplier = st.WriteTotalTimeoutMultiplier;
1031     lptimeouts->WriteTotalTimeoutConstant   = st.WriteTotalTimeoutConstant;
1032     return TRUE;
1033 }
1034
1035 /*****************************************************************************
1036  *      SetCommTimeouts         (KERNEL32.@)
1037  *
1038  * Sets the timeouts used when reading and writing data to/from COMM ports.
1039  *
1040  * PARAMS
1041  *      hComm           [in]    handle of COMM device
1042  *      lptimeouts      [in]    pointer to COMMTIMEOUTS structure
1043  *
1044  * ReadIntervalTimeout
1045  *     - converted and passes to linux kernel as c_cc[VTIME]
1046  * ReadTotalTimeoutMultiplier, ReadTotalTimeoutConstant
1047  *     - used in ReadFile to calculate GetOverlappedResult's timeout
1048  * WriteTotalTimeoutMultiplier, WriteTotalTimeoutConstant
1049  *     - used in WriteFile to calculate GetOverlappedResult's timeout
1050  *
1051  * RETURNS
1052  *
1053  *  True if the timeouts were set, false otherwise.
1054  */
1055 BOOL WINAPI SetCommTimeouts(HANDLE hComm, LPCOMMTIMEOUTS lptimeouts)
1056 {
1057     SERIAL_TIMEOUTS     st;
1058     DWORD dwBytesReturned;
1059
1060     TRACE("(%p, %p)\n", hComm, lptimeouts);
1061
1062     if (lptimeouts == NULL)
1063     {
1064         SetLastError(ERROR_INVALID_PARAMETER);
1065         return FALSE;
1066     }
1067     st.ReadIntervalTimeout         = lptimeouts->ReadIntervalTimeout;
1068     st.ReadTotalTimeoutMultiplier  = lptimeouts->ReadTotalTimeoutMultiplier;
1069     st.ReadTotalTimeoutConstant    = lptimeouts->ReadTotalTimeoutConstant;
1070     st.WriteTotalTimeoutMultiplier = lptimeouts->WriteTotalTimeoutMultiplier;
1071     st.WriteTotalTimeoutConstant   = lptimeouts->WriteTotalTimeoutConstant;
1072  
1073     return DeviceIoControl(hComm, IOCTL_SERIAL_SET_TIMEOUTS,
1074                            &st, sizeof(st), NULL, 0, &dwBytesReturned, NULL);
1075 }
1076
1077 /***********************************************************************
1078  *           GetCommModemStatus   (KERNEL32.@)
1079  *
1080  *  Obtains the four control register bits if supported by the hardware.
1081  *
1082  * PARAMS
1083  *
1084  *      hFile           [in]    The communications device
1085  *      lpModemStat     [out]   The control register bits
1086  *
1087  * RETURNS
1088  *
1089  *  True if the communications handle was good and for hardware that
1090  *  control register access, false otherwise.
1091  */
1092 BOOL WINAPI GetCommModemStatus(HANDLE hFile, LPDWORD lpModemStat)
1093 {
1094     DWORD dwBytesReturned;
1095     return DeviceIoControl(hFile, IOCTL_SERIAL_GET_MODEMSTATUS,
1096                            NULL, 0, lpModemStat, sizeof(DWORD), &dwBytesReturned, NULL);
1097 }
1098
1099 /***********************************************************************
1100  *           WaitCommEvent   (KERNEL32.@)
1101  *
1102  * Wait until something interesting happens on a COMM port.
1103  * Interesting things (events) are set by calling SetCommMask before
1104  * this function is called.
1105  *
1106  * RETURNS
1107  *   TRUE if successful
1108  *   FALSE if failure
1109  *
1110  *   The set of detected events will be written to *lpdwEventMask
1111  *   ERROR_IO_PENDING will be returned the overlapped structure was passed
1112  *
1113  * BUGS:
1114  *  Only supports EV_RXCHAR and EV_TXEMPTY
1115  */
1116 BOOL WINAPI WaitCommEvent(
1117     HANDLE hFile,              /* [in] handle of comm port to wait for */
1118     LPDWORD lpdwEvents,        /* [out] event(s) that were detected */
1119     LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
1120 {
1121     return DeviceIoControl(hFile, IOCTL_SERIAL_WAIT_ON_MASK, NULL, 0,
1122                            lpdwEvents, sizeof(DWORD), NULL, lpOverlapped);
1123 }
1124
1125 /***********************************************************************
1126  *           GetCommProperties   (KERNEL32.@)
1127  *
1128  * This function fills in a structure with the capabilities of the
1129  * communications port driver.
1130  *
1131  * RETURNS
1132  *
1133  *  TRUE on success, FALSE on failure
1134  *  If successful, the lpCommProp structure be filled in with
1135  *  properties of the comm port.
1136  */
1137 BOOL WINAPI GetCommProperties(
1138     HANDLE hFile,          /* [in] handle of the comm port */
1139     LPCOMMPROP lpCommProp) /* [out] pointer to struct to be filled */
1140 {
1141     TRACE("(%p %p)\n",hFile,lpCommProp);
1142     if(!lpCommProp)
1143         return FALSE;
1144
1145     /*
1146      * These values should be valid for LINUX's serial driver
1147      * FIXME: Perhaps they deserve an #ifdef LINUX
1148      */
1149     memset(lpCommProp,0,sizeof(COMMPROP));
1150     lpCommProp->wPacketLength       = 1;
1151     lpCommProp->wPacketVersion      = 1;
1152     lpCommProp->dwServiceMask       = SP_SERIALCOMM;
1153     lpCommProp->dwMaxTxQueue        = 4096;
1154     lpCommProp->dwMaxRxQueue        = 4096;
1155     lpCommProp->dwMaxBaud           = BAUD_115200;
1156     lpCommProp->dwProvSubType       = PST_RS232;
1157     lpCommProp->dwProvCapabilities  = PCF_DTRDSR | PCF_PARITY_CHECK | PCF_RTSCTS | PCF_TOTALTIMEOUTS;
1158     lpCommProp->dwSettableParams    = SP_BAUD | SP_DATABITS | SP_HANDSHAKING |
1159                                       SP_PARITY | SP_PARITY_CHECK | SP_STOPBITS ;
1160     lpCommProp->dwSettableBaud      = BAUD_075 | BAUD_110 | BAUD_134_5 | BAUD_150 |
1161                 BAUD_300 | BAUD_600 | BAUD_1200 | BAUD_1800 | BAUD_2400 | BAUD_4800 |
1162                 BAUD_9600 | BAUD_19200 | BAUD_38400 | BAUD_57600 | BAUD_115200 ;
1163     lpCommProp->wSettableData       = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8 ;
1164     lpCommProp->wSettableStopParity = STOPBITS_10 | STOPBITS_15 | STOPBITS_20 |
1165                 PARITY_NONE | PARITY_ODD |PARITY_EVEN | PARITY_MARK | PARITY_SPACE;
1166     lpCommProp->dwCurrentTxQueue    = lpCommProp->dwMaxTxQueue;
1167     lpCommProp->dwCurrentRxQueue    = lpCommProp->dwMaxRxQueue;
1168
1169     return TRUE;
1170 }
1171
1172 /***********************************************************************
1173  * FIXME:
1174  * The functionality of CommConfigDialogA, GetDefaultCommConfig and
1175  * SetDefaultCommConfig is implemented in a DLL (usually SERIALUI.DLL).
1176  * This is dependent on the type of COMM port, but since it is doubtful
1177  * anybody will get around to implementing support for fancy serial
1178  * ports in WINE, this is hardcoded for the time being.  The name of
1179  * this DLL should be stored in and read from the system registry in
1180  * the hive HKEY_LOCAL_MACHINE, key
1181  * System\\CurrentControlSet\\Services\\Class\\Ports\\????
1182  * where ???? is the port number... that is determined by PNP
1183  * The DLL should be loaded when the COMM port is opened, and closed
1184  * when the COMM port is closed. - MJM 20 June 2000
1185  ***********************************************************************/
1186 static const WCHAR lpszSerialUI[] = { 
1187    's','e','r','i','a','l','u','i','.','d','l','l',0 };
1188
1189
1190 /***********************************************************************
1191  *           CommConfigDialogA   (KERNEL32.@)
1192  *
1193  * Raises a dialog that allows the user to configure a comm port.
1194  * Fills the COMMCONFIG struct with information specified by the user.
1195  * This function should call a similar routine in the COMM driver...
1196  *
1197  * RETURNS
1198  *
1199  *  TRUE on success, FALSE on failure
1200  *  If successful, the lpCommConfig structure will contain a new
1201  *  configuration for the comm port, as specified by the user.
1202  *
1203  * BUGS
1204  *  The library with the CommConfigDialog code is never unloaded.
1205  * Perhaps this should be done when the comm port is closed?
1206  */
1207 BOOL WINAPI CommConfigDialogA(
1208     LPCSTR lpszDevice,         /* [in] name of communications device */
1209     HWND hWnd,                 /* [in] parent window for the dialog */
1210     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
1211 {
1212     LPWSTR  lpDeviceW = NULL;
1213     DWORD   len;
1214     BOOL    r;
1215
1216     TRACE("(%s, %p, %p)\n", debugstr_a(lpszDevice), hWnd, lpCommConfig);
1217
1218     if (lpszDevice)
1219     {
1220         len = MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, NULL, 0 );
1221         lpDeviceW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1222         MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, lpDeviceW, len );
1223     }
1224     r = CommConfigDialogW(lpDeviceW, hWnd, lpCommConfig);
1225     HeapFree( GetProcessHeap(), 0, lpDeviceW );
1226     return r;
1227 }
1228
1229 /***********************************************************************
1230  *           CommConfigDialogW   (KERNEL32.@)
1231  *
1232  * See CommConfigDialogA.
1233  */
1234 BOOL WINAPI CommConfigDialogW(
1235     LPCWSTR lpszDevice,        /* [in] name of communications device */
1236     HWND hWnd,                 /* [in] parent window for the dialog */
1237     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
1238 {
1239     DWORD (WINAPI *pCommConfigDialog)(LPCWSTR, HWND, LPCOMMCONFIG);
1240     HMODULE hConfigModule;
1241     DWORD   res = ERROR_INVALID_PARAMETER;
1242
1243     TRACE("(%s, %p, %p)\n", debugstr_w(lpszDevice), hWnd, lpCommConfig);
1244     hConfigModule = LoadLibraryW(lpszSerialUI);
1245
1246     if (hConfigModule) {
1247         pCommConfigDialog = (void *)GetProcAddress(hConfigModule, "drvCommConfigDialogW");
1248         if (pCommConfigDialog) {
1249             res = pCommConfigDialog(lpszDevice, hWnd, lpCommConfig);
1250         }
1251         FreeLibrary(hConfigModule);
1252     }
1253
1254     if (res) SetLastError(res);
1255     return (res == ERROR_SUCCESS);
1256 }
1257
1258 /***********************************************************************
1259  *           GetCommConfig     (KERNEL32.@)
1260  *
1261  * Fill in the COMMCONFIG structure for the comm port hFile
1262  *
1263  * RETURNS
1264  *
1265  *  TRUE on success, FALSE on failure
1266  *  If successful, lpCommConfig contains the comm port configuration.
1267  *
1268  * BUGS
1269  *
1270  */
1271 BOOL WINAPI GetCommConfig(
1272     HANDLE       hFile,        /* [in] The communications device. */
1273     LPCOMMCONFIG lpCommConfig, /* [out] The communications configuration of the device (if it fits). */
1274     LPDWORD      lpdwSize)     /* [in/out] Initially the size of the configuration buffer/structure,
1275                                   afterwards the number of bytes copied to the buffer or
1276                                   the needed size of the buffer. */
1277 {
1278     BOOL r;
1279
1280     TRACE("(%p, %p, %p) *lpdwSize: %u\n", hFile, lpCommConfig, lpdwSize, lpdwSize ? *lpdwSize : 0 );
1281
1282     if(lpCommConfig == NULL)
1283         return FALSE;
1284     r = *lpdwSize < sizeof(COMMCONFIG); /* TRUE if not enough space */
1285     *lpdwSize = sizeof(COMMCONFIG);
1286     if(r)
1287         return FALSE;
1288
1289     lpCommConfig->dwSize = sizeof(COMMCONFIG);
1290     lpCommConfig->wVersion = 1;
1291     lpCommConfig->wReserved = 0;
1292     r = GetCommState(hFile,&lpCommConfig->dcb);
1293     lpCommConfig->dwProviderSubType = PST_RS232;
1294     lpCommConfig->dwProviderOffset = 0;
1295     lpCommConfig->dwProviderSize = 0;
1296
1297     return r;
1298 }
1299
1300 /***********************************************************************
1301  *           SetCommConfig     (KERNEL32.@)
1302  *
1303  *  Sets the configuration of the communications device.
1304  *
1305  * RETURNS
1306  *
1307  *  True on success, false if the handle was bad is not a communications device.
1308  */
1309 BOOL WINAPI SetCommConfig(
1310     HANDLE       hFile,         /* [in] The communications device. */
1311     LPCOMMCONFIG lpCommConfig,  /* [in] The desired configuration. */
1312     DWORD dwSize)               /* [in] size of the lpCommConfig struct */
1313 {
1314     TRACE("(%p, %p, %u)\n", hFile, lpCommConfig, dwSize);
1315     return SetCommState(hFile,&lpCommConfig->dcb);
1316 }
1317
1318 /***********************************************************************
1319  *           SetDefaultCommConfigW  (KERNEL32.@)
1320  *
1321  * Initializes the default configuration for a communication device.
1322  *
1323  * PARAMS
1324  *  lpszDevice   [I] Name of the device targeted for configuration
1325  *  lpCommConfig [I] PTR to a buffer with the configuration for the device
1326  *  dwSize       [I] Number of bytes in the buffer
1327  *
1328  * RETURNS
1329  *  Failure: FALSE
1330  *  Success: TRUE, and default configuration saved
1331  *
1332  */
1333 BOOL WINAPI SetDefaultCommConfigW(LPCWSTR lpszDevice, LPCOMMCONFIG lpCommConfig, DWORD dwSize)
1334 {
1335     BOOL (WINAPI *lpfnSetDefaultCommConfig)(LPCWSTR, LPCOMMCONFIG, DWORD);
1336     HMODULE hConfigModule;
1337     BOOL r = FALSE;
1338
1339     TRACE("(%s, %p, %u)\n", debugstr_w(lpszDevice), lpCommConfig, dwSize);
1340
1341     hConfigModule = LoadLibraryW(lpszSerialUI);
1342     if(!hConfigModule)
1343         return r;
1344
1345     lpfnSetDefaultCommConfig = (void *)GetProcAddress(hConfigModule, "drvSetDefaultCommConfigW");
1346     if (lpfnSetDefaultCommConfig)
1347         r = lpfnSetDefaultCommConfig(lpszDevice, lpCommConfig, dwSize);
1348
1349     FreeLibrary(hConfigModule);
1350
1351     return r;
1352 }
1353
1354
1355 /***********************************************************************
1356  *           SetDefaultCommConfigA     (KERNEL32.@)
1357  *
1358  * Initializes the default configuration for a communication device.
1359  *
1360  * See SetDefaultCommConfigW.
1361  *
1362  */
1363 BOOL WINAPI SetDefaultCommConfigA(LPCSTR lpszDevice, LPCOMMCONFIG lpCommConfig, DWORD dwSize)
1364 {
1365     BOOL r;
1366     LPWSTR lpDeviceW = NULL;
1367     DWORD len;
1368
1369     TRACE("(%s, %p, %u)\n", debugstr_a(lpszDevice), lpCommConfig, dwSize);
1370
1371     if (lpszDevice)
1372     {
1373         len = MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, NULL, 0 );
1374         lpDeviceW = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
1375         MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, lpDeviceW, len );
1376     }
1377     r = SetDefaultCommConfigW(lpDeviceW,lpCommConfig,dwSize);
1378     HeapFree( GetProcessHeap(), 0, lpDeviceW );
1379     return r;
1380 }
1381
1382
1383 /***********************************************************************
1384  *           GetDefaultCommConfigW   (KERNEL32.@)
1385  *
1386  *   Acquires the default configuration of the specified communication device. (unicode)
1387  *
1388  *  RETURNS
1389  *
1390  *   True on successful reading of the default configuration,
1391  *   if the device is not found or the buffer is too small.
1392  */
1393 BOOL WINAPI GetDefaultCommConfigW(
1394     LPCWSTR      lpszName, /* [in] The unicode name of the device targeted for configuration. */
1395     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
1396     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
1397                               afterwards the number of bytes copied to the buffer or
1398                               the needed size of the buffer. */
1399 {
1400     DWORD (WINAPI *pGetDefaultCommConfig)(LPCWSTR, LPCOMMCONFIG, LPDWORD);
1401     HMODULE hConfigModule;
1402     DWORD   res = ERROR_INVALID_PARAMETER;
1403
1404     TRACE("(%s, %p, %p)  *lpdwSize: %u\n", debugstr_w(lpszName), lpCC, lpdwSize, lpdwSize ? *lpdwSize : 0 );
1405     hConfigModule = LoadLibraryW(lpszSerialUI);
1406
1407     if (hConfigModule) {
1408         pGetDefaultCommConfig = (void *)GetProcAddress(hConfigModule, "drvGetDefaultCommConfigW");
1409         if (pGetDefaultCommConfig) {
1410             res = pGetDefaultCommConfig(lpszName, lpCC, lpdwSize);
1411         }
1412         FreeLibrary(hConfigModule);
1413     }
1414
1415     if (res) SetLastError(res);
1416     return (res == ERROR_SUCCESS);
1417 }
1418
1419 /**************************************************************************
1420  *         GetDefaultCommConfigA                (KERNEL32.@)
1421  *
1422  *   Acquires the default configuration of the specified communication device. (ascii)
1423  *
1424  *  RETURNS
1425  *
1426  *   True on successful reading of the default configuration,
1427  *   if the device is not found or the buffer is too small.
1428  */
1429 BOOL WINAPI GetDefaultCommConfigA(
1430     LPCSTR       lpszName, /* [in] The ascii name of the device targeted for configuration. */
1431     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
1432     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
1433                               afterwards the number of bytes copied to the buffer or
1434                               the needed size of the buffer. */
1435 {
1436         BOOL ret = FALSE;
1437         UNICODE_STRING lpszNameW;
1438
1439         TRACE("(%s, %p, %p)  *lpdwSize: %u\n", debugstr_a(lpszName), lpCC, lpdwSize, lpdwSize ? *lpdwSize : 0 );
1440         if(lpszName) RtlCreateUnicodeStringFromAsciiz(&lpszNameW,lpszName);
1441         else lpszNameW.Buffer = NULL;
1442
1443         ret = GetDefaultCommConfigW(lpszNameW.Buffer,lpCC,lpdwSize);
1444
1445         RtlFreeUnicodeString(&lpszNameW);
1446         return ret;
1447 }