1605 lines
31 KiB
C
1605 lines
31 KiB
C
/*++
|
||
|
||
Copyright (c) 1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
blddcb.c
|
||
|
||
Abstract:
|
||
|
||
This module implements Win32 comm api buildcommdcb
|
||
|
||
Author:
|
||
|
||
Anthony V. Ercolano (tonye) 10-March-1992
|
||
|
||
Actually this code was generously donated by
|
||
ramonsa. It is basically the code used for
|
||
the mode command.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include <basedll.h>
|
||
|
||
typedef struct _PARSE_CONTEXT {
|
||
PSTR CharIndex;
|
||
PSTR AdvanceIndex;
|
||
PSTR MatchBegin;
|
||
PSTR MatchEnd;
|
||
} PARSE_CONTEXT,*PPARSE_CONTEXT;
|
||
|
||
static
|
||
BOOL
|
||
BuildDcb (
|
||
LPCSTR L,
|
||
LPDCB Dcb,
|
||
LPCOMMTIMEOUTS To
|
||
);
|
||
|
||
static
|
||
BOOL
|
||
Match(
|
||
PPARSE_CONTEXT C,
|
||
PSTR Pattern
|
||
);
|
||
|
||
static
|
||
VOID
|
||
Advance(
|
||
PPARSE_CONTEXT C
|
||
);
|
||
|
||
static
|
||
DWORD
|
||
GetNumber(
|
||
PPARSE_CONTEXT C
|
||
);
|
||
|
||
static
|
||
BOOL
|
||
ConvertBaudRate (
|
||
DWORD BaudIn,
|
||
PDWORD BaudRate
|
||
);
|
||
|
||
static
|
||
BOOL
|
||
ConvertDataBits (
|
||
DWORD DataBitsIn,
|
||
PBYTE DataBitsOut
|
||
);
|
||
|
||
static
|
||
BOOL
|
||
ConvertStopBits (
|
||
DWORD StopBitsIn,
|
||
PBYTE StopBits
|
||
);
|
||
|
||
static
|
||
BOOL
|
||
ConvertParity (
|
||
CHAR ParityIn,
|
||
PBYTE Parity
|
||
);
|
||
|
||
static
|
||
BOOL
|
||
ConvertDtrControl (
|
||
PSTR IdxBegin,
|
||
PSTR IdxEnd,
|
||
PBYTE DtrControl
|
||
);
|
||
|
||
static
|
||
BOOL
|
||
ConvertRtsControl (
|
||
PSTR IdxBegin,
|
||
PSTR IdxEnd,
|
||
PBYTE RtsControl
|
||
);
|
||
|
||
static
|
||
VOID
|
||
IgnoreDeviceName(
|
||
IN PPARSE_CONTEXT C
|
||
);
|
||
|
||
static
|
||
NTSTATUS
|
||
DeviceNameCompare(
|
||
IN PWSTR ValueName,
|
||
IN ULONG ValueType,
|
||
IN PVOID ValueData,
|
||
IN ULONG ValueLength,
|
||
IN PVOID Context,
|
||
IN PVOID EntryContext
|
||
);
|
||
|
||
|
||
BOOL
|
||
BuildCommDCBAndTimeoutsW(
|
||
LPCWSTR lpDef,
|
||
LPDCB lpDCB,
|
||
LPCOMMTIMEOUTS lpCommTimeouts
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function translates the definition string specified by the
|
||
lpDef parameter into appropriate device-control block codes and
|
||
places these codes into the block pointed to by the lpDCB parameter.
|
||
It also sets the timeouts if specified.
|
||
|
||
Arguments:
|
||
|
||
lpDef - Points to a null terminated character string that specifies
|
||
the device control information for the device.
|
||
|
||
lpDCB - Points to the DCB data structure that is to receive the
|
||
translated string.. The structure defines the control
|
||
settings for the serial communications device.
|
||
|
||
lpCommTimeouts - It "TO" included, it will set the timeouts.
|
||
|
||
Return Value:
|
||
|
||
The return value is TRUE if the function is successful or FALSE
|
||
if an error occurs.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
UNICODE_STRING Unicode;
|
||
ANSI_STRING Ansi;
|
||
NTSTATUS Status;
|
||
BOOL AnsiBool;
|
||
|
||
RtlInitUnicodeString(
|
||
&Unicode,
|
||
lpDef
|
||
);
|
||
|
||
Status = RtlUnicodeStringToAnsiString(
|
||
&Ansi,
|
||
&Unicode,
|
||
TRUE
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
BaseSetLastNTError(Status);
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
AnsiBool = BuildCommDCBAndTimeoutsA(
|
||
(LPCSTR)Ansi.Buffer,
|
||
lpDCB,
|
||
lpCommTimeouts
|
||
);
|
||
|
||
RtlFreeAnsiString(&Ansi);
|
||
return AnsiBool;
|
||
|
||
}
|
||
|
||
BOOL
|
||
BuildCommDCBAndTimeoutsA(
|
||
LPCSTR lpDef,
|
||
LPDCB lpDCB,
|
||
LPCOMMTIMEOUTS lpCommTimeouts
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function translates the definition string specified by the
|
||
lpDef parameter into appropriate device-control block codes and
|
||
places these codes into the block pointed to by the lpDCB parameter.
|
||
It can also set the timeout value.
|
||
|
||
Arguments:
|
||
|
||
lpDef - Points to a null terminated character string that specifies
|
||
the device control information for the device.
|
||
|
||
lpDCB - Points to the DCB data structure that is to receive the
|
||
translated string.. The structure defines the control
|
||
settings for the serial communications device.
|
||
|
||
lpCommTimeouts - If TO included in string then timeouts are also set.
|
||
|
||
Return Value:
|
||
|
||
The return value is TRUE if the function is successful or FALSE
|
||
if an error occurs.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
if (!BuildDcb(
|
||
lpDef,
|
||
lpDCB,
|
||
lpCommTimeouts
|
||
)) {
|
||
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
return FALSE;
|
||
|
||
} else {
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
BOOL
|
||
BuildCommDCBW(
|
||
LPCWSTR lpDef,
|
||
LPDCB lpDCB
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function translates the definition string specified by the
|
||
lpDef parameter into appropriate device-control block codes and
|
||
places these codes into the block pointed to by the lpDCB parameter.
|
||
|
||
Arguments:
|
||
|
||
lpDef - Points to a null terminated character string that specifies
|
||
the device control information for the device.
|
||
|
||
lpDCB - Points to the DCB data structure that is to receive the
|
||
translated string.. The structure defines the control
|
||
settings for the serial communications device.
|
||
|
||
Return Value:
|
||
|
||
The return value is TRUE if the function is successful or FALSE
|
||
if an error occurs.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
UNICODE_STRING Unicode;
|
||
ANSI_STRING Ansi;
|
||
NTSTATUS Status;
|
||
BOOL AnsiBool;
|
||
|
||
RtlInitUnicodeString(
|
||
&Unicode,
|
||
lpDef
|
||
);
|
||
|
||
Status = RtlUnicodeStringToAnsiString(
|
||
&Ansi,
|
||
&Unicode,
|
||
TRUE
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
BaseSetLastNTError(Status);
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
AnsiBool = BuildCommDCBA(
|
||
(LPCSTR)Ansi.Buffer,
|
||
lpDCB
|
||
);
|
||
|
||
RtlFreeAnsiString(&Ansi);
|
||
return AnsiBool;
|
||
|
||
}
|
||
|
||
BOOL
|
||
BuildCommDCBA(
|
||
LPCSTR lpDef,
|
||
LPDCB lpDCB
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function translates the definition string specified by the
|
||
lpDef parameter into appropriate device-control block codes and
|
||
places these codes into the block pointed to by the lpDCB parameter.
|
||
|
||
Arguments:
|
||
|
||
lpDef - Points to a null terminated character string that specifies
|
||
the device control information for the device.
|
||
|
||
lpDCB - Points to the DCB data structure that is to receive the
|
||
translated string.. The structure defines the control
|
||
settings for the serial communications device.
|
||
|
||
Return Value:
|
||
|
||
The return value is TRUE if the function is successful or FALSE
|
||
if an error occurs.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
COMMTIMEOUTS JunkTimeouts;
|
||
|
||
if (!BuildDcb(
|
||
lpDef,
|
||
lpDCB,
|
||
&JunkTimeouts
|
||
)) {
|
||
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
return FALSE;
|
||
|
||
} else {
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
static
|
||
BOOL
|
||
BuildDcb (
|
||
LPCSTR L,
|
||
LPDCB Dcb,
|
||
LPCOMMTIMEOUTS To
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
L - A pointer to the string to convert to a DCB.
|
||
Dcb - The dcb to fill in.
|
||
|
||
Return Value:
|
||
|
||
FALSE if the string has some error, TRUE otherwise.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
BOOL SetBaud = FALSE;
|
||
BOOL SetDataBits = FALSE;
|
||
BOOL SetStopBits = FALSE;
|
||
BOOL SetParity = FALSE;
|
||
BOOL SetRetry = FALSE;
|
||
BOOL SetTimeOut = FALSE;
|
||
BOOL SetXon = FALSE;
|
||
BOOL SetOdsr = FALSE;
|
||
BOOL SetIdsr = FALSE;
|
||
BOOL SetOcts = FALSE;
|
||
BOOL SetDtrControl = FALSE;
|
||
BOOL SetRtsControl = FALSE;
|
||
|
||
DWORD Baud;
|
||
BYTE DataBits;
|
||
BYTE StopBits;
|
||
BYTE Parity;
|
||
BOOL TimeOut;
|
||
BOOL Xon;
|
||
BOOL Odsr;
|
||
BOOL Idsr;
|
||
BOOL Octs;
|
||
BYTE DtrControl;
|
||
BYTE RtsControl;
|
||
PARSE_CONTEXT C = {0};
|
||
|
||
C.CharIndex = C.AdvanceIndex = (PSTR)L;
|
||
|
||
//
|
||
// This following call will query all of the *current* serial
|
||
// provider names. If it finds that the argurment string
|
||
// contains the name (with an optional :) it will simply
|
||
// advance past it.
|
||
//
|
||
|
||
IgnoreDeviceName(&C);
|
||
|
||
if ( Match(&C, "#" ) ) {
|
||
|
||
//
|
||
// Old syntax, where parameter are positional and comma-delimited.
|
||
//
|
||
// We will use the following automata for parsing the input
|
||
// (eoi = end of input):
|
||
//
|
||
// eoi
|
||
// [Baud]------------->[End]
|
||
// | ^
|
||
// |, |eoi
|
||
// v |
|
||
// [a]-----------+
|
||
// | ^
|
||
// | @ |eoi
|
||
// +-->[Parity]-+
|
||
// | | ^
|
||
// | |, |
|
||
// |<----+ |
|
||
// | |
|
||
// |, |eoi
|
||
// | |
|
||
// v |
|
||
// [b]-----------+
|
||
// | ^
|
||
// | # |eoi
|
||
// +-->[Data]---+
|
||
// | | ^
|
||
// | |, |
|
||
// |<----+ |
|
||
// | |
|
||
// |, |eoi
|
||
// v |
|
||
// [c]-----------+
|
||
// | ^
|
||
// | # |eoi
|
||
// +-->[Stop]---+
|
||
//
|
||
|
||
//
|
||
// Assume xon=off
|
||
//
|
||
|
||
SetXon = TRUE;
|
||
SetOdsr = TRUE;
|
||
SetOcts = TRUE;
|
||
SetDtrControl = TRUE;
|
||
SetRtsControl = TRUE;
|
||
Xon = FALSE;
|
||
Odsr = FALSE;
|
||
Octs = FALSE;
|
||
DtrControl = DTR_CONTROL_ENABLE;
|
||
RtsControl = RTS_CONTROL_ENABLE;
|
||
|
||
if (!ConvertBaudRate( GetNumber(&C), &Baud )) {
|
||
return FALSE;
|
||
}
|
||
SetBaud = TRUE;
|
||
Advance(&C);
|
||
|
||
//
|
||
// A:
|
||
//
|
||
if ( !Match(&C, "," ) ) {
|
||
goto Eoi;
|
||
}
|
||
Advance(&C);
|
||
|
||
if ( !Match(&C, "," ) && Match(&C, "@" ) ) {
|
||
|
||
//
|
||
// Parity
|
||
//
|
||
if (!ConvertParity( *C.MatchBegin,&Parity )) {
|
||
return FALSE;
|
||
}
|
||
SetParity = TRUE;
|
||
Advance(&C);
|
||
}
|
||
|
||
//
|
||
// B:
|
||
//
|
||
if ( !Match(&C, "," )) {
|
||
goto Eoi;
|
||
}
|
||
Advance(&C);
|
||
|
||
if ( Match(&C, "#" )) {
|
||
|
||
//
|
||
// Data bits
|
||
//
|
||
if (!ConvertDataBits( GetNumber(&C),&DataBits )) {
|
||
return FALSE;
|
||
}
|
||
SetDataBits = TRUE;
|
||
Advance(&C);
|
||
}
|
||
|
||
//
|
||
// C:
|
||
//
|
||
if ( !Match(&C, "," )) {
|
||
goto Eoi;
|
||
}
|
||
Advance(&C);
|
||
|
||
if ( Match(&C, "1.5" ) ) {
|
||
StopBits = ONE5STOPBITS;
|
||
SetStopBits = TRUE;
|
||
Advance(&C);
|
||
} else if ( Match(&C, "#" ) ) {
|
||
if (!ConvertStopBits( GetNumber(&C),&StopBits)) {
|
||
return FALSE;
|
||
}
|
||
SetStopBits = TRUE;
|
||
Advance(&C);
|
||
}
|
||
|
||
if ( !Match(&C, "," )) {
|
||
goto Eoi;
|
||
}
|
||
|
||
Advance(&C);
|
||
|
||
if ( Match(&C, "x" ) ) {
|
||
|
||
//
|
||
// XON=ON
|
||
//
|
||
SetXon = TRUE;
|
||
SetOdsr = TRUE;
|
||
SetOcts = TRUE;
|
||
SetDtrControl = TRUE;
|
||
SetRtsControl = TRUE;
|
||
Xon = TRUE;
|
||
Odsr = FALSE;
|
||
Octs = FALSE;
|
||
DtrControl = DTR_CONTROL_ENABLE;
|
||
RtsControl = RTS_CONTROL_ENABLE;
|
||
Advance(&C);
|
||
|
||
} else if ( Match(&C, "p" ) ) {
|
||
|
||
//
|
||
// Permanent retry - Hardware handshaking
|
||
//
|
||
|
||
SetXon = TRUE;
|
||
SetOdsr = TRUE;
|
||
SetOcts = TRUE;
|
||
SetDtrControl = TRUE;
|
||
SetRtsControl = TRUE;
|
||
Xon = FALSE;
|
||
Odsr = TRUE;
|
||
Octs = TRUE;
|
||
DtrControl = DTR_CONTROL_HANDSHAKE;
|
||
RtsControl = RTS_CONTROL_HANDSHAKE;
|
||
Advance(&C);
|
||
|
||
} else {
|
||
|
||
//
|
||
// XON=OFF
|
||
//
|
||
SetXon = TRUE;
|
||
SetOdsr = TRUE;
|
||
SetOcts = TRUE;
|
||
SetDtrControl = TRUE;
|
||
SetRtsControl = TRUE;
|
||
Xon = FALSE;
|
||
Odsr = FALSE;
|
||
Octs = FALSE;
|
||
DtrControl = DTR_CONTROL_ENABLE;
|
||
RtsControl = RTS_CONTROL_ENABLE;
|
||
}
|
||
|
||
Eoi:
|
||
if ( *C.CharIndex != '\0' ) {
|
||
|
||
//
|
||
// Error
|
||
//
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// New Form
|
||
//
|
||
|
||
while ( *C.CharIndex != '\0' ) {
|
||
|
||
if ( Match(&C, "BAUD=#" ) ) {
|
||
//
|
||
// BAUD=
|
||
//
|
||
if ( !ConvertBaudRate(GetNumber(&C), &Baud ) ) {
|
||
return FALSE;
|
||
}
|
||
SetBaud = TRUE;
|
||
Advance(&C);
|
||
|
||
} else if ( Match(&C, "PARITY=@" ) ) {
|
||
//
|
||
// PARITY=
|
||
//
|
||
if ( !ConvertParity( *C.MatchBegin, &Parity ) ) {
|
||
return FALSE;
|
||
}
|
||
SetParity = TRUE;
|
||
Advance(&C);
|
||
|
||
} else if ( Match(&C, "DATA=#" ) ) {
|
||
//
|
||
// DATA=
|
||
//
|
||
if ( !ConvertDataBits(GetNumber(&C), &DataBits ) ) {
|
||
return FALSE;
|
||
}
|
||
SetDataBits = TRUE;
|
||
Advance(&C);
|
||
|
||
} else if ( Match(&C, "STOP=1.5" ) ) {
|
||
//
|
||
// STOP=1.5
|
||
//
|
||
StopBits = ONE5STOPBITS;
|
||
SetStopBits = TRUE;
|
||
Advance(&C);
|
||
|
||
} else if ( Match(&C, "STOP=#" ) ) {
|
||
//
|
||
// STOP=
|
||
//
|
||
if ( !ConvertStopBits(GetNumber(&C), &StopBits ) ) {
|
||
return FALSE;
|
||
}
|
||
SetStopBits = TRUE;
|
||
Advance(&C);
|
||
|
||
} else if ( Match(&C, "TO=ON" ) ) {
|
||
//
|
||
// TO=ON
|
||
//
|
||
SetTimeOut = TRUE;
|
||
TimeOut = TRUE;
|
||
Advance(&C);
|
||
|
||
} else if ( Match(&C, "TO=OFF" ) ) {
|
||
//
|
||
// TO=ON
|
||
//
|
||
SetTimeOut = TRUE;
|
||
TimeOut = FALSE;
|
||
Advance(&C);
|
||
|
||
} else if ( Match(&C, "XON=ON" ) ) {
|
||
//
|
||
// XON=ON
|
||
//
|
||
SetXon = TRUE;
|
||
Xon = TRUE;
|
||
Advance(&C);
|
||
|
||
} else if ( Match(&C, "XON=OFF" ) ) {
|
||
//
|
||
// XON=OFF
|
||
//
|
||
SetXon = TRUE;
|
||
Xon = FALSE;
|
||
Advance(&C);
|
||
|
||
} else if ( Match(&C, "ODSR=ON" ) ) {
|
||
//
|
||
// ODSR=ON
|
||
//
|
||
SetOdsr = TRUE;
|
||
Odsr = TRUE;
|
||
Advance(&C);
|
||
|
||
} else if ( Match(&C, "ODSR=OFF" ) ) {
|
||
//
|
||
// ODSR=OFF
|
||
//
|
||
SetOdsr = TRUE;
|
||
Odsr = FALSE;
|
||
Advance(&C);
|
||
|
||
} else if ( Match(&C, "IDSR=ON" ) ) {
|
||
//
|
||
// IDSR=ON
|
||
//
|
||
SetIdsr = TRUE;
|
||
Idsr = TRUE;
|
||
Advance(&C);
|
||
|
||
} else if ( Match(&C, "IDSR=OFF" ) ) {
|
||
//
|
||
// IDSR=OFF
|
||
//
|
||
SetIdsr = TRUE;
|
||
Idsr = FALSE;
|
||
Advance(&C);
|
||
|
||
} else if ( Match(&C, "OCTS=ON" ) ) {
|
||
//
|
||
// OCS=ON
|
||
//
|
||
SetOcts = TRUE;
|
||
Octs = TRUE;
|
||
Advance(&C);
|
||
|
||
} else if ( Match(&C, "OCTS=OFF" ) ) {
|
||
//
|
||
// OCS=OFF
|
||
//
|
||
SetOcts = TRUE;
|
||
Octs = FALSE;
|
||
Advance(&C);
|
||
|
||
} else if ( Match(&C, "DTR=*" ) ) {
|
||
//
|
||
// DTR=
|
||
//
|
||
if ( !ConvertDtrControl(C.MatchBegin, C.MatchEnd, &DtrControl ) ) {
|
||
return FALSE;
|
||
}
|
||
SetDtrControl = TRUE;
|
||
Advance(&C);
|
||
|
||
} else if ( Match(&C, "RTS=*" ) ) {
|
||
//
|
||
// RTS=
|
||
//
|
||
if ( !ConvertRtsControl(C.MatchBegin, C.MatchEnd, &RtsControl ) ) {
|
||
return FALSE;
|
||
}
|
||
SetRtsControl = TRUE;
|
||
Advance(&C);
|
||
|
||
} else {
|
||
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
if ( SetBaud ) {
|
||
Dcb->BaudRate = Baud;
|
||
}
|
||
|
||
if ( SetDataBits ) {
|
||
Dcb->ByteSize = DataBits;
|
||
}
|
||
|
||
if ( SetStopBits ) {
|
||
Dcb->StopBits = StopBits;
|
||
} else if ( SetBaud && (Baud == 110) ) {
|
||
Dcb->StopBits = TWOSTOPBITS;
|
||
} else {
|
||
Dcb->StopBits = ONESTOPBIT;
|
||
}
|
||
|
||
if ( SetParity ) {
|
||
Dcb->Parity = Parity;
|
||
}
|
||
|
||
if ( SetXon ) {
|
||
if ( Xon ) {
|
||
Dcb->fInX = TRUE;
|
||
Dcb->fOutX = TRUE;
|
||
} else {
|
||
Dcb->fInX = FALSE;
|
||
Dcb->fOutX = FALSE;
|
||
}
|
||
}
|
||
|
||
if ( SetOcts ) {
|
||
|
||
if ( Octs ) {
|
||
Dcb->fOutxCtsFlow = TRUE;
|
||
} else {
|
||
Dcb->fOutxCtsFlow = FALSE;
|
||
}
|
||
}
|
||
|
||
|
||
if ( SetOdsr ) {
|
||
if ( Odsr ) {
|
||
Dcb->fOutxDsrFlow = TRUE;
|
||
} else {
|
||
Dcb->fOutxDsrFlow = FALSE;
|
||
}
|
||
}
|
||
|
||
if ( SetIdsr ) {
|
||
if ( Idsr ) {
|
||
Dcb->fDsrSensitivity = TRUE;
|
||
} else {
|
||
Dcb->fDsrSensitivity = FALSE;
|
||
}
|
||
}
|
||
|
||
if ( SetDtrControl ) {
|
||
Dcb->fDtrControl = DtrControl;
|
||
}
|
||
|
||
if ( SetRtsControl ) {
|
||
Dcb->fRtsControl = RtsControl;
|
||
}
|
||
|
||
if ( SetTimeOut ) {
|
||
if (TimeOut) {
|
||
To->ReadIntervalTimeout = 0;
|
||
To->ReadTotalTimeoutMultiplier = 0;
|
||
To->ReadTotalTimeoutConstant = 0;
|
||
To->WriteTotalTimeoutMultiplier = 0;
|
||
To->WriteTotalTimeoutConstant = 60000;
|
||
} else {
|
||
To->ReadIntervalTimeout = 0;
|
||
To->ReadTotalTimeoutMultiplier = 0;
|
||
To->ReadTotalTimeoutConstant = 0;
|
||
To->WriteTotalTimeoutMultiplier = 0;
|
||
To->WriteTotalTimeoutConstant = 0;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static
|
||
BOOL
|
||
Match(
|
||
PPARSE_CONTEXT C,
|
||
PSTR Pattern
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function matches a pattern against whatever
|
||
is in the command line at the current position.
|
||
|
||
Note that this does not advance our current position
|
||
within the command line.
|
||
|
||
If the pattern has a magic character, then the
|
||
variables C->MatchBegin and C->MatchEnd delimit the
|
||
substring of the command line that matched that
|
||
magic character.
|
||
|
||
Arguments:
|
||
|
||
C - The parse context.
|
||
Pattern - Supplies pointer to the pattern to match
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - TRUE if the pattern matched, FALSE otherwise
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PSTR CmdIndex; // Index within command line
|
||
PSTR PatternIndex; // Index within pattern
|
||
CHAR PatternChar; // Character in pattern
|
||
CHAR CmdChar; // Character in command line;
|
||
|
||
CmdIndex = C->CharIndex;
|
||
PatternIndex = Pattern;
|
||
|
||
while ( (PatternChar = *PatternIndex) != '\0' ) {
|
||
|
||
switch ( PatternChar ) {
|
||
|
||
case '#':
|
||
|
||
//
|
||
// Match a number
|
||
//
|
||
C->MatchBegin = CmdIndex;
|
||
C->MatchEnd = C->MatchBegin;
|
||
|
||
//
|
||
// Get all consecutive digits
|
||
//
|
||
while ( ((CmdChar = *C->MatchEnd) != '\0') &&
|
||
isdigit( (char)CmdChar ) ) {
|
||
C->MatchEnd++;
|
||
}
|
||
C->MatchEnd--;
|
||
|
||
if ( C->MatchBegin > C->MatchEnd ) {
|
||
//
|
||
// No number
|
||
//
|
||
return FALSE;
|
||
}
|
||
|
||
CmdIndex = C->MatchEnd + 1;
|
||
PatternIndex++;
|
||
|
||
break;
|
||
|
||
|
||
case '@':
|
||
|
||
//
|
||
// Match one character
|
||
//
|
||
if ( *CmdIndex == '\0' ) {
|
||
return FALSE;
|
||
}
|
||
|
||
C->MatchBegin = C->MatchEnd = CmdIndex;
|
||
CmdIndex++;
|
||
PatternIndex++;
|
||
|
||
break;
|
||
|
||
|
||
case '*':
|
||
|
||
//
|
||
// Match everything up to next blank (or end of input)
|
||
//
|
||
C->MatchBegin = CmdIndex;
|
||
C->MatchEnd = C->MatchBegin;
|
||
|
||
while ( ( (CmdChar = *C->MatchEnd ) != '\0' ) &&
|
||
( CmdChar != ' ' ) ) {
|
||
|
||
C->MatchEnd++;
|
||
}
|
||
C->MatchEnd--;
|
||
|
||
CmdIndex = C->MatchEnd+1;
|
||
PatternIndex++;
|
||
|
||
break;
|
||
|
||
case '[':
|
||
|
||
//
|
||
// Optional sequence
|
||
//
|
||
PatternIndex++;
|
||
|
||
PatternChar = *PatternIndex;
|
||
CmdChar = *CmdIndex;
|
||
|
||
//
|
||
// If the first charcter in the input does not match the
|
||
// first character in the optional sequence, we just
|
||
// skip the optional sequence.
|
||
//
|
||
if ( ( CmdChar == '\0' ) ||
|
||
( CmdChar == ' ') ||
|
||
( toupper(CmdChar) != toupper(PatternChar) ) ) {
|
||
|
||
while ( PatternChar != ']' ) {
|
||
PatternIndex++;
|
||
PatternChar = *PatternIndex;
|
||
}
|
||
PatternIndex++;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Since the first character in the sequence matched, now
|
||
// everything must match.
|
||
//
|
||
while ( PatternChar != ']' ) {
|
||
|
||
if ( toupper(PatternChar) != toupper(CmdChar) ) {
|
||
return FALSE;
|
||
}
|
||
CmdIndex++;
|
||
PatternIndex++;
|
||
CmdChar = *CmdIndex;
|
||
PatternChar = *PatternIndex;
|
||
}
|
||
|
||
PatternIndex++;
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
//
|
||
// Both characters must match
|
||
//
|
||
CmdChar = *CmdIndex;
|
||
|
||
if ( ( CmdChar == '\0' ) ||
|
||
( toupper(CmdChar) != toupper(PatternChar) ) ) {
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
CmdIndex++;
|
||
PatternIndex++;
|
||
|
||
break;
|
||
|
||
}
|
||
}
|
||
|
||
C->AdvanceIndex = CmdIndex;
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
static
|
||
VOID
|
||
Advance(
|
||
PPARSE_CONTEXT C
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Advances our pointers to the beginning of the next lexeme
|
||
|
||
Arguments:
|
||
|
||
C - The parse context.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
C->CharIndex = C->AdvanceIndex;
|
||
|
||
//
|
||
// Skip blank space
|
||
//
|
||
if ( *C->CharIndex == ' ' ) {
|
||
|
||
while ( *C->CharIndex == ' ' ) {
|
||
|
||
C->CharIndex++;
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
static
|
||
DWORD
|
||
GetNumber(
|
||
PPARSE_CONTEXT C
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Converts the substring delimited by C->MatchBegin and C->MatchEnd into
|
||
a number.
|
||
|
||
Arguments:
|
||
|
||
C - The parse context
|
||
|
||
Return Value:
|
||
|
||
ULONG - The matched string converted to a number
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD Number;
|
||
CHAR c;
|
||
PSTR p = C->MatchEnd+1;
|
||
|
||
c = *p;
|
||
// *p = '\0';
|
||
//intf( "Making number: %s\n", C->MatchBegin );
|
||
Number = atol( C->MatchBegin );
|
||
// *p = c;
|
||
|
||
return Number;
|
||
|
||
}
|
||
|
||
static
|
||
BOOL
|
||
ConvertBaudRate (
|
||
DWORD BaudIn,
|
||
PDWORD BaudRate
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Validates a baud rate given as an argument to the program, and converts
|
||
it to something that the COMM_DEVICE understands.
|
||
|
||
Arguments:
|
||
|
||
BaudIn - Supplies the baud rate given by the user
|
||
BaudRate - if returning TRUE then the baud rate to use.
|
||
|
||
Return Value:
|
||
|
||
If a valid baud rate then returns TRUE, otherwise FALSE.
|
||
|
||
--*/
|
||
|
||
{
|
||
switch ( BaudIn ) {
|
||
|
||
case 11:
|
||
case 110:
|
||
*BaudRate = 110;
|
||
break;
|
||
|
||
case 15:
|
||
case 150:
|
||
*BaudRate = 150;
|
||
break;
|
||
|
||
case 30:
|
||
case 300:
|
||
*BaudRate = 300;
|
||
break;
|
||
|
||
case 60:
|
||
case 600:
|
||
*BaudRate = 600;
|
||
break;
|
||
|
||
case 12:
|
||
case 1200:
|
||
*BaudRate = 1200;
|
||
break;
|
||
|
||
case 24:
|
||
case 2400:
|
||
*BaudRate = 2400;
|
||
break;
|
||
|
||
case 48:
|
||
case 4800:
|
||
*BaudRate = 4800;
|
||
break;
|
||
|
||
case 96:
|
||
case 9600:
|
||
*BaudRate = 9600;
|
||
break;
|
||
|
||
case 19:
|
||
case 19200:
|
||
*BaudRate = 19200;
|
||
break;
|
||
|
||
default:
|
||
|
||
*BaudRate = BaudIn;
|
||
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static
|
||
BOOL
|
||
ConvertDataBits (
|
||
DWORD DataBitsIn,
|
||
PBYTE DataBitsOut
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Validates the number of data bits given as an argument to the program,
|
||
and converts it to something that the COMM_DEVICE understands.
|
||
|
||
Arguments:
|
||
|
||
DataBitsIn - Supplies the number given by the user
|
||
DataBitsOut - if returning TRUE, then the number of data bits.
|
||
|
||
Return Value:
|
||
|
||
If a valid data bits then TRUE, otherwise FALSE.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
if ( ( DataBitsIn != 5 ) &&
|
||
( DataBitsIn != 6 ) &&
|
||
( DataBitsIn != 7 ) &&
|
||
( DataBitsIn != 8 ) ) {
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
*DataBitsOut = (BYTE)DataBitsIn;
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
static
|
||
BOOL
|
||
ConvertStopBits (
|
||
DWORD StopBitsIn,
|
||
PBYTE StopBits
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Validates a number of stop bits given as an argument to the program,
|
||
and converts it to something that the COMM_DEVICE understands.
|
||
|
||
Arguments:
|
||
|
||
StopBitsIn - Supplies the number given by the user
|
||
StopBits - If returning true then a valid stop bits setting.
|
||
|
||
Return Value:
|
||
|
||
If a valid stop bits setting then TRUE, otherwise false.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
switch ( StopBitsIn ) {
|
||
|
||
case 1:
|
||
*StopBits = ONESTOPBIT;
|
||
break;
|
||
|
||
case 2:
|
||
*StopBits = TWOSTOPBITS;
|
||
break;
|
||
|
||
default:
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
static
|
||
BOOL
|
||
ConvertParity (
|
||
CHAR ParityIn,
|
||
PBYTE Parity
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Validates a parity given as an argument to the program, and converts
|
||
it to something that the COMM_DEVICE understands.
|
||
|
||
Arguments:
|
||
|
||
ParityIn - Supplies the baud rate given by the user
|
||
Parity - The valid parity if return true.
|
||
|
||
Return Value:
|
||
|
||
If a valid parity setting then TRUE otherwise false.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// Set the correct parity value depending on the character.
|
||
//
|
||
switch ( tolower(ParityIn) ) {
|
||
|
||
case 'n':
|
||
*Parity = NOPARITY;
|
||
break;
|
||
|
||
case 'o':
|
||
*Parity = ODDPARITY;
|
||
break;
|
||
|
||
case 'e':
|
||
*Parity = EVENPARITY;
|
||
break;
|
||
|
||
case 'm':
|
||
*Parity = MARKPARITY;
|
||
break;
|
||
|
||
case 's':
|
||
*Parity = SPACEPARITY;
|
||
break;
|
||
|
||
default:
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static
|
||
BOOL
|
||
ConvertDtrControl (
|
||
PSTR IdxBegin,
|
||
PSTR IdxEnd,
|
||
PBYTE DtrControl
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Validates a DTR control value given as an argument to the
|
||
program, and converts it to something that the COMM_DEVICE
|
||
understands.
|
||
|
||
Arguments:
|
||
|
||
IdxBegin - Supplies Index of first character
|
||
IdxEnd - Supplies Index of last character
|
||
DtrControl - If returning true, the valid dtr setting.
|
||
|
||
Return Value:
|
||
|
||
DTR_CONTROL - The DTR control value
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PSTR p;
|
||
|
||
p = IdxBegin;
|
||
if ( (tolower(*p) == 'o' ) &&
|
||
p++ &&
|
||
(tolower(*p) == 'n' ) &&
|
||
(IdxEnd == p)) {
|
||
|
||
|
||
*DtrControl = DTR_CONTROL_ENABLE;
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
p = IdxBegin;
|
||
if ( (tolower(*p) == 'o') &&
|
||
p++ &&
|
||
(tolower(*p) == 'f') &&
|
||
p++ &&
|
||
(tolower(*p) == 'f') &&
|
||
(IdxEnd == p ) ) {
|
||
|
||
*DtrControl = DTR_CONTROL_DISABLE;
|
||
return TRUE;
|
||
}
|
||
|
||
p = IdxBegin;
|
||
if ( (tolower(*p) == 'h') &&
|
||
p++ &&
|
||
(tolower(*p++) == 's') &&
|
||
(IdxEnd == p ) ) {
|
||
|
||
*DtrControl = DTR_CONTROL_HANDSHAKE;
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
static
|
||
BOOL
|
||
ConvertRtsControl (
|
||
PSTR IdxBegin,
|
||
PSTR IdxEnd,
|
||
PBYTE RtsControl
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Validates a RTS control value given as an argument to the
|
||
program, and converts it to something that the COMM_DEVICE
|
||
understands.
|
||
|
||
Arguments:
|
||
|
||
IdxBegin - Supplies Index of first character
|
||
IdxEnd - Supplies Index of last character
|
||
RtsControl - If returning true, the valid rts setting.
|
||
|
||
Return Value:
|
||
|
||
RTS_CONTROL - The RTS control value
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PSTR p;
|
||
p = IdxBegin;
|
||
if ( (tolower(*p) == 'o' ) &&
|
||
p++ &&
|
||
(tolower(*p) == 'n' ) &&
|
||
(IdxEnd == p)) {
|
||
|
||
|
||
*RtsControl = RTS_CONTROL_ENABLE;
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
p = IdxBegin;
|
||
if ( (tolower(*p) == 'o') &&
|
||
p++ &&
|
||
(tolower(*p) == 'f') &&
|
||
p++ &&
|
||
(tolower(*p) == 'f') &&
|
||
(IdxEnd == p ) ) {
|
||
|
||
*RtsControl = RTS_CONTROL_DISABLE;
|
||
return TRUE;
|
||
}
|
||
|
||
p = IdxBegin;
|
||
if ( (tolower(*p) == 'h') &&
|
||
p++ &&
|
||
(tolower(*p++) == 's') &&
|
||
(IdxEnd == p ) ) {
|
||
|
||
*RtsControl = RTS_CONTROL_HANDSHAKE;
|
||
return TRUE;
|
||
}
|
||
|
||
p = IdxBegin;
|
||
if ( (tolower(*p) == 't') &&
|
||
p++ &&
|
||
(tolower(*p++) == 'g') &&
|
||
(IdxEnd == p ) ) {
|
||
|
||
*RtsControl = RTS_CONTROL_TOGGLE;
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
static
|
||
NTSTATUS
|
||
DeviceNameCompare(
|
||
IN PWSTR ValueName,
|
||
IN ULONG ValueType,
|
||
IN PVOID ValueData,
|
||
IN ULONG ValueLength,
|
||
IN PVOID Context,
|
||
IN PVOID EntryContext
|
||
)
|
||
|
||
{
|
||
|
||
PPARSE_CONTEXT C = EntryContext;
|
||
UNICODE_STRING uniName;
|
||
ANSI_STRING ansiName;
|
||
|
||
RtlInitUnicodeString(
|
||
&uniName,
|
||
ValueData
|
||
);
|
||
|
||
if (!NT_SUCCESS(RtlUnicodeStringToAnsiString(
|
||
&ansiName,
|
||
&uniName,
|
||
TRUE
|
||
))) {
|
||
|
||
//
|
||
// Oh well, couldn't form the name. Just get out.
|
||
//
|
||
return STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
//
|
||
// See if we got a name match.
|
||
//
|
||
|
||
if (Match(C,ansiName.Buffer)) {
|
||
|
||
//
|
||
// Ok, got a name match, advance past it.
|
||
//
|
||
|
||
Advance(C);
|
||
|
||
//
|
||
// See if they've got the optional : following the
|
||
// device name.
|
||
//
|
||
|
||
if (Match(C,":")) {
|
||
|
||
//
|
||
// Go past it.
|
||
//
|
||
|
||
Advance(C);
|
||
|
||
}
|
||
|
||
}
|
||
RtlFreeAnsiString(&ansiName);
|
||
return STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
static
|
||
VOID
|
||
IgnoreDeviceName(
|
||
IN PPARSE_CONTEXT C
|
||
)
|
||
|
||
{
|
||
|
||
RTL_QUERY_REGISTRY_TABLE qTable[2] = {0};
|
||
|
||
//
|
||
// Build the query table.
|
||
//
|
||
|
||
qTable[0].QueryRoutine = DeviceNameCompare;
|
||
qTable[0].EntryContext = C;
|
||
|
||
RtlQueryRegistryValues(
|
||
RTL_REGISTRY_DEVICEMAP,
|
||
L"SERIALCOMM",
|
||
&qTable[0],
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
}
|