/*------------------------------------------------------------------- | 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