2 * DEC 93 Erik Bos <erik@xs4all.nl>
4 * Copyright 1996 Marcus Meissner
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.
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.
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
31 #include "ddk/ntddser.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(comm
);
37 /***********************************************************************
38 * COMM_Parse* (Internal)
40 * The following COMM_Parse* functions are used by the BuildCommDCB
41 * functions to help parse the various parts of the device control string.
43 static LPCWSTR
COMM_ParseStart(LPCWSTR ptr
)
45 /* The device control string may optionally start with "COMx" followed
46 by an optional ':' and spaces. */
47 if(!wcsnicmp(ptr
, L
"COM", 3))
51 /* Allow any com port above 0 as Win 9x does (NT only allows
52 values for com ports which are actually present) */
53 if(*ptr
< '1' || *ptr
> '9')
56 /* Advance pointer past port number */
57 while(*ptr
>= '0' && *ptr
<= '9') ptr
++;
59 /* The com port number must be followed by a ':' or ' ' */
60 if(*ptr
!= ':' && *ptr
!= ' ')
63 /* Advance pointer to beginning of next parameter */
64 while(*ptr
== ' ') ptr
++;
68 while(*ptr
== ' ') ptr
++;
71 /* The device control string must not start with a space. */
78 static LPCWSTR
COMM_ParseNumber(LPCWSTR ptr
, LPDWORD lpnumber
)
80 if(*ptr
< '0' || *ptr
> '9') return NULL
;
81 *lpnumber
= wcstoul(ptr
, NULL
, 10);
82 while(*ptr
>= '0' && *ptr
<= '9') ptr
++;
86 static LPCWSTR
COMM_ParseParity(LPCWSTR ptr
, LPBYTE lpparity
)
88 /* Contrary to what you might expect, Windows only sets the Parity
89 member of DCB and not fParity even when parity is specified in the
90 device control string */
96 *lpparity
= EVENPARITY
;
100 *lpparity
= MARKPARITY
;
104 *lpparity
= NOPARITY
;
108 *lpparity
= ODDPARITY
;
112 *lpparity
= SPACEPARITY
;
121 static LPCWSTR
COMM_ParseByteSize(LPCWSTR ptr
, LPBYTE lpbytesize
)
125 if(!(ptr
= COMM_ParseNumber(ptr
, &temp
)))
128 if(temp
>= 5 && temp
<= 8)
137 static LPCWSTR
COMM_ParseStopBits(LPCWSTR ptr
, LPBYTE lpstopbits
)
141 if(!wcsncmp(L
"1.5", ptr
, 3))
144 *lpstopbits
= ONE5STOPBITS
;
148 if(!(ptr
= COMM_ParseNumber(ptr
, &temp
)))
152 *lpstopbits
= ONESTOPBIT
;
154 *lpstopbits
= TWOSTOPBITS
;
162 static LPCWSTR
COMM_ParseOnOff(LPCWSTR ptr
, LPDWORD lponoff
)
164 if(!wcsnicmp(L
"on", ptr
, 2))
169 else if(!wcsnicmp(L
"off", ptr
, 3))
180 /***********************************************************************
181 * COMM_BuildOldCommDCB (Internal)
183 * Build a DCB using the old style settings string eg: "96,n,8,1"
185 static BOOL
COMM_BuildOldCommDCB(LPCWSTR device
, LPDCB lpdcb
)
189 if(!(device
= COMM_ParseNumber(device
, &lpdcb
->BaudRate
)))
192 switch(lpdcb
->BaudRate
)
197 lpdcb
->BaudRate
*= 10;
203 lpdcb
->BaudRate
*= 100;
206 lpdcb
->BaudRate
= 19200;
210 while(*device
== ' ') device
++;
211 if(*device
++ != ',') return FALSE
;
212 while(*device
== ' ') device
++;
214 if(!(device
= COMM_ParseParity(device
, &lpdcb
->Parity
)))
217 while(*device
== ' ') device
++;
218 if(*device
++ != ',') return FALSE
;
219 while(*device
== ' ') device
++;
221 if(!(device
= COMM_ParseByteSize(device
, &lpdcb
->ByteSize
)))
224 while(*device
== ' ') device
++;
225 if(*device
++ != ',') return FALSE
;
226 while(*device
== ' ') device
++;
228 if(!(device
= COMM_ParseStopBits(device
, &lpdcb
->StopBits
)))
231 /* The last parameter for flow control is optional. */
232 while(*device
== ' ') device
++;
236 while(*device
== ' ') device
++;
237 if(*device
) last
= *device
++;
238 while(*device
== ' ') device
++;
241 /* Win NT sets the flow control members based on (or lack of) the last
242 parameter. Win 9x does not set these members. */
247 lpdcb
->fOutX
= FALSE
;
248 lpdcb
->fOutxCtsFlow
= FALSE
;
249 lpdcb
->fOutxDsrFlow
= FALSE
;
250 lpdcb
->fDtrControl
= DTR_CONTROL_ENABLE
;
251 lpdcb
->fRtsControl
= RTS_CONTROL_ENABLE
;
257 lpdcb
->fOutxCtsFlow
= FALSE
;
258 lpdcb
->fOutxDsrFlow
= FALSE
;
259 lpdcb
->fDtrControl
= DTR_CONTROL_ENABLE
;
260 lpdcb
->fRtsControl
= RTS_CONTROL_ENABLE
;
265 lpdcb
->fOutX
= FALSE
;
266 lpdcb
->fOutxCtsFlow
= TRUE
;
267 lpdcb
->fOutxDsrFlow
= TRUE
;
268 lpdcb
->fDtrControl
= DTR_CONTROL_HANDSHAKE
;
269 lpdcb
->fRtsControl
= RTS_CONTROL_HANDSHAKE
;
275 /* This should be the end of the string. */
276 if(*device
) return FALSE
;
281 /***********************************************************************
282 * COMM_BuildNewCommDCB (Internal)
284 * Build a DCB using the new style settings string.
285 * eg: "baud=9600 parity=n data=8 stop=1 xon=on to=on"
287 static BOOL
COMM_BuildNewCommDCB(LPCWSTR device
, LPDCB lpdcb
, LPCOMMTIMEOUTS lptimeouts
)
290 BOOL baud
= FALSE
, stop
= FALSE
;
294 while(*device
== ' ') device
++;
296 if(!wcsnicmp(L
"baud=", device
, 5))
300 if(!(device
= COMM_ParseNumber(device
+ 5, &lpdcb
->BaudRate
)))
303 else if(!wcsnicmp(L
"parity=", device
, 7))
305 if(!(device
= COMM_ParseParity(device
+ 7, &lpdcb
->Parity
)))
308 else if(!wcsnicmp(L
"data=", device
, 5))
310 if(!(device
= COMM_ParseByteSize(device
+ 5, &lpdcb
->ByteSize
)))
313 else if(!wcsnicmp(L
"stop=", device
, 5))
317 if(!(device
= COMM_ParseStopBits(device
+ 5, &lpdcb
->StopBits
)))
320 else if(!wcsnicmp(L
"to=", device
, 3))
322 if(!(device
= COMM_ParseOnOff(device
+ 3, &temp
)))
325 lptimeouts
->ReadIntervalTimeout
= 0;
326 lptimeouts
->ReadTotalTimeoutMultiplier
= 0;
327 lptimeouts
->ReadTotalTimeoutConstant
= 0;
328 lptimeouts
->WriteTotalTimeoutMultiplier
= 0;
329 lptimeouts
->WriteTotalTimeoutConstant
= temp
? 60000 : 0;
331 else if(!wcsnicmp(L
"xon=", device
, 4))
333 if(!(device
= COMM_ParseOnOff(device
+ 4, &temp
)))
339 else if(!wcsnicmp(L
"odsr=", device
, 5))
341 if(!(device
= COMM_ParseOnOff(device
+ 5, &temp
)))
344 lpdcb
->fOutxDsrFlow
= temp
;
346 else if(!wcsnicmp(L
"octs=", device
, 5))
348 if(!(device
= COMM_ParseOnOff(device
+ 5, &temp
)))
351 lpdcb
->fOutxCtsFlow
= temp
;
353 else if(!wcsnicmp(L
"dtr=", device
, 4))
355 if(!(device
= COMM_ParseOnOff(device
+ 4, &temp
)))
358 lpdcb
->fDtrControl
= temp
;
360 else if(!wcsnicmp(L
"rts=", device
, 4))
362 if(!(device
= COMM_ParseOnOff(device
+ 4, &temp
)))
365 lpdcb
->fRtsControl
= temp
;
367 else if(!wcsnicmp(L
"idsr=", device
, 5))
369 if(!(device
= COMM_ParseOnOff(device
+ 5, &temp
)))
372 /* Win NT sets the fDsrSensitivity member based on the
373 idsr parameter. Win 9x sets fOutxDsrFlow instead. */
374 lpdcb
->fDsrSensitivity
= temp
;
379 /* After the above parsing, the next character (if not the end of
380 the string) should be a space */
381 if(*device
&& *device
!= ' ')
385 /* If stop bits were not specified, a default is always supplied. */
388 if(baud
&& lpdcb
->BaudRate
== 110)
389 lpdcb
->StopBits
= TWOSTOPBITS
;
391 lpdcb
->StopBits
= ONESTOPBIT
;
397 /**************************************************************************
398 * BuildCommDCBA (KERNEL32.@)
400 * Updates a device control block data structure with values from an
401 * ANSI device control string. The device control string has two forms
402 * normal and extended, it must be exclusively in one or the other form.
406 * True on success, false on a malformed control string.
408 BOOL WINAPI
BuildCommDCBA(
409 LPCSTR device
, /* [in] The ANSI device control string used to update the DCB. */
410 LPDCB lpdcb
) /* [out] The device control block to be updated. */
412 return BuildCommDCBAndTimeoutsA(device
,lpdcb
,NULL
);
415 /**************************************************************************
416 * BuildCommDCBAndTimeoutsA (KERNEL32.@)
418 * Updates a device control block data structure with values from an
419 * ANSI device control string. Taking timeout values from a timeouts
420 * struct if desired by the control string.
424 * True on success, false bad handles etc.
426 BOOL WINAPI
BuildCommDCBAndTimeoutsA(
427 LPCSTR device
, /* [in] The ANSI device control string. */
428 LPDCB lpdcb
, /* [out] The device control block to be updated. */
429 LPCOMMTIMEOUTS lptimeouts
) /* [in] The COMMTIMEOUTS structure to be updated. */
432 UNICODE_STRING deviceW
;
434 TRACE("(%s,%p,%p)\n",device
,lpdcb
,lptimeouts
);
435 if(device
) RtlCreateUnicodeStringFromAsciiz(&deviceW
,device
);
436 else deviceW
.Buffer
= NULL
;
438 if(deviceW
.Buffer
) ret
= BuildCommDCBAndTimeoutsW(deviceW
.Buffer
,lpdcb
,lptimeouts
);
440 RtlFreeUnicodeString(&deviceW
);
444 /**************************************************************************
445 * BuildCommDCBAndTimeoutsW (KERNEL32.@)
447 * Updates a device control block data structure with values from a
448 * unicode device control string. Taking timeout values from a timeouts
449 * struct if desired by the control string.
453 * True on success, false bad handles etc
455 BOOL WINAPI
BuildCommDCBAndTimeoutsW(
456 LPCWSTR devid
, /* [in] The unicode device control string. */
457 LPDCB lpdcb
, /* [out] The device control block to be updated. */
458 LPCOMMTIMEOUTS lptimeouts
) /* [in] The COMMTIMEOUTS structure to be updated. */
461 COMMTIMEOUTS timeouts
;
465 TRACE("(%s,%p,%p)\n",debugstr_w(devid
),lpdcb
,lptimeouts
);
467 memset(&timeouts
, 0, sizeof timeouts
);
469 /* Set DCBlength. (Windows NT does not do this, but 9x does) */
470 lpdcb
->DCBlength
= sizeof(DCB
);
472 /* Make a copy of the original data structures to work with since if
473 if there is an error in the device control string the originals
474 should not be modified (except possibly DCBlength) */
476 if(lptimeouts
) timeouts
= *lptimeouts
;
478 ptr
= COMM_ParseStart(ptr
);
482 else if(wcschr(ptr
, ','))
483 result
= COMM_BuildOldCommDCB(ptr
, &dcb
);
485 result
= COMM_BuildNewCommDCB(ptr
, &dcb
, &timeouts
);
490 if(lptimeouts
) *lptimeouts
= timeouts
;
495 WARN("Invalid device control string: %s\n", debugstr_w(devid
));
496 SetLastError(ERROR_INVALID_PARAMETER
);
501 /**************************************************************************
502 * BuildCommDCBW (KERNEL32.@)
504 * Updates a device control block structure with values from an
505 * unicode device control string. The device control string has two forms
506 * normal and extended, it must be exclusively in one or the other form.
510 * True on success, false on a malformed control string.
512 BOOL WINAPI
BuildCommDCBW(
513 LPCWSTR devid
, /* [in] The unicode device control string. */
514 LPDCB lpdcb
) /* [out] The device control block to be updated. */
516 return BuildCommDCBAndTimeoutsW(devid
,lpdcb
,NULL
);
519 /***********************************************************************
521 * The functionality of CommConfigDialogA, GetDefaultCommConfig and
522 * SetDefaultCommConfig is implemented in a DLL (usually SERIALUI.DLL).
523 * This is dependent on the type of COMM port, but since it is doubtful
524 * anybody will get around to implementing support for fancy serial
525 * ports in WINE, this is hardcoded for the time being. The name of
526 * this DLL should be stored in and read from the system registry in
527 * the hive HKEY_LOCAL_MACHINE, key
528 * System\\CurrentControlSet\\Services\\Class\\Ports\\????
529 * where ???? is the port number... that is determined by PNP
530 * The DLL should be loaded when the COMM port is opened, and closed
531 * when the COMM port is closed. - MJM 20 June 2000
532 ***********************************************************************/
533 static const WCHAR lpszSerialUI
[] = L
"serialui.dll";
536 /***********************************************************************
537 * CommConfigDialogA (KERNEL32.@)
539 * Raises a dialog that allows the user to configure a comm port.
540 * Fills the COMMCONFIG struct with information specified by the user.
541 * This function should call a similar routine in the COMM driver...
545 * TRUE on success, FALSE on failure
546 * If successful, the lpCommConfig structure will contain a new
547 * configuration for the comm port, as specified by the user.
550 * The library with the CommConfigDialog code is never unloaded.
551 * Perhaps this should be done when the comm port is closed?
553 BOOL WINAPI
CommConfigDialogA(
554 LPCSTR lpszDevice
, /* [in] name of communications device */
555 HWND hWnd
, /* [in] parent window for the dialog */
556 LPCOMMCONFIG lpCommConfig
) /* [out] pointer to struct to fill */
558 LPWSTR lpDeviceW
= NULL
;
562 TRACE("(%s, %p, %p)\n", debugstr_a(lpszDevice
), hWnd
, lpCommConfig
);
566 len
= MultiByteToWideChar( CP_ACP
, 0, lpszDevice
, -1, NULL
, 0 );
567 lpDeviceW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
568 MultiByteToWideChar( CP_ACP
, 0, lpszDevice
, -1, lpDeviceW
, len
);
570 r
= CommConfigDialogW(lpDeviceW
, hWnd
, lpCommConfig
);
571 HeapFree( GetProcessHeap(), 0, lpDeviceW
);
575 /***********************************************************************
576 * CommConfigDialogW (KERNEL32.@)
578 * See CommConfigDialogA.
580 BOOL WINAPI
CommConfigDialogW(
581 LPCWSTR lpszDevice
, /* [in] name of communications device */
582 HWND hWnd
, /* [in] parent window for the dialog */
583 LPCOMMCONFIG lpCommConfig
) /* [out] pointer to struct to fill */
585 DWORD (WINAPI
*pCommConfigDialog
)(LPCWSTR
, HWND
, LPCOMMCONFIG
);
586 HMODULE hConfigModule
;
587 DWORD res
= ERROR_INVALID_PARAMETER
;
589 TRACE("(%s, %p, %p)\n", debugstr_w(lpszDevice
), hWnd
, lpCommConfig
);
590 hConfigModule
= LoadLibraryW(lpszSerialUI
);
593 pCommConfigDialog
= (void *)GetProcAddress(hConfigModule
, "drvCommConfigDialogW");
594 if (pCommConfigDialog
) {
595 res
= pCommConfigDialog(lpszDevice
, hWnd
, lpCommConfig
);
597 FreeLibrary(hConfigModule
);
600 if (res
) SetLastError(res
);
601 return (res
== ERROR_SUCCESS
);
604 /***********************************************************************
605 * SetDefaultCommConfigW (KERNEL32.@)
607 * Initializes the default configuration for a communication device.
610 * lpszDevice [I] Name of the device targeted for configuration
611 * lpCommConfig [I] PTR to a buffer with the configuration for the device
612 * dwSize [I] Number of bytes in the buffer
616 * Success: TRUE, and default configuration saved
619 BOOL WINAPI
SetDefaultCommConfigW(LPCWSTR lpszDevice
, LPCOMMCONFIG lpCommConfig
, DWORD dwSize
)
621 BOOL (WINAPI
*lpfnSetDefaultCommConfig
)(LPCWSTR
, LPCOMMCONFIG
, DWORD
);
622 HMODULE hConfigModule
;
625 TRACE("(%s, %p, %lu)\n", debugstr_w(lpszDevice
), lpCommConfig
, dwSize
);
627 hConfigModule
= LoadLibraryW(lpszSerialUI
);
631 lpfnSetDefaultCommConfig
= (void *)GetProcAddress(hConfigModule
, "drvSetDefaultCommConfigW");
632 if (lpfnSetDefaultCommConfig
)
633 r
= lpfnSetDefaultCommConfig(lpszDevice
, lpCommConfig
, dwSize
);
635 FreeLibrary(hConfigModule
);
641 /***********************************************************************
642 * SetDefaultCommConfigA (KERNEL32.@)
644 * Initializes the default configuration for a communication device.
646 * See SetDefaultCommConfigW.
649 BOOL WINAPI
SetDefaultCommConfigA(LPCSTR lpszDevice
, LPCOMMCONFIG lpCommConfig
, DWORD dwSize
)
652 LPWSTR lpDeviceW
= NULL
;
655 TRACE("(%s, %p, %lu)\n", debugstr_a(lpszDevice
), lpCommConfig
, dwSize
);
659 len
= MultiByteToWideChar( CP_ACP
, 0, lpszDevice
, -1, NULL
, 0 );
660 lpDeviceW
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(WCHAR
) );
661 MultiByteToWideChar( CP_ACP
, 0, lpszDevice
, -1, lpDeviceW
, len
);
663 r
= SetDefaultCommConfigW(lpDeviceW
,lpCommConfig
,dwSize
);
664 HeapFree( GetProcessHeap(), 0, lpDeviceW
);
669 /***********************************************************************
670 * GetDefaultCommConfigW (KERNEL32.@)
672 * Acquires the default configuration of the specified communication device. (unicode)
676 * True on successful reading of the default configuration,
677 * if the device is not found or the buffer is too small.
679 BOOL WINAPI
GetDefaultCommConfigW(
680 LPCWSTR lpszName
, /* [in] The unicode name of the device targeted for configuration. */
681 LPCOMMCONFIG lpCC
, /* [out] The default configuration for the device. */
682 LPDWORD lpdwSize
) /* [in/out] Initially the size of the default configuration buffer,
683 afterwards the number of bytes copied to the buffer or
684 the needed size of the buffer. */
686 DWORD (WINAPI
*pGetDefaultCommConfig
)(LPCWSTR
, LPCOMMCONFIG
, LPDWORD
);
687 HMODULE hConfigModule
;
688 DWORD res
= ERROR_INVALID_PARAMETER
;
690 TRACE("(%s, %p, %p) *lpdwSize: %lu\n", debugstr_w(lpszName
), lpCC
, lpdwSize
, lpdwSize
? *lpdwSize
: 0 );
691 hConfigModule
= LoadLibraryW(lpszSerialUI
);
694 pGetDefaultCommConfig
= (void *)GetProcAddress(hConfigModule
, "drvGetDefaultCommConfigW");
695 if (pGetDefaultCommConfig
) {
696 res
= pGetDefaultCommConfig(lpszName
, lpCC
, lpdwSize
);
698 FreeLibrary(hConfigModule
);
701 if (res
) SetLastError(res
);
702 return (res
== ERROR_SUCCESS
);
705 /**************************************************************************
706 * GetDefaultCommConfigA (KERNEL32.@)
708 * Acquires the default configuration of the specified communication device.
712 * True on successful reading of the default configuration,
713 * if the device is not found or the buffer is too small.
715 BOOL WINAPI
GetDefaultCommConfigA(
716 LPCSTR lpszName
, /* [in] The ANSI name of the device targeted for configuration. */
717 LPCOMMCONFIG lpCC
, /* [out] The default configuration for the device. */
718 LPDWORD lpdwSize
) /* [in/out] Initially the size of the default configuration buffer,
719 afterwards the number of bytes copied to the buffer or
720 the needed size of the buffer. */
723 UNICODE_STRING lpszNameW
;
725 TRACE("(%s, %p, %p) *lpdwSize: %lu\n", debugstr_a(lpszName
), lpCC
, lpdwSize
, lpdwSize
? *lpdwSize
: 0 );
726 if(lpszName
) RtlCreateUnicodeStringFromAsciiz(&lpszNameW
,lpszName
);
727 else lpszNameW
.Buffer
= NULL
;
729 ret
= GetDefaultCommConfigW(lpszNameW
.Buffer
,lpCC
,lpdwSize
);
731 RtlFreeUnicodeString(&lpszNameW
);