410 lines
10 KiB
C
410 lines
10 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
Copyright (c) 1991 Nokia Data Systems AB
|
||
|
||
Module Name:
|
||
|
||
dlctimr.c
|
||
|
||
Abstract:
|
||
|
||
This module implements timer services of NT DLC API.
|
||
|
||
Contents:
|
||
DirTimerSet
|
||
DirTimerCancelGroup
|
||
DirTimerCancel
|
||
SearchTimerCommand
|
||
AbortCommandsWithFlag
|
||
|
||
Author:
|
||
|
||
Antti Saarenheimo 02-Sep-1991
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include <dlc.h>
|
||
|
||
|
||
NTSTATUS
|
||
DirTimerSet(
|
||
IN PIRP pIrp,
|
||
IN PDLC_FILE_CONTEXT pFileContext,
|
||
IN PNT_DLC_PARMS pDlcParms,
|
||
IN ULONG InputBufferLength,
|
||
IN ULONG OutputBufferLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Procedure queues a timer set command to a special timer command
|
||
queue. The timer commands are queue by the cumulative time in
|
||
such way, that only the timer tick needs to decrement (and possibly
|
||
to complete) only the first command in the queue.
|
||
|
||
Arguments:
|
||
|
||
pIrp - current io request packet
|
||
pFileContext - DLC adapter context
|
||
pDlcParms - the current parameter block
|
||
InputBufferLength - the length of input parameters
|
||
OutputBufferLength - the length of output parameters
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS:
|
||
STATUS_SUCCESS
|
||
|
||
--*/
|
||
|
||
{
|
||
PDLC_COMMAND* ppNode;
|
||
PDLC_COMMAND pDlcCommand;
|
||
UINT TimerTicks;
|
||
|
||
UNREFERENCED_PARAMETER(InputBufferLength);
|
||
UNREFERENCED_PARAMETER(OutputBufferLength);
|
||
|
||
//
|
||
// Check the timer value (I don't know what 13107 half seconds
|
||
// means, this is just as in IBM spec).
|
||
//
|
||
|
||
TimerTicks = pDlcParms->Async.Ccb.u.dir.usParameter0 + 1;
|
||
if (TimerTicks > 13108) {
|
||
return DLC_STATUS_TIMER_ERROR;
|
||
}
|
||
|
||
//
|
||
// DIR.TIMER.CANCEL returns wrong error code !!!!
|
||
// (0x0a insted of TIMER_ERROR)
|
||
//
|
||
|
||
pDlcCommand = (PDLC_COMMAND)ALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool);
|
||
|
||
if (pDlcCommand == NULL) {
|
||
return DLC_STATUS_NO_MEMORY;
|
||
}
|
||
|
||
pDlcCommand->Event = 0;
|
||
pDlcCommand->pIrp = pIrp;
|
||
pDlcCommand->StationId = 0;
|
||
pDlcCommand->StationIdMask = (USHORT)(-1);
|
||
pDlcCommand->AbortHandle = pDlcParms->Async.Ccb.pCcbAddress;
|
||
|
||
//
|
||
// find the right place in the list to put this timer
|
||
//
|
||
|
||
for (ppNode = &pFileContext->pTimerQueue; ; ) {
|
||
if (*ppNode == NULL) {
|
||
pDlcCommand->LlcPacket.pNext = NULL;
|
||
break;
|
||
} else if ((*ppNode)->Overlay.TimerTicks >= TimerTicks) {
|
||
(*ppNode)->Overlay.TimerTicks -= TimerTicks;
|
||
pDlcCommand->LlcPacket.pNext = (PLLC_PACKET)*ppNode;
|
||
break;
|
||
} else {
|
||
TimerTicks -= (*ppNode)->Overlay.TimerTicks;
|
||
}
|
||
ppNode = (PDLC_COMMAND *)&(*ppNode)->LlcPacket.pNext;
|
||
}
|
||
*ppNode = pDlcCommand;
|
||
pDlcCommand->Overlay.TimerTicks = TimerTicks;
|
||
return STATUS_PENDING;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DirTimerCancelGroup(
|
||
IN PIRP pIrp,
|
||
IN PDLC_FILE_CONTEXT pFileContext,
|
||
IN PNT_DLC_PARMS pDlcParms,
|
||
IN ULONG InputBufferLength,
|
||
IN ULONG OutputBufferLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Procedure cancels all DirTimerSet commands having the given
|
||
command completion flag.
|
||
|
||
Arguments:
|
||
|
||
pIrp - current io request packet
|
||
pFileContext - DLC adapter context
|
||
pDlcParms - the current parameter block
|
||
InputBufferLength - the length of input parameters
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS:
|
||
STATUS_SUCCESS
|
||
|
||
--*/
|
||
|
||
{
|
||
UNREFERENCED_PARAMETER(pIrp);
|
||
UNREFERENCED_PARAMETER(InputBufferLength);
|
||
UNREFERENCED_PARAMETER(OutputBufferLength);
|
||
|
||
//
|
||
// All terminated DirTimerSet commands are chained to the
|
||
// CCB pointer of this cancel group command.
|
||
// Terminate the link list of the canceled CCBs.
|
||
//
|
||
|
||
pDlcParms->InputCcb.pCcbAddress = NULL;
|
||
AbortCommandsWithFlag(pFileContext,
|
||
pDlcParms->InputCcb.u.ulParameter, // CompletionFlag
|
||
&pDlcParms->InputCcb.pCcbAddress,
|
||
DLC_STATUS_CANCELLED_BY_USER
|
||
);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DirTimerCancel(
|
||
IN PIRP pIrp,
|
||
IN PDLC_FILE_CONTEXT pFileContext,
|
||
IN PNT_DLC_PARMS pDlcParms,
|
||
IN ULONG InputBufferLength,
|
||
IN ULONG OutputBufferLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This primitive cancels the given timer command in a
|
||
special timer queue.
|
||
|
||
Arguments:
|
||
|
||
pIrp - current io request packet
|
||
pFileContext - DLC process specific adapter context
|
||
pDlcParms - the current parameter block
|
||
InputBufferLength - the length of input parameters
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS:
|
||
STATUS_SUCCESS
|
||
DLC_STATUS_TIMER_ERROR
|
||
--*/
|
||
|
||
{
|
||
PDLC_COMMAND pDlcCommand;
|
||
PDLC_COMMAND *ppDlcCommand;
|
||
PVOID pCcbAddress = NULL;
|
||
|
||
UNREFERENCED_PARAMETER(pIrp);
|
||
UNREFERENCED_PARAMETER(InputBufferLength);
|
||
UNREFERENCED_PARAMETER(OutputBufferLength);
|
||
|
||
ppDlcCommand = SearchTimerCommand(&pFileContext->pTimerQueue,
|
||
pDlcParms->DlcCancelCommand.CcbAddress,
|
||
FALSE
|
||
);
|
||
|
||
//
|
||
// if the timer queue is not empty, cancel the timed DLC request else
|
||
// return an error
|
||
//
|
||
|
||
if (ppDlcCommand != NULL && *ppDlcCommand != NULL) {
|
||
pDlcCommand = *ppDlcCommand;
|
||
*ppDlcCommand = (PDLC_COMMAND)pDlcCommand->LlcPacket.pNext;
|
||
|
||
// >>> SNA bug #10126
|
||
//
|
||
// If there's a next timer after the canceled one we need to update
|
||
// it's tick count. Things will go really wrong if the next timer's tick
|
||
// count is 0 (it expires at the same time as the canceled one) because
|
||
// the timer tick routine (LlcEventIndication) first decrements the tick
|
||
// value and then checks if the result is 0.
|
||
//
|
||
if( *ppDlcCommand )
|
||
{
|
||
(*ppDlcCommand)->Overlay.TimerTicks += pDlcCommand->Overlay.TimerTicks;
|
||
if((*ppDlcCommand)->Overlay.TimerTicks == 0)
|
||
{
|
||
(*ppDlcCommand)->Overlay.TimerTicks++;
|
||
}
|
||
}
|
||
// >>> SNA bug #10126
|
||
|
||
#if LLC_DBG
|
||
pDlcCommand->LlcPacket.pNext = NULL;
|
||
#endif
|
||
|
||
CancelDlcCommand(pFileContext,
|
||
pDlcCommand,
|
||
&pCcbAddress,
|
||
DLC_STATUS_CANCELLED_BY_USER,
|
||
TRUE
|
||
);
|
||
return STATUS_SUCCESS;
|
||
} else {
|
||
return DLC_STATUS_TIMER_ERROR;
|
||
}
|
||
}
|
||
|
||
|
||
PDLC_COMMAND*
|
||
SearchTimerCommand(
|
||
IN PDLC_COMMAND *ppQueue,
|
||
IN PVOID pSearchHandle,
|
||
IN BOOLEAN SearchCompletionFlags
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This primitive cancels the given timer command in a
|
||
special timer queue.
|
||
|
||
Arguments:
|
||
|
||
ppQueue - the base address of the command queue
|
||
|
||
pSearchHandle - command completion flag or ccb address of
|
||
the timer command.
|
||
|
||
SearchCompletionFlags - ste TRUE, if we are searching a completion flag
|
||
|
||
Return Value:
|
||
|
||
PDLC_COMMAND * the address of the address of the found timer command
|
||
|
||
--*/
|
||
|
||
{
|
||
PDLC_COMMAND pCmd;
|
||
|
||
for (; *ppQueue != NULL; ppQueue = (PDLC_COMMAND *)&(*ppQueue)->LlcPacket.pNext) {
|
||
|
||
pCmd = *ppQueue;
|
||
|
||
//
|
||
// A Timer command can be cancelled either by its CCB address
|
||
// or by its command completion flag. The boolean flag
|
||
// defines the used search condition.
|
||
// We will rather space than speed optimize the rarely used
|
||
// procedures like this one.
|
||
//
|
||
|
||
if (pSearchHandle
|
||
== (SearchCompletionFlags
|
||
? (PVOID)
|
||
UlongToPtr(((PNT_DLC_CCB)pCmd->pIrp->AssociatedIrp.SystemBuffer)->CommandCompletionFlag)
|
||
: pCmd->AbortHandle)) {
|
||
|
||
return ppQueue;
|
||
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
|
||
VOID
|
||
AbortCommandsWithFlag(
|
||
IN PDLC_FILE_CONTEXT pFileContext,
|
||
IN ULONG CommandCompletionFlag,
|
||
IN OUT PVOID *ppCcbLink,
|
||
IN UINT CancelStatus
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The command cancels all (timer) commands having the given command
|
||
completion flag.
|
||
|
||
Arguments:
|
||
|
||
pFileContext - process specific adapetr context
|
||
|
||
EventMask - the event mask defining the canceled command
|
||
|
||
CommandCompletionFlag - the command completion flag of the canceled
|
||
commands
|
||
|
||
ppCcbLink - the canceled commands are linked by their next CCB pointer
|
||
fields together. The caller must provide the next CCB address
|
||
in this parameter (usually *ppCcbLink == NULL) and the function
|
||
will return the address of the last canceled CCB field.
|
||
|
||
Return Value:
|
||
|
||
DLC_STATUS_TIMER_ERROR - no mathing command was found
|
||
STATUS_SUCCESS - the command was canceled
|
||
|
||
--*/
|
||
|
||
{
|
||
PDLC_COMMAND pDlcCommand;
|
||
PDLC_COMMAND *ppQueue;
|
||
PVOID pNextCcb = NULL;
|
||
|
||
ppQueue = &pFileContext->pTimerQueue;
|
||
|
||
for (;;) {
|
||
|
||
ppQueue = SearchTimerCommand(ppQueue,
|
||
(PVOID)UlongToPtr(CommandCompletionFlag),
|
||
TRUE
|
||
);
|
||
if (ppQueue != NULL) {
|
||
pDlcCommand = *ppQueue;
|
||
*ppQueue = (PDLC_COMMAND)pDlcCommand->LlcPacket.pNext;
|
||
|
||
#if LLC_DBG
|
||
pDlcCommand->LlcPacket.pNext = NULL;
|
||
#endif
|
||
|
||
*ppCcbLink = ((PNT_DLC_PARMS)pDlcCommand->pIrp->AssociatedIrp.SystemBuffer)->Async.Ccb.pCcbAddress;
|
||
|
||
//
|
||
// We must suppress any kind of command
|
||
// completion indications to the applications.
|
||
// It is very intersting to see, if Io- system hangs up
|
||
// because of this modification.
|
||
//
|
||
|
||
pDlcCommand->pIrp->UserEvent = NULL;
|
||
pDlcCommand->pIrp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
|
||
pDlcCommand->pIrp->Overlay.AsynchronousParameters.UserApcContext = NULL;
|
||
CompleteAsyncCommand(pFileContext, CancelStatus, pDlcCommand->pIrp, pNextCcb, FALSE);
|
||
pNextCcb = *ppCcbLink;
|
||
|
||
DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pDlcCommand);
|
||
|
||
} else {
|
||
|
||
//
|
||
// This procedure do not care if we find any commands
|
||
// or not. Everything is ok, when there are no commands
|
||
// in the queue.
|
||
//
|
||
|
||
return;
|
||
}
|
||
}
|
||
}
|