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.
1114 lines
35 KiB
1114 lines
35 KiB
/*-------------------------------------------------------------------
|
|
| openclos.c - RocketPort/VS1000 driver Open & Close code.
|
|
|
|
12-6-00 add code to force modem status update on open.
|
|
5-13-99 - enable RTS toggling for VS
|
|
2-15-99 - clear any xoff tx state on port-open for VS.
|
|
2-09-99 - initialize RocketPort & VS modemstatus variables used
|
|
to detect and generate modem status change event callbacks.
|
|
Spurious initial events could be generated previously. kpb
|
|
9-24-98 add RING emulation, adjust VS port-close to wait on tx-data,
|
|
start using user-configured tx-data port-close wait timeout option.
|
|
6-13-97 allow multiple instances of opening monitor port.
|
|
5-27-96 minor corrections in ForceExtensionSettings - RTS setup
|
|
replaced this with code from ioctl(previous last case was clearing
|
|
SERIAL_RTS_STATE when shouldn't have. NULL_STRIPPING setup,
|
|
this was using RxCompare1 register, ioctl code using 0 so
|
|
changed to match. kpb.
|
|
|
|
4-16-96 add sDisLocalLoopback() to open() routine - kpb
|
|
|
|
Copyright 1993-97 Comtrol Corporation. All rights reserved.
|
|
|--------------------------------------------------------------------*/
|
|
#include "precomp.h"
|
|
|
|
|
|
static LARGE_INTEGER SerialGetCharTime(IN PSERIAL_DEVICE_EXTENSION Extension);
|
|
|
|
/******************************************************************************
|
|
Function : SerialCreateOpen
|
|
Purpose: Open a device.
|
|
Call: SerialCreateOpen(DeviceObject,Irp)
|
|
PDEVICE_OBJECT DeviceObject: Pointer to the Device Object
|
|
PIRP Irp: Pointer to the I/O Request Packet
|
|
Return: STATUS_SUCCESS: if successful
|
|
STATUS_DEVICE_ALREADY_ATTACHED: if device is already open
|
|
STATUS_NOT_A_DIRECTORY : if someone thinks this is a file!
|
|
STATUS_INSUFFICIENT_RESOURCES : if Tx or Rx buffer couldn't be
|
|
allocated from memory
|
|
Comments: This function is the device driver OPEN entry point
|
|
******************************************************************************/
|
|
NTSTATUS
|
|
SerialCreateOpen(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
|
|
BOOLEAN acceptingIRPs;
|
|
|
|
|
|
ExtTrace(extension,D_Ioctl,("Open Port"));
|
|
|
|
acceptingIRPs = SerialIRPPrologue(extension);
|
|
|
|
if (acceptingIRPs == FALSE) {
|
|
// || (extension->PNPState != SERIAL_PNP_STARTED)) {
|
|
MyKdPrint(D_Init,("NotAccIrps\n"))
|
|
Irp->IoStatus.Information = 0;
|
|
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
|
|
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
// object for special ioctls
|
|
if (extension->DeviceType != DEV_PORT)
|
|
{
|
|
MyKdPrint(D_Init,("Open Driver\n"))
|
|
//MyKdPrint(D_Init,("Driver IrpCnt:%d\n",extension->PendingIRPCnt))
|
|
// Hardware is ready, indicate that the device is open
|
|
//extension->DeviceIsOpen=TRUE;
|
|
++extension->DeviceIsOpen; // more than one can open
|
|
// If it is the rocketsys dev object return don't set up serial port
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information=0L;
|
|
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// Check for the device already being open
|
|
if (extension->DeviceIsOpen)
|
|
{
|
|
Irp->IoStatus.Status = STATUS_DEVICE_ALREADY_ATTACHED;
|
|
Irp->IoStatus.Information = 0;
|
|
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_DEVICE_ALREADY_ATTACHED;
|
|
}
|
|
|
|
// Make sure they aren't trying to create a directory.
|
|
if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Create.Options &
|
|
FILE_DIRECTORY_FILE)
|
|
{
|
|
Irp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
|
|
Irp->IoStatus.Information = 0;
|
|
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
return STATUS_NOT_A_DIRECTORY;
|
|
}
|
|
|
|
// Create a system side buffer for the RX data.
|
|
|
|
extension->RxQ.QSize = 4096 + 1;
|
|
extension->RxQ.QBase= our_locked_alloc(extension->RxQ.QSize, "exRX");
|
|
|
|
// Check that Rx buffer allocation was succesful
|
|
if (!extension->RxQ.QBase)
|
|
{ extension->RxQ.QSize = 0;
|
|
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
Irp->IoStatus.Information = 0;
|
|
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
extension->RxQ.QPut = extension->RxQ.QGet = 0;
|
|
|
|
#ifdef TXBUFFER
|
|
// Create a system side buffer for the TX data.
|
|
extension->TxBufSize = 4096;
|
|
extension->TxBuf= our_locked_alloc(extension->TxBufSize, "exTX");
|
|
|
|
// Check that Tx buffer allocation was succesful
|
|
if (!extension->TxBuf)
|
|
{ extension->TxBufSize = 0;
|
|
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
Irp->IoStatus.Information = 0;
|
|
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// Buffer allocation was successful
|
|
// Set up the indexes for our buffers
|
|
extension->TxIn = extension->TxOut = 0;
|
|
#endif //TXBUFFER
|
|
|
|
//------ reset our performance 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;
|
|
|
|
// Must start with a clear HistoryMask
|
|
extension->HistoryMask = 0;
|
|
extension->WaitIsISRs = 0;
|
|
extension->IrpMaskLocation = &extension->DummyIrpMaskLoc;
|
|
extension->IsrWaitMask = 0;
|
|
|
|
// Must start with a clear ErrorWord
|
|
extension->ErrorWord = 0;
|
|
|
|
extension->RXHolding = 0;
|
|
extension->TXHolding = 0;
|
|
#ifdef S_VS
|
|
if (extension->Port == NULL)
|
|
{
|
|
MyKdPrint(D_Error,("FATAL Err5F\n"))
|
|
KdBreakPoint();
|
|
}
|
|
pDisLocalLoopback(extension->Port);
|
|
PortFlushTx(extension->Port); // flush tx hardware
|
|
PortFlushRx(extension->Port); // flush tx hardware
|
|
// Clear any software flow control states
|
|
#ifdef DO_LATER
|
|
//sClrTxXOFF(extension->ChP);
|
|
#endif
|
|
#else
|
|
// Set pointers to the Rocket's info
|
|
extension->ChP = &extension->ch;
|
|
sDisLocalLoopback(extension->ChP);
|
|
sFlushRxFIFO(extension->ChP);
|
|
sFlushTxFIFO(extension->ChP);
|
|
// Clear any software flow control states
|
|
sClrTxXOFF(extension->ChP);
|
|
// Clear any pending errors
|
|
if(sGetChanStatus(extension->ChP) & STATMODE)
|
|
{ // Take channel out of statmode if necessary
|
|
sDisRxStatusMode(extension->ChP);
|
|
}
|
|
// Clear any pending modem changes
|
|
sGetChanIntID(extension->ChP);
|
|
#endif
|
|
|
|
extension->escapechar = 0; // virtual NT port uses this
|
|
|
|
// Set Status to indicate no flow control
|
|
extension->DevStatus = COM_RXFLOW_ON;
|
|
|
|
// Clear any holding states
|
|
extension->TXHolding = 0;
|
|
|
|
// Start with 0 chars queued
|
|
extension->TotalCharsQueued = 0;
|
|
|
|
// Force settings as specified in the extension
|
|
// Line settings and flow control settings "stick" between close and open
|
|
ForceExtensionSettings(extension);
|
|
|
|
|
|
#ifdef S_VS
|
|
|
|
//force an update of modem status to get current status from
|
|
// hub.
|
|
extension->Port->old_msr_value = ! extension->Port->msr_value;
|
|
|
|
#else
|
|
|
|
// fix, used to detect change and trip callbacks for rocketport.
|
|
extension->EventModemStatus = extension->ModemStatus;
|
|
SetExtensionModemStatus(extension);
|
|
|
|
// Enable Rx, Tx and interrupts for the channel
|
|
sEnRxFIFO(extension->ChP); // Enable Rx
|
|
sEnTransmit(extension->ChP); // Enable Tx
|
|
sSetRxTrigger(extension->ChP,TRIG_1); // always trigger
|
|
sEnInterrupts(extension->ChP, extension->IntEnables);// allow interrupts
|
|
#endif
|
|
|
|
extension->ISR_Flags = 0;
|
|
|
|
// Make sure we don't have a stale value in this var
|
|
extension->WriteLength = 0;
|
|
|
|
// Hardware is ready, indicate that the device is open
|
|
extension->DeviceIsOpen=TRUE;
|
|
|
|
// check if we should set RS485 override option
|
|
if (extension->port_config->RS485Override)
|
|
extension->Option |= OPTION_RS485_OVERRIDE;
|
|
else extension->Option &= ~OPTION_RS485_OVERRIDE;
|
|
|
|
if (!extension->port_config->RS485Low)
|
|
extension->Option |= OPTION_RS485_HIGH_ACTIVE;
|
|
else extension->Option &= ~OPTION_RS485_HIGH_ACTIVE;
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
// Finish the Irp
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information=0L;
|
|
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/******************************************************************************
|
|
Function : SerialClose
|
|
Purpose: Close a device.
|
|
Call: SerialClose(DeviceObject,Irp)
|
|
PDEVICE_OBJECT DeviceObject: Pointer to the Device Object
|
|
PIRP Irp: Pointer to the I/O Request Packet
|
|
Return: STATUS_SUCCESS: always
|
|
Comments: This function is the device driver CLOSE entry point
|
|
******************************************************************************/
|
|
NTSTATUS
|
|
SerialClose(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
LARGE_INTEGER charTime; // 100 ns ticks per char, related to baud rate
|
|
PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
|
|
LARGE_INTEGER WaitTime; // Actual time req'd for buffer to drain
|
|
ULONG check_cnt, nochg_cnt;
|
|
ULONG last_tx_count;
|
|
ULONG tx_count;
|
|
BOOLEAN acceptingIRPs;
|
|
ULONG time_to_stall;
|
|
|
|
acceptingIRPs = SerialIRPPrologue(extension);
|
|
|
|
if (acceptingIRPs == FALSE) {
|
|
MyKdPrint(D_Init,("NotAccIrps Close\n"))
|
|
Irp->IoStatus.Information = 0;
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// object for special ioctls
|
|
if (extension->DeviceType != DEV_PORT)
|
|
{
|
|
MyKdPrint(D_Init,("Close Driver\n"))
|
|
//MyKdPrint(D_Init,("Driver IrpCnt:%d\n",extension->PendingIRPCnt))
|
|
// Hardware is ready, indicate that the device is open
|
|
--extension->DeviceIsOpen;
|
|
// If it is the rocketsys dev object return don't set up serial port
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information=0L;
|
|
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
ExtTrace(extension,D_Ioctl,("Close"))
|
|
// Calculate 100ns ticks to delay for each character
|
|
// Negate for call to KeDelay...
|
|
charTime = RtlLargeIntegerNegate(SerialGetCharTime(extension));
|
|
|
|
#ifdef TXBUFFER
|
|
// Wait until ISR has pulled all data out of system side TxBuf
|
|
while (extension->TxIn != extension->TxOut)
|
|
{ // Determine how many characters are actually in TxBuf
|
|
TxCount= (extension->TxIn - extension->TxOut);
|
|
if (TxCount < 0L)
|
|
TxCount+=extension->TxBufSize;
|
|
WaitTime= RtlExtendedIntegerMultiply(charTime,TxCount);
|
|
KeDelayExecutionThread(KernelMode,FALSE,&WaitTime);
|
|
}
|
|
#endif //TXBUFFER
|
|
|
|
|
|
// Send an XON if Tx is suspend by IS_FLOW
|
|
// send now so we are sure that it gets out of the port before shutdown
|
|
if (extension->HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE)
|
|
{
|
|
if(!(extension->DevStatus & COM_RXFLOW_ON))
|
|
{
|
|
#ifdef S_RK
|
|
sWriteTxPrioByte(extension->ChP,extension->SpecialChars.XonChar);
|
|
extension->DevStatus |= COM_RXFLOW_ON;
|
|
#endif
|
|
extension->RXHolding &= ~SERIAL_RX_XOFF;
|
|
}
|
|
}
|
|
|
|
//----- wait for Tx data to finish spooling out
|
|
// If tx-data still in transmit buffers, then stall close for
|
|
// the configured amount of time waiting for data to spool out.
|
|
// If no data movement is seen, we timeout after TxCloseTime.
|
|
// If data movement is seen, wait and timeout after (TxCloseTime*3).
|
|
|
|
time_to_stall = extension->port_config->TxCloseTime;
|
|
if (time_to_stall <= 0)
|
|
time_to_stall = 1; // use 1-sec if set to 0
|
|
if (time_to_stall > 240) // 4-minute max
|
|
time_to_stall = 240;
|
|
|
|
time_to_stall *= 10; // change from seconds to 100ms(1/10th sec) units
|
|
|
|
#ifdef S_RK
|
|
tx_count = extension->TotalCharsQueued + sGetTxCnt(extension->ChP);
|
|
if ((sGetChanStatusLo(extension->ChP) & DRAINED) != DRAINED)
|
|
++tx_count;
|
|
#else
|
|
tx_count = extension->TotalCharsQueued +
|
|
PortGetTxCntRemote(extension->Port) +
|
|
PortGetTxCnt(extension->Port);
|
|
#endif
|
|
last_tx_count = tx_count;
|
|
|
|
if (tx_count != 0)
|
|
{
|
|
ExtTrace(extension,D_Ioctl,("Tx Stall"));
|
|
}
|
|
|
|
// wait for Tx data to finish spooling out
|
|
check_cnt = 0;
|
|
nochg_cnt = 0;
|
|
while ( (tx_count != 0) && (check_cnt < (time_to_stall*2)) )
|
|
{
|
|
// set wait-time to .1 second.(-1000 000 = relative(-), 100-ns units)
|
|
WaitTime = RtlConvertLongToLargeInteger(-1000000L);
|
|
KeDelayExecutionThread(KernelMode,FALSE,&WaitTime);
|
|
|
|
if (tx_count != last_tx_count)
|
|
{
|
|
tx_count = last_tx_count;
|
|
nochg_cnt = 0;
|
|
}
|
|
else
|
|
{
|
|
++nochg_cnt;
|
|
if (nochg_cnt > (time_to_stall)) // no draining occuring!
|
|
break; // bail out of while loop
|
|
}
|
|
++check_cnt;
|
|
#ifdef S_RK
|
|
tx_count = extension->TotalCharsQueued + sGetTxCnt(extension->ChP);
|
|
if ((sGetChanStatusLo(extension->ChP) & DRAINED) != DRAINED)
|
|
++tx_count;
|
|
#else
|
|
tx_count = extension->TotalCharsQueued +
|
|
PortGetTxCntRemote(extension->Port) +
|
|
PortGetTxCnt(extension->Port);
|
|
#endif
|
|
} // while tx_count
|
|
|
|
if (tx_count != 0)
|
|
{
|
|
ExtTrace(extension,D_Ioctl,("Tx Dropped!"));
|
|
}
|
|
|
|
#ifdef COMMENT_OUT
|
|
// Calculate total chars and time, then wait.
|
|
WaitTime= RtlExtendedIntegerMultiply(charTime,sGetTxCnt(extension->ChP));
|
|
KeDelayExecutionThread(KernelMode,FALSE,&WaitTime);
|
|
#endif
|
|
|
|
#ifdef S_RK
|
|
// Tx Data is drained, shut down the port
|
|
sDisInterrupts(extension->ChP, extension->IntEnables);
|
|
|
|
// Disable all Tx and Rx functions
|
|
sDisTransmit(extension->ChP);
|
|
sDisRxFIFO(extension->ChP);
|
|
sDisRTSFlowCtl(extension->ChP);
|
|
sDisCTSFlowCtl(extension->ChP);
|
|
sDisRTSToggle(extension->ChP);
|
|
sClrBreak(extension->ChP);
|
|
|
|
// Drop the modem outputs
|
|
// Takes care of DTR flow control as well
|
|
sClrRTS(extension->ChP);
|
|
sClrDTR(extension->ChP);
|
|
#else
|
|
// add this, 2-9-99, kpb, CNC xon/xoff problems...
|
|
PortFlushRx(extension->Port); // flush rx hardware
|
|
PortFlushTx(extension->Port); // flush tx hardware
|
|
pClrBreak(extension->Port);
|
|
pDisDTRFlowCtl(extension->Port);
|
|
pDisRTSFlowCtl(extension->Port);
|
|
pDisCTSFlowCtl(extension->Port);
|
|
pDisRTSToggle(extension->Port);
|
|
pDisDSRFlowCtl(extension->Port);
|
|
pDisCDFlowCtl(extension->Port);
|
|
pDisTxSoftFlowCtl(extension->Port);
|
|
pDisRxSoftFlowCtl(extension->Port);
|
|
pDisNullStrip(extension->Port);
|
|
pClrRTS(extension->Port);
|
|
pClrDTR(extension->Port);
|
|
#endif
|
|
|
|
//extension->ModemCtl &= ~(CTS_ACT | DSR_ACT | CD_ACT);
|
|
extension->DTRRTSStatus &= ~(SERIAL_DTR_STATE | SERIAL_RTS_STATE);
|
|
|
|
#ifdef TXBUFFER
|
|
// Release the memory being used for this device's buffers...
|
|
extension->TxBufSize = 0;
|
|
our_free(extension->TxBuf,"exTX");
|
|
extension->TxBuf = NULL;
|
|
#endif //TXBUFFER
|
|
|
|
extension->DeviceIsOpen = FALSE;
|
|
extension->RxQ.QSize = 0;
|
|
our_free(extension->RxQ.QBase,"exRx");
|
|
extension->RxQ.QBase = NULL;
|
|
|
|
// Finish the Irp
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = 0L;
|
|
|
|
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Routine Description:
|
|
This function is used to kill all longstanding IO operations.
|
|
Arguments:
|
|
DeviceObject - Pointer to the device object for this device
|
|
Irp - Pointer to the IRP for the current request
|
|
Return Value:
|
|
The function value is the final status of the call
|
|
****************************************************************************/
|
|
NTSTATUS
|
|
SerialCleanup(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
{
|
|
PSERIAL_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
|
|
KIRQL oldIrql;
|
|
BOOLEAN acceptingIRPs;
|
|
|
|
MyKdPrint(D_Init,("SerialCleanup\n"))
|
|
|
|
acceptingIRPs = SerialIRPPrologue(extension);
|
|
|
|
if (acceptingIRPs == FALSE) {
|
|
Irp->IoStatus.Information = 0;
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
if (extension->DeviceType != DEV_PORT)
|
|
{
|
|
MyKdPrint(D_Init,("Driver IrpCnt:%d\n",extension->PendingIRPCnt))
|
|
}
|
|
#if DBG
|
|
if (extension->CurrentWriteIrp)
|
|
{
|
|
MyKdPrint(D_Error,("CleanUp WriteQ\n"))
|
|
}
|
|
if (extension->CurrentReadIrp)
|
|
{
|
|
MyKdPrint(D_Error,("CleanUp ReadQ\n"))
|
|
}
|
|
if (extension->CurrentPurgeIrp)
|
|
{
|
|
MyKdPrint(D_Error,("CleanUp PurgeQ\n"))
|
|
}
|
|
if (extension->CurrentWaitIrp)
|
|
{
|
|
MyKdPrint(D_Error,("CleanUp WaitQ\n"))
|
|
}
|
|
#endif
|
|
|
|
ExtTrace(extension,D_Ioctl,("SerialCleanup"));
|
|
|
|
// First kill all the reads and writes.
|
|
SerialKillAllReadsOrWrites(
|
|
DeviceObject,
|
|
&extension->WriteQueue,
|
|
&extension->CurrentWriteIrp
|
|
);
|
|
|
|
SerialKillAllReadsOrWrites(
|
|
DeviceObject,
|
|
&extension->ReadQueue,
|
|
&extension->CurrentReadIrp
|
|
);
|
|
|
|
// Next get rid of purges.
|
|
SerialKillAllReadsOrWrites(
|
|
DeviceObject,
|
|
&extension->PurgeQueue,
|
|
&extension->CurrentPurgeIrp
|
|
);
|
|
|
|
// Get rid of any mask operations.
|
|
//SerialKillAllReadsOrWrites(
|
|
// DeviceObject,
|
|
// &extension->MaskQueue,
|
|
// &extension->CurrentMaskIrp
|
|
// );
|
|
|
|
if (extension->DeviceType != DEV_PORT)
|
|
{
|
|
MyKdPrint(D_Init,("Driver IrpCnt:%d\n",extension->PendingIRPCnt))
|
|
}
|
|
// Now get rid of any pending wait mask irp.
|
|
IoAcquireCancelSpinLock(&oldIrql);
|
|
if (extension->CurrentWaitIrp) {
|
|
PDRIVER_CANCEL cancelRoutine;
|
|
cancelRoutine = extension->CurrentWaitIrp->CancelRoutine;
|
|
extension->CurrentWaitIrp->Cancel = TRUE;
|
|
if (cancelRoutine)
|
|
{ extension->CurrentWaitIrp->CancelIrql = oldIrql;
|
|
extension->CurrentWaitIrp->CancelRoutine = NULL;
|
|
cancelRoutine( DeviceObject, extension->CurrentWaitIrp );
|
|
}
|
|
}
|
|
else
|
|
{ IoReleaseCancelSpinLock(oldIrql);
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information=0L;
|
|
|
|
SerialCompleteRequest(extension, Irp, IO_NO_INCREMENT);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
Routine: SerialGetCharTime
|
|
This function will return the number of 100 nanosecond intervals
|
|
there are in one character time (based on the present form
|
|
of flow control.
|
|
Return Value:
|
|
100 nanosecond intervals in a character time.
|
|
*************************************************************************/
|
|
LARGE_INTEGER SerialGetCharTime(IN PSERIAL_DEVICE_EXTENSION Extension)
|
|
{
|
|
ULONG dataSize;
|
|
ULONG paritySize;
|
|
ULONG stopSize;
|
|
ULONG charTime;
|
|
ULONG bitTime;
|
|
|
|
dataSize = Extension->LineCtl.WordLength;
|
|
if(!Extension->LineCtl.Parity)
|
|
paritySize = 0;
|
|
else
|
|
paritySize = 1;
|
|
|
|
if(Extension->LineCtl.StopBits == STOP_BIT_1)
|
|
stopSize = 1;
|
|
else
|
|
stopSize = 2;
|
|
|
|
// Calculate number of 100 nanosecond intervals in a single bit time
|
|
if (Extension->BaudRate == 0)
|
|
{
|
|
MyKdPrint(D_Init, ("0 Baud!\n"))
|
|
Extension->BaudRate = 9600;
|
|
}
|
|
|
|
bitTime = (10000000+(Extension->BaudRate-1))/Extension->BaudRate;
|
|
// Calculate number of 100 nanosecond intervals in a character time
|
|
charTime = bitTime + ((dataSize+paritySize+stopSize)*bitTime);
|
|
|
|
return RtlConvertUlongToLargeInteger(charTime);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
Function : ForceExtensionSettings
|
|
Description: "Forces" the RocketPort to settings as indicated
|
|
by the device extension
|
|
Note: This is somewhat redundant to SerialSetHandFlow() in ioctl.c.
|
|
*****************************************************************************/
|
|
VOID ForceExtensionSettings(IN PSERIAL_DEVICE_EXTENSION Extension)
|
|
#ifdef S_VS
|
|
{
|
|
/////////////////////////////////////////////////////////////
|
|
// set the baud rate....
|
|
ProgramBaudRate(Extension, Extension->BaudRate);
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
// set Line Control.... Data, Parity, Stop
|
|
ProgramLineControl(Extension, &Extension->LineCtl);
|
|
|
|
// HandFlow related options
|
|
/////////////////////////////////////////////////////////////
|
|
// set up RTS control
|
|
|
|
Extension->Option &= ~OPTION_RS485_SOFTWARE_TOGGLE;
|
|
switch(Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK)
|
|
{
|
|
case SERIAL_RTS_CONTROL: // RTS Should be asserted while open
|
|
pDisRTSFlowCtl(Extension->Port);
|
|
pSetRTS(Extension->Port);
|
|
Extension->DTRRTSStatus |= SERIAL_RTS_STATE;
|
|
break;
|
|
|
|
case SERIAL_RTS_HANDSHAKE: // RTS hardware input flow control
|
|
// Rocket can't determine RTS state... indicate true for this option
|
|
pEnRTSFlowCtl(Extension->Port);
|
|
Extension->DTRRTSStatus |= SERIAL_RTS_STATE;
|
|
break;
|
|
|
|
case SERIAL_TRANSMIT_TOGGLE: // RTS transmit toggle enabled
|
|
if ( Extension->Option & OPTION_RS485_HIGH_ACTIVE ) {
|
|
Extension->Option |= OPTION_RS485_SOFTWARE_TOGGLE;
|
|
Extension->DTRRTSStatus &= ~SERIAL_RTS_STATE;
|
|
pEnRTSToggleHigh(Extension->Port);
|
|
} else {
|
|
pEnRTSToggleLow(Extension->Port);
|
|
Extension->DTRRTSStatus |= SERIAL_RTS_STATE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
pDisRTSFlowCtl(Extension->Port);
|
|
// Is RTS_CONTROL off?
|
|
pClrRTS(Extension->Port);
|
|
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;
|
|
pEnRTSToggleHigh(Extension->Port);
|
|
}
|
|
else
|
|
{ // hardware reverse case
|
|
pEnRTSToggleLow(Extension->Port);
|
|
Extension->DTRRTSStatus |= SERIAL_RTS_STATE;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
// set up DTR control
|
|
|
|
pDisDTRFlowCtl(Extension->Port);
|
|
// Should DTR be asserted when the port is opened?
|
|
if ( (Extension->HandFlow.ControlHandShake & SERIAL_DTR_MASK) ==
|
|
SERIAL_DTR_CONTROL )
|
|
{
|
|
pSetDTR(Extension->Port);
|
|
Extension->DTRRTSStatus |= SERIAL_DTR_STATE;
|
|
}
|
|
else if ( (Extension->HandFlow.ControlHandShake & SERIAL_DTR_MASK) ==
|
|
SERIAL_DTR_HANDSHAKE )
|
|
{
|
|
pEnDTRFlowCtl(Extension->Port);
|
|
Extension->DTRRTSStatus |= SERIAL_DTR_STATE;
|
|
}
|
|
else
|
|
{
|
|
pClrDTR(Extension->Port);
|
|
Extension->DTRRTSStatus &= ~SERIAL_DTR_STATE;
|
|
}
|
|
|
|
///////////////////////////////////
|
|
// DSR hardware output flow control
|
|
|
|
if (Extension->HandFlow.ControlHandShake & SERIAL_DSR_HANDSHAKE)
|
|
{
|
|
pEnDSRFlowCtl(Extension->Port);
|
|
}
|
|
else
|
|
{
|
|
pDisDSRFlowCtl(Extension->Port);
|
|
}
|
|
|
|
///////////////////////////////////
|
|
// DCD hardware output flow control
|
|
if (Extension->HandFlow.ControlHandShake & SERIAL_DCD_HANDSHAKE)
|
|
{
|
|
pEnCDFlowCtl(Extension->Port);
|
|
}
|
|
else
|
|
{
|
|
pDisCDFlowCtl(Extension->Port);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
// Set up CTS Flow Control
|
|
if (Extension->HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE)
|
|
{
|
|
pEnCTSFlowCtl(Extension->Port);
|
|
}
|
|
else
|
|
{
|
|
pDisCTSFlowCtl(Extension->Port);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
// Set up NULL stripping OPTIONAL
|
|
// fix: this was using RxCompare1 register, ioctl code using 0 so
|
|
// changed to match.
|
|
if (Extension->HandFlow.FlowReplace & SERIAL_NULL_STRIPPING)
|
|
{
|
|
pEnNullStrip(Extension->Port);
|
|
}
|
|
else
|
|
{
|
|
pDisNullStrip(Extension->Port);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
// Set up Software Flow Control OPTIONAL
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
// Special chars needed by RocketPort
|
|
pSetXOFFChar(Extension->Port,Extension->SpecialChars.XoffChar);
|
|
pSetXONChar(Extension->Port,Extension->SpecialChars.XonChar);
|
|
|
|
// Software input flow control
|
|
// SERIAL_AUTO_RECEIVE
|
|
if (Extension->HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE)
|
|
{
|
|
pEnRxSoftFlowCtl(Extension->Port);
|
|
}
|
|
else
|
|
{
|
|
pDisRxSoftFlowCtl(Extension->Port);
|
|
}
|
|
|
|
// Software output flow control
|
|
if (Extension->HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT)
|
|
{
|
|
pEnTxSoftFlowCtl(Extension->Port);
|
|
}
|
|
else
|
|
{
|
|
pDisTxSoftFlowCtl(Extension->Port);
|
|
}
|
|
}
|
|
|
|
#else // rocketport code
|
|
{
|
|
/////////////////////////////////////////////////////////////
|
|
// set the baud rate....
|
|
ProgramBaudRate(Extension, Extension->BaudRate);
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
// set Line Control.... Data, Parity, Stop
|
|
ProgramLineControl(Extension, &Extension->LineCtl);
|
|
|
|
// HandFlow related options
|
|
/////////////////////////////////////////////////////////////
|
|
// set up RTS control
|
|
|
|
Extension->Option &= ~OPTION_RS485_SOFTWARE_TOGGLE;
|
|
switch(Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK)
|
|
{
|
|
case SERIAL_RTS_CONTROL: // RTS Should be asserted while open
|
|
sSetRTS(Extension->ChP);
|
|
Extension->DTRRTSStatus |= SERIAL_RTS_STATE;
|
|
break;
|
|
|
|
case SERIAL_RTS_HANDSHAKE: // RTS hardware input flow control
|
|
// Rocket can't determine RTS state... indicate true for this option
|
|
sEnRTSFlowCtl(Extension->ChP);
|
|
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;
|
|
sClrRTS(Extension->ChP);
|
|
}
|
|
else
|
|
{ // hardware reverse case
|
|
sEnRTSToggle(Extension->ChP);
|
|
Extension->DTRRTSStatus |= SERIAL_RTS_STATE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// Is RTS_CONTROL off?
|
|
sClrRTS(Extension->ChP);
|
|
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;
|
|
sClrRTS(Extension->ChP);
|
|
}
|
|
else
|
|
{ // hardware reverse case
|
|
sEnRTSToggle(Extension->ChP);
|
|
Extension->DTRRTSStatus |= SERIAL_RTS_STATE;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
// set up DTR control
|
|
|
|
// Should DTR be asserted when the port is opened?
|
|
if( Extension->HandFlow.ControlHandShake &
|
|
(SERIAL_DTR_CONTROL|SERIAL_DTR_HANDSHAKE)
|
|
)
|
|
{
|
|
sSetDTR(Extension->ChP);
|
|
Extension->DTRRTSStatus |= SERIAL_DTR_STATE;
|
|
}
|
|
else
|
|
{
|
|
sClrDTR(Extension->ChP);
|
|
Extension->DTRRTSStatus &= ~SERIAL_DTR_STATE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
// Set up CTS Flow Control
|
|
if (Extension->HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE)
|
|
{
|
|
sEnCTSFlowCtl(Extension->ChP);
|
|
}
|
|
else
|
|
{
|
|
sDisCTSFlowCtl(Extension->ChP);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
// Set up NULL stripping OPTIONAL
|
|
// fix: this was using RxCompare1 register, ioctl code using 0 so
|
|
// changed to match.
|
|
if (Extension->HandFlow.FlowReplace & SERIAL_NULL_STRIPPING)
|
|
{
|
|
sEnRxIgnore0(Extension->ChP,0);
|
|
}
|
|
else
|
|
{
|
|
sDisRxCompare0(Extension->ChP);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
// Set up Software Flow Control OPTIONAL
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
// Special chars needed by RocketPort
|
|
sSetTxXOFFChar(Extension->ChP,Extension->SpecialChars.XoffChar);
|
|
sSetTxXONChar(Extension->ChP,Extension->SpecialChars.XonChar);
|
|
|
|
// SERIAL_AUTO_RECEIVE is taken care of by the driver
|
|
|
|
// Software output flow control
|
|
if (Extension->HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT)
|
|
{
|
|
sEnTxSoftFlowCtl(Extension->ChP);
|
|
}
|
|
else
|
|
{
|
|
sDisTxSoftFlowCtl(Extension->ChP);
|
|
sClrTxXOFF(Extension->ChP);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef S_RK
|
|
/*****************************************************************************
|
|
Function : SetExtensionModemStatus
|
|
Description: Reads and saves a copy of the modem control inputs,
|
|
then fills out the ModemStatus member in the extension.
|
|
*****************************************************************************/
|
|
VOID
|
|
SetExtensionModemStatus(
|
|
IN PSERIAL_DEVICE_EXTENSION extension
|
|
)
|
|
{
|
|
unsigned int ModemStatus = 0; // start off with no status
|
|
ULONG wstat;
|
|
|
|
|
|
|
|
//MyKdPrint(D_Init, ("SetExtModemStat"))
|
|
|
|
// ModemCtl is an image of the RocketPort's modem status
|
|
// ModemStatus member is passed to host via IOCTL
|
|
#if DBG
|
|
// this is called during isr.c poll, so put
|
|
// some assertions where we have been burned before...
|
|
if (extension->board_ext->config == NULL)
|
|
{
|
|
MyKdPrint(D_Init, ("SetExtMdm Err0\n"))
|
|
return;
|
|
}
|
|
#ifdef S_RK
|
|
if (!extension->board_ext->config->RocketPortFound)
|
|
{
|
|
MyKdPrint(D_Init, ("SetExtMdm Err1\n"))
|
|
return;
|
|
}
|
|
#endif
|
|
if (NULL == extension->ChP)
|
|
{
|
|
MyKdPrint(D_Init, ("SetExtMdm Err2\n"))
|
|
return;
|
|
}
|
|
if (0 == extension->ChP->ChanStat)
|
|
{
|
|
MyKdPrint(D_Init, ("SetExtMdm Err3\n"))
|
|
return;
|
|
}
|
|
if (NULL == extension->port_config)
|
|
{
|
|
MyKdPrint(D_Init, ("SetExtMdm Err4\n"))
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
// Read the port's modem control inputs and save off a copy
|
|
extension->ModemCtl = sGetModemStatus(extension->ChP);
|
|
|
|
if (extension->port_config->MapCdToDsr) // if CD to DSR option, swap signals
|
|
{
|
|
// swap CD and DSR handling for RJ11 board owners,
|
|
// so they can have pick between CD or DSR
|
|
if ((extension->ModemCtl & (CD_ACT | DSR_ACT)) == CD_ACT)
|
|
{
|
|
// swap
|
|
extension->ModemCtl &= ~CD_ACT;
|
|
extension->ModemCtl |= DSR_ACT;
|
|
}
|
|
else if ((extension->ModemCtl & (CD_ACT | DSR_ACT)) == DSR_ACT)
|
|
{
|
|
extension->ModemCtl &= ~DSR_ACT;
|
|
extension->ModemCtl |= CD_ACT;
|
|
}
|
|
}
|
|
|
|
// handle RPortPlus RI signal
|
|
if (extension->board_ext->config->IsRocketPortPlus)
|
|
{
|
|
if (sGetRPlusModemRI(extension->ChP))
|
|
ModemStatus |= SERIAL_RI_STATE;
|
|
else ModemStatus &= ~SERIAL_RI_STATE;
|
|
}
|
|
|
|
#ifdef RING_FAKE
|
|
if (extension->port_config->RingEmulate)
|
|
{
|
|
if (extension->ring_timer != 0) // RI on
|
|
ModemStatus |= SERIAL_RI_STATE;
|
|
else ModemStatus &= ~SERIAL_RI_STATE;
|
|
}
|
|
#endif
|
|
|
|
if (extension->ModemCtl & COM_MDM_DSR) // if DSR on
|
|
{
|
|
ModemStatus |= SERIAL_DSR_STATE;
|
|
if (extension->TXHolding & SERIAL_TX_DSR) // holding
|
|
{
|
|
extension->TXHolding &= ~SERIAL_TX_DSR; // clear holding
|
|
// if not holding due to other reason
|
|
if ((extension->TXHolding &
|
|
(SERIAL_TX_DCD | SERIAL_TX_DSR | ST_XOFF_FAKE)) == 0)
|
|
sEnTransmit(extension->ChP); // re-enable transmit
|
|
}
|
|
}
|
|
else // if DSR off
|
|
{
|
|
if (extension->HandFlow.ControlHandShake & SERIAL_DSR_HANDSHAKE)
|
|
{
|
|
if (!(extension->TXHolding & SERIAL_TX_DSR)) // not holding
|
|
{
|
|
extension->TXHolding |= SERIAL_TX_DSR; // set holding
|
|
sDisTransmit(extension->ChP); // hold transmit
|
|
}
|
|
}
|
|
}
|
|
|
|
if (extension->ModemCtl & COM_MDM_CTS) // if CTS on
|
|
{
|
|
ModemStatus |= SERIAL_CTS_STATE;
|
|
if (extension->TXHolding & SERIAL_TX_CTS) // holding
|
|
extension->TXHolding &= ~SERIAL_TX_CTS; // clear holding
|
|
}
|
|
else // cts off
|
|
{
|
|
if (extension->HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE)
|
|
{
|
|
if (!(extension->TXHolding & SERIAL_TX_CTS)) // not holding
|
|
extension->TXHolding |= SERIAL_TX_CTS; // set holding
|
|
}
|
|
}
|
|
|
|
if (extension->ModemCtl & COM_MDM_CD) // if CD on
|
|
{
|
|
ModemStatus |= SERIAL_DCD_STATE;
|
|
if (extension->TXHolding & SERIAL_TX_DCD) // holding
|
|
{
|
|
extension->TXHolding &= ~SERIAL_TX_DCD; // clear holding
|
|
// if not holding due to other reason
|
|
if ((extension->TXHolding &
|
|
(SERIAL_TX_DCD | SERIAL_TX_DSR | ST_XOFF_FAKE)) == 0)
|
|
sEnTransmit(extension->ChP); // re-enable transmit
|
|
}
|
|
}
|
|
else // if CD off
|
|
{
|
|
if (extension->HandFlow.ControlHandShake & SERIAL_DCD_HANDSHAKE)
|
|
{
|
|
if (!(extension->TXHolding & SERIAL_TX_DCD)) // not holding
|
|
{
|
|
extension->TXHolding |= SERIAL_TX_DCD; // set holding
|
|
sDisTransmit(extension->ChP); // hold transmit
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// handle holding detection if xon,xoff tx control activated
|
|
if (extension->HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT)
|
|
{
|
|
wstat = sGetChanStatusLo(extension->ChP);
|
|
|
|
// check for tx-flowed off condition to report
|
|
if ((wstat & (TXFIFOMT | TXSHRMT)) == TXSHRMT)
|
|
{
|
|
if (!extension->TXHolding) // not holding
|
|
{
|
|
wstat = sGetChanStatusLo(extension->ChP);
|
|
if ((wstat & (TXFIFOMT | TXSHRMT)) == TXSHRMT)
|
|
{
|
|
extension->TXHolding |= SERIAL_TX_XOFF; // holding
|
|
}
|
|
}
|
|
}
|
|
else // clear xoff holding report
|
|
{
|
|
if (extension->TXHolding & SERIAL_TX_XOFF)
|
|
extension->TXHolding &= ~SERIAL_TX_XOFF; // not holding
|
|
}
|
|
}
|
|
|
|
extension->ModemStatus = ModemStatus;
|
|
}
|
|
#endif
|