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.
287 lines
8.3 KiB
287 lines
8.3 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1998 - 1999
|
|
//
|
|
// File: thread.c
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
//
|
|
// This file contains functions associated with ParClass worker threads
|
|
//
|
|
|
|
#include "pch.h"
|
|
|
|
VOID
|
|
PptPdoThread(
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the parallel thread routine. Loops performing I/O operations.
|
|
|
|
Arguments:
|
|
|
|
Context -- Really the extension
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PPDO_EXTENSION pdx = Context;
|
|
KIRQL OldIrql;
|
|
NTSTATUS Status;
|
|
LARGE_INTEGER Timeout;
|
|
PIRP CurrentIrp;
|
|
|
|
DD((PCE)pdx,DDT,"PptPdoThread - %s - enter\n",pdx->Location);
|
|
|
|
do {
|
|
|
|
Timeout = pdx->IdleTimeout;
|
|
|
|
Status = KeWaitForSingleObject( &pdx->RequestSemaphore, UserRequest, KernelMode, FALSE, &Timeout );
|
|
|
|
if( Status == STATUS_TIMEOUT ) {
|
|
|
|
if( pdx->P12843DL.bEventActive ) {
|
|
|
|
// Dot4.sys has a worker thread blocked on this event
|
|
// waiting for us to signal if the peripheral has data
|
|
// available for dot4 to read. When we signal this
|
|
// event dot4.sys generates a read request to retrieve
|
|
// the data from the peripheral.
|
|
|
|
if( ParHaveReadData( pdx ) ) {
|
|
// the peripheral has data - signal dot4.sys
|
|
DD((PCE)pdx,DDT,"PptPdoThread: Signaling Event [%x]\n", pdx->P12843DL.Event);
|
|
KeSetEvent(pdx->P12843DL.Event, 0, FALSE);
|
|
}
|
|
}
|
|
|
|
if( pdx->QueryNumWaiters( pdx->PortContext ) != 0 ) {
|
|
|
|
// someone else is waiting on the port - give up the
|
|
// port - we'll attempt to reaquire the port later
|
|
// when we have a request to process
|
|
|
|
ParTerminate(pdx);
|
|
ParFreePort(pdx);
|
|
continue;
|
|
}
|
|
|
|
} // endif STATUS_TIMEOUT
|
|
|
|
|
|
// wait here if PnP has paused us (e.g., QUERY_STOP, STOP, QUERY_REMOVE)
|
|
KeWaitForSingleObject(&pdx->PauseEvent, Executive, KernelMode, FALSE, 0);
|
|
|
|
if ( pdx->TimeToTerminateThread ) {
|
|
|
|
// A dispatch thread has signalled us that we should clean
|
|
// up any communication with our peripheral and then
|
|
// terminate self. The dispatch thread is blocked waiting
|
|
// for us to terminate self.
|
|
|
|
if( pdx->Connected ) {
|
|
|
|
// We currently have the port acquired and have the
|
|
// peripheral negotiated into an IEEE mode. Terminate
|
|
// the peripheral back to Compatibility mode forward
|
|
// idle and release the port.
|
|
|
|
ParTerminate( pdx );
|
|
ParFreePort( pdx );
|
|
}
|
|
|
|
// terminate self
|
|
|
|
PsTerminateSystemThread( STATUS_SUCCESS );
|
|
}
|
|
|
|
|
|
//
|
|
// process the next request from the work queue - use the
|
|
// Cancel SpinLock to protect the queue
|
|
//
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
ASSERT(!pdx->CurrentOpIrp);
|
|
|
|
while (!IsListEmpty(&pdx->WorkQueue)) {
|
|
|
|
// get next IRP from our list of work items
|
|
PLIST_ENTRY HeadOfList;
|
|
HeadOfList = RemoveHeadList(&pdx->WorkQueue);
|
|
CurrentIrp = CONTAINING_RECORD(HeadOfList, IRP, Tail.Overlay.ListEntry);
|
|
|
|
// we have started processing, this IRP can no longer be cancelled
|
|
#pragma warning( push )
|
|
#pragma warning( disable : 4054 4055 )
|
|
IoSetCancelRoutine(CurrentIrp, NULL);
|
|
#pragma warning( pop )
|
|
ASSERT(NULL == CurrentIrp->CancelRoutine);
|
|
ASSERT(!CurrentIrp->Cancel);
|
|
|
|
pdx->CurrentOpIrp = CurrentIrp;
|
|
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
//
|
|
// Do the Io - PptPdoStartIo will exectute and complete the IRP: pdx->CurrentIrp
|
|
//
|
|
PptPdoStartIo(pdx);
|
|
|
|
if( pdx->P12843DL.bEventActive ) {
|
|
|
|
// Dot4.sys has a worker thread blocked on this event
|
|
// waiting for us to signal if the peripheral has data
|
|
// available for dot4 to read. When we signal this
|
|
// event dot4.sys generates a read request to retrieve
|
|
// the data from the peripheral.
|
|
|
|
if( ParHaveReadData( pdx ) ) {
|
|
// the peripheral has data - signal dot4.sys
|
|
DD((PCE)pdx,DDT,"PptPdoThread: Signaling Eventb [%x]\n", pdx->P12843DL.Event);
|
|
KeSetEvent(pdx->P12843DL.Event, 0, FALSE);
|
|
}
|
|
}
|
|
|
|
// wait here if PnP has paused us (e.g., QUERY_STOP, STOP, QUERY_REMOVE)
|
|
KeWaitForSingleObject(&pdx->PauseEvent, Executive, KernelMode, FALSE, 0);
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
}
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
} while (TRUE);
|
|
}
|
|
|
|
NTSTATUS
|
|
ParCreateSystemThread(
|
|
PPDO_EXTENSION Pdx
|
|
)
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE ThreadHandle;
|
|
OBJECT_ATTRIBUTES objAttrib;
|
|
|
|
DD((PCE)Pdx,DDT,"ParCreateSystemThread - %s - enter\n",Pdx->Location);
|
|
|
|
// Start the thread - save referenced pointer to thread in our extension
|
|
InitializeObjectAttributes( &objAttrib, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
|
|
Status = PsCreateSystemThread( &ThreadHandle, THREAD_ALL_ACCESS, &objAttrib, NULL, NULL, PptPdoThread, Pdx );
|
|
if (!NT_ERROR(Status)) {
|
|
// We've got the thread. Now get a pointer to it.
|
|
Status = ObReferenceObjectByHandle( ThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &Pdx->ThreadObjectPointer, NULL );
|
|
if (NT_ERROR(Status)) {
|
|
if (!Pdx->TimeToTerminateThread)
|
|
{
|
|
// set the flag for the worker thread to kill itself
|
|
Pdx->TimeToTerminateThread = TRUE;
|
|
|
|
// wake up the thread so it can kill itself
|
|
KeReleaseSemaphore(&Pdx->RequestSemaphore, 0, 1, FALSE );
|
|
|
|
}
|
|
|
|
// error, go ahead and close the thread handle
|
|
ZwClose(ThreadHandle);
|
|
|
|
} else {
|
|
// Now that we have a reference to the thread we can simply close the handle.
|
|
ZwClose(ThreadHandle);
|
|
}
|
|
DD((PCE)Pdx,DDT,"ParCreateSystemThread - %s - SUCCESS\n",Pdx->Location);
|
|
} else {
|
|
DD((PCE)Pdx,DDT,"ParCreateSystemThread - %s FAIL - status = %x\n",Pdx->Location, Status);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
PptPdoStartIo(
|
|
IN PPDO_EXTENSION Pdx
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine starts an I/O operation for the driver and
|
|
then returns
|
|
|
|
Arguments:
|
|
|
|
Pdx - The parallel device extension
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
KIRQL CancelIrql;
|
|
|
|
Irp = Pdx->CurrentOpIrp;
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
if (!Pdx->Connected && !ParAllocPort(Pdx)) {
|
|
// #pragma message( "dvrh Left bad stuff in thread.c")
|
|
DD((PCE)Pdx,DDE,"PptPdoStartIo - %s - threads are hosed\n",Pdx->Location);
|
|
// __asm int 3
|
|
//
|
|
// If the allocation didn't succeed then fail this IRP.
|
|
//
|
|
goto CompleteIrp;
|
|
}
|
|
|
|
switch (IrpSp->MajorFunction) {
|
|
|
|
case IRP_MJ_WRITE:
|
|
ParWriteIrp(Pdx);
|
|
break;
|
|
|
|
case IRP_MJ_READ:
|
|
ParReadIrp(Pdx);
|
|
break;
|
|
|
|
default:
|
|
ParDeviceIo(Pdx);
|
|
break;
|
|
}
|
|
|
|
if (!Pdx->Connected && !Pdx->AllocatedByLockPort) {
|
|
|
|
// if we're not connected in a 1284 mode, then release host port
|
|
// otherwise let the watchdog timer do it.
|
|
|
|
ParFreePort(Pdx);
|
|
}
|
|
|
|
CompleteIrp:
|
|
|
|
IoAcquireCancelSpinLock(&CancelIrql);
|
|
Pdx->CurrentOpIrp = NULL;
|
|
IoReleaseCancelSpinLock(CancelIrql);
|
|
|
|
P4CompleteRequest( Irp, Irp->IoStatus.Status, Irp->IoStatus.Information );
|
|
|
|
return;
|
|
}
|