676 lines
13 KiB
C++
676 lines
13 KiB
C++
/*++
|
||
|
||
Copyright (c) 1990-2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
Lpt
|
||
|
||
Abstract:
|
||
|
||
Takes care of request involving an LPT device
|
||
|
||
Author:
|
||
|
||
Ramon Juan San Andres (ramonsa) 26-Jun-1991
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
#define _NTAPI_ULIB_
|
||
|
||
#include "mode.hxx"
|
||
#include "lpt.hxx"
|
||
#include "file.hxx"
|
||
#include "path.hxx"
|
||
#include "stream.hxx"
|
||
#include "redir.hxx"
|
||
#include "registry.hxx"
|
||
#include "regvalue.hxx"
|
||
#include "array.hxx"
|
||
#include "arrayit.hxx"
|
||
|
||
//
|
||
// When an LPT port is set, mode only sends it an EPSON/IBM sequence.
|
||
// The following macros define the EPSON sequences used.
|
||
//
|
||
#define CODE_ESCAPE 0x27
|
||
#define CODE_COLS_80 0x18
|
||
#define CODE_COLS_132 0x15
|
||
#define CODE_LINES_6 '2'
|
||
#define CODE_LINES_8 '0'
|
||
|
||
#undef LAST_COM
|
||
#define LAST_COM 4
|
||
|
||
|
||
//
|
||
// Local prototypes
|
||
//
|
||
BOOLEAN
|
||
LptStatus(
|
||
IN PCPATH DevicePath,
|
||
IN PREQUEST_HEADER Request
|
||
);
|
||
|
||
BOOLEAN
|
||
LptCodePage(
|
||
IN PCPATH DevicePath,
|
||
IN PREQUEST_HEADER Request
|
||
);
|
||
|
||
BOOLEAN
|
||
LptSetup(
|
||
IN PCPATH DevicePath,
|
||
IN PREQUEST_HEADER Request
|
||
);
|
||
|
||
BOOLEAN
|
||
LptRedirect(
|
||
IN PCPATH DevicePath,
|
||
IN PREQUEST_HEADER Request
|
||
);
|
||
|
||
BOOLEAN
|
||
LptEndRedir(
|
||
IN PCPATH DevicePath,
|
||
IN PREQUEST_HEADER Request
|
||
);
|
||
|
||
PPATH
|
||
GetRedirection(
|
||
IN PCPATH DevicePath,
|
||
OUT PREDIR_STATUS RedirStatus
|
||
);
|
||
|
||
|
||
|
||
BOOLEAN
|
||
IsAValidLptDevice (
|
||
IN DEVICE_TTYPE DeviceType,
|
||
IN ULONG DeviceNumber,
|
||
OUT PPATH *DevicePathPointer
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determines if a certain comm device exists and optionally
|
||
creates a path for it.
|
||
|
||
Arguments:
|
||
|
||
DeviceType - Supplies the type of device
|
||
DeviceNumber - Supplies the device number
|
||
DeviceName - Supplies a pointer to a pointer to the path for
|
||
the device.
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - TRUE if the device exists,
|
||
FALSE otherwise.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
DSTRING DeviceName;
|
||
DSTRING AlternateName;
|
||
DSTRING Number;
|
||
BOOLEAN Valid = FALSE;
|
||
REGISTRY Registry;
|
||
DSTRING ParentName;
|
||
DSTRING KeyName;
|
||
ARRAY ValueArray;
|
||
PARRAY_ITERATOR Iterator;
|
||
ULONG ErrorCode;
|
||
PCBYTE Data;
|
||
DSTRING PortName;
|
||
PREGISTRY_VALUE_ENTRY Value;
|
||
|
||
|
||
UNREFERENCED_PARAMETER( DeviceType );
|
||
|
||
|
||
if ( DeviceName.Initialize( (LPWSTR)L"LPT" )&&
|
||
Number.Initialize( DeviceNumber ) &&
|
||
DeviceName.Strcat( &Number ) &&
|
||
AlternateName.Initialize( (LPWSTR)L"\\DosDevices\\" ) &&
|
||
AlternateName.Strcat( &DeviceName ) &&
|
||
ParentName.Initialize( "" ) &&
|
||
KeyName.Initialize( LPT_KEY_NAME ) &&
|
||
ValueArray.Initialize() &&
|
||
Registry.Initialize()
|
||
) {
|
||
|
||
|
||
//
|
||
// Get the names of all the serial ports
|
||
//
|
||
if ( Registry.QueryValues(
|
||
PREDEFINED_KEY_LOCAL_MACHINE,
|
||
&ParentName,
|
||
&KeyName,
|
||
&ValueArray,
|
||
&ErrorCode
|
||
) ) {
|
||
|
||
//
|
||
// See if the given name matches any of the serial ports
|
||
//
|
||
if ( Iterator = (PARRAY_ITERATOR)ValueArray.QueryIterator() ) {
|
||
|
||
while ( Value = (PREGISTRY_VALUE_ENTRY)(Iterator->GetNext() ) ) {
|
||
|
||
if ( Value->GetData( &Data ) ) {
|
||
|
||
if ( PortName.Initialize( (PWSTR)Data ) ) {
|
||
|
||
if ( !DeviceName.Stricmp( &PortName ) ||
|
||
!AlternateName.Stricmp( &PortName ) ) {
|
||
|
||
Valid = TRUE;
|
||
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
DELETE( Iterator );
|
||
}
|
||
}
|
||
|
||
if ( DevicePathPointer ) {
|
||
|
||
if (!(*DevicePathPointer = NEW PATH)) {
|
||
DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
|
||
NULL,
|
||
(ULONG)EXIT_ERROR );
|
||
return FALSE; // help lint
|
||
}
|
||
(*DevicePathPointer)->Initialize( &DeviceName );
|
||
}
|
||
|
||
}
|
||
|
||
return Valid;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
BOOLEAN
|
||
LptHandler(
|
||
IN PREQUEST_HEADER Request
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Handles LPT requests
|
||
|
||
Arguments:
|
||
|
||
Request - Supplies pointer to request
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
PPATH DevicePath; // Name of Device
|
||
BOOLEAN Served = TRUE; // TRUE if request served OK.
|
||
REDIR_STATUS Status;
|
||
|
||
DebugPtrAssert( Request );
|
||
DebugAssert( Request->DeviceType == DEVICE_TYPE_LPT );
|
||
|
||
//
|
||
// Make sure that the device exists, and at the same time get its
|
||
// name ( For calling APIs ).
|
||
//
|
||
if ( Request->DeviceName ) {
|
||
|
||
if (!(DevicePath = NEW PATH)) {
|
||
DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
|
||
NULL,
|
||
(ULONG)EXIT_ERROR );
|
||
return FALSE; // help lint
|
||
}
|
||
|
||
DevicePath->Initialize( Request->DeviceName );
|
||
|
||
} else if ( (!IsAValidLptDevice( Request->DeviceType, Request->DeviceNumber, &DevicePath ) &&
|
||
Request->RequestType != REQUEST_TYPE_LPT_REDIRECT &&
|
||
!REDIR::IsRedirected( &Status, DevicePath )) ||
|
||
Request->DeviceNumber > LAST_LPT ) {
|
||
DisplayMessageAndExit( MODE_ERROR_INVALID_DEVICE_NAME,
|
||
DevicePath->GetPathString(),
|
||
(ULONG)EXIT_ERROR );
|
||
}
|
||
|
||
//
|
||
// So the device is valid. Now serve the request
|
||
//
|
||
switch( Request->RequestType ) {
|
||
|
||
|
||
case REQUEST_TYPE_STATUS:
|
||
|
||
//
|
||
// Display State of device
|
||
//
|
||
Served = LptStatus( DevicePath, Request );
|
||
break;
|
||
|
||
case REQUEST_TYPE_CODEPAGE_PREPARE:
|
||
case REQUEST_TYPE_CODEPAGE_SELECT:
|
||
case REQUEST_TYPE_CODEPAGE_REFRESH:
|
||
case REQUEST_TYPE_CODEPAGE_STATUS:
|
||
|
||
//
|
||
// Codepage request
|
||
//
|
||
Served = LptCodePage( DevicePath, Request );
|
||
break;
|
||
|
||
case REQUEST_TYPE_LPT_SETUP:
|
||
|
||
//
|
||
// Printer setup
|
||
//
|
||
Served = LptSetup( DevicePath, Request );
|
||
break;
|
||
|
||
case REQUEST_TYPE_LPT_REDIRECT:
|
||
|
||
//
|
||
// Redirect LPT to COM
|
||
//
|
||
Served = LptRedirect( DevicePath, Request );
|
||
break;
|
||
|
||
case REQUEST_TYPE_LPT_ENDREDIR:
|
||
|
||
//
|
||
// End redirection of LPT
|
||
//
|
||
Served = LptEndRedir( DevicePath, Request );
|
||
break;
|
||
|
||
default:
|
||
|
||
DisplayMessageAndExit( MODE_ERROR_INVALID_PARAMETER,
|
||
NULL,
|
||
(ULONG)EXIT_ERROR );
|
||
|
||
}
|
||
|
||
DELETE( DevicePath );
|
||
|
||
return Served;
|
||
|
||
}
|
||
|
||
BOOLEAN
|
||
LptStatus(
|
||
IN PCPATH DevicePath,
|
||
IN PREQUEST_HEADER Request
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Displays status if an LPT device
|
||
|
||
Arguments:
|
||
|
||
DevicePath - Supplies pointer to path of device
|
||
Request - Supplies pointer to request
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - TRUE if status displayed successfully,
|
||
FALSE otherwise
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
UNREFERENCED_PARAMETER( DevicePath );
|
||
UNREFERENCED_PARAMETER( Request );
|
||
|
||
PPATH RedirPath = NULL;
|
||
REDIR_STATUS RedirStatus;
|
||
|
||
RedirPath = GetRedirection( DevicePath, &RedirStatus );
|
||
|
||
if ( !RedirPath && (RedirStatus != REDIR_STATUS_NONEXISTENT) ) {
|
||
//
|
||
// We cannot find out the status of the redirection.
|
||
// This is almost certainly due to lack of privileges.
|
||
// We won't display the LPT status
|
||
//
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// Write the Header
|
||
//
|
||
WriteStatusHeader( DevicePath );
|
||
|
||
|
||
if ( !RedirPath ) {
|
||
|
||
DisplayMessage( MODE_MESSAGE_STATUS_NOT_REROUTED, NULL );
|
||
|
||
} else {
|
||
|
||
DisplayMessage( MODE_MESSAGE_STATUS_REROUTED, RedirPath->GetPathString() );
|
||
|
||
DELETE( RedirPath );
|
||
}
|
||
|
||
Get_Standard_Output_Stream()->WriteChar( '\r' );
|
||
Get_Standard_Output_Stream()->WriteChar( '\n' );
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOLEAN
|
||
LptCodePage(
|
||
IN PCPATH DevicePath,
|
||
IN PREQUEST_HEADER Request
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Handles Codepage requests for LPT device
|
||
|
||
Arguments:
|
||
|
||
DevicePath - Supplies pointer to path of device
|
||
Request - Supplies pointer to request
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - TRUE if request handled successfully,
|
||
FALSE otherwise
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
UNREFERENCED_PARAMETER( DevicePath );
|
||
UNREFERENCED_PARAMETER( Request );
|
||
|
||
DisplayMessage( MODE_ERROR_CODEPAGE_OPERATION_NOT_SUPPORTED, NULL );
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOLEAN
|
||
LptSetup(
|
||
IN PCPATH DevicePath,
|
||
IN PREQUEST_HEADER Request
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Sets LPT state
|
||
|
||
Arguments:
|
||
|
||
DevicePath - Supplies pointer to path of device
|
||
Request - Supplies pointer to request
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - TRUE if state set successfully,
|
||
FALSE otherwise
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PREQUEST_DATA_LPT_SETUP Data;
|
||
PFSN_FILE Lpt;
|
||
PFILE_STREAM LptStream;
|
||
|
||
|
||
|
||
Data = (PREQUEST_DATA_LPT_SETUP)&(((PLPT_REQUEST)Request)->Data.Setup);
|
||
|
||
if ( ( Data->SetCol && (Data->Col != 132) && ( Data->Col != 80 ) ) ||
|
||
( Data->SetLines && (Data->Lines != 6) && (Data->Lines != 8) ) ) {
|
||
|
||
//
|
||
// Invalid number of lines or columns
|
||
//
|
||
DisplayMessageAndExit( MODE_ERROR_LPT_CANNOT_SET, NULL, (ULONG)EXIT_ERROR );
|
||
|
||
}
|
||
|
||
|
||
Lpt = SYSTEM::QueryFile( DevicePath );
|
||
DebugPtrAssert( Lpt );
|
||
|
||
if ( Lpt ) {
|
||
LptStream = Lpt->QueryStream( WRITE_ACCESS );
|
||
DebugPtrAssert( LptStream );
|
||
}
|
||
|
||
if ( !Lpt || !LptStream ) {
|
||
DisplayMessageAndExit( MODE_ERROR_NO_MEMORY, NULL, (ULONG)EXIT_ERROR );
|
||
}
|
||
|
||
if ( Data->SetCol ) {
|
||
|
||
//
|
||
// Set number of columns. The sequence consists of one byte.
|
||
//
|
||
LptStream->WriteByte( (Data->Col == 80) ? CODE_COLS_80 : CODE_COLS_132 );
|
||
}
|
||
|
||
if ( Data->SetLines ) {
|
||
|
||
//
|
||
// Set line spacing. The sequence consists of one escape byte
|
||
// followed by one CODE_LINES_6 or CODE_LINES 8 byte.
|
||
//
|
||
LptStream->WriteByte( CODE_ESCAPE );
|
||
LptStream->WriteByte( (Data->Lines == 6) ? CODE_LINES_6 : CODE_LINES_8 );
|
||
|
||
}
|
||
|
||
DELETE( LptStream );
|
||
DELETE( Lpt );
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOLEAN
|
||
LptRedirect(
|
||
IN PCPATH DevicePath,
|
||
IN PREQUEST_HEADER Request
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Redirects LPT to a COMM port.
|
||
|
||
Arguments:
|
||
|
||
DevicePath - Supplies pointer to path of device
|
||
Request - Supplies pointer to request
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - TRUE if LPT redirected,
|
||
FALSE otherwise
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PREQUEST_DATA_LPT_REDIRECT Data;
|
||
PPATH RedirPath;
|
||
|
||
Data = (PREQUEST_DATA_LPT_REDIRECT)&(((PLPT_REQUEST)Request)->Data.Redirect);
|
||
|
||
//
|
||
// Verify that the serial device specified is valid
|
||
//
|
||
if ( !IsAValidDevice( Data->DeviceType, Data->DeviceNumber, &RedirPath )) {
|
||
|
||
DisplayMessageAndExit( MODE_ERROR_INVALID_DEVICE_NAME,
|
||
RedirPath->GetPathString(),
|
||
(ULONG)EXIT_ERROR );
|
||
|
||
}
|
||
|
||
if ( !REDIR::Redirect( DevicePath, RedirPath ) ) {
|
||
|
||
DisplayMessageAndExit( MODE_ERROR_LPT_CANNOT_REROUTE, RedirPath->GetPathString(), (ULONG)EXIT_ERROR );
|
||
|
||
}
|
||
|
||
//
|
||
// Display the status as confirmation
|
||
//
|
||
LptStatus( DevicePath, Request );
|
||
|
||
DELETE( RedirPath );
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
LptEndRedir (
|
||
IN PCPATH DevicePath,
|
||
IN PREQUEST_HEADER Request
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Ends the redirection of an LPT port
|
||
|
||
Arguments:
|
||
|
||
DevicePath - Supplies pointer to path of device
|
||
Request - Supplies pointer to request
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - TRUE
|
||
|
||
Notes:
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
REDIR_STATUS Status;
|
||
|
||
//
|
||
// If the LPT is being redirected, end the redirection
|
||
//
|
||
if ( REDIR::IsRedirected( &Status, DevicePath ) ) {
|
||
|
||
if ( !REDIR::EndRedirection( DevicePath )) {
|
||
|
||
DisplayMessageAndExit( MODE_ERROR_LPT_CANNOT_ENDREROUTE, NULL, (ULONG)EXIT_ERROR );
|
||
}
|
||
}
|
||
|
||
//
|
||
// Display status
|
||
//
|
||
LptStatus( DevicePath, Request );
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
PPATH
|
||
GetRedirection(
|
||
IN PCPATH DevicePath,
|
||
OUT PREDIR_STATUS RedirStatus
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determines to what device is the LPT redirected to
|
||
|
||
Arguments:
|
||
|
||
DevicePath - Supplies pointer to path of device
|
||
|
||
RedirStatus - Supplies pointer to redirection status
|
||
|
||
Return Value:
|
||
|
||
PPATH - Pointer to the redirected device
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
ULONG DeviceNumber = 1;
|
||
PPATH DestPath = NULL;
|
||
BOOLEAN ValidDevice = TRUE;
|
||
|
||
if ( REDIR::IsRedirected( RedirStatus, DevicePath ) ) {
|
||
|
||
for ( DeviceNumber = 1; DeviceNumber <= LAST_COM; DeviceNumber++ ) {
|
||
|
||
IsAValidDevice( DEVICE_TYPE_COM, DeviceNumber, &DestPath );
|
||
|
||
if ( REDIR::IsRedirected( RedirStatus, DevicePath, DestPath )) {
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
DELETE( DestPath );
|
||
DestPath = NULL;
|
||
|
||
}
|
||
}
|
||
|
||
return DestPath;
|
||
|
||
}
|