NT4/private/ntos/dd/digibrd/fep5/wait.c
2020-09-30 17:12:29 +02:00

400 lines
12 KiB
C
Raw 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.

/*++
*****************************************************************************
* *
* This software contains proprietary and confidential information of *
* *
* Digi International Inc. *
* *
* By accepting transfer of this copy, Recipient agrees to retain this *
* software in confidence, to prevent disclosure to others, and to make *
* no use of this software other than that for which it was delivered. *
* This is an unpublished copyrighted work of Digi International Inc. *
* Except as permitted by federal law, 17 USC 117, copying is strictly *
* prohibited. *
* *
*****************************************************************************
Module Name:
wait.c
Abstract:
This module contains the NT routines responsible for supplying
the proper behavior assoicated with Wait events.
Revision History:
* $Log: /Components/Windows/NT/Async/FEP5/wait.c $
*
* 1 3/04/96 12:21p Stana
* Module is responsible for handling Wait on Event requested from user
* applications.
*
* Revision 1.12.3.2 1995/11/28 12:49:32 dirkh
* Adopt common header file.
*
* Revision 1.12.3.1 1995/09/05 13:32:48 dirkh
* Minimize spin lock windows, especially IoCancel.
*
* Revision 1.12 1994/08/03 23:28:18 rik
* changed dbg string from unicode to C string. Unicode strings caused
* NT to bug check at DPC level.
*
* Revision 1.11 1993/10/06 11:03:04 rik
* added debugging output.
*
* Revision 1.10 1993/07/16 10:25:32 rik
* Fixed problem with window which could screw up event notification.
* Was most noticable when running Win16 applications.
*
* Revision 1.9 1993/06/06 14:10:31 rik
* Moved where I set a field in a Irp in the CancelCurrentWait routine. Moved
* it within a section of code that still has the Cancel spinlock held.
*
* Revision 1.8 1993/05/18 05:21:47 rik
* Fixed a problem with not releasing the Device extension spinlock BEFORE
* calling IoCompleteRequest.
*
* Revision 1.7 1993/05/09 09:36:39 rik
* Took out do-while loop because it wasn't necessary.
*
* Revision 1.6 1993/04/05 19:49:15 rik
* Changed so the StartWaitRequest routine won't get called when completing
* a wait IRP. This is because there is only one outstanding wait IRP at
* any given time.
*
* Revision 1.5 1993/03/08 07:18:50 rik
* Fixed a problem where I wasn't checking whether to satisfy a Wait event
* against the History of events which have occured. Fixed so I am now
* using the History of events to determine if an event is satisfied.
*
* Revision 1.4 1993/02/26 21:15:31 rik
* Made changes on how events are satisfied. I found out that a history needs
* to be kept from the time a SET_WAIT_MASK is recieve, not when you receive
* a WAIT_ON_MASK. Changes were made to support this new fact.
*
* Revision 1.3 1993/02/25 19:12:21 rik
* Added better debugging support for wait requests.
*
* Revision 1.2 1993/01/22 12:46:20 rik
* *** empty log message ***
*
* Revision 1.1 1992/12/10 16:03:34 rik
* Initial revision
*
--*/
#include "header.h"
#ifndef _WAIT_DOT_C
# define _WAIT_DOT_C
static char RCSInfo_WaitDotC[] = "$Header: /Components/Windows/NT/Async/FEP5/wait.c 1 3/04/96 12:21p Stana $";
#endif
/****************************************************************************/
/* Local Prototypes */
/****************************************************************************/
VOID DigiCancelCurrentWait( PDEVICE_OBJECT DeviceObject, PIRP Irp );
NTSTATUS StartWaitRequest( IN PDIGI_CONTROLLER_EXTENSION ControllerExt,
IN PDIGI_DEVICE_EXTENSION DeviceExt,
IN PKIRQL pOldIrql )
/*++
Routine Description:
This routine assumes the head of the DeviceExt->WaitQueue is the current
Irp to process. We will try to process as many of the Irps as
possible until we exhaust the list, or we can't complete the
current Irp.
NOTE: I assume the DeviceExt->ControlAccess spin lock is acquired
before this routine is called.
Arguments:
ControllerExt - a pointer to the controller extension associated with
this wait request.
DeviceExt - a pointer to the device extension associated with this wait
request.
pOldIrql - a pointer to the IRQL associated with the current spin lock
of the device extension.
Return Value:
--*/
{
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
NTSTATUS Status;
KIRQL OldCancelIrql;
PLIST_ENTRY WaitQueue;
DigiDump( (DIGIFLOW|DIGIWAIT), ("DigiBoard: Entering StartWaitRequest\n") );
WaitQueue = &DeviceExt->WaitQueue;
if( IsListEmpty( WaitQueue ) )
{
ASSERT( !IsListEmpty( WaitQueue ) );
return( STATUS_SUCCESS );
}
Irp = CONTAINING_RECORD( WaitQueue->Flink,
IRP,
Tail.Overlay.ListEntry );
IrpSp = IoGetCurrentIrpStackLocation( Irp );
IoAcquireCancelSpinLock( &OldCancelIrql );
IoSetCancelRoutine( Irp, NULL );
IoReleaseCancelSpinLock( OldCancelIrql );
//
// Must be a IOCTL_WAIT_ON_MASK request.
//
ASSERT( (IrpSp->Parameters.DeviceIoControl.IoControlCode ==
IOCTL_SERIAL_WAIT_ON_MASK) );
//
// Check to make sure we didn't receive a zero mask.
//
if( DeviceExt->WaitMask == 0 )
{
DigiDump( DIGIWAIT, (" Invalid WaitMask, completing IRP with STATUS_INVALID_PARAMETER\n"));
RemoveHeadList( WaitQueue );
ASSERT( IsListEmpty( WaitQueue ) );
KeReleaseSpinLock( &DeviceExt->ControlAccess, *pOldIrql );
Irp->IoStatus.Status = Status = STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
DigiIoCompleteRequest( Irp, IO_NO_INCREMENT );
KeAcquireSpinLock( &DeviceExt->ControlAccess, pOldIrql );
}
else
{
// Okay, we need to actually start checking for events
DIGI_INIT_REFERENCE( Irp );
//
// Quick check to make sure this Irp hasn't been cancelled.
//
IoAcquireCancelSpinLock( &OldCancelIrql );
if( Irp->Cancel )
{
IoReleaseCancelSpinLock( OldCancelIrql );
DigiRemoveIrp( &DeviceExt->WaitQueue );
KeReleaseSpinLock( &DeviceExt->ControlAccess, *pOldIrql );
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
DigiIoCompleteRequest( Irp, IO_NO_INCREMENT );
Status = STATUS_CANCELLED;
KeAcquireSpinLock( &DeviceExt->ControlAccess, pOldIrql );
}
else
{
//
// Increment because the CancelRoutine knows about this
// Irp.
//
DIGI_INC_REFERENCE( Irp );
IoSetCancelRoutine( Irp, DigiCancelCurrentWait );
IoReleaseCancelSpinLock( OldCancelIrql );
Status = STATUS_PENDING;
}
}
DigiDump( DIGIFLOW, ("Exiting StartWaitRequest\n") );
return( Status );
} // end StartWaitRequest
VOID DigiCancelCurrentWait( PDEVICE_OBJECT DeviceObject, PIRP Irp )
/*++
Routine Description:
This routine is used to cancel the current wait IRP.
NOTE: The global cancel spin lock is acquired, so don't forget
to release it before returning.
Arguments:
DeviceObject - Pointer to the device object for this device
Irp - Pointer to the IRP to be cancelled.
Return Value:
None.
--*/
{
PDIGI_DEVICE_EXTENSION DeviceExt;
KIRQL OldIrql;
IoReleaseCancelSpinLock( Irp->CancelIrql );
DigiDump( (DIGIFLOW|DIGIWAIT), ("Entering DigiCancelCurrentWait\n") );
DeviceExt = DeviceObject->DeviceExtension;
KeAcquireSpinLock( &DeviceExt->ControlAccess, &OldIrql );
ASSERT( !IsListEmpty( &DeviceExt->WaitQueue ) );
DigiTryToCompleteIrp( DeviceExt, &OldIrql,
STATUS_CANCELLED, &DeviceExt->WaitQueue,
NULL,
NULL,
NULL );
DigiDump( (DIGIFLOW|DIGIWAIT), ("Exiting DigiCancelCurrentWait\n") );
} // end DigiCancelCurrentWait
VOID DigiSatisfyEvent( PDIGI_CONTROLLER_EXTENSION ControllerExt,
PDIGI_DEVICE_EXTENSION DeviceExt,
ULONG EventReason )
/*++
Routine Description:
This routine will complete the current Wait on mask, if the WaitQueue
is not empty.
Arguments:
ControllerExt - pointer to this devices controller extension.
DeviceExt - a pointer to this devices extension.
EventSatisfied - the event which occurred.
Return Value:
None.
--*/
{
KIRQL OldIrql;
PLIST_ENTRY WaitQueue = &DeviceExt->WaitQueue;
PIRP Irp;
DigiDump( (DIGIFLOW|DIGIWAIT), ("Entering DigiSatisfyEvent: port = %s, Wait mask = 0x%x\tEventReason = 0x%x\n",
DeviceExt->DeviceDbgString,
DeviceExt->WaitMask, EventReason) );
KeAcquireSpinLock( &DeviceExt->ControlAccess, &OldIrql );
DeviceExt->HistoryWait |= (DeviceExt->WaitMask & EventReason);
if( !DeviceExt->HistoryWait || IsListEmpty( WaitQueue ) )
{
KeReleaseSpinLock( &DeviceExt->ControlAccess, OldIrql );
DigiDump( (DIGIFLOW|DIGIWAIT), ("Exiting DigiSatisfyEvent. (%d)\n", __LINE__) );
return;
}
#if DBG
DigiDump( DIGIWAIT, (" Wait event satisfied because:\n") );
if( DeviceExt->HistoryWait & SERIAL_EV_RXCHAR )
{
DigiDump( DIGIWAIT, ("\tSERIAL_EV_RXCHAR\n") );
}
if( DeviceExt->HistoryWait & SERIAL_EV_RXFLAG )
{
DigiDump( DIGIWAIT, ("\tSERIAL_EV_RXFLAG\n") );
}
if( DeviceExt->HistoryWait & SERIAL_EV_TXEMPTY )
{
DigiDump( DIGIWAIT, ("\tSERIAL_EV_TXEMPTY\n") );
}
if( DeviceExt->HistoryWait & SERIAL_EV_CTS )
{
DigiDump( DIGIWAIT, ("\tSERIAL_EV_CTS\n") );
}
if( DeviceExt->HistoryWait & SERIAL_EV_DSR )
{
DigiDump( DIGIWAIT, ("\tSERIAL_EV_DSR\n") );
}
if( DeviceExt->HistoryWait & SERIAL_EV_RLSD )
{
DigiDump( DIGIWAIT, ("\tSERIAL_EV_RLSD\n") );
}
if( DeviceExt->HistoryWait & SERIAL_EV_BREAK )
{
DigiDump( DIGIWAIT, ("\tSERIAL_EV_BREAK\n") );
}
if( DeviceExt->HistoryWait & SERIAL_EV_ERR )
{
DigiDump( DIGIWAIT, ("\tSERIAL_EV_ERR\n") );
}
if( DeviceExt->HistoryWait & SERIAL_EV_RING )
{
DigiDump( DIGIWAIT, ("\tSERIAL_EV_RING\n") );
}
if( DeviceExt->HistoryWait & SERIAL_EV_PERR )
{
DigiDump( DIGIWAIT, ("\tSERIAL_EV_PERR\n") );
}
if( DeviceExt->HistoryWait & SERIAL_EV_RX80FULL )
{
DigiDump( DIGIWAIT, ("\tSERIAL_EV_RX80FULL\n") );
}
if( DeviceExt->HistoryWait & SERIAL_EV_EVENT1 )
{
DigiDump( DIGIWAIT, ("\tSERIAL_EV_EVENT1\n") );
}
if( DeviceExt->HistoryWait & SERIAL_EV_EVENT2 )
{
DigiDump( DIGIWAIT, ("\tSERIAL_EV_EVENT2\n") );
}
#endif
//
// We need to complete the current Wait on Mask Irp with the passed
// in event.
//
Irp = CONTAINING_RECORD( WaitQueue->Flink,
IRP,
Tail.Overlay.ListEntry );
Irp->IoStatus.Information = sizeof(ULONG);
*(ULONG *)(Irp->AssociatedIrp.SystemBuffer) = DeviceExt->HistoryWait;
// Clear the HistoryWait
DeviceExt->HistoryWait = 0;
//
// Increment because we know about the Irp.
//
DIGI_INC_REFERENCE( Irp );
DigiTryToCompleteIrp( DeviceExt, &OldIrql,
STATUS_SUCCESS, WaitQueue,
NULL, NULL, NULL );
DigiDump( (DIGIFLOW|DIGIWAIT), ("Exiting DigiSatisfyEvent. (%d)\n", __LINE__) );
} // end DigiSatisfyEvent