rpcrt4: Remove variable hr which is not really used from NdrInterfacePointerBufferSize.
[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->fInX) ? "" : "~", (lpdcb->fOutX) ? "" : "~");
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     FIXME("(%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->dwReserved1         = 0;
1154     lpCommProp->dwMaxTxQueue        = 4096;
1155     lpCommProp->dwMaxRxQueue        = 4096;
1156     lpCommProp->dwMaxBaud           = BAUD_115200;
1157     lpCommProp->dwProvSubType       = PST_RS232;
1158     lpCommProp->dwProvCapabilities  = PCF_DTRDSR | PCF_PARITY_CHECK | PCF_RTSCTS | PCF_TOTALTIMEOUTS;
1159     lpCommProp->dwSettableParams    = SP_BAUD | SP_DATABITS | SP_HANDSHAKING |
1160                                       SP_PARITY | SP_PARITY_CHECK | SP_STOPBITS ;
1161     lpCommProp->dwSettableBaud      = BAUD_075 | BAUD_110 | BAUD_134_5 | BAUD_150 |
1162                 BAUD_300 | BAUD_600 | BAUD_1200 | BAUD_1800 | BAUD_2400 | BAUD_4800 |
1163                 BAUD_9600 | BAUD_19200 | BAUD_38400 | BAUD_57600 | BAUD_115200 ;
1164     lpCommProp->wSettableData       = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8 ;
1165     lpCommProp->wSettableStopParity = STOPBITS_10 | STOPBITS_15 | STOPBITS_20 |
1166                 PARITY_NONE | PARITY_ODD |PARITY_EVEN | PARITY_MARK | PARITY_SPACE;
1167     lpCommProp->dwCurrentTxQueue    = lpCommProp->dwMaxTxQueue;
1168     lpCommProp->dwCurrentRxQueue    = lpCommProp->dwMaxRxQueue;
1169
1170     return TRUE;
1171 }
1172
1173 /***********************************************************************
1174  * FIXME:
1175  * The functionality of CommConfigDialogA, GetDefaultCommConfig and
1176  * SetDefaultCommConfig is implemented in a DLL (usually SERIALUI.DLL).
1177  * This is dependent on the type of COMM port, but since it is doubtful
1178  * anybody will get around to implementing support for fancy serial
1179  * ports in WINE, this is hardcoded for the time being.  The name of
1180  * this DLL should be stored in and read from the system registry in
1181  * the hive HKEY_LOCAL_MACHINE, key
1182  * System\\CurrentControlSet\\Services\\Class\\Ports\\????
1183  * where ???? is the port number... that is determined by PNP
1184  * The DLL should be loaded when the COMM port is opened, and closed
1185  * when the COMM port is closed. - MJM 20 June 2000
1186  ***********************************************************************/
1187 static const WCHAR lpszSerialUI[] = { 
1188    's','e','r','i','a','l','u','i','.','d','l','l',0 };
1189
1190
1191 /***********************************************************************
1192  *           CommConfigDialogA   (KERNEL32.@)
1193  *
1194  * Raises a dialog that allows the user to configure a comm port.
1195  * Fills the COMMCONFIG struct with information specified by the user.
1196  * This function should call a similar routine in the COMM driver...
1197  *
1198  * RETURNS
1199  *
1200  *  TRUE on success, FALSE on failure
1201  *  If successful, the lpCommConfig structure will contain a new
1202  *  configuration for the comm port, as specified by the user.
1203  *
1204  * BUGS
1205  *  The library with the CommConfigDialog code is never unloaded.
1206  * Perhaps this should be done when the comm port is closed?
1207  */
1208 BOOL WINAPI CommConfigDialogA(
1209     LPCSTR lpszDevice,         /* [in] name of communications device */
1210     HWND hWnd,                 /* [in] parent window for the dialog */
1211     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
1212 {
1213     LPWSTR  lpDeviceW = NULL;
1214     DWORD   len;
1215     BOOL    r;
1216
1217     TRACE("(%s, %p, %p)\n", debugstr_a(lpszDevice), hWnd, lpCommConfig);
1218
1219     if (lpszDevice)
1220     {
1221         len = MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, NULL, 0 );
1222         lpDeviceW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1223         MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, lpDeviceW, len );
1224     }
1225     r = CommConfigDialogW(lpDeviceW, hWnd, lpCommConfig);
1226     HeapFree( GetProcessHeap(), 0, lpDeviceW );
1227     return r;
1228 }
1229
1230 /***********************************************************************
1231  *           CommConfigDialogW   (KERNEL32.@)
1232  *
1233  * See CommConfigDialogA.
1234  */
1235 BOOL WINAPI CommConfigDialogW(
1236     LPCWSTR lpszDevice,        /* [in] name of communications device */
1237     HWND hWnd,                 /* [in] parent window for the dialog */
1238     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
1239 {
1240     DWORD (WINAPI *pCommConfigDialog)(LPCWSTR, HWND, LPCOMMCONFIG);
1241     HMODULE hConfigModule;
1242     DWORD   res = ERROR_INVALID_PARAMETER;
1243
1244     TRACE("(%s, %p, %p)\n", debugstr_w(lpszDevice), hWnd, lpCommConfig);
1245     hConfigModule = LoadLibraryW(lpszSerialUI);
1246
1247     if (hConfigModule) {
1248         pCommConfigDialog = (void *)GetProcAddress(hConfigModule, "drvCommConfigDialogW");
1249         if (pCommConfigDialog) {
1250             res = pCommConfigDialog(lpszDevice, hWnd, lpCommConfig);
1251         }
1252         FreeLibrary(hConfigModule);
1253     }
1254
1255     if (res) SetLastError(res);
1256     return (res == ERROR_SUCCESS);
1257 }
1258
1259 /***********************************************************************
1260  *           GetCommConfig     (KERNEL32.@)
1261  *
1262  * Fill in the COMMCONFIG structure for the comm port hFile
1263  *
1264  * RETURNS
1265  *
1266  *  TRUE on success, FALSE on failure
1267  *  If successful, lpCommConfig contains the comm port configuration.
1268  *
1269  * BUGS
1270  *
1271  */
1272 BOOL WINAPI GetCommConfig(
1273     HANDLE       hFile,        /* [in] The communications device. */
1274     LPCOMMCONFIG lpCommConfig, /* [out] The communications configuration of the device (if it fits). */
1275     LPDWORD      lpdwSize)     /* [in/out] Initially the size of the configuration buffer/structure,
1276                                   afterwards the number of bytes copied to the buffer or
1277                                   the needed size of the buffer. */
1278 {
1279     BOOL r;
1280
1281     TRACE("(%p, %p, %p) *lpdwSize: %u\n", hFile, lpCommConfig, lpdwSize, lpdwSize ? *lpdwSize : 0 );
1282
1283     if(lpCommConfig == NULL)
1284         return FALSE;
1285     r = *lpdwSize < sizeof(COMMCONFIG); /* TRUE if not enough space */
1286     *lpdwSize = sizeof(COMMCONFIG);
1287     if(r)
1288         return FALSE;
1289
1290     lpCommConfig->dwSize = sizeof(COMMCONFIG);
1291     lpCommConfig->wVersion = 1;
1292     lpCommConfig->wReserved = 0;
1293     r = GetCommState(hFile,&lpCommConfig->dcb);
1294     lpCommConfig->dwProviderSubType = PST_RS232;
1295     lpCommConfig->dwProviderOffset = 0;
1296     lpCommConfig->dwProviderSize = 0;
1297
1298     return r;
1299 }
1300
1301 /***********************************************************************
1302  *           SetCommConfig     (KERNEL32.@)
1303  *
1304  *  Sets the configuration of the communications device.
1305  *
1306  * RETURNS
1307  *
1308  *  True on success, false if the handle was bad is not a communications device.
1309  */
1310 BOOL WINAPI SetCommConfig(
1311     HANDLE       hFile,         /* [in] The communications device. */
1312     LPCOMMCONFIG lpCommConfig,  /* [in] The desired configuration. */
1313     DWORD dwSize)               /* [in] size of the lpCommConfig struct */
1314 {
1315     TRACE("(%p, %p, %u)\n", hFile, lpCommConfig, dwSize);
1316     return SetCommState(hFile,&lpCommConfig->dcb);
1317 }
1318
1319 /***********************************************************************
1320  *           SetDefaultCommConfigW  (KERNEL32.@)
1321  *
1322  * Initializes the default configuration for a communication device.
1323  *
1324  * PARAMS
1325  *  lpszDevice   [I] Name of the device targeted for configuration
1326  *  lpCommConfig [I] PTR to a buffer with the configuration for the device
1327  *  dwSize       [I] Number of bytes in the buffer
1328  *
1329  * RETURNS
1330  *  Failure: FALSE
1331  *  Success: TRUE, and default configuration saved
1332  *
1333  */
1334 BOOL WINAPI SetDefaultCommConfigW(LPCWSTR lpszDevice, LPCOMMCONFIG lpCommConfig, DWORD dwSize)
1335 {
1336     BOOL (WINAPI *lpfnSetDefaultCommConfig)(LPCWSTR, LPCOMMCONFIG, DWORD);
1337     HMODULE hConfigModule;
1338     BOOL r = FALSE;
1339
1340     TRACE("(%s, %p, %u)\n", debugstr_w(lpszDevice), lpCommConfig, dwSize);
1341
1342     hConfigModule = LoadLibraryW(lpszSerialUI);
1343     if(!hConfigModule)
1344         return r;
1345
1346     lpfnSetDefaultCommConfig = (void *)GetProcAddress(hConfigModule, "drvSetDefaultCommConfigW");
1347     if (lpfnSetDefaultCommConfig)
1348         r = lpfnSetDefaultCommConfig(lpszDevice, lpCommConfig, dwSize);
1349
1350     FreeLibrary(hConfigModule);
1351
1352     return r;
1353 }
1354
1355
1356 /***********************************************************************
1357  *           SetDefaultCommConfigA     (KERNEL32.@)
1358  *
1359  * Initializes the default configuration for a communication device.
1360  *
1361  * See SetDefaultCommConfigW.
1362  *
1363  */
1364 BOOL WINAPI SetDefaultCommConfigA(LPCSTR lpszDevice, LPCOMMCONFIG lpCommConfig, DWORD dwSize)
1365 {
1366     BOOL r;
1367     LPWSTR lpDeviceW = NULL;
1368     DWORD len;
1369
1370     TRACE("(%s, %p, %u)\n", debugstr_a(lpszDevice), lpCommConfig, dwSize);
1371
1372     if (lpszDevice)
1373     {
1374         len = MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, NULL, 0 );
1375         lpDeviceW = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
1376         MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, lpDeviceW, len );
1377     }
1378     r = SetDefaultCommConfigW(lpDeviceW,lpCommConfig,dwSize);
1379     HeapFree( GetProcessHeap(), 0, lpDeviceW );
1380     return r;
1381 }
1382
1383
1384 /***********************************************************************
1385  *           GetDefaultCommConfigW   (KERNEL32.@)
1386  *
1387  *   Acquires the default configuration of the specified communication device. (unicode)
1388  *
1389  *  RETURNS
1390  *
1391  *   True on successful reading of the default configuration,
1392  *   if the device is not found or the buffer is too small.
1393  */
1394 BOOL WINAPI GetDefaultCommConfigW(
1395     LPCWSTR      lpszName, /* [in] The unicode name of the device targeted for configuration. */
1396     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
1397     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
1398                               afterwards the number of bytes copied to the buffer or
1399                               the needed size of the buffer. */
1400 {
1401     DWORD (WINAPI *pGetDefaultCommConfig)(LPCWSTR, LPCOMMCONFIG, LPDWORD);
1402     HMODULE hConfigModule;
1403     DWORD   res = ERROR_INVALID_PARAMETER;
1404
1405     TRACE("(%s, %p, %p)  *lpdwSize: %u\n", debugstr_w(lpszName), lpCC, lpdwSize, lpdwSize ? *lpdwSize : 0 );
1406     hConfigModule = LoadLibraryW(lpszSerialUI);
1407
1408     if (hConfigModule) {
1409         pGetDefaultCommConfig = (void *)GetProcAddress(hConfigModule, "drvGetDefaultCommConfigW");
1410         if (pGetDefaultCommConfig) {
1411             res = pGetDefaultCommConfig(lpszName, lpCC, lpdwSize);
1412         }
1413         FreeLibrary(hConfigModule);
1414     }
1415
1416     if (res) SetLastError(res);
1417     return (res == ERROR_SUCCESS);
1418 }
1419
1420 /**************************************************************************
1421  *         GetDefaultCommConfigA                (KERNEL32.@)
1422  *
1423  *   Acquires the default configuration of the specified communication device. (ascii)
1424  *
1425  *  RETURNS
1426  *
1427  *   True on successful reading of the default configuration,
1428  *   if the device is not found or the buffer is too small.
1429  */
1430 BOOL WINAPI GetDefaultCommConfigA(
1431     LPCSTR       lpszName, /* [in] The ascii name of the device targeted for configuration. */
1432     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
1433     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
1434                               afterwards the number of bytes copied to the buffer or
1435                               the needed size of the buffer. */
1436 {
1437         BOOL ret = FALSE;
1438         UNICODE_STRING lpszNameW;
1439
1440         TRACE("(%s, %p, %p)  *lpdwSize: %u\n", debugstr_a(lpszName), lpCC, lpdwSize, lpdwSize ? *lpdwSize : 0 );
1441         if(lpszName) RtlCreateUnicodeStringFromAsciiz(&lpszNameW,lpszName);
1442         else lpszNameW.Buffer = NULL;
1443
1444         ret = GetDefaultCommConfigW(lpszNameW.Buffer,lpCC,lpdwSize);
1445
1446         RtlFreeUnicodeString(&lpszNameW);
1447         return ret;
1448 }