//***************************************************************************** // // The interrupt-context handler for touch screen events from the touch screen // driver. This function merely bundles up the event parameters and posts // them to a message queue. In the context of the main loop, they will be // read from the queue and handled using TSMainHandler(). // //***************************************************************************** int32_t TSHandler(uint32_t ui32Message, int32_t i32X, int32_t i32Y) { tScribbleMessage sMsg; // // Build the message that we will write to the queue. // sMsg.ui32Msg = ui32Message; sMsg.i32X = i32X; sMsg.i32Y = i32Y; // // Make sure the queue isn't full. If it is, we just ignore this message. // if(!RingBufFull(&g_sMsgQueue)) { RingBufWrite(&g_sMsgQueue, (uint8_t *)&sMsg, sizeof(tScribbleMessage)); } // // Tell the touch handler that everything is fine. // return(1); }
WORD PortStatus(vm_t* vm) { WORD status=0x0008; // AL bit 3 (change in DCD) always set if(vm->online) // carrier detect status|=0x0080; // DCD if(RingBufFull(&vm->in)) // receive data ready status|=0x0100; // RDA if(vm->overrun) // overrun error detected status|=0x0200; // OVRN if(RingBufFree(&vm->out)> // room available in output buffer RINGBUF_SIZE_OUT/2) status|=0x2000; // THRE if(!RingBufFull(&vm->out)) // output buffer is empty status|=0x4000; // TSRE return(status); }
// UART interrupt handler // For each received byte, pushes it into the buffer. // For each transmitted byte, read the next available from the buffer. void USART2_IRQHandler() { // TX the next available char on the buffer if (USART_GetITStatus(USART2, USART_IT_TC)) { USART_ClearITPendingBit(USART2, USART_IT_TC); if (RingBufUsed(&txBuffer)) USART_SendData(USART2, (uint8_t)RingBufReadOne(&txBuffer)); } // RX and copy the data to buffer if (USART_GetITStatus(USART2, USART_IT_RXNE)) { if (!RingBufFull(&rxBuffer)) { RingBufWriteOne(&rxBuffer, (uint8_t)USART_ReceiveData(USART2)); } } }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL SBBSExecInt16::handler(VMHANDLE hVM, CLIENT_STRUCT* pRegs, DWORD intno) { BYTE ch; DWORD avail; vm_t* vm = find_vm(hVM); if(vm==NULL || !(vm->mode&SBBSEXEC_MODE_DOS_IN)) { return(FALSE); // Tells VMM that interrupt was not handled } // DBTRACExx(0,"Int16 (hVM, AX)", hVM, _clientAX); avail=RingBufFull(&vm->in); switch(_clientAH) { case 0x00: // Read char from keyboard case 0x10: // Read char from enhanced keyboard if(avail) { RingBufRead(&vm->in, &ch, 1); _clientAX=ch; return(TRUE); } break; case 0x01: // Get keyboard status case 0x11: // Get enhanced keyboard status if(avail) { RingBufPeek(&vm->in, &ch, 1); _clientFlags&=~(1<<6); // clear zero flag _clientAX=ch; return(TRUE); } break; default: DBTRACEx(0,"!UNHANDLED INT16 function", _clientAH); break; } return(FALSE); }
int send_byte(void* unused, uchar ch, unsigned timeout) { uchar buf[2] = { TELNET_IAC, TELNET_IAC }; unsigned len=1; DWORD result; if(telnet && ch==TELNET_IAC) /* escape IAC char */ len=2; else buf[0]=ch; if(RingBufFree(&outbuf)<len) { fprintf(statfp,"FLOW"); flows++; result=WaitForEvent(outbuf_empty,timeout*1000); fprintf(statfp,"\b\b\b\b \b\b\b\b"); if(result!=WAIT_OBJECT_0) { fprintf(statfp ,"\n!TIMEOUT (%d) waiting for output buffer to flush (%u seconds, %u bytes)\n" ,result, timeout, RingBufFull(&outbuf)); newline=TRUE; if(RingBufFree(&outbuf)<len) return(-1); } } RingBufWrite(&outbuf,buf,len); #if !defined(RINGBUF_EVENT) ResetEvent(outbuf_empty); #endif #if 0 if(debug_tx) lprintf(LOG_DEBUG,"TX: %s",chr(ch)); #endif return(0); }
DWORD SBBSExec::OnW32DeviceIoControl(PIOCTLPARAMS pIOCTL) { DWORD rd; DWORD wr; DWORD avail; vm_t* vm; // DBTRACEd(0,"SBBSEXEC ioctl" //,pIOCTL->dioc_IOCtlCode); switch(pIOCTL->dioc_IOCtlCode) { case DIOC_OPEN: DBTRACEd(0,"IOCTL: OPEN",Get_System_Time()); break; case DIOC_CLOSEHANDLE: DBTRACEd(0,"IOCTL: CLOSE",Get_System_Time()); break; case SBBSEXEC_IOCTL_START: DBTRACEd(0,"IOCTL: START",Get_System_Time()); DBTRACEx(0,"Current Thread Handle",Get_Cur_Thread_Handle()); if(start.event) { DBTRACE(0,"Exec already started!"); return(SBBSEXEC_ERROR_INUSE); } if (pIOCTL->dioc_InBuf==NULL || pIOCTL->dioc_cbInBuf!=sizeof(start)) { return(SBBSEXEC_ERROR_INBUF); } start=*(sbbsexec_start_t*)pIOCTL->dioc_InBuf; break; case SBBSEXEC_IOCTL_COMPLETE: DBTRACEd(0,"IOCTL: COMPLETE",Get_System_Time()); if(start.event || new_vm==NULL) { DBTRACE(0,"!VM never created"); start.event=0; return(SBBSEXEC_ERROR_INUSE); } if(pIOCTL->dioc_OutBuf==NULL || pIOCTL->dioc_cbOutBuf<sizeof(VMHANDLE)) { DBTRACE(0,"!Invalid OUTBUF"); return(SBBSEXEC_ERROR_OUTBUF); } *(VMHANDLE*)pIOCTL->dioc_OutBuf=new_vm->handle; DBTRACEx(0,"CREATED VM HANDLE", new_vm->handle); new_vm=NULL; if(pIOCTL->dioc_bytesret!=NULL) *pIOCTL->dioc_bytesret = sizeof(VMHANDLE); break; case SBBSEXEC_IOCTL_READ: if (pIOCTL->dioc_InBuf==NULL || pIOCTL->dioc_cbInBuf!=sizeof(VMHANDLE)) { DBTRACE(0,"!INVALID INBUF"); return(SBBSEXEC_ERROR_INBUF); } if (pIOCTL->dioc_OutBuf==NULL || pIOCTL->dioc_cbOutBuf==0) { DBTRACE(0,"!INVALID OUTBUF"); return(SBBSEXEC_ERROR_OUTBUF); } vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf); if(vm==NULL) { DBTRACE(0,"!NO VM LIST"); return(SBBSEXEC_ERROR_INDATA); } rd = RingBufFull(&vm->out); if(rd>pIOCTL->dioc_cbOutBuf) { DBTRACEdd(0,"Reducing read size" ,rd, pIOCTL->dioc_cbOutBuf); rd=pIOCTL->dioc_cbOutBuf; } RingBufRead(&vm->out, (BYTE*)pIOCTL->dioc_OutBuf, rd); if(pIOCTL->dioc_bytesret!=NULL) *pIOCTL->dioc_bytesret = rd; if(vm->output_sem!=NULL) // Wake up int14 handler Signal_Semaphore(vm->output_sem); if(rd>1) { DBTRACEd(1,"IOCTL_READ bytes", rd); } break; case SBBSEXEC_IOCTL_WRITE: if (pIOCTL->dioc_InBuf==NULL || pIOCTL->dioc_cbInBuf<sizeof(VMHANDLE)+1) { DBTRACE(0,"!INVALID INBUF"); return(SBBSEXEC_ERROR_INBUF); } if (pIOCTL->dioc_OutBuf==NULL || pIOCTL->dioc_cbOutBuf!=sizeof(DWORD)) { DBTRACE(0,"!INVALID OUTBUF"); return(SBBSEXEC_ERROR_OUTBUF); } vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf); if(vm==NULL) { DBTRACE(0,"!NO VM LIST"); return(SBBSEXEC_ERROR_INDATA); } wr = pIOCTL->dioc_cbInBuf-sizeof(VMHANDLE); avail = RingBufFree(&vm->in); if(wr>avail) { DBTRACEdd(0,"Reducing write size", wr, avail); wr=avail; } RingBufWrite(&vm->in, (BYTE*)pIOCTL->dioc_InBuf+sizeof(VMHANDLE), wr); *(DWORD *)pIOCTL->dioc_OutBuf = wr; if(pIOCTL->dioc_bytesret!=NULL) *pIOCTL->dioc_bytesret = sizeof(DWORD); if(vm->input_sem!=NULL) // Wake up int14 handler Signal_Semaphore(vm->input_sem); // Wake up the VDM (improves keyboard response - dramatically!) Wake_Up_VM(vm->handle); break; case SBBSEXEC_IOCTL_DISCONNECT: DBTRACEd(0,"IOCTL: DISCONNECT",Get_System_Time()); if (pIOCTL->dioc_InBuf==NULL || pIOCTL->dioc_cbInBuf!=sizeof(VMHANDLE)) { DBTRACE(0,"!INVALID INBUF"); return(SBBSEXEC_ERROR_INBUF); } vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf); if(vm==NULL) { DBTRACE(0,"!NO VM LIST"); return(SBBSEXEC_ERROR_INDATA); } vm->online=false; if(vm->input_sem!=NULL) // Wake up int14 handler Signal_Semaphore(vm->input_sem); if(vm->output_sem!=NULL) // Wake up int14 handler Signal_Semaphore(vm->output_sem); break; case SBBSEXEC_IOCTL_STOP: DBTRACEd(0,"IOCTL: STOP",Get_System_Time()); if (pIOCTL->dioc_InBuf==NULL || pIOCTL->dioc_cbInBuf!=sizeof(VMHANDLE)) { DBTRACE(0,"!INVALID INBUF"); return(SBBSEXEC_ERROR_INBUF); } vm = find_vm(*(VMHANDLE*)pIOCTL->dioc_InBuf); if(vm==NULL) { DBTRACE(0,"!NO VM LIST"); return(SBBSEXEC_ERROR_INDATA); } DBTRACEx(0,"CLOSING VM HANDLE", vm->handle); vm->handle=NULL; // Mark as available RingBufDispose(&vm->in); RingBufDispose(&vm->out); if(vm->input_sem!=NULL) // Wake up int14 handler Signal_Semaphore(vm->input_sem); if(vm->output_sem!=NULL) // Wake up int14 handler Signal_Semaphore(vm->output_sem); vm->input_sem=NULL; vm->output_sem=NULL; break; default: DBTRACEdx(0,"!UNKNOWN IOCTL" ,pIOCTL->dioc_IOCtlCode,pIOCTL->dioc_IOCtlCode); return(SBBSEXEC_ERROR_IOCTL); } return (0); // DEVIOCTL_NOERROR); }
BOOL SBBSExecInt14::handler(VMHANDLE hVM, CLIENT_STRUCT* pRegs, DWORD intno) { BYTE* buffer; BYTE ch; WORD buflen; WORD rd,wr; WORD avail; vm_t* vm = find_vm(hVM); if(vm==NULL || vm->mode!=SBBSEXEC_MODE_FOSSIL) { return(FALSE); // Tells VMM that interrupt was not handled } DBTRACEx(4,"Int14 func",_clientAH); switch(_clientAH) { case 0x00: /* Initialize/Set baud rate */ DBTRACE(0,"Int14 init"); _clientAX=PortStatus(vm); break; case 0x01: /* write char to com port */ if(RingBufFree(&vm->out)<2) { DBTRACEx(1,"!OUTPUT BUFFER OVERFLOW, hVM", hVM); vm->output_sem=Create_Semaphore(0); Wait_Semaphore(vm->output_sem,BLOCK_THREAD_IDLE); Destroy_Semaphore(vm->output_sem); vm->output_sem=NULL; if(!vm->online) { DBTRACE(0,"!USER HUNG UP"); return(true); } } ch=_clientAL; RingBufWrite(&vm->out,&ch,1); #if 0 /* Now done in SBBS.DLL/XTRN.CPP */ if(ch==0xff) { /* escape TELNET IAC */ RingBufWrite(&vm->out,&ch,1); DBTRACE(1,"Escaped IAC in output stream"); } #endif vm->overrun=false; _clientAX=PortStatus(vm); break; case 0x02: /* read char from com port */ if(!RingBufFull(&vm->in)) { DBTRACEx(0,"Waiting on input semaphore, hVM", hVM); vm->input_sem=Create_Semaphore(0); Wait_Semaphore(vm->input_sem,BLOCK_THREAD_IDLE); Destroy_Semaphore(vm->input_sem); vm->input_sem=NULL; #if 0 _clientAH=0x80; /* timed-out */ return(TRUE); #endif } RingBufRead(&vm->in,&ch,1); _clientAH=0; _clientAL=ch; break; case 0x03: /* request status */ _clientAX=PortStatus(vm); break; case 0x04: /* initialize */ DBTRACE(0,"Int14 func 4 init"); _clientAX=0x1954; /* magic number = success */ _clientBH=5; /* FOSSIL rev */ _clientBL=0x1B; /* maximum FOSSIL func supported */ break; case 0x08: // flush output buffer DBTRACE(0,"Int14 FLUSH OUTPUT BUFFER"); vm->output_sem=Create_Semaphore(0); Wait_Semaphore(vm->output_sem,BLOCK_THREAD_IDLE); Destroy_Semaphore(vm->output_sem); vm->output_sem=NULL; break; case 0x09: // purge output buffer DBTRACE(0,"Int14 PURGE OUTPUT BUFFER"); RingBufReInit(&vm->out); break; case 0x0A: // purge input buffer DBTRACE(0,"Int14 PURGE INPUT BUFFER"); RingBufReInit(&vm->in); break; case 0x0B: /* write char to com port, no wait */ if(RingBufFree(&vm->out)<2) { _clientAX=0; // char was not accepted break; } ch=_clientAL; RingBufWrite(&vm->out,&ch,1); #if 0 /* Now done in SBBS.DLL/XTRN.CPP */ if(ch==0xff) { /* escape TELNET IAC */ RingBufWrite(&vm->out,&ch,1); DBTRACE(1,"Escaped IAC in output stream"); } #endif _clientAX=1; // char was accepted break; case 0x0C: // non-destructive read-ahead if(!RingBufFull(&vm->in)) { _clientAX=0xffff; // no char available break; } RingBufPeek(&vm->in,&ch,1); _clientAH=0; _clientAL=ch; break; case 0x13: /* write to display */ dprintf("%c",_clientAL); break; case 0x18: /* read bock */ rd=_clientCX; avail=RingBufFull(&vm->in); if(rd>avail) rd=avail; if(rd) { buffer = (BYTE*)MAPFLAT(CRS.Client_ES, CWRS.Client_DI); rd = RingBufRead(&vm->in, buffer, rd); } _clientAX = rd; break; case 0x19: /* write block */ wr=_clientCX; avail=RingBufFree(&vm->out); if(wr>avail) wr=avail; if(wr) { buffer = (BYTE*)MAPFLAT(CRS.Client_ES, CWRS.Client_DI); wr = RingBufWrite(&vm->out, buffer, wr); } _clientAX = wr; break; #if 1 case 0x1B: // driver info { DBTRACE(1,"Int14 driver info"); struct { WORD info_size; BYTE curr_fossil; BYTE curr_rev; DWORD id_string; WORD inbuf_size; WORD inbuf_free; WORD outbuf_size; WORD outbuf_free; BYTE screen_width; BYTE screen_height; BYTE baud_rate; } info={ sizeof(info), 5, 1, 0 ,RINGBUF_SIZE_IN-1, RingBufFree(&vm->in) ,RINGBUF_SIZE_OUT-1, RingBufFree(&vm->out) ,80,25 ,1 // 38400 }; // Map_Lin_To_VM_Addr buffer = (BYTE*)MAPFLAT(CRS.Client_ES, CWRS.Client_DI); wr=sizeof(info); if(wr>_clientCX) wr=_clientCX; memcpy(buffer, &info, wr); _clientAX=wr; break; } #endif default: DBTRACEx(0,"!UNHANDLED INTERRUPT 14h function",_clientAH); break; } return(TRUE); // Tells VMM that interrupt was handled }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL SBBSExecInt21::handler(VMHANDLE hVM, CLIENT_STRUCT* pRegs, DWORD intno) { BYTE ch; BYTE* buffer; WORD buflen; vm_t* vm = find_vm(hVM); if(vm==NULL || !(vm->mode&SBBSEXEC_MODE_DOS_OUT)) { #if 0 if(vm && !(vm->mode&SBBSEXEC_MODE_DOS_OUT)) { DBTRACEx(0,"Int21 on unsupported VM", hVM); } #endif return(FALSE); // Tells VMM that interrupt was not handled } DBTRACEx(1,"Int21 function", _clientAH); DWORD avail = RingBufFree(&vm->out); switch(_clientAH) { case 0x01: DBTRACE(0,"!Int21 Char input WITH echo"); break; case 0x06: // Direct console I/O DBTRACEx(0,"DOS DIRECT CONSOLE IO, DL", _clientDL); if(_clientDL==0xff) { avail=RingBufFull(&vm->in); if(avail) { DBTRACEd(0,"avail",avail); RingBufRead(&vm->in, &ch, 1); _clientFlags&=~(1<<6); // clear zero flag _clientAX=ch; return(TRUE); } break; } // fall-through case 0x02: // Character output DBTRACEx(1,"Int21 function", _clientAH); if(!avail) { DBTRACEx(0,"!OUTPUT BUFFER OVERFLOW, hVM", hVM); vm->overrun=true; break; } ch=_clientDL; RingBufWrite(&vm->out,&ch,1); vm->overrun=false; break; case 0x09: // Display string DBTRACE(0,"!Int21 func 09 - DISPLAY STRING"); break; case 0x0A: // Buffered keyboard input DBTRACE(0,"Int21 Func 0A - Buffered Keyboard Input"); /* Need to get a string from the user, echo, and copy to DS:DX */ /* byte 0 = max length, byte 1 = actual read (minus CR) */ break; case 0x40: // Write file or device if(_clientBX!=1 && _clientBX!=2) { // !stdout and !stderr DBTRACEd(1,"!Int21 write to unsupported device", _clientBX); break; } DBTRACEdd(1,"Int21 write file", _clientBX, _clientCX); buffer = (BYTE*)MAPFLAT(CRS.Client_DS, CWRS.Client_DX); buflen = _clientCX; if(avail<buflen) { DBTRACEd(0,"!OUTPUT BUFFER OVERFLOW, avail", avail); vm->overrun=true; if(!avail) break; buflen=avail; } RingBufWrite(&vm->out,buffer,buflen); vm->overrun=false; break; } return(FALSE); // Tells VMM that interrupt was not handled }
static JSBool js_console_get(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { ulong val; jsint tiny; JSString* js_str; sbbs_t* sbbs; if((sbbs=(sbbs_t*)JS_GetContextPrivate(cx))==NULL) return(JS_FALSE); tiny = JSVAL_TO_INT(id); switch(tiny) { case CON_PROP_STATUS: val=sbbs->console; break; case CON_PROP_LNCNTR: val=sbbs->lncntr; break; case CON_PROP_ATTR: val=sbbs->curatr; break; case CON_PROP_TOS: val=sbbs->tos; break; case CON_PROP_ROWS: val=sbbs->rows; break; case CON_PROP_COLUMNS: val=sbbs->cols; break; case CON_PROP_AUTOTERM: val=sbbs->autoterm; break; case CON_PROP_TERMINAL: if((js_str=JS_NewStringCopyZ(cx, sbbs->terminal))==NULL) return(JS_FALSE); *vp = STRING_TO_JSVAL(js_str); return(JS_TRUE); case CON_PROP_TIMEOUT: val=sbbs->timeout; break; case CON_PROP_TIMELEFT_WARN: val=sbbs->timeleft_warn; break; case CON_PROP_ABORTED: *vp=BOOLEAN_TO_JSVAL(INT_TO_BOOL(sbbs->sys_status&SS_ABORT)); return(JS_TRUE); case CON_PROP_ABORTABLE: *vp=BOOLEAN_TO_JSVAL(INT_TO_BOOL(sbbs->rio_abortable)); return(JS_TRUE); case CON_PROP_TELNET_MODE: val=sbbs->telnet_mode; break; case CON_PROP_GETSTR_OFFSET: val=sbbs->getstr_offset; break; case CON_PROP_WORDWRAP: if((js_str=JS_NewStringCopyZ(cx, sbbs->wordwrap))==NULL) return(JS_FALSE); *vp = STRING_TO_JSVAL(js_str); return(JS_TRUE); case CON_PROP_QUESTION: if((js_str=JS_NewStringCopyZ(cx, sbbs->question))==NULL) return(JS_FALSE); *vp = STRING_TO_JSVAL(js_str); return(JS_TRUE); case CON_PROP_CTRLKEY_PASSTHRU: val=sbbs->cfg.ctrlkey_passthru; break; case CON_PROP_INBUF_LEVEL: val=RingBufFull(&sbbs->inbuf); break; case CON_PROP_INBUF_SPACE: val=RingBufFree(&sbbs->inbuf); break; case CON_PROP_OUTBUF_LEVEL: val=RingBufFull(&sbbs->outbuf); break; case CON_PROP_OUTBUF_SPACE: val=RingBufFree(&sbbs->outbuf); break; default: return(JS_TRUE); } *vp = INT_TO_JSVAL(val); return(JS_TRUE); }
static void output_thread(void* arg) { char stats[128]; BYTE buf[MAX_OUTBUF_SIZE]; int i; ulong avail; ulong total_sent=0; ulong total_pkts=0; ulong short_sends=0; ulong bufbot=0; ulong buftop=0; fd_set socket_set; struct timeval tv; #if 0 /* def _DEBUG */ fprintf(statfp,"output thread started\n"); #endif while(sock!=INVALID_SOCKET && !terminate) { if(bufbot==buftop) avail=RingBufFull(&outbuf); else avail=buftop-bufbot; if(!avail) { #if !defined(RINGBUF_EVENT) SetEvent(outbuf_empty); #endif sem_wait(&outbuf.sem); if(outbuf.highwater_mark) sem_trywait_block(&outbuf.highwater_sem,outbuf_drain_timeout); continue; } /* Check socket for writability (using select) */ tv.tv_sec=0; tv.tv_usec=1000; FD_ZERO(&socket_set); #ifdef __unix__ if(stdio) FD_SET(STDOUT_FILENO,&socket_set); else #endif FD_SET(sock,&socket_set); i=select(sock+1,NULL,&socket_set,NULL,&tv); if(i==SOCKET_ERROR) { lprintf(LOG_ERR,"ERROR %d selecting socket %u for send" ,ERROR_VALUE,sock); break; } if(i<1) { select_errors++; continue; } if(bufbot==buftop) { /* linear buf empty, read from ring buf */ if(avail>sizeof(buf)) { lprintf(LOG_ERR,"Insufficient linear output buffer (%lu > %lu)" ,avail, sizeof(buf)); avail=sizeof(buf); } buftop=RingBufRead(&outbuf, buf, avail); bufbot=0; } #ifdef __unix__ if(stdio) i=write(STDOUT_FILENO, (char*)buf+bufbot, buftop-bufbot); else #endif i=sendsocket(sock, (char*)buf+bufbot, buftop-bufbot); if(i==SOCKET_ERROR) { if(ERROR_VALUE == ENOTSOCK) lprintf(LOG_ERR,"client socket closed on send"); else if(ERROR_VALUE==ECONNRESET) lprintf(LOG_ERR,"connection reset by peer on send"); else if(ERROR_VALUE==ECONNABORTED) lprintf(LOG_ERR,"connection aborted by peer on send"); else lprintf(LOG_ERR,"ERROR %d sending on socket %d" ,ERROR_VALUE, sock); break; } if(debug_tx) dump(buf+bufbot,i); if(i!=(int)(buftop-bufbot)) { lprintf(LOG_ERR,"Short socket send (%u instead of %u)" ,i ,buftop-bufbot); short_sends++; } bufbot+=i; total_sent+=i; total_pkts++; } if(total_sent) sprintf(stats,"(sent %lu bytes in %lu blocks, %lu average, %lu short, %lu errors)" ,total_sent, total_pkts, total_sent/total_pkts, short_sends, select_errors); else stats[0]=0; lprintf(LOG_DEBUG,"output thread terminated\n%s", stats); }
__declspec(dllexport) void __cdecl VDDDispatch(void) { char str[512]; DWORD count; DWORD msgs; int retval; int node_num; BYTE* p; vdd_status_t* status; static DWORD writes; static DWORD bytes_written; static DWORD reads; static DWORD bytes_read; static DWORD inbuf_poll; static DWORD online_poll; static DWORD status_poll; static DWORD vdd_yields; static DWORD vdd_calls; VDD_IO_HANDLERS IOHandlers = { NULL }; static VDD_IO_PORTRANGE PortRange; retval=0; node_num=getBH(); lprintf(LOG_DEBUG,"VDD_OP: (handle=%d) %d (arg=%X)", getAX(),getBL(),getCX()); vdd_calls++; switch(getBL()) { case VDD_OPEN: sscanf("$Revision: 1.40 $", "%*s %s", revision); lprintf(LOG_INFO,"Synchronet Virtual Device Driver, rev %s %s %s" ,revision, __DATE__, __TIME__); #if 0 sprintf(str,"sbbsexec%d.log",node_num); fp=fopen(str,"wb"); #endif sprintf(str,"\\\\.\\mailslot\\sbbsexec\\wr%d",node_num); rdslot=CreateMailslot(str ,0 //LINEAR_RX_BUFLEN /* Max message size (0=any) */ ,MAILSLOT_WAIT_FOREVER /* Read timeout */ ,NULL); if(rdslot==INVALID_HANDLE_VALUE) { lprintf(LOG_ERR,"!VDD_OPEN: Error %d opening %s" ,GetLastError(),str); retval=1; break; } sprintf(str,"\\\\.\\mailslot\\sbbsexec\\rd%d",node_num); wrslot=CreateFile(str ,GENERIC_WRITE ,FILE_SHARE_READ ,NULL ,OPEN_EXISTING ,FILE_ATTRIBUTE_NORMAL ,(HANDLE) NULL); if(wrslot==INVALID_HANDLE_VALUE) { lprintf(LOG_ERR,"!VDD_OPEN: Error %d opening %s" ,GetLastError(),str); retval=2; break; } if(RingBufInit(&rdbuf, RINGBUF_SIZE_IN)!=0) { retval=3; break; } sprintf(str,"sbbsexec_hungup%d",node_num); hungup_event=OpenEvent( EVENT_ALL_ACCESS, /* access flag */ FALSE, /* inherit flag */ str); /* pointer to event-object name */ if(hungup_event==NULL) { lprintf(LOG_ERR,"!VDD_OPEN: Error %d opening %s" ,GetLastError(),str); retval=4; break; } sprintf(str,"sbbsexec_hangup%d",node_num); hangup_event=OpenEvent( EVENT_ALL_ACCESS, /* access flag */ FALSE, /* inherit flag */ str); /* pointer to event-object name */ if(hangup_event==NULL) { lprintf(LOG_WARNING,"!VDD_OPEN: Error %d opening %s" ,GetLastError(),str); } status_poll=0; inbuf_poll=0; online_poll=0; yields=0; lprintf(LOG_INFO,"Yield interval: %f milliseconds", yield_interval); if(virtualize_uart) { lprintf(LOG_INFO,"Virtualizing UART (0x%x, IRQ %u)" ,uart_io_base, uart_irq); IOHandlers.inb_handler = uart_rdport; IOHandlers.outb_handler = uart_wrport; PortRange.First=uart_io_base; PortRange.Last=uart_io_base + UART_IO_RANGE; VDDInstallIOHook((HANDLE)getAX(), 1, &PortRange, &IOHandlers); interrupt_event=CreateEvent(NULL,FALSE,FALSE,NULL); InitializeCriticalSection(&interrupt_mutex); _beginthread(interrupt_thread, 0, NULL); } lprintf(LOG_DEBUG,"VDD_OPEN: Opened successfully (wrslot=%p)", wrslot); _beginthread(input_thread, 0, NULL); retval=0; break; case VDD_CLOSE: lprintf(LOG_INFO,"VDD_CLOSE: rdbuf=%u " "status_poll=%u inbuf_poll=%u online_poll=%u yields=%u vdd_yields=%u vdd_calls=%u" ,RingBufFull(&rdbuf),status_poll,inbuf_poll,online_poll ,yields,vdd_yields,vdd_calls); lprintf(LOG_INFO," read=%u bytes (in %u calls)",bytes_read,reads); lprintf(LOG_INFO," wrote=%u bytes (in %u calls)",bytes_written,writes); if(virtualize_uart) { lprintf(LOG_INFO,"Uninstalling Virtualizaed UART IO Hook"); VDDDeInstallIOHook((HANDLE)getAX(), 1, &PortRange); } CloseHandle(rdslot); CloseHandle(wrslot); if(hungup_event!=NULL) CloseHandle(hungup_event); if(hangup_event!=NULL) CloseHandle(hangup_event); #if 0 /* This isn't strictly necessary... and possibly the cause of a NULL dereference in the input_thread */ RingBufDispose(&rdbuf); #endif status_poll=0; retval=0; break; case VDD_READ: count = getCX(); if(count != 1) lprintf(LOG_DEBUG,"VDD_READ of %d",count); p = (BYTE*) GetVDMPointer((ULONG)((getES() << 16)|getDI()) ,count,FALSE); retval=vdd_read(p, count); reads++; bytes_read+=retval; reset_yield(); break; case VDD_PEEK: count = getCX(); if(count != 1) lprintf(LOG_DEBUG,"VDD_PEEK of %d",count); p = (BYTE*) GetVDMPointer((ULONG)((getES() << 16)|getDI()) ,count,FALSE); retval=RingBufPeek(&rdbuf,p,count); reset_yield(); break; case VDD_WRITE: count = getCX(); if(count != 1) lprintf(LOG_DEBUG,"VDD_WRITE of %d",count); p = (BYTE*) GetVDMPointer((ULONG)((getES() << 16)|getDI()) ,count,FALSE); if(!WriteFile(wrslot,p,count,&retval,NULL)) { lprintf(LOG_ERR,"!VDD_WRITE: WriteFile Error %d (size=%d)" ,GetLastError(),retval); retval=0; } else { writes++; bytes_written+=retval; reset_yield(); } break; case VDD_STATUS: status_poll++; count = getCX(); if(count != sizeof(vdd_status_t)) { lprintf(LOG_DEBUG,"!VDD_STATUS: wrong size (%d!=%d)",count,sizeof(vdd_status_t)); retval=sizeof(vdd_status_t); break; } status = (vdd_status_t*) GetVDMPointer((ULONG)((getES() << 16)|getDI()) ,count,FALSE); status->inbuf_size=RINGBUF_SIZE_IN; status->inbuf_full=RingBufFull(&rdbuf); msgs=0; /* OUTBUF FULL/SIZE */ if(!GetMailslotInfo( wrslot, /* mailslot handle */ &status->outbuf_size, /* address of maximum message size */ &status->outbuf_full, /* address of size of next message */ &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)" ,wrslot ,GetLastError(), msgs, status->inbuf_full, status->inbuf_size); status->outbuf_full=0; status->outbuf_size=DEFAULT_MAX_MSG_SIZE; } else lprintf(LOG_DEBUG,"VDD_STATUS: MailSlot maxmsgsize=%u, nextmsgsize=%u, msgs=%u" ,status->outbuf_size ,status->outbuf_full ,msgs); if(status->outbuf_full==MAILSLOT_NO_MESSAGE) status->outbuf_full=0; status->outbuf_full*=msgs; /* ONLINE */ if(WaitForSingleObject(hungup_event,0)==WAIT_OBJECT_0) status->online=0; else status->online=1; retval=0; /* success */ break; case VDD_INBUF_PURGE: RingBufReInit(&rdbuf); retval=0; break; case VDD_OUTBUF_PURGE: lprintf(LOG_WARNING,"!VDD_OUTBUF_PURGE: NOT IMPLEMENTED"); retval=0; break; case VDD_INBUF_FULL: retval=RingBufFull(&rdbuf); inbuf_poll++; break; case VDD_INBUF_SIZE: retval=RINGBUF_SIZE_IN; break; case VDD_OUTBUF_FULL: if(!GetMailslotInfo( wrslot, /* mailslot handle */ NULL, /* address of maximum message size */ &retval, /* address of size of next message */ &msgs, /* address of number of messages */ NULL /* address of read time-out */ )) retval=0; if(retval==MAILSLOT_NO_MESSAGE) retval=0; retval*=msgs; break; case VDD_OUTBUF_SIZE: if(!GetMailslotInfo( wrslot, /* mailslot handle */ &retval, /* address of maximum message size */ NULL, /* address of size of next message */ NULL, /* address of number of messages */ NULL /* address of read time-out */ )) retval=DEFAULT_MAX_MSG_SIZE; break; case VDD_ONLINE: if(WaitForSingleObject(hungup_event,0)==WAIT_OBJECT_0) retval=0; else retval=1; online_poll++; break; case VDD_YIELD: /* forced yield */ vdd_yields++; yield(); break; case VDD_MAYBE_YIELD: /* yield if YieldInterval is enabled and expired */ maybe_yield(); break; case VDD_LOAD_INI_FILE: /* Load and parse settings file */ { FILE* fp; char cwd[MAX_PATH+1]; /* Load exec/sbbsexec.ini first (setting default values) */ count = getCX(); p = (BYTE*)GetVDMPointer((ULONG)((getES() << 16)|getDI()) ,count,FALSE); iniFileName(ini_fname, sizeof(ini_fname), p, INI_FILENAME); if((fp=fopen(ini_fname,"r"))!=NULL) { ini=iniReadFile(fp); fclose(fp); parse_ini(ROOT_SECTION); } /* Load cwd/sbbsexec.ini second (over-riding default values) */ GetCurrentDirectory(sizeof(cwd),cwd); iniFileName(ini_fname, sizeof(ini_fname), cwd, INI_FILENAME); if((fp=fopen(ini_fname,"r"))!=NULL) { ini=iniReadFile(fp); fclose(fp); parse_ini(ROOT_SECTION); } } break; case VDD_LOAD_INI_SECTION: /* Parse (program-specific) sub-section of settings file */ count = getCX(); p = (BYTE*)GetVDMPointer((ULONG)((getES() << 16)|getDI()) ,count,FALSE); parse_ini(p); break; case VDD_DEBUG_OUTPUT: /* Send string to debug output */ count = getCX(); p = (BYTE*)GetVDMPointer((ULONG)((getES() << 16)|getDI()) ,count,FALSE); lputs(LOG_INFO, p); break; case VDD_HANGUP: hangup(); break; default: lprintf(LOG_ERR,"!UNKNOWN VDD_OP: %d",getBL()); break; } setAX((WORD)retval); }
VOID uart_rdport(WORD port, PBYTE data) { int reg = port - uart_io_base; DWORD avail; lprintf(LOG_DEBUG,"read of port: %x (%s)", port, uart_reg_desc[reg]); switch(reg) { case UART_BASE: if(uart_lcr_reg&UART_LCR_DLAB) { lprintf(LOG_DEBUG,"reading divisor latch LSB"); *data = uart_divisor_latch_lsb; break; } if((avail=RingBufFull(&rdbuf))!=0) { vdd_read(data,sizeof(BYTE)); lprintf(LOG_DEBUG,"READ DATA: %s", chr(*data)); avail--; reset_yield(); } else *data=0; if(avail==0) { lprintf(LOG_DEBUG,"No more data"); /* Clear the data ready bit in the LSR */ uart_lsr_reg &= ~UART_LSR_DATA_READY; /* Clear data ready interrupt identification in IIR */ deassert_interrupt(UART_IER_RX_DATA); } else /* re-assert RX data (increment the semaphore) */ assert_interrupt(UART_IER_RX_DATA); break; case UART_IER: if(uart_lcr_reg&UART_LCR_DLAB) { lprintf(LOG_DEBUG,"reading divisor latch MSB"); *data = uart_divisor_latch_msb; } else *data = uart_ier_reg; break; case UART_IIR: /* Report IIR based on *priority* of pending interrupts */ if(pending_interrupts & UART_IER_LINE_STATUS) *data = UART_IIR_LINE_STATUS; else if(pending_interrupts & UART_IER_RX_DATA) *data = UART_IIR_RX_DATA; else if(pending_interrupts & UART_IER_TX_EMPTY) { *data = UART_IIR_TX_EMPTY; /* "Transmit Holding Register Empty" interrupt */ /* is reset on read of IIR */ deassert_interrupt(UART_IER_TX_EMPTY); } else if(pending_interrupts & UART_IER_MODEM_STATUS) *data = UART_IIR_MODEM_STATUS; else *data = UART_IIR_NONE; break; case UART_LCR: *data = uart_lcr_reg; break; case UART_MCR: *data = uart_mcr_reg; break; case UART_LSR: *data = uart_lsr_reg; maybe_yield(); /* Clear line status interrupt pending */ deassert_interrupt(UART_IER_LINE_STATUS); break; case UART_MSR: if(WaitForSingleObject(hungup_event,0)==WAIT_OBJECT_0) uart_msr_reg &=~ UART_MSR_DCD; else uart_msr_reg |= UART_MSR_DCD; *data = uart_msr_reg; maybe_yield(); /* Clear modem status interrupt pending */ deassert_interrupt(UART_IER_MODEM_STATUS); break; case UART_SCRATCH: *data = uart_scratch_reg; break; default: lprintf(LOG_ERR,"UNSUPPORTED register: %u", reg); break; } if(reg!=UART_BASE) lprintf(LOG_DEBUG, "returning 0x%02X", *data); }