diff options
Diffstat (limited to '')
-rw-r--r-- | private/mvdm/softpc.new/host/src/nt_com.c | 2206 |
1 files changed, 2206 insertions, 0 deletions
diff --git a/private/mvdm/softpc.new/host/src/nt_com.c b/private/mvdm/softpc.new/host/src/nt_com.c new file mode 100644 index 000000000..4900c27ca --- /dev/null +++ b/private/mvdm/softpc.new/host/src/nt_com.c @@ -0,0 +1,2206 @@ +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <ntddser.h> +#include <windows.h> +#include <vdm.h> +#include "ptypes32.h" +#include "insignia.h" +#include "host_def.h" + +/* + * Ade Brownlow + * Wed Jul 10 91 + * + * nt_com.c + * + * + */ + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Include files */ + +#include "xt.h" +#include "rs232.h" +#include "error.h" +#include "config.h" +#include "ica.h" +#include "ios.h" +#include "host_com.h" +#include "host_trc.h" +#include "debug.h" +#include "idetect.h" +#include "nt_com.h" + +#include <math.h> +#include <malloc.h> +#include <stdlib.h> +#include <stdio.h> +#include <excpt.h> +#include <nt_timer.h> +#include <nt_eoi.h> + + +/*:::::::::::::::::::::::::::::::::::::::::::::: Standard host com interface */ + +GLOBAL void host_com_init(int); +GLOBAL CPU void host_com_close IPT1(int, adapter); +GLOBAL RXCPU VOID host_com_read IPT3(int, adapter, UTINY *, data, int *, error); +GLOBAL RXCPU void host_com_write IPT2(int, adapter, char, data); +GLOBAL void host_com_ioctl(int, int, long); +GLOBAL void host_com_reset(int); + +GLOBAL void host_com_lock(int adapter); +GLOBAL void host_com_unlock(int adapter); +GLOBAL int host_com_open(int); + +#if 0 +GLOBAL boolean host_com_suspend(int adapter); +GLOBAL boolean host_com_resume(int adapter); +#endif + +/* autoflush stub */ +GLOBAL void host_setup_aflush (int); +GLOBAL DWORD nt_poll_comms(DWORD); +DWORD PollCommsThread(PVOID pv); + +/*:::::::::::::::::::::::::::::: TX flush and control functions and defines */ + +#define TX_MAX_BUFFER (200) +#define TX_SCALING_TRIGGER (2) + +typedef enum { XOFF_TRIGGER, TIMER_TRIGGER, TXFULL_TRIGGER, CLOSE_TRIGGER } FLUSHTYPE; + +/*::::::::::::::::::::::::::::::::::::::::: Local adaptor control structure */ + +#define MAX_PENDING_WRITES (3) +// this is the buffer size we ask the serial driver to allocate +// for its isr buffer(nopaged pool with quota). TonyE said it is no harm +// to give it a bigger one(a big smile, eh). 4KB already gave us lots +// of trouble, especially, on a slow machine. +#define INPUT_QUEUE_SIZE (8*1024) +#define OUTPUT_QUEUE_SIZE 100 + +// this is the buffer size we use to receive rx data from serial driver +// it should be big enough to prevent the serial driver from overflowing its +// ISR buffer. The speed we delivery rx data to the application can not +// keep up with the speed that serial driver can handle. + +#define BUFFER_SIZE INPUT_QUEUE_SIZE *2 + + +// this is the max number of chars we delivery to the application +// before the CPU thread gives the RX thread a taste of CPU. +// Too small, we waste too much time doing context switching and deliverying +// too many unnecessary rda interrupts to some smart application ISR, +// thus, reduce the overall throughput. Too big, we choke the application +// (because we immediately delivery another rda interrupt to the +// application as soon as the application IRET). +// Application RX buffer size can be anywhere and depends how smart the +// appllication ISR is, we may make the application really angry. +// Some application ISR read LSR register after it gets the first char +// and if the LSR indicates that there is another bytes ready, +// it reads it immediately without waiting for the other int. +// Some application set the IER after EOI an RDA int and expects +// another interrupt. +#define DEFAULT_RXWINDOW_SIZE 256 + + +#define ADAPTER_NULL 0 /* NULL device (/dev/null) */ +#define ADAPTER_REAL 1 /* Real comm port device */ +#define ADAPTER_SUSPENDED 2 /* Real device suspended */ + +typedef struct _COM_STATES { + UCHAR Break; + UCHAR DTR; + UCHAR RTS; + UCHAR Parity; + UCHAR StopBits; + UCHAR DataBits; + DWORD BaudRate; +}COM_STATES, *PCOM_STATES; + + +#define ESCAPECHAR ((UCHAR)(-1)) +typedef struct _host_com +{ + HANDLE handle; /* Device handle */ + int type; /* hopefully NULL or a device */ + BOOL rx; + BOOL dcbValid; /* TRUE if dcbBeforeOpen contains a valid DCB */ + DCB dcbBeforeOpen; /* device control block before open*/ + DWORD modem_status; /* modem status line settings */ + HANDLE ModemEvent; /* Get modem status control event */ + + int controller; /* ICA control used */ + int line; /* ICA line */ + + /*..................................... Error display control variables */ + + BOOL DisplayError; /* Enabled/Disabled */ + + /*......................................... RX buffer control variables */ + UCHAR * buffer; /* rx buffer */ + int head_inx; /* Next place to add char to */ + int tail_inx; /* Next place to remove char from */ + int bytes_in_rxbuf; /* Number of bytes in buffer */ + int rxwindow_size; /* rx buffer sliding window size */ + int bytes_in_rxwindow; /* bytes in the rx window */ + int EscapeCount; + int EscapeType; + + BOOL CharReadFromUART; + int RXFlushTrigger; + + HANDLE RXControlObject; + DWORD SignalRXThread; + + /*......................................... TX buffer control variables */ + + unsigned char TXBuffer[TX_MAX_BUFFER]; + int no_tx_chars; /* Chars in tx buffer */ + int tx_threshold; /* Current flush threshold */ + int max_tx_threshold; /* Max flush threshold */ + + int tx_flush_count; /* No. of flushs of below size */ + int tx_heart_beat_count; + int tx_timer_flush_count; /* Consecutive timer flush counts */ + int todate_timer_flush_total; + + OVERLAPPED DWOV[MAX_PENDING_WRITES];/* Delayed writes */ + int DWOVInx; /* Delayed writes index */ + + /*.............................................. Access control objects */ + + CRITICAL_SECTION CSEvent; /* Used to control access to above */ + CRITICAL_SECTION AdapterLock; + int AdapterLockCnt; /* Adapter lock count */ + + volatile BOOL TerminateRXThread; + + int ReOpenCounter; /* Counter to prevent to many open attempts */ + int RX_in_Control; + + /*.......................................... XON/XOFF control variables */ + + HANDLE XOFFEvent; /* XOFF ioctl competion event */ + BOOL XOFFInProgress; /* XOFF currently in progress */ + + void *firstStatusBlock; /* first block in IO status block linked list */ + void *lastStatusBlock; /* last block in IO staus block linked list */ + + /*...................................... Overlapped I/O control handles */ + + HANDLE RXEvent; /* Overlapped read complete event */ + HANDLE TXEvent[MAX_PENDING_WRITES]; /* Overlapped write complete event */ + + HANDLE EvtHandle; /* Used by WaitCommEvent */ + + /*............................................. RX thread handle and ID */ + + DWORD RXThreadID; /* RX thread ID */ + HANDLE RXThreadHandle; /* RX thread handle */ + COM_STATES ComStates; /* Com device states as we know it */ + int SuspendTimeoutTicks; /* auto close ticks setting */ + int SuspendTickCounter; /* auto close tick counter */ + BOOL SyncWrite; /* TRUE if we should write data synchrounously */ + BOOL Suspended; /* TRUE if the port has been suspended */ + BOOL Suspending; /* TRUE when the port is being suspended */ + DWORD TickCount; + +} HOST_COM, *PHOST_COM; + +#define BUMP_TAIL_INX(t,c) (c)--;if(++(t) == BUFFER_SIZE) (t) = 0; + +typedef enum { RXCHAR, CHARINERROR, RXERROR, MODEMSTATE, RXBUFEMPTY, UNKNOWN} RXBUFCHARTYPE; + +/*:::::::::::::::::::::::::::::::::::::::::::::::::: Local function protocols */ + +DWORD GetCharsFromDriver(int adaptor); +void RX GetErrorFromDriver(int adapter); +CPU int SendXOFFIoctlToDriver(int adapter); + +DWORD ReadWaitTimeOut(int adapter); +int MapHostToBaseError(UCHAR host_error); + +void RX WaitForAllXOFFsToComplete(int adapter); +BOOL RX RemoveCompletedXOFFs(int adapter); +void SendDataToDriver(int adatper, char data); + +void CPU FlushTXBuffer(int adapter, FLUSHTYPE FlushReason); +void ScaleTXThreshold(register HOST_COM *current, FLUSHTYPE FlushReason); + +GLOBAL void host_com_EOI_hook(long adapter); +GLOBAL void CPU host_com_poll(int adapter); + +RXBUFCHARTYPE GetCharacterTypeInBuffer(register HOST_COM *current); +void CPU EmptyRXBuffer(int adapter); +void GetCharFromRXBuffer(HOST_COM *current, RXBUFCHARTYPE type, + UCHAR *data, UCHAR *error); + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: LOCAL DATA */ + +LOCAL HOST_COM host_com[4]; /* 4 comm ports - the insignia MAX */ + +LOCAL PHOST_COM host_com_ptr[4] = { &host_com[0], &host_com[1],&host_com[2], + &host_com[3]}; + +LOCAL int disable_open[4] = { FALSE, FALSE, FALSE, FALSE }; + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Local defines */ + +#define CURRENT_ADAPTER() register HOST_COM *current = host_com_ptr[adapter] + +#define EV_MODEM (EV_CTS | EV_DSR | EV_RING | EV_RLSD) +//#define EV_MODEM (EV_DSR | EV_RING | EV_RLSD) + +#define XON_CHARACTER (17) /* XON character, Cntrl-Q */ +#define XOFF_CHARACTER (19) /* XOFF character, Cntrl-S */ +#define XOFF_TIMEOUT (2*1000) /* Timeout in milliseconds */ +#define XOFF_RXCHARCNT (5) /* RX character count */ + +#define REOPEN_DELAY (36) /* Reopen delay in 55ms (2 secs) */ +#define RXFLUSHTRIGGER (36) /* RX flush trigger (2 secs), if a + character is not read from the + UART within this time the RX buffer + is flushed */ + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::: Init comms system ::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +#include "error.h" +#include "host_rrr.h" +#include "nt_uis.h" + + +GLOBAL CPU void host_com_init IFN1(int, adapter) +{ + UNUSED(adapter); + + // Comms ports are only opened when they are accessed. +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::: Disable Open :::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +//This is called at the start of the adapter init code to prevent the comm +//port being opened during com_init() + +void host_com_disable_open IFN2(int, adapter, int, DisableOpen) +{ + disable_open[adapter] = DisableOpen; +} + + +#ifdef NTVDM +boolean host_com_check_adapter(int adapter) +{ + CURRENT_ADAPTER(); + return (current->type == ADAPTER_REAL); + +} +#endif + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::: Open comms port ::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/* Called first time port is written to ! */ + +GLOBAL CPU int host_com_open(int adapter) +{ + COMMTIMEOUTS comout; /* Comm port time out settings */ + DIVISOR_LATCH divisor_latch; /* Current latch settings */ + LINE_CONTROL_REG LCR_reg; /* Current LCR status */ + int i; + DCB LocalDCB; + ConfigValues ComConfigValues; + + CURRENT_ADAPTER(); /* Define and setup pointer to adapter */ + + /*:::::::::::::::::::::::::::::::::::::::::: Is the port already open ? */ + + if(current->type == ADAPTER_REAL) + return(TRUE); /* Exit port already open */ + + /*::::::::::: Attempting to open the port to soon after a failed open ? */ + + if(current->ReOpenCounter || disable_open[adapter]) + return(FALSE); /* Yes */ + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + always_trace1("HOST_COM_OPEN adapter= %d\n", adapter); + + /*::::::::::::::::::::::::::::::::::::::::::::: Check for a NULL device */ + + if(adapter > 3 || adapter < 0) + { + current->type = ADAPTER_NULL; + current->ReOpenCounter = REOPEN_DELAY; /* Delay next open attempt */ + return(FALSE); /* Open attempt failed */ + } + + /*::::::::::::::::::::::::::: We have a vaild adapter so try to open it */ + config_inquire((UTINY)(C_COM1_NAME + adapter), + &ComConfigValues); + current->handle = CreateFile(ComConfigValues.string, + GENERIC_READ | GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + NULL); + + /*............................................... Validate open attempt */ + + if(current->handle == (HANDLE) -1) + { + always_trace1("Cannot open comms port '%s'\n", + (CHAR*) config_inquire((UTINY)(C_COM1_NAME+adapter),NULL)); + + if(current->DisplayError) { + RcErrorBoxPrintf(EHS_ERR_OPENING_COM_PORT, + (CHAR*) config_inquire((UTINY)(C_COM1_NAME+adapter),NULL)); + current->DisplayError = FALSE; //Error only display once per session + } + + current->ReOpenCounter = REOPEN_DELAY; /* Delay next open attempt */ + current->type = ADAPTER_NULL; /* Unable to open adapter */ + return(FALSE); + } + + + /* allocate rx buffer and initialize rx queue size */ + + current->buffer = (UCHAR *) malloc(BUFFER_SIZE); + if (current->buffer == NULL) { + CloseHandle(current->handle); + current->type = ADAPTER_NULL; + return FALSE; + } + current->rxwindow_size = DEFAULT_RXWINDOW_SIZE; + current->bytes_in_rxwindow = 0; + current->SyncWrite = (BOOL)config_inquire(C_COM_SYNCWRITE, NULL); + /*:: Find out which ICA controller and line are used by this comms port */ + + com_int_data(adapter, ¤t->controller, ¤t->line); + + /*::::::::::::::::::::::::::::::: Enable IRET hooks for comms interrupt */ + +#ifdef MONITOR + ica_iret_hook_control(current->controller, current->line, TRUE); +#endif + + /*:::::::::::::::::::::: Create objects used to control comms activity */ + + current->ModemEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + current->RXControlObject = CreateEvent(NULL,FALSE,FALSE,NULL); + current->RXEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + current->EvtHandle = CreateEvent(NULL,TRUE,FALSE,NULL); + current->DWOVInx = 0; + + //Create objects used to control multipe overlapping writes + for(i=0; i < MAX_PENDING_WRITES; i++) + { + //Objects must be created in the signalled state for the closedown + //routine to function correctly + + current->TXEvent[i] = CreateEvent(NULL,TRUE,TRUE,NULL); + current->DWOV[i].hEvent = NULL; + } + + /*::::::::::::::::::::::::::::::::::::::::::::::::: Empty RX/TX buffers */ + + current->head_inx = current->tail_inx = 0; + current->EscapeCount = current->bytes_in_rxbuf = current->no_tx_chars = 0; + + current->CharReadFromUART = FALSE; + current->RXFlushTrigger = RXFLUSHTRIGGER; + current->RX_in_Control = TRUE; + current->SignalRXThread = (DWORD) 0; + /*:::::::::::::::::::::::::::::::::::::::::::: Get TX buffer thresholds */ + + current->max_tx_threshold = (short)config_inquire(C_COM_TXBUFFER_SIZE, NULL); + if (!current->max_tx_threshold || current->max_tx_threshold > TX_MAX_BUFFER) + current->max_tx_threshold = TX_MAX_BUFFER; + + //Setup other delayed write control variables + if (current->max_tx_threshold == 1) + current->tx_threshold = 0; + current->tx_flush_count = 0; // No. of flushs of below size + /*::::::::::::::::::::::::::: Extended control variables used by adaper */ + + current->type = ADAPTER_REAL; /* Adapter type */ + current->TerminateRXThread = FALSE; /* RX thread termination flag */ + + /*:::::::::::::::::::::::::::::::: Initialise the XOFF control varibles */ + + current->XOFFInProgress = FALSE; + current->XOFFEvent = CreateEvent(NULL,TRUE,FALSE,NULL); + current->firstStatusBlock = current->lastStatusBlock = NULL; + + /*:::: Init critical sections used to sync access to host functions, data */ + + /* critical section used to control access to adapters data structure */ + InitializeCriticalSection(¤t->CSEvent); + + /* critical section used to lock access to adapter from the base */ + InitializeCriticalSection(¤t->AdapterLock); + current->AdapterLockCnt = 0; + + /* NULL thread handle because host_com_close() may be called before + the comms RX thread is created */ + + current->RXThreadHandle = NULL; + current->dcbValid = FALSE; + /*::::::::::::::::::::::::::::::::::::::: Set Comms port to binary mode */ + + if(!GetCommState(current->handle, &(current->dcbBeforeOpen))) + { + always_trace0("ntvdm : GetCommState failed on open\n"); + host_com_close(adapter); /* turn it into a NULL adapter */ + current->ReOpenCounter = REOPEN_DELAY; /* Delay next open attempt */ + return(FALSE); + } + + current->dcbValid = TRUE; + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Setup DCB */ + + + /* we make a local copy of DCB because we have to reset the DCB + * to whatever it was before we opened it. This function is the only place + * we ever touch DCB. + */ + + LocalDCB = current->dcbBeforeOpen; + LocalDCB.fBinary = 1; /* Run in RAW mode */ + LocalDCB.fOutxCtsFlow = FALSE; /* Disable CTS */ + LocalDCB.fOutxDsrFlow = FALSE; /* Disable DSR */ + LocalDCB.fDtrControl = DTR_CONTROL_DISABLE; + LocalDCB.fOutX = FALSE; /* Disable XON/XOFF */ + LocalDCB.fInX = FALSE; + LocalDCB.fRtsControl = RTS_CONTROL_DISABLE; + + LocalDCB.XonChar = XON_CHARACTER; /* Define XON/XOFF chars */ + LocalDCB.XoffChar = XOFF_CHARACTER; + LocalDCB.fErrorChar = FALSE; /* Turn off error char replacement */ + /* if we are resuming the device, initialize DCB parameters to + * what they were before suspended + */ + if (current->Suspended) { + LocalDCB.BaudRate = current->ComStates.BaudRate; + LocalDCB.Parity = current->ComStates.Parity; + LocalDCB.StopBits = current->ComStates.StopBits; + LocalDCB.ByteSize = current->ComStates.DataBits; + LocalDCB.fParity = (LocalDCB.Parity == NOPARITY); + } + /* initialize the ComStates by copying data from DCB */ + else { + current->ComStates.BaudRate = current->dcbBeforeOpen.BaudRate; + current->ComStates.Parity = current->dcbBeforeOpen.Parity; + current->ComStates.StopBits = current->dcbBeforeOpen.StopBits; + current->ComStates.DataBits = current->dcbBeforeOpen.ByteSize; + current->ComStates.Break = 0; + } + ASSERT(LocalDCB.BaudRate != 0); + + /*::::::::::::::::::::::::::::::::::: Sync base to current line settings */ + + if(!SyncLineSettings(NULL, &(LocalDCB), &divisor_latch, &LCR_reg)) + { + always_trace0("ntvdm : Unable to sync line states\n"); + + host_com_close(adapter); + current->ReOpenCounter = REOPEN_DELAY; /* Delay next open attempt */ + return(FALSE); + } + + SyncBaseLineSettings(adapter,&divisor_latch, &LCR_reg); + + /*:::::::::::::::::::::::::::::::::::::::::::::::: Set Comms port state */ + + if(!SetCommState(current->handle, &(LocalDCB))) + { + always_trace0("ntvdm : SetCommState failed on open\n"); + + host_com_close(adapter); + current->ReOpenCounter = REOPEN_DELAY; /* Delay next open attempt */ + return(FALSE); + } + + /*::::::::::::::::::::: Put the driver into streaming MSR,LSR, RX mode */ + + if(!EnableMSRLSRRXmode(current->handle, current->ModemEvent, + (unsigned char) ESCAPECHAR)) + { + always_trace0("ntvdm : GetCommState failed on open\n"); + host_com_close(adapter); /* turn it into a NULL adapter */ + current->ReOpenCounter = REOPEN_DELAY; /* Delay next open attempt */ + return(FALSE); + } + + /*::::::::::::::::::::::::::::::::::::::::: Setup comm port queue sizes */ + + if(!SetupComm(current->handle,INPUT_QUEUE_SIZE,OUTPUT_QUEUE_SIZE)) + { + always_trace1("ntvdm : SetupComm failed, %d\n",GetLastError()); + + host_com_close(adapter); + current->ReOpenCounter = REOPEN_DELAY; /* Delay next open attempt */ + return(FALSE); + } + + /*::::::::::::::::::::: Set communication port up for non-blocking read */ + + GetCommTimeouts(current->handle,&comout); + + comout.ReadIntervalTimeout = (DWORD) -1; + comout.ReadTotalTimeoutMultiplier = 0; + comout.ReadTotalTimeoutConstant = 0; + + SetCommTimeouts(current->handle,&comout); + + /* restore device states in case of resume */ + if (current->Suspended) { + /* break line */ + if (current->ComStates.Break) + SetCommBreak(current->handle); + else + ClearCommBreak(current->handle); + /* Data Terminal Ready line */ + if (current->ComStates.DTR) + EscapeCommFunction(current->handle, SETDTR); + else + EscapeCommFunction(current->handle, CLRDTR); + /* Request To Send line */ + if (current->ComStates.RTS) + EscapeCommFunction(current->handle, SETRTS); + else + EscapeCommFunction(current->handle, CLRRTS); + + /* parity, stop bits and data bits */ + FastCommSetLineControl(current->handle, + current->ComStates.StopBits, + current->ComStates.Parity, + current->ComStates.DataBits + ); + /* baud rate */ + FastCommSetBaudRate(current->handle, current->ComStates.BaudRate); + + /* we are no longer in suspended state */ + current->Suspended = FALSE; + + } + else { + /*::::::::::::::::::::::::::::::::::::::::::::: Setup RTS and DTR states */ + setup_RTSDTR(adapter); + } + + /*::::::::::::::::::::::::::::::::::::::::::::::: Create Comms RX thread */ + + if(!(current->RXThreadHandle = CreateThread(NULL, + 8192, + PollCommsThread, + (LPVOID)adapter, + 0, + ¤t->RXThreadID))) + { + always_trace1("ntvdm : Failed comms thread for %d\n", adapter); + host_com_close(adapter); /* Unable to create RX thread */ + current->ReOpenCounter = REOPEN_DELAY; /* Delay next open attempt */ + return(FALSE); + } + /* reset the counter */ + current->SuspendTimeoutTicks = ComConfigValues.index * 1000; + current->SuspendTickCounter = current->SuspendTimeoutTicks; + current->TickCount = 0; + return(TRUE); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::: Close all open comms ports :::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +GLOBAL CPU void host_com_close_all(void) +{ + int adapter; + + for(adapter = 0; adapter < 4; adapter++) + { + host_com[adapter].DisplayError = TRUE; //Enable error displaying + host_com_close(adapter); + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::: Close comms port ::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +GLOBAL CPU void host_com_close IFN1(int, adapter) +{ + CURRENT_ADAPTER(); + int i; + + /*:::::::::::::::::::::::::::::::::::::::: Dealing with NULL adapter ? */ + + if(current->type != ADAPTER_NULL) + { + always_trace1("Closing comms port %d\n",adapter); + + /* only touch the device if we own the device */ + if (current->type == ADAPTER_REAL) { + /*....... Flush any delayed writes and wait for writes to complete */ + if (current->no_tx_chars) + FlushTXBuffer(adapter,CLOSE_TRIGGER); + WaitForMultipleObjects(MAX_PENDING_WRITES,current->TXEvent,TRUE,INFINITE); + /* reset DCB to whatever it was before open */ + if (current->dcbValid) { + SetCommState(current->handle, ¤t->dcbBeforeOpen); + current->dcbValid = FALSE; + } + + } + + + /* keep the base adapter states intact if we are suspending the device */ + if (!current->Suspending) + /*........................................ Reset base comms adatper */ + com_init(adapter); /* Initialise base comms adapter */ + + /*................................................. Close RX thread */ + + if(current->RXThreadHandle) + { + /*................................. Tell RX thread to terminate */ + + current->TerminateRXThread = TRUE; // Tell RX thread to terminate + current->RX_in_Control = TRUE; + SetEvent(current->RXControlObject); + + /* Wait for RX thread to close itself, max wait 30 seconds */ + + WaitForSingleObject(current->RXThreadHandle,30000); + CloseHandle(current->RXThreadHandle); + + current->RXThreadHandle = NULL; // Mark thread as closed + } + /* now it is safe to close the device */ + CloseHandle(current->handle); current->handle = NULL; + + /*............... Delete RX critical section and RX control objects */ + + DeleteCriticalSection(¤t->CSEvent); + DeleteCriticalSection(¤t->AdapterLock); + + /*............................................. Close event objects */ + + CloseHandle(current->ModemEvent); + CloseHandle(current->RXControlObject); + CloseHandle(current->RXEvent); // Overlapped read wait object + for(i=0; i < MAX_PENDING_WRITES; i++) + { + CloseHandle(current->TXEvent[i]); // Overlapped write wait object + current->TXEvent[i] = NULL; + } + + CloseHandle(current->EvtHandle); // WaitCommEvent wait object + CloseHandle(current->XOFFEvent); + + current->XOFFEvent = current->RXEvent = current->EvtHandle = NULL; + + /*.......................... Disable IRET hooks for comms interrupt */ + +#ifdef MONITOR + ica_iret_hook_control(current->controller, current->line, FALSE); +#endif + + /*. This makes sure that the next access to the port will reopen it */ + current->ReOpenCounter = 0; + + free(current->buffer); + current->buffer = NULL; + current->type = ADAPTER_NULL; /* Mark adapter as closed */ + } + else if (current->Suspended) { + /* the application is terminating while the port is suspended. + * first we turn the disable-open on so that we will not try + * to physical touch the port. Then we call base to reset the + * adapter + */ + + BOOL DisableOpen; + DisableOpen = disable_open[adapter]; + disable_open[adapter] = TRUE; + com_init(adapter); + disable_open[adapter] = DisableOpen; + current->Suspended = FALSE; + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::: Request from base for character :::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +#ifdef FIFO_ON +GLOBAL CPU UTINY host_com_read_char( int adapter, FIFORXDATA * buffer, UTINY count) +{ + CURRENT_ADAPTER(); + UCHAR host_error; + RXBUFCHARTYPE CharType; + UTINY RetCount = count; + /* if xoff is in progress, don't read nothing */ + if (!current->XOFFInProgress) { + while (count) { + CharType = GetCharacterTypeInBuffer(current); + if (CharType == RXCHAR || CharType == CHARINERROR) { + buffer->error = 0; + GetCharFromRXBuffer(current, CharType, &buffer->data, &host_error); + if (!host_error) + buffer->error = MapHostToBaseError(host_error); + buffer++; + count--; + } + else + break; + } + } + /* Tell comms idle system that there has been comms activity */ + IDLE_comlpt(); + current->SuspendTickCounter = current->SuspendTimeoutTicks; + return (RetCount - count); + +} +GLOBAL CPU void host_com_fifo_char_read(int adapter) +{ + CURRENT_ADAPTER(); + current->CharReadFromUART = TRUE; +} +#endif + +GLOBAL RXCPU VOID host_com_read IFN3(int, adapter, UTINY *, data, int *, error) +{ + CURRENT_ADAPTER(); + UCHAR host_error; + RXBUFCHARTYPE CharType; + BOOL MoreToProcess = TRUE; + /*::::::::::::::::::::::::::::::::::::::::: Dealing with NULL adapter ? */ + + if(current->type != ADAPTER_REAL && !host_com_open(adapter)) + return; /* Exit, unable to open adapter */ + + /*::::::::::::::::::::::: Get next character from input character queue */ + + + while(MoreToProcess) + { + + CharType = GetCharacterTypeInBuffer(current); + + //Process next character in buffer + switch(CharType) + { + //................................................Process character + + case RXCHAR: + case CHARINERROR: + host_error = 0; + GetCharFromRXBuffer(current,CharType,(UCHAR *)data,&host_error); + + //error reading character + if(host_error) + *error = MapHostToBaseError(host_error); /* Get error */ + MoreToProcess = FALSE; + break; + + //.....................Process receive error, no character available + + case RXERROR: + com_lsr_change(adapter); + break; + + //...................................... Process modem state changes + + case MODEMSTATE: + com_modem_change(adapter); + break; + + //..................................................RX buffer empty + + case RXBUFEMPTY: + always_trace0("Read requested on empty RX buffer"); + *error = 0; *data = (UTINY)-1; //Buffer empty + MoreToProcess = FALSE; + break; + + case UNKNOWN: + GetCharFromRXBuffer(current,CharType,(UCHAR *)data,&host_error); + *error = MapHostToBaseError(host_error); /* Get error */ + MoreToProcess = FALSE; + break; + + } + } + + /* Tell comms idle system that there has been comms activity */ + IDLE_comlpt(); + current->SuspendTickCounter = current->SuspendTimeoutTicks; +} + +/*:::::::::::::::::::::::::: Comms read returned to application by the base */ +// This function is called after each character is read from the comms port + +int CPU host_com_char_read(int adapter, int data_available_ints) +{ + CURRENT_ADAPTER(); + + current->CharReadFromUART = TRUE; //Char read from UART + if(data_available_ints) + host_com_EOI_hook((long) adapter); + else + host_com_poll(adapter); + + return(0); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::: Map host error to base error ::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +int RXCPU MapHostToBaseError(UCHAR host_error) +{ + int base_error = 0; + LINE_STATUS_REG LSR; + + LSR.all = host_error; + if(LSR.bits.framing_error) base_error |= HOST_COM_FRAMING_ERROR; + if(LSR.bits.parity_error) base_error |= HOST_COM_PARITY_ERROR; + if(LSR.bits.break_interrupt) base_error |= HOST_COM_BREAK_RECEIVED; + if(LSR.bits.overrun_error) base_error |= HOST_COM_OVERRUN_ERROR; + + return(base_error); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::: Write to comms port :::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +GLOBAL RXCPU void host_com_write IFN2(int, adapter, char, data) +{ + CURRENT_ADAPTER(); + + /*:::::::::::::::::::::::::::::::::: Are we dealing with a NULL adapter */ + + if(current->type != ADAPTER_REAL && !host_com_open(adapter)) + return; /* Exit, unable to open adapter */ + + if(data == XOFF_CHARACTER || data == XON_CHARACTER) + sub_note_trace1(HOST_COM_VERBOSE,"XO%s sent",data == XOFF_CHARACTER ? "FF" : "N"); + + /*::::::::::::::::::::::::::::::::::::::::: Is the user sending an XOFF */ + + + if(data == XOFF_CHARACTER) + { + if(current->no_tx_chars) FlushTXBuffer(adapter,XOFF_TRIGGER); + SendXOFFIoctlToDriver(adapter); + } + else + SendDataToDriver(adapter,data); + + /*::::::::::: Tell comms idle system that there has been comms activity */ + + IDLE_comlpt(); + current->SuspendTickCounter = current->SuspendTimeoutTicks; + /* tell base that the tx holding register is empty */ + tx_holding_register_empty(adapter); + /* async write mode -> tell base that the tx shift register is empty + * sync mode -> FlushTxBuffer will do the signaling. + */ + if (!current->SyncWrite) + tx_shift_register_empty(adapter); +} + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::: Write data to driver */ + +void SendDataToDriver(int adapter, char data) +{ + DWORD BytesWritten, error = 0; + OVERLAPPED OV; + CURRENT_ADAPTER(); + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::::: Delay write ? */ + + if(current->tx_threshold) + { + //Add char to tx buffer queue + current->TXBuffer[current->no_tx_chars++] = (unsigned char) data; + + + //Write threshold reached ? + if(current->tx_threshold <= current->no_tx_chars || + current->XOFFInProgress) + FlushTXBuffer(adapter,(current->XOFFInProgress) ? + XOFF_TRIGGER : TXFULL_TRIGGER); + return; + } + + + /*:::::::::::::::::::::::::::::: Setup overlapped I/O control structure */ + + OV.hEvent = current->TXEvent[0]; /* Event used to signal completion */ + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::: Write character */ + + if(!WriteFile(current->handle, &data, 1, &BytesWritten, &OV)) + { + if((error = GetLastError()) == ERROR_IO_PENDING) + { + /* Write request pending wait for it to complete */ + if(GetOverlappedResult(current->handle,&OV,&BytesWritten,TRUE)) + error = 0; /* Write successful */ + else + error = GetLastError(); + } + + /* Reset comms port, clear error */ + if(error) ClearCommError(current->handle,&error,NULL); + } + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::::: Display error */ + +#ifndef PROD + if(error) + always_trace2("host_com_write error, adapter %d,%d\n",adapter,error); +#endif + /* tell base that the tx shift register is empty */ + tx_shift_register_empty(adapter); + +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::: Send magic XOFF ioctl */ + +CPU int SendXOFFIoctlToDriver(int adapter) +{ + CURRENT_ADAPTER(); + void *newIOStatusBlock; + int rtn; + + /*.................... Allocate new IOstatus block, used by magic ioctl */ + + newIOStatusBlock = AllocStatusElement(); + + /*.............................................. Issue magic xoff IOCTL */ + + if(SendXOFFIoctl(current->handle, // Handle of comms port + current->XOFFEvent, // Event to signal completion on + XOFF_TIMEOUT, // Timeout in milliseconds + XOFF_RXCHARCNT, // RX character count + XOFF_CHARACTER, // XOFF character + newIOStatusBlock)) // IO status block for ioctl + + { + /*............................. Add new status block to linked list */ + + EnterCriticalSection(¤t->CSEvent); + + AddNewIOStatusBlockToList(¤t->firstStatusBlock, + ¤t->lastStatusBlock, newIOStatusBlock); + + current->XOFFInProgress = TRUE; + LeaveCriticalSection(¤t->CSEvent); + rtn =TRUE; // XOFF ioctl successful + } + else + { + /* Error, XOFF ioctl failed */ + free(newIOStatusBlock); + rtn = FALSE; // XOFF ioctl failed + } + + return(rtn); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + +GLOBAL RXCPU void host_com_ioctl IFN3(int, adapter, int, request, long, arg) +{ + UCHAR host_modem, error; + MODEM_STATUS_REG MSR; + char BaudRateStr[100]; + ULONG ModemState; + UCHAR DataBits, StopBits, Parity; + + CURRENT_ADAPTER(); /* Define and set 'current' adaptor pointer */ + + /*:::::::::::::::::::::::::::::::::: Are we dealing with a null adapter */ + + if(current->type != ADAPTER_REAL) + { + // Attempt to open adapter ! + + if(request == HOST_COM_FLUSH || request == HOST_COM_INPUT_READY || + request == HOST_COM_MODEM || !host_com_open(adapter)) + { + return; + } + } + /*:::::::::::::::::::::::::::::::::::::::::::::: Identify ioctl request */ + + + switch(request) + { + + case HOST_COM_LSR: + if(GetCharacterTypeInBuffer(current) == RXERROR) + { + GetCharFromRXBuffer(current, RXERROR, NULL, &error); + *(DWORD *)arg = (DWORD)error; + } + break; + + /*:::::::::::::::::::::::::::::::::::::::::: Process break requests */ + + case HOST_COM_SBRK: /* Set BREAK */ + sub_note_trace0(HOST_COM_VERBOSE, "set BREAK"); + SetCommBreak(current->handle); + current->ComStates.Break = 1; + break; + + case HOST_COM_CBRK: /* Clear BREAK */ + sub_note_trace0(HOST_COM_VERBOSE, "clear BREAK"); + ClearCommBreak(current->handle); + current->ComStates.Break = 0; + break; + + /*::::::::::::::::::::::::::::::::::::::::: Process baud rate change */ + + case HOST_COM_BAUD: + + if (!FastCommSetBaudRate(current->handle, arg)) + { + sprintf(BaudRateStr, "(%d)", arg); + host_error(EHS_UNSUPPORTED_BAUD, ERR_CONT, BaudRateStr); + always_trace1("set BAUD failed - SetBaudRate:%d", arg); + } + current->ComStates.BaudRate = (DWORD)arg; + + break; + + /*:::::::::::::::::::::::::::::::::::::::: Process DTR line requests */ + + case HOST_COM_SDTR: /* Set DTR line */ + //printf("Set DTR\n"); + sub_note_trace0(HOST_COM_VERBOSE, "set DTR"); + if(!EscapeCommFunction (current->handle, SETDTR)) + sub_note_trace0(HOST_COM_VERBOSE, "set DTR FAILED"); + current->ComStates.DTR = 1; + break; + + case HOST_COM_CDTR: /* Clear DTR line */ + //printf("Clear DTR\n"); + sub_note_trace0(HOST_COM_VERBOSE, "clear DTR"); + if(!EscapeCommFunction (current->handle, CLRDTR)) + sub_note_trace0(HOST_COM_VERBOSE, "clear DTR FAILED"); + current->ComStates.DTR = 0; + break; + + /*::::::::::::::::::::::::::::::::::::::::::::::::: flush comms port */ + + case HOST_COM_FLUSH: /* Flush comms port */ + sub_note_trace0(HOST_COM_VERBOSE, "Flush comms port"); + break; + + /*:::::::::::::::::::::::::::::::::::::::: Process RTS line requests */ + + case HOST_COM_CRTS: /* Clear RTS */ + //printf("Clear RTS\n"); + sub_note_trace0(HOST_COM_VERBOSE, "clear RTS"); + if(!EscapeCommFunction (current->handle, CLRRTS)) + sub_note_trace0(HOST_COM_VERBOSE, "clear RTS FAILED"); + current->ComStates.RTS = 0; + break; + + case HOST_COM_SRTS: + //printf("Set RTS\n"); + sub_note_trace0(HOST_COM_VERBOSE, "set RTS"); + if(!EscapeCommFunction (current->handle, SETRTS)) + sub_note_trace0(HOST_COM_VERBOSE, "set RTS FAILED"); + current->ComStates.RTS = 1; + break; + + /*::::::::::::::::::::::::::::::::::: Return status of the RX buffer */ + + case HOST_COM_INPUT_READY: + *(long *)arg = current->rx; /* check the port for data */ + break; + + /*:::::::::::::::::::::::::::::::::::::::::::::: Return modem status */ + + case HOST_COM_MODEM: /* Get modem state */ + + current->modem_status = 0; + if(GetCharacterTypeInBuffer(current) == MODEMSTATE) + { + GetCharFromRXBuffer(current, MODEMSTATE, &host_modem, &error); + MSR.all = host_modem; + + if(MSR.bits.CTS) current->modem_status |= HOST_COM_MODEM_CTS; + if(MSR.bits.RI) current->modem_status |= HOST_COM_MODEM_RI; + if(MSR.bits.DSR) current->modem_status |= HOST_COM_MODEM_DSR; + if(MSR.bits.RLSD) current->modem_status |= HOST_COM_MODEM_RLSD; + } + else + { + //.......................Get modem data from the serial driver ? + + FastGetCommModemStatus(current->handle, current->ModemEvent, + &ModemState); + + if(ModemState & MS_CTS_ON) + current->modem_status |= HOST_COM_MODEM_CTS; + + if(ModemState & MS_RING_ON) + current->modem_status |= HOST_COM_MODEM_RI; + + if(ModemState & MS_DSR_ON) + current->modem_status |= HOST_COM_MODEM_DSR; + + if(ModemState & MS_RLSD_ON) + current->modem_status |= HOST_COM_MODEM_RLSD; + } + + //.......................Return modem change information to the base + + sub_note_trace4(HOST_COM_VERBOSE, "CTS:%s RI:%s DSR:%s RLSD:%s", + current->modem_status & HOST_COM_MODEM_CTS ? "ON" : "OFF", + current->modem_status & HOST_COM_MODEM_RI ? "ON" : "OFF", + current->modem_status & HOST_COM_MODEM_DSR ? "ON" : "OFF", + current->modem_status & HOST_COM_MODEM_RLSD ? "ON" : "OFF"); + + *(long *)arg = current->modem_status; + break; + + /*::::::::::::::::::::::::::::::::::::::::: Setup number of stop bits */ + + case HOST_COM_STOPBITS: + sub_note_trace1(HOST_COM_VERBOSE, "Setting Stop bits %d", arg); + if (FastCommGetLineControl(current->handle, &StopBits, &Parity, + &DataBits)) + { + switch (arg) + { + case 1: + StopBits = ONESTOPBIT; + break; + case 2: + StopBits = DataBits == 5 ? ONE5STOPBITS : TWOSTOPBITS; + break; + + default: + always_trace1("STOPBITS strange request %d\n", arg); + break; + } + + if(!FastCommSetLineControl(current->handle, StopBits, Parity, DataBits)) + { + + always_trace1("set STOPBITS failed- FastCommSetLineControl:%d",arg); + } + } + else { + + always_trace1("set STOPBITS failed- FastCommGetLineControl:%d",arg); + } + current->ComStates.StopBits = StopBits; + break; + + /*:::::::::::::::::::::::::::::::::::::::::::::::::::::: Setup parity */ + + case HOST_COM_PARITY: + if (FastCommGetLineControl(current->handle, &StopBits, &Parity, &DataBits)) + { + switch(arg) + { + case HOST_COM_PARITY_EVEN: + sub_note_trace0(HOST_COM_VERBOSE, "Set EVEN Parity"); + Parity=EVENPARITY; + break; + + case HOST_COM_PARITY_ODD: + sub_note_trace0(HOST_COM_VERBOSE, "Set ODD Parity"); + Parity=ODDPARITY; + break; + + case HOST_COM_PARITY_MARK: + sub_note_trace0(HOST_COM_VERBOSE, "Set MARK Parity"); + Parity=MARKPARITY; + break; + + case HOST_COM_PARITY_SPACE: + sub_note_trace0(HOST_COM_VERBOSE, "Set SPACE Parity"); + Parity=SPACEPARITY; + break; + + case HOST_COM_PARITY_NONE: + sub_note_trace0(HOST_COM_VERBOSE, "Set DISABLE Parity"); + Parity=NOPARITY; + break; + } + if(!FastCommSetLineControl(current->handle, StopBits, Parity, DataBits)) + { + always_trace1("set PARITY failed - FastCommSetLineControl :%d",arg); + } + } + else { + + always_trace1("set STOPBITS failed- FastCommGetLineControl:%d",arg); + } + current->ComStates.Parity = Parity; + break; + + /*::::::::::::::::::::::::::::::::::::::::::::::::::: Setup data bits */ + + case HOST_COM_DATABITS: + sub_note_trace1(HOST_COM_VERBOSE, "Setting data bits %d",arg); + if (FastCommGetLineControl(current->handle, &StopBits, &Parity, &DataBits)) + { + DataBits = (UCHAR)arg; + if(!FastCommSetLineControl(current->handle, StopBits, Parity, DataBits)) + { + always_trace1("set DATABITS failed - FastCommSetLineControl:%d",arg); + } + } + else { + + always_trace1("set STOPBITS failed- FastCommGetLineControl:%d",arg); + } + current->ComStates.DataBits = DataBits; + break; + + /*::::::::::::::::::::::::::::::::::::::: Unrecognised host_com ioctl */ + + default: + always_trace0("Bad host_com_ioctl\n"); + sub_note_trace0(HOST_COM_VERBOSE, "Bad host_com_ioctl"); + break; + } + + /* Tell comms idle system that there has been comms activity */ + IDLE_comlpt(); + current->SuspendTickCounter = current->SuspendTimeoutTicks; +} + +/*:::::::::::::::::::::::::::::::::::::::::::::::::: Host comms reset ????? */ + +GLOBAL void host_com_reset IFN1(int, adapter) +{ + int controller, line; + half_word IMR_value; + + com_int_data(adapter, &controller, &line); + + always_trace3("com reset Adapter %d, controller %d, line %d\n",adapter,controller,line); + + //Disable interrupts on port being reset + ica_inb((io_addr) (controller ? ICA1_PORT_1 : ICA0_PORT_1), &IMR_value); + IMR_value |= 1 << line; + ica_outb((io_addr) (controller ? ICA1_PORT_1 : ICA0_PORT_1), IMR_value); + + //Enable error displaying + host_com[adapter].DisplayError = TRUE; + host_com[adapter].Suspended = FALSE; + host_com[adapter].Suspending = FALSE; +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Autoflush */ + +GLOBAL void host_setup_aflush IFN1(int, state) +{ + UNREFERENCED_FORMAL_PARAMETER(state); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::: RX buffer handling routines :::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +/*:::::::::::::::::::::::::::::::::::::::: Get chars from the serial driver */ + + +DWORD RX GetCharsFromDriver(int adapter) +{ + CURRENT_ADAPTER(); + DWORD bytesread = 0, bytestoread; + OVERLAPPED OV; + DWORD CommError; + DWORD bytes_before_wrap; + DWORD total_bytes_read = 0; + + + OV.hEvent = current->RXEvent; /* Event to signal completion on */ + EnterCriticalSection(¤t->CSEvent); + + bytestoread = BUFFER_SIZE - current->bytes_in_rxbuf; + bytes_before_wrap = BUFFER_SIZE - current->head_inx; + if (bytes_before_wrap < bytestoread){ + OV.Offset = 0; /* reset offset or ReadFile can fail */ + OV.OffsetHigh = 0; + if (!ReadFile(current->handle, ¤t->buffer[current->head_inx], + bytes_before_wrap, &bytesread, &OV)) + { + // we have zero timeout for the read operation + // this pending check may be redundant?????? + if (GetLastError() == ERROR_IO_PENDING) { + GetOverlappedResult(current->handle, &OV, + &bytesread, TRUE); + } + else { + ClearCommError(current->handle, &CommError, NULL); + bytesread = 0; + } + } + + if (bytesread) { + total_bytes_read = bytesread; + current->bytes_in_rxbuf += bytesread; + if (bytesread == bytes_before_wrap) { + current->head_inx = 0; + bytestoread -= bytesread; + } + else { + current->head_inx += bytesread; + bytestoread = 0; + + } + } + else + bytestoread = 0; + } + if (bytestoread){ + OV.Offset = 0; /* reset offset or ReadFile can fail */ + OV.OffsetHigh = 0; + if (!ReadFile(current->handle, ¤t->buffer[current->head_inx], + bytestoread, &bytesread, &OV)) + { + if (GetLastError() == ERROR_IO_PENDING) { + GetOverlappedResult(current->handle, &OV, + &bytesread, TRUE); + } + else { + ClearCommError(current->handle, &CommError, NULL); + bytesread = 0; + } + } + if (bytesread) { + current->bytes_in_rxbuf += bytesread; + current->head_inx += bytesread; + total_bytes_read += bytesread; + } + } + LeaveCriticalSection(¤t->CSEvent); + + return (total_bytes_read); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::: RX thread, one per comm port :::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +DWORD PollCommsThread(PVOID pv) +{ + DWORD adapter = (DWORD)pv; + DWORD dwRet = (WORD)-1; + + try { + dwRet = nt_poll_comms(adapter); + } + except(VdmUnhandledExceptionFilter(GetExceptionInformation())) { + ; // we shouldn't arrive here + } + + return dwRet; +} + + + +DWORD CPU nt_poll_comms IFN1(DWORD, adapter) +{ + CURRENT_ADAPTER(); /* Setup ptr to current adapter */ + DWORD EvtMask; /* Comms event mask */ + ULONG SignalledObj = (ULONG) -1; + HANDLE WaitTable[3]; + HANDLE SetCommEvt; /* Handle used by FastSetCommEvent */ + + BOOL CheckDriverForChars = FALSE; /* Check driver for characters */ + RXBUFCHARTYPE CharType; + + /*::::::::::::::::::::::::::::::::: Setup table of event signal objects */ + + WaitTable[0] = current->EvtHandle; + WaitTable[1] = current->RXControlObject; + + /*:::::::::::::::::::::::::::::::::::::::::::::::: Setup comm wait mask */ + + SetCommEvt = CreateEvent(NULL,TRUE,FALSE,NULL); + + FastSetCommMask(current->handle,SetCommEvt,EV_RXCHAR | EV_ERR | EV_MODEM); + + //Initialise FastWaitCommsOrCpuEvent function + FastWaitCommsOrCpuEvent(NULL, NULL, 0, NULL, NULL); + + /*::::::::::::::::::::::::::::::::::::::::::::::::::::: Enter read loop */ + + while(TRUE) + { + /*::::::::::::::::: Wait for communications events then process them */ + + if(SignalledObj != 1) + { + if(!FastWaitCommsOrCpuEvent(current->handle, WaitTable, 0, &EvtMask, + &SignalledObj)) + { + // Error getting comms/CPU thread event ? + DisplayErrorTerm(EHS_FUNC_FAILED,GetLastError(),__FILE__,__LINE__); + } + } + + /*::::::::::::::::::::: Is the CPU thread returning control to us ? */ + + if(SignalledObj == 1 || current->TerminateRXThread) + { + // The CPU thread is trying to tell us something. + + /*..................... Is it time to terminate this thread !!! */ + + if(current->TerminateRXThread) + { + FastSetCommMask(current->handle,SetCommEvt,0); + WaitForAllXOFFsToComplete(adapter); // Complete ioctl's + CloseHandle(SetCommEvt); + return(0); // Terminate thread + } + + /* we have 3 reasons why we are here: + (1). the CPU thread has emptied the current rx window + (2). XOFF is in progress + */ + } + + if (SignalledObj == 0 || current->bytes_in_rxwindow == 0) + GetCharsFromDriver(adapter); + /*:::::::::::::::::::::::::::::::: Is there data to pass to the base */ + + if((CharType = GetCharacterTypeInBuffer(current)) != RXBUFEMPTY) + { + if (CharType == RXCHAR || CharType == CHARINERROR) { + WaitForAllXOFFsToComplete(adapter); + } + + // slid the window. Note that there may be some character left in + // the window(because of XOFF). It is no harm to slid + // the window. + // + EnterCriticalSection(¤t->CSEvent); + if (current->bytes_in_rxbuf > current->rxwindow_size) + current->bytes_in_rxwindow = current->rxwindow_size; + else + current->bytes_in_rxwindow = current->bytes_in_rxbuf; + LeaveCriticalSection(¤t->CSEvent); + + host_com_lock(adapter); + + if(CharType == MODEMSTATE) + com_modem_change(adapter); + else if (CharType == RXERROR) + com_lsr_change(adapter); + else { + com_recv_char(adapter); + /* + * reset rx flush counter so we won't flush Rx buffer. + * current->RXFlushTrigger may have been RXFLUSHTRIGGER - 1 + * at this moment and when we switch context to main thread + * another timer tick may have come which would trigger + * EmptyRxBuffer and cause unwantted overrun. + */ + current->RXFlushTrigger = RXFLUSHTRIGGER; + current->RX_in_Control = FALSE; + current->SignalRXThread = 0; + } + host_com_unlock(adapter); + + //Wait for CPU thread to return control + if(CharType != MODEMSTATE && CharType != RXERROR) + { + WaitForSingleObject(current->RXControlObject, INFINITE); + } + + SignalledObj = 1; + } + else + SignalledObj = (ULONG) -1; + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::: Wait for XOFF ioctl's to complete ::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + + +void RX WaitForAllXOFFsToComplete(int adapter) +{ + CURRENT_ADAPTER(); + int PendingXOFF; + + if(current->firstStatusBlock == NULL && current->lastStatusBlock == NULL) + return; //list of pending ioctrl's empty + + /*::::::::::::::::::::::: Wait for all pending xoff ioctl's to complete */ + + do + { + PendingXOFF = RemoveCompletedXOFFs(adapter); + + /*................................... Are there any ioctl's pending */ + + if(PendingXOFF) + WaitForSingleObject(current->XOFFEvent,XOFF_TIMEOUT); // wait for ioctl + } + while(PendingXOFF); +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::: Removed completed XOFF ioctl's :::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +BOOL RX RemoveCompletedXOFFs(int adapter) +{ + CURRENT_ADAPTER(); + int PendingXOFF; + + /*........................................ Remove completed ioctl's */ + + EnterCriticalSection(¤t->CSEvent); + + PendingXOFF = RemoveCompletedIOCTLs(¤t->firstStatusBlock, + ¤t->lastStatusBlock); + + if(!PendingXOFF) current->XOFFInProgress = FALSE; + + LeaveCriticalSection(¤t->CSEvent); + + return((BOOL) PendingXOFF); +} + + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::: Enter critical section for adapter :::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void RXCPU host_com_lock(int adapter) +{ + CURRENT_ADAPTER(); + if(current->type != ADAPTER_REAL) return; /* Exit, NULL adapter */ + + EnterCriticalSection(¤t->AdapterLock); + current->AdapterLockCnt++; +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::: Leave critical section for adapter :::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void RXCPU host_com_unlock(int adapter) +{ + CURRENT_ADAPTER(); + + if(current->type != ADAPTER_REAL || current->AdapterLockCnt == 0) + return; /* Exit, NULL adapter */ + + current->AdapterLockCnt--; + LeaveCriticalSection(¤t->AdapterLock); + + //Have we been requested to signal the RX thread. After the SetEvent() + //function call the RX thread, which is blocked on the + //current->RXControlObject object, will run. If the SetEvent() function + //is called from within the critical section, then because it is highly + //likely that the RX thread will attempt to perform a host_com_lock(). The + //RX thread will block in the host_com_lock() function until another time + //slice is given to the CPU thread. + + // do not set the event if RX thread already in control + if(current->SignalRXThread && + current->SignalRXThread == GetCurrentThreadId()) + { + current->RX_in_Control = TRUE; + SetEvent(current->RXControlObject); + current->SignalRXThread = (DWORD) 0; + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::: Host coms heart beat ::::::::::::::::::::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +//This function is called approximately every 55ms. + +GLOBAL void CPU host_com_heart_beat() +{ + register int adapter; /* Adapter no of adapter being processed */ + register HOST_COM *current; /* Ptr to current adapter being processed */ + DWORD TickCount; + + /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + for(adapter = 0; adapter < (sizeof(host_com)/sizeof(HOST_COM)); adapter++) + { + current = host_com_ptr[adapter]; /* Ptr to current adapter */ + + if(current->type == ADAPTER_NULL) + { + if(current->ReOpenCounter) current->ReOpenCounter--; + } + else if (current->type == ADAPTER_REAL) + { + if(current->no_tx_chars) FlushTXBuffer(adapter,TIMER_TRIGGER); + current->tx_heart_beat_count++; + + if(current->RXFlushTrigger == 0 && !current->CharReadFromUART) + EmptyRXBuffer(adapter); //Empty RX buffer + else + if(current->CharReadFromUART) + { + current->RXFlushTrigger = 0; //Force trigger reset + current->CharReadFromUART = FALSE; + } + + //Update RX flush trigger counter + if(--current->RXFlushTrigger < 0) + current->RXFlushTrigger = RXFLUSHTRIGGER; + /* if auto close is enable, decrement the counter and + * suspend the adapter is time out + */ + + if (current->SuspendTimeoutTicks) { + TickCount = GetTickCount(); + + if (current->TickCount) { + current->SuspendTickCounter -= TickCount - current->TickCount; + } + else { + /* we have not yet initialize the tick count yet, + * presume that it is 55ms + */ + current->SuspendTickCounter -= 55; + } + current->TickCount = TickCount; + + /* time out, suspend the port */ + if (current->SuspendTickCounter <= 27) { + /* make sure host_com_close won't reset the adapter because + * we want to keep the adapter current states + */ + current->Suspending = TRUE; + host_com_close(adapter); + current->Suspended = TRUE; + current->Suspending = FALSE; + } + } + } + } +} + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::: Flush TX buffer ::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +void CPU FlushTXBuffer(int adapter, FLUSHTYPE FlushReason) +{ + CURRENT_ADAPTER(); + DWORD BytesWritten, error = 0; + + /*................................................. Scale TX threshold */ + + ScaleTXThreshold(current, FlushReason); + + if (current->SyncWrite) { + if (!WriteFile(current->handle, current->TXBuffer, + current->no_tx_chars, &BytesWritten, + ¤t->DWOV[0])) { + error = GetLastError(); + if (error == ERROR_IO_PENDING) { + if (!GetOverlappedResult(current->handle, + ¤t->DWOV[0], + &BytesWritten, + TRUE)) + error = GetLastError(); + else + error = ERROR_SUCCESS; + } + } + if (error != ERROR_SUCCESS) { + ClearCommError(current->handle, &error, NULL); +#ifndef PROD + always_trace2("host_com_write error, adapter %d,%d\n", adapter, error); +#endif + } + tx_shift_register_empty(adapter); + current->no_tx_chars = 0; + return; + } + /*...Clear pending writes on the OV structure that we are about to use*/ + + if(current->DWOV[current->DWOVInx].hEvent) + { + if(GetOverlappedResult(current->handle, + ¤t->DWOV[current->DWOVInx], + &BytesWritten,TRUE)) + { + error = 0; /* Write successful */ + } + else + { + error = GetLastError(); + } + +#ifndef PROD + if(error) + always_trace2("host_com_write error, adapter %d,%d\n",adapter,error); +#endif + + } + else + current->DWOV[current->DWOVInx].hEvent = current->TXEvent[current->DWOVInx]; + + /*..................................................... Write characters */ + + + if(!WriteFile(current->handle, current->TXBuffer, current->no_tx_chars, + &BytesWritten, ¤t->DWOV[current->DWOVInx])) + { + if((error = GetLastError()) == ERROR_IO_PENDING) + error = 0; //ignore IO PENDING + + /* Reset comms port, clear error */ + if(error) + { + ClearCommError(current->handle,&error,NULL); +#ifndef PROD + always_trace2("host_com_write error, adapter %d,%d\n",adapter, + error); +#endif + } + } + + if(++current->DWOVInx == MAX_PENDING_WRITES) current->DWOVInx =0; + current->no_tx_chars = 0; +} + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::: Scale TX threshold :::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + + +void ScaleTXThreshold(register HOST_COM *current,FLUSHTYPE FlushReason) +{ + + if(FlushReason != TIMER_TRIGGER) + { + current->tx_timer_flush_count = 0; + current->todate_timer_flush_total = 0; + } + + /*....................................................................*/ + + switch(FlushReason) + { + // Comms heart beat caused flush + + case TIMER_TRIGGER: + //printf("T%d",current->no_tx_chars); + if(++current->tx_timer_flush_count == 3) + { + //printf("X"); + // three consecutive timer trigged flushes, this maybe because + // the TX threshold is to high. If the threshold is to high + // then we are wasting time waiting for the communications + // heart beat to flush the buffer. Reduce TX threshold. + + current->todate_timer_flush_total += current->no_tx_chars; + current->tx_threshold = current->todate_timer_flush_total/3; + + //printf("[%dT]",current->tx_threshold); + + // Reset TXFULL_TRIGGER control variables + current->tx_heart_beat_count = 0; + current->tx_flush_count = 0; + + // Reset TIMER_TRIGGER control variables + current->tx_timer_flush_count = 0; + current->todate_timer_flush_total = 0; + } + else + { + current->todate_timer_flush_total += current->no_tx_chars; + } + + break; + + // TX threshold reached + + case TXFULL_TRIGGER: + + //printf("F"); + //TX scaling trigger triggered ????? + if(current->tx_heart_beat_count <= 3 && + current->tx_flush_count++ == TX_SCALING_TRIGGER) + { + current->tx_threshold = current->tx_threshold*2 > current->max_tx_threshold + ? current->max_tx_threshold + : current->tx_threshold*2; + + //printf("[%dF]",current->tx_threshold); + current->tx_flush_count = 0; + } + else + if(current->tx_heart_beat_count > 3) + { + current->tx_heart_beat_count = 0; + current->tx_flush_count = 0; + } + + break; + + // XOFF triggered or close triggered flush + + case XOFF_TRIGGER: + case CLOSE_TRIGGER: + break; + + } /* End of switch statement */ +} + + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::::: Comms character read hook ::::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +//This function is called after a character has been read out of the comms +//adapter (com.c). This function is always called from within an adapter +//critical section, host_com_lock(). + +void CPU host_com_EOI_hook(long adapter) +{ + CURRENT_ADAPTER(); + RXBUFCHARTYPE CharType; + + if (!current->XOFFInProgress && current->bytes_in_rxwindow) + { + while ((CharType = GetCharacterTypeInBuffer(current)) != RXBUFEMPTY){ + if (CharType == MODEMSTATE) + com_modem_change(adapter); + else if (CharType == RXERROR) + com_lsr_change(adapter); + else { + com_recv_char((int) adapter); + return; + } + } + } + //Request host_com_unlock() to signal the RX thread. This will + //return responsibility for interrupt generation to the RX thread. + + current->SignalRXThread = GetCurrentThreadId(); +} + +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*:::::::::::::::::: Polling applications LSR hook ::::::::::::::::::::::::*/ +/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +// This following function is only called from the comms adapter if data +// available interrupts are disabled and the adapters receive buffer is +// empty. Being called under these circumstances indicates that we +// are dealing with a application that is polling the comms adapter. + +// This function is always called from within an adapter critical section + + +void CPU host_com_poll(int adapter) +{ + CURRENT_ADAPTER(); + RXBUFCHARTYPE CharType; + + /*:::::::::::::::::::::::::::::::::: Are we dealing with a null adapter */ + + if(current->type != ADAPTER_REAL && !host_com_open(adapter)) + return; /* Exit, unable to open adapter */ + + /*::::::::::::::::: Has an XOFF character stop the generation of ints */ + + if(current->XOFFInProgress) + { + // XOFF in process, pass no more characters to the base and return + // control to the RX thread. + + current->SignalRXThread = GetCurrentThreadId(); + return; + } + + // If the RX buffer is empty see if there are any characters hanging + // around in the serial driver + + if(current->bytes_in_rxbuf == 0) GetCharsFromDriver(adapter); + + /*:::::::::::::::::::::: Are there any characters to pass to the base ? */ + + if(current->bytes_in_rxbuf == 0 || + (CharType = GetCharacterTypeInBuffer(current)) == RXBUFEMPTY) + { + current->SignalRXThread = GetCurrentThreadId(); + } + else + { + //Process modem state characters + while(CharType == MODEMSTATE || CharType == RXERROR) + { + if (CharType == MODEMSTATE) + com_modem_change(adapter); + else + com_lsr_change(adapter); + CharType = GetCharacterTypeInBuffer(current); + } + + if(CharType != RXBUFEMPTY) + { + com_recv_char((int)adapter); + } + else + current->SignalRXThread = GetCurrentThreadId(); + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::::: Comms adapter data available interrupt hook ::::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +// The comms adapter calls this function when the status of the data available +// interrupt has changed. The adapter lock is in affect + +void CPU host_com_da_int_change(int adapter, int data_int_state, int data_state) +{ + CURRENT_ADAPTER(); + + /*:::::::::::::::::::::::::::::::::: Are we dealing with a null adapter */ + + if(current->type != ADAPTER_REAL) + { + // Only attempt to open a null adapter if data available interrupts + // are being enabled + + if(data_int_state == 0 || !host_com_open(adapter)) + return; + } +} + +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ +/*::::::::::::: Get the type of character in tail of RX buffer :::::::::::::*/ +/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ + +RXBUFCHARTYPE GetCharacterTypeInBuffer(register HOST_COM *current) +{ + int tail_inx = current->tail_inx; + int bytes_in_buf = current->bytes_in_rxbuf; + RXBUFCHARTYPE rtn; + + //Buffer empty ? + + if(bytes_in_buf == 0) return(RXBUFEMPTY); + + //Escape character at head of buffer + + if(current->buffer[tail_inx] == ESCAPECHAR && bytes_in_buf > 1) + { + BUMP_TAIL_INX(tail_inx,bytes_in_buf); + + switch(current->buffer[tail_inx]) + { + case SERIAL_LSRMST_ESCAPE : + rtn = RXCHAR; + break; + + case SERIAL_LSRMST_LSR_NODATA : + rtn = bytes_in_buf > 1 ? RXERROR : RXBUFEMPTY; + break; + + case SERIAL_LSRMST_LSR_DATA : + rtn = bytes_in_buf > 2 ? CHARINERROR : RXBUFEMPTY; + break; + + case SERIAL_LSRMST_MST : + rtn = bytes_in_buf > 1 ? MODEMSTATE : RXBUFEMPTY; + break; + // receive an invalid escape id + default: + rtn = UNKNOWN; + break; + } + } + else + { + rtn = current->buffer[tail_inx] == ESCAPECHAR ? RXBUFEMPTY : RXCHAR; + } + + return(rtn); +} + + +//::::::::::::::::::::::::::::::::::::Get the next character from the RX buffer. + +void GetCharFromRXBuffer(register HOST_COM *current, RXBUFCHARTYPE type, + UCHAR *data, UCHAR *error) +{ + EnterCriticalSection(¤t->CSEvent); + + switch(type) + { + //................................................. Return modem status + + case MODEMSTATE : + // Skip escape character and type marker + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + + *data = current->buffer[current->tail_inx]; + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + current->bytes_in_rxwindow -= 3; + break; + + //.................................................... Return character + + case RXCHAR : + if(current->buffer[current->tail_inx] == ESCAPECHAR) + { + //Skip ESCAPE character + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + current->bytes_in_rxwindow--; + *data = ESCAPECHAR; + } + else + *data = current->buffer[current->tail_inx]; + + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + current->bytes_in_rxwindow--; + break; + + //...........................................Return character and error + + case CHARINERROR : + // Skip escape character and type marker + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + + *error = current->buffer[current->tail_inx]; + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + *data = current->buffer[current->tail_inx]; + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + current->bytes_in_rxwindow -= 4; + break; + + //................................Return line status error with no data + + case RXERROR : + // Skip escape character and type marker + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + + // Get linr status error + *error = current->buffer[current->tail_inx]; + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + current->bytes_in_rxwindow -= 3; + break; + case UNKNOWN: + // The only case we will hit an unknown type is unsupport escape + // id. Dump the escape char, return the byte follows the escape + // characater and post an overrun error + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + *data = current->buffer[current->tail_inx]; + BUMP_TAIL_INX(current->tail_inx, current->bytes_in_rxbuf); + current->bytes_in_rxwindow -= 2; + *error = 2; + break; + + } + + LeaveCriticalSection(¤t->CSEvent); +} + +//::::::Empty RX buffer, processing characters and changing in the modem status + +void CPU EmptyRXBuffer(int adapter) +{ + RXBUFCHARTYPE CharType; + CURRENT_ADAPTER(); + + if(!current->RX_in_Control && current->SignalRXThread == (DWORD)0) + { + always_trace0("Char not removed from UART, RX buffer flushed\n"); + + host_com_lock(adapter); + + while((CharType = GetCharacterTypeInBuffer(current)) != RXBUFEMPTY) + { + if(CharType == MODEMSTATE) + com_modem_change(adapter); + else if (CharType == RXERROR) + com_lsr_change(adapter); + else + com_recv_char(adapter); + } + + host_com_unlock(adapter); + + //Buffer empty return control to the RX thread + current->RX_in_Control = TRUE; + SetEvent(current->RXControlObject); + } +} + +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ DEBUG functions + + +#if 0 +void host_com_state(int adapter) +{ + + CURRENT_ADAPTER(); + + printf("Adapter %d\n\n",adapter); + printf("RX in control %s\n", current->RX_in_Control ? "TRUE" : "FALSE"); + printf("XOFFInProgress %s\n", current->XOFFInProgress ? "TRUE" : "FALSE"); + + printf("Head buffer ptr %xh\n",current->head_inx); + printf("Tail buffer ptr %xh\n",current->tail_inx); + printf("Bytes in buffer %d\n",current->bytes_in_rxbuf); + + printf("Bytes in TX buf %d\n",current->no_tx_chars); + printf("TX buf threshold %d\n",current->tx_threshold); + printf("TX threshold max %d\n",current->max_tx_threshold); + printf("TX flush count %d\n",current->tx_flush_count); + printf("TX timer count %d\n",current->tx_heart_beat_count); + + if(current->AdapterLock.DebugInfo) + { + printf("Adapter CS count %d\n",current->AdapterLock.DebugInfo->ContentionCount); + printf("Data CS count %d\n",current->CSEvent.DebugInfo->ContentionCount); + } + + printf("Bytes RX to date %d\n",byte_count); + printf("Last read size %d\n",lastread); + printf("Avg read size %d\n",byte_count && readcount ? byte_count/readcount : 0); + printf("Zero reads %d\n",zeroreads); + + zeroreads = readcount = byte_count=0; + + com_reg_dump(); +} +#endif |