You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
529 lines
16 KiB
529 lines
16 KiB
/***************************************************************************
|
|
|
|
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;
|
|
}
|