/*++ Copyright (c) 1998 Microsoft Corporation Module Name: pnp.c Abstract: This module contains the code for a serial imaging devices driver supporting PnP functionality Author: Vlad Sadovsky vlads 10-April-1998 Environment: Kernel mode Revision History : vlads 04/10/1998 Created first draft --*/ #include "serscan.h" #include "serlog.h" //#include extern ULONG SerScanDebugLevel; extern const PHYSICAL_ADDRESS PhysicalZero ; #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, SerScanPnp) #pragma alloc_text(PAGE, SerScanPower) #endif NTSTATUS SerScanPnp ( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) /*++ Routine Description: This routine handles all PNP IRPs, dispatching them as appropriate . Arguments: pDeviceObject - represents a device pIrp - PNP Irp Return Value: STATUS_SUCCESS - if successful. STATUS_UNSUCCESSFUL - otherwise. --*/ { NTSTATUS Status ; PDEVICE_EXTENSION Extension; PIO_STACK_LOCATION pIrpStack; PVOID pObject; ULONG NewReferenceCount; NTSTATUS ReturnStatus; pIrpStack = IoGetCurrentIrpStackLocation( pIrp ); Extension = pDeviceObject->DeviceExtension; Status = STATUS_SUCCESS; DebugDump(SERINITDEV,("Entering PnP Dispatcher\n")); switch (pIrpStack->MinorFunction) { case IRP_MN_START_DEVICE: // // Initialize PendingIoEvent. Set the number of pending i/o requests for this device to 1. // When this number falls to zero, it is okay to remove, or stop the device. // DebugDump(SERINITDEV,("Entering Start Device \n")); KeInitializeEvent(&Extension -> PdoStartEvent, SynchronizationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext(pIrp); Status = WaitForLowerDriverToCompleteIrp( Extension->LowerDevice, pIrp, &Extension->PdoStartEvent); if (!NT_SUCCESS(Status)) { pIrp->IoStatus.Status = Status; pIrp->IoStatus.Information = 0; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return (Status); } #ifdef CREATE_SYMBOLIC_NAME // // Now setup the symbolic link for windows. // Status = IoCreateUnprotectedSymbolicLink(&Extension->SymbolicLinkName, &Extension->ClassName); if (NT_SUCCESS(Status)) { // We were able to create the symbolic link, so record this // value in the extension for cleanup at unload time. Extension->CreatedSymbolicLink = TRUE; // Write out the result of the symbolic link to the registry. Status = RtlWriteRegistryValue(RTL_REGISTRY_DEVICEMAP, L"Serial Scanners", Extension->ClassName.Buffer, REG_SZ, Extension->SymbolicLinkName.Buffer, Extension->SymbolicLinkName.Length + sizeof(WCHAR)); if (!NT_SUCCESS(Status)) { // // It didn't work. Just go to cleanup. // DebugDump(SERERRORS, ("SerScan: Couldn't create the device map entry\n" "-------- for port %wZ\n", &Extension->ClassName)); SerScanLogError(pDeviceObject->DriverObject, pDeviceObject, PhysicalZero, PhysicalZero, 0, 0, 0, 6, Status, SER_NO_DEVICE_MAP_CREATED); } } else { // // Couldn't create the symbolic link. // Extension->CreatedSymbolicLink = FALSE; ExFreePool(Extension->SymbolicLinkName.Buffer); Extension->SymbolicLinkName.Buffer = NULL; DebugDump(SERERRORS, ("SerScan: Couldn't create the symbolic link\n" "-------- for port %wZ\n", &Extension->ClassName)); SerScanLogError(pDeviceObject->DriverObject, pDeviceObject, PhysicalZero, PhysicalZero, 0, 0, 0, 5, Status, SER_NO_SYMLINK_CREATED); } #endif ExFreePool(Extension->ClassName.Buffer); Extension->ClassName.Buffer = NULL; // // Ignore status of link registry write - always succeed // // // Clear InInit flag to indicate device object can be used // pDeviceObject->Flags &= ~(DO_DEVICE_INITIALIZING); pIrp->IoStatus.Status = Status; pIrp->IoStatus.Information = 0; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return (Status); break; case IRP_MN_QUERY_REMOVE_DEVICE: // // Always pass to lower device in stack after indicating that we don't object // DebugDump(SERALWAYS,("IRP_MN_QUERY_REMOVE_DEVICE\n")); Extension->Removing = TRUE; IoCopyCurrentIrpStackLocationToNext( pIrp ); return (IoCallDriver(Extension->LowerDevice, pIrp)); break; case IRP_MN_CANCEL_REMOVE_DEVICE: // // Always pass to lower device in stack , reset indicator as somebody canceled // DebugDump(SERALWAYS,("IRP_MN_CANCEL_REMOVE_DEVICE\n")); Extension->Removing = FALSE; // // Kill symbolic link // if (Extension->CreatedSymbolicLink) { IoDeleteSymbolicLink(&Extension->SymbolicLinkName); Extension->CreatedSymbolicLink = FALSE; } IoCopyCurrentIrpStackLocationToNext( pIrp ); return (IoCallDriver(Extension->LowerDevice, pIrp)); break; case IRP_MN_SURPRISE_REMOVAL: // // Should not ever happen with us, but still process // DebugDump(SERALWAYS,("IRP_MN_SURPRISE_REMOVAL\n")); Extension->Removing = TRUE; // // Get rid of the symbolic link // SerScanHandleSymbolicLink( Extension->Pdo, &Extension->InterfaceNameString, FALSE ); #ifdef USE_EXECUTIVE_RESOURCE ExAcquireResourceExclusiveLite( &Extension->Resource, TRUE ); #else ExAcquireFastMutex(&Extension->Mutex); #endif pObject = InterlockedExchangePointer(&Extension->AttachedFileObject,NULL); if (pObject) { ObDereferenceObject(pObject); } pObject = InterlockedExchangePointer(&Extension->AttachedDeviceObject,NULL); if (pObject) { ObDereferenceObject(pObject); } #ifdef USE_EXECUTIVE_RESOURCE ExReleaseResourceLite(&Extension->Resource); #else ExReleaseFastMutex(&Extension->Mutex); #endif IoCopyCurrentIrpStackLocationToNext( pIrp ); return (IoCallDriver(Extension->LowerDevice, pIrp)); break; case IRP_MN_REMOVE_DEVICE: DebugDump(SERALWAYS,("IRP_MN_REMOVE_DEVICE\n")); DebugDump(SERINITDEV,("Entering PnP Remove Device\n")); // // Stop new requests - device is being removed // Extension->Removing = TRUE; // // Get rid of the symbolic link // SerScanHandleSymbolicLink( Extension->Pdo, &Extension->InterfaceNameString, FALSE ); #ifdef USE_EXECUTIVE_RESOURCE ExAcquireResourceExclusiveLite( &Extension->Resource, TRUE ); #else ExAcquireFastMutex(&Extension->Mutex); #endif pObject = InterlockedExchangePointer(&Extension->AttachedFileObject,NULL); if (pObject) { ObDereferenceObject(pObject); } pObject = InterlockedExchangePointer(&Extension->AttachedDeviceObject,NULL); if (pObject) { ObDereferenceObject(pObject); } #ifdef USE_EXECUTIVE_RESOURCE ExReleaseResourceLite(&Extension->Resource); #else ExReleaseFastMutex(&Extension->Mutex); #endif // // Send IRP down to lower device // IoCopyCurrentIrpStackLocationToNext( pIrp ); ReturnStatus = IoCallDriver(Extension->LowerDevice, pIrp); // // Decrement ref count // NewReferenceCount = InterlockedDecrement(&Extension->ReferenceCount); if (NewReferenceCount != 0) { // // Wait for any io requests pending in our driver to // complete before finishing the remove // KeWaitForSingleObject(&Extension -> RemoveEvent, Suspended, KernelMode, FALSE, NULL); } // ASSERT(&Extension->ReferenceCount == 0); #ifdef USE_EXECUTIVE_RESOURCE ExDeleteResourceLite(&Extension->Resource); #endif DebugDump(SERALWAYS,("IRP_MN_QUERY_REMOVE_DEVICE - Calling IoDeleteDevice - gone\n")); IoDetachDevice(Extension->LowerDevice); // // Free allocated resource. // if(NULL != Extension->ClassName.Buffer){ ExFreePool(Extension->ClassName.Buffer); } // if(NULL != Extension->ClassName.Buffer) if(NULL != Extension->SymbolicLinkName.Buffer){ ExFreePool(Extension->SymbolicLinkName.Buffer); } // if(NULL != Extension->SymbolicLinkName.Buffer) IoDeleteDevice(pDeviceObject); return ReturnStatus; break; case IRP_MN_STOP_DEVICE: // // Pass down // DebugDump(SERALWAYS,("IRP_MN_STOP_DEVICE\n")); IoCopyCurrentIrpStackLocationToNext( pIrp ); return (IoCallDriver(Extension->LowerDevice, pIrp)); break; case IRP_MN_QUERY_STOP_DEVICE: // // Check open counts // DebugDump(SERALWAYS,("IRP_MN_QUERY_STOP_DEVICE\n")); if (Extension->OpenCount > 0 ) { DebugDump(SERALWAYS,("Rejecting QUERY_STOP_DEVICE\n")); pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return STATUS_UNSUCCESSFUL; } IoCopyCurrentIrpStackLocationToNext( pIrp ); return (IoCallDriver(Extension->LowerDevice, pIrp)); break; case IRP_MN_CANCEL_STOP_DEVICE: // // Nothing to do here, but pass to lower // DebugDump(SERALWAYS,("IRP_MN_CANCEL_STOP_DEVICE\n")); IoCopyCurrentIrpStackLocationToNext( pIrp ); return (IoCallDriver(Extension->LowerDevice, pIrp)); break; case IRP_MN_QUERY_CAPABILITIES: { ULONG i; KEVENT WaitEvent; // // Send this down to the PDO first // KeInitializeEvent(&WaitEvent, SynchronizationEvent, FALSE); IoCopyCurrentIrpStackLocationToNext(pIrp); Status=WaitForLowerDriverToCompleteIrp( Extension->LowerDevice, pIrp, &WaitEvent ); pIrpStack = IoGetCurrentIrpStackLocation(pIrp); for (i = PowerSystemUnspecified; i < PowerSystemMaximum; i++) { Extension->SystemPowerStateMap[i]=PowerDeviceD3; } for (i = PowerSystemUnspecified; i < PowerSystemHibernate; i++) { Extension->SystemPowerStateMap[i]=pIrpStack->Parameters.DeviceCapabilities.Capabilities->DeviceState[i]; } Extension->SystemPowerStateMap[PowerSystemWorking]=PowerDeviceD0; Extension->SystemWake=pIrpStack->Parameters.DeviceCapabilities.Capabilities->SystemWake; Extension->DeviceWake=pIrpStack->Parameters.DeviceCapabilities.Capabilities->DeviceWake; IoCompleteRequest( pIrp, IO_NO_INCREMENT ); return Status; } break; default: // // Unknown function - pass down // DebugDump(SERALWAYS,("Passing Pnp Irp down. MnFunc=%x , status = %x\n",pIrpStack->MinorFunction, Status)); IoCopyCurrentIrpStackLocationToNext( pIrp ); return (IoCallDriver(Extension->LowerDevice, pIrp)); break; } // // Complete the IRP... // if (!NT_SUCCESS(Status)) { pIrp -> IoStatus.Status = Status; pIrp->IoStatus.Information = 0; IoCompleteRequest( pIrp, IO_NO_INCREMENT ); } else { DebugDump(SERALWAYS,("Passing Pnp Irp down, status = %x\n", Status)); IoCopyCurrentIrpStackLocationToNext(pIrp); Status = IoCallDriver(Extension->LowerDevice, pIrp); } return( Status ); } VOID DevicePowerCompleteRoutine( PDEVICE_OBJECT DeviceObject, IN UCHAR MinorFunction, IN POWER_STATE PowerState, IN PVOID Context, IN PIO_STATUS_BLOCK IoStatus ) { return; } NTSTATUS SerScanPower( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ) /*++ Routine Description: Process the Power IRPs sent to the PDO for this device. Arguments: pDeviceObject - pointer to the functional device object (FDO) for this device. pIrp - pointer to an I/O Request Packet Return Value: NT status code --*/ { NTSTATUS Status; PDEVICE_EXTENSION Extension = pDeviceObject->DeviceExtension; PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp); POWER_STATE PowerState; PAGED_CODE(); Status = STATUS_SUCCESS; switch (pIrpStack->MinorFunction) { case IRP_MN_SET_POWER: if (pIrpStack->Parameters.Power.Type == SystemPowerState) { // // system power state change // // // request the change in device power state based on systemstate map // PowerState.DeviceState=Extension->SystemPowerStateMap[pIrpStack->Parameters.Power.State.SystemState]; PoRequestPowerIrp( Extension->Pdo, IRP_MN_SET_POWER, PowerState, DevicePowerCompleteRoutine, pIrp, NULL ); } else { // // changing device state // PoSetPowerState( Extension->Pdo, pIrpStack->Parameters.Power.Type, pIrpStack->Parameters.Power.State ); } break; case IRP_MN_QUERY_POWER: pIrp->IoStatus.Status = STATUS_SUCCESS; break; default: break; } PoStartNextPowerIrp(pIrp); IoSkipCurrentIrpStackLocation(pIrp); Status=PoCallDriver(Extension->LowerDevice, pIrp); return Status; }