windows-nt/Source/XPSP1/NT/drivers/dot4/dot4usb/pnp.c
2020-09-26 16:20:57 +08:00

530 lines
16 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/***************************************************************************
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;
}