/*++ 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; }