/*++ 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" #include "readwrit.h" // require declaration for ParReverseToForward() VOID ParpIoctlThreadLockPort( IN PDEVICE_EXTENSION Extension ) { NTSTATUS status; PIRP irp = Extension->CurrentOpIrp; ParDump2(PARIOCTL2, ("ParDeviceIo::IOCTL_INTERNAL_LOCK_PORT - attempting to acquire LockPortMutex\n") ); // ExAcquireFastMutex (&Extension->LockPortMutex); ParDump2(PARIOCTL2, ("ParDeviceIo::IOCTL_INTERNAL_LOCK_PORT - LockPortMutex acquired\n") ); Extension->AllocatedByLockPort = TRUE; // - begin ParDump2(PARIOCTL2, ("ParDeviceIo::IOCTL_INTERNAL_LOCK_PORT - attempting to Select Device\n") ); // dvdr if( ParSelectDevice(Extension,FALSE) ) { if( ParSelectDevice(Extension,TRUE) ) { ParDump2(PARIOCTL2, ("ParDeviceIo::IOCTL_INTERNAL_LOCK_PORT - Select Device - SUCCESS\n") ); status = STATUS_SUCCESS; } else { ParDump2(PARIOCTL2, ("ParDeviceIo::IOCTL_INTERNAL_LOCK_PORT - Select Device - FAIL\n") ); status = STATUS_UNSUCCESSFUL; Extension->AllocatedByLockPort = FALSE; ParDump2(PARIOCTL2, ("ParDeviceIo::IOCTL_INTERNAL_LOCK_PORT - Releasing LockPortMutex\n") ); // ExReleaseFastMutex (&Extension->LockPortMutex); ParDump2(PARIOCTL2, ("ParDeviceIo::IOCTL_INTERNAL_LOCK_PORT - Released LockPortMutex\n") ); } // - end irp->IoStatus.Status = status; } VOID ParpIoctlThreadUnlockPort( IN PDEVICE_EXTENSION Extension ) { PIRP irp = Extension->CurrentOpIrp; ParDump2(PARIOCTL2, ("ParDeviceIo::IOCTL_INTERNAL_UNLOCK_PORT\n") ); Extension->AllocatedByLockPort = FALSE; if( ParDeselectDevice(Extension, FALSE) ) { ParDump2(PARIOCTL2, ("ParDeviceIo::IOCTL_INTERNAL_UNLOCK_PORT - Device Deselected\n") ); } else { ParDump2(PARIOCTL2, ("ParDeviceIo::IOCTL_INTERNAL_UNLOCK_PORT - Device Deselect FAILED\n") ); } ParDump2(PARIOCTL2, ("ParDeviceIo::IOCTL_INTERNAL_UNLOCK_PORT - Releasing LockMutex\n") ); // ExReleaseFastMutex (&Extension->LockPortMutex); ParDump2(PARIOCTL2, ("ParDeviceIo::IOCTL_INTERNAL_UNLOCK_PORT - Released LockMutex\n") ); irp->IoStatus.Status = STATUS_SUCCESS; } NTSTATUS IoctlTest(PIRP Irp, PIO_STACK_LOCATION IrpSp, PDEVICE_EXTENSION Extension) { // if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(PAR_SET_INFORMATION)) {} // if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PAR_QUERY_INFORMATION)) {} // Status = STATUS_BUFFER_TOO_SMALL; ParDump2(PARIOCTL2, ("IoctlTest - Irp= %x , IrpSp= %x , Extension= %x\n", Irp, IrpSp, Extension) ); ParDump2(PARIOCTL2, ("OutputBufferLength= %d, sizeof(PARALLEL_WMI_LOG_INFO)= %d\n", IrpSp->Parameters.DeviceIoControl.OutputBufferLength, sizeof(PARALLEL_WMI_LOG_INFO) ) ); if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(PPARALLEL_WMI_LOG_INFO)) { PPARALLEL_WMI_LOG_INFO buffer = (PPARALLEL_WMI_LOG_INFO)Irp->AssociatedIrp.SystemBuffer; *buffer = Extension->log; Irp->IoStatus.Information = sizeof(PARALLEL_WMI_LOG_INFO); Irp->IoStatus.Status = STATUS_SUCCESS; ParCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS; } else { Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; ParCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_BUFFER_TOO_SMALL; } } 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 --*/ { PIO_STACK_LOCATION IrpSp; PPAR_SET_INFORMATION SetInfo; NTSTATUS Status; PSERIAL_TIMEOUTS SerialTimeouts; PDEVICE_EXTENSION Extension; KIRQL OldIrql; // PPARCLASS_INFORMATION pParclassInfo; ParDump2(PARIOCTL2, ("Enter ParDeviceControl(...)\n") ); Irp->IoStatus.Information = 0; IrpSp = IoGetCurrentIrpStackLocation(Irp); Extension = DeviceObject->DeviceExtension; // // bail out if a delete is pending for this device object // if(Extension->DeviceStateFlags & PAR_DEVICE_DELETE_PENDING) { Irp->IoStatus.Status = STATUS_DELETE_PENDING; ParCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_DELETE_PENDING; } // // bail out if a remove is pending for our ParPort device object // if(Extension->DeviceStateFlags & PAR_DEVICE_PORT_REMOVE_PENDING) { Irp->IoStatus.Status = STATUS_DELETE_PENDING; ParCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_DELETE_PENDING; } // // bail out if device has been removed // if(Extension->DeviceStateFlags & (PAR_DEVICE_REMOVED|PAR_DEVICE_SURPRISE_REMOVAL) ) { Irp->IoStatus.Status = STATUS_DEVICE_REMOVED; ParCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_DEVICE_REMOVED; } switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { #if 0 case IOCTL_PAR_TEST: return IoctlTest(Irp, IrpSp, Extension); #endif case IOCTL_PAR_SET_INFORMATION: ParDump2(PARIOCTL2, ("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 : ParDump2(PARIOCTL2, ("IOCTL_PAR_QUERY_INFORMATION - %wZ\n", &Extension->SymbolicLinkName) ); if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PAR_QUERY_INFORMATION)) { Status = STATUS_BUFFER_TOO_SMALL; } else { Status = STATUS_PENDING; } break; case IOCTL_SERIAL_SET_TIMEOUTS: ParDump2(PARIOCTL2, ("IOCTL_SERIAL_SET_TIMEOUTS - %wZ\n", &Extension->SymbolicLinkName) ); 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: ParDump2(PARIOCTL2, ("IOCTL_SERIAL_GET_TIMEOUTS - %wZ\n", &Extension->SymbolicLinkName) ); 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 * Extension->TimerStart; Irp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS); Status = STATUS_SUCCESS; } break; case IOCTL_PAR_QUERY_DEVICE_ID: case IOCTL_PAR_QUERY_RAW_DEVICE_ID: ParDump2(PARIOCTL2, ("IOCTL_PAR_QUERY_DEVICE_ID - %wZ\n", &Extension->SymbolicLinkName) ); if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength == 0) { Status = STATUS_BUFFER_TOO_SMALL; } else { Status = STATUS_PENDING; } break; case IOCTL_PAR_QUERY_DEVICE_ID_SIZE: ParDump2(PARIOCTL2, ("IOCTL_PAR_QUERY_DEVICE_ID_SIZE - %wZ\n", &Extension->SymbolicLinkName) ); 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: ParDump2(PARIOCTL2, ("IOCTL_PAR_IS_PORT_FREE - %wZ\n", &Extension->SymbolicLinkName)); if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(BOOLEAN) ) { Status = STATUS_BUFFER_TOO_SMALL; } else { if( Extension->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 = Extension->TryAllocatePort( Extension->PortContext ); if( tryAllocSuccess ) { // we were able to allocate the port, free it and report that the port is free Extension->FreePort( Extension->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: ParDump2(PARIOCTL2, ("IOCTL_PAR_GET_READ_ADDRESS - %wZ\n", &Extension->SymbolicLinkName) ); if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(Extension->ReverseInterfaceAddress)) { Status = STATUS_BUFFER_TOO_SMALL; } else { *((PUCHAR) Irp->AssociatedIrp.SystemBuffer) = Extension->ReverseInterfaceAddress; Irp->IoStatus.Information = sizeof(Extension->ReverseInterfaceAddress); Status = STATUS_SUCCESS; } break; case IOCTL_PAR_GET_WRITE_ADDRESS: ParDump2(PARIOCTL2, ("IOCTL_PAR_GET_WRITE_ADDRESS - %wZ\n", &Extension->SymbolicLinkName) ); if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(Extension->ForwardInterfaceAddress)) { Status = STATUS_BUFFER_TOO_SMALL; } else { *((PUCHAR) Irp->AssociatedIrp.SystemBuffer) = Extension->ForwardInterfaceAddress; Irp->IoStatus.Information = sizeof(Extension->ForwardInterfaceAddress); Status = STATUS_SUCCESS; } break; case IOCTL_PAR_SET_READ_ADDRESS: ParDump2(PARIOCTL2, (" IOCTL_PAR_SET_READ_ADDRESS - %wZ\n", &Extension->SymbolicLinkName) ); if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(Extension->ReverseInterfaceAddress)) { Status = STATUS_INVALID_PARAMETER; } else { Status = STATUS_PENDING; } break; case IOCTL_PAR_SET_WRITE_ADDRESS: ParDump2(PARIOCTL2, (" IOCTL_PAR_SET_WRITE_ADDRESS - %wZ\n", &Extension->SymbolicLinkName) ); if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(Extension->ForwardInterfaceAddress)) { Status = STATUS_INVALID_PARAMETER; } else { Status = STATUS_PENDING; } break; case IOCTL_IEEE1284_GET_MODE: ParDump2(PARIOCTL2, ("IOCTL_IEEE1284_GET_MODE - %wZ\n", &Extension->SymbolicLinkName) ); if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PARCLASS_NEGOTIATION_MASK)) { Status = STATUS_BUFFER_TOO_SMALL; } else { PPARCLASS_NEGOTIATION_MASK ppnmMask; ppnmMask = (PPARCLASS_NEGOTIATION_MASK)Irp->AssociatedIrp.SystemBuffer; ppnmMask->usReadMask = arpReverse[Extension->IdxReverseProtocol].Protocol; ppnmMask->usWriteMask = afpForward[Extension->IdxForwardProtocol].Protocol; Irp->IoStatus.Information = sizeof (PARCLASS_NEGOTIATION_MASK); Status = STATUS_SUCCESS; } break; case IOCTL_PAR_GET_DEFAULT_MODES: ParDump2(PARIOCTL2, ("IOCTL_IEEE1284_GET_MODE - %wZ\n", &Extension->SymbolicLinkName) ); if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PARCLASS_NEGOTIATION_MASK)) { Status = STATUS_BUFFER_TOO_SMALL; } else { PPARCLASS_NEGOTIATION_MASK ppnmMask; 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: ParDump2(PARIOCTL2, ("IOCTL_PAR_ECP_HOST_RECOVERY - %wZ\n", &Extension->SymbolicLinkName) ); { BOOLEAN *isSupported; if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(BOOLEAN) ) { Status = STATUS_INVALID_PARAMETER; } else { isSupported = (BOOLEAN *)Irp->AssociatedIrp.SystemBuffer; Extension->bIsHostRecoverSupported = *isSupported; Status = STATUS_SUCCESS; } } break; case IOCTL_PAR_PING: ParDump2(PARIOCTL2, ("IOCTL_PAR_PING - %wZ\n", &Extension->SymbolicLinkName) ); // No Parms to check! Status = STATUS_PENDING; break; case IOCTL_PAR_GET_DEVICE_CAPS: ParDump2(PARIOCTL2, ("IOCTL_PAR_GET_DEVICE_CAPS - %wZ\n", &Extension->SymbolicLinkName) ); if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(Extension->ProtocolModesSupported)) { Status = STATUS_BUFFER_TOO_SMALL; } else { Status = STATUS_PENDING; } break; case IOCTL_IEEE1284_NEGOTIATE: ParDump2(PARIOCTL2, ("IOCTL_IEEE1284_NEGOTIATE - %wZ\n", &Extension->SymbolicLinkName) ); if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(PARCLASS_NEGOTIATION_MASK) || IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PARCLASS_NEGOTIATION_MASK) ) { ParDump2(PARERRORS, ( "ParDeviceControl: IOCTL_IEEE1284_NEGOTIATE STATUS_INVALID_PARAMETER.\n" )); Status = STATUS_INVALID_PARAMETER; } else { PPARCLASS_NEGOTIATION_MASK ppnmMask; ppnmMask = (PPARCLASS_NEGOTIATION_MASK)Irp->AssociatedIrp.SystemBuffer; if ((ppnmMask->usReadMask == arpReverse[Extension->IdxReverseProtocol].Protocol) && (ppnmMask->usWriteMask == afpForward[Extension->IdxForwardProtocol].Protocol)) { Irp->IoStatus.Information = sizeof (PARCLASS_NEGOTIATION_MASK); ParDump2(PARINFO, ( "ParDeviceControl: IOCTL_IEEE1284_NEGOTIATE Passed.\n" )); Status = STATUS_SUCCESS; } else Status = STATUS_PENDING; } break; default : ParDump2(PARIOCTL2, ("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( &Extension->WorkQueue ); IoMarkIrpPending(Irp); IoSetCancelRoutine(Irp, ParCancelRequest); InsertTailList(&Extension->WorkQueue, &Irp->Tail.Overlay.ListEntry); IoReleaseCancelSpinLock(OldIrql); if( needToSignalSemaphore ) { KeReleaseSemaphore(&Extension->RequestSemaphore, 0, 1, FALSE); } } } if (Status != STATUS_PENDING) { Irp->IoStatus.Status = Status; ParCompleteRequest(Irp, IO_NO_INCREMENT); } 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; PDEVICE_EXTENSION Extension; KIRQL OldIrql; PPARCLASS_INFORMATION pParclassInfo; ParDump2(PARIOCTL2, ("Enter ParInternalDeviceControl(...)\n") ); Irp->IoStatus.Information = 0; IrpSp = IoGetCurrentIrpStackLocation(Irp); Extension = DeviceObject->DeviceExtension; // // bail out if a delete is pending for this device object // if(Extension->DeviceStateFlags & PAR_DEVICE_DELETE_PENDING) { Irp->IoStatus.Status = STATUS_DELETE_PENDING; ParCompleteRequest(Irp, IO_NO_INCREMENT); ParDump2(PARIOCTL2, ("ParInternalDeviceControl(...) - returning DELETE_PENDING\n") ); return STATUS_DELETE_PENDING; } // // bail out if a remove is pending for our ParPort device object // if(Extension->DeviceStateFlags & PAR_DEVICE_PORT_REMOVE_PENDING) { Irp->IoStatus.Status = STATUS_DELETE_PENDING; ParCompleteRequest(Irp, IO_NO_INCREMENT); ParDump2(PARIOCTL2, ("ParInternalDeviceControl(...) - returning DELETE_PENDING\n") ); return STATUS_DELETE_PENDING; } // // bail out if device has been removed // if(Extension->DeviceStateFlags & (PAR_DEVICE_REMOVED|PAR_DEVICE_SURPRISE_REMOVAL) ) { Irp->IoStatus.Status = STATUS_DEVICE_REMOVED; ParCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_DEVICE_REMOVED; } switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_INTERNAL_PARCLASS_CONNECT: ParDump2(PARIOCTL2, ("IOCTL_INTERNAL_PARCLASS_CONNECT - Dispatch\n") ); ParDump2(PARIOCTL2, ("IOCTL_INTERNAL_PARCLASS_CONNECT - %wZ\n", &Extension->SymbolicLinkName) ); if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PARCLASS_INFORMATION)) { Status = STATUS_BUFFER_TOO_SMALL; } else { pParclassInfo = Irp->AssociatedIrp.SystemBuffer; pParclassInfo->Controller = Extension->Controller; pParclassInfo->EcrController = Extension->EcrController; pParclassInfo->SpanOfController = Extension->SpanOfController; pParclassInfo->ParclassContext = Extension; pParclassInfo->HardwareCapabilities = Extension->HardwareCapabilities; pParclassInfo->FifoDepth = Extension->FifoDepth; pParclassInfo->FifoWidth = Extension->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_PARCLASS_DISCONNECT: Status = STATUS_SUCCESS; break; case IOCTL_INTERNAL_DISCONNECT_IDLE: case IOCTL_INTERNAL_LOCK_PORT: case IOCTL_INTERNAL_UNLOCK_PORT: 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 Extension->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 : ParDump2(PARIOCTL2, ("IOCTL_INTERNAL... default case - Dispatch\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( &Extension->WorkQueue ); IoMarkIrpPending(Irp); IoSetCancelRoutine(Irp, ParCancelRequest); InsertTailList(&Extension->WorkQueue, &Irp->Tail.Overlay.ListEntry); IoReleaseCancelSpinLock(OldIrql); if( needToSignalSemaphore ) { KeReleaseSemaphore(&Extension->RequestSemaphore, 0, 1, FALSE); } } } if (Status != STATUS_PENDING) { Irp->IoStatus.Status = Status; ParCompleteRequest(Irp, IO_NO_INCREMENT); } return Status; } VOID ParDeviceIo( IN PDEVICE_EXTENSION Extension ) /*++ Routine Description: This routine implements a DEVICE_IOCTL request with the extension's current irp. Arguments: Extension - Supplies the device extension. Return Value: None. --*/ { PIRP Irp; PIO_STACK_LOCATION IrpSp; ULONG IdLength; NTSTATUS NtStatus; UCHAR Status; UCHAR Control; ULONG ioControlCode; // ParDump2(PARIOCTL2,("Enter ParDeviceIo(...)\n") ); Irp = Extension->CurrentOpIrp; IrpSp = IoGetCurrentIrpStackLocation(Irp); ioControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode; switch( ioControlCode ) { case IOCTL_PAR_SET_INFORMATION : { PPAR_SET_INFORMATION IrpBuffer = Extension->CurrentOpIrp->AssociatedIrp.SystemBuffer; Status = ParInitializeDevice(Extension); if (!PAR_OK(Status)) { ParNotInitError(Extension, 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(Extension->Controller); Control = GetControl(Extension->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(Extension, Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.DeviceIoControl.OutputBufferLength, &IdLength, TRUE); Irp->IoStatus.Status = NtStatus; if (NT_SUCCESS(NtStatus)) { Irp->IoStatus.Information = IdLength; } else { Irp->IoStatus.Information = 0; } break; case IOCTL_PAR_QUERY_DEVICE_ID : // We always read the Device Id in Nibble Mode. NtStatus = SppQueryDeviceId(Extension, Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.DeviceIoControl.OutputBufferLength, &IdLength, FALSE); Irp->IoStatus.Status = NtStatus; if( NT_SUCCESS( NtStatus ) ) { ParDump2(PARIOCTL1, ("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) { ParDump2(PARIOCTL1, ("IOCTL_PAR_QUERY_ID - FAIL - BUFFER_TOO_SMALL - supplied= %d, required=%d\n", IrpSp->Parameters.DeviceIoControl.OutputBufferLength, IdLength) ); Irp->IoStatus.Information = 0; } else { ParDump2(PARIOCTL1, ("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(Extension, NULL, 0, &IdLength, FALSE); if (NtStatus == STATUS_BUFFER_TOO_SMALL) { ParDump2(PARIOCTL1, ("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(Extension); ParDump2(PARINFO, ("ParDeviceIo:IOCTL_PAR_PING\n")); Irp->IoStatus.Status = NtStatus; Irp->IoStatus.Information = 0; break; case IOCTL_INTERNAL_DISCONNECT_IDLE : if ((Extension->Connected) && (afpForward[Extension->IdxForwardProtocol].fnDisconnect)) { ParDump2(PARINFO, ("ParDeviceIo:IOCTL_INTERNAL_DISCONNECT_IDLE: Calling afpForward.fnDisconnect\n")); afpForward[Extension->IdxForwardProtocol].fnDisconnect (Extension); } 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(Extension); Irp->IoStatus.Status = IeeeNegotiateMode(Extension, ppnmMask->usReadMask, ppnmMask->usWriteMask); if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(PARCLASS_NEGOTIATION_MASK)) { ParDump2(PARINFO, ( "ParDeviceIo: IOCTL_IEEE1284_NEGOTIATE Passed.\n" )); ppnmMask->usReadMask = arpReverse[Extension->IdxReverseProtocol].Protocol; ppnmMask->usWriteMask = afpForward[Extension->IdxForwardProtocol].Protocol; Irp->IoStatus.Information = sizeof (PARCLASS_NEGOTIATION_MASK); } else { ParDump2(PARERRORS, ( "ParDeviceIo: IOCTL_IEEE1284_NEGOTIATE failed.\n" )); Irp->IoStatus.Information = 0; } } break; case IOCTL_PAR_GET_DEVICE_CAPS : Extension->BadProtocolModes = *((USHORT *) Irp->AssociatedIrp.SystemBuffer); IeeeDetermineSupportedProtocols(Extension); *((USHORT *) Irp->AssociatedIrp.SystemBuffer) = Extension->ProtocolModesSupported; Irp->IoStatus.Information = sizeof(Extension->ProtocolModesSupported); Irp->IoStatus.Status = STATUS_SUCCESS; break; case IOCTL_PAR_SET_READ_ADDRESS: { PUCHAR pAddress = (PUCHAR)Irp->AssociatedIrp.SystemBuffer; if (Extension->ReverseInterfaceAddress != *pAddress) { Extension->ReverseInterfaceAddress = *pAddress; Extension->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 (Extension->ForwardInterfaceAddress != *pAddress) { Extension->ForwardInterfaceAddress = *pAddress; if (Extension->Connected) { if (afpForward[Extension->IdxForwardProtocol].fnSetInterfaceAddress) { if (Extension->CurrentPhase != PHASE_FORWARD_IDLE && Extension->CurrentPhase != PHASE_FORWARD_XFER) { NtStatus = ParReverseToForward(Extension); } if (NT_SUCCESS(NtStatus)) { NtStatus = afpForward[Extension->IdxForwardProtocol].fnSetInterfaceAddress( Extension, Extension->ForwardInterfaceAddress ); } if (NT_SUCCESS(NtStatus)) { Extension->SetForwardAddress = FALSE; Extension->SetReverseAddress = FALSE; Extension->ReverseInterfaceAddress = *pAddress; } else { Extension->SetForwardAddress = TRUE; ParDump2(PARERRORS, ( "ParDeviceIo: IOCTL_PAR_SET_WRITE_ADDRESS Failed\n" )); } } else { #if DBG ParDump2(PARERRORS, ( "ParDeviceIo: Someone called IOCTL_PAR_SET_WRITE_ADDRESS.\n" )); ParDump2(PARERRORS, ( "ParDeviceIo: You don't have a fnSetInterfaceAddress.\n" )); ParDump2(PARERRORS, ( "ParDeviceIo: Either IEEE1284.c has wrong info or your caller is in error!\n" )); NtStatus = STATUS_UNSUCCESSFUL; #endif } } else { Extension->SetForwardAddress = TRUE; } } Irp->IoStatus.Information = 0; Irp->IoStatus.Status = NtStatus; } break; case IOCTL_INTERNAL_LOCK_PORT : ParpIoctlThreadLockPort(Extension); break; case IOCTL_INTERNAL_UNLOCK_PORT : ParpIoctlThreadUnlockPort(Extension); break; case IOCTL_SERIAL_SET_TIMEOUTS: { PSERIAL_TIMEOUTS ptoNew = Irp->AssociatedIrp.SystemBuffer; // // The only other thing let through is setting // the timer start. // Extension->TimerStart = ptoNew->WriteTotalTimeoutConstant / 1000; Irp->IoStatus.Status = STATUS_SUCCESS; } break; case IOCTL_INTERNAL_PARDOT3_CONNECT: ParDump2(PARIOCTL2, ("IOCTL_INTERNAL_PARDOT3_CONNECT - Dispatch\n") ); Irp->IoStatus.Status = ParDot3Connect(Extension); Irp->IoStatus.Information = 0; break; case IOCTL_INTERNAL_PARDOT3_DISCONNECT: ParDump2(PARIOCTL2, ("IOCTL_INTERNAL_PARDOT3_DISCONNECT - Dispatch\n") ); Irp->IoStatus.Status = ParDot3Disconnect(Extension); Irp->IoStatus.Information = 0; break; case IOCTL_INTERNAL_PARDOT3_SIGNAL: { PKEVENT Event;// = (PKEVENT)Irp->AssociatedIrp.SystemBuffer; RtlCopyMemory(&Event, Irp->AssociatedIrp.SystemBuffer, sizeof(PKEVENT)); ASSERT_EVENT(Event); ParDump2(PARIOCTL2, ("IOCTL_INTERNAL_PARDOT3_SIGNAL - Dispatch. Event [%x]\n", Event) ); Extension->P12843DL.Event = Event; Extension->P12843DL.bEventActive = TRUE; } Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; break; case IOCTL_INTERNAL_PARDOT3_RESET: ParDump2(PARIOCTL2, ("IOCTL_INTERNAL_PARDOT3_RESET - Dispatch\n") ); if (Extension->P12843DL.fnReset) Irp->IoStatus.Status = ((PDOT3_RESET_ROUTINE) (Extension->P12843DL.fnReset))(Extension); 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; }