windows-nt/Source/XPSP1/NT/base/win32/client/comm.c
2020-09-26 16:20:57 +08:00

3457 lines
79 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
comm.c
Abstract:
This module implements Win32 comm APIs
Author:
Anthony V. Ercolano (tonye) 25-April-1991
Revision History:
--*/
#include "basedll.h"
#pragma hdrstop
#include "ntddser.h"
#include "cfgmgr32.h"
WCHAR CfgmgrDllString[] = L"cfgmgr32.dll";
typedef struct _LOCALMATCHSTR {
DWORD FoundIt;
LPCWSTR FriendlyName;
} LOCALMATCHSTR,*PLOCALMATCHSTR;
static
NTSTATUS
GetConfigDialogName(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
)
{
PUNICODE_STRING dllToLoad = Context;
if (ValueType != REG_SZ) {
return STATUS_INVALID_PARAMETER;
}
//
// Allocate heap to hold the unicode string. We know
// that the string is zero terminated. Allocate that
// much. Set the maximum size and size to
// sizeof(WCHAR) - ValueLength.
//
RtlInitUnicodeString(
dllToLoad,
NULL
);
dllToLoad->Buffer = RtlAllocateHeap(
RtlProcessHeap(),
MAKE_TAG( TMP_TAG ),
ValueLength
);
if (!dllToLoad->Buffer) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlMoveMemory(
dllToLoad->Buffer,
ValueData,
ValueLength
);
dllToLoad->Length = (USHORT)(ValueLength - (sizeof(WCHAR)));
dllToLoad->MaximumLength = (USHORT)ValueLength;
return STATUS_SUCCESS;
}
static
NTSTATUS
GetFriendlyMatchComm(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
)
{
UNICODE_STRING s1;
UNICODE_STRING s2;
PLOCALMATCHSTR localMatch = Context;
RtlInitUnicodeString(
&s1,
localMatch->FriendlyName
);
RtlInitUnicodeString(
&s2,
ValueData
);
if (RtlEqualUnicodeString(
&s1,
&s2,
TRUE
)) {
localMatch->FoundIt = TRUE;
}
return STATUS_SUCCESS;
}
VOID
GetFriendlyUi(
LPCWSTR FriendlyName,
PUNICODE_STRING DllToInvoke
)
{
RTL_QUERY_REGISTRY_TABLE paramTable[2] = {0};
LOCALMATCHSTR localMatch = {0,FriendlyName};
HINSTANCE libHandle;
paramTable[0].QueryRoutine = GetFriendlyMatchComm;
paramTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
//
// First things first. Load the cfg manager library.
//
libHandle = LoadLibraryW(CfgmgrDllString);
if (libHandle) {
FARPROC getSize;
FARPROC getList;
FARPROC locateDevNode;
FARPROC openDevKey;
try {
getSize = GetProcAddress(
libHandle,
"CM_Get_Device_ID_List_SizeW"
);
getList = GetProcAddress(
libHandle,
"CM_Get_Device_ID_ListW"
);
locateDevNode = GetProcAddress(
libHandle,
"CM_Locate_DevNodeW"
);
openDevKey = GetProcAddress(
libHandle,
"CM_Open_DevNode_Key"
);
if (getSize && getList && locateDevNode && openDevKey) {
PWCHAR bufferForList = NULL;
DWORD sizeOfBuffer;
//
// Find how much memory for the buffer.
//
if (getSize(
&sizeOfBuffer,
L"MODEM",
CM_GETIDLIST_FILTER_SERVICE
) == CR_SUCCESS) {
//
// Allocate 2 extra wchar.
//
bufferForList = RtlAllocateHeap(
RtlProcessHeap(),
MAKE_TAG( TMP_TAG ),
(sizeOfBuffer*sizeof(WCHAR))
+(sizeof(WCHAR)*2)
);
if (bufferForList) {
PWCHAR currentId;
try {
if (getList(
L"modem",
bufferForList,
sizeOfBuffer,
CM_GETIDLIST_FILTER_SERVICE
) == CR_SUCCESS) {
for (
currentId = bufferForList;
*currentId;
currentId += wcslen(currentId)+1
) {
DWORD devInst = 0;
if (locateDevNode(
&devInst,
currentId,
CM_LOCATE_DEVINST_NORMAL
) == CR_SUCCESS) {
HANDLE handleToDev;
if (openDevKey(
devInst,
KEY_ALL_ACCESS,
0,
RegDisposition_OpenAlways,
&handleToDev,
CM_REGISTRY_SOFTWARE
) == CR_SUCCESS) {
NTSTATUS statusOfQuery;
localMatch.FoundIt = 0;
paramTable[0].Name =
L"FriendlyName";
//
// We now have an open
// handle to a dev node.
//
// Check to see if it's
// friendly name matches ours.
//
if (!NT_SUCCESS(
RtlQueryRegistryValues(
RTL_REGISTRY_HANDLE,
handleToDev,
&paramTable[0],
&localMatch,
NULL
)
)) {
CloseHandle(handleToDev);
continue;
}
if (!localMatch.FoundIt) {
CloseHandle(handleToDev);
continue;
}
//
// The names match. Now look
// for the config dll name.
//
paramTable[0].QueryRoutine =
GetConfigDialogName;
paramTable[0].Name =
L"ConfigDialog";
statusOfQuery =
RtlQueryRegistryValues(
RTL_REGISTRY_HANDLE,
handleToDev,
&paramTable[0],
DllToInvoke,
NULL
);
paramTable[0].QueryRoutine =
GetFriendlyMatchComm;
if (!NT_SUCCESS(statusOfQuery)) {
//
// We had a bad status
// back from getting the dll
// name we should have gotten.
//
// There is no point in
// looking for anymore
//
BaseSetLastNTError(
statusOfQuery
);
CloseHandle(handleToDev);
return;
}
//
// We know that we are dealing
// with a local registry here.
// we just call closehandle.
//
CloseHandle(handleToDev);
if (DllToInvoke->Buffer) {
//
// We have found a dll for
// the friendly name. Just
// leave. The finally
// handlers will clean up
// our allocations.
//
return;
}
}
}
}
}
} finally {
//
// Free the idlist memory.
//
RtlFreeHeap(
RtlProcessHeap(),
0,
bufferForList
);
}
}
}
}
} finally {
FreeLibrary(libHandle);
}
}
if (!DllToInvoke->Buffer) {
//
// Couldn't find the friendly name in the enum tree.
// See if the value is a valid comm port name. If
// it is, default return serialui.dll
//
paramTable[0].Name = NULL;
RtlQueryRegistryValues(
RTL_REGISTRY_DEVICEMAP,
L"SERIALCOMM",
paramTable,
&localMatch,
NULL
);
if (localMatch.FoundIt) {
ANSI_STRING ansiString;
RtlInitAnsiString(
&ansiString,
"serialui.dll"
);
DllToInvoke->Buffer = RtlAllocateHeap(
RtlProcessHeap(),
MAKE_TAG( TMP_TAG ),
(ansiString.Length+2)*sizeof(WCHAR)
);
if (!DllToInvoke->Buffer) {
BaseSetLastNTError(STATUS_INSUFFICIENT_RESOURCES);
return;
}
DllToInvoke->Length = 0;
DllToInvoke->MaximumLength = (ansiString.Length+1)*sizeof(WCHAR);
RtlAnsiStringToUnicodeString(
DllToInvoke,
&ansiString,
FALSE
);
*(DllToInvoke->Buffer+ansiString.Length) = 0;
} else {
SetLastError(ERROR_INVALID_PARAMETER);
}
}
}
BOOL
CommConfigDialogW(
LPCWSTR lpszName,
HWND hWnd,
LPCOMMCONFIG lpCC
)
{
UNICODE_STRING dllName = {0};
BOOL boolToReturn = TRUE;
HINSTANCE libInstance = 0;
DWORD statOfCall = 0;
//
// Given the "friendly name" get the name of the dll to load.
//
GetFriendlyUi(
lpszName,
&dllName
);
try {
if (dllName.Buffer) {
//
// Got the new library name. Try to load it.
//
libInstance = LoadLibraryW(dllName.Buffer);
if (libInstance) {
FARPROC procToCall;
//
// Got the lib. Get the proc address we need.
//
procToCall = GetProcAddress(
libInstance,
"drvCommConfigDialogW"
);
statOfCall = (DWORD)procToCall(
lpszName,
hWnd,
lpCC
);
} else {
boolToReturn = FALSE;
}
} else {
//
// Assume that an appropriate error has been set.
//
boolToReturn = FALSE;
}
} finally {
if (dllName.Buffer) {
RtlFreeHeap(
RtlProcessHeap(),
0,
dllName.Buffer
);
}
if (libInstance) {
FreeLibrary(libInstance);
}
if (statOfCall) {
SetLastError(statOfCall);
boolToReturn = FALSE;
}
}
return boolToReturn;
}
BOOL
CommConfigDialogA(
LPCSTR lpszName,
HWND hWnd,
LPCOMMCONFIG lpCC
)
{
PWCHAR unicodeName;
UNICODE_STRING tmpString;
ANSI_STRING ansiString;
BOOL uniBool;
RtlInitAnsiString(
&ansiString,
lpszName
);
unicodeName = RtlAllocateHeap(
RtlProcessHeap(),
MAKE_TAG( TMP_TAG ),
(ansiString.Length+2)*sizeof(WCHAR)
);
if (!unicodeName) {
BaseSetLastNTError(STATUS_INSUFFICIENT_RESOURCES);
return FALSE;
}
tmpString.Length = 0;
tmpString.MaximumLength = (ansiString.Length+1)*sizeof(WCHAR);
tmpString.Buffer = unicodeName;
RtlAnsiStringToUnicodeString(
&tmpString,
&ansiString,
FALSE
);
*(unicodeName+ansiString.Length) = 0;
try {
uniBool = CommConfigDialogW(
unicodeName,
hWnd,
lpCC
);
} finally {
RtlFreeHeap(
RtlProcessHeap(),
0,
unicodeName
);
}
return uniBool;
}
BOOL
GetDefaultCommConfigW(
LPCWSTR lpszName,
LPCOMMCONFIG lpCC,
LPDWORD lpdwSize
)
{
UNICODE_STRING dllName = {0};
BOOL boolToReturn = TRUE;
HINSTANCE libInstance = 0;
DWORD statOfCall = 0;
//
// Given the "friendly name" get the name of the dll to load.
//
GetFriendlyUi(
lpszName,
&dllName
);
try {
if (dllName.Buffer) {
//
// Got the new library name. Try to load it.
//
libInstance = LoadLibraryW(dllName.Buffer);
if (libInstance) {
FARPROC procToCall;
//
// Got the lib. Get the proc address we need.
//
procToCall = GetProcAddress(
libInstance,
"drvGetDefaultCommConfigW"
);
statOfCall = (DWORD)procToCall(
lpszName,
lpCC,
lpdwSize
);
} else {
boolToReturn = FALSE;
}
} else {
//
// Assume that an appropriate error has been set.
//
boolToReturn = FALSE;
}
} finally {
if (dllName.Buffer) {
RtlFreeHeap(
RtlProcessHeap(),
0,
dllName.Buffer
);
}
if (libInstance) {
FreeLibrary(libInstance);
}
if (statOfCall) {
SetLastError(statOfCall);
boolToReturn = FALSE;
}
}
return boolToReturn;
}
BOOL
GetDefaultCommConfigA(
LPCSTR lpszName,
LPCOMMCONFIG lpCC,
LPDWORD lpdwSize
)
{
PWCHAR unicodeName;
UNICODE_STRING tmpString;
ANSI_STRING ansiString;
BOOL uniBool;
RtlInitAnsiString(
&ansiString,
lpszName
);
unicodeName = RtlAllocateHeap(
RtlProcessHeap(),
MAKE_TAG( TMP_TAG ),
(ansiString.Length+2)*sizeof(WCHAR)
);
if (!unicodeName) {
BaseSetLastNTError(STATUS_INSUFFICIENT_RESOURCES);
return FALSE;
}
tmpString.Length = 0;
tmpString.MaximumLength = (ansiString.Length+1)*sizeof(WCHAR);
tmpString.Buffer = unicodeName;
RtlAnsiStringToUnicodeString(
&tmpString,
&ansiString,
FALSE
);
*(unicodeName+ansiString.Length) = 0;
try {
uniBool = GetDefaultCommConfigW(
unicodeName,
lpCC,
lpdwSize
);
} finally {
RtlFreeHeap(
RtlProcessHeap(),
0,
unicodeName
);
}
return uniBool;
}
BOOL
SetDefaultCommConfigW(
LPCWSTR lpszName,
LPCOMMCONFIG lpCC,
DWORD dwSize
)
{
UNICODE_STRING dllName = {0};
BOOL boolToReturn = TRUE;
HINSTANCE libInstance = 0;
DWORD statOfCall = 0;
//
// Given the "friendly name" get the name of the dll to load.
//
GetFriendlyUi(
lpszName,
&dllName
);
try {
if (dllName.Buffer) {
//
// Got the new library name. Try to load it.
//
libInstance = LoadLibraryW(dllName.Buffer);
if (libInstance) {
FARPROC procToCall;
//
// Got the lib. Get the proc address we need.
//
procToCall = GetProcAddress(
libInstance,
"drvSetDefaultCommConfigW"
);
statOfCall = (DWORD)procToCall(
lpszName,
lpCC,
dwSize
);
} else {
boolToReturn = FALSE;
}
} else {
//
// Assume that an appropriate error has been set.
//
boolToReturn = FALSE;
}
} finally {
if (dllName.Buffer) {
RtlFreeHeap(
RtlProcessHeap(),
0,
dllName.Buffer
);
}
if (libInstance) {
FreeLibrary(libInstance);
}
if (statOfCall) {
SetLastError(statOfCall);
boolToReturn = FALSE;
}
}
return boolToReturn;
}
BOOL
SetDefaultCommConfigA(
LPCSTR lpszName,
LPCOMMCONFIG lpCC,
DWORD dwSize
)
{
PWCHAR unicodeName;
UNICODE_STRING tmpString;
ANSI_STRING ansiString;
BOOL uniBool = TRUE;
RtlInitAnsiString(
&ansiString,
lpszName
);
unicodeName = RtlAllocateHeap(
RtlProcessHeap(),
MAKE_TAG( TMP_TAG ),
(ansiString.Length+2)*sizeof(WCHAR)
);
if (!unicodeName) {
BaseSetLastNTError(STATUS_INSUFFICIENT_RESOURCES);
return FALSE;
}
tmpString.Length = 0;
tmpString.MaximumLength = (ansiString.Length+1)*sizeof(WCHAR);
tmpString.Buffer = unicodeName;
RtlAnsiStringToUnicodeString(
&tmpString,
&ansiString,
FALSE
);
*(unicodeName+ansiString.Length) = 0;
try {
uniBool = SetDefaultCommConfigW(
unicodeName,
lpCC,
dwSize
);
} finally {
RtlFreeHeap(
RtlProcessHeap(),
0,
unicodeName
);
}
return uniBool;
}
BOOL
ClearCommBreak(
HANDLE hFile
)
/*++
Routine Description:
The function restores character transmission and places the transmission
line in a nonbreak state.
Arguments:
hFile - Specifies the communication device to be adjusted.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
return EscapeCommFunction(hFile,CLRBREAK);
}
BOOL
ClearCommError(
HANDLE hFile,
LPDWORD lpErrors,
LPCOMSTAT lpStat
)
/*++
Routine Description:
In case of a communications error, such as a buffer overrun or
framing error, the communications software will abort all
read and write operations on the communication port. No further
read or write operations will be accepted until this function
is called.
Arguments:
hFile - Specifies the communication device to be adjusted.
lpErrors - Points to the DWORD that is to receive the mask of the
error that occured.
lpStat - Points to the COMMSTAT structure that is to receive
the device status. The structure contains information
about the communications device.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
NTSTATUS Status;
HANDLE SyncEvent;
IO_STATUS_BLOCK Iosb;
SERIAL_STATUS LocalStat;
RtlZeroMemory(&LocalStat, sizeof(SERIAL_STATUS));
if (!(SyncEvent = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
}
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_GET_COMMSTATUS,
NULL,
0,
&LocalStat,
sizeof(LocalStat)
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
BaseSetLastNTError(Status);
return FALSE;
}
if (lpStat) {
//
// All is well up to this point. Translate the NT values
// into win32 values.
//
if (LocalStat.HoldReasons & SERIAL_TX_WAITING_FOR_CTS) {
lpStat->fCtsHold = TRUE;
} else {
lpStat->fCtsHold = FALSE;
}
if (LocalStat.HoldReasons & SERIAL_TX_WAITING_FOR_DSR) {
lpStat->fDsrHold = TRUE;
} else {
lpStat->fDsrHold = FALSE;
}
if (LocalStat.HoldReasons & SERIAL_TX_WAITING_FOR_DCD) {
lpStat->fRlsdHold = TRUE;
} else {
lpStat->fRlsdHold = FALSE;
}
if (LocalStat.HoldReasons & SERIAL_TX_WAITING_FOR_XON) {
lpStat->fXoffHold = TRUE;
} else {
lpStat->fXoffHold = FALSE;
}
if (LocalStat.HoldReasons & SERIAL_TX_WAITING_XOFF_SENT) {
lpStat->fXoffSent = TRUE;
} else {
lpStat->fXoffSent = FALSE;
}
lpStat->fEof = LocalStat.EofReceived;
lpStat->fTxim = LocalStat.WaitForImmediate;
lpStat->cbInQue = LocalStat.AmountInInQueue;
lpStat->cbOutQue = LocalStat.AmountInOutQueue;
}
if (lpErrors) {
*lpErrors = 0;
if (LocalStat.Errors & SERIAL_ERROR_BREAK) {
*lpErrors = *lpErrors | CE_BREAK;
}
if (LocalStat.Errors & SERIAL_ERROR_FRAMING) {
*lpErrors = *lpErrors | CE_FRAME;
}
if (LocalStat.Errors & SERIAL_ERROR_OVERRUN) {
*lpErrors = *lpErrors | CE_OVERRUN;
}
if (LocalStat.Errors & SERIAL_ERROR_QUEUEOVERRUN) {
*lpErrors = *lpErrors | CE_RXOVER;
}
if (LocalStat.Errors & SERIAL_ERROR_PARITY) {
*lpErrors = *lpErrors | CE_RXPARITY;
}
}
CloseHandle(SyncEvent);
return TRUE;
}
BOOL
SetupComm(
HANDLE hFile,
DWORD dwInQueue,
DWORD dwOutQueue
)
/*++
Routine Description:
The communication device is not initialized until SetupComm is
called. This function allocates space for receive and transmit
queues. These queues are used by the interrupt-driven transmit/
receive software and are internal to the provider.
Arguments:
hFile - Specifies the communication device to receive the settings.
The CreateFile function returns this value.
dwInQueue - Specifies the recommended size of the provider's
internal receive queue in bytes. This value must be
even. A value of -1 indicates that the default should
be used.
dwOutQueue - Specifies the recommended size of the provider's
internal transmit queue in bytes. This value must be
even. A value of -1 indicates that the default should
be used.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
NTSTATUS Status;
HANDLE SyncEvent;
IO_STATUS_BLOCK Iosb;
SERIAL_QUEUE_SIZE NewSizes = {0};
//
// Make sure that the sizes are even.
//
if (dwOutQueue != ((DWORD)-1)) {
if (((dwOutQueue/2)*2) != dwOutQueue) {
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
}
if (dwInQueue != ((DWORD)-1)) {
if (((dwInQueue/2)*2) != dwInQueue) {
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
}
NewSizes.InSize = dwInQueue;
NewSizes.OutSize = dwOutQueue;
if (!(SyncEvent = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
}
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_SET_QUEUE_SIZE,
&NewSizes,
sizeof(SERIAL_QUEUE_SIZE),
NULL,
0
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
BaseSetLastNTError(Status);
return FALSE;
}
CloseHandle(SyncEvent);
return TRUE;
}
BOOL
EscapeCommFunction(
HANDLE hFile,
DWORD dwFunc
)
/*++
Routine Description:
This function directs the communication-device specified by the
hFile parameter to carry out the extended function specified by
the dwFunc parameter.
Arguments:
hFile - Specifies the communication device to receive the settings.
The CreateFile function returns this value.
dwFunc - Specifies the function code of the extended function.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
NTSTATUS Status;
IO_STATUS_BLOCK Iosb;
ULONG ControlCode;
HANDLE Event;
switch (dwFunc) {
case SETXOFF: {
ControlCode = IOCTL_SERIAL_SET_XOFF;
break;
}
case SETXON: {
ControlCode = IOCTL_SERIAL_SET_XON;
break;
}
case SETRTS: {
ControlCode = IOCTL_SERIAL_SET_RTS;
break;
}
case CLRRTS: {
ControlCode = IOCTL_SERIAL_CLR_RTS;
break;
}
case SETDTR: {
ControlCode = IOCTL_SERIAL_SET_DTR;
break;
}
case CLRDTR: {
ControlCode = IOCTL_SERIAL_CLR_DTR;
break;
}
case RESETDEV: {
ControlCode = IOCTL_SERIAL_RESET_DEVICE;
break;
}
case SETBREAK: {
ControlCode = IOCTL_SERIAL_SET_BREAK_ON;
break;
}
case CLRBREAK: {
ControlCode = IOCTL_SERIAL_SET_BREAK_OFF;
break;
}
default: {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
}
if (!(Event = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
}
Status = NtDeviceIoControlFile(
hFile,
Event,
NULL,
NULL,
&Iosb,
ControlCode,
NULL,
0,
NULL,
0
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( Event, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(Event);
BaseSetLastNTError(Status);
return FALSE;
}
CloseHandle(Event);
return TRUE;
}
BOOL
GetCommConfig(
HANDLE hCommDev,
LPCOMMCONFIG lpCC,
LPDWORD lpdwSize
)
{
NTSTATUS Status;
IO_STATUS_BLOCK Iosb;
ULONG configLength;
HANDLE Event;
DWORD olddwSize = *lpdwSize;
//
// Ask the device how big the device config structure is.
//
if (!(Event = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
}
Status = NtDeviceIoControlFile(
hCommDev,
Event,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_CONFIG_SIZE,
NULL,
0,
&configLength,
sizeof(configLength)
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( Event, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
configLength = 0;
}
if (!configLength) {
//
// The size needed is simply the size of the comm config structure.
//
CloseHandle(Event);
if (!ARGUMENT_PRESENT(lpdwSize)) {
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
return FALSE;
} else {
*lpdwSize = sizeof(COMMCONFIG);
if (ARGUMENT_PRESENT(lpCC)) {
//
// Fill in the random fields.
//
lpCC->dwSize = sizeof(COMMCONFIG);
lpCC->wVersion = 1;
lpCC->wReserved = 0;
lpCC->dwProviderSubType = PST_RS232;
lpCC->dwProviderOffset = 0;
lpCC->dwProviderSize = 0;
lpCC->wcProviderData[0] = 0;
return GetCommState(
hCommDev,
&lpCC->dcb
);
} else {
return TRUE;
}
}
} else {
if (!ARGUMENT_PRESENT(lpdwSize)) {
CloseHandle(Event);
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
return FALSE;
} else {
if (*lpdwSize < sizeof(COMMCONFIG)) {
CloseHandle(Event);
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
*lpdwSize = configLength;
return FALSE;
} else {
if (ARGUMENT_PRESENT(lpCC)) {
lpCC->wVersion = 1;
lpCC->dwProviderSubType = PST_MODEM;
if (*lpdwSize < configLength) {
lpCC->dwProviderOffset = 0;
lpCC->dwProviderSize = 0;
lpCC->wcProviderData[0] = 0;
*lpdwSize = sizeof(COMMCONFIG);
CloseHandle(Event);
return GetCommState(
hCommDev,
&lpCC->dcb
);
} else {
*lpdwSize = configLength;
//
// Call down to the lower level serial provider
// if there is a passed comm config. Assume
// that the buffer is as large as it needs to be.
// Parameter validation will insure that we
// can write to at least that much.
//
Status = NtDeviceIoControlFile(
hCommDev,
Event,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_GET_COMMCONFIG,
NULL,
0,
lpCC,
configLength
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( Event, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(Event);
BaseSetLastNTError(Status);
return FALSE;
}
//
// Got the config stuff, get the comm state too.
//
CloseHandle(Event);
return GetCommState(
hCommDev,
&lpCC->dcb
);
}
} else {
*lpdwSize = configLength;
CloseHandle(Event);
return TRUE;
}
}
}
}
}
BOOL
GetCommMask(
HANDLE hFile,
LPDWORD lpEvtMask
)
/*++
Routine Description:
This function retrieves the value of the event mask for the handle
hFile. The mask is not cleared
Arguments:
hFile - Specifies the communication device to be examined.
The CreateFile function returns this value.
lpEvtMask - Points to a DWORD which is to receive the mask of events
which are currently enabled.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
NTSTATUS Status;
HANDLE SyncEvent;
IO_STATUS_BLOCK Iosb;
//
// First we do an assert to make sure that the
// values in the win header files are the same
// as the nt serial interface, and that the
// size of the win32 wait mask is the same size
// as the nt wait mask.
//
ASSERT((SERIAL_EV_RXCHAR == EV_RXCHAR ) &&
(SERIAL_EV_RXFLAG == EV_RXFLAG ) &&
(SERIAL_EV_TXEMPTY == EV_TXEMPTY ) &&
(SERIAL_EV_CTS == EV_CTS ) &&
(SERIAL_EV_DSR == EV_DSR ) &&
(SERIAL_EV_RLSD == EV_RLSD ) &&
(SERIAL_EV_BREAK == EV_BREAK ) &&
(SERIAL_EV_ERR == EV_ERR ) &&
(SERIAL_EV_RING == EV_RING ) &&
(SERIAL_EV_PERR == EV_PERR ) &&
(SERIAL_EV_RX80FULL == EV_RX80FULL) &&
(SERIAL_EV_EVENT1 == EV_EVENT1 ) &&
(SERIAL_EV_EVENT2 == EV_EVENT2 ) &&
(sizeof(ULONG) == sizeof(DWORD)));
//
// All is well, get the mask from the driver.
//
if (!(SyncEvent = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
}
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_GET_WAIT_MASK,
NULL,
0,
lpEvtMask,
sizeof(ULONG)
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
BaseSetLastNTError(Status);
return FALSE;
}
CloseHandle(SyncEvent);
return TRUE;
}
BOOL
GetCommModemStatus(
HANDLE hFile,
LPDWORD lpModemStat
)
/*++
Routine Description:
This routine returns the most current value of the modem
status registers non-delta values.
Arguments:
hFile - Specifies the communication device to be examined.
The CreateFile function returns this value.
lpEvtMask - Points to a DWORD which is to receive the mask of
non-delta values in the modem status register.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
NTSTATUS Status;
HANDLE SyncEvent;
IO_STATUS_BLOCK Iosb;
if (!(SyncEvent = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
}
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_GET_MODEMSTATUS,
NULL,
0,
lpModemStat,
sizeof(DWORD)
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
BaseSetLastNTError(Status);
return FALSE;
}
CloseHandle(SyncEvent);
return TRUE;
}
BOOL
GetCommProperties(
HANDLE hFile,
LPCOMMPROP lpCommProp
)
/*++
Routine Description:
This function fills the ubffer pointed to by lpCommProp with the
communications properties associated with the communications device
specified by the hFile.
Arguments:
hFile - Specifies the communication device to be examined.
The CreateFile function returns this value.
lpCommProp - Points to the COMMPROP data structure that is to
receive the communications properties structure. This
structure defines certain properties of the communications
device.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
NTSTATUS Status;
HANDLE SyncEvent;
IO_STATUS_BLOCK Iosb;
DWORD bufferLength;
//
// Make sure that the windows defines and the nt defines are
// still in sync.
//
ASSERT((SERIAL_PCF_DTRDSR == PCF_DTRDSR) &&
(SERIAL_PCF_RTSCTS == PCF_RTSCTS) &&
(SERIAL_PCF_CD == PCF_RLSD) &&
(SERIAL_PCF_PARITY_CHECK == PCF_PARITY_CHECK) &&
(SERIAL_PCF_XONXOFF == PCF_XONXOFF) &&
(SERIAL_PCF_SETXCHAR == PCF_SETXCHAR) &&
(SERIAL_PCF_TOTALTIMEOUTS == PCF_TOTALTIMEOUTS) &&
(SERIAL_PCF_INTTIMEOUTS == PCF_INTTIMEOUTS) &&
(SERIAL_PCF_SPECIALCHARS == PCF_SPECIALCHARS) &&
(SERIAL_PCF_16BITMODE == PCF_16BITMODE) &&
(SERIAL_SP_PARITY == SP_PARITY) &&
(SERIAL_SP_BAUD == SP_BAUD) &&
(SERIAL_SP_DATABITS == SP_DATABITS) &&
(SERIAL_SP_STOPBITS == SP_STOPBITS) &&
(SERIAL_SP_HANDSHAKING == SP_HANDSHAKING) &&
(SERIAL_SP_PARITY_CHECK == SP_PARITY_CHECK) &&
(SERIAL_SP_CARRIER_DETECT == SP_RLSD) &&
(SERIAL_BAUD_075 == BAUD_075) &&
(SERIAL_BAUD_110 == BAUD_110) &&
(SERIAL_BAUD_134_5 == BAUD_134_5) &&
(SERIAL_BAUD_150 == BAUD_150) &&
(SERIAL_BAUD_300 == BAUD_300) &&
(SERIAL_BAUD_600 == BAUD_600) &&
(SERIAL_BAUD_1200 == BAUD_1200) &&
(SERIAL_BAUD_1800 == BAUD_1800) &&
(SERIAL_BAUD_2400 == BAUD_2400) &&
(SERIAL_BAUD_4800 == BAUD_4800) &&
(SERIAL_BAUD_7200 == BAUD_7200) &&
(SERIAL_BAUD_9600 == BAUD_9600) &&
(SERIAL_BAUD_14400 == BAUD_14400) &&
(SERIAL_BAUD_19200 == BAUD_19200) &&
(SERIAL_BAUD_38400 == BAUD_38400) &&
(SERIAL_BAUD_56K == BAUD_56K) &&
(SERIAL_BAUD_57600 == BAUD_57600) &&
(SERIAL_BAUD_115200 == BAUD_115200) &&
(SERIAL_BAUD_USER == BAUD_USER) &&
(SERIAL_DATABITS_5 == DATABITS_5) &&
(SERIAL_DATABITS_6 == DATABITS_6) &&
(SERIAL_DATABITS_7 == DATABITS_7) &&
(SERIAL_DATABITS_8 == DATABITS_8) &&
(SERIAL_DATABITS_16 == DATABITS_16) &&
(SERIAL_DATABITS_16X == DATABITS_16X) &&
(SERIAL_STOPBITS_10 == STOPBITS_10) &&
(SERIAL_STOPBITS_15 == STOPBITS_15) &&
(SERIAL_STOPBITS_20 == STOPBITS_20) &&
(SERIAL_PARITY_NONE == PARITY_NONE) &&
(SERIAL_PARITY_ODD == PARITY_ODD) &&
(SERIAL_PARITY_EVEN == PARITY_EVEN) &&
(SERIAL_PARITY_MARK == PARITY_MARK) &&
(SERIAL_PARITY_SPACE == PARITY_SPACE));
ASSERT((SERIAL_SP_UNSPECIFIED == PST_UNSPECIFIED) &&
(SERIAL_SP_RS232 == PST_RS232) &&
(SERIAL_SP_PARALLEL == PST_PARALLELPORT) &&
(SERIAL_SP_RS422 == PST_RS422) &&
(SERIAL_SP_RS423 == PST_RS423) &&
(SERIAL_SP_RS449 == PST_RS449) &&
(SERIAL_SP_FAX == PST_FAX) &&
(SERIAL_SP_SCANNER == PST_SCANNER) &&
(SERIAL_SP_BRIDGE == PST_NETWORK_BRIDGE) &&
(SERIAL_SP_LAT == PST_LAT) &&
(SERIAL_SP_TELNET == PST_TCPIP_TELNET) &&
(SERIAL_SP_X25 == PST_X25));
ASSERT(sizeof(SERIAL_COMMPROP) == sizeof(COMMPROP));
//
// Get the total length of what to pass down. If the
// application indicates that there is provider specific data
// (by setting dwProvSpec1 to COMMPROP_INITIAILIZED) then
// use what's at the start of the commprop.
//
bufferLength = sizeof(COMMPROP);
if (lpCommProp->dwProvSpec1 == COMMPROP_INITIALIZED) {
bufferLength = lpCommProp->wPacketLength;
}
//
// Zero out the commprop. This might create an access violation
// if it isn't big enough. Which is ok, since we would rather
// get it before we create the sync event.
//
RtlZeroMemory(lpCommProp, bufferLength);
if (!(SyncEvent = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
}
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_GET_PROPERTIES,
NULL,
0,
lpCommProp,
bufferLength
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
BaseSetLastNTError(Status);
return FALSE;
}
CloseHandle(SyncEvent);
return TRUE;
}
BOOL
GetCommState(
HANDLE hFile,
LPDCB lpDCB
)
/*++
Routine Description:
This function fills the buffer pointed to by the lpDCB parameter with
the device control block of the communication device specified by hFile
parameter.
Arguments:
hFile - Specifies the communication device to be examined.
The CreateFile function returns this value.
lpDCB - Points to the DCB data structure that is to receive the current
device control block. The structure defines the control settings
for the device.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
SERIAL_BAUD_RATE LocalBaud;
SERIAL_LINE_CONTROL LineControl;
SERIAL_CHARS Chars;
SERIAL_HANDFLOW HandFlow;
IO_STATUS_BLOCK Iosb;
NTSTATUS Status;
//
// Given the possiblity that the app may be doing asynchronous
// io we need an event to wait on.
//
// We need to make sure that any exit to this routine closes this
// event handle.
//
HANDLE SyncEvent;
//
// Make sure the windows mapping is the same as the NT mapping.
//
ASSERT((ONESTOPBIT == STOP_BIT_1) &&
(ONE5STOPBITS == STOP_BITS_1_5) &&
(TWOSTOPBITS == STOP_BITS_2));
ASSERT((NOPARITY == NO_PARITY) &&
(ODDPARITY == ODD_PARITY) &&
(EVENPARITY == EVEN_PARITY) &&
(MARKPARITY == MARK_PARITY) &&
(SPACEPARITY == SPACE_PARITY));
//
// Zero out the dcb. This might create an access violation
// if it isn't big enough. Which is ok, since we would rather
// get it before we create the sync event.
//
RtlZeroMemory(lpDCB, sizeof(DCB));
lpDCB->DCBlength = sizeof(DCB);
lpDCB->fBinary = TRUE;
if (!(SyncEvent = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
}
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_GET_BAUD_RATE,
NULL,
0,
&LocalBaud,
sizeof(LocalBaud)
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
BaseSetLastNTError(Status);
return FALSE;
}
lpDCB->BaudRate = LocalBaud.BaudRate;
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_GET_LINE_CONTROL,
NULL,
0,
&LineControl,
sizeof(LineControl)
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
BaseSetLastNTError(Status);
return FALSE;
}
lpDCB->Parity = LineControl.Parity;
lpDCB->ByteSize = LineControl.WordLength;
lpDCB->StopBits = LineControl.StopBits;
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_GET_CHARS,
NULL,
0,
&Chars,
sizeof(Chars)
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
BaseSetLastNTError(Status);
return FALSE;
}
lpDCB->XonChar = Chars.XonChar;
lpDCB->XoffChar = Chars.XoffChar;
lpDCB->ErrorChar = Chars.ErrorChar;
lpDCB->EofChar = Chars.EofChar;
lpDCB->EvtChar = Chars.EventChar;
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_GET_HANDFLOW,
NULL,
0,
&HandFlow,
sizeof(HandFlow)
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
BaseSetLastNTError(Status);
return FALSE;
}
if (HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE) {
lpDCB->fOutxCtsFlow = TRUE;
}
if (HandFlow.ControlHandShake & SERIAL_DSR_HANDSHAKE) {
lpDCB->fOutxDsrFlow = TRUE;
}
if (HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT) {
lpDCB->fOutX = TRUE;
}
if (HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE) {
lpDCB->fInX = TRUE;
}
if (HandFlow.FlowReplace & SERIAL_NULL_STRIPPING) {
lpDCB->fNull = TRUE;
}
if (HandFlow.FlowReplace & SERIAL_ERROR_CHAR) {
lpDCB->fErrorChar = TRUE;
}
if (HandFlow.FlowReplace & SERIAL_XOFF_CONTINUE) {
lpDCB->fTXContinueOnXoff = TRUE;
}
if (HandFlow.ControlHandShake & SERIAL_ERROR_ABORT) {
lpDCB->fAbortOnError = TRUE;
}
switch (HandFlow.FlowReplace & SERIAL_RTS_MASK) {
case 0:
lpDCB->fRtsControl = RTS_CONTROL_DISABLE;
break;
case SERIAL_RTS_CONTROL:
lpDCB->fRtsControl = RTS_CONTROL_ENABLE;
break;
case SERIAL_RTS_HANDSHAKE:
lpDCB->fRtsControl = RTS_CONTROL_HANDSHAKE;
break;
case SERIAL_TRANSMIT_TOGGLE:
lpDCB->fRtsControl = RTS_CONTROL_TOGGLE;
break;
}
switch (HandFlow.ControlHandShake & SERIAL_DTR_MASK) {
case 0:
lpDCB->fDtrControl = DTR_CONTROL_DISABLE;
break;
case SERIAL_DTR_CONTROL:
lpDCB->fDtrControl = DTR_CONTROL_ENABLE;
break;
case SERIAL_DTR_HANDSHAKE:
lpDCB->fDtrControl = DTR_CONTROL_HANDSHAKE;
break;
}
lpDCB->fDsrSensitivity =
(HandFlow.ControlHandShake & SERIAL_DSR_SENSITIVITY)?(TRUE):(FALSE);
lpDCB->XonLim = (WORD)HandFlow.XonLimit;
lpDCB->XoffLim = (WORD)HandFlow.XoffLimit;
CloseHandle(SyncEvent);
return TRUE;
}
BOOL
GetCommTimeouts(
HANDLE hFile,
LPCOMMTIMEOUTS lpCommTimeouts
)
/*++
Routine Description:
This function returns the timeout characteristics for all read and
write operations on the handle specified by hFile.
Arguments:
hFile - Specifies the communication device to be examined.
The CreateFile function returns this value.
lpCommTimeouts - Points to a structure which is to receive the
current communications timeouts.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
SERIAL_TIMEOUTS To;
NTSTATUS Status;
IO_STATUS_BLOCK Iosb;
HANDLE Event;
if (!(Event = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
} else {
Status = NtDeviceIoControlFile(
hFile,
Event,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_GET_TIMEOUTS,
NULL,
0,
&To,
sizeof(To)
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( Event, FALSE, NULL );
if ( NT_SUCCESS( Status )) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
BaseSetLastNTError(Status);
CloseHandle(Event);
return FALSE;
}
CloseHandle(Event);
//
// Everything went ok. Move the value from the Nt records
// to the windows record.
//
lpCommTimeouts->ReadIntervalTimeout = To.ReadIntervalTimeout;
lpCommTimeouts->ReadTotalTimeoutMultiplier = To.ReadTotalTimeoutMultiplier;
lpCommTimeouts->ReadTotalTimeoutConstant = To.ReadTotalTimeoutConstant;
lpCommTimeouts->WriteTotalTimeoutMultiplier = To.WriteTotalTimeoutMultiplier;
lpCommTimeouts->WriteTotalTimeoutConstant = To.WriteTotalTimeoutConstant;
return TRUE;
}
}
BOOL
PurgeComm(
HANDLE hFile,
DWORD dwFlags
)
/*++
Routine Description:
This function is used to purge all characters from the transmit
or receive queues of the communication device specified by the
hFile parameter. The dwFlags parameter specifies what function
is to be performed.
Arguments:
hFile - Specifies the communication device to be purged.
The CreateFile function returns this value.
dwFlags - Bit mask defining actions to be taken.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
HANDLE Event;
NTSTATUS Status;
IO_STATUS_BLOCK Iosb;
if (!(Event = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
} else {
Status = NtDeviceIoControlFile(
hFile,
Event,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_PURGE,
&dwFlags,
sizeof(ULONG),
NULL,
0
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( Event, FALSE, NULL );
if ( NT_SUCCESS( Status )) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(Event);
BaseSetLastNTError(Status);
return FALSE;
}
CloseHandle(Event);
return TRUE;
}
}
BOOL
SetCommBreak(
HANDLE hFile
)
/*++
Routine Description:
The function suspends character transmission and places the transmission
line in a break state until the break condition is cleared..
Arguments:
hFile - Specifies the communication device to be suspended.
The CreateFile function returns this value.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
return EscapeCommFunction(hFile,SETBREAK);
}
BOOL
SetCommConfig(
HANDLE hCommDev,
LPCOMMCONFIG lpCC,
DWORD dwSize
)
{
NTSTATUS Status;
IO_STATUS_BLOCK Iosb;
HANDLE Event;
LPCOMMCONFIG comConf = lpCC;
if (lpCC->dwProviderOffset) {
if (!(Event = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
}
//
//
// Call the driver to set the config structure.
//
Status = NtDeviceIoControlFile(
hCommDev,
Event,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_SET_COMMCONFIG,
lpCC,
dwSize,
NULL,
0
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( Event, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(Event);
BaseSetLastNTError(Status);
return FALSE;
}
CloseHandle(Event);
}
return SetCommState(
hCommDev,
&comConf->dcb
);
}
BOOL
SetCommMask(
HANDLE hFile,
DWORD dwEvtMask
)
/*++
Routine Description:
The function enables the event mask of the communication device
specified by the hFile parameter. The bits of the nEvtMask parameter
define which events are to be enabled.
Arguments:
hFile - Specifies the communication device to receive the settings.
The CreateFile function returns this value.
dwEvtMask - Specifies which events are to enabled.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
NTSTATUS Status;
IO_STATUS_BLOCK Iosb;
HANDLE Event;
//
// First we do an assert to make sure that the
// values in the win header files are the same
// as the nt serial interface and the the size
// mask that serial expects is the same as the
// size that win32 expects.
//
ASSERT((SERIAL_EV_RXCHAR == EV_RXCHAR ) &&
(SERIAL_EV_RXFLAG == EV_RXFLAG ) &&
(SERIAL_EV_TXEMPTY == EV_TXEMPTY ) &&
(SERIAL_EV_CTS == EV_CTS ) &&
(SERIAL_EV_DSR == EV_DSR ) &&
(SERIAL_EV_RLSD == EV_RLSD ) &&
(SERIAL_EV_BREAK == EV_BREAK ) &&
(SERIAL_EV_ERR == EV_ERR ) &&
(SERIAL_EV_RING == EV_RING ) &&
(SERIAL_EV_PERR == EV_PERR ) &&
(SERIAL_EV_RX80FULL == EV_RX80FULL) &&
(SERIAL_EV_EVENT1 == EV_EVENT1 ) &&
(SERIAL_EV_EVENT2 == EV_EVENT2 ) &&
(sizeof(DWORD) == sizeof(ULONG)));
//
// Make sure that the users mask doesn't contain any values
// we don't support.
//
if (dwEvtMask & (~(EV_RXCHAR |
EV_RXFLAG |
EV_TXEMPTY |
EV_CTS |
EV_DSR |
EV_RLSD |
EV_BREAK |
EV_ERR |
EV_RING |
EV_PERR |
EV_RX80FULL |
EV_EVENT1 |
EV_EVENT2))) {
SetLastError(ERROR_INVALID_DATA);
return FALSE;
}
if (!(Event = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
} else {
//
// All is well, send the mask to the driver.
//
ULONG LocalMask = dwEvtMask;
Status = NtDeviceIoControlFile(
hFile,
Event,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_SET_WAIT_MASK,
&LocalMask,
sizeof(ULONG),
NULL,
0
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( Event, FALSE, NULL );
if ( NT_SUCCESS( Status )) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(Event);
BaseSetLastNTError(Status);
return FALSE;
}
CloseHandle(Event);
return TRUE;
}
}
BOOL
SetCommState(
HANDLE hFile,
LPDCB lpDCB
)
/*++
Routine Description:
The SetCommState function sets a communication device to the state
specified in the lpDCB parameter. The device is identified by the
hFile parameter. This function reinitializes all hardwae and controls
as specified byt the lpDCB, but does not empty the transmit or
receive queues.
Arguments:
hFile - Specifies the communication device to receive the settings.
The CreateFile function returns this value.
lpDCB - Points to a DCB structure that contains the desired
communications setting for the device.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
SERIAL_BAUD_RATE LocalBaud;
SERIAL_LINE_CONTROL LineControl;
SERIAL_CHARS Chars;
SERIAL_HANDFLOW HandFlow = {0};
IO_STATUS_BLOCK Iosb;
NTSTATUS Status;
//
// Keep a copy of what the DCB was like before we started
// changing things. If some error occurs we can use
// it to restore the old setup.
//
DCB OldDcb;
//
// Given the possiblity that the app may be doing asynchronous
// io we need an event to wait on. While it would be very
// strange to be setting the comm state while IO is active
// we need to make sure we don't compound the problem by
// returning before this API's IO is actually finished. This
// can happen because the file handle is set on the completion
// of any IO.
//
// We need to make sure that any exit to this routine closes this
// event handle.
//
HANDLE SyncEvent;
if (GetCommState(
hFile,
&OldDcb
)) {
//
// Try to set the baud rate. If we fail here, we just return
// because we never actually got to set anything.
//
if (!(SyncEvent = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
}
LocalBaud.BaudRate = lpDCB->BaudRate;
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_SET_BAUD_RATE,
&LocalBaud,
sizeof(LocalBaud),
NULL,
0
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
BaseSetLastNTError(Status);
return FALSE;
}
LineControl.StopBits = lpDCB->StopBits;
LineControl.Parity = lpDCB->Parity;
LineControl.WordLength = lpDCB->ByteSize;
LocalBaud.BaudRate = lpDCB->BaudRate;
Chars.XonChar = lpDCB->XonChar;
Chars.XoffChar = lpDCB->XoffChar;
Chars.ErrorChar = lpDCB->ErrorChar;
Chars.BreakChar = lpDCB->ErrorChar;
Chars.EofChar = lpDCB->EofChar;
Chars.EventChar = lpDCB->EvtChar;
HandFlow.FlowReplace &= ~SERIAL_RTS_MASK;
switch (lpDCB->fRtsControl) {
case RTS_CONTROL_DISABLE:
break;
case RTS_CONTROL_ENABLE:
HandFlow.FlowReplace |= SERIAL_RTS_CONTROL;
break;
case RTS_CONTROL_HANDSHAKE:
HandFlow.FlowReplace |= SERIAL_RTS_HANDSHAKE;
break;
case RTS_CONTROL_TOGGLE:
HandFlow.FlowReplace |= SERIAL_TRANSMIT_TOGGLE;
break;
default:
SetCommState(
hFile,
&OldDcb
);
CloseHandle(SyncEvent);
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
return FALSE;
}
HandFlow.ControlHandShake &= ~SERIAL_DTR_MASK;
switch (lpDCB->fDtrControl) {
case DTR_CONTROL_DISABLE:
break;
case DTR_CONTROL_ENABLE:
HandFlow.ControlHandShake |= SERIAL_DTR_CONTROL;
break;
case DTR_CONTROL_HANDSHAKE:
HandFlow.ControlHandShake |= SERIAL_DTR_HANDSHAKE;
break;
default:
SetCommState(
hFile,
&OldDcb
);
CloseHandle(SyncEvent);
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
return FALSE;
}
if (lpDCB->fDsrSensitivity) {
HandFlow.ControlHandShake |= SERIAL_DSR_SENSITIVITY;
}
if (lpDCB->fOutxCtsFlow) {
HandFlow.ControlHandShake |= SERIAL_CTS_HANDSHAKE;
}
if (lpDCB->fOutxDsrFlow) {
HandFlow.ControlHandShake |= SERIAL_DSR_HANDSHAKE;
}
if (lpDCB->fOutX) {
HandFlow.FlowReplace |= SERIAL_AUTO_TRANSMIT;
}
if (lpDCB->fInX) {
HandFlow.FlowReplace |= SERIAL_AUTO_RECEIVE;
}
if (lpDCB->fNull) {
HandFlow.FlowReplace |= SERIAL_NULL_STRIPPING;
}
if (lpDCB->fErrorChar) {
HandFlow.FlowReplace |= SERIAL_ERROR_CHAR;
}
if (lpDCB->fTXContinueOnXoff) {
HandFlow.FlowReplace |= SERIAL_XOFF_CONTINUE;
}
if (lpDCB->fAbortOnError) {
HandFlow.ControlHandShake |= SERIAL_ERROR_ABORT;
}
//
// For win95 compatiblity, if we are setting with
// xxx_control_XXXXXXX then set the modem status line
// to that state.
//
if (lpDCB->fRtsControl == RTS_CONTROL_ENABLE) {
EscapeCommFunction(
hFile,
SETRTS
);
} else if (lpDCB->fRtsControl == RTS_CONTROL_DISABLE) {
EscapeCommFunction(
hFile,
CLRRTS
);
}
if (lpDCB->fDtrControl == DTR_CONTROL_ENABLE) {
EscapeCommFunction(
hFile,
SETDTR
);
} else if (lpDCB->fDtrControl == DTR_CONTROL_DISABLE) {
EscapeCommFunction(
hFile,
CLRDTR
);
}
HandFlow.XonLimit = lpDCB->XonLim;
HandFlow.XoffLimit = lpDCB->XoffLim;
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_SET_LINE_CONTROL,
&LineControl,
sizeof(LineControl),
NULL,
0
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
SetCommState(
hFile,
&OldDcb
);
BaseSetLastNTError(Status);
return FALSE;
}
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_SET_CHARS,
&Chars,
sizeof(Chars),
NULL,
0
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
SetCommState(
hFile,
&OldDcb
);
BaseSetLastNTError(Status);
return FALSE;
}
Status = NtDeviceIoControlFile(
hFile,
SyncEvent,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_SET_HANDFLOW,
&HandFlow,
sizeof(HandFlow),
NULL,
0
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(SyncEvent);
SetCommState(
hFile,
&OldDcb
);
BaseSetLastNTError(Status);
return FALSE;
}
CloseHandle(SyncEvent);
return TRUE;
}
return FALSE;
}
BOOL
SetCommTimeouts(
HANDLE hFile,
LPCOMMTIMEOUTS lpCommTimeouts
)
/*++
Routine Description:
This function establishes the timeout characteristics for all
read and write operations on the handle specified by hFile.
Arguments:
hFile - Specifies the communication device to receive the settings.
The CreateFile function returns this value.
lpCommTimeouts - Points to a structure containing timeout parameters.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
SERIAL_TIMEOUTS To;
NTSTATUS Status;
IO_STATUS_BLOCK Iosb;
HANDLE Event;
To.ReadIntervalTimeout = lpCommTimeouts->ReadIntervalTimeout;
To.ReadTotalTimeoutMultiplier = lpCommTimeouts->ReadTotalTimeoutMultiplier;
To.ReadTotalTimeoutConstant = lpCommTimeouts->ReadTotalTimeoutConstant;
To.WriteTotalTimeoutMultiplier = lpCommTimeouts->WriteTotalTimeoutMultiplier;
To.WriteTotalTimeoutConstant = lpCommTimeouts->WriteTotalTimeoutConstant;
if (!(Event = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
} else {
Status = NtDeviceIoControlFile(
hFile,
Event,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_SET_TIMEOUTS,
&To,
sizeof(To),
NULL,
0
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( Event, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(Event);
BaseSetLastNTError(Status);
return FALSE;
}
CloseHandle(Event);
return TRUE;
}
}
BOOL
TransmitCommChar(
HANDLE hFile,
char cChar
)
/*++
Routine Description:
The function marks the character specified by the cChar parameter
for immediate transmission, by placing it at the head of the transmit
queue.
Arguments:
hFile - Specifies the communication device to send the character.
The CreateFile function returns this value.
cChar - Specifies the character to be placed in the recieve queue.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
NTSTATUS Status;
IO_STATUS_BLOCK Iosb;
HANDLE Event;
if (!(Event = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
} else {
Status = NtDeviceIoControlFile(
hFile,
Event,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_IMMEDIATE_CHAR,
&cChar,
sizeof(UCHAR),
NULL,
0
);
if ( Status == STATUS_PENDING) {
// Operation must complete before return & IoStatusBlock destroyed
Status = NtWaitForSingleObject( Event, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
if (NT_ERROR(Status)) {
CloseHandle(Event);
BaseSetLastNTError(Status);
return FALSE;
}
CloseHandle(Event);
return TRUE;
}
}
BOOL
WaitCommEvent(
HANDLE hFile,
LPDWORD lpEvtMask,
LPOVERLAPPED lpOverlapped
)
/*++
Routine Description:
This function will wait until any of the events occur that were
provided as the nEvtMask parameter to SetcommMask. If while waiting
the event mask is changed (via another call to SetCommMask), the
function will return immediately. The function will fill the EvtMask
pointed to by the lpEvtMask parameter with the reasons that the
wait was satisfied.
Arguments:
hFile - Specifies the communication device to be waited on.
The CreateFile function returns this value.
lpEvtMask - Points to a mask that will receive the reason that
the wait was satisfied.
lpOverLapped - An optional overlapped handle.
Return Value:
The return value is TRUE if the function is successful or FALSE
if an error occurs.
--*/
{
NTSTATUS Status;
if (ARGUMENT_PRESENT(lpOverlapped)) {
lpOverlapped->Internal = (DWORD)STATUS_PENDING;
Status = NtDeviceIoControlFile(
hFile,
lpOverlapped->hEvent,
NULL,
(ULONG_PTR)lpOverlapped->hEvent & 1 ? NULL : lpOverlapped,
(PIO_STATUS_BLOCK)&lpOverlapped->Internal,
IOCTL_SERIAL_WAIT_ON_MASK,
NULL,
0,
lpEvtMask,
sizeof(ULONG)
);
if (!NT_ERROR(Status) && (Status != STATUS_PENDING)) {
return TRUE;
} else {
BaseSetLastNTError(Status);
return FALSE;
}
} else {
IO_STATUS_BLOCK Iosb;
HANDLE Event;
if (!(Event = CreateEvent(
NULL,
TRUE,
FALSE,
NULL
))) {
return FALSE;
} else {
Status = NtDeviceIoControlFile(
hFile,
Event,
NULL,
NULL,
&Iosb,
IOCTL_SERIAL_WAIT_ON_MASK,
NULL,
0,
lpEvtMask,
sizeof(ULONG)
);
if ( Status == STATUS_PENDING) {
//
// Operation must complete before return &
// IoStatusBlock destroyed
Status = NtWaitForSingleObject( Event, FALSE, NULL );
if ( NT_SUCCESS(Status)) {
Status = Iosb.Status;
}
}
CloseHandle(Event);
if (NT_ERROR(Status)) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}
}
}