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.
2411 lines
53 KiB
2411 lines
53 KiB
/*++
|
|
|
|
Module Name:
|
|
|
|
utils.c
|
|
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History :
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
|
|
NTSTATUS
|
|
MoxaCompleteIfError(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
If the current irp is not an IOCTL_SERIAL_GET_COMMSTATUS request and
|
|
there is an error and the application requested abort on errors,
|
|
then cancel the irp.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object for this device
|
|
|
|
Irp - Pointer to the IRP to test.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS or STATUS_CANCELLED.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PMOXA_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
|
|
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
USHORT dataError;
|
|
|
|
|
|
if (extension->HandFlow.ControlHandShake & SERIAL_ERROR_ABORT) {
|
|
|
|
if (extension->ErrorWord) {
|
|
|
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
//
|
|
// There is a current error in the driver. No requests should
|
|
// come through except for the GET_COMMSTATUS.
|
|
//
|
|
|
|
if ((irpSp->MajorFunction != IRP_MJ_DEVICE_CONTROL) ||
|
|
(irpSp->Parameters.DeviceIoControl.IoControlCode !=
|
|
IOCTL_SERIAL_GET_COMMSTATUS)) {
|
|
|
|
status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
MoxaCompleteRequest(extension, Irp, 0);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
//
|
|
// t is 2ms
|
|
//
|
|
VOID
|
|
MoxaDelay(
|
|
IN ULONG t
|
|
)
|
|
{
|
|
LARGE_INTEGER delay;
|
|
|
|
t *= 20000; /* delay unit = 100 ns */
|
|
|
|
delay = RtlConvertUlongToLargeInteger(t);
|
|
|
|
delay = RtlLargeIntegerNegate(delay);
|
|
|
|
KeDelayExecutionThread(
|
|
KernelMode,
|
|
FALSE,
|
|
&delay
|
|
);
|
|
}
|
|
|
|
/* Must migrate to MoxaFunc1 for performace resaon */
|
|
VOID
|
|
MoxaFunc(
|
|
IN PUCHAR PortOfs,
|
|
IN UCHAR Command,
|
|
IN USHORT Argument
|
|
)
|
|
{
|
|
|
|
*(PUSHORT)(PortOfs + FuncArg) = Argument;
|
|
|
|
*(PortOfs + FuncCode) = Command;
|
|
|
|
MoxaWaitFinish(PortOfs);
|
|
}
|
|
|
|
VOID
|
|
MoxaFunc1(
|
|
IN PUCHAR PortOfs,
|
|
IN UCHAR Command,
|
|
IN USHORT Argument
|
|
)
|
|
{
|
|
|
|
*(PUSHORT)(PortOfs + FuncArg) = Argument;
|
|
|
|
*(PortOfs + FuncCode) = Command;
|
|
|
|
MoxaWaitFinish1(PortOfs);
|
|
}
|
|
|
|
VOID
|
|
MoxaFuncWithDumbWait(
|
|
IN PUCHAR PortOfs,
|
|
IN UCHAR Command,
|
|
IN USHORT Argument
|
|
)
|
|
{
|
|
|
|
*(PUSHORT)(PortOfs + FuncArg) = Argument;
|
|
|
|
*(PortOfs + FuncCode) = Command;
|
|
|
|
MoxaDumbWaitFinish(PortOfs);
|
|
}
|
|
|
|
VOID
|
|
MoxaFuncWithLock(
|
|
IN PMOXA_DEVICE_EXTENSION Extension,
|
|
IN UCHAR Command,
|
|
IN USHORT Argument
|
|
)
|
|
{
|
|
PUCHAR ofs;
|
|
KIRQL oldIrql;
|
|
|
|
KeAcquireSpinLock(
|
|
&Extension->ControlLock,
|
|
&oldIrql
|
|
);
|
|
|
|
ofs = Extension->PortOfs;
|
|
|
|
*(PUSHORT)(ofs + FuncArg) = Argument;
|
|
|
|
*(ofs + FuncCode) = Command;
|
|
|
|
MoxaWaitFinish(ofs);
|
|
|
|
KeReleaseSpinLock(
|
|
&Extension->ControlLock,
|
|
oldIrql
|
|
);
|
|
}
|
|
|
|
VOID
|
|
MoxaFuncGetLineStatus(
|
|
IN PUCHAR PortOfs,
|
|
IN PUSHORT Argument
|
|
)
|
|
{
|
|
*Argument = *(PUSHORT)(PortOfs + FlagStat) >> 4;
|
|
|
|
}
|
|
|
|
VOID
|
|
MoxaFuncGetDataError(
|
|
IN PUCHAR PortOfs,
|
|
IN PUSHORT Argument
|
|
)
|
|
{
|
|
*Argument = *(PUSHORT)(PortOfs + Data_error);
|
|
*(PUSHORT)(PortOfs + Data_error) = 0;
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
MoxaDumbWaitFinish(
|
|
IN PUCHAR PortOfs
|
|
)
|
|
{
|
|
LARGE_INTEGER targetTc, newTc, currTc, newTc1;
|
|
ULONG unit, count;
|
|
LARGE_INTEGER interval; /* 0.5 ms */
|
|
USHORT cnt = 1000; /* timeout = 500 ms */
|
|
|
|
|
|
KeQueryTickCount(&currTc);
|
|
|
|
unit = KeQueryTimeIncrement();
|
|
|
|
currTc = RtlExtendedIntegerMultiply(currTc, unit);
|
|
|
|
interval = RtlConvertUlongToLargeInteger(5000L);
|
|
|
|
targetTc = RtlLargeIntegerAdd(currTc, interval);
|
|
|
|
do {
|
|
|
|
count = 0;
|
|
|
|
/*********************************************************************
|
|
NOTE! sometimes I cann't leave the while loop. beacuse
|
|
newTc = 0 (I don't know why). So I must set boundary
|
|
MoxaLoopCnt to quit!
|
|
/*********************************************************************/
|
|
do {
|
|
|
|
KeQueryTickCount(&newTc);
|
|
|
|
newTc = RtlExtendedIntegerMultiply(newTc, unit);
|
|
|
|
if (++count > MoxaLoopCnt)
|
|
break;
|
|
|
|
} while (!RtlLargeIntegerGreaterThanOrEqualTo(newTc, targetTc));
|
|
|
|
if (*(PortOfs + FuncCode))
|
|
|
|
targetTc = RtlLargeIntegerAdd(targetTc, interval);
|
|
else
|
|
|
|
return TRUE;
|
|
|
|
|
|
} while (cnt--);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN
|
|
MoxaWaitFinish(
|
|
IN PUCHAR PortOfs
|
|
)
|
|
{
|
|
LARGE_INTEGER targetTc, newTc, currTc, newTc1;
|
|
ULONG unit, count;
|
|
LARGE_INTEGER interval; /* 0.5 ms */
|
|
USHORT cnt = 1000; /* timeout = 500 ms */
|
|
|
|
|
|
KeQueryTickCount(&currTc);
|
|
|
|
unit = KeQueryTimeIncrement();
|
|
|
|
currTc = RtlExtendedIntegerMultiply(currTc, unit);
|
|
|
|
interval = RtlConvertUlongToLargeInteger(5000L);
|
|
|
|
targetTc = RtlLargeIntegerAdd(currTc, interval);
|
|
|
|
do {
|
|
|
|
count = 0;
|
|
|
|
/*********************************************************************
|
|
NOTE! sometimes I cann't leave the while loop. beacuse
|
|
newTc = 0 (I don't know why). So I must set boundary
|
|
MoxaLoopCnt to quit!
|
|
/*********************************************************************/
|
|
do {
|
|
|
|
KeQueryTickCount(&newTc);
|
|
|
|
newTc = RtlExtendedIntegerMultiply(newTc, unit);
|
|
|
|
if (++count > MoxaLoopCnt)
|
|
break;
|
|
|
|
} while (!RtlLargeIntegerGreaterThanOrEqualTo(newTc, targetTc));
|
|
|
|
if (*(PortOfs + FuncCode))
|
|
|
|
targetTc = RtlLargeIntegerAdd(targetTc, interval);
|
|
else
|
|
|
|
return TRUE;
|
|
|
|
|
|
} while (cnt--);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
MoxaWaitFinish1(
|
|
IN PUCHAR PortOfs
|
|
)
|
|
{
|
|
|
|
USHORT cnt = 250; /* timeout = 500 ms */
|
|
|
|
while (cnt--) {
|
|
if (*(PortOfs + FuncCode))
|
|
MoxaDelay(1L);
|
|
else
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MoxaGetDivisorFromBaud(
|
|
IN ULONG ClockType,
|
|
IN LONG DesiredBaud,
|
|
OUT PSHORT AppropriateDivisor
|
|
)
|
|
{
|
|
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
ULONG clockRate;
|
|
SHORT calculatedDivisor;
|
|
ULONG denominator;
|
|
ULONG remainder;
|
|
|
|
//
|
|
// Allow up to a 1 percent error
|
|
//
|
|
|
|
ULONG maxRemain98 = 98304;
|
|
ULONG maxRemain11 = 110592;
|
|
ULONG maxRemain14 = 147456;
|
|
ULONG maxRemain;
|
|
|
|
if (ClockType == 1)
|
|
|
|
clockRate = 11059200;
|
|
else if (ClockType == 2)
|
|
|
|
clockRate = 14745600;
|
|
else
|
|
|
|
clockRate = 9830400;
|
|
|
|
//
|
|
// Reject any non-positive bauds.
|
|
//
|
|
|
|
denominator = DesiredBaud * (ULONG)16;
|
|
|
|
if (DesiredBaud <= 0) {
|
|
|
|
*AppropriateDivisor = -1;
|
|
|
|
} else if ((LONG)denominator < DesiredBaud) {
|
|
|
|
//
|
|
// If the desired baud was so huge that it cause the denominator
|
|
// calculation to wrap, don't support it.
|
|
//
|
|
|
|
*AppropriateDivisor = -1;
|
|
|
|
} else {
|
|
|
|
if (ClockType == 0) { /* ver1.0 BOX */
|
|
|
|
maxRemain = maxRemain98;
|
|
|
|
}
|
|
else if (ClockType == 1) { /* ver2.0 BOX */
|
|
|
|
maxRemain = maxRemain11;
|
|
|
|
}
|
|
else { /* ver3.0 BOX */
|
|
|
|
maxRemain = maxRemain14;
|
|
|
|
}
|
|
|
|
calculatedDivisor = (SHORT)(clockRate / denominator);
|
|
|
|
remainder = clockRate % denominator;
|
|
|
|
//
|
|
// Round up.
|
|
//
|
|
|
|
if (((remainder * 2) > clockRate) && (DesiredBaud != 110))
|
|
|
|
calculatedDivisor++;
|
|
|
|
//
|
|
// Only let the remainder calculations effect us if
|
|
// the baud rate is > 9600.
|
|
//
|
|
|
|
if (DesiredBaud >= 9600)
|
|
|
|
//
|
|
// If the remainder is less than the maximum remainder (wrt
|
|
// the clockRate) or the remainder + the maximum remainder is
|
|
// greater than or equal to the clockRate then assume that the
|
|
// baud is ok.
|
|
//
|
|
|
|
if ((remainder >= maxRemain) && ((remainder+maxRemain) < clockRate))
|
|
|
|
calculatedDivisor = -1;
|
|
|
|
//
|
|
// Don't support a baud that causes the denominator to
|
|
// be larger than the clock.
|
|
//
|
|
|
|
if (denominator > clockRate)
|
|
|
|
calculatedDivisor = -1;
|
|
|
|
*AppropriateDivisor = calculatedDivisor;
|
|
|
|
}
|
|
|
|
if (*AppropriateDivisor == -1) {
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
MoxaStartOrQueue(
|
|
IN PMOXA_DEVICE_EXTENSION Extension,
|
|
IN PIRP Irp,
|
|
IN PLIST_ENTRY QueueToExamine,
|
|
IN PIRP *CurrentOpIrp,
|
|
IN PMOXA_START_ROUTINE Starter
|
|
)
|
|
{
|
|
|
|
KIRQL oldIrql;
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
|
|
//
|
|
// If this is a write irp then take the amount of characters
|
|
// to write and add it to the count of characters to write.
|
|
//
|
|
|
|
if (IoGetCurrentIrpStackLocation(Irp)->MajorFunction
|
|
== IRP_MJ_WRITE)
|
|
|
|
Extension->TotalCharsQueued +=
|
|
IoGetCurrentIrpStackLocation(Irp)
|
|
->Parameters.Write.Length;
|
|
|
|
if ((IsListEmpty(QueueToExamine)) &&
|
|
!(*CurrentOpIrp)) {
|
|
|
|
//
|
|
// There were no current operation. Mark this one as
|
|
// current and start it up.
|
|
//
|
|
|
|
*CurrentOpIrp = Irp;
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
return Starter(Extension);
|
|
|
|
} else {
|
|
|
|
//
|
|
// We don't know how long the irp will be in the
|
|
// queue. So we need to handle cancel.
|
|
//
|
|
|
|
if (Irp->Cancel) {
|
|
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
MoxaCompleteRequest(Extension, Irp, 0);
|
|
|
|
return STATUS_CANCELLED;
|
|
|
|
} else {
|
|
|
|
Irp->IoStatus.Status = STATUS_PENDING;
|
|
IoMarkIrpPending(Irp);
|
|
|
|
InsertTailList(
|
|
QueueToExamine,
|
|
&Irp->Tail.Overlay.ListEntry
|
|
);
|
|
|
|
IoSetCancelRoutine(
|
|
Irp,
|
|
MoxaCancelQueued
|
|
);
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
return STATUS_PENDING;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
MoxaCancelQueued(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp
|
|
)
|
|
{
|
|
|
|
PMOXA_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
|
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
|
|
|
|
//
|
|
// If this is a write irp then take the amount of characters
|
|
// to write and subtract it from the count of characters to write.
|
|
//
|
|
|
|
if (irpSp->MajorFunction == IRP_MJ_WRITE)
|
|
|
|
extension->TotalCharsQueued -= irpSp->Parameters.Write.Length;
|
|
|
|
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
|
|
|
MoxaCompleteRequest(extension,
|
|
Irp,
|
|
// IO_SERIAL_INCREMENT
|
|
IO_NO_INCREMENT
|
|
);
|
|
|
|
|
|
}
|
|
|
|
VOID
|
|
MoxaGetNextIrp(
|
|
IN PIRP *CurrentOpIrp,
|
|
IN PLIST_ENTRY QueueToProcess,
|
|
OUT PIRP *NextIrp,
|
|
IN BOOLEAN CompleteCurrent,
|
|
IN PMOXA_DEVICE_EXTENSION extension
|
|
)
|
|
|
|
{
|
|
|
|
PIRP oldIrp;
|
|
KIRQL oldIrql;
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
|
|
oldIrp = *CurrentOpIrp;
|
|
|
|
if (!IsListEmpty(QueueToProcess)) {
|
|
|
|
PLIST_ENTRY headOfList;
|
|
|
|
headOfList = RemoveHeadList(QueueToProcess);
|
|
|
|
*CurrentOpIrp = CONTAINING_RECORD(
|
|
headOfList,
|
|
IRP,
|
|
Tail.Overlay.ListEntry
|
|
);
|
|
|
|
IoSetCancelRoutine(
|
|
*CurrentOpIrp,
|
|
NULL
|
|
);
|
|
|
|
} else {
|
|
|
|
*CurrentOpIrp = NULL;
|
|
|
|
}
|
|
|
|
*NextIrp = *CurrentOpIrp;
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
if (CompleteCurrent) {
|
|
|
|
if (oldIrp) {
|
|
|
|
MoxaCompleteRequest(extension,
|
|
oldIrp,
|
|
// IO_SERIAL_INCREMENT
|
|
IO_NO_INCREMENT
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
MoxaTryToCompleteCurrent(
|
|
IN PMOXA_DEVICE_EXTENSION Extension,
|
|
IN PKSYNCHRONIZE_ROUTINE SynchRoutine OPTIONAL,
|
|
IN KIRQL IrqlForRelease,
|
|
IN NTSTATUS StatusToUse,
|
|
IN PIRP *CurrentOpIrp,
|
|
IN PLIST_ENTRY QueueToProcess OPTIONAL,
|
|
IN PKTIMER IntervalTimer OPTIONAL,
|
|
IN PKTIMER TotalTimer OPTIONAL,
|
|
IN PMOXA_START_ROUTINE Starter OPTIONAL,
|
|
IN PMOXA_GET_NEXT_ROUTINE GetNextIrp OPTIONAL
|
|
)
|
|
{
|
|
|
|
if (*CurrentOpIrp == NULL) {
|
|
IoReleaseCancelSpinLock(IrqlForRelease);
|
|
return;
|
|
}
|
|
MOXA_DEC_REFERENCE(*CurrentOpIrp);
|
|
|
|
if (SynchRoutine) {
|
|
|
|
KeSynchronizeExecution(
|
|
Extension->Interrupt,
|
|
SynchRoutine,
|
|
Extension
|
|
);
|
|
}
|
|
|
|
MoxaRundownIrpRefs(
|
|
CurrentOpIrp,
|
|
IntervalTimer,
|
|
TotalTimer,
|
|
Extension
|
|
);
|
|
|
|
if (!MOXA_REFERENCE_COUNT(*CurrentOpIrp)) {
|
|
|
|
PIRP newIrp;
|
|
|
|
|
|
(*CurrentOpIrp)->IoStatus.Status = StatusToUse;
|
|
|
|
if (StatusToUse == STATUS_CANCELLED)
|
|
|
|
(*CurrentOpIrp)->IoStatus.Information = 0;
|
|
|
|
if (GetNextIrp) {
|
|
|
|
IoReleaseCancelSpinLock(IrqlForRelease);
|
|
|
|
GetNextIrp(
|
|
CurrentOpIrp,
|
|
QueueToProcess,
|
|
&newIrp,
|
|
TRUE,
|
|
Extension
|
|
);
|
|
|
|
if (newIrp)
|
|
|
|
Starter(Extension);
|
|
|
|
}
|
|
else {
|
|
|
|
PIRP oldIrp = *CurrentOpIrp;
|
|
|
|
*CurrentOpIrp = NULL;
|
|
|
|
IoReleaseCancelSpinLock(IrqlForRelease);
|
|
|
|
MoxaCompleteRequest(Extension,
|
|
oldIrp,
|
|
// IO_SERIAL_INCREMENT
|
|
IO_NO_INCREMENT
|
|
);
|
|
}
|
|
|
|
} else {
|
|
|
|
IoReleaseCancelSpinLock(IrqlForRelease);
|
|
|
|
}
|
|
}
|
|
|
|
VOID
|
|
MoxaRundownIrpRefs(
|
|
IN PIRP *CurrentOpIrp,
|
|
IN PKTIMER IntervalTimer OPTIONAL,
|
|
IN PKTIMER TotalTimer OPTIONAL,
|
|
IN PMOXA_DEVICE_EXTENSION pDevExt)
|
|
|
|
{
|
|
|
|
if ((*CurrentOpIrp)->CancelRoutine) {
|
|
|
|
MOXA_DEC_REFERENCE(*CurrentOpIrp);
|
|
|
|
IoSetCancelRoutine(
|
|
*CurrentOpIrp,
|
|
NULL
|
|
);
|
|
|
|
}
|
|
|
|
if (IntervalTimer) {
|
|
|
|
if (MoxaCancelTimer(IntervalTimer,pDevExt)) {
|
|
|
|
MOXA_DEC_REFERENCE(*CurrentOpIrp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (TotalTimer) {
|
|
|
|
|
|
if (MoxaCancelTimer(TotalTimer,pDevExt)) {
|
|
|
|
MOXA_DEC_REFERENCE(*CurrentOpIrp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
MoxaInsertQueueDpc(IN PRKDPC PDpc, IN PVOID Sarg1, IN PVOID Sarg2,
|
|
IN PMOXA_DEVICE_EXTENSION PDevExt)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function must be called to queue DPC's for the serial driver.
|
|
|
|
Arguments:
|
|
|
|
PDpc thru Sarg2 - Standard args to KeInsertQueueDpc()
|
|
|
|
PDevExt - Pointer to the device extension for the device that needs to
|
|
queue a DPC
|
|
|
|
Return Value:
|
|
|
|
Kicks up return value from KeInsertQueueDpc()
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN queued;
|
|
|
|
|
|
InterlockedIncrement(&PDevExt->DpcCount);
|
|
|
|
queued = KeInsertQueueDpc(PDpc, Sarg1, Sarg2);
|
|
|
|
if (!queued) {
|
|
ULONG pendingCnt;
|
|
|
|
pendingCnt = InterlockedDecrement(&PDevExt->DpcCount);
|
|
|
|
if (pendingCnt == 0) {
|
|
KeSetEvent(&PDevExt->PendingIRPEvent, IO_NO_INCREMENT, FALSE);
|
|
}
|
|
}
|
|
|
|
return queued;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
MoxaSetTimer(IN PKTIMER Timer, IN LARGE_INTEGER DueTime,
|
|
IN PKDPC Dpc OPTIONAL, IN PMOXA_DEVICE_EXTENSION PDevExt)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function must be called to set timers for the serial driver.
|
|
|
|
Arguments:
|
|
|
|
Timer - pointer to timer dispatcher object
|
|
|
|
DueTime - time at which the timer should expire
|
|
|
|
Dpc - option Dpc
|
|
|
|
PDevExt - Pointer to the device extension for the device that needs to
|
|
set a timer
|
|
|
|
Return Value:
|
|
|
|
Kicks up return value from KeSetTimer()
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN set;
|
|
|
|
|
|
InterlockedIncrement(&PDevExt->DpcCount);
|
|
|
|
set = KeSetTimer(Timer, DueTime, Dpc);
|
|
|
|
if (set) {
|
|
InterlockedDecrement(&PDevExt->DpcCount);
|
|
}
|
|
|
|
return set;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
MoxaCancelTimer(IN PKTIMER Timer, IN PMOXA_DEVICE_EXTENSION PDevExt)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function must be called to cancel timers for the serial driver.
|
|
|
|
Arguments:
|
|
|
|
Timer - pointer to timer dispatcher object
|
|
|
|
PDevExt - Pointer to the device extension for the device that needs to
|
|
set a timer
|
|
|
|
Return Value:
|
|
|
|
True if timer was cancelled
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN cancelled;
|
|
|
|
cancelled = KeCancelTimer(Timer);
|
|
|
|
if (cancelled) {
|
|
MoxaDpcEpilogue(PDevExt, Timer->Dpc);
|
|
}
|
|
|
|
return cancelled;
|
|
}
|
|
|
|
|
|
VOID
|
|
MoxaDpcEpilogue(IN PMOXA_DEVICE_EXTENSION PDevExt, PKDPC PDpc)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function must be called at the end of every dpc function.
|
|
|
|
Arguments:
|
|
|
|
PDevObj - Pointer to the device object we are tracking dpc's for.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
LONG pendingCnt;
|
|
#if 1 // !DBG
|
|
UNREFERENCED_PARAMETER(PDpc);
|
|
#endif
|
|
|
|
pendingCnt = InterlockedDecrement(&PDevExt->DpcCount);
|
|
|
|
// ASSERT(pendingCnt >= 0);
|
|
|
|
if (pendingCnt == 0) {
|
|
KeSetEvent(&PDevExt->PendingDpcEvent, IO_NO_INCREMENT, FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
MoxaKillAllReadsOrWrites(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PLIST_ENTRY QueueToClean,
|
|
IN PIRP *CurrentOpIrp
|
|
)
|
|
{
|
|
|
|
KIRQL cancelIrql;
|
|
PDRIVER_CANCEL cancelRoutine;
|
|
|
|
//
|
|
// We acquire the cancel spin lock. This will prevent the
|
|
// irps from moving around.
|
|
//
|
|
|
|
IoAcquireCancelSpinLock(&cancelIrql);
|
|
|
|
//
|
|
// Clean the list from back to front.
|
|
//
|
|
|
|
while (!IsListEmpty(QueueToClean)) {
|
|
|
|
PIRP currentLastIrp = CONTAINING_RECORD(
|
|
QueueToClean->Blink,
|
|
IRP,
|
|
Tail.Overlay.ListEntry
|
|
);
|
|
|
|
RemoveEntryList(QueueToClean->Blink);
|
|
|
|
cancelRoutine = currentLastIrp->CancelRoutine;
|
|
currentLastIrp->CancelIrql = cancelIrql;
|
|
currentLastIrp->CancelRoutine = NULL;
|
|
currentLastIrp->Cancel = TRUE;
|
|
/* 8-30-01 by William
|
|
|
|
cancelRoutine(
|
|
DeviceObject,
|
|
currentLastIrp
|
|
);
|
|
|
|
IoAcquireCancelSpinLock(&cancelIrql);
|
|
*/
|
|
if (cancelRoutine) {
|
|
cancelRoutine(
|
|
DeviceObject,
|
|
currentLastIrp
|
|
);
|
|
|
|
IoAcquireCancelSpinLock(&cancelIrql);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//
|
|
// The queue is clean. Now go after the current if
|
|
// it's there.
|
|
//
|
|
|
|
if (*CurrentOpIrp) {
|
|
|
|
|
|
cancelRoutine = (*CurrentOpIrp)->CancelRoutine;
|
|
(*CurrentOpIrp)->Cancel = TRUE;
|
|
|
|
//
|
|
// If the current irp is not in a cancelable state
|
|
// then it *will* try to enter one and the above
|
|
// assignment will kill it. If it already is in
|
|
// a cancelable state then the following will kill it.
|
|
//
|
|
|
|
if (cancelRoutine) {
|
|
|
|
(*CurrentOpIrp)->CancelRoutine = NULL;
|
|
(*CurrentOpIrp)->CancelIrql = cancelIrql;
|
|
|
|
//
|
|
// This irp is already in a cancelable state. We simply
|
|
// mark it as canceled and call the cancel routine for
|
|
// it.
|
|
//
|
|
|
|
cancelRoutine(
|
|
DeviceObject,
|
|
*CurrentOpIrp
|
|
);
|
|
|
|
}
|
|
else
|
|
|
|
IoReleaseCancelSpinLock(cancelIrql);
|
|
|
|
}
|
|
else
|
|
|
|
IoReleaseCancelSpinLock(cancelIrql);
|
|
|
|
}
|
|
|
|
VOID
|
|
MoxaCommError(
|
|
IN PKDPC Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemContext1,
|
|
IN PVOID SystemContext2
|
|
)
|
|
{
|
|
|
|
PMOXA_DEVICE_EXTENSION extension = DeferredContext;
|
|
|
|
MoxaKillAllReadsOrWrites(
|
|
extension->DeviceObject,
|
|
&extension->WriteQueue,
|
|
&extension->CurrentWriteIrp
|
|
);
|
|
|
|
MoxaKillAllReadsOrWrites(
|
|
extension->DeviceObject,
|
|
&extension->ReadQueue,
|
|
&extension->CurrentReadIrp
|
|
);
|
|
MoxaDpcEpilogue(extension, Dpc);
|
|
}
|
|
|
|
USHORT
|
|
GetDeviceTxQueueWithLock(
|
|
IN PMOXA_DEVICE_EXTENSION Extension
|
|
)
|
|
{
|
|
KIRQL controlIrql, oldIrql;
|
|
PUCHAR ofs;
|
|
PUSHORT rptr, wptr;
|
|
USHORT lenMask, count;
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
ofs = Extension->PortOfs;
|
|
rptr = (PUSHORT)(ofs + TXrptr);
|
|
wptr = (PUSHORT)(ofs + TXwptr);
|
|
lenMask = *(PUSHORT)(ofs + TX_mask);
|
|
count = (*wptr >= *rptr) ? (*wptr - *rptr)
|
|
: (*wptr - *rptr + lenMask + 1);
|
|
|
|
KeAcquireSpinLock(
|
|
&Extension->ControlLock,
|
|
&controlIrql
|
|
);
|
|
|
|
*(ofs + FuncCode) = FC_ExtOQueue;
|
|
|
|
MoxaWaitFinish(ofs);
|
|
|
|
count += *(PUSHORT)(ofs + FuncArg);
|
|
|
|
KeReleaseSpinLock(
|
|
&Extension->ControlLock,
|
|
controlIrql
|
|
);
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
return count;
|
|
}
|
|
|
|
USHORT
|
|
GetDeviceTxQueue(
|
|
IN PMOXA_DEVICE_EXTENSION Extension
|
|
)
|
|
{
|
|
PUCHAR ofs;
|
|
PUSHORT rptr, wptr;
|
|
USHORT lenMask, count;
|
|
|
|
ofs = Extension->PortOfs;
|
|
rptr = (PUSHORT)(ofs + TXrptr);
|
|
wptr = (PUSHORT)(ofs + TXwptr);
|
|
lenMask = *(PUSHORT)(ofs + TX_mask);
|
|
count = (*wptr >= *rptr) ? (*wptr - *rptr)
|
|
: (*wptr - *rptr + lenMask + 1);
|
|
*(ofs + FuncCode) = FC_ExtOQueue;
|
|
MoxaDumbWaitFinish(ofs);
|
|
|
|
count += *(PUSHORT)(ofs + FuncArg);
|
|
|
|
return count;
|
|
}
|
|
|
|
USHORT
|
|
GetDeviceRxQueueWithLock(
|
|
IN PMOXA_DEVICE_EXTENSION Extension
|
|
)
|
|
{
|
|
KIRQL controlIrql, oldIrql;
|
|
PUCHAR ofs;
|
|
PUSHORT rptr, wptr;
|
|
USHORT lenMask, count;
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
ofs = Extension->PortOfs;
|
|
rptr = (PUSHORT)(ofs + RXrptr);
|
|
wptr = (PUSHORT)(ofs + RXwptr);
|
|
lenMask = *(PUSHORT)(ofs + RX_mask);
|
|
count = (*wptr >= *rptr) ? (*wptr - *rptr)
|
|
: (*wptr - *rptr + lenMask + 1);
|
|
|
|
KeAcquireSpinLock(
|
|
&Extension->ControlLock,
|
|
&controlIrql
|
|
);
|
|
|
|
*(ofs + FuncCode) = FC_ExtIQueue;
|
|
|
|
MoxaWaitFinish(ofs);
|
|
|
|
count += *(PUSHORT)(ofs + FuncArg);
|
|
|
|
KeReleaseSpinLock(
|
|
&Extension->ControlLock,
|
|
controlIrql
|
|
);
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
return count;
|
|
}
|
|
|
|
VOID
|
|
MoxaLogError(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
|
IN PHYSICAL_ADDRESS P1,
|
|
IN PHYSICAL_ADDRESS P2,
|
|
IN ULONG SequenceNumber,
|
|
IN UCHAR MajorFunctionCode,
|
|
IN UCHAR RetryCount,
|
|
IN ULONG UniqueErrorValue,
|
|
IN NTSTATUS FinalStatus,
|
|
IN NTSTATUS SpecificIOStatus,
|
|
IN ULONG LengthOfInsert1,
|
|
IN PWCHAR Insert1,
|
|
IN ULONG LengthOfInsert2,
|
|
IN PWCHAR Insert2
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates an error log entry, copies the supplied data
|
|
to it, and requests that it be written to the error log file.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - A pointer to the driver object for the device.
|
|
|
|
DeviceObject - A pointer to the device object associated with the
|
|
device that had the error, early in initialization, one may not
|
|
yet exist.
|
|
|
|
P1,P2 - If phyical addresses for the controller ports involved
|
|
with the error are available, put them through as dump data.
|
|
|
|
SequenceNumber - A ulong value that is unique to an IRP over the
|
|
life of the irp in this driver - 0 generally means an error not
|
|
associated with an irp.
|
|
|
|
MajorFunctionCode - If there is an error associated with the irp,
|
|
this is the major function code of that irp.
|
|
|
|
RetryCount - The number of times a particular operation has been
|
|
retried.
|
|
|
|
UniqueErrorValue - A unique long word that identifies the particular
|
|
call to this function.
|
|
|
|
FinalStatus - The final status given to the irp that was associated
|
|
with this error. If this log entry is being made during one of
|
|
the retries this value will be STATUS_SUCCESS.
|
|
|
|
SpecificIOStatus - The IO status for a particular error.
|
|
|
|
LengthOfInsert1 - The length in bytes (including the terminating NULL)
|
|
of the first insertion string.
|
|
|
|
Insert1 - The first insertion string.
|
|
|
|
LengthOfInsert2 - The length in bytes (including the terminating NULL)
|
|
of the second insertion string. NOTE, there must
|
|
be a first insertion string for their to be
|
|
a second insertion string.
|
|
|
|
Insert2 - The second insertion string.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIO_ERROR_LOG_PACKET errorLogEntry;
|
|
|
|
PVOID objectToUse;
|
|
SHORT dumpToAllocate = 0;
|
|
PUCHAR ptrToFirstInsert;
|
|
PUCHAR ptrToSecondInsert;
|
|
|
|
//PAGED_CODE();
|
|
|
|
if (Insert1 == NULL) {
|
|
LengthOfInsert1 = 0;
|
|
}
|
|
|
|
if (Insert2 == NULL) {
|
|
LengthOfInsert2 = 0;
|
|
}
|
|
|
|
|
|
if (ARGUMENT_PRESENT(DeviceObject)) {
|
|
|
|
objectToUse = DeviceObject;
|
|
|
|
} else {
|
|
|
|
objectToUse = DriverObject;
|
|
|
|
}
|
|
|
|
if (MoxaMemCompare(
|
|
P1,
|
|
(ULONG)1,
|
|
MoxaPhysicalZero,
|
|
(ULONG)1
|
|
) != AddressesAreEqual) {
|
|
|
|
dumpToAllocate = (SHORT)sizeof(PHYSICAL_ADDRESS);
|
|
|
|
}
|
|
|
|
if (MoxaMemCompare(
|
|
P2,
|
|
(ULONG)1,
|
|
MoxaPhysicalZero,
|
|
(ULONG)1
|
|
) != AddressesAreEqual) {
|
|
|
|
dumpToAllocate += (SHORT)sizeof(PHYSICAL_ADDRESS);
|
|
|
|
}
|
|
|
|
errorLogEntry = IoAllocateErrorLogEntry(
|
|
objectToUse,
|
|
(UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
|
|
dumpToAllocate
|
|
+ LengthOfInsert1 +
|
|
LengthOfInsert2)
|
|
);
|
|
|
|
if ( errorLogEntry != NULL ) {
|
|
|
|
errorLogEntry->ErrorCode = SpecificIOStatus;
|
|
errorLogEntry->SequenceNumber = SequenceNumber;
|
|
errorLogEntry->MajorFunctionCode = MajorFunctionCode;
|
|
errorLogEntry->RetryCount = RetryCount;
|
|
errorLogEntry->UniqueErrorValue = UniqueErrorValue;
|
|
errorLogEntry->FinalStatus = FinalStatus;
|
|
errorLogEntry->DumpDataSize = dumpToAllocate;
|
|
|
|
if (dumpToAllocate) {
|
|
|
|
RtlCopyMemory(
|
|
&errorLogEntry->DumpData[0],
|
|
&P1,
|
|
sizeof(PHYSICAL_ADDRESS)
|
|
);
|
|
|
|
if (dumpToAllocate > sizeof(PHYSICAL_ADDRESS)) {
|
|
|
|
RtlCopyMemory(
|
|
((PUCHAR)&errorLogEntry->DumpData[0])
|
|
+sizeof(PHYSICAL_ADDRESS),
|
|
&P2,
|
|
sizeof(PHYSICAL_ADDRESS)
|
|
);
|
|
|
|
ptrToFirstInsert =
|
|
((PUCHAR)&errorLogEntry->DumpData[0])+(2*sizeof(PHYSICAL_ADDRESS));
|
|
|
|
} else {
|
|
|
|
ptrToFirstInsert =
|
|
((PUCHAR)&errorLogEntry->DumpData[0])+sizeof(PHYSICAL_ADDRESS);
|
|
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ptrToFirstInsert = (PUCHAR)&errorLogEntry->DumpData[0];
|
|
|
|
}
|
|
|
|
ptrToSecondInsert = ptrToFirstInsert + LengthOfInsert1;
|
|
|
|
if (LengthOfInsert1) {
|
|
|
|
errorLogEntry->NumberOfStrings = 1;
|
|
errorLogEntry->StringOffset = (USHORT)(ptrToFirstInsert -
|
|
(PUCHAR)errorLogEntry);
|
|
RtlCopyMemory(
|
|
ptrToFirstInsert,
|
|
Insert1,
|
|
LengthOfInsert1
|
|
);
|
|
|
|
if (LengthOfInsert2) {
|
|
|
|
errorLogEntry->NumberOfStrings = 2;
|
|
RtlCopyMemory(
|
|
ptrToSecondInsert,
|
|
Insert2,
|
|
LengthOfInsert2
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
IoWriteErrorLogEntry(errorLogEntry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MOXA_MEM_COMPARES
|
|
MoxaMemCompare(
|
|
IN PHYSICAL_ADDRESS A,
|
|
IN ULONG SpanOfA,
|
|
IN PHYSICAL_ADDRESS B,
|
|
IN ULONG SpanOfB
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compare two phsical address.
|
|
|
|
Arguments:
|
|
|
|
A - One half of the comparison.
|
|
|
|
SpanOfA - In units of bytes, the span of A.
|
|
|
|
B - One half of the comparison.
|
|
|
|
SpanOfB - In units of bytes, the span of B.
|
|
|
|
|
|
Return Value:
|
|
|
|
The result of the comparison.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
LARGE_INTEGER a;
|
|
LARGE_INTEGER b;
|
|
|
|
LARGE_INTEGER lower;
|
|
ULONG lowerSpan;
|
|
LARGE_INTEGER higher;
|
|
|
|
//PAGED_CODE();
|
|
|
|
a = A;
|
|
b = B;
|
|
|
|
if (a.QuadPart == b.QuadPart) {
|
|
|
|
return AddressesAreEqual;
|
|
|
|
}
|
|
|
|
if (a.QuadPart > b.QuadPart) {
|
|
|
|
higher = a;
|
|
lower = b;
|
|
lowerSpan = SpanOfB;
|
|
|
|
} else {
|
|
|
|
higher = b;
|
|
lower = a;
|
|
lowerSpan = SpanOfA;
|
|
|
|
}
|
|
|
|
if ((higher.QuadPart - lower.QuadPart) >= lowerSpan) {
|
|
|
|
return AddressesAreDisjoint;
|
|
|
|
}
|
|
|
|
return AddressesOverlap;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
MoxaFilterCancelQueued(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will be used cancel irps on the stalled queue.
|
|
|
|
Arguments:
|
|
|
|
PDevObj - Pointer to the device object.
|
|
|
|
PIrp - Pointer to the Irp to cancel
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PMOXA_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
|
|
PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(PIrp);
|
|
|
|
PIrp->IoStatus.Status = STATUS_CANCELLED;
|
|
PIrp->IoStatus.Information = 0;
|
|
|
|
RemoveEntryList(&PIrp->Tail.Overlay.ListEntry);
|
|
|
|
IoReleaseCancelSpinLock(PIrp->CancelIrql);
|
|
}
|
|
|
|
VOID
|
|
MoxaKillAllStalled(IN PDEVICE_OBJECT PDevObj)
|
|
{
|
|
KIRQL cancelIrql;
|
|
PDRIVER_CANCEL cancelRoutine;
|
|
PMOXA_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
|
|
|
|
IoAcquireCancelSpinLock(&cancelIrql);
|
|
|
|
while (!IsListEmpty(&pDevExt->StalledIrpQueue)) {
|
|
|
|
PIRP currentLastIrp = CONTAINING_RECORD(pDevExt->StalledIrpQueue.Blink,
|
|
IRP, Tail.Overlay.ListEntry);
|
|
|
|
RemoveEntryList(pDevExt->StalledIrpQueue.Blink);
|
|
|
|
cancelRoutine = currentLastIrp->CancelRoutine;
|
|
currentLastIrp->CancelIrql = cancelIrql;
|
|
currentLastIrp->CancelRoutine = NULL;
|
|
currentLastIrp->Cancel = TRUE;
|
|
|
|
cancelRoutine(PDevObj, currentLastIrp);
|
|
|
|
IoAcquireCancelSpinLock(&cancelIrql);
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(cancelIrql);
|
|
}
|
|
|
|
NTSTATUS
|
|
MoxaFilterIrps(IN PIRP PIrp, IN PMOXA_DEVICE_EXTENSION PDevExt)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will be used to approve irps for processing.
|
|
If an irp is approved, success will be returned. If not,
|
|
the irp will be queued or rejected outright. The IoStatus struct
|
|
and return value will appropriately reflect the actions taken.
|
|
|
|
Arguments:
|
|
|
|
PIrp - Pointer to the Irp to cancel
|
|
|
|
PDevExt - Pointer to the device extension
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION pIrpStack;
|
|
KIRQL oldIrqlFlags;
|
|
|
|
pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
|
|
|
|
KeAcquireSpinLock(&PDevExt->FlagsLock, &oldIrqlFlags);
|
|
|
|
if ((PDevExt->DevicePNPAccept == SERIAL_PNPACCEPT_OK)
|
|
&& ((PDevExt->Flags & SERIAL_FLAGS_BROKENHW) == 0)) {
|
|
KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if ((PDevExt->DevicePNPAccept & SERIAL_PNPACCEPT_REMOVING)
|
|
|| (PDevExt->Flags & SERIAL_FLAGS_BROKENHW)
|
|
|| (PDevExt->DevicePNPAccept & SERIAL_PNPACCEPT_SURPRISE_REMOVING)) {
|
|
|
|
KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);
|
|
|
|
//
|
|
// Accept all PNP IRP's -- we assume PNP can synchronize itself
|
|
//
|
|
|
|
if (pIrpStack->MajorFunction == IRP_MJ_PNP) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
PIrp->IoStatus.Status = STATUS_DELETE_PENDING;
|
|
return STATUS_DELETE_PENDING;
|
|
}
|
|
|
|
if (PDevExt->DevicePNPAccept & SERIAL_PNPACCEPT_STOPPING) {
|
|
KIRQL oldIrql;
|
|
|
|
KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);
|
|
|
|
|
|
//
|
|
// Accept all PNP IRP's -- we assume PNP can synchronize itself
|
|
//
|
|
|
|
if (pIrpStack->MajorFunction == IRP_MJ_PNP) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
|
|
if (PIrp->Cancel) {
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
PIrp->IoStatus.Status = STATUS_CANCELLED;
|
|
return STATUS_CANCELLED;
|
|
} else {
|
|
//
|
|
// Mark the Irp as pending
|
|
//
|
|
|
|
PIrp->IoStatus.Status = STATUS_PENDING;
|
|
IoMarkIrpPending(PIrp);
|
|
|
|
//
|
|
// Queue up the IRP
|
|
//
|
|
|
|
InsertTailList(&PDevExt->StalledIrpQueue,
|
|
&PIrp->Tail.Overlay.ListEntry);
|
|
|
|
IoSetCancelRoutine(PIrp, MoxaFilterCancelQueued);
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
return STATUS_PENDING;
|
|
}
|
|
}
|
|
|
|
KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrqlFlags);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
MoxaUnstallIrps(IN PMOXA_DEVICE_EXTENSION PDevExt)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will be used to restart irps temporarily stalled on
|
|
the stall queue due to a stop or some such nonsense.
|
|
|
|
Arguments:
|
|
|
|
PDevExt - Pointer to the device extension
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY pIrpLink;
|
|
PIRP pIrp;
|
|
PIO_STACK_LOCATION pIrpStack;
|
|
PDEVICE_OBJECT pDevObj;
|
|
PDRIVER_OBJECT pDrvObj;
|
|
KIRQL oldIrql;
|
|
|
|
MoxaKdPrint(
|
|
MX_DBG_TRACE,
|
|
("Entering MoxaUnstallIrps\n"));
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
|
|
pIrpLink = PDevExt->StalledIrpQueue.Flink;
|
|
|
|
while (pIrpLink != &PDevExt->StalledIrpQueue) {
|
|
pIrp = CONTAINING_RECORD(pIrpLink, IRP, Tail.Overlay.ListEntry);
|
|
pIrpLink = pIrp->Tail.Overlay.ListEntry.Flink;
|
|
RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
|
|
|
|
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
|
|
pDevObj = pIrpStack->DeviceObject;
|
|
pDrvObj = pDevObj->DriverObject;
|
|
IoSetCancelRoutine(pIrp, NULL);
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
MoxaKdPrint(MX_DBG_TRACE,("Unstalling Irp 0x%x with 0x%x\n",
|
|
pIrp, pIrpStack->MajorFunction));
|
|
|
|
pDrvObj->MajorFunction[pIrpStack->MajorFunction](pDevObj, pIrp);
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
MoxaKdPrint(MX_DBG_TRACE,("Leaving MoxaUnstallIrps\n"));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
MoxaIRPPrologue(IN PIRP PIrp, IN PMOXA_DEVICE_EXTENSION PDevExt)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function must be called at any IRP dispatch entry point. It,
|
|
with SerialIRPEpilogue(), keeps track of all pending IRP's for the given
|
|
PDevObj.
|
|
|
|
Arguments:
|
|
|
|
PDevObj - Pointer to the device object we are tracking pending IRP's for.
|
|
|
|
Return Value:
|
|
|
|
Tentative status of the Irp.
|
|
|
|
--*/
|
|
{
|
|
InterlockedIncrement(&PDevExt->PendingIRPCnt);
|
|
|
|
return MoxaFilterIrps(PIrp, PDevExt);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
MoxaIRPEpilogue(IN PMOXA_DEVICE_EXTENSION PDevExt)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function must be called at any IRP dispatch entry point. It,
|
|
with MoxaIRPPrologue(), keeps track of all pending IRP's for the given
|
|
PDevObj.
|
|
|
|
Arguments:
|
|
|
|
PDevObj - Pointer to the device object we are tracking pending IRP's for.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
LONG pendingCnt;
|
|
|
|
pendingCnt = InterlockedDecrement(&PDevExt->PendingIRPCnt);
|
|
//MoxaKdPrint(MX_DBG_TRACE,("MoxaIRPEpilogue = %x\n",PDevExt));
|
|
|
|
// ASSERT(pendingCnt >= 0);
|
|
|
|
if (pendingCnt == 0) {
|
|
KeSetEvent(&PDevExt->PendingIRPEvent, IO_NO_INCREMENT, FALSE);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
MoxaSetDeviceFlags(IN PMOXA_DEVICE_EXTENSION PDevExt, OUT PULONG PFlags,
|
|
IN ULONG Value, IN BOOLEAN Set)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets flags in a value protected by the flags spinlock. This is used
|
|
to set values that would stop IRP's from being accepted.
|
|
|
|
Arguments:
|
|
PDevExt - Device extension attached to PDevObj
|
|
|
|
PFlags - Pointer to the flags variable that needs changing
|
|
|
|
Value - Value to modify flags variable with
|
|
|
|
Set - TRUE if |= , FALSE if &=
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
KIRQL oldIrql;
|
|
|
|
KeAcquireSpinLock(&PDevExt->FlagsLock, &oldIrql);
|
|
|
|
if (Set) {
|
|
*PFlags |= Value;
|
|
} else {
|
|
*PFlags &= ~Value;
|
|
}
|
|
|
|
KeReleaseSpinLock(&PDevExt->FlagsLock, oldIrql);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MoxaIoCallDriver(PMOXA_DEVICE_EXTENSION PDevExt, PDEVICE_OBJECT PDevObj,
|
|
PIRP PIrp)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function must be called instead of IoCallDriver. It automatically
|
|
updates Irp tracking for PDevObj.
|
|
|
|
Arguments:
|
|
PDevExt - Device extension attached to PDevObj
|
|
|
|
PDevObj - Pointer to the device object we are tracking pending IRP's for.
|
|
|
|
PIrp - Pointer to the Irp we are passing to the next driver.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = IoCallDriver(PDevObj, PIrp);
|
|
MoxaIRPEpilogue(PDevExt);
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
MoxaPoCallDriver(PMOXA_DEVICE_EXTENSION PDevExt, PDEVICE_OBJECT PDevObj,
|
|
PIRP PIrp)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function must be called instead of PoCallDriver. It automatically
|
|
updates Irp tracking for PDevObj.
|
|
|
|
Arguments:
|
|
PDevExt - Device extension attached to PDevObj
|
|
|
|
PDevObj - Pointer to the device object we are tracking pending IRP's for.
|
|
|
|
PIrp - Pointer to the Irp we are passing to the next driver.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = PoCallDriver(PDevObj, PIrp);
|
|
MoxaIRPEpilogue(PDevExt);
|
|
return status;
|
|
}
|
|
|
|
|
|
VOID
|
|
MoxaKillPendingIrps(PDEVICE_OBJECT PDevObj)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine kills any irps pending for the passed device object.
|
|
|
|
Arguments:
|
|
|
|
PDevObj - Pointer to the device object whose irps must die.
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
PMOXA_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
|
|
KIRQL oldIrql;
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE,("Enter MoxaKillPendingIrps\n"));
|
|
|
|
//
|
|
// First kill all the reads and writes.
|
|
//
|
|
|
|
MoxaKillAllReadsOrWrites(PDevObj, &pDevExt->WriteQueue,
|
|
&pDevExt->CurrentWriteIrp);
|
|
|
|
MoxaKillAllReadsOrWrites(PDevObj, &pDevExt->ReadQueue,
|
|
&pDevExt->CurrentReadIrp);
|
|
|
|
//
|
|
// Next get rid of purges.
|
|
//
|
|
|
|
MoxaKillAllReadsOrWrites(PDevObj, &pDevExt->PurgeQueue,
|
|
&pDevExt->CurrentPurgeIrp);
|
|
|
|
//
|
|
// Get rid of any mask operations.
|
|
//
|
|
|
|
MoxaKillAllReadsOrWrites(PDevObj, &pDevExt->MaskQueue,
|
|
&pDevExt->CurrentMaskIrp);
|
|
|
|
//
|
|
// Now get rid a pending wait mask irp.
|
|
//
|
|
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
|
|
if (pDevExt->CurrentWaitIrp) {
|
|
|
|
PDRIVER_CANCEL cancelRoutine;
|
|
|
|
cancelRoutine = pDevExt->CurrentWaitIrp->CancelRoutine;
|
|
pDevExt->CurrentWaitIrp->Cancel = TRUE;
|
|
|
|
if (cancelRoutine) {
|
|
|
|
pDevExt->CurrentWaitIrp->CancelIrql = oldIrql;
|
|
pDevExt->CurrentWaitIrp->CancelRoutine = NULL;
|
|
|
|
cancelRoutine(PDevObj, pDevExt->CurrentWaitIrp);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
IoReleaseCancelSpinLock(oldIrql);
|
|
|
|
}
|
|
|
|
//
|
|
// Cancel any pending wait-wake irps
|
|
//
|
|
|
|
if (pDevExt->PendingWakeIrp != NULL) {
|
|
IoCancelIrp(pDevExt->PendingWakeIrp);
|
|
pDevExt->PendingWakeIrp = NULL;
|
|
}
|
|
|
|
//
|
|
// Finally, dump any stalled IRPS
|
|
//
|
|
|
|
MoxaKillAllStalled(PDevObj);
|
|
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE, ("Leave MoxaKillPendingIrps\n"));
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
MoxaReleaseResources(IN PMOXA_DEVICE_EXTENSION pDevExt)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Releases resources (not pool) stored in the device extension.
|
|
|
|
Arguments:
|
|
|
|
pDevExt - Pointer to the device extension to release resources from.
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
// PAGED_CODE();
|
|
BOOLEAN anyPortExist = TRUE;
|
|
ULONG port,i;
|
|
PDEVICE_OBJECT pDevObj;
|
|
UNICODE_STRING deviceLinkUnicodeString;
|
|
PMOXA_DEVICE_EXTENSION pDevExt1;
|
|
|
|
MoxaKdPrint(MX_DBG_TRACE,("Enter MoxaReleaseResources\n"));
|
|
|
|
|
|
|
|
// KeSynchronizeExecution(pDevExt->Interrupt, MoxaCleanInterruptShareLists, pDevExt);
|
|
MoxaCleanInterruptShareLists(pDevExt);
|
|
|
|
|
|
//
|
|
// Stop servicing interrupts if we are the last one
|
|
//
|
|
|
|
for (i = 0; i < MoxaGlobalData->NumPorts[pDevExt->BoardNo]; i++) {
|
|
port = pDevExt->BoardNo*MAXPORT_PER_CARD + i;
|
|
if ((pDevExt1 = MoxaGlobalData->Extension[port]) != NULL) {
|
|
if (pDevExt1->PortIndex != pDevExt->PortIndex) {
|
|
MoxaKdPrint(MX_DBG_TRACE,("There is still a port in this board %d/%d\n",i,port));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( i == MoxaGlobalData->NumPorts[pDevExt->BoardNo]) {
|
|
MoxaKdPrint(MX_DBG_TRACE,("It is the last port of this board\n"));
|
|
anyPortExist = FALSE;
|
|
|
|
for (i = 0; i < MAX_CARD; i++) {
|
|
if (MoxaGlobalData->CardType[i] && (i != pDevExt->BoardNo))
|
|
break;
|
|
}
|
|
if (i == MAX_CARD) {
|
|
MoxaKdPrint(MX_DBG_TRACE,("No more devices,so delete control device\n"));
|
|
RtlInitUnicodeString (
|
|
&deviceLinkUnicodeString,
|
|
CONTROL_DEVICE_LINK
|
|
);
|
|
|
|
IoDeleteSymbolicLink(&deviceLinkUnicodeString);
|
|
pDevObj=MoxaGlobalData->DriverObject->DeviceObject;
|
|
while (pDevObj) {
|
|
MoxaKdPrint(MX_DBG_TRACE,("There is still a devices\n"));
|
|
if (((PMOXA_DEVICE_EXTENSION)(pDevObj->DeviceExtension))->ControlDevice) {
|
|
MoxaKdPrint(MX_DBG_TRACE,("Is Control Device,so delete it\n"));
|
|
IoDeleteDevice(pDevObj);
|
|
break;
|
|
}
|
|
pDevObj=pDevObj->NextDevice;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
pDevExt->Interrupt = NULL;
|
|
|
|
//
|
|
// Stop handling timers
|
|
//
|
|
|
|
MoxaCancelTimer(&pDevExt->ReadRequestTotalTimer, pDevExt);
|
|
MoxaCancelTimer(&pDevExt->ReadRequestIntervalTimer, pDevExt);
|
|
MoxaCancelTimer(&pDevExt->WriteRequestTotalTimer, pDevExt);
|
|
|
|
|
|
//
|
|
// Stop servicing DPC's
|
|
//
|
|
|
|
MoxaRemoveQueueDpc(&pDevExt->CompleteWriteDpc, pDevExt);
|
|
MoxaRemoveQueueDpc(&pDevExt->CompleteReadDpc, pDevExt);
|
|
MoxaRemoveQueueDpc(&pDevExt->TotalReadTimeoutDpc, pDevExt);
|
|
MoxaRemoveQueueDpc(&pDevExt->IntervalReadTimeoutDpc, pDevExt);
|
|
MoxaRemoveQueueDpc(&pDevExt->TotalWriteTimeoutDpc, pDevExt);
|
|
MoxaRemoveQueueDpc(&pDevExt->CommErrorDpc, pDevExt);
|
|
MoxaRemoveQueueDpc(&pDevExt->CommWaitDpc, pDevExt);
|
|
|
|
//
|
|
// Remove us from any lists we may be on
|
|
//
|
|
|
|
MoxaGlobalData->Extension[pDevExt->PortNo] = NULL;
|
|
MoxaExtension[MoxaGlobalData->ComNo[pDevExt->BoardNo][pDevExt->PortIndex]] = NULL;
|
|
|
|
if (anyPortExist == FALSE ) {
|
|
MoxaKdPrint(MX_DBG_TRACE,("Free the global info. associated with this board\n"));
|
|
MoxaGlobalData->Interrupt[pDevExt->BoardNo] = NULL;
|
|
MoxaGlobalData->CardType[pDevExt->BoardNo] = 0;
|
|
MoxaGlobalData->InterfaceType[pDevExt->BoardNo] = 0;
|
|
MoxaGlobalData->IntVector[pDevExt->BoardNo] = 0;
|
|
MoxaGlobalData->PciIntAckBase[pDevExt->BoardNo] = NULL;
|
|
MoxaGlobalData->CardBase[pDevExt->BoardNo] = 0;
|
|
MoxaGlobalData->IntNdx[pDevExt->BoardNo] = NULL;
|
|
MoxaGlobalData->IntPend[pDevExt->BoardNo] = NULL;
|
|
MoxaGlobalData->IntTable[pDevExt->BoardNo] = NULL;
|
|
MoxaGlobalData->NumPorts[pDevExt->BoardNo] = 0;
|
|
RtlZeroMemory(&MoxaGlobalData->PciIntAckPort[pDevExt->BoardNo],sizeof(PHYSICAL_ADDRESS));
|
|
RtlZeroMemory(&MoxaGlobalData->BankAddr[pDevExt->BoardNo],sizeof(PHYSICAL_ADDRESS));
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
MoxaDisableInterfacesResources(IN PDEVICE_OBJECT PDevObj,
|
|
BOOLEAN DisableUART)
|
|
{
|
|
PMOXA_DEVICE_EXTENSION pDevExt
|
|
= (PMOXA_DEVICE_EXTENSION)PDevObj->DeviceExtension;
|
|
|
|
// PAGED_CODE();
|
|
|
|
MoxaKdPrint(MX_DBG_TRACE,("Enter MoxaDisableInterfaces\n"));
|
|
|
|
//
|
|
// Only do these many things if the device has started and still
|
|
// has resources allocated
|
|
//
|
|
|
|
// if (pDevExt->Flags & SERIAL_FLAGS_STARTED) {
|
|
if (!(pDevExt->Flags & SERIAL_FLAGS_STOPPED)) {
|
|
|
|
if (DisableUART) {
|
|
//
|
|
// Mask off interrupts
|
|
//
|
|
|
|
// ????? DISABLE_ALL_INTERRUPTS(pDevExt->Controller);
|
|
}
|
|
|
|
MoxaReleaseResources(pDevExt);
|
|
}
|
|
|
|
//
|
|
// Remove us from WMI consideration
|
|
//
|
|
|
|
IoWMIRegistrationControl(PDevObj, WMIREG_ACTION_DEREGISTER);
|
|
// }
|
|
|
|
//
|
|
// Undo external names
|
|
//
|
|
|
|
MoxaUndoExternalNaming(pDevExt);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
MoxaRemoveDevObj(IN PDEVICE_OBJECT PDevObj)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes a serial device object from the system.
|
|
|
|
Arguments:
|
|
|
|
PDevObj - A pointer to the Device Object we want removed.
|
|
|
|
Return Value:
|
|
|
|
Always TRUE
|
|
|
|
--*/
|
|
{
|
|
PMOXA_DEVICE_EXTENSION pDevExt
|
|
= (PMOXA_DEVICE_EXTENSION)PDevObj->DeviceExtension;
|
|
|
|
//PAGED_CODE();
|
|
|
|
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE,("Enter MoxaRemoveDevObj\n"));
|
|
|
|
if (!(pDevExt->DevicePNPAccept & SERIAL_PNPACCEPT_SURPRISE_REMOVING)) {
|
|
//
|
|
// Disable all external interfaces and release resources
|
|
//
|
|
|
|
MoxaDisableInterfacesResources(PDevObj,TRUE);
|
|
}
|
|
|
|
IoDetachDevice(pDevExt->LowerDeviceObject);
|
|
|
|
//
|
|
// Free memory allocated in the extension
|
|
//
|
|
|
|
if (pDevExt->DeviceName.Buffer != NULL) {
|
|
ExFreePool(pDevExt->DeviceName.Buffer);
|
|
}
|
|
|
|
if (pDevExt->SymbolicLinkName.Buffer != NULL) {
|
|
ExFreePool(pDevExt->SymbolicLinkName.Buffer);
|
|
}
|
|
|
|
if (pDevExt->ObjectDirectory.Buffer) {
|
|
ExFreePool(pDevExt->ObjectDirectory.Buffer);
|
|
}
|
|
|
|
//
|
|
// Delete the devobj
|
|
//
|
|
|
|
IoDeleteDevice(PDevObj);
|
|
|
|
|
|
MoxaKdPrint (MX_DBG_TRACE, ("Leave SerialRemoveDevObj\n"));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
MoxaIoSyncIoctlEx(ULONG Ioctl, BOOLEAN Internal, PDEVICE_OBJECT PDevObj,
|
|
PKEVENT PEvent, PIO_STATUS_BLOCK PIoStatusBlock,
|
|
PVOID PInBuffer, ULONG InBufferLen, PVOID POutBuffer, // output buffer - optional
|
|
ULONG OutBufferLen)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Performs a synchronous IO control request by waiting on the event object
|
|
passed to it. The IRP is deallocated by the IO system when finished.
|
|
|
|
Return value:
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PIRP pIrp;
|
|
NTSTATUS status;
|
|
|
|
KeClearEvent(PEvent);
|
|
|
|
// Allocate an IRP - No need to release
|
|
// When the next-lower driver completes this IRP, the IO Mgr releases it.
|
|
|
|
pIrp = IoBuildDeviceIoControlRequest(Ioctl, PDevObj, PInBuffer, InBufferLen,
|
|
POutBuffer, OutBufferLen, Internal,
|
|
PEvent, PIoStatusBlock);
|
|
|
|
if (pIrp == NULL) {
|
|
MoxaKdPrint (MX_DBG_TRACE, ("Failed to allocate IRP\n"));
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
status = MoxaIoSyncReq(PDevObj, pIrp, PEvent);
|
|
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
status = PIoStatusBlock->Status;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MoxaIoSyncReq(PDEVICE_OBJECT PDevObj, IN PIRP PIrp, PKEVENT PEvent)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Performs a synchronous IO request by waiting on the event object
|
|
passed to it. The IRP is deallocated by the IO system when finished.
|
|
|
|
Return value:
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = IoCallDriver(PDevObj, PIrp);
|
|
|
|
if (status == STATUS_PENDING) {
|
|
// wait for it...
|
|
status = KeWaitForSingleObject(PEvent, Executive, KernelMode, FALSE,
|
|
NULL);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
MoxaCleanInterruptShareLists(IN PMOXA_DEVICE_EXTENSION pDevExt )
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes a device object from any of the serial linked lists it may
|
|
appear on.
|
|
|
|
Arguments:
|
|
|
|
Context - Actually a PMOXA_DEVICE_EXTENSION (for the devobj being
|
|
removed).
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY interruptEntry;
|
|
PMOXA_CISR_SW cisrsw;
|
|
PMOXA_DEVICE_EXTENSION pDevExt1;
|
|
PMOXA_GLOBAL_DATA globalData = pDevExt->GlobalData;
|
|
ULONG cardNo,port,i;
|
|
PMOXA_MULTIPORT_DISPATCH dispatch;
|
|
|
|
|
|
// ASSERT(!IsListEmpty(pDevExt->InterruptShareList));
|
|
if (IsListEmpty(pDevExt->InterruptShareList))
|
|
return (FALSE);
|
|
|
|
//
|
|
// Stop servicing interrupts if we are the last one
|
|
//
|
|
|
|
for ( i = 0; i < globalData->NumPorts[pDevExt->BoardNo]; i++) {
|
|
port = pDevExt->BoardNo*MAXPORT_PER_CARD + i;
|
|
if ((pDevExt1 = globalData->Extension[port]) != NULL) {
|
|
if (pDevExt1->PortIndex != pDevExt->PortIndex) {
|
|
MoxaKdPrint(MX_DBG_TRACE,("There is still a port in this board %d/%d\n",i,port));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( i != globalData->NumPorts[pDevExt->BoardNo])
|
|
return (TRUE);
|
|
|
|
MoxaKdPrint(MX_DBG_TRACE,("It is the last port of this board\n"));
|
|
MoxaKdPrint(MX_DBG_TRACE,("Interrupt share list = %x\n",pDevExt->InterruptShareList));
|
|
|
|
|
|
interruptEntry = (pDevExt->InterruptShareList)->Flink;
|
|
|
|
do {
|
|
MoxaKdPrint(MX_DBG_TRACE,("find list\n"));
|
|
cisrsw = CONTAINING_RECORD(interruptEntry,
|
|
MOXA_CISR_SW,
|
|
SharerList
|
|
);
|
|
MoxaKdPrint(MX_DBG_TRACE,("cisrsw = %x\n",cisrsw));
|
|
|
|
if (!cisrsw)
|
|
return (FALSE);
|
|
dispatch = &cisrsw->Dispatch;
|
|
cardNo = dispatch->BoardNo;
|
|
MoxaKdPrint(MX_DBG_TRACE,("cardNo = %x\n",cardNo));
|
|
if (cardNo == pDevExt->BoardNo) {
|
|
|
|
MoxaRemoveLists(interruptEntry);
|
|
MoxaKdPrint(MX_DBG_TRACE,("list removed\n"));
|
|
if (IsListEmpty(pDevExt->InterruptShareList)) {
|
|
MoxaKdPrint(MX_DBG_TRACE,("No more board use this IRQ so Disconnect it\n"));
|
|
IoDisconnectInterrupt(pDevExt->Interrupt);
|
|
MoxaKdPrint(MX_DBG_TRACE,("free share list\n"));
|
|
ExFreePool(pDevExt->InterruptShareList);
|
|
}
|
|
MoxaKdPrint(MX_DBG_TRACE,("free others\n"));
|
|
|
|
ExFreePool(cisrsw);
|
|
MoxaKdPrint(MX_DBG_TRACE,("free ok\n"));
|
|
return (TRUE);
|
|
}
|
|
interruptEntry = interruptEntry->Flink;
|
|
MoxaKdPrint(MX_DBG_TRACE,("get next\n"));
|
|
|
|
}
|
|
while (interruptEntry != pDevExt->InterruptShareList);
|
|
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
MoxaRemoveLists(IN PVOID Context)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes a list entry from the InterruptShareList.
|
|
|
|
Arguments:
|
|
|
|
Context - Actually a list entry of InterruptShareList .
|
|
|
|
Return Value:
|
|
|
|
Always TRUE
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY pListEntry = (PLIST_ENTRY)Context;
|
|
|
|
RemoveEntryList(pListEntry);
|
|
return (TRUE);
|
|
}
|
|
|
|
|
|
VOID
|
|
MoxaUnlockPages(IN PKDPC PDpc, IN PVOID PDeferredContext,
|
|
IN PVOID PSysContext1, IN PVOID PSysContext2)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is a DPC routine queue from the ISR if he released the
|
|
last lock on pending DPC's.
|
|
|
|
Arguments:
|
|
|
|
PDpdc, PSysContext1, PSysContext2 -- not used
|
|
|
|
PDeferredContext -- Really the device extension
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PMOXA_DEVICE_EXTENSION pDevExt
|
|
= (PMOXA_DEVICE_EXTENSION)PDeferredContext;
|
|
|
|
UNREFERENCED_PARAMETER(PDpc);
|
|
UNREFERENCED_PARAMETER(PSysContext1);
|
|
UNREFERENCED_PARAMETER(PSysContext2);
|
|
|
|
KeSetEvent(&pDevExt->PendingDpcEvent, IO_NO_INCREMENT, FALSE);
|
|
}
|
|
|
|
VOID
|
|
MoxaLoop()
|
|
{
|
|
LARGE_INTEGER targetTc, newTc, currTc, newTc1;
|
|
ULONG unit, count;
|
|
LARGE_INTEGER interval; /* 1 ms */
|
|
|
|
KeQueryTickCount(&currTc);
|
|
|
|
unit = KeQueryTimeIncrement();
|
|
|
|
currTc = RtlExtendedIntegerMultiply(currTc, unit);
|
|
|
|
interval = RtlConvertUlongToLargeInteger(10000L);
|
|
|
|
targetTc = RtlLargeIntegerAdd(currTc, interval);
|
|
|
|
MoxaLoopCnt = 0;
|
|
|
|
do {
|
|
|
|
KeQueryTickCount(&newTc);
|
|
|
|
newTc = RtlExtendedIntegerMultiply(newTc, unit);
|
|
|
|
MoxaLoopCnt++;
|
|
|
|
} while (!RtlLargeIntegerGreaterThanOrEqualTo(newTc, targetTc));
|
|
|
|
MoxaLoopCnt += 0x1000;
|
|
}
|
|
|