|
|
/*++
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( ¤tTime ); 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; }
|