/*************************************************************************** Copyright (c) 2000 Microsoft Corporation Module Name: Dot4Usb.sys - Lower Filter Driver for Dot4.sys for USB connected IEEE 1284.4 devices. File Name: PnP.c Abstract: Plug and Play routines Environment: Kernel mode only Notes: THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. Copyright (c) 2000 Microsoft Corporation. All Rights Reserved. Revision History: 01/18/2000 : created ToDo in this file: - function cleanup and documentation - code review Author(s): Joby Lafky (JobyL) Doug Fritz (DFritz) ****************************************************************************/ #include "pch.h" NTSTATUS (*PnpDispatchTable[])(PDEVICE_EXTENSION,PIRP) = { PnpHandleStart, // IRP_MN_START_DEVICE 0x00 PnpHandleQueryRemove, // IRP_MN_QUERY_REMOVE_DEVICE 0x01 PnpHandleRemove, // IRP_MN_REMOVE_DEVICE 0x02 PnpHandleCancelRemove, // IRP_MN_CANCEL_REMOVE_DEVICE 0x03 PnpHandleStop, // IRP_MN_STOP_DEVICE 0x04 PnpHandleQueryStop, // IRP_MN_QUERY_STOP_DEVICE 0x05 PnpHandleCancelStop, // IRP_MN_CANCEL_STOP_DEVICE 0x06 PnpHandleQueryDeviceRelations,// IRP_MN_QUERY_DEVICE_RELATIONS 0x07 PnpDefaultHandler, // IRP_MN_QUERY_INTERFACE 0x08 PnpHandleQueryCapabilities, // IRP_MN_QUERY_CAPABILITIES 0x09 PnpDefaultHandler, // IRP_MN_QUERY_RESOURCES 0x0A PnpDefaultHandler, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS 0x0B PnpDefaultHandler, // IRP_MN_QUERY_DEVICE_TEXT 0x0C PnpDefaultHandler, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS 0x0D PnpDefaultHandler, // no defined IRP MN code 0x0E PnpDefaultHandler, // IRP_MN_READ_CONFIG 0x0F PnpDefaultHandler, // IRP_MN_WRITE_CONFIG 0x10 PnpDefaultHandler, // IRP_MN_EJECT 0x11 PnpDefaultHandler, // IRP_MN_SET_LOCK 0x12 PnpDefaultHandler, // IRP_MN_QUERY_ID 0x13 PnpDefaultHandler, // IRP_MN_QUERY_PNP_DEVICE_STATE 0x14 PnpDefaultHandler, // IRP_MN_QUERY_BUS_INFORMATION 0x15 PnpDefaultHandler, // IRP_MN_DEVICE_USAGE_NOTIFICATION 0x16 PnpHandleSurpriseRemoval, // IRP_MN_SURPRISE_REMOVAL 0x17 }; /************************************************************************/ /* DispatchPnp */ /************************************************************************/ // // Routine Description: // // Dispatch routine for IRP_MJ_PNP IRPs. Redirect IRPs to appropriate // handlers using the IRP_MN_* value as the key. // // Arguments: // // DevObj - pointer to DEVICE_OBJECT that is the target of the request // Irp - pointer to IRP // // Return Value: // // NTSTATUS // // Log: // 2000-05-03 Code Reviewed - TomGreen, JobyL, DFritz // /************************************************************************/ NTSTATUS DispatchPnp( IN PDEVICE_OBJECT DevObj, IN PIRP Irp ) { PDEVICE_EXTENSION devExt = DevObj->DeviceExtension; NTSTATUS status = IoAcquireRemoveLock( &devExt->RemoveLock , Irp ); if( NT_SUCCESS( status ) ) { // Acquire RemoveLock succeeded PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp ); ULONG minorFunc = irpSp->MinorFunction; TR_VERBOSE(("DispatchPnp - RemoveLock acquired - DevObj= %x , Irp= %x", DevObj, Irp)); // // Call appropriate handler based on PnP IRP_MN_xxx code // // note: Handler will complete the IRP // if( minorFunc >= arraysize(PnpDispatchTable) ) { status = PnpDefaultHandler( devExt, Irp ); } else { status = PnpDispatchTable[ minorFunc ]( devExt, Irp ); } } else { // Acquire RemoveLock failed TR_FAIL(("DispatchPnp - RemoveLock acquire FAILED - DevObj= %x , Irp= %x", DevObj, Irp)); Irp->IoStatus.Status = status; IoCompleteRequest( Irp, IO_NO_INCREMENT ); } return status; } /************************************************************************/ /* PnpDefaultHandler */ /************************************************************************/ // // Routine Description: // // Default handler for PnP IRPs that this driver does not explicitly handle. // // Arguments: // // DevExt - pointer to DEVICE_EXTENSION of the DEVICE_OBJECT that is // the target of the request // Irp - pointer to IRP // // Return Value: // // NTSTATUS returned by IoCallDriver // // Log: // 2000-05-03 Code Reviewed - TomGreen, JobyL, DFritz // /************************************************************************/ NTSTATUS PnpDefaultHandler( IN PDEVICE_EXTENSION DevExt, IN PIRP Irp ) { NTSTATUS status; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp ); TR_ENTER(("PnpDefaultHandler - IRP_MN = 0x%02x", irpSp->MinorFunction)); IoSkipCurrentIrpStackLocation( Irp ); status = IoCallDriver( DevExt->LowerDevObj, Irp ); IoReleaseRemoveLock( &DevExt->RemoveLock, Irp ); return status; } /************************************************************************/ /* PnpHandleStart */ /************************************************************************/ // // Routine Description: // // Handler for PnP IRP_MN_START_DEVICE. // // Arguments: // // DevExt - pointer to DEVICE_EXTENSION of the DEVICE_OBJECT that is // the target of the request // Irp - pointer to IRP // // Return Value: // // NTSTATUS // // Log: // 2000-05-03 - Code Reviewed - TomGreen, JobyL, DFritz // - cleanup required - error handling incorrect, may // result in driver attempting to use invalid and/or // uninitialized data // /************************************************************************/ NTSTATUS PnpHandleStart( IN PDEVICE_EXTENSION DevExt, IN PIRP Irp ) { NTSTATUS status; TR_ENTER(("PnpHandleStart")); DevExt->PnpState = STATE_STARTING; // // Driver stack below us must successfully start before we handle the Start IRP // Irp->IoStatus.Status = STATUS_SUCCESS; IoCopyCurrentIrpStackLocationToNext( Irp ); status = CallLowerDriverSync( DevExt->DevObj, Irp ); if( NT_SUCCESS(status) ) { // // Driver stack below us has successfully started, continue // // // Get a copy of the DEVICE_CAPABILITIES of the stack us and // save it in our DEVICE_EXTENSION for future reference. // status = GetDeviceCapabilities( DevExt ); if( NT_SUCCESS(status) ) { // get USB descriptor status = UsbGetDescriptor( DevExt ); if( !NT_SUCCESS(status) ) { TR_VERBOSE(("call to UsbGetDescriptor FAILED w/status = %x",status)); status = STATUS_SUCCESS; // start anyway } else { TR_VERBOSE(("call to UsbGetDescriptor - SUCCESS")); } // Configure Device status = UsbConfigureDevice( DevExt ); if( !NT_SUCCESS(status) ) { TR_VERBOSE(("call to UsbConfigureDevice FAILED w/status = %x",status)); status = STATUS_SUCCESS; // start anyway } else { TR_VERBOSE(("call to UsbConfigureDevice - SUCCESS")); } // get 1284 ID - just for kicks :-) { UCHAR Buffer[256]; LONG retCode; RtlZeroMemory(Buffer, sizeof(Buffer)); retCode = UsbGet1284Id(DevExt->DevObj, Buffer, sizeof(Buffer)-1); TR_VERBOSE(("retCode = %d",retCode)); TR_VERBOSE(("strlen = %d", strlen((PCSTR)&Buffer[2]))); TR_VERBOSE(("1284ID = <%s>",&Buffer[2])); } // get Pipes UsbBuildPipeList( DevExt->DevObj ); // we are now STARTED DevExt->PnpState = STATE_STARTED; } else { DevExt->PnpState = STATE_START_FAILED; } } else { // // Driver stack below us has FAILED the Start, we fail too // DevExt->PnpState = STATE_START_FAILED; } Irp->IoStatus.Status = status; IoCompleteRequest( Irp, IO_NO_INCREMENT ); IoReleaseRemoveLock( &DevExt->RemoveLock, Irp ); return status; } NTSTATUS PnpHandleQueryRemove( IN PDEVICE_EXTENSION DevExt, IN PIRP Irp ) { NTSTATUS status; TR_ENTER(("PnpHandleQueryRemove")); IoSkipCurrentIrpStackLocation( Irp ); status = IoCallDriver( DevExt->LowerDevObj, Irp ); IoReleaseRemoveLock( &DevExt->RemoveLock, Irp ); return status; } NTSTATUS PnpHandleRemove( IN PDEVICE_EXTENSION DevExt, IN PIRP Irp ) { NTSTATUS status; KIRQL oldIrql; TR_ENTER(("PnpHandleRemove")); DevExt->PnpState = STATE_REMOVED; UsbStopReadInterruptPipeLoop( DevExt->DevObj ); // stop polling Irp if any IoSkipCurrentIrpStackLocation( Irp ); status = IoCallDriver( DevExt->LowerDevObj, Irp); TR_TMP1(("PnpHandleRemove - Calling IoReleaseRemoveLockAndWait")); IoReleaseRemoveLockAndWait( &DevExt->RemoveLock, Irp ); TR_TMP1(("PnpHandleRemove - Returned from IoReleaseRemoveLockAndWait")); IoDetachDevice( DevExt->LowerDevObj ); // BUGBUG - verify that code in rest of driver that touches Interface // locks the extension while using it to prevent this function from // freeing the interface out from under them causing an AV KeAcquireSpinLock( &DevExt->SpinLock, &oldIrql ); if( DevExt->Interface ) { PVOID ptr = DevExt->Interface; DevExt->Interface = NULL; KeReleaseSpinLock( &DevExt->SpinLock, oldIrql ); ExFreePool( ptr ); } else { KeReleaseSpinLock( &DevExt->SpinLock, oldIrql ); } IoDeleteDevice( DevExt->DevObj ); return status; } NTSTATUS PnpHandleCancelRemove( IN PDEVICE_EXTENSION DevExt, IN PIRP Irp ) { NTSTATUS status; TR_ENTER(("PnpHandleCancelRemove")); IoSkipCurrentIrpStackLocation( Irp ); status = IoCallDriver( DevExt->LowerDevObj, Irp ); IoReleaseRemoveLock( &DevExt->RemoveLock, Irp ); return status; } NTSTATUS PnpHandleStop( IN PDEVICE_EXTENSION DevExt, IN PIRP Irp ) { NTSTATUS status; TR_ENTER(("PnpHandleStop")); if( DevExt->PnpState == STATE_STARTED ) { DevExt->PnpState = STATE_STOPPED; } IoSkipCurrentIrpStackLocation( Irp ); status = IoCallDriver( DevExt->LowerDevObj, Irp ); IoReleaseRemoveLock( &DevExt->RemoveLock, Irp ); return status; } NTSTATUS PnpHandleQueryStop( IN PDEVICE_EXTENSION DevExt, IN PIRP Irp ) { NTSTATUS status; TR_ENTER(("PnpHandleQueryStop")); Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation( Irp ); status = IoCallDriver( DevExt->LowerDevObj, Irp ); IoReleaseRemoveLock( &DevExt->RemoveLock, Irp ); return status; } NTSTATUS PnpHandleCancelStop( IN PDEVICE_EXTENSION DevExt, IN PIRP Irp ) { NTSTATUS status; TR_ENTER(("PnpHandleStop")); IoSkipCurrentIrpStackLocation( Irp ); status = IoCallDriver( DevExt->LowerDevObj, Irp ); IoReleaseRemoveLock( &DevExt->RemoveLock, Irp ); return status; } NTSTATUS PnpHandleQueryDeviceRelations( IN PDEVICE_EXTENSION DevExt, IN PIRP Irp ) { NTSTATUS status; TR_ENTER(("PnpHandleQueryDeviceRelations")); IoSkipCurrentIrpStackLocation( Irp ); status = IoCallDriver( DevExt->LowerDevObj, Irp ); IoReleaseRemoveLock( &DevExt->RemoveLock, Irp ); return status; } NTSTATUS PnpHandleQueryCapabilities( IN PDEVICE_EXTENSION DevExt, IN PIRP Irp ) { NTSTATUS status; TR_ENTER(("PnpHandleQueryCapabilities")); IoCopyCurrentIrpStackLocationToNext( Irp ); status = CallLowerDriverSync( DevExt->DevObj, Irp ); if( NT_SUCCESS( status ) ) { PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp ); irpSp->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE; } IoCompleteRequest( Irp, IO_NO_INCREMENT ); IoReleaseRemoveLock( &DevExt->RemoveLock, Irp ); return status; } NTSTATUS PnpHandleSurpriseRemoval( IN PDEVICE_EXTENSION DevExt, IN PIRP Irp ) { NTSTATUS status; TR_ENTER(("PnpHandleSurpriseRemoval")); DevExt->PnpState = STATE_REMOVING; TR_TMP1(("PnpHandleSurpriseRemoval")); UsbStopReadInterruptPipeLoop( DevExt->DevObj ); // stop polling Irp if any IoSkipCurrentIrpStackLocation( Irp ); status = IoCallDriver( DevExt->LowerDevObj, Irp ); IoReleaseRemoveLock( &DevExt->RemoveLock, Irp ); return status; } NTSTATUS GetDeviceCapabilities( IN PDEVICE_EXTENSION DevExt ) { NTSTATUS status; PIRP irp = IoAllocateIrp(DevExt->LowerDevObj->StackSize, FALSE); if( irp ) { PIO_STACK_LOCATION irpSp = IoGetNextIrpStackLocation( irp ); // must initialize DeviceCapabilities before sending... RtlZeroMemory( &DevExt->DeviceCapabilities, sizeof(DEVICE_CAPABILITIES) ); DevExt->DeviceCapabilities.Size = sizeof(DEVICE_CAPABILITIES); DevExt->DeviceCapabilities.Version = 1; DevExt->DeviceCapabilities.Address = (ULONG) -1; DevExt->DeviceCapabilities.UINumber = (ULONG) -1; // set up next irp stack location... irpSp->MajorFunction = IRP_MJ_PNP; irpSp->MinorFunction = IRP_MN_QUERY_CAPABILITIES; irpSp->Parameters.DeviceCapabilities.Capabilities = &DevExt->DeviceCapabilities; // required initial status irp->IoStatus.Status = STATUS_NOT_SUPPORTED; status = IoAcquireRemoveLock( &DevExt->RemoveLock, irp ); if( NT_SUCCESS(status) ) { status = CallLowerDriverSync( DevExt->DevObj, irp ); IoReleaseRemoveLock( &DevExt->RemoveLock, irp ); } else { TR_VERBOSE(("We're in the process of being removed - abort")); status = STATUS_DELETE_PENDING; } IoFreeIrp( irp ); } else { status = STATUS_INSUFFICIENT_RESOURCES; } return status; }