642 lines
25 KiB
C
642 lines
25 KiB
C
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
//
|
||
|
// Copyright (C) Microsoft Corporation, 1998 - 1999
|
||
|
//
|
||
|
// File: pnppdo.c
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
//
|
||
|
// This file contains functions associated with handling IRPs sent to a PDO
|
||
|
//
|
||
|
|
||
|
#include "pch.h"
|
||
|
|
||
|
NTSTATUS
|
||
|
ParPdoParallelPnp (
|
||
|
IN PDEVICE_OBJECT pDeviceObject,
|
||
|
IN PIRP pIrp
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine handles all PNP IRPs for the PDOs.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
pDeviceObject - represents a parallel device
|
||
|
|
||
|
pIrp - PNP Irp
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
STATUS_SUCCESS - if successful.
|
||
|
STATUS_UNSUCCESSFUL - otherwise.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
PDEVICE_EXTENSION Extension;
|
||
|
// PVOID pDriverObject;
|
||
|
PIO_STACK_LOCATION pIrpStack;
|
||
|
// PIO_STACK_LOCATION pNextIrpStack;
|
||
|
// KEVENT Event;
|
||
|
// ULONG cRequired;
|
||
|
// GUID Guid;
|
||
|
// WCHAR wszGuid[64];
|
||
|
// UNICODE_STRING uniGuid;
|
||
|
// WCHAR wszDeviceDesc[64];
|
||
|
// UNICODE_STRING uniDevice;
|
||
|
|
||
|
// ParDump(PARDUMP_VERBOSE_MAX,
|
||
|
// ("PARALLEL: "
|
||
|
// "Enter ParPdoParallelPnp(...): IRP_MJ_PNP\n") );
|
||
|
|
||
|
pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
|
||
|
Extension = pDeviceObject->DeviceExtension;
|
||
|
|
||
|
//
|
||
|
// dvdf RMT - don't blindly set information to 0
|
||
|
// - kills info passed down by disk.sys and prevents ZipPlus
|
||
|
// from getting assigned a drive letter.
|
||
|
//
|
||
|
// pIrp->IoStatus.Information = 0; // dvdr
|
||
|
|
||
|
|
||
|
//
|
||
|
// bail out if a delete is pending for this device object
|
||
|
//
|
||
|
if(Extension->DeviceStateFlags & PAR_DEVICE_DELETE_PENDING) {
|
||
|
pIrp->IoStatus.Status = STATUS_DELETE_PENDING;
|
||
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
||
|
return STATUS_DELETE_PENDING;
|
||
|
}
|
||
|
|
||
|
if(Extension->DeviceStateFlags & PAR_DEVICE_PORT_REMOVE_PENDING) {
|
||
|
ParDumpP( ("PDO PnP Dispatch - PAR_DEVICE_PORT_REMOVE_PENDING - IRP MN == %x\n", pIrpStack->MinorFunction) );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// The only PnP IRP that a PODO should receive is QDR/TargetDeviceRelation.
|
||
|
// Any other PnP IRP is an error.
|
||
|
//
|
||
|
if( ( Extension->DeviceType == PAR_DEVTYPE_PODO ) &&
|
||
|
! ( ( pIrpStack->MinorFunction == IRP_MN_QUERY_DEVICE_RELATIONS ) &&
|
||
|
( pIrpStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation ) ) ) {
|
||
|
|
||
|
ASSERTMSG( "PnP IRP sent to legacy device object ", FALSE);
|
||
|
pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
|
||
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
||
|
return STATUS_NOT_SUPPORTED;
|
||
|
}
|
||
|
|
||
|
|
||
|
switch (pIrpStack->MinorFunction) {
|
||
|
|
||
|
case IRP_MN_START_DEVICE:
|
||
|
|
||
|
ParDumpP( ("START_DEVICE - %wZ\n", &Extension->SymbolicLinkName) );
|
||
|
Extension->DeviceStateFlags = PAR_DEVICE_STARTED;
|
||
|
|
||
|
// tell parport device to list us in its PnP QDR/RemovalRelations response
|
||
|
// yes, we ignore the return value
|
||
|
Status = ParRegisterForParportRemovalRelations( Extension );
|
||
|
|
||
|
// initialize WMI context structure and register for WMI
|
||
|
// yes, we ignore the return value
|
||
|
Status = ParWmiPdoInitWmi(pDeviceObject);
|
||
|
|
||
|
pIrp->IoStatus.Status = STATUS_SUCCESS;
|
||
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
||
|
KeSetEvent(&Extension->PauseEvent, 0, FALSE);
|
||
|
return STATUS_SUCCESS;
|
||
|
|
||
|
case IRP_MN_QUERY_CAPABILITIES:
|
||
|
|
||
|
ParDumpP( ("QUERY_CAPABILITIES - %wZ\n", &Extension->SymbolicLinkName) );
|
||
|
pIrpStack->Parameters.DeviceCapabilities.Capabilities->RawDeviceOK = TRUE;
|
||
|
Status = STATUS_SUCCESS;
|
||
|
break;
|
||
|
|
||
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
||
|
|
||
|
ParDumpP( ("QUERY_DEVICE_RELATIONS - %wZ - Type=%d\n",
|
||
|
&Extension->SymbolicLinkName, pIrpStack->Parameters.QueryDeviceRelations.Type) );
|
||
|
|
||
|
if ( pIrpStack->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation ) {
|
||
|
|
||
|
#if 0
|
||
|
//
|
||
|
// Return a reference to this PDO (self)
|
||
|
//
|
||
|
PDEVICE_RELATIONS devRel;
|
||
|
|
||
|
ParDumpP( ("QUERY_DEVICE_RELATIONS - %wZ - TargetRelation\n", &Extension->SymbolicLinkName) );
|
||
|
|
||
|
devRel = ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
|
||
|
|
||
|
if (devRel){
|
||
|
//
|
||
|
// Add a reference to the PDO, since CONFIGMG will free it.
|
||
|
//
|
||
|
ObReferenceObject(Extension->DeviceObject);
|
||
|
devRel->Objects[0] = Extension->DeviceObject;
|
||
|
devRel->Count = 1;
|
||
|
pIrp->IoStatus.Information = (ULONG_PTR)devRel;
|
||
|
Status = STATUS_SUCCESS;
|
||
|
} else {
|
||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
#else
|
||
|
//
|
||
|
// Forward PnP QueryTargetRelation IRP to ParPort device
|
||
|
//
|
||
|
ParDumpP(("Preparing to forward QDR/TargetDevRel to ParPort\n"));
|
||
|
IoSkipCurrentIrpStackLocation(pIrp);
|
||
|
return ParCallDriver(Extension->PortDeviceObject, pIrp);
|
||
|
|
||
|
#endif // 0
|
||
|
|
||
|
} else {
|
||
|
//
|
||
|
// We don't handle this type of DeviceRelations query, so...
|
||
|
//
|
||
|
// Fail this Irp by returning the default status (typically STATUS_NOT_SUPPORTED).
|
||
|
//
|
||
|
|
||
|
// ParDumpP( ("QUERY_DEVICE_RELATIONS - %wZ - unhandled relation (!TargetRelation)\n",
|
||
|
// &Extension->SymbolicLinkName) );
|
||
|
Status = pIrp->IoStatus.Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Complete the IRP...
|
||
|
//
|
||
|
pIrp->IoStatus.Status = Status;
|
||
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
||
|
return Status;
|
||
|
|
||
|
|
||
|
case IRP_MN_QUERY_DEVICE_TEXT:
|
||
|
|
||
|
switch(pIrpStack->Parameters.QueryDeviceText.DeviceTextType) {
|
||
|
|
||
|
case DeviceTextDescription:
|
||
|
{
|
||
|
UCHAR RawString[MAX_ID_SIZE];
|
||
|
ANSI_STRING AnsiTextString;
|
||
|
UNICODE_STRING UnicodeDeviceText;
|
||
|
|
||
|
RtlInitAnsiString(&AnsiTextString,Extension->DeviceDescription);
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeDeviceText,&AnsiTextString,TRUE);
|
||
|
if( NT_SUCCESS( Status ) ) {
|
||
|
ParDumpP( ("QUERY_DEVICE_TEXT - DeviceTextDescription - %wZ\n", &UnicodeDeviceText) );
|
||
|
pIrp->IoStatus.Information = (ULONG_PTR)UnicodeDeviceText.Buffer;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case DeviceTextLocationInformation:
|
||
|
{
|
||
|
//
|
||
|
// Report SymbolicLinkName without the L"\\DosDevices\\" prefix
|
||
|
// as the location
|
||
|
//
|
||
|
ULONG prefixLength = sizeof(L"\\DosDevices\\") - sizeof(UNICODE_NULL);
|
||
|
ULONG bufferLength = Extension->SymbolicLinkName.Length - prefixLength + sizeof(UNICODE_NULL);
|
||
|
PWSTR buffer;
|
||
|
ParDumpP( ("QUERY_DEVICE_TEXT - DeviceTextLocationInformation\n") );
|
||
|
ParDumpP( (" - SymbolicLinkName = %wZ , bufferLength = %d\n",
|
||
|
&Extension->SymbolicLinkName, bufferLength) );
|
||
|
if(bufferLength <= MAX_ID_SIZE) {
|
||
|
buffer = ExAllocatePool(PagedPool, bufferLength);
|
||
|
} else {
|
||
|
// assume that something went very wrong
|
||
|
buffer = NULL;
|
||
|
}
|
||
|
if(!buffer) {
|
||
|
// unable to allocate a buffer to hold location information
|
||
|
pIrp->IoStatus.Information = 0;
|
||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
} else {
|
||
|
// copy location information to buffer and null terminate it
|
||
|
PCHAR src = (PCHAR)Extension->SymbolicLinkName.Buffer + prefixLength;
|
||
|
RtlCopyMemory( buffer, src, bufferLength - sizeof(UNICODE_NULL) );
|
||
|
buffer[ bufferLength/2 - 1 ] = UNICODE_NULL;
|
||
|
pIrp->IoStatus.Information = (ULONG_PTR)buffer;
|
||
|
Status = STATUS_SUCCESS;
|
||
|
ParDumpP( ("QUERY_DEVICE_TEXT - Device Location - %S\n", buffer) );
|
||
|
}
|
||
|
}
|
||
|
break; // from case DeviceTextLocationInformation:
|
||
|
|
||
|
default:
|
||
|
// unknown request type
|
||
|
// pIrp->IoStatus.Information = 0;
|
||
|
Status = pIrp->IoStatus.Status;
|
||
|
}
|
||
|
|
||
|
break; // from case IRP_MN_QUERY_DEVICE_TEXT:
|
||
|
|
||
|
case IRP_MN_QUERY_ID:
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// report the id depending on what the device attached to the port returned us
|
||
|
//
|
||
|
|
||
|
UCHAR DeviceIdString[MAX_ID_SIZE] = "LPTENUM\\NoPrinterOrNonPnpModel";
|
||
|
UCHAR RawString[MAX_ID_SIZE];
|
||
|
ANSI_STRING AnsiIdString;
|
||
|
UNICODE_STRING UnicodeDeviceId;
|
||
|
UNICODE_STRING UnicodeTemp;
|
||
|
ULONG DeviceIdLength;
|
||
|
HANDLE KeyHandle;
|
||
|
|
||
|
if (Extension->DeviceIdString[0] == 0) {
|
||
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
RtlZeroMemory(RawString, sizeof(RawString));
|
||
|
|
||
|
Status = STATUS_SUCCESS;
|
||
|
|
||
|
switch(pIrpStack->Parameters.QueryId.IdType) {
|
||
|
|
||
|
case BusQueryDeviceID:
|
||
|
|
||
|
if (Extension->DeviceIdString[0] == 0) {
|
||
|
Status = STATUS_NOT_FOUND;
|
||
|
break;
|
||
|
} else {
|
||
|
sprintf((PCHAR)RawString,"LPTENUM\\%s",Extension->DeviceIdString );
|
||
|
ParFixupDeviceId( (PUCHAR)RawString );
|
||
|
RtlInitAnsiString(&AnsiIdString, (PCHAR)RawString);
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeDeviceId, &AnsiIdString, TRUE);
|
||
|
}
|
||
|
|
||
|
if( NT_SUCCESS( Status ) ) {
|
||
|
ParDumpP( ("QUERY_ID - BusQueryDeviceID - %wZ\n", &UnicodeDeviceId) );
|
||
|
pIrp->IoStatus.Information = (ULONG_PTR)UnicodeDeviceId.Buffer;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case BusQueryInstanceID:
|
||
|
|
||
|
if (Extension->DeviceIdString[0] == 0) {
|
||
|
Status = STATUS_NOT_FOUND;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Report SymbolicLinkName without the L"\\DosDevices\\" prefix
|
||
|
// as the instance ID
|
||
|
//
|
||
|
{
|
||
|
ULONG prefixLength = sizeof(L"\\DosDevices\\") - sizeof(UNICODE_NULL);
|
||
|
ULONG bufferLength = Extension->SymbolicLinkName.Length - prefixLength + sizeof(UNICODE_NULL);
|
||
|
PWSTR buffer;
|
||
|
ParDumpP( ("QUERY_ID - BusQueryInstanceID - "
|
||
|
"SymbolicLinkName = %wZ , bufferLength = %d\n",
|
||
|
&Extension->SymbolicLinkName, bufferLength) );
|
||
|
if(bufferLength <= MAX_ID_SIZE) {
|
||
|
buffer = ExAllocatePool(PagedPool, bufferLength);
|
||
|
} else {
|
||
|
// assume that something went very wrong
|
||
|
buffer = NULL;
|
||
|
}
|
||
|
if(!buffer) {
|
||
|
// unable to allocate a buffer to hold location information
|
||
|
pIrp->IoStatus.Information = 0;
|
||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
} else {
|
||
|
// copy location information to buffer and null terminate it
|
||
|
PCHAR src = (PCHAR)Extension->SymbolicLinkName.Buffer + prefixLength;
|
||
|
RtlCopyMemory( buffer, src, bufferLength - sizeof(UNICODE_NULL) );
|
||
|
buffer[ bufferLength/2 - 1 ] = UNICODE_NULL;
|
||
|
pIrp->IoStatus.Information = (ULONG_PTR)buffer;
|
||
|
Status = STATUS_SUCCESS;
|
||
|
ParDumpP( ("QUERY_ID - BusQueryInstanceID - %S\n", buffer) );
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case BusQueryHardwareIDs:
|
||
|
|
||
|
if (Extension->DeviceIdString[0] == 0) {
|
||
|
// bail out if we don't have a device id
|
||
|
Status = STATUS_NOT_FOUND;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Store the port we are attached in the registry under our device instance
|
||
|
//
|
||
|
|
||
|
Status = IoOpenDeviceRegistryKey( pDeviceObject, PLUGPLAY_REGKEY_DEVICE, KEY_ALL_ACCESS, &KeyHandle );
|
||
|
|
||
|
if ( NT_SUCCESS(Status) ) {
|
||
|
|
||
|
//
|
||
|
// Create a new value under our instance, for the port number
|
||
|
//
|
||
|
sprintf((PCHAR)RawString,"PortName");
|
||
|
RtlInitAnsiString(&AnsiIdString,(PCHAR)RawString);
|
||
|
|
||
|
//
|
||
|
// Now we have to build the actual value contents
|
||
|
//
|
||
|
{
|
||
|
//
|
||
|
// - Start with the SymbolicLinkName
|
||
|
// - Discard the L"\\DosDevices\\" prefix
|
||
|
// WORKWORK/RMT TODO: - Discard the L".N" suffix if this is an End-Of-Chain device
|
||
|
// - Append L':'
|
||
|
//
|
||
|
ULONG prefixLength = sizeof(L"\\DosDevices\\") - sizeof(UNICODE_NULL);
|
||
|
ULONG bufferLength = Extension->SymbolicLinkName.Length
|
||
|
- prefixLength + sizeof(PAR_UNICODE_COLON) + sizeof(UNICODE_NULL);
|
||
|
PWSTR buffer;
|
||
|
ParDumpV( ( "QUERY_ID - BusQueryHardwareIDs - SymbolicLinkName = %wZ , bufferLength = %d\n",
|
||
|
&Extension->SymbolicLinkName, bufferLength) );
|
||
|
|
||
|
if(bufferLength > MAX_ID_SIZE) {
|
||
|
// we had a rollover and our bufferLength is not valid
|
||
|
buffer = NULL;
|
||
|
} else {
|
||
|
buffer = ExAllocatePool(PagedPool, bufferLength);
|
||
|
}
|
||
|
if(!buffer) {
|
||
|
// unable to allocate a buffer to hold location information
|
||
|
pIrp->IoStatus.Information = 0;
|
||
|
pIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
} else {
|
||
|
// copy location information to buffer and null terminate it
|
||
|
PCHAR src = (PCHAR)Extension->SymbolicLinkName.Buffer + prefixLength;
|
||
|
RtlCopyMemory( buffer, src, bufferLength - sizeof(UNICODE_NULL) );
|
||
|
buffer[ bufferLength/2 - 2 ] = PAR_UNICODE_COLON;
|
||
|
buffer[ bufferLength/2 - 1 ] = UNICODE_NULL;
|
||
|
{
|
||
|
// if this is an End-Of-Chain device, discard the L".N" suffix
|
||
|
// WARNING - HACKHACK until spooler is fully PnP
|
||
|
if( ( (Extension->Ieee1284_3DeviceId == DOT3_END_OF_CHAIN_ID) || Extension->EndOfChain ) &&
|
||
|
(buffer[bufferLength/2 - 3] <= L'9') &&
|
||
|
(buffer[bufferLength/2 - 3] >= L'0') &&
|
||
|
(buffer[bufferLength/2 - 4] == L'.') ) {
|
||
|
|
||
|
buffer[bufferLength/2 - 4] = PAR_UNICODE_COLON;
|
||
|
buffer[bufferLength/2 - 3] = UNICODE_NULL;
|
||
|
}
|
||
|
}
|
||
|
RtlInitUnicodeString(&UnicodeTemp, buffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{
|
||
|
UNICODE_STRING UnicodeRegValueName;
|
||
|
NTSTATUS status;
|
||
|
|
||
|
status = RtlAnsiStringToUnicodeString(&UnicodeRegValueName,&AnsiIdString,TRUE);
|
||
|
|
||
|
if( NT_SUCCESS ( status ) ) {
|
||
|
ZwSetValueKey( KeyHandle, &UnicodeRegValueName, 0, REG_SZ, UnicodeTemp.Buffer, UnicodeTemp.Length*sizeof(UCHAR) );
|
||
|
RtlFreeUnicodeString(&UnicodeRegValueName);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
ZwClose(KeyHandle);
|
||
|
|
||
|
}
|
||
|
|
||
|
ParDumpP( ("QUERY_ID - BusQueryHardwareIDs\n") );
|
||
|
|
||
|
//
|
||
|
// continue on, to return the actual HardwareID string
|
||
|
//
|
||
|
|
||
|
case BusQueryCompatibleIDs:
|
||
|
|
||
|
if (Extension->DeviceIdString[0] == 0) {
|
||
|
Status = STATUS_NOT_FOUND;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Status = ParPnpGetId(Extension->DeviceIdString,pIrpStack->Parameters.QueryId.IdType,RawString, NULL);
|
||
|
|
||
|
if( NT_SUCCESS( Status ) ) {
|
||
|
|
||
|
RawString[strlen((PCHAR)RawString)+1]=0;
|
||
|
RawString[strlen((PCHAR)RawString)]=32;
|
||
|
ParFixupDeviceId( (PUCHAR)RawString );
|
||
|
RtlInitAnsiString(&AnsiIdString,(PCHAR)RawString);
|
||
|
|
||
|
Status = RtlAnsiStringToUnicodeString(&UnicodeDeviceId,&AnsiIdString,TRUE);
|
||
|
|
||
|
if( NT_SUCCESS( Status ) ) {
|
||
|
|
||
|
ParDumpP( ("QUERY_ID - BusQueryHardwareIDs/BusQueryCompatibleIDs - %wZ\n", &UnicodeDeviceId) );
|
||
|
|
||
|
// Now append another NULL, to terminate the multi_sz
|
||
|
UnicodeTemp.Buffer = UnicodeDeviceId.Buffer;
|
||
|
((PSTR)UnicodeTemp.Buffer) += (UnicodeDeviceId.Length-2);
|
||
|
RtlZeroMemory(UnicodeTemp.Buffer,sizeof(WCHAR));
|
||
|
pIrp->IoStatus.Information = (ULONG_PTR)UnicodeDeviceId.Buffer;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
|
||
|
//
|
||
|
// unrecognized IdType
|
||
|
//
|
||
|
Status = pIrp->IoStatus.Status;
|
||
|
|
||
|
} // end switch(pIrpStack->Parameters.QueryId.IdType)
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case IRP_MN_QUERY_STOP_DEVICE:
|
||
|
|
||
|
ParDumpP( ("QUERY_STOP_DEVICE - %wZ\n", &Extension->SymbolicLinkName) );
|
||
|
Extension->DeviceStateFlags |= (PAR_DEVICE_STOP_PENDING | PAR_DEVICE_PAUSED);
|
||
|
KeClearEvent(&Extension->PauseEvent);
|
||
|
Status = STATUS_SUCCESS;
|
||
|
break;
|
||
|
|
||
|
case IRP_MN_CANCEL_STOP_DEVICE:
|
||
|
|
||
|
ParDumpP( ("IRP_MN_CANCEL_STOP_DEVICE - %wZ\n", &Extension->SymbolicLinkName) );
|
||
|
Extension->DeviceStateFlags &= ~PAR_DEVICE_STOP_PENDING;
|
||
|
KeSetEvent(&Extension->PauseEvent, 0, FALSE);
|
||
|
Status = STATUS_SUCCESS;
|
||
|
break;
|
||
|
|
||
|
case IRP_MN_STOP_DEVICE:
|
||
|
|
||
|
ParDumpP( ("IRP_MN_STOP_DEVICE - %wZ\n", &Extension->SymbolicLinkName) );
|
||
|
Extension->DeviceStateFlags |= PAR_DEVICE_PAUSED;
|
||
|
Extension->DeviceStateFlags &= ~PAR_DEVICE_STARTED;
|
||
|
KeClearEvent(&Extension->PauseEvent);
|
||
|
Status = STATUS_SUCCESS;
|
||
|
break;
|
||
|
|
||
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
||
|
|
||
|
// Succeed if no one has an open handle to us, fail otherwise
|
||
|
ExAcquireFastMutex(&Extension->OpenCloseMutex);
|
||
|
if(Extension->OpenCloseRefCount > 0) {
|
||
|
DDPnP1(("## Fail QueryRemove - %wZ\n",&Extension->SymbolicLinkName));
|
||
|
ParDump2(PARPNP1, ("QUERY_REMOVE_DEVICE - %wZ - FAIL - open handles to us\n", &Extension->SymbolicLinkName) );
|
||
|
Status = STATUS_DEVICE_BUSY;
|
||
|
} else {
|
||
|
DDPnP1(("## Succeed QueryRemove - %wZ\n",&Extension->SymbolicLinkName));
|
||
|
ParDump2(PARPNP1, ("IRP_MN_QUERY_REMOVE_DEVICE - %wZ - SUCCEED\n", &Extension->SymbolicLinkName) );
|
||
|
Extension->DeviceStateFlags |= (PAR_DEVICE_REMOVE_PENDING | PAR_DEVICE_PAUSED);
|
||
|
KeClearEvent(&Extension->PauseEvent);
|
||
|
if( Extension->PortDeviceFileObject ) {
|
||
|
//
|
||
|
// close our handle to parport so we don't block a parport removal
|
||
|
//
|
||
|
ParDump2(PARPNP1, ("CLOSE our handle to ParPort\n") );
|
||
|
ObDereferenceObject( Extension->PortDeviceFileObject );
|
||
|
Extension->PortDeviceFileObject = NULL;
|
||
|
}
|
||
|
Status = STATUS_SUCCESS;
|
||
|
}
|
||
|
ExReleaseFastMutex(&Extension->OpenCloseMutex);
|
||
|
break;
|
||
|
|
||
|
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
||
|
|
||
|
DDPnP1(("## CancelRemove - %wZ\n",&Extension->SymbolicLinkName));
|
||
|
|
||
|
ParDumpP( ("CANCEL_REMOVE_DEVICE - %wZ\n", &Extension->SymbolicLinkName) );
|
||
|
|
||
|
Extension->DeviceStateFlags &= ~(PAR_DEVICE_REMOVE_PENDING | PAR_DEVICE_PAUSED);
|
||
|
|
||
|
if( !Extension->PortDeviceFileObject ) {
|
||
|
|
||
|
//
|
||
|
// we dropped our connection to our ParPort prior to
|
||
|
// our ParPort receiving QUERY_REMOVE, reestablish
|
||
|
// a FILE connection and resume operation
|
||
|
//
|
||
|
|
||
|
NTSTATUS status;
|
||
|
PFILE_OBJECT portDeviceFileObject;
|
||
|
PDEVICE_OBJECT portDeviceObject;
|
||
|
|
||
|
ParDump2(PARPNP1, ("reopening file against our ParPort\n") );
|
||
|
|
||
|
status = IoGetDeviceObjectPointer(&Extension->PortSymbolicLinkName,
|
||
|
STANDARD_RIGHTS_ALL,
|
||
|
&portDeviceFileObject,
|
||
|
&portDeviceObject);
|
||
|
|
||
|
if(NT_SUCCESS(status) && portDeviceFileObject && portDeviceObject) {
|
||
|
// save REFERENCED PFILE_OBJECT in our device extension
|
||
|
Extension->PortDeviceFileObject = portDeviceFileObject;
|
||
|
// our ParPort device object should not have changed
|
||
|
ASSERT(Extension->PortDeviceObject == portDeviceObject);
|
||
|
|
||
|
} else {
|
||
|
ParDump2(PARPNP1, ("Unable to reopen FILE against our ParPort\n") );
|
||
|
|
||
|
//
|
||
|
// Unable to reestablish connection? Inconceivable!
|
||
|
//
|
||
|
ASSERT(FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
KeSetEvent(&Extension->PauseEvent, 0, FALSE);
|
||
|
Status = STATUS_SUCCESS;
|
||
|
break;
|
||
|
|
||
|
case IRP_MN_REMOVE_DEVICE:
|
||
|
|
||
|
DDPnP1(("## RemoveDevice - %wZ\n",&Extension->SymbolicLinkName));
|
||
|
|
||
|
ParDumpP( ("REMOVE_DEVICE - %x <%wZ>\n", Extension->DeviceObject, &Extension->SymbolicLinkName) );
|
||
|
|
||
|
Status = ParUnregisterForParportRemovalRelations( Extension );
|
||
|
|
||
|
//
|
||
|
// Unregister with WMI
|
||
|
//
|
||
|
ParWMIRegistrationControl(pDeviceObject, WMIREG_ACTION_DEREGISTER);
|
||
|
|
||
|
ParDumpP( ("REMOVE_DEVICE - %wZ - Checking if device still there...\n",
|
||
|
&Extension->SymbolicLinkName) );
|
||
|
|
||
|
if( !(Extension->DeviceStateFlags & PAR_DEVICE_HARDWARE_GONE) && ParDeviceExists(Extension,FALSE) ) {
|
||
|
ParDumpP( ("REMOVE_DEVICE - %wZ - Device still there - Keep DO\n",
|
||
|
&Extension->SymbolicLinkName) );
|
||
|
Extension->DeviceStateFlags = PAR_DEVICE_PAUSED;
|
||
|
} else {
|
||
|
ParDumpP( ("REMOVE_DEVICE - %wZ - Device no longer present - Kill DO\n",
|
||
|
&Extension->SymbolicLinkName) );
|
||
|
|
||
|
{
|
||
|
//
|
||
|
// Clean up the device object
|
||
|
//
|
||
|
PDEVICE_EXTENSION FdoExtension = Extension->ParClassFdo->DeviceExtension;
|
||
|
ExAcquireFastMutex(&FdoExtension->DevObjListMutex);
|
||
|
ParKillDeviceObject(pDeviceObject);
|
||
|
ExReleaseFastMutex(&FdoExtension->DevObjListMutex);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Status = STATUS_SUCCESS;
|
||
|
break;
|
||
|
|
||
|
|
||
|
case IRP_MN_SURPRISE_REMOVAL:
|
||
|
|
||
|
#define PAR_HANDLE_SURPRISE_REMOVAL 1
|
||
|
#if PAR_HANDLE_SURPRISE_REMOVAL
|
||
|
|
||
|
ParDumpP( ("SURPRISE_REMOVAL - %wZ - handled\n", &Extension->SymbolicLinkName) );
|
||
|
|
||
|
// note in our extension that we received SURPRISE_REMOVAL
|
||
|
Extension->DeviceStateFlags |= PAR_DEVICE_SURPRISE_REMOVAL;
|
||
|
|
||
|
// stop the worker thread
|
||
|
KeClearEvent(&Extension->PauseEvent);
|
||
|
Status = STATUS_SUCCESS;
|
||
|
break;
|
||
|
|
||
|
#else
|
||
|
ParDumpP( ("SURPRISE_REMOVAL - %wZ - NOT handled\n", &Extension->SymbolicLinkName) );
|
||
|
// we don't handle yet - fall through to default
|
||
|
|
||
|
#endif
|
||
|
|
||
|
default:
|
||
|
|
||
|
ParDumpP(("ParPdoParallelPnp - %wZ - Unhandled IRP %x\n",
|
||
|
&Extension->SymbolicLinkName, pIrpStack->MinorFunction) );
|
||
|
Status = pIrp->IoStatus.Status; // Don't modify status
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Complete the IRP...
|
||
|
//
|
||
|
pIrp->IoStatus.Status = Status;
|
||
|
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
|
||
|
return Status;
|
||
|
}
|