windows-nt/Source/XPSP1/NT/drivers/parallel/parclass/pnppdo.c
2020-09-26 16:20:57 +08:00

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;
}