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