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.
605 lines
17 KiB
605 lines
17 KiB
|
|
/*++
|
|
|
|
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; port<globalData->NumPorts[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);
|
|
}
|
|
|
|
|