Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2784 lines
71 KiB

/*++
Module Name:
ioctl.c
Environment:
Kernel mode
Revision History :
--*/
#include "precomp.h"
NTSTATUS
MoxaIoControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS status;
//
// The current stack location. This contains all of the
// information we need to process this particular request.
//
PIO_STACK_LOCATION irpSp;
//
PMOXA_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
ULONG ioControlCode;
KIRQL oldIrql;
//
// We expect to be open so all our pages are locked down. This is, after
// all, an IO operation, so the device should be open first.
//
if (extension->DeviceIsOpened != TRUE) {
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INVALID_DEVICE_REQUEST;
}
irpSp = IoGetCurrentIrpStackLocation(Irp);
ioControlCode = irpSp->Parameters.DeviceIoControl.IoControlCode;
if (extension->ControlDevice) {
if (
(ioControlCode != IOCTL_MOXA_GetSeg) &&
(ioControlCode != IOCTL_MOXA_RdData) &&
(ioControlCode != IOCTL_MOXA_WrData) &&
(ioControlCode != IOCTL_MOXA_FiData) &&
(ioControlCode != IOCTL_MOXA_Statistic) &&
(ioControlCode != IOCTL_MOXA_Linked) &&
(ioControlCode != IOCTL_MOXA_PortStatus)) {
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_INVALID_DEVICE_REQUEST;
}
}
else {
if ((status = MoxaIRPPrologue(Irp, extension))
!= STATUS_SUCCESS) {
Irp->IoStatus.Status = status;
MoxaCompleteRequest(extension, Irp, IO_NO_INCREMENT);
return status;
}
if (MoxaCompleteIfError(
DeviceObject,
Irp
) != STATUS_SUCCESS)
return STATUS_CANCELLED;
}
Irp->IoStatus.Information = 0L;
status = STATUS_SUCCESS;
switch (ioControlCode) {
case IOCTL_SERIAL_SET_BAUD_RATE : {
ULONG baudRate;
SHORT divisor;
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(SERIAL_BAUD_RATE)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
else
baudRate = ((PSERIAL_BAUD_RATE)(Irp->AssociatedIrp.SystemBuffer))->BaudRate;
if (baudRate > extension->MaxBaud) {
status = STATUS_INVALID_PARAMETER;
break;
}
status = MoxaGetDivisorFromBaud(
extension->ClockType,
baudRate,
&divisor
);
//
// Make sure we are at power D0
//
#if 0
if (NT_SUCCESS(status)) {
if (extension->PowerState != PowerDeviceD0) {
status = MoxaGotoPowerState(extension->Pdo, extension,
PowerDeviceD0);
if (!NT_SUCCESS(status)) {
break;
}
}
}
#endif
if (extension->PowerState != PowerDeviceD0) {
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
// MoxaKdPrint(MX_DBG_TRACE,("Set Baud to %d,divisor = %x,clock type=%x\n",baudRate,divisor,extension->ClockType));
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
if (NT_SUCCESS(status)) {
extension->CurrentBaud = baudRate;
extension->WmiCommData.BaudRate = baudRate;
MoxaFunc(
extension->PortOfs,
FC_SetBaud,
divisor
);
}
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
break;
}
case IOCTL_SERIAL_GET_BAUD_RATE: {
PSERIAL_BAUD_RATE Br = (PSERIAL_BAUD_RATE)Irp->AssociatedIrp.SystemBuffer;
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(SERIAL_BAUD_RATE)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
Br->BaudRate = extension->CurrentBaud;
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
Irp->IoStatus.Information = sizeof(SERIAL_BAUD_RATE);
break;
}
case IOCTL_SERIAL_SET_LINE_CONTROL: {
PSERIAL_LINE_CONTROL Lc =
((PSERIAL_LINE_CONTROL)(Irp->AssociatedIrp.SystemBuffer));
UCHAR lData;
UCHAR lStop;
UCHAR lParity;
UCHAR mask = 0xff;
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(SERIAL_LINE_CONTROL)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
//
// Make sure we are at power D0
//
#if 0
if (extension->PowerState != PowerDeviceD0) {
status = MoxaGotoPowerState(extension->Pdo, extension,
PowerDeviceD0);
if (!NT_SUCCESS(status)) {
break;
}
}
#endif
if (extension->PowerState != PowerDeviceD0) {
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
switch (Lc->WordLength) {
case 5:
lData = MOXA_5_DATA;
mask = 0x1f;
break;
case 6:
lData = MOXA_6_DATA;
mask = 0x3f;
break;
case 7:
lData = MOXA_7_DATA;
mask = 0x7f;
break;
case 8:
lData = MOXA_8_DATA;
break;
default:
status = STATUS_INVALID_PARAMETER;
goto DoneWithIoctl;
}
extension->WmiCommData.BitsPerByte = Lc->WordLength;
switch (Lc->Parity) {
case NO_PARITY:
lParity = MOXA_NONE_PARITY;
extension->WmiCommData.Parity = SERIAL_WMI_PARITY_NONE;
break;
case EVEN_PARITY:
lParity = MOXA_EVEN_PARITY;
extension->WmiCommData.Parity = SERIAL_WMI_PARITY_EVEN;
break;
case ODD_PARITY:
lParity = MOXA_ODD_PARITY;
extension->WmiCommData.Parity = SERIAL_WMI_PARITY_ODD;
break;
case SPACE_PARITY:
lParity = MOXA_SPACE_PARITY;
extension->WmiCommData.Parity = SERIAL_WMI_PARITY_SPACE;
break;
case MARK_PARITY:
lParity = MOXA_MARK_PARITY;
extension->WmiCommData.Parity = SERIAL_WMI_PARITY_MARK;
break;
default:
status = STATUS_INVALID_PARAMETER;
goto DoneWithIoctl;
}
switch (Lc->StopBits) {
case STOP_BIT_1:
lStop = MOXA_1_STOP;
extension->WmiCommData.StopBits = SERIAL_WMI_STOP_1;
break;
case STOP_BITS_1_5:
if (lData != MOXA_5_DATA) {
status = STATUS_INVALID_PARAMETER;
goto DoneWithIoctl;
}
lStop = MOXA_1_5_STOP;
extension->WmiCommData.StopBits = SERIAL_WMI_STOP_1_5;
break;
case STOP_BITS_2:
if (lData == MOXA_5_DATA) {
status = STATUS_INVALID_PARAMETER;
goto DoneWithIoctl;
}
lStop = MOXA_2_STOP;
extension->WmiCommData.StopBits = SERIAL_WMI_STOP_2;
break;
default:
status = STATUS_INVALID_PARAMETER;
goto DoneWithIoctl;
}
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
extension->DataMode = lData | lParity | lStop;
extension->ValidDataMask = mask;
MoxaFunc(
extension->PortOfs,
FC_SetDataMode,
extension->DataMode
);
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
break;
}
case IOCTL_SERIAL_GET_LINE_CONTROL: {
PSERIAL_LINE_CONTROL Lc = (PSERIAL_LINE_CONTROL)Irp->AssociatedIrp.SystemBuffer;
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(SERIAL_LINE_CONTROL)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
if ((extension->DataMode & MOXA_DATA_MASK) == MOXA_5_DATA) {
Lc->WordLength = 5;
} else if ((extension->DataMode & MOXA_DATA_MASK)
== MOXA_6_DATA) {
Lc->WordLength = 6;
} else if ((extension->DataMode & MOXA_DATA_MASK)
== MOXA_7_DATA) {
Lc->WordLength = 7;
} else if ((extension->DataMode & MOXA_DATA_MASK)
== MOXA_8_DATA) {
Lc->WordLength = 8;
}
if ((extension->DataMode & MOXA_PARITY_MASK)
== MOXA_NONE_PARITY) {
Lc->Parity = NO_PARITY;
} else if ((extension->DataMode & MOXA_PARITY_MASK)
== MOXA_ODD_PARITY) {
Lc->Parity = ODD_PARITY;
} else if ((extension->DataMode & MOXA_PARITY_MASK)
== MOXA_EVEN_PARITY) {
Lc->Parity = EVEN_PARITY;
} else if ((extension->DataMode & MOXA_PARITY_MASK)
== MOXA_MARK_PARITY) {
Lc->Parity = MARK_PARITY;
} else if ((extension->DataMode & MOXA_PARITY_MASK)
== MOXA_SPACE_PARITY) {
Lc->Parity = SPACE_PARITY;
}
if (extension->DataMode & MOXA_2_STOP) {
Lc->StopBits = STOP_BITS_2;
} else if (extension->DataMode & MOXA_1_5_STOP) {
Lc->StopBits = STOP_BITS_1_5;
} else {
Lc->StopBits = STOP_BIT_1;
}
Irp->IoStatus.Information = sizeof(SERIAL_LINE_CONTROL);
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
break;
}
case IOCTL_SERIAL_SET_TIMEOUTS: {
PSERIAL_TIMEOUTS newTimeouts =
((PSERIAL_TIMEOUTS)(Irp->AssociatedIrp.SystemBuffer));
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(SERIAL_TIMEOUTS)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
if ((newTimeouts->ReadIntervalTimeout == MAXULONG) &&
(newTimeouts->ReadTotalTimeoutMultiplier == MAXULONG) &&
(newTimeouts->ReadTotalTimeoutConstant == MAXULONG)) {
status = STATUS_INVALID_PARAMETER;
break;
}
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
extension->Timeouts.ReadIntervalTimeout =
newTimeouts->ReadIntervalTimeout;
extension->Timeouts.ReadTotalTimeoutMultiplier =
newTimeouts->ReadTotalTimeoutMultiplier;
extension->Timeouts.ReadTotalTimeoutConstant =
newTimeouts->ReadTotalTimeoutConstant;
extension->Timeouts.WriteTotalTimeoutMultiplier =
newTimeouts->WriteTotalTimeoutMultiplier;
extension->Timeouts.WriteTotalTimeoutConstant =
newTimeouts->WriteTotalTimeoutConstant;
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
break;
}
case IOCTL_SERIAL_GET_TIMEOUTS: {
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(SERIAL_TIMEOUTS)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
*((PSERIAL_TIMEOUTS)Irp->AssociatedIrp.SystemBuffer) =
extension->Timeouts;
Irp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS);
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
break;
}
case IOCTL_SERIAL_SET_CHARS: {
PSERIAL_CHARS newChars =
((PSERIAL_CHARS)(Irp->AssociatedIrp.SystemBuffer));
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(SERIAL_CHARS)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
//
// 9-26-01 by William
//
// if (newChars->XonChar == newChars->XoffChar) {
if ((newChars->XonChar == newChars->XoffChar) &&
(extension->HandFlow.FlowReplace & (SERIAL_AUTO_TRANSMIT|SERIAL_AUTO_RECEIVE) )
) {
status = STATUS_INVALID_PARAMETER;
break;
}
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
if (extension->EscapeChar) {
if ((extension->EscapeChar == newChars->XonChar) ||
(extension->EscapeChar == newChars->XoffChar)) {
status = STATUS_INVALID_PARAMETER;
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
break;
}
}
extension->SpecialChars = *newChars;
extension->WmiCommData.XonCharacter = newChars->XonChar;
extension->WmiCommData.XoffCharacter = newChars->XoffChar;
{
int i;
PUCHAR ofs;
USHORT cnt;
ofs = extension->PortOfs;
for (i=0; i<sizeof(SERIAL_CHARS); i++)
(ofs + FuncArg)[i] = ((PUCHAR)newChars)[i];
/*12-11-00 by William
cnt = 50;
*(ofs + FuncCode) = FC_SetChars;
while (*(ofs + FuncCode)) {
MoxaDelay(1);
if (--cnt == 0)
break;
}
*/
*(ofs + FuncCode) = FC_SetChars;
MoxaWaitFinish(ofs);
}
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
break;
}
case IOCTL_SERIAL_GET_CHARS: {
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(SERIAL_CHARS)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
*((PSERIAL_CHARS)Irp->AssociatedIrp.SystemBuffer) =
extension->SpecialChars;
Irp->IoStatus.Information = sizeof(SERIAL_CHARS);
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
break;
}
case IOCTL_SERIAL_SET_DTR:
case IOCTL_SERIAL_CLR_DTR: {
#if 0
if (extension->PowerState != PowerDeviceD0) {
status = MoxaGotoPowerState(extension->Pdo, extension, PowerDeviceD0);
if (!NT_SUCCESS(status)) {
break;
}
}
#endif
if (extension->PowerState != PowerDeviceD0) {
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
if ((extension->HandFlow.ControlHandShake & SERIAL_DTR_MASK)
== SERIAL_DTR_HANDSHAKE) {
status = STATUS_INVALID_PARAMETER;
} else {
USHORT arg;
arg =
((irpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_SET_DTR) ? (1):(0));
MoxaFunc(
extension->PortOfs,
FC_DTRcontrol,
arg
);
if ( arg )
MoxaFlagBit[extension->PortNo] |= 1;
else
MoxaFlagBit[extension->PortNo] &= 0xFE;
}
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
break;
}
case IOCTL_SERIAL_RESET_DEVICE: {
break;
}
case IOCTL_SERIAL_SET_RTS:
case IOCTL_SERIAL_CLR_RTS: {
#if 0
if (extension->PowerState != PowerDeviceD0) {
status = MoxaGotoPowerState(extension->Pdo, extension, PowerDeviceD0);
if (!NT_SUCCESS(status)) {
break;
}
}
#endif
if (extension->PowerState != PowerDeviceD0) {
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
if (((extension->HandFlow.FlowReplace & SERIAL_RTS_MASK)
== SERIAL_RTS_HANDSHAKE) ||
((extension->HandFlow.FlowReplace & SERIAL_RTS_MASK)
== SERIAL_TRANSMIT_TOGGLE)) {
status = STATUS_INVALID_PARAMETER;
} else {
USHORT arg;
arg =
((irpSp->Parameters.DeviceIoControl.IoControlCode ==
IOCTL_SERIAL_SET_RTS) ? (1):(0));
MoxaFunc(
extension->PortOfs,
FC_RTScontrol,
arg
);
if ( arg )
MoxaFlagBit[extension->PortNo] |= 2;
else
MoxaFlagBit[extension->PortNo] &= 0xFD;
}
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
break;
}
case IOCTL_SERIAL_SET_XOFF: {
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
extension->TXHolding |= SERIAL_TX_WAITING_FOR_XON;
MoxaFlagBit[extension->PortNo] |= 4;
MoxaFunc(
extension->PortOfs,
FC_SetXoffState,
Magic_code
);
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
break;
}
case IOCTL_SERIAL_SET_XON: {
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
extension->TXHolding &= ~SERIAL_TX_WAITING_FOR_XON;
MoxaFlagBit[extension->PortNo] &= 0xFB;
MoxaFunc(
extension->PortOfs,
FC_SetXonState,
Magic_code
);
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
break;
}
case IOCTL_SERIAL_SET_BREAK_ON: {
#if 0
if (extension->PowerState != PowerDeviceD0) {
status = MoxaGotoPowerState(extension->Pdo, extension, PowerDeviceD0);
if (!NT_SUCCESS(status)) {
break;
}
}
#endif
if (extension->PowerState != PowerDeviceD0) {
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
MoxaFunc(
extension->PortOfs,
FC_SendBreak,
Magic_code
);
extension->SendBreak = TRUE;
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
break;
}
case IOCTL_SERIAL_SET_BREAK_OFF: {
#if 0
if (extension->PowerState != PowerDeviceD0) {
status = MoxaGotoPowerState(extension->Pdo, extension, PowerDeviceD0);
if (!NT_SUCCESS(status)) {
break;
}
}
#endif
if (extension->PowerState != PowerDeviceD0) {
status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
MoxaFunc(
extension->PortOfs,
FC_StopBreak,
Magic_code
);
extension->SendBreak = FALSE;
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
break;
}
case IOCTL_SERIAL_SET_QUEUE_SIZE: {
break;
}
case IOCTL_SERIAL_GET_WAIT_MASK: {
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(ULONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
Irp->IoStatus.Information = sizeof(ULONG);
*((ULONG *)Irp->AssociatedIrp.SystemBuffer) = extension->IsrWaitMask;
break;
}
case IOCTL_SERIAL_SET_WAIT_MASK: {
ULONG newMask;
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(ULONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
else
newMask = *((ULONG *)Irp->AssociatedIrp.SystemBuffer);
if (newMask & ~(SERIAL_EV_RXCHAR |
SERIAL_EV_RXFLAG |
SERIAL_EV_TXEMPTY |
SERIAL_EV_CTS |
SERIAL_EV_DSR |
SERIAL_EV_RLSD |
SERIAL_EV_BREAK |
SERIAL_EV_ERR |
SERIAL_EV_RING |
SERIAL_EV_PERR |
SERIAL_EV_RX80FULL |
SERIAL_EV_EVENT1 |
SERIAL_EV_EVENT2)) {
status = STATUS_INVALID_PARAMETER;
break;
}
return MoxaStartOrQueue(
extension,
Irp,
&extension->MaskQueue,
&extension->CurrentMaskIrp,
MoxaStartMask
);
}
case IOCTL_SERIAL_WAIT_ON_MASK: {
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(ULONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
return MoxaStartOrQueue(
extension,
Irp,
&extension->MaskQueue,
&extension->CurrentMaskIrp,
MoxaStartMask
);
}
case IOCTL_SERIAL_IMMEDIATE_CHAR: {
UCHAR c;
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(UCHAR)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
IoAcquireCancelSpinLock(&oldIrql);
c = *((UCHAR *)(Irp->AssociatedIrp.SystemBuffer));
IoReleaseCancelSpinLock(oldIrql);
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
/* 9-14-01 by William
MoxaFunc(
extension->PortOfs,
FC_ImmSend,
c
);
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
*/
//
// 9-14-01 by William
//
*(PUSHORT)(extension->PortOfs + FuncArg) = c;
*(extension->PortOfs + FuncCode) = FC_ImmSend;
if (MoxaWaitFinish(extension->PortOfs) == FALSE) {
status = STATUS_UNSUCCESSFUL;
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
break;
}
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
IoAcquireCancelSpinLock(&oldIrql);
if (extension->Interrupt) {
KeSynchronizeExecution(
extension->Interrupt,
MoxaProcessEmptyTransmit,
extension
);
}
else {
MoxaProcessEmptyTransmit(extension);
}
IoReleaseCancelSpinLock(oldIrql);
// end
break;
}
case IOCTL_SERIAL_PURGE: {
ULONG mask;
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(ULONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
mask = *((ULONG *)(Irp->AssociatedIrp.SystemBuffer));
if ((!mask) || (mask & (~(SERIAL_PURGE_TXABORT |
SERIAL_PURGE_RXABORT |
SERIAL_PURGE_TXCLEAR |
SERIAL_PURGE_RXCLEAR
)
)
)) {
status = STATUS_INVALID_PARAMETER;
break;
}
return MoxaStartOrQueue(
extension,
Irp,
&extension->PurgeQueue,
&extension->CurrentPurgeIrp,
MoxaStartPurge
);
}
case IOCTL_SERIAL_GET_HANDFLOW: {
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(SERIAL_HANDFLOW)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
Irp->IoStatus.Information = sizeof(SERIAL_HANDFLOW);
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
*((PSERIAL_HANDFLOW)Irp->AssociatedIrp.SystemBuffer) =
extension->HandFlow;
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
break;
}
case IOCTL_SERIAL_SET_HANDFLOW: {
MOXA_IOCTL_SYNC S;
PSERIAL_HANDFLOW handFlow = Irp->AssociatedIrp.SystemBuffer;
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(SERIAL_HANDFLOW)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
if (handFlow->ControlHandShake & SERIAL_CONTROL_INVALID) {
status = STATUS_INVALID_PARAMETER;
break;
}
if (handFlow->FlowReplace & SERIAL_FLOW_INVALID) {
status = STATUS_INVALID_PARAMETER;
break;
}
if ((handFlow->ControlHandShake & SERIAL_DTR_MASK) ==
SERIAL_DTR_MASK) {
status = STATUS_INVALID_PARAMETER;
break;
}
if ((handFlow->XonLimit < 0) ||
((ULONG)handFlow->XonLimit > extension->RxBufferSize)) {
status = STATUS_INVALID_PARAMETER;
break;
}
//
// 10-03-01 by William
//
// if ((handFlow->XoffLimit < 0) ||
// ((ULONG)handFlow->XoffLimit > extension->RxBufferSize)) {
// status = STATUS_INVALID_PARAMETER;
// break;
//
// }
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
if (extension->EscapeChar) {
if (handFlow->FlowReplace & SERIAL_ERROR_CHAR) {
status = STATUS_INVALID_PARAMETER;
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
break;
}
}
//
// Set flowcontrol
//
S.Extension = extension;
S.Data = handFlow;
KeSynchronizeExecution(extension->Interrupt, MoxaSetupNewHandFlow, &S);
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
break;
}
case IOCTL_SERIAL_GET_MODEMSTATUS: {
USHORT data;
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(ULONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
Irp->IoStatus.Information = sizeof(ULONG);
MoxaFuncGetLineStatus(extension->PortOfs, &data);
*(PULONG)Irp->AssociatedIrp.SystemBuffer = (ULONG) (data << 4);
break;
}
case IOCTL_SERIAL_GET_DTRRTS: {
MOXA_IOCTL_FUNC_ARGU func;
USHORT modemControl;
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(ULONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
Irp->IoStatus.Information = sizeof(ULONG);
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
MoxaFunc(
extension->PortOfs,
FC_GetDTRRTS,
0
);
modemControl = *(PUSHORT)(extension->PortOfs + FuncArg);
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
*(PULONG)Irp->AssociatedIrp.SystemBuffer = (ULONG)modemControl;
break;
}
case IOCTL_SERIAL_GET_COMMSTATUS: {
MOXA_IOCTL_SYNC S;
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(SERIAL_STATUS)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
Irp->IoStatus.Information = sizeof(SERIAL_STATUS);
S.Extension = extension;
S.Data = Irp->AssociatedIrp.SystemBuffer;
IoAcquireCancelSpinLock(&oldIrql);
KeSynchronizeExecution(
extension->Interrupt,
MoxaGetCommStatus,
&S
);
IoReleaseCancelSpinLock(oldIrql);
break;
}
case IOCTL_SERIAL_GET_PROPERTIES: {
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(SERIAL_COMMPROP)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
MoxaGetProperties(
extension,
Irp->AssociatedIrp.SystemBuffer
);
Irp->IoStatus.Information = sizeof(SERIAL_COMMPROP);
break;
}
case IOCTL_SERIAL_XOFF_COUNTER: {
break;
}
case IOCTL_SERIAL_LSRMST_INSERT: {
break;
}
case IOCTL_SERIAL_CONFIG_SIZE: {
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(ULONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
Irp->IoStatus.Information = sizeof(ULONG);
Irp->IoStatus.Status = STATUS_SUCCESS;
*(PULONG)Irp->AssociatedIrp.SystemBuffer = 0;
break;
}
case IOCTL_SERIAL_GET_STATS: {
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(SERIALPERF_STATS)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
Irp->IoStatus.Information = sizeof(SERIALPERF_STATS);
Irp->IoStatus.Status = STATUS_SUCCESS;
KeSynchronizeExecution(
extension->Interrupt,
MoxaGetStats,
Irp
);
break;
}
case IOCTL_SERIAL_CLEAR_STATS: {
KeSynchronizeExecution(
extension->Interrupt,
MoxaClearStats,
extension
);
break;
}
case IOCTL_MOXA_Driver: {
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(ULONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
Irp->IoStatus.Information = sizeof(ULONG);
*(PULONG)Irp->AssociatedIrp.SystemBuffer = MX_DRIVER;
break;
}
#if 0
case IOCTL_MOXA_Reset: {
PMOXA_GLOBAL_DATA globalData;
PMOXA_DEVICE_EXTENSION portExt;
SHORT i;
if (!extension->ControlDevice) {
status = STATUS_INVALID_PARAMETER;
break;
}
if (*(PUSHORT)Irp->AssociatedIrp.SystemBuffer != 0x404) {
status = STATUS_INVALID_PARAMETER;
break;
}
globalData = extension->GlobalData;
for (i=0; i<MAX_PORT; i++) {
portExt = globalData->Extension[i];
if (portExt)
if (portExt->PortExist) {
portExt->PortExist = FALSE;
MoxaCancelTimer(&portExt->ReadRequestTotalTimer,portExt);
MoxaCancelTimer(&portExt->ReadRequestIntervalTimer,portExt);
MoxaCancelTimer(&portExt->WriteRequestTotalTimer,portExt);
KeRemoveQueueDpc(&portExt->CompleteWriteDpc);
KeRemoveQueueDpc(&portExt->CompleteReadDpc);
KeRemoveQueueDpc(&portExt->IsrOutDpc);
KeRemoveQueueDpc(&portExt->IsrInDpc);
KeRemoveQueueDpc(&portExt->TotalReadTimeoutDpc);
KeRemoveQueueDpc(&portExt->IntervalReadTimeoutDpc);
KeRemoveQueueDpc(&portExt->TotalWriteTimeoutDpc);
KeRemoveQueueDpc(&portExt->CommErrorDpc);
KeRemoveQueueDpc(&portExt->CommWaitDpc);
//
// 9-24-01 by William
//
// KeRemoveQueueDpc(&portExt->IntrLineDpc);
// KeRemoveQueueDpc(&portExt->IntrErrorDpc);
// end
}
}
KeSynchronizeExecution(
extension->Interrupt,
MoxaClearDownLoad,
globalData
);
break;
}
#endif
case IOCTL_MOXA_LineInput: {
//
// 03-14-02 by William
//
#if 0
if (irpSp->Parameters.DeviceIoControl.InputBufferLength !=
sizeof(UCHAR)) {
#endif
if ((irpSp->Parameters.DeviceIoControl.InputBufferLength != sizeof(UCHAR)) ||
(irpSp->Parameters.DeviceIoControl.OutputBufferLength < 1) ) {
// end
status = STATUS_BUFFER_TOO_SMALL;
break;
}
return MoxaStartOrQueue(
extension,
Irp,
&extension->ReadQueue,
&extension->CurrentReadIrp,
MoxaStartRead
);
}
case IOCTL_MOXA_OQueue: {
ULONG count;
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(ULONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
count = GetDeviceTxQueueWithLock(extension) + extension->WriteLength
+ extension->TotalCharsQueued;
*((PULONG)Irp->AssociatedIrp.SystemBuffer) = count;
Irp->IoStatus.Information = sizeof(ULONG);
break;
}
case IOCTL_MOXA_IQueue: {
ULONG count;
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(ULONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
count = GetDeviceRxQueueWithLock(extension);
*((PULONG)Irp->AssociatedIrp.SystemBuffer) = count;
Irp->IoStatus.Information = sizeof(ULONG);
break;
}
case IOCTL_MOXA_View: {
//
// 01-04-02 by William
//
// if (irpSp->Parameters.DeviceIoControl.InputBufferLength !=
// sizeof(UCHAR)) {
//
// status = STATUS_BUFFER_TOO_SMALL;
// break;
// }
//
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(ULONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
// end
return MoxaStartOrQueue(
extension,
Irp,
&extension->ReadQueue,
&extension->CurrentReadIrp,
MoxaStartRead
);
}
case IOCTL_MOXA_TxLowWater: {
LONG lowWater;
PMOXA_DEVICE_EXTENSION ext;
PUCHAR ofs;
USHORT cardNo, port, portNo;
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(LONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(LONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
lowWater = *((PLONG)Irp->AssociatedIrp.SystemBuffer);
if (lowWater > 1024)
lowWater = 1024;
if (lowWater >= 0) {
MoxaTxLowWater = lowWater;
for (cardNo=0; cardNo<MAX_CARD; cardNo++) {
if ((!MoxaGlobalData->CardType[cardNo]) ||
(!MoxaGlobalData->NumPorts[cardNo]))
continue;
for (port=0; port<MoxaGlobalData->NumPorts[cardNo]; port++) {
portNo = cardNo * MAXPORT_PER_CARD + port;
ext = MoxaGlobalData->Extension[portNo];
ofs = ext->PortOfs;
*(PUSHORT)(ofs + Tx_trigger) = (USHORT)(MoxaTxLowWater);
}
}
}
*((PLONG)Irp->AssociatedIrp.SystemBuffer) = MoxaTxLowWater;
Irp->IoStatus.Information = sizeof(LONG);
break;
}
case IOCTL_MOXA_GetSeg: {
PMOXA_IOCTL_MxSet Ms = (PMOXA_IOCTL_MxSet)Irp->AssociatedIrp.SystemBuffer;
PMOXA_GLOBAL_DATA Gd = (PMOXA_GLOBAL_DATA)extension->GlobalData;
int card;
if (!extension->ControlDevice) {
status = STATUS_INVALID_PARAMETER;
break;
}
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(MOXA_IOCTL_MxSet)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
for ( card=0; card<MAX_CARD; card++ ) {
if ( !Gd->CardType[card] )
break;
Ms->type[card] = Gd->CardType[card];
Ms->segment[card] = Gd->BankAddr[card].LowPart;
}
Ms->total_boards = card;
Irp->IoStatus.Information = sizeof(MOXA_IOCTL_MxSet);
break;
}
case IOCTL_MOXA_RdData: {
PMOXA_IOCTL_BlkHead Bh = (PMOXA_IOCTL_BlkHead)Irp->AssociatedIrp.SystemBuffer;
PMOXA_GLOBAL_DATA Gd = (PMOXA_GLOBAL_DATA)extension->GlobalData;
PUCHAR base;
PUCHAR buff;
int card, len, ofs, ndx;
if (!extension->ControlDevice) {
status = STATUS_INVALID_PARAMETER;
break;
}
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(MOXA_IOCTL_BlkHead)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
for ( card=0; card<MAX_CARD; card++ ) {
if ( Bh->data_seg == Gd->BankAddr[card].LowPart )
break;
}
if ( card == MAX_CARD ) {
status = STATUS_INVALID_PARAMETER;
break;
}
base = Gd->CardBase[card];
ofs = Bh->data_ofs;
len = Bh->data_len;
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
(unsigned long)len) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
buff = (PUCHAR)(Irp->AssociatedIrp.SystemBuffer);
for ( ndx=0; ndx<len; ndx++ ) {
if ( (ndx + ofs) >= 0x4000 )
break;
buff[ndx] = base[ofs + ndx];
}
Irp->IoStatus.Information = ndx;
break;
}
case IOCTL_MOXA_WrData: {
PMOXA_IOCTL_WrData Wd = (PMOXA_IOCTL_WrData)Irp->AssociatedIrp.SystemBuffer;
PMOXA_GLOBAL_DATA Gd = (PMOXA_GLOBAL_DATA)extension->GlobalData;
PUCHAR base;
int card, len, ofs, ndx;
if (!extension->ControlDevice) {
status = STATUS_INVALID_PARAMETER;
break;
}
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(DWORD)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
for ( card=0; card<MAX_CARD; card++ ) {
if ( Wd->datahead.data_seg == Gd->BankAddr[card].LowPart )
break;
}
if ( card == MAX_CARD ) {
status = STATUS_INVALID_PARAMETER;
break;
}
base = Gd->CardBase[card];
ofs = Wd->datahead.data_ofs;
len = Wd->datahead.data_len;
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
(sizeof(MOXA_IOCTL_BlkHead) + len)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
for ( ndx=0; ndx<len; ndx++ ) {
if ( (ndx + ofs) >= 0x4000 )
break;
base[ofs + ndx] = Wd->data[ndx];
}
*((PULONG)Irp->AssociatedIrp.SystemBuffer) = ndx;
Irp->IoStatus.Information = sizeof(DWORD);
break;
}
case IOCTL_MOXA_FiData: {
PMOXA_IOCTL_FiData Fi = (PMOXA_IOCTL_FiData)Irp->AssociatedIrp.SystemBuffer;
PMOXA_GLOBAL_DATA Gd = (PMOXA_GLOBAL_DATA)extension->GlobalData;
PUCHAR base;
int card, len, ofs, ndx;
if (!extension->ControlDevice) {
status = STATUS_INVALID_PARAMETER;
break;
}
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(MOXA_IOCTL_FiData)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(DWORD)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
for ( card=0; card<MAX_CARD; card++ ) {
if ( Fi->datahead.data_seg == Gd->BankAddr[card].LowPart )
break;
}
if ( card == MAX_CARD ) {
status = STATUS_INVALID_PARAMETER;
break;
}
base = Gd->CardBase[card];
ofs = Fi->datahead.data_ofs;
len = Fi->datahead.data_len;
for ( ndx=0; ndx<len; ndx++ ) {
if ( (ndx + ofs) >= 0x4000 )
break;
base[ofs + ndx] = Fi->fill_value;
}
*((PULONG)Irp->AssociatedIrp.SystemBuffer) = ndx;
Irp->IoStatus.Information = sizeof(DWORD);
break;
}
case IOCTL_MOXA_Linked: {
PMOXA_GLOBAL_DATA Gd = extension->GlobalData;
PUCHAR base;
ULONG cardNo;
if (!extension->ControlDevice) {
status = STATUS_INVALID_PARAMETER;
break;
}
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(ULONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(LONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
cardNo = *((PULONG)Irp->AssociatedIrp.SystemBuffer);
if (cardNo >= MAX_CARD) {
status = STATUS_INVALID_PARAMETER;
break;
}
if ((Gd->CardType[cardNo] != C320ISA)&&(Gd->CardType[cardNo] != C320PCI)) {
status = STATUS_INVALID_PARAMETER;
break;
}
base = Gd->CardBase[cardNo];
if (*((PUSHORT)(base + C320B_unlinked)) == Magic_no) {
((LONG)Irp->AssociatedIrp.SystemBuffer) = 1;
Irp->IoStatus.Information = sizeof(LONG);
break;
}
if (*((PUSHORT)(base + C320_runOK)) == Magic_no) {
if (*((PUSHORT)(base + C320B_restart)) == Magic_no) { // C320B Reload OK
((LONG)Irp->AssociatedIrp.SystemBuffer) = 2;
Irp->IoStatus.Information = sizeof(LONG);
*((PUSHORT)(base + C320B_restart)) = 0;
}
else { // OK
((LONG)Irp->AssociatedIrp.SystemBuffer) = 0;
Irp->IoStatus.Information = sizeof(LONG);
}
}
else { // Disconnected
((LONG)Irp->AssociatedIrp.SystemBuffer) = 1;
Irp->IoStatus.Information = sizeof(LONG);
}
break;
}
case IOCTL_MOXA_Statistic: {
PUSHORT com;
USHORT comNo[2];
PMOXA_IOCTL_Statistic St;
ULONG size;
int ndx, portNo, nn;
if (!extension->ControlDevice) {
status = STATUS_INVALID_PARAMETER;
break;
}
if (irpSp->Parameters.DeviceIoControl.InputBufferLength < 4) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
com = (PUSHORT)Irp->AssociatedIrp.SystemBuffer;
comNo[0] = com[0];
comNo[1] = com[1];
if ( comNo[1] < comNo[0] ) {
status = STATUS_INVALID_PARAMETER;
break;
}
size = sizeof(MOXA_IOCTL_Statistic) * (comNo[1] - comNo[0] + 1);
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < size) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
St = (PMOXA_IOCTL_Statistic)Irp->AssociatedIrp.SystemBuffer;
nn = 0;
for ( ndx=(int)comNo[0]; ndx<=(int)comNo[1]; ndx++, nn++ ) {
if ( ndx > MAX_COM )
break;
if ( (ndx <= 0) || (MoxaExtension[ndx] == NULL) )
continue;
portNo = (int)MoxaExtension[ndx]->PortNo;
St[nn].TxCount = MoxaExtension[ndx]->PerfStats.TransmittedCount +
MoxaTotalTx[portNo];
St[nn].RxCount = MoxaExtension[ndx]->PerfStats.ReceivedCount +
MoxaTotalRx[portNo];
MoxaFuncGetLineStatus(
MoxaExtension[ndx]->PortOfs,
(PUSHORT)&MoxaExtension[ndx]->ModemStatus
);
St[nn].LStatus = (ULONG)MoxaExtension[ndx]->ModemStatus & 0x0F;
St[nn].LStatus |= ((MoxaFlagBit[portNo] & 3) << 4);
if ( MoxaExtension[ndx]->DeviceIsOpened )
St[nn].LStatus |= 0x80;
St[nn].FlowCtl = (MoxaExtension[ndx]->HandFlow.ControlHandShake
& SERIAL_CTS_HANDSHAKE) |
(MoxaExtension[ndx]->HandFlow.FlowReplace &
(SERIAL_RTS_HANDSHAKE | SERIAL_AUTO_TRANSMIT |
SERIAL_AUTO_RECEIVE));
}
Irp->IoStatus.Information = size;
break;
}
case IOCTL_MOXA_LoopBack: {
ULONG mode;
PMOXA_GLOBAL_DATA Gd = extension->GlobalData;
if ((Gd->CardType[extension->BoardNo] == C320ISA) ||
(Gd->CardType[extension->BoardNo] == C320PCI)) {
status = STATUS_INVALID_PARAMETER;
break;
}
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(ULONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
mode = *(PULONG)Irp->AssociatedIrp.SystemBuffer;
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
MoxaFunc(
extension->PortOfs,
FC_DisableCH,
Magic_code
);
if ( mode ) {
// Set loop back mode
MoxaFunc(
extension->PortOfs,
FC_LoopbackON,
Magic_code
);
} else {
// Reset loop back mode
MoxaFunc(
extension->PortOfs,
FC_LoopbackOFF,
Magic_code
);
}
MoxaFunc(
extension->PortOfs,
FC_EnableCH,
Magic_code
);
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
Irp->IoStatus.Information = 0;
break;
}
case IOCTL_MOXA_UARTTest: {
int ier, old;
int MoxaReadReg(PUCHAR, int);
void MoxaWriteReg(PUCHAR, int, int);
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(ULONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
Irp->IoStatus.Information = sizeof(ULONG);
*(ULONG *)Irp->AssociatedIrp.SystemBuffer = 0;
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
old = MoxaReadReg(extension->PortOfs, 1);
MoxaWriteReg(extension->PortOfs, 1, 0);
ier = MoxaReadReg(extension->PortOfs, 1);
if ( ier == 0 ) {
MoxaWriteReg(extension->PortOfs, 1, 3);
ier = MoxaReadReg(extension->PortOfs, 1);
if ( ier == 3 )
*(ULONG *)Irp->AssociatedIrp.SystemBuffer = 1;
}
MoxaWriteReg(extension->PortOfs, 1, old);
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
break;
}
case IOCTL_MOXA_IRQTest: {
PUCHAR ofs;
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(ULONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
ofs = extension->PortOfs;
KeAcquireSpinLock(
&extension->ControlLock,
&oldIrql
);
MoxaIRQok = FALSE;
MoxaFunc(
ofs,
FC_GenIrq,
Magic_code
);
KeReleaseSpinLock(
&extension->ControlLock,
oldIrql
);
MoxaDelay(5); /* delay 10 msec */
if ( MoxaIRQok )
*((PULONG)Irp->AssociatedIrp.SystemBuffer) = 1;
else
*((PULONG)Irp->AssociatedIrp.SystemBuffer) = 0;
Irp->IoStatus.Information = sizeof(ULONG);
break;
}
case IOCTL_MOXA_LineStatus: {
USHORT data;
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(ULONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
Irp->IoStatus.Information = sizeof(ULONG);
MoxaFuncGetLineStatus(extension->PortOfs, &data);
*(PULONG)Irp->AssociatedIrp.SystemBuffer = data;
break;
}
case IOCTL_MOXA_PortStatus: {
ULONG comNo;
PMOXA_IOCTL_PortStatus Ps;
if (!extension->ControlDevice) {
status = STATUS_INVALID_PARAMETER;
break;
}
if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
sizeof(ULONG)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(MOXA_IOCTL_PortStatus)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
comNo = *((PULONG)Irp->AssociatedIrp.SystemBuffer);
if ( (comNo <= 0) || (comNo > MAX_COM) ||
(MoxaExtension[comNo] == NULL) ) {
status = STATUS_INVALID_PARAMETER;
break;
}
Ps = (PMOXA_IOCTL_PortStatus)Irp->AssociatedIrp.SystemBuffer;
Ps->Open = (USHORT)MoxaExtension[comNo]->DeviceIsOpened;
Ps->TxHold = 0;
if (MoxaExtension[comNo]->HandFlow.ControlHandShake &
SERIAL_CTS_HANDSHAKE) {
if ((MoxaExtension[comNo]->ModemStatus & LSTATUS_CTS) == 0)
Ps->TxHold |= 1;
}
if (MoxaExtension[comNo]->TXHolding & SERIAL_TX_WAITING_FOR_XON)
Ps->TxHold |= 2;
if (MoxaExtension[comNo]->SendBreak)
Ps->TxHold |= 4;
Ps->DataMode = MoxaExtension[comNo]->DataMode;
Ps->BaudRate = MoxaExtension[comNo]->CurrentBaud;
Ps->MaxBaudRate = MoxaExtension[comNo]->MaxBaud;
Ps->TxBuffer = MoxaExtension[comNo]->TxBufferSize;
Ps->RxBuffer = MoxaExtension[comNo]->RxBufferSize;
Ps->TxXonThreshold = MoxaExtension[comNo]->HandFlow.XonLimit;
Ps->TxXoffThreshold = MoxaExtension[comNo]->HandFlow.XoffLimit;
Ps->FlowControl = (MoxaExtension[comNo]->HandFlow.ControlHandShake &
SERIAL_CTS_HANDSHAKE) |
(MoxaExtension[comNo]->HandFlow.FlowReplace &
(SERIAL_RTS_HANDSHAKE | SERIAL_AUTO_TRANSMIT |
SERIAL_AUTO_RECEIVE));
Irp->IoStatus.Information = sizeof(MOXA_IOCTL_PortStatus);
break;
}
default:
status = STATUS_INVALID_PARAMETER;
break;
}
DoneWithIoctl:;
Irp->IoStatus.Status = status;
if (extension->ControlDevice) {
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
else {
MoxaCompleteRequest(extension, Irp, IO_NO_INCREMENT);
}
return status;
}
BOOLEAN
MoxaGetCommStatus(
IN PVOID Context
)
{
USHORT dataError;
PMOXA_DEVICE_EXTENSION extension = ((PMOXA_IOCTL_SYNC)Context)->Extension;
PSERIAL_STATUS stat = ((PMOXA_IOCTL_SYNC)Context)->Data;
PUCHAR ofs = extension->PortOfs;
MoxaFuncGetDataError(
ofs,
&dataError
);
stat->Errors = (extension->ErrorWord|dataError);
extension->ErrorWord = 0;
stat->EofReceived = FALSE;
{
PUSHORT rptr, wptr;
USHORT lenMask, count;
rptr = (PUSHORT)(ofs + RXrptr);
wptr = (PUSHORT)(ofs + RXwptr);
lenMask = *(PUSHORT)(ofs + RX_mask);
count = (*wptr >= *rptr) ? (*wptr - *rptr)
: (*wptr - *rptr + lenMask + 1);
stat->AmountInInQueue = (ULONG)count;
rptr = (PUSHORT)(ofs + TXrptr);
wptr = (PUSHORT)(ofs + TXwptr);
lenMask = *(PUSHORT)(ofs + TX_mask);
count = (*wptr >= *rptr) ? (*wptr - *rptr)
: (*wptr - *rptr + lenMask + 1);
stat->AmountInOutQueue = extension->TotalCharsQueued
+ extension->WriteLength;
stat->AmountInOutQueue += (ULONG)count;
}
stat->WaitForImmediate = FALSE;
stat->HoldReasons = 0;
MoxaFuncGetLineStatus(
ofs,
(PUSHORT)&extension->ModemStatus
);
if (extension->HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE) {
if ((extension->ModemStatus & LSTATUS_CTS) == 0)
stat->HoldReasons |= SERIAL_TX_WAITING_FOR_CTS;
}
if (*(PUSHORT)(extension->PortOfs + FlagStat) & Tx_flowOff)
stat->HoldReasons |= SERIAL_TX_WAITING_FOR_XON;
if (*(PUSHORT)(extension->PortOfs + FlagStat) & Rx_xoff)
if (extension->HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE)
stat->HoldReasons |= SERIAL_TX_WAITING_XOFF_SENT;
if (extension->SendBreak)
stat->HoldReasons |= SERIAL_TX_WAITING_ON_BREAK;
stat->HoldReasons |= (extension->TXHolding & SERIAL_TX_WAITING_FOR_XON);
return FALSE;
}
VOID
MoxaGetProperties(
IN PMOXA_DEVICE_EXTENSION Extension,
IN PSERIAL_COMMPROP Properties
)
{
RtlZeroMemory(
Properties,
sizeof(SERIAL_COMMPROP)
);
Properties->PacketLength = sizeof(SERIAL_COMMPROP);
Properties->PacketVersion = 2;
Properties->ServiceMask = SERIAL_SP_SERIALCOMM;
Properties->MaxTxQueue = Extension->TxBufferSize;
Properties->MaxRxQueue = Extension->RxBufferSize;
Properties->MaxBaud = SERIAL_BAUD_USER;
Properties->SettableBaud = Extension->SupportedBauds;
Properties->ProvSubType = SERIAL_SP_RS232;
Properties->ProvCapabilities = SERIAL_PCF_DTRDSR |
SERIAL_PCF_RTSCTS |
SERIAL_PCF_CD |
SERIAL_PCF_PARITY_CHECK |
SERIAL_PCF_XONXOFF |
SERIAL_PCF_SETXCHAR |
SERIAL_PCF_TOTALTIMEOUTS |
SERIAL_PCF_INTTIMEOUTS;
Properties->SettableParams = SERIAL_SP_PARITY |
SERIAL_SP_BAUD |
SERIAL_SP_DATABITS |
SERIAL_SP_STOPBITS |
SERIAL_SP_HANDSHAKING |
SERIAL_SP_PARITY_CHECK |
SERIAL_SP_CARRIER_DETECT;
Properties->SettableData = SERIAL_DATABITS_5 |
SERIAL_DATABITS_6 |
SERIAL_DATABITS_7 |
SERIAL_DATABITS_8;
Properties->SettableStopParity = SERIAL_STOPBITS_10 |
SERIAL_STOPBITS_15 |
SERIAL_STOPBITS_20 |
SERIAL_PARITY_NONE |
SERIAL_PARITY_ODD |
SERIAL_PARITY_EVEN |
SERIAL_PARITY_MARK |
SERIAL_PARITY_SPACE;
Properties->CurrentTxQueue = Extension->TxBufferSize;
Properties->CurrentRxQueue = Extension->RxBufferSize;
}
#if 0
BOOLEAN
MoxaClearDownLoad(
IN PVOID Context
)
{
PMOXA_GLOBAL_DATA globalData = Context;
USHORT i;
globalData->DownLoad = FALSE;
for (i=0; i<MAX_CARD; i++)
globalData->NumPorts[i] = 0;
return FALSE;
}
#endif
VOID
InitPort(
IN PMOXA_DEVICE_EXTENSION Extension,
IN ULONG RxBufSize,
IN ULONG TxBufSize,
IN ULONG MaxBaud
)
{
PUCHAR ofs;
ULONG count;
Extension->PortExist = TRUE;
Extension->DeviceIsOpened = FALSE;
Extension->OpenCount = 0;
Extension->SendBreak = FALSE;
Extension->OwnsPowerPolicy = TRUE;
Extension->GlobalData = MoxaGlobalData;
Extension->ControlDevice = FALSE;
Extension->PowerState = PowerDeviceD3;
//
// Initialize the count of IRP's pending
//
Extension->PendingIRPCnt = 1;
//
// Initialize the count of DPC's pending
//
Extension->DpcCount = 1;
InitializeListHead(&Extension->ReadQueue);
InitializeListHead(&Extension->WriteQueue);
InitializeListHead(&Extension->MaskQueue);
InitializeListHead(&Extension->PurgeQueue);
InitializeListHead(&Extension->AllDevObjs);
InitializeListHead(&Extension->StalledIrpQueue);
ExInitializeFastMutex(&Extension->OpenMutex);
ExInitializeFastMutex(&Extension->CloseMutex);
KeInitializeEvent(&Extension->PendingIRPEvent, SynchronizationEvent, FALSE);
KeInitializeEvent(&Extension->PendingDpcEvent, SynchronizationEvent, FALSE);
KeInitializeEvent(&Extension->PowerD0Event, SynchronizationEvent, FALSE);
KeInitializeSpinLock(&Extension->ControlLock);
KeInitializeTimer(&Extension->ReadRequestTotalTimer);
KeInitializeTimer(&Extension->ReadRequestIntervalTimer);
KeInitializeTimer(&Extension->WriteRequestTotalTimer);
KeInitializeDpc(
&Extension->CompleteWriteDpc,
MoxaCompleteWrite,
Extension
);
KeInitializeDpc(
&Extension->IsrOutDpc,
MoxaIsrOut,
Extension
);
KeInitializeDpc(
&Extension->CompleteReadDpc,
MoxaCompleteRead,
Extension
);
KeInitializeDpc(
&Extension->IsrInDpc,
MoxaIsrIn,
Extension
);
KeInitializeDpc(
&Extension->TotalReadTimeoutDpc,
MoxaReadTimeout,
Extension
);
KeInitializeDpc(
&Extension->IntervalReadTimeoutDpc,
MoxaIntervalReadTimeout,
Extension
);
KeInitializeDpc(
&Extension->TotalWriteTimeoutDpc,
MoxaWriteTimeout,
Extension
);
KeInitializeDpc(
&Extension->CommErrorDpc,
MoxaCommError,
Extension
);
KeInitializeDpc(
&Extension->CommWaitDpc,
MoxaCompleteWait,
Extension
);
//
// 9-24-01 by William
//
#if 0
KeInitializeDpc(
&Extension->IntrLineDpc,
MoxaIntrLine,
Extension
);
KeInitializeDpc(
&Extension->IntrErrorDpc,
MoxaIntrError,
Extension
);
#endif
// end
KeInitializeDpc(
&Extension->IsrUnlockPagesDpc,
MoxaUnlockPages,
Extension);
Extension->SpecialChars.EofChar = 0;
Extension->SpecialChars.ErrorChar = 0;
Extension->SpecialChars.BreakChar = 0;
Extension->SpecialChars.EventChar = 0;
Extension->SpecialChars.XonChar = 0x11;
Extension->SpecialChars.XoffChar = 0x13;
// Extension->HandFlow.ControlHandShake = SERIAL_DTR_CONTROL;
Extension->HandFlow.ControlHandShake = 0;
// Extension->HandFlow.FlowReplace = SERIAL_RTS_CONTROL;
Extension->HandFlow.FlowReplace = 0;
Extension->DataMode = MOXA_8_DATA | MOXA_NONE_PARITY;
Extension->ValidDataMask = 0xff;
Extension->CurrentBaud = 38400;
Extension->RxBufferSize = RxBufSize;
Extension->TxBufferSize = TxBufSize;
Extension->HandFlow.XoffLimit = Extension->RxBufferSize >> 3;
Extension->HandFlow.XonLimit = Extension->RxBufferSize >> 1;
Extension->BufferSizePt8 = ((3*(Extension->RxBufferSize>>2))+
(Extension->RxBufferSize>>4));
Extension->SupportedBauds =
SERIAL_BAUD_USER |
SERIAL_BAUD_075 |
SERIAL_BAUD_110 |
SERIAL_BAUD_134_5 |
SERIAL_BAUD_150 |
SERIAL_BAUD_300 |
SERIAL_BAUD_600 |
SERIAL_BAUD_1200 |
SERIAL_BAUD_1800 |
SERIAL_BAUD_2400 |
SERIAL_BAUD_4800 |
SERIAL_BAUD_7200 |
SERIAL_BAUD_9600 |
SERIAL_BAUD_14400 |
SERIAL_BAUD_19200 |
SERIAL_BAUD_38400;
Extension->DeviceIsOpened = FALSE;
Extension->ShortIntervalAmount.QuadPart = -1;
Extension->LongIntervalAmount.QuadPart = -10000000;
Extension->CutOverAmount.QuadPart = 200000000;
ofs = Extension->PortOfs;
count = 0;
while ((*(ofs + FuncCode) != 0)&&(count++ < 500))
MoxaDelay(1);
*(ofs + FuncCode) = FC_GetClockRate;
count = 0;
while ((*(ofs + FuncCode) != 0)&&(count++ < 500)) /* wait cmd process completed */
MoxaDelay(1);
Extension->ClockType = *(ofs + FuncArg); /* 0, 1, 2 */
if (Extension->ClockType) {
Extension->SupportedBauds |= SERIAL_BAUD_57600;
if (Extension->ClockType == 2)
Extension->SupportedBauds |= SERIAL_BAUD_115200;
}
Extension->MaxBaud = MaxBaud;
}
BOOLEAN
MoxaGetStats(
IN PVOID Context
)
/*++
Routine Description:
In sync with the interrpt service routine (which sets the perf stats)
return the perf stats to the caller.
Arguments:
Context - Pointer to a the irp.
Return Value:
This routine always returns FALSE.
--*/
{
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation((PIRP)Context);
PMOXA_DEVICE_EXTENSION extension = irpSp->DeviceObject->DeviceExtension;
PSERIALPERF_STATS sp = ((PIRP)Context)->AssociatedIrp.SystemBuffer;
*sp = extension->PerfStats;
return FALSE;
}
BOOLEAN
MoxaClearStats(
IN PVOID Context
)
/*++
Routine Description:
In sync with the interrpt service routine (which sets the perf stats)
clear the perf stats.
Arguments:
Context - Pointer to a the extension.
Return Value:
This routine always returns FALSE.
--*/
{
PSERIALPERF_STATS perf_stats;
int port;
perf_stats = &((PMOXA_DEVICE_EXTENSION)Context)->PerfStats;
port = (int)(((PMOXA_DEVICE_EXTENSION)Context)->PortNo);
MoxaTotalRx[port] += perf_stats->ReceivedCount;
MoxaTotalTx[port] += perf_stats->TransmittedCount;
RtlZeroMemory(
perf_stats,
sizeof(SERIALPERF_STATS)
);
return FALSE;
}
MoxaReadReg(
IN PUCHAR PortOfs,
IN int reg
)
{
USHORT value;
*(PUSHORT)(PortOfs + FuncArg) = (USHORT)reg;
*(PortOfs + FuncCode) = FC_InUARTreg;
MoxaWaitFinish(PortOfs);
value = *(PUSHORT)(PortOfs + FuncArg1);
return((int)value);
}
void
MoxaWriteReg(
IN PUCHAR PortOfs,
IN int reg,
IN int value
)
{
*(PUSHORT)(PortOfs + FuncArg1) = (USHORT)value;
*(PUSHORT)(PortOfs + FuncArg) = (USHORT)reg;
*(PortOfs + FuncCode) = FC_OutUARTreg;
MoxaWaitFinish(PortOfs);
}
//
// Internal Ioctl
//
NTSTATUS
MoxaInternalIoControl(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
/*++
Routine Description:
This routine provides the initial processing for all of the
internal Ioctrls for the serial device.
Arguments:
PDevObj - Pointer to the device object for this device
PIrp - Pointer to the IRP for the current request
Return Value:
The function value is the final status of the call
--*/
{
//
// The status that gets returned to the caller and
// set in the Irp.
//
NTSTATUS status;
//
// The current stack location. This contains all of the
// information we need to process this particular request.
//
PIO_STACK_LOCATION pIrpStack;
//
// Just what it says. This is the serial specific device
// extension of the device object create for the serial driver.
//
PMOXA_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
//
// A temporary to hold the old IRQL so that it can be
// restored once we complete/validate this request.
//
KIRQL OldIrql;
NTSTATUS prologueStatus;
if (pDevExt->ControlDevice) { // Control Device
status = STATUS_CANCELLED;
PIrp->IoStatus.Information = 0L;
PIrp->IoStatus.Status = status;
IoCompleteRequest(
PIrp,
0
);
return status;
}
if ((prologueStatus = MoxaIRPPrologue(PIrp, pDevExt))
!= STATUS_SUCCESS) {
MoxaCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
return prologueStatus;
}
if (MoxaCompleteIfError(PDevObj, PIrp) != STATUS_SUCCESS) {
return STATUS_CANCELLED;
}
pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
PIrp->IoStatus.Information = 0L;
status = STATUS_SUCCESS;
switch (pIrpStack->Parameters.DeviceIoControl.IoControlCode) {
//
// Send a wait-wake IRP
//
case IOCTL_SERIAL_INTERNAL_DO_WAIT_WAKE:
pDevExt->SendWaitWake = TRUE;
status = STATUS_SUCCESS;
break;
case IOCTL_SERIAL_INTERNAL_CANCEL_WAIT_WAKE:
pDevExt->SendWaitWake = FALSE;
if (pDevExt->PendingWakeIrp != NULL) {
IoCancelIrp(pDevExt->PendingWakeIrp);
}
status = STATUS_SUCCESS;
break;
//
// Put the serial port in a "filter-driver" appropriate state
//
// WARNING: This code assumes it is being called by a trusted kernel
// entity and no checking is done on the validity of the settings
// passed to IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS
//
// If validity checking is desired, the regular ioctl's should be used
//
case IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS:
case IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS: {
SERIAL_BASIC_SETTINGS basic;
PSERIAL_BASIC_SETTINGS pBasic;
SHORT AppropriateDivisor;
MOXA_IOCTL_SYNC S;
if (pIrpStack->Parameters.DeviceIoControl.IoControlCode
== IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS) {
//
// Check the buffer size
//
if (pIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
sizeof(SERIAL_BASIC_SETTINGS)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
//
// Everything is 0 -- timeouts and flow control. If
// We add additional features, this zero memory method
// may not work.
//
RtlZeroMemory(&basic, sizeof(SERIAL_BASIC_SETTINGS));
PIrp->IoStatus.Information = sizeof(SERIAL_BASIC_SETTINGS);
pBasic = (PSERIAL_BASIC_SETTINGS)PIrp->AssociatedIrp.SystemBuffer;
//
// Save off the old settings
//
RtlCopyMemory(&pBasic->Timeouts, &pDevExt->Timeouts,
sizeof(SERIAL_TIMEOUTS));
RtlCopyMemory(&pBasic->HandFlow, &pDevExt->HandFlow,
sizeof(SERIAL_HANDFLOW));
pBasic->RxFifo = pDevExt->RxFifoTrigger;
pBasic->TxFifo = pDevExt->TxFifoAmount;
//
// Point to our new settings
//
pBasic = &basic;
} else { // restoring settings
if (pIrpStack->Parameters.DeviceIoControl.InputBufferLength
< sizeof(SERIAL_BASIC_SETTINGS)) {
status = STATUS_BUFFER_TOO_SMALL;
break;
}
pBasic = (PSERIAL_BASIC_SETTINGS)PIrp->AssociatedIrp.SystemBuffer;
}
KeAcquireSpinLock(&pDevExt->ControlLock, &OldIrql);
//
// Set the timeouts
//
RtlCopyMemory(&pDevExt->Timeouts, &pBasic->Timeouts,
sizeof(SERIAL_TIMEOUTS));
//
// Set flowcontrol
//
S.Extension = pDevExt;
S.Data = &pBasic->HandFlow;
KeSynchronizeExecution(pDevExt->Interrupt, MoxaSetupNewHandFlow, &S);
pDevExt->TxFifoAmount = (USHORT)pBasic->TxFifo;
pDevExt->RxFifoTrigger = (USHORT)pBasic->RxFifo;
MoxaFunc(pDevExt->PortOfs, FC_SetTxFIFOCnt,pDevExt->TxFifoAmount);
MoxaFunc(pDevExt->PortOfs, FC_SetRxFIFOTrig,pDevExt->RxFifoTrigger);
KeReleaseSpinLock(&pDevExt->ControlLock, OldIrql);
break;
}
default:
status = STATUS_INVALID_PARAMETER;
break;
}
PIrp->IoStatus.Status = status;
MoxaCompleteRequest(pDevExt, PIrp, 0);
return status;
}