542 lines
13 KiB
C
542 lines
13 KiB
C
/*++
|
||
|
||
Copyright (C) Microsoft Corporation, 1993 - 1999
|
||
|
||
Module Name:
|
||
|
||
parclass.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the code for the parallel class driver.
|
||
|
||
Author:
|
||
|
||
Anthony V. Ercolano 1-Aug-1992
|
||
Norbert P. Kusters 22-Oct-1993
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History :
|
||
|
||
Timothy T. Wells (v-timtw) 13-Mar-97
|
||
|
||
Pretty serious overhaul to this and other files on this project to support additional modes
|
||
(EPP, ECP and others), as well as some new filter driver interfaces.
|
||
|
||
--*/
|
||
|
||
#include "pch.h"
|
||
|
||
#include <initguid.h>
|
||
#include <ntddpar.h>
|
||
#include <wdmguid.h>
|
||
|
||
#if DBG
|
||
|
||
//
|
||
// Initialize both debug variables even though both will be set
|
||
// based on registry values in function ParInitDebugLevel(...)
|
||
// during DriverEntry(...)
|
||
//
|
||
|
||
// How verbose do we want parallel.sys to be with DbgPrint messages?
|
||
// ULONG ParDebugLevel = PARDUMP_VERBOSE_MAX;
|
||
ULONG ParDebugLevel = PARDUMP_VERBOSE_MAX;
|
||
|
||
// What conditions do we want to break on?
|
||
// ULONG ParBreakOn = PAR_BREAK_ON_NOTHING;
|
||
ULONG ParBreakOn = PAR_BREAK_ON_NOTHING;
|
||
|
||
ULONG ParUseAsserts = 0;
|
||
|
||
#endif // DBG
|
||
|
||
|
||
// enable scans for Legacy Zip?
|
||
ULONG ParEnableLegacyZip = 0;
|
||
PCHAR ParLegacyZipPseudoId = PAR_LGZIP_PSEUDO_1284_ID_STRING;
|
||
|
||
ULONG DumpDevExtTable = 0; // want to default to zero in non-debugging environment
|
||
|
||
ULONG SppNoRaiseIrql = 0;
|
||
ULONG DefaultModes = 0;
|
||
|
||
ULONG gSppLoopDelay = 0;
|
||
ULONG gSppLoopBytesPerDelay = 0;
|
||
|
||
//
|
||
// Temporary Development Globals - used as switches in debug code
|
||
//
|
||
ULONG tdev1 = 1;
|
||
ULONG tdev2 = 0;
|
||
|
||
extern const PHYSICAL_ADDRESS PhysicalZero = {0};
|
||
|
||
//
|
||
// Definition of OpenCloseMutex. RMT DO WE NEED THIS ???
|
||
//
|
||
extern ULONG OpenCloseReferenceCount = 1;
|
||
extern PFAST_MUTEX OpenCloseMutex = NULL;
|
||
|
||
//
|
||
// Declarations only (Definition in Ieee1284.c)
|
||
//
|
||
extern FORWARD_PTCL afpForward[];
|
||
extern REVERSE_PTCL arpReverse[];
|
||
|
||
|
||
UCHAR
|
||
ParInitializeDevice(
|
||
IN PDEVICE_EXTENSION Extension
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is invoked to initialize the parallel port drive.
|
||
It performs the following actions:
|
||
|
||
o Send INIT to the driver and if the device is online.
|
||
|
||
Arguments:
|
||
|
||
Context - Really the device extension.
|
||
|
||
Return Value:
|
||
|
||
The last value that we got from the status register.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
KIRQL OldIrql;
|
||
UCHAR DeviceStatus = 0;
|
||
LARGE_INTEGER StartOfSpin = {0,0};
|
||
LARGE_INTEGER NextQuery = {0,0};
|
||
LARGE_INTEGER Difference = {0,0};
|
||
|
||
ParDump2(PARENTRY, ("Enter ParInitializeDevice(...)\n") );
|
||
|
||
//
|
||
// Tim Wells (WestTek, L.L.C.)
|
||
//
|
||
// - Removed the deferred initialization code from DriverEntry, device creation
|
||
// code. This code will be better utilized in the Create/Open logic or from
|
||
// the calling application.
|
||
//
|
||
// - Changed this code to always reset when asked, and to return after a fixed
|
||
// interval reqardless of the response. Additional responses can be provided by
|
||
// read and write code.
|
||
//
|
||
|
||
//
|
||
// Clear the register.
|
||
//
|
||
|
||
if (GetControl(Extension->Controller) & PAR_CONTROL_NOT_INIT) {
|
||
|
||
//
|
||
// We should stall for at least 60 microseconds after the init.
|
||
//
|
||
|
||
KeRaiseIrql( DISPATCH_LEVEL, &OldIrql );
|
||
|
||
StoreControl( Extension->Controller, (UCHAR)(PAR_CONTROL_WR_CONTROL | PAR_CONTROL_SLIN) );
|
||
|
||
KeStallExecutionProcessor(60);
|
||
KeLowerIrql(OldIrql);
|
||
|
||
}
|
||
|
||
StoreControl( Extension->Controller,
|
||
(UCHAR)(PAR_CONTROL_WR_CONTROL | PAR_CONTROL_NOT_INIT | PAR_CONTROL_SLIN) );
|
||
|
||
//
|
||
// Spin waiting for the device to initialize.
|
||
//
|
||
|
||
KeQueryTickCount(&StartOfSpin);
|
||
|
||
ParDumpV( ("Starting init wait loop\n") );
|
||
|
||
do {
|
||
|
||
KeQueryTickCount(&NextQuery);
|
||
|
||
Difference.QuadPart = NextQuery.QuadPart - StartOfSpin.QuadPart;
|
||
|
||
ASSERT(KeQueryTimeIncrement() <= MAXLONG);
|
||
|
||
if (Difference.QuadPart*KeQueryTimeIncrement() >= Extension->AbsoluteOneSecond.QuadPart) {
|
||
|
||
//
|
||
// Give up on getting PAR_OK.
|
||
//
|
||
|
||
ParDump2(PARINITDEV, ("Did spin of one second - StartOfSpin: %x NextQuery: %x\n",
|
||
StartOfSpin.LowPart,NextQuery.LowPart) );
|
||
ParDump2(PARINITDEV, ("ParInitialize 1 seconds wait\n") );
|
||
|
||
break;
|
||
}
|
||
|
||
DeviceStatus = GetStatus(Extension->Controller);
|
||
|
||
} while (!PAR_OK(DeviceStatus));
|
||
|
||
return (DeviceStatus);
|
||
}
|
||
|
||
VOID
|
||
ParNotInitError(
|
||
IN PDEVICE_EXTENSION Extension,
|
||
IN UCHAR DeviceStatus
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Extension - Supplies the device extension.
|
||
|
||
deviceStatus - Last read status.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PIRP Irp = Extension->CurrentOpIrp;
|
||
|
||
if (PAR_OFF_LINE(DeviceStatus)) {
|
||
|
||
Irp->IoStatus.Status = STATUS_DEVICE_OFF_LINE;
|
||
ParDump(PARSTARTER | PARDUMP_VERBOSE_MAX,
|
||
("PARALLEL: "
|
||
"Init Error - off line - "
|
||
"STATUS/INFORMATON: %x/%x\n",
|
||
Irp->IoStatus.Status, Irp->IoStatus.Information) );
|
||
|
||
} else if (PAR_NO_CABLE(DeviceStatus)) {
|
||
|
||
Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
|
||
ParDump(PARSTARTER | PARDUMP_VERBOSE_MAX,
|
||
("PARALLEL: "
|
||
"Init Error - no cable - not connected - "
|
||
"STATUS/INFORMATON: %x/%x\n",
|
||
Irp->IoStatus.Status, Irp->IoStatus.Information) );
|
||
|
||
} else if (PAR_PAPER_EMPTY(DeviceStatus)) {
|
||
|
||
Irp->IoStatus.Status = STATUS_DEVICE_PAPER_EMPTY;
|
||
ParDump(PARSTARTER | PARDUMP_VERBOSE_MAX,
|
||
("PARALLEL: "
|
||
"Init Error - paper empty - "
|
||
"STATUS/INFORMATON: %x/%x\n",
|
||
Irp->IoStatus.Status, Irp->IoStatus.Information) );
|
||
|
||
} else if (PAR_POWERED_OFF(DeviceStatus)) {
|
||
|
||
Irp->IoStatus.Status = STATUS_DEVICE_POWERED_OFF;
|
||
ParDump(PARSTARTER | PARDUMP_VERBOSE_MAX,
|
||
("PARALLEL: "
|
||
"Init Error - power off - "
|
||
"STATUS/INFORMATON: %x/%x\n",
|
||
Irp->IoStatus.Status, Irp->IoStatus.Information) );
|
||
|
||
} else {
|
||
|
||
Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
|
||
ParDump(PARSTARTER | PARDUMP_VERBOSE_MAX,
|
||
("PARALLEL: "
|
||
"Init Error - not conn - "
|
||
"STATUS/INFORMATON: %x/%x\n",
|
||
Irp->IoStatus.Status, Irp->IoStatus.Information) );
|
||
}
|
||
|
||
}
|
||
|
||
VOID
|
||
ParCancelRequest(
|
||
PDEVICE_OBJECT DeviceObject,
|
||
PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to cancel any request in the parallel driver.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to the device object for this device
|
||
|
||
Irp - Pointer to the IRP to be canceled.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
ParDumpV( ("ParCancelRequest: DO= %x , Irp= %x Cancel=%d, CancelRoutine= %x\n",
|
||
DeviceObject, Irp, Irp->Cancel, Irp->CancelRoutine) );
|
||
|
||
//
|
||
// The only reason that this irp can be on the queue is
|
||
// if it's not the current irp. Pull it off the queue
|
||
// and complete it as canceled.
|
||
//
|
||
|
||
ASSERT(!IsListEmpty(&Irp->Tail.Overlay.ListEntry));
|
||
|
||
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
|
||
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
||
|
||
Irp->IoStatus.Status = STATUS_CANCELLED;
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
ParCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
ParQueryInformationFile(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to query the end of file information on
|
||
the opened parallel port. Any other file information request
|
||
is retured with an invalid parameter.
|
||
|
||
This routine always returns an end of file of 0.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Supplies the device object.
|
||
|
||
Irp - Supplies the I/O request packet.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Success.
|
||
STATUS_INVALID_PARAMETER - Invalid file information request.
|
||
STATUS_BUFFER_TOO_SMALL - Buffer too small.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
PFILE_STANDARD_INFORMATION StdInfo;
|
||
PFILE_POSITION_INFORMATION PosInfo;
|
||
PDEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
|
||
|
||
UNREFERENCED_PARAMETER(DeviceObject);
|
||
|
||
// ParDumpV( ("In query information file\n") );
|
||
|
||
//
|
||
// bail out if device has been removed
|
||
//
|
||
if(Extension->DeviceStateFlags & (PAR_DEVICE_REMOVED|PAR_DEVICE_SURPRISE_REMOVAL) ) {
|
||
|
||
Irp->IoStatus.Status = STATUS_DEVICE_REMOVED;
|
||
ParCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
return STATUS_DEVICE_REMOVED;
|
||
}
|
||
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
|
||
switch (IrpSp->Parameters.QueryFile.FileInformationClass) {
|
||
|
||
case FileStandardInformation:
|
||
|
||
if (IrpSp->Parameters.QueryFile.Length < sizeof(FILE_STANDARD_INFORMATION)) {
|
||
|
||
Status = STATUS_BUFFER_TOO_SMALL;
|
||
|
||
} else {
|
||
|
||
StdInfo = Irp->AssociatedIrp.SystemBuffer;
|
||
StdInfo->AllocationSize.QuadPart = 0;
|
||
StdInfo->EndOfFile = StdInfo->AllocationSize;
|
||
StdInfo->NumberOfLinks = 0;
|
||
StdInfo->DeletePending = FALSE;
|
||
StdInfo->Directory = FALSE;
|
||
|
||
Irp->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION);
|
||
Status = STATUS_SUCCESS;
|
||
|
||
}
|
||
break;
|
||
|
||
case FilePositionInformation:
|
||
|
||
if (IrpSp->Parameters.SetFile.Length < sizeof(FILE_POSITION_INFORMATION)) {
|
||
|
||
Status = STATUS_BUFFER_TOO_SMALL;
|
||
|
||
} else {
|
||
|
||
PosInfo = Irp->AssociatedIrp.SystemBuffer;
|
||
PosInfo->CurrentByteOffset.QuadPart = 0;
|
||
|
||
Irp->IoStatus.Information = sizeof(FILE_POSITION_INFORMATION);
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
break;
|
||
|
||
}
|
||
|
||
Irp->IoStatus.Status = Status;
|
||
|
||
ParCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
ParSetInformationFile(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to set the end of file information on
|
||
the opened parallel port. Any other file information request
|
||
is retured with an invalid parameter.
|
||
|
||
This routine always ignores the actual end of file since
|
||
the query information code always returns an end of file of 0.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Supplies the device object.
|
||
|
||
Irp - Supplies the I/O request packet.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Success.
|
||
STATUS_INVALID_PARAMETER - Invalid file information request.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
FILE_INFORMATION_CLASS fileInfoClass;
|
||
PDEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
|
||
|
||
UNREFERENCED_PARAMETER(DeviceObject);
|
||
|
||
//
|
||
// bail out if device has been removed
|
||
//
|
||
if(Extension->DeviceStateFlags & (PAR_DEVICE_REMOVED|PAR_DEVICE_SURPRISE_REMOVAL) ) {
|
||
|
||
Irp->IoStatus.Status = STATUS_DEVICE_REMOVED;
|
||
ParCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
return STATUS_DEVICE_REMOVED;
|
||
}
|
||
|
||
|
||
// ParDump(PARIRPPATH | PARDUMP_VERBOSE_MAX,
|
||
// ("PARALLEL: "
|
||
// "In set information with IRP: %08x\n",
|
||
// Irp) );
|
||
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
fileInfoClass = IoGetCurrentIrpStackLocation(Irp)->Parameters.SetFile.FileInformationClass;
|
||
|
||
if (fileInfoClass == FileEndOfFileInformation) {
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
} else {
|
||
|
||
// ParDump(PARDUMP_VERBOSE_MAX,
|
||
// ("PARALLEL: "
|
||
// "In ParSetInformationFile(...): "
|
||
// "Invalid FileInformationClass: %d , only %d is valid\n"
|
||
// "PARALLEL: "
|
||
// " - Returning STATUS_INVALID_PARAMETER\n",
|
||
// fileInfoClass, FileEndOfFileInformation) );
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
|
||
}
|
||
|
||
Irp->IoStatus.Status = Status;
|
||
|
||
// ParDump(PARDUMP_VERBOSE_MAX,
|
||
// ("PARALLEL: "
|
||
// "About to complete IRP in set information - "
|
||
// "Irp: %x status: %x Information: %x\n",
|
||
// Irp, Irp->IoStatus.Status, Irp->IoStatus.Information) );
|
||
|
||
ParCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
#if PAR_NO_FAST_CALLS
|
||
// temp debug functions so params show up on stack trace
|
||
|
||
VOID
|
||
ParCompleteRequest(
|
||
IN PIRP Irp,
|
||
IN CCHAR PriorityBoost
|
||
)
|
||
{
|
||
// KIRQL CancelIrql;
|
||
// IoAcquireCancelSpinLock(&CancelIrql);
|
||
// ASSERT( !Irp->CancelRoutine );
|
||
// IoReleaseCancelSpinLock(CancelIrql);
|
||
if( Irp->UserEvent ) {
|
||
ASSERT_EVENT( Irp->UserEvent );
|
||
}
|
||
IoCompleteRequest(Irp, PriorityBoost);
|
||
}
|
||
|
||
NTSTATUS
|
||
ParCallDriver(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN OUT PIRP Irp
|
||
)
|
||
{
|
||
return IoCallDriver(DeviceObject, Irp);
|
||
}
|
||
|
||
#endif
|