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.
3239 lines
105 KiB
3239 lines
105 KiB
/*-------------------------------------------------------------------
|
|
| ioctl.c - handle all the misc. serial ioctl calls.
|
|
4-05-00 - Add address (&) operator to actual parameter passed to sWriteTxBlk
|
|
5-13-99 - enable RTS toggling for VS
|
|
2-15-99 - make SerialSetHandflow() public, so pnp can call it. kpb
|
|
1-21-99 - fix immed char send to trigger EV_TXEMPTY, add some support
|
|
for VS immediate char send.
|
|
11-24-98 - update DBG kdprint messages for event handling tests - kpb
|
|
9-24-98 - include tx-shift-reg in getcommstat report - kpb.
|
|
4-29-98 - adjust break output to start immediately if possible - kpb.
|
|
Copyright 1993-98 Comtrol Corporation. All rights reserved.
|
|
|--------------------------------------------------------------------*/
|
|
#include "precomp.h"
|
|
|
|
typedef struct {
|
|
ULONG struct_size;
|
|
ULONG num_ports;
|
|
ULONG total_loads;
|
|
ULONG good_loads;
|
|
ULONG backup_server;
|
|
ULONG state;
|
|
ULONG iframes_sent;
|
|
ULONG rawframes_sent; // was send_rawframes
|
|
ULONG ctlframes_sent; // was send_ctlframes
|
|
ULONG iframes_resent; // was pkt_resends
|
|
ULONG iframes_outofseq; // was ErrBadIndex
|
|
ULONG frames_rcvd; // was: rec_pkts
|
|
ULONG nic_index;
|
|
unsigned char dest_addr[6];
|
|
} PROBE_DEVICE_STRUCT;
|
|
|
|
typedef struct {
|
|
ULONG struct_size;
|
|
ULONG Open;
|
|
ULONG pkt_sent;
|
|
ULONG pkt_rcvd_ours;
|
|
ULONG pkt_rcvd_not_ours;
|
|
char NicName[64];
|
|
unsigned char address[6];
|
|
} PROBE_NIC_STRUCT;
|
|
|
|
static PSERIAL_DEVICE_EXTENSION find_ext_mac_match(unsigned char *mac_addr);
|
|
static int ProbeDevices(unsigned char *pPtr, int availableLength);
|
|
static int ProbeNic(unsigned char *pPtr, int availableLength);
|
|
|
|
/*-------------------------------------------------------------------
|
|
Function : SerialIoControl
|
|
Purpose: Process Ioctls for a device.
|
|
Call: SerialIoControl(DeviceObject,Irp)
|
|
PDEVICE_OBJECT DeviceObject: Pointer to the Device Object
|
|
PIRP Irp: Pointer to the I/O Request Packet
|
|
Return: STATUS_SUCCESS: always
|
|
STATUS_FAIL: if request couldn't be fulfilled
|
|
Comments: This function is the device driver IOCTL entry point.
|
|
|--------------------------------------------------------------------*/
|
|
NTSTATUS SerialIoControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
|
|
KIRQL OldIrql;
|
|
BOOLEAN acceptingIRPs;
|
|
|
|
acceptingIRPs = SerialIRPPrologue(Extension);
|
|
|
|
if (acceptingIRPs == FALSE) {
|
|
MyKdPrint(D_Ioctl,("Ioctl:no irps accepted!\n"))
|
|
Irp->IoStatus.Information = 0;
|
|
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
|
|
SerialCompleteRequest(Extension, Irp, IO_NO_INCREMENT);
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
Irp->IoStatus.Information = 0L;
|
|
|
|
MyKdPrint(D_Ioctl,("SerialIoControl: %x\n",
|
|
IrpSp->Parameters.DeviceIoControl.IoControlCode))
|
|
// Make sure we aren't aborting due to error (ERROR_ABORT)
|
|
|
|
if (Extension->ErrorWord)
|
|
{
|
|
if (Extension->DeviceType == DEV_PORT)
|
|
{
|
|
if (SerialCompleteIfError(DeviceObject, Irp) != STATUS_SUCCESS)
|
|
{
|
|
MyKdPrint(D_Ioctl,("ErrSet, Cancel!\n"))
|
|
{ExtTrace(Extension,D_Ioctl,"ErrSet!");}
|
|
return STATUS_CANCELLED;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Make sure IOCTL is applicable for the device type (i.e. ignore port
|
|
// level IOCTL's if board object is specified
|
|
//
|
|
|
|
if (Extension->DeviceType == DEV_BOARD)
|
|
{
|
|
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
|
|
{
|
|
case IOCTL_SERIAL_CONFIG_SIZE:
|
|
case IOCTL_SERIAL_GET_COMMCONFIG:
|
|
case IOCTL_SERIAL_SET_COMMCONFIG:
|
|
case IOCTL_RCKT_GET_STATS:
|
|
case IOCTL_RCKT_ISR_CNT:
|
|
case IOCTL_RCKT_CHECK:
|
|
case IOCTL_RCKT_MONALL:
|
|
case IOCTL_RCKT_SET_MODEM_RESET:
|
|
case IOCTL_RCKT_CLEAR_MODEM_RESET:
|
|
case IOCTL_RCKT_SEND_MODEM_ROW:
|
|
case IOCTL_RCKT_SET_MODEM_RESET_OLD:
|
|
case IOCTL_RCKT_CLEAR_MODEM_RESET_OLD:
|
|
case IOCTL_RCKT_GET_RCKTMDM_INFO_OLD:
|
|
case IOCTL_RCKT_SEND_MODEM_ROW_OLD:
|
|
|
|
break; // Allowable board level IOCTL's
|
|
|
|
default:
|
|
MyKdPrint (D_Ioctl, (" Bad Status: %xH on IIOCTL: %xH\n", Status,
|
|
IrpSp->Parameters.DeviceIoControl.IoControlCode));
|
|
ExtTrace2 (Extension, D_Ioctl, " Bad Status:%xH on IIOCTL:%xH",
|
|
Status, IrpSp->Parameters.DeviceIoControl.IoControlCode);
|
|
Irp->IoStatus.Information = 0;
|
|
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
SerialCompleteRequest(Extension, Irp, IO_NO_INCREMENT);
|
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
};
|
|
|
|
// Main IOCTL switch
|
|
//ExtTrace1(Extension,D_Ioctl,"Ioctl:%x",
|
|
// IrpSp->Parameters.DeviceIoControl.IoControlCode);
|
|
|
|
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
|
|
{
|
|
|
|
//******************************
|
|
case IOCTL_SERIAL_GET_STATS : // get performace stats
|
|
{
|
|
PSERIALPERF_STATS sp = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(SERIALPERF_STATS)) {
|
|
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
|
|
}
|
|
Irp->IoStatus.Information = sizeof(SERIALPERF_STATS);
|
|
Status = STATUS_SUCCESS;
|
|
|
|
|
|
sp->TransmittedCount = Extension->OurStats.TransmittedCount -
|
|
Extension->OldStats.TransmittedCount;
|
|
sp->FrameErrorCount = Extension->OurStats.FrameErrorCount -
|
|
Extension->OldStats.FrameErrorCount;
|
|
sp->SerialOverrunErrorCount = Extension->OurStats.SerialOverrunErrorCount -
|
|
Extension->OldStats.SerialOverrunErrorCount;
|
|
sp->BufferOverrunErrorCount = Extension->OurStats.BufferOverrunErrorCount -
|
|
Extension->OldStats.BufferOverrunErrorCount;
|
|
sp->ParityErrorCount = Extension->OurStats.ParityErrorCount -
|
|
Extension->OldStats.ParityErrorCount;
|
|
}
|
|
break;
|
|
|
|
//******************************
|
|
case IOCTL_SERIAL_CLEAR_STATS : // clear performace stats
|
|
{
|
|
|
|
Extension->OldStats.TransmittedCount =
|
|
Extension->OurStats.TransmittedCount;
|
|
|
|
Extension->OldStats.FrameErrorCount =
|
|
Extension->OurStats.FrameErrorCount;
|
|
|
|
Extension->OldStats.SerialOverrunErrorCount =
|
|
Extension->OurStats.SerialOverrunErrorCount;
|
|
|
|
Extension->OldStats.BufferOverrunErrorCount =
|
|
Extension->OurStats.BufferOverrunErrorCount;
|
|
|
|
Extension->OldStats.ParityErrorCount =
|
|
Extension->OurStats.ParityErrorCount;
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
//******************************
|
|
case IOCTL_SERIAL_SET_BAUD_RATE :
|
|
{
|
|
ULONG DesiredBaudRate;
|
|
MyKdPrint(D_Ioctl,("[Set Baud Rate]\n"))
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(SERIAL_BAUD_RATE))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
MyKdPrint(D_Ioctl,("[Buffer too Small]\n"))
|
|
break;
|
|
}
|
|
DesiredBaudRate =
|
|
((PSERIAL_BAUD_RATE)(Irp->AssociatedIrp.SystemBuffer))->BaudRate;
|
|
|
|
ExtTrace1(Extension,D_Ioctl,"Set Baud Rate:%d",DesiredBaudRate);
|
|
|
|
Status = ProgramBaudRate(Extension,DesiredBaudRate);
|
|
|
|
break;
|
|
}
|
|
|
|
//******************************
|
|
case IOCTL_SERIAL_GET_BAUD_RATE:
|
|
{
|
|
PSERIAL_BAUD_RATE Br =
|
|
(PSERIAL_BAUD_RATE)Irp->AssociatedIrp.SystemBuffer;
|
|
MyKdPrint(D_Ioctl,("[Get Baud Rate]\n"))
|
|
ExtTrace1(Extension,D_Ioctl,"Get Baud Rate:%d",Extension->BaudRate);
|
|
|
|
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(SERIAL_BAUD_RATE))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
KeAcquireSpinLock(&Extension->ControlLock,&OldIrql);
|
|
Br->BaudRate = Extension->BaudRate;
|
|
KeReleaseSpinLock(&Extension->ControlLock,OldIrql);
|
|
Irp->IoStatus.Information = sizeof(SERIAL_BAUD_RATE);
|
|
break;
|
|
}
|
|
|
|
//*********************************
|
|
case IOCTL_SERIAL_SET_LINE_CONTROL:
|
|
{
|
|
PSERIAL_LINE_CONTROL DesiredLineControl;
|
|
MyKdPrint(D_Ioctl,("[Set Line Control]\n"))
|
|
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(SERIAL_LINE_CONTROL))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
DesiredLineControl =
|
|
((PSERIAL_LINE_CONTROL)(Irp->AssociatedIrp.SystemBuffer));
|
|
|
|
ExtTrace(Extension,D_Ioctl, "Set Line Ctrl");
|
|
|
|
Status = ProgramLineControl(Extension,DesiredLineControl);
|
|
break;
|
|
}
|
|
|
|
//*********************************
|
|
case IOCTL_SERIAL_GET_LINE_CONTROL:
|
|
{
|
|
PSERIAL_LINE_CONTROL Lc =
|
|
(PSERIAL_LINE_CONTROL)Irp->AssociatedIrp.SystemBuffer;
|
|
MyKdPrint(D_Ioctl,("[Get Line Control]\n"))
|
|
ExtTrace(Extension,D_Ioctl,"Get Line Ctrl");
|
|
|
|
Irp->IoStatus.Information = sizeof(SERIAL_LINE_CONTROL);
|
|
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(SERIAL_LINE_CONTROL))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
Lc->Parity=Extension->LineCtl.Parity;
|
|
Lc->WordLength=Extension->LineCtl.WordLength;
|
|
Lc->StopBits=Extension->LineCtl.StopBits;
|
|
break;
|
|
}
|
|
|
|
//******************************
|
|
case IOCTL_SERIAL_SET_TIMEOUTS:
|
|
{
|
|
PSERIAL_TIMEOUTS NewTimeouts =
|
|
((PSERIAL_TIMEOUTS)(Irp->AssociatedIrp.SystemBuffer));
|
|
MyKdPrint(D_Ioctl,("[Set Timeouts]\n"))
|
|
|
|
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;
|
|
}
|
|
|
|
ExtTrace3(Extension,D_Ioctl,"Timeouts-RIT:%xH RM:%xH RC:%xH",
|
|
NewTimeouts->ReadIntervalTimeout,
|
|
NewTimeouts->ReadTotalTimeoutMultiplier,
|
|
NewTimeouts->ReadTotalTimeoutConstant);
|
|
|
|
ExtTrace2(Extension,D_Ioctl," WM:%xH WC:%xH",
|
|
NewTimeouts->WriteTotalTimeoutMultiplier,
|
|
NewTimeouts->WriteTotalTimeoutConstant);
|
|
|
|
|
|
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:
|
|
{
|
|
MyKdPrint(D_Ioctl,("[Get Timeouts]\n"))
|
|
ExtTrace(Extension,D_Ioctl,"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:
|
|
{
|
|
SERIAL_IOCTL_SYNC S;
|
|
PSERIAL_CHARS NewChars =
|
|
((PSERIAL_CHARS)(Irp->AssociatedIrp.SystemBuffer));
|
|
MyKdPrint(D_Ioctl,("[Set Xon/Xoff Chars]\n"))
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(SERIAL_CHARS))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
ExtTrace3(Extension,D_Ioctl,"Set Chars Xon:%xH, Xoff:%xH Evt:%xH",
|
|
NewChars->XonChar,NewChars->XoffChar, NewChars->EventChar);
|
|
|
|
// The only thing that can be wrong with the chars
|
|
// is that the xon and xoff characters are the same.
|
|
#ifdef COMMENT_OUT
|
|
// comment out kpb, problem with hardware flow control, nt
|
|
// may connect and do this(Delrina WinFaxPro, SAPS modem pooling
|
|
// had trouble erroring out, but not on standard microsoft port.
|
|
|
|
if (NewChars->XonChar == NewChars->XoffChar)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
#endif
|
|
// We acquire the control lock so that only
|
|
// one request can GET or SET the characters
|
|
// at a time. The sets could be synchronized
|
|
// by the interrupt spinlock, but that wouldn't
|
|
// prevent multiple gets at the same time.
|
|
S.Extension = Extension;
|
|
S.Data = NewChars;
|
|
|
|
KeAcquireSpinLock(&Extension->ControlLock,&OldIrql);
|
|
|
|
Extension->SpecialChars.EofChar = NewChars->EofChar;
|
|
Extension->SpecialChars.ErrorChar = NewChars->ErrorChar;
|
|
Extension->SpecialChars.BreakChar=NewChars->BreakChar;
|
|
|
|
// Only set up byte in case we're already EventChar-ing it,
|
|
// Actual programming of interrupt is done in wait on mask call.
|
|
Extension->SpecialChars.EventChar=NewChars->EventChar;
|
|
Extension->SpecialChars.XonChar=NewChars->XonChar;
|
|
Extension->SpecialChars.XoffChar=NewChars->XoffChar;
|
|
#ifdef S_RK
|
|
sSetRxCmpVal1(Extension->ChP,NewChars->EventChar);
|
|
sSetTxXONChar(Extension->ChP,NewChars->XonChar);
|
|
sSetTxXOFFChar(Extension->ChP,NewChars->XoffChar);
|
|
#else
|
|
pSetEventChar(Extension->Port,NewChars->EventChar);
|
|
pSetXONChar(Extension->Port,NewChars->XonChar);
|
|
pSetXOFFChar(Extension->Port,NewChars->XoffChar);
|
|
#endif
|
|
KeReleaseSpinLock(&Extension->ControlLock,OldIrql);
|
|
break;
|
|
}
|
|
|
|
//**************************
|
|
case IOCTL_SERIAL_GET_CHARS:
|
|
{
|
|
MyKdPrint(D_Ioctl,("[Get Xon/Xoff Chars]\n"))
|
|
ExtTrace(Extension,D_Ioctl,"Get Xon/Xoff Chars");
|
|
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(SERIAL_CHARS))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
KeAcquireSpinLock(&Extension->ControlLock,&OldIrql);
|
|
|
|
// Copy the whole struct over to the buffer
|
|
*((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:
|
|
{
|
|
MyKdPrint(D_Ioctl,("[Set and Clr DTR]\n"))
|
|
// We acquire the lock so that we can check whether
|
|
// automatic dtr flow control is enabled. If it is,
|
|
// then return an error since the app is not allowed
|
|
// to touch this if it is automatic.
|
|
|
|
KeAcquireSpinLock(&Extension->ControlLock, &OldIrql);
|
|
|
|
if ((Extension->HandFlow.ControlHandShake & SERIAL_DTR_MASK)
|
|
== SERIAL_DTR_HANDSHAKE)
|
|
{ // bogus
|
|
//Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
//Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
if(IrpSp->Parameters.DeviceIoControl.IoControlCode ==
|
|
IOCTL_SERIAL_SET_DTR )
|
|
{
|
|
ExtTrace(Extension,D_Ioctl,"Set DTR");
|
|
#ifdef S_VS
|
|
pSetDTR(Extension->Port);
|
|
#else
|
|
sSetDTR(Extension->ChP);
|
|
#endif
|
|
Extension->DTRRTSStatus |= SERIAL_DTR_STATE;
|
|
}
|
|
else
|
|
{
|
|
//must be IOCTL_SERIAL_CLR_DTR
|
|
ExtTrace(Extension,D_Ioctl,"Clr DTR");
|
|
#ifdef S_VS
|
|
pClrDTR(Extension->Port);
|
|
#else
|
|
sClrDTR(Extension->ChP);
|
|
#endif
|
|
Extension->DTRRTSStatus &= ~SERIAL_DTR_STATE;
|
|
}
|
|
}
|
|
|
|
KeReleaseSpinLock(&Extension->ControlLock, OldIrql);
|
|
|
|
break;
|
|
}
|
|
|
|
//************************
|
|
case IOCTL_SERIAL_RESET_DEVICE:
|
|
MyKdPrint(D_Ioctl,("[Reset Device]\n"));
|
|
ExtTrace(Extension,D_Ioctl,"Reset Device");
|
|
// Example driver also takes no action
|
|
break;
|
|
|
|
//************************
|
|
case IOCTL_SERIAL_SET_RTS:
|
|
MyKdPrint(D_Ioctl,("[Set RTS]\n"));
|
|
ExtTrace(Extension,D_Ioctl,"Set RTS");
|
|
// Make sure RTS isn't already used for handshake or toggle
|
|
if( ( (Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
|
|
SERIAL_RTS_HANDSHAKE) ||
|
|
( (Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
|
|
SERIAL_TRANSMIT_TOGGLE)
|
|
)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
ExtTrace(Extension,D_Ioctl," not set,flow");
|
|
}
|
|
else
|
|
{
|
|
if (!(Extension->Option & OPTION_RS485_OVERRIDE))
|
|
{
|
|
#ifdef S_VS
|
|
pSetRTS(Extension->Port);
|
|
#else
|
|
sSetRTS(Extension->ChP);
|
|
#endif
|
|
Extension->DTRRTSStatus |= SERIAL_RTS_STATE;
|
|
}
|
|
else
|
|
{
|
|
ExtTrace(Extension,D_Ioctl," not set,485");
|
|
}
|
|
}
|
|
break;
|
|
|
|
//************************
|
|
case IOCTL_SERIAL_CLR_RTS:
|
|
MyKdPrint(D_Ioctl,("[Clr RTS]\n"));
|
|
ExtTrace(Extension,D_Ioctl,"Clr RTS");
|
|
|
|
// Make sure RTS isn't already used for handshake or toggle
|
|
if( ( (Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
|
|
SERIAL_RTS_HANDSHAKE) ||
|
|
( (Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
|
|
SERIAL_TRANSMIT_TOGGLE)
|
|
)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
ExtTrace(Extension,D_Ioctl," not clr,flow");
|
|
}
|
|
else
|
|
{
|
|
if (!(Extension->Option & OPTION_RS485_OVERRIDE))
|
|
{
|
|
#ifdef S_VS
|
|
pClrRTS(Extension->Port);
|
|
#else
|
|
sClrRTS(Extension->ChP);
|
|
#endif
|
|
Extension->DTRRTSStatus &= ~SERIAL_RTS_STATE;
|
|
}
|
|
else
|
|
{
|
|
ExtTrace(Extension,D_Ioctl," not clr,485");
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
//*************************
|
|
case IOCTL_SERIAL_SET_XOFF:
|
|
MyKdPrint(D_Ioctl,("[Set Xoff]\n"));
|
|
ExtTrace(Extension,D_Ioctl,"Set Xoff");
|
|
|
|
#ifdef S_RK
|
|
if (sIsTxSoftFlowCtlEnabled(Extension->ChP))
|
|
{
|
|
sDisTxSoftFlowCtl(Extension->ChP); // turn off Tx software flow control
|
|
sDisTransmit(Extension->ChP); // Stop the transmitter
|
|
sEnRxIntCompare2(Extension->ChP,(unsigned char) Extension->SpecialChars.XonChar);
|
|
Extension->TXHolding |= SERIAL_TX_XOFF;
|
|
Extension->TXHolding |= ST_XOFF_FAKE;
|
|
}
|
|
#else
|
|
if (Extension->HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT)
|
|
{
|
|
Extension->TXHolding |= SERIAL_TX_XOFF;
|
|
pOverrideSetXoff(Extension->Port);
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
//************************
|
|
case IOCTL_SERIAL_SET_XON:
|
|
MyKdPrint(D_Ioctl,("[Set Xon]\n"));
|
|
ExtTrace(Extension,D_Ioctl,"Set Xon");
|
|
#ifdef S_VS
|
|
{
|
|
pOverrideClearXoff(Extension->Port);
|
|
Extension->TXHolding &= ~SERIAL_TX_XOFF;
|
|
}
|
|
#else
|
|
if (Extension->TXHolding & ST_XOFF_FAKE)
|
|
{
|
|
Extension->TXHolding &= ~SERIAL_TX_XOFF;
|
|
Extension->TXHolding &= ~ST_XOFF_FAKE;
|
|
if ((Extension->TXHolding &
|
|
(SERIAL_TX_DCD | SERIAL_TX_DSR | ST_XOFF_FAKE)) == 0)
|
|
sEnTransmit(Extension->ChP); // Start up the transmitter
|
|
sDisRxCompare2(Extension->ChP);
|
|
sEnTxSoftFlowCtl(Extension->ChP); // turn off Tx software flow control
|
|
}
|
|
|
|
// override an actual XOFF from remote
|
|
sClrTxXOFF(Extension->ChP);
|
|
|
|
// check for IOCTL_SERIAL_SET_XOFF state
|
|
if(Extension->TXHolding & SERIAL_TX_XOFF)
|
|
{
|
|
// Make sure BREAK state hasn't disabled the Transmitter
|
|
if(!(Extension->TXHolding & SERIAL_TX_BREAK))
|
|
sEnTransmit(Extension->ChP);
|
|
Extension->TXHolding &= ~SERIAL_TX_XOFF;
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
//******************************
|
|
case IOCTL_SERIAL_SET_BREAK_ON:
|
|
{
|
|
|
|
ExtTrace(Extension,D_Ioctl,"Set Break on");
|
|
#ifdef S_VS
|
|
pSetBreak(Extension->Port);
|
|
Extension->TXHolding |= SERIAL_TX_BREAK;
|
|
#else
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
if( !(Extension->TXHolding & SERIAL_TX_BREAK) )
|
|
{
|
|
// Stop the transmitter
|
|
sDisTransmit(Extension->ChP);
|
|
|
|
// Request break, Polling will check on Transmitter empty
|
|
Extension->TXHolding |= SERIAL_TX_BREAK;
|
|
|
|
// Make sure Transmitter is empty before slamming BREAK
|
|
// Check the bit twice in case of time between buf and txshr load
|
|
if( (sGetChanStatusLo(Extension->ChP) & TXSHRMT) &&
|
|
(sGetChanStatusLo(Extension->ChP) & TXSHRMT) )
|
|
{
|
|
sSendBreak(Extension->ChP);
|
|
Extension->DevStatus &= ~COM_REQUEST_BREAK;
|
|
}
|
|
else
|
|
Extension->DevStatus |= COM_REQUEST_BREAK;
|
|
}
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
//******************************
|
|
case IOCTL_SERIAL_SET_BREAK_OFF:
|
|
{
|
|
ExtTrace(Extension,D_Ioctl,"Set Break Off");
|
|
|
|
#ifdef S_VS
|
|
if (Extension->TXHolding & SERIAL_TX_BREAK)
|
|
{
|
|
Extension->TXHolding &= ~SERIAL_TX_BREAK;
|
|
pClrBreak(Extension->Port);
|
|
}
|
|
#else
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
if(Extension->TXHolding & SERIAL_TX_BREAK)
|
|
{
|
|
Extension->TXHolding &= ~SERIAL_TX_BREAK;
|
|
|
|
sClrBreak(Extension->ChP);
|
|
|
|
if(!(Extension->TXHolding & SERIAL_TX_XOFF))
|
|
{
|
|
sEnTransmit(Extension->ChP);
|
|
}
|
|
}
|
|
|
|
if(Extension->DevStatus & COM_REQUEST_BREAK)
|
|
{
|
|
// If we hit this code, the requested BREAK will not have gone out
|
|
Extension->DevStatus &= ~COM_REQUEST_BREAK;
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
//******************************
|
|
case IOCTL_SERIAL_SET_QUEUE_SIZE:
|
|
{
|
|
LONG new_size;
|
|
PUCHAR NewBuf;
|
|
|
|
PSERIAL_QUEUE_SIZE Rs =
|
|
((PSERIAL_QUEUE_SIZE)(Irp->AssociatedIrp.SystemBuffer));
|
|
|
|
MyKdPrint(D_Ioctl,("[Set Queue Size]\n"));
|
|
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(SERIAL_QUEUE_SIZE))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
new_size = (LONG) Rs->InSize;
|
|
ExtTrace1(Extension,D_Ioctl,"Set Queue Size, In:%d", new_size);
|
|
if (new_size > 0x20000L)
|
|
new_size = 0x20000L; /// limit to about 128K
|
|
|
|
// try to allocate buffer here if user requests larger buffer
|
|
// don't resize if they want to shrink(why bother)
|
|
if (new_size <= Extension->RxQ.QSize)
|
|
{
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
++new_size; // some circular queue wierdness
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
NewBuf = our_locked_alloc(new_size+16, "exRX"); // add some slop
|
|
if (NewBuf != NULL)
|
|
{
|
|
// Eprintf("Resized Buffer, new:%d, old:%d",new_size-1, Extension->RxQ.QSize-1);
|
|
Extension->RxQ.QSize = new_size;
|
|
our_free(Extension->RxQ.QBase, "exRX");
|
|
Extension->RxQ.QBase= NewBuf;
|
|
Extension->RxQ.QGet = 0;
|
|
Extension->RxQ.QPut = 0;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER; // not the greatest choise
|
|
}
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
break;
|
|
}
|
|
|
|
//******************************
|
|
case IOCTL_SERIAL_GET_WAIT_MASK:
|
|
// This mask contains the various Events the WaitIrp is waiting
|
|
// for from SetCommMask(), such as EV_BREAK, EV_CTS, EV_DSR,
|
|
// EV_ERR, EV_RING, EV_RLSD, EV_RXCHAR, EV_RXFLAG, EV_TXEMPTY
|
|
|
|
MyKdPrint(D_Ioctl,("[Get Wait Mask:%xH\n]",Extension->IsrWaitMask))
|
|
|
|
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(ULONG))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
ExtTrace1(Extension,D_Ioctl,"Get Wait Mask:%xH",Extension->IsrWaitMask);
|
|
|
|
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);
|
|
MyKdPrint(D_Ioctl,("set wait mask:%xH\n",NewMask))
|
|
ExtTrace1(Extension,D_Ioctl,"Set Wait Mask:%xH",NewMask);
|
|
}
|
|
|
|
//------- Complete the old wait if there is one.
|
|
#ifdef NEW_WAIT_SYNC_LOCK
|
|
SyncUp(Driver.InterruptObject,
|
|
&Driver.TimerLock,
|
|
SerialGrabWaitFromIsr,
|
|
Extension);
|
|
#endif
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
if (Extension->CurrentWaitIrp)
|
|
{
|
|
PIRP Irp;
|
|
Extension->IrpMaskLocation = NULL;
|
|
MyKdPrint(D_Ioctl,("[kill old wait]\n"))
|
|
ExtTrace(Extension,D_Ioctl, " Kill Old Wait");
|
|
*(ULONG *)Extension->CurrentWaitIrp->AssociatedIrp.SystemBuffer = 0;
|
|
Extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
|
|
Extension->CurrentWaitIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp = Extension->CurrentWaitIrp;
|
|
IoSetCancelRoutine(Irp, NULL);
|
|
Extension->CurrentWaitIrp = 0;
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
SerialCompleteRequest(Extension, Irp, IO_SERIAL_INCREMENT);
|
|
}
|
|
else
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
//----- retain any bits from when no WaitIrp present
|
|
Extension->HistoryMask &= NewMask;
|
|
|
|
//----- set the mask of interested events
|
|
Extension->IsrWaitMask = NewMask;
|
|
|
|
// move this from wait_on_mask call to here, kpb, 1-16-97
|
|
#ifdef S_RK
|
|
if (Extension->IsrWaitMask & SERIAL_EV_RXFLAG)
|
|
{
|
|
sEnRxIntCompare1(Extension->ChP,
|
|
Extension->SpecialChars.EventChar);
|
|
}
|
|
else
|
|
{
|
|
sDisRxCompare1(Extension->ChP);
|
|
}
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
//******************************
|
|
case IOCTL_SERIAL_WAIT_ON_MASK:
|
|
{
|
|
MyKdPrint(D_Ioctl,("[wait on mask]\n"))
|
|
ExtTrace(Extension,D_Ioctl,"Wait On Mask");
|
|
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(ULONG))
|
|
{
|
|
ExtTrace(Extension,D_Ioctl,"Wait IRP, Bad Size");
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
// put this in to fix an incompatibility with WaitOnMultipleObjects()
|
|
// 6-26-98 kpb
|
|
if (Extension->CurrentWaitIrp)
|
|
{
|
|
MyKdPrint(D_Ioctl,("[Already pending]\n"))
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
#ifdef NEW_WAIT_SYNC_LOCK
|
|
SyncUp(Driver.InterruptObject,
|
|
&Driver.TimerLock,
|
|
SerialGrabWaitFromIsr,
|
|
Extension);
|
|
#else
|
|
Extension->WaitIsISRs = 0;
|
|
Extension->IrpMaskLocation = &Extension->DummyIrpMaskLoc;
|
|
#endif
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
//------- Complete the old wait if there is one.
|
|
if (Extension->CurrentWaitIrp)
|
|
{
|
|
PIRP Irp;
|
|
|
|
MyKdPrint(D_Ioctl,("[kill old wait]\n"))
|
|
ExtTrace(Extension,D_Ioctl, " Kill Old Wait");
|
|
*(ULONG *)Extension->CurrentWaitIrp->AssociatedIrp.SystemBuffer = 0;
|
|
Extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
|
|
Extension->CurrentWaitIrp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
Irp = Extension->CurrentWaitIrp;
|
|
IoSetCancelRoutine(Irp, NULL);
|
|
Extension->CurrentWaitIrp = 0;
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
SerialCompleteRequest(Extension, Irp, IO_SERIAL_INCREMENT);
|
|
}
|
|
else
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
if (Extension->IsrWaitMask == 0)
|
|
{
|
|
ExtTrace(Extension,D_Ioctl," WaitMask==0");
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
if (Irp->Cancel)
|
|
{
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
SerialCompleteRequest(Extension, Irp, 0);
|
|
Status = STATUS_CANCELLED;
|
|
}
|
|
else
|
|
{
|
|
Extension->CurrentWaitIrp = Irp;
|
|
Irp->IoStatus.Status = STATUS_PENDING;
|
|
IoMarkIrpPending(Irp);
|
|
IoSetCancelRoutine(Extension->CurrentWaitIrp, SerialCancelWait);
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
// give to ISR to process
|
|
Extension->IrpMaskLocation = (ULONG *)
|
|
Extension->CurrentWaitIrp->AssociatedIrp.SystemBuffer;
|
|
Extension->WaitIsISRs = 1; // give to ISR
|
|
ExtTrace(Extension,D_Ioctl," PENDING.");
|
|
return STATUS_PENDING;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IOCTL_SERIAL_IMMEDIATE_CHAR:
|
|
{
|
|
UCHAR TxByte;
|
|
KIRQL OldIrql;
|
|
ExtTrace(Extension,D_Ioctl,"Immed. Char");
|
|
|
|
if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(UCHAR) )
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
TxByte = *((UCHAR *)(Irp->AssociatedIrp.SystemBuffer));
|
|
|
|
Extension->ISR_Flags |= TX_NOT_EMPTY; // fix for EV_TXEMPTY 1-21-99
|
|
#ifdef S_RK
|
|
if(!sWriteTxPrioByte(Extension->ChP,TxByte))
|
|
{
|
|
// No room for immediate character in Priority queue
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
#else
|
|
if ( (ULONG)(PortGetTxRoom(Extension->Port)) > 0)
|
|
{
|
|
// Send the byte
|
|
q_put(&Extension->Port->QOut,
|
|
(PUCHAR) &TxByte,
|
|
1);
|
|
}
|
|
#endif
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
break;
|
|
}
|
|
|
|
//**********************
|
|
case IOCTL_SERIAL_PURGE:
|
|
{
|
|
ULONG Mask;
|
|
|
|
MyKdPrint(D_Ioctl,("[Serial Purge]"));
|
|
|
|
// Check to make sure that the mask only has 0 or the other
|
|
// appropriate values. A null mask is equivalent to a mask of 0
|
|
|
|
if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(ULONG) )
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
};
|
|
|
|
if ( Irp->AssociatedIrp.SystemBuffer )
|
|
{
|
|
Mask = *((ULONG *)(Irp->AssociatedIrp.SystemBuffer));
|
|
ExtTrace1(Extension,D_Ioctl,"Serial Purge:%xH",Mask);
|
|
}
|
|
else
|
|
{
|
|
Mask = 0;
|
|
}
|
|
|
|
if ((!Mask) || (Mask & (~(SERIAL_PURGE_TXABORT |
|
|
SERIAL_PURGE_RXABORT |
|
|
SERIAL_PURGE_TXCLEAR |
|
|
SERIAL_PURGE_RXCLEAR )
|
|
) ))
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
return SerialStartOrQueue(Extension,
|
|
Irp,
|
|
&Extension->PurgeQueue,
|
|
&Extension->CurrentPurgeIrp,
|
|
SerialStartPurge );
|
|
|
|
}
|
|
|
|
//*****************************
|
|
case IOCTL_SERIAL_GET_HANDFLOW:
|
|
{
|
|
MyKdPrint(D_Ioctl,("[Get Handflow]\n"))
|
|
ExtTrace(Extension,D_Ioctl,"Get Handflow");
|
|
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(SERIAL_HANDFLOW))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Information = sizeof(SERIAL_HANDFLOW);
|
|
|
|
*((PSERIAL_HANDFLOW)Irp->AssociatedIrp.SystemBuffer) =
|
|
Extension->HandFlow;
|
|
|
|
break;
|
|
}
|
|
|
|
//*****************************
|
|
case IOCTL_SERIAL_SET_HANDFLOW:
|
|
{
|
|
ULONG trace_flags = 0;
|
|
SERIAL_IOCTL_SYNC S;
|
|
PSERIAL_HANDFLOW HandFlow = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
MyKdPrint(D_Ioctl,("[Set HandFlow]\n"))
|
|
ExtTrace(Extension,D_Ioctl,"Set HandFlow");
|
|
|
|
// Make sure that the buffer is big enough
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(SERIAL_HANDFLOW))
|
|
{
|
|
ExtTrace(Extension,D_Ioctl,"ErZ!");
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////
|
|
// Make sure that no invalid parameters have been set
|
|
|
|
// Check ControlHandShake first
|
|
// For Rocket, we or in several that can't be supported
|
|
|
|
if(HandFlow->ControlHandShake & (SERIAL_CONTROL_INVALID |
|
|
SERIAL_DSR_SENSITIVITY
|
|
) )
|
|
{
|
|
|
|
{ ExtTrace(Extension,D_Ioctl,"Err M!"); }
|
|
|
|
if(HandFlow->ControlHandShake & SERIAL_DSR_SENSITIVITY)
|
|
{ ExtTrace(Extension,D_Ioctl,"No DSR Sen!"); }
|
|
if(HandFlow->ControlHandShake & SERIAL_CONTROL_INVALID)
|
|
{ ExtTrace(Extension,D_Ioctl,"Invalid con!"); }
|
|
// don't bail out - kpb(5-23-96)
|
|
//Status = STATUS_INVALID_PARAMETER;
|
|
//break;
|
|
}
|
|
|
|
if (HandFlow->FlowReplace & SERIAL_FLOW_INVALID)
|
|
{
|
|
ExtTrace(Extension,D_Ioctl,"ErA!");
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
// Make sure that the app hasn't set an invalid DTR mode.
|
|
// Both options can't be set
|
|
if((HandFlow->ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_MASK)
|
|
{
|
|
ExtTrace(Extension,D_Ioctl,"ErB!");
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
// Xon/Xoff limits unused for RocketPort (they're internal).
|
|
HandFlow->XonLimit=0;
|
|
HandFlow->XoffLimit=0;
|
|
|
|
S.Extension = Extension;
|
|
S.Data = HandFlow;
|
|
|
|
KeAcquireSpinLock(&Extension->ControlLock,&OldIrql);
|
|
|
|
SerialSetHandFlow(Extension, HandFlow);
|
|
|
|
KeReleaseSpinLock(&Extension->ControlLock,OldIrql);
|
|
|
|
if ((Extension->HandFlow.ControlHandShake & SERIAL_RTS_MASK) ==
|
|
SERIAL_RTS_HANDSHAKE)
|
|
{ExtTrace(Extension,D_Ioctl,"RTS-Auto");}
|
|
|
|
if (Extension->HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE)
|
|
{ExtTrace(Extension,D_Ioctl,"CTS-Auto");}
|
|
|
|
if ((Extension->HandFlow.ControlHandShake & SERIAL_DTR_MASK) ==
|
|
SERIAL_DTR_HANDSHAKE)
|
|
{ExtTrace(Extension,D_Ioctl,"DTR-Auto");}
|
|
|
|
if (Extension->HandFlow.ControlHandShake & SERIAL_DSR_HANDSHAKE)
|
|
{ExtTrace(Extension,D_Ioctl,"DSR-Auto");}
|
|
|
|
if (Extension->HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT)
|
|
{ExtTrace(Extension,D_Ioctl,"Xon-Auto");}
|
|
}
|
|
break;
|
|
//********************************
|
|
case IOCTL_SERIAL_GET_MODEMSTATUS:
|
|
{
|
|
|
|
if ( IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(ULONG) )
|
|
{ Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Information = sizeof(ULONG);
|
|
//Irp->IoStatus.Status = STATUS_SUCCESS; bogus(set at end)
|
|
Status = STATUS_SUCCESS; // don't need, default
|
|
#ifdef S_RK
|
|
// Update the modem inputs, fn() reads and converts the bits
|
|
SetExtensionModemStatus(Extension);
|
|
#endif
|
|
|
|
ExtTrace1(Extension,D_Ioctl,"Get ModemStatus:%xH",Extension->ModemStatus);
|
|
|
|
*(PULONG)Irp->AssociatedIrp.SystemBuffer = Extension->ModemStatus;
|
|
|
|
break;
|
|
}
|
|
|
|
//***************************
|
|
case IOCTL_SERIAL_GET_DTRRTS:
|
|
{
|
|
MyKdPrint(D_Ioctl,("[Get DTR/RTS]\n"))
|
|
// The Rocket cannot truly reflect RTS setting, best guess is returned
|
|
if ( IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(ULONG) )
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Information = sizeof(ULONG);
|
|
//Irp->IoStatus.Status = STATUS_SUCCESS; bogus, set at end
|
|
Status = STATUS_SUCCESS; // don't need
|
|
|
|
*(PULONG)Irp->AssociatedIrp.SystemBuffer = Extension->DTRRTSStatus;
|
|
ExtTrace1(Extension,D_Ioctl,"Get DTR/RTS:%xH",Extension->DTRRTSStatus);
|
|
|
|
break;
|
|
}
|
|
|
|
//*******************************
|
|
case IOCTL_SERIAL_GET_COMMSTATUS:
|
|
{
|
|
PSERIAL_STATUS Stat;
|
|
LONG RxCount;
|
|
LONG TxCount;
|
|
|
|
if ( IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(SERIAL_STATUS) )
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Information = sizeof(SERIAL_STATUS);
|
|
Stat = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
// EOF is always off, NT only supports binary mode
|
|
// This in keeping with the example driver
|
|
Stat->EofReceived = FALSE;
|
|
|
|
// Reading error status clears out the errors.
|
|
Stat->Errors = Extension->ErrorWord;
|
|
Extension->ErrorWord = 0;
|
|
|
|
// We only report here what can be read immediately by the next read
|
|
// The RocketPort's hardware FIFO is not added into this count
|
|
RxCount = q_count(&Extension->RxQ);
|
|
|
|
Stat->AmountInInQueue = RxCount;
|
|
|
|
#ifdef NEW_Q
|
|
#ifdef S_VS
|
|
{
|
|
LONG tx_remote;
|
|
tx_remote = PortGetTxCntRemote(Extension->Port);
|
|
TxCount = PortGetTxCnt(Extension->Port);
|
|
Stat->AmountInOutQueue = Extension->TotalCharsQueued + TxCount + tx_remote;
|
|
ExtTrace4(Extension,D_Ioctl,"Get CommStat,In:%d IRPOut:%d BufOut:%d Remote:%d",
|
|
RxCount, Extension->TotalCharsQueued, TxCount, tx_remote);
|
|
}
|
|
#else
|
|
TxCount = sGetTxCnt(Extension->ChP);
|
|
if ((sGetChanStatusLo(Extension->ChP) & DRAINED) != DRAINED)
|
|
++TxCount;
|
|
|
|
Stat->AmountInOutQueue = Extension->TotalCharsQueued + TxCount;
|
|
ExtTrace3(Extension,D_Ioctl,"Get CommStat,In:%d IRPOut:%d HardOut:%d",
|
|
RxCount, Extension->TotalCharsQueued, TxCount);
|
|
|
|
#endif
|
|
#else
|
|
// older q-tracking code....
|
|
#ifdef S_VS
|
|
TxCount = PortGetTxCnt(Extension->Port);
|
|
#else
|
|
TxCount = sGetTxCnt(Extension->ChP);
|
|
#endif
|
|
Stat->AmountInOutQueue = Extension->TotalCharsQueued + TxCount;
|
|
|
|
ExtTrace3(Extension,D_Ioctl,"Get CommStat,In:%d SoftOut:%d HardOut:%d",
|
|
RxCount, Extension->TotalCharsQueued, TxCount);
|
|
// end older q-tracking code....
|
|
#endif
|
|
#ifdef S_RK
|
|
// NOTE: this can fail due to the Priority buffer bug.
|
|
// If the immediate byte ended up in the FIFO, this will
|
|
// not accurately reflect the Immediate char state.
|
|
if(sGetTxPriorityCnt(Extension->ChP))
|
|
Stat->WaitForImmediate = TRUE;
|
|
else
|
|
Stat->WaitForImmediate = FALSE;
|
|
#else
|
|
Stat->WaitForImmediate = FALSE;
|
|
#endif
|
|
// Holding reasons are hidden in the part
|
|
// Hardware takes care of all the details
|
|
Stat->HoldReasons = 0;
|
|
if (Extension->TXHolding)
|
|
{
|
|
if (Extension->TXHolding & SERIAL_TX_XOFF)
|
|
Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_XON;
|
|
if (Extension->TXHolding & SERIAL_TX_CTS)
|
|
Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_CTS;
|
|
if (Extension->TXHolding & SERIAL_TX_DSR)
|
|
Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_DSR;
|
|
if (Extension->TXHolding & SERIAL_TX_BREAK)
|
|
Stat->HoldReasons |= SERIAL_TX_WAITING_ON_BREAK;
|
|
if (Extension->TXHolding & SERIAL_TX_DCD)
|
|
Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_DCD;
|
|
}
|
|
if (Extension->RXHolding & SERIAL_RX_DSR)
|
|
Stat->HoldReasons |= SERIAL_RX_WAITING_FOR_DSR;
|
|
if (Extension->RXHolding & SERIAL_RX_XOFF)
|
|
Stat->HoldReasons |= SERIAL_TX_WAITING_XOFF_SENT;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = sizeof(SERIAL_STATUS);
|
|
|
|
break;
|
|
}
|
|
|
|
//*******************************
|
|
case IOCTL_SERIAL_GET_PROPERTIES:
|
|
{
|
|
PSERIAL_COMMPROP Properties;
|
|
|
|
MyKdPrint(D_Ioctl,("[Get Properties]\n"))
|
|
ExtTrace(Extension,D_Ioctl,"Get Properties");
|
|
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(SERIAL_COMMPROP))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
Properties=(PSERIAL_COMMPROP)Irp->AssociatedIrp.SystemBuffer;
|
|
RtlZeroMemory(Properties,sizeof(SERIAL_COMMPROP));
|
|
Properties->PacketLength = sizeof(SERIAL_COMMPROP);
|
|
Properties->PacketVersion = 2;
|
|
Properties->ServiceMask = SERIAL_SP_SERIALCOMM;
|
|
Properties->MaxTxQueue = 0;
|
|
Properties->MaxRxQueue = 0;
|
|
|
|
Properties->MaxBaud = SERIAL_BAUD_USER;
|
|
|
|
Properties->SettableBaud = 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 |
|
|
SERIAL_BAUD_56K |
|
|
SERIAL_BAUD_128K |
|
|
SERIAL_BAUD_115200 |
|
|
SERIAL_BAUD_57600 |
|
|
SERIAL_BAUD_USER;
|
|
|
|
Properties->ProvSubType = SERIAL_SP_RS232;
|
|
Properties->ProvCapabilities = 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_7 |
|
|
SERIAL_DATABITS_8;
|
|
|
|
Properties->SettableStopParity = SERIAL_STOPBITS_10 |
|
|
SERIAL_STOPBITS_20 |
|
|
SERIAL_PARITY_NONE |
|
|
SERIAL_PARITY_ODD |
|
|
SERIAL_PARITY_EVEN;
|
|
|
|
Properties->CurrentTxQueue = 0; // as per MS
|
|
|
|
// circular buffer req's -1
|
|
Properties->CurrentRxQueue = Extension->RxQ.QSize -1;
|
|
|
|
Irp->IoStatus.Information = sizeof(SERIAL_COMMPROP);
|
|
//Irp->IoStatus.Status = STATUS_SUCCESS; bogus, set at end
|
|
Status = STATUS_SUCCESS; // don't need
|
|
break;
|
|
}
|
|
|
|
//*****************************
|
|
case IOCTL_SERIAL_XOFF_COUNTER:
|
|
{
|
|
PSERIAL_XOFF_COUNTER Xc = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
MyKdPrint(D_Ioctl,("[Xoff Counter]\n"));
|
|
ExtTrace(Extension,D_Ioctl,"Xoff Counter");
|
|
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(SERIAL_XOFF_COUNTER))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
if (Xc->Counter <= 0)
|
|
{ Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
// write the 13H(don't play the xoff-counter game)
|
|
// which queues things up in the write queue. We may
|
|
// screw up the order of outgoing data if other writes
|
|
// pended, but thats life, and this xoff-counter nonsense
|
|
// sucks. Its used in the msdos 16450 uart emuluation on
|
|
// com1-com4.
|
|
#ifdef S_RK
|
|
sWriteTxBlk( Extension->ChP, (PUCHAR) &Xc->XoffChar, 1);
|
|
#else
|
|
q_put(&Extension->Port->QOut,(unsigned char *)&Xc->XoffChar,1);
|
|
#endif
|
|
Status = STATUS_SUCCESS;
|
|
|
|
break;
|
|
}
|
|
|
|
//******************************
|
|
case IOCTL_SERIAL_CONFIG_SIZE:
|
|
{
|
|
ExtTrace(Extension,D_Ioctl,"Config Size");
|
|
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(ULONG))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Information = sizeof(ULONG);
|
|
Status = STATUS_SUCCESS;
|
|
|
|
*(PULONG)Irp->AssociatedIrp.SystemBuffer = 0;
|
|
break;
|
|
}
|
|
|
|
//******************************
|
|
case IOCTL_SERIAL_GET_COMMCONFIG:
|
|
{
|
|
// this function is not defined or used in the sample driver.
|
|
ExtTrace(Extension,D_Ioctl,"Get Config");
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//******************************
|
|
case IOCTL_SERIAL_SET_COMMCONFIG:
|
|
{
|
|
// this function is not defined or used in the sample driver.
|
|
ExtTrace(Extension,D_Ioctl,"Set Config");
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//******************************
|
|
case IOCTL_SERIAL_LSRMST_INSERT:
|
|
{
|
|
PUCHAR escapeChar;
|
|
|
|
if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof (ULONG) )
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
escapeChar = Irp->AssociatedIrp.SystemBuffer;
|
|
};
|
|
|
|
ExtTrace1(Extension,D_Ioctl,"LSRMST Insert, Esc=%xH",
|
|
(ULONG) *escapeChar);
|
|
|
|
MyKdPrint(D_Ioctl,("[LSRMST Insert]\n"))
|
|
// this "feature" allows setting a escape character, which when
|
|
// non-zero will cause it to be used as an escape character for
|
|
// changes in MSR/LSR registers. If the Escape char is seen in
|
|
// from the port, it is escaped also. Oh what fun.
|
|
|
|
// used in Virtual driver of microsofts.
|
|
Extension->escapechar = *escapeChar;
|
|
#ifdef S_RK
|
|
if (Extension->escapechar != 0)
|
|
{sEnRxIntCompare2(Extension->ChP,Extension->escapechar);}
|
|
else
|
|
{sDisRxCompare2(Extension->ChP);}
|
|
#endif
|
|
// Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
#ifdef NT50
|
|
//******************************
|
|
case IOCTL_SERIAL_GET_MODEM_CONTROL:
|
|
{
|
|
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|
sizeof(ULONG)) {
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
Irp->IoStatus.Information = sizeof(ULONG);
|
|
|
|
//#define SERIAL_DTR_STATE ((ULONG)0x00000001)
|
|
//#define SERIAL_RTS_STATE ((ULONG)0x00000002)
|
|
|
|
//#define SERIAL_IOC_MCR_DTR ((ULONG)0x00000001)
|
|
//#define SERIAL_IOC_MCR_RTS ((ULONG)0x00000002)
|
|
//#define SERIAL_IOC_MCR_OUT1 ((ULONG)0x00000004)
|
|
//#define SERIAL_IOC_MCR_OUT2 ((ULONG)0x00000008)
|
|
//#define SERIAL_IOC_MCR_LOOP ((ULONG)0x00000010)
|
|
|
|
*((ULONG *)Irp->AssociatedIrp.SystemBuffer) =
|
|
(Extension->DTRRTSStatus & 3);
|
|
ExtTrace1(Extension,D_Ioctl,"get MCR:=%xH",
|
|
*((ULONG *)Irp->AssociatedIrp.SystemBuffer) );
|
|
}
|
|
break;
|
|
|
|
//******************************
|
|
case IOCTL_SERIAL_SET_MODEM_CONTROL:
|
|
{
|
|
ULONG mcr;
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(ULONG)) {
|
|
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
|
|
}
|
|
mcr = *((ULONG *)Irp->AssociatedIrp.SystemBuffer);
|
|
|
|
#ifdef S_VS
|
|
pDisRTSFlowCtl(Extension->Port);
|
|
#else
|
|
sDisRTSFlowCtl(Extension->ChP);
|
|
#endif
|
|
|
|
if (mcr & SERIAL_RTS_STATE)
|
|
{
|
|
#ifdef S_VS
|
|
pSetRTS(Extension->Port);
|
|
#else
|
|
sSetRTS(Extension->ChP);
|
|
#endif
|
|
Extension->DTRRTSStatus |= SERIAL_RTS_STATE;
|
|
}
|
|
else
|
|
{
|
|
#ifdef S_VS
|
|
pClrRTS(Extension->Port);
|
|
#else
|
|
sClrRTS(Extension->ChP);
|
|
#endif
|
|
Extension->DTRRTSStatus &= ~SERIAL_RTS_STATE;
|
|
}
|
|
|
|
if (mcr & SERIAL_DTR_STATE)
|
|
{
|
|
#ifdef S_VS
|
|
pSetDTR(Extension->Port);
|
|
#else
|
|
sSetDTR(Extension->ChP);
|
|
#endif
|
|
Extension->DTRRTSStatus |= SERIAL_DTR_STATE;
|
|
}
|
|
else
|
|
{
|
|
#ifdef S_VS
|
|
pClrDTR(Extension->Port);
|
|
#else
|
|
sClrDTR(Extension->ChP);
|
|
#endif
|
|
Extension->DTRRTSStatus &= ~SERIAL_DTR_STATE;
|
|
}
|
|
|
|
ExtTrace1(Extension,D_Ioctl,"set MCR:=%xH", mcr);
|
|
}
|
|
break;
|
|
|
|
//******************************
|
|
case IOCTL_SERIAL_SET_FIFO_CONTROL:
|
|
{
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
//******************************
|
|
case IOCTL_RCKT_CLR_STATS:
|
|
{
|
|
Tracer *tr;
|
|
PSERIAL_DEVICE_EXTENSION ComDevExt;
|
|
// PortStats *Stats;
|
|
|
|
MyKdPrint(D_Ioctl,("[Get Stats]\n"))
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(Tracer))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
MyKdPrint(D_Ioctl,("[Buffer too small]\n"))
|
|
break;
|
|
}
|
|
|
|
tr = (Tracer *)Irp->AssociatedIrp.SystemBuffer;
|
|
MyKdPrint(D_Ioctl,("Com_port: %s\n",tr->port_name))
|
|
ComDevExt = FindDevExt(tr->port_name);
|
|
if (ComDevExt == NULL)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
ComDevExt->OurStats.TransmittedCount = 0;
|
|
ComDevExt->OurStats.ReceivedCount = 0;
|
|
ComDevExt->OurStats.ParityErrorCount = 0;
|
|
ComDevExt->OurStats.FrameErrorCount = 0;
|
|
ComDevExt->OurStats.SerialOverrunErrorCount = 0;
|
|
ComDevExt->OurStats.BufferOverrunErrorCount = 0;
|
|
|
|
tr->status = 0;
|
|
Irp->IoStatus.Information = sizeof(Tracer);
|
|
Status = STATUS_SUCCESS;
|
|
|
|
break;
|
|
}
|
|
|
|
//******************************
|
|
case IOCTL_RCKT_SET_LOOPBACK_ON:
|
|
{
|
|
ExtTrace(Extension,D_Ioctl,"LoopBk On");
|
|
MyKdPrint(D_Ioctl,("[Set LoopBack On]"))
|
|
#ifdef S_VS
|
|
pEnLocalLoopback(Extension->Port);
|
|
#else
|
|
sEnLocalLoopback(Extension->ChP);
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
//******************************
|
|
case IOCTL_RCKT_SET_LOOPBACK_OFF:
|
|
{
|
|
ExtTrace(Extension,D_Ioctl,"LoopBk Off");
|
|
MyKdPrint(D_Ioctl,("[Set LoopBack Off]"))
|
|
#ifdef S_VS
|
|
pDisLocalLoopback(Extension->Port);
|
|
#else
|
|
sDisLocalLoopback(Extension->ChP);
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
//******************************
|
|
case IOCTL_RCKT_SET_TOGGLE_LOW:
|
|
{
|
|
ExtTrace(Extension,D_Ioctl,"Set 485 Low");
|
|
Extension->Option &= ~OPTION_RS485_HIGH_ACTIVE;
|
|
Extension->Option &= ~OPTION_RS485_SOFTWARE_TOGGLE;
|
|
Extension->Option |= OPTION_RS485_OVERRIDE;
|
|
// hardware reverse case
|
|
#ifdef S_VS
|
|
pEnRTSToggleLow(Extension->Port);
|
|
#else
|
|
sEnRTSToggle(Extension->ChP);
|
|
#endif
|
|
Extension->DTRRTSStatus |= SERIAL_RTS_STATE;
|
|
}
|
|
break;
|
|
|
|
case IOCTL_RCKT_CLEAR_TOGGLE_LOW:
|
|
{
|
|
ExtTrace(Extension,D_Ioctl,"Clear 485 Low");
|
|
Extension->Option &= ~OPTION_RS485_HIGH_ACTIVE;
|
|
Extension->Option &= ~OPTION_RS485_SOFTWARE_TOGGLE;
|
|
Extension->Option &= ~OPTION_RS485_OVERRIDE;
|
|
// hardware reverse case
|
|
#ifdef S_VS
|
|
pDisRTSToggle(Extension->Port);
|
|
pSetRTS(Extension->Port);
|
|
#else
|
|
sDisRTSToggle(Extension->ChP);
|
|
sSetRTS(Extension->ChP);
|
|
#endif
|
|
Extension->DTRRTSStatus |= SERIAL_RTS_STATE;
|
|
}
|
|
break;
|
|
|
|
//******************************
|
|
case IOCTL_RCKT_GET_STATS:
|
|
{
|
|
Tracer *tr;
|
|
PSERIAL_DEVICE_EXTENSION ComDevExt;
|
|
PortStats *Stats;
|
|
|
|
ExtTrace(Extension,D_Ioctl,"Get_Stats");
|
|
MyKdPrint(D_Ioctl,("[Get Stats]\n"));
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(Tracer))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
MyKdPrint(D_Ioctl,("[Buffer too small]\n"))
|
|
break;
|
|
}
|
|
|
|
tr = (Tracer *)Irp->AssociatedIrp.SystemBuffer;
|
|
MyKdPrint(D_Ioctl,("Com_port: %s\n",tr->port_name))
|
|
ComDevExt = FindDevExt(tr->port_name);
|
|
if (ComDevExt == NULL)
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
Stats = (PortStats *)tr->data;
|
|
|
|
if(ComDevExt->DeviceIsOpen)
|
|
{
|
|
#ifdef S_VS
|
|
Stats->transmitFifo = (LONG) (PortGetTxCnt(ComDevExt->Port));
|
|
Stats->receiveFifo = (LONG) (PortGetRxCnt(ComDevExt->Port));
|
|
#else
|
|
Stats->transmitFifo = (LONG) sGetTxCnt(ComDevExt->ChP);
|
|
Stats->receiveFifo = (LONG) sGetRxCnt(ComDevExt->ChP);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
Stats->transmitFifo = 0;
|
|
Stats->receiveFifo = 0;
|
|
}
|
|
|
|
Stats->transmitBytes = ComDevExt->OurStats.TransmittedCount;
|
|
Stats->receiveBytes = ComDevExt->OurStats.ReceivedCount;
|
|
Stats->parityErrors = ComDevExt->OurStats.ParityErrorCount;
|
|
Stats->framingErrors = ComDevExt->OurStats.FrameErrorCount;
|
|
Stats->overrunHardware = ComDevExt->OurStats.SerialOverrunErrorCount;
|
|
Stats->overrunSoftware = ComDevExt->OurStats.BufferOverrunErrorCount;
|
|
tr->status = 0;
|
|
|
|
Irp->IoStatus.Information = sizeof(Tracer);
|
|
Status = STATUS_SUCCESS;
|
|
|
|
break;
|
|
}
|
|
//******************************
|
|
case IOCTL_RCKT_ISR_CNT:
|
|
{
|
|
Tracer *tr;
|
|
Global_Track *Gt;
|
|
|
|
ExtTrace(Extension,D_Ioctl,"Isr_Cnt");
|
|
MyKdPrint(D_Ioctl,("[Get Stats]\n"))
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(Tracer))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
MyKdPrint(D_Ioctl,("[Buffer too small]\n"))
|
|
break;
|
|
}
|
|
|
|
tr = (Tracer *)Irp->AssociatedIrp.SystemBuffer;
|
|
tr->status = 0;
|
|
Gt = (Global_Track *)tr->data;
|
|
Gt->int_counter = Driver.PollCnt;
|
|
Gt->WriteDpc_counter = Driver.WriteDpcCnt;
|
|
Gt->Timer_counter = 0;
|
|
Gt->Poll_counter = Driver.PollCnt;
|
|
|
|
Irp->IoStatus.Information = sizeof(Tracer);
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
//******************************
|
|
case IOCTL_RCKT_CHECK:
|
|
{
|
|
Tracer *tr;
|
|
|
|
ExtTrace(Extension,D_Ioctl,"Rckt_Chk");
|
|
MyKdPrint(D_Ioctl,("[Check]\n"))
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(Tracer))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
MyKdPrint(D_Ioctl,("[Buffer too small]\n"))
|
|
break;
|
|
}
|
|
tr = (Tracer *)Irp->AssociatedIrp.SystemBuffer;
|
|
MyKdPrint(D_Ioctl,("Com_port: %s\n",tr->port_name))
|
|
tr->status = 0x5555;
|
|
Irp->IoStatus.Information = sizeof(Tracer);
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
//****************************** monitor
|
|
case IOCTL_RCKT_MONALL:
|
|
{
|
|
PSERIAL_DEVICE_EXTENSION extension;
|
|
PSERIAL_DEVICE_EXTENSION board_ext;
|
|
int Dev;
|
|
// int total_size;
|
|
PortMonBase *pmb;
|
|
PortMonNames *pmn;
|
|
PortMonStatus *pms;
|
|
char *buf;
|
|
MyKdPrint(D_Ioctl,("[MonAll..]"))
|
|
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof (PortMonBase) )
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
pmb = (PortMonBase *)Irp->AssociatedIrp.SystemBuffer;
|
|
};
|
|
|
|
switch (pmb->struct_type)
|
|
{
|
|
case 9: // old probe ioctl
|
|
Status = STATUS_SUCCESS; // don't need, default
|
|
break;
|
|
|
|
//***************
|
|
case 10: // name array [12] bytes
|
|
pmn = (PortMonNames *) &pmb[1]; // ptr to after first struct
|
|
if (pmb->struct_size != sizeof(PortMonNames))
|
|
{
|
|
MyKdPrint(D_Ioctl,("Err1L"))
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
(((NumPorts(NULL)+1) * sizeof(PortMonNames)) + sizeof(PortMonBase)) )
|
|
{
|
|
MyKdPrint(D_Ioctl,("Err4M, size:%d needed:%d\n",
|
|
IrpSp->Parameters.DeviceIoControl.InputBufferLength,
|
|
(((NumPorts(NULL)+1) * sizeof(PortMonNames)) + sizeof(PortMonBase))
|
|
))
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
Dev=0;
|
|
board_ext = Driver.board_ext;
|
|
while (board_ext)
|
|
{
|
|
extension = board_ext->port_ext;
|
|
while (extension)
|
|
{
|
|
strcpy(pmn->port_name, extension->SymbolicLinkName);
|
|
++pmn;
|
|
|
|
++Dev;
|
|
extension = extension->port_ext; // next in chain
|
|
} // while port extension
|
|
board_ext = board_ext->board_ext;
|
|
} // while port extension
|
|
pmb->num_structs = Dev;
|
|
pmn->port_name[0] = 0; // null terminate list.
|
|
Irp->IoStatus.Information = (sizeof(PortMonBase) +
|
|
sizeof(PortMonNames) *(Dev+1));
|
|
Status = STATUS_SUCCESS;
|
|
break; // case 10, names
|
|
|
|
//***************
|
|
case 11: // status array
|
|
pms = (PortMonStatus *) &pmb[1]; // ptr to after first struct
|
|
if (pmb->struct_size != sizeof(PortMonStatus))
|
|
{
|
|
MyKdPrint(D_Ioctl,("Err1M"))
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
((NumPorts(NULL) * sizeof(PortMonStatus)) + sizeof(PortMonBase)) )
|
|
{
|
|
MyKdPrint(D_Ioctl,("Err3M"))
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
Dev=0;
|
|
board_ext = Driver.board_ext;
|
|
while (board_ext)
|
|
{
|
|
extension = board_ext->port_ext;
|
|
while (extension)
|
|
{
|
|
pms->sent_bytes = extension->OurStats.TransmittedCount; // total number of sent bytes
|
|
pms->rec_bytes = extension->OurStats.ReceivedCount; // total number of receive bytes
|
|
|
|
pms->sent_packets = extension->sent_packets; // number of write() packets
|
|
pms->rec_packets = extension->rec_packets; // number of read() packets
|
|
|
|
pms->overrun_errors = (USHORT)(extension->OurStats.SerialOverrunErrorCount +
|
|
extension->OurStats.BufferOverrunErrorCount);
|
|
pms->framing_errors = (USHORT)(extension->OurStats.FrameErrorCount);
|
|
pms->parity_errors = (USHORT)(extension->OurStats.ParityErrorCount);
|
|
#ifdef S_VS
|
|
if (extension->Port != NULL)
|
|
pms->status_flags = // 20H, 10H, 8H
|
|
(extension->Port->msr_value & (CTS_ACT | DSR_ACT | CD_ACT)) |
|
|
// 1H, 2H
|
|
(WORD)(extension->DTRRTSStatus & (SERIAL_DTR_STATE | SERIAL_RTS_STATE));
|
|
#else
|
|
pms->status_flags = // 20H, 10H, 8H
|
|
(extension->ModemCtl & (CTS_ACT | DSR_ACT | CD_ACT)) |
|
|
// 1H, 2H
|
|
(WORD)(extension->DTRRTSStatus & (SERIAL_DTR_STATE | SERIAL_RTS_STATE));
|
|
#endif
|
|
if (extension->DeviceIsOpen)
|
|
pms->status_flags |= 0x100;
|
|
|
|
#ifdef COMMENT_OUT
|
|
if (sIsCTSFlowCtlEnabled(sIsComDevExt->ChP))
|
|
pms->status_flags |= 0x1000;
|
|
if (sIsRTSFlowCtlEnabled(sIsComDevExt->ChP))
|
|
pms->status_flags |= 0x2000;
|
|
if (sIsTxSoftFlowCtlEnabled(sIsComDevExt->ChP))
|
|
pms->status_flags |= 0x4000;
|
|
#endif
|
|
++pms;
|
|
++Dev;
|
|
extension = extension->port_ext; // next in chain
|
|
} // while port extension
|
|
board_ext = board_ext->board_ext; // next in chain
|
|
} // while board extension
|
|
|
|
Irp->IoStatus.Information = (sizeof(PortMonBase) +
|
|
sizeof(PortMonStatus)*Dev);
|
|
Status = STATUS_SUCCESS;
|
|
break; // case 11(status)
|
|
|
|
#ifdef COMMENT_OUT
|
|
//****************************** debug PCI
|
|
case 12: // debug in/out instructions
|
|
{
|
|
char *str;
|
|
int i,j,k;
|
|
// KIRQL newlevel, oldlevel;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
buf = (char *) &pmb[1]; // ptr to after first struct
|
|
// Eprintf("dump %s",buf);
|
|
str = buf;
|
|
while ((*str != 0) && (*str != ' '))
|
|
++str;
|
|
if (*str == ' ')
|
|
++str;
|
|
|
|
// newlevel = 2;
|
|
// KeRaiseIrql(newlevel, &oldlevel);
|
|
// KeLowerIrql(oldlevel);
|
|
+
|
|
if ((buf[0] == 'i') && (buf[1] == 'n'))
|
|
{
|
|
j = 0;
|
|
i = gethint(str, &j);
|
|
|
|
if (buf[2] == 'w')
|
|
{
|
|
str = (char *) i;
|
|
k = READ_PORT_USHORT((PUSHORT) str);
|
|
|
|
Sprintf(buf, "InW[%x] = %x\n",i, k);
|
|
}
|
|
else
|
|
{
|
|
str = (char *) i;
|
|
k = READ_PORT_UCHAR((PUCHAR) str);
|
|
// k = inp(i);
|
|
Sprintf(buf, "InB[%x] = %x\n",i, k);
|
|
}
|
|
|
|
}
|
|
else if ((buf[0] == 'o') && (buf[1] == 'u'))
|
|
{
|
|
j = 0;
|
|
i = gethint(str, &j);
|
|
k = gethint(&str[j], &j);
|
|
str = (char *) i;
|
|
buf[0] = 0;
|
|
if (buf[3] == 'd')
|
|
{
|
|
//sOutDW(i, k);
|
|
WRITE_PORT_ULONG((PULONG) str, (ULONG) k);
|
|
Sprintf(buf, "OutDW[%x] = %x\n",i, k);
|
|
}
|
|
else if (buf[3] == 'w')
|
|
{
|
|
//sOutW(i, k);
|
|
WRITE_PORT_USHORT((PUSHORT) str, (USHORT) k);
|
|
Sprintf(buf, "OutW[%x] = %x\n",i, k);
|
|
}
|
|
else
|
|
{
|
|
WRITE_PORT_UCHAR((PUCHAR) str, (UCHAR) k);
|
|
//sOutB(i, k);
|
|
Sprintf(buf, "OutB[%x] = %x\n",i, k);
|
|
}
|
|
// Eprintf("Out[%x] = %x\n",i, k);
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL; // return an error
|
|
strcpy(buf, "Bad ioctl");
|
|
Eprintf("bad io ioctl %s",buf);
|
|
}
|
|
|
|
Irp->IoStatus.Information = sizeof(PortMonBase) +
|
|
strlen(buf) + 1;
|
|
}
|
|
break; // case 12(in/out)
|
|
#endif
|
|
|
|
//*************** driver debug log
|
|
case 13: // driver debug log
|
|
{
|
|
char *str;
|
|
int i;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
// someone is actively running the debugger, so don't timeout
|
|
if (Driver.DebugTimeOut > 0) // used to timeout inactive debug sessions.
|
|
Driver.DebugTimeOut = 100; // about 600 second seconds timeout
|
|
|
|
buf = (char *) &pmb[1]; // ptr to after first struct
|
|
// Eprintf("dump %s",buf);
|
|
str = buf;
|
|
|
|
//----- limit incoming line buffer size
|
|
i = 0;
|
|
while ((*str != 0) && (i < 160))
|
|
{
|
|
++str;
|
|
++i;
|
|
}
|
|
*str = 0;
|
|
|
|
str = buf;
|
|
if (*str != 0)
|
|
do_cmd_line(str);
|
|
|
|
if (!q_empty(&Driver.DebugQ))
|
|
{
|
|
int q_cnt;
|
|
q_cnt = q_count(&Driver.DebugQ);
|
|
if (q_cnt > 1000)
|
|
q_cnt = 1000;
|
|
Irp->IoStatus.Information = sizeof(PortMonBase) + q_cnt;
|
|
pmb->struct_size = (ULONG) q_cnt;
|
|
buf = (char *) &pmb[1]; // ptr to after first struct
|
|
q_get(&Driver.DebugQ, (BYTE *) &pmb[1], q_cnt);
|
|
}
|
|
else
|
|
{
|
|
pmb->struct_size = (ULONG) 0;
|
|
Irp->IoStatus.Information = sizeof(PortMonBase);
|
|
}
|
|
}
|
|
break; // driver debug log
|
|
|
|
//*************** driver option set
|
|
case 14:
|
|
{
|
|
int stat;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
buf = (char *) &pmb[1]; // ptr to after first struct
|
|
MyKdPrint(D_Init, ("Ioctl Option:%s\n", buf))
|
|
stat = SetOptionStr(buf);
|
|
Sprintf(buf, "Option stat:%d\n",stat);
|
|
|
|
if (stat != 0)
|
|
{
|
|
MyKdPrint(D_Init, (" Err:%d\n", stat))
|
|
}
|
|
Irp->IoStatus.Information = sizeof(PortMonBase) +
|
|
strlen(buf) + 1;
|
|
}
|
|
break; // driver option set
|
|
|
|
#ifdef S_VS
|
|
//*************** mac-address list
|
|
case 15:
|
|
{
|
|
MyKdPrint(D_Ioctl,("start mac list\n"))
|
|
Status = STATUS_SUCCESS;
|
|
buf = (char *) &pmb[1]; // ptr to after first struct
|
|
buf[0] = 0;
|
|
|
|
MyKdPrint(D_Ioctl,("do find\n"))
|
|
find_all_boxes(0); // get list of all boxes out on networks
|
|
find_all_boxes(1); // do 2nd scan just to be sure
|
|
|
|
memcpy(buf, Driver.BoxMacs, 8*Driver.NumBoxMacs);
|
|
|
|
Irp->IoStatus.Information = sizeof(PortMonBase) +
|
|
8*Driver.NumBoxMacs;
|
|
MyKdPrint(D_Ioctl,("end mac list\n"))
|
|
}
|
|
break;
|
|
|
|
case 16: // advisor sheet: probe NIC status
|
|
MyKdPrint(D_Ioctl,("start nic probe"))
|
|
Irp->IoStatus.Information =
|
|
(ProbeNic((unsigned char *)&pmb[1],
|
|
(int)pmb->struct_size)) + sizeof(PortMonBase);
|
|
Status = STATUS_SUCCESS; // don't need, default
|
|
MyKdPrint(D_Ioctl,("end nic probe"))
|
|
break;
|
|
|
|
case 17: // advisor sheet: probe VS status
|
|
MyKdPrint(D_Ioctl,("start vs probe"))
|
|
Irp->IoStatus.Information =
|
|
(ProbeDevices((unsigned char *)&pmb[1],
|
|
(int)pmb->struct_size)) + sizeof(PortMonBase);
|
|
|
|
MyKdPrint(D_Ioctl,("end vs probe"))
|
|
Status = STATUS_SUCCESS; // don't need, default
|
|
break;
|
|
#endif
|
|
default:
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
} // switch
|
|
}
|
|
break;
|
|
|
|
//******************************
|
|
|
|
case IOCTL_RCKT_SET_MODEM_RESET:
|
|
{
|
|
char *ResetData;
|
|
PSERIAL_DEVICE_EXTENSION ext;
|
|
|
|
ExtTrace(Extension,D_Ioctl,"Set Modem Reset");
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof (char *) )
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
ResetData = (char *)Irp->AssociatedIrp.SystemBuffer;
|
|
MyKdPrint(D_Ioctl,("Set reset on Port: %s\n", ResetData))
|
|
ext = find_ext_by_name(ResetData, NULL);
|
|
if (ext)
|
|
ModemReset(ext, 1);
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
Status = STATUS_SUCCESS;
|
|
};
|
|
break;
|
|
}
|
|
|
|
case IOCTL_RCKT_CLEAR_MODEM_RESET:
|
|
{
|
|
char *ResetData;
|
|
PSERIAL_DEVICE_EXTENSION ext;
|
|
|
|
ExtTrace(Extension,D_Ioctl,"Clear Modem Reset");
|
|
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof (char *) )
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
ResetData = (char *)Irp->AssociatedIrp.SystemBuffer;
|
|
MyKdPrint(D_Ioctl,("Clear reset on Port: %s\n", ResetData))
|
|
ext = find_ext_by_name(ResetData, NULL);
|
|
if (ext)
|
|
ModemReset(ext, 0);
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
Status = STATUS_SUCCESS;
|
|
};
|
|
break;
|
|
}
|
|
|
|
case IOCTL_RCKT_SEND_MODEM_ROW:
|
|
{
|
|
char *ResetData;
|
|
PSERIAL_DEVICE_EXTENSION ext;
|
|
|
|
ExtTrace(Extension,D_Ioctl,"Send Modem ROW");
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof (char *) )
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
ResetData = (char *)Irp->AssociatedIrp.SystemBuffer;
|
|
MyKdPrint(D_Ioctl,("ROW write on Port: %s\n", ResetData))
|
|
ext = find_ext_by_name(ResetData, NULL);
|
|
if (ext)
|
|
ModemWriteROW(ext, Driver.MdmCountryCode);
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
Status = STATUS_SUCCESS;
|
|
};
|
|
break;
|
|
}
|
|
|
|
#ifdef S_RK
|
|
//******************************
|
|
// These are the old versions of
|
|
// the Reset/ROW ioctls and are
|
|
// provided here only for
|
|
// compatibility with RktReset
|
|
|
|
case IOCTL_RCKT_SET_MODEM_RESET_OLD:
|
|
{
|
|
int *ResetData;
|
|
int ChanNum;
|
|
int DevNum;
|
|
PSERIAL_DEVICE_EXTENSION ext;
|
|
|
|
ExtTrace(Extension,D_Ioctl,"Set Modem Reset");
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof (int *) )
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
ResetData = (int *)Irp->AssociatedIrp.SystemBuffer;
|
|
ChanNum = (*ResetData) & 0xFFFF;
|
|
DevNum = (*ResetData) >> 0x10;
|
|
MyKdPrint(D_Ioctl,("Set reset on Dev: %x, Chan: %x\n", DevNum, ChanNum))
|
|
ext = find_ext_by_index(DevNum, ChanNum);
|
|
if (ext)
|
|
sModemReset(ext->ChP, 1);
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
Status = STATUS_SUCCESS;
|
|
};
|
|
|
|
break;
|
|
}
|
|
|
|
case IOCTL_RCKT_CLEAR_MODEM_RESET_OLD:
|
|
{
|
|
int *ResetData;
|
|
int ChanNum;
|
|
int DevNum;
|
|
PSERIAL_DEVICE_EXTENSION ext;
|
|
|
|
ExtTrace(Extension,D_Ioctl,"Clear Modem Reset");
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof (int *) )
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
ResetData = (int *)Irp->AssociatedIrp.SystemBuffer;
|
|
ChanNum = (*ResetData) & 0xFFFF;
|
|
DevNum = (*ResetData) >> 0x10;
|
|
MyKdPrint(D_Ioctl,("Clear reset on Dev: %x, Chan: %x\n", DevNum, ChanNum))
|
|
ext = find_ext_by_index(DevNum, ChanNum);
|
|
if (ext)
|
|
sModemReset(ext->ChP, 0);
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
Status = STATUS_SUCCESS;
|
|
};
|
|
|
|
break;
|
|
}
|
|
|
|
case IOCTL_RCKT_GET_RCKTMDM_INFO_OLD:
|
|
{
|
|
// to maintain compatibility with RktReset, only the first
|
|
// four boards are reported and only the first eight ports
|
|
// on each are allowed.
|
|
RocketModemConfig *RMCfg;
|
|
int BoardNum;
|
|
int PortNum;
|
|
int np;
|
|
PSERIAL_DEVICE_EXTENSION ext_p; // port extension
|
|
PSERIAL_DEVICE_EXTENSION ext_b; // board extension
|
|
|
|
MyKdPrint(D_Ioctl, ("[Get RktMdm Cfg]\n"))
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof(RocketModemConfig))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
MyKdPrint(D_Ioctl, ("[Buffer too small]\n"))
|
|
break;
|
|
}
|
|
|
|
RMCfg = (RocketModemConfig *)Irp->AssociatedIrp.SystemBuffer;
|
|
RMCfg->rm_country_code = Driver.MdmCountryCode;
|
|
RMCfg->rm_settle_time = Driver.MdmSettleTime;
|
|
ext_b = Driver.board_ext;
|
|
BoardNum = 0;
|
|
while ((ext_b) && (BoardNum < 4) )
|
|
{
|
|
if (ext_b->config->ModemDevice) {
|
|
//np = ext_b->config->NumChan; [kpb, 5-7-98]
|
|
np = ext_b->config->NumPorts;
|
|
if (np > 8)
|
|
np = 8; // force to 8 since structure only has room for 8
|
|
RMCfg->rm_board_cfg[BoardNum].num_rktmdm_ports = np;
|
|
PortNum = 0;
|
|
ext_p = find_ext_by_index(BoardNum, PortNum);
|
|
while ( (ext_p) && (PortNum < np) )
|
|
{
|
|
if (ext_p)
|
|
strcpy(RMCfg->rm_board_cfg[BoardNum].port_names[PortNum],
|
|
ext_p->SymbolicLinkName);
|
|
else
|
|
strcpy(RMCfg->rm_board_cfg[BoardNum].port_names[PortNum], 0);
|
|
PortNum++;
|
|
ext_p = find_ext_by_index(BoardNum, PortNum);
|
|
}
|
|
}
|
|
ext_b = ext_b->board_ext;
|
|
BoardNum++;
|
|
}
|
|
Irp->IoStatus.Information = sizeof(RocketModemConfig);
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
case IOCTL_RCKT_SEND_MODEM_ROW_OLD:
|
|
{
|
|
int *ResetData;
|
|
int ChanNum;
|
|
int DevNum;
|
|
PSERIAL_DEVICE_EXTENSION ext;
|
|
|
|
ExtTrace(Extension,D_Ioctl,"Send Modem ROW");
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|
sizeof (int *) )
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
else
|
|
{
|
|
ResetData = (int *)Irp->AssociatedIrp.SystemBuffer;
|
|
ChanNum = (*ResetData) & 0xFFFF;
|
|
DevNum = (*ResetData) >> 0x10;
|
|
MyKdPrint(D_Ioctl,("ROW write on Dev: %x, Chan: %x\n", DevNum, ChanNum))
|
|
ext = find_ext_by_index(DevNum, ChanNum);
|
|
if (ext)
|
|
sModemWriteROW(ext->ChP, Driver.MdmCountryCode);
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
Status = STATUS_SUCCESS;
|
|
};
|
|
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
//******************************
|
|
default: // bad IOCTL request
|
|
{
|
|
MyKdPrint(D_Ioctl,("Err1O"))
|
|
ExtTrace1(Extension,D_Ioctl," UnHandle IoCtl:%d",
|
|
IrpSp->Parameters.DeviceIoControl.IoControlCode);
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
if (Status != STATUS_SUCCESS)
|
|
{
|
|
MyKdPrint(D_Ioctl, (" Bad Status:%xH on IOCTL:%xH",
|
|
Status, IrpSp->Parameters.DeviceIoControl.IoControlCode));
|
|
ExtTrace2(Extension, D_Ioctl, " Bad Status:%xH on IOCTL:%xH",
|
|
Status, IrpSp->Parameters.DeviceIoControl.IoControlCode);
|
|
switch (Status)
|
|
{
|
|
case STATUS_BUFFER_TOO_SMALL:
|
|
MyKdPrint(D_Ioctl,(" Err, Buf Too Small!"));
|
|
ExtTrace(Extension,D_Ioctl," Err, Buf Too Small!");
|
|
break;
|
|
case STATUS_INVALID_PARAMETER:
|
|
MyKdPrint(D_Ioctl,(" Err, Bad Parm!"));
|
|
ExtTrace(Extension,D_Ioctl," Err, Bad Parm!");
|
|
break;
|
|
default:
|
|
break;
|
|
|
|
}
|
|
}
|
|
SerialCompleteRequest(Extension, Irp, 0);
|
|
return Status;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
FindDevExt -
|
|
Purpose: To scan through my Dev objects and return a device object ext
|
|
Return: PSERIAL_DEVICE_EXTENSION
|
|
|--------------------------------------------------------------------------*/
|
|
PSERIAL_DEVICE_EXTENSION FindDevExt(IN PCHAR PortName)
|
|
{
|
|
PSERIAL_DEVICE_EXTENSION extension;
|
|
PSERIAL_DEVICE_EXTENSION board_ext;
|
|
int Dev;
|
|
char *pn;
|
|
char *dev_pn;
|
|
int done;
|
|
Dev =0;
|
|
board_ext = Driver.board_ext;
|
|
while (board_ext)
|
|
{
|
|
extension = board_ext->port_ext;
|
|
while (extension)
|
|
{
|
|
pn = PortName;
|
|
dev_pn = extension->SymbolicLinkName;
|
|
done = 0;
|
|
while ((*dev_pn != 0) && (*pn != 0) && (done == 0))
|
|
{
|
|
if (*dev_pn != *pn)
|
|
done = 1; // no match, try next
|
|
++dev_pn;
|
|
++pn;
|
|
}
|
|
if ((*dev_pn == 0) && (*pn == 0))
|
|
return (extension); // found it, return ext.
|
|
|
|
++Dev;
|
|
extension = extension->port_ext; // next in chain
|
|
} // while port extension
|
|
board_ext = board_ext->board_ext;
|
|
} // while board extension
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
ProgramBaudRate -
|
|
Purpose: Configure channel for desired baud rate
|
|
Return: STATUS_SUCCESS: if baud rate was configured
|
|
STATUS_INVALID_PARAMETER: if baud rate cannot be configured
|
|
|--------------------------------------------------------------------------*/
|
|
NTSTATUS
|
|
ProgramBaudRate(
|
|
IN PSERIAL_DEVICE_EXTENSION Extension,
|
|
IN ULONG DesiredBaudRate
|
|
)
|
|
{
|
|
ULONG InBaud = DesiredBaudRate;
|
|
|
|
//---- handle baud mapping
|
|
if (Extension->port_config->LockBaud != 0)
|
|
DesiredBaudRate = Extension->port_config->LockBaud;
|
|
|
|
MyKdPrint(D_Ioctl,("[DesiredBaud %d]",DesiredBaudRate))
|
|
if (DesiredBaudRate == 56000) DesiredBaudRate = 57600;
|
|
else if (DesiredBaudRate == 128000) DesiredBaudRate = 115200;
|
|
else if (DesiredBaudRate == 256000) DesiredBaudRate = 230400;
|
|
|
|
#ifdef S_VS
|
|
if(PortSetBaudRate(Extension->Port,DesiredBaudRate,FALSE,
|
|
Extension->board_ext->config->ClkRate,
|
|
Extension->board_ext->config->ClkPrescaler))
|
|
return(STATUS_INVALID_PARAMETER);
|
|
#else
|
|
if(sSetBaudRate(Extension->ChP,DesiredBaudRate,FALSE))
|
|
return(STATUS_INVALID_PARAMETER);
|
|
#endif
|
|
Extension->BaudRate = InBaud;
|
|
|
|
#ifdef S_VS
|
|
PortSetBaudRate(Extension->Port,DesiredBaudRate, TRUE,
|
|
Extension->board_ext->config->ClkRate,
|
|
Extension->board_ext->config->ClkPrescaler);
|
|
#else
|
|
sSetBaudRate(Extension->ChP,DesiredBaudRate,TRUE);
|
|
#endif
|
|
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------
|
|
ProgramLineControl
|
|
Purpose: Configure channels line control (data bits, stop bits, parity)
|
|
Return: STATUS_SUCCESS: if line control was programmed as desired
|
|
STATUS_INVALID_PARAMETER: if line control setting was invalid
|
|
|--------------------------------------------------------------------------*/
|
|
NTSTATUS
|
|
ProgramLineControl(
|
|
IN PSERIAL_DEVICE_EXTENSION Extension,
|
|
IN PSERIAL_LINE_CONTROL Lc
|
|
)
|
|
{
|
|
switch (Lc->WordLength)
|
|
{
|
|
case 7:
|
|
ExtTrace(Extension,D_Ioctl, "7-bits");
|
|
#ifdef S_VS
|
|
pSetData7(Extension->Port);
|
|
#else
|
|
sSetData7(Extension->ChP);
|
|
sSetRxMask(Extension->ChP,0x7f);
|
|
#endif
|
|
Extension->LineCtl.WordLength = Lc->WordLength;
|
|
break;
|
|
|
|
case 8:
|
|
ExtTrace(Extension,D_Ioctl, "8-bits");
|
|
#ifdef S_VS
|
|
pSetData8(Extension->Port);
|
|
#else
|
|
sSetData8(Extension->ChP);
|
|
sSetRxMask(Extension->ChP,0xff);
|
|
#endif
|
|
Extension->LineCtl.WordLength = Lc->WordLength;
|
|
break;
|
|
|
|
case 5:
|
|
ExtTrace(Extension,D_Ioctl, "Err WL5");
|
|
return(STATUS_INVALID_PARAMETER);
|
|
case 6:
|
|
ExtTrace(Extension,D_Ioctl, "Err WL6");
|
|
return(STATUS_INVALID_PARAMETER);
|
|
default:
|
|
ExtTrace(Extension,D_Ioctl, "Err WL?");
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
switch (Lc->Parity)
|
|
{
|
|
case NO_PARITY:
|
|
ExtTrace(Extension,D_Ioctl, "No-Par.");
|
|
#ifdef S_VS
|
|
pDisParity(Extension->Port);
|
|
#else
|
|
sDisParity(Extension->ChP);
|
|
#endif
|
|
Extension->LineCtl.Parity = Lc->Parity;
|
|
break;
|
|
|
|
case EVEN_PARITY:
|
|
ExtTrace(Extension,D_Ioctl, "Ev-Par.");
|
|
#ifdef S_VS
|
|
pSetEvenParity(Extension->Port);
|
|
#else
|
|
sEnParity(Extension->ChP);
|
|
sSetEvenParity(Extension->ChP);
|
|
#endif
|
|
Extension->LineCtl.Parity = Lc->Parity;
|
|
break;
|
|
|
|
case ODD_PARITY:
|
|
ExtTrace(Extension,D_Ioctl, "Odd-Par.");
|
|
#ifdef S_VS
|
|
pSetOddParity(Extension->Port);
|
|
#else
|
|
sEnParity(Extension->ChP);
|
|
sSetOddParity(Extension->ChP);
|
|
#endif
|
|
Extension->LineCtl.Parity = Lc->Parity;
|
|
break;
|
|
|
|
case MARK_PARITY:
|
|
ExtTrace(Extension,D_Ioctl, "Err PM");
|
|
return(STATUS_INVALID_PARAMETER);
|
|
case SPACE_PARITY:
|
|
ExtTrace(Extension,D_Ioctl, "Err PS");
|
|
return(STATUS_INVALID_PARAMETER);
|
|
default:
|
|
ExtTrace(Extension,D_Ioctl, "Err P?");
|
|
return(STATUS_INVALID_PARAMETER);
|
|
} // end switch parity...
|
|
|
|
switch (Lc->StopBits)
|
|
{
|
|
case STOP_BIT_1:
|
|
ExtTrace(Extension,D_Ioctl, "1-StopB");
|
|
#ifdef S_VS
|
|
pSetStop1(Extension->Port);
|
|
#else
|
|
sSetStop1(Extension->ChP);
|
|
#endif
|
|
Extension->LineCtl.StopBits = Lc->StopBits;
|
|
break;
|
|
|
|
case STOP_BITS_1_5:
|
|
ExtTrace(Extension,D_Ioctl, "Err S1.5");
|
|
return(STATUS_INVALID_PARAMETER);
|
|
|
|
case STOP_BITS_2:
|
|
if (Extension->port_config->Map2StopsTo1)
|
|
{
|
|
ExtTrace(Extension,D_Ioctl, "2to1-StopB");
|
|
#ifdef S_VS
|
|
pSetStop1(Extension->Port);
|
|
#else
|
|
sSetStop1(Extension->ChP);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
ExtTrace(Extension,D_Ioctl, "2-StopB");
|
|
#ifdef S_VS
|
|
pSetStop2(Extension->Port);
|
|
#else
|
|
sSetStop2(Extension->ChP);
|
|
#endif
|
|
}
|
|
Extension->LineCtl.StopBits = Lc->StopBits;
|
|
break;
|
|
}
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------
|
|
SerialSetHandFlow -
|
|
Note: This is somewhat redundant to ForceExtensionSettings() in openclos.c.
|
|
|-------------------------------------------------------------------*/
|
|
void SerialSetHandFlow(PSERIAL_DEVICE_EXTENSION Extension,
|
|
SERIAL_HANDFLOW *HandFlow)
|
|
{
|
|
//////////////////////////////////////////////
|
|
// All invalid parameters have been dealt with.
|
|
// Now, program the settings.
|
|
|
|
//////////////
|
|
// DTR control
|
|
|
|
if ((Extension->HandFlow.ControlHandShake & SERIAL_DTR_MASK) !=
|
|
(HandFlow->ControlHandShake & SERIAL_DTR_MASK))
|
|
{
|
|
Extension->RXHolding &= ~SERIAL_RX_DSR;
|
|
if ( (HandFlow->ControlHandShake & SERIAL_DTR_MASK) ==
|
|
SERIAL_DTR_CONTROL )
|
|
{
|
|
#ifdef S_VS
|
|
pSetDTR(Extension->Port);
|
|
#else
|
|
sSetDTR(Extension->ChP);
|
|
#endif
|
|
Extension->DTRRTSStatus |= SERIAL_DTR_STATE;
|
|
}
|
|
else if ( (HandFlow->ControlHandShake & SERIAL_DTR_MASK) ==
|
|
SERIAL_DTR_HANDSHAKE )
|
|
{
|
|
#ifdef S_VS
|
|
pEnDTRFlowCtl(Extension->Port);
|
|
Extension->DTRRTSStatus |= SERIAL_DTR_STATE;
|
|
#else
|
|
if( (sGetRxCnt(Extension->ChP) >= RX_HIWATER) ||
|
|
(!(Extension->DevStatus & COM_RXFLOW_ON))
|
|
)
|
|
{
|
|
// drop DTR
|
|
Extension->DevStatus &= ~COM_RXFLOW_ON;
|
|
sClrDTR(Extension->ChP);
|
|
Extension->DTRRTSStatus &= ~SERIAL_DTR_STATE;
|
|
Extension->RXHolding |= SERIAL_RX_DSR;
|
|
}
|
|
else
|
|
{
|
|
// DTR should be on
|
|
sSetDTR(Extension->ChP);
|
|
Extension->DTRRTSStatus |= SERIAL_DTR_STATE;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef S_VS
|
|
pClrDTR(Extension->Port);
|
|
#else
|
|
sClrDTR(Extension->ChP);
|
|
#endif
|
|
Extension->DTRRTSStatus &= ~SERIAL_DTR_STATE;
|
|
}
|
|
}
|
|
|
|
//////////////
|
|
// RTS control
|
|
|
|
if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) !=
|
|
(HandFlow->FlowReplace & SERIAL_RTS_MASK))
|
|
{
|
|
|
|
Extension->Option &= ~OPTION_RS485_SOFTWARE_TOGGLE;
|
|
#ifdef S_VS
|
|
pDisRTSFlowCtl(Extension->Port);
|
|
#else
|
|
sDisRTSFlowCtl(Extension->ChP); // add V2.8.001(2-19-96)
|
|
#endif
|
|
switch(HandFlow->FlowReplace & SERIAL_RTS_MASK)
|
|
{
|
|
case SERIAL_RTS_CONTROL: // RTS Should be asserted while open
|
|
#ifdef S_VS
|
|
pSetRTS(Extension->Port);
|
|
#else
|
|
sSetRTS(Extension->ChP);
|
|
#endif
|
|
Extension->DTRRTSStatus |= SERIAL_RTS_STATE;
|
|
break;
|
|
case SERIAL_RTS_HANDSHAKE: // RTS hardware input flow control
|
|
#ifdef S_VS
|
|
pEnRTSFlowCtl(Extension->Port);
|
|
#else
|
|
sEnRTSFlowCtl(Extension->ChP);
|
|
#endif
|
|
Extension->DTRRTSStatus |= SERIAL_RTS_STATE;
|
|
break;
|
|
case SERIAL_TRANSMIT_TOGGLE: // RTS transmit toggle enabled
|
|
|
|
if (Extension->Option & OPTION_RS485_HIGH_ACTIVE)
|
|
{ // normal case, emulate standard operation
|
|
Extension->Option |= OPTION_RS485_SOFTWARE_TOGGLE;
|
|
Extension->DTRRTSStatus &= ~SERIAL_RTS_STATE;
|
|
#ifdef S_VS
|
|
pEnRTSToggleHigh(Extension->Port);
|
|
#else
|
|
sClrRTS(Extension->ChP);
|
|
#endif
|
|
}
|
|
else
|
|
{ // hardware reverse case
|
|
#ifdef S_VS
|
|
pEnRTSToggleLow(Extension->Port);
|
|
#else
|
|
sEnRTSToggle(Extension->ChP);
|
|
#endif
|
|
Extension->DTRRTSStatus |= SERIAL_RTS_STATE;
|
|
}
|
|
break;
|
|
default:
|
|
#ifdef S_VS
|
|
pClrRTS(Extension->Port);
|
|
#else
|
|
sClrRTS(Extension->ChP);
|
|
#endif
|
|
Extension->DTRRTSStatus &= ~SERIAL_RTS_STATE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Extension->Option & OPTION_RS485_OVERRIDE) // 485 override
|
|
{
|
|
if (Extension->Option & OPTION_RS485_HIGH_ACTIVE)
|
|
{ // normal case, emulate standard operation
|
|
Extension->Option |= OPTION_RS485_SOFTWARE_TOGGLE;
|
|
Extension->DTRRTSStatus &= ~SERIAL_RTS_STATE;
|
|
#ifdef S_VS
|
|
pEnRTSToggleHigh(Extension->Port);
|
|
#else
|
|
sClrRTS(Extension->ChP);
|
|
#endif
|
|
}
|
|
else
|
|
{ // hardware reverse case
|
|
#ifdef S_VS
|
|
pEnRTSToggleLow(Extension->Port);
|
|
#else
|
|
sEnRTSToggle(Extension->ChP);
|
|
#endif
|
|
Extension->DTRRTSStatus |= SERIAL_RTS_STATE;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////
|
|
// Software output flow control
|
|
|
|
if ((Extension->HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT) !=
|
|
(HandFlow->FlowReplace & SERIAL_AUTO_TRANSMIT))
|
|
{
|
|
if (HandFlow->FlowReplace & SERIAL_AUTO_TRANSMIT)
|
|
{
|
|
#ifdef S_VS
|
|
pEnTxSoftFlowCtl(Extension->Port);
|
|
#else
|
|
sEnTxSoftFlowCtl(Extension->ChP);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef S_VS
|
|
pDisTxSoftFlowCtl(Extension->Port);
|
|
#else
|
|
if (Extension->TXHolding & ST_XOFF_FAKE)
|
|
{
|
|
Extension->TXHolding &= ~ST_XOFF_FAKE;
|
|
if ((Extension->TXHolding &
|
|
(SERIAL_TX_DCD | SERIAL_TX_DSR | ST_XOFF_FAKE)) == 0)
|
|
sEnTransmit(Extension->ChP); // Start up the transmitter
|
|
sDisRxCompare2(Extension->ChP);
|
|
}
|
|
sDisTxSoftFlowCtl(Extension->ChP);
|
|
sClrTxXOFF(Extension->ChP);
|
|
#endif
|
|
Extension->TXHolding &= ~SERIAL_TX_XOFF;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// SERIAL_AUTO_RECEIVE checked only because it may be necessary
|
|
// to send an XON if we were using s/w input flow control
|
|
|
|
// Did the setting change?
|
|
if ((Extension->HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE) !=
|
|
(HandFlow->FlowReplace & SERIAL_AUTO_RECEIVE))
|
|
{
|
|
#ifdef S_VS
|
|
if (HandFlow->FlowReplace & SERIAL_AUTO_RECEIVE)
|
|
{
|
|
pEnRxSoftFlowCtl(Extension->Port);
|
|
}
|
|
else
|
|
{
|
|
pDisRxSoftFlowCtl(Extension->Port);
|
|
}
|
|
#endif
|
|
// Are we turning AUTO_REC.. off?
|
|
if(!(HandFlow->FlowReplace & SERIAL_AUTO_RECEIVE))
|
|
{
|
|
// Is the remote flowed off?
|
|
if(!(Extension->DevStatus & COM_RXFLOW_ON))
|
|
{
|
|
// send XON
|
|
Extension->DevStatus |= COM_RXFLOW_ON;
|
|
#ifdef S_RK
|
|
sWriteTxPrioByte(Extension->ChP,
|
|
Extension->SpecialChars.XonChar);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////
|
|
// No need to program the Rocket for following:
|
|
// SERIAL_BREAK_CHAR
|
|
// Replace Break error (NULL) with SpecialChars.BreakChar
|
|
// SERIAL_ERROR_CHAR
|
|
// Replace Parity and Framing with SpecialChars.ErrorChar
|
|
|
|
///////////////////////////////////
|
|
// CTS hardware output flow control
|
|
|
|
if ((Extension->HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE) !=
|
|
(HandFlow->ControlHandShake & SERIAL_CTS_HANDSHAKE))
|
|
{
|
|
if (HandFlow->ControlHandShake & SERIAL_CTS_HANDSHAKE)
|
|
{
|
|
#ifdef S_VS
|
|
pEnCTSFlowCtl(Extension->Port);
|
|
#else
|
|
sEnCTSFlowCtl(Extension->ChP);
|
|
#endif
|
|
if (!(Extension->ModemStatus & SERIAL_CTS_STATE))
|
|
Extension->TXHolding |= SERIAL_TX_CTS; // clear holding
|
|
}
|
|
else
|
|
{
|
|
#ifdef S_VS
|
|
pDisCTSFlowCtl(Extension->Port);
|
|
#else
|
|
sDisCTSFlowCtl(Extension->ChP);
|
|
#endif
|
|
Extension->TXHolding &= ~SERIAL_TX_CTS; // clear holding
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////
|
|
// DSR hardware output flow control
|
|
#ifdef S_VS
|
|
if ((Extension->HandFlow.ControlHandShake & SERIAL_DSR_HANDSHAKE) !=
|
|
(HandFlow->ControlHandShake & SERIAL_DSR_HANDSHAKE))
|
|
{
|
|
if (HandFlow->ControlHandShake & SERIAL_DSR_HANDSHAKE)
|
|
{
|
|
pEnDSRFlowCtl(Extension->Port);
|
|
if (!(Extension->ModemStatus & SERIAL_DSR_STATE))
|
|
Extension->TXHolding |= SERIAL_TX_DSR;
|
|
}
|
|
else
|
|
{
|
|
pDisDSRFlowCtl(Extension->Port);
|
|
Extension->TXHolding &= ~SERIAL_TX_DSR;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef S_VS
|
|
///////////////////////////////////
|
|
// DCD hardware output flow control
|
|
|
|
if ((Extension->HandFlow.ControlHandShake & SERIAL_DCD_HANDSHAKE) !=
|
|
(HandFlow->ControlHandShake & SERIAL_DCD_HANDSHAKE))
|
|
{
|
|
if (HandFlow->ControlHandShake & SERIAL_DCD_HANDSHAKE)
|
|
{
|
|
pEnCDFlowCtl(Extension->Port);
|
|
if (!(Extension->ModemStatus & SERIAL_DCD_STATE))
|
|
Extension->TXHolding |= SERIAL_TX_DCD;
|
|
}
|
|
else
|
|
{
|
|
pDisCDFlowCtl(Extension->Port);
|
|
Extension->TXHolding &= ~SERIAL_TX_DCD;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/////////////////
|
|
// Null stripping
|
|
|
|
if (HandFlow->FlowReplace & SERIAL_NULL_STRIPPING)
|
|
{
|
|
#ifdef S_VS
|
|
pEnNullStrip(Extension->Port);
|
|
#else
|
|
sEnRxIgnore0(Extension->ChP,0);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef S_VS
|
|
pDisNullStrip(Extension->Port);
|
|
#else
|
|
sDisRxCompare0(Extension->ChP);
|
|
#endif
|
|
}
|
|
|
|
Extension->HandFlow.FlowReplace = HandFlow->FlowReplace;
|
|
Extension->HandFlow.ControlHandShake = HandFlow->ControlHandShake;
|
|
|
|
#ifdef S_RK
|
|
// update this because it handles flow-control and holding update
|
|
SetExtensionModemStatus(Extension);
|
|
#endif
|
|
}
|
|
|
|
#ifdef NT50
|
|
/*--------------------------------------------------------------------
|
|
SerialInternalIoControl -
|
|
|-------------------------------------------------------------------*/
|
|
NTSTATUS
|
|
SerialInternalIoControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
|
|
KIRQL OldIrql;
|
|
BOOLEAN acceptingIRPs;
|
|
|
|
acceptingIRPs = SerialIRPPrologue(Extension);
|
|
|
|
if (acceptingIRPs == FALSE) {
|
|
MyKdPrint(D_Ioctl,("Ioctl:no irps aceepted\n"))
|
|
Irp->IoStatus.Information = 0;
|
|
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
|
|
SerialCompleteRequest(Extension, Irp, IO_NO_INCREMENT);
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
Irp->IoStatus.Information = 0L;
|
|
|
|
MyKdPrint(D_Ioctl,("SerialIntIoControl: %x\n",
|
|
IrpSp->Parameters.DeviceIoControl.IoControlCode))
|
|
// Make sure we aren't aborting due to error (ERROR_ABORT)
|
|
|
|
if (Extension->ErrorWord)
|
|
{
|
|
if (Extension->DeviceType == DEV_PORT)
|
|
{
|
|
if (SerialCompleteIfError(DeviceObject, Irp) != STATUS_SUCCESS)
|
|
{
|
|
{ExtTrace(Extension,D_Ioctl,"ErrSet!");}
|
|
return STATUS_CANCELLED;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Extension->DeviceType == DEV_BOARD)
|
|
{
|
|
ExtTrace2 (Extension, D_Ioctl, " Bad Status:%xH on IIOCTL:%xH",
|
|
Status, IrpSp->Parameters.DeviceIoControl.IoControlCode);
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
SerialCompleteRequest (Extension, Irp, 0);
|
|
return Status;
|
|
};
|
|
|
|
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
|
|
{
|
|
#if 0
|
|
case IOCTL_SERIAL_INTERNAL_DO_WAIT_WAKE:
|
|
// Send a wait-wake IRP
|
|
Status = SerialSendWaitWake(Extension);
|
|
break;
|
|
|
|
case IOCTL_SERIAL_INTERNAL_CANCEL_WAIT_WAKE:
|
|
if (Extension->PendingWakeIrp != NULL) {
|
|
IoCancelIrp(Extension->PendingWakeIrp);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS:
|
|
case IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS:
|
|
{
|
|
SERIAL_BASIC_SETTINGS basic;
|
|
PSERIAL_BASIC_SETTINGS pBasic;
|
|
//SHORT AppropriateDivisor;
|
|
//SERIAL_IOCTL_SYNC S;
|
|
|
|
if (IrpSp->Parameters.DeviceIoControl.IoControlCode ==
|
|
IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS)
|
|
{
|
|
|
|
MyKdPrint(D_Ioctl,("[Set Internal Settings]\n"))
|
|
ExtTrace(Extension,D_Ioctl,"Set Int Settings");
|
|
|
|
// Check the buffer size
|
|
if (IrpSp->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));
|
|
|
|
Irp->IoStatus.Information = sizeof(SERIAL_BASIC_SETTINGS);
|
|
pBasic = (PSERIAL_BASIC_SETTINGS)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// Save off the old settings
|
|
//
|
|
|
|
RtlCopyMemory(&pBasic->Timeouts, &Extension->Timeouts,
|
|
sizeof(SERIAL_TIMEOUTS));
|
|
|
|
RtlCopyMemory(&pBasic->HandFlow, &Extension->HandFlow,
|
|
sizeof(SERIAL_HANDFLOW));
|
|
|
|
//
|
|
// Point to our new settings
|
|
//
|
|
|
|
pBasic = &basic;
|
|
}
|
|
else //restoring settings
|
|
{
|
|
MyKdPrint(D_Ioctl,("[Restore Internal Settings]\n"))
|
|
ExtTrace(Extension,D_Ioctl,"Reset Int Settings");
|
|
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength
|
|
< sizeof(SERIAL_BASIC_SETTINGS))
|
|
{
|
|
Status = STATUS_BUFFER_TOO_SMALL;
|
|
break;
|
|
}
|
|
|
|
pBasic = (PSERIAL_BASIC_SETTINGS)Irp->AssociatedIrp.SystemBuffer;
|
|
}
|
|
|
|
KeAcquireSpinLock(&Extension->ControlLock, &OldIrql);
|
|
|
|
//
|
|
// Set the timeouts
|
|
//
|
|
|
|
RtlCopyMemory(&Extension->Timeouts, &pBasic->Timeouts,
|
|
sizeof(SERIAL_TIMEOUTS));
|
|
|
|
//
|
|
// Set flowcontrol
|
|
//
|
|
|
|
//S.Extension = Extension;
|
|
//S.Data = &pBasic->HandFlow;
|
|
SerialSetHandFlow(Extension, &pBasic->HandFlow);
|
|
//KeSynchronizeExecution(Extension->Interrupt, SerialSetHandFlow, &S);
|
|
|
|
KeReleaseSpinLock(&Extension->ControlLock, OldIrql);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
if (Status != STATUS_SUCCESS)
|
|
{
|
|
ExtTrace2(Extension, D_Ioctl, " Bad Status:%xH on IIOCTL:%xH",
|
|
Status, IrpSp->Parameters.DeviceIoControl.IoControlCode);
|
|
}
|
|
SerialCompleteRequest(Extension, Irp, 0);
|
|
return Status;
|
|
}
|
|
#endif
|
|
|
|
#ifdef S_VS
|
|
#define RESET_STATS 1
|
|
|
|
/*--------------------------------------------------------------------
|
|
find_ext_mac_match
|
|
|-------------------------------------------------------------------*/
|
|
static PSERIAL_DEVICE_EXTENSION find_ext_mac_match(unsigned char *mac_addr)
|
|
{
|
|
PSERIAL_DEVICE_EXTENSION ext;
|
|
ext = Driver.board_ext;
|
|
while (ext != NULL)
|
|
{
|
|
if (mac_match(mac_addr, ext->hd->dest_addr))
|
|
{
|
|
//MyKdPrint(D_Ioctl,("Found ext:%x\n", ext))
|
|
return ext;
|
|
}
|
|
ext = ext->board_ext; // next one
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------
|
|
ProbeNic - determine status associated nic card.
|
|
|-------------------------------------------------------------------*/
|
|
static int ProbeNic(unsigned char *pPtr, int availableLength)
|
|
{
|
|
int nic_index;
|
|
int stat;
|
|
PROBE_NIC_STRUCT *pn;
|
|
Nic *nic;
|
|
int flag;
|
|
|
|
pn = (PROBE_NIC_STRUCT *) pPtr;
|
|
|
|
nic_index = (int) pPtr[0]; // they passed in an index to which nic card
|
|
flag = (int) pPtr[1]; // they passed in a flag too
|
|
|
|
stat = 0;
|
|
if (nic_index >= VS1000_MAX_NICS)
|
|
{
|
|
MyKdPrint(D_Error,("Err PD1F\n"))
|
|
stat = 1; // err
|
|
}
|
|
|
|
if (Driver.nics == NULL)
|
|
{
|
|
MyKdPrint(D_Error,("Err PD1G\n"))
|
|
stat = 2; // err
|
|
}
|
|
|
|
if (Driver.nics[nic_index].NICHandle == NULL)
|
|
{
|
|
MyKdPrint(D_Error,("Err PD1H\n"))
|
|
stat = 3; // err
|
|
}
|
|
if (stat != 0)
|
|
{
|
|
pn->struct_size = 0;
|
|
return sizeof(PROBE_NIC_STRUCT);
|
|
}
|
|
pn->struct_size = sizeof(PROBE_NIC_STRUCT);
|
|
|
|
nic = &Driver.nics[nic_index];
|
|
|
|
#if 0
|
|
if (flag & RESET_STATS) {
|
|
nic->pkt_sent = 0;
|
|
nic->pkt_rcvd_ours = 0;
|
|
nic->pkt_rcvd_not_ours = 0;
|
|
}
|
|
#endif
|
|
|
|
// copy over the data
|
|
memcpy(pn->NicName, nic->NicName, 60);
|
|
pn->NicName[59] = 0; // ensure null terminated
|
|
memcpy(pn->address, nic->address, 6);
|
|
pn->Open = nic->Open;
|
|
pn->pkt_sent = nic->pkt_sent;
|
|
pn->pkt_rcvd_ours = nic->pkt_rcvd_ours;
|
|
pn->pkt_rcvd_not_ours = nic->pkt_rcvd_not_ours;
|
|
|
|
return sizeof(PROBE_NIC_STRUCT);
|
|
}
|
|
|
|
/*--------------------------------------------------------------------
|
|
ProbeDevices - determine status associated with the hex MAC address at pPtr;
|
|
find associated Comtrol devices...
|
|
|-------------------------------------------------------------------*/
|
|
static int ProbeDevices(unsigned char *pPtr, int availableLength)
|
|
{
|
|
Nic *nic;
|
|
PortMan *pm;
|
|
Hdlc *hd;
|
|
unsigned char mac_address[6];
|
|
int flag;
|
|
int stat,i;
|
|
PSERIAL_DEVICE_EXTENSION ext;
|
|
PROBE_DEVICE_STRUCT *pr = (PROBE_DEVICE_STRUCT *) pPtr;
|
|
|
|
memcpy(mac_address,pPtr,sizeof(mac_address));
|
|
flag = pPtr[sizeof(mac_address)];
|
|
|
|
// find the active device with the matching address
|
|
ext = find_ext_mac_match(mac_address);
|
|
|
|
stat = 0;
|
|
if (ext == NULL)
|
|
{
|
|
MyKdPrint(D_Error,("No found mac:%x %x %x %x %x %x\n",
|
|
mac_address[0],mac_address[1],mac_address[2],
|
|
mac_address[3],mac_address[4],mac_address[5]))
|
|
stat = 1;
|
|
}
|
|
|
|
if (ext != NULL)
|
|
{
|
|
pm = ext->pm;
|
|
hd = ext->hd;
|
|
if ((pm == NULL) || (hd == NULL))
|
|
{
|
|
MyKdPrint(D_Error,("No pm or hd\n"))
|
|
stat = 2;
|
|
}
|
|
}
|
|
|
|
if (stat != 0)
|
|
{
|
|
pr->struct_size = 0;
|
|
MyKdPrint(D_Error,("ProbeErr1\n"))
|
|
return sizeof(PROBE_DEVICE_STRUCT);
|
|
}
|
|
|
|
pr->struct_size = sizeof(PROBE_DEVICE_STRUCT);
|
|
#if 0
|
|
if (flag & RESET_STATS) {
|
|
pm->good_loads = 0;
|
|
pm->total_loads = 0;
|
|
hd->iframes_sent = 0;
|
|
hd->ctlframes_sent = 0;
|
|
hd->rawframes_sent = 0;
|
|
hd->iframes_resent = 0;
|
|
hd->frames_rcvd = 0;
|
|
hd->iframes_outofseq = 0;
|
|
}
|
|
#endif
|
|
|
|
// give back a nic_index to use as a handle
|
|
pr->nic_index = 0; // default
|
|
for (i=0; i<VS1000_MAX_NICS; i++)
|
|
{
|
|
if ((hd->nic == &Driver.nics[i]) && (hd->nic != NULL))
|
|
pr->nic_index = i;
|
|
}
|
|
pr->num_ports = pm->num_ports;
|
|
pr->total_loads = pm->total_loads;
|
|
pr->good_loads = pm->good_loads;
|
|
pr->backup_server = pm->backup_server;
|
|
memcpy(pr->dest_addr, hd->dest_addr, 6);
|
|
pr->state = pm->state;
|
|
pr->iframes_sent = hd->iframes_sent;
|
|
pr->rawframes_sent = hd->rawframes_sent;
|
|
pr->ctlframes_sent = hd->ctlframes_sent;
|
|
pr->iframes_resent = hd->iframes_resent;
|
|
pr->iframes_outofseq = hd->iframes_outofseq;
|
|
pr->frames_rcvd = hd->frames_rcvd;
|
|
|
|
return sizeof(PROBE_DEVICE_STRUCT);
|
|
}
|
|
#endif
|
|
|