xref: /reactos/dll/win32/kernel32/wine/comm.c (revision 2d4d5b63)
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  */
COMM_ParseStart(LPCWSTR ptr)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 
COMM_ParseNumber(LPCWSTR ptr,LPDWORD lpnumber)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 
COMM_ParseParity(LPCWSTR ptr,LPBYTE lpparity)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 
COMM_ParseByteSize(LPCWSTR ptr,LPBYTE lpbytesize)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 
COMM_ParseStopBits(LPCWSTR ptr,LPBYTE lpstopbits)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 
COMM_ParseOnOff(LPCWSTR ptr,LPDWORD lponoff)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  */
COMM_BuildOldCommDCB(LPCWSTR device,LPDCB lpdcb)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  */
COMM_BuildNewCommDCB(LPCWSTR device,LPDCB lpdcb,LPCOMMTIMEOUTS lptimeouts)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  */
BuildCommDCBA(LPCSTR device,LPDCB lpdcb)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  */
BuildCommDCBAndTimeoutsA(LPCSTR device,LPDCB lpdcb,LPCOMMTIMEOUTS lptimeouts)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  */
BuildCommDCBAndTimeoutsW(LPCWSTR devid,LPDCB lpdcb,LPCOMMTIMEOUTS lptimeouts)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  */
BuildCommDCBW(LPCWSTR devid,LPDCB lpdcb)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  */
SetCommBreak(HANDLE handle)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  */
ClearCommBreak(HANDLE handle)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  */
EscapeCommFunction(HANDLE handle,DWORD func)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  */
PurgeComm(HANDLE handle,DWORD flags)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  */
ClearCommError(HANDLE handle,LPDWORD errors,LPCOMSTAT lpStat)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  */
SetupComm(HANDLE handle,DWORD insize,DWORD outsize)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  */
GetCommMask(HANDLE handle,LPDWORD evtmask)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  */
SetCommMask(HANDLE handle,DWORD evtmask)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 
dump_dcb(const DCB * lpdcb)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  */
SetCommState(HANDLE handle,LPDCB lpdcb)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     TRACE("handle %p, ptr %p\n", handle, lpdcb);
816 
817     if (lpdcb == NULL)
818     {
819         SetLastError(ERROR_INVALID_PARAMETER);
820         return FALSE;
821     }
822     dump_dcb(lpdcb);
823 
824     sbr.BaudRate = lpdcb->BaudRate;
825 
826     slc.StopBits = lpdcb->StopBits;
827     slc.Parity = lpdcb->Parity;
828     slc.WordLength = lpdcb->ByteSize;
829 
830     shf.ControlHandShake = 0;
831     shf.FlowReplace = 0;
832     if (lpdcb->fOutxCtsFlow)      shf.ControlHandShake |= SERIAL_CTS_HANDSHAKE;
833     if (lpdcb->fOutxDsrFlow)      shf.ControlHandShake |= SERIAL_DSR_HANDSHAKE;
834     switch (lpdcb->fDtrControl)
835     {
836     case DTR_CONTROL_DISABLE:                                                  break;
837     case DTR_CONTROL_ENABLE:      shf.ControlHandShake |= SERIAL_DTR_CONTROL;  break;
838     case DTR_CONTROL_HANDSHAKE:   shf.ControlHandShake |= SERIAL_DTR_HANDSHAKE;break;
839     default:
840         SetLastError(ERROR_INVALID_PARAMETER);
841         return FALSE;
842     }
843     switch (lpdcb->fRtsControl)
844     {
845     case RTS_CONTROL_DISABLE:                                                  break;
846     case RTS_CONTROL_ENABLE:      shf.FlowReplace |= SERIAL_RTS_CONTROL;       break;
847     case RTS_CONTROL_HANDSHAKE:   shf.FlowReplace |= SERIAL_RTS_HANDSHAKE;     break;
848     case RTS_CONTROL_TOGGLE:      shf.FlowReplace |= SERIAL_RTS_CONTROL |
849                                                      SERIAL_RTS_HANDSHAKE;     break;
850     default:
851         SetLastError(ERROR_INVALID_PARAMETER);
852         return FALSE;
853     }
854     if (lpdcb->fDsrSensitivity)   shf.ControlHandShake |= SERIAL_DSR_SENSITIVITY;
855     if (lpdcb->fAbortOnError)     shf.ControlHandShake |= SERIAL_ERROR_ABORT;
856 
857     if (lpdcb->fErrorChar)        shf.FlowReplace |= SERIAL_ERROR_CHAR;
858     if (lpdcb->fNull)             shf.FlowReplace |= SERIAL_NULL_STRIPPING;
859     if (lpdcb->fTXContinueOnXoff) shf.FlowReplace |= SERIAL_XOFF_CONTINUE;
860     if (lpdcb->fOutX)             shf.FlowReplace |= SERIAL_AUTO_TRANSMIT;
861     if (lpdcb->fInX)              shf.FlowReplace |= SERIAL_AUTO_RECEIVE;
862 
863     shf.XonLimit = lpdcb->XonLim;
864     shf.XoffLimit = lpdcb->XoffLim;
865 
866     sc.EofChar = lpdcb->EofChar;
867     sc.ErrorChar = lpdcb->ErrorChar;
868     sc.BreakChar = 0;
869     sc.EventChar = lpdcb->EvtChar;
870     sc.XonChar = lpdcb->XonChar;
871     sc.XoffChar = lpdcb->XoffChar;
872 
873     /* note: change DTR/RTS lines after setting the comm attributes,
874      * so flow control does not interfere.
875      */
876     return (DeviceIoControl(handle, IOCTL_SERIAL_SET_BAUD_RATE,
877                             &sbr, sizeof(sbr), NULL, 0, &dwBytesReturned, NULL) &&
878             DeviceIoControl(handle, IOCTL_SERIAL_SET_LINE_CONTROL,
879                             &slc, sizeof(slc), NULL, 0, &dwBytesReturned, NULL) &&
880             DeviceIoControl(handle, IOCTL_SERIAL_SET_HANDFLOW,
881                             &shf, sizeof(shf), NULL, 0, &dwBytesReturned, NULL) &&
882             DeviceIoControl(handle, IOCTL_SERIAL_SET_CHARS,
883                             &sc, sizeof(sc), NULL, 0, &dwBytesReturned, NULL));
884 }
885 
886 
887 /*****************************************************************************
888  *	GetCommState	(KERNEL32.@)
889  *
890  *  Fills in a device control block with information from a communications device.
891  *
892  * PARAMS
893  *      handle          [in]    The communications device
894  *      lpdcb           [out]   The device control block
895  *
896  * RETURNS
897  *
898  *  True on success, false if the communication device handle is bad etc
899  *
900  * BUGS
901  *
902  *  XonChar and XoffChar are not set.
903  */
GetCommState(HANDLE handle,LPDCB lpdcb)904 BOOL WINAPI GetCommState(HANDLE handle, LPDCB lpdcb)
905 {
906     SERIAL_BAUD_RATE    sbr;
907     SERIAL_LINE_CONTROL slc;
908     SERIAL_HANDFLOW     shf;
909     SERIAL_CHARS        sc;
910     DWORD dwBytesReturned;
911 
912     TRACE("handle %p, ptr %p\n", handle, lpdcb);
913 
914     if (!lpdcb)
915     {
916         SetLastError(ERROR_INVALID_PARAMETER);
917         return FALSE;
918     }
919 
920     if (!DeviceIoControl(handle, IOCTL_SERIAL_GET_BAUD_RATE,
921                          NULL, 0, &sbr, sizeof(sbr), &dwBytesReturned, NULL) ||
922         !DeviceIoControl(handle, IOCTL_SERIAL_GET_LINE_CONTROL,
923                          NULL, 0, &slc, sizeof(slc), &dwBytesReturned, NULL) ||
924         !DeviceIoControl(handle, IOCTL_SERIAL_GET_HANDFLOW,
925                          NULL, 0, &shf, sizeof(shf), &dwBytesReturned, NULL) ||
926         !DeviceIoControl(handle, IOCTL_SERIAL_GET_CHARS,
927                          NULL, 0, &sc, sizeof(sc), &dwBytesReturned, NULL))
928         return FALSE;
929 
930     memset(lpdcb, 0, sizeof(*lpdcb));
931     lpdcb->DCBlength = sizeof(*lpdcb);
932 
933     /* yes, they seem no never be (re)set on NT */
934     lpdcb->fBinary = 1;
935     lpdcb->fParity = 0;
936 
937     lpdcb->BaudRate = sbr.BaudRate;
938 
939     lpdcb->StopBits = slc.StopBits;
940     lpdcb->Parity = slc.Parity;
941     lpdcb->ByteSize = slc.WordLength;
942 
943     if (shf.ControlHandShake & SERIAL_CTS_HANDSHAKE)    lpdcb->fOutxCtsFlow = 1;
944     if (shf.ControlHandShake & SERIAL_DSR_HANDSHAKE)    lpdcb->fOutxDsrFlow = 1;
945     switch (shf.ControlHandShake & (SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE))
946     {
947     case 0:                     lpdcb->fDtrControl = DTR_CONTROL_DISABLE; break;
948     case SERIAL_DTR_CONTROL:    lpdcb->fDtrControl = DTR_CONTROL_ENABLE; break;
949     case SERIAL_DTR_HANDSHAKE:  lpdcb->fDtrControl = DTR_CONTROL_HANDSHAKE; break;
950     }
951     switch (shf.FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE))
952     {
953     case 0:                     lpdcb->fRtsControl = RTS_CONTROL_DISABLE; break;
954     case SERIAL_RTS_CONTROL:    lpdcb->fRtsControl = RTS_CONTROL_ENABLE; break;
955     case SERIAL_RTS_HANDSHAKE:  lpdcb->fRtsControl = RTS_CONTROL_HANDSHAKE; break;
956     case SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE:
957                                 lpdcb->fRtsControl = RTS_CONTROL_TOGGLE; break;
958     }
959     if (shf.ControlHandShake & SERIAL_DSR_SENSITIVITY)  lpdcb->fDsrSensitivity = 1;
960     if (shf.ControlHandShake & SERIAL_ERROR_ABORT)      lpdcb->fAbortOnError = 1;
961     if (shf.FlowReplace & SERIAL_ERROR_CHAR)            lpdcb->fErrorChar = 1;
962     if (shf.FlowReplace & SERIAL_NULL_STRIPPING)        lpdcb->fNull = 1;
963     if (shf.FlowReplace & SERIAL_XOFF_CONTINUE)         lpdcb->fTXContinueOnXoff = 1;
964     lpdcb->XonLim = shf.XonLimit;
965     lpdcb->XoffLim = shf.XoffLimit;
966 
967     if (shf.FlowReplace & SERIAL_AUTO_TRANSMIT) lpdcb->fOutX = 1;
968     if (shf.FlowReplace & SERIAL_AUTO_RECEIVE)  lpdcb->fInX = 1;
969 
970     lpdcb->EofChar = sc.EofChar;
971     lpdcb->ErrorChar = sc.ErrorChar;
972     lpdcb->EvtChar = sc.EventChar;
973     lpdcb->XonChar = sc.XonChar;
974     lpdcb->XoffChar = sc.XoffChar;
975 
976     TRACE("OK\n");
977     dump_dcb(lpdcb);
978 
979     return TRUE;
980 }
981 
982 /*****************************************************************************
983  *	TransmitCommChar	(KERNEL32.@)
984  *
985  *  Transmits a single character in front of any pending characters in the
986  *  output buffer.  Usually used to send an interrupt character to a host.
987  *
988  * PARAMS
989  *      hComm           [in]    The communication device in need of a command character
990  *      chTransmit      [in]    The character to transmit
991  *
992  * RETURNS
993  *
994  *  True if the call succeeded, false if the previous command character to the
995  *  same device has not been sent yet the handle is bad etc.
996  *
997  */
TransmitCommChar(HANDLE hComm,CHAR chTransmit)998 BOOL WINAPI TransmitCommChar(HANDLE hComm, CHAR chTransmit)
999 {
1000     DWORD dwBytesReturned;
1001     return DeviceIoControl(hComm, IOCTL_SERIAL_IMMEDIATE_CHAR,
1002                            &chTransmit, sizeof(chTransmit), NULL, 0, &dwBytesReturned, NULL);
1003 }
1004 
1005 
1006 /*****************************************************************************
1007  *	GetCommTimeouts		(KERNEL32.@)
1008  *
1009  *  Obtains the request timeout values for the communications device.
1010  *
1011  * PARAMS
1012  *      hComm           [in]    The communications device
1013  *      lptimeouts      [out]   The struct of request timeouts
1014  *
1015  * RETURNS
1016  *
1017  *  True on success, false if communications device handle is bad
1018  *  or the target structure is null.
1019  */
GetCommTimeouts(HANDLE hComm,LPCOMMTIMEOUTS lptimeouts)1020 BOOL WINAPI GetCommTimeouts(HANDLE hComm, LPCOMMTIMEOUTS lptimeouts)
1021 {
1022     SERIAL_TIMEOUTS     st;
1023     DWORD dwBytesReturned;
1024 
1025     TRACE("(%p, %p)\n", hComm, lptimeouts);
1026     if (!lptimeouts)
1027     {
1028         SetLastError(ERROR_INVALID_PARAMETER);
1029         return FALSE;
1030     }
1031     if (!DeviceIoControl(hComm, IOCTL_SERIAL_GET_TIMEOUTS,
1032                          NULL, 0, &st, sizeof(st), &dwBytesReturned, NULL))
1033         return FALSE;
1034     lptimeouts->ReadIntervalTimeout         = st.ReadIntervalTimeout;
1035     lptimeouts->ReadTotalTimeoutMultiplier  = st.ReadTotalTimeoutMultiplier;
1036     lptimeouts->ReadTotalTimeoutConstant    = st.ReadTotalTimeoutConstant;
1037     lptimeouts->WriteTotalTimeoutMultiplier = st.WriteTotalTimeoutMultiplier;
1038     lptimeouts->WriteTotalTimeoutConstant   = st.WriteTotalTimeoutConstant;
1039     return TRUE;
1040 }
1041 
1042 /*****************************************************************************
1043  *	SetCommTimeouts		(KERNEL32.@)
1044  *
1045  * Sets the timeouts used when reading and writing data to/from COMM ports.
1046  *
1047  * PARAMS
1048  *      hComm           [in]    handle of COMM device
1049  *      lptimeouts      [in]    pointer to COMMTIMEOUTS structure
1050  *
1051  * ReadIntervalTimeout
1052  *     - converted and passes to linux kernel as c_cc[VTIME]
1053  * ReadTotalTimeoutMultiplier, ReadTotalTimeoutConstant
1054  *     - used in ReadFile to calculate GetOverlappedResult's timeout
1055  * WriteTotalTimeoutMultiplier, WriteTotalTimeoutConstant
1056  *     - used in WriteFile to calculate GetOverlappedResult's timeout
1057  *
1058  * RETURNS
1059  *
1060  *  True if the timeouts were set, false otherwise.
1061  */
SetCommTimeouts(HANDLE hComm,LPCOMMTIMEOUTS lptimeouts)1062 BOOL WINAPI SetCommTimeouts(HANDLE hComm, LPCOMMTIMEOUTS lptimeouts)
1063 {
1064     SERIAL_TIMEOUTS     st;
1065     DWORD dwBytesReturned;
1066 
1067     TRACE("(%p, %p)\n", hComm, lptimeouts);
1068 
1069     if (lptimeouts == NULL)
1070     {
1071         SetLastError(ERROR_INVALID_PARAMETER);
1072         return FALSE;
1073     }
1074     st.ReadIntervalTimeout         = lptimeouts->ReadIntervalTimeout;
1075     st.ReadTotalTimeoutMultiplier  = lptimeouts->ReadTotalTimeoutMultiplier;
1076     st.ReadTotalTimeoutConstant    = lptimeouts->ReadTotalTimeoutConstant;
1077     st.WriteTotalTimeoutMultiplier = lptimeouts->WriteTotalTimeoutMultiplier;
1078     st.WriteTotalTimeoutConstant   = lptimeouts->WriteTotalTimeoutConstant;
1079 
1080     return DeviceIoControl(hComm, IOCTL_SERIAL_SET_TIMEOUTS,
1081                            &st, sizeof(st), NULL, 0, &dwBytesReturned, NULL);
1082 }
1083 
1084 /***********************************************************************
1085  *           GetCommModemStatus   (KERNEL32.@)
1086  *
1087  *  Obtains the four control register bits if supported by the hardware.
1088  *
1089  * PARAMS
1090  *
1091  *      hFile           [in]    The communications device
1092  *      lpModemStat     [out]   The control register bits
1093  *
1094  * RETURNS
1095  *
1096  *  True if the communications handle was good and for hardware that
1097  *  control register access, false otherwise.
1098  */
GetCommModemStatus(HANDLE hFile,LPDWORD lpModemStat)1099 BOOL WINAPI GetCommModemStatus(HANDLE hFile, LPDWORD lpModemStat)
1100 {
1101     DWORD dwBytesReturned;
1102     return DeviceIoControl(hFile, IOCTL_SERIAL_GET_MODEMSTATUS,
1103                            NULL, 0, lpModemStat, sizeof(DWORD), &dwBytesReturned, NULL);
1104 }
1105 
1106 /***********************************************************************
1107  *           WaitCommEvent   (KERNEL32.@)
1108  *
1109  * Wait until something interesting happens on a COMM port.
1110  * Interesting things (events) are set by calling SetCommMask before
1111  * this function is called.
1112  *
1113  * RETURNS
1114  *   TRUE if successful
1115  *   FALSE if failure
1116  *
1117  *   The set of detected events will be written to *lpdwEventMask
1118  *   ERROR_IO_PENDING will be returned the overlapped structure was passed
1119  *
1120  * BUGS:
1121  *  Only supports EV_RXCHAR and EV_TXEMPTY
1122  */
WaitCommEvent(HANDLE hFile,LPDWORD lpdwEvents,LPOVERLAPPED lpOverlapped)1123 BOOL WINAPI WaitCommEvent(
1124     HANDLE hFile,              /* [in] handle of comm port to wait for */
1125     LPDWORD lpdwEvents,        /* [out] event(s) that were detected */
1126     LPOVERLAPPED lpOverlapped) /* [in/out] for Asynchronous waiting */
1127 {
1128     return DeviceIoControl(hFile, IOCTL_SERIAL_WAIT_ON_MASK, NULL, 0,
1129                            lpdwEvents, sizeof(DWORD), NULL, lpOverlapped);
1130 }
1131 
1132 /***********************************************************************
1133  *           GetCommProperties   (KERNEL32.@)
1134  *
1135  * This function fills in a structure with the capabilities of the
1136  * communications port driver.
1137  *
1138  * RETURNS
1139  *
1140  *  TRUE on success, FALSE on failure
1141  *  If successful, the lpCommProp structure be filled in with
1142  *  properties of the comm port.
1143  */
GetCommProperties(HANDLE hFile,LPCOMMPROP lpCommProp)1144 BOOL WINAPI GetCommProperties(
1145     HANDLE hFile,          /* [in] handle of the comm port */
1146     LPCOMMPROP lpCommProp) /* [out] pointer to struct to be filled */
1147 {
1148     TRACE("(%p %p)\n",hFile,lpCommProp);
1149     if(!lpCommProp)
1150         return FALSE;
1151 
1152     /*
1153      * These values should be valid for LINUX's serial driver
1154      * FIXME: Perhaps they deserve an #ifdef LINUX
1155      */
1156     memset(lpCommProp,0,sizeof(COMMPROP));
1157     lpCommProp->wPacketLength       = 1;
1158     lpCommProp->wPacketVersion      = 1;
1159     lpCommProp->dwServiceMask       = SP_SERIALCOMM;
1160     lpCommProp->dwMaxTxQueue        = 4096;
1161     lpCommProp->dwMaxRxQueue        = 4096;
1162     lpCommProp->dwMaxBaud           = BAUD_115200;
1163     lpCommProp->dwProvSubType       = PST_RS232;
1164     lpCommProp->dwProvCapabilities  = PCF_DTRDSR | PCF_PARITY_CHECK | PCF_RTSCTS | PCF_TOTALTIMEOUTS;
1165     lpCommProp->dwSettableParams    = SP_BAUD | SP_DATABITS | SP_HANDSHAKING |
1166                                       SP_PARITY | SP_PARITY_CHECK | SP_STOPBITS ;
1167     lpCommProp->dwSettableBaud      = BAUD_075 | BAUD_110 | BAUD_134_5 | BAUD_150 |
1168                 BAUD_300 | BAUD_600 | BAUD_1200 | BAUD_1800 | BAUD_2400 | BAUD_4800 |
1169                 BAUD_9600 | BAUD_19200 | BAUD_38400 | BAUD_57600 | BAUD_115200 ;
1170     lpCommProp->wSettableData       = DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8 ;
1171     lpCommProp->wSettableStopParity = STOPBITS_10 | STOPBITS_15 | STOPBITS_20 |
1172                 PARITY_NONE | PARITY_ODD |PARITY_EVEN | PARITY_MARK | PARITY_SPACE;
1173     lpCommProp->dwCurrentTxQueue    = lpCommProp->dwMaxTxQueue;
1174     lpCommProp->dwCurrentRxQueue    = lpCommProp->dwMaxRxQueue;
1175 
1176     return TRUE;
1177 }
1178 
1179 /***********************************************************************
1180  * FIXME:
1181  * The functionality of CommConfigDialogA, GetDefaultCommConfig and
1182  * SetDefaultCommConfig is implemented in a DLL (usually SERIALUI.DLL).
1183  * This is dependent on the type of COMM port, but since it is doubtful
1184  * anybody will get around to implementing support for fancy serial
1185  * ports in WINE, this is hardcoded for the time being.  The name of
1186  * this DLL should be stored in and read from the system registry in
1187  * the hive HKEY_LOCAL_MACHINE, key
1188  * System\\CurrentControlSet\\Services\\Class\\Ports\\????
1189  * where ???? is the port number... that is determined by PNP
1190  * The DLL should be loaded when the COMM port is opened, and closed
1191  * when the COMM port is closed. - MJM 20 June 2000
1192  ***********************************************************************/
1193 static const WCHAR lpszSerialUI[] = {
1194    's','e','r','i','a','l','u','i','.','d','l','l',0 };
1195 
1196 
1197 /***********************************************************************
1198  *           CommConfigDialogA   (KERNEL32.@)
1199  *
1200  * Raises a dialog that allows the user to configure a comm port.
1201  * Fills the COMMCONFIG struct with information specified by the user.
1202  * This function should call a similar routine in the COMM driver...
1203  *
1204  * RETURNS
1205  *
1206  *  TRUE on success, FALSE on failure
1207  *  If successful, the lpCommConfig structure will contain a new
1208  *  configuration for the comm port, as specified by the user.
1209  *
1210  * BUGS
1211  *  The library with the CommConfigDialog code is never unloaded.
1212  * Perhaps this should be done when the comm port is closed?
1213  */
CommConfigDialogA(LPCSTR lpszDevice,HWND hWnd,LPCOMMCONFIG lpCommConfig)1214 BOOL WINAPI CommConfigDialogA(
1215     LPCSTR lpszDevice,         /* [in] name of communications device */
1216     HWND hWnd,                 /* [in] parent window for the dialog */
1217     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
1218 {
1219     LPWSTR  lpDeviceW = NULL;
1220     DWORD   len;
1221     BOOL    r;
1222 
1223     TRACE("(%s, %p, %p)\n", debugstr_a(lpszDevice), hWnd, lpCommConfig);
1224 
1225     if (lpszDevice)
1226     {
1227         len = MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, NULL, 0 );
1228         lpDeviceW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
1229         MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, lpDeviceW, len );
1230     }
1231     r = CommConfigDialogW(lpDeviceW, hWnd, lpCommConfig);
1232     HeapFree( GetProcessHeap(), 0, lpDeviceW );
1233     return r;
1234 }
1235 
1236 /***********************************************************************
1237  *           CommConfigDialogW   (KERNEL32.@)
1238  *
1239  * See CommConfigDialogA.
1240  */
CommConfigDialogW(LPCWSTR lpszDevice,HWND hWnd,LPCOMMCONFIG lpCommConfig)1241 BOOL WINAPI CommConfigDialogW(
1242     LPCWSTR lpszDevice,        /* [in] name of communications device */
1243     HWND hWnd,                 /* [in] parent window for the dialog */
1244     LPCOMMCONFIG lpCommConfig) /* [out] pointer to struct to fill */
1245 {
1246     DWORD (WINAPI *pCommConfigDialog)(LPCWSTR, HWND, LPCOMMCONFIG);
1247     HMODULE hConfigModule;
1248     DWORD   res = ERROR_INVALID_PARAMETER;
1249 
1250     TRACE("(%s, %p, %p)\n", debugstr_w(lpszDevice), hWnd, lpCommConfig);
1251     hConfigModule = LoadLibraryW(lpszSerialUI);
1252 
1253     if (hConfigModule) {
1254         pCommConfigDialog = (void *)GetProcAddress(hConfigModule, "drvCommConfigDialogW");
1255         if (pCommConfigDialog) {
1256             res = pCommConfigDialog(lpszDevice, hWnd, lpCommConfig);
1257         }
1258         FreeLibrary(hConfigModule);
1259     }
1260 
1261     if (res) SetLastError(res);
1262     return (res == ERROR_SUCCESS);
1263 }
1264 
1265 /***********************************************************************
1266  *           GetCommConfig     (KERNEL32.@)
1267  *
1268  * Fill in the COMMCONFIG structure for the comm port hFile
1269  *
1270  * RETURNS
1271  *
1272  *  TRUE on success, FALSE on failure
1273  *  If successful, lpCommConfig contains the comm port configuration.
1274  *
1275  * BUGS
1276  *
1277  */
GetCommConfig(HANDLE hFile,LPCOMMCONFIG lpCommConfig,LPDWORD lpdwSize)1278 BOOL WINAPI GetCommConfig(
1279     HANDLE       hFile,        /* [in] The communications device. */
1280     LPCOMMCONFIG lpCommConfig, /* [out] The communications configuration of the device (if it fits). */
1281     LPDWORD      lpdwSize)     /* [in/out] Initially the size of the configuration buffer/structure,
1282                                   afterwards the number of bytes copied to the buffer or
1283                                   the needed size of the buffer. */
1284 {
1285     BOOL r;
1286 
1287     TRACE("(%p, %p, %p) *lpdwSize: %u\n", hFile, lpCommConfig, lpdwSize, lpdwSize ? *lpdwSize : 0 );
1288 
1289     if(lpCommConfig == NULL)
1290         return FALSE;
1291     r = *lpdwSize < sizeof(COMMCONFIG); /* TRUE if not enough space */
1292     *lpdwSize = sizeof(COMMCONFIG);
1293     if(r)
1294         return FALSE;
1295 
1296     lpCommConfig->dwSize = sizeof(COMMCONFIG);
1297     lpCommConfig->wVersion = 1;
1298     lpCommConfig->wReserved = 0;
1299     r = GetCommState(hFile,&lpCommConfig->dcb);
1300     lpCommConfig->dwProviderSubType = PST_RS232;
1301     lpCommConfig->dwProviderOffset = 0;
1302     lpCommConfig->dwProviderSize = 0;
1303 
1304     return r;
1305 }
1306 
1307 /***********************************************************************
1308  *           SetCommConfig     (KERNEL32.@)
1309  *
1310  *  Sets the configuration of the communications device.
1311  *
1312  * RETURNS
1313  *
1314  *  True on success, false if the handle was bad is not a communications device.
1315  */
SetCommConfig(HANDLE hFile,LPCOMMCONFIG lpCommConfig,DWORD dwSize)1316 BOOL WINAPI SetCommConfig(
1317     HANDLE       hFile,		/* [in] The communications device. */
1318     LPCOMMCONFIG lpCommConfig,	/* [in] The desired configuration. */
1319     DWORD dwSize) 		/* [in] size of the lpCommConfig struct */
1320 {
1321     TRACE("(%p, %p, %u)\n", hFile, lpCommConfig, dwSize);
1322     return SetCommState(hFile,&lpCommConfig->dcb);
1323 }
1324 
1325 /***********************************************************************
1326  *           SetDefaultCommConfigW  (KERNEL32.@)
1327  *
1328  * Initializes the default configuration for a communication device.
1329  *
1330  * PARAMS
1331  *  lpszDevice   [I] Name of the device targeted for configuration
1332  *  lpCommConfig [I] PTR to a buffer with the configuration for the device
1333  *  dwSize       [I] Number of bytes in the buffer
1334  *
1335  * RETURNS
1336  *  Failure: FALSE
1337  *  Success: TRUE, and default configuration saved
1338  *
1339  */
SetDefaultCommConfigW(LPCWSTR lpszDevice,LPCOMMCONFIG lpCommConfig,DWORD dwSize)1340 BOOL WINAPI SetDefaultCommConfigW(LPCWSTR lpszDevice, LPCOMMCONFIG lpCommConfig, DWORD dwSize)
1341 {
1342     BOOL (WINAPI *lpfnSetDefaultCommConfig)(LPCWSTR, LPCOMMCONFIG, DWORD);
1343     HMODULE hConfigModule;
1344     BOOL r = FALSE;
1345 
1346     TRACE("(%s, %p, %u)\n", debugstr_w(lpszDevice), lpCommConfig, dwSize);
1347 
1348     hConfigModule = LoadLibraryW(lpszSerialUI);
1349     if(!hConfigModule)
1350         return r;
1351 
1352     lpfnSetDefaultCommConfig = (void *)GetProcAddress(hConfigModule, "drvSetDefaultCommConfigW");
1353     if (lpfnSetDefaultCommConfig)
1354         r = lpfnSetDefaultCommConfig(lpszDevice, lpCommConfig, dwSize);
1355 
1356     FreeLibrary(hConfigModule);
1357 
1358     return r;
1359 }
1360 
1361 
1362 /***********************************************************************
1363  *           SetDefaultCommConfigA     (KERNEL32.@)
1364  *
1365  * Initializes the default configuration for a communication device.
1366  *
1367  * See SetDefaultCommConfigW.
1368  *
1369  */
SetDefaultCommConfigA(LPCSTR lpszDevice,LPCOMMCONFIG lpCommConfig,DWORD dwSize)1370 BOOL WINAPI SetDefaultCommConfigA(LPCSTR lpszDevice, LPCOMMCONFIG lpCommConfig, DWORD dwSize)
1371 {
1372     BOOL r;
1373     LPWSTR lpDeviceW = NULL;
1374     DWORD len;
1375 
1376     TRACE("(%s, %p, %u)\n", debugstr_a(lpszDevice), lpCommConfig, dwSize);
1377 
1378     if (lpszDevice)
1379     {
1380         len = MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, NULL, 0 );
1381         lpDeviceW = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
1382         MultiByteToWideChar( CP_ACP, 0, lpszDevice, -1, lpDeviceW, len );
1383     }
1384     r = SetDefaultCommConfigW(lpDeviceW,lpCommConfig,dwSize);
1385     HeapFree( GetProcessHeap(), 0, lpDeviceW );
1386     return r;
1387 }
1388 
1389 
1390 /***********************************************************************
1391  *           GetDefaultCommConfigW   (KERNEL32.@)
1392  *
1393  *   Acquires the default configuration of the specified communication device. (unicode)
1394  *
1395  *  RETURNS
1396  *
1397  *   True on successful reading of the default configuration,
1398  *   if the device is not found or the buffer is too small.
1399  */
GetDefaultCommConfigW(LPCWSTR lpszName,LPCOMMCONFIG lpCC,LPDWORD lpdwSize)1400 BOOL WINAPI GetDefaultCommConfigW(
1401     LPCWSTR      lpszName, /* [in] The unicode name of the device targeted for configuration. */
1402     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
1403     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
1404                               afterwards the number of bytes copied to the buffer or
1405                               the needed size of the buffer. */
1406 {
1407     DWORD (WINAPI *pGetDefaultCommConfig)(LPCWSTR, LPCOMMCONFIG, LPDWORD);
1408     HMODULE hConfigModule;
1409     DWORD   res = ERROR_INVALID_PARAMETER;
1410 
1411     TRACE("(%s, %p, %p)  *lpdwSize: %u\n", debugstr_w(lpszName), lpCC, lpdwSize, lpdwSize ? *lpdwSize : 0 );
1412     hConfigModule = LoadLibraryW(lpszSerialUI);
1413 
1414     if (hConfigModule) {
1415         pGetDefaultCommConfig = (void *)GetProcAddress(hConfigModule, "drvGetDefaultCommConfigW");
1416         if (pGetDefaultCommConfig) {
1417             res = pGetDefaultCommConfig(lpszName, lpCC, lpdwSize);
1418         }
1419         FreeLibrary(hConfigModule);
1420     }
1421 
1422     if (res) SetLastError(res);
1423     return (res == ERROR_SUCCESS);
1424 }
1425 
1426 /**************************************************************************
1427  *         GetDefaultCommConfigA		(KERNEL32.@)
1428  *
1429  *   Acquires the default configuration of the specified communication device. (ascii)
1430  *
1431  *  RETURNS
1432  *
1433  *   True on successful reading of the default configuration,
1434  *   if the device is not found or the buffer is too small.
1435  */
GetDefaultCommConfigA(LPCSTR lpszName,LPCOMMCONFIG lpCC,LPDWORD lpdwSize)1436 BOOL WINAPI GetDefaultCommConfigA(
1437     LPCSTR       lpszName, /* [in] The ascii name of the device targeted for configuration. */
1438     LPCOMMCONFIG lpCC,     /* [out] The default configuration for the device. */
1439     LPDWORD      lpdwSize) /* [in/out] Initially the size of the default configuration buffer,
1440 			      afterwards the number of bytes copied to the buffer or
1441                               the needed size of the buffer. */
1442 {
1443 	BOOL ret = FALSE;
1444 	UNICODE_STRING lpszNameW;
1445 
1446 	TRACE("(%s, %p, %p)  *lpdwSize: %u\n", debugstr_a(lpszName), lpCC, lpdwSize, lpdwSize ? *lpdwSize : 0 );
1447 	if(lpszName) RtlCreateUnicodeStringFromAsciiz(&lpszNameW,lpszName);
1448 	else lpszNameW.Buffer = NULL;
1449 
1450 	ret = GetDefaultCommConfigW(lpszNameW.Buffer,lpCC,lpdwSize);
1451 
1452 	RtlFreeUnicodeString(&lpszNameW);
1453 	return ret;
1454 }
1455