Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1343 lines
35 KiB

/*++
Module Name:
read.c
Environment:
Kernel mode
Revision History :
--*/
#include "precomp.h"
NTSTATUS
MoxaRead(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS status;
PMOXA_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
if ((extension->ControlDevice == TRUE)||
(extension->DeviceIsOpened == FALSE) ||
(extension->PowerState != PowerDeviceD0) ) {
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information=0L;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_CANCELLED;
}
// MoxaKdPrint(MX_DBG_TRACE,("Enter MoxaRead\n"));
if ((status = MoxaIRPPrologue(Irp, extension)) != STATUS_SUCCESS) {
MoxaCompleteRequest(extension, Irp, IO_NO_INCREMENT);
return status;
}
if (MoxaCompleteIfError(
DeviceObject,
Irp
) != STATUS_SUCCESS) {
return STATUS_CANCELLED;
}
Irp->IoStatus.Information = 0L;
//
// Quick check for a zero length read. If it is zero length
// then we are already done!
//
if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length) {
//
// Well it looks like we actually have to do some
// work. Put the read on the queue so that we can
// process it when our previous reads are done.
//
return MoxaStartOrQueue(
extension,
Irp,
&extension->ReadQueue,
&extension->CurrentReadIrp,
MoxaStartRead
);
} else {
Irp->IoStatus.Status = STATUS_SUCCESS;
MoxaCompleteRequest(extension, Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
}
BOOLEAN
MoxaLineInput(
IN PVOID Context
)
{
PMOXA_DEVICE_EXTENSION extension = Context;
PIO_STACK_LOCATION irpSp;
irpSp = IoGetCurrentIrpStackLocation(extension->CurrentReadIrp);
LIterminater = *(PUCHAR)extension->CurrentReadIrp->AssociatedIrp.SystemBuffer;
LIbufferSize = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
LIdataBuffer = (PUCHAR)extension->CurrentReadIrp->AssociatedIrp.SystemBuffer;
LIbase = extension->PortBase;
LIofs = extension->PortOfs;
LIbuff = LIbase + DynPage_addr;
LIrptr = (PUSHORT)(LIofs + RXrptr);
LIwptr = (PUSHORT)(LIofs + RXwptr);
LIrxMask = *(PUSHORT)(LIofs + RX_mask);
LIspage = *(PUSHORT)(LIofs + Page_rxb);
LIepage = *(PUSHORT)(LIofs + EndPage_rxb);
LIhead = *LIrptr;
LItail = *LIwptr;
LIcount = (LItail >= LIhead) ? (LItail - LIhead)
: (LItail - LIhead + LIrxMask + 1);
if (!LIcount) /* Rx buffer no data! */
return FALSE;
if (LIspage == LIepage) {
LIbufHead = *(PUSHORT)(LIofs + Ofs_rxb);
*(LIbase + Control_reg) = (UCHAR)LIspage;
LIi = 0;
do {
LIi++;
*LIdataBuffer = LIbuff[LIbufHead+LIhead++];
LIhead &= LIrxMask;
if (*LIdataBuffer == LIterminater)
break;
LIdataBuffer++;
// if (LIhead == *LIwptr)
if ( (LIhead == *LIwptr) && (LIi < LIbufferSize) )
return FALSE;
} while (LIi < LIbufferSize);
}
else {
LIpageNo = LIspage + (LIhead >> 13);
LIpageOfs = LIhead & Page_mask;
*(LIbase + Control_reg) = (UCHAR)LIpageNo;
LIi = 0;
do {
LIi++;
*LIdataBuffer = LIbuff[LIpageOfs++];
LIhead++;
LIhead &= LIrxMask;
if (*LIdataBuffer == LIterminater)
break;
LIdataBuffer++;
// if (LIhead == *LIwptr)
if ( (LIhead == *LIwptr) && (LIi < LIbufferSize) )
return FALSE;
if (LIpageOfs == Page_size) {
if (++LIpageNo == LIepage)
LIpageNo = LIspage;
*(LIbase + Control_reg) = (UCHAR)LIpageNo;
LIpageOfs = 0;
}
} while (LIi < LIbufferSize);
}
*LIrptr = LIhead;
extension->CurrentReadIrp->IoStatus.Information = LIi;
extension->PerfStats.ReceivedCount += LIi;
if (*(LIofs + FlagStat) & Rx_xoff) {
LIcount = (*LIwptr >= *LIrptr) ? (*LIwptr - *LIrptr)
: (*LIwptr - *LIrptr + LIrxMask + 1);
if (LIcount < extension->HandFlow.XonLimit)
MoxaFuncWithDumbWait(LIofs, FC_SendXon, 0);
}
return FALSE;
}
BOOLEAN
MoxaView(
IN PVOID Context
)
{
PMOXA_DEVICE_EXTENSION extension = Context;
PIO_STACK_LOCATION irpSp;
irpSp = IoGetCurrentIrpStackLocation(extension->CurrentReadIrp);
LIbufferSize = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
LIdataBuffer = (PUCHAR)extension->CurrentReadIrp->AssociatedIrp.SystemBuffer;
LIbase = extension->PortBase;
LIofs = extension->PortOfs;
LIbuff = LIbase + DynPage_addr;
LIrptr = (PUSHORT)(LIofs + RXrptr);
LIwptr = (PUSHORT)(LIofs + RXwptr);
LIrxMask = *(PUSHORT)(LIofs + RX_mask);
LIspage = *(PUSHORT)(LIofs + Page_rxb);
LIepage = *(PUSHORT)(LIofs + EndPage_rxb);
LIhead = *LIrptr;
LItail = *LIwptr;
LIcount = (LItail >= LIhead) ? (LItail - LIhead)
: (LItail - LIhead + LIrxMask + 1);
if (!LIcount) /* Rx buffer no data! */
return FALSE;
if (LIcount > LIbufferSize)
LIcount = (USHORT)LIbufferSize;
LIlen = (USHORT)LIcount;
if (LIspage == LIepage) {
LIbufHead = *(PUSHORT)(LIofs + Ofs_rxb);
*(LIbase + Control_reg) = (UCHAR)LIspage;
if (LIhead & 1) {
*LIdataBuffer++ = LIbuff[LIbufHead+LIhead++];
LIhead &= LIrxMask;
LIcount--;
}
LIcount2 = LIcount >> 1;
while (LIcount2--) {
*((PUSHORT)LIdataBuffer)++ = *(PUSHORT)&(LIbuff[LIbufHead+LIhead]);
LIhead += 2;
LIhead &= LIrxMask;
}
if (LIcount & 1) {
*LIdataBuffer++ = LIbuff[LIbufHead+LIhead++];
LIhead &= LIrxMask;
}
}
else {
LIpageNo = LIspage + (LIhead >> 13);
LIpageOfs = LIhead & Page_mask;
do {
LIcnt = Page_size - LIpageOfs;
if (LIcnt > LIcount)
LIcnt = LIcount;
LIcount -= LIcnt;
if (LIcnt) {
*(LIbase + Control_reg) = (UCHAR)LIpageNo;
if (LIpageOfs & 1) {
*LIdataBuffer++ = LIbuff[LIpageOfs++];
LIcnt--;
}
LIcount2 = LIcnt >> 1;
while (LIcount2--) {
*((PUSHORT)LIdataBuffer)++ = *(PUSHORT)&(LIbuff[LIpageOfs]);
LIpageOfs += 2;
}
if (LIcnt & 1)
*LIdataBuffer++ = LIbuff[LIpageOfs++];
}
if (LIcount == 0)
break;
if (++LIpageNo == LIepage)
LIpageNo = LIspage;
LIpageOfs = 0;
} while (TRUE);
}
extension->CurrentReadIrp->IoStatus.Information = LIlen;
return FALSE;
}
BOOLEAN
MoxaIn(
IN PVOID Context
)
{
PMOXA_DEVICE_EXTENSION extension = Context;
extension->ReadCurrentChar = extension->CurrentReadIrp->AssociatedIrp.SystemBuffer;
MoxaGetData(extension);
return FALSE;
}
VOID
MoxaGetData(
IN PMOXA_DEVICE_EXTENSION Extension
)
{
//KdPrint(("In MoxaGetData\n"));
GDbase = Extension->PortBase;
GDofs = Extension->PortOfs;
GDbuff = GDbase + DynPage_addr;
GDrptr = (PUSHORT)(GDofs + RXrptr);
GDwptr = (PUSHORT)(GDofs + RXwptr);
GDrxMask = *(PUSHORT)(GDofs + RX_mask);
GDspage = *(PUSHORT)(GDofs + Page_rxb);
GDepage = *(PUSHORT)(GDofs + EndPage_rxb);
GDhead = *GDrptr;
GDtail = *GDwptr;
GDdataLen = Extension->NumberNeededForRead;
GDreadChar = Extension->ReadCurrentChar;
GDcount = (GDtail >= GDhead) ? (GDtail - GDhead)
: (GDtail - GDhead + GDrxMask + 1);
if (!GDcount) /* Rx buffer no data! */
return;
if (GDspage == GDepage) {
GDbufHead = *(PUSHORT)(GDofs + Ofs_rxb);
if (GDcount > GDdataLen)
GDcount = (USHORT)GDdataLen;
GDdataLen -= GDcount;
GDlen = GDcount;
*(GDbase + Control_reg) = (UCHAR)GDspage;
if (GDhead & 1) {
*GDreadChar++ = GDbuff[GDbufHead+GDhead++];
GDhead &= GDrxMask;
GDcount--;
}
GDcount2 = GDcount >> 1;
while (GDcount2--) {
*((PUSHORT)GDreadChar)++ = *(PUSHORT)&(GDbuff[GDbufHead+GDhead]);
GDhead += 2;
GDhead &= GDrxMask;
}
if (GDcount & 1) {
*GDreadChar++ = GDbuff[GDbufHead+GDhead++];
GDhead &= GDrxMask;
}
*GDrptr = GDhead;
}
else {
if (GDcount > GDdataLen)
GDcount = (USHORT)GDdataLen;
GDdataLen -= GDcount;
GDlen = GDcount;
GDpageNo = GDspage + (GDhead >> 13);
GDpageOfs = GDhead & Page_mask;
do {
GDcnt = Page_size - GDpageOfs;
if (GDcnt > GDcount)
GDcnt = GDcount;
GDcount -= GDcnt;
if (GDcnt) {
*(GDbase + Control_reg) = (UCHAR)GDpageNo;
if (GDpageOfs & 1) {
*GDreadChar++ = GDbuff[GDpageOfs++];
GDcnt--;
}
GDcount2 = GDcnt >> 1;
while (GDcount2--) {
*((PUSHORT)GDreadChar)++ = *(PUSHORT)&(GDbuff[GDpageOfs]);
GDpageOfs += 2;
}
if (GDcnt & 1)
*GDreadChar++ = GDbuff[GDpageOfs++];
}
if (GDcount == 0)
break;
if (++GDpageNo == GDepage)
GDpageNo = GDspage;
GDpageOfs = 0;
} while (TRUE);
*GDrptr = (GDhead + GDlen) & GDrxMask;
}
Extension->NumberNeededForRead = GDdataLen;
Extension->ReadCurrentChar = GDreadChar;
Extension->CurrentReadIrp->IoStatus.Information += GDlen;
Extension->PerfStats.ReceivedCount += GDlen;
if (*(GDofs + FlagStat) & Rx_xoff) {
GDcount = (*GDwptr >= *GDrptr) ? (*GDwptr - *GDrptr)
: (*GDwptr - *GDrptr + GDrxMask + 1);
if (GDcount < Extension->HandFlow.XonLimit)
MoxaFuncWithDumbWait(GDofs, FC_SendXon, 0);
}
}
BOOLEAN
MoxaInSwitchToUser(
IN PVOID Context
)
{
PMOXA_DEVICE_EXTENSION extension = Context;
USHORT max;
*(PUSHORT)(extension->PortOfs + Rx_trigger) = 1;
*(PUSHORT)(extension->PortOfs + HostStat) |= WakeupRxTrigger;
MoxaGetData(extension);
extension->ReadLength = extension->NumberNeededForRead;
if (extension->NumberNeededForRead) {
/* 8-14-01 by William
max = *(PUSHORT)(extension->PortOfs + RX_mask) - 128;
*/
max = *(PUSHORT)(extension->PortOfs + RX_mask) - RX_offset;
if (extension->NumberNeededForRead > max)
*(PUSHORT)(extension->PortOfs + Rx_trigger) = max;
else
*(PUSHORT)(extension->PortOfs + Rx_trigger) = (USHORT)extension->NumberNeededForRead;
MOXA_INC_REFERENCE(extension->CurrentReadIrp);
extension->CountOnLastRead =
extension->CurrentReadIrp->IoStatus.Information;
extension->ReadByIsr = 0;
IoSetCancelRoutine(
extension->CurrentReadIrp,
MoxaCancelCurrentRead
);
MOXA_INC_REFERENCE(extension->CurrentReadIrp);
}
else
*(PSHORT)(extension->PortOfs + HostStat) &= ~WakeupRxTrigger;
return FALSE;
}
NTSTATUS
MoxaStartRead(
IN PMOXA_DEVICE_EXTENSION Extension
)
{
PIO_STACK_LOCATION irpSp;
PIRP newIrp;
KIRQL oldIrql;
KIRQL controlIrql;
BOOLEAN returnWithWhatsPresent;
BOOLEAN os2ssreturn;
BOOLEAN crunchDownToOne;
BOOLEAN useTotalTimer;
BOOLEAN useIntervalTimer;
ULONG ioControlCode;
ULONG multiplierVal;
ULONG constantVal;
LARGE_INTEGER totalTime;
SERIAL_TIMEOUTS timeoutsForIrp;
BOOLEAN setFirstStatus = FALSE;
NTSTATUS firstStatus;
do {
irpSp = IoGetCurrentIrpStackLocation(Extension->CurrentReadIrp);
//
// Check if MOXA_IOCTL_xxx request
//
if (irpSp->MajorFunction != IRP_MJ_READ) {
KeAcquireSpinLock(
&Extension->ControlLock,
&controlIrql
);
IoAcquireCancelSpinLock(&oldIrql);
if (Extension->CurrentReadIrp->Cancel) {
Extension->CurrentReadIrp->IoStatus.Status =
STATUS_CANCELLED;
IoReleaseCancelSpinLock(oldIrql);
KeReleaseSpinLock(
&Extension->ControlLock,
controlIrql
);
if (!setFirstStatus) {
firstStatus = STATUS_CANCELLED;
setFirstStatus = TRUE;
}
}
else {
ioControlCode =
irpSp->Parameters.DeviceIoControl.IoControlCode;
if (ioControlCode == IOCTL_MOXA_LineInput)
KeSynchronizeExecution(
Extension->Interrupt,
MoxaLineInput,
Extension
);
else
KeSynchronizeExecution(
Extension->Interrupt,
MoxaView,
Extension
);
Extension->CurrentReadIrp->IoStatus.Status = STATUS_SUCCESS;
IoReleaseCancelSpinLock(oldIrql);
KeReleaseSpinLock(
&Extension->ControlLock,
controlIrql
);
if (!setFirstStatus) {
firstStatus = STATUS_SUCCESS;
setFirstStatus = TRUE;
}
}
}
else {
Extension->NumberNeededForRead =
IoGetCurrentIrpStackLocation(Extension->CurrentReadIrp)
->Parameters.Read.Length;
useTotalTimer = FALSE;
returnWithWhatsPresent = FALSE;
os2ssreturn = FALSE;
crunchDownToOne = FALSE;
useIntervalTimer = FALSE;
KeAcquireSpinLock(
&Extension->ControlLock,
&controlIrql
);
timeoutsForIrp = Extension->Timeouts;
KeReleaseSpinLock(
&Extension->ControlLock,
controlIrql
);
//
// Calculate the interval timeout for the read.
//
if (timeoutsForIrp.ReadIntervalTimeout &&
(timeoutsForIrp.ReadIntervalTimeout !=
MAXULONG)) {
useIntervalTimer = TRUE;
Extension->IntervalTime.QuadPart =
UInt32x32To64(
timeoutsForIrp.ReadIntervalTimeout,
10000
);
if (Extension->IntervalTime.QuadPart >=
Extension->CutOverAmount.QuadPart) {
Extension->IntervalTimeToUse =
&Extension->LongIntervalAmount;
} else {
Extension->IntervalTimeToUse =
&Extension->ShortIntervalAmount;
}
}
if (timeoutsForIrp.ReadIntervalTimeout == MAXULONG) {
//
// We need to do special return quickly stuff here.
//
// 1) If both constant and multiplier are
// 0 then we return immediately with whatever
// we've got, even if it was zero.
//
// 2) If constant and multiplier are not MAXULONG
// then return immediately if any characters
// are present, but if nothing is there, then
// use the timeouts as specified.
//
// 3) If multiplier is MAXULONG then do as in
// "2" but return when the first character
// arrives.
//
if (!timeoutsForIrp.ReadTotalTimeoutConstant &&
!timeoutsForIrp.ReadTotalTimeoutMultiplier) {
returnWithWhatsPresent = TRUE;
} else if ((timeoutsForIrp.ReadTotalTimeoutConstant != MAXULONG)
&&
(timeoutsForIrp.ReadTotalTimeoutMultiplier
!= MAXULONG)) {
useTotalTimer = TRUE;
os2ssreturn = TRUE;
multiplierVal = timeoutsForIrp.ReadTotalTimeoutMultiplier;
constantVal = timeoutsForIrp.ReadTotalTimeoutConstant;
} else if ((timeoutsForIrp.ReadTotalTimeoutConstant != MAXULONG)
&&
(timeoutsForIrp.ReadTotalTimeoutMultiplier
== MAXULONG)) {
useTotalTimer = TRUE;
os2ssreturn = TRUE;
crunchDownToOne = TRUE;
multiplierVal = 0;
constantVal = timeoutsForIrp.ReadTotalTimeoutConstant;
}
} else {
//
// If both the multiplier and the constant are
// zero then don't do any total timeout processing.
//
if (timeoutsForIrp.ReadTotalTimeoutMultiplier ||
timeoutsForIrp.ReadTotalTimeoutConstant) {
//
// We have some timer values to calculate.
//
useTotalTimer = TRUE;
multiplierVal = timeoutsForIrp.ReadTotalTimeoutMultiplier;
constantVal = timeoutsForIrp.ReadTotalTimeoutConstant;
}
}
if (useTotalTimer) {
totalTime.QuadPart = ((LONGLONG)(UInt32x32To64(
Extension->NumberNeededForRead,
multiplierVal
)
+ constantVal))
* -10000;
}
KeAcquireSpinLock(
&Extension->ControlLock,
&controlIrql
);
MOXA_INIT_REFERENCE(Extension->CurrentReadIrp);
IoAcquireCancelSpinLock(&oldIrql);
if (Extension->CurrentReadIrp->Cancel) {
Extension->CurrentReadIrp->IoStatus.Status =
STATUS_CANCELLED;
Extension->CurrentReadIrp->IoStatus.Information = 0;
IoReleaseCancelSpinLock(oldIrql);
KeReleaseSpinLock(
&Extension->ControlLock,
controlIrql
);
if (!setFirstStatus) {
firstStatus = STATUS_CANCELLED;
setFirstStatus = TRUE;
}
}
else {
KeSynchronizeExecution(
Extension->Interrupt,
MoxaIn,
Extension
);
if (returnWithWhatsPresent || (!Extension->NumberNeededForRead) ||
(os2ssreturn &&
Extension->CurrentReadIrp->IoStatus.Information)) {
//
// We got all we needed for this read.
//
Extension->CurrentReadIrp->IoStatus.Status = STATUS_SUCCESS;
IoReleaseCancelSpinLock(oldIrql);
KeReleaseSpinLock(
&Extension->ControlLock,
controlIrql
);
if (!setFirstStatus) {
firstStatus = STATUS_SUCCESS;
setFirstStatus = TRUE;
}
}
else {
//
// If we are supposed to crunch the read down to
// one character, then update the read length
// in the irp and truncate the number needed for
// read down to one. Note that if we are doing
// this crunching, then the information must be
// zero (or we would have completed above) and
// the number needed for the read must still be
// equal to the read length.
//
if (crunchDownToOne) {
Extension->NumberNeededForRead = 1;
IoGetCurrentIrpStackLocation(
Extension->CurrentReadIrp
)->Parameters.Read.Length = 1;
}
KeSynchronizeExecution(
Extension->Interrupt,
MoxaInSwitchToUser,
Extension
);
if (Extension->NumberNeededForRead) {
if (useTotalTimer) {
MOXA_INC_REFERENCE(Extension->CurrentReadIrp);
MoxaSetTimer(
&Extension->ReadRequestTotalTimer,
totalTime,
&Extension->TotalReadTimeoutDpc,
Extension
);
}
if (useIntervalTimer) {
MOXA_INC_REFERENCE(Extension->CurrentReadIrp);
KeQuerySystemTime(
&Extension->LastReadTime
);
MoxaSetTimer(
&Extension->ReadRequestIntervalTimer,
*Extension->IntervalTimeToUse,
&Extension->IntervalReadTimeoutDpc,
Extension
);
}
IoMarkIrpPending(Extension->CurrentReadIrp);
IoReleaseCancelSpinLock(oldIrql);
KeReleaseSpinLock(
&Extension->ControlLock,
controlIrql
);
if (!setFirstStatus) {
firstStatus = STATUS_PENDING;
}
return firstStatus;
} else {
Extension->CurrentReadIrp->IoStatus.Status =
STATUS_SUCCESS;
IoReleaseCancelSpinLock(oldIrql);
KeReleaseSpinLock(
&Extension->ControlLock,
controlIrql
);
if (!setFirstStatus) {
firstStatus = STATUS_SUCCESS;
setFirstStatus = TRUE;
}
}
}
}
}
//
// Well the operation is complete.
//
MoxaGetNextIrp(
&Extension->CurrentReadIrp,
&Extension->ReadQueue,
&newIrp,
TRUE,
Extension
);
} while (newIrp);
return firstStatus;
}
VOID
MoxaCancelCurrentRead(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
{
PMOXA_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
extension->CountOnLastRead = MOXA_COMPLETE_READ_CANCEL;
MoxaTryToCompleteCurrent(
extension,
MoxaGrabReadFromIsr,
Irp->CancelIrql,
STATUS_CANCELLED,
&extension->CurrentReadIrp,
&extension->ReadQueue,
&extension->ReadRequestIntervalTimer,
&extension->ReadRequestTotalTimer,
MoxaStartRead,
MoxaGetNextIrp
);
}
BOOLEAN
MoxaGrabReadFromIsr(
IN PVOID Context
)
{
PMOXA_DEVICE_EXTENSION extension = Context;
if (extension->ReadLength) {
extension->CurrentReadIrp->IoStatus.Information =
IoGetCurrentIrpStackLocation(
extension->CurrentReadIrp
)->Parameters.Read.Length -
extension->ReadLength;
*(PSHORT)(extension->PortOfs + HostStat) &= ~WakeupRxTrigger;
extension->ReadLength = 0;
MOXA_DEC_REFERENCE(extension->CurrentReadIrp);
}
return FALSE;
}
VOID
MoxaCompleteRead(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemContext1,
IN PVOID SystemContext2
)
{
PMOXA_DEVICE_EXTENSION extension = DeferredContext;
KIRQL oldIrql;
IoAcquireCancelSpinLock(&oldIrql);
extension->CountOnLastRead = MOXA_COMPLETE_READ_COMPLETE;
MoxaTryToCompleteCurrent(
extension,
NULL,
oldIrql,
STATUS_SUCCESS,
&extension->CurrentReadIrp,
&extension->ReadQueue,
&extension->ReadRequestIntervalTimer,
&extension->ReadRequestTotalTimer,
MoxaStartRead,
MoxaGetNextIrp
);
MoxaDpcEpilogue(extension, Dpc);
}
VOID
MoxaReadTimeout(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemContext1,
IN PVOID SystemContext2
)
{
PMOXA_DEVICE_EXTENSION extension = DeferredContext;
KIRQL oldIrql;
IoAcquireCancelSpinLock(&oldIrql);
if (extension->CountOnLastRead == MOXA_COMPLETE_READ_COMPLETE) {
MoxaTryToCompleteCurrent(
extension,
NULL,
oldIrql,
STATUS_SUCCESS,
&extension->CurrentReadIrp,
&extension->ReadQueue,
&extension->ReadRequestIntervalTimer,
&extension->ReadRequestTotalTimer,
MoxaStartRead,
MoxaGetNextIrp
);
MoxaDpcEpilogue(extension, Dpc);
return;
}
if (MoxaCheckInQueue(extension)) {
KeSynchronizeExecution(
extension->Interrupt,
MoxaPollGetData,
extension
);
if (!extension->ReadLength) {
extension->CountOnLastRead = MOXA_COMPLETE_READ_COMPLETE;
MOXA_DEC_REFERENCE(extension->CurrentReadIrp);
MoxaTryToCompleteCurrent(
extension,
NULL,
oldIrql,
STATUS_SUCCESS,
&extension->CurrentReadIrp,
&extension->ReadQueue,
&extension->ReadRequestIntervalTimer,
&extension->ReadRequestTotalTimer,
MoxaStartRead,
MoxaGetNextIrp
);
MoxaDpcEpilogue(extension, Dpc);
return;
}
}
extension->CountOnLastRead = MOXA_COMPLETE_READ_TOTAL;
MoxaTryToCompleteCurrent(
extension,
MoxaGrabReadFromIsr,
oldIrql,
STATUS_TIMEOUT,
&extension->CurrentReadIrp,
&extension->ReadQueue,
&extension->ReadRequestIntervalTimer,
&extension->ReadRequestTotalTimer,
MoxaStartRead,
MoxaGetNextIrp
);
MoxaDpcEpilogue(extension, Dpc);
}
VOID
MoxaIntervalReadTimeout(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemContext1,
IN PVOID SystemContext2
)
{
PMOXA_DEVICE_EXTENSION extension = DeferredContext;
KIRQL oldIrql;
USHORT count;
/*
PUCHAR base;
base = extension->PortBase;
*/
IoAcquireCancelSpinLock(&oldIrql);
if (extension->CountOnLastRead == MOXA_COMPLETE_READ_TOTAL) {
MoxaTryToCompleteCurrent(
extension,
MoxaGrabReadFromIsr,
oldIrql,
STATUS_TIMEOUT,
&extension->CurrentReadIrp,
&extension->ReadQueue,
&extension->ReadRequestIntervalTimer,
&extension->ReadRequestTotalTimer,
MoxaStartRead,
MoxaGetNextIrp
);
}
else if (extension->CountOnLastRead == MOXA_COMPLETE_READ_COMPLETE) {
MoxaTryToCompleteCurrent(
extension,
NULL,
oldIrql,
STATUS_SUCCESS,
&extension->CurrentReadIrp,
&extension->ReadQueue,
&extension->ReadRequestIntervalTimer,
&extension->ReadRequestTotalTimer,
MoxaStartRead,
MoxaGetNextIrp
);
}
else if (extension->CountOnLastRead == MOXA_COMPLETE_READ_CANCEL) {
MoxaTryToCompleteCurrent(
extension,
MoxaGrabReadFromIsr,
oldIrql,
STATUS_CANCELLED,
&extension->CurrentReadIrp,
&extension->ReadQueue,
&extension->ReadRequestIntervalTimer,
&extension->ReadRequestTotalTimer,
MoxaStartRead,
MoxaGetNextIrp
);
}
else {
if (extension->CountOnLastRead) {
//base[0x300]++;
IRTofs = extension->PortOfs;
IRTrptr = (PUSHORT)(IRTofs + RXrptr);
IRTwptr = (PUSHORT)(IRTofs + RXwptr);
IRTrxMask = *(PUSHORT)(IRTofs + RX_mask);
count = (*IRTwptr >= *IRTrptr) ? (*IRTwptr - *IRTrptr)
: (*IRTwptr - *IRTrptr + IRTrxMask + 1);
if (count > extension->ReadByIsr) {
//base[0x301]++;
extension->ReadByIsr = count;
KeQuerySystemTime(
&extension->LastReadTime
);
MoxaSetTimer(
&extension->ReadRequestIntervalTimer,
*extension->IntervalTimeToUse,
&extension->IntervalReadTimeoutDpc,
extension
);
IoReleaseCancelSpinLock(oldIrql);
}
else {
LARGE_INTEGER currentTime;
//base[0x302]++;
KeQuerySystemTime(
&currentTime
);
if ((currentTime.QuadPart - extension->LastReadTime.QuadPart) >=
extension->IntervalTime.QuadPart) {
//base[0x303]++;
if (MoxaCheckInQueue(extension)) {
//base[0x304]++;
KeSynchronizeExecution(
extension->Interrupt,
MoxaPollGetData,
extension
);
if (!extension->ReadLength) {
//base[0x305]++;
extension->CountOnLastRead =
MOXA_COMPLETE_READ_COMPLETE;
MOXA_DEC_REFERENCE(extension->CurrentReadIrp);
MoxaTryToCompleteCurrent(
extension,
NULL,
oldIrql,
STATUS_SUCCESS,
&extension->CurrentReadIrp,
&extension->ReadQueue,
&extension->ReadRequestIntervalTimer,
&extension->ReadRequestTotalTimer,
MoxaStartRead,
MoxaGetNextIrp
);
MoxaDpcEpilogue(extension, Dpc);
return;
}
}
//base[0x306]++;
MoxaTryToCompleteCurrent(
extension,
MoxaGrabReadFromIsr,
oldIrql,
STATUS_TIMEOUT,
&extension->CurrentReadIrp,
&extension->ReadQueue,
&extension->ReadRequestIntervalTimer,
&extension->ReadRequestTotalTimer,
MoxaStartRead,
MoxaGetNextIrp
);
}
else {
//base[0x307]++;
MoxaSetTimer(
&extension->ReadRequestIntervalTimer,
*extension->IntervalTimeToUse,
&extension->IntervalReadTimeoutDpc,
extension
);
IoReleaseCancelSpinLock(oldIrql);
}
}
}
else {
//base[0x308]++;
IRTofs = extension->PortOfs;
IRTrptr = (PUSHORT)(IRTofs + RXrptr);
IRTwptr = (PUSHORT)(IRTofs + RXwptr);
IRTrxMask = *(PUSHORT)(IRTofs + RX_mask);
count = (*IRTwptr >= *IRTrptr) ? (*IRTwptr - *IRTrptr)
: (*IRTwptr - *IRTrptr + IRTrxMask + 1);
if (count) {
//base[0x309]++;
extension->CountOnLastRead = count;
extension->ReadByIsr = count;
KeQuerySystemTime(
&extension->LastReadTime
);
}
MoxaSetTimer(
&extension->ReadRequestIntervalTimer,
*extension->IntervalTimeToUse,
&extension->IntervalReadTimeoutDpc,
extension
);
IoReleaseCancelSpinLock(oldIrql);
}
}
MoxaDpcEpilogue(extension, Dpc);
}
BOOLEAN
MoxaCheckInQueue(
IN PMOXA_DEVICE_EXTENSION Extension
)
{
PUCHAR ofs;
PUSHORT rptr, wptr;
ofs = Extension->PortOfs;
GDrptr = (PUSHORT)(ofs + RXrptr);
GDwptr = (PUSHORT)(ofs + RXwptr);
if (*GDrptr != *GDwptr)
return TRUE;
else
return FALSE;
}
BOOLEAN
MoxaPollGetData(
IN PVOID Context
)
{
PMOXA_DEVICE_EXTENSION extension = Context;
PIO_STACK_LOCATION irpSp;
MoxaGetData(extension);
extension->ReadLength = extension->NumberNeededForRead;
if (!extension->ReadLength) {
*(PSHORT)(extension->PortOfs + HostStat) &= ~WakeupRxTrigger;
irpSp = IoGetCurrentIrpStackLocation(
extension->CurrentReadIrp);
extension->CurrentReadIrp->IoStatus.Information =
irpSp->Parameters.Read.Length;
}
return FALSE;
}