You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
675 lines
14 KiB
675 lines
14 KiB
/*++
|
|
|
|
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;
|
|
|
|
}
|