Windows2003-3790/drivers/parallel/parport2/pdoioctl.c
2020-09-30 16:53:55 +02:00

1070 lines
35 KiB
C
Raw Permalink 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) Microsoft Corporation, 1998 - 1999
File Name:
ioctl.c
Contained in Module:
parallel.sys
Abstract:
This file contains functions associated with ParClass IOCTL processing.
- The three main entry points in this file are:
- ParDeviceControl() - Dispatch function for non-internal IOCTLs
- ParInternalDeviceControl() - Dispatch function for internal IOCTLs
- ParDeviceIo() - Worker thread entry point for handling all
IOCTLs not completed in a dispatch function
- Helper/Utility function naming conventions:
- ParpIoctlDispatch...() - private helper function called by dispatch function
- ParpIoctlThread...() - private helper function called by worker thread
Authors:
Anthony V. Ercolano 1-Aug-1992
Norbert P. Kusters 22-Oct-1993
Douglas G. Fritz 24-Jul-1998
Revision History :
--*/
#include "pch.h"
VOID
ParpIoctlThreadLockPort(
IN PPDO_EXTENSION Pdx
)
{
NTSTATUS status;
PIRP irp = Pdx->CurrentOpIrp;
DD((PCE)Pdx,DDT,"ParpIoctlThreadLockPort - enter\n");
if( ParSelectDevice(Pdx,TRUE) ) {
DD((PCE)Pdx,DDT,"ParpIoctlThreadLockPort - SUCCESS\n");
Pdx->AllocatedByLockPort = TRUE;
status = STATUS_SUCCESS;
} else {
DD((PCE)Pdx,DDW,"ParpIoctlThreadLockPort - FAIL\n");
Pdx->AllocatedByLockPort = FALSE;
status = STATUS_UNSUCCESSFUL;
}
irp->IoStatus.Status = status;
}
VOID
ParpIoctlThreadUnlockPort(
IN PPDO_EXTENSION Pdx
)
{
PIRP irp = Pdx->CurrentOpIrp;
Pdx->AllocatedByLockPort = FALSE;
DD((PCE)Pdx,DDT,"ParpIoctlThreadUnlockPort - enter\n");
if( ParDeselectDevice(Pdx, FALSE) ) {
DD((PCE)Pdx,DDT,"ParpIoctlThreadUnlockPort - SUCCESS\n");
} else {
DD((PCE)Pdx,DDW,"ParpIoctlThreadUnlockPort - FAIL - nothing we can do\n");
}
irp->IoStatus.Status = STATUS_SUCCESS;
}
NTSTATUS
ParDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is the dispatch for device control requests.
Arguments:
DeviceObject - Supplies the device object.
Irp - Supplies the I/O request packet.
Return Value:
STATUS_SUCCESS - Success.
STATUS_PENDING - Request pending.
STATUS_BUFFER_TOO_SMALL - Buffer too small.
STATUS_INVALID_PARAMETER - Invalid io control request.
STATUS_DELETE_PENDING - This device object is being deleted
--*/
{
PPDO_EXTENSION Pdx = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
PPAR_SET_INFORMATION SetInfo;
NTSTATUS Status;
PSERIAL_TIMEOUTS SerialTimeouts;
KIRQL OldIrql;
Irp->IoStatus.Information = 0;
//
// bail out if a delete is pending for this device object
//
if(Pdx->DeviceStateFlags & PPT_DEVICE_DELETE_PENDING) {
return P4CompleteRequest( Irp, STATUS_DELETE_PENDING, 0 );
}
//
// bail out if a remove is pending for our ParPort device object
//
if(Pdx->DeviceStateFlags & PAR_DEVICE_PORT_REMOVE_PENDING) {
return P4CompleteRequest( Irp, STATUS_DELETE_PENDING, 0 );
}
//
// bail out if device has been removed
//
if(Pdx->DeviceStateFlags & (PPT_DEVICE_REMOVED|PPT_DEVICE_SURPRISE_REMOVED) ) {
return P4CompleteRequest( Irp, STATUS_DEVICE_REMOVED, 0 );
}
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_PAR_QUERY_LOCATION:
DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_LOCATION\n");
{
ULONG outBufLen = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
ULONG locationLen = strlen(Pdx->Location);
if( outBufLen < locationLen+1 ) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
PCHAR buffer = (PCHAR)Irp->AssociatedIrp.SystemBuffer;
RtlCopyMemory( buffer, Pdx->Location, locationLen + 1 );
Irp->IoStatus.Information = locationLen + 1;
Status = STATUS_SUCCESS;
}
}
break;
case IOCTL_PAR_SET_INFORMATION:
DD((PCE)Pdx,DDT,"IOCTL_PAR_SET_INFORMATION\n");
SetInfo = Irp->AssociatedIrp.SystemBuffer;
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(PAR_SET_INFORMATION)) {
Status = STATUS_BUFFER_TOO_SMALL;
} else if (SetInfo->Init != PARALLEL_INIT) {
Status = STATUS_INVALID_PARAMETER;
} else {
//
// This is a parallel reset
//
Status = STATUS_PENDING;
}
break;
case IOCTL_PAR_QUERY_INFORMATION :
DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_INFORMATION\n");
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(PAR_QUERY_INFORMATION)) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
Status = STATUS_PENDING;
}
break;
case IOCTL_SERIAL_SET_TIMEOUTS:
DD((PCE)Pdx,DDT,"IOCTL_SERIAL_SET_TIMEOUTS\n");
SerialTimeouts = Irp->AssociatedIrp.SystemBuffer;
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(SERIAL_TIMEOUTS)) {
Status = STATUS_BUFFER_TOO_SMALL;
} else if (SerialTimeouts->WriteTotalTimeoutConstant < 2000) {
Status = STATUS_INVALID_PARAMETER;
} else {
Status = STATUS_PENDING;
}
break;
case IOCTL_SERIAL_GET_TIMEOUTS:
DD((PCE)Pdx,DDT,"IOCTL_SERIAL_GET_TIMEOUTS\n");
SerialTimeouts = Irp->AssociatedIrp.SystemBuffer;
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(SERIAL_TIMEOUTS)) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
//
// We don't need to synchronize the read.
//
RtlZeroMemory(SerialTimeouts, sizeof(SERIAL_TIMEOUTS));
SerialTimeouts->WriteTotalTimeoutConstant =
1000 * Pdx->TimerStart;
Irp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS);
Status = STATUS_SUCCESS;
}
break;
case IOCTL_PAR_QUERY_DEVICE_ID:
case IOCTL_PAR_QUERY_RAW_DEVICE_ID:
DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_[RAW_]DEVICE_ID\n");
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength == 0) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
Status = STATUS_PENDING;
}
break;
case IOCTL_PAR_QUERY_DEVICE_ID_SIZE:
DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_DEVICE_ID_SIZE\n");
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(PAR_DEVICE_ID_SIZE_INFORMATION)) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
Status = STATUS_PENDING;
}
break;
case IOCTL_PAR_IS_PORT_FREE:
DD((PCE)Pdx,DDT,"IOCTL_PAR_IS_PORT_FREE\n");
if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(BOOLEAN) ) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
if( Pdx->bAllocated ) {
// if we have the port then it is not free
*((PBOOLEAN)Irp->AssociatedIrp.SystemBuffer) = FALSE;
} else {
// determine if the port is free by trying to allocate and free it
// - our alloc/free will only succeed if no one else has the port
BOOLEAN tryAllocSuccess = Pdx->TryAllocatePort( Pdx->PortContext );
if( tryAllocSuccess ) {
// we were able to allocate the port, free it and report that the port is free
Pdx->FreePort( Pdx->PortContext );
*((PBOOLEAN)Irp->AssociatedIrp.SystemBuffer) = TRUE;
} else {
// we were unable to allocate the port, someone else must be using the port
*((PBOOLEAN)Irp->AssociatedIrp.SystemBuffer) = FALSE;
}
}
Irp->IoStatus.Information = sizeof(BOOLEAN);
Status = STATUS_SUCCESS;
}
break;
case IOCTL_PAR_GET_READ_ADDRESS:
DD((PCE)Pdx,DDT,"IOCTL_PAR_GET_READ_ADDRESS\n");
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(Pdx->ReverseInterfaceAddress)) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
*((PUCHAR) Irp->AssociatedIrp.SystemBuffer) = Pdx->ReverseInterfaceAddress;
Irp->IoStatus.Information = sizeof(Pdx->ReverseInterfaceAddress);
Status = STATUS_SUCCESS;
}
break;
case IOCTL_PAR_GET_WRITE_ADDRESS:
DD((PCE)Pdx,DDT,"IOCTL_PAR_GET_WRITE_ADDRESS\n");
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(Pdx->ForwardInterfaceAddress)) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
*((PUCHAR) Irp->AssociatedIrp.SystemBuffer) = Pdx->ForwardInterfaceAddress;
Irp->IoStatus.Information = sizeof(Pdx->ForwardInterfaceAddress);
Status = STATUS_SUCCESS;
}
break;
case IOCTL_PAR_SET_READ_ADDRESS:
DD((PCE)Pdx,DDT," IOCTL_PAR_SET_READ_ADDRESS\n");
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(Pdx->ReverseInterfaceAddress)) {
Status = STATUS_INVALID_PARAMETER;
} else {
Status = STATUS_PENDING;
}
break;
case IOCTL_PAR_SET_WRITE_ADDRESS:
DD((PCE)Pdx,DDT," IOCTL_PAR_SET_WRITE_ADDRESS\n");
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(Pdx->ForwardInterfaceAddress)) {
Status = STATUS_INVALID_PARAMETER;
} else {
Status = STATUS_PENDING;
}
break;
case IOCTL_IEEE1284_GET_MODE:
DD((PCE)Pdx,DDT,"IOCTL_IEEE1284_GET_MODE\n");
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PARCLASS_NEGOTIATION_MASK)) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
PPARCLASS_NEGOTIATION_MASK ppnmMask = (PPARCLASS_NEGOTIATION_MASK)Irp->AssociatedIrp.SystemBuffer;
ppnmMask->usReadMask = arpReverse[Pdx->IdxReverseProtocol].Protocol;
ppnmMask->usWriteMask = afpForward[Pdx->IdxForwardProtocol].Protocol;
Irp->IoStatus.Information = sizeof (PARCLASS_NEGOTIATION_MASK);
Status = STATUS_SUCCESS;
}
break;
case IOCTL_PAR_GET_DEFAULT_MODES:
DD((PCE)Pdx,DDT,"IOCTL_IEEE1284_GET_MODE\n");
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PARCLASS_NEGOTIATION_MASK)) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
PPARCLASS_NEGOTIATION_MASK ppnmMask = (PPARCLASS_NEGOTIATION_MASK)Irp->AssociatedIrp.SystemBuffer;
ppnmMask->usReadMask = NONE;
ppnmMask->usWriteMask = CENTRONICS;
Irp->IoStatus.Information = sizeof (PARCLASS_NEGOTIATION_MASK);
Status = STATUS_SUCCESS;
}
break;
case IOCTL_PAR_ECP_HOST_RECOVERY:
DD((PCE)Pdx,DDT,"IOCTL_PAR_ECP_HOST_RECOVERY\n");
{
BOOLEAN *isSupported;
if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(BOOLEAN) ) {
Status = STATUS_INVALID_PARAMETER;
} else {
isSupported = (BOOLEAN *)Irp->AssociatedIrp.SystemBuffer;
Pdx->bIsHostRecoverSupported = *isSupported;
Status = STATUS_SUCCESS;
}
}
break;
case IOCTL_PAR_PING:
DD((PCE)Pdx,DDT,"IOCTL_PAR_PING\n");
// No Parms to check!
Status = STATUS_PENDING;
break;
case IOCTL_PAR_GET_DEVICE_CAPS:
DD((PCE)Pdx,DDT,"IOCTL_PAR_GET_DEVICE_CAPS\n");
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(Pdx->ProtocolModesSupported)) {
Status = STATUS_BUFFER_TOO_SMALL;
} else if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(Pdx->BadProtocolModes)) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
Status = STATUS_PENDING;
}
break;
case IOCTL_IEEE1284_NEGOTIATE:
DD((PCE)Pdx,DDT,"IOCTL_IEEE1284_NEGOTIATE\n");
if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(PARCLASS_NEGOTIATION_MASK) ||
IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PARCLASS_NEGOTIATION_MASK) ) {
DD((PCE)Pdx,DDW,"ParDeviceControl: IOCTL_IEEE1284_NEGOTIATE STATUS_INVALID_PARAMETER\n");
Status = STATUS_INVALID_PARAMETER;
} else {
PPARCLASS_NEGOTIATION_MASK ppnmMask = (PPARCLASS_NEGOTIATION_MASK)Irp->AssociatedIrp.SystemBuffer;
if ((ppnmMask->usReadMask == arpReverse[Pdx->IdxReverseProtocol].Protocol) &&
(ppnmMask->usWriteMask == afpForward[Pdx->IdxForwardProtocol].Protocol)) {
Irp->IoStatus.Information = sizeof(PARCLASS_NEGOTIATION_MASK);
Status = STATUS_SUCCESS;
} else {
Status = STATUS_PENDING;
}
}
break;
default :
DD((PCE)Pdx,DDT,"IOCTL default case\n");
Status = STATUS_INVALID_PARAMETER;
break;
}
if (Status == STATUS_PENDING) {
IoAcquireCancelSpinLock(&OldIrql);
if (Irp->Cancel) {
IoReleaseCancelSpinLock(OldIrql);
Status = STATUS_CANCELLED;
} else {
//
// This IRP takes more time, so it should be queued.
//
BOOLEAN needToSignalSemaphore = (IsListEmpty( &Pdx->WorkQueue ) &&
!KeReadStateSemaphore( &Pdx->RequestSemaphore )) ? TRUE : FALSE;
IoMarkIrpPending(Irp);
#pragma warning( push )
#pragma warning( disable : 4054 4055 )
IoSetCancelRoutine(Irp, ParCancelRequest);
#pragma warning( pop )
InsertTailList(&Pdx->WorkQueue, &Irp->Tail.Overlay.ListEntry);
IoReleaseCancelSpinLock(OldIrql);
if( needToSignalSemaphore ) {
KeReleaseSemaphore(&Pdx->RequestSemaphore, 0, 1, FALSE);
}
}
}
if (Status != STATUS_PENDING) {
P4CompleteRequest( Irp, Status, Irp->IoStatus.Information );
}
return Status;
}
NTSTATUS
ParInternalDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is the dispatch for internal device control requests.
Arguments:
DeviceObject - Supplies the device object.
Irp - Supplies the I/O request packet.
Return Value:
STATUS_SUCCESS - Success.
STATUS_PENDING - Request pending.
STATUS_BUFFER_TOO_SMALL - Buffer too small.
STATUS_INVALID_PARAMETER - Invalid io control request.
STATUS_DELETE_PENDING - This device object is being deleted
--*/
{
PIO_STACK_LOCATION IrpSp;
// PPAR_SET_INFORMATION SetInfo;
NTSTATUS Status;
// PSERIAL_TIMEOUTS SerialTimeouts;
PPDO_EXTENSION Pdx;
KIRQL OldIrql;
PPARCLASS_INFORMATION pParclassInfo;
Irp->IoStatus.Information = 0;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
Pdx = DeviceObject->DeviceExtension;
//
// bail out if a delete is pending for this device object
//
if(Pdx->DeviceStateFlags & PPT_DEVICE_DELETE_PENDING) {
P4CompleteRequest( Irp, STATUS_DELETE_PENDING, Irp->IoStatus.Information );
return STATUS_DELETE_PENDING;
}
//
// bail out if a remove is pending for our ParPort device object
//
if(Pdx->DeviceStateFlags & PAR_DEVICE_PORT_REMOVE_PENDING) {
P4CompleteRequest( Irp, STATUS_DELETE_PENDING, Irp->IoStatus.Information );
return STATUS_DELETE_PENDING;
}
//
// bail out if device has been removed
//
if(Pdx->DeviceStateFlags & (PPT_DEVICE_REMOVED|PPT_DEVICE_SURPRISE_REMOVED) ) {
P4CompleteRequest( Irp, STATUS_DEVICE_REMOVED, Irp->IoStatus.Information );
return STATUS_DEVICE_REMOVED;
}
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_INTERNAL_PARCLASS_CONNECT:
DD((PCE)Pdx,DDT,"IOCTL_INTERNAL_PARCLASS_CONNECT\n");
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PARCLASS_INFORMATION)) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
PFDO_EXTENSION fdx = Pdx->Fdo->DeviceExtension;
PPARALLEL_PORT_INFORMATION portInfo = &fdx->PortInfo;
PPARALLEL_PNP_INFORMATION pnpInfo = &fdx->PnpInfo;
pParclassInfo = Irp->AssociatedIrp.SystemBuffer;
pParclassInfo->ParclassContext = Pdx;
pParclassInfo->Controller = portInfo->Controller;
pParclassInfo->SpanOfController = portInfo->SpanOfController;
pParclassInfo->EcrController = pnpInfo->EcpController;
pParclassInfo->HardwareCapabilities = pnpInfo->HardwareCapabilities;
pParclassInfo->FifoDepth = pnpInfo->FifoDepth;
pParclassInfo->FifoWidth = pnpInfo->FifoWidth;
pParclassInfo->DetermineIeeeModes = ParExportedDetermineIeeeModes;
pParclassInfo->TerminateIeeeMode = ParExportedTerminateIeeeMode;
pParclassInfo->NegotiateIeeeMode = ParExportedNegotiateIeeeMode;
pParclassInfo->IeeeFwdToRevMode = ParExportedIeeeFwdToRevMode;
pParclassInfo->IeeeRevToFwdMode = ParExportedIeeeRevToFwdMode;
pParclassInfo->ParallelRead = ParExportedParallelRead;
pParclassInfo->ParallelWrite = ParExportedParallelWrite;
Irp->IoStatus.Information = sizeof(PARCLASS_INFORMATION);
Status = STATUS_SUCCESS;
}
break;
case IOCTL_INTERNAL_GET_PARPORT_FDO:
DD((PCE)Pdx,DDT,"IOCTL_INTERNAL_GET_PARPORT_FDO\n");
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PDEVICE_OBJECT)) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
PDEVICE_OBJECT *pFdo = Irp->AssociatedIrp.SystemBuffer;
*pFdo = Pdx->Fdo;
Irp->IoStatus.Information = sizeof(PDEVICE_OBJECT);
Status = STATUS_SUCCESS;
}
break;
case IOCTL_INTERNAL_PARCLASS_DISCONNECT:
Status = STATUS_SUCCESS;
break;
case IOCTL_INTERNAL_DISCONNECT_IDLE:
case IOCTL_INTERNAL_LOCK_PORT:
case IOCTL_INTERNAL_UNLOCK_PORT:
case IOCTL_INTERNAL_LOCK_PORT_NO_SELECT:
case IOCTL_INTERNAL_UNLOCK_PORT_NO_DESELECT:
case IOCTL_INTERNAL_PARDOT3_CONNECT:
case IOCTL_INTERNAL_PARDOT3_RESET:
Status = STATUS_PENDING;
break;
case IOCTL_INTERNAL_PARDOT3_DISCONNECT:
// immediately tell worker thread to stop signalling
Pdx->P12843DL.bEventActive = FALSE;
Status = STATUS_PENDING;
break;
case IOCTL_INTERNAL_PARDOT3_SIGNAL:
if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(PKEVENT) ) {
Status = STATUS_INVALID_PARAMETER;
} else {
Status = STATUS_PENDING;
}
break;
default :
DD((PCE)Pdx,DDW,"IOCTL_INTERNAL... default case - invalid parameter\n");
Status = STATUS_INVALID_PARAMETER;
break;
}
if (Status == STATUS_PENDING) {
//
// This IRP takes more time, queue it for the worker thread
//
IoAcquireCancelSpinLock(&OldIrql);
if (Irp->Cancel) {
IoReleaseCancelSpinLock(OldIrql);
Status = STATUS_CANCELLED;
} else {
BOOLEAN needToSignalSemaphore = (IsListEmpty( &Pdx->WorkQueue ) &&
!KeReadStateSemaphore( &Pdx->RequestSemaphore )) ? TRUE : FALSE;
IoMarkIrpPending(Irp);
#pragma warning( push )
#pragma warning( disable : 4054 4055 )
IoSetCancelRoutine(Irp, ParCancelRequest);
#pragma warning( pop )
InsertTailList(&Pdx->WorkQueue, &Irp->Tail.Overlay.ListEntry);
IoReleaseCancelSpinLock(OldIrql);
if( needToSignalSemaphore ) {
KeReleaseSemaphore(&Pdx->RequestSemaphore, 0, 1, FALSE);
}
}
}
if (Status != STATUS_PENDING) {
P4CompleteRequest( Irp, Status, Irp->IoStatus.Information );
}
return Status;
}
VOID
ParDeviceIo(
IN PPDO_EXTENSION Pdx
)
/*++
Routine Description:
This routine implements a DEVICE_IOCTL request with the extension's current irp.
Arguments:
Pdx - Supplies the device extension.
Return Value:
None.
--*/
{
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
ULONG IdLength;
NTSTATUS NtStatus;
UCHAR Status;
UCHAR Control;
ULONG ioControlCode;
Irp = Pdx->CurrentOpIrp;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
ioControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
switch( ioControlCode ) {
case IOCTL_PAR_SET_INFORMATION :
{
Status = ParInitializeDevice(Pdx);
if (!PAR_OK(Status)) {
ParNotInitError(Pdx, Status); // Set the IoStatus.Status of the CurrentOpIrp appropriately
} else {
Irp->IoStatus.Status = STATUS_SUCCESS;
}
}
break;
case IOCTL_PAR_QUERY_INFORMATION :
{
PPAR_QUERY_INFORMATION IrpBuffer = Irp->AssociatedIrp.SystemBuffer;
Irp->IoStatus.Status = STATUS_SUCCESS;
Status = GetStatus(Pdx->Controller);
Control = GetControl(Pdx->Controller);
// Interpretating Status & Control
IrpBuffer->Status = 0x0;
if (PAR_POWERED_OFF(Status) || PAR_NO_CABLE(Status)) {
IrpBuffer->Status = (UCHAR)(IrpBuffer->Status | PARALLEL_POWER_OFF);
} else if (PAR_PAPER_EMPTY(Status)) {
IrpBuffer->Status = (UCHAR)(IrpBuffer->Status | PARALLEL_PAPER_EMPTY);
} else if (PAR_OFF_LINE(Status)) {
IrpBuffer->Status = (UCHAR)(IrpBuffer->Status | PARALLEL_OFF_LINE);
} else if (PAR_NOT_CONNECTED(Status)) {
IrpBuffer->Status = (UCHAR)(IrpBuffer->Status | PARALLEL_NOT_CONNECTED);
}
if (PAR_BUSY(Status)) {
IrpBuffer->Status = (UCHAR)(IrpBuffer->Status | PARALLEL_BUSY);
}
if (PAR_SELECTED(Status)) {
IrpBuffer->Status = (UCHAR)(IrpBuffer->Status | PARALLEL_SELECTED);
}
Irp->IoStatus.Information = sizeof( PAR_QUERY_INFORMATION );
}
break;
case IOCTL_PAR_QUERY_RAW_DEVICE_ID :
// We always read the Device Id in Nibble Mode.
NtStatus = SppQueryDeviceId(Pdx,
Irp->AssociatedIrp.SystemBuffer,
IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
&IdLength, TRUE);
Irp->IoStatus.Status = NtStatus;
if (NT_SUCCESS(NtStatus)) {
Irp->IoStatus.Information = IdLength + sizeof(CHAR);
} else {
Irp->IoStatus.Information = 0;
}
break;
case IOCTL_PAR_QUERY_DEVICE_ID :
// We always read the Device Id in Nibble Mode.
NtStatus = SppQueryDeviceId(Pdx,
Irp->AssociatedIrp.SystemBuffer,
IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
&IdLength, FALSE);
Irp->IoStatus.Status = NtStatus;
if( NT_SUCCESS( NtStatus ) ) {
DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_ID - SUCCESS - size = %d\n", IdLength);
// Include terminating NULL in the string to copy back to user buffer
Irp->IoStatus.Information = IdLength + sizeof(CHAR);
} else if( NtStatus == STATUS_BUFFER_TOO_SMALL) {
DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_ID - FAIL - BUFFER_TOO_SMALL - supplied= %d, required=%d\n",
IrpSp->Parameters.DeviceIoControl.OutputBufferLength, IdLength);
Irp->IoStatus.Information = 0;
} else {
DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_ID - FAIL - QUERY ID FAILED\n");
Irp->IoStatus.Information = 0;
}
break;
case IOCTL_PAR_QUERY_DEVICE_ID_SIZE :
//
// Read the first two bytes of the Nibble Id, add room for the terminating NULL and
// return this to the caller.
//
NtStatus = SppQueryDeviceId(Pdx, NULL, 0, &IdLength, FALSE);
if (NtStatus == STATUS_BUFFER_TOO_SMALL) {
DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_DEVICE_ID_SIZE - size required = %d\n", IdLength);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information =
sizeof(PAR_DEVICE_ID_SIZE_INFORMATION);
// include space for terminating NULL
((PPAR_DEVICE_ID_SIZE_INFORMATION)
Irp->AssociatedIrp.SystemBuffer)->DeviceIdSize = IdLength + sizeof(CHAR);
} else {
Irp->IoStatus.Status = NtStatus;
Irp->IoStatus.Information = 0;
}
break;
case IOCTL_PAR_PING :
// We need to do a quick terminate and negotiate of the current modes
NtStatus = ParPing(Pdx);
DD((PCE)Pdx,DDT,"ParDeviceIo:IOCTL_PAR_PING\n");
Irp->IoStatus.Status = NtStatus;
Irp->IoStatus.Information = 0;
break;
case IOCTL_INTERNAL_DISCONNECT_IDLE :
if ((Pdx->Connected) &&
(afpForward[Pdx->IdxForwardProtocol].fnDisconnect)) {
DD((PCE)Pdx,DDT,"ParDeviceIo:IOCTL_INTERNAL_DISCONNECT_IDLE: Calling afpForward.fnDisconnect\n");
afpForward[Pdx->IdxForwardProtocol].fnDisconnect (Pdx);
}
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
break;
case IOCTL_IEEE1284_NEGOTIATE:
{
PPARCLASS_NEGOTIATION_MASK ppnmMask = (PPARCLASS_NEGOTIATION_MASK)Irp->AssociatedIrp.SystemBuffer;
ParTerminate(Pdx);
Irp->IoStatus.Status = IeeeNegotiateMode(Pdx, ppnmMask->usReadMask, ppnmMask->usWriteMask);
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(PARCLASS_NEGOTIATION_MASK)) {
DD((PCE)Pdx,DDT, "ParDeviceIo: IOCTL_IEEE1284_NEGOTIATE Passed.\n");
ppnmMask->usReadMask = arpReverse[Pdx->IdxReverseProtocol].Protocol;
ppnmMask->usWriteMask = afpForward[Pdx->IdxForwardProtocol].Protocol;
Irp->IoStatus.Information = sizeof (PARCLASS_NEGOTIATION_MASK);
} else {
DD((PCE)Pdx,DDT, "ParDeviceIo: IOCTL_IEEE1284_NEGOTIATE failed.\n");
Irp->IoStatus.Information = 0;
}
}
break;
case IOCTL_PAR_GET_DEVICE_CAPS :
Pdx->BadProtocolModes = *((USHORT *) Irp->AssociatedIrp.SystemBuffer);
IeeeDetermineSupportedProtocols(Pdx);
*((USHORT *) Irp->AssociatedIrp.SystemBuffer) = Pdx->ProtocolModesSupported;
Irp->IoStatus.Information = sizeof(Pdx->ProtocolModesSupported);
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
case IOCTL_PAR_SET_READ_ADDRESS:
{
PUCHAR pAddress = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
if (Pdx->ReverseInterfaceAddress != *pAddress) {
Pdx->ReverseInterfaceAddress = *pAddress;
Pdx->SetReverseAddress = TRUE;
}
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
}
break;
case IOCTL_PAR_SET_WRITE_ADDRESS :
{
PUCHAR pAddress = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
NtStatus = STATUS_SUCCESS;
if (Pdx->ForwardInterfaceAddress != *pAddress) {
Pdx->ForwardInterfaceAddress = *pAddress;
if (Pdx->Connected) {
if (afpForward[Pdx->IdxForwardProtocol].fnSetInterfaceAddress) {
if (Pdx->CurrentPhase != PHASE_FORWARD_IDLE &&
Pdx->CurrentPhase != PHASE_FORWARD_XFER) {
NtStatus = ParReverseToForward(Pdx);
}
if (NT_SUCCESS(NtStatus)) {
NtStatus = afpForward[Pdx->IdxForwardProtocol].fnSetInterfaceAddress(
Pdx,
Pdx->ForwardInterfaceAddress
);
}
if (NT_SUCCESS(NtStatus)) {
Pdx->SetForwardAddress = FALSE;
Pdx->SetReverseAddress = FALSE;
Pdx->ReverseInterfaceAddress = *pAddress;
} else {
Pdx->SetForwardAddress = TRUE;
DD((PCE)Pdx,DDE,"ParDeviceIo: IOCTL_PAR_SET_WRITE_ADDRESS Failed\n");
}
} else {
DD((PCE)Pdx,DDE, "ParDeviceIo: Someone called IOCTL_PAR_SET_WRITE_ADDRESS.\n");
DD((PCE)Pdx,DDE, "ParDeviceIo: You don't have a fnSetInterfaceAddress.\n");
DD((PCE)Pdx,DDE, "ParDeviceIo: Either IEEE1284.c has wrong info or your caller is in error!\n");
NtStatus = STATUS_UNSUCCESSFUL;
}
} else {
Pdx->SetForwardAddress = TRUE;
}
}
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = NtStatus;
}
break;
case IOCTL_INTERNAL_LOCK_PORT :
ParpIoctlThreadLockPort(Pdx);
break;
case IOCTL_INTERNAL_UNLOCK_PORT :
ParpIoctlThreadUnlockPort(Pdx);
break;
case IOCTL_INTERNAL_LOCK_PORT_NO_SELECT:
DD((PCE)Pdx,DDT, "ParDeviceIo - IOCTL_INTERNAL_LOCK_PORT_NO_SELECT\n");
Pdx->AllocatedByLockPort = TRUE;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
break;
case IOCTL_INTERNAL_UNLOCK_PORT_NO_DESELECT:
DD((PCE)Pdx,DDT, "ParDeviceIo - IOCTL_INTERNAL_UNLOCK_PORT_NO_DESELECT\n");
Pdx->AllocatedByLockPort = FALSE;
PptAssert(!Pdx->Connected && !Pdx->AllocatedByLockPort);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
break;
case IOCTL_SERIAL_SET_TIMEOUTS:
{
PSERIAL_TIMEOUTS ptoNew = Irp->AssociatedIrp.SystemBuffer;
//
// The only other thing let through is setting
// the timer start.
//
Pdx->TimerStart = ptoNew->WriteTotalTimeoutConstant / 1000;
Irp->IoStatus.Status = STATUS_SUCCESS;
}
break;
case IOCTL_INTERNAL_PARDOT3_CONNECT:
DD((PCE)Pdx,DDT,"IOCTL_INTERNAL_PARDOT3_CONNECT - Dispatch\n");
Irp->IoStatus.Status = ParDot3Connect(Pdx);
Irp->IoStatus.Information = 0;
break;
case IOCTL_INTERNAL_PARDOT3_DISCONNECT:
DD((PCE)Pdx,DDT,"IOCTL_INTERNAL_PARDOT3_DISCONNECT - Dispatch\n");
Irp->IoStatus.Status = ParDot3Disconnect(Pdx);
Irp->IoStatus.Information = 0;
break;
case IOCTL_INTERNAL_PARDOT3_SIGNAL:
if( Pdx->IdxReverseProtocol != NIBBLE_MODE ) {
PKEVENT Event;// = (PKEVENT)Irp->AssociatedIrp.SystemBuffer;
RtlCopyMemory(&Event, Irp->AssociatedIrp.SystemBuffer, sizeof(PKEVENT));
ASSERT_EVENT(Event);
DD((PCE)Pdx,DDT,"IOCTL_INTERNAL_PARDOT3_SIGNAL - Dispatch. Event [%x]\n", Event);
Pdx->P12843DL.Event = Event;
Pdx->P12843DL.bEventActive = TRUE;
Irp->IoStatus.Status = STATUS_SUCCESS;
} else {
// don't use signalling in NIBBLE mode - rely on dot4 polling
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
}
Irp->IoStatus.Information = 0;
break;
case IOCTL_INTERNAL_PARDOT3_RESET:
DD((PCE)Pdx,DDT,"IOCTL_INTERNAL_PARDOT3_RESET - Dispatch\n");
if (Pdx->P12843DL.fnReset)
Irp->IoStatus.Status = ((PDOT3_RESET_ROUTINE) (Pdx->P12843DL.fnReset))(Pdx);
else
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
break;
default:
//
// unrecognized IOCTL? - we should never get here because the
// dispatch routines should have filtered this out
//
// probably harmless, but we want to know if this happens
// so we can fix the problem elsewhere
ASSERTMSG("Unrecognized IOCTL in ParDeviceIo()\n",FALSE);
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
}
return;
}