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