shell32: Always clone the return pidl to avoid a double free if the selection is...
[wine] / dlls / kernel32 / comm.c
CommitLineData
0c610287 1/*
ecc3712d 2 * DEC 93 Erik Bos <erik@xs4all.nl>
ac9c9b07
AJ
3 *
4 * Copyright 1996 Marcus Meissner
a1c45a52 5 *
0799c1a7
AJ
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
360a3f91 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
5f721f81
AJ
19 */
20
1425941e 21#include "config.h"
33c40709 22#include "wine/port.h"
c7c217b3 23
5f721f81 24#include <stdlib.h>
e37c6e18 25#include <stdarg.h>
d3e22d9d 26#include <stdio.h>
33929be4 27
9bd4f6bf
EP
28#define NONAMELESSUNION
29#define NONAMELESSSTRUCT
e37c6e18 30#include "windef.h"
33929be4 31#include "winbase.h"
a8486078 32#include "winerror.h"
2cdace27
EP
33#include "winioctl.h"
34#include "ddk/ntddser.h"
33c40709
PS
35
36#include "wine/server.h"
b370abab 37#include "wine/unicode.h"
a8486078 38
0799c1a7 39#include "wine/debug.h"
7bea8693 40
0799c1a7 41WINE_DEFAULT_DEBUG_CHANNEL(comm);
b4b9fae6 42
fe0529db 43/***********************************************************************
8be51c92 44 * COMM_Parse* (Internal)
fe0529db 45 *
8be51c92
KG
46 * The following COMM_Parse* functions are used by the BuildCommDCB
47 * functions to help parse the various parts of the device control string.
fe0529db 48 */
b370abab 49static LPCWSTR COMM_ParseStart(LPCWSTR ptr)
8be51c92 50{
6a6c85c6 51 static const WCHAR comW[] = {'C','O','M',0};
b370abab 52
8be51c92
KG
53 /* The device control string may optionally start with "COMx" followed
54 by an optional ':' and spaces. */
b370abab 55 if(!strncmpiW(ptr, comW, 3))
8be51c92
KG
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
b370abab 86static LPCWSTR COMM_ParseNumber(LPCWSTR ptr, LPDWORD lpnumber)
8be51c92
KG
87{
88 if(*ptr < '0' || *ptr > '9') return NULL;
b370abab 89 *lpnumber = strtoulW(ptr, NULL, 10);
8be51c92
KG
90 while(*ptr >= '0' && *ptr <= '9') ptr++;
91 return ptr;
92}
93
b370abab 94static LPCWSTR COMM_ParseParity(LPCWSTR ptr, LPBYTE lpparity)
8be51c92
KG
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
b370abab 100 switch(toupperW(*ptr++))
8be51c92
KG
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
b370abab 124static LPCWSTR COMM_ParseByteSize(LPCWSTR ptr, LPBYTE lpbytesize)
fe0529db 125{
8be51c92
KG
126 DWORD temp;
127
128 if(!(ptr = COMM_ParseNumber(ptr, &temp)))
129 return NULL;
130
131 if(temp >= 5 && temp <= 8)
fe0529db 132 {
8be51c92
KG
133 *lpbytesize = temp;
134 return ptr;
fe0529db 135 }
8be51c92
KG
136 else
137 return NULL;
138}
fe0529db 139
b370abab 140static LPCWSTR COMM_ParseStopBits(LPCWSTR ptr, LPBYTE lpstopbits)
8be51c92
KG
141{
142 DWORD temp;
6a6c85c6 143 static const WCHAR stopbits15W[] = {'1','.','5',0};
8be51c92 144
b370abab 145 if(!strncmpW(stopbits15W, ptr, 3))
8be51c92
KG
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
b370abab 166static LPCWSTR COMM_ParseOnOff(LPCWSTR ptr, LPDWORD lponoff)
8be51c92 167{
6a6c85c6
FG
168 static const WCHAR onW[] = {'o','n',0};
169 static const WCHAR offW[] = {'o','f','f',0};
b370abab
VB
170
171 if(!strncmpiW(onW, ptr, 2))
8be51c92
KG
172 {
173 ptr += 2;
174 *lponoff = 1;
175 }
b370abab 176 else if(!strncmpiW(offW, ptr, 3))
8be51c92
KG
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 */
b370abab 192static BOOL COMM_BuildOldCommDCB(LPCWSTR device, LPDCB lpdcb)
8be51c92 193{
b370abab 194 WCHAR last = 0;
8be51c92
KG
195
196 if(!(device = COMM_ParseNumber(device, &lpdcb->BaudRate)))
197 return FALSE;
198
199 switch(lpdcb->BaudRate)
200 {
fe0529db
MM
201 case 11:
202 case 30:
203 case 60:
8be51c92 204 lpdcb->BaudRate *= 10;
fe0529db
MM
205 break;
206 case 12:
207 case 24:
208 case 48:
209 case 96:
8be51c92 210 lpdcb->BaudRate *= 100;
fe0529db
MM
211 break;
212 case 19:
8be51c92 213 lpdcb->BaudRate = 19200;
fe0529db 214 break;
fe0529db 215 }
9a624916 216
8be51c92
KG
217 while(*device == ' ') device++;
218 if(*device++ != ',') return FALSE;
219 while(*device == ' ') device++;
fe0529db 220
8be51c92
KG
221 if(!(device = COMM_ParseParity(device, &lpdcb->Parity)))
222 return FALSE;
fe0529db 223
8be51c92
KG
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++;
b370abab 244 if(*device) last = toupperW(*device++);
8be51c92
KG
245 while(*device == ' ') device++;
246 }
49816197
KG
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. */
8be51c92
KG
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;
9a624916 259 break;
8be51c92
KG
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;
9a624916 267 break;
8be51c92
KG
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;
9a624916 275 break;
fe0529db 276 default:
fe0529db
MM
277 return FALSE;
278 }
279
8be51c92
KG
280 /* This should be the end of the string. */
281 if(*device) return FALSE;
282
283 return TRUE;
284}
fe0529db 285
8be51c92
KG
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 */
b370abab 292static BOOL COMM_BuildNewCommDCB(LPCWSTR device, LPDCB lpdcb, LPCOMMTIMEOUTS lptimeouts)
8be51c92
KG
293{
294 DWORD temp;
295 BOOL baud = FALSE, stop = FALSE;
6a6c85c6
FG
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};
8be51c92
KG
307
308 while(*device)
309 {
310 while(*device == ' ') device++;
311
b370abab 312 if(!strncmpiW(baudW, device, 5))
8be51c92
KG
313 {
314 baud = TRUE;
315
316 if(!(device = COMM_ParseNumber(device + 5, &lpdcb->BaudRate)))
317 return FALSE;
318 }
b370abab 319 else if(!strncmpiW(parityW, device, 7))
8be51c92
KG
320 {
321 if(!(device = COMM_ParseParity(device + 7, &lpdcb->Parity)))
322 return FALSE;
323 }
b370abab 324 else if(!strncmpiW(dataW, device, 5))
8be51c92
KG
325 {
326 if(!(device = COMM_ParseByteSize(device + 5, &lpdcb->ByteSize)))
327 return FALSE;
328 }
b370abab 329 else if(!strncmpiW(stopW, device, 5))
8be51c92
KG
330 {
331 stop = TRUE;
332
333 if(!(device = COMM_ParseStopBits(device + 5, &lpdcb->StopBits)))
334 return FALSE;
335 }
b370abab 336 else if(!strncmpiW(toW, device, 3))
8be51c92
KG
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 }
b370abab 347 else if(!strncmpiW(xonW, device, 4))
8be51c92
KG
348 {
349 if(!(device = COMM_ParseOnOff(device + 4, &temp)))
350 return FALSE;
351
352 lpdcb->fOutX = temp;
353 lpdcb->fInX = temp;
354 }
b370abab 355 else if(!strncmpiW(odsrW, device, 5))
8be51c92
KG
356 {
357 if(!(device = COMM_ParseOnOff(device + 5, &temp)))
358 return FALSE;
359
360 lpdcb->fOutxDsrFlow = temp;
361 }
b370abab 362 else if(!strncmpiW(octsW, device, 5))
8be51c92
KG
363 {
364 if(!(device = COMM_ParseOnOff(device + 5, &temp)))
365 return FALSE;
366
367 lpdcb->fOutxCtsFlow = temp;
368 }
b370abab 369 else if(!strncmpiW(dtrW, device, 4))
8be51c92
KG
370 {
371 if(!(device = COMM_ParseOnOff(device + 4, &temp)))
372 return FALSE;
373
374 lpdcb->fDtrControl = temp;
375 }
b370abab 376 else if(!strncmpiW(rtsW, device, 4))
8be51c92
KG
377 {
378 if(!(device = COMM_ParseOnOff(device + 4, &temp)))
379 return FALSE;
380
381 lpdcb->fRtsControl = temp;
382 }
b370abab 383 else if(!strncmpiW(idsrW, device, 5))
8be51c92
KG
384 {
385 if(!(device = COMM_ParseOnOff(device + 5, &temp)))
386 return FALSE;
387
49816197
KG
388 /* Win NT sets the fDsrSensitivity member based on the
389 idsr parameter. Win 9x sets fOutxDsrFlow instead. */
8be51c92
KG
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;
9a624916 399 }
fe0529db 400
8be51c92
KG
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;
fe0529db
MM
408 }
409
c5ea29f9 410 return TRUE;
fe0529db
MM
411}
412
a1c45a52 413/**************************************************************************
dae8de69 414 * BuildCommDCBA (KERNEL32.@)
03131aae
AJ
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 *
f16b401e 422 * True on success, false on a malformed control string.
a1c45a52 423 */
03131aae 424BOOL WINAPI BuildCommDCBA(
bca4a8dc
PS
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. */
a1c45a52
OK
427{
428 return BuildCommDCBAndTimeoutsA(device,lpdcb,NULL);
429}
430
431/**************************************************************************
b370abab 432 * BuildCommDCBAndTimeoutsA (KERNEL32.@)
03131aae
AJ
433 *
434 * Updates a device control block data structure with values from an
f16b401e 435 * ascii device control string. Taking timeout values from a timeouts
03131aae
AJ
436 * struct if desired by the control string.
437 *
438 * RETURNS
439 *
b370abab 440 * True on success, false bad handles etc.
a1c45a52 441 */
03131aae 442BOOL WINAPI BuildCommDCBAndTimeoutsA(
bca4a8dc
PS
443 LPCSTR device, /* [in] The ascii device control string. */
444 LPDCB lpdcb, /* [out] The device control block to be updated. */
8be51c92 445 LPCOMMTIMEOUTS lptimeouts) /* [in] The COMMTIMEOUTS structure to be updated. */
b370abab
VB
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 */
471BOOL 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. */
a1c45a52 475{
8be51c92
KG
476 DCB dcb;
477 COMMTIMEOUTS timeouts;
478 BOOL result;
b370abab 479 LPCWSTR ptr = devid;
54a376f2 480
b370abab 481 TRACE("(%s,%p,%p)\n",debugstr_w(devid),lpdcb,lptimeouts);
a1c45a52 482
54a376f2
AT
483 memset(&timeouts, 0, sizeof timeouts);
484
8be51c92
KG
485 /* Set DCBlength. (Windows NT does not do this, but 9x does) */
486 lpdcb->DCBlength = sizeof(DCB);
a1c45a52 487
8be51c92
KG
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) */
54a376f2
AT
491 dcb = *lpdcb;
492 if(lptimeouts) timeouts = *lptimeouts;
a1c45a52 493
8be51c92
KG
494 ptr = COMM_ParseStart(ptr);
495
496 if(ptr == NULL)
497 result = FALSE;
b370abab 498 else if(strchrW(ptr, ','))
8be51c92
KG
499 result = COMM_BuildOldCommDCB(ptr, &dcb);
500 else
501 result = COMM_BuildNewCommDCB(ptr, &dcb, &timeouts);
502
503 if(result)
504 {
54a376f2
AT
505 *lpdcb = dcb;
506 if(lptimeouts) *lptimeouts = timeouts;
8be51c92 507 return TRUE;
a1c45a52 508 }
8be51c92
KG
509 else
510 {
b370abab 511 WARN("Invalid device control string: %s\n", debugstr_w(devid));
8be51c92
KG
512 SetLastError(ERROR_INVALID_PARAMETER);
513 return FALSE;
514 }
a1c45a52
OK
515}
516
a1c45a52 517/**************************************************************************
dae8de69 518 * BuildCommDCBW (KERNEL32.@)
03131aae
AJ
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 *
6b10c324 526 * True on success, false on a malformed control string.
a1c45a52 527 */
03131aae 528BOOL WINAPI BuildCommDCBW(
bca4a8dc
PS
529 LPCWSTR devid, /* [in] The unicode device control string. */
530 LPDCB lpdcb) /* [out] The device control block to be updated. */
a1c45a52
OK
531{
532 return BuildCommDCBAndTimeoutsW(devid,lpdcb,NULL);
533}
534
a1c45a52 535/*****************************************************************************
dae8de69 536 * SetCommBreak (KERNEL32.@)
03131aae
AJ
537 *
538 * Halts the transmission of characters to a communications device.
539 *
2cdace27
EP
540 * PARAMS
541 * handle [in] The communications device to suspend
542 *
03131aae
AJ
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 *
9a624916 550 * Only TIOCSBRK and TIOCCBRK are supported.
a1c45a52 551 */
2cdace27 552BOOL WINAPI SetCommBreak(HANDLE handle)
a1c45a52 553{
4192d34d
CW
554 DWORD dwBytesReturned;
555 return DeviceIoControl(handle, IOCTL_SERIAL_SET_BREAK_ON, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
a1c45a52
OK
556}
557
558/*****************************************************************************
dae8de69 559 * ClearCommBreak (KERNEL32.@)
03131aae
AJ
560 *
561 * Resumes character transmission from a communication device.
562 *
2cdace27
EP
563 * PARAMS
564 *
565 * handle [in] The halted communication device whose character transmission is to be resumed
566 *
03131aae
AJ
567 * RETURNS
568 *
569 * True on success and false if the communications device could not be found.
570 *
571 * BUGS
572 *
9a624916 573 * Only TIOCSBRK and TIOCCBRK are supported.
a1c45a52 574 */
2cdace27 575BOOL WINAPI ClearCommBreak(HANDLE handle)
a1c45a52 576{
4192d34d
CW
577 DWORD dwBytesReturned;
578 return DeviceIoControl(handle, IOCTL_SERIAL_SET_BREAK_OFF, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
a1c45a52
OK
579}
580
581/*****************************************************************************
dae8de69 582 * EscapeCommFunction (KERNEL32.@)
03131aae
AJ
583 *
584 * Directs a communication device to perform an extended function.
585 *
5f9e9836
EP
586 * PARAMS
587 *
588 * handle [in] The communication device to perform the extended function
589 * nFunction [in] The extended function to be performed
590 *
03131aae
AJ
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.
a1c45a52 596 */
5f9e9836 597BOOL WINAPI EscapeCommFunction(HANDLE handle, UINT func)
a1c45a52 598{
5f9e9836 599 DWORD ioc;
4192d34d 600 DWORD dwBytesReturned;
a1c45a52 601
5f9e9836
EP
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 }
4192d34d 618 return DeviceIoControl(handle, ioc, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
a1c45a52
OK
619}
620
621/********************************************************************
dae8de69 622 * PurgeComm (KERNEL32.@)
03131aae
AJ
623 *
624 * Terminates pending operations and/or discards buffers on a
625 * communication resource.
626 *
b83c5ead
EP
627 * PARAMS
628 *
629 * handle [in] The communication resource to be purged
630 * flags [in] Flags for clear pending/buffer on input/output
631 *
03131aae
AJ
632 * RETURNS
633 *
634 * True on success and false if the communications handle is bad.
a1c45a52 635 */
b83c5ead 636BOOL WINAPI PurgeComm(HANDLE handle, DWORD flags)
a1c45a52 637{
4192d34d 638 DWORD dwBytesReturned;
b83c5ead 639 return DeviceIoControl(handle, IOCTL_SERIAL_PURGE, &flags, sizeof(flags),
4192d34d 640 NULL, 0, &dwBytesReturned, NULL);
a1c45a52
OK
641}
642
643/*****************************************************************************
dae8de69 644 * ClearCommError (KERNEL32.@)
03131aae
AJ
645 *
646 * Enables further I/O operations on a communications resource after
647 * supplying error and current status information.
648 *
8e5d2bdb
EP
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
03131aae
AJ
654 * RETURNS
655 *
656 * True on success, false if the communication resource handle is bad.
a1c45a52 657 */
8e5d2bdb 658BOOL WINAPI ClearCommError(HANDLE handle, LPDWORD errors, LPCOMSTAT lpStat)
a1c45a52 659{
8e5d2bdb 660 SERIAL_STATUS ss;
4192d34d 661 DWORD dwBytesReturned;
a1c45a52 662
8e5d2bdb 663 if (!DeviceIoControl(handle, IOCTL_SERIAL_GET_COMMSTATUS, NULL, 0,
4192d34d 664 &ss, sizeof(ss), &dwBytesReturned, NULL))
8e5d2bdb 665 return FALSE;
a1c45a52 666
8e5d2bdb
EP
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
9a624916 677 if (lpStat)
a1c45a52 678 {
8e5d2bdb
EP
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;
a1c45a52 690 }
a1c45a52
OK
691 return TRUE;
692}
693
694/*****************************************************************************
dae8de69 695 * SetupComm (KERNEL32.@)
03131aae
AJ
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 *
fcdc293b
EP
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 *
03131aae
AJ
705 * RETURNS
706 *
707 * True if successful, false if the communications resource handle is bad.
708 *
709 * BUGS
710 *
711 * Stub.
a1c45a52 712 */
fcdc293b 713BOOL WINAPI SetupComm(HANDLE handle, DWORD insize, DWORD outsize)
a1c45a52 714{
fcdc293b 715 SERIAL_QUEUE_SIZE sqs;
4192d34d 716 DWORD dwBytesReturned;
a1c45a52 717
fcdc293b
EP
718 sqs.InSize = insize;
719 sqs.OutSize = outsize;
720 return DeviceIoControl(handle, IOCTL_SERIAL_SET_QUEUE_SIZE,
4192d34d 721 &sqs, sizeof(sqs), NULL, 0, &dwBytesReturned, NULL);
9a624916 722}
a1c45a52
OK
723
724/*****************************************************************************
dae8de69 725 * GetCommMask (KERNEL32.@)
03131aae 726 *
f16b401e
AM
727 * Obtain the events associated with a communication device that will cause
728 * a call WaitCommEvent to return.
03131aae 729 *
58e719ce
EP
730 * PARAMS
731 *
732 * handle [in] The communications device
733 * evtmask [out] The events which cause WaitCommEvent to return
734 *
03131aae
AJ
735 * RETURNS
736 *
737 * True on success, fail on bad device handle etc.
a1c45a52 738 */
58e719ce 739BOOL WINAPI GetCommMask(HANDLE handle, LPDWORD evtmask)
a1c45a52 740{
4192d34d 741 DWORD dwBytesReturned;
308e04fc 742 TRACE("handle %p, mask %p\n", handle, evtmask);
58e719ce 743 return DeviceIoControl(handle, IOCTL_SERIAL_GET_WAIT_MASK,
4192d34d 744 NULL, 0, evtmask, sizeof(*evtmask), &dwBytesReturned, NULL);
a1c45a52
OK
745}
746
747/*****************************************************************************
dae8de69 748 * SetCommMask (KERNEL32.@)
03131aae
AJ
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 *
58e719ce
EP
754 * PARAMS
755 *
756 * handle [in] The communications device
757 * evtmask [in] The events that are to be monitored
758 *
03131aae
AJ
759 * RETURNS
760 *
761 * True on success, false on bad handle etc.
a1c45a52 762 */
58e719ce 763BOOL WINAPI SetCommMask(HANDLE handle, DWORD evtmask)
a1c45a52 764{
4192d34d 765 DWORD dwBytesReturned;
8c38b880 766 TRACE("handle %p, mask %x\n", handle, evtmask);
58e719ce 767 return DeviceIoControl(handle, IOCTL_SERIAL_SET_WAIT_MASK,
4192d34d 768 &evtmask, sizeof(evtmask), NULL, 0, &dwBytesReturned, NULL);
5f721f81
AJ
769}
770
631ec30f
EP
771static void dump_dcb(const DCB* lpdcb)
772{
8c38b880 773 TRACE("bytesize=%d baudrate=%d fParity=%d Parity=%d stopbits=%d\n",
631ec30f
EP
774 lpdcb->ByteSize, lpdcb->BaudRate, lpdcb->fParity, lpdcb->Parity,
775 (lpdcb->StopBits == ONESTOPBIT) ? 1 :
776 (lpdcb->StopBits == TWOSTOPBITS) ? 2 : 0);
ce195244 777 TRACE("%sIXON %sIXOFF\n", (lpdcb->fOutX) ? "" : "~", (lpdcb->fInX) ? "" : "~");
631ec30f
EP
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
ac9c9b07 786/*****************************************************************************
dae8de69 787 * SetCommState (KERNEL32.@)
03131aae
AJ
788 *
789 * Re-initializes all hardware and control settings of a communications device,
c531e2ab 790 * with values from a device control block without affecting the input and output
03131aae
AJ
791 * queues.
792 *
631ec30f
EP
793 * PARAMS
794 *
795 * handle [in] The communications device
796 * lpdcb [out] The device control block
797 *
03131aae
AJ
798 * RETURNS
799 *
c531e2ab 800 * True on success, false on failure, e.g., if the XonChar is equal to the XoffChar.
ac9c9b07 801 */
631ec30f 802BOOL WINAPI SetCommState( HANDLE handle, LPDCB lpdcb)
ac9c9b07 803{
65f137c5
EP
804 SERIAL_BAUD_RATE sbr;
805 SERIAL_LINE_CONTROL slc;
b68203ea 806 SERIAL_HANDFLOW shf;
a05a3435 807 SERIAL_CHARS sc;
4192d34d 808 DWORD dwBytesReturned;
65f137c5 809
631ec30f
EP
810 if (lpdcb == NULL)
811 {
812 SetLastError(ERROR_INVALID_PARAMETER);
813 return FALSE;
814 }
815 dump_dcb(lpdcb);
816
817 sbr.BaudRate = lpdcb->BaudRate;
65f137c5
EP
818
819 slc.StopBits = lpdcb->StopBits;
820 slc.Parity = lpdcb->Parity;
821 slc.WordLength = lpdcb->ByteSize;
822
b68203ea
EP
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 }
ea1e7555 836 switch (lpdcb->fRtsControl)
b68203ea
EP
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
a05a3435
EP
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
b68203ea
EP
866 /* note: change DTR/RTS lines after setting the comm attributes,
867 * so flow control does not interfere.
868 */
a05a3435 869 return (DeviceIoControl(handle, IOCTL_SERIAL_SET_BAUD_RATE,
4192d34d 870 &sbr, sizeof(sbr), NULL, 0, &dwBytesReturned, NULL) &&
a05a3435 871 DeviceIoControl(handle, IOCTL_SERIAL_SET_LINE_CONTROL,
4192d34d 872 &slc, sizeof(slc), NULL, 0, &dwBytesReturned, NULL) &&
a05a3435 873 DeviceIoControl(handle, IOCTL_SERIAL_SET_HANDFLOW,
4192d34d 874 &shf, sizeof(shf), NULL, 0, &dwBytesReturned, NULL) &&
a05a3435 875 DeviceIoControl(handle, IOCTL_SERIAL_SET_CHARS,
4192d34d 876 &sc, sizeof(sc), NULL, 0, &dwBytesReturned, NULL));
ac9c9b07
AJ
877}
878
879
ac9c9b07 880/*****************************************************************************
dae8de69 881 * GetCommState (KERNEL32.@)
03131aae
AJ
882 *
883 * Fills in a device control block with information from a communications device.
884 *
c7016d93
EP
885 * PARAMS
886 * handle [in] The communications device
887 * lpdcb [out] The device control block
888 *
03131aae
AJ
889 * RETURNS
890 *
891 * True on success, false if the communication device handle is bad etc
9a624916 892 *
03131aae
AJ
893 * BUGS
894 *
895 * XonChar and XoffChar are not set.
ac9c9b07 896 */
c7016d93 897BOOL WINAPI GetCommState(HANDLE handle, LPDCB lpdcb)
ac9c9b07 898{
c7016d93 899 SERIAL_BAUD_RATE sbr;
efb3244b 900 SERIAL_LINE_CONTROL slc;
48646ea8 901 SERIAL_HANDFLOW shf;
28cd4fae 902 SERIAL_CHARS sc;
4192d34d 903 DWORD dwBytesReturned;
c7016d93
EP
904
905 TRACE("handle %p, ptr %p\n", handle, lpdcb);
a8486078 906
c7016d93
EP
907 if (!lpdcb)
908 {
909 SetLastError(ERROR_INVALID_PARAMETER);
910 return FALSE;
911 }
c7016d93
EP
912
913 if (!DeviceIoControl(handle, IOCTL_SERIAL_GET_BAUD_RATE,
4192d34d 914 NULL, 0, &sbr, sizeof(sbr), &dwBytesReturned, NULL) ||
efb3244b 915 !DeviceIoControl(handle, IOCTL_SERIAL_GET_LINE_CONTROL,
4192d34d 916 NULL, 0, &slc, sizeof(slc), &dwBytesReturned, NULL) ||
48646ea8 917 !DeviceIoControl(handle, IOCTL_SERIAL_GET_HANDFLOW,
4192d34d 918 NULL, 0, &shf, sizeof(shf), &dwBytesReturned, NULL) ||
28cd4fae 919 !DeviceIoControl(handle, IOCTL_SERIAL_GET_CHARS,
4192d34d 920 NULL, 0, &sc, sizeof(sc), &dwBytesReturned, NULL))
c7016d93 921 return FALSE;
efb3244b 922
48646ea8
EP
923 memset(lpdcb, 0, sizeof(*lpdcb));
924 lpdcb->DCBlength = sizeof(*lpdcb);
925
c7016d93
EP
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;
efb3244b
EP
931
932 lpdcb->StopBits = slc.StopBits;
933 lpdcb->Parity = slc.Parity;
934 lpdcb->ByteSize = slc.WordLength;
935
48646ea8
EP
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;
ac9c9b07 959
48646ea8
EP
960 if (shf.FlowReplace & SERIAL_AUTO_TRANSMIT) lpdcb->fOutX = 1;
961 if (shf.FlowReplace & SERIAL_AUTO_RECEIVE) lpdcb->fInX = 1;
ac9c9b07 962
28cd4fae
EP
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;
ac9c9b07 968
c7016d93
EP
969 TRACE("OK\n");
970 dump_dcb(lpdcb);
9a624916 971
c7016d93 972 return TRUE;
ac9c9b07
AJ
973}
974
ac9c9b07 975/*****************************************************************************
dae8de69 976 * TransmitCommChar (KERNEL32.@)
03131aae
AJ
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 *
3c2abaf4
EP
981 * PARAMS
982 * hComm [in] The communication device in need of a command character
983 * chTransmit [in] The character to transmit
984 *
03131aae
AJ
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 *
ac9c9b07 990 */
3c2abaf4 991BOOL WINAPI TransmitCommChar(HANDLE hComm, CHAR chTransmit)
ac9c9b07 992{
4192d34d 993 DWORD dwBytesReturned;
3c2abaf4 994 return DeviceIoControl(hComm, IOCTL_SERIAL_IMMEDIATE_CHAR,
4192d34d 995 &chTransmit, sizeof(chTransmit), NULL, 0, &dwBytesReturned, NULL);
ac9c9b07
AJ
996}
997
eeb35656 998
ac9c9b07 999/*****************************************************************************
dae8de69 1000 * GetCommTimeouts (KERNEL32.@)
03131aae 1001 *
f16b401e 1002 * Obtains the request timeout values for the communications device.
03131aae 1003 *
b53e0169
EP
1004 * PARAMS
1005 * hComm [in] The communications device
1006 * lptimeouts [out] The struct of request timeouts
1007 *
03131aae
AJ
1008 * RETURNS
1009 *
1010 * True on success, false if communications device handle is bad
1011 * or the target structure is null.
ac9c9b07 1012 */
b53e0169 1013BOOL WINAPI GetCommTimeouts(HANDLE hComm, LPCOMMTIMEOUTS lptimeouts)
670cdc45 1014{
b53e0169 1015 SERIAL_TIMEOUTS st;
4192d34d 1016 DWORD dwBytesReturned;
654fcc72 1017
b53e0169
EP
1018 TRACE("(%p, %p)\n", hComm, lptimeouts);
1019 if (!lptimeouts)
654fcc72
MM
1020 {
1021 SetLastError(ERROR_INVALID_PARAMETER);
1022 return FALSE;
1023 }
b53e0169 1024 if (!DeviceIoControl(hComm, IOCTL_SERIAL_GET_TIMEOUTS,
4192d34d 1025 NULL, 0, &st, sizeof(st), &dwBytesReturned, NULL))
b53e0169
EP
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;
ac9c9b07
AJ
1033}
1034
1035/*****************************************************************************
dae8de69 1036 * SetCommTimeouts (KERNEL32.@)
654fcc72
MM
1037 *
1038 * Sets the timeouts used when reading and writing data to/from COMM ports.
1039 *
b53e0169
EP
1040 * PARAMS
1041 * hComm [in] handle of COMM device
1042 * lptimeouts [in] pointer to COMMTIMEOUTS structure
1043 *
9a624916 1044 * ReadIntervalTimeout
654fcc72
MM
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
03131aae
AJ
1050 *
1051 * RETURNS
1052 *
f16b401e 1053 * True if the timeouts were set, false otherwise.
ac9c9b07 1054 */
b53e0169 1055BOOL WINAPI SetCommTimeouts(HANDLE hComm, LPCOMMTIMEOUTS lptimeouts)
bca4a8dc 1056{
b53e0169 1057 SERIAL_TIMEOUTS st;
4192d34d 1058 DWORD dwBytesReturned;
7547d4de 1059
b53e0169 1060 TRACE("(%p, %p)\n", hComm, lptimeouts);
7547d4de 1061
b53e0169 1062 if (lptimeouts == NULL)
654fcc72
MM
1063 {
1064 SetLastError(ERROR_INVALID_PARAMETER);
654fcc72 1065 return FALSE;
57f05e19 1066 }
b53e0169
EP
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,
4192d34d 1074 &st, sizeof(st), NULL, 0, &dwBytesReturned, NULL);
641ee76a
AJ
1075}
1076
94113fa1 1077/***********************************************************************
dae8de69 1078 * GetCommModemStatus (KERNEL32.@)
03131aae
AJ
1079 *
1080 * Obtains the four control register bits if supported by the hardware.
1081 *
5973955e
EP
1082 * PARAMS
1083 *
1084 * hFile [in] The communications device
1085 * lpModemStat [out] The control register bits
1086 *
03131aae
AJ
1087 * RETURNS
1088 *
1089 * True if the communications handle was good and for hardware that
1090 * control register access, false otherwise.
94113fa1 1091 */
5973955e 1092BOOL WINAPI GetCommModemStatus(HANDLE hFile, LPDWORD lpModemStat)
94113fa1 1093{
4192d34d 1094 DWORD dwBytesReturned;
5973955e 1095 return DeviceIoControl(hFile, IOCTL_SERIAL_GET_MODEMSTATUS,
4192d34d 1096 NULL, 0, lpModemStat, sizeof(DWORD), &dwBytesReturned, NULL);
94113fa1 1097}
1eac1911 1098
1c32a46d 1099/***********************************************************************
dae8de69 1100 * WaitCommEvent (KERNEL32.@)
1c32a46d
MM
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 *
b8d9b619 1106 * RETURNS
1c32a46d
MM
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 */
1116BOOL 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{
d990c0d8
EP
1121 return DeviceIoControl(hFile, IOCTL_SERIAL_WAIT_ON_MASK, NULL, 0,
1122 lpdwEvents, sizeof(DWORD), NULL, lpOverlapped);
1c32a46d 1123}
9a624916 1124
a8486078 1125/***********************************************************************
dae8de69 1126 * GetCommProperties (KERNEL32.@)
a341a967 1127 *
9a624916 1128 * This function fills in a structure with the capabilities of the
a341a967
MM
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.
a8486078 1136 */
a341a967 1137BOOL WINAPI GetCommProperties(
bca4a8dc
PS
1138 HANDLE hFile, /* [in] handle of the comm port */
1139 LPCOMMPROP lpCommProp) /* [out] pointer to struct to be filled */
1140{
f999060f 1141 TRACE("(%p %p)\n",hFile,lpCommProp);
a341a967
MM
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;
a341a967
MM
1153 lpCommProp->dwMaxTxQueue = 4096;
1154 lpCommProp->dwMaxRxQueue = 4096;
1155 lpCommProp->dwMaxBaud = BAUD_115200;
1156 lpCommProp->dwProvSubType = PST_RS232;
eef5d668 1157 lpCommProp->dwProvCapabilities = PCF_DTRDSR | PCF_PARITY_CHECK | PCF_RTSCTS | PCF_TOTALTIMEOUTS;
9a624916 1158 lpCommProp->dwSettableParams = SP_BAUD | SP_DATABITS | SP_HANDSHAKING |
a341a967
MM
1159 SP_PARITY | SP_PARITY_CHECK | SP_STOPBITS ;
1160 lpCommProp->dwSettableBaud = BAUD_075 | BAUD_110 | BAUD_134_5 | BAUD_150 |
1161 BAUD_300 | BAUD_600 | BAUD_1200 | BAUD_1800 | BAUD_2400 | BAUD_4800 |
1162 BAUD_9600 | BAUD_19200 | BAUD_38400 | BAUD_57600 | BAUD_115200 ;
1163 lpCommProp->wSettableData = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8 ;
9a624916 1164 lpCommProp->wSettableStopParity = STOPBITS_10 | STOPBITS_15 | STOPBITS_20 |
a341a967
MM
1165 PARITY_NONE | PARITY_ODD |PARITY_EVEN | PARITY_MARK | PARITY_SPACE;
1166 lpCommProp->dwCurrentTxQueue = lpCommProp->dwMaxTxQueue;
1167 lpCommProp->dwCurrentRxQueue = lpCommProp->dwMaxRxQueue;
1168
a8486078
MM
1169 return TRUE;
1170}
1171
a341a967
MM
1172/***********************************************************************
1173 * FIXME:
1174 * The functionality of CommConfigDialogA, GetDefaultCommConfig and
1175 * SetDefaultCommConfig is implemented in a DLL (usually SERIALUI.DLL).
1176 * This is dependent on the type of COMM port, but since it is doubtful
1177 * anybody will get around to implementing support for fancy serial
9a624916
VB
1178 * ports in WINE, this is hardcoded for the time being. The name of
1179 * this DLL should be stored in and read from the system registry in
a341a967
MM
1180 * the hive HKEY_LOCAL_MACHINE, key
1181 * System\\CurrentControlSet\\Services\\Class\\Ports\\????
1182 * where ???? is the port number... that is determined by PNP
9a624916 1183 * The DLL should be loaded when the COMM port is opened, and closed
a341a967
MM
1184 * when the COMM port is closed. - MJM 20 June 2000
1185 ***********************************************************************/
57a579ff 1186static const WCHAR lpszSerialUI[] = {
568a91df 1187 's','e','r','i','a','l','u','i','.','d','l','l',0 };
a341a967
MM
1188
1189
1190/***********************************************************************
dae8de69 1191 * CommConfigDialogA (KERNEL32.@)
a341a967
MM
1192 *
1193 * Raises a dialog that allows the user to configure a comm port.
1194 * Fills the COMMCONFIG struct with information specified by the user.
1195 * This function should call a similar routine in the COMM driver...
1196 *
1197 * RETURNS
1198 *
1199 * TRUE on success, FALSE on failure
1200 * If successful, the lpCommConfig structure will contain a new
1201 * configuration for the comm port, as specified by the user.
1202 *
1203 * BUGS
1204 * The library with the CommConfigDialog code is never unloaded.
1205 * Perhaps this should be done when the comm port is closed?
1206 */
1207BOOL WINAPI CommConfigDialogA(
bca4a8dc 1208 LPCSTR lpszDevice, /* [in] name of communications device */
51198f8e 1209 HWND hWnd, /* [in] parent window for the dialog */
bca4a8dc
PS
1210 LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
1211{
20a32983
DR
1212 LPWSTR lpDeviceW = NULL;
1213 DWORD len;
1214 BOOL r;
a341a967 1215
d7e88ff9 1216 TRACE("(%s, %p, %p)\n", debugstr_a(lpszDevice), hWnd, lpCommConfig);
a341a967 1217
20a32983
DR
1218 if (lpszDevice)
1219 {
1220 len = MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, NULL, 0 );
1221 lpDeviceW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1222 MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, lpDeviceW, len );
1223 }
1224 r = CommConfigDialogW(lpDeviceW, hWnd, lpCommConfig);
1225 HeapFree( GetProcessHeap(), 0, lpDeviceW );
a341a967
MM
1226 return r;
1227}
1228
1229/***********************************************************************
dae8de69 1230 * CommConfigDialogW (KERNEL32.@)
a341a967 1231 *
b8d9b619 1232 * See CommConfigDialogA.
a341a967
MM
1233 */
1234BOOL WINAPI CommConfigDialogW(
bca4a8dc 1235 LPCWSTR lpszDevice, /* [in] name of communications device */
51198f8e 1236 HWND hWnd, /* [in] parent window for the dialog */
bca4a8dc
PS
1237 LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
1238{
858f0878 1239 DWORD (WINAPI *pCommConfigDialog)(LPCWSTR, HWND, LPCOMMCONFIG);
bf88644c 1240 HMODULE hConfigModule;
20a32983 1241 DWORD res = ERROR_INVALID_PARAMETER;
bf88644c 1242
d7e88ff9 1243 TRACE("(%s, %p, %p)\n", debugstr_w(lpszDevice), hWnd, lpCommConfig);
bf88644c 1244 hConfigModule = LoadLibraryW(lpszSerialUI);
bf88644c 1245
20a32983 1246 if (hConfigModule) {
858f0878 1247 pCommConfigDialog = (void *)GetProcAddress(hConfigModule, "drvCommConfigDialogW");
20a32983
DR
1248 if (pCommConfigDialog) {
1249 res = pCommConfigDialog(lpszDevice, hWnd, lpCommConfig);
1250 }
1251 FreeLibrary(hConfigModule);
1252 }
bf88644c 1253
20a32983
DR
1254 if (res) SetLastError(res);
1255 return (res == ERROR_SUCCESS);
a341a967
MM
1256}
1257
1258/***********************************************************************
cd6b8cad 1259 * GetCommConfig (KERNEL32.@)
a341a967
MM
1260 *
1261 * Fill in the COMMCONFIG structure for the comm port hFile
1262 *
1263 * RETURNS
1264 *
1265 * TRUE on success, FALSE on failure
1266 * If successful, lpCommConfig contains the comm port configuration.
03131aae
AJ
1267 *
1268 * BUGS
1269 *
a341a967
MM
1270 */
1271BOOL WINAPI GetCommConfig(
bca4a8dc 1272 HANDLE hFile, /* [in] The communications device. */
cd6b8cad 1273 LPCOMMCONFIG lpCommConfig, /* [out] The communications configuration of the device (if it fits). */
bca4a8dc 1274 LPDWORD lpdwSize) /* [in/out] Initially the size of the configuration buffer/structure,
9a624916 1275 afterwards the number of bytes copied to the buffer or
bca4a8dc 1276 the needed size of the buffer. */
bca4a8dc 1277{
a341a967
MM
1278 BOOL r;
1279
d7e88ff9 1280 TRACE("(%p, %p, %p) *lpdwSize: %u\n", hFile, lpCommConfig, lpdwSize, lpdwSize ? *lpdwSize : 0 );
a341a967
MM
1281
1282 if(lpCommConfig == NULL)
1283 return FALSE;
39a16e82 1284 r = *lpdwSize < sizeof(COMMCONFIG); /* TRUE if not enough space */
cd6b8cad 1285 *lpdwSize = sizeof(COMMCONFIG);
39a16e82 1286 if(r)
cd6b8cad
PS
1287 return FALSE;
1288
a341a967
MM
1289 lpCommConfig->dwSize = sizeof(COMMCONFIG);
1290 lpCommConfig->wVersion = 1;
1291 lpCommConfig->wReserved = 0;
1292 r = GetCommState(hFile,&lpCommConfig->dcb);
1293 lpCommConfig->dwProviderSubType = PST_RS232;
1294 lpCommConfig->dwProviderOffset = 0;
1295 lpCommConfig->dwProviderSize = 0;
1296
1297 return r;
1298}
1299
1300/***********************************************************************
dae8de69 1301 * SetCommConfig (KERNEL32.@)
a341a967 1302 *
f16b401e 1303 * Sets the configuration of the communications device.
03131aae
AJ
1304 *
1305 * RETURNS
1306 *
1307 * True on success, false if the handle was bad is not a communications device.
a341a967
MM
1308 */
1309BOOL WINAPI SetCommConfig(
99f54153
MM
1310 HANDLE hFile, /* [in] The communications device. */
1311 LPCOMMCONFIG lpCommConfig, /* [in] The desired configuration. */
1312 DWORD dwSize) /* [in] size of the lpCommConfig struct */
bca4a8dc 1313{
d7e88ff9 1314 TRACE("(%p, %p, %u)\n", hFile, lpCommConfig, dwSize);
03131aae 1315 return SetCommState(hFile,&lpCommConfig->dcb);
a341a967
MM
1316}
1317
1318/***********************************************************************
f2e7c43d 1319 * SetDefaultCommConfigW (KERNEL32.@)
03131aae 1320 *
f2e7c43d
DR
1321 * Initializes the default configuration for a communication device.
1322 *
1323 * PARAMS
1324 * lpszDevice [I] Name of the device targeted for configuration
1325 * lpCommConfig [I] PTR to a buffer with the configuration for the device
1326 * dwSize [I] Number of bytes in the buffer
03131aae
AJ
1327 *
1328 * RETURNS
f2e7c43d
DR
1329 * Failure: FALSE
1330 * Success: TRUE, and default configuration saved
03131aae 1331 *
a341a967 1332 */
f2e7c43d 1333BOOL WINAPI SetDefaultCommConfigW(LPCWSTR lpszDevice, LPCOMMCONFIG lpCommConfig, DWORD dwSize)
bca4a8dc 1334{
858f0878 1335 BOOL (WINAPI *lpfnSetDefaultCommConfig)(LPCWSTR, LPCOMMCONFIG, DWORD);
a341a967 1336 HMODULE hConfigModule;
568a91df 1337 BOOL r = FALSE;
a341a967 1338
d7e88ff9 1339 TRACE("(%s, %p, %u)\n", debugstr_w(lpszDevice), lpCommConfig, dwSize);
a341a967 1340
568a91df 1341 hConfigModule = LoadLibraryW(lpszSerialUI);
a341a967 1342 if(!hConfigModule)
568a91df 1343 return r;
a341a967 1344
858f0878 1345 lpfnSetDefaultCommConfig = (void *)GetProcAddress(hConfigModule, "drvSetDefaultCommConfigW");
568a91df
MM
1346 if (lpfnSetDefaultCommConfig)
1347 r = lpfnSetDefaultCommConfig(lpszDevice, lpCommConfig, dwSize);
a341a967 1348
568a91df 1349 FreeLibrary(hConfigModule);
a341a967
MM
1350
1351 return r;
1352}
1353
1354
1355/***********************************************************************
f2e7c43d 1356 * SetDefaultCommConfigA (KERNEL32.@)
a341a967 1357 *
f2e7c43d 1358 * Initializes the default configuration for a communication device.
03131aae 1359 *
f2e7c43d 1360 * See SetDefaultCommConfigW.
03131aae 1361 *
a341a967 1362 */
f2e7c43d 1363BOOL WINAPI SetDefaultCommConfigA(LPCSTR lpszDevice, LPCOMMCONFIG lpCommConfig, DWORD dwSize)
bca4a8dc 1364{
a341a967 1365 BOOL r;
568a91df
MM
1366 LPWSTR lpDeviceW = NULL;
1367 DWORD len;
a341a967 1368
d7e88ff9 1369 TRACE("(%s, %p, %u)\n", debugstr_a(lpszDevice), lpCommConfig, dwSize);
a341a967 1370
568a91df
MM
1371 if (lpszDevice)
1372 {
1373 len = MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, NULL, 0 );
1374 lpDeviceW = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
1375 MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, lpDeviceW, len );
1376 }
1377 r = SetDefaultCommConfigW(lpDeviceW,lpCommConfig,dwSize);
5ad7d858 1378 HeapFree( GetProcessHeap(), 0, lpDeviceW );
a341a967
MM
1379 return r;
1380}
1381
1382
00e7c334 1383/***********************************************************************
14263ab0 1384 * GetDefaultCommConfigW (KERNEL32.@)
03131aae
AJ
1385 *
1386 * Acquires the default configuration of the specified communication device. (unicode)
1387 *
1388 * RETURNS
1389 *
1390 * True on successful reading of the default configuration,
1391 * if the device is not found or the buffer is too small.
00e7c334 1392 */
14263ab0
VB
1393BOOL WINAPI GetDefaultCommConfigW(
1394 LPCWSTR lpszName, /* [in] The unicode name of the device targeted for configuration. */
bca4a8dc
PS
1395 LPCOMMCONFIG lpCC, /* [out] The default configuration for the device. */
1396 LPDWORD lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
1397 afterwards the number of bytes copied to the buffer or
1398 the needed size of the buffer. */
03131aae 1399{
858f0878 1400 DWORD (WINAPI *pGetDefaultCommConfig)(LPCWSTR, LPCOMMCONFIG, LPDWORD);
ade9fd64
DR
1401 HMODULE hConfigModule;
1402 DWORD res = ERROR_INVALID_PARAMETER;
00e7c334 1403
ade9fd64
DR
1404 TRACE("(%s, %p, %p) *lpdwSize: %u\n", debugstr_w(lpszName), lpCC, lpdwSize, lpdwSize ? *lpdwSize : 0 );
1405 hConfigModule = LoadLibraryW(lpszSerialUI);
00e7c334 1406
ade9fd64 1407 if (hConfigModule) {
858f0878 1408 pGetDefaultCommConfig = (void *)GetProcAddress(hConfigModule, "drvGetDefaultCommConfigW");
ade9fd64
DR
1409 if (pGetDefaultCommConfig) {
1410 res = pGetDefaultCommConfig(lpszName, lpCC, lpdwSize);
1411 }
1412 FreeLibrary(hConfigModule);
1413 }
00e7c334 1414
ade9fd64
DR
1415 if (res) SetLastError(res);
1416 return (res == ERROR_SUCCESS);
00e7c334
SL
1417}
1418
1419/**************************************************************************
14263ab0 1420 * GetDefaultCommConfigA (KERNEL32.@)
03131aae 1421 *
14263ab0 1422 * Acquires the default configuration of the specified communication device. (ascii)
03131aae
AJ
1423 *
1424 * RETURNS
1425 *
1426 * True on successful reading of the default configuration,
1427 * if the device is not found or the buffer is too small.
00e7c334 1428 */
14263ab0
VB
1429BOOL WINAPI GetDefaultCommConfigA(
1430 LPCSTR lpszName, /* [in] The ascii name of the device targeted for configuration. */
bca4a8dc
PS
1431 LPCOMMCONFIG lpCC, /* [out] The default configuration for the device. */
1432 LPDWORD lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
1433 afterwards the number of bytes copied to the buffer or
1434 the needed size of the buffer. */
1435{
03131aae 1436 BOOL ret = FALSE;
14263ab0 1437 UNICODE_STRING lpszNameW;
00e7c334 1438
d7e88ff9 1439 TRACE("(%s, %p, %p) *lpdwSize: %u\n", debugstr_a(lpszName), lpCC, lpdwSize, lpdwSize ? *lpdwSize : 0 );
14263ab0
VB
1440 if(lpszName) RtlCreateUnicodeStringFromAsciiz(&lpszNameW,lpszName);
1441 else lpszNameW.Buffer = NULL;
1442
ade9fd64 1443 ret = GetDefaultCommConfigW(lpszNameW.Buffer,lpCC,lpdwSize);
14263ab0
VB
1444
1445 RtlFreeUnicodeString(&lpszNameW);
00e7c334
SL
1446 return ret;
1447}