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.
582 lines
13 KiB
582 lines
13 KiB
/*--------------------------------------------------------------------------
|
|
*
|
|
* Copyright (C) Cyclades Corporation, 1997-2001.
|
|
* All rights reserved.
|
|
*
|
|
* Cyclades-Z Port Driver
|
|
*
|
|
* This file: cyzimmed.c
|
|
*
|
|
* Description: This module contains the code related to transmit
|
|
* immediate character operations in the Cyclades-Z
|
|
* Port driver.
|
|
*
|
|
* Notes: This code supports Windows 2000 and Windows XP,
|
|
* x86 and ia64 processors.
|
|
*
|
|
* Complies with Cyclades SW Coding Standard rev 1.3.
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
|
|
/*-------------------------------------------------------------------------
|
|
*
|
|
* Change History
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*
|
|
*
|
|
*--------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
VOID
|
|
CyzGetNextImmediate(
|
|
IN PIRP *CurrentOpIrp,
|
|
IN PLIST_ENTRY QueueToProcess,
|
|
IN PIRP *NewIrp,
|
|
IN BOOLEAN CompleteCurrent,
|
|
IN PCYZ_DEVICE_EXTENSION Extension
|
|
);
|
|
|
|
VOID
|
|
CyzCancelImmediate(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
BOOLEAN
|
|
CyzGiveImmediateToIsr(
|
|
IN PVOID Context
|
|
);
|
|
|
|
BOOLEAN
|
|
CyzGrabImmediateFromIsr(
|
|
IN PVOID Context
|
|
);
|
|
|
|
BOOLEAN
|
|
CyzGiveImmediateToIsr(
|
|
IN PVOID Context
|
|
);
|
|
|
|
BOOLEAN
|
|
CyzGrabImmediateFromIsr(
|
|
IN PVOID Context
|
|
);
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGESER,CyzStartImmediate)
|
|
#pragma alloc_text(PAGESER,CyzGetNextImmediate)
|
|
#pragma alloc_text(PAGESER,CyzCancelImmediate)
|
|
#pragma alloc_text(PAGESER,CyzGiveImmediateToIsr)
|
|
#pragma alloc_text(PAGESER,CyzGrabImmediateFromIsr)
|
|
#endif
|
|
|
|
|
|
VOID
|
|
CyzStartImmediate(
|
|
IN PCYZ_DEVICE_EXTENSION Extension
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will calculate the timeouts needed for the
|
|
write. It will then hand the irp off to the isr. It
|
|
will need to be careful incase the irp has been canceled.
|
|
|
|
Arguments:
|
|
|
|
Extension - A pointer to the serial device extension.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
#ifdef POLL
|
|
KIRQL pollIrql;
|
|
#endif
|
|
LARGE_INTEGER TotalTime;
|
|
BOOLEAN UseATimer;
|
|
SERIAL_TIMEOUTS Timeouts;
|
|
|
|
CYZ_LOCKED_PAGED_CODE();
|
|
|
|
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyzStartImmediate(%X)\n",
|
|
Extension);
|
|
|
|
UseATimer = FALSE;
|
|
Extension->CurrentImmediateIrp->IoStatus.Status = STATUS_PENDING;
|
|
IoMarkIrpPending(Extension->CurrentImmediateIrp);
|
|
|
|
//
|
|
// Calculate the timeout value needed for the
|
|
// request. Note that the values stored in the
|
|
// timeout record are in milliseconds. Note that
|
|
// if the timeout values are zero then we won't start
|
|
// the timer.
|
|
//
|
|
|
|
KeAcquireSpinLock(
|
|
&Extension->ControlLock,
|
|
&OldIrql
|
|
);
|
|
|
|
Timeouts = Extension->Timeouts;
|
|
|
|
KeReleaseSpinLock(
|
|
&Extension->ControlLock,
|
|
OldIrql
|
|
);
|
|
|
|
if (Timeouts.WriteTotalTimeoutConstant ||
|
|
Timeouts.WriteTotalTimeoutMultiplier) {
|
|
|
|
UseATimer = TRUE;
|
|
|
|
//
|
|
// We have some timer values to calculate.
|
|
//
|
|
|
|
TotalTime.QuadPart
|
|
= (LONGLONG)((ULONG)Timeouts.WriteTotalTimeoutMultiplier);
|
|
|
|
TotalTime.QuadPart += Timeouts.WriteTotalTimeoutConstant;
|
|
|
|
TotalTime.QuadPart *= -10000;
|
|
|
|
}
|
|
|
|
//
|
|
// As the irp might be going to the isr, this is a good time
|
|
// to initialize the reference count.
|
|
//
|
|
|
|
SERIAL_INIT_REFERENCE(Extension->CurrentImmediateIrp);
|
|
|
|
//
|
|
// We need to see if this irp should be canceled.
|
|
//
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
if (Extension->CurrentImmediateIrp->Cancel) {
|
|
|
|
PIRP OldIrp = Extension->CurrentImmediateIrp;
|
|
|
|
Extension->CurrentImmediateIrp = NULL;
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
OldIrp->IoStatus.Status = STATUS_CANCELLED;
|
|
OldIrp->IoStatus.Information = 0;
|
|
|
|
CyzCompleteRequest(Extension, OldIrp, 0);
|
|
|
|
} else {
|
|
|
|
//
|
|
// We give the irp to to the isr to write out.
|
|
// We set a cancel routine that knows how to
|
|
// grab the current write away from the isr.
|
|
//
|
|
|
|
IoSetCancelRoutine(
|
|
Extension->CurrentImmediateIrp,
|
|
CyzCancelImmediate
|
|
);
|
|
|
|
//
|
|
// Since the cancel routine knows about the irp we
|
|
// increment the reference count.
|
|
//
|
|
|
|
SERIAL_SET_REFERENCE(
|
|
Extension->CurrentImmediateIrp,
|
|
SERIAL_REF_CANCEL
|
|
);
|
|
|
|
if (UseATimer) {
|
|
|
|
CyzSetTimer(
|
|
&Extension->ImmediateTotalTimer,
|
|
TotalTime,
|
|
&Extension->TotalImmediateTimeoutDpc,
|
|
Extension
|
|
);
|
|
|
|
//
|
|
// Since the timer knows about the irp we increment
|
|
// the reference count.
|
|
//
|
|
|
|
SERIAL_SET_REFERENCE(
|
|
Extension->CurrentImmediateIrp,
|
|
SERIAL_REF_TOTAL_TIMER
|
|
);
|
|
|
|
}
|
|
|
|
#ifdef POLL
|
|
KeAcquireSpinLock(&Extension->PollLock,&pollIrql);
|
|
CyzGiveImmediateToIsr(Extension);
|
|
KeReleaseSpinLock(&Extension->PollLock,pollIrql);
|
|
#else
|
|
KeSynchronizeExecution(
|
|
Extension->Interrupt,
|
|
CyzGiveImmediateToIsr,
|
|
Extension
|
|
);
|
|
#endif
|
|
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
}
|
|
|
|
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyzStartImmediate\n");
|
|
|
|
}
|
|
|
|
VOID
|
|
CyzCompleteImmediate(
|
|
IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemContext1,
|
|
IN PVOID SystemContext2
|
|
)
|
|
|
|
{
|
|
|
|
PCYZ_DEVICE_EXTENSION Extension = DeferredContext;
|
|
KIRQL OldIrql;
|
|
|
|
UNREFERENCED_PARAMETER(SystemContext1);
|
|
UNREFERENCED_PARAMETER(SystemContext2);
|
|
|
|
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyzCompleteImmediate(%X)\n",
|
|
Extension);
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
CyzTryToCompleteCurrent(
|
|
Extension,
|
|
NULL,
|
|
OldIrql,
|
|
STATUS_SUCCESS,
|
|
&Extension->CurrentImmediateIrp,
|
|
NULL,
|
|
NULL,
|
|
&Extension->ImmediateTotalTimer,
|
|
NULL,
|
|
CyzGetNextImmediate,
|
|
SERIAL_REF_ISR
|
|
);
|
|
|
|
CyzDpcEpilogue(Extension, Dpc);
|
|
|
|
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyzCompleteImmediate\n");
|
|
|
|
}
|
|
|
|
VOID
|
|
CyzTimeoutImmediate(
|
|
IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemContext1,
|
|
IN PVOID SystemContext2
|
|
)
|
|
|
|
{
|
|
|
|
PCYZ_DEVICE_EXTENSION Extension = DeferredContext;
|
|
KIRQL OldIrql;
|
|
|
|
UNREFERENCED_PARAMETER(SystemContext1);
|
|
UNREFERENCED_PARAMETER(SystemContext2);
|
|
|
|
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, ">CyzTimeoutImmediate(%X)\n",
|
|
Extension);
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
CyzTryToCompleteCurrent(
|
|
Extension,
|
|
CyzGrabImmediateFromIsr,
|
|
OldIrql,
|
|
STATUS_TIMEOUT,
|
|
&Extension->CurrentImmediateIrp,
|
|
NULL,
|
|
NULL,
|
|
&Extension->ImmediateTotalTimer,
|
|
NULL,
|
|
CyzGetNextImmediate,
|
|
SERIAL_REF_TOTAL_TIMER
|
|
);
|
|
|
|
CyzDpcEpilogue(Extension, Dpc);
|
|
|
|
CyzDbgPrintEx(DPFLTR_TRACE_LEVEL, "<CyzTimeoutImmediate\n");
|
|
}
|
|
|
|
VOID
|
|
CyzGetNextImmediate(
|
|
IN PIRP *CurrentOpIrp,
|
|
IN PLIST_ENTRY QueueToProcess,
|
|
IN PIRP *NewIrp,
|
|
IN BOOLEAN CompleteCurrent,
|
|
IN PCYZ_DEVICE_EXTENSION Extension
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to complete the current immediate
|
|
irp. Even though the current immediate will always
|
|
be completed and there is no queue associated with it,
|
|
we use this routine so that we can try to satisfy
|
|
a wait for transmit queue empty event.
|
|
|
|
Arguments:
|
|
|
|
CurrentOpIrp - Pointer to the pointer that points to the
|
|
current write irp. This should point
|
|
to CurrentImmediateIrp.
|
|
|
|
QueueToProcess - Always NULL.
|
|
|
|
NewIrp - Always NULL on exit to this routine.
|
|
|
|
CompleteCurrent - Should always be true for this routine.
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
#ifdef POLL
|
|
KIRQL pollIrql;
|
|
#endif
|
|
PIRP OldIrp = *CurrentOpIrp;
|
|
|
|
UNREFERENCED_PARAMETER(QueueToProcess);
|
|
UNREFERENCED_PARAMETER(CompleteCurrent);
|
|
CYZ_LOCKED_PAGED_CODE();
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
ASSERT(Extension->TotalCharsQueued >= 1);
|
|
Extension->TotalCharsQueued--;
|
|
|
|
*CurrentOpIrp = NULL;
|
|
*NewIrp = NULL;
|
|
|
|
#ifdef POLL
|
|
KeAcquireSpinLock(&Extension->PollLock,&pollIrql);
|
|
CyzProcessEmptyTransmit(Extension);
|
|
KeReleaseSpinLock(&Extension->PollLock,pollIrql);
|
|
#else
|
|
KeSynchronizeExecution(
|
|
Extension->Interrupt,
|
|
CyzProcessEmptyTransmit,
|
|
Extension
|
|
);
|
|
#endif
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
CyzCompleteRequest(Extension, OldIrp, IO_SERIAL_INCREMENT);
|
|
}
|
|
|
|
VOID
|
|
CyzCancelImmediate(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to cancel a irp that is waiting on
|
|
a comm event.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object for this device
|
|
|
|
Irp - Pointer to the IRP for the current request
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PCYZ_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
|
|
CYZ_LOCKED_PAGED_CODE();
|
|
|
|
CyzTryToCompleteCurrent(
|
|
Extension,
|
|
CyzGrabImmediateFromIsr,
|
|
Irp->CancelIrql,
|
|
STATUS_CANCELLED,
|
|
&Extension->CurrentImmediateIrp,
|
|
NULL,
|
|
NULL,
|
|
&Extension->ImmediateTotalTimer,
|
|
NULL,
|
|
CyzGetNextImmediate,
|
|
SERIAL_REF_CANCEL
|
|
);
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
CyzGiveImmediateToIsr(
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Try to start off the write by slipping it in behind
|
|
a transmit immediate char, or if that isn't available
|
|
and the transmit holding register is empty, "tickle"
|
|
the UART into interrupting with a transmit buffer
|
|
empty.
|
|
|
|
NOTE: This routine is called by KeSynchronizeExecution.
|
|
|
|
NOTE: This routine assumes that it is called with the
|
|
cancel spin lock held.
|
|
|
|
Arguments:
|
|
|
|
Context - Really a pointer to the device extension.
|
|
|
|
Return Value:
|
|
|
|
This routine always returns FALSE.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PCYZ_DEVICE_EXTENSION Extension = Context;
|
|
CYZ_LOCKED_PAGED_CODE();
|
|
|
|
Extension->TransmitImmediate = TRUE;
|
|
Extension->ImmediateChar =
|
|
*((UCHAR *)
|
|
(Extension->CurrentImmediateIrp->AssociatedIrp.SystemBuffer));
|
|
|
|
//
|
|
// The isr now has a reference to the irp.
|
|
//
|
|
|
|
SERIAL_SET_REFERENCE(
|
|
Extension->CurrentImmediateIrp,
|
|
SERIAL_REF_ISR
|
|
);
|
|
|
|
//Removed at 02/07/00 by Fanny. Polling routine will do the transmission.
|
|
// //
|
|
// // Check first to see if a write is going on. If
|
|
// // there is then we'll just slip in during the write.
|
|
// //
|
|
//
|
|
// if (!Extension->WriteLength) {
|
|
//
|
|
// //
|
|
// // If there is no normal write transmitting then we
|
|
// // will "re-enable" the transmit holding register empty
|
|
// // interrupt. The 8250 family of devices will always
|
|
// // signal a transmit holding register empty interrupt
|
|
// // *ANY* time this bit is set to one. By doing things
|
|
// // this way we can simply use the normal interrupt code
|
|
// // to start off this write.
|
|
// //
|
|
// // We've been keeping track of whether the transmit holding
|
|
// // register is empty so it we only need to do this
|
|
// // if the register is empty.
|
|
// //
|
|
//
|
|
// if (Extension->HoldingEmpty) {
|
|
// CyzTxStart(Extension);
|
|
// }
|
|
//
|
|
// }
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
CyzGrabImmediateFromIsr(
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
This routine is used to grab the current irp, which could be timing
|
|
out or canceling, from the ISR
|
|
|
|
NOTE: This routine is being called from KeSynchronizeExecution.
|
|
|
|
NOTE: This routine assumes that the cancel spin lock is held
|
|
when this routine is called.
|
|
|
|
Arguments:
|
|
|
|
Context - Really a pointer to the device extension.
|
|
|
|
Return Value:
|
|
|
|
Always false.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PCYZ_DEVICE_EXTENSION Extension = Context;
|
|
CYZ_LOCKED_PAGED_CODE();
|
|
|
|
if (Extension->TransmitImmediate) {
|
|
|
|
Extension->TransmitImmediate = FALSE;
|
|
|
|
//
|
|
// Since the isr no longer references this irp, we can
|
|
// decrement it's reference count.
|
|
//
|
|
|
|
SERIAL_CLEAR_REFERENCE(
|
|
Extension->CurrentImmediateIrp,
|
|
SERIAL_REF_ISR
|
|
);
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|