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