409 lines
15 KiB
C
409 lines
15 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:
|
||
|
||
Ioctl.c
|
||
|
||
Abstract:
|
||
|
||
Dispatch routines for IRP_MJ_DEVICE_CONTROL and IRP_MJ_INTERNAL_DEVICE_CONTROL
|
||
|
||
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:
|
||
|
||
- code review
|
||
|
||
Author(s):
|
||
|
||
Doug Fritz (DFritz)
|
||
Joby Lafky (JobyL)
|
||
|
||
****************************************************************************/
|
||
|
||
#include "pch.h"
|
||
|
||
|
||
/************************************************************************/
|
||
/* DispatchDeviceControl */
|
||
/************************************************************************/
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// Dispatch routine for IRP_MJ_DEVICE_CONTROL
|
||
// - We don't currently handle any such requests but we may do
|
||
// so in the future. Pass any unhandled requests down the
|
||
// stack to the device below us.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// DevObj - pointer to DeviceObject that is the target of the request
|
||
// Irp - pointer to device control IRP
|
||
//
|
||
// Return Value:
|
||
//
|
||
// NTSTATUS
|
||
//
|
||
/************************************************************************/
|
||
NTSTATUS
|
||
DispatchDeviceControl(
|
||
IN PDEVICE_OBJECT DevObj,
|
||
IN PIRP Irp
|
||
)
|
||
{
|
||
PDEVICE_EXTENSION devExt = DevObj->DeviceExtension;
|
||
NTSTATUS status;
|
||
ULONG info = 0;
|
||
|
||
TR_VERBOSE(("DispatchDeviceControl - enter"));
|
||
|
||
status = IoAcquireRemoveLock( &devExt->RemoveLock, Irp );
|
||
|
||
if( NT_SUCCESS(status) ) {
|
||
|
||
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
|
||
switch( irpSp->Parameters.DeviceIoControl.IoControlCode ) {
|
||
|
||
case IOCTL_PAR_QUERY_DEVICE_ID:
|
||
// ISSUE - 000901 - DFritz - these new IOCTLs need to do parameter validation to avoid AVs
|
||
{
|
||
const LONG minValidIdLength = sizeof("MFG:x;MDL:y;");
|
||
const ULONG bufSize = 1024;
|
||
PCHAR idBuffer = ExAllocatePool( NonPagedPool, bufSize );
|
||
LONG idLength;
|
||
|
||
if( idBuffer ) {
|
||
|
||
RtlZeroMemory( idBuffer, bufSize );
|
||
|
||
idLength = UsbGet1284Id( DevObj, idBuffer, bufSize-1 );
|
||
|
||
if( idLength < minValidIdLength ) {
|
||
status = STATUS_UNSUCCESSFUL;
|
||
} else if( (ULONG)idLength >= irpSp->Parameters.DeviceIoControl.OutputBufferLength ) {
|
||
status = STATUS_BUFFER_TOO_SMALL;
|
||
} else {
|
||
RtlZeroMemory( Irp->AssociatedIrp.SystemBuffer, idLength+1 );
|
||
RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer, idBuffer+2, idLength-2 );
|
||
info = idLength - 1;
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
ExFreePool( idBuffer );
|
||
|
||
} else {
|
||
status = STATUS_NO_MEMORY;
|
||
}
|
||
}
|
||
|
||
Irp->IoStatus.Status = status;
|
||
Irp->IoStatus.Information = info;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
IoReleaseRemoveLock( &devExt->RemoveLock, Irp );
|
||
|
||
break;
|
||
|
||
case IOCTL_PAR_QUERY_RAW_DEVICE_ID:
|
||
{
|
||
const LONG minValidIdLength = sizeof("MFG:x;MDL:y;");
|
||
const ULONG bufSize = 1024;
|
||
PCHAR idBuffer = ExAllocatePool( NonPagedPool, bufSize );
|
||
LONG idLength;
|
||
|
||
if( idBuffer ) {
|
||
|
||
RtlZeroMemory( idBuffer, bufSize );
|
||
|
||
idLength = UsbGet1284Id( DevObj, idBuffer, bufSize-1 );
|
||
|
||
if( idLength < minValidIdLength ) {
|
||
status = STATUS_UNSUCCESSFUL;
|
||
} else if( (ULONG)idLength >= irpSp->Parameters.DeviceIoControl.OutputBufferLength ) {
|
||
status = STATUS_BUFFER_TOO_SMALL;
|
||
} else {
|
||
RtlZeroMemory( Irp->AssociatedIrp.SystemBuffer, idLength+1 );
|
||
RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer, idBuffer, idLength);
|
||
info = idLength + 1;
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
ExFreePool( idBuffer );
|
||
|
||
} else {
|
||
status = STATUS_NO_MEMORY;
|
||
}
|
||
}
|
||
|
||
Irp->IoStatus.Status = status;
|
||
Irp->IoStatus.Information = info;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
IoReleaseRemoveLock( &devExt->RemoveLock, Irp );
|
||
|
||
break;
|
||
|
||
case IOCTL_PAR_QUERY_DEVICE_ID_SIZE:
|
||
|
||
{
|
||
const LONG minValidIdLength = sizeof("MFG:x;MDL:y;");
|
||
const ULONG bufSize = 1024;
|
||
PCHAR idBuffer = ExAllocatePool( NonPagedPool, bufSize );
|
||
LONG idLength;
|
||
|
||
if( idBuffer ) {
|
||
|
||
RtlZeroMemory( idBuffer, bufSize );
|
||
|
||
idLength = UsbGet1284Id( DevObj, idBuffer, bufSize-1 );
|
||
|
||
if( idLength < minValidIdLength ) {
|
||
status = STATUS_UNSUCCESSFUL;
|
||
} else if( sizeof(ULONG) < irpSp->Parameters.DeviceIoControl.OutputBufferLength ) {
|
||
status = STATUS_BUFFER_TOO_SMALL;
|
||
} else {
|
||
++idLength; // save room for terminating NULL
|
||
RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer, &idLength, sizeof(ULONG));
|
||
info = sizeof(ULONG);
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
ExFreePool( idBuffer );
|
||
|
||
} else {
|
||
status = STATUS_NO_MEMORY;
|
||
}
|
||
}
|
||
|
||
Irp->IoStatus.Status = status;
|
||
Irp->IoStatus.Information = info;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
IoReleaseRemoveLock( &devExt->RemoveLock, Irp );
|
||
|
||
break;
|
||
|
||
case IOCTL_PAR_QUERY_LOCATION:
|
||
|
||
_snprintf( Irp->AssociatedIrp.SystemBuffer, 4, "USB" );
|
||
info = 4;
|
||
status = STATUS_SUCCESS;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
IoReleaseRemoveLock( &devExt->RemoveLock, Irp );
|
||
|
||
default:
|
||
|
||
// pass request down
|
||
IoSkipCurrentIrpStackLocation( Irp );
|
||
status = IoCallDriver( devExt->LowerDevObj, Irp );
|
||
IoReleaseRemoveLock( &devExt->RemoveLock, Irp );
|
||
|
||
}
|
||
|
||
} else {
|
||
// unable to acquire RemoveLock - FAIL request
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
/************************************************************************/
|
||
/* DispatchInternalDeviceControl */
|
||
/************************************************************************/
|
||
//
|
||
// Routine Description:
|
||
//
|
||
// Dispatch routine for IRP_MJ_INTERNAL_DEVICE_CONTROL
|
||
// - We expect DataLink requests from dot4.sys driver above us. Any
|
||
// request that we don't handle is simply passed down the stack
|
||
// to the driver below us.
|
||
//
|
||
// Arguments:
|
||
//
|
||
// DevObj - pointer to DeviceObject that is the target of the request
|
||
// Irp - pointer to device control IRP
|
||
//
|
||
// Return Value:
|
||
//
|
||
// NTSTATUS
|
||
//
|
||
/************************************************************************/
|
||
NTSTATUS
|
||
DispatchInternalDeviceControl(
|
||
IN PDEVICE_OBJECT DevObj,
|
||
IN PIRP Irp
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
PDEVICE_EXTENSION devExt = DevObj->DeviceExtension;
|
||
|
||
TR_VERBOSE(("DispatchInternalDeviceControl - enter"));
|
||
|
||
status = IoAcquireRemoveLock( &devExt->RemoveLock, Irp );
|
||
|
||
if( NT_SUCCESS(status) ) {
|
||
|
||
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
BOOLEAN bCompleteIrp = FALSE;
|
||
KIRQL oldIrql;
|
||
|
||
switch( irpSp->Parameters.DeviceIoControl.IoControlCode ) {
|
||
|
||
case IOCTL_INTERNAL_PARDOT3_CONNECT:
|
||
|
||
//
|
||
// Enter a "DataLink Connected" state with dot4.sys
|
||
//
|
||
|
||
TR_VERBOSE(("DispatchInternalDeviceControl - IOCTL_INTERNAL_PARDOT3_CONNECT"));
|
||
|
||
KeAcquireSpinLock( &devExt->SpinLock, &oldIrql );
|
||
if( !devExt->IsDLConnected ) {
|
||
devExt->IsDLConnected = TRUE;
|
||
status = STATUS_SUCCESS;
|
||
} else {
|
||
// we believe that we are in a "datalink connected state" but obviously
|
||
// dot4.sys doesn't agree - suggest investigating further if we hit
|
||
// this assert
|
||
D4UAssert(FALSE);
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
KeReleaseSpinLock( &devExt->SpinLock, oldIrql );
|
||
|
||
bCompleteIrp = TRUE;
|
||
break;
|
||
|
||
|
||
case IOCTL_INTERNAL_PARDOT3_RESET:
|
||
|
||
//
|
||
// This IOCTL is specific to parallel and is a NOOP for a USB connection.
|
||
//
|
||
|
||
TR_VERBOSE(("DispatchInternalDeviceControl - IOCTL_INTERNAL_PARDOT3_RESET"));
|
||
|
||
status = STATUS_SUCCESS;
|
||
bCompleteIrp = TRUE;
|
||
break;
|
||
|
||
case IOCTL_INTERNAL_PARDOT3_DISCONNECT:
|
||
|
||
//
|
||
// Terminate the "DataLink Connected" state with dot4.sys and
|
||
// invalidate any Dot4Event since the event may be freed anytime
|
||
// after we complete this IRP.
|
||
//
|
||
|
||
TR_VERBOSE(("DispatchInternalDeviceControl - IOCTL_INTERNAL_PARDOT3_DISCONNECT"));
|
||
|
||
UsbStopReadInterruptPipeLoop( DevObj );
|
||
|
||
KeAcquireSpinLock( &devExt->SpinLock, &oldIrql );
|
||
devExt->Dot4Event = NULL; // invalidate dot4's event, if any, so we stop signalling dot4
|
||
if( devExt->IsDLConnected ) {
|
||
devExt->IsDLConnected = FALSE;
|
||
} else {
|
||
// we believe that we are NOT in a "datalink connected state" but obviously
|
||
// dot4.sys doesn't agree - suggest investigating further if we hit
|
||
// this assert
|
||
D4UAssert(FALSE);
|
||
}
|
||
KeReleaseSpinLock( &devExt->SpinLock, oldIrql );
|
||
|
||
status = STATUS_SUCCESS; // we always succeed this request since it is a disconnect
|
||
bCompleteIrp = TRUE;
|
||
break;
|
||
|
||
case IOCTL_INTERNAL_PARDOT3_SIGNAL:
|
||
|
||
//
|
||
// dot4.sys is giving us a pointer to an Event that it owns and dot4
|
||
// expects us to Signal this event whenever we detect that the device has
|
||
// data available to be read. We continue signalling this event on device
|
||
// data avail until we receive a disconnect IOCTL.
|
||
//
|
||
|
||
TR_VERBOSE(("DispatchInternalDeviceControl - IOCTL_INTERNAL_PARDOT3_SIGNAL"));
|
||
|
||
KeAcquireSpinLock( &devExt->SpinLock, &oldIrql );
|
||
if( devExt->IsDLConnected ) {
|
||
if( !devExt->Dot4Event ) {
|
||
// our state indicates that it is OK to receive this request
|
||
if( irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(PKEVENT) ) {
|
||
status = STATUS_INVALID_PARAMETER;
|
||
} else {
|
||
// save the pointer to the event in our device extension
|
||
PKEVENT Event;
|
||
RtlCopyMemory(&Event, Irp->AssociatedIrp.SystemBuffer, sizeof(PKEVENT));
|
||
devExt->Dot4Event = Event;
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
} else {
|
||
// we already have an event and dot4.sys sent us another one? - bad driver - AV crash likely real soon now
|
||
D4UAssert(FALSE);
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
} else {
|
||
// we're not in a datalink connected state - this is an invalid request
|
||
D4UAssert(FALSE);
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
KeReleaseSpinLock( &devExt->SpinLock, oldIrql );
|
||
|
||
if( NT_SUCCESS(status) && devExt->InterruptPipe ) {
|
||
status = UsbStartReadInterruptPipeLoop( DevObj );
|
||
}
|
||
|
||
bCompleteIrp = TRUE;
|
||
break;
|
||
|
||
default :
|
||
|
||
// unhandled request - pass it down the stack
|
||
IoSkipCurrentIrpStackLocation( Irp );
|
||
status = IoCallDriver( devExt->LowerDevObj, Irp );
|
||
bCompleteIrp = FALSE;
|
||
|
||
}
|
||
|
||
if( bCompleteIrp ) {
|
||
// we didn't pass this request down the stack, so complete it now
|
||
Irp->IoStatus.Status = status;
|
||
Irp->IoStatus.Information = 0;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
}
|
||
|
||
IoReleaseRemoveLock( &devExt->RemoveLock, Irp );
|
||
|
||
} else {
|
||
// unable to acquire RemoveLock - we're in the process of being removed - FAIL request
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest( Irp, IO_NO_INCREMENT );
|
||
}
|
||
|
||
return status;
|
||
}
|