|
|
1.1 ! root 1: /* sbbsexec.c */ ! 2: ! 3: /* Synchronet Windows NT/2000 VDD for FOSSIL and DOS I/O Interrupts */ ! 4: ! 5: /* $Id: sbbsexec.c,v 1.38 2006/10/28 03:56:36 rswindell Exp $ */ ! 6: ! 7: /**************************************************************************** ! 8: * @format.tab-size 4 (Plain Text/Source Code File Header) * ! 9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * ! 10: * * ! 11: * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html * ! 12: * * ! 13: * This program is free software; you can redistribute it and/or * ! 14: * modify it under the terms of the GNU General Public License * ! 15: * as published by the Free Software Foundation; either version 2 * ! 16: * of the License, or (at your option) any later version. * ! 17: * See the GNU General Public License for more details: gpl.txt or * ! 18: * http://www.fsf.org/copyleft/gpl.html * ! 19: * * ! 20: * Anonymous FTP access to the most recent released source is available at * ! 21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * ! 22: * * ! 23: * Anonymous CVS access to the development source and modification history * ! 24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: * ! 25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login * ! 26: * (just hit return, no password is necessary) * ! 27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src * ! 28: * * ! 29: * For Synchronet coding style and modification guidelines, see * ! 30: * http://www.synchro.net/source.html * ! 31: * * ! 32: * You are encouraged to submit any modifications (preferably in Unix diff * ! 33: * format) via e-mail to [email protected] * ! 34: * * ! 35: * Note: If this box doesn't appear square, then you need to fix your tabs. * ! 36: ****************************************************************************/ ! 37: ! 38: #include <windows.h> ! 39: #include <stdio.h> ! 40: #include <vddsvc.h> ! 41: #include "uartdefs.h" ! 42: #include "vdd_func.h" ! 43: #include "ringbuf.h" ! 44: #include "genwrap.h" ! 45: #include "dirwrap.h" ! 46: #include "threadwrap.h" ! 47: #include "ini_file.h" ! 48: ! 49: #define INI_FILENAME "sbbsexec.ini" ! 50: #define RINGBUF_SIZE_IN 10000 ! 51: #define DEFAULT_MAX_MSG_SIZE 4000 ! 52: #define LINEAR_RX_BUFLEN 5000 ! 53: ! 54: /* UART Parameters and virtual registers */ ! 55: WORD uart_io_base = UART_COM1_IO_BASE; /* COM1 */ ! 56: BYTE uart_irq = UART_COM1_IRQ; ! 57: BYTE uart_ier_reg = 0; ! 58: BYTE uart_lcr_reg = UART_LCR_8_DATA_BITS; ! 59: BYTE uart_mcr_reg = UART_MCR_RTS | UART_MCR_DTR; ! 60: BYTE uart_lsr_reg = UART_LSR_EMPTY_DATA | UART_LSR_EMPTY_XMIT; ! 61: BYTE uart_msr_reg = UART_MSR_CTS | UART_MSR_DSR; ! 62: BYTE uart_scratch_reg = 0; ! 63: BYTE uart_divisor_latch_lsb = 0x03; /* 38400 */ ! 64: BYTE uart_divisor_latch_msb = 0x00; ! 65: ! 66: #if defined (_DEBUG) ! 67: int log_level = LOG_DEBUG; ! 68: #else ! 69: int log_level = LOG_WARNING; ! 70: #endif ! 71: ! 72: BOOL virtualize_uart=TRUE; ! 73: double yield_interval=1.0; ! 74: BOOL hangup_supported=TRUE; ! 75: HANDLE hangup_event=NULL; ! 76: HANDLE hungup_event=NULL; ! 77: HANDLE interrupt_event=NULL; ! 78: HANDLE rdslot=INVALID_HANDLE_VALUE; ! 79: HANDLE wrslot=INVALID_HANDLE_VALUE; ! 80: RingBuf rdbuf; ! 81: str_list_t ini; ! 82: char ini_fname[MAX_PATH+1]; ! 83: char revision[16]; ! 84: ! 85: void lputs(int level, char* msg) ! 86: { ! 87: char buf[1024]; ! 88: if(level > log_level) ! 89: return; ! 90: ! 91: SAFEPRINTF(buf,"SBBS: %s\r\n", msg); ! 92: OutputDebugString(buf); ! 93: } ! 94: ! 95: static void lprintf(int level, const char *fmt, ...) ! 96: { ! 97: char sbuf[1024]; ! 98: va_list argptr; ! 99: ! 100: if(level > log_level) ! 101: return; ! 102: ! 103: va_start(argptr,fmt); ! 104: _vsnprintf(sbuf,sizeof(sbuf),fmt,argptr); ! 105: sbuf[sizeof(sbuf)-1]=0; ! 106: va_end(argptr); ! 107: lputs(level,sbuf); ! 108: } ! 109: ! 110: void hangup() ! 111: { ! 112: if(hangup_supported && hangup_event!=NULL) { ! 113: lprintf(LOG_DEBUG,"Hanging-up at application request"); ! 114: SetEvent(hangup_event); ! 115: } ! 116: } ! 117: ! 118: void parse_ini(char* program) ! 119: { ! 120: char section[MAX_PATH+1]; ! 121: ! 122: if(ini==NULL) /* no initialization file */ ! 123: return; ! 124: ! 125: /* Read the root section of the sbbsexec.ini file */ ! 126: log_level=iniGetLogLevel(ini,program,"LogLevel",log_level); ! 127: if(iniGetBool(ini,program,"Debug",FALSE)) ! 128: log_level=LOG_DEBUG; ! 129: yield_interval=iniGetFloat(ini,program,"YieldInterval",yield_interval); ! 130: hangup_supported=iniGetBool(ini,program,"CanDisconnect",hangup_supported); ! 131: ! 132: lprintf(LOG_INFO,"Parsed %s section of %s" ! 133: ,program==ROOT_SECTION ? "root" : program ! 134: ,ini_fname); ! 135: ! 136: /* [UART] section */ ! 137: if(program==ROOT_SECTION) ! 138: SAFECOPY(section,"UART"); ! 139: else ! 140: SAFEPRINTF(section,"%s.UART",program); ! 141: ! 142: virtualize_uart=iniGetBool(ini,section,"Virtualize",virtualize_uart); ! 143: switch(iniGetInteger(ini,section,"ComPort",0)) { ! 144: case 1: /* COM1 */ ! 145: uart_irq =UART_COM1_IRQ; ! 146: uart_io_base =UART_COM1_IO_BASE; ! 147: break; ! 148: case 2: /* COM2 */ ! 149: uart_irq =UART_COM2_IRQ; ! 150: uart_io_base =UART_COM2_IO_BASE; ! 151: break; ! 152: case 3: /* COM3 */ ! 153: uart_irq =UART_COM3_IRQ; ! 154: uart_io_base =UART_COM3_IO_BASE; ! 155: break; ! 156: case 4: /* COM4 */ ! 157: uart_irq =UART_COM4_IRQ; ! 158: uart_io_base =UART_COM4_IO_BASE; ! 159: break; ! 160: } ! 161: uart_irq=(BYTE)iniGetShortInt(ini,section,"IRQ",uart_irq); ! 162: uart_io_base=iniGetShortInt(ini,section,"Address",uart_io_base); ! 163: ! 164: lprintf(LOG_INFO,"Parsed %s section of %s" ! 165: ,section ! 166: ,ini_fname); ! 167: } ! 168: ! 169: ! 170: /* Mutex-protected pending interrupt "queue" */ ! 171: int pending_interrupts = 0; ! 172: CRITICAL_SECTION interrupt_mutex; ! 173: ! 174: void set_interrupt_pending(BYTE intr, BOOL assert) ! 175: { ! 176: EnterCriticalSection(&interrupt_mutex); ! 177: lprintf(LOG_DEBUG,"%sasserting interrupt %02X (pending: %02X, IER: %02X)" ! 178: ,assert ? "" : "de-", intr ! 179: ,pending_interrupts ! 180: ,uart_ier_reg); ! 181: if(assert) { ! 182: if(uart_ier_reg&intr) { /* is interrupt enabled? */ ! 183: pending_interrupts |= intr; /* flag as pending */ ! 184: SetEvent(interrupt_event); ! 185: } ! 186: } else /* de-assert */ ! 187: pending_interrupts &= ~intr; /* remove as pending */ ! 188: ! 189: LeaveCriticalSection(&interrupt_mutex); ! 190: } ! 191: ! 192: #define assert_interrupt(i) set_interrupt_pending(i, TRUE) ! 193: #define deassert_interrupt(i) set_interrupt_pending(i, FALSE) ! 194: ! 195: void _cdecl interrupt_thread(void *arg) ! 196: { ! 197: while(1) { ! 198: if(WaitForSingleObject(interrupt_event,INFINITE)!=WAIT_OBJECT_0) ! 199: break; ! 200: if((uart_ier_reg&pending_interrupts) != 0) { ! 201: lprintf(LOG_DEBUG,"VDDSimulateInterrupt (pending: %02X) - IER: %02X" ! 202: ,pending_interrupts, uart_ier_reg); ! 203: VDDSimulateInterrupt(ICA_MASTER, uart_irq, /* count: */1); ! 204: } ! 205: #if 0 ! 206: /* "Real 16550s should always reassert ! 207: * this interrupt whenever the transmitter is idle and ! 208: * the interrupt is enabled." ! 209: */ ! 210: if(pending_interrupts==0 && uart_ier_reg&UART_IER_TX_EMPTY) ! 211: pending_interrupts|=UART_IER_TX_EMPTY; ! 212: #endif ! 213: } ! 214: } ! 215: ! 216: void _cdecl input_thread(void* arg) ! 217: { ! 218: char buf[LINEAR_RX_BUFLEN]; ! 219: int count; ! 220: ! 221: while(1) { ! 222: count=0; ! 223: if(!ReadFile(rdslot,buf,sizeof(buf),&count,NULL)) { ! 224: if(GetLastError()==ERROR_HANDLE_EOF) /* closed by VDD_CLOSE */ ! 225: break; ! 226: lprintf(LOG_ERR,"!input_thread: ReadFile Error %d (size=%d)" ! 227: ,GetLastError(),count); ! 228: continue; ! 229: } ! 230: if(count==0) { ! 231: lprintf(LOG_ERR,"!input_thread: ReadFile read 0"); ! 232: continue; ! 233: } ! 234: RingBufWrite(&rdbuf,buf,count); ! 235: /* Set the "Data ready" bit in the LSR */ ! 236: uart_lsr_reg |= UART_LSR_DATA_READY; ! 237: ! 238: assert_interrupt(UART_IER_RX_DATA); /* assert rx data interrupt */ ! 239: } ! 240: } ! 241: ! 242: unsigned vdd_read(BYTE* p, unsigned count) ! 243: { ! 244: sem_wait(rdbuf.sem); ! 245: count=RingBufRead(&rdbuf,p,count); ! 246: if(count==0) ! 247: lprintf(LOG_ERR,"!VDD_READ: RingBufRead read 0"); ! 248: ! 249: return(count); ! 250: } ! 251: ! 252: unsigned yields=0; ! 253: ! 254: void yield() ! 255: { ! 256: yields++; ! 257: lprintf(LOG_DEBUG,"Yielding (yields=%u)", yields); ! 258: Sleep(1); ! 259: } ! 260: ! 261: long double last_yield=0; ! 262: ! 263: void maybe_yield() ! 264: { ! 265: long double t; ! 266: ! 267: t=xp_timer(); ! 268: ! 269: if(yield_interval && (t-last_yield)*1000.0 >= yield_interval) { ! 270: yield(); ! 271: last_yield=t; ! 272: } ! 273: } ! 274: ! 275: void reset_yield() ! 276: { ! 277: last_yield=xp_timer(); ! 278: } ! 279: ! 280: /***********************/ ! 281: /* UART Virtualization */ ! 282: /***********************/ ! 283: ! 284: static char *chr(uchar ch) ! 285: { ! 286: static char str[25]; ! 287: ! 288: if(ch>=' ' && ch<='~') ! 289: sprintf(str,"'%c' (%02Xh)",ch,ch); ! 290: else if(ch<' ') ! 291: sprintf(str,"^%c (%02Xh)",'@'+ch,ch); ! 292: else ! 293: sprintf(str,"%u (%02Xh)",ch,ch); ! 294: return(str); ! 295: } ! 296: ! 297: VOID uart_wrport(WORD port, BYTE data) ! 298: { ! 299: int reg = port - uart_io_base; ! 300: int retval; ! 301: ! 302: lprintf(LOG_DEBUG,"write of port: %x (%s) <- %02X", port, uart_reg_desc[reg], data); ! 303: ! 304: switch(reg) { ! 305: case UART_BASE: ! 306: if(uart_lcr_reg&UART_LCR_DLAB) { ! 307: uart_divisor_latch_lsb = data; ! 308: lprintf(LOG_DEBUG,"set divisor latch low byte: %02X", data); ! 309: } else { ! 310: lprintf(LOG_DEBUG,"WRITE DATA: %s", chr(data)); ! 311: if(!WriteFile(wrslot,&data,sizeof(BYTE),&retval,NULL)) { ! 312: lprintf(LOG_ERR,"!VDD_WRITE: WriteFile Error %d (size=%d)" ! 313: ,GetLastError(),retval); ! 314: } else { ! 315: assert_interrupt(UART_IER_TX_EMPTY); ! 316: reset_yield(); ! 317: } ! 318: } ! 319: break; ! 320: case UART_IER: ! 321: if(uart_lcr_reg&UART_LCR_DLAB) { ! 322: uart_divisor_latch_msb = data; ! 323: lprintf(LOG_DEBUG,"set divisor latch high byte: %02X", data); ! 324: } else ! 325: uart_ier_reg = data; ! 326: assert_interrupt(UART_IER_TX_EMPTY); /* should this be re-asserted for all writes? */ ! 327: break; ! 328: case UART_IIR: /* FCR not supported */ ! 329: break; ! 330: case UART_LCR: ! 331: uart_lcr_reg = data; ! 332: break; ! 333: case UART_MCR: ! 334: uart_mcr_reg = data; ! 335: if((uart_mcr_reg&UART_MCR_DTR) == 0) /* Dropping DTR (i.e. "hangup") */ ! 336: hangup(); ! 337: break; ! 338: case UART_SCRATCH: ! 339: uart_scratch_reg = data; ! 340: break; ! 341: default: ! 342: lprintf(LOG_ERR,"UNSUPPORTED register: %u", reg); ! 343: break; ! 344: ! 345: } ! 346: } ! 347: ! 348: VOID uart_rdport(WORD port, PBYTE data) ! 349: { ! 350: int reg = port - uart_io_base; ! 351: DWORD avail; ! 352: ! 353: lprintf(LOG_DEBUG,"read of port: %x (%s)", port, uart_reg_desc[reg]); ! 354: ! 355: switch(reg) { ! 356: case UART_BASE: ! 357: if(uart_lcr_reg&UART_LCR_DLAB) { ! 358: lprintf(LOG_DEBUG,"reading divisor latch LSB"); ! 359: *data = uart_divisor_latch_lsb; ! 360: break; ! 361: } ! 362: if((avail=RingBufFull(&rdbuf))!=0) { ! 363: vdd_read(data,sizeof(BYTE)); ! 364: lprintf(LOG_DEBUG,"READ DATA: %s", chr(*data)); ! 365: avail--; ! 366: reset_yield(); ! 367: } else ! 368: *data=0; ! 369: if(avail==0) { ! 370: lprintf(LOG_DEBUG,"No more data"); ! 371: /* Clear the data ready bit in the LSR */ ! 372: uart_lsr_reg &= ~UART_LSR_DATA_READY; ! 373: ! 374: /* Clear data ready interrupt identification in IIR */ ! 375: deassert_interrupt(UART_IER_RX_DATA); ! 376: } else /* re-assert RX data (increment the semaphore) */ ! 377: assert_interrupt(UART_IER_RX_DATA); ! 378: break; ! 379: case UART_IER: ! 380: if(uart_lcr_reg&UART_LCR_DLAB) { ! 381: lprintf(LOG_DEBUG,"reading divisor latch MSB"); ! 382: *data = uart_divisor_latch_msb; ! 383: } else ! 384: *data = uart_ier_reg; ! 385: break; ! 386: case UART_IIR: ! 387: /* Report IIR based on *priority* of pending interrupts */ ! 388: if(pending_interrupts & UART_IER_LINE_STATUS) ! 389: *data = UART_IIR_LINE_STATUS; ! 390: else if(pending_interrupts & UART_IER_RX_DATA) ! 391: *data = UART_IIR_RX_DATA; ! 392: else if(pending_interrupts & UART_IER_TX_EMPTY) { ! 393: *data = UART_IIR_TX_EMPTY; ! 394: /* "Transmit Holding Register Empty" interrupt */ ! 395: /* is reset on read of IIR */ ! 396: deassert_interrupt(UART_IER_TX_EMPTY); ! 397: } ! 398: else if(pending_interrupts & UART_IER_MODEM_STATUS) ! 399: *data = UART_IIR_MODEM_STATUS; ! 400: else ! 401: *data = UART_IIR_NONE; ! 402: break; ! 403: case UART_LCR: ! 404: *data = uart_lcr_reg; ! 405: break; ! 406: case UART_MCR: ! 407: *data = uart_mcr_reg; ! 408: break; ! 409: case UART_LSR: ! 410: *data = uart_lsr_reg; ! 411: maybe_yield(); ! 412: /* Clear line status interrupt pending */ ! 413: deassert_interrupt(UART_IER_LINE_STATUS); ! 414: break; ! 415: case UART_MSR: ! 416: if(WaitForSingleObject(hungup_event,0)==WAIT_OBJECT_0) ! 417: uart_msr_reg &=~ UART_MSR_DCD; ! 418: else ! 419: uart_msr_reg |= UART_MSR_DCD; ! 420: *data = uart_msr_reg; ! 421: maybe_yield(); ! 422: /* Clear modem status interrupt pending */ ! 423: deassert_interrupt(UART_IER_MODEM_STATUS); ! 424: break; ! 425: case UART_SCRATCH: ! 426: *data = uart_scratch_reg; ! 427: break; ! 428: default: ! 429: lprintf(LOG_ERR,"UNSUPPORTED register: %u", reg); ! 430: break; ! 431: } ! 432: ! 433: if(reg!=UART_BASE) ! 434: lprintf(LOG_DEBUG, "returning 0x%02X", *data); ! 435: } ! 436: ! 437: /* VDD DOS Interface (mainly for FOSSIL driver in dosxtrn.exe) */ ! 438: ! 439: __declspec(dllexport) void __cdecl VDDDispatch(void) ! 440: { ! 441: char str[512]; ! 442: DWORD count; ! 443: DWORD msgs; ! 444: int retval; ! 445: int node_num; ! 446: BYTE* p; ! 447: vdd_status_t* status; ! 448: static DWORD writes; ! 449: static DWORD bytes_written; ! 450: static DWORD reads; ! 451: static DWORD bytes_read; ! 452: static DWORD inbuf_poll; ! 453: static DWORD online_poll; ! 454: static DWORD status_poll; ! 455: static DWORD vdd_yields; ! 456: static DWORD vdd_calls; ! 457: VDD_IO_HANDLERS IOHandlers = { NULL }; ! 458: static VDD_IO_PORTRANGE PortRange; ! 459: ! 460: retval=0; ! 461: node_num=getBH(); ! 462: ! 463: lprintf(LOG_DEBUG,"VDD_OP: (handle=%d) %d (arg=%X)", getAX(),getBL(),getCX()); ! 464: vdd_calls++; ! 465: ! 466: switch(getBL()) { ! 467: ! 468: case VDD_OPEN: ! 469: ! 470: sscanf("$Revision: 1.38 $", "%*s %s", revision); ! 471: ! 472: lprintf(LOG_INFO,"Synchronet Virtual Device Driver, rev %s %s %s" ! 473: ,revision, __DATE__, __TIME__); ! 474: #if 0 ! 475: sprintf(str,"sbbsexec%d.log",node_num); ! 476: fp=fopen(str,"wb"); ! 477: #endif ! 478: ! 479: sprintf(str,"\\\\.\\mailslot\\sbbsexec\\wr%d",node_num); ! 480: rdslot=CreateMailslot(str ! 481: ,LINEAR_RX_BUFLEN /* Max message size (0=any) */ ! 482: ,MAILSLOT_WAIT_FOREVER /* Read timeout */ ! 483: ,NULL); ! 484: if(rdslot==INVALID_HANDLE_VALUE) { ! 485: lprintf(LOG_ERR,"!VDD_OPEN: Error %d opening %s" ! 486: ,GetLastError(),str); ! 487: retval=1; ! 488: break; ! 489: } ! 490: ! 491: sprintf(str,"\\\\.\\mailslot\\sbbsexec\\rd%d",node_num); ! 492: wrslot=CreateFile(str ! 493: ,GENERIC_WRITE ! 494: ,FILE_SHARE_READ ! 495: ,NULL ! 496: ,OPEN_EXISTING ! 497: ,FILE_ATTRIBUTE_NORMAL ! 498: ,(HANDLE) NULL); ! 499: if(wrslot==INVALID_HANDLE_VALUE) { ! 500: lprintf(LOG_ERR,"!VDD_OPEN: Error %d opening %s" ! 501: ,GetLastError(),str); ! 502: retval=2; ! 503: break; ! 504: } ! 505: ! 506: if(RingBufInit(&rdbuf, RINGBUF_SIZE_IN)!=0) { ! 507: retval=3; ! 508: break; ! 509: } ! 510: ! 511: sprintf(str,"sbbsexec_hungup%d",node_num); ! 512: hungup_event=OpenEvent( ! 513: EVENT_ALL_ACCESS, /* access flag */ ! 514: FALSE, /* inherit flag */ ! 515: str); /* pointer to event-object name */ ! 516: if(hungup_event==NULL) { ! 517: lprintf(LOG_ERR,"!VDD_OPEN: Error %d opening %s" ! 518: ,GetLastError(),str); ! 519: retval=4; ! 520: break; ! 521: } ! 522: ! 523: sprintf(str,"sbbsexec_hangup%d",node_num); ! 524: hangup_event=OpenEvent( ! 525: EVENT_ALL_ACCESS, /* access flag */ ! 526: FALSE, /* inherit flag */ ! 527: str); /* pointer to event-object name */ ! 528: if(hangup_event==NULL) { ! 529: lprintf(LOG_WARNING,"!VDD_OPEN: Error %d opening %s" ! 530: ,GetLastError(),str); ! 531: } ! 532: ! 533: status_poll=0; ! 534: inbuf_poll=0; ! 535: online_poll=0; ! 536: yields=0; ! 537: ! 538: lprintf(LOG_INFO,"Yield interval: %f milliseconds", yield_interval); ! 539: ! 540: if(virtualize_uart) { ! 541: lprintf(LOG_INFO,"Virtualizing UART (0x%x, IRQ %u)" ! 542: ,uart_io_base, uart_irq); ! 543: ! 544: IOHandlers.inb_handler = uart_rdport; ! 545: IOHandlers.outb_handler = uart_wrport; ! 546: PortRange.First=uart_io_base; ! 547: PortRange.Last=uart_io_base + UART_IO_RANGE; ! 548: ! 549: VDDInstallIOHook((HANDLE)getAX(), 1, &PortRange, &IOHandlers); ! 550: ! 551: interrupt_event=CreateEvent(NULL,FALSE,FALSE,NULL); ! 552: InitializeCriticalSection(&interrupt_mutex); ! 553: ! 554: _beginthread(interrupt_thread, 0, NULL); ! 555: } ! 556: ! 557: lprintf(LOG_DEBUG,"VDD_OPEN: Opened successfully"); ! 558: ! 559: _beginthread(input_thread, 0, NULL); ! 560: ! 561: retval=0; ! 562: break; ! 563: ! 564: case VDD_CLOSE: ! 565: lprintf(LOG_INFO,"VDD_CLOSE: rdbuf=%u " ! 566: "status_poll=%u inbuf_poll=%u online_poll=%u yields=%u vdd_yields=%u vdd_calls=%u" ! 567: ,RingBufFull(&rdbuf),status_poll,inbuf_poll,online_poll ! 568: ,yields,vdd_yields,vdd_calls); ! 569: lprintf(LOG_INFO," read=%u bytes (in %u calls)",bytes_read,reads); ! 570: lprintf(LOG_INFO," wrote=%u bytes (in %u calls)",bytes_written,writes); ! 571: ! 572: if(virtualize_uart) { ! 573: lprintf(LOG_INFO,"Uninstalling Virtualizaed UART IO Hook"); ! 574: VDDDeInstallIOHook((HANDLE)getAX(), 1, &PortRange); ! 575: } ! 576: ! 577: CloseHandle(rdslot); ! 578: CloseHandle(wrslot); ! 579: if(hungup_event!=NULL) ! 580: CloseHandle(hungup_event); ! 581: if(hangup_event!=NULL) ! 582: CloseHandle(hangup_event); ! 583: ! 584: #if 0 /* This isn't strictly necessary... ! 585: and possibly the cause of a NULL dereference in the input_thread */ ! 586: RingBufDispose(&rdbuf); ! 587: #endif ! 588: status_poll=0; ! 589: retval=0; ! 590: ! 591: break; ! 592: ! 593: case VDD_READ: ! 594: count = getCX(); ! 595: if(count != 1) ! 596: lprintf(LOG_DEBUG,"VDD_READ of %d",count); ! 597: p = (BYTE*) GetVDMPointer((ULONG)((getES() << 16)|getDI()) ! 598: ,count,FALSE); ! 599: retval=vdd_read(p, count); ! 600: reads++; ! 601: bytes_read+=retval; ! 602: reset_yield(); ! 603: break; ! 604: ! 605: case VDD_PEEK: ! 606: count = getCX(); ! 607: if(count != 1) ! 608: lprintf(LOG_DEBUG,"VDD_PEEK of %d",count); ! 609: ! 610: p = (BYTE*) GetVDMPointer((ULONG)((getES() << 16)|getDI()) ! 611: ,count,FALSE); ! 612: retval=RingBufPeek(&rdbuf,p,count); ! 613: reset_yield(); ! 614: break; ! 615: ! 616: case VDD_WRITE: ! 617: count = getCX(); ! 618: if(count != 1) ! 619: lprintf(LOG_DEBUG,"VDD_WRITE of %d",count); ! 620: p = (BYTE*) GetVDMPointer((ULONG)((getES() << 16)|getDI()) ! 621: ,count,FALSE); ! 622: if(!WriteFile(wrslot,p,count,&retval,NULL)) { ! 623: lprintf(LOG_ERR,"!VDD_WRITE: WriteFile Error %d (size=%d)" ! 624: ,GetLastError(),retval); ! 625: retval=0; ! 626: } else { ! 627: writes++; ! 628: bytes_written+=retval; ! 629: reset_yield(); ! 630: } ! 631: break; ! 632: ! 633: case VDD_STATUS: ! 634: ! 635: status_poll++; ! 636: count = getCX(); ! 637: if(count != sizeof(vdd_status_t)) { ! 638: lprintf(LOG_DEBUG,"!VDD_STATUS: wrong size (%d!=%d)",count,sizeof(vdd_status_t)); ! 639: retval=sizeof(vdd_status_t); ! 640: break; ! 641: } ! 642: status = (vdd_status_t*) GetVDMPointer((ULONG)((getES() << 16)|getDI()) ! 643: ,count,FALSE); ! 644: ! 645: status->inbuf_full=RingBufFull(&rdbuf); ! 646: ! 647: /* OUTBUF FULL/SIZE */ ! 648: if(!GetMailslotInfo( ! 649: wrslot, /* mailslot handle */ ! 650: &status->outbuf_size, /* address of maximum message size */ ! 651: &status->outbuf_full, /* address of size of next message */ ! 652: &msgs, /* address of number of messages */ ! 653: NULL /* address of read time-out */ ! 654: )) { ! 655: status->outbuf_full=0; ! 656: status->outbuf_size=DEFAULT_MAX_MSG_SIZE; ! 657: } ! 658: if(status->outbuf_full==MAILSLOT_NO_MESSAGE) ! 659: status->outbuf_full=0; ! 660: status->outbuf_full*=msgs; ! 661: ! 662: /* ONLINE */ ! 663: if(WaitForSingleObject(hungup_event,0)==WAIT_OBJECT_0) ! 664: status->online=0; ! 665: else ! 666: status->online=1; ! 667: ! 668: retval=0; /* success */ ! 669: break; ! 670: ! 671: case VDD_INBUF_PURGE: ! 672: RingBufReInit(&rdbuf); ! 673: retval=0; ! 674: break; ! 675: ! 676: case VDD_OUTBUF_PURGE: ! 677: lprintf(LOG_WARNING,"!VDD_OUTBUF_PURGE: NOT IMPLEMENTED"); ! 678: retval=0; ! 679: break; ! 680: ! 681: case VDD_INBUF_FULL: ! 682: retval=RingBufFull(&rdbuf); ! 683: inbuf_poll++; ! 684: break; ! 685: ! 686: case VDD_INBUF_SIZE: ! 687: retval=RINGBUF_SIZE_IN; ! 688: break; ! 689: ! 690: case VDD_OUTBUF_FULL: ! 691: if(!GetMailslotInfo( ! 692: wrslot, /* mailslot handle */ ! 693: NULL, /* address of maximum message size */ ! 694: &retval, /* address of size of next message */ ! 695: &msgs, /* address of number of messages */ ! 696: NULL /* address of read time-out */ ! 697: )) ! 698: retval=0; ! 699: if(retval==MAILSLOT_NO_MESSAGE) ! 700: retval=0; ! 701: retval*=msgs; ! 702: break; ! 703: ! 704: case VDD_OUTBUF_SIZE: ! 705: if(!GetMailslotInfo( ! 706: wrslot, /* mailslot handle */ ! 707: &retval, /* address of maximum message size */ ! 708: NULL, /* address of size of next message */ ! 709: NULL, /* address of number of messages */ ! 710: NULL /* address of read time-out */ ! 711: )) ! 712: retval=DEFAULT_MAX_MSG_SIZE; ! 713: break; ! 714: ! 715: case VDD_ONLINE: ! 716: if(WaitForSingleObject(hungup_event,0)==WAIT_OBJECT_0) ! 717: retval=0; ! 718: else ! 719: retval=1; ! 720: online_poll++; ! 721: break; ! 722: ! 723: case VDD_YIELD: /* forced yield */ ! 724: vdd_yields++; ! 725: yield(); ! 726: break; ! 727: ! 728: case VDD_MAYBE_YIELD: /* yield if YieldInterval is enabled and expired */ ! 729: maybe_yield(); ! 730: break; ! 731: ! 732: case VDD_LOAD_INI_FILE: /* Load and parse settings file */ ! 733: { ! 734: FILE* fp; ! 735: char cwd[MAX_PATH+1]; ! 736: ! 737: /* Load exec/sbbsexec.ini first (setting default values) */ ! 738: count = getCX(); ! 739: p = (BYTE*)GetVDMPointer((ULONG)((getES() << 16)|getDI()) ! 740: ,count,FALSE); ! 741: iniFileName(ini_fname, sizeof(ini_fname), p, INI_FILENAME); ! 742: if((fp=fopen(ini_fname,"r"))!=NULL) { ! 743: ini=iniReadFile(fp); ! 744: fclose(fp); ! 745: parse_ini(ROOT_SECTION); ! 746: } ! 747: ! 748: /* Load cwd/sbbsexec.ini second (over-riding default values) */ ! 749: GetCurrentDirectory(sizeof(cwd),cwd); ! 750: iniFileName(ini_fname, sizeof(ini_fname), cwd, INI_FILENAME); ! 751: if((fp=fopen(ini_fname,"r"))!=NULL) { ! 752: ini=iniReadFile(fp); ! 753: fclose(fp); ! 754: parse_ini(ROOT_SECTION); ! 755: } ! 756: } ! 757: break; ! 758: ! 759: case VDD_LOAD_INI_SECTION: /* Parse (program-specific) sub-section of settings file */ ! 760: count = getCX(); ! 761: p = (BYTE*)GetVDMPointer((ULONG)((getES() << 16)|getDI()) ! 762: ,count,FALSE); ! 763: parse_ini(p); ! 764: break; ! 765: ! 766: case VDD_DEBUG_OUTPUT: /* Send string to debug output */ ! 767: count = getCX(); ! 768: p = (BYTE*)GetVDMPointer((ULONG)((getES() << 16)|getDI()) ! 769: ,count,FALSE); ! 770: lputs(LOG_INFO, p); ! 771: break; ! 772: ! 773: case VDD_HANGUP: ! 774: hangup(); ! 775: break; ! 776: ! 777: default: ! 778: lprintf(LOG_ERR,"!UNKNOWN VDD_OP: %d",getBL()); ! 779: break; ! 780: } ! 781: setAX((WORD)retval); ! 782: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.