530 lines
16 KiB
C
530 lines
16 KiB
C
/***************************************************************************
|
||
|
||
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;
|
||
}
|