/*++ 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; }