/*++ Module Name: isr.c Environment: Kernel mode Revision History : --*/ #include "precomp.h" BOOLEAN MoxaISR( IN PKINTERRUPT InterruptObject, IN PVOID Context ) { PMOXA_GLOBAL_DATA globalData; PMOXA_DEVICE_EXTENSION extension; USHORT boardNo, port, portNo, temp; PUSHORT ip; PIO_STACK_LOCATION irpSp; UCHAR ack; BOOLEAN servicedAnInterrupt = FALSE; BOOLEAN thisPassServiced; PLIST_ENTRY firstInterruptEntry = Context; PLIST_ENTRY interruptEntry; PMOXA_MULTIPORT_DISPATCH dispatch; MoxaIRQok = TRUE; if (!firstInterruptEntry) return (servicedAnInterrupt); MoxaKdPrint(MX_DBG_TRACE_ISR,("Enter ISR(first=%x)\n",firstInterruptEntry)); if (IsListEmpty(firstInterruptEntry)) return (servicedAnInterrupt); do { thisPassServiced = FALSE; interruptEntry = firstInterruptEntry->Flink; do { PMOXA_CISR_SW cisrsw = CONTAINING_RECORD( interruptEntry, MOXA_CISR_SW, SharerList ); MoxaKdPrint(MX_DBG_TRACE_ISR,("CISRSW=%x\n",cisrsw)); if (!cisrsw) return (servicedAnInterrupt); dispatch = &cisrsw->Dispatch; globalData = dispatch->GlobalData; boardNo = (USHORT)dispatch->BoardNo; if (!globalData || boardNo < 0) return (servicedAnInterrupt); MoxaKdPrint(MX_DBG_TRACE_ISR,("Board=%d,Pending=%x,IntIndx=%x,BoardReady=%d\n", boardNo, *globalData->IntPend[boardNo], *globalData->IntNdx[boardNo], globalData->BoardReady[boardNo] )); if (globalData->PciIntAckBase[boardNo]) { ack = READ_PORT_UCHAR(globalData->PciIntAckBase[boardNo]); MoxaKdPrint(MX_DBG_TRACE_ISR,("Ack Interrupt%d/%x/%x\n",boardNo,globalData->PciIntAckBase[boardNo],ack)); ack |= 4; WRITE_PORT_UCHAR(globalData->PciIntAckBase[boardNo],ack); } if ((globalData->BoardReady[boardNo] == TRUE) &&(*globalData->IntPend[boardNo] == 0xff) &&((*globalData->IntNdx[boardNo] == 0)||( *globalData->IntNdx[boardNo]==0x80)) ) { servicedAnInterrupt = TRUE; thisPassServiced = TRUE; ip = (PUSHORT)(globalData->IntTable[boardNo] + *globalData->IntNdx[boardNo]); for (port=0; portNumPorts[boardNo]; port++) { portNo = boardNo * MAXPORT_PER_CARD + port; if (!(extension = globalData->Extension[portNo])) continue; if ((temp = ip[extension->PortIndex]) != 0) { ip[extension->PortIndex] = 0; if ((!extension->DeviceIsOpened) || (extension->PowerState != PowerDeviceD0)) continue; if (temp & (IntrTx | IntrTxTrigger)) { if (extension->WriteLength) { if (!extension->IsrOutFlag) { extension->IsrOutFlag = 1; MoxaInsertQueueDpc( &extension->IsrOutDpc, NULL, NULL, extension ); } } else if (*(PSHORT)(extension->PortOfs + HostStat) & (WakeupTx|WakeupTxTrigger)) { *(PSHORT)(extension->PortOfs + HostStat) &= ~(WakeupTx|WakeupTxTrigger); irpSp = IoGetCurrentIrpStackLocation( extension->CurrentWriteIrp); extension->CurrentWriteIrp->IoStatus.Information = irpSp->Parameters.Write.Length; MoxaInsertQueueDpc( &extension->CompleteWriteDpc, NULL, NULL, extension ); } } if (temp & IntrRxTrigger) { if (extension->ReadLength) { if (!extension->IsrInFlag) { extension->IsrInFlag = 1; MoxaInsertQueueDpc( &extension->IsrInDpc, NULL, NULL, extension ); } } } if (temp & IntrRx) { if (extension->IsrWaitMask & SERIAL_EV_RXCHAR) extension->HistoryMask |= SERIAL_EV_RXCHAR; } if (temp & IntrEvent) { if (extension->IsrWaitMask & SERIAL_EV_RXFLAG) extension->HistoryMask |= SERIAL_EV_RXFLAG; } if (temp & IntrRx80Full) { if (extension->IsrWaitMask & SERIAL_EV_RX80FULL) extension->HistoryMask |= SERIAL_EV_RX80FULL; } if (temp & IntrBreak) { extension->ErrorWord |= SERIAL_ERROR_BREAK; if (extension->IsrWaitMask & SERIAL_EV_BREAK) extension->HistoryMask |= SERIAL_EV_BREAK; if (extension->HandFlow.ControlHandShake & SERIAL_ERROR_ABORT) { MoxaInsertQueueDpc( &extension->CommErrorDpc, NULL, NULL, extension ); } } if (temp & IntrLine) { // // 9-24-01 by William // #if 0 MoxaInsertQueueDpc( &extension->IntrLineDpc, NULL, NULL, extension ); #endif USHORT modemStatus; MoxaFuncGetLineStatus( extension->PortOfs, &modemStatus ); if (extension->IsrWaitMask & (SERIAL_EV_CTS | SERIAL_EV_DSR | SERIAL_EV_RLSD)) { USHORT change; change = modemStatus ^ extension->ModemStatus; if ((change & LSTATUS_CTS) && (extension->IsrWaitMask & SERIAL_EV_CTS)) extension->HistoryMask |= SERIAL_EV_CTS; if ((change & LSTATUS_DSR) && (extension->IsrWaitMask & SERIAL_EV_DSR)) extension->HistoryMask |= SERIAL_EV_DSR; if ((change & LSTATUS_DCD) && (extension->IsrWaitMask & SERIAL_EV_RLSD)) extension->HistoryMask |= SERIAL_EV_RLSD; } extension->ModemStatus = modemStatus; // end } if (temp & IntrError) { // // 9-24-01 by William // #if 0 MoxaInsertQueueDpc( &extension->IntrErrorDpc, NULL, NULL, extension ); #endif USHORT dataError; MoxaFuncGetDataError( extension->PortOfs, &dataError ); if ( dataError & SERIAL_ERROR_QUEUEOVERRUN ) { extension->PerfStats.BufferOverrunErrorCount++; } if (dataError & SERIAL_ERROR_OVERRUN) { extension->PerfStats.SerialOverrunErrorCount++; } if (dataError & SERIAL_ERROR_PARITY) { extension->PerfStats.ParityErrorCount++; } if (dataError & SERIAL_ERROR_FRAMING) { extension->PerfStats.FrameErrorCount++; } extension->ErrorWord |= (dataError & (SERIAL_ERROR_OVERRUN | SERIAL_ERROR_PARITY | SERIAL_ERROR_FRAMING | SERIAL_ERROR_QUEUEOVERRUN)); if (extension->IsrWaitMask & SERIAL_EV_ERR) { if (dataError & (SERIAL_ERROR_OVERRUN | SERIAL_ERROR_PARITY | SERIAL_ERROR_FRAMING)) extension->HistoryMask |= SERIAL_EV_ERR; } if (extension->HandFlow.ControlHandShake & SERIAL_ERROR_ABORT) { MoxaInsertQueueDpc( &extension->CommErrorDpc, NULL, NULL, extension ); } // end } if (extension->IrpMaskLocation && extension->HistoryMask) { *extension->IrpMaskLocation = extension->HistoryMask; extension->IrpMaskLocation = NULL; extension->HistoryMask = 0; extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG); MoxaInsertQueueDpc( &extension->CommWaitDpc, NULL, NULL, extension ); } } } *globalData->IntPend[boardNo] = 0; } interruptEntry = interruptEntry->Flink; servicedAnInterrupt |= thisPassServiced; } while (interruptEntry != firstInterruptEntry); } while (thisPassServiced == TRUE); MoxaKdPrint(MX_DBG_TRACE_ISR,("Exit ISR\n")); return (servicedAnInterrupt); } VOID MoxaIsrIn( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemContext1, IN PVOID SystemContext2 ) { PMOXA_DEVICE_EXTENSION extension = DeferredContext; KIRQL oldIrql; IoAcquireCancelSpinLock(&oldIrql); KeSynchronizeExecution( extension->Interrupt, MoxaIsrGetData, extension ); IoReleaseCancelSpinLock(oldIrql); MoxaDpcEpilogue(extension, Dpc); } BOOLEAN MoxaIsrGetData( IN PVOID Context ) { PMOXA_DEVICE_EXTENSION extension = Context; PIO_STACK_LOCATION irpSp; USHORT max; if (extension->ReadLength) { extension->NumberNeededForRead = extension->ReadLength; 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; extension->CountOnLastRead = MOXA_COMPLETE_READ_COMPLETE; MoxaInsertQueueDpc( &extension->CompleteReadDpc, NULL, NULL, extension ); } else { /* 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; *(PSHORT)(extension->PortOfs + HostStat) |= WakeupRxTrigger; } } extension->IsrInFlag = 0; return FALSE; } VOID MoxaIsrOut( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemContext1, IN PVOID SystemContext2 ) { PMOXA_DEVICE_EXTENSION extension = DeferredContext; KIRQL oldIrql; IoAcquireCancelSpinLock(&oldIrql); KeSynchronizeExecution( extension->Interrupt, MoxaIsrPutData, extension ); IoReleaseCancelSpinLock(oldIrql); MoxaDpcEpilogue(extension, Dpc); } BOOLEAN MoxaIsrPutData( IN PVOID Context ) { PMOXA_DEVICE_EXTENSION extension = Context; if (extension->WriteLength) MoxaPutData(extension); extension->IsrOutFlag = 0; return FALSE; } VOID MoxaIntrLine( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemContext1, IN PVOID SystemContext2 ) { PMOXA_DEVICE_EXTENSION extension = DeferredContext; KIRQL oldIrql; PUCHAR ofs = extension->PortOfs; USHORT modemStatus; MoxaFuncGetLineStatus( ofs, &modemStatus ); if (extension->IsrWaitMask & (SERIAL_EV_CTS | SERIAL_EV_DSR | SERIAL_EV_RLSD)) { USHORT change; change = modemStatus ^ extension->ModemStatus; if ((change & LSTATUS_CTS) && (extension->IsrWaitMask & SERIAL_EV_CTS)) extension->HistoryMask |= SERIAL_EV_CTS; if ((change & LSTATUS_DSR) && (extension->IsrWaitMask & SERIAL_EV_DSR)) extension->HistoryMask |= SERIAL_EV_DSR; if ((change & LSTATUS_DCD) && (extension->IsrWaitMask & SERIAL_EV_RLSD)) extension->HistoryMask |= SERIAL_EV_RLSD; } extension->ModemStatus = modemStatus; IoAcquireCancelSpinLock(&oldIrql); if (extension->IrpMaskLocation && extension->HistoryMask) { *extension->IrpMaskLocation = extension->HistoryMask; extension->IrpMaskLocation = NULL; extension->HistoryMask = 0; extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG); MoxaInsertQueueDpc( &extension->CommWaitDpc, NULL, NULL, extension ); } IoReleaseCancelSpinLock(oldIrql); MoxaDpcEpilogue(extension, Dpc); } VOID MoxaIntrError( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemContext1, IN PVOID SystemContext2 ) { PMOXA_DEVICE_EXTENSION extension = DeferredContext; KIRQL oldIrql; PUCHAR ofs = extension->PortOfs; USHORT dataError; KeAcquireSpinLock( &extension->ControlLock, &oldIrql ); MoxaFuncGetDataError( ofs, &dataError ); KeReleaseSpinLock( &extension->ControlLock, oldIrql ); if ( dataError & SERIAL_ERROR_QUEUEOVERRUN ) { extension->PerfStats.BufferOverrunErrorCount++; } if (dataError & SERIAL_ERROR_OVERRUN) { extension->PerfStats.SerialOverrunErrorCount++; } if (dataError & SERIAL_ERROR_PARITY) { extension->PerfStats.ParityErrorCount++; } if (dataError & SERIAL_ERROR_FRAMING) { extension->PerfStats.FrameErrorCount++; } extension->ErrorWord |= (dataError & (SERIAL_ERROR_OVERRUN | SERIAL_ERROR_PARITY | SERIAL_ERROR_FRAMING | SERIAL_ERROR_QUEUEOVERRUN)); if (extension->IsrWaitMask & SERIAL_EV_ERR) { if (dataError & (SERIAL_ERROR_OVERRUN | SERIAL_ERROR_PARITY | SERIAL_ERROR_FRAMING)) extension->HistoryMask |= SERIAL_EV_ERR; } if (extension->HandFlow.ControlHandShake & SERIAL_ERROR_ABORT) { MoxaInsertQueueDpc( &extension->CommErrorDpc, NULL, NULL, extension ); } IoAcquireCancelSpinLock(&oldIrql); if (extension->IrpMaskLocation && extension->HistoryMask) { *extension->IrpMaskLocation = extension->HistoryMask; extension->IrpMaskLocation = NULL; extension->HistoryMask = 0; extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG); MoxaInsertQueueDpc( &extension->CommWaitDpc, NULL, NULL, extension ); } IoReleaseCancelSpinLock(oldIrql); MoxaDpcEpilogue(extension, Dpc); }