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
30 #include "ddk/ntddser.h"
32 #include "wine/server.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(comm
);
38 /***********************************************************************
39 * COMM_Parse* (Internal)
41 * The following COMM_Parse* functions are used by the BuildCommDCB
42 * functions to help parse the various parts of the device control string.
44 static LPCWSTR
COMM_ParseStart(LPCWSTR ptr
)
46 /* The device control string may optionally start with "COMx" followed
47 by an optional ':' and spaces. */
48 if(!wcsnicmp(ptr
, L
"COM", 3))
52 /* Allow any com port above 0 as Win 9x does (NT only allows
53 values for com ports which are actually present) */
54 if(*ptr
< '1' || *ptr
> '9')
57 /* Advance pointer past port number */
58 while(*ptr
>= '0' && *ptr
<= '9') ptr
++;
60 /* The com port number must be followed by a ':' or ' ' */
61 if(*ptr
!= ':' && *ptr
!= ' ')
64 /* Advance pointer to beginning of next parameter */
65 while(*ptr
== ' ') ptr
++;
69 while(*ptr
== ' ') ptr
++;
72 /* The device control string must not start with a space. */
79 static LPCWSTR
COMM_ParseNumber(LPCWSTR ptr
, LPDWORD lpnumber
)
81 if(*ptr
< '0' || *ptr
> '9') return NULL
;
82 *lpnumber
= wcstoul(ptr
, NULL
, 10);
83 while(*ptr
>= '0' && *ptr
<= '9') ptr
++;
87 static LPCWSTR
COMM_ParseParity(LPCWSTR ptr
, LPBYTE lpparity
)
89 /* Contrary to what you might expect, Windows only sets the Parity
90 member of DCB and not fParity even when parity is specified in the
91 device control string */
97 *lpparity
= EVENPARITY
;
101 *lpparity
= MARKPARITY
;
105 *lpparity
= NOPARITY
;
109 *lpparity
= ODDPARITY
;
113 *lpparity
= SPACEPARITY
;
122 static LPCWSTR
COMM_ParseByteSize(LPCWSTR ptr
, LPBYTE lpbytesize
)
126 if(!(ptr
= COMM_ParseNumber(ptr
, &temp
)))
129 if(temp
>= 5 && temp
<= 8)
138 static LPCWSTR
COMM_ParseStopBits(LPCWSTR ptr
, LPBYTE lpstopbits
)
142 if(!wcsncmp(L
"1.5", ptr
, 3))
145 *lpstopbits
= ONE5STOPBITS
;
149 if(!(ptr
= COMM_ParseNumber(ptr
, &temp
)))
153 *lpstopbits
= ONESTOPBIT
;
155 *lpstopbits
= TWOSTOPBITS
;
163 static LPCWSTR
COMM_ParseOnOff(LPCWSTR ptr
, LPDWORD lponoff
)
165 if(!wcsnicmp(L
"on", ptr
, 2))
170 else if(!wcsnicmp(L
"off", ptr
, 3))
181 /***********************************************************************
182 * COMM_BuildOldCommDCB (Internal)
184 * Build a DCB using the old style settings string eg: "96,n,8,1"
186 static BOOL
COMM_BuildOldCommDCB(LPCWSTR device
, LPDCB lpdcb
)
190 if(!(device
= COMM_ParseNumber(device
, &lpdcb
->BaudRate
)))
193 switch(lpdcb
->BaudRate
)
198 lpdcb
->BaudRate
*= 10;
204 lpdcb
->BaudRate
*= 100;
207 lpdcb
->BaudRate
= 19200;
211 while(*device
== ' ') device
++;
212 if(*device
++ != ',') return FALSE
;
213 while(*device
== ' ') device
++;
215 if(!(device
= COMM_ParseParity(device
, &lpdcb
->Parity
)))
218 while(*device
== ' ') device
++;
219 if(*device
++ != ',') return FALSE
;
220 while(*device
== ' ') device
++;
222 if(!(device
= COMM_ParseByteSize(device
, &lpdcb
->ByteSize
)))
225 while(*device
== ' ') device
++;
226 if(*device
++ != ',') return FALSE
;
227 while(*device
== ' ') device
++;
229 if(!(device
= COMM_ParseStopBits(device
, &lpdcb
->StopBits
)))
232 /* The last parameter for flow control is optional. */
233 while(*device
== ' ') device
++;
237 while(*device
== ' ') device
++;
238 if(*device
) last
= *device
++;
239 while(*device
== ' ') device
++;
242 /* Win NT sets the flow control members based on (or lack of) the last
243 parameter. Win 9x does not set these members. */
248 lpdcb
->fOutX
= FALSE
;
249 lpdcb
->fOutxCtsFlow
= FALSE
;
250 lpdcb
->fOutxDsrFlow
= FALSE
;
251 lpdcb
->fDtrControl
= DTR_CONTROL_ENABLE
;
252 lpdcb
->fRtsControl
= RTS_CONTROL_ENABLE
;
258 lpdcb
->fOutxCtsFlow
= FALSE
;
259 lpdcb
->fOutxDsrFlow
= FALSE
;
260 lpdcb
->fDtrControl
= DTR_CONTROL_ENABLE
;
261 lpdcb
->fRtsControl
= RTS_CONTROL_ENABLE
;
266 lpdcb
->fOutX
= FALSE
;
267 lpdcb
->fOutxCtsFlow
= TRUE
;
268 lpdcb
->fOutxDsrFlow
= TRUE
;
269 lpdcb
->fDtrControl
= DTR_CONTROL_HANDSHAKE
;
270 lpdcb
->fRtsControl
= RTS_CONTROL_HANDSHAKE
;
276 /* This should be the end of the string. */
277 if(*device
) return FALSE
;
282 /***********************************************************************
283 * COMM_BuildNewCommDCB (Internal)
285 * Build a DCB using the new style settings string.
286 * eg: "baud=9600 parity=n data=8 stop=1 xon=on to=on"
288 static BOOL
COMM_BuildNewCommDCB(LPCWSTR device
, LPDCB lpdcb
, LPCOMMTIMEOUTS lptimeouts
)
291 BOOL baud
= FALSE
, stop
= FALSE
;
295 while(*device
== ' ') device
++;
297 if(!wcsnicmp(L
"baud=", device
, 5))
301 if(!(device
= COMM_ParseNumber(device
+ 5, &lpdcb
->BaudRate
)))
304 else if(!wcsnicmp(L
"parity=", device
, 7))
306 if(!(device
= COMM_ParseParity(device
+ 7, &lpdcb
->Parity
)))
309 else if(!wcsnicmp(L
"data=", device
, 5))
311 if(!(device
= COMM_ParseByteSize(device
+ 5, &lpdcb
->ByteSize
)))
314 else if(!wcsnicmp(L
"stop=", device
, 5))
318 if(!(device
= COMM_ParseStopBits(device
+ 5, &lpdcb
->StopBits
)))
321 else if(!wcsnicmp(L
"to=", device
, 3))
323 if(!(device
= COMM_ParseOnOff(device
+ 3, &temp
)))
326 lptimeouts
->ReadIntervalTimeout
= 0;
327 lptimeouts
->ReadTotalTimeoutMultiplier
= 0;
328 lptimeouts
->ReadTotalTimeoutConstant
= 0;
329 lptimeouts
->WriteTotalTimeoutMultiplier
= 0;
330 lptimeouts
->WriteTotalTimeoutConstant
= temp
? 60000 : 0;
332 else if(!wcsnicmp(L
"xon=", device
, 4))
334 if(!(device
= COMM_ParseOnOff(device
+ 4, &temp
)))
340 else if(!wcsnicmp(L
"odsr=", device
, 5))
342 if(!(device
= COMM_ParseOnOff(device
+ 5, &temp
)))
345 lpdcb
->fOutxDsrFlow
= temp
;
347 else if(!wcsnicmp(L
"octs=", device
, 5))
349 if(!(device
= COMM_ParseOnOff(device
+ 5, &temp
)))
352 lpdcb
->fOutxCtsFlow
= temp
;
354 else if(!wcsnicmp(L
"dtr=", device
, 4))
356 if(!(device
= COMM_ParseOnOff(device
+ 4, &temp
)))
359 lpdcb
->fDtrControl
= temp
;
361 else if(!wcsnicmp(L
"rts=", device
, 4))
363 if(!(device
= COMM_ParseOnOff(device
+ 4, &temp
)))
366 lpdcb
->fRtsControl
= temp
;
368 else if(!wcsnicmp(L
"idsr=", device
, 5))
370 if(!(device
= COMM_ParseOnOff(device
+ 5, &temp
)))
373 /* Win NT sets the fDsrSensitivity member based on the
374 idsr parameter. Win 9x sets fOutxDsrFlow instead. */
375 lpdcb
->fDsrSensitivity
= temp
;
380 /* After the above parsing, the next character (if not the end of
381 the string) should be a space */
382 if(*device
&& *device
!= ' ')
386 /* If stop bits were not specified, a default is always supplied. */
389 if(baud
&& lpdcb
->BaudRate
== 110)
390 lpdcb
->StopBits
= TWOSTOPBITS
;
392 lpdcb
->StopBits
= ONESTOPBIT
;
398 /**************************************************************************
399 * BuildCommDCBA (KERNEL32.@)
401 * Updates a device control block data structure with values from an
402 * ascii device control string. The device control string has two forms
403 * normal and extended, it must be exclusively in one or the other form.
407 * True on success, false on a malformed control string.
409 BOOL WINAPI
BuildCommDCBA(
410 LPCSTR device
, /* [in] The ascii device control string used to update the DCB. */
411 LPDCB lpdcb
) /* [out] The device control block to be updated. */
413 return BuildCommDCBAndTimeoutsA(device
,lpdcb
,NULL
);
416 /**************************************************************************
417 * BuildCommDCBAndTimeoutsA (KERNEL32.@)
419 * Updates a device control block data structure with values from an
420 * ascii device control string. Taking timeout values from a timeouts
421 * struct if desired by the control string.
425 * True on success, false bad handles etc.
427 BOOL WINAPI
BuildCommDCBAndTimeoutsA(
428 LPCSTR device
, /* [in] The ascii device control string. */
429 LPDCB lpdcb
, /* [out] The device control block to be updated. */
430 LPCOMMTIMEOUTS lptimeouts
) /* [in] The COMMTIMEOUTS structure to be updated. */
433 UNICODE_STRING deviceW
;
435 TRACE("(%s,%p,%p)\n",device
,lpdcb
,lptimeouts
);
436 if(device
) RtlCreateUnicodeStringFromAsciiz(&deviceW
,device
);
437 else deviceW
.Buffer
= NULL
;
439 if(deviceW
.Buffer
) ret
= BuildCommDCBAndTimeoutsW(deviceW
.Buffer
,lpdcb
,lptimeouts
);
441 RtlFreeUnicodeString(&deviceW
);
445 /**************************************************************************
446 * BuildCommDCBAndTimeoutsW (KERNEL32.@)
448 * Updates a device control block data structure with values from a
449 * unicode device control string. Taking timeout values from a timeouts
450 * struct if desired by the control string.
454 * True on success, false bad handles etc
456 BOOL WINAPI
BuildCommDCBAndTimeoutsW(
457 LPCWSTR devid
, /* [in] The unicode device control string. */
458 LPDCB lpdcb
, /* [out] The device control block to be updated. */
459 LPCOMMTIMEOUTS lptimeouts
) /* [in] The COMMTIMEOUTS structure to be updated. */
462 COMMTIMEOUTS timeouts
;
466 TRACE("(%s,%p,%p)\n",debugstr_w(devid
),lpdcb
,lptimeouts
);
468 memset(&timeouts
, 0, sizeof timeouts
);
470 /* Set DCBlength. (Windows NT does not do this, but 9x does) */
471 lpdcb
->DCBlength
= sizeof(DCB
);
473 /* Make a copy of the original data structures to work with since if
474 if there is an error in the device control string the originals
475 should not be modified (except possibly DCBlength) */
477 if(lptimeouts
) timeouts
= *lptimeouts
;
479 ptr
= COMM_ParseStart(ptr
);
483 else if(wcschr(ptr
, ','))
484 result
= COMM_BuildOldCommDCB(ptr
, &dcb
);
486 result
= COMM_BuildNewCommDCB(ptr
, &dcb
, &timeouts
);
491 if(lptimeouts
) *lptimeouts
= timeouts
;
496 WARN("Invalid device control string: %s\n", debugstr_w(devid
));
497 SetLastError(ERROR_INVALID_PARAMETER
);
502 /**************************************************************************
503 * BuildCommDCBW (KERNEL32.@)
505 * Updates a device control block structure with values from an
506 * unicode device control string. The device control string has two forms
507 * normal and extended, it must be exclusively in one or the other form.
511 * True on success, false on a malformed control string.
513 BOOL WINAPI
BuildCommDCBW(
514 LPCWSTR devid
, /* [in] The unicode device control string. */
515 LPDCB lpdcb
) /* [out] The device control block to be updated. */
517 return BuildCommDCBAndTimeoutsW(devid
,lpdcb
,NULL
);
520 /***********************************************************************
522 * The functionality of CommConfigDialogA, GetDefaultCommConfig and
523 * SetDefaultCommConfig is implemented in a DLL (usually SERIALUI.DLL).
524 * This is dependent on the type of COMM port, but since it is doubtful
525 * anybody will get around to implementing support for fancy serial
526 * ports in WINE, this is hardcoded for the time being. The name of
527 * this DLL should be stored in and read from the system registry in
528 * the hive HKEY_LOCAL_MACHINE, key
529 * System\\CurrentControlSet\\Services\\Class\\Ports\\????
530 * where ???? is the port number... that is determined by PNP
531 * The DLL should be loaded when the COMM port is opened, and closed
532 * when the COMM port is closed. - MJM 20 June 2000
533 ***********************************************************************/
534 static const WCHAR lpszSerialUI
[] = L
"serialui.dll";
537 /***********************************************************************
538 * CommConfigDialogA (KERNEL32.@)
540 * Raises a dialog that allows the user to configure a comm port.
541 * Fills the COMMCONFIG struct with information specified by the user.
542 * This function should call a similar routine in the COMM driver...
546 * TRUE on success, FALSE on failure
547 * If successful, the lpCommConfig structure will contain a new
548 * configuration for the comm port, as specified by the user.
551 * The library with the CommConfigDialog code is never unloaded.
552 * Perhaps this should be done when the comm port is closed?
554 BOOL WINAPI
CommConfigDialogA(
555 LPCSTR lpszDevice
, /* [in] name of communications device */
556 HWND hWnd
, /* [in] parent window for the dialog */
557 LPCOMMCONFIG lpCommConfig
) /* [out] pointer to struct to fill */
559 LPWSTR lpDeviceW
= NULL
;
563 TRACE("(%s, %p, %p)\n", debugstr_a(lpszDevice
), hWnd
, lpCommConfig
);
567 len
= MultiByteToWideChar( CP_ACP
, 0, lpszDevice
, -1, NULL
, 0 );
568 lpDeviceW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
569 MultiByteToWideChar( CP_ACP
, 0, lpszDevice
, -1, lpDeviceW
, len
);
571 r
= CommConfigDialogW(lpDeviceW
, hWnd
, lpCommConfig
);
572 HeapFree( GetProcessHeap(), 0, lpDeviceW
);
576 /***********************************************************************
577 * CommConfigDialogW (KERNEL32.@)
579 * See CommConfigDialogA.
581 BOOL WINAPI
CommConfigDialogW(
582 LPCWSTR lpszDevice
, /* [in] name of communications device */
583 HWND hWnd
, /* [in] parent window for the dialog */
584 LPCOMMCONFIG lpCommConfig
) /* [out] pointer to struct to fill */
586 DWORD (WINAPI
*pCommConfigDialog
)(LPCWSTR
, HWND
, LPCOMMCONFIG
);
587 HMODULE hConfigModule
;
588 DWORD res
= ERROR_INVALID_PARAMETER
;
590 TRACE("(%s, %p, %p)\n", debugstr_w(lpszDevice
), hWnd
, lpCommConfig
);
591 hConfigModule
= LoadLibraryW(lpszSerialUI
);
594 pCommConfigDialog
= (void *)GetProcAddress(hConfigModule
, "drvCommConfigDialogW");
595 if (pCommConfigDialog
) {
596 res
= pCommConfigDialog(lpszDevice
, hWnd
, lpCommConfig
);
598 FreeLibrary(hConfigModule
);
601 if (res
) SetLastError(res
);
602 return (res
== ERROR_SUCCESS
);
605 /***********************************************************************
606 * SetDefaultCommConfigW (KERNEL32.@)
608 * Initializes the default configuration for a communication device.
611 * lpszDevice [I] Name of the device targeted for configuration
612 * lpCommConfig [I] PTR to a buffer with the configuration for the device
613 * dwSize [I] Number of bytes in the buffer
617 * Success: TRUE, and default configuration saved
620 BOOL WINAPI
SetDefaultCommConfigW(LPCWSTR lpszDevice
, LPCOMMCONFIG lpCommConfig
, DWORD dwSize
)
622 BOOL (WINAPI
*lpfnSetDefaultCommConfig
)(LPCWSTR
, LPCOMMCONFIG
, DWORD
);
623 HMODULE hConfigModule
;
626 TRACE("(%s, %p, %u)\n", debugstr_w(lpszDevice
), lpCommConfig
, dwSize
);
628 hConfigModule
= LoadLibraryW(lpszSerialUI
);
632 lpfnSetDefaultCommConfig
= (void *)GetProcAddress(hConfigModule
, "drvSetDefaultCommConfigW");
633 if (lpfnSetDefaultCommConfig
)
634 r
= lpfnSetDefaultCommConfig(lpszDevice
, lpCommConfig
, dwSize
);
636 FreeLibrary(hConfigModule
);
642 /***********************************************************************
643 * SetDefaultCommConfigA (KERNEL32.@)
645 * Initializes the default configuration for a communication device.
647 * See SetDefaultCommConfigW.
650 BOOL WINAPI
SetDefaultCommConfigA(LPCSTR lpszDevice
, LPCOMMCONFIG lpCommConfig
, DWORD dwSize
)
653 LPWSTR lpDeviceW
= NULL
;
656 TRACE("(%s, %p, %u)\n", debugstr_a(lpszDevice
), lpCommConfig
, dwSize
);
660 len
= MultiByteToWideChar( CP_ACP
, 0, lpszDevice
, -1, NULL
, 0 );
661 lpDeviceW
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof(WCHAR
) );
662 MultiByteToWideChar( CP_ACP
, 0, lpszDevice
, -1, lpDeviceW
, len
);
664 r
= SetDefaultCommConfigW(lpDeviceW
,lpCommConfig
,dwSize
);
665 HeapFree( GetProcessHeap(), 0, lpDeviceW
);
670 /***********************************************************************
671 * GetDefaultCommConfigW (KERNEL32.@)
673 * Acquires the default configuration of the specified communication device. (unicode)
677 * True on successful reading of the default configuration,
678 * if the device is not found or the buffer is too small.
680 BOOL WINAPI
GetDefaultCommConfigW(
681 LPCWSTR lpszName
, /* [in] The unicode name of the device targeted for configuration. */
682 LPCOMMCONFIG lpCC
, /* [out] The default configuration for the device. */
683 LPDWORD lpdwSize
) /* [in/out] Initially the size of the default configuration buffer,
684 afterwards the number of bytes copied to the buffer or
685 the needed size of the buffer. */
687 DWORD (WINAPI
*pGetDefaultCommConfig
)(LPCWSTR
, LPCOMMCONFIG
, LPDWORD
);
688 HMODULE hConfigModule
;
689 DWORD res
= ERROR_INVALID_PARAMETER
;
691 TRACE("(%s, %p, %p) *lpdwSize: %u\n", debugstr_w(lpszName
), lpCC
, lpdwSize
, lpdwSize
? *lpdwSize
: 0 );
692 hConfigModule
= LoadLibraryW(lpszSerialUI
);
695 pGetDefaultCommConfig
= (void *)GetProcAddress(hConfigModule
, "drvGetDefaultCommConfigW");
696 if (pGetDefaultCommConfig
) {
697 res
= pGetDefaultCommConfig(lpszName
, lpCC
, lpdwSize
);
699 FreeLibrary(hConfigModule
);
702 if (res
) SetLastError(res
);
703 return (res
== ERROR_SUCCESS
);
706 /**************************************************************************
707 * GetDefaultCommConfigA (KERNEL32.@)
709 * Acquires the default configuration of the specified communication device. (ascii)
713 * True on successful reading of the default configuration,
714 * if the device is not found or the buffer is too small.
716 BOOL WINAPI
GetDefaultCommConfigA(
717 LPCSTR lpszName
, /* [in] The ascii name of the device targeted for configuration. */
718 LPCOMMCONFIG lpCC
, /* [out] The default configuration for the device. */
719 LPDWORD lpdwSize
) /* [in/out] Initially the size of the default configuration buffer,
720 afterwards the number of bytes copied to the buffer or
721 the needed size of the buffer. */
724 UNICODE_STRING lpszNameW
;
726 TRACE("(%s, %p, %p) *lpdwSize: %u\n", debugstr_a(lpszName
), lpCC
, lpdwSize
, lpdwSize
? *lpdwSize
: 0 );
727 if(lpszName
) RtlCreateUnicodeStringFromAsciiz(&lpszNameW
,lpszName
);
728 else lpszNameW
.Buffer
= NULL
;
730 ret
= GetDefaultCommConfigW(lpszNameW
.Buffer
,lpCC
,lpdwSize
);
732 RtlFreeUnicodeString(&lpszNameW
);