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.
408 lines
15 KiB
408 lines
15 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:
|
|
|
|
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;
|
|
}
|