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