www.pudn.com > VSer.rar > pnp.c


/*++ 
 
Copyright (c) 2005  Changzhi Zhou All Rights Reserved 
 
Module Name: 
 
    pnp.c 
 
Abstract: 
 
    This module works for the handles Plug&Play dispatch. 
 
Environment: 
 
    Kernel mode 
 
Revision History: 
	Changzhi Zhou Dec 20  2004 
 
--*/ 
#include  
#include  
#include "main.h" 
#include "tdiclient.h" 
#include "..\inc\wdmioctl.h" 
 
NTSTATUS 
SamplePnpDispatch ( 
    IN PDEVICE_OBJECT DeviceObject, 
    IN PIRP Irp 
    ) 
/*++ 
 
Routine Description: 
 
    The plug and play dispatch routines. 
 
    Most of these the driver will completely ignore. 
    In all cases it must pass on the IRP to the lower driver. 
 
Arguments: 
 
   DeviceObject - pointer to a device object. 
 
   Irp - pointer to an I/O Request Packet. 
 
Return Value: 
 
      NT status code 
 
--*/ 
{ 
    PDEVICE_EXTENSION   deviceExtension; 
    PIO_STACK_LOCATION  irpStack; 
    NTSTATUS            status; 
    KEVENT              event; 
	KIRQL				oldIrql; 
 
    PAGED_CODE(); 
 
    deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; 
	irpStack = IoGetCurrentIrpStackLocation(Irp); 
    DebugPrint(("Sample %s IRP:0x%x \n", PnPMinorFunctionString(irpStack->MinorFunction), Irp)); 
 
	if ( Removed == deviceExtension->DevicePnPState) { 
        status = STATUS_DELETE_PENDING; 
		return CompleteRequest(Irp, status, 0 ); 
    } 
	status = STATUS_SUCCESS; 
	SampleIoIncrement( deviceExtension ); 
     
    switch (irpStack->MinorFunction) { 
    case IRP_MN_START_DEVICE: 
		status = PnpStartDevice( DeviceObject, Irp); 
		break; 
    case IRP_MN_QUERY_STOP_DEVICE: 
		status = PnpQueryStopDevice( DeviceObject, Irp ); 
		return status; 
    case IRP_MN_CANCEL_STOP_DEVICE: 
		status = PnpCancelStopDevice( DeviceObject, Irp ); 
		break; 
    case IRP_MN_STOP_DEVICE: 
        SET_NEW_PNP_STATE(deviceExtension, Stopped); 
		SampleIoDecrement( deviceExtension ); 
 		status = DefaultPnpHandler( DeviceObject, Irp ); 
		return status; 
    case IRP_MN_QUERY_REMOVE_DEVICE: 
		status = PnpQueryRemoveDevice( DeviceObject, Irp ); 
		return status; 
    case IRP_MN_CANCEL_REMOVE_DEVICE: 
		status = PnpCancelRemoveDevice( DeviceObject, Irp ); 
		break; 
    case IRP_MN_REMOVE_DEVICE: 
		status = PnpRemoveDevice( DeviceObject, Irp );         
        return status; 
    case IRP_MN_SURPRISE_REMOVAL: 
		status = PnpSurpriseRemoval( DeviceObject, Irp ); 
		SampleIoDecrement( deviceExtension ); 
        return status; 
	case IRP_MN_QUERY_CAPABILITIES: 
		return PnpQueryCapabilities( DeviceObject, Irp ); 
    default: 
        IoSkipCurrentIrpStackLocation(Irp); 
        status = IoCallDriver(deviceExtension->NextLowerDriver, Irp); 
		SampleIoDecrement(deviceExtension); 
		return status; 
    } 
	CompleteRequest( Irp, status, 0 ); 
    SampleIoDecrement(deviceExtension); 
	return status; 
} 
 
NTSTATUS PnpStartDevice(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 
/*++ 
 
Routine Description: 
 
	Pnp handler to IRP_MN_START_DEVICE. 
 
Arguments: 
 
    deviceExtension - pointer to a device object extension. 
	Irp				- the pointer to PnP IRP_MN_START_DEVICE Irp. 
 
Return Value: 
 
    NT status code. 
 
--*/ 
{ 
    NTSTATUS			status; 
	PDEVICE_EXTENSION	deviceExtension; 
    PIO_STACK_LOCATION	irpStack; 
	KIRQL				oldIrql; 
 
	deviceExtension = DeviceObject->DeviceExtension; 
	status = ForwardAndWait( DeviceObject, Irp); 
    if ( !NT_SUCCESS( status ) ) 
        return CompleteRequest(Irp, status, Irp->IoStatus.Information); 
 
	irpStack = IoGetCurrentIrpStackLocation( Irp ); 
	//status = CreateWorkThread( deviceExtension ); 
	//	Open transport address, set clienteventhandler and initialize recvContext. 
	status = InitializeConnection( deviceExtension ); 
	if( NT_SUCCESS( status ) && NT_SUCCESS( Irp->IoStatus.Status ) ){ 
 
		status = IoSetDeviceInterfaceState( &deviceExtension->InterfaceName, TRUE ); 
		if( !NT_SUCCESS( status )){ 
			DebugPrint(( "StartDevice:  IoSetDeviceInterfaceState failed (%x)\n", status )); 
		} 
		SET_NEW_PNP_STATE( deviceExtension, Working ); 
	} 
    return status; 
} 
NTSTATUS 
PnpQueryStopDevice( 
    IN PDEVICE_OBJECT DeviceObject, 
    IN PIRP           Irp 
    ) 
/*++ 
 
Routine Description: 
 
	Pnp handler to IRP_MN_QUERY_STOP_DEVICE. 
 
Arguments: 
 
    deviceExtension - pointer to a device object extension. 
	Irp				- the pointer to PnP IRP_MN_START_DEVICE Irp. 
 
Return Value: 
 
    NT status code. 
 
--*/ 
{ 
    KIRQL             oldIrql; 
    NTSTATUS          status; 
    PDEVICE_EXTENSION deviceExtension; 
 
    deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; 
    // 
    // If we can stop the device, we need to set the QueueState to  
    // PendingStop so further requests will be queued. 
    // 
    SET_NEW_PNP_STATE(deviceExtension, PendingStop); 
    SampleIoDecrement( deviceExtension ); 
 
    KeWaitForSingleObject(&deviceExtension->StopEvent, 
                          Executive, 
                          KernelMode, 
                          FALSE, 
                          NULL); 
	status = DefaultPnpHandler( DeviceObject, Irp ); 
    return status; 
} 
 
NTSTATUS 
PnpCancelStopDevice( 
    IN PDEVICE_OBJECT DeviceObject, 
    IN PIRP           Irp 
    ) 
/*++ 
 
Routine Description: 
 
	Pnp handler to IRP_MN_CANCEL_STOP_DEVICE. 
 
Arguments: 
 
    deviceExtension - pointer to a device object extension. 
	Irp				- the pointer to PnP IRP_MN_START_DEVICE Irp. 
 
Return Value: 
 
    NT status code. 
 
--*/ 
{ 
    KIRQL             oldIrql;     
    KEVENT            event; 
    NTSTATUS          status; 
    PDEVICE_EXTENSION deviceExtension; 
 
    deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; 
    // 
    // Send this IRP down and wait for it to come back. 
    // Set the QueueState flag to AllowRequests,  
    // and process all the previously queued up IRPs. 
    // 
 
    // 
    // First check to see whether you have received cancel-stop 
    // without first receiving a query-stop. This could happen if someone 
    // above us fails a query-stop and passes down the subsequent 
    // cancel-stop. 
    // 
    if(PendingStop == deviceExtension->DevicePnPState) { 
		status = ForwardAndWait( DeviceObject, Irp ); 
        if(NT_SUCCESS( status )) { 
            RESTORE_PREVIOUS_PNP_STATE(deviceExtension); 
        } 
    } 
    else { 
        status = STATUS_SUCCESS; 
    } 
    return status; 
} 
 
NTSTATUS 
PnpQueryRemoveDevice( 
    IN PDEVICE_OBJECT DeviceObject, 
    IN PIRP           Irp 
    ) 
/*++ 
 
Routine Description: 
 
	Pnp handler to IRP_MN_QUERY_REMOVE_DEVICE. 
 
Arguments: 
 
    deviceExtension - pointer to a device object extension. 
	Irp				- the pointer to PnP IRP_MN_START_DEVICE Irp. 
 
Return Value: 
 
    NT status code. 
 
--*/ 
 
{ 
#define WDM_DELAY_VALUE            (ULONG)(-1 * 20000 * 1000)     // 2s 
    KIRQL             oldIrql; 
    NTSTATUS          status; 
    PDEVICE_EXTENSION deviceExtension; 
    LARGE_INTEGER deltaTime; 
 
 
    deviceExtension		= (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; 
    SampleIoDecrement( deviceExtension ); 
 
	deltaTime.LowPart	= WDM_DELAY_VALUE; 
	deltaTime.HighPart	= -1; 
    // 
    // Wait deltaTime for all the requests to be completed. 
    // If timeout, that means some Irps haven't be completed. 
	// So we will simply return Device_Busy and not pass down to lower driver. 
	// 
    status = KeWaitForSingleObject(&deviceExtension->StopEvent,  
                          Executive, 
                          KernelMode, 
                          FALSE, 
                          &deltaTime); 
	if( STATUS_TIMEOUT == status ) 
		return CompleteRequest( Irp, STATUS_DEVICE_BUSY, 0 ); 
    // 
    // If we can allow removal of the device, we should set the QueueState 
    // to HoldRequests so further requests will be queued. This is required 
    // so that we can process queued up requests in cancel-remove just in  
    // case somebody else in the stack fails the query-remove.  
    // 
    SET_NEW_PNP_STATE(deviceExtension, PendingRemove ); 
 
	status = DefaultPnpHandler( DeviceObject, Irp ); 
    return status; 
} 
 
NTSTATUS 
PnpCancelRemoveDevice( 
    IN PDEVICE_OBJECT DeviceObject, 
    IN PIRP           Irp 
    ) 
/*++ 
 
Routine Description: 
 
	Pnp handler to IRP_MN_CANEL_REMOVE_DEVICE. 
 
Arguments: 
 
    deviceExtension - pointer to a device object extension. 
	Irp				- the pointer to PnP IRP_MN_START_DEVICE Irp. 
 
Return Value: 
 
    NT status code. 
 
--*/ 
{ 
    NTSTATUS          status; 
    PDEVICE_EXTENSION deviceExtension; 
	KIRQL				oldIrql; 
    // 
    // initialize variables 
    // 
    deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; 
    // 
    // We need to reset the QueueState flag to ProcessRequest,  
    // since the device resume its normal activities. 
    // 
    // 
    // First check to see whether you have received cancel-remove 
    // without first receiving a query-remove. This could happen if  
    // someone above us fails a query-remove and passes down the  
    // subsequent cancel-remove. 
    // 
    if(PendingRemove == deviceExtension->DevicePnPState) { 
		status = ForwardAndWait( DeviceObject, Irp ); 
        if(NT_SUCCESS( status )) { 
            RESTORE_PREVIOUS_PNP_STATE( deviceExtension ); 
        } 
		// Re-start workthread. omit now. 
		// 
    } 
    else { 
        //  
        // spurious cancel-remove 
        // 
        status = STATUS_SUCCESS; 
    } 
    return status; 
} 
 
NTSTATUS PnpRemoveDevice( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 
/*++ 
 
Routine Description: 
 
	Pnp handler to IRP_MN_REMOVE_DEVICE. 
 
Arguments: 
 
    deviceExtension - pointer to a device object extension. 
	Irp				- the pointer to PnP IRP_MN_START_DEVICE Irp. 
 
Return Value: 
 
    NT status code. 
 
--*/ 
{ 
	NTSTATUS			status; 
	PDEVICE_EXTENSION	deviceExtension; 
	KIRQL				oldIrql; 
	ULONG				requestCount; 
 
	DebugPrint(("+Enter RemoveDevice routine\n" )); 
	deviceExtension = DeviceObject->DeviceExtension; 
	//  TODO: handle our remove work at first 
	if ( SurpriseRemoved != deviceExtension->DevicePnPState ) 
	{ 
		// 
		// If the device is not surprise removed, we should call set interface to FALSE. 
		// If surprise removed, This step has been called in SurprisedRemoved handle. 
		// 
		status = IoSetDeviceInterfaceState( &deviceExtension->InterfaceName, FALSE ); 
		if( !NT_SUCCESS( status ) ){ 
			DebugPrint(( "RemoveDevice: IoSetDeviceInterfaceState failed (%x)\n", status )); 
		} 
	} 
	// set new PNP state 
	SET_NEW_PNP_STATE(deviceExtension, Removed ); 
    requestCount = SampleIoDecrement( deviceExtension ); 
    ASSERT(requestCount > 0); 
    requestCount = SampleIoDecrement( deviceExtension ); 
 
    KeWaitForSingleObject(&deviceExtension->RemoveEvent,  
                          Executive,  
                          KernelMode,  
                          FALSE,  
                          NULL); 
	Disconnection( deviceExtension ); 
	// Unregister serial DosName and delete register 
	SerialUndoExternalNaming( deviceExtension ); 
	// delete buffer pool used for device name , dos name and others. 
	SerialRemoveDevObj( DeviceObject ); 
	RtlFreeUnicodeString( &deviceExtension->InterfaceName ); 
 
	Disconnection( deviceExtension ); 
 
	if ( deviceExtension->RxBuffer ) 
		ExFreePool ( deviceExtension->RxBuffer ); 
	if ( deviceExtension->recvContext.RemainderBuffer ) 
		ExFreePool ( deviceExtension->recvContext.RemainderBuffer ); 
 
	// Pass down the IRP 
	status = DefaultPnpHandler( DeviceObject, Irp ); 
 
	IoDetachDevice( deviceExtension->NextLowerDriver ); 
	// 
	// Free up interface memory 
	// 
	IoDeleteDevice( DeviceObject ); 
	DebugPrint(("-Exit RemoveDevice routine\n")); 
	return status; 
} 
 
NTSTATUS 
PnpSurpriseRemoval( 
    IN PDEVICE_OBJECT DeviceObject, 
    IN PIRP           Irp 
	) 
/*++ 
 
Routine Description: 
 
	Pnp handler to IRP_MN_SURPRISE_REMOVAL. 
 
Arguments: 
 
    deviceExtension - pointer to a device object extension. 
	Irp				- the pointer to PnP IRP_MN_START_DEVICE Irp. 
 
Return Value: 
 
    NT status code. 
 
--*/ 
{ 
	KIRQL             oldIrql; 
    NTSTATUS          status; 
    PDEVICE_EXTENSION deviceExtension; 
    deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; 
 
	// set new PNP state 
	SET_NEW_PNP_STATE(deviceExtension, SurpriseRemoved ); 
	status = IoSetDeviceInterfaceState( &deviceExtension->InterfaceName, FALSE ); 
	if( !NT_SUCCESS( status ) ){ 
		DebugPrint(( "RemoveDevice: IoSetDeviceInterfaceState failed (%x)\n", status )); 
	} 
	status = DefaultPnpHandler( DeviceObject, Irp ); 
	return status; 
} 
 
 
NTSTATUS PnpQueryCapabilities( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 
/*++ 
 
Routine Description: 
 
	Pnp handler to IRP_MN_QUERY_CAPABILITIES. 
 
Arguments: 
 
    deviceExtension - pointer to a device object extension. 
	Irp				- the pointer to PnP IRP_MN_START_DEVICE Irp. 
 
Return Value: 
 
    NT status code. 
 
--*/ 
{ 
    NTSTATUS			status; 
	PIO_STACK_LOCATION      stack; 
    PDEVICE_CAPABILITIES    deviceCapabilities; 
    PAGED_CODE (); 
 
	status = ForwardAndWait( DeviceObject, Irp ); 
 
    stack = IoGetCurrentIrpStackLocation (Irp); 
    // 
    // add our device's capabilities. 
    // 
    deviceCapabilities = stack->Parameters.DeviceCapabilities.Capabilities; 
	// 
	// thess mean the device is Removeable and NOT surprise removed. 
	// If user force to surprise remove the device, "Unsafe remove device" dialog will appear. 
	// 
	deviceCapabilities->SurpriseRemovalOK = FALSE; 
	//deviceCapabilities->Removable = TRUE; 
	status = CompleteRequest( Irp, status, Irp->IoStatus.Information ); 
    SampleIoDecrement( DeviceObject->DeviceExtension ); 
	return status; 
} 
NTSTATUS DefaultPnpHandler(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 
{ 
	PDEVICE_EXTENSION	deviceExtension; 
    deviceExtension				= (PDEVICE_EXTENSION)DeviceObject->DeviceExtension; 
    IoSkipCurrentIrpStackLocation( Irp ); 
    return IoCallDriver( deviceExtension->NextLowerDriver, Irp); 
} 
 
NTSTATUS ForwardAndWait(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 
/*++ 
 
Routine Description: 
 
	pass down Irp to lower driver and wait for its completion. 
 
Arguments: 
 
    deviceExtension - pointer to a device object extension. 
	Irp				- the pointer to PnP IRP_MN_START_DEVICE Irp. 
 
Return Value: 
 
    NT status code. 
 
--*/ 
{ 
    KEVENT				event; 
    NTSTATUS			status; 
	PDEVICE_EXTENSION	deviceExtension; 
 
	deviceExtension = ( PDEVICE_EXTENSION )DeviceObject->DeviceExtension; 
     
	KeInitializeEvent(&event, NotificationEvent, FALSE); 
 
    IoCopyCurrentIrpStackLocationToNext( Irp ); 
 
    IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE)  
        OnRequestComplete, (PVOID) &event, TRUE, TRUE, TRUE); 
 
	status = IoCallDriver( deviceExtension->NextLowerDriver, Irp); 
    if (status == STATUS_PENDING) 
    {                       // wait for completion 
        KeWaitForSingleObject( 
			&event, 
			Executive,		//	Waiting for reasion of a driver 
			KernelMode,		//	Waiting in kernel mode 
			FALSE,			//	No alert 
			NULL);			//	No timeout 
        status = Irp->IoStatus.Status; 
    }                       // wait for completion 
 
    return status; 
} 
NTSTATUS OnRequestComplete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, 
    IN PKEVENT event) 
{ 
    KeSetEvent( event, 0, FALSE); 
    return STATUS_MORE_PROCESSING_REQUIRED; 
} 
 
#if DBG 
PCHAR 
PnPMinorFunctionString ( 
    UCHAR MinorFunction 
) 
/*++ 
 
Routine Description: 
 
	Print PnP Irp's minor function informaion. 
 
Arguments: 
 
    deviceExtension - pointer to a device object extension. 
	Irp				- the pointer to PnP IRP_MN_START_DEVICE Irp. 
 
Return Value: 
 
    NT status code. 
 
--*/ 
{ 
    switch (MinorFunction) 
    { 
        case IRP_MN_START_DEVICE: 
            return "IRP_MN_START_DEVICE"; 
        case IRP_MN_QUERY_REMOVE_DEVICE: 
            return "IRP_MN_QUERY_REMOVE_DEVICE"; 
        case IRP_MN_REMOVE_DEVICE: 
            return "IRP_MN_REMOVE_DEVICE"; 
        case IRP_MN_CANCEL_REMOVE_DEVICE: 
            return "IRP_MN_CANCEL_REMOVE_DEVICE"; 
        case IRP_MN_STOP_DEVICE: 
            return "IRP_MN_STOP_DEVICE"; 
        case IRP_MN_QUERY_STOP_DEVICE: 
            return "IRP_MN_QUERY_STOP_DEVICE"; 
        case IRP_MN_CANCEL_STOP_DEVICE: 
            return "IRP_MN_CANCEL_STOP_DEVICE"; 
        case IRP_MN_QUERY_DEVICE_RELATIONS: 
            return "IRP_MN_QUERY_DEVICE_RELATIONS"; 
        case IRP_MN_QUERY_INTERFACE: 
            return "IRP_MN_QUERY_INTERFACE"; 
        case IRP_MN_QUERY_CAPABILITIES: 
            return "IRP_MN_QUERY_CAPABILITIES"; 
        case IRP_MN_QUERY_RESOURCES: 
            return "IRP_MN_QUERY_RESOURCES"; 
        case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: 
            return "IRP_MN_QUERY_RESOURCE_REQUIREMENTS"; 
        case IRP_MN_QUERY_DEVICE_TEXT: 
            return "IRP_MN_QUERY_DEVICE_TEXT"; 
        case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: 
            return "IRP_MN_FILTER_RESOURCE_REQUIREMENTS"; 
        case IRP_MN_READ_CONFIG: 
            return "IRP_MN_READ_CONFIG"; 
        case IRP_MN_WRITE_CONFIG: 
            return "IRP_MN_WRITE_CONFIG"; 
        case IRP_MN_EJECT: 
            return "IRP_MN_EJECT"; 
        case IRP_MN_SET_LOCK: 
            return "IRP_MN_SET_LOCK"; 
        case IRP_MN_QUERY_ID: 
            return "IRP_MN_QUERY_ID"; 
        case IRP_MN_QUERY_PNP_DEVICE_STATE: 
            return "IRP_MN_QUERY_PNP_DEVICE_STATE"; 
        case IRP_MN_QUERY_BUS_INFORMATION: 
            return "IRP_MN_QUERY_BUS_INFORMATION"; 
        case IRP_MN_DEVICE_USAGE_NOTIFICATION: 
            return "IRP_MN_DEVICE_USAGE_NOTIFICATION"; 
        case IRP_MN_SURPRISE_REMOVAL: 
            return "IRP_MN_SURPRISE_REMOVAL"; 
             
        default: 
            return "IRP_MN_?????"; 
    } 
} 
#endif