windows-nt/Source/XPSP1/NT/drivers/parallel/parclass/pnpfdo.c

575 lines
19 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1998 - 1999
//
// File: pnpfdo.c
//
//--------------------------------------------------------------------------
//
// This file contains functions for handing AddDevice and PnP IRPs sent to the FDO
//
#include "pch.h"
NTSTATUS
ParPnpNotifyHwProfileChange(
IN PHWPROFILE_CHANGE_NOTIFICATION NotificationStructure,
IN PDEVICE_OBJECT Fdo
)
//
// We just completed either a dock or an undock - trigger bus rescan to check for new devices
//
{
PDEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
PAGED_CODE();
if( IsEqualGUID( (LPGUID)&(NotificationStructure->Event), (LPGUID)&GUID_HWPROFILE_CHANGE_COMPLETE) ) {
IoInvalidateDeviceRelations( fdoExt->PhysicalDeviceObject, BusRelations );
}
return STATUS_SUCCESS;
}
NTSTATUS
ParPnpFdoStartDevice(
IN PDEVICE_OBJECT Fdo,
IN PIRP Irp
)
{
NTSTATUS status = STATUS_NOT_SUPPORTED;
PDEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
KEVENT event;
ParDumpP( ("IRP_MN_START_DEVICE - FDO\n") );
//
// The stack below us must successfully START before we can START.
//
// Pass the IRP down the stack and catch it on the way back up in our
// completion routine. Our completion routine simply sets "event"
// to its signalled state and returns STATUS_MORE_PROCESSING_REQUIRED,
// which allows us to regain control of the IRP in this routine after
// the stack below us has finished processing the START.
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp, ParSynchCompletionRoutine, &event, TRUE, TRUE, TRUE );
status = ParCallDriver(fdoExt->ParentDeviceObject, Irp);
// wait for our completion routine to signal that it has caught the IRP
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
//
// We have control of the IRP again and the stack below us has finished processing.
//
if( status == STATUS_PENDING ) {
// IRP completed asynchronously below us - extract "real" status from the IRP
status = Irp->IoStatus.Status;
}
//
// did anyone below us FAIL the IRP?
//
if( !NT_SUCCESS(status) ) {
// someone below us FAILed the IRP, bail out
ParDump2(PARERRORS, ("START IRP FAILED below us in stack, status=%x\n", status) );
IoCompleteRequest(Irp, IO_NO_INCREMENT);
ParReleaseRemoveLock(&fdoExt->RemoveLock, Irp);
return status;
}
//
// The stack below us is STARTed.
//
//
// Register for ParPort PnP Interface changes.
//
// We will get an ARRIVAL callback for every ParPort device that is STARTed and
// a REMOVAL callback for every ParPort that is REMOVEd
//
#if 0 // disable parclass enumeration to work with new parport enumerator - DFritz - 2000-03-25
status = IoRegisterPlugPlayNotification (EventCategoryDeviceInterfaceChange,
PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
(PVOID)&GUID_PARALLEL_DEVICE,
Fdo->DriverObject,
(PDRIVER_NOTIFICATION_CALLBACK_ROUTINE)ParPnpNotifyInterfaceChange,
(PVOID)Fdo,
&fdoExt->NotificationHandle);
if (!NT_SUCCESS(status)) {
// registration failed, we will never have any ParPort devices to talk to
ParDumpP( ("IoRegisterPlugPlayNotification InterfaceChange FAILED, status= %x\n", status) );
}
status = IoRegisterPlugPlayNotification( EventCategoryHardwareProfileChange,
0,
NULL,
Fdo->DriverObject,
(PDRIVER_NOTIFICATION_CALLBACK_ROUTINE)ParPnpNotifyHwProfileChange,
(PVOID)Fdo,
&fdoExt->HwProfileChangeNotificationHandle );
if (!NT_SUCCESS(status)) {
// registration failed, we will never have any ParPort devices to talk to
ParDumpP( ("IoRegisterPlugPlayNotification HwProfileChange FAILED, status= %x\n", status) );
}
#endif // 0
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
ParReleaseRemoveLock(&fdoExt->RemoveLock, Irp);
return status;
}
NTSTATUS
ParPnpFdoQueryCapabilities(
IN PDEVICE_OBJECT Fdo,
IN PIRP Irp
)
{
NTSTATUS status;
PDEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
// KEVENT event;
PIO_STACK_LOCATION irpStack;
ParDumpP( ("IRP_MN_QUERY_CAPABILITIES - FDO\n") );
irpStack = IoGetCurrentIrpStackLocation( Irp );
// - does RawDeviceOK = TRUE make sense for the FDO?
//
// Start us even if no function driver or filter driver is found.
//
irpStack->Parameters.DeviceCapabilities.Capabilities->RawDeviceOK = TRUE;
//
// The instance ID's that we report are system wide unique.
//
// irpStack->Parameters.DeviceCapabilities.Capabilities->UniqueID = TRUE;
// - change to FALSE because we reuse names for LPTx.y during rescan
// when we detect that the daisy chain devices changed
//
irpStack->Parameters.DeviceCapabilities.Capabilities->UniqueID = FALSE;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoSkipCurrentIrpStackLocation(Irp);
status = ParCallDriver(fdoExt->ParentDeviceObject, Irp);
ParReleaseRemoveLock(&fdoExt->RemoveLock, Irp);
return status;
}
NTSTATUS
ParFdoParallelPnp (
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP pIrp
)
/*++
Routine Description:
This routine handles all PNP IRPs sent to the ParClass FDO.
We got here because !(Extension->IsPdo)
Arguments:
pDeviceObject - The ParClass FDO
pIrp - PNP Irp
Return Value:
STATUS_SUCCESS - if successful.
STATUS_UNSUCCESSFUL - otherwise.
--*/
{
NTSTATUS Status = STATUS_NOT_SUPPORTED;
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;
pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
Extension = pDeviceObject->DeviceExtension; // FDO Extension
{
NTSTATUS status = ParAcquireRemoveLock(&Extension->RemoveLock, pIrp);
if ( !NT_SUCCESS( status ) ) {
//
// Someone gave us a pnp irp after a remove. Unthinkable!
//
// ASSERT(FALSE);
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return status;
}
}
// dvdr
// pIrp->IoStatus.Information = 0;
switch (pIrpStack->MinorFunction) {
case IRP_MN_START_DEVICE:
return ParPnpFdoStartDevice(pDeviceObject, pIrp);
case IRP_MN_QUERY_CAPABILITIES:
ParDumpP( ("IRP_MN_QUERY_CAPABILITIES - FDO\n") );
pIrpStack->Parameters.DeviceCapabilities.Capabilities->RawDeviceOK = TRUE; // no Function Driver required
pIrpStack->Parameters.DeviceCapabilities.Capabilities->UniqueID = TRUE; // ID's reported are system wide unique
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation(pIrp);
ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
return ParCallDriver(Extension->ParentDeviceObject, pIrp);
case IRP_MN_QUERY_DEVICE_RELATIONS: {
ParDumpP( ("QUERY_DEVICE_RELATIONS - FDO\n") );
if(pIrpStack->Parameters.QueryDeviceRelations.Type != BusRelations) {
break; // bail out if we don't handle this query type
} else {
return ParPnpFdoQueryDeviceRelationsBusRelations(pDeviceObject, pIrp);
}
}
case IRP_MN_QUERY_STOP_DEVICE:
// always SUCCEED
ParDumpP( ( "QUERY_STOP_DEVICE - FDO\n") );
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation (pIrp);
ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
return ParCallDriver(Extension->ParentDeviceObject, pIrp);
case IRP_MN_CANCEL_STOP_DEVICE:
ParDumpP( ("CANCEL_STOP_DEVICE - FDO\n") );
// handle IRP synchronously:
// - set completion routine and event to wake on
// - pass IRP down the stack
// - our completion routine sets the event which wakes us
// - we wake on the event and regain control of
// the IRP on its way back up
// setup
IoCopyCurrentIrpStackLocationToNext(pIrp);
IoSetCompletionRoutine(pIrp, ParSynchCompletionRoutine, &Event, TRUE, TRUE, TRUE);
KeInitializeEvent(&Event, NotificationEvent, FALSE);
// pass IRP down the stack
Status = ParCallDriver(Extension->ParentDeviceObject, pIrp);
// wait for our completion routine to wake us up
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
// we have NOW regained control of the IRP on its way back up the stack
// extract "real" status from IRP if IoCallDriver returned PENDING
if (Status == STATUS_PENDING) {
Status = pIrp->IoStatus.Status;
}
// check if anyone below us in the stack failed the IRP
if ( !NT_SUCCESS(Status) && (Status != STATUS_NOT_SUPPORTED) ) {
ParDumpP( ("CANCEL_STOP_DEVICE failed at parent, Status= %x\n", Status) );
break;
}
// SUCCESS
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
return STATUS_SUCCESS;
case IRP_MN_STOP_DEVICE:
// always SUCCEED
ParDumpP( ("STOP_DEVICE - FDO\n") );
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation (pIrp);
ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
return ParCallDriver(Extension->ParentDeviceObject, pIrp);
case IRP_MN_QUERY_REMOVE_DEVICE:
// SUCCEED if no PODOs (i.e., no parallel ports), FAIL otherwise
if( Extension->ParClassPdo ) {
ParDumpP( ("QUERY_REMOVE_DEVICE - FDO - FAIL - Legacy PODOs may be using Ports\n") );
pIrp->IoStatus.Status = STATUS_DEVICE_BUSY;
ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
ParCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_DEVICE_BUSY;
} else {
ParDumpP( ("QUERY_REMOVE_DEVICE - FDO - SUCCESS - no ParPorts exist\n") );
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation (pIrp);
ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
return ParCallDriver(Extension->ParentDeviceObject, pIrp);
}
case IRP_MN_CANCEL_REMOVE_DEVICE:
ParDumpP( ( "CANCEL_REMOVE_DEVICE - FDO\n") );
// handle IRP synchronously:
// - set completion routine and event to wake on
// - pass IRP down the stack
// - our completion routine sets the event which wakes us
// - we wake on the event and regain control of
// the IRP on its way back up
// setup
IoCopyCurrentIrpStackLocationToNext(pIrp);
IoSetCompletionRoutine(pIrp, ParSynchCompletionRoutine, &Event, TRUE, TRUE, TRUE);
KeInitializeEvent(&Event, NotificationEvent, FALSE);
// pass IRP down the stack
Status = ParCallDriver(Extension->ParentDeviceObject, pIrp);
// wait for our completion routine to wake us up
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
// we have NOW regained control of the IRP on its way back up the stack
// extract "real" status from IRP if IoCallDriver returned PENDING
if (Status == STATUS_PENDING) {
Status = pIrp->IoStatus.Status;
}
// check if anyone below us in the stack failed the IRP
if (!NT_SUCCESS(Status)) {
ParDumpP( ("CANCEL_REMOVE_DEVICE FAILED, Status = %x\n", Status) );
break;
}
// SUCCESS
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
return STATUS_SUCCESS;
case IRP_MN_REMOVE_DEVICE:
ParDumpP( ("REMOVE_DEVICE - FDO\n") );
Extension->DeviceStateFlags |= PAR_DEVICE_REMOVED;
if(Extension->NotificationHandle) {
IoUnregisterPlugPlayNotification (Extension->NotificationHandle);
Extension->NotificationHandle = 0;
}
if( Extension->HwProfileChangeNotificationHandle ) {
IoUnregisterPlugPlayNotification( Extension->HwProfileChangeNotificationHandle );
Extension->HwProfileChangeNotificationHandle = 0;
}
IoSkipCurrentIrpStackLocation(pIrp);
pIrp->IoStatus.Status = STATUS_SUCCESS;
Status = ParCallDriver(Extension->ParentDeviceObject, pIrp);
ParReleaseRemoveLockAndWait(&Extension->RemoveLock, pIrp);
IoDetachDevice(Extension->ParentDeviceObject);
if (Extension->ClassName.Buffer) {
ExFreePool(Extension->ClassName.Buffer);
}
//
// walk the list of remaining ParClass ejected device objects and kill them
//
{
PDEVICE_OBJECT current;
PDEVICE_EXTENSION FdoExtension = Extension; // fix alanmo discovered bug from machine where parport not started
ExAcquireFastMutex(&FdoExtension->DevObjListMutex);
current = Extension->ParClassPdo;
while(current) {
PDEVICE_OBJECT next = ( (PDEVICE_EXTENSION)(current->DeviceExtension) )->Next;
ParKillDeviceObject(current);
current = next;
}
ExReleaseFastMutex(&FdoExtension->DevObjListMutex);
}
Extension->DeviceStateFlags |= PAR_DEVICE_DELETED;
IoDeleteDevice(pDeviceObject);
return Status;
case IRP_MN_SURPRISE_REMOVAL:
// ParClass FDO is root enumerated - we should never get this IRP
ParDumpP( ("IRP_MN_SURPRISE_REMOVAL - FDO - We are not supposed to get this IRP!!!\n") );
// fall through into default case since we don't handle this
default:
// We don't handle this request, simply pass it down the stack
ParDumpP( ("Unhandled PNP IRP: %x - FDO\n", pIrpStack->MinorFunction) );
IoSkipCurrentIrpStackLocation(pIrp);
ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
return ParCallDriver(Extension->ParentDeviceObject, pIrp);
}
//
// Set the return code only if we have something to add.
//
if( Status != STATUS_NOT_SUPPORTED ) {
pIrp->IoStatus.Status = Status ;
}
//
// Complete immediately if we have failed the Irp for any reason other
// than STATUS_NOT_SUPPORTED. Otherwise, pass down.
//
if( NT_SUCCESS(Status) || (Status == STATUS_NOT_SUPPORTED) ) {
IoSkipCurrentIrpStackLocation(pIrp);
ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
return ParCallDriver(Extension->ParentDeviceObject, pIrp);
}
//
// Complete the IRP...
//
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
ParReleaseRemoveLock(&Extension->RemoveLock, pIrp);
return Status;
}
NTSTATUS
ParPnpAddDevice(
IN PDRIVER_OBJECT pDriverObject,
IN PDEVICE_OBJECT pPhysicalDeviceObject
)
/*++
Routine Description:
This routine is the ParClass AddDevice routine.
This routine creates the ParClass FDO and attaches it to the device stack
Arguments:
pDriverObject - pointer to the driver object for this instance of parport.
pPhysicalDeviceObject - pointer to the device object that represents the port.
Return Value:
STATUS_SUCCESS - if successful.
!STATUS_SUCCESS - otherwise.
--*/
{
PDEVICE_OBJECT pDeviceObject;
PDEVICE_EXTENSION Extension;
NTSTATUS Status;
ParBreak(PAR_BREAK_ON_ADD_DEVICE, ("ParPnpAddDevice(PDRIVER_OBJECT, PDEVICE_OBJECT)\n") );
//
// Create the device object for this device.
//
Status = ParCreateDevice(pDriverObject, sizeof(DEVICE_EXTENSION), NULL,
FILE_DEVICE_PARALLEL_PORT, 0, TRUE, &pDeviceObject);
if (!NT_SUCCESS(Status)) {
ParLogError(pDriverObject, NULL, PhysicalZero, PhysicalZero, 0, 0, 0, 9, STATUS_SUCCESS, Status);
ParDump(PARERRORS, ("PARALLEL: Could not create a Device Object for FDO\n") );
return Status;
}
//
// Setup buffered I/O
//
pDeviceObject->Flags |= DO_BUFFERED_IO;
Extension = pDeviceObject->DeviceExtension;
RtlZeroMemory(Extension, sizeof(DEVICE_EXTENSION));
Extension->DeviceType = PAR_DEVTYPE_FDO;
ExInitializeFastMutex(&Extension->OpenCloseMutex);
ExInitializeFastMutex(&Extension->DevObjListMutex); // only FDO has this Mutex
IoInitializeRemoveLock(&Extension->RemoveLock, PARCLASS_POOL_TAG, 1, 10);
Extension->ExtensionSignature = PARCLASS_EXTENSION_SIGNATURE;
Extension->ExtensionSignatureEnd = PARCLASS_EXTENSION_SIGNATURE;
Extension->DeviceObject = pDeviceObject;
//
// Attach our new Device to our parent's stack.
//
Extension->ParentDeviceObject = IoAttachDeviceToDeviceStack( pDeviceObject, pPhysicalDeviceObject);
ParDumpV( ("ParPnpAddDevice(...): "
"pDeviceObject= %08x , Extension= %08x , ParentDeviceObject= %08x\n",
pDeviceObject, Extension, Extension->ParentDeviceObject) );
if (NULL == Extension->ParentDeviceObject) {
ParDump2(PARERRORS, ("ParPnpAddDevice(...): IoAttachDeviceToDeviceStack FAILED\n") );
IoDeleteDevice(pDeviceObject);
return STATUS_UNSUCCESSFUL;
}
//
// Done initializing
//
Extension->PhysicalDeviceObject = pPhysicalDeviceObject;
pDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
}