Commits (2)
  • Rob Swindell's avatar
    The sem_wait() call was just a bad idea after-all · 48874e1e
    Rob Swindell authored
    The sem_wait() call from vdd_read() that was fixed in the previous commit to this file was a bad idea to begin with:
    There is (often) not a 1:1 ratio of bytes in the receive ring buffer and the semaphore count, so we'd often halt here waiting for the semaphore to be signaled even though there were still characters in the receive buffer. This caused (new) stalls/hangs in keyboard input in DOS door games. We didn't see this previously because the sem_wait() call just didn't work (wrong semaphore pointer value).
    
    Now, call sem_trywait_block() in vdd_read(), but only if the RingBufRead() returned 0 (no bytes read) and even then, only block/wait for a maximum of 30 seconds (same as X00 FOSSIL driver). This blocking behavior is specified for FOSSIL function 02h (Get received character with wait) and would not have worked previous to the previous "fix", so now we have that corrected behavior too. The FTSC spec says the wait is indefinite, but I think a 30 second timeout (ala X00) is more reasonable.
    
    Log the git brach/hash instead of the old CVS revision.
    
    GetMailSlotInfo() apparently always fails on Windows 7 with error 87 (even using Microsoft's own sample code), so lower the log message severity of that failure from ERR to DEBUG. Apparently this is pretty harmless anyway as nothing really needs the write-mailslot status. <shrug>
    48874e1e
  • Rob Swindell's avatar
    Fix some FOSSIL functions · 18bcbeb7
    Rob Swindell authored
    Function 0Ch (peek) never worked correctly (character was not returned in AX); I guess nothing uses this function (?).
    
    Function 01h (transmit char w/wait) now will set the timeout flag (0x8000) in the AX if the VDD_WRITE function fails (returns value other than 1).
    
    Optimize Function 18h (read block) - no need for the extra VDD_STATUS call.
    
    Use newly defined FOSSIL macros instead of magic numbers of port status bits.
    
    Log the git branch/hash values to the Windows debug log (via sbbsexec.dll).
    18bcbeb7
......@@ -191,26 +191,26 @@ void vdd_getstatus(vdd_status_t* status)
WORD PortStatus()
{
WORD status=0x0008; /* AL bit 3 (change in DCD) always set */
WORD status=FOSSIL_MDM_STATUS_DCD_CHNG; /* AL bit 3 (change in DCD) always set */
vdd_status_t vdd_status;
vdd_getstatus(&vdd_status);
if(vdd_status.online) /* carrier detect */
status|=0x0080; /* DCD */
status|=FOSSIL_MDM_STATUS_DCD;
if(vdd_status.inbuf_full) /* receive data ready */
status|=0x0100; /* RDA */
status|=FOSSIL_LINE_STATUS_RDA;
/* if(vm->overrun) /* overrun error detected */
/* status|=0x0200; /* OVRN */
if(vdd_status.outbuf_full
<vdd_status.outbuf_size/2) /* room available in output buffer */
status|=0x2000; /* THRE */
status|=FOSSIL_LINE_STATUS_THRE;
if(!vdd_status.outbuf_full) /* output buffer is empty */
status|=0x4000; /* TSRE */
status|=FOSSIL_LINE_STATUS_TSRE;
return(status);
}
......@@ -256,6 +256,7 @@ void interrupt winNTint14(
BYTE ch;
BYTE far* p;
WORD buf_seg;
int rd;
int wr;
vdd_status_t vdd_status;
fossil_info_t info = {
......@@ -288,22 +289,23 @@ void interrupt winNTint14(
case FOSSIL_FUNC_PUT_CHAR: /* write char to com port, with wait */
ch=_ax&0xff;
_asm mov buf_seg, ss;
vdd_buf(VDD_WRITE, 1, buf_seg, (WORD)&ch);
wr = vdd_buf(VDD_WRITE, 1, buf_seg, (WORD)&ch);
_ax = PortStatus();
if(wr != 1)
_ax |= FOSSIL_LINE_STATUS_TIMEOUT;
break;
case FOSSIL_FUNC_GET_CHAR: /* read char from com port, with wait */
_asm mov buf_seg, ss;
_ax = vdd_buf(VDD_READ, 1, buf_seg, (WORD)&ch);
if(!_ax) {
_ax = 0x8000; /* timed-out */
rd = vdd_buf(VDD_READ, 1, buf_seg, (WORD)&ch);
_ax = ch;
if(rd != 1) {
vdd_op(VDD_YIELD);
} else {
_ax = ch;
_ax = FOSSIL_LINE_STATUS_TIMEOUT;
}
break;
case FOSSIL_FUNC_GET_STATUS: /* request status */
_ax=PortStatus();
if(_ax==0x6088)
if(_ax == FOSSIL_MDM_STATUS_DCD_CHNG | FOSSIL_MDM_STATUS_DCD | FOSSIL_LINE_STATUS_THRE | FOSSIL_LINE_STATUS_TSRE)
vdd_op(VDD_MAYBE_YIELD);
break;
case FOSSIL_FUNC_INIT: /* initialize */
......@@ -323,32 +325,23 @@ void interrupt winNTint14(
vdd_op(VDD_INBUF_PURGE);
break;
case FOSSIL_FUNC_WRITE_CHAR: /* write char to com port, no wait */
if(0 /*RingBufFree(&vm->out)<2 */) {
_ax=0; /* char was not accepted */
break;
}
ch=_ax&0xff;
_asm mov buf_seg, ss;
_ax = vdd_buf(VDD_WRITE, 1, buf_seg, (WORD)&ch);
if(_ax != 1)
vdd_op(VDD_YIELD);
break;
case FOSSIL_FUNC_PEEK: /* non-destructive read-ahead */
vdd_getstatus(&vdd_status);
if(!vdd_status.inbuf_full) {
_ax=0xffff; /* no char available */
vdd_op(VDD_YIELD);
break;
}
_asm mov buf_seg, ss;
_ax = vdd_buf(VDD_PEEK, 1, buf_seg, (WORD)&ch);
if(_ax == 0)
rd = vdd_buf(VDD_PEEK, 1, buf_seg, (WORD)&ch);
_ax = ch;
if(rd == 0) {
vdd_op(VDD_YIELD);
_ax = FOSSIL_CHAR_NOT_AVAILABLE;
}
break;
case FOSSIL_FUNC_READ_BLOCK: /* read block, no wait */
vdd_getstatus(&vdd_status);
if(!vdd_status.inbuf_full)
_ax = 0; /* no data available */
else
_ax = vdd_buf(VDD_READ, _cx, _es, _di);
_ax = vdd_buf(VDD_READ, _cx, _es, _di);
if(_ax == 0)
vdd_op(VDD_YIELD);
break;
......@@ -374,7 +367,7 @@ void interrupt winNTint14(
_ax=wr;
break;
case FOSSIL_FUNC_GET_KB:
_ax=0xffff;
_ax = FOSSIL_CHAR_NOT_AVAILABLE;
break;
}
}
......@@ -625,7 +618,7 @@ int main(int argc, char **argv)
vdd_str(VDD_LOAD_INI_SECTION, getfname(arg[0]));
sprintf(str,"%s, rev %u, %s %s mode=%u", __FILE__, DOSXTRN_REVISION, __DATE__, __TIME__, mode);
sprintf(str,"%s, rev %u %s/%s, %s %s mode=%u", __FILE__, DOSXTRN_REVISION, GIT_BRANCH, GIT_HASH, __DATE__, __TIME__, mode);
vdd_str(VDD_DEBUG_OUTPUT, str);
i=vdd_op(VDD_OPEN);
......@@ -685,7 +678,7 @@ int main(int argc, char **argv)
#ifdef DEBUG_DOS_CALLS
for(i=0;i<0x100;i++) {
if(dos_calls[i]>100) {
sprintf(str,"int21h function %02X calls: %u\n"
sprintf(str,"int21h function %02X calls: %u"
,i, dos_calls[i]);
vdd_str(VDD_DEBUG_OUTPUT, str);
}
......
/* fossdefs.h */
/* FOSSIL (FSC-15) structure and constant definitions */
/* $Id: fossdefs.h,v 1.3 2018/07/24 01:11:07 rswindell Exp $ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
......@@ -122,6 +118,23 @@ unsigned fossil_stop_bits[] = { 1, 2 };
unsigned fossil_data_bits[] = { 5, 6, 7, 8 };
#define FOSSIL_MDM_STATUS_CTS_CHNG (1<<0) // Delta clear to send (not reliable)
#define FOSSIL_MDM_STATUS_DSR_CHNG (1<<1) // Delta data set ready (not reliable)
#define FOSSIL_MDM_STATUS_RI_CHNG (1<<2) // trailing edge of ring indicator (documented wrong in X00REF.DOC)
#define FOSSIL_MDM_STATUS_DCD_CHNG (1<<3) // Delta data carrier detect
#define FOSSIL_MDM_STATUS_CTS (1<<4) // Clear to send
#define FOSSIL_MDM_STATUS_DSR (1<<5) // Data set ready
#define FOSSIL_MDM_STATUS_RI (1<<6) // Ring indicator
#define FOSSIL_MDM_STATUS_DCD (1<<7) // Data carrier detect
#define FOSSIL_LINE_STATUS_RDA (1<<8) // input data is available in buffer
#define FOSSIL_LINE_STATUS_OVRN (1<<9) // the input buffer has been overrun
#define FOSSIL_LINE_STATUS_THRE (1<<13) // room is available in output buffer
#define FOSSIL_LINE_STATUS_TSRE (1<<14) // output buffer is empty
#define FOSSIL_LINE_STATUS_TIMEOUT (1<<15) // Timeout (set by functions 1 and 2 only)
#define FOSSIL_CHAR_NOT_AVAILABLE 0xffff
#if defined(__GNUC__)
#define PACKED_STRUCT __attribute__((packed))
#else /* non-GCC compiler */
......
/* sbbsexec.c */
/* Synchronet Windows NT/2000 VDD for FOSSIL and DOS I/O Interrupts */
/* $Id: sbbsexec.c,v 1.41 2018/07/24 01:11:08 rswindell Exp $ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
......@@ -45,11 +41,14 @@
#include "dirwrap.h"
#include "threadwrap.h"
#include "ini_file.h"
#include "git_branch.h"
#include "git_hash.h"
#define INI_FILENAME "sbbsexec.ini"
#define RINGBUF_SIZE_IN 10000
#define DEFAULT_MAX_MSG_SIZE 4000
#define LINEAR_RX_BUFLEN 10000
#define READ_TIMEOUT (30 * 1000) // X00REF.DOC "the timeout value is set to 30 seconds"
/* UART Parameters and virtual registers */
WORD uart_io_base = UART_COM1_IO_BASE; /* COM1 */
......@@ -80,7 +79,6 @@ HANDLE wrslot=INVALID_HANDLE_VALUE;
RingBuf rdbuf;
str_list_t ini;
char ini_fname[MAX_PATH+1];
char revision[16];
void lputs(int level, char* msg)
{
......@@ -255,10 +253,14 @@ void _cdecl input_thread(void* arg)
unsigned vdd_read(BYTE* p, unsigned count)
{
sem_wait(&rdbuf.sem);
count=RingBufRead(&rdbuf,p,count);
if(count==0)
lprintf(LOG_ERR,"!VDD_READ: RingBufRead read 0");
if(count==0) {
lprintf(LOG_ERR,"!VDD_READ: RingBufRead read 0, waiting");
if(sem_trywait_block(&rdbuf.sem, READ_TIMEOUT) != 0)
lprintf(LOG_ERR,"!VDD_READ: rdbuf sem timeout");
count = RingBufRead(&rdbuf,p,count);
lprintf(LOG_ERR,"!VDD_READ: RingBufRead read 0 (after wait)");
}
return(count);
}
......@@ -481,10 +483,8 @@ __declspec(dllexport) void __cdecl VDDDispatch(void)
case VDD_OPEN:
sscanf("$Revision: 1.41 $", "%*s %s", revision);
lprintf(LOG_INFO,"Synchronet Virtual Device Driver, rev %s %s %s"
,revision, __DATE__, __TIME__);
lprintf(LOG_INFO,"Synchronet Virtual Device Driver, %s/%s %s %s"
,GIT_BRANCH, GIT_HASH, __DATE__, __TIME__);
#if 0
sprintf(str,"sbbsexec%d.log",node_num);
fp=fopen(str,"wb");
......@@ -668,7 +668,8 @@ __declspec(dllexport) void __cdecl VDDDispatch(void)
&msgs, /* address of number of messages */
NULL /* address of read time-out */
)) {
lprintf(LOG_ERR,"!VDD_STATUS: GetMailSlotInfo(%p) failed, error %u (msgs=%u, inbuf_full=%u, inbuf_size=%u)"
// Known to fail with error 87 (The Parameter is Incorrect) on Windows 7 <shrug>
lprintf(LOG_DEBUG,"!VDD_STATUS: GetMailSlotInfo(%p) failed, error %u (msgs=%u, inbuf_full=%u, inbuf_size=%u)"
,wrslot
,GetLastError(), msgs, status->inbuf_full, status->inbuf_size);
status->outbuf_full=0;
......